]> git.hungrycats.org Git - linux/commitdiff
[PATCH] IEEE-1394/Firewire updates
authorBen Collins <bcollins@debian.org>
Fri, 11 Apr 2003 11:38:49 +0000 (04:38 -0700)
committerLinus Torvalds <torvalds@home.transmeta.com>
Fri, 11 Apr 2003 11:38:49 +0000 (04:38 -0700)
- Convert nodemgr to new driver model.
- Convert to new module_param() calls.
- Merged fixes for devfs mkdir and some sleep-in-atomic fixes from
  mainline 2.5-bk
- Fix possible memory corruption on highlevel local read/write.
- Fix bitmap usage for some bitops.
- Fix bug in closing ISO stream.
- Fixes for nodemgr probing in the event of a reset storm.
- Workaround for nForce2 firewire chipset. This is preliminary.
- Conversion of SBP-2 to use new driver model in nodemgr, including
  providing a driver for firewire unit directories and registering
  proper callbacks.

19 files changed:
drivers/ieee1394/csr.c
drivers/ieee1394/dv1394.c
drivers/ieee1394/highlevel.c
drivers/ieee1394/highlevel.h
drivers/ieee1394/hosts.h
drivers/ieee1394/ieee1394.h
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/ieee1394_core.h
drivers/ieee1394/ieee1394_hotplug.h
drivers/ieee1394/ieee1394_transactions.c
drivers/ieee1394/ieee1394_types.h
drivers/ieee1394/iso.c
drivers/ieee1394/nodemgr.c
drivers/ieee1394/nodemgr.h
drivers/ieee1394/ohci1394.c
drivers/ieee1394/ohci1394.h
drivers/ieee1394/pcilynx.c
drivers/ieee1394/sbp2.c
drivers/ieee1394/sbp2.h

index 6cd4774c1dab7a165200f9e9bd1cc5f807251134..e13186e64115f5dc5bcedd96e10617a9fa8ff09f 100644 (file)
@@ -18,7 +18,8 @@
  */
 
 #include <linux/string.h>
-#include <linux/module.h> /* needed for MODULE_PARM */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
 
 #include "ieee1394_types.h"
 #include "hosts.h"
 
 /* Module Parameters */
 /* this module parameter can be used to disable mapping of the FCP registers */
-MODULE_PARM(fcp,"i");
-MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
+
 static int fcp = 1;
+module_param(fcp, int, 0444);
+MODULE_PARM_DESC(fcp, "Map FCP registers (default = 1, disable = 0).");
 
 static u16 csr_crc16(unsigned *data, int length)
 {
index 932088e7519d942aa4862b3c73ecd956dbcc3859..ae5e2a601809d08d5f766026c365672fa9517902 100644 (file)
@@ -2919,11 +2919,7 @@ static int __init dv1394_init_module(void)
        }
 
 #ifdef CONFIG_DEVFS_FS
-       if (!devfs_mk_dir("ieee1394/dv")) {
-               printk(KERN_ERR "dv1394: unable to create /dev/ieee1394/dv\n");
-               ieee1394_unregister_chardev(IEEE1394_MINOR_BLOCK_DV1394);
-               return -ENOMEM;
-       }
+       devfs_mk_dir("ieee1394/dv");
 #endif
 
 #ifdef CONFIG_PROC_FS
index cfe98e92fe4249e91dd398813e04e87b0646294b..843675b655e68034b80fc5d9f98a56af91300c2a 100644 (file)
@@ -57,7 +57,8 @@ struct hpsb_highlevel *hpsb_register_highlevel(const char *name,
         list_add_tail(&hl->hl_list, &hl_drivers);
        up(&hl_drivers_lock);
 
-       hl_all_hosts(hl->op->add_host);
+       if (hl->op->add_host)
+               hl_all_hosts(hl->op->add_host);
 
         return hl;
 }
@@ -98,6 +99,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
         struct hpsb_address_serve *as;
         struct list_head *entry;
         int retval = 0;
+        unsigned long flags;
 
         if (((start|end) & 3) || (start >= end) || (end > 0x1000000000000ULL)) {
                 HPSB_ERR("%s called with invalid addresses", __FUNCTION__);
@@ -116,7 +118,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
         as->start = start;
         as->end = end;
 
-        write_lock_irq(&addr_space_lock);
+        write_lock_irqsave(&addr_space_lock, flags);
         entry = addr_space.next;
 
         while (list_entry(entry, struct hpsb_address_serve, as_list)->end <= start) {
@@ -128,7 +130,7 @@ int hpsb_register_addrspace(struct hpsb_highlevel *hl,
                 }
                 entry = entry->next;
         }
-        write_unlock_irq(&addr_space_lock);
+        write_unlock_irqrestore(&addr_space_lock, flags);
 
         if (retval == 0) {
                 kfree(as);
@@ -142,8 +144,9 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
         int retval = 0;
         struct hpsb_address_serve *as;
         struct list_head *entry;
+        unsigned long flags;
 
-        write_lock_irq(&addr_space_lock);
+        write_lock_irqsave(&addr_space_lock, flags);
 
         entry = hl->addr_list.next;
 
@@ -159,7 +162,7 @@ int hpsb_unregister_addrspace(struct hpsb_highlevel *hl, u64 start)
                 }
         }
 
-        write_unlock_irq(&addr_space_lock);
+        write_unlock_irqrestore(&addr_space_lock, flags);
 
         return retval;
 }
@@ -202,7 +205,8 @@ void highlevel_add_host(struct hpsb_host *host)
         list_for_each(entry, &hl_drivers) {
                 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
 
-               hl->op->add_host(host);
+               if (hl->op->add_host)
+                       hl->op->add_host(host);
         }
         up(&hl_drivers_lock);
 }
@@ -237,48 +241,40 @@ void highlevel_host_reset(struct hpsb_host *host)
        up(&hl_drivers_lock);
 }
 
-void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
+void highlevel_iso_receive(struct hpsb_host *host, void *data,
                            unsigned int length)
 {
         struct list_head *entry;
         struct hpsb_highlevel *hl;
-        int channel = (data[0] >> 8) & 0x3f;
+        int channel = (((quadlet_t *)data)[0] >> 8) & 0x3f;
 
         down(&hl_drivers_lock);
-        entry = hl_drivers.next;
-
-        while (entry != &hl_drivers) {
+       list_for_each(entry, &hl_drivers) {
                 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
-                if (hl->op->iso_receive) {
+
+                if (hl->op->iso_receive)
                         hl->op->iso_receive(host, channel, data, length);
-                }
-                entry = entry->next;
         }
         up(&hl_drivers_lock);
 }
 
 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                           u8 *data, unsigned int length)
+                           void *data, unsigned int length)
 {
         struct list_head *entry;
         struct hpsb_highlevel *hl;
-        int cts = data[0] >> 4;
+        int cts = ((quadlet_t *)data)[0] >> 4;
 
         down(&hl_drivers_lock);
-        entry = hl_drivers.next;
-
-        while (entry != &hl_drivers) {
+       list_for_each(entry, &hl_drivers) {
                 hl = list_entry(entry, struct hpsb_highlevel, hl_list);
-                if (hl->op->fcp_request) {
-                        hl->op->fcp_request(host, nodeid, direction, cts, data,
-                                            length);
-                }
-                entry = entry->next;
+                if (hl->op->fcp_request)
+                        hl->op->fcp_request(host, nodeid, direction, cts, data, length);
         }
         up(&hl_drivers_lock);
 }
 
-int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
                    u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
@@ -295,13 +291,14 @@ int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
                 if (as->end > addr) {
                         partlength = min(as->end - addr, (u64) length);
 
-                        if (as->op->read != NULL) {
-                                rcode = as->op->read(host, nodeid, buffer,
+                        if (as->op->read) {
+                                rcode = as->op->read(host, nodeid, data,
                                                     addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
 
+                       (u8 *)data += partlength;
                         length -= partlength;
                         addr += partlength;
 
@@ -324,7 +321,7 @@ int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
 }
 
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-                   quadlet_t *data, u64 addr, unsigned int length, u16 flags)
+                   void *data, u64 addr, unsigned int length, u16 flags)
 {
         struct hpsb_address_serve *as;
         struct list_head *entry;
@@ -340,13 +337,14 @@ int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
                 if (as->end > addr) {
                         partlength = min(as->end - addr, (u64) length);
 
-                        if (as->op->write != NULL) {
+                        if (as->op->write) {
                                 rcode = as->op->write(host, nodeid, destid,
                                                      data, addr, partlength, flags);
                         } else {
                                 rcode = RCODE_TYPE_ERROR;
                         }
 
+                       (u8 *)data += partlength;
                         length -= partlength;
                         addr += partlength;
 
@@ -383,7 +381,7 @@ int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
 
         while (as->start <= addr) {
                 if (as->end > addr) {
-                        if (as->op->lock != NULL) {
+                        if (as->op->lock) {
                                 rcode = as->op->lock(host, nodeid, store, addr,
                                                      data, arg, ext_tcode, flags);
                         } else {
@@ -416,7 +414,7 @@ int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
 
         while (as->start <= addr) {
                 if (as->end > addr) {
-                        if (as->op->lock64 != NULL) {
+                        if (as->op->lock64) {
                                 rcode = as->op->lock64(host, nodeid, store,
                                                        addr, data, arg,
                                                        ext_tcode, flags);
index 5e556b5b702327f9d0074bc7de0ca919652df693..d6a90ddf24251b1563788e84684a404ab880bdb1 100644 (file)
@@ -108,19 +108,19 @@ void highlevel_host_reset(struct hpsb_host *host);
    later case, no response will be sent and the driver, that handled the request
    will send the response itself.
 */
-int highlevel_read(struct hpsb_host *host, int nodeid, quadlet_t *buffer,
+int highlevel_read(struct hpsb_host *host, int nodeid, void *data,
                    u64 addr, unsigned int length, u16 flags);
 int highlevel_write(struct hpsb_host *host, int nodeid, int destid,
-                   quadlet_t *data, u64 addr, unsigned int length, u16 flags);
+                   void *data, u64 addr, unsigned int length, u16 flags);
 int highlevel_lock(struct hpsb_host *host, int nodeid, quadlet_t *store,
                    u64 addr, quadlet_t data, quadlet_t arg, int ext_tcode, u16 flags);
 int highlevel_lock64(struct hpsb_host *host, int nodeid, octlet_t *store,
                      u64 addr, octlet_t data, octlet_t arg, int ext_tcode, u16 flags);
 
-void highlevel_iso_receive(struct hpsb_host *host, quadlet_t *data,
+void highlevel_iso_receive(struct hpsb_host *host, void *data,
                            unsigned int length);
 void highlevel_fcp_request(struct hpsb_host *host, int nodeid, int direction,
-                           u8 *data, unsigned int length);
+                           void *data, unsigned int length);
 
 
 /*
index 25e0e205978430041f4219803717107ba7ddca3e..0c39327a52afe5186ba0ca0c397d25cb30bd1745 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _IEEE1394_HOSTS_H
 #define _IEEE1394_HOSTS_H
 
+#include <linux/device.h>
 #include <linux/wait.h>
 #include <linux/list.h>
 #include <asm/semaphore.h>
@@ -64,6 +65,8 @@ struct hpsb_host {
         struct hpsb_host_driver *driver;
 
        struct pci_dev *pdev;
+
+       struct device device;
 };
 
 
index fe59095108d210918db9cb18d23a34cc4912d653..4763597298eb6fc96303baf40c33f2e388752c84 100644 (file)
 #define ACKX_TIMEOUT             (-4)
 
 
-#define SPEED_100                0x0
-#define SPEED_200                0x1
-#define SPEED_400                0x2
+#define SPEED_100              0x00
+#define SPEED_200              0x01
+#define SPEED_400              0x02
+#define SPEED_800              0x03
+#define SPEED_1600             0x04
+#define SPEED_3200             0x05
+
 
 /* Maps speed values above to a string representation */
 extern const char *hpsb_speedto_str[];
index c32a7896cdabaeaddbfb3c94d97de68b4b0dbdbb..2c1e53f95b0410b76a103d38bdae5d8e198d078d 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/proc_fs.h>
 #include <linux/bitops.h>
 #include <asm/byteorder.h>
 /*
  * Disable the nodemgr detection and config rom reading functionality.
  */
-MODULE_PARM(disable_nodemgr, "i");
-MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 static int disable_nodemgr = 0;
-
-MODULE_PARM(disable_hotplug, "i");
-MODULE_PARM_DESC(disable_hotplug, "Disable hotplug for detected nodes.");
-static int disable_hotplug = 0;
+module_param(disable_nodemgr, int, 0444);
+MODULE_PARM_DESC(disable_nodemgr, "Disable nodemgr functionality.");
 
 /* We are GPL, so treat us special */
 MODULE_LICENSE("GPL");
@@ -62,7 +59,7 @@ MODULE_LICENSE("GPL");
 static kmem_cache_t *hpsb_packet_cache;
 
 /* Some globals used */
-const char *hpsb_speedto_str[] = { "S100", "S200", "S400" };
+const char *hpsb_speedto_str[] = { "S100", "S200", "S400", "S800", "S1600", "S3200" };
 
 static void dump_packet(const char *text, quadlet_t *data, int size)
 {
@@ -130,9 +127,8 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
 {
         struct hpsb_packet *packet = NULL;
         void *data = NULL;
-        int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
 
-        packet = kmem_cache_alloc(hpsb_packet_cache, kmflags);
+        packet = kmem_cache_alloc(hpsb_packet_cache, GFP_ATOMIC);
         if (packet == NULL)
                 return NULL;
 
@@ -140,7 +136,7 @@ struct hpsb_packet *alloc_hpsb_packet(size_t data_size)
         packet->header = packet->embedded_header;
 
         if (data_size) {
-                data = kmalloc(data_size + 8, kmflags);
+                data = kmalloc(data_size + 8, GFP_ATOMIC);
                 if (data == NULL) {
                        kmem_cache_free(hpsb_packet_cache, packet);
                         return NULL;
@@ -496,8 +492,7 @@ int hpsb_send_packet(struct hpsb_packet *packet)
                 quadlet_t *data;
                 size_t size=packet->data_size+packet->header_size;
 
-                int kmflags = in_interrupt() ? GFP_ATOMIC : GFP_KERNEL;
-                data = kmalloc(packet->header_size + packet->data_size, kmflags);
+                data = kmalloc(packet->header_size + packet->data_size, GFP_ATOMIC);
                 if (!data) {
                         HPSB_ERR("unable to allocate memory for concatenating header and data");
                         return 0;
@@ -1120,7 +1115,7 @@ static int ieee1394_dispatch_open(struct inode *inode, struct file *file)
        /* follow through with the open() */
        retval = file_ops->open(inode, file);
 
-       if(retval == 0) {
+       if (retval == 0) {
                
                /* If the open() succeeded, then ieee1394 will be left
                 * with an extra module reference, so we discard it here.
@@ -1166,7 +1161,7 @@ static int __init ieee1394_init(void)
 #ifdef CONFIG_PROC_FS
        /* Must be done before we start everything else, since the drivers
         * may use it.  */
-       ieee1394_procfs_entry = proc_mkdir( "ieee1394", proc_bus);
+       ieee1394_procfs_entry = proc_mkdir("ieee1394", proc_bus);
        if (ieee1394_procfs_entry == NULL) {
                HPSB_ERR("unable to create /proc/bus/ieee1394\n");
                unregister_chrdev(IEEE1394_MAJOR, "ieee1394");
@@ -1179,7 +1174,7 @@ static int __init ieee1394_init(void)
        init_hpsb_highlevel();
        init_csr();
        if (!disable_nodemgr)
-               init_ieee1394_nodemgr(disable_hotplug);
+               init_ieee1394_nodemgr();
        else
                HPSB_INFO("nodemgr functionality disabled");
 
@@ -1273,7 +1268,7 @@ EXPORT_SYMBOL(hpsb_node_write);
 EXPORT_SYMBOL(hpsb_node_lock);
 EXPORT_SYMBOL(hpsb_register_protocol);
 EXPORT_SYMBOL(hpsb_unregister_protocol);
-EXPORT_SYMBOL(hpsb_release_unit_directory);
+EXPORT_SYMBOL(ieee1394_bus_type);
 
 /** csr.c **/
 EXPORT_SYMBOL(hpsb_update_config_rom);
index 030406396e1abfca2da9122d95ae785bcdaa19c5..37db15faac3ea43f31fb6a4d4a98ae1cea79375d 100644 (file)
@@ -231,4 +231,7 @@ extern devfs_handle_t ieee1394_devfs_handle;
 /* the proc_fs entry for /proc/ieee1394 */
 extern struct proc_dir_entry *ieee1394_procfs_entry;
 
+/* Our sysfs bus entry */
+extern struct bus_type ieee1394_bus_type;
+
 #endif /* _IEEE1394_CORE_H */
index f5933274accd21dc072214625878209f547ee5ed..211f9f1721fa089fd1f55c525d2bb351f6c65efd 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _IEEE1394_HOTPLUG_H
 #define _IEEE1394_HOTPLUG_H
 
+#include <linux/device.h>
+
 #include "ieee1394_core.h"
 #include "nodemgr.h"
 
@@ -31,26 +33,6 @@ struct hpsb_protocol_driver {
         */
        struct ieee1394_device_id *id_table;
 
-       /* 
-        * The probe function is called when a device is added to the
-        * bus and the nodemgr finds a matching entry in the drivers
-        * device id table or when registering this driver and a
-        * previously unhandled device can be handled.  The driver may
-        * decline to handle the device based on further investigation
-        * of the device (or whatever reason) in which case a negative
-        * error code should be returned, otherwise 0 should be
-        * returned. The driver may use the driver_data field in the
-        * unit directory to store per device driver specific data.
-        */
-       int (*probe)(struct unit_directory *ud);
-
-       /* 
-        * The disconnect function is called when a device is removed
-        * from the bus or if it wasn't possible to read the guid
-        * after the last bus reset.
-        */
-       void (*disconnect)(struct unit_directory *ud);
-
        /* 
         * The update function is called when the node has just
         * survived a bus reset, i.e. it is still present on the bus.
@@ -59,18 +41,12 @@ struct hpsb_protocol_driver {
         */
        void (*update)(struct unit_directory *ud);
 
-       /* Driver in list of all registered drivers */
-       struct list_head list;
 
-       /* The list of unit directories managed by this driver */
-       struct list_head unit_directories;
+       /* Our LDM structure */
+       struct device_driver driver;
 };
 
 int hpsb_register_protocol(struct hpsb_protocol_driver *driver);
 void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver);
 
-int hpsb_claim_unit_directory(struct unit_directory *ud,
-                             struct hpsb_protocol_driver *driver);
-void hpsb_release_unit_directory(struct unit_directory *ud);
-
 #endif /* _IEEE1394_HOTPLUG_H */
index 7b5a6af2296879a7bc6f84ba1935f36a3a2033c6..e8ddaa8bc1942de9092e20304f09d08de89325fe 100644 (file)
@@ -146,10 +146,10 @@ int hpsb_get_tlabel(struct hpsb_packet *packet, int wait)
 
        spin_lock_irqsave(&tp->lock, flags);
        
-       packet->tlabel = find_next_zero_bit(&tp->pool, 64, tp->next);
+       packet->tlabel = find_next_zero_bit(tp->pool, 64, tp->next);
        tp->next = (packet->tlabel + 1) % 64;
        /* Should _never_ happen */
-       BUG_ON(test_and_set_bit(packet->tlabel, &tp->pool));
+       BUG_ON(test_and_set_bit(packet->tlabel, tp->pool));
        tp->allocations++;
        spin_unlock_irqrestore(&tp->lock, flags);
 
@@ -177,7 +177,7 @@ void hpsb_free_tlabel(struct hpsb_packet *packet)
        BUG_ON(packet->tlabel > 63 || packet->tlabel < 0);
 
         spin_lock_irqsave(&tp->lock, flags);
-       BUG_ON(!test_and_clear_bit(packet->tlabel, &tp->pool));
+       BUG_ON(!test_and_clear_bit(packet->tlabel, tp->pool));
         spin_unlock_irqrestore(&tp->lock, flags);
 
        up(&tp->count);
index 95b8965bb2bd1da060ad2ab71a6da20293c823ff..5ae4824a65bb449879cc78384f3d453654f53b1c 100644 (file)
 
 /* Transaction Label handling */
 struct hpsb_tlabel_pool {
-       u64 pool;
+       DECLARE_BITMAP(pool, 64);
        spinlock_t lock;
        u8 next;
        u32 allocations;
        struct semaphore count;
 };
 
-#define HPSB_TPOOL_INIT(_tp)            \
-do {                                    \
-       sema_init(&(_tp)->count, 63);   \
-       spin_lock_init(&(_tp)->lock);   \
-       (_tp)->next = 0;                \
-       (_tp)->pool = 0;                \
+#define HPSB_TPOOL_INIT(_tp)                   \
+do {                                           \
+       CLEAR_BITMAP((_tp)->pool, 64);          \
+       spin_lock_init(&(_tp)->lock);           \
+       (_tp)->next = 0;                        \
+       (_tp)->allocations = 0;                 \
+       sema_init(&(_tp)->count, 63);           \
 } while(0)
 
 
index 74831f7d2363d24c5189898581233771b9cf68ac..ec4e0b10b2bb8d39ce75dbd22fbb5a9e63a11a45 100644 (file)
@@ -14,7 +14,7 @@
 
 void hpsb_iso_stop(struct hpsb_iso *iso)
 {
-       if(!iso->flags & HPSB_ISO_DRIVER_STARTED)
+       if (!(iso->flags & HPSB_ISO_DRIVER_STARTED))
                return;
 
        iso->host->driver->isoctl(iso, iso->type == HPSB_ISO_XMIT ?
index 72412bcfe1d5700ec7507c1537a0c04bbef4e8a8..b4bd67978ee08a75f2ba1ae18b3cdde84d948b81 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Node information (ConfigROM) collection and management.
  *
- * Copyright (C) 2000 Andreas E. Bombe
- *               2001 Ben Collins <bcollins@debian.net>
+ * Copyright (C) 2000          Andreas E. Bombe
+ *               2001-2003     Ben Collins <bcollins@debian.net>
  *
  * This code is licensed under the GPL.  See the file COPYING in the root
  * directory of the kernel sources for details.
@@ -17,9 +17,7 @@
 #include <linux/kmod.h>
 #include <linux/completion.h>
 #include <linux/delay.h>
-#ifdef CONFIG_PROC_FS
-#include <linux/proc_fs.h>
-#endif
+#include <linux/pci.h>
 #include <asm/atomic.h>
 #include <asm/byteorder.h>
 
 #include "csr.h"
 #include "nodemgr.h"
 
-#ifdef CONFIG_IEEE1394_OUI_DB
-struct oui_list_struct {
-       int oui;
-       char *name;
-};
 
-extern struct oui_list_struct oui_list[];
 
-static char *nodemgr_find_oui_name(int oui) {
+static char *nodemgr_find_oui_name(int oui)
+{
+#ifdef CONFIG_IEEE1394_OUI_DB
+       extern struct oui_list_struct {
+               int oui;
+               char *name;
+       } oui_list[];
        int i;
 
        for (i = 0; oui_list[i].name; i++)
                if (oui_list[i].oui == oui)
                        return oui_list[i].name;
-
+#endif
        return NULL;
 }
-#endif
 
 /* 
  * Basically what we do here is start off retrieving the bus_info block.
@@ -60,163 +57,469 @@ static char *nodemgr_find_oui_name(int oui) {
  * complete directory entry (be it a leaf or a directory). We then process
  * it and add the info to our structure for that particular node.
  *
- * We verify CRC's along the way for each directory/block/leaf. The
- * entire node structure is generic, and simply stores the information in
- * a way that's easy to parse by the protocol interface.
+ * We verify CRC's along the way for each directory/block/leaf. The entire
+ * node structure is generic, and simply stores the information in a way
+ * that's easy to parse by the protocol interface.
  */
 
-/* The nodemgr maintains a number of data structures: the node list,
- * the driver list, unit directory list and the host info list.  The
- * first three lists are accessed from process context only: /proc
- * readers, insmod and rmmod, and the nodemgr thread.  Access to these
- * lists are serialized by means of the nodemgr_serialize mutex, which
- * must be taken before accessing the structures and released
- * afterwards.  The host info list is only accessed during insmod,
- * rmmod and from interrupt and allways only for a short period of
- * time, so a spinlock is used to protect this list.
+/* 
+ * The nodemgr relies heavily on the Drive Model for device callbacks and
+ * driver/device mappings. The old nodemgr used to handle all this itself,
+ * but now we are much simpler because of the LDM.
  */
 
 static DECLARE_MUTEX(nodemgr_serialize);
-static LIST_HEAD(node_list);
-static LIST_HEAD(driver_list);
-static LIST_HEAD(unit_directory_list);
 
 static LIST_HEAD(host_info_list);
 static spinlock_t host_info_lock = SPIN_LOCK_UNLOCKED;
 
-/* Disables use of the hotplug calls.  */
-static int nodemgr_disable_hotplug = 0;
-
 struct host_info {
        struct hpsb_host *host;
        struct list_head list;
        struct completion exited;
        struct semaphore reset_sem;
        int pid;
+       int id;
+       char daemon_name[15];
+};
+
+
+#define fw_attr(class, class_type, field, type, format_string)         \
+static ssize_t fw_show_##class##_##field (struct device *dev, char *buf)\
+{                                                                      \
+       class_type *class;                                              \
+       class = container_of(dev, class_type, device);                  \
+       return sprintf(buf, format_string, (type)class->field);         \
+}                                                                      \
+static struct device_attribute dev_attr_##class##_##field = {          \
+       .attr = {.name = __stringify(field), .mode = S_IRUGO },         \
+       .show   = fw_show_##class##_##field,                            \
 };
 
-#ifdef CONFIG_PROC_FS
 
-#define PUTF(fmt, args...) out += sprintf(out, fmt, ## args)
+#define fw_drv_attr(field, type, format_string)                        \
+static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \
+{                                                              \
+       struct hpsb_protocol_driver *driver;                    \
+       driver = container_of(drv, struct hpsb_protocol_driver, driver); \
+       return sprintf(buf, format_string, (type)driver->field);\
+}                                                              \
+static struct driver_attribute driver_attr_drv_##field = {     \
+        .attr = {.name = __stringify(field), .mode = S_IRUGO },        \
+        .show   = fw_drv_show_##field,                         \
+};
+
 
-static int raw1394_read_proc(char *page, char **start, off_t off,
-                            int count, int *eof, void *data)
+static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf)
 {
-       struct list_head *lh;
-       struct node_entry *ne;
-       int len;
-       char *out = page;
-       unsigned long flags;
+       struct node_entry *ne = container_of(dev, struct node_entry, device);
 
-       if (down_interruptible(&nodemgr_serialize))
-               return -EINTR;
+       return sprintf(buf, "IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d) "
+                       "LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n", ne->busopt.irmc,
+                       ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
+                       ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
+                       ne->busopt.max_rec, ne->busopt.cyc_clk_acc);
+}
+static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL);
 
-       list_for_each(lh, &node_list) {
-               struct list_head *l;
-               int ud_count = 0;
 
-               ne = list_entry(lh, struct node_entry, list);
-               if (!ne)
-                       continue;
+static ssize_t fw_show_ne_tlabels_free(struct device *dev, char *buf)
+{
+       struct node_entry *ne = container_of(dev, struct node_entry, device);
+       return sprintf(buf, "%d\n", atomic_read(&ne->tpool->count.count) + 1);
+}
+static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL);
+
+
+static ssize_t fw_show_ne_tlabels_allocations(struct device *dev, char *buf)
+{
+       struct node_entry *ne = container_of(dev, struct node_entry, device);
+       return sprintf(buf, "%u\n", ne->tpool->allocations);
+}
+static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL);
 
-               PUTF("Node[" NODE_BUS_FMT "]  GUID[%016Lx]:\n",
-                    NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
-
-               /* Generic Node information */
-               PUTF("  Vendor ID   : `%s' [0x%06x]\n", ne->oui_name, ne->vendor_id);
-               if (ne->vendor_name)
-                       PUTF("  Vendor text : `%s'\n", ne->vendor_name);
-               PUTF("  Capabilities: 0x%06x\n", ne->capabilities);
-               PUTF("  Tlabel stats:\n");
-               spin_lock_irqsave(&ne->tpool->lock, flags);
-               PUTF("    Free  : %d\n", atomic_read(&ne->tpool->count.count) + 1);
-               PUTF("    Total : %u\n", ne->tpool->allocations);
-               PUTF("    Mask  : %016Lx\n", (unsigned long long)ne->tpool->pool);
-               spin_unlock_irqrestore(&ne->tpool->lock, flags);
-               PUTF("  Bus Options :\n");
-               PUTF("    IRMC(%d) CMC(%d) ISC(%d) BMC(%d) PMC(%d) GEN(%d)\n"
-                    "    LSPD(%d) MAX_REC(%d) CYC_CLK_ACC(%d)\n",
-                    ne->busopt.irmc, ne->busopt.cmc, ne->busopt.isc, ne->busopt.bmc,
-                    ne->busopt.pmc, ne->busopt.generation, ne->busopt.lnkspd,
-                    ne->busopt.max_rec, ne->busopt.cyc_clk_acc);
-
-               /* If this is the host entry, output some info about it aswell */
-               if (ne->host != NULL && ne->host->node_id == ne->nodeid) {
-                       PUTF("  Host Node Status:\n");
-                       PUTF("    Host Driver     : %s\n", ne->host->driver->name);
-                       PUTF("    Nodes connected : %d\n", ne->host->node_count);
-                       PUTF("    Nodes active    : %d\n", ne->host->nodes_active);
-                       PUTF("    SelfIDs received: %d\n", ne->host->selfid_count);
-                       PUTF("    Irm ID          : [" NODE_BUS_FMT "]\n",
-                            NODE_BUS_ARGS(ne->host->irm_id));
-                       PUTF("    BusMgr ID       : [" NODE_BUS_FMT "]\n",
-                            NODE_BUS_ARGS(ne->host->busmgr_id));
-                       PUTF("    In Bus Reset    : %s\n", ne->host->in_bus_reset ? "yes" : "no");
-                       PUTF("    Root            : %s\n", ne->host->is_root ? "yes" : "no");
-                       PUTF("    Cycle Master    : %s\n", ne->host->is_cycmst ? "yes" : "no");
-                       PUTF("    IRM             : %s\n", ne->host->is_irm ? "yes" : "no");
-                       PUTF("    Bus Manager     : %s\n", ne->host->is_busmgr ? "yes" : "no");
+
+static ssize_t fw_show_ne_tlabels_mask(struct device *dev, char *buf)
+{
+       struct node_entry *ne = container_of(dev, struct node_entry, device);
+#if (BITS_PER_LONG <= 32)
+       return sprintf(buf, "0x%08lx%08lx\n", ne->tpool->pool[0], ne->tpool->pool[1]);
+#else
+       return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]);
+#endif
+}
+static DEVICE_ATTR(tlabels_mask,S_IRUGO,fw_show_ne_tlabels_mask,NULL);
+
+
+fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n")
+fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n")
+
+fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n")
+fw_attr(ne, struct node_entry, vendor_name, const char *, "%s\n")
+fw_attr(ne, struct node_entry, vendor_oui, const char *, "%s\n")
+
+fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n")
+fw_attr(ne, struct node_entry, guid_vendor_id, unsigned int, "0x%06x\n")
+fw_attr(ne, struct node_entry, guid_vendor_oui, const char *, "%s\n")
+
+static struct device_attribute *const fw_ne_attrs[] = {
+       &dev_attr_ne_guid,
+       &dev_attr_ne_guid_vendor_id,
+       &dev_attr_ne_capabilities,
+       &dev_attr_ne_vendor_id,
+       &dev_attr_ne_nodeid,
+       &dev_attr_bus_options,
+       &dev_attr_tlabels_free,
+       &dev_attr_tlabels_allocations,
+       &dev_attr_tlabels_mask,
+};
+
+
+
+fw_attr(ud, struct unit_directory, address, unsigned long long, "0x%016Lx\n")
+fw_attr(ud, struct unit_directory, length, int, "%d\n")
+/* These are all dependent on the value being provided */
+fw_attr(ud, struct unit_directory, vendor_id, unsigned int, "0x%06x\n")
+fw_attr(ud, struct unit_directory, model_id, unsigned int, "0x%06x\n")
+fw_attr(ud, struct unit_directory, specifier_id, unsigned int, "0x%06x\n")
+fw_attr(ud, struct unit_directory, version, unsigned int, "0x%06x\n")
+fw_attr(ud, struct unit_directory, vendor_name, const char *, "%s\n")
+fw_attr(ud, struct unit_directory, vendor_oui, const char *, "%s\n")
+fw_attr(ud, struct unit_directory, model_name, const char *, "%s\n")
+
+static struct device_attribute *const fw_ud_attrs[] = {
+       &dev_attr_ud_address,
+       &dev_attr_ud_length,
+};
+
+
+fw_attr(host, struct hpsb_host, node_count, int, "%d\n")
+fw_attr(host, struct hpsb_host, selfid_count, int, "%d\n")
+fw_attr(host, struct hpsb_host, nodes_active, int, "%d\n")
+fw_attr(host, struct hpsb_host, in_bus_reset, int, "%d\n")
+fw_attr(host, struct hpsb_host, is_root, int, "%d\n")
+fw_attr(host, struct hpsb_host, is_cycmst, int, "%d\n")
+fw_attr(host, struct hpsb_host, is_irm, int, "%d\n")
+fw_attr(host, struct hpsb_host, is_busmgr, int, "%d\n")
+
+static struct device_attribute *const fw_host_attrs[] = {
+       &dev_attr_host_node_count,
+       &dev_attr_host_selfid_count,
+       &dev_attr_host_nodes_active,
+       &dev_attr_host_in_bus_reset,
+       &dev_attr_host_is_root,
+       &dev_attr_host_is_cycmst,
+       &dev_attr_host_is_irm,
+       &dev_attr_host_is_busmgr,
+};
+
+
+static ssize_t fw_show_drv_device_ids(struct device_driver *drv, char *buf)
+{
+       struct hpsb_protocol_driver *driver;
+       struct ieee1394_device_id *id;
+       int length = 0;
+       char *scratch = buf;
+
+        driver = container_of(drv, struct hpsb_protocol_driver, driver);
+
+       for (id = driver->id_table; id->match_flags != 0; id++) {
+               int need_coma = 0;
+
+               if (id->match_flags & IEEE1394_MATCH_VENDOR_ID) {
+                       length += sprintf(scratch, "vendor_id=0x%06x", id->vendor_id);
+                       scratch = buf + length;
+                       need_coma++;
                }
 
-               /* Now the unit directories */
-               list_for_each (l, &ne->unit_directories) {
-                       struct unit_directory *ud = list_entry (l, struct unit_directory, node_list);
-                       int printed = 0; // small hack
+               if (id->match_flags & IEEE1394_MATCH_MODEL_ID) {
+                       length += sprintf(scratch, "%smodel_id=0x%06x",
+                                         need_coma++ ? "," : "",
+                                         id->model_id);
+                       scratch = buf + length;
+               }
 
-                       PUTF("  Unit Directory %d:\n", ud_count++);
+               if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) {
+                       length += sprintf(scratch, "%sspecifier_id=0x%06x",
+                                         need_coma++ ? "," : "",
+                                         id->specifier_id);
+                       scratch = buf + length;
+               }
 
-                       if (ud->flags & UNIT_DIRECTORY_VENDOR_ID ||
-                           ud->flags & UNIT_DIRECTORY_MODEL_ID) {
-                               PUTF("    Vendor/Model ID  : ");
-                       }
-                       if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
-                               PUTF("%s [%06x]", ud->vendor_name ?: "Unknown",
-                                    ud->vendor_id);
-                               printed = 1;
-                       }
-                       if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
-                               if (!printed) {
-                                       PUTF("%s [%06x]", ne->vendor_name ?: "Unknown",
-                                            ne->vendor_id);
-                               }
-                               PUTF(" / %s [%06x]", ud->model_name ?: "Unknown", ud->model_id);
-                               printed = 1;
-                       }
-                       if (printed)
-                               PUTF("\n");
-
-                       if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
-                               PUTF("    Software Spec ID : %06x\n", ud->specifier_id);
-                       if (ud->flags & UNIT_DIRECTORY_VERSION)
-                               PUTF("    Software Version : %06x\n", ud->version);
-                       if (ud->driver)
-                               PUTF("    Driver           : %s\n", ud->driver->name);
-                       PUTF("    Length (in quads): %d\n", ud->count);
+               if (id->match_flags & IEEE1394_MATCH_VERSION) {
+                       length += sprintf(scratch, "%sversion=0x%06x",
+                                         need_coma++ ? "," : "",
+                                         id->version);
+                       scratch = buf + length;
                }
 
+               if (need_coma) {
+                       *scratch++ = '\n';
+                       length++;
+               }
        }
 
-       up(&nodemgr_serialize);
+       return length;
+}
+static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL);
 
-       len = out - page;
-       len -= off;
-       if (len < count) {
-               *eof = 1;
-               if (len <= 0)
-                       return 0;
-       } else
-               len = count;
 
-        *start = page + off;
+fw_drv_attr(name, const char *, "%s\n")
+
+static struct driver_attribute *const fw_drv_attrs[] = {
+       &driver_attr_drv_name,
+       &driver_attr_device_ids,
+};
+
+
+static void nodemgr_create_drv_files(struct hpsb_protocol_driver *driver)
+{
+       struct device_driver *drv = &driver->driver;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
+               driver_create_file(drv, fw_drv_attrs[i]);
+}
+
+
+static void nodemgr_remove_drv_files(struct hpsb_protocol_driver *driver)
+{
+       struct device_driver *drv = &driver->driver;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_drv_attrs); i++)
+               driver_remove_file(drv, fw_drv_attrs[i]);
+}
+
+
+static void nodemgr_create_ne_dev_files(struct node_entry *ne)
+{
+       struct device *dev = &ne->device;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
+               device_create_file(dev, fw_ne_attrs[i]);
+}
+
+
+static void nodemgr_create_host_dev_files(struct hpsb_host *host)
+{
+       struct device *dev = &host->device;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
+               device_create_file(dev, fw_host_attrs[i]);
+}
+
+
+static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid);
+
+static void nodemgr_update_host_dev_links(struct hpsb_host *host)
+{
+       struct device *dev = &host->device;
+       struct node_entry *ne;
+
+       sysfs_remove_link(&dev->kobj, "irm_id");
+       sysfs_remove_link(&dev->kobj, "busmgr_id");
+       sysfs_remove_link(&dev->kobj, "host_id");
+
+       if ((ne = find_entry_by_nodeid(host, host->irm_id)))
+               sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id");
+       if ((ne = find_entry_by_nodeid(host, host->busmgr_id)))
+               sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id");
+       if ((ne = find_entry_by_nodeid(host, host->node_id)))
+               sysfs_create_link(&dev->kobj, &ne->device.kobj, "host_id");
+}
+
+static void nodemgr_create_ud_dev_files(struct unit_directory *ud)
+{
+       struct device *dev = &ud->device;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
+               device_create_file(dev, fw_ud_attrs[i]);
+
+       if (ud->flags & UNIT_DIRECTORY_SPECIFIER_ID)
+               device_create_file(dev, &dev_attr_ud_specifier_id);
+
+       if (ud->flags & UNIT_DIRECTORY_VERSION)
+               device_create_file(dev, &dev_attr_ud_version);
+
+       if (ud->flags & UNIT_DIRECTORY_VENDOR_ID) {
+               device_create_file(dev, &dev_attr_ud_vendor_id);
+               if (ud->flags & UNIT_DIRECTORY_VENDOR_TEXT)
+                       device_create_file(dev, &dev_attr_ud_vendor_name);
+       }
+
+       if (ud->flags & UNIT_DIRECTORY_MODEL_ID) {
+               device_create_file(dev, &dev_attr_ud_model_id);
+               if (ud->flags & UNIT_DIRECTORY_MODEL_TEXT)
+                       device_create_file(dev, &dev_attr_ud_model_name);
+       }
+}
+
+
+static int nodemgr_bus_match(struct device * dev, struct device_driver * drv)
+{
+        struct hpsb_protocol_driver *driver;
+        struct unit_directory *ud;
+       struct ieee1394_device_id *id;
+
+       if (dev->class_num != DEV_CLASS_UNIT_DIRECTORY)
+               return 0;
+
+       ud = container_of(dev, struct unit_directory, device);
+       driver = container_of(drv, struct hpsb_protocol_driver, driver);
+
+        for (id = driver->id_table; id->match_flags != 0; id++) {
+                if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
+                    id->vendor_id != ud->vendor_id)
+                        continue;
+
+                if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
+                    id->model_id != ud->model_id)
+                        continue;
+
+                if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
+                    id->specifier_id != ud->specifier_id)
+                        continue;
+
+                if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
+                    id->version != ud->version)
+                        continue;
+
+               return 1;
+        }
+
+       return 0;
+}
+
+
+static void nodemgr_release_ud(struct device *dev)
+{
+       kfree(container_of(dev, struct unit_directory, device));
+}
+
+
+static void nodemgr_release_ne(struct device *dev)
+{
+       kfree(container_of(dev, struct node_entry, device));
+}
+
+
+static void nodemgr_remove_ud(struct unit_directory *ud)
+{
+       struct device *dev = &ud->device;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(fw_ud_attrs); i++)
+               device_remove_file(dev, fw_ud_attrs[i]);
+
+       device_remove_file(dev, &dev_attr_ud_specifier_id);
+       device_remove_file(dev, &dev_attr_ud_version);
+       device_remove_file(dev, &dev_attr_ud_vendor_id);
+       device_remove_file(dev, &dev_attr_ud_vendor_name);
+       device_remove_file(dev, &dev_attr_ud_vendor_oui);
+       device_remove_file(dev, &dev_attr_ud_model_id);
+       device_remove_file(dev, &dev_attr_ud_model_name);
+
+       device_unregister(dev);
+}
+
+
+static void nodemgr_remove_node_uds(struct node_entry *ne)
+{
+       struct list_head *lh, *next;
+
+       list_for_each_safe(lh, next, &ne->device.children) {
+               struct unit_directory *ud;
+               ud = container_of(list_to_dev(lh), struct unit_directory, device);
+               nodemgr_remove_ud(ud);
+       }
+}
+
+
+static void nodemgr_update_ud_names(struct host_info *hi, struct node_entry *ne)
+{
+       struct list_head *lh;
+
+       list_for_each(lh, &ne->device.children) {
+               struct unit_directory *ud;
+               ud = container_of(list_to_dev(lh), struct unit_directory, device);
+
+               snprintf(ud->device.name, DEVICE_NAME_SIZE,
+                        "IEEE-1394 unit directory %d-" NODE_BUS_FMT "-%u",
+                        hi->id, NODE_BUS_ARGS(ne->nodeid), ud->id);
+       }
+}
+
+
+static void nodemgr_remove_ne(struct node_entry *ne)
+{
+       struct device *dev = &ne->device;
+       int i;
+
+       nodemgr_remove_node_uds(ne);
+
+       for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++)
+               device_remove_file(dev, fw_ne_attrs[i]);
+
+       device_remove_file(dev, &dev_attr_ne_guid_vendor_oui);
+       device_remove_file(dev, &dev_attr_ne_vendor_name);
+       device_remove_file(dev, &dev_attr_ne_vendor_oui);
+
+       device_unregister(dev);
+}
+
+
+static void nodemgr_remove_host_dev(struct device *dev)
+{
+       int i;
+       struct list_head *lh, *next;
+
+       list_for_each_safe(lh, next, &dev->children) {
+               struct node_entry *ne;
+               ne = container_of(list_to_dev(lh), struct node_entry, device);
+               nodemgr_remove_ne(ne);
+       }
+
+       for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++)
+               device_remove_file(dev, fw_host_attrs[i]);
 
-       return len;
+       sysfs_remove_link(&dev->kobj, "irm_id");
+       sysfs_remove_link(&dev->kobj, "busmgr_id");
+       sysfs_remove_link(&dev->kobj, "host_id");
 }
 
-#undef PUTF
-#endif /* CONFIG_PROC_FS */
 
-static void nodemgr_process_config_rom(struct node_entry *ne, 
-                                      quadlet_t busoptions);
+static struct device nodemgr_dev_template_ud = {
+       .bus            = &ieee1394_bus_type,
+       .release        = nodemgr_release_ud,
+       .class_num      = DEV_CLASS_UNIT_DIRECTORY,
+};
+
+static struct device nodemgr_dev_template_ne = {
+       .bus            = &ieee1394_bus_type,
+       .release        = nodemgr_release_ne,
+       .class_num      = DEV_CLASS_NODE,
+};
+
+static struct device nodemgr_dev_template_host = {
+       .bus            = &ieee1394_bus_type,
+       .class_num      = DEV_CLASS_HOST,
+};
+
+
+static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
+                           char *buffer, int buffer_size);
+
+
+struct bus_type ieee1394_bus_type = {
+       .name           = "ieee1394",
+       .match          = nodemgr_bus_match,
+       .hotplug        = nodemgr_hotplug,
+};
+
 
 static int nodemgr_read_quadlet(struct hpsb_host *host,
                                nodeid_t nodeid, unsigned int generation,
@@ -292,7 +595,8 @@ static int nodemgr_read_text_leaf(struct node_entry *ne,
        ret = -ENXIO;
        for (; size > 0; size--, address += 4, quadp++) {
                for (i = 0; i < 3; i++) {
-                       ret = hpsb_read(ne->host, ne->nodeid, ne->generation, address, quadp, 4);
+                       
+                       ret = hpsb_node_read(ne, address, quadp, 4);
                        if (ret != -EAGAIN)
                                break;
                }
@@ -349,9 +653,10 @@ static struct node_entry *nodemgr_scan_root_directory
        if (!ne)
                return NULL;
 
+       memset(ne, 0, total_size);
+
        if (size != 0) {
-               ne->vendor_name
-                       = (const char *) &(ne->quadlets[2]);
+               ne->vendor_name = (const char *) &(ne->quadlets[2]);
                ne->quadlets[size] = 0;
        } else {
                ne->vendor_name = NULL;
@@ -360,62 +665,129 @@ static struct node_entry *nodemgr_scan_root_directory
        return ne; 
 }
 
+
+static void nodemgr_process_config_rom(struct host_info *hi,
+               struct node_entry *ne, quadlet_t busoptions);
+
 static struct node_entry *nodemgr_create_node(octlet_t guid, quadlet_t busoptions,
-                                             struct hpsb_host *host,
-                                             nodeid_t nodeid, unsigned int generation)
+                                             struct host_info *hi, nodeid_t nodeid,
+                                             unsigned int generation)
 {
+       struct hpsb_host *host = hi->host;
         struct node_entry *ne;
 
        ne = nodemgr_scan_root_directory (host, nodeid, generation);
         if (!ne) return NULL;
 
-        INIT_LIST_HEAD(&ne->list);
-       INIT_LIST_HEAD(&ne->unit_directories);
-
        ne->tpool = &host->tpool[nodeid & NODE_MASK];
 
         ne->host = host;
         ne->nodeid = nodeid;
-        ne->guid = guid;
        ne->generation = generation;
 
-        list_add_tail(&ne->list, &node_list);
+        ne->guid = guid;
+       ne->guid_vendor_id = (guid >> 40) & 0xffffff;
+       ne->guid_vendor_oui = nodemgr_find_oui_name(ne->guid_vendor_id);
+
+       memcpy(&ne->device, &nodemgr_dev_template_ne,
+              sizeof(ne->device));
+       ne->device.parent = &host->device;
+       snprintf(ne->device.bus_id, BUS_ID_SIZE, "%016Lx",
+                (unsigned long long)(ne->guid));
+       snprintf(ne->device.name, DEVICE_NAME_SIZE,
+                "IEEE-1394 device %d-" NODE_BUS_FMT, hi->id,
+                NODE_BUS_ARGS(ne->nodeid));
+
+       device_register(&ne->device);
+
+       if (ne->guid_vendor_oui)
+               device_create_file(&ne->device, &dev_attr_ne_guid_vendor_oui);
+       nodemgr_create_ne_dev_files(ne);
 
-       nodemgr_process_config_rom (ne, busoptions);
+       nodemgr_process_config_rom (hi, ne, busoptions);
 
-       HPSB_DEBUG("%s added: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s] (%s)",
+       nodemgr_update_ud_names(hi, ne);
+
+       HPSB_DEBUG("%s added: ID:BUS[%d-" NODE_BUS_FMT "]  GUID[%016Lx]",
                   (host->node_id == nodeid) ? "Host" : "Node",
-                  NODE_BUS_ARGS(nodeid), (unsigned long long)guid,
-                  ne->oui_name,
-                  ne->vendor_name ?: "Unknown");
+                  hi->id, NODE_BUS_ARGS(nodeid), (unsigned long long)guid);
 
         return ne;
 }
 
-static struct node_entry *find_entry_by_guid(u64 guid)
+
+struct guid_search_baton {
+       u64 guid;
+       struct node_entry *ne;
+};
+
+static int nodemgr_guid_search_cb(struct device *dev, void *__data)
 {
-        struct list_head *lh;
+        struct guid_search_baton *search = __data;
         struct node_entry *ne;
-        
-        list_for_each(lh, &node_list) {
-                ne = list_entry(lh, struct node_entry, list);
-                if (ne->guid == guid) return ne;
-        }
 
-        return NULL;
+        if (dev->class_num != DEV_CLASS_NODE)
+                return 0;
+
+        ne = container_of(dev, struct node_entry, device);
+
+        if (ne->guid == search->guid) {
+               search->ne = ne;
+               return 1;
+       }
+
+       return 0;
 }
 
-static struct node_entry *find_entry_by_nodeid(nodeid_t nodeid)
+static struct node_entry *find_entry_by_guid(u64 guid)
 {
-       struct list_head *lh;
+       struct guid_search_baton search;
+
+       search.guid = guid;
+       search.ne = NULL;
+
+       bus_for_each_dev(&ieee1394_bus_type, NULL, &search, nodemgr_guid_search_cb);
+
+        return search.ne;
+}
+
+
+struct nodeid_search_baton {
+       nodeid_t nodeid;
        struct node_entry *ne;
+       struct hpsb_host *host;
+};
 
-       list_for_each(lh, &node_list) {
-               ne = list_entry(lh, struct node_entry, list);
-               if (ne->nodeid == nodeid) return ne;
+static int nodemgr_nodeid_search_cb(struct device *dev, void *__data)
+{
+       struct nodeid_search_baton *search = __data;
+       struct node_entry *ne;
+
+       if (dev->class_num != DEV_CLASS_NODE)
+               return 0;
+
+       ne = container_of(dev, struct node_entry, device);
+
+       if (ne->host == search->host && ne->nodeid == search->nodeid) {
+               search->ne = ne;
+               /* Returning 1 stops the iteration */
+               return 1;
        }
 
-       return NULL;
+       return 0;
+}
+
+static struct node_entry *find_entry_by_nodeid(struct hpsb_host *host, nodeid_t nodeid)
+{
+       struct nodeid_search_baton search;
+
+       search.nodeid = nodeid;
+       search.ne = NULL;
+       search.host = host;
+
+       bus_for_each_dev(&ieee1394_bus_type, NULL, &search, nodemgr_nodeid_search_cb);
+
+       return search.ne;
 }
 
 static struct unit_directory *nodemgr_scan_unit_directory
@@ -500,28 +872,27 @@ static struct unit_directory *nodemgr_scan_unit_directory
                                return NULL;
                }
        }
+
        total_size += count * sizeof (quadlet_t);
        ud = kmalloc (total_size, GFP_KERNEL);
+
        if (ud != NULL) {
-               memset (ud, 0, sizeof *ud);
+               memset (ud, 0, total_size);
                ud->flags = flags;
-               ud->count = count;
+               ud->length = count;
                ud->vendor_name_size = vendor_name_size;
                ud->model_name_size = model_name_size;
-               /* If there is no vendor name in the unit directory,
-                  use the one in the root directory.  */
-               ud->vendor_name = ne->vendor_name;
        }
+
        return ud;
 }
 
+
 /* This implementation currently only scans the config rom and its
  * immediate unit directories looking for software_id and
- * software_version entries, in order to get driver autoloading working.
- */
-
-static void nodemgr_process_unit_directory(struct node_entry *ne, 
-                                          octlet_t address)
+ * software_version entries, in order to get driver autoloading working. */
+static void nodemgr_process_unit_directory(struct host_info *hi, struct node_entry *ne, 
+                                          octlet_t address, unsigned int id)
 {
        struct unit_directory *ud;
        quadlet_t quad;
@@ -533,6 +904,7 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
 
        ud->ne = ne;
        ud->address = address;
+       ud->id = id;
 
        if (nodemgr_read_quadlet(ne->host, ne->nodeid, ne->generation,
                                 address, &quad))
@@ -556,14 +928,16 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
                case CONFIG_ROM_VENDOR_ID:
                        ud->vendor_id = value;
                        ud->flags |= UNIT_DIRECTORY_VENDOR_ID;
+
+                       if (ud->vendor_id)
+                               ud->vendor_oui = nodemgr_find_oui_name(ud->vendor_id);
+
                        if ((ud->flags & UNIT_DIRECTORY_VENDOR_TEXT) != 0) {
                                length--;
                                address += 4;
-                               quadp = &(ud->quadlets[ud->count]);
-                               if (nodemgr_read_text_leaf(ne, address,
-                                                          quadp) == 0
-                                   && quadp[0] == 0
-                                   && quadp[1] == 0) {
+                               quadp = &(ud->quadlets[ud->length]);
+                               if (nodemgr_read_text_leaf(ne, address, quadp) == 0
+                                   && quadp[0] == 0 && quadp[1] == 0) {
                                        /* We only support minimal
                                           ASCII and English. */
                                        quadp[ud->vendor_name_size] = 0;
@@ -579,11 +953,9 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
                        if ((ud->flags & UNIT_DIRECTORY_MODEL_TEXT) != 0) {
                                length--;
                                address += 4;
-                               quadp = &(ud->quadlets[ud->count + ud->vendor_name_size + 1]);
-                               if (nodemgr_read_text_leaf(ne, address,
-                                                          quadp) == 0
-                                   && quadp[0] == 0
-                                   && quadp[1] == 0) {
+                               quadp = &(ud->quadlets[ud->length + ud->vendor_name_size + 1]);
+                               if (nodemgr_read_text_leaf(ne, address, quadp) == 0
+                                   && quadp[0] == 0 && quadp[1] == 0) {
                                        /* We only support minimal
                                           ASCII and English. */
                                        quadp[ud->model_name_size] = 0;
@@ -619,8 +991,17 @@ static void nodemgr_process_unit_directory(struct node_entry *ne,
                }
        }
 
-       list_add_tail(&ud->node_list, &ne->unit_directories);
-       list_add_tail(&ud->driver_list, &unit_directory_list);
+       memcpy(&ud->device, &nodemgr_dev_template_ud,
+              sizeof(ud->device));
+       ud->device.parent = &ne->device;
+       snprintf(ud->device.bus_id, BUS_ID_SIZE, "%s-%u",
+                ne->device.bus_id, ud->id);
+
+       device_register(&ud->device);
+
+       if (ud->vendor_oui)
+               device_create_file(&ud->device, &dev_attr_ud_vendor_oui);
+       nodemgr_create_ud_dev_files(ud);
 
        return;
 
@@ -657,11 +1038,12 @@ static void dump_directories (struct node_entry *ne)
        return;
 }
 
-static void nodemgr_process_root_directory(struct node_entry *ne)
+static void nodemgr_process_root_directory(struct host_info *hi, struct node_entry *ne)
 {
        octlet_t address;
        quadlet_t quad;
        int length;
+       unsigned int ud_id = 0;
 
        address = CSR_REGISTER_BASE + CSR_CONFIG_ROM;
        
@@ -688,24 +1070,23 @@ static void nodemgr_process_root_directory(struct node_entry *ne)
                switch (code) {
                case CONFIG_ROM_VENDOR_ID:
                        ne->vendor_id = value;
-#ifdef CONFIG_IEEE1394_OUI_DB
-                       ne->oui_name = nodemgr_find_oui_name(value);
-#else
-                       ne->oui_name = "Unknown";
-#endif
+
+                       if (ne->vendor_id)
+                               ne->vendor_oui = nodemgr_find_oui_name(ne->vendor_id);
+
                        /* Now check if there is a vendor name text
                           string.  */
                        if (ne->vendor_name != NULL) {
                                length--;
                                address += 4;
-                               if (nodemgr_read_text_leaf(ne, address,
-                                                          ne->quadlets)
-                                   != 0
-                                   || ne->quadlets [0] != 0
-                                   || ne->quadlets [1] != 0)
+                               if (nodemgr_read_text_leaf(ne, address, ne->quadlets) != 0
+                                   || ne->quadlets[0] != 0 || ne->quadlets[1] != 0)
                                        /* We only support minimal
                                           ASCII and English. */
                                        ne->vendor_name = NULL;
+                               else
+                                       device_create_file(&ne->device,
+                                               &dev_attr_ne_vendor_name);
                        }
                        break;
 
@@ -714,7 +1095,7 @@ static void nodemgr_process_root_directory(struct node_entry *ne)
                        break;
 
                case CONFIG_ROM_UNIT_DIRECTORY:
-                       nodemgr_process_unit_directory(ne, address + value * 4);
+                       nodemgr_process_unit_directory(hi, ne, address + value * 4, ud_id++);
                        break;                  
 
                case CONFIG_ROM_DESCRIPTOR_LEAF:
@@ -729,208 +1110,94 @@ static void nodemgr_process_root_directory(struct node_entry *ne)
 
 #ifdef CONFIG_HOTPLUG
 
-static void nodemgr_call_policy(char *verb, struct unit_directory *ud)
+static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
+                          char *buffer, int buffer_size)
 {
-       char *argv [3], **envp, *buf, *scratch;
-       int i = 0, value;
+       struct unit_directory *ud;
+       char *scratch;
+       int i = 0;
+       int length = 0;
 
-       /* User requested to disable hotplug when module was loaded. */
-       if (nodemgr_disable_hotplug)
-               return;
+       if (!dev)
+               return -ENODEV;
 
-       if (!hotplug_path [0])
-               return;
-       if (!current->fs->root)
-               return;
-       if (!(envp = (char **) kmalloc(20 * sizeof (char *), GFP_KERNEL))) {
-               HPSB_DEBUG ("ENOMEM");
-               return;
-       }
-       if (!(buf = kmalloc(256, GFP_KERNEL))) {
-               kfree(envp);
-               HPSB_DEBUG("ENOMEM2");
-               return;
-       }
+       if (dev->class_num != DEV_CLASS_UNIT_DIRECTORY)
+               return -ENODEV;
 
-       /* only one standardized param to hotplug command: type */
-       argv[0] = hotplug_path;
-       argv[1] = "ieee1394";
-       argv[2] = 0;
+       ud = container_of(dev, struct unit_directory, device);
 
-       /* minimal command environment */
-       envp[i++] = "HOME=/";
-       envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
+       scratch = buffer;
 
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-       /* hint that policy agent should enter no-stdout debug mode */
-       envp[i++] = "DEBUG=kernel";
-#endif
-       /* extensible set of named bus-specific parameters,
-        * supporting multiple driver selection algorithms.
-        */
-       scratch = buf;
-
-       envp[i++] = scratch;
-       scratch += sprintf(scratch, "ACTION=%s", verb) + 1;
-       envp[i++] = scratch;
-       scratch += sprintf(scratch, "VENDOR_ID=%06x", ud->ne->vendor_id) + 1;
-       envp[i++] = scratch;
-       scratch += sprintf(scratch, "GUID=%016Lx", (long long unsigned)ud->ne->guid) + 1;
-       envp[i++] = scratch;
-       scratch += sprintf(scratch, "SPECIFIER_ID=%06x", ud->specifier_id) + 1;
-       envp[i++] = scratch;
-       scratch += sprintf(scratch, "VERSION=%06x", ud->version) + 1;
-       envp[i++] = 0;
-
-       /* NOTE: user mode daemons can call the agents too */
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-       HPSB_DEBUG("NodeMgr: %s %s %016Lx", argv[0], verb, (long long unsigned)ud->ne->guid);
-#endif
-       value = call_usermodehelper(argv[0], argv, envp, 0);
-       kfree(buf);
-       kfree(envp);
-       if (value != 0)
-               HPSB_DEBUG("NodeMgr: hotplug policy returned %d", value);
-}
+#define PUT_ENVP(fmt,val)                                      \
+do {                                                           \
+       envp[i++] = scratch;                                    \
+       length += snprintf(scratch, buffer_size - length,       \
+                          fmt, val);                           \
+       if ((buffer_size - length <= 0) || (i >= num_envp))     \
+               return -ENOMEM;                                 \
+       ++length;                                               \
+       scratch = buffer + length;                              \
+} while(0)
 
-#else
+       PUT_ENVP("VENDOR_ID=%06x", ud->vendor_id);
+       PUT_ENVP("MODEL_ID=%06x", ud->model_id);
+       PUT_ENVP("GUID=%016Lx", (unsigned long long)ud->ne->guid);
+       PUT_ENVP("SPECIFIER_ID=%06x", ud->specifier_id);
+       PUT_ENVP("VERSION=%06x", ud->version);
 
-static inline void
-nodemgr_call_policy(char *verb, struct unit_directory *ud)
-{
-#ifdef CONFIG_IEEE1394_VERBOSEDEBUG
-       HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled");
-#endif
-       return;
-} 
+#undef PUT_ENVP
 
-#endif /* CONFIG_HOTPLUG */
+       envp[i] = 0;
 
-static void nodemgr_claim_unit_directory(struct unit_directory *ud,
-                                        struct hpsb_protocol_driver *driver)
-{
-       ud->driver = driver;
-       list_del(&ud->driver_list);
-       list_add_tail(&ud->driver_list, &driver->unit_directories);
+       return 0;
 }
 
-static void nodemgr_release_unit_directory(struct unit_directory *ud)
-{
-       ud->driver = NULL;
-       list_del(&ud->driver_list);
-       list_add_tail(&ud->driver_list, &unit_directory_list);
-}
+#else
 
-void hpsb_release_unit_directory(struct unit_directory *ud)
+static int nodemgr_hotplug(struct device *dev, char **envp, int num_envp,
+                          char *buffer, int buffer_size)
 {
-       down(&nodemgr_serialize);
-       nodemgr_release_unit_directory(ud);
-       up(&nodemgr_serialize);
-}
+       return -ENODEV;
+} 
 
-static void nodemgr_free_unit_directories(struct node_entry *ne)
-{
-       struct list_head *lh;
-       struct unit_directory *ud;
+#endif /* CONFIG_HOTPLUG */
 
-       lh = ne->unit_directories.next;
-       while (lh != &ne->unit_directories) {
-               ud = list_entry(lh, struct unit_directory, node_list);
-               lh = lh->next;
-               if (ud->driver && ud->driver->disconnect)
-                       ud->driver->disconnect(ud);
-               nodemgr_release_unit_directory(ud);
-               nodemgr_call_policy("remove", ud);
-               list_del(&ud->driver_list);
-               kfree(ud);
-       }
-}
 
-static struct ieee1394_device_id *
-nodemgr_match_driver(struct hpsb_protocol_driver *driver, 
-                    struct unit_directory *ud)
+static int nodemgr_alloc_host_num(void)
 {
-       struct ieee1394_device_id *id;
+       int hostnum = 0;
+       unsigned long flags;
+       struct list_head *lh;
 
-       for (id = driver->id_table; id->match_flags != 0; id++) {
-               if ((id->match_flags & IEEE1394_MATCH_VENDOR_ID) &&
-                   id->vendor_id != ud->vendor_id)
-                       continue;
+       spin_lock_irqsave (&host_info_lock, flags);
 
-               if ((id->match_flags & IEEE1394_MATCH_MODEL_ID) &&
-                   id->model_id != ud->model_id)
-                       continue;
+       while (1) {
+               int found = 0;
 
-               if ((id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) &&
-                   id->specifier_id != ud->specifier_id)
-                       continue;
+               list_for_each(lh, &host_info_list) {
+                       struct host_info *hi = list_entry(lh, struct host_info, list);
+                       if (hi->id == hostnum) {
+                               found = 1;
+                               break;
+                       }
+               }
 
-               if ((id->match_flags & IEEE1394_MATCH_VERSION) &&
-                   id->version != ud->version)
-                       continue;
+               if (!found)
+                       break;
 
-               return id;
+               hostnum++;
        }
 
-       return NULL;
-}
-
-static struct hpsb_protocol_driver *
-nodemgr_find_driver(struct unit_directory *ud)
-{
-       struct list_head *l;
-       struct hpsb_protocol_driver *match, *driver;
-       struct ieee1394_device_id *device_id;
-
-       match = NULL;
-       list_for_each(l, &driver_list) {
-               driver = list_entry(l, struct hpsb_protocol_driver, list);
-               device_id = nodemgr_match_driver(driver, ud);
-
-               if (device_id != NULL) {
-                       match = driver;
-                       break;
-               }
-       }
+       spin_unlock_irqrestore (&host_info_lock, flags);
 
-       return match;
+       return hostnum;
 }
 
-static void nodemgr_bind_drivers (struct node_entry *ne)
-{
-       struct list_head *lh;
-       struct hpsb_protocol_driver *driver;
-       struct unit_directory *ud;
-
-       list_for_each(lh, &ne->unit_directories) {
-               ud = list_entry(lh, struct unit_directory, node_list);
-               driver = nodemgr_find_driver(ud);
-               if (driver != NULL && driver->probe(ud) == 0)
-                       nodemgr_claim_unit_directory(ud, driver);
-               nodemgr_call_policy("add", ud);
-       }
-}
 
 int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
 {
-       struct unit_directory *ud;
-       struct list_head *lh;
-
-       if (down_interruptible(&nodemgr_serialize))
-               return -EINTR;
-
-       list_add_tail(&driver->list, &driver_list);
-
-       INIT_LIST_HEAD(&driver->unit_directories);
-       lh = unit_directory_list.next;
-       while (lh != &unit_directory_list) {
-               ud = list_entry(lh, struct unit_directory, driver_list);
-               lh = lh->next;
-               if (nodemgr_match_driver(driver, ud) && driver->probe(ud) == 0)
-                       nodemgr_claim_unit_directory(ud, driver);
-       }
-
-       up(&nodemgr_serialize);
+       driver_register(&driver->driver);
+       nodemgr_create_drv_files(driver);
 
        /*
         * Right now registration always succeeds, but maybe we should
@@ -942,26 +1209,14 @@ int hpsb_register_protocol(struct hpsb_protocol_driver *driver)
 
 void hpsb_unregister_protocol(struct hpsb_protocol_driver *driver)
 {
-       struct list_head *lh;
-       struct unit_directory *ud;
-
-       down(&nodemgr_serialize);
-
-       list_del(&driver->list);
-       lh = driver->unit_directories.next;
-       while (lh != &driver->unit_directories) {
-               ud = list_entry(lh, struct unit_directory, driver_list);
-               lh = lh->next;
-               if (ud->driver && ud->driver->disconnect)
-                       ud->driver->disconnect(ud);
-               nodemgr_release_unit_directory(ud);
-       }
-
-       up(&nodemgr_serialize);
+       nodemgr_remove_drv_files(driver);
+       /* This will subsequently disconnect all devices that our driver
+        * is attached to. */
+       driver_unregister(&driver->driver);
 }
 
-static void nodemgr_process_config_rom(struct node_entry *ne, 
-                                      quadlet_t busoptions)
+static void nodemgr_process_config_rom(struct host_info *hi,
+               struct node_entry *ne, quadlet_t busoptions)
 {
        ne->busopt.irmc         = (busoptions >> 31) & 1;
        ne->busopt.cmc          = (busoptions >> 30) & 1;
@@ -981,16 +1236,42 @@ static void nodemgr_process_config_rom(struct node_entry *ne,
                   ne->busopt.cyc_clk_acc, ne->busopt.max_rec,
                   ne->busopt.generation, ne->busopt.lnkspd);
 #endif
+       device_remove_file(&ne->device, &dev_attr_ne_vendor_oui);
 
-       /*
-        * When the config rom changes we disconnect all drivers and
-        * free the cached unit directories and reread the whole
-        * thing.  If this was a new device, the call to
-        * nodemgr_disconnect_drivers is a no-op and all is well.
-        */
-       nodemgr_free_unit_directories(ne);
-       nodemgr_process_root_directory(ne);
-       nodemgr_bind_drivers(ne);
+       nodemgr_process_root_directory(hi, ne);
+
+       if (ne->vendor_oui)
+               device_create_file(&ne->device, &dev_attr_ne_vendor_oui);
+}
+
+
+/* Searches the list of ud's that match a ne as the parent. If the ud has
+ * a driver associated with it, we call that driver's update function
+ * with the ud as the argument. */
+static int nodemgr_driver_search_cb(struct device *dev, void *__data)
+{
+       struct node_entry *ne = __data;
+       struct unit_directory *ud;
+
+       if (dev->class_num != DEV_CLASS_UNIT_DIRECTORY)
+               return 0;
+
+       ud = container_of(dev, struct unit_directory, device);
+
+       if (&ne->device != ud->device.parent)
+               return 0;
+
+       if (ud->device.driver) {
+               struct hpsb_protocol_driver *pdrv;
+
+               pdrv = container_of(ud->device.driver,
+                               struct hpsb_protocol_driver, driver);
+
+               if (pdrv->update)
+                       pdrv->update(ud);
+       }
+
+       return 0;
 }
 
 /*
@@ -1001,29 +1282,42 @@ static void nodemgr_process_config_rom(struct node_entry *ne,
  * the to take whatever actions required.
  */
 static void nodemgr_update_node(struct node_entry *ne, quadlet_t busoptions,
-                               struct hpsb_host *host,
-                               nodeid_t nodeid, unsigned int generation)
+                               struct host_info *hi, nodeid_t nodeid,
+                               unsigned int generation)
 {
-       struct list_head *lh;
-       struct unit_directory *ud;
+       int update_ud_names = 0;
 
        if (ne->nodeid != nodeid) {
+               snprintf(ne->device.name, DEVICE_NAME_SIZE,
+                        "IEEE-1394 device %d-" NODE_BUS_FMT,
+                        hi->id, NODE_BUS_ARGS(ne->nodeid));
                HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT,
                           NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid));
                ne->nodeid = nodeid;
+
+               update_ud_names++;
+       }
+
+       if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) {
+               /* If the node's configrom generation has changed, we
+                * unregister all the unit directories. */
+               nodemgr_remove_node_uds(ne);
+
+               /* This will re-register our unitdir's */
+               nodemgr_process_config_rom (hi, ne, busoptions);
+
+               update_ud_names++;
        }
 
-       if (ne->busopt.generation != ((busoptions >> 4) & 0xf))
-               nodemgr_process_config_rom (ne, busoptions);
+       if (update_ud_names)
+               nodemgr_update_ud_names(hi, ne);
 
        /* Since that's done, we can declare this record current */
        ne->generation = generation;
 
-       list_for_each (lh, &ne->unit_directories) {
-               ud = list_entry (lh, struct unit_directory, node_list);
-               if (ud->driver != NULL && ud->driver->update != NULL)
-                       ud->driver->update(ud);
-       }
+       /* Update unit_dirs with attached drivers */
+       bus_for_each_dev(&ieee1394_bus_type, NULL, ne,
+                        nodemgr_driver_search_cb);
 }
 
 static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation,
@@ -1087,24 +1381,13 @@ static int read_businfo_block(struct hpsb_host *host, nodeid_t nodeid, unsigned
        return 0;
 }              
 
-static void nodemgr_remove_node(struct node_entry *ne)
-{
-       HPSB_DEBUG("Device removed: Node[" NODE_BUS_FMT "]  GUID[%016Lx]  [%s]",
-                  NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid,
-                  ne->vendor_name ?: "Unknown");
-
-       nodemgr_free_unit_directories(ne);
-       list_del(&ne->list);
-       kfree(ne);
-
-       return;
-}
 
 /* This is where we probe the nodes for their information and provided
  * features.  */
-static void nodemgr_node_probe_one(struct hpsb_host *host,
+static void nodemgr_node_probe_one(struct host_info *hi,
                                   nodeid_t nodeid, int generation)
 {
+       struct hpsb_host *host = hi->host;
        struct node_entry *ne;
        quadlet_t buffer[5];
        octlet_t guid;
@@ -1132,58 +1415,48 @@ static void nodemgr_node_probe_one(struct hpsb_host *host,
        ne = find_entry_by_guid(guid);
 
        if (!ne)
-               nodemgr_create_node(guid, buffer[2], host, nodeid, generation);
+               nodemgr_create_node(guid, buffer[2], hi, nodeid, generation);
        else
-               nodemgr_update_node(ne, buffer[2], host, nodeid, generation);
+               nodemgr_update_node(ne, buffer[2], hi, nodeid, generation);
 
        return;
 }
 
-static void nodemgr_node_probe_cleanup(struct hpsb_host *host, unsigned int generation)
+
+struct cleanup_baton {
+       unsigned int generation;
+       struct hpsb_host *host;
+       struct node_entry *ne;
+};
+
+static int nodemgr_remove_node(struct device *dev, void *__data)
 {
-       struct list_head *lh, *next;
+       struct cleanup_baton *cleanup = __data;
        struct node_entry *ne;
 
-       /* Now check to see if we have any nodes that aren't referenced
-        * any longer.  */
-       list_for_each_safe(lh, next, &node_list) {
-               ne = list_entry(lh, struct node_entry, list);
+       if (dev->class_num != DEV_CLASS_NODE)
+               return 0;
 
-               /* Only checking this host */
-               if (ne->host != host)
-                       continue;
+       ne = container_of(dev, struct node_entry, device);
 
-               /* If the generation didn't get updated, then either the
-                * node was removed, or it failed the above probe. Either
-                * way, we remove references to it, since they are
-                * invalid.  */
-               if (ne->generation != generation)
-                       nodemgr_remove_node(ne);
+       if (ne->host != cleanup->host)
+               return 0;
+
+       if (ne->generation != cleanup->generation) {
+               cleanup->ne = ne;
+               return 1;
        }
 
-       return;
+       return 0;
 }
 
-static void nodemgr_node_probe(struct hpsb_host *host)
+
+static void nodemgr_node_probe(struct host_info *hi, int generation)
 {
        int count;
+       struct hpsb_host *host = hi->host;
        struct selfid *sid = (struct selfid *)host->topology_map;
        nodeid_t nodeid = LOCAL_BUS;
-       unsigned int generation;
-
-       /* Pause for 1/4 second, to make sure things settle down. If
-        * schedule_timeout returns non-zero, it means we caught a signal
-        * and need to return. */
-       set_current_state(TASK_INTERRUPTIBLE);
-       if (schedule_timeout (HZ/4))
-               return;
-
-       /* Now get the generation in which the node ID's we collect
-        * are valid.  During the bus scan we will use this generation
-        * for the read transactions, so that if another reset occurs
-        * during the scan the transactions will fail instead of
-        * returning bogus data. */
-       generation = get_hpsb_generation(host);
 
        /* Scan each node on the bus */
        for (count = host->selfid_count; count; count--, sid++) {
@@ -1194,8 +1467,7 @@ static void nodemgr_node_probe(struct hpsb_host *host)
                        nodeid++;
                        continue;
                }
-
-               nodemgr_node_probe_one(host, nodeid++, generation);
+               nodemgr_node_probe_one(hi, nodeid++, generation);
        }
 
        /* If we had a bus reset while we were scanning the bus, it is
@@ -1204,8 +1476,33 @@ static void nodemgr_node_probe(struct hpsb_host *host)
         * were still on the bus.  The bus reset increased
         * hi->reset_sem, so there's a bus scan pending which will do
         * the clean up eventually. */
-       if (generation == get_hpsb_generation(host))
-               nodemgr_node_probe_cleanup(host, generation);
+       if (generation == get_hpsb_generation(host)) {
+               struct cleanup_baton cleanup;
+
+               cleanup.generation = generation;
+               cleanup.host = host;
+
+               /* This will iterate until all devices that do not match
+                * the generation are removed. */
+               while (bus_for_each_dev(&ieee1394_bus_type, NULL, &cleanup,
+                                       nodemgr_remove_node)) {
+                       struct node_entry *ne = cleanup.ne;
+
+                       HPSB_DEBUG("Device removed: ID:BUS[" NODE_BUS_FMT "]  GUID[%016Lx]",
+                                  NODE_BUS_ARGS(ne->nodeid), (unsigned long long)ne->guid);
+
+                       nodemgr_remove_ne(ne);
+               }
+
+               /* Now let's tell the bus to rescan our devices. This may
+                * seem like overhead, but the driver-model core will only
+                * scan a device for a driver when either the device is
+                * added, or when a new driver is added. A bus reset is a
+                * good reason to rescan devices that were there before.
+                * For example, an sbp2 device may become available for
+                * login, if the host that held it was just removed. */
+               bus_rescan_devices(&ieee1394_bus_type);
+       }
 
        return;
 }
@@ -1226,8 +1523,7 @@ static void nodemgr_do_irm_duties(struct hpsb_host *host)
 
        hpsb_write(host, LOCAL_BUS | ALL_NODES, get_hpsb_generation(host),
                   (CSR_REGISTER_BASE | CSR_BROADCAST_CHANNEL),
-                  &bc,
-                  sizeof(quadlet_t));
+                  &bc, sizeof(quadlet_t));
 }
 
 /* We need to ensure that if we are not the IRM, that the IRM node is capable of
@@ -1249,7 +1545,7 @@ static int nodemgr_check_root_capability(struct hpsb_host *host)
        if (status < 0 || !(be32_to_cpu(bc) & 0x80000000)) {
                /* The root node does not have a valid BROADCAST_CHANNEL
                 * register and we do, so reset the bus with force_root set */
-               HPSB_INFO("Remote root is not IRM capable, resetting...");
+               HPSB_DEBUG("Remote root is not IRM capable, resetting...");
                hpsb_reset_bus(host, LONG_RESET_FORCE_ROOT);
                return 0;
        }
@@ -1259,27 +1555,58 @@ static int nodemgr_check_root_capability(struct hpsb_host *host)
 static int nodemgr_host_thread(void *__hi)
 {
        struct host_info *hi = (struct host_info *)__hi;
+       struct hpsb_host *host = hi->host;
 
        /* No userlevel access needed */
-       daemonize("knodemgrd");
+       daemonize(hi->daemon_name);
        allow_signal(SIGTERM);
-       
+
+       /* Setup our device-model entries */
+       device_register(&host->device);
+       nodemgr_create_host_dev_files(host);
+
        /* Sit and wait for a signal to probe the nodes on the bus. This
         * happens when we get a bus reset. */
        while (!down_interruptible(&hi->reset_sem) &&
               !down_interruptible(&nodemgr_serialize)) {
+               unsigned int generation;
+               int i;
+
+               /* Pause for 1/4 second, to make sure things settle down. */
+               for (i = HZ/4; i > 0; i-= HZ/16) {
+                       set_current_state(TASK_INTERRUPTIBLE);
+                       if (schedule_timeout(HZ/16))
+                               goto caught_signal;
+
+                       /* Now get the generation in which the node ID's we collect
+                        * are valid.  During the bus scan we will use this generation
+                        * for the read transactions, so that if another reset occurs
+                        * during the scan the transactions will fail instead of
+                        * returning bogus data. */
+                       generation = get_hpsb_generation(hi->host);
+
+                       /* If we get a reset before we are done waiting, then
+                        * start the the waiting over again */
+                       while (!down_trylock(&hi->reset_sem))
+                               i = HZ/4;
+               }
 
-               if (!nodemgr_check_root_capability(hi->host)) {
+               if (!nodemgr_check_root_capability(host)) {
                        /* Do nothing, we are resetting */
                        up(&nodemgr_serialize);
                        continue;
                }
 
-               nodemgr_node_probe(hi->host);
-               nodemgr_do_irm_duties(hi->host);
+               nodemgr_node_probe(hi, generation);
+               nodemgr_do_irm_duties(host);
+
+               /* Update some of our sysfs symlinks */
+               nodemgr_update_host_dev_links(host);
 
                up(&nodemgr_serialize);
        }
+
+caught_signal:
 #ifdef CONFIG_IEEE1394_VERBOSEDEBUG
        HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name);
 #endif
@@ -1298,24 +1625,24 @@ struct node_entry *hpsb_guid_get_entry(u64 guid)
         return ne;
 }
 
-struct node_entry *hpsb_nodeid_get_entry(nodeid_t nodeid)
+struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid)
 {
        struct node_entry *ne;
 
        down(&nodemgr_serialize);
-       ne = find_entry_by_nodeid(nodeid);
+       ne = find_entry_by_nodeid(host, nodeid);
        up(&nodemgr_serialize);
 
        return ne;
 }
 
-struct node_entry *hpsb_check_nodeid(nodeid_t nodeid)
+struct node_entry *hpsb_check_nodeid(struct hpsb_host *host, nodeid_t nodeid)
 {
        struct node_entry *ne;
 
        if (down_trylock(&nodemgr_serialize))
                return NULL;
-       ne = find_entry_by_nodeid(nodeid);
+       ne = find_entry_by_nodeid(host, nodeid);
        up(&nodemgr_serialize);
 
        return ne;
@@ -1389,23 +1716,38 @@ static void nodemgr_add_host(struct hpsb_host *host)
        /* Initialize the hostinfo here and start the thread.  The
         * thread blocks on the reset semaphore until a bus reset
         * happens. */
+       memset(hi, 0, sizeof(*hi));
        hi->host = host;
        INIT_LIST_HEAD(&hi->list);
        init_completion(&hi->exited);
         sema_init(&hi->reset_sem, 0);
 
+       hi->id = nodemgr_alloc_host_num();
+
+       memcpy(&host->device, &nodemgr_dev_template_host,
+              sizeof(host->device));
+       host->device.parent = &host->pdev->dev;
+       snprintf(host->device.bus_id, BUS_ID_SIZE, "fw-host%d", hi->id);
+       snprintf(host->device.name, DEVICE_NAME_SIZE, "IEEE-1394 Host %s-%d",
+                host->driver->name, hi->id);
+
+       sprintf(hi->daemon_name, "knodemgrd_%d", hi->id);
+
+       spin_lock_irqsave (&host_info_lock, flags);
+
        hi->pid = kernel_thread(nodemgr_host_thread, hi,
                                CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
        
        if (hi->pid < 0) {
-               HPSB_ERR ("NodeMgr: failed to start NodeMgr thread for %s",
-                         host->driver->name);
+               HPSB_ERR ("NodeMgr: failed to start %s thread for %s",
+                         hi->daemon_name, host->driver->name);
                kfree(hi);
+               spin_unlock_irqrestore (&host_info_lock, flags);
                return;
        }
 
-       spin_lock_irqsave (&host_info_lock, flags);
        list_add_tail (&hi->list, &host_info_list);
+
        spin_unlock_irqrestore (&host_info_lock, flags);
 
        return;
@@ -1442,7 +1784,6 @@ static void nodemgr_host_reset(struct hpsb_host *host)
 static void nodemgr_remove_host(struct hpsb_host *host)
 {
        struct list_head *lh, *next;
-       struct node_entry *ne;
        unsigned long flags;
        struct host_info *hi = NULL;
 
@@ -1455,31 +1796,20 @@ static void nodemgr_remove_host(struct hpsb_host *host)
                        break;
                }
        }
-       spin_unlock_irqrestore (&host_info_lock, flags);
 
        if (hi) {
                if (hi->pid >= 0) {
                        kill_proc(hi->pid, SIGTERM, 1);
                        wait_for_completion(&hi->exited);
+                       nodemgr_remove_host_dev(&host->device);
+                       device_unregister(&host->device);
                }
                kfree(hi);
-       }
-       else
+       } else
                HPSB_ERR("NodeMgr: host %s does not exist, cannot remove",
                         host->driver->name);
 
-       down(&nodemgr_serialize);
-
-       /* Even if we fail the host_info part, remove all the node
-        * entries.  */
-       list_for_each_safe(lh, next, &node_list) {
-               ne = list_entry(lh, struct node_entry, list);
-
-               if (ne->host == host)
-                       nodemgr_remove_node(ne);
-       }
-
-       up(&nodemgr_serialize);
+       spin_unlock_irqrestore (&host_info_lock, flags);
 
        return;
 }
@@ -1492,15 +1822,10 @@ static struct hpsb_highlevel_ops nodemgr_ops = {
 
 static struct hpsb_highlevel *hl;
 
-#define PROC_ENTRY "devices"
-
-void init_ieee1394_nodemgr(int disable_hotplug)
+void init_ieee1394_nodemgr(void)
 {
-       nodemgr_disable_hotplug = disable_hotplug;
-#ifdef CONFIG_PROC_FS
-       if (!create_proc_read_entry(PROC_ENTRY, 0444, ieee1394_procfs_entry, raw1394_read_proc, NULL))
-               HPSB_ERR("Can't create devices procfs entry");
-#endif
+       bus_register(&ieee1394_bus_type);
+
         hl = hpsb_register_highlevel("Node manager", &nodemgr_ops);
         if (!hl) {
                HPSB_ERR("NodeMgr: out of memory during ieee1394 initialization");
@@ -1510,7 +1835,6 @@ void init_ieee1394_nodemgr(int disable_hotplug)
 void cleanup_ieee1394_nodemgr(void)
 {
         hpsb_unregister_highlevel(hl);
-#ifdef CONFIG_PROC_FS
-       remove_proc_entry(PROC_ENTRY, ieee1394_procfs_entry);
-#endif
+
+       bus_unregister(&ieee1394_bus_type);
 }
index 64210b048116fe298531fa9a061348efe8146ebb..a419118138c8bc4e6613e31600934e3205deb724 100644 (file)
@@ -20,6 +20,8 @@
 #ifndef _IEEE1394_NODEMGR_H
 #define _IEEE1394_NODEMGR_H
 
+#include <linux/device.h>
+
 #define CONFIG_ROM_BUS_INFO_LENGTH(q)          ((q) >> 24)
 #define CONFIG_ROM_BUS_CRC_LENGTH(q)           (((q) >> 16) & 0xff)
 #define CONFIG_ROM_BUS_CRC(q)                  ((q) & 0xffff)
@@ -76,6 +78,12 @@ struct bus_options {
        u16     max_rec;        /* Maximum packet size node can receive */
 };
 
+enum {
+       DEV_CLASS_NODE,
+       DEV_CLASS_UNIT_DIRECTORY,
+       DEV_CLASS_HOST,
+};
+
 #define UNIT_DIRECTORY_VENDOR_ID       0x01
 #define UNIT_DIRECTORY_MODEL_ID                0x02
 #define UNIT_DIRECTORY_SPECIFIER_ID    0x04
@@ -87,18 +95,16 @@ struct bus_options {
  * A unit directory corresponds to a protocol supported by the
  * node. If a node supports eg. IP/1394 and AV/C, its config rom has a
  * unit directory for each of these protocols.
- * 
- * Unit directories appear on two types of lists: for each node we
- * maintain a list of the unit directories found in its config rom and
- * for each driver we maintain a list of the unit directories
- * (ie. devices) the driver manages.
  */
 struct unit_directory {
        struct node_entry *ne;  /* The node which this directory belongs to */
        octlet_t address;       /* Address of the unit directory on the node */
        u8 flags;               /* Indicates which entries were read */
+
        quadlet_t vendor_id;
        const char *vendor_name;
+       const char *vendor_oui;
+
        int vendor_name_size;
        quadlet_t model_id;
        const char *model_name;
@@ -106,22 +112,21 @@ struct unit_directory {
        quadlet_t specifier_id;
        quadlet_t version;
 
-       struct hpsb_protocol_driver *driver;
-       void *driver_data;
+       unsigned int id;
 
-       /* For linking the nodes managed by the driver, or unmanaged nodes */
-       struct list_head driver_list;
+       int length;             /* Number of quadlets */
 
-       /* For linking directories belonging to a node */
-       struct list_head node_list;
+       struct device device;
 
-       int count;              /* Number of quadlets */
+       /* XXX Must be last in the struct! */
        quadlet_t quadlets[0];
 };
 
 struct node_entry {
-       struct list_head list;
        u64 guid;                       /* GUID of this node */
+       u32 guid_vendor_id;             /* Top 24bits of guid */
+       const char *guid_vendor_oui;    /* OUI name of guid vendor id */
+
        struct hpsb_host *host;         /* Host this node is attached to */
        nodeid_t nodeid;                /* NodeID */
        struct bus_options busopt;      /* Bus Options */
@@ -129,14 +134,16 @@ struct node_entry {
 
        /* The following is read from the config rom */
        u32 vendor_id;
+       const char *vendor_name;
+       const char *vendor_oui;
+
        u32 capabilities;       
-       struct list_head unit_directories;
 
        struct hpsb_tlabel_pool *tpool;
 
-       const char *vendor_name;
-       char *oui_name;
+       struct device device;
 
+       /* XXX Must be last in the struct! */
        quadlet_t quadlets[0];
 };
 
@@ -154,11 +161,11 @@ struct node_entry *hpsb_guid_get_entry(u64 guid);
 
 /* Same as above, but use the nodeid to get an node entry. This is not
  * fool-proof by itself, since the nodeid can change.  */
-struct node_entry *hpsb_nodeid_get_entry(nodeid_t nodeid);
+struct node_entry *hpsb_nodeid_get_entry(struct hpsb_host *host, nodeid_t nodeid);
 
 /* Same as above except that it will not block waiting for the nodemgr
  * serialize semaphore.  */
-struct node_entry *hpsb_check_nodeid(nodeid_t nodeid);
+struct node_entry *hpsb_check_nodeid(struct hpsb_host *host, nodeid_t nodeid);
 
 /*
  * If the entry refers to a local host, this function will return the pointer
@@ -188,7 +195,7 @@ int hpsb_node_lock(struct node_entry *ne, u64 addr,
                   int extcode, quadlet_t *data, quadlet_t arg);
 
 
-void init_ieee1394_nodemgr(int disable_hotplug);
+void init_ieee1394_nodemgr(void);
 void cleanup_ieee1394_nodemgr(void);
 
 #endif /* _IEEE1394_NODEMGR_H */
index 9da0dce7b83fe4bb03855c547fba480bf0bd98d2..c1b4693080169d280e4596ac823a9a579741cf8f 100644 (file)
  * Manfred Weihs <weihs@ict.tuwien.ac.at>
  *  . Reworked code for initiating bus resets
  *    (long, short, with or without hold-off)
+ *
+ * Nandu Santhi <contactnandu@users.sourceforge.net>
+ *  . Added support for nVidia nForce2 onboard Firewire chipset
+ *
  */
 
 #include <linux/config.h>
@@ -90,6 +94,7 @@
 #include <linux/wait.h>
 #include <linux/errno.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/pci.h>
 #include <linux/fs.h>
 #include <linux/poll.h>
@@ -145,7 +150,7 @@ printk(KERN_INFO "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 #define OHCI_DMA_FREE(fmt, args...) \
        HPSB_ERR("%s(%s)free(%d): "fmt, OHCI1394_DRIVER_NAME, __FUNCTION__, \
                --global_outstanding_dmas, ## args)
-u32 global_outstanding_dmas = 0;
+static int global_outstanding_dmas = 0;
 #else
 #define OHCI_DMA_ALLOC(fmt, args...)
 #define OHCI_DMA_FREE(fmt, args...)
@@ -160,12 +165,12 @@ printk(level "%s: " fmt "\n" , OHCI1394_DRIVER_NAME , ## args)
 printk(level "%s_%d: " fmt "\n" , OHCI1394_DRIVER_NAME, card , ## args)
 
 static char version[] __devinitdata =
-       "$Rev: 801 $ Ben Collins <bcollins@debian.org>";
+       "$Rev: 858 $ Ben Collins <bcollins@debian.org>";
 
 /* Module Parameters */
-MODULE_PARM(phys_dma,"i");
-MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1).");
 static int phys_dma = 1;
+module_param(phys_dma, int, 0644);
+MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1).");
 
 static void dma_trm_tasklet(unsigned long data);
 static void dma_trm_reset(struct dma_trm_ctx *d);
@@ -354,10 +359,10 @@ static void handle_selfid(struct ti_ohci *ohci, struct hpsb_host *host,
 static void ohci_soft_reset(struct ti_ohci *ohci) {
        int i;
 
-       reg_write(ohci, OHCI1394_HCControlSet, 0x00010000);
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_softReset);
   
        for (i = 0; i < OHCI_LOOP_COUNT; i++) {
-               if (reg_read(ohci, OHCI1394_HCControlSet) & 0x00010000)
+               if (!reg_read(ohci, OHCI1394_HCControlSet) & OHCI1394_HCControl_softReset)
                        break;
                mdelay(1);
        }
@@ -514,7 +519,7 @@ static void ohci_initialize(struct ti_ohci *ohci)
        reg_write(ohci, OHCI1394_NodeID, 0x0000ffc0);
 
        /* Enable posted writes */
-       reg_write(ohci, OHCI1394_HCControlSet, 0x00040000);
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_postedWriteEnable);
 
        /* Clear link control register */
        reg_write(ohci, OHCI1394_LinkControlClear, 0xffffffff);
@@ -577,7 +582,7 @@ static void ohci_initialize(struct ti_ohci *ohci)
                  (OHCI1394_MAX_PHYS_RESP_RETRIES<<8));
 
        /* We don't want hardware swapping */
-       reg_write(ohci, OHCI1394_HCControlClear, 0x40000000);
+       reg_write(ohci, OHCI1394_HCControlClear, OHCI1394_HCControl_noByteSwap);
 
        /* Enable interrupts */
        reg_write(ohci, OHCI1394_IntMaskSet,
@@ -594,7 +599,7 @@ static void ohci_initialize(struct ti_ohci *ohci)
                  OHCI1394_cycleInconsistent);
 
        /* Enable link */
-       reg_write(ohci, OHCI1394_HCControlSet, 0x00020000);
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_linkEnable);
 
        buf = reg_read(ohci, OHCI1394_Version);
        PRINT(KERN_INFO, ohci->id, "OHCI-1394 %d.%d (PCI): IRQ=[%d]  "
@@ -1190,10 +1195,11 @@ static int ohci_iso_recv_init(struct hpsb_iso *iso)
                /* iso->irq_interval is in packets - translate that to blocks */
                /* (err, sort of... 1 is always the safest value) */
                recv->block_irq_interval = iso->irq_interval / recv->nblocks;
+               if(recv->block_irq_interval*4 > recv->nblocks)
+                       recv->block_irq_interval = recv->nblocks/4;
                if(recv->block_irq_interval < 1)
                        recv->block_irq_interval = 1;
-               else if(recv->block_irq_interval*4 > recv->nblocks)
-                       recv->block_irq_interval = recv->nblocks/4;
+
        } else {
                int max_packet_size;
 
@@ -2291,17 +2297,35 @@ static void ohci_irq_handler(int irq, void *dev_id,
                 * selfID phase, so we disable busReset interrupts, to
                 * avoid burying the cpu in interrupt requests. */
                spin_lock_irqsave(&ohci->event_lock, flags);
-               reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
-               if (ohci->dev->vendor == PCI_VENDOR_ID_APPLE && 
-                   ohci->dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) {
-                       udelay(10);
-                       while(reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
-                               reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+               reg_write(ohci, OHCI1394_IntMaskClear, OHCI1394_busReset);
+
+               if (ohci->check_busreset) {
+                       int loop_count = 0;
+
+                       udelay(10);
+
+                       while (reg_read(ohci, OHCI1394_IntEventSet) & OHCI1394_busReset) {
+                               reg_write(ohci, OHCI1394_IntEventClear, OHCI1394_busReset);
+
                                spin_unlock_irqrestore(&ohci->event_lock, flags);
-                               udelay(10);
+                               udelay(10);
                                spin_lock_irqsave(&ohci->event_lock, flags);
-                       }
-               }
+
+                               /* The loop counter check is to prevent the driver
+                                * from remaining in this state forever. For the
+                                * initial bus reset, the loop continues for ever
+                                * and the system hangs, until some device is plugged-in
+                                * or out manually into a port! The forced reset seems
+                                * to solve this problem. This mainly effects nForce2. */
+                               if (loop_count > 10000) {
+                                       hpsb_reset_bus(host, 1);
+                                       DBGMSG(ohci->id, "Detected bus-reset loop. Forced a bus reset!");
+                                       loop_count = 0;
+                               }
+
+                               loop_count++;
+                       }
+               }
                spin_unlock_irqrestore(&ohci->event_lock, flags);
                if (!host->in_bus_reset) {
                        DBGMSG(ohci->id, "irq_handler: Bus reset requested");
@@ -2438,6 +2462,8 @@ selfid_not_valid:
        if (event)
                PRINT(KERN_ERR, ohci->id, "Unhandled interrupt(s) 0x%08x",
                      event);
+
+       return;
 }
 
 /* Put the buffer back into the dma context */
@@ -3277,6 +3303,18 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
                ohci->selfid_swap = 1;
 #endif
 
+#ifndef PCI_DEVICE_ID_NVIDIA_NFORCE2_FW
+#define PCI_DEVICE_ID_NVIDIA_NFORCE2_FW 0x006e
+#endif
+
+       /* These chipsets require a bit of extra care when checking after
+        * a busreset.  */
+       if ((dev->vendor == PCI_VENDOR_ID_APPLE &&
+            dev->device == PCI_DEVICE_ID_APPLE_UNI_N_FW) ||
+           (dev->vendor ==  PCI_VENDOR_ID_NVIDIA &&
+            dev->device == PCI_DEVICE_ID_NVIDIA_NFORCE2_FW))
+               ohci->check_busreset = 1;
+
        /* We hardwire the MMIO length, since some CardBus adaptors
         * fail to report the right length.  Anyway, the ohci spec
         * clearly says it's 2kb, so this shouldn't be a problem. */ 
@@ -3363,7 +3401,7 @@ static int __devinit ohci1394_pci_probe(struct pci_dev *dev,
         * accessing registers in the SClk domain without LPS enabled
         * will lock up the machine.  Wait 50msec to make sure we have
         * full link enabled.  */
-       reg_write(ohci, OHCI1394_HCControlSet, 0x00080000);
+       reg_write(ohci, OHCI1394_HCControlSet, OHCI1394_HCControl_LPS);
        mdelay(50);
 
        /* Determine the number of available IR and IT contexts. */
@@ -3489,7 +3527,7 @@ static void ohci1394_pci_remove(struct pci_dev *pdev)
 static struct pci_device_id ohci1394_pci_tbl[] __devinitdata = {
        {
                .class =        PCI_CLASS_FIREWIRE_OHCI,
-               .class_mask =   ~0,
+               .class_mask =   PCI_ANY_ID,
                .vendor =       PCI_ANY_ID,
                .device =       PCI_ANY_ID,
                .subvendor =    PCI_ANY_ID,
index 234f1b153816e9a5e772f0e3f1f5696fc724daa2..8e75ca0471f6a95ad5cb6e4a877db984a39aef26 100644 (file)
@@ -233,6 +233,9 @@ struct ti_ohci {
        unsigned int selfid_swap:1;
        /* Some Apple chipset seem to swap incoming headers for us */
        unsigned int no_swap_incoming:1;
+
+       /* Force extra paranoia checking on bus-reset handling */
+       unsigned int check_busreset:1;
 };
 
 static inline int cross_bound(unsigned long addr, unsigned int size)
@@ -288,6 +291,13 @@ static inline u32 reg_read(const struct ti_ohci *ohci, int offset)
 #define OHCI1394_VendorID                     0x040
 #define OHCI1394_HCControlSet                 0x050
 #define OHCI1394_HCControlClear               0x054
+#define  OHCI1394_HCControl_noByteSwap         0x40000000
+#define  OHCI1394_HCControl_programPhyEnable   0x00800000
+#define  OHCI1394_HCControl_aPhyEnhanceEnable  0x00400000
+#define  OHCI1394_HCControl_LPS                        0x00080000
+#define  OHCI1394_HCControl_postedWriteEnable  0x00040000
+#define  OHCI1394_HCControl_linkEnable         0x00020000
+#define  OHCI1394_HCControl_softReset          0x00010000
 #define OHCI1394_SelfIDBuffer                 0x064
 #define OHCI1394_SelfIDCount                  0x068
 #define OHCI1394_IRMultiChanMaskHiSet         0x070
index de0be238d3359a904d00d75487a8222bc0eeb95f..8ae1b0c2a0b7c699d2b82489c9b4ab55daf6fc9e 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/wait.h>
 #include <linux/errno.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/fs.h>
@@ -71,8 +72,8 @@
 
 
 /* Module Parameters */
-MODULE_PARM(skip_eeprom,"i");
-MODULE_PARM_DESC(skip_eeprom, "Do not try to read bus info block from serial eeprom, but user generic one (default = 0).");
+module_param(skip_eeprom, int, 0444);
+MODULE_PARM_DESC(skip_eeprom, "Use generic bus info block instead of serial eeprom (default = 0).");
 static int skip_eeprom = 0;
 
 
@@ -983,8 +984,9 @@ loff_t mem_llseek(struct file *file, loff_t offs, int orig)
  * on performance - the value 2400 was found by experiment and may not work
  * everywhere as good as here - use mem_mindma option for modules to change 
  */
-short mem_mindma = 2400;
-MODULE_PARM(mem_mindma, "h");
+static short mem_mindma = 2400;
+module_param(mem_mindma, short, 0444);
+MODULE_PARM_DESC(mem_mindma, "Minimum amount of data required to use DMA");
 
 static ssize_t mem_dmaread(struct memdata *md, u32 physbuf, ssize_t count,
                            int offset)
index dbeb597a683e788cdf473d919acc34cba26099ce..1910d0515ac241377bac7a6994c6cc6f75b24f48 100644 (file)
  * driver. It also registers as a SCSI lower-level driver in order to accept
  * SCSI commands for transport using SBP-2.
  *
- * The easiest way to add/detect new SBP-2 devices is to run the shell script
- * rescan-scsi-bus.sh (or re-load the SBP-2 driver). This script may be 
- * found at:
- * http://www.garloff.de/kurt/linux/rescan-scsi-bus.sh
- *
- * As an alternative, you may manually add/remove SBP-2 devices via the procfs with
- * add-single-device <h> <b> <t> <l> or remove-single-device <h> <b> <t> <l>, where:
- *     <h> = host (starting at zero for first SCSI adapter)
- *     <b> = bus (normally zero)
- *     <t> = target (starting at zero for first SBP-2 device)
- *     <l> = lun (normally zero)
- *
- * e.g. To manually add/detect a new SBP-2 device
- *     echo "scsi add-single-device 0 0 0 0" > /proc/scsi/scsi
- *
- * e.g. To manually remove a SBP-2 device after it's been unplugged
- *     echo "scsi remove-single-device 0 0 0 0" > /proc/scsi/scsi
- *
- * e.g. To check to see which SBP-2/SCSI devices are currently registered
- *     cat /proc/scsi/scsi
- *
- * After scanning for new SCSI devices (above), you may access any attached 
- * SBP-2 storage devices as if they were SCSI devices (e.g. mount /dev/sda1, 
- * fdisk, mkfs, etc.).
+ * You may access any attached SBP-2 storage devices as if they were SCSI
+ * devices (e.g. mount /dev/sda1,  fdisk, mkfs, etc.).
  *
  *
  * Module Load Options:
  *
- * sbp2_max_speed              - Force max speed allowed 
- *                               (2 = 400mb, 1 = 200mb, 0 = 100mb. default = 2)
- * sbp2_serialize_io           - Serialize all I/O coming down from the scsi drivers
- *                               (0 = deserialized, 1 = serialized, default = 0)
- * sbp2_max_sectors,           - Change max sectors per I/O supported (default = 255)
- * sbp2_exclusive_login                - Set to zero if you'd like to allow multiple hosts the ability
- *                               to log in at the same time. Sbp2 device must support this,
- *                               and you must know what you're doing (default = 1)
+ * max_speed           - Force max speed allowed 
+ *                       (2 = 400mb, 1 = 200mb, 0 = 100mb. default = 2)
+ * serialize_io                - Serialize all I/O coming down from the scsi drivers
+ *                       (0 = deserialized, 1 = serialized, default = 0)
+ * max_sectors,        - Change max sectors per I/O supported (default = 255)
+ * exclusive_login     - Set to zero if you'd like to allow multiple hosts the ability
+ *                       to log in at the same time. Sbp2 device must support this,
+ *                       and you must know what you're doing (default = 1)
  *
- * (e.g. insmod sbp2 sbp2_serialize_io = 1)
+ * (e.g. insmod sbp2 sbp2.serialize_io = 1)
  *
  *
  * Current Support:
  *                * New packet dump debug define (CONFIG_IEEE1394_SBP2_PACKET_DUMP) which allows
  *                  dumping of all sbp2 related packets sent and received. Especially effective
  *                  when phys dma is disabled on ohci controller (e.g. insmod ohci1394 phys_dma=0).
- *                * Added new sbp2 module load option (sbp2_exclusive_login) for allowing
+ *                * Added new sbp2 module load option (exclusive_login) for allowing
  *                  non-exclusive login to sbp2 device, for special multi-host applications.
  *     04/23/02 - Fix for Sony CD-ROM drives. Only send fetch agent reset to sbp2 device if it
  *                returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one.
 #include <linux/fs.h>
 #include <linux/poll.h>
 #include <linux/module.h>
+#include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include "sbp2.h"
 
 static char version[] __devinitdata =
-       "$Rev: 797 $ James Goodwin <jamesg@filanet.com>";
+       "$Rev: 846 $ James Goodwin <jamesg@filanet.com>";
 
 /*
  * Module load parameter definitions
  */
 
 /*
- * Change sbp2_max_speed on module load if you have a bad IEEE-1394
+ * Change max_speed on module load if you have a bad IEEE-1394
  * controller that has trouble running 2KB packets at 400mb.
  *
  * NOTE: On certain OHCI parts I have seen short packets on async transmit
@@ -334,34 +313,34 @@ static char version[] __devinitdata =
  * bump down the speed if you are running into problems.
  *
  * Valid values:
- * sbp2_max_speed = 2 (default: max speed 400mb)
- * sbp2_max_speed = 1 (max speed 200mb)
- * sbp2_max_speed = 0 (max speed 100mb)
+ * max_speed = 2 (default: max speed 400mb)
+ * max_speed = 1 (max speed 200mb)
+ * max_speed = 0 (max speed 100mb)
  */
-MODULE_PARM(sbp2_max_speed,"i");
-MODULE_PARM_DESC(sbp2_max_speed, "Force max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)");
-static int sbp2_max_speed = SPEED_400;
+static int max_speed = SPEED_400;
+module_param(max_speed, int, 0644);
+MODULE_PARM_DESC(max_speed, "Force max speed (2 = 400mb default, 1 = 200mb, 0 = 100mb)");
 
 /*
- * Set sbp2_serialize_io to 1 if you'd like only one scsi command sent
+ * Set serialize_io to 1 if you'd like only one scsi command sent
  * down to us at a time (debugging). This might be necessary for very
  * badly behaved sbp2 devices.
  */
-MODULE_PARM(sbp2_serialize_io,"i");
-MODULE_PARM_DESC(sbp2_serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
-static int sbp2_serialize_io = 0;      /* serialize I/O - available for debugging purposes */
+static int serialize_io = 0;
+module_param(serialize_io, int, 0444);
+MODULE_PARM_DESC(serialize_io, "Serialize all I/O coming down from the scsi drivers (default = 0)");
 
 /*
- * Bump up sbp2_max_sectors if you'd like to support very large sized
+ * Bump up max_sectors if you'd like to support very large sized
  * transfers. Please note that some older sbp2 bridge chips are broken for
  * transfers greater or equal to 128KB.  Default is a value of 255
  * sectors, or just under 128KB (at 512 byte sector size). I can note that
  * the Oxsemi sbp2 chipsets have no problems supporting very large
  * transfer sizes.
  */
-MODULE_PARM(sbp2_max_sectors,"i");
-MODULE_PARM_DESC(sbp2_max_sectors, "Change max sectors per I/O supported (default = 255)");
-static int sbp2_max_sectors = SBP2_MAX_SECTORS;
+static int max_sectors = SBP2_MAX_SECTORS;
+module_param(max_sectors, int, 0444);
+MODULE_PARM_DESC(max_sectors, "Change max sectors per I/O supported (default = 255)");
 
 /*
  * Exclusive login to sbp2 device? In most cases, the sbp2 driver should
@@ -370,13 +349,13 @@ static int sbp2_max_sectors = SBP2_MAX_SECTORS;
  * etc.). If you're running an sbp2 device that supports multiple logins,
  * and you're either running read-only filesystems or some sort of special
  * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
- * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
+ * see opengfs.sourceforge.net for more info), then set exclusive_login
  * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
  * concurrent logins.
  */
-MODULE_PARM(sbp2_exclusive_login,"i");
-MODULE_PARM_DESC(sbp2_exclusive_login, "Exclusive login to sbp2 device (default = 1)");
-static int sbp2_exclusive_login = 1;
+static int exclusive_login = 1;
+module_param(exclusive_login, int, 0644);
+MODULE_PARM_DESC(exclusive_login, "Exclusive login to sbp2 device (default = 1)");
 
 /*
  * SCSI inquiry hack for really badly behaved sbp2 devices. Turn this on
@@ -384,13 +363,13 @@ static int sbp2_exclusive_login = 1;
  * This hack makes the inquiry look more like a typical MS Windows
  * inquiry.
  * 
- * If sbp2_force_inquiry_hack=1 is required for your device to work,
+ * If force_inquiry_hack=1 is required for your device to work,
  * please submit the logged sbp2_firmware_revision value of this device to
  * the linux1394-devel mailing list.
  */
-MODULE_PARM(sbp2_force_inquiry_hack,"i");
-MODULE_PARM_DESC(sbp2_force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
-static int sbp2_force_inquiry_hack = 0;
+static int force_inquiry_hack = 0;
+module_param(force_inquiry_hack, int, 0444);
+MODULE_PARM_DESC(force_inquiry_hack, "Force SCSI inquiry hack (default = 0)");
 
 
 /*
@@ -466,12 +445,10 @@ static u32 global_outstanding_dmas = 0;
  * Globals
  */
 
-static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi,
-                                          struct scsi_id_instance_data *scsi_id,
+static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id,
                                           u32 status);
 
-static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi,
-                                     struct scsi_id_instance_data *scsi_id,
+static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
                                      u32 scsi_status, Scsi_Cmnd *SCpnt,
                                      void (*done)(Scsi_Cmnd *));
        
@@ -486,7 +463,6 @@ static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
 static struct hpsb_highlevel *sbp2_hl_handle = NULL;
 
 static struct hpsb_highlevel_ops sbp2_hl_ops = {
-       .add_host =     sbp2_add_host,
        .remove_host =  sbp2_remove_host,
 };
 
@@ -502,13 +478,18 @@ static struct hpsb_address_ops sbp2_physdma_ops = {
 #endif
 
 static struct hpsb_protocol_driver sbp2_driver = {
-       .name =         "SBP2 Driver",
-       .id_table =     sbp2_id_table,
-       .probe =        sbp2_probe,
-       .disconnect =   sbp2_disconnect,
-       .update =       sbp2_update
+       .name           = "SBP2 Driver",
+       .id_table       = sbp2_id_table,
+       .update         = sbp2_update,
+       .driver         = {
+               .name           = SBP2_DEVICE_NAME,
+               .bus            = &ieee1394_bus_type,
+               .probe          = sbp2_probe,
+               .remove         = sbp2_remove,
+       },
 };
 
+
 /* List of device firmware's that require a forced 36 byte inquiry.  */
 static u32 sbp2_broken_inquiry_list[] = {
        0x00002800,     /* Stefan Richter <richtest@bauwesen.tu-cottbus.de> */
@@ -648,14 +629,14 @@ sbp2util_allocate_write_packet(struct sbp2scsi_host_info *hi,
  * This function is called to create a pool of command orbs used for
  * command processing. It is called when a new sbp2 device is detected.
  */
-static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id,
-                                           struct sbp2scsi_host_info *hi)
+static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id)
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        int i;
        unsigned long flags, orbs;
        struct sbp2_command_info *command;
 
-       orbs = sbp2_serialize_io ? 2 : SBP2_MAX_COMMAND_ORBS;
+       orbs = serialize_io ? 2 : SBP2_MAX_COMMAND_ORBS;
         
        spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
        for (i = 0; i < orbs; i++) {
@@ -686,9 +667,9 @@ static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_i
 /*
  * This function is called to delete a pool of command orbs.
  */
-static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id,
-                                            struct sbp2scsi_host_info *hi)
+static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id)
 {
+       struct hpsb_host *host = scsi_id->hi->host;
        struct list_head *lh, *next;
        struct sbp2_command_info *command;
        unsigned long flags;
@@ -699,11 +680,11 @@ static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_
                        command = list_entry(lh, struct sbp2_command_info, list);
 
                        /* Release our generic DMA's */
-                       pci_unmap_single(hi->host->pdev, command->command_orb_dma,
+                       pci_unmap_single(host->pdev, command->command_orb_dma,
                                         sizeof(struct sbp2_command_orb),
                                         PCI_DMA_BIDIRECTIONAL);
                        SBP2_DMA_FREE("single command orb DMA");
-                       pci_unmap_single(hi->host->pdev, command->sge_dma,
+                       pci_unmap_single(host->pdev, command->sge_dma,
                                         sizeof(command->scatter_gather_element),
                                         PCI_DMA_BIDIRECTIONAL);
                        SBP2_DMA_FREE("scatter_gather_element");
@@ -773,8 +754,7 @@ static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_
 static struct sbp2_command_info *sbp2util_allocate_command_orb(
                struct scsi_id_instance_data *scsi_id, 
                Scsi_Cmnd *Current_SCpnt, 
-               void (*Current_done)(Scsi_Cmnd *),
-               struct sbp2scsi_host_info *hi)
+               void (*Current_done)(Scsi_Cmnd *))
 {
        struct list_head *lh;
        struct sbp2_command_info *command = NULL;
@@ -849,78 +829,86 @@ static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_i
  * IEEE-1394 core driver stack related section
  *********************************************/
 
-static int sbp2_probe(struct unit_directory *ud)
+static int sbp2_probe(struct device *dev)
 {
+       struct unit_directory *ud;
        struct sbp2scsi_host_info *hi;
 
-       SBP2_DEBUG("sbp2_probe");
-       hi = sbp2_find_host_info(ud->ne->host);
+       SBP2_DEBUG(__FUNCTION__);
+
+       ud = container_of(dev, struct unit_directory, device);
+
+       /* This will only add it if it doesn't exist */
+       hi = sbp2_add_host(ud->ne->host);
+
+       if (!hi)
+               return -ENODEV;
 
        return sbp2_start_device(hi, ud);
 }
 
-static void sbp2_disconnect(struct unit_directory *ud)
+static int sbp2_remove(struct device *dev)
 {
-       struct sbp2scsi_host_info *hi;
-       struct scsi_id_instance_data *scsi_id = ud->driver_data;
+       struct unit_directory *ud;
+       struct scsi_id_instance_data *scsi_id;
+
+       SBP2_DEBUG(__FUNCTION__);
 
-       SBP2_DEBUG("sbp2_disconnect");
-       hi = sbp2_find_host_info(ud->ne->host);
+       ud = container_of(dev, struct unit_directory, device);
+       scsi_id = ud->device.driver_data;
+       ud->device.driver_data = NULL;
 
-       if (hi != NULL) {
-               sbp2_logout_device(hi, scsi_id);
-               sbp2_remove_device(hi, scsi_id);
+       if (scsi_id != NULL) {
+               sbp2_logout_device(scsi_id);
+               sbp2_remove_device(scsi_id);
        }
+
+       return 0;
 }
 
 static void sbp2_update(struct unit_directory *ud)
 {
-       struct sbp2scsi_host_info *hi;
-       struct scsi_id_instance_data *scsi_id = ud->driver_data;
+       struct scsi_id_instance_data *scsi_id = ud->device.driver_data;
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        unsigned long flags;
 
        SBP2_DEBUG("sbp2_update");
-       hi = sbp2_find_host_info(ud->ne->host);
 
-       if (sbp2_reconnect_device(hi, scsi_id)) {
+       if (sbp2_reconnect_device(scsi_id)) {
                
                /* 
                 * Ok, reconnect has failed. Perhaps we didn't
                 * reconnect fast enough. Try doing a regular login.
                 */
-               if (sbp2_login_device(hi, scsi_id)) {
-
+               if (sbp2_login_device(scsi_id)) {
                        /* Login failed too, just remove the device. */
                        SBP2_ERR("sbp2_reconnect_device failed!");
-                       sbp2_remove_device(hi, scsi_id);
-                       hpsb_release_unit_directory(ud);
+                       sbp2_remove_device(scsi_id);
                        return;
                }
        }
 
        /* Set max retries to something large on the device. */
-       sbp2_set_busy_timeout(hi, scsi_id);
+       sbp2_set_busy_timeout(scsi_id);
 
        /* Do a SBP-2 fetch agent reset. */
-       sbp2_agent_reset(hi, scsi_id, 1);
+       sbp2_agent_reset(scsi_id, 1);
        
        /* Get the max speed and packet size that we can use. */
-       sbp2_max_speed_and_size(hi, scsi_id);
+       sbp2_max_speed_and_size(scsi_id);
 
        /* Complete any pending commands with busy (so they get
         * retried) and remove them from our queue
         */
        spin_lock_irqsave(&hi->sbp2_command_lock, flags);
-       sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);
+       sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
        spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
 }
 
-/*
- * This function is called after registering our operations in sbp2_init.
- * We go ahead and allocate some memory for our host info structure, and
- * init some structures.
- */
-static void sbp2_add_host(struct hpsb_host *host)
+/* This functions is called by the sbp2_probe, for each new device. If the
+ * host_info already exists, it will return it. If not, it allocated a new
+ * host_info entry and a corresponding scsi_host. */
+static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host)
 {
        struct sbp2scsi_host_info *hi;
        unsigned long flags;
@@ -928,11 +916,15 @@ static void sbp2_add_host(struct hpsb_host *host)
 
        SBP2_DEBUG("sbp2_add_host");
 
+       hi = sbp2_find_host_info(host);
+       if (hi)
+               return hi;
+
        /* Register our host with the SCSI stack. */
        scsi_host = scsi_register (&scsi_driver_template, sizeof(struct sbp2scsi_host_info));
        if (!scsi_host) {
                SBP2_ERR("failed to register scsi host");
-               return;
+               return NULL;
        }
 
        hi = (struct sbp2scsi_host_info *)&scsi_host->hostdata;
@@ -948,11 +940,10 @@ static void sbp2_add_host(struct hpsb_host *host)
        list_add_tail(&hi->list, &sbp2_host_info_list);
        spin_unlock_irqrestore(&sbp2_host_info_lock, flags);
 
-       /*
-        * XXX(hch): Hopefully the ieee1394 code will be converted
-        * to the driver model at some point.  Until that happens
-        * we'll have to pass in NULL here.
-        */
+       /* XXX We need a device to pass here as the scsi-host class. Can't
+        * use the PCI device, since it is already bound to the ieee1394
+        * host. Can't use the fw-host device since it is multi-class
+        * enabled (scsi-host uses classdata member of the device). */
        if (scsi_add_host(hi->scsi_host, NULL)) {
                SBP2_ERR("failed to add scsi host");
 
@@ -963,7 +954,7 @@ static void sbp2_add_host(struct hpsb_host *host)
                scsi_unregister(hi->scsi_host);
        }
 
-       return;
+       return hi;
 }
 
 /*
@@ -1048,6 +1039,8 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_director
                goto alloc_fail_first;
        memset(scsi_id, 0, sizeof(struct scsi_id_instance_data));
 
+       scsi_id->hi = hi;
+
        /* Login FIFO DMA */
        scsi_id->login_response =
                pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_response),
@@ -1076,7 +1069,7 @@ static int sbp2_start_device(struct sbp2scsi_host_info *hi, struct unit_director
        scsi_id->login_orb =
                pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_orb),
                                     &scsi_id->login_orb_dma);
-       if (scsi_id->login_orb == NULL) {
+       if (!scsi_id->login_orb) {
 alloc_fail:
                if (scsi_id->logout_orb) {
                        pci_free_consistent(hi->host->pdev,
@@ -1105,7 +1098,8 @@ alloc_fail:
                kfree(scsi_id);
 alloc_fail_first:
                SBP2_ERR ("Could not allocate memory for scsi_id");
-               return(-ENOMEM);
+
+               return -ENOMEM;
        }
        SBP2_DMA_ALLOC("consistent DMA region for login ORB");
 
@@ -1116,7 +1110,7 @@ alloc_fail_first:
        scsi_id->ud = ud;
        scsi_id->speed_code = SPEED_100;
        scsi_id->max_payload_size = sbp2_speedto_maxrec[SPEED_100];
-       ud->driver_data = scsi_id;
+       ud->device.driver_data = scsi_id;
 
        atomic_set(&scsi_id->sbp2_login_complete, 0);
 
@@ -1149,9 +1143,9 @@ alloc_fail_first:
        /*
         * Create our command orb pool
         */
-       if (sbp2util_create_command_orb_pool(scsi_id, hi)) {
+       if (sbp2util_create_command_orb_pool(scsi_id)) {
                SBP2_ERR("sbp2util_create_command_orb_pool failed!");
-               sbp2_remove_device(hi, scsi_id);
+               sbp2_remove_device(scsi_id);
                return -ENOMEM;
        }
 
@@ -1160,35 +1154,33 @@ alloc_fail_first:
         */
        if (i == hi->scsi_host->max_id) {
                SBP2_ERR("No slots left for SBP-2 device");
-               sbp2_remove_device(hi, scsi_id);
+               sbp2_remove_device(scsi_id);
                return -EBUSY;
        }
 
        /*
         * Login to the sbp-2 device
         */
-       if (sbp2_login_device(hi, scsi_id)) {
-
+       if (sbp2_login_device(scsi_id)) {
                /* Login failed, just remove the device. */
-               SBP2_ERR("sbp2_login_device failed");
-               sbp2_remove_device(hi, scsi_id);
+               sbp2_remove_device(scsi_id);
                return -EBUSY;
        }
 
        /*
         * Set max retries to something large on the device
         */
-       sbp2_set_busy_timeout(hi, scsi_id);
+       sbp2_set_busy_timeout(scsi_id);
        
        /*
         * Do a SBP-2 fetch agent reset
         */
-       sbp2_agent_reset(hi, scsi_id, 1);
+       sbp2_agent_reset(scsi_id, 1);
        
        /*
         * Get the max speed and packet size that we can use
         */
-       sbp2_max_speed_and_size(hi, scsi_id);
+       sbp2_max_speed_and_size(scsi_id);
 
        /* Add this device to the scsi layer now */
        sdev = scsi_add_device(hi->scsi_host, 0, scsi_id->id, 0);
@@ -1203,21 +1195,21 @@ alloc_fail_first:
 /*
  * This function removes an sbp2 device from the sbp2scsi_host_info struct.
  */
-static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
-                              struct scsi_id_instance_data *scsi_id)
+static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id)
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        struct scsi_device *sdev = scsi_find_device(hi->scsi_host, 0, scsi_id->id, 0);
 
        SBP2_DEBUG("sbp2_remove_device");
 
        /* Complete any pending commands with selection timeout */
-       sbp2scsi_complete_all_commands(hi, scsi_id, DID_NO_CONNECT);
+       sbp2scsi_complete_all_commands(scsi_id, DID_NO_CONNECT);
 
        /* Remove it from the scsi layer now */
-       if (scsi_remove_device(sdev))
+       if (sdev && scsi_remove_device(sdev))
                SBP2_ERR("scsi_remove_device failed");
 
-       sbp2util_remove_command_orb_pool(scsi_id, hi);
+       sbp2util_remove_command_orb_pool(scsi_id);
 
        hi->scsi_id[scsi_id->id] = NULL;
 
@@ -1311,8 +1303,9 @@ static __inline__ int sbp2_command_conversion_device_type(u8 device_type)
  * This function is called in order to login to a particular SBP-2 device,
  * after a bus reset.
  */
-static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
+static int sbp2_login_device(struct scsi_id_instance_data *scsi_id) 
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        quadlet_t data[2];
 
        SBP2_DEBUG("sbp2_login_device");
@@ -1333,7 +1326,7 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta
 
        scsi_id->login_orb->lun_misc = ORB_SET_FUNCTION(LOGIN_REQUEST);
        scsi_id->login_orb->lun_misc |= ORB_SET_RECONNECT(0);   /* One second reconnect time */
-       scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(sbp2_exclusive_login);        /* Exclusive access to device */
+       scsi_id->login_orb->lun_misc |= ORB_SET_EXCLUSIVE(exclusive_login);     /* Exclusive access to device */
        scsi_id->login_orb->lun_misc |= ORB_SET_NOTIFY(1);      /* Notify us of login complete */
        /* Set the lun if we were able to pull it from the device's unit directory */
        if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
@@ -1438,8 +1431,9 @@ static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_insta
  * This function is called in order to logout from a particular SBP-2
  * device, usually called during driver unload.
  */
-static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
+static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id) 
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        quadlet_t data[2];
 
        SBP2_DEBUG("sbp2_logout_device");
@@ -1496,8 +1490,9 @@ static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_inst
  * This function is called in order to reconnect to a particular SBP-2
  * device, after a bus reset.
  */
-static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id) 
+static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id) 
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        quadlet_t data[2];
 
        SBP2_DEBUG("sbp2_reconnect_device");
@@ -1584,8 +1579,8 @@ static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_i
  * This function is called in order to set the busy timeout (number of
  * retries to attempt) on the sbp2 device. 
  */
-static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
-{      
+static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id)
+{
        quadlet_t data;
 
        SBP2_DEBUG("sbp2_set_busy_timeout");
@@ -1625,7 +1620,7 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
        ud = scsi_id->ud;
 
        /* Handle different fields in the unit directory, based on keys */
-       for (i = 0; i < ud->count; i++) {
+       for (i = 0; i < ud->length; i++) {
                switch (CONFIG_ROM_KEY(ud->quadlets[i])) {
                case SBP2_CSR_OFFSET_KEY:
                        /* Save off the management agent address */
@@ -1679,7 +1674,7 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
                        /* Firmware revision */
                        scsi_id->sbp2_firmware_revision
                                = CONFIG_ROM_VALUE(ud->quadlets[i]);
-                       if (sbp2_force_inquiry_hack)
+                       if (force_inquiry_hack)
                                SBP2_INFO("sbp2_firmware_revision = %x",
                                   (unsigned int) scsi_id->sbp2_firmware_revision);
                        else    SBP2_DEBUG("sbp2_firmware_revision = %x",
@@ -1697,20 +1692,20 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
 
        /* If the vendor id is 0xa0b8 (Symbios vendor id), then we have a
         * bridge with 128KB max transfer size limitation. For sanity, we
-        * only voice this when the current sbp2_max_sectors setting
+        * only voice this when the current max_sectors setting
         * exceeds the 128k limit. By default, that is not the case.
         *
         * It would be really nice if we could detect this before the scsi
         * host gets initialized. That way we can down-force the
-        * sbp2_max_sectors to account for it. That is not currently
+        * max_sectors to account for it. That is not currently
         * possible.  */
        if ((scsi_id->sbp2_firmware_revision & 0xffff00) ==
                        SBP2_128KB_BROKEN_FIRMWARE &&
-                       (sbp2_max_sectors * 512) > (128*1024)) {
+                       (max_sectors * 512) > (128*1024)) {
                SBP2_WARN("Node " NODE_BUS_FMT ": Bridge only supports 128KB max transfer size.",
                                NODE_BUS_ARGS(scsi_id->ne->nodeid));
-               SBP2_WARN("WARNING: Current sbp2_max_sectors setting is larger than 128KB (%d sectors)!",
-                               sbp2_max_sectors);
+               SBP2_WARN("WARNING: Current max_sectors setting is larger than 128KB (%d sectors)!",
+                               max_sectors);
                scsi_id->workarounds |= SBP2_BREAKAGE_128K_MAX_TRANSFER;
        }
 
@@ -1737,8 +1732,10 @@ static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id)
  * the speed that it needs to use, and the max_rec the host supports, and
  * it takes care of the rest.
  */
-static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
+static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id)
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
+
        SBP2_DEBUG("sbp2_max_speed_and_size");
 
        /* Initial setting comes from the hosts speed map */
@@ -1746,8 +1743,8 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id
                                                  + NODEID_TO_NODE(scsi_id->ne->nodeid)];
 
        /* Bump down our speed if the user requested it */
-       if (scsi_id->speed_code > sbp2_max_speed) {
-               scsi_id->speed_code = sbp2_max_speed;
+       if (scsi_id->speed_code > max_speed) {
+               scsi_id->speed_code = max_speed;
                SBP2_ERR("Forcing SBP-2 max speed down to %s",
                         hpsb_speedto_str[scsi_id->speed_code]);
        }
@@ -1767,8 +1764,9 @@ static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id
 /*
  * This function is called in order to perform a SBP-2 agent reset. 
  */
-static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, int wait) 
+static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait) 
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        struct hpsb_packet *packet;
        quadlet_t data;
        
@@ -1811,8 +1809,7 @@ static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instan
  * This function is called to create the actual command orb and s/g list
  * out of the scsi command itself.
  */
-static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
-                                  struct scsi_id_instance_data *scsi_id,
+static int sbp2_create_command_orb(struct scsi_id_instance_data *scsi_id,
                                   struct sbp2_command_info *command,
                                   unchar *scsi_cmd,
                                   unsigned int scsi_use_sg,
@@ -1820,6 +1817,7 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
                                   void *scsi_request_buffer, 
                                   unsigned char scsi_dir)
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        struct scatterlist *sgpnt = (struct scatterlist *) scsi_request_buffer;
        struct sbp2_command_orb *command_orb = &command->command_orb;
        struct sbp2_unrestricted_page_table *scatter_gather_element =
@@ -2062,9 +2060,10 @@ static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi,
 /*
  * This function is called in order to begin a regular SBP-2 command. 
  */
-static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
+static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
                                 struct sbp2_command_info *command)
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
         struct hpsb_packet *packet;
        struct sbp2_command_orb *command_orb = &command->command_orb;
 
@@ -2166,7 +2165,7 @@ static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_i
 /*
  * This function is called in order to begin a regular SBP-2 command. 
  */
-static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
+static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
                             Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
 {
        unchar *cmd = (unchar *) SCpnt->cmnd;
@@ -2184,7 +2183,7 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
        /*
         * Allocate a command orb and s/g structure
         */
-       command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done, hi);
+       command = sbp2util_allocate_command_orb(scsi_id, SCpnt, done);
        if (!command) {
                return(-EIO);
        }
@@ -2195,7 +2194,7 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
         * reject this inquiry command. Fix the request_bufflen. 
         */
        if (*cmd == INQUIRY) {
-               if (sbp2_force_inquiry_hack || scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK)
+               if (force_inquiry_hack || scsi_id->workarounds & SBP2_BREAKAGE_INQUIRY_HACK)
                        request_bufflen = cmd[4] = 0x24;
                else
                        request_bufflen = cmd[4];
@@ -2204,7 +2203,7 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
        /*
         * Now actually fill in the comamnd orb and sbp2 s/g list
         */
-       sbp2_create_command_orb(hi, scsi_id, command, cmd, SCpnt->use_sg,
+       sbp2_create_command_orb(scsi_id, command, cmd, SCpnt->use_sg,
                                request_bufflen, SCpnt->request_buffer,
                                SCpnt->sc_data_direction); 
        /*
@@ -2224,7 +2223,7 @@ static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_insta
        /*
         * Link up the orb, and ring the doorbell if needed
         */
-       sbp2_link_orb_command(hi, scsi_id, command);
+       sbp2_link_orb_command(scsi_id, command);
        
        return(0);
 }
@@ -2543,7 +2542,7 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
                                 * Initiate a fetch agent reset. 
                                 */
                                SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
-                                sbp2_agent_reset(hi, scsi_id, 0);
+                                sbp2_agent_reset(scsi_id, 0);
                        }
 
                        SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
@@ -2583,7 +2582,8 @@ static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int dest
                 * io_request_lock (in sbp2scsi_queuecommand).
                 */
                SBP2_DEBUG("Completing SCSI command");
-               sbp2scsi_complete_command(hi, scsi_id, scsi_status, SCpnt, command->Current_done);
+               sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
+                                         command->Current_done);
                SBP2_ORB_DEBUG("command orb completed");
        }
 
@@ -2649,7 +2649,7 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
                SBP2_DEBUG("REQUEST_SENSE");
                memcpy(SCpnt->request_buffer, SCpnt->sense_buffer, SCpnt->request_bufflen);
                memset(SCpnt->sense_buffer, 0, sizeof(SCpnt->sense_buffer));
-               sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done);
+               sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_GOOD, SCpnt, done);
                return(0);
        }
 
@@ -2667,9 +2667,10 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
         * Try and send our SCSI command
         */
        spin_lock_irqsave(&hi->sbp2_command_lock, flags);
-       if (sbp2_send_command(hi, scsi_id, SCpnt, done)) {
+       if (sbp2_send_command(scsi_id, SCpnt, done)) {
                SBP2_ERR("Error sending SCSI command");
-               sbp2scsi_complete_command(hi, scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT, SCpnt, done);
+               sbp2scsi_complete_command(scsi_id, SBP2_SCSI_STATUS_SELECTION_TIMEOUT,
+                                         SCpnt, done);
        }
        spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
 
@@ -2680,10 +2681,10 @@ static int sbp2scsi_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
  * This function is called in order to complete all outstanding SBP-2
  * commands (in case of resets, etc.).
  */
-static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi,
-                                          struct scsi_id_instance_data *scsi_id, 
+static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id, 
                                           u32 status)
 {
+       struct sbp2scsi_host_info *hi = scsi_id->hi;
        struct list_head *lh;
        struct sbp2_command_info *command;
 
@@ -2715,8 +2716,7 @@ static void sbp2scsi_complete_all_commands(struct sbp2scsi_host_info *hi,
  *
  * This can be called in interrupt context.
  */
-static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi,
-                                     struct scsi_id_instance_data *scsi_id,
+static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
                                      u32 scsi_status, Scsi_Cmnd *SCpnt,
                                      void (*done)(Scsi_Cmnd *))
 {
@@ -2825,9 +2825,9 @@ static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi,
        done (SCpnt);
        spin_unlock_irqrestore(&io_request_lock,flags);
 #else
-       spin_lock_irqsave(hi->scsi_host->host_lock,flags);
+       spin_lock_irqsave(scsi_id->hi->scsi_host->host_lock,flags);
        done (SCpnt);
-       spin_unlock_irqrestore(hi->scsi_host->host_lock,flags);
+       spin_unlock_irqrestore(scsi_id->hi->scsi_host->host_lock,flags);
 #endif
 
        return;
@@ -2876,8 +2876,8 @@ static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
                /*
                 * Initiate a fetch agent reset. 
                 */
-               sbp2_agent_reset(hi, scsi_id, 0);
-               sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);              
+               sbp2_agent_reset(scsi_id, 0);
+               sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);          
                spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
        }
 
@@ -2896,7 +2896,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
 
        if (scsi_id) {
                SBP2_ERR("Generating sbp2 fetch agent reset");
-               sbp2_agent_reset(hi, scsi_id, 0);
+               sbp2_agent_reset(scsi_id, 0);
        }
 
        return(SUCCESS);
@@ -2904,7 +2904,7 @@ static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
 
 static const char *sbp2scsi_info (struct Scsi_Host *host)
 {
-        return "SCSI emulation for for IEEE-1394 Storage Devices";
+        return "SCSI emulation for IEEE-1394 SBP-2 Devices";
 }
 
 /* Called for contents of procfs */
@@ -2936,10 +2936,10 @@ static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset,
        SPRINTF("Driver version         : %s\n", version);
 
        SPRINTF("\nModule options         :\n");
-       SPRINTF("  sbp2_max_speed       : %s\n", hpsb_speedto_str[sbp2_max_speed]);
-       SPRINTF("  sbp2_max_sectors     : %d\n", sbp2_max_sectors);
-       SPRINTF("  sbp2_serialize_io    : %s\n", sbp2_serialize_io ? "yes" : "no");
-       SPRINTF("  sbp2_exclusive_login : %s\n", sbp2_exclusive_login ? "yes" : "no");
+       SPRINTF("  max_speed       : %s\n", hpsb_speedto_str[max_speed]);
+       SPRINTF("  max_sectors     : %d\n", max_sectors);
+       SPRINTF("  serialize_io    : %s\n", serialize_io ? "yes" : "no");
+       SPRINTF("  exclusive_login : %s\n", exclusive_login ? "yes" : "no");
 
        SPRINTF("\nAttached devices       : %s\n", !list_empty(&host->my_devices) ?
                "" : "none");
@@ -3010,7 +3010,7 @@ static int sbp2_module_init(void)
 
        /* Module load debug option to force one command at a time
         * (serializing I/O) */
-       if (sbp2_serialize_io) {
+       if (serialize_io) {
                SBP2_ERR("Driver forced to serialize I/O (serialize_io = 1)");
                scsi_driver_template.can_queue = 1;
                scsi_driver_template.cmd_per_lun = 1;
@@ -3019,7 +3019,7 @@ static int sbp2_module_init(void)
        /* 
         * Set max sectors (module load option). Default is 255 sectors. 
         */
-       scsi_driver_template.max_sectors = sbp2_max_sectors;
+       scsi_driver_template.max_sectors = max_sectors;
 
 
        /*
index 8283194b4405058130b039efb498e7e87e62c1f0..d56fc82d9ecb16803e453e22120cb71afec171f7 100644 (file)
@@ -238,7 +238,7 @@ struct sbp2_status_block {
  */
 
 #define SBP2_MAX_SG_ELEMENT_LENGTH     0xf000
-#define SBP2SCSI_MAX_SCSI_IDS          16      /* Max sbp2 device instances supported */
+#define SBP2SCSI_MAX_SCSI_IDS          32      /* Max sbp2 device instances supported */
 #define SBP2_MAX_SECTORS               255     /* Max sectors supported */
 
 #ifndef TYPE_SDAD
@@ -320,6 +320,10 @@ struct sbp2_command_info {
 #define SBP2_BREAKAGE_128K_MAX_TRANSFER                0x1
 #define SBP2_BREAKAGE_INQUIRY_HACK             0x2
 
+
+struct sbp2scsi_host_info;
+
+
 /*
  * Information needed on a per scsi id basis (one for each sbp2 device)
  */
@@ -375,6 +379,9 @@ struct scsi_id_instance_data {
        /* Node entry, as retrieved from NodeMgr entries */
        struct node_entry *ne;
 
+       /* A backlink to our host_info */
+       struct sbp2scsi_host_info *hi;
+
        /* Device specific workarounds/brokeness */
        u32 workarounds;
 };
@@ -406,7 +413,6 @@ struct sbp2scsi_host_info {
         * SCSI ID instance data (one for each sbp2 device instance possible)
         */
        struct scsi_id_instance_data *scsi_id[SBP2SCSI_MAX_SCSI_IDS];
-
 };
 
 /*
@@ -416,30 +422,30 @@ struct sbp2scsi_host_info {
 /*
  * Various utility prototypes
  */
-static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi);
-static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id, struct sbp2scsi_host_info *hi);
+static int sbp2util_create_command_orb_pool(struct scsi_id_instance_data *scsi_id);
+static void sbp2util_remove_command_orb_pool(struct scsi_id_instance_data *scsi_id);
 static struct sbp2_command_info *sbp2util_find_command_for_orb(struct scsi_id_instance_data *scsi_id, dma_addr_t orb);
 static struct sbp2_command_info *sbp2util_find_command_for_SCpnt(struct scsi_id_instance_data *scsi_id, void *SCpnt);
 static struct sbp2_command_info *sbp2util_allocate_command_orb(struct scsi_id_instance_data *scsi_id, 
                                                          Scsi_Cmnd *Current_SCpnt, 
-                                                         void (*Current_done)(Scsi_Cmnd *),
-                                                         struct sbp2scsi_host_info *hi);
+                                                         void (*Current_done)(Scsi_Cmnd *));
 static void sbp2util_mark_command_completed(struct scsi_id_instance_data *scsi_id,
                struct sbp2_command_info *command);
 
 /*
  * IEEE-1394 core driver related prototypes
  */
-static void sbp2_add_host(struct hpsb_host *host);
+static struct sbp2scsi_host_info *sbp2_add_host(struct hpsb_host *host);
 static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host);
 static void sbp2_remove_host(struct hpsb_host *host);
-static int sbp2_probe(struct unit_directory *ud);
-static void sbp2_disconnect(struct unit_directory *ud);
+
+static int sbp2_probe(struct device *dev);
+static int sbp2_remove(struct device *dev);
 static void sbp2_update(struct unit_directory *ud);
+
 static int sbp2_start_device(struct sbp2scsi_host_info *hi, 
                             struct unit_directory *ud);
-static void sbp2_remove_device(struct sbp2scsi_host_info *hi, 
-                              struct scsi_id_instance_data *scsi_id);
+static void sbp2_remove_device(struct scsi_id_instance_data *scsi_id);
 
 #ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
 static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
@@ -451,29 +457,28 @@ static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_
 /*
  * SBP-2 protocol related prototypes
  */
-static int sbp2_login_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
-static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
-static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id); 
+static int sbp2_login_device(struct scsi_id_instance_data *scsi_id);
+static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id); 
+static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id); 
 static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
                                    quadlet_t *data, u64 addr, unsigned int length, u16 flags);
-static int sbp2_agent_reset(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, int wait);
-static int sbp2_create_command_orb(struct sbp2scsi_host_info *hi, 
-                                  struct scsi_id_instance_data *scsi_id,
+static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait);
+static int sbp2_create_command_orb(struct scsi_id_instance_data *scsi_id,
                                   struct sbp2_command_info *command,
                                   unchar *scsi_cmd,
                                   unsigned int scsi_use_sg,
                                   unsigned int scsi_request_bufflen,
                                   void *scsi_request_buffer, 
                                   unsigned char scsi_dir);
-static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
+static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
                                 struct sbp2_command_info *command);
-static int sbp2_send_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
+static int sbp2_send_command(struct scsi_id_instance_data *scsi_id,
                             Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *));
 static unsigned int sbp2_status_to_sense_data(unchar *sbp2_status, unchar *sense_data);
 static void sbp2_check_sbp2_command(struct scsi_id_instance_data *scsi_id, unchar *cmd);
 static void sbp2_check_sbp2_response(struct scsi_id_instance_data *scsi_id, Scsi_Cmnd *SCpnt);
 static void sbp2_parse_unit_directory(struct scsi_id_instance_data *scsi_id);
-static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
-static int sbp2_max_speed_and_size(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id);
+static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id);
+static int sbp2_max_speed_and_size(struct scsi_id_instance_data *scsi_id);
 
 #endif /* SBP2_H */