From 359e10f087dbb7b9c9f3035a8cc4391af45bd651 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:47 -0700 Subject: scsi: lpfc: Fix pt2pt discovery on SLI3 HBAs After exchanging PLOGI on an SLI-3 adapter, the PRLI exchange failed. Link trace showed the port was assigned a non-zero n_port_id, but didn't use the address on the PRLI. The assigned address is set on the port by the CONFIG_LINK mailbox command. The driver responded to the PRLI before the mailbox command completed. Thus the PRLI response used the old n_port_id. Defer the PRLI response until CONFIG_LINK completes. Link: https://lore.kernel.org/r/20190922035906.10977-2-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nportdisc.c | 141 ++++++++++++++++++++++++++++++------- 1 file changed, 115 insertions(+), 26 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index f4b879d25fe9..4e96d28cba39 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -279,6 +279,55 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_cancel_retry_delay_tmo(phba->pport, ndlp); } +/* lpfc_defer_pt2pt_acc - Complete SLI3 pt2pt processing on link up + * @phba: pointer to lpfc hba data structure. + * @link_mbox: pointer to CONFIG_LINK mailbox object + * + * This routine is only called if we are SLI3, direct connect pt2pt + * mode and the remote NPort issues the PLOGI after link up. + */ +void +lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) +{ + LPFC_MBOXQ_t *login_mbox; + MAILBOX_t *mb = &link_mbox->u.mb; + struct lpfc_iocbq *save_iocb; + struct lpfc_nodelist *ndlp; + int rc; + + ndlp = link_mbox->ctx_ndlp; + login_mbox = link_mbox->context3; + save_iocb = login_mbox->context3; + link_mbox->context3 = NULL; + login_mbox->context3 = NULL; + + /* Check for CONFIG_LINK error */ + if (mb->mbxStatus) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "4575 CONFIG_LINK fails pt2pt discovery: %x\n", + mb->mbxStatus); + mempool_free(login_mbox, phba->mbox_mem_pool); + mempool_free(link_mbox, phba->mbox_mem_pool); + lpfc_sli_release_iocbq(phba, save_iocb); + return; + } + + /* Now that CONFIG_LINK completed, and our SID is configured, + * we can now proceed with sending the PLOGI ACC. + */ + rc = lpfc_els_rsp_acc(link_mbox->vport, ELS_CMD_PLOGI, + save_iocb, ndlp, login_mbox); + if (rc) { + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "4576 PLOGI ACC fails pt2pt discovery: %x\n", + rc); + mempool_free(login_mbox, phba->mbox_mem_pool); + } + + mempool_free(link_mbox, phba->mbox_mem_pool); + lpfc_sli_release_iocbq(phba, save_iocb); +} + static int lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, struct lpfc_iocbq *cmdiocb) @@ -291,10 +340,12 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, IOCB_t *icmd; struct serv_parm *sp; uint32_t ed_tov; - LPFC_MBOXQ_t *mbox; + LPFC_MBOXQ_t *link_mbox; + LPFC_MBOXQ_t *login_mbox; + struct lpfc_iocbq *save_iocb; struct ls_rjt stat; uint32_t vid, flag; - int rc; + int rc, defer_acc; memset(&stat, 0, sizeof (struct ls_rjt)); pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; @@ -343,6 +394,7 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, else ndlp->nlp_fcp_info |= CLASS3; + defer_acc = 0; ndlp->nlp_class_sup = 0; if (sp->cls1.classValid) ndlp->nlp_class_sup |= FC_COS_CLASS1; @@ -354,7 +406,6 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_class_sup |= FC_COS_CLASS4; ndlp->nlp_maxframe = ((sp->cmn.bbRcvSizeMsb & 0x0F) << 8) | sp->cmn.bbRcvSizeLsb; - /* if already logged in, do implicit logout */ switch (ndlp->nlp_state) { case NLP_STE_NPR_NODE: @@ -396,6 +447,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; ndlp->nlp_flag &= ~NLP_FIRSTBURST; + login_mbox = NULL; + link_mbox = NULL; + save_iocb = NULL; + /* Check for Nport to NPort pt2pt protocol */ if ((vport->fc_flag & FC_PT2PT) && !(vport->fc_flag & FC_PT2PT_PLOGI)) { @@ -423,17 +478,22 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (phba->sli_rev == LPFC_SLI_REV4) lpfc_issue_reg_vfi(vport); else { - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (mbox == NULL) + defer_acc = 1; + link_mbox = mempool_alloc(phba->mbox_mem_pool, + GFP_KERNEL); + if (!link_mbox) goto out; - lpfc_config_link(phba, mbox); - mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; - mbox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) { - mempool_free(mbox, phba->mbox_mem_pool); + lpfc_config_link(phba, link_mbox); + link_mbox->mbox_cmpl = lpfc_defer_pt2pt_acc; + link_mbox->vport = vport; + link_mbox->ctx_ndlp = ndlp; + + save_iocb = lpfc_sli_get_iocbq(phba); + if (!save_iocb) goto out; - } + /* Save info from cmd IOCB used in rsp */ + memcpy((uint8_t *)save_iocb, (uint8_t *)cmdiocb, + sizeof(struct lpfc_iocbq)); } lpfc_can_disctmo(vport); @@ -448,8 +508,8 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_flag |= NLP_SUPPRESS_RSP; } - mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + login_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!login_mbox) goto out; /* Registering an existing RPI behaves differently for SLI3 vs SLI4 */ @@ -457,21 +517,19 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, lpfc_unreg_rpi(vport, ndlp); rc = lpfc_reg_rpi(phba, vport->vpi, icmd->un.rcvels.remoteID, - (uint8_t *) sp, mbox, ndlp->nlp_rpi); - if (rc) { - mempool_free(mbox, phba->mbox_mem_pool); + (uint8_t *)sp, login_mbox, ndlp->nlp_rpi); + if (rc) goto out; - } /* ACC PLOGI rsp command needs to execute first, - * queue this mbox command to be processed later. + * queue this login_mbox command to be processed later. */ - mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; + login_mbox->mbox_cmpl = lpfc_mbx_cmpl_reg_login; /* - * mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox + * login_mbox->ctx_ndlp = lpfc_nlp_get(ndlp) deferred until mailbox * command issued in lpfc_cmpl_els_acc(). */ - mbox->vport = vport; + login_mbox->vport = vport; spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= (NLP_ACC_REGLOGIN | NLP_RCV_PLOGI); spin_unlock_irq(shost->host_lock); @@ -504,16 +562,47 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, stat.un.b.lsRjtRsnCode = LSRJT_INVALID_CMD; stat.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; rc = lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, - ndlp, mbox); + ndlp, login_mbox); if (rc) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(login_mbox, phba->mbox_mem_pool); return 1; } - rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, mbox); + if (defer_acc) { + /* So the order here should be: + * Issue CONFIG_LINK mbox + * CONFIG_LINK cmpl + * Issue PLOGI ACC + * PLOGI ACC cmpl + * Issue REG_LOGIN mbox + */ + + /* Save the REG_LOGIN mbox for and rcv IOCB copy later */ + link_mbox->context3 = login_mbox; + login_mbox->context3 = save_iocb; + + /* Start the ball rolling by issuing CONFIG_LINK here */ + rc = lpfc_sli_issue_mbox(phba, link_mbox, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) + goto out; + return 1; + } + + rc = lpfc_els_rsp_acc(vport, ELS_CMD_PLOGI, cmdiocb, ndlp, login_mbox); if (rc) - mempool_free(mbox, phba->mbox_mem_pool); + mempool_free(login_mbox, phba->mbox_mem_pool); return 1; out: + if (defer_acc) + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, + "4577 pt2pt discovery failure: %p %p %p\n", + save_iocb, link_mbox, login_mbox); + if (save_iocb) + lpfc_sli_release_iocbq(phba, save_iocb); + if (link_mbox) + mempool_free(link_mbox, phba->mbox_mem_pool); + if (login_mbox) + mempool_free(login_mbox, phba->mbox_mem_pool); + stat.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; stat.un.b.lsRjtRsnCodeExp = LSEXP_OUT_OF_RESOURCE; lpfc_els_rsp_reject(vport, stat.un.lsRjtError, cmdiocb, ndlp, NULL); -- cgit v1.2.3 From 65a3df63e7ff5addafc75ad8bc5ef5856db55429 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:48 -0700 Subject: scsi: lpfc: Fix premature re-enabling of interrupts in lpfc_sli_host_down Use of spin_lock_irq may re-enable interrupts prematurely. Convert to spin_lock. Note: code is under the phba->hba_lock which has been locked with irqsave. Link: https://lore.kernel.org/r/20190922035906.10977-3-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index a0c6945b8139..3b3ae2182e59 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -10678,14 +10678,14 @@ lpfc_sli_host_down(struct lpfc_vport *vport) set_bit(LPFC_DATA_READY, &phba->data_flags); } prev_pring_flag = pring->flag; - spin_lock_irq(&pring->ring_lock); + spin_lock(&pring->ring_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { if (iocb->vport != vport) continue; list_move_tail(&iocb->list, &completions); } - spin_unlock_irq(&pring->ring_lock); + spin_unlock(&pring->ring_lock); list_for_each_entry_safe(iocb, next_iocb, &pring->txcmplq, list) { if (iocb->vport != vport) -- cgit v1.2.3 From b7b95fb8637d7bd271df25e17e002a584b16f411 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:49 -0700 Subject: scsi: lpfc: Fix miss of register read failure check Coverity flagged missing status check on register read that flags a poisoned data return value. Add checking of register read status. Link: https://lore.kernel.org/r/20190922035906.10977-4-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 25aa7a53d255..41cc91d3c77e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1475,8 +1475,9 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) int i; msleep(100); - lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0)) + return -EIO; /* verify if privileged for the request operation */ if (!bf_get(lpfc_sliport_status_rn, &portstat_reg) && @@ -1486,8 +1487,9 @@ lpfc_sli4_pdev_status_reg_wait(struct lpfc_hba *phba) /* wait for the SLI port firmware ready after firmware reset */ for (i = 0; i < LPFC_FW_RESET_MAXIMUM_WAIT_10MS_CNT; i++) { msleep(10); - lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, - &portstat_reg.word0); + if (lpfc_readl(phba->sli4_hba.u.if_type2.STATUSregaddr, + &portstat_reg.word0)) + continue; if (!bf_get(lpfc_sliport_status_err, &portstat_reg)) continue; if (!bf_get(lpfc_sliport_status_rn, &portstat_reg)) -- cgit v1.2.3 From a5f7337f5a82fc4b13b4481a7e56977656cbe7d1 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:50 -0700 Subject: scsi: lpfc: Fix NVME io abort failures causing hangs The nvme-fc transport may call to abort an io on controller reset. If the driver is out of resources to issue an abort command, it just gives up and does nothing. The transport expects the lldd to always be able to terminate an io it has issued. At that point, the controller hangs waiting for aborted ios to be returned. Note: flaged by "6136" and "6176" error messages. Root issue was the adapter mis-allocated the number resources it allocated for command entries for the adapter. Convert the driver to allocate command resources based on the number of xris supported by the FC port - 1 resource for the original command and 1 resource for the abort request. Link: https://lore.kernel.org/r/20190922035906.10977-5-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 - drivers/scsi/lpfc/lpfc_attr.c | 5 ----- drivers/scsi/lpfc/lpfc_init.c | 9 +++------ drivers/scsi/lpfc/lpfc_sli.c | 17 +++++++++++------ 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 691acbdcc46d..291335e16806 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -872,7 +872,6 @@ struct lpfc_hba { uint32_t cfg_aer_support; uint32_t cfg_sriov_nr_virtfn; uint32_t cfg_request_firmware_upgrade; - uint32_t cfg_iocb_cnt; uint32_t cfg_suppress_link_up; uint32_t cfg_rrq_xri_bitmap_sz; uint32_t cfg_delay_discovery; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 41cc91d3c77e..79a192479755 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3582,9 +3582,6 @@ lpfc_txcmplq_hw_show(struct device *dev, struct device_attribute *attr, static DEVICE_ATTR(txcmplq_hw, S_IRUGO, lpfc_txcmplq_hw_show, NULL); -LPFC_ATTR_R(iocb_cnt, 2, 1, 5, - "Number of IOCBs alloc for ELS, CT, and ABTS: 1k to 5k IOCBs"); - /* # lpfc_nodev_tmo: If set, it will hold all I/O errors on devices that disappear # until the timer expires. Value range is [0,255]. Default value is 30. @@ -6073,7 +6070,6 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_sriov_nr_virtfn, &dev_attr_lpfc_req_fw_upgrade, &dev_attr_lpfc_suppress_link_up, - &dev_attr_lpfc_iocb_cnt, &dev_attr_iocb_hw, &dev_attr_txq_hw, &dev_attr_txcmplq_hw, @@ -7212,7 +7208,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn); lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade); lpfc_suppress_link_up_init(phba, lpfc_suppress_link_up); - lpfc_iocb_cnt_init(phba, lpfc_iocb_cnt); lpfc_delay_discovery_init(phba, lpfc_delay_discovery); lpfc_sli_mode_init(phba, lpfc_sli_mode); phba->cfg_enable_dss = 1; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index e91377a4cafe..bb84d2a20e76 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7126,7 +7126,7 @@ lpfc_init_iocb_list(struct lpfc_hba *phba, int iocb_count) if (iocbq_entry == NULL) { printk(KERN_ERR "%s: only allocated %d iocbs of " "expected %d count. Unloading driver.\n", - __func__, i, LPFC_IOCB_LIST_CNT); + __func__, i, iocb_count); goto out_free_iocbq; } @@ -11591,13 +11591,10 @@ fcponly: } /* If the NVME FC4 type is enabled, scale the sg_seg_cnt to - * accommodate 512K and 1M IOs in a single nvme buf and supply - * enough NVME LS iocb buffers for larger connectivity counts. + * accommodate 512K and 1M IOs in a single nvme buf. */ - if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) { + if (phba->cfg_enable_fc4_type & LPFC_ENABLE_NVME) phba->cfg_sg_seg_cnt = LPFC_MAX_NVME_SEG_CNT; - phba->cfg_iocb_cnt = 5; - } /* Only embed PBDE for if_type 6, PBDE support requires xib be set */ if ((bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) != diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 3b3ae2182e59..827406f58b1e 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -7523,9 +7523,11 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) } phba->sli4_hba.nvmet_xri_cnt = rc; - cnt = phba->cfg_iocb_cnt * 1024; - /* We need 1 iocbq for every SGL, for IO processing */ - cnt += phba->sli4_hba.nvmet_xri_cnt; + /* We allocate an iocbq for every receive context SGL. + * The additional allocation is for abort and ls handling. + */ + cnt = phba->sli4_hba.nvmet_xri_cnt + + phba->sli4_hba.max_cfg_param.max_xri; } else { /* update host common xri-sgl sizes and mappings */ rc = lpfc_sli4_io_sgl_update(phba); @@ -7547,14 +7549,17 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) rc = -ENODEV; goto out_destroy_queue; } - cnt = phba->cfg_iocb_cnt * 1024; + /* Each lpfc_io_buf job structure has an iocbq element. + * This cnt provides for abort, els, ct and ls requests. + */ + cnt = phba->sli4_hba.max_cfg_param.max_xri; } if (!phba->sli.iocbq_lookup) { /* Initialize and populate the iocb list per host */ lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "2821 initialize iocb list %d total %d\n", - phba->cfg_iocb_cnt, cnt); + "2821 initialize iocb list with %d entries\n", + cnt); rc = lpfc_init_iocb_list(phba, cnt); if (rc) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, -- cgit v1.2.3 From 97acd0019d5dadd9c0e111c2083c889bfe548f25 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:51 -0700 Subject: scsi: lpfc: Fix rpi release when deleting vport A prior use-after-free mailbox fix solved it's problem by null'ing a ndlp pointer. However, further testing has shown that this change causes a later state change to occasionally be skipped, which results in a reference count never being decremented thus the rpi is never released, which causes a vport delete to never succeed. Revise the fix in the prior patch to no longer null the ndlp. Instead the RELEASE_RPI flag is set which will drive the release of the rpi. Given the new code was added at a deep indentation level, refactor the code block using a new routine that avoids the indentation issues. Fixes: 9b1640686470 ("scsi: lpfc: Fix use-after-free mailbox cmd completion") Link: https://lore.kernel.org/r/20190922035906.10977-6-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 88 +++++++++++++++++++++++++++------------- drivers/scsi/lpfc/lpfc_sli.c | 2 + 2 files changed, 61 insertions(+), 29 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 749286acdc17..9df6f0cabab0 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4840,6 +4840,44 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } } +/* + * Sets the mailbox completion handler to be used for the + * unreg_rpi command. The handler varies based on the state of + * the port and what will be happening to the rpi next. + */ +static void +lpfc_set_unreg_login_mbx_cmpl(struct lpfc_hba *phba, struct lpfc_vport *vport, + struct lpfc_nodelist *ndlp, LPFC_MBOXQ_t *mbox) +{ + unsigned long iflags; + + if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { + mbox->ctx_ndlp = ndlp; + mbox->mbox_cmpl = lpfc_nlp_logo_unreg; + + } else if (phba->sli_rev == LPFC_SLI_REV4 && + (!(vport->load_flag & FC_UNLOADING)) && + (bf_get(lpfc_sli_intf_if_type, &phba->sli4_hba.sli_intf) >= + LPFC_SLI_INTF_IF_TYPE_2) && + (kref_read(&ndlp->kref) > 0)) { + mbox->ctx_ndlp = lpfc_nlp_get(ndlp); + mbox->mbox_cmpl = lpfc_sli4_unreg_rpi_cmpl_clr; + } else { + if (vport->load_flag & FC_UNLOADING) { + if (phba->sli_rev == LPFC_SLI_REV4) { + spin_lock_irqsave(&vport->phba->ndlp_lock, + iflags); + ndlp->nlp_flag |= NLP_RELEASE_RPI; + spin_unlock_irqrestore(&vport->phba->ndlp_lock, + iflags); + } + lpfc_nlp_get(ndlp); + } + mbox->ctx_ndlp = ndlp; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + } +} + /* * Free rpi associated with LPFC_NODELIST entry. * This routine is called from lpfc_freenode(), when we are removing @@ -4890,33 +4928,12 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_unreg_login(phba, vport->vpi, rpi, mbox); mbox->vport = vport; - if (ndlp->nlp_flag & NLP_ISSUE_LOGO) { - mbox->ctx_ndlp = ndlp; - mbox->mbox_cmpl = lpfc_nlp_logo_unreg; - } else { - if (phba->sli_rev == LPFC_SLI_REV4 && - (!(vport->load_flag & FC_UNLOADING)) && - (bf_get(lpfc_sli_intf_if_type, - &phba->sli4_hba.sli_intf) >= - LPFC_SLI_INTF_IF_TYPE_2) && - (kref_read(&ndlp->kref) > 0)) { - mbox->ctx_ndlp = lpfc_nlp_get(ndlp); - mbox->mbox_cmpl = - lpfc_sli4_unreg_rpi_cmpl_clr; - /* - * accept PLOGIs after unreg_rpi_cmpl - */ - acc_plogi = 0; - } else if (vport->load_flag & FC_UNLOADING) { - mbox->ctx_ndlp = NULL; - mbox->mbox_cmpl = - lpfc_sli_def_mbox_cmpl; - } else { - mbox->ctx_ndlp = ndlp; - mbox->mbox_cmpl = - lpfc_sli_def_mbox_cmpl; - } - } + lpfc_set_unreg_login_mbx_cmpl(phba, vport, ndlp, mbox); + if (mbox->mbox_cmpl == lpfc_sli4_unreg_rpi_cmpl_clr) + /* + * accept PLOGIs after unreg_rpi_cmpl + */ + acc_plogi = 0; if (((ndlp->nlp_DID & Fabric_DID_MASK) != Fabric_DID_MASK) && (!(vport->fc_flag & FC_OFFLINE_MODE))) @@ -5057,6 +5074,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *mb, *nextmb; struct lpfc_dmabuf *mp; + unsigned long iflags; /* Cleanup node for NPort */ lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, @@ -5138,8 +5156,20 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_cleanup_vports_rrqs(vport, ndlp); if (phba->sli_rev == LPFC_SLI_REV4) ndlp->nlp_flag |= NLP_RELEASE_RPI; - lpfc_unreg_rpi(vport, ndlp); - + if (!lpfc_unreg_rpi(vport, ndlp)) { + /* Clean up unregistered and non freed rpis */ + if ((ndlp->nlp_flag & NLP_RELEASE_RPI) && + !(ndlp->nlp_rpi == LPFC_RPI_ALLOC_ERROR)) { + lpfc_sli4_free_rpi(vport->phba, + ndlp->nlp_rpi); + spin_lock_irqsave(&vport->phba->ndlp_lock, + iflags); + ndlp->nlp_flag &= ~NLP_RELEASE_RPI; + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + spin_unlock_irqrestore(&vport->phba->ndlp_lock, + iflags); + } + } return 0; } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 827406f58b1e..f764012ba0a6 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2526,6 +2526,8 @@ lpfc_sli_def_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) } else { __lpfc_sli_rpi_release(vport, ndlp); } + if (vport->load_flag & FC_UNLOADING) + lpfc_nlp_put(ndlp); pmb->ctx_ndlp = NULL; } } -- cgit v1.2.3 From 0f154226d699fefe651ccc4db773efc05a820b56 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:52 -0700 Subject: scsi: lpfc: Fix device recovery errors after PLOGI failures When target-side fault injections are made, the driver isn't reconnecting to the remote port. The driver is logging "2753" error messages which state: "PLOGI failure DID:1B2400 Status:x3/xf0240008" The failures status is indicating a Illegal field error, which points to the Temporary RPI field being used for the ELS. This error typically means the driver used an RPI that was already registered (shouldn't be registered if using it in this context). Study has found that if the driver were in discovery attempts and encountered an error, it wouldn't flag the temporary rpi in error. Yet the rpi was released for reallocation in these error paths and another ELS could allocate the rpi. In the failure situation a retry was done on an ELS that had encountered an error, and as the rpi wasn't marked in error, the ELS reused the rpi it originally allocated. But that rpi had been allocated by a different ELS issued after the original error and before the retry attempt. The different ELS had succeeded and the RPI was registered. Fix by marking the rpi state for the node to be in error, aka as needing reallocation, upon an error in the els processing. Error state marking is always done prior to release back to the internal rpi free list, which the driver wasn't doing in cases prior. Also enhanced some of the logging to help in the next case of problem troubleshooting. Link: https://lore.kernel.org/r/20190922035906.10977-7-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 44 ++++++++++++++++++++++++---------------- drivers/scsi/lpfc/lpfc_init.c | 40 ++++++++++++++++++++---------------- drivers/scsi/lpfc/lpfc_sli.c | 8 +++++--- 3 files changed, 55 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 9df6f0cabab0..144786947b63 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -4046,7 +4046,7 @@ out: ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0003 rpi:%x DID:%x flg:%x %d map%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), @@ -4575,8 +4575,10 @@ lpfc_enable_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return ndlp; free_rpi: - if (phba->sli_rev == LPFC_SLI_REV4) + if (phba->sli_rev == LPFC_SLI_REV4) { lpfc_sli4_free_rpi(vport->phba, rpi); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; + } return NULL; } @@ -4835,6 +4837,7 @@ lpfc_nlp_logo_unreg(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (ndlp->nlp_flag & NLP_RELEASE_RPI) { lpfc_sli4_free_rpi(vport->phba, ndlp->nlp_rpi); ndlp->nlp_flag &= ~NLP_RELEASE_RPI; + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } ndlp->nlp_flag &= ~NLP_UNREG_INP; } @@ -4898,7 +4901,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_flag & NLP_RPI_REGISTERED || ndlp->nlp_flag & NLP_REG_LOGIN_SEND) { if (ndlp->nlp_flag & NLP_REG_LOGIN_SEND) - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "3366 RPI x%x needs to be " "unregistered nlp_flag x%x " "did x%x\n", @@ -4909,7 +4913,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * no need to queue up another one. */ if (ndlp->nlp_flag & NLP_UNREG_INP) { - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "1436 unreg_rpi SKIP UNREG x%x on " "NPort x%x deferred x%x flg x%x " "Data: x%px\n", @@ -4939,7 +4944,8 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) (!(vport->fc_flag & FC_OFFLINE_MODE))) ndlp->nlp_flag |= NLP_UNREG_INP; - lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "1433 unreg_rpi UNREG x%x on " "NPort x%x deferred flg x%x " "Data:x%px\n", @@ -5195,8 +5201,10 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* For this case we need to cleanup the default rpi * allocated by the firmware. */ - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0005 rpi:%x DID:%x flg:%x %d map:%x x%px\n", + lpfc_printf_vlog(vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0005 Cleanup Default rpi:x%x DID:x%x flg:x%x " + "ref %d map:x%x ndlp x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), ndlp->nlp_usg_map, ndlp); @@ -5233,8 +5241,9 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) */ lpfc_printf_vlog(vport, KERN_WARNING, LOG_NODE, "0940 removed node x%px DID x%x " - " rport not null x%px\n", - ndlp, ndlp->nlp_DID, ndlp->rport); + "rpi %d rport not null x%px\n", + ndlp, ndlp->nlp_DID, ndlp->nlp_rpi, + ndlp->rport); rport = ndlp->rport; rdata = rport->dd_data; rdata->pnode = NULL; @@ -6026,7 +6035,7 @@ lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) ndlp->nlp_flag |= NLP_RPI_REGISTERED; ndlp->nlp_type |= NLP_FABRIC; lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - lpfc_printf_vlog(vport, KERN_INFO, LOG_SLI, + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, "0004 rpi:%x DID:%x flg:%x %d map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, ndlp->nlp_flag, kref_read(&ndlp->kref), @@ -6215,12 +6224,12 @@ lpfc_nlp_init(struct lpfc_vport *vport, uint32_t did) INIT_LIST_HEAD(&ndlp->nlp_listp); if (vport->phba->sli_rev == LPFC_SLI_REV4) { ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE, - "0007 rpi:%x DID:%x flg:%x refcnt:%d " - "map:%x x%px\n", ndlp->nlp_rpi, ndlp->nlp_DID, - ndlp->nlp_flag, - kref_read(&ndlp->kref), - ndlp->nlp_usg_map, ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_NODE | LOG_DISCOVERY, + "0007 Init New ndlp x%px, rpi:x%x DID:%x " + "flg:x%x refcnt:%d map:x%x\n", + ndlp, ndlp->nlp_rpi, ndlp->nlp_DID, + ndlp->nlp_flag, kref_read(&ndlp->kref), + ndlp->nlp_usg_map); ndlp->active_rrqs_xri_bitmap = mempool_alloc(vport->phba->active_rrq_pool, @@ -6449,7 +6458,8 @@ lpfc_fcf_inuse(struct lpfc_hba *phba) goto out; } else if (ndlp->nlp_flag & NLP_RPI_REGISTERED) { ret = 1; - lpfc_printf_log(phba, KERN_INFO, LOG_ELS, + lpfc_printf_log(phba, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "2624 RPI %x DID %x flag %x " "still logged in\n", ndlp->nlp_rpi, ndlp->nlp_DID, diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index bb84d2a20e76..12885b01fa27 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -3053,11 +3053,12 @@ lpfc_sli4_node_prep(struct lpfc_hba *phba) continue; } ndlp->nlp_rpi = rpi; - lpfc_printf_vlog(ndlp->vport, KERN_INFO, LOG_NODE, - "0009 rpi:%x DID:%x " - "flg:%x map:%x x%px\n", ndlp->nlp_rpi, - ndlp->nlp_DID, ndlp->nlp_flag, - ndlp->nlp_usg_map, ndlp); + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0009 Assign RPI x%x to ndlp x%px " + "DID:x%06x flg:x%x map:x%x\n", + ndlp->nlp_rpi, ndlp, ndlp->nlp_DID, + ndlp->nlp_flag, ndlp->nlp_usg_map); } } lpfc_destroy_vport_work_array(phba, vports); @@ -3453,10 +3454,15 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) list_for_each_entry_safe(ndlp, next_ndlp, &vports[i]->fc_nodes, nlp_listp) { - if (!NLP_CHK_NODE_ACT(ndlp)) - continue; - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + if ((!NLP_CHK_NODE_ACT(ndlp)) || + ndlp->nlp_state == NLP_STE_UNUSED_NODE) { + /* Driver must assume RPI is invalid for + * any unused or inactive node. + */ + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; continue; + } + if (ndlp->nlp_type & NLP_FABRIC) { lpfc_disc_state_machine(vports[i], ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); @@ -3472,16 +3478,16 @@ lpfc_offline_prep(struct lpfc_hba *phba, int mbx_action) * comes back online. */ if (phba->sli_rev == LPFC_SLI_REV4) { - lpfc_printf_vlog(ndlp->vport, - KERN_INFO, LOG_NODE, - "0011 lpfc_offline: " - "ndlp:x%px did %x " - "usgmap:x%x rpi:%x\n", - ndlp, ndlp->nlp_DID, - ndlp->nlp_usg_map, - ndlp->nlp_rpi); - + lpfc_printf_vlog(ndlp->vport, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0011 Free RPI x%x on " + "ndlp:x%px did x%x " + "usgmap:x%x\n", + ndlp->nlp_rpi, ndlp, + ndlp->nlp_DID, + ndlp->nlp_usg_map); lpfc_sli4_free_rpi(phba, ndlp->nlp_rpi); + ndlp->nlp_rpi = LPFC_RPI_ALLOC_ERROR; } lpfc_unreg_rpi(vports[i], ndlp); } diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index f764012ba0a6..24d6779a99f8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -18131,8 +18131,9 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) phba->sli4_hba.max_cfg_param.rpi_used++; phba->sli4_hba.rpi_count++; } - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "0001 rpi:%x max:%x lim:%x\n", + lpfc_printf_log(phba, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, + "0001 Allocated rpi:x%x max:x%x lim:x%x\n", (int) rpi, max_rpi, rpi_limit); /* @@ -18192,7 +18193,8 @@ __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) phba->sli4_hba.rpi_count--; phba->sli4_hba.max_cfg_param.rpi_used--; } else { - lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + lpfc_printf_log(phba, KERN_INFO, + LOG_NODE | LOG_DISCOVERY, "2016 rpi %x not inuse\n", rpi); } -- cgit v1.2.3 From 07b8582430370097238b589f4e24da7613ca6dd3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:53 -0700 Subject: scsi: lpfc: Fix locking on mailbox command completion Symptoms were seen of the driver not having valid data for mailbox commands. After debugging, the following sequence was found: The driver maintains a port-wide pointer of the mailbox command that is currently in execution. Once finished, the port-wide pointer is cleared (done in lpfc_sli4_mq_release()). The next mailbox command issued will set the next pointer and so on. The mailbox response data is only copied if there is a valid port-wide pointer. In the failing case, it was seen that a new mailbox command was being attempted in parallel with the completion. The parallel path was seeing the mailbox no long in use (flag check under lock) and thus set the port pointer. The completion path had cleared the active flag under lock, but had not touched the port pointer. The port pointer is cleared after the lock is released. In this case, the completion path cleared the just-set value by the parallel path. Fix by making the calls that clear mbox state/port pointer while under lock. Also slightly cleaned up the error path. Link: https://lore.kernel.org/r/20190922035906.10977-8-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 24d6779a99f8..313441a3c4cf 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13165,13 +13165,19 @@ send_current_mbox: phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE; /* Setting active mailbox pointer need to be in sync to flag clear */ phba->sli.mbox_active = NULL; + if (bf_get(lpfc_trailer_consumed, mcqe)) + lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq); spin_unlock_irqrestore(&phba->hbalock, iflags); /* Wake up worker thread to post the next pending mailbox command */ lpfc_worker_wake_up(phba); + return workposted; + out_no_mqe_complete: + spin_lock_irqsave(&phba->hbalock, iflags); if (bf_get(lpfc_trailer_consumed, mcqe)) lpfc_sli4_mq_release(phba->sli4_hba.mbx_wq); - return workposted; + spin_unlock_irqrestore(&phba->hbalock, iflags); + return false; } /** -- cgit v1.2.3 From 9df0a0381a600438d19def2c3868c02871e0cd72 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:54 -0700 Subject: scsi: lpfc: Fix GPF on scsi command completion Faults are seen with RIP of lpfc_scsi_cmd_iocb_cmpl(). The failure is when lpfc_update_status is being called as part of the completion. After debugging, it was seen the issue was the shost pointer that the driver derived from the scsi cmd. The crash showed the cmd->device pointer being bogus, which is likely as the scsi devices were offlined prior. The bogus device pointer caused subsequent pointers derived from the location, specifically the vport, to be bogus. Fix by adjusting the calling sequence to pass in the vport rather than having to derive it from the cmd structure. Link: https://lore.kernel.org/r/20190922035906.10977-9-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index fe1097666de4..c2773c07657d 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -134,21 +134,21 @@ lpfc_sli4_set_rsp_sgl_last(struct lpfc_hba *phba, /** * lpfc_update_stats - Update statistical data for the command completion - * @phba: Pointer to HBA object. + * @vport: The virtual port on which this call is executing. * @lpfc_cmd: lpfc scsi command object pointer. * * This function is called when there is a command completion and this * function updates the statistical data for the command completion. **/ static void -lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_cmd) +lpfc_update_stats(struct lpfc_vport *vport, struct lpfc_io_buf *lpfc_cmd) { + struct lpfc_hba *phba = vport->phba; struct lpfc_rport_data *rdata; struct lpfc_nodelist *pnode; struct scsi_cmnd *cmd = lpfc_cmd->pCmd; unsigned long flags; - struct Scsi_Host *shost = cmd->device->host; - struct lpfc_vport *vport = (struct lpfc_vport *) shost->hostdata; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); unsigned long latency; int i; @@ -4004,7 +4004,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, scsi_get_resid(cmd)); } - lpfc_update_stats(phba, lpfc_cmd); + lpfc_update_stats(vport, lpfc_cmd); if (vport->cfg_max_scsicmpl_time && time_after(jiffies, lpfc_cmd->start_time + msecs_to_jiffies(vport->cfg_max_scsicmpl_time))) { -- cgit v1.2.3 From 3f97aed6117c7677eb16756c4ec8b86000fd5822 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:55 -0700 Subject: scsi: lpfc: Fix discovery failures when target device connectivity bounces An issue was seen discovering all SCSI Luns when a target device undergoes link bounce. The driver currently does not qualify the FC4 support on the target. Therefore it will send a SCSI PRLI and an NVMe PRLI. The expectation is that the target will reject the PRLI if it is not supported. If a PRLI times out, the driver will retry. The driver will not proceed with the device until both SCSI and NVMe PRLIs are resolved. In the failure case, the device is FCP only and does not respond to the NVMe PRLI, thus initiating the wait/retry loop in the driver. During that time, a RSCN is received (device bounced) causing the driver to issue a GID_FT. The GID_FT response comes back before the PRLI mess is resolved and it prematurely cancels the PRLI retry logic and leaves the device in a STE_PRLI_ISSUE state. Discovery with the target never completes or resets. Fix by resetting the node state back to STE_NPR_NODE when GID_FT completes, thereby restarting the discovery process for the node. Link: https://lore.kernel.org/r/20190922035906.10977-10-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 144786947b63..f483b3aea22b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5444,9 +5444,14 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) /* If we've already received a PLOGI from this NPort * we don't need to try to discover it again. */ - if (ndlp->nlp_flag & NLP_RCV_PLOGI) + if (ndlp->nlp_flag & NLP_RCV_PLOGI && + !(ndlp->nlp_type & + (NLP_FCP_TARGET | NLP_NVME_TARGET))) return NULL; + ndlp->nlp_prev_state = ndlp->nlp_state; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); -- cgit v1.2.3 From 51f8e43ed355d30b3c93293077ecb0c0afac3799 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:56 -0700 Subject: scsi: lpfc: Fix NVMe ABTS in response to receiving an ABTS When the port, running as a nvme target, receives an ABTS, it submits commands to the adapter to Abort i/o outstanding in the adapter. The Abort command formatting routine left a command field set to zero, which instructs the adapter to generate an ABTS on the wire as part of cleaning up the I/O. This is common operation for an initiator, but not for a target. Fix the driver to check whether an ABTS had been received for the I/O, and if so, change the Abort command formatting so that the ABTS generation is disabled (IA=1). No need to ABTS it when the other side already has. Also refactored the code such that there is a single routine being used for nvme or nvmet ABORT requests, and IA is an argument. Link: https://lore.kernel.org/r/20190922035906.10977-11-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_crtn.h | 1 + drivers/scsi/lpfc/lpfc_hw4.h | 1 + drivers/scsi/lpfc/lpfc_nvme.c | 73 ++++++++++++++++++++++++------------------ drivers/scsi/lpfc/lpfc_nvmet.c | 34 ++------------------ 4 files changed, 46 insertions(+), 63 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index b2ad8c750486..6e09fd98a922 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -586,6 +586,7 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *ncmd, void lpfc_nvme_cmd_template(void); void lpfc_nvmet_cmd_template(void); void lpfc_nvme_cancel_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *pwqeIn); +void lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt); extern int lpfc_enable_nvmet_cnt; extern unsigned long long lpfc_enable_nvmet[]; extern int lpfc_no_hba_reset_cnt; diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index bd533475c86a..f70fb7629c82 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -4659,6 +4659,7 @@ struct create_xri_wqe { uint32_t rsvd_12_15[4]; /* word 12-15 */ }; +#define INHIBIT_ABORT 1 #define T_REQUEST_TAG 3 #define T_XRI_TAG 1 diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index a227e36cbdc2..5af944b97c4c 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -195,6 +195,46 @@ lpfc_nvme_cmd_template(void) /* Word 12, 13, 14, 15 - is zero */ } +/** + * lpfc_nvme_prep_abort_wqe - set up 'abort' work queue entry. + * @pwqeq: Pointer to command iocb. + * @xritag: Tag that uniqely identifies the local exchange resource. + * @opt: Option bits - + * bit 0 = inhibit sending abts on the link + * + * This function is called with hbalock held. + **/ +void +lpfc_nvme_prep_abort_wqe(struct lpfc_iocbq *pwqeq, u16 xritag, u8 opt) +{ + union lpfc_wqe128 *wqe = &pwqeq->wqe; + + /* WQEs are reused. Clear stale data and set key fields to + * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. + */ + memset(wqe, 0, sizeof(*wqe)); + + if (opt & INHIBIT_ABORT) + bf_set(abort_cmd_ia, &wqe->abort_cmd, 1); + /* Abort specified xri tag, with the mask deliberately zeroed */ + bf_set(abort_cmd_criteria, &wqe->abort_cmd, T_XRI_TAG); + + bf_set(wqe_cmnd, &wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); + + /* Abort the IO associated with this outstanding exchange ID. */ + wqe->abort_cmd.wqe_com.abort_tag = xritag; + + /* iotag for the wqe completion. */ + bf_set(wqe_reqtag, &wqe->abort_cmd.wqe_com, pwqeq->iotag); + + bf_set(wqe_qosd, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_lenloc, &wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); + + bf_set(wqe_cmd_type, &wqe->abort_cmd.wqe_com, OTHER_COMMAND); + bf_set(wqe_wqec, &wqe->abort_cmd.wqe_com, 1); + bf_set(wqe_cqid, &wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); +} + /** * lpfc_nvme_create_queue - * @lpfc_pnvme: Pointer to the driver's nvme instance data @@ -1791,7 +1831,6 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, struct lpfc_iocbq *abts_buf; struct lpfc_iocbq *nvmereq_wqe; struct lpfc_nvme_fcpreq_priv *freqpriv; - union lpfc_wqe128 *abts_wqe; unsigned long flags; int ret_val; @@ -1912,37 +1951,7 @@ lpfc_nvme_fcp_abort(struct nvme_fc_local_port *pnvme_lport, /* Ready - mark outstanding as aborted by driver. */ nvmereq_wqe->iocb_flag |= LPFC_DRIVER_ABORTED; - /* Complete prepping the abort wqe and issue to the FW. */ - abts_wqe = &abts_buf->wqe; - - /* WQEs are reused. Clear stale data and set key fields to - * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. - */ - memset(abts_wqe, 0, sizeof(*abts_wqe)); - bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); - - /* word 7 */ - bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - bf_set(wqe_class, &abts_wqe->abort_cmd.wqe_com, - nvmereq_wqe->iocb.ulpClass); - - /* word 8 - tell the FW to abort the IO associated with this - * outstanding exchange ID. - */ - abts_wqe->abort_cmd.wqe_com.abort_tag = nvmereq_wqe->sli4_xritag; - - /* word 9 - this is the iotag for the abts_wqe completion. */ - bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com, - abts_buf->iotag); - - /* word 10 */ - bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - /* word 11 */ - bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + lpfc_nvme_prep_abort_wqe(abts_buf, nvmereq_wqe->sli4_xritag, 0); /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_buf->iocb_flag |= LPFC_IO_NVME; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 9884228800a5..121dbdcbb583 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -3239,9 +3239,9 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, { struct lpfc_nvmet_tgtport *tgtp; struct lpfc_iocbq *abts_wqeq; - union lpfc_wqe128 *abts_wqe; struct lpfc_nodelist *ndlp; unsigned long flags; + u8 opt; int rc; tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; @@ -3280,8 +3280,8 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, return 0; } abts_wqeq = ctxp->abort_wqeq; - abts_wqe = &abts_wqeq->wqe; ctxp->state = LPFC_NVMET_STE_ABORT; + opt = (ctxp->flag & LPFC_NVMET_ABTS_RCV) ? INHIBIT_ABORT : 0; spin_unlock_irqrestore(&ctxp->ctxlock, flags); /* Announce entry to new IO submit field. */ @@ -3327,35 +3327,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, /* Ready - mark outstanding as aborted by driver. */ abts_wqeq->iocb_flag |= LPFC_DRIVER_ABORTED; - /* WQEs are reused. Clear stale data and set key fields to - * zero like ia, iaab, iaar, xri_tag, and ctxt_tag. - */ - memset(abts_wqe, 0, sizeof(*abts_wqe)); - - /* word 3 */ - bf_set(abort_cmd_criteria, &abts_wqe->abort_cmd, T_XRI_TAG); - - /* word 7 */ - bf_set(wqe_ct, &abts_wqe->abort_cmd.wqe_com, 0); - bf_set(wqe_cmnd, &abts_wqe->abort_cmd.wqe_com, CMD_ABORT_XRI_CX); - - /* word 8 - tell the FW to abort the IO associated with this - * outstanding exchange ID. - */ - abts_wqe->abort_cmd.wqe_com.abort_tag = ctxp->wqeq->sli4_xritag; - - /* word 9 - this is the iotag for the abts_wqe completion. */ - bf_set(wqe_reqtag, &abts_wqe->abort_cmd.wqe_com, - abts_wqeq->iotag); - - /* word 10 */ - bf_set(wqe_qosd, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_lenloc, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_LENLOC_NONE); - - /* word 11 */ - bf_set(wqe_cmd_type, &abts_wqe->abort_cmd.wqe_com, OTHER_COMMAND); - bf_set(wqe_wqec, &abts_wqe->abort_cmd.wqe_com, 1); - bf_set(wqe_cqid, &abts_wqe->abort_cmd.wqe_com, LPFC_WQE_CQ_ID_DEFAULT); + lpfc_nvme_prep_abort_wqe(abts_wqeq, ctxp->wqeq->sli4_xritag, opt); /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx; -- cgit v1.2.3 From 43bfea1bffb6b01089c2fe483ede1b036e166579 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:57 -0700 Subject: scsi: lpfc: Fix coverity errors on NULL pointer checks Coverity flagged several scenarios where checking of null pointer values wasn't consistent. Fix the code to that be consistent on checking. Link: https://lore.kernel.org/r/20190922035906.10977-12-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 5 +++++ drivers/scsi/lpfc/lpfc_nvmet.c | 19 +++++++++++++++---- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 9 ++++++--- 4 files changed, 27 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index d5303994bfd6..55ab37572e92 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4291,6 +4291,11 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &rspiocb->iocb; + if (!vport) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "3177 ELS response failed\n"); + goto out; + } if (cmdiocb->context_un.mbox) mbox = cmdiocb->context_un.mbox; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index 121dbdcbb583..c9481a618b85 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -1958,12 +1958,10 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, uint32_t *payload; uint32_t size, oxid, sid, rc; - fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); - oxid = be16_to_cpu(fc_hdr->fh_ox_id); - if (!phba->targetport) { + if (!nvmebuf || !phba->targetport) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6154 LS Drop IO x%x\n", oxid); + "6154 LS Drop IO\n"); oxid = 0; size = 0; sid = 0; @@ -1971,6 +1969,9 @@ lpfc_nvmet_unsol_ls_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, goto dropit; } + fc_hdr = (struct fc_frame_header *)(nvmebuf->hbuf.virt); + oxid = be16_to_cpu(fc_hdr->fh_ox_id); + tgtp = (struct lpfc_nvmet_tgtport *)phba->targetport->private; payload = (uint32_t *)(nvmebuf->dbuf.virt); size = bf_get(lpfc_rcqe_length, &nvmebuf->cq_event.cqe.rcqe_cmpl); @@ -2401,6 +2402,11 @@ lpfc_nvmet_unsol_ls_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, d_buf = piocb->context2; nvmebuf = container_of(d_buf, struct hbq_dmabuf, dbuf); + if (!nvmebuf) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "3015 LS Drop IO\n"); + return; + } if (phba->nvmet_support == 0) { lpfc_in_buf_free(phba, &nvmebuf->dbuf); return; @@ -2429,6 +2435,11 @@ lpfc_nvmet_unsol_fcp_event(struct lpfc_hba *phba, uint64_t isr_timestamp, uint8_t cqflag) { + if (!nvmebuf) { + lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, + "3167 NVMET FCP Drop IO\n"); + return; + } if (phba->nvmet_support == 0) { lpfc_rq_buf_free(phba, &nvmebuf->hbuf); return; diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index c2773c07657d..f06f63e58596 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -3814,7 +3814,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, /* Sanity check on return of outstanding command */ cmd = lpfc_cmd->pCmd; - if (!cmd) { + if (!cmd || !phba) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, "2621 IO completion: Not an active IO\n"); spin_unlock(&lpfc_cmd->buf_lock); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 313441a3c4cf..939efee6b5dd 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -2674,7 +2674,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_SLI, "(%d):0323 Unknown Mailbox command " "x%x (x%x/x%x) Cmpl\n", - pmb->vport ? pmb->vport->vpi : 0, + pmb->vport ? pmb->vport->vpi : + LPFC_VPORT_UNKNOWN, pmbox->mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, pmb), @@ -2695,7 +2696,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) "(%d):0305 Mbox cmd cmpl " "error - RETRYing Data: x%x " "(x%x/x%x) x%x x%x x%x\n", - pmb->vport ? pmb->vport->vpi : 0, + pmb->vport ? pmb->vport->vpi : + LPFC_VPORT_UNKNOWN, pmbox->mbxCommand, lpfc_sli_config_mbox_subsys_get(phba, pmb), @@ -2703,7 +2705,8 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba) pmb), pmbox->mbxStatus, pmbox->un.varWords[0], - pmb->vport->port_state); + pmb->vport ? pmb->vport->port_state : + LPFC_VPORT_UNKNOWN); pmbox->mbxStatus = 0; pmbox->mbxOwner = OWN_HOST; rc = lpfc_sli_issue_mbox(phba, pmb, MBX_NOWAIT); -- cgit v1.2.3 From 24c7c0a6d3de68b6e15532d18749e561d260c160 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:58 -0700 Subject: scsi: lpfc: Fix host hang at boot or slow boot Scenarios were seen where a host hung when the system booted or the host was very slow in booting. The link would not come up and no luns were visible to the host. After investigation, this was found to be due to the introduction of a new ACQE that adapter may generate to report a adapter hw warning. The ACQE was delivered to the driver very early in adapter initialization, when the driver did not expect command completion. As part of handling this unexpected interrupt the an EQEs are consumed and discarded and the EQ rearmed. The issue is the CQ that cause the EQE and thus the interrupt was not processed and the CQ was left unarmed. Meaning it would no longer generate a new interrupt condition. Subsequent mailbox commands used to initialize the adapter use the same CQ, and as there was no completion interrupt generated, the driver never saw the mailbox commands complete and it would wait long command timeouts. Fix by having the early flush routine also process the related CQ and rearm the CQ. Link: https://lore.kernel.org/r/20190922035906.10977-13-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 939efee6b5dd..412cd8c56d90 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -87,6 +87,10 @@ static void lpfc_sli4_hba_handle_eqe(struct lpfc_hba *phba, struct lpfc_eqe *eqe); static bool lpfc_sli4_mbox_completions_pending(struct lpfc_hba *phba); static bool lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba); +static struct lpfc_cqe *lpfc_sli4_cq_get(struct lpfc_queue *q); +static void __lpfc_sli4_consume_cqe(struct lpfc_hba *phba, + struct lpfc_queue *cq, + struct lpfc_cqe *cqe); static IOCB_t * lpfc_get_iocb_from_iocbq(struct lpfc_iocbq *iocbq) @@ -467,21 +471,47 @@ __lpfc_sli4_consume_eqe(struct lpfc_hba *phba, struct lpfc_queue *eq, } static void -lpfc_sli4_eq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) +lpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) { - struct lpfc_eqe *eqe; - uint32_t count = 0; + struct lpfc_eqe *eqe = NULL; + u32 eq_count = 0, cq_count = 0; + struct lpfc_cqe *cqe = NULL; + struct lpfc_queue *cq = NULL, *childq = NULL; + int cqid = 0; /* walk all the EQ entries and drop on the floor */ eqe = lpfc_sli4_eq_get(eq); while (eqe) { + /* Get the reference to the corresponding CQ */ + cqid = bf_get_le32(lpfc_eqe_resource_id, eqe); + cq = NULL; + + list_for_each_entry(childq, &eq->child_list, list) { + if (childq->queue_id == cqid) { + cq = childq; + break; + } + } + /* If CQ is valid, iterate through it and drop all the CQEs */ + if (cq) { + cqe = lpfc_sli4_cq_get(cq); + while (cqe) { + __lpfc_sli4_consume_cqe(phba, cq, cqe); + cq_count++; + cqe = lpfc_sli4_cq_get(cq); + } + /* Clear and re-arm the CQ */ + phba->sli4_hba.sli4_write_cq_db(phba, cq, cq_count, + LPFC_QUEUE_REARM); + cq_count = 0; + } __lpfc_sli4_consume_eqe(phba, eq, eqe); - count++; + eq_count++; eqe = lpfc_sli4_eq_get(eq); } /* Clear and re-arm the EQ */ - phba->sli4_hba.sli4_write_eq_db(phba, eq, count, LPFC_QUEUE_REARM); + phba->sli4_hba.sli4_write_eq_db(phba, eq, eq_count, LPFC_QUEUE_REARM); } static int @@ -14236,7 +14266,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) spin_lock_irqsave(&phba->hbalock, iflag); if (phba->link_state < LPFC_LINK_DOWN) /* Flush, clear interrupt, and rearm the EQ */ - lpfc_sli4_eq_flush(phba, fpeq); + lpfc_sli4_eqcq_flush(phba, fpeq); spin_unlock_irqrestore(&phba->hbalock, iflag); return IRQ_NONE; } -- cgit v1.2.3 From 15498dc1a55b7aaea4b51ff03e3ff0f662e73f44 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:58:59 -0700 Subject: scsi: lpfc: Fix list corruption in lpfc_sli_get_iocbq After study, it was determined there was a double free of a CT iocb during execution of lpfc_offline_prep and lpfc_offline. The prep routine issued an abort for some CT iocbs, but the aborts did not complete fast enough for a subsequent routine that waits for completion. Thus the driver proceeded to lpfc_offline, which releases any pending iocbs. Unfortunately, the completions for the aborts were then received which re-released the ct iocbs. Turns out the issue for why the aborts didn't complete fast enough was not their time on the wire/in the adapter. It was the lpfc_work_done routine, which requires the adapter state to be UP before it calls lpfc_sli_handle_slow_ring_event() to process the completions. The issue is the prep routine takes the link down as part of it's processing. To fix, the following was performed: - Prevent the offline routine from releasing iocbs that have had aborts issued on them. Defer to the abort completions. Also means the driver fully waits for the completions. Given this change, the recognition of "driver-generated" status which then releases the iocb is no longer valid. As such, the change made in the commit 296012285c90 is reverted. As recognition of "driver-generated" status is no longer valid, this patch reverts the changes made in commit 296012285c90 ("scsi: lpfc: Fix leak of ELS completions on adapter reset") - Modify lpfc_work_done to allow slow path completions so that the abort completions aren't ignored. - Updated the fdmi path to recognize a CT request that fails due to the port being unusable. This stops FDMI retries. FDMI will be restarted on next link up. Link: https://lore.kernel.org/r/20190922035906.10977-14-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 6 ++++++ drivers/scsi/lpfc/lpfc_els.c | 3 +++ drivers/scsi/lpfc/lpfc_hbadisc.c | 5 ++++- drivers/scsi/lpfc/lpfc_sli.c | 3 --- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index 25e86706e207..f883fac2d2b1 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -1868,6 +1868,12 @@ lpfc_cmpl_ct_disc_fdmi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT) { switch ((irsp->un.ulpWord[4] & IOERR_PARAM_MASK)) { case IOERR_SLI_ABORTED: + case IOERR_SLI_DOWN: + /* Driver aborted this IO. No retry as error + * is likely Offline->Online or some adapter + * error. Recovery will try again. + */ + break; case IOERR_ABORT_IN_PROGRESS: case IOERR_SEQUENCE_TIMEOUT: case IOERR_ILLEGAL_FRAME: diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 55ab37572e92..bd8109b2a083 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -8019,6 +8019,9 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (piocb->vport != vport) continue; + if (piocb->iocb_flag & LPFC_DRIVER_ABORTED) + continue; + /* On the ELS ring we can have ELS_REQUESTs or * GEN_REQUESTs waiting for a response. */ diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index f483b3aea22b..808ad666bb1b 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -700,7 +700,10 @@ lpfc_work_done(struct lpfc_hba *phba) if (!(phba->hba_flag & HBA_SP_QUEUE_EVT)) set_bit(LPFC_DATA_READY, &phba->data_flags); } else { - if (phba->link_state >= LPFC_LINK_UP || + /* Driver could have abort request completed in queue + * when link goes down. Allow for this transition. + */ + if (phba->link_state >= LPFC_LINK_DOWN || phba->link_flag & LS_MDS_LOOPBACK) { pring->flag &= ~LPFC_DEFERRED_RING_EVENT; lpfc_sli_handle_slow_ring_event(phba, pring, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 412cd8c56d90..ff261c0c738a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -11090,9 +11090,6 @@ lpfc_sli_abort_els_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4]); spin_unlock_irq(&phba->hbalock); - if (irsp->ulpStatus == IOSTAT_LOCAL_REJECT && - irsp->un.ulpWord[4] == IOERR_SLI_ABORTED) - lpfc_sli_release_iocbq(phba, abort_iocb); } release_iocb: lpfc_sli_release_iocbq(phba, cmdiocb); -- cgit v1.2.3 From d38b4a527fe898f859f74a3a43d4308f48ac7855 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:00 -0700 Subject: scsi: lpfc: Fix spinlock_irq issues in lpfc_els_flush_cmd() While reviewing the CT behavior, issues with spinlock_irq were seen. The driver should be using spinlock_irqsave/irqrestore in the els flush routine. Changed to spinlock_irqsave/irqrestore. Link: https://lore.kernel.org/r/20190922035906.10977-15-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index bd8109b2a083..da90c7bf2287 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -7991,20 +7991,22 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) struct lpfc_sli_ring *pring; struct lpfc_iocbq *tmp_iocb, *piocb; IOCB_t *cmd = NULL; + unsigned long iflags = 0; lpfc_fabric_abort_vport(vport); + /* * For SLI3, only the hbalock is required. But SLI4 needs to coordinate * with the ring insert operation. Because lpfc_sli_issue_abort_iotag * ultimately grabs the ring_lock, the driver must splice the list into * a working list and release the locks before calling the abort. */ - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); pring = lpfc_phba_elsring(phba); /* Bail out if we've no ELS wq, like in PCI error recovery case. */ if (unlikely(!pring)) { - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); return; } @@ -8045,21 +8047,21 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring->ring_lock); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); /* Abort each txcmpl iocb on aborted list and remove the dlist links. */ list_for_each_entry_safe(piocb, tmp_iocb, &abort_list, dlist) { - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); list_del_init(&piocb->dlist); lpfc_sli_issue_abort_iotag(phba, pring, piocb); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); } if (!list_empty(&abort_list)) lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "3387 abort list for txq not empty\n"); INIT_LIST_HEAD(&abort_list); - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, iflags); if (phba->sli_rev == LPFC_SLI_REV4) spin_lock(&pring->ring_lock); @@ -8099,7 +8101,7 @@ lpfc_els_flush_cmd(struct lpfc_vport *vport) if (phba->sli_rev == LPFC_SLI_REV4) spin_unlock(&pring->ring_lock); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, iflags); /* Cancel all the IOCBs from the completions list */ lpfc_sli_cancel_iocbs(phba, &abort_list, -- cgit v1.2.3 From a4c21acca2be6729ecbe72eda9b08092725b0a77 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:01 -0700 Subject: scsi: lpfc: Fix hdwq sgl locks and irq handling Many of the sgl-per-hdwq paths are locking with spin_lock_irq() and spin_unlock_irq() and may unwittingly raising irq when it shouldn't. Hard deadlocks were seen around lpfc_scsi_prep_cmnd(). Fix by converting the locks to irqsave/irqrestore. Fixes: d79c9e9d4b3d ("scsi: lpfc: Support dynamic unbounded SGL lists on G7 hardware.") Link: https://lore.kernel.org/r/20190922035906.10977-16-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 38 ++++++++++++++++++++++---------------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index ff261c0c738a..6d89dd3dd532 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20444,8 +20444,9 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) struct sli4_hybrid_sgl *allocated_sgl = NULL; struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; struct list_head *buf_list = &hdwq->sgl_list; + unsigned long iflags; - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); if (likely(!list_empty(buf_list))) { /* break off 1 chunk from the sgl_list */ @@ -20457,7 +20458,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) } } else { /* allocate more */ - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, cpu_to_node(smp_processor_id())); if (!tmp) { @@ -20479,7 +20480,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) return NULL; } - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); list_add_tail(&tmp->list_node, &lpfc_buf->dma_sgl_xtra_list); } @@ -20487,7 +20488,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) struct sli4_hybrid_sgl, list_node); - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); return allocated_sgl; } @@ -20511,8 +20512,9 @@ lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) struct sli4_hybrid_sgl *tmp = NULL; struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; struct list_head *buf_list = &hdwq->sgl_list; + unsigned long iflags; - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); if (likely(!list_empty(&lpfc_buf->dma_sgl_xtra_list))) { list_for_each_entry_safe(list_entry, tmp, @@ -20525,7 +20527,7 @@ lpfc_put_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) rc = -EINVAL; } - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); return rc; } @@ -20546,8 +20548,9 @@ lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba, struct list_head *buf_list = &hdwq->sgl_list; struct sli4_hybrid_sgl *list_entry = NULL; struct sli4_hybrid_sgl *tmp = NULL; + unsigned long iflags; - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); /* Free sgl pool */ list_for_each_entry_safe(list_entry, tmp, @@ -20559,7 +20562,7 @@ lpfc_free_sgl_per_hdwq(struct lpfc_hba *phba, kfree(list_entry); } - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); } /** @@ -20583,8 +20586,9 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, struct fcp_cmd_rsp_buf *allocated_buf = NULL; struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; struct list_head *buf_list = &hdwq->cmd_rsp_buf_list; + unsigned long iflags; - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); if (likely(!list_empty(buf_list))) { /* break off 1 chunk from the list */ @@ -20597,7 +20601,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, } } else { /* allocate more */ - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, cpu_to_node(smp_processor_id())); if (!tmp) { @@ -20624,7 +20628,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, tmp->fcp_rsp = (struct fcp_rsp *)((uint8_t *)tmp->fcp_cmnd + sizeof(struct fcp_cmnd)); - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); list_add_tail(&tmp->list_node, &lpfc_buf->dma_cmd_rsp_list); } @@ -20632,7 +20636,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, struct fcp_cmd_rsp_buf, list_node); - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); return allocated_buf; } @@ -20657,8 +20661,9 @@ lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, struct fcp_cmd_rsp_buf *tmp = NULL; struct lpfc_sli4_hdw_queue *hdwq = lpfc_buf->hdwq; struct list_head *buf_list = &hdwq->cmd_rsp_buf_list; + unsigned long iflags; - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); if (likely(!list_empty(&lpfc_buf->dma_cmd_rsp_list))) { list_for_each_entry_safe(list_entry, tmp, @@ -20671,7 +20676,7 @@ lpfc_put_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, rc = -EINVAL; } - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); return rc; } @@ -20692,8 +20697,9 @@ lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, struct list_head *buf_list = &hdwq->cmd_rsp_buf_list; struct fcp_cmd_rsp_buf *list_entry = NULL; struct fcp_cmd_rsp_buf *tmp = NULL; + unsigned long iflags; - spin_lock_irq(&hdwq->hdwq_lock); + spin_lock_irqsave(&hdwq->hdwq_lock, iflags); /* Free cmd_rsp buf pool */ list_for_each_entry_safe(list_entry, tmp, @@ -20706,5 +20712,5 @@ lpfc_free_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, kfree(list_entry); } - spin_unlock_irq(&hdwq->hdwq_lock); + spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); } -- cgit v1.2.3 From 35a635af54ce79881eb35ba20b64dcb1e81b0389 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:02 -0700 Subject: scsi: lpfc: Fix list corruption detected in lpfc_put_sgl_per_hdwq In lpfc_release_io_buf, an lpfc_io_buf is returned to the 'available' pool before any associated sgl or cmd and rsp buffers are returned via their respective 'put' routines. If xri rebalancing occurs and an lpfc_io_buf structure is reused quickly, there may be a race condition between release of old and association of new resources. Re-ordered lpfc_release_io_buf to release sgl and cmd/rsp buffer lists before releasing the lpfc_io_buf structure for re-use. Fixes: d79c9e9d4b3d ("scsi: lpfc: Support dynamic unbounded SGL lists on G7 hardware.") Link: https://lore.kernel.org/r/20190922035906.10977-17-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 6d89dd3dd532..09e275e3bcd8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20138,6 +20138,13 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, lpfc_ncmd->cur_iocbq.wqe_cmpl = NULL; lpfc_ncmd->cur_iocbq.iocb_cmpl = NULL; + if (phba->cfg_xpsgl && !phba->nvmet_support && + !list_empty(&lpfc_ncmd->dma_sgl_xtra_list)) + lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd); + + if (!list_empty(&lpfc_ncmd->dma_cmd_rsp_list)) + lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd); + if (phba->cfg_xri_rebalancing) { if (lpfc_ncmd->expedite) { /* Return to expedite pool */ @@ -20202,13 +20209,6 @@ void lpfc_release_io_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd, spin_unlock_irqrestore(&qp->io_buf_list_put_lock, iflag); } - - if (phba->cfg_xpsgl && !phba->nvmet_support && - !list_empty(&lpfc_ncmd->dma_sgl_xtra_list)) - lpfc_put_sgl_per_hdwq(phba, lpfc_ncmd); - - if (!list_empty(&lpfc_ncmd->dma_cmd_rsp_list)) - lpfc_put_cmd_rsp_buf_per_hdwq(phba, lpfc_ncmd); } /** -- cgit v1.2.3 From d11ed16db698c31663938d004451b11ac6b2b2e1 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:03 -0700 Subject: scsi: lpfc: Update async event logging This patch updates ACQE handling for: - an EEPROM failure error reported by the adapter. - ensures that all data for any ACQE, recognized or not, is logged. - Given that all data is now logged unconditionally, the default case (unrecognized) data can be reduced. Link: https://lore.kernel.org/r/20190922035906.10977-18-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index f70fb7629c82..6095e3cfddd3 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -4261,6 +4261,7 @@ struct lpfc_acqe_sli { #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5 #define LPFC_SLI_EVENT_TYPE_MISCONFIGURED 0x9 #define LPFC_SLI_EVENT_TYPE_REMOTE_DPORT 0xA +#define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE 0x10 }; /* diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 12885b01fa27..a0aa7a555811 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5289,10 +5289,10 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) evt_type = bf_get(lpfc_trailer_type, acqe_sli); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "2901 Async SLI event - Event Data1:x%08x Event Data2:" - "x%08x SLI Event Type:%d\n", + "2901 Async SLI event - Type:%d, Event Data: x%08x " + "x%08x x%08x x%08x\n", evt_type, acqe_sli->event_data1, acqe_sli->event_data2, - evt_type); + acqe_sli->reserved, acqe_sli->trailer); port_name = phba->Port[0]; if (port_name == 0x00) @@ -5439,11 +5439,16 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "Event Data1:x%08x Event Data2: x%08x\n", acqe_sli->event_data1, acqe_sli->event_data2); break; + case LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE: + /* EEPROM failure. No driver action is required */ + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2518 EEPROM failure - " + "Event Data1: x%08x Event Data2: x%08x\n", + acqe_sli->event_data1, acqe_sli->event_data2); + break; default: lpfc_printf_log(phba, KERN_INFO, LOG_SLI, - "3193 Async SLI event - Event Data1:x%08x Event Data2:" - "x%08x SLI Event Type:%d\n", - acqe_sli->event_data1, acqe_sli->event_data2, + "3193 Unrecognized SLI event, type: 0x%x", evt_type); break; } -- cgit v1.2.3 From 412e7375e48fc7dc660da99c4b699e4475873f7b Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:04 -0700 Subject: scsi: lpfc: Complete removal of FCoE T10 PI support on SLI-4 adapters T10 PI support on SLI-4-based FCoE adapters is not supported. A prior commit in the 12.4.0.0 stream added device recognition that would prevent T10 PI enablement. However, it didn't contain a complete device list. Thus some SLI-4 FCoE adapters still had T10 PI enabled. Fix by expanding the device list that identifies FCoE devices. Link: https://lore.kernel.org/r/20190922035906.10977-19-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 79a192479755..e4c89e56c632 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -7083,11 +7083,22 @@ struct fc_function_template lpfc_vport_transport_functions = { static void lpfc_get_hba_function_mode(struct lpfc_hba *phba) { - /* If it's a SkyHawk FCoE adapter */ - if (phba->pcidev->device == PCI_DEVICE_ID_SKYHAWK) + /* If the adapter supports FCoE mode */ + switch (phba->pcidev->device) { + case PCI_DEVICE_ID_SKYHAWK: + case PCI_DEVICE_ID_SKYHAWK_VF: + case PCI_DEVICE_ID_LANCER_FCOE: + case PCI_DEVICE_ID_LANCER_FCOE_VF: + case PCI_DEVICE_ID_ZEPHYR_DCSP: + case PCI_DEVICE_ID_HORNET: + case PCI_DEVICE_ID_TIGERSHARK: + case PCI_DEVICE_ID_TOMCAT: phba->hba_flag |= HBA_FCOE_MODE; - else + break; + default: + /* for others, clear the flag */ phba->hba_flag &= ~HBA_FCOE_MODE; + } } /** -- cgit v1.2.3 From ff349bca17716f310697b619b8cf9b926e852ba9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:05 -0700 Subject: scsi: lpfc: cleanup: remove unused fcp_txcmlpq_cnt Local variable fcp_txcmplq_cnt is initialized to 0 and then displayed in lpfc driver message 0387. Presumed residual (or unused) code from previous commit. Removed fcp_txcmplq_cnt. Link: https://lore.kernel.org/r/20190922035906.10977-20-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 09e275e3bcd8..379c37451645 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13260,7 +13260,6 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, struct lpfc_sli_ring *pring = cq->pring; int txq_cnt = 0; int txcmplq_cnt = 0; - int fcp_txcmplq_cnt = 0; /* Check for response status */ if (unlikely(bf_get(lpfc_wcqe_c_status, wcqe))) { @@ -13282,9 +13281,8 @@ lpfc_sli4_sp_handle_els_wcqe(struct lpfc_hba *phba, struct lpfc_queue *cq, txcmplq_cnt++; lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "0387 NO IOCBQ data: txq_cnt=%d iocb_cnt=%d " - "fcp_txcmplq_cnt=%d, els_txcmplq_cnt=%d\n", + "els_txcmplq_cnt=%d\n", txq_cnt, phba->iocb_cnt, - fcp_txcmplq_cnt, txcmplq_cnt); return false; } -- cgit v1.2.3 From 5f9d423a725a86505ba42ed026c9a827410a69cd Mon Sep 17 00:00:00 2001 From: James Smart Date: Sat, 21 Sep 2019 20:59:06 -0700 Subject: scsi: lpfc: Update lpfc version to 12.4.0.1 Update lpfc version to 12.4.0.1 Link: https://lore.kernel.org/r/20190922035906.10977-21-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index b8aae31ffda3..d8839d95f7fe 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 "12.4.0.0" +#define LPFC_DRIVER_VERSION "12.4.0.1" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From d04a6edfed0b2e99d9a8385503737944db3d5649 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:38 -0400 Subject: scsi: mpt3sas: Register trace buffer based on NVDATA settings Currently if user wishes to enable the host trace buffer during driver load time, then user has to load the driver with module parameter 'diag_buffer_enable' set to one. Alternatively now the user can enable host trace buffer by enabling the following fields in manufacturing page11 in NVDATA (nvdata xml is used while building HBA firmware image): * HostTraceBufferMaxSizeKB - Maximum trace buffer size in KB that host can allocate, * HostTraceBufferMinSizeKB - Minimum trace buffer size in KB atleast host should allocate, * HostTraceBufferDecrementSizeKB - size by which host can reduce from buffer size and retry the buffer allocation when buffer allocation failed with previous calculated buffer size. The driver will register the trace buffer automatically without any module parameter during boot time when above fields are enabled in manufacturing page11 in HBA firmware. Driver follows the following algorithm for enabling the host trace buffer during driver load time: * If user has loaded the driver with module parameter 'diag_buffer_enable' set to one, then driver allocates 2MB buffer and registers this buffer with HBA firmware for capturing the firmware trace logs. * Else driver reads manufacture page11 data and checks whether HostTraceBufferMaxSizeKB filed is zero or not? - If HostTraceBufferMaxSizeKB is non-zero then driver tries to allocate HostTraceBufferMaxSizeKB size of memory. If the buffer allocation is successful, then it will register this buffer with HBA firmware, else in a loop the driver will try again by reducing the current buffer size with HostTraceBufferDecrementSizeKB size until memory allocation is successful or buffer size falls below HostTraceBufferMinSizeKB. If the memory allocation is successful, then the buffer will be registered with the firmware. Else, if the buffer size falls below the HostTraceBufferMinSizeKB, then driver won't register trace buffer with HBA firmware. - If HostTraceBufferMaxSizeKB is zero, then driver won't register trace buffer with HBA firmware. Link: https://lore.kernel.org/r/1568379890-18347-2-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 9 +++-- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 71 ++++++++++++++++++++++++++++++++++-- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 + 3 files changed, 75 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index faca0a5e71f8..a501c254baef 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -391,9 +391,12 @@ struct Mpi2ManufacturingPage11_t { u8 Reserved6; /* 2Fh */ __le32 Reserved7[7]; /* 30h - 4Bh */ u8 NVMeAbortTO; /* 4Ch */ - u8 Reserved8; /* 4Dh */ - u16 Reserved9; /* 4Eh */ - __le32 Reserved10[4]; /* 50h - 60h */ + u8 NumPerDevEvents; /* 4Dh */ + u8 HostTraceBufferDecrementSizeKB; /* 4Eh */ + u8 HostTraceBufferFlags; /* 4Fh */ + u16 HostTraceBufferMaxSizeKB; /* 50h */ + u16 HostTraceBufferMinSizeKB; /* 52h */ + __le32 Reserved10[2]; /* 54h - 5Bh */ }; /** diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 7d696952b376..285edd73864b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -1669,6 +1669,10 @@ void mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) { struct mpt3_diag_register diag_register; + u32 ret_val; + u32 trace_buff_size = ioc->manu_pg11.HostTraceBufferMaxSizeKB<<10; + u32 min_trace_buff_size = 0; + u32 decr_trace_buff_size = 0; memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); @@ -1677,10 +1681,61 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) ioc->diag_trigger_master.MasterData = (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - /* register for 2MB buffers */ - diag_register.requested_buffer_size = 2 * (1024 * 1024); diag_register.unique_id = 0x7075900; - _ctl_diag_register_2(ioc, &diag_register); + + if (trace_buff_size != 0) { + diag_register.requested_buffer_size = trace_buff_size; + min_trace_buff_size = + ioc->manu_pg11.HostTraceBufferMinSizeKB<<10; + decr_trace_buff_size = + ioc->manu_pg11.HostTraceBufferDecrementSizeKB<<10; + + if (min_trace_buff_size > trace_buff_size) { + /* The buff size is not set correctly */ + ioc_err(ioc, + "Min Trace Buff size (%d KB) greater than Max Trace Buff size (%d KB)\n", + min_trace_buff_size>>10, + trace_buff_size>>10); + ioc_err(ioc, + "Using zero Min Trace Buff Size\n"); + min_trace_buff_size = 0; + } + + if (decr_trace_buff_size == 0) { + /* + * retry the min size if decrement + * is not available. + */ + decr_trace_buff_size = + trace_buff_size - min_trace_buff_size; + } + } else { + /* register for 2MB buffers */ + diag_register.requested_buffer_size = 2 * (1024 * 1024); + } + + do { + ret_val = _ctl_diag_register_2(ioc, &diag_register); + + if (ret_val == -ENOMEM && min_trace_buff_size && + (trace_buff_size - decr_trace_buff_size) >= + min_trace_buff_size) { + /* adjust the buffer size */ + trace_buff_size -= decr_trace_buff_size; + diag_register.requested_buffer_size = + trace_buff_size; + } else + break; + } while (true); + + if (ret_val == -ENOMEM) + ioc_err(ioc, + "Cannot allocate trace buffer memory. Last memory tried = %d KB\n", + diag_register.requested_buffer_size>>10); + else if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] + & MPT3_DIAG_BUFFER_IS_REGISTERED) + ioc_err(ioc, "Trace buffer memory %d KB allocated\n", + diag_register.requested_buffer_size>>10); } if (bits_to_register & 2) { @@ -3130,7 +3185,15 @@ host_trace_buffer_enable_store(struct device *cdev, memset(&diag_register, 0, sizeof(struct mpt3_diag_register)); ioc_info(ioc, "posting host trace buffers\n"); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - diag_register.requested_buffer_size = (1024 * 1024); + + if (ioc->manu_pg11.HostTraceBufferMaxSizeKB != 0 && + ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0) { + /* post the same buffer allocated previously */ + diag_register.requested_buffer_size = + ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE]; + } else + diag_register.requested_buffer_size = (1024 * 1024); + diag_register.unique_id = 0x7075900; ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; _ctl_diag_register_2(ioc, &diag_register); diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index c8e512ba6d39..3f0797e6f941 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -10193,6 +10193,8 @@ scsih_scan_start(struct Scsi_Host *shost) int rc; if (diag_buffer_enable != -1 && diag_buffer_enable != 0) mpt3sas_enable_diag_buffer(ioc, diag_buffer_enable); + else if (ioc->manu_pg11.HostTraceBufferMaxSizeKB != 0) + mpt3sas_enable_diag_buffer(ioc, 1); if (disable_discovery > 0) return; -- cgit v1.2.3 From 4bc50dc1afb7b77dfc80a1f8f0742b14d6f6e376 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:39 -0400 Subject: scsi: mpt3sas: Display message before releasing diag buffer Display message before releasing the diag buffer so that user knows which event caused the release of diag buffer. Releasing of diag buffer means HBA firmware stops posting the firmware logs on the registered diag buffer. Link: https://lore.kernel.org/r/1568379890-18347-3-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 7 +++++++ drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c | 12 +++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 285edd73864b..76ca416a3806 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -466,6 +466,13 @@ void mpt3sas_ctl_pre_reset_handler(struct MPT3SAS_ADAPTER *ioc) if ((ioc->diag_buffer_status[i] & MPT3_DIAG_BUFFER_IS_RELEASED)) continue; + + /* + * add a log message to indicate the release + */ + ioc_info(ioc, + "%s: Releasing the trace buffer due to adapter reset.", + __func__); mpt3sas_send_diag_release(ioc, i, &issue_reset); } } diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c index 6ac453fd5937..8ec9bab20ec4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c +++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c @@ -113,15 +113,21 @@ mpt3sas_process_trigger_data(struct MPT3SAS_ADAPTER *ioc, struct SL_WH_TRIGGERS_EVENT_DATA_T *event_data) { u8 issue_reset = 0; + u32 *trig_data = (u32 *)&event_data->u.master; dTriggerDiagPrintk(ioc, ioc_info(ioc, "%s: enter\n", __func__)); /* release the diag buffer trace */ if ((ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & MPT3_DIAG_BUFFER_IS_RELEASED) == 0) { - dTriggerDiagPrintk(ioc, - ioc_info(ioc, "%s: release trace diag buffer\n", - __func__)); + /* + * add a log message so that user knows which event caused + * the release + */ + ioc_info(ioc, + "%s: Releasing the trace buffer. Trigger_Type 0x%08x, Data[0] 0x%08x, Data[1] 0x%08x\n", + __func__, event_data->trigger_type, + trig_data[0], trig_data[1]); mpt3sas_send_diag_release(ioc, MPI2_DIAG_BUF_TYPE_TRACE, &issue_reset); } -- cgit v1.2.3 From 782b281883caf70289ba6a186af29441a117d23e Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:40 -0400 Subject: scsi: mpt3sas: Fix clear pending bit in ioctl status When user issues diag register command from application with required size, and if driver unable to allocate the memory, then it will fail the register command. While failing the register command, driver is not currently clearing MPT3_CMD_PENDING bit in ctl_cmds.status variable which was set before trying to allocate the memory. As this bit is set, subsequent register command will be failed with BUSY status even when user wants to register the trace buffer will less memory. Clear MPT3_CMD_PENDING bit in ctl_cmds.status before returning the diag register command with no memory status. Link: https://lore.kernel.org/r/1568379890-18347-4-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 76ca416a3806..a195caed8d9b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -1591,7 +1591,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, ioc_err(ioc, "%s: failed allocating memory for diag buffers, requested size(%d)\n", __func__, request_data_sz); mpt3sas_base_free_smid(ioc, smid); - return -ENOMEM; + rc = -ENOMEM; + goto out; } ioc->diag_buffer[buffer_type] = request_data; ioc->diag_buffer_sz[buffer_type] = request_data_sz; -- cgit v1.2.3 From 764f472ba4a7a0c18107ebfbe1a9f1f5f5a1e411 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:41 -0400 Subject: scsi: mpt3sas: Free diag buffer without any status check Memory leak can happen when diag buffer is released but not unregistered (where buffer is deallocated) by the user. During module unload time driver is not deallocating the buffer if the buffer is in released state. Deallocate the diag buffer during module unload time without any diag buffer status checks. Link: https://lore.kernel.org/r/1568379890-18347-5-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index a195caed8d9b..9b37a3296cda 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -3773,12 +3773,6 @@ mpt3sas_ctl_exit(ushort hbas_to_enumerate) for (i = 0; i < MPI2_DIAG_BUF_TYPE_COUNT; i++) { if (!ioc->diag_buffer[i]) continue; - if (!(ioc->diag_buffer_status[i] & - MPT3_DIAG_BUFFER_IS_REGISTERED)) - continue; - if ((ioc->diag_buffer_status[i] & - MPT3_DIAG_BUFFER_IS_RELEASED)) - continue; dma_free_coherent(&ioc->pdev->dev, ioc->diag_buffer_sz[i], ioc->diag_buffer[i], -- cgit v1.2.3 From 08e7378ee331a803cfdd91c512a3dea040f1da79 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:42 -0400 Subject: scsi: mpt3sas: Maintain owner of buffer through UniqueID Application A has registered a diag buffer and looking for particular event to happen to release & read the trace buffer. Meanwhile application B has unregistered the diag buffer and now Application A can't get the required diag buffer. So proper diag buffer ownership is missing. Each application has to maintain its own Unique ID. Now driver has to save the Application's UniqueID for each diag buffer type when diag buffer is registered. And driver has to allow 'release', 'read' & 'unregister' diag commands only if application's UniqueID matches with saved UniqueID for the corresponding diag buffer type. When diag buffer is registered by the driver, then the UniqueID saved by the driver is "BRCM" (i.e. 0x4252434D) for SAS3 and above generations HBA devices. For SAS2 HBAs, driver keeps the legacy UniqueID 0x07075900 for maintaining compatibility with the legacy SAS2 application and this improvement won't be applicable for SAS2 HBA devices. Any application can own the buffer registered by the driver by sending diag register request to driver with same buffer type and size (Application can get the buffer size by sending 'query' command). Then driver changes the ownership of the buffer by saving application's UniqueID for that corresponding buffer type. Also, application can re-register the diag buffer with same size without un-registering it, but diag buffer should be released before re-registering it. By allowing this, driver no need to deallocate and allocate a new buffer for re-register command, same buffer can be re-used. Link: https://lore.kernel.org/r/1568379890-18347-6-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 114 ++++++++++++++++++++++++++++++++++--- drivers/scsi/mpt3sas/mpt3sas_ctl.h | 8 +++ 2 files changed, 113 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 9b37a3296cda..a14ff88db54b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -1491,6 +1491,26 @@ _ctl_diag_capability(struct MPT3SAS_ADAPTER *ioc, u8 buffer_type) return rc; } +/** + * _ctl_diag_get_bufftype - return diag buffer type + * either TRACE, SNAPSHOT, or EXTENDED + * @ioc: per adapter object + * @unique_id: specifies the unique_id for the buffer + * + * returns MPT3_DIAG_UID_NOT_FOUND if the id not found + */ +static u8 +_ctl_diag_get_bufftype(struct MPT3SAS_ADAPTER *ioc, u32 unique_id) +{ + u8 index; + + for (index = 0; index < MPI2_DIAG_BUF_TYPE_COUNT; index++) { + if (ioc->unique_id[index] == unique_id) + return index; + } + + return MPT3_DIAG_UID_NOT_FOUND; +} /** * _ctl_diag_register_2 - wrapper for registering diag buffer support @@ -1538,11 +1558,65 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, return -EPERM; } + if (diag_register->unique_id == 0) { + ioc_err(ioc, + "%s: Invalid UID(0x%08x), buffer_type(0x%02x)\n", __func__, + diag_register->unique_id, buffer_type); + return -EINVAL; + } + if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_REGISTERED) { - ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n", - __func__, buffer_type); - return -EINVAL; + /* + * If driver posts buffer initially, then an application wants + * to Register that buffer (own it) without Releasing first, + * the application Register command MUST have the same buffer + * type and size in the Register command (obtained from the + * Query command). Otherwise that Register command will be + * failed. If the application has released the buffer but wants + * to re-register it, it should be allowed as long as the + * Unique-Id/Size match. + */ + + if (ioc->unique_id[buffer_type] == MPT3DIAGBUFFUNIQUEID && + ioc->diag_buffer_sz[buffer_type] == + diag_register->requested_buffer_size) { + + if (!(ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_RELEASED)) { + dctlprintk(ioc, ioc_info(ioc, + "%s: diag_buffer (%d) ownership changed. old-ID(0x%08x), new-ID(0x%08x)\n", + __func__, buffer_type, + ioc->unique_id[buffer_type], + diag_register->unique_id)); + + /* + * Application wants to own the buffer with + * the same size. + */ + ioc->unique_id[buffer_type] = + diag_register->unique_id; + rc = 0; /* success */ + goto out; + } + } else if (ioc->unique_id[buffer_type] != + MPT3DIAGBUFFUNIQUEID) { + if (ioc->unique_id[buffer_type] != + diag_register->unique_id || + ioc->diag_buffer_sz[buffer_type] != + diag_register->requested_buffer_size || + !(ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_RELEASED)) { + ioc_err(ioc, + "%s: already has a registered buffer for buffer_type(0x%02x)\n", + __func__, buffer_type); + return -EINVAL; + } + } else { + ioc_err(ioc, "%s: already has a registered buffer for buffer_type(0x%02x)\n", + __func__, buffer_type); + return -EINVAL; + } } if (diag_register->requested_buffer_size % 4) { @@ -1689,7 +1763,9 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) ioc->diag_trigger_master.MasterData = (MASTER_TRIGGER_FW_FAULT + MASTER_TRIGGER_ADAPTER_RESET); diag_register.buffer_type = MPI2_DIAG_BUF_TYPE_TRACE; - diag_register.unique_id = 0x7075900; + diag_register.unique_id = + (ioc->hba_mpi_version_belonged == MPI2_VERSION) ? + (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID); if (trace_buff_size != 0) { diag_register.requested_buffer_size = trace_buff_size; @@ -1815,7 +1891,13 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) dctlprintk(ioc, ioc_info(ioc, "%s\n", __func__)); - buffer_type = karg.unique_id & 0x000000ff; + buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id); + if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) { + ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n", + __func__, karg.unique_id); + return -EINVAL; + } + if (!_ctl_diag_capability(ioc, buffer_type)) { ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", __func__, buffer_type); @@ -1899,7 +1981,7 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EINVAL; } - if (karg.unique_id & 0xffffff00) { + if (karg.unique_id) { if (karg.unique_id != ioc->unique_id[buffer_type]) { ioc_err(ioc, "%s: unique_id(0x%08x) is not registered\n", __func__, karg.unique_id); @@ -2065,7 +2147,13 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) dctlprintk(ioc, ioc_info(ioc, "%s\n", __func__)); - buffer_type = karg.unique_id & 0x000000ff; + buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id); + if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) { + ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n", + __func__, karg.unique_id); + return -EINVAL; + } + if (!_ctl_diag_capability(ioc, buffer_type)) { ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", __func__, buffer_type); @@ -2149,7 +2237,13 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) dctlprintk(ioc, ioc_info(ioc, "%s\n", __func__)); - buffer_type = karg.unique_id & 0x000000ff; + buffer_type = _ctl_diag_get_bufftype(ioc, karg.unique_id); + if (buffer_type == MPT3_DIAG_UID_NOT_FOUND) { + ioc_err(ioc, "%s: buffer with unique_id(0x%08x) not found\n", + __func__, karg.unique_id); + return -EINVAL; + } + if (!_ctl_diag_capability(ioc, buffer_type)) { ioc_err(ioc, "%s: doesn't have capability for buffer_type(0x%02x)\n", __func__, buffer_type); @@ -3202,7 +3296,9 @@ host_trace_buffer_enable_store(struct device *cdev, } else diag_register.requested_buffer_size = (1024 * 1024); - diag_register.unique_id = 0x7075900; + diag_register.unique_id = + (ioc->hba_mpi_version_belonged == MPI2_VERSION) ? + (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID); ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; _ctl_diag_register_2(ioc, &diag_register); } else if (!strcmp(str, "release")) { diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index 18b46faef6f1..d1a6ab148448 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -95,6 +95,14 @@ #define MPT3DIAGREADBUFFER _IOWR(MPT3_MAGIC_NUMBER, 30, \ struct mpt3_diag_read_buffer) +/* Trace Buffer default UniqueId */ +#define MPT2DIAGBUFFUNIQUEID (0x07075900) +#define MPT3DIAGBUFFUNIQUEID (0x4252434D) + +/* UID not found */ +#define MPT3_DIAG_UID_NOT_FOUND (0xFF) + + /** * struct mpt3_ioctl_header - main header structure * @ioc_number - IOC unit number -- cgit v1.2.3 From dd180e4eedfd85b80020a6fd566601f4765a9d69 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:43 -0400 Subject: scsi: mpt3sas: clear release bit when buffer reregistered Clear MPT3_DIAG_BUFFER_IS_RELEASED bit once diag buffer is re-registered after reading the buffer, else driver won't release the buffer and return the 'diag release' command with -EINVAL status saying that buffer is already released. Link: https://lore.kernel.org/r/1568379890-18347-7-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index a14ff88db54b..504e035a90c4 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -2367,6 +2367,8 @@ _ctl_diag_read_buffer(struct MPT3SAS_ADAPTER *ioc, void __user *arg) if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { ioc->diag_buffer_status[buffer_type] |= MPT3_DIAG_BUFFER_IS_REGISTERED; + ioc->diag_buffer_status[buffer_type] &= + ~MPT3_DIAG_BUFFER_IS_RELEASED; dctlprintk(ioc, ioc_info(ioc, "%s: success\n", __func__)); } else { ioc_info(ioc, "%s: ioc_status(0x%04x) log_info(0x%08x)\n", -- cgit v1.2.3 From a066f4c31359d07b1a2c5144b4b9a29901365fd0 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:44 -0400 Subject: scsi: mpt3sas: Reuse diag buffer allocated at load time The diag buffer which is allocated during driver load time or through sysfs parameter is marked as driver allocated diag buffer. MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED bit will be set for this buffer. This buffer won't be de-allocated even when application issues unregister command, driver just clears the registered status bit. Same buffer will be reused while re-registering the same diag buffer type by any application. While re-registering the same diag buffer type application has to register with the same size that the buffer was allocated during driver load time. This buffer size can be read by the application by issuing diag 'query' command. This always makes sure that the memory is available for applications for collecting the firmware logs. Only thing is that this won't allow the application to re-register the diag buffer with different size, but the buffer size which is allocated during driver load time will be enough for most of the cases for collecting the firmware logs. Link: https://lore.kernel.org/r/1568379890-18347-8-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 1 + drivers/scsi/mpt3sas/mpt3sas_ctl.c | 88 ++++++++++++++++++++++++++++--------- drivers/scsi/mpt3sas/mpt3sas_ctl.h | 1 + 3 files changed, 69 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index a501c254baef..eaeb71f9b546 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -303,6 +303,7 @@ struct mpt3sas_nvme_cmd { #define MPT3_DIAG_BUFFER_IS_REGISTERED (0x01) #define MPT3_DIAG_BUFFER_IS_RELEASED (0x02) #define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) +#define MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED (0x08) /* * HP HBA branding diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 504e035a90c4..b5492f1a73a0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -1617,6 +1617,19 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, __func__, buffer_type); return -EINVAL; } + } else if (ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) { + + if (ioc->unique_id[buffer_type] != MPT3DIAGBUFFUNIQUEID || + ioc->diag_buffer_sz[buffer_type] != + diag_register->requested_buffer_size) { + + ioc_err(ioc, + "%s: already a buffer is allocated for buffer_type(0x%02x) of size %d bytes, so please try registering again with same size\n", + __func__, buffer_type, + ioc->diag_buffer_sz[buffer_type]); + return -EINVAL; + } } if (diag_register->requested_buffer_size % 4) { @@ -1641,7 +1654,8 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, request_data = ioc->diag_buffer[buffer_type]; request_data_sz = diag_register->requested_buffer_size; ioc->unique_id[buffer_type] = diag_register->unique_id; - ioc->diag_buffer_status[buffer_type] = 0; + ioc->diag_buffer_status[buffer_type] &= + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; memcpy(ioc->product_specific[buffer_type], diag_register->product_specific, MPT3_PRODUCT_SPECIFIC_DWORDS); ioc->diagnostic_flags[buffer_type] = diag_register->diagnostic_flags; @@ -1731,9 +1745,12 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, out: - if (rc && request_data) + if (rc && request_data) { dma_free_coherent(&ioc->pdev->dev, request_data_sz, request_data, request_data_dma); + ioc->diag_buffer_status[buffer_type] &= + ~MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; + } ioc->ctl_cmds.status = MPT3_CMD_NOT_USED; return rc; @@ -1817,9 +1834,14 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) "Cannot allocate trace buffer memory. Last memory tried = %d KB\n", diag_register.requested_buffer_size>>10); else if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] - & MPT3_DIAG_BUFFER_IS_REGISTERED) + & MPT3_DIAG_BUFFER_IS_REGISTERED) { ioc_err(ioc, "Trace buffer memory %d KB allocated\n", diag_register.requested_buffer_size>>10); + if (ioc->hba_mpi_version_belonged != MPI2_VERSION) + ioc->diag_buffer_status[ + MPI2_DIAG_BUF_TYPE_TRACE] |= + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; + } } if (bits_to_register & 2) { @@ -1930,12 +1952,19 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -ENOMEM; } - request_data_sz = ioc->diag_buffer_sz[buffer_type]; - request_data_dma = ioc->diag_buffer_dma[buffer_type]; - dma_free_coherent(&ioc->pdev->dev, request_data_sz, - request_data, request_data_dma); - ioc->diag_buffer[buffer_type] = NULL; - ioc->diag_buffer_status[buffer_type] = 0; + if (ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) { + ioc->unique_id[buffer_type] = MPT3DIAGBUFFUNIQUEID; + ioc->diag_buffer_status[buffer_type] &= + ~MPT3_DIAG_BUFFER_IS_REGISTERED; + } else { + request_data_sz = ioc->diag_buffer_sz[buffer_type]; + request_data_dma = ioc->diag_buffer_dma[buffer_type]; + dma_free_coherent(&ioc->pdev->dev, request_data_sz, + request_data, request_data_dma); + ioc->diag_buffer[buffer_type] = NULL; + ioc->diag_buffer_status[buffer_type] = 0; + } return 0; } @@ -1974,11 +2003,14 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -EPERM; } - if ((ioc->diag_buffer_status[buffer_type] & - MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { - ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", - __func__, buffer_type); - return -EINVAL; + if (!(ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) { + if ((ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_REGISTERED) == 0) { + ioc_err(ioc, "%s: buffer_type(0x%02x) is not registered\n", + __func__, buffer_type); + return -EINVAL; + } } if (karg.unique_id) { @@ -1996,13 +2028,17 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) return -ENOMEM; } - if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_RELEASED) - karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED | - MPT3_APP_FLAGS_BUFFER_VALID); - else - karg.application_flags = (MPT3_APP_FLAGS_APP_OWNED | - MPT3_APP_FLAGS_BUFFER_VALID | - MPT3_APP_FLAGS_FW_BUFFER_ACCESS); + if ((ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_REGISTERED)) + karg.application_flags |= MPT3_APP_FLAGS_BUFFER_VALID; + + if (!(ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_RELEASED)) + karg.application_flags |= MPT3_APP_FLAGS_FW_BUFFER_ACCESS; + + if (!(ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) + karg.application_flags |= MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC; for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) karg.product_specific[i] = @@ -3303,6 +3339,16 @@ host_trace_buffer_enable_store(struct device *cdev, (MPT2DIAGBUFFUNIQUEID):(MPT3DIAGBUFFUNIQUEID); ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] = 0; _ctl_diag_register_2(ioc, &diag_register); + if (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT3_DIAG_BUFFER_IS_REGISTERED) { + ioc_info(ioc, + "Trace buffer %d KB allocated through sysfs\n", + diag_register.requested_buffer_size>>10); + if (ioc->hba_mpi_version_belonged != MPI2_VERSION) + ioc->diag_buffer_status[ + MPI2_DIAG_BUF_TYPE_TRACE] |= + MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED; + } } else if (!strcmp(str, "release")) { /* exit out if host buffers are already released */ if (!ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE]) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h index d1a6ab148448..0f7aa4ddade0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h @@ -318,6 +318,7 @@ struct mpt3_ioctl_btdh_mapping { #define MPT3_APP_FLAGS_APP_OWNED (0x0001) #define MPT3_APP_FLAGS_BUFFER_VALID (0x0002) #define MPT3_APP_FLAGS_FW_BUFFER_ACCESS (0x0004) +#define MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC (0x0008) /* flags for mpt3_diag_read_buffer */ #define MPT3_FLAGS_REREGISTER (0x0001) -- cgit v1.2.3 From a8a6cbcd038de4ee3722c17edd7a4d84ce423f7d Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:45 -0400 Subject: scsi: mpt3sas: Add app owned flag support for diag buffer Added a new status flag named MPT3_DIAG_BUFFER_IS_APP_OWNED and it will set whenever application registers the diag buffer & it will be cleared when application unregisters the buffer. When this flag is enabled, and if application issues diag buffer register command without releasing the buffer, then register command will be failed with -EINVAL status by saying that this buffer is already registered by the application. When user issues a trace buffer register command through sysfs parameter, and if trace buffer is in released stated but not yet unregistered by the application which was owning it, then driver will unregister the buffer by itself and freshly register the 1MB sized trace buffer with the HBA firmware. Link: https://lore.kernel.org/r/1568379890-18347-9-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 1 + drivers/scsi/mpt3sas/mpt3sas_ctl.c | 43 ++++++++++++++++++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index eaeb71f9b546..91f663688bf0 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -304,6 +304,7 @@ struct mpt3sas_nvme_cmd { #define MPT3_DIAG_BUFFER_IS_RELEASED (0x02) #define MPT3_DIAG_BUFFER_IS_DIAG_RESET (0x04) #define MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED (0x08) +#define MPT3_DIAG_BUFFER_IS_APP_OWNED (0x10) /* * HP HBA branding diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index b5492f1a73a0..62e878d6a52b 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -1565,6 +1565,16 @@ _ctl_diag_register_2(struct MPT3SAS_ADAPTER *ioc, return -EINVAL; } + if ((ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_APP_OWNED) && + !(ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_RELEASED)) { + ioc_err(ioc, + "%s: buffer_type(0x%02x) is already registered by application with UID(0x%08x)\n", + __func__, buffer_type, ioc->unique_id[buffer_type]); + return -EINVAL; + } + if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_REGISTERED) { /* @@ -1884,6 +1894,12 @@ _ctl_diag_register(struct MPT3SAS_ADAPTER *ioc, void __user *arg) } rc = _ctl_diag_register_2(ioc, &karg); + + if (!rc && (ioc->diag_buffer_status[karg.buffer_type] & + MPT3_DIAG_BUFFER_IS_REGISTERED)) + ioc->diag_buffer_status[karg.buffer_type] |= + MPT3_DIAG_BUFFER_IS_APP_OWNED; + return rc; } @@ -1955,6 +1971,8 @@ _ctl_diag_unregister(struct MPT3SAS_ADAPTER *ioc, void __user *arg) if (ioc->diag_buffer_status[buffer_type] & MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED) { ioc->unique_id[buffer_type] = MPT3DIAGBUFFUNIQUEID; + ioc->diag_buffer_status[buffer_type] &= + ~MPT3_DIAG_BUFFER_IS_APP_OWNED; ioc->diag_buffer_status[buffer_type] &= ~MPT3_DIAG_BUFFER_IS_REGISTERED; } else { @@ -2040,6 +2058,10 @@ _ctl_diag_query(struct MPT3SAS_ADAPTER *ioc, void __user *arg) MPT3_DIAG_BUFFER_IS_DRIVER_ALLOCATED)) karg.application_flags |= MPT3_APP_FLAGS_DYNAMIC_BUFFER_ALLOC; + if ((ioc->diag_buffer_status[buffer_type] & + MPT3_DIAG_BUFFER_IS_APP_OWNED)) + karg.application_flags |= MPT3_APP_FLAGS_APP_OWNED; + for (i = 0; i < MPT3_PRODUCT_SPECIFIC_DWORDS; i++) karg.product_specific[i] = ioc->product_specific[buffer_type][i]; @@ -3331,8 +3353,27 @@ host_trace_buffer_enable_store(struct device *cdev, /* post the same buffer allocated previously */ diag_register.requested_buffer_size = ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE]; - } else + } else { + /* + * Free the diag buffer memory which was previously + * allocated by an application. + */ + if ((ioc->diag_buffer_sz[MPI2_DIAG_BUF_TYPE_TRACE] != 0) + && + (ioc->diag_buffer_status[MPI2_DIAG_BUF_TYPE_TRACE] & + MPT3_DIAG_BUFFER_IS_APP_OWNED)) { + pci_free_consistent(ioc->pdev, + ioc->diag_buffer_sz[ + MPI2_DIAG_BUF_TYPE_TRACE], + ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE], + ioc->diag_buffer_dma[ + MPI2_DIAG_BUF_TYPE_TRACE]); + ioc->diag_buffer[MPI2_DIAG_BUF_TYPE_TRACE] = + NULL; + } + diag_register.requested_buffer_size = (1024 * 1024); + } diag_register.unique_id = (ioc->hba_mpi_version_belonged == MPI2_VERSION) ? -- cgit v1.2.3 From 29f571f8b4cc652cae9244630f714a610549d301 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:46 -0400 Subject: scsi: mpt3sas: Fail release cmnd if diag buffer is released Return the diag buffer release command with -EINVAL status if the buffer is already released. Link: https://lore.kernel.org/r/1568379890-18347-10-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 62e878d6a52b..9267ffecedcd 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -2235,7 +2235,7 @@ _ctl_diag_release(struct MPT3SAS_ADAPTER *ioc, void __user *arg) MPT3_DIAG_BUFFER_IS_RELEASED) { ioc_err(ioc, "%s: buffer_type(0x%02x) is already released\n", __func__, buffer_type); - return 0; + return -EINVAL; } request_data = ioc->diag_buffer[buffer_type]; -- cgit v1.2.3 From b06ff10249036eec74fa8565503ac40d0ee92213 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:47 -0400 Subject: scsi: mpt3sas: Use Component img header to get Package ver The firmware image layout has been changed for Aero controllers. All compatible HBAs have to get Firmware Package version from Component Image Header layout. The Signature field in FW header is set to 0xEB000042 for products compatible with Component Image Header. For compatible controllers, driver fetches firmware package version from ApplicationSpecific field of Component Image Header. Link: https://lore.kernel.org/r/1568379890-18347-11-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index fea3cb6a090b..5f5330352646 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -4242,10 +4242,12 @@ _base_display_OEMs_branding(struct MPT3SAS_ADAPTER *ioc) static int _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) { - Mpi2FWImageHeader_t *FWImgHdr; + Mpi2FWImageHeader_t *fw_img_hdr; + Mpi26ComponentImageHeader_t *cmp_img_hdr; Mpi25FWUploadRequest_t *mpi_request; Mpi2FWUploadReply_t mpi_reply; int r = 0; + u32 package_version = 0; void *fwpkg_data = NULL; dma_addr_t fwpkg_data_dma; u16 smid, ioc_status; @@ -4302,14 +4304,26 @@ _base_display_fwpkg_version(struct MPT3SAS_ADAPTER *ioc) ioc_status = le16_to_cpu(mpi_reply.IOCStatus) & MPI2_IOCSTATUS_MASK; if (ioc_status == MPI2_IOCSTATUS_SUCCESS) { - FWImgHdr = (Mpi2FWImageHeader_t *)fwpkg_data; - if (FWImgHdr->PackageVersion.Word) { - ioc_info(ioc, "FW Package Version (%02d.%02d.%02d.%02d)\n", - FWImgHdr->PackageVersion.Struct.Major, - FWImgHdr->PackageVersion.Struct.Minor, - FWImgHdr->PackageVersion.Struct.Unit, - FWImgHdr->PackageVersion.Struct.Dev); - } + fw_img_hdr = (Mpi2FWImageHeader_t *)fwpkg_data; + if (le32_to_cpu(fw_img_hdr->Signature) == + MPI26_IMAGE_HEADER_SIGNATURE0_MPI26) { + cmp_img_hdr = + (Mpi26ComponentImageHeader_t *) + (fwpkg_data); + package_version = + le32_to_cpu( + cmp_img_hdr->ApplicationSpecific); + } else + package_version = + le32_to_cpu( + fw_img_hdr->PackageVersion.Word); + if (package_version) + ioc_info(ioc, + "FW Package Ver(%02d.%02d.%02d.%02d)\n", + ((package_version) & 0xFF000000) >> 24, + ((package_version) & 0x00FF0000) >> 16, + ((package_version) & 0x0000FF00) >> 8, + (package_version) & 0x000000FF); } else { _debug_dump_mf(&mpi_reply, sizeof(Mpi2FWUploadReply_t)/4); -- cgit v1.2.3 From 77fd4f2c88bf83205a21f9ca49fdcc0c7868dba9 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:48 -0400 Subject: scsi: mpt3sas: Reject NVMe Encap cmnds to unsupported HBA If any faulty application issues an NVMe Encapsulated commands to HBA which doesn't support NVMe protocol then driver should return the command as invalid with the following message. "HBA doesn't support NVMe. Rejecting NVMe Encapsulated request." Otherwise below page fault kernel panic will be observed while building the PRPs as there is no PRP pools allocated for the HBA which doesn't support NVMe drives. RIP: 0010:_base_build_nvme_prp+0x3b/0xf0 [mpt3sas] Call Trace: _ctl_do_mpt_command+0x931/0x1120 [mpt3sas] _ctl_ioctl_main.isra.11+0xa28/0x11e0 [mpt3sas] ? prepare_to_wait+0xb0/0xb0 ? tty_ldisc_deref+0x16/0x20 _ctl_ioctl+0x1a/0x20 [mpt3sas] do_vfs_ioctl+0xaa/0x620 ? vfs_read+0x117/0x140 ksys_ioctl+0x67/0x90 __x64_sys_ioctl+0x1a/0x20 do_syscall_64+0x60/0x190 entry_SYSCALL_64_after_hwframe+0x44/0xa9 [mkp: tweaked error string] Link: https://lore.kernel.org/r/1568379890-18347-12-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 9267ffecedcd..0c77f2209cec 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -785,6 +785,18 @@ _ctl_do_mpt_command(struct MPT3SAS_ADAPTER *ioc, struct mpt3_ioctl_command karg, case MPI2_FUNCTION_NVME_ENCAPSULATED: { nvme_encap_request = (Mpi26NVMeEncapsulatedRequest_t *)request; + if (!ioc->pcie_sg_lookup) { + dtmprintk(ioc, ioc_info(ioc, + "HBA doesn't support NVMe. Rejecting NVMe Encapsulated request.\n" + )); + + if (ioc->logging_level & MPT_DEBUG_TM) + _debug_dump_mf(nvme_encap_request, + ioc->request_sz/4); + mpt3sas_base_free_smid(ioc, smid); + ret = -EINVAL; + goto out; + } /* * Get the Physical Address of the sense buffer. * Use Error Response buffer address field to hold the sense -- cgit v1.2.3 From 9e64fd1e65f72d229f96fcf390576e772770a01c Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:49 -0400 Subject: scsi: mpt3sas: Fix module parameter max_msix_vectors Load driver with module parameter "max_msix_vectors". Value provided in module parameter is not used by mpt3sas driver. Driver loads with max controller supported MSI-X value. In _base_alloc_irq_vectors use reply_queue_count which is determined using user provided msix value insted of ioc->msix_vector_count which tells max supported msix value of the controller. Link: https://lore.kernel.org/r/1568379890-18347-13-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c index 5f5330352646..848fbec7bda6 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.c +++ b/drivers/scsi/mpt3sas/mpt3sas_base.c @@ -3044,11 +3044,11 @@ _base_alloc_irq_vectors(struct MPT3SAS_ADAPTER *ioc) descp = NULL; ioc_info(ioc, " %d %d\n", ioc->high_iops_queues, - ioc->msix_vector_count); + ioc->reply_queue_count); i = pci_alloc_irq_vectors_affinity(ioc->pdev, ioc->high_iops_queues, - ioc->msix_vector_count, irq_flags, descp); + ioc->reply_queue_count, irq_flags, descp); return i; } -- cgit v1.2.3 From d8b2625f4699a36b1753d87e96b0c50a4531c065 Mon Sep 17 00:00:00 2001 From: Sreekanth Reddy Date: Fri, 13 Sep 2019 09:04:50 -0400 Subject: scsi: mpt3sas: Bump mpt3sas driver version to 32.100.00.00 Bump mpt3sas driver version to 32.100.00.00 Link: https://lore.kernel.org/r/1568379890-18347-14-git-send-email-sreekanth.reddy@broadcom.com Signed-off-by: Sreekanth Reddy Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_base.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h index 91f663688bf0..4ebf81ea4d2f 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_base.h +++ b/drivers/scsi/mpt3sas/mpt3sas_base.h @@ -76,8 +76,8 @@ #define MPT3SAS_DRIVER_NAME "mpt3sas" #define MPT3SAS_AUTHOR "Avago Technologies " #define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver" -#define MPT3SAS_DRIVER_VERSION "31.100.00.00" -#define MPT3SAS_MAJOR_VERSION 31 +#define MPT3SAS_DRIVER_VERSION "32.100.00.00" +#define MPT3SAS_MAJOR_VERSION 32 #define MPT3SAS_MINOR_VERSION 100 #define MPT3SAS_BUILD_VERSION 0 #define MPT3SAS_RELEASE_VERSION 00 -- cgit v1.2.3 From a3a65ddd79c3c975eb1295863289aa4bbaded283 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Sat, 31 Aug 2019 08:39:03 +0100 Subject: scsi: smartpqi: clean up indentation of a statement There is a statement that is indented one level too deeply, remove the tab, re-join broken line and remove some empty lines. Link: https://lore.kernel.org/r/20190831073903.7834-1-colin.king@canonical.com Addresses-Coverity: ("Indentation does not match nesting") Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index ea5409bebf57..652d48224942 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -2175,10 +2175,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) device->aio_handle = phys_lun_ext_entry->aio_handle; } - - pqi_get_physical_disk_info(ctrl_info, - device, id_phys); - + pqi_get_physical_disk_info(ctrl_info, device, id_phys); } else { memcpy(device->volume_id, log_lun_ext_entry->volume_id, sizeof(device->volume_id)); -- cgit v1.2.3 From 1c6294858950a3cc609570f050734e1492e6a155 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Sat, 31 Aug 2019 13:03:48 +0000 Subject: scsi: smartpqi: remove set but not used variable 'ctrl_info' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/smartpqi/smartpqi_init.c: In function 'pqi_driver_version_show': drivers/scsi/smartpqi/smartpqi_init.c:6164:24: warning: variable 'ctrl_info' set but not used [-Wunused-but-set-variable] commit 6d90615f1346 ("scsi: smartpqi: add sysfs entries") added it but it was never used. Also remove variable 'shost'. [mkp: commit desc] Link: https://lore.kernel.org/r/20190831130348.20552-1-yuehaibing@huawei.com Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 652d48224942..4f649ad9e5bd 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6157,12 +6157,6 @@ static ssize_t pqi_firmware_version_show(struct device *dev, static ssize_t pqi_driver_version_show(struct device *dev, struct device_attribute *attr, char *buffer) { - struct Scsi_Host *shost; - struct pqi_ctrl_info *ctrl_info; - - shost = class_to_shost(dev); - ctrl_info = shost_to_hba(shost); - return snprintf(buffer, PAGE_SIZE, "%s\n", DRIVER_VERSION BUILD_TIMESTAMP); } -- cgit v1.2.3 From da6d2965dbdb480f091c42f54a09abe8056282e5 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 Sep 2019 14:42:29 +0100 Subject: scsi: qla2xxx: remove redundant assignment to pointer host The pointer host is being initialized with a value that is never read and is being re-assigned a little later on. The assignment is redundant and hence can be removed. Link: https://lore.kernel.org/r/20190905134229.21194-1-colin.king@canonical.com Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_target.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_target.c b/drivers/scsi/qla2xxx/qla_target.c index 0ffda6171614..584f45a7be2f 100644 --- a/drivers/scsi/qla2xxx/qla_target.c +++ b/drivers/scsi/qla2xxx/qla_target.c @@ -463,7 +463,7 @@ void qlt_response_pkt_all_vps(struct scsi_qla_host *vha, case IMMED_NOTIFY_TYPE: { - struct scsi_qla_host *host = vha; + struct scsi_qla_host *host; struct imm_ntfy_from_isp *entry = (struct imm_ntfy_from_isp *)pkt; -- cgit v1.2.3 From c88dcd8aca65bf8de54093e245128157bb953d85 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 5 Sep 2019 14:50:17 +0100 Subject: scsi: mvsas: remove redundant assignment to variable rc The variable rc is being initialized with a value that is never read and is being re-assigned a little later on. The assignment is redundant and hence can be removed. Link: https://lore.kernel.org/r/20190905135017.23772-1-colin.king@canonical.com Addresses-Coverity: ("Unused value") Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/mvsas/mv_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c index 3e0b8ebe257f..a920eced92ec 100644 --- a/drivers/scsi/mvsas/mv_sas.c +++ b/drivers/scsi/mvsas/mv_sas.c @@ -1541,7 +1541,7 @@ out: int mvs_abort_task_set(struct domain_device *dev, u8 *lun) { - int rc = TMF_RESP_FUNC_FAILED; + int rc; struct mvs_tmf_task tmf_task; tmf_task.tmf = TMF_ABORT_TASK_SET; -- cgit v1.2.3 From b23c640c33b8ab10060b8d243d1aa817e5eb00dc Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 6 Sep 2019 17:39:45 +0100 Subject: scsi: fnic: make array dev_cmd_err static const, makes object smaller Don't populate the array dev_cmd_err on the stack but instead make it static const. Makes the object code smaller by 80 bytes. Before: text data bss dec hex filename 21461 1564 0 23025 59f1 drivers/scsi/fnic/vnic_dev.o After: text data bss dec hex filename 21318 1628 0 22946 59a2 drivers/scsi/fnic/vnic_dev.o (gcc version 9.2.1, amd64) Link: https://lore.kernel.org/r/20190906163945.3889-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/vnic_dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c index 78af9cc2009b..1f55b9e4e74a 100644 --- a/drivers/scsi/fnic/vnic_dev.c +++ b/drivers/scsi/fnic/vnic_dev.c @@ -259,7 +259,7 @@ int vnic_dev_cmd1(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, int wait) struct vnic_devcmd __iomem *devcmd = vdev->devcmd; int delay; u32 status; - int dev_cmd_err[] = { + static const int dev_cmd_err[] = { /* convert from fw's version of error.h to host's version */ 0, /* ERR_SUCCESS */ EINVAL, /* ERR_EINVAL */ -- cgit v1.2.3 From 5ece56a2a6b24f635bd46931467bd70acd8bcce9 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 6 Sep 2019 17:45:22 +0100 Subject: scsi: ips: make array 'options' static const, makes object smaller Don't populate the array 'options' on the stack but instead make it static const. Makes the object code smaller by 143 bytes. Before: text data bss dec hex filename 94483 11272 1184 106939 1a1bb drivers/scsi/ips.o After: text data bss dec hex filename 94244 11368 1184 106796 1a12c drivers/scsi/ips.o (gcc version 9.2.1, amd64) Link: https://lore.kernel.org/r/20190906164522.5644-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ips.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c index e8bc8d328bab..f25672982c5f 100644 --- a/drivers/scsi/ips.c +++ b/drivers/scsi/ips.c @@ -498,7 +498,7 @@ ips_setup(char *ips_str) int i; char *key; char *value; - IPS_OPTION options[] = { + static const IPS_OPTION options[] = { {"noi2o", &ips_force_i2o, 0}, {"nommap", &ips_force_memio, 0}, {"ioctlsize", &ips_ioctlsize, IPS_IOCTL_SIZE}, -- cgit v1.2.3 From 7e52440c81aa2cf200102072e337ab6b11c331ef Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 6 Sep 2019 18:01:04 +0100 Subject: scsi: ufs: make array setup_attrs static const, makes object smaller Don't populate the array setup_attrs on the stack but instead make it static const. Makes the object code smaller by 180 bytes. Before: text data bss dec hex filename 2140 224 0 2364 93c drivers/scsi/ufs/ufshcd-dwc.o After: text data bss dec hex filename 1863 320 0 2183 887 drivers/scsi/ufs/ufshcd-dwc.o (gcc version 9.2.1, amd64) Link: https://lore.kernel.org/r/20190906170104.10450-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd-dwc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd-dwc.c b/drivers/scsi/ufs/ufshcd-dwc.c index fb9e2ff4f8d2..6a901da2d15a 100644 --- a/drivers/scsi/ufs/ufshcd-dwc.c +++ b/drivers/scsi/ufs/ufshcd-dwc.c @@ -80,7 +80,7 @@ static int ufshcd_dwc_link_is_up(struct ufs_hba *hba) */ static int ufshcd_dwc_connection_setup(struct ufs_hba *hba) { - const struct ufshcd_dme_attr_val setup_attrs[] = { + static const struct ufshcd_dme_attr_val setup_attrs[] = { { UIC_ARG_MIB(T_CONNECTIONSTATE), 0, DME_LOCAL }, { UIC_ARG_MIB(N_DEVICEID), 0, DME_LOCAL }, { UIC_ARG_MIB(N_DEVICEID_VALID), 0, DME_LOCAL }, -- cgit v1.2.3 From 69be9264e35c107a262bcda6909ca1bcb0b1524c Mon Sep 17 00:00:00 2001 From: Markus Elfring Date: Sat, 7 Sep 2019 14:25:31 +0200 Subject: scsi: ufs-hisi: Use PTR_ERR_OR_ZERO() in ufs_hisi_get_resource() Simplify this function implementation by using a known function. Generated by: scripts/coccinelle/api/ptr_ret.cocci [mkp: applied by hand] Link: https://lore.kernel.org/r/9e667f19-434e-ed30-78cb-9ddc6323c51e@web.de Signed-off-by: Markus Elfring Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-hisi.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/drivers/scsi/ufs/ufs-hisi.c b/drivers/scsi/ufs/ufs-hisi.c index 6bbb1679bb91..5d6487350a6c 100644 --- a/drivers/scsi/ufs/ufs-hisi.c +++ b/drivers/scsi/ufs/ufs-hisi.c @@ -452,10 +452,7 @@ static int ufs_hisi_get_resource(struct ufs_hisi_host *host) /* get resource of ufs sys ctrl */ host->ufs_sys_ctrl = devm_platform_ioremap_resource(pdev, 1); - if (IS_ERR(host->ufs_sys_ctrl)) - return PTR_ERR(host->ufs_sys_ctrl); - - return 0; + return PTR_ERR_OR_ZERO(host->ufs_sys_ctrl); } static void ufs_hisi_set_pm_lvl(struct ufs_hba *hba) -- cgit v1.2.3 From 0e62395da2bd5166d7c9e14cbc7503b256a34cb0 Mon Sep 17 00:00:00 2001 From: Navid Emamdoost Date: Tue, 10 Sep 2019 18:44:15 -0500 Subject: scsi: bfa: release allocated memory in case of error In bfad_im_get_stats if bfa_port_get_stats fails, allocated memory needs to be released. Link: https://lore.kernel.org/r/20190910234417.22151-1-navid.emamdoost@gmail.com Signed-off-by: Navid Emamdoost Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfad_attr.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/bfa/bfad_attr.c b/drivers/scsi/bfa/bfad_attr.c index 29ab81df75c0..fbfce02e5b93 100644 --- a/drivers/scsi/bfa/bfad_attr.c +++ b/drivers/scsi/bfa/bfad_attr.c @@ -275,8 +275,10 @@ bfad_im_get_stats(struct Scsi_Host *shost) rc = bfa_port_get_stats(BFA_FCPORT(&bfad->bfa), fcstats, bfad_hcb_comp, &fcomp); spin_unlock_irqrestore(&bfad->bfad_lock, flags); - if (rc != BFA_STATUS_OK) + if (rc != BFA_STATUS_OK) { + kfree(fcstats); return NULL; + } wait_for_completion(&fcomp.comp); -- cgit v1.2.3 From 63e40c553f0844b210f7aeb557500af7bb384b15 Mon Sep 17 00:00:00 2001 From: Arkadiusz Drabczyk Date: Thu, 12 Sep 2019 19:25:46 +0200 Subject: scsi: csiostor: Fix spelling typos Fix several spelling typos in comments in csio_hw.c. Link: https://lore.kernel.org/r/20190912172546.16489-1-arkadiusz@drabczyk.org Signed-off-by: Arkadiusz Drabczyk Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_hw.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c index e51923886475..950f9cdf0577 100644 --- a/drivers/scsi/csiostor/csio_hw.c +++ b/drivers/scsi/csiostor/csio_hw.c @@ -793,10 +793,10 @@ csio_hw_get_flash_params(struct csio_hw *hw) goto found; } - /* Decode Flash part size. The code below looks repetative with + /* Decode Flash part size. The code below looks repetitive with * common encodings, but that's not guaranteed in the JEDEC - * specification for the Read JADEC ID command. The only thing that - * we're guaranteed by the JADEC specification is where the + * specification for the Read JEDEC ID command. The only thing that + * we're guaranteed by the JEDEC specification is where the * Manufacturer ID is in the returned result. After that each * Manufacturer ~could~ encode things completely differently. * Note, all Flash parts must have 64KB sectors. @@ -983,8 +983,8 @@ retry: waiting -= 50; /* - * If neither Error nor Initialialized are indicated - * by the firmware keep waiting till we exaust our + * If neither Error nor Initialized are indicated + * by the firmware keep waiting till we exhaust our * timeout ... and then retry if we haven't exhausted * our retries ... */ @@ -1738,7 +1738,7 @@ static void csio_link_l1cfg(struct link_config *lc, uint16_t fw_caps, * Convert Common Code Forward Error Control settings into the * Firmware's API. If the current Requested FEC has "Automatic" * (IEEE 802.3) specified, then we use whatever the Firmware - * sent us as part of it's IEEE 802.3-based interpratation of + * sent us as part of it's IEEE 802.3-based interpretation of * the Transceiver Module EPROM FEC parameters. Otherwise we * use whatever is in the current Requested FEC settings. */ @@ -2834,7 +2834,7 @@ csio_hws_configuring(struct csio_hw *hw, enum csio_hw_ev evt) } /* - * csio_hws_initializing - Initialiazing state + * csio_hws_initializing - Initializing state * @hw - HW module * @evt - Event * @@ -3049,7 +3049,7 @@ csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt) if (!csio_is_hw_master(hw)) break; /* - * The BYE should have alerady been issued, so we cant + * The BYE should have already been issued, so we can't * use the mailbox interface. Hence we use the PL_RST * register directly. */ @@ -3104,7 +3104,7 @@ csio_hws_pcierr(struct csio_hw *hw, enum csio_hw_ev evt) * * A table driven interrupt handler that applies a set of masks to an * interrupt status word and performs the corresponding actions if the - * interrupts described by the mask have occured. The actions include + * interrupts described by the mask have occurred. The actions include * optionally emitting a warning or alert message. The table is terminated * by an entry specifying mask 0. Returns the number of fatal interrupt * conditions. @@ -4219,7 +4219,7 @@ csio_mgmtm_exit(struct csio_mgmtm *mgmtm) * @hw: Pointer to HW module. * * It is assumed that the initialization is a synchronous operation. - * So when we return afer posting the event, the HW SM should be in + * So when we return after posting the event, the HW SM should be in * the ready state, if there were no errors during init. */ int -- cgit v1.2.3 From b1000fcca1760d3e81f0943f0ca8b9be3ed3b999 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Mon, 16 Sep 2019 10:17:06 +0100 Subject: scsi: hisi_sas: fix spelling mistake "digial" -> "digital" There is a spelling mistake in literal string. Fix it. Link: https://lore.kernel.org/r/20190916091706.32268-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index d1513fdf1e00..e934d0b11745 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -3539,7 +3539,7 @@ static const struct { int value; char *name; } hisi_sas_debugfs_loop_modes[] = { - { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digial" }, + { HISI_SAS_BIST_LOOPBACK_MODE_DIGITAL, "digital" }, { HISI_SAS_BIST_LOOPBACK_MODE_SERDES, "serdes" }, { HISI_SAS_BIST_LOOPBACK_MODE_REMOTE, "remote" }, }; -- cgit v1.2.3 From c74f8056621738f5be9f5d3d7e0caa927b21aef6 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Mon, 16 Sep 2019 23:56:49 +0800 Subject: scsi: core: allow auto suspend override by low-level driver Rework from previous work by: Sujit Reddy Thumma Until now the scsi mid-layer forbids runtime suspend till userspace enables it. This is mainly to quarantine some disks with broken runtime power management or have high latencies executing suspend resume callbacks. If the userspace doesn't enable the runtime suspend the underlying hardware will be always on even when it is not doing any useful work and thus wasting power. Some low-level drivers for the controllers can efficiently use runtime power management to reduce power consumption and improve battery life. Allow runtime suspend parameters override within the LLD itself instead of waiting for userspace to control the power management. Link: https://lore.kernel.org/r/1568649411-5127-2-git-send-email-stanley.chu@mediatek.com Reviewed-by: Avri Altman Reviewed-by: Bart Van Assche Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_sysfs.c | 3 ++- drivers/scsi/sd.c | 4 ++++ include/scsi/scsi_device.h | 3 ++- include/scsi/scsi_host.h | 3 +++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index 64c96c7828ee..cebb9336c02b 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -1300,7 +1300,8 @@ int scsi_sysfs_add_sdev(struct scsi_device *sdev) device_enable_async_suspend(&sdev->sdev_gendev); scsi_autopm_get_target(starget); pm_runtime_set_active(&sdev->sdev_gendev); - pm_runtime_forbid(&sdev->sdev_gendev); + if (!sdev->rpm_autosuspend) + pm_runtime_forbid(&sdev->sdev_gendev); pm_runtime_enable(&sdev->sdev_gendev); scsi_autopm_put_target(starget); diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 50928bc266eb..a16014f04aa4 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -3367,6 +3367,10 @@ static int sd_probe(struct device *dev) } blk_pm_runtime_init(sdp->request_queue, dev); + if (sdp->rpm_autosuspend) { + pm_runtime_set_autosuspend_delay(dev, + sdp->host->hostt->rpm_autosuspend_delay); + } device_add_disk(dev, gd, NULL); if (sdkp->capacity) sd_dif_config_host(sdkp); diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 202f4d6a4342..039e289f295e 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -199,7 +199,8 @@ struct scsi_device { unsigned broken_fua:1; /* Don't set FUA bit */ unsigned lun_in_cdb:1; /* Store LUN bits in CDB[1] */ unsigned unmap_limit_for_ws:1; /* Use the UNMAP limit for WRITE SAME */ - + unsigned rpm_autosuspend:1; /* Enable runtime autosuspend at device + * creation time */ atomic_t disk_events_disable_depth; /* disable depth for disk events */ DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /* supported events */ diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 31e0d6ca1eba..2c3f0c58869b 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -486,6 +486,9 @@ struct scsi_host_template { */ unsigned int cmd_size; struct scsi_host_cmd_pool *cmd_pool; + + /* Delay for runtime autosuspend */ + int rpm_autosuspend_delay; }; /* -- cgit v1.2.3 From 49615ba144a0929c725d08f0d3ba8494c8b77404 Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Mon, 16 Sep 2019 23:56:50 +0800 Subject: scsi: ufs: override auto suspend tunables for ufs Rework from previous work by: Sujit Reddy Thumma Override auto suspend tunables for UFS device LUNs during initialization so as to efficiently manage background operations and the power consumption. Link: https://lore.kernel.org/r/1568649411-5127-3-git-send-email-stanley.chu@mediatek.com Reviewed-by: Avri Altman Reviewed-by: Bean Huo Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 9 +++++++++ drivers/scsi/ufs/ufshcd.h | 10 ++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 034dd9cb9ec8..b580685eebcc 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -88,6 +88,9 @@ /* Interrupt aggregation default timeout, unit: 40us */ #define INT_AGGR_DEF_TO 0x02 +/* default delay of autosuspend: 2000 ms */ +#define RPM_AUTOSUSPEND_DELAY_MS 2000 + #define ufshcd_toggle_vreg(_dev, _vreg, _on) \ ({ \ int _ret; \ @@ -4631,9 +4634,14 @@ static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth) */ static int ufshcd_slave_configure(struct scsi_device *sdev) { + struct ufs_hba *hba = shost_priv(sdev->host); struct request_queue *q = sdev->request_queue; blk_queue_update_dma_pad(q, PRDT_DATA_BYTE_COUNT_PAD - 1); + + if (ufshcd_is_rpm_autosuspend_allowed(hba)) + sdev->rpm_autosuspend = 1; + return 0; } @@ -7069,6 +7077,7 @@ static struct scsi_host_template ufshcd_driver_template = { .track_queue_depth = 1, .sdev_groups = ufshcd_driver_groups, .dma_boundary = PAGE_SIZE - 1, + .rpm_autosuspend_delay = RPM_AUTOSUSPEND_DELAY_MS, }; static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg, diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index c94cfda52829..e0fe247c719e 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -716,6 +716,12 @@ struct ufs_hba { * the performance of ongoing read/write operations. */ #define UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND (1 << 5) + /* + * This capability allows host controller driver to automatically + * enable runtime power management by itself instead of waiting + * for userspace to control the power management. + */ +#define UFSHCD_CAP_RPM_AUTOSUSPEND (1 << 6) struct devfreq *devfreq; struct ufs_clk_scaling clk_scaling; @@ -749,6 +755,10 @@ static inline bool ufshcd_can_autobkops_during_suspend(struct ufs_hba *hba) { return hba->caps & UFSHCD_CAP_AUTO_BKOPS_SUSPEND; } +static inline bool ufshcd_is_rpm_autosuspend_allowed(struct ufs_hba *hba) +{ + return hba->caps & UFSHCD_CAP_RPM_AUTOSUSPEND; +} static inline bool ufshcd_is_intr_aggr_allowed(struct ufs_hba *hba) { -- cgit v1.2.3 From e6d6ba8014e5205d66e3711047463f04132c3b1e Mon Sep 17 00:00:00 2001 From: Stanley Chu Date: Mon, 16 Sep 2019 23:56:51 +0800 Subject: scsi: ufs-mediatek: enable auto suspend capability Enable auto suspend capability in MediaTek UFS driver. Link: https://lore.kernel.org/r/1568649411-5127-4-git-send-email-stanley.chu@mediatek.com Reviewed-by: Avri Altman Signed-off-by: Stanley Chu Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-mediatek.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c index 0f6ff33ce52e..83e28edc3ac5 100644 --- a/drivers/scsi/ufs/ufs-mediatek.c +++ b/drivers/scsi/ufs/ufs-mediatek.c @@ -147,6 +147,9 @@ static int ufs_mtk_init(struct ufs_hba *hba) if (err) goto out_variant_clear; + /* Enable runtime autosuspend */ + hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND; + /* * ufshcd_vops_init() is invoked after * ufshcd_setup_clock(true) in ufshcd_hba_init() thus -- cgit v1.2.3 From c3dde2f3fe6aa48ed4650e103d23aac8f9620ddd Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Tue, 24 Sep 2019 09:29:06 +0200 Subject: scsi: qedf: Add port_id getter Add qedf_get_host_port_id() to the transport template. The fc_transport_template initializes the port_id member to the default value of -1. The new getter ensures that the sysfs entry shows the current value and not the default one, e.g by using 'lsscsi -H -t' Link: https://lore.kernel.org/r/20190924072906.23737-1-dwagner@suse.de Signed-off-by: Daniel Wagner Acked-by: Saurav Kashyap Reviewed-by: Hannes Reinecke Signed-off-by: Martin K. Petersen --- drivers/scsi/qedf/qedf_main.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/qedf/qedf_main.c b/drivers/scsi/qedf/qedf_main.c index 1659d35cd37b..eeea9c03931a 100644 --- a/drivers/scsi/qedf/qedf_main.c +++ b/drivers/scsi/qedf/qedf_main.c @@ -1926,6 +1926,13 @@ static int qedf_fcoe_reset(struct Scsi_Host *shost) return 0; } +static void qedf_get_host_port_id(struct Scsi_Host *shost) +{ + struct fc_lport *lport = shost_priv(shost); + + fc_host_port_id(shost) = lport->port_id; +} + static struct fc_host_statistics *qedf_fc_get_host_stats(struct Scsi_Host *shost) { @@ -1996,6 +2003,7 @@ static struct fc_function_template qedf_fc_transport_fn = { .show_host_active_fc4s = 1, .show_host_maxframe_size = 1, + .get_host_port_id = qedf_get_host_port_id, .show_host_port_id = 1, .show_host_supported_speeds = 1, .get_host_speed = fc_get_host_speed, -- cgit v1.2.3 From 8ee132b3cb699530a74faba44f6227ad4ead0ea1 Mon Sep 17 00:00:00 2001 From: "Milan P. Gandhi" Date: Thu, 26 Sep 2019 10:55:02 +0530 Subject: scsi: core: Log SCSI command age with errors Couple of users had requested to print the SCSI command age along with command failure errors. This is a small change, but allows users to get more important information about the command that was failed, it would help the users in debugging the command failures: Link: https://lore.kernel.org/r/20190926052501.GA8352@machine1 Signed-off-by: Milan P. Gandhi Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_logging.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c index c6ed0b12e807..c91fa3feb930 100644 --- a/drivers/scsi/scsi_logging.c +++ b/drivers/scsi/scsi_logging.c @@ -390,6 +390,7 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg, const char *mlret_string = scsi_mlreturn_string(disposition); const char *hb_string = scsi_hostbyte_string(cmd->result); const char *db_string = scsi_driverbyte_string(cmd->result); + unsigned long cmd_age = (jiffies - cmd->jiffies_at_alloc) / HZ; logbuf = scsi_log_reserve_buffer(&logbuf_len); if (!logbuf) @@ -431,10 +432,15 @@ void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg, if (db_string) off += scnprintf(logbuf + off, logbuf_len - off, - "driverbyte=%s", db_string); + "driverbyte=%s ", db_string); else off += scnprintf(logbuf + off, logbuf_len - off, - "driverbyte=0x%02x", driver_byte(cmd->result)); + "driverbyte=0x%02x ", + driver_byte(cmd->result)); + + off += scnprintf(logbuf + off, logbuf_len - off, + "cmd_age=%lus", cmd_age); + out_printk: dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf); scsi_log_release_buffer(logbuf); -- cgit v1.2.3 From 9adc2a5c3b7df39c8f7ede1edf8232a377694829 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 26 Sep 2019 12:57:16 +0100 Subject: scsi: csiostor: clean up indentation issue The goto statement is indented incorrectly, remove the extraneous tab. Link: https://lore.kernel.org/r/20190926115716.3698-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_mb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c index 6f13673d6aa0..94810b19e747 100644 --- a/drivers/scsi/csiostor/csio_mb.c +++ b/drivers/scsi/csiostor/csio_mb.c @@ -1210,7 +1210,7 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp) !csio_is_hw_intr_enabled(hw)) { csio_err(hw, "Cannot issue mailbox in interrupt mode 0x%x\n", *((uint8_t *)mbp->mb)); - goto error_out; + goto error_out; } if (mbm->mcurrent != NULL) { -- cgit v1.2.3 From 9e322310e16c8cc2ae90b885a821dba121025eb7 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 27 Sep 2019 10:58:40 +0100 Subject: scsi: smartpqi: clean up an indentation issue There are some statements that are indented too deeply, remove the extraneous tabs and rejoin split lines. Link: https://lore.kernel.org/r/20190927095840.26377-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 4f649ad9e5bd..e5c4202a862d 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -2172,8 +2172,8 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED) && phys_lun_ext_entry->aio_handle) { device->aio_enabled = true; - device->aio_handle = - phys_lun_ext_entry->aio_handle; + device->aio_handle = + phys_lun_ext_entry->aio_handle; } pqi_get_physical_disk_info(ctrl_info, device, id_phys); } else { -- cgit v1.2.3 From d188b0675b21d5a6ca27b3e741381813983f4719 Mon Sep 17 00:00:00 2001 From: Ryan Attard Date: Thu, 26 Sep 2019 11:22:17 -0500 Subject: scsi: core: Add sysfs attributes for VPD pages 0h and 89h Add sysfs attributes for the ATA information page and Supported VPD Pages page. Link: https://lore.kernel.org/r/20190926162216.56591-1-ryanattard@ryanattard.info Signed-off-by: Ryan Attard Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi.c | 4 ++++ drivers/scsi/scsi_sysfs.c | 19 +++++++++++++++++++ include/scsi/scsi_device.h | 2 ++ 3 files changed, 25 insertions(+) diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 1f5b5c8a7f72..4f76841a7038 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -465,10 +465,14 @@ void scsi_attach_vpd(struct scsi_device *sdev) return; for (i = 4; i < vpd_buf->len; i++) { + if (vpd_buf->data[i] == 0x0) + scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0); if (vpd_buf->data[i] == 0x80) scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80); if (vpd_buf->data[i] == 0x83) scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83); + if (vpd_buf->data[i] == 0x89) + scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89); } kfree(vpd_buf); } diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c index cebb9336c02b..2c76d7a43f67 100644 --- a/drivers/scsi/scsi_sysfs.c +++ b/drivers/scsi/scsi_sysfs.c @@ -437,6 +437,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) struct device *parent; struct list_head *this, *tmp; struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL; + struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL; unsigned long flags; sdev = container_of(work, struct scsi_device, ew.work); @@ -466,16 +467,24 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work) sdev->request_queue = NULL; mutex_lock(&sdev->inquiry_mutex); + rcu_swap_protected(sdev->vpd_pg0, vpd_pg0, + lockdep_is_held(&sdev->inquiry_mutex)); rcu_swap_protected(sdev->vpd_pg80, vpd_pg80, lockdep_is_held(&sdev->inquiry_mutex)); rcu_swap_protected(sdev->vpd_pg83, vpd_pg83, lockdep_is_held(&sdev->inquiry_mutex)); + rcu_swap_protected(sdev->vpd_pg89, vpd_pg89, + lockdep_is_held(&sdev->inquiry_mutex)); mutex_unlock(&sdev->inquiry_mutex); + if (vpd_pg0) + kfree_rcu(vpd_pg0, rcu); if (vpd_pg83) kfree_rcu(vpd_pg83, rcu); if (vpd_pg80) kfree_rcu(vpd_pg80, rcu); + if (vpd_pg89) + kfree_rcu(vpd_pg89, rcu); kfree(sdev->inquiry); kfree(sdev); @@ -859,6 +868,8 @@ static struct bin_attribute dev_attr_vpd_##_page = { \ sdev_vpd_pg_attr(pg83); sdev_vpd_pg_attr(pg80); +sdev_vpd_pg_attr(pg89); +sdev_vpd_pg_attr(pg0); static ssize_t show_inquiry(struct file *filep, struct kobject *kobj, struct bin_attribute *bin_attr, @@ -1191,12 +1202,18 @@ static umode_t scsi_sdev_bin_attr_is_visible(struct kobject *kobj, struct scsi_device *sdev = to_scsi_device(dev); + if (attr == &dev_attr_vpd_pg0 && !sdev->vpd_pg0) + return 0; + if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80) return 0; if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83) return 0; + if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89) + return 0; + return S_IRUGO; } @@ -1239,8 +1256,10 @@ static struct attribute *scsi_sdev_attrs[] = { }; static struct bin_attribute *scsi_sdev_bin_attrs[] = { + &dev_attr_vpd_pg0, &dev_attr_vpd_pg83, &dev_attr_vpd_pg80, + &dev_attr_vpd_pg89, &dev_attr_inquiry, NULL }; diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h index 039e289f295e..3ed836db5306 100644 --- a/include/scsi/scsi_device.h +++ b/include/scsi/scsi_device.h @@ -140,8 +140,10 @@ struct scsi_device { const char * rev; /* ... "nullnullnullnull" before scan */ #define SCSI_VPD_PG_LEN 255 + struct scsi_vpd __rcu *vpd_pg0; struct scsi_vpd __rcu *vpd_pg83; struct scsi_vpd __rcu *vpd_pg80; + struct scsi_vpd __rcu *vpd_pg89; unsigned char current_tag; /* current tag */ struct scsi_target *sdev_target; /* used only for single_lun */ -- cgit v1.2.3 From f99f6f46f6de186b0465709e36a903c01639ab2d Mon Sep 17 00:00:00 2001 From: Austin Kim Date: Tue, 24 Sep 2019 18:37:16 +0900 Subject: scsi: libcxgbi: remove unused function to stop warning Since 'commit fc8d0590d914 ("libcxgbi: Add ipv6 api to driver")' was introduced, there is no call to csk_print_port() and csk_print_ip() is made. Hence kernel build with clang complains below message: drivers/scsi/cxgbi/libcxgbi.c:2287:19: warning: unused function 'csk_print_port' [-Wunused-function] static inline int csk_print_port(struct cxgbi_sock *csk, char *buf) ^ drivers/scsi/cxgbi/libcxgbi.c:2298:19: warning: unused function 'csk_print_ip' [-Wunused-function] static inline int csk_print_ip(struct cxgbi_sock *csk, char *buf) ^ Remove csk_print_port() and csk_print_ip() to stop warning. Link: https://lore.kernel.org/r/20190924093716.GA78230@LGEARND20B15 Signed-off-by: Austin Kim Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/libcxgbi.c | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/drivers/scsi/cxgbi/libcxgbi.c b/drivers/scsi/cxgbi/libcxgbi.c index 3e17af8aedeb..0d044c165960 100644 --- a/drivers/scsi/cxgbi/libcxgbi.c +++ b/drivers/scsi/cxgbi/libcxgbi.c @@ -2284,34 +2284,6 @@ int cxgbi_set_conn_param(struct iscsi_cls_conn *cls_conn, } EXPORT_SYMBOL_GPL(cxgbi_set_conn_param); -static inline int csk_print_port(struct cxgbi_sock *csk, char *buf) -{ - int len; - - cxgbi_sock_get(csk); - len = sprintf(buf, "%hu\n", ntohs(csk->daddr.sin_port)); - cxgbi_sock_put(csk); - - return len; -} - -static inline int csk_print_ip(struct cxgbi_sock *csk, char *buf) -{ - int len; - - cxgbi_sock_get(csk); - if (csk->csk_family == AF_INET) - len = sprintf(buf, "%pI4", - &csk->daddr.sin_addr.s_addr); - else - len = sprintf(buf, "%pI6", - &csk->daddr6.sin6_addr); - - cxgbi_sock_put(csk); - - return len; -} - int cxgbi_get_ep_param(struct iscsi_endpoint *ep, enum iscsi_param param, char *buf) { -- cgit v1.2.3 From 7cd4cb94cf4f3bfd070d78714d4fe249700250a8 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 30 Sep 2019 17:43:27 +0800 Subject: scsi: bfa: Make restart_bfa static Fix sparse warning: drivers/scsi/bfa/bfad.c:1491:1: warning: symbol 'restart_bfa' was not declared. Should it be static? Link: https://lore.kernel.org/r/20190930094327.46836-1-yuehaibing@huawei.com Reported-by: Hulk Robot Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/bfa/bfad.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/bfa/bfad.c b/drivers/scsi/bfa/bfad.c index 2f9213b257a4..eb0c76338295 100644 --- a/drivers/scsi/bfa/bfad.c +++ b/drivers/scsi/bfa/bfad.c @@ -1487,8 +1487,7 @@ bfad_pci_error_detected(struct pci_dev *pdev, pci_channel_state_t state) return ret; } -int -restart_bfa(struct bfad_s *bfad) +static int restart_bfa(struct bfad_s *bfad) { unsigned long flags; struct pci_dev *pdev = bfad->pcidev; -- cgit v1.2.3 From 27f722ccbe1563629275bb7ee30c0e307f5837a2 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Mon, 30 Sep 2019 16:22:24 -0700 Subject: scsi: target: Remove tpg_list and se_portal_group.se_tpg_node Maintaining tpg_list without ever iterating over it is not useful. Hence remove tpg_list. This patch does not change the behavior of the SCSI target code. Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Nicholas Bellinger Link: https://lore.kernel.org/r/20190930232224.58980-1-bvanassche@acm.org Signed-off-by: Bart Van Assche Reviewed-by: Mike Christie Signed-off-by: Martin K. Petersen --- drivers/target/target_core_tpg.c | 12 ------------ drivers/target/target_core_xcopy.c | 1 - include/target/target_core_base.h | 1 - 3 files changed, 14 deletions(-) diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index e5a71addbb06..d24e0a3ba3ff 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c @@ -32,9 +32,6 @@ extern struct se_device *g_lun0_dev; -static DEFINE_SPINLOCK(tpg_lock); -static LIST_HEAD(tpg_list); - /* __core_tpg_get_initiator_node_acl(): * * mutex_lock(&tpg->acl_node_mutex); must be held when calling @@ -475,7 +472,6 @@ int core_tpg_register( se_tpg->se_tpg_wwn = se_wwn; atomic_set(&se_tpg->tpg_pr_ref_count, 0); INIT_LIST_HEAD(&se_tpg->acl_node_list); - INIT_LIST_HEAD(&se_tpg->se_tpg_node); INIT_LIST_HEAD(&se_tpg->tpg_sess_list); spin_lock_init(&se_tpg->session_lock); mutex_init(&se_tpg->tpg_lun_mutex); @@ -494,10 +490,6 @@ int core_tpg_register( } } - spin_lock_bh(&tpg_lock); - list_add_tail(&se_tpg->se_tpg_node, &tpg_list); - spin_unlock_bh(&tpg_lock); - pr_debug("TARGET_CORE[%s]: Allocated portal_group for endpoint: %s, " "Proto: %d, Portal Tag: %u\n", se_tpg->se_tpg_tfo->fabric_name, se_tpg->se_tpg_tfo->tpg_get_wwn(se_tpg) ? @@ -519,10 +511,6 @@ int core_tpg_deregister(struct se_portal_group *se_tpg) tfo->tpg_get_wwn(se_tpg) ? tfo->tpg_get_wwn(se_tpg) : NULL, se_tpg->proto_id, tfo->tpg_get_tag(se_tpg)); - spin_lock_bh(&tpg_lock); - list_del(&se_tpg->se_tpg_node); - spin_unlock_bh(&tpg_lock); - while (atomic_read(&se_tpg->tpg_pr_ref_count) != 0) cpu_relax(); diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index b9b1e92c6f8d..425c1070de08 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c @@ -467,7 +467,6 @@ int target_xcopy_setup_pt(void) } memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group)); - INIT_LIST_HEAD(&xcopy_pt_tpg.se_tpg_node); INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list); INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list); diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h index 7c9716fe731e..1728e883b7b2 100644 --- a/include/target/target_core_base.h +++ b/include/target/target_core_base.h @@ -876,7 +876,6 @@ struct se_portal_group { /* Spinlock for adding/removing sessions */ spinlock_t session_lock; struct mutex tpg_lun_mutex; - struct list_head se_tpg_node; /* linked list for initiator ACL list */ struct list_head acl_node_list; struct hlist_head tpg_lun_hlist; -- cgit v1.2.3 From 84ed362ac40ca44dbbbebf767301463aa72bc797 Mon Sep 17 00:00:00 2001 From: Michael Hernandez Date: Thu, 12 Sep 2019 11:09:12 -0700 Subject: scsi: qla2xxx: Dual FCP-NVMe target port support Some storage arrays advertise FCP LUNs and NVMe namespaces behind the same WWN. The driver now offers a user option by way of NVRAM parameter to allow users to choose, on a per port basis, the kind of FC-4 type they would like to prioritize for login. Link: https://lore.kernel.org/r/20190912180918.6436-9-hmadhani@marvell.com Signed-off-by: Michael Hernandez Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 26 ++++++++++++++-- drivers/scsi/qla2xxx/qla_fw.h | 2 ++ drivers/scsi/qla2xxx/qla_gs.c | 42 ++++++++++++++----------- drivers/scsi/qla2xxx/qla_init.c | 64 ++++++++++++++++++++++----------------- drivers/scsi/qla2xxx/qla_inline.h | 12 ++++++++ drivers/scsi/qla2xxx/qla_mbx.c | 11 ++++--- drivers/scsi/qla2xxx/qla_os.c | 17 +++++------ 7 files changed, 114 insertions(+), 60 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 6ffa9877c28b..721ee7f09b39 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2277,7 +2277,7 @@ typedef struct { uint8_t fabric_port_name[WWN_SIZE]; uint16_t fp_speed; uint8_t fc4_type; - uint8_t fc4f_nvme; /* nvme fc4 feature bits */ + uint8_t fc4_features; } sw_info_t; /* FCP-4 types */ @@ -2445,7 +2445,7 @@ typedef struct fc_port { u32 supported_classes; uint8_t fc4_type; - uint8_t fc4f_nvme; + uint8_t fc4_features; uint8_t scan_state; unsigned long last_queue_full; @@ -2476,6 +2476,9 @@ typedef struct fc_port { u16 n2n_chip_reset; } fc_port_t; +#define FC4_PRIORITY_NVME 0 +#define FC4_PRIORITY_FCP 1 + #define QLA_FCPORT_SCAN 1 #define QLA_FCPORT_FOUND 2 @@ -4291,6 +4294,8 @@ struct qla_hw_data { atomic_t nvme_active_aen_cnt; uint16_t nvme_last_rptd_aen; /* Last recorded aen count */ + uint8_t fc4_type_priority; + atomic_t zio_threshold; uint16_t last_zio_threshold; @@ -4816,6 +4821,23 @@ struct sff_8247_a0 { ha->current_topology == ISP_CFG_N || \ !ha->current_topology) +#define NVME_TYPE(fcport) \ + (fcport->fc4_type & FS_FC4TYPE_NVME) \ + +#define FCP_TYPE(fcport) \ + (fcport->fc4_type & FS_FC4TYPE_FCP) \ + +#define NVME_ONLY_TARGET(fcport) \ + (NVME_TYPE(fcport) && !FCP_TYPE(fcport)) \ + +#define NVME_FCP_TARGET(fcport) \ + (FCP_TYPE(fcport) && NVME_TYPE(fcport)) \ + +#define NVME_TARGET(ha, fcport) \ + ((NVME_FCP_TARGET(fcport) && \ + (ha->fc4_type_priority == FC4_PRIORITY_NVME)) || \ + NVME_ONLY_TARGET(fcport)) \ + #include "qla_target.h" #include "qla_gbl.h" #include "qla_dbg.h" diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 732bb871c433..59f6903e5abe 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -2101,4 +2101,6 @@ struct qla_fcp_prio_cfg { #define FA_FLASH_LAYOUT_ADDR_83 (0x3F1000/4) #define FA_FLASH_LAYOUT_ADDR_28 (0x11000/4) +#define NVRAM_DUAL_FCP_NVME_FLAG_OFFSET 0x196 + #endif diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 5298ed10059f..5b5ac09f38db 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -248,7 +248,7 @@ qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) WWN_SIZE); fcport->fc4_type = (ct_rsp->rsp.ga_nxt.fc4_types[2] & BIT_0) ? - FC4_TYPE_FCP_SCSI : FC4_TYPE_OTHER; + FS_FC4TYPE_FCP : FC4_TYPE_OTHER; if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE && ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE) @@ -2887,7 +2887,7 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) struct ct_sns_req *ct_req; struct ct_sns_rsp *ct_rsp; struct qla_hw_data *ha = vha->hw; - uint8_t fcp_scsi_features = 0; + uint8_t fcp_scsi_features = 0, nvme_features = 0; struct ct_arg arg; for (i = 0; i < ha->max_fibre_devices; i++) { @@ -2933,14 +2933,19 @@ qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; fcp_scsi_features &= 0x0f; - if (fcp_scsi_features) - list[i].fc4_type = FC4_TYPE_FCP_SCSI; - else - list[i].fc4_type = FC4_TYPE_OTHER; + if (fcp_scsi_features) { + list[i].fc4_type = FS_FC4TYPE_FCP; + list[i].fc4_features = fcp_scsi_features; + } - list[i].fc4f_nvme = + nvme_features = ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; - list[i].fc4f_nvme &= 0xf; + nvme_features &= 0xf; + + if (nvme_features) { + list[i].fc4_type |= FS_FC4TYPE_NVME; + list[i].fc4_features = nvme_features; + } } /* Last device exit. */ @@ -3435,6 +3440,8 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res) fc_port_t *fcport = sp->fcport; struct ct_sns_rsp *ct_rsp; struct event_arg ea; + uint8_t fc4_scsi_feat; + uint8_t fc4_nvme_feat; ql_dbg(ql_dbg_disc, vha, 0x2133, "Async done-%s res %x ID %x. %8phC\n", @@ -3442,24 +3449,25 @@ void qla24xx_async_gffid_sp_done(srb_t *sp, int res) fcport->flags &= ~FCF_ASYNC_SENT; ct_rsp = &fcport->ct_desc.ct_sns->p.rsp; + fc4_scsi_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; + fc4_nvme_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; + /* * FC-GS-7, 5.2.3.12 FC-4 Features - format * The format of the FC-4 Features object, as defined by the FC-4, * Shall be an array of 4-bit values, one for each type code value */ if (!res) { - if (ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET] & 0xf) { + if (fc4_scsi_feat & 0xf) { /* w1 b00:03 */ - fcport->fc4_type = - ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; - fcport->fc4_type &= 0xf; - } + fcport->fc4_type = FS_FC4TYPE_FCP; + fcport->fc4_features = fc4_scsi_feat & 0xf; + } - if (ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET] & 0xf) { + if (fc4_nvme_feat & 0xf) { /* w5 [00:03]/28h */ - fcport->fc4f_nvme = - ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; - fcport->fc4f_nvme &= 0xf; + fcport->fc4_type |= FS_FC4TYPE_NVME; + fcport->fc4_features = fc4_nvme_feat & 0xf; } } diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 1d041313ec52..7cb7545de962 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -328,7 +328,7 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, else lio->u.logio.flags |= SRB_LOGIN_COND_PLOGI; - if (fcport->fc4f_nvme) + if (NVME_TARGET(vha->hw, fcport)) lio->u.logio.flags |= SRB_LOGIN_SKIP_PRLI; ql_dbg(ql_dbg_disc, vha, 0x2072, @@ -726,19 +726,17 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, loop_id = le16_to_cpu(e->nport_handle); loop_id = (loop_id & 0x7fff); - if (fcport->fc4f_nvme) + if (NVME_TARGET(vha->hw, fcport)) current_login_state = e->current_login_state >> 4; else current_login_state = e->current_login_state & 0xf; - ql_dbg(ql_dbg_disc, vha, 0x20e2, - "%s found %8phC CLS [%x|%x] nvme %d ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", + "%s found %8phC CLS [%x|%x] fc4_type %d ID[%06x|%06x] lid[%d|%d]\n", __func__, fcport->port_name, e->current_login_state, fcport->fw_login_state, - fcport->fc4f_nvme, id.b.domain, id.b.area, id.b.al_pa, - fcport->d_id.b.domain, fcport->d_id.b.area, - fcport->d_id.b.al_pa, loop_id, fcport->loop_id); + fcport->fc4_type, id.b24, fcport->d_id.b24, + loop_id, fcport->loop_id); switch (fcport->disc_state) { case DSC_DELETE_PEND: @@ -1225,13 +1223,13 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) sp->done = qla2x00_async_prli_sp_done; lio->u.logio.flags = 0; - if (fcport->fc4f_nvme) + if (NVME_TARGET(vha->hw, fcport)) lio->u.logio.flags |= SRB_LOGIN_NVME_PRLI; ql_dbg(ql_dbg_disc, vha, 0x211b, "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d %s.\n", fcport->port_name, sp->handle, fcport->loop_id, fcport->d_id.b24, - fcport->login_retry, fcport->fc4f_nvme ? "nvme" : "fc"); + fcport->login_retry, NVME_TARGET(vha->hw, fcport) ? "nvme" : "fc"); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { @@ -1382,14 +1380,14 @@ void qla24xx_handle_gpdb_event(scsi_qla_host_t *vha, struct event_arg *ea) fcport->flags &= ~FCF_ASYNC_SENT; ql_dbg(ql_dbg_disc, vha, 0x20d2, - "%s %8phC DS %d LS %d nvme %x rc %d\n", __func__, fcport->port_name, - fcport->disc_state, pd->current_login_state, fcport->fc4f_nvme, - ea->rc); + "%s %8phC DS %d LS %d fc4_type %x rc %d\n", __func__, + fcport->port_name, fcport->disc_state, pd->current_login_state, + fcport->fc4_type, ea->rc); if (fcport->disc_state == DSC_DELETE_PEND) return; - if (fcport->fc4f_nvme) + if (NVME_TARGET(vha->hw, fcport)) ls = pd->current_login_state >> 4; else ls = pd->current_login_state & 0xf; @@ -1578,7 +1576,8 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) ql_dbg(ql_dbg_disc, vha, 0x2118, "%s %d %8phC post %s PRLI\n", __func__, __LINE__, fcport->port_name, - fcport->fc4f_nvme ? "NVME" : "FC"); + NVME_TARGET(vha->hw, fcport) ? "NVME" : + "FC"); qla24xx_post_prli_work(vha, fcport); } break; @@ -1860,13 +1859,22 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) break; } - if (ea->fcport->fc4f_nvme) { + /* + * Retry PRLI with other FC-4 type if failure occurred on dual + * FCP/NVMe port + */ + if (NVME_FCP_TARGET(ea->fcport)) { + if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME) + ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME; + else + ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP; ql_dbg(ql_dbg_disc, vha, 0x2118, - "%s %d %8phC post fc4 prli\n", - __func__, __LINE__, ea->fcport->port_name); - ea->fcport->fc4f_nvme = 0; + "%s %d %8phC post %s prli\n", + __func__, __LINE__, ea->fcport->port_name, + (ea->fcport->fc4_type & FS_FC4TYPE_NVME) ? + "NVMe" : "FCP"); qla24xx_post_prli_work(vha, ea->fcport); - return; + break; } /* at this point both PRLI NVME & PRLI FCP failed */ @@ -1952,7 +1960,7 @@ qla24xx_handle_plogi_done_event(struct scsi_qla_host *vha, struct event_arg *ea) * force a relogin attempt via implicit LOGO, PLOGI, and PRLI * requests. */ - if (ea->fcport->fc4f_nvme) { + if (NVME_TARGET(vha->hw, ea->fcport)) { ql_dbg(ql_dbg_disc, vha, 0x2117, "%s %d %8phC post prli\n", __func__, __LINE__, ea->fcport->port_name); @@ -5382,7 +5390,7 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) qla2x00_iidma_fcport(vha, fcport); - if (fcport->fc4f_nvme) { + if (NVME_TARGET(vha->hw, fcport)) { qla_nvme_register_remote(vha, fcport); fcport->disc_state = DSC_LOGIN_COMPLETE; qla2x00_set_fcport_state(fcport, FCS_ONLINE); @@ -5710,11 +5718,8 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) new_fcport->fc4_type = swl[swl_idx].fc4_type; new_fcport->nvme_flag = 0; - new_fcport->fc4f_nvme = 0; if (vha->flags.nvme_enabled && - swl[swl_idx].fc4f_nvme) { - new_fcport->fc4f_nvme = - swl[swl_idx].fc4f_nvme; + swl[swl_idx].fc4_type & FS_FC4TYPE_NVME) { ql_log(ql_log_info, vha, 0x2131, "FOUND: NVME port %8phC as FC Type 28h\n", new_fcport->port_name); @@ -5770,7 +5775,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) /* Bypass ports whose FCP-4 type is not FCP_SCSI */ if (ql2xgffidenable && - (new_fcport->fc4_type != FC4_TYPE_FCP_SCSI && + (!(new_fcport->fc4_type & FS_FC4TYPE_FCP) && new_fcport->fc4_type != FC4_TYPE_UNKNOWN)) continue; @@ -5839,7 +5844,7 @@ qla2x00_find_all_fabric_devs(scsi_qla_host_t *vha) break; } - if (fcport->fc4f_nvme) { + if (NVME_TARGET(vha->hw, fcport)) { if (fcport->disc_state == DSC_DELETE_PEND) { fcport->disc_state = DSC_GNL; vha->fcport_count--; @@ -8514,6 +8519,11 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* N2N: driver will initiate Login instead of FW */ icb->firmware_options_3 |= BIT_8; + /* Determine NVMe/FCP priority for target ports */ + ha->fc4_type_priority = qla2xxx_get_fc4_priority(vha); + ql_log(ql_log_info, vha, 0xffff, "FC4 priority set to %s\n", + ha->fc4_type_priority & BIT_0 ? "FCP" : "NVMe"); + if (rval) { ql_log(ql_log_warn, vha, 0x0076, "NVRAM configuration failed.\n"); diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 0c3d907af769..d728b179e347 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -307,3 +307,15 @@ qla_83xx_start_iocbs(struct qla_qpair *qpair) WRT_REG_DWORD(req->req_q_in, req->ring_index); } + +static inline int +qla2xxx_get_fc4_priority(struct scsi_qla_host *vha) +{ + uint32_t data; + + data = + ((uint8_t *)vha->hw->nvram)[NVRAM_DUAL_FCP_NVME_FLAG_OFFSET]; + + + return ((data >> 6) & BIT_0); +} diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 1cc6913f76c4..d4d75bcdac73 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1931,7 +1931,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) pd24 = (struct port_database_24xx *) pd; /* Check for logged in state. */ - if (fcport->fc4f_nvme) { + if (NVME_TARGET(ha, fcport)) { current_login_state = pd24->current_login_state >> 4; last_login_state = pd24->last_login_state >> 4; } else { @@ -3898,8 +3898,9 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, fcport->scan_state = QLA_FCPORT_FOUND; fcport->n2n_flag = 1; fcport->keep_nport_handle = 1; + fcport->fc4_type = FS_FC4TYPE_FCP; if (vha->flags.nvme_enabled) - fcport->fc4f_nvme = 1; + fcport->fc4_type |= FS_FC4TYPE_NVME; switch (fcport->disc_state) { case DSC_DELETED: @@ -6361,7 +6362,7 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, uint64_t zero = 0; u8 current_login_state, last_login_state; - if (fcport->fc4f_nvme) { + if (NVME_TARGET(vha->hw, fcport)) { current_login_state = pd->current_login_state >> 4; last_login_state = pd->last_login_state >> 4; } else { @@ -6396,8 +6397,8 @@ int __qla24xx_parse_gpdb(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->d_id.b.al_pa = pd->port_id[2]; fcport->d_id.b.rsvd_1 = 0; - if (fcport->fc4f_nvme) { - fcport->port_type = 0; + if (NVME_TARGET(vha->hw, fcport)) { + fcport->port_type = FCT_NVME; if ((pd->prli_svc_param_word_3[0] & BIT_5) == 0) fcport->port_type |= FCT_NVME_INITIATOR; if ((pd->prli_svc_param_word_3[0] & BIT_4) == 0) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 3568031c6504..eae631775a76 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -5032,19 +5032,17 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->d_id = e->u.new_sess.id; fcport->flags |= FCF_FABRIC_DEVICE; fcport->fw_login_state = DSC_LS_PLOGI_PEND; - if (e->u.new_sess.fc4_type == FS_FC4TYPE_FCP) - fcport->fc4_type = FC4_TYPE_FCP_SCSI; - - if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) { - fcport->fc4_type = FC4_TYPE_OTHER; - fcport->fc4f_nvme = FC4_TYPE_NVME; - } memcpy(fcport->port_name, e->u.new_sess.port_name, WWN_SIZE); - if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N) + fcport->fc4_type = e->u.new_sess.fc4_type; + if (e->u.new_sess.fc4_type & FS_FCP_IS_N2N) { + fcport->fc4_type = FS_FC4TYPE_FCP; fcport->n2n_flag = 1; + if (vha->flags.nvme_enabled) + fcport->fc4_type |= FS_FC4TYPE_NVME; + } } else { ql_dbg(ql_dbg_disc, vha, 0xffff, @@ -5148,7 +5146,8 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) fcport->flags &= ~FCF_FABRIC_DEVICE; fcport->keep_nport_handle = 1; if (vha->flags.nvme_enabled) { - fcport->fc4f_nvme = 1; + fcport->fc4_type = + (FS_FC4TYPE_NVME | FS_FC4TYPE_FCP); fcport->n2n_flag = 1; } fcport->fw_login_state = 0; -- cgit v1.2.3 From c76ae845ea836d6128982dcbd41ac35c81e2de63 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 12 Sep 2019 11:09:13 -0700 Subject: scsi: qla2xxx: Add error handling for PLOGI ELS passthrough Add error handling logic to ELS Passthrough relating to NVME devices. Current code does not parse error code to take proper recovery action, instead it re-logins with the same login parameters that encountered the error. Ex: nport handle collision. Link: https://lore.kernel.org/r/20190912180918.6436-10-hmadhani@marvell.com Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_iocb.c | 95 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 518eb954cf42..eeb526411536 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2740,6 +2740,10 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) struct scsi_qla_host *vha = sp->vha; struct event_arg ea; struct qla_work_evt *e; + struct fc_port *conflict_fcport; + port_id_t cid; /* conflict Nport id */ + u32 *fw_status = sp->u.iocb_cmd.u.els_plogi.fw_status; + u16 lid; ql_dbg(ql_dbg_disc, vha, 0x3072, "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n", @@ -2751,14 +2755,99 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) if (sp->flags & SRB_WAKEUP_ON_COMP) complete(&lio->u.els_plogi.comp); else { - if (res) { - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); - } else { + switch (fw_status[0]) { + case CS_DATA_UNDERRUN: + case CS_COMPLETE: memset(&ea, 0, sizeof(ea)); ea.fcport = fcport; ea.data[0] = MBS_COMMAND_COMPLETE; ea.sp = sp; qla24xx_handle_plogi_done_event(vha, &ea); + break; + case CS_IOCB_ERROR: + switch (fw_status[1]) { + case LSC_SCODE_PORTID_USED: + lid = fw_status[2] & 0xffff; + qlt_find_sess_invalidate_other(vha, + wwn_to_u64(fcport->port_name), + fcport->d_id, lid, &conflict_fcport); + if (conflict_fcport) { + /* + * Another fcport shares the same + * loop_id & nport id; conflict + * fcport needs to finish cleanup + * before this fcport can proceed + * to login. + */ + conflict_fcport->conflict = fcport; + fcport->login_pause = 1; + ql_dbg(ql_dbg_disc, vha, 0x20ed, + "%s %d %8phC pid %06x inuse with lid %#x post gidpn\n", + __func__, __LINE__, + fcport->port_name, + fcport->d_id.b24, lid); + } else { + ql_dbg(ql_dbg_disc, vha, 0x20ed, + "%s %d %8phC pid %06x inuse with lid %#x sched del\n", + __func__, __LINE__, + fcport->port_name, + fcport->d_id.b24, lid); + qla2x00_clear_loop_id(fcport); + set_bit(lid, vha->hw->loop_id_map); + fcport->loop_id = lid; + fcport->keep_nport_handle = 0; + qlt_schedule_sess_for_deletion(fcport); + } + break; + + case LSC_SCODE_NPORT_USED: + cid.b.domain = (fw_status[2] >> 16) & 0xff; + cid.b.area = (fw_status[2] >> 8) & 0xff; + cid.b.al_pa = fw_status[2] & 0xff; + cid.b.rsvd_1 = 0; + + ql_dbg(ql_dbg_disc, vha, 0x20ec, + "%s %d %8phC lid %#x in use with pid %06x post gnl\n", + __func__, __LINE__, fcport->port_name, + fcport->loop_id, cid.b24); + set_bit(fcport->loop_id, + vha->hw->loop_id_map); + fcport->loop_id = FC_NO_LOOP_ID; + qla24xx_post_gnl_work(vha, fcport); + break; + + case LSC_SCODE_NOXCB: + vha->hw->exch_starvation++; + if (vha->hw->exch_starvation > 5) { + ql_log(ql_log_warn, vha, 0xd046, + "Exchange starvation. Resetting RISC\n"); + vha->hw->exch_starvation = 0; + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } + /* fall through */ + default: + ql_dbg(ql_dbg_disc, vha, 0x20eb, + "%s %8phC cmd error fw_status 0x%x 0x%x 0x%x\n", + __func__, sp->fcport->port_name, + fw_status[0], fw_status[1], fw_status[2]); + + fcport->flags &= ~FCF_ASYNC_SENT; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + break; + } + break; + + default: + ql_dbg(ql_dbg_disc, vha, 0x20eb, + "%s %8phC cmd error 2 fw_status 0x%x 0x%x 0x%x\n", + __func__, sp->fcport->port_name, + fw_status[0], fw_status[1], fw_status[2]); + + sp->fcport->flags &= ~FCF_ASYNC_SENT; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + break; } e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); -- cgit v1.2.3 From 6997db98d00a659d05cda23bd33c34aff546635b Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 12 Sep 2019 11:09:14 -0700 Subject: scsi: qla2xxx: Set remove flag for all VP During driver unload, the remove flag will be set for all scsi_qla_host/NPIV. This allows each NPIV to see the flag instead of reaching for base_vha to search for it. Link: https://lore.kernel.org/r/20190912180918.6436-11-hmadhani@marvell.com Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index eae631775a76..16f9b6ed574a 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -3486,6 +3486,29 @@ disable_device: return ret; } +static void __qla_set_remove_flag(scsi_qla_host_t *base_vha) +{ + scsi_qla_host_t *vp; + unsigned long flags; + struct qla_hw_data *ha; + + if (!base_vha) + return; + + ha = base_vha->hw; + + spin_lock_irqsave(&ha->vport_slock, flags); + list_for_each_entry(vp, &ha->vp_list, list) + set_bit(PFLG_DRIVER_REMOVING, &vp->pci_flags); + + /* + * Indicate device removal to prevent future board_disable + * and wait until any pending board_disable has completed. + */ + set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags); + spin_unlock_irqrestore(&ha->vport_slock, flags); +} + static void qla2x00_shutdown(struct pci_dev *pdev) { @@ -3502,7 +3525,7 @@ qla2x00_shutdown(struct pci_dev *pdev) * Prevent future board_disable and wait * until any pending board_disable has completed. */ - set_bit(PFLG_DRIVER_REMOVING, &vha->pci_flags); + __qla_set_remove_flag(vha); cancel_work_sync(&ha->board_disable); if (!atomic_read(&pdev->enable_cnt)) @@ -3658,10 +3681,7 @@ qla2x00_remove_one(struct pci_dev *pdev) ha = base_vha->hw; ql_log(ql_log_info, base_vha, 0xb079, "Removing driver\n"); - - /* Indicate device removal to prevent future board_disable and wait - * until any pending board_disable has completed. */ - set_bit(PFLG_DRIVER_REMOVING, &base_vha->pci_flags); + __qla_set_remove_flag(base_vha); cancel_work_sync(&ha->board_disable); /* -- cgit v1.2.3 From c55474197a2e29fd0858fb9678db1628f4a39861 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 12 Sep 2019 11:09:15 -0700 Subject: scsi: qla2xxx: Check for MB timeout while capturing ISP27/28xx FW dump Add mailbox timeout checkout for ISP 27xx/28xx during FW dump procedure. Without the timeout check, hardware lock can be held for long period. This patch would shorten the dump procedure if a timeout condition is encountered. Link: https://lore.kernel.org/r/20190912180918.6436-12-hmadhani@marvell.com Reviewed-by: Laurence Oberman Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_tmpl.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index 294d77c02cdf..b948d94c8b3c 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -10,6 +10,7 @@ #define ISPREG(vha) (&(vha)->hw->iobase->isp24) #define IOBAR(reg) offsetof(typeof(*(reg)), iobase_addr) #define IOBASE(vha) IOBAR(ISPREG(vha)) +#define INVALID_ENTRY ((struct qla27xx_fwdt_entry *)0xffffffffffffffffUL) static inline void qla27xx_insert16(uint16_t value, void *buf, ulong *len) @@ -261,6 +262,7 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, ulong start = le32_to_cpu(ent->t262.start_addr); ulong end = le32_to_cpu(ent->t262.end_addr); ulong dwords; + int rc; ql_dbg(ql_dbg_misc, vha, 0xd206, "%s: rdram(%x) [%lx]\n", __func__, ent->t262.ram_area, *len); @@ -308,7 +310,13 @@ qla27xx_fwdt_entry_t262(struct scsi_qla_host *vha, dwords = end - start + 1; if (buf) { buf += *len; - qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf); + rc = qla24xx_dump_ram(vha->hw, start, buf, dwords, &buf); + if (rc != QLA_SUCCESS) { + ql_dbg(ql_dbg_async, vha, 0xffff, + "%s: dump ram MB failed. Area %xh start %lxh end %lxh\n", + __func__, area, start, end); + return INVALID_ENTRY; + } } *len += dwords * sizeof(uint32_t); done: @@ -838,6 +846,13 @@ qla27xx_walk_template(struct scsi_qla_host *vha, ent = qla27xx_find_entry(type)(vha, ent, buf, len); if (!ent) break; + + if (ent == INVALID_ENTRY) { + *len = 0; + ql_dbg(ql_dbg_async, vha, 0xffff, + "Unable to capture FW dump"); + goto bailout; + } } if (tmp->count) @@ -847,6 +862,9 @@ qla27xx_walk_template(struct scsi_qla_host *vha, if (ent) ql_dbg(ql_dbg_misc, vha, 0xd019, "%s: missing end entry\n", __func__); + +bailout: + cpu_to_le32s(&tmp->count); /* endianize residual count */ } static void @@ -1010,7 +1028,9 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) } len = qla27xx_execute_fwdt_template(vha, fwdt->template, buf); - if (len != fwdt->dump_size) { + if (len == 0) { + goto bailout; + } else if (len != fwdt->dump_size) { ql_log(ql_log_warn, vha, 0xd013, "-> fwdt%u fwdump residual=%+ld\n", j, fwdt->dump_size - len); @@ -1025,6 +1045,7 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP); } +bailout: #ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); -- cgit v1.2.3 From d52cd7747d905f5b2a6ec07d5f6abe8720969dc5 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Thu, 12 Sep 2019 11:09:16 -0700 Subject: scsi: qla2xxx: Capture FW dump on MPI heartbeat stop event For MPI heartbeat stop Async Event, this patch would capture MPI FW dump and chip reset. FW will tell which function to capture FW dump for. Link: https://lore.kernel.org/r/20190912180918.6436-13-hmadhani@marvell.com Reviewed-by: Laurence Oberman Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_attr.c | 4 +++- drivers/scsi/qla2xxx/qla_isr.c | 31 ++++++++++++++++++++++++++----- drivers/scsi/qla2xxx/qla_tmpl.c | 4 +++- 3 files changed, 32 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_attr.c b/drivers/scsi/qla2xxx/qla_attr.c index 30bafd9d21e9..481c05dbea06 100644 --- a/drivers/scsi/qla2xxx/qla_attr.c +++ b/drivers/scsi/qla2xxx/qla_attr.c @@ -102,8 +102,10 @@ qla2x00_sysfs_write_fw_dump(struct file *filp, struct kobject *kobj, qla8044_idc_lock(ha); qla82xx_set_reset_owner(vha); qla8044_idc_unlock(ha); - } else + } else { + ha->fw_dump_mpi = 1; qla2x00_system_error(vha); + } break; case 4: if (IS_P3P_TYPE(ha)) { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 009fd5a33fcd..acef3d73983c 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1227,11 +1227,32 @@ global_port_update: break; case MBA_IDC_AEN: - mb[4] = RD_REG_WORD(®24->mailbox4); - mb[5] = RD_REG_WORD(®24->mailbox5); - mb[6] = RD_REG_WORD(®24->mailbox6); - mb[7] = RD_REG_WORD(®24->mailbox7); - qla83xx_handle_8200_aen(vha, mb); + if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) { + ha->flags.fw_init_done = 0; + ql_log(ql_log_warn, vha, 0xffff, + "MPI Heartbeat stop. Chip reset needed. MB0[%xh] MB1[%xh] MB2[%xh] MB3[%xh]\n", + mb[0], mb[1], mb[2], mb[3]); + + if ((mb[1] & BIT_8) || + (mb[2] & BIT_8)) { + ql_log(ql_log_warn, vha, 0xd013, + "MPI Heartbeat stop. FW dump needed\n"); + ha->fw_dump_mpi = 1; + ha->isp_ops->fw_dump(vha, 1); + } + set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags); + qla2xxx_wake_dpc(vha); + } else if (IS_QLA83XX(ha)) { + mb[4] = RD_REG_WORD(®24->mailbox4); + mb[5] = RD_REG_WORD(®24->mailbox5); + mb[6] = RD_REG_WORD(®24->mailbox6); + mb[7] = RD_REG_WORD(®24->mailbox7); + qla83xx_handle_8200_aen(vha, mb); + } else { + ql_dbg(ql_dbg_async, vha, 0x5052, + "skip Heartbeat processing mb0-3=[0x%04x] [0x%04x] [0x%04x] [0x%04x]\n", + mb[0], mb[1], mb[2], mb[3]); + } break; case MBA_DPORT_DIAGNOSTICS: diff --git a/drivers/scsi/qla2xxx/qla_tmpl.c b/drivers/scsi/qla2xxx/qla_tmpl.c index b948d94c8b3c..5b0c057def2b 100644 --- a/drivers/scsi/qla2xxx/qla_tmpl.c +++ b/drivers/scsi/qla2xxx/qla_tmpl.c @@ -1017,8 +1017,9 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) uint j; ulong len; void *buf = vha->hw->fw_dump; + uint count = vha->hw->fw_dump_mpi ? 2 : 1; - for (j = 0; j < 2; j++, fwdt++, buf += len) { + for (j = 0; j < count; j++, fwdt++, buf += len) { ql_log(ql_log_warn, vha, 0xd011, "-> fwdt%u running...\n", j); if (!fwdt->template) { @@ -1046,6 +1047,7 @@ qla27xx_fwdump(scsi_qla_host_t *vha, int hardware_locked) } bailout: + vha->hw->fw_dump_mpi = 0; #ifndef __CHECKER__ if (!hardware_locked) spin_unlock_irqrestore(&vha->hw->hardware_lock, flags); -- cgit v1.2.3 From 45c96e442f52c4890f7fceeda9496a5900909aa5 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Thu, 12 Sep 2019 11:09:17 -0700 Subject: scsi: qla2xxx: Improve logging for scan thread Move messages to verbose logging for scan thread. Link: https://lore.kernel.org/r/20190912180918.6436-14-hmadhani@marvell.com Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 5b5ac09f38db..7a00272ca380 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3571,7 +3571,7 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) u8 recheck = 0; u16 dup = 0, dup_cnt = 0; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, "%s enter\n", __func__); if (sp->gen1 != vha->hw->base_qpair->chip_reset) { @@ -3588,8 +3588,9 @@ void qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); } else { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "Fabric scan failed on all retries.\n"); + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, + "%s: Fabric scan failed for %d retries.\n", + __func__, vha->scan.scan_retry); } goto out; } @@ -4055,7 +4056,7 @@ done_free_sp: void qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, "%s enter\n", __func__); qla24xx_async_gnnft(vha, sp, sp->gen2); } @@ -4069,7 +4070,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) u32 rspsz; unsigned long flags; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, "%s enter\n", __func__); if (!vha->flags.online) @@ -4078,14 +4079,15 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) spin_lock_irqsave(&vha->work_lock, flags); if (vha->scan.scan_flags & SF_SCANNING) { spin_unlock_irqrestore(&vha->work_lock, flags); - ql_dbg(ql_dbg_disc, vha, 0xffff, "scan active\n"); + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, + "%s: scan active\n", __func__); return rval; } vha->scan.scan_flags |= SF_SCANNING; spin_unlock_irqrestore(&vha->work_lock, flags); if (fc4_type == FC4_TYPE_FCP_SCSI) { - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, "%s: Performing FCP Scan\n", __func__); if (sp) @@ -4140,7 +4142,7 @@ int qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) } sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz; - ql_dbg(ql_dbg_disc, vha, 0xffff, + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, "%s scan list size %d\n", __func__, vha->scan.size); memset(vha->scan.l, 0, vha->scan.size); @@ -4205,8 +4207,8 @@ done_free_sp: spin_lock_irqsave(&vha->work_lock, flags); vha->scan.scan_flags &= ~SF_SCANNING; if (vha->scan.scan_flags == 0) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s: schedule\n", __func__); + ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, + "%s: Scan scheduled.\n", __func__); vha->scan.scan_flags |= SF_QUEUED; schedule_delayed_work(&vha->scan.scan_work, 5); } -- cgit v1.2.3 From 8ae15a460b1471622f85bad6caebe56fd91f4f83 Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Thu, 12 Sep 2019 11:09:18 -0700 Subject: scsi: qla2xxx: Update driver version to 10.01.00.20-k Link: https://lore.kernel.org/r/20190912180918.6436-15-hmadhani@marvell.com Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index a8f2a953ceff..225e401b62fa 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.01.00.19-k" +#define QLA2XXX_VERSION "10.01.00.20-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 1 -- cgit v1.2.3 From c51c4841f1571673d9075b8cf5efa6995ea91d0e Mon Sep 17 00:00:00 2001 From: Masahiro Yamada Date: Mon, 29 Jul 2019 01:46:43 +0900 Subject: scsi: ch: add include guard to chio.h Add a header include guard just in case. Link: https://lore.kernel.org/r/20190728164643.16335-1-yamada.masahiro@socionext.com Signed-off-by: Masahiro Yamada Signed-off-by: Martin K. Petersen --- include/uapi/linux/chio.h | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/include/uapi/linux/chio.h b/include/uapi/linux/chio.h index 689fc93fafda..e1cad4c319ee 100644 --- a/include/uapi/linux/chio.h +++ b/include/uapi/linux/chio.h @@ -3,6 +3,9 @@ * ioctl interface for the scsi media changer driver */ +#ifndef _UAPI_LINUX_CHIO_H +#define _UAPI_LINUX_CHIO_H + /* changer element types */ #define CHET_MT 0 /* media transport element (robot) */ #define CHET_ST 1 /* storage element (media slots) */ @@ -160,10 +163,4 @@ struct changer_set_voltag { #define CHIOSVOLTAG _IOW('c',18,struct changer_set_voltag) #define CHIOGVPARAMS _IOR('c',19,struct changer_vendor_params) -/* ---------------------------------------------------------------------- */ - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ +#endif /* _UAPI_LINUX_CHIO_H */ -- cgit v1.2.3 From f7cb0d0945ebc9879aff72cf7b3342fd1040ffaa Mon Sep 17 00:00:00 2001 From: zhengbin Date: Fri, 4 Oct 2019 18:04:37 +0800 Subject: scsi: lpfc: Make function lpfc_defer_pt2pt_acc static Fix sparse warnings: drivers/scsi/lpfc/lpfc_nportdisc.c:290:1: warning: symbol 'lpfc_defer_pt2pt_acc' was not declared. Should it be static? Link: https://lore.kernel.org/r/1570183477-137273-1-git-send-email-zhengbin13@huawei.com Reported-by: Hulk Robot Signed-off-by: zhengbin Reviewed-by: Dick Kennedy Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nportdisc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 4e96d28cba39..cc6b1b0bae83 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -286,7 +286,7 @@ lpfc_els_abort(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) * This routine is only called if we are SLI3, direct connect pt2pt * mode and the remote NPort issues the PLOGI after link up. */ -void +static void lpfc_defer_pt2pt_acc(struct lpfc_hba *phba, LPFC_MBOXQ_t *link_mbox) { LPFC_MBOXQ_t *login_mbox; -- cgit v1.2.3 From 3524a38e594dd5f090cbc3226e5f47cb4067fac7 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Fri, 4 Oct 2019 13:06:15 +0300 Subject: scsi: mpt3sas: Clean up some indenting This line is indented too far so it's a bit confusing. Link: https://lore.kernel.org/r/20191004100615.GA823@mwanda Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_ctl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c index 0c77f2209cec..6874cf017739 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c +++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c @@ -1821,7 +1821,7 @@ mpt3sas_enable_diag_buffer(struct MPT3SAS_ADAPTER *ioc, u8 bits_to_register) trace_buff_size>>10); ioc_err(ioc, "Using zero Min Trace Buff Size\n"); - min_trace_buff_size = 0; + min_trace_buff_size = 0; } if (decr_trace_buff_size == 0) { -- cgit v1.2.3 From 0530736e40a0695b1ee2762e2684d00549699da4 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Mon, 7 Oct 2019 17:31:23 -0500 Subject: scsi: smartpqi: fix controller lockup observed during force reboot Link: https://lore.kernel.org/r/157048748297.11757.3872221216800537383.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 9 ++- drivers/scsi/smartpqi/smartpqi_init.c | 126 +++++++++++++++++++++++++++++----- 2 files changed, 115 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 79d2af36f655..2aa81b22f269 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -1130,8 +1130,9 @@ struct pqi_ctrl_info { struct mutex ofa_mutex; /* serialize ofa */ bool controller_online; bool block_requests; - bool in_shutdown; + bool block_device_reset; bool in_ofa; + bool in_shutdown; u8 inbound_spanning_supported : 1; u8 outbound_spanning_supported : 1; u8 pqi_mode_enabled : 1; @@ -1173,6 +1174,7 @@ struct pqi_ctrl_info { struct pqi_ofa_memory *pqi_ofa_mem_virt_addr; dma_addr_t pqi_ofa_mem_dma_handle; void **pqi_ofa_chunk_virt_addr; + atomic_t sync_cmds_outstanding; }; enum pqi_ctrl_mode { @@ -1423,6 +1425,11 @@ static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info) return ctrl_info->block_requests; } +static inline bool pqi_device_reset_blocked(struct pqi_ctrl_info *ctrl_info) +{ + return ctrl_info->block_device_reset; +} + void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, struct sas_rphy *rphy); diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index e5c4202a862d..64924ad0cd6e 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -249,6 +249,11 @@ static inline void pqi_ctrl_unblock_requests(struct pqi_ctrl_info *ctrl_info) scsi_unblock_requests(ctrl_info->scsi_host); } +static inline void pqi_ctrl_block_device_reset(struct pqi_ctrl_info *ctrl_info) +{ + ctrl_info->block_device_reset = true; +} + static unsigned long pqi_wait_if_ctrl_blocked(struct pqi_ctrl_info *ctrl_info, unsigned long timeout_msecs) { @@ -331,6 +336,16 @@ static inline bool pqi_device_in_remove(struct pqi_ctrl_info *ctrl_info, return device->in_remove && !ctrl_info->in_shutdown; } +static inline void pqi_ctrl_shutdown_start(struct pqi_ctrl_info *ctrl_info) +{ + ctrl_info->in_shutdown = true; +} + +static inline bool pqi_ctrl_in_shutdown(struct pqi_ctrl_info *ctrl_info) +{ + return ctrl_info->in_shutdown; +} + static inline void pqi_schedule_rescan_worker_with_delay( struct pqi_ctrl_info *ctrl_info, unsigned long delay) { @@ -360,6 +375,11 @@ static inline void pqi_cancel_rescan_worker(struct pqi_ctrl_info *ctrl_info) cancel_delayed_work_sync(&ctrl_info->rescan_work); } +static inline void pqi_cancel_event_worker(struct pqi_ctrl_info *ctrl_info) +{ + cancel_work_sync(&ctrl_info->event_work); +} + static inline u32 pqi_read_heartbeat_counter(struct pqi_ctrl_info *ctrl_info) { if (!ctrl_info->heartbeat_counter) @@ -4119,6 +4139,8 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info, goto out; } + atomic_inc(&ctrl_info->sync_cmds_outstanding); + io_request = pqi_alloc_io_request(ctrl_info); put_unaligned_le16(io_request->index, @@ -4165,6 +4187,7 @@ static int pqi_submit_raid_request_synchronous(struct pqi_ctrl_info *ctrl_info, pqi_free_io_request(io_request); + atomic_dec(&ctrl_info->sync_cmds_outstanding); out: up(&ctrl_info->sync_request_sem); @@ -5399,7 +5422,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, pqi_ctrl_busy(ctrl_info); if (pqi_ctrl_blocked(ctrl_info) || pqi_device_in_reset(device) || - pqi_ctrl_in_ofa(ctrl_info)) { + pqi_ctrl_in_ofa(ctrl_info) || pqi_ctrl_in_shutdown(ctrl_info)) { rc = SCSI_MLQUEUE_HOST_BUSY; goto out; } @@ -5647,6 +5670,18 @@ static int pqi_ctrl_wait_for_pending_io(struct pqi_ctrl_info *ctrl_info, return 0; } +static int pqi_ctrl_wait_for_pending_sync_cmds(struct pqi_ctrl_info *ctrl_info) +{ + while (atomic_read(&ctrl_info->sync_cmds_outstanding)) { + pqi_check_ctrl_health(ctrl_info); + if (pqi_ctrl_offline(ctrl_info)) + return -ENXIO; + usleep_range(1000, 2000); + } + + return 0; +} + static void pqi_lun_reset_complete(struct pqi_io_request *io_request, void *context) { @@ -5784,17 +5819,17 @@ static int pqi_eh_device_reset_handler(struct scsi_cmnd *scmd) shost->host_no, device->bus, device->target, device->lun); pqi_check_ctrl_health(ctrl_info); - if (pqi_ctrl_offline(ctrl_info)) { - dev_err(&ctrl_info->pci_dev->dev, - "controller %u offlined - cannot send device reset\n", - ctrl_info->ctrl_id); + if (pqi_ctrl_offline(ctrl_info) || + pqi_device_reset_blocked(ctrl_info)) { rc = FAILED; goto out; } pqi_wait_until_ofa_finished(ctrl_info); + atomic_inc(&ctrl_info->sync_cmds_outstanding); rc = pqi_device_reset(ctrl_info, device); + atomic_dec(&ctrl_info->sync_cmds_outstanding); out: dev_err(&ctrl_info->pci_dev->dev, @@ -6116,7 +6151,8 @@ static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd, ctrl_info = shost_to_hba(sdev->host); - if (pqi_ctrl_in_ofa(ctrl_info)) + if (pqi_ctrl_in_ofa(ctrl_info) || + pqi_ctrl_in_shutdown(ctrl_info)) return -EBUSY; switch (cmd) { @@ -7065,13 +7101,20 @@ static int pqi_force_sis_mode(struct pqi_ctrl_info *ctrl_info) return pqi_revert_to_sis_mode(ctrl_info); } +#define PQI_POST_RESET_DELAY_B4_MSGU_READY 5000 + static int pqi_ctrl_init(struct pqi_ctrl_info *ctrl_info) { int rc; - rc = pqi_force_sis_mode(ctrl_info); - if (rc) - return rc; + if (reset_devices) { + sis_soft_reset(ctrl_info); + msleep(PQI_POST_RESET_DELAY_B4_MSGU_READY); + } else { + rc = pqi_force_sis_mode(ctrl_info); + if (rc) + return rc; + } /* * Wait until the controller is ready to start accepting SIS @@ -7505,6 +7548,7 @@ static struct pqi_ctrl_info *pqi_alloc_ctrl_info(int numa_node) INIT_WORK(&ctrl_info->event_work, pqi_event_worker); atomic_set(&ctrl_info->num_interrupts, 0); + atomic_set(&ctrl_info->sync_cmds_outstanding, 0); INIT_DELAYED_WORK(&ctrl_info->rescan_work, pqi_rescan_worker); INIT_DELAYED_WORK(&ctrl_info->update_time_work, pqi_update_time_worker); @@ -7778,8 +7822,6 @@ static int pqi_ofa_host_memory_update(struct pqi_ctrl_info *ctrl_info) 0, NULL, NO_TIMEOUT); } -#define PQI_POST_RESET_DELAY_B4_MSGU_READY 5000 - static int pqi_ofa_ctrl_restart(struct pqi_ctrl_info *ctrl_info) { msleep(PQI_POST_RESET_DELAY_B4_MSGU_READY); @@ -7947,28 +7989,74 @@ static void pqi_pci_remove(struct pci_dev *pci_dev) pqi_remove_ctrl(ctrl_info); } +static void pqi_crash_if_pending_command(struct pqi_ctrl_info *ctrl_info) +{ + unsigned int i; + struct pqi_io_request *io_request; + struct scsi_cmnd *scmd; + + for (i = 0; i < ctrl_info->max_io_slots; i++) { + io_request = &ctrl_info->io_request_pool[i]; + if (atomic_read(&io_request->refcount) == 0) + continue; + scmd = io_request->scmd; + WARN_ON(scmd != NULL); /* IO command from SML */ + WARN_ON(scmd == NULL); /* Non-IO cmd or driver initiated*/ + } +} + static void pqi_shutdown(struct pci_dev *pci_dev) { int rc; struct pqi_ctrl_info *ctrl_info; ctrl_info = pci_get_drvdata(pci_dev); - if (!ctrl_info) - goto error; + if (!ctrl_info) { + dev_err(&pci_dev->dev, + "cache could not be flushed\n"); + return; + } + + pqi_disable_events(ctrl_info); + pqi_wait_until_ofa_finished(ctrl_info); + pqi_cancel_update_time_worker(ctrl_info); + pqi_cancel_rescan_worker(ctrl_info); + pqi_cancel_event_worker(ctrl_info); + + pqi_ctrl_shutdown_start(ctrl_info); + pqi_ctrl_wait_until_quiesced(ctrl_info); + + rc = pqi_ctrl_wait_for_pending_io(ctrl_info, NO_TIMEOUT); + if (rc) { + dev_err(&pci_dev->dev, + "wait for pending I/O failed\n"); + return; + } + + pqi_ctrl_block_device_reset(ctrl_info); + pqi_wait_until_lun_reset_finished(ctrl_info); /* * Write all data in the controller's battery-backed cache to * storage. */ rc = pqi_flush_cache(ctrl_info, SHUTDOWN); - pqi_free_interrupts(ctrl_info); - pqi_reset(ctrl_info); - if (rc == 0) + if (rc) + dev_err(&pci_dev->dev, + "unable to flush controller cache\n"); + + pqi_ctrl_block_requests(ctrl_info); + + rc = pqi_ctrl_wait_for_pending_sync_cmds(ctrl_info); + if (rc) { + dev_err(&pci_dev->dev, + "wait for pending sync cmds failed\n"); return; + } + + pqi_crash_if_pending_command(ctrl_info); + pqi_reset(ctrl_info); -error: - dev_warn(&pci_dev->dev, - "unable to flush controller cache\n"); } static void pqi_process_lockup_action_param(void) -- cgit v1.2.3 From b969261134c1b990b96ea98fe5e0fcf8ec937c04 Mon Sep 17 00:00:00 2001 From: Murthy Bhat Date: Mon, 7 Oct 2019 17:31:28 -0500 Subject: scsi: smartpqi: fix call trace in device discovery Use sas_phy_delete rather than sas_phy_free which, according to comments, should not be called for PHYs that have been set up successfully. Link: https://lore.kernel.org/r/157048748876.11757.17773443136670011786.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Signed-off-by: Murthy Bhat Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_sas_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index 6776dfc1d317..b7e28b9f8589 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -45,9 +45,9 @@ static void pqi_free_sas_phy(struct pqi_sas_phy *pqi_sas_phy) struct sas_phy *phy = pqi_sas_phy->phy; sas_port_delete_phy(pqi_sas_phy->parent_port->port, phy); - sas_phy_free(phy); if (pqi_sas_phy->added_to_port) list_del(&pqi_sas_phy->phy_list_entry); + sas_phy_delete(phy); kfree(pqi_sas_phy); } -- cgit v1.2.3 From 21432010d5282a9aa4d0946816468849bd2fe1b5 Mon Sep 17 00:00:00 2001 From: koshyaji Date: Mon, 7 Oct 2019 17:31:34 -0500 Subject: scsi: smartpqi: add inquiry timeouts Add timeout field in RAID IU. Link: https://lore.kernel.org/r/157048749461.11757.10013040278241807855.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Signed-off-by: koshyaji Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 6 +++++- drivers/scsi/smartpqi/smartpqi_init.c | 34 ++++++++++++++++++++++++++++------ 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 2aa81b22f269..af0662b8a09c 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -276,7 +276,9 @@ struct pqi_raid_path_request { u8 reserved4 : 2; u8 additional_cdb_bytes_usage : 3; u8 reserved5 : 3; - u8 cdb[32]; + u8 cdb[16]; + u8 reserved6[12]; + __le32 timeout; struct pqi_sg_descriptor sg_descriptors[PQI_MAX_EMBEDDED_SG_DESCRIPTORS]; }; @@ -761,6 +763,7 @@ struct pqi_config_table_firmware_features { #define PQI_FIRMWARE_FEATURE_OFA 0 #define PQI_FIRMWARE_FEATURE_SMP 1 #define PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE 11 +#define PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT 13 struct pqi_config_table_debug { struct pqi_config_table_section_header header; @@ -1138,6 +1141,7 @@ struct pqi_ctrl_info { u8 pqi_mode_enabled : 1; u8 pqi_reset_quiesce_supported : 1; u8 soft_reset_handshake_supported : 1; + u8 raid_iu_timeout_supported: 1; struct list_head scsi_device_list; spinlock_t scsi_device_list_lock; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 64924ad0cd6e..9ae17bde0b30 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -6098,6 +6098,9 @@ static int pqi_passthru_ioctl(struct pqi_ctrl_info *ctrl_info, void __user *arg) put_unaligned_le16(iu_length, &request.header.iu_length); + if (ctrl_info->raid_iu_timeout_supported) + put_unaligned_le32(iocommand.Request.Timeout, &request.timeout); + rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, PQI_SYNC_FLAGS_INTERRUPTABLE, &pqi_error_info, NO_TIMEOUT); @@ -6871,6 +6874,23 @@ static void pqi_firmware_feature_status(struct pqi_ctrl_info *ctrl_info, firmware_feature->feature_name); } +static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info, + struct pqi_firmware_feature *firmware_feature) +{ + switch (firmware_feature->feature_bit) { + case PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE: + ctrl_info->soft_reset_handshake_supported = + firmware_feature->enabled; + break; + case PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT: + ctrl_info->raid_iu_timeout_supported = + firmware_feature->enabled; + break; + } + + pqi_firmware_feature_status(ctrl_info, firmware_feature); +} + static inline void pqi_firmware_feature_update(struct pqi_ctrl_info *ctrl_info, struct pqi_firmware_feature *firmware_feature) { @@ -6894,7 +6914,12 @@ static struct pqi_firmware_feature pqi_firmware_features[] = { { .feature_name = "New Soft Reset Handshake", .feature_bit = PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE, - .feature_status = pqi_firmware_feature_status, + .feature_status = pqi_ctrl_update_feature_flags, + }, + { + .feature_name = "RAID IU Timeout", + .feature_bit = PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT, + .feature_status = pqi_ctrl_update_feature_flags, }, }; @@ -6948,7 +6973,6 @@ static void pqi_process_firmware_features( return; } - ctrl_info->soft_reset_handshake_supported = false; for (i = 0; i < ARRAY_SIZE(pqi_firmware_features); i++) { if (!pqi_firmware_features[i].supported) continue; @@ -6956,10 +6980,6 @@ static void pqi_process_firmware_features( firmware_features_iomem_addr, pqi_firmware_features[i].feature_bit)) { pqi_firmware_features[i].enabled = true; - if (pqi_firmware_features[i].feature_bit == - PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE) - ctrl_info->soft_reset_handshake_supported = - true; } pqi_firmware_feature_update(ctrl_info, &pqi_firmware_features[i]); @@ -8764,6 +8784,8 @@ static void __attribute__((unused)) verify_structures(void) error_index) != 27); BUILD_BUG_ON(offsetof(struct pqi_raid_path_request, cdb) != 32); + BUILD_BUG_ON(offsetof(struct pqi_raid_path_request, + timeout) != 60); BUILD_BUG_ON(offsetof(struct pqi_raid_path_request, sg_descriptors) != 64); BUILD_BUG_ON(sizeof(struct pqi_raid_path_request) != -- cgit v1.2.3 From c2922f174fa0fbb699c3bd0ad40c73d067a90197 Mon Sep 17 00:00:00 2001 From: Murthy Bhat Date: Mon, 7 Oct 2019 17:31:40 -0500 Subject: scsi: smartpqi: fix LUN reset when fw bkgnd thread is hung Add support for a timeout on LUN resets. Link: https://lore.kernel.org/r/157048750055.11757.9689400788261610618.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Reviewed-by: Kevin Barnett Signed-off-by: Murthy Bhat Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 5 ++++- drivers/scsi/smartpqi/smartpqi_init.c | 21 ++++++++++++++++++--- 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index af0662b8a09c..c09d48366d38 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -387,7 +387,8 @@ struct pqi_task_management_request { struct pqi_iu_header header; __le16 request_id; __le16 nexus_id; - u8 reserved[4]; + u8 reserved[2]; + __le16 timeout; u8 lun_number[8]; __le16 protocol_specific; __le16 outbound_queue_id_to_manage; @@ -764,6 +765,7 @@ struct pqi_config_table_firmware_features { #define PQI_FIRMWARE_FEATURE_SMP 1 #define PQI_FIRMWARE_FEATURE_SOFT_RESET_HANDSHAKE 11 #define PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT 13 +#define PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT 14 struct pqi_config_table_debug { struct pqi_config_table_section_header header; @@ -1142,6 +1144,7 @@ struct pqi_ctrl_info { u8 pqi_reset_quiesce_supported : 1; u8 soft_reset_handshake_supported : 1; u8 raid_iu_timeout_supported: 1; + u8 tmf_iu_timeout_supported: 1; struct list_head scsi_device_list; spinlock_t scsi_device_list_lock; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 9ae17bde0b30..549455f3f4ae 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -5690,7 +5690,8 @@ static void pqi_lun_reset_complete(struct pqi_io_request *io_request, complete(waiting); } -#define PQI_LUN_RESET_TIMEOUT_SECS 10 +#define PQI_LUN_RESET_TIMEOUT_SECS 60 +#define PQI_LUN_RESET_POLL_COMPLETION_SECS 10 static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, struct completion *wait) @@ -5699,7 +5700,7 @@ static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info, while (1) { if (wait_for_completion_io_timeout(wait, - PQI_LUN_RESET_TIMEOUT_SECS * PQI_HZ)) { + PQI_LUN_RESET_POLL_COMPLETION_SECS * PQI_HZ)) { rc = 0; break; } @@ -5736,6 +5737,9 @@ static int pqi_lun_reset(struct pqi_ctrl_info *ctrl_info, memcpy(request->lun_number, device->scsi3addr, sizeof(request->lun_number)); request->task_management_function = SOP_TASK_MANAGEMENT_LUN_RESET; + if (ctrl_info->tmf_iu_timeout_supported) + put_unaligned_le16(PQI_LUN_RESET_TIMEOUT_SECS, + &request->timeout); pqi_start_io(ctrl_info, &ctrl_info->queue_groups[PQI_DEFAULT_QUEUE_GROUP], RAID_PATH, @@ -5765,7 +5769,7 @@ static int _pqi_device_reset(struct pqi_ctrl_info *ctrl_info, for (retries = 0;;) { rc = pqi_lun_reset(ctrl_info, device); - if (rc != -EAGAIN || ++retries > PQI_LUN_RESET_RETRIES) + if (rc == 0 || ++retries > PQI_LUN_RESET_RETRIES) break; msleep(PQI_LUN_RESET_RETRY_INTERVAL_MSECS); } @@ -6886,6 +6890,10 @@ static void pqi_ctrl_update_feature_flags(struct pqi_ctrl_info *ctrl_info, ctrl_info->raid_iu_timeout_supported = firmware_feature->enabled; break; + case PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT: + ctrl_info->tmf_iu_timeout_supported = + firmware_feature->enabled; + break; } pqi_firmware_feature_status(ctrl_info, firmware_feature); @@ -6921,6 +6929,11 @@ static struct pqi_firmware_feature pqi_firmware_features[] = { .feature_bit = PQI_FIRMWARE_FEATURE_RAID_IU_TIMEOUT, .feature_status = pqi_ctrl_update_feature_flags, }, + { + .feature_name = "TMF IU Timeout", + .feature_bit = PQI_FIRMWARE_FEATURE_TMF_IU_TIMEOUT, + .feature_status = pqi_ctrl_update_feature_flags, + }, }; static void pqi_process_firmware_features( @@ -8940,6 +8953,8 @@ static void __attribute__((unused)) verify_structures(void) request_id) != 8); BUILD_BUG_ON(offsetof(struct pqi_task_management_request, nexus_id) != 10); + BUILD_BUG_ON(offsetof(struct pqi_task_management_request, + timeout) != 14); BUILD_BUG_ON(offsetof(struct pqi_task_management_request, lun_number) != 16); BUILD_BUG_ON(offsetof(struct pqi_task_management_request, -- cgit v1.2.3 From bb9af08cfc41e3e5d6f5e7e350eb2063e023e782 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Mon, 7 Oct 2019 17:31:46 -0500 Subject: scsi: smartpqi: change TMF timeout from 60 to 30 seconds Link: https://lore.kernel.org/r/157048750649.11757.7811056360633694725.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 549455f3f4ae..453ced42801c 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -5690,7 +5690,7 @@ static void pqi_lun_reset_complete(struct pqi_io_request *io_request, complete(waiting); } -#define PQI_LUN_RESET_TIMEOUT_SECS 60 +#define PQI_LUN_RESET_TIMEOUT_SECS 30 #define PQI_LUN_RESET_POLL_COMPLETION_SECS 10 static int pqi_wait_for_lun_reset_completion(struct pqi_ctrl_info *ctrl_info, -- cgit v1.2.3 From e655d469c32d54b7a439677f3f5d4b4cd0af985a Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Mon, 7 Oct 2019 17:31:52 -0500 Subject: scsi: smartpqi: correct syntax issue Link: https://lore.kernel.org/r/157048751247.11757.1727592925624138646.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 453ced42801c..9eecb50543f9 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -3858,7 +3858,7 @@ static int pqi_create_admin_queues(struct pqi_ctrl_info *ctrl_info) &pqi_registers->admin_oq_pi_addr); reg = PQI_ADMIN_IQ_NUM_ELEMENTS | - (PQI_ADMIN_OQ_NUM_ELEMENTS) << 8 | + (PQI_ADMIN_OQ_NUM_ELEMENTS << 8) | (admin_queues->int_msg_num << 16); writel(reg, &pqi_registers->admin_iq_num_elements); writel(PQI_CREATE_ADMIN_QUEUE_PAIR, -- cgit v1.2.3 From 5b083b305b49f65269b888885455b8c0cf1a52e4 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Mon, 7 Oct 2019 17:31:58 -0500 Subject: scsi: smartpqi: fix problem with unique ID for physical device Obtain the unique IDs from the RLL and RPL instead of VPD page 83h. Link: https://lore.kernel.org/r/157048751833.11757.11996314786914610803.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 1 - drivers/scsi/smartpqi/smartpqi_init.c | 99 +++++------------------------------ 2 files changed, 12 insertions(+), 88 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index c09d48366d38..068336904477 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -912,7 +912,6 @@ struct pqi_scsi_dev { u8 scsi3addr[8]; __be64 wwid; u8 volume_id[16]; - u8 unique_id[16]; u8 is_physical_device : 1; u8 is_external_raid_device : 1; u8 is_expander_smp_device : 1; diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 9eecb50543f9..81b6ea600096 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -648,79 +648,6 @@ static inline int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info, buffer, buffer_length, vpd_page, NULL, NO_TIMEOUT); } -static bool pqi_vpd_page_supported(struct pqi_ctrl_info *ctrl_info, - u8 *scsi3addr, u16 vpd_page) -{ - int rc; - int i; - int pages; - unsigned char *buf, bufsize; - - buf = kzalloc(256, GFP_KERNEL); - if (!buf) - return false; - - /* Get the size of the page list first */ - rc = pqi_scsi_inquiry(ctrl_info, scsi3addr, - VPD_PAGE | SCSI_VPD_SUPPORTED_PAGES, - buf, SCSI_VPD_HEADER_SZ); - if (rc != 0) - goto exit_unsupported; - - pages = buf[3]; - if ((pages + SCSI_VPD_HEADER_SZ) <= 255) - bufsize = pages + SCSI_VPD_HEADER_SZ; - else - bufsize = 255; - - /* Get the whole VPD page list */ - rc = pqi_scsi_inquiry(ctrl_info, scsi3addr, - VPD_PAGE | SCSI_VPD_SUPPORTED_PAGES, - buf, bufsize); - if (rc != 0) - goto exit_unsupported; - - pages = buf[3]; - for (i = 1; i <= pages; i++) - if (buf[3 + i] == vpd_page) - goto exit_supported; - -exit_unsupported: - kfree(buf); - return false; - -exit_supported: - kfree(buf); - return true; -} - -static int pqi_get_device_id(struct pqi_ctrl_info *ctrl_info, - u8 *scsi3addr, u8 *device_id, int buflen) -{ - int rc; - unsigned char *buf; - - if (!pqi_vpd_page_supported(ctrl_info, scsi3addr, SCSI_VPD_DEVICE_ID)) - return 1; /* function not supported */ - - buf = kzalloc(64, GFP_KERNEL); - if (!buf) - return -ENOMEM; - - rc = pqi_scsi_inquiry(ctrl_info, scsi3addr, - VPD_PAGE | SCSI_VPD_DEVICE_ID, - buf, 64); - if (rc == 0) { - if (buflen > 16) - buflen = 16; - memcpy(device_id, &buf[SCSI_VPD_DEVICE_ID_IDX], buflen); - } - - kfree(buf); - - return rc; -} - static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, struct bmic_identify_physical_device *buffer, @@ -1405,14 +1332,6 @@ static int pqi_get_device_info(struct pqi_ctrl_info *ctrl_info, } } - if (pqi_get_device_id(ctrl_info, device->scsi3addr, - device->unique_id, sizeof(device->unique_id)) < 0) - dev_warn(&ctrl_info->pci_dev->dev, - "Can't get device id for scsi %d:%d:%d:%d\n", - ctrl_info->scsi_host->host_no, - device->bus, device->target, - device->lun); - out: kfree(buffer); @@ -6317,7 +6236,7 @@ static ssize_t pqi_unique_id_show(struct device *dev, struct scsi_device *sdev; struct pqi_scsi_dev *device; unsigned long flags; - unsigned char uid[16]; + u8 unique_id[16]; sdev = to_scsi_device(dev); ctrl_info = shost_to_hba(sdev->host); @@ -6330,16 +6249,22 @@ static ssize_t pqi_unique_id_show(struct device *dev, flags); return -ENODEV; } - memcpy(uid, device->unique_id, sizeof(uid)); + + if (device->is_physical_device) { + memset(unique_id, 0, 8); + memcpy(unique_id + 8, &device->wwid, sizeof(device->wwid)); + } else { + memcpy(unique_id, device->volume_id, sizeof(device->volume_id)); + } spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); return snprintf(buffer, PAGE_SIZE, "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X\n", - uid[0], uid[1], uid[2], uid[3], - uid[4], uid[5], uid[6], uid[7], - uid[8], uid[9], uid[10], uid[11], - uid[12], uid[13], uid[14], uid[15]); + unique_id[0], unique_id[1], unique_id[2], unique_id[3], + unique_id[4], unique_id[5], unique_id[6], unique_id[7], + unique_id[8], unique_id[9], unique_id[10], unique_id[11], + unique_id[12], unique_id[13], unique_id[14], unique_id[15]); } static ssize_t pqi_lunid_show(struct device *dev, -- cgit v1.2.3 From 0fa31a88bfd23e97a261956ae3c822f5be4e31a9 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Mon, 7 Oct 2019 17:32:04 -0500 Subject: scsi: smartpqi: remove unused manifest constants Removed some unused manifest constants. Link: https://lore.kernel.org/r/157048752420.11757.3464951542864727227.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index 068336904477..c42bf033109e 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -958,13 +958,9 @@ struct pqi_scsi_dev { }; /* VPD inquiry pages */ -#define SCSI_VPD_SUPPORTED_PAGES 0x0 /* standard page */ -#define SCSI_VPD_DEVICE_ID 0x83 /* standard page */ #define CISS_VPD_LV_DEVICE_GEOMETRY 0xc1 /* vendor-specific page */ #define CISS_VPD_LV_BYPASS_STATUS 0xc2 /* vendor-specific page */ #define CISS_VPD_LV_STATUS 0xc3 /* vendor-specific page */ -#define SCSI_VPD_HEADER_SZ 4 -#define SCSI_VPD_DEVICE_ID_IDX 8 /* Index of page id in page */ #define VPD_PAGE (1 << 8) -- cgit v1.2.3 From 694c5d5b4625fe4617990beb02eedb176e8309c9 Mon Sep 17 00:00:00 2001 From: Kevin Barnett Date: Mon, 7 Oct 2019 17:32:10 -0500 Subject: scsi: smartpqi: Align driver syntax with oob Formatting changes, no functional changes. Link: https://lore.kernel.org/r/157048753005.11757.2228541207280057256.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Scott Teel Signed-off-by: Kevin Barnett Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi.h | 60 +++++----- drivers/scsi/smartpqi/smartpqi_init.c | 150 ++++++++++++++----------- drivers/scsi/smartpqi/smartpqi_sas_transport.c | 20 +--- 3 files changed, 112 insertions(+), 118 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi.h b/drivers/scsi/smartpqi/smartpqi.h index c42bf033109e..1129fe7a27ed 100644 --- a/drivers/scsi/smartpqi/smartpqi.h +++ b/drivers/scsi/smartpqi/smartpqi.h @@ -448,7 +448,7 @@ struct pqi_vendor_general_response { struct pqi_ofa_memory { __le64 signature; /* "OFA_QRM" */ - __le16 version; /* version of this struct(1 = 1st version) */ + __le16 version; /* version of this struct (1 = 1st version) */ u8 reserved[62]; __le32 bytes_allocated; /* total allocated memory in bytes */ __le16 num_memory_descriptors; @@ -831,10 +831,17 @@ union pqi_reset_register { struct report_lun_header { __be32 list_length; - u8 extended_response; + u8 flags; u8 reserved[3]; }; +/* for flags field of struct report_lun_header */ +#define CISS_REPORT_LOG_FLAG_UNIQUE_LUN_ID (1 << 0) +#define CISS_REPORT_LOG_FLAG_QUEUE_DEPTH (1 << 5) +#define CISS_REPORT_LOG_FLAG_DRIVE_TYPE_MIX (1 << 6) + +#define CISS_REPORT_PHYS_FLAG_OTHER (1 << 1) + struct report_log_lun_extended_entry { u8 lunid[8]; u8 volume_id[16]; @@ -856,7 +863,7 @@ struct report_phys_lun_extended_entry { }; /* for device_flags field of struct report_phys_lun_extended_entry */ -#define REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED 0x8 +#define CISS_REPORT_PHYS_DEV_FLAG_AIO_ENABLED 0x8 struct report_phys_lun_extended { struct report_lun_header header; @@ -869,7 +876,7 @@ struct raid_map_disk_data { u8 reserved[2]; }; -/* constants for flags field of RAID map */ +/* for flags field of RAID map */ #define RAID_MAP_ENCRYPTION_ENABLED 0x1 struct raid_map { @@ -1173,9 +1180,9 @@ struct pqi_ctrl_info { spinlock_t raid_bypass_retry_list_lock; struct work_struct raid_bypass_retry_work; - struct pqi_ofa_memory *pqi_ofa_mem_virt_addr; - dma_addr_t pqi_ofa_mem_dma_handle; - void **pqi_ofa_chunk_virt_addr; + struct pqi_ofa_memory *pqi_ofa_mem_virt_addr; + dma_addr_t pqi_ofa_mem_dma_handle; + void **pqi_ofa_chunk_virt_addr; atomic_t sync_cmds_outstanding; }; @@ -1195,10 +1202,6 @@ enum pqi_ctrl_mode { #define CISS_REPORT_PHYS 0xc3 /* Report Physical LUNs */ #define CISS_GET_RAID_MAP 0xc8 -/* constants for CISS_REPORT_LOG/CISS_REPORT_PHYS commands */ -#define CISS_REPORT_LOG_EXTENDED 0x1 -#define CISS_REPORT_PHYS_EXTENDED 0x2 - /* BMIC commands */ #define BMIC_IDENTIFY_CONTROLLER 0x11 #define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15 @@ -1212,7 +1215,7 @@ enum pqi_ctrl_mode { #define BMIC_SET_DIAG_OPTIONS 0xf4 #define BMIC_SENSE_DIAG_OPTIONS 0xf5 -#define CSMI_CC_SAS_SMP_PASSTHRU 0X17 +#define CSMI_CC_SAS_SMP_PASSTHRU 0x17 #define SA_FLUSH_CACHE 0x1 @@ -1248,10 +1251,12 @@ struct bmic_sense_subsystem_info { u8 ctrl_serial_number[16]; }; -#define SA_EXPANDER_SMP_DEVICE 0x05 -#define SA_CONTROLLER_DEVICE 0x07 -/*SCSI Invalid Device Type for SAS devices*/ -#define PQI_SAS_SCSI_INVALID_DEVTYPE 0xff +/* constants for device_type field */ +#define SA_DEVICE_TYPE_SATA 0x1 +#define SA_DEVICE_TYPE_SAS 0x2 +#define SA_DEVICE_TYPE_EXPANDER_SMP 0x5 +#define SA_DEVICE_TYPE_CONTROLLER 0x7 +#define SA_DEVICE_TYPE_NVME 0x9 struct bmic_identify_physical_device { u8 scsi_bus; /* SCSI Bus number on controller */ @@ -1277,7 +1282,7 @@ struct bmic_identify_physical_device { __le32 rpm; /* drive rotational speed in RPM */ u8 device_type; /* type of drive */ u8 sata_version; /* only valid when device_type = */ - /* BMIC_DEVICE_TYPE_SATA */ + /* SA_DEVICE_TYPE_SATA */ __le64 big_total_block_count; __le64 ris_starting_lba; __le32 ris_size; @@ -1400,18 +1405,6 @@ struct bmic_diag_options { #pragma pack() -static inline struct pqi_ctrl_info *shost_to_hba(struct Scsi_Host *shost) -{ - void *hostdata = shost_priv(shost); - - return *((struct pqi_ctrl_info **)hostdata); -} - -static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info) -{ - return !ctrl_info->controller_online; -} - static inline void pqi_ctrl_busy(struct pqi_ctrl_info *ctrl_info) { atomic_inc(&ctrl_info->num_busy_threads); @@ -1422,14 +1415,11 @@ static inline void pqi_ctrl_unbusy(struct pqi_ctrl_info *ctrl_info) atomic_dec(&ctrl_info->num_busy_threads); } -static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info) +static inline struct pqi_ctrl_info *shost_to_hba(struct Scsi_Host *shost) { - return ctrl_info->block_requests; -} + void *hostdata = shost_priv(shost); -static inline bool pqi_device_reset_blocked(struct pqi_ctrl_info *ctrl_info) -{ - return ctrl_info->block_device_reset; + return *((struct pqi_ctrl_info **)hostdata); } void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 81b6ea600096..98c15c9fcc5a 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -211,6 +211,11 @@ static inline bool pqi_is_external_raid_addr(u8 *scsi3addr) return scsi3addr[2] != 0; } +static inline bool pqi_ctrl_offline(struct pqi_ctrl_info *ctrl_info) +{ + return !ctrl_info->controller_online; +} + static inline void pqi_check_ctrl_health(struct pqi_ctrl_info *ctrl_info) { if (ctrl_info->controller_online) @@ -235,6 +240,21 @@ static inline void pqi_save_ctrl_mode(struct pqi_ctrl_info *ctrl_info, sis_write_driver_scratch(ctrl_info, mode); } +static inline void pqi_ctrl_block_device_reset(struct pqi_ctrl_info *ctrl_info) +{ + ctrl_info->block_device_reset = true; +} + +static inline bool pqi_device_reset_blocked(struct pqi_ctrl_info *ctrl_info) +{ + return ctrl_info->block_device_reset; +} + +static inline bool pqi_ctrl_blocked(struct pqi_ctrl_info *ctrl_info) +{ + return ctrl_info->block_requests; +} + static inline void pqi_ctrl_block_requests(struct pqi_ctrl_info *ctrl_info) { ctrl_info->block_requests = true; @@ -249,11 +269,6 @@ static inline void pqi_ctrl_unblock_requests(struct pqi_ctrl_info *ctrl_info) scsi_unblock_requests(ctrl_info->scsi_host); } -static inline void pqi_ctrl_block_device_reset(struct pqi_ctrl_info *ctrl_info) -{ - ctrl_info->block_device_reset = true; -} - static unsigned long pqi_wait_if_ctrl_blocked(struct pqi_ctrl_info *ctrl_info, unsigned long timeout_msecs) { @@ -397,7 +412,7 @@ static inline u8 pqi_read_soft_reset_status(struct pqi_ctrl_info *ctrl_info) } static inline void pqi_clear_soft_reset_status(struct pqi_ctrl_info *ctrl_info, - u8 clear) + u8 clear) { u8 status; @@ -482,9 +497,9 @@ static int pqi_build_raid_path_request(struct pqi_ctrl_info *ctrl_info, request->data_direction = SOP_READ_FLAG; cdb[0] = cmd; if (cmd == CISS_REPORT_PHYS) - cdb[1] = CISS_REPORT_PHYS_EXTENDED; + cdb[1] = CISS_REPORT_PHYS_FLAG_OTHER; else - cdb[1] = CISS_REPORT_LOG_EXTENDED; + cdb[1] = CISS_REPORT_LOG_FLAG_UNIQUE_LUN_ID; put_unaligned_be32(cdb_length, &cdb[6]); break; case CISS_GET_RAID_MAP: @@ -587,13 +602,12 @@ static void pqi_free_io_request(struct pqi_io_request *io_request) } static int pqi_send_scsi_raid_request(struct pqi_ctrl_info *ctrl_info, u8 cmd, - u8 *scsi3addr, void *buffer, size_t buffer_length, u16 vpd_page, - struct pqi_raid_error_info *error_info, - unsigned long timeout_msecs) + u8 *scsi3addr, void *buffer, size_t buffer_length, u16 vpd_page, + struct pqi_raid_error_info *error_info, unsigned long timeout_msecs) { int rc; - enum dma_data_direction dir; struct pqi_raid_path_request request; + enum dma_data_direction dir; rc = pqi_build_raid_path_request(ctrl_info, &request, cmd, scsi3addr, buffer, @@ -601,44 +615,44 @@ static int pqi_send_scsi_raid_request(struct pqi_ctrl_info *ctrl_info, u8 cmd, if (rc) return rc; - rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, - 0, error_info, timeout_msecs); + rc = pqi_submit_raid_request_synchronous(ctrl_info, &request.header, 0, + error_info, timeout_msecs); pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); + return rc; } -/* Helper functions for pqi_send_scsi_raid_request */ +/* helper functions for pqi_send_scsi_raid_request */ static inline int pqi_send_ctrl_raid_request(struct pqi_ctrl_info *ctrl_info, - u8 cmd, void *buffer, size_t buffer_length) + u8 cmd, void *buffer, size_t buffer_length) { return pqi_send_scsi_raid_request(ctrl_info, cmd, RAID_CTLR_LUNID, - buffer, buffer_length, 0, NULL, NO_TIMEOUT); + buffer, buffer_length, 0, NULL, NO_TIMEOUT); } static inline int pqi_send_ctrl_raid_with_error(struct pqi_ctrl_info *ctrl_info, - u8 cmd, void *buffer, size_t buffer_length, - struct pqi_raid_error_info *error_info) + u8 cmd, void *buffer, size_t buffer_length, + struct pqi_raid_error_info *error_info) { return pqi_send_scsi_raid_request(ctrl_info, cmd, RAID_CTLR_LUNID, - buffer, buffer_length, 0, error_info, NO_TIMEOUT); + buffer, buffer_length, 0, error_info, NO_TIMEOUT); } - static inline int pqi_identify_controller(struct pqi_ctrl_info *ctrl_info, - struct bmic_identify_controller *buffer) + struct bmic_identify_controller *buffer) { return pqi_send_ctrl_raid_request(ctrl_info, BMIC_IDENTIFY_CONTROLLER, - buffer, sizeof(*buffer)); + buffer, sizeof(*buffer)); } static inline int pqi_sense_subsystem_info(struct pqi_ctrl_info *ctrl_info, - struct bmic_sense_subsystem_info *sense_info) + struct bmic_sense_subsystem_info *sense_info) { return pqi_send_ctrl_raid_request(ctrl_info, - BMIC_SENSE_SUBSYSTEM_INFORMATION, - sense_info, sizeof(*sense_info)); + BMIC_SENSE_SUBSYSTEM_INFORMATION, sense_info, + sizeof(*sense_info)); } static inline int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info, @@ -650,8 +664,7 @@ static inline int pqi_scsi_inquiry(struct pqi_ctrl_info *ctrl_info, static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info, struct pqi_scsi_dev *device, - struct bmic_identify_physical_device *buffer, - size_t buffer_length) + struct bmic_identify_physical_device *buffer, size_t buffer_length) { int rc; enum dma_data_direction dir; @@ -672,6 +685,7 @@ static int pqi_identify_physical_device(struct pqi_ctrl_info *ctrl_info, 0, NULL, NO_TIMEOUT); pqi_pci_unmap(ctrl_info->pci_dev, request.sg_descriptors, 1, dir); + return rc; } @@ -710,7 +724,7 @@ int pqi_csmi_smp_passthru(struct pqi_ctrl_info *ctrl_info, buffer, buffer_length, error_info); } -#define PQI_FETCH_PTRAID_DATA (1UL<<31) +#define PQI_FETCH_PTRAID_DATA (1 << 31) static int pqi_set_diag_rescan(struct pqi_ctrl_info *ctrl_info) { @@ -722,14 +736,15 @@ static int pqi_set_diag_rescan(struct pqi_ctrl_info *ctrl_info) return -ENOMEM; rc = pqi_send_ctrl_raid_request(ctrl_info, BMIC_SENSE_DIAG_OPTIONS, - diag, sizeof(*diag)); + diag, sizeof(*diag)); if (rc) goto out; diag->options |= cpu_to_le32(PQI_FETCH_PTRAID_DATA); - rc = pqi_send_ctrl_raid_request(ctrl_info, BMIC_SET_DIAG_OPTIONS, - diag, sizeof(*diag)); + rc = pqi_send_ctrl_raid_request(ctrl_info, BMIC_SET_DIAG_OPTIONS, diag, + sizeof(*diag)); + out: kfree(diag); @@ -740,7 +755,7 @@ static inline int pqi_write_host_wellness(struct pqi_ctrl_info *ctrl_info, void *buffer, size_t buffer_length) { return pqi_send_ctrl_raid_request(ctrl_info, BMIC_WRITE_HOST_WELLNESS, - buffer, buffer_length); + buffer, buffer_length); } #pragma pack(1) @@ -893,7 +908,7 @@ static inline int pqi_report_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd, void *buffer, size_t buffer_length) { return pqi_send_ctrl_raid_request(ctrl_info, cmd, buffer, - buffer_length); + buffer_length); } static int pqi_report_phys_logical_luns(struct pqi_ctrl_info *ctrl_info, u8 cmd, @@ -1227,9 +1242,9 @@ static void pqi_get_raid_bypass_status(struct pqi_ctrl_info *ctrl_info, if (rc) goto out; -#define RAID_BYPASS_STATUS 4 -#define RAID_BYPASS_CONFIGURED 0x1 -#define RAID_BYPASS_ENABLED 0x2 +#define RAID_BYPASS_STATUS 4 +#define RAID_BYPASS_CONFIGURED 0x1 +#define RAID_BYPASS_ENABLED 0x2 bypass_status = buffer[RAID_BYPASS_STATUS]; device->raid_bypass_configured = @@ -1352,6 +1367,7 @@ static void pqi_get_physical_disk_info(struct pqi_ctrl_info *ctrl_info, device->queue_depth = PQI_PHYSICAL_DISK_DEFAULT_MAX_QUEUE_DEPTH; return; } + device->box_index = id_phys->box_index; device->phys_box_on_bus = id_phys->phys_box_on_bus; device->phy_connected_dev_type = id_phys->phy_connected_dev_type[0]; @@ -1767,7 +1783,7 @@ static void pqi_update_device_list(struct pqi_ctrl_info *ctrl_info, device = new_device_list[i]; find_result = pqi_scsi_find_entry(ctrl_info, device, - &matching_device); + &matching_device); switch (find_result) { case DEVICE_SAME: @@ -1996,9 +2012,8 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) rc = -ENOMEM; goto out; } - if (pqi_hide_vsep) { - int i; + if (pqi_hide_vsep) { for (i = num_physicals - 1; i >= 0; i--) { phys_lun_ext_entry = &physdev_list->lun_entries[i]; @@ -2071,7 +2086,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) device->is_physical_device = is_physical_device; if (is_physical_device) { if (phys_lun_ext_entry->device_type == - SA_EXPANDER_SMP_DEVICE) + SA_DEVICE_TYPE_EXPANDER_SMP) device->is_expander_smp_device = true; } else { device->is_external_raid_device = @@ -2108,7 +2123,7 @@ static int pqi_update_scsi_devices(struct pqi_ctrl_info *ctrl_info) if (device->is_physical_device) { device->wwid = phys_lun_ext_entry->wwid; if ((phys_lun_ext_entry->device_flags & - REPORT_PHYS_LUN_DEV_FLAG_AIO_ENABLED) && + CISS_REPORT_PHYS_DEV_FLAG_AIO_ENABLED) && phys_lun_ext_entry->aio_handle) { device->aio_enabled = true; device->aio_handle = @@ -3094,7 +3109,7 @@ static enum pqi_soft_reset_status pqi_poll_for_soft_reset_status( } static void pqi_process_soft_reset(struct pqi_ctrl_info *ctrl_info, - enum pqi_soft_reset_status reset_status) + enum pqi_soft_reset_status reset_status) { int rc; @@ -3138,8 +3153,8 @@ static void pqi_ofa_process_event(struct pqi_ctrl_info *ctrl_info, if (event_id == PQI_EVENT_OFA_QUIESCE) { dev_info(&ctrl_info->pci_dev->dev, - "Received Online Firmware Activation quiesce event for controller %u\n", - ctrl_info->ctrl_id); + "Received Online Firmware Activation quiesce event for controller %u\n", + ctrl_info->ctrl_id); pqi_ofa_ctrl_quiesce(ctrl_info); pqi_acknowledge_event(ctrl_info, event); if (ctrl_info->soft_reset_handshake_supported) { @@ -3159,8 +3174,8 @@ static void pqi_ofa_process_event(struct pqi_ctrl_info *ctrl_info, pqi_ofa_free_host_buffer(ctrl_info); pqi_acknowledge_event(ctrl_info, event); dev_info(&ctrl_info->pci_dev->dev, - "Online Firmware Activation(%u) cancel reason : %u\n", - ctrl_info->ctrl_id, event->ofa_cancel_reason); + "Online Firmware Activation(%u) cancel reason : %u\n", + ctrl_info->ctrl_id, event->ofa_cancel_reason); } mutex_unlock(&ctrl_info->ofa_mutex); @@ -3339,7 +3354,7 @@ static unsigned int pqi_process_event_intr(struct pqi_ctrl_info *ctrl_info) #define PQI_LEGACY_INTX_MASK 0x1 static inline void pqi_configure_legacy_intx(struct pqi_ctrl_info *ctrl_info, - bool enable_intx) + bool enable_intx) { u32 intx_mask; struct pqi_device_registers __iomem *pqi_registers; @@ -3984,8 +3999,8 @@ static void pqi_raid_synchronous_complete(struct pqi_io_request *io_request, complete(waiting); } -static int pqi_process_raid_io_error_synchronous(struct pqi_raid_error_info - *error_info) +static int pqi_process_raid_io_error_synchronous( + struct pqi_raid_error_info *error_info) { int rc = -EIO; @@ -4604,11 +4619,11 @@ static void pqi_free_all_io_requests(struct pqi_ctrl_info *ctrl_info) static inline int pqi_alloc_error_buffer(struct pqi_ctrl_info *ctrl_info) { - ctrl_info->error_buffer = dma_alloc_coherent(&ctrl_info->pci_dev->dev, - ctrl_info->error_buffer_length, - &ctrl_info->error_buffer_dma_handle, - GFP_KERNEL); + ctrl_info->error_buffer = dma_alloc_coherent(&ctrl_info->pci_dev->dev, + ctrl_info->error_buffer_length, + &ctrl_info->error_buffer_dma_handle, + GFP_KERNEL); if (!ctrl_info->error_buffer) return -ENOMEM; @@ -5358,7 +5373,7 @@ static int pqi_scsi_queue_command(struct Scsi_Host *shost, if (pqi_is_logical_device(device)) { raid_bypassed = false; if (device->raid_bypass_enabled && - !blk_rq_is_passthrough(scmd->request)) { + !blk_rq_is_passthrough(scmd->request)) { rc = pqi_raid_bypass_submit_scsi_cmd(ctrl_info, device, scmd, queue_group); if (rc == 0 || rc == SCSI_MLQUEUE_HOST_BUSY) @@ -6077,8 +6092,7 @@ static int pqi_ioctl(struct scsi_device *sdev, unsigned int cmd, ctrl_info = shost_to_hba(sdev->host); - if (pqi_ctrl_in_ofa(ctrl_info) || - pqi_ctrl_in_shutdown(ctrl_info)) + if (pqi_ctrl_in_ofa(ctrl_info) || pqi_ctrl_in_shutdown(ctrl_info)) return -EBUSY; switch (cmd) { @@ -6119,8 +6133,8 @@ static ssize_t pqi_firmware_version_show(struct device *dev, static ssize_t pqi_driver_version_show(struct device *dev, struct device_attribute *attr, char *buffer) { - return snprintf(buffer, PAGE_SIZE, - "%s\n", DRIVER_VERSION BUILD_TIMESTAMP); + return snprintf(buffer, PAGE_SIZE, "%s\n", + DRIVER_VERSION BUILD_TIMESTAMP); } static ssize_t pqi_serial_number_show(struct device *dev, @@ -6287,6 +6301,7 @@ static ssize_t pqi_lunid_show(struct device *dev, flags); return -ENODEV; } + memcpy(lunid, device->scsi3addr, sizeof(lunid)); spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); @@ -6294,7 +6309,8 @@ static ssize_t pqi_lunid_show(struct device *dev, return snprintf(buffer, PAGE_SIZE, "0x%8phN\n", lunid); } -#define MAX_PATHS 8 +#define MAX_PATHS 8 + static ssize_t pqi_path_info_show(struct device *dev, struct device_attribute *attr, char *buf) { @@ -6306,9 +6322,9 @@ static ssize_t pqi_path_info_show(struct device *dev, int output_len = 0; u8 box; u8 bay; - u8 path_map_index = 0; + u8 path_map_index; char *active; - unsigned char phys_connector[2]; + u8 phys_connector[2]; sdev = to_scsi_device(dev); ctrl_info = shost_to_hba(sdev->host); @@ -6324,7 +6340,7 @@ static ssize_t pqi_path_info_show(struct device *dev, bay = device->bay; for (i = 0; i < MAX_PATHS; i++) { - path_map_index = 1<active_path_index) active = "Active"; else if (device->path_map & path_map_index) @@ -6375,10 +6391,10 @@ end_buffer: } spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); + return output_len; } - static ssize_t pqi_sas_address_show(struct device *dev, struct device_attribute *attr, char *buffer) { @@ -6399,6 +6415,7 @@ static ssize_t pqi_sas_address_show(struct device *dev, flags); return -ENODEV; } + sas_address = device->sas_address; spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); @@ -7378,7 +7395,7 @@ static int pqi_ctrl_init_resume(struct pqi_ctrl_info *ctrl_info) rc = pqi_get_ctrl_product_details(ctrl_info); if (rc) { dev_err(&ctrl_info->pci_dev->dev, - "error obtaining product detail\n"); + "error obtaining product details\n"); return rc; } @@ -7714,6 +7731,8 @@ static void pqi_ofa_setup_host_buffer(struct pqi_ctrl_info *ctrl_info, dev_err(dev, "Failed to allocate host buffer of size = %u", bytes_requested); } + + return; } static void pqi_ofa_free_host_buffer(struct pqi_ctrl_info *ctrl_info) @@ -8014,7 +8033,6 @@ static void pqi_shutdown(struct pci_dev *pci_dev) pqi_crash_if_pending_command(ctrl_info); pqi_reset(ctrl_info); - } static void pqi_process_lockup_action_param(void) diff --git a/drivers/scsi/smartpqi/smartpqi_sas_transport.c b/drivers/scsi/smartpqi/smartpqi_sas_transport.c index b7e28b9f8589..b7289112455c 100644 --- a/drivers/scsi/smartpqi/smartpqi_sas_transport.c +++ b/drivers/scsi/smartpqi/smartpqi_sas_transport.c @@ -312,7 +312,6 @@ static int pqi_sas_get_linkerrors(struct sas_phy *phy) static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier) { - int rc; unsigned long flags; struct Scsi_Host *shost; @@ -361,7 +360,7 @@ static int pqi_sas_get_enclosure_identifier(struct sas_rphy *rphy, } } - if (found_device->phy_connected_dev_type != SA_CONTROLLER_DEVICE) { + if (found_device->phy_connected_dev_type != SA_DEVICE_TYPE_CONTROLLER) { rc = -EINVAL; goto out; } @@ -382,12 +381,10 @@ out: spin_unlock_irqrestore(&ctrl_info->scsi_device_list_lock, flags); return rc; - } static int pqi_sas_get_bay_identifier(struct sas_rphy *rphy) { - int rc; unsigned long flags; struct pqi_ctrl_info *ctrl_info; @@ -482,7 +479,6 @@ pqi_build_csmi_smp_passthru_buffer(struct sas_rphy *rphy, req_size -= SMP_CRC_FIELD_LENGTH; put_unaligned_le32(req_size, ¶meters->request_length); - put_unaligned_le32(resp_size, ¶meters->response_length); sg_copy_to_buffer(job->request_payload.sg_list, @@ -512,12 +508,12 @@ void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, struct sas_rphy *rphy) { int rc; - struct pqi_ctrl_info *ctrl_info = shost_to_hba(shost); + struct pqi_ctrl_info *ctrl_info; struct bmic_csmi_smp_passthru_buffer *smp_buf; struct pqi_raid_error_info error_info; unsigned int reslen = 0; - pqi_ctrl_busy(ctrl_info); + ctrl_info = shost_to_hba(shost); if (job->reply_payload.payload_len == 0) { rc = -ENOMEM; @@ -539,16 +535,6 @@ void pqi_sas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost, goto out; } - if (pqi_ctrl_offline(ctrl_info)) { - rc = -ENXIO; - goto out; - } - - if (pqi_ctrl_blocked(ctrl_info)) { - rc = -EBUSY; - goto out; - } - smp_buf = pqi_build_csmi_smp_passthru_buffer(rphy, job); if (!smp_buf) { rc = -ENOMEM; -- cgit v1.2.3 From 390e28087823e38331990636ff5159ce622a0380 Mon Sep 17 00:00:00 2001 From: Don Brace Date: Mon, 7 Oct 2019 17:32:15 -0500 Subject: scsi: smartpqi: bump version Link: https://lore.kernel.org/r/157048753592.11757.3634142461093493860.stgit@brunhilda Reviewed-by: Scott Benesh Reviewed-by: Gerry Morong Signed-off-by: Don Brace Signed-off-by: Martin K. Petersen --- drivers/scsi/smartpqi/smartpqi_init.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/smartpqi/smartpqi_init.c b/drivers/scsi/smartpqi/smartpqi_init.c index 98c15c9fcc5a..7b7ef3acb504 100644 --- a/drivers/scsi/smartpqi/smartpqi_init.c +++ b/drivers/scsi/smartpqi/smartpqi_init.c @@ -33,11 +33,11 @@ #define BUILD_TIMESTAMP #endif -#define DRIVER_VERSION "1.2.8-026" +#define DRIVER_VERSION "1.2.10-025" #define DRIVER_MAJOR 1 #define DRIVER_MINOR 2 -#define DRIVER_RELEASE 8 -#define DRIVER_REVISION 26 +#define DRIVER_RELEASE 10 +#define DRIVER_REVISION 25 #define DRIVER_NAME "Microsemi PQI Driver (v" \ DRIVER_VERSION BUILD_TIMESTAMP ")" -- cgit v1.2.3 From ff7ca7fd03ce7dc225b3fc653d6877d2485c5716 Mon Sep 17 00:00:00 2001 From: Chandrakanth Patil Date: Mon, 7 Oct 2019 10:48:28 +0530 Subject: scsi: megaraid_sas: Unique names for MSI-X vectors Currently, MSI-X vectors name appears in /proc/interrupts is "megasas" which is same for all the vectors. This patch provides a unique name for all megaraid_sas controllers and their associated MSI-X interrupts. Link: https://lore.kernel.org/r/20191007051828.12294-1-chandrakanth.patil@broadcom.com Suggested-by: Konstantin Shalygin Signed-off-by: Sumit Saxena Signed-off-by: Chandrakanth Patil Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas.h | 3 +++ drivers/scsi/megaraid/megaraid_sas_base.c | 8 ++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h index a6e788c02ff4..bd8184072bed 100644 --- a/drivers/scsi/megaraid/megaraid_sas.h +++ b/drivers/scsi/megaraid/megaraid_sas.h @@ -24,6 +24,8 @@ #define MEGASAS_VERSION "07.710.50.00-rc1" #define MEGASAS_RELDATE "June 28, 2019" +#define MEGASAS_MSIX_NAME_LEN 32 + /* * Device IDs */ @@ -2203,6 +2205,7 @@ struct megasas_aen_event { }; struct megasas_irq_context { + char name[MEGASAS_MSIX_NAME_LEN]; struct megasas_instance *instance; u32 MSIxIndex; u32 os_irq; diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c index 42cf38c1ea99..c40fbea06cc5 100644 --- a/drivers/scsi/megaraid/megaraid_sas_base.c +++ b/drivers/scsi/megaraid/megaraid_sas_base.c @@ -5546,9 +5546,11 @@ megasas_setup_irqs_ioapic(struct megasas_instance *instance) pdev = instance->pdev; instance->irq_context[0].instance = instance; instance->irq_context[0].MSIxIndex = 0; + snprintf(instance->irq_context->name, MEGASAS_MSIX_NAME_LEN, "%s%u", + "megasas", instance->host->host_no); if (request_irq(pci_irq_vector(pdev, 0), instance->instancet->service_isr, IRQF_SHARED, - "megasas", &instance->irq_context[0])) { + instance->irq_context->name, &instance->irq_context[0])) { dev_err(&instance->pdev->dev, "Failed to register IRQ from %s %d\n", __func__, __LINE__); @@ -5580,8 +5582,10 @@ megasas_setup_irqs_msix(struct megasas_instance *instance, u8 is_probe) for (i = 0; i < instance->msix_vectors; i++) { instance->irq_context[i].instance = instance; instance->irq_context[i].MSIxIndex = i; + snprintf(instance->irq_context[i].name, MEGASAS_MSIX_NAME_LEN, "%s%u-msix%u", + "megasas", instance->host->host_no, i); if (request_irq(pci_irq_vector(pdev, i), - instance->instancet->service_isr, 0, "megasas", + instance->instancet->service_isr, 0, instance->irq_context[i].name, &instance->irq_context[i])) { dev_err(&instance->pdev->dev, "Failed to register IRQ for vector %d.\n", i); -- cgit v1.2.3 From 8cfb8e40d686a756428c627dccfaff28ca70dd8b Mon Sep 17 00:00:00 2001 From: zhengbin Date: Wed, 9 Oct 2019 15:23:44 +0800 Subject: scsi: megaraid_sas: remove unused variables 'debugBlk','fusion' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/megaraid/megaraid_sas_fp.c: In function MR_GetSpanBlock: drivers/scsi/megaraid/megaraid_sas_fp.c:400:16: warning: variable debugBlk set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_sas_fp.c: In function mr_spanset_get_phy_params: drivers/scsi/megaraid/megaraid_sas_fp.c:713:25: warning: variable fusion set but not used [-Wunused-but-set-variable] drivers/scsi/megaraid/megaraid_sas_fp.c: In function MR_GetPhyParams: drivers/scsi/megaraid/megaraid_sas_fp.c:815:25: warning: variable fusion set but not used [-Wunused-but-set-variable] 'debugBlk' is introduced by commit 9c915a8c99bc ("[SCSI] megaraid_sas: Add 9565/9285 specific code"), but never used, so remove it 'fusion' is not used since commit c365178f3147 ("scsi: megaraid_sas: use adapter_type for all gen controllers") Link: https://lore.kernel.org/r/1570605824-89133-1-git-send-email-zhengbin13@huawei.com Reported-by: Hulk Robot Signed-off-by: zhengbin Signed-off-by: Martin K. Petersen --- drivers/scsi/megaraid/megaraid_sas_fp.c | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c index 50b8c1b12767..89c3685f5163 100644 --- a/drivers/scsi/megaraid/megaraid_sas_fp.c +++ b/drivers/scsi/megaraid/megaraid_sas_fp.c @@ -386,9 +386,8 @@ u32 MR_GetSpanBlock(u32 ld, u64 row, u64 *span_blk, le64_to_cpu(quad->logEnd) && (mega_mod64(row - le64_to_cpu(quad->logStart), le32_to_cpu(quad->diff))) == 0) { if (span_blk != NULL) { - u64 blk, debugBlk; + u64 blk; blk = mega_div64_32((row-le64_to_cpu(quad->logStart)), le32_to_cpu(quad->diff)); - debugBlk = blk; blk = (blk + le64_to_cpu(quad->offsetInSpan)) << raid->stripeShift; *span_blk = blk; @@ -699,9 +698,7 @@ static u8 mr_spanset_get_phy_params(struct megasas_instance *instance, u32 ld, __le16 *pDevHandle = &io_info->devHandle; u8 *pPdInterface = &io_info->pd_interface; u32 logArm, rowMod, armQ, arm; - struct fusion_context *fusion; - fusion = instance->ctrl_context; *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); /*Get row and span from io_info for Uneven Span IO.*/ @@ -801,9 +798,7 @@ u8 MR_GetPhyParams(struct megasas_instance *instance, u32 ld, u64 stripRow, u64 *pdBlock = &io_info->pdBlock; __le16 *pDevHandle = &io_info->devHandle; u8 *pPdInterface = &io_info->pd_interface; - struct fusion_context *fusion; - fusion = instance->ctrl_context; *pDevHandle = cpu_to_le16(MR_DEVHANDLE_INVALID); row = mega_div64_32(stripRow, raid->rowDataSize); -- cgit v1.2.3 From c86fbe484c10b2cd1e770770db2d6b2c88801c1d Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:51:58 +0530 Subject: scsi: aacraid: fix illegal IO beyond last LBA The driver fails to handle data when read or written beyond device reported LBA, which triggers kernel panic Link: https://lore.kernel.org/r/1571120524-6037-2-git-send-email-balsundar.p@microsemi.com Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aachba.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 0ed3f806ace5..2388143d59f5 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -2467,13 +2467,13 @@ static int aac_read(struct scsi_cmnd * scsicmd) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, + ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE, ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); scsicmd->scsi_done(scsicmd); - return 1; + return 0; } dprintk((KERN_DEBUG "aac_read[cpu %d]: lba = %llu, t = %ld.\n", @@ -2559,13 +2559,13 @@ static int aac_write(struct scsi_cmnd * scsicmd) scsicmd->result = DID_OK << 16 | COMMAND_COMPLETE << 8 | SAM_STAT_CHECK_CONDITION; set_sense(&dev->fsa_dev[cid].sense_data, - HARDWARE_ERROR, SENCODE_INTERNAL_TARGET_FAILURE, + ILLEGAL_REQUEST, SENCODE_LBA_OUT_OF_RANGE, ASENCODE_INTERNAL_TARGET_FAILURE, 0, 0); memcpy(scsicmd->sense_buffer, &dev->fsa_dev[cid].sense_data, min_t(size_t, sizeof(dev->fsa_dev[cid].sense_data), SCSI_SENSE_BUFFERSIZE)); scsicmd->scsi_done(scsicmd); - return 1; + return 0; } dprintk((KERN_DEBUG "aac_write[cpu %d]: lba = %llu, t = %ld.\n", -- cgit v1.2.3 From f2244c1b35e5302070af4c729db0b0e9eb8350c9 Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:51:59 +0530 Subject: scsi: aacraid: fixed IO reporting error The problem is the driver detects FastResponse bit set and saves it to Fib's flags to not check IO response status, but it never clears it for next IO. Hence the next IO will pick up FastResponse bit to not check the IO response status and fail to report any type IO error to kernel Link: https://lore.kernel.org/r/1571120524-6037-3-git-send-email-balsundar.p@microsemi.com Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/commsup.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 2142a649e865..3f268f669cc3 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -232,6 +232,7 @@ struct fib *aac_fib_alloc_tag(struct aac_dev *dev, struct scsi_cmnd *scmd) fibptr->type = FSAFS_NTC_FIB_CONTEXT; fibptr->callback_data = NULL; fibptr->callback = NULL; + fibptr->flags = 0; return fibptr; } -- cgit v1.2.3 From c02a3342bad32baa9be201da39d3809b74f92239 Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:52:00 +0530 Subject: scsi: aacraid: fixed firmware assert issue Before issuing IOP reset, INTX mode is selected. This is triggering MSGU lockup and ended in basecode assert. Use DROP_IO command when IOP reset is sent in preparation for interrupt mode switch. Link: https://lore.kernel.org/r/1571120524-6037-4-git-send-email-balsundar.p@microsemi.com Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aacraid.h | 1 + drivers/scsi/aacraid/comminit.c | 5 +++++ drivers/scsi/aacraid/src.c | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 3fa03230f6ba..3fdd4583cbb5 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1673,6 +1673,7 @@ struct aac_dev u8 adapter_shutdown; u32 handle_pci_error; bool init_reset; + u8 soft_reset_support; }; #define aac_adapter_interrupt(dev) \ diff --git a/drivers/scsi/aacraid/comminit.c b/drivers/scsi/aacraid/comminit.c index d4fcfa1e54e0..f75878d773cf 100644 --- a/drivers/scsi/aacraid/comminit.c +++ b/drivers/scsi/aacraid/comminit.c @@ -571,6 +571,11 @@ struct aac_dev *aac_init_adapter(struct aac_dev *dev) else dev->sa_firmware = 0; + if (status[4] & le32_to_cpu(AAC_EXTOPT_SOFT_RESET)) + dev->soft_reset_support = 1; + else + dev->soft_reset_support = 0; + if ((dev->comm_interface == AAC_COMM_MESSAGE) && (status[2] > dev->base_size)) { aac_adapter_ioremap(dev, 0); diff --git a/drivers/scsi/aacraid/src.c b/drivers/scsi/aacraid/src.c index 3b66e06726c8..787ec9baebb0 100644 --- a/drivers/scsi/aacraid/src.c +++ b/drivers/scsi/aacraid/src.c @@ -733,10 +733,20 @@ static bool aac_is_ctrl_up_and_running(struct aac_dev *dev) return ctrl_up; } +static void aac_src_drop_io(struct aac_dev *dev) +{ + if (!dev->soft_reset_support) + return; + + aac_adapter_sync_cmd(dev, DROP_IO, + 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); +} + static void aac_notify_fw_of_iop_reset(struct aac_dev *dev) { aac_adapter_sync_cmd(dev, IOP_RESET_ALWAYS, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL); + aac_src_drop_io(dev); } static void aac_send_iop_reset(struct aac_dev *dev) -- cgit v1.2.3 From e2fd90dd2ed87bdcfdfb640f06da48fd23efa080 Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:52:01 +0530 Subject: scsi: aacraid: setting different timeout for src and thor Set 180 second timeout for thor and 60 seconds for src controllers. Link: https://lore.kernel.org/r/1571120524-6037-5-git-send-email-balsundar.p@microsemi.com Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aachba.c | 3 ++- drivers/scsi/aacraid/aacraid.h | 2 ++ drivers/scsi/aacraid/linit.c | 10 +++++++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 2388143d59f5..e36608ce937a 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c @@ -1477,6 +1477,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd struct aac_srb * srbcmd; u32 flag; u32 timeout; + struct aac_dev *dev = fib->dev; aac_fib_init(fib); switch(cmd->sc_data_direction){ @@ -1503,7 +1504,7 @@ static struct aac_srb * aac_scsi_common(struct fib * fib, struct scsi_cmnd * cmd srbcmd->flags = cpu_to_le32(flag); timeout = cmd->request->timeout/HZ; if (timeout == 0) - timeout = 1; + timeout = (dev->sa_firmware ? AAC_SA_TIMEOUT : AAC_ARC_TIMEOUT); srbcmd->timeout = cpu_to_le32(timeout); // timeout in seconds srbcmd->retry_limit = 0; /* Obsolete parameter */ srbcmd->cdb_size = cpu_to_le32(cmd->cmd_len); diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 3fdd4583cbb5..f76a33cb0259 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -108,6 +108,8 @@ enum { #define AAC_BUS_TARGET_LOOP (AAC_MAX_BUSES * AAC_MAX_TARGETS) #define AAC_MAX_NATIVE_SIZE 2048 #define FW_ERROR_BUFFER_SIZE 512 +#define AAC_SA_TIMEOUT 180 +#define AAC_ARC_TIMEOUT 60 #define get_bus_number(x) (x/AAC_MAX_TARGETS) #define get_target_number(x) (x%AAC_MAX_TARGETS) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 4a858789e6c5..40f78509ca94 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -391,6 +391,7 @@ static int aac_slave_configure(struct scsi_device *sdev) int chn, tid; unsigned int depth = 0; unsigned int set_timeout = 0; + int timeout = 0; bool set_qd_dev_type = false; u8 devtype = 0; @@ -483,10 +484,13 @@ common_config: /* * Firmware has an individual device recovery time typically - * of 35 seconds, give us a margin. + * of 35 seconds, give us a margin. Thor devices can take longer in + * error recovery, hence different value. */ - if (set_timeout && sdev->request_queue->rq_timeout < (45 * HZ)) - blk_queue_rq_timeout(sdev->request_queue, 45*HZ); + if (set_timeout) { + timeout = aac->sa_firmware ? AAC_SA_TIMEOUT : AAC_ARC_TIMEOUT; + blk_queue_rq_timeout(sdev->request_queue, timeout * HZ); + } if (depth > 256) depth = 256; -- cgit v1.2.3 From 572ee53a9badf62f3973d66f6475f9ce69720a25 Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:52:02 +0530 Subject: scsi: aacraid: check adapter health Currently driver waits for the command IOCTL from the firmware and if the firmware enters nonresponsive state, the driver doesn't respond till the firmware is responsive again. Check that firmware is alive, otherwise return -EBUSY. [mkp: clarified commit desc] Link: https://lore.kernel.org/r/1571120524-6037-6-git-send-email-balsundar.p@microsemi.com Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/linit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 40f78509ca94..55a55c56fea9 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -612,9 +612,13 @@ static struct device_attribute *aac_dev_attrs[] = { static int aac_ioctl(struct scsi_device *sdev, unsigned int cmd, void __user *arg) { + int retval; struct aac_dev *dev = (struct aac_dev *)sdev->host->hostdata; if (!capable(CAP_SYS_RAWIO)) return -EPERM; + retval = aac_adapter_check_health(dev); + if (retval) + return -EBUSY; return aac_do_ioctl(dev, cmd, arg); } -- cgit v1.2.3 From 26c54d0ec25c186329d845ad1beb9d3dde586af9 Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:52:03 +0530 Subject: scsi: aacraid: send AIF request post IOP RESET After IOP reset completion, AIF request command is not issued to the controller. Driver schedules a worker thread to issue a AIF request command after IOP reset completion. [mkp: fix zeroday warning] Link: https://lore.kernel.org/r/1571120524-6037-7-git-send-email-balsundar.p@microsemi.com Acked-by: Balsundar P < Balsundar.P@microchip.com> Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aacraid.h | 18 +++++++++++++----- drivers/scsi/aacraid/commsup.c | 20 +++++++++++++++++++- drivers/scsi/aacraid/linit.c | 21 ++++++++++++++++++--- 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index f76a33cb0259..17a4e8b8bd00 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -1330,7 +1330,7 @@ struct fib { #define AAC_DEVTYPE_ARC_RAW 2 #define AAC_DEVTYPE_NATIVE_RAW 3 -#define AAC_SAFW_RESCAN_DELAY (10 * HZ) +#define AAC_RESCAN_DELAY (10 * HZ) struct aac_hba_map_info { __le32 rmw_nexus; /* nexus for native HBA devices */ @@ -1603,6 +1603,7 @@ struct aac_dev struct fsa_dev_info *fsa_dev; struct task_struct *thread; struct delayed_work safw_rescan_work; + struct delayed_work src_reinit_aif_worker; int cardtype; /* *This lock will protect the two 32-bit @@ -2647,7 +2648,12 @@ int aac_scan_host(struct aac_dev *dev); static inline void aac_schedule_safw_scan_worker(struct aac_dev *dev) { - schedule_delayed_work(&dev->safw_rescan_work, AAC_SAFW_RESCAN_DELAY); + schedule_delayed_work(&dev->safw_rescan_work, AAC_RESCAN_DELAY); +} + +static inline void aac_schedule_src_reinit_aif_worker(struct aac_dev *dev) +{ + schedule_delayed_work(&dev->src_reinit_aif_worker, AAC_RESCAN_DELAY); } static inline void aac_safw_rescan_worker(struct work_struct *work) @@ -2661,10 +2667,10 @@ static inline void aac_safw_rescan_worker(struct work_struct *work) aac_scan_host(dev); } -static inline void aac_cancel_safw_rescan_worker(struct aac_dev *dev) +static inline void aac_cancel_rescan_worker(struct aac_dev *dev) { - if (dev->sa_firmware) - cancel_delayed_work_sync(&dev->safw_rescan_work); + cancel_delayed_work_sync(&dev->safw_rescan_work); + cancel_delayed_work_sync(&dev->src_reinit_aif_worker); } /* SCp.phase values */ @@ -2674,6 +2680,7 @@ static inline void aac_cancel_safw_rescan_worker(struct aac_dev *dev) #define AAC_OWNER_FIRMWARE 0x106 void aac_safw_rescan_worker(struct work_struct *work); +void aac_src_reinit_aif_worker(struct work_struct *work); int aac_acquire_irq(struct aac_dev *dev); void aac_free_irq(struct aac_dev *dev); int aac_setup_safw_adapter(struct aac_dev *dev); @@ -2731,6 +2738,7 @@ int aac_probe_container(struct aac_dev *dev, int cid); int _aac_rx_init(struct aac_dev *dev); int aac_rx_select_comm(struct aac_dev *dev, int comm); int aac_rx_deliver_producer(struct fib * fib); +void aac_reinit_aif(struct aac_dev *aac, unsigned int index); static inline int aac_is_src(struct aac_dev *dev) { diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 3f268f669cc3..5a8a999606ea 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c @@ -1464,6 +1464,14 @@ retry_next: } } +static void aac_schedule_bus_scan(struct aac_dev *aac) +{ + if (aac->sa_firmware) + aac_schedule_safw_scan_worker(aac); + else + aac_schedule_src_reinit_aif_worker(aac); +} + static int _aac_reset_adapter(struct aac_dev *aac, int forced, u8 reset_type) { int index, quirks; @@ -1639,7 +1647,7 @@ out: */ if (!retval && !is_kdump_kernel()) { dev_info(&aac->pdev->dev, "Scheduling bus rescan\n"); - aac_schedule_safw_scan_worker(aac); + aac_schedule_bus_scan(aac); } if (jafo) { @@ -1960,6 +1968,16 @@ int aac_scan_host(struct aac_dev *dev) return rcode; } +void aac_src_reinit_aif_worker(struct work_struct *work) +{ + struct aac_dev *dev = container_of(to_delayed_work(work), + struct aac_dev, src_reinit_aif_worker); + + wait_event(dev->scsi_host_ptr->host_wait, + !scsi_host_in_recovery(dev->scsi_host_ptr)); + aac_reinit_aif(dev, dev->cardtype); +} + /** * aac_handle_sa_aif Handle a message from the firmware * @dev: Which adapter this fib is from diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c index 55a55c56fea9..ee6bc2f9b80a 100644 --- a/drivers/scsi/aacraid/linit.c +++ b/drivers/scsi/aacraid/linit.c @@ -1593,6 +1593,19 @@ static void aac_init_char(void) } } +void aac_reinit_aif(struct aac_dev *aac, unsigned int index) +{ + /* + * Firmware may send a AIF messages very early and the Driver may have + * ignored as it is not fully ready to process the messages. Send + * AIF to firmware so that if there are any unprocessed events they + * can be processed now. + */ + if (aac_drivers[index].quirks & AAC_QUIRK_SRC) + aac_intr_normal(aac, 0, 2, 0, NULL); + +} + static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { unsigned index = id->driver_data; @@ -1690,6 +1703,8 @@ static int aac_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) mutex_init(&aac->scan_mutex); INIT_DELAYED_WORK(&aac->safw_rescan_work, aac_safw_rescan_worker); + INIT_DELAYED_WORK(&aac->src_reinit_aif_worker, + aac_src_reinit_aif_worker); /* * Map in the registers from the adapter. */ @@ -1880,7 +1895,7 @@ static int aac_suspend(struct pci_dev *pdev, pm_message_t state) struct aac_dev *aac = (struct aac_dev *)shost->hostdata; scsi_block_requests(shost); - aac_cancel_safw_rescan_worker(aac); + aac_cancel_rescan_worker(aac); aac_send_shutdown(aac); aac_release_resources(aac); @@ -1939,7 +1954,7 @@ static void aac_remove_one(struct pci_dev *pdev) struct Scsi_Host *shost = pci_get_drvdata(pdev); struct aac_dev *aac = (struct aac_dev *)shost->hostdata; - aac_cancel_safw_rescan_worker(aac); + aac_cancel_rescan_worker(aac); scsi_remove_host(shost); __aac_shutdown(aac); @@ -1997,7 +2012,7 @@ static pci_ers_result_t aac_pci_error_detected(struct pci_dev *pdev, aac->handle_pci_error = 1; scsi_block_requests(aac->scsi_host_ptr); - aac_cancel_safw_rescan_worker(aac); + aac_cancel_rescan_worker(aac); aac_flush_ios(aac); aac_release_resources(aac); -- cgit v1.2.3 From c695793b52216ad6a11ce952fc8d29f3a9d0c7cd Mon Sep 17 00:00:00 2001 From: Balsundar P Date: Tue, 15 Oct 2019 11:52:04 +0530 Subject: scsi: aacraid: bump version Bump version to 50877. Link: https://lore.kernel.org/r/1571120524-6037-8-git-send-email-balsundar.p@microsemi.com Signed-off-by: Balsundar P Signed-off-by: Martin K. Petersen --- drivers/scsi/aacraid/aacraid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 17a4e8b8bd00..e3e4ecbea726 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h @@ -85,7 +85,7 @@ enum { #define PMC_GLOBAL_INT_BIT0 0x00000001 #ifndef AAC_DRIVER_BUILD -# define AAC_DRIVER_BUILD 50877 +# define AAC_DRIVER_BUILD 50983 # define AAC_DRIVER_BRANCH "-custom" #endif #define MAXIMUM_NUM_CONTAINERS 32 -- cgit v1.2.3 From 9cef2a7955f2754257a7cddedec16edae7b587d0 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Thu, 12 Sep 2019 11:55:45 +0200 Subject: scsi: target: compare full CHAP_A Algorithm strings RFC 2307 states: For CHAP [RFC1994], in the first step, the initiator MUST send: CHAP_A= Where A1,A2... are proposed algorithms, in order of preference. ... For the Algorithm, as stated in [RFC1994], one value is required to be implemented: 5 (CHAP with MD5) LIO currently checks for this value by only comparing a single byte in the tokenized Algorithm string, which means that any value starting with a '5' (e.g. "55") is interpreted as "CHAP with MD5". Fix this by comparing the entire tokenized string. Reviewed-by: Lee Duncan Reviewed-by: Mike Christie Signed-off-by: David Disseldorp Link: https://lore.kernel.org/r/20190912095547.22427-2-ddiss@suse.de Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_auth.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 51ddca2033e0..8fe9b12a07a4 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -70,7 +70,7 @@ static int chap_check_algorithm(const char *a_str) if (!token) goto out; - if (!strncmp(token, "5", 1)) { + if (!strcmp(token, "5")) { pr_debug("Selected MD5 Algorithm\n"); kfree(orig); return CHAP_DIGEST_MD5; -- cgit v1.2.3 From 95f8f6a974cc99c10530accc785267859c2b6c14 Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Thu, 12 Sep 2019 11:55:46 +0200 Subject: scsi: target: fix SendTargets=All string compares strncmp is currently used for "SendTargets" key and "All" value matching without checking for trailing garbage. This means that Text request PDUs with garbage such as "SendTargetsPlease=All" and "SendTargets=Alle" are processed successfully as if they were "SendTargets=All" requests. Reviewed-by: Mike Christie Signed-off-by: David Disseldorp Link: https://lore.kernel.org/r/20190912095547.22427-3-ddiss@suse.de Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index d19e051f2bc2..09e55ea0bf5d 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -2189,24 +2189,22 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, } goto empty_sendtargets; } - if (strncmp("SendTargets", text_in, 11) != 0) { + if (strncmp("SendTargets=", text_in, 12) != 0) { pr_err("Received Text Data that is not" " SendTargets, cannot continue.\n"); goto reject; } + /* '=' confirmed in strncmp */ text_ptr = strchr(text_in, '='); - if (!text_ptr) { - pr_err("No \"=\" separator found in Text Data," - " cannot continue.\n"); - goto reject; - } - if (!strncmp("=All", text_ptr, 4)) { + BUG_ON(!text_ptr); + if (!strncmp("=All", text_ptr, 5)) { cmd->cmd_flags |= ICF_SENDTARGETS_ALL; } else if (!strncmp("=iqn.", text_ptr, 5) || !strncmp("=eui.", text_ptr, 5)) { cmd->cmd_flags |= ICF_SENDTARGETS_SINGLE; } else { - pr_err("Unable to locate valid SendTargets=%s value\n", text_ptr); + pr_err("Unable to locate valid SendTargets%s value\n", + text_ptr); goto reject; } -- cgit v1.2.3 From d30f53dd014d739a9ab36c8867d7cd33d0892c8d Mon Sep 17 00:00:00 2001 From: David Disseldorp Date: Thu, 12 Sep 2019 11:55:47 +0200 Subject: scsi: target: remove unused extension parameters Reviewed-by: Mike Christie Signed-off-by: David Disseldorp Link: https://lore.kernel.org/r/20190912095547.22427-4-ddiss@suse.de Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_parameters.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index daf47f38e081..240c4c4344f6 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h @@ -93,9 +93,6 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, #define OFMARKER "OFMarker" #define IFMARKINT "IFMarkInt" #define OFMARKINT "OFMarkInt" -#define X_EXTENSIONKEY "X-com.sbei.version" -#define X_EXTENSIONKEY_CISCO_NEW "X-com.cisco.protocol" -#define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft" /* * Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-5046 -- cgit v1.2.3 From e519a34c29597110e92908294be8464e91cabf9c Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 21 Oct 2019 22:19:57 +0800 Subject: scsi: cxlflash: remove set but not used variable 'ioarcb' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/cxlflash/main.c:47:22: warning: variable ioarcb set but not used [-Wunused-but-set-variable] It is never used, so can be removed. Link: https://lore.kernel.org/r/20191021141957.18828-1-yuehaibing@huawei.com Signed-off-by: YueHaibing Acked-by: Matthew R. Ochs Signed-off-by: Martin K. Petersen --- drivers/scsi/cxlflash/main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/cxlflash/main.c b/drivers/scsi/cxlflash/main.c index 93ef97af22df..4f01ef5c7f69 100644 --- a/drivers/scsi/cxlflash/main.c +++ b/drivers/scsi/cxlflash/main.c @@ -44,14 +44,12 @@ static void process_cmd_err(struct afu_cmd *cmd, struct scsi_cmnd *scp) struct afu *afu = cmd->parent; struct cxlflash_cfg *cfg = afu->parent; struct device *dev = &cfg->dev->dev; - struct sisl_ioarcb *ioarcb; struct sisl_ioasa *ioasa; u32 resid; if (unlikely(!cmd)) return; - ioarcb = &(cmd->rcb); ioasa = &(cmd->sa); if (ioasa->rc.flags & SISL_RC_FLAGS_UNDERRUN) { -- cgit v1.2.3 From 97a9ed3b3ae8eae27a231129c0939151879d5f2b Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:17 -0700 Subject: scsi: lpfc: fix lpfc_nvmet_mrq to be bound by hdw queue count Currently, lpfc_nvmet_mrq is always scaled back to the min(lpfc_nvmet_mrq, lpfc_irq_chann). There's no reason to reduce it to the number of interrupt vectors. Rather, it should be scaled down based on the number of hardware queues for the system (if lower than max of 16). Change scaling to use hardware queue count rather than interrupt vector count. Link: https://lore.kernel.org/r/20191018211832.7917-2-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 6 +++--- drivers/scsi/lpfc/lpfc_init.c | 6 ++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e4c89e56c632..266a71b01c47 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -7264,11 +7264,11 @@ lpfc_nvme_mod_param_dep(struct lpfc_hba *phba) } if (!phba->cfg_nvmet_mrq) - phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + phba->cfg_nvmet_mrq = phba->cfg_hdw_queue; /* Adjust lpfc_nvmet_mrq to avoid running out of WQE slots */ - if (phba->cfg_nvmet_mrq > phba->cfg_irq_chann) { - phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + if (phba->cfg_nvmet_mrq > phba->cfg_hdw_queue) { + phba->cfg_nvmet_mrq = phba->cfg_hdw_queue; lpfc_printf_log(phba, KERN_ERR, LOG_NVME_DISC, "6018 Adjust lpfc_nvmet_mrq to %d\n", phba->cfg_nvmet_mrq); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index a0aa7a555811..d2cb3b0d1849 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -8630,8 +8630,8 @@ lpfc_sli4_queue_verify(struct lpfc_hba *phba) */ if (phba->nvmet_support) { - if (phba->cfg_irq_chann < phba->cfg_nvmet_mrq) - phba->cfg_nvmet_mrq = phba->cfg_irq_chann; + if (phba->cfg_hdw_queue < phba->cfg_nvmet_mrq) + phba->cfg_nvmet_mrq = phba->cfg_hdw_queue; if (phba->cfg_nvmet_mrq > LPFC_NVMET_MRQ_MAX) phba->cfg_nvmet_mrq = LPFC_NVMET_MRQ_MAX; } @@ -11033,8 +11033,6 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) phba->cfg_irq_chann, vectors); if (phba->cfg_irq_chann > vectors) phba->cfg_irq_chann = vectors; - if (phba->nvmet_support && (phba->cfg_nvmet_mrq > vectors)) - phba->cfg_nvmet_mrq = vectors; } return rc; -- cgit v1.2.3 From 0a5ce731977da1cc6d8d6d7df01c2e53ebb81796 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:18 -0700 Subject: scsi: lpfc: Fix reporting of read-only fw error errors When the adapter FW is administratively set to RO mode, a FW update triggered by the driver's sysfs attribute will fail. Currently, the driver's logging mechanism does not properly parse the adapter return codes and print a meaningful message. This oversight prevents quick diagnosis in the field. Parse the adapter return codes for Write_Object and write an appropriate message to the system console. [mkp: typo] Link: https://lore.kernel.org/r/20191018211832.7917-3-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 69 ++++++++++++++++++++++++++++++------------- 2 files changed, 50 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 6095e3cfddd3..1cd3016f7783 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2320,6 +2320,7 @@ struct lpfc_mbx_redisc_fcf_tbl { #define ADD_STATUS_OPERATION_ALREADY_ACTIVE 0x67 #define ADD_STATUS_FW_NOT_SUPPORTED 0xEB #define ADD_STATUS_INVALID_REQUEST 0x4B +#define ADD_STATUS_FW_DOWNLOAD_HW_DISABLED 0x58 struct lpfc_mbx_sli4_config { struct mbox_header header; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index d2cb3b0d1849..1d14aa22f973 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -12320,35 +12320,57 @@ lpfc_sli4_get_iocb_cnt(struct lpfc_hba *phba) } -static void +static int lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, uint32_t magic_number, uint32_t ftype, uint32_t fid, uint32_t fsize, const struct firmware *fw) { - if ((offset == ADD_STATUS_FW_NOT_SUPPORTED) || + int rc; + + /* Three cases: (1) FW was not supported on the detected adapter. + * (2) FW update has been locked out administratively. + * (3) Some other error during FW update. + * In each case, an unmaskable message is written to the console + * for admin diagnosis. + */ + if (offset == ADD_STATUS_FW_NOT_SUPPORTED || (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && magic_number != MAGIC_NUMER_G6) || (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC && - magic_number != MAGIC_NUMER_G7)) + magic_number != MAGIC_NUMER_G7)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3030 This firmware version is not supported on " - "this HBA model. Device:%x Magic:%x Type:%x " - "ID:%x Size %d %zd\n", - phba->pcidev->device, magic_number, ftype, fid, - fsize, fw->size); - else + "3030 This firmware version is not supported on" + " this HBA model. Device:%x Magic:%x Type:%x " + "ID:%x Size %d %zd\n", + phba->pcidev->device, magic_number, ftype, fid, + fsize, fw->size); + rc = -EINVAL; + } else if (offset == ADD_STATUS_FW_DOWNLOAD_HW_DISABLED) { + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3021 Firmware downloads have been prohibited " + "by a system configuration setting on " + "Device:%x Magic:%x Type:%x ID:%x Size %d " + "%zd\n", + phba->pcidev->device, magic_number, ftype, fid, + fsize, fw->size); + rc = -EACCES; + } else { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3022 FW Download failed. Device:%x Magic:%x Type:%x " - "ID:%x Size %d %zd\n", - phba->pcidev->device, magic_number, ftype, fid, - fsize, fw->size); + "3022 FW Download failed. Add Status x%x " + "Device:%x Magic:%x Type:%x ID:%x Size %d " + "%zd\n", + offset, phba->pcidev->device, magic_number, + ftype, fid, fsize, fw->size); + rc = -EIO; + } + return rc; } - /** * lpfc_write_firmware - attempt to write a firmware image to the port * @fw: pointer to firmware image returned from request_firmware. - * @phba: pointer to lpfc hba data structure. + * @context: pointer to firmware image returned from request_firmware. + * @ret: return value this routine provides to the caller. * **/ static void @@ -12417,8 +12439,12 @@ lpfc_write_firmware(const struct firmware *fw, void *context) rc = lpfc_wr_object(phba, &dma_buffer_list, (fw->size - offset), &offset); if (rc) { - lpfc_log_write_firmware_error(phba, offset, - magic_number, ftype, fid, fsize, fw); + rc = lpfc_log_write_firmware_error(phba, offset, + magic_number, + ftype, + fid, + fsize, + fw); goto release_out; } } @@ -12438,9 +12464,12 @@ release_out: } release_firmware(fw); out: - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3024 Firmware update done: %d.\n", rc); - return; + if (rc < 0) + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3062 Firmware update error, status %d.\n", rc); + else + lpfc_printf_log(phba, KERN_ERR, LOG_INIT, + "3024 Firmware update success: size %d.\n", rc); } /** -- cgit v1.2.3 From 27f3efd637ce4859a44a7ca730c72392b4111c26 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:19 -0700 Subject: scsi: lpfc: Fix lockdep errors in sli_ringtx_put Fix lockdep error in __lpfc_sli_ringtx_put(): The hbalock is valid for sli3, but not for sli4. Change lockdep to look at ring lock if sli4. Also update comment in __lpfc_sli_issue_iocb_s4() to reflect proper lock. Note: lockdep check is already correct. Link: https://lore.kernel.org/r/20191018211832.7917-4-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 379c37451645..3a6520187ee5 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -9004,7 +9004,8 @@ lpfc_mbox_api_table_setup(struct lpfc_hba *phba, uint8_t dev_grp) * @pring: Pointer to driver SLI ring object. * @piocb: Pointer to address of newly added command iocb. * - * This function is called with hbalock held to add a command + * This function is called with hbalock held for SLI3 ports or + * the ring lock held for SLI4 ports to add a command * iocb to the txq when SLI layer cannot submit the command iocb * to the ring. **/ @@ -9012,7 +9013,10 @@ void __lpfc_sli_ringtx_put(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, struct lpfc_iocbq *piocb) { - lockdep_assert_held(&phba->hbalock); + if (phba->sli_rev == LPFC_SLI_REV4) + lockdep_assert_held(&pring->ring_lock); + else + lockdep_assert_held(&phba->hbalock); /* Insert the caller's iocb in the txq tail for later processing. */ list_add_tail(&piocb->list, &pring->txq); } @@ -9903,7 +9907,7 @@ lpfc_sli4_iocb2wqe(struct lpfc_hba *phba, struct lpfc_iocbq *iocbq, * __lpfc_sli_issue_iocb_s4 is used by other functions in the driver to issue * an iocb command to an HBA with SLI-4 interface spec. * - * This function is called with hbalock held. The function will return success + * This function is called with ringlock held. The function will return success * after it successfully submit the iocb to firmware or after adding to the * txq. **/ -- cgit v1.2.3 From feff8b3d84d3d9570f893b4d83e5eab6693d6a52 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:20 -0700 Subject: scsi: lpfc: Fix SLI3 hba in loop mode not discovering devices When operating in private loop mode, PLOGI exchanges are racing and the driver tries to abort it's PLOGI. But the PLOGI abort ends up terminating the login with the other end causing the other end to abort its PLOGI as well. Discovery never fully completes. Fix by disabling the PLOGI abort when private loop and letting the state machine play out. Link: https://lore.kernel.org/r/20191018211832.7917-5-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nportdisc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index cc6b1b0bae83..64b7aeeea337 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -542,8 +542,10 @@ lpfc_rcv_plogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * single discovery thread, this will cause a huge delay in * discovery. Also this will cause multiple state machines * running in parallel for this node. + * This only applies to a fabric environment. */ - if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) { + if ((ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) && + (vport->fc_flag & FC_FABRIC)) { /* software abort outstanding PLOGI */ lpfc_els_abort(phba, ndlp); } -- cgit v1.2.3 From 324e1c402069e8d277d2a2b18ce40bde1265b96a Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:21 -0700 Subject: scsi: lpfc: Fix bad ndlp ptr in xri aborted handling In cases where I/O may be aborted, such as driver unload or link bounces, the system will crash based on a bad ndlp pointer. Example: RIP: 0010:lpfc_sli4_abts_err_handler+0x15/0x140 [lpfc] ... lpfc_sli4_io_xri_aborted+0x20d/0x270 [lpfc] lpfc_sli4_sp_handle_abort_xri_wcqe.isra.54+0x84/0x170 [lpfc] lpfc_sli4_fp_handle_cqe+0xc2/0x480 [lpfc] __lpfc_sli4_process_cq+0xc6/0x230 [lpfc] __lpfc_sli4_hba_process_cq+0x29/0xc0 [lpfc] process_one_work+0x14c/0x390 Crash was caused by a bad ndlp address passed to I/O indicated by the XRI aborted CQE. The address was not NULL so the routine deferenced the ndlp ptr. The bad ndlp also caused the lpfc_sli4_io_xri_aborted to call an erroneous io handler. Root cause for the bad ndlp was an lpfc_ncmd that was aborted, put on the abort_io list, completed, taken off the abort_io list, sent to lpfc_release_nvme_buf where it was put back on the abort_io list because the lpfc_ncmd->flags setting LPFC_SBUF_XBUSY was not cleared on the final completion. Rework the exchange busy handling to ensure the flags are properly set for both scsi and nvme. Fixes: c490850a0947 ("scsi: lpfc: Adapt partitioned XRI lists to efficient sharing") Cc: # v5.1+ Link: https://lore.kernel.org/r/20191018211832.7917-6-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 11 +++++++---- drivers/scsi/lpfc/lpfc_sli.c | 5 ++++- drivers/scsi/lpfc/lpfc_sli.h | 3 +-- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index f06f63e58596..13e3e14b43f9 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -526,7 +526,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, &qp->lpfc_abts_io_buf_list, list) { if (psb->cur_iocbq.sli4_xritag == xri) { list_del_init(&psb->list); - psb->exch_busy = 0; + psb->flags &= ~LPFC_SBUF_XBUSY; psb->status = IOSTAT_SUCCESS; #ifdef BUILD_NVME if (psb->cur_iocbq.iocb_flag == LPFC_IO_NVME) { @@ -568,7 +568,7 @@ lpfc_sli4_io_xri_aborted(struct lpfc_hba *phba, if (iocbq->sli4_xritag != xri) continue; psb = container_of(iocbq, struct lpfc_io_buf, cur_iocbq); - psb->exch_busy = 0; + psb->flags &= ~LPFC_SBUF_XBUSY; spin_unlock_irqrestore(&phba->hbalock, iflag); if (!list_empty(&pring->txq)) lpfc_worker_wake_up(phba); @@ -788,7 +788,7 @@ lpfc_release_scsi_buf_s4(struct lpfc_hba *phba, struct lpfc_io_buf *psb) psb->prot_seg_cnt = 0; qp = psb->hdwq; - if (psb->exch_busy) { + if (psb->flags & LPFC_SBUF_XBUSY) { spin_lock_irqsave(&qp->abts_io_buf_list_lock, iflag); psb->pCmd = NULL; list_add_tail(&psb->list, &qp->lpfc_abts_io_buf_list); @@ -3837,7 +3837,10 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, lpfc_cmd->result = (pIocbOut->iocb.un.ulpWord[4] & IOERR_PARAM_MASK); lpfc_cmd->status = pIocbOut->iocb.ulpStatus; /* pick up SLI4 exhange busy status from HBA */ - lpfc_cmd->exch_busy = pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY; + if (pIocbOut->iocb_flag & LPFC_EXCHANGE_BUSY) + lpfc_cmd->flags |= LPFC_SBUF_XBUSY; + else + lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS if (lpfc_cmd->prot_data_type) { diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 3a6520187ee5..bb0e155eb32c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -11777,7 +11777,10 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba, !(cmdiocbq->iocb_flag & LPFC_IO_LIBDFC)) { lpfc_cmd = container_of(cmdiocbq, struct lpfc_io_buf, cur_iocbq); - lpfc_cmd->exch_busy = rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY; + if (rspiocbq && (rspiocbq->iocb_flag & LPFC_EXCHANGE_BUSY)) + lpfc_cmd->flags |= LPFC_SBUF_XBUSY; + else + lpfc_cmd->flags &= ~LPFC_SBUF_XBUSY; } pdone_q = cmdiocbq->context_un.wait_queue; diff --git a/drivers/scsi/lpfc/lpfc_sli.h b/drivers/scsi/lpfc/lpfc_sli.h index 37fbcb46387e..7bcf922a8be2 100644 --- a/drivers/scsi/lpfc/lpfc_sli.h +++ b/drivers/scsi/lpfc/lpfc_sli.h @@ -384,14 +384,13 @@ struct lpfc_io_buf { struct lpfc_nodelist *ndlp; uint32_t timeout; - uint16_t flags; /* TBD convert exch_busy to flags */ + uint16_t flags; #define LPFC_SBUF_XBUSY 0x1 /* SLI4 hba reported XB on WCQE cmpl */ #define LPFC_SBUF_BUMP_QDEPTH 0x2 /* bumped queue depth counter */ /* External DIF device IO conversions */ #define LPFC_SBUF_NORMAL_DIF 0x4 /* normal mode to insert/strip */ #define LPFC_SBUF_PASS_DIF 0x8 /* insert/strip mode to passthru */ #define LPFC_SBUF_NOT_POSTED 0x10 /* SGL failed post to FW. */ - uint16_t exch_busy; /* SLI4 hba reported XB on complete WCQE */ uint16_t status; /* From IOCB Word 7- ulpStatus */ uint32_t result; /* From IOCB Word 4. */ -- cgit v1.2.3 From 91a52b617cdb8bf6d298892101c061d438b84a19 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:22 -0700 Subject: scsi: lpfc: Fix hardlockup in lpfc_abort_handler In lpfc_abort_handler, the lock acquire order is hbalock (irqsave), buf_lock (irq) and ring_lock (irq). The issue is that in two places the locks are released out of order - the buf_lock and the hbalock - resulting in the cpu preemption/lock flags getting restored out of order and deadlocking the cpu. Fix the unlock order by fully releasing the hbalocks as well. CC: Zhangguanghui Link: https://lore.kernel.org/r/20191018211832.7917-7-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 13e3e14b43f9..e4ec2b99b583 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -4848,20 +4848,21 @@ lpfc_abort_handler(struct scsi_cmnd *cmnd) ret_val = __lpfc_sli_issue_iocb(phba, LPFC_FCP_RING, abtsiocb, 0); } - /* no longer need the lock after this point */ - spin_unlock_irqrestore(&phba->hbalock, flags); if (ret_val == IOCB_ERROR) { /* Indicate the IO is not being aborted by the driver. */ iocb->iocb_flag &= ~LPFC_DRIVER_ABORTED; lpfc_cmd->waitq = NULL; spin_unlock(&lpfc_cmd->buf_lock); + spin_unlock_irqrestore(&phba->hbalock, flags); lpfc_sli_release_iocbq(phba, abtsiocb); ret = FAILED; goto out; } + /* no longer need the lock after this point */ spin_unlock(&lpfc_cmd->buf_lock); + spin_unlock_irqrestore(&phba->hbalock, flags); if (phba->cfg_poll & DISABLE_FCP_RING_INT) lpfc_sli_handle_fast_ring_event(phba, -- cgit v1.2.3 From f84f8f93f01feb64fdda8dd6c72d1b7dc24ad11d Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:23 -0700 Subject: scsi: lpfc: fix coverity error of dereference after null check Log message conditional upon vport being NULL dereferences vport to determine log verbose setting. Changed to use lpfc_print_log which uses phba to determine the active log verbose setting. Fixes: 43bfea1bffb6 ("scsi: lpfc: Fix coverity errors on NULL pointer checks") Link: https://lore.kernel.org/r/20191018211832.7917-8-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index da90c7bf2287..2235a45999a8 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4292,8 +4292,8 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp = &rspiocb->iocb; if (!vport) { - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "3177 ELS response failed\n"); + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "3177 ELS response failed\n"); goto out; } if (cmdiocb->context_un.mbox) -- cgit v1.2.3 From 22770cbabf6bb77a397d9f11d41f97667dd0caa2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:24 -0700 Subject: scsi: lpfc: Slight fast-path performance optimizations Slightly rework some error check code paths for better streamlining. Added compiler unlikely hints to allow slightly better optimization of the fast-path. Removed a few pointer checks that were obviously already valid. Link: https://lore.kernel.org/r/20191018211832.7917-9-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 2 +- drivers/scsi/lpfc/lpfc_scsi.c | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 5af944b97c4c..328ddce87f12 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2093,7 +2093,7 @@ lpfc_release_nvme_buf(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_ncmd) lpfc_ncmd->flags &= ~LPFC_SBUF_BUMP_QDEPTH; qp = lpfc_ncmd->hdwq; - if (lpfc_ncmd->flags & LPFC_SBUF_XBUSY) { + if (unlikely(lpfc_ncmd->flags & LPFC_SBUF_XBUSY)) { lpfc_printf_log(phba, KERN_INFO, LOG_NVME_ABTS, "6310 XB release deferred for " "ox_id x%x on reqtag x%x\n", diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index e4ec2b99b583..959ef471d758 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -611,7 +611,7 @@ lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, } spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, iflag); - if (lpfc_ndlp_check_qdepth(phba, ndlp) && lpfc_cmd) { + if (lpfc_ndlp_check_qdepth(phba, ndlp)) { atomic_inc(&ndlp->cmd_pending); lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; } @@ -3826,7 +3826,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, phba->sli4_hba.hdwq[idx].scsi_cstat.io_cmpls++; #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) { + if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) { cpu = raw_smp_processor_id(); if (cpu < LPFC_CHECK_CPU_CNT && phba->sli4_hba.hdwq) phba->sli4_hba.hdwq[idx].cpucheck_cmpl_io[cpu]++; @@ -3874,7 +3874,7 @@ lpfc_scsi_cmd_iocb_cmpl(struct lpfc_hba *phba, struct lpfc_iocbq *pIocbIn, } #endif - if (lpfc_cmd->status) { + if (unlikely(lpfc_cmd->status)) { if (lpfc_cmd->status == IOSTAT_LOCAL_REJECT && (lpfc_cmd->result & IOERR_DRVR_MASK)) lpfc_cmd->status = IOSTAT_DRIVER_REJECT; @@ -4615,17 +4615,18 @@ lpfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd) err = lpfc_scsi_prep_dma_buf(phba, lpfc_cmd); } - if (err == 2) { - cmnd->result = DID_ERROR << 16; - goto out_fail_command_release_buf; - } else if (err) { + if (unlikely(err)) { + if (err == 2) { + cmnd->result = DID_ERROR << 16; + goto out_fail_command_release_buf; + } goto out_host_busy_free_buf; } lpfc_scsi_prep_cmnd(vport, lpfc_cmd, ndlp); #ifdef CONFIG_SCSI_LPFC_DEBUG_FS - if (phba->cpucheck_on & LPFC_CHECK_SCSI_IO) { + if (unlikely(phba->cpucheck_on & LPFC_CHECK_SCSI_IO)) { cpu = raw_smp_processor_id(); if (cpu < LPFC_CHECK_CPU_CNT) { struct lpfc_sli4_hdw_queue *hdwq = -- cgit v1.2.3 From ea85a20cd54f3b09880f6c08994b059f0d114a11 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:25 -0700 Subject: scsi: lpfc: Remove lock contention target write path Lower IOps performance with write operations. Perf tool shows lock contention in dma_pool_alloc and dma_pool_free related to the txrdy_payload_pool. The allocations are for dma buffers for XFER_RDY's, which actually are not needed for the FCP_TRECEIVE command as the command contents are used by the adapter to generate the IU. Remove the allocations and the associated buffer pool. Rather than leaving NULLs in buffer pointer locations, set command and sgl to indicate skipped SGLE indexes. Link: https://lore.kernel.org/r/20191018211832.7917-10-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 - drivers/scsi/lpfc/lpfc_init.c | 16 ++++----------- drivers/scsi/lpfc/lpfc_mem.c | 3 --- drivers/scsi/lpfc/lpfc_nvmet.c | 46 +++++++++--------------------------------- drivers/scsi/lpfc/lpfc_nvmet.h | 2 -- 5 files changed, 14 insertions(+), 54 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 291335e16806..dabb5eac5fed 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -989,7 +989,6 @@ struct lpfc_hba { struct dma_pool *lpfc_drb_pool; /* data receive buffer pool */ struct dma_pool *lpfc_nvmet_drb_pool; /* data receive buffer pool */ struct dma_pool *lpfc_hbq_pool; /* SLI3 hbq buffer pool */ - struct dma_pool *txrdy_payload_pool; struct dma_pool *lpfc_cmd_rsp_buf_pool; struct lpfc_dma_pool lpfc_mbuf_safety_pool; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 1d14aa22f973..8292b66e4b07 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -7556,18 +7556,10 @@ lpfc_create_shost(struct lpfc_hba *phba) if (phba->nvmet_support) { /* Only 1 vport (pport) will support NVME target */ - if (phba->txrdy_payload_pool == NULL) { - phba->txrdy_payload_pool = dma_pool_create( - "txrdy_pool", &phba->pcidev->dev, - TXRDY_PAYLOAD_LEN, 16, 0); - if (phba->txrdy_payload_pool) { - phba->targetport = NULL; - phba->cfg_enable_fc4_type = LPFC_ENABLE_NVME; - lpfc_printf_log(phba, KERN_INFO, - LOG_INIT | LOG_NVME_DISC, - "6076 NVME Target Found\n"); - } - } + phba->targetport = NULL; + phba->cfg_enable_fc4_type = LPFC_ENABLE_NVME; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT | LOG_NVME_DISC, + "6076 NVME Target Found\n"); } lpfc_debugfs_initialize(vport); diff --git a/drivers/scsi/lpfc/lpfc_mem.c b/drivers/scsi/lpfc/lpfc_mem.c index ae09bb863497..7082279e4c01 100644 --- a/drivers/scsi/lpfc/lpfc_mem.c +++ b/drivers/scsi/lpfc/lpfc_mem.c @@ -230,9 +230,6 @@ lpfc_mem_free(struct lpfc_hba *phba) dma_pool_destroy(phba->lpfc_hrb_pool); phba->lpfc_hrb_pool = NULL; - dma_pool_destroy(phba->txrdy_payload_pool); - phba->txrdy_payload_pool = NULL; - dma_pool_destroy(phba->lpfc_hbq_pool); phba->lpfc_hbq_pool = NULL; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index c9481a618b85..e3ac9059d33d 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -378,13 +378,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) int cpu; unsigned long iflag; - if (ctxp->txrdy) { - dma_pool_free(phba->txrdy_payload_pool, ctxp->txrdy, - ctxp->txrdy_phys); - ctxp->txrdy = NULL; - ctxp->txrdy_phys = 0; - } - if (ctxp->state == LPFC_NVMET_STE_FREE) { lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, "6411 NVMET free, already free IO x%x: %d %d\n", @@ -430,7 +423,6 @@ lpfc_nvmet_ctxbuf_post(struct lpfc_hba *phba, struct lpfc_nvmet_ctxbuf *ctx_buf) ctxp = (struct lpfc_nvmet_rcv_ctx *)ctx_buf->context; ctxp->wqeq = NULL; - ctxp->txrdy = NULL; ctxp->offset = 0; ctxp->phba = phba; ctxp->size = size; @@ -2327,7 +2319,6 @@ lpfc_nvmet_unsol_fcp_buffer(struct lpfc_hba *phba, ctxp->state, ctxp->entry_cnt, ctxp->oxid); } ctxp->wqeq = NULL; - ctxp->txrdy = NULL; ctxp->offset = 0; ctxp->phba = phba; ctxp->size = size; @@ -2606,7 +2597,6 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, struct scatterlist *sgel; union lpfc_wqe128 *wqe; struct ulp_bde64 *bde; - uint32_t *txrdy; dma_addr_t physaddr; int i, cnt; int do_pbde; @@ -2768,23 +2758,11 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, &lpfc_treceive_cmd_template.words[3], sizeof(uint32_t) * 9); - /* Words 0 - 2 : The first sg segment */ - txrdy = dma_pool_alloc(phba->txrdy_payload_pool, - GFP_KERNEL, &physaddr); - if (!txrdy) { - lpfc_printf_log(phba, KERN_ERR, LOG_NVME_IOERR, - "6041 Bad txrdy buffer: oxid x%x\n", - ctxp->oxid); - return NULL; - } - ctxp->txrdy = txrdy; - ctxp->txrdy_phys = physaddr; - wqe->fcp_treceive.bde.tus.f.bdeFlags = BUFF_TYPE_BDE_64; - wqe->fcp_treceive.bde.tus.f.bdeSize = TXRDY_PAYLOAD_LEN; - wqe->fcp_treceive.bde.addrLow = - cpu_to_le32(putPaddrLow(physaddr)); - wqe->fcp_treceive.bde.addrHigh = - cpu_to_le32(putPaddrHigh(physaddr)); + /* Words 0 - 2 : First SGE is skipped, set invalid BDE type */ + wqe->fcp_treceive.bde.tus.f.bdeFlags = LPFC_SGE_TYPE_SKIP; + wqe->fcp_treceive.bde.tus.f.bdeSize = 0; + wqe->fcp_treceive.bde.addrLow = 0; + wqe->fcp_treceive.bde.addrHigh = 0; /* Word 4 */ wqe->fcp_treceive.relative_offset = ctxp->offset; @@ -2819,17 +2797,13 @@ lpfc_nvmet_prep_fcp_wqe(struct lpfc_hba *phba, /* Word 12 */ wqe->fcp_tsend.fcp_data_len = rsp->transfer_length; - /* Setup 1 TXRDY and 1 SKIP SGE */ - txrdy[0] = 0; - txrdy[1] = cpu_to_be32(rsp->transfer_length); - txrdy[2] = 0; - - sgl->addr_hi = putPaddrHigh(physaddr); - sgl->addr_lo = putPaddrLow(physaddr); + /* Setup 2 SKIP SGEs */ + sgl->addr_hi = 0; + sgl->addr_lo = 0; sgl->word2 = 0; - bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_DATA); + bf_set(lpfc_sli4_sge_type, sgl, LPFC_SGE_TYPE_SKIP); sgl->word2 = cpu_to_le32(sgl->word2); - sgl->sge_len = cpu_to_le32(TXRDY_PAYLOAD_LEN); + sgl->sge_len = 0; sgl++; sgl->addr_hi = 0; sgl->addr_lo = 0; diff --git a/drivers/scsi/lpfc/lpfc_nvmet.h b/drivers/scsi/lpfc/lpfc_nvmet.h index 8ff67deac10a..b80b1639b9a7 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.h +++ b/drivers/scsi/lpfc/lpfc_nvmet.h @@ -112,9 +112,7 @@ struct lpfc_nvmet_rcv_ctx { struct lpfc_hba *phba; struct lpfc_iocbq *wqeq; struct lpfc_iocbq *abort_wqeq; - dma_addr_t txrdy_phys; spinlock_t ctxlock; /* protect flag access */ - uint32_t *txrdy; uint32_t sid; uint32_t offset; uint16_t oxid; -- cgit v1.2.3 From 8156d378c4cbf8ca19df5d8f0c610ce6923b61e2 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:26 -0700 Subject: scsi: lpfc: Revise interrupt coalescing for missing scenarios The existing "auto eq delay" mechanism was sometimes skipping over an EQ, not ramping the coalescing down under light load fast enough, and in other cases never kicked in as cpu sharing by multiple vectors didn't quite add up right. Tweak the interrupt mechanism such that: - Add a flag to the EQ to force checking for colaescing values when being serviced in the interrupt handler. The flag will be set by any CQ bound to the EQ whenever the number of CQ elements process in a single scan meets or exceeds the hardware queue notify level. E.g. there's a significant number of completions happening. - In the heartbeat work item that checks coalescing: - Replace the structure that was counting the number of EQs that interrupted on a single cpu with a new structure that looks at the EQ to see whether EQ currently has a coalescing value (thus it should be re-evaluate) or was marked by the new flag indicating heavy completions. - When a cpu, which may be servicing multiple vectors, had at least 1 EQ that should be checked, a new coalescing delay is calculated based on the number of interrupts that occurred on the cpu. - The new coalescing value is then applied to the EQs that had interrupted on the cpu. Link: https://lore.kernel.org/r/20191018211832.7917-11-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 1 - drivers/scsi/lpfc/lpfc_init.c | 51 ++++++++++++++++++------------------------- drivers/scsi/lpfc/lpfc_sli.c | 3 ++- drivers/scsi/lpfc/lpfc_sli4.h | 1 + 4 files changed, 24 insertions(+), 32 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 1cd3016f7783..ac86b80230e7 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -210,7 +210,6 @@ struct lpfc_sli_intf { #define LPFC_MAX_IMAX 5000000 #define LPFC_DEF_IMAX 0 -#define LPFC_IMAX_THRESHOLD 1000 #define LPFC_MAX_AUTO_EQ_DELAY 120 #define LPFC_EQ_DELAY_STEP 15 #define LPFC_EQD_ISR_TRIGGER 20000 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 8292b66e4b07..316a2c2beb0c 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -1235,10 +1235,9 @@ lpfc_hb_eq_delay_work(struct work_struct *work) struct lpfc_hba, eq_delay_work); struct lpfc_eq_intr_info *eqi, *eqi_new; struct lpfc_queue *eq, *eq_next; - unsigned char *eqcnt = NULL; + unsigned char *ena_delay = NULL; uint32_t usdelay; int i; - bool update = false; if (!phba->cfg_auto_imax || phba->pport->load_flag & FC_UNLOADING) return; @@ -1247,44 +1246,36 @@ lpfc_hb_eq_delay_work(struct work_struct *work) phba->pport->fc_flag & FC_OFFLINE_MODE) goto requeue; - eqcnt = kcalloc(num_possible_cpus(), sizeof(unsigned char), - GFP_KERNEL); - if (!eqcnt) + ena_delay = kcalloc(phba->sli4_hba.num_possible_cpu, sizeof(*ena_delay), + GFP_KERNEL); + if (!ena_delay) goto requeue; - if (phba->cfg_irq_chann > 1) { - /* Loop thru all IRQ vectors */ - for (i = 0; i < phba->cfg_irq_chann; i++) { - /* Get the EQ corresponding to the IRQ vector */ - eq = phba->sli4_hba.hba_eq_hdl[i].eq; - if (!eq) - continue; - if (eq->q_mode) { - update = true; - break; - } - if (eqcnt[eq->last_cpu] < 2) - eqcnt[eq->last_cpu]++; + for (i = 0; i < phba->cfg_irq_chann; i++) { + /* Get the EQ corresponding to the IRQ vector */ + eq = phba->sli4_hba.hba_eq_hdl[i].eq; + if (!eq) + continue; + if (eq->q_mode || eq->q_flag & HBA_EQ_DELAY_CHK) { + eq->q_flag &= ~HBA_EQ_DELAY_CHK; + ena_delay[eq->last_cpu] = 1; } - } else - update = true; + } for_each_present_cpu(i) { eqi = per_cpu_ptr(phba->sli4_hba.eq_info, i); - if (!update && eqcnt[i] < 2) { - eqi->icnt = 0; - continue; + if (ena_delay[i]) { + usdelay = (eqi->icnt >> 10) * LPFC_EQ_DELAY_STEP; + if (usdelay > LPFC_MAX_AUTO_EQ_DELAY) + usdelay = LPFC_MAX_AUTO_EQ_DELAY; + } else { + usdelay = 0; } - usdelay = (eqi->icnt / LPFC_IMAX_THRESHOLD) * - LPFC_EQ_DELAY_STEP; - if (usdelay > LPFC_MAX_AUTO_EQ_DELAY) - usdelay = LPFC_MAX_AUTO_EQ_DELAY; - eqi->icnt = 0; list_for_each_entry_safe(eq, eq_next, &eqi->list, cpu_list) { - if (eq->last_cpu != i) { + if (unlikely(eq->last_cpu != i)) { eqi_new = per_cpu_ptr(phba->sli4_hba.eq_info, eq->last_cpu); list_move_tail(&eq->cpu_list, &eqi_new->list); @@ -1296,7 +1287,7 @@ lpfc_hb_eq_delay_work(struct work_struct *work) } } - kfree(eqcnt); + kfree(ena_delay); requeue: queue_delayed_work(phba->wq, &phba->eq_delay_work, diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index bb0e155eb32c..0e6674bd15c6 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -13640,6 +13640,7 @@ __lpfc_sli4_process_cq(struct lpfc_hba *phba, struct lpfc_queue *cq, phba->sli4_hba.sli4_write_cq_db(phba, cq, consumed, LPFC_QUEUE_NOARM); consumed = 0; + cq->assoc_qp->q_flag |= HBA_EQ_DELAY_CHK; } if (count == LPFC_NVMET_CQ_NOTIFY) @@ -14278,7 +14279,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) fpeq->last_cpu = raw_smp_processor_id(); if (icnt > LPFC_EQD_ISR_TRIGGER && - phba->cfg_irq_chann == 1 && + fpeq->q_flag & HBA_EQ_DELAY_CHK && phba->cfg_auto_imax && fpeq->q_mode != LPFC_MAX_AUTO_EQ_DELAY && phba->sli.sli_flag & LPFC_SLI_USE_EQDR) diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index 0d4882a9e634..c9e068ca0fec 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -199,6 +199,7 @@ struct lpfc_queue { uint8_t q_flag; #define HBA_NVMET_WQFULL 0x1 /* We hit WQ Full condition for NVMET */ #define HBA_NVMET_CQ_NOTIFY 0x1 /* LPFC_NVMET_CQ_NOTIFY CQEs this EQE */ +#define HBA_EQ_DELAY_CHK 0x2 /* EQ is a candidate for coalescing */ #define LPFC_NVMET_CQ_NOTIFY 4 void __iomem *db_regaddr; uint16_t dpp_enable; -- cgit v1.2.3 From 95bfc6d8ad86a76c89f62bb466f740b0fc05a667 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:27 -0700 Subject: scsi: lpfc: Make FW logging dynamically configurable Currently, the FW logging facility is a load/boot time parameter which requires the driver to be unloaded/reloaded or the system rebooted in order to change its configuration. Convert the logging facility to allow dynamic enablement and configuration. Specifically: - Convert the feature so that it can be enabled dynamically via an attribute. Additionally, the size of the buffer can be configured dynamically. - Add locks around states that now may be changing. - Tie the feature into debugfs so that the logs can be read at any time. Link: https://lore.kernel.org/r/20191018211832.7917-12-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 9 ++- drivers/scsi/lpfc/lpfc_attr.c | 48 +++++++++++++++- drivers/scsi/lpfc/lpfc_bsg.c | 18 ++++-- drivers/scsi/lpfc/lpfc_debugfs.c | 117 ++++++++++++++++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_sli.c | 22 +++++++- 5 files changed, 204 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index dabb5eac5fed..884d6076d7aa 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -605,6 +605,12 @@ struct lpfc_epd_pool { spinlock_t lock; /* lock for expedite pool */ }; +enum ras_state { + INACTIVE, + REG_INPROGRESS, + ACTIVE +}; + struct lpfc_ras_fwlog { uint8_t *fwlog_buff; uint32_t fw_buffcount; /* Buffer size posted to FW */ @@ -621,7 +627,7 @@ struct lpfc_ras_fwlog { bool ras_enabled; /* Ras Enabled for the function */ #define LPFC_RAS_DISABLE_LOGGING 0x00 #define LPFC_RAS_ENABLE_LOGGING 0x01 - bool ras_active; /* RAS logging running state */ + enum ras_state state; /* RAS logging running state */ }; struct lpfc_hba { @@ -1053,6 +1059,7 @@ struct lpfc_hba { #ifdef LPFC_HDWQ_LOCK_STAT struct dentry *debug_lockstat; #endif + struct dentry *debug_ras_log; atomic_t nvmeio_trc_cnt; uint32_t nvmeio_trc_size; uint32_t nvmeio_trc_output_idx; diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 266a71b01c47..ba504cc6e8ed 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5932,7 +5932,53 @@ LPFC_ATTR_RW(enable_mds_diags, 0, 0, 1, "Enable MDS Diagnostics"); * [1-4] = Multiple of 1/4th Mb of host memory for FW logging * Value range [0..4]. Default value is 0 */ -LPFC_ATTR_RW(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging"); +LPFC_ATTR(ras_fwlog_buffsize, 0, 0, 4, "Host memory for FW logging"); +lpfc_param_show(ras_fwlog_buffsize); + +static ssize_t +lpfc_ras_fwlog_buffsize_set(struct lpfc_hba *phba, uint val) +{ + int ret = 0; + enum ras_state state; + + if (!lpfc_rangecheck(val, 0, 4)) + return -EINVAL; + + if (phba->cfg_ras_fwlog_buffsize == val) + return 0; + + if (phba->cfg_ras_fwlog_func == PCI_FUNC(phba->pcidev->devfn)) + return -EINVAL; + + spin_lock_irq(&phba->hbalock); + state = phba->ras_fwlog.state; + spin_unlock_irq(&phba->hbalock); + + if (state == REG_INPROGRESS) { + lpfc_printf_log(phba, KERN_ERR, LOG_SLI, "6147 RAS Logging " + "registration is in progress\n"); + return -EBUSY; + } + + /* For disable logging: stop the logs and free the DMA. + * For ras_fwlog_buffsize size change we still need to free and + * reallocate the DMA in lpfc_sli4_ras_fwlog_init. + */ + phba->cfg_ras_fwlog_buffsize = val; + if (state == ACTIVE) { + lpfc_ras_stop_fwlog(phba); + lpfc_sli4_ras_dma_free(phba); + } + + lpfc_sli4_ras_init(phba); + if (phba->ras_fwlog.ras_enabled) + ret = lpfc_sli4_ras_fwlog_init(phba, phba->cfg_ras_fwlog_level, + LPFC_RAS_ENABLE_LOGGING); + return ret; +} + +lpfc_param_store(ras_fwlog_buffsize); +static DEVICE_ATTR_RW(lpfc_ras_fwlog_buffsize); /* * lpfc_ras_fwlog_level: Firmware logging verbosity level diff --git a/drivers/scsi/lpfc/lpfc_bsg.c b/drivers/scsi/lpfc/lpfc_bsg.c index 39a736b887b1..d4e1b120cc9e 100644 --- a/drivers/scsi/lpfc/lpfc_bsg.c +++ b/drivers/scsi/lpfc/lpfc_bsg.c @@ -5435,10 +5435,12 @@ lpfc_bsg_get_ras_config(struct bsg_job *job) bsg_reply->reply_data.vendor_reply.vendor_rsp; /* Current logging state */ - if (ras_fwlog->ras_active == true) + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state == ACTIVE) ras_reply->state = LPFC_RASLOG_STATE_RUNNING; else ras_reply->state = LPFC_RASLOG_STATE_STOPPED; + spin_unlock_irq(&phba->hbalock); ras_reply->log_level = phba->ras_fwlog.fw_loglevel; ras_reply->log_buff_sz = phba->cfg_ras_fwlog_buffsize; @@ -5495,10 +5497,13 @@ lpfc_bsg_set_ras_config(struct bsg_job *job) if (action == LPFC_RASACTION_STOP_LOGGING) { /* Check if already disabled */ - if (ras_fwlog->ras_active == false) { + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state != ACTIVE) { + spin_unlock_irq(&phba->hbalock); rc = -ESRCH; goto ras_job_error; } + spin_unlock_irq(&phba->hbalock); /* Disable logging */ lpfc_ras_stop_fwlog(phba); @@ -5509,8 +5514,10 @@ lpfc_bsg_set_ras_config(struct bsg_job *job) * FW-logging with new log-level. Return status * "Logging already Running" to caller. **/ - if (ras_fwlog->ras_active) + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state != INACTIVE) action_status = -EINPROGRESS; + spin_unlock_irq(&phba->hbalock); /* Enable logging */ rc = lpfc_sli4_ras_fwlog_init(phba, log_level, @@ -5626,10 +5633,13 @@ lpfc_bsg_get_ras_fwlog(struct bsg_job *job) goto ras_job_error; /* Logging to be stopped before reading */ - if (ras_fwlog->ras_active == true) { + spin_lock_irq(&phba->hbalock); + if (ras_fwlog->state == ACTIVE) { + spin_unlock_irq(&phba->hbalock); rc = -EINPROGRESS; goto ras_job_error; } + spin_unlock_irq(&phba->hbalock); if (job->request_len < sizeof(struct fc_bsg_request) + diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 8d34be60d379..ab124f7d50d6 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -2078,6 +2078,96 @@ lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf, } #endif +int +lpfc_debugfs_ras_log_data(struct lpfc_hba *phba, char *buffer, int size) +{ + int copied = 0; + struct lpfc_dmabuf *dmabuf, *next; + + spin_lock_irq(&phba->hbalock); + if (phba->ras_fwlog.state != ACTIVE) { + spin_unlock_irq(&phba->hbalock); + return -EINVAL; + } + spin_unlock_irq(&phba->hbalock); + + list_for_each_entry_safe(dmabuf, next, + &phba->ras_fwlog.fwlog_buff_list, list) { + memcpy(buffer + copied, dmabuf->virt, LPFC_RAS_MAX_ENTRY_SIZE); + copied += LPFC_RAS_MAX_ENTRY_SIZE; + if (size > copied) + break; + } + return copied; +} + +static int +lpfc_debugfs_ras_log_release(struct inode *inode, struct file *file) +{ + struct lpfc_debug *debug = file->private_data; + + vfree(debug->buffer); + kfree(debug); + + return 0; +} + +/** + * lpfc_debugfs_ras_log_open - Open the RAS log debugfs buffer + * @inode: The inode pointer that contains a vport pointer. + * @file: The file pointer to attach the log output. + * + * Description: + * This routine is the entry point for the debugfs open file operation. It gets + * the vport from the i_private field in @inode, allocates the necessary buffer + * for the log, fills the buffer from the in-memory log for this vport, and then + * returns a pointer to that log in the private_data field in @file. + * + * Returns: + * This function returns zero if successful. On error it will return a negative + * error value. + **/ +static int +lpfc_debugfs_ras_log_open(struct inode *inode, struct file *file) +{ + struct lpfc_hba *phba = inode->i_private; + struct lpfc_debug *debug; + int size; + int rc = -ENOMEM; + + spin_lock_irq(&phba->hbalock); + if (phba->ras_fwlog.state != ACTIVE) { + spin_unlock_irq(&phba->hbalock); + rc = -EINVAL; + goto out; + } + spin_unlock_irq(&phba->hbalock); + debug = kmalloc(sizeof(*debug), GFP_KERNEL); + if (!debug) + goto out; + + size = LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize; + debug->buffer = vmalloc(size); + if (!debug->buffer) + goto free_debug; + + debug->len = lpfc_debugfs_ras_log_data(phba, debug->buffer, size); + if (debug->len < 0) { + rc = -EINVAL; + goto free_buffer; + } + file->private_data = debug; + + return 0; + +free_buffer: + vfree(debug->buffer); +free_debug: + kfree(debug); +out: + return rc; +} + /** * lpfc_debugfs_dumpHBASlim_open - Open the Dump HBA SLIM debugfs buffer * @inode: The inode pointer that contains a vport pointer. @@ -5286,6 +5376,16 @@ static const struct file_operations lpfc_debugfs_op_lockstat = { }; #endif +#undef lpfc_debugfs_ras_log +static const struct file_operations lpfc_debugfs_ras_log = { + .owner = THIS_MODULE, + .open = lpfc_debugfs_ras_log_open, + .llseek = lpfc_debugfs_lseek, + .read = lpfc_debugfs_read, + .release = lpfc_debugfs_ras_log_release, +}; +#endif + #undef lpfc_debugfs_op_dumpHBASlim static const struct file_operations lpfc_debugfs_op_dumpHBASlim = { .owner = THIS_MODULE, @@ -5457,7 +5557,6 @@ static const struct file_operations lpfc_idiag_op_extAcc = { .release = lpfc_idiag_cmd_release, }; -#endif /* lpfc_idiag_mbxacc_dump_bsg_mbox - idiag debugfs dump bsg mailbox command * @phba: Pointer to HBA context object. @@ -5707,6 +5806,19 @@ lpfc_debugfs_initialize(struct lpfc_vport *vport) goto debug_failed; } + /* RAS log */ + snprintf(name, sizeof(name), "ras_log"); + phba->debug_ras_log = + debugfs_create_file(name, 0644, + phba->hba_debugfs_root, + phba, &lpfc_debugfs_ras_log); + if (!phba->debug_ras_log) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, + "6148 Cannot create debugfs" + " ras_log\n"); + goto debug_failed; + } + /* Setup hbqinfo */ snprintf(name, sizeof(name), "hbqinfo"); phba->debug_hbqinfo = @@ -6117,6 +6229,9 @@ lpfc_debugfs_terminate(struct lpfc_vport *vport) debugfs_remove(phba->debug_hbqinfo); /* hbqinfo */ phba->debug_hbqinfo = NULL; + debugfs_remove(phba->debug_ras_log); + phba->debug_ras_log = NULL; + #ifdef LPFC_HDWQ_LOCK_STAT debugfs_remove(phba->debug_lockstat); /* lockstat */ phba->debug_lockstat = NULL; diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 0e6674bd15c6..294f041961a8 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6219,11 +6219,16 @@ lpfc_ras_stop_fwlog(struct lpfc_hba *phba) { struct lpfc_ras_fwlog *ras_fwlog = &phba->ras_fwlog; - ras_fwlog->ras_active = false; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = INACTIVE; + spin_unlock_irq(&phba->hbalock); /* Disable FW logging to host memory */ writel(LPFC_CTL_PDEV_CTL_DDL_RAS, phba->sli4_hba.conf_regs_memmap_p + LPFC_CTL_PDEV_CTL_OFFSET); + + /* Wait 10ms for firmware to stop using DMA buffer */ + usleep_range(10 * 1000, 20 * 1000); } /** @@ -6259,7 +6264,9 @@ lpfc_sli4_ras_dma_free(struct lpfc_hba *phba) ras_fwlog->lwpd.virt = NULL; } - ras_fwlog->ras_active = false; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = INACTIVE; + spin_unlock_irq(&phba->hbalock); } /** @@ -6361,7 +6368,9 @@ lpfc_sli4_ras_mbox_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) goto disable_ras; } - ras_fwlog->ras_active = true; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = ACTIVE; + spin_unlock_irq(&phba->hbalock); mempool_free(pmb, phba->mbox_mem_pool); return; @@ -6393,6 +6402,10 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, uint32_t len = 0, fwlog_buffsize, fwlog_entry_count; int rc = 0; + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = INACTIVE; + spin_unlock_irq(&phba->hbalock); + fwlog_buffsize = (LPFC_RAS_MIN_BUFF_POST_SIZE * phba->cfg_ras_fwlog_buffsize); fwlog_entry_count = (fwlog_buffsize/LPFC_RAS_MAX_ENTRY_SIZE); @@ -6452,6 +6465,9 @@ lpfc_sli4_ras_fwlog_init(struct lpfc_hba *phba, mbx_fwlog->u.request.lwpd.addr_lo = putPaddrLow(ras_fwlog->lwpd.phys); mbx_fwlog->u.request.lwpd.addr_hi = putPaddrHigh(ras_fwlog->lwpd.phys); + spin_lock_irq(&phba->hbalock); + ras_fwlog->state = REG_INPROGRESS; + spin_unlock_irq(&phba->hbalock); mbox->vport = phba->pport; mbox->mbox_cmpl = lpfc_sli4_ras_mbox_cmpl; -- cgit v1.2.3 From b1dfa5411ea440f7a5bd65176259ffb3bfbdecf0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:28 -0700 Subject: scsi: lpfc: Add log macros to allow print by serverity or verbosity setting Add two new macros to aid in message logging: Both macros print a message if the corresponding lpfc verbosity setting is set or the kernel log level is WARNING or more critical. One macro is for use with a phba structure, the other with a vport structure. [mkp: typo] Link: https://lore.kernel.org/r/20191018211832.7917-13-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_logmsg.h | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_logmsg.h b/drivers/scsi/lpfc/lpfc_logmsg.h index ea10f03437f5..148d02a27b58 100644 --- a/drivers/scsi/lpfc/lpfc_logmsg.h +++ b/drivers/scsi/lpfc/lpfc_logmsg.h @@ -46,6 +46,23 @@ #define LOG_NVME_IOERR 0x00800000 /* NVME IO Error events. */ #define LOG_ALL_MSG 0xffffffff /* LOG all messages */ +/* generate message by verbose log setting or severity */ +#define lpfc_vlog_msg(vport, level, mask, fmt, arg...) \ +{ if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '4')) \ + dev_printk(level, &((vport)->phba->pcidev)->dev, "%d:(%d):" \ + fmt, (vport)->phba->brd_no, vport->vpi, ##arg); } + +#define lpfc_log_msg(phba, level, mask, fmt, arg...) \ +do { \ + { uint32_t log_verbose = (phba)->pport ? \ + (phba)->pport->cfg_log_verbose : \ + (phba)->cfg_log_verbose; \ + if (((mask) & log_verbose) || (level[1] <= '4')) \ + dev_printk(level, &((phba)->pcidev)->dev, "%d:" \ + fmt, phba->brd_no, ##arg); \ + } \ +} while (0) + #define lpfc_printf_vlog(vport, level, mask, fmt, arg...) \ do { \ { if (((mask) & (vport)->cfg_log_verbose) || (level[1] <= '3')) \ -- cgit v1.2.3 From e7d8595272553c27846946601b72e4c581f9712a Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:29 -0700 Subject: scsi: lpfc: Add FA-WWN Async Event reporting Add decode support for adapter Async Events which report FA-WWN configuration errors. Link: https://lore.kernel.org/r/20191018211832.7917-14-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 1 + drivers/scsi/lpfc/lpfc_init.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index ac86b80230e7..818a0f4325af 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -4261,6 +4261,7 @@ struct lpfc_acqe_sli { #define LPFC_SLI_EVENT_TYPE_DIAG_DUMP 0x5 #define LPFC_SLI_EVENT_TYPE_MISCONFIGURED 0x9 #define LPFC_SLI_EVENT_TYPE_REMOTE_DPORT 0xA +#define LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN 0xF #define LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE 0x10 }; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 316a2c2beb0c..d821adbb0047 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -5430,6 +5430,16 @@ lpfc_sli4_async_sli_evt(struct lpfc_hba *phba, struct lpfc_acqe_sli *acqe_sli) "Event Data1:x%08x Event Data2: x%08x\n", acqe_sli->event_data1, acqe_sli->event_data2); break; + case LPFC_SLI_EVENT_TYPE_MISCONF_FAWWN: + /* Misconfigured WWN. Reports that the SLI Port is configured + * to use FA-WWN, but the attached device doesn’t support it. + * No driver action is required. + * Event Data1 - N.A, Event Data2 - N.A + */ + lpfc_log_msg(phba, KERN_WARNING, LOG_SLI, + "2699 Misconfigured FA-WWN - Attached device does " + "not support FA-WWN\n"); + break; case LPFC_SLI_EVENT_TYPE_EEPROM_FAILURE: /* EEPROM failure. No driver action is required */ lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, -- cgit v1.2.3 From 83c6cb1ae8be6948b5fa43b2450a176dba80688b Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:30 -0700 Subject: scsi: lpfc: Add FC-AL support to lpe32000 models In the past, the lpe32000 models, based their main support being for 32G, and as FC-AL is not supported in the FC standards past 8G, did not support FC-AL operation. This patch adds private-loop FC-AL support for the LPE32000 adapters when a link is 8G or below. To avoid conditions where link rate may change, which would cause non-connectivity to the AL device, FC-AL mode must become a persistent setting and the link kept at a speed supporting FC-AL. The patch: - Adds a pls attribute indicating whether the adapter properly supports FC-AL. - Adds support for the adapter to indicate that topology should be fixed and the topology types to be configured. - Adds a pt attribute to report the persistent topology if present. Link: https://lore.kernel.org/r/20191018211832.7917-15-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 1 + drivers/scsi/lpfc/lpfc_attr.c | 38 +++++++++++++++++- drivers/scsi/lpfc/lpfc_hw4.h | 12 ++++++ drivers/scsi/lpfc/lpfc_init.c | 90 +++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/lpfc/lpfc_mbox.c | 1 + drivers/scsi/lpfc/lpfc_sli4.h | 1 + 6 files changed, 142 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 884d6076d7aa..4559f1700c6d 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -731,6 +731,7 @@ struct lpfc_hba { #define HBA_FCOE_MODE 0x4 /* HBA function in FCoE Mode */ #define HBA_SP_QUEUE_EVT 0x8 /* Slow-path qevt posted to worker thread*/ #define HBA_POST_RECEIVE_BUFFER 0x10 /* Rcv buffers need to be posted */ +#define HBA_PERSISTENT_TOPO 0x20 /* Persistent topology support in hba */ #define ELS_XRI_ABORT_EVENT 0x40 #define ASYNC_EVENT 0x80 #define LINK_DISABLED 0x100 /* Link disabled by user */ diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index ba504cc6e8ed..e738c1529d2d 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -3535,6 +3535,31 @@ LPFC_ATTR_R(enable_rrq, 2, 0, 2, LPFC_ATTR_R(suppress_link_up, LPFC_INITIALIZE_LINK, LPFC_INITIALIZE_LINK, LPFC_DELAY_INIT_LINK_INDEFINITELY, "Suppress Link Up at initialization"); + +static ssize_t +lpfc_pls_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + phba->sli4_hba.pc_sli4_params.pls); +} +static DEVICE_ATTR(pls, 0444, + lpfc_pls_show, NULL); + +static ssize_t +lpfc_pt_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_hba *phba = ((struct lpfc_vport *)shost->hostdata)->phba; + + return scnprintf(buf, PAGE_SIZE, "%d\n", + (phba->hba_flag & HBA_PERSISTENT_TOPO) ? 1 : 0); +} +static DEVICE_ATTR(pt, 0444, + lpfc_pt_show, NULL); + /* # lpfc_cnt: Number of IOCBs allocated for ELS, CT, and ABTS # 1 - (1024) @@ -4095,7 +4120,16 @@ lpfc_topology_store(struct device *dev, struct device_attribute *attr, val); return -EINVAL; } - if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || + /* + * The 'topology' is not a configurable parameter if : + * - persistent topology enabled + * - G7 adapters + * - G6 with no private loop support + */ + + if (((phba->hba_flag & HBA_PERSISTENT_TOPO) || + (!phba->sli4_hba.pc_sli4_params.pls && + phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC) || phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && val == 4) { lpfc_printf_vlog(vport, KERN_ERR, LOG_INIT, @@ -6117,6 +6151,8 @@ struct device_attribute *lpfc_hba_attrs[] = { &dev_attr_lpfc_req_fw_upgrade, &dev_attr_lpfc_suppress_link_up, &dev_attr_iocb_hw, + &dev_attr_pls, + &dev_attr_pt, &dev_attr_txq_hw, &dev_attr_txcmplq_hw, &dev_attr_lpfc_fips_level, diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 818a0f4325af..d40bfe5aa21f 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -2809,6 +2809,15 @@ struct lpfc_mbx_read_config { #define lpfc_mbx_rd_conf_trunk_SHIFT 12 #define lpfc_mbx_rd_conf_trunk_MASK 0x0000000F #define lpfc_mbx_rd_conf_trunk_WORD word2 +#define lpfc_mbx_rd_conf_pt_SHIFT 20 +#define lpfc_mbx_rd_conf_pt_MASK 0x00000003 +#define lpfc_mbx_rd_conf_pt_WORD word2 +#define lpfc_mbx_rd_conf_tf_SHIFT 22 +#define lpfc_mbx_rd_conf_tf_MASK 0x00000001 +#define lpfc_mbx_rd_conf_tf_WORD word2 +#define lpfc_mbx_rd_conf_ptv_SHIFT 23 +#define lpfc_mbx_rd_conf_ptv_MASK 0x00000001 +#define lpfc_mbx_rd_conf_ptv_WORD word2 #define lpfc_mbx_rd_conf_topology_SHIFT 24 #define lpfc_mbx_rd_conf_topology_MASK 0x000000FF #define lpfc_mbx_rd_conf_topology_WORD word2 @@ -3479,6 +3488,9 @@ struct lpfc_sli4_parameters { #define cfg_bv1s_SHIFT 10 #define cfg_bv1s_MASK 0x00000001 #define cfg_bv1s_WORD word19 +#define cfg_pvl_SHIFT 13 +#define cfg_pvl_MASK 0x00000001 +#define cfg_pvl_WORD word19 #define cfg_nsler_SHIFT 12 #define cfg_nsler_MASK 0x00000001 diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index d821adbb0047..686677dd52a4 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -8239,6 +8239,94 @@ lpfc_destroy_bootstrap_mbox(struct lpfc_hba *phba) memset(&phba->sli4_hba.bmbx, 0, sizeof(struct lpfc_bmbx)); } +static const char * const lpfc_topo_to_str[] = { + "Loop then P2P", + "Loopback", + "P2P Only", + "Unsupported", + "Loop Only", + "Unsupported", + "P2P then Loop", +}; + +/** + * lpfc_map_topology - Map the topology read from READ_CONFIG + * @phba: pointer to lpfc hba data structure. + * @rdconf: pointer to read config data + * + * This routine is invoked to map the topology values as read + * from the read config mailbox command. If the persistent + * topology feature is supported, the firmware will provide the + * saved topology information to be used in INIT_LINK + * + **/ +#define LINK_FLAGS_DEF 0x0 +#define LINK_FLAGS_P2P 0x1 +#define LINK_FLAGS_LOOP 0x2 +static void +lpfc_map_topology(struct lpfc_hba *phba, struct lpfc_mbx_read_config *rd_config) +{ + u8 ptv, tf, pt; + + ptv = bf_get(lpfc_mbx_rd_conf_ptv, rd_config); + tf = bf_get(lpfc_mbx_rd_conf_tf, rd_config); + pt = bf_get(lpfc_mbx_rd_conf_pt, rd_config); + + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2027 Read Config Data : ptv:0x%x, tf:0x%x pt:0x%x", + ptv, tf, pt); + if (!ptv) { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2019 FW does not support persistent topology " + "Using driver parameter defined value [%s]", + lpfc_topo_to_str[phba->cfg_topology]); + return; + } + /* FW supports persistent topology - override module parameter value */ + phba->hba_flag |= HBA_PERSISTENT_TOPO; + switch (phba->pcidev->device) { + case PCI_DEVICE_ID_LANCER_G7_FC: + if (tf || (pt == LINK_FLAGS_LOOP)) { + /* Invalid values from FW - use driver params */ + phba->hba_flag &= ~HBA_PERSISTENT_TOPO; + } else { + /* Prism only supports PT2PT topology */ + phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT; + } + break; + case PCI_DEVICE_ID_LANCER_G6_FC: + if (!tf) { + phba->cfg_topology = ((pt == LINK_FLAGS_LOOP) + ? FLAGS_TOPOLOGY_MODE_LOOP + : FLAGS_TOPOLOGY_MODE_PT_PT); + } else { + phba->hba_flag &= ~HBA_PERSISTENT_TOPO; + } + break; + default: /* G5 */ + if (tf) { + /* If topology failover set - pt is '0' or '1' */ + phba->cfg_topology = (pt ? FLAGS_TOPOLOGY_MODE_PT_LOOP : + FLAGS_TOPOLOGY_MODE_LOOP_PT); + } else { + phba->cfg_topology = ((pt == LINK_FLAGS_P2P) + ? FLAGS_TOPOLOGY_MODE_PT_PT + : FLAGS_TOPOLOGY_MODE_LOOP); + } + break; + } + if (phba->hba_flag & HBA_PERSISTENT_TOPO) { + lpfc_printf_log(phba, KERN_INFO, LOG_SLI, + "2020 Using persistent topology value [%s]", + lpfc_topo_to_str[phba->cfg_topology]); + } else { + lpfc_printf_log(phba, KERN_WARNING, LOG_SLI, + "2021 Invalid topology values from FW " + "Using driver parameter defined value [%s]", + lpfc_topo_to_str[phba->cfg_topology]); + } +} + /** * lpfc_sli4_read_config - Get the config parameters. * @phba: pointer to lpfc hba data structure. @@ -8350,6 +8438,7 @@ lpfc_sli4_read_config(struct lpfc_hba *phba) phba->max_vpi = (phba->sli4_hba.max_cfg_param.max_vpi > 0) ? (phba->sli4_hba.max_cfg_param.max_vpi - 1) : 0; phba->max_vports = phba->max_vpi; + lpfc_map_topology(phba, rd_config); lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "2003 cfg params Extents? %d " "XRI(B:%d M:%d), " @@ -11542,6 +11631,7 @@ lpfc_get_sli4_parameters(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq) sli4_params->cqav = bf_get(cfg_cqav, mbx_sli4_parameters); sli4_params->wqsize = bf_get(cfg_wqsize, mbx_sli4_parameters); sli4_params->bv1s = bf_get(cfg_bv1s, mbx_sli4_parameters); + sli4_params->pls = bf_get(cfg_pvl, mbx_sli4_parameters); sli4_params->sgl_pages_max = bf_get(cfg_sgl_page_cnt, mbx_sli4_parameters); sli4_params->wqpcnt = bf_get(cfg_wqpcnt, mbx_sli4_parameters); diff --git a/drivers/scsi/lpfc/lpfc_mbox.c b/drivers/scsi/lpfc/lpfc_mbox.c index 8abe933bad09..d1773c01d2b3 100644 --- a/drivers/scsi/lpfc/lpfc_mbox.c +++ b/drivers/scsi/lpfc/lpfc_mbox.c @@ -515,6 +515,7 @@ lpfc_init_link(struct lpfc_hba * phba, if ((phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC || phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC) && + !(phba->sli4_hba.pc_sli4_params.pls) && mb->un.varInitLnk.link_flags & FLAGS_TOPOLOGY_MODE_LOOP) { mb->un.varInitLnk.link_flags = FLAGS_TOPOLOGY_MODE_PT_PT; phba->cfg_topology = FLAGS_TOPOLOGY_MODE_PT_PT; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index c9e068ca0fec..bbe24c19b1d9 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -514,6 +514,7 @@ struct lpfc_pc_sli4_params { uint8_t cqav; uint8_t wqsize; uint8_t bv1s; + uint8_t pls; #define LPFC_WQ_SZ64_SUPPORT 1 #define LPFC_WQ_SZ128_SUPPORT 2 uint8_t wqpcnt; -- cgit v1.2.3 From b4b3417cf6c8051f9f210cd694e6342fb008795c Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:31 -0700 Subject: scsi: lpfc: Add additional discovery log messages When debugging a recent discovery customer problem it was very hard to tell what was happening with the existing discovery log messages. To fully debug the issue additional log messages were necessary. Add or extend log messages so that sufficient information is present for debugging. Link: https://lore.kernel.org/r/20191018211832.7917-16-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_ct.c | 22 +++++++++++++++++++--- drivers/scsi/lpfc/lpfc_els.c | 10 ++++++++-- drivers/scsi/lpfc/lpfc_hbadisc.c | 39 +++++++++++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_ct.c b/drivers/scsi/lpfc/lpfc_ct.c index f883fac2d2b1..99c9bb249758 100644 --- a/drivers/scsi/lpfc/lpfc_ct.c +++ b/drivers/scsi/lpfc/lpfc_ct.c @@ -763,9 +763,11 @@ lpfc_cmpl_ct_cmd_gid_ft(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, "0208 NameServer Rsp Data: x%x x%x " - "sz x%x\n", + "x%x x%x sz x%x\n", vport->fc_flag, CTreq->un.gid.Fc4Type, + vport->num_disc_nodes, + vport->gidft_inp, irsp->un.genreq64.bdl.bdeSize); lpfc_ns_rsp(vport, @@ -961,9 +963,13 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (CTrsp->CommandResponse.bits.CmdRsp == cpu_to_be16(SLI_CT_RESPONSE_FS_ACC)) { lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "4105 NameServer Rsp Data: x%x x%x\n", + "4105 NameServer Rsp Data: x%x x%x " + "x%x x%x sz x%x\n", vport->fc_flag, - CTreq->un.gid.Fc4Type); + CTreq->un.gid.Fc4Type, + vport->num_disc_nodes, + vport->gidft_inp, + irsp->un.genreq64.bdl.bdeSize); lpfc_ns_rsp(vport, outp, @@ -1025,6 +1031,11 @@ lpfc_cmpl_ct_cmd_gid_pt(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } vport->gidft_inp--; } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6450 GID_PT cmpl inp %d disc %d\n", + vport->gidft_inp, vport->num_disc_nodes); + /* Link up / RSCN discovery */ if ((vport->num_disc_nodes == 0) && (vport->gidft_inp == 0)) { @@ -1159,6 +1170,11 @@ out: /* Link up / RSCN discovery */ if (vport->num_disc_nodes) vport->num_disc_nodes--; + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6451 GFF_ID cmpl inp %d disc %d\n", + vport->gidft_inp, vport->num_disc_nodes); + if (vport->num_disc_nodes == 0) { /* * The driver has cycled through all Nports in the RSCN payload. diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2235a45999a8..9a1b7f331718 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -5265,6 +5265,11 @@ lpfc_els_disc_plogi(struct lpfc_vport *vport) } } } + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6452 Discover PLOGI %d flag x%x\n", + sentplogi, vport->fc_flag); + if (sentplogi) { lpfc_set_disctmo(vport); } @@ -6668,9 +6673,10 @@ lpfc_els_handle_rscn(struct lpfc_vport *vport) /* RSCN processed */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0215 RSCN processed Data: x%x x%x x%x x%x\n", + "0215 RSCN processed Data: x%x x%x x%x x%x x%x x%x\n", vport->fc_flag, 0, vport->fc_rscn_id_cnt, - vport->port_state); + vport->port_state, vport->num_disc_nodes, + vport->gidft_inp); /* To process RSCN, first compare RSCN data with NameServer */ vport->fc_ns_retry = 0; diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 808ad666bb1b..40075b391546 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -5404,6 +5404,13 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) if (!ndlp) return NULL; lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6453 Setup New Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -5417,6 +5424,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) "0014 Could not enable ndlp\n"); return NULL; } + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6454 Setup Enabled Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); @@ -5436,6 +5449,12 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) */ lpfc_cancel_retry_delay_tmo(vport, ndlp); + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6455 Setup RSCN Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + /* NVME Target mode waits until rport is known to be * impacted by the RSCN before it transitions. No * active management - just go to NPR provided the @@ -5458,9 +5477,21 @@ lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; spin_unlock_irq(shost->host_lock); - } else + } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6456 Skip Setup RSCN Node x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); ndlp = NULL; + } } else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, + "6457 Setup Active Node 2B_DISC x%x " + "Data:x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, + ndlp->nlp_state, vport->fc_flag); + /* If the initiator received a PLOGI from this NPort or if the * initiator is already in the process of discovery on it, * there's no need to try to discover it again. @@ -5612,10 +5643,10 @@ lpfc_disc_start(struct lpfc_vport *vport) /* Start Discovery state */ lpfc_printf_vlog(vport, KERN_INFO, LOG_DISCOVERY, - "0202 Start Discovery hba state x%x " - "Data: x%x x%x x%x\n", + "0202 Start Discovery port state x%x " + "flg x%x Data: x%x x%x x%x\n", vport->port_state, vport->fc_flag, vport->fc_plogi_cnt, - vport->fc_adisc_cnt); + vport->fc_adisc_cnt, vport->fc_npr_cnt); /* First do ADISCs - if any */ num_sent = lpfc_els_disc_adisc(vport); -- cgit v1.2.3 From 74acec655f560ef721c1e191732af2bcb094b537 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 18 Oct 2019 14:18:32 -0700 Subject: scsi: lpfc: Update lpfc version to 12.6.0.0 Update lpfc version to 12.6.0.0 Link: https://lore.kernel.org/r/20191018211832.7917-17-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index d8839d95f7fe..ed1b10b0161e 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 "12.4.0.1" +#define LPFC_DRIVER_VERSION "12.6.0.0" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From 2c7fb469024f0da98f4d078fcf570786ec87c384 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Thu, 24 Oct 2019 08:27:29 +0530 Subject: scsi: lpfc: lpfc_attr: Fix Use plain integer as NULL pointer Replace assignment of 0 to pointer with NULL assignment. Link: https://lore.kernel.org/r/20191024025726.GA31421@saurav Signed-off-by: Saurav Girepunje Acked-by: Dick Kennedy Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e738c1529d2d..2d090ea2b736 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -1644,7 +1644,7 @@ lpfc_set_trunking(struct lpfc_hba *phba, char *buff_out) { LPFC_MBOXQ_t *mbox = NULL; unsigned long val = 0; - char *pval = 0; + char *pval = NULL; int rc = 0; if (!strncmp("enable", buff_out, -- cgit v1.2.3 From 5314995e370e46ac12d12378544ad4575b6f6672 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Thu, 24 Oct 2019 08:39:01 +0530 Subject: scsi: lpfc: lpfc_nvmet: Fix Use plain integer as NULL pointer Replace assignment of 0 to pointer with NULL assignment. Link: https://lore.kernel.org/r/20191024030857.GA12097@saurav Signed-off-by: Saurav Girepunje Acked-by: Dick Kennedy Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvmet.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvmet.c b/drivers/scsi/lpfc/lpfc_nvmet.c index e3ac9059d33d..9dc9afe1c255 100644 --- a/drivers/scsi/lpfc/lpfc_nvmet.c +++ b/drivers/scsi/lpfc/lpfc_nvmet.c @@ -3317,7 +3317,7 @@ lpfc_nvmet_sol_fcp_issue_abort(struct lpfc_hba *phba, /* ABTS WQE must go to the same WQ as the WQE to be aborted */ abts_wqeq->hba_wqidx = ctxp->wqeq->hba_wqidx; abts_wqeq->wqe_cmpl = lpfc_nvmet_sol_fcp_abort_cmp; - abts_wqeq->iocb_cmpl = 0; + abts_wqeq->iocb_cmpl = NULL; abts_wqeq->iocb_flag |= LPFC_IO_NVME; abts_wqeq->context2 = ctxp; abts_wqeq->vport = phba->pport; @@ -3452,7 +3452,7 @@ lpfc_nvmet_unsol_ls_issue_abort(struct lpfc_hba *phba, spin_lock_irqsave(&phba->hbalock, flags); abts_wqeq->wqe_cmpl = lpfc_nvmet_xmt_ls_abort_cmp; - abts_wqeq->iocb_cmpl = 0; + abts_wqeq->iocb_cmpl = NULL; abts_wqeq->iocb_flag |= LPFC_IO_NVME_LS; rc = lpfc_sli4_issue_wqe(phba, ctxp->hdwq, abts_wqeq); spin_unlock_irqrestore(&phba->hbalock, flags); -- cgit v1.2.3 From d6c9b31ac3064fbedf8961f120a4c117daa59932 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Sat, 19 Oct 2019 11:59:13 +0300 Subject: scsi: csiostor: Don't enable IRQs too early These are called with IRQs disabled from csio_mgmt_tmo_handler() so we can't call spin_unlock_irq() or it will enable IRQs prematurely. Fixes: a3667aaed569 ("[SCSI] csiostor: Chelsio FCoE offload driver") Link: https://lore.kernel.org/r/20191019085913.GA14245@mwanda Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_lnode.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index 66e58f0a75dc..23cbe4cda760 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -301,6 +301,7 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) struct fc_fdmi_port_name *port_name; uint8_t buf[64]; uint8_t *fc4_type; + unsigned long flags; if (fdmi_req->wr_status != FW_SUCCESS) { csio_ln_dbg(ln, "WR error:%x in processing fdmi rhba cmd\n", @@ -385,13 +386,13 @@ csio_ln_fdmi_rhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) len = (uint32_t)(pld - (uint8_t *)cmd); /* Submit FDMI RPA request */ - spin_lock_irq(&hw->lock); + spin_lock_irqsave(&hw->lock, flags); if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_done, FCOE_CT, &fdmi_req->dma_buf, len)) { CSIO_INC_STATS(ln, n_fdmi_err); csio_ln_dbg(ln, "Failed to issue fdmi rpa req\n"); } - spin_unlock_irq(&hw->lock); + spin_unlock_irqrestore(&hw->lock, flags); } /* @@ -412,6 +413,7 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) struct fc_fdmi_rpl *reg_pl; struct fs_fdmi_attrs *attrib_blk; uint8_t buf[64]; + unsigned long flags; if (fdmi_req->wr_status != FW_SUCCESS) { csio_ln_dbg(ln, "WR error:%x in processing fdmi dprt cmd\n", @@ -491,13 +493,13 @@ csio_ln_fdmi_dprt_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) attrib_blk->numattrs = htonl(numattrs); /* Submit FDMI RHBA request */ - spin_lock_irq(&hw->lock); + spin_lock_irqsave(&hw->lock, flags); if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_rhba_cbfn, FCOE_CT, &fdmi_req->dma_buf, len)) { CSIO_INC_STATS(ln, n_fdmi_err); csio_ln_dbg(ln, "Failed to issue fdmi rhba req\n"); } - spin_unlock_irq(&hw->lock); + spin_unlock_irqrestore(&hw->lock, flags); } /* @@ -512,6 +514,7 @@ csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) void *cmd; struct fc_fdmi_port_name *port_name; uint32_t len; + unsigned long flags; if (fdmi_req->wr_status != FW_SUCCESS) { csio_ln_dbg(ln, "WR error:%x in processing fdmi dhba cmd\n", @@ -542,13 +545,13 @@ csio_ln_fdmi_dhba_cbfn(struct csio_hw *hw, struct csio_ioreq *fdmi_req) len += sizeof(*port_name); /* Submit FDMI request */ - spin_lock_irq(&hw->lock); + spin_lock_irqsave(&hw->lock, flags); if (csio_ln_mgmt_submit_req(fdmi_req, csio_ln_fdmi_dprt_cbfn, FCOE_CT, &fdmi_req->dma_buf, len)) { CSIO_INC_STATS(ln, n_fdmi_err); csio_ln_dbg(ln, "Failed to issue fdmi dprt req\n"); } - spin_unlock_irq(&hw->lock); + spin_unlock_irqrestore(&hw->lock, flags); } /** -- cgit v1.2.3 From e07734fdee7800b5ca7f24fa4e3f0b0ea13845ba Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 21 Oct 2019 22:20:42 +0800 Subject: scsi: cxgb4i: remove set but not used variable 'ppmax' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/cxgbi/cxgb4i/cxgb4i.c:2076:15: warning: variable ppmax set but not used [-Wunused-but-set-variable] drivers/target/iscsi/cxgbit/cxgbit_ddp.c:300:15: warning: variable ppmax set but not used [-Wunused-but-set-variable] It is not used since commit a248384e6420 ("cxgb4/libcxgb/cxgb4i/cxgbit: enable eDRAM page pods for iSCSI") Link: https://lore.kernel.org/r/20191021142042.30964-1-yuehaibing@huawei.com Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/cxgbi/cxgb4i/cxgb4i.c | 2 -- drivers/target/iscsi/cxgbit/cxgbit_ddp.c | 3 --- 2 files changed, 5 deletions(-) diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c index da50e87921bc..bc1086ae6835 100644 --- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c +++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c @@ -2073,7 +2073,6 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev); struct net_device *ndev = cdev->ports[0]; struct cxgbi_tag_format tformat; - unsigned int ppmax; int i, err; if (!lldi->vr->iscsi.size) { @@ -2082,7 +2081,6 @@ static int cxgb4i_ddp_init(struct cxgbi_device *cdev) } cdev->flags |= CXGBI_FLAG_USE_PPOD_OFLDQ; - ppmax = lldi->vr->iscsi.size >> PPOD_SIZE_SHIFT; memset(&tformat, 0, sizeof(struct cxgbi_tag_format)); for (i = 0; i < 4; i++) diff --git a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c index 54bb1ebd8eb5..af35251232eb 100644 --- a/drivers/target/iscsi/cxgbit/cxgbit_ddp.c +++ b/drivers/target/iscsi/cxgbit/cxgbit_ddp.c @@ -297,7 +297,6 @@ int cxgbit_ddp_init(struct cxgbit_device *cdev) struct cxgb4_lld_info *lldi = &cdev->lldi; struct net_device *ndev = cdev->lldi.ports[0]; struct cxgbi_tag_format tformat; - unsigned int ppmax; int ret, i; if (!lldi->vr->iscsi.size) { @@ -305,8 +304,6 @@ int cxgbit_ddp_init(struct cxgbit_device *cdev) return -EACCES; } - ppmax = lldi->vr->iscsi.size >> PPOD_SIZE_SHIFT; - memset(&tformat, 0, sizeof(struct cxgbi_tag_format)); for (i = 0; i < 4; i++) tformat.pgsz_order[i] = (lldi->iscsi_pgsz_order >> (i << 3)) -- cgit v1.2.3 From 906ca6353ac09696c1bf0892513c8edffff5e0a6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Tue, 22 Oct 2019 13:23:24 +0300 Subject: scsi: esas2r: unlock on error in esas2r_nvram_read_direct() This error path is missing an unlock. Fixes: 26780d9e12ed ("[SCSI] esas2r: ATTO Technology ExpressSAS 6G SAS/SATA RAID Adapter Driver") Link: https://lore.kernel.org/r/20191022102324.GA27540@mwanda Signed-off-by: Dan Carpenter Signed-off-by: Martin K. Petersen --- drivers/scsi/esas2r/esas2r_flash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/esas2r/esas2r_flash.c b/drivers/scsi/esas2r/esas2r_flash.c index 7bd376d95ed5..b02ac389e6c6 100644 --- a/drivers/scsi/esas2r/esas2r_flash.c +++ b/drivers/scsi/esas2r/esas2r_flash.c @@ -1197,6 +1197,7 @@ bool esas2r_nvram_read_direct(struct esas2r_adapter *a) if (!esas2r_read_flash_block(a, a->nvram, FLS_OFFSET_NVR, sizeof(struct esas2r_sas_nvram))) { esas2r_hdebug("NVRAM read failed, using defaults"); + up(&a->nvram_semaphore); return false; } -- cgit v1.2.3 From 5bb2f743cdaa6da618e77a6aab5c38b46072365b Mon Sep 17 00:00:00 2001 From: Tomas Henzl Date: Thu, 24 Oct 2019 17:28:35 +0200 Subject: scsi: mpt3sas: change allocation option From an interrupt handler path memory may be allocated using GFP_KERNEL, replace it with GFP_ATOMIC. _base_interrupt->_scsih_io_done->_scsih_smart_predicted_fault Link: https://lore.kernel.org/r/20191024152835.6177-1-thenzl@redhat.com Signed-off-by: Tomas Henzl Signed-off-by: Martin K. Petersen --- drivers/scsi/mpt3sas/mpt3sas_scsih.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c index 3f0797e6f941..a038be8a0e90 100644 --- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c +++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c @@ -5161,7 +5161,7 @@ _scsih_smart_predicted_fault(struct MPT3SAS_ADAPTER *ioc, u16 handle) /* insert into event log */ sz = offsetof(Mpi2EventNotificationReply_t, EventData) + sizeof(Mpi2EventDataSasDeviceStatusChange_t); - event_reply = kzalloc(sz, GFP_KERNEL); + event_reply = kzalloc(sz, GFP_ATOMIC); if (!event_reply) { ioc_err(ioc, "failure at %s:%d/%s()!\n", __FILE__, __LINE__, __func__); -- cgit v1.2.3 From d44c897c391ed55b7cede2f58d40b0a6e0c5763b Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:25:43 +0200 Subject: scsi: isci: Spelling s/configruation/configuration/ Fix misspelling of "configuration". Link: https://lore.kernel.org/r/20191024152543.30310-1-geert+renesas@glider.be Signed-off-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/isci/port_config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/isci/port_config.c b/drivers/scsi/isci/port_config.c index 9e8de1462593..b1c197505579 100644 --- a/drivers/scsi/isci/port_config.c +++ b/drivers/scsi/isci/port_config.c @@ -147,7 +147,7 @@ static struct isci_port *sci_port_configuration_agent_find_port( /** * * @controller: This is the controller object that contains the port agent - * @port_agent: This is the port configruation agent for the controller. + * @port_agent: This is the port configuration agent for the controller. * * This routine will validate the port configuration is correct for the SCU * hardware. The SCU hardware allows for port configurations as follows. LP0 -- cgit v1.2.3 From 1125c70a92383be7fc9f4b4413a6b269288e1b24 Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Thu, 24 Oct 2019 17:26:33 +0200 Subject: scsi: Fix various misspellings of "connect" Fix misspellings of "disonnect", "reconnect", "connection", "connected", and "disconnection". Link: https://lore.kernel.org/r/20191024152633.30404-1-geert+renesas@glider.be Signed-off-by: Geert Uytterhoeven Signed-off-by: Martin K. Petersen --- drivers/scsi/arm/acornscsi.c | 4 ++-- drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h | 2 +- drivers/scsi/isci/remote_device.c | 2 +- drivers/scsi/ncr53c8xx.c | 2 +- drivers/scsi/nsp32.c | 2 +- drivers/scsi/qedf/qedf_dbg.h | 2 +- drivers/scsi/qedi/qedi_dbg.h | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c index d12dd89538df..ddb52e7ba622 100644 --- a/drivers/scsi/arm/acornscsi.c +++ b/drivers/scsi/arm/acornscsi.c @@ -1067,7 +1067,7 @@ void acornscsi_dma_setup(AS_Host *host, dmadir_t direction) * Purpose : ensure that all DMA transfers are up-to-date & host->scsi.SCp is correct * Params : host - host to finish * Notes : This is called when a command is: - * terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONECT + * terminating, RESTORE_POINTERS, SAVE_POINTERS, DISCONNECT * : This must not return until all transfers are completed. */ static @@ -1816,7 +1816,7 @@ int acornscsi_reconnect(AS_Host *host) } /* - * Function: int acornscsi_reconect_finish(AS_Host *host) + * Function: int acornscsi_reconnect_finish(AS_Host *host) * Purpose : finish reconnecting a command * Params : host - host to complete * Returns : 0 if failed diff --git a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h index e4469df9c469..698f5ebaa0c2 100644 --- a/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h +++ b/drivers/scsi/bnx2fc/57xx_hsi_bnx2fc.h @@ -813,7 +813,7 @@ struct fcoe_confqe { /* - * FCoE conection data base + * FCoE connection data base */ struct fcoe_conn_db { #if defined(__BIG_ENDIAN) diff --git a/drivers/scsi/isci/remote_device.c b/drivers/scsi/isci/remote_device.c index 49aa4e657c44..cd1e4b4d95bb 100644 --- a/drivers/scsi/isci/remote_device.c +++ b/drivers/scsi/isci/remote_device.c @@ -1504,7 +1504,7 @@ static enum sci_status isci_remote_device_construct(struct isci_port *iport, * This function builds the isci_remote_device when a libsas dev_found message * is received. * @isci_host: This parameter specifies the isci host object. - * @port: This parameter specifies the isci_port conected to this device. + * @port: This parameter specifies the isci_port connected to this device. * * pointer to new isci_remote_device. */ diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c index e0b427fdf818..11a2cb844ecb 100644 --- a/drivers/scsi/ncr53c8xx.c +++ b/drivers/scsi/ncr53c8xx.c @@ -1722,7 +1722,7 @@ struct ncb { ** Miscellaneous configuration and status parameters. **---------------------------------------------------------------- */ - u_char disc; /* Diconnection allowed */ + u_char disc; /* Disconnection allowed */ u_char scsi_mode; /* Current SCSI BUS mode */ u_char order; /* Tag order to use */ u_char verbose; /* Verbosity for this controller*/ diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c index 70db79254155..b6e04d14292d 100644 --- a/drivers/scsi/nsp32.c +++ b/drivers/scsi/nsp32.c @@ -1542,7 +1542,7 @@ static void nsp32_scsi_done(struct scsi_cmnd *SCpnt) * with ACK reply when below condition is matched: * MsgIn 00: Command Complete. * MsgIn 02: Save Data Pointer. - * MsgIn 04: Diconnect. + * MsgIn 04: Disconnect. * In other case, unexpected BUSFREE is detected. */ static int nsp32_busfree_occur(struct scsi_cmnd *SCpnt, unsigned short execph) diff --git a/drivers/scsi/qedf/qedf_dbg.h b/drivers/scsi/qedf/qedf_dbg.h index d979f095aeda..2386bfb73c46 100644 --- a/drivers/scsi/qedf/qedf_dbg.h +++ b/drivers/scsi/qedf/qedf_dbg.h @@ -42,7 +42,7 @@ extern uint qedf_debug; #define QEDF_LOG_LPORT 0x4000 /* lport logs */ #define QEDF_LOG_ELS 0x8000 /* ELS logs */ #define QEDF_LOG_NPIV 0x10000 /* NPIV logs */ -#define QEDF_LOG_SESS 0x20000 /* Conection setup, cleanup */ +#define QEDF_LOG_SESS 0x20000 /* Connection setup, cleanup */ #define QEDF_LOG_TID 0x80000 /* * FW TID context acquire * free diff --git a/drivers/scsi/qedi/qedi_dbg.h b/drivers/scsi/qedi/qedi_dbg.h index 243acc8b520a..37d084086fd4 100644 --- a/drivers/scsi/qedi/qedi_dbg.h +++ b/drivers/scsi/qedi/qedi_dbg.h @@ -44,7 +44,7 @@ extern uint qedi_dbg_log; #define QEDI_LOG_LPORT 0x4000 /* lport logs */ #define QEDI_LOG_ELS 0x8000 /* ELS logs */ #define QEDI_LOG_NPIV 0x10000 /* NPIV logs */ -#define QEDI_LOG_SESS 0x20000 /* Conection setup, cleanup */ +#define QEDI_LOG_SESS 0x20000 /* Connection setup, cleanup */ #define QEDI_LOG_UIO 0x40000 /* iSCSI UIO logs */ #define QEDI_LOG_TID 0x80000 /* FW TID context acquire, * free -- cgit v1.2.3 From 35160421b63d4753a72e9f72ebcdd9d6f88f84b9 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 24 Oct 2019 22:08:08 +0800 Subject: scsi: hisi_sas: Don't create debugfs dump folder twice Due to a merge error, we attempt to create 2x debugfs dump folders, which fails: [ 861.101914] debugfs: Directory 'dump' with parent '0000:74:02.0' already present! This breaks the dump function. To fix, remove the superfluous attempt to create the folder. Fixes: 7ec7082c57ec ("scsi: hisi_sas: Add hisi_sas_debugfs_alloc() to centralise allocation") Link: https://lore.kernel.org/r/1571926105-74636-2-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 1a25f0f15fd0..ceba1016b77f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -3712,9 +3712,6 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) int p, c, d; size_t sz; - hisi_hba->debugfs_dump_dentry = - debugfs_create_dir("dump", hisi_hba->debugfs_dir); - sz = hw->debugfs_reg_array[DEBUGFS_GLOBAL]->count * 4; hisi_hba->debugfs_regs[DEBUGFS_GLOBAL] = devm_kmalloc(dev, sz, GFP_KERNEL); -- cgit v1.2.3 From 65a3b8bd56942dc988b8c05615bd3f510a10012b Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 24 Oct 2019 22:08:09 +0800 Subject: scsi: hisi_sas: Set the BIST init value before enabling BIST If set the BIST init value after enabling BIST, there may be still some few error bits. According to the process, need to set the BIST init value before enabling BIST. Fixes: 97b151e75861 ("scsi: hisi_sas: Add BIST support for phy loopback") Link: https://lore.kernel.org/r/1571926105-74636-3-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index cb8d087762db..cc594937fa8d 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3022,11 +3022,6 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) hisi_sas_phy_write32(hisi_hba, phy_id, SAS_PHY_BIST_CTRL, reg_val); - mdelay(100); - reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK); - hisi_sas_phy_write32(hisi_hba, phy_id, - SAS_PHY_BIST_CTRL, reg_val); - /* set the bist init value */ hisi_sas_phy_write32(hisi_hba, phy_id, SAS_PHY_BIST_CODE, @@ -3035,6 +3030,11 @@ static int debugfs_set_bist_v3_hw(struct hisi_hba *hisi_hba, bool enable) SAS_PHY_BIST_CODE1, SAS_PHY_BIST_CODE1_INIT); + mdelay(100); + reg_val |= (CFG_RX_BIST_EN_MSK | CFG_TX_BIST_EN_MSK); + hisi_sas_phy_write32(hisi_hba, phy_id, + SAS_PHY_BIST_CTRL, reg_val); + /* clear error bit */ mdelay(100); hisi_sas_phy_read32(hisi_hba, phy_id, SAS_BIST_ERR_CNT); -- cgit v1.2.3 From 8fa9a7bd3099a96194d767ce681c68dbcb8a957e Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 24 Oct 2019 22:08:10 +0800 Subject: scsi: hisi_sas: use wait_for_completion_timeout() when clearing ITCT When injecting 2bit ecc errors, it will cause confusion inside SAS controller which needs host reset to recover it. If a device is gone at the same times inject 2bit ecc errors, we may not receive the ITCT interrupt so it will wait for completion in clear_itct_v3_hw() all the time. And host reset will also not occur because it can't require hisi_hba->sem, so the system will be suspended. To solve the issue, use wait_for_completion_timeout() instead of wait_for_completion(), and also don't mark the gone device as SAS_PHY_UNUSED when device gone. Link: https://lore.kernel.org/r/1571926105-74636-4-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 5 +++-- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 ++++++-- drivers/scsi/hisi_sas/hisi_sas_v1_hw.c | 6 ++++-- drivers/scsi/hisi_sas/hisi_sas_v2_hw.c | 13 ++++++++++--- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 13 ++++++++++--- 5 files changed, 33 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 720c4d6be939..83232e8472fb 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -84,6 +84,7 @@ #define HISI_SAS_PROT_MASK (HISI_SAS_DIF_PROT_MASK | HISI_SAS_DIX_PROT_MASK) #define HISI_SAS_WAIT_PHYUP_TIMEOUT 20 +#define CLEAR_ITCT_TIMEOUT 20 struct hisi_hba; @@ -296,8 +297,8 @@ struct hisi_sas_hw { void (*phy_set_linkrate)(struct hisi_hba *hisi_hba, int phy_no, struct sas_phy_linkrates *linkrates); enum sas_linkrate (*phy_get_max_linkrate)(void); - void (*clear_itct)(struct hisi_hba *hisi_hba, - struct hisi_sas_device *dev); + int (*clear_itct)(struct hisi_hba *hisi_hba, + struct hisi_sas_device *dev); void (*free_device)(struct hisi_sas_device *sas_dev); int (*get_wideport_bitmap)(struct hisi_hba *hisi_hba, int port_id); void (*dereg_device)(struct hisi_hba *hisi_hba, diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index ceba1016b77f..621eebbeacd6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1045,6 +1045,7 @@ static void hisi_sas_dev_gone(struct domain_device *device) struct hisi_sas_device *sas_dev = device->lldd_dev; struct hisi_hba *hisi_hba = dev_to_hisi_hba(device); struct device *dev = hisi_hba->dev; + int ret = 0; dev_info(dev, "dev[%d:%x] is gone\n", sas_dev->device_id, sas_dev->dev_type); @@ -1056,13 +1057,16 @@ static void hisi_sas_dev_gone(struct domain_device *device) hisi_sas_dereg_device(hisi_hba, device); - hisi_hba->hw->clear_itct(hisi_hba, sas_dev); + ret = hisi_hba->hw->clear_itct(hisi_hba, sas_dev); device->lldd_dev = NULL; } if (hisi_hba->hw->free_device) hisi_hba->hw->free_device(sas_dev); - sas_dev->dev_type = SAS_PHY_UNUSED; + + /* Don't mark it as SAS_PHY_UNUSED if failed to clear ITCT */ + if (!ret) + sas_dev->dev_type = SAS_PHY_UNUSED; sas_dev->sas_device = NULL; up(&hisi_hba->sem); } diff --git a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c index b861a0f14c9d..3af53cc42bd6 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v1_hw.c @@ -531,8 +531,8 @@ static void setup_itct_v1_hw(struct hisi_hba *hisi_hba, (0xff00ULL << ITCT_HDR_REJ_OPEN_TL_OFF)); } -static void clear_itct_v1_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_device *sas_dev) +static int clear_itct_v1_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_device *sas_dev) { u64 dev_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id]; @@ -551,6 +551,8 @@ static void clear_itct_v1_hw(struct hisi_hba *hisi_hba, qw0 = le64_to_cpu(itct->qw0); qw0 &= ~ITCT_HDR_VALID_MSK; itct->qw0 = cpu_to_le64(qw0); + + return 0; } static int reset_hw_v1_hw(struct hisi_hba *hisi_hba) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c index 8e96a257e439..61b1e2693b08 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v2_hw.c @@ -974,13 +974,14 @@ static void setup_itct_v2_hw(struct hisi_hba *hisi_hba, (0x1ULL << ITCT_HDR_RTOLT_OFF)); } -static void clear_itct_v2_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_device *sas_dev) +static int clear_itct_v2_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_device *sas_dev) { DECLARE_COMPLETION_ONSTACK(completion); u64 dev_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id]; u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); + struct device *dev = hisi_hba->dev; int i; sas_dev->completion = &completion; @@ -990,13 +991,19 @@ static void clear_itct_v2_hw(struct hisi_hba *hisi_hba, hisi_sas_write32(hisi_hba, ENT_INT_SRC3, ENT_INT_SRC3_ITC_INT_MSK); + /* need to set register twice to clear ITCT for v2 hw */ for (i = 0; i < 2; i++) { reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK); hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val); - wait_for_completion(sas_dev->completion); + if (!wait_for_completion_timeout(sas_dev->completion, + CLEAR_ITCT_TIMEOUT * HZ)) { + dev_warn(dev, "failed to clear ITCT\n"); + return -ETIMEDOUT; + } memset(itct, 0, sizeof(struct hisi_sas_itct)); } + return 0; } static void free_device_v2_hw(struct hisi_sas_device *sas_dev) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index cc594937fa8d..19a8cfeb8f6e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -795,13 +795,14 @@ static void setup_itct_v3_hw(struct hisi_hba *hisi_hba, (0x1ULL << ITCT_HDR_RTOLT_OFF)); } -static void clear_itct_v3_hw(struct hisi_hba *hisi_hba, - struct hisi_sas_device *sas_dev) +static int clear_itct_v3_hw(struct hisi_hba *hisi_hba, + struct hisi_sas_device *sas_dev) { DECLARE_COMPLETION_ONSTACK(completion); u64 dev_id = sas_dev->device_id; struct hisi_sas_itct *itct = &hisi_hba->itct[dev_id]; u32 reg_val = hisi_sas_read32(hisi_hba, ENT_INT_SRC3); + struct device *dev = hisi_hba->dev; sas_dev->completion = &completion; @@ -814,8 +815,14 @@ static void clear_itct_v3_hw(struct hisi_hba *hisi_hba, reg_val = ITCT_CLR_EN_MSK | (dev_id & ITCT_DEV_MSK); hisi_sas_write32(hisi_hba, ITCT_CLR, reg_val); - wait_for_completion(sas_dev->completion); + if (!wait_for_completion_timeout(sas_dev->completion, + CLEAR_ITCT_TIMEOUT * HZ)) { + dev_warn(dev, "failed to clear ITCT\n"); + return -ETIMEDOUT; + } + memset(itct, 0, sizeof(struct hisi_sas_itct)); + return 0; } static void dereg_device_v3_hw(struct hisi_hba *hisi_hba, -- cgit v1.2.3 From 550c0d89d52d3bec5c299f69b4ed5d2ee6b8a9a6 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Thu, 24 Oct 2019 22:08:11 +0800 Subject: scsi: hisi_sas: Replace in_softirq() check in hisi_sas_task_exec() For IOs from upper layer, preemption may be disabled as it may be called by function __blk_mq_delay_run_hw_queue which will call get_cpu() (it disables preemption). So if flags HISI_SAS_REJECT_CMD_BIT is set in function hisi_sas_task_exec(), it may disable preempt twice after down() and up() which will cause following call trace: BUG: scheduling while atomic: fio/60373/0x00000002 Call trace: dump_backtrace+0x0/0x150 show_stack+0x24/0x30 dump_stack+0xa0/0xc4 __schedule_bug+0x68/0x88 __schedule+0x4b8/0x548 schedule+0x40/0xd0 schedule_timeout+0x200/0x378 __down+0x78/0xc8 down+0x54/0x70 hisi_sas_task_exec.isra.10+0x598/0x8d8 [hisi_sas_main] hisi_sas_queue_command+0x28/0x38 [hisi_sas_main] sas_queuecommand+0x168/0x1b0 [libsas] scsi_queue_rq+0x2ac/0x980 blk_mq_dispatch_rq_list+0xb0/0x550 blk_mq_do_dispatch_sched+0x6c/0x110 blk_mq_sched_dispatch_requests+0x114/0x1d8 __blk_mq_run_hw_queue+0xb8/0x130 __blk_mq_delay_run_hw_queue+0x1c0/0x220 blk_mq_run_hw_queue+0xb0/0x128 blk_mq_sched_insert_requests+0xdc/0x208 blk_mq_flush_plug_list+0x1b4/0x3a0 blk_flush_plug_list+0xdc/0x110 blk_finish_plug+0x3c/0x50 blkdev_direct_IO+0x404/0x550 generic_file_read_iter+0x9c/0x848 blkdev_read_iter+0x50/0x78 aio_read+0xc8/0x170 io_submit_one+0x1fc/0x8d8 __arm64_sys_io_submit+0xdc/0x280 el0_svc_common.constprop.0+0xe0/0x1e0 el0_svc_handler+0x34/0x90 el0_svc+0x10/0x14 ... To solve the issue, check preemptible() to avoid disabling preempt multiple when flag HISI_SAS_REJECT_CMD_BIT is set. Link: https://lore.kernel.org/r/1571926105-74636-5-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 621eebbeacd6..a7bac5dc389a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -587,7 +587,13 @@ static int hisi_sas_task_exec(struct sas_task *task, gfp_t gfp_flags, dev = hisi_hba->dev; if (unlikely(test_bit(HISI_SAS_REJECT_CMD_BIT, &hisi_hba->flags))) { - if (in_softirq()) + /* + * For IOs from upper layer, it may already disable preempt + * in the IO path, if disable preempt again in down(), + * function schedule() will report schedule_bug(), so check + * preemptible() before goto down(). + */ + if (!preemptible()) return -EINVAL; down(&hisi_hba->sem); -- cgit v1.2.3 From d28ed83b769378deefa82456f962e14a4b0afadf Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:12 +0800 Subject: scsi: hisi_sas: Add timestamp for a debugfs dump It's useful to know when the dump occurred, so add a timestamp file for this. Link: https://lore.kernel.org/r/1571926105-74636-6-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 2 ++ drivers/scsi/hisi_sas/hisi_sas_main.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 83232e8472fb..7069dae4cec9 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -410,6 +411,7 @@ struct hisi_hba { struct hisi_sas_iost *debugfs_iost; struct hisi_sas_itct *debugfs_itct; u64 *debugfs_iost_cache; + u64 debugfs_timestamp; u64 *debugfs_itct_cache; struct dentry *debugfs_dir; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a7bac5dc389a..a0d04e4e13e2 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -3194,6 +3194,7 @@ static const struct file_operations hisi_sas_debugfs_itct_cache_fops = { static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { + u64 *debugfs_timestamp; struct dentry *dump_dentry; struct dentry *dentry; char name[256]; @@ -3201,10 +3202,14 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) int c; int d; + debugfs_timestamp = &hisi_hba->debugfs_timestamp; /* Create dump dir inside device dir */ dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); hisi_hba->debugfs_dump_dentry = dump_dentry; + debugfs_create_u64("timestamp", 0400, dump_dentry, + debugfs_timestamp); + debugfs_create_file("global", 0400, dump_dentry, hisi_hba, &hisi_sas_debugfs_global_fops); @@ -3684,7 +3689,10 @@ void hisi_sas_debugfs_work_handler(struct work_struct *work) { struct hisi_hba *hisi_hba = container_of(work, struct hisi_hba, debugfs_work); + u64 timestamp = local_clock(); + do_div(timestamp, NSEC_PER_MSEC); + hisi_hba->debugfs_timestamp = timestamp; if (hisi_hba->debugfs_snapshot) return; hisi_hba->debugfs_snapshot = true; -- cgit v1.2.3 From 35ea630b2bad4fe9f7db34624eaab3663bb2cb42 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:13 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for CQ Create a file structure which was used to save the memory address and CQ pointer for CQ at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it need. Link: https://lore.kernel.org/r/1571926105-74636-7-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 7 ++++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 29 ++++++++++++++++------------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 7069dae4cec9..5b0f08286af7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -323,6 +323,11 @@ struct hisi_sas_hw { const struct hisi_sas_debugfs_reg *debugfs_reg_port; }; +struct hisi_sas_debugfs_cq { + struct hisi_sas_cq *cq; + void *complete_hdr; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -406,7 +411,7 @@ struct hisi_hba { /* Put Global AXI and RAS Register into register array */ u32 *debugfs_regs[DEBUGFS_REGS_NUM]; u32 *debugfs_port_reg[HISI_SAS_MAX_PHYS]; - void *debugfs_complete_hdr[HISI_SAS_MAX_QUEUES]; + struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_cmd_hdr *debugfs_cmd_hdr[HISI_SAS_MAX_QUEUES]; struct hisi_sas_iost *debugfs_iost; struct hisi_sas_itct *debugfs_itct; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a0d04e4e13e2..5c1005f77131 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2700,7 +2700,7 @@ static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) int i; for (i = 0; i < hisi_hba->queue_count; i++) - memcpy(hisi_hba->debugfs_complete_hdr[i], + memcpy(hisi_hba->debugfs_cq[i].complete_hdr, hisi_hba->complete_hdr[i], HISI_SAS_QUEUE_SLOTS * queue_entry_size); } @@ -2985,13 +2985,13 @@ static void hisi_sas_show_row_32(struct seq_file *s, int index, seq_puts(s, "\n"); } -static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr) +static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, + struct hisi_sas_debugfs_cq *debugfs_cq) { - struct hisi_sas_cq *cq = cq_ptr; + struct hisi_sas_cq *cq = debugfs_cq->cq; struct hisi_hba *hisi_hba = cq->hisi_hba; - void *complete_queue = hisi_hba->debugfs_complete_hdr[cq->id]; - __le32 *complete_hdr = complete_queue + - (hisi_hba->hw->complete_hdr_size * slot); + __le32 *complete_hdr = debugfs_cq->complete_hdr + + (hisi_hba->hw->complete_hdr_size * slot); hisi_sas_show_row_32(s, slot, hisi_hba->hw->complete_hdr_size, @@ -3000,11 +3000,11 @@ static void hisi_sas_cq_show_slot(struct seq_file *s, int slot, void *cq_ptr) static int hisi_sas_debugfs_cq_show(struct seq_file *s, void *p) { - struct hisi_sas_cq *cq = s->private; + struct hisi_sas_debugfs_cq *debugfs_cq = s->private; int slot; for (slot = 0; slot < HISI_SAS_QUEUE_SLOTS; slot++) { - hisi_sas_cq_show_slot(s, slot, cq); + hisi_sas_cq_show_slot(s, slot, debugfs_cq); } return 0; } @@ -3227,7 +3227,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) for (c = 0; c < hisi_hba->queue_count; c++) { snprintf(name, 256, "%d", c); - debugfs_create_file(name, 0400, dentry, &hisi_hba->cq[c], + debugfs_create_file(name, 0400, dentry, + &hisi_hba->debugfs_cq[c], &hisi_sas_debugfs_cq_fops); } @@ -3714,7 +3715,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) devm_kfree(dev, hisi_hba->debugfs_cmd_hdr[i]); for (i = 0; i < hisi_hba->queue_count; i++) - devm_kfree(dev, hisi_hba->debugfs_complete_hdr[i]); + devm_kfree(dev, hisi_hba->debugfs_cq[i].complete_hdr); for (i = 0; i < DEBUGFS_REGS_NUM; i++) devm_kfree(dev, hisi_hba->debugfs_regs[i]); @@ -3762,11 +3763,13 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; for (c = 0; c < hisi_hba->queue_count; c++) { - hisi_hba->debugfs_complete_hdr[c] = - devm_kmalloc(dev, sz, GFP_KERNEL); + struct hisi_sas_debugfs_cq *cq = + &hisi_hba->debugfs_cq[c]; - if (!hisi_hba->debugfs_complete_hdr[c]) + cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!cq->complete_hdr) goto fail; + cq->cq = &hisi_hba->cq[c]; } sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; -- cgit v1.2.3 From 1b54c4db725d875dcae645a3da74625b9e4b3bdf Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:14 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for DQ Create a file structure which was used to save the memory address and DQ pointer for DQ at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it need. Link: https://lore.kernel.org/r/1571926105-74636-8-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 7 ++++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 22 ++++++++++++---------- 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 5b0f08286af7..91c10be3dfb7 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -328,6 +328,11 @@ struct hisi_sas_debugfs_cq { void *complete_hdr; }; +struct hisi_sas_debugfs_dq { + struct hisi_sas_dq *dq; + struct hisi_sas_cmd_hdr *hdr; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -412,7 +417,7 @@ struct hisi_hba { u32 *debugfs_regs[DEBUGFS_REGS_NUM]; u32 *debugfs_port_reg[HISI_SAS_MAX_PHYS]; struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; - struct hisi_sas_cmd_hdr *debugfs_cmd_hdr[HISI_SAS_MAX_QUEUES]; + struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_iost *debugfs_iost; struct hisi_sas_itct *debugfs_itct; u64 *debugfs_iost_cache; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 5c1005f77131..647a14983696 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2711,10 +2711,10 @@ static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) int i; for (i = 0; i < hisi_hba->queue_count; i++) { - struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; + struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; int j; - debugfs_cmd_hdr = hisi_hba->debugfs_cmd_hdr[i]; + debugfs_cmd_hdr = hisi_hba->debugfs_dq[i].hdr; cmd_hdr = hisi_hba->cmd_hdr[i]; for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) @@ -3024,9 +3024,8 @@ static const struct file_operations hisi_sas_debugfs_cq_fops = { static void hisi_sas_dq_show_slot(struct seq_file *s, int slot, void *dq_ptr) { - struct hisi_sas_dq *dq = dq_ptr; - struct hisi_hba *hisi_hba = dq->hisi_hba; - void *cmd_queue = hisi_hba->debugfs_cmd_hdr[dq->id]; + struct hisi_sas_debugfs_dq *debugfs_dq = dq_ptr; + void *cmd_queue = debugfs_dq->hdr; __le32 *cmd_hdr = cmd_queue + sizeof(struct hisi_sas_cmd_hdr) * slot; @@ -3237,7 +3236,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) for (d = 0; d < hisi_hba->queue_count; d++) { snprintf(name, 256, "%d", d); - debugfs_create_file(name, 0400, dentry, &hisi_hba->dq[d], + debugfs_create_file(name, 0400, dentry, + &hisi_hba->debugfs_dq[d], &hisi_sas_debugfs_dq_fops); } @@ -3712,7 +3712,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) devm_kfree(dev, hisi_hba->debugfs_iost); for (i = 0; i < hisi_hba->queue_count; i++) - devm_kfree(dev, hisi_hba->debugfs_cmd_hdr[i]); + devm_kfree(dev, hisi_hba->debugfs_dq[i].hdr); for (i = 0; i < hisi_hba->queue_count; i++) devm_kfree(dev, hisi_hba->debugfs_cq[i].complete_hdr); @@ -3774,11 +3774,13 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; for (d = 0; d < hisi_hba->queue_count; d++) { - hisi_hba->debugfs_cmd_hdr[d] = - devm_kmalloc(dev, sz, GFP_KERNEL); + struct hisi_sas_debugfs_dq *dq = + &hisi_hba->debugfs_dq[d]; - if (!hisi_hba->debugfs_cmd_hdr[d]) + dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!dq->hdr) goto fail; + dq->dq = &hisi_hba->dq[d]; } sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); -- cgit v1.2.3 From c61163981076476e0bcf2d453dcddf8db605f115 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:15 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for registers Create a file structure which was used to save the memory address and hisi_hba pointer for REGS at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it need. Link: https://lore.kernel.org/r/1571926105-74636-9-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 7 +++- drivers/scsi/hisi_sas/hisi_sas_main.c | 62 ++++++++++++++++------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 91c10be3dfb7..1c01e0e76a0e 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -333,6 +333,11 @@ struct hisi_sas_debugfs_dq { struct hisi_sas_cmd_hdr *hdr; }; +struct hisi_sas_debugfs_regs { + struct hisi_hba *hisi_hba; + u32 *data; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -414,7 +419,7 @@ struct hisi_hba { /* debugfs memories */ /* Put Global AXI and RAS Register into register array */ - u32 *debugfs_regs[DEBUGFS_REGS_NUM]; + struct hisi_sas_debugfs_regs debugfs_regs[DEBUGFS_REGS_NUM]; u32 *debugfs_port_reg[HISI_SAS_MAX_PHYS]; struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 647a14983696..92cf9b514a70 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2743,7 +2743,7 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_GLOBAL]; + u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_GLOBAL].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; @@ -2755,7 +2755,7 @@ static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_AXI]; + u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_AXI].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *axi = hw->debugfs_reg_array[DEBUGFS_AXI]; @@ -2768,7 +2768,7 @@ static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_RAS]; + u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_RAS].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *ras = hw->debugfs_reg_array[DEBUGFS_RAS]; @@ -2852,11 +2852,12 @@ static void hisi_sas_debugfs_print_reg(u32 *regs_val, const void *ptr, static int hisi_sas_debugfs_global_show(struct seq_file *s, void *p) { - struct hisi_hba *hisi_hba = s->private; + struct hisi_sas_debugfs_regs *global = s->private; + struct hisi_hba *hisi_hba = global->hisi_hba; const struct hisi_sas_hw *hw = hisi_hba->hw; const void *reg_global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; - hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_GLOBAL], + hisi_sas_debugfs_print_reg(global->data, reg_global, s); return 0; @@ -2878,11 +2879,12 @@ static const struct file_operations hisi_sas_debugfs_global_fops = { static int hisi_sas_debugfs_axi_show(struct seq_file *s, void *p) { - struct hisi_hba *hisi_hba = s->private; + struct hisi_sas_debugfs_regs *axi = s->private; + struct hisi_hba *hisi_hba = axi->hisi_hba; const struct hisi_sas_hw *hw = hisi_hba->hw; const void *reg_axi = hw->debugfs_reg_array[DEBUGFS_AXI]; - hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_AXI], + hisi_sas_debugfs_print_reg(axi->data, reg_axi, s); return 0; @@ -2904,11 +2906,12 @@ static const struct file_operations hisi_sas_debugfs_axi_fops = { static int hisi_sas_debugfs_ras_show(struct seq_file *s, void *p) { - struct hisi_hba *hisi_hba = s->private; + struct hisi_sas_debugfs_regs *ras = s->private; + struct hisi_hba *hisi_hba = ras->hisi_hba; const struct hisi_sas_hw *hw = hisi_hba->hw; const void *reg_ras = hw->debugfs_reg_array[DEBUGFS_RAS]; - hisi_sas_debugfs_print_reg(hisi_hba->debugfs_regs[DEBUGFS_RAS], + hisi_sas_debugfs_print_reg(ras->data, reg_ras, s); return 0; @@ -3209,7 +3212,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) debugfs_create_u64("timestamp", 0400, dump_dentry, debugfs_timestamp); - debugfs_create_file("global", 0400, dump_dentry, hisi_hba, + debugfs_create_file("global", 0400, dump_dentry, + &hisi_hba->debugfs_regs[DEBUGFS_GLOBAL], &hisi_sas_debugfs_global_fops); /* Create port dir and files */ @@ -3253,10 +3257,12 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) debugfs_create_file("itct_cache", 0400, dump_dentry, hisi_hba, &hisi_sas_debugfs_itct_cache_fops); - debugfs_create_file("axi", 0400, dump_dentry, hisi_hba, + debugfs_create_file("axi", 0400, dump_dentry, + &hisi_hba->debugfs_regs[DEBUGFS_AXI], &hisi_sas_debugfs_axi_fops); - debugfs_create_file("ras", 0400, dump_dentry, hisi_hba, + debugfs_create_file("ras", 0400, dump_dentry, + &hisi_hba->debugfs_regs[DEBUGFS_RAS], &hisi_sas_debugfs_ras_fops); return; @@ -3718,7 +3724,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) devm_kfree(dev, hisi_hba->debugfs_cq[i].complete_hdr); for (i = 0; i < DEBUGFS_REGS_NUM; i++) - devm_kfree(dev, hisi_hba->debugfs_regs[i]); + devm_kfree(dev, hisi_hba->debugfs_regs[i].data); for (i = 0; i < hisi_hba->n_phy; i++) devm_kfree(dev, hisi_hba->debugfs_port_reg[i]); @@ -3728,15 +3734,19 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) { const struct hisi_sas_hw *hw = hisi_hba->hw; struct device *dev = hisi_hba->dev; - int p, c, d; + int p, c, d, r; size_t sz; - sz = hw->debugfs_reg_array[DEBUGFS_GLOBAL]->count * 4; - hisi_hba->debugfs_regs[DEBUGFS_GLOBAL] = - devm_kmalloc(dev, sz, GFP_KERNEL); + for (r = 0; r < DEBUGFS_REGS_NUM; r++) { + struct hisi_sas_debugfs_regs *regs = + &hisi_hba->debugfs_regs[r]; - if (!hisi_hba->debugfs_regs[DEBUGFS_GLOBAL]) - goto fail; + sz = hw->debugfs_reg_array[r]->count * 4; + regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!regs->data) + goto fail; + regs->hisi_hba = hisi_hba; + } sz = hw->debugfs_reg_port->count * 4; for (p = 0; p < hisi_hba->n_phy; p++) { @@ -3747,20 +3757,6 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) goto fail; } - sz = hw->debugfs_reg_array[DEBUGFS_AXI]->count * 4; - hisi_hba->debugfs_regs[DEBUGFS_AXI] = - devm_kmalloc(dev, sz, GFP_KERNEL); - - if (!hisi_hba->debugfs_regs[DEBUGFS_AXI]) - goto fail; - - sz = hw->debugfs_reg_array[DEBUGFS_RAS]->count * 4; - hisi_hba->debugfs_regs[DEBUGFS_RAS] = - devm_kmalloc(dev, sz, GFP_KERNEL); - - if (!hisi_hba->debugfs_regs[DEBUGFS_RAS]) - goto fail; - sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; for (c = 0; c < hisi_hba->queue_count; c++) { struct hisi_sas_debugfs_cq *cq = -- cgit v1.2.3 From 1f66e1fd26bddb4c9275b61934dbaaf4b0b0bd79 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:16 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for port Create a file structure which was used to save the memory address and phy pointer for port at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it need. Link: https://lore.kernel.org/r/1571926105-74636-10-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 7 ++++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 1c01e0e76a0e..af5f836e5807 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -338,6 +338,11 @@ struct hisi_sas_debugfs_regs { u32 *data; }; +struct hisi_sas_debugfs_port { + struct hisi_sas_phy *phy; + u32 *data; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -420,7 +425,7 @@ struct hisi_hba { /* debugfs memories */ /* Put Global AXI and RAS Register into register array */ struct hisi_sas_debugfs_regs debugfs_regs[DEBUGFS_REGS_NUM]; - u32 *debugfs_port_reg[HISI_SAS_MAX_PHYS]; + struct hisi_sas_debugfs_port debugfs_port_reg[HISI_SAS_MAX_PHYS]; struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_iost *debugfs_iost; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 92cf9b514a70..e28aa3d517da 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2732,7 +2732,7 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) u32 *databuf; for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { - databuf = (u32 *)hisi_hba->debugfs_port_reg[phy_cnt]; + databuf = hisi_hba->debugfs_port_reg[phy_cnt].data; for (i = 0; i < port->count; i++, databuf++) { offset = port->base_off + 4 * i; *databuf = port->read_port_reg(hisi_hba, phy_cnt, @@ -2933,13 +2933,13 @@ static const struct file_operations hisi_sas_debugfs_ras_fops = { static int hisi_sas_debugfs_port_show(struct seq_file *s, void *p) { - struct hisi_sas_phy *phy = s->private; + struct hisi_sas_debugfs_port *port = s->private; + struct hisi_sas_phy *phy = port->phy; struct hisi_hba *hisi_hba = phy->hisi_hba; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *reg_port = hw->debugfs_reg_port; - u32 *databuf = hisi_hba->debugfs_port_reg[phy->sas_phy.id]; - hisi_sas_debugfs_print_reg(databuf, reg_port, s); + hisi_sas_debugfs_print_reg(port->data, reg_port, s); return 0; } @@ -3221,7 +3221,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) for (p = 0; p < hisi_hba->n_phy; p++) { snprintf(name, 256, "%d", p); - debugfs_create_file(name, 0400, dentry, &hisi_hba->phy[p], + debugfs_create_file(name, 0400, dentry, + &hisi_hba->debugfs_port_reg[p], &hisi_sas_debugfs_port_fops); } @@ -3727,7 +3728,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) devm_kfree(dev, hisi_hba->debugfs_regs[i].data); for (i = 0; i < hisi_hba->n_phy; i++) - devm_kfree(dev, hisi_hba->debugfs_port_reg[i]); + devm_kfree(dev, hisi_hba->debugfs_port_reg[i].data); } static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) @@ -3750,11 +3751,13 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = hw->debugfs_reg_port->count * 4; for (p = 0; p < hisi_hba->n_phy; p++) { - hisi_hba->debugfs_port_reg[p] = - devm_kmalloc(dev, sz, GFP_KERNEL); + struct hisi_sas_debugfs_port *port = + &hisi_hba->debugfs_port_reg[p]; - if (!hisi_hba->debugfs_port_reg[p]) + port->data = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!port->data) goto fail; + port->phy = &hisi_hba->phy[p]; } sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; -- cgit v1.2.3 From e15f2e2dff5b809dce923839f21362d6b0d06b1e Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:17 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for IOST Create a file structure which was used to save the memory address for IOST at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it needs. Link: https://lore.kernel.org/r/1571926105-74636-11-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 6 +++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 21 +++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index af5f836e5807..c4bcaa5aff8a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -343,6 +343,10 @@ struct hisi_sas_debugfs_port { u32 *data; }; +struct hisi_sas_debugfs_iost { + struct hisi_sas_iost *iost; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -428,7 +432,7 @@ struct hisi_hba { struct hisi_sas_debugfs_port debugfs_port_reg[HISI_SAS_MAX_PHYS]; struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; - struct hisi_sas_iost *debugfs_iost; + struct hisi_sas_debugfs_iost debugfs_iost; struct hisi_sas_itct *debugfs_itct; u64 *debugfs_iost_cache; u64 debugfs_timestamp; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index e28aa3d517da..55191056f37f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2801,7 +2801,7 @@ static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) { int max_command_entries = HISI_SAS_MAX_COMMANDS; void *cachebuf = hisi_hba->debugfs_iost_cache; - void *databuf = hisi_hba->debugfs_iost; + void *databuf = hisi_hba->debugfs_iost.iost; struct hisi_sas_iost *iost; int i; @@ -3060,14 +3060,14 @@ static const struct file_operations hisi_sas_debugfs_dq_fops = { static int hisi_sas_debugfs_iost_show(struct seq_file *s, void *p) { - struct hisi_hba *hisi_hba = s->private; - struct hisi_sas_iost *debugfs_iost = hisi_hba->debugfs_iost; + struct hisi_sas_debugfs_iost *debugfs_iost = s->private; + struct hisi_sas_iost *iost = debugfs_iost->iost; int i, max_command_entries = HISI_SAS_MAX_COMMANDS; - for (i = 0; i < max_command_entries; i++, debugfs_iost++) { - __le64 *iost = &debugfs_iost->qw0; + for (i = 0; i < max_command_entries; i++, iost++) { + __le64 *data = &iost->qw0; - hisi_sas_show_row_64(s, i, sizeof(*debugfs_iost), iost); + hisi_sas_show_row_64(s, i, sizeof(*iost), data); } return 0; @@ -3246,7 +3246,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) &hisi_sas_debugfs_dq_fops); } - debugfs_create_file("iost", 0400, dump_dentry, hisi_hba, + debugfs_create_file("iost", 0400, dump_dentry, + &hisi_hba->debugfs_iost, &hisi_sas_debugfs_iost_fops); debugfs_create_file("iost_cache", 0400, dump_dentry, hisi_hba, @@ -3716,7 +3717,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) devm_kfree(dev, hisi_hba->debugfs_iost_cache); devm_kfree(dev, hisi_hba->debugfs_itct_cache); - devm_kfree(dev, hisi_hba->debugfs_iost); + devm_kfree(dev, hisi_hba->debugfs_iost.iost); for (i = 0; i < hisi_hba->queue_count; i++) devm_kfree(dev, hisi_hba->debugfs_dq[i].hdr); @@ -3784,8 +3785,8 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); - hisi_hba->debugfs_iost = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_iost) + hisi_hba->debugfs_iost.iost = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost.iost) goto fail; sz = HISI_SAS_IOST_ITCT_CACHE_NUM * -- cgit v1.2.3 From 0161d55f23a1e020e5e6892177caf92a61e5c161 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:18 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for ITCT Create a file structure which was used to save the memory address for ITCT at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it needs. Link: https://lore.kernel.org/r/1571926105-74636-12-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 6 +++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 23 ++++++++++++----------- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index c4bcaa5aff8a..f42f1b34f843 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -347,6 +347,10 @@ struct hisi_sas_debugfs_iost { struct hisi_sas_iost *iost; }; +struct hisi_sas_debugfs_itct { + struct hisi_sas_itct *itct; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -433,7 +437,7 @@ struct hisi_hba { struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_debugfs_iost debugfs_iost; - struct hisi_sas_itct *debugfs_itct; + struct hisi_sas_debugfs_itct debugfs_itct; u64 *debugfs_iost_cache; u64 debugfs_timestamp; u64 *debugfs_itct_cache; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 55191056f37f..a35d3a76ac11 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1573,7 +1573,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) struct Scsi_Host *shost = hisi_hba->shost; int rc; - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct) + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct.itct) queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); if (!hisi_hba->hw->soft_reset) @@ -2065,7 +2065,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, /* Internal abort timed out */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct) + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct.itct) queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { @@ -2782,7 +2782,7 @@ static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) { void *cachebuf = hisi_hba->debugfs_itct_cache; - void *databuf = hisi_hba->debugfs_itct; + void *databuf = hisi_hba->debugfs_itct.itct; struct hisi_sas_itct *itct; int i; @@ -3129,13 +3129,13 @@ static const struct file_operations hisi_sas_debugfs_iost_cache_fops = { static int hisi_sas_debugfs_itct_show(struct seq_file *s, void *p) { int i; - struct hisi_hba *hisi_hba = s->private; - struct hisi_sas_itct *debugfs_itct = hisi_hba->debugfs_itct; + struct hisi_sas_debugfs_itct *debugfs_itct = s->private; + struct hisi_sas_itct *itct = debugfs_itct->itct; - for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, debugfs_itct++) { - __le64 *itct = &debugfs_itct->qw0; + for (i = 0; i < HISI_SAS_MAX_ITCT_ENTRIES; i++, itct++) { + __le64 *data = &itct->qw0; - hisi_sas_show_row_64(s, i, sizeof(*debugfs_itct), itct); + hisi_sas_show_row_64(s, i, sizeof(*itct), data); } return 0; @@ -3253,7 +3253,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) debugfs_create_file("iost_cache", 0400, dump_dentry, hisi_hba, &hisi_sas_debugfs_iost_cache_fops); - debugfs_create_file("itct", 0400, dump_dentry, hisi_hba, + debugfs_create_file("itct", 0400, dump_dentry, + &hisi_hba->debugfs_itct, &hisi_sas_debugfs_itct_fops); debugfs_create_file("itct_cache", 0400, dump_dentry, hisi_hba, @@ -3806,8 +3807,8 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) /* New memory allocation must be locate before itct */ sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); - hisi_hba->debugfs_itct = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_itct) + hisi_hba->debugfs_itct.itct = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct.itct) goto fail; return 0; -- cgit v1.2.3 From b714dd8f36dc609dd4b0078cf5563978134838ed Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:19 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for IOST cache Create a file structure which was used to save the memory address for IOST cache at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it needs. Link: https://lore.kernel.org/r/1571926105-74636-13-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 6 +++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 16 ++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index f42f1b34f843..4e32d1b77d16 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -351,6 +351,10 @@ struct hisi_sas_debugfs_itct { struct hisi_sas_itct *itct; }; +struct hisi_sas_debugfs_iost_cache { + struct hisi_sas_iost_itct_cache *cache; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -438,8 +442,8 @@ struct hisi_hba { struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; struct hisi_sas_debugfs_iost debugfs_iost; struct hisi_sas_debugfs_itct debugfs_itct; - u64 *debugfs_iost_cache; u64 debugfs_timestamp; + struct hisi_sas_debugfs_iost_cache debugfs_iost_cache; u64 *debugfs_itct_cache; struct dentry *debugfs_dir; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index a35d3a76ac11..499a733f9a5a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2800,7 +2800,7 @@ static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) { int max_command_entries = HISI_SAS_MAX_COMMANDS; - void *cachebuf = hisi_hba->debugfs_iost_cache; + void *cachebuf = hisi_hba->debugfs_iost_cache.cache; void *databuf = hisi_hba->debugfs_iost.iost; struct hisi_sas_iost *iost; int i; @@ -3088,9 +3088,8 @@ static const struct file_operations hisi_sas_debugfs_iost_fops = { static int hisi_sas_debugfs_iost_cache_show(struct seq_file *s, void *p) { - struct hisi_hba *hisi_hba = s->private; - struct hisi_sas_iost_itct_cache *iost_cache = - (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_iost_cache; + struct hisi_sas_debugfs_iost_cache *debugfs_iost_cache = s->private; + struct hisi_sas_iost_itct_cache *iost_cache = debugfs_iost_cache->cache; u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; int i, tab_idx; __le64 *iost; @@ -3250,7 +3249,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) &hisi_hba->debugfs_iost, &hisi_sas_debugfs_iost_fops); - debugfs_create_file("iost_cache", 0400, dump_dentry, hisi_hba, + debugfs_create_file("iost_cache", 0400, dump_dentry, + &hisi_hba->debugfs_iost_cache, &hisi_sas_debugfs_iost_cache_fops); debugfs_create_file("itct", 0400, dump_dentry, @@ -3716,7 +3716,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) struct device *dev = hisi_hba->dev; int i; - devm_kfree(dev, hisi_hba->debugfs_iost_cache); + devm_kfree(dev, hisi_hba->debugfs_iost_cache.cache); devm_kfree(dev, hisi_hba->debugfs_itct_cache); devm_kfree(dev, hisi_hba->debugfs_iost.iost); @@ -3793,8 +3793,8 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = HISI_SAS_IOST_ITCT_CACHE_NUM * sizeof(struct hisi_sas_iost_itct_cache); - hisi_hba->debugfs_iost_cache = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_iost_cache) + hisi_hba->debugfs_iost_cache.cache = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost_cache.cache) goto fail; sz = HISI_SAS_IOST_ITCT_CACHE_NUM * -- cgit v1.2.3 From 357e4fc7a933ed5bfbf1eb2fad9c198afe6a11e1 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:20 +0800 Subject: scsi: hisi_sas: Add debugfs file structure for ITCT cache Create a file structure which was used to save the memory address for ITCT cache at debugfs. This structure is bound to the corresponding debugfs file, it can help callback function of debugfs file to get what it needs. Link: https://lore.kernel.org/r/1571926105-74636-14-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 6 +++++- drivers/scsi/hisi_sas/hisi_sas_main.c | 16 ++++++++-------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 4e32d1b77d16..a608b2bef0b4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -355,6 +355,10 @@ struct hisi_sas_debugfs_iost_cache { struct hisi_sas_iost_itct_cache *cache; }; +struct hisi_sas_debugfs_itct_cache { + struct hisi_sas_iost_itct_cache *cache; +}; + struct hisi_hba { /* This must be the first element, used by SHOST_TO_SAS_HA */ struct sas_ha_struct *p; @@ -444,7 +448,7 @@ struct hisi_hba { struct hisi_sas_debugfs_itct debugfs_itct; u64 debugfs_timestamp; struct hisi_sas_debugfs_iost_cache debugfs_iost_cache; - u64 *debugfs_itct_cache; + struct hisi_sas_debugfs_itct_cache debugfs_itct_cache; struct dentry *debugfs_dir; struct dentry *debugfs_dump_dentry; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 499a733f9a5a..5014a7a21aa4 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2781,7 +2781,7 @@ static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) { - void *cachebuf = hisi_hba->debugfs_itct_cache; + void *cachebuf = hisi_hba->debugfs_itct_cache.cache; void *databuf = hisi_hba->debugfs_itct.itct; struct hisi_sas_itct *itct; int i; @@ -3155,9 +3155,8 @@ static const struct file_operations hisi_sas_debugfs_itct_fops = { static int hisi_sas_debugfs_itct_cache_show(struct seq_file *s, void *p) { - struct hisi_hba *hisi_hba = s->private; - struct hisi_sas_iost_itct_cache *itct_cache = - (struct hisi_sas_iost_itct_cache *)hisi_hba->debugfs_itct_cache; + struct hisi_sas_debugfs_itct_cache *debugfs_itct_cache = s->private; + struct hisi_sas_iost_itct_cache *itct_cache = debugfs_itct_cache->cache; u32 cache_size = HISI_SAS_IOST_ITCT_CACHE_DW_SZ * 4; int i, tab_idx; __le64 *itct; @@ -3257,7 +3256,8 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) &hisi_hba->debugfs_itct, &hisi_sas_debugfs_itct_fops); - debugfs_create_file("itct_cache", 0400, dump_dentry, hisi_hba, + debugfs_create_file("itct_cache", 0400, dump_dentry, + &hisi_hba->debugfs_itct_cache, &hisi_sas_debugfs_itct_cache_fops); debugfs_create_file("axi", 0400, dump_dentry, @@ -3717,7 +3717,7 @@ static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) int i; devm_kfree(dev, hisi_hba->debugfs_iost_cache.cache); - devm_kfree(dev, hisi_hba->debugfs_itct_cache); + devm_kfree(dev, hisi_hba->debugfs_itct_cache.cache); devm_kfree(dev, hisi_hba->debugfs_iost.iost); for (i = 0; i < hisi_hba->queue_count; i++) @@ -3800,8 +3800,8 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = HISI_SAS_IOST_ITCT_CACHE_NUM * sizeof(struct hisi_sas_iost_itct_cache); - hisi_hba->debugfs_itct_cache = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_itct_cache) + hisi_hba->debugfs_itct_cache.cache = devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct_cache.cache) goto fail; /* New memory allocation must be locate before itct */ -- cgit v1.2.3 From a70e33eae363e6f3e2ad9498daaccd231790f7f5 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:21 +0800 Subject: scsi: hisi_sas: Allocate memory for multiple dumps of debugfs We add multiple dumps for debugfs, but only allocate memory this time and only dump #0. Link: https://lore.kernel.org/r/1571926105-74636-15-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 19 +++--- drivers/scsi/hisi_sas/hisi_sas_main.c | 110 +++++++++++++++++++--------------- 2 files changed, 73 insertions(+), 56 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index a608b2bef0b4..b4c6bec4b92c 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -323,6 +323,8 @@ struct hisi_sas_hw { const struct hisi_sas_debugfs_reg *debugfs_reg_port; }; +#define HISI_SAS_MAX_DEBUGFS_DUMP (50) + struct hisi_sas_debugfs_cq { struct hisi_sas_cq *cq; void *complete_hdr; @@ -440,15 +442,16 @@ struct hisi_hba { /* debugfs memories */ /* Put Global AXI and RAS Register into register array */ - struct hisi_sas_debugfs_regs debugfs_regs[DEBUGFS_REGS_NUM]; - struct hisi_sas_debugfs_port debugfs_port_reg[HISI_SAS_MAX_PHYS]; - struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_QUEUES]; - struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_QUEUES]; - struct hisi_sas_debugfs_iost debugfs_iost; - struct hisi_sas_debugfs_itct debugfs_itct; + struct hisi_sas_debugfs_regs debugfs_regs[HISI_SAS_MAX_DEBUGFS_DUMP][DEBUGFS_REGS_NUM]; + struct hisi_sas_debugfs_port debugfs_port_reg[HISI_SAS_MAX_DEBUGFS_DUMP][HISI_SAS_MAX_PHYS]; + struct hisi_sas_debugfs_cq debugfs_cq[HISI_SAS_MAX_DEBUGFS_DUMP][HISI_SAS_MAX_QUEUES]; + struct hisi_sas_debugfs_dq debugfs_dq[HISI_SAS_MAX_DEBUGFS_DUMP][HISI_SAS_MAX_QUEUES]; + struct hisi_sas_debugfs_iost debugfs_iost[HISI_SAS_MAX_DEBUGFS_DUMP]; + struct hisi_sas_debugfs_itct debugfs_itct[HISI_SAS_MAX_DEBUGFS_DUMP]; + struct hisi_sas_debugfs_iost_cache debugfs_iost_cache[HISI_SAS_MAX_DEBUGFS_DUMP]; + struct hisi_sas_debugfs_itct_cache debugfs_itct_cache[HISI_SAS_MAX_DEBUGFS_DUMP]; + u64 debugfs_timestamp; - struct hisi_sas_debugfs_iost_cache debugfs_iost_cache; - struct hisi_sas_debugfs_itct_cache debugfs_itct_cache; struct dentry *debugfs_dir; struct dentry *debugfs_dump_dentry; diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 5014a7a21aa4..b599595ea095 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1573,7 +1573,7 @@ static int hisi_sas_controller_reset(struct hisi_hba *hisi_hba) struct Scsi_Host *shost = hisi_hba->shost; int rc; - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct.itct) + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); if (!hisi_hba->hw->soft_reset) @@ -2065,7 +2065,7 @@ _hisi_sas_internal_task_abort(struct hisi_hba *hisi_hba, /* Internal abort timed out */ if ((task->task_state_flags & SAS_TASK_STATE_ABORTED)) { - if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct.itct) + if (hisi_sas_debugfs_enable && hisi_hba->debugfs_itct[0].itct) queue_work(hisi_hba->wq, &hisi_hba->debugfs_work); if (!(task->task_state_flags & SAS_TASK_STATE_DONE)) { @@ -2700,7 +2700,7 @@ static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) int i; for (i = 0; i < hisi_hba->queue_count; i++) - memcpy(hisi_hba->debugfs_cq[i].complete_hdr, + memcpy(hisi_hba->debugfs_cq[0][i].complete_hdr, hisi_hba->complete_hdr[i], HISI_SAS_QUEUE_SLOTS * queue_entry_size); } @@ -2714,7 +2714,7 @@ static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; int j; - debugfs_cmd_hdr = hisi_hba->debugfs_dq[i].hdr; + debugfs_cmd_hdr = hisi_hba->debugfs_dq[0][i].hdr; cmd_hdr = hisi_hba->cmd_hdr[i]; for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) @@ -2732,7 +2732,7 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) u32 *databuf; for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { - databuf = hisi_hba->debugfs_port_reg[phy_cnt].data; + databuf = hisi_hba->debugfs_port_reg[0][phy_cnt].data; for (i = 0; i < port->count; i++, databuf++) { offset = port->base_off + 4 * i; *databuf = port->read_port_reg(hisi_hba, phy_cnt, @@ -2743,7 +2743,7 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_GLOBAL].data; + u32 *databuf = hisi_hba->debugfs_regs[0][DEBUGFS_GLOBAL].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; @@ -2755,7 +2755,7 @@ static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_AXI].data; + u32 *databuf = hisi_hba->debugfs_regs[0][DEBUGFS_AXI].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *axi = hw->debugfs_reg_array[DEBUGFS_AXI]; @@ -2768,7 +2768,7 @@ static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[DEBUGFS_RAS].data; + u32 *databuf = hisi_hba->debugfs_regs[0][DEBUGFS_RAS].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *ras = hw->debugfs_reg_array[DEBUGFS_RAS]; @@ -2781,8 +2781,8 @@ static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) { - void *cachebuf = hisi_hba->debugfs_itct_cache.cache; - void *databuf = hisi_hba->debugfs_itct.itct; + void *cachebuf = hisi_hba->debugfs_itct_cache[0].cache; + void *databuf = hisi_hba->debugfs_itct[0].itct; struct hisi_sas_itct *itct; int i; @@ -2800,8 +2800,8 @@ static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) { int max_command_entries = HISI_SAS_MAX_COMMANDS; - void *cachebuf = hisi_hba->debugfs_iost_cache.cache; - void *databuf = hisi_hba->debugfs_iost.iost; + void *cachebuf = hisi_hba->debugfs_iost_cache[0].cache; + void *databuf = hisi_hba->debugfs_iost[0].iost; struct hisi_sas_iost *iost; int i; @@ -3211,7 +3211,7 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) debugfs_timestamp); debugfs_create_file("global", 0400, dump_dentry, - &hisi_hba->debugfs_regs[DEBUGFS_GLOBAL], + &hisi_hba->debugfs_regs[0][DEBUGFS_GLOBAL], &hisi_sas_debugfs_global_fops); /* Create port dir and files */ @@ -3220,7 +3220,7 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", p); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_port_reg[p], + &hisi_hba->debugfs_port_reg[0][p], &hisi_sas_debugfs_port_fops); } @@ -3230,7 +3230,7 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", c); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_cq[c], + &hisi_hba->debugfs_cq[0][c], &hisi_sas_debugfs_cq_fops); } @@ -3240,32 +3240,32 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", d); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_dq[d], + &hisi_hba->debugfs_dq[0][d], &hisi_sas_debugfs_dq_fops); } debugfs_create_file("iost", 0400, dump_dentry, - &hisi_hba->debugfs_iost, + &hisi_hba->debugfs_iost[0], &hisi_sas_debugfs_iost_fops); debugfs_create_file("iost_cache", 0400, dump_dentry, - &hisi_hba->debugfs_iost_cache, + &hisi_hba->debugfs_iost_cache[0], &hisi_sas_debugfs_iost_cache_fops); debugfs_create_file("itct", 0400, dump_dentry, - &hisi_hba->debugfs_itct, + &hisi_hba->debugfs_itct[0], &hisi_sas_debugfs_itct_fops); debugfs_create_file("itct_cache", 0400, dump_dentry, - &hisi_hba->debugfs_itct_cache, + &hisi_hba->debugfs_itct_cache[0], &hisi_sas_debugfs_itct_cache_fops); debugfs_create_file("axi", 0400, dump_dentry, - &hisi_hba->debugfs_regs[DEBUGFS_AXI], + &hisi_hba->debugfs_regs[0][DEBUGFS_AXI], &hisi_sas_debugfs_axi_fops); debugfs_create_file("ras", 0400, dump_dentry, - &hisi_hba->debugfs_regs[DEBUGFS_RAS], + &hisi_hba->debugfs_regs[0][DEBUGFS_RAS], &hisi_sas_debugfs_ras_fops); return; @@ -3711,38 +3711,40 @@ void hisi_sas_debugfs_work_handler(struct work_struct *work) } EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler); -static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba) +static void hisi_sas_debugfs_release(struct hisi_hba *hisi_hba, int dump_index) { struct device *dev = hisi_hba->dev; int i; - devm_kfree(dev, hisi_hba->debugfs_iost_cache.cache); - devm_kfree(dev, hisi_hba->debugfs_itct_cache.cache); - devm_kfree(dev, hisi_hba->debugfs_iost.iost); + devm_kfree(dev, hisi_hba->debugfs_iost_cache[dump_index].cache); + devm_kfree(dev, hisi_hba->debugfs_itct_cache[dump_index].cache); + devm_kfree(dev, hisi_hba->debugfs_iost[dump_index].iost); + devm_kfree(dev, hisi_hba->debugfs_itct[dump_index].itct); for (i = 0; i < hisi_hba->queue_count; i++) - devm_kfree(dev, hisi_hba->debugfs_dq[i].hdr); + devm_kfree(dev, hisi_hba->debugfs_dq[dump_index][i].hdr); for (i = 0; i < hisi_hba->queue_count; i++) - devm_kfree(dev, hisi_hba->debugfs_cq[i].complete_hdr); + devm_kfree(dev, + hisi_hba->debugfs_cq[dump_index][i].complete_hdr); for (i = 0; i < DEBUGFS_REGS_NUM; i++) - devm_kfree(dev, hisi_hba->debugfs_regs[i].data); + devm_kfree(dev, hisi_hba->debugfs_regs[dump_index][i].data); for (i = 0; i < hisi_hba->n_phy; i++) - devm_kfree(dev, hisi_hba->debugfs_port_reg[i].data); + devm_kfree(dev, hisi_hba->debugfs_port_reg[dump_index][i].data); } -static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) +static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index) { const struct hisi_sas_hw *hw = hisi_hba->hw; struct device *dev = hisi_hba->dev; - int p, c, d, r; + int p, c, d, r, i; size_t sz; for (r = 0; r < DEBUGFS_REGS_NUM; r++) { struct hisi_sas_debugfs_regs *regs = - &hisi_hba->debugfs_regs[r]; + &hisi_hba->debugfs_regs[dump_index][r]; sz = hw->debugfs_reg_array[r]->count * 4; regs->data = devm_kmalloc(dev, sz, GFP_KERNEL); @@ -3754,7 +3756,7 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = hw->debugfs_reg_port->count * 4; for (p = 0; p < hisi_hba->n_phy; p++) { struct hisi_sas_debugfs_port *port = - &hisi_hba->debugfs_port_reg[p]; + &hisi_hba->debugfs_port_reg[dump_index][p]; port->data = devm_kmalloc(dev, sz, GFP_KERNEL); if (!port->data) @@ -3765,7 +3767,7 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = hw->complete_hdr_size * HISI_SAS_QUEUE_SLOTS; for (c = 0; c < hisi_hba->queue_count; c++) { struct hisi_sas_debugfs_cq *cq = - &hisi_hba->debugfs_cq[c]; + &hisi_hba->debugfs_cq[dump_index][c]; cq->complete_hdr = devm_kmalloc(dev, sz, GFP_KERNEL); if (!cq->complete_hdr) @@ -3776,7 +3778,7 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = sizeof(struct hisi_sas_cmd_hdr) * HISI_SAS_QUEUE_SLOTS; for (d = 0; d < hisi_hba->queue_count; d++) { struct hisi_sas_debugfs_dq *dq = - &hisi_hba->debugfs_dq[d]; + &hisi_hba->debugfs_dq[dump_index][d]; dq->hdr = devm_kmalloc(dev, sz, GFP_KERNEL); if (!dq->hdr) @@ -3786,34 +3788,39 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba) sz = HISI_SAS_MAX_COMMANDS * sizeof(struct hisi_sas_iost); - hisi_hba->debugfs_iost.iost = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_iost.iost) + hisi_hba->debugfs_iost[dump_index].iost = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost[dump_index].iost) goto fail; sz = HISI_SAS_IOST_ITCT_CACHE_NUM * sizeof(struct hisi_sas_iost_itct_cache); - hisi_hba->debugfs_iost_cache.cache = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_iost_cache.cache) + hisi_hba->debugfs_iost_cache[dump_index].cache = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_iost_cache[dump_index].cache) goto fail; sz = HISI_SAS_IOST_ITCT_CACHE_NUM * sizeof(struct hisi_sas_iost_itct_cache); - hisi_hba->debugfs_itct_cache.cache = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_itct_cache.cache) + hisi_hba->debugfs_itct_cache[dump_index].cache = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct_cache[dump_index].cache) goto fail; /* New memory allocation must be locate before itct */ sz = HISI_SAS_MAX_ITCT_ENTRIES * sizeof(struct hisi_sas_itct); - hisi_hba->debugfs_itct.itct = devm_kmalloc(dev, sz, GFP_KERNEL); - if (!hisi_hba->debugfs_itct.itct) + hisi_hba->debugfs_itct[dump_index].itct = + devm_kmalloc(dev, sz, GFP_KERNEL); + if (!hisi_hba->debugfs_itct[dump_index].itct) goto fail; return 0; fail: - hisi_sas_debugfs_release(hisi_hba); + for (i = 0; i < HISI_SAS_MAX_DEBUGFS_DUMP; i++) + hisi_sas_debugfs_release(hisi_hba, i); return -ENOMEM; } @@ -3848,6 +3855,7 @@ static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba) void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) { struct device *dev = hisi_hba->dev; + int i; hisi_hba->debugfs_dir = debugfs_create_dir(dev_name(dev), hisi_sas_debugfs_dir); @@ -3859,9 +3867,15 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) /* create bist structures */ hisi_sas_debugfs_bist_init(hisi_hba); - if (hisi_sas_debugfs_alloc(hisi_hba)) { - debugfs_remove_recursive(hisi_hba->debugfs_dir); - dev_dbg(dev, "failed to init debugfs!\n"); + hisi_hba->debugfs_dump_dentry = + debugfs_create_dir("dump", hisi_hba->debugfs_dir); + + for (i = 0; i < HISI_SAS_MAX_DEBUGFS_DUMP; i++) { + if (hisi_sas_debugfs_alloc(hisi_hba, i)) { + debugfs_remove_recursive(hisi_hba->debugfs_dir); + dev_dbg(dev, "failed to init debugfs!\n"); + break; + } } } EXPORT_SYMBOL_GPL(hisi_sas_debugfs_init); -- cgit v1.2.3 From 905ab01faf5fc81ba2fc46dddcd21ad5a2dd137b Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:22 +0800 Subject: scsi: hisi_sas: Add module parameter for debugfs dump count We still only use dump index #0 however. Link: https://lore.kernel.org/r/1571926105-74636-16-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index b4c6bec4b92c..bdd4aa7ed730 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -598,6 +598,7 @@ struct hisi_sas_slot_dif_buf_table { extern struct scsi_transport_template *hisi_sas_stt; extern bool hisi_sas_debugfs_enable; +extern u32 hisi_sas_debugfs_dump_count; extern struct dentry *hisi_sas_debugfs_dir; extern void hisi_sas_stop_phys(struct hisi_hba *hisi_hba); diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index b599595ea095..5b3cee67bb24 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -3819,7 +3819,7 @@ static int hisi_sas_debugfs_alloc(struct hisi_hba *hisi_hba, int dump_index) return 0; fail: - for (i = 0; i < HISI_SAS_MAX_DEBUGFS_DUMP; i++) + for (i = 0; i < hisi_sas_debugfs_dump_count; i++) hisi_sas_debugfs_release(hisi_hba, i); return -ENOMEM; } @@ -3870,7 +3870,7 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) hisi_hba->debugfs_dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); - for (i = 0; i < HISI_SAS_MAX_DEBUGFS_DUMP; i++) { + for (i = 0; i < hisi_sas_debugfs_dump_count; i++) { if (hisi_sas_debugfs_alloc(hisi_hba, i)) { debugfs_remove_recursive(hisi_hba->debugfs_dir); dev_dbg(dev, "failed to init debugfs!\n"); @@ -3909,14 +3909,24 @@ EXPORT_SYMBOL_GPL(hisi_sas_debugfs_enable); module_param_named(debugfs_enable, hisi_sas_debugfs_enable, bool, 0444); MODULE_PARM_DESC(hisi_sas_debugfs_enable, "Enable driver debugfs (default disabled)"); +u32 hisi_sas_debugfs_dump_count = 1; +EXPORT_SYMBOL_GPL(hisi_sas_debugfs_dump_count); +module_param_named(debugfs_dump_count, hisi_sas_debugfs_dump_count, uint, 0444); +MODULE_PARM_DESC(hisi_sas_debugfs_dump_count, "Number of debugfs dumps to allow"); + static __init int hisi_sas_init(void) { hisi_sas_stt = sas_domain_attach_transport(&hisi_sas_transport_ops); if (!hisi_sas_stt) return -ENOMEM; - if (hisi_sas_debugfs_enable) + if (hisi_sas_debugfs_enable) { hisi_sas_debugfs_dir = debugfs_create_dir("hisi_sas", NULL); + if (hisi_sas_debugfs_dump_count > HISI_SAS_MAX_DEBUGFS_DUMP) { + pr_info("hisi_sas: Limiting debugfs dump count\n"); + hisi_sas_debugfs_dump_count = HISI_SAS_MAX_DEBUGFS_DUMP; + } + } return 0; } -- cgit v1.2.3 From 8f6432986e610612688dc77c2683657d7289546f Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:23 +0800 Subject: scsi: hisi_sas: Add ability to have multiple debugfs dumps We use the module parameter debugfs_dump_count to manage the upper limit of the memory block for multiple dumps. Link: https://lore.kernel.org/r/1571926105-74636-17-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 5 +-- drivers/scsi/hisi_sas/hisi_sas_main.c | 76 +++++++++++++++++++++-------------- 2 files changed, 47 insertions(+), 34 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index bdd4aa7ed730..72823222e08f 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -451,12 +451,11 @@ struct hisi_hba { struct hisi_sas_debugfs_iost_cache debugfs_iost_cache[HISI_SAS_MAX_DEBUGFS_DUMP]; struct hisi_sas_debugfs_itct_cache debugfs_itct_cache[HISI_SAS_MAX_DEBUGFS_DUMP]; - u64 debugfs_timestamp; - + u64 debugfs_timestamp[HISI_SAS_MAX_DEBUGFS_DUMP]; + int debugfs_dump_index; struct dentry *debugfs_dir; struct dentry *debugfs_dump_dentry; struct dentry *debugfs_bist_dentry; - bool debugfs_snapshot; }; /* Generic HW DMA host memory structures */ diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 5b3cee67bb24..7fa9a5a51b80 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2697,10 +2697,11 @@ struct dentry *hisi_sas_debugfs_dir; static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) { int queue_entry_size = hisi_hba->hw->complete_hdr_size; + int dump_index = hisi_hba->debugfs_dump_index; int i; for (i = 0; i < hisi_hba->queue_count; i++) - memcpy(hisi_hba->debugfs_cq[0][i].complete_hdr, + memcpy(hisi_hba->debugfs_cq[dump_index][i].complete_hdr, hisi_hba->complete_hdr[i], HISI_SAS_QUEUE_SLOTS * queue_entry_size); } @@ -2708,13 +2709,14 @@ static void hisi_sas_debugfs_snapshot_cq_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) { int queue_entry_size = sizeof(struct hisi_sas_cmd_hdr); + int dump_index = hisi_hba->debugfs_dump_index; int i; for (i = 0; i < hisi_hba->queue_count; i++) { struct hisi_sas_cmd_hdr *debugfs_cmd_hdr, *cmd_hdr; int j; - debugfs_cmd_hdr = hisi_hba->debugfs_dq[0][i].hdr; + debugfs_cmd_hdr = hisi_hba->debugfs_dq[dump_index][i].hdr; cmd_hdr = hisi_hba->cmd_hdr[i]; for (j = 0; j < HISI_SAS_QUEUE_SLOTS; j++) @@ -2725,6 +2727,7 @@ static void hisi_sas_debugfs_snapshot_dq_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) { + int dump_index = hisi_hba->debugfs_dump_index; const struct hisi_sas_debugfs_reg *port = hisi_hba->hw->debugfs_reg_port; int i, phy_cnt; @@ -2732,7 +2735,7 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) u32 *databuf; for (phy_cnt = 0; phy_cnt < hisi_hba->n_phy; phy_cnt++) { - databuf = hisi_hba->debugfs_port_reg[0][phy_cnt].data; + databuf = hisi_hba->debugfs_port_reg[dump_index][phy_cnt].data; for (i = 0; i < port->count; i++, databuf++) { offset = port->base_off + 4 * i; *databuf = port->read_port_reg(hisi_hba, phy_cnt, @@ -2743,7 +2746,8 @@ static void hisi_sas_debugfs_snapshot_port_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[0][DEBUGFS_GLOBAL].data; + int dump_index = hisi_hba->debugfs_dump_index; + u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *global = hw->debugfs_reg_array[DEBUGFS_GLOBAL]; @@ -2755,7 +2759,8 @@ static void hisi_sas_debugfs_snapshot_global_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[0][DEBUGFS_AXI].data; + int dump_index = hisi_hba->debugfs_dump_index; + u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *axi = hw->debugfs_reg_array[DEBUGFS_AXI]; @@ -2768,7 +2773,8 @@ static void hisi_sas_debugfs_snapshot_axi_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) { - u32 *databuf = hisi_hba->debugfs_regs[0][DEBUGFS_RAS].data; + int dump_index = hisi_hba->debugfs_dump_index; + u32 *databuf = hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS].data; const struct hisi_sas_hw *hw = hisi_hba->hw; const struct hisi_sas_debugfs_reg *ras = hw->debugfs_reg_array[DEBUGFS_RAS]; @@ -2781,8 +2787,9 @@ static void hisi_sas_debugfs_snapshot_ras_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) { - void *cachebuf = hisi_hba->debugfs_itct_cache[0].cache; - void *databuf = hisi_hba->debugfs_itct[0].itct; + int dump_index = hisi_hba->debugfs_dump_index; + void *cachebuf = hisi_hba->debugfs_itct_cache[dump_index].cache; + void *databuf = hisi_hba->debugfs_itct[dump_index].itct; struct hisi_sas_itct *itct; int i; @@ -2799,9 +2806,10 @@ static void hisi_sas_debugfs_snapshot_itct_reg(struct hisi_hba *hisi_hba) static void hisi_sas_debugfs_snapshot_iost_reg(struct hisi_hba *hisi_hba) { + int dump_index = hisi_hba->debugfs_dump_index; int max_command_entries = HISI_SAS_MAX_COMMANDS; - void *cachebuf = hisi_hba->debugfs_iost_cache[0].cache; - void *databuf = hisi_hba->debugfs_iost[0].iost; + void *cachebuf = hisi_hba->debugfs_iost_cache[dump_index].cache; + void *databuf = hisi_hba->debugfs_iost[dump_index].iost; struct hisi_sas_iost *iost; int i; @@ -3195,6 +3203,7 @@ static const struct file_operations hisi_sas_debugfs_itct_cache_fops = { static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) { u64 *debugfs_timestamp; + int dump_index = hisi_hba->debugfs_dump_index; struct dentry *dump_dentry; struct dentry *dentry; char name[256]; @@ -3202,17 +3211,18 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) int c; int d; - debugfs_timestamp = &hisi_hba->debugfs_timestamp; - /* Create dump dir inside device dir */ - dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); - hisi_hba->debugfs_dump_dentry = dump_dentry; + snprintf(name, 256, "%d", dump_index); + + dump_dentry = debugfs_create_dir(name, hisi_hba->debugfs_dump_dentry); + + debugfs_timestamp = &hisi_hba->debugfs_timestamp[dump_index]; debugfs_create_u64("timestamp", 0400, dump_dentry, debugfs_timestamp); debugfs_create_file("global", 0400, dump_dentry, - &hisi_hba->debugfs_regs[0][DEBUGFS_GLOBAL], - &hisi_sas_debugfs_global_fops); + &hisi_hba->debugfs_regs[dump_index][DEBUGFS_GLOBAL], + &hisi_sas_debugfs_global_fops); /* Create port dir and files */ dentry = debugfs_create_dir("port", dump_dentry); @@ -3220,7 +3230,7 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", p); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_port_reg[0][p], + &hisi_hba->debugfs_port_reg[dump_index][p], &hisi_sas_debugfs_port_fops); } @@ -3230,7 +3240,7 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", c); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_cq[0][c], + &hisi_hba->debugfs_cq[dump_index][c], &hisi_sas_debugfs_cq_fops); } @@ -3240,32 +3250,32 @@ static void hisi_sas_debugfs_create_files(struct hisi_hba *hisi_hba) snprintf(name, 256, "%d", d); debugfs_create_file(name, 0400, dentry, - &hisi_hba->debugfs_dq[0][d], + &hisi_hba->debugfs_dq[dump_index][d], &hisi_sas_debugfs_dq_fops); } debugfs_create_file("iost", 0400, dump_dentry, - &hisi_hba->debugfs_iost[0], + &hisi_hba->debugfs_iost[dump_index], &hisi_sas_debugfs_iost_fops); debugfs_create_file("iost_cache", 0400, dump_dentry, - &hisi_hba->debugfs_iost_cache[0], + &hisi_hba->debugfs_iost_cache[dump_index], &hisi_sas_debugfs_iost_cache_fops); debugfs_create_file("itct", 0400, dump_dentry, - &hisi_hba->debugfs_itct[0], + &hisi_hba->debugfs_itct[dump_index], &hisi_sas_debugfs_itct_fops); debugfs_create_file("itct_cache", 0400, dump_dentry, - &hisi_hba->debugfs_itct_cache[0], + &hisi_hba->debugfs_itct_cache[dump_index], &hisi_sas_debugfs_itct_cache_fops); debugfs_create_file("axi", 0400, dump_dentry, - &hisi_hba->debugfs_regs[0][DEBUGFS_AXI], + &hisi_hba->debugfs_regs[dump_index][DEBUGFS_AXI], &hisi_sas_debugfs_axi_fops); debugfs_create_file("ras", 0400, dump_dentry, - &hisi_hba->debugfs_regs[0][DEBUGFS_RAS], + &hisi_hba->debugfs_regs[dump_index][DEBUGFS_RAS], &hisi_sas_debugfs_ras_fops); return; @@ -3296,8 +3306,7 @@ static ssize_t hisi_sas_debugfs_trigger_dump_write(struct file *file, struct hisi_hba *hisi_hba = file->f_inode->i_private; char buf[8]; - /* A bit racy, but don't care too much since it's only debugfs */ - if (hisi_hba->debugfs_snapshot) + if (hisi_hba->debugfs_dump_index >= hisi_sas_debugfs_dump_count) return -EFAULT; if (count > 8) @@ -3699,15 +3708,20 @@ void hisi_sas_debugfs_work_handler(struct work_struct *work) { struct hisi_hba *hisi_hba = container_of(work, struct hisi_hba, debugfs_work); + int debugfs_dump_index = hisi_hba->debugfs_dump_index; + struct device *dev = hisi_hba->dev; u64 timestamp = local_clock(); - do_div(timestamp, NSEC_PER_MSEC); - hisi_hba->debugfs_timestamp = timestamp; - if (hisi_hba->debugfs_snapshot) + if (debugfs_dump_index >= hisi_sas_debugfs_dump_count) { + dev_warn(dev, "dump count exceeded!\n"); return; - hisi_hba->debugfs_snapshot = true; + } + + do_div(timestamp, NSEC_PER_MSEC); + hisi_hba->debugfs_timestamp[debugfs_dump_index] = timestamp; hisi_sas_debugfs_snapshot_regs(hisi_hba); + hisi_hba->debugfs_dump_index++; } EXPORT_SYMBOL_GPL(hisi_sas_debugfs_work_handler); -- cgit v1.2.3 From cabe7c10c97a0857a9fb14b6c772ab784947995d Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:24 +0800 Subject: scsi: hisi_sas: Delete the debugfs folder of hisi_sas when the probe fails Although if the debugfs initialization fails, we will delete the debugfs folder of hisi_sas, but we did not consider the scenario where debugfs was successfully initialized, but the probe failed for other reasons. We found out that hisi_sas folder is still remain after the probe failed. When probe fail, we should delete debugfs folder to avoid the above issue. Link: https://lore.kernel.org/r/1571926105-74636-18-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 1 + drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 + 2 files changed, 2 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 7fa9a5a51b80..669ad7463615 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -2686,6 +2686,7 @@ int hisi_sas_probe(struct platform_device *pdev, err_out_register_ha: scsi_remove_host(shost); err_out_ha: + hisi_sas_debugfs_exit(hisi_hba); hisi_sas_free(hisi_hba); scsi_host_put(shost); return rc; diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 19a8cfeb8f6e..e4da309009c0 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3266,6 +3266,7 @@ hisi_sas_v3_probe(struct pci_dev *pdev, const struct pci_device_id *id) err_out_register_ha: scsi_remove_host(shost); err_out_ha: + hisi_sas_debugfs_exit(hisi_hba); scsi_host_put(shost); err_out_regions: pci_release_regions(pdev); -- cgit v1.2.3 From f873b66119f2d6fc7b932a68df8d77a26357bab6 Mon Sep 17 00:00:00 2001 From: Luo Jiaxing Date: Thu, 24 Oct 2019 22:08:25 +0800 Subject: scsi: hisi_sas: Record the phy down event in debugfs The number of phy down reflects the quality of the link between SAS controller and disk. In order to allow the user to confirm the link quality of the system, we record the number of phy down for each phy. The user can check the current phy down count by reading the debugfs file corresponding to the specific phy, or clear the phy down count by writing 0 to the debugfs file. Link: https://lore.kernel.org/r/1571926105-74636-19-git-send-email-john.garry@huawei.com Signed-off-by: Luo Jiaxing Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas.h | 1 + drivers/scsi/hisi_sas/hisi_sas_main.c | 63 ++++++++++++++++++++++++++++++++++ drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 2 ++ 3 files changed, 66 insertions(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas.h b/drivers/scsi/hisi_sas/hisi_sas.h index 72823222e08f..233c73e01246 100644 --- a/drivers/scsi/hisi_sas/hisi_sas.h +++ b/drivers/scsi/hisi_sas/hisi_sas.h @@ -169,6 +169,7 @@ struct hisi_sas_phy { enum sas_linkrate minimum_linkrate; enum sas_linkrate maximum_linkrate; int enable; + atomic_t down_cnt; }; struct hisi_sas_port { diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 669ad7463615..18c95b33592b 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -3705,6 +3705,52 @@ static const struct file_operations hisi_sas_debugfs_bist_enable_ops = { .owner = THIS_MODULE, }; +static ssize_t hisi_sas_debugfs_phy_down_cnt_write(struct file *filp, + const char __user *buf, + size_t count, loff_t *ppos) +{ + struct seq_file *s = filp->private_data; + struct hisi_sas_phy *phy = s->private; + unsigned int set_val; + int res; + + res = kstrtouint_from_user(buf, count, 0, &set_val); + if (res) + return res; + + if (set_val > 0) + return -EINVAL; + + atomic_set(&phy->down_cnt, 0); + + return count; +} + +static int hisi_sas_debugfs_phy_down_cnt_show(struct seq_file *s, void *p) +{ + struct hisi_sas_phy *phy = s->private; + + seq_printf(s, "%d\n", atomic_read(&phy->down_cnt)); + + return 0; +} + +static int hisi_sas_debugfs_phy_down_cnt_open(struct inode *inode, + struct file *filp) +{ + return single_open(filp, hisi_sas_debugfs_phy_down_cnt_show, + inode->i_private); +} + +static const struct file_operations hisi_sas_debugfs_phy_down_cnt_ops = { + .open = hisi_sas_debugfs_phy_down_cnt_open, + .read = seq_read, + .write = hisi_sas_debugfs_phy_down_cnt_write, + .llseek = seq_lseek, + .release = single_release, + .owner = THIS_MODULE, +}; + void hisi_sas_debugfs_work_handler(struct work_struct *work) { struct hisi_hba *hisi_hba = @@ -3839,6 +3885,21 @@ fail: return -ENOMEM; } +static void hisi_sas_debugfs_phy_down_cnt_init(struct hisi_hba *hisi_hba) +{ + struct dentry *dir = debugfs_create_dir("phy_down_cnt", + hisi_hba->debugfs_dir); + char name[16]; + int phy_no; + + for (phy_no = 0; phy_no < hisi_hba->n_phy; phy_no++) { + snprintf(name, 16, "%d", phy_no); + debugfs_create_file(name, 0600, dir, + &hisi_hba->phy[phy_no], + &hisi_sas_debugfs_phy_down_cnt_ops); + } +} + static void hisi_sas_debugfs_bist_init(struct hisi_hba *hisi_hba) { hisi_hba->debugfs_bist_dentry = @@ -3885,6 +3946,8 @@ void hisi_sas_debugfs_init(struct hisi_hba *hisi_hba) hisi_hba->debugfs_dump_dentry = debugfs_create_dir("dump", hisi_hba->debugfs_dir); + hisi_sas_debugfs_phy_down_cnt_init(hisi_hba); + for (i = 0; i < hisi_sas_debugfs_dump_count; i++) { if (hisi_sas_debugfs_alloc(hisi_hba, i)) { debugfs_remove_recursive(hisi_hba->debugfs_dir); diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index e4da309009c0..2ae7070db41a 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -1549,6 +1549,8 @@ static irqreturn_t phy_down_v3_hw(int phy_no, struct hisi_hba *hisi_hba) u32 phy_state, sl_ctrl, txid_auto; struct device *dev = hisi_hba->dev; + atomic_inc(&phy->down_cnt); + del_timer(&phy->timer); hisi_sas_phy_write32(hisi_hba, phy_no, PHYCTRL_NOT_RDY_MSK, 1); -- cgit v1.2.3 From 9e2edb41c3d4cab6da0eedcc07ae04758af62ab8 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 25 Oct 2019 11:25:30 -0700 Subject: scsi: lpfc: fix build error of lpfc_debugfs.c for vfree/vmalloc lpfc_debufs.c was missing include of vmalloc.h when compiled on PPC. Add missing header. Link: https://lore.kernel.org/r/20191025182530.26653-1-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_debugfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index ab124f7d50d6..6c8effcfc8ae 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include -- cgit v1.2.3 From 5792a0e81678da41f05bb724ebd20f134604fa15 Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 25 Oct 2019 11:43:42 -0700 Subject: scsi: lpfc: fix spelling error in MAGIC_NUMER_xxx convert MAGIC_NUMER_xxx to MAGIC_NUMBER_xxx Link: https://lore.kernel.org/r/20191025184342.6623-1-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Reviewed-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 4 ++-- drivers/scsi/lpfc/lpfc_init.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index d40bfe5aa21f..9daa2b494b5c 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -4822,8 +4822,8 @@ union lpfc_wqe128 { struct send_frame_wqe send_frame; }; -#define MAGIC_NUMER_G6 0xFEAA0003 -#define MAGIC_NUMER_G7 0xFEAA0005 +#define MAGIC_NUMBER_G6 0xFEAA0003 +#define MAGIC_NUMBER_G7 0xFEAA0005 struct lpfc_grp_hdr { uint32_t size; diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 686677dd52a4..9536ad3cc4ee 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -12418,9 +12418,9 @@ lpfc_log_write_firmware_error(struct lpfc_hba *phba, uint32_t offset, */ if (offset == ADD_STATUS_FW_NOT_SUPPORTED || (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G6_FC && - magic_number != MAGIC_NUMER_G6) || + magic_number != MAGIC_NUMBER_G6) || (phba->pcidev->device == PCI_DEVICE_ID_LANCER_G7_FC && - magic_number != MAGIC_NUMER_G7)) { + magic_number != MAGIC_NUMBER_G7)) { lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3030 This firmware version is not supported on" " this HBA model. Device:%x Magic:%x Type:%x " -- cgit v1.2.3 From c3e5aac3e2f501ad4fcb03fed0e32a6f009faea2 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Sun, 27 Oct 2019 01:17:17 +0530 Subject: scsi: lpfc: Fix NULL check before mempool_destroy is not needed mempool_destroy has taken null pointer check into account. Remove the redundant check. Link: https://lore.kernel.org/r/20191026194712.GA22249@saurav Signed-off-by: Saurav Girepunje Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 9536ad3cc4ee..ec9dbc042a41 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -13464,8 +13464,7 @@ lpfc_sli4_oas_verify(struct lpfc_hba *phba) phba->cfg_fof = 1; } else { phba->cfg_fof = 0; - if (phba->device_data_mem_pool) - mempool_destroy(phba->device_data_mem_pool); + mempool_destroy(phba->device_data_mem_pool); phba->device_data_mem_pool = NULL; } -- cgit v1.2.3 From 7b10db555257d1248398643a23e10cf36b50d516 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Mon, 28 Oct 2019 21:25:56 +0800 Subject: scsi: lpfc: Make lpfc_debugfs_ras_log_data static Fix sparse warning: drivers/scsi/lpfc/lpfc_debugfs.c:2083:1: warning: symbol 'lpfc_debugfs_ras_log_data' was not declared. Should it be static? Link: https://lore.kernel.org/r/20191028132556.16272-1-yuehaibing@huawei.com Reported-by: Hulk Robot Signed-off-by: YueHaibing Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_debugfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c index 6c8effcfc8ae..2e6a68d9ea4f 100644 --- a/drivers/scsi/lpfc/lpfc_debugfs.c +++ b/drivers/scsi/lpfc/lpfc_debugfs.c @@ -2079,8 +2079,8 @@ lpfc_debugfs_lockstat_write(struct file *file, const char __user *buf, } #endif -int -lpfc_debugfs_ras_log_data(struct lpfc_hba *phba, char *buffer, int size) +static int lpfc_debugfs_ras_log_data(struct lpfc_hba *phba, + char *buffer, int size) { int copied = 0; struct lpfc_dmabuf *dmabuf, *next; -- cgit v1.2.3 From 92953c6e0aa77d4febcca6dd691e8192910c8a28 Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:43 +0200 Subject: scsi: zfcp: signal incomplete or error for sync exchange config/port data Adds a new FSF-Request status flag (ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE) that signal that the data received using Exchange Config Data or Exchange Port Data was incomplete. This new flags is set in the respective handlers during the response path. With this patch, only the synchronous FSF-functions for each command got support for the new flag, otherwise it is transparent. Together with this new flag and already existing status flags the synchronous FSF-functions are extended to now detect whether the received data is complete, incomplete or completely invalid (this includes cases where a command ran into a timeout). This is now signaled back to the caller, where previously only failures on the request path would result in a bad return-code. For complete data the return-code remains 0. For incomplete data a new return-code -EAGAIN is added to the function-interface. For completely invalid data the already existing return-code -EIO is reused - formerly this was used to signal failures on the request path. Existing callers of the FSF-functions are adjusted so that they behave as before for return-code 0 and -EAGAIN, to not change the user-interface. As -EIO existed all along, it was already exposed to the user - and needed handling - and will now also be exposed in this new special case. Link: https://lore.kernel.org/r/e14f0702fa2b00a4d1f37c7981a13f2dd1ea2c83.1572018130.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_def.h | 1 + drivers/s390/scsi/zfcp_fsf.c | 46 +++++++++++++++++++++++++++++++++++++----- drivers/s390/scsi/zfcp_scsi.c | 4 ++-- drivers/s390/scsi/zfcp_sysfs.c | 4 ++-- 4 files changed, 46 insertions(+), 9 deletions(-) diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index 87d2f47a6990..f5acdb67442e 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -86,6 +86,7 @@ #define ZFCP_STATUS_FSFREQ_ABORTNOTNEEDED 0x00000080 #define ZFCP_STATUS_FSFREQ_TMFUNCFAILED 0x00000200 #define ZFCP_STATUS_FSFREQ_DISMISSED 0x00001000 +#define ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE 0x00020000 /************************* STRUCTURE DEFINITIONS *****************************/ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index cf63916814cc..d8f0e446fe13 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -585,6 +585,8 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) &adapter->status); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE; + fc_host_node_name(shost) = 0; fc_host_port_name(shost) = 0; fc_host_port_id(shost) = 0; @@ -663,6 +665,8 @@ static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) zfcp_fsf_exchange_port_evaluate(req); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE; + zfcp_fsf_exchange_port_evaluate(req); zfcp_fsf_link_down_info_eval(req, &qtcb->header.fsf_status_qual.link_down_info); @@ -1278,6 +1282,19 @@ out: return retval; } + +/** + * zfcp_fsf_exchange_config_data_sync() - Request information about FCP channel. + * @qdio: pointer to the QDIO-Queue to use for sending the command. + * @data: pointer to the QTCB-Bottom for storing the result of the command, + * might be %NULL. + * + * Returns: + * * 0 - Exchange Config Data was successful, @data is complete + * * -EIO - Exchange Config Data was not successful, @data is invalid + * * -EAGAIN - @data contains incomplete data + * * -ENOMEM - Some memory allocation failed along the way + */ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_config *data) { @@ -1309,9 +1326,16 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, zfcp_fsf_start_timer(req, ZFCP_FSF_REQUEST_TIMEOUT); retval = zfcp_fsf_req_send(req); spin_unlock_irq(&qdio->req_q_lock); + if (!retval) { /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */ wait_for_completion(&req->completion); + + if (req->status & + (ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_DISMISSED)) + retval = -EIO; + else if (req->status & ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE) + retval = -EAGAIN; } zfcp_fsf_req_free(req); @@ -1369,10 +1393,17 @@ out: } /** - * zfcp_fsf_exchange_port_data_sync - request information about local port - * @qdio: pointer to struct zfcp_qdio - * @data: pointer to struct fsf_qtcb_bottom_port - * Returns: 0 on success, error otherwise + * zfcp_fsf_exchange_port_data_sync() - Request information about local port. + * @qdio: pointer to the QDIO-Queue to use for sending the command. + * @data: pointer to the QTCB-Bottom for storing the result of the command, + * might be %NULL. + * + * Returns: + * * 0 - Exchange Port Data was successful, @data is complete + * * -EIO - Exchange Port Data was not successful, @data is invalid + * * -EAGAIN - @data contains incomplete data + * * -ENOMEM - Some memory allocation failed along the way + * * -EOPNOTSUPP - This operation is not supported */ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, struct fsf_qtcb_bottom_port *data) @@ -1408,10 +1439,15 @@ int zfcp_fsf_exchange_port_data_sync(struct zfcp_qdio *qdio, if (!retval) { /* NOTE: ONLY TOUCH SYNC req AGAIN ON req->completion. */ wait_for_completion(&req->completion); + + if (req->status & + (ZFCP_STATUS_FSFREQ_ERROR | ZFCP_STATUS_FSFREQ_DISMISSED)) + retval = -EIO; + else if (req->status & ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE) + retval = -EAGAIN; } zfcp_fsf_req_free(req); - return retval; out_unlock: diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c index e9ded2befa0d..3910d529c15a 100644 --- a/drivers/s390/scsi/zfcp_scsi.c +++ b/drivers/s390/scsi/zfcp_scsi.c @@ -605,7 +605,7 @@ zfcp_scsi_get_fc_host_stats(struct Scsi_Host *host) return NULL; ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); - if (ret) { + if (ret != 0 && ret != -EAGAIN) { kfree(data); return NULL; } @@ -634,7 +634,7 @@ static void zfcp_scsi_reset_fc_host_stats(struct Scsi_Host *shost) return; ret = zfcp_fsf_exchange_port_data_sync(adapter->qdio, data); - if (ret) + if (ret != 0 && ret != -EAGAIN) kfree(data); else { adapter->stats_reset = jiffies/HZ; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index af197e2b3e69..90d851d49410 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -577,7 +577,7 @@ static ssize_t zfcp_sysfs_adapter_util_show(struct device *dev, return -ENOMEM; retval = zfcp_fsf_exchange_port_data_sync(adapter->qdio, qtcb_port); - if (!retval) + if (retval == 0 || retval == -EAGAIN) retval = sprintf(buf, "%u %u %u\n", qtcb_port->cp_util, qtcb_port->cb_util, qtcb_port->a_util); kfree(qtcb_port); @@ -603,7 +603,7 @@ static int zfcp_sysfs_adapter_ex_config(struct device *dev, return -ENOMEM; retval = zfcp_fsf_exchange_config_data_sync(adapter->qdio, qtcb_config); - if (!retval) + if (retval == 0 || retval == -EAGAIN) *stat_inf = qtcb_config->stat_info; kfree(qtcb_config); -- cgit v1.2.3 From 7e418833e68948cb9ed15262889173b7db2960cb Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:44 +0200 Subject: scsi: zfcp: diagnostics buffer caching and use for exchange port data The FCP channel exposes two central interfaces to receive information about the local FCP-Adapter/-Port: Exchange Port and Exchange Config Data. Using these commands can negatively impact the adapter if we allow them to be sent at a very high rate. The later parts of this patchset will introduce new user-interfaces to receive more diagnostics from the adapter. To prevent any negative impact from using those, this patch adds a simple caching-mechanism that will prevent a malicious/faulty userspace-application from generating an abnormal high amount of Exchange Port/Config Data traffic. Relevant diagnostic data that is received via Exchange Config/Port Data is cached in buffers associated with the corresponding adapter-struct. Each buffer is associated with a timestamp that signals how old the data is, and, added via a following patch in this series, lets userspace-interfaces determine when the data is too old and needs to be updated. Buffer-updates are made during the normal response path of the corresponding command. With this patch only the output of the Exchange Port Data command is captured. Link: https://lore.kernel.org/r/054ca020ce0a53dc0d9176428bea373898944e6a.1572018130.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/Makefile | 2 +- drivers/s390/scsi/zfcp_aux.c | 8 +++- drivers/s390/scsi/zfcp_def.h | 3 +- drivers/s390/scsi/zfcp_diag.c | 93 +++++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_diag.h | 60 ++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_fsf.c | 12 ++++++ 6 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 drivers/s390/scsi/zfcp_diag.c create mode 100644 drivers/s390/scsi/zfcp_diag.h diff --git a/drivers/s390/scsi/Makefile b/drivers/s390/scsi/Makefile index 9dda431ec8f3..352056eb0dd1 100644 --- a/drivers/s390/scsi/Makefile +++ b/drivers/s390/scsi/Makefile @@ -5,6 +5,6 @@ zfcp-objs := zfcp_aux.o zfcp_ccw.o zfcp_dbf.o zfcp_erp.o \ zfcp_fc.o zfcp_fsf.o zfcp_qdio.o zfcp_scsi.o zfcp_sysfs.o \ - zfcp_unit.o + zfcp_unit.o zfcp_diag.o obj-$(CONFIG_ZFCP) += zfcp.o diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index e390f8c6d5f3..a19189d7b3f3 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -4,7 +4,7 @@ * * Module interface and handling of zfcp data structures. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ /* @@ -25,6 +25,7 @@ * Martin Petermann * Sven Schuetz * Steffen Maier + * Benjamin Block */ #define KMSG_COMPONENT "zfcp" @@ -36,6 +37,7 @@ #include "zfcp_ext.h" #include "zfcp_fc.h" #include "zfcp_reqlist.h" +#include "zfcp_diag.h" #define ZFCP_BUS_ID_SIZE 20 @@ -356,6 +358,9 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) adapter->erp_action.adapter = adapter; + if (zfcp_diag_adapter_setup(adapter)) + goto failed; + if (zfcp_qdio_setup(adapter)) goto failed; @@ -449,6 +454,7 @@ void zfcp_adapter_release(struct kref *ref) dev_set_drvdata(&adapter->ccw_device->dev, NULL); zfcp_fc_gs_destroy(adapter); zfcp_free_low_mem_buffers(adapter); + zfcp_diag_adapter_free(adapter); kfree(adapter->req_list); kfree(adapter->fc_stats); kfree(adapter->stats_reset_data); diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h index f5acdb67442e..8cc0eefe4ccc 100644 --- a/drivers/s390/scsi/zfcp_def.h +++ b/drivers/s390/scsi/zfcp_def.h @@ -4,7 +4,7 @@ * * Global definitions for the zfcp device driver. * - * Copyright IBM Corp. 2002, 2017 + * Copyright IBM Corp. 2002, 2018 */ #ifndef ZFCP_DEF_H @@ -198,6 +198,7 @@ struct zfcp_adapter { struct device_dma_parameters dma_parms; struct zfcp_fc_events events; unsigned long next_port_scan; + struct zfcp_diag_adapter *diagnostics; }; struct zfcp_port { diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c new file mode 100644 index 000000000000..fa1b25f3ec3c --- /dev/null +++ b/drivers/s390/scsi/zfcp_diag.c @@ -0,0 +1,93 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * zfcp device driver + * + * Functions to handle diagnostics. + * + * Copyright IBM Corp. 2018 + */ + +#include +#include +#include +#include +#include + +#include "zfcp_diag.h" +#include "zfcp_ext.h" +#include "zfcp_def.h" + +/* Max age of data in a diagnostics buffer before it needs a refresh (in ms). */ +#define ZFCP_DIAG_MAX_AGE (5 * 1000) + +/** + * zfcp_diag_adapter_setup() - Setup storage for adapter diagnostics. + * @adapter: the adapter to setup diagnostics for. + * + * Creates the data-structures to store the diagnostics for an adapter. This + * overwrites whatever was stored before at &zfcp_adapter->diagnostics! + * + * Return: + * * 0 - Everyting is OK + * * -ENOMEM - Could not allocate all/parts of the data-structures; + * &zfcp_adapter->diagnostics remains unchanged + */ +int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter) +{ + struct zfcp_diag_adapter *diag; + struct zfcp_diag_header *hdr; + + diag = kzalloc(sizeof(*diag), GFP_KERNEL); + if (diag == NULL) + return -ENOMEM; + + /* setup header for port_data */ + hdr = &diag->port_data.header; + + spin_lock_init(&hdr->access_lock); + hdr->buffer = &diag->port_data.data; + hdr->buffer_size = sizeof(diag->port_data.data); + /* set the timestamp so that the first test on age will always fail */ + hdr->timestamp = jiffies - msecs_to_jiffies(ZFCP_DIAG_MAX_AGE); + + adapter->diagnostics = diag; + return 0; +} + +/** + * zfcp_diag_adapter_free() - Frees all adapter diagnostics allocations. + * @adapter: the adapter whose diagnostic structures should be freed. + * + * Frees all data-structures in the given adapter that store diagnostics + * information. Can savely be called with partially setup diagnostics. + */ +void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter) +{ + kfree(adapter->diagnostics); + adapter->diagnostics = NULL; +} + +/** + * zfcp_diag_update_xdata() - Update a diagnostics buffer. + * @hdr: the meta data to update. + * @data: data to use for the update. + * @incomplete: flag stating whether the data in @data is incomplete. + */ +void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr, + const void *const data, const bool incomplete) +{ + const unsigned long capture_timestamp = jiffies; + unsigned long flags; + + spin_lock_irqsave(&hdr->access_lock, flags); + + /* make sure we never go into the past with an update */ + if (!time_after_eq(capture_timestamp, hdr->timestamp)) + goto out; + + hdr->timestamp = capture_timestamp; + hdr->incomplete = incomplete; + memcpy(hdr->buffer, data, hdr->buffer_size); +out: + spin_unlock_irqrestore(&hdr->access_lock, flags); +} diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h new file mode 100644 index 000000000000..2a933326b6e4 --- /dev/null +++ b/drivers/s390/scsi/zfcp_diag.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * zfcp device driver + * + * Definitions for handling diagnostics in the the zfcp device driver. + * + * Copyright IBM Corp. 2018 + */ + +#ifndef ZFCP_DIAG_H +#define ZFCP_DIAG_H + +#include + +#include "zfcp_fsf.h" +#include "zfcp_def.h" + +/** + * struct zfcp_diag_header - general part of a diagnostic buffer. + * @access_lock: lock protecting all the data in this buffer. + * @updating: flag showing that an update for this buffer is currently running. + * @incomplete: flag showing that the data in @buffer is incomplete. + * @timestamp: time in jiffies when the data of this buffer was last captured. + * @buffer: implementation-depending data of this buffer + * @buffer_size: size of @buffer + */ +struct zfcp_diag_header { + spinlock_t access_lock; + + /* Flags */ + u64 updating :1; + u64 incomplete :1; + + unsigned long timestamp; + + void *buffer; + size_t buffer_size; +}; + +/** + * struct zfcp_diag_adapter - central storage for all diagnostics concerning an + * adapter. + * @port_data: data retrieved using exchange port data. + * @port_data.header: header with metadata for the cache in @port_data.data. + * @port_data.data: cached QTCB Bottom of command exchange port data. + */ +struct zfcp_diag_adapter { + struct { + struct zfcp_diag_header header; + struct fsf_qtcb_bottom_port data; + } port_data; +}; + +int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter); +void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter); + +void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr, + const void *const data, const bool incomplete); + +#endif /* ZFCP_DIAG_H */ diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index d8f0e446fe13..883bbfd67a62 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "zfcp_dbf.h" #include "zfcp_qdio.h" #include "zfcp_reqlist.h" +#include "zfcp_diag.h" /* timeout for FSF requests sent during scsi_eh: abort or FCP TMF */ #define ZFCP_FSF_SCSI_ER_TIMEOUT (10*HZ) @@ -655,16 +657,26 @@ static void zfcp_fsf_exchange_port_evaluate(struct zfcp_fsf_req *req) static void zfcp_fsf_exchange_port_data_handler(struct zfcp_fsf_req *req) { + struct zfcp_diag_header *const diag_hdr = + &req->adapter->diagnostics->port_data.header; struct fsf_qtcb *qtcb = req->qtcb; + struct fsf_qtcb_bottom_port *bottom = &qtcb->bottom.port; if (req->status & ZFCP_STATUS_FSFREQ_ERROR) return; switch (qtcb->header.fsf_status) { case FSF_GOOD: + /* + * usually we wait with an update till the cache is too old, + * but because we have the data available, update it anyway + */ + zfcp_diag_update_xdata(diag_hdr, bottom, false); + zfcp_fsf_exchange_port_evaluate(req); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + zfcp_diag_update_xdata(diag_hdr, bottom, true); req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE; zfcp_fsf_exchange_port_evaluate(req); -- cgit v1.2.3 From 088210233e6fc039fd2c0bfe44b06bb94328d09e Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:45 +0200 Subject: scsi: zfcp: add diagnostics buffer for exchange config data In the same vein as the previous patch, add diagnostic data capture for the Exchange Config Data command. Link: https://lore.kernel.org/r/7d8ac0a6cad403fa8f8b888693476a84e80a277b.1572018131.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_diag.c | 14 ++++++++++++-- drivers/s390/scsi/zfcp_diag.h | 7 +++++++ drivers/s390/scsi/zfcp_fsf.c | 9 +++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c index fa1b25f3ec3c..d7d2db85b32e 100644 --- a/drivers/s390/scsi/zfcp_diag.c +++ b/drivers/s390/scsi/zfcp_diag.c @@ -34,6 +34,9 @@ */ int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter) { + /* set the timestamp so that the first test on age will always fail */ + const unsigned long initial_timestamp = + jiffies - msecs_to_jiffies(ZFCP_DIAG_MAX_AGE); struct zfcp_diag_adapter *diag; struct zfcp_diag_header *hdr; @@ -47,8 +50,15 @@ int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter) spin_lock_init(&hdr->access_lock); hdr->buffer = &diag->port_data.data; hdr->buffer_size = sizeof(diag->port_data.data); - /* set the timestamp so that the first test on age will always fail */ - hdr->timestamp = jiffies - msecs_to_jiffies(ZFCP_DIAG_MAX_AGE); + hdr->timestamp = initial_timestamp; + + /* setup header for config_data */ + hdr = &diag->config_data.header; + + spin_lock_init(&hdr->access_lock); + hdr->buffer = &diag->config_data.data; + hdr->buffer_size = sizeof(diag->config_data.data); + hdr->timestamp = initial_timestamp; adapter->diagnostics = diag; return 0; diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h index 2a933326b6e4..a3eb21cc201d 100644 --- a/drivers/s390/scsi/zfcp_diag.h +++ b/drivers/s390/scsi/zfcp_diag.h @@ -43,12 +43,19 @@ struct zfcp_diag_header { * @port_data: data retrieved using exchange port data. * @port_data.header: header with metadata for the cache in @port_data.data. * @port_data.data: cached QTCB Bottom of command exchange port data. + * @config_data: data retrieved using exchange config data. + * @config_data.header: header with metadata for the cache in @config_data.data. + * @config_data.data: cached QTCB Bottom of command exchange config data. */ struct zfcp_diag_adapter { struct { struct zfcp_diag_header header; struct fsf_qtcb_bottom_port data; } port_data; + struct { + struct zfcp_diag_header header; + struct fsf_qtcb_bottom_config data; + } config_data; }; int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter); diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 883bbfd67a62..0fff060de5ac 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -556,6 +556,8 @@ static int zfcp_fsf_exchange_config_evaluate(struct zfcp_fsf_req *req) static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) { struct zfcp_adapter *adapter = req->adapter; + struct zfcp_diag_header *const diag_hdr = + &adapter->diagnostics->config_data.header; struct fsf_qtcb *qtcb = req->qtcb; struct fsf_qtcb_bottom_config *bottom = &qtcb->bottom.config; struct Scsi_Host *shost = adapter->scsi_host; @@ -572,6 +574,12 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) switch (qtcb->header.fsf_status) { case FSF_GOOD: + /* + * usually we wait with an update till the cache is too old, + * but because we have the data available, update it anyway + */ + zfcp_diag_update_xdata(diag_hdr, bottom, false); + if (zfcp_fsf_exchange_config_evaluate(req)) return; @@ -587,6 +595,7 @@ static void zfcp_fsf_exchange_config_data_handler(struct zfcp_fsf_req *req) &adapter->status); break; case FSF_EXCHANGE_CONFIG_DATA_INCOMPLETE: + zfcp_diag_update_xdata(diag_hdr, bottom, true); req->status |= ZFCP_STATUS_FSFREQ_XDATAINCOMPLETE; fc_host_node_name(shost) = 0; -- cgit v1.2.3 From a10a61e807b0a226b78e2041843cbf0521bd0c35 Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:46 +0200 Subject: scsi: zfcp: support retrieval of SFP Data via Exchange Port Data A new FCP channel feature allows us to read the diagnostics from our local SFP transceivers. To make use of that add a flag (FSF_FEATURE_REQUEST_SFP_DATA) to the feature-set we request from the FCP channel. Whether the channel actually implements this can be determined via an other new flag (FSF_FEATURE_REPORT_SFP_DATA), that is set in the adapter_features field of the adapter structure after Exchange Config Data finished. Also add the corresponding definitions in the QTCB Bottom for Exchange Port Data. These new definitions are only valid, if FSF_FEATURE_REPORT_SFP_DATA is set. Link: https://lore.kernel.org/r/ee1eba4de71eb06b4d82207ad4f428429346156f.1572018132.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_fsf.c | 6 ++++-- drivers/s390/scsi/zfcp_fsf.h | 21 ++++++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c index 0fff060de5ac..223a805f0b0b 100644 --- a/drivers/s390/scsi/zfcp_fsf.c +++ b/drivers/s390/scsi/zfcp_fsf.c @@ -1286,7 +1286,8 @@ int zfcp_fsf_exchange_config_data(struct zfcp_erp_action *erp_action) req->qtcb->bottom.config.feature_selection = FSF_FEATURE_NOTIFICATION_LOST | - FSF_FEATURE_UPDATE_ALERT; + FSF_FEATURE_UPDATE_ALERT | + FSF_FEATURE_REQUEST_SFP_DATA; req->erp_action = erp_action; req->handler = zfcp_fsf_exchange_config_data_handler; erp_action->fsf_req_id = req->req_id; @@ -1339,7 +1340,8 @@ int zfcp_fsf_exchange_config_data_sync(struct zfcp_qdio *qdio, req->qtcb->bottom.config.feature_selection = FSF_FEATURE_NOTIFICATION_LOST | - FSF_FEATURE_UPDATE_ALERT; + FSF_FEATURE_UPDATE_ALERT | + FSF_FEATURE_REQUEST_SFP_DATA; if (data) req->data = data; diff --git a/drivers/s390/scsi/zfcp_fsf.h b/drivers/s390/scsi/zfcp_fsf.h index 2c658b66318c..2b1e4da1944f 100644 --- a/drivers/s390/scsi/zfcp_fsf.h +++ b/drivers/s390/scsi/zfcp_fsf.h @@ -163,6 +163,8 @@ #define FSF_FEATURE_ELS_CT_CHAINED_SBALS 0x00000020 #define FSF_FEATURE_UPDATE_ALERT 0x00000100 #define FSF_FEATURE_MEASUREMENT_DATA 0x00000200 +#define FSF_FEATURE_REQUEST_SFP_DATA 0x00000200 +#define FSF_FEATURE_REPORT_SFP_DATA 0x00000800 #define FSF_FEATURE_DIF_PROT_TYPE1 0x00010000 #define FSF_FEATURE_DIX_PROT_TCPIP 0x00020000 @@ -407,7 +409,24 @@ struct fsf_qtcb_bottom_port { u8 cp_util; u8 cb_util; u8 a_util; - u8 res2[253]; + u8 res2; + u16 temperature; + u16 vcc; + u16 tx_bias; + u16 tx_power; + u16 rx_power; + union { + u16 raw; + struct { + u16 fec_active :1; + u16:7; + u16 connector_type :2; + u16 sfp_invalid :1; + u16 optical_port :1; + u16 port_tx_type :4; + }; + } sfp_flags; + u8 res3[240]; } __attribute__ ((packed)); union fsf_qtcb_bottom { -- cgit v1.2.3 From 6028f7c4cd87cac13481255d7e35dd2c9207ecae Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:47 +0200 Subject: scsi: zfcp: introduce sysfs interface for diagnostics of local SFP transceiver MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This adds an interface to read the diagnostics of the local SFP transceiver of an FCP-Channel from userspace. This comes in the form of new sysfs entries that are attached to the CCW device representing the FCP device. Each type of data gets its own sysfs entry; the whole collection of entries is pooled into a new child-directory of the CCW device node: "diagnostics". Adds sysfs entries for: * sfp_invalid: boolean value evaluating to whether the following 5 fields are invalid; {0, 1}; 1 - invalid * temperature: transceiver temp.; unit 1/256°C; range [-128°C, +128°C] * vcc: supply voltage; unit 100μV; range [0, 6.55V] * tx_bias: transmitter laser bias current; unit 2μA; range [0, 131mA] * tx_power: coupled TX output power; unit 0.1μW; range [0, 6.5mW] * rx_power: received optical power; unit 0.1μW; range [0, 6.5mW] * optical_port: boolean value evaluating to whether the FCP-Channel has an optical port; {0, 1}; 1 - optical * fec_active: boolean value evaluating to whether 16G FEC is active; {0, 1}; 1 - active * port_tx_type: nibble describing the port type; {0, 1, 2, 3}; 0 - unknown, 1 - short wave, 2 - long wave LC 1310nm, 3 - long wave LL 1550nm * connector_type: two bits describing the connector type; {0, 1}; 0 - unknown, 1 - SFP+ This is only supported if the FCP-Channel in turn supports reporting the SFP Diagnostic Data, otherwise read() on these new entries will return EOPNOTSUPP (this affects only adapters older than FICON Express8S, on Mainframe generations older than z14). Other possible errors for read() include ENOLINK, ENODEV and ENOMEM. With this patch the userspace-interface will only read data stored in the corresponding "diagnostic buffer" (that was stored during completion of an previous Exchange Port Data command). Implicit updating will follow later in this series. Link: https://lore.kernel.org/r/1f9cce7c829c881e7d71a3f10c5b57f3dd84ab32.1572018132.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_aux.c | 4 +++ drivers/s390/scsi/zfcp_diag.c | 42 +++++++++++++++++++++++++ drivers/s390/scsi/zfcp_diag.h | 18 +++++++++++ drivers/s390/scsi/zfcp_ext.h | 1 + drivers/s390/scsi/zfcp_sysfs.c | 71 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+) diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c index a19189d7b3f3..09ec846fe01d 100644 --- a/drivers/s390/scsi/zfcp_aux.c +++ b/drivers/s390/scsi/zfcp_aux.c @@ -407,6 +407,9 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device) &zfcp_sysfs_adapter_attrs)) goto failed; + if (zfcp_diag_sysfs_setup(adapter)) + goto failed; + /* report size limit per scatter-gather segment */ adapter->ccw_device->dev.dma_parms = &adapter->dma_parms; @@ -431,6 +434,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter) zfcp_fc_wka_ports_force_offline(adapter->gs); zfcp_scsi_adapter_unregister(adapter); + zfcp_diag_sysfs_destroy(adapter); sysfs_remove_group(&cdev->dev.kobj, &zfcp_sysfs_adapter_attrs); zfcp_erp_thread_kill(adapter); diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c index d7d2db85b32e..8df3ace6135d 100644 --- a/drivers/s390/scsi/zfcp_diag.c +++ b/drivers/s390/scsi/zfcp_diag.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -77,6 +79,46 @@ void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter) adapter->diagnostics = NULL; } +/** + * zfcp_diag_sysfs_setup() - Setup the sysfs-group for adapter-diagnostics. + * @adapter: target adapter to which the group should be added. + * + * Return: 0 on success; Something else otherwise (see sysfs_create_group()). + */ +int zfcp_diag_sysfs_setup(struct zfcp_adapter *const adapter) +{ + int rc = sysfs_create_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_diag_attr_group); + if (rc == 0) + adapter->diagnostics->sysfs_established = 1; + + return rc; +} + +/** + * zfcp_diag_sysfs_destroy() - Remove the sysfs-group for adapter-diagnostics. + * @adapter: target adapter from which the group should be removed. + */ +void zfcp_diag_sysfs_destroy(struct zfcp_adapter *const adapter) +{ + if (adapter->diagnostics == NULL || + !adapter->diagnostics->sysfs_established) + return; + + /* + * We need this state-handling so we can prevent warnings being printed + * on the kernel-console in case we have to abort a halfway done + * zfcp_adapter_enqueue(), in which the sysfs-group was not yet + * established. sysfs_remove_group() does this checking as well, but + * still prints a warning in case we try to remove a group that has not + * been established before + */ + adapter->diagnostics->sysfs_established = 0; + sysfs_remove_group(&adapter->ccw_device->dev.kobj, + &zfcp_sysfs_diag_attr_group); +} + + /** * zfcp_diag_update_xdata() - Update a diagnostics buffer. * @hdr: the meta data to update. diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h index a3eb21cc201d..2deebccda17d 100644 --- a/drivers/s390/scsi/zfcp_diag.h +++ b/drivers/s390/scsi/zfcp_diag.h @@ -40,6 +40,8 @@ struct zfcp_diag_header { /** * struct zfcp_diag_adapter - central storage for all diagnostics concerning an * adapter. + * @sysfs_established: flag showing that the associated sysfs-group was created + * during run of zfcp_adapter_enqueue(). * @port_data: data retrieved using exchange port data. * @port_data.header: header with metadata for the cache in @port_data.data. * @port_data.data: cached QTCB Bottom of command exchange port data. @@ -48,6 +50,8 @@ struct zfcp_diag_header { * @config_data.data: cached QTCB Bottom of command exchange config data. */ struct zfcp_diag_adapter { + u64 sysfs_established :1; + struct { struct zfcp_diag_header header; struct fsf_qtcb_bottom_port data; @@ -61,7 +65,21 @@ struct zfcp_diag_adapter { int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter); void zfcp_diag_adapter_free(struct zfcp_adapter *const adapter); +int zfcp_diag_sysfs_setup(struct zfcp_adapter *const adapter); +void zfcp_diag_sysfs_destroy(struct zfcp_adapter *const adapter); + void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr, const void *const data, const bool incomplete); +/** + * zfcp_diag_support_sfp() - Return %true if the @adapter supports reporting + * SFP Data. + * @adapter: adapter to test the availability of SFP Data reporting for. + */ +static inline bool +zfcp_diag_support_sfp(const struct zfcp_adapter *const adapter) +{ + return !!(adapter->adapter_features & FSF_FEATURE_REPORT_SFP_DATA); +} + #endif /* ZFCP_DIAG_H */ diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h index 31e8a7240fd7..c8556787cfdc 100644 --- a/drivers/s390/scsi/zfcp_ext.h +++ b/drivers/s390/scsi/zfcp_ext.h @@ -167,6 +167,7 @@ extern const struct attribute_group *zfcp_port_attr_groups[]; extern struct mutex zfcp_sysfs_port_units_mutex; extern struct device_attribute *zfcp_sysfs_sdev_attrs[]; extern struct device_attribute *zfcp_sysfs_shost_attrs[]; +extern const struct attribute_group zfcp_sysfs_diag_attr_group; bool zfcp_sysfs_port_is_removing(const struct zfcp_port *const port); /* zfcp_unit.c */ diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 90d851d49410..6c0cea71ae5d 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -11,6 +11,7 @@ #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt #include +#include "zfcp_diag.h" #include "zfcp_ext.h" #define ZFCP_DEV_ATTR(_feat, _name, _mode, _show, _store) \ @@ -664,3 +665,73 @@ struct device_attribute *zfcp_sysfs_shost_attrs[] = { &dev_attr_queue_full, NULL }; + +#define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt) \ + static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show( \ + struct device *dev, struct device_attribute *attr, char *buf) \ + { \ + struct zfcp_adapter *const adapter = \ + zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); \ + struct zfcp_diag_header *diag_hdr; \ + ssize_t rc = -ENOLINK; \ + unsigned long flags; \ + unsigned int status; \ + \ + if (!adapter) \ + return -ENODEV; \ + \ + status = atomic_read(&adapter->status); \ + if (0 == (status & ZFCP_STATUS_COMMON_OPEN) || \ + 0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) || \ + 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED)) \ + goto out; \ + \ + if (!zfcp_diag_support_sfp(adapter)) { \ + rc = -EOPNOTSUPP; \ + goto out; \ + } \ + \ + diag_hdr = &adapter->diagnostics->port_data.header; \ + \ + spin_lock_irqsave(&diag_hdr->access_lock, flags); \ + rc = scnprintf( \ + buf, (_prtsize) + 2, _prtfmt "\n", \ + adapter->diagnostics->port_data.data._qtcb_member); \ + spin_unlock_irqrestore(&diag_hdr->access_lock, flags); \ + \ + out: \ + zfcp_ccw_adapter_put(adapter); \ + return rc; \ + } \ + static ZFCP_DEV_ATTR(adapter_diag_sfp, _name, 0400, \ + zfcp_sysfs_adapter_diag_sfp_##_name##_show, NULL) + +ZFCP_DEFINE_DIAG_SFP_ATTR(temperature, temperature, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(vcc, vcc, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_bias, tx_bias, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(tx_power, tx_power, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(rx_power, rx_power, 5, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(port_tx_type, sfp_flags.port_tx_type, 2, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(optical_port, sfp_flags.optical_port, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(sfp_invalid, sfp_flags.sfp_invalid, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(connector_type, sfp_flags.connector_type, 1, "%hu"); +ZFCP_DEFINE_DIAG_SFP_ATTR(fec_active, sfp_flags.fec_active, 1, "%hu"); + +static struct attribute *zfcp_sysfs_diag_attrs[] = { + &dev_attr_adapter_diag_sfp_temperature.attr, + &dev_attr_adapter_diag_sfp_vcc.attr, + &dev_attr_adapter_diag_sfp_tx_bias.attr, + &dev_attr_adapter_diag_sfp_tx_power.attr, + &dev_attr_adapter_diag_sfp_rx_power.attr, + &dev_attr_adapter_diag_sfp_port_tx_type.attr, + &dev_attr_adapter_diag_sfp_optical_port.attr, + &dev_attr_adapter_diag_sfp_sfp_invalid.attr, + &dev_attr_adapter_diag_sfp_connector_type.attr, + &dev_attr_adapter_diag_sfp_fec_active.attr, + NULL, +}; + +const struct attribute_group zfcp_sysfs_diag_attr_group = { + .name = "diagnostics", + .attrs = zfcp_sysfs_diag_attrs, +}; -- cgit v1.2.3 From 8155eb0785279728b6b2e29aba2ca52d16aa526f Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:48 +0200 Subject: scsi: zfcp: implicitly refresh port-data diagnostics when reading sysfs This patch adds implicit updates to the sysfs entries that read the diagnostic data stored in the "caching buffer" for Exchange Port Data. An update is triggered once the buffer is older than ZFCP_DIAG_MAX_AGE milliseconds (5s). This entails sending an Exchange Port Data command to the FCP-Channel, and during its ingress path updating the cached data and the timestamp. To prevent multiple concurrent userspace-applications from triggering this update in parallel we synchronize all of them using a wait-queue (waiting threads are interruptible; the updating thread is not). Link: https://lore.kernel.org/r/c145b5cfc99a63b6a018b1184fbd27bb09c955f5.1572018132.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_diag.c | 129 +++++++++++++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_diag.h | 11 ++++ drivers/s390/scsi/zfcp_sysfs.c | 5 ++ 3 files changed, 145 insertions(+) diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c index 8df3ace6135d..9c5a0f3431ca 100644 --- a/drivers/s390/scsi/zfcp_diag.c +++ b/drivers/s390/scsi/zfcp_diag.c @@ -22,6 +22,8 @@ /* Max age of data in a diagnostics buffer before it needs a refresh (in ms). */ #define ZFCP_DIAG_MAX_AGE (5 * 1000) +static DECLARE_WAIT_QUEUE_HEAD(__zfcp_diag_publish_wait); + /** * zfcp_diag_adapter_setup() - Setup storage for adapter diagnostics. * @adapter: the adapter to setup diagnostics for. @@ -143,3 +145,130 @@ void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr, out: spin_unlock_irqrestore(&hdr->access_lock, flags); } + +/** + * zfcp_diag_update_port_data_buffer() - Implementation of + * &typedef zfcp_diag_update_buffer_func + * to collect and update Port Data. + * @adapter: Adapter to collect Port Data from. + * + * This call is SYNCHRONOUS ! It blocks till the respective command has + * finished completely, or has failed in some way. + * + * Return: + * * 0 - Successfully retrieved new Diagnostics and Updated the buffer; + * this also includes cases where data was retrieved, but + * incomplete; you'll have to check the flag ``incomplete`` + * of &struct zfcp_diag_header. + * * see zfcp_fsf_exchange_port_data_sync() for possible error-codes ( + * excluding -EAGAIN) + */ +int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter) +{ + int rc; + + rc = zfcp_fsf_exchange_port_data_sync(adapter->qdio, NULL); + if (rc == -EAGAIN) + rc = 0; /* signaling incomplete via struct zfcp_diag_header */ + + /* buffer-data was updated in zfcp_fsf_exchange_port_data_handler() */ + + return rc; +} + +static int __zfcp_diag_update_buffer(struct zfcp_adapter *const adapter, + struct zfcp_diag_header *const hdr, + zfcp_diag_update_buffer_func buffer_update, + unsigned long *const flags) + __must_hold(hdr->access_lock) +{ + int rc; + + if (hdr->updating == 1) { + rc = wait_event_interruptible_lock_irq(__zfcp_diag_publish_wait, + hdr->updating == 0, + hdr->access_lock); + rc = (rc == 0 ? -EAGAIN : -EINTR); + } else { + hdr->updating = 1; + spin_unlock_irqrestore(&hdr->access_lock, *flags); + + /* unlocked, because update function sleeps */ + rc = buffer_update(adapter); + + spin_lock_irqsave(&hdr->access_lock, *flags); + hdr->updating = 0; + + /* + * every thread waiting here went via an interruptible wait, + * so its fine to only wake those + */ + wake_up_interruptible_all(&__zfcp_diag_publish_wait); + } + + return rc; +} + +static bool +__zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_header *const hdr) + __must_hold(hdr->access_lock) +{ + const unsigned long now = jiffies; + + /* + * Should not happen (data is from the future).. if it does, still + * signal that it needs refresh + */ + if (!time_after_eq(now, hdr->timestamp)) + return false; + + if (jiffies_to_msecs(now - hdr->timestamp) >= ZFCP_DIAG_MAX_AGE) + return false; + + return true; +} + +/** + * zfcp_diag_update_buffer_limited() - Collect diagnostics and update a + * diagnostics buffer rate limited. + * @adapter: Adapter to collect the diagnostics from. + * @hdr: buffer-header for which to update with the collected diagnostics. + * @buffer_update: Specific implementation for collecting and updating. + * + * This function will cause an update of the given @hdr by calling the also + * given @buffer_update function. If called by multiple sources at the same + * time, it will synchornize the update by only allowing one source to call + * @buffer_update and the others to wait for that source to complete instead + * (the wait is interruptible). + * + * Additionally this version is rate-limited and will only exit if either the + * buffer is fresh enough (within the limit) - it will do nothing if the buffer + * is fresh enough to begin with -, or if the source/thread that started this + * update is the one that made the update (to prevent endless loops). + * + * Return: + * * 0 - If the update was successfully published and/or the buffer is + * fresh enough + * * -EINTR - If the thread went into the wait-state and was interrupted + * * whatever @buffer_update returns + */ +int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter, + struct zfcp_diag_header *const hdr, + zfcp_diag_update_buffer_func buffer_update) +{ + unsigned long flags; + int rc; + + spin_lock_irqsave(&hdr->access_lock, flags); + + for (rc = 0; !__zfcp_diag_test_buffer_age_isfresh(hdr); rc = 0) { + rc = __zfcp_diag_update_buffer(adapter, hdr, buffer_update, + &flags); + if (rc != -EAGAIN) + break; + } + + spin_unlock_irqrestore(&hdr->access_lock, flags); + + return rc; +} diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h index 2deebccda17d..7ff8fb0bb735 100644 --- a/drivers/s390/scsi/zfcp_diag.h +++ b/drivers/s390/scsi/zfcp_diag.h @@ -71,6 +71,17 @@ void zfcp_diag_sysfs_destroy(struct zfcp_adapter *const adapter); void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr, const void *const data, const bool incomplete); +/* + * Function-Type used in zfcp_diag_update_buffer_limited() for the function + * that does the buffer-implementation dependent work. + */ +typedef int (*zfcp_diag_update_buffer_func)(struct zfcp_adapter *const adapter); + +int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter); +int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter, + struct zfcp_diag_header *const hdr, + zfcp_diag_update_buffer_func buffer_update); + /** * zfcp_diag_support_sfp() - Return %true if the @adapter supports reporting * SFP Data. diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 6c0cea71ae5d..a2fa3db5695d 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -693,6 +693,11 @@ struct device_attribute *zfcp_sysfs_shost_attrs[] = { \ diag_hdr = &adapter->diagnostics->port_data.header; \ \ + rc = zfcp_diag_update_buffer_limited( \ + adapter, diag_hdr, zfcp_diag_update_port_data_buffer); \ + if (rc != 0) \ + goto out; \ + \ spin_lock_irqsave(&diag_hdr->access_lock, flags); \ rc = scnprintf( \ buf, (_prtsize) + 2, _prtfmt "\n", \ -- cgit v1.2.3 From 5a2876f0d1ef26b76755749f978d46e4666013dd Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:49 +0200 Subject: scsi: zfcp: introduce sysfs interface to read the local B2B-Credit In addition to the diagnostic data from the local SFP transceiver this patch adds an interface to read the advertised buffer-to-buffer credit from the local FC_Port. With this patch the userspace-interface will only read data stored in the corresponding "diagnostic buffer" (that was stored during completion of a previous Exchange Config Data command). Implicit updating will follow later in this series. Link: https://lore.kernel.org/r/8a53aef87b53c50cfb1a3425b799bacb6f82b832.1572018132.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_sysfs.c | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index a2fa3db5695d..376d76b9f337 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -666,6 +666,45 @@ struct device_attribute *zfcp_sysfs_shost_attrs[] = { NULL }; +static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show( + struct device *dev, struct device_attribute *attr, char *buf) +{ + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); + struct zfcp_diag_header *diag_hdr; + struct fc_els_flogi *nsp; + ssize_t rc = -ENOLINK; + unsigned long flags; + unsigned int status; + + if (!adapter) + return -ENODEV; + + status = atomic_read(&adapter->status); + if (0 == (status & ZFCP_STATUS_COMMON_OPEN) || + 0 == (status & ZFCP_STATUS_COMMON_UNBLOCKED) || + 0 != (status & ZFCP_STATUS_COMMON_ERP_FAILED)) + goto out; + + diag_hdr = &adapter->diagnostics->config_data.header; + + spin_lock_irqsave(&diag_hdr->access_lock, flags); + /* nport_serv_param doesn't contain the ELS_Command code */ + nsp = (struct fc_els_flogi *)((unsigned long) + adapter->diagnostics->config_data + .data.nport_serv_param - + sizeof(u32)); + + rc = scnprintf(buf, 5 + 2, "%hu\n", + be16_to_cpu(nsp->fl_csp.sp_bb_cred)); + spin_unlock_irqrestore(&diag_hdr->access_lock, flags); + +out: + zfcp_ccw_adapter_put(adapter); + return rc; +} +static ZFCP_DEV_ATTR(adapter_diag, b2b_credit, 0400, + zfcp_sysfs_adapter_diag_b2b_credit_show, NULL); + #define ZFCP_DEFINE_DIAG_SFP_ATTR(_name, _qtcb_member, _prtsize, _prtfmt) \ static ssize_t zfcp_sysfs_adapter_diag_sfp_##_name##_show( \ struct device *dev, struct device_attribute *attr, char *buf) \ @@ -733,6 +772,7 @@ static struct attribute *zfcp_sysfs_diag_attrs[] = { &dev_attr_adapter_diag_sfp_sfp_invalid.attr, &dev_attr_adapter_diag_sfp_connector_type.attr, &dev_attr_adapter_diag_sfp_fec_active.attr, + &dev_attr_adapter_diag_b2b_credit.attr, NULL, }; -- cgit v1.2.3 From 8a72db70b5ca3c3feb3ca25519e8a9516cc60cfe Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:50 +0200 Subject: scsi: zfcp: implicitly refresh config-data diagnostics when reading sysfs Adds implicit updates of cached diagnostics via Exchange Config Data when reading sysfs attributes interfacing them. Right now this only affects the new B2B-Credit diagnostic attribute. This uses the same mechanism previously also used for cached diagnostics of Exchange Port Data. Link: https://lore.kernel.org/r/60a94f55f2630b74b468fed5f39880208abb2679.1572018132.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_diag.c | 30 ++++++++++++++++++++++++++++++ drivers/s390/scsi/zfcp_diag.h | 1 + drivers/s390/scsi/zfcp_sysfs.c | 5 +++++ 3 files changed, 36 insertions(+) diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c index 9c5a0f3431ca..5ef7b3288c6f 100644 --- a/drivers/s390/scsi/zfcp_diag.c +++ b/drivers/s390/scsi/zfcp_diag.c @@ -176,6 +176,36 @@ int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter) return rc; } +/** + * zfcp_diag_update_config_data_buffer() - Implementation of + * &typedef zfcp_diag_update_buffer_func + * to collect and update Config Data. + * @adapter: Adapter to collect Config Data from. + * + * This call is SYNCHRONOUS ! It blocks till the respective command has + * finished completely, or has failed in some way. + * + * Return: + * * 0 - Successfully retrieved new Diagnostics and Updated the buffer; + * this also includes cases where data was retrieved, but + * incomplete; you'll have to check the flag ``incomplete`` + * of &struct zfcp_diag_header. + * * see zfcp_fsf_exchange_config_data_sync() for possible error-codes ( + * excluding -EAGAIN) + */ +int zfcp_diag_update_config_data_buffer(struct zfcp_adapter *const adapter) +{ + int rc; + + rc = zfcp_fsf_exchange_config_data_sync(adapter->qdio, NULL); + if (rc == -EAGAIN) + rc = 0; /* signaling incomplete via struct zfcp_diag_header */ + + /* buffer-data was updated in zfcp_fsf_exchange_config_data_handler() */ + + return rc; +} + static int __zfcp_diag_update_buffer(struct zfcp_adapter *const adapter, struct zfcp_diag_header *const hdr, zfcp_diag_update_buffer_func buffer_update, diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h index 7ff8fb0bb735..cf2947cd8c8f 100644 --- a/drivers/s390/scsi/zfcp_diag.h +++ b/drivers/s390/scsi/zfcp_diag.h @@ -77,6 +77,7 @@ void zfcp_diag_update_xdata(struct zfcp_diag_header *const hdr, */ typedef int (*zfcp_diag_update_buffer_func)(struct zfcp_adapter *const adapter); +int zfcp_diag_update_config_data_buffer(struct zfcp_adapter *const adapter); int zfcp_diag_update_port_data_buffer(struct zfcp_adapter *const adapter); int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter, struct zfcp_diag_header *const hdr, diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index 376d76b9f337..ae8e9137f448 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -687,6 +687,11 @@ static ssize_t zfcp_sysfs_adapter_diag_b2b_credit_show( diag_hdr = &adapter->diagnostics->config_data.header; + rc = zfcp_diag_update_buffer_limited( + adapter, diag_hdr, zfcp_diag_update_config_data_buffer); + if (rc != 0) + goto out; + spin_lock_irqsave(&diag_hdr->access_lock, flags); /* nport_serv_param doesn't contain the ELS_Command code */ nsp = (struct fc_els_flogi *)((unsigned long) -- cgit v1.2.3 From 48910f8c35cfd250d806f3e03150d256f40b6d4c Mon Sep 17 00:00:00 2001 From: Benjamin Block Date: Fri, 25 Oct 2019 18:12:51 +0200 Subject: scsi: zfcp: move maximum age of diagnostic buffers into a per-adapter variable Replace the static define (ZFCP_DIAG_MAX_AGE) with a per-adapter variable (${adapter}->diagnostics->max_age). This new variable is exported via sysfs, along with other, already existing adapter variables, and can both be read and written. This way users can choose how much time should pass between refreshes of diagnostic buffers. The default value for the age remains to be five seconds. By setting this new variable to 0, the caching of diagnostic buffers for userspace accesses can also be completely removed. All diagnostic buffers of a given adapter are subject to this setting in the same way. Link: https://lore.kernel.org/r/b1d0977cc884b16dd4ca6418e4320c56a4c31d63.1572018132.git.bblock@linux.ibm.com Reviewed-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_diag.c | 23 ++++++++++----------- drivers/s390/scsi/zfcp_diag.h | 4 ++++ drivers/s390/scsi/zfcp_sysfs.c | 45 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 11 deletions(-) diff --git a/drivers/s390/scsi/zfcp_diag.c b/drivers/s390/scsi/zfcp_diag.c index 5ef7b3288c6f..67a8f4e57db1 100644 --- a/drivers/s390/scsi/zfcp_diag.c +++ b/drivers/s390/scsi/zfcp_diag.c @@ -19,9 +19,6 @@ #include "zfcp_ext.h" #include "zfcp_def.h" -/* Max age of data in a diagnostics buffer before it needs a refresh (in ms). */ -#define ZFCP_DIAG_MAX_AGE (5 * 1000) - static DECLARE_WAIT_QUEUE_HEAD(__zfcp_diag_publish_wait); /** @@ -38,9 +35,6 @@ static DECLARE_WAIT_QUEUE_HEAD(__zfcp_diag_publish_wait); */ int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter) { - /* set the timestamp so that the first test on age will always fail */ - const unsigned long initial_timestamp = - jiffies - msecs_to_jiffies(ZFCP_DIAG_MAX_AGE); struct zfcp_diag_adapter *diag; struct zfcp_diag_header *hdr; @@ -48,13 +42,16 @@ int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter) if (diag == NULL) return -ENOMEM; + diag->max_age = (5 * 1000); /* default value: 5 s */ + /* setup header for port_data */ hdr = &diag->port_data.header; spin_lock_init(&hdr->access_lock); hdr->buffer = &diag->port_data.data; hdr->buffer_size = sizeof(diag->port_data.data); - hdr->timestamp = initial_timestamp; + /* set the timestamp so that the first test on age will always fail */ + hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age); /* setup header for config_data */ hdr = &diag->config_data.header; @@ -62,7 +59,8 @@ int zfcp_diag_adapter_setup(struct zfcp_adapter *const adapter) spin_lock_init(&hdr->access_lock); hdr->buffer = &diag->config_data.data; hdr->buffer_size = sizeof(diag->config_data.data); - hdr->timestamp = initial_timestamp; + /* set the timestamp so that the first test on age will always fail */ + hdr->timestamp = jiffies - msecs_to_jiffies(diag->max_age); adapter->diagnostics = diag; return 0; @@ -240,7 +238,8 @@ static int __zfcp_diag_update_buffer(struct zfcp_adapter *const adapter, } static bool -__zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_header *const hdr) +__zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_adapter *const diag, + const struct zfcp_diag_header *const hdr) __must_hold(hdr->access_lock) { const unsigned long now = jiffies; @@ -252,7 +251,7 @@ __zfcp_diag_test_buffer_age_isfresh(const struct zfcp_diag_header *const hdr) if (!time_after_eq(now, hdr->timestamp)) return false; - if (jiffies_to_msecs(now - hdr->timestamp) >= ZFCP_DIAG_MAX_AGE) + if (jiffies_to_msecs(now - hdr->timestamp) >= diag->max_age) return false; return true; @@ -291,7 +290,9 @@ int zfcp_diag_update_buffer_limited(struct zfcp_adapter *const adapter, spin_lock_irqsave(&hdr->access_lock, flags); - for (rc = 0; !__zfcp_diag_test_buffer_age_isfresh(hdr); rc = 0) { + for (rc = 0; + !__zfcp_diag_test_buffer_age_isfresh(adapter->diagnostics, hdr); + rc = 0) { rc = __zfcp_diag_update_buffer(adapter, hdr, buffer_update, &flags); if (rc != -EAGAIN) diff --git a/drivers/s390/scsi/zfcp_diag.h b/drivers/s390/scsi/zfcp_diag.h index cf2947cd8c8f..b9c93d15f67c 100644 --- a/drivers/s390/scsi/zfcp_diag.h +++ b/drivers/s390/scsi/zfcp_diag.h @@ -42,6 +42,8 @@ struct zfcp_diag_header { * adapter. * @sysfs_established: flag showing that the associated sysfs-group was created * during run of zfcp_adapter_enqueue(). + * @max_age: maximum age of data in diagnostic buffers before they need to be + * refreshed (in ms). * @port_data: data retrieved using exchange port data. * @port_data.header: header with metadata for the cache in @port_data.data. * @port_data.data: cached QTCB Bottom of command exchange port data. @@ -52,6 +54,8 @@ struct zfcp_diag_header { struct zfcp_diag_adapter { u64 sysfs_established :1; + unsigned long max_age; + struct { struct zfcp_diag_header header; struct fsf_qtcb_bottom_port data; diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c index ae8e9137f448..494b9fe9cc94 100644 --- a/drivers/s390/scsi/zfcp_sysfs.c +++ b/drivers/s390/scsi/zfcp_sysfs.c @@ -326,6 +326,50 @@ static ssize_t zfcp_sysfs_port_remove_store(struct device *dev, static ZFCP_DEV_ATTR(adapter, port_remove, S_IWUSR, NULL, zfcp_sysfs_port_remove_store); +static ssize_t +zfcp_sysfs_adapter_diag_max_age_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); + ssize_t rc; + + if (!adapter) + return -ENODEV; + + /* ceil(log(2^64 - 1) / log(10)) = 20 */ + rc = scnprintf(buf, 20 + 2, "%lu\n", adapter->diagnostics->max_age); + + zfcp_ccw_adapter_put(adapter); + return rc; +} + +static ssize_t +zfcp_sysfs_adapter_diag_max_age_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct zfcp_adapter *adapter = zfcp_ccw_adapter_by_cdev(to_ccwdev(dev)); + unsigned long max_age; + ssize_t rc; + + if (!adapter) + return -ENODEV; + + rc = kstrtoul(buf, 10, &max_age); + if (rc != 0) + goto out; + + adapter->diagnostics->max_age = max_age; + + rc = count; +out: + zfcp_ccw_adapter_put(adapter); + return rc; +} +static ZFCP_DEV_ATTR(adapter, diag_max_age, 0644, + zfcp_sysfs_adapter_diag_max_age_show, + zfcp_sysfs_adapter_diag_max_age_store); + static struct attribute *zfcp_adapter_attrs[] = { &dev_attr_adapter_failed.attr, &dev_attr_adapter_in_recovery.attr, @@ -338,6 +382,7 @@ static struct attribute *zfcp_adapter_attrs[] = { &dev_attr_adapter_lic_version.attr, &dev_attr_adapter_status.attr, &dev_attr_adapter_hardware_version.attr, + &dev_attr_adapter_diag_max_age.attr, NULL }; -- cgit v1.2.3 From e76acc51942649398660ca50655af5afecf29c42 Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Fri, 25 Oct 2019 18:12:52 +0200 Subject: scsi: zfcp: proper indentation to reduce confusion in zfcp_erp_required_act No functional change. The unary not operator only applies to the sub expression before the logical or. So we return early if (not running) or failed. Link: https://lore.kernel.org/r/df4f897f6e83eaa528465d0858d5a22daac47a2f.1572018132.git.bblock@linux.ibm.com Reviewed-by: Jens Remus Reviewed-by: Benjamin Block Signed-off-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_erp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c index 96f0d34e9459..93655b85b73f 100644 --- a/drivers/s390/scsi/zfcp_erp.c +++ b/drivers/s390/scsi/zfcp_erp.c @@ -174,7 +174,7 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want, return 0; p_status = atomic_read(&port->status); if (!(p_status & ZFCP_STATUS_COMMON_RUNNING) || - p_status & ZFCP_STATUS_COMMON_ERP_FAILED) + p_status & ZFCP_STATUS_COMMON_ERP_FAILED) return 0; if (!(p_status & ZFCP_STATUS_COMMON_UNBLOCKED)) need = ZFCP_ERP_ACTION_REOPEN_PORT; @@ -190,7 +190,7 @@ static enum zfcp_erp_act_type zfcp_erp_required_act(enum zfcp_erp_act_type want, return 0; a_status = atomic_read(&adapter->status); if (!(a_status & ZFCP_STATUS_COMMON_RUNNING) || - a_status & ZFCP_STATUS_COMMON_ERP_FAILED) + a_status & ZFCP_STATUS_COMMON_ERP_FAILED) return 0; if (p_status & ZFCP_STATUS_COMMON_NOESC) return need; -- cgit v1.2.3 From 100843f176109af94600e500da0428e21030ca7f Mon Sep 17 00:00:00 2001 From: Steffen Maier Date: Fri, 25 Oct 2019 18:12:53 +0200 Subject: scsi: zfcp: trace channel log even for FCP command responses While v2.6.26 commit b75db73159cc ("[SCSI] zfcp: Add qtcb dump to hba debug trace") is right that we don't want to flood the (payload) trace ring buffer, we don't trace successful FCP command responses by default. So we can include the channel log for problem determination with failed responses of any FSF request type. Fixes: b75db73159cc ("[SCSI] zfcp: Add qtcb dump to hba debug trace") Fixes: a54ca0f62f95 ("[SCSI] zfcp: Redesign of the debug tracing for HBA records.") Cc: #2.6.38+ Link: https://lore.kernel.org/r/e37597b5c4ae123aaa85fd86c23a9f71e994e4a9.1572018132.git.bblock@linux.ibm.com Reviewed-by: Benjamin Block Signed-off-by: Steffen Maier Signed-off-by: Benjamin Block Signed-off-by: Martin K. Petersen --- drivers/s390/scsi/zfcp_dbf.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/s390/scsi/zfcp_dbf.c b/drivers/s390/scsi/zfcp_dbf.c index dccdb41bed8c..1234294700c4 100644 --- a/drivers/s390/scsi/zfcp_dbf.c +++ b/drivers/s390/scsi/zfcp_dbf.c @@ -95,11 +95,9 @@ void zfcp_dbf_hba_fsf_res(char *tag, int level, struct zfcp_fsf_req *req) memcpy(rec->u.res.fsf_status_qual, &q_head->fsf_status_qual, FSF_STATUS_QUALIFIER_SIZE); - if (q_head->fsf_command != FSF_QTCB_FCP_CMND) { - rec->pl_len = q_head->log_length; - zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start, - rec->pl_len, "fsf_res", req->req_id); - } + rec->pl_len = q_head->log_length; + zfcp_dbf_pl_write(dbf, (char *)q_pref + q_head->log_start, + rec->pl_len, "fsf_res", req->req_id); debug_event(dbf->hba, level, rec, sizeof(*rec)); spin_unlock_irqrestore(&dbf->hba_lock, flags); -- cgit v1.2.3 From 059efd847a4097c67817782d8ff65397e369e69b Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 29 Oct 2019 14:22:45 +0000 Subject: scsi: ufs: delete redundant function ufshcd_def_desc_sizes() There is no need to call ufshcd_def_desc_sizes() in ufshcd_init(), since descriptor lengths will be checked and initialized later in ufshcd_init_desc_sizes(). Fixes: a4b0e8a4e92b1b(scsi: ufs: Factor out ufshcd_read_desc_param) Link: https://lore.kernel.org/r/BN7PR08MB5684A3ACE214C3D4792CE729DB610@BN7PR08MB5684.namprd08.prod.outlook.com Signed-off-by: Bean Huo Acked-by: Avri Altman Reviewed-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index c28c144d9b4a..21a7244882a1 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -6778,23 +6778,13 @@ static void ufshcd_init_desc_sizes(struct ufs_hba *hba) &hba->desc_size.geom_desc); if (err) hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; + err = ufshcd_read_desc_length(hba, QUERY_DESC_IDN_HEALTH, 0, &hba->desc_size.hlth_desc); if (err) hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; } -static void ufshcd_def_desc_sizes(struct ufs_hba *hba) -{ - hba->desc_size.dev_desc = QUERY_DESC_DEVICE_DEF_SIZE; - hba->desc_size.pwr_desc = QUERY_DESC_POWER_DEF_SIZE; - hba->desc_size.interc_desc = QUERY_DESC_INTERCONNECT_DEF_SIZE; - hba->desc_size.conf_desc = QUERY_DESC_CONFIGURATION_DEF_SIZE; - hba->desc_size.unit_desc = QUERY_DESC_UNIT_DEF_SIZE; - hba->desc_size.geom_desc = QUERY_DESC_GEOMETRY_DEF_SIZE; - hba->desc_size.hlth_desc = QUERY_DESC_HEALTH_DEF_SIZE; -} - static struct ufs_ref_clk ufs_ref_clk_freqs[] = { {19200000, REF_CLK_FREQ_19_2_MHZ}, {26000000, REF_CLK_FREQ_26_MHZ}, @@ -8283,9 +8273,6 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) hba->mmio_base = mmio_base; hba->irq = irq; - /* Set descriptor lengths to specification defaults */ - ufshcd_def_desc_sizes(hba); - err = ufshcd_hba_init(hba); if (err) goto out_error; -- cgit v1.2.3 From d0e9760de338635450c4e8ebb07bdbcfb1b56e64 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 29 Oct 2019 16:07:08 -0700 Subject: scsi: ufs: Fix kernel-doc warnings Fix the following three kernel-doc warnings: drivers/scsi/ufs/ufs_bsg.c:165: warning: Function parameter or member 'hba' not described in 'ufs_bsg_remove' drivers/scsi/ufs/ufshcd.c:5789: warning: Function parameter or member 'cmd_type' not described in 'ufshcd_issue_devman_upiu_cmd' drivers/scsi/ufs/ufshcd.c:5789: warning: Excess function parameter 'msgcode' description in 'ufshcd_issue_devman_upiu_cmd' Cc: Yaniv Gardi Cc: Subhash Jadavani Cc: Stanley Chu Cc: Avri Altman Cc: Tomas Winkler Link: https://lore.kernel.org/r/20191029230710.211926-2-bvanassche@acm.org Signed-off-by: Bart Van Assche Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs_bsg.c | 1 + drivers/scsi/ufs/ufshcd.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufs_bsg.c b/drivers/scsi/ufs/ufs_bsg.c index a9344eb4e047..3a2e68f1ad42 100644 --- a/drivers/scsi/ufs/ufs_bsg.c +++ b/drivers/scsi/ufs/ufs_bsg.c @@ -158,6 +158,7 @@ out: /** * ufs_bsg_remove - detach and remove the added ufs-bsg node + * @hba: per adapter object * * Should be called when unloading the driver. */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 21a7244882a1..12f88a86e65f 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5768,9 +5768,9 @@ static int ufshcd_issue_tm_cmd(struct ufs_hba *hba, int lun_id, int task_id, * @hba: per-adapter instance * @req_upiu: upiu request * @rsp_upiu: upiu reply - * @msgcode: message code, one of UPIU Transaction Codes Initiator to Target * @desc_buff: pointer to descriptor buffer, NULL if NA * @buff_len: descriptor size, 0 if NA + * @cmd_type: specifies the type (NOP, Query...) * @desc_op: descriptor operation * * Those type of requests uses UTP Transfer Request Descriptor - utrd. -- cgit v1.2.3 From 7f674c38a38e056bb33d1d67700410c3f3124d34 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 29 Oct 2019 16:07:09 -0700 Subject: scsi: ufs: Use enum dev_cmd_type where appropriate Declare all variables that hold dev_cmd_type values as an enum instead of as an int. Cc: Yaniv Gardi Cc: Subhash Jadavani Cc: Stanley Chu Cc: Avri Altman Cc: Tomas Winkler Link: https://lore.kernel.org/r/20191029230710.211926-3-bvanassche@acm.org Signed-off-by: Bart Van Assche Reviewed-by: Avri Altman Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 12f88a86e65f..9cbe3b45cf1c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -5784,7 +5784,7 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, struct utp_upiu_req *req_upiu, struct utp_upiu_req *rsp_upiu, u8 *desc_buff, int *buff_len, - int cmd_type, + enum dev_cmd_type cmd_type, enum query_opcode desc_op) { struct ufshcd_lrb *lrbp; @@ -5899,7 +5899,7 @@ int ufshcd_exec_raw_upiu_cmd(struct ufs_hba *hba, enum query_opcode desc_op) { int err; - int cmd_type = DEV_CMD_TYPE_QUERY; + enum dev_cmd_type cmd_type = DEV_CMD_TYPE_QUERY; struct utp_task_req_desc treq = { { 0 }, }; int ocs_value; u8 tm_f = be32_to_cpu(req_upiu->header.dword_1) >> 16 & MASK_TM_FUNC; -- cgit v1.2.3 From 6eb045e092efefafc6687409a6fa6d1dabf0fb69 Mon Sep 17 00:00:00 2001 From: Ming Lei Date: Fri, 25 Oct 2019 14:58:55 +0800 Subject: scsi: core: avoid host-wide host_busy counter for scsi_mq It isn't necessary to check the host depth in scsi_queue_rq() any more since it has been respected by blk-mq before calling scsi_queue_rq() via getting driver tag. Lots of LUNs may attach to same host and per-host IOPS may reach millions, so we should avoid expensive atomic operations on the host-wide counter in the IO path. This patch implements scsi_host_busy() via blk_mq_tagset_busy_iter() with one scsi command state for reading the count of busy IOs for scsi_mq. It is observed that IOPS is increased by 15% in IO test on scsi_debug (32 LUNs, 32 submit queues, 1024 can_queue, libaio/dio) in a dual-socket system. Cc: Jens Axboe Cc: Ewan D. Milne Cc: Omar Sandoval , Cc: "Martin K. Petersen" , Cc: James Bottomley , Cc: Christoph Hellwig , Cc: Kashyap Desai Cc: Hannes Reinecke Cc: Laurence Oberman Cc: Bart Van Assche Link: https://lore.kernel.org/r/20191025065855.6309-1-ming.lei@redhat.com Signed-off-by: Ming Lei Reviewed-by: Jens Axboe Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/hosts.c | 19 ++++++++++++++++++- drivers/scsi/scsi.c | 2 +- drivers/scsi/scsi_lib.c | 45 ++++++++++++++++++++++----------------------- drivers/scsi/scsi_priv.h | 2 +- include/scsi/scsi_cmnd.h | 1 + include/scsi/scsi_host.h | 3 +-- 6 files changed, 44 insertions(+), 28 deletions(-) diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index 55522b7162d3..1d669e47b692 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -38,6 +38,7 @@ #include #include #include +#include #include "scsi_priv.h" #include "scsi_logging.h" @@ -554,13 +555,29 @@ struct Scsi_Host *scsi_host_get(struct Scsi_Host *shost) } EXPORT_SYMBOL(scsi_host_get); +static bool scsi_host_check_in_flight(struct request *rq, void *data, + bool reserved) +{ + int *count = data; + struct scsi_cmnd *cmd = blk_mq_rq_to_pdu(rq); + + if (test_bit(SCMD_STATE_INFLIGHT, &cmd->state)) + (*count)++; + + return true; +} + /** * scsi_host_busy - Return the host busy counter * @shost: Pointer to Scsi_Host to inc. **/ int scsi_host_busy(struct Scsi_Host *shost) { - return atomic_read(&shost->host_busy); + int cnt = 0; + + blk_mq_tagset_busy_iter(&shost->tag_set, + scsi_host_check_in_flight, &cnt); + return cnt; } EXPORT_SYMBOL(scsi_host_busy); diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 4f76841a7038..adfe8b3693d5 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -186,7 +186,7 @@ void scsi_finish_command(struct scsi_cmnd *cmd) struct scsi_driver *drv; unsigned int good_bytes; - scsi_device_unbusy(sdev); + scsi_device_unbusy(sdev, cmd); /* * Clear the flags that say that the device/target/host is no longer diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c index dc210b9d4896..2563b061f56b 100644 --- a/drivers/scsi/scsi_lib.c +++ b/drivers/scsi/scsi_lib.c @@ -189,7 +189,7 @@ static void __scsi_queue_insert(struct scsi_cmnd *cmd, int reason, bool unbusy) * active on the host/device. */ if (unbusy) - scsi_device_unbusy(device); + scsi_device_unbusy(device, cmd); /* * Requeue this command. It will go before all other commands @@ -321,20 +321,20 @@ static void scsi_init_cmd_errh(struct scsi_cmnd *cmd) } /* - * Decrement the host_busy counter and wake up the error handler if necessary. - * Avoid as follows that the error handler is not woken up if shost->host_busy - * == shost->host_failed: use call_rcu() in scsi_eh_scmd_add() in combination - * with an RCU read lock in this function to ensure that this function in its - * entirety either finishes before scsi_eh_scmd_add() increases the + * Wake up the error handler if necessary. Avoid as follows that the error + * handler is not woken up if host in-flight requests number == + * shost->host_failed: use call_rcu() in scsi_eh_scmd_add() in combination + * with an RCU read lock in this function to ensure that this function in + * its entirety either finishes before scsi_eh_scmd_add() increases the * host_failed counter or that it notices the shost state change made by * scsi_eh_scmd_add(). */ -static void scsi_dec_host_busy(struct Scsi_Host *shost) +static void scsi_dec_host_busy(struct Scsi_Host *shost, struct scsi_cmnd *cmd) { unsigned long flags; rcu_read_lock(); - atomic_dec(&shost->host_busy); + __clear_bit(SCMD_STATE_INFLIGHT, &cmd->state); if (unlikely(scsi_host_in_recovery(shost))) { spin_lock_irqsave(shost->host_lock, flags); if (shost->host_failed || shost->host_eh_scheduled) @@ -344,12 +344,12 @@ static void scsi_dec_host_busy(struct Scsi_Host *shost) rcu_read_unlock(); } -void scsi_device_unbusy(struct scsi_device *sdev) +void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd) { struct Scsi_Host *shost = sdev->host; struct scsi_target *starget = scsi_target(sdev); - scsi_dec_host_busy(shost); + scsi_dec_host_busy(shost, cmd); if (starget->can_queue > 0) atomic_dec(&starget->target_busy); @@ -430,9 +430,6 @@ static inline bool scsi_target_is_busy(struct scsi_target *starget) static inline bool scsi_host_is_busy(struct Scsi_Host *shost) { - if (shost->can_queue > 0 && - atomic_read(&shost->host_busy) >= shost->can_queue) - return true; if (atomic_read(&shost->host_blocked) > 0) return true; if (shost->host_self_blocked) @@ -1139,6 +1136,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) unsigned int flags = cmd->flags & SCMD_PRESERVED_FLAGS; unsigned long jiffies_at_alloc; int retries; + bool in_flight; if (!blk_rq_is_scsi(rq) && !(flags & SCMD_INITIALIZED)) { flags |= SCMD_INITIALIZED; @@ -1147,6 +1145,7 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) jiffies_at_alloc = cmd->jiffies_at_alloc; retries = cmd->retries; + in_flight = test_bit(SCMD_STATE_INFLIGHT, &cmd->state); /* zero out the cmd, except for the embedded scsi_request */ memset((char *)cmd + sizeof(cmd->req), 0, sizeof(*cmd) - sizeof(cmd->req) + dev->host->hostt->cmd_size); @@ -1158,6 +1157,8 @@ void scsi_init_command(struct scsi_device *dev, struct scsi_cmnd *cmd) INIT_DELAYED_WORK(&cmd->abort_work, scmd_eh_abort_handler); cmd->jiffies_at_alloc = jiffies_at_alloc; cmd->retries = retries; + if (in_flight) + __set_bit(SCMD_STATE_INFLIGHT, &cmd->state); scsi_add_cmd_to_list(cmd); } @@ -1367,16 +1368,14 @@ out_dec: */ static inline int scsi_host_queue_ready(struct request_queue *q, struct Scsi_Host *shost, - struct scsi_device *sdev) + struct scsi_device *sdev, + struct scsi_cmnd *cmd) { - unsigned int busy; - if (scsi_host_in_recovery(shost)) return 0; - busy = atomic_inc_return(&shost->host_busy) - 1; if (atomic_read(&shost->host_blocked) > 0) { - if (busy) + if (scsi_host_busy(shost) > 0) goto starved; /* @@ -1390,8 +1389,6 @@ static inline int scsi_host_queue_ready(struct request_queue *q, "unblocking host at zero depth\n")); } - if (shost->can_queue > 0 && busy >= shost->can_queue) - goto starved; if (shost->host_self_blocked) goto starved; @@ -1403,6 +1400,8 @@ static inline int scsi_host_queue_ready(struct request_queue *q, spin_unlock_irq(shost->host_lock); } + __set_bit(SCMD_STATE_INFLIGHT, &cmd->state); + return 1; starved: @@ -1411,7 +1410,7 @@ starved: list_add_tail(&sdev->starved_entry, &shost->starved_list); spin_unlock_irq(shost->host_lock); out_dec: - scsi_dec_host_busy(shost); + scsi_dec_host_busy(shost, cmd); return 0; } @@ -1665,7 +1664,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, ret = BLK_STS_RESOURCE; if (!scsi_target_queue_ready(shost, sdev)) goto out_put_budget; - if (!scsi_host_queue_ready(q, shost, sdev)) + if (!scsi_host_queue_ready(q, shost, sdev, cmd)) goto out_dec_target_busy; if (!(req->rq_flags & RQF_DONTPREP)) { @@ -1697,7 +1696,7 @@ static blk_status_t scsi_queue_rq(struct blk_mq_hw_ctx *hctx, return BLK_STS_OK; out_dec_host_busy: - scsi_dec_host_busy(shost); + scsi_dec_host_busy(shost, cmd); out_dec_target_busy: if (scsi_target(sdev)->can_queue > 0) atomic_dec(&scsi_target(sdev)->target_busy); diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h index cc2859d76d81..3bff9f7aa684 100644 --- a/drivers/scsi/scsi_priv.h +++ b/drivers/scsi/scsi_priv.h @@ -87,7 +87,7 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd); extern void scsi_add_cmd_to_list(struct scsi_cmnd *cmd); extern void scsi_del_cmd_from_list(struct scsi_cmnd *cmd); extern int scsi_maybe_unblock_host(struct scsi_device *sdev); -extern void scsi_device_unbusy(struct scsi_device *sdev); +extern void scsi_device_unbusy(struct scsi_device *sdev, struct scsi_cmnd *cmd); extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason); extern void scsi_io_completion(struct scsi_cmnd *, unsigned int); extern void scsi_run_host_queues(struct Scsi_Host *shost); diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 91bd749a02f7..9c22e85902ec 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -63,6 +63,7 @@ struct scsi_pointer { /* for scmd->state */ #define SCMD_STATE_COMPLETE 0 +#define SCMD_STATE_INFLIGHT 1 struct scsi_cmnd { struct scsi_request req; diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 2c3f0c58869b..fccdf84ec7e2 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -345,7 +345,7 @@ struct scsi_host_template { /* * This determines if we will use a non-interrupt driven * or an interrupt driven scheme. It is set to the maximum number - * of simultaneous commands a given host adapter will accept. + * of simultaneous commands a single hw queue in HBA will accept. */ int can_queue; @@ -554,7 +554,6 @@ struct Scsi_Host { /* Area to keep a shared tag map */ struct blk_mq_tag_set tag_set; - atomic_t host_busy; /* commands actually active on low-level */ atomic_t host_blocked; unsigned int host_failed; /* commands that failed. -- cgit v1.2.3 From 62fb8b34be369d668226ce8e993e1355c0cca1de Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Fri, 25 Oct 2019 19:20:14 +0530 Subject: scsi: pm8001: Fix Use plain integer as NULL pointer Replace assignment of 0 to pointer with NULL assignment. Link: https://lore.kernel.org/r/20191025135010.GA6191@saurav Signed-off-by: Saurav Girepunje Acked-by: Jack Wang Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index 3374f553c617..ad67cdd4d3cf 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -432,7 +432,7 @@ static int pm8001_ioremap(struct pm8001_hba_info *pm8001_ha) } else { pm8001_ha->io_mem[logicalBar].membase = 0; pm8001_ha->io_mem[logicalBar].memsize = 0; - pm8001_ha->io_mem[logicalBar].memvirtaddr = 0; + pm8001_ha->io_mem[logicalBar].memvirtaddr = NULL; } logicalBar++; } -- cgit v1.2.3 From 75a740e6e81c89e26a1bd2e628b84131ad90c997 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Sun, 27 Oct 2019 01:26:30 +0530 Subject: scsi: csiostor: Fix NULL check before debugfs_remove_recursive debugfs_remove_recursive() has taken the null pointer into account. Remove the null check before debugfs_remove_recursive(). Link: https://lore.kernel.org/r/20191026195625.GA22455@saurav Signed-off-by: Saurav Girepunje Reviewed-by: Greg Kroah-Hartman Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_init.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index a6dd704d7f2d..f98f36c0d6b7 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -157,8 +157,7 @@ csio_dfs_create(struct csio_hw *hw) static int csio_dfs_destroy(struct csio_hw *hw) { - if (hw->debugfs_root) - debugfs_remove_recursive(hw->debugfs_root); + debugfs_remove_recursive(hw->debugfs_root); return 0; } -- cgit v1.2.3 From 64dc4f346b5be50a96f41d628e88c0fdb0ee0254 Mon Sep 17 00:00:00 2001 From: Saurav Girepunje Date: Tue, 29 Oct 2019 01:12:34 +0530 Subject: scsi: csiostor: Return value not required for csio_dfs_destroy Only csio_hw_free() calling csio_dfs_destroy() and it is not checking return value. So remove the return from csio_dfs_destroy(). Link: https://lore.kernel.org/r/20191028194234.GA27848@saurav Signed-off-by: Saurav Girepunje Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_init.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c index f98f36c0d6b7..2e8a3ac575cb 100644 --- a/drivers/scsi/csiostor/csio_init.c +++ b/drivers/scsi/csiostor/csio_init.c @@ -154,12 +154,10 @@ csio_dfs_create(struct csio_hw *hw) /* * csio_dfs_destroy - Destroys per-hw debugfs. */ -static int +static void csio_dfs_destroy(struct csio_hw *hw) { debugfs_remove_recursive(hw->debugfs_root); - - return 0; } /* -- cgit v1.2.3 From b1335f5b0486f61fb66b123b40f8e7a98e49605d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 1 Nov 2019 14:14:47 -0700 Subject: scsi: core: scsi_trace: Use get_unaligned_be*() This patch fixes an unintended sign extension on left shifts. From Colin King: "Shifting a u8 left will cause the value to be promoted to an integer. If the top bit of the u8 is set then the following conversion to an u64 will sign extend the value causing the upper 32 bits to be set in the result." Fix this by using get_unaligned_be*() instead. Fixes: bf8162354233 ("[SCSI] add scsi trace core functions and put trace points") Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Douglas Gilbert Link: https://lore.kernel.org/r/20191101211447.187151-1-bvanassche@acm.org Reported-by: Colin Ian King Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_trace.c | 109 +++++++++++++--------------------------------- 1 file changed, 31 insertions(+), 78 deletions(-) diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 0f17e7dac1b0..784ed9a32a0d 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -9,7 +9,7 @@ #include #define SERVICE_ACTION16(cdb) (cdb[1] & 0x1f) -#define SERVICE_ACTION32(cdb) ((cdb[8] << 8) | cdb[9]) +#define SERVICE_ACTION32(cdb) (get_unaligned_be16(&cdb[8])) static const char * scsi_trace_misc(struct trace_seq *, unsigned char *, int); @@ -36,17 +36,12 @@ static const char * scsi_trace_rw10(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; + u32 lba, txlen; - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[7] << 8); - txlen |= cdb[8]; + lba = get_unaligned_be32(&cdb[2]); + txlen = get_unaligned_be16(&cdb[7]); - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); if (cdb[0] == WRITE_SAME) @@ -61,19 +56,12 @@ static const char * scsi_trace_rw12(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; + u32 lba, txlen; + + lba = get_unaligned_be32(&cdb[2]); + txlen = get_unaligned_be32(&cdb[6]); - lba |= (cdb[2] << 24); - lba |= (cdb[3] << 16); - lba |= (cdb[4] << 8); - lba |= cdb[5]; - txlen |= (cdb[6] << 24); - txlen |= (cdb[7] << 16); - txlen |= (cdb[8] << 8); - txlen |= cdb[9]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + trace_seq_printf(p, "lba=%u txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); trace_seq_putc(p, 0); @@ -84,23 +72,13 @@ static const char * scsi_trace_rw16(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; + u64 lba; + u32 txlen; + + lba = get_unaligned_be64(&cdb[2]); + txlen = get_unaligned_be32(&cdb[10]); - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - txlen |= (cdb[10] << 24); - txlen |= (cdb[11] << 16); - txlen |= (cdb[12] << 8); - txlen |= cdb[13]; - - trace_seq_printf(p, "lba=%llu txlen=%llu protect=%u", - (unsigned long long)lba, (unsigned long long)txlen, + trace_seq_printf(p, "lba=%llu txlen=%u protect=%u", lba, txlen, cdb[1] >> 5); if (cdb[0] == WRITE_SAME_16) @@ -115,8 +93,8 @@ static const char * scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p), *cmd; - sector_t lba = 0, txlen = 0; - u32 ei_lbrt = 0; + u64 lba; + u32 ei_lbrt, txlen; switch (SERVICE_ACTION32(cdb)) { case READ_32: @@ -136,26 +114,12 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len) goto out; } - lba |= ((u64)cdb[12] << 56); - lba |= ((u64)cdb[13] << 48); - lba |= ((u64)cdb[14] << 40); - lba |= ((u64)cdb[15] << 32); - lba |= (cdb[16] << 24); - lba |= (cdb[17] << 16); - lba |= (cdb[18] << 8); - lba |= cdb[19]; - ei_lbrt |= (cdb[20] << 24); - ei_lbrt |= (cdb[21] << 16); - ei_lbrt |= (cdb[22] << 8); - ei_lbrt |= cdb[23]; - txlen |= (cdb[28] << 24); - txlen |= (cdb[29] << 16); - txlen |= (cdb[30] << 8); - txlen |= cdb[31]; - - trace_seq_printf(p, "%s_32 lba=%llu txlen=%llu protect=%u ei_lbrt=%u", - cmd, (unsigned long long)lba, - (unsigned long long)txlen, cdb[10] >> 5, ei_lbrt); + lba = get_unaligned_be64(&cdb[12]); + ei_lbrt = get_unaligned_be32(&cdb[20]); + txlen = get_unaligned_be32(&cdb[28]); + + trace_seq_printf(p, "%s_32 lba=%llu txlen=%u protect=%u ei_lbrt=%u", + cmd, lba, txlen, cdb[10] >> 5, ei_lbrt); if (SERVICE_ACTION32(cdb) == WRITE_SAME_32) trace_seq_printf(p, " unmap=%u", cdb[10] >> 3 & 1); @@ -170,7 +134,7 @@ static const char * scsi_trace_unmap(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - unsigned int regions = cdb[7] << 8 | cdb[8]; + unsigned int regions = get_unaligned_be16(&cdb[7]); trace_seq_printf(p, "regions=%u", (regions - 8) / 16); trace_seq_putc(p, 0); @@ -182,8 +146,8 @@ static const char * scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p), *cmd; - sector_t lba = 0; - u32 alloc_len = 0; + u64 lba; + u32 alloc_len; switch (SERVICE_ACTION16(cdb)) { case SAI_READ_CAPACITY_16: @@ -197,21 +161,10 @@ scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len) goto out; } - lba |= ((u64)cdb[2] << 56); - lba |= ((u64)cdb[3] << 48); - lba |= ((u64)cdb[4] << 40); - lba |= ((u64)cdb[5] << 32); - lba |= (cdb[6] << 24); - lba |= (cdb[7] << 16); - lba |= (cdb[8] << 8); - lba |= cdb[9]; - alloc_len |= (cdb[10] << 24); - alloc_len |= (cdb[11] << 16); - alloc_len |= (cdb[12] << 8); - alloc_len |= cdb[13]; - - trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, - (unsigned long long)lba, alloc_len); + lba = get_unaligned_be64(&cdb[2]); + alloc_len = get_unaligned_be32(&cdb[10]); + + trace_seq_printf(p, "%s lba=%llu alloc_len=%u", cmd, lba, alloc_len); out: trace_seq_putc(p, 0); -- cgit v1.2.3 From ec990306f77fd4c58c3b27cc3b3c53032d6e6670 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Mon, 4 Nov 2019 23:26:22 +0800 Subject: scsi: fnic: fix use after free The memory chunk io_req is released by mempool_free. Accessing io_req->start_time will result in a use after free bug. The variable start_time is a backup of the timestamp. So, use start_time here to avoid use after free. Link: https://lore.kernel.org/r/1572881182-37664-1-git-send-email-bianpan2016@163.com Signed-off-by: Pan Bian Reviewed-by: Satish Kharat Signed-off-by: Martin K. Petersen --- drivers/scsi/fnic/fnic_scsi.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c index 80608b53897b..8ef150dfb6f7 100644 --- a/drivers/scsi/fnic/fnic_scsi.c +++ b/drivers/scsi/fnic/fnic_scsi.c @@ -1024,7 +1024,8 @@ static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, atomic64_inc(&fnic_stats->io_stats.io_completions); - io_duration_time = jiffies_to_msecs(jiffies) - jiffies_to_msecs(io_req->start_time); + io_duration_time = jiffies_to_msecs(jiffies) - + jiffies_to_msecs(start_time); if(io_duration_time <= 10) atomic64_inc(&fnic_stats->io_stats.io_btw_0_to_10_msec); -- cgit v1.2.3 From a16a47416d3f4f78dd8766e3278459ead45d6193 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:18 +0100 Subject: scsi: sg: sg_ioctl(): fix copyout handling First of all, __put_user() can fail with access_ok() succeeding. And access_ok() + __copy_to_user() is spelled copy_to_user()... __put_user() *can* fail with access_ok() succeeding... Link: https://lore.kernel.org/r/20191017193925.25539-1-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 43 ++++++++++++++++--------------------------- 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index cce757506383..634460421ce4 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -963,26 +963,21 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) case SG_GET_LOW_DMA: return put_user((int) sdp->device->host->unchecked_isa_dma, ip); case SG_GET_SCSI_ID: - if (!access_ok(p, sizeof (sg_scsi_id_t))) - return -EFAULT; - else { - sg_scsi_id_t __user *sg_idp = p; + { + sg_scsi_id_t v; if (atomic_read(&sdp->detaching)) return -ENODEV; - __put_user((int) sdp->device->host->host_no, - &sg_idp->host_no); - __put_user((int) sdp->device->channel, - &sg_idp->channel); - __put_user((int) sdp->device->id, &sg_idp->scsi_id); - __put_user((int) sdp->device->lun, &sg_idp->lun); - __put_user((int) sdp->device->type, &sg_idp->scsi_type); - __put_user((short) sdp->device->host->cmd_per_lun, - &sg_idp->h_cmd_per_lun); - __put_user((short) sdp->device->queue_depth, - &sg_idp->d_queue_depth); - __put_user(0, &sg_idp->unused[0]); - __put_user(0, &sg_idp->unused[1]); + memset(&v, 0, sizeof(v)); + v.host_no = sdp->device->host->host_no; + v.channel = sdp->device->channel; + v.scsi_id = sdp->device->id; + v.lun = sdp->device->lun; + v.scsi_type = sdp->device->type; + v.h_cmd_per_lun = sdp->device->host->cmd_per_lun; + v.d_queue_depth = sdp->device->queue_depth; + if (copy_to_user(p, &v, sizeof(sg_scsi_id_t))) + return -EFAULT; return 0; } case SG_SET_FORCE_PACK_ID: @@ -992,20 +987,16 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) sfp->force_packid = val ? 1 : 0; return 0; case SG_GET_PACK_ID: - if (!access_ok(ip, sizeof (int))) - return -EFAULT; read_lock_irqsave(&sfp->rq_list_lock, iflags); list_for_each_entry(srp, &sfp->rq_list, entry) { if ((1 == srp->done) && (!srp->sg_io_owned)) { read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - __put_user(srp->header.pack_id, ip); - return 0; + return put_user(srp->header.pack_id, ip); } } read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - __put_user(-1, ip); - return 0; + return put_user(-1, ip); case SG_GET_NUM_WAITING: read_lock_irqsave(&sfp->rq_list_lock, iflags); val = 0; @@ -1073,9 +1064,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) val = (sdp->device ? 1 : 0); return put_user(val, ip); case SG_GET_REQUEST_TABLE: - if (!access_ok(p, SZ_SG_REQ_INFO * SG_MAX_QUEUE)) - return -EFAULT; - else { + { sg_req_info_t *rinfo; rinfo = kcalloc(SG_MAX_QUEUE, SZ_SG_REQ_INFO, @@ -1085,7 +1074,7 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) read_lock_irqsave(&sfp->rq_list_lock, iflags); sg_fill_request_table(sfp, rinfo); read_unlock_irqrestore(&sfp->rq_list_lock, iflags); - result = __copy_to_user(p, rinfo, + result = copy_to_user(p, rinfo, SZ_SG_REQ_INFO * SG_MAX_QUEUE); result = result ? -EFAULT : 0; kfree(rinfo); -- cgit v1.2.3 From a62726cb9cb42b366f2af2c1951ae2fff66e2ad3 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:19 +0100 Subject: scsi: sg: sg_new_write(): replace access_ok() + __copy_from_user() with copy_from_user() Link: https://lore.kernel.org/r/20191017193925.25539-2-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 634460421ce4..026628aa556d 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -763,11 +763,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, sg_remove_request(sfp, srp); return -EMSGSIZE; } - if (!access_ok(hp->cmdp, hp->cmd_len)) { - sg_remove_request(sfp, srp); - return -EFAULT; /* protects following copy_from_user()s + get_user()s */ - } - if (__copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) { + if (copy_from_user(cmnd, hp->cmdp, hp->cmd_len)) { sg_remove_request(sfp, srp); return -EFAULT; } -- cgit v1.2.3 From 062c9d4527ccbdbf49139607efd44c9c3f82a2fd Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:20 +0100 Subject: scsi: sg: sg_write(): __get_user() can fail... Link: https://lore.kernel.org/r/20191017193925.25539-3-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 026628aa556d..4c62237cdf37 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -640,13 +640,15 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) if (count < (SZ_SG_HEADER + 6)) return -EIO; /* The minimum scsi command length is 6 bytes. */ + buf += SZ_SG_HEADER; + if (__get_user(opcode, buf)) + return -EFAULT; + if (!(srp = sg_add_request(sfp))) { SCSI_LOG_TIMEOUT(1, sg_printk(KERN_INFO, sdp, "sg_write: queue full\n")); return -EDOM; } - buf += SZ_SG_HEADER; - __get_user(opcode, buf); mutex_lock(&sfp->f_mutex); if (sfp->next_cmd_len > 0) { cmd_size = sfp->next_cmd_len; -- cgit v1.2.3 From c35a5cfb41509c2214228aa321509ffd91cbf063 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:21 +0100 Subject: scsi: sg: sg_read(): simplify reading ->pack_id of userland sg_io_hdr_t We don't need to allocate a temporary buffer and read the entire structure in it, only to fetch a single field and free what we'd allocated. Just use get_user() and be done with it... Link: https://lore.kernel.org/r/20191017193925.25539-4-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 4c62237cdf37..2d30e89075e9 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -441,17 +441,8 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) } if (old_hdr->reply_len < 0) { if (count >= SZ_SG_IO_HDR) { - sg_io_hdr_t *new_hdr; - new_hdr = kmalloc(SZ_SG_IO_HDR, GFP_KERNEL); - if (!new_hdr) { - retval = -ENOMEM; - goto free_old_hdr; - } - retval =__copy_from_user - (new_hdr, buf, SZ_SG_IO_HDR); - req_pack_id = new_hdr->pack_id; - kfree(new_hdr); - if (retval) { + sg_io_hdr_t __user *p = (void __user *)buf; + if (get_user(req_pack_id, &p->pack_id)) { retval = -EFAULT; goto free_old_hdr; } -- cgit v1.2.3 From d9fc5617bcb6f8278ffedd0f25bfbb697da5ca87 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:22 +0100 Subject: scsi: sg: sg_new_write(): don't bother with access_ok ... just use copy_from_user(). We copy only SZ_SG_IO_HDR bytes, so that would, strictly speaking, loosen the check. However, for call chains via ->write() the caller has actually checked the entire range and SG_IO passes exactly SZ_SG_IO_HDR for count. So no visible behaviour changes happen if we check only what we really need for copyin. Link: https://lore.kernel.org/r/20191017193925.25539-5-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 2d30e89075e9..3702f66493f7 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -717,8 +717,6 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, if (count < SZ_SG_IO_HDR) return -EINVAL; - if (!access_ok(buf, count)) - return -EFAULT; /* protects following copy_from_user()s + get_user()s */ sfp->cmd_q = 1; /* when sg_io_hdr seen, set command queuing on */ if (!(srp = sg_add_request(sfp))) { @@ -728,7 +726,7 @@ sg_new_write(Sg_fd *sfp, struct file *file, const char __user *buf, } srp->sg_io_owned = sg_io_owned; hp = &srp->header; - if (__copy_from_user(hp, buf, SZ_SG_IO_HDR)) { + if (copy_from_user(hp, buf, SZ_SG_IO_HDR)) { sg_remove_request(sfp, srp); return -EFAULT; } -- cgit v1.2.3 From c8c12792d5fe11375af54c6bbbbebdda105eb933 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:23 +0100 Subject: scsi: sg: sg_read(): get rid of access_ok()/__copy_..._user() Use copy_..._user() instead, both in sg_read() and in sg_read_oxfer(). And don't open-code memdup_user()... Link: https://lore.kernel.org/r/20191017193925.25539-6-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 3702f66493f7..9f6534a025cd 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -429,16 +429,10 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) SCSI_LOG_TIMEOUT(3, sg_printk(KERN_INFO, sdp, "sg_read: count=%d\n", (int) count)); - if (!access_ok(buf, count)) - return -EFAULT; if (sfp->force_packid && (count >= SZ_SG_HEADER)) { - old_hdr = kmalloc(SZ_SG_HEADER, GFP_KERNEL); - if (!old_hdr) - return -ENOMEM; - if (__copy_from_user(old_hdr, buf, SZ_SG_HEADER)) { - retval = -EFAULT; - goto free_old_hdr; - } + old_hdr = memdup_user(buf, SZ_SG_HEADER); + if (IS_ERR(old_hdr)) + return PTR_ERR(old_hdr); if (old_hdr->reply_len < 0) { if (count >= SZ_SG_IO_HDR) { sg_io_hdr_t __user *p = (void __user *)buf; @@ -529,7 +523,7 @@ sg_read(struct file *filp, char __user *buf, size_t count, loff_t * ppos) /* Now copy the result back to the user buffer. */ if (count >= SZ_SG_HEADER) { - if (__copy_to_user(buf, old_hdr, SZ_SG_HEADER)) { + if (copy_to_user(buf, old_hdr, SZ_SG_HEADER)) { retval = -EFAULT; goto free_old_hdr; } @@ -1960,12 +1954,12 @@ sg_read_oxfer(Sg_request * srp, char __user *outp, int num_read_xfer) num = 1 << (PAGE_SHIFT + schp->page_order); for (k = 0; k < schp->k_use_sg && schp->pages[k]; k++) { if (num > num_read_xfer) { - if (__copy_to_user(outp, page_address(schp->pages[k]), + if (copy_to_user(outp, page_address(schp->pages[k]), num_read_xfer)) return -EFAULT; break; } else { - if (__copy_to_user(outp, page_address(schp->pages[k]), + if (copy_to_user(outp, page_address(schp->pages[k]), num)) return -EFAULT; num_read_xfer -= num; -- cgit v1.2.3 From a64e5a868573d6fe3b76e8d17538b10499239631 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:24 +0100 Subject: scsi: sg: sg_write(): get rid of access_ok()/__copy_from_user()/__get_user() Just use plain copy_from_user() and get_user(). Note that while a buf-derived pointer gets stored into ->dxferp, all places that actually use the resulting value feed it either to import_iovec() or to import_single_range(), and both will do validation. Link: https://lore.kernel.org/r/20191017193925.25539-7-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index 9f6534a025cd..f3d090b93cdf 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -612,11 +612,9 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) scsi_block_when_processing_errors(sdp->device))) return -ENXIO; - if (!access_ok(buf, count)) - return -EFAULT; /* protects following copy_from_user()s + get_user()s */ if (count < SZ_SG_HEADER) return -EIO; - if (__copy_from_user(&old_hdr, buf, SZ_SG_HEADER)) + if (copy_from_user(&old_hdr, buf, SZ_SG_HEADER)) return -EFAULT; blocking = !(filp->f_flags & O_NONBLOCK); if (old_hdr.reply_len < 0) @@ -626,7 +624,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) return -EIO; /* The minimum scsi command length is 6 bytes. */ buf += SZ_SG_HEADER; - if (__get_user(opcode, buf)) + if (get_user(opcode, buf)) return -EFAULT; if (!(srp = sg_add_request(sfp))) { @@ -676,7 +674,7 @@ sg_write(struct file *filp, const char __user *buf, size_t count, loff_t * ppos) hp->flags = input_size; /* structure abuse ... */ hp->pack_id = old_hdr.pack_id; hp->usr_ptr = NULL; - if (__copy_from_user(cmnd, buf, cmd_size)) + if (copy_from_user(cmnd, buf, cmd_size)) return -EFAULT; /* * SG_DXFER_TO_FROM_DEV is functionally equivalent to SG_DXFER_FROM_DEV, -- cgit v1.2.3 From 1feefb7ec2fe11d666f6bdca6daa7affbf9c6ce9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Thu, 17 Oct 2019 20:39:25 +0100 Subject: scsi: sg: sg_ioctl(): get rid of access_ok() simply not needed there - neither sg_new_read() nor sg_new_write() need it. Link: https://lore.kernel.org/r/20191017193925.25539-8-viro@ZenIV.linux.org.uk Signed-off-by: Al Viro Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/sg.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c index f3d090b93cdf..0940abd91d3c 100644 --- a/drivers/scsi/sg.c +++ b/drivers/scsi/sg.c @@ -896,8 +896,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg) return -ENODEV; if (!scsi_block_when_processing_errors(sdp->device)) return -ENXIO; - if (!access_ok(p, SZ_SG_IO_HDR)) - return -EFAULT; result = sg_new_write(sfp, filp, p, SZ_SG_IO_HDR, 1, read_only, 1, &srp); if (result < 0) -- cgit v1.2.3 From 7cfd5639d99bec0d27af089d0c8c114330e43a72 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:56:58 -0800 Subject: scsi: lpfc: Fix duplicate unreg_rpi error in port offline flow If the driver receives a login that is later then LOGO'd by the remote port (aka ndlp), the driver, upon the completion of the LOGO ACC transmission, will logout the node and unregister the rpi that is being used for the node. As part of the unreg, the node's rpi value is replaced by the LPFC_RPI_ALLOC_ERROR value. If the port is subsequently offlined, the offline walks the nodes and ensures they are logged out, which possibly entails unreg'ing their rpi values. This path does not validate the node's rpi value, thus doesn't detect that it has been unreg'd already. The replaced rpi value is then used when accessing the rpi bitmask array which tracks active rpi values. As the LPFC_RPI_ALLOC_ERROR value is not a valid index for the bitmask, it may fault the system. Revise the rpi release code to detect when the rpi value is the replaced RPI_ALLOC_ERROR value and ignore further release steps. Link: https://lore.kernel.org/r/20191105005708.7399-2-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 294f041961a8..660f96218b25 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -18247,6 +18247,13 @@ lpfc_sli4_alloc_rpi(struct lpfc_hba *phba) static void __lpfc_sli4_free_rpi(struct lpfc_hba *phba, int rpi) { + /* + * if the rpi value indicates a prior unreg has already + * been done, skip the unreg. + */ + if (rpi == LPFC_RPI_ALLOC_ERROR) + return; + if (test_and_clear_bit(rpi, phba->sli4_hba.rpi_bmask)) { phba->sli4_hba.rpi_count--; phba->sli4_hba.max_cfg_param.rpi_used--; -- cgit v1.2.3 From 6bfb1620829825c01e1dcdd63b6a7700352babd9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:56:59 -0800 Subject: scsi: lpfc: Fix configuration of BB credit recovery in service parameters The driver today is reading service parameters from the firmware and then overwriting the firmware-provided values with values of its own. There are some switch features that require preliminary FLOGI's that are switch-specific and done prior to the actual fabric FLOGI for traffic. The fw will perform those FLOGIs and will revise the service parameters for the features configured. As the driver later overwrites those values with its own values, it misconfigures things like BBSCN use by doing so. Correct by eliminating the driver-overwrite of firmware values. The driver correctly re-reads the service parameters after each link up to obtain the latest values from firmware. Link: https://lore.kernel.org/r/20191105005708.7399-3-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 40075b391546..88507aa4e920 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1138,7 +1138,6 @@ void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - uint8_t bbscn = 0; if (pmb->u.mb.mbxStatus) goto out; @@ -1165,17 +1164,11 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Start discovery by sending a FLOGI. port_state is identically * LPFC_FLOGI while waiting for FLOGI cmpl */ - if (vport->port_state != LPFC_FLOGI) { - if (phba->bbcredit_support && phba->cfg_enable_bbcr) { - bbscn = bf_get(lpfc_bbscn_def, - &phba->sli4_hba.bbscn_params); - vport->fc_sparam.cmn.bbRcvSizeMsb &= 0xf; - vport->fc_sparam.cmn.bbRcvSizeMsb |= (bbscn << 4); - } + if (vport->port_state != LPFC_FLOGI) lpfc_initial_flogi(vport); - } else if (vport->fc_flag & FC_PT2PT) { + else if (vport->fc_flag & FC_PT2PT) lpfc_disc_start(vport); - } + return; out: -- cgit v1.2.3 From 6c1e803eac846f886cd35131e6516fc51a8414b9 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:00 -0800 Subject: scsi: lpfc: Fix kernel crash at lpfc_nvme_info_show during remote port bounce When reading sysfs nvme_info file while a remote port leaves and comes back, a NULL pointer is encountered. The issue is due to ndlp list corruption as the the nvme_info_show does not use the same lock as the rest of the code. Correct by removing the rcu_xxx_lock calls and replace by the host_lock and phba->hbaLock spinlocks that are used by the rest of the driver. Given we're called from sysfs, we are safe to use _irq rather than _irqsave. Link: https://lore.kernel.org/r/20191105005708.7399-4-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 2d090ea2b736..3f30bc02da9e 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -176,7 +176,6 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, int i; int len = 0; char tmp[LPFC_MAX_NVME_INFO_TMP_LEN] = {0}; - unsigned long iflags = 0; if (!(vport->cfg_enable_fc4_type & LPFC_ENABLE_NVME)) { len = scnprintf(buf, PAGE_SIZE, "NVME Disabled\n"); @@ -347,7 +346,6 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, if (strlcat(buf, "\nNVME Initiator Enabled\n", PAGE_SIZE) >= PAGE_SIZE) goto buffer_done; - rcu_read_lock(); scnprintf(tmp, sizeof(tmp), "XRI Dist lpfc%d Total %d IO %d ELS %d\n", phba->brd_no, @@ -355,7 +353,7 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, phba->sli4_hba.io_xri_max, lpfc_sli4_get_els_iocb_cnt(phba)); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto buffer_done; /* Port state is only one of two values for now. */ if (localport->port_id) @@ -371,15 +369,17 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, wwn_to_u64(vport->fc_nodename.u.wwn), localport->port_id, statep); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto buffer_done; + + spin_lock_irq(shost->host_lock); list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { nrport = NULL; - spin_lock_irqsave(&vport->phba->hbalock, iflags); + spin_lock(&vport->phba->hbalock); rport = lpfc_ndlp_get_nrport(ndlp); if (rport) nrport = rport->remoteport; - spin_unlock_irqrestore(&vport->phba->hbalock, iflags); + spin_unlock(&vport->phba->hbalock); if (!nrport) continue; @@ -398,39 +398,39 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, /* Tab in to show lport ownership. */ if (strlcat(buf, "NVME RPORT ", PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; if (phba->brd_no >= 10) { if (strlcat(buf, " ", PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; } scnprintf(tmp, sizeof(tmp), "WWPN x%llx ", nrport->port_name); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; scnprintf(tmp, sizeof(tmp), "WWNN x%llx ", nrport->node_name); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; scnprintf(tmp, sizeof(tmp), "DID x%06x ", nrport->port_id); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; /* An NVME rport can have multiple roles. */ if (nrport->port_role & FC_PORT_ROLE_NVME_INITIATOR) { if (strlcat(buf, "INITIATOR ", PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; } if (nrport->port_role & FC_PORT_ROLE_NVME_TARGET) { if (strlcat(buf, "TARGET ", PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; } if (nrport->port_role & FC_PORT_ROLE_NVME_DISCOVERY) { if (strlcat(buf, "DISCSRVC ", PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; } if (nrport->port_role & ~(FC_PORT_ROLE_NVME_INITIATOR | FC_PORT_ROLE_NVME_TARGET | @@ -438,14 +438,14 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, scnprintf(tmp, sizeof(tmp), "UNKNOWN ROLE x%x", nrport->port_role); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; } scnprintf(tmp, sizeof(tmp), "%s\n", statep); if (strlcat(buf, tmp, PAGE_SIZE) >= PAGE_SIZE) - goto rcu_unlock_buf_done; + goto unlock_buf_done; } - rcu_read_unlock(); + spin_unlock_irq(shost->host_lock); if (!lport) goto buffer_done; @@ -505,11 +505,11 @@ lpfc_nvme_info_show(struct device *dev, struct device_attribute *attr, atomic_read(&lport->cmpl_fcp_err)); strlcat(buf, tmp, PAGE_SIZE); - /* RCU is already unlocked. */ + /* host_lock is already unlocked. */ goto buffer_done; - rcu_unlock_buf_done: - rcu_read_unlock(); + unlock_buf_done: + spin_unlock_irq(shost->host_lock); buffer_done: len = strnlen(buf, PAGE_SIZE); -- cgit v1.2.3 From 2332e6e475b016e2026763f51333f84e2e6c57a3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:01 -0800 Subject: scsi: lpfc: Fix unexpected error messages during RSCN handling During heavy RCN activity and log_verbose = 0 we see these messages: 2754 PRLI failure DID:521245 Status:x9/xb2c00, data: x0 0231 RSCN timeout Data: x0 x3 0230 Unexpected timeout, hba link state x5 This is due to delayed RSCN activity. Correct by avoiding the timeout thus the messages by restarting the discovery timeout whenever an rscn is received. Filter PRLI responses such that severity depends on whether expected for the configuration or not. For example, PRLI errors on a fabric will be informational (they are expected), but Point-to-Point errors are not necessarily expected so they are raised to an error level. Link: https://lore.kernel.org/r/20191105005708.7399-5-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 9a1b7f331718..9a570c15b2a1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -2236,6 +2236,7 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, struct Scsi_Host *shost = lpfc_shost_from_vport(vport); IOCB_t *irsp; struct lpfc_nodelist *ndlp; + char *mode; /* we pass cmdiocb to state machine which needs rspiocb as well */ cmdiocb->context_un.rsp_iocb = rspiocb; @@ -2273,8 +2274,17 @@ lpfc_cmpl_els_prli(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, goto out; } + /* If we don't send GFT_ID to Fabric, a PRLI error + * could be expected. + */ + if ((vport->fc_flag & FC_FABRIC) || + (vport->cfg_enable_fc4_type != LPFC_ENABLE_BOTH)) + mode = KERN_ERR; + else + mode = KERN_INFO; + /* PRLI failed */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + lpfc_printf_vlog(vport, mode, LOG_ELS, "2754 PRLI failure DID:%06X Status:x%x/x%x, " "data: x%x\n", ndlp->nlp_DID, irsp->ulpStatus, @@ -6465,7 +6475,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, uint32_t payload_len, length, nportid, *cmd; int rscn_cnt; int rscn_id = 0, hba_id = 0; - int i; + int i, tmo; pcmd = (struct lpfc_dmabuf *) cmdiocb->context2; lp = (uint32_t *) pcmd->virt; @@ -6571,6 +6581,13 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DEFERRED; + + /* Restart disctmo if its already running */ + if (vport->fc_flag & FC_DISC_TMO) { + tmo = ((phba->fc_ratov * 3) + 3); + mod_timer(&vport->fc_disctmo, + jiffies + msecs_to_jiffies(1000 * tmo)); + } if ((rscn_cnt < FC_MAX_HOLD_RSCN) && !(vport->fc_flag & FC_RSCN_DISCOVERY)) { vport->fc_flag |= FC_RSCN_MODE; -- cgit v1.2.3 From dda5bdf074da3782ff9e785ee50cd2a3f214d498 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:02 -0800 Subject: scsi: lpfc: Fix dynamic fw log enablement check The recently posted patch had a typo that incorrectly tested the receiving function. Fix the typo (change == to !=) Fixes: 95bfc6d8ad86 ("scsi: lpfc: Make FW logging dynamically configurable") Link: https://lore.kernel.org/r/20191105005708.7399-6-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_attr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index 3f30bc02da9e..e7f6581935bf 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5981,7 +5981,7 @@ lpfc_ras_fwlog_buffsize_set(struct lpfc_hba *phba, uint val) if (phba->cfg_ras_fwlog_buffsize == val) return 0; - if (phba->cfg_ras_fwlog_func == PCI_FUNC(phba->pcidev->devfn)) + if (phba->cfg_ras_fwlog_func != PCI_FUNC(phba->pcidev->devfn)) return -EINVAL; spin_lock_irq(&phba->hbalock); -- cgit v1.2.3 From 69641627c653464db46f3e3d8c438349be055670 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:03 -0800 Subject: scsi: lpfc: Sync with FC-NVMe-2 SLER change to require Conf with SLER Prior to the last FC-NVME-2 draft, SLER and CONF were independent. SLER now requires CONF to be set. Revise the NVME PRLI checking to look for both inorder to enable SLER. Link: https://lore.kernel.org/r/20191105005708.7399-7-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nportdisc.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_nportdisc.c b/drivers/scsi/lpfc/lpfc_nportdisc.c index 64b7aeeea337..3bbe77c36a05 100644 --- a/drivers/scsi/lpfc/lpfc_nportdisc.c +++ b/drivers/scsi/lpfc/lpfc_nportdisc.c @@ -2121,7 +2121,9 @@ lpfc_cmpl_prli_prli_issue(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (bf_get_be32(prli_init, nvpr)) ndlp->nlp_type |= NLP_NVME_INITIATOR; - if (phba->nsler && bf_get_be32(prli_nsler, nvpr)) + if (phba->nsler && bf_get_be32(prli_nsler, nvpr) && + bf_get_be32(prli_conf, nvpr)) + ndlp->nlp_nvme_info |= NLP_NVME_NSLER; else ndlp->nlp_nvme_info &= ~NLP_NVME_NSLER; -- cgit v1.2.3 From b9da814cd5f5bb93041a6e4dbc9c5149713186ff Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:04 -0800 Subject: scsi: lpfc: Clarify FAWNN error message Current message on FAWWN events is rather cryptic. Expand the message to clarify its meaning. Link: https://lore.kernel.org/r/20191105005708.7399-8-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hbadisc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 88507aa4e920..85ada3deb47d 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -3452,8 +3452,8 @@ lpfc_mbx_cmpl_read_topology(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) phba->pport->port_state, vport->fc_flag); else if (attn_type == LPFC_ATT_UNEXP_WWPN) lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, - "1313 Link Down UNEXP WWPN Event x%x received " - "Data: x%x x%x x%x x%x x%x\n", + "1313 Link Down Unexpected FA WWPN Event x%x " + "received Data: x%x x%x x%x x%x x%x\n", la->eventTag, phba->fc_eventTag, phba->pport->port_state, vport->fc_flag, bf_get(lpfc_mbx_read_top_mm, la), -- cgit v1.2.3 From 93a4d6f40198dffcca35d9a928c409f9290f1fe0 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:05 -0800 Subject: scsi: lpfc: Add registration for CPU Offline/Online events The recent affinitization didn't address cpu offlining/onlining. If an interrupt vector is shared and the low order cpu owning the vector is offlined, as interrupts are managed, the vector is taken offline. This causes the other CPUs sharing the vector will hang as they can't get io completions. Correct by registering callbacks with the system for Offline/Online events. When a cpu is taken offline, its eq, which is tied to an interrupt vector is found. If the cpu is the "owner" of the vector and if the eq/vector is shared by other CPUs, the eq is placed into a polled mode. Additionally, code paths that perform io submission on the "sharing CPUs" will check the eq state and poll for completion after submission of new io to a wq that uses the eq. Similarly, when a cpu comes back online and owns an offlined vector, the eq is taken out of polled mode and rearmed to start driving interrupts for eq. Link: https://lore.kernel.org/r/20191105005708.7399-9-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 7 ++ drivers/scsi/lpfc/lpfc_crtn.h | 6 ++ drivers/scsi/lpfc/lpfc_init.c | 202 +++++++++++++++++++++++++++++++++++++++++- drivers/scsi/lpfc/lpfc_sli.c | 164 ++++++++++++++++++++++++++++++++-- drivers/scsi/lpfc/lpfc_sli4.h | 21 ++++- 5 files changed, 388 insertions(+), 12 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 4559f1700c6d..88d5fd99f5ec 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -1215,6 +1215,13 @@ struct lpfc_hba { uint64_t ktime_seg10_min; uint64_t ktime_seg10_max; #endif + + struct hlist_node cpuhp; /* used for cpuhp per hba callback */ + struct timer_list cpuhp_poll_timer; + struct list_head poll_list; /* slowpath eq polling list */ +#define LPFC_POLL_HB 1 /* slowpath heartbeat */ +#define LPFC_POLL_FASTPATH 0 /* called from fastpath */ +#define LPFC_POLL_SLOWPATH 1 /* called from slowpath */ }; static inline struct Scsi_Host * diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index 6e09fd98a922..d91aa5330306 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -215,6 +215,12 @@ irqreturn_t lpfc_sli_fp_intr_handler(int, void *); irqreturn_t lpfc_sli4_intr_handler(int, void *); irqreturn_t lpfc_sli4_hba_intr_handler(int, void *); +inline void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba); +int lpfc_sli4_poll_eq(struct lpfc_queue *q, uint8_t path); +void lpfc_sli4_poll_hbtimer(struct timer_list *t); +void lpfc_sli4_start_polling(struct lpfc_queue *q); +void lpfc_sli4_stop_polling(struct lpfc_queue *q); + void lpfc_read_rev(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_sli4_swap_str(struct lpfc_hba *, LPFC_MBOXQ_t *); void lpfc_config_ring(struct lpfc_hba *, int, LPFC_MBOXQ_t *); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index ec9dbc042a41..888ad32d5267 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -66,9 +67,13 @@ #include "lpfc_version.h" #include "lpfc_ids.h" +static enum cpuhp_state lpfc_cpuhp_state; /* Used when mapping IRQ vectors in a driver centric manner */ static uint32_t lpfc_present_cpu; +static void __lpfc_cpuhp_remove(struct lpfc_hba *phba); +static void lpfc_cpuhp_remove(struct lpfc_hba *phba); +static void lpfc_cpuhp_add(struct lpfc_hba *phba); static void lpfc_get_hba_model_desc(struct lpfc_hba *, uint8_t *, uint8_t *); static int lpfc_post_rcv_buf(struct lpfc_hba *); static int lpfc_sli4_queue_verify(struct lpfc_hba *); @@ -3379,6 +3384,8 @@ lpfc_online(struct lpfc_hba *phba) if (phba->cfg_xri_rebalancing) lpfc_create_multixri_pools(phba); + lpfc_cpuhp_add(phba); + lpfc_unblock_mgmt_io(phba); return 0; } @@ -3542,6 +3549,7 @@ lpfc_offline(struct lpfc_hba *phba) spin_unlock_irq(shost->host_lock); } lpfc_destroy_vport_work_array(phba, vports); + __lpfc_cpuhp_remove(phba); if (phba->cfg_xri_rebalancing) lpfc_destroy_multixri_pools(phba); @@ -9255,6 +9263,8 @@ lpfc_sli4_queue_destroy(struct lpfc_hba *phba) } spin_unlock_irq(&phba->hbalock); + lpfc_sli4_cleanup_poll_list(phba); + /* Release HBA eqs */ if (phba->sli4_hba.hdwq) lpfc_sli4_release_hdwq(phba); @@ -11057,6 +11067,170 @@ found_any: return; } +/** + * lpfc_cpuhp_get_eq + * + * @phba: pointer to lpfc hba data structure. + * @cpu: cpu going offline + * @eqlist: + */ +static void +lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, + struct list_head *eqlist) +{ + struct lpfc_vector_map_info *map; + const struct cpumask *maskp; + struct lpfc_queue *eq; + unsigned int i; + cpumask_t tmp; + u16 idx; + + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + maskp = pci_irq_get_affinity(phba->pcidev, idx); + if (!maskp) + continue; + /* + * if irq is not affinitized to the cpu going + * then we don't need to poll the eq attached + * to it. + */ + if (!cpumask_and(&tmp, maskp, cpumask_of(cpu))) + continue; + /* get the cpus that are online and are affini- + * tized to this irq vector. If the count is + * more than 1 then cpuhp is not going to shut- + * down this vector. Since this cpu has not + * gone offline yet, we need >1. + */ + cpumask_and(&tmp, maskp, cpu_online_mask); + if (cpumask_weight(&tmp) > 1) + continue; + + /* Now that we have an irq to shutdown, get the eq + * mapped to this irq. Note: multiple hdwq's in + * the software can share an eq, but eventually + * only eq will be mapped to this vector + */ + for_each_possible_cpu(i) { + map = &phba->sli4_hba.cpu_map[i]; + if (!(map->irq == pci_irq_vector(phba->pcidev, idx))) + continue; + eq = phba->sli4_hba.hdwq[map->hdwq].hba_eq; + list_add(&eq->_poll_list, eqlist); + /* 1 is good enough. others will be a copy of this */ + break; + } + } +} + +static void __lpfc_cpuhp_remove(struct lpfc_hba *phba) +{ + if (phba->sli_rev != LPFC_SLI_REV4) + return; + + cpuhp_state_remove_instance_nocalls(lpfc_cpuhp_state, + &phba->cpuhp); + /* + * unregistering the instance doesn't stop the polling + * timer. Wait for the poll timer to retire. + */ + synchronize_rcu(); + del_timer_sync(&phba->cpuhp_poll_timer); +} + +static void lpfc_cpuhp_remove(struct lpfc_hba *phba) +{ + if (phba->pport->fc_flag & FC_OFFLINE_MODE) + return; + + __lpfc_cpuhp_remove(phba); +} + +static void lpfc_cpuhp_add(struct lpfc_hba *phba) +{ + if (phba->sli_rev != LPFC_SLI_REV4) + return; + + rcu_read_lock(); + + if (!list_empty(&phba->poll_list)) { + timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); + mod_timer(&phba->cpuhp_poll_timer, + jiffies + msecs_to_jiffies(LPFC_POLL_HB)); + } + + rcu_read_unlock(); + + cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, + &phba->cpuhp); +} + +static int __lpfc_cpuhp_checks(struct lpfc_hba *phba, int *retval) +{ + if (phba->pport->load_flag & FC_UNLOADING) { + *retval = -EAGAIN; + return true; + } + + if (phba->sli_rev != LPFC_SLI_REV4) { + *retval = 0; + return true; + } + + /* proceed with the hotplug */ + return false; +} + +static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) +{ + struct lpfc_hba *phba = hlist_entry_safe(node, struct lpfc_hba, cpuhp); + struct lpfc_queue *eq, *next; + LIST_HEAD(eqlist); + int retval; + + if (!phba) { + WARN_ONCE(!phba, "cpu: %u. phba:NULL", raw_smp_processor_id()); + return 0; + } + + if (__lpfc_cpuhp_checks(phba, &retval)) + return retval; + + lpfc_cpuhp_get_eq(phba, cpu, &eqlist); + + /* start polling on these eq's */ + list_for_each_entry_safe(eq, next, &eqlist, _poll_list) { + list_del_init(&eq->_poll_list); + lpfc_sli4_start_polling(eq); + } + + return 0; +} + +static int lpfc_cpu_online(unsigned int cpu, struct hlist_node *node) +{ + struct lpfc_hba *phba = hlist_entry_safe(node, struct lpfc_hba, cpuhp); + struct lpfc_queue *eq, *next; + unsigned int n; + int retval; + + if (!phba) { + WARN_ONCE(!phba, "cpu: %u. phba:NULL", raw_smp_processor_id()); + return 0; + } + + if (__lpfc_cpuhp_checks(phba, &retval)) + return retval; + + list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list) { + n = lpfc_find_cpu_handle(phba, eq->hdwq, LPFC_FIND_BY_HDWQ); + if (n == cpu) + lpfc_sli4_stop_polling(eq); + } + + return 0; +} + /** * lpfc_sli4_enable_msix - Enable MSI-X interrupt mode to SLI-4 device * @phba: pointer to lpfc hba data structure. @@ -11460,6 +11634,9 @@ lpfc_sli4_hba_unset(struct lpfc_hba *phba) /* Wait for completion of device XRI exchange busy */ lpfc_sli4_xri_exchange_busy_wait(phba); + /* per-phba callback de-registration for hotplug event */ + lpfc_cpuhp_remove(phba); + /* Disable PCI subsystem interrupt */ lpfc_sli4_disable_intr(phba); @@ -12752,6 +12929,9 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) /* Enable RAS FW log support */ lpfc_sli4_ras_setup(phba); + INIT_LIST_HEAD(&phba->poll_list); + cpuhp_state_add_instance_nocalls(lpfc_cpuhp_state, &phba->cpuhp); + return 0; out_free_sysfs_attr: @@ -13569,11 +13749,24 @@ lpfc_init(void) /* Initialize in case vector mapping is needed */ lpfc_present_cpu = num_present_cpus(); + error = cpuhp_setup_state_multi(CPUHP_AP_ONLINE_DYN, + "lpfc/sli4:online", + lpfc_cpu_online, lpfc_cpu_offline); + if (error < 0) + goto cpuhp_failure; + lpfc_cpuhp_state = error; + error = pci_register_driver(&lpfc_driver); - if (error) { - fc_release_transport(lpfc_transport_template); - fc_release_transport(lpfc_vport_transport_template); - } + if (error) + goto unwind; + + return error; + +unwind: + cpuhp_remove_multi_state(lpfc_cpuhp_state); +cpuhp_failure: + fc_release_transport(lpfc_transport_template); + fc_release_transport(lpfc_vport_transport_template); return error; } @@ -13590,6 +13783,7 @@ lpfc_exit(void) { misc_deregister(&lpfc_mgmt_dev); pci_unregister_driver(&lpfc_driver); + cpuhp_remove_multi_state(lpfc_cpuhp_state); fc_release_transport(lpfc_transport_template); fc_release_transport(lpfc_vport_transport_template); idr_destroy(&lpfc_hba_index); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 660f96218b25..f8de313d592c 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -515,7 +515,8 @@ lpfc_sli4_eqcq_flush(struct lpfc_hba *phba, struct lpfc_queue *eq) } static int -lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq) +lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq, + uint8_t rearm) { struct lpfc_eqe *eqe; int count = 0, consumed = 0; @@ -549,8 +550,8 @@ lpfc_sli4_process_eq(struct lpfc_hba *phba, struct lpfc_queue *eq) eq->queue_claimed = 0; rearm_and_exit: - /* Always clear and re-arm the EQ */ - phba->sli4_hba.sli4_write_eq_db(phba, eq, consumed, LPFC_QUEUE_REARM); + /* Always clear the EQ. */ + phba->sli4_hba.sli4_write_eq_db(phba, eq, consumed, rearm); return count; } @@ -7948,7 +7949,7 @@ lpfc_sli4_process_missed_mbox_completions(struct lpfc_hba *phba) if (mbox_pending) /* process and rearm the EQ */ - lpfc_sli4_process_eq(phba, fpeq); + lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM); else /* Always clear and re-arm the EQ */ sli4_hba->sli4_write_eq_db(phba, fpeq, 0, LPFC_QUEUE_REARM); @@ -10113,10 +10114,13 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, struct lpfc_iocbq *piocb, uint32_t flag) { struct lpfc_sli_ring *pring; + struct lpfc_queue *eq; unsigned long iflags; int rc; if (phba->sli_rev == LPFC_SLI_REV4) { + eq = phba->sli4_hba.hdwq[piocb->hba_wqidx].hba_eq; + pring = lpfc_sli4_calc_ring(phba, piocb); if (unlikely(pring == NULL)) return IOCB_ERROR; @@ -10124,6 +10128,8 @@ lpfc_sli_issue_iocb(struct lpfc_hba *phba, uint32_t ring_number, spin_lock_irqsave(&pring->ring_lock, iflags); rc = __lpfc_sli_issue_iocb(phba, ring_number, piocb, flag); spin_unlock_irqrestore(&pring->ring_lock, iflags); + + lpfc_sli4_poll_eq(eq, LPFC_POLL_FASTPATH); } else { /* For now, SLI2/3 will still use hbalock */ spin_lock_irqsave(&phba->hbalock, iflags); @@ -14302,7 +14308,7 @@ lpfc_sli4_hba_intr_handler(int irq, void *dev_id) lpfc_sli4_mod_hba_eq_delay(phba, fpeq, LPFC_MAX_AUTO_EQ_DELAY); /* process and rearm the EQ */ - ecount = lpfc_sli4_process_eq(phba, fpeq); + ecount = lpfc_sli4_process_eq(phba, fpeq, LPFC_QUEUE_REARM); if (unlikely(ecount == 0)) { fpeq->EQ_no_entry++; @@ -14362,6 +14368,147 @@ lpfc_sli4_intr_handler(int irq, void *dev_id) return (hba_handled == true) ? IRQ_HANDLED : IRQ_NONE; } /* lpfc_sli4_intr_handler */ +void lpfc_sli4_poll_hbtimer(struct timer_list *t) +{ + struct lpfc_hba *phba = from_timer(phba, t, cpuhp_poll_timer); + struct lpfc_queue *eq; + int i = 0; + + rcu_read_lock(); + + list_for_each_entry_rcu(eq, &phba->poll_list, _poll_list) + i += lpfc_sli4_poll_eq(eq, LPFC_POLL_SLOWPATH); + if (!list_empty(&phba->poll_list)) + mod_timer(&phba->cpuhp_poll_timer, + jiffies + msecs_to_jiffies(LPFC_POLL_HB)); + + rcu_read_unlock(); +} + +inline int lpfc_sli4_poll_eq(struct lpfc_queue *eq, uint8_t path) +{ + struct lpfc_hba *phba = eq->phba; + int i = 0; + + /* + * Unlocking an irq is one of the entry point to check + * for re-schedule, but we are good for io submission + * path as midlayer does a get_cpu to glue us in. Flush + * out the invalidate queue so we can see the updated + * value for flag. + */ + smp_rmb(); + + if (READ_ONCE(eq->mode) == LPFC_EQ_POLL) + /* We will not likely get the completion for the caller + * during this iteration but i guess that's fine. + * Future io's coming on this eq should be able to + * pick it up. As for the case of single io's, they + * will be handled through a sched from polling timer + * function which is currently triggered every 1msec. + */ + i = lpfc_sli4_process_eq(phba, eq, LPFC_QUEUE_NOARM); + + return i; +} + +static inline void lpfc_sli4_add_to_poll_list(struct lpfc_queue *eq) +{ + struct lpfc_hba *phba = eq->phba; + + if (list_empty(&phba->poll_list)) { + timer_setup(&phba->cpuhp_poll_timer, lpfc_sli4_poll_hbtimer, 0); + /* kickstart slowpath processing for this eq */ + mod_timer(&phba->cpuhp_poll_timer, + jiffies + msecs_to_jiffies(LPFC_POLL_HB)); + } + + list_add_rcu(&eq->_poll_list, &phba->poll_list); + synchronize_rcu(); +} + +static inline void lpfc_sli4_remove_from_poll_list(struct lpfc_queue *eq) +{ + struct lpfc_hba *phba = eq->phba; + + /* Disable slowpath processing for this eq. Kick start the eq + * by RE-ARMING the eq's ASAP + */ + list_del_rcu(&eq->_poll_list); + synchronize_rcu(); + + if (list_empty(&phba->poll_list)) + del_timer_sync(&phba->cpuhp_poll_timer); +} + +inline void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba) +{ + struct lpfc_queue *eq, *next; + + list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list) + list_del(&eq->_poll_list); + + INIT_LIST_HEAD(&phba->poll_list); + synchronize_rcu(); +} + +static inline void +__lpfc_sli4_switch_eqmode(struct lpfc_queue *eq, uint8_t mode) +{ + if (mode == eq->mode) + return; + /* + * currently this function is only called during a hotplug + * event and the cpu on which this function is executing + * is going offline. By now the hotplug has instructed + * the scheduler to remove this cpu from cpu active mask. + * So we don't need to work about being put aside by the + * scheduler for a high priority process. Yes, the inte- + * rrupts could come but they are known to retire ASAP. + */ + + /* Disable polling in the fastpath */ + WRITE_ONCE(eq->mode, mode); + /* flush out the store buffer */ + smp_wmb(); + + /* + * Add this eq to the polling list and start polling. For + * a grace period both interrupt handler and poller will + * try to process the eq _but_ that's fine. We have a + * synchronization mechanism in place (queue_claimed) to + * deal with it. This is just a draining phase for int- + * errupt handler (not eq's) as we have guranteed through + * barrier that all the CPUs have seen the new CQ_POLLED + * state. which will effectively disable the REARMING of + * the EQ. The whole idea is eq's die off eventually as + * we are not rearming EQ's anymore. + */ + mode ? lpfc_sli4_add_to_poll_list(eq) : + lpfc_sli4_remove_from_poll_list(eq); +} + +void lpfc_sli4_start_polling(struct lpfc_queue *eq) +{ + __lpfc_sli4_switch_eqmode(eq, LPFC_EQ_POLL); +} + +void lpfc_sli4_stop_polling(struct lpfc_queue *eq) +{ + struct lpfc_hba *phba = eq->phba; + + __lpfc_sli4_switch_eqmode(eq, LPFC_EQ_INTERRUPT); + + /* Kick start for the pending io's in h/w. + * Once we switch back to interrupt processing on a eq + * the io path completion will only arm eq's when it + * receives a completion. But since eq's are in disa- + * rmed state it doesn't receive a completion. This + * creates a deadlock scenaro. + */ + phba->sli4_hba.sli4_write_eq_db(phba, eq, 0, LPFC_QUEUE_REARM); +} + /** * lpfc_sli4_queue_free - free a queue structure and associated memory * @queue: The queue structure to free. @@ -14436,6 +14583,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t page_size, return NULL; INIT_LIST_HEAD(&queue->list); + INIT_LIST_HEAD(&queue->_poll_list); INIT_LIST_HEAD(&queue->wq_list); INIT_LIST_HEAD(&queue->wqfull_list); INIT_LIST_HEAD(&queue->page_list); @@ -19757,6 +19905,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, lpfc_sli_ringtxcmpl_put(phba, pring, pwqe); spin_unlock_irqrestore(&pring->ring_lock, iflags); + + lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH); return 0; } @@ -19777,6 +19927,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } lpfc_sli_ringtxcmpl_put(phba, pring, pwqe); spin_unlock_irqrestore(&pring->ring_lock, iflags); + + lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH); return 0; } @@ -19805,6 +19957,8 @@ lpfc_sli4_issue_wqe(struct lpfc_hba *phba, struct lpfc_sli4_hdw_queue *qp, } lpfc_sli_ringtxcmpl_put(phba, pring, pwqe); spin_unlock_irqrestore(&pring->ring_lock, iflags); + + lpfc_sli4_poll_eq(qp->hba_eq, LPFC_POLL_FASTPATH); return 0; } return WQE_ERROR; diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index bbe24c19b1d9..ef32159248d7 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -133,6 +133,23 @@ struct lpfc_rqb { struct lpfc_queue { struct list_head list; struct list_head wq_list; + + /* + * If interrupts are in effect on _all_ the eq's the footprint + * of polling code is zero (except mode). This memory is chec- + * ked for every io to see if the io needs to be polled and + * while completion to check if the eq's needs to be rearmed. + * Keep in same cacheline as the queue ptr to avoid cpu fetch + * stalls. Using 1B memory will leave us with 7B hole. Fill + * it with other frequently used members. + */ + uint16_t last_cpu; /* most recent cpu */ + uint16_t hdwq; + uint8_t qe_valid; + uint8_t mode; /* interrupt or polling */ +#define LPFC_EQ_INTERRUPT 0 +#define LPFC_EQ_POLL 1 + struct list_head wqfull_list; enum lpfc_sli4_queue_type type; enum lpfc_sli4_queue_subtype subtype; @@ -240,10 +257,8 @@ struct lpfc_queue { struct delayed_work sched_spwork; uint64_t isr_timestamp; - uint16_t hdwq; - uint16_t last_cpu; /* most recent cpu */ - uint8_t qe_valid; struct lpfc_queue *assoc_qp; + struct list_head _poll_list; void **q_pgs; /* array to index entries per page */ }; -- cgit v1.2.3 From dcaa213679387e95a315dca05c57dbb15273703c Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:06 -0800 Subject: scsi: lpfc: Change default IRQ model on AMD architectures The current driver attempts to allocate an interrupt vector per cpu using the systems managed IRQ allocator (flag PCI_IRQ_AFFINITY). The system IRQ allocator will either provide the per-cpu vector, or return fewer vectors. When fewer vectors, they are evenly spread between the numa nodes on the system. When run on an AMD architecture, if interrupts occur to a cpu that is not in the same numa node as the adapter generating the interrupt, there are extreme costs and overheads in performance. Thus, if 1:1 vector allocation is used, or the "balanced" vectors in the other numa nodes, performance can be hit significantly. A much more performant model is to allocate interrupts only on the cpus that are in the numa node where the adapter resides. I/O completion is still performed by the cpu where the I/O was generated. Unfortunately, there is no flag to request the managed IRQ subsystem allocate vectors only for the CPUs in the numa node as the adapter. On AMD architecture, revert the irq allocation to the normal style (non-managed) and then use irq_set_affinity_hint() to set the cpu affinity and disable user-space rebalancing. Tie the support into CPU offline/online. If the cpu being offlined owns a vector, the vector is re-affinitized to one of the other CPUs on the same numa node. If there are no more CPUs on the numa node, the vector has all affinity removed and lets the system determine where it's serviced. Similarly, when the cpu that owned a vector comes online, the vector is reaffinitized to the cpu. Link: https://lore.kernel.org/r/20191105005708.7399-10-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc.h | 21 ++ drivers/scsi/lpfc/lpfc_attr.c | 132 +++++++++++-- drivers/scsi/lpfc/lpfc_init.c | 450 +++++++++++++++++++++++++++++++----------- drivers/scsi/lpfc/lpfc_sli4.h | 19 +- 4 files changed, 484 insertions(+), 138 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc.h b/drivers/scsi/lpfc/lpfc.h index 88d5fd99f5ec..935f98804198 100644 --- a/drivers/scsi/lpfc/lpfc.h +++ b/drivers/scsi/lpfc/lpfc.h @@ -837,6 +837,7 @@ struct lpfc_hba { uint32_t cfg_fcp_mq_threshold; uint32_t cfg_hdw_queue; uint32_t cfg_irq_chann; + uint32_t cfg_irq_numa; uint32_t cfg_suppress_rsp; uint32_t cfg_nvme_oas; uint32_t cfg_nvme_embed_cmd; @@ -1311,6 +1312,26 @@ lpfc_phba_elsring(struct lpfc_hba *phba) return &phba->sli.sli3_ring[LPFC_ELS_RING]; } +/** + * lpfc_next_online_numa_cpu - Finds next online CPU on NUMA node + * @numa_mask: Pointer to phba's numa_mask member. + * @start: starting cpu index + * + * Note: If no valid cpu found, then nr_cpu_ids is returned. + * + **/ +static inline unsigned int +lpfc_next_online_numa_cpu(const struct cpumask *numa_mask, unsigned int start) +{ + unsigned int cpu_it; + + for_each_cpu_wrap(cpu_it, numa_mask, start) { + if (cpu_online(cpu_it)) + break; + } + + return cpu_it; +} /** * lpfc_sli4_mod_hba_eq_delay - update EQ delay * @phba: Pointer to HBA context object. diff --git a/drivers/scsi/lpfc/lpfc_attr.c b/drivers/scsi/lpfc/lpfc_attr.c index e7f6581935bf..4ff82b36a37a 100644 --- a/drivers/scsi/lpfc/lpfc_attr.c +++ b/drivers/scsi/lpfc/lpfc_attr.c @@ -5331,7 +5331,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, len += scnprintf(buf + len, PAGE_SIZE - len, "CPU %02d not present\n", phba->sli4_hba.curr_disp_cpu); - else if (cpup->irq == LPFC_VECTOR_MAP_EMPTY) { + else if (cpup->eq == LPFC_VECTOR_MAP_EMPTY) { if (cpup->hdwq == LPFC_VECTOR_MAP_EMPTY) len += scnprintf( buf + len, PAGE_SIZE - len, @@ -5344,10 +5344,10 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, else len += scnprintf( buf + len, PAGE_SIZE - len, - "CPU %02d EQ %04d hdwq %04d " + "CPU %02d EQ None hdwq %04d " "physid %d coreid %d ht %d ua %d\n", phba->sli4_hba.curr_disp_cpu, - cpup->eq, cpup->hdwq, cpup->phys_id, + cpup->hdwq, cpup->phys_id, cpup->core_id, (cpup->flag & LPFC_CPU_MAP_HYPER), (cpup->flag & LPFC_CPU_MAP_UNASSIGN)); @@ -5362,7 +5362,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, cpup->core_id, (cpup->flag & LPFC_CPU_MAP_HYPER), (cpup->flag & LPFC_CPU_MAP_UNASSIGN), - cpup->irq); + lpfc_get_irq(cpup->eq)); else len += scnprintf( buf + len, PAGE_SIZE - len, @@ -5373,7 +5373,7 @@ lpfc_fcp_cpu_map_show(struct device *dev, struct device_attribute *attr, cpup->core_id, (cpup->flag & LPFC_CPU_MAP_HYPER), (cpup->flag & LPFC_CPU_MAP_UNASSIGN), - cpup->irq); + lpfc_get_irq(cpup->eq)); } phba->sli4_hba.curr_disp_cpu++; @@ -5744,7 +5744,7 @@ LPFC_ATTR_RW(nvme_embed_cmd, 1, 0, 2, * the driver will advertise it supports to the SCSI layer. * * 0 = Set nr_hw_queues by the number of CPUs or HW queues. - * 1,128 = Manually specify the maximum nr_hw_queue value to be set, + * 1,256 = Manually specify nr_hw_queue value to be advertised, * * Value range is [0,256]. Default value is 8. */ @@ -5762,30 +5762,130 @@ LPFC_ATTR_R(fcp_mq_threshold, LPFC_FCP_MQ_THRESHOLD_DEF, * A hardware IO queue maps (qidx) to a specific driver CQ/WQ. * * 0 = Configure the number of hdw queues to the number of active CPUs. - * 1,128 = Manually specify how many hdw queues to use. + * 1,256 = Manually specify how many hdw queues to use. * - * Value range is [0,128]. Default value is 0. + * Value range is [0,256]. Default value is 0. */ LPFC_ATTR_R(hdw_queue, LPFC_HBA_HDWQ_DEF, LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX, "Set the number of I/O Hardware Queues"); +static inline void +lpfc_assign_default_irq_numa(struct lpfc_hba *phba) +{ +#if IS_ENABLED(CONFIG_X86) + /* If AMD architecture, then default is LPFC_IRQ_CHANN_NUMA */ + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + phba->cfg_irq_numa = 1; + else + phba->cfg_irq_numa = 0; +#else + phba->cfg_irq_numa = 0; +#endif +} + /* * lpfc_irq_chann: Set the number of IRQ vectors that are available * for Hardware Queues to utilize. This also will map to the number * of EQ / MSI-X vectors the driver will create. This should never be * more than the number of Hardware Queues * - * 0 = Configure number of IRQ Channels to the number of active CPUs. - * 1,128 = Manually specify how many IRQ Channels to use. + * 0 = Configure number of IRQ Channels to: + * if AMD architecture, number of CPUs on HBA's NUMA node + * otherwise, number of active CPUs. + * [1,256] = Manually specify how many IRQ Channels to use. * - * Value range is [0,128]. Default value is 0. + * Value range is [0,256]. Default value is [0]. */ -LPFC_ATTR_R(irq_chann, - LPFC_HBA_HDWQ_DEF, - LPFC_HBA_HDWQ_MIN, LPFC_HBA_HDWQ_MAX, - "Set the number of I/O IRQ Channels"); +static uint lpfc_irq_chann = LPFC_IRQ_CHANN_DEF; +module_param(lpfc_irq_chann, uint, 0444); +MODULE_PARM_DESC(lpfc_irq_chann, "Set number of interrupt vectors to allocate"); + +/* lpfc_irq_chann_init - Set the hba irq_chann initial value + * @phba: lpfc_hba pointer. + * @val: contains the initial value + * + * Description: + * Validates the initial value is within range and assigns it to the + * adapter. If not in range, an error message is posted and the + * default value is assigned. + * + * Returns: + * zero if value is in range and is set + * -EINVAL if value was out of range + **/ +static int +lpfc_irq_chann_init(struct lpfc_hba *phba, uint32_t val) +{ + const struct cpumask *numa_mask; + + if (phba->cfg_use_msi != 2) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8532 use_msi = %u ignoring cfg_irq_numa\n", + phba->cfg_use_msi); + phba->cfg_irq_numa = 0; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN; + return 0; + } + + /* Check if default setting was passed */ + if (val == LPFC_IRQ_CHANN_DEF) + lpfc_assign_default_irq_numa(phba); + + if (phba->cfg_irq_numa) { + numa_mask = &phba->sli4_hba.numa_mask; + + if (cpumask_empty(numa_mask)) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8533 Could not identify NUMA node, " + "ignoring cfg_irq_numa\n"); + phba->cfg_irq_numa = 0; + phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN; + } else { + phba->cfg_irq_chann = cpumask_weight(numa_mask); + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8543 lpfc_irq_chann set to %u " + "(numa)\n", phba->cfg_irq_chann); + } + } else { + if (val > LPFC_IRQ_CHANN_MAX) { + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "8545 lpfc_irq_chann attribute cannot " + "be set to %u, allowed range is " + "[%u,%u]\n", + val, + LPFC_IRQ_CHANN_MIN, + LPFC_IRQ_CHANN_MAX); + phba->cfg_irq_chann = LPFC_IRQ_CHANN_MIN; + return -EINVAL; + } + phba->cfg_irq_chann = val; + } + + return 0; +} + +/** + * lpfc_irq_chann_show - Display value of irq_chann + * @dev: class converted to a Scsi_host structure. + * @attr: device attribute, not used. + * @buf: on return contains a string with the list sizes + * + * Returns: size of formatted string. + **/ +static ssize_t +lpfc_irq_chann_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct Scsi_Host *shost = class_to_shost(dev); + struct lpfc_vport *vport = (struct lpfc_vport *)shost->hostdata; + struct lpfc_hba *phba = vport->phba; + + return scnprintf(buf, PAGE_SIZE, "%u\n", phba->cfg_irq_chann); +} + +static DEVICE_ATTR_RO(lpfc_irq_chann); /* # lpfc_enable_hba_reset: Allow or prevent HBA resets to the hardware. @@ -7190,6 +7290,7 @@ lpfc_get_hba_function_mode(struct lpfc_hba *phba) void lpfc_get_cfgparam(struct lpfc_hba *phba) { + lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_fcp_io_sched_init(phba, lpfc_fcp_io_sched); lpfc_ns_query_init(phba, lpfc_ns_query); lpfc_fcp2_no_tgt_reset_init(phba, lpfc_fcp2_no_tgt_reset); @@ -7296,7 +7397,6 @@ lpfc_get_cfgparam(struct lpfc_hba *phba) phba->cfg_soft_wwpn = 0L; lpfc_sg_seg_cnt_init(phba, lpfc_sg_seg_cnt); lpfc_hba_queue_depth_init(phba, lpfc_hba_queue_depth); - lpfc_hba_log_verbose_init(phba, lpfc_log_verbose); lpfc_aer_support_init(phba, lpfc_aer_support); lpfc_sriov_nr_virtfn_init(phba, lpfc_sriov_nr_virtfn); lpfc_request_firmware_upgrade_init(phba, lpfc_req_fw_upgrade); diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 888ad32d5267..28e6a763f106 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -5995,6 +5996,35 @@ static void lpfc_log_intr_mode(struct lpfc_hba *phba, uint32_t intr_mode) return; } +/** + * lpfc_cpumask_of_node_init - initalizes cpumask of phba's NUMA node + * @phba: Pointer to HBA context object. + * + **/ +static void +lpfc_cpumask_of_node_init(struct lpfc_hba *phba) +{ + unsigned int cpu, numa_node; + struct cpumask *numa_mask = NULL; + +#ifdef CONFIG_NUMA + numa_node = phba->pcidev->dev.numa_node; +#else + numa_node = NUMA_NO_NODE; +#endif + numa_mask = &phba->sli4_hba.numa_mask; + + cpumask_clear(numa_mask); + + /* Check if we're a NUMA architecture */ + if (!cpumask_of_node(numa_node)) + return; + + for_each_possible_cpu(cpu) + if (cpu_to_node(cpu) == numa_node) + cpumask_set_cpu(cpu, numa_mask); +} + /** * lpfc_enable_pci_dev - Enable a generic PCI device. * @phba: pointer to lpfc hba data structure. @@ -6438,6 +6468,7 @@ lpfc_sli4_driver_resource_setup(struct lpfc_hba *phba) phba->sli4_hba.num_present_cpu = lpfc_present_cpu; phba->sli4_hba.num_possible_cpu = num_possible_cpus(); phba->sli4_hba.curr_disp_cpu = 0; + lpfc_cpumask_of_node_init(phba); /* Get all the module params for configuring this host */ lpfc_get_cfgparam(phba); @@ -6973,6 +7004,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba) phba->sli4_hba.num_possible_cpu = 0; phba->sli4_hba.num_present_cpu = 0; phba->sli4_hba.curr_disp_cpu = 0; + cpumask_clear(&phba->sli4_hba.numa_mask); /* Free memory allocated for fast-path work queue handles */ kfree(phba->sli4_hba.hba_eq_hdl); @@ -10686,7 +10718,6 @@ lpfc_find_cpu_handle(struct lpfc_hba *phba, uint16_t id, int match) */ if ((match == LPFC_FIND_BY_EQ) && (cpup->flag & LPFC_CPU_FIRST_IRQ) && - (cpup->irq != LPFC_VECTOR_MAP_EMPTY) && (cpup->eq == id)) return cpu; @@ -10724,6 +10755,75 @@ lpfc_find_hyper(struct lpfc_hba *phba, int cpu, } #endif +/* + * lpfc_assign_eq_map_info - Assigns eq for vector_map structure + * @phba: pointer to lpfc hba data structure. + * @eqidx: index for eq and irq vector + * @flag: flags to set for vector_map structure + * @cpu: cpu used to index vector_map structure + * + * The routine assigns eq info into vector_map structure + */ +static inline void +lpfc_assign_eq_map_info(struct lpfc_hba *phba, uint16_t eqidx, uint16_t flag, + unsigned int cpu) +{ + struct lpfc_vector_map_info *cpup = &phba->sli4_hba.cpu_map[cpu]; + struct lpfc_hba_eq_hdl *eqhdl = lpfc_get_eq_hdl(eqidx); + + cpup->eq = eqidx; + cpup->flag |= flag; + + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3336 Set Affinity: CPU %d irq %d eq %d flag x%x\n", + cpu, eqhdl->irq, cpup->eq, cpup->flag); +} + +/** + * lpfc_cpu_map_array_init - Initialize cpu_map structure + * @phba: pointer to lpfc hba data structure. + * + * The routine initializes the cpu_map array structure + */ +static void +lpfc_cpu_map_array_init(struct lpfc_hba *phba) +{ + struct lpfc_vector_map_info *cpup; + struct lpfc_eq_intr_info *eqi; + int cpu; + + for_each_possible_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + cpup->phys_id = LPFC_VECTOR_MAP_EMPTY; + cpup->core_id = LPFC_VECTOR_MAP_EMPTY; + cpup->hdwq = LPFC_VECTOR_MAP_EMPTY; + cpup->eq = LPFC_VECTOR_MAP_EMPTY; + cpup->flag = 0; + eqi = per_cpu_ptr(phba->sli4_hba.eq_info, cpu); + INIT_LIST_HEAD(&eqi->list); + eqi->icnt = 0; + } +} + +/** + * lpfc_hba_eq_hdl_array_init - Initialize hba_eq_hdl structure + * @phba: pointer to lpfc hba data structure. + * + * The routine initializes the hba_eq_hdl array structure + */ +static void +lpfc_hba_eq_hdl_array_init(struct lpfc_hba *phba) +{ + struct lpfc_hba_eq_hdl *eqhdl; + int i; + + for (i = 0; i < phba->cfg_irq_chann; i++) { + eqhdl = lpfc_get_eq_hdl(i); + eqhdl->irq = LPFC_VECTOR_MAP_EMPTY; + eqhdl->phba = phba; + } +} + /** * lpfc_cpu_affinity_check - Check vector CPU affinity mappings * @phba: pointer to lpfc hba data structure. @@ -10742,22 +10842,10 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) int max_core_id, min_core_id; struct lpfc_vector_map_info *cpup; struct lpfc_vector_map_info *new_cpup; - const struct cpumask *maskp; #ifdef CONFIG_X86 struct cpuinfo_x86 *cpuinfo; #endif - /* Init cpu_map array */ - for_each_possible_cpu(cpu) { - cpup = &phba->sli4_hba.cpu_map[cpu]; - cpup->phys_id = LPFC_VECTOR_MAP_EMPTY; - cpup->core_id = LPFC_VECTOR_MAP_EMPTY; - cpup->hdwq = LPFC_VECTOR_MAP_EMPTY; - cpup->eq = LPFC_VECTOR_MAP_EMPTY; - cpup->irq = LPFC_VECTOR_MAP_EMPTY; - cpup->flag = 0; - } - max_phys_id = 0; min_phys_id = LPFC_VECTOR_MAP_EMPTY; max_core_id = 0; @@ -10793,65 +10881,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) min_core_id = cpup->core_id; } - for_each_possible_cpu(i) { - struct lpfc_eq_intr_info *eqi = - per_cpu_ptr(phba->sli4_hba.eq_info, i); - - INIT_LIST_HEAD(&eqi->list); - eqi->icnt = 0; - } - - /* This loop sets up all CPUs that are affinitized with a - * irq vector assigned to the driver. All affinitized CPUs - * will get a link to that vectors IRQ and EQ. - * - * NULL affinity mask handling: - * If irq count is greater than one, log an error message. - * If the null mask is received for the first irq, find the - * first present cpu, and assign the eq index to ensure at - * least one EQ is assigned. - */ - for (idx = 0; idx < phba->cfg_irq_chann; idx++) { - /* Get a CPU mask for all CPUs affinitized to this vector */ - maskp = pci_irq_get_affinity(phba->pcidev, idx); - if (!maskp) { - if (phba->cfg_irq_chann > 1) - lpfc_printf_log(phba, KERN_ERR, LOG_INIT, - "3329 No affinity mask found " - "for vector %d (%d)\n", - idx, phba->cfg_irq_chann); - if (!idx) { - cpu = cpumask_first(cpu_present_mask); - cpup = &phba->sli4_hba.cpu_map[cpu]; - cpup->eq = idx; - cpup->irq = pci_irq_vector(phba->pcidev, idx); - cpup->flag |= LPFC_CPU_FIRST_IRQ; - } - break; - } - - i = 0; - /* Loop through all CPUs associated with vector idx */ - for_each_cpu_and(cpu, maskp, cpu_present_mask) { - /* Set the EQ index and IRQ for that vector */ - cpup = &phba->sli4_hba.cpu_map[cpu]; - cpup->eq = idx; - cpup->irq = pci_irq_vector(phba->pcidev, idx); - - /* If this is the first CPU thats assigned to this - * vector, set LPFC_CPU_FIRST_IRQ. - */ - if (!i) - cpup->flag |= LPFC_CPU_FIRST_IRQ; - i++; - - lpfc_printf_log(phba, KERN_INFO, LOG_INIT, - "3336 Set Affinity: CPU %d " - "irq %d eq %d flag x%x\n", - cpu, cpup->irq, cpup->eq, cpup->flag); - } - } - /* After looking at each irq vector assigned to this pcidev, its * possible to see that not ALL CPUs have been accounted for. * Next we will set any unassigned (unaffinitized) cpu map @@ -10877,7 +10906,7 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && - (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY) && + (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY) && (new_cpup->phys_id == cpup->phys_id)) goto found_same; new_cpu = cpumask_next( @@ -10890,7 +10919,6 @@ lpfc_cpu_affinity_check(struct lpfc_hba *phba, int vectors) found_same: /* We found a matching phys_id, so copy the IRQ info */ cpup->eq = new_cpup->eq; - cpup->irq = new_cpup->irq; /* Bump start_cpu to the next slot to minmize the * chance of having multiple unassigned CPU entries @@ -10902,9 +10930,10 @@ found_same: lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3337 Set Affinity: CPU %d " - "irq %d from id %d same " + "eq %d from peer cpu %d same " "phys_id (%d)\n", - cpu, cpup->irq, new_cpu, cpup->phys_id); + cpu, cpup->eq, new_cpu, + cpup->phys_id); } } @@ -10928,7 +10957,7 @@ found_same: for (i = 0; i < phba->sli4_hba.num_present_cpu; i++) { new_cpup = &phba->sli4_hba.cpu_map[new_cpu]; if (!(new_cpup->flag & LPFC_CPU_MAP_UNASSIGN) && - (new_cpup->irq != LPFC_VECTOR_MAP_EMPTY)) + (new_cpup->eq != LPFC_VECTOR_MAP_EMPTY)) goto found_any; new_cpu = cpumask_next( new_cpu, cpu_present_mask); @@ -10938,13 +10967,12 @@ found_same: /* We should never leave an entry unassigned */ lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3339 Set Affinity: CPU %d " - "irq %d UNASSIGNED\n", - cpup->hdwq, cpup->irq); + "eq %d UNASSIGNED\n", + cpup->hdwq, cpup->eq); continue; found_any: /* We found an available entry, copy the IRQ info */ cpup->eq = new_cpup->eq; - cpup->irq = new_cpup->irq; /* Bump start_cpu to the next slot to minmize the * chance of having multiple unassigned CPU entries @@ -10956,8 +10984,8 @@ found_any: lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "3338 Set Affinity: CPU %d " - "irq %d from id %d (%d/%d)\n", - cpu, cpup->irq, new_cpu, + "eq %d from peer cpu %d (%d/%d)\n", + cpu, cpup->eq, new_cpu, new_cpup->phys_id, new_cpup->core_id); } } @@ -10978,9 +11006,9 @@ found_any: idx++; lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3333 Set Affinity: CPU %d (phys %d core %d): " - "hdwq %d eq %d irq %d flg x%x\n", + "hdwq %d eq %d flg x%x\n", cpu, cpup->phys_id, cpup->core_id, - cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); + cpup->hdwq, cpup->eq, cpup->flag); } /* Finally we need to associate a hdwq with each cpu_map entry * This will be 1 to 1 - hdwq to cpu, unless there are less @@ -11056,9 +11084,9 @@ found_any: logit: lpfc_printf_log(phba, KERN_ERR, LOG_INIT, "3335 Set Affinity: CPU %d (phys %d core %d): " - "hdwq %d eq %d irq %d flg x%x\n", + "hdwq %d eq %d flg x%x\n", cpu, cpup->phys_id, cpup->core_id, - cpup->hdwq, cpup->eq, cpup->irq, cpup->flag); + cpup->hdwq, cpup->eq, cpup->flag); } /* The cpu_map array will be used later during initialization @@ -11078,10 +11106,8 @@ static void lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, struct list_head *eqlist) { - struct lpfc_vector_map_info *map; const struct cpumask *maskp; struct lpfc_queue *eq; - unsigned int i; cpumask_t tmp; u16 idx; @@ -11111,15 +11137,8 @@ lpfc_cpuhp_get_eq(struct lpfc_hba *phba, unsigned int cpu, * the software can share an eq, but eventually * only eq will be mapped to this vector */ - for_each_possible_cpu(i) { - map = &phba->sli4_hba.cpu_map[i]; - if (!(map->irq == pci_irq_vector(phba->pcidev, idx))) - continue; - eq = phba->sli4_hba.hdwq[map->hdwq].hba_eq; - list_add(&eq->_poll_list, eqlist); - /* 1 is good enough. others will be a copy of this */ - break; - } + eq = phba->sli4_hba.hba_eq_hdl[idx].eq; + list_add(&eq->_poll_list, eqlist); } } @@ -11181,6 +11200,99 @@ static int __lpfc_cpuhp_checks(struct lpfc_hba *phba, int *retval) return false; } +/** + * lpfc_irq_set_aff - set IRQ affinity + * @eqhdl: EQ handle + * @cpu: cpu to set affinity + * + **/ +static inline void +lpfc_irq_set_aff(struct lpfc_hba_eq_hdl *eqhdl, unsigned int cpu) +{ + cpumask_clear(&eqhdl->aff_mask); + cpumask_set_cpu(cpu, &eqhdl->aff_mask); + irq_set_status_flags(eqhdl->irq, IRQ_NO_BALANCING); + irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask); +} + +/** + * lpfc_irq_clear_aff - clear IRQ affinity + * @eqhdl: EQ handle + * + **/ +static inline void +lpfc_irq_clear_aff(struct lpfc_hba_eq_hdl *eqhdl) +{ + cpumask_clear(&eqhdl->aff_mask); + irq_clear_status_flags(eqhdl->irq, IRQ_NO_BALANCING); + irq_set_affinity_hint(eqhdl->irq, &eqhdl->aff_mask); +} + +/** + * lpfc_irq_rebalance - rebalances IRQ affinity according to cpuhp event + * @phba: pointer to HBA context object. + * @cpu: cpu going offline/online + * @offline: true, cpu is going offline. false, cpu is coming online. + * + * If cpu is going offline, we'll try our best effort to find the next + * online cpu on the phba's NUMA node and migrate all offlining IRQ affinities. + * + * If cpu is coming online, reaffinitize the IRQ back to the onlineng cpu. + * + * Note: Call only if cfg_irq_numa is enabled, otherwise rely on + * PCI_IRQ_AFFINITY to auto-manage IRQ affinity. + * + **/ +static void +lpfc_irq_rebalance(struct lpfc_hba *phba, unsigned int cpu, bool offline) +{ + struct lpfc_vector_map_info *cpup; + struct cpumask *aff_mask; + unsigned int cpu_select, cpu_next, idx; + const struct cpumask *numa_mask; + + if (!phba->cfg_irq_numa) + return; + + numa_mask = &phba->sli4_hba.numa_mask; + + if (!cpumask_test_cpu(cpu, numa_mask)) + return; + + cpup = &phba->sli4_hba.cpu_map[cpu]; + + if (!(cpup->flag & LPFC_CPU_FIRST_IRQ)) + return; + + if (offline) { + /* Find next online CPU on NUMA node */ + cpu_next = cpumask_next_wrap(cpu, numa_mask, cpu, true); + cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu_next); + + /* Found a valid CPU */ + if ((cpu_select < nr_cpu_ids) && (cpu_select != cpu)) { + /* Go through each eqhdl and ensure offlining + * cpu aff_mask is migrated + */ + for (idx = 0; idx < phba->cfg_irq_chann; idx++) { + aff_mask = lpfc_get_aff_mask(idx); + + /* Migrate affinity */ + if (cpumask_test_cpu(cpu, aff_mask)) + lpfc_irq_set_aff(lpfc_get_eq_hdl(idx), + cpu_select); + } + } else { + /* Rely on irqbalance if no online CPUs left on NUMA */ + for (idx = 0; idx < phba->cfg_irq_chann; idx++) + lpfc_irq_clear_aff(lpfc_get_eq_hdl(idx)); + } + } else { + /* Migrate affinity back to this CPU */ + lpfc_irq_set_aff(lpfc_get_eq_hdl(cpup->eq), cpu); + } +} + static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) { struct lpfc_hba *phba = hlist_entry_safe(node, struct lpfc_hba, cpuhp); @@ -11196,6 +11308,8 @@ static int lpfc_cpu_offline(unsigned int cpu, struct hlist_node *node) if (__lpfc_cpuhp_checks(phba, &retval)) return retval; + lpfc_irq_rebalance(phba, cpu, true); + lpfc_cpuhp_get_eq(phba, cpu, &eqlist); /* start polling on these eq's */ @@ -11222,6 +11336,8 @@ static int lpfc_cpu_online(unsigned int cpu, struct hlist_node *node) if (__lpfc_cpuhp_checks(phba, &retval)) return retval; + lpfc_irq_rebalance(phba, cpu, false); + list_for_each_entry_safe(eq, next, &phba->poll_list, _poll_list) { n = lpfc_find_cpu_handle(phba, eq->hdwq, LPFC_FIND_BY_HDWQ); if (n == cpu) @@ -11236,7 +11352,24 @@ static int lpfc_cpu_online(unsigned int cpu, struct hlist_node *node) * @phba: pointer to lpfc hba data structure. * * This routine is invoked to enable the MSI-X interrupt vectors to device - * with SLI-4 interface spec. + * with SLI-4 interface spec. It also allocates MSI-X vectors and maps them + * to cpus on the system. + * + * When cfg_irq_numa is enabled, the adapter will only allocate vectors for + * the number of cpus on the same numa node as this adapter. The vectors are + * allocated without requesting OS affinity mapping. A vector will be + * allocated and assigned to each online and offline cpu. If the cpu is + * online, then affinity will be set to that cpu. If the cpu is offline, then + * affinity will be set to the nearest peer cpu within the numa node that is + * online. If there are no online cpus within the numa node, affinity is not + * assigned and the OS may do as it pleases. Note: cpu vector affinity mapping + * is consistent with the way cpu online/offline is handled when cfg_irq_numa is + * configured. + * + * If numa mode is not enabled and there is more than 1 vector allocated, then + * the driver relies on the managed irq interface where the OS assigns vector to + * cpu affinity. The driver will then use that affinity mapping to setup its + * cpu mapping table. * * Return codes * 0 - successful @@ -11247,13 +11380,31 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) { int vectors, rc, index; char *name; + const struct cpumask *numa_mask = NULL; + unsigned int cpu = 0, cpu_cnt = 0, cpu_select = nr_cpu_ids; + struct lpfc_hba_eq_hdl *eqhdl; + const struct cpumask *maskp; + bool first; + unsigned int flags = PCI_IRQ_MSIX; /* Set up MSI-X multi-message vectors */ vectors = phba->cfg_irq_chann; - rc = pci_alloc_irq_vectors(phba->pcidev, - 1, - vectors, PCI_IRQ_MSIX | PCI_IRQ_AFFINITY); + if (phba->cfg_irq_numa) { + numa_mask = &phba->sli4_hba.numa_mask; + cpu_cnt = cpumask_weight(numa_mask); + vectors = min(phba->cfg_irq_chann, cpu_cnt); + + /* cpu: iterates over numa_mask including offline or online + * cpu_select: iterates over online numa_mask to set affinity + */ + cpu = cpumask_first(numa_mask); + cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu); + } else { + flags |= PCI_IRQ_AFFINITY; + } + + rc = pci_alloc_irq_vectors(phba->pcidev, 1, vectors, flags); if (rc < 0) { lpfc_printf_log(phba, KERN_INFO, LOG_INIT, "0484 PCI enable MSI-X failed (%d)\n", rc); @@ -11263,23 +11414,61 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) /* Assign MSI-X vectors to interrupt handlers */ for (index = 0; index < vectors; index++) { - name = phba->sli4_hba.hba_eq_hdl[index].handler_name; + eqhdl = lpfc_get_eq_hdl(index); + name = eqhdl->handler_name; memset(name, 0, LPFC_SLI4_HANDLER_NAME_SZ); snprintf(name, LPFC_SLI4_HANDLER_NAME_SZ, LPFC_DRIVER_HANDLER_NAME"%d", index); - phba->sli4_hba.hba_eq_hdl[index].idx = index; - phba->sli4_hba.hba_eq_hdl[index].phba = phba; + eqhdl->idx = index; rc = request_irq(pci_irq_vector(phba->pcidev, index), &lpfc_sli4_hba_intr_handler, 0, - name, - &phba->sli4_hba.hba_eq_hdl[index]); + name, eqhdl); if (rc) { lpfc_printf_log(phba, KERN_WARNING, LOG_INIT, "0486 MSI-X fast-path (%d) " "request_irq failed (%d)\n", index, rc); goto cfg_fail_out; } + + eqhdl->irq = pci_irq_vector(phba->pcidev, index); + + if (phba->cfg_irq_numa) { + /* If found a neighboring online cpu, set affinity */ + if (cpu_select < nr_cpu_ids) + lpfc_irq_set_aff(eqhdl, cpu_select); + + /* Assign EQ to cpu_map */ + lpfc_assign_eq_map_info(phba, index, + LPFC_CPU_FIRST_IRQ, + cpu); + + /* Iterate to next offline or online cpu in numa_mask */ + cpu = cpumask_next(cpu, numa_mask); + + /* Find next online cpu in numa_mask to set affinity */ + cpu_select = lpfc_next_online_numa_cpu(numa_mask, cpu); + } else if (vectors == 1) { + cpu = cpumask_first(cpu_present_mask); + lpfc_assign_eq_map_info(phba, index, LPFC_CPU_FIRST_IRQ, + cpu); + } else { + maskp = pci_irq_get_affinity(phba->pcidev, index); + + first = true; + /* Loop through all CPUs associated with vector index */ + for_each_cpu_and(cpu, maskp, cpu_present_mask) { + /* If this is the first CPU thats assigned to + * this vector, set LPFC_CPU_FIRST_IRQ. + */ + lpfc_assign_eq_map_info(phba, index, + first ? + LPFC_CPU_FIRST_IRQ : 0, + cpu); + if (first) + first = false; + } + } } if (vectors != phba->cfg_irq_chann) { @@ -11295,9 +11484,12 @@ lpfc_sli4_enable_msix(struct lpfc_hba *phba) cfg_fail_out: /* free the irq already requested */ - for (--index; index >= 0; index--) - free_irq(pci_irq_vector(phba->pcidev, index), - &phba->sli4_hba.hba_eq_hdl[index]); + for (--index; index >= 0; index--) { + eqhdl = lpfc_get_eq_hdl(index); + lpfc_irq_clear_aff(eqhdl); + irq_set_affinity_hint(eqhdl->irq, NULL); + free_irq(eqhdl->irq, eqhdl); + } /* Unconfigure MSI-X capability structure */ pci_free_irq_vectors(phba->pcidev); @@ -11324,6 +11516,8 @@ static int lpfc_sli4_enable_msi(struct lpfc_hba *phba) { int rc, index; + unsigned int cpu; + struct lpfc_hba_eq_hdl *eqhdl; rc = pci_alloc_irq_vectors(phba->pcidev, 1, 1, PCI_IRQ_MSI | PCI_IRQ_AFFINITY); @@ -11345,9 +11539,15 @@ lpfc_sli4_enable_msi(struct lpfc_hba *phba) return rc; } + eqhdl = lpfc_get_eq_hdl(0); + eqhdl->irq = pci_irq_vector(phba->pcidev, 0); + + cpu = cpumask_first(cpu_present_mask); + lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, cpu); + for (index = 0; index < phba->cfg_irq_chann; index++) { - phba->sli4_hba.hba_eq_hdl[index].idx = index; - phba->sli4_hba.hba_eq_hdl[index].phba = phba; + eqhdl = lpfc_get_eq_hdl(index); + eqhdl->idx = index; } return 0; @@ -11380,7 +11580,9 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) retval = 0; if (!retval) { /* Now, try to enable MSI-X interrupt mode */ + get_online_cpus(); retval = lpfc_sli4_enable_msix(phba); + put_online_cpus(); if (!retval) { /* Indicate initialization to MSI-X mode */ phba->intr_type = MSIX; @@ -11405,15 +11607,21 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) IRQF_SHARED, LPFC_DRIVER_NAME, phba); if (!retval) { struct lpfc_hba_eq_hdl *eqhdl; + unsigned int cpu; /* Indicate initialization to INTx mode */ phba->intr_type = INTx; intr_mode = 0; + eqhdl = lpfc_get_eq_hdl(0); + eqhdl->irq = pci_irq_vector(phba->pcidev, 0); + + cpu = cpumask_first(cpu_present_mask); + lpfc_assign_eq_map_info(phba, 0, LPFC_CPU_FIRST_IRQ, + cpu); for (idx = 0; idx < phba->cfg_irq_chann; idx++) { - eqhdl = &phba->sli4_hba.hba_eq_hdl[idx]; + eqhdl = lpfc_get_eq_hdl(idx); eqhdl->idx = idx; - eqhdl->phba = phba; } } } @@ -11435,14 +11643,14 @@ lpfc_sli4_disable_intr(struct lpfc_hba *phba) /* Disable the currently initialized interrupt mode */ if (phba->intr_type == MSIX) { int index; + struct lpfc_hba_eq_hdl *eqhdl; /* Free up MSI-X multi-message vectors */ for (index = 0; index < phba->cfg_irq_chann; index++) { - irq_set_affinity_hint( - pci_irq_vector(phba->pcidev, index), - NULL); - free_irq(pci_irq_vector(phba->pcidev, index), - &phba->sli4_hba.hba_eq_hdl[index]); + eqhdl = lpfc_get_eq_hdl(index); + lpfc_irq_clear_aff(eqhdl); + irq_set_affinity_hint(eqhdl->irq, NULL); + free_irq(eqhdl->irq, eqhdl); } } else { free_irq(phba->pcidev->irq, phba); @@ -12848,6 +13056,12 @@ lpfc_pci_probe_one_s4(struct pci_dev *pdev, const struct pci_device_id *pid) phba->pport = NULL; lpfc_stop_port(phba); + /* Init cpu_map array */ + lpfc_cpu_map_array_init(phba); + + /* Init hba_eq_hdl array */ + lpfc_hba_eq_hdl_array_init(phba); + /* Configure and enable interrupt */ intr_mode = lpfc_sli4_enable_intr(phba, cfg_mode); if (intr_mode == LPFC_INTR_ERROR) { diff --git a/drivers/scsi/lpfc/lpfc_sli4.h b/drivers/scsi/lpfc/lpfc_sli4.h index ef32159248d7..d963ca871383 100644 --- a/drivers/scsi/lpfc/lpfc_sli4.h +++ b/drivers/scsi/lpfc/lpfc_sli4.h @@ -41,8 +41,13 @@ /* Multi-queue arrangement for FCP EQ/CQ/WQ tuples */ #define LPFC_HBA_HDWQ_MIN 0 -#define LPFC_HBA_HDWQ_MAX 128 -#define LPFC_HBA_HDWQ_DEF 0 +#define LPFC_HBA_HDWQ_MAX 256 +#define LPFC_HBA_HDWQ_DEF LPFC_HBA_HDWQ_MIN + +/* irq_chann range, values */ +#define LPFC_IRQ_CHANN_MIN 0 +#define LPFC_IRQ_CHANN_MAX 256 +#define LPFC_IRQ_CHANN_DEF LPFC_IRQ_CHANN_MIN /* FCP MQ queue count limiting */ #define LPFC_FCP_MQ_THRESHOLD_MIN 0 @@ -467,11 +472,17 @@ struct lpfc_hba; #define LPFC_SLI4_HANDLER_NAME_SZ 16 struct lpfc_hba_eq_hdl { uint32_t idx; + uint16_t irq; char handler_name[LPFC_SLI4_HANDLER_NAME_SZ]; struct lpfc_hba *phba; struct lpfc_queue *eq; + struct cpumask aff_mask; }; +#define lpfc_get_eq_hdl(eqidx) (&phba->sli4_hba.hba_eq_hdl[eqidx]) +#define lpfc_get_aff_mask(eqidx) (&phba->sli4_hba.hba_eq_hdl[eqidx].aff_mask) +#define lpfc_get_irq(eqidx) (phba->sli4_hba.hba_eq_hdl[eqidx].irq) + /*BB Credit recovery value*/ struct lpfc_bbscn_params { uint32_t word0; @@ -561,11 +572,10 @@ struct lpfc_sli4_lnk_info { #define LPFC_SLI4_HANDLER_CNT (LPFC_HBA_IO_CHAN_MAX+ \ LPFC_FOF_IO_CHAN_NUM) -/* Used for IRQ vector to CPU mapping */ +/* Used for tracking CPU mapping attributes */ struct lpfc_vector_map_info { uint16_t phys_id; uint16_t core_id; - uint16_t irq; uint16_t eq; uint16_t hdwq; uint16_t flag; @@ -908,6 +918,7 @@ struct lpfc_sli4_hba { struct lpfc_vector_map_info *cpu_map; uint16_t num_possible_cpu; uint16_t num_present_cpu; + struct cpumask numa_mask; uint16_t curr_disp_cpu; struct lpfc_eq_intr_info __percpu *eq_info; uint32_t conf_trunk; -- cgit v1.2.3 From 171f6c41949f6e9d5e09dcac842a10bf8dda8dcc Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:07 -0800 Subject: scsi: lpfc: Add enablement of multiple adapter dumps Some adapters support the ability to hold multiple adapter dumps on the adapter flash. Some adapters default to enabling this feature while others default to single-dump. Make support uniform by enabling dual dump by default. Link: https://lore.kernel.org/r/20191105005708.7399-11-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_hw4.h | 10 ++++++++++ drivers/scsi/lpfc/lpfc_sli.c | 27 ++++++++++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_hw4.h b/drivers/scsi/lpfc/lpfc_hw4.h index 9daa2b494b5c..25cdcbc2b02f 100644 --- a/drivers/scsi/lpfc/lpfc_hw4.h +++ b/drivers/scsi/lpfc/lpfc_hw4.h @@ -3530,6 +3530,7 @@ struct lpfc_sli4_parameters { #define LPFC_SET_UE_RECOVERY 0x10 #define LPFC_SET_MDS_DIAGS 0x11 +#define LPFC_SET_DUAL_DUMP 0x1e struct lpfc_mbx_set_feature { struct mbox_header header; uint32_t feature; @@ -3544,6 +3545,15 @@ struct lpfc_mbx_set_feature { #define lpfc_mbx_set_feature_mds_deep_loopbk_SHIFT 1 #define lpfc_mbx_set_feature_mds_deep_loopbk_MASK 0x00000001 #define lpfc_mbx_set_feature_mds_deep_loopbk_WORD word6 +#define lpfc_mbx_set_feature_dd_SHIFT 0 +#define lpfc_mbx_set_feature_dd_MASK 0x00000001 +#define lpfc_mbx_set_feature_dd_WORD word6 +#define lpfc_mbx_set_feature_ddquery_SHIFT 1 +#define lpfc_mbx_set_feature_ddquery_MASK 0x00000001 +#define lpfc_mbx_set_feature_ddquery_WORD word6 +#define LPFC_DISABLE_DUAL_DUMP 0 +#define LPFC_ENABLE_DUAL_DUMP 1 +#define LPFC_QUERY_OP_DUAL_DUMP 2 uint32_t word7; #define lpfc_mbx_set_feature_UERP_SHIFT 0 #define lpfc_mbx_set_feature_UERP_MASK 0x0000ffff diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index f8de313d592c..fad890cea21a 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -6203,6 +6203,14 @@ lpfc_set_features(struct lpfc_hba *phba, LPFC_MBOXQ_t *mbox, mbox->u.mqe.un.set_feature.feature = LPFC_SET_MDS_DIAGS; mbox->u.mqe.un.set_feature.param_len = 8; break; + case LPFC_SET_DUAL_DUMP: + bf_set(lpfc_mbx_set_feature_dd, + &mbox->u.mqe.un.set_feature, LPFC_ENABLE_DUAL_DUMP); + bf_set(lpfc_mbx_set_feature_ddquery, + &mbox->u.mqe.un.set_feature, 0); + mbox->u.mqe.un.set_feature.feature = LPFC_SET_DUAL_DUMP; + mbox->u.mqe.un.set_feature.param_len = 4; + break; } return; @@ -7200,7 +7208,7 @@ lpfc_post_rq_buffer(struct lpfc_hba *phba, struct lpfc_queue *hrq, int lpfc_sli4_hba_setup(struct lpfc_hba *phba) { - int rc, i, cnt, len; + int rc, i, cnt, len, dd; LPFC_MBOXQ_t *mboxq; struct lpfc_mqe *mqe; uint8_t *vpd; @@ -7451,6 +7459,23 @@ lpfc_sli4_hba_setup(struct lpfc_hba *phba) phba->sli3_options |= (LPFC_SLI3_NPIV_ENABLED | LPFC_SLI3_HBQ_ENABLED); spin_unlock_irq(&phba->hbalock); + /* Always try to enable dual dump feature if we can */ + lpfc_set_features(phba, mboxq, LPFC_SET_DUAL_DUMP); + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_POLL); + dd = bf_get(lpfc_mbx_set_feature_dd, &mboxq->u.mqe.un.set_feature); + if ((rc == MBX_SUCCESS) && (dd == LPFC_ENABLE_DUAL_DUMP)) + lpfc_printf_log(phba, KERN_ERR, LOG_SLI | LOG_INIT, + "6448 Dual Dump is enabled\n"); + else + lpfc_printf_log(phba, KERN_INFO, LOG_SLI | LOG_INIT, + "6447 Dual Dump Mailbox x%x (x%x/x%x) failed, " + "rc:x%x dd:x%x\n", + bf_get(lpfc_mqe_command, &mboxq->u.mqe), + lpfc_sli_config_mbox_subsys_get( + phba, mboxq), + lpfc_sli_config_mbox_opcode_get( + phba, mboxq), + rc, dd); /* * Allocate all resources (xri,rpi,vpi,vfi) now. Subsequent * calls depends on these resources to complete port setup. -- cgit v1.2.3 From aff6ab9e7221c1b5d15418419b9797e5badd4aec Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 4 Nov 2019 16:57:08 -0800 Subject: scsi: lpfc: Update lpfc version to 12.6.0.1 Update lpfc version to 12.6.0.1 Link: https://lore.kernel.org/r/20191105005708.7399-12-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index ed1b10b0161e..1532390770f5 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 "12.6.0.0" +#define LPFC_DRIVER_VERSION "12.6.0.1" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From f6b8540f40201bff91062dd64db8e29e4ddaaa9d Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 5 Nov 2019 13:55:53 -0800 Subject: scsi: tracing: Fix handling of TRANSFER LENGTH == 0 for READ(6) and WRITE(6) According to SBC-2 a TRANSFER LENGTH field of zero means that 256 logical blocks must be transferred. Make the SCSI tracing code follow SBC-2. Fixes: bf8162354233 ("[SCSI] add scsi trace core functions and put trace points") Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Douglas Gilbert Link: https://lore.kernel.org/r/20191105215553.185018-1-bvanassche@acm.org Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_trace.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c index 784ed9a32a0d..ac35c301c792 100644 --- a/drivers/scsi/scsi_trace.c +++ b/drivers/scsi/scsi_trace.c @@ -18,15 +18,18 @@ static const char * scsi_trace_rw6(struct trace_seq *p, unsigned char *cdb, int len) { const char *ret = trace_seq_buffer_ptr(p); - sector_t lba = 0, txlen = 0; + u32 lba = 0, txlen; lba |= ((cdb[1] & 0x1F) << 16); lba |= (cdb[2] << 8); lba |= cdb[3]; - txlen = cdb[4]; + /* + * From SBC-2: a TRANSFER LENGTH field set to zero specifies that 256 + * logical blocks shall be read (READ(6)) or written (WRITE(6)). + */ + txlen = cdb[4] ? cdb[4] : 256; - trace_seq_printf(p, "lba=%llu txlen=%llu", - (unsigned long long)lba, (unsigned long long)txlen); + trace_seq_printf(p, "lba=%u txlen=%u", lba, txlen); trace_seq_putc(p, 0); return ret; -- cgit v1.2.3 From a572d24af4d16e70743feb0b4decb17aaae7ce43 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Mon, 28 Oct 2019 13:38:20 +0100 Subject: scsi: target: iscsi: CHAP: add support for SHA1, SHA256 and SHA3-256 This patch modifies the chap_server_compute_hash() function to make it agnostic to the choice of hash algorithm that is used. It also adds support to three new hash algorithms: SHA1, SHA256 and SHA3-256. The chap_got_response() function has been removed because the digest type validity is already checked by chap_server_open() Link: https://lore.kernel.org/r/20191028123822.5864-2-mlombard@redhat.com Signed-off-by: Maurizio Lombardi Tested-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_auth.c | 169 ++++++++++++++++++++----------- drivers/target/iscsi/iscsi_target_auth.h | 13 ++- 2 files changed, 120 insertions(+), 62 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index 8fe9b12a07a4..b09f20842e40 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -18,6 +18,22 @@ #include "iscsi_target_nego.h" #include "iscsi_target_auth.h" +static char *chap_get_digest_name(const int digest_type) +{ + switch (digest_type) { + case CHAP_DIGEST_MD5: + return "md5"; + case CHAP_DIGEST_SHA1: + return "sha1"; + case CHAP_DIGEST_SHA256: + return "sha256"; + case CHAP_DIGEST_SHA3_256: + return "sha3-256"; + default: + return NULL; + } +} + static int chap_gen_challenge( struct iscsi_conn *conn, int caller, @@ -46,9 +62,23 @@ static int chap_gen_challenge( return 0; } +static int chap_test_algorithm(const char *name) +{ + struct crypto_shash *tfm; + + tfm = crypto_alloc_shash(name, 0, 0); + if (IS_ERR(tfm)) + return -1; + + crypto_free_shash(tfm); + return 0; +} + static int chap_check_algorithm(const char *a_str) { - char *tmp, *orig, *token; + char *tmp, *orig, *token, *digest_name; + long digest_type; + int r = CHAP_DIGEST_UNKNOWN; tmp = kstrdup(a_str, GFP_KERNEL); if (!tmp) { @@ -70,15 +100,24 @@ static int chap_check_algorithm(const char *a_str) if (!token) goto out; - if (!strcmp(token, "5")) { - pr_debug("Selected MD5 Algorithm\n"); - kfree(orig); - return CHAP_DIGEST_MD5; + if (kstrtol(token, 10, &digest_type)) + continue; + + digest_name = chap_get_digest_name(digest_type); + if (!digest_name) + continue; + + pr_debug("Selected %s Algorithm\n", digest_name); + if (chap_test_algorithm(digest_name) < 0) { + pr_err("failed to allocate %s algo\n", digest_name); + } else { + r = digest_type; + goto out; } } out: kfree(orig); - return CHAP_DIGEST_UNKNOWN; + return r; } static void chap_close(struct iscsi_conn *conn) @@ -94,7 +133,7 @@ static struct iscsi_chap *chap_server_open( char *aic_str, unsigned int *aic_len) { - int ret; + int digest_type; struct iscsi_chap *chap; if (!(auth->naf_flags & NAF_USERID_SET) || @@ -109,17 +148,19 @@ static struct iscsi_chap *chap_server_open( return NULL; chap = conn->auth_protocol; - ret = chap_check_algorithm(a_str); - switch (ret) { + digest_type = chap_check_algorithm(a_str); + switch (digest_type) { case CHAP_DIGEST_MD5: - pr_debug("[server] Got CHAP_A=5\n"); - /* - * Send back CHAP_A set to MD5. - */ - *aic_len = sprintf(aic_str, "CHAP_A=5"); - *aic_len += 1; - chap->digest_type = CHAP_DIGEST_MD5; - pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type); + chap->digest_size = MD5_SIGNATURE_SIZE; + break; + case CHAP_DIGEST_SHA1: + chap->digest_size = SHA1_SIGNATURE_SIZE; + break; + case CHAP_DIGEST_SHA256: + chap->digest_size = SHA256_SIGNATURE_SIZE; + break; + case CHAP_DIGEST_SHA3_256: + chap->digest_size = SHA3_256_SIGNATURE_SIZE; break; case CHAP_DIGEST_UNKNOWN: default: @@ -128,6 +169,13 @@ static struct iscsi_chap *chap_server_open( return NULL; } + chap->digest_name = chap_get_digest_name(digest_type); + + pr_debug("[server] Got CHAP_A=%d\n", digest_type); + *aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type); + *aic_len += 1; + pr_debug("[server] Sending CHAP_A=%d\n", digest_type); + /* * Set Identifier. */ @@ -146,7 +194,7 @@ static struct iscsi_chap *chap_server_open( return chap; } -static int chap_server_compute_md5( +static int chap_server_compute_hash( struct iscsi_conn *conn, struct iscsi_node_auth *auth, char *nr_in_ptr, @@ -155,12 +203,13 @@ static int chap_server_compute_md5( { unsigned long id; unsigned char id_as_uchar; - unsigned char digest[MD5_SIGNATURE_SIZE]; - unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2]; + unsigned char type; unsigned char identifier[10], *challenge = NULL; unsigned char *challenge_binhex = NULL; - unsigned char client_digest[MD5_SIGNATURE_SIZE]; - unsigned char server_digest[MD5_SIGNATURE_SIZE]; + unsigned char *digest = NULL; + unsigned char *response = NULL; + unsigned char *client_digest = NULL; + unsigned char *server_digest = NULL; unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH]; size_t compare_len; struct iscsi_chap *chap = conn->auth_protocol; @@ -168,13 +217,33 @@ static int chap_server_compute_md5( struct shash_desc *desc = NULL; int auth_ret = -1, ret, challenge_len; + digest = kzalloc(chap->digest_size, GFP_KERNEL); + if (!digest) { + pr_err("Unable to allocate the digest buffer\n"); + goto out; + } + + response = kzalloc(chap->digest_size * 2 + 2, GFP_KERNEL); + if (!response) { + pr_err("Unable to allocate the response buffer\n"); + goto out; + } + + client_digest = kzalloc(chap->digest_size, GFP_KERNEL); + if (!client_digest) { + pr_err("Unable to allocate the client_digest buffer\n"); + goto out; + } + + server_digest = kzalloc(chap->digest_size, GFP_KERNEL); + if (!server_digest) { + pr_err("Unable to allocate the server_digest buffer\n"); + goto out; + } + memset(identifier, 0, 10); memset(chap_n, 0, MAX_CHAP_N_SIZE); memset(chap_r, 0, MAX_RESPONSE_LENGTH); - memset(digest, 0, MD5_SIGNATURE_SIZE); - memset(response, 0, MD5_SIGNATURE_SIZE * 2 + 2); - memset(client_digest, 0, MD5_SIGNATURE_SIZE); - memset(server_digest, 0, MD5_SIGNATURE_SIZE); challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); if (!challenge) { @@ -219,18 +288,18 @@ static int chap_server_compute_md5( pr_err("Could not find CHAP_R.\n"); goto out; } - if (strlen(chap_r) != MD5_SIGNATURE_SIZE * 2) { + if (strlen(chap_r) != chap->digest_size * 2) { pr_err("Malformed CHAP_R\n"); goto out; } - if (hex2bin(client_digest, chap_r, MD5_SIGNATURE_SIZE) < 0) { + if (hex2bin(client_digest, chap_r, chap->digest_size) < 0) { pr_err("Malformed CHAP_R\n"); goto out; } pr_debug("[server] Got CHAP_R=%s\n", chap_r); - tfm = crypto_alloc_shash("md5", 0, 0); + tfm = crypto_alloc_shash(chap->digest_name, 0, 0); if (IS_ERR(tfm)) { tfm = NULL; pr_err("Unable to allocate struct crypto_shash\n"); @@ -271,15 +340,15 @@ static int chap_server_compute_md5( goto out; } - bin2hex(response, server_digest, MD5_SIGNATURE_SIZE); - pr_debug("[server] MD5 Server Digest: %s\n", response); + bin2hex(response, server_digest, chap->digest_size); + pr_debug("[server] %s Server Digest: %s\n", hash_name, response); - if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) { - pr_debug("[server] MD5 Digests do not match!\n\n"); + if (memcmp(server_digest, client_digest, chap->digest_size) != 0) { + pr_debug("[server] %s Digests do not match!\n\n", hash_name); goto out; } else - pr_debug("[server] MD5 Digests match, CHAP connection" - " successful.\n\n"); + pr_debug("[server] %s Digests match, CHAP connection" + " successful.\n\n", hash_name); /* * One way authentication has succeeded, return now if mutual * authentication is not enabled. @@ -393,7 +462,7 @@ static int chap_server_compute_md5( /* * Convert response from binary hex to ascii hext. */ - bin2hex(response, digest, MD5_SIGNATURE_SIZE); + bin2hex(response, digest, chap->digest_size); *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s", response); *nr_out_len += 1; @@ -405,31 +474,13 @@ out: crypto_free_shash(tfm); kfree(challenge); kfree(challenge_binhex); + kfree(digest); + kfree(response); + kfree(server_digest); + kfree(client_digest); return auth_ret; } -static int chap_got_response( - struct iscsi_conn *conn, - struct iscsi_node_auth *auth, - char *nr_in_ptr, - char *nr_out_ptr, - unsigned int *nr_out_len) -{ - struct iscsi_chap *chap = conn->auth_protocol; - - switch (chap->digest_type) { - case CHAP_DIGEST_MD5: - if (chap_server_compute_md5(conn, auth, nr_in_ptr, - nr_out_ptr, nr_out_len) < 0) - return -1; - return 0; - default: - pr_err("Unknown CHAP digest type %d!\n", - chap->digest_type); - return -1; - } -} - u32 chap_main_loop( struct iscsi_conn *conn, struct iscsi_node_auth *auth, @@ -448,7 +499,7 @@ u32 chap_main_loop( return 0; } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) { convert_null_to_semi(in_text, *in_len); - if (chap_got_response(conn, auth, in_text, out_text, + if (chap_server_compute_hash(conn, auth, in_text, out_text, out_len) < 0) { chap_close(conn); return 2; diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h index d5600ac30b53..93db1ab5516c 100644 --- a/drivers/target/iscsi/iscsi_target_auth.h +++ b/drivers/target/iscsi/iscsi_target_auth.h @@ -6,14 +6,19 @@ #define CHAP_DIGEST_UNKNOWN 0 #define CHAP_DIGEST_MD5 5 -#define CHAP_DIGEST_SHA 6 +#define CHAP_DIGEST_SHA1 6 +#define CHAP_DIGEST_SHA256 7 +#define CHAP_DIGEST_SHA3_256 8 #define CHAP_CHALLENGE_LENGTH 16 #define CHAP_CHALLENGE_STR_LEN 4096 -#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 */ +#define MAX_RESPONSE_LENGTH 128 /* sufficient for SHA3 256 */ #define MAX_CHAP_N_SIZE 512 #define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */ +#define SHA1_SIGNATURE_SIZE 20 /* 20 bytes in a SHA1 message digest */ +#define SHA256_SIGNATURE_SIZE 32 /* 32 bytes in a SHA256 message digest */ +#define SHA3_256_SIGNATURE_SIZE 32 /* 32 bytes in a SHA3 256 message digest */ #define CHAP_STAGE_CLIENT_A 1 #define CHAP_STAGE_SERVER_AIC 2 @@ -28,9 +33,11 @@ extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, int *, int *); struct iscsi_chap { - unsigned char digest_type; unsigned char id; unsigned char challenge[CHAP_CHALLENGE_LENGTH]; + unsigned int challenge_len; + unsigned char *digest_name; + unsigned int digest_size; unsigned int authenticate_target; unsigned int chap_state; } ____cacheline_aligned; -- cgit v1.2.3 From 19f5f88ed779180f16e236949e18389a0dca4aae Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Thu, 17 Oct 2019 15:10:36 +0200 Subject: scsi: target: iscsi: tie the challenge length to the hash digest size Link: https://lore.kernel.org/r/20191017131037.9903-3-mlombard@redhat.com Signed-off-by: Maurizio Lombardi Tested-by: Chris Leech Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_auth.c | 37 ++++++++++++++++++++++---------- drivers/target/iscsi/iscsi_target_auth.h | 4 ++-- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index b09f20842e40..f3973ab19da2 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -41,16 +41,21 @@ static int chap_gen_challenge( unsigned int *c_len) { int ret; - unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1]; + unsigned char *challenge_asciihex; struct iscsi_chap *chap = conn->auth_protocol; - memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1); + challenge_asciihex = kzalloc(chap->challenge_len * 2 + 1, GFP_KERNEL); + if (!challenge_asciihex) + return -ENOMEM; - ret = get_random_bytes_wait(chap->challenge, CHAP_CHALLENGE_LENGTH); + memset(chap->challenge, 0, MAX_CHAP_CHALLENGE_LEN); + + ret = get_random_bytes_wait(chap->challenge, chap->challenge_len); if (unlikely(ret)) - return ret; + goto out; + bin2hex(challenge_asciihex, chap->challenge, - CHAP_CHALLENGE_LENGTH); + chap->challenge_len); /* * Set CHAP_C, and copy the generated challenge into c_str. */ @@ -59,7 +64,10 @@ static int chap_gen_challenge( pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client", challenge_asciihex); - return 0; + +out: + kfree(challenge_asciihex); + return ret; } static int chap_test_algorithm(const char *name) @@ -171,6 +179,9 @@ static struct iscsi_chap *chap_server_open( chap->digest_name = chap_get_digest_name(digest_type); + /* Tie the challenge length to the digest size */ + chap->challenge_len = chap->digest_size; + pr_debug("[server] Got CHAP_A=%d\n", digest_type); *aic_len = sprintf(aic_str, "CHAP_A=%d", digest_type); *aic_len += 1; @@ -334,21 +345,23 @@ static int chap_server_compute_hash( } ret = crypto_shash_finup(desc, chap->challenge, - CHAP_CHALLENGE_LENGTH, server_digest); + chap->challenge_len, server_digest); if (ret < 0) { pr_err("crypto_shash_finup() failed for challenge\n"); goto out; } bin2hex(response, server_digest, chap->digest_size); - pr_debug("[server] %s Server Digest: %s\n", hash_name, response); + pr_debug("[server] %s Server Digest: %s\n", + chap->digest_name, response); if (memcmp(server_digest, client_digest, chap->digest_size) != 0) { - pr_debug("[server] %s Digests do not match!\n\n", hash_name); + pr_debug("[server] %s Digests do not match!\n\n", + chap->digest_name); goto out; } else pr_debug("[server] %s Digests match, CHAP connection" - " successful.\n\n", hash_name); + " successful.\n\n", chap->digest_name); /* * One way authentication has succeeded, return now if mutual * authentication is not enabled. @@ -414,7 +427,9 @@ static int chap_server_compute_hash( * initiator must not match the original CHAP_C generated by * the target. */ - if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) { + if (challenge_len == chap->challenge_len && + !memcmp(challenge_binhex, chap->challenge, + challenge_len)) { pr_err("initiator CHAP_C matches target CHAP_C, failing" " login attempt\n"); goto out; diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h index 93db1ab5516c..fc75c1c20e23 100644 --- a/drivers/target/iscsi/iscsi_target_auth.h +++ b/drivers/target/iscsi/iscsi_target_auth.h @@ -10,7 +10,7 @@ #define CHAP_DIGEST_SHA256 7 #define CHAP_DIGEST_SHA3_256 8 -#define CHAP_CHALLENGE_LENGTH 16 +#define MAX_CHAP_CHALLENGE_LEN 32 #define CHAP_CHALLENGE_STR_LEN 4096 #define MAX_RESPONSE_LENGTH 128 /* sufficient for SHA3 256 */ #define MAX_CHAP_N_SIZE 512 @@ -34,7 +34,7 @@ extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, struct iscsi_chap { unsigned char id; - unsigned char challenge[CHAP_CHALLENGE_LENGTH]; + unsigned char challenge[MAX_CHAP_CHALLENGE_LEN]; unsigned int challenge_len; unsigned char *digest_name; unsigned int digest_size; -- cgit v1.2.3 From f9fab3d9860050ed69b7cee348a449a7853a3259 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Thu, 17 Oct 2019 15:10:37 +0200 Subject: scsi: target: iscsi: rename some variables to avoid confusion. This patch renames some variables in chap_server_compute_hash() to make it harder to confuse the initiator's challenge with the target's challenge when the mutual chap authentication is used. Link: https://lore.kernel.org/r/20191017131037.9903-4-mlombard@redhat.com Signed-off-by: Maurizio Lombardi Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target_auth.c | 40 ++++++++++++++++---------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index f3973ab19da2..0e54627d9aa8 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c @@ -215,8 +215,8 @@ static int chap_server_compute_hash( unsigned long id; unsigned char id_as_uchar; unsigned char type; - unsigned char identifier[10], *challenge = NULL; - unsigned char *challenge_binhex = NULL; + unsigned char identifier[10], *initiatorchg = NULL; + unsigned char *initiatorchg_binhex = NULL; unsigned char *digest = NULL; unsigned char *response = NULL; unsigned char *client_digest = NULL; @@ -226,7 +226,7 @@ static int chap_server_compute_hash( struct iscsi_chap *chap = conn->auth_protocol; struct crypto_shash *tfm = NULL; struct shash_desc *desc = NULL; - int auth_ret = -1, ret, challenge_len; + int auth_ret = -1, ret, initiatorchg_len; digest = kzalloc(chap->digest_size, GFP_KERNEL); if (!digest) { @@ -256,15 +256,15 @@ static int chap_server_compute_hash( memset(chap_n, 0, MAX_CHAP_N_SIZE); memset(chap_r, 0, MAX_RESPONSE_LENGTH); - challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); - if (!challenge) { + initiatorchg = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); + if (!initiatorchg) { pr_err("Unable to allocate challenge buffer\n"); goto out; } - challenge_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); - if (!challenge_binhex) { - pr_err("Unable to allocate challenge_binhex buffer\n"); + initiatorchg_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); + if (!initiatorchg_binhex) { + pr_err("Unable to allocate initiatorchg_binhex buffer\n"); goto out; } /* @@ -399,7 +399,7 @@ static int chap_server_compute_hash( * Get CHAP_C. */ if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN, - challenge, &type) < 0) { + initiatorchg, &type) < 0) { pr_err("Could not find CHAP_C.\n"); goto out; } @@ -408,28 +408,28 @@ static int chap_server_compute_hash( pr_err("Could not find CHAP_C.\n"); goto out; } - challenge_len = DIV_ROUND_UP(strlen(challenge), 2); - if (!challenge_len) { + initiatorchg_len = DIV_ROUND_UP(strlen(initiatorchg), 2); + if (!initiatorchg_len) { pr_err("Unable to convert incoming challenge\n"); goto out; } - if (challenge_len > 1024) { + if (initiatorchg_len > 1024) { pr_err("CHAP_C exceeds maximum binary size of 1024 bytes\n"); goto out; } - if (hex2bin(challenge_binhex, challenge, challenge_len) < 0) { + if (hex2bin(initiatorchg_binhex, initiatorchg, initiatorchg_len) < 0) { pr_err("Malformed CHAP_C\n"); goto out; } - pr_debug("[server] Got CHAP_C=%s\n", challenge); + pr_debug("[server] Got CHAP_C=%s\n", initiatorchg); /* * During mutual authentication, the CHAP_C generated by the * initiator must not match the original CHAP_C generated by * the target. */ - if (challenge_len == chap->challenge_len && - !memcmp(challenge_binhex, chap->challenge, - challenge_len)) { + if (initiatorchg_len == chap->challenge_len && + !memcmp(initiatorchg_binhex, chap->challenge, + initiatorchg_len)) { pr_err("initiator CHAP_C matches target CHAP_C, failing" " login attempt\n"); goto out; @@ -461,7 +461,7 @@ static int chap_server_compute_hash( /* * Convert received challenge to binary hex. */ - ret = crypto_shash_finup(desc, challenge_binhex, challenge_len, + ret = crypto_shash_finup(desc, initiatorchg_binhex, initiatorchg_len, digest); if (ret < 0) { pr_err("crypto_shash_finup() failed for ma challenge\n"); @@ -487,8 +487,8 @@ out: kzfree(desc); if (tfm) crypto_free_shash(tfm); - kfree(challenge); - kfree(challenge_binhex); + kfree(initiatorchg); + kfree(initiatorchg_binhex); kfree(digest); kfree(response); kfree(server_digest); -- cgit v1.2.3 From c8510d240306075ebb2ac2a44054d664cb39908b Mon Sep 17 00:00:00 2001 From: Vinod Koul Date: Thu, 24 Oct 2019 13:18:00 +0530 Subject: scsi: dt-bindings: ufs: Add sm8150 compatible string Document "qcom,sm8150-ufshc" compatible string for UFS HC found on SM8150. Link: https://lore.kernel.org/r/20191024074802.26526-2-vkoul@kernel.org Reviewed-by: Bjorn Andersson Reviewed-by: Stephen Boyd Acked-by: Rob Herring Signed-off-by: Vinod Koul Signed-off-by: Martin K. Petersen --- Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt index d78ef63935f9..415ccdd7442d 100644 --- a/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt +++ b/Documentation/devicetree/bindings/ufs/ufshcd-pltfrm.txt @@ -13,6 +13,7 @@ Required properties: "qcom,msm8996-ufshc", "qcom,ufshc", "jedec,ufs-2.0" "qcom,msm8998-ufshc", "qcom,ufshc", "jedec,ufs-2.0" "qcom,sdm845-ufshc", "qcom,ufshc", "jedec,ufs-2.0" + "qcom,sm8150-ufshc", "qcom,ufshc", "jedec,ufs-2.0" - interrupts : - reg : -- cgit v1.2.3 From 983f127603fac650fa34ee69db363e4615eaf9e7 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 5 Nov 2019 07:06:50 -0800 Subject: scsi: qla2xxx: Retry PLOGI on FC-NVMe PRLI failure Current code will send PRLI with FC-NVMe bit set for the targets which support only FCP. This may result into issue with targets which do not understand NVMe and will go into a strange state. This patch would restart the login process by going back to PLOGI state. The PLOGI state will force the target to respond to correct PRLI request. Fixes: c76ae845ea836 ("scsi: qla2xxx: Add error handling for PLOGI ELS passthrough") Cc: stable@vger.kernel.org # 5.4 Link: https://lore.kernel.org/r/20191105150657.8092-2-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 37 ++++++++----------------------------- drivers/scsi/qla2xxx/qla_iocb.c | 6 +++++- 2 files changed, 13 insertions(+), 30 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 7cb7545de962..5db8ad832893 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1864,42 +1864,21 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) * FCP/NVMe port */ if (NVME_FCP_TARGET(ea->fcport)) { - if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME) - ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME; - else - ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP; ql_dbg(ql_dbg_disc, vha, 0x2118, "%s %d %8phC post %s prli\n", __func__, __LINE__, ea->fcport->port_name, (ea->fcport->fc4_type & FS_FC4TYPE_NVME) ? "NVMe" : "FCP"); - qla24xx_post_prli_work(vha, ea->fcport); - break; + if (vha->hw->fc4_type_priority == FC4_PRIORITY_NVME) + ea->fcport->fc4_type &= ~FS_FC4TYPE_NVME; + else + ea->fcport->fc4_type &= ~FS_FC4TYPE_FCP; } - /* at this point both PRLI NVME & PRLI FCP failed */ - if (N2N_TOPO(vha->hw)) { - if (ea->fcport->n2n_link_reset_cnt < 3) { - ea->fcport->n2n_link_reset_cnt++; - /* - * remote port is not sending Plogi. Reset - * link to kick start his state machine - */ - set_bit(N2N_LINK_RESET, &vha->dpc_flags); - } else { - ql_log(ql_log_warn, vha, 0x2119, - "%s %d %8phC Unable to reconnect\n", - __func__, __LINE__, ea->fcport->port_name); - } - } else { - /* - * switch connect. login failed. Take connection - * down and allow relogin to retrigger - */ - ea->fcport->flags &= ~FCF_ASYNC_SENT; - ea->fcport->keep_nport_handle = 0; - qlt_schedule_sess_for_deletion(ea->fcport); - } + ea->fcport->flags &= ~FCF_ASYNC_SENT; + ea->fcport->keep_nport_handle = 0; + ea->fcport->logout_on_delete = 1; + qlt_schedule_sess_for_deletion(ea->fcport); break; } } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index eeb526411536..2b675da34bda 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2764,6 +2764,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) ea.sp = sp; qla24xx_handle_plogi_done_event(vha, &ea); break; + case CS_IOCB_ERROR: switch (fw_status[1]) { case LSC_SCODE_PORTID_USED: @@ -2834,6 +2835,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) fw_status[0], fw_status[1], fw_status[2]); fcport->flags &= ~FCF_ASYNC_SENT; + fcport->disc_state = DSC_LOGIN_FAILED; set_bit(RELOGIN_NEEDED, &vha->dpc_flags); break; } @@ -2846,6 +2848,7 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) fw_status[0], fw_status[1], fw_status[2]); sp->fcport->flags &= ~FCF_ASYNC_SENT; + sp->fcport->disc_state = DSC_LOGIN_FAILED; set_bit(RELOGIN_NEEDED, &vha->dpc_flags); break; } @@ -2881,11 +2884,12 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, return -ENOMEM; } + fcport->flags |= FCF_ASYNC_SENT; + fcport->disc_state = DSC_LOGIN_PEND; elsio = &sp->u.iocb_cmd; ql_dbg(ql_dbg_io, vha, 0x3073, "Enter: PLOGI portid=%06x\n", fcport->d_id.b24); - fcport->flags |= FCF_ASYNC_SENT; sp->type = SRB_ELS_DCMD; sp->name = "ELS_DCMD"; sp->fcport = fcport; -- cgit v1.2.3 From 71c80b75ce8f08c0978ce9a9816b81b5c3ce5e12 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 5 Nov 2019 07:06:51 -0800 Subject: scsi: qla2xxx: Do command completion on abort timeout On switch, fabric and mgt command timeout, driver send Abort to tell FW to return the original command. If abort is timeout, then return both Abort and original command for cleanup. Fixes: 219d27d7147e0 ("scsi: qla2xxx: Fix race conditions in the code for aborting SCSI commands") Cc: stable@vger.kernel.org # 5.2 Link: https://lore.kernel.org/r/20191105150657.8092-3-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 721ee7f09b39..ef9bb3c7ad6f 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -604,6 +604,7 @@ typedef struct srb { const char *name; int iocbs; struct qla_qpair *qpair; + struct srb *cmd_sp; struct list_head elem; u32 gen1; /* scratch */ u32 gen2; /* scratch */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 5db8ad832893..7fdbe041cc19 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -101,8 +101,22 @@ static void qla24xx_abort_iocb_timeout(void *data) u32 handle; unsigned long flags; + if (sp->cmd_sp) + ql_dbg(ql_dbg_async, sp->vha, 0x507c, + "Abort timeout - cmd hdl=%x, cmd type=%x hdl=%x, type=%x\n", + sp->cmd_sp->handle, sp->cmd_sp->type, + sp->handle, sp->type); + else + ql_dbg(ql_dbg_async, sp->vha, 0x507c, + "Abort timeout 2 - hdl=%x, type=%x\n", + sp->handle, sp->type); + spin_lock_irqsave(qpair->qp_lock_ptr, flags); for (handle = 1; handle < qpair->req->num_outstanding_cmds; handle++) { + if (sp->cmd_sp && (qpair->req->outstanding_cmds[handle] == + sp->cmd_sp)) + qpair->req->outstanding_cmds[handle] = NULL; + /* removing the abort */ if (qpair->req->outstanding_cmds[handle] == sp) { qpair->req->outstanding_cmds[handle] = NULL; @@ -111,6 +125,9 @@ static void qla24xx_abort_iocb_timeout(void *data) } spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + if (sp->cmd_sp) + sp->cmd_sp->done(sp->cmd_sp, QLA_OS_TIMER_EXPIRED); + abt->u.abt.comp_status = CS_TIMEOUT; sp->done(sp, QLA_OS_TIMER_EXPIRED); } @@ -142,6 +159,7 @@ static int qla24xx_async_abort_cmd(srb_t *cmd_sp, bool wait) sp->type = SRB_ABT_CMD; sp->name = "abort"; sp->qpair = cmd_sp->qpair; + sp->cmd_sp = cmd_sp; if (wait) sp->flags = SRB_WAKEUP_ON_COMP; -- cgit v1.2.3 From af2a0c51b1205327f55a7e82e530403ae1d42cbb Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 5 Nov 2019 07:06:52 -0800 Subject: scsi: qla2xxx: Fix SRB leak on switch command timeout when GPSC/GPDB switch command fails, driver just returns without doing a proper cleanup. This patch fixes this memory leak by calling sp->free() in the error path. Link: https://lore.kernel.org/r/20191105150657.8092-4-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gs.c | 2 +- drivers/scsi/qla2xxx/qla_init.c | 11 +++++------ drivers/scsi/qla2xxx/qla_mbx.c | 4 ---- drivers/scsi/qla2xxx/qla_mid.c | 11 ++++------- drivers/scsi/qla2xxx/qla_os.c | 7 ++++++- 5 files changed, 16 insertions(+), 19 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index 7a00272ca380..67230688b05e 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3010,7 +3010,7 @@ static void qla24xx_async_gpsc_sp_done(srb_t *sp, int res) fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); if (res == QLA_FUNCTION_TIMEOUT) - return; + goto done; if (res == (DID_ERROR << 16)) { /* entry status error */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 7fdbe041cc19..bddb26baedd2 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1151,19 +1151,18 @@ static void qla24xx_async_gpdb_sp_done(srb_t *sp, int res) "Async done-%s res %x, WWPN %8phC mb[1]=%x mb[2]=%x \n", sp->name, res, fcport->port_name, mb[1], mb[2]); - if (res == QLA_FUNCTION_TIMEOUT) { - dma_pool_free(sp->vha->hw->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, - sp->u.iocb_cmd.u.mbx.in_dma); - return; - } - fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); + + if (res == QLA_FUNCTION_TIMEOUT) + goto done; + memset(&ea, 0, sizeof(ea)); ea.fcport = fcport; ea.sp = sp; qla24xx_handle_gpdb_event(vha, &ea); +done: dma_pool_free(ha->s_dma_pool, sp->u.iocb_cmd.u.mbx.in, sp->u.iocb_cmd.u.mbx.in_dma); diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index d4d75bcdac73..4eb88c3ee08e 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -6287,17 +6287,13 @@ int qla24xx_send_mb_cmd(struct scsi_qla_host *vha, mbx_cmd_t *mcp) case QLA_SUCCESS: ql_dbg(ql_dbg_mbx, vha, 0x119d, "%s: %s done.\n", __func__, sp->name); - sp->free(sp); break; default: ql_dbg(ql_dbg_mbx, vha, 0x119e, "%s: %s Failed. %x.\n", __func__, sp->name, rval); - sp->free(sp); break; } - return rval; - done_free_sp: sp->free(sp); done: diff --git a/drivers/scsi/qla2xxx/qla_mid.c b/drivers/scsi/qla2xxx/qla_mid.c index 6afad68e5ba2..bd62c4595b73 100644 --- a/drivers/scsi/qla2xxx/qla_mid.c +++ b/drivers/scsi/qla2xxx/qla_mid.c @@ -944,7 +944,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) sp = qla2x00_get_sp(base_vha, NULL, GFP_KERNEL); if (!sp) - goto done; + return rval; sp->type = SRB_CTRL_VP; sp->name = "ctrl_vp"; @@ -960,7 +960,7 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) ql_dbg(ql_dbg_async, vha, 0xffff, "%s: %s Failed submission. %x.\n", __func__, sp->name, rval); - goto done_free_sp; + goto done; } ql_dbg(ql_dbg_vport, vha, 0x113f, "%s hndl %x submitted\n", @@ -978,16 +978,13 @@ int qla24xx_control_vp(scsi_qla_host_t *vha, int cmd) case QLA_SUCCESS: ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s done.\n", __func__, sp->name); - goto done_free_sp; + break; default: ql_dbg(ql_dbg_vport, vha, 0xffff, "%s: %s Failed. %x.\n", __func__, sp->name, rval); - goto done_free_sp; + break; } done: - return rval; - -done_free_sp: sp->free(sp); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 16f9b6ed574a..fc8cb25fa748 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -996,7 +996,7 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, ql_dbg(ql_dbg_io + ql_dbg_verbose, vha, 0x3078, "Start scsi failed rval=%d for cmd=%p.\n", rval, cmd); if (rval == QLA_INTERFACE_ERROR) - goto qc24_fail_command; + goto qc24_free_sp_fail_command; goto qc24_host_busy_free_sp; } @@ -1008,6 +1008,11 @@ qc24_host_busy_free_sp: qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; +qc24_free_sp_fail_command: + sp->free(sp); + CMD_SP(cmd) = NULL; + qla2xxx_rel_qpair_sp(sp->qpair, sp); + qc24_fail_command: cmd->scsi_done(cmd); -- cgit v1.2.3 From dd322b7f3efc8cda085bb60eadc4aee6324eadd8 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 5 Nov 2019 07:06:53 -0800 Subject: scsi: qla2xxx: Fix driver unload hang This patch fixes driver unload hang by removing msleep() Fixes: d74595278f4ab ("scsi: qla2xxx: Add multiple queue pair functionality.") Cc: stable@vger.kernel.org Link: https://lore.kernel.org/r/20191105150657.8092-5-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Quinn Tran Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index bddb26baedd2..ff4528702b4e 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -9009,8 +9009,6 @@ int qla2xxx_delete_qpair(struct scsi_qla_host *vha, struct qla_qpair *qpair) struct qla_hw_data *ha = qpair->hw; qpair->delete_in_progress = 1; - while (atomic_read(&qpair->ref_count)) - msleep(500); ret = qla25xx_delete_req_que(vha, qpair->req); if (ret != QLA_SUCCESS) -- cgit v1.2.3 From f45bca8c5052e8c59bab64ee90c44441678b9a52 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Tue, 5 Nov 2019 07:06:54 -0800 Subject: scsi: qla2xxx: Fix double scsi_done for abort path Current code assumes abort will remove the original command from the active list where scsi_done will not be called. Instead, the eh_abort thread will do the scsi_done. That is not the case. Instead, we have a double scsi_done calls triggering use after free. Abort will tell FW to release the command from FW possesion. The original command will return to ULP with error in its normal fashion via scsi_done. eh_abort path would wait for the original command completion before returning. eh_abort path will not perform the scsi_done call. Fixes: 219d27d7147e0 ("scsi: qla2xxx: Fix race conditions in the code for aborting SCSI commands") Cc: stable@vger.kernel.org # 5.2 Link: https://lore.kernel.org/r/20191105150657.8092-6-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Quinn Tran Signed-off-by: Arun Easi Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 5 +- drivers/scsi/qla2xxx/qla_isr.c | 5 ++ drivers/scsi/qla2xxx/qla_nvme.c | 4 +- drivers/scsi/qla2xxx/qla_os.c | 117 +++++++++++++++++++++------------------- 4 files changed, 72 insertions(+), 59 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index ef9bb3c7ad6f..2a9e6a9a8c9d 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -591,13 +591,16 @@ typedef struct srb { */ uint8_t cmd_type; uint8_t pad[3]; - atomic_t ref_count; struct kref cmd_kref; /* need to migrate ref_count over to this */ void *priv; wait_queue_head_t nvme_ls_waitq; struct fc_port *fcport; struct scsi_qla_host *vha; unsigned int start_timer:1; + unsigned int abort:1; + unsigned int aborted:1; + unsigned int completed:1; + uint32_t handle; uint16_t flags; uint16_t type; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index acef3d73983c..1b8f297449cf 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -2487,6 +2487,11 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) return; } + if (sp->abort) + sp->aborted = 1; + else + sp->completed = 1; + if (sp->cmd_type != TYPE_SRB) { req->outstanding_cmds[handle] = NULL; ql_dbg(ql_dbg_io, vha, 0x3015, diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 6cc19e060afc..941aa53363f5 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -224,8 +224,8 @@ static void qla_nvme_abort_work(struct work_struct *work) if (ha->flags.host_shutting_down) { ql_log(ql_log_info, sp->fcport->vha, 0xffff, - "%s Calling done on sp: %p, type: 0x%x, sp->ref_count: 0x%x\n", - __func__, sp, sp->type, atomic_read(&sp->ref_count)); + "%s Calling done on sp: %p, type: 0x%x\n", + __func__, sp, sp->type); sp->done(sp, 0); goto out; } diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index fc8cb25fa748..48e7b36f5513 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -698,11 +698,6 @@ void qla2x00_sp_compl(srb_t *sp, int res) struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct completion *comp = sp->comp; - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - - atomic_dec(&sp->ref_count); - sp->free(sp); cmd->result = res; CMD_SP(cmd) = NULL; @@ -794,11 +789,6 @@ void qla2xxx_qpair_sp_compl(srb_t *sp, int res) struct scsi_cmnd *cmd = GET_CMD_SP(sp); struct completion *comp = sp->comp; - if (WARN_ON_ONCE(atomic_read(&sp->ref_count) == 0)) - return; - - atomic_dec(&sp->ref_count); - sp->free(sp); cmd->result = res; CMD_SP(cmd) = NULL; @@ -903,7 +893,7 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) sp->u.scmd.cmd = cmd; sp->type = SRB_SCSI_CMD; - atomic_set(&sp->ref_count, 1); + CMD_SP(cmd) = (void *)sp; sp->free = qla2x00_sp_free_dma; sp->done = qla2x00_sp_compl; @@ -985,11 +975,9 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, sp->u.scmd.cmd = cmd; sp->type = SRB_SCSI_CMD; - atomic_set(&sp->ref_count, 1); CMD_SP(cmd) = (void *)sp; sp->free = qla2xxx_qpair_sp_free_dma; sp->done = qla2xxx_qpair_sp_compl; - sp->qpair = qpair; rval = ha->isp_ops->start_scsi_mq(sp); if (rval != QLA_SUCCESS) { @@ -1187,16 +1175,6 @@ qla2x00_wait_for_chip_reset(scsi_qla_host_t *vha) return return_status; } -static int -sp_get(struct srb *sp) -{ - if (!refcount_inc_not_zero((refcount_t *)&sp->ref_count)) - /* kref get fail */ - return ENXIO; - else - return 0; -} - #define ISP_REG_DISCONNECT 0xffffffffU /************************************************************************** * qla2x00_isp_reg_stat @@ -1252,6 +1230,9 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) uint64_t lun; int rval; struct qla_hw_data *ha = vha->hw; + uint32_t ratov_j; + struct qla_qpair *qpair; + unsigned long flags; if (qla2x00_isp_reg_stat(ha)) { ql_log(ql_log_info, vha, 0x8042, @@ -1264,13 +1245,26 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) return ret; sp = scsi_cmd_priv(cmd); + qpair = sp->qpair; - if (sp->fcport && sp->fcport->deleted) + if ((sp->fcport && sp->fcport->deleted) || !qpair) return SUCCESS; - /* Return if the command has already finished. */ - if (sp_get(sp)) + spin_lock_irqsave(qpair->qp_lock_ptr, flags); + if (sp->completed) { + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); return SUCCESS; + } + + if (sp->abort || sp->aborted) { + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + return FAILED; + } + + sp->abort = 1; + sp->comp = ∁ + spin_unlock_irqrestore(qpair->qp_lock_ptr, flags); + id = cmd->device->id; lun = cmd->device->lun; @@ -1279,47 +1273,37 @@ qla2xxx_eh_abort(struct scsi_cmnd *cmd) "Aborting from RISC nexus=%ld:%d:%llu sp=%p cmd=%p handle=%x\n", vha->host_no, id, lun, sp, cmd, sp->handle); + /* + * Abort will release the original Command/sp from FW. Let the + * original command call scsi_done. In return, he will wakeup + * this sleeping thread. + */ rval = ha->isp_ops->abort_command(sp); + ql_dbg(ql_dbg_taskm, vha, 0x8003, "Abort command mbx cmd=%p, rval=%x.\n", cmd, rval); + /* Wait for the command completion. */ + ratov_j = ha->r_a_tov/10 * 4 * 1000; + ratov_j = msecs_to_jiffies(ratov_j); switch (rval) { case QLA_SUCCESS: - /* - * The command has been aborted. That means that the firmware - * won't report a completion. - */ - sp->done(sp, DID_ABORT << 16); - ret = SUCCESS; - break; - case QLA_FUNCTION_PARAMETER_ERROR: { - /* Wait for the command completion. */ - uint32_t ratov = ha->r_a_tov/10; - uint32_t ratov_j = msecs_to_jiffies(4 * ratov * 1000); - - WARN_ON_ONCE(sp->comp); - sp->comp = ∁ if (!wait_for_completion_timeout(&comp, ratov_j)) { ql_dbg(ql_dbg_taskm, vha, 0xffff, "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n", - __func__, ha->r_a_tov); + __func__, ha->r_a_tov/10); ret = FAILED; } else { ret = SUCCESS; } break; - } default: - /* - * Either abort failed or abort and completion raced. Let - * the SCSI core retry the abort in the former case. - */ ret = FAILED; break; } sp->comp = NULL; - atomic_dec(&sp->ref_count); + ql_log(ql_log_info, vha, 0x801c, "Abort command issued nexus=%ld:%d:%llu -- %x.\n", vha->host_no, id, lun, ret); @@ -1711,32 +1695,53 @@ static void qla2x00_abort_srb(struct qla_qpair *qp, srb_t *sp, const int res, scsi_qla_host_t *vha = qp->vha; struct qla_hw_data *ha = vha->hw; int rval; + bool ret_cmd; + uint32_t ratov_j; - if (sp_get(sp)) + if (qla2x00_chip_is_down(vha)) { + sp->done(sp, res); return; + } if (sp->type == SRB_NVME_CMD || sp->type == SRB_NVME_LS || (sp->type == SRB_SCSI_CMD && !ha->flags.eeh_busy && !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) && !qla2x00_isp_reg_stat(ha))) { + if (sp->comp) { + sp->done(sp, res); + return; + } + sp->comp = ∁ + sp->abort = 1; spin_unlock_irqrestore(qp->qp_lock_ptr, *flags); - rval = ha->isp_ops->abort_command(sp); + rval = ha->isp_ops->abort_command(sp); + /* Wait for command completion. */ + ret_cmd = false; + ratov_j = ha->r_a_tov/10 * 4 * 1000; + ratov_j = msecs_to_jiffies(ratov_j); switch (rval) { case QLA_SUCCESS: - sp->done(sp, res); + if (wait_for_completion_timeout(&comp, ratov_j)) { + ql_dbg(ql_dbg_taskm, vha, 0xffff, + "%s: Abort wait timer (4 * R_A_TOV[%d]) expired\n", + __func__, ha->r_a_tov/10); + ret_cmd = true; + } + /* else FW return SP to driver */ break; - case QLA_FUNCTION_PARAMETER_ERROR: - wait_for_completion(&comp); + default: + ret_cmd = true; break; } spin_lock_irqsave(qp->qp_lock_ptr, *flags); - sp->comp = NULL; + if (ret_cmd && (!sp->completed || !sp->aborted)) + sp->done(sp, res); + } else { + sp->done(sp, res); } - - atomic_dec(&sp->ref_count); } static void @@ -1758,7 +1763,6 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) { sp = req->outstanding_cmds[cnt]; if (sp) { - req->outstanding_cmds[cnt] = NULL; switch (sp->cmd_type) { case TYPE_SRB: qla2x00_abort_srb(qp, sp, res, &flags); @@ -1780,6 +1784,7 @@ __qla2x00_abort_all_cmds(struct qla_qpair *qp, int res) default: break; } + req->outstanding_cmds[cnt] = NULL; } } spin_unlock_irqrestore(qp->qp_lock_ptr, flags); -- cgit v1.2.3 From 2f856d4e8c23f5ad5221f8da4a2f22d090627f19 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 5 Nov 2019 07:06:55 -0800 Subject: scsi: qla2xxx: Fix memory leak when sending I/O fails On heavy loads, a memory leak of the srb_t structure is observed. This would make the qla2xxx_srbs cache gobble up memory. Fixes: 219d27d7147e0 ("scsi: qla2xxx: Fix race conditions in the code for aborting SCSI commands") Cc: stable@vger.kernel.org # 5.2 Link: https://lore.kernel.org/r/20191105150657.8092-7-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Arun Easi Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 48e7b36f5513..f5c660b4a16c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -909,6 +909,8 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) qc24_host_busy_free_sp: sp->free(sp); + CMD_SP(cmd) = NULL; + qla2x00_rel_sp(sp); qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; @@ -992,6 +994,8 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, qc24_host_busy_free_sp: sp->free(sp); + CMD_SP(cmd) = NULL; + qla2xxx_rel_qpair_sp(sp->qpair, sp); qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; -- cgit v1.2.3 From 65e9200938052ce90f24421bb057e1be1d6147c7 Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Tue, 5 Nov 2019 07:06:56 -0800 Subject: scsi: qla2xxx: Fix device connect issues in P2P configuration P2P needs to take the alternate plogi route. Link: https://lore.kernel.org/r/20191105150657.8092-8-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Arun Easi Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_gbl.h | 1 + drivers/scsi/qla2xxx/qla_init.c | 9 +++++++++ drivers/scsi/qla2xxx/qla_iocb.c | 5 ++--- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index d11416dcee4e..5b163ad85c34 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -917,4 +917,5 @@ int qla2x00_set_data_rate(scsi_qla_host_t *vha, uint16_t mode); /* nvme.c */ void qla_nvme_unregister_remote_port(struct fc_port *fcport); +void qla_handle_els_plogi_done(scsi_qla_host_t *vha, struct event_arg *ea); #endif /* _QLA_GBL_H */ diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index ff4528702b4e..6bb4ddd90b6e 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1717,6 +1717,15 @@ void qla24xx_handle_relogin_event(scsi_qla_host_t *vha, qla24xx_fcport_handle_login(vha, fcport); } +void qla_handle_els_plogi_done(scsi_qla_host_t *vha, + struct event_arg *ea) +{ + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post PRLI\n", + __func__, __LINE__, ea->fcport->port_name); + qla24xx_post_prli_work(vha, ea->fcport); +} + /* * RSCN(s) came in for this fcport, but the RSCN(s) was not able * to be consumed by the fcport diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 2b675da34bda..b25f87ff8cde 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2760,9 +2760,8 @@ static void qla2x00_els_dcmd2_sp_done(srb_t *sp, int res) case CS_COMPLETE: memset(&ea, 0, sizeof(ea)); ea.fcport = fcport; - ea.data[0] = MBS_COMMAND_COMPLETE; - ea.sp = sp; - qla24xx_handle_plogi_done_event(vha, &ea); + ea.rc = res; + qla_handle_els_plogi_done(vha, &ea); break; case CS_IOCB_ERROR: -- cgit v1.2.3 From b3f74568411b2df0806e0d1df6458cb270eb29ce Mon Sep 17 00:00:00 2001 From: Himanshu Madhani Date: Tue, 5 Nov 2019 07:06:57 -0800 Subject: scsi: qla2xxx: Update driver version to 10.01.00.21-k Link: https://lore.kernel.org/r/20191105150657.8092-9-hmadhani@marvell.com Reviewed-by: Ewan D. Milne Signed-off-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 225e401b62fa..03bd3b712b77 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -7,7 +7,7 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.01.00.20-k" +#define QLA2XXX_VERSION "10.01.00.21-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 1 -- cgit v1.2.3 From 47140a20a8198192af9957dc8bb8f7c8e578b5a9 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 5 Nov 2019 20:42:25 -0800 Subject: scsi: qla2xxx: Remove an include directive Since the code in qla_init.c is initiator code, remove the SCSI target core include directive. Cc: Himanshu Madhani Link: https://lore.kernel.org/r/20191106044226.5207-2-bvanassche@acm.org Reviewed-by: Martin Wilck Acked-by: Himanshu Madhani Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 6bb4ddd90b6e..cefd05483e1f 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -17,7 +17,6 @@ #include #endif -#include #include "qla_target.h" /* -- cgit v1.2.3 From 162b805e38327135168cb0938bd37b131b481cb0 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Tue, 5 Nov 2019 20:42:26 -0800 Subject: scsi: qla2xxx: Fix a dma_pool_free() call This patch fixes the following kernel warning: DMA-API: qla2xxx 0000:00:0a.0: device driver frees DMA memory with different size [device address=0x00000000c7b60000] [map size=4088 bytes] [unmap size=512 bytes] WARNING: CPU: 3 PID: 1122 at kernel/dma/debug.c:1021 check_unmap+0x4d0/0xbd0 CPU: 3 PID: 1122 Comm: rmmod Tainted: G O 5.4.0-rc1-dbg+ #1 RIP: 0010:check_unmap+0x4d0/0xbd0 Call Trace: debug_dma_free_coherent+0x123/0x173 dma_free_attrs+0x76/0xe0 qla2x00_mem_free+0x329/0xc40 [qla2xxx_scst] qla2x00_free_device+0x170/0x1c0 [qla2xxx_scst] qla2x00_remove_one+0x4f0/0x6d0 [qla2xxx_scst] pci_device_remove+0xd5/0x1f0 device_release_driver_internal+0x159/0x280 driver_detach+0x8b/0xf2 bus_remove_driver+0x9a/0x15a driver_unregister+0x51/0x70 pci_unregister_driver+0x2d/0x130 qla2x00_module_exit+0x1c/0xbc [qla2xxx_scst] __x64_sys_delete_module+0x22a/0x300 do_syscall_64+0x6f/0x2e0 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: 3f006ac342c0 ("scsi: qla2xxx: Secure flash update support for ISP28XX") # v5.2-rc1~130^2~270. Cc: Michael Hernandez Cc: Himanshu Madhani Link: https://lore.kernel.org/r/20191106044226.5207-3-bvanassche@acm.org Reviewed-by: Martin Wilck Acked-by: Himanshu Madhani Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index f5c660b4a16c..be33d61197d1 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4690,7 +4690,8 @@ qla2x00_mem_free(struct qla_hw_data *ha) ha->sfp_data = NULL; if (ha->flt) - dma_free_coherent(&ha->pdev->dev, SFP_DEV_SIZE, + dma_free_coherent(&ha->pdev->dev, + sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE, ha->flt, ha->flt_dma); ha->flt = NULL; ha->flt_dma = 0; -- cgit v1.2.3 From f5a2b219a7897751f9bb1c8d7308933e33000f2f Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Thu, 7 Nov 2019 22:48:55 +0000 Subject: scsi: qla2xxx: initialize fc4_type_priority ha->fc4_type_priority is currently initialized only in qla81xx_nvram_config(). That makes it default to NVMe for other adapters. Fix it. Fixes: 84ed362ac40c ("scsi: qla2xxx: Dual FCP-NVMe target port support") Link: https://lore.kernel.org/r/20191107224839.32417-2-martin.wilck@suse.com Tested-by: David Bond Acked-by: Himanshu Madhani Reviewed-by: Bart Van Assche Signed-off-by: Martin Wilck Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index cefd05483e1f..1dbee8800218 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2218,8 +2218,18 @@ qla2x00_initialize_adapter(scsi_qla_host_t *vha) ql_dbg(ql_dbg_init, vha, 0x0061, "Configure NVRAM parameters...\n"); + /* Let priority default to FCP, can be overridden by nvram_config */ + ha->fc4_type_priority = FC4_PRIORITY_FCP; + ha->isp_ops->nvram_config(vha); + if (ha->fc4_type_priority != FC4_PRIORITY_FCP && + ha->fc4_type_priority != FC4_PRIORITY_NVME) + ha->fc4_type_priority = FC4_PRIORITY_FCP; + + ql_log(ql_log_info, vha, 0xffff, "FC4 priority set to %s\n", + ha->fc4_type_priority == FC4_PRIORITY_FCP ? "FCP" : "NVMe"); + if (ha->flags.disable_serdes) { /* Mask HBA via NVRAM settings? */ ql_log(ql_log_info, vha, 0x0077, @@ -8525,8 +8535,6 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* Determine NVMe/FCP priority for target ports */ ha->fc4_type_priority = qla2xxx_get_fc4_priority(vha); - ql_log(ql_log_info, vha, 0xffff, "FC4 priority set to %s\n", - ha->fc4_type_priority & BIT_0 ? "FCP" : "NVMe"); if (rval) { ql_log(ql_log_warn, vha, 0x0076, -- cgit v1.2.3 From a10c8803d0dbab54370eeac2a07e6540c6215908 Mon Sep 17 00:00:00 2001 From: Martin Wilck Date: Thu, 7 Nov 2019 22:48:57 +0000 Subject: scsi: qla2xxx: don't use zero for FC4_PRIORITY_NVME Avoid an uninitialized value (0) for ha->fc4_type_priority being falsely interpreted as NVMe priority. Not strictly needed any more after the previous patch, but makes the fc4_type_priority handling more explicit. Link: https://lore.kernel.org/r/20191107224839.32417-3-martin.wilck@suse.com Tested-by: David Bond Acked-by: Himanshu Madhani Reviewed-by: Bart Van Assche Signed-off-by: Martin Wilck Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 6 ++++-- drivers/scsi/qla2xxx/qla_inline.h | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index 2a9e6a9a8c9d..460f443f6471 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -2480,8 +2480,10 @@ typedef struct fc_port { u16 n2n_chip_reset; } fc_port_t; -#define FC4_PRIORITY_NVME 0 -#define FC4_PRIORITY_FCP 1 +enum { + FC4_PRIORITY_NVME = 1, + FC4_PRIORITY_FCP = 2, +}; #define QLA_FCPORT_SCAN 1 #define QLA_FCPORT_FOUND 2 diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index d728b179e347..352aba4127f7 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -317,5 +317,5 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha) ((uint8_t *)vha->hw->nvram)[NVRAM_DUAL_FCP_NVME_FLAG_OFFSET]; - return ((data >> 6) & BIT_0); + return (data >> 6) & BIT_0 ? FC4_PRIORITY_FCP : FC4_PRIORITY_NVME; } -- cgit v1.2.3 From 765ab6cdac3b681952da0e22184bf6cf1ae41cf8 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 6 Nov 2019 21:21:54 -0800 Subject: scsi: lpfc: Fix a kernel warning triggered by lpfc_get_sgl_per_hdwq() Fix the following kernel bug report: BUG: using smp_processor_id() in preemptible [00000000] code: systemd-udevd/954 Fixes: d79c9e9d4b3d ("scsi: lpfc: Support dynamic unbounded SGL lists on G7 hardware.") Link: https://lore.kernel.org/r/20191107052158.25788-2-bvanassche@acm.org Signed-off-by: Bart Van Assche Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index fad890cea21a..613fbf4a7da9 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20668,7 +20668,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) /* allocate more */ spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, - cpu_to_node(smp_processor_id())); + cpu_to_node(raw_smp_processor_id())); if (!tmp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "8353 error kmalloc memory for HDWQ " @@ -20811,7 +20811,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, /* allocate more */ spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, - cpu_to_node(smp_processor_id())); + cpu_to_node(raw_smp_processor_id())); if (!tmp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "8355 error kmalloc memory for HDWQ " -- cgit v1.2.3 From eea2d396aa57acb3607f79ef04c08c2c5166f3fa Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 6 Nov 2019 21:21:56 -0800 Subject: scsi: lpfc: Fix a kernel warning triggered by lpfc_sli4_enable_intr() Fix the following lockdep warning: ============================================ WARNING: possible recursive locking detected 5.4.0-rc6-dbg+ #2 Not tainted -------------------------------------------- systemd-udevd/130 is trying to acquire lock: ffffffff826b05d0 (cpu_hotplug_lock.rw_sem){++++}, at: irq_calc_affinity_vectors+0x63/0x90 but task is already holding lock: ffffffff826b05d0 (cpu_hotplug_lock.rw_sem){++++}, at: lpfc_sli4_enable_intr+0x422/0xd50 [lpfc] other info that might help us debug this: Possible unsafe locking scenario: CPU0 ---- lock(cpu_hotplug_lock.rw_sem); lock(cpu_hotplug_lock.rw_sem); *** DEADLOCK *** May be due to missing lock nesting notation 2 locks held by systemd-udevd/130: #0: ffff8880d53fe210 (&dev->mutex){....}, at: __device_driver_lock+0x4a/0x70 #1: ffffffff826b05d0 (cpu_hotplug_lock.rw_sem){++++}, at: lpfc_sli4_enable_intr+0x422/0xd50 [lpfc] stack backtrace: CPU: 1 PID: 130 Comm: systemd-udevd Not tainted 5.4.0-rc6-dbg+ #2 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Call Trace: dump_stack+0xa5/0xe6 __lock_acquire.cold+0xf7/0x23a lock_acquire+0x106/0x240 cpus_read_lock+0x41/0xe0 irq_calc_affinity_vectors+0x63/0x90 __pci_enable_msix_range+0x10a/0x950 pci_alloc_irq_vectors_affinity+0x144/0x210 lpfc_sli4_enable_intr+0x4b2/0xd50 [lpfc] lpfc_pci_probe_one+0x1411/0x22b0 [lpfc] local_pci_probe+0x7c/0xc0 pci_device_probe+0x25d/0x390 really_probe+0x170/0x510 driver_probe_device+0x127/0x190 device_driver_attach+0x98/0xa0 __driver_attach+0xb6/0x1a0 bus_for_each_dev+0x100/0x150 driver_attach+0x31/0x40 bus_add_driver+0x246/0x300 driver_register+0xe0/0x170 __pci_register_driver+0xde/0xf0 lpfc_init+0x134/0x1000 [lpfc] do_one_initcall+0xda/0x47e do_init_module+0x10a/0x3b0 load_module+0x4318/0x47c0 __do_sys_finit_module+0x134/0x1d0 __x64_sys_finit_module+0x47/0x50 do_syscall_64+0x6f/0x2e0 entry_SYSCALL_64_after_hwframe+0x49/0xbe Fixes: dcaa21367938 ("scsi: lpfc: Change default IRQ model on AMD architectures") Link: https://lore.kernel.org/r/20191107052158.25788-4-bvanassche@acm.org Signed-off-by: Bart Van Assche Reviewed-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 28e6a763f106..37e57fd9ba5d 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11580,9 +11580,7 @@ lpfc_sli4_enable_intr(struct lpfc_hba *phba, uint32_t cfg_mode) retval = 0; if (!retval) { /* Now, try to enable MSI-X interrupt mode */ - get_online_cpus(); retval = lpfc_sli4_enable_msix(phba); - put_online_cpus(); if (!retval) { /* Indicate initialization to MSI-X mode */ phba->intr_type = MSIX; -- cgit v1.2.3 From 61951a6d3153b4482404b739be921a7459f8dc12 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Fri, 8 Nov 2019 14:59:47 -0800 Subject: scsi: lpfc: Fix lpfc_cpumask_of_node_init() Fix the following kernel warning: cpumask_of_node(-1): (unsigned)node >= nr_node_ids(1) Fixes: dcaa21367938 ("scsi: lpfc: Change default IRQ model on AMD architectures") Link: https://lore.kernel.org/r/20191108225947.1395-1-jsmart2021@gmail.com Signed-off-by: Bart Van Assche Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 37e57fd9ba5d..303bfff0ecc8 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -6005,19 +6005,13 @@ static void lpfc_cpumask_of_node_init(struct lpfc_hba *phba) { unsigned int cpu, numa_node; - struct cpumask *numa_mask = NULL; - -#ifdef CONFIG_NUMA - numa_node = phba->pcidev->dev.numa_node; -#else - numa_node = NUMA_NO_NODE; -#endif - numa_mask = &phba->sli4_hba.numa_mask; + struct cpumask *numa_mask = &phba->sli4_hba.numa_mask; cpumask_clear(numa_mask); /* Check if we're a NUMA architecture */ - if (!cpumask_of_node(numa_node)) + numa_node = dev_to_node(&phba->pcidev->dev); + if (numa_node == NUMA_NO_NODE) return; for_each_possible_cpu(cpu) -- cgit v1.2.3 From 9237f04e12cc385334043cd7cf84b74dcbda0256 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Wed, 30 Oct 2019 18:08:47 +0900 Subject: scsi: core: Fix scsi_get/set_resid() interface struct scsi_cmnd cmd->req.resid_len which is returned and set respectively by the helper functions scsi_get_resid() and scsi_set_resid() is an unsigned int. Reflect this fact in the interface of these helper functions. Also fix compilation errors due to min() and max() type mismatch introduced by this change in scsi debug code, usb transport code and in the USB ENE card reader driver. Link: https://lore.kernel.org/r/20191030090847.25650-1-damien.lemoal@wdc.com Signed-off-by: Damien Le Moal Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 4 ++-- drivers/usb/storage/ene_ub6250.c | 2 +- drivers/usb/storage/transport.c | 3 +-- include/scsi/scsi_cmnd.h | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index d323523f5f9d..4daf2637c011 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -1025,7 +1025,7 @@ static int fill_from_dev_buffer(struct scsi_cmnd *scp, unsigned char *arr, static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, int arr_len, unsigned int off_dst) { - int act_len, n; + unsigned int act_len, n; struct scsi_data_buffer *sdb = &scp->sdb; off_t skip = off_dst; @@ -1039,7 +1039,7 @@ static int p_fill_from_dev_buffer(struct scsi_cmnd *scp, const void *arr, pr_debug("%s: off_dst=%u, scsi_bufflen=%u, act_len=%u, resid=%d\n", __func__, off_dst, scsi_bufflen(scp), act_len, scsi_get_resid(scp)); - n = (int)scsi_bufflen(scp) - ((int)off_dst + act_len); + n = scsi_bufflen(scp) - (off_dst + act_len); scsi_set_resid(scp, min(scsi_get_resid(scp), n)); return 0; } diff --git a/drivers/usb/storage/ene_ub6250.c b/drivers/usb/storage/ene_ub6250.c index 8b1b73065421..98c1aa594e6c 100644 --- a/drivers/usb/storage/ene_ub6250.c +++ b/drivers/usb/storage/ene_ub6250.c @@ -561,7 +561,7 @@ static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) residue = min(residue, transfer_length); if (us->srb != NULL) scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), - (int)residue)); + residue)); } if (bcs->Status != US_BULK_STAT_OK) diff --git a/drivers/usb/storage/transport.c b/drivers/usb/storage/transport.c index 96cb0409dd89..238a8088e17f 100644 --- a/drivers/usb/storage/transport.c +++ b/drivers/usb/storage/transport.c @@ -1284,8 +1284,7 @@ int usb_stor_Bulk_transport(struct scsi_cmnd *srb, struct us_data *us) } else { residue = min(residue, transfer_length); - scsi_set_resid(srb, max(scsi_get_resid(srb), - (int) residue)); + scsi_set_resid(srb, max(scsi_get_resid(srb), residue)); } } diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h index 9c22e85902ec..a2849bb9cd19 100644 --- a/include/scsi/scsi_cmnd.h +++ b/include/scsi/scsi_cmnd.h @@ -191,12 +191,12 @@ static inline unsigned scsi_bufflen(struct scsi_cmnd *cmd) return cmd->sdb.length; } -static inline void scsi_set_resid(struct scsi_cmnd *cmd, int resid) +static inline void scsi_set_resid(struct scsi_cmnd *cmd, unsigned int resid) { cmd->req.resid_len = resid; } -static inline int scsi_get_resid(struct scsi_cmnd *cmd) +static inline unsigned int scsi_get_resid(struct scsi_cmnd *cmd) { return cmd->req.resid_len; } -- cgit v1.2.3 From 0eccce866f84db2cd23e1f28737920aa7b9e70d7 Mon Sep 17 00:00:00 2001 From: Damien Le Moal Date: Fri, 8 Nov 2019 17:29:01 +0900 Subject: scsi: target: tcmu: Prevent memory reclaim recursion Prevent recursion into the IO path under low memory conditions by using GFP_NOIO in place of GFP_KERNEL when allocating a new command with tcmu_alloc_cmd() and user ring space with tcmu_get_empty_block(). Link: https://lore.kernel.org/r/20191108082901.417950-1-damien.lemoal@wdc.com Reported-by: Masato Suzuki Signed-off-by: Damien Le Moal Acked-by: Mike Christie Reviewed-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_user.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 35be1be87d2a..0b9dfa6b17bc 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c @@ -499,7 +499,7 @@ static inline bool tcmu_get_empty_block(struct tcmu_dev *udev, schedule_delayed_work(&tcmu_unmap_work, 0); /* try to get new page from the mm */ - page = alloc_page(GFP_KERNEL); + page = alloc_page(GFP_NOIO); if (!page) goto err_alloc; @@ -573,7 +573,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) struct tcmu_dev *udev = TCMU_DEV(se_dev); struct tcmu_cmd *tcmu_cmd; - tcmu_cmd = kmem_cache_zalloc(tcmu_cmd_cache, GFP_KERNEL); + tcmu_cmd = kmem_cache_zalloc(tcmu_cmd_cache, GFP_NOIO); if (!tcmu_cmd) return NULL; @@ -584,7 +584,7 @@ static struct tcmu_cmd *tcmu_alloc_cmd(struct se_cmd *se_cmd) tcmu_cmd_reset_dbi_cur(tcmu_cmd); tcmu_cmd->dbi_cnt = tcmu_cmd_get_block_cnt(tcmu_cmd); tcmu_cmd->dbi = kcalloc(tcmu_cmd->dbi_cnt, sizeof(uint32_t), - GFP_KERNEL); + GFP_NOIO); if (!tcmu_cmd->dbi) { kmem_cache_free(tcmu_cmd_cache, tcmu_cmd); return NULL; -- cgit v1.2.3 From 8e31a94938adffb208f714a33ba651491b53a5d0 Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Fri, 8 Nov 2019 22:18:56 +0530 Subject: scsi: dt-bindings: ufs: ti,j721e-ufs.yaml: Add binding for TI UFS wrapper Add binding documentation of TI wrapper for Cadence UFS Controller. Link: https://lore.kernel.org/r/20191108164857.11466-2-vigneshr@ti.com Reviewed-by: Rob Herring Signed-off-by: Vignesh Raghavendra Signed-off-by: Martin K. Petersen --- .../devicetree/bindings/ufs/ti,j721e-ufs.yaml | 68 ++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml diff --git a/Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml b/Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml new file mode 100644 index 000000000000..c8a2a92074df --- /dev/null +++ b/Documentation/devicetree/bindings/ufs/ti,j721e-ufs.yaml @@ -0,0 +1,68 @@ +# SPDX-License-Identifier: GPL-2.0 +%YAML 1.2 +--- +$id: http://devicetree.org/schemas/ufs/ti,j721e-ufs.yaml# +$schema: http://devicetree.org/meta-schemas/core.yaml# + +title: TI J721e UFS Host Controller Glue Driver + +maintainers: + - Vignesh Raghavendra + +properties: + compatible: + items: + - const: ti,j721e-ufs + + reg: + maxItems: 1 + description: address of TI UFS glue registers + + clocks: + maxItems: 1 + description: phandle to the M-PHY clock + + power-domains: + maxItems: 1 + +required: + - compatible + - reg + - clocks + - power-domains + +patternProperties: + "^ufs@[0-9a-f]+$": + type: object + description: | + Cadence UFS controller node must be the child node. Refer + Documentation/devicetree/bindings/ufs/cdns,ufshc.txt for binding + documentation of child node + +examples: + - | + #include + #include + + ufs_wrapper: ufs-wrapper@4e80000 { + compatible = "ti,j721e-ufs"; + reg = <0x0 0x4e80000 0x0 0x100>; + power-domains = <&k3_pds 277>; + clocks = <&k3_clks 277 1>; + assigned-clocks = <&k3_clks 277 1>; + assigned-clock-parents = <&k3_clks 277 4>; + #address-cells = <2>; + #size-cells = <2>; + + ufs@4e84000 { + compatible = "cdns,ufshc-m31-16nm", "jedec,ufs-2.0"; + reg = <0x0 0x4e84000 0x0 0x10000>; + interrupts = ; + freq-table-hz = <19200000 19200000>; + power-domains = <&k3_pds 277>; + clocks = <&k3_clks 277 1>; + assigned-clocks = <&k3_clks 277 1>; + assigned-clock-parents = <&k3_clks 277 4>; + clock-names = "core_clk"; + }; + }; -- cgit v1.2.3 From 6979e56cec9782db0d7b5700058c0d60dc31b7cc Mon Sep 17 00:00:00 2001 From: Vignesh Raghavendra Date: Fri, 8 Nov 2019 22:18:57 +0530 Subject: scsi: ufs: Add driver for TI wrapper for Cadence UFS IP TI's J721e SoC has a Cadence UFS IP with a TI specific wrapper. This is a minimal driver to configure the wrapper. It releases the UFS slave device out of reset and sets up registers to indicate PHY reference clock input frequency before probing child Cadence UFS driver. Link: https://lore.kernel.org/r/20191108164857.11466-3-vigneshr@ti.com Reviewed-by: Avri Altman Reviewed-by: Alim Akhtar Signed-off-by: Vignesh Raghavendra Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/Kconfig | 10 +++++ drivers/scsi/ufs/Makefile | 1 + drivers/scsi/ufs/ti-j721e-ufs.c | 90 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 101 insertions(+) create mode 100644 drivers/scsi/ufs/ti-j721e-ufs.c diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig index 0b845ab7c3bf..d14c2243e02a 100644 --- a/drivers/scsi/ufs/Kconfig +++ b/drivers/scsi/ufs/Kconfig @@ -132,6 +132,16 @@ config SCSI_UFS_HISI Select this if you have UFS controller on Hisilicon chipset. If unsure, say N. +config SCSI_UFS_TI_J721E + tristate "TI glue layer for Cadence UFS Controller" + depends on OF && HAS_IOMEM && (ARCH_K3 || COMPILE_TEST) + help + This selects driver for TI glue layer for Cadence UFS Host + Controller IP. + + Selects this if you have TI platform with UFS controller. + If unsure, say N. + config SCSI_UFS_BSG bool "Universal Flash Storage BSG device node" depends on SCSI_UFSHCD diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile index 2a9097939bcb..94c6c5d7334b 100644 --- a/drivers/scsi/ufs/Makefile +++ b/drivers/scsi/ufs/Makefile @@ -11,3 +11,4 @@ obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o obj-$(CONFIG_SCSI_UFS_HISI) += ufs-hisi.o obj-$(CONFIG_SCSI_UFS_MEDIATEK) += ufs-mediatek.o +obj-$(CONFIG_SCSI_UFS_TI_J721E) += ti-j721e-ufs.o diff --git a/drivers/scsi/ufs/ti-j721e-ufs.c b/drivers/scsi/ufs/ti-j721e-ufs.c new file mode 100644 index 000000000000..5216d228cdd9 --- /dev/null +++ b/drivers/scsi/ufs/ti-j721e-ufs.c @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +// +// Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ +// + +#include +#include +#include +#include +#include +#include +#include + +#define TI_UFS_SS_CTRL 0x4 +#define TI_UFS_SS_RST_N_PCS BIT(0) +#define TI_UFS_SS_CLK_26MHZ BIT(4) + +static int ti_j721e_ufs_probe(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + unsigned long clk_rate; + void __iomem *regbase; + struct clk *clk; + u32 reg = 0; + int ret; + + regbase = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(regbase)) + return PTR_ERR(regbase); + + pm_runtime_enable(dev); + ret = pm_runtime_get_sync(dev); + if (ret < 0) { + pm_runtime_put_noidle(dev); + return ret; + } + + /* Select MPHY refclk frequency */ + clk = devm_clk_get(dev, NULL); + if (IS_ERR(clk)) { + dev_err(dev, "Cannot claim MPHY clock.\n"); + return PTR_ERR(clk); + } + clk_rate = clk_get_rate(clk); + if (clk_rate == 26000000) + reg |= TI_UFS_SS_CLK_26MHZ; + devm_clk_put(dev, clk); + + /* Take UFS slave device out of reset */ + reg |= TI_UFS_SS_RST_N_PCS; + writel(reg, regbase + TI_UFS_SS_CTRL); + + ret = of_platform_populate(pdev->dev.of_node, NULL, NULL, + dev); + if (ret) { + dev_err(dev, "failed to populate child nodes %d\n", ret); + pm_runtime_put_sync(dev); + } + + return ret; +} + +static int ti_j721e_ufs_remove(struct platform_device *pdev) +{ + of_platform_depopulate(&pdev->dev); + pm_runtime_put_sync(&pdev->dev); + + return 0; +} + +static const struct of_device_id ti_j721e_ufs_of_match[] = { + { + .compatible = "ti,j721e-ufs", + }, + { }, +}; + +static struct platform_driver ti_j721e_ufs_driver = { + .probe = ti_j721e_ufs_probe, + .remove = ti_j721e_ufs_remove, + .driver = { + .name = "ti-j721e-ufs", + .of_match_table = ti_j721e_ufs_of_match, + }, +}; +module_platform_driver(ti_j721e_ufs_driver); + +MODULE_AUTHOR("Vignesh Raghavendra "); +MODULE_DESCRIPTION("TI UFS host controller glue driver"); +MODULE_LICENSE("GPL v2"); -- cgit v1.2.3 From 6f23f8c5c9f1be4eb17c035129c80e49000c18a7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 11 Nov 2019 15:03:56 -0800 Subject: scsi: lpfc: fix: Coverity: lpfc_get_scsi_buf_s3(): Null pointer dereferences Coverity reported the following: *** CID 1487391: Null pointer dereferences (FORWARD_NULL) /drivers/scsi/lpfc/lpfc_scsi.c: 614 in lpfc_get_scsi_buf_s3() 608 spin_unlock(&phba->scsi_buf_list_put_lock); 609 } 610 spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, iflag); 611 612 if (lpfc_ndlp_check_qdepth(phba, ndlp)) { 613 atomic_inc(&ndlp->cmd_pending); vvv CID 1487391: Null pointer dereferences (FORWARD_NULL) vvv Dereferencing null pointer "lpfc_cmd". 614 lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; 615 } 616 return lpfc_cmd; 617 } 618 /** 619 * lpfc_get_scsi_buf_s4 - Get a scsi buffer from io_buf_list of the HBA Fix by checking lpfc_cmd to be non-NULL as part of line 612 Reported-by: coverity-bot Addresses-Coverity-ID: 1487391 ("Null pointer dereferences") Fixes: 2a5b7d626ed2 ("scsi: lpfc: Limit tracking of tgt queue depth in fast path") CC: "Martin K. Petersen" CC: "Gustavo A. R. Silva" CC: linux-next@vger.kernel.org Link: https://lore.kernel.org/r/20191111230401.12958-2-jsmart2021@gmail.com Reviewed-by: Ewan D. Milne Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_scsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c index 959ef471d758..ba26df90a36a 100644 --- a/drivers/scsi/lpfc/lpfc_scsi.c +++ b/drivers/scsi/lpfc/lpfc_scsi.c @@ -611,7 +611,7 @@ lpfc_get_scsi_buf_s3(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, } spin_unlock_irqrestore(&phba->scsi_buf_list_get_lock, iflag); - if (lpfc_ndlp_check_qdepth(phba, ndlp)) { + if (lpfc_ndlp_check_qdepth(phba, ndlp) && lpfc_cmd) { atomic_inc(&ndlp->cmd_pending); lpfc_cmd->flags |= LPFC_SBUF_BUMP_QDEPTH; } -- cgit v1.2.3 From 6c6d59e0fe5b86cf273d6d744a6a9768c4ecc756 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 11 Nov 2019 15:03:57 -0800 Subject: scsi: lpfc: fix: Coverity: lpfc_cmpl_els_rsp(): Null pointer dereferences Coverity reported the following: *** CID 101747: Null pointer dereferences (FORWARD_NULL) /drivers/scsi/lpfc/lpfc_els.c: 4439 in lpfc_cmpl_els_rsp() 4433 kfree(mp); 4434 } 4435 mempool_free(mbox, phba->mbox_mem_pool); 4436 } 4437 out: 4438 if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { vvv CID 101747: Null pointer dereferences (FORWARD_NULL) vvv Dereferencing null pointer "shost". 4439 spin_lock_irq(shost->host_lock); 4440 ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); 4441 spin_unlock_irq(shost->host_lock); 4442 4443 /* If the node is not being used by another discovery thread, 4444 * and we are sending a reject, we are done with it. Fix by adding a check for non-null shost in line 4438. The scenario when shost is set to null is when ndlp is null. As such, the ndlp check present was sufficient. But better safe than sorry so add the shost check. Reported-by: coverity-bot Addresses-Coverity-ID: 101747 ("Null pointer dereferences") Fixes: 2e0fef85e098 ("[SCSI] lpfc: NPIV: split ports") CC: James Bottomley CC: "Gustavo A. R. Silva" CC: linux-next@vger.kernel.org Link: https://lore.kernel.org/r/20191111230401.12958-3-jsmart2021@gmail.com Reviewed-by: Ewan D. Milne Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_els.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 9a570c15b2a1..42a2bf38eaea 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -4445,7 +4445,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, mempool_free(mbox, phba->mbox_mem_pool); } out: - if (ndlp && NLP_CHK_NODE_ACT(ndlp)) { + if (ndlp && NLP_CHK_NODE_ACT(ndlp) && shost) { spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~(NLP_ACC_REGLOGIN | NLP_RM_DFLT_RPI); spin_unlock_irq(shost->host_lock); -- cgit v1.2.3 From d480e57809a043333a3b9e755c0bdd43e10a9f12 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 11 Nov 2019 15:03:58 -0800 Subject: scsi: lpfc: fix inlining of lpfc_sli4_cleanup_poll_list() Compilation can fail due to having an inline function reference where the function body is not present. Fix by removing the inline tag. Fixes: 93a4d6f40198 ("scsi: lpfc: Add registration for CPU Offline/Online events") Link: https://lore.kernel.org/r/20191111230401.12958-4-jsmart2021@gmail.com Reviewed-by: Ewan D. Milne Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_crtn.h | 2 +- drivers/scsi/lpfc/lpfc_sli.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_crtn.h b/drivers/scsi/lpfc/lpfc_crtn.h index d91aa5330306..ee353c84a097 100644 --- a/drivers/scsi/lpfc/lpfc_crtn.h +++ b/drivers/scsi/lpfc/lpfc_crtn.h @@ -215,7 +215,7 @@ irqreturn_t lpfc_sli_fp_intr_handler(int, void *); irqreturn_t lpfc_sli4_intr_handler(int, void *); irqreturn_t lpfc_sli4_hba_intr_handler(int, void *); -inline void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba); +void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba); int lpfc_sli4_poll_eq(struct lpfc_queue *q, uint8_t path); void lpfc_sli4_poll_hbtimer(struct timer_list *t); void lpfc_sli4_start_polling(struct lpfc_queue *q); diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 613fbf4a7da9..5286c78645ac 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -14466,7 +14466,7 @@ static inline void lpfc_sli4_remove_from_poll_list(struct lpfc_queue *eq) del_timer_sync(&phba->cpuhp_poll_timer); } -inline void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba) +void lpfc_sli4_cleanup_poll_list(struct lpfc_hba *phba) { struct lpfc_queue *eq, *next; -- cgit v1.2.3 From bc227dde0d8b687aa525d01b0df5556d4d37eca3 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 11 Nov 2019 15:03:59 -0800 Subject: scsi: lpfc: Initialize cpu_map for not present cpus Currently, cpu_map[cpu#]->hdwq is left to equal LPFC_VECTOR_MAP_EMPTY for not present CPUs. If a CPU is dynamically hot-added, it is possible we may crash due to not assigning an allocated hdwq. Correct by assigning a hdwq at initialization for all not-present CPUs. Fixes: dcaa21367938 ("scsi: lpfc: Change default IRQ model on AMD architectures") Link: https://lore.kernel.org/r/20191111230401.12958-5-jsmart2021@gmail.com Reviewed-by: Ewan D. Milne Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_init.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_init.c b/drivers/scsi/lpfc/lpfc_init.c index 303bfff0ecc8..e9323889f199 100644 --- a/drivers/scsi/lpfc/lpfc_init.c +++ b/drivers/scsi/lpfc/lpfc_init.c @@ -11004,7 +11004,7 @@ found_any: cpu, cpup->phys_id, cpup->core_id, cpup->hdwq, cpup->eq, cpup->flag); } - /* Finally we need to associate a hdwq with each cpu_map entry + /* Associate a hdwq with each cpu_map entry * This will be 1 to 1 - hdwq to cpu, unless there are less * hardware queues then CPUs. For that case we will just round-robin * the available hardware queues as they get assigned to CPUs. @@ -11083,6 +11083,23 @@ found_any: cpup->hdwq, cpup->eq, cpup->flag); } + /* + * Initialize the cpu_map slots for not-present cpus in case + * a cpu is hot-added. Perform a simple hdwq round robin assignment. + */ + idx = 0; + for_each_possible_cpu(cpu) { + cpup = &phba->sli4_hba.cpu_map[cpu]; + if (cpup->hdwq != LPFC_VECTOR_MAP_EMPTY) + continue; + + cpup->hdwq = idx++ % phba->cfg_hdw_queue; + lpfc_printf_log(phba, KERN_INFO, LOG_INIT, + "3340 Set Affinity: not present " + "CPU %d hdwq %d\n", + cpu, cpup->hdwq); + } + /* The cpu_map array will be used later during initialization * when EQ / CQ / WQs are allocated and configured. */ -- cgit v1.2.3 From 542ddc9b346984cb5bbc2a923d3f3f27ae961ffa Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 11 Nov 2019 15:04:00 -0800 Subject: scsi: lpfc: revise nvme max queues to be hdwq count Driver is setting the initiator nvme template with a max hw queues value of the present cpu count which is odd. It should be registering the number of hdwq queues (queues created on the adapter). Change to set nvme tempate, in all cases, to the number of hardware queues. Link: https://lore.kernel.org/r/20191111230401.12958-6-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_nvme.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_nvme.c b/drivers/scsi/lpfc/lpfc_nvme.c index 328ddce87f12..db4a04a207ec 100644 --- a/drivers/scsi/lpfc/lpfc_nvme.c +++ b/drivers/scsi/lpfc/lpfc_nvme.c @@ -2148,12 +2148,10 @@ lpfc_nvme_create_localport(struct lpfc_vport *vport) */ lpfc_nvme_template.max_sgl_segments = phba->cfg_nvme_seg_cnt + 1; - /* Advertise how many hw queues we support based on fcp_io_sched */ - if (phba->cfg_fcp_io_sched == LPFC_FCP_SCHED_BY_HDWQ) - lpfc_nvme_template.max_hw_queues = phba->cfg_hdw_queue; - else - lpfc_nvme_template.max_hw_queues = - phba->sli4_hba.num_present_cpu; + /* Advertise how many hw queues we support based on cfg_hdw_queue, + * which will not exceed cpu count. + */ + lpfc_nvme_template.max_hw_queues = phba->cfg_hdw_queue; if (!IS_ENABLED(CONFIG_NVME_FC)) return ret; -- cgit v1.2.3 From 3b294c0fb910dc91250abab574e85c9c1957c795 Mon Sep 17 00:00:00 2001 From: James Smart Date: Mon, 11 Nov 2019 15:04:01 -0800 Subject: scsi: lpfc: Update lpfc version to 12.6.0.2 Update lpfc version to 12.6.0.2 Link: https://lore.kernel.org/r/20191111230401.12958-7-jsmart2021@gmail.com Reviewed-by: Ewan D. Milne Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/lpfc/lpfc_version.h b/drivers/scsi/lpfc/lpfc_version.h index 1532390770f5..9e5ff58edaca 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 "12.6.0.1" +#define LPFC_DRIVER_VERSION "12.6.0.2" #define LPFC_DRIVER_NAME "lpfc" /* Used for SLI 2/3 */ -- cgit v1.2.3 From 8c39673d5474b95374df2104dc1f65205c5278b8 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Tue, 12 Nov 2019 17:30:56 +0800 Subject: scsi: hisi_sas: Check sas_port before using it Need to check the structure sas_port before using it. Link: https://lore.kernel.org/r/1573551059-107873-2-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index 18c95b33592b..c72fc59353bd 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -974,12 +974,13 @@ static void hisi_sas_port_notify_formed(struct asd_sas_phy *sas_phy) struct hisi_hba *hisi_hba = sas_ha->lldd_ha; struct hisi_sas_phy *phy = sas_phy->lldd_phy; struct asd_sas_port *sas_port = sas_phy->port; - struct hisi_sas_port *port = to_hisi_sas_port(sas_port); + struct hisi_sas_port *port; unsigned long flags; if (!sas_port) return; + port = to_hisi_sas_port(sas_port); spin_lock_irqsave(&hisi_hba->lock, flags); port->port_attached = 1; port->id = phy->port_id; -- cgit v1.2.3 From 547fde8b5a1923050f388caae4f76613b5a620e0 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Tue, 12 Nov 2019 17:30:57 +0800 Subject: scsi: hisi_sas: Return directly if init hardware failed Need to return directly if init hardware failed. Fixes: 73a4925d154c ("scsi: hisi_sas: Update all the registers after suspend and resume") Link: https://lore.kernel.org/r/1573551059-107873-3-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index 2ae7070db41a..b7836406debe 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3432,6 +3432,7 @@ static int hisi_sas_v3_resume(struct pci_dev *pdev) if (rc) { scsi_remove_host(shost); pci_disable_device(pdev); + return rc; } hisi_hba->hw->phys_init(hisi_hba); sas_resume_ha(sha); -- cgit v1.2.3 From 7c0ecd40c31246a2d0de81879966436ff07505a4 Mon Sep 17 00:00:00 2001 From: Xiang Chen Date: Tue, 12 Nov 2019 17:30:58 +0800 Subject: scsi: hisi_sas: Relocate call to hisi_sas_debugfs_exit() Currently we call function hisi_sas_debugfs_exit() to remove debugfs_dir before freeing interrupt irqs and destroying workqueue in the driver remove path. If a dump is triggered before function hisi_sas_debugfs_exit() but debugfs_work may be called after it, so it may refer to already removed debugfs_dir which will cause NULL pointer dereference. To avoid it, put function hisi_sas_debugfs_exit() after free_irqs and destroy workqueue when removing hisi_sas driver. Link: https://lore.kernel.org/r/1573551059-107873-4-git-send-email-john.garry@huawei.com Signed-off-by: Xiang Chen Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_v3_hw.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c index b7836406debe..bf5d5f138437 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c +++ b/drivers/scsi/hisi_sas/hisi_sas_v3_hw.c @@ -3302,8 +3302,6 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) struct hisi_hba *hisi_hba = sha->lldd_ha; struct Scsi_Host *shost = sha->core.shost; - hisi_sas_debugfs_exit(hisi_hba); - if (timer_pending(&hisi_hba->timer)) del_timer(&hisi_hba->timer); @@ -3315,6 +3313,7 @@ static void hisi_sas_v3_remove(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); hisi_sas_free(hisi_hba); + hisi_sas_debugfs_exit(hisi_hba); scsi_host_put(shost); } -- cgit v1.2.3 From 964231aa0c7ef53ebc9c2a6889bbc50d8a3f2220 Mon Sep 17 00:00:00 2001 From: John Garry Date: Tue, 12 Nov 2019 17:30:59 +0800 Subject: scsi: hisi_sas: Stop converting a bool into a bool The !! operator on a bool is pointless, so remove an example in hisi_sas_rescan_topology(). Link: https://lore.kernel.org/r/1573551059-107873-5-git-send-email-john.garry@huawei.com Signed-off-by: John Garry Signed-off-by: Martin K. Petersen --- drivers/scsi/hisi_sas/hisi_sas_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/hisi_sas/hisi_sas_main.c b/drivers/scsi/hisi_sas/hisi_sas_main.c index c72fc59353bd..03588ec3c394 100644 --- a/drivers/scsi/hisi_sas/hisi_sas_main.c +++ b/drivers/scsi/hisi_sas/hisi_sas_main.c @@ -1413,7 +1413,7 @@ static void hisi_sas_rescan_topology(struct hisi_hba *hisi_hba, u32 state) struct hisi_sas_phy *phy = &hisi_hba->phy[phy_no]; struct asd_sas_phy *sas_phy = &phy->sas_phy; struct asd_sas_port *sas_port = sas_phy->port; - bool do_port_check = !!(_sas_port != sas_port); + bool do_port_check = _sas_port != sas_port; if (!sas_phy->phy->enabled) continue; -- cgit v1.2.3 From 3d4881d1d6450b7b60da498e607610ac382bdb49 Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 12 Nov 2019 23:34:35 +0100 Subject: scsi: ufs: print helpful hint when response size exceed buffer size Print out returned response size and buffer size, while the front one is bigger than the back one. Link: https://lore.kernel.org/r/20191112223436.27449-2-huobean@gmail.com Reviewed-by: Alim Akhtar Reviewed-by: Bart Van Assche Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 9cbe3b45cf1c..527bd3b4f834 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1938,8 +1938,8 @@ int ufshcd_copy_query_response(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) memcpy(hba->dev_cmd.query.descriptor, descp, resp_len); } else { dev_warn(hba->dev, - "%s: Response size is bigger than buffer", - __func__); + "%s: rsp size %d is bigger than buffer size %d", + __func__, resp_len, buf_len); return -EINVAL; } } @@ -5864,7 +5864,9 @@ static int ufshcd_issue_devman_upiu_cmd(struct ufs_hba *hba, memcpy(desc_buff, descp, resp_len); *buff_len = resp_len; } else { - dev_warn(hba->dev, "rsp size is bigger than buffer"); + dev_warn(hba->dev, + "%s: rsp size %d is bigger than buffer size %d", + __func__, resp_len, *buff_len); *buff_len = 0; err = -EINVAL; } -- cgit v1.2.3 From cfcbae3895b86c390ede57b2a8f601dd5972b47b Mon Sep 17 00:00:00 2001 From: Bean Huo Date: Tue, 12 Nov 2019 23:34:36 +0100 Subject: scsi: ufs: fix potential bug which ends in system hang In function __ufshcd_query_descriptor(), in the event of an error happening, we directly goto out_unlock and forget to invaliate hba->dev_cmd.query.descriptor pointer. This results in this pointer still valid in ufshcd_copy_query_response() for other query requests which go through ufshcd_exec_raw_upiu_cmd(). This will cause __memcpy() crash and system hangs. Log as shown below: Unable to handle kernel paging request at virtual address ffff000012233c40 Mem abort info: ESR = 0x96000047 Exception class = DABT (current EL), IL = 32 bits SET = 0, FnV = 0 EA = 0, S1PTW = 0 Data abort info: ISV = 0, ISS = 0x00000047 CM = 0, WnR = 1 swapper pgtable: 4k pages, 48-bit VAs, pgdp = 0000000028cc735c [ffff000012233c40] pgd=00000000bffff003, pud=00000000bfffe003, pmd=00000000ba8b8003, pte=0000000000000000 Internal error: Oops: 96000047 [#2] PREEMPT SMP ... Call trace: __memcpy+0x74/0x180 ufshcd_issue_devman_upiu_cmd+0x250/0x3c0 ufshcd_exec_raw_upiu_cmd+0xfc/0x1a8 ufs_bsg_request+0x178/0x3b0 bsg_queue_rq+0xc0/0x118 blk_mq_dispatch_rq_list+0xb0/0x538 blk_mq_sched_dispatch_requests+0x18c/0x1d8 __blk_mq_run_hw_queue+0xb4/0x118 blk_mq_run_work_fn+0x28/0x38 process_one_work+0x1ec/0x470 worker_thread+0x48/0x458 kthread+0x130/0x138 ret_from_fork+0x10/0x1c Code: 540000ab a8c12027 a88120c7 a8c12027 (a88120c7) ---[ end trace 793e1eb5dff69f2d ]--- note: kworker/0:2H[2054] exited with preempt_count 1 This patch is to move "descriptor = NULL" down to below the label "out_unlock". Fixes: d44a5f98bb49b2(ufs: query descriptor API) Link: https://lore.kernel.org/r/20191112223436.27449-3-huobean@gmail.com Reviewed-by: Alim Akhtar Reviewed-by: Bart Van Assche Signed-off-by: Bean Huo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 527bd3b4f834..977d0c6fef95 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -2989,10 +2989,10 @@ static int __ufshcd_query_descriptor(struct ufs_hba *hba, goto out_unlock; } - hba->dev_cmd.query.descriptor = NULL; *buf_len = be16_to_cpu(response->upiu_res.length); out_unlock: + hba->dev_cmd.query.descriptor = NULL; mutex_unlock(&hba->dev_cmd.lock); out: ufshcd_release(hba); -- cgit v1.2.3 From 63f565aa6e06d07bcf0cb7cfac82889c12c465a3 Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Tue, 29 Oct 2019 06:15:30 +0000 Subject: scsi: csiostor: Remove set but not used variable 'rln' Fixes gcc '-Wunused-but-set-variable' warning: drivers/scsi/csiostor/csio_lnode.c: In function 'csio_ln_init': drivers/scsi/csiostor/csio_lnode.c:1995:21: warning: variable 'rln' set but not used [-Wunused-but-set-variable] It is never used since introduction, so remove it. Link: https://lore.kernel.org/r/20191029061530.98197-1-yuehaibing@huawei.com Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/csiostor/csio_lnode.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c index 23cbe4cda760..74ff8adc41f7 100644 --- a/drivers/scsi/csiostor/csio_lnode.c +++ b/drivers/scsi/csiostor/csio_lnode.c @@ -1992,7 +1992,7 @@ static int csio_ln_init(struct csio_lnode *ln) { int rv = -EINVAL; - struct csio_lnode *rln, *pln; + struct csio_lnode *pln; struct csio_hw *hw = csio_lnode_to_hw(ln); csio_init_state(&ln->sm, csio_lns_uninit); @@ -2022,7 +2022,6 @@ csio_ln_init(struct csio_lnode *ln) * THe rest is common for non-root physical and NPIV lnodes. * Just get references to all other modules */ - rln = csio_root_lnode(ln); if (csio_is_npiv_ln(ln)) { /* NPIV */ -- cgit v1.2.3 From 02f7e9f351a9de95577eafdc3bd413ed1c3b589f Mon Sep 17 00:00:00 2001 From: Kars de Jong Date: Tue, 12 Nov 2019 18:55:23 +0100 Subject: scsi: zorro_esp: Limit DMA transfers to 65536 bytes (except on Fastlane) When using this driver on a Blizzard 1260, there were failures whenever DMA transfers from the SCSI bus to memory of 65535 bytes were followed by a DMA transfer of 1 byte. This caused the byte at offset 65535 to be overwritten with 0xff. The Blizzard hardware can't handle single byte DMA transfers. Besides this issue, limiting the DMA length to something that is not a multiple of the page size is very inefficient on most file systems. It seems this limit was chosen because the DMA transfer counter of the ESP by default is 16 bits wide, thus limiting the length to 65535 bytes. However, the value 0 means 65536 bytes, which is handled by the ESP and the Blizzard just fine. It is also the default maximum used by esp_scsi when drivers don't provide their own dma_length_limit() function. The limit of 65536 bytes can be used by all boards except the Fastlane. The old driver used a limit of 65532 bytes (0xfffc), which is reintroduced in this patch. Fixes: b7ded0e8b0d1 ("scsi: zorro_esp: Limit DMA transfers to 65535 bytes") Link: https://lore.kernel.org/r/20191112175523.23145-1-jongk@linux-m68k.org Signed-off-by: Kars de Jong Reviewed-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/zorro_esp.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/zorro_esp.c b/drivers/scsi/zorro_esp.c index ca8e3abeb2c7..a23a8e5794f5 100644 --- a/drivers/scsi/zorro_esp.c +++ b/drivers/scsi/zorro_esp.c @@ -218,7 +218,14 @@ static int fastlane_esp_irq_pending(struct esp *esp) static u32 zorro_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len) { - return dma_len > 0xFFFF ? 0xFFFF : dma_len; + return dma_len > (1U << 16) ? (1U << 16) : dma_len; +} + +static u32 fastlane_esp_dma_length_limit(struct esp *esp, u32 dma_addr, + u32 dma_len) +{ + /* The old driver used 0xfffc as limit, so do that here too */ + return dma_len > 0xfffc ? 0xfffc : dma_len; } static void zorro_esp_reset_dma(struct esp *esp) @@ -604,7 +611,7 @@ static const struct esp_driver_ops fastlane_esp_ops = { .esp_write8 = zorro_esp_write8, .esp_read8 = zorro_esp_read8, .irq_pending = fastlane_esp_irq_pending, - .dma_length_limit = zorro_esp_dma_length_limit, + .dma_length_limit = fastlane_esp_dma_length_limit, .reset_dma = zorro_esp_reset_dma, .dma_drain = zorro_esp_dma_drain, .dma_invalidate = fastlane_esp_dma_invalidate, -- cgit v1.2.3 From 70e8d9accd0a9165972031ff51b4f28ee8287c0f Mon Sep 17 00:00:00 2001 From: YueHaibing Date: Fri, 1 Nov 2019 22:00:58 +0800 Subject: scsi: ufs: ufshcd: Remove dev_err() on platform_get_irq() failure platform_get_irq() will call dev_err() itself on failure, so there is no need for the driver to also do this. This is detected by coccinelle. Link: https://lore.kernel.org/r/20191101140058.23212-1-yuehaibing@huawei.com Signed-off-by: YueHaibing Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd-pltfrm.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd-pltfrm.c b/drivers/scsi/ufs/ufshcd-pltfrm.c index 8d40dc918f4e..76f9be71c31b 100644 --- a/drivers/scsi/ufs/ufshcd-pltfrm.c +++ b/drivers/scsi/ufs/ufshcd-pltfrm.c @@ -402,7 +402,6 @@ int ufshcd_pltfrm_init(struct platform_device *pdev, irq = platform_get_irq(pdev, 0); if (irq < 0) { - dev_err(dev, "IRQ resource not available\n"); err = -ENODEV; goto out; } -- cgit v1.2.3 From 63cb70a1ee89d6d301466550f7306cd8d8892e66 Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 Nov 2019 09:56:08 +0100 Subject: scsi: nsp_cs: drop redundant MODULE_LICENSE ifdef The MODULE_LICENSE macro is unconditionally defined in module.h, no need to ifdef its use. Link: https://lore.kernel.org/r/20191105085609.2338-2-johan@kernel.org Signed-off-by: Johan Hovold Signed-off-by: Martin K. Petersen --- drivers/scsi/pcmcia/nsp_cs.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c index 97416e1dcc5b..93616f9fd6d7 100644 --- a/drivers/scsi/pcmcia/nsp_cs.c +++ b/drivers/scsi/pcmcia/nsp_cs.c @@ -56,9 +56,7 @@ MODULE_AUTHOR("YOKOTA Hiroshi "); MODULE_DESCRIPTION("WorkBit NinjaSCSI-3 / NinjaSCSI-32Bi(16bit) PCMCIA SCSI host adapter module"); MODULE_SUPPORTED_DEVICE("sd,sr,sg,st"); -#ifdef MODULE_LICENSE MODULE_LICENSE("GPL"); -#endif #include "nsp_io.h" -- cgit v1.2.3 From d04adaa475082e7f86ccb20bcfdd2601d1d1cb7b Mon Sep 17 00:00:00 2001 From: Johan Hovold Date: Tue, 5 Nov 2019 09:56:09 +0100 Subject: scsi: nsp_cs: enable compile-testing on 64-bit For some reason this driver depends on !64BIT, but it can still be useful to allow compile-testing on 64-bit machines. Link: https://lore.kernel.org/r/20191105085609.2338-3-johan@kernel.org Signed-off-by: Johan Hovold Signed-off-by: Martin K. Petersen --- drivers/scsi/pcmcia/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pcmcia/Kconfig b/drivers/scsi/pcmcia/Kconfig index 2368f34efba3..dc9b74c9348a 100644 --- a/drivers/scsi/pcmcia/Kconfig +++ b/drivers/scsi/pcmcia/Kconfig @@ -32,7 +32,7 @@ config PCMCIA_FDOMAIN config PCMCIA_NINJA_SCSI tristate "NinjaSCSI-3 / NinjaSCSI-32Bi (16bit) PCMCIA support" - depends on !64BIT + depends on !64BIT || COMPILE_TEST help If you intend to attach this type of PCMCIA SCSI host adapter to your computer, say Y here and read -- cgit v1.2.3 From 79172ab20bfd8437b277254028efdb68484e2c21 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 2 Nov 2019 12:06:54 +1100 Subject: scsi: atari_scsi: sun3_scsi: Set sg_tablesize to 1 instead of SG_NONE Since the scsi subsystem adopted the blk-mq API, a host with zero sg_tablesize crashes with a NULL pointer dereference. blk_queue_max_segments: set to minimum 1 scsi 0:0:0:0: Direct-Access QEMU QEMU HARDDISK 2.5+ PQ: 0 ANSI: 5 scsi target0:0:0: Beginning Domain Validation scsi target0:0:0: Domain Validation skipping write tests scsi target0:0:0: Ending Domain Validation blk_queue_max_segments: set to minimum 1 scsi 0:0:1:0: Direct-Access QEMU QEMU HARDDISK 2.5+ PQ: 0 ANSI: 5 scsi target0:0:1: Beginning Domain Validation scsi target0:0:1: Domain Validation skipping write tests scsi target0:0:1: Ending Domain Validation blk_queue_max_segments: set to minimum 1 scsi 0:0:2:0: CD-ROM QEMU QEMU CD-ROM 2.5+ PQ: 0 ANSI: 5 scsi target0:0:2: Beginning Domain Validation scsi target0:0:2: Domain Validation skipping write tests scsi target0:0:2: Ending Domain Validation blk_queue_max_segments: set to minimum 1 blk_queue_max_segments: set to minimum 1 blk_queue_max_segments: set to minimum 1 blk_queue_max_segments: set to minimum 1 sr 0:0:2:0: Power-on or device reset occurred sd 0:0:0:0: Power-on or device reset occurred sd 0:0:1:0: Power-on or device reset occurred sd 0:0:0:0: [sda] 10485762 512-byte logical blocks: (5.37 GB/5.00 GiB) sd 0:0:0:0: [sda] Write Protect is off sd 0:0:0:0: [sda] Write cache: enabled, read cache: enabled, doesn't support DPO or FUA Unable to handle kernel NULL pointer dereference at virtual address (ptrval) Oops: 00000000 Modules linked in: PC: [<001cd874>] blk_mq_free_request+0x66/0xe2 SR: 2004 SP: (ptrval) a2: 00874520 d0: 00000000 d1: 00000000 d2: 009ba800 d3: 00000000 d4: 00000000 d5: 08000002 a0: 0087be68 a1: 009a81e0 Process kworker/u2:2 (pid: 15, task=(ptrval)) Frame format=7 eff addr=0000007a ssw=0505 faddr=0000007a wb 1 stat/addr/data: 0000 00000000 00000000 wb 2 stat/addr/data: 0000 00000000 00000000 wb 3 stat/addr/data: 0000 0000007a 00000000 push data: 00000000 00000000 00000000 00000000 Stack from 0087bd98: 00000002 00000000 0087be72 009a7820 0087bdb4 001c4f6c 009a7820 0087bdd4 0024d200 009a7820 0024d0dc 0087be72 009baa00 0087be68 009a5000 0087be7c 00265d10 009a5000 0087be72 00000003 00000000 00000000 00000000 0087be68 00000bb8 00000005 00000000 00000000 00000000 00000000 00265c56 00000000 009ba60c 0036ddf4 00000002 ffffffff 009baa00 009ba600 009a50d6 0087be74 00227ba0 009baa08 00000001 009baa08 009ba60c 0036ddf4 00000000 00000000 Call Trace: [<001c4f6c>] blk_put_request+0xe/0x14 [<0024d200>] __scsi_execute+0x124/0x174 [<0024d0dc>] __scsi_execute+0x0/0x174 [<00265d10>] sd_revalidate_disk+0xba/0x1f02 [<00265c56>] sd_revalidate_disk+0x0/0x1f02 [<0036ddf4>] strlen+0x0/0x22 [<00227ba0>] device_add+0x3da/0x604 [<0036ddf4>] strlen+0x0/0x22 [<00267e64>] sd_probe+0x30c/0x4b4 [<0002da44>] process_one_work+0x0/0x402 [<0022b978>] really_probe+0x226/0x354 [<0022bc34>] driver_probe_device+0xa4/0xf0 [<0002da44>] process_one_work+0x0/0x402 [<0022bcd0>] __driver_attach_async_helper+0x50/0x70 [<00035dae>] async_run_entry_fn+0x36/0x130 [<0002db88>] process_one_work+0x144/0x402 [<0002e1aa>] worker_thread+0x0/0x570 [<0002e29a>] worker_thread+0xf0/0x570 [<0002e1aa>] worker_thread+0x0/0x570 [<003768d8>] schedule+0x0/0xb8 [<0003f58c>] __init_waitqueue_head+0x0/0x12 [<00033e92>] kthread+0xc2/0xf6 [<000331e8>] kthread_parkme+0x0/0x4e [<003768d8>] schedule+0x0/0xb8 [<00033dd0>] kthread+0x0/0xf6 [<00002c10>] ret_from_kernel_thread+0xc/0x14 Code: 0280 0006 0800 56c0 4400 0280 0000 00ff <52b4> 0c3a 082b 0006 0013 6706 2042 53a8 00c4 4ab9 0047 3374 6640 202d 000c 670c Disabling lock debugging due to kernel taint Avoid this by setting sg_tablesize = 1. Link: https://lore.kernel.org/r/4567bcae94523b47d6f3b77450ba305823bca479.1572656814.git.fthain@telegraphics.com.au Reported-and-tested-by: Michael Schmitz Reviewed-by: Michael Schmitz References: commit 68ab2d76e4be ("scsi: cxlflash: Set sg_tablesize to 1 instead of SG_NONE") Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/atari_scsi.c | 6 +++--- drivers/scsi/mac_scsi.c | 2 +- drivers/scsi/sun3_scsi.c | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index e809493d0d06..a82b63a66635 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -742,7 +742,7 @@ static int __init atari_scsi_probe(struct platform_device *pdev) atari_scsi_template.sg_tablesize = SG_ALL; } else { atari_scsi_template.can_queue = 1; - atari_scsi_template.sg_tablesize = SG_NONE; + atari_scsi_template.sg_tablesize = 1; } if (setup_can_queue > 0) @@ -751,8 +751,8 @@ static int __init atari_scsi_probe(struct platform_device *pdev) if (setup_cmd_per_lun > 0) atari_scsi_template.cmd_per_lun = setup_cmd_per_lun; - /* Leave sg_tablesize at 0 on a Falcon! */ - if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0) + /* Don't increase sg_tablesize on Falcon! */ + if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize > 0) atari_scsi_template.sg_tablesize = setup_sg_tablesize; if (setup_hostid >= 0) { diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c index 9c5566217ef6..b5dde9d0d054 100644 --- a/drivers/scsi/mac_scsi.c +++ b/drivers/scsi/mac_scsi.c @@ -464,7 +464,7 @@ static int __init mac_scsi_probe(struct platform_device *pdev) mac_scsi_template.can_queue = setup_can_queue; if (setup_cmd_per_lun > 0) mac_scsi_template.cmd_per_lun = setup_cmd_per_lun; - if (setup_sg_tablesize >= 0) + if (setup_sg_tablesize > 0) mac_scsi_template.sg_tablesize = setup_sg_tablesize; if (setup_hostid >= 0) mac_scsi_template.this_id = setup_hostid & 7; diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c index 955e4c938d49..701b842296f0 100644 --- a/drivers/scsi/sun3_scsi.c +++ b/drivers/scsi/sun3_scsi.c @@ -501,7 +501,7 @@ static struct scsi_host_template sun3_scsi_template = { .eh_host_reset_handler = sun3scsi_host_reset, .can_queue = 16, .this_id = 7, - .sg_tablesize = SG_NONE, + .sg_tablesize = 1, .cmd_per_lun = 2, .dma_boundary = PAGE_SIZE - 1, .cmd_size = NCR5380_CMD_SIZE, @@ -523,7 +523,7 @@ static int __init sun3_scsi_probe(struct platform_device *pdev) sun3_scsi_template.can_queue = setup_can_queue; if (setup_cmd_per_lun > 0) sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun; - if (setup_sg_tablesize >= 0) + if (setup_sg_tablesize > 0) sun3_scsi_template.sg_tablesize = setup_sg_tablesize; if (setup_hostid >= 0) sun3_scsi_template.this_id = setup_hostid & 7; -- cgit v1.2.3 From 35c3363363ac7c8877b4984cdd8a2af377a4e92e Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 2 Nov 2019 12:06:54 +1100 Subject: scsi: core: Clean up SG_NONE Remove SG_NONE and a related misleading comment. Update documentation. This patch does not affect behaviour as zero initialization is redundant. Cc: Jonathan Corbet Cc: Bartlomiej Zolnierkiewicz Cc: Jens Axboe Cc: Viresh Kumar Cc: Oliver Neukum Cc: Alan Stern Cc: Greg Kroah-Hartman Cc: usb-storage@lists.one-eyed-alien.net Link: https://lore.kernel.org/r/b4779b7a6563f6bd8d259ee457871c1c463c420e.1572656814.git.fthain@telegraphics.com.au Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- Documentation/scsi/scsi_mid_low_api.txt | 3 ++- drivers/ata/pata_arasan_cf.c | 1 - drivers/scsi/atp870u.c | 2 +- drivers/usb/storage/uas.c | 1 - include/scsi/scsi_host.h | 13 ------------- 5 files changed, 3 insertions(+), 17 deletions(-) diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt index c1dd4939f4ae..2a4be1c3e6db 100644 --- a/Documentation/scsi/scsi_mid_low_api.txt +++ b/Documentation/scsi/scsi_mid_low_api.txt @@ -1084,7 +1084,8 @@ of interest: commands to the adapter. this_id - scsi id of host (scsi initiator) or -1 if not known sg_tablesize - maximum scatter gather elements allowed by host. - 0 implies scatter gather not supported by host + Set this to SG_ALL or less to avoid chained SG lists. + Must be at least 1. max_sectors - maximum number of sectors (usually 512 bytes) allowed in a single SCSI command. The default value of 0 leads to a setting of SCSI_DEFAULT_MAX_SECTORS (defined in diff --git a/drivers/ata/pata_arasan_cf.c b/drivers/ata/pata_arasan_cf.c index ebecab8c3f36..135173c8d138 100644 --- a/drivers/ata/pata_arasan_cf.c +++ b/drivers/ata/pata_arasan_cf.c @@ -219,7 +219,6 @@ struct arasan_cf_dev { static struct scsi_host_template arasan_cf_sht = { ATA_BASE_SHT(DRIVER_NAME), - .sg_tablesize = SG_NONE, .dma_boundary = 0xFFFFFFFFUL, }; diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c index e41f0bbdc9fd..c6a752309dda 100644 --- a/drivers/scsi/atp870u.c +++ b/drivers/scsi/atp870u.c @@ -1680,7 +1680,7 @@ static struct scsi_host_template atp870u_template = { .bios_param = atp870u_biosparam /* biosparm */, .can_queue = qcnt /* can_queue */, .this_id = 7 /* SCSI ID */, - .sg_tablesize = ATP870U_SCATTER /*SG_ALL*/ /*SG_NONE*/, + .sg_tablesize = ATP870U_SCATTER /*SG_ALL*/, .max_sectors = ATP870U_MAX_SECTORS, }; diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c index bf80d6f81f58..fd9c0d2c111f 100644 --- a/drivers/usb/storage/uas.c +++ b/drivers/usb/storage/uas.c @@ -879,7 +879,6 @@ static struct scsi_host_template uas_host_template = { .eh_abort_handler = uas_eh_abort_handler, .eh_device_reset_handler = uas_eh_device_reset_handler, .this_id = -1, - .sg_tablesize = SG_NONE, .skip_settle_delay = 1, .dma_boundary = PAGE_SIZE - 1, }; diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index fccdf84ec7e2..f577647bf5f2 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h @@ -23,19 +23,6 @@ struct scsi_host_cmd_pool; struct scsi_transport_template; -/* - * The various choices mean: - * NONE: Self evident. Host adapter is not capable of scatter-gather. - * ALL: Means that the host adapter module can do scatter-gather, - * and that there is no limit to the size of the table to which - * we scatter/gather data. The value we set here is the maximum - * single element sglist. To use chained sglists, the adapter - * has to set a value beyond ALL (and correctly use the chain - * handling API. - * Anything else: Indicates the maximum number of chains that can be - * used in one scatter-gather request. - */ -#define SG_NONE 0 #define SG_ALL SG_CHUNK_SIZE #define MODE_UNKNOWN 0x00 -- cgit v1.2.3 From ebdd1dfde5d2c9b2532ee5b393d66d8bc5f56177 Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 14 Nov 2019 22:09:24 -0800 Subject: scsi: ufs: Add device reset in link recovery path In order to recover from hibern8 exit failure, perform a reset in link recovery path before issuing link start-up. Link: https://lore.kernel.org/r/1573798172-20534-2-git-send-email-cang@codeaurora.org Reviewed-by: Bean Huo Reviewed-by: Stanley Chu Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 977d0c6fef95..e644e1e29c91 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3859,6 +3859,9 @@ static int ufshcd_link_recovery(struct ufs_hba *hba) ufshcd_set_eh_in_progress(hba); spin_unlock_irqrestore(hba->host->host_lock, flags); + /* Reset the attached device */ + ufshcd_vops_device_reset(hba); + ret = ufshcd_host_reset_and_restore(hba); spin_lock_irqsave(hba->host->host_lock, flags); -- cgit v1.2.3 From 870b1279c7a0344c99d85a9cb1619f6023e752ed Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 14 Nov 2019 22:09:25 -0800 Subject: scsi: ufs-qcom: Add reset control support for host controller Add reset control for host controller so that host controller can be reset as required in its power up sequence. Link: https://lore.kernel.org/r/1573798172-20534-3-git-send-email-cang@codeaurora.org Reviewed-by: Avri Altman Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-qcom.c | 53 +++++++++++++++++++++++++++++++++++++++++++++ drivers/scsi/ufs/ufs-qcom.h | 3 +++ 2 files changed, 56 insertions(+) diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index a5b71487a206..c69c29a1ceb9 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -246,6 +246,44 @@ static void ufs_qcom_select_unipro_mode(struct ufs_qcom_host *host) mb(); } +/** + * ufs_qcom_host_reset - reset host controller and PHY + */ +static int ufs_qcom_host_reset(struct ufs_hba *hba) +{ + int ret = 0; + struct ufs_qcom_host *host = ufshcd_get_variant(hba); + + if (!host->core_reset) { + dev_warn(hba->dev, "%s: reset control not set\n", __func__); + goto out; + } + + ret = reset_control_assert(host->core_reset); + if (ret) { + dev_err(hba->dev, "%s: core_reset assert failed, err = %d\n", + __func__, ret); + goto out; + } + + /* + * The hardware requirement for delay between assert/deassert + * is at least 3-4 sleep clock (32.7KHz) cycles, which comes to + * ~125us (4/32768). To be on the safe side add 200us delay. + */ + usleep_range(200, 210); + + ret = reset_control_deassert(host->core_reset); + if (ret) + dev_err(hba->dev, "%s: core_reset deassert failed, err = %d\n", + __func__, ret); + + usleep_range(1000, 1100); + +out: + return ret; +} + static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) { struct ufs_qcom_host *host = ufshcd_get_variant(hba); @@ -254,6 +292,12 @@ static int ufs_qcom_power_up_sequence(struct ufs_hba *hba) bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B) ? true : false; + /* 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); + if (is_rate_B) phy_set_mode(phy, PHY_MODE_UFS_HS_B); @@ -1101,6 +1145,15 @@ static int ufs_qcom_init(struct ufs_hba *hba) host->hba = hba; ufshcd_set_variant(hba, host); + /* Setup the reset control of HCI */ + host->core_reset = devm_reset_control_get(hba->dev, "rst"); + if (IS_ERR(host->core_reset)) { + err = PTR_ERR(host->core_reset); + dev_warn(dev, "Failed to get reset control %d\n", err); + host->core_reset = NULL; + err = 0; + } + /* Fire up the reset controller. Failure here is non-fatal. */ host->rcdev.of_node = dev->of_node; host->rcdev.ops = &ufs_qcom_reset_ops; diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h index d401f174bb70..2d95e7cc7187 100644 --- a/drivers/scsi/ufs/ufs-qcom.h +++ b/drivers/scsi/ufs/ufs-qcom.h @@ -6,6 +6,7 @@ #define UFS_QCOM_H_ #include +#include #define MAX_UFS_QCOM_HOSTS 1 #define MAX_U32 (~(u32)0) @@ -233,6 +234,8 @@ struct ufs_qcom_host { u32 dbg_print_en; struct ufs_qcom_testbus testbus; + /* Reset control of HCI */ + struct reset_control *core_reset; struct reset_controller_dev rcdev; struct gpio_desc *device_reset; -- cgit v1.2.3 From 71d848b8d97ec0f8e993d63cf9de6ac8b3f7c43d Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 14 Nov 2019 22:09:26 -0800 Subject: scsi: ufs: Fix up auto hibern8 enablement Fix up possible unclocked register access to auto hibern8 register in resume path and through sysfs entry. Meanwhile, enable auto hibern8 only after device is fully initialized in probe path. Link: https://lore.kernel.org/r/1573798172-20534-4-git-send-email-cang@codeaurora.org Reviewed-by: Stanley Chu Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufs-sysfs.c | 15 +++++++++------ drivers/scsi/ufs/ufshcd.c | 14 +++++++------- drivers/scsi/ufs/ufshcd.h | 2 ++ 3 files changed, 18 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c index 969a36b15897..ad2abc96c0f1 100644 --- a/drivers/scsi/ufs/ufs-sysfs.c +++ b/drivers/scsi/ufs/ufs-sysfs.c @@ -126,13 +126,16 @@ static void ufshcd_auto_hibern8_update(struct ufs_hba *hba, u32 ahit) return; spin_lock_irqsave(hba->host->host_lock, flags); - if (hba->ahit == ahit) - goto out_unlock; - hba->ahit = ahit; - if (!pm_runtime_suspended(hba->dev)) - ufshcd_writel(hba, hba->ahit, REG_AUTO_HIBERNATE_IDLE_TIMER); -out_unlock: + if (hba->ahit != ahit) + hba->ahit = ahit; spin_unlock_irqrestore(hba->host->host_lock, flags); + if (!pm_runtime_suspended(hba->dev)) { + pm_runtime_get_sync(hba->dev); + ufshcd_hold(hba, false); + ufshcd_auto_hibern8_enable(hba); + ufshcd_release(hba); + pm_runtime_put(hba->dev); + } } /* Convert Auto-Hibernate Idle Timer register value to microseconds */ diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index e644e1e29c91..7bba6bb45035 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3947,7 +3947,7 @@ static int ufshcd_uic_hibern8_exit(struct ufs_hba *hba) return ret; } -static void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) +void ufshcd_auto_hibern8_enable(struct ufs_hba *hba) { unsigned long flags; @@ -6884,9 +6884,6 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* UniPro link is active now */ ufshcd_set_link_active(hba); - /* Enable Auto-Hibernate if configured */ - ufshcd_auto_hibern8_enable(hba); - ret = ufshcd_verify_dev_init(hba); if (ret) goto out; @@ -6937,6 +6934,9 @@ static int ufshcd_probe_hba(struct ufs_hba *hba) /* set the state as operational after switching to desired gear */ hba->ufshcd_state = UFSHCD_STATE_OPERATIONAL; + /* Enable Auto-Hibernate if configured */ + ufshcd_auto_hibern8_enable(hba); + /* * If we are in error handling context or in power management callbacks * context, no need to scan the host @@ -7954,12 +7954,12 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op) if (hba->clk_scaling.is_allowed) ufshcd_resume_clkscaling(hba); - /* Schedule clock gating in case of no access to UFS device yet */ - ufshcd_release(hba); - /* Enable Auto-Hibernate if configured */ ufshcd_auto_hibern8_enable(hba); + /* Schedule clock gating in case of no access to UFS device yet */ + ufshcd_release(hba); + goto out; set_old_link_state: diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index e0fe247c719e..2740f6941ec6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -926,6 +926,8 @@ int ufshcd_query_attr(struct ufs_hba *hba, enum query_opcode opcode, int ufshcd_query_flag(struct ufs_hba *hba, enum query_opcode opcode, enum flag_idn idn, bool *flag_res); +void ufshcd_auto_hibern8_enable(struct ufs_hba *hba); + #define SD_ASCII_STD true #define SD_RAW false int ufshcd_read_string_desc(struct ufs_hba *hba, u8 desc_index, -- cgit v1.2.3 From cddaebaf3d81584180d647e9cbda4ecbf8e8e71c Mon Sep 17 00:00:00 2001 From: Can Guo Date: Thu, 14 Nov 2019 22:09:27 -0800 Subject: scsi: ufs: Fix register dump caused sleep in atomic context ufshcd_print_host_regs() can be called by interrupt handler, but it may sleep due to ufshcd_dump_regs() allocates the dump buffer memory with flag GFP_KERNEL. Fix it by changing GFP_KERNEL to GFP_ATMOIC. Link: https://lore.kernel.org/r/1573798172-20534-5-git-send-email-cang@codeaurora.org Reviewed-by: Bean Huo Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 7bba6bb45035..31ecccf1a15d 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -117,7 +117,7 @@ int ufshcd_dump_regs(struct ufs_hba *hba, size_t offset, size_t len, if (offset % 4 != 0 || len % 4 != 0) /* keep readl happy */ return -EINVAL; - regs = kzalloc(len, GFP_KERNEL); + regs = kzalloc(len, GFP_ATOMIC); if (!regs) return -ENOMEM; -- cgit v1.2.3 From 9333d77573485c827b4c0fc960c840df3e5ce719 Mon Sep 17 00:00:00 2001 From: Venkat Gopalakrishnan Date: Thu, 14 Nov 2019 22:09:28 -0800 Subject: scsi: ufs: Fix irq return code Return IRQ_HANDLED only if the irq is really handled, this will help in catching spurious interrupts that go unhandled. Link: https://lore.kernel.org/r/1573798172-20534-6-git-send-email-cang@codeaurora.org Reviewed-by: Avri Altman Signed-off-by: Venkat Gopalakrishnan Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 134 ++++++++++++++++++++++++++++++++++------------ drivers/scsi/ufs/ufshci.h | 2 +- 2 files changed, 100 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 31ecccf1a15d..6a690a94790c 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -240,7 +240,7 @@ static struct ufs_dev_fix ufs_fixups[] = { END_FIX }; -static void ufshcd_tmc_handler(struct ufs_hba *hba); +static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba); static void ufshcd_async_scan(void *data, async_cookie_t cookie); static int ufshcd_reset_and_restore(struct ufs_hba *hba); static int ufshcd_eh_host_reset_handler(struct scsi_cmnd *cmd); @@ -4799,19 +4799,29 @@ ufshcd_transfer_rsp_status(struct ufs_hba *hba, struct ufshcd_lrb *lrbp) * ufshcd_uic_cmd_compl - handle completion of uic command * @hba: per adapter instance * @intr_status: interrupt status generated by the controller + * + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ -static void ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) +static irqreturn_t ufshcd_uic_cmd_compl(struct ufs_hba *hba, u32 intr_status) { + irqreturn_t retval = IRQ_NONE; + if ((intr_status & UIC_COMMAND_COMPL) && hba->active_uic_cmd) { hba->active_uic_cmd->argument2 |= ufshcd_get_uic_cmd_result(hba); hba->active_uic_cmd->argument3 = ufshcd_get_dme_attr_val(hba); complete(&hba->active_uic_cmd->done); + retval = IRQ_HANDLED; } - if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) + if ((intr_status & UFSHCD_UIC_PWR_MASK) && hba->uic_async_done) { complete(hba->uic_async_done); + retval = IRQ_HANDLED; + } + return retval; } /** @@ -4867,8 +4877,12 @@ static void __ufshcd_transfer_req_compl(struct ufs_hba *hba, /** * ufshcd_transfer_req_compl - handle SCSI and query command completion * @hba: per adapter instance + * + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ -static void ufshcd_transfer_req_compl(struct ufs_hba *hba) +static irqreturn_t ufshcd_transfer_req_compl(struct ufs_hba *hba) { unsigned long completed_reqs; u32 tr_doorbell; @@ -4887,7 +4901,12 @@ static void ufshcd_transfer_req_compl(struct ufs_hba *hba) tr_doorbell = ufshcd_readl(hba, REG_UTP_TRANSFER_REQ_DOOR_BELL); completed_reqs = tr_doorbell ^ hba->outstanding_reqs; - __ufshcd_transfer_req_compl(hba, completed_reqs); + if (completed_reqs) { + __ufshcd_transfer_req_compl(hba, completed_reqs); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } } /** @@ -5406,61 +5425,77 @@ out: /** * ufshcd_update_uic_error - check and set fatal UIC error flags. * @hba: per-adapter instance + * + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ -static void ufshcd_update_uic_error(struct ufs_hba *hba) +static irqreturn_t ufshcd_update_uic_error(struct ufs_hba *hba) { u32 reg; + irqreturn_t retval = IRQ_NONE; /* PHY layer lane error */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_PHY_ADAPTER_LAYER); /* Ignore LINERESET indication, as this is not an error */ if ((reg & UIC_PHY_ADAPTER_LAYER_ERROR) && - (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { + (reg & UIC_PHY_ADAPTER_LAYER_LANE_ERR_MASK)) { /* * To know whether this error is fatal or not, DB timeout * must be checked but this error is handled separately. */ dev_dbg(hba->dev, "%s: UIC Lane error reported\n", __func__); ufshcd_update_reg_hist(&hba->ufs_stats.pa_err, reg); + retval |= IRQ_HANDLED; } /* PA_INIT_ERROR is fatal and needs UIC reset */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DATA_LINK_LAYER); - if (reg) + if ((reg & UIC_DATA_LINK_LAYER_ERROR) && + (reg & UIC_DATA_LINK_LAYER_ERROR_CODE_MASK)) { ufshcd_update_reg_hist(&hba->ufs_stats.dl_err, reg); - if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) - hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; - else if (hba->dev_quirks & - UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) { - if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED) - hba->uic_error |= - UFSHCD_UIC_DL_NAC_RECEIVED_ERROR; - else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT) - hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR; + if (reg & UIC_DATA_LINK_LAYER_ERROR_PA_INIT) + hba->uic_error |= UFSHCD_UIC_DL_PA_INIT_ERROR; + else if (hba->dev_quirks & + UFS_DEVICE_QUIRK_RECOVERY_FROM_DL_NAC_ERRORS) { + if (reg & UIC_DATA_LINK_LAYER_ERROR_NAC_RECEIVED) + hba->uic_error |= + UFSHCD_UIC_DL_NAC_RECEIVED_ERROR; + else if (reg & UIC_DATA_LINK_LAYER_ERROR_TCx_REPLAY_TIMEOUT) + hba->uic_error |= UFSHCD_UIC_DL_TCx_REPLAY_ERROR; + } + retval |= IRQ_HANDLED; } /* UIC NL/TL/DME errors needs software retry */ reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_NETWORK_LAYER); - if (reg) { + if ((reg & UIC_NETWORK_LAYER_ERROR) && + (reg & UIC_NETWORK_LAYER_ERROR_CODE_MASK)) { ufshcd_update_reg_hist(&hba->ufs_stats.nl_err, reg); hba->uic_error |= UFSHCD_UIC_NL_ERROR; + retval |= IRQ_HANDLED; } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_TRANSPORT_LAYER); - if (reg) { + if ((reg & UIC_TRANSPORT_LAYER_ERROR) && + (reg & UIC_TRANSPORT_LAYER_ERROR_CODE_MASK)) { ufshcd_update_reg_hist(&hba->ufs_stats.tl_err, reg); hba->uic_error |= UFSHCD_UIC_TL_ERROR; + retval |= IRQ_HANDLED; } reg = ufshcd_readl(hba, REG_UIC_ERROR_CODE_DME); - if (reg) { + if ((reg & UIC_DME_ERROR) && + (reg & UIC_DME_ERROR_CODE_MASK)) { ufshcd_update_reg_hist(&hba->ufs_stats.dme_err, reg); hba->uic_error |= UFSHCD_UIC_DME_ERROR; + retval |= IRQ_HANDLED; } dev_dbg(hba->dev, "%s: UIC error flags = 0x%08x\n", __func__, hba->uic_error); + return retval; } static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, @@ -5483,10 +5518,15 @@ static bool ufshcd_is_auto_hibern8_error(struct ufs_hba *hba, /** * ufshcd_check_errors - Check for errors that need s/w attention * @hba: per-adapter instance + * + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ -static void ufshcd_check_errors(struct ufs_hba *hba) +static irqreturn_t ufshcd_check_errors(struct ufs_hba *hba) { bool queue_eh_work = false; + irqreturn_t retval = IRQ_NONE; if (hba->errors & INT_FATAL_ERRORS) { ufshcd_update_reg_hist(&hba->ufs_stats.fatal_err, hba->errors); @@ -5495,7 +5535,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba) if (hba->errors & UIC_ERROR) { hba->uic_error = 0; - ufshcd_update_uic_error(hba); + retval = ufshcd_update_uic_error(hba); if (hba->uic_error) queue_eh_work = true; } @@ -5543,6 +5583,7 @@ static void ufshcd_check_errors(struct ufs_hba *hba) } schedule_work(&hba->eh_work); } + retval |= IRQ_HANDLED; } /* * if (!queue_eh_work) - @@ -5550,44 +5591,62 @@ static void ufshcd_check_errors(struct ufs_hba *hba) * itself without s/w intervention or errors that will be * handled by the SCSI core layer. */ + return retval; } /** * ufshcd_tmc_handler - handle task management function completion * @hba: per adapter instance + * + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ -static void ufshcd_tmc_handler(struct ufs_hba *hba) +static irqreturn_t ufshcd_tmc_handler(struct ufs_hba *hba) { u32 tm_doorbell; tm_doorbell = ufshcd_readl(hba, REG_UTP_TASK_REQ_DOOR_BELL); hba->tm_condition = tm_doorbell ^ hba->outstanding_tasks; - wake_up(&hba->tm_wq); + if (hba->tm_condition) { + wake_up(&hba->tm_wq); + return IRQ_HANDLED; + } else { + return IRQ_NONE; + } } /** * ufshcd_sl_intr - Interrupt service routine * @hba: per adapter instance * @intr_status: contains interrupts generated by the controller + * + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ -static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) +static irqreturn_t ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) { + irqreturn_t retval = IRQ_NONE; + hba->errors = UFSHCD_ERROR_MASK & intr_status; if (ufshcd_is_auto_hibern8_error(hba, intr_status)) hba->errors |= (UFSHCD_UIC_HIBERN8_MASK & intr_status); if (hba->errors) - ufshcd_check_errors(hba); + retval |= ufshcd_check_errors(hba); if (intr_status & UFSHCD_UIC_MASK) - ufshcd_uic_cmd_compl(hba, intr_status); + retval |= ufshcd_uic_cmd_compl(hba, intr_status); if (intr_status & UTP_TASK_REQ_COMPL) - ufshcd_tmc_handler(hba); + retval |= ufshcd_tmc_handler(hba); if (intr_status & UTP_TRANSFER_REQ_COMPL) - ufshcd_transfer_req_compl(hba); + retval |= ufshcd_transfer_req_compl(hba); + + return retval; } /** @@ -5595,8 +5654,9 @@ static void ufshcd_sl_intr(struct ufs_hba *hba, u32 intr_status) * @irq: irq number * @__hba: pointer to adapter instance * - * Returns IRQ_HANDLED - If interrupt is valid - * IRQ_NONE - If invalid interrupt + * Returns + * IRQ_HANDLED - If interrupt is valid + * IRQ_NONE - If invalid interrupt */ static irqreturn_t ufshcd_intr(int irq, void *__hba) { @@ -5619,14 +5679,18 @@ static irqreturn_t ufshcd_intr(int irq, void *__hba) intr_status & ufshcd_readl(hba, REG_INTERRUPT_ENABLE); if (intr_status) ufshcd_writel(hba, intr_status, REG_INTERRUPT_STATUS); - if (enabled_intr_status) { - ufshcd_sl_intr(hba, enabled_intr_status); - retval = IRQ_HANDLED; - } + if (enabled_intr_status) + retval |= ufshcd_sl_intr(hba, enabled_intr_status); intr_status = ufshcd_readl(hba, REG_INTERRUPT_STATUS); } while (intr_status && --retries); + if (retval == IRQ_NONE) { + dev_err(hba->dev, "%s: Unhandled interrupt 0x%08x\n", + __func__, intr_status); + ufshcd_dump_regs(hba, 0, UFSHCI_REG_SPACE_SIZE, "host_regs: "); + } + spin_unlock(hba->host->host_lock); return retval; } diff --git a/drivers/scsi/ufs/ufshci.h b/drivers/scsi/ufs/ufshci.h index dbb75cd28dc8..c2961d37cc1c 100644 --- a/drivers/scsi/ufs/ufshci.h +++ b/drivers/scsi/ufs/ufshci.h @@ -195,7 +195,7 @@ enum { /* UECDL - Host UIC Error Code Data Link Layer 3Ch */ #define UIC_DATA_LINK_LAYER_ERROR 0x80000000 -#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0x7FFF +#define UIC_DATA_LINK_LAYER_ERROR_CODE_MASK 0xFFFF #define UIC_DATA_LINK_LAYER_ERROR_TCX_REP_TIMER_EXP 0x2 #define UIC_DATA_LINK_LAYER_ERROR_AFCX_REQ_TIMER_EXP 0x4 #define UIC_DATA_LINK_LAYER_ERROR_FCX_PRO_TIMER_EXP 0x8 -- cgit v1.2.3 From 18f01374b55b4595ad7f56250891bdbdb9d7a052 Mon Sep 17 00:00:00 2001 From: Asutosh Das Date: Thu, 14 Nov 2019 22:09:29 -0800 Subject: scsi: ufs: Abort gating if clock on request is pending This change attempts to abort gating of clocks if a request to turn-on clocks is pending. This would in turn avoid turning OFF and back ON the clocks. Link: https://lore.kernel.org/r/1573798172-20534-7-git-send-email-cang@codeaurora.org Reviewed-by: Bean Huo Signed-off-by: Asutosh Das Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 6a690a94790c..180593ac4062 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -1610,7 +1610,7 @@ static void ufshcd_gate_work(struct work_struct *work) * state to CLKS_ON. */ if (hba->clk_gating.is_suspended || - (hba->clk_gating.state == REQ_CLKS_ON)) { + (hba->clk_gating.state != REQ_CLKS_OFF)) { hba->clk_gating.state = CLKS_ON; trace_ufshcd_clk_gating(dev_name(hba->dev), hba->clk_gating.state); -- cgit v1.2.3 From 6d303e4b19d694cdbebf76bcdb51ada664ee953d Mon Sep 17 00:00:00 2001 From: Subhash Jadavani Date: Thu, 14 Nov 2019 22:09:30 -0800 Subject: scsi: ufs: Fix error handing during hibern8 enter MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During clock gating (ufshcd_gate_work()), we first put the link hibern8 by calling ufshcd_uic_hibern8_enter() and if ufshcd_uic_hibern8_enter() returns success (0) then we gate all the clocks. Now let’s zoom in to what ufshcd_uic_hibern8_enter() does internally: It calls __ufshcd_uic_hibern8_enter() and if failure is encountered, link recovery shall put the link back to the highest HS gear and returns success (0) to ufshcd_uic_hibern8_enter() which is the issue as link is still in active state due to recovery! Now ufshcd_uic_hibern8_enter() returns success to ufshcd_gate_work() and hence it goes ahead with gating the UFS clock while link is still in active state hence I believe controller would raise UIC error interrupts. But when we service the interrupt, clocks might have already been disabled! This change fixes for this by returning failure from __ufshcd_uic_hibern8_enter() if recovery succeeds as link is still not in hibern8, upon receiving the error ufshcd_hibern8_enter() would initiate retry to put the link state back into hibern8. Link: https://lore.kernel.org/r/1573798172-20534-8-git-send-email-cang@codeaurora.org Reviewed-by: Avri Altman Reviewed-by: Bean Huo Signed-off-by: Subhash Jadavani Signed-off-by: Can Guo Signed-off-by: Martin K. Petersen --- drivers/scsi/ufs/ufshcd.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 180593ac4062..b5966faf3e98 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -3891,15 +3891,24 @@ static int __ufshcd_uic_hibern8_enter(struct ufs_hba *hba) ktime_to_us(ktime_sub(ktime_get(), start)), ret); if (ret) { + int err; + dev_err(hba->dev, "%s: hibern8 enter failed. ret = %d\n", __func__, ret); /* - * If link recovery fails then return error so that caller - * don't retry the hibern8 enter again. + * If link recovery fails then return error code returned from + * ufshcd_link_recovery(). + * If link recovery succeeds then return -EAGAIN to attempt + * hibern8 enter retry again. */ - if (ufshcd_link_recovery(hba)) - ret = -ENOLINK; + err = ufshcd_link_recovery(hba); + if (err) { + dev_err(hba->dev, "%s: link recovery failed", __func__); + ret = err; + } else { + ret = -EAGAIN; + } } else ufshcd_vops_hibern8_notify(hba, UIC_CMD_DME_HIBER_ENTER, POST_CHANGE); @@ -3913,7 +3922,7 @@ static int ufshcd_uic_hibern8_enter(struct ufs_hba *hba) for (retries = UIC_HIBERN8_ENTER_RETRIES; retries > 0; retries--) { ret = __ufshcd_uic_hibern8_enter(hba); - if (!ret || ret == -ENOLINK) + if (!ret) goto out; } out: -- cgit v1.2.3 From ce21c63ee995b7a8b7b81245f2cee521f8c3c220 Mon Sep 17 00:00:00 2001 From: peter chang Date: Thu, 14 Nov 2019 15:38:58 +0530 Subject: scsi: pm80xx: Fix for SATA device discovery Driver was missing complete() call in mpi_sata_completion which result in SATA abort error handling timing out. That causes the device to be left in the in_recovery state so subsequent commands sent to the device fail and the OS removes access to it. Link: https://lore.kernel.org/r/20191114100910.6153-2-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: peter chang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 73261902d75d..161bf4760eac 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -2382,6 +2382,8 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("task 0x%p done with io_status 0x%x" " resp 0x%x stat 0x%x but aborted by upper layer!\n", t, status, ts->resp, ts->stat)); + if (t->slow_task) + complete(&t->slow_task->completion); pm8001_ccb_task_free(pm8001_ha, t, ccb, tag); } else { spin_unlock_irqrestore(&t->task_state_lock, flags); -- cgit v1.2.3 From e703977b505ff010c3e99c4793c353c5d5e28f84 Mon Sep 17 00:00:00 2001 From: peter chang Date: Thu, 14 Nov 2019 15:38:59 +0530 Subject: scsi: pm80xx: Make phy enable completion as NULL After the completing the mpi_phy_start_resp, make phy enable completion as NULL. Link: https://lore.kernel.org/r/20191114100910.6153-3-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: peter chang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 161bf4760eac..ee9c187d8caa 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -3132,8 +3132,10 @@ static int mpi_phy_start_resp(struct pm8001_hba_info *pm8001_ha, void *piomb) if (status == 0) { phy->phy_state = PHY_LINK_DOWN; if (pm8001_ha->flags == PM8001F_RUN_TIME && - phy->enable_completion != NULL) + phy->enable_completion != NULL) { complete(phy->enable_completion); + phy->enable_completion = NULL; + } } return 0; -- cgit v1.2.3 From cef1538456ba1f965289c778c418460106d0c1c7 Mon Sep 17 00:00:00 2001 From: John Sperbeck Date: Thu, 14 Nov 2019 15:39:00 +0530 Subject: scsi: pm80xx: Initialize variable used as return status In pm8001_task_exec(), if the PHY is down, then we return the current value of 'rc'. We need to make sure it's initialized. Link: https://lore.kernel.org/r/20191114100910.6153-4-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: John Sperbeck Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 7e48154e11c3..81160e99c75e 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -384,7 +384,7 @@ static int pm8001_task_exec(struct sas_task *task, struct pm8001_port *port = NULL; struct sas_task *t = task; struct pm8001_ccb_info *ccb; - u32 tag = 0xdeadbeef, rc, n_elem = 0; + u32 tag = 0xdeadbeef, rc = 0, n_elem = 0; unsigned long flags = 0; if (!dev->port) { -- cgit v1.2.3 From 4daf1ef3c681754159411bd7ee0aecf2d43acf59 Mon Sep 17 00:00:00 2001 From: Vikram Auradkar Date: Thu, 14 Nov 2019 15:39:01 +0530 Subject: scsi: pm80xx: Convert 'long' mdelay to msleep For delays longer than 20ms [um]delay isn't recommended. pm80xx_chip_soft_rst starts off with a 500ms delay before it even gets around to checking for the results of the reset. As long as it's at least 500ms it doesn't matter what the scheduler is doing. The delay in the pm8001_exec_internal_task_abort does nothing, and theory is this is a delay to avoid a double-free. Link: https://lore.kernel.org/r/20191114100910.6153-5-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: Vikram Auradkar Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index ee9c187d8caa..1a1adda15db8 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -1241,7 +1241,7 @@ pm80xx_chip_soft_rst(struct pm8001_hba_info *pm8001_ha) pm8001_printk("reset register before write : 0x%x\n", regval)); pm8001_cw32(pm8001_ha, 0, SPC_REG_SOFT_RESET, SPCv_NORMAL_RESET_VALUE); - mdelay(500); + msleep(500); regval = pm8001_cr32(pm8001_ha, 0, SPC_REG_SOFT_RESET); PM8001_INIT_DBG(pm8001_ha, @@ -2986,7 +2986,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_get_attached_sas_addr(phy, phy->sas_phy.attached_sas_addr); spin_unlock_irqrestore(&phy->sas_phy.frame_rcvd_lock, flags); if (pm8001_ha->flags == PM8001F_RUN_TIME) - mdelay(200);/*delay a moment to wait disk to spinup*/ + msleep(200);/*delay a moment to wait disk to spinup*/ pm8001_bytes_dmaed(pm8001_ha, phy_id); } -- cgit v1.2.3 From 7370672dc3e7e4bf73cc2bb5ece8ad47fdb00e39 Mon Sep 17 00:00:00 2001 From: peter chang Date: Thu, 14 Nov 2019 15:39:02 +0530 Subject: scsi: pm80xx: Squashed logging cleanup changes The default logging doesn't include the device name, so it's difficult to determine which controller is being logged about in error scenarios. The logging level was only settable via sysfs, which made it inconvenient for actual debugging. This changes the default to only cover error handling. Link: https://lore.kernel.org/r/20191114100910.6153-6-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: peter chang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 62 ++++++++++++++------ drivers/scsi/pm8001/pm8001_init.c | 6 +- drivers/scsi/pm8001/pm8001_sas.c | 6 +- drivers/scsi/pm8001/pm8001_sas.h | 15 ++++- drivers/scsi/pm8001/pm80xx_hwi.c | 118 +++++++++++++++++++++++++++++++++----- 5 files changed, 170 insertions(+), 37 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 68a8217032d0..2c1c722eca17 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1364,7 +1364,7 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, /*Update the PI to the firmware*/ pm8001_cw32(pm8001_ha, circularQ->pi_pci_bar, circularQ->pi_offset, circularQ->producer_idx); - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("INB Q %x OPCODE:%x , UPDATED PI=%d CI=%d\n", responseQueue, opCode, circularQ->producer_idx, circularQ->consumer_index)); @@ -1436,6 +1436,10 @@ u32 pm8001_mpi_msg_consume(struct pm8001_hba_info *pm8001_ha, /* read header */ header_tmp = pm8001_read_32(msgHeader); msgHeader_tmp = cpu_to_le32(header_tmp); + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( + "outbound opcode msgheader:%x ci=%d pi=%d\n", + msgHeader_tmp, circularQ->consumer_idx, + circularQ->producer_index)); if (0 != (le32_to_cpu(msgHeader_tmp) & 0x80000000)) { if (OPC_OUB_SKIP_ENTRY != (le32_to_cpu(msgHeader_tmp) & 0xfff)) { @@ -1604,7 +1608,8 @@ void pm8001_work_fn(struct work_struct *work) break; default: - pm8001_printk("...query task failed!!!\n"); + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( + "...query task failed!!!\n")); break; }); @@ -1890,6 +1895,11 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) pm8001_printk("SAS Address of IO Failure Drive:" "%016llx", SAS_ADDR(t->dev->sas_addr))); + if (status) + PM8001_IOERR_DBG(pm8001_ha, pm8001_printk( + "status:0x%x, tag:0x%x, task:0x%p\n", + status, tag, t)); + switch (status) { case IO_SUCCESS: PM8001_IO_DBG(pm8001_ha, pm8001_printk("IO_SUCCESS" @@ -2072,7 +2082,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -2125,7 +2135,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("port_id = %x,device_id = %x\n", port_id, dev_id)); switch (event) { @@ -2263,7 +2273,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) pm8001_printk(" IO_XFER_CMD_FRAME_ISSUED\n")); return; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", event)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -2352,6 +2362,12 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("ts null\n")); return; } + + if (status) + PM8001_IOERR_DBG(pm8001_ha, pm8001_printk( + "status:0x%x, tag:0x%x, task::0x%p\n", + status, tag, t)); + /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { @@ -2652,7 +2668,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -2723,7 +2739,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_IO_DBG(pm8001_ha, pm8001_printk( + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( "port_id:0x%x, device_id:0x%x, tag:0x%x, event:0x%x\n", port_id, dev_id, tag, event)); switch (event) { @@ -2872,7 +2888,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) ts->stat = SAS_OPEN_TO; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", event)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -2917,9 +2933,13 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) t = ccb->task; ts = &t->task_status; pm8001_dev = ccb->device; - if (status) + if (status) { PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("smp IO status 0x%x\n", status)); + PM8001_IOERR_DBG(pm8001_ha, + pm8001_printk("status:0x%x, tag:0x%x, task:0x%p\n", + status, tag, t)); + } if (unlikely(!t || !t->lldd_task || !t->dev)) return; @@ -3070,7 +3090,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; @@ -3416,7 +3436,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_get_lrate_mode(phy, link_rate); break; default: - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("unknown device type(%x)\n", deviceType)); break; } @@ -3463,7 +3483,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; unsigned long flags; - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("HW_EVENT_SATA_PHY_UP port id = %d," " phy id = %d\n", port_id, phy_id)); port->port_state = portstate; @@ -3541,7 +3561,7 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) break; default: port->port_attached = 0; - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(" phy Down and(default) = %x\n", portstate)); break; @@ -3689,7 +3709,7 @@ int pm8001_mpi_fw_flash_update_resp(struct pm8001_hba_info *pm8001_ha, pm8001_printk(": FLASH_UPDATE_DISABLED\n")); break; default: - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("No matched status = %d\n", status)); break; } @@ -3805,8 +3825,9 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("outbound queue HW event & event type : ")); + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( + "SPC HW event for portid:%d, phyid:%d, event:%x, status:%x\n", + port_id, phy_id, eventType, status)); switch (eventType) { case HW_EVENT_PHY_START_STATUS: PM8001_MSG_DBG(pm8001_ha, @@ -3990,7 +4011,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void* piomb) pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n")); break; default: - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown event type = %x\n", eventType)); break; } @@ -4161,7 +4182,7 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("OPC_OUB_SAS_RE_INITIALIZE\n")); break; default: - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown outbound Queue IOMB OPC = %x\n", opc)); break; @@ -4649,6 +4670,9 @@ static irqreturn_t pm8001_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) { pm8001_chip_interrupt_disable(pm8001_ha, vec); + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( + "irq vec %d, ODMR:0x%x\n", + vec, pm8001_cr32(pm8001_ha, 0, 0x30))); process_oq(pm8001_ha, vec); pm8001_chip_interrupt_enable(pm8001_ha, vec); return IRQ_HANDLED; @@ -4960,6 +4984,8 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, if (!fw_control_context) return -ENOMEM; fw_control = (struct fw_control_info *)&ioctl_payload->func_specific; + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( + "dma fw_control context input length :%x\n", fw_control->len)); memcpy(buffer, fw_control->buffer, fw_control->len); flash_update_info.sgl.addr = cpu_to_le64(phys_addr); flash_update_info.sgl.im_len.len = cpu_to_le32(fw_control->len); diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index ad67cdd4d3cf..d7075c7215ae 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -42,6 +42,10 @@ #include "pm8001_sas.h" #include "pm8001_chips.h" +static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING; +module_param(logging_level, ulong, 0644); +MODULE_PARM_DESC(logging_level, " bits for enabling logging info."); + static struct scsi_transport_template *pm8001_stt; /** @@ -466,7 +470,7 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, pm8001_ha->sas = sha; pm8001_ha->shost = shost; pm8001_ha->id = pm8001_id++; - pm8001_ha->logging_level = 0x01; + pm8001_ha->logging_level = logging_level; sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); /* IOMB size is 128 for 8088/89 controllers */ if (pm8001_ha->chip_id != chip_8001) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 81160e99c75e..447a66d60275 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -119,7 +119,7 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, mem_virt_alloc = dma_alloc_coherent(&pdev->dev, mem_size + align, &mem_dma_handle, GFP_KERNEL); if (!mem_virt_alloc) { - pm8001_printk("memory allocation error\n"); + pr_err("pm80xx: memory allocation error\n"); return -1; } *pphys_addr = mem_dma_handle; @@ -249,6 +249,8 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func, spin_unlock_irqrestore(&pm8001_ha->lock, flags); return 0; default: + PM8001_DEVIO_DBG(pm8001_ha, + pm8001_printk("func 0x%x\n", func)); rc = -EOPNOTSUPP; } msleep(300); @@ -1179,7 +1181,7 @@ int pm8001_query_task(struct sas_task *task) break; } } - pm8001_printk(":rc= %d\n", rc); + pr_err("pm80xx: rc= %d\n", rc); return rc; } diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index ff17c6aff63d..9e0da7bccb45 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -66,8 +66,11 @@ #define PM8001_EH_LOGGING 0x10 /* libsas EH function logging*/ #define PM8001_IOCTL_LOGGING 0x20 /* IOCTL message logging */ #define PM8001_MSG_LOGGING 0x40 /* misc message logging */ -#define pm8001_printk(format, arg...) printk(KERN_INFO "pm80xx %s %d:" \ - format, __func__, __LINE__, ## arg) +#define PM8001_DEV_LOGGING 0x80 /* development message logging */ +#define PM8001_DEVIO_LOGGING 0x100 /* development io message logging */ +#define PM8001_IOERR_LOGGING 0x200 /* development io err message logging */ +#define pm8001_printk(format, arg...) pr_info("%s:: %s %d:" \ + format, pm8001_ha->name, __func__, __LINE__, ## arg) #define PM8001_CHECK_LOGGING(HBA, LEVEL, CMD) \ do { \ if (unlikely(HBA->logging_level & LEVEL)) \ @@ -97,6 +100,14 @@ do { \ #define PM8001_MSG_DBG(HBA, CMD) \ PM8001_CHECK_LOGGING(HBA, PM8001_MSG_LOGGING, CMD) +#define PM8001_DEV_DBG(HBA, CMD) \ + PM8001_CHECK_LOGGING(HBA, PM8001_DEV_LOGGING, CMD) + +#define PM8001_DEVIO_DBG(HBA, CMD) \ + PM8001_CHECK_LOGGING(HBA, PM8001_DEVIO_LOGGING, CMD) + +#define PM8001_IOERR_DBG(HBA, CMD) \ + PM8001_CHECK_LOGGING(HBA, PM8001_IOERR_LOGGING, CMD) #define PM8001_USE_TASKLET #define PM8001_USE_MSIX diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 1a1adda15db8..6057610263c1 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -317,6 +317,25 @@ static void read_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_mr32(address, MAIN_MPI_ILA_RELEASE_TYPE); pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version = pm8001_mr32(address, MAIN_MPI_INACTIVE_FW_VERSION); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "Main cfg table: sign:%x interface rev:%x fw_rev:%x\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.signature, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.interface_rev, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.firmware_rev)); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "table offset: gst:%x iq:%x oq:%x int vec:%x phy attr:%x\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.gst_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.inbound_queue_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.outbound_queue_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.int_vec_table_offset, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.phy_attr_table_offset)); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "Main cfg table; ila rev:%x Inactive fw rev:%x\n", + pm8001_ha->main_cfg_tbl.pm80xx_tbl.ila_version, + pm8001_ha->main_cfg_tbl.pm80xx_tbl.inc_fw_version)); } /** @@ -521,6 +540,11 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) pm8001_mr32(addressib, (offsetib + 0x18)); pm8001_ha->inbnd_q_tbl[i].producer_idx = 0; pm8001_ha->inbnd_q_tbl[i].consumer_index = 0; + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "IQ %d pi_bar 0x%x pi_offset 0x%x\n", i, + pm8001_ha->inbnd_q_tbl[i].pi_pci_bar, + pm8001_ha->inbnd_q_tbl[i].pi_offset)); } for (i = 0; i < PM8001_MAX_SPCV_OUTB_NUM; i++) { pm8001_ha->outbnd_q_tbl[i].element_size_cnt = @@ -549,6 +573,11 @@ static void init_default_table_values(struct pm8001_hba_info *pm8001_ha) pm8001_mr32(addressob, (offsetob + 0x18)); pm8001_ha->outbnd_q_tbl[i].consumer_idx = 0; pm8001_ha->outbnd_q_tbl[i].producer_index = 0; + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "OQ %d ci_bar 0x%x ci_offset 0x%x\n", i, + pm8001_ha->outbnd_q_tbl[i].ci_pci_bar, + pm8001_ha->outbnd_q_tbl[i].ci_offset)); } } @@ -582,6 +611,10 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) ((pm8001_ha->number_of_intr - 1) << 8); pm8001_mw32(address, MAIN_FATAL_ERROR_INTERRUPT, pm8001_ha->main_cfg_tbl.pm80xx_tbl.fatal_err_interrupt); + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "Updated Fatal error interrupt vector 0x%x\n", + pm8001_mr32(address, MAIN_FATAL_ERROR_INTERRUPT))); + pm8001_mw32(address, MAIN_EVENT_CRC_CHECK, pm8001_ha->main_cfg_tbl.pm80xx_tbl.crc_core_dump); @@ -591,6 +624,9 @@ static void update_main_config_table(struct pm8001_hba_info *pm8001_ha) pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping |= 0x20000000; pm8001_mw32(address, MAIN_GPIO_LED_FLAGS_OFFSET, pm8001_ha->main_cfg_tbl.pm80xx_tbl.gpio_led_mapping); + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "Programming DW 0x21 in main cfg table with 0x%x\n", + pm8001_mr32(address, MAIN_GPIO_LED_FLAGS_OFFSET))); pm8001_mw32(address, MAIN_PORT_RECOVERY_TIMER, pm8001_ha->main_cfg_tbl.pm80xx_tbl.port_recovery_timer); @@ -629,6 +665,21 @@ static void update_inbnd_queue_table(struct pm8001_hba_info *pm8001_ha, pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr); pm8001_mw32(address, offset + IB_CI_BASE_ADDR_LO_OFFSET, pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "IQ %d: Element pri size 0x%x\n", + number, + pm8001_ha->inbnd_q_tbl[number].element_pri_size_cnt)); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "IQ upr base addr 0x%x IQ lwr base addr 0x%x\n", + pm8001_ha->inbnd_q_tbl[number].upper_base_addr, + pm8001_ha->inbnd_q_tbl[number].lower_base_addr)); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "CI upper base addr 0x%x CI lower base addr 0x%x\n", + pm8001_ha->inbnd_q_tbl[number].ci_upper_base_addr, + pm8001_ha->inbnd_q_tbl[number].ci_lower_base_addr)); } /** @@ -652,6 +703,21 @@ static void update_outbnd_queue_table(struct pm8001_hba_info *pm8001_ha, pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr); pm8001_mw32(address, offset + OB_INTERRUPT_COALES_OFFSET, pm8001_ha->outbnd_q_tbl[number].interrup_vec_cnt_delay); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "OQ %d: Element pri size 0x%x\n", + number, + pm8001_ha->outbnd_q_tbl[number].element_size_cnt)); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "OQ upr base addr 0x%x OQ lwr base addr 0x%x\n", + pm8001_ha->outbnd_q_tbl[number].upper_base_addr, + pm8001_ha->outbnd_q_tbl[number].lower_base_addr)); + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "PI upper base addr 0x%x PI lower base addr 0x%x\n", + pm8001_ha->outbnd_q_tbl[number].pi_upper_base_addr, + pm8001_ha->outbnd_q_tbl[number].pi_lower_base_addr)); } /** @@ -797,7 +863,7 @@ static void init_pci_device_addresses(struct pm8001_hba_info *pm8001_ha) value = pm8001_cr32(pm8001_ha, 0, MSGU_SCRATCH_PAD_0); offset = value & 0x03FFFFFF; /* scratch pad 0 TBL address */ - PM8001_INIT_DBG(pm8001_ha, + PM8001_DEV_DBG(pm8001_ha, pm8001_printk("Scratchpad 0 Offset: 0x%x value 0x%x\n", offset, value)); pcilogic = (value & 0xFC000000) >> 26; @@ -885,6 +951,10 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) (THERMAL_ENABLE << 8) | page_code; payload.cfg_pg[1] = (LTEMPHIL << 24) | (RTEMPHIL << 8); + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", + payload.cfg_pg[0], payload.cfg_pg[1])); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); if (rc) pm8001_tag_free(pm8001_ha, tag); @@ -1090,6 +1160,10 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) payload.new_curidx_ksop = ((1 << 24) | (1 << 16) | (1 << 8) | KEK_MGMT_SUBOP_KEYCARDUPDATE); + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "Saving Encryption info to flash. payload 0x%x\n", + payload.new_curidx_ksop)); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); if (rc) pm8001_tag_free(pm8001_ha, tag); @@ -1570,6 +1644,10 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; + + PM8001_DEV_DBG(pm8001_ha, pm8001_printk( + "tag::0x%x, status::0x%x task::0x%p\n", tag, status, t)); + /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) @@ -1772,7 +1850,7 @@ mpi_ssp_completion(struct pm8001_hba_info *pm8001_ha , void *piomb) ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -1826,7 +1904,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) if (unlikely(!t || !t->lldd_task || !t->dev)) return; ts = &t->task_status; - PM8001_IO_DBG(pm8001_ha, + PM8001_IOERR_DBG(pm8001_ha, pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n", port_id, tag, event)); switch (event) { @@ -1963,7 +2041,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) ts->stat = SAS_DATA_OVERRUN; break; case IO_XFER_ERROR_INTERNAL_CRC_ERROR: - PM8001_IO_DBG(pm8001_ha, + PM8001_IOERR_DBG(pm8001_ha, pm8001_printk("IO_XFR_ERROR_INTERNAL_CRC_ERROR\n")); /* TBC: used default set values */ ts->resp = SAS_TASK_COMPLETE; @@ -1974,7 +2052,7 @@ static void mpi_ssp_event(struct pm8001_hba_info *pm8001_ha , void *piomb) pm8001_printk("IO_XFER_CMD_FRAME_ISSUED\n")); return; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", event)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -2062,6 +2140,12 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("ts null\n")); return; } + + if (unlikely(status)) + PM8001_IOERR_DBG(pm8001_ha, pm8001_printk( + "status:0x%x, tag:0x%x, task::0x%p\n", + status, tag, t)); + /* Print sas address of IO failed device */ if ((status != IO_SUCCESS) && (status != IO_OVERFLOW) && (status != IO_UNDERFLOW)) { @@ -2365,7 +2449,7 @@ mpi_sata_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); /* not allowed case. Therefore, return failed status */ ts->resp = SAS_TASK_COMPLETE; @@ -2437,7 +2521,7 @@ static void mpi_sata_event(struct pm8001_hba_info *pm8001_ha , void *piomb) } ts = &t->task_status; - PM8001_IO_DBG(pm8001_ha, + PM8001_IOERR_DBG(pm8001_ha, pm8001_printk("port_id:0x%x, tag:0x%x, event:0x%x\n", port_id, tag, event)); switch (event) { @@ -2657,6 +2741,9 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) if (unlikely(!t || !t->lldd_task || !t->dev)) return; + PM8001_DEV_DBG(pm8001_ha, + pm8001_printk("tag::0x%x status::0x%x\n", tag, status)); + switch (status) { case IO_SUCCESS: @@ -2824,7 +2911,7 @@ mpi_smp_completion(struct pm8001_hba_info *pm8001_ha, void *piomb) ts->open_rej_reason = SAS_OREJ_RSVD_RETRY; break; default: - PM8001_IO_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown status 0x%x\n", status)); ts->resp = SAS_TASK_COMPLETE; ts->stat = SAS_DEV_NO_RESPONSE; @@ -2966,7 +3053,7 @@ hw_event_sas_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_get_lrate_mode(phy, link_rate); break; default: - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("unknown device type(%x)\n", deviceType)); break; } @@ -3015,7 +3102,7 @@ hw_event_sata_phy_up(struct pm8001_hba_info *pm8001_ha, void *piomb) struct sas_ha_struct *sas_ha = pm8001_ha->sas; struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; unsigned long flags; - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( "port id %d, phy id %d link_rate %d portstate 0x%x\n", port_id, phy_id, link_rate, portstate)); @@ -3103,7 +3190,7 @@ hw_event_phy_down(struct pm8001_hba_info *pm8001_ha, void *piomb) break; default: port->port_attached = 0; - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk(" Phy Down and(default) = 0x%x\n", portstate)); break; @@ -3195,7 +3282,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) struct pm8001_phy *phy = &pm8001_ha->phy[phy_id]; struct pm8001_port *port = &pm8001_ha->port[port_id]; struct asd_sas_phy *sas_phy = sas_ha->sas_phy[phy_id]; - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEV_DBG(pm8001_ha, pm8001_printk("portid:%d phyid:%d event:0x%x status:0x%x\n", port_id, phy_id, eventType, status)); @@ -3380,7 +3467,7 @@ static int mpi_hw_event(struct pm8001_hba_info *pm8001_ha, void *piomb) pm8001_printk("EVENT_BROADCAST_ASYNCH_EVENT\n")); break; default: - PM8001_MSG_DBG(pm8001_ha, + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk("Unknown event type 0x%x\n", eventType)); break; } @@ -3762,7 +3849,7 @@ static void process_one_iomb(struct pm8001_hba_info *pm8001_ha, void *piomb) ssp_coalesced_comp_resp(pm8001_ha, piomb); break; default: - PM8001_MSG_DBG(pm8001_ha, pm8001_printk( + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( "Unknown outbound Queue IOMB OPC = 0x%x\n", opc)); break; } @@ -4645,6 +4732,9 @@ static irqreturn_t pm80xx_chip_isr(struct pm8001_hba_info *pm8001_ha, u8 vec) { pm80xx_chip_interrupt_disable(pm8001_ha, vec); + PM8001_DEVIO_DBG(pm8001_ha, pm8001_printk( + "irq vec %d, ODMR:0x%x\n", + vec, pm8001_cr32(pm8001_ha, 0, 0x30))); process_oq(pm8001_ha, vec); pm80xx_chip_interrupt_enable(pm8001_ha, vec); return IRQ_HANDLED; -- cgit v1.2.3 From e90e236250e9edd2584a3405d0b2482ef687a637 Mon Sep 17 00:00:00 2001 From: ianyar Date: Thu, 14 Nov 2019 15:39:03 +0530 Subject: scsi: pm80xx: Increase timeout for pm80xx mpi_uninit_check The function mpi_uninit_check takes longer for inbound doorbell register to be cleared. Increased the timeout substantially so that the driver does not fail to load. Link: https://lore.kernel.org/r/20191114100910.6153-7-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: ianyar Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm80xx_hwi.c | 4 ++-- drivers/scsi/pm8001/pm80xx_hwi.h | 3 +++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 6057610263c1..9d04e5cfffb4 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -735,9 +735,9 @@ static int mpi_init_check(struct pm8001_hba_info *pm8001_ha) pm8001_cw32(pm8001_ha, 0, MSGU_IBDB_SET, SPCv_MSGU_CFG_TABLE_UPDATE); /* wait until Inbound DoorBell Clear Register toggled */ if (IS_SPCV_12G(pm8001_ha->pdev)) { - max_wait_count = 4 * 1000 * 1000;/* 4 sec */ + max_wait_count = SPCV_DOORBELL_CLEAR_TIMEOUT; } else { - max_wait_count = 2 * 1000 * 1000;/* 2 sec */ + max_wait_count = SPC_DOORBELL_CLEAR_TIMEOUT; } do { udelay(1); diff --git a/drivers/scsi/pm8001/pm80xx_hwi.h b/drivers/scsi/pm8001/pm80xx_hwi.h index dc9ab7689060..701951a0f715 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.h +++ b/drivers/scsi/pm8001/pm80xx_hwi.h @@ -220,6 +220,9 @@ #define SAS_DOPNRJT_RTRY_TMO 128 #define SAS_COPNRJT_RTRY_TMO 128 +#define SPCV_DOORBELL_CLEAR_TIMEOUT (30 * 1000 * 1000) /* 30 sec */ +#define SPC_DOORBELL_CLEAR_TIMEOUT (15 * 1000 * 1000) /* 15 sec */ + /* Making ORR bigger than IT NEXUS LOSS which is 2000000us = 2 second. Assuming a bigger value 3 second, 3000000/128 = 23437.5 where 128 -- cgit v1.2.3 From a88d9db94c4c9fb2b6ce9f5748928bef46aa9885 Mon Sep 17 00:00:00 2001 From: Vikram Auradkar Date: Thu, 14 Nov 2019 15:39:04 +0530 Subject: scsi: pm80xx: Fix dereferencing dangling pointer sas_task structure should not be used after task_done is called. If the device is gone or not attached, we call task_done on t and continue to use in the sas_task in rest of the function. task_done is pointing to sas_ata_task_done, may free the memory associated with the task before returning. Link: https://lore.kernel.org/r/20191114100910.6153-8-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: Vikram Auradkar Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 447a66d60275..4491de8d40fc 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -388,6 +388,7 @@ static int pm8001_task_exec(struct sas_task *task, struct pm8001_ccb_info *ccb; u32 tag = 0xdeadbeef, rc = 0, n_elem = 0; unsigned long flags = 0; + enum sas_protocol task_proto = t->task_proto; if (!dev->port) { struct task_status_struct *tsm = &t->task_status; @@ -412,7 +413,7 @@ static int pm8001_task_exec(struct sas_task *task, pm8001_dev = dev->lldd_dev; port = &pm8001_ha->port[sas_find_local_port_id(dev)]; if (DEV_IS_GONE(pm8001_dev) || !port->port_attached) { - if (sas_protocol_ata(t->task_proto)) { + if (sas_protocol_ata(task_proto)) { struct task_status_struct *ts = &t->task_status; ts->resp = SAS_TASK_UNDELIVERED; ts->stat = SAS_PHY_DOWN; @@ -434,7 +435,7 @@ static int pm8001_task_exec(struct sas_task *task, goto err_out; ccb = &pm8001_ha->ccb_info[tag]; - if (!sas_protocol_ata(t->task_proto)) { + if (!sas_protocol_ata(task_proto)) { if (t->num_scatter) { n_elem = dma_map_sg(pm8001_ha->dev, t->scatter, @@ -454,7 +455,7 @@ static int pm8001_task_exec(struct sas_task *task, ccb->ccb_tag = tag; ccb->task = t; ccb->device = pm8001_dev; - switch (t->task_proto) { + switch (task_proto) { case SAS_PROTOCOL_SMP: rc = pm8001_task_prep_smp(pm8001_ha, ccb); break; @@ -471,8 +472,7 @@ static int pm8001_task_exec(struct sas_task *task, break; default: dev_printk(KERN_ERR, pm8001_ha->dev, - "unknown sas_task proto: 0x%x\n", - t->task_proto); + "unknown sas_task proto: 0x%x\n", task_proto); rc = -EINVAL; break; } @@ -495,7 +495,7 @@ err_out_tag: pm8001_tag_free(pm8001_ha, tag); err_out: dev_printk(KERN_ERR, pm8001_ha->dev, "pm8001 exec failed[%d]!\n", rc); - if (!sas_protocol_ata(t->task_proto)) + if (!sas_protocol_ata(task_proto)) if (n_elem) dma_unmap_sg(pm8001_ha->dev, t->scatter, t->num_scatter, t->data_dir); -- cgit v1.2.3 From 91a43fa61f102e045d9bac07a4b7739a4bbe623a Mon Sep 17 00:00:00 2001 From: peter chang Date: Thu, 14 Nov 2019 15:39:05 +0530 Subject: scsi: pm80xx: Fix command issue sizing The commands to the controller are sent in fixed sized chunks which are set per-chip-generation and stashed in iomb_size. The driver fills in structs matching the register layout and memcpy this to memory shared with the controller. However, there are two problem cases: 1) Things like phy_start_req are too large because they share the sas_identify_frame definition with libsas, and it includes the crc word. This means that it's overwriting the start of the next command block, that's ok except if it happens at the end of the shared memory area. 2) Things like set_nvm_data_req which are shared between the HAL layers. This means that it's sending 'random' data for things that are in the reserved area. So far we haven't found a case where the controller FW cares, but sending possible gibberish (for most of the structures this is in the reserved area so previously zeroed) is not recommended. Link: https://lore.kernel.org/r/20191114100910.6153-9-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: peter chang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_hwi.c | 69 ++++++++++++++++++++++++++-------------- drivers/scsi/pm8001/pm8001_sas.h | 3 +- drivers/scsi/pm8001/pm80xx_hwi.c | 47 +++++++++++++++++---------- 3 files changed, 79 insertions(+), 40 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 2c1c722eca17..1cbcade747fe 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c @@ -1336,10 +1336,13 @@ int pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ, * @circularQ: the inbound queue we want to transfer to HBA. * @opCode: the operation code represents commands which LLDD and fw recognized. * @payload: the command payload of each operation command. + * @nb: size in bytes of the command payload + * @responseQueue: queue to interrupt on w/ command response (if any) */ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, struct inbound_queue_table *circularQ, - u32 opCode, void *payload, u32 responseQueue) + u32 opCode, void *payload, size_t nb, + u32 responseQueue) { u32 Header = 0, hpriority = 0, bc = 1, category = 0x02; void *pMessage; @@ -1350,10 +1353,13 @@ int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, pm8001_printk("No free mpi buffer\n")); return -ENOMEM; } - BUG_ON(!payload); - /*Copy to the payload*/ - memcpy(pMessage, payload, (pm8001_ha->iomb_size - - sizeof(struct mpi_msg_hdr))); + + if (nb > (pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr))) + nb = pm8001_ha->iomb_size - sizeof(struct mpi_msg_hdr); + memcpy(pMessage, payload, nb); + if (nb + sizeof(struct mpi_msg_hdr) < pm8001_ha->iomb_size) + memset(pMessage + nb, 0, pm8001_ha->iomb_size - + (nb + sizeof(struct mpi_msg_hdr))); /*Build the header*/ Header = ((1 << 31) | (hpriority << 30) | ((bc & 0x1f) << 24) @@ -1763,7 +1769,8 @@ static void pm8001_send_abort_all(struct pm8001_hba_info *pm8001_ha, task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id); task_abort.tag = cpu_to_le32(ccb_tag); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, + sizeof(task_abort), 0); if (ret) pm8001_tag_free(pm8001_ha, ccb_tag); @@ -1836,7 +1843,8 @@ static void pm8001_send_read_log(struct pm8001_hba_info *pm8001_ha, sata_cmd.ncqtag_atap_dir_m |= ((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); - res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0); + res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, + sizeof(sata_cmd), 0); if (res) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); @@ -3375,7 +3383,8 @@ static void pm8001_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, ((phyId & 0x0F) << 4) | (port_id & 0x0F)); payload.param0 = cpu_to_le32(param0); payload.param1 = cpu_to_le32(param1); - pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); } static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, @@ -4305,7 +4314,7 @@ static int pm8001_chip_smp_req(struct pm8001_hba_info *pm8001_ha, cpu_to_le32((u32)sg_dma_len(&task->smp_task.smp_resp)-4); build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd); rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, - (u32 *)&smp_cmd, 0); + &smp_cmd, sizeof(smp_cmd), 0); if (rc) goto err_out_2; @@ -4373,7 +4382,8 @@ static int pm8001_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, ssp_cmd.len = cpu_to_le32(task->total_xfer_len); ssp_cmd.esgl = 0; } - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &ssp_cmd, + sizeof(ssp_cmd), 0); return ret; } @@ -4482,7 +4492,8 @@ static int pm8001_chip_sata_req(struct pm8001_hba_info *pm8001_ha, } } - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, + sizeof(sata_cmd), 0); return ret; } @@ -4517,7 +4528,8 @@ pm8001_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) memcpy(payload.sas_identify.sas_addr, pm8001_ha->sas_addr, SAS_ADDR_SIZE); payload.sas_identify.phy_id = phy_id; - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, + sizeof(payload), 0); return ret; } @@ -4539,7 +4551,8 @@ static int pm8001_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, memset(&payload, 0, sizeof(payload)); payload.tag = cpu_to_le32(tag); payload.phy_id = cpu_to_le32(phy_id); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, + sizeof(payload), 0); return ret; } @@ -4598,7 +4611,8 @@ static int pm8001_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, cpu_to_le32(ITNT | (firstBurstSize * 0x10000)); memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr, SAS_ADDR_SIZE); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); return rc; } @@ -4619,7 +4633,8 @@ int pm8001_chip_dereg_dev_req(struct pm8001_hba_info *pm8001_ha, payload.device_id = cpu_to_le32(device_id); PM8001_MSG_DBG(pm8001_ha, pm8001_printk("unregister device device_id = %d\n", device_id)); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); return ret; } @@ -4642,7 +4657,8 @@ static int pm8001_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, payload.tag = cpu_to_le32(1); payload.phyop_phyid = cpu_to_le32(((phy_op & 0xff) << 8) | (phyId & 0x0F)); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); return ret; } @@ -4696,7 +4712,8 @@ static int send_task_abort(struct pm8001_hba_info *pm8001_ha, u32 opc, task_abort.device_id = cpu_to_le32(dev_id); task_abort.tag = cpu_to_le32(cmd_tag); } - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, + sizeof(task_abort), 0); return ret; } @@ -4753,7 +4770,8 @@ int pm8001_chip_ssp_tm_req(struct pm8001_hba_info *pm8001_ha, if (pm8001_ha->chip_id != chip_8001) sspTMCmd.ds_ads_m = 0x08; circularQ = &pm8001_ha->inbnd_q_tbl[0]; - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sspTMCmd, + sizeof(sspTMCmd), 0); return ret; } @@ -4843,7 +4861,8 @@ int pm8001_chip_get_nvmd_req(struct pm8001_hba_info *pm8001_ha, default: break; } - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, + sizeof(nvmd_req), 0); if (rc) { kfree(fw_control_context); pm8001_tag_free(pm8001_ha, tag); @@ -4927,7 +4946,8 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, default: break; } - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &nvmd_req, + sizeof(nvmd_req), 0); if (rc) { kfree(fw_control_context); pm8001_tag_free(pm8001_ha, tag); @@ -4962,7 +4982,8 @@ pm8001_chip_fw_flash_update_build(struct pm8001_hba_info *pm8001_ha, cpu_to_le32(lower_32_bits(le64_to_cpu(info->sgl.addr))); payload.sgl_addr_hi = cpu_to_le32(upper_32_bits(le64_to_cpu(info->sgl.addr))); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); return ret; } @@ -5109,7 +5130,8 @@ pm8001_chip_set_dev_state_req(struct pm8001_hba_info *pm8001_ha, payload.tag = cpu_to_le32(tag); payload.device_id = cpu_to_le32(pm8001_dev->device_id); payload.nds = cpu_to_le32(state); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); return rc; } @@ -5134,7 +5156,8 @@ pm8001_chip_sas_re_initialization(struct pm8001_hba_info *pm8001_ha) payload.SSAHOLT = cpu_to_le32(0xd << 25); payload.sata_hol_tmo = cpu_to_le32(80); payload.open_reject_cmdretries_data_retries = cpu_to_le32(0xff00ff); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); return rc; diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index 9e0da7bccb45..d64883b80da9 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -674,7 +674,8 @@ int pm8001_mem_alloc(struct pci_dev *pdev, void **virt_addr, void pm8001_chip_iounmap(struct pm8001_hba_info *pm8001_ha); int pm8001_mpi_build_cmd(struct pm8001_hba_info *pm8001_ha, struct inbound_queue_table *circularQ, - u32 opCode, void *payload, u32 responseQueue); + u32 opCode, void *payload, size_t nb, + u32 responseQueue); int pm8001_mpi_msg_free_get(struct inbound_queue_table *circularQ, u16 messageSize, void **messagePtr); u32 pm8001_mpi_msg_free_set(struct pm8001_hba_info *pm8001_ha, void *pMsg, diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 9d04e5cfffb4..09008db2efdc 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -955,7 +955,8 @@ pm80xx_set_thermal_config(struct pm8001_hba_info *pm8001_ha) "Setting up thermal config. cfg_pg 0 0x%x cfg_pg 1 0x%x\n", payload.cfg_pg[0], payload.cfg_pg[1])); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); return rc; @@ -1037,7 +1038,8 @@ pm80xx_set_sas_protocol_timer_config(struct pm8001_hba_info *pm8001_ha) memcpy(&payload.cfg_pg, &SASConfigPage, sizeof(SASProtocolTimerConfig_t)); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); @@ -1164,7 +1166,8 @@ static int pm80xx_encrypt_update(struct pm8001_hba_info *pm8001_ha) "Saving Encryption info to flash. payload 0x%x\n", payload.new_curidx_ksop)); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); @@ -1517,7 +1520,10 @@ static void pm80xx_send_abort_all(struct pm8001_hba_info *pm8001_ha, task_abort.device_id = cpu_to_le32(pm8001_ha_dev->device_id); task_abort.tag = cpu_to_le32(ccb_tag); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &task_abort, + sizeof(task_abort), 0); + PM8001_FAIL_DBG(pm8001_ha, + pm8001_printk("Executing abort task end\n")); if (ret) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); @@ -1593,7 +1599,9 @@ static void pm80xx_send_read_log(struct pm8001_hba_info *pm8001_ha, sata_cmd.ncqtag_atap_dir_m_dad |= ((0x1 << 7) | (0x5 << 9)); memcpy(&sata_cmd.sata_fis, &fis, sizeof(struct host_to_dev_fis)); - res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, 0); + res = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &sata_cmd, + sizeof(sata_cmd), 0); + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk("Executing read log end\n")); if (res) { sas_free_task(task); pm8001_tag_free(pm8001_ha, ccb_tag); @@ -2962,7 +2970,8 @@ static void pm80xx_hw_event_ack_req(struct pm8001_hba_info *pm8001_ha, ((phyId & 0xFF) << 24) | (port_id & 0xFF)); payload.param0 = cpu_to_le32(param0); payload.param1 = cpu_to_le32(param1); - pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); } static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, @@ -4082,8 +4091,8 @@ static int pm80xx_chip_smp_req(struct pm8001_hba_info *pm8001_ha, build_smp_cmd(pm8001_dev->device_id, smp_cmd.tag, &smp_cmd, pm8001_ha->smp_exp_mode, length); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, - (u32 *)&smp_cmd, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &smp_cmd, + sizeof(smp_cmd), 0); if (rc) goto err_out_2; return 0; @@ -4291,7 +4300,7 @@ static int pm80xx_chip_ssp_io_req(struct pm8001_hba_info *pm8001_ha, } q_index = (u32) (pm8001_dev->id & 0x00ffffff) % PM8001_MAX_OUTB_NUM; ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, - &ssp_cmd, q_index); + &ssp_cmd, sizeof(ssp_cmd), q_index); return ret; } @@ -4532,7 +4541,7 @@ static int pm80xx_chip_sata_req(struct pm8001_hba_info *pm8001_ha, } q_index = (u32) (pm8001_ha_dev->id & 0x00ffffff) % PM8001_MAX_OUTB_NUM; ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, - &sata_cmd, q_index); + &sata_cmd, sizeof(sata_cmd), q_index); return ret; } @@ -4587,7 +4596,8 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) memcpy(payload.sas_identify.sas_addr, &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); payload.sas_identify.phy_id = phy_id; - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, + sizeof(payload), 0); return ret; } @@ -4609,7 +4619,8 @@ static int pm80xx_chip_phy_stop_req(struct pm8001_hba_info *pm8001_ha, memset(&payload, 0, sizeof(payload)); payload.tag = cpu_to_le32(tag); payload.phy_id = cpu_to_le32(phy_id); - ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, 0); + ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, + sizeof(payload), 0); return ret; } @@ -4675,7 +4686,8 @@ static int pm80xx_chip_reg_dev_req(struct pm8001_hba_info *pm8001_ha, memcpy(payload.sas_addr, pm8001_dev->sas_device->sas_addr, SAS_ADDR_SIZE); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); @@ -4705,7 +4717,8 @@ static int pm80xx_chip_phy_ctl_req(struct pm8001_hba_info *pm8001_ha, payload.tag = cpu_to_le32(tag); payload.phyop_phyid = cpu_to_le32(((phy_op & 0xFF) << 8) | (phyId & 0xFF)); - return pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + return pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); } static u32 pm80xx_chip_is_our_interrupt(struct pm8001_hba_info *pm8001_ha) @@ -4763,7 +4776,8 @@ void mpi_set_phy_profile_req(struct pm8001_hba_info *pm8001_ha, payload.reserved[j] = cpu_to_le32(*((u32 *)buf + i)); j++; } - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); } @@ -4805,7 +4819,8 @@ void pm8001_set_phy_profile_single(struct pm8001_hba_info *pm8001_ha, for (i = 0; i < length; i++) payload.reserved[i] = cpu_to_le32(*(buf + i)); - rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, 0); + rc = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opc, &payload, + sizeof(payload), 0); if (rc) pm8001_tag_free(pm8001_ha, tag); -- cgit v1.2.3 From 51c1c5f6ed64c2b65a8cf89dac136273d25ca540 Mon Sep 17 00:00:00 2001 From: peter chang Date: Thu, 14 Nov 2019 15:39:06 +0530 Subject: scsi: pm80xx: Cleanup command when a reset times out Added the fix so the if driver properly sent the abort it tries to remove it from the firmware's list of outstanding commands regardless of the abort status. This means that the task gets freed 'now' rather than possibly getting freed later when the scsi layer thinks it's leaked but still valid. Link: https://lore.kernel.org/r/20191114100910.6153-10-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: peter chang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.c | 50 +++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 13 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c index 4491de8d40fc..b7cbc312843e 100644 --- a/drivers/scsi/pm8001/pm8001_sas.c +++ b/drivers/scsi/pm8001/pm8001_sas.c @@ -1204,8 +1204,8 @@ int pm8001_abort_task(struct sas_task *task) pm8001_dev = dev->lldd_dev; pm8001_ha = pm8001_find_ha_by_dev(dev); phy_id = pm8001_dev->attached_phy; - rc = pm8001_find_tag(task, &tag); - if (rc == 0) { + ret = pm8001_find_tag(task, &tag); + if (ret == 0) { pm8001_printk("no tag for task:%p\n", task); return TMF_RESP_FUNC_FAILED; } @@ -1243,26 +1243,50 @@ int pm8001_abort_task(struct sas_task *task) /* 2. Send Phy Control Hard Reset */ reinit_completion(&completion); + phy->port_reset_status = PORT_RESET_TMO; phy->reset_success = false; phy->enable_completion = &completion; phy->reset_completion = &completion_reset; ret = PM8001_CHIP_DISP->phy_ctl_req(pm8001_ha, phy_id, PHY_HARD_RESET); - if (ret) - goto out; - PM8001_MSG_DBG(pm8001_ha, - pm8001_printk("Waiting for local phy ctl\n")); - wait_for_completion(&completion); - if (!phy->reset_success) + if (ret) { + phy->enable_completion = NULL; + phy->reset_completion = NULL; goto out; + } - /* 3. Wait for Port Reset complete / Port reset TMO */ + /* In the case of the reset timeout/fail we still + * abort the command at the firmware. The assumption + * here is that the drive is off doing something so + * that it's not processing requests, and we want to + * avoid getting a completion for this and either + * leaking the task in libsas or losing the race and + * getting a double free. + */ PM8001_MSG_DBG(pm8001_ha, + pm8001_printk("Waiting for local phy ctl\n")); + ret = wait_for_completion_timeout(&completion, + PM8001_TASK_TIMEOUT * HZ); + if (!ret || !phy->reset_success) { + phy->enable_completion = NULL; + phy->reset_completion = NULL; + } else { + /* 3. Wait for Port Reset complete or + * Port reset TMO + */ + PM8001_MSG_DBG(pm8001_ha, pm8001_printk("Waiting for Port reset\n")); - wait_for_completion(&completion_reset); - if (phy->port_reset_status) { - pm8001_dev_gone_notify(dev); - goto out; + ret = wait_for_completion_timeout( + &completion_reset, + PM8001_TASK_TIMEOUT * HZ); + if (!ret) + phy->reset_completion = NULL; + WARN_ON(phy->port_reset_status == + PORT_RESET_TMO); + if (phy->port_reset_status == PORT_RESET_TMO) { + pm8001_dev_gone_notify(dev); + goto out; + } } /* -- cgit v1.2.3 From 3e253d9657b06b20ab289caba81941c6249afd0b Mon Sep 17 00:00:00 2001 From: peter chang Date: Thu, 14 Nov 2019 15:39:07 +0530 Subject: scsi: pm80xx: Do not request 12G sas speeds Occasionally, 6G capable drives fail to train at 6G on links that look good from a signal-integrity perspective. PMC suggests configuring the port to not even expect 12G. Link: https://lore.kernel.org/r/20191114100910.6153-11-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: peter chang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 17 +++++++++++++++++ drivers/scsi/pm8001/pm8001_sas.h | 1 + drivers/scsi/pm8001/pm80xx_hwi.c | 21 ++++----------------- 3 files changed, 22 insertions(+), 17 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index d7075c7215ae..c0c9551d1f54 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -41,11 +41,20 @@ #include #include "pm8001_sas.h" #include "pm8001_chips.h" +#include "pm80xx_hwi.h" static ulong logging_level = PM8001_FAIL_LOGGING | PM8001_IOERR_LOGGING; module_param(logging_level, ulong, 0644); MODULE_PARM_DESC(logging_level, " bits for enabling logging info."); +static ulong link_rate = LINKRATE_15 | LINKRATE_30 | LINKRATE_60 | LINKRATE_120; +module_param(link_rate, ulong, 0644); +MODULE_PARM_DESC(link_rate, "Enable link rate.\n" + " 1: Link rate 1.5G\n" + " 2: Link rate 3.0G\n" + " 4: Link rate 6.0G\n" + " 8: Link rate 12.0G\n"); + static struct scsi_transport_template *pm8001_stt; /** @@ -471,6 +480,14 @@ static struct pm8001_hba_info *pm8001_pci_alloc(struct pci_dev *pdev, pm8001_ha->shost = shost; pm8001_ha->id = pm8001_id++; pm8001_ha->logging_level = logging_level; + if (link_rate >= 1 && link_rate <= 15) + pm8001_ha->link_rate = (link_rate << 8); + else { + pm8001_ha->link_rate = LINKRATE_15 | LINKRATE_30 | + LINKRATE_60 | LINKRATE_120; + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "Setting link rate to default value\n")); + } sprintf(pm8001_ha->name, "%s%d", DRV_NAME, pm8001_ha->id); /* IOMB size is 128 for 8088/89 controllers */ if (pm8001_ha->chip_id != chip_8001) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index d64883b80da9..f7be7b85624e 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -546,6 +546,7 @@ struct pm8001_hba_info { struct tasklet_struct tasklet[PM8001_MAX_MSIX_VEC]; #endif u32 logging_level; + u32 link_rate; u32 fw_status; u32 smp_exp_mode; bool controller_fatal_error; diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 09008db2efdc..5ca9732f4704 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -37,6 +37,7 @@ * POSSIBILITY OF SUCH DAMAGES. * */ + #include #include #include "pm8001_sas.h" #include "pm80xx_hwi.h" @@ -4565,23 +4566,9 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) PM8001_INIT_DBG(pm8001_ha, pm8001_printk("PHY START REQ for phy_id %d\n", phy_id)); - /* - ** [0:7] PHY Identifier - ** [8:11] link rate 1.5G, 3G, 6G - ** [12:13] link mode 01b SAS mode; 10b SATA mode; 11b Auto mode - ** [14] 0b disable spin up hold; 1b enable spin up hold - ** [15] ob no change in current PHY analig setup 1b enable using SPAST - */ - if (!IS_SPCV_12G(pm8001_ha->pdev)) - payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | - LINKMODE_AUTO | LINKRATE_15 | - LINKRATE_30 | LINKRATE_60 | phy_id); - else - payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | - LINKMODE_AUTO | LINKRATE_15 | - LINKRATE_30 | LINKRATE_60 | LINKRATE_120 | - phy_id); + payload.ase_sh_lm_slr_phyid = cpu_to_le32(SPINHOLD_DISABLE | + LINKMODE_AUTO | pm8001_ha->link_rate | phy_id); /* SSC Disable and SAS Analog ST configuration */ /** payload.ase_sh_lm_slr_phyid = @@ -4594,7 +4581,7 @@ pm80xx_chip_phy_start_req(struct pm8001_hba_info *pm8001_ha, u8 phy_id) payload.sas_identify.dev_type = SAS_END_DEVICE; payload.sas_identify.initiator_bits = SAS_PROTOCOL_ALL; memcpy(payload.sas_identify.sas_addr, - &pm8001_ha->phy[phy_id].dev_sas_addr, SAS_ADDR_SIZE); + &pm8001_ha->sas_addr, SAS_ADDR_SIZE); payload.sas_identify.phy_id = phy_id; ret = pm8001_mpi_build_cmd(pm8001_ha, circularQ, opcode, &payload, sizeof(payload), 0); -- cgit v1.2.3 From e2773c67e24a6ae93355767eb236e0a22200993e Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Thu, 14 Nov 2019 15:39:08 +0530 Subject: scsi: pm80xx: Controller fatal error through sysfs Added support to check controller fatal error through sysfs. Link: https://lore.kernel.org/r/20191114100910.6153-12-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_ctl.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index 6b85016b4db3..7c6be2ec110d 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -69,6 +69,25 @@ static ssize_t pm8001_ctl_mpi_interface_rev_show(struct device *cdev, static DEVICE_ATTR(interface_rev, S_IRUGO, pm8001_ctl_mpi_interface_rev_show, NULL); +/** + * controller_fatal_error_show - check controller is under fatal err + * @cdev: pointer to embedded class device + * @buf: the buffer returned + * + * A sysfs 'read only' shost attribute. + */ +static ssize_t controller_fatal_error_show(struct device *cdev, + struct device_attribute *attr, char *buf) +{ + struct Scsi_Host *shost = class_to_shost(cdev); + struct sas_ha_struct *sha = SHOST_TO_SAS_HA(shost); + struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; + + return snprintf(buf, PAGE_SIZE, "%d\n", + pm8001_ha->controller_fatal_error); +} +static DEVICE_ATTR_RO(controller_fatal_error); + /** * pm8001_ctl_fw_version_show - firmware version * @cdev: pointer to embedded class device @@ -804,6 +823,7 @@ static DEVICE_ATTR(update_fw, S_IRUGO|S_IWUSR|S_IWGRP, pm8001_show_update_fw, pm8001_store_update_fw); struct device_attribute *pm8001_host_attrs[] = { &dev_attr_interface_rev, + &dev_attr_controller_fatal_error, &dev_attr_fw_version, &dev_attr_update_fw, &dev_attr_aap_log, -- cgit v1.2.3 From 7295493682aaa68e0826b61af4b88941363075ca Mon Sep 17 00:00:00 2001 From: Vikram Auradkar Date: Thu, 14 Nov 2019 15:39:09 +0530 Subject: scsi: pm80xx: Tie the interrupt name to the module instance With MSI-x enabled, the interrupt instances are where the prefix is fixed for all module instances, making it a little harder to track down what's what. Link: https://lore.kernel.org/r/20191114100910.6153-13-deepak.ukey@microchip.com Acked-by: Jack Wang Signed-off-by: Vikram Auradkar Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_init.c | 11 ++++++----- drivers/scsi/pm8001/pm8001_sas.h | 2 ++ 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c index c0c9551d1f54..c6d9da7b546e 100644 --- a/drivers/scsi/pm8001/pm8001_init.c +++ b/drivers/scsi/pm8001/pm8001_init.c @@ -894,7 +894,6 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) u32 number_of_intr; int flag = 0; int rc; - static char intr_drvname[PM8001_MAX_MSIX_VEC][sizeof(DRV_NAME)+3]; /* SPCv controllers supports 64 msi-x */ if (pm8001_ha->chip_id == chip_8001) { @@ -915,14 +914,16 @@ static u32 pm8001_setup_msix(struct pm8001_hba_info *pm8001_ha) rc, pm8001_ha->number_of_intr)); for (i = 0; i < number_of_intr; i++) { - snprintf(intr_drvname[i], sizeof(intr_drvname[0]), - DRV_NAME"%d", i); + snprintf(pm8001_ha->intr_drvname[i], + sizeof(pm8001_ha->intr_drvname[0]), + "%s-%d", pm8001_ha->name, i); pm8001_ha->irq_vector[i].irq_id = i; pm8001_ha->irq_vector[i].drv_inst = pm8001_ha; rc = request_irq(pci_irq_vector(pm8001_ha->pdev, i), pm8001_interrupt_handler_msix, flag, - intr_drvname[i], &(pm8001_ha->irq_vector[i])); + pm8001_ha->intr_drvname[i], + &(pm8001_ha->irq_vector[i])); if (rc) { for (j = 0; j < i; j++) { free_irq(pci_irq_vector(pm8001_ha->pdev, i), @@ -963,7 +964,7 @@ intx: pm8001_ha->irq_vector[0].irq_id = 0; pm8001_ha->irq_vector[0].drv_inst = pm8001_ha; rc = request_irq(pdev->irq, pm8001_interrupt_handler_intx, IRQF_SHARED, - DRV_NAME, SHOST_TO_SAS_HA(pm8001_ha->shost)); + pm8001_ha->name, SHOST_TO_SAS_HA(pm8001_ha->shost)); return rc; } diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index f7be7b85624e..a55b03bca529 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -541,6 +541,8 @@ struct pm8001_hba_info { struct pm8001_ccb_info *ccb_info; #ifdef PM8001_USE_MSIX int number_of_intr;/*will be used in remove()*/ + char intr_drvname[PM8001_MAX_MSIX_VEC] + [PM8001_NAME_LENGTH+1+3+1]; #endif #ifdef PM8001_USE_TASKLET struct tasklet_struct tasklet[PM8001_MAX_MSIX_VEC]; -- cgit v1.2.3 From 044f59de3a3de9c193cfc600c7a3045b24b3079f Mon Sep 17 00:00:00 2001 From: Deepak Ukey Date: Thu, 14 Nov 2019 15:39:10 +0530 Subject: scsi: pm80xx: Modified the logic to collect fatal dump Added the correct method to collect the fatal dump. Link: https://lore.kernel.org/r/20191114100910.6153-14-deepak.ukey@microchip.com Reported-by: kbuild test robot Acked-by: Jack Wang Signed-off-by: Deepak Ukey Signed-off-by: Viswas G Signed-off-by: Martin K. Petersen --- drivers/scsi/pm8001/pm8001_sas.h | 3 + drivers/scsi/pm8001/pm80xx_hwi.c | 251 ++++++++++++++++++++++++++++++--------- 2 files changed, 195 insertions(+), 59 deletions(-) diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h index a55b03bca529..93438c8f67da 100644 --- a/drivers/scsi/pm8001/pm8001_sas.h +++ b/drivers/scsi/pm8001/pm8001_sas.h @@ -152,6 +152,8 @@ struct pm8001_ioctl_payload { #define MPI_FATAL_EDUMP_TABLE_HANDSHAKE 0x0C /* FDDHSHK */ #define MPI_FATAL_EDUMP_TABLE_STATUS 0x10 /* FDDTSTAT */ #define MPI_FATAL_EDUMP_TABLE_ACCUM_LEN 0x14 /* ACCDDLEN */ +#define MPI_FATAL_EDUMP_TABLE_TOTAL_LEN 0x18 /* TOTALLEN */ +#define MPI_FATAL_EDUMP_TABLE_SIGNATURE 0x1C /* SIGNITURE */ #define MPI_FATAL_EDUMP_HANDSHAKE_RDY 0x1 #define MPI_FATAL_EDUMP_HANDSHAKE_BUSY 0x0 #define MPI_FATAL_EDUMP_TABLE_STAT_RSVD 0x0 @@ -507,6 +509,7 @@ struct pm8001_hba_info { u32 forensic_last_offset; u32 fatal_forensic_shift_offset; u32 forensic_fatal_step; + u32 forensic_preserved_accumulated_transfer; u32 evtlog_ib_offset; u32 evtlog_ob_offset; void __iomem *msg_unit_tbl_addr;/*Message Unit Table Addr*/ diff --git a/drivers/scsi/pm8001/pm80xx_hwi.c b/drivers/scsi/pm8001/pm80xx_hwi.c index 5ca9732f4704..19601138e889 100644 --- a/drivers/scsi/pm8001/pm80xx_hwi.c +++ b/drivers/scsi/pm8001/pm80xx_hwi.c @@ -76,7 +76,7 @@ void pm80xx_pci_mem_copy(struct pm8001_hba_info *pm8001_ha, u32 soffset, destination1 = (u32 *)destination; for (index = 0; index < dw_count; index += 4, destination1++) { - offset = (soffset + index / 4); + offset = (soffset + index); if (offset < (64 * 1024)) { value = pm8001_cr32(pm8001_ha, bus_base_number, offset); *destination1 = cpu_to_le32(value); @@ -93,9 +93,12 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, struct pm8001_hba_info *pm8001_ha = sha->lldd_ha; void __iomem *fatal_table_address = pm8001_ha->fatal_tbl_addr; u32 accum_len , reg_val, index, *temp; + u32 status = 1; unsigned long start; u8 *direct_data; char *fatal_error_data = buf; + u32 length_to_read; + u32 offset; pm8001_ha->forensic_info.data_buf.direct_data = buf; if (pm8001_ha->chip_id == chip_8001) { @@ -105,16 +108,35 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } + /* initialize variables for very first call from host application */ if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { PM8001_IO_DBG(pm8001_ha, pm8001_printk("forensic_info TYPE_NON_FATAL..............\n")); direct_data = (u8 *)fatal_error_data; pm8001_ha->forensic_info.data_type = TYPE_NON_FATAL; pm8001_ha->forensic_info.data_buf.direct_len = SYSFS_OFFSET; + pm8001_ha->forensic_info.data_buf.direct_offset = 0; pm8001_ha->forensic_info.data_buf.read_len = 0; + pm8001_ha->forensic_preserved_accumulated_transfer = 0; - pm8001_ha->forensic_info.data_buf.direct_data = direct_data; + /* Write signature to fatal dump table */ + pm8001_mw32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_SIGNATURE, 0x1234abcd); + pm8001_ha->forensic_info.data_buf.direct_data = direct_data; + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("ossaHwCB: status1 %d\n", status)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("ossaHwCB: read_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.read_len)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("ossaHwCB: direct_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_len)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("ossaHwCB: direct_offset 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_offset)); + } + if (pm8001_ha->forensic_info.data_buf.direct_offset == 0) { /* start to get data */ /* Program the MEMBASE II Shifting Register with 0x00.*/ pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, @@ -127,30 +149,66 @@ ssize_t pm80xx_get_fatal_dump(struct device *cdev, /* Read until accum_len is retrived */ accum_len = pm8001_mr32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); - PM8001_IO_DBG(pm8001_ha, pm8001_printk("accum_len 0x%x\n", - accum_len)); + /* Determine length of data between previously stored transfer length + * and current accumulated transfer length + */ + length_to_read = + accum_len - pm8001_ha->forensic_preserved_accumulated_transfer; + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv: accum_len 0x%x\n", accum_len)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv: length_to_read 0x%x\n", + length_to_read)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv: last_offset 0x%x\n", + pm8001_ha->forensic_last_offset)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv: read_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.read_len)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv:: direct_len 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_len)); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv:: direct_offset 0x%x\n", + pm8001_ha->forensic_info.data_buf.direct_offset)); + + /* If accumulated length failed to read correctly fail the attempt.*/ if (accum_len == 0xFFFFFFFF) { PM8001_IO_DBG(pm8001_ha, pm8001_printk("Possible PCI issue 0x%x not expected\n", - accum_len)); - return -EIO; + accum_len)); + return status; } - if (accum_len == 0 || accum_len >= 0x100000) { + /* If accumulated length is zero fail the attempt */ + if (accum_len == 0) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, - "%08x ", 0xFFFFFFFF); + "%08x ", 0xFFFFFFFF); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } + /* Accumulated length is good so start capturing the first data */ temp = (u32 *)pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr; if (pm8001_ha->forensic_fatal_step == 0) { moreData: + /* If data to read is less than SYSFS_OFFSET then reduce the + * length of dataLen + */ + if (pm8001_ha->forensic_last_offset + SYSFS_OFFSET + > length_to_read) { + pm8001_ha->forensic_info.data_buf.direct_len = + length_to_read - + pm8001_ha->forensic_last_offset; + } else { + pm8001_ha->forensic_info.data_buf.direct_len = + SYSFS_OFFSET; + } if (pm8001_ha->forensic_info.data_buf.direct_data) { /* Data is in bar, copy to host memory */ - pm80xx_pci_mem_copy(pm8001_ha, pm8001_ha->fatal_bar_loc, - pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, - pm8001_ha->forensic_info.data_buf.direct_len , - 1); + pm80xx_pci_mem_copy(pm8001_ha, + pm8001_ha->fatal_bar_loc, + pm8001_ha->memoryMap.region[FORENSIC_MEM].virt_ptr, + pm8001_ha->forensic_info.data_buf.direct_len, 1); } pm8001_ha->fatal_bar_loc += pm8001_ha->forensic_info.data_buf.direct_len; @@ -161,21 +219,29 @@ moreData: pm8001_ha->forensic_info.data_buf.read_len = pm8001_ha->forensic_info.data_buf.direct_len; - if (pm8001_ha->forensic_last_offset >= accum_len) { + if (pm8001_ha->forensic_last_offset >= length_to_read) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, "%08x ", 3); - for (index = 0; index < (SYSFS_OFFSET / 4); index++) { + for (index = 0; index < + (pm8001_ha->forensic_info.data_buf.direct_len + / 4); index++) { pm8001_ha->forensic_info.data_buf.direct_data += - sprintf(pm8001_ha-> - forensic_info.data_buf.direct_data, - "%08x ", *(temp + index)); + sprintf( + pm8001_ha->forensic_info.data_buf.direct_data, + "%08x ", *(temp + index)); } pm8001_ha->fatal_bar_loc = 0; pm8001_ha->forensic_fatal_step = 1; pm8001_ha->fatal_forensic_shift_offset = 0; pm8001_ha->forensic_last_offset = 0; + status = 0; + offset = (int) + ((char *)pm8001_ha->forensic_info.data_buf.direct_data + - (char *)buf); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv:return1 0x%x\n", offset)); return (char *)pm8001_ha-> forensic_info.data_buf.direct_data - (char *)buf; @@ -185,12 +251,20 @@ moreData: sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", 2); - for (index = 0; index < (SYSFS_OFFSET / 4); index++) { - pm8001_ha->forensic_info.data_buf.direct_data += - sprintf(pm8001_ha-> + for (index = 0; index < + (pm8001_ha->forensic_info.data_buf.direct_len + / 4); index++) { + pm8001_ha->forensic_info.data_buf.direct_data + += sprintf(pm8001_ha-> forensic_info.data_buf.direct_data, "%08x ", *(temp + index)); } + status = 0; + offset = (int) + ((char *)pm8001_ha->forensic_info.data_buf.direct_data + - (char *)buf); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv:return2 0x%x\n", offset)); return (char *)pm8001_ha-> forensic_info.data_buf.direct_data - (char *)buf; @@ -200,63 +274,122 @@ moreData: pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha->forensic_info.data_buf.direct_data, "%08x ", 2); - for (index = 0; index < 256; index++) { + for (index = 0; index < + (pm8001_ha->forensic_info.data_buf.direct_len + / 4) ; index++) { pm8001_ha->forensic_info.data_buf.direct_data += sprintf(pm8001_ha-> - forensic_info.data_buf.direct_data, - "%08x ", *(temp + index)); + forensic_info.data_buf.direct_data, + "%08x ", *(temp + index)); } pm8001_ha->fatal_forensic_shift_offset += 0x100; pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, pm8001_ha->fatal_forensic_shift_offset); pm8001_ha->fatal_bar_loc = 0; + status = 0; + offset = (int) + ((char *)pm8001_ha->forensic_info.data_buf.direct_data + - (char *)buf); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv: return3 0x%x\n", offset)); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } if (pm8001_ha->forensic_fatal_step == 1) { - pm8001_ha->fatal_forensic_shift_offset = 0; - /* Read 64K of the debug data. */ - pm8001_cw32(pm8001_ha, 0, MEMBASE_II_SHIFT_REGISTER, - pm8001_ha->fatal_forensic_shift_offset); - pm8001_mw32(fatal_table_address, - MPI_FATAL_EDUMP_TABLE_HANDSHAKE, + /* store previous accumulated length before triggering next + * accumulated length update + */ + pm8001_ha->forensic_preserved_accumulated_transfer = + pm8001_mr32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_ACCUM_LEN); + + /* continue capturing the fatal log until Dump status is 0x3 */ + if (pm8001_mr32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_STATUS) < + MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { + + /* reset fddstat bit by writing to zero*/ + pm8001_mw32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_STATUS, 0x0); + + /* set dump control value to '1' so that new data will + * be transferred to shared memory + */ + pm8001_mw32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_HANDSHAKE, MPI_FATAL_EDUMP_HANDSHAKE_RDY); - /* Poll FDDHSHK until clear */ - start = jiffies + (2 * HZ); /* 2 sec */ + /*Poll FDDHSHK until clear */ + start = jiffies + (2 * HZ); /* 2 sec */ - do { - reg_val = pm8001_mr32(fatal_table_address, + do { + reg_val = pm8001_mr32(fatal_table_address, MPI_FATAL_EDUMP_TABLE_HANDSHAKE); - } while ((reg_val) && time_before(jiffies, start)); + } while ((reg_val) && time_before(jiffies, start)); - if (reg_val != 0) { - PM8001_FAIL_DBG(pm8001_ha, - pm8001_printk("TIMEOUT:MEMBASE_II_SHIFT_REGISTER" - " = 0x%x\n", reg_val)); - return -EIO; - } - - /* Read the next 64K of the debug data. */ - pm8001_ha->forensic_fatal_step = 0; - if (pm8001_mr32(fatal_table_address, - MPI_FATAL_EDUMP_TABLE_STATUS) != - MPI_FATAL_EDUMP_TABLE_STAT_NF_SUCCESS_DONE) { - pm8001_mw32(fatal_table_address, - MPI_FATAL_EDUMP_TABLE_HANDSHAKE, 0); - goto moreData; - } else { - pm8001_ha->forensic_info.data_buf.direct_data += - sprintf(pm8001_ha-> - forensic_info.data_buf.direct_data, - "%08x ", 4); - pm8001_ha->forensic_info.data_buf.read_len = 0xFFFFFFFF; - pm8001_ha->forensic_info.data_buf.direct_len = 0; - pm8001_ha->forensic_info.data_buf.direct_offset = 0; - pm8001_ha->forensic_info.data_buf.read_len = 0; + if (reg_val != 0) { + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "TIMEOUT:MPI_FATAL_EDUMP_TABLE_HDSHAKE 0x%x\n", + reg_val)); + /* Fail the dump if a timeout occurs */ + pm8001_ha->forensic_info.data_buf.direct_data += + sprintf( + pm8001_ha->forensic_info.data_buf.direct_data, + "%08x ", 0xFFFFFFFF); + return((char *) + pm8001_ha->forensic_info.data_buf.direct_data + - (char *)buf); + } + /* Poll status register until set to 2 or + * 3 for up to 2 seconds + */ + start = jiffies + (2 * HZ); /* 2 sec */ + + do { + reg_val = pm8001_mr32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_STATUS); + } while (((reg_val != 2) || (reg_val != 3)) && + time_before(jiffies, start)); + + if (reg_val < 2) { + PM8001_FAIL_DBG(pm8001_ha, pm8001_printk( + "TIMEOUT:MPI_FATAL_EDUMP_TABLE_STATUS = 0x%x\n", + reg_val)); + /* Fail the dump if a timeout occurs */ + pm8001_ha->forensic_info.data_buf.direct_data += + sprintf( + pm8001_ha->forensic_info.data_buf.direct_data, + "%08x ", 0xFFFFFFFF); + pm8001_cw32(pm8001_ha, 0, + MEMBASE_II_SHIFT_REGISTER, + pm8001_ha->fatal_forensic_shift_offset); + } + /* Read the next block of the debug data.*/ + length_to_read = pm8001_mr32(fatal_table_address, + MPI_FATAL_EDUMP_TABLE_ACCUM_LEN) - + pm8001_ha->forensic_preserved_accumulated_transfer; + if (length_to_read != 0x0) { + pm8001_ha->forensic_fatal_step = 0; + goto moreData; + } else { + pm8001_ha->forensic_info.data_buf.direct_data += + sprintf( + pm8001_ha->forensic_info.data_buf.direct_data, + "%08x ", 4); + pm8001_ha->forensic_info.data_buf.read_len + = 0xFFFFFFFF; + pm8001_ha->forensic_info.data_buf.direct_len + = 0; + pm8001_ha->forensic_info.data_buf.direct_offset + = 0; + pm8001_ha->forensic_info.data_buf.read_len = 0; + } } } - + offset = (int)((char *)pm8001_ha->forensic_info.data_buf.direct_data + - (char *)buf); + PM8001_IO_DBG(pm8001_ha, + pm8001_printk("get_fatal_spcv: return4 0x%x\n", offset)); return (char *)pm8001_ha->forensic_info.data_buf.direct_data - (char *)buf; } -- cgit v1.2.3 From 3fe3d2428b62822b7b030577cd612790bdd8c941 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Tue, 5 Nov 2019 17:25:27 +0800 Subject: scsi: qla4xxx: fix double free bug The variable init_fw_cb is released twice, resulting in a double free bug. The call to the function dma_free_coherent() before goto is removed to get rid of potential double free. Fixes: 2a49a78ed3c8 ("[SCSI] qla4xxx: added IPv6 support.") Link: https://lore.kernel.org/r/1572945927-27796-1-git-send-email-bianpan2016@163.com Signed-off-by: Pan Bian Acked-by: Manish Rangankar Signed-off-by: Martin K. Petersen --- drivers/scsi/qla4xxx/ql4_mbx.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/drivers/scsi/qla4xxx/ql4_mbx.c b/drivers/scsi/qla4xxx/ql4_mbx.c index dac9a7013208..02636b4785c5 100644 --- a/drivers/scsi/qla4xxx/ql4_mbx.c +++ b/drivers/scsi/qla4xxx/ql4_mbx.c @@ -640,9 +640,6 @@ int qla4xxx_initialize_fw_cb(struct scsi_qla_host * ha) if (qla4xxx_get_ifcb(ha, &mbox_cmd[0], &mbox_sts[0], init_fw_cb_dma) != QLA_SUCCESS) { - dma_free_coherent(&ha->pdev->dev, - sizeof(struct addr_ctrl_blk), - init_fw_cb, init_fw_cb_dma); goto exit_init_fw_cb; } -- cgit v1.2.3 From 9b44ffab49e337982d4717cfa6799eceaf7359a3 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 14 Nov 2019 18:00:07 +0000 Subject: scsi: arcmsr: fix indentation issues There are a few statements that are indented incorrectly, fix these. Link: https://lore.kernel.org/r/20191114180007.325856-1-colin.king@canonical.com Signed-off-by: Colin Ian King Signed-off-by: Martin K. Petersen --- drivers/scsi/arcmsr/arcmsr_hba.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c index 88053b15c363..db687ef8a99e 100644 --- a/drivers/scsi/arcmsr/arcmsr_hba.c +++ b/drivers/scsi/arcmsr/arcmsr_hba.c @@ -1400,7 +1400,7 @@ static void arcmsr_drain_donequeue(struct AdapterControlBlock *acb, struct Comma , pCCB->acb , pCCB->startdone , atomic_read(&acb->ccboutstandingcount)); - return; + return; } arcmsr_report_ccb_state(acb, pCCB, error); } @@ -3476,8 +3476,8 @@ polling_hbc_ccb_retry: , pCCB->pcmd->device->id , (u32)pCCB->pcmd->device->lun , pCCB); - pCCB->pcmd->result = DID_ABORT << 16; - arcmsr_ccb_complete(pCCB); + pCCB->pcmd->result = DID_ABORT << 16; + arcmsr_ccb_complete(pCCB); continue; } printk(KERN_NOTICE "arcmsr%d: polling get an illegal ccb" -- cgit v1.2.3 From 4583a4f66b323c6e4d774be2649e83a4e7c7b78c Mon Sep 17 00:00:00 2001 From: James Smart Date: Fri, 15 Nov 2019 16:38:47 -0800 Subject: scsi: lpfc: use hdwq assigned cpu for allocation Looking at the recent conversion from smp_processor_id() to raw_smp_processor_id(), realized that the allocation should be based on the cpu the hdwq is bound to, not the executing cpu. Revise to pull cpu number from the hdwq Fixes: 765ab6cdac3b ("scsi: lpfc: Fix a kernel warning triggered by lpfc_get_sgl_per_hdwq()") Link: https://lore.kernel.org/r/20191116003847.6141-1-jsmart2021@gmail.com Signed-off-by: Dick Kennedy Signed-off-by: James Smart Signed-off-by: Martin K. Petersen --- drivers/scsi/lpfc/lpfc_sli.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/lpfc/lpfc_sli.c b/drivers/scsi/lpfc/lpfc_sli.c index 5286c78645ac..7c8527bd1677 100644 --- a/drivers/scsi/lpfc/lpfc_sli.c +++ b/drivers/scsi/lpfc/lpfc_sli.c @@ -20668,7 +20668,7 @@ lpfc_get_sgl_per_hdwq(struct lpfc_hba *phba, struct lpfc_io_buf *lpfc_buf) /* allocate more */ spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, - cpu_to_node(raw_smp_processor_id())); + cpu_to_node(hdwq->io_wq->chann)); if (!tmp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "8353 error kmalloc memory for HDWQ " @@ -20811,7 +20811,7 @@ lpfc_get_cmd_rsp_buf_per_hdwq(struct lpfc_hba *phba, /* allocate more */ spin_unlock_irqrestore(&hdwq->hdwq_lock, iflags); tmp = kmalloc_node(sizeof(*tmp), GFP_ATOMIC, - cpu_to_node(raw_smp_processor_id())); + cpu_to_node(hdwq->io_wq->chann)); if (!tmp) { lpfc_printf_log(phba, KERN_INFO, LOG_SLI, "8355 error kmalloc memory for HDWQ " -- cgit v1.2.3 From aa5334c4f3014940f11bf876e919c956abef4089 Mon Sep 17 00:00:00 2001 From: Maurizio Lombardi Date: Fri, 15 Nov 2019 17:37:27 +0100 Subject: scsi: scsi_debug: num_tgts must be >= 0 Passing the parameter "num_tgts=-1" will start an infinite loop that exhausts the system memory Link: https://lore.kernel.org/r/20191115163727.24626-1-mlombard@redhat.com Signed-off-by: Maurizio Lombardi Acked-by: Douglas Gilbert Signed-off-by: Martin K. Petersen --- drivers/scsi/scsi_debug.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c index 4daf2637c011..44cb054d5e66 100644 --- a/drivers/scsi/scsi_debug.c +++ b/drivers/scsi/scsi_debug.c @@ -5263,6 +5263,11 @@ static int __init scsi_debug_init(void) return -EINVAL; } + if (sdebug_num_tgts < 0) { + pr_err("num_tgts must be >= 0\n"); + return -EINVAL; + } + if (sdebug_guard > 1) { pr_err("guard must be 0 or 1\n"); return -EINVAL; -- cgit v1.2.3 From 350767f20be86ee58f862caddadcfa192b9b976d Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 16 Nov 2019 14:36:57 +1100 Subject: scsi: NCR5380: Call scsi_set_resid() on command completion Most NCR5380 drivers calculate the residual for every data transfer. (A few drivers just set it to zero.) Pass this quantity back to the scsi mid-layer on command completion. Cc: Michael Schmitz Cc: Ondrej Zary Link: https://lore.kernel.org/r/1f26ead9dd0dc053fcd27979d69a7ca74b6589b4.1573875417.git.fthain@telegraphics.com.au Reviewed-and-tested-by: Michael Schmitz Tested-by: Ondrej Zary Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 536426f25e86..b040b83a5418 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -172,6 +172,19 @@ static inline void advance_sg_buffer(struct scsi_cmnd *cmd) } } +static inline void set_resid_from_SCp(struct scsi_cmnd *cmd) +{ + int resid = cmd->SCp.this_residual; + struct scatterlist *s = cmd->SCp.buffer; + + if (s) + while (!sg_is_last(s)) { + s = sg_next(s); + resid += s->length; + } + scsi_set_resid(cmd, resid); +} + /** * NCR5380_poll_politely2 - wait for two chip register values * @hostdata: host private data @@ -1803,6 +1816,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) cmd->result |= cmd->SCp.Status; cmd->result |= cmd->SCp.Message << 8; + set_resid_from_SCp(cmd); + if (cmd->cmnd[0] == REQUEST_SENSE) complete_cmd(instance, cmd); else { -- cgit v1.2.3 From d04fc41af247a2ce993155bce7995d857464a096 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 16 Nov 2019 14:36:57 +1100 Subject: scsi: NCR5380: Unconditionally clear ICR after do_abort() When do_abort() succeeds, the target will go to BUS FREE phase and there will be no connected command. Therefore, that function should clear the Initiator Command Register before returning. It already does so in case of NCR5380_poll_politely() failure; do the same for the other error case too, that is, NCR5380_transfer_pio() failure. Cc: Michael Schmitz Cc: Ondrej Zary Link: https://lore.kernel.org/r/4277b28ee2551f884aefa85965ef3c498344f301.1573875417.git.fthain@telegraphics.com.au Reviewed-and-tested-by: Michael Schmitz Tested-by: Ondrej Zary Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index b040b83a5418..43745f26ef75 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -1392,7 +1392,7 @@ static void do_reset(struct Scsi_Host *instance) * MESSAGE OUT phase and sending an ABORT message. * @instance: relevant scsi host instance * - * Returns 0 on success, -1 on failure. + * Returns 0 on success, negative error code on failure. */ static int do_abort(struct Scsi_Host *instance) @@ -1417,7 +1417,7 @@ static int do_abort(struct Scsi_Host *instance) rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, SR_REQ, 10 * HZ); if (rc < 0) - goto timeout; + goto out; tmp = NCR5380_read(STATUS_REG) & PHASE_MASK; @@ -1428,7 +1428,7 @@ static int do_abort(struct Scsi_Host *instance) ICR_BASE | ICR_ASSERT_ATN | ICR_ASSERT_ACK); rc = NCR5380_poll_politely(hostdata, STATUS_REG, SR_REQ, 0, 3 * HZ); if (rc < 0) - goto timeout; + goto out; NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN); } @@ -1437,17 +1437,17 @@ static int do_abort(struct Scsi_Host *instance) len = 1; phase = PHASE_MSGOUT; NCR5380_transfer_pio(instance, &phase, &len, &msgptr); + if (len) + rc = -ENXIO; /* * If we got here, and the command completed successfully, * we're about to go into bus free state. */ - return len ? -1 : 0; - -timeout: +out: NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - return -1; + return rc; } /* @@ -2279,7 +2279,7 @@ static int NCR5380_abort(struct scsi_cmnd *cmd) dsprintk(NDEBUG_ABORT, instance, "abort: cmd %p is connected\n", cmd); hostdata->connected = NULL; hostdata->dma_len = 0; - if (do_abort(instance)) { + if (do_abort(instance) < 0) { set_host_byte(cmd, DID_ERROR); complete_cmd(instance, cmd); result = FAILED; -- cgit v1.2.3 From 0b7a223552d455bcfba6fb9cfc5eef2b5fce1491 Mon Sep 17 00:00:00 2001 From: Finn Thain Date: Sat, 16 Nov 2019 14:36:57 +1100 Subject: scsi: NCR5380: Add disconnect_mask module parameter Add a module parameter to inhibit disconnect/reselect for individual targets. This gains compatibility with Aztec PowerMonster SCSI/SATA adapters with buggy firmware. (No fix is available from the vendor.) Apparently these adapters pass-through the product/vendor of the attached SATA device. Since they can't be identified from the response to an INQUIRY command, a device blacklist flag won't work. Cc: Michael Schmitz Link: https://lore.kernel.org/r/993b17545990f31f9fa5a98202b51102a68e7594.1573875417.git.fthain@telegraphics.com.au Reviewed-and-tested-by: Michael Schmitz Signed-off-by: Finn Thain Signed-off-by: Martin K. Petersen --- drivers/scsi/NCR5380.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c index 43745f26ef75..f2f7e6e76c07 100644 --- a/drivers/scsi/NCR5380.c +++ b/drivers/scsi/NCR5380.c @@ -129,6 +129,9 @@ #define NCR5380_release_dma_irq(x) #endif +static unsigned int disconnect_mask = ~0; +module_param(disconnect_mask, int, 0444); + static int do_abort(struct Scsi_Host *); static void do_reset(struct Scsi_Host *); static void bus_reset_cleanup(struct Scsi_Host *); @@ -967,7 +970,8 @@ static bool NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd) int err; bool ret = true; bool can_disconnect = instance->irq != NO_IRQ && - cmd->cmnd[0] != REQUEST_SENSE; + cmd->cmnd[0] != REQUEST_SENSE && + (disconnect_mask & BIT(scmd_id(cmd))); NCR5380_dprint(NDEBUG_ARBITRATION, instance); dsprintk(NDEBUG_ARBITRATION, instance, "starting arbitration, id = %d\n", -- cgit v1.2.3 From 5a993e507ee65a28eca6690ee11868555c4ca46b Mon Sep 17 00:00:00 2001 From: "Martin K. Petersen" Date: Mon, 18 Nov 2019 23:55:45 -0500 Subject: Revert "scsi: qla2xxx: Fix memory leak when sending I/O fails" This reverts commit 2f856d4e8c23f5ad5221f8da4a2f22d090627f19. This patch was found to introduce a double free regression. The issue it originally attempted to address was fixed in patch f45bca8c5052 ("scsi: qla2xxx: Fix double scsi_done for abort path"). Link: https://lore.kernel.org/r/4BDE2B95-835F-43BE-A32C-2629D7E03E0A@marvell.com Requested-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index be33d61197d1..2450ba933bb2 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -909,8 +909,6 @@ qla2xxx_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd) qc24_host_busy_free_sp: sp->free(sp); - CMD_SP(cmd) = NULL; - qla2x00_rel_sp(sp); qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; @@ -994,8 +992,6 @@ qla2xxx_mqueuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd, qc24_host_busy_free_sp: sp->free(sp); - CMD_SP(cmd) = NULL; - qla2xxx_rel_qpair_sp(sp->qpair, sp); qc24_target_busy: return SCSI_MLQUEUE_TARGET_BUSY; -- cgit v1.2.3 From 29d28f2b8d3736ac61c28ef7e20fda63795b74d9 Mon Sep 17 00:00:00 2001 From: Pan Bian Date: Wed, 6 Nov 2019 20:32:21 +0800 Subject: scsi: bnx2i: fix potential use after free The member hba->pcidev may be used after its reference is dropped. Move the put function to where it is never used to avoid potential use after free issues. Fixes: a77171806515 ("[SCSI] bnx2i: Removed the reference to the netdev->base_addr") Link: https://lore.kernel.org/r/1573043541-19126-1-git-send-email-bianpan2016@163.com Signed-off-by: Pan Bian Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2i/bnx2i_iscsi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c index c5fa5f3b00e9..0b28d44d3573 100644 --- a/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -915,12 +915,12 @@ void bnx2i_free_hba(struct bnx2i_hba *hba) INIT_LIST_HEAD(&hba->ep_ofld_list); INIT_LIST_HEAD(&hba->ep_active_list); INIT_LIST_HEAD(&hba->ep_destroy_list); - pci_dev_put(hba->pcidev); if (hba->regview) { pci_iounmap(hba->pcidev, hba->regview); hba->regview = NULL; } + pci_dev_put(hba->pcidev); bnx2i_free_mp_bdt(hba); bnx2i_release_free_cid_que(hba); iscsi_host_free(shost); -- cgit v1.2.3 From 11bf1d14b2d6fd4f144d8ee3ac2e71057fc0ec35 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 7 Nov 2019 13:54:58 -0800 Subject: scsi: target: core: Document target_cmd_size_check() Since it is nontrivial to derive the meaning of the size argument from the code, add a documentation header above target_cmd_size_check(). Cc: Mike Christie Cc: Christoph Hellwig Cc: Hannes Reinecke Cc: Nicholas Bellinger Link: https://lore.kernel.org/r/20191107215458.64242-1-bvanassche@acm.org Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 7f06a62f8661..652ef1c9a9f6 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -1243,6 +1243,19 @@ target_check_max_data_sg_nents(struct se_cmd *cmd, struct se_device *dev, return TCM_NO_SENSE; } +/** + * target_cmd_size_check - Check whether there will be a residual. + * @cmd: SCSI command. + * @size: Data buffer size derived from CDB. The data buffer size provided by + * the SCSI transport driver is available in @cmd->data_length. + * + * Compare the data buffer size from the CDB with the data buffer limit from the transport + * header. Set @cmd->residual_count and SCF_OVERFLOW_BIT or SCF_UNDERFLOW_BIT if necessary. + * + * Note: target drivers set @cmd->data_length by calling transport_init_se_cmd(). + * + * Return: TCM_NO_SENSE + */ sense_reason_t target_cmd_size_check(struct se_cmd *cmd, unsigned int size) { -- cgit v1.2.3 From 80647a89eaf3f2549741648f3230cd6ff68c23b4 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 13 Nov 2019 14:05:07 -0800 Subject: scsi: target: core: Release SPC-2 reservations when closing a session The SCSI specs require releasing SPC-2 reservations when a session is closed. Make sure that the target core does this. Running the libiscsi tests triggers the KASAN complaint shown below. This patch fixes that use-after-free. BUG: KASAN: use-after-free in target_check_reservation+0x171/0x980 [target_core_mod] Read of size 8 at addr ffff88802ecd1878 by task iscsi_trx/17200 CPU: 0 PID: 17200 Comm: iscsi_trx Not tainted 5.4.0-rc1-dbg+ #1 Hardware name: Bochs Bochs, BIOS Bochs 01/01/2011 Call Trace: dump_stack+0x8a/0xd6 print_address_description.constprop.0+0x40/0x60 __kasan_report.cold+0x1b/0x34 kasan_report+0x16/0x20 __asan_load8+0x58/0x90 target_check_reservation+0x171/0x980 [target_core_mod] __target_execute_cmd+0xb1/0xf0 [target_core_mod] target_execute_cmd+0x22d/0x4d0 [target_core_mod] transport_generic_new_cmd+0x31f/0x5b0 [target_core_mod] transport_handle_cdb_direct+0x6f/0x90 [target_core_mod] iscsit_execute_cmd+0x381/0x3f0 [iscsi_target_mod] iscsit_sequence_cmd+0x13b/0x1f0 [iscsi_target_mod] iscsit_process_scsi_cmd+0x4c/0x130 [iscsi_target_mod] iscsit_get_rx_pdu+0x8e8/0x15f0 [iscsi_target_mod] iscsi_target_rx_thread+0x105/0x1b0 [iscsi_target_mod] kthread+0x1bc/0x210 ret_from_fork+0x24/0x30 Allocated by task 1079: save_stack+0x23/0x90 __kasan_kmalloc.constprop.0+0xcf/0xe0 kasan_slab_alloc+0x12/0x20 kmem_cache_alloc+0xfe/0x3a0 transport_alloc_session+0x29/0x80 [target_core_mod] iscsi_target_login_thread+0xceb/0x1920 [iscsi_target_mod] kthread+0x1bc/0x210 ret_from_fork+0x24/0x30 Freed by task 17193: save_stack+0x23/0x90 __kasan_slab_free+0x13a/0x190 kasan_slab_free+0x12/0x20 kmem_cache_free+0xc8/0x3e0 transport_free_session+0x179/0x2f0 [target_core_mod] transport_deregister_session+0x121/0x170 [target_core_mod] iscsit_close_session+0x12c/0x350 [iscsi_target_mod] iscsit_logout_post_handler+0x136/0x380 [iscsi_target_mod] iscsit_response_queue+0x8fa/0xc00 [iscsi_target_mod] iscsi_target_tx_thread+0x28e/0x390 [iscsi_target_mod] kthread+0x1bc/0x210 ret_from_fork+0x24/0x30 The buggy address belongs to the object at ffff88802ecd1860 which belongs to the cache se_sess_cache of size 352 The buggy address is located 24 bytes inside of 352-byte region [ffff88802ecd1860, ffff88802ecd19c0) The buggy address belongs to the page: page:ffffea0000bb3400 refcount:1 mapcount:0 mapping:ffff8880bef2ed00 index:0x0 compound_mapcount: 0 flags: 0x1000000000010200(slab|head) raw: 1000000000010200 dead000000000100 dead000000000122 ffff8880bef2ed00 raw: 0000000000000000 0000000080270027 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff88802ecd1700: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff88802ecd1780: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb >ffff88802ecd1800: fb fb fb fb fc fc fc fc fc fc fc fc fb fb fb fb ^ ffff88802ecd1880: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff88802ecd1900: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb Cc: Mike Christie Link: https://lore.kernel.org/r/20191113220508.198257-2-bvanassche@acm.org Reviewed-by: Roman Bolshakov Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_transport.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 652ef1c9a9f6..ea482d4b1f00 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c @@ -584,6 +584,15 @@ void transport_free_session(struct se_session *se_sess) } EXPORT_SYMBOL(transport_free_session); +static int target_release_res(struct se_device *dev, void *data) +{ + struct se_session *sess = data; + + if (dev->reservation_holder == sess) + target_release_reservation(dev); + return 0; +} + void transport_deregister_session(struct se_session *se_sess) { struct se_portal_group *se_tpg = se_sess->se_tpg; @@ -600,6 +609,12 @@ void transport_deregister_session(struct se_session *se_sess) se_sess->fabric_sess_ptr = NULL; spin_unlock_irqrestore(&se_tpg->session_lock, flags); + /* + * Since the session is being removed, release SPC-2 + * reservations held by the session that is disappearing. + */ + target_for_each_device(target_release_res, se_sess); + pr_debug("TARGET_CORE[%s]: Deregistered fabric_sess\n", se_tpg->se_tpg_tfo->fabric_name); /* -- cgit v1.2.3 From e9d3009cb936bd0faf0719f68d98ad8afb1e613b Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Wed, 13 Nov 2019 14:05:08 -0800 Subject: scsi: target: iscsi: Wait for all commands to finish before freeing a session The iSCSI target driver is the only target driver that does not wait for ongoing commands to finish before freeing a session. Make the iSCSI target driver wait for ongoing commands to finish before freeing a session. This patch fixes the following KASAN complaint: BUG: KASAN: use-after-free in __lock_acquire+0xb1a/0x2710 Read of size 8 at addr ffff8881154eca70 by task kworker/0:2/247 CPU: 0 PID: 247 Comm: kworker/0:2 Not tainted 5.4.0-rc1-dbg+ #6 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Workqueue: target_completion target_complete_ok_work [target_core_mod] Call Trace: dump_stack+0x8a/0xd6 print_address_description.constprop.0+0x40/0x60 __kasan_report.cold+0x1b/0x33 kasan_report+0x16/0x20 __asan_load8+0x58/0x90 __lock_acquire+0xb1a/0x2710 lock_acquire+0xd3/0x200 _raw_spin_lock_irqsave+0x43/0x60 target_release_cmd_kref+0x162/0x7f0 [target_core_mod] target_put_sess_cmd+0x2e/0x40 [target_core_mod] lio_check_stop_free+0x12/0x20 [iscsi_target_mod] transport_cmd_check_stop_to_fabric+0xd8/0xe0 [target_core_mod] target_complete_ok_work+0x1b0/0x790 [target_core_mod] process_one_work+0x549/0xa40 worker_thread+0x7a/0x5d0 kthread+0x1bc/0x210 ret_from_fork+0x24/0x30 Allocated by task 889: save_stack+0x23/0x90 __kasan_kmalloc.constprop.0+0xcf/0xe0 kasan_slab_alloc+0x12/0x20 kmem_cache_alloc+0xf6/0x360 transport_alloc_session+0x29/0x80 [target_core_mod] iscsi_target_login_thread+0xcd6/0x18f0 [iscsi_target_mod] kthread+0x1bc/0x210 ret_from_fork+0x24/0x30 Freed by task 1025: save_stack+0x23/0x90 __kasan_slab_free+0x13a/0x190 kasan_slab_free+0x12/0x20 kmem_cache_free+0x146/0x400 transport_free_session+0x179/0x2f0 [target_core_mod] transport_deregister_session+0x130/0x180 [target_core_mod] iscsit_close_session+0x12c/0x350 [iscsi_target_mod] iscsit_logout_post_handler+0x136/0x380 [iscsi_target_mod] iscsit_response_queue+0x8de/0xbe0 [iscsi_target_mod] iscsi_target_tx_thread+0x27f/0x370 [iscsi_target_mod] kthread+0x1bc/0x210 ret_from_fork+0x24/0x30 The buggy address belongs to the object at ffff8881154ec9c0 which belongs to the cache se_sess_cache of size 352 The buggy address is located 176 bytes inside of 352-byte region [ffff8881154ec9c0, ffff8881154ecb20) The buggy address belongs to the page: page:ffffea0004553b00 refcount:1 mapcount:0 mapping:ffff888101755400 index:0x0 compound_mapcount: 0 flags: 0x2fff000000010200(slab|head) raw: 2fff000000010200 dead000000000100 dead000000000122 ffff888101755400 raw: 0000000000000000 0000000080130013 00000001ffffffff 0000000000000000 page dumped because: kasan: bad access detected Memory state around the buggy address: ffff8881154ec900: fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc fc ffff8881154ec980: fc fc fc fc fc fc fc fc fb fb fb fb fb fb fb fb >ffff8881154eca00: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ^ ffff8881154eca80: fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb fb ffff8881154ecb00: fb fb fb fb fc fc fc fc fc fc fc fc fc fc fc fc Cc: Mike Christie Link: https://lore.kernel.org/r/20191113220508.198257-3-bvanassche@acm.org Reviewed-by: Roman Bolshakov Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/iscsi/iscsi_target.c | 10 ++++++++-- include/scsi/iscsi_proto.h | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 09e55ea0bf5d..7251a87bb576 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c @@ -1165,7 +1165,9 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length, conn->cid); - target_get_sess_cmd(&cmd->se_cmd, true); + if (target_get_sess_cmd(&cmd->se_cmd, true) < 0) + return iscsit_add_reject_cmd(cmd, + ISCSI_REASON_WAITING_FOR_LOGOUT, buf); cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, scsilun_to_int(&hdr->lun)); @@ -2002,7 +2004,9 @@ iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, conn->sess->se_sess, 0, DMA_NONE, TCM_SIMPLE_TAG, cmd->sense_buffer + 2); - target_get_sess_cmd(&cmd->se_cmd, true); + if (target_get_sess_cmd(&cmd->se_cmd, true) < 0) + return iscsit_add_reject_cmd(cmd, + ISCSI_REASON_WAITING_FOR_LOGOUT, buf); /* * TASK_REASSIGN for ERL=2 / connection stays inside of @@ -4230,6 +4234,8 @@ int iscsit_close_connection( * must wait until they have completed. */ iscsit_check_conn_usage_count(conn); + target_sess_cmd_list_set_waiting(sess->se_sess); + target_wait_for_sess_cmds(sess->se_sess); ahash_request_free(conn->conn_tx_hash); if (conn->conn_rx_hash) { diff --git a/include/scsi/iscsi_proto.h b/include/scsi/iscsi_proto.h index b71b5c4f418c..533f56733ba8 100644 --- a/include/scsi/iscsi_proto.h +++ b/include/scsi/iscsi_proto.h @@ -627,6 +627,7 @@ struct iscsi_reject { #define ISCSI_REASON_BOOKMARK_INVALID 9 #define ISCSI_REASON_BOOKMARK_NO_RESOURCES 10 #define ISCSI_REASON_NEGOTIATION_RESET 11 +#define ISCSI_REASON_WAITING_FOR_LOGOUT 12 /* Max. number of Key=Value pairs in a text message */ #define MAX_KEY_VALUE_PAIRS 8192 -- cgit v1.2.3 From 238191d65d7217982d69e21c1d623616da34b281 Mon Sep 17 00:00:00 2001 From: Anatol Pomazau Date: Fri, 15 Nov 2019 19:47:35 -0500 Subject: scsi: iscsi: Don't send data to unbound connection If a faulty initiator fails to bind the socket to the iSCSI connection before emitting a command, for instance, a subsequent send_pdu, it will crash the kernel due to a null pointer dereference in sock_sendmsg(), as shown in the log below. This patch makes sure the bind succeeded before trying to use the socket. BUG: kernel NULL pointer dereference, address: 0000000000000018 #PF: supervisor read access in kernel mode #PF: error_code(0x0000) - not-present page PGD 0 P4D 0 Oops: 0000 [#1] SMP PTI CPU: 3 PID: 7 Comm: kworker/u8:0 Not tainted 5.4.0-rc2.iscsi+ #13 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 [ 24.158246] Workqueue: iscsi_q_0 iscsi_xmitworker [ 24.158883] RIP: 0010:apparmor_socket_sendmsg+0x5/0x20 [...] [ 24.161739] RSP: 0018:ffffab6440043ca0 EFLAGS: 00010282 [ 24.162400] RAX: ffffffff891c1c00 RBX: ffffffff89d53968 RCX: 0000000000000001 [ 24.163253] RDX: 0000000000000030 RSI: ffffab6440043d00 RDI: 0000000000000000 [ 24.164104] RBP: 0000000000000030 R08: 0000000000000030 R09: 0000000000000030 [ 24.165166] R10: ffffffff893e66a0 R11: 0000000000000018 R12: ffffab6440043d00 [ 24.166038] R13: 0000000000000000 R14: 0000000000000000 R15: ffff9d5575a62e90 [ 24.166919] FS: 0000000000000000(0000) GS:ffff9d557db80000(0000) knlGS:0000000000000000 [ 24.167890] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 24.168587] CR2: 0000000000000018 CR3: 000000007a838000 CR4: 00000000000006e0 [ 24.169451] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 [ 24.170320] DR3: 0000000000000000 DR6: 00000000fffe0ff0 DR7: 0000000000000400 [ 24.171214] Call Trace: [ 24.171537] security_socket_sendmsg+0x3a/0x50 [ 24.172079] sock_sendmsg+0x16/0x60 [ 24.172506] iscsi_sw_tcp_xmit_segment+0x77/0x120 [ 24.173076] iscsi_sw_tcp_pdu_xmit+0x58/0x170 [ 24.173604] ? iscsi_dbg_trace+0x63/0x80 [ 24.174087] iscsi_tcp_task_xmit+0x101/0x280 [ 24.174666] iscsi_xmit_task+0x83/0x110 [ 24.175206] iscsi_xmitworker+0x57/0x380 [ 24.175757] ? __schedule+0x2a2/0x700 [ 24.176273] process_one_work+0x1b5/0x360 [ 24.176837] worker_thread+0x50/0x3c0 [ 24.177353] kthread+0xf9/0x130 [ 24.177799] ? process_one_work+0x360/0x360 [ 24.178401] ? kthread_park+0x90/0x90 [ 24.178915] ret_from_fork+0x35/0x40 [ 24.179421] Modules linked in: [ 24.179856] CR2: 0000000000000018 [ 24.180327] ---[ end trace b4b7674b6df5f480 ]--- Signed-off-by: Anatol Pomazau Co-developed-by: Frank Mayhar Signed-off-by: Frank Mayhar Co-developed-by: Bharath Ravi Signed-off-by: Bharath Ravi Co-developed-by: Khazhimsel Kumykov Signed-off-by: Khazhimsel Kumykov Co-developed-by: Gabriel Krisman Bertazi Signed-off-by: Gabriel Krisman Bertazi Reviewed-by: Lee Duncan Signed-off-by: Martin K. Petersen --- drivers/scsi/iscsi_tcp.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index 7bedbe877704..0bc63a7ab41c 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -369,8 +369,16 @@ static int iscsi_sw_tcp_pdu_xmit(struct iscsi_task *task) { struct iscsi_conn *conn = task->conn; unsigned int noreclaim_flag; + struct iscsi_tcp_conn *tcp_conn = conn->dd_data; + struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data; int rc = 0; + if (!tcp_sw_conn->sock) { + iscsi_conn_printk(KERN_ERR, conn, + "Transport not bound to socket!\n"); + return -EINVAL; + } + noreclaim_flag = memalloc_noreclaim_save(); while (iscsi_sw_tcp_xmit_qlen(conn)) { -- cgit v1.2.3 From c941e0d172605731de9b4628bd4146d35cf2e7d6 Mon Sep 17 00:00:00 2001 From: Bart Van Assche Date: Thu, 7 Nov 2019 13:55:25 -0800 Subject: scsi: target: core: Fix a pr_debug() argument Print the string for which conversion failed instead of printing the function name twice. Fixes: 2650d71e244f ("target: move transport ID handling to the core") Cc: Christoph Hellwig Link: https://lore.kernel.org/r/20191107215525.64415-1-bvanassche@acm.org Signed-off-by: Bart Van Assche Signed-off-by: Martin K. Petersen --- drivers/target/target_core_fabric_lib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 3c79411c4cd0..6b4b354c88aa 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c @@ -118,7 +118,7 @@ static int srp_get_pr_transport_id( memset(buf + 8, 0, leading_zero_bytes); rc = hex2bin(buf + 8 + leading_zero_bytes, p, count); if (rc < 0) { - pr_debug("hex2bin failed for %s: %d\n", __func__, rc); + pr_debug("hex2bin failed for %s: %d\n", p, rc); return rc; } -- cgit v1.2.3 From 65309ef6b258f5a7b57c1033a82ba2aba5c434cc Mon Sep 17 00:00:00 2001 From: Laurence Oberman Date: Tue, 19 Nov 2019 10:46:34 -0500 Subject: scsi: bnx2fc: timeout calculation invalid for bnx2fc_eh_abort() In the bnx2fc_eh_abort() function there is a calculation for wait_for_completion that uses a HZ multiplier. This is incorrect, it scales the timeout by 1000 seconds instead of converting the ms value to jiffies. Therefore change the calculation. Link: https://lore.kernel.org/r/1574178394-16635-1-git-send-email-loberman@redhat.com Reported-by: David Jeffery Reviewed-by: John Pittman Reviewed-by: Chad Dupuis Signed-off-by: Laurence Oberman Signed-off-by: Martin K. Petersen --- drivers/scsi/bnx2fc/bnx2fc_io.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c index 401743e2b429..4c8122a82322 100644 --- a/drivers/scsi/bnx2fc/bnx2fc_io.c +++ b/drivers/scsi/bnx2fc/bnx2fc_io.c @@ -1242,7 +1242,7 @@ int bnx2fc_eh_abort(struct scsi_cmnd *sc_cmd) /* Wait 2 * RA_TOV + 1 to be sure timeout function hasn't fired */ time_left = wait_for_completion_timeout(&io_req->abts_done, - (2 * rp->r_a_tov + 1) * HZ); + msecs_to_jiffies(2 * rp->r_a_tov + 1)); if (time_left) BNX2FC_IO_DBG(io_req, "Timed out in eh_abort waiting for abts_done"); -- cgit v1.2.3