X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Fmegaraid%2Fmegaraid_sas.c;h=e2cf12ef3688d326d6959bc64d2d9a3dd19bbf20;hb=56906c612e10b5e32a48ccbe8a3c08ab6acf5a28;hp=9c5e4da5a132459f09584f749de22a903508ecb5;hpb=cf62a0a543fbab15286509d2e04e3dcf5549e966;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index 9c5e4da..e2cf12e 100644 --- a/drivers/scsi/megaraid/megaraid_sas.c +++ b/drivers/scsi/megaraid/megaraid_sas.c @@ -10,11 +10,13 @@ * 2 of the License, or (at your option) any later version. * * FILE : megaraid_sas.c - * Version : v00.00.03.05 + * Version : v00.00.03.10-rc5 * * Authors: - * Sreenivas Bagalkote - * Sumant Patro + * (email-id : megaraidlinux@lsi.com) + * Sreenivas Bagalkote + * Sumant Patro + * Bo Yang * * List of supported controllers * @@ -856,6 +858,18 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) goto out_done; } + switch (scmd->cmnd[0]) { + case SYNCHRONIZE_CACHE: + /* + * FW takes care of flush cache on its own + * No need to send it down + */ + scmd->result = DID_OK << 16; + goto out_done; + default: + break; + } + cmd = megasas_get_cmd(instance); if (!cmd) return SCSI_MLQUEUE_HOST_BUSY; @@ -872,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 @@ -905,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; } @@ -967,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 " @@ -986,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) @@ -1098,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, }; @@ -1201,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) { @@ -1792,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) @@ -1814,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); + } + } /** @@ -2384,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 @@ -2711,9 +2778,9 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, * For each user buffer, create a mirror buffer and copy in */ for (i = 0; i < ioc->sge_count; i++) { - kbuff_arr[i] = pci_alloc_consistent(instance->pdev, + kbuff_arr[i] = dma_alloc_coherent(&instance->pdev->dev, ioc->sgl[i].iov_len, - &buf_handle); + &buf_handle, GFP_KERNEL); if (!kbuff_arr[i]) { printk(KERN_DEBUG "megasas: Failed to alloc " "kernel SGL buffer for IOCTL \n"); @@ -2740,8 +2807,8 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, } if (ioc->sense_len) { - sense = pci_alloc_consistent(instance->pdev, ioc->sense_len, - &sense_handle); + sense = dma_alloc_coherent(&instance->pdev->dev, ioc->sense_len, + &sense_handle, GFP_KERNEL); if (!sense) { error = -ENOMEM; goto out; @@ -2800,12 +2867,12 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance, out: if (sense) { - pci_free_consistent(instance->pdev, ioc->sense_len, + dma_free_coherent(&instance->pdev->dev, ioc->sense_len, sense, sense_handle); } for (i = 0; i < ioc->sge_count && kbuff_arr[i]; i++) { - pci_free_consistent(instance->pdev, + dma_free_coherent(&instance->pdev->dev, kern_sge32[i].length, kbuff_arr[i], kern_sge32[i].phys_addr); }