patch-2.4.21 linux-2.4.21/drivers/ieee1394/sbp2.c
Next file: linux-2.4.21/drivers/ieee1394/sbp2.h
Previous file: linux-2.4.21/drivers/ieee1394/raw1394.h
Back to the patch index
Back to the overall index
- Lines: 1948
- Date:
2003-06-13 07:51:34.000000000 -0700
- Orig file:
linux-2.4.20/drivers/ieee1394/sbp2.c
- Orig date:
2002-11-28 15:53:13.000000000 -0800
diff -urN linux-2.4.20/drivers/ieee1394/sbp2.c linux-2.4.21/drivers/ieee1394/sbp2.c
@@ -84,8 +84,6 @@
* 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_max_outstanding_cmds - Change max outstanding concurrent commands (default = 8)
- * sbp2_max_cmds_per_lun - Change max concurrent commands per sbp2 device (default = 1)
* 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)
@@ -298,6 +296,9 @@
* returns the dead bit in status. Thanks to Chandan (chandan@toad.net) for this one.
* 04/27/02 - Fix sbp2 login problem on SMP systems, enable real spinlocks by default. (JSG)
* 06/09/02 - Don't force 36-bute SCSI inquiry, but leave in a define for badly behaved devices. (JSG)
+ * 02/04/03 - Fixed a SMP deadlock (don't hold sbp2_command_lock while calling sbp2scsi_complete_command).
+ * Also save/restore irq flags in sbp2scsi_complete_command - Sancho Dauskardt <sda@bdit.de>
+ *
*/
@@ -320,7 +321,6 @@
#include <linux/blk.h>
#include <linux/smp_lock.h>
#include <linux/init.h>
-#include <linux/blk.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include <asm/io.h>
@@ -351,7 +351,7 @@
#include "sbp2.h"
static char version[] __devinitdata =
- "$Rev: 584 $ James Goodwin <jamesg@filanet.com>";
+ "$Rev: 906 $ James Goodwin <jamesg@filanet.com>";
/*
* Module load parameter definitions
@@ -364,15 +364,10 @@
* NOTE: On certain OHCI parts I have seen short packets on async transmit
* (probably due to PCI latency/throughput issues with the part). You can
* 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)
*/
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;
+MODULE_PARM_DESC(sbp2_max_speed, "Force max speed (3 = 800mb, 2 = 400mb default, 1 = 200mb, 0 = 100mb)");
+static int sbp2_max_speed = SPEED_MAX;
/*
* Set sbp2_serialize_io to 1 if you'd like only one scsi command sent
@@ -396,33 +391,14 @@
static int sbp2_max_sectors = SBP2_MAX_SECTORS;
/*
- * Adjust sbp2_max_outstanding_cmds to tune performance if you have many
- * sbp2 devices attached (or if you need to do some debugging).
- */
-MODULE_PARM(sbp2_max_outstanding_cmds,"i");
-MODULE_PARM_DESC(sbp2_max_outstanding_cmds, "Change max outstanding concurrent commands (default = 8)");
-static int sbp2_max_outstanding_cmds = SBP2SCSI_MAX_OUTSTANDING_CMDS;
-
-/*
- * Adjust sbp2_max_cmds_per_lun to tune performance. Enabling more than
- * one concurrent/linked command per sbp2 device may allow some
- * performance gains, but some older sbp2 devices have firmware bugs
- * resulting in problems when linking commands... so, enable this with
- * care. I can note that the Oxsemi OXFW911 sbp2 chipset works very well
- * with large numbers of concurrent/linked commands. =)
- */
-MODULE_PARM(sbp2_max_cmds_per_lun,"i");
-MODULE_PARM_DESC(sbp2_max_cmds_per_lun, "Change max concurrent commands per sbp2 device (default = 1)");
-static int sbp2_max_cmds_per_lun = SBP2SCSI_MAX_CMDS_PER_LUN;
-
-/*
* Exclusive login to sbp2 device? In most cases, the sbp2 driver should
* do an exclusive login, as it's generally unsafe to have two hosts
* talking to a single sbp2 device at the same time (filesystem coherency,
* 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, then set sbp2_exclusive_login to
- * zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
+ * filesystem supporting multiple hosts (one such filesystem is OpenGFS,
+ * see opengfs.sourceforge.net for more info), then set sbp2_exclusive_login
+ * to zero. Note: The Oxsemi OXFW911 sbp2 chipset supports up to four
* concurrent logins.
*/
MODULE_PARM(sbp2_exclusive_login,"i");
@@ -512,33 +488,22 @@
#define SBP2_ERR(fmt, args...) HPSB_ERR("sbp2: "fmt, ## args)
-/*
- * Spinlock debugging stuff.
- */
-#define SBP2_USE_REAL_SPINLOCKS
-
-#ifdef SBP2_USE_REAL_SPINLOCKS
-#define sbp2_spin_lock(lock, flags) spin_lock_irqsave(lock, flags)
-#define sbp2_spin_unlock(lock, flags) spin_unlock_irqrestore(lock, flags);
-static spinlock_t sbp2_host_info_lock = SPIN_LOCK_UNLOCKED;
-#else
-#define sbp2_spin_lock(lock, flags) do {save_flags(flags); cli();} while (0)
-#define sbp2_spin_unlock(lock, flags) do {restore_flags(flags);} while (0)
-#endif
/*
* Globals
*/
-static Scsi_Host_Template scsi_driver_template;
-
-static u8 sbp2_speedto_maxrec[] = { 0x7, 0x8, 0x9 };
-
-static LIST_HEAD(sbp2_host_info_list);
+static void sbp2scsi_complete_all_commands(struct scsi_id_instance_data *scsi_id,
+ u32 status);
-static struct hpsb_highlevel *sbp2_hl_handle = NULL;
+static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
+ u32 scsi_status, Scsi_Cmnd *SCpnt,
+ void (*done)(Scsi_Cmnd *));
+
+static Scsi_Host_Template scsi_driver_template;
-static struct hpsb_highlevel_ops sbp2_hl_ops = {
+static struct hpsb_highlevel sbp2_highlevel = {
+ .name = SBP2_DEVICE_NAME,
.add_host = sbp2_add_host,
.remove_host = sbp2_remove_host,
};
@@ -557,7 +522,7 @@
static struct hpsb_protocol_driver sbp2_driver = {
.name = "SBP2 Driver",
.id_table = sbp2_id_table,
- .probe = sbp2_probe,
+ .probe = sbp2_probe,
.disconnect = sbp2_disconnect,
.update = sbp2_update
};
@@ -660,90 +625,11 @@
return ((i > 0) ? 0:1);
}
-/*
- * This function is called to initially create a packet pool for use in
- * sbp2 I/O requests. This packet pool is used when sending out sbp2
- * command and agent reset requests, and allows us to remove all
- * kmallocs/kfrees from the critical I/O paths.
- */
-static int sbp2util_create_request_packet_pool(struct sbp2scsi_host_info *hi)
+/* Free's an allocated packet */
+static void sbp2_free_packet(struct hpsb_packet *packet)
{
- struct hpsb_packet *packet;
- int i;
-
- hi->request_packet = kmalloc(sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS,
- GFP_KERNEL);
-
- if (!hi->request_packet) {
- SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!");
- return(-ENOMEM);
- }
- memset(hi->request_packet, 0, sizeof(struct sbp2_request_packet) * SBP2_MAX_REQUEST_PACKETS);
-
- /*
- * Create a pool of request packets. Just take the max supported
- * concurrent commands and multiply by two to be safe...
- */
- for (i=0; i<SBP2_MAX_REQUEST_PACKETS; i++) {
-
- /*
- * Max payload of 8 bytes since the sbp2 command request
- * uses a payload of 8 bytes, and agent reset is a quadlet
- * write request. Bump this up if we plan on using this
- * pool for other stuff.
- */
- packet = alloc_hpsb_packet(8);
-
- if (!packet) {
- SBP2_ERR("sbp2util_create_request_packet_pool - packet allocation failed!");
- return(-ENOMEM);
- }
-
- /*
- * Put these request packets into a free list
- */
- INIT_LIST_HEAD(&hi->request_packet[i].list);
- hi->request_packet[i].packet = packet;
- list_add_tail(&hi->request_packet[i].list, &hi->sbp2_req_free);
-
- }
-
- return(0);
-}
-
-/*
- * This function is called to remove the packet pool. It is called when
- * the sbp2 driver is unloaded.
- */
-static void sbp2util_remove_request_packet_pool(struct sbp2scsi_host_info *hi)
-{
- struct list_head *lh;
- struct sbp2_request_packet *request_packet;
- unsigned long flags;
-
- /*
- * Go through free list releasing packets
- */
- sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
- while (!list_empty(&hi->sbp2_req_free)) {
-
- lh = hi->sbp2_req_free.next;
- list_del(lh);
-
- request_packet = list_entry(lh, struct sbp2_request_packet, list);
-
- /*
- * Free the hpsb packets that we allocated for the pool
- */
- if (request_packet) {
- free_hpsb_packet(request_packet->packet);
- }
-
- }
- kfree(hi->request_packet);
- sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
-
- return;
+ hpsb_free_tlabel(packet);
+ free_hpsb_packet(packet);
}
/*
@@ -753,110 +639,48 @@
* out a free request packet and re-initialize values in it. I'm sure this
* can still stand some more optimization.
*/
-static struct sbp2_request_packet *
-sbp2util_allocate_write_request_packet(struct sbp2scsi_host_info *hi,
- struct node_entry *ne, u64 addr,
- size_t data_size,
- quadlet_t data) {
- struct list_head *lh;
- struct sbp2_request_packet *request_packet = NULL;
+static struct hpsb_packet *
+sbp2util_allocate_write_packet(struct sbp2scsi_host_info *hi,
+ struct node_entry *ne, u64 addr,
+ size_t data_size,
+ quadlet_t *data)
+{
struct hpsb_packet *packet;
- unsigned long flags;
-
- sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
- if (!list_empty(&hi->sbp2_req_free)) {
-
- /*
- * Pull out a free request packet
- */
- lh = hi->sbp2_req_free.next;
- list_del(lh);
-
- request_packet = list_entry(lh, struct sbp2_request_packet, list);
- packet = request_packet->packet;
-
- /*
- * Initialize the packet (this is really initialization
- * the core 1394 stack should do, but I'm doing it myself
- * to avoid the overhead).
- */
- packet->data_size = data_size;
- INIT_LIST_HEAD(&packet->list);
- sema_init(&packet->state_change, 0);
- packet->state = hpsb_unused;
- packet->data_be = 1;
-
- hpsb_node_fill_packet(ne, packet);
- packet->tlabel = get_tlabel(hi->host, packet->node_id, 0);
-
- if (!data_size) {
- fill_async_writequad(packet, addr, data);
- } else {
- fill_async_writeblock(packet, addr, data_size);
- }
+ packet = hpsb_make_writepacket(hi->host, ne->nodeid,
+ addr, data, data_size);
- /*
- * Set up a task queue completion routine, which returns
- * the packet to the free list and releases the tlabel.
- */
- request_packet->tq.routine = (void (*)(void*))sbp2util_free_request_packet;
- request_packet->tq.data = request_packet;
- request_packet->hi_context = hi;
- hpsb_add_packet_complete_task(packet, &request_packet->tq);
+ if (!packet)
+ return NULL;
- /*
- * Now, put the packet on the in-use list.
- */
- list_add_tail(&request_packet->list, &hi->sbp2_req_inuse);
+ hpsb_set_packet_complete_task(packet, (void (*)(void*))sbp2_free_packet,
+ packet);
- } else {
- SBP2_ERR("sbp2util_allocate_request_packet - no packets available!");
- }
- sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
+ hpsb_node_fill_packet(ne, packet);
- return(request_packet);
+ return packet;
}
-/*
- * This function is called to return a packet to our packet pool. It is
- * also called as a completion routine when a request packet is completed.
- */
-static void sbp2util_free_request_packet(struct sbp2_request_packet *request_packet)
-{
- unsigned long flags;
- struct sbp2scsi_host_info *hi = request_packet->hi_context;
-
- /*
- * Free the tlabel, and return the packet to the free pool.
- */
- sbp2_spin_lock(&hi->sbp2_request_packet_lock, flags);
- free_tlabel(hi->host, LOCAL_BUS | request_packet->packet->node_id,
- request_packet->packet->tlabel);
- list_del(&request_packet->list);
- list_add_tail(&request_packet->list, &hi->sbp2_req_free);
- sbp2_spin_unlock(&hi->sbp2_request_packet_lock, flags);
-
- return;
-}
/*
* 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;
+ unsigned long flags, orbs;
struct sbp2_command_info *command;
+
+ orbs = sbp2_serialize_io ? 2 : SBP2_MAX_COMMAND_ORBS;
- sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
- for (i = 0; i < scsi_id->sbp2_total_command_orbs; i++) {
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
+ for (i = 0; i < orbs; i++) {
command = (struct sbp2_command_info *)
- kmalloc(sizeof(struct sbp2_command_info), GFP_KERNEL);
+ kmalloc(sizeof(struct sbp2_command_info), GFP_ATOMIC);
if (!command) {
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return(-ENOMEM);
}
memset(command, '\0', sizeof(struct sbp2_command_info));
@@ -873,31 +697,31 @@
INIT_LIST_HEAD(&command->list);
list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
}
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return 0;
}
/*
* 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;
- sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
list_for_each_safe(lh, next, &scsi_id->sbp2_command_orb_completed) {
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");
@@ -905,7 +729,7 @@
kfree(command);
}
}
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return;
}
@@ -920,17 +744,17 @@
struct sbp2_command_info *command;
unsigned long flags;
- sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {
command = list_entry(lh, struct sbp2_command_info, list);
if (command->command_orb_dma == orb) {
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return (command);
}
}
}
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
SBP2_ORB_DEBUG("could not match command orb %x", (unsigned int)orb);
@@ -947,17 +771,17 @@
struct sbp2_command_info *command;
unsigned long flags;
- sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
if (!list_empty(&scsi_id->sbp2_command_orb_inuse)) {
list_for_each(lh, &scsi_id->sbp2_command_orb_inuse) {
command = list_entry(lh, struct sbp2_command_info, list);
if (command->Current_SCpnt == SCpnt) {
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return (command);
}
}
}
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return(NULL);
}
@@ -967,14 +791,13 @@
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;
unsigned long flags;
- sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
if (!list_empty(&scsi_id->sbp2_command_orb_completed)) {
lh = scsi_id->sbp2_command_orb_completed.next;
list_del(lh);
@@ -985,7 +808,7 @@
} else {
SBP2_ERR("sbp2util_allocate_command_orb - No orbs available!");
}
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
return (command);
}
@@ -993,10 +816,10 @@
static void sbp2util_free_command_dma(struct sbp2_command_info *command)
{
struct sbp2scsi_host_info *hi;
-
- hi = (struct sbp2scsi_host_info *) command->Current_SCpnt->host->hostdata[0];
- if (hi == NULL) {
+ hi = hpsb_get_hostinfo_bykey(&sbp2_highlevel,
+ (unsigned long)command->Current_SCpnt->device->host->hostt);
+ if (!hi) {
printk(KERN_ERR "%s: hi == NULL\n", __FUNCTION__);
return;
}
@@ -1007,13 +830,8 @@
command->dma_size, command->dma_dir);
SBP2_DMA_FREE("single bulk");
} else if (command->dma_type == CMD_DMA_PAGE) {
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
- pci_unmap_single(hi->host->pdev, command->cmd_dma,
- command->dma_size, command->dma_dir);
-#else
pci_unmap_page(hi->host->pdev, command->cmd_dma,
command->dma_size, command->dma_dir);
-#endif /* Linux version < 2.4.13 */
SBP2_DMA_FREE("single page");
} /* XXX: Check for CMD_DMA_NONE bug */
command->dma_type = CMD_DMA_NONE;
@@ -1035,11 +853,11 @@
{
unsigned long flags;
- sbp2_spin_lock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_lock_irqsave(&scsi_id->sbp2_command_orb_lock, flags);
list_del(&command->list);
sbp2util_free_command_dma(command);
list_add_tail(&command->list, &scsi_id->sbp2_command_orb_completed);
- sbp2_spin_unlock(&scsi_id->sbp2_command_orb_lock, flags);
+ spin_unlock_irqrestore(&scsi_id->sbp2_command_orb_lock, flags);
}
@@ -1052,53 +870,22 @@
* This function is called at SCSI init in order to register our driver
* with the IEEE-1394 stack.
*/
-int sbp2_init(void)
+static int sbp2scsi_detect(Scsi_Host_Template *tpnt)
{
- SBP2_DEBUG("sbp2_init");
+ struct Scsi_Host *scsi_host;
+ struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(&sbp2_highlevel, (unsigned long)tpnt);
- /*
- * Register our high level driver with 1394 stack
- */
- sbp2_hl_handle = hpsb_register_highlevel(SBP2_DEVICE_NAME, &sbp2_hl_ops);
-
- if (sbp2_hl_handle == NULL) {
- SBP2_ERR("sbp2 failed to register with ieee1394 highlevel");
- return(-ENOMEM);
- }
+ SBP2_DEBUG("sbp2scsi_detect");
- /*
- * Register our sbp2 status address space...
- */
- hpsb_register_addrspace(sbp2_hl_handle, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
- SBP2_STATUS_FIFO_ADDRESS +
- SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
+ /* Register our host with the SCSI stack. */
+ if (!(scsi_host = scsi_register(tpnt, 0)))
+ return 0;
- /*
- * Handle data movement if physical dma is not enabled/supported on host controller
- */
-#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
- hpsb_register_addrspace(sbp2_hl_handle, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);
-#endif
+ scsi_set_pci_device(scsi_host, hi->host->pdev);
- hpsb_register_protocol(&sbp2_driver);
+ tpnt->present = 1;
- return 0;
-}
-
-/*
- * This function is called from cleanup module, or during shut-down, in
- * order to unregister our driver.
- */
-void sbp2_cleanup(void)
-{
- SBP2_DEBUG("sbp2_cleanup");
-
- hpsb_unregister_protocol(&sbp2_driver);
-
- if (sbp2_hl_handle) {
- hpsb_unregister_highlevel(sbp2_hl_handle);
- sbp2_hl_handle = NULL;
- }
+ return tpnt->present;
}
static int sbp2_probe(struct unit_directory *ud)
@@ -1106,22 +893,20 @@
struct sbp2scsi_host_info *hi;
SBP2_DEBUG("sbp2_probe");
- hi = sbp2_find_host_info(ud->ne->host);
+ hi = hpsb_get_hostinfo(&sbp2_highlevel, ud->ne->host);
return sbp2_start_device(hi, ud);
}
static void sbp2_disconnect(struct unit_directory *ud)
{
- struct sbp2scsi_host_info *hi;
struct scsi_id_instance_data *scsi_id = ud->driver_data;
SBP2_DEBUG("sbp2_disconnect");
- hi = sbp2_find_host_info(ud->ne->host);
- if (hi != NULL) {
- sbp2_logout_device(hi, scsi_id);
- sbp2_remove_device(hi, scsi_id);
+ if (scsi_id) {
+ sbp2_logout_device(scsi_id);
+ sbp2_remove_device(scsi_id);
}
}
@@ -1132,56 +917,52 @@
unsigned long flags;
SBP2_DEBUG("sbp2_update");
- hi = sbp2_find_host_info(ud->ne->host);
+ hi = hpsb_get_hostinfo(&sbp2_highlevel, 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);
+ sbp2_remove_device(scsi_id);
hpsb_release_unit_directory(ud);
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, 0);
+ sbp2_agent_reset(scsi_id, 0);
/* 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
*/
- sbp2_spin_lock(&hi->sbp2_command_lock, flags);
- sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);
- sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+ spin_lock_irqsave(&hi->sbp2_command_lock, flags);
+ 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)
{
struct sbp2scsi_host_info *hi;
- unsigned long flags;
SBP2_DEBUG("sbp2_add_host");
/* Allocate some memory for our host info structure */
- hi = (struct sbp2scsi_host_info *)kmalloc(sizeof(struct sbp2scsi_host_info),
- GFP_KERNEL);
+ hi = hpsb_create_hostinfo(&sbp2_highlevel, host, sizeof(*hi));
if (hi == NULL) {
SBP2_ERR("out of memory in sbp2_add_host");
@@ -1189,70 +970,36 @@
}
/* Initialize some host stuff */
- memset(hi, 0, sizeof(struct sbp2scsi_host_info));
- INIT_LIST_HEAD(&hi->list);
- INIT_LIST_HEAD(&hi->sbp2_req_inuse);
- INIT_LIST_HEAD(&hi->sbp2_req_free);
hi->host = host;
hi->sbp2_command_lock = SPIN_LOCK_UNLOCKED;
- hi->sbp2_request_packet_lock = SPIN_LOCK_UNLOCKED;
- /* Create our request packet pool (pool of packets for use in I/O) */
- if (sbp2util_create_request_packet_pool(hi)) {
- SBP2_ERR("sbp2util_create_request_packet_pool failed!");
+ memcpy(&hi->sht, &scsi_driver_template, sizeof hi->sht);
+ sprintf(hi->proc_name, "%s_%d", SBP2_DEVICE_NAME, host->id);
+ hi->sht.proc_name = hi->proc_name;
+ hpsb_set_hostinfo_key(&sbp2_highlevel, host, (unsigned long)&hi->sht);
+
+ if (SCSI_REGISTER_HOST(&hi->sht)) {
+ SBP2_ERR("Failed to register scsi template for ieee1394 host");
+ hpsb_destroy_hostinfo(&sbp2_highlevel, host);
+ return;
+ }
+
+ for (hi->scsi_host = scsi_hostlist; hi->scsi_host; hi->scsi_host = hi->scsi_host->next)
+ if (hi->scsi_host->hostt == &hi->sht)
+ break;
+
+ if (!hi->scsi_host) {
+ SBP2_ERR("Failed to register scsi host for ieee1394 host");
+ SCSI_UNREGISTER_HOST(&hi->sht);
+ hpsb_destroy_hostinfo(&sbp2_highlevel, host);
return;
}
- sbp2_spin_lock(&sbp2_host_info_lock, flags);
- list_add_tail(&hi->list, &sbp2_host_info_list);
- sbp2_spin_unlock(&sbp2_host_info_lock, flags);
-
- /* Register our host with the SCSI stack. */
- hi->scsi_host = scsi_register (&scsi_driver_template, sizeof(void *));
- if (hi->scsi_host) {
- hi->scsi_host->hostdata[0] = (unsigned long)hi;
- hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
- }
- scsi_driver_template.present++;
+ hi->scsi_host->max_id = SBP2SCSI_MAX_SCSI_IDS;
return;
}
-/*
- * This fuction returns a host info structure from the host structure, in
- * case we have multiple hosts.
- */
-static struct sbp2scsi_host_info *sbp2_find_host_info(struct hpsb_host *host)
-{
- struct list_head *lh;
- struct sbp2scsi_host_info *hi;
-
- list_for_each (lh, &sbp2_host_info_list) {
- hi = list_entry(lh, struct sbp2scsi_host_info, list);
- if (hi->host == host)
- return hi;
- }
-
- return NULL;
-}
-
-/*
- * This function returns a host info structure for a given Scsi_Host
- * struct.
- */
-static struct sbp2scsi_host_info *sbp2_find_host_info_scsi(struct Scsi_Host *host)
-{
- struct list_head *lh;
- struct sbp2scsi_host_info *hi;
-
- list_for_each (lh, &sbp2_host_info_list) {
- hi = list_entry(lh, struct sbp2scsi_host_info, list);
- if (hi->scsi_host == host)
- return hi;
- }
-
- return NULL;
-}
/*
* This function is called when a host is removed.
@@ -1260,22 +1007,15 @@
static void sbp2_remove_host(struct hpsb_host *host)
{
struct sbp2scsi_host_info *hi;
- unsigned long flags;
SBP2_DEBUG("sbp2_remove_host");
- sbp2_spin_lock(&sbp2_host_info_lock, flags);
+ hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
- hi = sbp2_find_host_info(host);
- if (hi != NULL) {
- sbp2util_remove_request_packet_pool(hi);
- list_del(&hi->list);
- kfree(hi);
- }
+ if (hi)
+ SCSI_UNREGISTER_HOST(&hi->sht);
else
SBP2_ERR("attempt to remove unknown host %p", host);
-
- sbp2_spin_unlock(&sbp2_host_info_lock, flags);
}
/*
@@ -1301,6 +1041,8 @@
goto alloc_fail_first;
memset(scsi_id, 0, sizeof(struct scsi_id_instance_data));
+ scsi_id->hi = hi;
+
/* Login FIFO DMA */
scsi_id->login_response =
pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_login_response),
@@ -1309,6 +1051,22 @@
goto alloc_fail;
SBP2_DMA_ALLOC("consistent DMA region for login FIFO");
+ /* Query logins ORB DMA */
+ scsi_id->query_logins_orb =
+ pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_orb),
+ &scsi_id->query_logins_orb_dma);
+ if (!scsi_id->query_logins_orb)
+ goto alloc_fail;
+ SBP2_DMA_ALLOC("consistent DMA region for query logins ORB");
+
+ /* Query logins response DMA */
+ scsi_id->query_logins_response =
+ pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_query_logins_response),
+ &scsi_id->query_logins_response_dma);
+ if (!scsi_id->query_logins_response)
+ goto alloc_fail;
+ SBP2_DMA_ALLOC("consistent DMA region for query logins response");
+
/* Reconnect ORB DMA */
scsi_id->reconnect_orb =
pci_alloc_consistent(hi->host->pdev, sizeof(struct sbp2_reconnect_orb),
@@ -1329,8 +1087,24 @@
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->query_logins_response) {
+ pci_free_consistent(hi->host->pdev,
+ sizeof(struct sbp2_query_logins_response),
+ scsi_id->query_logins_response,
+ scsi_id->query_logins_response_dma);
+ SBP2_DMA_FREE("query logins response DMA");
+ }
+
+ if (scsi_id->query_logins_orb) {
+ pci_free_consistent(hi->host->pdev,
+ sizeof(struct sbp2_query_logins_orb),
+ scsi_id->query_logins_orb,
+ scsi_id->query_logins_orb_dma);
+ SBP2_DMA_FREE("query logins ORB DMA");
+ }
+
if (scsi_id->logout_orb) {
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_logout_orb),
@@ -1358,7 +1132,8 @@
kfree(scsi_id);
alloc_fail_first:
SBP2_ERR ("Could not allocate memory for scsi_id");
- return(-ENOMEM);
+
+ return -ENOMEM;
}
SBP2_DMA_ALLOC("consistent DMA region for login ORB");
@@ -1368,7 +1143,7 @@
scsi_id->ne = ne;
scsi_id->ud = ud;
scsi_id->speed_code = SPEED_100;
- scsi_id->max_payload_size = sbp2_speedto_maxrec[SPEED_100];
+ scsi_id->max_payload_size = hpsb_speedto_maxrec[SPEED_100];
ud->driver_data = scsi_id;
atomic_set(&scsi_id->sbp2_login_complete, 0);
@@ -1379,7 +1154,6 @@
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_inuse);
INIT_LIST_HEAD(&scsi_id->sbp2_command_orb_completed);
scsi_id->sbp2_command_orb_lock = SPIN_LOCK_UNLOCKED;
- scsi_id->sbp2_total_command_orbs = 0;
/*
* Make sure that we've gotten ahold of the sbp2 management agent
@@ -1388,19 +1162,10 @@
*/
sbp2_parse_unit_directory(scsi_id);
- scsi_id->sbp2_total_command_orbs = SBP2_MAX_COMMAND_ORBS;
-
- /*
- * Knock the total command orbs down if we are serializing I/O
- */
- if (sbp2_serialize_io) {
- scsi_id->sbp2_total_command_orbs = 2; /* one extra for good measure */
- }
-
/*
* Find an empty spot to stick our scsi id instance data.
*/
- for (i = 0; i < SBP2SCSI_MAX_SCSI_IDS; i++) {
+ for (i = 0; i < hi->scsi_host->max_id; i++) {
if (!hi->scsi_id[i]) {
hi->scsi_id[i] = scsi_id;
scsi_id->id = i;
@@ -1412,46 +1177,44 @@
/*
* 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;
}
/*
* Make sure we are not out of space
*/
- if (i == SBP2SCSI_MAX_SCSI_IDS) {
+ 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, 0);
+ 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);
return 0;
}
@@ -1459,18 +1222,19 @@
/*
* 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;
+
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);
/* Clean up any other structures */
- if (scsi_id->sbp2_total_command_orbs) {
- sbp2util_remove_command_orb_pool(scsi_id, hi);
- }
+ sbp2util_remove_command_orb_pool(scsi_id);
+
+ hi->scsi_id[scsi_id->id] = NULL;
if (scsi_id->login_response) {
pci_free_consistent(hi->host->pdev,
@@ -1500,12 +1264,28 @@
pci_free_consistent(hi->host->pdev,
sizeof(struct sbp2_logout_orb),
scsi_id->logout_orb,
- scsi_id->reconnect_orb_dma);
+ scsi_id->logout_orb_dma);
SBP2_DMA_FREE("single logout orb");
}
+ if (scsi_id->query_logins_orb) {
+ pci_free_consistent(hi->host->pdev,
+ sizeof(struct sbp2_query_logins_orb),
+ scsi_id->query_logins_orb,
+ scsi_id->query_logins_orb_dma);
+ SBP2_DMA_FREE("single query logins orb");
+ }
+
+ if (scsi_id->query_logins_response) {
+ pci_free_consistent(hi->host->pdev,
+ sizeof(struct sbp2_query_logins_response),
+ scsi_id->query_logins_response,
+ scsi_id->query_logins_response_dma);
+ SBP2_DMA_FREE("single query logins data");
+ }
+
SBP2_DEBUG("SBP-2 device removed, SCSI ID = %d", scsi_id->id);
- hi->scsi_id[scsi_id->id] = NULL;
+
kfree(scsi_id);
}
@@ -1515,7 +1295,7 @@
* physical dma in hardware). Mostly just here for debugging...
*/
static int sbp2_handle_physdma_write(struct hpsb_host *host, int nodeid, int destid, quadlet_t *data,
- u64 addr, unsigned int length)
+ u64 addr, unsigned int length, u16 flags)
{
/*
@@ -1531,7 +1311,7 @@
* physical dma in hardware). Mostly just here for debugging...
*/
static int sbp2_handle_physdma_read(struct hpsb_host *host, int nodeid, quadlet_t *data,
- u64 addr, unsigned int length)
+ u64 addr, unsigned int length, u16 flags)
{
/*
@@ -1559,11 +1339,109 @@
}
/*
+ * This function queries the device for the maximum concurrent logins it
+ * supports.
+ */
+static int sbp2_query_logins(struct scsi_id_instance_data *scsi_id)
+{
+ struct sbp2scsi_host_info *hi = scsi_id->hi;
+ quadlet_t data[2];
+ int max_logins;
+ int active_logins;
+
+ SBP2_DEBUG("sbp2_query_logins");
+
+ scsi_id->query_logins_orb->reserved1 = 0x0;
+ scsi_id->query_logins_orb->reserved2 = 0x0;
+
+ scsi_id->query_logins_orb->query_response_lo = scsi_id->query_logins_response_dma;
+ scsi_id->query_logins_orb->query_response_hi = ORB_SET_NODE_ID(hi->host->node_id);
+ SBP2_DEBUG("sbp2_query_logins: query_response_hi/lo initialized");
+
+ scsi_id->query_logins_orb->lun_misc = ORB_SET_FUNCTION(QUERY_LOGINS_REQUEST);
+ scsi_id->query_logins_orb->lun_misc |= ORB_SET_NOTIFY(1);
+ if (scsi_id->sbp2_device_type_and_lun != SBP2_DEVICE_TYPE_LUN_UNINITIALIZED) {
+ scsi_id->query_logins_orb->lun_misc |= ORB_SET_LUN(scsi_id->sbp2_device_type_and_lun);
+ }
+ SBP2_DEBUG("sbp2_query_logins: lun_misc initialized");
+
+ scsi_id->query_logins_orb->reserved_resp_length =
+ ORB_SET_QUERY_LOGINS_RESP_LENGTH(sizeof(struct sbp2_query_logins_response));
+ SBP2_DEBUG("sbp2_query_logins: reserved_resp_length initialized");
+
+ scsi_id->query_logins_orb->status_FIFO_lo = SBP2_STATUS_FIFO_ADDRESS_LO +
+ SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(scsi_id->id);
+ scsi_id->query_logins_orb->status_FIFO_hi = (ORB_SET_NODE_ID(hi->host->node_id) |
+ SBP2_STATUS_FIFO_ADDRESS_HI);
+ SBP2_DEBUG("sbp2_query_logins: status FIFO initialized");
+
+ sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_orb, sizeof(struct sbp2_query_logins_orb));
+
+ SBP2_DEBUG("sbp2_query_logins: orb byte-swapped");
+
+ sbp2util_packet_dump(scsi_id->query_logins_orb, sizeof(stuct sbp2_query_logins_orb),
+ "sbp2 query logins orb", scsi_id->query_logins_orb_dma);
+
+ memset(scsi_id->query_logins_response, 0, sizeof(struct sbp2_query_logins_response));
+ memset(&scsi_id->status_block, 0, sizeof(struct sbp2_status_block));
+
+ SBP2_DEBUG("sbp2_query_logins: query_logins_response/status FIFO memset");
+
+ data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+ data[1] = scsi_id->query_logins_orb_dma;
+ sbp2util_cpu_to_be32_buffer(data, 8);
+
+ atomic_set(&scsi_id->sbp2_login_complete, 0);
+
+ SBP2_DEBUG("sbp2_query_logins: prepared to write");
+ hpsb_node_write(scsi_id->ne, scsi_id->sbp2_management_agent_addr, data, 8);
+ SBP2_DEBUG("sbp2_query_logins: written");
+
+ if (sbp2util_down_timeout(&scsi_id->sbp2_login_complete, 2*HZ)) {
+ SBP2_ERR("Error querying logins to SBP-2 device - timed out");
+ return(-EIO);
+ }
+
+ if (scsi_id->status_block.ORB_offset_lo != scsi_id->query_logins_orb_dma) {
+ SBP2_ERR("Error querying logins to SBP-2 device - timed out");
+ return(-EIO);
+ }
+
+ if (STATUS_GET_RESP(scsi_id->status_block.ORB_offset_hi_misc) ||
+ STATUS_GET_DEAD_BIT(scsi_id->status_block.ORB_offset_hi_misc) ||
+ STATUS_GET_SBP_STATUS(scsi_id->status_block.ORB_offset_hi_misc)) {
+
+ SBP2_ERR("Error querying logins to SBP-2 device - timed out");
+ return(-EIO);
+ }
+
+ sbp2util_cpu_to_be32_buffer(scsi_id->query_logins_response, sizeof(struct sbp2_query_logins_response));
+
+ SBP2_DEBUG("length_max_logins = %x",
+ (unsigned int)scsi_id->query_logins_response->length_max_logins);
+
+ SBP2_INFO("Query logins to SBP-2 device successful");
+
+ max_logins = RESPONSE_GET_MAX_LOGINS(scsi_id->query_logins_response->length_max_logins);
+ SBP2_INFO("Maximum concurrent logins supported: %d", max_logins);
+
+ active_logins = RESPONSE_GET_ACTIVE_LOGINS(scsi_id->query_logins_response->length_max_logins);
+ SBP2_INFO("Number of active logins: %d", active_logins);
+
+ if (active_logins >= max_logins) {
+ return(-EIO);
+ }
+
+ return 0;
+}
+
+/*
* 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");
@@ -1573,6 +1451,13 @@
return(-EIO);
}
+ if (!sbp2_exclusive_login) {
+ if (sbp2_query_logins(scsi_id)) {
+ SBP2_ERR("Device does not support any more concurrent logins");
+ return(-EIO);
+ }
+ }
+
/* Set-up login ORB, assume no password */
scsi_id->login_orb->password_hi = 0;
scsi_id->login_orb->password_lo = 0;
@@ -1689,8 +1574,9 @@
* This function is called in order to logout from a particular SBP-2
* device, usually called during driver unload.
*/
-static int sbp2_logout_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
+static int sbp2_logout_device(struct scsi_id_instance_data *scsi_id)
{
+ struct sbp2scsi_host_info *hi = scsi_id->hi;
quadlet_t data[2];
SBP2_DEBUG("sbp2_logout_device");
@@ -1747,8 +1633,9 @@
* This function is called in order to reconnect to a particular SBP-2
* device, after a bus reset.
*/
-static int sbp2_reconnect_device(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
+static int sbp2_reconnect_device(struct scsi_id_instance_data *scsi_id)
{
+ struct sbp2scsi_host_info *hi = scsi_id->hi;
quadlet_t data[2];
SBP2_DEBUG("sbp2_reconnect_device");
@@ -1835,8 +1722,8 @@
* This function is called in order to set the busy timeout (number of
* retries to attempt) on the sbp2 device.
*/
-static int sbp2_set_busy_timeout(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id)
-{
+static int sbp2_set_busy_timeout(struct scsi_id_instance_data *scsi_id)
+{
quadlet_t data;
SBP2_DEBUG("sbp2_set_busy_timeout");
@@ -1876,7 +1763,7 @@
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 */
@@ -1988,13 +1875,15 @@
* 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 */
- scsi_id->speed_code = hi->host->speed_map[(hi->host->node_id & NODE_MASK) * 64
- + (scsi_id->ne->nodeid & NODE_MASK)];
+ scsi_id->speed_code = hi->host->speed_map[NODEID_TO_NODE(hi->host->node_id) * 64
+ + NODEID_TO_NODE(scsi_id->ne->nodeid)];
/* Bump down our speed if the user requested it */
if (scsi_id->speed_code > sbp2_max_speed) {
@@ -2005,7 +1894,7 @@
/* Payload size is the lesser of what our speed supports and what
* our host supports. */
- scsi_id->max_payload_size = min(sbp2_speedto_maxrec[scsi_id->speed_code],
+ scsi_id->max_payload_size = min(hpsb_speedto_maxrec[scsi_id->speed_code],
(u8)(((be32_to_cpu(hi->host->csr.rom[2]) >> 12) & 0xf) - 1));
SBP2_ERR("Node[" NODE_BUS_FMT "]: Max speed [%s] - Max payload [%u]",
@@ -2018,35 +1907,37 @@
/*
* 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, u32 flags)
+static int sbp2_agent_reset(struct scsi_id_instance_data *scsi_id, int wait)
{
- struct sbp2_request_packet *agent_reset_request_packet;
-
+ struct sbp2scsi_host_info *hi = scsi_id->hi;
+ struct hpsb_packet *packet;
+ quadlet_t data;
+
SBP2_DEBUG("sbp2_agent_reset");
/*
* Ok, let's write to the target's management agent register
*/
- agent_reset_request_packet =
- sbp2util_allocate_write_request_packet(hi, scsi_id->ne,
- scsi_id->sbp2_command_block_agent_addr +
- SBP2_AGENT_RESET_OFFSET,
- 0, ntohl(SBP2_AGENT_RESET_DATA));
+ data = ntohl(SBP2_AGENT_RESET_DATA);
+ packet = sbp2util_allocate_write_packet(hi, scsi_id->ne,
+ scsi_id->sbp2_command_block_agent_addr +
+ SBP2_AGENT_RESET_OFFSET,
+ 4, &data);
- if (!agent_reset_request_packet) {
- SBP2_ERR("sbp2util_allocate_write_request_packet failed");
- return(-EIO);
+ if (!packet) {
+ SBP2_ERR("sbp2util_allocate_write_packet failed");
+ return(-ENOMEM);
}
- if (!hpsb_send_packet(agent_reset_request_packet->packet)) {
+ if (!hpsb_send_packet(packet)) {
SBP2_ERR("hpsb_send_packet failed");
- sbp2util_free_request_packet(agent_reset_request_packet);
+ sbp2_free_packet(packet);
return(-EIO);
}
- if (!(flags & SBP2_SEND_NO_WAIT)) {
- down(&agent_reset_request_packet->packet->state_change);
- down(&agent_reset_request_packet->packet->state_change);
+ if (wait) {
+ down(&packet->state_change);
+ down(&packet->state_change);
}
/*
@@ -2055,15 +1946,13 @@
scsi_id->last_orb = NULL;
return(0);
-
}
/*
* 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,
@@ -2071,6 +1960,7 @@
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 =
@@ -2146,17 +2036,11 @@
command->dma_dir = dma_dir;
command->dma_size = sgpnt[0].length;
command->dma_type = CMD_DMA_PAGE;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,13)
- command->cmd_dma = pci_map_single (hi->host->pdev, sgpnt[0].address,
- command->dma_size,
- command->dma_dir);
-#else
command->cmd_dma = pci_map_page(hi->host->pdev,
sgpnt[0].page,
sgpnt[0].offset,
command->dma_size,
command->dma_dir);
-#endif /* Linux version < 2.4.13 */
SBP2_DMA_ALLOC("single page scatter element");
command_orb->data_descriptor_hi = ORB_SET_NODE_ID(hi->host->node_id);
@@ -2319,10 +2203,11 @@
/*
* This function is called in order to begin a regular SBP-2 command.
*/
-static int sbp2_link_orb_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id,
+static int sbp2_link_orb_command(struct scsi_id_instance_data *scsi_id,
struct sbp2_command_info *command)
{
- struct sbp2_request_packet *command_request_packet;
+ struct sbp2scsi_host_info *hi = scsi_id->hi;
+ struct hpsb_packet *packet;
struct sbp2_command_orb *command_orb = &command->command_orb;
outstanding_orb_incr;
@@ -2345,25 +2230,24 @@
*/
if (hpsb_node_entry_valid(scsi_id->ne)) {
- command_request_packet =
- sbp2util_allocate_write_request_packet(hi, scsi_id->ne,
+ packet = sbp2util_allocate_write_packet(hi, scsi_id->ne,
scsi_id->sbp2_command_block_agent_addr +
- SBP2_ORB_POINTER_OFFSET, 8, 0);
+ SBP2_ORB_POINTER_OFFSET, 8, NULL);
- if (!command_request_packet) {
- SBP2_ERR("sbp2util_allocate_write_request_packet failed");
- return(-EIO);
+ if (!packet) {
+ SBP2_ERR("sbp2util_allocate_write_packet failed");
+ return(-ENOMEM);
}
- command_request_packet->packet->data[0] = ORB_SET_NODE_ID(hi->host->node_id);
- command_request_packet->packet->data[1] = command->command_orb_dma;
- sbp2util_cpu_to_be32_buffer(command_request_packet->packet->data, 8);
+ packet->data[0] = ORB_SET_NODE_ID(hi->host->node_id);
+ packet->data[1] = command->command_orb_dma;
+ sbp2util_cpu_to_be32_buffer(packet->data, 8);
SBP2_ORB_DEBUG("write command agent, command orb %p", command_orb);
- if (!hpsb_send_packet(command_request_packet->packet)) {
+ if (!hpsb_send_packet(packet)) {
SBP2_ERR("hpsb_send_packet failed");
- sbp2util_free_request_packet(command_request_packet);
+ sbp2_free_packet(packet);
return(-EIO);
}
@@ -2394,22 +2278,22 @@
* Ring the doorbell
*/
if (hpsb_node_entry_valid(scsi_id->ne)) {
+ quadlet_t data = cpu_to_be32(command->command_orb_dma);
- command_request_packet = sbp2util_allocate_write_request_packet(hi,
- scsi_id->ne,
- scsi_id->sbp2_command_block_agent_addr + SBP2_DOORBELL_OFFSET,
- 0, cpu_to_be32(command->command_orb_dma));
+ packet = sbp2util_allocate_write_packet(hi, scsi_id->ne,
+ scsi_id->sbp2_command_block_agent_addr +
+ SBP2_DOORBELL_OFFSET, 4, &data);
- if (!command_request_packet) {
- SBP2_ERR("sbp2util_allocate_write_request_packet failed");
- return(-EIO);
+ if (!packet) {
+ SBP2_ERR("sbp2util_allocate_write_packet failed");
+ return(-ENOMEM);
}
SBP2_ORB_DEBUG("ring doorbell, command orb %p", command_orb);
- if (!hpsb_send_packet(command_request_packet->packet)) {
+ if (!hpsb_send_packet(packet)) {
SBP2_ERR("hpsb_send_packet failed");
- sbp2util_free_request_packet(command_request_packet);
+ sbp2_free_packet(packet);
return(-EIO);
}
}
@@ -2424,7 +2308,7 @@
/*
* 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;
@@ -2442,7 +2326,7 @@
/*
* 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);
}
@@ -2462,7 +2346,7 @@
/*
* 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);
/*
@@ -2482,7 +2366,7 @@
/*
* 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);
}
@@ -2702,7 +2586,7 @@
* This function deals with status writes from the SBP-2 device
*/
static int sbp2_handle_status_write(struct hpsb_host *host, int nodeid, int destid,
- quadlet_t *data, u64 addr, unsigned int length)
+ quadlet_t *data, u64 addr, unsigned int length, u16 fl)
{
struct sbp2scsi_host_info *hi = NULL;
struct scsi_id_instance_data *scsi_id = NULL;
@@ -2721,16 +2605,14 @@
return(RCODE_ADDRESS_ERROR);
}
- sbp2_spin_lock(&sbp2_host_info_lock, flags);
- hi = sbp2_find_host_info(host);
- sbp2_spin_unlock(&sbp2_host_info_lock, flags);
+ hi = hpsb_get_hostinfo(&sbp2_highlevel, host);
if (!hi) {
SBP2_ERR("host info is NULL - this is bad!");
return(RCODE_ADDRESS_ERROR);
}
- sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+ spin_lock_irqsave(&hi->sbp2_command_lock, flags);
/*
* Find our scsi_id structure by looking at the status fifo address written to by
@@ -2741,7 +2623,7 @@
if (!scsi_id) {
SBP2_ERR("scsi_id is NULL - device is gone?");
- sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+ spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
return(RCODE_ADDRESS_ERROR);
}
@@ -2801,17 +2683,10 @@
* Initiate a fetch agent reset.
*/
SBP2_DEBUG("Dead bit set - initiating fetch agent reset");
- sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
+ sbp2_agent_reset(scsi_id, 0);
}
SBP2_ORB_DEBUG("completing command orb %p", &command->command_orb);
-
- /*
- * Complete the SCSI command
- */
- SBP2_DEBUG("Completing SCSI command");
- sbp2scsi_complete_command(hi, scsi_id, scsi_status, SCpnt, command->Current_done);
- SBP2_ORB_DEBUG("command orb completed");
}
/*
@@ -2829,13 +2704,31 @@
* It's probably a login/logout/reconnect status.
*/
if ((scsi_id->login_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
+ (scsi_id->query_logins_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
(scsi_id->reconnect_orb_dma == scsi_id->status_block.ORB_offset_lo) ||
(scsi_id->logout_orb_dma == scsi_id->status_block.ORB_offset_lo)) {
atomic_set(&scsi_id->sbp2_login_complete, 1);
}
}
- sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+ spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
+
+
+ if (SCpnt) {
+
+ /*
+ * Complete the SCSI command.
+ *
+ * Only do it after we've released the sbp2_command_lock,
+ * as it might otherwise deadlock with the
+ * io_request_lock (in sbp2scsi_queuecommand).
+ */
+ SBP2_DEBUG("Completing SCSI command");
+ sbp2scsi_complete_command(scsi_id, scsi_status, SCpnt,
+ command->Current_done);
+ SBP2_ORB_DEBUG("command orb completed");
+ }
+
return(RCODE_COMPLETE);
}
@@ -2859,7 +2752,7 @@
/*
* Pull our host info and scsi id instance data from the scsi command
*/
- hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
+ hi = hpsb_get_hostinfo_bykey(&sbp2_highlevel, (unsigned long)SCpnt->device->host->hostt);
if (!hi) {
SBP2_ERR("sbp2scsi_host_info is NULL - this is bad!");
@@ -2898,7 +2791,7 @@
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);
}
@@ -2915,12 +2808,13 @@
/*
* Try and send our SCSI command
*/
- sbp2_spin_lock(&hi->sbp2_command_lock, flags);
- if (sbp2_send_command(hi, scsi_id, SCpnt, done)) {
+ spin_lock_irqsave(&hi->sbp2_command_lock, flags);
+ 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);
}
- sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+ spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
return(0);
}
@@ -2929,10 +2823,10 @@
* 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;
@@ -2961,10 +2855,15 @@
/*
* This function is called in order to complete a regular SBP-2 command.
+ *
+ * This can be called in interrupt context.
*/
-static void sbp2scsi_complete_command(struct sbp2scsi_host_info *hi, struct scsi_id_instance_data *scsi_id, u32 scsi_status,
- Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+static void sbp2scsi_complete_command(struct scsi_id_instance_data *scsi_id,
+ u32 scsi_status, Scsi_Cmnd *SCpnt,
+ void (*done)(Scsi_Cmnd *))
{
+ unsigned long flags;
+
SBP2_DEBUG("sbp2scsi_complete_command");
/*
@@ -3063,15 +2962,9 @@
/*
* Tell scsi stack that we're done with this command
*/
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- spin_lock_irq(&io_request_lock);
- done (SCpnt);
- spin_unlock_irq(&io_request_lock);
-#else
- spin_lock_irq(hi->scsi_host->host_lock);
+ spin_lock_irqsave(&io_request_lock, flags);
done (SCpnt);
- spin_unlock_irq(hi->scsi_host->host_lock);
-#endif
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
@@ -3082,7 +2975,8 @@
*/
static int sbp2scsi_abort (Scsi_Cmnd *SCpnt)
{
- struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
+ struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(&sbp2_highlevel,
+ (unsigned long)SCpnt->device->host->hostt);
struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->target];
struct sbp2_command_info *command;
unsigned long flags;
@@ -3096,7 +2990,7 @@
* Right now, just return any matching command structures
* to the free pool.
*/
- sbp2_spin_lock(&hi->sbp2_command_lock, flags);
+ spin_lock_irqsave(&hi->sbp2_command_lock, flags);
command = sbp2util_find_command_for_SCpnt(scsi_id, SCpnt);
if (command) {
SBP2_DEBUG("Found command to abort");
@@ -3119,9 +3013,9 @@
/*
* Initiate a fetch agent reset.
*/
- sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
- sbp2scsi_complete_all_commands(hi, scsi_id, DID_BUS_BUSY);
- sbp2_spin_unlock(&hi->sbp2_command_lock, flags);
+ sbp2_agent_reset(scsi_id, 0);
+ sbp2scsi_complete_all_commands(scsi_id, DID_BUS_BUSY);
+ spin_unlock_irqrestore(&hi->sbp2_command_lock, flags);
}
return(SUCCESS);
@@ -3132,105 +3026,94 @@
*/
static int sbp2scsi_reset (Scsi_Cmnd *SCpnt)
{
- struct sbp2scsi_host_info *hi = (struct sbp2scsi_host_info *) SCpnt->host->hostdata[0];
- struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->target];
+ struct sbp2scsi_host_info *hi = hpsb_get_hostinfo_bykey(&sbp2_highlevel,
+ (unsigned long)SCpnt->device->host->hostt);
+ struct scsi_id_instance_data *scsi_id = hi->scsi_id[SCpnt->device->id];
SBP2_ERR("reset requested");
if (scsi_id) {
SBP2_ERR("Generating sbp2 fetch agent reset");
- sbp2_agent_reset(hi, scsi_id, SBP2_SEND_NO_WAIT);
+ sbp2_agent_reset(scsi_id, 0);
}
return(SUCCESS);
}
-/*
- * Called by scsi stack to get bios parameters (used by fdisk, and at boot).
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,28)
-static int sbp2scsi_biosparam (Scsi_Disk *disk, kdev_t dev, int geom[])
-#else
-static int sbp2scsi_biosparam (Scsi_Disk *disk, struct block_device *dev, int geom[])
-#endif
+static const char *sbp2scsi_info (struct Scsi_Host *host)
{
- int heads, sectors, cylinders;
+ return "SCSI emulation for IEEE-1394 SBP-2 Devices";
+}
- SBP2_DEBUG("Request for bios parameters");
+/* Called for contents of procfs */
+#define SPRINTF(args...) \
+ do { if (pos < buffer+length) pos += sprintf(pos, ## args); } while (0)
- heads = 64;
- sectors = 32;
- cylinders = disk->capacity / (heads * sectors);
+static int sbp2scsi_proc_info(char *buffer, char **start, off_t offset,
+ int length, int hostno, int inout)
+{
+ Scsi_Device *scd;
+ struct Scsi_Host *host;
+ struct sbp2scsi_host_info *hi;
+ char *pos = buffer;
- if (cylinders > 1024) {
- heads = 255;
- sectors = 63;
- cylinders = disk->capacity / (heads * sectors);
- }
+ /* if someone is sending us data, just throw it away */
+ if (inout)
+ return length;
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
+ for (host = scsi_hostlist; host; host = host->next)
+ if (host->host_no == hostno)
+ break;
- return(0);
-}
+ if (!host) /* if we couldn't find it, we return an error */
+ return -ESRCH;
-/*
- * Called by scsi stack after scsi driver is registered
- */
-static int sbp2scsi_detect (Scsi_Host_Template *tpnt)
-{
- SBP2_DEBUG("sbp2scsi_detect");
+ hi = hpsb_get_hostinfo_bykey(&sbp2_highlevel, (unsigned long)host->hostt);
+ if (!hi) /* shouldn't happen, but... */
+ return -ESRCH;
- /*
- * Call sbp2_init to register with the ieee1394 stack. This
- * results in a callback to sbp2_add_host for each ieee1394
- * host controller currently registered, and for each of those
- * we register a scsi host with the scsi stack.
- */
-
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- spin_unlock_irq(&io_request_lock);
- sbp2_init();
- spin_lock_irq(&io_request_lock);
-#else
- sbp2_init();
-#endif
+ SPRINTF("Host scsi%d : SBP-2 IEEE-1394 (%s)\n", hostno,
+ hi->host->driver->name);
+ SPRINTF("Driver version : %s\n", version);
- /* We return the number of hosts registered. */
- return scsi_driver_template.present;
-}
+ SPRINTF("\nModule options :\n");
+ SPRINTF(" max_speed : %s\n", hpsb_speedto_str[sbp2_max_speed]);
+ SPRINTF(" max_sectors : %d\n", sbp2_max_sectors);
+ SPRINTF(" serialize_io : %s\n", sbp2_serialize_io ? "yes" : "no");
+ SPRINTF(" exclusive_login : %s\n", sbp2_exclusive_login ? "yes" : "no");
+ SPRINTF("\nAttached devices : %s\n", host->host_queue ? "" : "none");
-/*
- * Called for contents of procfs
- */
-static const char *sbp2scsi_info (struct Scsi_Host *host)
-{
- struct sbp2scsi_host_info *hi = sbp2_find_host_info_scsi(host);
- static char info[1024];
+ for (scd = host->host_queue; scd; scd = scd->next) {
+ int i;
- if (!hi) /* shouldn't happen, but... */
- return "IEEE-1394 SBP-2 protocol driver";
+ SPRINTF(" [Channel: %02d, Id: %02d, Lun: %02d] ", scd->channel,
+ scd->id, scd->lun);
+ SPRINTF("%s ", (scd->type < MAX_SCSI_DEVICE_CODE) ?
+ scsi_device_types[(short) scd->type] : "Unknown device");
+
+ for (i = 0; (i < 8) && (scd->vendor[i] >= 0x20); i++)
+ SPRINTF("%c", scd->vendor[i]);
+
+ SPRINTF(" ");
- sprintf(info, "IEEE-1394 SBP-2 protocol driver (host: %s)\n%s\n"
- "SBP-2 module load options:\n"
- "- Max speed supported: %s\n"
- "- Max sectors per I/O supported: %d\n"
- "- Max outstanding commands supported: %d\n"
- "- Max outstanding commands per lun supported: %d\n"
- "- Serialized I/O (debug): %s\n"
- "- Exclusive login: %s",
- hi->host->driver->name,
- version,
- hpsb_speedto_str[sbp2_max_speed],
- sbp2_max_sectors,
- sbp2_max_outstanding_cmds,
- sbp2_max_cmds_per_lun,
- sbp2_serialize_io ? "yes" : "no",
- sbp2_exclusive_login ? "yes" : "no");
+ for (i = 0; (i < 16) && (scd->model[i] >= 0x20); i++)
+ SPRINTF("%c", scd->model[i]);
- return info;
+ SPRINTF("\n");
+ }
+
+ SPRINTF("\n");
+
+ /* Calculate start of next buffer, and return value. */
+ *start = buffer + offset;
+
+ if ((pos - buffer) < offset)
+ return (0);
+ else if ((pos - buffer - offset) < length)
+ return (pos - buffer - offset);
+ else
+ return (length);
}
@@ -3241,62 +3124,57 @@
/* SCSI host template */
static Scsi_Host_Template scsi_driver_template = {
- .name = "IEEE-1394 SBP-2 protocol driver",
- .info = sbp2scsi_info,
- .detect = sbp2scsi_detect,
- .queuecommand = sbp2scsi_queuecommand,
- .eh_abort_handler = sbp2scsi_abort,
- .eh_device_reset_handler =sbp2scsi_reset,
- .eh_bus_reset_handler = sbp2scsi_reset,
- .eh_host_reset_handler =sbp2scsi_reset,
- .bios_param = sbp2scsi_biosparam,
- .this_id = -1,
- .sg_tablesize = SBP2_MAX_SG_ELEMENTS,
- .use_clustering = SBP2_CLUSTERING,
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
- .use_new_eh_code = TRUE,
-#endif
- .emulated = 1,
- .proc_name = SBP2_DEVICE_NAME,
+ .module = THIS_MODULE,
+ .name = "SBP-2 IEEE-1394",
+ .proc_name = NULL, // Filled in per-host
+ .info = sbp2scsi_info,
+ .proc_info = sbp2scsi_proc_info,
+ .detect = sbp2scsi_detect,
+ .queuecommand = sbp2scsi_queuecommand,
+ .eh_abort_handler = sbp2scsi_abort,
+ .eh_device_reset_handler = sbp2scsi_reset,
+ .eh_bus_reset_handler = sbp2scsi_reset,
+ .eh_host_reset_handler = sbp2scsi_reset,
+ .use_new_eh_code = 1,
+ .this_id = -1,
+ .sg_tablesize = SG_ALL,
+ .use_clustering = ENABLE_CLUSTERING,
+ .cmd_per_lun = SBP2_MAX_CMDS_PER_LUN,
+ .can_queue = SBP2_MAX_SCSI_QUEUE,
+ .emulated = 1,
+ .highmem_io = 1,
};
static int sbp2_module_init(void)
{
SBP2_DEBUG("sbp2_module_init");
- /*
- * Module load debug option to force one command at a time (serializing I/O)
- */
+ /* Module load debug option to force one command at a time (serializing I/O) */
if (sbp2_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;
- } else {
- scsi_driver_template.can_queue = sbp2_max_outstanding_cmds;
- scsi_driver_template.cmd_per_lun = sbp2_max_cmds_per_lun;
}
- /*
- * Set max sectors (module load option). Default is 255 sectors.
- */
+ /* Set max sectors (module load option). Default is 255 sectors. */
scsi_driver_template.max_sectors = sbp2_max_sectors;
- /*
- * Ideally we would register our scsi_driver_template with the
- * scsi stack and after that register with the ieee1394 stack
- * and process the add_host callbacks. However, the detect
- * function in the scsi host template requires that we find at
- * least one host, so we "nest" the registrations by calling
- * sbp2_init from the detect function.
- */
- scsi_driver_template.module = THIS_MODULE;
- if (SCSI_REGISTER_HOST(&scsi_driver_template) ||
- !scsi_driver_template.present) {
- SBP2_ERR("Please load the lower level IEEE-1394 driver "
- "(e.g. ohci1394) before sbp2...");
- sbp2_cleanup();
- return -ENODEV;
- }
+
+ /* Register our high level driver with 1394 stack */
+ hpsb_register_highlevel(&sbp2_highlevel);
+
+ /* Register our sbp2 status address space... */
+ hpsb_register_addrspace(&sbp2_highlevel, &sbp2_ops, SBP2_STATUS_FIFO_ADDRESS,
+ SBP2_STATUS_FIFO_ADDRESS +
+ SBP2_STATUS_FIFO_ENTRY_TO_OFFSET(SBP2SCSI_MAX_SCSI_IDS+1));
+
+ /* Handle data movement if physical dma is not enabled/supported
+ * on host controller */
+#ifdef CONFIG_IEEE1394_SBP2_PHYS_DMA
+ hpsb_register_addrspace(&sbp2_highlevel, &sbp2_physdma_ops, 0x0ULL, 0xfffffffcULL);
+#endif
+
+ hpsb_register_protocol(&sbp2_driver);
return 0;
}
@@ -3305,17 +3183,9 @@
{
SBP2_DEBUG("sbp2_module_exit");
- /*
- * On module unload we unregister with the ieee1394 stack
- * which results in remove_host callbacks for all ieee1394
- * host controllers. In the callbacks we unregister the
- * corresponding scsi hosts.
- */
- sbp2_cleanup();
-
- if (SCSI_UNREGISTER_HOST(&scsi_driver_template))
- SBP2_ERR("sbp2_module_exit: couldn't unregister scsi driver");
+ hpsb_unregister_protocol(&sbp2_driver);
+ hpsb_unregister_highlevel(&sbp2_highlevel);
}
module_init(sbp2_module_init);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)