Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-mmc
[sfrench/cifs-2.6.git] / drivers / scsi / sym53c8xx_2 / sym_glue.c
index 1fffd2b3c654d93da2ef9f49d1b4ac929dd3d5a0..8c505076c0eb3631268dfa356528591284797835 100644 (file)
 #define NAME53C                "sym53c"
 #define NAME53C8XX     "sym53c8xx"
 
-/* SPARC just has to be different ... */
-#ifdef __sparc__
-#define IRQ_FMT "%s"
-#define IRQ_PRM(x) __irq_itoa(x)
-#else
 #define IRQ_FMT "%d"
 #define IRQ_PRM(x) (x)
-#endif
 
 struct sym_driver_setup sym_driver_setup = SYM_LINUX_DRIVER_SETUP;
 unsigned int sym_debug_flags = 0;
@@ -134,66 +128,17 @@ 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;
 
-/*
- *  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 */
-       dma_addr_t data_mapping;
-       u_char  data_mapped;
-       struct sym_eh_wait *eh_wait;
+       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))
@@ -205,7 +150,7 @@ static void __unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
 
        switch(SYM_UCMD_PTR(cmd)->data_mapped) {
        case 2:
-               pci_unmap_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+               pci_unmap_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
                break;
        case 1:
                pci_unmap_single(pdev, SYM_UCMD_PTR(cmd)->data_mapping,
@@ -235,7 +180,7 @@ static int __map_scsi_sg_data(struct pci_dev *pdev, struct scsi_cmnd *cmd)
        int use_sg;
        int dma_dir = cmd->sc_data_direction;
 
-       use_sg = pci_map_sg(pdev, cmd->buffer, cmd->use_sg, dma_dir);
+       use_sg = pci_map_sg(pdev, cmd->request_buffer, cmd->use_sg, dma_dir);
        if (use_sg > 0) {
                SYM_UCMD_PTR(cmd)->data_mapped  = 2;
                SYM_UCMD_PTR(cmd)->data_mapping = use_sg;
@@ -425,7 +370,7 @@ static int sym_scatter(struct sym_hcb *np, struct sym_ccb *cp, struct scsi_cmnd
        if (!use_sg)
                segment = sym_scatter_no_sglist(np, cp, cmd);
        else if ((use_sg = map_scsi_sg_data(np, cmd)) > 0) {
-               struct scatterlist *scatter = (struct scatterlist *)cmd->buffer;
+               struct scatterlist *scatter = (struct scatterlist *)cmd->request_buffer;
                struct sym_tcb *tp = &np->target[cp->target];
                struct sym_tblmove *data;
 
@@ -514,8 +459,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;
 
@@ -596,7 +539,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:
@@ -751,44 +694,22 @@ 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
 
 /*
- *  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;
+       struct sym_ucmd *ucmd = SYM_UCMD_PTR(cmd);
+       BUILD_BUG_ON(sizeof(struct scsi_pointer) < sizeof(struct sym_ucmd));
 
-       /* 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;
-       }
+       cmd->scsi_done = ucmd->old_done;
 
-       /* Revert everything */
-       SYM_UCMD_PTR(cmd)->eh_wait = NULL;
-       cmd->scsi_done = ep->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->eh_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.
@@ -796,35 +717,31 @@ 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;
+       struct completion eh_done;
 
        dev_warn(&cmd->device->sdev_gendev, "%s operation started.\n", opname);
 
+       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);
                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:
-               init_completion(&ep->done);
-               /* fall through */
-       case SYM_EH_DO_COMPLETE:
-               ep->old_done = cmd->scsi_done;
+       if (to_do == SYM_EH_DO_WAIT) {
+               init_completion(&eh_done);
+               ucmd->old_done = cmd->scsi_done;
+               ucmd->eh_done = &eh_done;
+               wmb();
                cmd->scsi_done = sym_eh_done;
-               SYM_UCMD_PTR(cmd)->eh_wait = ep;
        }
 
        /* Try to proceed the operation we have been asked for */
@@ -851,29 +768,19 @@ prepare:
 
        /* 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;
-       /* 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);
+       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(&eh_done, 5*HZ)) {
+                       ucmd->to_do = SYM_EH_DO_IGNORE;
+                       wmb();
                        sts = -2;
+               }
        }
        dev_warn(&cmd->device->sdev_gendev, "%s operation %s.\n", opname,
                        sts==0 ? "complete" :sts==-2 ? "timed-out" : "failed");
@@ -886,46 +793,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);
 }
 
 /*
@@ -944,15 +827,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);
        }
 }
 
@@ -1667,7 +1547,7 @@ static struct Scsi_Host * __devinit sym_attach(struct scsi_host_template *tpnt,
         *  If we synchonize the C code with SCRIPTS on interrupt, 
         *  we do not want to share the INTR line at all.
         */
-       if (request_irq(pdev->irq, sym53c8xx_intr, SA_SHIRQ, NAME53C8XX, np)) {
+       if (request_irq(pdev->irq, sym53c8xx_intr, IRQF_SHARED, NAME53C8XX, np)) {
                printf_err("%s: request irq %d failure\n",
                        sym_name(np), pdev->irq);
                goto attach_failed;
@@ -1866,15 +1746,25 @@ 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;
 
-#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));
@@ -1978,7 +1868,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,