|
@@ -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 *))
|
|
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)
|
|
* 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)
|
|
|
|
|
|
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->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) {
|
|
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)
|
|
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 = {
|
|
.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,
|
|
int exception = 0;
|
|
int exception = 0;
|
|
struct megasas_header *hdr = &cmd->frame->hdr;
|
|
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) {
|
|
switch (hdr->cmd) {
|
|
|
|
|
|
@@ -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)
|
|
}
|
|
}
|
|
|
|
|
|
*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)
|
|
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
|