[Linux1394-cvslog] rev 833 - trunk
Brought to you by:
aeb,
bencollins
From: SVN U. <ben...@li...> - 2003-03-10 20:38:50
|
Author: bencollins Date: 2003-03-10 15:38:05 -0500 (Mon, 10 Mar 2003) New Revision: 833 Modified: trunk/TODO trunk/ieee1394_core.c trunk/ieee1394_hotplug.h trunk/nodemgr.c trunk/nodemgr.h trunk/sbp2.c trunk/sbp2.h Log: This is the huge patch you've been waiting for. This pretty much converts our entire bus management - including driver attachment, bus scanning and matching, etc. - over to the new driver model. SBP-2 has been converted over to provide a device_driver, which is then matched against unit-dir's in the same way as before. Anyone has any questions about this new model in relation to linux1394, please email the -devel list and I'll answer any questions. See Documentation/driver-model/ for questions about the driver core in general. Modified: trunk/ieee1394_hotplug.h ============================================================================== --- trunk/ieee1394_hotplug.h (original) +++ trunk/ieee1394_hotplug.h 2003-03-10 15:38:07.000000000 -0500 @@ -34,26 +34,6 @@ 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. * However, it may be necessary to reestablish the connection @@ -61,20 +41,12 @@ */ 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 */ Modified: trunk/ieee1394_core.c ============================================================================== --- trunk/ieee1394_core.c (original) +++ trunk/ieee1394_core.c 2003-03-10 15:38:07.000000000 -0500 @@ -52,10 +52,6 @@ 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; - /* We are GPL, so treat us special */ MODULE_LICENSE("GPL"); @@ -1179,7 +1175,7 @@ init_hpsb_highlevel(); init_csr(); if (!disable_nodemgr) - init_ieee1394_nodemgr(disable_hotplug); + init_ieee1394_nodemgr(); else HPSB_INFO("nodemgr functionality disabled"); @@ -1273,7 +1269,6 @@ 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 **/ Modified: trunk/nodemgr.c ============================================================================== --- trunk/nodemgr.c (original) +++ trunk/nodemgr.c 2003-03-10 15:38:07.000000000 -0500 @@ -1,8 +1,8 @@ /* * Node information (ConfigROM) collection and management. * - * Copyright (C) 2000 Andreas E. Bombe - * 2001 Ben Collins <bco...@de...> + * Copyright (C) 2000 Andreas E. Bombe + * 2001-2003 Ben Collins <bco...@de...> * * This code is licensed under the GPL. See the file COPYING in the root * directory of the kernel sources for details. @@ -30,14 +30,6 @@ #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[]; -#endif /* Shitty part is, 0x0 can just mean it wasn't set, but that matches an * OUI entry. We don't want that, so we take a chance and never match 0x0. @@ -45,6 +37,10 @@ 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 = 1; oui_list[i].name; i++) @@ -69,28 +65,16 @@ */ /* - * 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; @@ -102,72 +86,33 @@ }; -#define fw_ne_attr(field, type, format_string) \ -static ssize_t fw_ne_show_##field (struct device *dev, char *buf)\ -{ \ - struct node_entry *ne; \ - ne = container_of(dev, struct node_entry, device); \ - return sprintf(buf, format_string, (type)ne->field); \ -} \ -static struct device_attribute dev_attr_ne_##field = { \ - .attr = {.name = __stringify(field), .mode = S_IRUGO }, \ - .show = fw_ne_show_##field, \ +#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, \ }; -#define fw_ud_attr(field, type, format_string) \ -static ssize_t fw_ud_show_##field (struct device *dev, char *buf) \ -{ \ - struct unit_directory *ud; \ - ud = container_of(dev, struct unit_directory, device); \ - return sprintf(buf, format_string, (type)ud->field); \ -} \ -static struct device_attribute dev_attr_ud_##field = { \ - .attr = {.name = __stringify(field), .mode = S_IRUGO }, \ - .show = fw_ud_show_##field, \ -}; -#define fw_host_attr(field, type, format_string) \ -static ssize_t fw_host_show_##field (struct device *dev, char *buf) \ +#define fw_drv_attr(field, type, format_string) \ +static ssize_t fw_drv_show_##field (struct device_driver *drv, char *buf) \ { \ - struct hpsb_host *host; \ - host = container_of(dev, struct hpsb_host, device); \ - return sprintf(buf, format_string, (type)host->field); \ + struct hpsb_protocol_driver *driver; \ + driver = container_of(drv, struct hpsb_protocol_driver, driver); \ + return sprintf(buf, format_string, (type)driver->field);\ } \ -static struct device_attribute dev_attr_host_##field = { \ - .attr = {.name = __stringify(field), .mode = S_IRUGO }, \ - .show = fw_host_show_##field, \ +static struct driver_attribute driver_attr_drv_##field = { \ + .attr = {.name = __stringify(field), .mode = S_IRUGO }, \ + .show = fw_drv_show_##field, \ }; -fw_ne_attr(guid, unsigned long long, "0x%016Lx\n") -fw_ne_attr(capabilities, unsigned int, "0x%06x\n") -fw_ne_attr(vendor_id, unsigned int, "0x%06x\n") -fw_ne_attr(nodeid, unsigned int, "0x%04x\n") -fw_ne_attr(vendor_name, const char *, "%s\n") -fw_ne_attr(oui_name, const char *, "%s\n") - - -fw_ud_attr(address, unsigned long long, "0x%016Lx\n") -fw_ud_attr(vendor_id, unsigned int, "0x%06x\n") -fw_ud_attr(model_id, unsigned int, "0x%06x\n") -fw_ud_attr(specifier_id, unsigned int, "0x%06x\n") -fw_ud_attr(version, unsigned int, "0x%06x\n") -fw_ud_attr(length, int, "%d\n") -fw_ud_attr(vendor_name, const char *, "%s\n") -fw_ud_attr(model_name, const char *, "%s\n") - - -fw_host_attr(node_count, int, "%d\n") -fw_host_attr(selfid_count, int, "%d\n") -fw_host_attr(nodes_active, int, "%d\n") -fw_host_attr(in_bus_reset, int, "%d\n") -fw_host_attr(is_root, int, "%d\n") -fw_host_attr(is_cycmst, int, "%d\n") -fw_host_attr(is_irm, int, "%d\n") -fw_host_attr(is_busmgr, int, "%d\n") - - -static ssize_t fw_ne_show_bus_options(struct device *dev, char *buf) +static ssize_t fw_show_ne_bus_options(struct device *dev, char *buf) { struct node_entry *ne = container_of(dev, struct node_entry, device); @@ -177,26 +122,26 @@ 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_ne_show_bus_options,NULL); +static DEVICE_ATTR(bus_options,S_IRUGO,fw_show_ne_bus_options,NULL); -static ssize_t fw_ne_show_tlabels_free(struct device *dev, char *buf) +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_ne_show_tlabels_free,NULL); +static DEVICE_ATTR(tlabels_free,S_IRUGO,fw_show_ne_tlabels_free,NULL); -static ssize_t fw_ne_show_tlabels_allocations(struct device *dev, char *buf) +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_ne_show_tlabels_allocations,NULL); +static DEVICE_ATTR(tlabels_allocations,S_IRUGO,fw_show_ne_tlabels_allocations,NULL); -static ssize_t fw_ne_show_tlabels_mask(struct device *dev, char *buf) +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) @@ -205,49 +150,188 @@ return sprintf(buf, "0x%016lx\n", ne->tpool->pool[0]); #endif } -static DEVICE_ATTR(tlabels_mask,S_IRUGO,fw_ne_show_tlabels_mask,NULL); +static DEVICE_ATTR(tlabels_mask,S_IRUGO,fw_show_ne_tlabels_mask,NULL); + + +fw_attr(ne, struct node_entry, guid, unsigned long long, "0x%016Lx\n") +fw_attr(ne, struct node_entry, capabilities, unsigned int, "0x%06x\n") +fw_attr(ne, struct node_entry, vendor_id, unsigned int, "0x%06x\n") +fw_attr(ne, struct node_entry, nodeid, unsigned int, "0x%04x\n") +fw_attr(ne, struct node_entry, vendor_name, const char *, "%s\n") +fw_attr(ne, struct node_entry, oui_name, const char *, "%s\n") + +static struct device_attribute *const fw_ne_attrs[] = { + &dev_attr_ne_guid, + &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 if the value is preovided */ +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, 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++; + } + + if (id->match_flags & IEEE1394_MATCH_MODEL_ID) { + length += sprintf(scratch, "%smodel_id=0x%06x", + need_coma++ ? "," : "", + id->model_id); + scratch = buf + length; + } + + if (id->match_flags & IEEE1394_MATCH_SPECIFIER_ID) { + length += sprintf(scratch, "%sspecifier_id=0x%06x", + need_coma++ ? "," : "", + id->specifier_id); + scratch = buf + length; + } + + 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++; + } + } + + return length; +} +static DRIVER_ATTR(device_ids,S_IRUGO,fw_show_drv_device_ids,NULL); + + +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; - device_create_file(dev, &dev_attr_ne_guid); - device_create_file(dev, &dev_attr_ne_capabilities); - device_create_file(dev, &dev_attr_ne_vendor_id); - device_create_file(dev, &dev_attr_ne_nodeid); - device_create_file(dev, &dev_attr_bus_options); - device_create_file(dev, &dev_attr_tlabels_free); - device_create_file(dev, &dev_attr_tlabels_allocations); - device_create_file(dev, &dev_attr_tlabels_mask); + 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 void nodemgr_update_host_dev_links(struct hpsb_host *host) +{ + struct device *dev = &host->device; struct node_entry *ne; - device_create_file(dev, &dev_attr_host_node_count); - device_create_file(dev, &dev_attr_host_selfid_count); - device_create_file(dev, &dev_attr_host_nodes_active); - device_create_file(dev, &dev_attr_host_in_bus_reset); - device_create_file(dev, &dev_attr_host_is_root); - device_create_file(dev, &dev_attr_host_is_cycmst); - device_create_file(dev, &dev_attr_host_is_irm); - device_create_file(dev, &dev_attr_host_is_busmgr); + sysfs_remove_link(&dev->kobj, "irm_id"); + sysfs_remove_link(&dev->kobj, "busmgr_id"); + sysfs_remove_link(&dev->kobj, "host_id"); - if ((ne = hpsb_nodeid_get_entry(host->irm_id))) + if ((ne = hpsb_nodeid_get_entry(host, host->irm_id))) sysfs_create_link(&dev->kobj, &ne->device.kobj, "irm_id"); - if ((ne = hpsb_nodeid_get_entry(host->busmgr_id))) + if ((ne = hpsb_nodeid_get_entry(host, host->busmgr_id))) sysfs_create_link(&dev->kobj, &ne->device.kobj, "busmgr_id"); + if ((ne = hpsb_nodeid_get_entry(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; - device_create_file(dev, &dev_attr_ud_address); - device_create_file(dev, &dev_attr_ud_length); + 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); @@ -271,16 +355,137 @@ 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 device *dev) +{ + 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_model_id); + device_remove_file(dev, &dev_attr_ud_model_name); + + device_unregister(dev); +} + + +static void nodemgr_remove_ne(struct device *dev) +{ + int i; + struct list_head *lh, *next; + + list_for_each_safe(lh, next, &dev->children) + nodemgr_remove_ud(list_to_dev(lh)); + + for (i = 0; i < ARRAY_SIZE(fw_ne_attrs); i++) + device_remove_file(dev, fw_ne_attrs[i]); + + 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 device *child_dev = list_to_dev(lh); + struct node_entry *ne; + + ne = container_of(child_dev, struct node_entry, device); + /* Force free'ing of ne struct aswell */ + ne->device.release = nodemgr_release_ne; + + nodemgr_remove_ne(child_dev); + } + + for (i = 0; i < ARRAY_SIZE(fw_host_attrs); i++) + device_remove_file(dev, fw_host_attrs[i]); + + sysfs_remove_link(&dev->kobj, "irm_id"); + sysfs_remove_link(&dev->kobj, "busmgr_id"); + sysfs_remove_link(&dev->kobj, "host_id"); +} + + +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, + .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 void nodemgr_process_config_rom(struct node_entry *ne, - quadlet_t busoptions); static int nodemgr_read_quadlet(struct hpsb_host *host, nodeid_t nodeid, unsigned int generation, @@ -356,7 +561,8 @@ 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; } @@ -426,9 +632,13 @@ 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 host_info *hi, - 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; @@ -436,9 +646,6 @@ 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; @@ -446,50 +653,92 @@ ne->guid = guid; ne->generation = generation; - list_add_tail(&ne->list, &node_list); - + memcpy(&ne->device, &nodemgr_dev_template_ne, + sizeof(ne->device)); ne->device.parent = &host->device; - sprintf(ne->device.bus_id, "%d-" NODE_BUS_FMT, hi->id, NODE_BUS_ARGS(nodeid)); - sprintf(ne->device.name, "IEEE-1394 device %s", ne->device.bus_id); - ne->device.bus = &ieee1394_bus_type; - - device_register(&ne->device); - 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[%s] GUID[%016Lx] [%s] (%s)", + HPSB_DEBUG("%s added: ID:BUS[%d-" NODE_BUS_FMT "] GUID[%016Lx]", (host->node_id == nodeid) ? "Host" : "Node", - ne->device.bus_id, (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; +}; + +static int nodemgr_nodeid_search_cb(struct device *dev, void *__data) +{ + struct nodeid_search_baton *search = __data; struct node_entry *ne; - list_for_each(lh, &node_list) { - ne = list_entry(lh, struct node_entry, list); - if (ne->nodeid == nodeid) return 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 @@ -589,11 +838,10 @@ 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. - */ - + * software_version entries, in order to get driver autoloading working. */ static void nodemgr_process_unit_directory(struct node_entry *ne, octlet_t address, unsigned int id) { @@ -690,13 +938,11 @@ } } - 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; sprintf(ud->device.bus_id, "%s-%u", ne->device.bus_id, ud->id); sprintf(ud->device.name, "IEEE-1394 unit directory %s", ud->device.bus_id); - ud->device.bus = &ieee1394_bus_type; device_register(&ud->device); nodemgr_create_ud_dev_files(ud); @@ -809,79 +1055,54 @@ #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; - - /* User requested to disable hotplug when module was loaded. */ - if (nodemgr_disable_hotplug) - return; - - 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; - } + struct unit_directory *ud; + char *scratch; + int i = 0; + int length = 0; + + if (!dev) + return -ENODEV; + + if (dev->class_num != DEV_CLASS_UNIT_DIRECTORY) + return -ENODEV; + + ud = container_of(dev, struct unit_directory, device); + + scratch = buffer; + +#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) + + 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); - /* only one standardized param to hotplug command: type */ - argv[0] = hotplug_path; - argv[1] = "ieee1394"; - argv[2] = 0; - - /* minimal command environment */ - envp[i++] = "HOME=/"; - envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; +#undef PUT_ENVP -#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; + 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); + return 0; } #else -static inline 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) { -#ifdef CONFIG_IEEE1394_VERBOSEDEBUG - HPSB_DEBUG("NodeMgr: nodemgr_call_policy(): hotplug not enabled"); -#endif - return; + return -ENODEV; } #endif /* CONFIG_HOTPLUG */ @@ -919,135 +1140,11 @@ } } -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); -} - -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); -} - -void hpsb_release_unit_directory(struct unit_directory *ud) -{ - down(&nodemgr_serialize); - nodemgr_release_unit_directory(ud); - up(&nodemgr_serialize); -} - -static void nodemgr_free_unit_directories(struct node_entry *ne) -{ - struct list_head *lh; - struct unit_directory *ud; - - 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); - device_unregister(&ud->device); - kfree(ud); - } -} - -static struct ieee1394_device_id * -nodemgr_match_driver(struct hpsb_protocol_driver *driver, - struct unit_directory *ud) -{ - struct ieee1394_device_id *id; - - 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 id; - } - - 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; - } - } - - return match; -} - -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; - - if (driver->driver.name[0]) - driver_register(&driver->driver); - - 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 @@ -1059,26 +1156,14 @@ 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; @@ -1099,15 +1184,43 @@ ne->busopt.generation, ne->busopt.lnkspd); #endif - /* - * 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); + sprintf(ne->device.bus_id, "%d-" NODE_BUS_FMT, hi->id, NODE_BUS_ARGS(ne->nodeid)); + sprintf(ne->device.name, "IEEE-1394 device %s", ne->device.bus_id); + + device_register(&ne->device); + nodemgr_create_ne_dev_files(ne); + nodemgr_process_root_directory(ne); - nodemgr_bind_drivers(ne); +} + + +/* 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; } /* @@ -1118,29 +1231,30 @@ * 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; - if (ne->nodeid != nodeid) { HPSB_DEBUG("Node " NODE_BUS_FMT " changed to " NODE_BUS_FMT, NODE_BUS_ARGS(ne->nodeid), NODE_BUS_ARGS(nodeid)); ne->nodeid = nodeid; } - if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) - nodemgr_process_config_rom (ne, busoptions); + /* If the node's configrom generation has changed, we unregister + * it, which in turn unregisters it's children (unit directories). */ + if (ne->busopt.generation != ((busoptions >> 4) & 0xf)) { + nodemgr_remove_ne(&ne->device); + + /* This will re-register our node + ud's */ + nodemgr_process_config_rom (hi, ne, busoptions); + } /* 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, @@ -1204,19 +1318,6 @@ 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); - device_unregister(&ne->device); - kfree(ne); - - return; -} /* This is where we probe the nodes for their information and provided * features. */ @@ -1253,36 +1354,40 @@ if (!ne) 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 host_info *hi) { int count; @@ -1314,7 +1419,6 @@ nodeid++; continue; } - nodemgr_node_probe_one(hi, nodeid++, generation); } @@ -1324,8 +1428,28 @@ * 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[%s] GUID[%016Lx]", + ne->device.bus_id, (unsigned long long)ne->guid); + + /* Causes ne to be free'd when the device isn't + * referenced anymore. */ + ne->device.release = nodemgr_release_ne; + + nodemgr_remove_ne(&ne->device); + } + } return; } @@ -1346,8 +1470,7 @@ 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 @@ -1379,33 +1502,34 @@ static int nodemgr_host_thread(void *__hi) { struct host_info *hi = (struct host_info *)__hi; - int host_dev_files = 0; + struct hpsb_host *host = hi->host; /* No userlevel access needed */ 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)) { - 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); - nodemgr_do_irm_duties(hi->host); + nodemgr_do_irm_duties(host); up(&nodemgr_serialize); - /* First time around, let's also create the host dev files */ - if (!host_dev_files) { - nodemgr_create_host_dev_files(hi->host); - host_dev_files = 1; - } + /* Update some of our sysfs symlinks */ + nodemgr_update_host_dev_links(host); } #ifdef CONFIG_IEEE1394_VERBOSEDEBUG HPSB_DEBUG ("NodeMgr: Exiting thread for %s", hi->host->driver->name); @@ -1425,24 +1549,24 @@ 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; @@ -1523,14 +1647,13 @@ hi->id = nodemgr_alloc_host_num(); + memcpy(&host->device, &nodemgr_dev_template_host, + sizeof(host->device)); host->device.parent = &host->pdev->dev; sprintf(host->device.bus_id, "fw-host%d", hi->id); sprintf(host->device.name, "IEEE-1394 Host %s-%d", host->driver->name, hi->id); - host->device.bus = &ieee1394_bus_type; - sprintf(hi->daemon_name, "knodemgrd/%d", hi->id); - - device_register(&host->device); + sprintf(hi->daemon_name, "knodemgrd_%d", hi->id); hi->pid = kernel_thread(nodemgr_host_thread, hi, CLONE_FS | CLONE_FILES | CLONE_SIGHAND); @@ -1538,7 +1661,6 @@ if (hi->pid < 0) { HPSB_ERR ("NodeMgr: failed to start %s thread for %s", hi->daemon_name, host->driver->name); - device_unregister(&host->device); kfree(hi); return; } @@ -1581,7 +1703,6 @@ 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; @@ -1600,28 +1721,14 @@ 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); - } - - device_unregister(&host->device); - - up(&nodemgr_serialize); - return; } @@ -1633,10 +1740,8 @@ static struct hpsb_highlevel *hl; -void init_ieee1394_nodemgr(int disable_hotplug) +void init_ieee1394_nodemgr(void) { - nodemgr_disable_hotplug = disable_hotplug; - bus_register(&ieee1394_bus_type); hl = hpsb_register_highlevel("Node manager", &nodemgr_ops); Modified: trunk/nodemgr.h ============================================================================== --- trunk/nodemgr.h (original) +++ trunk/nodemgr.h 2003-03-10 15:38:07.000000000 -0500 @@ -78,6 +78,12 @@ 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 @@ -89,11 +95,6 @@ * 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 */ @@ -108,15 +109,6 @@ quadlet_t specifier_id; quadlet_t version; - struct hpsb_protocol_driver *driver; - void *driver_data; - - /* For linking the nodes managed by the driver, or unmanaged nodes */ - struct list_head driver_list; - - /* For linking directories belonging to a node */ - struct list_head node_list; - unsigned int id; int length; /* Number of quadlets */ @@ -128,7 +120,6 @@ }; struct node_entry { - struct list_head list; u64 guid; /* GUID of this node */ struct hpsb_host *host; /* Host this node is attached to */ nodeid_t nodeid; /* NodeID */ @@ -138,7 +129,6 @@ /* The following is read from the config rom */ u32 vendor_id; u32 capabilities; - struct list_head unit_directories; struct hpsb_tlabel_pool *tpool; @@ -165,11 +155,11 @@ /* 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 @@ -199,7 +189,7 @@ 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 */ Modified: trunk/sbp2.c ============================================================================== --- trunk/sbp2.c (original) +++ trunk/sbp2.c 2003-03-10 15:38:07.000000000 -0500 @@ -444,12 +444,10 @@ * 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 *)); @@ -464,7 +462,6 @@ 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, }; @@ -482,12 +479,12 @@ static struct hpsb_protocol_driver sbp2_driver = { .name = "SBP2 Driver", .id_table = sbp2_id_table, - .probe = sbp2_probe, - .disconnect = sbp2_disconnect, .update = sbp2_update, .driver = { - .name = "sbp2", + .name = SBP2_DEVICE_NAME, .bus = &ieee1394_bus_type, + .probe = sbp2_probe, + .remove = sbp2_remove, }, }; @@ -631,9 +628,9 @@ * 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; @@ -669,9 +666,9 @@ /* * 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; @@ -682,11 +679,11 @@ 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"); @@ -756,8 +753,7 @@ 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; @@ -832,78 +828,86 @@ * 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; @@ -911,11 +915,15 @@ 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; @@ -945,7 +953,7 @@ scsi_unregister(hi->scsi_host); } - return; + return hi; } /* @@ -1030,6 +1038,8 @@ 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), @@ -1058,7 +1068,7 @@ 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, @@ -1087,7 +1097,8 @@ 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"); @@ -1098,7 +1109,7 @@ 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); @@ -1131,9 +1142,9 @@ /* * 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; } @@ -1142,35 +1153,33 @@ */ 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); @@ -1185,21 +1194,21 @@ /* * 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; @@ -1293,8 +1302,9 @@ * 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"); @@ -1420,8 +1430,9 @@ * 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"); @@ -1478,8 +1489,9 @@ * 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"); @@ -1566,8 +1578,8 @@ * 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"); @@ -1719,8 +1731,10 @@ * 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 */ @@ -1749,8 +1763,9 @@ /* * 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; @@ -1793,8 +1808,7 @@ * 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_o... [truncated message content] |