summaryrefslogtreecommitdiff
path: root/drivers/scsi/megaraid/megaraid_sas.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas.c')
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.c130
1 files changed, 127 insertions, 3 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c
index d3c9cdee292b..7451bc096a01 100644
--- a/drivers/scsi/megaraid/megaraid_sas.c
+++ b/drivers/scsi/megaraid/megaraid_sas.c
@@ -10,7 +10,7 @@
* 2 of the License, or (at your option) any later version.
*
* FILE : megaraid_sas.c
- * Version : v00.00.04.17.1-rc1
+ * Version : v00.00.04.31-rc1
*
* Authors:
* (email-id : megaraidlinux@lsi.com)
@@ -56,6 +56,15 @@ module_param_named(poll_mode_io, poll_mode_io, int, 0);
MODULE_PARM_DESC(poll_mode_io,
"Complete cmds from IO path, (default=0)");
+/*
+ * Number of sectors per IO command
+ * Will be set in megasas_init_mfi if user does not provide
+ */
+static unsigned int max_sectors;
+module_param_named(max_sectors, max_sectors, int, 0);
+MODULE_PARM_DESC(max_sectors,
+ "Maximum number of sectors per IO command");
+
MODULE_LICENSE("GPL");
MODULE_VERSION(MEGASAS_VERSION);
MODULE_AUTHOR("megaraidlinux@lsi.com");
@@ -103,6 +112,7 @@ static int megasas_poll_wait_aen;
static DECLARE_WAIT_QUEUE_HEAD(megasas_poll_wait);
static u32 support_poll_for_event;
static u32 megasas_dbg_lvl;
+static u32 support_device_change;
/* define lock for aen poll */
spinlock_t poll_aen_lock;
@@ -718,6 +728,10 @@ static int
megasas_check_reset_gen2(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
+ if (instance->adprecovery != MEGASAS_HBA_OPERATIONAL) {
+ return 1;
+ }
+
return 0;
}
@@ -930,6 +944,7 @@ megasas_make_sgl_skinny(struct megasas_instance *instance,
mfi_sgl->sge_skinny[i].length = sg_dma_len(os_sgl);
mfi_sgl->sge_skinny[i].phys_addr =
sg_dma_address(os_sgl);
+ mfi_sgl->sge_skinny[i].flag = 0;
}
}
return sge_count;
@@ -1319,7 +1334,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
* @done: Callback entry point
*/
static int
-megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
+megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
{
u32 frame_count;
struct megasas_cmd *cmd;
@@ -1402,6 +1417,8 @@ megasas_queue_command(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *))
return 0;
}
+static DEF_SCSI_QCMD(megasas_queue_command)
+
static struct megasas_instance *megasas_lookup_instance(u16 host_no)
{
int i;
@@ -1557,6 +1574,28 @@ static void megasas_complete_cmd_dpc(unsigned long instance_addr)
}
}
+static void
+megasas_internal_reset_defer_cmds(struct megasas_instance *instance);
+
+static void
+process_fw_state_change_wq(struct work_struct *work);
+
+void megasas_do_ocr(struct megasas_instance *instance)
+{
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS1064R) ||
+ (instance->pdev->device == PCI_DEVICE_ID_DELL_PERC5) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_VERDE_ZCR)) {
+ *instance->consumer = MEGASAS_ADPRESET_INPROG_SIGN;
+ }
+ instance->instancet->disable_intr(instance->reg_set);
+ instance->adprecovery = MEGASAS_ADPRESET_SM_INFAULT;
+ instance->issuepend_done = 0;
+
+ atomic_set(&instance->fw_outstanding, 0);
+ megasas_internal_reset_defer_cmds(instance);
+ process_fw_state_change_wq(&instance->work_init);
+}
+
/**
* megasas_wait_for_outstanding - Wait for all outstanding cmds
* @instance: Adapter soft state
@@ -1574,6 +1613,8 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
unsigned long flags;
struct list_head clist_local;
struct megasas_cmd *reset_cmd;
+ u32 fw_state;
+ u8 kill_adapter_flag;
spin_lock_irqsave(&instance->hba_lock, flags);
adprecovery = instance->adprecovery;
@@ -1659,7 +1700,45 @@ static int megasas_wait_for_outstanding(struct megasas_instance *instance)
msleep(1000);
}
- if (atomic_read(&instance->fw_outstanding)) {
+ i = 0;
+ kill_adapter_flag = 0;
+ do {
+ fw_state = instance->instancet->read_fw_status_reg(
+ instance->reg_set) & MFI_STATE_MASK;
+ if ((fw_state == MFI_STATE_FAULT) &&
+ (instance->disableOnlineCtrlReset == 0)) {
+ if (i == 3) {
+ kill_adapter_flag = 2;
+ break;
+ }
+ megasas_do_ocr(instance);
+ kill_adapter_flag = 1;
+
+ /* wait for 1 secs to let FW finish the pending cmds */
+ msleep(1000);
+ }
+ i++;
+ } while (i <= 3);
+
+ if (atomic_read(&instance->fw_outstanding) &&
+ !kill_adapter_flag) {
+ if (instance->disableOnlineCtrlReset == 0) {
+
+ megasas_do_ocr(instance);
+
+ /* wait for 5 secs to let FW finish the pending cmds */
+ for (i = 0; i < wait_time; i++) {
+ int outstanding =
+ atomic_read(&instance->fw_outstanding);
+ if (!outstanding)
+ return SUCCESS;
+ msleep(1000);
+ }
+ }
+ }
+
+ if (atomic_read(&instance->fw_outstanding) ||
+ (kill_adapter_flag == 2)) {
printk(KERN_NOTICE "megaraid_sas: pending cmds after reset\n");
/*
* Send signal to FW to stop processing any pending cmds.
@@ -2669,6 +2748,7 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
return -ENOMEM;
}
+ memset(cmd->frame, 0, total_sz);
cmd->frame->io.context = cmd->index;
cmd->frame->io.pad_0 = 0;
}
@@ -3585,6 +3665,27 @@ static int megasas_io_attach(struct megasas_instance *instance)
instance->max_fw_cmds - MEGASAS_INT_CMDS;
host->this_id = instance->init_id;
host->sg_tablesize = instance->max_num_sge;
+ /*
+ * Check if the module parameter value for max_sectors can be used
+ */
+ if (max_sectors && max_sectors < instance->max_sectors_per_req)
+ instance->max_sectors_per_req = max_sectors;
+ else {
+ if (max_sectors) {
+ if (((instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS1078GEN2) ||
+ (instance->pdev->device ==
+ PCI_DEVICE_ID_LSI_SAS0079GEN2)) &&
+ (max_sectors <= MEGASAS_MAX_SECTORS)) {
+ instance->max_sectors_per_req = max_sectors;
+ } else {
+ printk(KERN_INFO "megasas: max_sectors should be > 0"
+ "and <= %d (or < 1MB for GEN2 controller)\n",
+ instance->max_sectors_per_req);
+ }
+ }
+ }
+
host->max_sectors = instance->max_sectors_per_req;
host->cmd_per_lun = 128;
host->max_channel = MEGASAS_MAX_CHANNELS - 1;
@@ -4658,6 +4759,15 @@ megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
static DRIVER_ATTR(support_poll_for_event, S_IRUGO,
megasas_sysfs_show_support_poll_for_event, NULL);
+ static ssize_t
+megasas_sysfs_show_support_device_change(struct device_driver *dd, char *buf)
+{
+ return sprintf(buf, "%u\n", support_device_change);
+}
+
+static DRIVER_ATTR(support_device_change, S_IRUGO,
+ megasas_sysfs_show_support_device_change, NULL);
+
static ssize_t
megasas_sysfs_show_dbg_lvl(struct device_driver *dd, char *buf)
{
@@ -4978,6 +5088,7 @@ static int __init megasas_init(void)
MEGASAS_EXT_VERSION);
support_poll_for_event = 2;
+ support_device_change = 1;
memset(&megasas_mgmt_info, 0, sizeof(megasas_mgmt_info));
@@ -5026,8 +5137,17 @@ static int __init megasas_init(void)
if (rval)
goto err_dcf_poll_mode_io;
+ rval = driver_create_file(&megasas_pci_driver.driver,
+ &driver_attr_support_device_change);
+ if (rval)
+ goto err_dcf_support_device_change;
+
return rval;
+err_dcf_support_device_change:
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_poll_mode_io);
+
err_dcf_poll_mode_io:
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl);
@@ -5058,6 +5178,10 @@ static void __exit megasas_exit(void)
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_dbg_lvl);
driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_poll_for_event);
+ driver_remove_file(&megasas_pci_driver.driver,
+ &driver_attr_support_device_change);
+ driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_release_date);
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);