scsi: megaraid_sas - throttle io if cmds are in risk of being timed-out
Subsystems (2)
PATCH 1/1 scsi: megaraid_sas - throttle io if cmds are in risk of being timed-out
Driver to throttle IO to reduce risk of OS timing out cmds.
Implemented a circular queue to keep track of pending OS cmds in FW. This queue is periodically (every 10 sec) checked by a timer routine. If there is any cmd that is in risk of getting timed-out by the OS, the host->can_queue is reduced to 16 and MEGASAS_FW_BUSY flag is set. The host->can_queue will be restored to default value when the following two conditions are met : 5 secs has elapsed and the # of outstanding cmds in FW is less than 17.
Also increased the per cmd timeout to 120*HZ from 90*HZ.
---
drivers/scsi/megaraid/megaraid_sas.c | 118 ++++++++++++++++++++++++- drivers/scsi/megaraid/megaraid_sas.h | 25 ++++- 2 files changed, 136 insertions(+), 7 deletions(-)
drivers/scsi/megaraid/megaraid_sas.c +114 -4
@@ -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-rc2 * * Authors: * (email-id : [email protected])
@@ -112,6 +112,15 @@ megasas_return_cmd(struct megasas_instan {unsigned long flags; +if (cmd->watchdog_slot !=0xff ) { +spin_lock_irqsave (&instance->watchdog_lock, flags); + + instance->watchdog_arr[cmd->watchdog_slot]--; + cmd->watchdog_slot =0xff ; + +spin_unlock_irqrestore (&instance->watchdog_lock, flags); + } +spin_lock_irqsave (&instance->cmd_pool_lock, flags); cmd->scmd =NULL ;
@@ -841,6 +850,7 @@ megasas_queue_command(struct scsi_cmnd *u32 frame_count;struct megasas_cmd *cmd;struct megasas_instance *instance; +unsigned long flags; instance = (struct megasas_instance *) scmd->device->host->hostdata;
@@ -888,6 +898,16 @@ megasas_queue_command(struct scsi_cmnd * cmd->scmd = scmd;/* +* Update watchdog array before sending cmd to FW +*/ +spin_lock_irqsave (&instance->watchdog_lock, flags); + + cmd->watchdog_slot = instance->watchdog_head; + instance->watchdog_arr[cmd->watchdog_slot]++; + +spin_unlock_irqrestore (&instance->watchdog_lock, flags); + +/* * Issue the command to the FW */ atomic_inc (&instance->fw_outstanding);
@@ -919,7 +939,7 @@ static int megasas_slave_configure(struc* The RAID firmware may require extended timeouts. */ if (sdev->channel >=MEGASAS_MAX_PD_CHANNELS ) - sdev->timeout =90 *HZ ; + sdev->timeout =120 *HZ ;return 0 ; }
@@ -981,8 +1001,8 @@ static int megasas_generic_reset(struct 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 "
@@ -1714,6 +1734,7 @@ static int megasas_alloc_cmds(struct megmemset (cmd,0 ,sizeof (struct megasas_cmd )); cmd->index = i; cmd->instance = instance; + cmd->watchdog_slot =0xff ;list_add_tail (&cmd->list, &instance->cmd_pool); }
@@ -1828,9 +1849,80 @@ static void megasas_complete_cmd_dpc(uns } *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 ) { + + instance->flag &= ~MEGASAS_FW_BUSY ; + instance->host->can_queue = + instance->max_fw_cmds -MEGASAS_INT_CMDS ; + } +} + +/** +* megasas_start_timer - Initializes a timer object +* @instance: Adapter soft state +* @timer: timer object to be initialized +* @fn: timer function +* @interval: time interval between timer function call +* +*/ +static inline void +megasas_start_timer (struct megasas_instance *instance, +struct timer_list *timer, +void *fn,unsigned long interval) +{ +init_timer (timer); + timer->expires = jiffies + interval; + timer->data = (unsigned long )instance; + timer->function = fn; +add_timer (timer); }/** +* megasas_throttle_timer - Timer fn +* @instance_addr: Address of adapter soft state +* +* Verifies and sets the FW busy flag if there is any pending cmd +* with the FW that is in risk of being timed-out by the OS +*/ +static void +megasas_throttle_timer (unsigned long instance_addr) +{ +unsigned long flags; +u32 pending; +struct megasas_instance *instance = (struct megasas_instance *)instance_addr; + +spin_lock_irqsave (&instance->watchdog_lock, flags); + + instance->watchdog_head++; +if (instance->watchdog_head ==MEGASAS_MAX_WATCHDOG_SLOTS ) + instance->watchdog_head =0 ; + +if (instance->watchdog_head == instance->watchdog_tail) { + pending = instance->watchdog_arr[instance->watchdog_tail]; +if (pending) { +/* FW is busy, throttle IO */ + instance->host->can_queue =16 ; + instance->last_time = jiffies; + instance->flag |=MEGASAS_FW_BUSY ; + } + instance->watchdog_tail++; +if (instance->watchdog_tail ==MEGASAS_MAX_WATCHDOG_SLOTS ) + instance->watchdog_tail =0 ; + } +spin_unlock_irqrestore (&instance->watchdog_lock, flags); + +/* Restart timer */ +mod_timer (&instance->throttle_timer, + jiffies +MEGASAS_WATCHDOG_TIMER_INTERVAL ); +} + +/** * megasas_init_mfi - Initializes the FW * @instance: Adapter soft state *
@@ -1851,6 +1943,7 @@ static int megasas_init_mfi(struct megasstruct megasas_init_queue_info *initq_info;dma_addr_t init_frame_h;dma_addr_t initq_info_h; +int i;/* * Map the message registers
@@ -2006,6 +2099,19 @@ static int megasas_init_mfi(struct megastasklet_init (&instance->isr_tasklet, megasas_complete_cmd_dpc, (unsigned long )instance); + +/* Initialize watchdog data structs */ +for (i =0 ; i <MEGASAS_MAX_WATCHDOG_SLOTS ; i++) + instance->watchdog_arr[i] =0 ; + + instance->watchdog_head =0 ; + instance->watchdog_tail =MEGASAS_MAX_WATCHDOG_SLOTS -1 ; + +/* Initialize the throttle IO timer */ +megasas_start_timer (instance, &instance->throttle_timer, + megasas_throttle_timer, +MEGASAS_WATCHDOG_TIMER_INTERVAL ); +return 0 ; fail_fw_init:
@@ -2385,6 +2491,7 @@ megasas_probe_one(struct pci_dev *pdev,init_waitqueue_head (&instance->abort_cmd_wait_q);spin_lock_init (&instance->cmd_pool_lock); +spin_lock_init (&instance->watchdog_lock);sema_init (&instance->aen_mutex,1 );sema_init (&instance->ioctl_sem,MEGASAS_INT_CMDS );
@@ -2398,6 +2505,8 @@ megasas_probe_one(struct pci_dev *pdev, instance->init_id =MEGASAS_DEFAULT_INIT_ID ; megasas_dbg_lvl =0 ; + instance->flag =0 ; + instance->last_time =0 ;/* * Initialize MFI Firmware
@@ -2566,6 +2675,7 @@ static void megasas_detach_one(struct pcmegasas_flush_cache (instance);megasas_shutdown_controller (instance);tasklet_kill (&instance->isr_tasklet); +del_timer_sync (&instance->throttle_timer);/* * Take the instance off the instance array. Note that we will not
drivers/scsi/megaraid/megaraid_sas.h +22 -3
@@ -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-rc2" +#define MEGASAS_RELDATE "Mar 01, 2007" +#define MEGASAS_EXT_VERSION "Thu Mar 01 10:07:34 PST 2007"/* * Device IDs
@@ -539,6 +539,10 @@ struct megasas_ctrl_info {#define MEGASAS_DBG_LVL 1 +#define MEGASAS_WATCHDOG_TIMER_INTERVAL 10*HZ +#define MEGASAS_MAX_WATCHDOG_SLOTS 8 +#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
@@ -1104,6 +1108,18 @@ struct megasas_instance {struct megasas_instance_template *instancet;struct tasklet_struct isr_tasklet; + +/* +* watchdog data structs used to throttle IO if required +*/ +u8 flag; +u8 watchdog_head; +u8 watchdog_tail; +u8 resvd; +unsigned long last_time; +u32 watchdog_arr[MEGASAS_MAX_WATCHDOG_SLOTS ]; +spinlock_t watchdog_lock; +struct timer_list throttle_timer; };#define MEGASAS_IS_LOGICAL (scp) \
@@ -1129,6 +1145,9 @@ struct megasas_cmd {struct scsi_cmnd *scmd;struct megasas_instance *instance;u32 frame_count; + +u8 watchdog_slot; +u8 resvd[3 ]; };#define MAX_MGMT_ADAPTERS 1024
Quoted 10 lines · Sumant Patro
Driver to throttle IO to reduce risk of OS timing out cmds.
Implemented a circular queue to keep track of pending OS cmds in FW. This queue is periodically (every 10 sec) checked by a timer routine. If there is any cmd that is in risk of getting timed-out by the OS, the
host->can_queueis reduced to 16 andMEGASAS_FW_BUSYflag is set. Thehost->can_queuewill be restored to default value when the following two conditions are met : 5 secs has elapsed and the # of outstanding cmds in FW is less than 17.
Also increased the per cmd timeout to 120*HZ from 90*HZ.
OK, this is still not nice. What you need to be doing is intercepting the timeout before it fires (and quiesces the machine). Currently the eh_timed_out() callback is only exposed to transport classes, I'll put it back into the host template and then you can use it.
James
RE: [PATCH] scsi: megaraid_sas - throttle io if cmds are in riskof being timed-out
Thank you James.
I will submit new patch that will throttle (if required) from eh_timed_out call back.
Regards,
Sumant
-----Original Message-----
From: James Bottomley [mailto:[email protected]]
Sent: Friday, March 16, 2007 3:23 PM
To: Patro, Sumant
Cc: [email protected]; [email protected]; [email protected]; Kolli, Neela; Yang, Bo
Subject: Re: [PATCH] scsi: megaraid_sas - throttle io if cmds are in riskof being timed-out
Quoted 10 lines · Sumant Patro
Driver to throttle IO to reduce risk of OS timing out cmds.
Implemented a circular queue to keep track of pending OS cmds in FW. This queue is periodically (every 10 sec) checked by a timer routine. If there is any cmd that is in risk of getting timed-out by the OS, the
host->can_queueis reduced to 16 andMEGASAS_FW_BUSYflag is set. Thehost->can_queuewill be restored to default value when the following two conditions are met : 5 secs has elapsed and the # of outstanding cmds in FW is less than 17.
Also increased the per cmd timeout to 120*HZ from 90*HZ.
OK, this is still not nice. What you need to be doing is intercepting the timeout before it fires (and quiesces the machine). Currently the eh_timed_out() callback is only exposed to transport classes, I'll put it back into the host template and then you can use it.
James