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 = &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