From 1f61d82490a26dbcde903b33e24f6d11b758b64c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Mar 2006 11:03:43 -0500 Subject: [SCSI] Change Kconfig option from IOMAPPED to MMIO Most of the Kconfig options for switching between IO Port and MMIO operations use the opposite sense from sym2. Really, this option should be set at a chipset level rather than per-driver. Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 1fffd2b3c65..ec9d93aa160 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1874,7 +1874,7 @@ sym_init_device(struct pci_dev *pdev, struct sym_device *device) i = pci_get_base_address(pdev, 1, &device->mmio_base); pci_get_base_address(pdev, i, &device->ram_base); -#ifndef CONFIG_SCSI_SYM53C8XX_IOMAPPED +#ifdef CONFIG_SCSI_SYM53C8XX_MMIO if (device->mmio_base) device->s.ioaddr = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); -- cgit v1.2.3-70-g09d2 From b6d105d7ee188040a6e5eb86101e7476d94b3076 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Mar 2006 11:03:44 -0500 Subject: [SCSI] Use pcibios_resource_to_bus() We had our own code (pci_get_base_address()) to get the bus address of a BAR. We can get this using pcibios_resource_to_bus() instead. Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 55 +++++++++---------------------------- 1 file changed, 13 insertions(+), 42 deletions(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index ec9d93aa160..e6ff89a8524 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -134,45 +134,6 @@ static void sym2_setup_params(void) } } -/* - * We used to try to deal with 64-bit BARs here, but don't any more. - * There are many parts of this driver which would need to be modified - * to handle a 64-bit base address, including scripts. I'm uncomfortable - * with making those changes when I have no way of testing it, so I'm - * just going to disable it. - * - * Note that some machines (eg HP rx8620 and Superdome) have bus addresses - * below 4GB and physical addresses above 4GB. These will continue to work. - */ -static int __devinit -pci_get_base_address(struct pci_dev *pdev, int index, unsigned long *basep) -{ - u32 tmp; - unsigned long base; -#define PCI_BAR_OFFSET(index) (PCI_BASE_ADDRESS_0 + (index<<2)) - - pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp); - base = tmp; - if ((tmp & 0x7) == PCI_BASE_ADDRESS_MEM_TYPE_64) { - pci_read_config_dword(pdev, PCI_BAR_OFFSET(index++), &tmp); - if (tmp > 0) { - dev_err(&pdev->dev, - "BAR %d is 64-bit, disabling\n", index - 1); - base = 0; - } - } - - if ((base & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO) { - base &= PCI_BASE_ADDRESS_IO_MASK; - } else { - base &= PCI_BASE_ADDRESS_MEM_MASK; - } - - *basep = base; - return index; -#undef PCI_BAR_OFFSET -} - static struct scsi_transport_template *sym2_transport_template = NULL; /* @@ -1866,13 +1827,23 @@ static int __devinit sym_set_workarounds(struct sym_device *device) static void __devinit sym_init_device(struct pci_dev *pdev, struct sym_device *device) { - int i; + int i = 2; + struct pci_bus_region bus_addr; device->host_id = SYM_SETUP_HOST_ID; device->pdev = pdev; - i = pci_get_base_address(pdev, 1, &device->mmio_base); - pci_get_base_address(pdev, i, &device->ram_base); + pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[1]); + device->mmio_base = bus_addr.start; + + /* + * If the BAR is 64-bit, resource 2 will be occupied by the + * upper 32 bits + */ + if (!pdev->resource[i].flags) + i++; + pcibios_resource_to_bus(pdev, &bus_addr, &pdev->resource[i]); + device->ram_base = bus_addr.start; #ifdef CONFIG_SCSI_SYM53C8XX_MMIO if (device->mmio_base) -- cgit v1.2.3-70-g09d2 From ab19d52bec6c1b266228417b58ae6f36f3ea097c Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Mar 2006 11:03:44 -0500 Subject: [SCSI] Simplify error handling a bit - to_do was never set to SYM_EH_DO_COMPLETE, so remove that code - move the spinlocks inside the common error handler code path Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 50 ++++++------------------------------- 1 file changed, 8 insertions(+), 42 deletions(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index e6ff89a8524..052ce11806a 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -712,7 +712,6 @@ static void sym53c8xx_timer(unsigned long npref) * What we will do regarding the involved SCSI command. */ #define SYM_EH_DO_IGNORE 0 -#define SYM_EH_DO_COMPLETE 1 #define SYM_EH_DO_WAIT 2 /* @@ -764,25 +763,18 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); + spin_lock_irq(cmd->device->host->host_lock); /* This one is queued in some place -> to wait for completion */ FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); if (cp->cmd == cmd) { to_do = SYM_EH_DO_WAIT; - goto prepare; + break; } } -prepare: - /* Prepare stuff to either ignore, complete or wait for completion */ - switch(to_do) { - default: - case SYM_EH_DO_IGNORE: - break; - case SYM_EH_DO_WAIT: + if (to_do == SYM_EH_DO_WAIT) { init_completion(&ep->done); - /* fall through */ - case SYM_EH_DO_COMPLETE: ep->old_done = cmd->scsi_done; cmd->scsi_done = sym_eh_done; SYM_UCMD_PTR(cmd)->eh_wait = ep; @@ -818,9 +810,6 @@ prepare: } ep->to_do = to_do; - /* Complete the command with locks held as required by the driver */ - if (to_do == SYM_EH_DO_COMPLETE) - sym_xpt_done2(np, cmd, DID_ABORT); /* Wait for completion with locks released, as required by kernel */ if (to_do == SYM_EH_DO_WAIT) { @@ -836,6 +825,7 @@ prepare: if (ep->timed_out) sts = -2; } + spin_unlock_irq(cmd->device->host->host_lock); dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); return sts ? SCSI_FAILED : SCSI_SUCCESS; @@ -847,46 +837,22 @@ prepare: */ static int sym53c8xx_eh_abort_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_ABORT, "ABORT", cmd); } static int sym53c8xx_eh_device_reset_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_DEVICE_RESET, "DEVICE RESET", cmd); } static int sym53c8xx_eh_bus_reset_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_BUS_RESET, "BUS RESET", cmd); } static int sym53c8xx_eh_host_reset_handler(struct scsi_cmnd *cmd) { - int rc; - - spin_lock_irq(cmd->device->host->host_lock); - rc = sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); - spin_unlock_irq(cmd->device->host->host_lock); - - return rc; + return sym_eh_handler(SYM_EH_HOST_RESET, "HOST RESET", cmd); } /* -- cgit v1.2.3-70-g09d2 From 3bea15a76eecc03729bf74d6ab2a1f849c08423e Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Mar 2006 11:03:44 -0500 Subject: [SCSI] Disable sym2 driver queueing Undef SYM_OPT_HANDLE_DEVICE_QUEUEING. Call sym_put_start_queue instead of sym_start_next_ccbs. Turn asserts into checks that we can send the command to the adapter, and return busy from queuecommand if we can't. Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 9 ++------- drivers/scsi/sym53c8xx_2/sym_glue.h | 2 +- drivers/scsi/sym53c8xx_2/sym_hipd.c | 8 +++++--- drivers/scsi/sym53c8xx_2/sym_hipd.h | 2 ++ 4 files changed, 10 insertions(+), 11 deletions(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 052ce11806a..a27dd66b661 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -475,8 +475,6 @@ static inline int sym_setup_cdb(struct sym_hcb *np, struct scsi_cmnd *cmd, struc */ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp) { - struct sym_tcb *tp = &np->target[cp->target]; - struct sym_lcb *lp = sym_lp(tp, cp->lun); u32 lastp, goalp; int dir; @@ -557,7 +555,7 @@ int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct s /* * activate this job. */ - sym_start_next_ccbs(np, lp, 2); + sym_put_start_queue(np, cp); return 0; out_abort: @@ -871,15 +869,12 @@ static void sym_tune_dev_queuing(struct sym_tcb *tp, int lun, u_short reqtags) if (reqtags > lp->s.scdev_depth) reqtags = lp->s.scdev_depth; - lp->started_limit = reqtags ? reqtags : 2; - lp->started_max = 1; lp->s.reqtags = reqtags; if (reqtags != oldtags) { dev_info(&tp->starget->dev, "tagged command queuing %s, command queue depth %d.\n", - lp->s.reqtags ? "enabled" : "disabled", - lp->started_limit); + lp->s.reqtags ? "enabled" : "disabled", reqtags); } } diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.h b/drivers/scsi/sym53c8xx_2/sym_glue.h index cc92d0c70cd..a446cda3f64 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.h +++ b/drivers/scsi/sym53c8xx_2/sym_glue.h @@ -68,7 +68,7 @@ */ #define SYM_CONF_TIMER_INTERVAL ((HZ+1)/2) -#define SYM_OPT_HANDLE_DEVICE_QUEUEING +#undef SYM_OPT_HANDLE_DEVICE_QUEUEING #define SYM_OPT_LIMIT_COMMAND_REORDERING /* diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.c b/drivers/scsi/sym53c8xx_2/sym_hipd.c index b2ac482caae..a6cbb90e2bb 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.c +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.c @@ -1469,7 +1469,7 @@ static int sym_prepare_nego(struct sym_hcb *np, struct sym_ccb *cp, u_char *msgp /* * Insert a job into the start queue. */ -static void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) +void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp) { u_short qidx; @@ -4602,7 +4602,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t * Debugging purpose. */ #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(lp->busy_itl == 0); + if (lp->busy_itl != 0) + goto out_free; #endif /* * Allocate resources for tags if not yet. @@ -4647,7 +4648,8 @@ struct sym_ccb *sym_get_ccb (struct sym_hcb *np, struct scsi_cmnd *cmd, u_char t * Debugging purpose. */ #ifndef SYM_OPT_HANDLE_DEVICE_QUEUEING - assert(lp->busy_itl == 0 && lp->busy_itlq == 0); + if (lp->busy_itl != 0 || lp->busy_itlq != 0) + goto out_free; #endif /* * Count this nexus for this LUN. diff --git a/drivers/scsi/sym53c8xx_2/sym_hipd.h b/drivers/scsi/sym53c8xx_2/sym_hipd.h index 2456090bb24..79ab6a17703 100644 --- a/drivers/scsi/sym53c8xx_2/sym_hipd.h +++ b/drivers/scsi/sym53c8xx_2/sym_hipd.h @@ -1049,6 +1049,8 @@ int sym_reset_scsi_bus(struct sym_hcb *np, int enab_int); struct sym_chip *sym_lookup_chip_table(u_short device_id, u_char revision); #ifdef SYM_OPT_HANDLE_DEVICE_QUEUEING void sym_start_next_ccbs(struct sym_hcb *np, struct sym_lcb *lp, int maxn); +#else +void sym_put_start_queue(struct sym_hcb *np, struct sym_ccb *cp); #endif void sym_start_up(struct sym_hcb *np, int reason); void sym_interrupt(struct sym_hcb *np); -- cgit v1.2.3-70-g09d2 From b4e93a739ed1352664defd41d5e4f82afa29b928 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Mar 2006 11:03:44 -0500 Subject: [SCSI] Simplify error handling Use wait_for_completion_timeout() instead of using a timer (as Christoph Hellwig did for aic7xxx). That lets me eliminate the sym_eh_wait structure; the struct completion, the old_done pointer and the to_do flag can be folded into the sym_ucmd (which overrides the scsi_pointer in scsi_cmnd). The sym_eh_done() function becomes much simpler as the timeout handling is done in sym_eh_handler() directly. The host_lock can be unlocked earlier, and I cache the host in a local variable to make accesses to it quicker. Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 84 ++++++++++--------------------------- 1 file changed, 22 insertions(+), 62 deletions(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index a27dd66b661..e48409e26e5 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -136,25 +136,15 @@ static void sym2_setup_params(void) static struct scsi_transport_template *sym2_transport_template = NULL; -/* - * Used by the eh thread to wait for command completion. - * It is allocated on the eh thread stack. - */ -struct sym_eh_wait { - struct completion done; - struct timer_list timer; - void (*old_done)(struct scsi_cmnd *); - int to_do; - int timed_out; -}; - /* * Driver private area in the SCSI command structure. */ struct sym_ucmd { /* Override the SCSI pointer structure */ + struct completion done; + void (*old_done)(struct scsi_cmnd *); dma_addr_t data_mapping; - u_char data_mapped; - struct sym_eh_wait *eh_wait; + int to_do; + u_char data_mapped; /* corresponds to data_mapping above */ }; #define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) @@ -713,40 +703,19 @@ static void sym53c8xx_timer(unsigned long npref) #define SYM_EH_DO_WAIT 2 /* - * Our general completion handler. + * scsi_done() alias when error recovery is in progress. */ -static void __sym_eh_done(struct scsi_cmnd *cmd, int timed_out) +static void sym_eh_done(struct scsi_cmnd *cmd) { - struct sym_eh_wait *ep = SYM_UCMD_PTR(cmd)->eh_wait; - if (!ep) - return; - - /* Try to avoid a race here (not 100% safe) */ - if (!timed_out) { - ep->timed_out = 0; - if (ep->to_do == SYM_EH_DO_WAIT && !del_timer(&ep->timer)) - return; - } + struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); + BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd)); - /* Revert everything */ - SYM_UCMD_PTR(cmd)->eh_wait = NULL; - cmd->scsi_done = ep->old_done; + cmd->scsi_done = ucmd->old_done; - /* Wake up the eh thread if it wants to sleep */ - if (ep->to_do == SYM_EH_DO_WAIT) - complete(&ep->done); + if (ucmd->to_do == SYM_EH_DO_WAIT) + complete(&ucmd->done); } -/* - * scsi_done() alias when error recovery is in progress. - */ -static void sym_eh_done(struct scsi_cmnd *cmd) { __sym_eh_done(cmd, 0); } - -/* - * Some timeout handler to avoid waiting too long. - */ -static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); } - /* * Generic method for our eh processing. * The 'op' argument tells what we have to do. @@ -754,14 +723,15 @@ static void sym_eh_timeout(u_long p) { __sym_eh_done((struct scsi_cmnd *)p, 1); static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) { struct sym_hcb *np = SYM_SOFTC_PTR(cmd); + struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd); + struct Scsi_Host *host = cmd->device->host; SYM_QUEHEAD *qp; int to_do = SYM_EH_DO_IGNORE; int sts = -1; - struct sym_eh_wait eh, *ep = &eh; dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); - spin_lock_irq(cmd->device->host->host_lock); + spin_lock_irq(host->host_lock); /* This one is queued in some place -> to wait for completion */ FOR_EACH_QUEUED_ELEMENT(&np->busy_ccbq, qp) { struct sym_ccb *cp = sym_que_entry(qp, struct sym_ccb, link_ccbq); @@ -772,10 +742,9 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) } if (to_do == SYM_EH_DO_WAIT) { - init_completion(&ep->done); - ep->old_done = cmd->scsi_done; + init_completion(&ucmd->done); + ucmd->old_done = cmd->scsi_done; cmd->scsi_done = sym_eh_done; - SYM_UCMD_PTR(cmd)->eh_wait = ep; } /* Try to proceed the operation we have been asked for */ @@ -802,28 +771,19 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) /* On error, restore everything and cross fingers :) */ if (sts) { - SYM_UCMD_PTR(cmd)->eh_wait = NULL; - cmd->scsi_done = ep->old_done; + cmd->scsi_done = ucmd->old_done; to_do = SYM_EH_DO_IGNORE; } - ep->to_do = to_do; + ucmd->to_do = to_do; + spin_unlock_irq(host->host_lock); - /* Wait for completion with locks released, as required by kernel */ if (to_do == SYM_EH_DO_WAIT) { - init_timer(&ep->timer); - ep->timer.expires = jiffies + (5*HZ); - ep->timer.function = sym_eh_timeout; - ep->timer.data = (u_long)cmd; - ep->timed_out = 1; /* Be pessimistic for once :) */ - add_timer(&ep->timer); - spin_unlock_irq(np->s.host->host_lock); - wait_for_completion(&ep->done); - spin_lock_irq(np->s.host->host_lock); - if (ep->timed_out) + if (!wait_for_completion_timeout(&ucmd->done, 5*HZ)) { + ucmd->to_do = SYM_EH_DO_IGNORE; sts = -2; + } } - spin_unlock_irq(cmd->device->host->host_lock); dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname, sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed"); return sts ? SCSI_FAILED : SCSI_SUCCESS; -- cgit v1.2.3-70-g09d2 From 14ac8bf58d8ad46d8cd9e5db025beb9f8da24854 Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Tue, 28 Mar 2006 11:03:44 -0500 Subject: [SCSI] Enable clustering and large transfers This patch enables clustering and sets max_sectors to 0xffff to enable reading and writing of large blocks with tapes (and large transfers with sg). This change is needed after the sg and st drivers started using chained bios through scsi_request_async() in 2.6.16. Signed-off-by: Kai Makisara Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index e48409e26e5..2c4e5f1e7a9 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -1870,7 +1870,8 @@ static struct scsi_host_template sym2_template = { .eh_bus_reset_handler = sym53c8xx_eh_bus_reset_handler, .eh_host_reset_handler = sym53c8xx_eh_host_reset_handler, .this_id = 7, - .use_clustering = DISABLE_CLUSTERING, + .use_clustering = ENABLE_CLUSTERING, + .max_sectors = 0xFFFF, #ifdef SYM_LINUX_PROC_INFO_SUPPORT .proc_info = sym53c8xx_proc_info, .proc_name = NAME53C8XX, -- cgit v1.2.3-70-g09d2 From d637c4543fdc86cbef5805c679d24bb665172a7d Mon Sep 17 00:00:00 2001 From: Matthew Wilcox Date: Wed, 29 Mar 2006 14:45:18 -0700 Subject: [SCSI] sym2: Fix build when spinlock debugging is enabled When spinlock debugging is turned on, a struct completion grows beyond the size allowed for the scsi_pointer. So move the struct completion back onto the stack. The additional memory barriers are to keep us from completing a random piece of kernel stack if the command happens to complete after the error handling has finished. Signed-off-by: Matthew Wilcox Signed-off-by: James Bottomley --- drivers/scsi/sym53c8xx_2/sym_glue.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) (limited to 'drivers/scsi/sym53c8xx_2/sym_glue.c') diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c index 2c4e5f1e7a9..9c83b4d39a2 100644 --- a/drivers/scsi/sym53c8xx_2/sym_glue.c +++ b/drivers/scsi/sym53c8xx_2/sym_glue.c @@ -140,11 +140,11 @@ static struct scsi_transport_template *sym2_transport_template = NULL; * Driver private area in the SCSI command structure. */ struct sym_ucmd { /* Override the SCSI pointer structure */ - struct completion done; - void (*old_done)(struct scsi_cmnd *); - dma_addr_t data_mapping; - int to_do; - u_char data_mapped; /* corresponds to data_mapping above */ + dma_addr_t data_mapping; + unsigned char data_mapped; + unsigned char to_do; /* For error handling */ + void (*old_done)(struct scsi_cmnd *); /* For error handling */ + struct completion *eh_done; /* For error handling */ }; #define SYM_UCMD_PTR(cmd) ((struct sym_ucmd *)(&(cmd)->SCp)) @@ -713,7 +713,7 @@ static void sym_eh_done(struct scsi_cmnd *cmd) cmd->scsi_done = ucmd->old_done; if (ucmd->to_do == SYM_EH_DO_WAIT) - complete(&ucmd->done); + complete(ucmd->eh_done); } /* @@ -728,6 +728,7 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) SYM_QUEHEAD *qp; int to_do = SYM_EH_DO_IGNORE; int sts = -1; + struct completion eh_done; dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname); @@ -742,8 +743,10 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) } if (to_do == SYM_EH_DO_WAIT) { - init_completion(&ucmd->done); + init_completion(&eh_done); ucmd->old_done = cmd->scsi_done; + ucmd->eh_done = &eh_done; + wmb(); cmd->scsi_done = sym_eh_done; } @@ -779,8 +782,9 @@ static int sym_eh_handler(int op, char *opname, struct scsi_cmnd *cmd) spin_unlock_irq(host->host_lock); if (to_do == SYM_EH_DO_WAIT) { - if (!wait_for_completion_timeout(&ucmd->done, 5*HZ)) { + if (!wait_for_completion_timeout(&eh_done, 5*HZ)) { ucmd->to_do = SYM_EH_DO_IGNORE; + wmb(); sts = -2; } } -- cgit v1.2.3-70-g09d2