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