diff options
author | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-29 22:39:52 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-05-29 22:39:52 +0200 |
commit | a43266355b3d8cf6717a27159f9a417bdff73782 (patch) | |
tree | 3d7e87d115a2aa6326e72171a5c05962830d5f41 /drivers/scsi | |
parent | USB: replace flush_workqueue with cancel_sync_work (diff) | |
parent | [SCSI] megaraid_sas: intercept cmd timeout and throttle io (diff) | |
download | linux-a43266355b3d8cf6717a27159f9a417bdff73782.tar.xz linux-a43266355b3d8cf6717a27159f9a417bdff73782.zip |
Merge master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6
* master.kernel.org:/pub/scm/linux/kernel/git/jejb/scsi-rc-fixes-2.6:
[SCSI] megaraid_sas: intercept cmd timeout and throttle io
[SCSI] fusion: Fix |/|| confusion
[SCSI] aic94xx: asd_clear_nexus should fail if the cleared task does not complete
[SCSI] aic7xxx: fix aicasm build failure with gcc-3.4.6
[SCSI] aacraid: apply commit config for reset_devices flag
[SCSI] sd: fix refcounting regression in suspend/resume routines
[SCSI] aacraid: fix panic on short Inquiry
[SCSI] aacraid: Correct sa platform support. (Was: [Bug 8469] Bad EIP value on pentium3 SMP kernel-2.6.21.1)
[SCSI] NCR53C9x: correct spelling mistake in deprecation notice
[SCSI] tgt: fix a rdma indirect transfer error bug
[SCSI] MegaRAID: Update MAINTAINERS email-id
[SCSI] stex: minor cleanup and version update
[SCSI] stex: fix reset recovery for console device
[SCSI] stex: extend hard reset wait time
[SCSI] stex: fix id mapping issue
[SCSI] ipr: Proper return codes for eh_dev_reset for SATA devices
[SCSI] zfcp: IO stall after deleting and path checker changes after reenabling zfcp devices
[SCSI] zfcp: avoid clutter in erp_dbf
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/aacraid/aachba.c | 15 | ||||
-rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 3 | ||||
-rw-r--r-- | drivers/scsi/aacraid/rx.c | 8 | ||||
-rw-r--r-- | drivers/scsi/aacraid/sa.c | 9 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_gram.y | 1 | ||||
-rw-r--r-- | drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y | 1 | ||||
-rw-r--r-- | drivers/scsi/aic94xx/aic94xx_tmf.c | 14 | ||||
-rw-r--r-- | drivers/scsi/ipr.c | 7 | ||||
-rw-r--r-- | drivers/scsi/libsrp.c | 1 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 67 | ||||
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 14 | ||||
-rw-r--r-- | drivers/scsi/scsi_devinfo.c | 1 | ||||
-rw-r--r-- | drivers/scsi/sd.c | 18 | ||||
-rw-r--r-- | drivers/scsi/stex.c | 90 |
14 files changed, 181 insertions, 68 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 1e82c69b36b0..8dcfe4ec35c2 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -146,7 +146,7 @@ static char *aac_get_status_string(u32 status); static int nondasd = -1; static int dacmode = -1; -static int commit = -1; +int aac_commit = -1; int startup_timeout = 180; int aif_timeout = 120; @@ -154,7 +154,7 @@ module_param(nondasd, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(nondasd, "Control scanning of hba for nondasd devices. 0=off, 1=on"); module_param(dacmode, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(dacmode, "Control whether dma addressing is using 64 bit DAC. 0=off, 1=on"); -module_param(commit, int, S_IRUGO|S_IWUSR); +module_param_named(commit, aac_commit, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(commit, "Control whether a COMMIT_CONFIG is issued to the adapter for foreign arrays.\nThis is typically needed in systems that do not have a BIOS. 0=off, 1=on"); module_param(startup_timeout, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(startup_timeout, "The duration of time in seconds to wait for adapter to have it's kernel up and\nrunning. This is typically adjusted for large systems that do not have a BIOS."); @@ -173,6 +173,9 @@ int expose_physicals = -1; module_param(expose_physicals, int, S_IRUGO|S_IWUSR); MODULE_PARM_DESC(expose_physicals, "Expose physical components of the arrays. -1=protect 0=off, 1=on"); +int aac_reset_devices = 0; +module_param_named(reset_devices, aac_reset_devices, int, S_IRUGO|S_IWUSR); +MODULE_PARM_DESC(reset_devices, "Force an adapter reset at initialization."); static inline int aac_valid_context(struct scsi_cmnd *scsicmd, struct fib *fibptr) { @@ -246,7 +249,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag) aac_fib_complete(fibptr); /* Send a CT_COMMIT_CONFIG to enable discovery of devices */ if (status >= 0) { - if ((commit == 1) || commit_flag) { + if ((aac_commit == 1) || commit_flag) { struct aac_commit_config * dinfo; aac_fib_init(fibptr); dinfo = (struct aac_commit_config *) fib_data(fibptr); @@ -261,7 +264,7 @@ int aac_get_config_status(struct aac_dev *dev, int commit_flag) 1, 1, NULL, NULL); aac_fib_complete(fibptr); - } else if (commit == 0) { + } else if (aac_commit == 0) { printk(KERN_WARNING "aac_get_config_status: Foreign device configurations are being ignored\n"); } @@ -340,7 +343,7 @@ int aac_get_containers(struct aac_dev *dev) static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigned int offset, unsigned int len) { void *buf; - unsigned int transfer_len; + int transfer_len; struct scatterlist *sg = scsicmd->request_buffer; if (scsicmd->use_sg) { @@ -351,7 +354,7 @@ static void aac_internal_transfer(struct scsi_cmnd *scsicmd, void *data, unsigne transfer_len = min(scsicmd->request_bufflen, len + offset); } transfer_len -= offset; - if (buf && transfer_len) + if (buf && transfer_len > 0) memcpy(buf + offset, data, transfer_len); if (scsicmd->use_sg) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 45ca3e801619..c81edf36913f 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1823,9 +1823,12 @@ int aac_send_shutdown(struct aac_dev *dev); int aac_probe_container(struct aac_dev *dev, int cid); int _aac_rx_init(struct aac_dev *dev); int aac_rx_select_comm(struct aac_dev *dev, int comm); +int aac_rx_deliver_producer(struct fib * fib); extern int numacb; extern int acbsize; extern char aac_driver_version[]; extern int startup_timeout; extern int aif_timeout; extern int expose_physicals; +extern int aac_reset_devices; +extern int aac_commit; diff --git a/drivers/scsi/aacraid/rx.c b/drivers/scsi/aacraid/rx.c index 291cd14f4e98..ae978a373c56 100644 --- a/drivers/scsi/aacraid/rx.c +++ b/drivers/scsi/aacraid/rx.c @@ -378,7 +378,7 @@ static int aac_rx_check_health(struct aac_dev *dev) * * Will send a fib, returning 0 if successful. */ -static int aac_rx_deliver_producer(struct fib * fib) +int aac_rx_deliver_producer(struct fib * fib) { struct aac_dev *dev = fib->dev; struct aac_queue *q = &dev->queues->queue[AdapNormCmdQueue]; @@ -488,6 +488,8 @@ static int aac_rx_restart_adapter(struct aac_dev *dev, int bled) return -EINVAL; if (rx_readl(dev, MUnit.OMRx[0]) & KERNEL_PANIC) return -ENODEV; + if (startup_timeout < 300) + startup_timeout = 300; return 0; } @@ -542,7 +544,7 @@ int _aac_rx_init(struct aac_dev *dev) dev->a_ops.adapter_sync_cmd = rx_sync_cmd; dev->a_ops.adapter_enable_int = aac_rx_disable_interrupt; dev->OIMR = status = rx_readb (dev, MUnit.OIMR); - if ((((status & 0x0c) != 0x0c) || reset_devices) && + if ((((status & 0x0c) != 0x0c) || aac_reset_devices || reset_devices) && !aac_rx_restart_adapter(dev, 0)) ++restart; /* @@ -594,6 +596,8 @@ int _aac_rx_init(struct aac_dev *dev) } msleep(1); } + if (restart) + aac_commit = 1; /* * Fill in the common function dispatch table. */ diff --git a/drivers/scsi/aacraid/sa.c b/drivers/scsi/aacraid/sa.c index f4b5e9742ab0..85b91bc578c9 100644 --- a/drivers/scsi/aacraid/sa.c +++ b/drivers/scsi/aacraid/sa.c @@ -5,7 +5,7 @@ * based on the old aacraid driver that is.. * Adaptec aacraid device driver for Linux. * - * Copyright (c) 2000 Adaptec, Inc. (aacraid@adaptec.com) + * Copyright (c) 2000-2007 Adaptec, Inc. (aacraid@adaptec.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -257,6 +257,11 @@ static void aac_sa_start_adapter(struct aac_dev *dev) NULL, NULL, NULL, NULL, NULL); } +static int aac_sa_restart_adapter(struct aac_dev *dev, int bled) +{ + return -EINVAL; +} + /** * aac_sa_check_health * @dev: device to check if healthy @@ -366,7 +371,9 @@ int aac_sa_init(struct aac_dev *dev) dev->a_ops.adapter_notify = aac_sa_notify_adapter; dev->a_ops.adapter_sync_cmd = sa_sync_cmd; dev->a_ops.adapter_check_health = aac_sa_check_health; + dev->a_ops.adapter_restart = aac_sa_restart_adapter; dev->a_ops.adapter_intr = aac_sa_intr; + dev->a_ops.adapter_deliver = aac_rx_deliver_producer; dev->a_ops.adapter_ioremap = aac_sa_ioremap; /* diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y index c328596def3c..6066998ed562 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_gram.y @@ -106,6 +106,7 @@ static void make_expression(expression_t *immed, int value); static void add_conditional(symbol_t *symbol); static void add_version(const char *verstring); static int is_download_const(expression_t *immed); +void yyerror(const char *string); #define SRAM_SYMNAME "SRAM_BASE" #define SCB_SYMNAME "SCB_BASE" diff --git a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y index 439f760b34b5..ff46aa6801bf 100644 --- a/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y +++ b/drivers/scsi/aic7xxx/aicasm/aicasm_macro_gram.y @@ -65,6 +65,7 @@ static symbol_t *macro_symbol; static void add_macro_arg(const char *argtext, int position); +void mmerror(const char *string); %} diff --git a/drivers/scsi/aic94xx/aic94xx_tmf.c b/drivers/scsi/aic94xx/aic94xx_tmf.c index 9a14a6d97275..c0d0b7d7a8ce 100644 --- a/drivers/scsi/aic94xx/aic94xx_tmf.c +++ b/drivers/scsi/aic94xx/aic94xx_tmf.c @@ -290,6 +290,7 @@ static void asd_tmf_tasklet_complete(struct asd_ascb *ascb, static inline int asd_clear_nexus(struct sas_task *task) { int res = TMF_RESP_FUNC_FAILED; + int leftover; struct asd_ascb *tascb = task->lldd_task; unsigned long flags; @@ -298,10 +299,12 @@ static inline int asd_clear_nexus(struct sas_task *task) res = asd_clear_nexus_tag(task); else res = asd_clear_nexus_index(task); - wait_for_completion_timeout(&tascb->completion, - AIC94XX_SCB_TIMEOUT); + leftover = wait_for_completion_timeout(&tascb->completion, + AIC94XX_SCB_TIMEOUT); ASD_DPRINTK("came back from clear nexus\n"); spin_lock_irqsave(&task->task_state_lock, flags); + if (leftover < 1) + res = TMF_RESP_FUNC_FAILED; if (task->task_state_flags & SAS_TASK_STATE_DONE) res = TMF_RESP_FUNC_COMPLETE; spin_unlock_irqrestore(&task->task_state_lock, flags); @@ -350,6 +353,7 @@ int asd_abort_task(struct sas_task *task) unsigned long flags; struct asd_ascb *ascb = NULL; struct scb *scb; + int leftover; spin_lock_irqsave(&task->task_state_lock, flags); if (task->task_state_flags & SAS_TASK_STATE_DONE) { @@ -455,9 +459,11 @@ int asd_abort_task(struct sas_task *task) break; case TF_TMF_TASK_DONE + 0xFF00: /* done but not reported yet */ res = TMF_RESP_FUNC_FAILED; - wait_for_completion_timeout(&tascb->completion, - AIC94XX_SCB_TIMEOUT); + leftover = wait_for_completion_timeout(&tascb->completion, + AIC94XX_SCB_TIMEOUT); spin_lock_irqsave(&task->task_state_lock, flags); + if (leftover < 1) + res = TMF_RESP_FUNC_FAILED; if (task->task_state_flags & SAS_TASK_STATE_DONE) res = TMF_RESP_FUNC_COMPLETE; spin_unlock_irqrestore(&task->task_state_lock, flags); diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 4baa79e68679..fa6ff295e568 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -3954,6 +3954,13 @@ static int __ipr_eh_dev_reset(struct scsi_cmnd * scsi_cmd) spin_unlock_irq(scsi_cmd->device->host->host_lock); ata_do_eh(ap, NULL, NULL, ipr_sata_reset, NULL); spin_lock_irq(scsi_cmd->device->host->host_lock); + + list_for_each_entry(ipr_cmd, &ioa_cfg->pending_q, queue) { + if (ipr_cmd->ioarcb.res_handle == res->cfgte.res_handle) { + rc = -EIO; + break; + } + } } else rc = ipr_device_reset(ioa_cfg, res); res->resetting_device = 0; diff --git a/drivers/scsi/libsrp.c b/drivers/scsi/libsrp.c index 5631c199a8eb..732446e63963 100644 --- a/drivers/scsi/libsrp.c +++ b/drivers/scsi/libsrp.c @@ -254,6 +254,7 @@ static int srp_indirect_data(struct scsi_cmnd *sc, struct srp_cmd *cmd, sg_init_one(&dummy, md, id->table_desc.len); sg_dma_address(&dummy) = token; + sg_dma_len(&dummy) = id->table_desc.len; err = rdma_io(sc, &dummy, 1, &id->table_desc, 1, DMA_TO_DEVICE, id->table_desc.len); if (err) { diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 7a812677ff8a..e2cf12ef3688 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,7 +10,7 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.10-rc1 + * Version : v00.00.03.10-rc5 * * Authors: * (email-id : megaraidlinux@lsi.com) @@ -886,6 +886,7 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) goto out_return_cmd; cmd->scmd = scmd; + scmd->SCp.ptr = (char *)cmd; /* * Issue the command to the FW @@ -919,7 +920,7 @@ static int megasas_slave_configure(struct scsi_device *sdev) * The RAID firmware may require extended timeouts. */ if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) - sdev->timeout = 90 * HZ; + sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ; return 0; } @@ -981,8 +982,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) instance = (struct megasas_instance *)scmd->device->host->hostdata; - scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x\n", - scmd->serial_number, scmd->cmnd[0]); + scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", + scmd->serial_number, scmd->cmnd[0], scmd->retries); if (instance->hw_crit_error) { printk(KERN_ERR "megasas: cannot recover from previous reset " @@ -1000,6 +1001,39 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) } /** + * megasas_reset_timer - quiesce the adapter if required + * @scmd: scsi cmnd + * + * Sets the FW busy flag and reduces the host->can_queue if the + * cmd has not been completed within the timeout period. + */ +static enum +scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) +{ + struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr; + struct megasas_instance *instance; + unsigned long flags; + + if (time_after(jiffies, scmd->jiffies_at_alloc + + (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) { + return EH_NOT_HANDLED; + } + + instance = cmd->instance; + if (!(instance->flag & MEGASAS_FW_BUSY)) { + /* FW is busy, throttle IO */ + spin_lock_irqsave(instance->host->host_lock, flags); + + instance->host->can_queue = 16; + instance->last_time = jiffies; + instance->flag |= MEGASAS_FW_BUSY; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + } + return EH_RESET_TIMER; +} + +/** * megasas_reset_device - Device reset handler entry point */ static int megasas_reset_device(struct scsi_cmnd *scmd) @@ -1112,6 +1146,7 @@ static struct scsi_host_template megasas_template = { .eh_device_reset_handler = megasas_reset_device, .eh_bus_reset_handler = megasas_reset_bus_host, .eh_host_reset_handler = megasas_reset_bus_host, + .eh_timed_out = megasas_reset_timer, .bios_param = megasas_bios_param, .use_clustering = ENABLE_CLUSTERING, }; @@ -1215,9 +1250,8 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, int exception = 0; struct megasas_header *hdr = &cmd->frame->hdr; - if (cmd->scmd) { - cmd->scmd->SCp.ptr = (char *)0; - } + if (cmd->scmd) + cmd->scmd->SCp.ptr = NULL; switch (hdr->cmd) { @@ -1806,6 +1840,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) u32 context; struct megasas_cmd *cmd; struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + unsigned long flags; /* If we have already declared adapter dead, donot complete cmds */ if (instance->hw_crit_error) @@ -1828,6 +1863,22 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) } *instance->consumer = producer; + + /* + * Check if we can restore can_queue + */ + if (instance->flag & MEGASAS_FW_BUSY + && time_after(jiffies, instance->last_time + 5 * HZ) + && atomic_read(&instance->fw_outstanding) < 17) { + + spin_lock_irqsave(instance->host->host_lock, flags); + instance->flag &= ~MEGASAS_FW_BUSY; + instance->host->can_queue = + instance->max_fw_cmds - MEGASAS_INT_CMDS; + + spin_unlock_irqrestore(instance->host->host_lock, flags); + } + } /** @@ -2398,6 +2449,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance->init_id = MEGASAS_DEFAULT_INIT_ID; megasas_dbg_lvl = 0; + instance->flag = 0; + instance->last_time = 0; /* * Initialize MFI Firmware diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index e862992ee377..4dffc918a414 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -18,9 +18,9 @@ /* * MegaRAID SAS Driver meta data */ -#define MEGASAS_VERSION "00.00.03.10-rc1" -#define MEGASAS_RELDATE "Feb 14, 2007" -#define MEGASAS_EXT_VERSION "Wed Feb 14 10:14:25 PST 2007" +#define MEGASAS_VERSION "00.00.03.10-rc5" +#define MEGASAS_RELDATE "May 17, 2007" +#define MEGASAS_EXT_VERSION "Thu May 17 10:09:32 PDT 2007" /* * Device IDs @@ -539,6 +539,8 @@ struct megasas_ctrl_info { #define MEGASAS_DBG_LVL 1 +#define MEGASAS_FW_BUSY 1 + /* * When SCSI mid-layer calls driver's reset routine, driver waits for * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note @@ -549,8 +551,8 @@ struct megasas_ctrl_info { #define MEGASAS_RESET_WAIT_TIME 180 #define MEGASAS_INTERNAL_CMD_WAIT_TIME 180 #define MEGASAS_RESET_NOTICE_INTERVAL 5 - #define MEGASAS_IOCTL_CMD 0 +#define MEGASAS_DEFAULT_CMD_TIMEOUT 90 /* * FW reports the maximum of number of commands that it can accept (maximum @@ -1073,7 +1075,6 @@ struct megasas_instance { struct megasas_register_set __iomem *reg_set; s8 init_id; - u8 reserved[3]; u16 max_num_sge; u16 max_fw_cmds; @@ -1104,6 +1105,9 @@ struct megasas_instance { struct megasas_instance_template *instancet; struct tasklet_struct isr_tasklet; + + u8 flag; + unsigned long last_time; }; #define MEGASAS_IS_LOGICAL(scp) \ diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index ce63044b1ec8..18dd5cc4d7c6 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c @@ -209,6 +209,7 @@ static struct { {"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN}, + {"Promise", "", NULL, BLIST_SPARSELUN}, {"REGAL", "CDC-4X", NULL, BLIST_MAX5LUN | BLIST_SINGLELUN}, {"SanDisk", "ImageMate CF-SD1", NULL, BLIST_FORCELUN}, {"SEAGATE", "ST34555N", "0930", BLIST_NOTQ}, /* Chokes on tagged INQUIRY */ diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 00e46662296f..3d8c9cb24f91 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -1789,7 +1789,7 @@ static void sd_shutdown(struct device *dev) static int sd_suspend(struct device *dev, pm_message_t mesg) { struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); - int ret; + int ret = 0; if (!sdkp) return 0; /* this can happen */ @@ -1798,30 +1798,34 @@ static int sd_suspend(struct device *dev, pm_message_t mesg) sd_printk(KERN_NOTICE, sdkp, "Synchronizing SCSI cache\n"); ret = sd_sync_cache(sdkp); if (ret) - return ret; + goto done; } if (mesg.event == PM_EVENT_SUSPEND && sdkp->device->manage_start_stop) { sd_printk(KERN_NOTICE, sdkp, "Stopping disk\n"); ret = sd_start_stop_device(sdkp, 0); - if (ret) - return ret; } - return 0; +done: + scsi_disk_put(sdkp); + return ret; } static int sd_resume(struct device *dev) { struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev); + int ret = 0; if (!sdkp->device->manage_start_stop) - return 0; + goto done; sd_printk(KERN_NOTICE, sdkp, "Starting disk\n"); + ret = sd_start_stop_device(sdkp, 1); - return sd_start_stop_device(sdkp, 1); +done: + scsi_disk_put(sdkp); + return ret; } /** diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c index 69be1324b114..9ac83abc4028 100644 --- a/drivers/scsi/stex.c +++ b/drivers/scsi/stex.c @@ -32,11 +32,12 @@ #include <scsi/scsi_cmnd.h> #include <scsi/scsi_host.h> #include <scsi/scsi_tcq.h> +#include <scsi/scsi_dbg.h> #define DRV_NAME "stex" -#define ST_DRIVER_VERSION "3.1.0.1" +#define ST_DRIVER_VERSION "3.6.0000.1" #define ST_VER_MAJOR 3 -#define ST_VER_MINOR 1 +#define ST_VER_MINOR 6 #define ST_OEM 0 #define ST_BUILD_VER 1 @@ -113,10 +114,6 @@ enum { SG_CF_64B = 0x40, /* 64 bit item */ SG_CF_HOST = 0x20, /* sg in host memory */ - ST_MAX_ARRAY_SUPPORTED = 16, - ST_MAX_TARGET_NUM = (ST_MAX_ARRAY_SUPPORTED+1), - ST_MAX_LUN_PER_TARGET = 16, - st_shasta = 0, st_vsc = 1, st_vsc1 = 2, @@ -586,7 +583,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) u16 tag; host = cmd->device->host; id = cmd->device->id; - lun = cmd->device->channel; /* firmware lun issue work around */ + lun = cmd->device->lun; hba = (struct st_hba *) &host->hostdata[0]; switch (cmd->cmnd[0]) { @@ -605,8 +602,26 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) stex_invalid_field(cmd, done); return 0; } + case REPORT_LUNS: + /* + * The shasta firmware does not report actual luns in the + * target, so fail the command to force sequential lun scan. + * Also, the console device does not support this command. + */ + if (hba->cardtype == st_shasta || id == host->max_id - 1) { + stex_invalid_field(cmd, done); + return 0; + } + break; + case TEST_UNIT_READY: + if (id == host->max_id - 1) { + cmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8; + done(cmd); + return 0; + } + break; case INQUIRY: - if (id != ST_MAX_ARRAY_SUPPORTED) + if (id != host->max_id - 1) break; if (lun == 0 && (cmd->cmnd[1] & INQUIRY_EVPD) == 0) { stex_direct_copy(cmd, console_inq_page, @@ -624,7 +639,7 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) ver.oem = ST_OEM; ver.build = ST_BUILD_VER; ver.signature[0] = PASSTHRU_SIGNATURE; - ver.console_id = ST_MAX_ARRAY_SUPPORTED; + ver.console_id = host->max_id - 1; ver.host_no = hba->host->host_no; cmd->result = stex_direct_copy(cmd, &ver, sizeof(ver)) ? DID_OK << 16 | COMMAND_COMPLETE << 8 : @@ -645,13 +660,8 @@ stex_queuecommand(struct scsi_cmnd *cmd, void (* done)(struct scsi_cmnd *)) req = stex_alloc_req(hba); - if (hba->cardtype == st_yosemite) { - req->lun = lun * (ST_MAX_TARGET_NUM - 1) + id; - req->target = 0; - } else { - req->lun = lun; - req->target = id; - } + req->lun = lun; + req->target = id; /* cdb */ memcpy(req->cdb, cmd->cmnd, STEX_CDB_LENGTH); @@ -767,18 +777,6 @@ static void stex_ys_commands(struct st_hba *hba, ccb->srb_status = SRB_STATUS_SELECTION_TIMEOUT; else ccb->srb_status = SRB_STATUS_SUCCESS; - } else if (ccb->cmd->cmnd[0] == REPORT_LUNS) { - u8 *report_lun_data = (u8 *)hba->copy_buffer; - - count = STEX_EXTRA_SIZE; - stex_internal_copy(ccb->cmd, report_lun_data, - &count, ccb->sg_count, ST_FROM_CMD); - if (report_lun_data[2] || report_lun_data[3]) { - report_lun_data[2] = 0x00; - report_lun_data[3] = 0x08; - stex_internal_copy(ccb->cmd, report_lun_data, - &count, ccb->sg_count, ST_TO_CMD); - } } } @@ -995,6 +993,11 @@ static int stex_abort(struct scsi_cmnd *cmd) u32 data; int result = SUCCESS; unsigned long flags; + + printk(KERN_INFO DRV_NAME + "(%s): aborting command\n", pci_name(hba->pdev)); + scsi_print_command(cmd); + base = hba->mmio_base; spin_lock_irqsave(host->host_lock, flags); if (tag < host->can_queue && hba->ccb[tag].cmd == cmd) @@ -1051,7 +1054,12 @@ static void stex_hard_reset(struct st_hba *hba) pci_read_config_byte(bus->self, PCI_BRIDGE_CONTROL, &pci_bctl); pci_bctl |= PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); - msleep(1); + + /* + * 1 ms may be enough for 8-port controllers. But 16-port controllers + * require more time to finish bus reset. Use 100 ms here for safety + */ + msleep(100); pci_bctl &= ~PCI_BRIDGE_CTL_BUS_RESET; pci_write_config_byte(bus->self, PCI_BRIDGE_CONTROL, pci_bctl); @@ -1075,6 +1083,10 @@ static int stex_reset(struct scsi_cmnd *cmd) unsigned long before; hba = (struct st_hba *) &cmd->device->host->hostdata[0]; + printk(KERN_INFO DRV_NAME + "(%s): resetting host\n", pci_name(hba->pdev)); + scsi_print_command(cmd); + hba->mu_status = MU_STATE_RESETTING; if (hba->cardtype == st_shasta) @@ -1194,7 +1206,7 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_scsi_host_put; } - hba->mmio_base = ioremap(pci_resource_start(pdev, 0), + hba->mmio_base = ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); if ( !hba->mmio_base) { printk(KERN_ERR DRV_NAME "(%s): memory map failed\n", @@ -1229,12 +1241,18 @@ stex_probe(struct pci_dev *pdev, const struct pci_device_id *id) hba->copy_buffer = hba->dma_mem + MU_BUFFER_SIZE; hba->mu_status = MU_STATE_STARTING; - /* firmware uses id/lun pair for a logical drive, but lun would be - always 0 if CONFIG_SCSI_MULTI_LUN not configured, so we use - channel to map lun here */ - host->max_channel = ST_MAX_LUN_PER_TARGET - 1; - host->max_id = ST_MAX_TARGET_NUM; - host->max_lun = 1; + if (hba->cardtype == st_shasta) { + host->max_lun = 8; + host->max_id = 16 + 1; + } else if (hba->cardtype == st_yosemite) { + host->max_lun = 128; + host->max_id = 1 + 1; + } else { + /* st_vsc and st_vsc1 */ + host->max_lun = 1; + host->max_id = 128 + 1; + } + host->max_channel = 0; host->unique_id = host->host_no; host->max_cmd_len = STEX_CDB_LENGTH; |