162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver 462306a36Sopenharmony_ci * Copyright (c) 2003-2014 QLogic Corporation 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci#include "qla_def.h" 762306a36Sopenharmony_ci#include "qla_target.h" 862306a36Sopenharmony_ci#include <linux/utsname.h> 962306a36Sopenharmony_ci 1062306a36Sopenharmony_cistatic int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *); 1162306a36Sopenharmony_cistatic int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *); 1262306a36Sopenharmony_cistatic int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *); 1362306a36Sopenharmony_cistatic int qla2x00_sns_gnn_id(scsi_qla_host_t *, sw_info_t *); 1462306a36Sopenharmony_cistatic int qla2x00_sns_rft_id(scsi_qla_host_t *); 1562306a36Sopenharmony_cistatic int qla2x00_sns_rnn_id(scsi_qla_host_t *); 1662306a36Sopenharmony_cistatic int qla_async_rftid(scsi_qla_host_t *, port_id_t *); 1762306a36Sopenharmony_cistatic int qla_async_rffid(scsi_qla_host_t *, port_id_t *, u8, u8); 1862306a36Sopenharmony_cistatic int qla_async_rnnid(scsi_qla_host_t *, port_id_t *, u8*); 1962306a36Sopenharmony_cistatic int qla_async_rsnn_nn(scsi_qla_host_t *); 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/** 2462306a36Sopenharmony_ci * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query. 2562306a36Sopenharmony_ci * @vha: HA context 2662306a36Sopenharmony_ci * @arg: CT arguments 2762306a36Sopenharmony_ci * 2862306a36Sopenharmony_ci * Returns a pointer to the @vha's ms_iocb. 2962306a36Sopenharmony_ci */ 3062306a36Sopenharmony_civoid * 3162306a36Sopenharmony_ciqla2x00_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 3462306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci ms_pkt = (ms_iocb_entry_t *)arg->iocb; 3762306a36Sopenharmony_ci memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci ms_pkt->entry_type = MS_IOCB_TYPE; 4062306a36Sopenharmony_ci ms_pkt->entry_count = 1; 4162306a36Sopenharmony_ci SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER); 4262306a36Sopenharmony_ci ms_pkt->control_flags = cpu_to_le16(CF_READ | CF_HEAD_TAG); 4362306a36Sopenharmony_ci ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); 4462306a36Sopenharmony_ci ms_pkt->cmd_dsd_count = cpu_to_le16(1); 4562306a36Sopenharmony_ci ms_pkt->total_dsd_count = cpu_to_le16(2); 4662306a36Sopenharmony_ci ms_pkt->rsp_bytecount = cpu_to_le32(arg->rsp_size); 4762306a36Sopenharmony_ci ms_pkt->req_bytecount = cpu_to_le32(arg->req_size); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci put_unaligned_le64(arg->req_dma, &ms_pkt->req_dsd.address); 5062306a36Sopenharmony_ci ms_pkt->req_dsd.length = ms_pkt->req_bytecount; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci put_unaligned_le64(arg->rsp_dma, &ms_pkt->rsp_dsd.address); 5362306a36Sopenharmony_ci ms_pkt->rsp_dsd.length = ms_pkt->rsp_bytecount; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci vha->qla_stats.control_requests++; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci return (ms_pkt); 5862306a36Sopenharmony_ci} 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci/** 6162306a36Sopenharmony_ci * qla24xx_prep_ms_iocb() - Prepare common CT IOCB fields for SNS CT query. 6262306a36Sopenharmony_ci * @vha: HA context 6362306a36Sopenharmony_ci * @arg: CT arguments 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * Returns a pointer to the @ha's ms_iocb. 6662306a36Sopenharmony_ci */ 6762306a36Sopenharmony_civoid * 6862306a36Sopenharmony_ciqla24xx_prep_ms_iocb(scsi_qla_host_t *vha, struct ct_arg *arg) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 7162306a36Sopenharmony_ci struct ct_entry_24xx *ct_pkt; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci ct_pkt = (struct ct_entry_24xx *)arg->iocb; 7462306a36Sopenharmony_ci memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci ct_pkt->entry_type = CT_IOCB_TYPE; 7762306a36Sopenharmony_ci ct_pkt->entry_count = 1; 7862306a36Sopenharmony_ci ct_pkt->nport_handle = cpu_to_le16(arg->nport_handle); 7962306a36Sopenharmony_ci ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); 8062306a36Sopenharmony_ci ct_pkt->cmd_dsd_count = cpu_to_le16(1); 8162306a36Sopenharmony_ci ct_pkt->rsp_dsd_count = cpu_to_le16(1); 8262306a36Sopenharmony_ci ct_pkt->rsp_byte_count = cpu_to_le32(arg->rsp_size); 8362306a36Sopenharmony_ci ct_pkt->cmd_byte_count = cpu_to_le32(arg->req_size); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci put_unaligned_le64(arg->req_dma, &ct_pkt->dsd[0].address); 8662306a36Sopenharmony_ci ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci put_unaligned_le64(arg->rsp_dma, &ct_pkt->dsd[1].address); 8962306a36Sopenharmony_ci ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count; 9062306a36Sopenharmony_ci ct_pkt->vp_index = vha->vp_idx; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci vha->qla_stats.control_requests++; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return (ct_pkt); 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci/** 9862306a36Sopenharmony_ci * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query. 9962306a36Sopenharmony_ci * @p: CT request buffer 10062306a36Sopenharmony_ci * @cmd: GS command 10162306a36Sopenharmony_ci * @rsp_size: response size in bytes 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * Returns a pointer to the intitialized @ct_req. 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_cistatic inline struct ct_sns_req * 10662306a36Sopenharmony_ciqla2x00_prep_ct_req(struct ct_sns_pkt *p, uint16_t cmd, uint16_t rsp_size) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci memset(p, 0, sizeof(struct ct_sns_pkt)); 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci p->p.req.header.revision = 0x01; 11162306a36Sopenharmony_ci p->p.req.header.gs_type = 0xFC; 11262306a36Sopenharmony_ci p->p.req.header.gs_subtype = 0x02; 11362306a36Sopenharmony_ci p->p.req.command = cpu_to_be16(cmd); 11462306a36Sopenharmony_ci p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci return &p->p.req; 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ciint 12062306a36Sopenharmony_ciqla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt, 12162306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp, const char *routine) 12262306a36Sopenharmony_ci{ 12362306a36Sopenharmony_ci int rval; 12462306a36Sopenharmony_ci uint16_t comp_status; 12562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 12662306a36Sopenharmony_ci bool lid_is_sns = false; 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 12962306a36Sopenharmony_ci if (ms_pkt->entry_status != 0) { 13062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2031, 13162306a36Sopenharmony_ci "%s failed, error status (%x) on port_id: %02x%02x%02x.\n", 13262306a36Sopenharmony_ci routine, ms_pkt->entry_status, vha->d_id.b.domain, 13362306a36Sopenharmony_ci vha->d_id.b.area, vha->d_id.b.al_pa); 13462306a36Sopenharmony_ci } else { 13562306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) 13662306a36Sopenharmony_ci comp_status = le16_to_cpu( 13762306a36Sopenharmony_ci ((struct ct_entry_24xx *)ms_pkt)->comp_status); 13862306a36Sopenharmony_ci else 13962306a36Sopenharmony_ci comp_status = le16_to_cpu(ms_pkt->status); 14062306a36Sopenharmony_ci switch (comp_status) { 14162306a36Sopenharmony_ci case CS_COMPLETE: 14262306a36Sopenharmony_ci case CS_DATA_UNDERRUN: 14362306a36Sopenharmony_ci case CS_DATA_OVERRUN: /* Overrun? */ 14462306a36Sopenharmony_ci if (ct_rsp->header.response != 14562306a36Sopenharmony_ci cpu_to_be16(CT_ACCEPT_RESPONSE)) { 14662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077, 14762306a36Sopenharmony_ci "%s failed rejected request on port_id: %02x%02x%02x Completion status 0x%x, response 0x%x\n", 14862306a36Sopenharmony_ci routine, vha->d_id.b.domain, 14962306a36Sopenharmony_ci vha->d_id.b.area, vha->d_id.b.al_pa, 15062306a36Sopenharmony_ci comp_status, ct_rsp->header.response); 15162306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 15262306a36Sopenharmony_ci 0x2078, ct_rsp, 15362306a36Sopenharmony_ci offsetof(typeof(*ct_rsp), rsp)); 15462306a36Sopenharmony_ci rval = QLA_INVALID_COMMAND; 15562306a36Sopenharmony_ci } else 15662306a36Sopenharmony_ci rval = QLA_SUCCESS; 15762306a36Sopenharmony_ci break; 15862306a36Sopenharmony_ci case CS_PORT_LOGGED_OUT: 15962306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 16062306a36Sopenharmony_ci if (le16_to_cpu(ms_pkt->loop_id.extended) == 16162306a36Sopenharmony_ci NPH_SNS) 16262306a36Sopenharmony_ci lid_is_sns = true; 16362306a36Sopenharmony_ci } else { 16462306a36Sopenharmony_ci if (le16_to_cpu(ms_pkt->loop_id.extended) == 16562306a36Sopenharmony_ci SIMPLE_NAME_SERVER) 16662306a36Sopenharmony_ci lid_is_sns = true; 16762306a36Sopenharmony_ci } 16862306a36Sopenharmony_ci if (lid_is_sns) { 16962306a36Sopenharmony_ci ql_dbg(ql_dbg_async, vha, 0x502b, 17062306a36Sopenharmony_ci "%s failed, Name server has logged out", 17162306a36Sopenharmony_ci routine); 17262306a36Sopenharmony_ci rval = QLA_NOT_LOGGED_IN; 17362306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 17462306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 17562306a36Sopenharmony_ci } 17662306a36Sopenharmony_ci break; 17762306a36Sopenharmony_ci case CS_TIMEOUT: 17862306a36Sopenharmony_ci rval = QLA_FUNCTION_TIMEOUT; 17962306a36Sopenharmony_ci fallthrough; 18062306a36Sopenharmony_ci default: 18162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2033, 18262306a36Sopenharmony_ci "%s failed, completion status (%x) on port_id: " 18362306a36Sopenharmony_ci "%02x%02x%02x.\n", routine, comp_status, 18462306a36Sopenharmony_ci vha->d_id.b.domain, vha->d_id.b.area, 18562306a36Sopenharmony_ci vha->d_id.b.al_pa); 18662306a36Sopenharmony_ci break; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci return rval; 19062306a36Sopenharmony_ci} 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci/** 19362306a36Sopenharmony_ci * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command. 19462306a36Sopenharmony_ci * @vha: HA context 19562306a36Sopenharmony_ci * @fcport: fcport entry to updated 19662306a36Sopenharmony_ci * 19762306a36Sopenharmony_ci * Returns 0 on success. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ciint 20062306a36Sopenharmony_ciqla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) 20162306a36Sopenharmony_ci{ 20262306a36Sopenharmony_ci int rval; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 20562306a36Sopenharmony_ci struct ct_sns_req *ct_req; 20662306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 20762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 20862306a36Sopenharmony_ci struct ct_arg arg; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 21162306a36Sopenharmony_ci return qla2x00_sns_ga_nxt(vha, fcport); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 21462306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 21562306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 21662306a36Sopenharmony_ci arg.req_size = GA_NXT_REQ_SIZE; 21762306a36Sopenharmony_ci arg.rsp_size = GA_NXT_RSP_SIZE; 21862306a36Sopenharmony_ci arg.nport_handle = NPH_SNS; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* Issue GA_NXT */ 22162306a36Sopenharmony_ci /* Prepare common MS IOCB */ 22262306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_iocb(vha, &arg); 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci /* Prepare CT request */ 22562306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ha->ct_sns, GA_NXT_CMD, 22662306a36Sopenharmony_ci GA_NXT_RSP_SIZE); 22762306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci /* Prepare CT arguments -- port_id */ 23062306a36Sopenharmony_ci ct_req->req.port_id.port_id = port_id_to_be_id(fcport->d_id); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci /* Execute MS IOCB */ 23362306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 23462306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 23562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 23662306a36Sopenharmony_ci /*EMPTY*/ 23762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2062, 23862306a36Sopenharmony_ci "GA_NXT issue IOCB failed (%d).\n", rval); 23962306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GA_NXT") != 24062306a36Sopenharmony_ci QLA_SUCCESS) { 24162306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 24262306a36Sopenharmony_ci } else { 24362306a36Sopenharmony_ci /* Populate fc_port_t entry. */ 24462306a36Sopenharmony_ci fcport->d_id = be_to_port_id(ct_rsp->rsp.ga_nxt.port_id); 24562306a36Sopenharmony_ci 24662306a36Sopenharmony_ci memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name, 24762306a36Sopenharmony_ci WWN_SIZE); 24862306a36Sopenharmony_ci memcpy(fcport->port_name, ct_rsp->rsp.ga_nxt.port_name, 24962306a36Sopenharmony_ci WWN_SIZE); 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci fcport->fc4_type = (ct_rsp->rsp.ga_nxt.fc4_types[2] & BIT_0) ? 25262306a36Sopenharmony_ci FS_FC4TYPE_FCP : FC4_TYPE_OTHER; 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE && 25562306a36Sopenharmony_ci ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE) 25662306a36Sopenharmony_ci fcport->d_id.b.domain = 0xf0; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2063, 25962306a36Sopenharmony_ci "GA_NXT entry - nn %8phN pn %8phN " 26062306a36Sopenharmony_ci "port_id=%02x%02x%02x.\n", 26162306a36Sopenharmony_ci fcport->node_name, fcport->port_name, 26262306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, 26362306a36Sopenharmony_ci fcport->d_id.b.al_pa); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci return (rval); 26762306a36Sopenharmony_ci} 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_cistatic inline int 27062306a36Sopenharmony_ciqla2x00_gid_pt_rsp_size(scsi_qla_host_t *vha) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci return vha->hw->max_fibre_devices * 4 + 16; 27362306a36Sopenharmony_ci} 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci/** 27662306a36Sopenharmony_ci * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command. 27762306a36Sopenharmony_ci * @vha: HA context 27862306a36Sopenharmony_ci * @list: switch info entries to populate 27962306a36Sopenharmony_ci * 28062306a36Sopenharmony_ci * NOTE: Non-Nx_Ports are not requested. 28162306a36Sopenharmony_ci * 28262306a36Sopenharmony_ci * Returns 0 on success. 28362306a36Sopenharmony_ci */ 28462306a36Sopenharmony_ciint 28562306a36Sopenharmony_ciqla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) 28662306a36Sopenharmony_ci{ 28762306a36Sopenharmony_ci int rval; 28862306a36Sopenharmony_ci uint16_t i; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 29162306a36Sopenharmony_ci struct ct_sns_req *ct_req; 29262306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci struct ct_sns_gid_pt_data *gid_data; 29562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 29662306a36Sopenharmony_ci uint16_t gid_pt_rsp_size; 29762306a36Sopenharmony_ci struct ct_arg arg; 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 30062306a36Sopenharmony_ci return qla2x00_sns_gid_pt(vha, list); 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci gid_data = NULL; 30362306a36Sopenharmony_ci gid_pt_rsp_size = qla2x00_gid_pt_rsp_size(vha); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 30662306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 30762306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 30862306a36Sopenharmony_ci arg.req_size = GID_PT_REQ_SIZE; 30962306a36Sopenharmony_ci arg.rsp_size = gid_pt_rsp_size; 31062306a36Sopenharmony_ci arg.nport_handle = NPH_SNS; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* Issue GID_PT */ 31362306a36Sopenharmony_ci /* Prepare common MS IOCB */ 31462306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_iocb(vha, &arg); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci /* Prepare CT request */ 31762306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ha->ct_sns, GID_PT_CMD, gid_pt_rsp_size); 31862306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci /* Prepare CT arguments -- port_type */ 32162306a36Sopenharmony_ci ct_req->req.gid_pt.port_type = NS_NX_PORT_TYPE; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci /* Execute MS IOCB */ 32462306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 32562306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 32662306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 32762306a36Sopenharmony_ci /*EMPTY*/ 32862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2055, 32962306a36Sopenharmony_ci "GID_PT issue IOCB failed (%d).\n", rval); 33062306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GID_PT") != 33162306a36Sopenharmony_ci QLA_SUCCESS) { 33262306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 33362306a36Sopenharmony_ci } else { 33462306a36Sopenharmony_ci /* Set port IDs in switch info list. */ 33562306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 33662306a36Sopenharmony_ci gid_data = &ct_rsp->rsp.gid_pt.entries[i]; 33762306a36Sopenharmony_ci list[i].d_id = be_to_port_id(gid_data->port_id); 33862306a36Sopenharmony_ci memset(list[i].fabric_port_name, 0, WWN_SIZE); 33962306a36Sopenharmony_ci list[i].fp_speed = PORT_SPEED_UNKNOWN; 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci /* Last one exit. */ 34262306a36Sopenharmony_ci if (gid_data->control_byte & BIT_7) { 34362306a36Sopenharmony_ci list[i].d_id.b.rsvd_1 = gid_data->control_byte; 34462306a36Sopenharmony_ci break; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci } 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* 34962306a36Sopenharmony_ci * If we've used all available slots, then the switch is 35062306a36Sopenharmony_ci * reporting back more devices than we can handle with this 35162306a36Sopenharmony_ci * single call. Return a failed status, and let GA_NXT handle 35262306a36Sopenharmony_ci * the overload. 35362306a36Sopenharmony_ci */ 35462306a36Sopenharmony_ci if (i == ha->max_fibre_devices) 35562306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 35662306a36Sopenharmony_ci } 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci return (rval); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/** 36262306a36Sopenharmony_ci * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query. 36362306a36Sopenharmony_ci * @vha: HA context 36462306a36Sopenharmony_ci * @list: switch info entries to populate 36562306a36Sopenharmony_ci * 36662306a36Sopenharmony_ci * Returns 0 on success. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ciint 36962306a36Sopenharmony_ciqla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) 37062306a36Sopenharmony_ci{ 37162306a36Sopenharmony_ci int rval = QLA_SUCCESS; 37262306a36Sopenharmony_ci uint16_t i; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 37562306a36Sopenharmony_ci struct ct_sns_req *ct_req; 37662306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 37762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 37862306a36Sopenharmony_ci struct ct_arg arg; 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 38162306a36Sopenharmony_ci return qla2x00_sns_gpn_id(vha, list); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 38462306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 38562306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 38662306a36Sopenharmony_ci arg.req_size = GPN_ID_REQ_SIZE; 38762306a36Sopenharmony_ci arg.rsp_size = GPN_ID_RSP_SIZE; 38862306a36Sopenharmony_ci arg.nport_handle = NPH_SNS; 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 39162306a36Sopenharmony_ci /* Issue GPN_ID */ 39262306a36Sopenharmony_ci /* Prepare common MS IOCB */ 39362306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_iocb(vha, &arg); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci /* Prepare CT request */ 39662306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ha->ct_sns, GPN_ID_CMD, 39762306a36Sopenharmony_ci GPN_ID_RSP_SIZE); 39862306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci /* Prepare CT arguments -- port_id */ 40162306a36Sopenharmony_ci ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); 40262306a36Sopenharmony_ci 40362306a36Sopenharmony_ci /* Execute MS IOCB */ 40462306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 40562306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 40662306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 40762306a36Sopenharmony_ci /*EMPTY*/ 40862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2056, 40962306a36Sopenharmony_ci "GPN_ID issue IOCB failed (%d).\n", rval); 41062306a36Sopenharmony_ci break; 41162306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, 41262306a36Sopenharmony_ci "GPN_ID") != QLA_SUCCESS) { 41362306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 41462306a36Sopenharmony_ci break; 41562306a36Sopenharmony_ci } else { 41662306a36Sopenharmony_ci /* Save portname */ 41762306a36Sopenharmony_ci memcpy(list[i].port_name, 41862306a36Sopenharmony_ci ct_rsp->rsp.gpn_id.port_name, WWN_SIZE); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci /* Last device exit. */ 42262306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 42362306a36Sopenharmony_ci break; 42462306a36Sopenharmony_ci } 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci return (rval); 42762306a36Sopenharmony_ci} 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci/** 43062306a36Sopenharmony_ci * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query. 43162306a36Sopenharmony_ci * @vha: HA context 43262306a36Sopenharmony_ci * @list: switch info entries to populate 43362306a36Sopenharmony_ci * 43462306a36Sopenharmony_ci * Returns 0 on success. 43562306a36Sopenharmony_ci */ 43662306a36Sopenharmony_ciint 43762306a36Sopenharmony_ciqla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci int rval = QLA_SUCCESS; 44062306a36Sopenharmony_ci uint16_t i; 44162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 44262306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 44362306a36Sopenharmony_ci struct ct_sns_req *ct_req; 44462306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 44562306a36Sopenharmony_ci struct ct_arg arg; 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 44862306a36Sopenharmony_ci return qla2x00_sns_gnn_id(vha, list); 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 45162306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 45262306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 45362306a36Sopenharmony_ci arg.req_size = GNN_ID_REQ_SIZE; 45462306a36Sopenharmony_ci arg.rsp_size = GNN_ID_RSP_SIZE; 45562306a36Sopenharmony_ci arg.nport_handle = NPH_SNS; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 45862306a36Sopenharmony_ci /* Issue GNN_ID */ 45962306a36Sopenharmony_ci /* Prepare common MS IOCB */ 46062306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_iocb(vha, &arg); 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci /* Prepare CT request */ 46362306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ha->ct_sns, GNN_ID_CMD, 46462306a36Sopenharmony_ci GNN_ID_RSP_SIZE); 46562306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci /* Prepare CT arguments -- port_id */ 46862306a36Sopenharmony_ci ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* Execute MS IOCB */ 47162306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 47262306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 47362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 47462306a36Sopenharmony_ci /*EMPTY*/ 47562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2057, 47662306a36Sopenharmony_ci "GNN_ID issue IOCB failed (%d).\n", rval); 47762306a36Sopenharmony_ci break; 47862306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, 47962306a36Sopenharmony_ci "GNN_ID") != QLA_SUCCESS) { 48062306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 48162306a36Sopenharmony_ci break; 48262306a36Sopenharmony_ci } else { 48362306a36Sopenharmony_ci /* Save nodename */ 48462306a36Sopenharmony_ci memcpy(list[i].node_name, 48562306a36Sopenharmony_ci ct_rsp->rsp.gnn_id.node_name, WWN_SIZE); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2058, 48862306a36Sopenharmony_ci "GID_PT entry - nn %8phN pn %8phN " 48962306a36Sopenharmony_ci "portid=%02x%02x%02x.\n", 49062306a36Sopenharmony_ci list[i].node_name, list[i].port_name, 49162306a36Sopenharmony_ci list[i].d_id.b.domain, list[i].d_id.b.area, 49262306a36Sopenharmony_ci list[i].d_id.b.al_pa); 49362306a36Sopenharmony_ci } 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_ci /* Last device exit. */ 49662306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 49762306a36Sopenharmony_ci break; 49862306a36Sopenharmony_ci } 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci return (rval); 50162306a36Sopenharmony_ci} 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_cistatic void qla2x00_async_sns_sp_done(srb_t *sp, int rc) 50462306a36Sopenharmony_ci{ 50562306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 50662306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 50762306a36Sopenharmony_ci struct qla_work_evt *e; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci sp->rc = rc; 51062306a36Sopenharmony_ci if (rc == QLA_SUCCESS) { 51162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204f, 51262306a36Sopenharmony_ci "Async done-%s exiting normally.\n", 51362306a36Sopenharmony_ci sp->name); 51462306a36Sopenharmony_ci } else if (rc == QLA_FUNCTION_TIMEOUT) { 51562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204f, 51662306a36Sopenharmony_ci "Async done-%s timeout\n", sp->name); 51762306a36Sopenharmony_ci } else { 51862306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.rsp; 51962306a36Sopenharmony_ci memset(ct_sns, 0, sizeof(*ct_sns)); 52062306a36Sopenharmony_ci sp->retry_count++; 52162306a36Sopenharmony_ci if (sp->retry_count > 3) 52262306a36Sopenharmony_ci goto err; 52362306a36Sopenharmony_ci 52462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204f, 52562306a36Sopenharmony_ci "Async done-%s fail rc %x. Retry count %d\n", 52662306a36Sopenharmony_ci sp->name, rc, sp->retry_count); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_SP_RETRY); 52962306a36Sopenharmony_ci if (!e) 53062306a36Sopenharmony_ci goto err2; 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci e->u.iosb.sp = sp; 53362306a36Sopenharmony_ci qla2x00_post_work(vha, e); 53462306a36Sopenharmony_ci return; 53562306a36Sopenharmony_ci } 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_cierr: 53862306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_UNMAP); 53962306a36Sopenharmony_cierr2: 54062306a36Sopenharmony_ci if (!e) { 54162306a36Sopenharmony_ci /* please ignore kernel warning. otherwise, we have mem leak. */ 54262306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.req) { 54362306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 54462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 54562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 54662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 54762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci 55062306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.rsp) { 55162306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 55262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 55362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp, 55462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma); 55562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = NULL; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci /* ref: INIT */ 55962306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 56062306a36Sopenharmony_ci return; 56162306a36Sopenharmony_ci } 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci e->u.iosb.sp = sp; 56462306a36Sopenharmony_ci qla2x00_post_work(vha, e); 56562306a36Sopenharmony_ci} 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci/** 56862306a36Sopenharmony_ci * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. 56962306a36Sopenharmony_ci * @vha: HA context 57062306a36Sopenharmony_ci * 57162306a36Sopenharmony_ci * Returns 0 on success. 57262306a36Sopenharmony_ci */ 57362306a36Sopenharmony_ciint 57462306a36Sopenharmony_ciqla2x00_rft_id(scsi_qla_host_t *vha) 57562306a36Sopenharmony_ci{ 57662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 57762306a36Sopenharmony_ci 57862306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 57962306a36Sopenharmony_ci return qla2x00_sns_rft_id(vha); 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci return qla_async_rftid(vha, &vha->d_id); 58262306a36Sopenharmony_ci} 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_cistatic int qla_async_rftid(scsi_qla_host_t *vha, port_id_t *d_id) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci int rval = QLA_MEMORY_ALLOC_FAILED; 58762306a36Sopenharmony_ci struct ct_sns_req *ct_req; 58862306a36Sopenharmony_ci srb_t *sp; 58962306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci if (!vha->flags.online) 59262306a36Sopenharmony_ci goto done; 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_ci /* ref: INIT */ 59562306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); 59662306a36Sopenharmony_ci if (!sp) 59762306a36Sopenharmony_ci goto done; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 60062306a36Sopenharmony_ci sp->name = "rft_id"; 60162306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 60262306a36Sopenharmony_ci qla2x00_async_sns_sp_done); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, 60562306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, 60662306a36Sopenharmony_ci GFP_KERNEL); 60762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); 60862306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req) { 60962306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd041, 61062306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 61162306a36Sopenharmony_ci __func__); 61262306a36Sopenharmony_ci goto done_free_sp; 61362306a36Sopenharmony_ci } 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, 61662306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.rsp_dma, 61762306a36Sopenharmony_ci GFP_KERNEL); 61862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); 61962306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.rsp) { 62062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd042, 62162306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 62262306a36Sopenharmony_ci __func__); 62362306a36Sopenharmony_ci goto done_free_sp; 62462306a36Sopenharmony_ci } 62562306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.rsp; 62662306a36Sopenharmony_ci memset(ct_sns, 0, sizeof(*ct_sns)); 62762306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci /* Prepare CT request */ 63062306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ct_sns, RFT_ID_CMD, RFT_ID_RSP_SIZE); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci /* Prepare CT arguments -- port_id, FC-4 types */ 63362306a36Sopenharmony_ci ct_req->req.rft_id.port_id = port_id_to_be_id(vha->d_id); 63462306a36Sopenharmony_ci ct_req->req.rft_id.fc4_types[2] = 0x01; /* FCP-3 */ 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (vha->flags.nvme_enabled && qla_ini_mode_enabled(vha)) 63762306a36Sopenharmony_ci ct_req->req.rft_id.fc4_types[6] = 1; /* NVMe type 28h */ 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = RFT_ID_REQ_SIZE; 64062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = RFT_ID_RSP_SIZE; 64162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 64462306a36Sopenharmony_ci "Async-%s - hdl=%x portid %06x.\n", 64562306a36Sopenharmony_ci sp->name, sp->handle, d_id->b24); 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 64862306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 64962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2043, 65062306a36Sopenharmony_ci "RFT_ID issue IOCB failed (%d).\n", rval); 65162306a36Sopenharmony_ci goto done_free_sp; 65262306a36Sopenharmony_ci } 65362306a36Sopenharmony_ci return rval; 65462306a36Sopenharmony_cidone_free_sp: 65562306a36Sopenharmony_ci /* ref: INIT */ 65662306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 65762306a36Sopenharmony_cidone: 65862306a36Sopenharmony_ci return rval; 65962306a36Sopenharmony_ci} 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci/** 66262306a36Sopenharmony_ci * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA. 66362306a36Sopenharmony_ci * @vha: HA context 66462306a36Sopenharmony_ci * @type: not used 66562306a36Sopenharmony_ci * 66662306a36Sopenharmony_ci * Returns 0 on success. 66762306a36Sopenharmony_ci */ 66862306a36Sopenharmony_ciint 66962306a36Sopenharmony_ciqla2x00_rff_id(scsi_qla_host_t *vha, u8 type) 67062306a36Sopenharmony_ci{ 67162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) { 67462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2046, 67562306a36Sopenharmony_ci "RFF_ID call not supported on ISP2100/ISP2200.\n"); 67662306a36Sopenharmony_ci return (QLA_SUCCESS); 67762306a36Sopenharmony_ci } 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci return qla_async_rffid(vha, &vha->d_id, qlt_rff_id(vha), type); 68062306a36Sopenharmony_ci} 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_cistatic int qla_async_rffid(scsi_qla_host_t *vha, port_id_t *d_id, 68362306a36Sopenharmony_ci u8 fc4feature, u8 fc4type) 68462306a36Sopenharmony_ci{ 68562306a36Sopenharmony_ci int rval = QLA_MEMORY_ALLOC_FAILED; 68662306a36Sopenharmony_ci struct ct_sns_req *ct_req; 68762306a36Sopenharmony_ci srb_t *sp; 68862306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* ref: INIT */ 69162306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); 69262306a36Sopenharmony_ci if (!sp) 69362306a36Sopenharmony_ci goto done; 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 69662306a36Sopenharmony_ci sp->name = "rff_id"; 69762306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 69862306a36Sopenharmony_ci qla2x00_async_sns_sp_done); 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, 70162306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, 70262306a36Sopenharmony_ci GFP_KERNEL); 70362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); 70462306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req) { 70562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd041, 70662306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 70762306a36Sopenharmony_ci __func__); 70862306a36Sopenharmony_ci goto done_free_sp; 70962306a36Sopenharmony_ci } 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, 71262306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.rsp_dma, 71362306a36Sopenharmony_ci GFP_KERNEL); 71462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); 71562306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.rsp) { 71662306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd042, 71762306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 71862306a36Sopenharmony_ci __func__); 71962306a36Sopenharmony_ci goto done_free_sp; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.rsp; 72262306a36Sopenharmony_ci memset(ct_sns, 0, sizeof(*ct_sns)); 72362306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci /* Prepare CT request */ 72662306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ct_sns, RFF_ID_CMD, RFF_ID_RSP_SIZE); 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci /* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */ 72962306a36Sopenharmony_ci ct_req->req.rff_id.port_id = port_id_to_be_id(*d_id); 73062306a36Sopenharmony_ci ct_req->req.rff_id.fc4_feature = fc4feature; 73162306a36Sopenharmony_ci ct_req->req.rff_id.fc4_type = fc4type; /* SCSI-FCP or FC-NVMe */ 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = RFF_ID_REQ_SIZE; 73462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = RFF_ID_RSP_SIZE; 73562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 73862306a36Sopenharmony_ci "Async-%s - hdl=%x portid %06x feature %x type %x.\n", 73962306a36Sopenharmony_ci sp->name, sp->handle, d_id->b24, fc4feature, fc4type); 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 74262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 74362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2047, 74462306a36Sopenharmony_ci "RFF_ID issue IOCB failed (%d).\n", rval); 74562306a36Sopenharmony_ci goto done_free_sp; 74662306a36Sopenharmony_ci } 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci return rval; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_cidone_free_sp: 75162306a36Sopenharmony_ci /* ref: INIT */ 75262306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 75362306a36Sopenharmony_cidone: 75462306a36Sopenharmony_ci return rval; 75562306a36Sopenharmony_ci} 75662306a36Sopenharmony_ci 75762306a36Sopenharmony_ci/** 75862306a36Sopenharmony_ci * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. 75962306a36Sopenharmony_ci * @vha: HA context 76062306a36Sopenharmony_ci * 76162306a36Sopenharmony_ci * Returns 0 on success. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ciint 76462306a36Sopenharmony_ciqla2x00_rnn_id(scsi_qla_host_t *vha) 76562306a36Sopenharmony_ci{ 76662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) 76962306a36Sopenharmony_ci return qla2x00_sns_rnn_id(vha); 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return qla_async_rnnid(vha, &vha->d_id, vha->node_name); 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic int qla_async_rnnid(scsi_qla_host_t *vha, port_id_t *d_id, 77562306a36Sopenharmony_ci u8 *node_name) 77662306a36Sopenharmony_ci{ 77762306a36Sopenharmony_ci int rval = QLA_MEMORY_ALLOC_FAILED; 77862306a36Sopenharmony_ci struct ct_sns_req *ct_req; 77962306a36Sopenharmony_ci srb_t *sp; 78062306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci /* ref: INIT */ 78362306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); 78462306a36Sopenharmony_ci if (!sp) 78562306a36Sopenharmony_ci goto done; 78662306a36Sopenharmony_ci 78762306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 78862306a36Sopenharmony_ci sp->name = "rnid"; 78962306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 79062306a36Sopenharmony_ci qla2x00_async_sns_sp_done); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, 79362306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, 79462306a36Sopenharmony_ci GFP_KERNEL); 79562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); 79662306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req) { 79762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd041, 79862306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 79962306a36Sopenharmony_ci __func__); 80062306a36Sopenharmony_ci goto done_free_sp; 80162306a36Sopenharmony_ci } 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, 80462306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.rsp_dma, 80562306a36Sopenharmony_ci GFP_KERNEL); 80662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); 80762306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.rsp) { 80862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd042, 80962306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 81062306a36Sopenharmony_ci __func__); 81162306a36Sopenharmony_ci goto done_free_sp; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.rsp; 81462306a36Sopenharmony_ci memset(ct_sns, 0, sizeof(*ct_sns)); 81562306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci /* Prepare CT request */ 81862306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ct_sns, RNN_ID_CMD, RNN_ID_RSP_SIZE); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci /* Prepare CT arguments -- port_id, node_name */ 82162306a36Sopenharmony_ci ct_req->req.rnn_id.port_id = port_id_to_be_id(vha->d_id); 82262306a36Sopenharmony_ci memcpy(ct_req->req.rnn_id.node_name, vha->node_name, WWN_SIZE); 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = RNN_ID_REQ_SIZE; 82562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = RNN_ID_RSP_SIZE; 82662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 82962306a36Sopenharmony_ci "Async-%s - hdl=%x portid %06x\n", 83062306a36Sopenharmony_ci sp->name, sp->handle, d_id->b24); 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 83362306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 83462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204d, 83562306a36Sopenharmony_ci "RNN_ID issue IOCB failed (%d).\n", rval); 83662306a36Sopenharmony_ci goto done_free_sp; 83762306a36Sopenharmony_ci } 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci return rval; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_cidone_free_sp: 84262306a36Sopenharmony_ci /* ref: INIT */ 84362306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 84462306a36Sopenharmony_cidone: 84562306a36Sopenharmony_ci return rval; 84662306a36Sopenharmony_ci} 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_cisize_t 84962306a36Sopenharmony_ciqla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn, size_t size) 85062306a36Sopenharmony_ci{ 85162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci if (IS_QLAFX00(ha)) 85462306a36Sopenharmony_ci return scnprintf(snn, size, "%s FW:v%s DVR:v%s", 85562306a36Sopenharmony_ci ha->model_number, ha->mr.fw_version, qla2x00_version_str); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci return scnprintf(snn, size, "%s FW:v%d.%02d.%02d DVR:v%s", 85862306a36Sopenharmony_ci ha->model_number, ha->fw_major_version, ha->fw_minor_version, 85962306a36Sopenharmony_ci ha->fw_subminor_version, qla2x00_version_str); 86062306a36Sopenharmony_ci} 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci/** 86362306a36Sopenharmony_ci * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA. 86462306a36Sopenharmony_ci * @vha: HA context 86562306a36Sopenharmony_ci * 86662306a36Sopenharmony_ci * Returns 0 on success. 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ciint 86962306a36Sopenharmony_ciqla2x00_rsnn_nn(scsi_qla_host_t *vha) 87062306a36Sopenharmony_ci{ 87162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha)) { 87462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2050, 87562306a36Sopenharmony_ci "RSNN_ID call unsupported on ISP2100/ISP2200.\n"); 87662306a36Sopenharmony_ci return (QLA_SUCCESS); 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci return qla_async_rsnn_nn(vha); 88062306a36Sopenharmony_ci} 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_cistatic int qla_async_rsnn_nn(scsi_qla_host_t *vha) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci int rval = QLA_MEMORY_ALLOC_FAILED; 88562306a36Sopenharmony_ci struct ct_sns_req *ct_req; 88662306a36Sopenharmony_ci srb_t *sp; 88762306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* ref: INIT */ 89062306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); 89162306a36Sopenharmony_ci if (!sp) 89262306a36Sopenharmony_ci goto done; 89362306a36Sopenharmony_ci 89462306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 89562306a36Sopenharmony_ci sp->name = "rsnn_nn"; 89662306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 89762306a36Sopenharmony_ci qla2x00_async_sns_sp_done); 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, 90062306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.req_dma, 90162306a36Sopenharmony_ci GFP_KERNEL); 90262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); 90362306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req) { 90462306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd041, 90562306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 90662306a36Sopenharmony_ci __func__); 90762306a36Sopenharmony_ci goto done_free_sp; 90862306a36Sopenharmony_ci } 90962306a36Sopenharmony_ci 91062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, 91162306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), &sp->u.iocb_cmd.u.ctarg.rsp_dma, 91262306a36Sopenharmony_ci GFP_KERNEL); 91362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); 91462306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.rsp) { 91562306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd042, 91662306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 91762306a36Sopenharmony_ci __func__); 91862306a36Sopenharmony_ci goto done_free_sp; 91962306a36Sopenharmony_ci } 92062306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.rsp; 92162306a36Sopenharmony_ci memset(ct_sns, 0, sizeof(*ct_sns)); 92262306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci /* Prepare CT request */ 92562306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ct_sns, RSNN_NN_CMD, RSNN_NN_RSP_SIZE); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci /* Prepare CT arguments -- node_name, symbolic node_name, size */ 92862306a36Sopenharmony_ci memcpy(ct_req->req.rsnn_nn.node_name, vha->node_name, WWN_SIZE); 92962306a36Sopenharmony_ci 93062306a36Sopenharmony_ci /* Prepare the Symbolic Node Name */ 93162306a36Sopenharmony_ci qla2x00_get_sym_node_name(vha, ct_req->req.rsnn_nn.sym_node_name, 93262306a36Sopenharmony_ci sizeof(ct_req->req.rsnn_nn.sym_node_name)); 93362306a36Sopenharmony_ci ct_req->req.rsnn_nn.name_len = 93462306a36Sopenharmony_ci (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name); 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = 24 + 1 + ct_req->req.rsnn_nn.name_len; 93862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = RSNN_NN_RSP_SIZE; 93962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 94262306a36Sopenharmony_ci "Async-%s - hdl=%x.\n", 94362306a36Sopenharmony_ci sp->name, sp->handle); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 94662306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 94762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2043, 94862306a36Sopenharmony_ci "RFT_ID issue IOCB failed (%d).\n", rval); 94962306a36Sopenharmony_ci goto done_free_sp; 95062306a36Sopenharmony_ci } 95162306a36Sopenharmony_ci 95262306a36Sopenharmony_ci return rval; 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cidone_free_sp: 95562306a36Sopenharmony_ci /* ref: INIT */ 95662306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 95762306a36Sopenharmony_cidone: 95862306a36Sopenharmony_ci return rval; 95962306a36Sopenharmony_ci} 96062306a36Sopenharmony_ci 96162306a36Sopenharmony_ci/** 96262306a36Sopenharmony_ci * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query. 96362306a36Sopenharmony_ci * @vha: HA context 96462306a36Sopenharmony_ci * @cmd: GS command 96562306a36Sopenharmony_ci * @scmd_len: Subcommand length 96662306a36Sopenharmony_ci * @data_size: response size in bytes 96762306a36Sopenharmony_ci * 96862306a36Sopenharmony_ci * Returns a pointer to the @ha's sns_cmd. 96962306a36Sopenharmony_ci */ 97062306a36Sopenharmony_cistatic inline struct sns_cmd_pkt * 97162306a36Sopenharmony_ciqla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len, 97262306a36Sopenharmony_ci uint16_t data_size) 97362306a36Sopenharmony_ci{ 97462306a36Sopenharmony_ci uint16_t wc; 97562306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 97662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 97762306a36Sopenharmony_ci 97862306a36Sopenharmony_ci sns_cmd = ha->sns_cmd; 97962306a36Sopenharmony_ci memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt)); 98062306a36Sopenharmony_ci wc = data_size / 2; /* Size in 16bit words. */ 98162306a36Sopenharmony_ci sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc); 98262306a36Sopenharmony_ci put_unaligned_le64(ha->sns_cmd_dma, &sns_cmd->p.cmd.buffer_address); 98362306a36Sopenharmony_ci sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len); 98462306a36Sopenharmony_ci sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd); 98562306a36Sopenharmony_ci wc = (data_size - 16) / 4; /* Size in 32bit words. */ 98662306a36Sopenharmony_ci sns_cmd->p.cmd.size = cpu_to_le16(wc); 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci vha->qla_stats.control_requests++; 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci return (sns_cmd); 99162306a36Sopenharmony_ci} 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci/** 99462306a36Sopenharmony_ci * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command. 99562306a36Sopenharmony_ci * @vha: HA context 99662306a36Sopenharmony_ci * @fcport: fcport entry to updated 99762306a36Sopenharmony_ci * 99862306a36Sopenharmony_ci * This command uses the old Exectute SNS Command mailbox routine. 99962306a36Sopenharmony_ci * 100062306a36Sopenharmony_ci * Returns 0 on success. 100162306a36Sopenharmony_ci */ 100262306a36Sopenharmony_cistatic int 100362306a36Sopenharmony_ciqla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport) 100462306a36Sopenharmony_ci{ 100562306a36Sopenharmony_ci int rval = QLA_SUCCESS; 100662306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 100762306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci /* Issue GA_NXT. */ 101062306a36Sopenharmony_ci /* Prepare SNS command request. */ 101162306a36Sopenharmony_ci sns_cmd = qla2x00_prep_sns_cmd(vha, GA_NXT_CMD, GA_NXT_SNS_SCMD_LEN, 101262306a36Sopenharmony_ci GA_NXT_SNS_DATA_SIZE); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci /* Prepare SNS command arguments -- port_id. */ 101562306a36Sopenharmony_ci sns_cmd->p.cmd.param[0] = fcport->d_id.b.al_pa; 101662306a36Sopenharmony_ci sns_cmd->p.cmd.param[1] = fcport->d_id.b.area; 101762306a36Sopenharmony_ci sns_cmd->p.cmd.param[2] = fcport->d_id.b.domain; 101862306a36Sopenharmony_ci 101962306a36Sopenharmony_ci /* Execute SNS command. */ 102062306a36Sopenharmony_ci rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, GA_NXT_SNS_CMD_SIZE / 2, 102162306a36Sopenharmony_ci sizeof(struct sns_cmd_pkt)); 102262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 102362306a36Sopenharmony_ci /*EMPTY*/ 102462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x205f, 102562306a36Sopenharmony_ci "GA_NXT Send SNS failed (%d).\n", rval); 102662306a36Sopenharmony_ci } else if (sns_cmd->p.gan_data[8] != 0x80 || 102762306a36Sopenharmony_ci sns_cmd->p.gan_data[9] != 0x02) { 102862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2084, 102962306a36Sopenharmony_ci "GA_NXT failed, rejected request ga_nxt_rsp:\n"); 103062306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2074, 103162306a36Sopenharmony_ci sns_cmd->p.gan_data, 16); 103262306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 103362306a36Sopenharmony_ci } else { 103462306a36Sopenharmony_ci /* Populate fc_port_t entry. */ 103562306a36Sopenharmony_ci fcport->d_id.b.domain = sns_cmd->p.gan_data[17]; 103662306a36Sopenharmony_ci fcport->d_id.b.area = sns_cmd->p.gan_data[18]; 103762306a36Sopenharmony_ci fcport->d_id.b.al_pa = sns_cmd->p.gan_data[19]; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci memcpy(fcport->node_name, &sns_cmd->p.gan_data[284], WWN_SIZE); 104062306a36Sopenharmony_ci memcpy(fcport->port_name, &sns_cmd->p.gan_data[20], WWN_SIZE); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci if (sns_cmd->p.gan_data[16] != NS_N_PORT_TYPE && 104362306a36Sopenharmony_ci sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE) 104462306a36Sopenharmony_ci fcport->d_id.b.domain = 0xf0; 104562306a36Sopenharmony_ci 104662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2061, 104762306a36Sopenharmony_ci "GA_NXT entry - nn %8phN pn %8phN " 104862306a36Sopenharmony_ci "port_id=%02x%02x%02x.\n", 104962306a36Sopenharmony_ci fcport->node_name, fcport->port_name, 105062306a36Sopenharmony_ci fcport->d_id.b.domain, fcport->d_id.b.area, 105162306a36Sopenharmony_ci fcport->d_id.b.al_pa); 105262306a36Sopenharmony_ci } 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return (rval); 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_ci/** 105862306a36Sopenharmony_ci * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command. 105962306a36Sopenharmony_ci * @vha: HA context 106062306a36Sopenharmony_ci * @list: switch info entries to populate 106162306a36Sopenharmony_ci * 106262306a36Sopenharmony_ci * This command uses the old Exectute SNS Command mailbox routine. 106362306a36Sopenharmony_ci * 106462306a36Sopenharmony_ci * NOTE: Non-Nx_Ports are not requested. 106562306a36Sopenharmony_ci * 106662306a36Sopenharmony_ci * Returns 0 on success. 106762306a36Sopenharmony_ci */ 106862306a36Sopenharmony_cistatic int 106962306a36Sopenharmony_ciqla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list) 107062306a36Sopenharmony_ci{ 107162306a36Sopenharmony_ci int rval; 107262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 107362306a36Sopenharmony_ci uint16_t i; 107462306a36Sopenharmony_ci uint8_t *entry; 107562306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 107662306a36Sopenharmony_ci uint16_t gid_pt_sns_data_size; 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci gid_pt_sns_data_size = qla2x00_gid_pt_rsp_size(vha); 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci /* Issue GID_PT. */ 108162306a36Sopenharmony_ci /* Prepare SNS command request. */ 108262306a36Sopenharmony_ci sns_cmd = qla2x00_prep_sns_cmd(vha, GID_PT_CMD, GID_PT_SNS_SCMD_LEN, 108362306a36Sopenharmony_ci gid_pt_sns_data_size); 108462306a36Sopenharmony_ci 108562306a36Sopenharmony_ci /* Prepare SNS command arguments -- port_type. */ 108662306a36Sopenharmony_ci sns_cmd->p.cmd.param[0] = NS_NX_PORT_TYPE; 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci /* Execute SNS command. */ 108962306a36Sopenharmony_ci rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, GID_PT_SNS_CMD_SIZE / 2, 109062306a36Sopenharmony_ci sizeof(struct sns_cmd_pkt)); 109162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 109262306a36Sopenharmony_ci /*EMPTY*/ 109362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x206d, 109462306a36Sopenharmony_ci "GID_PT Send SNS failed (%d).\n", rval); 109562306a36Sopenharmony_ci } else if (sns_cmd->p.gid_data[8] != 0x80 || 109662306a36Sopenharmony_ci sns_cmd->p.gid_data[9] != 0x02) { 109762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x202f, 109862306a36Sopenharmony_ci "GID_PT failed, rejected request, gid_rsp:\n"); 109962306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2081, 110062306a36Sopenharmony_ci sns_cmd->p.gid_data, 16); 110162306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 110262306a36Sopenharmony_ci } else { 110362306a36Sopenharmony_ci /* Set port IDs in switch info list. */ 110462306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 110562306a36Sopenharmony_ci entry = &sns_cmd->p.gid_data[(i * 4) + 16]; 110662306a36Sopenharmony_ci list[i].d_id.b.domain = entry[1]; 110762306a36Sopenharmony_ci list[i].d_id.b.area = entry[2]; 110862306a36Sopenharmony_ci list[i].d_id.b.al_pa = entry[3]; 110962306a36Sopenharmony_ci 111062306a36Sopenharmony_ci /* Last one exit. */ 111162306a36Sopenharmony_ci if (entry[0] & BIT_7) { 111262306a36Sopenharmony_ci list[i].d_id.b.rsvd_1 = entry[0]; 111362306a36Sopenharmony_ci break; 111462306a36Sopenharmony_ci } 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* 111862306a36Sopenharmony_ci * If we've used all available slots, then the switch is 111962306a36Sopenharmony_ci * reporting back more devices that we can handle with this 112062306a36Sopenharmony_ci * single call. Return a failed status, and let GA_NXT handle 112162306a36Sopenharmony_ci * the overload. 112262306a36Sopenharmony_ci */ 112362306a36Sopenharmony_ci if (i == ha->max_fibre_devices) 112462306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci return (rval); 112862306a36Sopenharmony_ci} 112962306a36Sopenharmony_ci 113062306a36Sopenharmony_ci/** 113162306a36Sopenharmony_ci * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query. 113262306a36Sopenharmony_ci * @vha: HA context 113362306a36Sopenharmony_ci * @list: switch info entries to populate 113462306a36Sopenharmony_ci * 113562306a36Sopenharmony_ci * This command uses the old Exectute SNS Command mailbox routine. 113662306a36Sopenharmony_ci * 113762306a36Sopenharmony_ci * Returns 0 on success. 113862306a36Sopenharmony_ci */ 113962306a36Sopenharmony_cistatic int 114062306a36Sopenharmony_ciqla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list) 114162306a36Sopenharmony_ci{ 114262306a36Sopenharmony_ci int rval = QLA_SUCCESS; 114362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 114462306a36Sopenharmony_ci uint16_t i; 114562306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 114662306a36Sopenharmony_ci 114762306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 114862306a36Sopenharmony_ci /* Issue GPN_ID */ 114962306a36Sopenharmony_ci /* Prepare SNS command request. */ 115062306a36Sopenharmony_ci sns_cmd = qla2x00_prep_sns_cmd(vha, GPN_ID_CMD, 115162306a36Sopenharmony_ci GPN_ID_SNS_SCMD_LEN, GPN_ID_SNS_DATA_SIZE); 115262306a36Sopenharmony_ci 115362306a36Sopenharmony_ci /* Prepare SNS command arguments -- port_id. */ 115462306a36Sopenharmony_ci sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa; 115562306a36Sopenharmony_ci sns_cmd->p.cmd.param[1] = list[i].d_id.b.area; 115662306a36Sopenharmony_ci sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain; 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_ci /* Execute SNS command. */ 115962306a36Sopenharmony_ci rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, 116062306a36Sopenharmony_ci GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt)); 116162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 116262306a36Sopenharmony_ci /*EMPTY*/ 116362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2032, 116462306a36Sopenharmony_ci "GPN_ID Send SNS failed (%d).\n", rval); 116562306a36Sopenharmony_ci } else if (sns_cmd->p.gpn_data[8] != 0x80 || 116662306a36Sopenharmony_ci sns_cmd->p.gpn_data[9] != 0x02) { 116762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e, 116862306a36Sopenharmony_ci "GPN_ID failed, rejected request, gpn_rsp:\n"); 116962306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207f, 117062306a36Sopenharmony_ci sns_cmd->p.gpn_data, 16); 117162306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 117262306a36Sopenharmony_ci } else { 117362306a36Sopenharmony_ci /* Save portname */ 117462306a36Sopenharmony_ci memcpy(list[i].port_name, &sns_cmd->p.gpn_data[16], 117562306a36Sopenharmony_ci WWN_SIZE); 117662306a36Sopenharmony_ci } 117762306a36Sopenharmony_ci 117862306a36Sopenharmony_ci /* Last device exit. */ 117962306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 118062306a36Sopenharmony_ci break; 118162306a36Sopenharmony_ci } 118262306a36Sopenharmony_ci 118362306a36Sopenharmony_ci return (rval); 118462306a36Sopenharmony_ci} 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci/** 118762306a36Sopenharmony_ci * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query. 118862306a36Sopenharmony_ci * @vha: HA context 118962306a36Sopenharmony_ci * @list: switch info entries to populate 119062306a36Sopenharmony_ci * 119162306a36Sopenharmony_ci * This command uses the old Exectute SNS Command mailbox routine. 119262306a36Sopenharmony_ci * 119362306a36Sopenharmony_ci * Returns 0 on success. 119462306a36Sopenharmony_ci */ 119562306a36Sopenharmony_cistatic int 119662306a36Sopenharmony_ciqla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list) 119762306a36Sopenharmony_ci{ 119862306a36Sopenharmony_ci int rval = QLA_SUCCESS; 119962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 120062306a36Sopenharmony_ci uint16_t i; 120162306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 120262306a36Sopenharmony_ci 120362306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 120462306a36Sopenharmony_ci /* Issue GNN_ID */ 120562306a36Sopenharmony_ci /* Prepare SNS command request. */ 120662306a36Sopenharmony_ci sns_cmd = qla2x00_prep_sns_cmd(vha, GNN_ID_CMD, 120762306a36Sopenharmony_ci GNN_ID_SNS_SCMD_LEN, GNN_ID_SNS_DATA_SIZE); 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci /* Prepare SNS command arguments -- port_id. */ 121062306a36Sopenharmony_ci sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa; 121162306a36Sopenharmony_ci sns_cmd->p.cmd.param[1] = list[i].d_id.b.area; 121262306a36Sopenharmony_ci sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain; 121362306a36Sopenharmony_ci 121462306a36Sopenharmony_ci /* Execute SNS command. */ 121562306a36Sopenharmony_ci rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, 121662306a36Sopenharmony_ci GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt)); 121762306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 121862306a36Sopenharmony_ci /*EMPTY*/ 121962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x203f, 122062306a36Sopenharmony_ci "GNN_ID Send SNS failed (%d).\n", rval); 122162306a36Sopenharmony_ci } else if (sns_cmd->p.gnn_data[8] != 0x80 || 122262306a36Sopenharmony_ci sns_cmd->p.gnn_data[9] != 0x02) { 122362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2082, 122462306a36Sopenharmony_ci "GNN_ID failed, rejected request, gnn_rsp:\n"); 122562306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207a, 122662306a36Sopenharmony_ci sns_cmd->p.gnn_data, 16); 122762306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 122862306a36Sopenharmony_ci } else { 122962306a36Sopenharmony_ci /* Save nodename */ 123062306a36Sopenharmony_ci memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16], 123162306a36Sopenharmony_ci WWN_SIZE); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x206e, 123462306a36Sopenharmony_ci "GID_PT entry - nn %8phN pn %8phN " 123562306a36Sopenharmony_ci "port_id=%02x%02x%02x.\n", 123662306a36Sopenharmony_ci list[i].node_name, list[i].port_name, 123762306a36Sopenharmony_ci list[i].d_id.b.domain, list[i].d_id.b.area, 123862306a36Sopenharmony_ci list[i].d_id.b.al_pa); 123962306a36Sopenharmony_ci } 124062306a36Sopenharmony_ci 124162306a36Sopenharmony_ci /* Last device exit. */ 124262306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 124362306a36Sopenharmony_ci break; 124462306a36Sopenharmony_ci } 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci return (rval); 124762306a36Sopenharmony_ci} 124862306a36Sopenharmony_ci 124962306a36Sopenharmony_ci/** 125062306a36Sopenharmony_ci * qla2x00_sns_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA. 125162306a36Sopenharmony_ci * @vha: HA context 125262306a36Sopenharmony_ci * 125362306a36Sopenharmony_ci * This command uses the old Exectute SNS Command mailbox routine. 125462306a36Sopenharmony_ci * 125562306a36Sopenharmony_ci * Returns 0 on success. 125662306a36Sopenharmony_ci */ 125762306a36Sopenharmony_cistatic int 125862306a36Sopenharmony_ciqla2x00_sns_rft_id(scsi_qla_host_t *vha) 125962306a36Sopenharmony_ci{ 126062306a36Sopenharmony_ci int rval; 126162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 126262306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 126362306a36Sopenharmony_ci 126462306a36Sopenharmony_ci /* Issue RFT_ID. */ 126562306a36Sopenharmony_ci /* Prepare SNS command request. */ 126662306a36Sopenharmony_ci sns_cmd = qla2x00_prep_sns_cmd(vha, RFT_ID_CMD, RFT_ID_SNS_SCMD_LEN, 126762306a36Sopenharmony_ci RFT_ID_SNS_DATA_SIZE); 126862306a36Sopenharmony_ci 126962306a36Sopenharmony_ci /* Prepare SNS command arguments -- port_id, FC-4 types */ 127062306a36Sopenharmony_ci sns_cmd->p.cmd.param[0] = vha->d_id.b.al_pa; 127162306a36Sopenharmony_ci sns_cmd->p.cmd.param[1] = vha->d_id.b.area; 127262306a36Sopenharmony_ci sns_cmd->p.cmd.param[2] = vha->d_id.b.domain; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci sns_cmd->p.cmd.param[5] = 0x01; /* FCP-3 */ 127562306a36Sopenharmony_ci 127662306a36Sopenharmony_ci /* Execute SNS command. */ 127762306a36Sopenharmony_ci rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, RFT_ID_SNS_CMD_SIZE / 2, 127862306a36Sopenharmony_ci sizeof(struct sns_cmd_pkt)); 127962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 128062306a36Sopenharmony_ci /*EMPTY*/ 128162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2060, 128262306a36Sopenharmony_ci "RFT_ID Send SNS failed (%d).\n", rval); 128362306a36Sopenharmony_ci } else if (sns_cmd->p.rft_data[8] != 0x80 || 128462306a36Sopenharmony_ci sns_cmd->p.rft_data[9] != 0x02) { 128562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2083, 128662306a36Sopenharmony_ci "RFT_ID failed, rejected request rft_rsp:\n"); 128762306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2080, 128862306a36Sopenharmony_ci sns_cmd->p.rft_data, 16); 128962306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 129062306a36Sopenharmony_ci } else { 129162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2073, 129262306a36Sopenharmony_ci "RFT_ID exiting normally.\n"); 129362306a36Sopenharmony_ci } 129462306a36Sopenharmony_ci 129562306a36Sopenharmony_ci return (rval); 129662306a36Sopenharmony_ci} 129762306a36Sopenharmony_ci 129862306a36Sopenharmony_ci/** 129962306a36Sopenharmony_ci * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA. 130062306a36Sopenharmony_ci * @vha: HA context 130162306a36Sopenharmony_ci * 130262306a36Sopenharmony_ci * This command uses the old Exectute SNS Command mailbox routine. 130362306a36Sopenharmony_ci * 130462306a36Sopenharmony_ci * Returns 0 on success. 130562306a36Sopenharmony_ci */ 130662306a36Sopenharmony_cistatic int 130762306a36Sopenharmony_ciqla2x00_sns_rnn_id(scsi_qla_host_t *vha) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci int rval; 131062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 131162306a36Sopenharmony_ci struct sns_cmd_pkt *sns_cmd; 131262306a36Sopenharmony_ci 131362306a36Sopenharmony_ci /* Issue RNN_ID. */ 131462306a36Sopenharmony_ci /* Prepare SNS command request. */ 131562306a36Sopenharmony_ci sns_cmd = qla2x00_prep_sns_cmd(vha, RNN_ID_CMD, RNN_ID_SNS_SCMD_LEN, 131662306a36Sopenharmony_ci RNN_ID_SNS_DATA_SIZE); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci /* Prepare SNS command arguments -- port_id, nodename. */ 131962306a36Sopenharmony_ci sns_cmd->p.cmd.param[0] = vha->d_id.b.al_pa; 132062306a36Sopenharmony_ci sns_cmd->p.cmd.param[1] = vha->d_id.b.area; 132162306a36Sopenharmony_ci sns_cmd->p.cmd.param[2] = vha->d_id.b.domain; 132262306a36Sopenharmony_ci 132362306a36Sopenharmony_ci sns_cmd->p.cmd.param[4] = vha->node_name[7]; 132462306a36Sopenharmony_ci sns_cmd->p.cmd.param[5] = vha->node_name[6]; 132562306a36Sopenharmony_ci sns_cmd->p.cmd.param[6] = vha->node_name[5]; 132662306a36Sopenharmony_ci sns_cmd->p.cmd.param[7] = vha->node_name[4]; 132762306a36Sopenharmony_ci sns_cmd->p.cmd.param[8] = vha->node_name[3]; 132862306a36Sopenharmony_ci sns_cmd->p.cmd.param[9] = vha->node_name[2]; 132962306a36Sopenharmony_ci sns_cmd->p.cmd.param[10] = vha->node_name[1]; 133062306a36Sopenharmony_ci sns_cmd->p.cmd.param[11] = vha->node_name[0]; 133162306a36Sopenharmony_ci 133262306a36Sopenharmony_ci /* Execute SNS command. */ 133362306a36Sopenharmony_ci rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, RNN_ID_SNS_CMD_SIZE / 2, 133462306a36Sopenharmony_ci sizeof(struct sns_cmd_pkt)); 133562306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 133662306a36Sopenharmony_ci /*EMPTY*/ 133762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204a, 133862306a36Sopenharmony_ci "RNN_ID Send SNS failed (%d).\n", rval); 133962306a36Sopenharmony_ci } else if (sns_cmd->p.rnn_data[8] != 0x80 || 134062306a36Sopenharmony_ci sns_cmd->p.rnn_data[9] != 0x02) { 134162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207b, 134262306a36Sopenharmony_ci "RNN_ID failed, rejected request, rnn_rsp:\n"); 134362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207c, 134462306a36Sopenharmony_ci sns_cmd->p.rnn_data, 16); 134562306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 134662306a36Sopenharmony_ci } else { 134762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204c, 134862306a36Sopenharmony_ci "RNN_ID exiting normally.\n"); 134962306a36Sopenharmony_ci } 135062306a36Sopenharmony_ci 135162306a36Sopenharmony_ci return (rval); 135262306a36Sopenharmony_ci} 135362306a36Sopenharmony_ci 135462306a36Sopenharmony_ci/** 135562306a36Sopenharmony_ci * qla2x00_mgmt_svr_login() - Login to fabric Management Service. 135662306a36Sopenharmony_ci * @vha: HA context 135762306a36Sopenharmony_ci * 135862306a36Sopenharmony_ci * Returns 0 on success. 135962306a36Sopenharmony_ci */ 136062306a36Sopenharmony_ciint 136162306a36Sopenharmony_ciqla2x00_mgmt_svr_login(scsi_qla_host_t *vha) 136262306a36Sopenharmony_ci{ 136362306a36Sopenharmony_ci int ret, rval; 136462306a36Sopenharmony_ci uint16_t mb[MAILBOX_REGISTER_COUNT]; 136562306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 136662306a36Sopenharmony_ci 136762306a36Sopenharmony_ci ret = QLA_SUCCESS; 136862306a36Sopenharmony_ci if (vha->flags.management_server_logged_in) 136962306a36Sopenharmony_ci return ret; 137062306a36Sopenharmony_ci 137162306a36Sopenharmony_ci rval = ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 137262306a36Sopenharmony_ci 0xfa, mb, BIT_1); 137362306a36Sopenharmony_ci if (rval != QLA_SUCCESS || mb[0] != MBS_COMMAND_COMPLETE) { 137462306a36Sopenharmony_ci if (rval == QLA_MEMORY_ALLOC_FAILED) 137562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2085, 137662306a36Sopenharmony_ci "Failed management_server login: loopid=%x " 137762306a36Sopenharmony_ci "rval=%d\n", vha->mgmt_svr_loop_id, rval); 137862306a36Sopenharmony_ci else 137962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2024, 138062306a36Sopenharmony_ci "Failed management_server login: loopid=%x " 138162306a36Sopenharmony_ci "mb[0]=%x mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n", 138262306a36Sopenharmony_ci vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6], 138362306a36Sopenharmony_ci mb[7]); 138462306a36Sopenharmony_ci ret = QLA_FUNCTION_FAILED; 138562306a36Sopenharmony_ci } else 138662306a36Sopenharmony_ci vha->flags.management_server_logged_in = 1; 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci return ret; 138962306a36Sopenharmony_ci} 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci/** 139262306a36Sopenharmony_ci * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. 139362306a36Sopenharmony_ci * @vha: HA context 139462306a36Sopenharmony_ci * @req_size: request size in bytes 139562306a36Sopenharmony_ci * @rsp_size: response size in bytes 139662306a36Sopenharmony_ci * 139762306a36Sopenharmony_ci * Returns a pointer to the @ha's ms_iocb. 139862306a36Sopenharmony_ci */ 139962306a36Sopenharmony_civoid * 140062306a36Sopenharmony_ciqla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, 140162306a36Sopenharmony_ci uint32_t rsp_size) 140262306a36Sopenharmony_ci{ 140362306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 140462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 140562306a36Sopenharmony_ci 140662306a36Sopenharmony_ci ms_pkt = ha->ms_iocb; 140762306a36Sopenharmony_ci memset(ms_pkt, 0, sizeof(ms_iocb_entry_t)); 140862306a36Sopenharmony_ci 140962306a36Sopenharmony_ci ms_pkt->entry_type = MS_IOCB_TYPE; 141062306a36Sopenharmony_ci ms_pkt->entry_count = 1; 141162306a36Sopenharmony_ci SET_TARGET_ID(ha, ms_pkt->loop_id, vha->mgmt_svr_loop_id); 141262306a36Sopenharmony_ci ms_pkt->control_flags = cpu_to_le16(CF_READ | CF_HEAD_TAG); 141362306a36Sopenharmony_ci ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); 141462306a36Sopenharmony_ci ms_pkt->cmd_dsd_count = cpu_to_le16(1); 141562306a36Sopenharmony_ci ms_pkt->total_dsd_count = cpu_to_le16(2); 141662306a36Sopenharmony_ci ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size); 141762306a36Sopenharmony_ci ms_pkt->req_bytecount = cpu_to_le32(req_size); 141862306a36Sopenharmony_ci 141962306a36Sopenharmony_ci put_unaligned_le64(ha->ct_sns_dma, &ms_pkt->req_dsd.address); 142062306a36Sopenharmony_ci ms_pkt->req_dsd.length = ms_pkt->req_bytecount; 142162306a36Sopenharmony_ci 142262306a36Sopenharmony_ci put_unaligned_le64(ha->ct_sns_dma, &ms_pkt->rsp_dsd.address); 142362306a36Sopenharmony_ci ms_pkt->rsp_dsd.length = ms_pkt->rsp_bytecount; 142462306a36Sopenharmony_ci 142562306a36Sopenharmony_ci return ms_pkt; 142662306a36Sopenharmony_ci} 142762306a36Sopenharmony_ci 142862306a36Sopenharmony_ci/** 142962306a36Sopenharmony_ci * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query. 143062306a36Sopenharmony_ci * @vha: HA context 143162306a36Sopenharmony_ci * @req_size: request size in bytes 143262306a36Sopenharmony_ci * @rsp_size: response size in bytes 143362306a36Sopenharmony_ci * 143462306a36Sopenharmony_ci * Returns a pointer to the @ha's ms_iocb. 143562306a36Sopenharmony_ci */ 143662306a36Sopenharmony_civoid * 143762306a36Sopenharmony_ciqla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size, 143862306a36Sopenharmony_ci uint32_t rsp_size) 143962306a36Sopenharmony_ci{ 144062306a36Sopenharmony_ci struct ct_entry_24xx *ct_pkt; 144162306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 144262306a36Sopenharmony_ci 144362306a36Sopenharmony_ci ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; 144462306a36Sopenharmony_ci memset(ct_pkt, 0, sizeof(struct ct_entry_24xx)); 144562306a36Sopenharmony_ci 144662306a36Sopenharmony_ci ct_pkt->entry_type = CT_IOCB_TYPE; 144762306a36Sopenharmony_ci ct_pkt->entry_count = 1; 144862306a36Sopenharmony_ci ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id); 144962306a36Sopenharmony_ci ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2); 145062306a36Sopenharmony_ci ct_pkt->cmd_dsd_count = cpu_to_le16(1); 145162306a36Sopenharmony_ci ct_pkt->rsp_dsd_count = cpu_to_le16(1); 145262306a36Sopenharmony_ci ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size); 145362306a36Sopenharmony_ci ct_pkt->cmd_byte_count = cpu_to_le32(req_size); 145462306a36Sopenharmony_ci 145562306a36Sopenharmony_ci put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[0].address); 145662306a36Sopenharmony_ci ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count; 145762306a36Sopenharmony_ci 145862306a36Sopenharmony_ci put_unaligned_le64(ha->ct_sns_dma, &ct_pkt->dsd[1].address); 145962306a36Sopenharmony_ci ct_pkt->dsd[1].length = ct_pkt->rsp_byte_count; 146062306a36Sopenharmony_ci ct_pkt->vp_index = vha->vp_idx; 146162306a36Sopenharmony_ci 146262306a36Sopenharmony_ci return ct_pkt; 146362306a36Sopenharmony_ci} 146462306a36Sopenharmony_ci 146562306a36Sopenharmony_cistatic void 146662306a36Sopenharmony_ciqla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size) 146762306a36Sopenharmony_ci{ 146862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 146962306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt = ha->ms_iocb; 147062306a36Sopenharmony_ci struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb; 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 147362306a36Sopenharmony_ci ct_pkt->cmd_byte_count = cpu_to_le32(req_size); 147462306a36Sopenharmony_ci ct_pkt->dsd[0].length = ct_pkt->cmd_byte_count; 147562306a36Sopenharmony_ci } else { 147662306a36Sopenharmony_ci ms_pkt->req_bytecount = cpu_to_le32(req_size); 147762306a36Sopenharmony_ci ms_pkt->req_dsd.length = ms_pkt->req_bytecount; 147862306a36Sopenharmony_ci } 147962306a36Sopenharmony_ci} 148062306a36Sopenharmony_ci 148162306a36Sopenharmony_ci/** 148262306a36Sopenharmony_ci * qla2x00_prep_ct_fdmi_req() - Prepare common CT request fields for SNS query. 148362306a36Sopenharmony_ci * @p: CT request buffer 148462306a36Sopenharmony_ci * @cmd: GS command 148562306a36Sopenharmony_ci * @rsp_size: response size in bytes 148662306a36Sopenharmony_ci * 148762306a36Sopenharmony_ci * Returns a pointer to the intitialized @ct_req. 148862306a36Sopenharmony_ci */ 148962306a36Sopenharmony_cistatic inline struct ct_sns_req * 149062306a36Sopenharmony_ciqla2x00_prep_ct_fdmi_req(struct ct_sns_pkt *p, uint16_t cmd, 149162306a36Sopenharmony_ci uint16_t rsp_size) 149262306a36Sopenharmony_ci{ 149362306a36Sopenharmony_ci memset(p, 0, sizeof(struct ct_sns_pkt)); 149462306a36Sopenharmony_ci 149562306a36Sopenharmony_ci p->p.req.header.revision = 0x01; 149662306a36Sopenharmony_ci p->p.req.header.gs_type = 0xFA; 149762306a36Sopenharmony_ci p->p.req.header.gs_subtype = 0x10; 149862306a36Sopenharmony_ci p->p.req.command = cpu_to_be16(cmd); 149962306a36Sopenharmony_ci p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); 150062306a36Sopenharmony_ci 150162306a36Sopenharmony_ci return &p->p.req; 150262306a36Sopenharmony_ci} 150362306a36Sopenharmony_ci 150462306a36Sopenharmony_ciuint 150562306a36Sopenharmony_ciqla25xx_fdmi_port_speed_capability(struct qla_hw_data *ha) 150662306a36Sopenharmony_ci{ 150762306a36Sopenharmony_ci uint speeds = 0; 150862306a36Sopenharmony_ci 150962306a36Sopenharmony_ci if (IS_CNA_CAPABLE(ha)) 151062306a36Sopenharmony_ci return FDMI_PORT_SPEED_10GB; 151162306a36Sopenharmony_ci if (IS_QLA28XX(ha) || IS_QLA27XX(ha)) { 151262306a36Sopenharmony_ci if (ha->max_supported_speed == 2) { 151362306a36Sopenharmony_ci if (ha->min_supported_speed <= 6) 151462306a36Sopenharmony_ci speeds |= FDMI_PORT_SPEED_64GB; 151562306a36Sopenharmony_ci } 151662306a36Sopenharmony_ci if (ha->max_supported_speed == 2 || 151762306a36Sopenharmony_ci ha->max_supported_speed == 1) { 151862306a36Sopenharmony_ci if (ha->min_supported_speed <= 5) 151962306a36Sopenharmony_ci speeds |= FDMI_PORT_SPEED_32GB; 152062306a36Sopenharmony_ci } 152162306a36Sopenharmony_ci if (ha->max_supported_speed == 2 || 152262306a36Sopenharmony_ci ha->max_supported_speed == 1 || 152362306a36Sopenharmony_ci ha->max_supported_speed == 0) { 152462306a36Sopenharmony_ci if (ha->min_supported_speed <= 4) 152562306a36Sopenharmony_ci speeds |= FDMI_PORT_SPEED_16GB; 152662306a36Sopenharmony_ci } 152762306a36Sopenharmony_ci if (ha->max_supported_speed == 1 || 152862306a36Sopenharmony_ci ha->max_supported_speed == 0) { 152962306a36Sopenharmony_ci if (ha->min_supported_speed <= 3) 153062306a36Sopenharmony_ci speeds |= FDMI_PORT_SPEED_8GB; 153162306a36Sopenharmony_ci } 153262306a36Sopenharmony_ci if (ha->max_supported_speed == 0) { 153362306a36Sopenharmony_ci if (ha->min_supported_speed <= 2) 153462306a36Sopenharmony_ci speeds |= FDMI_PORT_SPEED_4GB; 153562306a36Sopenharmony_ci } 153662306a36Sopenharmony_ci return speeds; 153762306a36Sopenharmony_ci } 153862306a36Sopenharmony_ci if (IS_QLA2031(ha)) { 153962306a36Sopenharmony_ci if ((ha->pdev->subsystem_vendor == 0x103C) && 154062306a36Sopenharmony_ci ((ha->pdev->subsystem_device == 0x8002) || 154162306a36Sopenharmony_ci (ha->pdev->subsystem_device == 0x8086))) { 154262306a36Sopenharmony_ci speeds = FDMI_PORT_SPEED_16GB; 154362306a36Sopenharmony_ci } else { 154462306a36Sopenharmony_ci speeds = FDMI_PORT_SPEED_16GB|FDMI_PORT_SPEED_8GB| 154562306a36Sopenharmony_ci FDMI_PORT_SPEED_4GB; 154662306a36Sopenharmony_ci } 154762306a36Sopenharmony_ci return speeds; 154862306a36Sopenharmony_ci } 154962306a36Sopenharmony_ci if (IS_QLA25XX(ha) || IS_QLAFX00(ha)) 155062306a36Sopenharmony_ci return FDMI_PORT_SPEED_8GB|FDMI_PORT_SPEED_4GB| 155162306a36Sopenharmony_ci FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB; 155262306a36Sopenharmony_ci if (IS_QLA24XX_TYPE(ha)) 155362306a36Sopenharmony_ci return FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_2GB| 155462306a36Sopenharmony_ci FDMI_PORT_SPEED_1GB; 155562306a36Sopenharmony_ci if (IS_QLA23XX(ha)) 155662306a36Sopenharmony_ci return FDMI_PORT_SPEED_2GB|FDMI_PORT_SPEED_1GB; 155762306a36Sopenharmony_ci return FDMI_PORT_SPEED_1GB; 155862306a36Sopenharmony_ci} 155962306a36Sopenharmony_ci 156062306a36Sopenharmony_ciuint 156162306a36Sopenharmony_ciqla25xx_fdmi_port_speed_currently(struct qla_hw_data *ha) 156262306a36Sopenharmony_ci{ 156362306a36Sopenharmony_ci switch (ha->link_data_rate) { 156462306a36Sopenharmony_ci case PORT_SPEED_1GB: 156562306a36Sopenharmony_ci return FDMI_PORT_SPEED_1GB; 156662306a36Sopenharmony_ci case PORT_SPEED_2GB: 156762306a36Sopenharmony_ci return FDMI_PORT_SPEED_2GB; 156862306a36Sopenharmony_ci case PORT_SPEED_4GB: 156962306a36Sopenharmony_ci return FDMI_PORT_SPEED_4GB; 157062306a36Sopenharmony_ci case PORT_SPEED_8GB: 157162306a36Sopenharmony_ci return FDMI_PORT_SPEED_8GB; 157262306a36Sopenharmony_ci case PORT_SPEED_10GB: 157362306a36Sopenharmony_ci return FDMI_PORT_SPEED_10GB; 157462306a36Sopenharmony_ci case PORT_SPEED_16GB: 157562306a36Sopenharmony_ci return FDMI_PORT_SPEED_16GB; 157662306a36Sopenharmony_ci case PORT_SPEED_32GB: 157762306a36Sopenharmony_ci return FDMI_PORT_SPEED_32GB; 157862306a36Sopenharmony_ci case PORT_SPEED_64GB: 157962306a36Sopenharmony_ci return FDMI_PORT_SPEED_64GB; 158062306a36Sopenharmony_ci default: 158162306a36Sopenharmony_ci return FDMI_PORT_SPEED_UNKNOWN; 158262306a36Sopenharmony_ci } 158362306a36Sopenharmony_ci} 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci/** 158662306a36Sopenharmony_ci * qla2x00_hba_attributes() - perform HBA attributes registration 158762306a36Sopenharmony_ci * @vha: HA context 158862306a36Sopenharmony_ci * @entries: number of entries to use 158962306a36Sopenharmony_ci * @callopt: Option to issue extended or standard FDMI 159062306a36Sopenharmony_ci * command parameter 159162306a36Sopenharmony_ci * 159262306a36Sopenharmony_ci * Returns 0 on success. 159362306a36Sopenharmony_ci */ 159462306a36Sopenharmony_cistatic unsigned long 159562306a36Sopenharmony_ciqla2x00_hba_attributes(scsi_qla_host_t *vha, void *entries, 159662306a36Sopenharmony_ci unsigned int callopt) 159762306a36Sopenharmony_ci{ 159862306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 159962306a36Sopenharmony_ci struct new_utsname *p_sysid = utsname(); 160062306a36Sopenharmony_ci struct ct_fdmi_hba_attr *eiter; 160162306a36Sopenharmony_ci uint16_t alen; 160262306a36Sopenharmony_ci unsigned long size = 0; 160362306a36Sopenharmony_ci 160462306a36Sopenharmony_ci /* Nodename. */ 160562306a36Sopenharmony_ci eiter = entries + size; 160662306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_NODE_NAME); 160762306a36Sopenharmony_ci memcpy(eiter->a.node_name, vha->node_name, sizeof(eiter->a.node_name)); 160862306a36Sopenharmony_ci alen = sizeof(eiter->a.node_name); 160962306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 161062306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 161162306a36Sopenharmony_ci size += alen; 161262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a0, 161362306a36Sopenharmony_ci "NODENAME = %016llx.\n", wwn_to_u64(eiter->a.node_name)); 161462306a36Sopenharmony_ci /* Manufacturer. */ 161562306a36Sopenharmony_ci eiter = entries + size; 161662306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_MANUFACTURER); 161762306a36Sopenharmony_ci alen = scnprintf( 161862306a36Sopenharmony_ci eiter->a.manufacturer, sizeof(eiter->a.manufacturer), 161962306a36Sopenharmony_ci "%s", QLA2XXX_MANUFACTURER); 162062306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 162162306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 162262306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 162362306a36Sopenharmony_ci size += alen; 162462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a1, 162562306a36Sopenharmony_ci "MANUFACTURER = %s.\n", eiter->a.manufacturer); 162662306a36Sopenharmony_ci /* Serial number. */ 162762306a36Sopenharmony_ci eiter = entries + size; 162862306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_SERIAL_NUMBER); 162962306a36Sopenharmony_ci alen = 0; 163062306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 163162306a36Sopenharmony_ci alen = qla2xxx_get_vpd_field(vha, "SN", 163262306a36Sopenharmony_ci eiter->a.serial_num, sizeof(eiter->a.serial_num)); 163362306a36Sopenharmony_ci } 163462306a36Sopenharmony_ci if (!alen) { 163562306a36Sopenharmony_ci uint32_t sn = ((ha->serial0 & 0x1f) << 16) | 163662306a36Sopenharmony_ci (ha->serial2 << 8) | ha->serial1; 163762306a36Sopenharmony_ci alen = scnprintf( 163862306a36Sopenharmony_ci eiter->a.serial_num, sizeof(eiter->a.serial_num), 163962306a36Sopenharmony_ci "%c%05d", 'A' + sn / 100000, sn % 100000); 164062306a36Sopenharmony_ci } 164162306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 164262306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 164362306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 164462306a36Sopenharmony_ci size += alen; 164562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a2, 164662306a36Sopenharmony_ci "SERIAL NUMBER = %s.\n", eiter->a.serial_num); 164762306a36Sopenharmony_ci /* Model name. */ 164862306a36Sopenharmony_ci eiter = entries + size; 164962306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_MODEL); 165062306a36Sopenharmony_ci alen = scnprintf( 165162306a36Sopenharmony_ci eiter->a.model, sizeof(eiter->a.model), 165262306a36Sopenharmony_ci "%s", ha->model_number); 165362306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 165462306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 165562306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 165662306a36Sopenharmony_ci size += alen; 165762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a3, 165862306a36Sopenharmony_ci "MODEL NAME = %s.\n", eiter->a.model); 165962306a36Sopenharmony_ci /* Model description. */ 166062306a36Sopenharmony_ci eiter = entries + size; 166162306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION); 166262306a36Sopenharmony_ci alen = scnprintf( 166362306a36Sopenharmony_ci eiter->a.model_desc, sizeof(eiter->a.model_desc), 166462306a36Sopenharmony_ci "%s", ha->model_desc); 166562306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 166662306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 166762306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 166862306a36Sopenharmony_ci size += alen; 166962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a4, 167062306a36Sopenharmony_ci "MODEL DESCRIPTION = %s.\n", eiter->a.model_desc); 167162306a36Sopenharmony_ci /* Hardware version. */ 167262306a36Sopenharmony_ci eiter = entries + size; 167362306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_HARDWARE_VERSION); 167462306a36Sopenharmony_ci alen = 0; 167562306a36Sopenharmony_ci if (IS_FWI2_CAPABLE(ha)) { 167662306a36Sopenharmony_ci if (!alen) { 167762306a36Sopenharmony_ci alen = qla2xxx_get_vpd_field(vha, "MN", 167862306a36Sopenharmony_ci eiter->a.hw_version, sizeof(eiter->a.hw_version)); 167962306a36Sopenharmony_ci } 168062306a36Sopenharmony_ci if (!alen) { 168162306a36Sopenharmony_ci alen = qla2xxx_get_vpd_field(vha, "EC", 168262306a36Sopenharmony_ci eiter->a.hw_version, sizeof(eiter->a.hw_version)); 168362306a36Sopenharmony_ci } 168462306a36Sopenharmony_ci } 168562306a36Sopenharmony_ci if (!alen) { 168662306a36Sopenharmony_ci alen = scnprintf( 168762306a36Sopenharmony_ci eiter->a.hw_version, sizeof(eiter->a.hw_version), 168862306a36Sopenharmony_ci "HW:%s", ha->adapter_id); 168962306a36Sopenharmony_ci } 169062306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 169162306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 169262306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 169362306a36Sopenharmony_ci size += alen; 169462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a5, 169562306a36Sopenharmony_ci "HARDWARE VERSION = %s.\n", eiter->a.hw_version); 169662306a36Sopenharmony_ci /* Driver version. */ 169762306a36Sopenharmony_ci eiter = entries + size; 169862306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_DRIVER_VERSION); 169962306a36Sopenharmony_ci alen = scnprintf( 170062306a36Sopenharmony_ci eiter->a.driver_version, sizeof(eiter->a.driver_version), 170162306a36Sopenharmony_ci "%s", qla2x00_version_str); 170262306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 170362306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 170462306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 170562306a36Sopenharmony_ci size += alen; 170662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a6, 170762306a36Sopenharmony_ci "DRIVER VERSION = %s.\n", eiter->a.driver_version); 170862306a36Sopenharmony_ci /* Option ROM version. */ 170962306a36Sopenharmony_ci eiter = entries + size; 171062306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION); 171162306a36Sopenharmony_ci alen = scnprintf( 171262306a36Sopenharmony_ci eiter->a.orom_version, sizeof(eiter->a.orom_version), 171362306a36Sopenharmony_ci "%d.%02d", ha->bios_revision[1], ha->bios_revision[0]); 171462306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 171562306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 171662306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 171762306a36Sopenharmony_ci size += alen; 171862306a36Sopenharmony_ci 171962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a7, 172062306a36Sopenharmony_ci "OPTROM VERSION = %d.%02d.\n", 172162306a36Sopenharmony_ci eiter->a.orom_version[1], eiter->a.orom_version[0]); 172262306a36Sopenharmony_ci /* Firmware version */ 172362306a36Sopenharmony_ci eiter = entries + size; 172462306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION); 172562306a36Sopenharmony_ci ha->isp_ops->fw_version_str(vha, eiter->a.fw_version, 172662306a36Sopenharmony_ci sizeof(eiter->a.fw_version)); 172762306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 172862306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 172962306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 173062306a36Sopenharmony_ci size += alen; 173162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a8, 173262306a36Sopenharmony_ci "FIRMWARE VERSION = %s.\n", eiter->a.fw_version); 173362306a36Sopenharmony_ci /* OS Name and Version */ 173462306a36Sopenharmony_ci eiter = entries + size; 173562306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_OS_NAME_AND_VERSION); 173662306a36Sopenharmony_ci alen = 0; 173762306a36Sopenharmony_ci if (p_sysid) { 173862306a36Sopenharmony_ci alen = scnprintf( 173962306a36Sopenharmony_ci eiter->a.os_version, sizeof(eiter->a.os_version), 174062306a36Sopenharmony_ci "%s %s %s", 174162306a36Sopenharmony_ci p_sysid->sysname, p_sysid->release, p_sysid->machine); 174262306a36Sopenharmony_ci } 174362306a36Sopenharmony_ci if (!alen) { 174462306a36Sopenharmony_ci alen = scnprintf( 174562306a36Sopenharmony_ci eiter->a.os_version, sizeof(eiter->a.os_version), 174662306a36Sopenharmony_ci "%s %s", 174762306a36Sopenharmony_ci "Linux", fc_host_system_hostname(vha->host)); 174862306a36Sopenharmony_ci } 174962306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 175062306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 175162306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 175262306a36Sopenharmony_ci size += alen; 175362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a9, 175462306a36Sopenharmony_ci "OS VERSION = %s.\n", eiter->a.os_version); 175562306a36Sopenharmony_ci if (callopt == CALLOPT_FDMI1) 175662306a36Sopenharmony_ci goto done; 175762306a36Sopenharmony_ci /* MAX CT Payload Length */ 175862306a36Sopenharmony_ci eiter = entries + size; 175962306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_MAXIMUM_CT_PAYLOAD_LENGTH); 176062306a36Sopenharmony_ci eiter->a.max_ct_len = cpu_to_be32(ha->frame_payload_size >> 2); 176162306a36Sopenharmony_ci 176262306a36Sopenharmony_ci alen = sizeof(eiter->a.max_ct_len); 176362306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 176462306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 176562306a36Sopenharmony_ci size += alen; 176662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20aa, 176762306a36Sopenharmony_ci "CT PAYLOAD LENGTH = 0x%x.\n", be32_to_cpu(eiter->a.max_ct_len)); 176862306a36Sopenharmony_ci /* Node Symbolic Name */ 176962306a36Sopenharmony_ci eiter = entries + size; 177062306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_NODE_SYMBOLIC_NAME); 177162306a36Sopenharmony_ci alen = qla2x00_get_sym_node_name(vha, eiter->a.sym_name, 177262306a36Sopenharmony_ci sizeof(eiter->a.sym_name)); 177362306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 177462306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 177562306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 177662306a36Sopenharmony_ci size += alen; 177762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ab, 177862306a36Sopenharmony_ci "SYMBOLIC NAME = %s.\n", eiter->a.sym_name); 177962306a36Sopenharmony_ci /* Vendor Specific information */ 178062306a36Sopenharmony_ci eiter = entries + size; 178162306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_SPECIFIC_INFO); 178262306a36Sopenharmony_ci eiter->a.vendor_specific_info = cpu_to_be32(PCI_VENDOR_ID_QLOGIC); 178362306a36Sopenharmony_ci alen = sizeof(eiter->a.vendor_specific_info); 178462306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 178562306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 178662306a36Sopenharmony_ci size += alen; 178762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ac, 178862306a36Sopenharmony_ci "VENDOR SPECIFIC INFO = 0x%x.\n", 178962306a36Sopenharmony_ci be32_to_cpu(eiter->a.vendor_specific_info)); 179062306a36Sopenharmony_ci /* Num Ports */ 179162306a36Sopenharmony_ci eiter = entries + size; 179262306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_NUM_PORTS); 179362306a36Sopenharmony_ci eiter->a.num_ports = cpu_to_be32(1); 179462306a36Sopenharmony_ci alen = sizeof(eiter->a.num_ports); 179562306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 179662306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 179762306a36Sopenharmony_ci size += alen; 179862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ad, 179962306a36Sopenharmony_ci "PORT COUNT = %x.\n", be32_to_cpu(eiter->a.num_ports)); 180062306a36Sopenharmony_ci /* Fabric Name */ 180162306a36Sopenharmony_ci eiter = entries + size; 180262306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_FABRIC_NAME); 180362306a36Sopenharmony_ci memcpy(eiter->a.fabric_name, vha->fabric_node_name, 180462306a36Sopenharmony_ci sizeof(eiter->a.fabric_name)); 180562306a36Sopenharmony_ci alen = sizeof(eiter->a.fabric_name); 180662306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 180762306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 180862306a36Sopenharmony_ci size += alen; 180962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ae, 181062306a36Sopenharmony_ci "FABRIC NAME = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); 181162306a36Sopenharmony_ci /* BIOS Version */ 181262306a36Sopenharmony_ci eiter = entries + size; 181362306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_BOOT_BIOS_NAME); 181462306a36Sopenharmony_ci alen = scnprintf( 181562306a36Sopenharmony_ci eiter->a.bios_name, sizeof(eiter->a.bios_name), 181662306a36Sopenharmony_ci "BIOS %d.%02d", ha->bios_revision[1], ha->bios_revision[0]); 181762306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 181862306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 181962306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 182062306a36Sopenharmony_ci size += alen; 182162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20af, 182262306a36Sopenharmony_ci "BIOS NAME = %s\n", eiter->a.bios_name); 182362306a36Sopenharmony_ci /* Vendor Identifier */ 182462306a36Sopenharmony_ci eiter = entries + size; 182562306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_HBA_VENDOR_IDENTIFIER); 182662306a36Sopenharmony_ci alen = scnprintf( 182762306a36Sopenharmony_ci eiter->a.vendor_identifier, sizeof(eiter->a.vendor_identifier), 182862306a36Sopenharmony_ci "%s", "QLGC"); 182962306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 183062306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 183162306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 183262306a36Sopenharmony_ci size += alen; 183362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20b0, 183462306a36Sopenharmony_ci "VENDOR IDENTIFIER = %s.\n", eiter->a.vendor_identifier); 183562306a36Sopenharmony_cidone: 183662306a36Sopenharmony_ci return size; 183762306a36Sopenharmony_ci} 183862306a36Sopenharmony_ci 183962306a36Sopenharmony_ci/** 184062306a36Sopenharmony_ci * qla2x00_port_attributes() - perform Port attributes registration 184162306a36Sopenharmony_ci * @vha: HA context 184262306a36Sopenharmony_ci * @entries: number of entries to use 184362306a36Sopenharmony_ci * @callopt: Option to issue extended or standard FDMI 184462306a36Sopenharmony_ci * command parameter 184562306a36Sopenharmony_ci * 184662306a36Sopenharmony_ci * Returns 0 on success. 184762306a36Sopenharmony_ci */ 184862306a36Sopenharmony_cistatic unsigned long 184962306a36Sopenharmony_ciqla2x00_port_attributes(scsi_qla_host_t *vha, void *entries, 185062306a36Sopenharmony_ci unsigned int callopt) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 185362306a36Sopenharmony_ci struct new_utsname *p_sysid = utsname(); 185462306a36Sopenharmony_ci char *hostname = p_sysid ? 185562306a36Sopenharmony_ci p_sysid->nodename : fc_host_system_hostname(vha->host); 185662306a36Sopenharmony_ci struct ct_fdmi_port_attr *eiter; 185762306a36Sopenharmony_ci uint16_t alen; 185862306a36Sopenharmony_ci unsigned long size = 0; 185962306a36Sopenharmony_ci 186062306a36Sopenharmony_ci /* FC4 types. */ 186162306a36Sopenharmony_ci eiter = entries + size; 186262306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPES); 186362306a36Sopenharmony_ci eiter->a.fc4_types[0] = 0x00; 186462306a36Sopenharmony_ci eiter->a.fc4_types[1] = 0x00; 186562306a36Sopenharmony_ci eiter->a.fc4_types[2] = 0x01; 186662306a36Sopenharmony_ci eiter->a.fc4_types[3] = 0x00; 186762306a36Sopenharmony_ci alen = sizeof(eiter->a.fc4_types); 186862306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 186962306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 187062306a36Sopenharmony_ci size += alen; 187162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c0, 187262306a36Sopenharmony_ci "FC4 TYPES = %016llx.\n", *(uint64_t *)eiter->a.fc4_types); 187362306a36Sopenharmony_ci if (vha->flags.nvme_enabled) { 187462306a36Sopenharmony_ci eiter->a.fc4_types[6] = 1; /* NVMe type 28h */ 187562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x211f, 187662306a36Sopenharmony_ci "NVME FC4 Type = %02x 0x0 0x0 0x0 0x0 0x0.\n", 187762306a36Sopenharmony_ci eiter->a.fc4_types[6]); 187862306a36Sopenharmony_ci } 187962306a36Sopenharmony_ci /* Supported speed. */ 188062306a36Sopenharmony_ci eiter = entries + size; 188162306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_SUPPORT_SPEED); 188262306a36Sopenharmony_ci eiter->a.sup_speed = cpu_to_be32( 188362306a36Sopenharmony_ci qla25xx_fdmi_port_speed_capability(ha)); 188462306a36Sopenharmony_ci alen = sizeof(eiter->a.sup_speed); 188562306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 188662306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 188762306a36Sopenharmony_ci size += alen; 188862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c1, 188962306a36Sopenharmony_ci "SUPPORTED SPEED = %x.\n", be32_to_cpu(eiter->a.sup_speed)); 189062306a36Sopenharmony_ci /* Current speed. */ 189162306a36Sopenharmony_ci eiter = entries + size; 189262306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_CURRENT_SPEED); 189362306a36Sopenharmony_ci eiter->a.cur_speed = cpu_to_be32( 189462306a36Sopenharmony_ci qla25xx_fdmi_port_speed_currently(ha)); 189562306a36Sopenharmony_ci alen = sizeof(eiter->a.cur_speed); 189662306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 189762306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 189862306a36Sopenharmony_ci size += alen; 189962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c2, 190062306a36Sopenharmony_ci "CURRENT SPEED = %x.\n", be32_to_cpu(eiter->a.cur_speed)); 190162306a36Sopenharmony_ci /* Max frame size. */ 190262306a36Sopenharmony_ci eiter = entries + size; 190362306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE); 190462306a36Sopenharmony_ci eiter->a.max_frame_size = cpu_to_be32(ha->frame_payload_size); 190562306a36Sopenharmony_ci alen = sizeof(eiter->a.max_frame_size); 190662306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 190762306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 190862306a36Sopenharmony_ci size += alen; 190962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c3, 191062306a36Sopenharmony_ci "MAX FRAME SIZE = %x.\n", be32_to_cpu(eiter->a.max_frame_size)); 191162306a36Sopenharmony_ci /* OS device name. */ 191262306a36Sopenharmony_ci eiter = entries + size; 191362306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME); 191462306a36Sopenharmony_ci alen = scnprintf( 191562306a36Sopenharmony_ci eiter->a.os_dev_name, sizeof(eiter->a.os_dev_name), 191662306a36Sopenharmony_ci "%s:host%lu", QLA2XXX_DRIVER_NAME, vha->host_no); 191762306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 191862306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 191962306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 192062306a36Sopenharmony_ci size += alen; 192162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c4, 192262306a36Sopenharmony_ci "OS DEVICE NAME = %s.\n", eiter->a.os_dev_name); 192362306a36Sopenharmony_ci /* Hostname. */ 192462306a36Sopenharmony_ci eiter = entries + size; 192562306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_HOST_NAME); 192662306a36Sopenharmony_ci if (!*hostname || !strncmp(hostname, "(none)", 6)) 192762306a36Sopenharmony_ci hostname = "Linux-default"; 192862306a36Sopenharmony_ci alen = scnprintf( 192962306a36Sopenharmony_ci eiter->a.host_name, sizeof(eiter->a.host_name), 193062306a36Sopenharmony_ci "%s", hostname); 193162306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 193262306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 193362306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 193462306a36Sopenharmony_ci size += alen; 193562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c5, 193662306a36Sopenharmony_ci "HOSTNAME = %s.\n", eiter->a.host_name); 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci if (callopt == CALLOPT_FDMI1) 193962306a36Sopenharmony_ci goto done; 194062306a36Sopenharmony_ci 194162306a36Sopenharmony_ci /* Node Name */ 194262306a36Sopenharmony_ci eiter = entries + size; 194362306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_NODE_NAME); 194462306a36Sopenharmony_ci memcpy(eiter->a.node_name, vha->node_name, sizeof(eiter->a.node_name)); 194562306a36Sopenharmony_ci alen = sizeof(eiter->a.node_name); 194662306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 194762306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 194862306a36Sopenharmony_ci size += alen; 194962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c6, 195062306a36Sopenharmony_ci "NODENAME = %016llx.\n", wwn_to_u64(eiter->a.node_name)); 195162306a36Sopenharmony_ci 195262306a36Sopenharmony_ci /* Port Name */ 195362306a36Sopenharmony_ci eiter = entries + size; 195462306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_NAME); 195562306a36Sopenharmony_ci memcpy(eiter->a.port_name, vha->port_name, sizeof(eiter->a.port_name)); 195662306a36Sopenharmony_ci alen = sizeof(eiter->a.port_name); 195762306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 195862306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 195962306a36Sopenharmony_ci size += alen; 196062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c7, 196162306a36Sopenharmony_ci "PORTNAME = %016llx.\n", wwn_to_u64(eiter->a.port_name)); 196262306a36Sopenharmony_ci 196362306a36Sopenharmony_ci /* Port Symbolic Name */ 196462306a36Sopenharmony_ci eiter = entries + size; 196562306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_SYM_NAME); 196662306a36Sopenharmony_ci alen = qla2x00_get_sym_node_name(vha, eiter->a.port_sym_name, 196762306a36Sopenharmony_ci sizeof(eiter->a.port_sym_name)); 196862306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 196962306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 197062306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 197162306a36Sopenharmony_ci size += alen; 197262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c8, 197362306a36Sopenharmony_ci "PORT SYMBOLIC NAME = %s\n", eiter->a.port_sym_name); 197462306a36Sopenharmony_ci 197562306a36Sopenharmony_ci /* Port Type */ 197662306a36Sopenharmony_ci eiter = entries + size; 197762306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_TYPE); 197862306a36Sopenharmony_ci eiter->a.port_type = cpu_to_be32(NS_NX_PORT_TYPE); 197962306a36Sopenharmony_ci alen = sizeof(eiter->a.port_type); 198062306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 198162306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 198262306a36Sopenharmony_ci size += alen; 198362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20c9, 198462306a36Sopenharmony_ci "PORT TYPE = %x.\n", be32_to_cpu(eiter->a.port_type)); 198562306a36Sopenharmony_ci 198662306a36Sopenharmony_ci /* Supported Class of Service */ 198762306a36Sopenharmony_ci eiter = entries + size; 198862306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_SUPP_COS); 198962306a36Sopenharmony_ci eiter->a.port_supported_cos = cpu_to_be32(FC_CLASS_3); 199062306a36Sopenharmony_ci alen = sizeof(eiter->a.port_supported_cos); 199162306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 199262306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 199362306a36Sopenharmony_ci size += alen; 199462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ca, 199562306a36Sopenharmony_ci "SUPPORTED COS = %08x\n", be32_to_cpu(eiter->a.port_supported_cos)); 199662306a36Sopenharmony_ci 199762306a36Sopenharmony_ci /* Port Fabric Name */ 199862306a36Sopenharmony_ci eiter = entries + size; 199962306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_FABRIC_NAME); 200062306a36Sopenharmony_ci memcpy(eiter->a.fabric_name, vha->fabric_node_name, 200162306a36Sopenharmony_ci sizeof(eiter->a.fabric_name)); 200262306a36Sopenharmony_ci alen = sizeof(eiter->a.fabric_name); 200362306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 200462306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 200562306a36Sopenharmony_ci size += alen; 200662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20cb, 200762306a36Sopenharmony_ci "FABRIC NAME = %016llx.\n", wwn_to_u64(eiter->a.fabric_name)); 200862306a36Sopenharmony_ci 200962306a36Sopenharmony_ci /* FC4_type */ 201062306a36Sopenharmony_ci eiter = entries + size; 201162306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_FC4_TYPE); 201262306a36Sopenharmony_ci eiter->a.port_fc4_type[0] = 0x00; 201362306a36Sopenharmony_ci eiter->a.port_fc4_type[1] = 0x00; 201462306a36Sopenharmony_ci eiter->a.port_fc4_type[2] = 0x01; 201562306a36Sopenharmony_ci eiter->a.port_fc4_type[3] = 0x00; 201662306a36Sopenharmony_ci alen = sizeof(eiter->a.port_fc4_type); 201762306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 201862306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 201962306a36Sopenharmony_ci size += alen; 202062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20cc, 202162306a36Sopenharmony_ci "PORT ACTIVE FC4 TYPE = %016llx.\n", 202262306a36Sopenharmony_ci *(uint64_t *)eiter->a.port_fc4_type); 202362306a36Sopenharmony_ci 202462306a36Sopenharmony_ci /* Port State */ 202562306a36Sopenharmony_ci eiter = entries + size; 202662306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_STATE); 202762306a36Sopenharmony_ci eiter->a.port_state = cpu_to_be32(2); 202862306a36Sopenharmony_ci alen = sizeof(eiter->a.port_state); 202962306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 203062306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 203162306a36Sopenharmony_ci size += alen; 203262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20cd, 203362306a36Sopenharmony_ci "PORT_STATE = %x.\n", be32_to_cpu(eiter->a.port_state)); 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci /* Number of Ports */ 203662306a36Sopenharmony_ci eiter = entries + size; 203762306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_COUNT); 203862306a36Sopenharmony_ci eiter->a.num_ports = cpu_to_be32(1); 203962306a36Sopenharmony_ci alen = sizeof(eiter->a.num_ports); 204062306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 204162306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 204262306a36Sopenharmony_ci size += alen; 204362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ce, 204462306a36Sopenharmony_ci "PORT COUNT = %x.\n", be32_to_cpu(eiter->a.num_ports)); 204562306a36Sopenharmony_ci 204662306a36Sopenharmony_ci /* Port Identifier */ 204762306a36Sopenharmony_ci eiter = entries + size; 204862306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_PORT_IDENTIFIER); 204962306a36Sopenharmony_ci eiter->a.port_id = cpu_to_be32(vha->d_id.b24); 205062306a36Sopenharmony_ci alen = sizeof(eiter->a.port_id); 205162306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 205262306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 205362306a36Sopenharmony_ci size += alen; 205462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20cf, 205562306a36Sopenharmony_ci "PORT ID = %x.\n", be32_to_cpu(eiter->a.port_id)); 205662306a36Sopenharmony_ci 205762306a36Sopenharmony_ci if (callopt == CALLOPT_FDMI2 || !ql2xsmartsan) 205862306a36Sopenharmony_ci goto done; 205962306a36Sopenharmony_ci 206062306a36Sopenharmony_ci /* Smart SAN Service Category (Populate Smart SAN Initiator)*/ 206162306a36Sopenharmony_ci eiter = entries + size; 206262306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_SMARTSAN_SERVICE); 206362306a36Sopenharmony_ci alen = scnprintf( 206462306a36Sopenharmony_ci eiter->a.smartsan_service, sizeof(eiter->a.smartsan_service), 206562306a36Sopenharmony_ci "%s", "Smart SAN Initiator"); 206662306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 206762306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 206862306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 206962306a36Sopenharmony_ci size += alen; 207062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d0, 207162306a36Sopenharmony_ci "SMARTSAN SERVICE CATEGORY = %s.\n", eiter->a.smartsan_service); 207262306a36Sopenharmony_ci 207362306a36Sopenharmony_ci /* Smart SAN GUID (NWWN+PWWN) */ 207462306a36Sopenharmony_ci eiter = entries + size; 207562306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_SMARTSAN_GUID); 207662306a36Sopenharmony_ci memcpy(eiter->a.smartsan_guid, vha->node_name, WWN_SIZE); 207762306a36Sopenharmony_ci memcpy(eiter->a.smartsan_guid + WWN_SIZE, vha->port_name, WWN_SIZE); 207862306a36Sopenharmony_ci alen = sizeof(eiter->a.smartsan_guid); 207962306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 208062306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 208162306a36Sopenharmony_ci size += alen; 208262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d1, 208362306a36Sopenharmony_ci "Smart SAN GUID = %016llx-%016llx\n", 208462306a36Sopenharmony_ci wwn_to_u64(eiter->a.smartsan_guid), 208562306a36Sopenharmony_ci wwn_to_u64(eiter->a.smartsan_guid + WWN_SIZE)); 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_ci /* Smart SAN Version (populate "Smart SAN Version 1.0") */ 208862306a36Sopenharmony_ci eiter = entries + size; 208962306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_SMARTSAN_VERSION); 209062306a36Sopenharmony_ci alen = scnprintf( 209162306a36Sopenharmony_ci eiter->a.smartsan_version, sizeof(eiter->a.smartsan_version), 209262306a36Sopenharmony_ci "%s", "Smart SAN Version 2.0"); 209362306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 209462306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 209562306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 209662306a36Sopenharmony_ci size += alen; 209762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d2, 209862306a36Sopenharmony_ci "SMARTSAN VERSION = %s\n", eiter->a.smartsan_version); 209962306a36Sopenharmony_ci 210062306a36Sopenharmony_ci /* Smart SAN Product Name (Specify Adapter Model No) */ 210162306a36Sopenharmony_ci eiter = entries + size; 210262306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_SMARTSAN_PROD_NAME); 210362306a36Sopenharmony_ci alen = scnprintf(eiter->a.smartsan_prod_name, 210462306a36Sopenharmony_ci sizeof(eiter->a.smartsan_prod_name), 210562306a36Sopenharmony_ci "ISP%04x", ha->pdev->device); 210662306a36Sopenharmony_ci alen += FDMI_ATTR_ALIGNMENT(alen); 210762306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 210862306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 210962306a36Sopenharmony_ci size += alen; 211062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d3, 211162306a36Sopenharmony_ci "SMARTSAN PRODUCT NAME = %s\n", eiter->a.smartsan_prod_name); 211262306a36Sopenharmony_ci 211362306a36Sopenharmony_ci /* Smart SAN Port Info (specify: 1=Physical, 2=NPIV, 3=SRIOV) */ 211462306a36Sopenharmony_ci eiter = entries + size; 211562306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_SMARTSAN_PORT_INFO); 211662306a36Sopenharmony_ci eiter->a.smartsan_port_info = cpu_to_be32(vha->vp_idx ? 2 : 1); 211762306a36Sopenharmony_ci alen = sizeof(eiter->a.smartsan_port_info); 211862306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 211962306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 212062306a36Sopenharmony_ci size += alen; 212162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d4, 212262306a36Sopenharmony_ci "SMARTSAN PORT INFO = %x\n", eiter->a.smartsan_port_info); 212362306a36Sopenharmony_ci 212462306a36Sopenharmony_ci /* Smart SAN Security Support */ 212562306a36Sopenharmony_ci eiter = entries + size; 212662306a36Sopenharmony_ci eiter->type = cpu_to_be16(FDMI_SMARTSAN_SECURITY_SUPPORT); 212762306a36Sopenharmony_ci eiter->a.smartsan_security_support = cpu_to_be32(1); 212862306a36Sopenharmony_ci alen = sizeof(eiter->a.smartsan_security_support); 212962306a36Sopenharmony_ci alen += FDMI_ATTR_TYPELEN(eiter); 213062306a36Sopenharmony_ci eiter->len = cpu_to_be16(alen); 213162306a36Sopenharmony_ci size += alen; 213262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d6, 213362306a36Sopenharmony_ci "SMARTSAN SECURITY SUPPORT = %d\n", 213462306a36Sopenharmony_ci be32_to_cpu(eiter->a.smartsan_security_support)); 213562306a36Sopenharmony_ci 213662306a36Sopenharmony_cidone: 213762306a36Sopenharmony_ci return size; 213862306a36Sopenharmony_ci} 213962306a36Sopenharmony_ci 214062306a36Sopenharmony_ci/** 214162306a36Sopenharmony_ci * qla2x00_fdmi_rhba() - perform RHBA FDMI registration 214262306a36Sopenharmony_ci * @vha: HA context 214362306a36Sopenharmony_ci * @callopt: Option to issue FDMI registration 214462306a36Sopenharmony_ci * 214562306a36Sopenharmony_ci * Returns 0 on success. 214662306a36Sopenharmony_ci */ 214762306a36Sopenharmony_cistatic int 214862306a36Sopenharmony_ciqla2x00_fdmi_rhba(scsi_qla_host_t *vha, unsigned int callopt) 214962306a36Sopenharmony_ci{ 215062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 215162306a36Sopenharmony_ci unsigned long size = 0; 215262306a36Sopenharmony_ci unsigned int rval, count; 215362306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 215462306a36Sopenharmony_ci struct ct_sns_req *ct_req; 215562306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 215662306a36Sopenharmony_ci void *entries; 215762306a36Sopenharmony_ci 215862306a36Sopenharmony_ci count = callopt != CALLOPT_FDMI1 ? 215962306a36Sopenharmony_ci FDMI2_HBA_ATTR_COUNT : FDMI1_HBA_ATTR_COUNT; 216062306a36Sopenharmony_ci 216162306a36Sopenharmony_ci size = RHBA_RSP_SIZE; 216262306a36Sopenharmony_ci 216362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e0, 216462306a36Sopenharmony_ci "RHBA (callopt=%x count=%u size=%lu).\n", callopt, count, size); 216562306a36Sopenharmony_ci 216662306a36Sopenharmony_ci /* Request size adjusted after CT preparation */ 216762306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); 216862306a36Sopenharmony_ci 216962306a36Sopenharmony_ci /* Prepare CT request */ 217062306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RHBA_CMD, size); 217162306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 217262306a36Sopenharmony_ci 217362306a36Sopenharmony_ci /* Prepare FDMI command entries */ 217462306a36Sopenharmony_ci memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, 217562306a36Sopenharmony_ci sizeof(ct_req->req.rhba.hba_identifier)); 217662306a36Sopenharmony_ci size += sizeof(ct_req->req.rhba.hba_identifier); 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_ci ct_req->req.rhba.entry_count = cpu_to_be32(1); 217962306a36Sopenharmony_ci size += sizeof(ct_req->req.rhba.entry_count); 218062306a36Sopenharmony_ci 218162306a36Sopenharmony_ci memcpy(ct_req->req.rhba.port_name, vha->port_name, 218262306a36Sopenharmony_ci sizeof(ct_req->req.rhba.port_name)); 218362306a36Sopenharmony_ci size += sizeof(ct_req->req.rhba.port_name); 218462306a36Sopenharmony_ci 218562306a36Sopenharmony_ci /* Attribute count */ 218662306a36Sopenharmony_ci ct_req->req.rhba.attrs.count = cpu_to_be32(count); 218762306a36Sopenharmony_ci size += sizeof(ct_req->req.rhba.attrs.count); 218862306a36Sopenharmony_ci 218962306a36Sopenharmony_ci /* Attribute block */ 219062306a36Sopenharmony_ci entries = &ct_req->req.rhba.attrs.entry; 219162306a36Sopenharmony_ci 219262306a36Sopenharmony_ci size += qla2x00_hba_attributes(vha, entries, callopt); 219362306a36Sopenharmony_ci 219462306a36Sopenharmony_ci /* Update MS request size. */ 219562306a36Sopenharmony_ci qla2x00_update_ms_fdmi_iocb(vha, size + 16); 219662306a36Sopenharmony_ci 219762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e1, 219862306a36Sopenharmony_ci "RHBA %016llx %016llx.\n", 219962306a36Sopenharmony_ci wwn_to_u64(ct_req->req.rhba.hba_identifier), 220062306a36Sopenharmony_ci wwn_to_u64(ct_req->req.rhba.port_name)); 220162306a36Sopenharmony_ci 220262306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20e2, 220362306a36Sopenharmony_ci entries, size); 220462306a36Sopenharmony_ci 220562306a36Sopenharmony_ci /* Execute MS IOCB */ 220662306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 220762306a36Sopenharmony_ci sizeof(*ha->ms_iocb)); 220862306a36Sopenharmony_ci if (rval) { 220962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e3, 221062306a36Sopenharmony_ci "RHBA iocb failed (%d).\n", rval); 221162306a36Sopenharmony_ci return rval; 221262306a36Sopenharmony_ci } 221362306a36Sopenharmony_ci 221462306a36Sopenharmony_ci rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA"); 221562306a36Sopenharmony_ci if (rval) { 221662306a36Sopenharmony_ci if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && 221762306a36Sopenharmony_ci ct_rsp->header.explanation_code == 221862306a36Sopenharmony_ci CT_EXPL_ALREADY_REGISTERED) { 221962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e4, 222062306a36Sopenharmony_ci "RHBA already registered.\n"); 222162306a36Sopenharmony_ci return QLA_ALREADY_REGISTERED; 222262306a36Sopenharmony_ci } 222362306a36Sopenharmony_ci 222462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e5, 222562306a36Sopenharmony_ci "RHBA failed, CT Reason %#x, CT Explanation %#x\n", 222662306a36Sopenharmony_ci ct_rsp->header.reason_code, 222762306a36Sopenharmony_ci ct_rsp->header.explanation_code); 222862306a36Sopenharmony_ci return rval; 222962306a36Sopenharmony_ci } 223062306a36Sopenharmony_ci 223162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e6, "RHBA exiting normally.\n"); 223262306a36Sopenharmony_ci return rval; 223362306a36Sopenharmony_ci} 223462306a36Sopenharmony_ci 223562306a36Sopenharmony_ci 223662306a36Sopenharmony_cistatic int 223762306a36Sopenharmony_ciqla2x00_fdmi_dhba(scsi_qla_host_t *vha) 223862306a36Sopenharmony_ci{ 223962306a36Sopenharmony_ci int rval; 224062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 224162306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 224262306a36Sopenharmony_ci struct ct_sns_req *ct_req; 224362306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 224462306a36Sopenharmony_ci /* Issue RPA */ 224562306a36Sopenharmony_ci /* Prepare common MS IOCB */ 224662306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, DHBA_REQ_SIZE, 224762306a36Sopenharmony_ci DHBA_RSP_SIZE); 224862306a36Sopenharmony_ci /* Prepare CT request */ 224962306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, DHBA_CMD, DHBA_RSP_SIZE); 225062306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 225162306a36Sopenharmony_ci /* Prepare FDMI command arguments -- portname. */ 225262306a36Sopenharmony_ci memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE); 225362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2036, 225462306a36Sopenharmony_ci "DHBA portname = %8phN.\n", ct_req->req.dhba.port_name); 225562306a36Sopenharmony_ci /* Execute MS IOCB */ 225662306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 225762306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 225862306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 225962306a36Sopenharmony_ci /*EMPTY*/ 226062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2037, 226162306a36Sopenharmony_ci "DHBA issue IOCB failed (%d).\n", rval); 226262306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "DHBA") != 226362306a36Sopenharmony_ci QLA_SUCCESS) { 226462306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 226562306a36Sopenharmony_ci } else { 226662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2038, 226762306a36Sopenharmony_ci "DHBA exiting normally.\n"); 226862306a36Sopenharmony_ci } 226962306a36Sopenharmony_ci return rval; 227062306a36Sopenharmony_ci} 227162306a36Sopenharmony_ci 227262306a36Sopenharmony_ci/** 227362306a36Sopenharmony_ci * qla2x00_fdmi_rprt() - perform RPRT registration 227462306a36Sopenharmony_ci * @vha: HA context 227562306a36Sopenharmony_ci * @callopt: Option to issue extended or standard FDMI 227662306a36Sopenharmony_ci * command parameter 227762306a36Sopenharmony_ci * 227862306a36Sopenharmony_ci * Returns 0 on success. 227962306a36Sopenharmony_ci */ 228062306a36Sopenharmony_cistatic int 228162306a36Sopenharmony_ciqla2x00_fdmi_rprt(scsi_qla_host_t *vha, int callopt) 228262306a36Sopenharmony_ci{ 228362306a36Sopenharmony_ci struct scsi_qla_host *base_vha = pci_get_drvdata(vha->hw->pdev); 228462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 228562306a36Sopenharmony_ci ulong size = 0; 228662306a36Sopenharmony_ci uint rval, count; 228762306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 228862306a36Sopenharmony_ci struct ct_sns_req *ct_req; 228962306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 229062306a36Sopenharmony_ci void *entries; 229162306a36Sopenharmony_ci count = callopt == CALLOPT_FDMI2_SMARTSAN && ql2xsmartsan ? 229262306a36Sopenharmony_ci FDMI2_SMARTSAN_PORT_ATTR_COUNT : 229362306a36Sopenharmony_ci callopt != CALLOPT_FDMI1 ? 229462306a36Sopenharmony_ci FDMI2_PORT_ATTR_COUNT : FDMI1_PORT_ATTR_COUNT; 229562306a36Sopenharmony_ci 229662306a36Sopenharmony_ci size = RPRT_RSP_SIZE; 229762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e8, 229862306a36Sopenharmony_ci "RPRT (callopt=%x count=%u size=%lu).\n", callopt, count, size); 229962306a36Sopenharmony_ci /* Request size adjusted after CT preparation */ 230062306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); 230162306a36Sopenharmony_ci /* Prepare CT request */ 230262306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPRT_CMD, size); 230362306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 230462306a36Sopenharmony_ci /* Prepare FDMI command entries */ 230562306a36Sopenharmony_ci memcpy(ct_req->req.rprt.hba_identifier, base_vha->port_name, 230662306a36Sopenharmony_ci sizeof(ct_req->req.rprt.hba_identifier)); 230762306a36Sopenharmony_ci size += sizeof(ct_req->req.rprt.hba_identifier); 230862306a36Sopenharmony_ci memcpy(ct_req->req.rprt.port_name, vha->port_name, 230962306a36Sopenharmony_ci sizeof(ct_req->req.rprt.port_name)); 231062306a36Sopenharmony_ci size += sizeof(ct_req->req.rprt.port_name); 231162306a36Sopenharmony_ci /* Attribute count */ 231262306a36Sopenharmony_ci ct_req->req.rprt.attrs.count = cpu_to_be32(count); 231362306a36Sopenharmony_ci size += sizeof(ct_req->req.rprt.attrs.count); 231462306a36Sopenharmony_ci /* Attribute block */ 231562306a36Sopenharmony_ci entries = ct_req->req.rprt.attrs.entry; 231662306a36Sopenharmony_ci size += qla2x00_port_attributes(vha, entries, callopt); 231762306a36Sopenharmony_ci /* Update MS request size. */ 231862306a36Sopenharmony_ci qla2x00_update_ms_fdmi_iocb(vha, size + 16); 231962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20e9, 232062306a36Sopenharmony_ci "RPRT %016llx %016llx.\n", 232162306a36Sopenharmony_ci wwn_to_u64(ct_req->req.rprt.port_name), 232262306a36Sopenharmony_ci wwn_to_u64(ct_req->req.rprt.port_name)); 232362306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20ea, 232462306a36Sopenharmony_ci entries, size); 232562306a36Sopenharmony_ci /* Execute MS IOCB */ 232662306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 232762306a36Sopenharmony_ci sizeof(*ha->ms_iocb)); 232862306a36Sopenharmony_ci if (rval) { 232962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20eb, 233062306a36Sopenharmony_ci "RPRT iocb failed (%d).\n", rval); 233162306a36Sopenharmony_ci return rval; 233262306a36Sopenharmony_ci } 233362306a36Sopenharmony_ci rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPRT"); 233462306a36Sopenharmony_ci if (rval) { 233562306a36Sopenharmony_ci if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && 233662306a36Sopenharmony_ci ct_rsp->header.explanation_code == 233762306a36Sopenharmony_ci CT_EXPL_ALREADY_REGISTERED) { 233862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ec, 233962306a36Sopenharmony_ci "RPRT already registered.\n"); 234062306a36Sopenharmony_ci return QLA_ALREADY_REGISTERED; 234162306a36Sopenharmony_ci } 234262306a36Sopenharmony_ci 234362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ed, 234462306a36Sopenharmony_ci "RPRT failed, CT Reason code: %#x, CT Explanation %#x\n", 234562306a36Sopenharmony_ci ct_rsp->header.reason_code, 234662306a36Sopenharmony_ci ct_rsp->header.explanation_code); 234762306a36Sopenharmony_ci return rval; 234862306a36Sopenharmony_ci } 234962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20ee, "RPRT exiting normally.\n"); 235062306a36Sopenharmony_ci return rval; 235162306a36Sopenharmony_ci} 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci/** 235462306a36Sopenharmony_ci * qla2x00_fdmi_rpa() - perform RPA registration 235562306a36Sopenharmony_ci * @vha: HA context 235662306a36Sopenharmony_ci * @callopt: Option to issue FDMI registration 235762306a36Sopenharmony_ci * 235862306a36Sopenharmony_ci * Returns 0 on success. 235962306a36Sopenharmony_ci */ 236062306a36Sopenharmony_cistatic int 236162306a36Sopenharmony_ciqla2x00_fdmi_rpa(scsi_qla_host_t *vha, uint callopt) 236262306a36Sopenharmony_ci{ 236362306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 236462306a36Sopenharmony_ci ulong size = 0; 236562306a36Sopenharmony_ci uint rval, count; 236662306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 236762306a36Sopenharmony_ci struct ct_sns_req *ct_req; 236862306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 236962306a36Sopenharmony_ci void *entries; 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci count = 237262306a36Sopenharmony_ci callopt == CALLOPT_FDMI2_SMARTSAN && ql2xsmartsan ? 237362306a36Sopenharmony_ci FDMI2_SMARTSAN_PORT_ATTR_COUNT : 237462306a36Sopenharmony_ci callopt != CALLOPT_FDMI1 ? 237562306a36Sopenharmony_ci FDMI2_PORT_ATTR_COUNT : FDMI1_PORT_ATTR_COUNT; 237662306a36Sopenharmony_ci 237762306a36Sopenharmony_ci size = 237862306a36Sopenharmony_ci callopt != CALLOPT_FDMI1 ? 237962306a36Sopenharmony_ci SMARTSAN_RPA_RSP_SIZE : RPA_RSP_SIZE; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f0, 238262306a36Sopenharmony_ci "RPA (callopt=%x count=%u size=%lu).\n", callopt, count, size); 238362306a36Sopenharmony_ci 238462306a36Sopenharmony_ci /* Request size adjusted after CT preparation */ 238562306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, size); 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_ci /* Prepare CT request */ 238862306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_fdmi_req(ha->ct_sns, RPA_CMD, size); 238962306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 239062306a36Sopenharmony_ci 239162306a36Sopenharmony_ci /* Prepare FDMI command entries. */ 239262306a36Sopenharmony_ci memcpy(ct_req->req.rpa.port_name, vha->port_name, 239362306a36Sopenharmony_ci sizeof(ct_req->req.rpa.port_name)); 239462306a36Sopenharmony_ci size += sizeof(ct_req->req.rpa.port_name); 239562306a36Sopenharmony_ci 239662306a36Sopenharmony_ci /* Attribute count */ 239762306a36Sopenharmony_ci ct_req->req.rpa.attrs.count = cpu_to_be32(count); 239862306a36Sopenharmony_ci size += sizeof(ct_req->req.rpa.attrs.count); 239962306a36Sopenharmony_ci 240062306a36Sopenharmony_ci /* Attribute block */ 240162306a36Sopenharmony_ci entries = ct_req->req.rpa.attrs.entry; 240262306a36Sopenharmony_ci 240362306a36Sopenharmony_ci size += qla2x00_port_attributes(vha, entries, callopt); 240462306a36Sopenharmony_ci 240562306a36Sopenharmony_ci /* Update MS request size. */ 240662306a36Sopenharmony_ci qla2x00_update_ms_fdmi_iocb(vha, size + 16); 240762306a36Sopenharmony_ci 240862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f1, 240962306a36Sopenharmony_ci "RPA %016llx.\n", wwn_to_u64(ct_req->req.rpa.port_name)); 241062306a36Sopenharmony_ci 241162306a36Sopenharmony_ci ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x20f2, 241262306a36Sopenharmony_ci entries, size); 241362306a36Sopenharmony_ci 241462306a36Sopenharmony_ci /* Execute MS IOCB */ 241562306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 241662306a36Sopenharmony_ci sizeof(*ha->ms_iocb)); 241762306a36Sopenharmony_ci if (rval) { 241862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f3, 241962306a36Sopenharmony_ci "RPA iocb failed (%d).\n", rval); 242062306a36Sopenharmony_ci return rval; 242162306a36Sopenharmony_ci } 242262306a36Sopenharmony_ci 242362306a36Sopenharmony_ci rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA"); 242462306a36Sopenharmony_ci if (rval) { 242562306a36Sopenharmony_ci if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM && 242662306a36Sopenharmony_ci ct_rsp->header.explanation_code == 242762306a36Sopenharmony_ci CT_EXPL_ALREADY_REGISTERED) { 242862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f4, 242962306a36Sopenharmony_ci "RPA already registered.\n"); 243062306a36Sopenharmony_ci return QLA_ALREADY_REGISTERED; 243162306a36Sopenharmony_ci } 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f5, 243462306a36Sopenharmony_ci "RPA failed, CT Reason code: %#x, CT Explanation %#x\n", 243562306a36Sopenharmony_ci ct_rsp->header.reason_code, 243662306a36Sopenharmony_ci ct_rsp->header.explanation_code); 243762306a36Sopenharmony_ci return rval; 243862306a36Sopenharmony_ci } 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20f6, "RPA exiting normally.\n"); 244162306a36Sopenharmony_ci return rval; 244262306a36Sopenharmony_ci} 244362306a36Sopenharmony_ci 244462306a36Sopenharmony_ci/** 244562306a36Sopenharmony_ci * qla2x00_fdmi_register() - 244662306a36Sopenharmony_ci * @vha: HA context 244762306a36Sopenharmony_ci * 244862306a36Sopenharmony_ci * Returns 0 on success. 244962306a36Sopenharmony_ci */ 245062306a36Sopenharmony_ciint 245162306a36Sopenharmony_ciqla2x00_fdmi_register(scsi_qla_host_t *vha) 245262306a36Sopenharmony_ci{ 245362306a36Sopenharmony_ci int rval = QLA_SUCCESS; 245462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 245562306a36Sopenharmony_ci 245662306a36Sopenharmony_ci if (IS_QLA2100(ha) || IS_QLA2200(ha) || 245762306a36Sopenharmony_ci IS_QLAFX00(ha)) 245862306a36Sopenharmony_ci return rval; 245962306a36Sopenharmony_ci 246062306a36Sopenharmony_ci rval = qla2x00_mgmt_svr_login(vha); 246162306a36Sopenharmony_ci if (rval) 246262306a36Sopenharmony_ci return rval; 246362306a36Sopenharmony_ci 246462306a36Sopenharmony_ci /* For npiv/vport send rprt only */ 246562306a36Sopenharmony_ci if (vha->vp_idx) { 246662306a36Sopenharmony_ci if (ql2xsmartsan) 246762306a36Sopenharmony_ci rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI2_SMARTSAN); 246862306a36Sopenharmony_ci if (rval || !ql2xsmartsan) 246962306a36Sopenharmony_ci rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI2); 247062306a36Sopenharmony_ci if (rval) 247162306a36Sopenharmony_ci rval = qla2x00_fdmi_rprt(vha, CALLOPT_FDMI1); 247262306a36Sopenharmony_ci 247362306a36Sopenharmony_ci return rval; 247462306a36Sopenharmony_ci } 247562306a36Sopenharmony_ci 247662306a36Sopenharmony_ci /* Try fdmi2 first, if fails then try fdmi1 */ 247762306a36Sopenharmony_ci rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI2); 247862306a36Sopenharmony_ci if (rval) { 247962306a36Sopenharmony_ci if (rval != QLA_ALREADY_REGISTERED) 248062306a36Sopenharmony_ci goto try_fdmi; 248162306a36Sopenharmony_ci 248262306a36Sopenharmony_ci rval = qla2x00_fdmi_dhba(vha); 248362306a36Sopenharmony_ci if (rval) 248462306a36Sopenharmony_ci goto try_fdmi; 248562306a36Sopenharmony_ci 248662306a36Sopenharmony_ci rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI2); 248762306a36Sopenharmony_ci if (rval) 248862306a36Sopenharmony_ci goto try_fdmi; 248962306a36Sopenharmony_ci } 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci if (ql2xsmartsan) 249262306a36Sopenharmony_ci rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI2_SMARTSAN); 249362306a36Sopenharmony_ci if (rval || !ql2xsmartsan) 249462306a36Sopenharmony_ci rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI2); 249562306a36Sopenharmony_ci if (rval) 249662306a36Sopenharmony_ci goto try_fdmi; 249762306a36Sopenharmony_ci 249862306a36Sopenharmony_ci return rval; 249962306a36Sopenharmony_ci 250062306a36Sopenharmony_citry_fdmi: 250162306a36Sopenharmony_ci rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI1); 250262306a36Sopenharmony_ci if (rval) { 250362306a36Sopenharmony_ci if (rval != QLA_ALREADY_REGISTERED) 250462306a36Sopenharmony_ci return rval; 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci rval = qla2x00_fdmi_dhba(vha); 250762306a36Sopenharmony_ci if (rval) 250862306a36Sopenharmony_ci return rval; 250962306a36Sopenharmony_ci 251062306a36Sopenharmony_ci rval = qla2x00_fdmi_rhba(vha, CALLOPT_FDMI1); 251162306a36Sopenharmony_ci if (rval) 251262306a36Sopenharmony_ci return rval; 251362306a36Sopenharmony_ci } 251462306a36Sopenharmony_ci 251562306a36Sopenharmony_ci rval = qla2x00_fdmi_rpa(vha, CALLOPT_FDMI1); 251662306a36Sopenharmony_ci 251762306a36Sopenharmony_ci return rval; 251862306a36Sopenharmony_ci} 251962306a36Sopenharmony_ci 252062306a36Sopenharmony_ci/** 252162306a36Sopenharmony_ci * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query. 252262306a36Sopenharmony_ci * @vha: HA context 252362306a36Sopenharmony_ci * @list: switch info entries to populate 252462306a36Sopenharmony_ci * 252562306a36Sopenharmony_ci * Returns 0 on success. 252662306a36Sopenharmony_ci */ 252762306a36Sopenharmony_ciint 252862306a36Sopenharmony_ciqla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list) 252962306a36Sopenharmony_ci{ 253062306a36Sopenharmony_ci int rval = QLA_SUCCESS; 253162306a36Sopenharmony_ci uint16_t i; 253262306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 253362306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 253462306a36Sopenharmony_ci struct ct_sns_req *ct_req; 253562306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 253662306a36Sopenharmony_ci struct ct_arg arg; 253762306a36Sopenharmony_ci 253862306a36Sopenharmony_ci if (!IS_IIDMA_CAPABLE(ha)) 253962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 254062306a36Sopenharmony_ci 254162306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 254262306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 254362306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 254462306a36Sopenharmony_ci arg.req_size = GFPN_ID_REQ_SIZE; 254562306a36Sopenharmony_ci arg.rsp_size = GFPN_ID_RSP_SIZE; 254662306a36Sopenharmony_ci arg.nport_handle = NPH_SNS; 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 254962306a36Sopenharmony_ci /* Issue GFPN_ID */ 255062306a36Sopenharmony_ci /* Prepare common MS IOCB */ 255162306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_iocb(vha, &arg); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci /* Prepare CT request */ 255462306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ha->ct_sns, GFPN_ID_CMD, 255562306a36Sopenharmony_ci GFPN_ID_RSP_SIZE); 255662306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 255762306a36Sopenharmony_ci 255862306a36Sopenharmony_ci /* Prepare CT arguments -- port_id */ 255962306a36Sopenharmony_ci ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); 256062306a36Sopenharmony_ci 256162306a36Sopenharmony_ci /* Execute MS IOCB */ 256262306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 256362306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 256462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 256562306a36Sopenharmony_ci /*EMPTY*/ 256662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2023, 256762306a36Sopenharmony_ci "GFPN_ID issue IOCB failed (%d).\n", rval); 256862306a36Sopenharmony_ci break; 256962306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, 257062306a36Sopenharmony_ci "GFPN_ID") != QLA_SUCCESS) { 257162306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 257262306a36Sopenharmony_ci break; 257362306a36Sopenharmony_ci } else { 257462306a36Sopenharmony_ci /* Save fabric portname */ 257562306a36Sopenharmony_ci memcpy(list[i].fabric_port_name, 257662306a36Sopenharmony_ci ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE); 257762306a36Sopenharmony_ci } 257862306a36Sopenharmony_ci 257962306a36Sopenharmony_ci /* Last device exit. */ 258062306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 258162306a36Sopenharmony_ci break; 258262306a36Sopenharmony_ci } 258362306a36Sopenharmony_ci 258462306a36Sopenharmony_ci return (rval); 258562306a36Sopenharmony_ci} 258662306a36Sopenharmony_ci 258762306a36Sopenharmony_ci 258862306a36Sopenharmony_cistatic inline struct ct_sns_req * 258962306a36Sopenharmony_ciqla24xx_prep_ct_fm_req(struct ct_sns_pkt *p, uint16_t cmd, 259062306a36Sopenharmony_ci uint16_t rsp_size) 259162306a36Sopenharmony_ci{ 259262306a36Sopenharmony_ci memset(p, 0, sizeof(struct ct_sns_pkt)); 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_ci p->p.req.header.revision = 0x01; 259562306a36Sopenharmony_ci p->p.req.header.gs_type = 0xFA; 259662306a36Sopenharmony_ci p->p.req.header.gs_subtype = 0x01; 259762306a36Sopenharmony_ci p->p.req.command = cpu_to_be16(cmd); 259862306a36Sopenharmony_ci p->p.req.max_rsp_size = cpu_to_be16((rsp_size - 16) / 4); 259962306a36Sopenharmony_ci 260062306a36Sopenharmony_ci return &p->p.req; 260162306a36Sopenharmony_ci} 260262306a36Sopenharmony_ci 260362306a36Sopenharmony_cistatic uint16_t 260462306a36Sopenharmony_ciqla2x00_port_speed_capability(uint16_t speed) 260562306a36Sopenharmony_ci{ 260662306a36Sopenharmony_ci switch (speed) { 260762306a36Sopenharmony_ci case BIT_15: 260862306a36Sopenharmony_ci return PORT_SPEED_1GB; 260962306a36Sopenharmony_ci case BIT_14: 261062306a36Sopenharmony_ci return PORT_SPEED_2GB; 261162306a36Sopenharmony_ci case BIT_13: 261262306a36Sopenharmony_ci return PORT_SPEED_4GB; 261362306a36Sopenharmony_ci case BIT_12: 261462306a36Sopenharmony_ci return PORT_SPEED_10GB; 261562306a36Sopenharmony_ci case BIT_11: 261662306a36Sopenharmony_ci return PORT_SPEED_8GB; 261762306a36Sopenharmony_ci case BIT_10: 261862306a36Sopenharmony_ci return PORT_SPEED_16GB; 261962306a36Sopenharmony_ci case BIT_8: 262062306a36Sopenharmony_ci return PORT_SPEED_32GB; 262162306a36Sopenharmony_ci case BIT_7: 262262306a36Sopenharmony_ci return PORT_SPEED_64GB; 262362306a36Sopenharmony_ci default: 262462306a36Sopenharmony_ci return PORT_SPEED_UNKNOWN; 262562306a36Sopenharmony_ci } 262662306a36Sopenharmony_ci} 262762306a36Sopenharmony_ci 262862306a36Sopenharmony_ci/** 262962306a36Sopenharmony_ci * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query. 263062306a36Sopenharmony_ci * @vha: HA context 263162306a36Sopenharmony_ci * @list: switch info entries to populate 263262306a36Sopenharmony_ci * 263362306a36Sopenharmony_ci * Returns 0 on success. 263462306a36Sopenharmony_ci */ 263562306a36Sopenharmony_ciint 263662306a36Sopenharmony_ciqla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list) 263762306a36Sopenharmony_ci{ 263862306a36Sopenharmony_ci int rval; 263962306a36Sopenharmony_ci uint16_t i; 264062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 264162306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 264262306a36Sopenharmony_ci struct ct_sns_req *ct_req; 264362306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 264462306a36Sopenharmony_ci struct ct_arg arg; 264562306a36Sopenharmony_ci 264662306a36Sopenharmony_ci if (!IS_IIDMA_CAPABLE(ha)) 264762306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 264862306a36Sopenharmony_ci if (!ha->flags.gpsc_supported) 264962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 265062306a36Sopenharmony_ci 265162306a36Sopenharmony_ci rval = qla2x00_mgmt_svr_login(vha); 265262306a36Sopenharmony_ci if (rval) 265362306a36Sopenharmony_ci return rval; 265462306a36Sopenharmony_ci 265562306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 265662306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 265762306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 265862306a36Sopenharmony_ci arg.req_size = GPSC_REQ_SIZE; 265962306a36Sopenharmony_ci arg.rsp_size = GPSC_RSP_SIZE; 266062306a36Sopenharmony_ci arg.nport_handle = vha->mgmt_svr_loop_id; 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 266362306a36Sopenharmony_ci /* Issue GFPN_ID */ 266462306a36Sopenharmony_ci /* Prepare common MS IOCB */ 266562306a36Sopenharmony_ci ms_pkt = qla24xx_prep_ms_iocb(vha, &arg); 266662306a36Sopenharmony_ci 266762306a36Sopenharmony_ci /* Prepare CT request */ 266862306a36Sopenharmony_ci ct_req = qla24xx_prep_ct_fm_req(ha->ct_sns, GPSC_CMD, 266962306a36Sopenharmony_ci GPSC_RSP_SIZE); 267062306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 267162306a36Sopenharmony_ci 267262306a36Sopenharmony_ci /* Prepare CT arguments -- port_name */ 267362306a36Sopenharmony_ci memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name, 267462306a36Sopenharmony_ci WWN_SIZE); 267562306a36Sopenharmony_ci 267662306a36Sopenharmony_ci /* Execute MS IOCB */ 267762306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 267862306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 267962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 268062306a36Sopenharmony_ci /*EMPTY*/ 268162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2059, 268262306a36Sopenharmony_ci "GPSC issue IOCB failed (%d).\n", rval); 268362306a36Sopenharmony_ci } else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, 268462306a36Sopenharmony_ci "GPSC")) != QLA_SUCCESS) { 268562306a36Sopenharmony_ci /* FM command unsupported? */ 268662306a36Sopenharmony_ci if (rval == QLA_INVALID_COMMAND && 268762306a36Sopenharmony_ci (ct_rsp->header.reason_code == 268862306a36Sopenharmony_ci CT_REASON_INVALID_COMMAND_CODE || 268962306a36Sopenharmony_ci ct_rsp->header.reason_code == 269062306a36Sopenharmony_ci CT_REASON_COMMAND_UNSUPPORTED)) { 269162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x205a, 269262306a36Sopenharmony_ci "GPSC command unsupported, disabling " 269362306a36Sopenharmony_ci "query.\n"); 269462306a36Sopenharmony_ci ha->flags.gpsc_supported = 0; 269562306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 269662306a36Sopenharmony_ci break; 269762306a36Sopenharmony_ci } 269862306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 269962306a36Sopenharmony_ci } else { 270062306a36Sopenharmony_ci list->fp_speed = qla2x00_port_speed_capability( 270162306a36Sopenharmony_ci be16_to_cpu(ct_rsp->rsp.gpsc.speed)); 270262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x205b, 270362306a36Sopenharmony_ci "GPSC ext entry - fpn " 270462306a36Sopenharmony_ci "%8phN speeds=%04x speed=%04x.\n", 270562306a36Sopenharmony_ci list[i].fabric_port_name, 270662306a36Sopenharmony_ci be16_to_cpu(ct_rsp->rsp.gpsc.speeds), 270762306a36Sopenharmony_ci be16_to_cpu(ct_rsp->rsp.gpsc.speed)); 270862306a36Sopenharmony_ci } 270962306a36Sopenharmony_ci 271062306a36Sopenharmony_ci /* Last device exit. */ 271162306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 271262306a36Sopenharmony_ci break; 271362306a36Sopenharmony_ci } 271462306a36Sopenharmony_ci 271562306a36Sopenharmony_ci return (rval); 271662306a36Sopenharmony_ci} 271762306a36Sopenharmony_ci 271862306a36Sopenharmony_ci/** 271962306a36Sopenharmony_ci * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query. 272062306a36Sopenharmony_ci * 272162306a36Sopenharmony_ci * @vha: HA context 272262306a36Sopenharmony_ci * @list: switch info entries to populate 272362306a36Sopenharmony_ci * 272462306a36Sopenharmony_ci */ 272562306a36Sopenharmony_civoid 272662306a36Sopenharmony_ciqla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list) 272762306a36Sopenharmony_ci{ 272862306a36Sopenharmony_ci int rval; 272962306a36Sopenharmony_ci uint16_t i; 273062306a36Sopenharmony_ci 273162306a36Sopenharmony_ci ms_iocb_entry_t *ms_pkt; 273262306a36Sopenharmony_ci struct ct_sns_req *ct_req; 273362306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 273462306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 273562306a36Sopenharmony_ci uint8_t fcp_scsi_features = 0, nvme_features = 0; 273662306a36Sopenharmony_ci struct ct_arg arg; 273762306a36Sopenharmony_ci 273862306a36Sopenharmony_ci for (i = 0; i < ha->max_fibre_devices; i++) { 273962306a36Sopenharmony_ci /* Set default FC4 Type as UNKNOWN so the default is to 274062306a36Sopenharmony_ci * Process this port */ 274162306a36Sopenharmony_ci list[i].fc4_type = 0; 274262306a36Sopenharmony_ci 274362306a36Sopenharmony_ci /* Do not attempt GFF_ID if we are not FWI_2 capable */ 274462306a36Sopenharmony_ci if (!IS_FWI2_CAPABLE(ha)) 274562306a36Sopenharmony_ci continue; 274662306a36Sopenharmony_ci 274762306a36Sopenharmony_ci arg.iocb = ha->ms_iocb; 274862306a36Sopenharmony_ci arg.req_dma = ha->ct_sns_dma; 274962306a36Sopenharmony_ci arg.rsp_dma = ha->ct_sns_dma; 275062306a36Sopenharmony_ci arg.req_size = GFF_ID_REQ_SIZE; 275162306a36Sopenharmony_ci arg.rsp_size = GFF_ID_RSP_SIZE; 275262306a36Sopenharmony_ci arg.nport_handle = NPH_SNS; 275362306a36Sopenharmony_ci 275462306a36Sopenharmony_ci /* Prepare common MS IOCB */ 275562306a36Sopenharmony_ci ms_pkt = ha->isp_ops->prep_ms_iocb(vha, &arg); 275662306a36Sopenharmony_ci 275762306a36Sopenharmony_ci /* Prepare CT request */ 275862306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ha->ct_sns, GFF_ID_CMD, 275962306a36Sopenharmony_ci GFF_ID_RSP_SIZE); 276062306a36Sopenharmony_ci ct_rsp = &ha->ct_sns->p.rsp; 276162306a36Sopenharmony_ci 276262306a36Sopenharmony_ci /* Prepare CT arguments -- port_id */ 276362306a36Sopenharmony_ci ct_req->req.port_id.port_id = port_id_to_be_id(list[i].d_id); 276462306a36Sopenharmony_ci 276562306a36Sopenharmony_ci /* Execute MS IOCB */ 276662306a36Sopenharmony_ci rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma, 276762306a36Sopenharmony_ci sizeof(ms_iocb_entry_t)); 276862306a36Sopenharmony_ci 276962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 277062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x205c, 277162306a36Sopenharmony_ci "GFF_ID issue IOCB failed (%d).\n", rval); 277262306a36Sopenharmony_ci } else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, 277362306a36Sopenharmony_ci "GFF_ID") != QLA_SUCCESS) { 277462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x205d, 277562306a36Sopenharmony_ci "GFF_ID IOCB status had a failure status code.\n"); 277662306a36Sopenharmony_ci } else { 277762306a36Sopenharmony_ci fcp_scsi_features = 277862306a36Sopenharmony_ci ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; 277962306a36Sopenharmony_ci fcp_scsi_features &= 0x0f; 278062306a36Sopenharmony_ci 278162306a36Sopenharmony_ci if (fcp_scsi_features) { 278262306a36Sopenharmony_ci list[i].fc4_type = FS_FC4TYPE_FCP; 278362306a36Sopenharmony_ci list[i].fc4_features = fcp_scsi_features; 278462306a36Sopenharmony_ci } 278562306a36Sopenharmony_ci 278662306a36Sopenharmony_ci nvme_features = 278762306a36Sopenharmony_ci ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; 278862306a36Sopenharmony_ci nvme_features &= 0xf; 278962306a36Sopenharmony_ci 279062306a36Sopenharmony_ci if (nvme_features) { 279162306a36Sopenharmony_ci list[i].fc4_type |= FS_FC4TYPE_NVME; 279262306a36Sopenharmony_ci list[i].fc4_features = nvme_features; 279362306a36Sopenharmony_ci } 279462306a36Sopenharmony_ci } 279562306a36Sopenharmony_ci 279662306a36Sopenharmony_ci /* Last device exit. */ 279762306a36Sopenharmony_ci if (list[i].d_id.b.rsvd_1 != 0) 279862306a36Sopenharmony_ci break; 279962306a36Sopenharmony_ci } 280062306a36Sopenharmony_ci} 280162306a36Sopenharmony_ci 280262306a36Sopenharmony_ciint qla24xx_post_gpsc_work(struct scsi_qla_host *vha, fc_port_t *fcport) 280362306a36Sopenharmony_ci{ 280462306a36Sopenharmony_ci struct qla_work_evt *e; 280562306a36Sopenharmony_ci 280662306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_GPSC); 280762306a36Sopenharmony_ci if (!e) 280862306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 280962306a36Sopenharmony_ci 281062306a36Sopenharmony_ci e->u.fcport.fcport = fcport; 281162306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 281262306a36Sopenharmony_ci} 281362306a36Sopenharmony_ci 281462306a36Sopenharmony_civoid qla24xx_handle_gpsc_event(scsi_qla_host_t *vha, struct event_arg *ea) 281562306a36Sopenharmony_ci{ 281662306a36Sopenharmony_ci struct fc_port *fcport = ea->fcport; 281762306a36Sopenharmony_ci 281862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d8, 281962306a36Sopenharmony_ci "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d lid %d\n", 282062306a36Sopenharmony_ci __func__, fcport->port_name, fcport->disc_state, 282162306a36Sopenharmony_ci fcport->fw_login_state, ea->rc, ea->sp->gen2, fcport->login_gen, 282262306a36Sopenharmony_ci ea->sp->gen2, fcport->rscn_gen|ea->sp->gen1, fcport->loop_id); 282362306a36Sopenharmony_ci 282462306a36Sopenharmony_ci if (fcport->disc_state == DSC_DELETE_PEND) 282562306a36Sopenharmony_ci return; 282662306a36Sopenharmony_ci 282762306a36Sopenharmony_ci /* We will figure-out what happen after AUTH completes */ 282862306a36Sopenharmony_ci if (fcport->disc_state == DSC_LOGIN_AUTH_PEND) 282962306a36Sopenharmony_ci return; 283062306a36Sopenharmony_ci 283162306a36Sopenharmony_ci if (ea->sp->gen2 != fcport->login_gen) { 283262306a36Sopenharmony_ci /* target side must have changed it. */ 283362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d3, 283462306a36Sopenharmony_ci "%s %8phC generation changed\n", 283562306a36Sopenharmony_ci __func__, fcport->port_name); 283662306a36Sopenharmony_ci return; 283762306a36Sopenharmony_ci } else if (ea->sp->gen1 != fcport->rscn_gen) { 283862306a36Sopenharmony_ci return; 283962306a36Sopenharmony_ci } 284062306a36Sopenharmony_ci 284162306a36Sopenharmony_ci qla_post_iidma_work(vha, fcport); 284262306a36Sopenharmony_ci} 284362306a36Sopenharmony_ci 284462306a36Sopenharmony_cistatic void qla24xx_async_gpsc_sp_done(srb_t *sp, int res) 284562306a36Sopenharmony_ci{ 284662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 284762306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 284862306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 284962306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 285062306a36Sopenharmony_ci struct event_arg ea; 285162306a36Sopenharmony_ci 285262306a36Sopenharmony_ci ct_rsp = &fcport->ct_desc.ct_sns->p.rsp; 285362306a36Sopenharmony_ci 285462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2053, 285562306a36Sopenharmony_ci "Async done-%s res %x, WWPN %8phC \n", 285662306a36Sopenharmony_ci sp->name, res, fcport->port_name); 285762306a36Sopenharmony_ci 285862306a36Sopenharmony_ci fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE); 285962306a36Sopenharmony_ci 286062306a36Sopenharmony_ci if (res == QLA_FUNCTION_TIMEOUT) 286162306a36Sopenharmony_ci goto done; 286262306a36Sopenharmony_ci 286362306a36Sopenharmony_ci if (res == (DID_ERROR << 16)) { 286462306a36Sopenharmony_ci /* entry status error */ 286562306a36Sopenharmony_ci goto done; 286662306a36Sopenharmony_ci } else if (res) { 286762306a36Sopenharmony_ci if ((ct_rsp->header.reason_code == 286862306a36Sopenharmony_ci CT_REASON_INVALID_COMMAND_CODE) || 286962306a36Sopenharmony_ci (ct_rsp->header.reason_code == 287062306a36Sopenharmony_ci CT_REASON_COMMAND_UNSUPPORTED)) { 287162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2019, 287262306a36Sopenharmony_ci "GPSC command unsupported, disabling query.\n"); 287362306a36Sopenharmony_ci ha->flags.gpsc_supported = 0; 287462306a36Sopenharmony_ci goto done; 287562306a36Sopenharmony_ci } 287662306a36Sopenharmony_ci } else { 287762306a36Sopenharmony_ci fcport->fp_speed = qla2x00_port_speed_capability( 287862306a36Sopenharmony_ci be16_to_cpu(ct_rsp->rsp.gpsc.speed)); 287962306a36Sopenharmony_ci 288062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2054, 288162306a36Sopenharmony_ci "Async-%s OUT WWPN %8phC speeds=%04x speed=%04x.\n", 288262306a36Sopenharmony_ci sp->name, fcport->fabric_port_name, 288362306a36Sopenharmony_ci be16_to_cpu(ct_rsp->rsp.gpsc.speeds), 288462306a36Sopenharmony_ci be16_to_cpu(ct_rsp->rsp.gpsc.speed)); 288562306a36Sopenharmony_ci } 288662306a36Sopenharmony_ci memset(&ea, 0, sizeof(ea)); 288762306a36Sopenharmony_ci ea.rc = res; 288862306a36Sopenharmony_ci ea.fcport = fcport; 288962306a36Sopenharmony_ci ea.sp = sp; 289062306a36Sopenharmony_ci qla24xx_handle_gpsc_event(vha, &ea); 289162306a36Sopenharmony_ci 289262306a36Sopenharmony_cidone: 289362306a36Sopenharmony_ci /* ref: INIT */ 289462306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 289562306a36Sopenharmony_ci} 289662306a36Sopenharmony_ci 289762306a36Sopenharmony_ciint qla24xx_async_gpsc(scsi_qla_host_t *vha, fc_port_t *fcport) 289862306a36Sopenharmony_ci{ 289962306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 290062306a36Sopenharmony_ci struct ct_sns_req *ct_req; 290162306a36Sopenharmony_ci srb_t *sp; 290262306a36Sopenharmony_ci 290362306a36Sopenharmony_ci if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) 290462306a36Sopenharmony_ci return rval; 290562306a36Sopenharmony_ci 290662306a36Sopenharmony_ci /* ref: INIT */ 290762306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 290862306a36Sopenharmony_ci if (!sp) 290962306a36Sopenharmony_ci goto done; 291062306a36Sopenharmony_ci 291162306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 291262306a36Sopenharmony_ci sp->name = "gpsc"; 291362306a36Sopenharmony_ci sp->gen1 = fcport->rscn_gen; 291462306a36Sopenharmony_ci sp->gen2 = fcport->login_gen; 291562306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 291662306a36Sopenharmony_ci qla24xx_async_gpsc_sp_done); 291762306a36Sopenharmony_ci 291862306a36Sopenharmony_ci /* CT_IU preamble */ 291962306a36Sopenharmony_ci ct_req = qla24xx_prep_ct_fm_req(fcport->ct_desc.ct_sns, GPSC_CMD, 292062306a36Sopenharmony_ci GPSC_RSP_SIZE); 292162306a36Sopenharmony_ci 292262306a36Sopenharmony_ci /* GPSC req */ 292362306a36Sopenharmony_ci memcpy(ct_req->req.gpsc.port_name, fcport->fabric_port_name, 292462306a36Sopenharmony_ci WWN_SIZE); 292562306a36Sopenharmony_ci 292662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; 292762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; 292862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; 292962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; 293062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = GPSC_REQ_SIZE; 293162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = GPSC_RSP_SIZE; 293262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = vha->mgmt_svr_loop_id; 293362306a36Sopenharmony_ci 293462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x205e, 293562306a36Sopenharmony_ci "Async-%s %8phC hdl=%x loopid=%x portid=%02x%02x%02x.\n", 293662306a36Sopenharmony_ci sp->name, fcport->port_name, sp->handle, 293762306a36Sopenharmony_ci fcport->loop_id, fcport->d_id.b.domain, 293862306a36Sopenharmony_ci fcport->d_id.b.area, fcport->d_id.b.al_pa); 293962306a36Sopenharmony_ci 294062306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 294162306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 294262306a36Sopenharmony_ci goto done_free_sp; 294362306a36Sopenharmony_ci return rval; 294462306a36Sopenharmony_ci 294562306a36Sopenharmony_cidone_free_sp: 294662306a36Sopenharmony_ci /* ref: INIT */ 294762306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 294862306a36Sopenharmony_cidone: 294962306a36Sopenharmony_ci return rval; 295062306a36Sopenharmony_ci} 295162306a36Sopenharmony_ci 295262306a36Sopenharmony_civoid qla24xx_sp_unmap(scsi_qla_host_t *vha, srb_t *sp) 295362306a36Sopenharmony_ci{ 295462306a36Sopenharmony_ci struct srb_iocb *c = &sp->u.iocb_cmd; 295562306a36Sopenharmony_ci 295662306a36Sopenharmony_ci switch (sp->type) { 295762306a36Sopenharmony_ci case SRB_ELS_DCMD: 295862306a36Sopenharmony_ci qla2x00_els_dcmd2_free(vha, &c->u.els_plogi); 295962306a36Sopenharmony_ci break; 296062306a36Sopenharmony_ci case SRB_CT_PTHRU_CMD: 296162306a36Sopenharmony_ci default: 296262306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.req) { 296362306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 296462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 296562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 296662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 296762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 296862306a36Sopenharmony_ci } 296962306a36Sopenharmony_ci 297062306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.rsp) { 297162306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 297262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 297362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp, 297462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma); 297562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = NULL; 297662306a36Sopenharmony_ci } 297762306a36Sopenharmony_ci break; 297862306a36Sopenharmony_ci } 297962306a36Sopenharmony_ci 298062306a36Sopenharmony_ci /* ref: INIT */ 298162306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 298262306a36Sopenharmony_ci} 298362306a36Sopenharmony_ci 298462306a36Sopenharmony_civoid qla24xx_async_gffid_sp_done(srb_t *sp, int res) 298562306a36Sopenharmony_ci{ 298662306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 298762306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 298862306a36Sopenharmony_ci struct ct_sns_rsp *ct_rsp; 298962306a36Sopenharmony_ci uint8_t fc4_scsi_feat; 299062306a36Sopenharmony_ci uint8_t fc4_nvme_feat; 299162306a36Sopenharmony_ci 299262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x2133, 299362306a36Sopenharmony_ci "Async done-%s res %x ID %x. %8phC\n", 299462306a36Sopenharmony_ci sp->name, res, fcport->d_id.b24, fcport->port_name); 299562306a36Sopenharmony_ci 299662306a36Sopenharmony_ci ct_rsp = sp->u.iocb_cmd.u.ctarg.rsp; 299762306a36Sopenharmony_ci fc4_scsi_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET]; 299862306a36Sopenharmony_ci fc4_nvme_feat = ct_rsp->rsp.gff_id.fc4_features[GFF_NVME_OFFSET]; 299962306a36Sopenharmony_ci sp->rc = res; 300062306a36Sopenharmony_ci 300162306a36Sopenharmony_ci /* 300262306a36Sopenharmony_ci * FC-GS-7, 5.2.3.12 FC-4 Features - format 300362306a36Sopenharmony_ci * The format of the FC-4 Features object, as defined by the FC-4, 300462306a36Sopenharmony_ci * Shall be an array of 4-bit values, one for each type code value 300562306a36Sopenharmony_ci */ 300662306a36Sopenharmony_ci if (!res) { 300762306a36Sopenharmony_ci if (fc4_scsi_feat & 0xf) { 300862306a36Sopenharmony_ci /* w1 b00:03 */ 300962306a36Sopenharmony_ci fcport->fc4_type = FS_FC4TYPE_FCP; 301062306a36Sopenharmony_ci fcport->fc4_features = fc4_scsi_feat & 0xf; 301162306a36Sopenharmony_ci } 301262306a36Sopenharmony_ci 301362306a36Sopenharmony_ci if (fc4_nvme_feat & 0xf) { 301462306a36Sopenharmony_ci /* w5 [00:03]/28h */ 301562306a36Sopenharmony_ci fcport->fc4_type |= FS_FC4TYPE_NVME; 301662306a36Sopenharmony_ci fcport->fc4_features = fc4_nvme_feat & 0xf; 301762306a36Sopenharmony_ci } 301862306a36Sopenharmony_ci } 301962306a36Sopenharmony_ci 302062306a36Sopenharmony_ci if (sp->flags & SRB_WAKEUP_ON_COMP) { 302162306a36Sopenharmony_ci complete(sp->comp); 302262306a36Sopenharmony_ci } else { 302362306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.req) { 302462306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 302562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 302662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 302762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 302862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 302962306a36Sopenharmony_ci } 303062306a36Sopenharmony_ci 303162306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.rsp) { 303262306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 303362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 303462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp, 303562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma); 303662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = NULL; 303762306a36Sopenharmony_ci } 303862306a36Sopenharmony_ci 303962306a36Sopenharmony_ci /* ref: INIT */ 304062306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 304162306a36Sopenharmony_ci /* we should not be here */ 304262306a36Sopenharmony_ci dump_stack(); 304362306a36Sopenharmony_ci } 304462306a36Sopenharmony_ci} 304562306a36Sopenharmony_ci 304662306a36Sopenharmony_ci/* Get FC4 Feature with Nport ID. */ 304762306a36Sopenharmony_ciint qla24xx_async_gffid(scsi_qla_host_t *vha, fc_port_t *fcport, bool wait) 304862306a36Sopenharmony_ci{ 304962306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 305062306a36Sopenharmony_ci struct ct_sns_req *ct_req; 305162306a36Sopenharmony_ci srb_t *sp; 305262306a36Sopenharmony_ci DECLARE_COMPLETION_ONSTACK(comp); 305362306a36Sopenharmony_ci 305462306a36Sopenharmony_ci /* this routine does not have handling for no wait */ 305562306a36Sopenharmony_ci if (!vha->flags.online || !wait) 305662306a36Sopenharmony_ci return rval; 305762306a36Sopenharmony_ci 305862306a36Sopenharmony_ci /* ref: INIT */ 305962306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL); 306062306a36Sopenharmony_ci if (!sp) 306162306a36Sopenharmony_ci return rval; 306262306a36Sopenharmony_ci 306362306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 306462306a36Sopenharmony_ci sp->name = "gffid"; 306562306a36Sopenharmony_ci sp->gen1 = fcport->rscn_gen; 306662306a36Sopenharmony_ci sp->gen2 = fcport->login_gen; 306762306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 306862306a36Sopenharmony_ci qla24xx_async_gffid_sp_done); 306962306a36Sopenharmony_ci sp->comp = ∁ 307062306a36Sopenharmony_ci sp->u.iocb_cmd.timeout = qla2x00_els_dcmd2_iocb_timeout; 307162306a36Sopenharmony_ci 307262306a36Sopenharmony_ci if (wait) 307362306a36Sopenharmony_ci sp->flags = SRB_WAKEUP_ON_COMP; 307462306a36Sopenharmony_ci 307562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); 307662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, 307762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 307862306a36Sopenharmony_ci &sp->u.iocb_cmd.u.ctarg.req_dma, 307962306a36Sopenharmony_ci GFP_KERNEL); 308062306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req) { 308162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd041, 308262306a36Sopenharmony_ci "%s: Failed to allocate ct_sns request.\n", 308362306a36Sopenharmony_ci __func__); 308462306a36Sopenharmony_ci goto done_free_sp; 308562306a36Sopenharmony_ci } 308662306a36Sopenharmony_ci 308762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = sizeof(struct ct_sns_pkt); 308862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, 308962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 309062306a36Sopenharmony_ci &sp->u.iocb_cmd.u.ctarg.rsp_dma, 309162306a36Sopenharmony_ci GFP_KERNEL); 309262306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.rsp) { 309362306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xd041, 309462306a36Sopenharmony_ci "%s: Failed to allocate ct_sns response.\n", 309562306a36Sopenharmony_ci __func__); 309662306a36Sopenharmony_ci goto done_free_sp; 309762306a36Sopenharmony_ci } 309862306a36Sopenharmony_ci 309962306a36Sopenharmony_ci /* CT_IU preamble */ 310062306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(sp->u.iocb_cmd.u.ctarg.req, GFF_ID_CMD, GFF_ID_RSP_SIZE); 310162306a36Sopenharmony_ci 310262306a36Sopenharmony_ci ct_req->req.gff_id.port_id[0] = fcport->d_id.b.domain; 310362306a36Sopenharmony_ci ct_req->req.gff_id.port_id[1] = fcport->d_id.b.area; 310462306a36Sopenharmony_ci ct_req->req.gff_id.port_id[2] = fcport->d_id.b.al_pa; 310562306a36Sopenharmony_ci 310662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = GFF_ID_REQ_SIZE; 310762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = GFF_ID_RSP_SIZE; 310862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 310962306a36Sopenharmony_ci 311062306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 311162306a36Sopenharmony_ci 311262306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 311362306a36Sopenharmony_ci rval = QLA_FUNCTION_FAILED; 311462306a36Sopenharmony_ci goto done_free_sp; 311562306a36Sopenharmony_ci } else { 311662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x3074, 311762306a36Sopenharmony_ci "Async-%s hdl=%x portid %06x\n", 311862306a36Sopenharmony_ci sp->name, sp->handle, fcport->d_id.b24); 311962306a36Sopenharmony_ci } 312062306a36Sopenharmony_ci 312162306a36Sopenharmony_ci wait_for_completion(sp->comp); 312262306a36Sopenharmony_ci rval = sp->rc; 312362306a36Sopenharmony_ci 312462306a36Sopenharmony_cidone_free_sp: 312562306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.req) { 312662306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 312762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 312862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 312962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 313062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 313162306a36Sopenharmony_ci } 313262306a36Sopenharmony_ci 313362306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.rsp) { 313462306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 313562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 313662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp, 313762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma); 313862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = NULL; 313962306a36Sopenharmony_ci } 314062306a36Sopenharmony_ci 314162306a36Sopenharmony_ci /* ref: INIT */ 314262306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 314362306a36Sopenharmony_ci return rval; 314462306a36Sopenharmony_ci} 314562306a36Sopenharmony_ci 314662306a36Sopenharmony_ci/* GPN_FT + GNN_FT*/ 314762306a36Sopenharmony_cistatic int qla2x00_is_a_vp(scsi_qla_host_t *vha, u64 wwn) 314862306a36Sopenharmony_ci{ 314962306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 315062306a36Sopenharmony_ci scsi_qla_host_t *vp; 315162306a36Sopenharmony_ci unsigned long flags; 315262306a36Sopenharmony_ci u64 twwn; 315362306a36Sopenharmony_ci int rc = 0; 315462306a36Sopenharmony_ci 315562306a36Sopenharmony_ci if (!ha->num_vhosts) 315662306a36Sopenharmony_ci return 0; 315762306a36Sopenharmony_ci 315862306a36Sopenharmony_ci spin_lock_irqsave(&ha->vport_slock, flags); 315962306a36Sopenharmony_ci list_for_each_entry(vp, &ha->vp_list, list) { 316062306a36Sopenharmony_ci twwn = wwn_to_u64(vp->port_name); 316162306a36Sopenharmony_ci if (wwn == twwn) { 316262306a36Sopenharmony_ci rc = 1; 316362306a36Sopenharmony_ci break; 316462306a36Sopenharmony_ci } 316562306a36Sopenharmony_ci } 316662306a36Sopenharmony_ci spin_unlock_irqrestore(&ha->vport_slock, flags); 316762306a36Sopenharmony_ci 316862306a36Sopenharmony_ci return rc; 316962306a36Sopenharmony_ci} 317062306a36Sopenharmony_ci 317162306a36Sopenharmony_civoid qla24xx_async_gnnft_done(scsi_qla_host_t *vha, srb_t *sp) 317262306a36Sopenharmony_ci{ 317362306a36Sopenharmony_ci fc_port_t *fcport; 317462306a36Sopenharmony_ci u32 i, rc; 317562306a36Sopenharmony_ci bool found; 317662306a36Sopenharmony_ci struct fab_scan_rp *rp, *trp; 317762306a36Sopenharmony_ci unsigned long flags; 317862306a36Sopenharmony_ci u8 recheck = 0; 317962306a36Sopenharmony_ci u16 dup = 0, dup_cnt = 0; 318062306a36Sopenharmony_ci 318162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 318262306a36Sopenharmony_ci "%s enter\n", __func__); 318362306a36Sopenharmony_ci 318462306a36Sopenharmony_ci if (sp->gen1 != vha->hw->base_qpair->chip_reset) { 318562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 318662306a36Sopenharmony_ci "%s scan stop due to chip reset %x/%x\n", 318762306a36Sopenharmony_ci sp->name, sp->gen1, vha->hw->base_qpair->chip_reset); 318862306a36Sopenharmony_ci goto out; 318962306a36Sopenharmony_ci } 319062306a36Sopenharmony_ci 319162306a36Sopenharmony_ci rc = sp->rc; 319262306a36Sopenharmony_ci if (rc) { 319362306a36Sopenharmony_ci vha->scan.scan_retry++; 319462306a36Sopenharmony_ci if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { 319562306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 319662306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 319762306a36Sopenharmony_ci goto out; 319862306a36Sopenharmony_ci } else { 319962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 320062306a36Sopenharmony_ci "%s: Fabric scan failed for %d retries.\n", 320162306a36Sopenharmony_ci __func__, vha->scan.scan_retry); 320262306a36Sopenharmony_ci /* 320362306a36Sopenharmony_ci * Unable to scan any rports. logout loop below 320462306a36Sopenharmony_ci * will unregister all sessions. 320562306a36Sopenharmony_ci */ 320662306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 320762306a36Sopenharmony_ci if ((fcport->flags & FCF_FABRIC_DEVICE) != 0) { 320862306a36Sopenharmony_ci fcport->scan_state = QLA_FCPORT_SCAN; 320962306a36Sopenharmony_ci if (fcport->loop_id == FC_NO_LOOP_ID) 321062306a36Sopenharmony_ci fcport->logout_on_delete = 0; 321162306a36Sopenharmony_ci else 321262306a36Sopenharmony_ci fcport->logout_on_delete = 1; 321362306a36Sopenharmony_ci } 321462306a36Sopenharmony_ci } 321562306a36Sopenharmony_ci goto login_logout; 321662306a36Sopenharmony_ci } 321762306a36Sopenharmony_ci } 321862306a36Sopenharmony_ci vha->scan.scan_retry = 0; 321962306a36Sopenharmony_ci 322062306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) 322162306a36Sopenharmony_ci fcport->scan_state = QLA_FCPORT_SCAN; 322262306a36Sopenharmony_ci 322362306a36Sopenharmony_ci for (i = 0; i < vha->hw->max_fibre_devices; i++) { 322462306a36Sopenharmony_ci u64 wwn; 322562306a36Sopenharmony_ci int k; 322662306a36Sopenharmony_ci 322762306a36Sopenharmony_ci rp = &vha->scan.l[i]; 322862306a36Sopenharmony_ci found = false; 322962306a36Sopenharmony_ci 323062306a36Sopenharmony_ci wwn = wwn_to_u64(rp->port_name); 323162306a36Sopenharmony_ci if (wwn == 0) 323262306a36Sopenharmony_ci continue; 323362306a36Sopenharmony_ci 323462306a36Sopenharmony_ci /* Remove duplicate NPORT ID entries from switch data base */ 323562306a36Sopenharmony_ci for (k = i + 1; k < vha->hw->max_fibre_devices; k++) { 323662306a36Sopenharmony_ci trp = &vha->scan.l[k]; 323762306a36Sopenharmony_ci if (rp->id.b24 == trp->id.b24) { 323862306a36Sopenharmony_ci dup = 1; 323962306a36Sopenharmony_ci dup_cnt++; 324062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, 324162306a36Sopenharmony_ci vha, 0xffff, 324262306a36Sopenharmony_ci "Detected duplicate NPORT ID from switch data base: ID %06x WWN %8phN WWN %8phN\n", 324362306a36Sopenharmony_ci rp->id.b24, rp->port_name, trp->port_name); 324462306a36Sopenharmony_ci memset(trp, 0, sizeof(*trp)); 324562306a36Sopenharmony_ci } 324662306a36Sopenharmony_ci } 324762306a36Sopenharmony_ci 324862306a36Sopenharmony_ci if (!memcmp(rp->port_name, vha->port_name, WWN_SIZE)) 324962306a36Sopenharmony_ci continue; 325062306a36Sopenharmony_ci 325162306a36Sopenharmony_ci /* Bypass reserved domain fields. */ 325262306a36Sopenharmony_ci if ((rp->id.b.domain & 0xf0) == 0xf0) 325362306a36Sopenharmony_ci continue; 325462306a36Sopenharmony_ci 325562306a36Sopenharmony_ci /* Bypass virtual ports of the same host. */ 325662306a36Sopenharmony_ci if (qla2x00_is_a_vp(vha, wwn)) 325762306a36Sopenharmony_ci continue; 325862306a36Sopenharmony_ci 325962306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 326062306a36Sopenharmony_ci if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE)) 326162306a36Sopenharmony_ci continue; 326262306a36Sopenharmony_ci fcport->scan_state = QLA_FCPORT_FOUND; 326362306a36Sopenharmony_ci fcport->last_rscn_gen = fcport->rscn_gen; 326462306a36Sopenharmony_ci fcport->fc4_type = rp->fc4type; 326562306a36Sopenharmony_ci found = true; 326662306a36Sopenharmony_ci 326762306a36Sopenharmony_ci if (fcport->scan_needed) { 326862306a36Sopenharmony_ci if (NVME_PRIORITY(vha->hw, fcport)) 326962306a36Sopenharmony_ci fcport->do_prli_nvme = 1; 327062306a36Sopenharmony_ci else 327162306a36Sopenharmony_ci fcport->do_prli_nvme = 0; 327262306a36Sopenharmony_ci } 327362306a36Sopenharmony_ci 327462306a36Sopenharmony_ci /* 327562306a36Sopenharmony_ci * If device was not a fabric device before. 327662306a36Sopenharmony_ci */ 327762306a36Sopenharmony_ci if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { 327862306a36Sopenharmony_ci qla2x00_clear_loop_id(fcport); 327962306a36Sopenharmony_ci fcport->flags |= FCF_FABRIC_DEVICE; 328062306a36Sopenharmony_ci } else if (fcport->d_id.b24 != rp->id.b24 || 328162306a36Sopenharmony_ci (fcport->scan_needed && 328262306a36Sopenharmony_ci fcport->port_type != FCT_INITIATOR && 328362306a36Sopenharmony_ci fcport->port_type != FCT_NVME_INITIATOR)) { 328462306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 328562306a36Sopenharmony_ci } 328662306a36Sopenharmony_ci fcport->d_id.b24 = rp->id.b24; 328762306a36Sopenharmony_ci fcport->scan_needed = 0; 328862306a36Sopenharmony_ci break; 328962306a36Sopenharmony_ci } 329062306a36Sopenharmony_ci 329162306a36Sopenharmony_ci if (!found) { 329262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 329362306a36Sopenharmony_ci "%s %d %8phC post new sess\n", 329462306a36Sopenharmony_ci __func__, __LINE__, rp->port_name); 329562306a36Sopenharmony_ci qla24xx_post_newsess_work(vha, &rp->id, rp->port_name, 329662306a36Sopenharmony_ci rp->node_name, NULL, rp->fc4type); 329762306a36Sopenharmony_ci } 329862306a36Sopenharmony_ci } 329962306a36Sopenharmony_ci 330062306a36Sopenharmony_ci if (dup) { 330162306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xffff, 330262306a36Sopenharmony_ci "Detected %d duplicate NPORT ID(s) from switch data base\n", 330362306a36Sopenharmony_ci dup_cnt); 330462306a36Sopenharmony_ci } 330562306a36Sopenharmony_ci 330662306a36Sopenharmony_cilogin_logout: 330762306a36Sopenharmony_ci /* 330862306a36Sopenharmony_ci * Logout all previous fabric dev marked lost, except FCP2 devices. 330962306a36Sopenharmony_ci */ 331062306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 331162306a36Sopenharmony_ci if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) { 331262306a36Sopenharmony_ci fcport->scan_needed = 0; 331362306a36Sopenharmony_ci continue; 331462306a36Sopenharmony_ci } 331562306a36Sopenharmony_ci 331662306a36Sopenharmony_ci if (fcport->scan_state != QLA_FCPORT_FOUND) { 331762306a36Sopenharmony_ci bool do_delete = false; 331862306a36Sopenharmony_ci 331962306a36Sopenharmony_ci if (fcport->scan_needed && 332062306a36Sopenharmony_ci fcport->disc_state == DSC_LOGIN_PEND) { 332162306a36Sopenharmony_ci /* Cable got disconnected after we sent 332262306a36Sopenharmony_ci * a login. Do delete to prevent timeout. 332362306a36Sopenharmony_ci */ 332462306a36Sopenharmony_ci fcport->logout_on_delete = 1; 332562306a36Sopenharmony_ci do_delete = true; 332662306a36Sopenharmony_ci } 332762306a36Sopenharmony_ci 332862306a36Sopenharmony_ci fcport->scan_needed = 0; 332962306a36Sopenharmony_ci if (((qla_dual_mode_enabled(vha) || 333062306a36Sopenharmony_ci qla_ini_mode_enabled(vha)) && 333162306a36Sopenharmony_ci atomic_read(&fcport->state) == FCS_ONLINE) || 333262306a36Sopenharmony_ci do_delete) { 333362306a36Sopenharmony_ci if (fcport->loop_id != FC_NO_LOOP_ID) { 333462306a36Sopenharmony_ci if (fcport->flags & FCF_FCP2_DEVICE) 333562306a36Sopenharmony_ci continue; 333662306a36Sopenharmony_ci 333762306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0x20f0, 333862306a36Sopenharmony_ci "%s %d %8phC post del sess\n", 333962306a36Sopenharmony_ci __func__, __LINE__, 334062306a36Sopenharmony_ci fcport->port_name); 334162306a36Sopenharmony_ci 334262306a36Sopenharmony_ci fcport->tgt_link_down_time = 0; 334362306a36Sopenharmony_ci qlt_schedule_sess_for_deletion(fcport); 334462306a36Sopenharmony_ci continue; 334562306a36Sopenharmony_ci } 334662306a36Sopenharmony_ci } 334762306a36Sopenharmony_ci } else { 334862306a36Sopenharmony_ci if (fcport->scan_needed || 334962306a36Sopenharmony_ci fcport->disc_state != DSC_LOGIN_COMPLETE) { 335062306a36Sopenharmony_ci if (fcport->login_retry == 0) { 335162306a36Sopenharmony_ci fcport->login_retry = 335262306a36Sopenharmony_ci vha->hw->login_retry_count; 335362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20a3, 335462306a36Sopenharmony_ci "Port login retry %8phN, lid 0x%04x retry cnt=%d.\n", 335562306a36Sopenharmony_ci fcport->port_name, fcport->loop_id, 335662306a36Sopenharmony_ci fcport->login_retry); 335762306a36Sopenharmony_ci } 335862306a36Sopenharmony_ci fcport->scan_needed = 0; 335962306a36Sopenharmony_ci qla24xx_fcport_handle_login(vha, fcport); 336062306a36Sopenharmony_ci } 336162306a36Sopenharmony_ci } 336262306a36Sopenharmony_ci } 336362306a36Sopenharmony_ci 336462306a36Sopenharmony_ci recheck = 1; 336562306a36Sopenharmony_ciout: 336662306a36Sopenharmony_ci qla24xx_sp_unmap(vha, sp); 336762306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 336862306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 336962306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 337062306a36Sopenharmony_ci 337162306a36Sopenharmony_ci if (recheck) { 337262306a36Sopenharmony_ci list_for_each_entry(fcport, &vha->vp_fcports, list) { 337362306a36Sopenharmony_ci if (fcport->scan_needed) { 337462306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 337562306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 337662306a36Sopenharmony_ci break; 337762306a36Sopenharmony_ci } 337862306a36Sopenharmony_ci } 337962306a36Sopenharmony_ci } 338062306a36Sopenharmony_ci} 338162306a36Sopenharmony_ci 338262306a36Sopenharmony_cistatic int qla2x00_post_gnnft_gpnft_done_work(struct scsi_qla_host *vha, 338362306a36Sopenharmony_ci srb_t *sp, int cmd) 338462306a36Sopenharmony_ci{ 338562306a36Sopenharmony_ci struct qla_work_evt *e; 338662306a36Sopenharmony_ci 338762306a36Sopenharmony_ci if (cmd != QLA_EVT_GPNFT_DONE && cmd != QLA_EVT_GNNFT_DONE) 338862306a36Sopenharmony_ci return QLA_PARAMETER_ERROR; 338962306a36Sopenharmony_ci 339062306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, cmd); 339162306a36Sopenharmony_ci if (!e) 339262306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 339362306a36Sopenharmony_ci 339462306a36Sopenharmony_ci e->u.iosb.sp = sp; 339562306a36Sopenharmony_ci 339662306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 339762306a36Sopenharmony_ci} 339862306a36Sopenharmony_ci 339962306a36Sopenharmony_cistatic int qla2x00_post_nvme_gpnft_work(struct scsi_qla_host *vha, 340062306a36Sopenharmony_ci srb_t *sp, int cmd) 340162306a36Sopenharmony_ci{ 340262306a36Sopenharmony_ci struct qla_work_evt *e; 340362306a36Sopenharmony_ci 340462306a36Sopenharmony_ci if (cmd != QLA_EVT_GPNFT) 340562306a36Sopenharmony_ci return QLA_PARAMETER_ERROR; 340662306a36Sopenharmony_ci 340762306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, cmd); 340862306a36Sopenharmony_ci if (!e) 340962306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 341062306a36Sopenharmony_ci 341162306a36Sopenharmony_ci e->u.gpnft.fc4_type = FC4_TYPE_NVME; 341262306a36Sopenharmony_ci e->u.gpnft.sp = sp; 341362306a36Sopenharmony_ci 341462306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 341562306a36Sopenharmony_ci} 341662306a36Sopenharmony_ci 341762306a36Sopenharmony_cistatic void qla2x00_find_free_fcp_nvme_slot(struct scsi_qla_host *vha, 341862306a36Sopenharmony_ci struct srb *sp) 341962306a36Sopenharmony_ci{ 342062306a36Sopenharmony_ci struct qla_hw_data *ha = vha->hw; 342162306a36Sopenharmony_ci int num_fibre_dev = ha->max_fibre_devices; 342262306a36Sopenharmony_ci struct ct_sns_req *ct_req = 342362306a36Sopenharmony_ci (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; 342462306a36Sopenharmony_ci struct ct_sns_gpnft_rsp *ct_rsp = 342562306a36Sopenharmony_ci (struct ct_sns_gpnft_rsp *)sp->u.iocb_cmd.u.ctarg.rsp; 342662306a36Sopenharmony_ci struct ct_sns_gpn_ft_data *d; 342762306a36Sopenharmony_ci struct fab_scan_rp *rp; 342862306a36Sopenharmony_ci u16 cmd = be16_to_cpu(ct_req->command); 342962306a36Sopenharmony_ci u8 fc4_type = sp->gen2; 343062306a36Sopenharmony_ci int i, j, k; 343162306a36Sopenharmony_ci port_id_t id; 343262306a36Sopenharmony_ci u8 found; 343362306a36Sopenharmony_ci u64 wwn; 343462306a36Sopenharmony_ci 343562306a36Sopenharmony_ci j = 0; 343662306a36Sopenharmony_ci for (i = 0; i < num_fibre_dev; i++) { 343762306a36Sopenharmony_ci d = &ct_rsp->entries[i]; 343862306a36Sopenharmony_ci 343962306a36Sopenharmony_ci id.b.rsvd_1 = 0; 344062306a36Sopenharmony_ci id.b.domain = d->port_id[0]; 344162306a36Sopenharmony_ci id.b.area = d->port_id[1]; 344262306a36Sopenharmony_ci id.b.al_pa = d->port_id[2]; 344362306a36Sopenharmony_ci wwn = wwn_to_u64(d->port_name); 344462306a36Sopenharmony_ci 344562306a36Sopenharmony_ci if (id.b24 == 0 || wwn == 0) 344662306a36Sopenharmony_ci continue; 344762306a36Sopenharmony_ci 344862306a36Sopenharmony_ci if (fc4_type == FC4_TYPE_FCP_SCSI) { 344962306a36Sopenharmony_ci if (cmd == GPN_FT_CMD) { 345062306a36Sopenharmony_ci rp = &vha->scan.l[j]; 345162306a36Sopenharmony_ci rp->id = id; 345262306a36Sopenharmony_ci memcpy(rp->port_name, d->port_name, 8); 345362306a36Sopenharmony_ci j++; 345462306a36Sopenharmony_ci rp->fc4type = FS_FC4TYPE_FCP; 345562306a36Sopenharmony_ci } else { 345662306a36Sopenharmony_ci for (k = 0; k < num_fibre_dev; k++) { 345762306a36Sopenharmony_ci rp = &vha->scan.l[k]; 345862306a36Sopenharmony_ci if (id.b24 == rp->id.b24) { 345962306a36Sopenharmony_ci memcpy(rp->node_name, 346062306a36Sopenharmony_ci d->port_name, 8); 346162306a36Sopenharmony_ci break; 346262306a36Sopenharmony_ci } 346362306a36Sopenharmony_ci } 346462306a36Sopenharmony_ci } 346562306a36Sopenharmony_ci } else { 346662306a36Sopenharmony_ci /* Search if the fibre device supports FC4_TYPE_NVME */ 346762306a36Sopenharmony_ci if (cmd == GPN_FT_CMD) { 346862306a36Sopenharmony_ci found = 0; 346962306a36Sopenharmony_ci 347062306a36Sopenharmony_ci for (k = 0; k < num_fibre_dev; k++) { 347162306a36Sopenharmony_ci rp = &vha->scan.l[k]; 347262306a36Sopenharmony_ci if (!memcmp(rp->port_name, 347362306a36Sopenharmony_ci d->port_name, 8)) { 347462306a36Sopenharmony_ci /* 347562306a36Sopenharmony_ci * Supports FC-NVMe & FCP 347662306a36Sopenharmony_ci */ 347762306a36Sopenharmony_ci rp->fc4type |= FS_FC4TYPE_NVME; 347862306a36Sopenharmony_ci found = 1; 347962306a36Sopenharmony_ci break; 348062306a36Sopenharmony_ci } 348162306a36Sopenharmony_ci } 348262306a36Sopenharmony_ci 348362306a36Sopenharmony_ci /* We found new FC-NVMe only port */ 348462306a36Sopenharmony_ci if (!found) { 348562306a36Sopenharmony_ci for (k = 0; k < num_fibre_dev; k++) { 348662306a36Sopenharmony_ci rp = &vha->scan.l[k]; 348762306a36Sopenharmony_ci if (wwn_to_u64(rp->port_name)) { 348862306a36Sopenharmony_ci continue; 348962306a36Sopenharmony_ci } else { 349062306a36Sopenharmony_ci rp->id = id; 349162306a36Sopenharmony_ci memcpy(rp->port_name, 349262306a36Sopenharmony_ci d->port_name, 8); 349362306a36Sopenharmony_ci rp->fc4type = 349462306a36Sopenharmony_ci FS_FC4TYPE_NVME; 349562306a36Sopenharmony_ci break; 349662306a36Sopenharmony_ci } 349762306a36Sopenharmony_ci } 349862306a36Sopenharmony_ci } 349962306a36Sopenharmony_ci } else { 350062306a36Sopenharmony_ci for (k = 0; k < num_fibre_dev; k++) { 350162306a36Sopenharmony_ci rp = &vha->scan.l[k]; 350262306a36Sopenharmony_ci if (id.b24 == rp->id.b24) { 350362306a36Sopenharmony_ci memcpy(rp->node_name, 350462306a36Sopenharmony_ci d->port_name, 8); 350562306a36Sopenharmony_ci break; 350662306a36Sopenharmony_ci } 350762306a36Sopenharmony_ci } 350862306a36Sopenharmony_ci } 350962306a36Sopenharmony_ci } 351062306a36Sopenharmony_ci } 351162306a36Sopenharmony_ci} 351262306a36Sopenharmony_ci 351362306a36Sopenharmony_cistatic void qla2x00_async_gpnft_gnnft_sp_done(srb_t *sp, int res) 351462306a36Sopenharmony_ci{ 351562306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 351662306a36Sopenharmony_ci struct ct_sns_req *ct_req = 351762306a36Sopenharmony_ci (struct ct_sns_req *)sp->u.iocb_cmd.u.ctarg.req; 351862306a36Sopenharmony_ci u16 cmd = be16_to_cpu(ct_req->command); 351962306a36Sopenharmony_ci u8 fc4_type = sp->gen2; 352062306a36Sopenharmony_ci unsigned long flags; 352162306a36Sopenharmony_ci int rc; 352262306a36Sopenharmony_ci 352362306a36Sopenharmony_ci /* gen2 field is holding the fc4type */ 352462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 352562306a36Sopenharmony_ci "Async done-%s res %x FC4Type %x\n", 352662306a36Sopenharmony_ci sp->name, res, sp->gen2); 352762306a36Sopenharmony_ci 352862306a36Sopenharmony_ci sp->rc = res; 352962306a36Sopenharmony_ci if (res) { 353062306a36Sopenharmony_ci unsigned long flags; 353162306a36Sopenharmony_ci const char *name = sp->name; 353262306a36Sopenharmony_ci 353362306a36Sopenharmony_ci if (res == QLA_OS_TIMER_EXPIRED) { 353462306a36Sopenharmony_ci /* switch is ignoring all commands. 353562306a36Sopenharmony_ci * This might be a zone disable behavior. 353662306a36Sopenharmony_ci * This means we hit 64s timeout. 353762306a36Sopenharmony_ci * 22s GPNFT + 44s Abort = 64s 353862306a36Sopenharmony_ci */ 353962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 354062306a36Sopenharmony_ci "%s: Switch Zone check please .\n", 354162306a36Sopenharmony_ci name); 354262306a36Sopenharmony_ci qla2x00_mark_all_devices_lost(vha); 354362306a36Sopenharmony_ci } 354462306a36Sopenharmony_ci 354562306a36Sopenharmony_ci /* 354662306a36Sopenharmony_ci * We are in an Interrupt context, queue up this 354762306a36Sopenharmony_ci * sp for GNNFT_DONE work. This will allow all 354862306a36Sopenharmony_ci * the resource to get freed up. 354962306a36Sopenharmony_ci */ 355062306a36Sopenharmony_ci rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, 355162306a36Sopenharmony_ci QLA_EVT_GNNFT_DONE); 355262306a36Sopenharmony_ci if (rc) { 355362306a36Sopenharmony_ci /* Cleanup here to prevent memory leak */ 355462306a36Sopenharmony_ci qla24xx_sp_unmap(vha, sp); 355562306a36Sopenharmony_ci 355662306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 355762306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 355862306a36Sopenharmony_ci vha->scan.scan_retry++; 355962306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 356062306a36Sopenharmony_ci 356162306a36Sopenharmony_ci if (vha->scan.scan_retry < MAX_SCAN_RETRIES) { 356262306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 356362306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 356462306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 356562306a36Sopenharmony_ci } else { 356662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 356762306a36Sopenharmony_ci "Async done-%s rescan failed on all retries.\n", 356862306a36Sopenharmony_ci name); 356962306a36Sopenharmony_ci } 357062306a36Sopenharmony_ci } 357162306a36Sopenharmony_ci return; 357262306a36Sopenharmony_ci } 357362306a36Sopenharmony_ci 357462306a36Sopenharmony_ci qla2x00_find_free_fcp_nvme_slot(vha, sp); 357562306a36Sopenharmony_ci 357662306a36Sopenharmony_ci if ((fc4_type == FC4_TYPE_FCP_SCSI) && vha->flags.nvme_enabled && 357762306a36Sopenharmony_ci cmd == GNN_FT_CMD) { 357862306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 357962306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 358062306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 358162306a36Sopenharmony_ci 358262306a36Sopenharmony_ci sp->rc = res; 358362306a36Sopenharmony_ci rc = qla2x00_post_nvme_gpnft_work(vha, sp, QLA_EVT_GPNFT); 358462306a36Sopenharmony_ci if (rc) { 358562306a36Sopenharmony_ci qla24xx_sp_unmap(vha, sp); 358662306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 358762306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 358862306a36Sopenharmony_ci } 358962306a36Sopenharmony_ci return; 359062306a36Sopenharmony_ci } 359162306a36Sopenharmony_ci 359262306a36Sopenharmony_ci if (cmd == GPN_FT_CMD) { 359362306a36Sopenharmony_ci rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, 359462306a36Sopenharmony_ci QLA_EVT_GPNFT_DONE); 359562306a36Sopenharmony_ci } else { 359662306a36Sopenharmony_ci rc = qla2x00_post_gnnft_gpnft_done_work(vha, sp, 359762306a36Sopenharmony_ci QLA_EVT_GNNFT_DONE); 359862306a36Sopenharmony_ci } 359962306a36Sopenharmony_ci 360062306a36Sopenharmony_ci if (rc) { 360162306a36Sopenharmony_ci qla24xx_sp_unmap(vha, sp); 360262306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 360362306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 360462306a36Sopenharmony_ci return; 360562306a36Sopenharmony_ci } 360662306a36Sopenharmony_ci} 360762306a36Sopenharmony_ci 360862306a36Sopenharmony_ci/* 360962306a36Sopenharmony_ci * Get WWNN list for fc4_type 361062306a36Sopenharmony_ci * 361162306a36Sopenharmony_ci * It is assumed the same SRB is re-used from GPNFT to avoid 361262306a36Sopenharmony_ci * mem free & re-alloc 361362306a36Sopenharmony_ci */ 361462306a36Sopenharmony_cistatic int qla24xx_async_gnnft(scsi_qla_host_t *vha, struct srb *sp, 361562306a36Sopenharmony_ci u8 fc4_type) 361662306a36Sopenharmony_ci{ 361762306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 361862306a36Sopenharmony_ci struct ct_sns_req *ct_req; 361962306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 362062306a36Sopenharmony_ci unsigned long flags; 362162306a36Sopenharmony_ci 362262306a36Sopenharmony_ci if (!vha->flags.online) { 362362306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 362462306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 362562306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 362662306a36Sopenharmony_ci goto done_free_sp; 362762306a36Sopenharmony_ci } 362862306a36Sopenharmony_ci 362962306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req || !sp->u.iocb_cmd.u.ctarg.rsp) { 363062306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xffff, 363162306a36Sopenharmony_ci "%s: req %p rsp %p are not setup\n", 363262306a36Sopenharmony_ci __func__, sp->u.iocb_cmd.u.ctarg.req, 363362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp); 363462306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 363562306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 363662306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 363762306a36Sopenharmony_ci WARN_ON(1); 363862306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 363962306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 364062306a36Sopenharmony_ci goto done_free_sp; 364162306a36Sopenharmony_ci } 364262306a36Sopenharmony_ci 364362306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xfffff, 364462306a36Sopenharmony_ci "%s: FC4Type %x, CT-PASSTHRU %s command ctarg rsp size %d, ctarg req size %d\n", 364562306a36Sopenharmony_ci __func__, fc4_type, sp->name, sp->u.iocb_cmd.u.ctarg.rsp_size, 364662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size); 364762306a36Sopenharmony_ci 364862306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 364962306a36Sopenharmony_ci sp->name = "gnnft"; 365062306a36Sopenharmony_ci sp->gen1 = vha->hw->base_qpair->chip_reset; 365162306a36Sopenharmony_ci sp->gen2 = fc4_type; 365262306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 365362306a36Sopenharmony_ci qla2x00_async_gpnft_gnnft_sp_done); 365462306a36Sopenharmony_ci 365562306a36Sopenharmony_ci memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size); 365662306a36Sopenharmony_ci memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size); 365762306a36Sopenharmony_ci 365862306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; 365962306a36Sopenharmony_ci /* CT_IU preamble */ 366062306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ct_sns, GNN_FT_CMD, 366162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size); 366262306a36Sopenharmony_ci 366362306a36Sopenharmony_ci /* GPN_FT req */ 366462306a36Sopenharmony_ci ct_req->req.gpn_ft.port_type = fc4_type; 366562306a36Sopenharmony_ci 366662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = GNN_FT_REQ_SIZE; 366762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 366862306a36Sopenharmony_ci 366962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 367062306a36Sopenharmony_ci "Async-%s hdl=%x FC4Type %x.\n", sp->name, 367162306a36Sopenharmony_ci sp->handle, ct_req->req.gpn_ft.port_type); 367262306a36Sopenharmony_ci 367362306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 367462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 367562306a36Sopenharmony_ci goto done_free_sp; 367662306a36Sopenharmony_ci } 367762306a36Sopenharmony_ci 367862306a36Sopenharmony_ci return rval; 367962306a36Sopenharmony_ci 368062306a36Sopenharmony_cidone_free_sp: 368162306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.req) { 368262306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 368362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 368462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 368562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 368662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 368762306a36Sopenharmony_ci } 368862306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.rsp) { 368962306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 369062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 369162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp, 369262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma); 369362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = NULL; 369462306a36Sopenharmony_ci } 369562306a36Sopenharmony_ci /* ref: INIT */ 369662306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 369762306a36Sopenharmony_ci 369862306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 369962306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 370062306a36Sopenharmony_ci if (vha->scan.scan_flags == 0) { 370162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 370262306a36Sopenharmony_ci "%s: schedule\n", __func__); 370362306a36Sopenharmony_ci vha->scan.scan_flags |= SF_QUEUED; 370462306a36Sopenharmony_ci schedule_delayed_work(&vha->scan.scan_work, 5); 370562306a36Sopenharmony_ci } 370662306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 370762306a36Sopenharmony_ci 370862306a36Sopenharmony_ci 370962306a36Sopenharmony_ci return rval; 371062306a36Sopenharmony_ci} /* GNNFT */ 371162306a36Sopenharmony_ci 371262306a36Sopenharmony_civoid qla24xx_async_gpnft_done(scsi_qla_host_t *vha, srb_t *sp) 371362306a36Sopenharmony_ci{ 371462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 371562306a36Sopenharmony_ci "%s enter\n", __func__); 371662306a36Sopenharmony_ci qla24xx_async_gnnft(vha, sp, sp->gen2); 371762306a36Sopenharmony_ci} 371862306a36Sopenharmony_ci 371962306a36Sopenharmony_ci/* Get WWPN list for certain fc4_type */ 372062306a36Sopenharmony_ciint qla24xx_async_gpnft(scsi_qla_host_t *vha, u8 fc4_type, srb_t *sp) 372162306a36Sopenharmony_ci{ 372262306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 372362306a36Sopenharmony_ci struct ct_sns_req *ct_req; 372462306a36Sopenharmony_ci struct ct_sns_pkt *ct_sns; 372562306a36Sopenharmony_ci u32 rspsz; 372662306a36Sopenharmony_ci unsigned long flags; 372762306a36Sopenharmony_ci 372862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 372962306a36Sopenharmony_ci "%s enter\n", __func__); 373062306a36Sopenharmony_ci 373162306a36Sopenharmony_ci if (!vha->flags.online) 373262306a36Sopenharmony_ci return rval; 373362306a36Sopenharmony_ci 373462306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 373562306a36Sopenharmony_ci if (vha->scan.scan_flags & SF_SCANNING) { 373662306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 373762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 373862306a36Sopenharmony_ci "%s: scan active\n", __func__); 373962306a36Sopenharmony_ci return rval; 374062306a36Sopenharmony_ci } 374162306a36Sopenharmony_ci vha->scan.scan_flags |= SF_SCANNING; 374262306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 374362306a36Sopenharmony_ci 374462306a36Sopenharmony_ci if (fc4_type == FC4_TYPE_FCP_SCSI) { 374562306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 374662306a36Sopenharmony_ci "%s: Performing FCP Scan\n", __func__); 374762306a36Sopenharmony_ci 374862306a36Sopenharmony_ci if (sp) { 374962306a36Sopenharmony_ci /* ref: INIT */ 375062306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 375162306a36Sopenharmony_ci } 375262306a36Sopenharmony_ci 375362306a36Sopenharmony_ci /* ref: INIT */ 375462306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, NULL, GFP_KERNEL); 375562306a36Sopenharmony_ci if (!sp) { 375662306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 375762306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 375862306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 375962306a36Sopenharmony_ci return rval; 376062306a36Sopenharmony_ci } 376162306a36Sopenharmony_ci 376262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = dma_alloc_coherent(&vha->hw->pdev->dev, 376362306a36Sopenharmony_ci sizeof(struct ct_sns_pkt), 376462306a36Sopenharmony_ci &sp->u.iocb_cmd.u.ctarg.req_dma, 376562306a36Sopenharmony_ci GFP_KERNEL); 376662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size = sizeof(struct ct_sns_pkt); 376762306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.req) { 376862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xffff, 376962306a36Sopenharmony_ci "Failed to allocate ct_sns request.\n"); 377062306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 377162306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 377262306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 377362306a36Sopenharmony_ci qla2x00_rel_sp(sp); 377462306a36Sopenharmony_ci return rval; 377562306a36Sopenharmony_ci } 377662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = GPN_FT_REQ_SIZE; 377762306a36Sopenharmony_ci 377862306a36Sopenharmony_ci rspsz = sizeof(struct ct_sns_gpnft_rsp) + 377962306a36Sopenharmony_ci vha->hw->max_fibre_devices * 378062306a36Sopenharmony_ci sizeof(struct ct_sns_gpn_ft_data); 378162306a36Sopenharmony_ci 378262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = dma_alloc_coherent(&vha->hw->pdev->dev, 378362306a36Sopenharmony_ci rspsz, 378462306a36Sopenharmony_ci &sp->u.iocb_cmd.u.ctarg.rsp_dma, 378562306a36Sopenharmony_ci GFP_KERNEL); 378662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size = rspsz; 378762306a36Sopenharmony_ci if (!sp->u.iocb_cmd.u.ctarg.rsp) { 378862306a36Sopenharmony_ci ql_log(ql_log_warn, vha, 0xffff, 378962306a36Sopenharmony_ci "Failed to allocate ct_sns request.\n"); 379062306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 379162306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 379262306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 379362306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 379462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 379562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 379662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 379762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 379862306a36Sopenharmony_ci /* ref: INIT */ 379962306a36Sopenharmony_ci qla2x00_rel_sp(sp); 380062306a36Sopenharmony_ci return rval; 380162306a36Sopenharmony_ci } 380262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = rspsz; 380362306a36Sopenharmony_ci 380462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 380562306a36Sopenharmony_ci "%s scan list size %d\n", __func__, vha->scan.size); 380662306a36Sopenharmony_ci 380762306a36Sopenharmony_ci memset(vha->scan.l, 0, vha->scan.size); 380862306a36Sopenharmony_ci } else if (!sp) { 380962306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 381062306a36Sopenharmony_ci "NVME scan did not provide SP\n"); 381162306a36Sopenharmony_ci return rval; 381262306a36Sopenharmony_ci } 381362306a36Sopenharmony_ci 381462306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 381562306a36Sopenharmony_ci sp->name = "gpnft"; 381662306a36Sopenharmony_ci sp->gen1 = vha->hw->base_qpair->chip_reset; 381762306a36Sopenharmony_ci sp->gen2 = fc4_type; 381862306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 381962306a36Sopenharmony_ci qla2x00_async_gpnft_gnnft_sp_done); 382062306a36Sopenharmony_ci 382162306a36Sopenharmony_ci rspsz = sp->u.iocb_cmd.u.ctarg.rsp_size; 382262306a36Sopenharmony_ci memset(sp->u.iocb_cmd.u.ctarg.rsp, 0, sp->u.iocb_cmd.u.ctarg.rsp_size); 382362306a36Sopenharmony_ci memset(sp->u.iocb_cmd.u.ctarg.req, 0, sp->u.iocb_cmd.u.ctarg.req_size); 382462306a36Sopenharmony_ci 382562306a36Sopenharmony_ci ct_sns = (struct ct_sns_pkt *)sp->u.iocb_cmd.u.ctarg.req; 382662306a36Sopenharmony_ci /* CT_IU preamble */ 382762306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(ct_sns, GPN_FT_CMD, rspsz); 382862306a36Sopenharmony_ci 382962306a36Sopenharmony_ci /* GPN_FT req */ 383062306a36Sopenharmony_ci ct_req->req.gpn_ft.port_type = fc4_type; 383162306a36Sopenharmony_ci 383262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 383362306a36Sopenharmony_ci 383462306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 383562306a36Sopenharmony_ci "Async-%s hdl=%x FC4Type %x.\n", sp->name, 383662306a36Sopenharmony_ci sp->handle, ct_req->req.gpn_ft.port_type); 383762306a36Sopenharmony_ci 383862306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 383962306a36Sopenharmony_ci if (rval != QLA_SUCCESS) { 384062306a36Sopenharmony_ci goto done_free_sp; 384162306a36Sopenharmony_ci } 384262306a36Sopenharmony_ci 384362306a36Sopenharmony_ci return rval; 384462306a36Sopenharmony_ci 384562306a36Sopenharmony_cidone_free_sp: 384662306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.req) { 384762306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 384862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_allocated_size, 384962306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req, 385062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma); 385162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = NULL; 385262306a36Sopenharmony_ci } 385362306a36Sopenharmony_ci if (sp->u.iocb_cmd.u.ctarg.rsp) { 385462306a36Sopenharmony_ci dma_free_coherent(&vha->hw->pdev->dev, 385562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_allocated_size, 385662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp, 385762306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma); 385862306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = NULL; 385962306a36Sopenharmony_ci } 386062306a36Sopenharmony_ci 386162306a36Sopenharmony_ci /* ref: INIT */ 386262306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 386362306a36Sopenharmony_ci 386462306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 386562306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_SCANNING; 386662306a36Sopenharmony_ci if (vha->scan.scan_flags == 0) { 386762306a36Sopenharmony_ci ql_dbg(ql_dbg_disc + ql_dbg_verbose, vha, 0xffff, 386862306a36Sopenharmony_ci "%s: Scan scheduled.\n", __func__); 386962306a36Sopenharmony_ci vha->scan.scan_flags |= SF_QUEUED; 387062306a36Sopenharmony_ci schedule_delayed_work(&vha->scan.scan_work, 5); 387162306a36Sopenharmony_ci } 387262306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 387362306a36Sopenharmony_ci 387462306a36Sopenharmony_ci 387562306a36Sopenharmony_ci return rval; 387662306a36Sopenharmony_ci} 387762306a36Sopenharmony_ci 387862306a36Sopenharmony_civoid qla_scan_work_fn(struct work_struct *work) 387962306a36Sopenharmony_ci{ 388062306a36Sopenharmony_ci struct fab_scan *s = container_of(to_delayed_work(work), 388162306a36Sopenharmony_ci struct fab_scan, scan_work); 388262306a36Sopenharmony_ci struct scsi_qla_host *vha = container_of(s, struct scsi_qla_host, 388362306a36Sopenharmony_ci scan); 388462306a36Sopenharmony_ci unsigned long flags; 388562306a36Sopenharmony_ci 388662306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 388762306a36Sopenharmony_ci "%s: schedule loop resync\n", __func__); 388862306a36Sopenharmony_ci set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags); 388962306a36Sopenharmony_ci set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags); 389062306a36Sopenharmony_ci qla2xxx_wake_dpc(vha); 389162306a36Sopenharmony_ci spin_lock_irqsave(&vha->work_lock, flags); 389262306a36Sopenharmony_ci vha->scan.scan_flags &= ~SF_QUEUED; 389362306a36Sopenharmony_ci spin_unlock_irqrestore(&vha->work_lock, flags); 389462306a36Sopenharmony_ci} 389562306a36Sopenharmony_ci 389662306a36Sopenharmony_ci/* GPFN_ID */ 389762306a36Sopenharmony_civoid qla24xx_handle_gfpnid_event(scsi_qla_host_t *vha, struct event_arg *ea) 389862306a36Sopenharmony_ci{ 389962306a36Sopenharmony_ci fc_port_t *fcport = ea->fcport; 390062306a36Sopenharmony_ci 390162306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 390262306a36Sopenharmony_ci "%s %8phC DS %d LS %d rc %d login %d|%d rscn %d|%d fcpcnt %d\n", 390362306a36Sopenharmony_ci __func__, fcport->port_name, fcport->disc_state, 390462306a36Sopenharmony_ci fcport->fw_login_state, ea->rc, fcport->login_gen, ea->sp->gen2, 390562306a36Sopenharmony_ci fcport->rscn_gen, ea->sp->gen1, vha->fcport_count); 390662306a36Sopenharmony_ci 390762306a36Sopenharmony_ci if (fcport->disc_state == DSC_DELETE_PEND) 390862306a36Sopenharmony_ci return; 390962306a36Sopenharmony_ci 391062306a36Sopenharmony_ci if (ea->sp->gen2 != fcport->login_gen) { 391162306a36Sopenharmony_ci /* target side must have changed it. */ 391262306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x20d3, 391362306a36Sopenharmony_ci "%s %8phC generation changed\n", 391462306a36Sopenharmony_ci __func__, fcport->port_name); 391562306a36Sopenharmony_ci return; 391662306a36Sopenharmony_ci } else if (ea->sp->gen1 != fcport->rscn_gen) { 391762306a36Sopenharmony_ci return; 391862306a36Sopenharmony_ci } 391962306a36Sopenharmony_ci 392062306a36Sopenharmony_ci qla24xx_post_gpsc_work(vha, fcport); 392162306a36Sopenharmony_ci} 392262306a36Sopenharmony_ci 392362306a36Sopenharmony_cistatic void qla2x00_async_gfpnid_sp_done(srb_t *sp, int res) 392462306a36Sopenharmony_ci{ 392562306a36Sopenharmony_ci struct scsi_qla_host *vha = sp->vha; 392662306a36Sopenharmony_ci fc_port_t *fcport = sp->fcport; 392762306a36Sopenharmony_ci u8 *fpn = fcport->ct_desc.ct_sns->p.rsp.rsp.gfpn_id.port_name; 392862306a36Sopenharmony_ci struct event_arg ea; 392962306a36Sopenharmony_ci u64 wwn; 393062306a36Sopenharmony_ci 393162306a36Sopenharmony_ci wwn = wwn_to_u64(fpn); 393262306a36Sopenharmony_ci if (wwn) 393362306a36Sopenharmony_ci memcpy(fcport->fabric_port_name, fpn, WWN_SIZE); 393462306a36Sopenharmony_ci 393562306a36Sopenharmony_ci memset(&ea, 0, sizeof(ea)); 393662306a36Sopenharmony_ci ea.fcport = fcport; 393762306a36Sopenharmony_ci ea.sp = sp; 393862306a36Sopenharmony_ci ea.rc = res; 393962306a36Sopenharmony_ci 394062306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0x204f, 394162306a36Sopenharmony_ci "Async done-%s res %x, WWPN %8phC %8phC\n", 394262306a36Sopenharmony_ci sp->name, res, fcport->port_name, fcport->fabric_port_name); 394362306a36Sopenharmony_ci 394462306a36Sopenharmony_ci qla24xx_handle_gfpnid_event(vha, &ea); 394562306a36Sopenharmony_ci 394662306a36Sopenharmony_ci /* ref: INIT */ 394762306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 394862306a36Sopenharmony_ci} 394962306a36Sopenharmony_ci 395062306a36Sopenharmony_ciint qla24xx_async_gfpnid(scsi_qla_host_t *vha, fc_port_t *fcport) 395162306a36Sopenharmony_ci{ 395262306a36Sopenharmony_ci int rval = QLA_FUNCTION_FAILED; 395362306a36Sopenharmony_ci struct ct_sns_req *ct_req; 395462306a36Sopenharmony_ci srb_t *sp; 395562306a36Sopenharmony_ci 395662306a36Sopenharmony_ci if (!vha->flags.online || (fcport->flags & FCF_ASYNC_SENT)) 395762306a36Sopenharmony_ci return rval; 395862306a36Sopenharmony_ci 395962306a36Sopenharmony_ci /* ref: INIT */ 396062306a36Sopenharmony_ci sp = qla2x00_get_sp(vha, fcport, GFP_ATOMIC); 396162306a36Sopenharmony_ci if (!sp) 396262306a36Sopenharmony_ci goto done; 396362306a36Sopenharmony_ci 396462306a36Sopenharmony_ci sp->type = SRB_CT_PTHRU_CMD; 396562306a36Sopenharmony_ci sp->name = "gfpnid"; 396662306a36Sopenharmony_ci sp->gen1 = fcport->rscn_gen; 396762306a36Sopenharmony_ci sp->gen2 = fcport->login_gen; 396862306a36Sopenharmony_ci qla2x00_init_async_sp(sp, qla2x00_get_async_timeout(vha) + 2, 396962306a36Sopenharmony_ci qla2x00_async_gfpnid_sp_done); 397062306a36Sopenharmony_ci 397162306a36Sopenharmony_ci /* CT_IU preamble */ 397262306a36Sopenharmony_ci ct_req = qla2x00_prep_ct_req(fcport->ct_desc.ct_sns, GFPN_ID_CMD, 397362306a36Sopenharmony_ci GFPN_ID_RSP_SIZE); 397462306a36Sopenharmony_ci 397562306a36Sopenharmony_ci /* GFPN_ID req */ 397662306a36Sopenharmony_ci ct_req->req.port_id.port_id = port_id_to_be_id(fcport->d_id); 397762306a36Sopenharmony_ci 397862306a36Sopenharmony_ci 397962306a36Sopenharmony_ci /* req & rsp use the same buffer */ 398062306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req = fcport->ct_desc.ct_sns; 398162306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_dma = fcport->ct_desc.ct_sns_dma; 398262306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp = fcport->ct_desc.ct_sns; 398362306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_dma = fcport->ct_desc.ct_sns_dma; 398462306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.req_size = GFPN_ID_REQ_SIZE; 398562306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.rsp_size = GFPN_ID_RSP_SIZE; 398662306a36Sopenharmony_ci sp->u.iocb_cmd.u.ctarg.nport_handle = NPH_SNS; 398762306a36Sopenharmony_ci 398862306a36Sopenharmony_ci ql_dbg(ql_dbg_disc, vha, 0xffff, 398962306a36Sopenharmony_ci "Async-%s - %8phC hdl=%x loopid=%x portid %06x.\n", 399062306a36Sopenharmony_ci sp->name, fcport->port_name, 399162306a36Sopenharmony_ci sp->handle, fcport->loop_id, fcport->d_id.b24); 399262306a36Sopenharmony_ci 399362306a36Sopenharmony_ci rval = qla2x00_start_sp(sp); 399462306a36Sopenharmony_ci if (rval != QLA_SUCCESS) 399562306a36Sopenharmony_ci goto done_free_sp; 399662306a36Sopenharmony_ci 399762306a36Sopenharmony_ci return rval; 399862306a36Sopenharmony_ci 399962306a36Sopenharmony_cidone_free_sp: 400062306a36Sopenharmony_ci /* ref: INIT */ 400162306a36Sopenharmony_ci kref_put(&sp->cmd_kref, qla2x00_sp_release); 400262306a36Sopenharmony_cidone: 400362306a36Sopenharmony_ci return rval; 400462306a36Sopenharmony_ci} 400562306a36Sopenharmony_ci 400662306a36Sopenharmony_ciint qla24xx_post_gfpnid_work(struct scsi_qla_host *vha, fc_port_t *fcport) 400762306a36Sopenharmony_ci{ 400862306a36Sopenharmony_ci struct qla_work_evt *e; 400962306a36Sopenharmony_ci int ls; 401062306a36Sopenharmony_ci 401162306a36Sopenharmony_ci ls = atomic_read(&vha->loop_state); 401262306a36Sopenharmony_ci if (((ls != LOOP_READY) && (ls != LOOP_UP)) || 401362306a36Sopenharmony_ci test_bit(UNLOADING, &vha->dpc_flags)) 401462306a36Sopenharmony_ci return 0; 401562306a36Sopenharmony_ci 401662306a36Sopenharmony_ci e = qla2x00_alloc_work(vha, QLA_EVT_GFPNID); 401762306a36Sopenharmony_ci if (!e) 401862306a36Sopenharmony_ci return QLA_FUNCTION_FAILED; 401962306a36Sopenharmony_ci 402062306a36Sopenharmony_ci e->u.fcport.fcport = fcport; 402162306a36Sopenharmony_ci return qla2x00_post_work(vha, e); 402262306a36Sopenharmony_ci} 4023