diff options
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas.c | 130 |
1 files changed, 127 insertions, 3 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas.c b/drivers/scsi/megaraid/megaraid_sas.c index d3c9cdee292..7451bc096a0 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); |