From 0c227dc22ca18856055983f27594feb2e0149965 Mon Sep 17 00:00:00 2001 From: Shreyas Deodhar Date: Mon, 19 Dec 2022 03:07:38 -0800 Subject: [PATCH 01/11] scsi: qla2xxx: Check if port is online before sending ELS CT Ping and ELS cmds fail for NVMe targets. Check if port is online before sending ELS instead of sending login. Cc: stable@vger.kernel.org Signed-off-by: Shreyas Deodhar Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_bsg.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_bsg.c b/drivers/scsi/qla2xxx/qla_bsg.c index cd75b179410d..dba7bba788d7 100644 --- a/drivers/scsi/qla2xxx/qla_bsg.c +++ b/drivers/scsi/qla2xxx/qla_bsg.c @@ -278,8 +278,8 @@ qla2x00_process_els(struct bsg_job *bsg_job) const char *type; int req_sg_cnt, rsp_sg_cnt; int rval = (DID_ERROR << 16); - uint16_t nextlid = 0; uint32_t els_cmd = 0; + int qla_port_allocated = 0; if (bsg_request->msgcode == FC_BSG_RPT_ELS) { rport = fc_bsg_to_rport(bsg_job); @@ -329,9 +329,9 @@ qla2x00_process_els(struct bsg_job *bsg_job) /* make sure the rport is logged in, * if not perform fabric login */ - if (qla2x00_fabric_login(vha, fcport, &nextlid)) { + if (atomic_read(&fcport->state) != FCS_ONLINE) { ql_dbg(ql_dbg_user, vha, 0x7003, - "Failed to login port %06X for ELS passthru.\n", + "Port %06X is not online for ELS passthru.\n", fcport->d_id.b24); rval = -EIO; goto done; @@ -348,6 +348,7 @@ qla2x00_process_els(struct bsg_job *bsg_job) goto done; } + qla_port_allocated = 1; /* Initialize all required fields of fcport */ fcport->vha = vha; fcport->d_id.b.al_pa = @@ -432,7 +433,7 @@ qla2x00_process_els(struct bsg_job *bsg_job) goto done_free_fcport; done_free_fcport: - if (bsg_request->msgcode != FC_BSG_RPT_ELS) + if (qla_port_allocated) qla2x00_free_fcport(fcport); done: return rval; From b1ae65c082f74536ec292b15766f2846f0238373 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:39 -0800 Subject: [PATCH 02/11] scsi: qla2xxx: Fix link failure in NPIV environment User experienced symptoms of adapter failure in NPIV environment. NPIV hosts were allowed to trigger chip reset back to back due to NPIV link state being slow to come online. Fix link failure in NPIV environment by removing NPIV host from directly being able to perform chip reset. kernel: qla2xxx [0000:04:00.1]-6009:261: Loop down - aborting ISP. kernel: qla2xxx [0000:04:00.1]-6009:262: Loop down - aborting ISP. kernel: qla2xxx [0000:04:00.1]-6009:281: Loop down - aborting ISP. kernel: qla2xxx [0000:04:00.1]-6009:285: Loop down - aborting ISP Fixes: 0d6e61bc6a4f ("[SCSI] qla2xxx: Correct various NPIV issues.") Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 7fb28c207ee5..36d3cecab20e 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -7447,7 +7447,7 @@ qla2x00_timer(struct timer_list *t) /* if the loop has been down for 4 minutes, reinit adapter */ if (atomic_dec_and_test(&vha->loop_down_timer) != 0) { - if (!(vha->device_flags & DFLG_NO_CABLE)) { + if (!(vha->device_flags & DFLG_NO_CABLE) && !vha->vp_idx) { ql_log(ql_log_warn, vha, 0x6009, "Loop down - aborting ISP.\n"); From c75e6aef5039830cce5d4cf764dd204522f89e6b Mon Sep 17 00:00:00 2001 From: Arun Easi Date: Mon, 19 Dec 2022 03:07:40 -0800 Subject: [PATCH 03/11] scsi: qla2xxx: Fix DMA-API call trace on NVMe LS requests The following message and call trace was seen with debug kernels: DMA-API: qla2xxx 0000:41:00.0: device driver failed to check map error [device address=0x00000002a3ff38d8] [size=1024 bytes] [mapped as single] WARNING: CPU: 0 PID: 2930 at kernel/dma/debug.c:1017 check_unmap+0xf42/0x1990 Call Trace: debug_dma_unmap_page+0xc9/0x100 qla_nvme_ls_unmap+0x141/0x210 [qla2xxx] Remove DMA mapping from the driver altogether, as it is already done by FC layer. This prevents the warning. Fixes: c85ab7d9e27a ("scsi: qla2xxx: Fix missed DMA unmap for NVMe ls requests") Cc: stable@vger.kernel.org Signed-off-by: Arun Easi Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_nvme.c | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 02fdeb0d31ec..8927ddc5e69c 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -170,18 +170,6 @@ static void qla_nvme_release_fcp_cmd_kref(struct kref *kref) qla2xxx_rel_qpair_sp(sp->qpair, sp); } -static void qla_nvme_ls_unmap(struct srb *sp, struct nvmefc_ls_req *fd) -{ - if (sp->flags & SRB_DMA_VALID) { - struct srb_iocb *nvme = &sp->u.iocb_cmd; - struct qla_hw_data *ha = sp->fcport->vha->hw; - - dma_unmap_single(&ha->pdev->dev, nvme->u.nvme.cmd_dma, - fd->rqstlen, DMA_TO_DEVICE); - sp->flags &= ~SRB_DMA_VALID; - } -} - static void qla_nvme_release_ls_cmd_kref(struct kref *kref) { struct srb *sp = container_of(kref, struct srb, cmd_kref); @@ -199,7 +187,6 @@ static void qla_nvme_release_ls_cmd_kref(struct kref *kref) fd = priv->fd; - qla_nvme_ls_unmap(sp, fd); fd->done(fd, priv->comp_status); out: qla2x00_rel_sp(sp); @@ -365,13 +352,10 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, nvme->u.nvme.rsp_len = fd->rsplen; nvme->u.nvme.rsp_dma = fd->rspdma; nvme->u.nvme.timeout_sec = fd->timeout; - nvme->u.nvme.cmd_dma = dma_map_single(&ha->pdev->dev, fd->rqstaddr, - fd->rqstlen, DMA_TO_DEVICE); + nvme->u.nvme.cmd_dma = fd->rqstdma; dma_sync_single_for_device(&ha->pdev->dev, nvme->u.nvme.cmd_dma, fd->rqstlen, DMA_TO_DEVICE); - sp->flags |= SRB_DMA_VALID; - rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { ql_log(ql_log_warn, vha, 0x700e, @@ -379,7 +363,6 @@ static int qla_nvme_ls_req(struct nvme_fc_local_port *lport, wake_up(&sp->nvme_ls_waitq); sp->priv = NULL; priv->sp = NULL; - qla_nvme_ls_unmap(sp, fd); qla2x00_rel_sp(sp); return rval; } From 41e5afe51f75f2858f5563145348f6c26d307b8f Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:41 -0800 Subject: [PATCH 04/11] scsi: qla2xxx: Fix exchange oversubscription In large environment, it is possible to experience command timeout and escalation of path recovery. Currently the driver does not track the number of exchanges/commands sent to FW. If there is a delay for commands at the head of the queue, then this will create back pressure for commands at the back of the queue. Check for exchange availability before command submission. Fixes: 89c72f4245a8 ("scsi: qla2xxx: Add IOCB resource tracking") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 6 +++- drivers/scsi/qla2xxx/qla_edif.c | 7 +++-- drivers/scsi/qla2xxx/qla_init.c | 13 ++++++++ drivers/scsi/qla2xxx/qla_inline.h | 52 +++++++++++++++++++++---------- drivers/scsi/qla2xxx/qla_iocb.c | 28 ++++++++++------- drivers/scsi/qla2xxx/qla_isr.c | 3 +- drivers/scsi/qla2xxx/qla_nvme.c | 15 ++++++++- 7 files changed, 88 insertions(+), 36 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index a26a373be9da..cd4eb11b0707 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -660,7 +660,7 @@ enum { struct iocb_resource { u8 res_type; - u8 pad; + u8 exch_cnt; u16 iocb_cnt; }; @@ -3721,6 +3721,10 @@ struct qla_fw_resources { u16 iocbs_limit; u16 iocbs_qp_limit; u16 iocbs_used; + u16 exch_total; + u16 exch_limit; + u16 exch_used; + u16 pad; }; #define QLA_IOCB_PCT_LIMIT 95 diff --git a/drivers/scsi/qla2xxx/qla_edif.c b/drivers/scsi/qla2xxx/qla_edif.c index e4240aae5f9e..53186a145962 100644 --- a/drivers/scsi/qla2xxx/qla_edif.c +++ b/drivers/scsi/qla2xxx/qla_edif.c @@ -2989,9 +2989,10 @@ qla28xx_start_scsi_edif(srb_t *sp) tot_dsds = nseg; req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - sp->iores.res_type = RESOURCE_INI; + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; sp->iores.iocb_cnt = req_cnt; - if (qla_get_iocbs(sp->qpair, &sp->iores)) + if (qla_get_fw_resources(sp->qpair, &sp->iores)) goto queuing_error; if (req->cnt < (req_cnt + 2)) { @@ -3185,7 +3186,7 @@ qla28xx_start_scsi_edif(srb_t *sp) mempool_free(sp->u.scmd.ct6_ctx, ha->ctx_mempool); sp->u.scmd.ct6_ctx = NULL; } - qla_put_iocbs(sp->qpair, &sp->iores); + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(lock, flags); return QLA_FUNCTION_FAILED; diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 8d9ecabb1aac..fd27fb511479 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -128,12 +128,14 @@ static void qla24xx_abort_iocb_timeout(void *data) sp->cmd_sp)) { qpair->req->outstanding_cmds[handle] = NULL; cmdsp_found = 1; + qla_put_fw_resources(qpair, &sp->cmd_sp->iores); } /* removing the abort */ if (qpair->req->outstanding_cmds[handle] == sp) { qpair->req->outstanding_cmds[handle] = NULL; sp_found = 1; + qla_put_fw_resources(qpair, &sp->iores); break; } } @@ -2000,6 +2002,7 @@ qla2x00_tmf_iocb_timeout(void *data) for (h = 1; h < sp->qpair->req->num_outstanding_cmds; h++) { if (sp->qpair->req->outstanding_cmds[h] == sp) { sp->qpair->req->outstanding_cmds[h] = NULL; + qla_put_fw_resources(sp->qpair, &sp->iores); break; } } @@ -3943,6 +3946,12 @@ void qla_init_iocb_limit(scsi_qla_host_t *vha) ha->base_qpair->fwres.iocbs_limit = limit; ha->base_qpair->fwres.iocbs_qp_limit = limit / num_qps; ha->base_qpair->fwres.iocbs_used = 0; + + ha->base_qpair->fwres.exch_total = ha->orig_fw_xcb_count; + ha->base_qpair->fwres.exch_limit = (ha->orig_fw_xcb_count * + QLA_IOCB_PCT_LIMIT) / 100; + ha->base_qpair->fwres.exch_used = 0; + for (i = 0; i < ha->max_qpairs; i++) { if (ha->queue_pair_map[i]) { ha->queue_pair_map[i]->fwres.iocbs_total = @@ -3951,6 +3960,10 @@ void qla_init_iocb_limit(scsi_qla_host_t *vha) ha->queue_pair_map[i]->fwres.iocbs_qp_limit = limit / num_qps; ha->queue_pair_map[i]->fwres.iocbs_used = 0; + ha->queue_pair_map[i]->fwres.exch_total = ha->orig_fw_xcb_count; + ha->queue_pair_map[i]->fwres.exch_limit = + (ha->orig_fw_xcb_count * QLA_IOCB_PCT_LIMIT) / 100; + ha->queue_pair_map[i]->fwres.exch_used = 0; } } } diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 5185dc5daf80..2d5a275d8b00 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -380,13 +380,16 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha) enum { RESOURCE_NONE, - RESOURCE_INI, + RESOURCE_IOCB = BIT_0, + RESOURCE_EXCH = BIT_1, /* exchange */ + RESOURCE_FORCE = BIT_2, }; static inline int -qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores) +qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) { u16 iocbs_used, i; + u16 exch_used; struct qla_hw_data *ha = qp->vha->hw; if (!ql2xenforce_iocb_limit) { @@ -394,10 +397,7 @@ qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores) return 0; } - if ((iores->iocb_cnt + qp->fwres.iocbs_used) < qp->fwres.iocbs_qp_limit) { - qp->fwres.iocbs_used += iores->iocb_cnt; - return 0; - } else { + if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) { /* no need to acquire qpair lock. It's just rough calculation */ iocbs_used = ha->base_qpair->fwres.iocbs_used; for (i = 0; i < ha->max_qpairs; i++) { @@ -405,30 +405,48 @@ qla_get_iocbs(struct qla_qpair *qp, struct iocb_resource *iores) iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used; } - if ((iores->iocb_cnt + iocbs_used) < qp->fwres.iocbs_limit) { - qp->fwres.iocbs_used += iores->iocb_cnt; - return 0; - } else { + if ((iores->iocb_cnt + iocbs_used) >= qp->fwres.iocbs_limit) { iores->res_type = RESOURCE_NONE; return -ENOSPC; } } + + if (iores->res_type & RESOURCE_EXCH) { + exch_used = ha->base_qpair->fwres.exch_used; + for (i = 0; i < ha->max_qpairs; i++) { + if (ha->queue_pair_map[i]) + exch_used += ha->queue_pair_map[i]->fwres.exch_used; + } + + if ((exch_used + iores->exch_cnt) >= qp->fwres.exch_limit) { + iores->res_type = RESOURCE_NONE; + return -ENOSPC; + } + } + qp->fwres.iocbs_used += iores->iocb_cnt; + qp->fwres.exch_used += iores->exch_cnt; + return 0; } static inline void -qla_put_iocbs(struct qla_qpair *qp, struct iocb_resource *iores) +qla_put_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) { - switch (iores->res_type) { - case RESOURCE_NONE: - break; - default: + if (iores->res_type & RESOURCE_IOCB) { if (qp->fwres.iocbs_used >= iores->iocb_cnt) { qp->fwres.iocbs_used -= iores->iocb_cnt; } else { - // should not happen + /* should not happen */ qp->fwres.iocbs_used = 0; } - break; + } + + if (iores->res_type & RESOURCE_EXCH) { + if (qp->fwres.exch_used >= iores->exch_cnt) { + qp->fwres.exch_used -= iores->exch_cnt; + } else { + /* should not happen */ + qp->fwres.exch_used = 0; + } } iores->res_type = RESOURCE_NONE; } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 42ce4e1fe744..399ec8da2d73 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -1589,9 +1589,10 @@ qla24xx_start_scsi(srb_t *sp) tot_dsds = nseg; req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - sp->iores.res_type = RESOURCE_INI; + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; sp->iores.iocb_cnt = req_cnt; - if (qla_get_iocbs(sp->qpair, &sp->iores)) + if (qla_get_fw_resources(sp->qpair, &sp->iores)) goto queuing_error; if (req->cnt < (req_cnt + 2)) { @@ -1678,7 +1679,7 @@ qla24xx_start_scsi(srb_t *sp) if (tot_dsds) scsi_dma_unmap(cmd); - qla_put_iocbs(sp->qpair, &sp->iores); + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_FUNCTION_FAILED; @@ -1793,9 +1794,10 @@ qla24xx_dif_start_scsi(srb_t *sp) tot_prot_dsds = nseg; tot_dsds += nseg; - sp->iores.res_type = RESOURCE_INI; + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - if (qla_get_iocbs(sp->qpair, &sp->iores)) + if (qla_get_fw_resources(sp->qpair, &sp->iores)) goto queuing_error; if (req->cnt < (req_cnt + 2)) { @@ -1883,7 +1885,7 @@ qla24xx_dif_start_scsi(srb_t *sp) } /* Cleanup will be performed by the caller (queuecommand) */ - qla_put_iocbs(sp->qpair, &sp->iores); + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(&ha->hardware_lock, flags); return QLA_FUNCTION_FAILED; @@ -1952,9 +1954,10 @@ qla2xxx_start_scsi_mq(srb_t *sp) tot_dsds = nseg; req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - sp->iores.res_type = RESOURCE_INI; + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; sp->iores.iocb_cnt = req_cnt; - if (qla_get_iocbs(sp->qpair, &sp->iores)) + if (qla_get_fw_resources(sp->qpair, &sp->iores)) goto queuing_error; if (req->cnt < (req_cnt + 2)) { @@ -2041,7 +2044,7 @@ qla2xxx_start_scsi_mq(srb_t *sp) if (tot_dsds) scsi_dma_unmap(cmd); - qla_put_iocbs(sp->qpair, &sp->iores); + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_FUNCTION_FAILED; @@ -2171,9 +2174,10 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) tot_prot_dsds = nseg; tot_dsds += nseg; - sp->iores.res_type = RESOURCE_INI; + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; sp->iores.iocb_cnt = qla24xx_calc_iocbs(vha, tot_dsds); - if (qla_get_iocbs(sp->qpair, &sp->iores)) + if (qla_get_fw_resources(sp->qpair, &sp->iores)) goto queuing_error; if (req->cnt < (req_cnt + 2)) { @@ -2260,7 +2264,7 @@ qla2xxx_dif_start_scsi_mq(srb_t *sp) } /* Cleanup will be performed by the caller (queuecommand) */ - qla_put_iocbs(sp->qpair, &sp->iores); + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(&qpair->qp_lock, flags); return QLA_FUNCTION_FAILED; diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index e19fde304e5c..42d3d2de3d31 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3197,7 +3197,7 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) } return; } - qla_put_iocbs(sp->qpair, &sp->iores); + qla_put_fw_resources(sp->qpair, &sp->iores); if (sp->cmd_type != TYPE_SRB) { req->outstanding_cmds[handle] = NULL; @@ -3618,7 +3618,6 @@ qla2x00_error_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, sts_entry_t *pkt) default: sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (sp) { - qla_put_iocbs(sp->qpair, &sp->iores); sp->done(sp, res); return 0; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index 8927ddc5e69c..c57e02a35521 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -428,13 +428,24 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) goto queuing_error; } req_cnt = qla24xx_calc_iocbs(vha, tot_dsds); + + sp->iores.res_type = RESOURCE_IOCB | RESOURCE_EXCH; + sp->iores.exch_cnt = 1; + sp->iores.iocb_cnt = req_cnt; + if (qla_get_fw_resources(sp->qpair, &sp->iores)) { + rval = -EBUSY; + goto queuing_error; + } + if (req->cnt < (req_cnt + 2)) { if (IS_SHADOW_REG_CAPABLE(ha)) { cnt = *req->out_ptr; } else { cnt = rd_reg_dword_relaxed(req->req_q_out); - if (qla2x00_check_reg16_for_disconnect(vha, cnt)) + if (qla2x00_check_reg16_for_disconnect(vha, cnt)) { + rval = -EBUSY; goto queuing_error; + } } if (req->ring_index < cnt) @@ -583,6 +594,8 @@ static inline int qla2x00_start_nvme_mq(srb_t *sp) qla24xx_process_response_queue(vha, rsp); queuing_error: + if (rval) + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(&qpair->qp_lock, flags); return rval; From 5f63a163ed2f12c34dd4ae9b2757962ec7bb86e5 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:42 -0800 Subject: [PATCH 05/11] scsi: qla2xxx: Fix exchange oversubscription for management commands Add resource checking for management (non-I/O) commands. Fixes: 89c72f4245a8 ("scsi: qla2xxx: Add IOCB resource tracking") Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_dfs.c | 10 ++++- drivers/scsi/qla2xxx/qla_inline.h | 5 ++- drivers/scsi/qla2xxx/qla_iocb.c | 67 +++++++++++++++++++++++++++++++ drivers/scsi/qla2xxx/qla_isr.c | 1 + 4 files changed, 80 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c index 777808af5634..1925cc6897b6 100644 --- a/drivers/scsi/qla2xxx/qla_dfs.c +++ b/drivers/scsi/qla2xxx/qla_dfs.c @@ -235,7 +235,7 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) uint16_t mb[MAX_IOCB_MB_REG]; int rc; struct qla_hw_data *ha = vha->hw; - u16 iocbs_used, i; + u16 iocbs_used, i, exch_used; rc = qla24xx_res_count_wait(vha, mb, SIZEOF_IOCB_MB_REG); if (rc != QLA_SUCCESS) { @@ -263,13 +263,19 @@ qla_dfs_fw_resource_cnt_show(struct seq_file *s, void *unused) if (ql2xenforce_iocb_limit) { /* lock is not require. It's an estimate. */ iocbs_used = ha->base_qpair->fwres.iocbs_used; + exch_used = ha->base_qpair->fwres.exch_used; for (i = 0; i < ha->max_qpairs; i++) { - if (ha->queue_pair_map[i]) + if (ha->queue_pair_map[i]) { iocbs_used += ha->queue_pair_map[i]->fwres.iocbs_used; + exch_used += ha->queue_pair_map[i]->fwres.exch_used; + } } seq_printf(s, "Driver: estimate iocb used [%d] high water limit [%d]\n", iocbs_used, ha->base_qpair->fwres.iocbs_limit); + + seq_printf(s, "estimate exchange used[%d] high water limit [%d] n", + exch_used, ha->base_qpair->fwres.exch_limit); } return 0; diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index 2d5a275d8b00..b0ee307b5d4b 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -380,7 +380,7 @@ qla2xxx_get_fc4_priority(struct scsi_qla_host *vha) enum { RESOURCE_NONE, - RESOURCE_IOCB = BIT_0, + RESOURCE_IOCB = BIT_0, RESOURCE_EXCH = BIT_1, /* exchange */ RESOURCE_FORCE = BIT_2, }; @@ -396,6 +396,8 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) iores->res_type = RESOURCE_NONE; return 0; } + if (iores->res_type & RESOURCE_FORCE) + goto force; if ((iores->iocb_cnt + qp->fwres.iocbs_used) >= qp->fwres.iocbs_qp_limit) { /* no need to acquire qpair lock. It's just rough calculation */ @@ -423,6 +425,7 @@ qla_get_fw_resources(struct qla_qpair *qp, struct iocb_resource *iores) return -ENOSPC; } } +force: qp->fwres.iocbs_used += iores->iocb_cnt; qp->fwres.exch_used += iores->exch_cnt; return 0; diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 399ec8da2d73..4f48f098ea5a 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3817,6 +3817,65 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->vp_index = sp->fcport->vha->vp_idx; } +int qla_get_iocbs_resource(struct srb *sp) +{ + bool get_exch; + bool push_it_through = false; + + if (!ql2xenforce_iocb_limit) { + sp->iores.res_type = RESOURCE_NONE; + return 0; + } + sp->iores.res_type = RESOURCE_NONE; + + switch (sp->type) { + case SRB_TM_CMD: + case SRB_PRLI_CMD: + case SRB_ADISC_CMD: + push_it_through = true; + fallthrough; + case SRB_LOGIN_CMD: + case SRB_ELS_CMD_RPT: + case SRB_ELS_CMD_HST: + case SRB_ELS_CMD_HST_NOLOGIN: + case SRB_CT_CMD: + case SRB_NVME_LS: + case SRB_ELS_DCMD: + get_exch = true; + break; + + case SRB_FXIOCB_DCMD: + case SRB_FXIOCB_BCMD: + sp->iores.res_type = RESOURCE_NONE; + return 0; + + case SRB_SA_UPDATE: + case SRB_SA_REPLACE: + case SRB_MB_IOCB: + case SRB_ABT_CMD: + case SRB_NACK_PLOGI: + case SRB_NACK_PRLI: + case SRB_NACK_LOGO: + case SRB_LOGOUT_CMD: + case SRB_CTRL_VP: + push_it_through = true; + fallthrough; + default: + get_exch = false; + } + + sp->iores.res_type |= RESOURCE_IOCB; + sp->iores.iocb_cnt = 1; + if (get_exch) { + sp->iores.res_type |= RESOURCE_EXCH; + sp->iores.exch_cnt = 1; + } + if (push_it_through) + sp->iores.res_type |= RESOURCE_FORCE; + + return qla_get_fw_resources(sp->qpair, &sp->iores); +} + int qla2x00_start_sp(srb_t *sp) { @@ -3831,6 +3890,12 @@ qla2x00_start_sp(srb_t *sp) return -EIO; spin_lock_irqsave(qp->qp_lock_ptr, flags); + rval = qla_get_iocbs_resource(sp); + if (rval) { + spin_unlock_irqrestore(qp->qp_lock_ptr, flags); + return -EAGAIN; + } + pkt = __qla2x00_alloc_iocbs(sp->qpair, sp); if (!pkt) { rval = EAGAIN; @@ -3931,6 +3996,8 @@ qla2x00_start_sp(srb_t *sp) wmb(); qla2x00_start_iocbs(vha, qp->req); done: + if (rval) + qla_put_fw_resources(sp->qpair, &sp->iores); spin_unlock_irqrestore(qp->qp_lock_ptr, flags); return rval; } diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 42d3d2de3d31..759bea69de12 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3112,6 +3112,7 @@ qla25xx_process_bidir_status_iocb(scsi_qla_host_t *vha, void *pkt, } bsg_reply->reply_payload_rcv_len = 0; + qla_put_fw_resources(sp->qpair, &sp->iores); done: /* Return the vendor specific reply to API */ bsg_reply->reply_data.vendor_reply.vendor_rsp[0] = rval; From 40f5b1b9a4af2917f97bd98f277baebad8cde323 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:43 -0800 Subject: [PATCH 06/11] scsi: qla2xxx: Fix stalled login If a login failed due to low FW resources, the session can stall and will not be connected. Reset session state to allow relogin logic to redrive the connection. Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_init.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index fd27fb511479..745fee298d56 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -390,6 +390,12 @@ qla2x00_async_login(struct scsi_qla_host *vha, fc_port_t *fcport, fcport->flags &= ~FCF_ASYNC_SENT; done: fcport->flags &= ~FCF_ASYNC_ACTIVE; + + /* + * async login failed. Could be due to iocb/exchange resource + * being low. Set state DELETED for re-login process to start again. + */ + qla2x00_set_fcport_disc_state(fcport, DSC_DELETED); return rval; } From 7e8a936a2d0f98dd6e5d05d4838affabe606cabc Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:44 -0800 Subject: [PATCH 07/11] scsi: qla2xxx: Remove unintended flag clearing FCF_ASYNC_SENT flag is used in session management. This flag is cleared in task management path by accident. Remove unintended flag clearing. Fixes: 388a49959ee4 ("scsi: qla2xxx: Fix panic from use after free in qla2x00_async_tm_cmd") Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani 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 745fee298d56..6968e8d08968 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -2082,7 +2082,6 @@ qla2x00_async_tm_cmd(fc_port_t *fcport, uint32_t flags, uint32_t lun, done_free_sp: /* ref: INIT */ kref_put(&sp->cmd_kref, qla2x00_sp_release); - fcport->flags &= ~FCF_ASYNC_SENT; done: return rval; } From 3fbc74feb642deb688cc97f76d40b7287ddd4cb1 Mon Sep 17 00:00:00 2001 From: Quinn Tran Date: Mon, 19 Dec 2022 03:07:45 -0800 Subject: [PATCH 08/11] scsi: qla2xxx: Fix erroneous link down If after an adapter reset the appearance of link is not recovered, the devices are not rediscovered. This is result of a race condition between adapter reset (abort_isp) and the topology scan. During adapter reset, the ABORT_ISP_ACTIVE flag is set. Topology scan usually occurred after adapter reset. In this case, the topology scan came earlier than usual where it ran into problem due to ABORT_ISP_ACTIVE flag was still set. kernel: qla2xxx [0000:13:00.0]-1005:1: Cmd 0x6a aborted with timeout since ISP Abort is pending kernel: qla2xxx [0000:13:00.0]-28a0:1: MBX_GET_PORT_NAME failed, No FL Port. kernel: qla2xxx [0000:13:00.0]-286b:1: qla2x00_configure_loop: exiting normally. local port wwpn 51402ec0123d9a80 id 012300) kernel: qla2xxx [0000:13:00.0]-8017:1: ADAPTER RESET SUCCEEDED nexus=1:0:15. Allow adapter reset to complete before any scan can start. Cc: stable@vger.kernel.org Signed-off-by: Quinn Tran Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_os.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 36d3cecab20e..2d86f804872b 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -7094,9 +7094,12 @@ qla2x00_do_dpc(void *data) } } loop_resync_check: - if (test_and_clear_bit(LOOP_RESYNC_NEEDED, + if (!qla2x00_reset_active(base_vha) && + test_and_clear_bit(LOOP_RESYNC_NEEDED, &base_vha->dpc_flags)) { - + /* + * Allow abort_isp to complete before moving on to scanning. + */ ql_dbg(ql_dbg_dpc, base_vha, 0x400f, "Loop resync scheduled.\n"); From d676a9e3d9efb7e93df460bcf4c445496c16314f Mon Sep 17 00:00:00 2001 From: Saurav Kashyap Date: Mon, 19 Dec 2022 03:07:46 -0800 Subject: [PATCH 09/11] scsi: qla2xxx: Remove increment of interface err cnt Residual underrun is not an interface error, hence no need to increment that count. Fixes: dbf1f53cfd23 ("scsi: qla2xxx: Implementation to get and manage host, target stats and initiator port") Cc: stable@vger.kernel.org Signed-off-by: Saurav Kashyap Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_isr.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index 759bea69de12..cbbd7014da93 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -3363,8 +3363,6 @@ qla2x00_status_entry(scsi_qla_host_t *vha, struct rsp_que *rsp, void *pkt) "Dropped frame(s) detected (0x%x of 0x%x bytes).\n", resid, scsi_bufflen(cp)); - vha->interface_err_cnt++; - res = DID_ERROR << 16 | lscsi_status; goto check_scsi_status; } From 1e27648c848235046cfd83e656c1c0d360861f25 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Mon, 19 Dec 2022 03:07:47 -0800 Subject: [PATCH 10/11] scsi: qla2xxx: Fix IOCB resource check warning Make qla_get_iocbs_resource() static to fix the warning: >> drivers/scsi/qla2xxx/qla_iocb.c:3820:5: warning: no previous prototype for >> 'qla_get_iocbs_resource' [-Wmissing-prototypes] 3820 | int qla_get_iocbs_resource(struct srb *sp) | ^~~~~~~~~~~~~~~~~~~~~~ Reported-by: kernel test robot Signed-off-by: Nilesh Javali Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_iocb.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 4f48f098ea5a..6b91dcfd994d 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -3817,7 +3817,7 @@ qla24xx_prlo_iocb(srb_t *sp, struct logio_entry_24xx *logio) logio->vp_index = sp->fcport->vha->vp_idx; } -int qla_get_iocbs_resource(struct srb *sp) +static int qla_get_iocbs_resource(struct srb *sp) { bool get_exch; bool push_it_through = false; From f590c2554c7764a91e83f29347a1e27c4d9f1335 Mon Sep 17 00:00:00 2001 From: Nilesh Javali Date: Mon, 19 Dec 2022 03:07:48 -0800 Subject: [PATCH 11/11] scsi: qla2xxx: Update version to 10.02.08.100-k Signed-off-by: Nilesh Javali Reviewed-by: Himanshu Madhani Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_version.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_version.h b/drivers/scsi/qla2xxx/qla_version.h index 03f3e2cd62b5..9f55f75c5890 100644 --- a/drivers/scsi/qla2xxx/qla_version.h +++ b/drivers/scsi/qla2xxx/qla_version.h @@ -6,9 +6,9 @@ /* * Driver version */ -#define QLA2XXX_VERSION "10.02.07.900-k" +#define QLA2XXX_VERSION "10.02.08.100-k" #define QLA_DRIVER_MAJOR_VER 10 #define QLA_DRIVER_MINOR_VER 2 -#define QLA_DRIVER_PATCH_VER 7 -#define QLA_DRIVER_BETA_VER 900 +#define QLA_DRIVER_PATCH_VER 8 +#define QLA_DRIVER_BETA_VER 100