From 7b55ea658ef29f90d82be7388b695ef922d27a63 Mon Sep 17 00:00:00 2001 From: Ben Collins Date: Fri, 11 Apr 2003 04:38:49 -0700 Subject: [PATCH] [PATCH] IEEE-1394/Firewire updates - 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. --- drivers/ieee1394/csr.c | 8 +- drivers/ieee1394/dv1394.c | 6 +- drivers/ieee1394/highlevel.c | 60 +- drivers/ieee1394/highlevel.h | 8 +- drivers/ieee1394/hosts.h | 3 + drivers/ieee1394/ieee1394.h | 10 +- drivers/ieee1394/ieee1394_core.c | 27 +- drivers/ieee1394/ieee1394_core.h | 3 + drivers/ieee1394/ieee1394_hotplug.h | 32 +- drivers/ieee1394/ieee1394_transactions.c | 6 +- drivers/ieee1394/ieee1394_types.h | 15 +- drivers/ieee1394/iso.c | 2 +- drivers/ieee1394/nodemgr.c | 1320 ++++++++++++++-------- drivers/ieee1394/nodemgr.h | 45 +- drivers/ieee1394/ohci1394.c | 82 +- drivers/ieee1394/ohci1394.h | 10 + drivers/ieee1394/pcilynx.c | 10 +- drivers/ieee1394/sbp2.c | 354 +++--- drivers/ieee1394/sbp2.h | 47 +- 19 files changed, 1206 insertions(+), 842 deletions(-) diff --git a/drivers/ieee1394/csr.c b/drivers/ieee1394/csr.c index 6cd4774c1dab7..e13186e64115f 100644 --- a/drivers/ieee1394/csr.c +++ b/drivers/ieee1394/csr.c @@ -18,7 +18,8 @@ */ #include -#include /* needed for MODULE_PARM */ +#include +#include #include "ieee1394_types.h" #include "hosts.h" @@ -27,9 +28,10 @@ /* 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) { diff --git a/drivers/ieee1394/dv1394.c b/drivers/ieee1394/dv1394.c index 932088e7519d9..ae5e2a601809d 100644 --- a/drivers/ieee1394/dv1394.c +++ b/drivers/ieee1394/dv1394.c @@ -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 diff --git a/drivers/ieee1394/highlevel.c b/drivers/ieee1394/highlevel.c index cfe98e92fe424..843675b655e68 100644 --- a/drivers/ieee1394/highlevel.c +++ b/drivers/ieee1394/highlevel.c @@ -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); diff --git a/drivers/ieee1394/highlevel.h b/drivers/ieee1394/highlevel.h index 5e556b5b70232..d6a90ddf24251 100644 --- a/drivers/ieee1394/highlevel.h +++ b/drivers/ieee1394/highlevel.h @@ -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); /* diff --git a/drivers/ieee1394/hosts.h b/drivers/ieee1394/hosts.h index 25e0e20597843..0c39327a52afe 100644 --- a/drivers/ieee1394/hosts.h +++ b/drivers/ieee1394/hosts.h @@ -1,6 +1,7 @@ #ifndef _IEEE1394_HOSTS_H #define _IEEE1394_HOSTS_H +#include #include #include #include @@ -64,6 +65,8 @@ struct hpsb_host { struct hpsb_host_driver *driver; struct pci_dev *pdev; + + struct device device; }; diff --git a/drivers/ieee1394/ieee1394.h b/drivers/ieee1394/ieee1394.h index fe59095108d21..4763597298eb6 100644 --- a/drivers/ieee1394/ieee1394.h +++ b/drivers/ieee1394/ieee1394.h @@ -46,9 +46,13 @@ #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[]; diff --git a/drivers/ieee1394/ieee1394_core.c b/drivers/ieee1394/ieee1394_core.c index c32a7896cdaba..2c1e53f95b041 100644 --- a/drivers/ieee1394/ieee1394_core.c +++ b/drivers/ieee1394/ieee1394_core.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -48,13 +49,9 @@ /* * 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); diff --git a/drivers/ieee1394/ieee1394_core.h b/drivers/ieee1394/ieee1394_core.h index 030406396e1ab..37db15faac3ea 100644 --- a/drivers/ieee1394/ieee1394_core.h +++ b/drivers/ieee1394/ieee1394_core.h @@ -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 */ diff --git a/drivers/ieee1394/ieee1394_hotplug.h b/drivers/ieee1394/ieee1394_hotplug.h index f5933274accd2..211f9f1721fa0 100644 --- a/drivers/ieee1394/ieee1394_hotplug.h +++ b/drivers/ieee1394/ieee1394_hotplug.h @@ -1,6 +1,8 @@ #ifndef _IEEE1394_HOTPLUG_H #define _IEEE1394_HOTPLUG_H +#include + #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 */ diff --git a/drivers/ieee1394/ieee1394_transactions.c b/drivers/ieee1394/ieee1394_transactions.c index 7b5a6af229687..e8ddaa8bc1942 100644 --- a/drivers/ieee1394/ieee1394_transactions.c +++ b/drivers/ieee1394/ieee1394_transactions.c @@ -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); diff --git a/drivers/ieee1394/ieee1394_types.h b/drivers/ieee1394/ieee1394_types.h index 95b8965bb2bd1..5ae4824a65bb4 100644 --- a/drivers/ieee1394/ieee1394_types.h +++ b/drivers/ieee1394/ieee1394_types.h @@ -72,19 +72,20 @@ /* 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) diff --git a/drivers/ieee1394/iso.c b/drivers/ieee1394/iso.c index 74831f7d2363d..ec4e0b10b2bb8 100644 --- a/drivers/ieee1394/iso.c +++ b/drivers/ieee1394/iso.c @@ -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 ? diff --git a/drivers/ieee1394/nodemgr.c b/drivers/ieee1394/nodemgr.c index 72412bcfe1d57..b4bd67978ee08 100644 --- a/drivers/ieee1394/nodemgr.c +++ b/drivers/ieee1394/nodemgr.c @@ -1,8 +1,8 @@ /* * Node information (ConfigROM) collection and management. * - * Copyright (C) 2000 Andreas E. Bombe - * 2001 Ben Collins + * Copyright (C) 2000 Andreas E. Bombe + * 2001-2003 Ben Collins * * 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 #include #include -#ifdef CONFIG_PROC_FS -#include -#endif +#include #include #include @@ -32,24 +30,23 @@ #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); } diff --git a/drivers/ieee1394/nodemgr.h b/drivers/ieee1394/nodemgr.h index 64210b048116f..a419118138c8b 100644 --- a/drivers/ieee1394/nodemgr.h +++ b/drivers/ieee1394/nodemgr.h @@ -20,6 +20,8 @@ #ifndef _IEEE1394_NODEMGR_H #define _IEEE1394_NODEMGR_H +#include + #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 */ diff --git a/drivers/ieee1394/ohci1394.c b/drivers/ieee1394/ohci1394.c index 9da0dce7b83fe..c1b4693080169 100644 --- a/drivers/ieee1394/ohci1394.c +++ b/drivers/ieee1394/ohci1394.c @@ -80,6 +80,10 @@ * Manfred Weihs * . Reworked code for initiating bus resets * (long, short, with or without hold-off) + * + * Nandu Santhi + * . Added support for nVidia nForce2 onboard Firewire chipset + * */ #include @@ -90,6 +94,7 @@ #include #include #include +#include #include #include #include @@ -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 "; + "$Rev: 858 $ Ben Collins "; /* 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, diff --git a/drivers/ieee1394/ohci1394.h b/drivers/ieee1394/ohci1394.h index 234f1b153816e..8e75ca0471f6a 100644 --- a/drivers/ieee1394/ohci1394.h +++ b/drivers/ieee1394/ohci1394.h @@ -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 diff --git a/drivers/ieee1394/pcilynx.c b/drivers/ieee1394/pcilynx.c index de0be238d3359..8ae1b0c2a0b7c 100644 --- a/drivers/ieee1394/pcilynx.c +++ b/drivers/ieee1394/pcilynx.c @@ -37,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -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) diff --git a/drivers/ieee1394/sbp2.c b/drivers/ieee1394/sbp2.c index dbeb597a683e7..1910d0515ac24 100644 --- a/drivers/ieee1394/sbp2.c +++ b/drivers/ieee1394/sbp2.c @@ -27,44 +27,22 @@ * 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 or remove-single-device , where: - * = host (starting at zero for first SCSI adapter) - * = bus (normally zero) - * = target (starting at zero for first SBP-2 device) - * = 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: @@ -258,7 +236,7 @@ * * 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. @@ -285,6 +263,7 @@ #include #include #include +#include #include #include #include @@ -319,14 +298,14 @@ #include "sbp2.h" static char version[] __devinitdata = - "$Rev: 797 $ James Goodwin "; + "$Rev: 846 $ James Goodwin "; /* * 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 */ @@ -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; /* diff --git a/drivers/ieee1394/sbp2.h b/drivers/ieee1394/sbp2.h index 8283194b44050..d56fc82d9ecb1 100644 --- a/drivers/ieee1394/sbp2.h +++ b/drivers/ieee1394/sbp2.h @@ -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 */ -- 2.53.0