1/*
2 * QLogic Fibre Channel HBA Driver
3 * Copyright (c)  2003-2011 QLogic Corporation
4 *
5 * See LICENSE.qla2xxx for copyright and licensing details.
6 */
7#include "qla_def.h"
8
9static int qla2x00_sns_ga_nxt(scsi_qla_host_t *, fc_port_t *);
10static int qla2x00_sns_gid_pt(scsi_qla_host_t *, sw_info_t *);
11static int qla2x00_sns_gpn_id(scsi_qla_host_t *, sw_info_t *);
12static int qla2x00_sns_gnn_id(scsi_qla_host_t *, sw_info_t *);
13static int qla2x00_sns_rft_id(scsi_qla_host_t *);
14static int qla2x00_sns_rnn_id(scsi_qla_host_t *);
15
16/**
17 * qla2x00_prep_ms_iocb() - Prepare common MS/CT IOCB fields for SNS CT query.
18 * @ha: HA context
19 * @req_size: request size in bytes
20 * @rsp_size: response size in bytes
21 *
22 * Returns a pointer to the @ha's ms_iocb.
23 */
24void *
25qla2x00_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
26{
27	struct qla_hw_data *ha = vha->hw;
28	ms_iocb_entry_t *ms_pkt;
29
30	ms_pkt = ha->ms_iocb;
31	memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));
32
33	ms_pkt->entry_type = MS_IOCB_TYPE;
34	ms_pkt->entry_count = 1;
35	SET_TARGET_ID(ha, ms_pkt->loop_id, SIMPLE_NAME_SERVER);
36	ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
37	ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
38	ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
39	ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
40	ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
41	ms_pkt->req_bytecount = cpu_to_le32(req_size);
42
43	ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
44	ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
45	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
46
47	ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
48	ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
49	ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
50
51	return (ms_pkt);
52}
53
54/**
55 * qla24xx_prep_ms_iocb() - Prepare common CT IOCB fields for SNS CT query.
56 * @ha: HA context
57 * @req_size: request size in bytes
58 * @rsp_size: response size in bytes
59 *
60 * Returns a pointer to the @ha's ms_iocb.
61 */
62void *
63qla24xx_prep_ms_iocb(scsi_qla_host_t *vha, uint32_t req_size, uint32_t rsp_size)
64{
65	struct qla_hw_data *ha = vha->hw;
66	struct ct_entry_24xx *ct_pkt;
67
68	ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
69	memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
70
71	ct_pkt->entry_type = CT_IOCB_TYPE;
72	ct_pkt->entry_count = 1;
73	ct_pkt->nport_handle = __constant_cpu_to_le16(NPH_SNS);
74	ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
75	ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
76	ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
77	ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
78	ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
79
80	ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
81	ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
82	ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
83
84	ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
85	ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
86	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
87	ct_pkt->vp_index = vha->vp_idx;
88
89	return (ct_pkt);
90}
91
92/**
93 * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
94 * @ct_req: CT request buffer
95 * @cmd: GS command
96 * @rsp_size: response size in bytes
97 *
98 * Returns a pointer to the intitialized @ct_req.
99 */
100static inline struct ct_sns_req *
101qla2x00_prep_ct_req(struct ct_sns_req *ct_req, uint16_t cmd, uint16_t rsp_size)
102{
103	memset(ct_req, 0, sizeof(struct ct_sns_pkt));
104
105	ct_req->header.revision = 0x01;
106	ct_req->header.gs_type = 0xFC;
107	ct_req->header.gs_subtype = 0x02;
108	ct_req->command = cpu_to_be16(cmd);
109	ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
110
111	return (ct_req);
112}
113
114static int
115qla2x00_chk_ms_status(scsi_qla_host_t *vha, ms_iocb_entry_t *ms_pkt,
116    struct ct_sns_rsp *ct_rsp, const char *routine)
117{
118	int rval;
119	uint16_t comp_status;
120	struct qla_hw_data *ha = vha->hw;
121
122	rval = QLA_FUNCTION_FAILED;
123	if (ms_pkt->entry_status != 0) {
124		ql_dbg(ql_dbg_disc, vha, 0x2031,
125		    "%s failed, error status (%x) on port_id: %02x%02x%02x.\n",
126		    routine, ms_pkt->entry_status, vha->d_id.b.domain,
127		    vha->d_id.b.area, vha->d_id.b.al_pa);
128	} else {
129		if (IS_FWI2_CAPABLE(ha))
130			comp_status = le16_to_cpu(
131			    ((struct ct_entry_24xx *)ms_pkt)->comp_status);
132		else
133			comp_status = le16_to_cpu(ms_pkt->status);
134		switch (comp_status) {
135		case CS_COMPLETE:
136		case CS_DATA_UNDERRUN:
137		case CS_DATA_OVERRUN:		/* Overrun? */
138			if (ct_rsp->header.response !=
139			    __constant_cpu_to_be16(CT_ACCEPT_RESPONSE)) {
140				ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2077,
141				    "%s failed rejected request on port_id: "
142				    "%02x%02x%02x.\n", routine,
143				    vha->d_id.b.domain, vha->d_id.b.area,
144				    vha->d_id.b.al_pa);
145				ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha,
146				    0x2078, (uint8_t *)&ct_rsp->header,
147				    sizeof(struct ct_rsp_hdr));
148				rval = QLA_INVALID_COMMAND;
149			} else
150				rval = QLA_SUCCESS;
151			break;
152		default:
153			ql_dbg(ql_dbg_disc, vha, 0x2033,
154			    "%s failed, completion status (%x) on port_id: "
155			    "%02x%02x%02x.\n", routine, comp_status,
156			    vha->d_id.b.domain, vha->d_id.b.area,
157			    vha->d_id.b.al_pa);
158			break;
159		}
160	}
161	return rval;
162}
163
164/**
165 * qla2x00_ga_nxt() - SNS scan for fabric devices via GA_NXT command.
166 * @ha: HA context
167 * @fcport: fcport entry to updated
168 *
169 * Returns 0 on success.
170 */
171int
172qla2x00_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
173{
174	int		rval;
175
176	ms_iocb_entry_t	*ms_pkt;
177	struct ct_sns_req	*ct_req;
178	struct ct_sns_rsp	*ct_rsp;
179	struct qla_hw_data *ha = vha->hw;
180
181	if (IS_QLA2100(ha) || IS_QLA2200(ha))
182		return qla2x00_sns_ga_nxt(vha, fcport);
183
184	/* Issue GA_NXT */
185	/* Prepare common MS IOCB */
186	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GA_NXT_REQ_SIZE,
187	    GA_NXT_RSP_SIZE);
188
189	/* Prepare CT request */
190	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GA_NXT_CMD,
191	    GA_NXT_RSP_SIZE);
192	ct_rsp = &ha->ct_sns->p.rsp;
193
194	/* Prepare CT arguments -- port_id */
195	ct_req->req.port_id.port_id[0] = fcport->d_id.b.domain;
196	ct_req->req.port_id.port_id[1] = fcport->d_id.b.area;
197	ct_req->req.port_id.port_id[2] = fcport->d_id.b.al_pa;
198
199	/* Execute MS IOCB */
200	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
201	    sizeof(ms_iocb_entry_t));
202	if (rval != QLA_SUCCESS) {
203		/*EMPTY*/
204		ql_dbg(ql_dbg_disc, vha, 0x2062,
205		    "GA_NXT issue IOCB failed (%d).\n", rval);
206	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GA_NXT") !=
207	    QLA_SUCCESS) {
208		rval = QLA_FUNCTION_FAILED;
209	} else {
210		/* Populate fc_port_t entry. */
211		fcport->d_id.b.domain = ct_rsp->rsp.ga_nxt.port_id[0];
212		fcport->d_id.b.area = ct_rsp->rsp.ga_nxt.port_id[1];
213		fcport->d_id.b.al_pa = ct_rsp->rsp.ga_nxt.port_id[2];
214
215		memcpy(fcport->node_name, ct_rsp->rsp.ga_nxt.node_name,
216		    WWN_SIZE);
217		memcpy(fcport->port_name, ct_rsp->rsp.ga_nxt.port_name,
218		    WWN_SIZE);
219
220		if (ct_rsp->rsp.ga_nxt.port_type != NS_N_PORT_TYPE &&
221		    ct_rsp->rsp.ga_nxt.port_type != NS_NL_PORT_TYPE)
222			fcport->d_id.b.domain = 0xf0;
223
224		ql_dbg(ql_dbg_disc, vha, 0x2063,
225		    "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
226		    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
227		    "port_id=%02x%02x%02x.\n",
228		    fcport->node_name[0], fcport->node_name[1],
229		    fcport->node_name[2], fcport->node_name[3],
230		    fcport->node_name[4], fcport->node_name[5],
231		    fcport->node_name[6], fcport->node_name[7],
232		    fcport->port_name[0], fcport->port_name[1],
233		    fcport->port_name[2], fcport->port_name[3],
234		    fcport->port_name[4], fcport->port_name[5],
235		    fcport->port_name[6], fcport->port_name[7],
236		    fcport->d_id.b.domain, fcport->d_id.b.area,
237		    fcport->d_id.b.al_pa);
238	}
239
240	return (rval);
241}
242
243/**
244 * qla2x00_gid_pt() - SNS scan for fabric devices via GID_PT command.
245 * @ha: HA context
246 * @list: switch info entries to populate
247 *
248 * NOTE: Non-Nx_Ports are not requested.
249 *
250 * Returns 0 on success.
251 */
252int
253qla2x00_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
254{
255	int		rval;
256	uint16_t	i;
257
258	ms_iocb_entry_t	*ms_pkt;
259	struct ct_sns_req	*ct_req;
260	struct ct_sns_rsp	*ct_rsp;
261
262	struct ct_sns_gid_pt_data *gid_data;
263	struct qla_hw_data *ha = vha->hw;
264
265	if (IS_QLA2100(ha) || IS_QLA2200(ha))
266		return qla2x00_sns_gid_pt(vha, list);
267
268	gid_data = NULL;
269
270	/* Issue GID_PT */
271	/* Prepare common MS IOCB */
272	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GID_PT_REQ_SIZE,
273	    GID_PT_RSP_SIZE);
274
275	/* Prepare CT request */
276	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GID_PT_CMD,
277	    GID_PT_RSP_SIZE);
278	ct_rsp = &ha->ct_sns->p.rsp;
279
280	/* Prepare CT arguments -- port_type */
281	ct_req->req.gid_pt.port_type = NS_NX_PORT_TYPE;
282
283	/* Execute MS IOCB */
284	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
285	    sizeof(ms_iocb_entry_t));
286	if (rval != QLA_SUCCESS) {
287		/*EMPTY*/
288		ql_dbg(ql_dbg_disc, vha, 0x2055,
289		    "GID_PT issue IOCB failed (%d).\n", rval);
290	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "GID_PT") !=
291	    QLA_SUCCESS) {
292		rval = QLA_FUNCTION_FAILED;
293	} else {
294		/* Set port IDs in switch info list. */
295		for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
296			gid_data = &ct_rsp->rsp.gid_pt.entries[i];
297			list[i].d_id.b.domain = gid_data->port_id[0];
298			list[i].d_id.b.area = gid_data->port_id[1];
299			list[i].d_id.b.al_pa = gid_data->port_id[2];
300			memset(list[i].fabric_port_name, 0, WWN_SIZE);
301			list[i].fp_speed = PORT_SPEED_UNKNOWN;
302
303			/* Last one exit. */
304			if (gid_data->control_byte & BIT_7) {
305				list[i].d_id.b.rsvd_1 = gid_data->control_byte;
306				break;
307			}
308		}
309
310		/*
311		 * If we've used all available slots, then the switch is
312		 * reporting back more devices than we can handle with this
313		 * single call.  Return a failed status, and let GA_NXT handle
314		 * the overload.
315		 */
316		if (i == MAX_FIBRE_DEVICES)
317			rval = QLA_FUNCTION_FAILED;
318	}
319
320	return (rval);
321}
322
323/**
324 * qla2x00_gpn_id() - SNS Get Port Name (GPN_ID) query.
325 * @ha: HA context
326 * @list: switch info entries to populate
327 *
328 * Returns 0 on success.
329 */
330int
331qla2x00_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
332{
333	int		rval;
334	uint16_t	i;
335
336	ms_iocb_entry_t	*ms_pkt;
337	struct ct_sns_req	*ct_req;
338	struct ct_sns_rsp	*ct_rsp;
339	struct qla_hw_data *ha = vha->hw;
340
341	if (IS_QLA2100(ha) || IS_QLA2200(ha))
342		return qla2x00_sns_gpn_id(vha, list);
343
344	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
345		/* Issue GPN_ID */
346		/* Prepare common MS IOCB */
347		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GPN_ID_REQ_SIZE,
348		    GPN_ID_RSP_SIZE);
349
350		/* Prepare CT request */
351		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GPN_ID_CMD,
352		    GPN_ID_RSP_SIZE);
353		ct_rsp = &ha->ct_sns->p.rsp;
354
355		/* Prepare CT arguments -- port_id */
356		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
357		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
358		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
359
360		/* Execute MS IOCB */
361		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
362		    sizeof(ms_iocb_entry_t));
363		if (rval != QLA_SUCCESS) {
364			/*EMPTY*/
365			ql_dbg(ql_dbg_disc, vha, 0x2056,
366			    "GPN_ID issue IOCB failed (%d).\n", rval);
367		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
368		    "GPN_ID") != QLA_SUCCESS) {
369			rval = QLA_FUNCTION_FAILED;
370		} else {
371			/* Save portname */
372			memcpy(list[i].port_name,
373			    ct_rsp->rsp.gpn_id.port_name, WWN_SIZE);
374		}
375
376		/* Last device exit. */
377		if (list[i].d_id.b.rsvd_1 != 0)
378			break;
379	}
380
381	return (rval);
382}
383
384/**
385 * qla2x00_gnn_id() - SNS Get Node Name (GNN_ID) query.
386 * @ha: HA context
387 * @list: switch info entries to populate
388 *
389 * Returns 0 on success.
390 */
391int
392qla2x00_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
393{
394	int		rval;
395	uint16_t	i;
396	struct qla_hw_data *ha = vha->hw;
397	ms_iocb_entry_t	*ms_pkt;
398	struct ct_sns_req	*ct_req;
399	struct ct_sns_rsp	*ct_rsp;
400
401	if (IS_QLA2100(ha) || IS_QLA2200(ha))
402		return qla2x00_sns_gnn_id(vha, list);
403
404	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
405		/* Issue GNN_ID */
406		/* Prepare common MS IOCB */
407		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GNN_ID_REQ_SIZE,
408		    GNN_ID_RSP_SIZE);
409
410		/* Prepare CT request */
411		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GNN_ID_CMD,
412		    GNN_ID_RSP_SIZE);
413		ct_rsp = &ha->ct_sns->p.rsp;
414
415		/* Prepare CT arguments -- port_id */
416		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
417		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
418		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
419
420		/* Execute MS IOCB */
421		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
422		    sizeof(ms_iocb_entry_t));
423		if (rval != QLA_SUCCESS) {
424			/*EMPTY*/
425			ql_dbg(ql_dbg_disc, vha, 0x2057,
426			    "GNN_ID issue IOCB failed (%d).\n", rval);
427		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
428		    "GNN_ID") != QLA_SUCCESS) {
429			rval = QLA_FUNCTION_FAILED;
430		} else {
431			/* Save nodename */
432			memcpy(list[i].node_name,
433			    ct_rsp->rsp.gnn_id.node_name, WWN_SIZE);
434
435			ql_dbg(ql_dbg_disc, vha, 0x2058,
436			    "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02X%02x "
437			    "pn %02x%02x%02x%02x%02x%02x%02X%02x "
438			    "portid=%02x%02x%02x.\n",
439			    list[i].node_name[0], list[i].node_name[1],
440			    list[i].node_name[2], list[i].node_name[3],
441			    list[i].node_name[4], list[i].node_name[5],
442			    list[i].node_name[6], list[i].node_name[7],
443			    list[i].port_name[0], list[i].port_name[1],
444			    list[i].port_name[2], list[i].port_name[3],
445			    list[i].port_name[4], list[i].port_name[5],
446			    list[i].port_name[6], list[i].port_name[7],
447			    list[i].d_id.b.domain, list[i].d_id.b.area,
448			    list[i].d_id.b.al_pa);
449		}
450
451		/* Last device exit. */
452		if (list[i].d_id.b.rsvd_1 != 0)
453			break;
454	}
455
456	return (rval);
457}
458
459/**
460 * qla2x00_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA.
461 * @ha: HA context
462 *
463 * Returns 0 on success.
464 */
465int
466qla2x00_rft_id(scsi_qla_host_t *vha)
467{
468	int		rval;
469	struct qla_hw_data *ha = vha->hw;
470	ms_iocb_entry_t	*ms_pkt;
471	struct ct_sns_req	*ct_req;
472	struct ct_sns_rsp	*ct_rsp;
473
474	if (IS_QLA2100(ha) || IS_QLA2200(ha))
475		return qla2x00_sns_rft_id(vha);
476
477	/* Issue RFT_ID */
478	/* Prepare common MS IOCB */
479	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, RFT_ID_REQ_SIZE,
480	    RFT_ID_RSP_SIZE);
481
482	/* Prepare CT request */
483	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFT_ID_CMD,
484	    RFT_ID_RSP_SIZE);
485	ct_rsp = &ha->ct_sns->p.rsp;
486
487	/* Prepare CT arguments -- port_id, FC-4 types */
488	ct_req->req.rft_id.port_id[0] = vha->d_id.b.domain;
489	ct_req->req.rft_id.port_id[1] = vha->d_id.b.area;
490	ct_req->req.rft_id.port_id[2] = vha->d_id.b.al_pa;
491
492	ct_req->req.rft_id.fc4_types[2] = 0x01;		/* FCP-3 */
493
494	/* Execute MS IOCB */
495	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
496	    sizeof(ms_iocb_entry_t));
497	if (rval != QLA_SUCCESS) {
498		/*EMPTY*/
499		ql_dbg(ql_dbg_disc, vha, 0x2043,
500		    "RFT_ID issue IOCB failed (%d).\n", rval);
501	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFT_ID") !=
502	    QLA_SUCCESS) {
503		rval = QLA_FUNCTION_FAILED;
504	} else {
505		ql_dbg(ql_dbg_disc, vha, 0x2044,
506		    "RFT_ID exiting normally.\n");
507	}
508
509	return (rval);
510}
511
512/**
513 * qla2x00_rff_id() - SNS Register FC-4 Features (RFF_ID) supported by the HBA.
514 * @ha: HA context
515 *
516 * Returns 0 on success.
517 */
518int
519qla2x00_rff_id(scsi_qla_host_t *vha)
520{
521	int		rval;
522	struct qla_hw_data *ha = vha->hw;
523	ms_iocb_entry_t	*ms_pkt;
524	struct ct_sns_req	*ct_req;
525	struct ct_sns_rsp	*ct_rsp;
526
527	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
528		ql_dbg(ql_dbg_disc, vha, 0x2046,
529		    "RFF_ID call not supported on ISP2100/ISP2200.\n");
530		return (QLA_SUCCESS);
531	}
532
533	/* Issue RFF_ID */
534	/* Prepare common MS IOCB */
535	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, RFF_ID_REQ_SIZE,
536	    RFF_ID_RSP_SIZE);
537
538	/* Prepare CT request */
539	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RFF_ID_CMD,
540	    RFF_ID_RSP_SIZE);
541	ct_rsp = &ha->ct_sns->p.rsp;
542
543	/* Prepare CT arguments -- port_id, FC-4 feature, FC-4 type */
544	ct_req->req.rff_id.port_id[0] = vha->d_id.b.domain;
545	ct_req->req.rff_id.port_id[1] = vha->d_id.b.area;
546	ct_req->req.rff_id.port_id[2] = vha->d_id.b.al_pa;
547
548	ct_req->req.rff_id.fc4_feature = BIT_1;
549	ct_req->req.rff_id.fc4_type = 0x08;		/* SCSI - FCP */
550
551	/* Execute MS IOCB */
552	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
553	    sizeof(ms_iocb_entry_t));
554	if (rval != QLA_SUCCESS) {
555		/*EMPTY*/
556		ql_dbg(ql_dbg_disc, vha, 0x2047,
557		    "RFF_ID issue IOCB failed (%d).\n", rval);
558	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RFF_ID") !=
559	    QLA_SUCCESS) {
560		rval = QLA_FUNCTION_FAILED;
561	} else {
562		ql_dbg(ql_dbg_disc, vha, 0x2048,
563		    "RFF_ID exiting normally.\n");
564	}
565
566	return (rval);
567}
568
569/**
570 * qla2x00_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA.
571 * @ha: HA context
572 *
573 * Returns 0 on success.
574 */
575int
576qla2x00_rnn_id(scsi_qla_host_t *vha)
577{
578	int		rval;
579	struct qla_hw_data *ha = vha->hw;
580	ms_iocb_entry_t	*ms_pkt;
581	struct ct_sns_req	*ct_req;
582	struct ct_sns_rsp	*ct_rsp;
583
584	if (IS_QLA2100(ha) || IS_QLA2200(ha))
585		return qla2x00_sns_rnn_id(vha);
586
587	/* Issue RNN_ID */
588	/* Prepare common MS IOCB */
589	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, RNN_ID_REQ_SIZE,
590	    RNN_ID_RSP_SIZE);
591
592	/* Prepare CT request */
593	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RNN_ID_CMD,
594	    RNN_ID_RSP_SIZE);
595	ct_rsp = &ha->ct_sns->p.rsp;
596
597	/* Prepare CT arguments -- port_id, node_name */
598	ct_req->req.rnn_id.port_id[0] = vha->d_id.b.domain;
599	ct_req->req.rnn_id.port_id[1] = vha->d_id.b.area;
600	ct_req->req.rnn_id.port_id[2] = vha->d_id.b.al_pa;
601
602	memcpy(ct_req->req.rnn_id.node_name, vha->node_name, WWN_SIZE);
603
604	/* Execute MS IOCB */
605	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
606	    sizeof(ms_iocb_entry_t));
607	if (rval != QLA_SUCCESS) {
608		/*EMPTY*/
609		ql_dbg(ql_dbg_disc, vha, 0x204d,
610		    "RNN_ID issue IOCB failed (%d).\n", rval);
611	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RNN_ID") !=
612	    QLA_SUCCESS) {
613		rval = QLA_FUNCTION_FAILED;
614	} else {
615		ql_dbg(ql_dbg_disc, vha, 0x204e,
616		    "RNN_ID exiting normally.\n");
617	}
618
619	return (rval);
620}
621
622void
623qla2x00_get_sym_node_name(scsi_qla_host_t *vha, uint8_t *snn)
624{
625	struct qla_hw_data *ha = vha->hw;
626	sprintf(snn, "%s FW:v%d.%02d.%02d DVR:v%s",ha->model_number,
627	    ha->fw_major_version, ha->fw_minor_version,
628	    ha->fw_subminor_version, qla2x00_version_str);
629}
630
631/**
632 * qla2x00_rsnn_nn() - SNS Register Symbolic Node Name (RSNN_NN) of the HBA.
633 * @ha: HA context
634 *
635 * Returns 0 on success.
636 */
637int
638qla2x00_rsnn_nn(scsi_qla_host_t *vha)
639{
640	int		rval;
641	struct qla_hw_data *ha = vha->hw;
642	ms_iocb_entry_t	*ms_pkt;
643	struct ct_sns_req	*ct_req;
644	struct ct_sns_rsp	*ct_rsp;
645
646	if (IS_QLA2100(ha) || IS_QLA2200(ha)) {
647		ql_dbg(ql_dbg_disc, vha, 0x2050,
648		    "RSNN_ID call unsupported on ISP2100/ISP2200.\n");
649		return (QLA_SUCCESS);
650	}
651
652	/* Issue RSNN_NN */
653	/* Prepare common MS IOCB */
654	/*   Request size adjusted after CT preparation */
655	ms_pkt = ha->isp_ops->prep_ms_iocb(vha, 0, RSNN_NN_RSP_SIZE);
656
657	/* Prepare CT request */
658	ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, RSNN_NN_CMD,
659	    RSNN_NN_RSP_SIZE);
660	ct_rsp = &ha->ct_sns->p.rsp;
661
662	/* Prepare CT arguments -- node_name, symbolic node_name, size */
663	memcpy(ct_req->req.rsnn_nn.node_name, vha->node_name, WWN_SIZE);
664
665	/* Prepare the Symbolic Node Name */
666	qla2x00_get_sym_node_name(vha, ct_req->req.rsnn_nn.sym_node_name);
667
668	/* Calculate SNN length */
669	ct_req->req.rsnn_nn.name_len =
670	    (uint8_t)strlen(ct_req->req.rsnn_nn.sym_node_name);
671
672	/* Update MS IOCB request */
673	ms_pkt->req_bytecount =
674	    cpu_to_le32(24 + 1 + ct_req->req.rsnn_nn.name_len);
675	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
676
677	/* Execute MS IOCB */
678	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
679	    sizeof(ms_iocb_entry_t));
680	if (rval != QLA_SUCCESS) {
681		/*EMPTY*/
682		ql_dbg(ql_dbg_disc, vha, 0x2051,
683		    "RSNN_NN issue IOCB failed (%d).\n", rval);
684	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RSNN_NN") !=
685	    QLA_SUCCESS) {
686		rval = QLA_FUNCTION_FAILED;
687	} else {
688		ql_dbg(ql_dbg_disc, vha, 0x2052,
689		    "RSNN_NN exiting normally.\n");
690	}
691
692	return (rval);
693}
694
695/**
696 * qla2x00_prep_sns_cmd() - Prepare common SNS command request fields for query.
697 * @ha: HA context
698 * @cmd: GS command
699 * @scmd_len: Subcommand length
700 * @data_size: response size in bytes
701 *
702 * Returns a pointer to the @ha's sns_cmd.
703 */
704static inline struct sns_cmd_pkt *
705qla2x00_prep_sns_cmd(scsi_qla_host_t *vha, uint16_t cmd, uint16_t scmd_len,
706    uint16_t data_size)
707{
708	uint16_t		wc;
709	struct sns_cmd_pkt	*sns_cmd;
710	struct qla_hw_data *ha = vha->hw;
711
712	sns_cmd = ha->sns_cmd;
713	memset(sns_cmd, 0, sizeof(struct sns_cmd_pkt));
714	wc = data_size / 2;			/* Size in 16bit words. */
715	sns_cmd->p.cmd.buffer_length = cpu_to_le16(wc);
716	sns_cmd->p.cmd.buffer_address[0] = cpu_to_le32(LSD(ha->sns_cmd_dma));
717	sns_cmd->p.cmd.buffer_address[1] = cpu_to_le32(MSD(ha->sns_cmd_dma));
718	sns_cmd->p.cmd.subcommand_length = cpu_to_le16(scmd_len);
719	sns_cmd->p.cmd.subcommand = cpu_to_le16(cmd);
720	wc = (data_size - 16) / 4;		/* Size in 32bit words. */
721	sns_cmd->p.cmd.size = cpu_to_le16(wc);
722
723	return (sns_cmd);
724}
725
726/**
727 * qla2x00_sns_ga_nxt() - SNS scan for fabric devices via GA_NXT command.
728 * @ha: HA context
729 * @fcport: fcport entry to updated
730 *
731 * This command uses the old Exectute SNS Command mailbox routine.
732 *
733 * Returns 0 on success.
734 */
735static int
736qla2x00_sns_ga_nxt(scsi_qla_host_t *vha, fc_port_t *fcport)
737{
738	int		rval;
739	struct qla_hw_data *ha = vha->hw;
740	struct sns_cmd_pkt	*sns_cmd;
741
742	/* Issue GA_NXT. */
743	/* Prepare SNS command request. */
744	sns_cmd = qla2x00_prep_sns_cmd(vha, GA_NXT_CMD, GA_NXT_SNS_SCMD_LEN,
745	    GA_NXT_SNS_DATA_SIZE);
746
747	/* Prepare SNS command arguments -- port_id. */
748	sns_cmd->p.cmd.param[0] = fcport->d_id.b.al_pa;
749	sns_cmd->p.cmd.param[1] = fcport->d_id.b.area;
750	sns_cmd->p.cmd.param[2] = fcport->d_id.b.domain;
751
752	/* Execute SNS command. */
753	rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, GA_NXT_SNS_CMD_SIZE / 2,
754	    sizeof(struct sns_cmd_pkt));
755	if (rval != QLA_SUCCESS) {
756		/*EMPTY*/
757		ql_dbg(ql_dbg_disc, vha, 0x205f,
758		    "GA_NXT Send SNS failed (%d).\n", rval);
759	} else if (sns_cmd->p.gan_data[8] != 0x80 ||
760	    sns_cmd->p.gan_data[9] != 0x02) {
761		ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2084,
762		    "GA_NXT failed, rejected request ga_nxt_rsp:\n");
763		ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2074,
764		    sns_cmd->p.gan_data, 16);
765		rval = QLA_FUNCTION_FAILED;
766	} else {
767		/* Populate fc_port_t entry. */
768		fcport->d_id.b.domain = sns_cmd->p.gan_data[17];
769		fcport->d_id.b.area = sns_cmd->p.gan_data[18];
770		fcport->d_id.b.al_pa = sns_cmd->p.gan_data[19];
771
772		memcpy(fcport->node_name, &sns_cmd->p.gan_data[284], WWN_SIZE);
773		memcpy(fcport->port_name, &sns_cmd->p.gan_data[20], WWN_SIZE);
774
775		if (sns_cmd->p.gan_data[16] != NS_N_PORT_TYPE &&
776		    sns_cmd->p.gan_data[16] != NS_NL_PORT_TYPE)
777			fcport->d_id.b.domain = 0xf0;
778
779		ql_dbg(ql_dbg_disc, vha, 0x2061,
780		    "GA_NXT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
781		    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
782		    "port_id=%02x%02x%02x.\n",
783		    fcport->node_name[0], fcport->node_name[1],
784		    fcport->node_name[2], fcport->node_name[3],
785		    fcport->node_name[4], fcport->node_name[5],
786		    fcport->node_name[6], fcport->node_name[7],
787		    fcport->port_name[0], fcport->port_name[1],
788		    fcport->port_name[2], fcport->port_name[3],
789		    fcport->port_name[4], fcport->port_name[5],
790		    fcport->port_name[6], fcport->port_name[7],
791		    fcport->d_id.b.domain, fcport->d_id.b.area,
792		    fcport->d_id.b.al_pa);
793	}
794
795	return (rval);
796}
797
798/**
799 * qla2x00_sns_gid_pt() - SNS scan for fabric devices via GID_PT command.
800 * @ha: HA context
801 * @list: switch info entries to populate
802 *
803 * This command uses the old Exectute SNS Command mailbox routine.
804 *
805 * NOTE: Non-Nx_Ports are not requested.
806 *
807 * Returns 0 on success.
808 */
809static int
810qla2x00_sns_gid_pt(scsi_qla_host_t *vha, sw_info_t *list)
811{
812	int		rval;
813	struct qla_hw_data *ha = vha->hw;
814	uint16_t	i;
815	uint8_t		*entry;
816	struct sns_cmd_pkt	*sns_cmd;
817
818	/* Issue GID_PT. */
819	/* Prepare SNS command request. */
820	sns_cmd = qla2x00_prep_sns_cmd(vha, GID_PT_CMD, GID_PT_SNS_SCMD_LEN,
821	    GID_PT_SNS_DATA_SIZE);
822
823	/* Prepare SNS command arguments -- port_type. */
824	sns_cmd->p.cmd.param[0] = NS_NX_PORT_TYPE;
825
826	/* Execute SNS command. */
827	rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, GID_PT_SNS_CMD_SIZE / 2,
828	    sizeof(struct sns_cmd_pkt));
829	if (rval != QLA_SUCCESS) {
830		/*EMPTY*/
831		ql_dbg(ql_dbg_disc, vha, 0x206d,
832		    "GID_PT Send SNS failed (%d).\n", rval);
833	} else if (sns_cmd->p.gid_data[8] != 0x80 ||
834	    sns_cmd->p.gid_data[9] != 0x02) {
835		ql_dbg(ql_dbg_disc, vha, 0x202f,
836		    "GID_PT failed, rejected request, gid_rsp:\n");
837		ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2081,
838		    sns_cmd->p.gid_data, 16);
839		rval = QLA_FUNCTION_FAILED;
840	} else {
841		/* Set port IDs in switch info list. */
842		for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
843			entry = &sns_cmd->p.gid_data[(i * 4) + 16];
844			list[i].d_id.b.domain = entry[1];
845			list[i].d_id.b.area = entry[2];
846			list[i].d_id.b.al_pa = entry[3];
847
848			/* Last one exit. */
849			if (entry[0] & BIT_7) {
850				list[i].d_id.b.rsvd_1 = entry[0];
851				break;
852			}
853		}
854
855		/*
856		 * If we've used all available slots, then the switch is
857		 * reporting back more devices that we can handle with this
858		 * single call.  Return a failed status, and let GA_NXT handle
859		 * the overload.
860		 */
861		if (i == MAX_FIBRE_DEVICES)
862			rval = QLA_FUNCTION_FAILED;
863	}
864
865	return (rval);
866}
867
868/**
869 * qla2x00_sns_gpn_id() - SNS Get Port Name (GPN_ID) query.
870 * @ha: HA context
871 * @list: switch info entries to populate
872 *
873 * This command uses the old Exectute SNS Command mailbox routine.
874 *
875 * Returns 0 on success.
876 */
877static int
878qla2x00_sns_gpn_id(scsi_qla_host_t *vha, sw_info_t *list)
879{
880	int		rval;
881	struct qla_hw_data *ha = vha->hw;
882	uint16_t	i;
883	struct sns_cmd_pkt	*sns_cmd;
884
885	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
886		/* Issue GPN_ID */
887		/* Prepare SNS command request. */
888		sns_cmd = qla2x00_prep_sns_cmd(vha, GPN_ID_CMD,
889		    GPN_ID_SNS_SCMD_LEN, GPN_ID_SNS_DATA_SIZE);
890
891		/* Prepare SNS command arguments -- port_id. */
892		sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa;
893		sns_cmd->p.cmd.param[1] = list[i].d_id.b.area;
894		sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain;
895
896		/* Execute SNS command. */
897		rval = qla2x00_send_sns(vha, ha->sns_cmd_dma,
898		    GPN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
899		if (rval != QLA_SUCCESS) {
900			/*EMPTY*/
901			ql_dbg(ql_dbg_disc, vha, 0x2032,
902			    "GPN_ID Send SNS failed (%d).\n", rval);
903		} else if (sns_cmd->p.gpn_data[8] != 0x80 ||
904		    sns_cmd->p.gpn_data[9] != 0x02) {
905			ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207e,
906			    "GPN_ID failed, rejected request, gpn_rsp:\n");
907			ql_dump_buffer(ql_dbg_disc, vha, 0x207f,
908			    sns_cmd->p.gpn_data, 16);
909			rval = QLA_FUNCTION_FAILED;
910		} else {
911			/* Save portname */
912			memcpy(list[i].port_name, &sns_cmd->p.gpn_data[16],
913			    WWN_SIZE);
914		}
915
916		/* Last device exit. */
917		if (list[i].d_id.b.rsvd_1 != 0)
918			break;
919	}
920
921	return (rval);
922}
923
924/**
925 * qla2x00_sns_gnn_id() - SNS Get Node Name (GNN_ID) query.
926 * @ha: HA context
927 * @list: switch info entries to populate
928 *
929 * This command uses the old Exectute SNS Command mailbox routine.
930 *
931 * Returns 0 on success.
932 */
933static int
934qla2x00_sns_gnn_id(scsi_qla_host_t *vha, sw_info_t *list)
935{
936	int		rval;
937	struct qla_hw_data *ha = vha->hw;
938	uint16_t	i;
939	struct sns_cmd_pkt	*sns_cmd;
940
941	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
942		/* Issue GNN_ID */
943		/* Prepare SNS command request. */
944		sns_cmd = qla2x00_prep_sns_cmd(vha, GNN_ID_CMD,
945		    GNN_ID_SNS_SCMD_LEN, GNN_ID_SNS_DATA_SIZE);
946
947		/* Prepare SNS command arguments -- port_id. */
948		sns_cmd->p.cmd.param[0] = list[i].d_id.b.al_pa;
949		sns_cmd->p.cmd.param[1] = list[i].d_id.b.area;
950		sns_cmd->p.cmd.param[2] = list[i].d_id.b.domain;
951
952		/* Execute SNS command. */
953		rval = qla2x00_send_sns(vha, ha->sns_cmd_dma,
954		    GNN_ID_SNS_CMD_SIZE / 2, sizeof(struct sns_cmd_pkt));
955		if (rval != QLA_SUCCESS) {
956			/*EMPTY*/
957			ql_dbg(ql_dbg_disc, vha, 0x203f,
958			    "GNN_ID Send SNS failed (%d).\n", rval);
959		} else if (sns_cmd->p.gnn_data[8] != 0x80 ||
960		    sns_cmd->p.gnn_data[9] != 0x02) {
961			ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2082,
962			    "GNN_ID failed, rejected request, gnn_rsp:\n");
963			ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207a,
964			    sns_cmd->p.gnn_data, 16);
965			rval = QLA_FUNCTION_FAILED;
966		} else {
967			/* Save nodename */
968			memcpy(list[i].node_name, &sns_cmd->p.gnn_data[16],
969			    WWN_SIZE);
970
971			ql_dbg(ql_dbg_disc, vha, 0x206e,
972			    "GID_PT entry - nn %02x%02x%02x%02x%02x%02x%02x%02x "
973			    "pn %02x%02x%02x%02x%02x%02x%02x%02x "
974			    "port_id=%02x%02x%02x.\n",
975			    list[i].node_name[0], list[i].node_name[1],
976			    list[i].node_name[2], list[i].node_name[3],
977			    list[i].node_name[4], list[i].node_name[5],
978			    list[i].node_name[6], list[i].node_name[7],
979			    list[i].port_name[0], list[i].port_name[1],
980			    list[i].port_name[2], list[i].port_name[3],
981			    list[i].port_name[4], list[i].port_name[5],
982			    list[i].port_name[6], list[i].port_name[7],
983			    list[i].d_id.b.domain, list[i].d_id.b.area,
984			    list[i].d_id.b.al_pa);
985		}
986
987		/* Last device exit. */
988		if (list[i].d_id.b.rsvd_1 != 0)
989			break;
990	}
991
992	return (rval);
993}
994
995/**
996 * qla2x00_snd_rft_id() - SNS Register FC-4 TYPEs (RFT_ID) supported by the HBA.
997 * @ha: HA context
998 *
999 * This command uses the old Exectute SNS Command mailbox routine.
1000 *
1001 * Returns 0 on success.
1002 */
1003static int
1004qla2x00_sns_rft_id(scsi_qla_host_t *vha)
1005{
1006	int		rval;
1007	struct qla_hw_data *ha = vha->hw;
1008	struct sns_cmd_pkt	*sns_cmd;
1009
1010	/* Issue RFT_ID. */
1011	/* Prepare SNS command request. */
1012	sns_cmd = qla2x00_prep_sns_cmd(vha, RFT_ID_CMD, RFT_ID_SNS_SCMD_LEN,
1013	    RFT_ID_SNS_DATA_SIZE);
1014
1015	/* Prepare SNS command arguments -- port_id, FC-4 types */
1016	sns_cmd->p.cmd.param[0] = vha->d_id.b.al_pa;
1017	sns_cmd->p.cmd.param[1] = vha->d_id.b.area;
1018	sns_cmd->p.cmd.param[2] = vha->d_id.b.domain;
1019
1020	sns_cmd->p.cmd.param[5] = 0x01;			/* FCP-3 */
1021
1022	/* Execute SNS command. */
1023	rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, RFT_ID_SNS_CMD_SIZE / 2,
1024	    sizeof(struct sns_cmd_pkt));
1025	if (rval != QLA_SUCCESS) {
1026		/*EMPTY*/
1027		ql_dbg(ql_dbg_disc, vha, 0x2060,
1028		    "RFT_ID Send SNS failed (%d).\n", rval);
1029	} else if (sns_cmd->p.rft_data[8] != 0x80 ||
1030	    sns_cmd->p.rft_data[9] != 0x02) {
1031		ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x2083,
1032		    "RFT_ID failed, rejected request rft_rsp:\n");
1033		ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2080,
1034		    sns_cmd->p.rft_data, 16);
1035		rval = QLA_FUNCTION_FAILED;
1036	} else {
1037		ql_dbg(ql_dbg_disc, vha, 0x2073,
1038		    "RFT_ID exiting normally.\n");
1039	}
1040
1041	return (rval);
1042}
1043
1044/**
1045 * qla2x00_sns_rnn_id() - SNS Register Node Name (RNN_ID) of the HBA.
1046 * HBA.
1047 * @ha: HA context
1048 *
1049 * This command uses the old Exectute SNS Command mailbox routine.
1050 *
1051 * Returns 0 on success.
1052 */
1053static int
1054qla2x00_sns_rnn_id(scsi_qla_host_t *vha)
1055{
1056	int		rval;
1057	struct qla_hw_data *ha = vha->hw;
1058	struct sns_cmd_pkt	*sns_cmd;
1059
1060	/* Issue RNN_ID. */
1061	/* Prepare SNS command request. */
1062	sns_cmd = qla2x00_prep_sns_cmd(vha, RNN_ID_CMD, RNN_ID_SNS_SCMD_LEN,
1063	    RNN_ID_SNS_DATA_SIZE);
1064
1065	/* Prepare SNS command arguments -- port_id, nodename. */
1066	sns_cmd->p.cmd.param[0] = vha->d_id.b.al_pa;
1067	sns_cmd->p.cmd.param[1] = vha->d_id.b.area;
1068	sns_cmd->p.cmd.param[2] = vha->d_id.b.domain;
1069
1070	sns_cmd->p.cmd.param[4] = vha->node_name[7];
1071	sns_cmd->p.cmd.param[5] = vha->node_name[6];
1072	sns_cmd->p.cmd.param[6] = vha->node_name[5];
1073	sns_cmd->p.cmd.param[7] = vha->node_name[4];
1074	sns_cmd->p.cmd.param[8] = vha->node_name[3];
1075	sns_cmd->p.cmd.param[9] = vha->node_name[2];
1076	sns_cmd->p.cmd.param[10] = vha->node_name[1];
1077	sns_cmd->p.cmd.param[11] = vha->node_name[0];
1078
1079	/* Execute SNS command. */
1080	rval = qla2x00_send_sns(vha, ha->sns_cmd_dma, RNN_ID_SNS_CMD_SIZE / 2,
1081	    sizeof(struct sns_cmd_pkt));
1082	if (rval != QLA_SUCCESS) {
1083		/*EMPTY*/
1084		ql_dbg(ql_dbg_disc, vha, 0x204a,
1085		    "RNN_ID Send SNS failed (%d).\n", rval);
1086	} else if (sns_cmd->p.rnn_data[8] != 0x80 ||
1087	    sns_cmd->p.rnn_data[9] != 0x02) {
1088		ql_dbg(ql_dbg_disc + ql_dbg_buffer, vha, 0x207b,
1089		    "RNN_ID failed, rejected request, rnn_rsp:\n");
1090		ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x207c,
1091		    sns_cmd->p.rnn_data, 16);
1092		rval = QLA_FUNCTION_FAILED;
1093	} else {
1094		ql_dbg(ql_dbg_disc, vha, 0x204c,
1095		    "RNN_ID exiting normally.\n");
1096	}
1097
1098	return (rval);
1099}
1100
1101/**
1102 * qla2x00_mgmt_svr_login() - Login to fabric Management Service.
1103 * @ha: HA context
1104 *
1105 * Returns 0 on success.
1106 */
1107static int
1108qla2x00_mgmt_svr_login(scsi_qla_host_t *vha)
1109{
1110	int ret;
1111	uint16_t mb[MAILBOX_REGISTER_COUNT];
1112	struct qla_hw_data *ha = vha->hw;
1113	ret = QLA_SUCCESS;
1114	if (vha->flags.management_server_logged_in)
1115		return ret;
1116
1117	ha->isp_ops->fabric_login(vha, vha->mgmt_svr_loop_id, 0xff, 0xff, 0xfa,
1118	    mb, BIT_1|BIT_0);
1119	if (mb[0] != MBS_COMMAND_COMPLETE) {
1120		ql_dbg(ql_dbg_disc, vha, 0x2024,
1121		    "Failed management_server login: loopid=%x mb[0]=%x "
1122		    "mb[1]=%x mb[2]=%x mb[6]=%x mb[7]=%x.\n",
1123		    vha->mgmt_svr_loop_id, mb[0], mb[1], mb[2], mb[6], mb[7]);
1124		ret = QLA_FUNCTION_FAILED;
1125	} else
1126		vha->flags.management_server_logged_in = 1;
1127
1128	return ret;
1129}
1130
1131/**
1132 * qla2x00_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
1133 * @ha: HA context
1134 * @req_size: request size in bytes
1135 * @rsp_size: response size in bytes
1136 *
1137 * Returns a pointer to the @ha's ms_iocb.
1138 */
1139void *
1140qla2x00_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
1141    uint32_t rsp_size)
1142{
1143	ms_iocb_entry_t *ms_pkt;
1144	struct qla_hw_data *ha = vha->hw;
1145	ms_pkt = ha->ms_iocb;
1146	memset(ms_pkt, 0, sizeof(ms_iocb_entry_t));
1147
1148	ms_pkt->entry_type = MS_IOCB_TYPE;
1149	ms_pkt->entry_count = 1;
1150	SET_TARGET_ID(ha, ms_pkt->loop_id, vha->mgmt_svr_loop_id);
1151	ms_pkt->control_flags = __constant_cpu_to_le16(CF_READ | CF_HEAD_TAG);
1152	ms_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
1153	ms_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
1154	ms_pkt->total_dsd_count = __constant_cpu_to_le16(2);
1155	ms_pkt->rsp_bytecount = cpu_to_le32(rsp_size);
1156	ms_pkt->req_bytecount = cpu_to_le32(req_size);
1157
1158	ms_pkt->dseg_req_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
1159	ms_pkt->dseg_req_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
1160	ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
1161
1162	ms_pkt->dseg_rsp_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
1163	ms_pkt->dseg_rsp_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
1164	ms_pkt->dseg_rsp_length = ms_pkt->rsp_bytecount;
1165
1166	return ms_pkt;
1167}
1168
1169/**
1170 * qla24xx_prep_ms_fdmi_iocb() - Prepare common MS IOCB fields for FDMI query.
1171 * @ha: HA context
1172 * @req_size: request size in bytes
1173 * @rsp_size: response size in bytes
1174 *
1175 * Returns a pointer to the @ha's ms_iocb.
1176 */
1177void *
1178qla24xx_prep_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size,
1179    uint32_t rsp_size)
1180{
1181	struct ct_entry_24xx *ct_pkt;
1182	struct qla_hw_data *ha = vha->hw;
1183
1184	ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
1185	memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
1186
1187	ct_pkt->entry_type = CT_IOCB_TYPE;
1188	ct_pkt->entry_count = 1;
1189	ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id);
1190	ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
1191	ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
1192	ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
1193	ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
1194	ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
1195
1196	ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
1197	ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
1198	ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
1199
1200	ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
1201	ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
1202	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
1203	ct_pkt->vp_index = vha->vp_idx;
1204
1205	return ct_pkt;
1206}
1207
1208static inline ms_iocb_entry_t *
1209qla2x00_update_ms_fdmi_iocb(scsi_qla_host_t *vha, uint32_t req_size)
1210{
1211	struct qla_hw_data *ha = vha->hw;
1212	ms_iocb_entry_t *ms_pkt = ha->ms_iocb;
1213	struct ct_entry_24xx *ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
1214
1215	if (IS_FWI2_CAPABLE(ha)) {
1216		ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
1217		ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
1218	} else {
1219		ms_pkt->req_bytecount = cpu_to_le32(req_size);
1220		ms_pkt->dseg_req_length = ms_pkt->req_bytecount;
1221	}
1222
1223	return ms_pkt;
1224}
1225
1226/**
1227 * qla2x00_prep_ct_req() - Prepare common CT request fields for SNS query.
1228 * @ct_req: CT request buffer
1229 * @cmd: GS command
1230 * @rsp_size: response size in bytes
1231 *
1232 * Returns a pointer to the intitialized @ct_req.
1233 */
1234static inline struct ct_sns_req *
1235qla2x00_prep_ct_fdmi_req(struct ct_sns_req *ct_req, uint16_t cmd,
1236    uint16_t rsp_size)
1237{
1238	memset(ct_req, 0, sizeof(struct ct_sns_pkt));
1239
1240	ct_req->header.revision = 0x01;
1241	ct_req->header.gs_type = 0xFA;
1242	ct_req->header.gs_subtype = 0x10;
1243	ct_req->command = cpu_to_be16(cmd);
1244	ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
1245
1246	return ct_req;
1247}
1248
1249/**
1250 * qla2x00_fdmi_rhba() -
1251 * @ha: HA context
1252 *
1253 * Returns 0 on success.
1254 */
1255static int
1256qla2x00_fdmi_rhba(scsi_qla_host_t *vha)
1257{
1258	int rval, alen;
1259	uint32_t size, sn;
1260
1261	ms_iocb_entry_t *ms_pkt;
1262	struct ct_sns_req *ct_req;
1263	struct ct_sns_rsp *ct_rsp;
1264	uint8_t *entries;
1265	struct ct_fdmi_hba_attr *eiter;
1266	struct qla_hw_data *ha = vha->hw;
1267
1268	/* Issue RHBA */
1269	/* Prepare common MS IOCB */
1270	/*   Request size adjusted after CT preparation */
1271	ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RHBA_RSP_SIZE);
1272
1273	/* Prepare CT request */
1274	ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RHBA_CMD,
1275	    RHBA_RSP_SIZE);
1276	ct_rsp = &ha->ct_sns->p.rsp;
1277
1278	/* Prepare FDMI command arguments -- attribute block, attributes. */
1279	memcpy(ct_req->req.rhba.hba_identifier, vha->port_name, WWN_SIZE);
1280	ct_req->req.rhba.entry_count = __constant_cpu_to_be32(1);
1281	memcpy(ct_req->req.rhba.port_name, vha->port_name, WWN_SIZE);
1282	size = 2 * WWN_SIZE + 4 + 4;
1283
1284	/* Attributes */
1285	ct_req->req.rhba.attrs.count =
1286	    __constant_cpu_to_be32(FDMI_HBA_ATTR_COUNT);
1287	entries = ct_req->req.rhba.hba_identifier;
1288
1289	/* Nodename. */
1290	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1291	eiter->type = __constant_cpu_to_be16(FDMI_HBA_NODE_NAME);
1292	eiter->len = __constant_cpu_to_be16(4 + WWN_SIZE);
1293	memcpy(eiter->a.node_name, vha->node_name, WWN_SIZE);
1294	size += 4 + WWN_SIZE;
1295
1296	ql_dbg(ql_dbg_disc, vha, 0x2025,
1297	    "NodeName = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
1298	    eiter->a.node_name[0], eiter->a.node_name[1],
1299	    eiter->a.node_name[2], eiter->a.node_name[3],
1300	    eiter->a.node_name[4], eiter->a.node_name[5],
1301	    eiter->a.node_name[6], eiter->a.node_name[7]);
1302
1303	/* Manufacturer. */
1304	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1305	eiter->type = __constant_cpu_to_be16(FDMI_HBA_MANUFACTURER);
1306	strcpy(eiter->a.manufacturer, "QLogic Corporation");
1307	alen = strlen(eiter->a.manufacturer);
1308	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1309	eiter->len = cpu_to_be16(4 + alen);
1310	size += 4 + alen;
1311
1312	ql_dbg(ql_dbg_disc, vha, 0x2026,
1313	    "Manufacturer = %s.\n", eiter->a.manufacturer);
1314
1315	/* Serial number. */
1316	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1317	eiter->type = __constant_cpu_to_be16(FDMI_HBA_SERIAL_NUMBER);
1318	sn = ((ha->serial0 & 0x1f) << 16) | (ha->serial2 << 8) | ha->serial1;
1319	sprintf(eiter->a.serial_num, "%c%05d", 'A' + sn / 100000, sn % 100000);
1320	alen = strlen(eiter->a.serial_num);
1321	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1322	eiter->len = cpu_to_be16(4 + alen);
1323	size += 4 + alen;
1324
1325	ql_dbg(ql_dbg_disc, vha, 0x2027,
1326	    "Serial no. = %s.\n", eiter->a.serial_num);
1327
1328	/* Model name. */
1329	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1330	eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL);
1331	strcpy(eiter->a.model, ha->model_number);
1332	alen = strlen(eiter->a.model);
1333	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1334	eiter->len = cpu_to_be16(4 + alen);
1335	size += 4 + alen;
1336
1337	ql_dbg(ql_dbg_disc, vha, 0x2028,
1338	    "Model Name = %s.\n", eiter->a.model);
1339
1340	/* Model description. */
1341	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1342	eiter->type = __constant_cpu_to_be16(FDMI_HBA_MODEL_DESCRIPTION);
1343	if (ha->model_desc)
1344		strncpy(eiter->a.model_desc, ha->model_desc, 80);
1345	alen = strlen(eiter->a.model_desc);
1346	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1347	eiter->len = cpu_to_be16(4 + alen);
1348	size += 4 + alen;
1349
1350	ql_dbg(ql_dbg_disc, vha, 0x2029,
1351	    "Model Desc = %s.\n", eiter->a.model_desc);
1352
1353	/* Hardware version. */
1354	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1355	eiter->type = __constant_cpu_to_be16(FDMI_HBA_HARDWARE_VERSION);
1356	strcpy(eiter->a.hw_version, ha->adapter_id);
1357	alen = strlen(eiter->a.hw_version);
1358	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1359	eiter->len = cpu_to_be16(4 + alen);
1360	size += 4 + alen;
1361
1362	ql_dbg(ql_dbg_disc, vha, 0x202a,
1363	    "Hardware ver = %s.\n", eiter->a.hw_version);
1364
1365	/* Driver version. */
1366	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1367	eiter->type = __constant_cpu_to_be16(FDMI_HBA_DRIVER_VERSION);
1368	strcpy(eiter->a.driver_version, qla2x00_version_str);
1369	alen = strlen(eiter->a.driver_version);
1370	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1371	eiter->len = cpu_to_be16(4 + alen);
1372	size += 4 + alen;
1373
1374	ql_dbg(ql_dbg_disc, vha, 0x202b,
1375	    "Driver ver = %s.\n", eiter->a.driver_version);
1376
1377	/* Option ROM version. */
1378	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1379	eiter->type = __constant_cpu_to_be16(FDMI_HBA_OPTION_ROM_VERSION);
1380	strcpy(eiter->a.orom_version, "0.00");
1381	alen = strlen(eiter->a.orom_version);
1382	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1383	eiter->len = cpu_to_be16(4 + alen);
1384	size += 4 + alen;
1385
1386	ql_dbg(ql_dbg_disc, vha , 0x202c,
1387	    "Optrom vers = %s.\n", eiter->a.orom_version);
1388
1389	/* Firmware version */
1390	eiter = (struct ct_fdmi_hba_attr *) (entries + size);
1391	eiter->type = __constant_cpu_to_be16(FDMI_HBA_FIRMWARE_VERSION);
1392	ha->isp_ops->fw_version_str(vha, eiter->a.fw_version);
1393	alen = strlen(eiter->a.fw_version);
1394	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1395	eiter->len = cpu_to_be16(4 + alen);
1396	size += 4 + alen;
1397
1398	ql_dbg(ql_dbg_disc, vha, 0x202d,
1399	    "Firmware vers = %s.\n", eiter->a.fw_version);
1400
1401	/* Update MS request size. */
1402	qla2x00_update_ms_fdmi_iocb(vha, size + 16);
1403
1404	ql_dbg(ql_dbg_disc, vha, 0x202e,
1405	    "RHBA identifier = "
1406	    "%02x%02x%02x%02x%02x%02x%02x%02x size=%d.\n",
1407	    ct_req->req.rhba.hba_identifier[0],
1408	    ct_req->req.rhba.hba_identifier[1],
1409	    ct_req->req.rhba.hba_identifier[2],
1410	    ct_req->req.rhba.hba_identifier[3],
1411	    ct_req->req.rhba.hba_identifier[4],
1412	    ct_req->req.rhba.hba_identifier[5],
1413	    ct_req->req.rhba.hba_identifier[6],
1414	    ct_req->req.rhba.hba_identifier[7], size);
1415	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2076,
1416	    entries, size);
1417
1418	/* Execute MS IOCB */
1419	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
1420	    sizeof(ms_iocb_entry_t));
1421	if (rval != QLA_SUCCESS) {
1422		/*EMPTY*/
1423		ql_dbg(ql_dbg_disc, vha, 0x2030,
1424		    "RHBA issue IOCB failed (%d).\n", rval);
1425	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RHBA") !=
1426	    QLA_SUCCESS) {
1427		rval = QLA_FUNCTION_FAILED;
1428		if (ct_rsp->header.reason_code == CT_REASON_CANNOT_PERFORM &&
1429		    ct_rsp->header.explanation_code ==
1430		    CT_EXPL_ALREADY_REGISTERED) {
1431			ql_dbg(ql_dbg_disc, vha, 0x2034,
1432			    "HBA already registered.\n");
1433			rval = QLA_ALREADY_REGISTERED;
1434		}
1435	} else {
1436		ql_dbg(ql_dbg_disc, vha, 0x2035,
1437		    "RHBA exiting normally.\n");
1438	}
1439
1440	return rval;
1441}
1442
1443/**
1444 * qla2x00_fdmi_dhba() -
1445 * @ha: HA context
1446 *
1447 * Returns 0 on success.
1448 */
1449static int
1450qla2x00_fdmi_dhba(scsi_qla_host_t *vha)
1451{
1452	int rval;
1453	struct qla_hw_data *ha = vha->hw;
1454	ms_iocb_entry_t *ms_pkt;
1455	struct ct_sns_req *ct_req;
1456	struct ct_sns_rsp *ct_rsp;
1457
1458	/* Issue RPA */
1459	/* Prepare common MS IOCB */
1460	ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, DHBA_REQ_SIZE,
1461	    DHBA_RSP_SIZE);
1462
1463	/* Prepare CT request */
1464	ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, DHBA_CMD,
1465	    DHBA_RSP_SIZE);
1466	ct_rsp = &ha->ct_sns->p.rsp;
1467
1468	/* Prepare FDMI command arguments -- portname. */
1469	memcpy(ct_req->req.dhba.port_name, vha->port_name, WWN_SIZE);
1470
1471	ql_dbg(ql_dbg_disc, vha, 0x2036,
1472	    "DHBA portname = %02x%02x%02x%02x%02x%02x%02x%02x.\n",
1473	    ct_req->req.dhba.port_name[0], ct_req->req.dhba.port_name[1],
1474	    ct_req->req.dhba.port_name[2], ct_req->req.dhba.port_name[3],
1475	    ct_req->req.dhba.port_name[4], ct_req->req.dhba.port_name[5],
1476	    ct_req->req.dhba.port_name[6], ct_req->req.dhba.port_name[7]);
1477
1478	/* Execute MS IOCB */
1479	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
1480	    sizeof(ms_iocb_entry_t));
1481	if (rval != QLA_SUCCESS) {
1482		/*EMPTY*/
1483		ql_dbg(ql_dbg_disc, vha, 0x2037,
1484		    "DHBA issue IOCB failed (%d).\n", rval);
1485	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "DHBA") !=
1486	    QLA_SUCCESS) {
1487		rval = QLA_FUNCTION_FAILED;
1488	} else {
1489		ql_dbg(ql_dbg_disc, vha, 0x2038,
1490		    "DHBA exiting normally.\n");
1491	}
1492
1493	return rval;
1494}
1495
1496/**
1497 * qla2x00_fdmi_rpa() -
1498 * @ha: HA context
1499 *
1500 * Returns 0 on success.
1501 */
1502static int
1503qla2x00_fdmi_rpa(scsi_qla_host_t *vha)
1504{
1505	int rval, alen;
1506	uint32_t size, max_frame_size;
1507	struct qla_hw_data *ha = vha->hw;
1508	ms_iocb_entry_t *ms_pkt;
1509	struct ct_sns_req *ct_req;
1510	struct ct_sns_rsp *ct_rsp;
1511	uint8_t *entries;
1512	struct ct_fdmi_port_attr *eiter;
1513	struct init_cb_24xx *icb24 = (struct init_cb_24xx *)ha->init_cb;
1514
1515	/* Issue RPA */
1516	/* Prepare common MS IOCB */
1517	/*   Request size adjusted after CT preparation */
1518	ms_pkt = ha->isp_ops->prep_ms_fdmi_iocb(vha, 0, RPA_RSP_SIZE);
1519
1520	/* Prepare CT request */
1521	ct_req = qla2x00_prep_ct_fdmi_req(&ha->ct_sns->p.req, RPA_CMD,
1522	    RPA_RSP_SIZE);
1523	ct_rsp = &ha->ct_sns->p.rsp;
1524
1525	/* Prepare FDMI command arguments -- attribute block, attributes. */
1526	memcpy(ct_req->req.rpa.port_name, vha->port_name, WWN_SIZE);
1527	size = WWN_SIZE + 4;
1528
1529	/* Attributes */
1530	ct_req->req.rpa.attrs.count =
1531	    __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT - 1);
1532	entries = ct_req->req.rpa.port_name;
1533
1534	/* FC4 types. */
1535	eiter = (struct ct_fdmi_port_attr *) (entries + size);
1536	eiter->type = __constant_cpu_to_be16(FDMI_PORT_FC4_TYPES);
1537	eiter->len = __constant_cpu_to_be16(4 + 32);
1538	eiter->a.fc4_types[2] = 0x01;
1539	size += 4 + 32;
1540
1541	ql_dbg(ql_dbg_disc, vha, 0x2039,
1542	    "FC4_TYPES=%02x %02x.\n",
1543	    eiter->a.fc4_types[2],
1544	    eiter->a.fc4_types[1]);
1545
1546	/* Supported speed. */
1547	eiter = (struct ct_fdmi_port_attr *) (entries + size);
1548	eiter->type = __constant_cpu_to_be16(FDMI_PORT_SUPPORT_SPEED);
1549	eiter->len = __constant_cpu_to_be16(4 + 4);
1550	if (IS_QLA8XXX_TYPE(ha))
1551		eiter->a.sup_speed = __constant_cpu_to_be32(
1552		    FDMI_PORT_SPEED_10GB);
1553	else if (IS_QLA25XX(ha))
1554		eiter->a.sup_speed = __constant_cpu_to_be32(
1555		    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
1556		    FDMI_PORT_SPEED_4GB|FDMI_PORT_SPEED_8GB);
1557	else if (IS_QLA24XX_TYPE(ha))
1558		eiter->a.sup_speed = __constant_cpu_to_be32(
1559		    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB|
1560		    FDMI_PORT_SPEED_4GB);
1561	else if (IS_QLA23XX(ha))
1562		eiter->a.sup_speed =__constant_cpu_to_be32(
1563		    FDMI_PORT_SPEED_1GB|FDMI_PORT_SPEED_2GB);
1564	else
1565		eiter->a.sup_speed = __constant_cpu_to_be32(
1566		    FDMI_PORT_SPEED_1GB);
1567	size += 4 + 4;
1568
1569	ql_dbg(ql_dbg_disc, vha, 0x203a,
1570	    "Supported_Speed=%x.\n", eiter->a.sup_speed);
1571
1572	/* Current speed. */
1573	eiter = (struct ct_fdmi_port_attr *) (entries + size);
1574	eiter->type = __constant_cpu_to_be16(FDMI_PORT_CURRENT_SPEED);
1575	eiter->len = __constant_cpu_to_be16(4 + 4);
1576	switch (ha->link_data_rate) {
1577	case PORT_SPEED_1GB:
1578		eiter->a.cur_speed =
1579		    __constant_cpu_to_be32(FDMI_PORT_SPEED_1GB);
1580		break;
1581	case PORT_SPEED_2GB:
1582		eiter->a.cur_speed =
1583		    __constant_cpu_to_be32(FDMI_PORT_SPEED_2GB);
1584		break;
1585	case PORT_SPEED_4GB:
1586		eiter->a.cur_speed =
1587		    __constant_cpu_to_be32(FDMI_PORT_SPEED_4GB);
1588		break;
1589	case PORT_SPEED_8GB:
1590		eiter->a.cur_speed =
1591		    __constant_cpu_to_be32(FDMI_PORT_SPEED_8GB);
1592		break;
1593	case PORT_SPEED_10GB:
1594		eiter->a.cur_speed =
1595		    __constant_cpu_to_be32(FDMI_PORT_SPEED_10GB);
1596		break;
1597	default:
1598		eiter->a.cur_speed =
1599		    __constant_cpu_to_be32(FDMI_PORT_SPEED_UNKNOWN);
1600		break;
1601	}
1602	size += 4 + 4;
1603
1604	ql_dbg(ql_dbg_disc, vha, 0x203b,
1605	    "Current_Speed=%x.\n", eiter->a.cur_speed);
1606
1607	/* Max frame size. */
1608	eiter = (struct ct_fdmi_port_attr *) (entries + size);
1609	eiter->type = __constant_cpu_to_be16(FDMI_PORT_MAX_FRAME_SIZE);
1610	eiter->len = __constant_cpu_to_be16(4 + 4);
1611	max_frame_size = IS_FWI2_CAPABLE(ha) ?
1612	    le16_to_cpu(icb24->frame_payload_size):
1613	    le16_to_cpu(ha->init_cb->frame_payload_size);
1614	eiter->a.max_frame_size = cpu_to_be32(max_frame_size);
1615	size += 4 + 4;
1616
1617	ql_dbg(ql_dbg_disc, vha, 0x203c,
1618	    "Max_Frame_Size=%x.\n", eiter->a.max_frame_size);
1619
1620	/* OS device name. */
1621	eiter = (struct ct_fdmi_port_attr *) (entries + size);
1622	eiter->type = __constant_cpu_to_be16(FDMI_PORT_OS_DEVICE_NAME);
1623	strcpy(eiter->a.os_dev_name, QLA2XXX_DRIVER_NAME);
1624	alen = strlen(eiter->a.os_dev_name);
1625	alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1626	eiter->len = cpu_to_be16(4 + alen);
1627	size += 4 + alen;
1628
1629	ql_dbg(ql_dbg_disc, vha, 0x204b,
1630	    "OS_Device_Name=%s.\n", eiter->a.os_dev_name);
1631
1632	/* Hostname. */
1633	if (strlen(fc_host_system_hostname(vha->host))) {
1634		ct_req->req.rpa.attrs.count =
1635		    __constant_cpu_to_be32(FDMI_PORT_ATTR_COUNT);
1636		eiter = (struct ct_fdmi_port_attr *) (entries + size);
1637		eiter->type = __constant_cpu_to_be16(FDMI_PORT_HOST_NAME);
1638		snprintf(eiter->a.host_name, sizeof(eiter->a.host_name),
1639		    "%s", fc_host_system_hostname(vha->host));
1640		alen = strlen(eiter->a.host_name);
1641		alen += (alen & 3) ? (4 - (alen & 3)) : 4;
1642		eiter->len = cpu_to_be16(4 + alen);
1643		size += 4 + alen;
1644
1645		ql_dbg(ql_dbg_disc, vha, 0x203d,
1646		    "HostName=%s.\n", eiter->a.host_name);
1647	}
1648
1649	/* Update MS request size. */
1650	qla2x00_update_ms_fdmi_iocb(vha, size + 16);
1651
1652	ql_dbg(ql_dbg_disc, vha, 0x203e,
1653	    "RPA portname= %02x%02x%02x%02x%02X%02x%02x%02x size=%d.\n",
1654	    ct_req->req.rpa.port_name[0], ct_req->req.rpa.port_name[1],
1655	    ct_req->req.rpa.port_name[2], ct_req->req.rpa.port_name[3],
1656	    ct_req->req.rpa.port_name[4], ct_req->req.rpa.port_name[5],
1657	    ct_req->req.rpa.port_name[6], ct_req->req.rpa.port_name[7],
1658	    size);
1659	ql_dump_buffer(ql_dbg_disc + ql_dbg_buffer, vha, 0x2079,
1660	    entries, size);
1661
1662	/* Execute MS IOCB */
1663	rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
1664	    sizeof(ms_iocb_entry_t));
1665	if (rval != QLA_SUCCESS) {
1666		/*EMPTY*/
1667		ql_dbg(ql_dbg_disc, vha, 0x2040,
1668		    "RPA issue IOCB failed (%d).\n", rval);
1669	} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp, "RPA") !=
1670	    QLA_SUCCESS) {
1671		rval = QLA_FUNCTION_FAILED;
1672	} else {
1673		ql_dbg(ql_dbg_disc, vha, 0x2041,
1674		    "RPA exiting nornally.\n");
1675	}
1676
1677	return rval;
1678}
1679
1680/**
1681 * qla2x00_fdmi_register() -
1682 * @ha: HA context
1683 *
1684 * Returns 0 on success.
1685 */
1686int
1687qla2x00_fdmi_register(scsi_qla_host_t *vha)
1688{
1689	int rval;
1690       struct qla_hw_data *ha = vha->hw;
1691
1692	if (IS_QLA2100(ha) || IS_QLA2200(ha))
1693		return QLA_FUNCTION_FAILED;
1694
1695	rval = qla2x00_mgmt_svr_login(vha);
1696	if (rval)
1697		return rval;
1698
1699	rval = qla2x00_fdmi_rhba(vha);
1700	if (rval) {
1701		if (rval != QLA_ALREADY_REGISTERED)
1702			return rval;
1703
1704		rval = qla2x00_fdmi_dhba(vha);
1705		if (rval)
1706			return rval;
1707
1708		rval = qla2x00_fdmi_rhba(vha);
1709		if (rval)
1710			return rval;
1711	}
1712	rval = qla2x00_fdmi_rpa(vha);
1713
1714	return rval;
1715}
1716
1717/**
1718 * qla2x00_gfpn_id() - SNS Get Fabric Port Name (GFPN_ID) query.
1719 * @ha: HA context
1720 * @list: switch info entries to populate
1721 *
1722 * Returns 0 on success.
1723 */
1724int
1725qla2x00_gfpn_id(scsi_qla_host_t *vha, sw_info_t *list)
1726{
1727	int		rval;
1728	uint16_t	i;
1729	struct qla_hw_data *ha = vha->hw;
1730	ms_iocb_entry_t	*ms_pkt;
1731	struct ct_sns_req	*ct_req;
1732	struct ct_sns_rsp	*ct_rsp;
1733
1734	if (!IS_IIDMA_CAPABLE(ha))
1735		return QLA_FUNCTION_FAILED;
1736
1737	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
1738		/* Issue GFPN_ID */
1739		/* Prepare common MS IOCB */
1740		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFPN_ID_REQ_SIZE,
1741		    GFPN_ID_RSP_SIZE);
1742
1743		/* Prepare CT request */
1744		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFPN_ID_CMD,
1745		    GFPN_ID_RSP_SIZE);
1746		ct_rsp = &ha->ct_sns->p.rsp;
1747
1748		/* Prepare CT arguments -- port_id */
1749		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
1750		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
1751		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
1752
1753		/* Execute MS IOCB */
1754		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
1755		    sizeof(ms_iocb_entry_t));
1756		if (rval != QLA_SUCCESS) {
1757			/*EMPTY*/
1758			ql_dbg(ql_dbg_disc, vha, 0x2023,
1759			    "GFPN_ID issue IOCB failed (%d).\n", rval);
1760		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
1761		    "GFPN_ID") != QLA_SUCCESS) {
1762			rval = QLA_FUNCTION_FAILED;
1763		} else {
1764			/* Save fabric portname */
1765			memcpy(list[i].fabric_port_name,
1766			    ct_rsp->rsp.gfpn_id.port_name, WWN_SIZE);
1767		}
1768
1769		/* Last device exit. */
1770		if (list[i].d_id.b.rsvd_1 != 0)
1771			break;
1772	}
1773
1774	return (rval);
1775}
1776
1777static inline void *
1778qla24xx_prep_ms_fm_iocb(scsi_qla_host_t *vha, uint32_t req_size,
1779    uint32_t rsp_size)
1780{
1781	struct ct_entry_24xx *ct_pkt;
1782	struct qla_hw_data *ha = vha->hw;
1783	ct_pkt = (struct ct_entry_24xx *)ha->ms_iocb;
1784	memset(ct_pkt, 0, sizeof(struct ct_entry_24xx));
1785
1786	ct_pkt->entry_type = CT_IOCB_TYPE;
1787	ct_pkt->entry_count = 1;
1788	ct_pkt->nport_handle = cpu_to_le16(vha->mgmt_svr_loop_id);
1789	ct_pkt->timeout = cpu_to_le16(ha->r_a_tov / 10 * 2);
1790	ct_pkt->cmd_dsd_count = __constant_cpu_to_le16(1);
1791	ct_pkt->rsp_dsd_count = __constant_cpu_to_le16(1);
1792	ct_pkt->rsp_byte_count = cpu_to_le32(rsp_size);
1793	ct_pkt->cmd_byte_count = cpu_to_le32(req_size);
1794
1795	ct_pkt->dseg_0_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
1796	ct_pkt->dseg_0_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
1797	ct_pkt->dseg_0_len = ct_pkt->cmd_byte_count;
1798
1799	ct_pkt->dseg_1_address[0] = cpu_to_le32(LSD(ha->ct_sns_dma));
1800	ct_pkt->dseg_1_address[1] = cpu_to_le32(MSD(ha->ct_sns_dma));
1801	ct_pkt->dseg_1_len = ct_pkt->rsp_byte_count;
1802	ct_pkt->vp_index = vha->vp_idx;
1803
1804	return ct_pkt;
1805}
1806
1807
1808static inline struct ct_sns_req *
1809qla24xx_prep_ct_fm_req(struct ct_sns_req *ct_req, uint16_t cmd,
1810    uint16_t rsp_size)
1811{
1812	memset(ct_req, 0, sizeof(struct ct_sns_pkt));
1813
1814	ct_req->header.revision = 0x01;
1815	ct_req->header.gs_type = 0xFA;
1816	ct_req->header.gs_subtype = 0x01;
1817	ct_req->command = cpu_to_be16(cmd);
1818	ct_req->max_rsp_size = cpu_to_be16((rsp_size - 16) / 4);
1819
1820	return ct_req;
1821}
1822
1823/**
1824 * qla2x00_gpsc() - FCS Get Port Speed Capabilities (GPSC) query.
1825 * @ha: HA context
1826 * @list: switch info entries to populate
1827 *
1828 * Returns 0 on success.
1829 */
1830int
1831qla2x00_gpsc(scsi_qla_host_t *vha, sw_info_t *list)
1832{
1833	int		rval;
1834	uint16_t	i;
1835	struct qla_hw_data *ha = vha->hw;
1836	ms_iocb_entry_t	*ms_pkt;
1837	struct ct_sns_req	*ct_req;
1838	struct ct_sns_rsp	*ct_rsp;
1839
1840	if (!IS_IIDMA_CAPABLE(ha))
1841		return QLA_FUNCTION_FAILED;
1842	if (!ha->flags.gpsc_supported)
1843		return QLA_FUNCTION_FAILED;
1844
1845	rval = qla2x00_mgmt_svr_login(vha);
1846	if (rval)
1847		return rval;
1848
1849	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
1850		/* Issue GFPN_ID */
1851		/* Prepare common MS IOCB */
1852		ms_pkt = qla24xx_prep_ms_fm_iocb(vha, GPSC_REQ_SIZE,
1853		    GPSC_RSP_SIZE);
1854
1855		/* Prepare CT request */
1856		ct_req = qla24xx_prep_ct_fm_req(&ha->ct_sns->p.req,
1857		    GPSC_CMD, GPSC_RSP_SIZE);
1858		ct_rsp = &ha->ct_sns->p.rsp;
1859
1860		/* Prepare CT arguments -- port_name */
1861		memcpy(ct_req->req.gpsc.port_name, list[i].fabric_port_name,
1862		    WWN_SIZE);
1863
1864		/* Execute MS IOCB */
1865		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
1866		    sizeof(ms_iocb_entry_t));
1867		if (rval != QLA_SUCCESS) {
1868			/*EMPTY*/
1869			ql_dbg(ql_dbg_disc, vha, 0x2059,
1870			    "GPSC issue IOCB failed (%d).\n", rval);
1871		} else if ((rval = qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
1872		    "GPSC")) != QLA_SUCCESS) {
1873			/* FM command unsupported? */
1874			if (rval == QLA_INVALID_COMMAND &&
1875			    (ct_rsp->header.reason_code ==
1876				CT_REASON_INVALID_COMMAND_CODE ||
1877			     ct_rsp->header.reason_code ==
1878				CT_REASON_COMMAND_UNSUPPORTED)) {
1879				ql_dbg(ql_dbg_disc, vha, 0x205a,
1880				    "GPSC command unsupported, disabling "
1881				    "query.\n");
1882				ha->flags.gpsc_supported = 0;
1883				rval = QLA_FUNCTION_FAILED;
1884				break;
1885			}
1886			rval = QLA_FUNCTION_FAILED;
1887		} else {
1888			/* Save port-speed */
1889			switch (be16_to_cpu(ct_rsp->rsp.gpsc.speed)) {
1890			case BIT_15:
1891				list[i].fp_speed = PORT_SPEED_1GB;
1892				break;
1893			case BIT_14:
1894				list[i].fp_speed = PORT_SPEED_2GB;
1895				break;
1896			case BIT_13:
1897				list[i].fp_speed = PORT_SPEED_4GB;
1898				break;
1899			case BIT_12:
1900				list[i].fp_speed = PORT_SPEED_10GB;
1901				break;
1902			case BIT_11:
1903				list[i].fp_speed = PORT_SPEED_8GB;
1904				break;
1905			}
1906
1907			ql_dbg(ql_dbg_disc, vha, 0x205b,
1908			    "GPSC ext entry - fpn "
1909			    "%02x%02x%02x%02x%02x%02x%02x%02x speeds=%04x "
1910			    "speed=%04x.\n",
1911			    list[i].fabric_port_name[0],
1912			    list[i].fabric_port_name[1],
1913			    list[i].fabric_port_name[2],
1914			    list[i].fabric_port_name[3],
1915			    list[i].fabric_port_name[4],
1916			    list[i].fabric_port_name[5],
1917			    list[i].fabric_port_name[6],
1918			    list[i].fabric_port_name[7],
1919			    be16_to_cpu(ct_rsp->rsp.gpsc.speeds),
1920			    be16_to_cpu(ct_rsp->rsp.gpsc.speed));
1921		}
1922
1923		/* Last device exit. */
1924		if (list[i].d_id.b.rsvd_1 != 0)
1925			break;
1926	}
1927
1928	return (rval);
1929}
1930
1931/**
1932 * qla2x00_gff_id() - SNS Get FC-4 Features (GFF_ID) query.
1933 *
1934 * @ha: HA context
1935 * @list: switch info entries to populate
1936 *
1937 */
1938void
1939qla2x00_gff_id(scsi_qla_host_t *vha, sw_info_t *list)
1940{
1941	int		rval;
1942	uint16_t	i;
1943
1944	ms_iocb_entry_t	*ms_pkt;
1945	struct ct_sns_req	*ct_req;
1946	struct ct_sns_rsp	*ct_rsp;
1947	struct qla_hw_data *ha = vha->hw;
1948	uint8_t fcp_scsi_features = 0;
1949
1950	for (i = 0; i < MAX_FIBRE_DEVICES; i++) {
1951		/* Set default FC4 Type as UNKNOWN so the default is to
1952		 * Process this port */
1953		list[i].fc4_type = FC4_TYPE_UNKNOWN;
1954
1955		/* Do not attempt GFF_ID if we are not FWI_2 capable */
1956		if (!IS_FWI2_CAPABLE(ha))
1957			continue;
1958
1959		/* Prepare common MS IOCB */
1960		ms_pkt = ha->isp_ops->prep_ms_iocb(vha, GFF_ID_REQ_SIZE,
1961		    GFF_ID_RSP_SIZE);
1962
1963		/* Prepare CT request */
1964		ct_req = qla2x00_prep_ct_req(&ha->ct_sns->p.req, GFF_ID_CMD,
1965		    GFF_ID_RSP_SIZE);
1966		ct_rsp = &ha->ct_sns->p.rsp;
1967
1968		/* Prepare CT arguments -- port_id */
1969		ct_req->req.port_id.port_id[0] = list[i].d_id.b.domain;
1970		ct_req->req.port_id.port_id[1] = list[i].d_id.b.area;
1971		ct_req->req.port_id.port_id[2] = list[i].d_id.b.al_pa;
1972
1973		/* Execute MS IOCB */
1974		rval = qla2x00_issue_iocb(vha, ha->ms_iocb, ha->ms_iocb_dma,
1975		   sizeof(ms_iocb_entry_t));
1976
1977		if (rval != QLA_SUCCESS) {
1978			ql_dbg(ql_dbg_disc, vha, 0x205c,
1979			    "GFF_ID issue IOCB failed (%d).\n", rval);
1980		} else if (qla2x00_chk_ms_status(vha, ms_pkt, ct_rsp,
1981			       "GFF_ID") != QLA_SUCCESS) {
1982			ql_dbg(ql_dbg_disc, vha, 0x205d,
1983			    "GFF_ID IOCB status had a failure status code.\n");
1984		} else {
1985			fcp_scsi_features =
1986			   ct_rsp->rsp.gff_id.fc4_features[GFF_FCP_SCSI_OFFSET];
1987			fcp_scsi_features &= 0x0f;
1988
1989			if (fcp_scsi_features)
1990				list[i].fc4_type = FC4_TYPE_FCP_SCSI;
1991			else
1992				list[i].fc4_type = FC4_TYPE_OTHER;
1993		}
1994
1995		/* Last device exit. */
1996		if (list[i].d_id.b.rsvd_1 != 0)
1997			break;
1998	}
1999}
2000