diff options
| author | Sumant Patro <sumant.patro@lsi.com> | 2007-05-17 08:47:51 -0400 |
|---|---|---|
| committer | James Bottomley <jejb@mulgrave.il.steeleye.com> | 2007-05-24 10:08:27 -0400 |
| commit | 05e9ebbefb379a4da782b21b8427c88ac28a2334 (patch) | |
| tree | effaeaafd39a849d6a4a303bde6f60714c1a72c9 | |
| parent | 3d9780b97667fcd63159c0933fdce75465da6c70 (diff) | |
[SCSI] megaraid_sas: intercept cmd timeout and throttle io
eh_timed_out call back (megasas_reset_timer) is used to throttle io
to the adapter when it is called the first time for a scmd.
The MEGASAS_FW_BUSY flag is set and can_queue reduced to 16.
The can_queue is restored from completion routine in following
two conditions : 5 seconds has elapsed and
the # of outstanding cmds in FW is < 17.
Signed-off-by: Sumant Patro <sumant.patro@lsi.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 67 | ||||
| -rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.h | 14 |
2 files changed, 69 insertions, 12 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 |
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 @@ | |||
| 18 | /* | 18 | /* |
| 19 | * MegaRAID SAS Driver meta data | 19 | * MegaRAID SAS Driver meta data |
| 20 | */ | 20 | */ |
| 21 | #define MEGASAS_VERSION "00.00.03.10-rc1" | 21 | #define MEGASAS_VERSION "00.00.03.10-rc5" |
| 22 | #define MEGASAS_RELDATE "Feb 14, 2007" | 22 | #define MEGASAS_RELDATE "May 17, 2007" |
| 23 | #define MEGASAS_EXT_VERSION "Wed Feb 14 10:14:25 PST 2007" | 23 | #define MEGASAS_EXT_VERSION "Thu May 17 10:09:32 PDT 2007" |
| 24 | 24 | ||
| 25 | /* | 25 | /* |
| 26 | * Device IDs | 26 | * Device IDs |
| @@ -539,6 +539,8 @@ struct megasas_ctrl_info { | |||
| 539 | 539 | ||
| 540 | #define MEGASAS_DBG_LVL 1 | 540 | #define MEGASAS_DBG_LVL 1 |
| 541 | 541 | ||
| 542 | #define MEGASAS_FW_BUSY 1 | ||
| 543 | |||
| 542 | /* | 544 | /* |
| 543 | * When SCSI mid-layer calls driver's reset routine, driver waits for | 545 | * When SCSI mid-layer calls driver's reset routine, driver waits for |
| 544 | * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note | 546 | * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note |
| @@ -549,8 +551,8 @@ struct megasas_ctrl_info { | |||
| 549 | #define MEGASAS_RESET_WAIT_TIME 180 | 551 | #define MEGASAS_RESET_WAIT_TIME 180 |
| 550 | #define MEGASAS_INTERNAL_CMD_WAIT_TIME 180 | 552 | #define MEGASAS_INTERNAL_CMD_WAIT_TIME 180 |
| 551 | #define MEGASAS_RESET_NOTICE_INTERVAL 5 | 553 | #define MEGASAS_RESET_NOTICE_INTERVAL 5 |
| 552 | |||
| 553 | #define MEGASAS_IOCTL_CMD 0 | 554 | #define MEGASAS_IOCTL_CMD 0 |
| 555 | #define MEGASAS_DEFAULT_CMD_TIMEOUT 90 | ||
| 554 | 556 | ||
| 555 | /* | 557 | /* |
| 556 | * FW reports the maximum of number of commands that it can accept (maximum | 558 | * FW reports the maximum of number of commands that it can accept (maximum |
| @@ -1073,7 +1075,6 @@ struct megasas_instance { | |||
| 1073 | struct megasas_register_set __iomem *reg_set; | 1075 | struct megasas_register_set __iomem *reg_set; |
| 1074 | 1076 | ||
| 1075 | s8 init_id; | 1077 | s8 init_id; |
| 1076 | u8 reserved[3]; | ||
| 1077 | 1078 | ||
| 1078 | u16 max_num_sge; | 1079 | u16 max_num_sge; |
| 1079 | u16 max_fw_cmds; | 1080 | u16 max_fw_cmds; |
| @@ -1104,6 +1105,9 @@ struct megasas_instance { | |||
| 1104 | 1105 | ||
| 1105 | struct megasas_instance_template *instancet; | 1106 | struct megasas_instance_template *instancet; |
| 1106 | struct tasklet_struct isr_tasklet; | 1107 | struct tasklet_struct isr_tasklet; |
| 1108 | |||
| 1109 | u8 flag; | ||
| 1110 | unsigned long last_time; | ||
| 1107 | }; | 1111 | }; |
| 1108 | 1112 | ||
| 1109 | #define MEGASAS_IS_LOGICAL(scp) \ | 1113 | #define MEGASAS_IS_LOGICAL(scp) \ |
