diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2024-01-11 14:24:32 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2024-01-11 14:24:32 -0800 |
commit | 22d29f1112c85c1ad519a8c0403f7f7289cf060c (patch) | |
tree | 42649f46668e27e25afb6c71065f5ae6698a78e4 | |
parent | 4c72e2b8c42e57f65d8fbfb01329e79d2b450653 (diff) | |
parent | 45a2c87f28ad0ee8c286bb6dd5686bc54f5b7160 (diff) |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"Updates to the usual drivers (ufs, mpi3mr, mpt3sas, lpfc, fnic,
hisi_sas, arcmsr, ) plus the usual assorted minor fixes and updates.
This time around there's only a single line update to the core, so
nothing major and barely anything minor"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (135 commits)
scsi: ufs: core: Simplify ufshcd_auto_hibern8_update()
scsi: ufs: core: Rename ufshcd_auto_hibern8_enable() and make it static
scsi: ufs: qcom: Fix ESI vector mask
scsi: ufs: host: Fix kernel-doc warning
scsi: hisi_sas: Correct the number of global debugfs registers
scsi: hisi_sas: Rollback some operations if FLR failed
scsi: hisi_sas: Check before using pointer variables
scsi: hisi_sas: Replace with standard error code return value
scsi: hisi_sas: Set .phy_attached before notifing phyup event HISI_PHYE_PHY_UP_PM
scsi: ufs: core: Add sysfs node for UFS RTC update
scsi: ufs: core: Add UFS RTC support
scsi: ufs: core: Add ufshcd_is_ufs_dev_busy()
scsi: ufs: qcom: Remove unused definitions
scsi: ufs: qcom: Use ufshcd_rmwl() where applicable
scsi: ufs: qcom: Remove support for host controllers older than v2.0
scsi: ufs: qcom: Simplify ufs_qcom_{assert/deassert}_reset
scsi: ufs: qcom: Initialize cycles_in_1us variable in ufs_qcom_set_core_clk_ctrl()
scsi: ufs: qcom: Sort includes alphabetically
scsi: ufs: qcom: Remove unused ufs_qcom_hosts struct array
scsi: ufs: qcom: Use dev_err_probe() to simplify error handling of devm_gpiod_get_optional()
...
97 files changed, 2567 insertions, 1730 deletions
diff --git a/Documentation/ABI/testing/sysfs-driver-ufs b/Documentation/ABI/testing/sysfs-driver-ufs index 0c7efaf62de0..5bf7073b4f75 100644 --- a/Documentation/ABI/testing/sysfs-driver-ufs +++ b/Documentation/ABI/testing/sysfs-driver-ufs @@ -1223,6 +1223,55 @@ Description: This file shows the total latency (in micro seconds) of write The file is read only. +What: /sys/bus/platform/drivers/ufshcd/*/power_info/lane +What: /sys/bus/platform/devices/*.ufs/power_info/lane +Date: September 2023 +Contact: Can Guo <quic_cang@quicinc.com> +Description: This file shows how many lanes are enabled on the UFS link, + i.e., an output 2 means UFS link is operating with 2 lanes. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/mode +What: /sys/bus/platform/devices/*.ufs/power_info/mode +Date: September 2023 +Contact: Can Guo <quic_cang@quicinc.com> +Description: This file shows the PA power mode of UFS. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/rate +What: /sys/bus/platform/devices/*.ufs/power_info/rate +Date: September 2023 +Contact: Can Guo <quic_cang@quicinc.com> +Description: This file shows the speed rate of UFS link. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/gear +What: /sys/bus/platform/devices/*.ufs/power_info/gear +Date: September 2023 +Contact: Can Guo <quic_cang@quicinc.com> +Description: This file shows the gear of UFS link. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/dev_pm +What: /sys/bus/platform/devices/*.ufs/power_info/dev_pm +Date: September 2023 +Contact: Can Guo <quic_cang@quicinc.com> +Description: This file shows the UFS device power mode. + + The file is read only. + +What: /sys/bus/platform/drivers/ufshcd/*/power_info/link_state +What: /sys/bus/platform/devices/*.ufs/power_info/link_state +Date: September 2023 +Contact: Can Guo <quic_cang@quicinc.com> +Description: This file shows the state of UFS link. + + The file is read only. + What: /sys/bus/platform/drivers/ufshcd/*/device_descriptor/wb_presv_us_en What: /sys/bus/platform/devices/*.ufs/device_descriptor/wb_presv_us_en Date: June 2020 @@ -1474,3 +1523,10 @@ Description: Indicates status of Write Booster. The file is read only. +What: /sys/bus/platform/drivers/ufshcd/*/rtc_update_ms +What: /sys/bus/platform/devices/*.ufs/rtc_update_ms +Date: November 2023 +Contact: Bean Huo <beanhuo@micron.com> +Description: + rtc_update_ms indicates how often the host should synchronize or update the + UFS RTC. If set to 0, this will disable UFS RTC periodic update. diff --git a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml index 2cf3d016db42..10c146424baa 100644 --- a/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml +++ b/Documentation/devicetree/bindings/ufs/qcom,ufs.yaml @@ -27,6 +27,7 @@ properties: - qcom,msm8996-ufshc - qcom,msm8998-ufshc - qcom,sa8775p-ufshc + - qcom,sc7280-ufshc - qcom,sc8280xp-ufshc - qcom,sdm845-ufshc - qcom,sm6115-ufshc @@ -118,6 +119,7 @@ allOf: enum: - qcom,msm8998-ufshc - qcom,sa8775p-ufshc + - qcom,sc7280-ufshc - qcom,sc8280xp-ufshc - qcom,sm8250-ufshc - qcom,sm8350-ufshc diff --git a/Documentation/devicetree/bindings/ufs/ufs-common.yaml b/Documentation/devicetree/bindings/ufs/ufs-common.yaml index 985ea8f64de8..31fe7f30ff5b 100644 --- a/Documentation/devicetree/bindings/ufs/ufs-common.yaml +++ b/Documentation/devicetree/bindings/ufs/ufs-common.yaml @@ -87,6 +87,8 @@ properties: description: Specifies max. load that can be drawn from VCCQ2 supply. + msi-parent: true + dependencies: freq-table-hz: [ clocks ] operating-points-v2: [ clocks, clock-names ] diff --git a/MAINTAINERS b/MAINTAINERS index 62a446462ef7..f8efcb72ad4b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -22320,7 +22320,8 @@ S: Maintained F: drivers/ufs/host/ufs-exynos* UNIVERSAL FLASH STORAGE HOST CONTROLLER DRIVER MEDIATEK HOOKS -M: Stanley Chu <stanley.chu@mediatek.com> +M: Peter Wang <peter.wang@mediatek.com> +R: Stanley Jhu <chu.stanley@gmail.com> L: linux-scsi@vger.kernel.org L: linux-mediatek@lists.infradead.org (moderated for non-subscribers) S: Maintained diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c index 4f0d0e55f0d4..d6516ab00437 100644 --- a/drivers/s390/scsi/zfcp_fc.c +++ b/drivers/s390/scsi/zfcp_fc.c @@ -900,8 +900,19 @@ static void zfcp_fc_rspn(struct zfcp_adapter *adapter, zfcp_fc_ct_ns_init(&rspn_req->ct_hdr, FC_NS_RSPN_ID, FC_SYMBOLIC_NAME_SIZE); hton24(rspn_req->rspn.fr_fid.fp_fid, fc_host_port_id(shost)); - len = strlcpy(rspn_req->rspn.fr_name, fc_host_symbolic_name(shost), - FC_SYMBOLIC_NAME_SIZE); + + BUILD_BUG_ON(sizeof(rspn_req->name) != + sizeof(fc_host_symbolic_name(shost))); + BUILD_BUG_ON(sizeof(rspn_req->name) != + type_max(typeof(rspn_req->rspn.fr_name_len)) + 1); + len = strscpy(rspn_req->name, fc_host_symbolic_name(shost), + sizeof(rspn_req->name)); + /* + * It should be impossible for this to truncate (see BUILD_BUG_ON() + * above), but be robust anyway. + */ + if (WARN_ON(len < 0)) + len = sizeof(rspn_req->name) - 1; rspn_req->rspn.fr_name_len = len; sg_init_one(&fc_req->sg_req, rspn_req, sizeof(*rspn_req)); diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c index 55989eaa2d9f..9bdb75dfdcd7 100644 --- a/drivers/scsi/3w-sas.c +++ b/drivers/scsi/3w-sas.c @@ -1326,7 +1326,8 @@ static int twl_reset_sequence(TW_Device_Extension *tw_dev, int soft_reset) } /* Load rest of compatibility struct */ - strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION)); + strscpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, + sizeof(tw_dev->tw_compat_info.driver_version)); tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL; tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH; tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD; diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index c3028726bbe4..378906f77909 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -282,7 +282,7 @@ fail_alloc: return error; } -static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) +static void __exit amiga_a3000_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); struct a3000_hostdata *hdata = shost_priv(instance); @@ -293,11 +293,10 @@ static int __exit amiga_a3000_scsi_remove(struct platform_device *pdev) free_irq(IRQ_AMIGA_PORTS, instance); scsi_host_put(instance); release_mem_region(res->start, resource_size(res)); - return 0; } static struct platform_driver amiga_a3000_scsi_driver = { - .remove = __exit_p(amiga_a3000_scsi_remove), + .remove_new = __exit_p(amiga_a3000_scsi_remove), .driver = { .name = "amiga-a3000-scsi", }, diff --git a/drivers/scsi/a4000t.c b/drivers/scsi/a4000t.c index 5e575afce134..e435fc06a624 100644 --- a/drivers/scsi/a4000t.c +++ b/drivers/scsi/a4000t.c @@ -95,7 +95,7 @@ static int __init amiga_a4000t_scsi_probe(struct platform_device *pdev) return -ENODEV; } -static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) +static void __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *host = platform_get_drvdata(pdev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); @@ -106,11 +106,10 @@ static int __exit amiga_a4000t_scsi_remove(struct platform_device *pdev) kfree(hostdata); free_irq(host->irq, host); release_mem_region(res->start, resource_size(res)); - return 0; } static struct platform_driver amiga_a4000t_scsi_driver = { - .remove = __exit_p(amiga_a4000t_scsi_remove), + .remove_new = __exit_p(amiga_a4000t_scsi_remove), .driver = { .name = "amiga-a4000t-scsi", }, diff --git a/drivers/scsi/aic7xxx/aic7770_osm.c b/drivers/scsi/aic7xxx/aic7770_osm.c index bdd177e3d762..a19cdd87c453 100644 --- a/drivers/scsi/aic7xxx/aic7770_osm.c +++ b/drivers/scsi/aic7xxx/aic7770_osm.c @@ -87,17 +87,17 @@ aic7770_probe(struct device *dev) sprintf(buf, "ahc_eisa:%d", eisaBase >> 12); name = kstrdup(buf, GFP_ATOMIC); if (name == NULL) - return (ENOMEM); + return -ENOMEM; ahc = ahc_alloc(&aic7xxx_driver_template, name); if (ahc == NULL) - return (ENOMEM); + return -ENOMEM; ahc->dev = dev; error = aic7770_config(ahc, aic7770_ident_table + edev->id.driver_data, eisaBase); if (error != 0) { ahc->bsh.ioport = 0; ahc_free(ahc); - return (error); + return error < 0 ? error : -error; } dev_set_drvdata(dev, ahc); diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c index 4ae0a1c4d374..b0c4f2345321 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c @@ -1085,7 +1085,7 @@ ahc_linux_register_host(struct ahc_softc *ahc, struct scsi_host_template *templa template->name = ahc->description; host = scsi_host_alloc(template, sizeof(struct ahc_softc *)); if (host == NULL) - return (ENOMEM); + return -ENOMEM; *((struct ahc_softc **)host->hostdata) = ahc; ahc->platform_data->host = host; diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c index a07e94fac673..198440dc0918 100644 --- a/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c +++ b/drivers/scsi/aic7xxx/aic7xxx_osm_pci.c @@ -241,8 +241,7 @@ ahc_linux_pci_dev_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ahc_linux_pci_inherit_flags(ahc); pci_set_drvdata(pdev, ahc); - ahc_linux_register_host(ahc, &aic7xxx_driver_template); - return (0); + return ahc_linux_register_host(ahc, &aic7xxx_driver_template); } /******************************* PCI Routines *********************************/ diff --git a/drivers/scsi/arcmsr/arcmsr.h b/drivers/scsi/arcmsr/arcmsr.h index ed8d9319862a..12c4148fe16f 100644 --- a/drivers/scsi/arcmsr/arcmsr.h +++ b/drivers/scsi/arcmsr/arcmsr.h @@ -50,7 +50,7 @@ struct device_attribute; #define ARCMSR_MAX_OUTSTANDING_CMD 1024 #define ARCMSR_DEFAULT_OUTSTANDING_CMD 128 #define ARCMSR_MIN_OUTSTANDING_CMD 32 -#define ARCMSR_DRIVER_VERSION "v1.50.00.13-20230206" +#define ARCMSR_DRIVER_VERSION "v1.51.00.14-20230915" #define ARCMSR_SCSI_INITIATOR_ID 255 #define ARCMSR_MAX_XFER_SECTORS 512 #define ARCMSR_MAX_XFER_SECTORS_B 4096 @@ -78,9 +78,13 @@ struct device_attribute; #ifndef PCI_DEVICE_ID_ARECA_1203 #define PCI_DEVICE_ID_ARECA_1203 0x1203 #endif +#ifndef PCI_DEVICE_ID_ARECA_1883 +#define PCI_DEVICE_ID_ARECA_1883 0x1883 +#endif #ifndef PCI_DEVICE_ID_ARECA_1884 #define PCI_DEVICE_ID_ARECA_1884 0x1884 #endif +#define PCI_DEVICE_ID_ARECA_1886_0 0x1886 #define PCI_DEVICE_ID_ARECA_1886 0x188A #define ARCMSR_HOURS (1000 * 60 * 60 * 4) #define ARCMSR_MINUTES (1000 * 60 * 60) @@ -818,6 +822,23 @@ typedef struct deliver_completeQ { uint16_t cmdLMID; // reserved (0) uint16_t cmdFlag2; // reserved (0) } DeliverQ, CompletionQ, *pDeliver_Q, *pCompletion_Q; + +#define ARCMSR_XOR_SEG_SIZE (1024 * 1024) +struct HostRamBuf { + uint32_t hrbSignature; // must be "HRBS" + uint32_t hrbSize; // total sg size, be multiples of MB + uint32_t hrbRes[2]; // reserved, must be set to 0 +}; +struct Xor_sg { + dma_addr_t xorPhys; + uint64_t xorBufLen; +}; +struct XorHandle { + dma_addr_t xorPhys; + uint64_t xorBufLen; + void *xorVirt; +}; + /* ******************************************************************************* ** Adapter Control Block @@ -929,6 +950,7 @@ struct AdapterControlBlock char firm_model[12]; char firm_version[20]; char device_map[20]; /*21,84-99*/ + uint32_t firm_PicStatus; struct work_struct arcmsr_do_message_isr_bh; struct timer_list eternal_timer; unsigned short fw_flag; @@ -937,6 +959,7 @@ struct AdapterControlBlock #define FW_DEADLOCK 0x0010 uint32_t maxOutstanding; int vector_count; + int xor_mega; uint32_t maxFreeCCB; struct timer_list refresh_timer; uint32_t doneq_index; @@ -946,6 +969,10 @@ struct AdapterControlBlock uint32_t completionQ_entry; pCompletion_Q pCompletionQ; uint32_t completeQ_size; + void *xorVirt; + dma_addr_t xorPhys; + unsigned int init2cfg_size; + unsigned int xorVirtOffset; };/* HW_DEVICE_EXTENSION */ /* ******************************************************************************* diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index a66221c3b72f..ad227e6cb10e 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -214,8 +214,12 @@ static struct pci_device_id arcmsr_device_id_table[] = { .driver_data = ACB_ADAPTER_TYPE_A}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1880), .driver_data = ACB_ADAPTER_TYPE_C}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1883), + .driver_data = ACB_ADAPTER_TYPE_C}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1884), .driver_data = ACB_ADAPTER_TYPE_E}, + {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1886_0), + .driver_data = ACB_ADAPTER_TYPE_F}, {PCI_DEVICE(PCI_VENDOR_ID_ARECA, PCI_DEVICE_ID_ARECA_1886), .driver_data = ACB_ADAPTER_TYPE_F}, {0, 0}, /* Terminating entry */ @@ -747,6 +751,57 @@ static bool arcmsr_alloc_io_queue(struct AdapterControlBlock *acb) return rtn; } +static int arcmsr_alloc_xor_buffer(struct AdapterControlBlock *acb) +{ + int rc = 0; + struct pci_dev *pdev = acb->pdev; + void *dma_coherent; + dma_addr_t dma_coherent_handle; + int i, xor_ram; + struct Xor_sg *pXorPhys; + void **pXorVirt; + struct HostRamBuf *pRamBuf; + + // allocate 1 MB * N physically continuous memory for XOR engine. + xor_ram = (acb->firm_PicStatus >> 24) & 0x0f; + acb->xor_mega = (xor_ram - 1) * 32 + 128 + 3; + acb->init2cfg_size = sizeof(struct HostRamBuf) + + (sizeof(struct XorHandle) * acb->xor_mega); + dma_coherent = dma_alloc_coherent(&pdev->dev, acb->init2cfg_size, + &dma_coherent_handle, GFP_KERNEL); + acb->xorVirt = dma_coherent; + acb->xorPhys = dma_coherent_handle; + pXorPhys = (struct Xor_sg *)((unsigned long)dma_coherent + + sizeof(struct HostRamBuf)); + acb->xorVirtOffset = sizeof(struct HostRamBuf) + + (sizeof(struct Xor_sg) * acb->xor_mega); + pXorVirt = (void **)((unsigned long)dma_coherent + + (unsigned long)acb->xorVirtOffset); + for (i = 0; i < acb->xor_mega; i++) { + dma_coherent = dma_alloc_coherent(&pdev->dev, + ARCMSR_XOR_SEG_SIZE, + &dma_coherent_handle, GFP_KERNEL); + if (dma_coherent) { + pXorPhys->xorPhys = dma_coherent_handle; + pXorPhys->xorBufLen = ARCMSR_XOR_SEG_SIZE; + *pXorVirt = dma_coherent; + pXorPhys++; + pXorVirt++; + } else { + pr_info("arcmsr%d: alloc max XOR buffer = 0x%x MB\n", + acb->host->host_no, i); + rc = -ENOMEM; + break; + } + } + pRamBuf = (struct HostRamBuf *)acb->xorVirt; + pRamBuf->hrbSignature = 0x53425248; //HRBS + pRamBuf->hrbSize = i * ARCMSR_XOR_SEG_SIZE; + pRamBuf->hrbRes[0] = 0; + pRamBuf->hrbRes[1] = 0; + return rc; +} + static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) { struct pci_dev *pdev = acb->pdev; @@ -836,7 +891,11 @@ static int arcmsr_alloc_ccb_pool(struct AdapterControlBlock *acb) acb->completionQ_entry = acb->ioqueue_size / sizeof(struct deliver_completeQ); acb->doneq_index = 0; break; - } + } + if ((acb->firm_PicStatus >> 24) & 0x0f) { + if (arcmsr_alloc_xor_buffer(acb)) + return -ENOMEM; + } return 0; } @@ -2022,6 +2081,29 @@ static void arcmsr_stop_adapter_bgrb(struct AdapterControlBlock *acb) static void arcmsr_free_ccb_pool(struct AdapterControlBlock *acb) { + if (acb->xor_mega) { + struct Xor_sg *pXorPhys; + void **pXorVirt; + int i; + + pXorPhys = (struct Xor_sg *)(acb->xorVirt + + sizeof(struct HostRamBuf)); + pXorVirt = (void **)((unsigned long)acb->xorVirt + + (unsigned long)acb->xorVirtOffset); + for (i = 0; i < acb->xor_mega; i++) { + if (pXorPhys->xorPhys) { + dma_free_coherent(&acb->pdev->dev, + ARCMSR_XOR_SEG_SIZE, + *pXorVirt, pXorPhys->xorPhys); + pXorPhys->xorPhys = 0; + *pXorVirt = NULL; + } + pXorPhys++; + pXorVirt++; + } + dma_free_coherent(&acb->pdev->dev, acb->init2cfg_size, + acb->xorVirt, acb->xorPhys); + } dma_free_coherent(&acb->pdev->dev, acb->uncache_size, acb->dma_coherent, acb->dma_coherent_handle); } @@ -3309,6 +3391,10 @@ static void arcmsr_get_adapter_config(struct AdapterControlBlock *pACB, uint32_t pACB->firm_sdram_size = readl(&rwbuffer[3]); pACB->firm_hd_channels = readl(&rwbuffer[4]); pACB->firm_cfg_version = readl(&rwbuffer[25]); + if (pACB->adapter_type == ACB_ADAPTER_TYPE_F) + pACB->firm_PicStatus = readl(&rwbuffer[30]); + else + pACB->firm_PicStatus = 0; pr_notice("Areca RAID Controller%d: Model %s, F/W %s\n", pACB->host->host_no, pACB->firm_model, @@ -4096,6 +4182,12 @@ static int arcmsr_iop_confirm(struct AdapterControlBlock *acb) acb->msgcode_rwbuffer[5] = lower_32_bits(acb->dma_coherent_handle2); acb->msgcode_rwbuffer[6] = upper_32_bits(acb->dma_coherent_handle2); acb->msgcode_rwbuffer[7] = acb->completeQ_size; + if (acb->xor_mega) { + acb->msgcode_rwbuffer[8] = 0x455AA; //Linux init 2 + acb->msgcode_rwbuffer[9] = 0; + acb->msgcode_rwbuffer[10] = lower_32_bits(acb->xorPhys); + acb->msgcode_rwbuffer[11] = upper_32_bits(acb->xorPhys); + } writel(ARCMSR_INBOUND_MESG0_SET_CONFIG, ®->inbound_msgaddr0); acb->out_doorbell ^= ARCMSR_HBEMU_DRV2IOP_MESSAGE_CMD_DONE; writel(acb->out_doorbell, ®->iobound_doorbell); @@ -4706,9 +4798,11 @@ static const char *arcmsr_info(struct Scsi_Host *host) case PCI_DEVICE_ID_ARECA_1680: case PCI_DEVICE_ID_ARECA_1681: case PCI_DEVICE_ID_ARECA_1880: + case PCI_DEVICE_ID_ARECA_1883: case PCI_DEVICE_ID_ARECA_1884: type = "SAS/SATA"; break; + case PCI_DEVICE_ID_ARECA_1886_0: case PCI_DEVICE_ID_ARECA_1886: type = "NVMe/SAS/SATA"; break; diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index d401cf27113a..d99e70914817 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -865,7 +865,7 @@ fail_alloc: return error; } -static int __exit atari_scsi_remove(struct platform_device *pdev) +static void __exit atari_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); @@ -876,11 +876,10 @@ static int __exit atari_scsi_remove(struct platform_device *pdev) scsi_host_put(instance); if (atari_dma_buffer) atari_stram_free(atari_dma_buffer); - return 0; } static struct platform_driver atari_scsi_driver = { - .remove = __exit_p(atari_scsi_remove), + .remove_new = __exit_p(atari_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/bfa/bfad_bsg.c b/drivers/scsi/bfa/bfad_bsg.c index 520f9152f3bf..d4ceca2d435e 100644 --- a/drivers/scsi/bfa/bfad_bsg.c +++ b/drivers/scsi/bfa/bfad_bsg.c @@ -2550,7 +2550,7 @@ out: static void bfad_reset_sdev_bflags(struct bfad_im_port_s *im_port, int lunmask_cfg) { - const u32 scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; + const blist_flags_t scan_flags = BLIST_NOREPORTLUN | BLIST_SPARSELUN; struct bfad_itnim_s *itnim; struct scsi_device *sdev; unsigned long flags; diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c index 451a58e0fd96..1078c20c5ef6 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c +++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c @@ -1734,32 +1734,32 @@ static int bnx2fc_bind_pcidev(struct bnx2fc_hba *hba) switch (pdev->device) { case PCI_DEVICE_ID_NX2_57710: - strncpy(hba->chip_num, "BCM57710", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57710", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57711: - strncpy(hba->chip_num, "BCM57711", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57711", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57712: case PCI_DEVICE_ID_NX2_57712_MF: case PCI_DEVICE_ID_NX2_57712_VF: - strncpy(hba->chip_num, "BCM57712", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57712", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57800: case PCI_DEVICE_ID_NX2_57800_MF: case PCI_DEVICE_ID_NX2_57800_VF: - strncpy(hba->chip_num, "BCM57800", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57800", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57810: case PCI_DEVICE_ID_NX2_57810_MF: case PCI_DEVICE_ID_NX2_57810_VF: - strncpy(hba->chip_num, "BCM57810", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57810", sizeof(hba->chip_num)); break; case PCI_DEVICE_ID_NX2_57840: case PCI_DEVICE_ID_NX2_57840_MF: case PCI_DEVICE_ID_NX2_57840_VF: case PCI_DEVICE_ID_NX2_57840_2_20: case PCI_DEVICE_ID_NX2_57840_4_10: - strncpy(hba->chip_num, "BCM57840", BCM_CHIP_LEN); + strscpy(hba->chip_num, "BCM57840", sizeof(hba->chip_num)); break; default: pr_err(PFX "Unknown device id 0x%x\n", pdev->device); @@ -1797,7 +1797,7 @@ static int bnx2fc_ulp_get_stats(void *handle) if (!stats_addr) return -EINVAL; - strncpy(stats_addr->version, BNX2FC_VERSION, + strscpy(stats_addr->version, BNX2FC_VERSION, sizeof(stats_addr->version)); stats_addr->txq_size = BNX2FC_SQ_WQES_MAX; stats_addr->rxq_size = BNX2FC_CQ_WQES_MAX; diff --git a/drivers/scsi/bvme6000_scsi.c b/drivers/scsi/bvme6000_scsi.c index 8d72b25535c5..f893e9779e9d 100644 --- a/drivers/scsi/bvme6000_scsi.c +++ b/drivers/scsi/bvme6000_scsi.c @@ -89,7 +89,7 @@ bvme6000_probe(struct platform_device *dev) return -ENODEV; } -static int +static void bvme6000_device_remove(struct platform_device *dev) { struct Scsi_Host *host = platform_get_drvdata(dev); @@ -99,8 +99,6 @@ bvme6000_device_remove(struct platform_device *dev) NCR_700_release(host); kfree(hostdata); free_irq(host->irq, host); - - return 0; } static struct platform_driver bvme6000_scsi_driver = { @@ -108,7 +106,7 @@ static struct platform_driver bvme6000_scsi_driver = { .name = "bvme6000-scsi", }, .probe = bvme6000_probe, - .remove = bvme6000_device_remove, + .remove_new = bvme6000_device_remove, }; static int __init bvme6000_scsi_init(void) diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c index cb0a399be1cc..2b864061e073 100644 --- a/drivers/scsi/ch.c +++ b/drivers/scsi/ch.c @@ -659,19 +659,23 @@ static long ch_ioctl(struct file *file, memset(&vparams,0,sizeof(vparams)); if (ch->counts[CHET_V1]) { vparams.cvp_n1 = ch->counts[CHET_V1]; - strncpy(vparams.cvp_label1,vendor_labels[0],16); + strscpy(vparams.cvp_label1, vendor_labels[0], + sizeof(vparams.cvp_label1)); } if (ch->counts[CHET_V2]) { vparams.cvp_n2 = ch->counts[CHET_V2]; - strncpy(vparams.cvp_label2,vendor_labels[1],16); + strscpy(vparams.cvp_label2, vendor_labels[1], + sizeof(vparams.cvp_label2)); } if (ch->counts[CHET_V3]) { vparams.cvp_n3 = ch->counts[CHET_V3]; - strncpy(vparams.cvp_label3,vendor_labels[2],16); + strscpy(vparams.cvp_label3, vendor_labels[2], + sizeof(vparams.cvp_label3)); } if (ch->counts[CHET_V4]) { vparams.cvp_n4 = ch->counts[CHET_V4]; - strncpy(vparams.cvp_label4,vendor_labels[3],16); + strscpy(vparams.cvp_label4, vendor_labels[3], + sizeof(vparams.cvp_label4)); } if (copy_to_user(argp, &vparams, sizeof(vparams))) return -EFAULT; diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index 0c32faefad7c..d649b7a2a879 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -521,7 +521,8 @@ static struct csio_hw *csio_hw_alloc(struct pci_dev *pdev) goto err; hw->pdev = pdev; - strncpy(hw->drv_version, CSIO_DRV_VERSION, 32); + strscpy(hw->drv_version, CSIO_DRV_VERSION, + sizeof(hw->drv_version)); /* memory pool/DMA pool allocation */ if (csio_resource_alloc(hw)) diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c index c8e86f8a631e..d108a86e196e 100644 --- a/drivers/scsi/dc395x.c +++ b/drivers/scsi/dc395x.c @@ -1366,7 +1366,7 @@ static u8 start_scsi(struct AdapterCtlBlk* acb, struct DeviceCtlBlk* dcb, "command while another command (0x%p) is active.", srb->cmd, acb->active_dcb->active_srb ? - acb->active_dcb->active_srb->cmd : 0); + acb->active_dcb->active_srb->cmd : NULL); return 1; } if (DC395x_read16(acb, TRM_S1040_SCSI_STATUS) & SCSIINTERRUPT) { diff --git a/drivers/scsi/elx/libefc/efc_node.h b/drivers/scsi/elx/libefc/efc_node.h index e9c600ac45d5..e57579988ba4 100644 --- a/drivers/scsi/elx/libefc/efc_node.h +++ b/drivers/scsi/elx/libefc/efc_node.h @@ -26,13 +26,13 @@ efc_node_evt_set(struct efc_sm_ctx *ctx, enum efc_sm_event evt, struct efc_node *node = ctx->app; if (evt == EFC_EVT_ENTER) { - strncpy(node->current_state_name, handler, - sizeof(node->current_state_name)); + strscpy_pad(node->current_state_name, handler, + sizeof(node->current_state_name)); } else if (evt == EFC_EVT_EXIT) { - strncpy(node->prev_state_name, node->current_state_name, - sizeof(node->prev_state_name)); - strncpy(node->current_state_name, "invalid", - sizeof(node->current_state_name)); + memcpy(node->prev_state_name, node->current_state_name, + sizeof(node->prev_state_name)); + strscpy_pad(node->current_state_name, "invalid", + sizeof(node->current_state_name)); } node->prev_evt = node->current_evt; node->current_evt = evt; diff --git a/drivers/scsi/fcoe/fcoe_sysfs.c b/drivers/scsi/fcoe/fcoe_sysfs.c index e17957f8085c..408a806bf4c2 100644 --- a/drivers/scsi/fcoe/fcoe_sysfs.c +++ b/drivers/scsi/fcoe/fcoe_sysfs.c @@ -10,6 +10,7 @@ #include <linux/kernel.h> #include <linux/etherdevice.h> #include <linux/ctype.h> +#include <linux/string.h> #include <scsi/fcoe_sysfs.h> #include <scsi/libfcoe.h> @@ -214,25 +215,13 @@ static const char *get_fcoe_##title##_name(enum table_type table_key) \ return table[table_key]; \ } -static char *fip_conn_type_names[] = { +static const char * const fip_conn_type_names[] = { [ FIP_CONN_TYPE_UNKNOWN ] = "Unknown", [ FIP_CONN_TYPE_FABRIC ] = "Fabric", [ FIP_CONN_TYPE_VN2VN ] = "VN2VN", }; fcoe_enum_name_search(ctlr_mode, fip_conn_type, fip_conn_type_names) -static enum fip_conn_type fcoe_parse_mode(const char *buf) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(fip_conn_type_names); i++) { - if (strcasecmp(buf, fip_conn_type_names[i]) == 0) - return i; - } - - return FIP_CONN_TYPE_UNKNOWN; -} - static char *fcf_state_names[] = { [ FCOE_FCF_STATE_UNKNOWN ] = "Unknown", [ FCOE_FCF_STATE_DISCONNECTED ] = "Disconnected", @@ -274,17 +263,10 @@ static ssize_t store_ctlr_mode(struct device *dev, const char *buf, size_t count) { struct fcoe_ctlr_device *ctlr = dev_to_ctlr(dev); - char mode[FCOE_MAX_MODENAME_LEN + 1]; if (count > FCOE_MAX_MODENAME_LEN) return -EINVAL; - strncpy(mode, buf, count); - - if (mode[count - 1] == '\n') - mode[count - 1] = '\0'; - else - mode[count] = '\0'; switch (ctlr->enabled) { case FCOE_CTLR_ENABLED: @@ -297,8 +279,8 @@ static ssize_t store_ctlr_mode(struct device *dev, return -ENOTSUPP; } - ctlr->mode = fcoe_parse_mode(mode); - if (ctlr->mode == FIP_CONN_TYPE_UNKNOWN) { + ctlr->mode = sysfs_match_string(fip_conn_type_names, buf); + if (ctlr->mode < 0 || ctlr->mode == FIP_CONN_TYPE_UNKNOWN) { LIBFCOE_SYSFS_DBG(ctlr, "Unknown mode %s provided.\n", buf); return -EINVAL; diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h index 22cef283b2b9..2074937c05bc 100644 --- a/drivers/scsi/fnic/fnic.h +++ b/drivers/scsi/fnic/fnic.h @@ -27,7 +27,7 @@ #define DRV_NAME "fnic" #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" -#define DRV_VERSION "1.6.0.57" +#define DRV_VERSION "1.7.0.0" #define PFX DRV_NAME ": " #define DFX DRV_NAME "%d: " @@ -36,7 +36,6 @@ #define FNIC_MIN_IO_REQ 256 /* Min IO throttle count */ #define FNIC_MAX_IO_REQ 1024 /* scsi_cmnd tag map entries */ #define FNIC_DFLT_IO_REQ 256 /* Default scsi_cmnd tag map entries */ -#define FNIC_IO_LOCKS 64 /* IO locks: power of 2 */ #define FNIC_DFLT_QUEUE_DEPTH 256 #define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */ @@ -109,7 +108,7 @@ static inline u64 fnic_flags_and_state(struct scsi_cmnd *cmd) #define FNIC_ABT_TERM_DELAY_TIMEOUT 500 /* mSec */ #define FNIC_MAX_FCP_TARGET 256 - +#define FNIC_PCI_OFFSET 2 /** * state_flags to identify host state along along with fnic's state **/ @@ -144,31 +143,48 @@ do { \ } while (0); \ } while (0) -#define FNIC_MAIN_DBG(kern_level, host, fmt, args...) \ +#define FNIC_MAIN_DBG(kern_level, host, fnic_num, fmt, args...) \ FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) + shost_printk(kern_level, host, \ + "fnic<%d>: %s: %d: " fmt, fnic_num,\ + __func__, __LINE__, ##args);) -#define FNIC_FCS_DBG(kern_level, host, fmt, args...) \ +#define FNIC_FCS_DBG(kern_level, host, fnic_num, fmt, args...) \ FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) + shost_printk(kern_level, host, \ + "fnic<%d>: %s: %d: " fmt, fnic_num,\ + __func__, __LINE__, ##args);) -#define FNIC_SCSI_DBG(kern_level, host, fmt, args...) \ +#define FNIC_SCSI_DBG(kern_level, host, fnic_num, fmt, args...) \ FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) + shost_printk(kern_level, host, \ + "fnic<%d>: %s: %d: " fmt, fnic_num,\ + __func__, __LINE__, ##args);) -#define FNIC_ISR_DBG(kern_level, host, fmt, args...) \ +#define FNIC_ISR_DBG(kern_level, host, fnic_num, fmt, args...) \ FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \ - shost_printk(kern_level, host, fmt, ##args);) + shost_printk(kern_level, host, \ + "fnic<%d>: %s: %d: " fmt, fnic_num,\ + __func__, __LINE__, ##args);) #define FNIC_MAIN_NOTE(kern_level, host, fmt, args...) \ shost_printk(kern_level, host, fmt, ##args) +#define FNIC_WQ_COPY_MAX 64 +#define FNIC_WQ_MAX 1 +#define FNIC_RQ_MAX 1 +#define FNIC_CQ_MAX (FNIC_WQ_COPY_MAX + FNIC_WQ_MAX + FNIC_RQ_MAX) +#define FNIC_DFLT_IO_COMPLETIONS 256 + +#define FNIC_MQ_CQ_INDEX 2 + extern const char *fnic_state_str[]; enum fnic_intx_intr_index { FNIC_INTX_WQ_RQ_COPYWQ, - FNIC_INTX_ERR, + FNIC_INTX_DUMMY, FNIC_INTX_NOTIFY, + FNIC_INTX_ERR, FNIC_INTX_INTR_MAX, }; @@ -176,7 +192,7 @@ enum fnic_msix_intr_index { FNIC_MSIX_RQ, FNIC_MSIX_WQ, FNIC_MSIX_WQ_COPY, - FNIC_MSIX_ERR_NOTIFY, + FNIC_MSIX_ERR_NOTIFY = FNIC_MSIX_WQ_COPY + FNIC_WQ_COPY_MAX, FNIC_MSIX_INTR_MAX, }; @@ -185,6 +201,7 @@ struct fnic_msix_entry { char devname[IFNAMSIZ + 11]; irqreturn_t (*isr)(int, void *); void *devid; + int irq_num; }; enum fnic_state { @@ -194,12 +211,6 @@ enum fnic_state { FNIC_IN_ETH_TRANS_FC_MODE, }; -#define FNIC_WQ_COPY_MAX 1 -#define FNIC_WQ_MAX 1 -#define FNIC_RQ_MAX 1 -#define FNIC_CQ_MAX (FNIC_WQ_COPY_MAX + FNIC_WQ_MAX + FNIC_RQ_MAX) -#define FNIC_DFLT_IO_COMPLETIONS 256 - struct mempool; enum fnic_evt { @@ -214,8 +225,16 @@ struct fnic_event { enum fnic_evt event; }; +struct fnic_cpy_wq { + unsigned long hw_lock_flags; + u16 active_ioreq_count; + u16 ioreq_table_size; + ____cacheline_aligned struct fnic_io_req **io_req_table; +}; + /* Per-instance private data structure */ struct fnic { + int fnic_num; struct fc_lport *lport; struct fcoe_ctlr ctlr; /* FIP FCoE controller structure */ struct vnic_dev_bar bar0; @@ -282,8 +301,8 @@ struct fnic { struct fnic_host_tag *tags; mempool_t *io_req_pool; mempool_t *io_sgl_pool[FNIC_SGL_NUM_CACHES]; - spinlock_t io_req_lock[FNIC_IO_LOCKS]; /* locks for scsi cmnds */ + unsigned int copy_wq_base; struct work_struct link_work; struct work_struct frame_work; struct sk_buff_head frame_queue; @@ -302,7 +321,9 @@ struct fnic { /*** FIP related data members -- end ***/ /* copy work queue cache line section */ - ____cacheline_aligned struct vnic_wq_copy wq_copy[FNIC_WQ_COPY_MAX]; + ____cacheline_aligned struct vnic_wq_copy hw_copy_wq[FNIC_WQ_COPY_MAX]; + ____cacheline_aligned struct fnic_cpy_wq sw_copy_wq[FNIC_WQ_COPY_MAX]; + /* completion queue cache line section */ ____cacheline_aligned struct vnic_cq cq[FNIC_CQ_MAX]; @@ -330,6 +351,7 @@ extern const struct attribute_group *fnic_host_groups[]; void fnic_clear_intr_mode(struct fnic *fnic); int fnic_set_intr_mode(struct fnic *fnic); +int fnic_set_intr_mode_msix(struct fnic *fnic); void fnic_free_intr(struct fnic *fnic); int fnic_request_intr(struct fnic *fnic); @@ -356,7 +378,7 @@ void fnic_scsi_cleanup(struct fc_lport *); void fnic_scsi_abort_io(struct fc_lport *); void fnic_empty_scsi_cleanup(struct fc_lport *); void fnic_exch_mgr_reset(struct fc_lport *, u32, u32); -int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int); +int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index); int fnic_wq_cmpl_handler(struct fnic *fnic, int); int fnic_flogi_reg_handler(struct fnic *fnic, u32); void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, @@ -364,7 +386,7 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, int fnic_fw_reset_handler(struct fnic *fnic); void fnic_terminate_rport_io(struct fc_rport *); const char *fnic_state_to_str(unsigned int state); - +void fnic_mq_map_queues_cpus(struct Scsi_Host *host); void fnic_log_q_error(struct fnic *fnic); void fnic_handle_link_event(struct fnic *fnic); diff --git a/drivers/scsi/fnic/fnic_debugfs.c b/drivers/scsi/fnic/fnic_debugfs.c index c4d9ed0d7d75..2619a2d4f5f1 100644 --- a/drivers/scsi/fnic/fnic_debugfs.c +++ b/drivers/scsi/fnic/fnic_debugfs.c @@ -52,9 +52,10 @@ int fnic_debugfs_init(void) fc_trc_flag->fnic_trace = 2; fc_trc_flag->fc_trace = 3; fc_trc_flag->fc_clear = 4; + return 0; } - return 0; + return -ENOMEM; } /* diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c index 55632c67a8f2..5e312a55cc7d 100644 --- a/drivers/scsi/fnic/fnic_fcs.c +++ b/drivers/scsi/fnic/fnic_fcs.c @@ -63,8 +63,8 @@ void fnic_handle_link(struct work_struct *work) atomic64_set(&fnic->fnic_stats.misc_stats.current_port_speed, new_port_speed); if (old_port_speed != new_port_speed) - FNIC_MAIN_DBG(KERN_INFO, fnic->lport->host, - "Current vnic speed set to : %llu\n", + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Current vnic speed set to: %llu\n", new_port_speed); switch (vnic_dev_port_speed(fnic->vdev)) { @@ -102,6 +102,8 @@ void fnic_handle_link(struct work_struct *work) fnic_fc_trace_set_data(fnic->lport->host->host_no, FNIC_FC_LE, "Link Status: DOWN->DOWN", strlen("Link Status: DOWN->DOWN")); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "down->down\n"); } else { if (old_link_down_cnt != fnic->link_down_cnt) { /* UP -> DOWN -> UP */ @@ -113,7 +115,7 @@ void fnic_handle_link(struct work_struct *work) "Link Status:UP_DOWN_UP", strlen("Link_Status:UP_DOWN_UP") ); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "link down\n"); fcoe_ctlr_link_down(&fnic->ctlr); if (fnic->config.flags & VFCF_FIP_CAPABLE) { @@ -128,8 +130,8 @@ void fnic_handle_link(struct work_struct *work) fnic_fcoe_send_vlan_req(fnic); return; } - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "link up\n"); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "up->down->up: Link up\n"); fcoe_ctlr_link_up(&fnic->ctlr); } else { /* UP -> UP */ @@ -138,6 +140,8 @@ void fnic_handle_link(struct work_struct *work) fnic->lport->host->host_no, FNIC_FC_LE, "Link Status: UP_UP", strlen("Link Status: UP_UP")); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "up->up\n"); } } } else if (fnic->link_status) { @@ -153,7 +157,8 @@ void fnic_handle_link(struct work_struct *work) return; } - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link up\n"); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "down->up: Link up\n"); fnic_fc_trace_set_data(fnic->lport->host->host_no, FNIC_FC_LE, "Link Status: DOWN_UP", strlen("Link Status: DOWN_UP")); fcoe_ctlr_link_up(&fnic->ctlr); @@ -161,13 +166,14 @@ void fnic_handle_link(struct work_struct *work) /* UP -> DOWN */ fnic->lport->host_stats.link_failure_count++; spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link down\n"); + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "up->down: Link down\n"); fnic_fc_trace_set_data( fnic->lport->host->host_no, FNIC_FC_LE, "Link Status: UP_DOWN", strlen("Link Status: UP_DOWN")); if (fnic->config.flags & VFCF_FIP_CAPABLE) { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "deleting fip-timer during link-down\n"); del_timer_sync(&fnic->fip_timer); } @@ -270,12 +276,12 @@ void fnic_handle_event(struct work_struct *work) spin_lock_irqsave(&fnic->fnic_lock, flags); break; case FNIC_EVT_START_FCF_DISC: - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Start FCF Discovery\n"); fnic_fcoe_start_fcf_disc(fnic); break; default: - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Unknown event 0x%x\n", fevt->event); break; } @@ -370,7 +376,7 @@ static void fnic_fcoe_send_vlan_req(struct fnic *fnic) fnic->set_vlan(fnic, 0); if (printk_ratelimit()) - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "Sending VLAN request...\n"); skb = dev_alloc_skb(sizeof(struct fip_vlan)); @@ -423,12 +429,12 @@ static void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct sk_buff *skb) u64 sol_time; unsigned long flags; - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "Received VLAN response...\n"); fiph = (struct fip_header *) skb->data; - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "Received VLAN response... OP 0x%x SUB_OP 0x%x\n", ntohs(fiph->fip_op), fiph->fip_subcode); @@ -463,7 +469,7 @@ static void fnic_fcoe_process_vlan_resp(struct fnic *fnic, struct sk_buff *skb) if (list_empty(&fnic->vlans)) { /* retry from timer */ atomic64_inc(&fnic_stats->vlan_stats.resp_withno_vlanID); - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "No VLAN descriptors in FIP VLAN response\n"); spin_unlock_irqrestore(&fnic->vlans_lock, flags); goto out; @@ -721,7 +727,8 @@ void fnic_update_mac_locked(struct fnic *fnic, u8 *new) new = ctl; if (ether_addr_equal(data, new)) return; - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "update_mac %pM\n", new); + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "update_mac %pM\n", new); if (!is_zero_ether_addr(data) && !ether_addr_equal(data, ctl)) vnic_dev_del_addr(fnic->vdev, data); memcpy(data, new, ETH_ALEN); @@ -763,8 +770,9 @@ void fnic_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp) u8 *mac; int ret; - FNIC_FCS_DBG(KERN_DEBUG, lport->host, "set port_id %x fp %p\n", - port_id, fp); + FNIC_FCS_DBG(KERN_DEBUG, lport->host, fnic->fnic_num, + "set port_id 0x%x fp 0x%p\n", + port_id, fp); /* * If we're clearing the FC_ID, change to use the ctl_src_addr. @@ -790,10 +798,9 @@ void fnic_set_port_id(struct fc_lport *lport, u32 port_id, struct fc_frame *fp) if (fnic->state == FNIC_IN_ETH_MODE || fnic->state == FNIC_IN_FC_MODE) fnic->state = FNIC_IN_ETH_TRANS_FC_MODE; else { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, - "Unexpected fnic state %s while" - " processing flogi resp\n", - fnic_state_to_str(fnic->state)); + FNIC_FCS_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "Unexpected fnic state: %s processing FLOGI response", + fnic_state_to_str(fnic->state)); spin_unlock_irq(&fnic->fnic_lock); return; } @@ -870,7 +877,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc skb_trim(skb, bytes_written); if (!fcs_ok) { atomic64_inc(&fnic_stats->misc_stats.frame_errors); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fcs error. dropping packet.\n"); goto drop; } @@ -886,7 +893,7 @@ static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc if (!fcs_ok || packet_error || !fcoe_fc_crc_ok || fcoe_enc_error) { atomic64_inc(&fnic_stats->misc_stats.frame_errors); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic rq_cmpl fcoe x%x fcsok x%x" " pkterr x%x fcoe_fc_crc_ok x%x, fcoe_enc_err" " x%x\n", @@ -967,7 +974,7 @@ int fnic_alloc_rq_frame(struct vnic_rq *rq) len = FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM; skb = dev_alloc_skb(len); if (!skb) { - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Unable to allocate RQ sk_buff\n"); return -ENOMEM; } @@ -1341,12 +1348,12 @@ void fnic_handle_fip_timer(struct fnic *fnic) } vlan = list_first_entry(&fnic->vlans, struct fcoe_vlan, list); - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fip_timer: vlan %d state %d sol_count %d\n", vlan->vid, vlan->state, vlan->sol_count); switch (vlan->state) { case FIP_VLAN_USED: - FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "FIP VLAN is selected for FC transaction\n"); spin_unlock_irqrestore(&fnic->vlans_lock, flags); break; @@ -1365,7 +1372,7 @@ void fnic_handle_fip_timer(struct fnic *fnic) * no response on this vlan, remove from the list. * Try the next vlan */ - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "Dequeue this VLAN ID %d from list\n", vlan->vid); list_del(&vlan->list); @@ -1375,7 +1382,7 @@ void fnic_handle_fip_timer(struct fnic *fnic) /* we exhausted all vlans, restart vlan disc */ spin_unlock_irqrestore(&fnic->vlans_lock, flags); - FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, + FNIC_FCS_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "fip_timer: vlan list empty, " "trigger vlan disc\n"); fnic_event_enq(fnic, FNIC_EVT_START_VLAN_DISC); diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c index 8896758fed8c..ff85441c6cea 100644 --- a/drivers/scsi/fnic/fnic_isr.c +++ b/drivers/scsi/fnic/fnic_isr.c @@ -38,8 +38,13 @@ static irqreturn_t fnic_isr_legacy(int irq, void *data) fnic_log_q_error(fnic); } + if (pba & (1 << FNIC_INTX_DUMMY)) { + atomic64_inc(&fnic->fnic_stats.misc_stats.intx_dummy); + vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_DUMMY]); + } + if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) { - work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions); + work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions, FNIC_MQ_CQ_INDEX); work_done += fnic_wq_cmpl_handler(fnic, -1); work_done += fnic_rq_cmpl_handler(fnic, -1); @@ -60,7 +65,7 @@ static irqreturn_t fnic_isr_msi(int irq, void *data) fnic->fnic_stats.misc_stats.last_isr_time = jiffies; atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count); - work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions); + work_done += fnic_wq_copy_cmpl_handler(fnic, io_completions, FNIC_MQ_CQ_INDEX); work_done += fnic_wq_cmpl_handler(fnic, -1); work_done += fnic_rq_cmpl_handler(fnic, -1); @@ -109,12 +114,22 @@ static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data) { struct fnic *fnic = data; unsigned long wq_copy_work_done = 0; + int i; fnic->fnic_stats.misc_stats.last_isr_time = jiffies; atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count); - wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, io_completions); - vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY], + i = irq - fnic->msix[0].irq_num; + if (i >= fnic->wq_copy_count + fnic->copy_wq_base || + i < 0 || fnic->msix[i].irq_num != irq) { + for (i = fnic->copy_wq_base; i < fnic->wq_copy_count + fnic->copy_wq_base ; i++) { + if (fnic->msix[i].irq_num == irq) + break; + } + } + + wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, io_completions, i); + vnic_intr_return_credits(&fnic->intr[i], wq_copy_work_done, 1 /* unmask intr */, 1 /* reset intr timer */); @@ -128,7 +143,7 @@ static irqreturn_t fnic_isr_msix_err_notify(int irq, void *data) fnic->fnic_stats.misc_stats.last_isr_time = jiffies; atomic64_inc(&fnic->fnic_stats.misc_stats.isr_count); - vnic_intr_return_all_credits(&fnic->intr[FNIC_MSIX_ERR_NOTIFY]); + vnic_intr_return_all_credits(&fnic->intr[fnic->err_intr_offset]); fnic_log_q_error(fnic); fnic_handle_link_event(fnic); @@ -186,26 +201,30 @@ int fnic_request_intr(struct fnic *fnic) fnic->msix[FNIC_MSIX_WQ].isr = fnic_isr_msix_wq; fnic->msix[FNIC_MSIX_WQ].devid = fnic; - sprintf(fnic->msix[FNIC_MSIX_WQ_COPY].devname, - "%.11s-scsi-wq", fnic->name); - fnic->msix[FNIC_MSIX_WQ_COPY].isr = fnic_isr_msix_wq_copy; - fnic->msix[FNIC_MSIX_WQ_COPY].devid = fnic; + for (i = fnic->copy_wq_base; i < fnic->wq_copy_count + fnic->copy_wq_base; i++) { + sprintf(fnic->msix[i].devname, + "%.11s-scsi-wq-%d", fnic->name, i-FNIC_MSIX_WQ_COPY); + fnic->msix[i].isr = fnic_isr_msix_wq_copy; + fnic->msix[i].devid = fnic; + } - sprintf(fnic->msix[FNIC_MSIX_ERR_NOTIFY].devname, + sprintf(fnic->msix[fnic->err_intr_offset].devname, "%.11s-err-notify", fnic->name); - fnic->msix[FNIC_MSIX_ERR_NOTIFY].isr = + fnic->msix[fnic->err_intr_offset].isr = fnic_isr_msix_err_notify; - fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic; + fnic->msix[fnic->err_intr_offset].devid = fnic; - for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) { - err = request_irq(pci_irq_vector(fnic->pdev, i), - fnic->msix[i].isr, 0, - fnic->msix[i].devname, - fnic->msix[i].devid); + for (i = 0; i < fnic->intr_count; i++) { + fnic->msix[i].irq_num = pci_irq_vector(fnic->pdev, i); + + err = request_irq(fnic->msix[i].irq_num, + fnic->msix[i].isr, 0, + fnic->msix[i].devname, + fnic->msix[i].devid); if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "MSIX: request_irq" - " failed %d\n", err); + FNIC_ISR_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "request_irq failed with error: %d\n", + err); fnic_free_intr(fnic); break; } @@ -220,44 +239,99 @@ int fnic_request_intr(struct fnic *fnic) return err; } -int fnic_set_intr_mode(struct fnic *fnic) +int fnic_set_intr_mode_msix(struct fnic *fnic) { unsigned int n = ARRAY_SIZE(fnic->rq); unsigned int m = ARRAY_SIZE(fnic->wq); - unsigned int o = ARRAY_SIZE(fnic->wq_copy); + unsigned int o = ARRAY_SIZE(fnic->hw_copy_wq); + unsigned int min_irqs = n + m + 1 + 1; /*rq, raw wq, wq, err*/ /* - * Set interrupt mode (INTx, MSI, MSI-X) depending - * system capabilities. - * - * Try MSI-X first - * * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs * (last INTR is used for WQ/RQ errors and notification area) */ - if (fnic->rq_count >= n && - fnic->raw_wq_count >= m && - fnic->wq_copy_count >= o && - fnic->cq_count >= n + m + o) { - int vecs = n + m + o + 1; - - if (pci_alloc_irq_vectors(fnic->pdev, vecs, vecs, - PCI_IRQ_MSIX) == vecs) { + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "rq-array size: %d wq-array size: %d copy-wq array size: %d\n", + n, m, o); + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "rq_count: %d raw_wq_count: %d wq_copy_count: %d cq_count: %d\n", + fnic->rq_count, fnic->raw_wq_count, + fnic->wq_copy_count, fnic->cq_count); + + if (fnic->rq_count <= n && fnic->raw_wq_count <= m && + fnic->wq_copy_count <= o) { + int vec_count = 0; + int vecs = fnic->rq_count + fnic->raw_wq_count + fnic->wq_copy_count + 1; + + vec_count = pci_alloc_irq_vectors(fnic->pdev, min_irqs, vecs, + PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "allocated %d MSI-X vectors\n", + vec_count); + + if (vec_count > 0) { + if (vec_count < vecs) { + FNIC_ISR_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "interrupts number mismatch: vec_count: %d vecs: %d\n", + vec_count, vecs); + if (vec_count < min_irqs) { + FNIC_ISR_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "no interrupts for copy wq\n"); + return 1; + } + } + fnic->rq_count = n; fnic->raw_wq_count = m; - fnic->wq_copy_count = o; - fnic->wq_count = m + o; - fnic->cq_count = n + m + o; - fnic->intr_count = vecs; - fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY; - - FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, - "Using MSI-X Interrupts\n"); - vnic_dev_set_intr_mode(fnic->vdev, - VNIC_DEV_INTR_MODE_MSIX); + fnic->copy_wq_base = fnic->rq_count + fnic->raw_wq_count; + fnic->wq_copy_count = vec_count - n - m - 1; + fnic->wq_count = fnic->raw_wq_count + fnic->wq_copy_count; + if (fnic->cq_count != vec_count - 1) { + FNIC_ISR_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "CQ count: %d does not match MSI-X vector count: %d\n", + fnic->cq_count, vec_count); + fnic->cq_count = vec_count - 1; + } + fnic->intr_count = vec_count; + fnic->err_intr_offset = fnic->rq_count + fnic->wq_count; + + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "rq_count: %d raw_wq_count: %d copy_wq_base: %d\n", + fnic->rq_count, + fnic->raw_wq_count, fnic->copy_wq_base); + + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "wq_copy_count: %d wq_count: %d cq_count: %d\n", + fnic->wq_copy_count, + fnic->wq_count, fnic->cq_count); + + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "intr_count: %d err_intr_offset: %u", + fnic->intr_count, + fnic->err_intr_offset); + + vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSIX); + FNIC_ISR_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "fnic using MSI-X\n"); return 0; } } + return 1; +} + +int fnic_set_intr_mode(struct fnic *fnic) +{ + int ret_status = 0; + + /* + * Set interrupt mode (INTx, MSI, MSI-X) depending + * system capabilities. + * + * Try MSI-X first + */ + ret_status = fnic_set_intr_mode_msix(fnic); + if (ret_status == 0) + return ret_status; /* * Next try MSI @@ -277,7 +351,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->intr_count = 1; fnic->err_intr_offset = 0; - FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Using MSI Interrupts\n"); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI); @@ -303,7 +377,7 @@ int fnic_set_intr_mode(struct fnic *fnic) fnic->cq_count = 3; fnic->intr_count = 3; - FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Using Legacy Interrupts\n"); vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c index f27f9319e0b2..5ed1d897311a 100644 --- a/drivers/scsi/fnic/fnic_main.c +++ b/drivers/scsi/fnic/fnic_main.c @@ -12,9 +12,11 @@ #include <linux/pci.h> #include <linux/skbuff.h> #include <linux/interrupt.h> +#include <linux/irq.h> #include <linux/spinlock.h> #include <linux/workqueue.h> #include <linux/if_ether.h> +#include <linux/blk-mq-pci.h> #include <scsi/fc/fc_fip.h> #include <scsi/scsi_host.h> #include <scsi/scsi_transport.h> @@ -39,6 +41,7 @@ static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES]; static struct kmem_cache *fnic_io_req_cache; static LIST_HEAD(fnic_list); static DEFINE_SPINLOCK(fnic_list_lock); +static DEFINE_IDA(fnic_ida); /* Supported devices by fnic module */ static struct pci_device_id fnic_id_table[] = { @@ -113,6 +116,7 @@ static const struct scsi_host_template fnic_host_template = { .shost_groups = fnic_host_groups, .track_queue_depth = 1, .cmd_size = sizeof(struct fnic_cmd_priv), + .map_queues = fnic_mq_map_queues_cpus, }; static void @@ -209,7 +213,7 @@ static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host) spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (ret) { - FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic: Get vnic stats failed" " 0x%x", ret); return stats; @@ -321,7 +325,7 @@ static void fnic_reset_host_stats(struct Scsi_Host *host) spin_unlock_irqrestore(&fnic->fnic_lock, flags); if (ret) { - FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic: Reset vnic stats failed" " 0x%x", ret); return; @@ -354,7 +358,7 @@ void fnic_log_q_error(struct fnic *fnic) } for (i = 0; i < fnic->wq_copy_count; i++) { - error_status = ioread32(&fnic->wq_copy[i].ctrl->error_status); + error_status = ioread32(&fnic->hw_copy_wq[i].ctrl->error_status); if (error_status) shost_printk(KERN_ERR, fnic->lport->host, "CWQ[%d] error_status" @@ -389,7 +393,7 @@ static int fnic_notify_set(struct fnic *fnic) err = vnic_dev_notify_set(fnic->vdev, -1); break; case VNIC_DEV_INTR_MODE_MSIX: - err = vnic_dev_notify_set(fnic->vdev, FNIC_MSIX_ERR_NOTIFY); + err = vnic_dev_notify_set(fnic->vdev, fnic->wq_copy_count + fnic->copy_wq_base); break; default: shost_printk(KERN_ERR, fnic->lport->host, @@ -475,6 +479,7 @@ static int fnic_cleanup(struct fnic *fnic) { unsigned int i; int err; + int raw_wq_rq_counts; vnic_dev_disable(fnic->vdev); for (i = 0; i < fnic->intr_count; i++) @@ -491,13 +496,14 @@ static int fnic_cleanup(struct fnic *fnic) return err; } for (i = 0; i < fnic->wq_copy_count; i++) { - err = vnic_wq_copy_disable(&fnic->wq_copy[i]); + err = vnic_wq_copy_disable(&fnic->hw_copy_wq[i]); if (err) return err; + raw_wq_rq_counts = fnic->raw_wq_count + fnic->rq_count; + fnic_wq_copy_cmpl_handler(fnic, -1, i + raw_wq_rq_counts); } /* Clean up completed IOs and FCS frames */ - fnic_wq_copy_cmpl_handler(fnic, io_completions); fnic_wq_cmpl_handler(fnic, -1); fnic_rq_cmpl_handler(fnic, -1); @@ -507,7 +513,7 @@ static int fnic_cleanup(struct fnic *fnic) for (i = 0; i < fnic->rq_count; i++) vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); for (i = 0; i < fnic->wq_copy_count; i++) - vnic_wq_copy_clean(&fnic->wq_copy[i], + vnic_wq_copy_clean(&fnic->hw_copy_wq[i], fnic_wq_copy_cleanup_handler); for (i = 0; i < fnic->cq_count; i++) @@ -560,11 +566,6 @@ static int fnic_scsi_drv_init(struct fnic *fnic) host->max_cmd_len = FCOE_MAX_CMD_LEN; host->nr_hw_queues = fnic->wq_copy_count; - if (host->nr_hw_queues > 1) - shost_printk(KERN_ERR, host, - "fnic: blk-mq is not supported"); - - host->nr_hw_queues = fnic->wq_copy_count = 1; shost_printk(KERN_INFO, host, "fnic: can_queue: %d max_lun: %llu", @@ -577,15 +578,43 @@ static int fnic_scsi_drv_init(struct fnic *fnic) return 0; } +void fnic_mq_map_queues_cpus(struct Scsi_Host *host) +{ + struct fc_lport *lp = shost_priv(host); + struct fnic *fnic = lport_priv(lp); + struct pci_dev *l_pdev = fnic->pdev; + int intr_mode = fnic->config.intr_mode; + struct blk_mq_queue_map *qmap = &host->tag_set.map[HCTX_TYPE_DEFAULT]; + + if (intr_mode == VNIC_DEV_INTR_MODE_MSI || intr_mode == VNIC_DEV_INTR_MODE_INTX) { + FNIC_MAIN_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "intr_mode is not msix\n"); + return; + } + + FNIC_MAIN_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "qmap->nr_queues: %d\n", qmap->nr_queues); + + if (l_pdev == NULL) { + FNIC_MAIN_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "l_pdev is null\n"); + return; + } + + blk_mq_pci_map_queues(qmap, l_pdev, FNIC_PCI_OFFSET); +} + static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct Scsi_Host *host; struct fc_lport *lp; struct fnic *fnic; mempool_t *pool; - int err; + int err = 0; + int fnic_id = 0; int i; unsigned long flags; + int hwq; /* * Allocate SCSI Host and set up association between host, @@ -597,25 +626,28 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err = -ENOMEM; goto err_out; } + host = lp->host; fnic = lport_priv(lp); + + fnic_id = ida_alloc(&fnic_ida, GFP_KERNEL); + if (fnic_id < 0) { + pr_err("Unable to alloc fnic ID\n"); + err = fnic_id; + goto err_out_ida_alloc; + } fnic->lport = lp; fnic->ctlr.lp = lp; - fnic->link_events = 0; + fnic->pdev = pdev; snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, host->host_no); host->transportt = fnic_fc_transport; - + fnic->fnic_num = fnic_id; fnic_stats_debugfs_init(fnic); - /* Setup PCI resources */ - pci_set_drvdata(pdev, fnic); - - fnic->pdev = pdev; - err = pci_enable_device(pdev); if (err) { shost_printk(KERN_ERR, fnic->lport->host, @@ -717,7 +749,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_dev_close; } - fnic_scsi_drv_init(fnic); + /* Setup PCI resources */ + pci_set_drvdata(pdev, fnic); fnic_get_res_counts(fnic); @@ -737,6 +770,16 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_clear_intr; } + fnic_scsi_drv_init(fnic); + + for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) { + fnic->sw_copy_wq[hwq].ioreq_table_size = fnic->fnic_max_tag_id; + fnic->sw_copy_wq[hwq].io_req_table = + kzalloc((fnic->sw_copy_wq[hwq].ioreq_table_size + 1) * + sizeof(struct fnic_io_req *), GFP_KERNEL); + } + shost_printk(KERN_INFO, fnic->lport->host, "fnic copy wqs: %d, Q0 ioreq table size: %d\n", + fnic->wq_copy_count, fnic->sw_copy_wq[0].ioreq_table_size); /* initialize all fnic locks */ spin_lock_init(&fnic->fnic_lock); @@ -751,11 +794,6 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) fnic->fw_ack_index[i] = -1; } - for (i = 0; i < FNIC_IO_LOCKS; i++) - spin_lock_init(&fnic->io_req_lock[i]); - - spin_lock_init(&fnic->sgreset_lock); - err = -ENOMEM; fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache); if (!fnic->io_req_pool) @@ -823,16 +861,32 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) /* allocate RQ buffers and post them to RQ*/ for (i = 0; i < fnic->rq_count; i++) { - vnic_rq_enable(&fnic->rq[i]); err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); if (err) { shost_printk(KERN_ERR, fnic->lport->host, "fnic_alloc_rq_frame can't alloc " "frame\n"); - goto err_out_free_rq_buf; + goto err_out_rq_buf; } } + /* Enable all queues */ + for (i = 0; i < fnic->raw_wq_count; i++) + vnic_wq_enable(&fnic->wq[i]); + for (i = 0; i < fnic->rq_count; i++) { + if (!ioread32(&fnic->rq[i].ctrl->enable)) + vnic_rq_enable(&fnic->rq[i]); + } + for (i = 0; i < fnic->wq_copy_count; i++) + vnic_wq_copy_enable(&fnic->hw_copy_wq[i]); + + err = fnic_request_intr(fnic); + if (err) { + shost_printk(KERN_ERR, fnic->lport->host, + "Unable to request irq.\n"); + goto err_out_request_intr; + } + /* * Initialization done with PCI system, hardware, firmware. * Add host to SCSI @@ -841,9 +895,10 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (err) { shost_printk(KERN_ERR, fnic->lport->host, "fnic: scsi_add_host failed...exiting\n"); - goto err_out_free_rq_buf; + goto err_out_scsi_add_host; } + /* Start local port initiatialization */ lp->link_up = 0; @@ -867,7 +922,7 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (!fc_exch_mgr_alloc(lp, FC_CLASS_3, FCPIO_HOST_EXCH_RANGE_START, FCPIO_HOST_EXCH_RANGE_END, NULL)) { err = -ENOMEM; - goto err_out_remove_scsi_host; + goto err_out_fc_exch_mgr_alloc; } fc_lport_init_stats(lp); @@ -895,21 +950,8 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) skb_queue_head_init(&fnic->frame_queue); skb_queue_head_init(&fnic->tx_queue); - /* Enable all queues */ - for (i = 0; i < fnic->raw_wq_count; i++) - vnic_wq_enable(&fnic->wq[i]); - for (i = 0; i < fnic->wq_copy_count; i++) - vnic_wq_copy_enable(&fnic->wq_copy[i]); - fc_fabric_login(lp); - err = fnic_request_intr(fnic); - if (err) { - shost_printk(KERN_ERR, fnic->lport->host, - "Unable to request irq.\n"); - goto err_out_free_exch_mgr; - } - vnic_dev_enable(fnic->vdev); for (i = 0; i < fnic->intr_count; i++) @@ -921,12 +963,15 @@ static int fnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err_out_free_exch_mgr: fc_exch_mgr_free(lp); -err_out_remove_scsi_host: +err_out_fc_exch_mgr_alloc: fc_remove_host(lp->host); scsi_remove_host(lp->host); -err_out_free_rq_buf: +err_out_scsi_add_host: + fnic_free_intr(fnic); +err_out_request_intr: for (i = 0; i < fnic->rq_count; i++) vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); +err_out_rq_buf: vnic_dev_notify_unset(fnic->vdev); err_out_free_max_pool: mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]); @@ -935,6 +980,8 @@ err_out_free_dflt_pool: err_out_free_ioreq_pool: mempool_destroy(fnic->io_req_pool); err_out_free_resources: + for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) + kfree(fnic->sw_copy_wq[hwq].io_req_table); fnic_free_vnic_resources(fnic); err_out_clear_intr: fnic_clear_intr_mode(fnic); @@ -951,6 +998,8 @@ err_out_disable_device: pci_disable_device(pdev); err_out_free_hba: fnic_stats_debugfs_remove(fnic); + ida_free(&fnic_ida, fnic->fnic_num); +err_out_ida_alloc: scsi_host_put(lp->host); err_out: return err; @@ -961,6 +1010,7 @@ static void fnic_remove(struct pci_dev *pdev) struct fnic *fnic = pci_get_drvdata(pdev); struct fc_lport *lp = fnic->lport; unsigned long flags; + int hwq; /* * Mark state so that the workqueue thread stops forwarding @@ -1021,6 +1071,8 @@ static void fnic_remove(struct pci_dev *pdev) fc_remove_host(fnic->lport->host); scsi_remove_host(fnic->lport->host); + for (hwq = 0; hwq < fnic->wq_copy_count; hwq++) + kfree(fnic->sw_copy_wq[hwq].io_req_table); fc_exch_mgr_free(fnic->lport); vnic_dev_notify_unset(fnic->vdev); fnic_free_intr(fnic); @@ -1031,6 +1083,7 @@ static void fnic_remove(struct pci_dev *pdev) fnic_iounmap(fnic); pci_release_regions(pdev); pci_disable_device(pdev); + ida_free(&fnic_ida, fnic->fnic_num); scsi_host_put(lp->host); } @@ -1168,6 +1221,7 @@ static void __exit fnic_cleanup_module(void) fnic_trace_free(); fnic_fc_trace_free(); fnic_debugfs_terminate(); + ida_destroy(&fnic_ida); } module_init(fnic_init_module); diff --git a/drivers/scsi/fnic/fnic_res.c b/drivers/scsi/fnic/fnic_res.c index a1c9cfcace7f..33dd27f6f24e 100644 --- a/drivers/scsi/fnic/fnic_res.c +++ b/drivers/scsi/fnic/fnic_res.c @@ -57,6 +57,8 @@ int fnic_get_vnic_config(struct fnic *fnic) GET_CONFIG(port_down_timeout); GET_CONFIG(port_down_io_retries); GET_CONFIG(luns_per_tgt); + GET_CONFIG(intr_mode); + GET_CONFIG(wq_copy_count); c->wq_enet_desc_count = min_t(u32, VNIC_FNIC_WQ_DESCS_MAX, @@ -131,6 +133,12 @@ int fnic_get_vnic_config(struct fnic *fnic) c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); c->intr_timer_type = c->intr_timer_type; + /* for older firmware, GET_CONFIG will not return anything */ + if (c->wq_copy_count == 0) + c->wq_copy_count = 1; + + c->wq_copy_count = min_t(u16, FNIC_WQ_COPY_MAX, c->wq_copy_count); + shost_printk(KERN_INFO, fnic->lport->host, "vNIC MAC addr %pM " "wq/wq_copy/rq %d/%d/%d\n", @@ -161,6 +169,10 @@ int fnic_get_vnic_config(struct fnic *fnic) shost_printk(KERN_INFO, fnic->lport->host, "vNIC port dn io retries %d port dn timeout %d\n", c->port_down_io_retries, c->port_down_timeout); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC wq_copy_count: %d\n", c->wq_copy_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC intr mode: %d\n", c->intr_mode); return 0; } @@ -187,12 +199,25 @@ int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu, void fnic_get_res_counts(struct fnic *fnic) { fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ); - fnic->raw_wq_count = fnic->wq_count - 1; - fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count; + fnic->raw_wq_count = 1; + fnic->wq_copy_count = fnic->config.wq_copy_count; fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ); fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ); fnic->intr_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_INTR_CTRL); + + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC fw resources wq_count: %d\n", fnic->wq_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC fw resources raw_wq_count: %d\n", fnic->raw_wq_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC fw resources wq_copy_count: %d\n", fnic->wq_copy_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC fw resources rq_count: %d\n", fnic->rq_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC fw resources cq_count: %d\n", fnic->cq_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC fw resources intr_count: %d\n", fnic->intr_count); } void fnic_free_vnic_resources(struct fnic *fnic) @@ -203,7 +228,7 @@ void fnic_free_vnic_resources(struct fnic *fnic) vnic_wq_free(&fnic->wq[i]); for (i = 0; i < fnic->wq_copy_count; i++) - vnic_wq_copy_free(&fnic->wq_copy[i]); + vnic_wq_copy_free(&fnic->hw_copy_wq[i]); for (i = 0; i < fnic->rq_count; i++) vnic_rq_free(&fnic->rq[i]); @@ -234,10 +259,15 @@ int fnic_alloc_vnic_resources(struct fnic *fnic) intr_mode == VNIC_DEV_INTR_MODE_MSIX ? "MSI-X" : "unknown"); - shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: " - "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n", - fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count, - fnic->rq_count, fnic->cq_count, fnic->intr_count); + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC resources avail: wq %d cp_wq %d raw_wq %d rq %d", + fnic->wq_count, fnic->wq_copy_count, + fnic->raw_wq_count, fnic->rq_count); + + shost_printk(KERN_INFO, fnic->lport->host, + "vNIC resources avail: cq %d intr %d cpy-wq desc count %d\n", + fnic->cq_count, fnic->intr_count, + fnic->config.wq_copy_desc_count); /* Allocate Raw WQ used for FCS frames */ for (i = 0; i < fnic->raw_wq_count; i++) { @@ -250,7 +280,7 @@ int fnic_alloc_vnic_resources(struct fnic *fnic) /* Allocate Copy WQs used for SCSI IOs */ for (i = 0; i < fnic->wq_copy_count; i++) { - err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i], + err = vnic_wq_copy_alloc(fnic->vdev, &fnic->hw_copy_wq[i], (fnic->raw_wq_count + i), fnic->config.wq_copy_desc_count, sizeof(struct fcpio_host_req)); @@ -357,7 +387,7 @@ int fnic_alloc_vnic_resources(struct fnic *fnic) } for (i = 0; i < fnic->wq_copy_count; i++) { - vnic_wq_copy_init(&fnic->wq_copy[i], + vnic_wq_copy_init(&fnic->hw_copy_wq[i], 0 /* cq_index 0 - always */, error_interrupt_enable, error_interrupt_offset); diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 416d81954819..4d6db4509e75 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -92,20 +92,6 @@ static const char *fnic_fcpio_status_to_str(unsigned int status) static void fnic_cleanup_io(struct fnic *fnic); -static inline spinlock_t *fnic_io_lock_hash(struct fnic *fnic, - struct scsi_cmnd *sc) -{ - u32 hash = scsi_cmd_to_rq(sc)->tag & (FNIC_IO_LOCKS - 1); - - return &fnic->io_req_lock[hash]; -} - -static inline spinlock_t *fnic_io_lock_tag(struct fnic *fnic, - int tag) -{ - return &fnic->io_req_lock[tag & (FNIC_IO_LOCKS - 1)]; -} - /* * Unmap the data buffer and sense buffer for an io_req, * also unmap and free the device-private scatter/gather list. @@ -129,23 +115,23 @@ static void fnic_release_ioreq_buf(struct fnic *fnic, } /* Free up Copy Wq descriptors. Called with copy_wq lock held */ -static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq) +static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq, unsigned int hwq) { /* if no Ack received from firmware, then nothing to clean */ - if (!fnic->fw_ack_recd[0]) + if (!fnic->fw_ack_recd[hwq]) return 1; /* * Update desc_available count based on number of freed descriptors * Account for wraparound */ - if (wq->to_clean_index <= fnic->fw_ack_index[0]) - wq->ring.desc_avail += (fnic->fw_ack_index[0] + if (wq->to_clean_index <= fnic->fw_ack_index[hwq]) + wq->ring.desc_avail += (fnic->fw_ack_index[hwq] - wq->to_clean_index + 1); else wq->ring.desc_avail += (wq->ring.desc_count - wq->to_clean_index - + fnic->fw_ack_index[0] + 1); + + fnic->fw_ack_index[hwq] + 1); /* * just bump clean index to ack_index+1 accounting for wraparound @@ -153,10 +139,10 @@ static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq) * to_clean_index and fw_ack_index, both inclusive */ wq->to_clean_index = - (fnic->fw_ack_index[0] + 1) % wq->ring.desc_count; + (fnic->fw_ack_index[hwq] + 1) % wq->ring.desc_count; /* we have processed the acks received so far */ - fnic->fw_ack_recd[0] = 0; + fnic->fw_ack_recd[hwq] = 0; return 0; } @@ -170,17 +156,14 @@ __fnic_set_state_flags(struct fnic *fnic, unsigned long st_flags, unsigned long clearbits) { unsigned long flags = 0; - unsigned long host_lock_flags = 0; spin_lock_irqsave(&fnic->fnic_lock, flags); - spin_lock_irqsave(fnic->lport->host->host_lock, host_lock_flags); if (clearbits) fnic->state_flags &= ~st_flags; else fnic->state_flags |= st_flags; - spin_unlock_irqrestore(fnic->lport->host->host_lock, host_lock_flags); spin_unlock_irqrestore(&fnic->fnic_lock, flags); return; @@ -193,7 +176,7 @@ __fnic_set_state_flags(struct fnic *fnic, unsigned long st_flags, */ int fnic_fw_reset_handler(struct fnic *fnic) { - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; + struct vnic_wq_copy *wq = &fnic->hw_copy_wq[0]; int ret = 0; unsigned long flags; @@ -210,7 +193,7 @@ int fnic_fw_reset_handler(struct fnic *fnic) spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); + free_wq_copy_descs(fnic, wq, 0); if (!vnic_wq_copy_desc_avail(wq)) ret = -EAGAIN; @@ -228,12 +211,12 @@ int fnic_fw_reset_handler(struct fnic *fnic) if (!ret) { atomic64_inc(&fnic->fnic_stats.reset_stats.fw_resets); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Issued fw reset\n"); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Issued fw reset\n"); } else { fnic_clear_state_flags(fnic, FNIC_FLAGS_FWRESET); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Failed to issue fw reset\n"); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "Failed to issue fw reset\n"); } return ret; @@ -246,7 +229,7 @@ int fnic_fw_reset_handler(struct fnic *fnic) */ int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) { - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; + struct vnic_wq_copy *wq = &fnic->hw_copy_wq[0]; enum fcpio_flogi_reg_format_type format; struct fc_lport *lp = fnic->lport; u8 gw_mac[ETH_ALEN]; @@ -256,7 +239,7 @@ int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); + free_wq_copy_descs(fnic, wq, 0); if (!vnic_wq_copy_desc_avail(wq)) { ret = -EAGAIN; @@ -276,15 +259,15 @@ int fnic_flogi_reg_handler(struct fnic *fnic, u32 fc_id) fc_id, gw_mac, fnic->data_src_addr, lp->r_a_tov, lp->e_d_tov); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "FLOGI FIP reg issued fcid %x src %pM dest %pM\n", fc_id, fnic->data_src_addr, gw_mac); } else { fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG, format, fc_id, gw_mac); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "FLOGI reg issued fcid %x map %d dest %pM\n", - fc_id, fnic->ctlr.map_dest, gw_mac); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "FLOGI reg issued fcid 0x%x map %d dest 0x%p\n", + fc_id, fnic->ctlr.map_dest, gw_mac); } atomic64_inc(&fnic->fnic_stats.fw_stats.active_fw_reqs); @@ -306,7 +289,9 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, struct vnic_wq_copy *wq, struct fnic_io_req *io_req, struct scsi_cmnd *sc, - int sg_count) + int sg_count, + uint32_t mqtag, + uint16_t hwq) { struct scatterlist *sg; struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); @@ -314,7 +299,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, struct host_sg_desc *desc; struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; unsigned int i; - unsigned long intr_flags; int flags; u8 exch_flags; struct scsi_lun fc_lun; @@ -354,14 +338,11 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, int_to_scsilun(sc->device->lun, &fc_lun); /* Enqueue the descriptor in the Copy WQ */ - spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); - - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); + if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[hwq]) + free_wq_copy_descs(fnic, wq, hwq); if (unlikely(!vnic_wq_copy_desc_avail(wq))) { - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "fnic_queue_wq_copy_desc failure - no descriptors\n"); atomic64_inc(&misc_stats->io_cpwq_alloc_failures); return SCSI_MLQUEUE_HOST_BUSY; @@ -378,7 +359,7 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, (rp->flags & FC_RP_FLAGS_RETRY)) exch_flags |= FCPIO_ICMND_SRFLAG_RETRY; - fnic_queue_wq_copy_desc_icmnd_16(wq, scsi_cmd_to_rq(sc)->tag, + fnic_queue_wq_copy_desc_icmnd_16(wq, mqtag, 0, exch_flags, io_req->sgl_cnt, SCSI_SENSE_BUFFERSIZE, io_req->sgl_list_pa, @@ -399,43 +380,52 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); return 0; } -/* - * fnic_queuecommand - * Routine to send a scsi cdb - * Called with host_lock held and interrupts disabled. - */ -static int fnic_queuecommand_lck(struct scsi_cmnd *sc) +int fnic_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *sc) { + struct request *const rq = scsi_cmd_to_rq(sc); + uint32_t mqtag = 0; void (*done)(struct scsi_cmnd *) = scsi_done; - const int tag = scsi_cmd_to_rq(sc)->tag; struct fc_lport *lp = shost_priv(sc->device->host); struct fc_rport *rport; struct fnic_io_req *io_req = NULL; struct fnic *fnic = lport_priv(lp); struct fnic_stats *fnic_stats = &fnic->fnic_stats; struct vnic_wq_copy *wq; - int ret; + int ret = 1; u64 cmd_trace; int sg_count = 0; unsigned long flags = 0; unsigned long ptr; - spinlock_t *io_lock = NULL; int io_lock_acquired = 0; struct fc_rport_libfc_priv *rp; + uint16_t hwq = 0; + + mqtag = blk_mq_unique_tag(rq); + spin_lock_irqsave(&fnic->fnic_lock, flags); - if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) + if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) { + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "fnic IO blocked flags: 0x%lx. Returning SCSI_MLQUEUE_HOST_BUSY\n", + fnic->state_flags); return SCSI_MLQUEUE_HOST_BUSY; + } - if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) + if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_FWRESET))) { + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "fnic flags: 0x%lx. Returning SCSI_MLQUEUE_HOST_BUSY\n", + fnic->state_flags); return SCSI_MLQUEUE_HOST_BUSY; + } rport = starget_to_rport(scsi_target(sc->device)); if (!rport) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "returning DID_NO_CONNECT for IO as rport is NULL\n"); sc->result = DID_NO_CONNECT << 16; done(sc); @@ -444,7 +434,8 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) ret = fc_remote_port_chkready(rport); if (ret) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "rport is not ready\n"); atomic64_inc(&fnic_stats->misc_stats.rport_not_ready); sc->result = ret; @@ -454,7 +445,8 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) rp = rport->dd_data; if (!rp || rp->rp_state == RPORT_ST_DELETE) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "rport 0x%x removed, returning DID_NO_CONNECT\n", rport->port_id); @@ -465,7 +457,8 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) } if (rp->rp_state != RPORT_ST_READY) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "rport 0x%x in state 0x%x, returning DID_IMM_RETRY\n", rport->port_id, rp->rp_state); @@ -474,17 +467,17 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) return 0; } - if (lp->state != LPORT_ST_READY || !(lp->link_up)) + if (lp->state != LPORT_ST_READY || !(lp->link_up)) { + spin_unlock_irqrestore(&fnic->fnic_lock, flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "state not ready: %d/link not up: %d Returning HOST_BUSY\n", + lp->state, lp->link_up); return SCSI_MLQUEUE_HOST_BUSY; + } atomic_inc(&fnic->in_flight); - /* - * Release host lock, use driver resource specific locks from here. - * Don't re-enable interrupts in case they were disabled prior to the - * caller disabling them. - */ - spin_unlock(lp->host->host_lock); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); fnic_priv(sc)->state = FNIC_IOREQ_NOT_INITED; fnic_priv(sc)->flags = FNIC_NO_FLAGS; @@ -501,7 +494,7 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) sg_count = scsi_dma_map(sc); if (sg_count < 0) { FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, - tag, sc, 0, sc->cmnd[0], sg_count, fnic_priv(sc)->state); + mqtag, sc, 0, sc->cmnd[0], sg_count, fnic_priv(sc)->state); mempool_free(io_req, fnic->io_req_pool); goto out; } @@ -536,11 +529,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) } /* - * Will acquire lock defore setting to IO initialized. + * Will acquire lock before setting to IO initialized. */ - - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); + hwq = blk_mq_unique_tag_to_hwq(mqtag); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); /* initialize rest of io_req */ io_lock_acquired = 1; @@ -549,28 +541,39 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc) fnic_priv(sc)->state = FNIC_IOREQ_CMD_PENDING; fnic_priv(sc)->io_req = io_req; fnic_priv(sc)->flags |= FNIC_IO_INITIALIZED; + io_req->sc = sc; + + if (fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(mqtag)] != NULL) { + WARN(1, "fnic<%d>: %s: hwq: %d tag 0x%x already exists\n", + fnic->fnic_num, __func__, hwq, blk_mq_unique_tag_to_tag(mqtag)); + return SCSI_MLQUEUE_HOST_BUSY; + } + + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(mqtag)] = io_req; + io_req->tag = mqtag; /* create copy wq desc and enqueue it */ - wq = &fnic->wq_copy[0]; - ret = fnic_queue_wq_copy_desc(fnic, wq, io_req, sc, sg_count); + wq = &fnic->hw_copy_wq[hwq]; + atomic64_inc(&fnic_stats->io_stats.ios[hwq]); + ret = fnic_queue_wq_copy_desc(fnic, wq, io_req, sc, sg_count, mqtag, hwq); if (ret) { /* * In case another thread cancelled the request, * refetch the pointer under the lock. */ FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, - tag, sc, 0, 0, 0, fnic_flags_and_state(sc)); + mqtag, sc, 0, 0, 0, fnic_flags_and_state(sc)); io_req = fnic_priv(sc)->io_req; fnic_priv(sc)->io_req = NULL; + if (io_req) + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(mqtag)] = NULL; fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if (io_req) { fnic_release_ioreq_buf(fnic, io_req, sc); mempool_free(io_req, fnic->io_req_pool); } atomic_dec(&fnic->in_flight); - /* acquire host lock before returning to SCSI */ - spin_lock(lp->host->host_lock); return ret; } else { atomic64_inc(&fnic_stats->io_stats.active_ios); @@ -590,20 +593,17 @@ out: sc->cmnd[5]); FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no, - tag, sc, io_req, sg_count, cmd_trace, + mqtag, sc, io_req, sg_count, cmd_trace, fnic_flags_and_state(sc)); /* if only we issued IO, will we have the io lock */ if (io_lock_acquired) - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); atomic_dec(&fnic->in_flight); - /* acquire host lock before returning to SCSI */ - spin_lock(lp->host->host_lock); return ret; } -DEF_SCSI_QCMD(fnic_queuecommand) /* * fnic_fcpio_fw_reset_cmpl_handler @@ -636,15 +636,14 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) { /* Check status of reset completion */ if (!hdr_status) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "reset cmpl success\n"); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "reset cmpl success\n"); /* Ready to send flogi out */ fnic->state = FNIC_IN_ETH_MODE; } else { - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "fnic fw_reset : failed %s\n", - fnic_fcpio_status_to_str(hdr_status)); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "reset failed with header status: %s\n", + fnic_fcpio_status_to_str(hdr_status)); /* * Unable to change to eth mode, cannot send out flogi @@ -657,10 +656,9 @@ static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, ret = -1; } } else { - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "Unexpected state %s while processing" - " reset cmpl\n", fnic_state_to_str(fnic->state)); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "Unexpected state while processing reset completion: %s\n", + fnic_state_to_str(fnic->state)); atomic64_inc(&reset_stats->fw_reset_failures); ret = -1; } @@ -711,19 +709,19 @@ static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, /* Check flogi registration completion status */ if (!hdr_status) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "flog reg succeeded\n"); fnic->state = FNIC_IN_FC_MODE; } else { FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, + fnic->lport->host, fnic->fnic_num, "fnic flogi reg :failed %s\n", fnic_fcpio_status_to_str(hdr_status)); fnic->state = FNIC_IN_ETH_MODE; ret = -1; } } else { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Unexpected fnic state %s while" " processing flogi reg completion\n", fnic_state_to_str(fnic->state)); @@ -780,20 +778,21 @@ static inline void fnic_fcpio_ack_handler(struct fnic *fnic, u16 request_out = desc->u.ack.request_out; unsigned long flags; u64 *ox_id_tag = (u64 *)(void *)desc; + unsigned int wq_index = cq_index; /* mark the ack state */ - wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; - spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); + wq = &fnic->hw_copy_wq[cq_index]; + spin_lock_irqsave(&fnic->wq_copy_lock[wq_index], flags); fnic->fnic_stats.misc_stats.last_ack_time = jiffies; if (is_ack_index_in_range(wq, request_out)) { - fnic->fw_ack_index[0] = request_out; - fnic->fw_ack_recd[0] = 1; + fnic->fw_ack_index[wq_index] = request_out; + fnic->fw_ack_recd[wq_index] = 1; } else atomic64_inc( &fnic->fnic_stats.misc_stats.ack_index_out_of_range); - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[wq_index], flags); FNIC_TRACE(fnic_fcpio_ack_handler, fnic->lport->host->host_no, 0, 0, ox_id_tag[2], ox_id_tag[3], ox_id_tag[4], ox_id_tag[5]); @@ -803,12 +802,12 @@ static inline void fnic_fcpio_ack_handler(struct fnic *fnic, * fnic_fcpio_icmnd_cmpl_handler * Routine to handle icmnd completions */ -static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, +static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, unsigned int cq_index, struct fcpio_fw_req *desc) { u8 type; u8 hdr_status; - struct fcpio_tag tag; + struct fcpio_tag ftag; u32 id; u64 xfer_len = 0; struct fcpio_icmnd_cmpl *icmnd_cmpl; @@ -816,27 +815,47 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, struct scsi_cmnd *sc; struct fnic_stats *fnic_stats = &fnic->fnic_stats; unsigned long flags; - spinlock_t *io_lock; u64 cmd_trace; unsigned long start_time; unsigned long io_duration_time; + unsigned int hwq = 0; + unsigned int mqtag = 0; + unsigned int tag = 0; /* Decode the cmpl description to get the io_req id */ - fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); - fcpio_tag_id_dec(&tag, &id); + fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag); + fcpio_tag_id_dec(&ftag, &id); icmnd_cmpl = &desc->u.icmnd_cmpl; - if (id >= fnic->fnic_max_tag_id) { - shost_printk(KERN_ERR, fnic->lport->host, - "Tag out of range tag %x hdr status = %s\n", - id, fnic_fcpio_status_to_str(hdr_status)); + mqtag = id; + tag = blk_mq_unique_tag_to_tag(mqtag); + hwq = blk_mq_unique_tag_to_hwq(mqtag); + + if (hwq != cq_index) { + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", + hwq, mqtag, tag, cq_index); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hdr status: %s icmnd completion on the wrong queue\n", + fnic_fcpio_status_to_str(hdr_status)); + } + + if (tag >= fnic->fnic_max_tag_id) { + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", + hwq, mqtag, tag, cq_index); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hdr status: %s Out of range tag\n", + fnic_fcpio_status_to_str(hdr_status)); return; } + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); sc = scsi_host_find_tag(fnic->lport->host, id); WARN_ON_ONCE(!sc); if (!sc) { atomic64_inc(&fnic_stats->io_stats.sc_null); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); shost_printk(KERN_ERR, fnic->lport->host, "icmnd_cmpl sc is null - " "hdr status = %s tag = 0x%x desc = 0x%p\n", @@ -852,14 +871,19 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, return; } - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); io_req = fnic_priv(sc)->io_req; + if (fnic->sw_copy_wq[hwq].io_req_table[tag] != io_req) { + WARN(1, "%s: %d: hwq: %d mqtag: 0x%x tag: 0x%x io_req tag mismatch\n", + __func__, __LINE__, hwq, mqtag, tag); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + return; + } + WARN_ON_ONCE(!io_req); if (!io_req) { atomic64_inc(&fnic_stats->io_stats.ioreq_null); fnic_priv(sc)->flags |= FNIC_IO_REQ_NULL; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); shost_printk(KERN_ERR, fnic->lport->host, "icmnd_cmpl io_req is null - " "hdr status = %s tag = 0x%x sc 0x%p\n", @@ -883,11 +907,11 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, */ fnic_priv(sc)->flags |= FNIC_IO_DONE; fnic_priv(sc)->flags |= FNIC_IO_ABTS_PENDING; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if(FCPIO_ABORTED == hdr_status) fnic_priv(sc)->flags |= FNIC_IO_ABORTED; - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "icmnd_cmpl abts pending " "hdr status = %s tag = 0x%x sc = 0x%p " "scsi_status = %x residual = %d\n", @@ -971,7 +995,11 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, /* Break link with the SCSI command */ fnic_priv(sc)->io_req = NULL; + io_req->sc = NULL; fnic_priv(sc)->flags |= FNIC_IO_DONE; + fnic->sw_copy_wq[hwq].io_req_table[tag] = NULL; + + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if (hdr_status != FCPIO_SUCCESS) { atomic64_inc(&fnic_stats->io_stats.io_failures); @@ -1005,7 +1033,6 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, /* Call SCSI completion function to complete the IO */ scsi_done(sc); - spin_unlock_irqrestore(io_lock, flags); mempool_free(io_req, fnic->io_req_pool); @@ -1042,7 +1069,7 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, /* fnic_fcpio_itmf_cmpl_handler * Routine to handle itmf completions */ -static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, +static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, unsigned int cq_index, struct fcpio_fw_req *desc) { u8 type; @@ -1056,51 +1083,73 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; unsigned long flags; - spinlock_t *io_lock; unsigned long start_time; + unsigned int hwq = cq_index; + unsigned int mqtag; unsigned int tag; fcpio_header_dec(&desc->hdr, &type, &hdr_status, &ftag); fcpio_tag_id_dec(&ftag, &id); - tag = id & FNIC_TAG_MASK; - if (tag == fnic->fnic_max_tag_id) { - if (!(id & FNIC_TAG_DEV_RST)) { - shost_printk(KERN_ERR, fnic->lport->host, - "Tag out of range id 0x%x hdr status = %s\n", - id, fnic_fcpio_status_to_str(hdr_status)); - return; - } - } else if (tag > fnic->fnic_max_tag_id) { - shost_printk(KERN_ERR, fnic->lport->host, - "Tag out of range tag 0x%x hdr status = %s\n", - tag, fnic_fcpio_status_to_str(hdr_status)); + mqtag = id & FNIC_TAG_MASK; + tag = blk_mq_unique_tag_to_tag(id & FNIC_TAG_MASK); + hwq = blk_mq_unique_tag_to_hwq(id & FNIC_TAG_MASK); + + if (hwq != cq_index) { + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", + hwq, mqtag, tag, cq_index); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hdr status: %s ITMF completion on the wrong queue\n", + fnic_fcpio_status_to_str(hdr_status)); + } + + if (tag > fnic->fnic_max_tag_id) { + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", + hwq, mqtag, tag, cq_index); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hdr status: %s Tag out of range\n", + fnic_fcpio_status_to_str(hdr_status)); + return; + } else if ((tag == fnic->fnic_max_tag_id) && !(id & FNIC_TAG_DEV_RST)) { + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x cq index: %d ", + hwq, mqtag, tag, cq_index); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hdr status: %s Tag out of range\n", + fnic_fcpio_status_to_str(hdr_status)); return; } - if ((tag == fnic->fnic_max_tag_id) && (id & FNIC_TAG_DEV_RST)) { - sc = fnic->sgreset_sc; - io_lock = &fnic->sgreset_lock; + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); + + /* If it is sg3utils allocated SC then tag_id + * is max_tag_id and SC is retrieved from io_req + */ + if ((mqtag == fnic->fnic_max_tag_id) && (id & FNIC_TAG_DEV_RST)) { + io_req = fnic->sw_copy_wq[hwq].io_req_table[tag]; + if (io_req) + sc = io_req->sc; } else { sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK); - io_lock = fnic_io_lock_hash(fnic, sc); } WARN_ON_ONCE(!sc); if (!sc) { atomic64_inc(&fnic_stats->io_stats.sc_null); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); shost_printk(KERN_ERR, fnic->lport->host, "itmf_cmpl sc is null - hdr status = %s tag = 0x%x\n", fnic_fcpio_status_to_str(hdr_status), tag); return; } - spin_lock_irqsave(io_lock, flags); io_req = fnic_priv(sc)->io_req; WARN_ON_ONCE(!io_req); if (!io_req) { atomic64_inc(&fnic_stats->io_stats.ioreq_null); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; shost_printk(KERN_ERR, fnic->lport->host, "itmf_cmpl io_req is null - " @@ -1113,17 +1162,22 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, if ((id & FNIC_TAG_ABORT) && (id & FNIC_TAG_DEV_RST)) { /* Abort and terminate completion of device reset req */ /* REVISIT : Add asserts about various flags */ - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "dev reset abts cmpl recd. id %x status %s\n", - id, fnic_fcpio_status_to_str(hdr_status)); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Abt/term completion received\n", + hwq, mqtag, tag, + fnic_fcpio_status_to_str(hdr_status)); fnic_priv(sc)->state = FNIC_IOREQ_ABTS_COMPLETE; fnic_priv(sc)->abts_status = hdr_status; fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE; if (io_req->abts_done) complete(io_req->abts_done); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } else if (id & FNIC_TAG_ABORT) { /* Completion of abort cmd */ + shost_printk(KERN_DEBUG, fnic->lport->host, + "hwq: %d mqtag: 0x%x tag: 0x%x Abort header status: %s\n", + hwq, mqtag, tag, + fnic_fcpio_status_to_str(hdr_status)); switch (hdr_status) { case FCPIO_SUCCESS: break; @@ -1135,7 +1189,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, &term_stats->terminate_fw_timeouts); break; case FCPIO_ITMF_REJECTED: - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, "abort reject recd. id %d\n", (int)(id & FNIC_TAG_MASK)); break; @@ -1156,7 +1210,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, } if (fnic_priv(sc)->state != FNIC_IOREQ_ABTS_PENDING) { /* This is a late completion. Ignore it */ - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return; } @@ -1170,7 +1224,7 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) atomic64_inc(&misc_stats->no_icmnd_itmf_cmpls); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "abts cmpl recd. id %d status %s\n", (int)(id & FNIC_TAG_MASK), fnic_fcpio_status_to_str(hdr_status)); @@ -1182,14 +1236,19 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, */ if (io_req->abts_done) { complete(io_req->abts_done); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + shost_printk(KERN_INFO, fnic->lport->host, + "hwq: %d mqtag: 0x%x tag: 0x%x Waking up abort thread\n", + hwq, mqtag, tag); } else { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "abts cmpl, completing IO\n"); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Completing IO\n", + hwq, mqtag, + tag, fnic_fcpio_status_to_str(hdr_status)); fnic_priv(sc)->io_req = NULL; sc->result = (DID_ERROR << 16); - - spin_unlock_irqrestore(io_lock, flags); + fnic->sw_copy_wq[hwq].io_req_table[tag] = NULL; + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_release_ioreq_buf(fnic, io_req, sc); mempool_free(io_req, fnic->io_req_pool); @@ -1213,29 +1272,32 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, } } else if (id & FNIC_TAG_DEV_RST) { /* Completion of device reset */ + shost_printk(KERN_INFO, fnic->lport->host, + "hwq: %d mqtag: 0x%x tag: 0x%x DR hst: %s\n", + hwq, mqtag, + tag, fnic_fcpio_status_to_str(hdr_status)); fnic_priv(sc)->lr_status = hdr_status; if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_DEV_RST_ABTS_PENDING; FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, sc->device->host->host_no, id, sc, jiffies_to_msecs(jiffies - start_time), desc, 0, fnic_flags_and_state(sc)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Terminate pending " - "dev reset cmpl recd. id %d status %s\n", - (int)(id & FNIC_TAG_MASK), - fnic_fcpio_status_to_str(hdr_status)); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s Terminate pending\n", + hwq, mqtag, + tag, fnic_fcpio_status_to_str(hdr_status)); return; } if (fnic_priv(sc)->flags & FNIC_DEV_RST_TIMED_OUT) { /* Need to wait for terminate completion */ - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); FNIC_TRACE(fnic_fcpio_itmf_cmpl_handler, sc->device->host->host_no, id, sc, jiffies_to_msecs(jiffies - start_time), desc, 0, fnic_flags_and_state(sc)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "dev reset cmpl recd after time out. " "id %d status %s\n", (int)(id & FNIC_TAG_MASK), @@ -1244,19 +1306,19 @@ static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, } fnic_priv(sc)->state = FNIC_IOREQ_CMD_COMPLETE; fnic_priv(sc)->flags |= FNIC_DEV_RST_DONE; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "dev reset cmpl recd. id %d status %s\n", - (int)(id & FNIC_TAG_MASK), - fnic_fcpio_status_to_str(hdr_status)); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x hst: %s DR completion received\n", + hwq, mqtag, + tag, fnic_fcpio_status_to_str(hdr_status)); if (io_req->dr_done) complete(io_req->dr_done); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } else { shost_printk(KERN_ERR, fnic->lport->host, - "Unexpected itmf io state %s tag %x\n", - fnic_ioreq_state_to_str(fnic_priv(sc)->state), id); - spin_unlock_irqrestore(io_lock, flags); + "%s: Unexpected itmf io state: hwq: %d tag 0x%x %s\n", + __func__, hwq, id, fnic_ioreq_state_to_str(fnic_priv(sc)->state)); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } } @@ -1283,17 +1345,19 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, break; } + cq_index -= fnic->copy_wq_base; + switch (desc->hdr.type) { case FCPIO_ACK: /* fw copied copy wq desc to its queue */ fnic_fcpio_ack_handler(fnic, cq_index, desc); break; case FCPIO_ICMND_CMPL: /* fw completed a command */ - fnic_fcpio_icmnd_cmpl_handler(fnic, desc); + fnic_fcpio_icmnd_cmpl_handler(fnic, cq_index, desc); break; case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ - fnic_fcpio_itmf_cmpl_handler(fnic, desc); + fnic_fcpio_itmf_cmpl_handler(fnic, cq_index, desc); break; case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ @@ -1306,7 +1370,7 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, break; default: - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "firmware completion type %d\n", desc->hdr.type); break; @@ -1319,10 +1383,8 @@ static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, * fnic_wq_copy_cmpl_handler * Routine to process wq copy */ -int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do) +int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do, unsigned int cq_index) { - unsigned int wq_work_done = 0; - unsigned int i, cq_index; unsigned int cur_work_done; struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; u64 start_jiffies = 0; @@ -1330,44 +1392,51 @@ int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do) u64 delta_jiffies = 0; u64 delta_ms = 0; - for (i = 0; i < fnic->wq_copy_count; i++) { - cq_index = i + fnic->raw_wq_count + fnic->rq_count; - - start_jiffies = jiffies; - cur_work_done = vnic_cq_copy_service(&fnic->cq[cq_index], - fnic_fcpio_cmpl_handler, - copy_work_to_do); - end_jiffies = jiffies; - - wq_work_done += cur_work_done; - delta_jiffies = end_jiffies - start_jiffies; - if (delta_jiffies > - (u64) atomic64_read(&misc_stats->max_isr_jiffies)) { - atomic64_set(&misc_stats->max_isr_jiffies, - delta_jiffies); - delta_ms = jiffies_to_msecs(delta_jiffies); - atomic64_set(&misc_stats->max_isr_time_ms, delta_ms); - atomic64_set(&misc_stats->corr_work_done, - cur_work_done); - } + start_jiffies = jiffies; + cur_work_done = vnic_cq_copy_service(&fnic->cq[cq_index], + fnic_fcpio_cmpl_handler, + copy_work_to_do); + end_jiffies = jiffies; + delta_jiffies = end_jiffies - start_jiffies; + if (delta_jiffies > (u64) atomic64_read(&misc_stats->max_isr_jiffies)) { + atomic64_set(&misc_stats->max_isr_jiffies, delta_jiffies); + delta_ms = jiffies_to_msecs(delta_jiffies); + atomic64_set(&misc_stats->max_isr_time_ms, delta_ms); + atomic64_set(&misc_stats->corr_work_done, cur_work_done); } - return wq_work_done; + + return cur_work_done; } static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data) { - const int tag = scsi_cmd_to_rq(sc)->tag; + struct request *const rq = scsi_cmd_to_rq(sc); struct fnic *fnic = data; struct fnic_io_req *io_req; unsigned long flags = 0; - spinlock_t *io_lock; unsigned long start_time = 0; struct fnic_stats *fnic_stats = &fnic->fnic_stats; + uint16_t hwq = 0; + int tag; + int mqtag; - io_lock = fnic_io_lock_tag(fnic, tag); - spin_lock_irqsave(io_lock, flags); + mqtag = blk_mq_unique_tag(rq); + hwq = blk_mq_unique_tag_to_hwq(mqtag); + tag = blk_mq_unique_tag_to_tag(mqtag); + + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); + + fnic->sw_copy_wq[hwq].io_req_table[tag] = NULL; io_req = fnic_priv(sc)->io_req; + if (!io_req) { + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d mqtag: 0x%x tag: 0x%x flags: 0x%x No ioreq. Returning\n", + hwq, mqtag, tag, fnic_priv(sc)->flags); + return true; + } + if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && !(fnic_priv(sc)->flags & FNIC_DEV_RST_DONE)) { /* @@ -1379,20 +1448,16 @@ static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data) complete(io_req->dr_done); else if (io_req && io_req->abts_done) complete(io_req->abts_done); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } else if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } - if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - goto cleanup_scsi_cmd; - } fnic_priv(sc)->io_req = NULL; - - spin_unlock_irqrestore(io_lock, flags); + io_req->sc = NULL; + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); /* * If there is a scsi_cmnd associated with this io_req, then @@ -1402,23 +1467,16 @@ static bool fnic_cleanup_io_iter(struct scsi_cmnd *sc, void *data) fnic_release_ioreq_buf(fnic, io_req, sc); mempool_free(io_req, fnic->io_req_pool); -cleanup_scsi_cmd: sc->result = DID_TRANSPORT_DISRUPTED << 16; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "fnic_cleanup_io: tag:0x%x : sc:0x%p duration = %lu DID_TRANSPORT_DISRUPTED\n", - tag, sc, jiffies - start_time); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "mqtag:0x%x tag: 0x%x sc:0x%p duration = %lu DID_TRANSPORT_DISRUPTED\n", + mqtag, tag, sc, (jiffies - start_time)); if (atomic64_read(&fnic->io_cmpl_skip)) atomic64_dec(&fnic->io_cmpl_skip); else atomic64_inc(&fnic_stats->io_stats.io_completions); - /* Complete the command to SCSI */ - if (!(fnic_priv(sc)->flags & FNIC_IO_ISSUED)) - shost_printk(KERN_ERR, fnic->lport->host, - "Calling done for IO not issued to fw: tag:0x%x sc:0x%p\n", - tag, sc); - FNIC_TRACE(fnic_cleanup_io, sc->device->host->host_no, tag, sc, jiffies_to_msecs(jiffies - start_time), @@ -1447,8 +1505,8 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, struct fnic_io_req *io_req; struct scsi_cmnd *sc; unsigned long flags; - spinlock_t *io_lock; unsigned long start_time = 0; + uint16_t hwq; /* get the tag reference */ fcpio_tag_id_dec(&desc->hdr.tag, &id); @@ -1461,8 +1519,8 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, if (!sc) return; - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); + hwq = blk_mq_unique_tag_to_hwq(id); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); /* Get the IO context which this desc refers to */ io_req = fnic_priv(sc)->io_req; @@ -1470,13 +1528,15 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, /* fnic interrupts are turned off by now */ if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); goto wq_copy_cleanup_scsi_cmd; } fnic_priv(sc)->io_req = NULL; + io_req->sc = NULL; + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(id)] = NULL; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); start_time = io_req->start_time; fnic_release_ioreq_buf(fnic, io_req, sc); @@ -1484,7 +1544,7 @@ void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, wq_copy_cleanup_scsi_cmd: sc->result = DID_NO_CONNECT << 16; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "wq_copy_cleanup_handler:" " DID_NO_CONNECT\n"); FNIC_TRACE(fnic_wq_copy_cleanup_handler, @@ -1500,31 +1560,31 @@ wq_copy_cleanup_scsi_cmd: static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, u32 task_req, u8 *fc_lun, - struct fnic_io_req *io_req) + struct fnic_io_req *io_req, + unsigned int hwq) { - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; - struct Scsi_Host *host = fnic->lport->host; + struct vnic_wq_copy *wq = &fnic->hw_copy_wq[hwq]; struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; unsigned long flags; - spin_lock_irqsave(host->host_lock, flags); + spin_lock_irqsave(&fnic->fnic_lock, flags); if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) { - spin_unlock_irqrestore(host->host_lock, flags); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); return 1; } else atomic_inc(&fnic->in_flight); - spin_unlock_irqrestore(host->host_lock, flags); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); - spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); + if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[hwq]) + free_wq_copy_descs(fnic, wq, hwq); if (!vnic_wq_copy_desc_avail(wq)) { - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); atomic_dec(&fnic->in_flight); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic_queue_abort_io_req: failure: no descriptors\n"); atomic64_inc(&misc_stats->abts_cpwq_alloc_failures); return 1; @@ -1539,7 +1599,7 @@ static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, atomic64_set(&fnic->fnic_stats.fw_stats.max_fw_reqs, atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); atomic_dec(&fnic->in_flight); return 0; @@ -1553,33 +1613,36 @@ struct fnic_rport_abort_io_iter_data { static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) { + struct request *const rq = scsi_cmd_to_rq(sc); struct fnic_rport_abort_io_iter_data *iter_data = data; struct fnic *fnic = iter_data->fnic; - int abt_tag = scsi_cmd_to_rq(sc)->tag; + int abt_tag = 0; struct fnic_io_req *io_req; - spinlock_t *io_lock; unsigned long flags; struct reset_stats *reset_stats = &fnic->fnic_stats.reset_stats; struct terminate_stats *term_stats = &fnic->fnic_stats.term_stats; struct scsi_lun fc_lun; enum fnic_ioreq_state old_ioreq_state; + uint16_t hwq = 0; - io_lock = fnic_io_lock_tag(fnic, abt_tag); - spin_lock_irqsave(io_lock, flags); + abt_tag = blk_mq_unique_tag(rq); + hwq = blk_mq_unique_tag_to_hwq(abt_tag); + + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req || io_req->port_id != iter_data->port_id) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && !(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED)) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "fnic_rport_exch_reset dev rst not pending sc 0x%p\n", - sc); - spin_unlock_irqrestore(io_lock, flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d abt_tag: 0x%x flags: 0x%x Device reset is not pending\n", + hwq, abt_tag, fnic_priv(sc)->flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } @@ -1588,7 +1651,7 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) * belongs to rport that went away */ if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } if (io_req->abts_done) { @@ -1612,38 +1675,41 @@ static bool fnic_rport_abort_io_iter(struct scsi_cmnd *sc, void *data) atomic64_inc(&reset_stats->device_reset_terminates); abt_tag |= FNIC_TAG_DEV_RST; } - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic_rport_exch_reset dev rst sc 0x%p\n", sc); BUG_ON(io_req->abts_done); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic_rport_reset_exch: Issuing abts\n"); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); /* Now queue the abort command to firmware */ int_to_scsilun(sc->device->lun, &fc_lun); if (fnic_queue_abort_io_req(fnic, abt_tag, FCPIO_ITMF_ABT_TASK_TERM, - fc_lun.scsi_lun, io_req)) { + fc_lun.scsi_lun, io_req, hwq)) { /* * Revert the cmd state back to old state, if * it hasn't changed in between. This cmd will get * aborted later by scsi_eh, or cleaned up during * lun reset */ - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d abt_tag: 0x%x flags: 0x%x Queuing abort failed\n", + hwq, abt_tag, fnic_priv(sc)->flags); if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) fnic_priv(sc)->state = old_ioreq_state; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } else { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) fnic_priv(sc)->flags |= FNIC_DEV_RST_TERM_ISSUED; else fnic_priv(sc)->flags |= FNIC_IO_INTERNAL_TERM_ISSUED; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); atomic64_inc(&term_stats->terminates); iter_data->term_cnt++; } @@ -1660,7 +1726,7 @@ static void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) }; FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, + fnic->lport->host, fnic->fnic_num, "fnic_rport_exch_reset called portid 0x%06x\n", port_id); @@ -1697,9 +1763,8 @@ void fnic_terminate_rport_io(struct fc_rport *rport) return; } fnic = lport_priv(lport); - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, "fnic_terminate_rport_io called" - " wwpn 0x%llx, wwnn0x%llx, rport 0x%p, portid 0x%06x\n", + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "wwpn 0x%llx, wwnn0x%llx, rport 0x%p, portid 0x%06x\n", rport->port_name, rport->node_name, rport, rport->port_id); @@ -1721,7 +1786,6 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) struct fnic *fnic; struct fnic_io_req *io_req = NULL; struct fc_rport *rport; - spinlock_t *io_lock; unsigned long flags; unsigned long start_time = 0; int ret = SUCCESS; @@ -1731,8 +1795,10 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) struct abort_stats *abts_stats; struct terminate_stats *term_stats; enum fnic_ioreq_state old_ioreq_state; - const int tag = rq->tag; + int mqtag; unsigned long abt_issued_time; + uint16_t hwq = 0; + DECLARE_COMPLETION_ONSTACK(tm_done); /* Wait for rport to unblock */ @@ -1742,23 +1808,25 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) lp = shost_priv(sc->device->host); fnic = lport_priv(lp); + + spin_lock_irqsave(&fnic->fnic_lock, flags); fnic_stats = &fnic->fnic_stats; abts_stats = &fnic->fnic_stats.abts_stats; term_stats = &fnic->fnic_stats.term_stats; rport = starget_to_rport(scsi_target(sc->device)); - FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, - "Abort Cmd called FCID 0x%x, LUN 0x%llx TAG %x flags %x\n", - rport->port_id, sc->device->lun, tag, fnic_priv(sc)->flags); + mqtag = blk_mq_unique_tag(rq); + hwq = blk_mq_unique_tag_to_hwq(mqtag); fnic_priv(sc)->flags = FNIC_NO_FLAGS; if (lp->state != LPORT_ST_READY || !(lp->link_up)) { ret = FAILED; + spin_unlock_irqrestore(&fnic->fnic_lock, flags); goto fnic_abort_cmd_end; } + spin_unlock_irqrestore(&fnic->fnic_lock, flags); /* * Avoid a race between SCSI issuing the abort and the device * completing the command. @@ -1771,18 +1839,17 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) * * .io_req will not be cleared except while holding io_req_lock. */ - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); goto fnic_abort_cmd_end; } io_req->abts_done = &tm_done; if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); goto wait_pending; } @@ -1802,8 +1869,9 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) else atomic64_inc(&abts_stats->abort_issued_greater_than_60_sec); - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "CBD Opcode: %02x Abort issued time: %lu msec\n", sc->cmnd[0], abt_issued_time); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "CDB Opcode: 0x%02x Abort issued time: %lu msec\n", + sc->cmnd[0], abt_issued_time); /* * Command is still pending, need to abort it * If the firmware completes the command after this point, @@ -1814,7 +1882,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) fnic_priv(sc)->state = FNIC_IOREQ_ABTS_PENDING; fnic_priv(sc)->abts_status = FCPIO_INVALID_CODE; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); /* * Check readiness of the remote port. If the path to remote @@ -1831,15 +1899,15 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) /* Now queue the abort command to firmware */ int_to_scsilun(sc->device->lun, &fc_lun); - if (fnic_queue_abort_io_req(fnic, tag, task_req, fc_lun.scsi_lun, - io_req)) { - spin_lock_irqsave(io_lock, flags); + if (fnic_queue_abort_io_req(fnic, mqtag, task_req, fc_lun.scsi_lun, + io_req, hwq)) { + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) fnic_priv(sc)->state = old_ioreq_state; io_req = fnic_priv(sc)->io_req; if (io_req) io_req->abts_done = NULL; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); ret = FAILED; goto fnic_abort_cmd_end; } @@ -1863,12 +1931,12 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) fnic->config.ed_tov)); /* Check the abort status */ - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req) { atomic64_inc(&fnic_stats->io_stats.ioreq_null); - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; ret = FAILED; goto fnic_abort_cmd_end; @@ -1877,7 +1945,7 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) /* fw did not complete abort, timed out */ if (fnic_priv(sc)->abts_status == FCPIO_INVALID_CODE) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if (task_req == FCPIO_ITMF_ABT_TASK) { atomic64_inc(&abts_stats->abort_drv_timeouts); } else { @@ -1891,9 +1959,9 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) /* IO out of order */ if (!(fnic_priv(sc)->flags & (FNIC_IO_ABORTED | FNIC_IO_DONE))) { - spin_unlock_irqrestore(io_lock, flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Issuing Host reset due to out of order IO\n"); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "Issuing host reset due to out of order IO\n"); ret = FAILED; goto fnic_abort_cmd_end; @@ -1907,15 +1975,18 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) * free the io_req if successful. If abort fails, * Device reset will clean the I/O. */ - if (fnic_priv(sc)->abts_status == FCPIO_SUCCESS) { + if (fnic_priv(sc)->abts_status == FCPIO_SUCCESS || + (fnic_priv(sc)->abts_status == FCPIO_ABORTED)) { fnic_priv(sc)->io_req = NULL; + io_req->sc = NULL; } else { ret = FAILED; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); goto fnic_abort_cmd_end; } - spin_unlock_irqrestore(io_lock, flags); + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(mqtag)] = NULL; + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_release_ioreq_buf(fnic, io_req, sc); mempool_free(io_req, fnic->io_req_pool); @@ -1930,14 +2001,14 @@ int fnic_abort_cmd(struct scsi_cmnd *sc) atomic64_inc(&fnic_stats->io_stats.io_completions); fnic_abort_cmd_end: - FNIC_TRACE(fnic_abort_cmd, sc->device->host->host_no, tag, sc, + FNIC_TRACE(fnic_abort_cmd, sc->device->host->host_no, mqtag, sc, jiffies_to_msecs(jiffies - start_time), 0, ((u64)sc->cmnd[0] << 32 | (u64)sc->cmnd[2] << 24 | (u64)sc->cmnd[3] << 16 | (u64)sc->cmnd[4] << 8 | sc->cmnd[5]), fnic_flags_and_state(sc)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Returning from abort cmd type %x %s\n", task_req, (ret == SUCCESS) ? "SUCCESS" : "FAILED"); @@ -1948,33 +2019,34 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic, struct scsi_cmnd *sc, struct fnic_io_req *io_req) { - struct vnic_wq_copy *wq = &fnic->wq_copy[0]; - struct Scsi_Host *host = fnic->lport->host; + struct vnic_wq_copy *wq; struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats; struct scsi_lun fc_lun; int ret = 0; - unsigned long intr_flags; - unsigned int tag = scsi_cmd_to_rq(sc)->tag; + unsigned long flags; + uint16_t hwq = 0; + uint32_t tag = 0; - if (tag == SCSI_NO_TAG) - tag = io_req->tag; + tag = io_req->tag; + hwq = blk_mq_unique_tag_to_hwq(tag); + wq = &fnic->hw_copy_wq[hwq]; - spin_lock_irqsave(host->host_lock, intr_flags); + spin_lock_irqsave(&fnic->fnic_lock, flags); if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED))) { - spin_unlock_irqrestore(host->host_lock, intr_flags); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); return FAILED; } else atomic_inc(&fnic->in_flight); - spin_unlock_irqrestore(host->host_lock, intr_flags); + spin_unlock_irqrestore(&fnic->fnic_lock, flags); - spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); - if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) - free_wq_copy_descs(fnic, wq); + if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[hwq]) + free_wq_copy_descs(fnic, wq, hwq); if (!vnic_wq_copy_desc_avail(wq)) { - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "queue_dr_io_req failure - no descriptors\n"); atomic64_inc(&misc_stats->devrst_cpwq_alloc_failures); ret = -EAGAIN; @@ -1997,7 +2069,7 @@ static inline int fnic_queue_dr_io_req(struct fnic *fnic, atomic64_read(&fnic->fnic_stats.fw_stats.active_fw_reqs)); lr_io_req_end: - spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); atomic_dec(&fnic->in_flight); return ret; @@ -2012,12 +2084,13 @@ struct fnic_pending_aborts_iter_data { static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) { + struct request *const rq = scsi_cmd_to_rq(sc); struct fnic_pending_aborts_iter_data *iter_data = data; struct fnic *fnic = iter_data->fnic; struct scsi_device *lun_dev = iter_data->lun_dev; - int abt_tag = scsi_cmd_to_rq(sc)->tag; + unsigned long abt_tag = 0; + uint16_t hwq = 0; struct fnic_io_req *io_req; - spinlock_t *io_lock; unsigned long flags; struct scsi_lun fc_lun; DECLARE_COMPLETION_ONSTACK(tm_done); @@ -2026,11 +2099,13 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) if (sc == iter_data->lr_sc || sc->device != lun_dev) return true; - io_lock = fnic_io_lock_tag(fnic, abt_tag); - spin_lock_irqsave(io_lock, flags); + abt_tag = blk_mq_unique_tag(rq); + hwq = blk_mq_unique_tag_to_hwq(abt_tag); + + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } @@ -2038,20 +2113,19 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) * Found IO that is still pending with firmware and * belongs to the LUN that we are resetting */ - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Found IO in %s on lun\n", fnic_ioreq_state_to_str(fnic_priv(sc)->state)); if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } if ((fnic_priv(sc)->flags & FNIC_DEVICE_RESET) && (!(fnic_priv(sc)->flags & FNIC_DEV_RST_ISSUED))) { - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "%s dev rst not pending sc 0x%p\n", __func__, - sc); - spin_unlock_irqrestore(io_lock, flags); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "dev rst not pending sc 0x%p\n", sc); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } @@ -2072,35 +2146,37 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) BUG_ON(io_req->abts_done); if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) { - abt_tag |= FNIC_TAG_DEV_RST; - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "%s: dev rst sc 0x%p\n", __func__, sc); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "dev rst sc 0x%p\n", sc); } fnic_priv(sc)->abts_status = FCPIO_INVALID_CODE; io_req->abts_done = &tm_done; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); /* Now queue the abort command to firmware */ int_to_scsilun(sc->device->lun, &fc_lun); if (fnic_queue_abort_io_req(fnic, abt_tag, FCPIO_ITMF_ABT_TASK_TERM, - fc_lun.scsi_lun, io_req)) { - spin_lock_irqsave(io_lock, flags); + fc_lun.scsi_lun, io_req, hwq)) { + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (io_req) io_req->abts_done = NULL; if (fnic_priv(sc)->state == FNIC_IOREQ_ABTS_PENDING) fnic_priv(sc)->state = old_ioreq_state; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); iter_data->ret = FAILED; + FNIC_SCSI_DBG(KERN_ERR, fnic->lport->host, fnic->fnic_num, + "hwq: %d abt_tag: 0x%lx Abort could not be queued\n", + hwq, abt_tag); return false; } else { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); if (fnic_priv(sc)->flags & FNIC_DEVICE_RESET) fnic_priv(sc)->flags |= FNIC_DEV_RST_TERM_ISSUED; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } fnic_priv(sc)->flags |= FNIC_IO_INTERNAL_TERM_ISSUED; @@ -2108,10 +2184,10 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) (fnic->config.ed_tov)); /* Recheck cmd state to check if it is now aborted */ - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_REQ_NULL; return true; } @@ -2120,7 +2196,7 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) /* if abort is still pending with fw, fail */ if (fnic_priv(sc)->abts_status == FCPIO_INVALID_CODE) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_IO_ABT_TERM_DONE; iter_data->ret = FAILED; return false; @@ -2128,9 +2204,11 @@ static bool fnic_pending_aborts_iter(struct scsi_cmnd *sc, void *data) fnic_priv(sc)->state = FNIC_IOREQ_ABTS_COMPLETE; /* original sc used for lr is handled by dev reset code */ - if (sc != iter_data->lr_sc) + if (sc != iter_data->lr_sc) { fnic_priv(sc)->io_req = NULL; - spin_unlock_irqrestore(io_lock, flags); + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(abt_tag)] = NULL; + } + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); /* original sc used for lr is handled by dev reset code */ if (sc != iter_data->lr_sc) { @@ -2182,8 +2260,8 @@ static int fnic_clean_pending_aborts(struct fnic *fnic, ret = 1; clean_pending_aborts_end: - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "%s: exit status: %d\n", __func__, ret); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "exit status: %d\n", ret); return ret; } @@ -2201,15 +2279,15 @@ int fnic_device_reset(struct scsi_cmnd *sc) struct fc_rport *rport; int status; int ret = FAILED; - spinlock_t *io_lock; unsigned long flags; unsigned long start_time = 0; struct scsi_lun fc_lun; struct fnic_stats *fnic_stats; struct reset_stats *reset_stats; - int tag = rq->tag; + int mqtag = rq->tag; DECLARE_COMPLETION_ONSTACK(tm_done); bool new_sc = 0; + uint16_t hwq = 0; /* Wait for rport to unblock */ fc_block_scsi_eh(sc); @@ -2224,9 +2302,10 @@ int fnic_device_reset(struct scsi_cmnd *sc) atomic64_inc(&reset_stats->device_resets); rport = starget_to_rport(scsi_target(sc->device)); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Device reset called FCID 0x%x, LUN 0x%llx sc 0x%p\n", - rport->port_id, sc->device->lun, sc); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "fcid: 0x%x lun: 0x%llx hwq: %d mqtag: 0x%x flags: 0x%x Device reset\n", + rport->port_id, sc->device->lun, hwq, mqtag, + fnic_priv(sc)->flags); if (lp->state != LPORT_ST_READY || !(lp->link_up)) goto fnic_device_reset_end; @@ -2239,7 +2318,7 @@ int fnic_device_reset(struct scsi_cmnd *sc) fnic_priv(sc)->flags = FNIC_DEVICE_RESET; - if (unlikely(tag < 0)) { + if (unlikely(mqtag < 0)) { /* * For device reset issued through sg3utils, we let * only one LUN_RESET to go through and use a special @@ -2248,17 +2327,14 @@ int fnic_device_reset(struct scsi_cmnd *sc) * allocated by mid layer. */ mutex_lock(&fnic->sgreset_mutex); - tag = fnic->fnic_max_tag_id; + mqtag = fnic->fnic_max_tag_id; new_sc = 1; - fnic->sgreset_sc = sc; - io_lock = &fnic->sgreset_lock; - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "fcid: 0x%x lun: 0x%llx flags: 0x%x tag: 0x%x Issuing sgreset\n", - rport->port_id, sc->device->lun, fnic_priv(sc)->flags, tag); - } else - io_lock = fnic_io_lock_hash(fnic, sc); + } else { + mqtag = blk_mq_unique_tag(rq); + hwq = blk_mq_unique_tag_to_hwq(mqtag); + } - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; /* @@ -2268,36 +2344,43 @@ int fnic_device_reset(struct scsi_cmnd *sc) if (!io_req) { io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); goto fnic_device_reset_end; } memset(io_req, 0, sizeof(*io_req)); io_req->port_id = rport->port_id; - io_req->tag = tag; - io_req->sc = sc; + io_req->tag = mqtag; fnic_priv(sc)->io_req = io_req; + io_req->sc = sc; + + if (fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(mqtag)] != NULL) + WARN(1, "fnic<%d>: %s: tag 0x%x already exists\n", + fnic->fnic_num, __func__, blk_mq_unique_tag_to_tag(mqtag)); + + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(mqtag)] = + io_req; } io_req->dr_done = &tm_done; fnic_priv(sc)->state = FNIC_IOREQ_CMD_PENDING; fnic_priv(sc)->lr_status = FCPIO_INVALID_CODE; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "TAG %x\n", tag); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "TAG %x\n", mqtag); /* * issue the device reset, if enqueue failed, clean up the ioreq * and break assoc with scsi cmd */ if (fnic_queue_dr_io_req(fnic, sc, io_req)) { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (io_req) io_req->dr_done = NULL; goto fnic_device_reset_clean; } - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_DEV_RST_ISSUED; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); /* * Wait on the local completion for LUN reset. The io_req may be @@ -2306,12 +2389,12 @@ int fnic_device_reset(struct scsi_cmnd *sc) wait_for_completion_timeout(&tm_done, msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "io_req is null tag 0x%x sc 0x%p\n", tag, sc); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "io_req is null mqtag 0x%x sc 0x%p\n", mqtag, sc); goto fnic_device_reset_end; } io_req->dr_done = NULL; @@ -2324,44 +2407,44 @@ int fnic_device_reset(struct scsi_cmnd *sc) */ if (status == FCPIO_INVALID_CODE) { atomic64_inc(&reset_stats->device_reset_timeouts); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Device reset timed out\n"); fnic_priv(sc)->flags |= FNIC_DEV_RST_TIMED_OUT; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); int_to_scsilun(sc->device->lun, &fc_lun); /* * Issue abort and terminate on device reset request. * If q'ing of terminate fails, retry it after a delay. */ while (1) { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); if (fnic_priv(sc)->flags & FNIC_DEV_RST_TERM_ISSUED) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); break; } - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if (fnic_queue_abort_io_req(fnic, - tag | FNIC_TAG_DEV_RST, + mqtag | FNIC_TAG_DEV_RST, FCPIO_ITMF_ABT_TASK_TERM, - fc_lun.scsi_lun, io_req)) { + fc_lun.scsi_lun, io_req, hwq)) { wait_for_completion_timeout(&tm_done, msecs_to_jiffies(FNIC_ABT_TERM_DELAY_TIMEOUT)); } else { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); fnic_priv(sc)->flags |= FNIC_DEV_RST_TERM_ISSUED; fnic_priv(sc)->state = FNIC_IOREQ_ABTS_PENDING; io_req->abts_done = &tm_done; - spin_unlock_irqrestore(io_lock, flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Abort and terminate issued on Device reset " - "tag 0x%x sc 0x%p\n", tag, sc); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, + "Abort and terminate issued on Device reset mqtag 0x%x sc 0x%p\n", + mqtag, sc); break; } } while (1) { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); if (!(fnic_priv(sc)->flags & FNIC_DEV_RST_DONE)) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); wait_for_completion_timeout(&tm_done, msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); break; @@ -2372,14 +2455,14 @@ int fnic_device_reset(struct scsi_cmnd *sc) } } } else { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); } /* Completed, but not successful, clean up the io_req, return fail */ if (status != FCPIO_SUCCESS) { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); FNIC_SCSI_DBG(KERN_DEBUG, - fnic->lport->host, + fnic->lport->host, fnic->fnic_num, "Device reset completed - failed\n"); io_req = fnic_priv(sc)->io_req; goto fnic_device_reset_clean; @@ -2393,26 +2476,29 @@ int fnic_device_reset(struct scsi_cmnd *sc) * succeeds */ if (fnic_clean_pending_aborts(fnic, sc, new_sc)) { - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Device reset failed" " since could not abort all IOs\n"); goto fnic_device_reset_clean; } /* Clean lun reset command */ - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (io_req) /* Completed, and successful */ ret = SUCCESS; fnic_device_reset_clean: - if (io_req) + if (io_req) { fnic_priv(sc)->io_req = NULL; + io_req->sc = NULL; + fnic->sw_copy_wq[hwq].io_req_table[blk_mq_unique_tag_to_tag(io_req->tag)] = NULL; + } - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if (io_req) { start_time = io_req->start_time; @@ -2433,7 +2519,7 @@ fnic_device_reset_end: mutex_unlock(&fnic->sgreset_mutex); } - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "Returning from device reset %s\n", (ret == SUCCESS) ? "SUCCESS" : "FAILED"); @@ -2456,8 +2542,8 @@ int fnic_reset(struct Scsi_Host *shost) fnic = lport_priv(lp); reset_stats = &fnic->fnic_stats.reset_stats; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "fnic_reset called\n"); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Issuing fnic reset\n"); atomic64_inc(&reset_stats->fnic_resets); @@ -2467,10 +2553,9 @@ int fnic_reset(struct Scsi_Host *shost) */ ret = fc_lport_reset(lp); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, - "Returning from fnic reset %s\n", - (ret == 0) ? - "SUCCESS" : "FAILED"); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "Returning from fnic reset with: %s\n", + (ret == 0) ? "SUCCESS" : "FAILED"); if (ret == 0) atomic64_inc(&reset_stats->fnic_reset_completions); @@ -2503,7 +2588,7 @@ int fnic_host_reset(struct scsi_cmnd *sc) fnic->internal_reset_inprogress = true; } else { spin_unlock_irqrestore(&fnic->fnic_lock, flags); - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "host reset in progress skipping another host reset\n"); return SUCCESS; } @@ -2578,7 +2663,7 @@ retry_fw_reset: spin_lock_irqsave(&fnic->fnic_lock, flags); fnic->remove_wait = NULL; - FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, + FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, fnic->fnic_num, "fnic_scsi_abort_io %s\n", (fnic->state == FNIC_IN_ETH_MODE) ? "SUCCESS" : "FAILED"); @@ -2652,12 +2737,17 @@ call_fc_exch_mgr_reset: static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data) { + struct request *const rq = scsi_cmd_to_rq(sc); struct fnic_pending_aborts_iter_data *iter_data = data; struct fnic *fnic = iter_data->fnic; int cmd_state; struct fnic_io_req *io_req; - spinlock_t *io_lock; unsigned long flags; + uint16_t hwq = 0; + int tag; + + tag = blk_mq_unique_tag(rq); + hwq = blk_mq_unique_tag_to_hwq(tag); /* * ignore this lun reset cmd or cmds that do not belong to @@ -2668,12 +2758,11 @@ static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data) if (iter_data->lun_dev && sc->device != iter_data->lun_dev) return true; - io_lock = fnic_io_lock_hash(fnic, sc); - spin_lock_irqsave(io_lock, flags); + spin_lock_irqsave(&fnic->wq_copy_lock[hwq], flags); io_req = fnic_priv(sc)->io_req; if (!io_req) { - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); return true; } @@ -2681,11 +2770,12 @@ static bool fnic_abts_pending_iter(struct scsi_cmnd *sc, void *data) * Found IO that is still pending with firmware and * belongs to the LUN that we are resetting */ - FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, - "Found IO in %s on lun\n", - fnic_ioreq_state_to_str(fnic_priv(sc)->state)); + FNIC_SCSI_DBG(KERN_INFO, fnic->lport->host, fnic->fnic_num, + "hwq: %d tag: 0x%x Found IO in state: %s on lun\n", + hwq, tag, + fnic_ioreq_state_to_str(fnic_priv(sc)->state)); cmd_state = fnic_priv(sc)->state; - spin_unlock_irqrestore(io_lock, flags); + spin_unlock_irqrestore(&fnic->wq_copy_lock[hwq], flags); if (cmd_state == FNIC_IOREQ_ABTS_PENDING) iter_data->ret = 1; diff --git a/drivers/scsi/fnic/fnic_stats.h b/drivers/scsi/fnic/fnic_stats.h index bdf639eef8cf..9d7f98c452dd 100644 --- a/drivers/scsi/fnic/fnic_stats.h +++ b/drivers/scsi/fnic/fnic_stats.h @@ -2,6 +2,7 @@ /* Copyright 2013 Cisco Systems, Inc. All rights reserved. */ #ifndef _FNIC_STATS_H_ #define _FNIC_STATS_H_ +#define FNIC_MQ_MAX_QUEUES 64 struct stats_timestamps { struct timespec64 last_reset_time; @@ -26,6 +27,7 @@ struct io_path_stats { atomic64_t io_btw_10000_to_30000_msec; atomic64_t io_greater_than_30000_msec; atomic64_t current_max_io_time; + atomic64_t ios[FNIC_MQ_MAX_QUEUES]; }; struct abort_stats { @@ -103,6 +105,7 @@ struct misc_stats { atomic64_t rport_not_ready; atomic64_t frame_errors; atomic64_t current_port_speed; + atomic64_t intx_dummy; }; struct fnic_stats { diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c index be0d7c57b242..aaa4ea02fb7c 100644 --- a/drivers/scsi/fnic/fnic_trace.c +++ b/drivers/scsi/fnic/fnic_trace.c @@ -204,6 +204,7 @@ int fnic_get_stats_data(struct stats_debug_info *debug, int len = 0; int buf_size = debug->buf_size; struct timespec64 val1, val2; + int i = 0; ktime_get_real_ts64(&val1); len = scnprintf(debug->debug_buffer + len, buf_size - len, @@ -267,6 +268,16 @@ int fnic_get_stats_data(struct stats_debug_info *debug, (u64)atomic64_read(&stats->io_stats.io_greater_than_30000_msec)); len += scnprintf(debug->debug_buffer + len, buf_size - len, + "------------------------------------------\n" + "\t\tIO Queues and cumulative IOs\n" + "------------------------------------------\n"); + + for (i = 0; i < FNIC_MQ_MAX_QUEUES; i++) { + len += scnprintf(debug->debug_buffer + len, buf_size - len, + "Q:%d -> %lld\n", i, (u64)atomic64_read(&stats->io_stats.ios[i])); + } + + len += scnprintf(debug->debug_buffer + len, buf_size - len, "\nCurrent Max IO time : %lld\n", (u64)atomic64_read(&stats->io_stats.current_max_io_time)); diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index 3e5b437c0492..e0b173cc9d5f 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -143,6 +143,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; } + pr_info("res_type_wq: %d res_type_rq: %d res_type_cq: %d res_type_intr_ctrl: %d\n", + vdev->res[RES_TYPE_WQ].count, vdev->res[RES_TYPE_RQ].count, + vdev->res[RES_TYPE_CQ].count, vdev->res[RES_TYPE_INTR_CTRL].count); + return 0; } diff --git a/drivers/scsi/fnic/vnic_scsi.h b/drivers/scsi/fnic/vnic_scsi.h index 4e12f7b32d9d..f715f7942bfe 100644 --- a/drivers/scsi/fnic/vnic_scsi.h +++ b/drivers/scsi/fnic/vnic_scsi.h @@ -26,7 +26,7 @@ #define VNIC_FNIC_RATOV_MAX 255000 #define VNIC_FNIC_MAXDATAFIELDSIZE_MIN 256 -#define VNIC_FNIC_MAXDATAFIELDSIZE_MAX 2112 +#define VNIC_FNIC_MAXDATAFIELDSIZE_MAX 2048 #define VNIC_FNIC_FLOGI_RETRIES_MIN 0 #define VNIC_FNIC_FLOGI_RETRIES_MAX 0xffffffff @@ -55,7 +55,7 @@ #define VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX 255 #define VNIC_FNIC_LUNS_PER_TARGET_MIN 1 -#define VNIC_FNIC_LUNS_PER_TARGET_MAX 1024 +#define VNIC_FNIC_LUNS_PER_TARGET_MAX 4096 /* Device-specific region: scsi configuration */ struct vnic_fc_config { @@ -79,10 +79,19 @@ struct vnic_fc_config { u16 ra_tov; u16 intr_timer; u8 intr_timer_type; + u8 intr_mode; + u8 lun_queue_depth; + u8 io_timeout_retry; + u16 wq_copy_count; }; #define VFCF_FCP_SEQ_LVL_ERR 0x1 /* Enable FCP-2 Error Recovery */ #define VFCF_PERBI 0x2 /* persistent binding info available */ #define VFCF_FIP_CAPABLE 0x4 /* firmware can handle FIP */ +#define VFCF_FC_INITIATOR 0x20 /* FC Initiator Mode */ +#define VFCF_FC_TARGET 0x40 /* FC Target Mode */ +#define VFCF_FC_NVME_INITIATOR 0x80 /* FC-NVMe Initiator Mode */ +#define VFCF_FC_NVME_TARGET 0x100 /* FC-NVMe Target Mode */ + #endif /* _VNIC_SCSI_H_ */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d50058b41409..bbb7b2d9ffcf 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1565,12 +1565,12 @@ EXPORT_SYMBOL_GPL(hisi_sas_controller_reset_done); static int hisi_sas_controller_prereset(struct hisi_hba *hisi_hba) { if (!hisi_hba->hw->soft_reset) - return -1; + return -ENOENT; down(&hisi_hba->sem); if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) { up(&hisi_hba->sem); - return -1; + return -EPERM; } if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) @@ -1641,7 +1641,10 @@ static int hisi_sas_abort_task(struct sas_task *task) task->task_state_flags |= SAS_TASK_STATE_ABORTED; spin_unlock_irqrestore(&task->task_state_lock, flags); - if (slot && task->task_proto & SAS_PROTOCOL_SSP) { + if (!slot) + goto out; + + if (task->task_proto & SAS_PROTOCOL_SSP) { u16 tag = slot->idx; int rc2; @@ -1688,7 +1691,7 @@ static int hisi_sas_abort_task(struct sas_task *task) rc = hisi_sas_softreset_ata_disk(device); } } - } else if (slot && task->task_proto & SAS_PROTOCOL_SMP) { + } else if (task->task_proto & SAS_PROTOCOL_SMP) { /* SMP */ u32 tag = slot->idx; struct hisi_sas_cq *cq = &hisi_hba->cq[slot->dlvry_queue]; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index d8437a98037b..b56fbc61a15a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1605,6 +1605,11 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) } phy->port_id = port_id; + spin_lock(&phy->lock); + /* Delete timer and set phy_attached atomically */ + del_timer(&phy->timer); + phy->phy_attached = 1; + spin_unlock(&phy->lock); /* * Call pm_runtime_get_noresume() which pairs with @@ -1618,11 +1623,6 @@ static irqreturn_t phy_up_v3_hw(int phy_no, struct hisi_hba *hisi_hba) res = IRQ_HANDLED; - spin_lock(&phy->lock); - /* Delete timer and set phy_attached atomically */ - del_timer(&phy->timer); - phy->phy_attached = 1; - spin_unlock(&phy->lock); end: if (phy->reset_completion) complete(phy->reset_completion); @@ -3476,7 +3476,7 @@ static void debugfs_snapshot_global_reg_v3_hw(struct hisi_hba *hisi_hba) u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data; int i; - for (i = 0; i < debugfs_axi_reg.count; i++, databuf++) + for (i = 0; i < debugfs_global_reg.count; i++, databuf++) *databuf = hisi_sas_read32(hisi_hba, 4 * i); } @@ -4968,6 +4968,7 @@ static void hisi_sas_reset_done_v3_hw(struct pci_dev *pdev) { struct sas_ha_struct *sha = pci_get_drvdata(pdev); struct hisi_hba *hisi_hba = sha->lldd_ha; + struct Scsi_Host *shost = hisi_hba->shost; struct device *dev = hisi_hba->dev; int rc; @@ -4976,6 +4977,10 @@ static void hisi_sas_reset_done_v3_hw(struct pci_dev *pdev) rc = hw_init_v3_hw(hisi_hba); if (rc) { dev_err(dev, "FLR: hw init failed rc=%d\n", rc); + clear_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags); + scsi_unblock_requests(shost); + clear_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags); + up(&hisi_hba->sem); return; } @@ -5018,7 +5023,7 @@ static int _suspend_v3_hw(struct device *device) } if (test_and_set_bit(HISI_SAS_RESETTING_BIT, &hisi_hba->flags)) - return -1; + return -EPERM; dev_warn(dev, "entering suspend state\n"); diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c index 92c440f2e3a7..46d0b3a0e12f 100644 --- a/drivers/scsi/ibmvscsi/ibmvfc.c +++ b/drivers/scsi/ibmvscsi/ibmvfc.c @@ -1464,7 +1464,7 @@ static void ibmvfc_gather_partition_info(struct ibmvfc_host *vhost) name = of_get_property(rootdn, "ibm,partition-name", NULL); if (name) - strncpy(vhost->partition_name, name, sizeof(vhost->partition_name)); + strscpy(vhost->partition_name, name, sizeof(vhost->partition_name)); num = of_get_property(rootdn, "ibm,partition-no", NULL); if (num) vhost->partition_number = *num; @@ -1513,13 +1513,15 @@ static void ibmvfc_set_login_info(struct ibmvfc_host *vhost) login_info->async.va = cpu_to_be64(vhost->async_crq.msg_token); login_info->async.len = cpu_to_be32(async_crq->size * sizeof(*async_crq->msgs.async)); - strncpy(login_info->partition_name, vhost->partition_name, IBMVFC_MAX_NAME); - strncpy(login_info->device_name, - dev_name(&vhost->host->shost_gendev), IBMVFC_MAX_NAME); + strscpy(login_info->partition_name, vhost->partition_name, + sizeof(login_info->partition_name)); + + strscpy(login_info->device_name, + dev_name(&vhost->host->shost_gendev), sizeof(login_info->device_name)); location = of_get_property(of_node, "ibm,loc-code", NULL); location = location ? location : dev_name(vhost->dev); - strncpy(login_info->drc_name, location, IBMVFC_MAX_NAME); + strscpy(login_info->drc_name, location, sizeof(login_info->drc_name)); } /** diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c index 59599299615d..71f3e9563520 100644 --- a/drivers/scsi/ibmvscsi/ibmvscsi.c +++ b/drivers/scsi/ibmvscsi/ibmvscsi.c @@ -266,7 +266,7 @@ static void set_adapter_info(struct ibmvscsi_host_data *hostdata) dev_info(hostdata->dev, "SRP_VERSION: %s\n", SRP_VERSION); strcpy(hostdata->madapter_info.srp_version, SRP_VERSION); - strncpy(hostdata->madapter_info.partition_name, partition_name, + strscpy(hostdata->madapter_info.partition_name, partition_name, sizeof(hostdata->madapter_info.partition_name)); hostdata->madapter_info.partition_number = diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c index 81e3d464d1f6..3819f7c42788 100644 --- a/drivers/scsi/ipr.c +++ b/drivers/scsi/ipr.c @@ -77,7 +77,6 @@ static LIST_HEAD(ipr_ioa_head); static unsigned int ipr_log_level = IPR_DEFAULT_LOG_LEVEL; static unsigned int ipr_max_speed = 1; -static int ipr_testmode = 0; static unsigned int ipr_fastfail = 0; static unsigned int ipr_transop_timeout = 0; static unsigned int ipr_debug = 0; @@ -193,8 +192,6 @@ module_param_named(max_speed, ipr_max_speed, uint, 0); MODULE_PARM_DESC(max_speed, "Maximum bus speed (0-2). Default: 1=U160. Speeds: 0=80 MB/s, 1=U160, 2=U320"); module_param_named(log_level, ipr_log_level, uint, 0); MODULE_PARM_DESC(log_level, "Set to 0 - 4 for increasing verbosity of device driver"); -module_param_named(testmode, ipr_testmode, int, 0); -MODULE_PARM_DESC(testmode, "DANGEROUS!!! Allows unsupported configurations"); module_param_named(fastfail, ipr_fastfail, int, S_IRUGO | S_IWUSR); MODULE_PARM_DESC(fastfail, "Reduce timeouts and retries"); module_param_named(transop_timeout, ipr_transop_timeout, int, 0); @@ -6416,45 +6413,6 @@ static const struct scsi_host_template driver_template = { .proc_name = IPR_NAME, }; -#ifdef CONFIG_PPC_PSERIES -static const u16 ipr_blocked_processors[] = { - PVR_NORTHSTAR, - PVR_PULSAR, - PVR_POWER4, - PVR_ICESTAR, - PVR_SSTAR, - PVR_POWER4p, - PVR_630, - PVR_630p -}; - -/** - * ipr_invalid_adapter - Determine if this adapter is supported on this hardware - * @ioa_cfg: ioa cfg struct - * - * Adapters that use Gemstone revision < 3.1 do not work reliably on - * certain pSeries hardware. This function determines if the given - * adapter is in one of these confgurations or not. - * - * Return value: - * 1 if adapter is not supported / 0 if adapter is supported - **/ -static int ipr_invalid_adapter(struct ipr_ioa_cfg *ioa_cfg) -{ - int i; - - if ((ioa_cfg->type == 0x5702) && (ioa_cfg->pdev->revision < 4)) { - for (i = 0; i < ARRAY_SIZE(ipr_blocked_processors); i++) { - if (pvr_version_is(ipr_blocked_processors[i])) - return 1; - } - } - return 0; -} -#else -#define ipr_invalid_adapter(ioa_cfg) 0 -#endif - /** * ipr_ioa_bringdown_done - IOA bring down completion. * @ipr_cmd: ipr command struct @@ -7385,19 +7343,6 @@ static int ipr_ioafp_page0_inquiry(struct ipr_cmnd *ipr_cmd) type[4] = '\0'; ioa_cfg->type = simple_strtoul((char *)type, NULL, 16); - if (ipr_invalid_adapter(ioa_cfg)) { - dev_err(&ioa_cfg->pdev->dev, - "Adapter not supported in this hardware configuration.\n"); - - if (!ipr_testmode) { - ioa_cfg->reset_retries += IPR_NUM_RESET_RELOAD_RETRIES; - ipr_initiate_ioa_reset(ioa_cfg, IPR_SHUTDOWN_NONE); - list_add_tail(&ipr_cmd->queue, - &ioa_cfg->hrrq->hrrq_free_q); - return IPR_RC_JOB_RETURN; - } - } - ipr_cmd->job_step = ipr_ioafp_page3_inquiry; ipr_ioafp_inquiry(ipr_cmd, 1, 0, diff --git a/drivers/scsi/isci/request.c b/drivers/scsi/isci/request.c index a7b3243b471d..71f711cb0628 100644 --- a/drivers/scsi/isci/request.c +++ b/drivers/scsi/isci/request.c @@ -738,8 +738,7 @@ static enum sci_status sci_io_request_construct_basic_ssp(struct isci_request *i return SCI_SUCCESS; } -enum sci_status sci_task_request_construct_ssp( - struct isci_request *ireq) +void sci_task_request_construct_ssp(struct isci_request *ireq) { /* Construct the SSP Task SCU Task Context */ scu_ssp_task_request_construct_task_context(ireq); @@ -748,8 +747,6 @@ enum sci_status sci_task_request_construct_ssp( sci_task_request_build_ssp_task_iu(ireq); sci_change_state(&ireq->sm, SCI_REQ_CONSTRUCTED); - - return SCI_SUCCESS; } static enum sci_status sci_io_request_construct_basic_sata(struct isci_request *ireq) diff --git a/drivers/scsi/isci/request.h b/drivers/scsi/isci/request.h index 20b141739e4d..79ddfffbf73c 100644 --- a/drivers/scsi/isci/request.h +++ b/drivers/scsi/isci/request.h @@ -300,7 +300,7 @@ sci_task_request_construct(struct isci_host *ihost, struct isci_remote_device *idev, u16 io_tag, struct isci_request *ireq); -enum sci_status sci_task_request_construct_ssp(struct isci_request *ireq); +void sci_task_request_construct_ssp(struct isci_request *ireq); void sci_smp_request_copy_response(struct isci_request *ireq); static inline int isci_task_is_ncq_recovery(struct sas_task *task) diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c index c514b20293b2..3a25b1a2c52d 100644 --- a/drivers/scsi/isci/task.c +++ b/drivers/scsi/isci/task.c @@ -243,9 +243,7 @@ static struct isci_request *isci_task_request_build(struct isci_host *ihost, /* XXX convert to get this from task->tproto like other drivers */ if (dev->dev_type == SAS_END_DEVICE) { isci_tmf->proto = SAS_PROTOCOL_SSP; - status = sci_task_request_construct_ssp(ireq); - if (status != SCI_SUCCESS) - return NULL; + sci_task_request_construct_ssp(ireq); } return ireq; diff --git a/drivers/scsi/jazz_esp.c b/drivers/scsi/jazz_esp.c index 0c842fb29aa0..494a671fb556 100644 --- a/drivers/scsi/jazz_esp.c +++ b/drivers/scsi/jazz_esp.c @@ -176,7 +176,7 @@ fail: return err; } -static int esp_jazz_remove(struct platform_device *dev) +static void esp_jazz_remove(struct platform_device *dev) { struct esp *esp = dev_get_drvdata(&dev->dev); unsigned int irq = esp->host->irq; @@ -189,8 +189,6 @@ static int esp_jazz_remove(struct platform_device *dev) esp->command_block_dma); scsi_host_put(esp->host); - - return 0; } /* work with hotplug and coldplug */ @@ -198,7 +196,7 @@ MODULE_ALIAS("platform:jazz_esp"); static struct platform_driver esp_jazz_driver = { .probe = esp_jazz_probe, - .remove = esp_jazz_remove, + .remove_new = esp_jazz_remove, .driver = { .name = "jazz_esp", }, diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c index 945adca5e72f..80be3a936d92 100644 --- a/drivers/scsi/libfc/fc_fcp.c +++ b/drivers/scsi/libfc/fc_fcp.c @@ -265,6 +265,11 @@ static int fc_fcp_send_abort(struct fc_fcp_pkt *fsp) if (!fsp->seq_ptr) return -EINVAL; + if (fsp->state & FC_SRB_ABORT_PENDING) { + FC_FCP_DBG(fsp, "abort already pending\n"); + return -EBUSY; + } + this_cpu_inc(fsp->lp->stats->FcpPktAborts); fsp->state |= FC_SRB_ABORT_PENDING; @@ -1671,7 +1676,7 @@ static void fc_fcp_rec_error(struct fc_fcp_pkt *fsp, struct fc_frame *fp) if (fsp->recov_retry++ < FC_MAX_RECOV_RETRY) fc_fcp_rec(fsp); else - fc_fcp_recovery(fsp, FC_ERROR); + fc_fcp_recovery(fsp, FC_TIMED_OUT); break; } fc_fcp_unlock_pkt(fsp); @@ -1690,11 +1695,12 @@ static void fc_fcp_recovery(struct fc_fcp_pkt *fsp, u8 code) fsp->status_code = code; fsp->cdb_status = 0; fsp->io_status = 0; - /* - * if this fails then we let the scsi command timer fire and - * scsi-ml escalate. - */ - fc_fcp_send_abort(fsp); + if (!fsp->cmd) + /* + * Only abort non-scsi commands; otherwise let the + * scsi command timer fire and scsi-ml escalate. + */ + fc_fcp_send_abort(fsp); } /** @@ -2056,9 +2062,9 @@ static void fc_io_compl(struct fc_fcp_pkt *fsp) sc_cmd->result = (DID_PARITY << 16); break; case FC_TIMED_OUT: - FC_FCP_DBG(fsp, "Returning DID_BUS_BUSY to scsi-ml " + FC_FCP_DBG(fsp, "Returning DID_TIME_OUT to scsi-ml " "due to FC_TIMED_OUT\n"); - sc_cmd->result = (DID_BUS_BUSY << 16) | fsp->io_status; + sc_cmd->result = (DID_TIME_OUT << 16); break; default: FC_FCP_DBG(fsp, "Returning DID_ERROR to scsi-ml " diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index af15f7a22d25..04d608ea9106 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -33,6 +33,7 @@ struct lpfc_sli2_slim; #define ELX_MODEL_NAME_SIZE 80 +#define ELX_FW_NAME_SIZE 84 #define LPFC_PCI_DEV_LP 0x1 #define LPFC_PCI_DEV_OC 0x2 diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index b1c9107d3408..d3a5d6ecdf7d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5905,11 +5905,11 @@ LPFC_ATTR_RW(ras_fwlog_level, 0, 0, 4, "Firmware Logging Level"); /* * lpfc_ras_fwlog_func: Firmware logging enabled on function number * Default function which has RAS support : 0 - * Value Range is [0..7]. + * Value Range is [0..3]. * FW logging is a global action and enablement is via a specific * port. */ -LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 7, "Firmware Logging Enabled on Function"); +LPFC_ATTR_RW(ras_fwlog_func, 0, 0, 3, "Firmware Logging Enabled on Function"); /* * lpfc_enable_bbcr: Enable BB Credit Recovery @@ -5954,7 +5954,7 @@ LPFC_ATTR_R(enable_mi, 1, 0, 1, "Enable MI"); * 4 - 255 = vmid support enabled for 4-255 VMs * Value range is [4,255]. */ -LPFC_ATTR_RW(max_vmid, LPFC_MIN_VMID, LPFC_MIN_VMID, LPFC_MAX_VMID, +LPFC_ATTR_R(max_vmid, LPFC_MIN_VMID, LPFC_MIN_VMID, LPFC_MAX_VMID, "Maximum number of VMs supported"); /* @@ -5962,7 +5962,7 @@ LPFC_ATTR_RW(max_vmid, LPFC_MIN_VMID, LPFC_MIN_VMID, LPFC_MAX_VMID, * 0 = Timeout is disabled * Value range is [0,24]. */ -LPFC_ATTR_RW(vmid_inactivity_timeout, 4, 0, 24, +LPFC_ATTR_R(vmid_inactivity_timeout, 4, 0, 24, "Inactivity timeout in hours"); /* @@ -5971,7 +5971,7 @@ LPFC_ATTR_RW(vmid_inactivity_timeout, 4, 0, 24, * 1 = Support is enabled * Value range is [0,1]. */ -LPFC_ATTR_RW(vmid_app_header, LPFC_VMID_APP_HEADER_DISABLE, +LPFC_ATTR_R(vmid_app_header, LPFC_VMID_APP_HEADER_DISABLE, LPFC_VMID_APP_HEADER_DISABLE, LPFC_VMID_APP_HEADER_ENABLE, "Enable App Header VMID support"); @@ -5982,7 +5982,7 @@ LPFC_ATTR_RW(vmid_app_header, LPFC_VMID_APP_HEADER_DISABLE, * 2 = Allow all targets * Value range is [0,2]. */ -LPFC_ATTR_RW(vmid_priority_tagging, LPFC_VMID_PRIO_TAG_DISABLE, +LPFC_ATTR_R(vmid_priority_tagging, LPFC_VMID_PRIO_TAG_DISABLE, LPFC_VMID_PRIO_TAG_DISABLE, LPFC_VMID_PRIO_TAG_ALL_TARGETS, "Enable Priority Tagging VMID support"); diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index f9627eddab08..4d723200690a 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1130,12 +1130,12 @@ stop_rr_fcf_flogi: vport->port_state, vport->fc_flag, sp->cmn.priority_tagging, kref_read(&ndlp->kref)); - if (sp->cmn.priority_tagging) - vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | - LPFC_VMID_TYPE_PRIO); /* reinitialize the VMID datastructure before returning */ if (lpfc_is_vmid_enabled(phba)) lpfc_reinit_vmid(vport); + if (sp->cmn.priority_tagging) + vport->phba->pport->vmid_flag |= (LPFC_VMID_ISSUE_QFPA | + LPFC_VMID_TYPE_PRIO); /* * Address a timing race with dev_loss. If dev_loss is active on @@ -2062,8 +2062,9 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* PLOGI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0102 PLOGI completes to NPort x%06x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, ndlp->nlp_fc4_type, + "IoTag x%x Data: x%x x%x x%x x%x x%x\n", + ndlp->nlp_DID, iotag, + ndlp->nlp_fc4_type, ulp_status, ulp_word4, disc, vport->num_disc_nodes); @@ -2128,8 +2129,8 @@ lpfc_cmpl_els_plogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, NLP_EVT_DEVICE_RM); } else { /* Good status, call state machine */ - prsp = list_entry(cmdiocb->cmd_dmabuf->list.next, - struct lpfc_dmabuf, list); + prsp = list_get_first(&cmdiocb->cmd_dmabuf->list, + struct lpfc_dmabuf, list); if (!prsp) goto out; if (!lpfc_is_els_acc_rsp(prsp)) @@ -2362,9 +2363,10 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* PRLI completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0103 PRLI completes to NPort x%06x " - "Data: x%x x%x x%x x%x\n", + "Data: x%x x%x x%x x%x x%x\n", ndlp->nlp_DID, ulp_status, ulp_word4, - vport->num_disc_nodes, ndlp->fc4_prli_sent); + vport->num_disc_nodes, ndlp->fc4_prli_sent, + ndlp->fc4_xpt_flags); /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) @@ -2805,7 +2807,7 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, IOCB_t *irsp; struct lpfc_nodelist *ndlp; int disc; - u32 ulp_status, ulp_word4, tmo; + u32 ulp_status, ulp_word4, tmo, iotag; bool release_node = false; /* we pass cmdiocb to state machine which needs rspiocb as well */ @@ -2818,9 +2820,11 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (phba->sli_rev == LPFC_SLI_REV4) { tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); } else { irsp = &rspiocb->iocb; tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; } lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, @@ -2838,9 +2842,11 @@ lpfc_cmpl_els_adisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* ADISC completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0104 ADISC completes to NPort x%x " - "Data: x%x x%x x%x x%x x%x\n", - ndlp->nlp_DID, ulp_status, ulp_word4, + "IoTag x%x Data: x%x x%x x%x x%x x%x\n", + ndlp->nlp_DID, iotag, + ulp_status, ulp_word4, tmo, disc, vport->num_disc_nodes); + /* Check to see if link went down during discovery */ if (lpfc_els_chk_latt(vport)) { spin_lock_irq(&ndlp->lock); @@ -3001,7 +3007,7 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, int wake_up_waiter = 0; u32 ulp_status; u32 ulp_word4; - u32 tmo; + u32 tmo, iotag; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->rsp_iocb = rspiocb; @@ -3011,9 +3017,11 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (phba->sli_rev == LPFC_SLI_REV4) { tmo = get_wqe_tmo(cmdiocb); + iotag = get_wqe_reqtag(cmdiocb); } else { irsp = &rspiocb->iocb; tmo = irsp->ulpTimeout; + iotag = irsp->ulpIoTag; } spin_lock_irq(&ndlp->lock); @@ -3032,9 +3040,11 @@ lpfc_cmpl_els_logo(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* LOGO completes to NPort <nlp_DID> */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0105 LOGO completes to NPort x%x " - "refcnt %d nflags x%x Data: x%x x%x x%x x%x\n", - ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp->nlp_flag, - ulp_status, ulp_word4, + "IoTag x%x refcnt %d nflags x%x xflags x%x " + "Data: x%x x%x x%x x%x\n", + ndlp->nlp_DID, iotag, + kref_read(&ndlp->kref), ndlp->nlp_flag, + ndlp->fc4_xpt_flags, ulp_status, ulp_word4, tmo, vport->num_disc_nodes); if (lpfc_els_chk_latt(vport)) { @@ -5075,16 +5085,19 @@ out_retry: if (logerr) { lpfc_printf_vlog(vport, KERN_ERR, LOG_TRACE_EVENT, "0137 No retry ELS command x%x to remote " - "NPORT x%x: Out of Resources: Error:x%x/%x\n", - cmd, did, ulp_status, - ulp_word4); + "NPORT x%x: Out of Resources: Error:x%x/%x " + "IoTag x%x\n", + cmd, did, ulp_status, ulp_word4, + cmdiocb->iotag); } else { lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0108 No retry ELS command x%x to remote " - "NPORT x%x Retried:%d Error:x%x/%x\n", - cmd, did, cmdiocb->retry, ulp_status, - ulp_word4); + "0108 No retry ELS command x%x to remote " + "NPORT x%x Retried:%d Error:x%x/%x " + "IoTag x%x nflags x%x\n", + cmd, did, cmdiocb->retry, ulp_status, + ulp_word4, cmdiocb->iotag, + (ndlp ? ndlp->nlp_flag : 0)); } return 0; } @@ -11130,6 +11143,14 @@ mbox_err_exit: lpfc_nlp_put(ndlp); mempool_free(pmb, phba->mbox_mem_pool); + + /* reinitialize the VMID datastructure before returning. + * this is specifically for vport + */ + if (lpfc_is_vmid_enabled(phba)) + lpfc_reinit_vmid(vport); + vport->vmid_flag = vport->phba->pport->vmid_flag; + return; } diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 7ef9841f0728..f80bbc315f4c 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -411,7 +411,7 @@ lpfc_check_nlp_post_devloss(struct lpfc_vport *vport, "port_state = x%x\n", ndlp->nlp_DID, kref_read(&ndlp->kref), ndlp, ndlp->nlp_flag, vport->port_state); - spin_lock_irqsave(&ndlp->lock, iflags); + return; } spin_unlock_irqrestore(&ndlp->lock, iflags); } diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e7c47ee185a4..70bcee64bc8c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -14721,7 +14721,7 @@ out: int lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) { - uint8_t file_name[ELX_MODEL_NAME_SIZE]; + char file_name[ELX_FW_NAME_SIZE] = {0}; int ret; const struct firmware *fw; @@ -14730,7 +14730,7 @@ lpfc_sli4_request_firmware_update(struct lpfc_hba *phba, uint8_t fw_upgrade) LPFC_SLI_INTF_IF_TYPE_2) return -EPERM; - snprintf(file_name, ELX_MODEL_NAME_SIZE, "%s.grp", phba->ModelName); + scnprintf(file_name, sizeof(file_name), "%s.grp", phba->ModelName); if (fw_upgrade == INT_FW_UPGRADE) { ret = request_firmware_nowait(THIS_MODULE, FW_ACTION_UEVENT, diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 0dfdc0c4c08c..cadcd16494e1 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -1814,7 +1814,9 @@ lpfc_sli4_mbox_cmd_free(struct lpfc_hba *phba, struct lpfcMboxq *mbox) dma_free_coherent(&phba->pcidev->dev, SLI4_PAGE_SIZE, mbox->sge_array->addr[sgentry], phyaddr); } - /* Free the sge address array memory */ + /* Reinitialize the context pointers to avoid stale usage. */ + mbox->ctx_buf = NULL; + mbox->context3 = NULL; kfree(mbox->sge_array); /* Finally, free the mailbox command itself */ mempool_free(mbox, phba->mbox_mem_pool); diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index 89cbeba06aea..2697da3248b3 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2014 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -48,6 +48,29 @@ #define LPFC_RRQ_POOL_SIZE 256 /* max elements in non-DMA pool */ #define LPFC_MBX_POOL_SIZE 256 /* max elements in MBX non-DMA pool */ +/* lpfc_mbox_free_sli_mbox + * + * @phba: HBA to free memory for + * @mbox: mailbox command to free + * + * This routine detects the mbox type and calls the correct + * free routine to fully release all associated memory. + */ +static void +lpfc_mem_free_sli_mbox(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox) +{ + /* Detect if the caller's mbox is an SLI4_CONFIG type. If so, this + * mailbox type requires a different cleanup routine. Otherwise, the + * mailbox is just an mbuf and mem_pool release. + */ + if (phba->sli_rev == LPFC_SLI_REV4 && + bf_get(lpfc_mqe_command, &mbox->u.mqe) == MBX_SLI4_CONFIG) { + lpfc_sli4_mbox_cmd_free(phba, mbox); + } else { + lpfc_mbox_rsrc_cleanup(phba, mbox, MBOX_THD_UNLOCKED); + } +} + int lpfc_mem_alloc_active_rrq_pool_s4(struct lpfc_hba *phba) { size_t bytes; @@ -288,27 +311,16 @@ lpfc_mem_free_all(struct lpfc_hba *phba) { struct lpfc_sli *psli = &phba->sli; LPFC_MBOXQ_t *mbox, *next_mbox; - struct lpfc_dmabuf *mp; /* Free memory used in mailbox queue back to mailbox memory pool */ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq, list) { - mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } list_del(&mbox->list); - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_mem_free_sli_mbox(phba, mbox); } /* Free memory used in mailbox cmpl list back to mailbox memory pool */ list_for_each_entry_safe(mbox, next_mbox, &psli->mboxq_cmpl, list) { - mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } list_del(&mbox->list); - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_mem_free_sli_mbox(phba, mbox); } /* Free the active mailbox command back to the mailbox memory pool */ spin_lock_irq(&phba->hbalock); @@ -316,12 +328,7 @@ lpfc_mem_free_all(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); if (psli->mbox_active) { mbox = psli->mbox_active; - mp = (struct lpfc_dmabuf *)(mbox->ctx_buf); - if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - } - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_mem_free_sli_mbox(phba, mbox); psli->mbox_active = NULL; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 9386e7b44750..46e6f807d1ca 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2995,8 +2995,9 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) LPFC_SLI_INTF_IF_TYPE_2)) { if (ndlp) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_MBOX | LOG_SLI, - "0010 UNREG_LOGIN vpi:%x " + vport, KERN_INFO, + LOG_MBOX | LOG_SLI | LOG_NODE, + "0010 UNREG_LOGIN vpi:x%x " "rpi:%x DID:%x defer x%x flg x%x " "x%px\n", vport->vpi, ndlp->nlp_rpi, @@ -3012,7 +3013,8 @@ lpfc_sli4_unreg_rpi_cmpl_clr(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) (ndlp->nlp_defer_did != NLP_EVT_NOTHING_PENDING)) { lpfc_printf_vlog( - vport, KERN_INFO, LOG_DISCOVERY, + vport, KERN_INFO, + LOG_MBOX | LOG_SLI | LOG_NODE, "4111 UNREG cmpl deferred " "clr x%x on " "NPort x%x Data: x%x x%px\n", @@ -3938,6 +3940,9 @@ void lpfc_poll_eratt(struct timer_list *t) if (!(phba->hba_flag & HBA_SETUP)) return; + if (phba->pport->load_flag & FC_UNLOADING) + return; + /* Here we will also keep track of interrupts per sec of the hba */ sli_intr = phba->sli.slistat.sli_intr; @@ -10141,11 +10146,12 @@ lpfc_sli_issue_mbox_s4(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq, spin_unlock_irqrestore(&phba->hbalock, iflags); lpfc_printf_log(phba, KERN_INFO, LOG_MBOX | LOG_SLI, "(%d):0354 Mbox cmd issue - Enqueue Data: " - "x%x (x%x/x%x) x%x x%x x%x\n", + "x%x (x%x/x%x) x%x x%x x%x x%x\n", mboxq->vport ? mboxq->vport->vpi : 0xffffff, bf_get(lpfc_mqe_command, &mboxq->u.mqe), lpfc_sli_config_mbox_subsys_get(phba, mboxq), lpfc_sli_config_mbox_opcode_get(phba, mboxq), + mboxq->u.mb.un.varUnregLogin.rpi, phba->pport->port_state, psli->sli_flag, MBX_NOWAIT); /* Wake up worker thread to transport mailbox command from head */ @@ -22167,6 +22173,12 @@ struct lpfc_io_buf *lpfc_get_io_buf(struct lpfc_hba *phba, * The data will be truncated if datasz is not large enough. * Version 1 is not supported with Embedded mbox cmd, so we must use version 0. * Returns the actual bytes read from the object. + * + * This routine is hard coded to use a poll completion. Unlike other + * sli4_config mailboxes, it uses lpfc_mbuf memory which is not + * cleaned up in lpfc_sli4_cmd_mbox_free. If this routine is modified + * to use interrupt-based completions, code is needed to fully cleanup + * the memory. */ int lpfc_read_object(struct lpfc_hba *phba, char *rdobject, uint32_t *datap, diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index cd33dfec758c..c911a39cb46b 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2017-2022 Broadcom. All Rights Reserved. The term * + * Copyright (C) 2017-2023 Broadcom. All Rights Reserved. The term * * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. * * Copyright (C) 2004-2016 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * @@ -182,9 +182,11 @@ typedef struct lpfcMboxq { struct lpfc_mqe mqe; } u; struct lpfc_vport *vport; /* virtual port pointer */ - void *ctx_ndlp; /* caller ndlp information */ - void *ctx_buf; /* caller buffer information */ - void *context3; + void *ctx_ndlp; /* an lpfc_nodelist pointer */ + void *ctx_buf; /* an lpfc_dmabuf pointer */ + void *context3; /* a generic pointer. Code must + * accommodate the actual datatype. + */ void (*mbox_cmpl) (struct lpfc_hba *, struct lpfcMboxq *); uint8_t mbox_flag; diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 88068834cab9..aba1c1cee8c4 100644 --- a/drivers/scsi/lpfc/lpfc_version.h +++ b/drivers/scsi/lpfc/lpfc_version.h @@ -20,7 +20,7 @@ * included with this package. * *******************************************************************/ -#define LPFC_DRIVER_VERSION "14.2.0.15" +#define LPFC_DRIVER_VERSION "14.2.0.17" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ diff --git a/drivers/scsi/lpfc/lpfc_vmid.c b/drivers/scsi/lpfc/lpfc_vmid.c index cf8ba840d0ea..773e02ae20c3 100644 --- a/drivers/scsi/lpfc/lpfc_vmid.c +++ b/drivers/scsi/lpfc/lpfc_vmid.c @@ -321,5 +321,6 @@ lpfc_reinit_vmid(struct lpfc_vport *vport) if (!hash_empty(vport->hash_table)) hash_for_each_safe(vport->hash_table, bucket, tmp, cur, hnode) hash_del(&cur->hnode); + vport->vmid_flag = 0; write_unlock(&vport->vmid_lock); } diff --git a/drivers/scsi/mac_esp.c b/drivers/scsi/mac_esp.c index 3f0061b00494..187ae0a65d40 100644 --- a/drivers/scsi/mac_esp.c +++ b/drivers/scsi/mac_esp.c @@ -407,7 +407,7 @@ fail: return err; } -static int esp_mac_remove(struct platform_device *dev) +static void esp_mac_remove(struct platform_device *dev) { struct mac_esp_priv *mep = platform_get_drvdata(dev); struct esp *esp = mep->esp; @@ -428,13 +428,11 @@ static int esp_mac_remove(struct platform_device *dev) kfree(esp->command_block); scsi_host_put(esp->host); - - return 0; } static struct platform_driver esp_mac_driver = { .probe = esp_mac_probe, - .remove = esp_mac_remove, + .remove_new = esp_mac_remove, .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 2e511697fce3..181f16899fdc 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -523,7 +523,7 @@ fail_init: return error; } -static int __exit mac_scsi_remove(struct platform_device *pdev) +static void __exit mac_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); @@ -532,11 +532,10 @@ static int __exit mac_scsi_remove(struct platform_device *pdev) free_irq(instance->irq, instance); NCR5380_exit(instance); scsi_host_put(instance); - return 0; } static struct platform_driver mac_scsi_driver = { - .remove = __exit_p(mac_scsi_remove), + .remove_new = __exit_p(mac_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h index 1e4a60fc655f..0cb24fc03620 100644 --- a/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h +++ b/drivers/scsi/mpi3mr/mpi/mpi30_ioc.h @@ -28,6 +28,7 @@ struct mpi3_ioc_init_request { __le64 driver_information_address; }; +#define MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED (0x04) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_MASK (0x03) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_NOT_USED (0x00) #define MPI3_IOCINIT_MSGFLAGS_HOSTMETADATA_SEPARATED (0x01) diff --git a/drivers/scsi/mpi3mr/mpi3mr.h b/drivers/scsi/mpi3mr/mpi3mr.h index ae98d15c30b1..3de1ee05c44e 100644 --- a/drivers/scsi/mpi3mr/mpi3mr.h +++ b/drivers/scsi/mpi3mr/mpi3mr.h @@ -55,8 +55,8 @@ extern struct list_head mrioc_list; extern int prot_mask; extern atomic64_t event_counter; -#define MPI3MR_DRIVER_VERSION "8.5.0.0.0" -#define MPI3MR_DRIVER_RELDATE "24-July-2023" +#define MPI3MR_DRIVER_VERSION "8.5.1.0.0" +#define MPI3MR_DRIVER_RELDATE "5-December-2023" #define MPI3MR_DRIVER_NAME "mpi3mr" #define MPI3MR_DRIVER_LICENSE "GPL" @@ -218,14 +218,16 @@ extern atomic64_t event_counter; * @length: SGE length * @rsvd: Reserved * @rsvd1: Reserved - * @sgl_type: sgl type + * @sub_type: sgl sub type + * @type: sgl type */ struct mpi3mr_nvme_pt_sge { - u64 base_addr; - u32 length; + __le64 base_addr; + __le32 length; u16 rsvd; u8 rsvd1; - u8 sgl_type; + u8 sub_type:4; + u8 type:4; }; /** @@ -247,6 +249,8 @@ struct mpi3mr_buf_map { u32 kern_buf_len; dma_addr_t kern_buf_dma; u8 data_dir; + u16 num_dma_desc; + struct dma_memory_desc *dma_desc; }; /* IOC State definitions */ @@ -477,6 +481,10 @@ struct mpi3mr_throttle_group_info { /* HBA port flags */ #define MPI3MR_HBA_PORT_FLAG_DIRTY 0x01 +/* IOCTL data transfer sge*/ +#define MPI3MR_NUM_IOCTL_SGE 256 +#define MPI3MR_IOCTL_SGE_SIZE (8 * 1024) + /** * struct mpi3mr_hba_port - HBA's port information * @port_id: Port number @@ -506,7 +514,7 @@ struct mpi3mr_sas_port { u8 num_phys; u8 marked_responding; int lowest_phy; - u32 phy_mask; + u64 phy_mask; struct mpi3mr_hba_port *hba_port; struct sas_identify remote_identify; struct sas_rphy *rphy; @@ -1042,6 +1050,11 @@ struct scmd_priv { * @sas_node_lock: Lock to protect SAS node list * @hba_port_table_list: List of HBA Ports * @enclosure_list: List of Enclosure objects + * @ioctl_dma_pool: DMA pool for IOCTL data buffers + * @ioctl_sge: DMA buffer descriptors for IOCTL data + * @ioctl_chain_sge: DMA buffer descriptor for IOCTL chain + * @ioctl_resp_sge: DMA buffer descriptor for Mgmt cmd response + * @ioctl_sges_allocated: Flag for IOCTL SGEs allocated or not */ struct mpi3mr_ioc { struct list_head list; @@ -1227,6 +1240,12 @@ struct mpi3mr_ioc { spinlock_t sas_node_lock; struct list_head hba_port_table_list; struct list_head enclosure_list; + + struct dma_pool *ioctl_dma_pool; + struct dma_memory_desc ioctl_sge[MPI3MR_NUM_IOCTL_SGE]; + struct dma_memory_desc ioctl_chain_sge; + struct dma_memory_desc ioctl_resp_sge; + bool ioctl_sges_allocated; }; /** diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c index 08645a99ad6b..0380996b5ad2 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_app.c +++ b/drivers/scsi/mpi3mr/mpi3mr_app.c @@ -223,6 +223,22 @@ static long mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc, return rval; } + if (mrioc->unrecoverable) { + dprint_bsg_err(mrioc, "%s: unrecoverable controller\n", + __func__); + return -EFAULT; + } + + if (mrioc->reset_in_progress) { + dprint_bsg_err(mrioc, "%s: reset in progress\n", __func__); + return -EAGAIN; + } + + if (mrioc->stop_bsgs) { + dprint_bsg_err(mrioc, "%s: bsgs are blocked\n", __func__); + return -EAGAIN; + } + sg_copy_to_buffer(job->request_payload.sg_list, job->request_payload.sg_cnt, &pel_enable, sizeof(pel_enable)); @@ -548,7 +564,36 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job) } /** + * mpi3mr_total_num_ioctl_sges - Count number of SGEs required + * @drv_bufs: DMA address of the buffers to be placed in sgl + * @bufcnt: Number of DMA buffers + * + * This function returns total number of data SGEs required + * including zero length SGEs and excluding management request + * and response buffer for the given list of data buffer + * descriptors + * + * Return: Number of SGE elements needed + */ +static inline u16 mpi3mr_total_num_ioctl_sges(struct mpi3mr_buf_map *drv_bufs, + u8 bufcnt) +{ + u16 i, sge_count = 0; + + for (i = 0; i < bufcnt; i++, drv_bufs++) { + if (drv_bufs->data_dir == DMA_NONE || + drv_bufs->kern_buf) + continue; + sge_count += drv_bufs->num_dma_desc; + if (!drv_bufs->num_dma_desc) + sge_count++; + } + return sge_count; +} + +/** * mpi3mr_bsg_build_sgl - SGL construction for MPI commands + * @mrioc: Adapter instance reference * @mpi_req: MPI request * @sgl_offset: offset to start sgl in the MPI request * @drv_bufs: DMA address of the buffers to be placed in sgl @@ -560,27 +605,45 @@ static long mpi3mr_bsg_process_drv_cmds(struct bsg_job *job) * This function places the DMA address of the given buffers in * proper format as SGEs in the given MPI request. * - * Return: Nothing + * Return: 0 on success,-1 on failure */ -static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset, - struct mpi3mr_buf_map *drv_bufs, u8 bufcnt, u8 is_rmc, - u8 is_rmr, u8 num_datasges) +static int mpi3mr_bsg_build_sgl(struct mpi3mr_ioc *mrioc, u8 *mpi_req, + u32 sgl_offset, struct mpi3mr_buf_map *drv_bufs, + u8 bufcnt, u8 is_rmc, u8 is_rmr, u8 num_datasges) { + struct mpi3_request_header *mpi_header = + (struct mpi3_request_header *)mpi_req; u8 *sgl = (mpi_req + sgl_offset), count = 0; struct mpi3_mgmt_passthrough_request *rmgmt_req = (struct mpi3_mgmt_passthrough_request *)mpi_req; struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; - u8 sgl_flags, sgl_flags_last; + u8 flag, sgl_flags, sgl_flag_eob, sgl_flags_last, last_chain_sgl_flag; + u16 available_sges, i, sges_needed; + u32 sge_element_size = sizeof(struct mpi3_sge_common); + bool chain_used = false; sgl_flags = MPI3_SGE_FLAGS_ELEMENT_TYPE_SIMPLE | - MPI3_SGE_FLAGS_DLAS_SYSTEM | MPI3_SGE_FLAGS_END_OF_BUFFER; - sgl_flags_last = sgl_flags | MPI3_SGE_FLAGS_END_OF_LIST; + MPI3_SGE_FLAGS_DLAS_SYSTEM; + sgl_flag_eob = sgl_flags | MPI3_SGE_FLAGS_END_OF_BUFFER; + sgl_flags_last = sgl_flag_eob | MPI3_SGE_FLAGS_END_OF_LIST; + last_chain_sgl_flag = MPI3_SGE_FLAGS_ELEMENT_TYPE_LAST_CHAIN | + MPI3_SGE_FLAGS_DLAS_SYSTEM; + + sges_needed = mpi3mr_total_num_ioctl_sges(drv_bufs, bufcnt); if (is_rmc) { mpi3mr_add_sg_single(&rmgmt_req->command_sgl, sgl_flags_last, drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); - sgl = (u8 *)drv_buf_iter->kern_buf + drv_buf_iter->bsg_buf_len; + sgl = (u8 *)drv_buf_iter->kern_buf + + drv_buf_iter->bsg_buf_len; + available_sges = (drv_buf_iter->kern_buf_len - + drv_buf_iter->bsg_buf_len) / sge_element_size; + + if (sges_needed > available_sges) + return -1; + + chain_used = true; drv_buf_iter++; count++; if (is_rmr) { @@ -592,23 +655,95 @@ static void mpi3mr_bsg_build_sgl(u8 *mpi_req, uint32_t sgl_offset, } else mpi3mr_build_zero_len_sge( &rmgmt_req->response_sgl); + if (num_datasges) { + i = 0; + goto build_sges; + } + } else { + if (sgl_offset >= MPI3MR_ADMIN_REQ_FRAME_SZ) + return -1; + available_sges = (MPI3MR_ADMIN_REQ_FRAME_SZ - sgl_offset) / + sge_element_size; + if (!available_sges) + return -1; } if (!num_datasges) { mpi3mr_build_zero_len_sge(sgl); - return; + return 0; } + if (mpi_header->function == MPI3_BSG_FUNCTION_SMP_PASSTHROUGH) { + if ((sges_needed > 2) || (sges_needed > available_sges)) + return -1; + for (; count < bufcnt; count++, drv_buf_iter++) { + if (drv_buf_iter->data_dir == DMA_NONE || + !drv_buf_iter->num_dma_desc) + continue; + mpi3mr_add_sg_single(sgl, sgl_flags_last, + drv_buf_iter->dma_desc[0].size, + drv_buf_iter->dma_desc[0].dma_addr); + sgl += sge_element_size; + } + return 0; + } + i = 0; + +build_sges: for (; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - if (num_datasges == 1 || !is_rmc) - mpi3mr_add_sg_single(sgl, sgl_flags_last, - drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); - else - mpi3mr_add_sg_single(sgl, sgl_flags, - drv_buf_iter->kern_buf_len, drv_buf_iter->kern_buf_dma); - sgl += sizeof(struct mpi3_sge_common); + if (!drv_buf_iter->num_dma_desc) { + if (chain_used && !available_sges) + return -1; + if (!chain_used && (available_sges == 1) && + (sges_needed > 1)) + goto setup_chain; + flag = sgl_flag_eob; + if (num_datasges == 1) + flag = sgl_flags_last; + mpi3mr_add_sg_single(sgl, flag, 0, 0); + sgl += sge_element_size; + sges_needed--; + available_sges--; + num_datasges--; + continue; + } + for (; i < drv_buf_iter->num_dma_desc; i++) { + if (chain_used && !available_sges) + return -1; + if (!chain_used && (available_sges == 1) && + (sges_needed > 1)) + goto setup_chain; + flag = sgl_flags; + if (i == (drv_buf_iter->num_dma_desc - 1)) { + if (num_datasges == 1) + flag = sgl_flags_last; + else + flag = sgl_flag_eob; + } + + mpi3mr_add_sg_single(sgl, flag, + drv_buf_iter->dma_desc[i].size, + drv_buf_iter->dma_desc[i].dma_addr); + sgl += sge_element_size; + available_sges--; + sges_needed--; + } num_datasges--; + i = 0; } + return 0; + +setup_chain: + available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; + if (sges_needed > available_sges) + return -1; + mpi3mr_add_sg_single(sgl, last_chain_sgl_flag, + (sges_needed * sge_element_size), + mrioc->ioctl_chain_sge.dma_addr); + memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); + sgl = (u8 *)mrioc->ioctl_chain_sge.addr; + chain_used = true; + goto build_sges; } /** @@ -648,14 +783,20 @@ static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc, struct mpi3mr_buf_map *drv_bufs, u8 bufcnt) { struct mpi3mr_nvme_pt_sge *nvme_sgl; - u64 sgl_ptr; + __le64 sgl_dma; u8 count; size_t length = 0; + u16 available_sges = 0, i; + u32 sge_element_size = sizeof(struct mpi3mr_nvme_pt_sge); struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << mrioc->facts.sge_mod_shift) << 32); u64 sgemod_val = ((u64)(mrioc->facts.sge_mod_value) << mrioc->facts.sge_mod_shift) << 32; + u32 size; + + nvme_sgl = (struct mpi3mr_nvme_pt_sge *) + ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); /* * Not all commands require a data transfer. If no data, just return @@ -664,27 +805,59 @@ static int mpi3mr_build_nvme_sgl(struct mpi3mr_ioc *mrioc, for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - sgl_ptr = (u64)drv_buf_iter->kern_buf_dma; length = drv_buf_iter->kern_buf_len; break; } - if (!length) + if (!length || !drv_buf_iter->num_dma_desc) return 0; - if (sgl_ptr & sgemod_mask) { + if (drv_buf_iter->num_dma_desc == 1) { + available_sges = 1; + goto build_sges; + } + + sgl_dma = cpu_to_le64(mrioc->ioctl_chain_sge.dma_addr); + if (sgl_dma & sgemod_mask) { dprint_bsg_err(mrioc, - "%s: SGL address collides with SGE modifier\n", + "%s: SGL chain address collides with SGE modifier\n", __func__); return -1; } - sgl_ptr &= ~sgemod_mask; - sgl_ptr |= sgemod_val; - nvme_sgl = (struct mpi3mr_nvme_pt_sge *) - ((u8 *)(nvme_encap_request->command) + MPI3MR_NVME_CMD_SGL_OFFSET); + sgl_dma &= ~sgemod_mask; + sgl_dma |= sgemod_val; + + memset(mrioc->ioctl_chain_sge.addr, 0, mrioc->ioctl_chain_sge.size); + available_sges = mrioc->ioctl_chain_sge.size / sge_element_size; + if (available_sges < drv_buf_iter->num_dma_desc) + return -1; memset(nvme_sgl, 0, sizeof(struct mpi3mr_nvme_pt_sge)); - nvme_sgl->base_addr = sgl_ptr; - nvme_sgl->length = length; + nvme_sgl->base_addr = sgl_dma; + size = drv_buf_iter->num_dma_desc * sizeof(struct mpi3mr_nvme_pt_sge); + nvme_sgl->length = cpu_to_le32(size); + nvme_sgl->type = MPI3MR_NVMESGL_LAST_SEGMENT; + nvme_sgl = (struct mpi3mr_nvme_pt_sge *)mrioc->ioctl_chain_sge.addr; + +build_sges: + for (i = 0; i < drv_buf_iter->num_dma_desc; i++) { + sgl_dma = cpu_to_le64(drv_buf_iter->dma_desc[i].dma_addr); + if (sgl_dma & sgemod_mask) { + dprint_bsg_err(mrioc, + "%s: SGL address collides with SGE modifier\n", + __func__); + return -1; + } + + sgl_dma &= ~sgemod_mask; + sgl_dma |= sgemod_val; + + nvme_sgl->base_addr = sgl_dma; + nvme_sgl->length = cpu_to_le32(drv_buf_iter->dma_desc[i].size); + nvme_sgl->type = MPI3MR_NVMESGL_DATA_SEGMENT; + nvme_sgl++; + available_sges--; + } + return 0; } @@ -712,7 +885,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, dma_addr_t prp_entry_dma, prp_page_dma, dma_addr; u32 offset, entry_len, dev_pgsz; u32 page_mask_result, page_mask; - size_t length = 0; + size_t length = 0, desc_len; u8 count; struct mpi3mr_buf_map *drv_buf_iter = drv_bufs; u64 sgemod_mask = ((u64)((mrioc->facts.sge_mod_mask) << @@ -721,6 +894,7 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, mrioc->facts.sge_mod_shift) << 32; u16 dev_handle = nvme_encap_request->dev_handle; struct mpi3mr_tgt_dev *tgtdev; + u16 desc_count = 0; tgtdev = mpi3mr_get_tgtdev_by_handle(mrioc, dev_handle); if (!tgtdev) { @@ -739,6 +913,21 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, dev_pgsz = 1 << (tgtdev->dev_spec.pcie_inf.pgsz); mpi3mr_tgtdev_put(tgtdev); + page_mask = dev_pgsz - 1; + + if (dev_pgsz > MPI3MR_IOCTL_SGE_SIZE) { + dprint_bsg_err(mrioc, + "%s: NVMe device page size(%d) is greater than ioctl data sge size(%d) for handle 0x%04x\n", + __func__, dev_pgsz, MPI3MR_IOCTL_SGE_SIZE, dev_handle); + return -1; + } + + if (MPI3MR_IOCTL_SGE_SIZE % dev_pgsz) { + dprint_bsg_err(mrioc, + "%s: ioctl data sge size(%d) is not a multiple of NVMe device page size(%d) for handle 0x%04x\n", + __func__, MPI3MR_IOCTL_SGE_SIZE, dev_pgsz, dev_handle); + return -1; + } /* * Not all commands require a data transfer. If no data, just return @@ -747,14 +936,26 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - dma_addr = drv_buf_iter->kern_buf_dma; length = drv_buf_iter->kern_buf_len; break; } - if (!length) + if (!length || !drv_buf_iter->num_dma_desc) return 0; + for (count = 0; count < drv_buf_iter->num_dma_desc; count++) { + dma_addr = drv_buf_iter->dma_desc[count].dma_addr; + if (dma_addr & page_mask) { + dprint_bsg_err(mrioc, + "%s:dma_addr %pad is not aligned with page size 0x%x\n", + __func__, &dma_addr, dev_pgsz); + return -1; + } + } + + dma_addr = drv_buf_iter->dma_desc[0].dma_addr; + desc_len = drv_buf_iter->dma_desc[0].size; + mrioc->prp_sz = 0; mrioc->prp_list_virt = dma_alloc_coherent(&mrioc->pdev->dev, dev_pgsz, &mrioc->prp_list_dma, GFP_KERNEL); @@ -784,7 +985,6 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, * Check if we are within 1 entry of a page boundary we don't * want our first entry to be a PRP List entry. */ - page_mask = dev_pgsz - 1; page_mask_result = (uintptr_t)((u8 *)prp_page + prp_size) & page_mask; if (!page_mask_result) { dprint_bsg_err(mrioc, "%s: PRP page is not page aligned\n", @@ -898,18 +1098,31 @@ static int mpi3mr_build_nvme_prp(struct mpi3mr_ioc *mrioc, prp_entry_dma += prp_size; } - /* - * Bump the phys address of the command's data buffer by the - * entry_len. - */ - dma_addr += entry_len; - /* decrement length accounting for last partial page. */ - if (entry_len > length) + if (entry_len >= length) { length = 0; - else + } else { + if (entry_len <= desc_len) { + dma_addr += entry_len; + desc_len -= entry_len; + } + if (!desc_len) { + if ((++desc_count) >= + drv_buf_iter->num_dma_desc) { + dprint_bsg_err(mrioc, + "%s: Invalid len %zd while building PRP\n", + __func__, length); + goto err_out; + } + dma_addr = + drv_buf_iter->dma_desc[desc_count].dma_addr; + desc_len = + drv_buf_iter->dma_desc[desc_count].size; + } length -= entry_len; + } } + return 0; err_out: if (mrioc->prp_list_virt) { @@ -919,10 +1132,66 @@ err_out: } return -1; } + +/** + * mpi3mr_map_data_buffer_dma - build dma descriptors for data + * buffers + * @mrioc: Adapter instance reference + * @drv_buf: buffer map descriptor + * @desc_count: Number of already consumed dma descriptors + * + * This function computes how many pre-allocated DMA descriptors + * are required for the given data buffer and if those number of + * descriptors are free, then setup the mapping of the scattered + * DMA address to the given data buffer, if the data direction + * of the buffer is DMA_TO_DEVICE then the actual data is copied to + * the DMA buffers + * + * Return: 0 on success, -1 on failure + */ +static int mpi3mr_map_data_buffer_dma(struct mpi3mr_ioc *mrioc, + struct mpi3mr_buf_map *drv_buf, + u16 desc_count) +{ + u16 i, needed_desc = drv_buf->kern_buf_len / MPI3MR_IOCTL_SGE_SIZE; + u32 buf_len = drv_buf->kern_buf_len, copied_len = 0; + + if (drv_buf->kern_buf_len % MPI3MR_IOCTL_SGE_SIZE) + needed_desc++; + if ((needed_desc + desc_count) > MPI3MR_NUM_IOCTL_SGE) { + dprint_bsg_err(mrioc, "%s: DMA descriptor mapping error %d:%d:%d\n", + __func__, needed_desc, desc_count, MPI3MR_NUM_IOCTL_SGE); + return -1; + } + drv_buf->dma_desc = kzalloc(sizeof(*drv_buf->dma_desc) * needed_desc, + GFP_KERNEL); + if (!drv_buf->dma_desc) + return -1; + for (i = 0; i < needed_desc; i++, desc_count++) { + drv_buf->dma_desc[i].addr = mrioc->ioctl_sge[desc_count].addr; + drv_buf->dma_desc[i].dma_addr = + mrioc->ioctl_sge[desc_count].dma_addr; + if (buf_len < mrioc->ioctl_sge[desc_count].size) + drv_buf->dma_desc[i].size = buf_len; + else + drv_buf->dma_desc[i].size = + mrioc->ioctl_sge[desc_count].size; + buf_len -= drv_buf->dma_desc[i].size; + memset(drv_buf->dma_desc[i].addr, 0, + mrioc->ioctl_sge[desc_count].size); + if (drv_buf->data_dir == DMA_TO_DEVICE) { + memcpy(drv_buf->dma_desc[i].addr, + drv_buf->bsg_buf + copied_len, + drv_buf->dma_desc[i].size); + copied_len += drv_buf->dma_desc[i].size; + } + } + drv_buf->num_dma_desc = needed_desc; + return 0; +} /** * mpi3mr_bsg_process_mpt_cmds - MPI Pass through BSG handler * @job: BSG job reference - * @reply_payload_rcv_len: length of payload recvd * * This function is the top level handler for MPI Pass through * command, this does basic validation of the input data buffers, @@ -938,10 +1207,9 @@ err_out: * Return: 0 on success and proper error codes on failure */ -static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply_payload_rcv_len) +static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job) { long rval = -EINVAL; - struct mpi3mr_ioc *mrioc = NULL; u8 *mpi_req = NULL, *sense_buff_k = NULL; u8 mpi_msg_size = 0; @@ -949,9 +1217,10 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply struct mpi3mr_bsg_mptcmd *karg; struct mpi3mr_buf_entry *buf_entries = NULL; struct mpi3mr_buf_map *drv_bufs = NULL, *drv_buf_iter = NULL; - u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0, din_cnt = 0, dout_cnt = 0; - u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF, sg_entries = 0; - u8 block_io = 0, resp_code = 0, nvme_fmt = 0; + u8 count, bufcnt = 0, is_rmcb = 0, is_rmrb = 0; + u8 din_cnt = 0, dout_cnt = 0; + u8 invalid_be = 0, erb_offset = 0xFF, mpirep_offset = 0xFF; + u8 block_io = 0, nvme_fmt = 0, resp_code = 0; struct mpi3_request_header *mpi_header = NULL; struct mpi3_status_reply_descriptor *status_desc; struct mpi3_scsi_task_mgmt_request *tm_req; @@ -963,6 +1232,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply u32 din_size = 0, dout_size = 0; u8 *din_buf = NULL, *dout_buf = NULL; u8 *sgl_iter = NULL, *sgl_din_iter = NULL, *sgl_dout_iter = NULL; + u16 rmc_size = 0, desc_count = 0; bsg_req = job->request; karg = (struct mpi3mr_bsg_mptcmd *)&bsg_req->cmd.mptcmd; @@ -971,6 +1241,12 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply if (!mrioc) return -ENODEV; + if (!mrioc->ioctl_sges_allocated) { + dprint_bsg_err(mrioc, "%s: DMA memory was not allocated\n", + __func__); + return -ENOMEM; + } + if (karg->timeout < MPI3MR_APP_DEFAULT_TIMEOUT) karg->timeout = MPI3MR_APP_DEFAULT_TIMEOUT; @@ -1011,26 +1287,13 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply for (count = 0; count < bufcnt; count++, buf_entries++, drv_buf_iter++) { - if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { - dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", - __func__); - rval = -EINVAL; - goto out; - } - if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { - dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", - __func__); - rval = -EINVAL; - goto out; - } - switch (buf_entries->buf_type) { case MPI3MR_BSG_BUFTYPE_RAIDMGMT_CMD: sgl_iter = sgl_dout_iter; sgl_dout_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_TO_DEVICE; is_rmcb = 1; - if (count != 0) + if ((count != 0) || !buf_entries->buf_len) invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_RAIDMGMT_RESP: @@ -1038,7 +1301,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_FROM_DEVICE; is_rmrb = 1; - if (count != 1 || !is_rmcb) + if (count != 1 || !is_rmcb || !buf_entries->buf_len) invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_DATA_IN: @@ -1046,7 +1309,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_FROM_DEVICE; din_cnt++; - din_size += drv_buf_iter->bsg_buf_len; + din_size += buf_entries->buf_len; if ((din_cnt > 1) && !is_rmcb) invalid_be = 1; break; @@ -1055,7 +1318,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_dout_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_TO_DEVICE; dout_cnt++; - dout_size += drv_buf_iter->bsg_buf_len; + dout_size += buf_entries->buf_len; if ((dout_cnt > 1) && !is_rmcb) invalid_be = 1; break; @@ -1064,12 +1327,16 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_NONE; mpirep_offset = count; + if (!buf_entries->buf_len) + invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_ERR_RESPONSE: sgl_iter = sgl_din_iter; sgl_din_iter += buf_entries->buf_len; drv_buf_iter->data_dir = DMA_NONE; erb_offset = count; + if (!buf_entries->buf_len) + invalid_be = 1; break; case MPI3MR_BSG_BUFTYPE_MPI_REQUEST: sgl_iter = sgl_dout_iter; @@ -1096,21 +1363,31 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply goto out; } - drv_buf_iter->bsg_buf = sgl_iter; - drv_buf_iter->bsg_buf_len = buf_entries->buf_len; - - } - if (!is_rmcb && (dout_cnt || din_cnt)) { - sg_entries = dout_cnt + din_cnt; - if (((mpi_msg_size) + (sg_entries * - sizeof(struct mpi3_sge_common))) > MPI3MR_ADMIN_REQ_FRAME_SZ) { - dprint_bsg_err(mrioc, - "%s:%d: invalid message size passed\n", - __func__, __LINE__); + if (sgl_dout_iter > (dout_buf + job->request_payload.payload_len)) { + dprint_bsg_err(mrioc, "%s: data_out buffer length mismatch\n", + __func__); rval = -EINVAL; goto out; } + if (sgl_din_iter > (din_buf + job->reply_payload.payload_len)) { + dprint_bsg_err(mrioc, "%s: data_in buffer length mismatch\n", + __func__); + rval = -EINVAL; + goto out; + } + + drv_buf_iter->bsg_buf = sgl_iter; + drv_buf_iter->bsg_buf_len = buf_entries->buf_len; } + + if (is_rmcb && ((din_size + dout_size) > MPI3MR_MAX_APP_XFER_SIZE)) { + dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size = %d, dout_size = %d\n", + __func__, __LINE__, mpi_header->function, din_size, + dout_size); + rval = -EINVAL; + goto out; + } + if (din_size > MPI3MR_MAX_APP_XFER_SIZE) { dprint_bsg_err(mrioc, "%s:%d: invalid data transfer size passed for function 0x%x din_size=%d\n", @@ -1126,30 +1403,64 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply goto out; } + if (mpi_header->function == MPI3_BSG_FUNCTION_SMP_PASSTHROUGH) { + if (din_size > MPI3MR_IOCTL_SGE_SIZE || + dout_size > MPI3MR_IOCTL_SGE_SIZE) { + dprint_bsg_err(mrioc, "%s:%d: invalid message size passed:%d:%d:%d:%d\n", + __func__, __LINE__, din_cnt, dout_cnt, din_size, + dout_size); + rval = -EINVAL; + goto out; + } + } + drv_buf_iter = drv_bufs; for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; drv_buf_iter->kern_buf_len = drv_buf_iter->bsg_buf_len; - if (is_rmcb && !count) - drv_buf_iter->kern_buf_len += ((dout_cnt + din_cnt) * - sizeof(struct mpi3_sge_common)); - - if (!drv_buf_iter->kern_buf_len) - continue; - - drv_buf_iter->kern_buf = dma_alloc_coherent(&mrioc->pdev->dev, - drv_buf_iter->kern_buf_len, &drv_buf_iter->kern_buf_dma, - GFP_KERNEL); - if (!drv_buf_iter->kern_buf) { - rval = -ENOMEM; - goto out; - } - if (drv_buf_iter->data_dir == DMA_TO_DEVICE) { + if (is_rmcb && !count) { + drv_buf_iter->kern_buf_len = + mrioc->ioctl_chain_sge.size; + drv_buf_iter->kern_buf = + mrioc->ioctl_chain_sge.addr; + drv_buf_iter->kern_buf_dma = + mrioc->ioctl_chain_sge.dma_addr; + drv_buf_iter->dma_desc = NULL; + drv_buf_iter->num_dma_desc = 0; + memset(drv_buf_iter->kern_buf, 0, + drv_buf_iter->kern_buf_len); tmplen = min(drv_buf_iter->kern_buf_len, - drv_buf_iter->bsg_buf_len); + drv_buf_iter->bsg_buf_len); + rmc_size = tmplen; memcpy(drv_buf_iter->kern_buf, drv_buf_iter->bsg_buf, tmplen); + } else if (is_rmrb && (count == 1)) { + drv_buf_iter->kern_buf_len = + mrioc->ioctl_resp_sge.size; + drv_buf_iter->kern_buf = + mrioc->ioctl_resp_sge.addr; + drv_buf_iter->kern_buf_dma = + mrioc->ioctl_resp_sge.dma_addr; + drv_buf_iter->dma_desc = NULL; + drv_buf_iter->num_dma_desc = 0; + memset(drv_buf_iter->kern_buf, 0, + drv_buf_iter->kern_buf_len); + tmplen = min(drv_buf_iter->kern_buf_len, + drv_buf_iter->bsg_buf_len); + drv_buf_iter->kern_buf_len = tmplen; + memset(drv_buf_iter->bsg_buf, 0, + drv_buf_iter->bsg_buf_len); + } else { + if (!drv_buf_iter->kern_buf_len) + continue; + if (mpi3mr_map_data_buffer_dma(mrioc, drv_buf_iter, desc_count)) { + rval = -ENOMEM; + dprint_bsg_err(mrioc, "%s:%d: mapping data buffers failed\n", + __func__, __LINE__); + goto out; + } + desc_count += drv_buf_iter->num_dma_desc; } } @@ -1219,9 +1530,14 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply goto out; } } else { - mpi3mr_bsg_build_sgl(mpi_req, (mpi_msg_size), - drv_bufs, bufcnt, is_rmcb, is_rmrb, - (dout_cnt + din_cnt)); + if (mpi3mr_bsg_build_sgl(mrioc, mpi_req, mpi_msg_size, + drv_bufs, bufcnt, is_rmcb, is_rmrb, + (dout_cnt + din_cnt))) { + dprint_bsg_err(mrioc, "%s: sgl build failed\n", __func__); + rval = -EAGAIN; + mutex_unlock(&mrioc->bsg_cmds.mutex); + goto out; + } } if (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_TASK_MGMT) { @@ -1257,7 +1573,7 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply if (mpi_header->function == MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) { drv_buf_iter = &drv_bufs[0]; dprint_dump(drv_buf_iter->kern_buf, - drv_buf_iter->kern_buf_len, "mpi3_mgmt_req"); + rmc_size, "mpi3_mgmt_req"); } } @@ -1292,10 +1608,9 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply MPI3_BSG_FUNCTION_MGMT_PASSTHROUGH) { drv_buf_iter = &drv_bufs[0]; dprint_dump(drv_buf_iter->kern_buf, - drv_buf_iter->kern_buf_len, "mpi3_mgmt_req"); + rmc_size, "mpi3_mgmt_req"); } } - if ((mpi_header->function == MPI3_BSG_FUNCTION_NVME_ENCAPSULATED) || (mpi_header->function == MPI3_BSG_FUNCTION_SCSI_IO)) mpi3mr_issue_tm(mrioc, @@ -1366,17 +1681,27 @@ static long mpi3mr_bsg_process_mpt_cmds(struct bsg_job *job, unsigned int *reply for (count = 0; count < bufcnt; count++, drv_buf_iter++) { if (drv_buf_iter->data_dir == DMA_NONE) continue; - if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) { - tmplen = min(drv_buf_iter->kern_buf_len, - drv_buf_iter->bsg_buf_len); + if ((count == 1) && is_rmrb) { memcpy(drv_buf_iter->bsg_buf, - drv_buf_iter->kern_buf, tmplen); + drv_buf_iter->kern_buf, + drv_buf_iter->kern_buf_len); + } else if (drv_buf_iter->data_dir == DMA_FROM_DEVICE) { + tmplen = 0; + for (desc_count = 0; + desc_count < drv_buf_iter->num_dma_desc; + desc_count++) { + memcpy(((u8 *)drv_buf_iter->bsg_buf + tmplen), + drv_buf_iter->dma_desc[desc_count].addr, + drv_buf_iter->dma_desc[desc_count].size); + tmplen += + drv_buf_iter->dma_desc[desc_count].size; } } + } out_unlock: if (din_buf) { - *reply_payload_rcv_len = + job->reply_payload_rcv_len = sg_copy_from_buffer(job->reply_payload.sg_list, job->reply_payload.sg_cnt, din_buf, job->reply_payload.payload_len); @@ -1392,13 +1717,8 @@ out: kfree(mpi_req); if (drv_bufs) { drv_buf_iter = drv_bufs; - for (count = 0; count < bufcnt; count++, drv_buf_iter++) { - if (drv_buf_iter->kern_buf && drv_buf_iter->kern_buf_dma) - dma_free_coherent(&mrioc->pdev->dev, - drv_buf_iter->kern_buf_len, - drv_buf_iter->kern_buf, - drv_buf_iter->kern_buf_dma); - } + for (count = 0; count < bufcnt; count++, drv_buf_iter++) + kfree(drv_buf_iter->dma_desc); kfree(drv_bufs); } kfree(bsg_reply_buf); @@ -1457,7 +1777,7 @@ static int mpi3mr_bsg_request(struct bsg_job *job) rval = mpi3mr_bsg_process_drv_cmds(job); break; case MPI3MR_MPT_CMD: - rval = mpi3mr_bsg_process_mpt_cmds(job, &reply_payload_rcv_len); + rval = mpi3mr_bsg_process_mpt_cmds(job); break; default: pr_err("%s: unsupported BSG command(0x%08x)\n", diff --git a/drivers/scsi/mpi3mr/mpi3mr_fw.c b/drivers/scsi/mpi3mr/mpi3mr_fw.c index f039f1d98647..d8c57a0a518f 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_fw.c +++ b/drivers/scsi/mpi3mr/mpi3mr_fw.c @@ -1059,6 +1059,114 @@ enum mpi3mr_iocstate mpi3mr_get_iocstate(struct mpi3mr_ioc *mrioc) } /** + * mpi3mr_free_ioctl_dma_memory - free memory for ioctl dma + * @mrioc: Adapter instance reference + * + * Free the DMA memory allocated for IOCTL handling purpose. + + * + * Return: None + */ +static void mpi3mr_free_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) +{ + struct dma_memory_desc *mem_desc; + u16 i; + + if (!mrioc->ioctl_dma_pool) + return; + + for (i = 0; i < MPI3MR_NUM_IOCTL_SGE; i++) { + mem_desc = &mrioc->ioctl_sge[i]; + if (mem_desc->addr) { + dma_pool_free(mrioc->ioctl_dma_pool, + mem_desc->addr, + mem_desc->dma_addr); + mem_desc->addr = NULL; + } + } + dma_pool_destroy(mrioc->ioctl_dma_pool); + mrioc->ioctl_dma_pool = NULL; + mem_desc = &mrioc->ioctl_chain_sge; + + if (mem_desc->addr) { + dma_free_coherent(&mrioc->pdev->dev, mem_desc->size, + mem_desc->addr, mem_desc->dma_addr); + mem_desc->addr = NULL; + } + mem_desc = &mrioc->ioctl_resp_sge; + if (mem_desc->addr) { + dma_free_coherent(&mrioc->pdev->dev, mem_desc->size, + mem_desc->addr, mem_desc->dma_addr); + mem_desc->addr = NULL; + } + + mrioc->ioctl_sges_allocated = false; +} + +/** + * mpi3mr_alloc_ioctl_dma_memory - Alloc memory for ioctl dma + * @mrioc: Adapter instance reference + + * + * This function allocates dmaable memory required to handle the + * application issued MPI3 IOCTL requests. + * + * Return: None + */ +static void mpi3mr_alloc_ioctl_dma_memory(struct mpi3mr_ioc *mrioc) + +{ + struct dma_memory_desc *mem_desc; + u16 i; + + mrioc->ioctl_dma_pool = dma_pool_create("ioctl dma pool", + &mrioc->pdev->dev, + MPI3MR_IOCTL_SGE_SIZE, + MPI3MR_PAGE_SIZE_4K, 0); + + if (!mrioc->ioctl_dma_pool) { + ioc_err(mrioc, "ioctl_dma_pool: dma_pool_create failed\n"); + goto out_failed; + } + + for (i = 0; i < MPI3MR_NUM_IOCTL_SGE; i++) { + mem_desc = &mrioc->ioctl_sge[i]; + mem_desc->size = MPI3MR_IOCTL_SGE_SIZE; + mem_desc->addr = dma_pool_zalloc(mrioc->ioctl_dma_pool, + GFP_KERNEL, + &mem_desc->dma_addr); + if (!mem_desc->addr) + goto out_failed; + } + + mem_desc = &mrioc->ioctl_chain_sge; + mem_desc->size = MPI3MR_PAGE_SIZE_4K; + mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev, + mem_desc->size, + &mem_desc->dma_addr, + GFP_KERNEL); + if (!mem_desc->addr) + goto out_failed; + + mem_desc = &mrioc->ioctl_resp_sge; + mem_desc->size = MPI3MR_PAGE_SIZE_4K; + mem_desc->addr = dma_alloc_coherent(&mrioc->pdev->dev, + mem_desc->size, + &mem_desc->dma_addr, + GFP_KERNEL); + if (!mem_desc->addr) + goto out_failed; + + mrioc->ioctl_sges_allocated = true; + + return; +out_failed: + ioc_warn(mrioc, "cannot allocate DMA memory for the mpt commands\n" + "from the applications, application interface for MPT command is disabled\n"); + mpi3mr_free_ioctl_dma_memory(mrioc); +} + +/** * mpi3mr_clear_reset_history - clear reset history * @mrioc: Adapter instance reference * @@ -1892,7 +2000,8 @@ static int mpi3mr_create_op_reply_q(struct mpi3mr_ioc *mrioc, u16 qidx) reply_qid = qidx + 1; op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD; - if (!mrioc->pdev->revision) + if ((mrioc->pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && + !mrioc->pdev->revision) op_reply_q->num_replies = MPI3MR_OP_REP_Q_QD4K; op_reply_q->ci = 0; op_reply_q->ephase = 1; @@ -3193,6 +3302,9 @@ static int mpi3mr_issue_iocinit(struct mpi3mr_ioc *mrioc) current_time = ktime_get_real(); iocinit_req.time_stamp = cpu_to_le64(ktime_to_ms(current_time)); + iocinit_req.msg_flags |= + MPI3_IOCINIT_MSGFLAGS_SCSIIOSTATUSREPLY_SUPPORTED; + init_completion(&mrioc->init_cmds.done); retval = mpi3mr_admin_request_post(mrioc, &iocinit_req, sizeof(iocinit_req), 1); @@ -3870,6 +3982,9 @@ retry_init: } } + dprint_init(mrioc, "allocating ioctl dma buffers\n"); + mpi3mr_alloc_ioctl_dma_memory(mrioc); + if (!mrioc->init_cmds.reply) { retval = mpi3mr_alloc_reply_sense_bufs(mrioc); if (retval) { @@ -4289,6 +4404,7 @@ void mpi3mr_free_mem(struct mpi3mr_ioc *mrioc) struct mpi3mr_intr_info *intr_info; mpi3mr_free_enclosure_list(mrioc); + mpi3mr_free_ioctl_dma_memory(mrioc); if (mrioc->sense_buf_pool) { if (mrioc->sense_buf) diff --git a/drivers/scsi/mpi3mr/mpi3mr_os.c b/drivers/scsi/mpi3mr/mpi3mr_os.c index 040031eb0c12..1bffd629c124 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_os.c +++ b/drivers/scsi/mpi3mr/mpi3mr_os.c @@ -1047,8 +1047,9 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) list_for_each_entry_safe(tgtdev, tgtdev_next, &mrioc->tgtdev_list, list) { if ((tgtdev->dev_handle == MPI3MR_INVALID_DEV_HANDLE) && - tgtdev->host_exposed && tgtdev->starget && - tgtdev->starget->hostdata) { + tgtdev->is_hidden && + tgtdev->host_exposed && tgtdev->starget && + tgtdev->starget->hostdata) { tgt_priv = tgtdev->starget->hostdata; tgt_priv->dev_removed = 1; atomic_set(&tgt_priv->block_io, 0); @@ -1064,14 +1065,24 @@ void mpi3mr_rfresh_tgtdevs(struct mpi3mr_ioc *mrioc) mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); mpi3mr_tgtdev_del_from_list(mrioc, tgtdev, true); mpi3mr_tgtdev_put(tgtdev); + } else if (tgtdev->is_hidden & tgtdev->host_exposed) { + dprint_reset(mrioc, "hiding target device with perst_id(%d)\n", + tgtdev->perst_id); + mpi3mr_remove_tgtdev_from_host(mrioc, tgtdev); } } tgtdev = NULL; list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) { if ((tgtdev->dev_handle != MPI3MR_INVALID_DEV_HANDLE) && - !tgtdev->is_hidden && !tgtdev->host_exposed) - mpi3mr_report_tgtdev_to_host(mrioc, tgtdev->perst_id); + !tgtdev->is_hidden) { + if (!tgtdev->host_exposed) + mpi3mr_report_tgtdev_to_host(mrioc, + tgtdev->perst_id); + else if (tgtdev->starget) + starget_for_each_device(tgtdev->starget, + (void *)tgtdev, mpi3mr_update_sdev); + } } } @@ -3194,6 +3205,7 @@ void mpi3mr_process_op_reply_desc(struct mpi3mr_ioc *mrioc, tg = stgt_priv_data->throttle_group; throttle_enabled_dev = stgt_priv_data->io_throttle_enabled; + dev_handle = stgt_priv_data->dev_handle; } } if (unlikely((data_len_blks >= mrioc->io_throttle_data_length) && @@ -5101,7 +5113,10 @@ mpi3mr_probe(struct pci_dev *pdev, const struct pci_device_id *id) mpi3mr_init_drv_cmd(&mrioc->evtack_cmds[i], MPI3MR_HOSTTAG_EVTACKCMD_MIN + i); - if (pdev->revision) + if ((pdev->device == MPI3_MFGPAGE_DEVID_SAS4116) && + !pdev->revision) + mrioc->enable_segqueue = false; + else mrioc->enable_segqueue = true; init_waitqueue_head(&mrioc->reset_waitq); @@ -5430,6 +5445,14 @@ static const struct pci_device_id mpi3mr_pci_id_table[] = { PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, MPI3_MFGPAGE_DEVID_SAS4116, PCI_ANY_ID, PCI_ANY_ID) }, + { + PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, + MPI3_MFGPAGE_DEVID_SAS5116_MPI, PCI_ANY_ID, PCI_ANY_ID) + }, + { + PCI_DEVICE_SUB(MPI3_MFGPAGE_VENDORID_BROADCOM, + MPI3_MFGPAGE_DEVID_SAS5116_MPI_MGMT, PCI_ANY_ID, PCI_ANY_ID) + }, { 0 } }; MODULE_DEVICE_TABLE(pci, mpi3mr_pci_id_table); diff --git a/drivers/scsi/mpi3mr/mpi3mr_transport.c b/drivers/scsi/mpi3mr/mpi3mr_transport.c index 82b55e955730..c0c8ab586957 100644 --- a/drivers/scsi/mpi3mr/mpi3mr_transport.c +++ b/drivers/scsi/mpi3mr/mpi3mr_transport.c @@ -1587,7 +1587,7 @@ static void mpi3mr_sas_port_remove(struct mpi3mr_ioc *mrioc, u64 sas_address, */ struct host_port { u64 sas_address; - u32 phy_mask; + u64 phy_mask; u16 handle; u8 iounit_port_id; u8 used; @@ -1611,7 +1611,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, struct mpi3mr_sas_port *mr_sas_port) { struct mpi3mr_sas_phy *mr_sas_phy; - u32 phy_mask_xor; + u64 phy_mask_xor; u64 phys_to_be_added, phys_to_be_removed; int i; @@ -1619,7 +1619,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, mr_sas_port->marked_responding = 1; dev_info(&mr_sas_port->port->dev, - "sas_address(0x%016llx), old: port_id %d phy_mask 0x%x, new: port_id %d phy_mask:0x%x\n", + "sas_address(0x%016llx), old: port_id %d phy_mask 0x%llx, new: port_id %d phy_mask:0x%llx\n", mr_sas_port->remote_identify.sas_address, mr_sas_port->hba_port->port_id, mr_sas_port->phy_mask, h_port->iounit_port_id, h_port->phy_mask); @@ -1637,7 +1637,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, * if these phys are previously registered with another port * then delete these phys from that port first. */ - for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u32)) { + for_each_set_bit(i, (ulong *) &phys_to_be_added, BITS_PER_TYPE(u64)) { mr_sas_phy = &mrioc->sas_hba.phy[i]; if (mr_sas_phy->phy_belongs_to_port) mpi3mr_del_phy_from_an_existing_port(mrioc, @@ -1649,7 +1649,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, } /* Delete the phys which are not part of current mr_sas_port's port. */ - for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u32)) { + for_each_set_bit(i, (ulong *) &phys_to_be_removed, BITS_PER_TYPE(u64)) { mr_sas_phy = &mrioc->sas_hba.phy[i]; if (mr_sas_phy->phy_belongs_to_port) mpi3mr_del_phy_from_an_existing_port(mrioc, @@ -1671,7 +1671,7 @@ mpi3mr_update_mr_sas_port(struct mpi3mr_ioc *mrioc, struct host_port *h_port, void mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) { - struct host_port h_port[32]; + struct host_port h_port[64]; int i, j, found, host_port_count = 0, port_idx; u16 sz, attached_handle, ioc_status; struct mpi3_sas_io_unit_page0 *sas_io_unit_pg0 = NULL; @@ -1742,7 +1742,7 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) list_for_each_entry(mr_sas_port, &mrioc->sas_hba.sas_port_list, port_list) { ioc_info(mrioc, - "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n", + "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n", mr_sas_port->hba_port->port_id, mr_sas_port->remote_identify.sas_address, mr_sas_port->phy_mask, mr_sas_port->lowest_phy); @@ -1751,7 +1751,7 @@ mpi3mr_refresh_sas_ports(struct mpi3mr_ioc *mrioc) ioc_info(mrioc, "Host port details after reset\n"); for (i = 0; i < host_port_count; i++) { ioc_info(mrioc, - "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%x), lowest phy id:%d\n", + "port_id:%d, sas_address:(0x%016llx), phy_mask:(0x%llx), lowest phy id:%d\n", h_port[i].iounit_port_id, h_port[i].sas_address, h_port[i].phy_mask, h_port[i].lowest_phy); } diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h index 4d0be5ab98c1..587f7d248219 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_cnfg.h @@ -643,18 +643,14 @@ typedef struct _MPI2_CHIP_REVISION_ID { /*Manufacturing Page 2 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check Header.PageLength at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check Header.PageLength at + *runtime before using HwSettings[]. */ -#ifndef MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS -#define MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS (1) -#endif typedef struct _MPI2_CONFIG_PAGE_MAN_2 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ - U32 - HwSettings[MPI2_MAN_PAGE_2_HW_SETTINGS_WORDS];/*0x08 */ + U32 HwSettings[]; /*0x08 */ } MPI2_CONFIG_PAGE_MAN_2, *PTR_MPI2_CONFIG_PAGE_MAN_2, Mpi2ManufacturingPage2_t, @@ -666,18 +662,14 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_2 { /*Manufacturing Page 3 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check Header.PageLength at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check Header.PageLength at + *runtime before using Info[]. */ -#ifndef MPI2_MAN_PAGE_3_INFO_WORDS -#define MPI2_MAN_PAGE_3_INFO_WORDS (1) -#endif typedef struct _MPI2_CONFIG_PAGE_MAN_3 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ MPI2_CHIP_REVISION_ID ChipId; /*0x04 */ - U32 - Info[MPI2_MAN_PAGE_3_INFO_WORDS];/*0x08 */ + U32 Info[]; /*0x08 */ } MPI2_CONFIG_PAGE_MAN_3, *PTR_MPI2_CONFIG_PAGE_MAN_3, Mpi2ManufacturingPage3_t, @@ -765,12 +757,9 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_4 { /*Manufacturing Page 5 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using Phy[]. */ -#ifndef MPI2_MAN_PAGE_5_PHY_ENTRIES -#define MPI2_MAN_PAGE_5_PHY_ENTRIES (1) -#endif typedef struct _MPI2_MANUFACTURING5_ENTRY { U64 WWID; /*0x00 */ @@ -787,8 +776,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_5 { U16 Reserved2; /*0x06 */ U32 Reserved3; /*0x08 */ U32 Reserved4; /*0x0C */ - MPI2_MANUFACTURING5_ENTRY - Phy[MPI2_MAN_PAGE_5_PHY_ENTRIES];/*0x08 */ + MPI2_MANUFACTURING5_ENTRY Phy[]; /*0x10 */ } MPI2_CONFIG_PAGE_MAN_5, *PTR_MPI2_CONFIG_PAGE_MAN_5, Mpi2ManufacturingPage5_t, @@ -864,12 +852,9 @@ typedef struct _MPI2_MANPAGE7_CONNECTOR_INFO { #define MPI2_MANPAGE7_SLOT_UNKNOWN (0xFFFF) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using ConnectorInfo[]. */ -#ifndef MPI2_MANPAGE7_CONNECTOR_INFO_MAX -#define MPI2_MANPAGE7_CONNECTOR_INFO_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_MAN_7 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -880,8 +865,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7 { U8 NumPhys; /*0x20 */ U8 Reserved3; /*0x21 */ U16 Reserved4; /*0x22 */ - MPI2_MANPAGE7_CONNECTOR_INFO - ConnectorInfo[MPI2_MANPAGE7_CONNECTOR_INFO_MAX]; /*0x24 */ + MPI2_MANPAGE7_CONNECTOR_INFO ConnectorInfo[]; /*0x24 */ } MPI2_CONFIG_PAGE_MAN_7, *PTR_MPI2_CONFIG_PAGE_MAN_7, Mpi2ManufacturingPage7_t, @@ -990,7 +974,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_1 { /* *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for GPIOCount at runtime. + *36 and check the value returned for GPIOCount at runtime. */ #ifndef MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX #define MPI2_IO_UNIT_PAGE_3_GPIO_VAL_MAX (36) @@ -1019,12 +1003,9 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_3 { /*IO Unit Page 5 */ /* - *Upper layer code (drivers, utilities, etc.) should leave this define set to - *one and check the value returned for NumDmaEngines at runtime. + *Upper layer code (drivers, utilities, etc.) should check the value returned + *for NumDmaEngines at runtime before using DmaEngineCapabilities[]. */ -#ifndef MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES -#define MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1042,7 +1023,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_5 { U32 Reserved2; /*0x24 */ U32 Reserved3; /*0x28 */ U32 - DmaEngineCapabilities[MPI2_IOUNITPAGE5_DMAENGINE_ENTRIES]; /*0x2C */ + DmaEngineCapabilities[]; /*0x2C */ } MPI2_CONFIG_PAGE_IO_UNIT_5, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_5, Mpi2IOUnitPage5_t, *pMpi2IOUnitPage5_t; @@ -1219,12 +1200,9 @@ typedef struct _MPI2_IOUNIT8_SENSOR { #define MPI2_IOUNIT8_SENSOR_FLAGS_T0_ENABLE (0x0001) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumSensors at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumSensors at runtime before using Sensor[]. */ -#ifndef MPI2_IOUNITPAGE8_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE8_SENSOR_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1233,8 +1211,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_8 { U8 NumSensors; /*0x0C */ U8 PollingInterval; /*0x0D */ U16 Reserved3; /*0x0E */ - MPI2_IOUNIT8_SENSOR - Sensor[MPI2_IOUNITPAGE8_SENSOR_ENTRIES];/*0x10 */ + MPI2_IOUNIT8_SENSOR Sensor[]; /*0x10 */ } MPI2_CONFIG_PAGE_IO_UNIT_8, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_8, Mpi2IOUnitPage8_t, *pMpi2IOUnitPage8_t; @@ -1259,12 +1236,9 @@ typedef struct _MPI2_IOUNIT9_SENSOR { #define MPI2_IOUNIT9_SENSOR_FLAGS_TEMP_VALID (0x01) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumSensors at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumSensors at runtime before using Sensor[]. */ -#ifndef MPI2_IOUNITPAGE9_SENSOR_ENTRIES -#define MPI2_IOUNITPAGE9_SENSOR_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1273,8 +1247,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_9 { U8 NumSensors; /*0x0C */ U8 Reserved4; /*0x0D */ U16 Reserved3; /*0x0E */ - MPI2_IOUNIT9_SENSOR - Sensor[MPI2_IOUNITPAGE9_SENSOR_ENTRIES];/*0x10 */ + MPI2_IOUNIT9_SENSOR Sensor[]; /*0x10 */ } MPI2_CONFIG_PAGE_IO_UNIT_9, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_9, Mpi2IOUnitPage9_t, *pMpi2IOUnitPage9_t; @@ -1294,12 +1267,9 @@ typedef struct _MPI2_IOUNIT10_FUNCTION { *pMpi2IOUnit10Function_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumFunctions at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumFunctions at runtime before using Function[]. */ -#ifndef MPI2_IOUNITPAGE10_FUNCTION_ENTRIES -#define MPI2_IOUNITPAGE10_FUNCTION_ENTRIES (1) -#endif typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1308,8 +1278,7 @@ typedef struct _MPI2_CONFIG_PAGE_IO_UNIT_10 { U16 Reserved2; /*0x06 */ U32 Reserved3; /*0x08 */ U32 Reserved4; /*0x0C */ - MPI2_IOUNIT10_FUNCTION - Function[MPI2_IOUNITPAGE10_FUNCTION_ENTRIES];/*0x10 */ + MPI2_IOUNIT10_FUNCTION Function[]; /*0x10 */ } MPI2_CONFIG_PAGE_IO_UNIT_10, *PTR_MPI2_CONFIG_PAGE_IO_UNIT_10, Mpi2IOUnitPage10_t, *pMpi2IOUnitPage10_t; @@ -1764,12 +1733,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_3 { /*BIOS Page 4 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using Phy[]. */ -#ifndef MPI2_BIOS_PAGE_4_PHY_ENTRIES -#define MPI2_BIOS_PAGE_4_PHY_ENTRIES (1) -#endif typedef struct _MPI2_BIOS4_ENTRY { U64 ReassignmentWWID; /*0x00 */ @@ -1782,8 +1748,7 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_4 { U8 NumPhys; /*0x04 */ U8 Reserved1; /*0x05 */ U16 Reserved2; /*0x06 */ - MPI2_BIOS4_ENTRY - Phy[MPI2_BIOS_PAGE_4_PHY_ENTRIES]; /*0x08 */ + MPI2_BIOS4_ENTRY Phy[]; /*0x08 */ } MPI2_CONFIG_PAGE_BIOS_4, *PTR_MPI2_CONFIG_PAGE_BIOS_4, Mpi2BiosPage4_t, *pMpi2BiosPage4_t; @@ -1836,12 +1801,9 @@ typedef struct _MPI2_RAIDVOL0_SETTINGS { #define MPI2_RAIDVOL0_SETTING_ENABLE_WRITE_CACHING (0x0002) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhysDisks at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhysDisks at runtime before using PhysDisk[]. */ -#ifndef MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX -#define MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 { MPI2_CONFIG_PAGE_HEADER Header; /*0x00 */ @@ -1861,8 +1823,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_VOL_0 { U8 Reserved2; /*0x25 */ U8 Reserved3; /*0x26 */ U8 InactiveStatus; /*0x27 */ - MPI2_RAIDVOL0_PHYS_DISK - PhysDisk[MPI2_RAID_VOL_PAGE_0_PHYSDISK_MAX]; /*0x28 */ + MPI2_RAIDVOL0_PHYS_DISK PhysDisk[]; /*0x28 */ } MPI2_CONFIG_PAGE_RAID_VOL_0, *PTR_MPI2_CONFIG_PAGE_RAID_VOL_0, Mpi2RaidVolPage0_t, *pMpi2RaidVolPage0_t; @@ -2045,12 +2006,9 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_0 { /*RAID Physical Disk Page 1 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhysDiskPaths at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhysDiskPaths at runtime before using PhysicalDiskPath[]. */ -#ifndef MPI2_RAID_PHYS_DISK1_PATH_MAX -#define MPI2_RAID_PHYS_DISK1_PATH_MAX (1) -#endif typedef struct _MPI2_RAIDPHYSDISK1_PATH { U16 DevHandle; /*0x00 */ @@ -2075,8 +2033,7 @@ typedef struct _MPI2_CONFIG_PAGE_RD_PDISK_1 { U8 PhysDiskNum; /*0x05 */ U16 Reserved1; /*0x06 */ U32 Reserved2; /*0x08 */ - MPI2_RAIDPHYSDISK1_PATH - PhysicalDiskPath[MPI2_RAID_PHYS_DISK1_PATH_MAX];/*0x0C */ + MPI2_RAIDPHYSDISK1_PATH PhysicalDiskPath[]; /*0x0C */ } MPI2_CONFIG_PAGE_RD_PDISK_1, *PTR_MPI2_CONFIG_PAGE_RD_PDISK_1, Mpi2RaidPhysDiskPage1_t, @@ -2221,12 +2178,9 @@ typedef struct _MPI2_SAS_IO_UNIT0_PHY_DATA { *pMpi2SasIOUnit0PhyData_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI2_SAS_IOUNIT0_PHY_MAX -#define MPI2_SAS_IOUNIT0_PHY_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2234,8 +2188,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_0 { U8 NumPhys; /*0x0C */ U8 Reserved2;/*0x0D */ U16 Reserved3;/*0x0E */ - MPI2_SAS_IO_UNIT0_PHY_DATA - PhyData[MPI2_SAS_IOUNIT0_PHY_MAX]; /*0x10 */ + MPI2_SAS_IO_UNIT0_PHY_DATA PhyData[];/*0x10 */ } MPI2_CONFIG_PAGE_SASIOUNIT_0, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_0, Mpi2SasIOUnitPage0_t, *pMpi2SasIOUnitPage0_t; @@ -2296,12 +2249,9 @@ typedef struct _MPI2_SAS_IO_UNIT1_PHY_DATA { *pMpi2SasIOUnit1PhyData_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI2_SAS_IOUNIT1_PHY_MAX -#define MPI2_SAS_IOUNIT1_PHY_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2322,7 +2272,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_1 { U8 IODeviceMissingDelay; /*0x13 */ MPI2_SAS_IO_UNIT1_PHY_DATA - PhyData[MPI2_SAS_IOUNIT1_PHY_MAX]; /*0x14 */ + PhyData[]; /*0x14 */ } MPI2_CONFIG_PAGE_SASIOUNIT_1, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_1, Mpi2SasIOUnitPage1_t, *pMpi2SasIOUnitPage1_t; @@ -2502,12 +2452,9 @@ typedef struct _MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS { #define MPI2_SASIOUNIT5_ITE_ONE_MICROSECOND (0) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using SASPhyPowerManagementSettings[]. */ -#ifndef MPI2_SAS_IOUNIT5_PHY_MAX -#define MPI2_SAS_IOUNIT5_PHY_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2516,7 +2463,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_5 { U16 Reserved2;/*0x0A */ U32 Reserved3;/*0x0C */ MPI2_SAS_IO_UNIT5_PHY_PM_SETTINGS - SASPhyPowerManagementSettings[MPI2_SAS_IOUNIT5_PHY_MAX];/*0x10 */ + SASPhyPowerManagementSettings[]; /*0x10 */ } MPI2_CONFIG_PAGE_SASIOUNIT_5, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_5, Mpi2SasIOUnitPage5_t, *pMpi2SasIOUnitPage5_t; @@ -2554,12 +2501,9 @@ typedef struct _MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS { #define MPI2_SASIOUNIT6_MODULATION_100_PERCENT (0x03) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumGroups at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumGroups at runtime before using PortWidthModulationGroupStatus[]. */ -#ifndef MPI2_SAS_IOUNIT6_GROUP_MAX -#define MPI2_SAS_IOUNIT6_GROUP_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2569,7 +2513,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_6 { U8 Reserved3; /*0x11 */ U16 Reserved4; /*0x12 */ MPI2_SAS_IO_UNIT6_PORT_WIDTH_MOD_GROUP_STATUS - PortWidthModulationGroupStatus[MPI2_SAS_IOUNIT6_GROUP_MAX]; /*0x14 */ + PortWidthModulationGroupStatus[]; /*0x14 */ } MPI2_CONFIG_PAGE_SASIOUNIT_6, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_6, Mpi2SasIOUnitPage6_t, *pMpi2SasIOUnitPage6_t; @@ -2597,12 +2541,9 @@ typedef struct _MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS { /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumGroups at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumGroups at runtime before using PortWidthModulationGroupSettings[]. */ -#ifndef MPI2_SAS_IOUNIT7_GROUP_MAX -#define MPI2_SAS_IOUNIT7_GROUP_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -2615,7 +2556,7 @@ typedef struct _MPI2_CONFIG_PAGE_SASIOUNIT_7 { U8 Reserved4; /*0x15 */ U16 Reserved5; /*0x16 */ MPI2_SAS_IO_UNIT7_PORT_WIDTH_MOD_GROUP_SETTINGS - PortWidthModulationGroupSettings[MPI2_SAS_IOUNIT7_GROUP_MAX];/*0x18 */ + PortWidthModulationGroupSettings[]; /*0x18 */ } MPI2_CONFIG_PAGE_SASIOUNIT_7, *PTR_MPI2_CONFIG_PAGE_SASIOUNIT_7, Mpi2SasIOUnitPage7_t, *pMpi2SasIOUnitPage7_t; @@ -3086,12 +3027,9 @@ typedef struct _MPI2_SASPHY2_PHY_EVENT { /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhyEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhyEvents at runtime before using PhyEvent[]. */ -#ifndef MPI2_SASPHY2_PHY_EVENT_MAX -#define MPI2_SASPHY2_PHY_EVENT_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { MPI2_CONFIG_EXTENDED_PAGE_HEADER @@ -3105,7 +3043,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_2 { U16 Reserved3; /*0x0E */ MPI2_SASPHY2_PHY_EVENT - PhyEvent[MPI2_SASPHY2_PHY_EVENT_MAX]; /*0x10 */ + PhyEvent[]; /*0x10 */ } MPI2_CONFIG_PAGE_SAS_PHY_2, *PTR_MPI2_CONFIG_PAGE_SAS_PHY_2, Mpi2SasPhyPage2_t, @@ -3200,12 +3138,9 @@ typedef struct _MPI2_SASPHY3_PHY_EVENT_CONFIG { #define MPI2_SASPHY3_TFLAGS_EVENT_NOTIFY (0x0001) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhyEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhyEvents at runtime before using PhyEventConfig[]. */ -#ifndef MPI2_SASPHY3_PHY_EVENT_MAX -#define MPI2_SASPHY3_PHY_EVENT_MAX (1) -#endif typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { MPI2_CONFIG_EXTENDED_PAGE_HEADER @@ -3219,7 +3154,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_PHY_3 { U16 Reserved3; /*0x0E */ MPI2_SASPHY3_PHY_EVENT_CONFIG - PhyEventConfig[MPI2_SASPHY3_PHY_EVENT_MAX]; /*0x10 */ + PhyEventConfig[]; /*0x10 */ } MPI2_CONFIG_PAGE_SAS_PHY_3, *PTR_MPI2_CONFIG_PAGE_SAS_PHY_3, Mpi2SasPhyPage3_t, *pMpi2SasPhyPage3_t; @@ -3358,12 +3293,9 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0 { /*Log Page 0 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumLogEntries at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumLogEntries at runtime before using LogEntry[]. */ -#ifndef MPI2_LOG_0_NUM_LOG_ENTRIES -#define MPI2_LOG_0_NUM_LOG_ENTRIES (1) -#endif #define MPI2_LOG_0_LOG_DATA_LENGTH (0x1C) @@ -3393,8 +3325,7 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0 { U32 Reserved2; /*0x0C */ U16 NumLogEntries;/*0x10 */ U16 Reserved3; /*0x12 */ - MPI2_LOG_0_ENTRY - LogEntry[MPI2_LOG_0_NUM_LOG_ENTRIES]; /*0x14 */ + MPI2_LOG_0_ENTRY LogEntry[]; /*0x14 */ } MPI2_CONFIG_PAGE_LOG_0, *PTR_MPI2_CONFIG_PAGE_LOG_0, Mpi2LogPage0_t, *pMpi2LogPage0_t; @@ -3408,12 +3339,9 @@ typedef struct _MPI2_CONFIG_PAGE_LOG_0 { /*RAID Page 0 */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumElements at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumElements at runtime before using ConfigElement[]. */ -#ifndef MPI2_RAIDCONFIG0_MAX_ELEMENTS -#define MPI2_RAIDCONFIG0_MAX_ELEMENTS (1) -#endif typedef struct _MPI2_RAIDCONFIG0_CONFIG_ELEMENT { U16 ElementFlags; /*0x00 */ @@ -3446,8 +3374,7 @@ typedef struct _MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0 { U8 NumElements; /*0x2C */ U8 Reserved2; /*0x2D */ U16 Reserved3; /*0x2E */ - MPI2_RAIDCONFIG0_CONFIG_ELEMENT - ConfigElement[MPI2_RAIDCONFIG0_MAX_ELEMENTS]; /*0x30 */ + MPI2_RAIDCONFIG0_CONFIG_ELEMENT ConfigElement[];/*0x30 */ } MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, *PTR_MPI2_CONFIG_PAGE_RAID_CONFIGURATION_0, Mpi2RaidConfigurationPage0_t, @@ -3687,12 +3614,9 @@ typedef struct _MPI26_PCIE_IO_UNIT0_PHY_DATA { Mpi26PCIeIOUnit0PhyData_t, *pMpi26PCIeIOUnit0PhyData_t; /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI26_PCIE_IOUNIT0_PHY_MAX -#define MPI26_PCIE_IOUNIT0_PHY_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_0 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -3701,7 +3625,7 @@ typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_0 { U8 InitStatus; /*0x0D */ U16 Reserved3; /*0x0E */ MPI26_PCIE_IO_UNIT0_PHY_DATA - PhyData[MPI26_PCIE_IOUNIT0_PHY_MAX]; /*0x10 */ + PhyData[]; /*0x10 */ } MPI26_CONFIG_PAGE_PIOUNIT_0, *PTR_MPI26_CONFIG_PAGE_PIOUNIT_0, Mpi26PCIeIOUnitPage0_t, *pMpi26PCIeIOUnitPage0_t; @@ -3744,12 +3668,9 @@ typedef struct _MPI26_PCIE_IO_UNIT1_PHY_DATA { #define MPI26_PCIEIOUNIT1_LINKFLAGS_SRNS_EN (0x02) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumPhys at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumPhys at runtime before using PhyData[]. */ -#ifndef MPI26_PCIE_IOUNIT1_PHY_MAX -#define MPI26_PCIE_IOUNIT1_PHY_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -3761,7 +3682,7 @@ typedef struct _MPI26_CONFIG_PAGE_PIOUNIT_1 { U8 DMDReportPCIe; /*0x11 */ U16 Reserved2; /*0x12 */ MPI26_PCIE_IO_UNIT1_PHY_DATA - PhyData[MPI26_PCIE_IOUNIT1_PHY_MAX];/*0x14 */ + PhyData[]; /*0x14 */ } MPI26_CONFIG_PAGE_PIOUNIT_1, *PTR_MPI26_CONFIG_PAGE_PIOUNIT_1, Mpi26PCIeIOUnitPage1_t, *pMpi26PCIeIOUnitPage1_t; @@ -3993,12 +3914,9 @@ typedef struct _MPI26_PCIELINK2_LINK_EVENT { /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumLinkEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumLinkEvents at runtime before using LinkEvent[]. */ -#ifndef MPI26_PCIELINK2_LINK_EVENT_MAX -#define MPI26_PCIELINK2_LINK_EVENT_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PCIELINK_2 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -4009,7 +3927,7 @@ typedef struct _MPI26_CONFIG_PAGE_PCIELINK_2 { U8 Reserved3; /*0x0D */ U16 Reserved4; /*0x0E */ MPI26_PCIELINK2_LINK_EVENT - LinkEvent[MPI26_PCIELINK2_LINK_EVENT_MAX]; /*0x10 */ + LinkEvent[]; /*0x10 */ } MPI26_CONFIG_PAGE_PCIELINK_2, *PTR_MPI26_CONFIG_PAGE_PCIELINK_2, Mpi26PcieLinkPage2_t, *pMpi26PcieLinkPage2_t; @@ -4067,12 +3985,9 @@ typedef struct _MPI26_PCIELINK3_LINK_EVENT_CONFIG { #define MPI26_PCIELINK3_TFLAGS_EVENT_NOTIFY (0x0001) /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check the value returned for NumLinkEvents at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check the value returned + *for NumLinkEvents at runtime before using LinkEventConfig[]. */ -#ifndef MPI26_PCIELINK3_LINK_EVENT_MAX -#define MPI26_PCIELINK3_LINK_EVENT_MAX (1) -#endif typedef struct _MPI26_CONFIG_PAGE_PCIELINK_3 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /*0x00 */ @@ -4083,7 +3998,7 @@ typedef struct _MPI26_CONFIG_PAGE_PCIELINK_3 { U8 Reserved3; /*0x0D */ U16 Reserved4; /*0x0E */ MPI26_PCIELINK3_LINK_EVENT_CONFIG - LinkEventConfig[MPI26_PCIELINK3_LINK_EVENT_MAX]; /*0x10 */ + LinkEventConfig[]; /*0x10 */ } MPI26_CONFIG_PAGE_PCIELINK_3, *PTR_MPI26_CONFIG_PAGE_PCIELINK_3, Mpi26PcieLinkPage3_t, *pMpi26PcieLinkPage3_t; diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_image.h b/drivers/scsi/mpt3sas/mpi/mpi2_image.h index 33b9c3a6fd40..798ab6e33eb9 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_image.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_image.h @@ -295,20 +295,9 @@ typedef struct _MPI2_EXT_IMAGE_HEADER { /*FLASH Layout Extended Image Data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check RegionsPerLayout at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumberOfLayouts and + *RegionsPerLayout at runtime before using Layout[] and Region[]. */ -#ifndef MPI2_FLASH_NUMBER_OF_REGIONS -#define MPI2_FLASH_NUMBER_OF_REGIONS (1) -#endif - -/* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumberOfLayouts at runtime. - */ -#ifndef MPI2_FLASH_NUMBER_OF_LAYOUTS -#define MPI2_FLASH_NUMBER_OF_LAYOUTS (1) -#endif typedef struct _MPI2_FLASH_REGION { U8 RegionType; /*0x00 */ @@ -325,7 +314,7 @@ typedef struct _MPI2_FLASH_LAYOUT { U32 Reserved1; /*0x04 */ U32 Reserved2; /*0x08 */ U32 Reserved3; /*0x0C */ - MPI2_FLASH_REGION Region[MPI2_FLASH_NUMBER_OF_REGIONS]; /*0x10 */ + MPI2_FLASH_REGION Region[]; /*0x10 */ } MPI2_FLASH_LAYOUT, *PTR_MPI2_FLASH_LAYOUT, Mpi2FlashLayout_t, *pMpi2FlashLayout_t; @@ -339,7 +328,7 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA { U16 MinimumSectorAlignment; /*0x08 */ U16 Reserved3; /*0x0A */ U32 Reserved4; /*0x0C */ - MPI2_FLASH_LAYOUT Layout[MPI2_FLASH_NUMBER_OF_LAYOUTS]; /*0x10 */ + MPI2_FLASH_LAYOUT Layout[]; /*0x10 */ } MPI2_FLASH_LAYOUT_DATA, *PTR_MPI2_FLASH_LAYOUT_DATA, Mpi2FlashLayoutData_t, *pMpi2FlashLayoutData_t; @@ -373,12 +362,9 @@ typedef struct _MPI2_FLASH_LAYOUT_DATA { /*Supported Devices Extended Image Data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumberOfDevices at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumberOfDevices at + *runtime before using SupportedDevice[]. */ -#ifndef MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES -#define MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES (1) -#endif typedef struct _MPI2_SUPPORTED_DEVICE { U16 DeviceID; /*0x00 */ @@ -399,7 +385,7 @@ typedef struct _MPI2_SUPPORTED_DEVICES_DATA { U8 Reserved2; /*0x03 */ U32 Reserved3; /*0x04 */ MPI2_SUPPORTED_DEVICE - SupportedDevice[MPI2_SUPPORTED_DEVICES_IMAGE_NUM_DEVICES];/*0x08 */ + SupportedDevice[]; /*0x08 */ } MPI2_SUPPORTED_DEVICES_DATA, *PTR_MPI2_SUPPORTED_DEVICES_DATA, Mpi2SupportedDevicesData_t, *pMpi2SupportedDevicesData_t; @@ -464,7 +450,7 @@ typedef struct _MPI25_ENCRYPTED_HASH_ENTRY { U8 EncryptionAlgorithm; /*0x02 */ U8 Reserved1; /*0x03 */ U32 Reserved2; /*0x04 */ - U32 EncryptedHash[1]; /*0x08 */ /* variable length */ + U32 EncryptedHash[]; /*0x08 */ } MPI25_ENCRYPTED_HASH_ENTRY, *PTR_MPI25_ENCRYPTED_HASH_ENTRY, Mpi25EncryptedHashEntry_t, *pMpi25EncryptedHashEntry_t; @@ -508,7 +494,7 @@ typedef struct _MPI25_ENCRYPTED_HASH_DATA { U8 NumHash; /*0x01 */ U16 Reserved1; /*0x02 */ U32 Reserved2; /*0x04 */ - MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[1]; /*0x08 */ + MPI25_ENCRYPTED_HASH_ENTRY EncryptedHashEntry[]; /*0x08 */ } MPI25_ENCRYPTED_HASH_DATA, *PTR_MPI25_ENCRYPTED_HASH_DATA, Mpi25EncryptedHashData_t, *pMpi25EncryptedHashData_t; diff --git a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h index 2c57115172cf..d92852591134 100644 --- a/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h +++ b/drivers/scsi/mpt3sas/mpi/mpi2_ioc.h @@ -808,12 +808,9 @@ typedef struct _MPI2_EVENT_DATA_IR_PHYSICAL_DISK { /*Integrated RAID Configuration Change List Event data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumElements at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumElements at + *runtime before using ConfigElement[]. */ -#ifndef MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT -#define MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT (1) -#endif typedef struct _MPI2_EVENT_IR_CONFIG_ELEMENT { U16 ElementFlags; /*0x00 */ @@ -848,7 +845,7 @@ typedef struct _MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST { U8 ConfigNum; /*0x03 */ U32 Flags; /*0x04 */ MPI2_EVENT_IR_CONFIG_ELEMENT - ConfigElement[MPI2_EVENT_IR_CONFIG_ELEMENT_COUNT];/*0x08 */ + ConfigElement[];/*0x08 */ } MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, *PTR_MPI2_EVENT_DATA_IR_CONFIG_CHANGE_LIST, Mpi2EventDataIrConfigChangeList_t, @@ -969,12 +966,9 @@ typedef struct _MPI2_EVENT_DATA_SAS_INIT_TABLE_OVERFLOW { /*SAS Topology Change List Event data */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumEntries at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumEntries at + *runtime before using PHY[]. */ -#ifndef MPI2_EVENT_SAS_TOPO_PHY_COUNT -#define MPI2_EVENT_SAS_TOPO_PHY_COUNT (1) -#endif typedef struct _MPI2_EVENT_SAS_TOPO_PHY_ENTRY { U16 AttachedDevHandle; /*0x00 */ @@ -994,7 +988,7 @@ typedef struct _MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST { U8 ExpStatus; /*0x0A */ U8 PhysicalPort; /*0x0B */ MPI2_EVENT_SAS_TOPO_PHY_ENTRY - PHY[MPI2_EVENT_SAS_TOPO_PHY_COUNT]; /*0x0C */ + PHY[]; /*0x0C */ } MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, *PTR_MPI2_EVENT_DATA_SAS_TOPOLOGY_CHANGE_LIST, Mpi2EventDataSasTopologyChangeList_t, @@ -1229,12 +1223,9 @@ typedef struct _MPI26_EVENT_DATA_PCIE_ENUMERATION { /*PCIe Topology Change List Event data (MPI v2.6 and later) */ /* - *Host code (drivers, BIOS, utilities, etc.) should leave this define set to - *one and check NumEntries at runtime. + *Host code (drivers, BIOS, utilities, etc.) should check NumEntries at + *runtime before using PortEntry[]. */ -#ifndef MPI26_EVENT_PCIE_TOPO_PORT_COUNT -#define MPI26_EVENT_PCIE_TOPO_PORT_COUNT (1) -#endif typedef struct _MPI26_EVENT_PCIE_TOPO_PORT_ENTRY { U16 AttachedDevHandle; /*0x00 */ @@ -1286,7 +1277,7 @@ typedef struct _MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST { U8 SwitchStatus; /*0x0A */ U8 PhysicalPort; /*0x0B */ MPI26_EVENT_PCIE_TOPO_PORT_ENTRY - PortEntry[MPI26_EVENT_PCIE_TOPO_PORT_COUNT]; /*0x0C */ + PortEntry[]; /*0x0C */ } MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, *PTR_MPI26_EVENT_DATA_PCIE_TOPOLOGY_CHANGE_LIST, Mpi26EventDataPCIeTopologyChangeList_t, diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index a75f670bf551..8761bc58d965 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4893,8 +4893,7 @@ mpt3sas_base_update_missing_delay(struct MPT3SAS_ADAPTER *ioc, if (!num_phys) return; - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -5044,7 +5043,7 @@ _base_get_event_diag_triggers(struct MPT3SAS_ADAPTER *ioc) { Mpi26DriverTriggerPage2_t trigger_pg2; struct SL_WH_EVENT_TRIGGER_T *event_tg; - MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY *mpi_event_tg; + MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY *mpi_event_tg; Mpi2ConfigReply_t mpi_reply; int r = 0, i = 0; u16 count = 0; @@ -5096,7 +5095,7 @@ _base_get_scsi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) { Mpi26DriverTriggerPage3_t trigger_pg3; struct SL_WH_SCSI_TRIGGER_T *scsi_tg; - MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY *mpi_scsi_tg; + MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY *mpi_scsi_tg; Mpi2ConfigReply_t mpi_reply; int r = 0, i = 0; u16 count = 0; @@ -5148,7 +5147,7 @@ _base_get_mpi_diag_triggers(struct MPT3SAS_ADAPTER *ioc) { Mpi26DriverTriggerPage4_t trigger_pg4; struct SL_WH_MPI_TRIGGER_T *status_tg; - MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY *mpi_status_tg; + MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY *mpi_status_tg; Mpi2ConfigReply_t mpi_reply; int r = 0, i = 0; u16 count = 0; @@ -5379,10 +5378,9 @@ _base_update_diag_trigger_pages(struct MPT3SAS_ADAPTER *ioc) static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc) { Mpi2ConfigReply_t mpi_reply; - Mpi2SasIOUnitPage1_t *sas_iounit_pg1 = NULL; + Mpi2SasIOUnitPage1_t sas_iounit_pg1; Mpi26PCIeIOUnitPage1_t pcie_iounit_pg1; u16 depth; - int sz; int rc = 0; ioc->max_wideport_qd = MPT3SAS_SAS_QUEUE_DEPTH; @@ -5392,28 +5390,21 @@ static int _base_assign_fw_reported_qd(struct MPT3SAS_ADAPTER *ioc) if (!ioc->is_gen35_ioc) goto out; /* sas iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData); - sas_iounit_pg1 = kzalloc(sizeof(Mpi2SasIOUnitPage1_t), GFP_KERNEL); - if (!sas_iounit_pg1) { - pr_err("%s: failure at %s:%d/%s()!\n", - ioc->name, __FILE__, __LINE__, __func__); - return rc; - } rc = mpt3sas_config_get_sas_iounit_pg1(ioc, &mpi_reply, - sas_iounit_pg1, sz); + &sas_iounit_pg1, sizeof(Mpi2SasIOUnitPage1_t)); if (rc) { pr_err("%s: failure at %s:%d/%s()!\n", ioc->name, __FILE__, __LINE__, __func__); goto out; } - depth = le16_to_cpu(sas_iounit_pg1->SASWideMaxQueueDepth); + depth = le16_to_cpu(sas_iounit_pg1.SASWideMaxQueueDepth); ioc->max_wideport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH); - depth = le16_to_cpu(sas_iounit_pg1->SASNarrowMaxQueueDepth); + depth = le16_to_cpu(sas_iounit_pg1.SASNarrowMaxQueueDepth); ioc->max_narrowport_qd = (depth ? depth : MPT3SAS_SAS_QUEUE_DEPTH); - depth = sas_iounit_pg1->SATAMaxQDepth; + depth = sas_iounit_pg1.SATAMaxQDepth; ioc->max_sata_qd = (depth ? depth : MPT3SAS_SATA_QUEUE_DEPTH); /* pcie iounit page 1 */ @@ -5432,7 +5423,6 @@ out: "MaxWidePortQD: 0x%x MaxNarrowPortQD: 0x%x MaxSataQD: 0x%x MaxNvmeQD: 0x%x\n", ioc->max_wideport_qd, ioc->max_narrowport_qd, ioc->max_sata_qd, ioc->max_nvme_qd)); - kfree(sas_iounit_pg1); return rc; } @@ -5588,6 +5578,7 @@ out: static int _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) { + Mpi2IOUnitPage8_t iounit_pg8; Mpi2ConfigReply_t mpi_reply; u32 iounit_pg1_flags; int tg_flags = 0; @@ -5684,7 +5675,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) rc = mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1); if (rc) return rc; - rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8); + rc = mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &iounit_pg8); if (rc) return rc; _base_display_ioc_capabilities(ioc); @@ -5706,8 +5697,8 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc) if (rc) return rc; - if (ioc->iounit_pg8.NumSensors) - ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors; + if (iounit_pg8.NumSensors) + ioc->temp_sensors_count = iounit_pg8.NumSensors; if (ioc->is_aero_ioc) { rc = _base_update_ioc_page1_inlinewith_perf_mode(ioc); if (rc) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 1be0850ca17a..6d0bc8c66700 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -1237,7 +1237,6 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc); * @ioc_pg8: static ioc page 8 * @iounit_pg0: static iounit page 0 * @iounit_pg1: static iounit page 1 - * @iounit_pg8: static iounit page 8 * @sas_hba: sas host object * @sas_expander_list: expander object list * @enclosure_list: enclosure object list @@ -1465,7 +1464,6 @@ struct MPT3SAS_ADAPTER { Mpi2IOCPage8_t ioc_pg8; Mpi2IOUnitPage0_t iounit_pg0; Mpi2IOUnitPage1_t iounit_pg1; - Mpi2IOUnitPage8_t iounit_pg8; Mpi2IOCPage1_t ioc_pg1_copy; struct _boot_device req_boot_device; @@ -1983,6 +1981,7 @@ extern const struct attribute_group *mpt3sas_host_groups[]; extern const struct attribute_group *mpt3sas_dev_groups[]; void mpt3sas_ctl_init(ushort hbas_to_enumerate); void mpt3sas_ctl_exit(ushort hbas_to_enumerate); +void mpt3sas_ctl_release(struct MPT3SAS_ADAPTER *ioc); u8 mpt3sas_ctl_done(struct MPT3SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply); void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc); diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c index d114ef381c44..2e88f456fc34 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_config.c +++ b/drivers/scsi/mpt3sas/mpt3sas_config.c @@ -2334,7 +2334,7 @@ mpt3sas_config_update_driver_trigger_pg2(struct MPT3SAS_ADAPTER *ioc, tg_pg2.NumMPIEventTrigger = 0; memset(&tg_pg2.MPIEventTriggers[0], 0, NUM_VALID_ENTRIES * sizeof( - MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY)); + MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY)); } rc = _config_set_driver_trigger_pg2(ioc, &mpi_reply, &tg_pg2); @@ -2493,7 +2493,7 @@ mpt3sas_config_update_driver_trigger_pg3(struct MPT3SAS_ADAPTER *ioc, tg_pg3.NumSCSISenseTrigger = 0; memset(&tg_pg3.SCSISenseTriggers[0], 0, NUM_VALID_ENTRIES * sizeof( - MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY)); + MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY)); } rc = _config_set_driver_trigger_pg3(ioc, &mpi_reply, &tg_pg3); @@ -2649,7 +2649,7 @@ mpt3sas_config_update_driver_trigger_pg4(struct MPT3SAS_ADAPTER *ioc, tg_pg4.NumIOCStatusLogInfoTrigger = 0; memset(&tg_pg4.IOCStatusLoginfoTriggers[0], 0, NUM_VALID_ENTRIES * sizeof( - MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY)); + MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY)); } rc = _config_set_driver_trigger_pg4(ioc, &mpi_reply, &tg_pg4); diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index efdb8178db32..147cb7088d55 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -4157,31 +4157,37 @@ mpt3sas_ctl_init(ushort hbas_to_enumerate) } /** - * mpt3sas_ctl_exit - exit point for ctl - * @hbas_to_enumerate: ? + * mpt3sas_ctl_release - release dma for ctl + * @ioc: per adapter object */ void -mpt3sas_ctl_exit(ushort hbas_to_enumerate) +mpt3sas_ctl_release(struct MPT3SAS_ADAPTER *ioc) { - struct MPT3SAS_ADAPTER *ioc; int i; - list_for_each_entry(ioc, &mpt3sas_ioc_list, list) { + /* free memory associated to diag buffers */ + for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { + if (!ioc->diag_buffer[i]) + continue; + dma_free_coherent(&ioc->pdev->dev, + ioc->diag_buffer_sz[i], + ioc->diag_buffer[i], + ioc->diag_buffer_dma[i]); + ioc->diag_buffer[i] = NULL; + ioc->diag_buffer_status[i] = 0; + } - /* free memory associated to diag buffers */ - for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { - if (!ioc->diag_buffer[i]) - continue; - dma_free_coherent(&ioc->pdev->dev, - ioc->diag_buffer_sz[i], - ioc->diag_buffer[i], - ioc->diag_buffer_dma[i]); - ioc->diag_buffer[i] = NULL; - ioc->diag_buffer_status[i] = 0; - } + kfree(ioc->event_log); +} + +/** + * mpt3sas_ctl_exit - exit point for ctl + * @hbas_to_enumerate: ? + */ +void +mpt3sas_ctl_exit(ushort hbas_to_enumerate) +{ - kfree(ioc->event_log); - } if (hbas_to_enumerate != 1) misc_deregister(&ctl_dev); if (hbas_to_enumerate != 2) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 605013d3ee83..51b5788da040 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -2431,8 +2431,7 @@ _scsih_get_volume_capabilities(struct MPT3SAS_ADAPTER *ioc, } raid_device->num_pds = num_pds; - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); + sz = struct_size(vol_pg0, PhysDisk, num_pds); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { dfailprintk(ioc, @@ -5966,8 +5965,7 @@ _scsih_update_vphys_after_reset(struct MPT3SAS_ADAPTER *ioc) /* * Read SASIOUnitPage0 to get each HBA Phy's data. */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + - (ioc->sas_hba.num_phys * sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6145,8 +6143,7 @@ _scsih_get_port_table_after_reset(struct MPT3SAS_ADAPTER *ioc, u64 attached_sas_addr; u8 found = 0, port_count = 0, port_id; - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys - * sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6579,8 +6576,7 @@ _scsih_sas_host_refresh(struct MPT3SAS_ADAPTER *ioc) ioc_info(ioc, "updating handles for sas_host(0x%016llx)\n", (u64)ioc->sas_hba.sas_address)); - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys - * sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6731,8 +6727,7 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) ioc->sas_hba.num_phys = num_phys; /* sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -6754,8 +6749,7 @@ _scsih_sas_host_add(struct MPT3SAS_ADAPTER *ioc) } /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -10376,8 +10370,8 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) Mpi2ExpanderPage0_t expander_pg0; Mpi2SasDevicePage0_t sas_device_pg0; Mpi26PCIeDevicePage0_t pcie_device_pg0; - Mpi2RaidVolPage1_t *volume_pg1; - Mpi2RaidVolPage0_t *volume_pg0; + Mpi2RaidVolPage1_t volume_pg1; + Mpi2RaidVolPage0_t volume_pg0; Mpi2RaidPhysDiskPage0_t pd_pg0; Mpi2EventIrConfigElement_t element; Mpi2ConfigReply_t mpi_reply; @@ -10392,16 +10386,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) u8 retry_count; unsigned long flags; - volume_pg0 = kzalloc(sizeof(*volume_pg0), GFP_KERNEL); - if (!volume_pg0) - return; - - volume_pg1 = kzalloc(sizeof(*volume_pg1), GFP_KERNEL); - if (!volume_pg1) { - kfree(volume_pg0); - return; - } - ioc_info(ioc, "scan devices: start\n"); _scsih_sas_host_refresh(ioc); @@ -10511,7 +10495,7 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) /* volumes */ handle = 0xFFFF; while (!(mpt3sas_config_get_raid_volume_pg1(ioc, &mpi_reply, - volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { + &volume_pg1, MPI2_RAID_VOLUME_PGAD_FORM_GET_NEXT_HANDLE, handle))) { ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status != MPI2_IOCSTATUS_SUCCESS) { @@ -10519,15 +10503,15 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } - handle = le16_to_cpu(volume_pg1->DevHandle); + handle = le16_to_cpu(volume_pg1.DevHandle); spin_lock_irqsave(&ioc->raid_device_lock, flags); raid_device = _scsih_raid_device_find_by_wwid(ioc, - le64_to_cpu(volume_pg1->WWID)); + le64_to_cpu(volume_pg1.WWID)); spin_unlock_irqrestore(&ioc->raid_device_lock, flags); if (raid_device) continue; if (mpt3sas_config_get_raid_volume_pg0(ioc, &mpi_reply, - volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, + &volume_pg0, MPI2_RAID_VOLUME_PGAD_FORM_HANDLE, handle, sizeof(Mpi2RaidVolPage0_t))) continue; ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & @@ -10537,17 +10521,17 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) ioc_status, le32_to_cpu(mpi_reply.IOCLogInfo)); break; } - if (volume_pg0->VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || - volume_pg0->VolumeState == MPI2_RAID_VOL_STATE_ONLINE || - volume_pg0->VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { + if (volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_OPTIMAL || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_ONLINE || + volume_pg0.VolumeState == MPI2_RAID_VOL_STATE_DEGRADED) { memset(&element, 0, sizeof(Mpi2EventIrConfigElement_t)); element.ReasonCode = MPI2_EVENT_IR_CHANGE_RC_ADDED; - element.VolDevHandle = volume_pg1->DevHandle; + element.VolDevHandle = volume_pg1.DevHandle; ioc_info(ioc, "\tBEFORE adding volume: handle (0x%04x)\n", - volume_pg1->DevHandle); + volume_pg1.DevHandle); _scsih_sas_volume_add(ioc, &element); ioc_info(ioc, "\tAFTER adding volume: handle (0x%04x)\n", - volume_pg1->DevHandle); + volume_pg1.DevHandle); } } @@ -10636,9 +10620,6 @@ _scsih_scan_for_devices_after_reset(struct MPT3SAS_ADAPTER *ioc) handle, (u64)le64_to_cpu(pcie_device_pg0.WWID)); } - kfree(volume_pg0); - kfree(volume_pg1); - ioc_info(ioc, "\tpcie devices: pcie end devices complete\n"); ioc_info(ioc, "scan devices: complete\n"); } @@ -11350,6 +11331,7 @@ static void scsih_remove(struct pci_dev *pdev) } mpt3sas_base_detach(ioc); + mpt3sas_ctl_release(ioc); spin_lock(&gioc_lock); list_del(&ioc->list); spin_unlock(&gioc_lock); diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c index e8a4750f6ec4..421ea511b664 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_transport.c +++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c @@ -1792,8 +1792,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable) /* handle hba phys */ /* read sas_iounit page 0 */ - sz = offsetof(Mpi2SasIOUnitPage0_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit0PhyData_t)); + sz = struct_size(sas_iounit_pg0, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg0 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg0) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -1833,8 +1832,7 @@ _transport_phy_enable(struct sas_phy *phy, int enable) } /* read sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", @@ -1944,8 +1942,7 @@ _transport_phy_speed(struct sas_phy *phy, struct sas_phy_linkrates *rates) /* handle hba phys */ /* sas_iounit page 1 */ - sz = offsetof(Mpi2SasIOUnitPage1_t, PhyData) + (ioc->sas_hba.num_phys * - sizeof(Mpi2SasIOUnit1PhyData_t)); + sz = struct_size(sas_iounit_pg1, PhyData, ioc->sas_hba.num_phys); sas_iounit_pg1 = kzalloc(sz, GFP_KERNEL); if (!sas_iounit_pg1) { ioc_err(ioc, "failure at %s:%d/%s()!\n", diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h index 5f3328f011a2..edb8fe709089 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_pages.h @@ -20,12 +20,12 @@ #define MPI2_CONFIG_EXTPAGETYPE_DRIVER_PERSISTENT_TRIGGER (0xE0) #define MPI26_DRIVER_TRIGGER_PAGE0_PAGEVERSION (0x01) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_0 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 TriggerFlags; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ U32 Reserved0xC[61]; /* 0x0C */ -} _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0, Mpi26DriverTriggerPage0_t; +} _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_0, Mpi26DriverTriggerPage0_t; /* Trigger Flags */ #define MPI26_DRIVER_TRIGGER0_FLAG_MASTER_TRIGGER_VALID (0x0001) @@ -34,61 +34,61 @@ typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_0 { #define MPI26_DRIVER_TRIGGER0_FLAG_LOGINFO_TRIGGER_VALID (0x0008) #define MPI26_DRIVER_TRIGGER_PAGE1_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_MASTER_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_MASTER_TRIGGER_ENTRY { U32 MasterTriggerFlags; -} MPI26_DRIVER_MASTER_TIGGER_ENTRY; +} MPI26_DRIVER_MASTER_TRIGGER_ENTRY; #define MPI26_MAX_MASTER_TRIGGERS (1) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_1 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_1 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumMasterTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_MASTER_TIGGER_ENTRY MasterTriggers[MPI26_MAX_MASTER_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_1, Mpi26DriverTriggerPage1_t; + MPI26_DRIVER_MASTER_TRIGGER_ENTRY MasterTriggers[MPI26_MAX_MASTER_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_1, Mpi26DriverTriggerPage1_t; #define MPI26_DRIVER_TRIGGER_PAGE2_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY { U16 MPIEventCode; /* 0x00 */ U16 MPIEventCodeSpecific; /* 0x02 */ -} MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY; +} MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY; #define MPI26_MAX_MPI_EVENT_TRIGGERS (20) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_2 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_2 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumMPIEventTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_MPI_EVENT_TIGGER_ENTRY MPIEventTriggers[MPI26_MAX_MPI_EVENT_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_2, Mpi26DriverTriggerPage2_t; + MPI26_DRIVER_MPI_EVENT_TRIGGER_ENTRY MPIEventTriggers[MPI26_MAX_MPI_EVENT_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_2, Mpi26DriverTriggerPage2_t; #define MPI26_DRIVER_TRIGGER_PAGE3_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY { U8 ASCQ; /* 0x00 */ U8 ASC; /* 0x01 */ U8 SenseKey; /* 0x02 */ U8 Reserved; /* 0x03 */ -} MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY; +} MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY; #define MPI26_MAX_SCSI_SENSE_TRIGGERS (20) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_3 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_3 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumSCSISenseTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_SCSI_SENSE_TIGGER_ENTRY SCSISenseTriggers[MPI26_MAX_SCSI_SENSE_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_3, Mpi26DriverTriggerPage3_t; + MPI26_DRIVER_SCSI_SENSE_TRIGGER_ENTRY SCSISenseTriggers[MPI26_MAX_SCSI_SENSE_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_3, Mpi26DriverTriggerPage3_t; #define MPI26_DRIVER_TRIGGER_PAGE4_PAGEVERSION (0x01) -typedef struct _MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY { +typedef struct _MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY { U16 IOCStatus; /* 0x00 */ U16 Reserved; /* 0x02 */ U32 LogInfo; /* 0x04 */ -} MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY; +} MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY; #define MPI26_MAX_LOGINFO_TRIGGERS (20) -typedef struct _MPI26_CONFIG_PAGE_DRIVER_TIGGER_4 { +typedef struct _MPI26_CONFIG_PAGE_DRIVER_TRIGGER_4 { MPI2_CONFIG_EXTENDED_PAGE_HEADER Header; /* 0x00 */ U16 NumIOCStatusLogInfoTrigger; /* 0x08 */ U16 Reserved0xA; /* 0x0A */ - MPI26_DRIVER_IOCSTATUS_LOGINFO_TIGGER_ENTRY IOCStatusLoginfoTriggers[MPI26_MAX_LOGINFO_TRIGGERS]; /* 0x0C */ -} MPI26_CONFIG_PAGE_DRIVER_TIGGER_4, Mpi26DriverTriggerPage4_t; + MPI26_DRIVER_IOCSTATUS_LOGINFO_TRIGGER_ENTRY IOCStatusLoginfoTriggers[MPI26_MAX_LOGINFO_TRIGGERS]; /* 0x0C */ +} MPI26_CONFIG_PAGE_DRIVER_TRIGGER_4, Mpi26DriverTriggerPage4_t; #endif diff --git a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c index cc07ba41f507..1d64e5056a8a 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c +++ b/drivers/scsi/mpt3sas/mpt3sas_warpdrive.c @@ -141,8 +141,7 @@ mpt3sas_init_warpdrive_properties(struct MPT3SAS_ADAPTER *ioc, return; } - sz = offsetof(Mpi2RaidVolPage0_t, PhysDisk) + (num_pds * - sizeof(Mpi2RaidVol0PhysDisk_t)); + sz = struct_size(vol_pg0, PhysDisk, num_pds); vol_pg0 = kzalloc(sz, GFP_KERNEL); if (!vol_pg0) { ioc_info(ioc, "WarpDrive : Direct IO is disabled Memory allocation failure for RVPG0\n"); diff --git a/drivers/scsi/mvme16x_scsi.c b/drivers/scsi/mvme16x_scsi.c index 21d638299ab8..e08a38e2a442 100644 --- a/drivers/scsi/mvme16x_scsi.c +++ b/drivers/scsi/mvme16x_scsi.c @@ -103,7 +103,7 @@ static int mvme16x_probe(struct platform_device *dev) return -ENODEV; } -static int mvme16x_device_remove(struct platform_device *dev) +static void mvme16x_device_remove(struct platform_device *dev) { struct Scsi_Host *host = platform_get_drvdata(dev); struct NCR_700_Host_Parameters *hostdata = shost_priv(host); @@ -120,8 +120,6 @@ static int mvme16x_device_remove(struct platform_device *dev) NCR_700_release(host); kfree(hostdata); free_irq(host->irq, host); - - return 0; } static struct platform_driver mvme16x_scsi_driver = { @@ -129,7 +127,7 @@ static struct platform_driver mvme16x_scsi_driver = { .name = "mvme16x-scsi", }, .probe = mvme16x_probe, - .remove = mvme16x_device_remove, + .remove_new = mvme16x_device_remove, }; static int __init mvme16x_scsi_init(void) diff --git a/drivers/scsi/qlogicpti.c b/drivers/scsi/qlogicpti.c index 3b95f7a6216f..5d560d9b8944 100644 --- a/drivers/scsi/qlogicpti.c +++ b/drivers/scsi/qlogicpti.c @@ -1409,7 +1409,7 @@ fail_unlink: return -ENODEV; } -static int qpti_sbus_remove(struct platform_device *op) +static void qpti_sbus_remove(struct platform_device *op) { struct qlogicpti *qpti = dev_get_drvdata(&op->dev); @@ -1438,8 +1438,6 @@ static int qpti_sbus_remove(struct platform_device *op) of_iounmap(&op->resource[0], qpti->sreg, sizeof(unsigned char)); scsi_host_put(qpti->qhost); - - return 0; } static const struct of_device_id qpti_match[] = { @@ -1465,7 +1463,7 @@ static struct platform_driver qpti_sbus_driver = { .of_match_table = qpti_match, }, .probe = qpti_sbus_probe, - .remove = qpti_sbus_remove, + .remove_new = qpti_sbus_remove, }; module_platform_driver(qpti_sbus_driver); diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c index 1223d34c04da..885a7d5df3b9 100644 --- a/drivers/scsi/scsi_error.c +++ b/drivers/scsi/scsi_error.c @@ -301,6 +301,7 @@ void scsi_eh_scmd_add(struct scsi_cmnd *scmd) int ret; WARN_ON_ONCE(!shost->ehandler); + WARN_ON_ONCE(!test_bit(SCMD_STATE_INFLIGHT, &scmd->state)); spin_lock_irqsave(shost->host_lock, flags); if (scsi_host_set_state(shost, SHOST_RECOVERY)) { diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c index 88e2b5eb9caa..b0bef83db7b6 100644 --- a/drivers/scsi/sgiwd93.c +++ b/drivers/scsi/sgiwd93.c @@ -291,7 +291,7 @@ out: return err; } -static int sgiwd93_remove(struct platform_device *pdev) +static void sgiwd93_remove(struct platform_device *pdev) { struct Scsi_Host *host = platform_get_drvdata(pdev); struct ip22_hostdata *hdata = (struct ip22_hostdata *) host->hostdata; @@ -302,12 +302,11 @@ static int sgiwd93_remove(struct platform_device *pdev) dma_free_noncoherent(&pdev->dev, HPC_DMA_SIZE, hdata->cpu, hdata->dma, DMA_TO_DEVICE); scsi_host_put(host); - return 0; } static struct platform_driver sgiwd93_driver = { .probe = sgiwd93_probe, - .remove = sgiwd93_remove, + .remove_new = sgiwd93_remove, .driver = { .name = "sgiwd93", } diff --git a/drivers/scsi/sni_53c710.c b/drivers/scsi/sni_53c710.c index 678651b9b4dd..9df1c90a24c1 100644 --- a/drivers/scsi/sni_53c710.c +++ b/drivers/scsi/sni_53c710.c @@ -104,7 +104,7 @@ static int snirm710_probe(struct platform_device *dev) return -ENODEV; } -static int snirm710_driver_remove(struct platform_device *dev) +static void snirm710_driver_remove(struct platform_device *dev) { struct Scsi_Host *host = dev_get_drvdata(&dev->dev); struct NCR_700_Host_Parameters *hostdata = @@ -115,13 +115,11 @@ static int snirm710_driver_remove(struct platform_device *dev) free_irq(host->irq, host); iounmap(hostdata->base); kfree(hostdata); - - return 0; } static struct platform_driver snirm710_driver = { .probe = snirm710_probe, - .remove = snirm710_driver_remove, + .remove_new = snirm710_driver_remove, .driver = { .name = "snirm_53c710", }, diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index abf229b847a1..4a8cc2e8238e 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -641,7 +641,7 @@ fail_alloc: return error; } -static int __exit sun3_scsi_remove(struct platform_device *pdev) +static void __exit sun3_scsi_remove(struct platform_device *pdev) { struct Scsi_Host *instance = platform_get_drvdata(pdev); struct NCR5380_hostdata *hostdata = shost_priv(instance); @@ -654,11 +654,10 @@ static int __exit sun3_scsi_remove(struct platform_device *pdev) if (udc_regs) dvma_free(udc_regs); iounmap(ioaddr); - return 0; } static struct platform_driver sun3_scsi_driver = { - .remove = __exit_p(sun3_scsi_remove), + .remove_new = __exit_p(sun3_scsi_remove), .driver = { .name = DRV_MODULE_NAME, }, diff --git a/drivers/scsi/sun3x_esp.c b/drivers/scsi/sun3x_esp.c index 30f67cbf4a7a..09219c362acc 100644 --- a/drivers/scsi/sun3x_esp.c +++ b/drivers/scsi/sun3x_esp.c @@ -243,7 +243,7 @@ fail: return err; } -static int esp_sun3x_remove(struct platform_device *dev) +static void esp_sun3x_remove(struct platform_device *dev) { struct esp *esp = dev_get_drvdata(&dev->dev); unsigned int irq = esp->host->irq; @@ -261,13 +261,11 @@ static int esp_sun3x_remove(struct platform_device *dev) esp->command_block_dma); scsi_host_put(esp->host); - - return 0; } static struct platform_driver esp_sun3x_driver = { .probe = esp_sun3x_probe, - .remove = esp_sun3x_remove, + .remove_new = esp_sun3x_remove, .driver = { .name = "sun3x_esp", }, diff --git a/drivers/scsi/sun_esp.c b/drivers/scsi/sun_esp.c index afa9d02a33ec..64a7c2c6c5ff 100644 --- a/drivers/scsi/sun_esp.c +++ b/drivers/scsi/sun_esp.c @@ -550,7 +550,7 @@ static int esp_sbus_probe(struct platform_device *op) return ret; } -static int esp_sbus_remove(struct platform_device *op) +static void esp_sbus_remove(struct platform_device *op) { struct esp *esp = dev_get_drvdata(&op->dev); struct platform_device *dma_of = esp->dma; @@ -581,8 +581,6 @@ static int esp_sbus_remove(struct platform_device *op) dev_set_drvdata(&op->dev, NULL); put_device(&dma_of->dev); - - return 0; } static const struct of_device_id esp_match[] = { @@ -605,7 +603,7 @@ static struct platform_driver esp_sbus_driver = { .of_match_table = esp_match, }, .probe = esp_sbus_probe, - .remove = esp_sbus_remove, + .remove_new = esp_sbus_remove, }; module_platform_driver(esp_sbus_driver); diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index 49d9167bb263..80b7d85030d0 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c @@ -470,6 +470,7 @@ static int core_scsi3_pr_seq_non_holder(struct se_cmd *cmd, u32 pr_reg_type, case INQUIRY: case LOG_SENSE: case SERVICE_ACTION_IN_12: + case READ_CAPACITY: case REPORT_LUNS: case REQUEST_SENSE: case PERSISTENT_RESERVE_IN: diff --git a/drivers/ufs/core/ufs-fault-injection.c b/drivers/ufs/core/ufs-fault-injection.c index 5b1184aac585..169540417079 100644 --- a/drivers/ufs/core/ufs-fault-injection.c +++ b/drivers/ufs/core/ufs-fault-injection.c @@ -4,6 +4,7 @@ #include <linux/types.h> #include <linux/fault-inject.h> #include <linux/module.h> +#include <ufs/ufshcd.h> #include "ufs-fault-injection.h" static int ufs_fault_get(char *buffer, const struct kernel_param *kp); @@ -59,12 +60,22 @@ static int ufs_fault_set(const char *val, const struct kernel_param *kp) return 0; } -bool ufs_trigger_eh(void) +void ufs_fault_inject_hba_init(struct ufs_hba *hba) { - return should_fail(&ufs_trigger_eh_attr, 1); + hba->trigger_eh_attr = ufs_trigger_eh_attr; + hba->timeout_attr = ufs_timeout_attr; +#ifdef CONFIG_FAULT_INJECTION_DEBUG_FS + fault_create_debugfs_attr("trigger_eh_inject", hba->debugfs_root, &hba->trigger_eh_attr); + fault_create_debugfs_attr("timeout_inject", hba->debugfs_root, &hba->timeout_attr); +#endif } -bool ufs_fail_completion(void) +bool ufs_trigger_eh(struct ufs_hba *hba) { - return should_fail(&ufs_timeout_attr, 1); + return should_fail(&hba->trigger_eh_attr, 1); +} + +bool ufs_fail_completion(struct ufs_hba *hba) +{ + return should_fail(&hba->timeout_attr, 1); } diff --git a/drivers/ufs/core/ufs-fault-injection.h b/drivers/ufs/core/ufs-fault-injection.h index 6d0cd8e10c87..996a35769781 100644 --- a/drivers/ufs/core/ufs-fault-injection.h +++ b/drivers/ufs/core/ufs-fault-injection.h @@ -7,15 +7,20 @@ #include <linux/types.h> #ifdef CONFIG_SCSI_UFS_FAULT_INJECTION -bool ufs_trigger_eh(void); -bool ufs_fail_completion(void); +void ufs_fault_inject_hba_init(struct ufs_hba *hba); +bool ufs_trigger_eh(struct ufs_hba *hba); +bool ufs_fail_completion(struct ufs_hba *hba); #else -static inline bool ufs_trigger_eh(void) +static inline void ufs_fault_inject_hba_init(struct ufs_hba *hba) +{ +} + +static inline bool ufs_trigger_eh(struct ufs_hba *hba) { return false; } -static inline bool ufs_fail_completion(void) +static inline bool ufs_fail_completion(struct ufs_hba *hba) { return false; } diff --git a/drivers/ufs/core/ufs-sysfs.c b/drivers/ufs/core/ufs-sysfs.c index c95906443d5f..e6d12289e017 100644 --- a/drivers/ufs/core/ufs-sysfs.c +++ b/drivers/ufs/core/ufs-sysfs.c @@ -7,9 +7,56 @@ #include <asm/unaligned.h> #include <ufs/ufs.h> +#include <ufs/unipro.h> #include "ufs-sysfs.h" #include "ufshcd-priv.h" +static const char *ufs_pa_pwr_mode_to_string(enum ufs_pa_pwr_mode mode) +{ + switch (mode) { + case FAST_MODE: return "FAST_MODE"; + case SLOW_MODE: return "SLOW_MODE"; + case FASTAUTO_MODE: return "FASTAUTO_MODE"; + case SLOWAUTO_MODE: return "SLOWAUTO_MODE"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_hs_gear_rate_to_string(enum ufs_hs_gear_rate rate) +{ + switch (rate) { + case PA_HS_MODE_A: return "HS_RATE_A"; + case PA_HS_MODE_B: return "HS_RATE_B"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_pwm_gear_to_string(enum ufs_pwm_gear_tag gear) +{ + switch (gear) { + case UFS_PWM_G1: return "PWM_GEAR1"; + case UFS_PWM_G2: return "PWM_GEAR2"; + case UFS_PWM_G3: return "PWM_GEAR3"; + case UFS_PWM_G4: return "PWM_GEAR4"; + case UFS_PWM_G5: return "PWM_GEAR5"; + case UFS_PWM_G6: return "PWM_GEAR6"; + case UFS_PWM_G7: return "PWM_GEAR7"; + default: return "UNKNOWN"; + } +} + +static const char *ufs_hs_gear_to_string(enum ufs_hs_gear_tag gear) +{ + switch (gear) { + case UFS_HS_G1: return "HS_GEAR1"; + case UFS_HS_G2: return "HS_GEAR2"; + case UFS_HS_G3: return "HS_GEAR3"; + case UFS_HS_G4: return "HS_GEAR4"; + case UFS_HS_G5: return "HS_GEAR5"; + default: return "UNKNOWN"; + } +} + static const char *ufshcd_uic_link_state_to_string( enum uic_link_state state) { @@ -255,6 +302,35 @@ out: return res < 0 ? res : count; } +static ssize_t rtc_update_ms_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%d\n", hba->dev_info.rtc_update_period); +} + +static ssize_t rtc_update_ms_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + unsigned int ms; + bool resume_period_update = false; + + if (kstrtouint(buf, 0, &ms)) + return -EINVAL; + + if (!hba->dev_info.rtc_update_period && ms > 0) + resume_period_update = true; + /* Minimum and maximum update frequency should be synchronized with all UFS vendors */ + hba->dev_info.rtc_update_period = ms; + + if (resume_period_update) + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(hba->dev_info.rtc_update_period)); + return count; +} + static ssize_t enable_wb_buf_flush_show(struct device *dev, struct device_attribute *attr, char *buf) @@ -339,6 +415,7 @@ static DEVICE_ATTR_RW(auto_hibern8); static DEVICE_ATTR_RW(wb_on); static DEVICE_ATTR_RW(enable_wb_buf_flush); static DEVICE_ATTR_RW(wb_flush_threshold); +static DEVICE_ATTR_RW(rtc_update_ms); static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_rpm_lvl.attr, @@ -351,6 +428,7 @@ static struct attribute *ufs_sysfs_ufshcd_attrs[] = { &dev_attr_wb_on.attr, &dev_attr_enable_wb_buf_flush.attr, &dev_attr_wb_flush_threshold.attr, + &dev_attr_rtc_update_ms.attr, NULL }; @@ -628,6 +706,78 @@ static const struct attribute_group ufs_sysfs_monitor_group = { .attrs = ufs_sysfs_monitor_attrs, }; +static ssize_t lane_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%u\n", hba->pwr_info.lane_rx); +} + +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufs_pa_pwr_mode_to_string(hba->pwr_info.pwr_rx)); +} + +static ssize_t rate_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufs_hs_gear_rate_to_string(hba->pwr_info.hs_rate)); +} + +static ssize_t gear_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", hba->pwr_info.hs_rate ? + ufs_hs_gear_to_string(hba->pwr_info.gear_rx) : + ufs_pwm_gear_to_string(hba->pwr_info.gear_rx)); +} + +static ssize_t dev_pm_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufshcd_ufs_dev_pwr_mode_to_string(hba->curr_dev_pwr_mode)); +} + +static ssize_t link_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ufs_hba *hba = dev_get_drvdata(dev); + + return sysfs_emit(buf, "%s\n", ufshcd_uic_link_state_to_string(hba->uic_link_state)); +} + +static DEVICE_ATTR_RO(lane); +static DEVICE_ATTR_RO(mode); +static DEVICE_ATTR_RO(rate); +static DEVICE_ATTR_RO(gear); +static DEVICE_ATTR_RO(dev_pm); +static DEVICE_ATTR_RO(link_state); + +static struct attribute *ufs_power_info_attrs[] = { + &dev_attr_lane.attr, + &dev_attr_mode.attr, + &dev_attr_rate.attr, + &dev_attr_gear.attr, + &dev_attr_dev_pm.attr, + &dev_attr_link_state.attr, + NULL +}; + +static const struct attribute_group ufs_sysfs_power_info_group = { + .name = "power_info", + .attrs = ufs_power_info_attrs, +}; + static ssize_t ufs_sysfs_read_desc_param(struct ufs_hba *hba, enum desc_idn desc_id, u8 desc_index, @@ -1233,6 +1383,7 @@ static const struct attribute_group *ufs_sysfs_groups[] = { &ufs_sysfs_default_group, &ufs_sysfs_capabilities_group, &ufs_sysfs_monitor_group, + &ufs_sysfs_power_info_group, &ufs_sysfs_device_descriptor_group, &ufs_sysfs_interconnect_descriptor_group, &ufs_sysfs_geometry_descriptor_group, diff --git a/drivers/ufs/core/ufshcd.c b/drivers/ufs/core/ufshcd.c index 16d76325039a..d1e33328ff3f 100644 --- a/drivers/ufs/core/ufshcd.c +++ b/drivers/ufs/core/ufshcd.c @@ -99,6 +99,9 @@ /* Polling time to wait for fDeviceInit */ #define FDEVICEINIT_COMPL_TIMEOUT 1500 /* millisecs */ +/* Default RTC update every 10 seconds */ +#define UFS_RTC_UPDATE_INTERVAL_MS (10 * MSEC_PER_SEC) + /* UFSHC 4.0 compliant HC support this mode. */ static bool use_mcq_mode = true; @@ -235,6 +238,12 @@ ufs_get_desired_pm_lvl_for_dev_link_state(enum ufs_dev_pwr_mode dev_state, return UFS_PM_LVL_0; } +static bool ufshcd_is_ufs_dev_busy(struct ufs_hba *hba) +{ + return (hba->clk_gating.active_reqs || hba->outstanding_reqs || hba->outstanding_tasks || + hba->active_uic_cmd || hba->uic_async_done); +} + static const struct ufs_dev_quirk ufs_fixups[] = { /* UFS cards deviations table */ { .wmanufacturerid = UFS_VENDOR_MICRON, @@ -289,21 +298,23 @@ static void ufshcd_wb_toggle_buf_flush_during_h8(struct ufs_hba *hba, static void ufshcd_hba_vreg_set_lpm(struct ufs_hba *hba); static void ufshcd_hba_vreg_set_hpm(struct ufs_hba *hba); -static inline void ufshcd_enable_irq(struct ufs_hba *hba) +void ufshcd_enable_irq(struct ufs_hba *hba) { if (!hba->is_irq_enabled) { enable_irq(hba->irq); hba->is_irq_enabled = true; } } +EXPORT_SYMBOL_GPL(ufshcd_enable_irq); -static inline void ufshcd_disable_irq(struct ufs_hba *hba) +void ufshcd_disable_irq(struct ufs_hba *hba) { if (hba->is_irq_enabled) { disable_irq(hba->irq); hba->is_irq_enabled = false; } } +EXPORT_SYMBOL_GPL(ufshcd_disable_irq); static void ufshcd_configure_wb(struct ufs_hba *hba) { @@ -677,6 +688,8 @@ static void ufshcd_device_reset(struct ufs_hba *hba) hba->dev_info.wb_enabled = false; hba->dev_info.wb_buf_flush_enabled = false; } + if (hba->dev_info.rtc_type == UFS_RTC_RELATIVE) + hba->dev_info.rtc_time_baseline = 0; } if (err != -EOPNOTSUPP) ufshcd_update_evt_hist(hba, UFS_EVT_DEV_RESET, err); @@ -1917,10 +1930,7 @@ static void ufshcd_gate_work(struct work_struct *work) goto rel_lock; } - if (hba->clk_gating.active_reqs - || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL - || hba->outstanding_reqs || hba->outstanding_tasks - || hba->active_uic_cmd || hba->uic_async_done) + if (ufshcd_is_ufs_dev_busy(hba) || hba->ufshcd_state != UFSHCD_STATE_OPERATIONAL) goto rel_lock; spin_unlock_irqrestore(hba->host->host_lock, flags); @@ -2721,6 +2731,8 @@ void ufshcd_prepare_utp_scsi_cmd_upiu(struct ufshcd_lrb *lrbp, u8 upiu_flags) .command_set_type = UPIU_COMMAND_SET_TYPE_SCSI, }; + WARN_ON_ONCE(ucd_req_ptr->header.task_tag != lrbp->task_tag); + ucd_req_ptr->sc.exp_data_transfer_len = cpu_to_be32(cmd->sdb.length); cdb_len = min_t(unsigned short, cmd->cmd_len, UFS_CDB_SIZE); @@ -2993,7 +3005,7 @@ static int ufshcd_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) ufshcd_send_command(hba, tag, hwq); out: - if (ufs_trigger_eh()) { + if (ufs_trigger_eh(hba)) { unsigned long flags; spin_lock_irqsave(hba->host->host_lock, flags); @@ -4402,40 +4414,32 @@ int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) } EXPORT_SYMBOL_GPL(ufshcd_uic_hibern8_exit); -void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) +static void ufshcd_configure_auto_hibern8(struct ufs_hba *hba) { - unsigned long flags; - bool update = false; - if (!ufshcd_is_auto_hibern8_supported(hba)) return; - spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->ahit != ahit) { - hba->ahit = ahit; - update = true; - } - spin_unlock_irqrestore(hba->host->host_lock, flags); + ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); +} + +void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) +{ + const u32 cur_ahit = READ_ONCE(hba->ahit); - if (update && - !pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) { + if (!ufshcd_is_auto_hibern8_supported(hba) || cur_ahit == ahit) + return; + + WRITE_ONCE(hba->ahit, ahit); + if (!pm_runtime_suspended(&hba->ufs_device_wlun->sdev_gendev)) { ufshcd_rpm_get_sync(hba); ufshcd_hold(hba); - ufshcd_auto_hibern8_enable(hba); + ufshcd_configure_auto_hibern8(hba); ufshcd_release(hba); ufshcd_rpm_put_sync(hba); } } EXPORT_SYMBOL_GPL(ufshcd_auto_hibern8_update); -void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) -{ - if (!ufshcd_is_auto_hibern8_supported(hba)) - return; - - ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); -} - /** * ufshcd_init_pwr_info - setting the POR (power on reset) * values in hba power info @@ -5650,7 +5654,7 @@ static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) !(hba->quirks & UFSHCI_QUIRK_SKIP_RESET_INTR_AGGR)) ufshcd_reset_intr_aggr(hba); - if (ufs_fail_completion()) + if (ufs_fail_completion(hba)) return IRQ_HANDLED; /* @@ -8199,6 +8203,79 @@ static void ufs_fixup_device_setup(struct ufs_hba *hba) ufshcd_vops_fixup_dev_quirks(hba); } +static void ufshcd_update_rtc(struct ufs_hba *hba) +{ + struct timespec64 ts64; + int err; + u32 val; + + ktime_get_real_ts64(&ts64); + + if (ts64.tv_sec < hba->dev_info.rtc_time_baseline) { + dev_warn_once(hba->dev, "%s: Current time precedes previous setting!\n", __func__); + return; + } + + /* + * The Absolute RTC mode has a 136-year limit, spanning from 2010 to 2146. If a time beyond + * 2146 is required, it is recommended to choose the relative RTC mode. + */ + val = ts64.tv_sec - hba->dev_info.rtc_time_baseline; + + ufshcd_rpm_get_sync(hba); + err = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_WRITE_ATTR, QUERY_ATTR_IDN_SECONDS_PASSED, + 0, 0, &val); + ufshcd_rpm_put_sync(hba); + + if (err) + dev_err(hba->dev, "%s: Failed to update rtc %d\n", __func__, err); + else if (hba->dev_info.rtc_type == UFS_RTC_RELATIVE) + hba->dev_info.rtc_time_baseline = ts64.tv_sec; +} + +static void ufshcd_rtc_work(struct work_struct *work) +{ + struct ufs_hba *hba; + + hba = container_of(to_delayed_work(work), struct ufs_hba, ufs_rtc_update_work); + + /* Update RTC only when there are no requests in progress and UFSHCI is operational */ + if (!ufshcd_is_ufs_dev_busy(hba) && hba->ufshcd_state == UFSHCD_STATE_OPERATIONAL) + ufshcd_update_rtc(hba); + + if (ufshcd_is_ufs_dev_active(hba) && hba->dev_info.rtc_update_period) + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(hba->dev_info.rtc_update_period)); +} + +static void ufs_init_rtc(struct ufs_hba *hba, u8 *desc_buf) +{ + u16 periodic_rtc_update = get_unaligned_be16(&desc_buf[DEVICE_DESC_PARAM_FRQ_RTC]); + struct ufs_dev_info *dev_info = &hba->dev_info; + + if (periodic_rtc_update & UFS_RTC_TIME_BASELINE) { + dev_info->rtc_type = UFS_RTC_ABSOLUTE; + + /* + * The concept of measuring time in Linux as the number of seconds elapsed since + * 00:00:00 UTC on January 1, 1970, and UFS ABS RTC is elapsed from January 1st + * 2010 00:00, here we need to adjust ABS baseline. + */ + dev_info->rtc_time_baseline = mktime64(2010, 1, 1, 0, 0, 0) - + mktime64(1970, 1, 1, 0, 0, 0); + } else { + dev_info->rtc_type = UFS_RTC_RELATIVE; + dev_info->rtc_time_baseline = 0; + } + + /* + * We ignore TIME_PERIOD defined in wPeriodicRTCUpdate because Spec does not clearly state + * how to calculate the specific update period for each time unit. And we disable periodic + * RTC update work, let user configure by sysfs node according to specific circumstance. + */ + dev_info->rtc_update_period = 0; +} + static int ufs_get_device_desc(struct ufs_hba *hba) { int err; @@ -8251,6 +8328,8 @@ static int ufs_get_device_desc(struct ufs_hba *hba) ufshcd_temp_notif_probe(hba, desc_buf); + ufs_init_rtc(hba, desc_buf); + if (hba->ext_iid_sup) ufshcd_ext_iid_probe(hba, desc_buf); @@ -8804,6 +8883,8 @@ static int ufshcd_device_init(struct ufs_hba *hba, bool init_dev_params) ufshcd_force_reset_auto_bkops(hba); ufshcd_set_timestamp_attr(hba); + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); /* Gear up to HS gear if supported */ if (hba->max_pwr_info.is_valid) { @@ -8878,8 +8959,7 @@ static int ufshcd_probe_hba(struct ufs_hba *hba, bool init_dev_params) if (hba->ee_usr_mask) ufshcd_write_ee_control(hba); - /* Enable Auto-Hibernate if configured */ - ufshcd_auto_hibern8_enable(hba); + ufshcd_configure_auto_hibern8(hba); out: spin_lock_irqsave(hba->host->host_lock, flags); @@ -9362,6 +9442,7 @@ static int ufshcd_hba_init(struct ufs_hba *hba) goto out_disable_vreg; ufs_debugfs_hba_init(hba); + ufs_fault_inject_hba_init(hba); hba->is_powered = true; goto out; @@ -9760,6 +9841,8 @@ vops_suspend: ret = ufshcd_vops_suspend(hba, pm_op, POST_CHANGE); if (ret) goto set_link_active; + + cancel_delayed_work_sync(&hba->ufs_rtc_update_work); goto out; set_link_active: @@ -9854,6 +9937,8 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (ret) goto set_old_link_state; ufshcd_set_timestamp_attr(hba); + schedule_delayed_work(&hba->ufs_rtc_update_work, + msecs_to_jiffies(UFS_RTC_UPDATE_INTERVAL_MS)); } if (ufshcd_keep_autobkops_enabled_except_suspend(hba)) @@ -9876,8 +9961,7 @@ static int __ufshcd_wl_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) cancel_delayed_work(&hba->rpm_dev_flush_recheck_work); } - /* Enable Auto-Hibernate if configured */ - ufshcd_auto_hibern8_enable(hba); + ufshcd_configure_auto_hibern8(hba); goto out; @@ -10550,8 +10634,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) UFS_SLEEP_PWR_MODE, UIC_LINK_HIBERN8_STATE); - INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work, - ufshcd_rpm_dev_flush_recheck_work); + INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work, ufshcd_rpm_dev_flush_recheck_work); + INIT_DELAYED_WORK(&hba->ufs_rtc_update_work, ufshcd_rtc_work); /* Set the default auto-hiberate idle timer value to 150 ms */ if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) { diff --git a/drivers/ufs/host/ufs-exynos.c b/drivers/ufs/host/ufs-exynos.c index 71bd6dbc0547..734d40f99e31 100644 --- a/drivers/ufs/host/ufs-exynos.c +++ b/drivers/ufs/host/ufs-exynos.c @@ -765,7 +765,7 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, { struct exynos_ufs *ufs = ufshcd_get_variant(hba); struct phy *generic_phy = ufs->phy; - struct ufs_dev_params ufs_exynos_cap; + struct ufs_host_params host_params; int ret; if (!dev_req_params) { @@ -774,10 +774,9 @@ static int exynos_ufs_pre_pwr_mode(struct ufs_hba *hba, goto out; } - ufshcd_init_pwr_dev_param(&ufs_exynos_cap); + ufshcd_init_host_params(&host_params); - ret = ufshcd_get_pwr_dev_param(&ufs_exynos_cap, - dev_max_params, dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_err("%s: failed to determine capabilities\n", __func__); goto out; diff --git a/drivers/ufs/host/ufs-hisi.c b/drivers/ufs/host/ufs-hisi.c index 0229ac0a8dbe..5ee73ff05251 100644 --- a/drivers/ufs/host/ufs-hisi.c +++ b/drivers/ufs/host/ufs-hisi.c @@ -293,9 +293,9 @@ static int ufs_hisi_link_startup_notify(struct ufs_hba *hba, return err; } -static void ufs_hisi_set_dev_cap(struct ufs_dev_params *hisi_param) +static void ufs_hisi_set_dev_cap(struct ufs_host_params *host_params) { - ufshcd_init_pwr_dev_param(hisi_param); + ufshcd_init_host_params(host_params); } static void ufs_hisi_pwr_change_pre_change(struct ufs_hba *hba) @@ -365,7 +365,7 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_max_params, struct ufs_pa_layer_attr *dev_req_params) { - struct ufs_dev_params ufs_hisi_cap; + struct ufs_host_params host_params; int ret = 0; if (!dev_req_params) { @@ -377,9 +377,8 @@ static int ufs_hisi_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufs_hisi_set_dev_cap(&ufs_hisi_cap); - ret = ufshcd_get_pwr_dev_param(&ufs_hisi_cap, - dev_max_params, dev_req_params); + ufs_hisi_set_dev_cap(&host_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufs-mediatek.c b/drivers/ufs/host/ufs-mediatek.c index fc61790d289b..776bca4f70c8 100644 --- a/drivers/ufs/host/ufs-mediatek.c +++ b/drivers/ufs/host/ufs-mediatek.c @@ -996,16 +996,14 @@ static int ufs_mtk_pre_pwr_change(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_mtk_host *host = ufshcd_get_variant(hba); - struct ufs_dev_params host_cap; + struct ufs_host_params host_params; int ret; - ufshcd_init_pwr_dev_param(&host_cap); - host_cap.hs_rx_gear = UFS_HS_G5; - host_cap.hs_tx_gear = UFS_HS_G5; + ufshcd_init_host_params(&host_params); + host_params.hs_rx_gear = UFS_HS_G5; + host_params.hs_tx_gear = UFS_HS_G5; - ret = ufshcd_get_pwr_dev_param(&host_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_negotiate_pwr_params(&host_params, dev_max_params, dev_req_params); if (ret) { pr_info("%s: failed to determine capabilities\n", __func__); diff --git a/drivers/ufs/host/ufs-qcom.c b/drivers/ufs/host/ufs-qcom.c index 17e24270477d..480787048e75 100644 --- a/drivers/ufs/host/ufs-qcom.c +++ b/drivers/ufs/host/ufs-qcom.c @@ -4,26 +4,26 @@ */ #include <linux/acpi.h> -#include <linux/time.h> #include <linux/clk.h> #include <linux/delay.h> +#include <linux/devfreq.h> +#include <linux/gpio/consumer.h> #include <linux/interconnect.h> #include <linux/module.h> #include <linux/of.h> -#include <linux/platform_device.h> #include <linux/phy/phy.h> -#include <linux/gpio/consumer.h> +#include <linux/platform_device.h> #include <linux/reset-controller.h> -#include <linux/devfreq.h> +#include <linux/time.h> #include <soc/qcom/ice.h> #include <ufs/ufshcd.h> -#include "ufshcd-pltfrm.h" -#include <ufs/unipro.h> -#include "ufs-qcom.h" #include <ufs/ufshci.h> #include <ufs/ufs_quirks.h> +#include <ufs/unipro.h> +#include "ufshcd-pltfrm.h" +#include "ufs-qcom.h" #define MCQ_QCFGPTR_MASK GENMASK(7, 0) #define MCQ_QCFGPTR_UNIT 0x200 @@ -90,8 +90,6 @@ static const struct __ufs_qcom_bw_table { [MODE_MAX][0][0] = { 7643136, 307200 }, }; -static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS]; - static void ufs_qcom_get_default_testbus_cfg(struct ufs_qcom_host *host); static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up); @@ -158,7 +156,7 @@ static int ufs_qcom_ice_program_key(struct ufs_hba *hba, cap = hba->crypto_cap_array[cfg->crypto_cap_idx]; if (cap.algorithm_id != UFS_CRYPTO_ALG_AES_XTS || cap.key_size != UFS_CRYPTO_KEY_SIZE_256) - return -EINVAL; + return -EOPNOTSUPP; if (config_enable) return qcom_ice_program_key(host->ice, @@ -194,52 +192,12 @@ static inline int ufs_qcom_ice_suspend(struct ufs_qcom_host *host) } #endif -static int ufs_qcom_host_clk_get(struct device *dev, - const char *name, struct clk **clk_out, bool optional) -{ - struct clk *clk; - int err = 0; - - clk = devm_clk_get(dev, name); - if (!IS_ERR(clk)) { - *clk_out = clk; - return 0; - } - - err = PTR_ERR(clk); - - if (optional && err == -ENOENT) { - *clk_out = NULL; - return 0; - } - - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to get %s err %d\n", name, err); - - return err; -} - -static int ufs_qcom_host_clk_enable(struct device *dev, - const char *name, struct clk *clk) -{ - int err = 0; - - err = clk_prepare_enable(clk); - if (err) - dev_err(dev, "%s: %s enable failed %d\n", __func__, name, err); - - return err; -} - static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) { if (!host->is_lane_clks_enabled) return; - clk_disable_unprepare(host->tx_l1_sync_clk); - clk_disable_unprepare(host->tx_l0_sync_clk); - clk_disable_unprepare(host->rx_l1_sync_clk); - clk_disable_unprepare(host->rx_l0_sync_clk); + clk_bulk_disable_unprepare(host->num_clks, host->clks); host->is_lane_clks_enabled = false; } @@ -247,73 +205,29 @@ static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host) static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host) { int err; - struct device *dev = host->hba->dev; - if (host->is_lane_clks_enabled) - return 0; - - err = ufs_qcom_host_clk_enable(dev, "rx_lane0_sync_clk", - host->rx_l0_sync_clk); + err = clk_bulk_prepare_enable(host->num_clks, host->clks); if (err) return err; - err = ufs_qcom_host_clk_enable(dev, "tx_lane0_sync_clk", - host->tx_l0_sync_clk); - if (err) - goto disable_rx_l0; - - err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk", - host->rx_l1_sync_clk); - if (err) - goto disable_tx_l0; - - err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk", - host->tx_l1_sync_clk); - if (err) - goto disable_rx_l1; - host->is_lane_clks_enabled = true; return 0; - -disable_rx_l1: - clk_disable_unprepare(host->rx_l1_sync_clk); -disable_tx_l0: - clk_disable_unprepare(host->tx_l0_sync_clk); -disable_rx_l0: - clk_disable_unprepare(host->rx_l0_sync_clk); - - return err; } static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) { - int err = 0; + int err; struct device *dev = host->hba->dev; if (has_acpi_companion(dev)) return 0; - err = ufs_qcom_host_clk_get(dev, "rx_lane0_sync_clk", - &host->rx_l0_sync_clk, false); - if (err) + err = devm_clk_bulk_get_all(dev, &host->clks); + if (err <= 0) return err; - err = ufs_qcom_host_clk_get(dev, "tx_lane0_sync_clk", - &host->tx_l0_sync_clk, false); - if (err) - return err; - - /* In case of single lane per direction, don't read lane1 clocks */ - if (host->hba->lanes_per_direction > 1) { - err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk", - &host->rx_l1_sync_clk, false); - if (err) - return err; - - err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk", - &host->tx_l1_sync_clk, true); - } + host->num_clks = err; return 0; } @@ -321,7 +235,7 @@ static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host) static int ufs_qcom_check_hibern8(struct ufs_hba *hba) { int err; - u32 tx_fsm_val = 0; + u32 tx_fsm_val; unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS); do { @@ -360,9 +274,7 @@ static int ufs_qcom_check_hibern8(struct ufs_hba *hba) static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) { - ufshcd_rmwl(host->hba, QUNIPRO_SEL, - ufs_qcom_cap_qunipro(host) ? QUNIPRO_SEL : 0, - REG_UFS_CFG1); + ufshcd_rmwl(host->hba, QUNIPRO_SEL, QUNIPRO_SEL, REG_UFS_CFG1); if (host->hw_ver.major >= 0x05) ufshcd_rmwl(host->hba, QUNIPRO_G4_SEL, 0, REG_UFS_CFG0); @@ -376,18 +288,15 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) */ static int ufs_qcom_host_reset(struct ufs_hba *hba) { - int ret = 0; + int ret; struct ufs_qcom_host *host = ufshcd_get_variant(hba); - bool reenable_intr = false; + bool reenable_intr; - if (!host->core_reset) { - dev_warn(hba->dev, "%s: reset control not set\n", __func__); + if (!host->core_reset) return 0; - } reenable_intr = hba->is_irq_enabled; - disable_irq(hba->irq); - hba->is_irq_enabled = false; + ufshcd_disable_irq(hba); ret = reset_control_assert(host->core_reset); if (ret) { @@ -404,16 +313,16 @@ static int ufs_qcom_host_reset(struct ufs_hba *hba) usleep_range(200, 210); ret = reset_control_deassert(host->core_reset); - if (ret) + if (ret) { dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n", __func__, ret); + return ret; + } usleep_range(1000, 1100); - if (reenable_intr) { - enable_irq(hba->irq); - hba->is_irq_enabled = true; - } + if (reenable_intr) + ufshcd_enable_irq(hba); return 0; } @@ -422,18 +331,8 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (host->hw_ver.major == 0x1) { - /* - * HS-G3 operations may not reliably work on legacy QCOM - * UFS host controller hardware even though capability - * exchange during link startup phase may end up - * negotiating maximum supported gear as G3. - * Hence downgrade the maximum supported gear to HS-G2. - */ - return UFS_HS_G2; - } else if (host->hw_ver.major >= 0x4) { + if (host->hw_ver.major >= 0x4) return UFS_QCOM_MAX_GEAR(ufshcd_readl(hba, REG_UFS_PARAM0)); - } /* Default is HS-G3 */ return UFS_HS_G3; @@ -442,14 +341,29 @@ static u32 ufs_qcom_get_hs_gear(struct ufs_hba *hba) static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_host_params *host_params = &host->host_params; struct phy *phy = host->generic_phy; + enum phy_mode mode; int ret; + /* + * HW ver 5 can only support up to HS-G5 Rate-A due to HW limitations. + * If the HS-G5 PHY gear is used, update host_params->hs_rate to Rate-A, + * so that the subsequent power mode change shall stick to Rate-A. + */ + if (host->hw_ver.major == 0x5) { + if (host->phy_gear == UFS_HS_G5) + host_params->hs_rate = PA_HS_MODE_A; + else + host_params->hs_rate = PA_HS_MODE_B; + } + + mode = host_params->hs_rate == PA_HS_MODE_B ? PHY_MODE_UFS_HS_B : PHY_MODE_UFS_HS_A; + /* Reset UFS Host Controller and PHY */ ret = ufs_qcom_host_reset(hba); if (ret) - dev_warn(hba->dev, "%s: host reset returned %d\n", - __func__, ret); + return ret; /* phy initialization - calibrate the phy */ ret = phy_init(phy); @@ -459,7 +373,9 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) return ret; } - phy_set_mode_ext(phy, PHY_MODE_UFS_HS_B, host->phy_gear); + ret = phy_set_mode_ext(phy, mode, host->phy_gear); + if (ret) + goto out_disable_phy; /* power on phy - start serdes and phy's power and clocks */ ret = phy_power_on(phy); @@ -489,9 +405,8 @@ out_disable_phy: */ static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba) { - ufshcd_writel(hba, - ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL, - REG_UFS_CFG2); + ufshcd_rmwl(hba, REG_UFS_CFG2_CGC_EN_ALL, REG_UFS_CFG2_CGC_EN_ALL, + REG_UFS_CFG2); /* Ensure that HW clock gating is enabled before next operations */ mb(); @@ -501,11 +416,14 @@ static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; + int err; switch (status) { case PRE_CHANGE: - ufs_qcom_power_up_sequence(hba); + err = ufs_qcom_power_up_sequence(hba); + if (err) + return err; + /* * The PHY PLL output is the source of tx/rx lane symbol * clocks, hence, enable the lane clocks only after PHY @@ -544,41 +462,16 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, { struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct ufs_clk_info *clki; - u32 core_clk_period_in_ns; - u32 tx_clk_cycles_per_us = 0; unsigned long core_clk_rate = 0; - u32 core_clk_cycles_per_us = 0; - - static u32 pwm_fr_table[][2] = { - {UFS_PWM_G1, 0x1}, - {UFS_PWM_G2, 0x1}, - {UFS_PWM_G3, 0x1}, - {UFS_PWM_G4, 0x1}, - }; - - static u32 hs_fr_table_rA[][2] = { - {UFS_HS_G1, 0x1F}, - {UFS_HS_G2, 0x3e}, - {UFS_HS_G3, 0x7D}, - }; - - static u32 hs_fr_table_rB[][2] = { - {UFS_HS_G1, 0x24}, - {UFS_HS_G2, 0x49}, - {UFS_HS_G3, 0x92}, - }; + u32 core_clk_cycles_per_us; /* - * The Qunipro controller does not use following registers: - * SYS1CLK_1US_REG, TX_SYMBOL_CLK_1US_REG, CLK_NS_REG & - * UFS_REG_PA_LINK_STARTUP_TIMER. - * However UTP controller uses SYS1CLK_1US_REG register for Interrupt + * UTP controller uses SYS1CLK_1US_REG register for Interrupt * Aggregation logic. * It is mandatory to write SYS1CLK_1US_REG register on UFS host * controller V4.0.0 onwards. */ - if (host->hw_ver.major < 4 && ufs_qcom_cap_qunipro(host) && - !ufshcd_is_intr_aggr_allowed(hba)) + if (host->hw_ver.major < 4 && !ufshcd_is_intr_aggr_allowed(hba)) return 0; if (gear == 0) { @@ -611,79 +504,6 @@ static int ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, mb(); } - if (ufs_qcom_cap_qunipro(host)) - return 0; - - core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate; - core_clk_period_in_ns <<= OFFSET_CLK_NS_REG; - core_clk_period_in_ns &= MASK_CLK_NS_REG; - - switch (hs) { - case FASTAUTO_MODE: - case FAST_MODE: - if (rate == PA_HS_MODE_A) { - if (gear > ARRAY_SIZE(hs_fr_table_rA)) { - dev_err(hba->dev, - "%s: index %d exceeds table size %zu\n", - __func__, gear, - ARRAY_SIZE(hs_fr_table_rA)); - return -EINVAL; - } - tx_clk_cycles_per_us = hs_fr_table_rA[gear-1][1]; - } else if (rate == PA_HS_MODE_B) { - if (gear > ARRAY_SIZE(hs_fr_table_rB)) { - dev_err(hba->dev, - "%s: index %d exceeds table size %zu\n", - __func__, gear, - ARRAY_SIZE(hs_fr_table_rB)); - return -EINVAL; - } - tx_clk_cycles_per_us = hs_fr_table_rB[gear-1][1]; - } else { - dev_err(hba->dev, "%s: invalid rate = %d\n", - __func__, rate); - return -EINVAL; - } - break; - case SLOWAUTO_MODE: - case SLOW_MODE: - if (gear > ARRAY_SIZE(pwm_fr_table)) { - dev_err(hba->dev, - "%s: index %d exceeds table size %zu\n", - __func__, gear, - ARRAY_SIZE(pwm_fr_table)); - return -EINVAL; - } - tx_clk_cycles_per_us = pwm_fr_table[gear-1][1]; - break; - case UNCHANGED: - default: - dev_err(hba->dev, "%s: invalid mode = %d\n", __func__, hs); - return -EINVAL; - } - - if (ufshcd_readl(hba, REG_UFS_TX_SYMBOL_CLK_NS_US) != - (core_clk_period_in_ns | tx_clk_cycles_per_us)) { - /* this register 2 fields shall be written at once */ - ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us, - REG_UFS_TX_SYMBOL_CLK_NS_US); - /* - * make sure above write gets applied before we return from - * this function. - */ - mb(); - } - - if (update_link_startup_timer && host->hw_ver.major != 0x5) { - ufshcd_writel(hba, ((core_clk_rate / MSEC_PER_SEC) * 100), - REG_UFS_CFG0); - /* - * make sure that this configuration is applied before - * we return - */ - mb(); - } - return 0; } @@ -691,7 +511,6 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, enum ufs_notify_change_status status) { int err = 0; - struct ufs_qcom_host *host = ufshcd_get_variant(hba); switch (status) { case PRE_CHANGE: @@ -702,11 +521,9 @@ static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, return -EINVAL; } - if (ufs_qcom_cap_qunipro(host)) { - err = ufs_qcom_set_core_clk_ctrl(hba, true); - if (err) - dev_err(hba->dev, "cfg core clk ctrl failed\n"); - } + err = ufs_qcom_set_core_clk_ctrl(hba, true); + if (err) + dev_err(hba->dev, "cfg core clk ctrl failed\n"); /* * Some UFS devices (and may be host) have issues if LCC is * enabled. So we are setting PA_Local_TX_LCC_Enable to 0 @@ -898,7 +715,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, struct ufs_pa_layer_attr *dev_req_params) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - struct ufs_dev_params ufs_qcom_cap; + struct ufs_host_params *host_params = &host->host_params; int ret = 0; if (!dev_req_params) { @@ -908,15 +725,7 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, switch (status) { case PRE_CHANGE: - ufshcd_init_pwr_dev_param(&ufs_qcom_cap); - ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE; - - /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ - ufs_qcom_cap.hs_tx_gear = ufs_qcom_cap.hs_rx_gear = ufs_qcom_get_hs_gear(hba); - - ret = ufshcd_get_pwr_dev_param(&ufs_qcom_cap, - dev_max_params, - dev_req_params); + ret = ufshcd_negotiate_pwr_params(host_params, dev_max_params, dev_req_params); if (ret) { dev_err(hba->dev, "%s: failed to determine capabilities\n", __func__); @@ -924,11 +733,12 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, } /* - * Update phy_gear only when the gears are scaled to a higher value. This is - * because, the PHY gear settings are backwards compatible and we only need to - * change the PHY gear settings while scaling to higher gears. + * During UFS driver probe, always update the PHY gear to match the negotiated + * gear, so that, if quirk UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH is enabled, + * the second init can program the optimal PHY settings. This allows one to start + * the first init with either the minimum or the maximum support gear. */ - if (dev_req_params->gear_tx > host->phy_gear) + if (hba->ufshcd_state == UFSHCD_STATE_RESET) host->phy_gear = dev_req_params->gear_tx; /* enable the device ref clock before changing to HS mode */ @@ -1005,12 +815,7 @@ static int ufs_qcom_apply_dev_quirks(struct ufs_hba *hba) static u32 ufs_qcom_get_ufs_hci_version(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - - if (host->hw_ver.major == 0x1) - return ufshci_version(1, 1); - else - return ufshci_version(2, 0); + return ufshci_version(2, 0); } /** @@ -1026,46 +831,69 @@ static void ufs_qcom_advertise_quirks(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - if (host->hw_ver.major == 0x01) { - hba->quirks |= UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS - | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP - | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE; + if (host->hw_ver.major == 0x2) + hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; - if (host->hw_ver.minor == 0x0001 && host->hw_ver.step == 0x0001) - hba->quirks |= UFSHCD_QUIRK_BROKEN_INTR_AGGR; + if (host->hw_ver.major > 0x3) + hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; +} - hba->quirks |= UFSHCD_QUIRK_BROKEN_LCC; - } +static void ufs_qcom_set_phy_gear(struct ufs_qcom_host *host) +{ + struct ufs_host_params *host_params = &host->host_params; + u32 val, dev_major; - if (host->hw_ver.major == 0x2) { - hba->quirks |= UFSHCD_QUIRK_BROKEN_UFS_HCI_VERSION; + host->phy_gear = host_params->hs_tx_gear; - if (!ufs_qcom_cap_qunipro(host)) - /* Legacy UniPro mode still need following quirks */ - hba->quirks |= (UFSHCD_QUIRK_DELAY_BEFORE_DME_CMDS - | UFSHCD_QUIRK_DME_PEER_ACCESS_AUTO_MODE - | UFSHCD_QUIRK_BROKEN_PA_RXHSUNTERMCAP); - } + if (host->hw_ver.major < 0x4) { + /* + * For controllers whose major HW version is < 4, power up the + * PHY using minimum supported gear (UFS_HS_G2). Switching to + * max gear will be performed during reinit if supported. + * For newer controllers, whose major HW version is >= 4, power + * up the PHY using max supported gear. + */ + host->phy_gear = UFS_HS_G2; + } else if (host->hw_ver.major >= 0x5) { + val = ufshcd_readl(host->hba, REG_UFS_DEBUG_SPARE_CFG); + dev_major = FIELD_GET(UFS_DEV_VER_MAJOR_MASK, val); - if (host->hw_ver.major > 0x3) - hba->quirks |= UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + /* + * Since the UFS device version is populated, let's remove the + * REINIT quirk as the negotiated gear won't change during boot. + * So there is no need to do reinit. + */ + if (dev_major != 0x0) + host->hba->quirks &= ~UFSHCD_QUIRK_REINIT_AFTER_MAX_GEAR_SWITCH; + + /* + * For UFS 3.1 device and older, power up the PHY using HS-G4 + * PHY gear to save power. + */ + if (dev_major > 0x0 && dev_major < 0x4) + host->phy_gear = UFS_HS_G4; + } } -static void ufs_qcom_set_caps(struct ufs_hba *hba) +static void ufs_qcom_set_host_params(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); + struct ufs_host_params *host_params = &host->host_params; + + ufshcd_init_host_params(host_params); + /* This driver only supports symmetic gear setting i.e., hs_tx_gear == hs_rx_gear */ + host_params->hs_tx_gear = host_params->hs_rx_gear = ufs_qcom_get_hs_gear(hba); +} + +static void ufs_qcom_set_caps(struct ufs_hba *hba) +{ hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_HIBERN8_WITH_CLK_GATING; hba->caps |= UFSHCD_CAP_CLK_SCALING | UFSHCD_CAP_WB_WITH_CLK_SCALING; hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND; hba->caps |= UFSHCD_CAP_WB_EN; hba->caps |= UFSHCD_CAP_AGGR_POWER_COLLAPSE; hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND; - - if (host->hw_ver.major >= 0x2) { - host->caps = UFS_QCOM_CAP_QUNIPRO | - UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE; - } } /** @@ -1188,16 +1016,12 @@ static int ufs_qcom_init(struct ufs_hba *hba) { int err; struct device *dev = hba->dev; - struct platform_device *pdev = to_platform_device(dev); struct ufs_qcom_host *host; - struct resource *res; struct ufs_clk_info *clki; host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL); - if (!host) { - dev_err(dev, "%s: no memory for qcom ufs host\n", __func__); + if (!host) return -ENOMEM; - } /* Make a two way bind between the qcom host and the hba */ host->hba = hba; @@ -1235,34 +1059,16 @@ static int ufs_qcom_init(struct ufs_hba *hba) host->device_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH); if (IS_ERR(host->device_reset)) { - err = PTR_ERR(host->device_reset); - if (err != -EPROBE_DEFER) - dev_err(dev, "failed to acquire reset gpio: %d\n", err); + err = dev_err_probe(dev, PTR_ERR(host->device_reset), + "Failed to acquire device reset gpio\n"); goto out_variant_clear; } ufs_qcom_get_controller_revision(hba, &host->hw_ver.major, &host->hw_ver.minor, &host->hw_ver.step); - /* - * for newer controllers, device reference clock control bit has - * moved inside UFS controller register address space itself. - */ - if (host->hw_ver.major >= 0x02) { - host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; - host->dev_ref_clk_en_mask = BIT(26); - } else { - /* "dev_ref_clk_ctrl_mem" is optional resource */ - res = platform_get_resource_byname(pdev, IORESOURCE_MEM, - "dev_ref_clk_ctrl_mem"); - if (res) { - host->dev_ref_clk_ctrl_mmio = - devm_ioremap_resource(dev, res); - if (IS_ERR(host->dev_ref_clk_ctrl_mmio)) - host->dev_ref_clk_ctrl_mmio = NULL; - host->dev_ref_clk_en_mask = BIT(5); - } - } + host->dev_ref_clk_ctrl_mmio = hba->mmio_base + REG_UFS_CFG1; + host->dev_ref_clk_en_mask = BIT(26); list_for_each_entry(clki, &hba->clk_list_head, list) { if (!strcmp(clki->name, "core_clk_unipro")) @@ -1275,6 +1081,8 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_set_caps(hba); ufs_qcom_advertise_quirks(hba); + ufs_qcom_set_host_params(hba); + ufs_qcom_set_phy_gear(host); err = ufs_qcom_ice_init(host); if (err) @@ -1282,9 +1090,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) ufs_qcom_setup_clocks(hba, true, POST_CHANGE); - if (hba->dev->id < MAX_UFS_QCOM_HOSTS) - ufs_qcom_hosts[hba->dev->id] = host; - ufs_qcom_get_default_testbus_cfg(host); err = ufs_qcom_testbus_config(host); if (err) @@ -1292,12 +1097,6 @@ static int ufs_qcom_init(struct ufs_hba *hba) dev_warn(dev, "%s: failed to configure the testbus %d\n", __func__, err); - /* - * Power up the PHY using the minimum supported gear (UFS_HS_G2). - * Switching to max gear will be performed during reinit if supported. - */ - host->phy_gear = UFS_HS_G2; - return 0; out_variant_clear: @@ -1391,7 +1190,7 @@ static int ufs_qcom_set_core_clk_ctrl(struct ufs_hba *hba, bool is_scale_up) struct ufs_qcom_host *host = ufshcd_get_variant(hba); struct list_head *head = &hba->clk_list_head; struct ufs_clk_info *clki; - u32 cycles_in_1us; + u32 cycles_in_1us = 0; u32 core_clk_ctrl_reg; int err; @@ -1444,9 +1243,6 @@ static int ufs_qcom_clk_scale_up_pre_change(struct ufs_hba *hba) struct ufs_pa_layer_attr *attr = &host->dev_req_params; int ret; - if (!ufs_qcom_cap_qunipro(host)) - return 0; - ret = ufs_qcom_cfg_timers(hba, attr->gear_rx, attr->pwr_rx, attr->hs_rate, false, true); if (ret) { @@ -1464,13 +1260,9 @@ static int ufs_qcom_clk_scale_up_post_change(struct ufs_hba *hba) static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); int err; u32 core_clk_ctrl_reg; - if (!ufs_qcom_cap_qunipro(host)) - return 0; - err = ufshcd_dme_get(hba, UIC_ARG_MIB(DME_VS_CORE_CLK_CTRL), &core_clk_ctrl_reg); @@ -1489,11 +1281,6 @@ static int ufs_qcom_clk_scale_down_pre_change(struct ufs_hba *hba) static int ufs_qcom_clk_scale_down_post_change(struct ufs_hba *hba) { - struct ufs_qcom_host *host = ufshcd_get_variant(hba); - - if (!ufs_qcom_cap_qunipro(host)) - return 0; - /* set unipro core clock attributes and clear clock divider */ return ufs_qcom_set_core_clk_ctrl(hba, false); } @@ -1502,7 +1289,7 @@ static int ufs_qcom_clk_scale_notify(struct ufs_hba *hba, bool scale_up, enum ufs_notify_change_status status) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); - int err = 0; + int err; /* check the host controller state before sending hibern8 cmd */ if (!ufshcd_is_hba_active(hba)) @@ -1775,7 +1562,7 @@ static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba) struct platform_device *pdev = to_platform_device(hba->dev); struct ufshcd_res_info *res; struct resource *res_mem, *res_mcq; - int i, ret = 0; + int i, ret; memcpy(hba->res, ufs_res_info, sizeof(ufs_res_info)); @@ -1787,7 +1574,7 @@ static int ufs_qcom_mcq_config_resource(struct ufs_hba *hba) if (!res->resource) { dev_info(hba->dev, "Resource %s not provided\n", res->name); if (i == RES_UFS) - return -ENOMEM; + return -ENODEV; continue; } else if (i == RES_UFS) { res_mem = res->resource; @@ -1958,11 +1745,10 @@ static int ufs_qcom_config_esi(struct ufs_hba *hba) platform_msi_domain_free_irqs(hba->dev); } else { if (host->hw_ver.major == 6 && host->hw_ver.minor == 0 && - host->hw_ver.step == 0) { - ufshcd_writel(hba, - ufshcd_readl(hba, REG_UFS_CFG3) | 0x1F000, - REG_UFS_CFG3); - } + host->hw_ver.step == 0) + ufshcd_rmwl(hba, ESI_VEC_MASK, + FIELD_PREP(ESI_VEC_MASK, MAX_ESI_VEC - 1), + REG_UFS_CFG3); ufshcd_mcq_enable_esi(hba); } diff --git a/drivers/ufs/host/ufs-qcom.h b/drivers/ufs/host/ufs-qcom.h index 9950a0089475..9dd9a391ebb7 100644 --- a/drivers/ufs/host/ufs-qcom.h +++ b/drivers/ufs/host/ufs-qcom.h @@ -10,22 +10,17 @@ #include <soc/qcom/ice.h> #include <ufs/ufshcd.h> -#define MAX_UFS_QCOM_HOSTS 1 -#define MAX_U32 (~(u32)0) #define MPHY_TX_FSM_STATE 0x41 #define TX_FSM_HIBERN8 0x1 #define HBRN8_POLL_TOUT_MS 100 #define DEFAULT_CLK_RATE_HZ 1000000 -#define BUS_VECTOR_NAME_LEN 32 #define MAX_SUPP_MAC 64 +#define MAX_ESI_VEC 32 #define UFS_HW_VER_MAJOR_MASK GENMASK(31, 28) #define UFS_HW_VER_MINOR_MASK GENMASK(27, 16) #define UFS_HW_VER_STEP_MASK GENMASK(15, 0) - -/* vendor specific pre-defined parameters */ -#define SLOW 1 -#define FAST 2 +#define UFS_DEV_VER_MAJOR_MASK GENMASK(7, 4) #define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B @@ -56,6 +51,8 @@ enum { UFS_AH8_CFG = 0xFC, REG_UFS_CFG3 = 0x271C, + + REG_UFS_DEBUG_SPARE_CFG = 0x284C, }; /* QCOM UFS host controller vendor specific debug registers */ @@ -93,9 +90,6 @@ enum { #define TEST_BUS_SEL GENMASK(22, 19) #define UFS_REG_TEST_BUS_EN BIT(30) -#define UFS_PHY_RESET_ENABLE 1 -#define UFS_PHY_RESET_DISABLE 0 - /* bit definitions for REG_UFS_CFG2 register */ #define UAWM_HW_CGC_EN BIT(0) #define UARM_HW_CGC_EN BIT(1) @@ -106,6 +100,9 @@ enum { #define TMRLUT_HW_CGC_EN BIT(6) #define OCSC_HW_CGC_EN BIT(7) +/* bit definitions for REG_UFS_CFG3 register */ +#define ESI_VEC_MASK GENMASK(22, 12) + /* bit definitions for REG_UFS_PARAM0 */ #define MAX_HS_GEAR_MASK GENMASK(6, 4) #define UFS_QCOM_MAX_GEAR(x) FIELD_GET(MAX_HS_GEAR_MASK, (x)) @@ -118,13 +115,6 @@ enum { DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\ TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN) -/* bit offset */ -#define OFFSET_CLK_NS_REG 0xa - -/* bit masks */ -#define MASK_TX_SYMBOL_CLK_1US_REG GENMASK(9, 0) -#define MASK_CLK_NS_REG GENMASK(23, 10) - /* QUniPro Vendor specific attributes */ #define PA_VS_CONFIG_REG1 0x9000 #define DME_VS_CORE_CLK_CTRL 0xD002 @@ -158,8 +148,7 @@ ufs_qcom_get_controller_revision(struct ufs_hba *hba, static inline void ufs_qcom_assert_reset(struct ufs_hba *hba) { - ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_ENABLE), - REG_UFS_CFG1); + ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, UFS_PHY_SOFT_RESET, REG_UFS_CFG1); /* * Make sure assertion of ufs phy reset is written to @@ -170,8 +159,7 @@ static inline void ufs_qcom_assert_reset(struct ufs_hba *hba) static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba) { - ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, FIELD_PREP(UFS_PHY_SOFT_RESET, UFS_PHY_RESET_DISABLE), - REG_UFS_CFG1); + ufshcd_rmwl(hba, UFS_PHY_SOFT_RESET, 0, REG_UFS_CFG1); /* * Make sure de-assertion of ufs phy reset is written to @@ -195,28 +183,11 @@ struct ufs_qcom_testbus { struct gpio_desc; struct ufs_qcom_host { - /* - * Set this capability if host controller supports the QUniPro mode - * and if driver wants the Host controller to operate in QUniPro mode. - * Note: By default this capability will be kept enabled if host - * controller supports the QUniPro mode. - */ - #define UFS_QCOM_CAP_QUNIPRO 0x1 - - /* - * Set this capability if host controller can retain the secure - * configuration even after UFS controller core power collapse. - */ - #define UFS_QCOM_CAP_RETAIN_SEC_CFG_AFTER_PWR_COLLAPSE 0x2 - u32 caps; - struct phy *generic_phy; struct ufs_hba *hba; struct ufs_pa_layer_attr dev_req_params; - struct clk *rx_l0_sync_clk; - struct clk *tx_l0_sync_clk; - struct clk *rx_l1_sync_clk; - struct clk *tx_l1_sync_clk; + struct clk_bulk_data *clks; + u32 num_clks; bool is_lane_clks_enabled; struct icc_path *icc_ddr; @@ -240,6 +211,7 @@ struct ufs_qcom_host { struct gpio_desc *device_reset; + struct ufs_host_params host_params; u32 phy_gear; bool esi_enabled; @@ -261,9 +233,4 @@ ufs_qcom_get_debug_reg_offset(struct ufs_qcom_host *host, u32 reg) int ufs_qcom_testbus_config(struct ufs_qcom_host *host); -static inline bool ufs_qcom_cap_qunipro(struct ufs_qcom_host *host) -{ - return host->caps & UFS_QCOM_CAP_QUNIPRO; -} - #endif /* UFS_QCOM_H_ */ diff --git a/drivers/ufs/host/ufshcd-pltfrm.c b/drivers/ufs/host/ufshcd-pltfrm.c index db9d9365ff55..a3e69ecafd27 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.c +++ b/drivers/ufs/host/ufshcd-pltfrm.c @@ -339,61 +339,60 @@ static int ufshcd_parse_operating_points(struct ufs_hba *hba) } /** - * ufshcd_get_pwr_dev_param - get finally agreed attributes for - * power mode change - * @pltfrm_param: pointer to platform parameters + * ufshcd_negotiate_pwr_params - find power mode settings that are supported by + * both the controller and the device + * @host_params: pointer to host parameters * @dev_max: pointer to device attributes * @agreed_pwr: returned agreed attributes * * Return: 0 on success, non-zero value on failure. */ -int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, - const struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr) +int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, + const struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr) { - int min_pltfrm_gear; + int min_host_gear; int min_dev_gear; bool is_dev_sup_hs = false; - bool is_pltfrm_max_hs = false; + bool is_host_max_hs = false; if (dev_max->pwr_rx == FAST_MODE) is_dev_sup_hs = true; - if (pltfrm_param->desired_working_mode == UFS_HS_MODE) { - is_pltfrm_max_hs = true; - min_pltfrm_gear = min_t(u32, pltfrm_param->hs_rx_gear, - pltfrm_param->hs_tx_gear); + if (host_params->desired_working_mode == UFS_HS_MODE) { + is_host_max_hs = true; + min_host_gear = min_t(u32, host_params->hs_rx_gear, + host_params->hs_tx_gear); } else { - min_pltfrm_gear = min_t(u32, pltfrm_param->pwm_rx_gear, - pltfrm_param->pwm_tx_gear); + min_host_gear = min_t(u32, host_params->pwm_rx_gear, + host_params->pwm_tx_gear); } /* - * device doesn't support HS but - * pltfrm_param->desired_working_mode is HS, - * thus device and pltfrm_param don't agree + * device doesn't support HS but host_params->desired_working_mode is HS, + * thus device and host_params don't agree */ - if (!is_dev_sup_hs && is_pltfrm_max_hs) { + if (!is_dev_sup_hs && is_host_max_hs) { pr_info("%s: device doesn't support HS\n", __func__); return -ENOTSUPP; - } else if (is_dev_sup_hs && is_pltfrm_max_hs) { + } else if (is_dev_sup_hs && is_host_max_hs) { /* * since device supports HS, it supports FAST_MODE. - * since pltfrm_param->desired_working_mode is also HS + * since host_params->desired_working_mode is also HS * then final decision (FAST/FASTAUTO) is done according * to pltfrm_params as it is the restricting factor */ - agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_hs; + agreed_pwr->pwr_rx = host_params->rx_pwr_hs; agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; } else { /* - * here pltfrm_param->desired_working_mode is PWM. + * here host_params->desired_working_mode is PWM. * it doesn't matter whether device supports HS or PWM, - * in both cases pltfrm_param->desired_working_mode will + * in both cases host_params->desired_working_mode will * determine the mode */ - agreed_pwr->pwr_rx = pltfrm_param->rx_pwr_pwm; + agreed_pwr->pwr_rx = host_params->rx_pwr_pwm; agreed_pwr->pwr_tx = agreed_pwr->pwr_rx; } @@ -403,9 +402,9 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, * the same decision will be made for rx */ agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx, - pltfrm_param->tx_lanes); + host_params->tx_lanes); agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx, - pltfrm_param->rx_lanes); + host_params->rx_lanes); /* device maximum gear is the minimum between device rx and tx gears */ min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx); @@ -418,26 +417,26 @@ int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *pltfrm_param, * what is the gear, as it is the one that also decided previously what * pwr the device will be configured to. */ - if ((is_dev_sup_hs && is_pltfrm_max_hs) || - (!is_dev_sup_hs && !is_pltfrm_max_hs)) { + if ((is_dev_sup_hs && is_host_max_hs) || + (!is_dev_sup_hs && !is_host_max_hs)) { agreed_pwr->gear_rx = - min_t(u32, min_dev_gear, min_pltfrm_gear); + min_t(u32, min_dev_gear, min_host_gear); } else if (!is_dev_sup_hs) { agreed_pwr->gear_rx = min_dev_gear; } else { - agreed_pwr->gear_rx = min_pltfrm_gear; + agreed_pwr->gear_rx = min_host_gear; } agreed_pwr->gear_tx = agreed_pwr->gear_rx; - agreed_pwr->hs_rate = pltfrm_param->hs_rate; + agreed_pwr->hs_rate = host_params->hs_rate; return 0; } -EXPORT_SYMBOL_GPL(ufshcd_get_pwr_dev_param); +EXPORT_SYMBOL_GPL(ufshcd_negotiate_pwr_params); -void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) +void ufshcd_init_host_params(struct ufs_host_params *host_params) { - *dev_param = (struct ufs_dev_params){ + *host_params = (struct ufs_host_params){ .tx_lanes = UFS_LANE_2, .rx_lanes = UFS_LANE_2, .hs_rx_gear = UFS_HS_G3, @@ -452,7 +451,7 @@ void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param) .desired_working_mode = UFS_HS_MODE, }; } -EXPORT_SYMBOL_GPL(ufshcd_init_pwr_dev_param); +EXPORT_SYMBOL_GPL(ufshcd_init_host_params); /** * ufshcd_pltfrm_init - probe routine of the driver diff --git a/drivers/ufs/host/ufshcd-pltfrm.h b/drivers/ufs/host/ufshcd-pltfrm.h index a86a3ada4bef..df387be5216b 100644 --- a/drivers/ufs/host/ufshcd-pltfrm.h +++ b/drivers/ufs/host/ufshcd-pltfrm.h @@ -10,7 +10,7 @@ #define UFS_PWM_MODE 1 #define UFS_HS_MODE 2 -struct ufs_dev_params { +struct ufs_host_params { u32 pwm_rx_gear; /* pwm rx gear to work in */ u32 pwm_tx_gear; /* pwm tx gear to work in */ u32 hs_rx_gear; /* hs rx gear to work in */ @@ -25,10 +25,10 @@ struct ufs_dev_params { u32 desired_working_mode; }; -int ufshcd_get_pwr_dev_param(const struct ufs_dev_params *dev_param, - const struct ufs_pa_layer_attr *dev_max, - struct ufs_pa_layer_attr *agreed_pwr); -void ufshcd_init_pwr_dev_param(struct ufs_dev_params *dev_param); +int ufshcd_negotiate_pwr_params(const struct ufs_host_params *host_params, + const struct ufs_pa_layer_attr *dev_max, + struct ufs_pa_layer_attr *agreed_pwr); +void ufshcd_init_host_params(struct ufs_host_params *host_params); int ufshcd_pltfrm_init(struct platform_device *pdev, const struct ufs_hba_variant_ops *vops); int ufshcd_populate_vreg(struct device *dev, const char *name, diff --git a/include/uapi/scsi/scsi_bsg_mpi3mr.h b/include/uapi/scsi/scsi_bsg_mpi3mr.h index 907d345f04f9..c72ce387286a 100644 --- a/include/uapi/scsi/scsi_bsg_mpi3mr.h +++ b/include/uapi/scsi/scsi_bsg_mpi3mr.h @@ -491,6 +491,8 @@ struct mpi3_nvme_encapsulated_error_reply { #define MPI3MR_NVME_DATA_FORMAT_PRP 0 #define MPI3MR_NVME_DATA_FORMAT_SGL1 1 #define MPI3MR_NVME_DATA_FORMAT_SGL2 2 +#define MPI3MR_NVMESGL_DATA_SEGMENT 0x00 +#define MPI3MR_NVMESGL_LAST_SEGMENT 0x03 /* MPI3: task management related definitions */ struct mpi3_scsi_task_mgmt_request { diff --git a/include/ufs/ufs.h b/include/ufs/ufs.h index e77ab1786856..b6003749bc83 100644 --- a/include/ufs/ufs.h +++ b/include/ufs/ufs.h @@ -14,6 +14,7 @@ #include <linux/bitops.h> #include <linux/types.h> #include <uapi/scsi/scsi_bsg_ufs.h> +#include <linux/time64.h> /* * Using static_assert() is not allowed in UAPI header files. Hence the check @@ -551,6 +552,14 @@ struct ufs_vreg_info { struct ufs_vreg *vdd_hba; }; +/* UFS device descriptor wPeriodicRTCUpdate bit9 defines RTC time baseline */ +#define UFS_RTC_TIME_BASELINE BIT(9) + +enum ufs_rtc_time { + UFS_RTC_RELATIVE, + UFS_RTC_ABSOLUTE +}; + struct ufs_dev_info { bool f_power_on_wp_en; /* Keeps information if any of the LU is power on write protected */ @@ -578,6 +587,11 @@ struct ufs_dev_info { /* UFS EXT_IID Enable */ bool b_ext_iid_en; + + /* UFS RTC */ + enum ufs_rtc_time rtc_type; + time64_t rtc_time_baseline; + u32 rtc_update_period; }; /* diff --git a/include/ufs/ufshcd.h b/include/ufs/ufshcd.h index 7f0b2c5599cd..8e2bce9a4f21 100644 --- a/include/ufs/ufshcd.h +++ b/include/ufs/ufshcd.h @@ -16,6 +16,7 @@ #include <linux/blk-crypto-profile.h> #include <linux/blk-mq.h> #include <linux/devfreq.h> +#include <linux/fault-inject.h> #include <linux/msi.h> #include <linux/pm_runtime.h> #include <linux/dma-direction.h> @@ -911,6 +912,8 @@ enum ufshcd_mcq_opr { * @mcq_base: Multi circular queue registers base address * @uhq: array of supported hardware queues * @dev_cmd_queue: Queue for issuing device management commands + * @mcq_opr: MCQ operation and runtime registers + * @ufs_rtc_update_work: A work for UFS RTC periodic update */ struct ufs_hba { void __iomem *mmio_base; @@ -1058,6 +1061,10 @@ struct ufs_hba { struct delayed_work debugfs_ee_work; u32 debugfs_ee_rate_limit_ms; #endif +#ifdef CONFIG_SCSI_UFS_FAULT_INJECTION + struct fault_attr trigger_eh_attr; + struct fault_attr timeout_attr; +#endif u32 luns_avail; unsigned int nr_hw_queues; unsigned int nr_queues[HCTX_MAX_TYPES]; @@ -1071,6 +1078,8 @@ struct ufs_hba { struct ufs_hw_queue *uhq; struct ufs_hw_queue *dev_cmd_queue; struct ufshcd_mcq_opr_info_t mcq_opr[OPR_MAX]; + + struct delayed_work ufs_rtc_update_work; }; /** @@ -1231,6 +1240,8 @@ static inline void ufshcd_rmwl(struct ufs_hba *hba, u32 mask, u32 val, u32 reg) ufshcd_writel(hba, tmp, reg); } +void ufshcd_enable_irq(struct ufs_hba *hba); +void ufshcd_disable_irq(struct ufs_hba *hba); int ufshcd_alloc_host(struct device *, struct ufs_hba **); void ufshcd_dealloc_host(struct ufs_hba *); int ufshcd_hba_enable(struct ufs_hba *hba); @@ -1360,7 +1371,6 @@ static inline int ufshcd_disable_host_tx_lcc(struct ufs_hba *hba) return ufshcd_dme_set(hba, UIC_ARG_MIB(PA_LOCAL_TX_LCC_ENABLE), 0); } -void ufshcd_auto_hibern8_enable(struct ufs_hba *hba); void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit); void ufshcd_fixup_dev_quirks(struct ufs_hba *hba, const struct ufs_dev_quirk *fixups); diff --git a/include/ufs/unipro.h b/include/ufs/unipro.h index 256eb3a43f54..360e1245fb40 100644 --- a/include/ufs/unipro.h +++ b/include/ufs/unipro.h @@ -193,7 +193,7 @@ #define DME_LocalAFC0ReqTimeOutVal 0xD043 /* PA power modes */ -enum { +enum ufs_pa_pwr_mode { FAST_MODE = 1, SLOW_MODE = 2, FASTAUTO_MODE = 4, @@ -205,7 +205,7 @@ enum { #define PWRMODE_RX_OFFSET 4 /* PA TX/RX Frequency Series */ -enum { +enum ufs_hs_gear_rate { PA_HS_MODE_A = 1, PA_HS_MODE_B = 2, }; |