#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;
}
}
-/*
- * 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))
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,
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;
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;
*/
int sym_setup_data_and_start(struct sym_hcb *np, struct scsi_cmnd *cmd, struct sym_ccb *cp)
{
+ u32 lastp, goalp;
int dir;
- struct sym_tcb *tp = &np->target[cp->target];
- struct sym_lcb *lp = sym_lp(tp, cp->lun);
/*
* Build the CDB.
sym_set_cam_status(cmd, DID_ERROR);
goto out_abort;
}
+
+ /*
+ * No segments means no data.
+ */
+ if (!cp->segments)
+ dir = DMA_NONE;
} else {
cp->data_len = 0;
cp->segments = 0;
}
/*
- * Set data pointers.
+ * Set the data pointer.
+ */
+ switch (dir) {
+ case DMA_BIDIRECTIONAL:
+ printk("%s: got DMA_BIDIRECTIONAL command", sym_name(np));
+ sym_set_cam_status(cmd, DID_ERROR);
+ goto out_abort;
+ case DMA_TO_DEVICE:
+ goalp = SCRIPTA_BA(np, data_out2) + 8;
+ lastp = goalp - 8 - (cp->segments * (2*4));
+ break;
+ case DMA_FROM_DEVICE:
+ cp->host_flags |= HF_DATA_IN;
+ goalp = SCRIPTA_BA(np, data_in2) + 8;
+ lastp = goalp - 8 - (cp->segments * (2*4));
+ break;
+ case DMA_NONE:
+ default:
+ lastp = goalp = SCRIPTB_BA(np, no_data);
+ break;
+ }
+
+ /*
+ * Set all pointers values needed by SCRIPTS.
*/
- sym_setup_data_pointers(np, cp, dir);
+ cp->phys.head.lastp = cpu_to_scr(lastp);
+ cp->phys.head.savep = cpu_to_scr(lastp);
+ cp->startp = cp->phys.head.savep;
+ cp->goalp = cpu_to_scr(goalp);
/*
* When `#ifed 1', the code below makes the driver
/*
* activate this job.
*/
- if (lp)
- sym_start_next_ccbs(np, lp, 2);
- else
- sym_put_start_queue(np, cp);
+ sym_put_start_queue(np, cp);
return 0;
out_abort:
* 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.
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 */
/* 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");
*/
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);
}
/*
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);
}
}
static int sym53c8xx_slave_alloc(struct scsi_device *sdev)
{
- struct sym_hcb *np;
- struct sym_tcb *tp;
+ struct sym_hcb *np = sym_get_hcb(sdev->host);
+ struct sym_tcb *tp = &np->target[sdev->id];
+ struct sym_lcb *lp;
if (sdev->id >= SYM_CONF_MAX_TARGET || sdev->lun >= SYM_CONF_MAX_LUN)
return -ENXIO;
- np = sym_get_hcb(sdev->host);
- tp = &np->target[sdev->id];
-
+ tp->starget = sdev->sdev_target;
/*
* Fail the device init if the device is flagged NOSCAN at BOOT in
* the NVRAM. This may speed up boot and maintain coherency with
* lun devices behave badly when asked for a non zero LUN.
*/
- if ((tp->usrflags & SYM_SCAN_BOOT_DISABLED) ||
- ((tp->usrflags & SYM_SCAN_LUNS_DISABLED) && sdev->lun != 0)) {
+ if (tp->usrflags & SYM_SCAN_BOOT_DISABLED) {
tp->usrflags &= ~SYM_SCAN_BOOT_DISABLED;
+ starget_printk(KERN_INFO, tp->starget,
+ "Scan at boot disabled in NVRAM\n");
return -ENXIO;
}
- tp->starget = sdev->sdev_target;
+ if (tp->usrflags & SYM_SCAN_LUNS_DISABLED) {
+ if (sdev->lun != 0)
+ return -ENXIO;
+ starget_printk(KERN_INFO, tp->starget,
+ "Multiple LUNs disabled in NVRAM\n");
+ }
+
+ lp = sym_alloc_lcb(np, sdev->id, sdev->lun);
+ if (!lp)
+ return -ENOMEM;
+
+ spi_min_period(tp->starget) = tp->usr_period;
+ spi_max_width(tp->starget) = tp->usr_width;
+
return 0;
}
/*
* Linux entry point for device queue sizing.
*/
-static int sym53c8xx_slave_configure(struct scsi_device *device)
+static int sym53c8xx_slave_configure(struct scsi_device *sdev)
{
- struct sym_hcb *np = sym_get_hcb(device->host);
- struct sym_tcb *tp = &np->target[device->id];
- struct sym_lcb *lp;
+ struct sym_hcb *np = sym_get_hcb(sdev->host);
+ struct sym_tcb *tp = &np->target[sdev->id];
+ struct sym_lcb *lp = sym_lp(tp, sdev->lun);
int reqtags, depth_to_use;
- /*
- * Allocate the LCB if not yet.
- * If it fail, we may well be in the sh*t. :)
- */
- lp = sym_alloc_lcb(np, device->id, device->lun);
- if (!lp)
- return -ENOMEM;
-
/*
* Get user flags.
*/
* Use at least 2.
* Donnot use more than our maximum.
*/
- reqtags = device_queue_depth(np, device->id, device->lun);
+ reqtags = device_queue_depth(np, sdev->id, sdev->lun);
if (reqtags > tp->usrtags)
reqtags = tp->usrtags;
- if (!device->tagged_supported)
+ if (!sdev->tagged_supported)
reqtags = 0;
#if 1 /* Avoid to locally queue commands for no good reasons */
if (reqtags > SYM_CONF_MAX_TAG)
#else
depth_to_use = (reqtags ? SYM_CONF_MAX_TAG : 2);
#endif
- scsi_adjust_queue_depth(device,
- (device->tagged_supported ?
+ scsi_adjust_queue_depth(sdev,
+ (sdev->tagged_supported ?
MSG_SIMPLE_TAG : 0),
depth_to_use);
lp->s.scdev_depth = depth_to_use;
- sym_tune_dev_queuing(tp, device->lun, reqtags);
+ sym_tune_dev_queuing(tp, sdev->lun, reqtags);
- if (!spi_initial_dv(device->sdev_target))
- spi_dv_device(device);
+ if (!spi_initial_dv(sdev->sdev_target))
+ spi_dv_device(sdev);
return 0;
}
+static void sym53c8xx_slave_destroy(struct scsi_device *sdev)
+{
+ struct sym_hcb *np = sym_get_hcb(sdev->host);
+ struct sym_lcb *lp = sym_lp(&np->target[sdev->id], sdev->lun);
+
+ if (lp->itlq_tbl)
+ sym_mfree_dma(lp->itlq_tbl, SYM_CONF_MAX_TASK * 4, "ITLQ_TBL");
+ kfree(lp->cb_tags);
+ sym_mfree_dma(lp, sizeof(*lp), "LCB");
+}
+
/*
* Linux entry point for info() function
*/
{
#if SYM_CONF_DMA_ADDRESSING_MODE > 0
#if SYM_CONF_DMA_ADDRESSING_MODE == 1
-#define DMA_DAC_MASK 0x000000ffffffffffULL /* 40-bit */
+#define DMA_DAC_MASK DMA_40BIT_MASK
#elif SYM_CONF_DMA_ADDRESSING_MODE == 2
#define DMA_DAC_MASK DMA_64BIT_MASK
#endif
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));
.queuecommand = sym53c8xx_queue_command,
.slave_alloc = sym53c8xx_slave_alloc,
.slave_configure = sym53c8xx_slave_configure,
+ .slave_destroy = sym53c8xx_slave_destroy,
.eh_abort_handler = sym53c8xx_eh_abort_handler,
.eh_device_reset_handler = sym53c8xx_eh_device_reset_handler,
.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,