diff options
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 67 |
1 files changed, 60 insertions, 7 deletions
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 @@ | |||
10 | * 2 of the License, or (at your option) any later version. | 10 | * 2 of the License, or (at your option) any later version. |
11 | * | 11 | * |
12 | * FILE : megaraid_sas.c | 12 | * FILE : megaraid_sas.c |
13 | * Version : v00.00.03.10-rc1 | 13 | * Version : v00.00.03.10-rc5 |
14 | * | 14 | * |
15 | * Authors: | 15 | * Authors: |
16 | * (email-id : megaraidlinux@lsi.com) | 16 | * (email-id : megaraidlinux@lsi.com) |
@@ -886,6 +886,7 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) | |||
886 | goto out_return_cmd; | 886 | goto out_return_cmd; |
887 | 887 | ||
888 | cmd->scmd = scmd; | 888 | cmd->scmd = scmd; |
889 | scmd->SCp.ptr = (char *)cmd; | ||
889 | 890 | ||
890 | /* | 891 | /* |
891 | * Issue the command to the FW | 892 | * Issue the command to the FW |
@@ -919,7 +920,7 @@ static int megasas_slave_configure(struct scsi_device *sdev) | |||
919 | * The RAID firmware may require extended timeouts. | 920 | * The RAID firmware may require extended timeouts. |
920 | */ | 921 | */ |
921 | if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) | 922 | if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) |
922 | sdev->timeout = 90 * HZ; | 923 | sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ; |
923 | return 0; | 924 | return 0; |
924 | } | 925 | } |
925 | 926 | ||
@@ -981,8 +982,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) | |||
981 | 982 | ||
982 | instance = (struct megasas_instance *)scmd->device->host->hostdata; | 983 | instance = (struct megasas_instance *)scmd->device->host->hostdata; |
983 | 984 | ||
984 | scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x\n", | 985 | scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n", |
985 | scmd->serial_number, scmd->cmnd[0]); | 986 | scmd->serial_number, scmd->cmnd[0], scmd->retries); |
986 | 987 | ||
987 | if (instance->hw_crit_error) { | 988 | if (instance->hw_crit_error) { |
988 | printk(KERN_ERR "megasas: cannot recover from previous reset " | 989 | printk(KERN_ERR "megasas: cannot recover from previous reset " |
@@ -1000,6 +1001,39 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) | |||
1000 | } | 1001 | } |
1001 | 1002 | ||
1002 | /** | 1003 | /** |
1004 | * megasas_reset_timer - quiesce the adapter if required | ||
1005 | * @scmd: scsi cmnd | ||
1006 | * | ||
1007 | * Sets the FW busy flag and reduces the host->can_queue if the | ||
1008 | * cmd has not been completed within the timeout period. | ||
1009 | */ | ||
1010 | static enum | ||
1011 | scsi_eh_timer_return megasas_reset_timer(struct scsi_cmnd *scmd) | ||
1012 | { | ||
1013 | struct megasas_cmd *cmd = (struct megasas_cmd *)scmd->SCp.ptr; | ||
1014 | struct megasas_instance *instance; | ||
1015 | unsigned long flags; | ||
1016 | |||
1017 | if (time_after(jiffies, scmd->jiffies_at_alloc + | ||
1018 | (MEGASAS_DEFAULT_CMD_TIMEOUT * 2) * HZ)) { | ||
1019 | return EH_NOT_HANDLED; | ||
1020 | } | ||
1021 | |||
1022 | instance = cmd->instance; | ||
1023 | if (!(instance->flag & MEGASAS_FW_BUSY)) { | ||
1024 | /* FW is busy, throttle IO */ | ||
1025 | spin_lock_irqsave(instance->host->host_lock, flags); | ||
1026 | |||
1027 | instance->host->can_queue = 16; | ||
1028 | instance->last_time = jiffies; | ||
1029 | instance->flag |= MEGASAS_FW_BUSY; | ||
1030 | |||
1031 | spin_unlock_irqrestore(instance->host->host_lock, flags); | ||
1032 | } | ||
1033 | return EH_RESET_TIMER; | ||
1034 | } | ||
1035 | |||
1036 | /** | ||
1003 | * megasas_reset_device - Device reset handler entry point | 1037 | * megasas_reset_device - Device reset handler entry point |
1004 | */ | 1038 | */ |
1005 | static int megasas_reset_device(struct scsi_cmnd *scmd) | 1039 | static int megasas_reset_device(struct scsi_cmnd *scmd) |
@@ -1112,6 +1146,7 @@ static struct scsi_host_template megasas_template = { | |||
1112 | .eh_device_reset_handler = megasas_reset_device, | 1146 | .eh_device_reset_handler = megasas_reset_device, |
1113 | .eh_bus_reset_handler = megasas_reset_bus_host, | 1147 | .eh_bus_reset_handler = megasas_reset_bus_host, |
1114 | .eh_host_reset_handler = megasas_reset_bus_host, | 1148 | .eh_host_reset_handler = megasas_reset_bus_host, |
1149 | .eh_timed_out = megasas_reset_timer, | ||
1115 | .bios_param = megasas_bios_param, | 1150 | .bios_param = megasas_bios_param, |
1116 | .use_clustering = ENABLE_CLUSTERING, | 1151 | .use_clustering = ENABLE_CLUSTERING, |
1117 | }; | 1152 | }; |
@@ -1215,9 +1250,8 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, | |||
1215 | int exception = 0; | 1250 | int exception = 0; |
1216 | struct megasas_header *hdr = &cmd->frame->hdr; | 1251 | struct megasas_header *hdr = &cmd->frame->hdr; |
1217 | 1252 | ||
1218 | if (cmd->scmd) { | 1253 | if (cmd->scmd) |
1219 | cmd->scmd->SCp.ptr = (char *)0; | 1254 | cmd->scmd->SCp.ptr = NULL; |
1220 | } | ||
1221 | 1255 | ||
1222 | switch (hdr->cmd) { | 1256 | switch (hdr->cmd) { |
1223 | 1257 | ||
@@ -1806,6 +1840,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
1806 | u32 context; | 1840 | u32 context; |
1807 | struct megasas_cmd *cmd; | 1841 | struct megasas_cmd *cmd; |
1808 | struct megasas_instance *instance = (struct megasas_instance *)instance_addr; | 1842 | struct megasas_instance *instance = (struct megasas_instance *)instance_addr; |
1843 | unsigned long flags; | ||
1809 | 1844 | ||
1810 | /* If we have already declared adapter dead, donot complete cmds */ | 1845 | /* If we have already declared adapter dead, donot complete cmds */ |
1811 | if (instance->hw_crit_error) | 1846 | if (instance->hw_crit_error) |
@@ -1828,6 +1863,22 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) | |||
1828 | } | 1863 | } |
1829 | 1864 | ||
1830 | *instance->consumer = producer; | 1865 | *instance->consumer = producer; |
1866 | |||
1867 | /* | ||
1868 | * Check if we can restore can_queue | ||
1869 | */ | ||
1870 | if (instance->flag & MEGASAS_FW_BUSY | ||
1871 | && time_after(jiffies, instance->last_time + 5 * HZ) | ||
1872 | && atomic_read(&instance->fw_outstanding) < 17) { | ||
1873 | |||
1874 | spin_lock_irqsave(instance->host->host_lock, flags); | ||
1875 | instance->flag &= ~MEGASAS_FW_BUSY; | ||
1876 | instance->host->can_queue = | ||
1877 | instance->max_fw_cmds - MEGASAS_INT_CMDS; | ||
1878 | |||
1879 | spin_unlock_irqrestore(instance->host->host_lock, flags); | ||
1880 | } | ||
1881 | |||
1831 | } | 1882 | } |
1832 | 1883 | ||
1833 | /** | 1884 | /** |
@@ -2398,6 +2449,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) | |||
2398 | instance->init_id = MEGASAS_DEFAULT_INIT_ID; | 2449 | instance->init_id = MEGASAS_DEFAULT_INIT_ID; |
2399 | 2450 | ||
2400 | megasas_dbg_lvl = 0; | 2451 | megasas_dbg_lvl = 0; |
2452 | instance->flag = 0; | ||
2453 | instance->last_time = 0; | ||
2401 | 2454 | ||
2402 | /* | 2455 | /* |
2403 | * Initialize MFI Firmware | 2456 | * Initialize MFI Firmware |