diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_init.c')
-rw-r--r-- | drivers/scsi/pm8001/pm8001_init.c | 285 |
1 files changed, 153 insertions, 132 deletions
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 443a3176c6c0..ed6b7d954dda 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -56,6 +56,18 @@ MODULE_PARM_DESC(link_rate, "Enable link rate.\n" " 4: Link rate 6.0G\n" " 8: Link rate 12.0G\n"); +bool pm8001_use_msix = true; +module_param_named(use_msix, pm8001_use_msix, bool, 0444); +MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true"); + +static bool pm8001_use_tasklet = true; +module_param_named(use_tasklet, pm8001_use_tasklet, bool, 0444); +MODULE_PARM_DESC(zoned, "Use MSIX interrupts. Default: true"); + +static bool pm8001_read_wwn = true; +module_param_named(read_wwn, pm8001_read_wwn, bool, 0444); +MODULE_PARM_DESC(zoned, "Get WWN from the controller. Default: true"); + static struct scsi_transport_template *pm8001_stt; static int pm8001_init_ccb_tag(struct pm8001_hba_info *); @@ -200,8 +212,6 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) kfree(pm8001_ha); } -#ifdef PM8001_USE_TASKLET - /** * pm8001_tasklet() - tasklet for 64 msi-x interrupt handler * @opaque: the passed general host adapter struct @@ -209,16 +219,67 @@ static void pm8001_free(struct pm8001_hba_info *pm8001_ha) */ static void pm8001_tasklet(unsigned long opaque) { - struct pm8001_hba_info *pm8001_ha; - struct isr_param *irq_vector; + struct isr_param *irq_vector = (struct isr_param *)opaque; + struct pm8001_hba_info *pm8001_ha = irq_vector->drv_inst; + + if (WARN_ON_ONCE(!pm8001_ha)) + return; - irq_vector = (struct isr_param *)opaque; - pm8001_ha = irq_vector->drv_inst; - if (unlikely(!pm8001_ha)) - BUG_ON(1); PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id); } -#endif + +static void pm8001_init_tasklet(struct pm8001_hba_info *pm8001_ha) +{ + int i; + + if (!pm8001_use_tasklet) + return; + + /* Tasklet for non msi-x interrupt handler */ + if ((!pm8001_ha->pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) { + tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, + (unsigned long)&(pm8001_ha->irq_vector[0])); + return; + } + for (i = 0; i < PM8001_MAX_MSIX_VEC; i++) + tasklet_init(&pm8001_ha->tasklet[i], pm8001_tasklet, + (unsigned long)&(pm8001_ha->irq_vector[i])); +} + +static void pm8001_kill_tasklet(struct pm8001_hba_info *pm8001_ha) +{ + int i; + + if (!pm8001_use_tasklet) + return; + + /* For non-msix and msix interrupts */ + if ((!pm8001_ha->pdev->msix_cap || !pci_msi_enabled()) || + (pm8001_ha->chip_id == chip_8001)) { + tasklet_kill(&pm8001_ha->tasklet[0]); + return; + } + + for (i = 0; i < PM8001_MAX_MSIX_VEC; i++) + tasklet_kill(&pm8001_ha->tasklet[i]); +} + +static irqreturn_t pm8001_handle_irq(struct pm8001_hba_info *pm8001_ha, + int irq) +{ + if (unlikely(!pm8001_ha)) + return IRQ_NONE; + + if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) + return IRQ_NONE; + + if (!pm8001_use_tasklet) + return PM8001_CHIP_DISP->isr(pm8001_ha, irq); + + tasklet_schedule(&pm8001_ha->tasklet[irq]); + return IRQ_HANDLED; +} /** * pm8001_interrupt_handler_msix - main MSIX interrupt handler. @@ -230,22 +291,10 @@ static void pm8001_tasklet(unsigned long opaque) */ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque) { - struct isr_param *irq_vector; - struct pm8001_hba_info *pm8001_ha; - irqreturn_t ret = IRQ_HANDLED; - irq_vector = (struct isr_param *)opaque; - pm8001_ha = irq_vector->drv_inst; + struct isr_param *irq_vector = (struct isr_param *)opaque; + struct pm8001_hba_info *pm8001_ha = irq_vector->drv_inst; - if (unlikely(!pm8001_ha)) - return IRQ_NONE; - if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) - return IRQ_NONE; -#ifdef PM8001_USE_TASKLET - tasklet_schedule(&pm8001_ha->tasklet[irq_vector->irq_id]); -#else - ret = PM8001_CHIP_DISP->isr(pm8001_ha, irq_vector->irq_id); -#endif - return ret; + return pm8001_handle_irq(pm8001_ha, irq_vector->irq_id); } /** @@ -256,24 +305,14 @@ static irqreturn_t pm8001_interrupt_handler_msix(int irq, void *opaque) static irqreturn_t pm8001_interrupt_handler_intx(int irq, void *dev_id) { - struct pm8001_hba_info *pm8001_ha; - irqreturn_t ret = IRQ_HANDLED; struct sas_ha_struct *sha = dev_id; - pm8001_ha = sha->lldd_ha; - if (unlikely(!pm8001_ha)) - return IRQ_NONE; - if (!PM8001_CHIP_DISP->is_our_interrupt(pm8001_ha)) - return IRQ_NONE; + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; -#ifdef PM8001_USE_TASKLET - tasklet_schedule(&pm8001_ha->tasklet[0]); -#else - ret = PM8001_CHIP_DISP->isr(pm8001_ha, 0); -#endif - return ret; + return pm8001_handle_irq(pm8001_ha, 0); } static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha); +static void pm8001_free_irq(struct pm8001_hba_info *pm8001_ha); /** * pm8001_alloc - initiate our hba structure and 6 DMAs area. @@ -511,7 +550,6 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, { struct pm8001_hba_info *pm8001_ha; struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); - int j; pm8001_ha = sha->lldd_ha; if (!pm8001_ha) @@ -542,17 +580,8 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, else pm8001_ha->iomb_size = IOMB_SIZE_SPC; -#ifdef PM8001_USE_TASKLET - /* Tasklet for non msi-x interrupt handler */ - if ((!pdev->msix_cap || !pci_msi_enabled()) - || (pm8001_ha->chip_id == chip_8001)) - tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, - (unsigned long)&(pm8001_ha->irq_vector[0])); - else - for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) - tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, - (unsigned long)&(pm8001_ha->irq_vector[j])); -#endif + pm8001_init_tasklet(pm8001_ha); + if (pm8001_ioremap(pm8001_ha)) goto failed_pci_alloc; if (!pm8001_alloc(pm8001_ha, ent)) @@ -658,19 +687,30 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost, */ static int pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) { - u8 i, j; - u8 sas_add[8]; -#ifdef PM8001_READ_VPD - /* For new SPC controllers WWN is stored in flash vpd - * For SPC/SPCve controllers WWN is stored in EEPROM - * For Older SPC WWN is stored in NVMD - */ DECLARE_COMPLETION_ONSTACK(completion); struct pm8001_ioctl_payload payload; + unsigned long time_remaining; + u8 sas_add[8]; u16 deviceid; int rc; - unsigned long time_remaining; + u8 i, j; + + if (!pm8001_read_wwn) { + __be64 dev_sas_addr = cpu_to_be64(0x50010c600047f9d0ULL); + for (i = 0; i < pm8001_ha->chip->n_phy; i++) + memcpy(&pm8001_ha->phy[i].dev_sas_addr, &dev_sas_addr, + SAS_ADDR_SIZE); + memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, + SAS_ADDR_SIZE); + return 0; + } + + /* + * For new SPC controllers WWN is stored in flash vpd. For SPC/SPCve + * controllers WWN is stored in EEPROM. And for Older SPC WWN is stored + * in NVMD. + */ if (PM8001_CHIP_DISP->fatal_errors(pm8001_ha)) { pm8001_dbg(pm8001_ha, FAIL, "controller is in fatal error state\n"); return -EIO; @@ -744,16 +784,7 @@ static int pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) pm8001_ha->phy[i].dev_sas_addr); } kfree(payload.func_specific); -#else - for (i = 0; i < pm8001_ha->chip->n_phy; i++) { - pm8001_ha->phy[i].dev_sas_addr = 0x50010c600047f9d0ULL; - pm8001_ha->phy[i].dev_sas_addr = - cpu_to_be64((u64) - (*(u64 *)&pm8001_ha->phy[i].dev_sas_addr)); - } - memcpy(pm8001_ha->sas_addr, &pm8001_ha->phy[0].dev_sas_addr, - SAS_ADDR_SIZE); -#endif + return 0; } @@ -763,13 +794,13 @@ static int pm8001_init_sas_add(struct pm8001_hba_info *pm8001_ha) */ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) { - -#ifdef PM8001_READ_VPD - /*OPTION ROM FLASH read for the SPC cards */ DECLARE_COMPLETION_ONSTACK(completion); struct pm8001_ioctl_payload payload; int rc; + if (!pm8001_read_wwn) + return 0; + pm8001_ha->nvmd_completion = &completion; /* SAS ADDRESS read from flash / EEPROM */ payload.minor_function = 6; @@ -788,7 +819,7 @@ static int pm8001_get_phy_settings_info(struct pm8001_hba_info *pm8001_ha) wait_for_completion(&completion); pm8001_set_phy_profile(pm8001_ha, sizeof(u8), payload.func_specific); kfree(payload.func_specific); -#endif + return 0; } @@ -939,7 +970,6 @@ static int pm8001_configure_phy_settings(struct pm8001_hba_info *pm8001_ha) } } -#ifdef PM8001_USE_MSIX /** * pm8001_setup_msix - enable MSI-X interrupt * @pm8001_ha: our ha struct. @@ -1021,7 +1051,6 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) return rc; } -#endif /** * pm8001_request_irq - register interrupt @@ -1030,10 +1059,9 @@ static u32 pm8001_request_msix(struct pm8001_hba_info *pm8001_ha) static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) { struct pci_dev *pdev = pm8001_ha->pdev; -#ifdef PM8001_USE_MSIX int rc; - if (pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { + if (pm8001_use_msix && pci_find_capability(pdev, PCI_CAP_ID_MSIX)) { rc = pm8001_setup_msix(pm8001_ha); if (rc) { pm8001_dbg(pm8001_ha, FAIL, @@ -1041,14 +1069,22 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) return rc; } - if (pdev->msix_cap && pci_msi_enabled()) - return pm8001_request_msix(pm8001_ha); + if (!pdev->msix_cap || !pci_msi_enabled()) + goto use_intx; + + rc = pm8001_request_msix(pm8001_ha); + if (rc) + return rc; + + pm8001_ha->use_msix = true; + + return 0; } +use_intx: + /* Initialize the INT-X interrupt */ pm8001_dbg(pm8001_ha, INIT, "MSIX not supported!!!\n"); -#endif - - /* initialize the INT-X interrupt */ + pm8001_ha->use_msix = false; pm8001_ha->irq_vector[0].irq_id = 0; pm8001_ha->irq_vector[0].drv_inst = pm8001_ha; @@ -1057,6 +1093,26 @@ static u32 pm8001_request_irq(struct pm8001_hba_info *pm8001_ha) SHOST_TO_SAS_HA(pm8001_ha->shost)); } +static void pm8001_free_irq(struct pm8001_hba_info *pm8001_ha) +{ + struct pci_dev *pdev = pm8001_ha->pdev; + int i; + + if (pm8001_ha->use_msix) { + for (i = 0; i < pm8001_ha->number_of_intr; i++) + synchronize_irq(pci_irq_vector(pdev, i)); + + for (i = 0; i < pm8001_ha->number_of_intr; i++) + free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]); + + pci_free_irq_vectors(pdev); + return; + } + + /* INT-X */ + free_irq(pm8001_ha->irq, pm8001_ha->sas); +} + /** * pm8001_pci_probe - probe supported device * @pdev: pci device which kernel has been prepared for. @@ -1252,33 +1308,17 @@ err_out: static void pm8001_pci_remove(struct pci_dev *pdev) { struct sas_ha_struct *sha = pci_get_drvdata(pdev); - struct pm8001_hba_info *pm8001_ha; - int i, j; - pm8001_ha = sha->lldd_ha; + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + int i; + sas_unregister_ha(sha); sas_remove_host(pm8001_ha->shost); list_del(&pm8001_ha->list); PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); -#ifdef PM8001_USE_MSIX - for (i = 0; i < pm8001_ha->number_of_intr; i++) - synchronize_irq(pci_irq_vector(pdev, i)); - for (i = 0; i < pm8001_ha->number_of_intr; i++) - free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]); - pci_free_irq_vectors(pdev); -#else - free_irq(pm8001_ha->irq, sha); -#endif -#ifdef PM8001_USE_TASKLET - /* For non-msix and msix interrupts */ - if ((!pdev->msix_cap || !pci_msi_enabled()) || - (pm8001_ha->chip_id == chip_8001)) - tasklet_kill(&pm8001_ha->tasklet[0]); - else - for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) - tasklet_kill(&pm8001_ha->tasklet[j]); -#endif + pm8001_free_irq(pm8001_ha); + pm8001_kill_tasklet(pm8001_ha); scsi_host_put(pm8001_ha->shost); for (i = 0; i < pm8001_ha->ccb_count; i++) { @@ -1309,7 +1349,7 @@ static int __maybe_unused pm8001_pci_suspend(struct device *dev) struct pci_dev *pdev = to_pci_dev(dev); struct sas_ha_struct *sha = pci_get_drvdata(pdev); struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; - int i, j; + sas_suspend_ha(sha); flush_workqueue(pm8001_wq); scsi_block_requests(pm8001_ha->shost); @@ -1319,24 +1359,10 @@ static int __maybe_unused pm8001_pci_suspend(struct device *dev) } PM8001_CHIP_DISP->interrupt_disable(pm8001_ha, 0xFF); PM8001_CHIP_DISP->chip_soft_rst(pm8001_ha); -#ifdef PM8001_USE_MSIX - for (i = 0; i < pm8001_ha->number_of_intr; i++) - synchronize_irq(pci_irq_vector(pdev, i)); - for (i = 0; i < pm8001_ha->number_of_intr; i++) - free_irq(pci_irq_vector(pdev, i), &pm8001_ha->irq_vector[i]); - pci_free_irq_vectors(pdev); -#else - free_irq(pm8001_ha->irq, sha); -#endif -#ifdef PM8001_USE_TASKLET - /* For non-msix and msix interrupts */ - if ((!pdev->msix_cap || !pci_msi_enabled()) || - (pm8001_ha->chip_id == chip_8001)) - tasklet_kill(&pm8001_ha->tasklet[0]); - else - for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) - tasklet_kill(&pm8001_ha->tasklet[j]); -#endif + + pm8001_free_irq(pm8001_ha); + pm8001_kill_tasklet(pm8001_ha); + pm8001_info(pm8001_ha, "pdev=0x%p, slot=%s, entering " "suspended state\n", pdev, pm8001_ha->name); @@ -1355,7 +1381,7 @@ static int __maybe_unused pm8001_pci_resume(struct device *dev) struct sas_ha_struct *sha = pci_get_drvdata(pdev); struct pm8001_hba_info *pm8001_ha; int rc; - u8 i = 0, j; + u8 i = 0; DECLARE_COMPLETION_ONSTACK(completion); pm8001_ha = sha->lldd_ha; @@ -1383,17 +1409,9 @@ static int __maybe_unused pm8001_pci_resume(struct device *dev) rc = pm8001_request_irq(pm8001_ha); if (rc) goto err_out_disable; -#ifdef PM8001_USE_TASKLET - /* Tasklet for non msi-x interrupt handler */ - if ((!pdev->msix_cap || !pci_msi_enabled()) || - (pm8001_ha->chip_id == chip_8001)) - tasklet_init(&pm8001_ha->tasklet[0], pm8001_tasklet, - (unsigned long)&(pm8001_ha->irq_vector[0])); - else - for (j = 0; j < PM8001_MAX_MSIX_VEC; j++) - tasklet_init(&pm8001_ha->tasklet[j], pm8001_tasklet, - (unsigned long)&(pm8001_ha->irq_vector[j])); -#endif + + pm8001_init_tasklet(pm8001_ha); + PM8001_CHIP_DISP->interrupt_enable(pm8001_ha, 0); if (pm8001_ha->chip_id != chip_8001) { for (i = 1; i < pm8001_ha->number_of_intr; i++) @@ -1525,6 +1543,9 @@ static int __init pm8001_init(void) { int rc = -ENOMEM; + if (pm8001_use_tasklet && !pm8001_use_msix) + pm8001_use_tasklet = false; + pm8001_wq = alloc_workqueue("pm80xx", 0, 0); if (!pm8001_wq) goto err; |