From: Quinn Tran <quinn.tran@xxxxxxxxxx> This patch fixes regression introduced for the N2N support for FC-NVMe. For FC-NVMe with N2N connection, instead of FW initiating the Login, Driver starts Login process. This patch migrate that new process from a standalone path into existing session management state machine. With this state change now driver will not wait for pull NPort ID from FW. Fixes: edd05de197592 ("scsi: qla2xxx: Changes to support N2N logins") Signed-off-by: Quinn Tran <quinn.tran@xxxxxxxxxx> Signed-off-by: Himanshu Madhani <himanshu.madhani@xxxxxxxxxx> --- drivers/scsi/qla2xxx/qla_def.h | 12 +- drivers/scsi/qla2xxx/qla_fw.h | 5 + drivers/scsi/qla2xxx/qla_gbl.h | 3 +- drivers/scsi/qla2xxx/qla_gs.c | 47 +++++--- drivers/scsi/qla2xxx/qla_init.c | 229 ++++++++++++++++++++++++++++++------- drivers/scsi/qla2xxx/qla_inline.h | 2 - drivers/scsi/qla2xxx/qla_iocb.c | 112 +++++++++++++----- drivers/scsi/qla2xxx/qla_mbx.c | 77 ++++++++++--- drivers/scsi/qla2xxx/qla_nvme.c | 15 ++- drivers/scsi/qla2xxx/qla_nvme.h | 2 +- drivers/scsi/qla2xxx/qla_os.c | 32 ++++-- drivers/scsi/qla2xxx/tcm_qla2xxx.c | 3 - 12 files changed, 413 insertions(+), 126 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index d1ff1b8f1ae5..a03e12797f30 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -398,6 +398,8 @@ struct srb_iocb { struct completion comp; struct els_plogi_payload *els_plogi_pyld; struct els_plogi_payload *els_resp_pyld; + u32 tx_size; + u32 rx_size; dma_addr_t els_plogi_pyld_dma; dma_addr_t els_resp_pyld_dma; uint32_t fw_status[3]; @@ -2312,6 +2314,7 @@ enum fcport_mgt_event { FCME_ADISC_DONE, FCME_GNNID_DONE, FCME_GFPNID_DONE, + FCME_ELS_PLOGI_DONE, }; enum rscn_addr_format { @@ -2408,6 +2411,7 @@ typedef struct fc_port { struct ct_sns_desc ct_desc; enum discovery_state disc_state; enum login_state fw_login_state; + unsigned long dm_login_expire; unsigned long plogi_nack_done_deadline; u32 login_gen, last_login_gen; @@ -2418,7 +2422,8 @@ typedef struct fc_port { u8 iocb[IOCB_SIZE]; u8 current_login_state; u8 last_login_state; - struct completion n2n_done; + u16 n2n_link_reset_cnt; + u16 n2n_chip_reset; } fc_port_t; #define QLA_FCPORT_SCAN 1 @@ -3228,6 +3233,7 @@ enum qla_work_type { QLA_EVT_GFPNID, QLA_EVT_SP_RETRY, QLA_EVT_IIDMA, + QLA_EVT_ELS_PLOGI, }; @@ -3600,6 +3606,7 @@ struct qla_hw_data { uint32_t using_lr_setting:1; uint32_t rida_fmt2:1; uint32_t purge_mbox:1; + uint32_t n2n_bigger:1; } flags; uint16_t max_exchg; @@ -3908,6 +3915,9 @@ struct qla_hw_data { int exchoffld_size; int exchoffld_count; + /* n2n */ + struct els_plogi_payload plogi_els_payld; + void *swl; /* These are used by mailbox operations. */ diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index 5d8688e5bc7c..50c1e6c62e31 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -1366,6 +1366,11 @@ struct vp_rpt_id_entry_24xx { /* format 1 fabric */ uint8_t vpstat1_subcode; /* vp_status=1 subcode */ uint8_t flags; +#define TOPO_MASK 0xE +#define TOPO_FL 0x2 +#define TOPO_N2N 0x4 +#define TOPO_F 0x6 + uint16_t fip_flags; uint8_t rsv2[12]; diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 6f2a37220a55..035ab18bd534 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -45,8 +45,7 @@ extern int qla2x00_fabric_login(scsi_qla_host_t *, fc_port_t *, uint16_t *); extern int qla2x00_local_device_login(scsi_qla_host_t *, fc_port_t *); extern int qla24xx_els_dcmd_iocb(scsi_qla_host_t *, int, port_id_t); -extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *, - port_id_t); +extern int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *, int, fc_port_t *, bool); extern void qla2x00_update_fcports(scsi_qla_host_t *); diff --git a/drivers/scsi/qla2xxx/qla_gs.c b/drivers/scsi/qla2xxx/qla_gs.c index af9a75df6700..3a93a9389a49 100644 --- a/drivers/scsi/qla2xxx/qla_gs.c +++ b/drivers/scsi/qla2xxx/qla_gs.c @@ -3384,19 +3384,40 @@ int qla24xx_post_gpnid_work(struct scsi_qla_host *vha, port_id_t *id) void qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp) { - if (sp->u.iocb_cmd.u.ctarg.req) { - dma_free_coherent(&vha->hw->pdev->dev, - sizeof(struct ct_sns_pkt), - sp->u.iocb_cmd.u.ctarg.req, - sp->u.iocb_cmd.u.ctarg.req_dma); - sp->u.iocb_cmd.u.ctarg.req = NULL; - } - if (sp->u.iocb_cmd.u.ctarg.rsp) { - dma_free_coherent(&vha->hw->pdev->dev, - sizeof(struct ct_sns_pkt), - sp->u.iocb_cmd.u.ctarg.rsp, - sp->u.iocb_cmd.u.ctarg.rsp_dma); - sp->u.iocb_cmd.u.ctarg.rsp = NULL; + struct srb_iocb *c = &sp->u.iocb_cmd; + + switch (sp->type) { + case SRB_ELS_DCMD: + if (c->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&vha->hw->pdev->dev, + c->u.els_plogi.tx_size, + c->u.els_plogi.els_plogi_pyld, + c->u.els_plogi.els_plogi_pyld_dma); + + if (c->u.els_plogi.els_resp_pyld) + dma_free_coherent(&vha->hw->pdev->dev, + c->u.els_plogi.rx_size, + c->u.els_plogi.els_resp_pyld, + c->u.els_plogi.els_resp_pyld_dma); + break; + case SRB_CT_PTHRU_CMD: + default: + if (sp->u.iocb_cmd.u.ctarg.req) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.req, + sp->u.iocb_cmd.u.ctarg.req_dma); + sp->u.iocb_cmd.u.ctarg.req = NULL; + } + + if (sp->u.iocb_cmd.u.ctarg.rsp) { + dma_free_coherent(&vha->hw->pdev->dev, + sizeof(struct ct_sns_pkt), + sp->u.iocb_cmd.u.ctarg.rsp, + sp->u.iocb_cmd.u.ctarg.rsp_dma); + sp->u.iocb_cmd.u.ctarg.rsp = NULL; + } + break; } sp->free(sp); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 471322c29db6..f52c68b4da44 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -419,6 +419,19 @@ void qla24xx_handle_adisc_event(scsi_qla_host_t *vha, struct event_arg *ea) __qla24xx_handle_gpdb_event(vha, ea); } +int qla_post_els_plogi_work(struct scsi_qla_host *vha, fc_port_t *fcport) +{ + struct qla_work_evt *e; + + e = qla2x00_alloc_work(vha, QLA_EVT_ELS_PLOGI); + if (!e) + return QLA_FUNCTION_FAILED; + + e->u.fcport.fcport = fcport; + fcport->flags |= FCF_ASYNC_ACTIVE; + return qla2x00_post_work(vha, e); +} + static void qla2x00_async_adisc_sp_done(void *ptr, int res) { @@ -467,6 +480,8 @@ qla2x00_async_adisc(struct scsi_qla_host *vha, fc_port_t *fcport, lio = &sp->u.iocb_cmd; lio->timeout = qla2x00_async_iocb_timeout; + sp->gen1 = fcport->rscn_gen; + sp->gen2 = fcport->login_gen; qla2x00_init_timer(sp, qla2x00_get_async_timeout(vha) + 2); sp->done = qla2x00_async_adisc_sp_done; @@ -560,12 +575,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) + 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 [%d|%d] ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", + "%s found %8phC CLS [%x|%x] nvme %d ID[%02x%02x%02x|%02x%02x%02x] lid[%d|%d]\n", __func__, fcport->port_name, e->current_login_state, fcport->fw_login_state, - id.b.domain, id.b.area, id.b.al_pa, + 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); @@ -574,9 +594,13 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, case DSC_DELETED: break; default: - if ((id.b24 != fcport->d_id.b24) || - ((fcport->loop_id != FC_NO_LOOP_ID) && - (fcport->loop_id != loop_id))) { + if ((id.b24 != fcport->d_id.b24 && + fcport->d_id.b24) || + (fcport->loop_id != FC_NO_LOOP_ID && + fcport->loop_id != loop_id)) { + ql_dbg(ql_dbg_disc, vha, 0x20e3, + "%s %d %8phC post del sess\n", + __func__, __LINE__, fcport->port_name); qlt_schedule_sess_for_deletion(fcport); return; } @@ -599,11 +623,6 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, fcport->login_pause = 1; } - if (fcport->fc4f_nvme) - current_login_state = e->current_login_state >> 4; - else - current_login_state = e->current_login_state & 0xf; - switch (vha->hw->current_topology) { default: switch (current_login_state) { @@ -632,6 +651,8 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, } break; case ISP_CFG_N: + fcport->fw_login_state = current_login_state; + fcport->d_id = id; switch (current_login_state) { case DSC_LS_PRLI_COMP: if ((e->prli_svc_param_word_3[0] & BIT_4) == 0) @@ -705,12 +726,39 @@ static void qla24xx_handle_gnl_done_event(scsi_qla_host_t *vha, qla24xx_fcport_handle_login(vha, fcport); break; case ISP_CFG_N: - /* - * FW handles the initial login for n2n. - * Do link reinit to trigger this auto login. - */ - set_bit(N2N_LINK_RESET, &vha->dpc_flags); - qla2xxx_wake_dpc(vha); + fcport->disc_state = DSC_DELETED; + if (time_after_eq(jiffies, fcport->dm_login_expire)) { + if (fcport->n2n_link_reset_cnt < 2) { + 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 { + if (fcport->n2n_chip_reset < 1) { + ql_log(ql_log_info, vha, 0x705d, + "Chip reset to bring laser down"); + set_bit(ISP_ABORT_NEEDED, + &vha->dpc_flags); + fcport->n2n_chip_reset++; + } else { + ql_log(ql_log_info, vha, 0x705d, + "Remote port %8ph is not coming back\n", + fcport->port_name); + fcport->scan_state = 0; + } + } + qla2xxx_wake_dpc(vha); + } else { + /* + * report port suppose to do PLOGI. Give him + * more time. FW will catch it. + */ + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } break; default: break; @@ -1020,9 +1068,9 @@ qla24xx_async_prli(struct scsi_qla_host *vha, fc_port_t *fcport) } ql_dbg(ql_dbg_disc, vha, 0x211b, - "Async-prli - %8phC hdl=%x, loopid=%x portid=%06x retries=%d.\n", - fcport->port_name, sp->handle, fcport->loop_id, - fcport->d_id.b24, fcport->login_retry); + "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"); return rval; @@ -1164,8 +1212,9 @@ 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 rc %d\n", __func__, fcport->port_name, - fcport->disc_state, pd->current_login_state, ea->rc); + "%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); if (fcport->disc_state == DSC_DELETE_PEND) return; @@ -1286,36 +1335,76 @@ int qla24xx_fcport_handle_login(struct scsi_qla_host *vha, fc_port_t *fcport) return 0; } - switch (fcport->disc_state) { case DSC_DELETED: - fcport->login_retry--; wwn = wwn_to_u64(fcport->node_name); - if (wwn == 0) { - ql_dbg(ql_dbg_disc, vha, 0xffff, - "%s %d %8phC post GNNID\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gnnid_work(vha, fcport); - } else if (fcport->loop_id == FC_NO_LOOP_ID) { - ql_dbg(ql_dbg_disc, vha, 0x20bd, - "%s %d %8phC post gnl\n", - __func__, __LINE__, fcport->port_name); - qla24xx_post_gnl_work(vha, fcport); - } else { - fcport->login_retry--; - qla_chk_n2n_b4_login(vha, fcport); + switch (vha->hw->current_topology) { + case ISP_CFG_N: + if (fcport_is_smaller(fcport)) { + /* this adapter is bigger */ + if (fcport->login_retry) { + if (fcport->loop_id == FC_NO_LOOP_ID) { + qla2x00_find_new_loop_id(vha, + fcport); + fcport->fw_login_state = + DSC_LS_PORT_UNAVAIL; + } + fcport->login_retry--; + qla_post_els_plogi_work(vha, fcport); + } else { + ql_log(ql_log_info, vha, 0x705d, + "Unable to reach remote port %8phC", + fcport->port_name); + } + } else { + qla24xx_post_gnl_work(vha, fcport); + } + break; + default: + if (wwn == 0) { + ql_dbg(ql_dbg_disc, vha, 0xffff, + "%s %d %8phC post GNNID\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gnnid_work(vha, fcport); + } else if (fcport->loop_id == FC_NO_LOOP_ID) { + ql_dbg(ql_dbg_disc, vha, 0x20bd, + "%s %d %8phC post gnl\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_gnl_work(vha, fcport); + } else { + qla_chk_n2n_b4_login(vha, fcport); + } + break; } break; case DSC_GNL: - if (fcport->login_pause) { - fcport->last_rscn_gen = fcport->rscn_gen; - fcport->last_login_gen = fcport->login_gen; - set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + switch (vha->hw->current_topology) { + case ISP_CFG_N: + if ((fcport->current_login_state & 0xf) == 0x6) { + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post GPDB work\n", + __func__, __LINE__, fcport->port_name); + fcport->chip_reset = + vha->hw->base_qpair->chip_reset; + qla24xx_post_gpdb_work(vha, fcport, 0); + } else { + ql_dbg(ql_dbg_disc, vha, 0x2118, + "%s %d %8phC post NVMe PRLI\n", + __func__, __LINE__, fcport->port_name); + qla24xx_post_prli_work(vha, fcport); + } + break; + default: + if (fcport->login_pause) { + fcport->last_rscn_gen = fcport->rscn_gen; + fcport->last_login_gen = fcport->login_gen; + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + break; + } + qla_chk_n2n_b4_login(vha, fcport); break; } - - qla_chk_n2n_b4_login(vha, fcport); break; case DSC_LOGIN_FAILED: @@ -1429,6 +1518,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); +} + void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) { fc_port_t *f, *tf; @@ -1530,6 +1628,9 @@ void qla2x00_fcport_event_handler(scsi_qla_host_t *vha, struct event_arg *ea) case FCME_GFPNID_DONE: qla24xx_handle_gfpnid_event(vha, ea); break; + case FCME_ELS_PLOGI_DONE: + qla_handle_els_plogi_done(vha, ea); + break; default: BUG_ON(1); break; @@ -4160,7 +4261,8 @@ qla2x00_configure_hba(scsi_qla_host_t *vha) id.b.al_pa = al_pa; id.b.rsvd_1 = 0; spin_lock_irqsave(&ha->hardware_lock, flags); - qlt_update_host_map(vha, id); + if (!(topo == 2 && ha->flags.n2n_bigger)) + qlt_update_host_map(vha, id); spin_unlock_irqrestore(&ha->hardware_lock, flags); if (!vha->flags.init_done) @@ -4813,6 +4915,31 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) struct qla_hw_data *ha = vha->hw; unsigned long flags; + /* Inititae N2N login. */ + if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { + /* borrowing */ + u32 *bp, i, sz; + + memset(ha->init_cb, 0, ha->init_cb_size); + sz = min_t(int, sizeof(struct els_plogi_payload), + ha->init_cb_size); + rval = qla24xx_get_port_login_templ(vha, ha->init_cb_dma, + (void *)ha->init_cb, sz); + if (rval == QLA_SUCCESS) { + bp = (uint32_t *)ha->init_cb; + for (i = 0; i < sz/4 ; i++, bp++) + *bp = cpu_to_be32(*bp); + + memcpy(&ha->plogi_els_payld.data, (void *)ha->init_cb, + sizeof(ha->plogi_els_payld.data)); + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } else { + ql_dbg(ql_dbg_init, vha, 0x00d1, + "PLOGI ELS param read fail.\n"); + } + return QLA_SUCCESS; + } + found_devs = 0; new_fcport = NULL; entries = MAX_FIBRE_DEVICES_LOOP; @@ -5105,9 +5232,19 @@ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport) fcport->deleted = 0; fcport->logout_on_delete = 1; fcport->login_retry = vha->hw->login_retry_count; + fcport->n2n_chip_reset = fcport->n2n_link_reset_cnt = 0; qla2x00_iidma_fcport(vha, fcport); + switch (vha->hw->current_topology) { + case ISP_CFG_N: + case ISP_CFG_NL: + fcport->keep_nport_handle = 1; + break; + default: + break; + } + if (fcport->fc4f_nvme) { qla_nvme_register_remote(vha, fcport); fcport->disc_state = DSC_LOGIN_COMPLETE; @@ -6992,6 +7129,9 @@ qla24xx_nvram_config(scsi_qla_host_t *vha) if (ql2xloginretrycount) ha->login_retry_count = ql2xloginretrycount; + /* N2N: driver will initiate Login instead of FW */ + icb->firmware_options_3 |= BIT_8; + /* Enable ZIO. */ if (!vha->flags.init_done) { ha->zio_mode = le32_to_cpu(icb->firmware_options_2) & @@ -8076,6 +8216,9 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) /* enable RIDA Format2 */ icb->firmware_options_3 |= BIT_0; + /* N2N: driver will initiate Login instead of FW */ + icb->firmware_options_3 |= BIT_8; + if (IS_QLA27XX(ha)) { icb->firmware_options_3 |= BIT_8; ql_dbg(ql_log_info, vha, 0x0075, diff --git a/drivers/scsi/qla2xxx/qla_inline.h b/drivers/scsi/qla2xxx/qla_inline.h index acf6511e8ef7..a29f8898c687 100644 --- a/drivers/scsi/qla2xxx/qla_inline.h +++ b/drivers/scsi/qla2xxx/qla_inline.h @@ -280,8 +280,6 @@ qla2x00_init_timer(srb_t *sp, unsigned long tmo) init_completion(&sp->comp); if (IS_QLAFX00(sp->vha->hw) && (sp->type == SRB_FXIOCB_DCMD)) init_completion(&sp->u.iocb_cmd.u.fxiocb.fxiocb_comp); - if (sp->type == SRB_ELS_DCMD) - init_completion(&sp->u.iocb_cmd.u.els_logo.comp); add_timer(&sp->u.iocb_cmd.timer); } diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index ba14db8d0b8d..059f2c9dc192 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2465,6 +2465,7 @@ qla24xx_els_dcmd_iocb(scsi_qla_host_t *vha, int els_opcode, sp->fcport = fcport; elsio->timeout = qla2x00_els_dcmd_iocb_timeout; qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); + init_completion(&sp->u.iocb_cmd.u.els_logo.comp); sp->done = qla2x00_els_dcmd_sp_done; sp->free = qla2x00_els_dcmd_sp_free; @@ -2512,7 +2513,6 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { scsi_qla_host_t *vha = sp->vha; struct srb_iocb *elsio = &sp->u.iocb_cmd; - uint32_t dsd_len = 24; els_iocb->entry_type = ELS_IOCB_TYPE; els_iocb->entry_count = 1; @@ -2535,20 +2535,21 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->control_flags = 0; if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { - els_iocb->tx_byte_count = sizeof(struct els_plogi_payload); + els_iocb->tx_byte_count = els_iocb->tx_len = + sizeof(struct els_plogi_payload); els_iocb->tx_address[0] = cpu_to_le32(LSD(elsio->u.els_plogi.els_plogi_pyld_dma)); els_iocb->tx_address[1] = cpu_to_le32(MSD(elsio->u.els_plogi.els_plogi_pyld_dma)); - els_iocb->tx_len = dsd_len; els_iocb->rx_dsd_count = 1; - els_iocb->rx_byte_count = sizeof(struct els_plogi_payload); + els_iocb->rx_byte_count = els_iocb->rx_len = + sizeof(struct els_plogi_payload); els_iocb->rx_address[0] = cpu_to_le32(LSD(elsio->u.els_plogi.els_resp_pyld_dma)); els_iocb->rx_address[1] = cpu_to_le32(MSD(elsio->u.els_plogi.els_resp_pyld_dma)); - els_iocb->rx_len = dsd_len; + ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI ELS IOCB:\n"); ql_dump_buffer(ql_log_info, vha, 0x0109, @@ -2577,7 +2578,6 @@ qla2x00_els_dcmd2_iocb_timeout(void *data) fc_port_t *fcport = sp->fcport; struct scsi_qla_host *vha = sp->vha; struct qla_hw_data *ha = vha->hw; - struct srb_iocb *lio = &sp->u.iocb_cmd; unsigned long flags = 0; int res; @@ -2593,7 +2593,7 @@ qla2x00_els_dcmd2_iocb_timeout(void *data) (res == QLA_SUCCESS) ? "successful" : "failed"); spin_unlock_irqrestore(&ha->hardware_lock, flags); - complete(&lio->u.els_plogi.comp); + sp->done(sp, QLA_FUNCTION_TIMEOUT); } static void @@ -2603,17 +2603,54 @@ qla2x00_els_dcmd2_sp_done(void *ptr, int res) fc_port_t *fcport = sp->fcport; struct srb_iocb *lio = &sp->u.iocb_cmd; struct scsi_qla_host *vha = sp->vha; + struct event_arg ea; + struct qla_work_evt *e; + + ql_dbg(ql_dbg_disc, vha, 0x3072, + "%s ELS done rc %d hdl=%x, portid=%06x %8phC\n", + sp->name, res, sp->handle, fcport->d_id.b24, fcport->port_name); - ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3072, - "%s ELS hdl=%x, portid=%06x done %8phC\n", - sp->name, sp->handle, fcport->d_id.b24, fcport->port_name); + fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE); + del_timer(&sp->u.iocb_cmd.timer); - complete(&lio->u.els_plogi.comp); + if (sp->flags & SRB_WAKEUP_ON_COMP) + complete(&lio->u.els_plogi.comp); + else { + if (res) { + set_bit(RELOGIN_NEEDED, &vha->dpc_flags); + } else { + memset(&ea, 0, sizeof(ea)); + ea.fcport = fcport; + ea.rc = res; + ea.event = FCME_ELS_PLOGI_DONE; + qla2x00_fcport_event_handler(vha, &ea); + } + + e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); + if (!e) { + struct srb_iocb *elsio = &sp->u.iocb_cmd; + + if (elsio->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.tx_size, + elsio->u.els_plogi.els_plogi_pyld, + elsio->u.els_plogi.els_plogi_pyld_dma); + + if (elsio->u.els_plogi.els_resp_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.rx_size, + elsio->u.els_plogi.els_resp_pyld, + elsio->u.els_plogi.els_resp_pyld_dma); + sp->free(sp); + } + e->u.iosb.sp = sp; + qla2x00_post_work(vha, e); + } } int qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, - fc_port_t *fcport, port_id_t remote_did) + fc_port_t *fcport, bool wait) { srb_t *sp; struct srb_iocb *elsio = NULL; @@ -2641,9 +2678,13 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, elsio->timeout = qla2x00_els_dcmd2_iocb_timeout; init_completion(&elsio->u.els_plogi.comp); - qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); + if (wait) + sp->flags = SRB_WAKEUP_ON_COMP; + + qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT + 2); sp->done = qla2x00_els_dcmd2_sp_done; + elsio->u.els_plogi.tx_size = elsio->u.els_plogi.rx_size = DMA_POOL_SIZE; ptr = elsio->u.els_plogi.els_plogi_pyld = dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, @@ -2668,33 +2709,52 @@ qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, memset(ptr, 0, sizeof(struct els_plogi_payload)); memset(resp_ptr, 0, sizeof(struct els_plogi_payload)); + memcpy(elsio->u.els_plogi.els_plogi_pyld->data, + &ha->plogi_els_payld.data, + sizeof(elsio->u.els_plogi.els_plogi_pyld->data)); + elsio->u.els_plogi.els_cmd = els_opcode; elsio->u.els_plogi.els_plogi_pyld->opcode = els_opcode; - qla24xx_get_port_login_templ(vha, ptr_dma + 4, - &elsio->u.els_plogi.els_plogi_pyld->data[0], - sizeof(struct els_plogi_payload)); - ql_dbg(ql_dbg_io + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n"); - ql_dump_buffer(ql_dbg_io + ql_dbg_buffer, vha, 0x0109, + ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x3073, "PLOGI buffer:\n"); + ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x0109, (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 0x70); rval = qla2x00_start_sp(sp); if (rval != QLA_SUCCESS) { rval = QLA_FUNCTION_FAILED; - goto out; + } else { + ql_dbg(ql_dbg_disc, vha, 0x3074, + "%s PLOGI sent, hdl=%x, loopid=%x, to port_id %06x from port_id %06x\n", + sp->name, sp->handle, fcport->loop_id, + fcport->d_id.b24, vha->d_id.b24); } - ql_dbg(ql_dbg_io, vha, 0x3074, - "%s PLOGI sent, hdl=%x, loopid=%x, portid=%06x\n", - sp->name, sp->handle, fcport->loop_id, fcport->d_id.b24); - - wait_for_completion(&elsio->u.els_plogi.comp); + if (wait) { + wait_for_completion(&elsio->u.els_plogi.comp); - if (elsio->u.els_plogi.comp_status != CS_COMPLETE) - rval = QLA_FUNCTION_FAILED; + if (elsio->u.els_plogi.comp_status != CS_COMPLETE) + rval = QLA_FUNCTION_FAILED; + } else { + goto done; + } out: + fcport->flags &= ~(FCF_ASYNC_SENT); + if (elsio->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.tx_size, + elsio->u.els_plogi.els_plogi_pyld, + elsio->u.els_plogi.els_plogi_pyld_dma); + + if (elsio->u.els_plogi.els_resp_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, + elsio->u.els_plogi.rx_size, + elsio->u.els_plogi.els_resp_pyld, + elsio->u.els_plogi.els_resp_pyld_dma); + sp->free(sp); +done: return rval; } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 10847cdca093..7c07a939cf15 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -59,6 +59,7 @@ static struct rom_cmd { { MBC_IOCB_COMMAND_A64 }, { MBC_GET_ADAPTER_LOOP_ID }, { MBC_READ_SFP }, + { MBC_GET_RNID_PARAMS }, }; static int is_rom_cmd(uint16_t cmd) @@ -3842,30 +3843,68 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, "Format 1: WWPN %8phC.\n", vha->port_name); - /* N2N. direct connect */ - if (IS_QLA27XX(ha) && - ((rptid_entry->u.f1.flags>>1) & 0x7) == 2) { - /* if our portname is higher then initiate N2N login */ - if (wwn_to_u64(vha->port_name) > - wwn_to_u64(rptid_entry->u.f1.port_name)) { - // ??? qlt_update_host_map(vha, id); - vha->n2n_id = 0x1; - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: Setting n2n_update_needed for id %d\n", - vha->n2n_id); + switch (rptid_entry->u.f1.flags & TOPO_MASK) { + case TOPO_N2N: + ha->current_topology = ISP_CFG_N; + spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); + fcport = qla2x00_find_fcport_by_wwpn(vha, + rptid_entry->u.f1.port_name, 1); + spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); + + if (fcport) { + fcport->plogi_nack_done_deadline = jiffies + HZ; + fcport->dm_login_expire = jiffies + 3*HZ; + fcport->scan_state = QLA_FCPORT_FOUND; + switch (fcport->disc_state) { + case DSC_DELETED: + set_bit(RELOGIN_NEEDED, + &vha->dpc_flags); + break; + case DSC_DELETE_PEND: + break; + default: + qlt_schedule_sess_for_deletion(fcport); + break; + } } else { - ql_dbg(ql_dbg_async, vha, 0x5075, - "Format 1: Remote login - Waiting for WWPN %8phC.\n", - rptid_entry->u.f1.port_name); + id.b24 = 0; + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(rptid_entry->u.f1.port_name)) { + vha->d_id.b24 = 0; + vha->d_id.b.al_pa = 1; + ha->flags.n2n_bigger = 1; + + id.b.al_pa = 2; + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: assign local id %x remote id %x\n", + vha->d_id.b24, id.b24); + } else { + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: Remote login - Waiting for WWPN %8phC.\n", + rptid_entry->u.f1.port_name); + ha->flags.n2n_bigger = 0; + } + qla24xx_post_newsess_work(vha, &id, + rptid_entry->u.f1.port_name, + rptid_entry->u.f1.node_name, + NULL, + FC4_TYPE_UNKNOWN); } - memcpy(vha->n2n_port_name, rptid_entry->u.f1.port_name, - WWN_SIZE); + /* if our portname is higher then initiate N2N login */ + set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); - set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); - set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); ha->flags.n2n_ae = 1; return; + break; + case TOPO_FL: + ha->current_topology = ISP_CFG_FL; + break; + case TOPO_F: + ha->current_topology = ISP_CFG_F; + break; + default: + break; } ha->flags.gpsc_supported = 1; @@ -4681,7 +4720,7 @@ qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma, "Done %s.\n", __func__); bp = (uint32_t *) buf; for (i = 0; i < (bufsiz-4)/4; i++, bp++) - *bp = cpu_to_be32(*bp); + *bp = le32_to_cpu(*bp); } return rval; diff --git a/drivers/scsi/qla2xxx/qla_nvme.c b/drivers/scsi/qla2xxx/qla_nvme.c index c5a963c2c86e..20d9dc39f0fb 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.c +++ b/drivers/scsi/qla2xxx/qla_nvme.c @@ -30,6 +30,9 @@ int qla_nvme_register_remote(struct scsi_qla_host *vha, struct fc_port *fcport) return 0; } + if (!vha->nvme_local_port && qla_nvme_register_hba(vha)) + return 0; + if (!(fcport->nvme_prli_service_param & (NVME_PRLI_SP_TARGET | NVME_PRLI_SP_DISCOVERY)) || (fcport->nvme_flag & NVME_FLAG_REGISTERED)) @@ -676,15 +679,15 @@ void qla_nvme_delete(struct scsi_qla_host *vha) } } -void qla_nvme_register_hba(struct scsi_qla_host *vha) +int qla_nvme_register_hba(struct scsi_qla_host *vha) { struct nvme_fc_port_template *tmpl; struct qla_hw_data *ha; struct nvme_fc_port_info pinfo; - int ret; + int ret = EINVAL; if (!IS_ENABLED(CONFIG_NVME_FC)) - return; + return ret; ha = vha->hw; tmpl = &qla_nvme_fc_transport; @@ -711,7 +714,9 @@ void qla_nvme_register_hba(struct scsi_qla_host *vha) if (ret) { ql_log(ql_log_warn, vha, 0xffff, "register_localport failed: ret=%x\n", ret); - return; + } else { + vha->nvme_local_port->private = vha; } - vha->nvme_local_port->private = vha; + + return ret; } diff --git a/drivers/scsi/qla2xxx/qla_nvme.h b/drivers/scsi/qla2xxx/qla_nvme.h index 816854ada654..4941d107fb1c 100644 --- a/drivers/scsi/qla2xxx/qla_nvme.h +++ b/drivers/scsi/qla2xxx/qla_nvme.h @@ -142,7 +142,7 @@ struct pt_ls4_rx_unsol { /* * Global functions prototype in qla_nvme.c source file. */ -void qla_nvme_register_hba(struct scsi_qla_host *); +int qla_nvme_register_hba(struct scsi_qla_host *); int qla_nvme_register_remote(struct scsi_qla_host *, struct fc_port *); void qla_nvme_delete(struct scsi_qla_host *); void qla_nvme_abort(struct qla_hw_data *, struct srb *sp, int res); diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c index 48d1003c8178..15b63136961c 100644 --- a/drivers/scsi/qla2xxx/qla_os.c +++ b/drivers/scsi/qla2xxx/qla_os.c @@ -4789,7 +4789,6 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) struct qlt_plogi_ack_t *pla = (struct qlt_plogi_ack_t *)e->u.new_sess.pla; uint8_t free_fcport = 0; - u64 wwn; ql_dbg(ql_dbg_disc, vha, 0xffff, "%s %d %8phC enter\n", @@ -4817,10 +4816,10 @@ 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) + 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) { + if (e->u.new_sess.fc4_type == FS_FC4TYPE_NVME) { fcport->fc4_type = FC4_TYPE_OTHER; fcport->fc4f_nvme = FC4_TYPE_NVME; } @@ -4862,9 +4861,6 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags); if (fcport) { - if (N2N_TOPO(vha->hw)) - fcport->flags &= ~FCF_FABRIC_DEVICE; - fcport->id_changed = 1; fcport->scan_state = QLA_FCPORT_FOUND; memcpy(fcport->node_name, e->u.new_sess.node_name, WWN_SIZE); @@ -4925,12 +4921,22 @@ void qla24xx_create_new_sess(struct scsi_qla_host *vha, struct qla_work_evt *e) if (dfcp) qlt_schedule_sess_for_deletion(tfcp); - wwn = wwn_to_u64(fcport->node_name); - if (!wwn) - qla24xx_async_gnnid(vha, fcport); - else - qla24xx_async_gnl(vha, fcport); + if (N2N_TOPO(vha->hw)) + fcport->flags &= ~FCF_FABRIC_DEVICE; + + if (N2N_TOPO(vha->hw)) { + if (vha->flags.nvme_enabled) { + fcport->fc4f_nvme = 1; + fcport->n2n_flag = 1; + } + fcport->fw_login_state = 0; + /* + * wait link init done before sending login + */ + } else { + qla24xx_fcport_handle_login(vha, fcport); + } } } @@ -5065,6 +5071,10 @@ qla2x00_do_work(struct scsi_qla_host *vha) case QLA_EVT_IIDMA: qla_do_iidma_work(vha, e->u.fcport.fcport); break; + case QLA_EVT_ELS_PLOGI: + qla24xx_els_dcmd2_iocb(vha, ELS_DCMD_PLOGI, + e->u.fcport.fcport, false); + break; } if (e->flags & QLA_EVT_FLAG_FREE) kfree(e); diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c index cfb5d6067f9f..5daa8832e389 100644 --- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c +++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c @@ -1620,9 +1620,6 @@ static void tcm_qla2xxx_update_sess(struct fc_port *sess, port_id_t s_id, sess->conf_compl_supported = conf_compl_supported; - /* Reset logout parameters to default */ - sess->logout_on_delete = 1; - sess->keep_nport_handle = 0; } /* -- 2.12.0