Commit 7b55ea65 authored by Ben Collins's avatar Ben Collins Committed by Linus Torvalds

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