diff options
Diffstat (limited to 'drivers/scsi/megaraid/megaraid_sas_base.c')
-rw-r--r-- | drivers/scsi/megaraid/megaraid_sas_base.c | 278 |
1 files changed, 173 insertions, 105 deletions
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 6e7bb7ca986..5938267e472 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -131,6 +131,20 @@ spinlock_t poll_aen_lock; static void megasas_complete_cmd(struct megasas_instance *instance, struct megasas_cmd *cmd, u8 alt_status); +static irqreturn_t megasas_isr(int irq, void *devp); +static u32 +megasas_init_adapter_mfi(struct megasas_instance *instance); +u32 +megasas_build_and_issue_cmd(struct megasas_instance *instance, + struct scsi_cmnd *scmd); +static void megasas_complete_cmd_dpc(unsigned long instance_addr); + +void +megasas_issue_dcmd(struct megasas_instance *instance, struct megasas_cmd *cmd) +{ + instance->instancet->fire_cmd(instance, + cmd->frame_phys_addr, 0, instance->reg_set); +} /** * megasas_get_cmd - Get a command from the free pool @@ -334,6 +348,11 @@ static struct megasas_instance_template megasas_instance_template_xscale = { .read_fw_status_reg = megasas_read_fw_status_reg_xscale, .adp_reset = megasas_adp_reset_xscale, .check_reset = megasas_check_reset_xscale, + .service_isr = megasas_isr, + .tasklet = megasas_complete_cmd_dpc, + .init_adapter = megasas_init_adapter_mfi, + .build_and_issue_cmd = megasas_build_and_issue_cmd, + .issue_dcmd = megasas_issue_dcmd, }; /** @@ -460,6 +479,11 @@ static struct megasas_instance_template megasas_instance_template_ppc = { .read_fw_status_reg = megasas_read_fw_status_reg_ppc, .adp_reset = megasas_adp_reset_ppc, .check_reset = megasas_check_reset_ppc, + .service_isr = megasas_isr, + .tasklet = megasas_complete_cmd_dpc, + .init_adapter = megasas_init_adapter_mfi, + .build_and_issue_cmd = megasas_build_and_issue_cmd, + .issue_dcmd = megasas_issue_dcmd, }; /** @@ -581,6 +605,11 @@ static struct megasas_instance_template megasas_instance_template_skinny = { .read_fw_status_reg = megasas_read_fw_status_reg_skinny, .adp_reset = megasas_adp_reset_skinny, .check_reset = megasas_check_reset_skinny, + .service_isr = megasas_isr, + .tasklet = megasas_complete_cmd_dpc, + .init_adapter = megasas_init_adapter_mfi, + .build_and_issue_cmd = megasas_build_and_issue_cmd, + .issue_dcmd = megasas_issue_dcmd, }; @@ -755,6 +784,11 @@ static struct megasas_instance_template megasas_instance_template_gen2 = { .read_fw_status_reg = megasas_read_fw_status_reg_gen2, .adp_reset = megasas_adp_reset_gen2, .check_reset = megasas_check_reset_gen2, + .service_isr = megasas_isr, + .tasklet = megasas_complete_cmd_dpc, + .init_adapter = megasas_init_adapter_mfi, + .build_and_issue_cmd = megasas_build_and_issue_cmd, + .issue_dcmd = megasas_issue_dcmd, }; /** @@ -1339,6 +1373,51 @@ megasas_dump_pending_frames(struct megasas_instance *instance) printk(KERN_ERR "megasas[%d]: Dumping Done.\n\n",instance->host->host_no); } +u32 +megasas_build_and_issue_cmd(struct megasas_instance *instance, + struct scsi_cmnd *scmd) +{ + struct megasas_cmd *cmd; + u32 frame_count; + + cmd = megasas_get_cmd(instance); + if (!cmd) + return SCSI_MLQUEUE_HOST_BUSY; + + /* + * Logical drive command + */ + if (megasas_is_ldio(scmd)) + frame_count = megasas_build_ldio(instance, scmd, cmd); + else + frame_count = megasas_build_dcdb(instance, scmd, cmd); + + if (!frame_count) + goto out_return_cmd; + + cmd->scmd = scmd; + scmd->SCp.ptr = (char *)cmd; + + /* + * Issue the command to the FW + */ + atomic_inc(&instance->fw_outstanding); + + instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, + cmd->frame_count-1, instance->reg_set); + /* + * Check if we have pend cmds to be completed + */ + if (poll_mode_io && atomic_read(&instance->fw_outstanding)) + tasklet_schedule(&instance->isr_tasklet); + + return 0; +out_return_cmd: + megasas_return_cmd(instance, cmd); + return 1; +} + + /** * megasas_queue_command - Queue entry point * @scmd: SCSI command to be queued @@ -1347,8 +1426,6 @@ megasas_dump_pending_frames(struct megasas_instance *instance) static int megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd *)) { - u32 frame_count; - struct megasas_cmd *cmd; struct megasas_instance *instance; unsigned long flags; @@ -1387,42 +1464,13 @@ megasas_queue_command_lck(struct scsi_cmnd *scmd, void (*done) (struct scsi_cmnd break; } - cmd = megasas_get_cmd(instance); - if (!cmd) + if (instance->instancet->build_and_issue_cmd(instance, scmd)) { + printk(KERN_ERR "megasas: Err returned from build_and_issue_cmd\n"); return SCSI_MLQUEUE_HOST_BUSY; - - /* - * Logical drive command - */ - if (megasas_is_ldio(scmd)) - frame_count = megasas_build_ldio(instance, scmd, cmd); - else - frame_count = megasas_build_dcdb(instance, scmd, cmd); - - if (!frame_count) - goto out_return_cmd; - - cmd->scmd = scmd; - scmd->SCp.ptr = (char *)cmd; - - /* - * Issue the command to the FW - */ - atomic_inc(&instance->fw_outstanding); - - instance->instancet->fire_cmd(instance, cmd->frame_phys_addr, - cmd->frame_count-1, instance->reg_set); - /* - * Check if we have pend cmds to be completed - */ - if (poll_mode_io && atomic_read(&instance->fw_outstanding)) - tasklet_schedule(&instance->isr_tasklet); - + } return 0; - out_return_cmd: - megasas_return_cmd(instance, cmd); out_done: done(scmd); return 0; @@ -3221,69 +3269,15 @@ megasas_io_completion_timer(unsigned long instance_addr) jiffies + MEGASAS_COMPLETION_TIMER_INTERVAL); } -/** - * megasas_init_mfi - Initializes the FW - * @instance: Adapter soft state - * - * This is the main function for initializing MFI firmware. - */ -static int megasas_init_mfi(struct megasas_instance *instance) +static u32 +megasas_init_adapter_mfi(struct megasas_instance *instance) { + struct megasas_register_set __iomem *reg_set; u32 context_sz; u32 reply_q_sz; - u32 max_sectors_1; - u32 max_sectors_2; - u32 tmp_sectors; - struct megasas_register_set __iomem *reg_set; - struct megasas_ctrl_info *ctrl_info; - unsigned long bar_list; - - /* Find first memory bar */ - bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); - instance->bar = find_first_bit(&bar_list, sizeof(unsigned long)); - instance->base_addr = pci_resource_start(instance->pdev, instance->bar); - if (pci_request_selected_regions(instance->pdev, instance->bar, - "megasas: LSI")) { - printk(KERN_DEBUG "megasas: IO memory region busy!\n"); - return -EBUSY; - } - - instance->reg_set = ioremap_nocache(instance->base_addr, 8192); - - if (!instance->reg_set) { - printk(KERN_DEBUG "megasas: Failed to map IO mem\n"); - goto fail_ioremap; - } reg_set = instance->reg_set; - switch(instance->pdev->device) - { - case PCI_DEVICE_ID_LSI_SAS1078R: - case PCI_DEVICE_ID_LSI_SAS1078DE: - instance->instancet = &megasas_instance_template_ppc; - break; - case PCI_DEVICE_ID_LSI_SAS1078GEN2: - case PCI_DEVICE_ID_LSI_SAS0079GEN2: - instance->instancet = &megasas_instance_template_gen2; - break; - case PCI_DEVICE_ID_LSI_SAS0073SKINNY: - case PCI_DEVICE_ID_LSI_SAS0071SKINNY: - instance->instancet = &megasas_instance_template_skinny; - break; - case PCI_DEVICE_ID_LSI_SAS1064R: - case PCI_DEVICE_ID_DELL_PERC5: - default: - instance->instancet = &megasas_instance_template_xscale; - break; - } - - /* - * We expect the FW state to be READY - */ - if (megasas_transition_to_ready(instance)) - goto fail_ready_state; - /* * Get various operational parameters from status register */ @@ -3337,6 +3331,87 @@ static int megasas_init_mfi(struct megasas_instance *instance) if (instance->fw_support_ieee) instance->flag_ieee = 1; + return 0; + +fail_fw_init: + + pci_free_consistent(instance->pdev, reply_q_sz, + instance->reply_queue, instance->reply_queue_h); +fail_reply_queue: + megasas_free_cmds(instance); + +fail_alloc_cmds: + iounmap(instance->reg_set); + return 1; +} + +/** + * megasas_init_fw - Initializes the FW + * @instance: Adapter soft state + * + * This is the main function for initializing firmware + */ + +static int megasas_init_fw(struct megasas_instance *instance) +{ + u32 max_sectors_1; + u32 max_sectors_2; + u32 tmp_sectors; + struct megasas_register_set __iomem *reg_set; + struct megasas_ctrl_info *ctrl_info; + unsigned long bar_list; + + /* Find first memory bar */ + bar_list = pci_select_bars(instance->pdev, IORESOURCE_MEM); + instance->bar = find_first_bit(&bar_list, sizeof(unsigned long)); + instance->base_addr = pci_resource_start(instance->pdev, instance->bar); + if (pci_request_selected_regions(instance->pdev, instance->bar, + "megasas: LSI")) { + printk(KERN_DEBUG "megasas: IO memory region busy!\n"); + return -EBUSY; + } + + instance->reg_set = ioremap_nocache(instance->base_addr, 8192); + + if (!instance->reg_set) { + printk(KERN_DEBUG "megasas: Failed to map IO mem\n"); + goto fail_ioremap; + } + + reg_set = instance->reg_set; + + switch (instance->pdev->device) { + case PCI_DEVICE_ID_LSI_SAS1078R: + case PCI_DEVICE_ID_LSI_SAS1078DE: + instance->instancet = &megasas_instance_template_ppc; + break; + case PCI_DEVICE_ID_LSI_SAS1078GEN2: + case PCI_DEVICE_ID_LSI_SAS0079GEN2: + instance->instancet = &megasas_instance_template_gen2; + break; + case PCI_DEVICE_ID_LSI_SAS0073SKINNY: + case PCI_DEVICE_ID_LSI_SAS0071SKINNY: + instance->instancet = &megasas_instance_template_skinny; + break; + case PCI_DEVICE_ID_LSI_SAS1064R: + case PCI_DEVICE_ID_DELL_PERC5: + default: + instance->instancet = &megasas_instance_template_xscale; + break; + } + + /* + * We expect the FW state to be READY + */ + if (megasas_transition_to_ready(instance)) + goto fail_ready_state; + + /* Get operational params, sge flags, send init cmd to controller */ + if (instance->instancet->init_adapter(instance)) + return -ENODEV; + + printk(KERN_ERR "megasas: INIT adapter done\n"); + /** for passthrough * the following function will get the PD LIST. */ @@ -3392,15 +3467,7 @@ static int megasas_init_mfi(struct megasas_instance *instance) MEGASAS_COMPLETION_TIMER_INTERVAL); return 0; - fail_fw_init: - - pci_free_consistent(instance->pdev, reply_q_sz, - instance->reply_queue, instance->reply_queue_h); - fail_reply_queue: - megasas_free_cmds(instance); - - fail_alloc_cmds: - fail_ready_state: +fail_ready_state: iounmap(instance->reg_set); fail_ioremap: @@ -3855,7 +3922,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) /* * Initialize MFI Firmware */ - if (megasas_init_mfi(instance)) + if (megasas_init_fw(instance)) goto fail_init_mfi; /* Try to enable MSI-X */ @@ -3870,7 +3937,7 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) * Register IRQ */ if (request_irq(instance->msi_flag ? instance->msixentry.vector : - pdev->irq, megasas_isr, + pdev->irq, instance->instancet->service_isr, IRQF_SHARED, "megasas", instance)) { printk(KERN_DEBUG "megasas: Failed to register IRQ\n"); goto fail_irq; @@ -3920,7 +3987,6 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance->pdev->irq, instance); if (instance->msi_flag) pci_disable_msix(instance->pdev); - megasas_release_mfi(instance); fail_irq: fail_init_mfi: @@ -3930,9 +3996,11 @@ megasas_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) instance->evt_detail, instance->evt_detail_h); - if (instance->producer) + if (instance->producer) { pci_free_consistent(pdev, sizeof(u32), instance->producer, instance->producer_h); + megasas_release_mfi(instance); + } if (instance->consumer) pci_free_consistent(pdev, sizeof(u32), instance->consumer, instance->consumer_h); @@ -4134,7 +4202,7 @@ megasas_resume(struct pci_dev *pdev) * Register IRQ */ if (request_irq(instance->msi_flag ? instance->msixentry.vector : - pdev->irq, megasas_isr, + pdev->irq, instance->instancet->service_isr, IRQF_SHARED, "megasas", instance)) { printk(KERN_ERR "megasas: Failed to register IRQ\n"); goto fail_irq; |