From edd05de1975927b51b4e8e1135ef4d6130dfd17c Mon Sep 17 00:00:00 2001 From: Duane Grigsby Date: Fri, 13 Oct 2017 09:34:06 -0700 Subject: [PATCH] scsi: qla2xxx: Changes to support N2N logins If we discovered a topology that is N2N then we will issue a login to the target. If our WWPN is bigger than the target's WWPN then we will initiate login, otherwise we will just wait for the target to initiate login. [mkp: many whitespace errors] Signed-off-by: Duane Grigsby Signed-off-by: Michael Hernandez Signed-off-by: Himanshu Madhani Reviewed-by: Johannes Thumshirn Tested-by: Ewan D. Milne Signed-off-by: Martin K. Petersen --- drivers/scsi/qla2xxx/qla_def.h | 24 ++++ drivers/scsi/qla2xxx/qla_fw.h | 4 +- drivers/scsi/qla2xxx/qla_gbl.h | 4 + drivers/scsi/qla2xxx/qla_init.c | 135 +++++++++++++++++++++- drivers/scsi/qla2xxx/qla_iocb.c | 195 ++++++++++++++++++++++++++++++-- drivers/scsi/qla2xxx/qla_isr.c | 42 ++++++- drivers/scsi/qla2xxx/qla_mbx.c | 76 +++++++++++++ 7 files changed, 459 insertions(+), 21 deletions(-) diff --git a/drivers/scsi/qla2xxx/qla_def.h b/drivers/scsi/qla2xxx/qla_def.h index f712c0cd46d6..01a9b8971e88 100644 --- a/drivers/scsi/qla2xxx/qla_def.h +++ b/drivers/scsi/qla2xxx/qla_def.h @@ -323,6 +323,12 @@ struct els_logo_payload { uint8_t wwpn[WWN_SIZE]; }; +struct els_plogi_payload { + uint8_t opcode; + uint8_t rsvd[3]; + uint8_t data[112]; +}; + struct ct_arg { void *iocb; u16 nport_handle; @@ -358,6 +364,19 @@ struct srb_iocb { dma_addr_t els_logo_pyld_dma; } els_logo; struct { +#define ELS_DCMD_PLOGI 0x3 + uint32_t flags; + uint32_t els_cmd; + struct completion comp; + struct els_plogi_payload *els_plogi_pyld; + struct els_plogi_payload *els_resp_pyld; + dma_addr_t els_plogi_pyld_dma; + dma_addr_t els_resp_pyld_dma; + uint32_t fw_status[3]; + __le16 comp_status; + __le16 len; + } els_plogi; + struct { /* * Values for flags field below are as * defined in tsk_mgmt_entry struct @@ -2349,6 +2368,7 @@ typedef struct fc_port { uint8_t fc4_type; uint8_t fc4f_nvme; uint8_t scan_state; + uint8_t n2n_flag; unsigned long last_queue_full; unsigned long last_ramp_up; @@ -2372,6 +2392,7 @@ typedef struct fc_port { u8 iocb[IOCB_SIZE]; u8 current_login_state; u8 last_login_state; + struct completion n2n_done; } fc_port_t; #define QLA_FCPORT_SCAN 1 @@ -4228,6 +4249,9 @@ typedef struct scsi_qla_host { wait_queue_head_t fcport_waitQ; wait_queue_head_t vref_waitq; uint8_t min_link_speed_feat; + uint8_t n2n_node_name[WWN_SIZE]; + uint8_t n2n_port_name[WWN_SIZE]; + uint16_t n2n_id; } scsi_qla_host_t; struct qla27xx_image_status { diff --git a/drivers/scsi/qla2xxx/qla_fw.h b/drivers/scsi/qla2xxx/qla_fw.h index bec641aae7b3..d5cef0727e72 100644 --- a/drivers/scsi/qla2xxx/qla_fw.h +++ b/drivers/scsi/qla2xxx/qla_fw.h @@ -753,9 +753,7 @@ struct els_entry_24xx { uint8_t reserved_2; uint8_t port_id[3]; - uint8_t reserved_3; - - uint16_t reserved_4; + uint8_t s_id[3]; uint16_t control_flags; /* Control flags. */ #define ECF_PAYLOAD_DESCR_MASK (BIT_15|BIT_14|BIT_13) diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h index 46c7822c20fc..0a23af5aa479 100644 --- a/drivers/scsi/qla2xxx/qla_gbl.h +++ b/drivers/scsi/qla2xxx/qla_gbl.h @@ -45,6 +45,8 @@ 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 void qla2x00_update_fcports(scsi_qla_host_t *); @@ -487,6 +489,8 @@ int qla24xx_gidlist_wait(struct scsi_qla_host *, void *, dma_addr_t, uint16_t *); int __qla24xx_parse_gpdb(struct scsi_qla_host *, fc_port_t *, struct port_database_24xx *); +int qla24xx_get_port_login_templ(scsi_qla_host_t *, dma_addr_t, + void *, uint16_t); extern int qla27xx_get_zio_threshold(scsi_qla_host_t *, uint16_t *); extern int qla27xx_set_zio_threshold(scsi_qla_host_t *, uint16_t); diff --git a/drivers/scsi/qla2xxx/qla_init.c b/drivers/scsi/qla2xxx/qla_init.c index 4c53199db371..1c53c0774e24 100644 --- a/drivers/scsi/qla2xxx/qla_init.c +++ b/drivers/scsi/qla2xxx/qla_init.c @@ -1433,6 +1433,14 @@ qla24xx_handle_prli_done_event(struct scsi_qla_host *vha, struct event_arg *ea) qla24xx_post_gpdb_work(vha, ea->fcport, 0); break; default: + if (ea->fcport->n2n_flag) { + 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; + ea->fcport->n2n_flag = 0; + qla24xx_post_prli_work(vha, ea->fcport); + } ql_dbg(ql_dbg_disc, vha, 0x2119, "%s %d %8phC unhandle event of %x\n", __func__, __LINE__, ea->fcport->port_name, ea->data[0]); @@ -4366,7 +4374,109 @@ qla2x00_configure_loop(scsi_qla_host_t *vha) return (rval); } +/* + * N2N Login + * Updates Fibre Channel Device Database with local loop devices. + * + * Input: + * ha = adapter block pointer. + * + * Returns: + */ +static int qla24xx_n2n_handle_login(struct scsi_qla_host *vha, + fc_port_t *fcport) +{ + struct qla_hw_data *ha = vha->hw; + int res = QLA_SUCCESS, rval; + int greater_wwpn = 0; + int logged_in = 0; + if (ha->current_topology != ISP_CFG_N) + return res; + + if (wwn_to_u64(vha->port_name) > + wwn_to_u64(vha->n2n_port_name)) { + ql_dbg(ql_dbg_disc, vha, 0x2002, + "HBA WWPN is greater %llx > target %llx\n", + wwn_to_u64(vha->port_name), + wwn_to_u64(vha->n2n_port_name)); + greater_wwpn = 1; + fcport->d_id.b24 = vha->n2n_id; + } + + fcport->loop_id = vha->loop_id; + fcport->fc4f_nvme = 0; + fcport->query = 1; + + ql_dbg(ql_dbg_disc, vha, 0x4001, + "Initiate N2N login handler: HBA port_id=%06x loopid=%d\n", + fcport->d_id.b24, vha->loop_id); + + /* Fill in member data. */ + if (!greater_wwpn) { + rval = qla2x00_get_port_database(vha, fcport, 0); + ql_dbg(ql_dbg_disc, vha, 0x1051, + "Remote login-state (%x/%x) port_id=%06x loop_id=%x, rval=%d\n", + fcport->current_login_state, fcport->last_login_state, + fcport->d_id.b24, fcport->loop_id, rval); + + if (((fcport->current_login_state & 0xf) == 0x4) || + ((fcport->current_login_state & 0xf) == 0x6)) + logged_in = 1; + } + + if (logged_in || greater_wwpn) { + if (!vha->nvme_local_port && vha->flags.nvme_enabled) + qla_nvme_register_hba(vha); + + /* Set connected N_Port d_id */ + if (vha->flags.nvme_enabled) + fcport->fc4f_nvme = 1; + + fcport->scan_state = QLA_FCPORT_FOUND; + fcport->fw_login_state = DSC_LS_PORT_UNAVAIL; + fcport->disc_state = DSC_GNL; + fcport->n2n_flag = 1; + fcport->flags = 3; + vha->hw->flags.gpsc_supported = 0; + + if (greater_wwpn) { + ql_dbg(ql_dbg_disc, vha, 0x20e5, + "%s %d PLOGI ELS %8phC\n", + __func__, __LINE__, fcport->port_name); + + res = qla24xx_els_dcmd2_iocb(vha, ELS_DCMD_PLOGI, + fcport, fcport->d_id); + } + + if (res != QLA_SUCCESS) { + ql_log(ql_log_info, vha, 0xd04d, + "PLOGI Failed: portid=%06x - retrying\n", + fcport->d_id.b24); + res = QLA_SUCCESS; + } else { + /* State 0x6 means FCP PRLI complete */ + 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); + } + } + } else { + /* Wait for next database change */ + set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); + } + + return res; +} /* * qla2x00_configure_local_loop @@ -4437,6 +4547,14 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) } } + /* Inititae N2N login. */ + if (test_and_clear_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags)) { + rval = qla24xx_n2n_handle_login(vha, new_fcport); + if (rval != QLA_SUCCESS) + goto cleanup_allocation; + return QLA_SUCCESS; + } + /* Add devices to port list. */ id_iter = (char *)ha->gid_list; for (index = 0; index < entries; index++) { @@ -4478,10 +4596,13 @@ qla2x00_configure_local_loop(scsi_qla_host_t *vha) "Failed to retrieve fcport information " "-- get_port_database=%x, loop_id=0x%04x.\n", rval2, new_fcport->loop_id); - ql_dbg(ql_dbg_disc, vha, 0x2105, - "Scheduling resync.\n"); - set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); - continue; + /* Skip retry if N2N */ + if (ha->current_topology != ISP_CFG_N) { + ql_dbg(ql_dbg_disc, vha, 0x2105, + "Scheduling resync.\n"); + set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); + continue; + } } spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags); @@ -7554,6 +7675,12 @@ qla81xx_nvram_config(scsi_qla_host_t *vha) if (qla_tgt_mode_enabled(vha) || qla_dual_mode_enabled(vha)) icb->firmware_options_3 |= BIT_0; + if (IS_QLA27XX(ha)) { + icb->firmware_options_3 |= BIT_8; + ql_dbg(ql_log_info, vha, 0x0075, + "Enabling direct connection.\n"); + } + if (rval) { ql_log(ql_log_warn, vha, 0x0076, "NVRAM configuration failed.\n"); diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c index 2f94159186d7..d810a447cb4a 100644 --- a/drivers/scsi/qla2xxx/qla_iocb.c +++ b/drivers/scsi/qla2xxx/qla_iocb.c @@ -2518,6 +2518,7 @@ 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; @@ -2534,23 +2535,197 @@ qla24xx_els_logo_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) els_iocb->port_id[0] = sp->fcport->d_id.b.al_pa; els_iocb->port_id[1] = sp->fcport->d_id.b.area; els_iocb->port_id[2] = sp->fcport->d_id.b.domain; + els_iocb->s_id[0] = vha->d_id.b.al_pa; + els_iocb->s_id[1] = vha->d_id.b.area; + els_iocb->s_id[2] = vha->d_id.b.domain; els_iocb->control_flags = 0; - els_iocb->tx_byte_count = sizeof(struct els_logo_payload); - els_iocb->tx_address[0] = - cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma)); - els_iocb->tx_address[1] = - cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma)); - els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload)); + if (elsio->u.els_logo.els_cmd == ELS_DCMD_PLOGI) { + els_iocb->tx_byte_count = 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_byte_count = 0; - els_iocb->rx_address[0] = 0; - els_iocb->rx_address[1] = 0; - els_iocb->rx_len = 0; + els_iocb->rx_dsd_count = 1; + els_iocb->rx_byte_count = 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, + (uint8_t *)els_iocb, 0x70); + } else { + els_iocb->tx_byte_count = sizeof(struct els_logo_payload); + els_iocb->tx_address[0] = + cpu_to_le32(LSD(elsio->u.els_logo.els_logo_pyld_dma)); + els_iocb->tx_address[1] = + cpu_to_le32(MSD(elsio->u.els_logo.els_logo_pyld_dma)); + els_iocb->tx_len = cpu_to_le32(sizeof(struct els_logo_payload)); + + els_iocb->rx_byte_count = 0; + els_iocb->rx_address[0] = 0; + els_iocb->rx_address[1] = 0; + els_iocb->rx_len = 0; + } sp->vha->qla_stats.control_requests++; } +static void +qla2x00_els_dcmd2_sp_free(void *data) +{ + srb_t *sp = data; + struct srb_iocb *elsio = &sp->u.iocb_cmd; + + if (elsio->u.els_plogi.els_plogi_pyld) + dma_free_coherent(&sp->vha->hw->pdev->dev, DMA_POOL_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, DMA_POOL_SIZE, + elsio->u.els_plogi.els_resp_pyld, + elsio->u.els_plogi.els_resp_pyld_dma); + + del_timer(&elsio->timer); + qla2x00_rel_sp(sp); +} + +static void +qla2x00_els_dcmd2_iocb_timeout(void *data) +{ + srb_t *sp = 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; + + ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3069, + "%s hdl=%x ELS Timeout, %8phC portid=%06x\n", + sp->name, sp->handle, fcport->port_name, fcport->d_id.b24); + + /* Abort the exchange */ + spin_lock_irqsave(&ha->hardware_lock, flags); + res = ha->isp_ops->abort_command(sp); + ql_dbg(ql_dbg_io, vha, 0x3070, + "mbx abort_command %s\n", + (res == QLA_SUCCESS) ? "successful" : "failed"); + spin_unlock_irqrestore(&ha->hardware_lock, flags); + + complete(&lio->u.els_plogi.comp); +} + +static void +qla2x00_els_dcmd2_sp_done(void *ptr, int res) +{ + srb_t *sp = ptr; + fc_port_t *fcport = sp->fcport; + struct srb_iocb *lio = &sp->u.iocb_cmd; + struct scsi_qla_host *vha = sp->vha; + + ql_dbg(ql_dbg_io + ql_dbg_disc, vha, 0x3072, + "%s ELS hdl=%x, portid=%06x done %8pC\n", + sp->name, sp->handle, fcport->d_id.b24, fcport->port_name); + + complete(&lio->u.els_plogi.comp); +} + +int +qla24xx_els_dcmd2_iocb(scsi_qla_host_t *vha, int els_opcode, + fc_port_t *fcport, port_id_t remote_did) +{ + srb_t *sp; + struct srb_iocb *elsio = NULL; + struct qla_hw_data *ha = vha->hw; + int rval = QLA_SUCCESS; + void *ptr, *resp_ptr; + dma_addr_t ptr_dma; + + /* Alloc SRB structure */ + sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); + if (!sp) { + ql_log(ql_log_info, vha, 0x70e6, + "SRB allocation failed\n"); + return -ENOMEM; + } + + elsio = &sp->u.iocb_cmd; + fcport->d_id.b.domain = remote_did.b.domain; + fcport->d_id.b.area = remote_did.b.area; + fcport->d_id.b.al_pa = remote_did.b.al_pa; + + ql_dbg(ql_dbg_io, vha, 0x3073, + "Enter: PLOGI portid=%06x\n", fcport->d_id.b24); + + sp->type = SRB_ELS_DCMD; + sp->name = "ELS_DCMD"; + sp->fcport = fcport; + qla2x00_init_timer(sp, ELS_DCMD_TIMEOUT); + elsio->timeout = qla2x00_els_dcmd2_iocb_timeout; + sp->done = qla2x00_els_dcmd2_sp_done; + sp->free = qla2x00_els_dcmd2_sp_free; + + ptr = elsio->u.els_plogi.els_plogi_pyld = + dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + &elsio->u.els_plogi.els_plogi_pyld_dma, GFP_KERNEL); + ptr_dma = elsio->u.els_plogi.els_plogi_pyld_dma; + + if (!elsio->u.els_plogi.els_plogi_pyld) { + rval = QLA_FUNCTION_FAILED; + goto out; + } + + resp_ptr = elsio->u.els_plogi.els_resp_pyld = + dma_alloc_coherent(&ha->pdev->dev, DMA_POOL_SIZE, + &elsio->u.els_plogi.els_resp_pyld_dma, GFP_KERNEL); + + if (!elsio->u.els_plogi.els_resp_pyld) { + rval = QLA_FUNCTION_FAILED; + goto out; + } + + ql_dbg(ql_dbg_io, vha, 0x3073, "PLOGI %p %p\n", ptr, resp_ptr); + + memset(ptr, 0, sizeof(struct els_plogi_payload)); + memset(resp_ptr, 0, sizeof(struct els_plogi_payload)); + 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, + (uint8_t *)elsio->u.els_plogi.els_plogi_pyld, 0x70); + + init_completion(&elsio->u.els_plogi.comp); + rval = qla2x00_start_sp(sp); + if (rval != QLA_SUCCESS) { + rval = QLA_FUNCTION_FAILED; + goto out; + } + + 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 (elsio->u.els_plogi.comp_status != CS_COMPLETE) + rval = QLA_FUNCTION_FAILED; + +out: + sp->free(sp); + return rval; +} + static void qla24xx_els_iocb(srb_t *sp, struct els_entry_24xx *els_iocb) { diff --git a/drivers/scsi/qla2xxx/qla_isr.c b/drivers/scsi/qla2xxx/qla_isr.c index ab97fb06c239..c7878be9dd5f 100644 --- a/drivers/scsi/qla2xxx/qla_isr.c +++ b/drivers/scsi/qla2xxx/qla_isr.c @@ -1041,6 +1041,7 @@ global_port_update: */ atomic_set(&vha->loop_down_timer, 0); if (atomic_read(&vha->loop_state) != LOOP_DOWN && + !ha->flags.n2n_ae && atomic_read(&vha->loop_state) != LOOP_DEAD) { ql_dbg(ql_dbg_async, vha, 0x5011, "Asynchronous PORT UPDATE ignored %04x/%04x/%04x.\n", @@ -1545,6 +1546,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, uint32_t fw_status[3]; uint8_t* fw_sts_ptr; int res; + struct srb_iocb *els; sp = qla2x00_get_sp_from_handle(vha, func, req, pkt); if (!sp) @@ -1561,10 +1563,14 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, break; case SRB_ELS_DCMD: type = "Driver ELS logo"; - ql_dbg(ql_dbg_user, vha, 0x5047, - "Completing %s: (%p) type=%d.\n", type, sp, sp->type); - sp->done(sp, 0); - return; + if (iocb_type != ELS_IOCB_TYPE) { + ql_dbg(ql_dbg_user, vha, 0x5047, + "Completing %s: (%p) type=%d.\n", + type, sp, sp->type); + sp->done(sp, 0); + return; + } + break; case SRB_CT_PTHRU_CMD: /* borrowing sts_entry_24xx.comp_status. same location as ct_entry_24xx.comp_status @@ -1584,6 +1590,33 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, fw_status[1] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_1); fw_status[2] = le16_to_cpu(((struct els_sts_entry_24xx*)pkt)->error_subcode_2); + if (iocb_type == ELS_IOCB_TYPE) { + els = &sp->u.iocb_cmd; + els->u.els_plogi.fw_status[0] = fw_status[0]; + els->u.els_plogi.fw_status[1] = fw_status[1]; + els->u.els_plogi.fw_status[2] = fw_status[2]; + els->u.els_plogi.comp_status = fw_status[0]; + if (comp_status == CS_COMPLETE) { + res = DID_OK << 16; + } else { + if (comp_status == CS_DATA_UNDERRUN) { + res = DID_OK << 16; + els->u.els_plogi.len = + le16_to_cpu(((struct els_sts_entry_24xx *) + pkt)->total_byte_count); + } else { + els->u.els_plogi.len = 0; + res = DID_ERROR << 16; + } + } + ql_log(ql_log_info, vha, 0x503f, + "ELS IOCB Done -%s error hdl=%x comp_status=0x%x error subcode 1=0x%x error subcode 2=0x%x total_byte=0x%x\n", + type, sp->handle, comp_status, fw_status[1], fw_status[2], + le16_to_cpu(((struct els_sts_entry_24xx *) + pkt)->total_byte_count)); + goto els_ct_done; + } + /* return FC_CTELS_STATUS_OK and leave the decoding of the ELS/CT * fc payload to the caller */ @@ -1631,6 +1664,7 @@ qla24xx_els_ct_entry(scsi_qla_host_t *vha, struct req_que *req, bsg_reply->reply_payload_rcv_len = bsg_job->reply_payload.payload_len; bsg_job->reply_len = 0; } +els_ct_done: sp->done(sp, res); } diff --git a/drivers/scsi/qla2xxx/qla_mbx.c b/drivers/scsi/qla2xxx/qla_mbx.c index 71e56877e1eb..cb717d47339f 100644 --- a/drivers/scsi/qla2xxx/qla_mbx.c +++ b/drivers/scsi/qla2xxx/qla_mbx.c @@ -1786,6 +1786,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) if (pd == NULL) { ql_log(ql_log_warn, vha, 0x1050, "Failed to allocate port database structure.\n"); + fcport->query = 0; return QLA_MEMORY_ALLOC_FAILED; } @@ -1926,6 +1927,7 @@ qla2x00_get_port_database(scsi_qla_host_t *vha, fc_port_t *fcport, uint8_t opt) gpd_error_out: dma_pool_free(ha->s_dma_pool, pd, pd_dma); + fcport->query = 0; if (rval != QLA_SUCCESS) { ql_dbg(ql_dbg_mbx, vha, 0x1052, @@ -3762,6 +3764,38 @@ qla24xx_report_id_acquisition(scsi_qla_host_t *vha, rptid_entry->vp_status, rptid_entry->port_id[2], rptid_entry->port_id[1], rptid_entry->port_id[0]); + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: Remote WWPN %8phC.\n", + rptid_entry->u.f1.port_name); + + ql_dbg(ql_dbg_async, vha, 0x5075, + "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); + } else { + ql_dbg(ql_dbg_async, vha, 0x5075, + "Format 1: Remote login - Waiting for WWPN %8phC.\n", + rptid_entry->u.f1.port_name); + } + + memcpy(vha->n2n_port_name, rptid_entry->u.f1.port_name, + WWN_SIZE); + set_bit(N2N_LOGIN_NEEDED, &vha->dpc_flags); + set_bit(REGISTER_FC4_NEEDED, &vha->dpc_flags); + set_bit(REGISTER_FDMI_NEEDED, &vha->dpc_flags); + return; + } /* buffer to buffer credit flag */ vha->flags.bbcr_enable = (rptid_entry->u.f1.bbcr & 0xf) != 0; @@ -4599,6 +4633,48 @@ qla25xx_set_driver_version(scsi_qla_host_t *vha, char *version) return rval; } +int +qla24xx_get_port_login_templ(scsi_qla_host_t *vha, dma_addr_t buf_dma, + void *buf, uint16_t bufsiz) +{ + int rval, i; + mbx_cmd_t mc; + mbx_cmd_t *mcp = &mc; + uint32_t *bp; + + if (!IS_FWI2_CAPABLE(vha->hw)) + return QLA_FUNCTION_FAILED; + + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x1159, + "Entered %s.\n", __func__); + + mcp->mb[0] = MBC_GET_RNID_PARAMS; + mcp->mb[1] = RNID_TYPE_PORT_LOGIN << 8; + mcp->mb[2] = MSW(buf_dma); + mcp->mb[3] = LSW(buf_dma); + mcp->mb[6] = MSW(MSD(buf_dma)); + mcp->mb[7] = LSW(MSD(buf_dma)); + mcp->mb[8] = bufsiz/4; + mcp->out_mb = MBX_8|MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0; + mcp->in_mb = MBX_1|MBX_0; + mcp->tov = MBX_TOV_SECONDS; + mcp->flags = 0; + rval = qla2x00_mailbox_command(vha, mcp); + + if (rval != QLA_SUCCESS) { + ql_dbg(ql_dbg_mbx, vha, 0x115a, + "Failed=%x mb[0]=%x,%x.\n", rval, mcp->mb[0], mcp->mb[1]); + } else { + ql_dbg(ql_dbg_mbx + ql_dbg_verbose, vha, 0x115b, + "Done %s.\n", __func__); + bp = (uint32_t *) buf; + for (i = 0; i < (bufsiz-4)/4; i++, bp++) + *bp = cpu_to_be32(*bp); + } + + return rval; +} + static int qla2x00_read_asic_temperature(scsi_qla_host_t *vha, uint16_t *temp) {