Commit 05e9ebbe authored by Sumant Patro's avatar Sumant Patro Committed by James Bottomley

[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: default avatarSumant Patro <sumant.patro@lsi.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@SteelEye.com>
parent 3d9780b9
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
* *
* FILE : megaraid_sas.c * FILE : megaraid_sas.c
* Version : v00.00.03.10-rc1 * Version : v00.00.03.10-rc5
* *
* Authors: * Authors:
* (email-id : megaraidlinux@lsi.com) * (email-id : megaraidlinux@lsi.com)
...@@ -886,6 +886,7 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) ...@@ -886,6 +886,7 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
goto out_return_cmd; goto out_return_cmd;
cmd->scmd = scmd; cmd->scmd = scmd;
scmd->SCp.ptr = (char *)cmd;
/* /*
* Issue the command to the FW * Issue the command to the FW
...@@ -919,7 +920,7 @@ static int megasas_slave_configure(struct scsi_device *sdev) ...@@ -919,7 +920,7 @@ static int megasas_slave_configure(struct scsi_device *sdev)
* The RAID firmware may require extended timeouts. * The RAID firmware may require extended timeouts.
*/ */
if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS) if (sdev->channel >= MEGASAS_MAX_PD_CHANNELS)
sdev->timeout = 90 * HZ; sdev->timeout = MEGASAS_DEFAULT_CMD_TIMEOUT * HZ;
return 0; return 0;
} }
...@@ -981,8 +982,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) ...@@ -981,8 +982,8 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)scmd->device->host->hostdata; instance = (struct megasas_instance *)scmd->device->host->hostdata;
scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x\n", scmd_printk(KERN_NOTICE, scmd, "megasas: RESET -%ld cmd=%x retries=%x\n",
scmd->serial_number, scmd->cmnd[0]); scmd->serial_number, scmd->cmnd[0], scmd->retries);
if (instance->hw_crit_error) { if (instance->hw_crit_error) {
printk(KERN_ERR "megasas: cannot recover from previous reset " printk(KERN_ERR "megasas: cannot recover from previous reset "
...@@ -999,6 +1000,39 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd) ...@@ -999,6 +1000,39 @@ static int megasas_generic_reset(struct scsi_cmnd *scmd)
return ret_val; return ret_val;
} }
/**
* 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 * megasas_reset_device - Device reset handler entry point
*/ */
...@@ -1112,6 +1146,7 @@ static struct scsi_host_template megasas_template = { ...@@ -1112,6 +1146,7 @@ static struct scsi_host_template megasas_template = {
.eh_device_reset_handler = megasas_reset_device, .eh_device_reset_handler = megasas_reset_device,
.eh_bus_reset_handler = megasas_reset_bus_host, .eh_bus_reset_handler = megasas_reset_bus_host,
.eh_host_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, .bios_param = megasas_bios_param,
.use_clustering = ENABLE_CLUSTERING, .use_clustering = ENABLE_CLUSTERING,
}; };
...@@ -1215,9 +1250,8 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, ...@@ -1215,9 +1250,8 @@ megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd,
int exception = 0; int exception = 0;
struct megasas_header *hdr = &cmd->frame->hdr; struct megasas_header *hdr = &cmd->frame->hdr;
if (cmd->scmd) { if (cmd->scmd)
cmd->scmd->SCp.ptr = (char *)0; cmd->scmd->SCp.ptr = NULL;
}
switch (hdr->cmd) { switch (hdr->cmd) {
...@@ -1806,6 +1840,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) ...@@ -1806,6 +1840,7 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
u32 context; u32 context;
struct megasas_cmd *cmd; struct megasas_cmd *cmd;
struct megasas_instance *instance = (struct megasas_instance *)instance_addr; struct megasas_instance *instance = (struct megasas_instance *)instance_addr;
unsigned long flags;
/* If we have already declared adapter dead, donot complete cmds */ /* If we have already declared adapter dead, donot complete cmds */
if (instance->hw_crit_error) if (instance->hw_crit_error)
...@@ -1828,6 +1863,22 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr) ...@@ -1828,6 +1863,22 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
} }
*instance->consumer = producer; *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) ...@@ -2398,6 +2449,8 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
instance->init_id = MEGASAS_DEFAULT_INIT_ID; instance->init_id = MEGASAS_DEFAULT_INIT_ID;
megasas_dbg_lvl = 0; megasas_dbg_lvl = 0;
instance->flag = 0;
instance->last_time = 0;
/* /*
* Initialize MFI Firmware * Initialize MFI Firmware
......
...@@ -18,9 +18,9 @@ ...@@ -18,9 +18,9 @@
/* /*
* MegaRAID SAS Driver meta data * MegaRAID SAS Driver meta data
*/ */
#define MEGASAS_VERSION "00.00.03.10-rc1" #define MEGASAS_VERSION "00.00.03.10-rc5"
#define MEGASAS_RELDATE "Feb 14, 2007" #define MEGASAS_RELDATE "May 17, 2007"
#define MEGASAS_EXT_VERSION "Wed Feb 14 10:14:25 PST 2007" #define MEGASAS_EXT_VERSION "Thu May 17 10:09:32 PDT 2007"
/* /*
* Device IDs * Device IDs
...@@ -539,6 +539,8 @@ struct megasas_ctrl_info { ...@@ -539,6 +539,8 @@ struct megasas_ctrl_info {
#define MEGASAS_DBG_LVL 1 #define MEGASAS_DBG_LVL 1
#define MEGASAS_FW_BUSY 1
/* /*
* When SCSI mid-layer calls driver's reset routine, driver waits for * When SCSI mid-layer calls driver's reset routine, driver waits for
* MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note * MEGASAS_RESET_WAIT_TIME seconds for all outstanding IO to complete. Note
...@@ -549,8 +551,8 @@ struct megasas_ctrl_info { ...@@ -549,8 +551,8 @@ struct megasas_ctrl_info {
#define MEGASAS_RESET_WAIT_TIME 180 #define MEGASAS_RESET_WAIT_TIME 180
#define MEGASAS_INTERNAL_CMD_WAIT_TIME 180 #define MEGASAS_INTERNAL_CMD_WAIT_TIME 180
#define MEGASAS_RESET_NOTICE_INTERVAL 5 #define MEGASAS_RESET_NOTICE_INTERVAL 5
#define MEGASAS_IOCTL_CMD 0 #define MEGASAS_IOCTL_CMD 0
#define MEGASAS_DEFAULT_CMD_TIMEOUT 90
/* /*
* FW reports the maximum of number of commands that it can accept (maximum * FW reports the maximum of number of commands that it can accept (maximum
...@@ -1073,7 +1075,6 @@ struct megasas_instance { ...@@ -1073,7 +1075,6 @@ struct megasas_instance {
struct megasas_register_set __iomem *reg_set; struct megasas_register_set __iomem *reg_set;
s8 init_id; s8 init_id;
u8 reserved[3];
u16 max_num_sge; u16 max_num_sge;
u16 max_fw_cmds; u16 max_fw_cmds;
...@@ -1104,6 +1105,9 @@ struct megasas_instance { ...@@ -1104,6 +1105,9 @@ struct megasas_instance {
struct megasas_instance_template *instancet; struct megasas_instance_template *instancet;
struct tasklet_struct isr_tasklet; struct tasklet_struct isr_tasklet;
u8 flag;
unsigned long last_time;
}; };
#define MEGASAS_IS_LOGICAL(scp) \ #define MEGASAS_IS_LOGICAL(scp) \
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment