xref: /illumos-gate/usr/src/uts/common/io/fibre-channel/fca/emlxs/emlxs_dfc.c (revision b6805bf78d2bbbeeaea8909a05623587b42d58b3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2010 Emulex.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 
28 #include <emlxs.h>
29 
30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
31 EMLXS_MSG_DEF(EMLXS_DFC_C);
32 
33 static int32_t		emlxs_dfc_get_rev(emlxs_hba_t *hba, dfc_t *dfc,
34 				int32_t mode);
35 static int32_t		emlxs_dfc_get_hbainfo(emlxs_hba_t *hba, dfc_t *dfc,
36 				int32_t mode);
37 static int32_t		emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc,
38 				int32_t mode);
39 static int32_t		emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc,
40 				int32_t mode);
41 static int32_t		emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc,
42 				int32_t mode);
43 static int32_t		emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc,
44 				int32_t mode);
45 static int32_t		emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc,
46 				int32_t mode);
47 static int32_t		emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc,
48 				int32_t mode);
49 static int32_t		emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc,
50 				int32_t mode);
51 static int32_t		emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc,
52 				int32_t mode);
53 static int32_t		emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc,
54 				int32_t mode);
55 static int32_t		emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc,
56 				int32_t mode);
57 static int32_t		emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc,
58 				int32_t mode);
59 static int32_t		emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc,
60 				int32_t mode);
61 static int32_t		emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc,
62 				int32_t mode);
63 static int32_t		emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc,
64 				int32_t mode);
65 static int32_t		emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc,
66 				int32_t mode);
67 static int32_t		emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc,
68 				int32_t mode);
69 static int32_t		emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc,
70 				int32_t mode);
71 static int32_t		emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc,
72 				int32_t mode);
73 static int32_t		emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc,
74 				int32_t mode);
75 static int32_t		emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc,
76 				int32_t mode);
77 static int32_t		emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc,
78 				int32_t mode);
79 static int32_t		emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc,
80 				int32_t mode);
81 static int32_t		emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc,
82 				int32_t mode);
83 static int32_t		emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc,
84 				int32_t mode);
85 static int32_t		emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc,
86 				int32_t mode);
87 static int32_t		emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc,
88 				int32_t mode);
89 static int32_t		emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc,
90 				int32_t mode);
91 
92 #ifdef SFCT_SUPPORT
93 static int32_t		emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc,
94 				int32_t mode);
95 #endif /* SFCT_SUPPORT */
96 
97 static int32_t		emlxs_dfc_create_vport(emlxs_hba_t *hba, dfc_t *dfc,
98 				int32_t mode);
99 static int32_t		emlxs_dfc_destroy_vport(emlxs_hba_t *hba, dfc_t *dfc,
100 				int32_t mode);
101 static int32_t		emlxs_dfc_get_vportinfo(emlxs_hba_t *hba, dfc_t *dfc,
102 				int32_t mode);
103 static int32_t		emlxs_dfc_npiv_resource(emlxs_hba_t *hba, dfc_t *dfc,
104 				int32_t mode);
105 static int32_t		emlxs_dfc_npiv_test(emlxs_hba_t *hba, dfc_t *dfc,
106 				int32_t mode);
107 static emlxs_port_t	*emlxs_vport_find_wwpn(emlxs_hba_t *hba, uint8_t *wwpn);
108 
109 #ifdef DHCHAP_SUPPORT
110 static int32_t		emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc,
111 				int32_t mode);
112 static int32_t		emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc,
113 				int32_t mode);
114 static int32_t		emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc,
115 				int32_t mode);
116 static int32_t		emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc,
117 				int32_t mode);
118 static int32_t		emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc,
119 				int32_t mode);
120 static int32_t		emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc,
121 				int32_t mode);
122 static int32_t		emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba,
123 				dfc_t *dfc, int32_t mode);
124 static int32_t		emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba,
125 				dfc_t *dfc, int32_t mode);
126 #endif	/* DHCHAP_SUPPORT */
127 
128 #ifdef SAN_DIAG_SUPPORT
129 static int32_t		emlxs_dfc_sd_set_bucket(dfc_t *dfc, int32_t mode);
130 static int32_t		emlxs_dfc_sd_destroy_bucket(dfc_t *dfc);
131 static int32_t		emlxs_dfc_sd_get_bucket(dfc_t *dfc, int32_t mode);
132 static int32_t		emlxs_dfc_sd_start_collection(emlxs_hba_t *hba,
133 				dfc_t *dfc, int32_t mode);
134 static int32_t		emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba,
135 				dfc_t *dfc, int32_t mode);
136 static int32_t		emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba,
137 				dfc_t *dfc, int32_t mode);
138 static int32_t		emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc,
139 				int32_t mode);
140 static int32_t		emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc,
141 				int32_t mode);
142 static int32_t		emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc,
143 				int32_t mode);
144 #endif	/* SAN_DIAG_SUPPORT */
145 
146 static int32_t		emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc,
147 				int32_t mode);
148 #ifdef FCIO_SUPPORT
149 static int32_t		emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc,
150 				int32_t mode);
151 #endif	/* FCIO_SUPPORT */
152 
153 static int32_t		emlxs_dfc_get_persist_linkdown(emlxs_hba_t *hba,
154 				dfc_t *dfc, int32_t mode);
155 static int32_t		emlxs_dfc_set_persist_linkdown(emlxs_hba_t *hba,
156 				dfc_t *dfc, int32_t mode);
157 
158 /* SLI-4 ioctls */
159 static int32_t		emlxs_dfc_get_fcflist(emlxs_hba_t *hba, dfc_t *dfc,
160 				int32_t mode);
161 static int32_t		emlxs_dfc_send_mbox4(emlxs_hba_t *hba, dfc_t *dfc,
162 				int32_t mode);
163 static int		emlxs_dfc_rd_be_fcf(emlxs_hba_t *hba, dfc_t *dfc,
164 			    int32_t mode);
165 static int		emlxs_dfc_set_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc,
166 			    int32_t mode);
167 static int		emlxs_dfc_get_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc,
168 			    int32_t mode);
169 static int		emlxs_dfc_get_qos(emlxs_hba_t *hba, dfc_t *dfc,
170 			    int32_t mode);
171 
172 
173 uint32_t	emlxs_loopback_tmo = 60;
174 
175 emlxs_table_t emlxs_dfc_table[] = {
176 	{EMLXS_GET_HBAINFO, "GET_HBAINFO"},
177 	{EMLXS_GET_REV, "GET_REV"},
178 	{EMLXS_SET_DIAG, "SET_DIAG"},
179 	{EMLXS_SEND_MBOX, "SEND_MBOX"},
180 	{EMLXS_READ_PCI, "READ_PCI"},
181 	{EMLXS_WRITE_PCI, "WRITE_PCI"},
182 	{EMLXS_GET_CFG, "GET_CFG"},
183 	{EMLXS_SET_CFG, "SET_CFG"},
184 	{EMLXS_SEND_CT, "SEND_CT"},
185 	{EMLXS_SEND_CT_RSP, "SEND_CT_RSP"},
186 	{EMLXS_SEND_MENLO, "SEND_MENLO"},
187 	{EMLXS_WRITE_FLASH, "WRITE_FLASH"},
188 	{EMLXS_READ_FLASH, "READ_FLASH"},
189 	{EMLXS_SEND_ELS, "SEND_ELS"},
190 	{EMLXS_LOOPBACK_TEST, "LOOPBACK_TEST"},
191 	{EMLXS_GET_DUMPREGION, "GET_DUMPREGION"},
192 	{EMLXS_LOOPBACK_MODE, "LOOPBACK_MODE"},
193 	{EMLXS_GET_IOINFO, "GET_IOINFO"},
194 	{EMLXS_GET_LINKINFO, "GET_LINKINFO"},
195 	{EMLXS_GET_NODEINFO, "GET_NODEINFO"},
196 	{EMLXS_READ_MEM, "READ_MEM"},
197 	{EMLXS_WRITE_MEM, "WRITE_MEM"},
198 	{EMLXS_WRITE_CTLREG, "WRITE_CTLREG"},
199 	{EMLXS_READ_CTLREG, "READ_CTLREG"},
200 	{EMLXS_SEND_SCSI, "SEND_SCSI"},
201 	{EMLXS_GET_EVENT, "GET_EVENT"},
202 	{EMLXS_SET_EVENT, "SET_EVENT"},
203 	{EMLXS_GET_EVENTINFO, "GET_EVENTINFO"},
204 	{EMLXS_GET_HBASTATS, "GET_HBASTATS"},
205 	{EMLXS_GET_DRVSTATS, "GET_DRVSTATS"},
206 	{EMLXS_CREATE_VPORT, "CREATE_VPORT"},
207 	{EMLXS_DESTROY_VPORT, "DESTROY_VPORT"},
208 	{EMLXS_GET_VPORTINFO, "GET_VPORTINFO"},
209 	{EMLXS_NPIV_RESOURCE, "NPIV_RESOURCE"},
210 	{EMLXS_NPIV_TEST, "NPIV_TEST"},
211 	{EMLXS_INIT_AUTH, "INIT_AUTH"},
212 	{EMLXS_GET_AUTH_CFG, "GET_AUTH_CFG"},
213 	{EMLXS_SET_AUTH_CFG, "SET_AUTH_CFG"},
214 	{EMLXS_GET_AUTH_PASSWORD, "GET_AUTH_PASSWORD"},
215 	{EMLXS_SET_AUTH_PASSWORD, "SET_AUTH_PASSWORD"},
216 	{EMLXS_GET_AUTH_STATUS, "GET_AUTH_STATUS"},
217 	{EMLXS_GET_AUTH_CFG_TABLE, "GET_AUTH_CFG_TABLE"},
218 	{EMLXS_GET_AUTH_KEY_TABLE, "GET_AUTH_KEY_TABLE"},
219 	{EMLXS_FCIO_CMD, "FCIO_CMD"},
220 	{EMLXS_GET_FCTSTAT, "GET_FCTSTAT"},
221 	{EMLXS_GET_PERSIST_LINKDOWN, "GET_PERSIST_LINKDOWN"},
222 	{EMLXS_SET_PERSIST_LINKDOWN, "SET_PERSIST_LINKDOWN"},
223 	{EMLXS_GET_FCOE_FCFLIST, "GET_FCOE_FCFLIST"},
224 	{EMLXS_SEND_MBOX4, "SEND_MBOX4"},
225 	{EMLXS_RD_BE_FCF, "RD_BE_FCF"},
226 	{EMLXS_SET_BE_DCBX, "SET_BE_DCBX"},
227 	{EMLXS_GET_BE_DCBX, "GET_BE_DCBX"},
228 	{EMLXS_GET_QOS, "GET_QOS"},
229 
230 };	/* emlxs_dfc_table */
231 
232 
233 emlxs_table_t emlxs_dfc_event_table[] = {
234 	{FC_REG_LINK_EVENT,		"LINK_EVENT"},
235 	{FC_REG_RSCN_EVENT,		"RSCN_EVENT"},
236 	{FC_REG_CT_EVENT,		"CT_EVENT"},
237 	{FC_REG_DUMP_EVENT,		"DUMP_EVENT"},
238 	{FC_REG_TEMP_EVENT,		"TEMP_EVENT"},
239 	{FC_REG_VPORTRSCN_EVENT,	"VPORTRSCN_EVENT"},
240 	{FC_REG_FCOE_EVENT,		"FCOE_EVENT"},
241 
242 };	/* emlxs_dfc_event_table */
243 
244 
245 #ifdef SAN_DIAG_SUPPORT
246 kmutex_t		sd_bucket_mutex;
247 sd_bucket_info_t	sd_bucket;
248 #endif	/* SAN_DIAG_SUPPORT */
249 
250 extern char    *
251 emlxs_dfc_xlate(uint16_t cmd)
252 {
253 	static char	buffer[32];
254 	uint32_t	i;
255 	uint32_t	count;
256 
257 	count = sizeof (emlxs_dfc_table) / sizeof (emlxs_table_t);
258 	for (i = 0; i < count; i++) {
259 		if (cmd == emlxs_dfc_table[i].code) {
260 			return (emlxs_dfc_table[i].string);
261 		}
262 	}
263 
264 	(void) sprintf(buffer, "Cmd=0x%x", cmd);
265 	return (buffer);
266 
267 } /* emlxs_dfc_xlate() */
268 
269 
270 extern char    *
271 emlxs_dfc_event_xlate(uint32_t event)
272 {
273 	static char	buffer[32];
274 	uint32_t	i;
275 	uint32_t	count;
276 
277 	count = sizeof (emlxs_dfc_event_table) / sizeof (emlxs_table_t);
278 	for (i = 0; i < count; i++) {
279 		if (event == emlxs_dfc_event_table[i].code) {
280 			return (emlxs_dfc_event_table[i].string);
281 		}
282 	}
283 
284 	(void) sprintf(buffer, "Event=0x%x", event);
285 	return (buffer);
286 
287 } /* emlxs_dfc_event_xlate() */
288 
289 
290 
291 extern int32_t
292 emlxs_dfc_manage(emlxs_hba_t *hba, void *arg, int32_t mode)
293 {
294 	emlxs_port_t	*port = &PPORT;
295 	int		rval = 0;
296 	dfc_t		*dfc;
297 
298 	dfc = (dfc_t *)kmem_zalloc(sizeof (dfc_t), KM_SLEEP);
299 
300 #ifdef	_MULTI_DATAMODEL
301 	switch (ddi_model_convert_from(mode & FMODELS)) {
302 	case DDI_MODEL_ILP32:
303 		{
304 			dfc32_t		dfc32;
305 
306 			if (ddi_copyin((void *)arg, (void *)&dfc32,
307 			    sizeof (dfc32_t), mode)) {
308 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
309 				    "%s: ddi_copyin failed.",
310 				    emlxs_dfc_xlate(dfc->cmd));
311 
312 				rval = DFC_COPYIN_ERROR;
313 				break;
314 			}
315 
316 			dfc->cmd = dfc32.cmd;
317 			dfc->flag = dfc32.flag;
318 			dfc->buf1 = (void *)((uintptr_t)dfc32.buf1);
319 			dfc->buf1_size = dfc32.buf1_size;
320 			dfc->data1 = dfc32.data1;
321 			dfc->buf2 = (void *)((uintptr_t)dfc32.buf2);
322 			dfc->buf2_size = dfc32.buf2_size;
323 			dfc->data2 = dfc32.data2;
324 			dfc->buf3 = (void *)((uintptr_t)dfc32.buf3);
325 			dfc->buf3_size = dfc32.buf3_size;
326 			dfc->data3 = dfc32.data3;
327 			dfc->buf4 = (void *)((uintptr_t)dfc32.buf4);
328 			dfc->buf4_size = dfc32.buf4_size;
329 			dfc->data4 = dfc32.data4;
330 
331 			break;
332 		}
333 
334 	case DDI_MODEL_NONE:
335 		if (ddi_copyin((void *)arg, (void *)dfc, sizeof (dfc_t),
336 		    mode)) {
337 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
338 			    "%s: ddi_copyin failed.",
339 			    emlxs_dfc_xlate(dfc->cmd));
340 
341 			rval = DFC_COPYIN_ERROR;
342 		}
343 		break;
344 	}
345 #else	/* _MULTI_DATAMODEL */
346 	if (ddi_copyin((void *)arg, (void *)dfc, sizeof (dfc_t), mode)) {
347 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
348 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
349 
350 		rval = DFC_COPYIN_ERROR;
351 	}
352 #endif	/* _MULTI_DATAMODEL */
353 
354 
355 	switch (dfc->cmd) {
356 	case EMLXS_GET_HBAINFO:
357 		{
358 
359 			rval = emlxs_dfc_get_hbainfo(hba, dfc, mode);
360 
361 			break;
362 		}
363 
364 	case EMLXS_GET_HBASTATS:
365 		{
366 
367 			rval = emlxs_dfc_get_hbastats(hba, dfc, mode);
368 
369 			break;
370 		}
371 
372 	case EMLXS_GET_DRVSTATS:
373 		{
374 
375 			rval = emlxs_dfc_get_drvstats(hba, dfc, mode);
376 
377 			break;
378 		}
379 
380 	case EMLXS_GET_NODEINFO:
381 		{
382 
383 			rval = emlxs_dfc_get_nodeinfo(hba, dfc, mode);
384 
385 			break;
386 		}
387 
388 	case EMLXS_SET_DIAG:
389 		{
390 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
391 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
392 
393 			rval = emlxs_dfc_set_diag(hba, dfc, mode);
394 
395 			break;
396 		}
397 
398 	case EMLXS_SEND_MBOX:
399 		{
400 			rval = emlxs_dfc_send_mbox(hba, dfc, mode);
401 
402 			break;
403 		}
404 
405 	case EMLXS_READ_PCI:
406 		{
407 			rval = emlxs_dfc_read_pci(hba, dfc, mode);
408 
409 			break;
410 		}
411 
412 	case EMLXS_WRITE_PCI:
413 		{
414 			rval = emlxs_dfc_write_pci(hba, dfc, mode);
415 
416 			break;
417 		}
418 
419 	case EMLXS_GET_CFG:
420 		{
421 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
422 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
423 
424 			rval = emlxs_dfc_get_cfg(hba, dfc, mode);
425 
426 			break;
427 		}
428 
429 	case EMLXS_SET_CFG:
430 		{
431 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
432 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
433 
434 			rval = emlxs_dfc_set_cfg(hba, dfc, mode);
435 
436 			break;
437 		}
438 
439 	case EMLXS_SEND_CT:
440 		{
441 			rval = emlxs_dfc_send_ct(hba, dfc, mode);
442 
443 			break;
444 		}
445 
446 	case EMLXS_SEND_CT_RSP:
447 		{
448 			rval = emlxs_dfc_send_ct_rsp(hba, dfc, mode);
449 
450 			break;
451 		}
452 
453 #ifdef MENLO_SUPPORT
454 	case EMLXS_SEND_MENLO:
455 		{
456 			rval = emlxs_dfc_send_menlo(hba, dfc, mode);
457 
458 			break;
459 		}
460 #endif /* MENLO_SUPPORT */
461 
462 	case EMLXS_WRITE_FLASH:
463 		{
464 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
465 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
466 
467 			rval = emlxs_dfc_write_flash(hba, dfc, mode);
468 
469 			break;
470 		}
471 
472 	case EMLXS_READ_FLASH:
473 		{
474 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
475 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
476 
477 			rval = emlxs_dfc_read_flash(hba, dfc, mode);
478 
479 			break;
480 		}
481 
482 	case EMLXS_SEND_ELS:
483 		{
484 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
485 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
486 
487 			rval = emlxs_dfc_send_els(hba, dfc, mode);
488 
489 			break;
490 		}
491 
492 	case EMLXS_LOOPBACK_TEST:
493 		{
494 			rval = emlxs_dfc_loopback_test(hba, dfc, mode);
495 
496 			break;
497 		}
498 
499 	case EMLXS_GET_DUMPREGION:
500 		{
501 
502 			rval = emlxs_dfc_get_dump_region(hba, dfc, mode);
503 
504 			break;
505 		}
506 
507 	case EMLXS_LOOPBACK_MODE:
508 		{
509 			rval = emlxs_dfc_loopback_mode(hba, dfc, mode);
510 
511 			break;
512 		}
513 
514 	case EMLXS_GET_IOINFO:
515 		{
516 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
517 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
518 
519 			rval = emlxs_dfc_get_ioinfo(hba, dfc, mode);
520 
521 			break;
522 		}
523 
524 	case EMLXS_GET_LINKINFO:
525 		{
526 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
527 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
528 
529 			rval = emlxs_dfc_get_linkinfo(hba, dfc, mode);
530 
531 			break;
532 		}
533 
534 #ifdef SFCT_SUPPORT
535 	case EMLXS_GET_FCTSTAT:
536 		{
537 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
538 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
539 
540 			rval = emlxs_dfc_get_fctstat(hba, dfc, mode);
541 
542 			break;
543 		}
544 #endif /* SFCT_SUPPORT */
545 
546 	case EMLXS_READ_MEM:
547 		{
548 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
549 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
550 
551 			rval = emlxs_dfc_read_mem(hba, dfc, mode);
552 
553 			break;
554 		}
555 
556 	case EMLXS_WRITE_MEM:
557 		{
558 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
559 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
560 
561 			rval = emlxs_dfc_write_mem(hba, dfc, mode);
562 
563 			break;
564 		}
565 
566 	case EMLXS_WRITE_CTLREG:
567 		{
568 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
569 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
570 
571 			rval = emlxs_dfc_write_ctlreg(hba, dfc, mode);
572 
573 			break;
574 		}
575 
576 	case EMLXS_READ_CTLREG:
577 		{
578 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
579 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
580 
581 			rval = emlxs_dfc_read_ctlreg(hba, dfc, mode);
582 
583 			break;
584 		}
585 
586 
587 	case EMLXS_GET_EVENTINFO:
588 		{
589 			rval = emlxs_dfc_get_eventinfo(hba, dfc, mode);
590 
591 			break;
592 		}
593 
594 	case EMLXS_GET_EVENT:
595 		{
596 			rval = emlxs_dfc_get_event(hba, dfc, mode);
597 
598 			break;
599 		}
600 
601 	case EMLXS_SET_EVENT:
602 		{
603 			rval = emlxs_dfc_set_event(hba, dfc, mode);
604 
605 			break;
606 		}
607 
608 	case EMLXS_GET_REV:
609 		{
610 			rval = emlxs_dfc_get_rev(hba, dfc, mode);
611 
612 			break;
613 		}
614 
615 	case EMLXS_SEND_SCSI:
616 		{
617 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
618 		    "%s requested.", emlxs_dfc_xlate(dfc->cmd));
619 			rval = emlxs_dfc_send_scsi_fcp(hba, dfc, mode);
620 			break;
621 		}
622 
623 	case EMLXS_CREATE_VPORT:
624 		{
625 
626 			rval = emlxs_dfc_create_vport(hba, dfc, mode);
627 
628 			break;
629 		}
630 
631 	case EMLXS_DESTROY_VPORT:
632 		{
633 
634 			rval = emlxs_dfc_destroy_vport(hba, dfc, mode);
635 
636 			break;
637 		}
638 
639 	case EMLXS_GET_VPORTINFO:
640 		{
641 
642 			rval = emlxs_dfc_get_vportinfo(hba, dfc, mode);
643 
644 			break;
645 		}
646 
647 	case EMLXS_NPIV_RESOURCE:
648 		{
649 			rval = emlxs_dfc_npiv_resource(hba, dfc, mode);
650 
651 			break;
652 		}
653 
654 	case EMLXS_NPIV_TEST:
655 		{
656 			rval = emlxs_dfc_npiv_test(hba, dfc, mode);
657 
658 			break;
659 		}
660 
661 #ifdef DHCHAP_SUPPORT
662 	case EMLXS_INIT_AUTH:
663 		{
664 			rval = emlxs_dfc_init_auth(hba, dfc, mode);
665 
666 			break;
667 		}
668 
669 	case EMLXS_GET_AUTH_CFG:
670 		{
671 			rval = emlxs_dfc_get_auth_cfg(hba, dfc, mode);
672 
673 			break;
674 		}
675 
676 	case EMLXS_SET_AUTH_CFG:
677 		{
678 			rval = emlxs_dfc_set_auth_cfg(hba, dfc, mode);
679 
680 			break;
681 		}
682 
683 	case EMLXS_GET_AUTH_PASSWORD:
684 		{
685 			rval = emlxs_dfc_get_auth_pwd(hba, dfc, mode);
686 
687 			break;
688 		}
689 
690 	case EMLXS_SET_AUTH_PASSWORD:
691 		{
692 			rval = emlxs_dfc_set_auth_pwd(hba, dfc, mode);
693 
694 			break;
695 		}
696 
697 	case EMLXS_GET_AUTH_STATUS:
698 		{
699 			rval = emlxs_dfc_get_auth_status(hba, dfc, mode);
700 
701 			break;
702 		}
703 
704 	case EMLXS_GET_AUTH_CFG_TABLE:
705 		{
706 			rval = emlxs_dfc_get_auth_cfg_table(hba, dfc, mode);
707 			break;
708 		}
709 
710 	case EMLXS_GET_AUTH_KEY_TABLE:
711 		{
712 			rval = emlxs_dfc_get_auth_key_table(hba, dfc, mode);
713 			break;
714 		}
715 
716 #endif	/* DHCHAP_SUPPORT */
717 
718 #ifdef FCIO_SUPPORT
719 	case EMLXS_FCIO_CMD:
720 		rval = emlxs_fcio_manage(hba, dfc, mode);
721 		break;
722 #endif /* FCIO_SUPPORT */
723 
724 #ifdef SAN_DIAG_SUPPORT
725 	case EMLXS_SD_SET_BUCKET:
726 		rval = emlxs_dfc_sd_set_bucket(dfc, mode);
727 		break;
728 
729 	case EMLXS_SD_DESTROY_BUCKET:
730 		rval = emlxs_dfc_sd_destroy_bucket(dfc);
731 		break;
732 
733 	case EMLXS_SD_GET_BUCKET:
734 		rval = emlxs_dfc_sd_get_bucket(dfc, mode);
735 		break;
736 
737 	case EMLXS_SD_START_DATA_COLLECTION:
738 		rval = emlxs_dfc_sd_start_collection(hba, dfc, mode);
739 		break;
740 
741 	case EMLXS_SD_STOP_DATA_COLLECTION:
742 		rval = emlxs_dfc_sd_stop_collection(hba, dfc, mode);
743 		break;
744 
745 	case EMLXS_SD_RESET_DATA_COLLECTION:
746 		rval = emlxs_dfc_sd_reset_collection(hba, dfc, mode);
747 		break;
748 
749 	case EMLXS_SD_GET_DATA:
750 		rval = emlxs_dfc_sd_get_data(hba, dfc, mode);
751 		break;
752 
753 	case EMLXS_SD_SET_EVENT:
754 		rval = emlxs_dfc_sd_set_event(hba, dfc, mode);
755 		break;
756 
757 	case EMLXS_SD_GET_EVENT:
758 		rval = emlxs_dfc_sd_get_event(hba, dfc, mode);
759 		break;
760 #endif	/* SAN_DIAG_SUPPORT */
761 
762 	case EMLXS_GET_PERSIST_LINKDOWN:
763 		rval = emlxs_dfc_get_persist_linkdown(hba, dfc, mode);
764 		break;
765 
766 	case EMLXS_SET_PERSIST_LINKDOWN:
767 		rval = emlxs_dfc_set_persist_linkdown(hba, dfc, mode);
768 		break;
769 
770 	case EMLXS_GET_FCOE_FCFLIST:
771 		rval = emlxs_dfc_get_fcflist(hba, dfc, mode);
772 		break;
773 
774 	case EMLXS_SEND_MBOX4:
775 		rval = emlxs_dfc_send_mbox4(hba, dfc, mode);
776 		break;
777 
778 	case EMLXS_RD_BE_FCF:
779 		rval = emlxs_dfc_rd_be_fcf(hba, dfc, mode);
780 		break;
781 
782 	case EMLXS_SET_BE_DCBX:
783 		rval = emlxs_dfc_set_be_dcbx(hba, dfc, mode);
784 		break;
785 
786 	case EMLXS_GET_BE_DCBX:
787 		rval = emlxs_dfc_get_be_dcbx(hba, dfc, mode);
788 		break;
789 
790 	case EMLXS_GET_QOS:
791 		rval = emlxs_dfc_get_qos(hba, dfc, mode);
792 		break;
793 
794 	default:
795 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
796 		    "Unknown command received. (0x%x)", dfc->cmd);
797 		rval = DFC_ARG_INVALID;
798 
799 	}	/* switch() */
800 
801 	kmem_free(dfc, sizeof (dfc_t));
802 	return (rval);
803 
804 } /* emlxs_dfc_manage() */
805 
806 
807 #ifdef FCIO_SUPPORT
808 
809 emlxs_table_t emlxs_fcio_table[] = {
810 	{FCIO_GET_NUM_DEVS, "GET_NUM_DEVS"},
811 	{FCIO_GET_DEV_LIST, "GET_DEV_LIST"},
812 	{FCIO_GET_SYM_PNAME, "GET_SYM_PNAME"},
813 	{FCIO_GET_SYM_NNAME, "GET_SYM_NNAME"},
814 	{FCIO_SET_SYM_PNAME, "SET_SYM_PNAME"},
815 	{FCIO_SET_SYM_NNAME, "SET_SYM_NNAME"},
816 	{FCIO_GET_LOGI_PARAMS, "GET_LOGI_PARAMS"},
817 	{FCIO_DEV_LOGIN, "DEV_LOGIN"},
818 	{FCIO_DEV_LOGOUT, "DEV_LOGOUT"},
819 	{FCIO_GET_STATE, "GET_STATE"},
820 	{FCIO_DEV_REMOVE, "DEV_REMOVE"},
821 	{FCIO_GET_FCODE_REV, "GET_FCODE_REV"},
822 	{FCIO_GET_FW_REV, "GET_FW_REV"},
823 	{FCIO_GET_DUMP_SIZE, "GET_DUMP_SIZE"},
824 	{FCIO_FORCE_DUMP, "FORCE_DUMP"},
825 	{FCIO_GET_DUMP, "GET_DUMP"},
826 	{FCIO_GET_TOPOLOGY, "GET_TOPOLOGY"},
827 	{FCIO_RESET_LINK, "RESET_LINK"},
828 	{FCIO_RESET_HARD, "RESET_HARD"},
829 	{FCIO_RESET_HARD_CORE, "RESET_HARD_CORE"},
830 	{FCIO_DIAG, "DIAG"},
831 	{FCIO_NS, "NS"},
832 	{FCIO_DOWNLOAD_FW, "DOWNLOAD_FW"},
833 	{FCIO_GET_HOST_PARAMS, "GET_HOST_PARAMS"},
834 	{FCIO_LINK_STATUS, "LINK_STATUS"},
835 	{FCIO_DOWNLOAD_FCODE, "DOWNLOAD_FCODE"},
836 	{FCIO_GET_NODE_ID, "GET_NODE_ID"},
837 	{FCIO_SET_NODE_ID, "SET_NODE_ID"},
838 	{FCIO_SEND_NODE_ID, "SEND_NODE_ID"},
839 	/* {FCIO_GET_P2P_INFO, "GET_P2P_INFO"}, */
840 	{FCIO_GET_ADAPTER_ATTRIBUTES, "GET_ADAPTER_ATTRIBUTES"},
841 	{FCIO_GET_OTHER_ADAPTER_PORTS, "GET_OTHER_ADAPTER_PORTS"},
842 	{FCIO_GET_ADAPTER_PORT_ATTRIBUTES, "GET_ADAPTER_PORT_ATTRIBUTES"},
843 	{FCIO_GET_DISCOVERED_PORT_ATTRIBUTES, "GET_DISCOVERED_PORT_ATTRIBUTES"},
844 	{FCIO_GET_PORT_ATTRIBUTES, "GET_PORT_ATTRIBUTES"},
845 	{FCIO_GET_ADAPTER_PORT_STATS, "GET_ADAPTER_PORT_STATS"},
846 };	/* emlxs_fcio_table */
847 
848 
849 extern char    *
850 emlxs_fcio_xlate(uint16_t cmd)
851 {
852 	static char	buffer[32];
853 	uint32_t	i;
854 	uint32_t	count;
855 
856 	count = sizeof (emlxs_fcio_table) / sizeof (emlxs_table_t);
857 	for (i = 0; i < count; i++) {
858 		if (cmd == emlxs_fcio_table[i].code) {
859 			return (emlxs_fcio_table[i].string);
860 		}
861 	}
862 
863 	(void) sprintf(buffer, "Cmd=0x%x", cmd);
864 	return (buffer);
865 
866 } /* emlxs_fcio_xlate() */
867 
868 
869 static int32_t
870 emlxs_fcio_manage(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
871 {
872 	emlxs_port_t			*port = &PPORT;
873 	emlxs_config_t			*cfg  = &CFG;
874 	int				rval = 0;
875 	fcio_t				local_fcio;
876 	fcio_t				*fcio = &local_fcio;
877 	emlxs_vpd_t			*vpd = &VPD;
878 	fc_hba_port_attributes_t	*port_attrs;
879 	emlxs_node_t			*ndlp;
880 	uint8_t				*wwpn;
881 	uint32_t			use32 = 0;
882 
883 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: %s: requested.",
884 	    emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1));
885 
886 	if (!dfc->buf4 || !dfc->buf4_size) {
887 		EMLXS_MSGF(EMLXS_CONTEXT,
888 		    &emlxs_dfc_error_msg, "%s: %s: Null buffer4 found.",
889 		    emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1));
890 
891 		return (EFAULT);
892 	}
893 
894 	if (dfc->buf4_size < sizeof (uint32_t)) {
895 		EMLXS_MSGF(EMLXS_CONTEXT,
896 		    &emlxs_dfc_error_msg,
897 		    "%s: %s: Buffer4 too small. (size=%d)",
898 		    emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1),
899 		    dfc->buf4_size);
900 
901 		return (EFAULT);
902 	}
903 
904 	/* Map DFC to FCIO */
905 	bzero(fcio, sizeof (fcio_t));
906 	fcio->fcio_flags	= dfc->flag;
907 	fcio->fcio_cmd		= dfc->data1;
908 	fcio->fcio_cmd_flags	= dfc->data2;
909 	fcio->fcio_xfer		= dfc->data3;
910 	fcio->fcio_errno	= 0; /* dfc->buf4 on return */
911 
912 	if (dfc->buf1_size && dfc->buf1) {
913 		fcio->fcio_ilen = dfc->buf1_size;
914 		fcio->fcio_ibuf = kmem_zalloc(dfc->buf1_size, KM_SLEEP);
915 
916 		if (ddi_copyin(dfc->buf1, fcio->fcio_ibuf, fcio->fcio_ilen,
917 		    mode)) {
918 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
919 			    "%s: %s: ddi_copyin failed. (size=%d)",
920 			    emlxs_dfc_xlate(dfc->cmd),
921 			    emlxs_fcio_xlate(dfc->data1), fcio->fcio_ilen);
922 
923 			rval = EFAULT;
924 			goto done;
925 		}
926 	}
927 
928 	if (dfc->buf2_size && dfc->buf2) {
929 		fcio->fcio_olen = dfc->buf2_size;
930 		fcio->fcio_obuf = kmem_zalloc(dfc->buf2_size, KM_SLEEP);
931 
932 		if (ddi_copyin(dfc->buf2, fcio->fcio_obuf, fcio->fcio_olen,
933 		    mode)) {
934 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
935 			    "%s: %s: ddi_copyin failed. (size=%d)",
936 			    emlxs_dfc_xlate(dfc->cmd),
937 			    emlxs_fcio_xlate(dfc->data1), fcio->fcio_olen);
938 
939 			rval = EFAULT;
940 			goto done;
941 		}
942 	}
943 
944 	if (dfc->buf3_size && dfc->buf3) {
945 		fcio->fcio_alen = dfc->buf3_size;
946 		fcio->fcio_abuf = kmem_zalloc(dfc->buf3_size, KM_SLEEP);
947 
948 		if (ddi_copyin(dfc->buf3, fcio->fcio_abuf, fcio->fcio_alen,
949 		    mode)) {
950 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
951 			    "%s: %s: ddi_copyin failed. (size=%d)",
952 			    emlxs_dfc_xlate(dfc->cmd),
953 			    emlxs_fcio_xlate(dfc->data1), fcio->fcio_alen);
954 
955 			rval = EFAULT;
956 			goto done;
957 		}
958 	}
959 
960 #ifdef	_MULTI_DATAMODEL
961 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
962 		use32 = 1;
963 	}
964 #endif	/* _MULTI_DATAMODEL */
965 
966 	/* FCIO command */
967 	switch (fcio->fcio_cmd) {
968 	case FCIO_DIAG:
969 	{
970 		fc_fca_pm_t pm;
971 
972 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
973 
974 		pm.pm_cmd_len   = fcio->fcio_ilen;
975 		pm.pm_cmd_buf   = fcio->fcio_ibuf;
976 		pm.pm_data_len  = fcio->fcio_alen;
977 		pm.pm_data_buf  = fcio->fcio_abuf;
978 		pm.pm_stat_len  = fcio->fcio_olen;
979 		pm.pm_stat_buf  = fcio->fcio_obuf;
980 		pm.pm_cmd_code  = FC_PORT_DIAG;
981 		pm.pm_cmd_flags = fcio->fcio_cmd_flags;
982 
983 		rval = emlxs_fca_port_manage(port, &pm);
984 
985 		if (rval != FC_SUCCESS) {
986 			fcio->fcio_errno = rval;
987 
988 			if (rval == FC_INVALID_REQUEST) {
989 				rval = ENOTTY;
990 			} else {
991 				rval = EIO;
992 			}
993 		}
994 		if (fcio->fcio_olen > pm.pm_stat_len) {
995 			fcio->fcio_olen = pm.pm_stat_len;
996 		}
997 
998 		break;
999 	}
1000 
1001 	case FCIO_GET_HOST_PARAMS:
1002 	{
1003 		if (use32) {
1004 			fc_port_dev32_t *port_dev;
1005 			uint32_t i;
1006 
1007 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1008 			    fcio->fcio_olen != sizeof (fc_port_dev32_t)) {
1009 				rval = EINVAL;
1010 				break;
1011 			}
1012 
1013 			port_dev = (fc_port_dev32_t *)fcio->fcio_obuf;
1014 			port_dev->dev_did.port_id = port->did;
1015 			port_dev->dev_hard_addr.hard_addr =
1016 			    cfg[CFG_ASSIGN_ALPA].current;
1017 			port_dev->dev_state = port->ulp_statec;
1018 			bcopy((caddr_t)&port->wwpn,
1019 			    (caddr_t)&port_dev->dev_pwwn, 8);
1020 			bcopy((caddr_t)&port->wwnn,
1021 			    (caddr_t)&port_dev->dev_nwwn, 8);
1022 
1023 			if (hba->topology == TOPOLOGY_LOOP) {
1024 				for (i = 0; i < port->alpa_map[0]; i++) {
1025 			if (port->alpa_map[i + 1] == port->did) {
1026 				port_dev->dev_did.priv_lilp_posit =
1027 				    (uint8_t)(i & 0xff);
1028 				break;
1029 			}
1030 				}
1031 			}
1032 
1033 			port_dev->dev_type[0] = LE_SWAP32(0x00000120);
1034 			port_dev->dev_type[1] = LE_SWAP32(0x00000001);
1035 
1036 		} else {
1037 
1038 			fc_port_dev_t *port_dev;
1039 			uint32_t i;
1040 
1041 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1042 			    fcio->fcio_olen != sizeof (fc_port_dev_t)) {
1043 				rval = EINVAL;
1044 				break;
1045 			}
1046 
1047 			port_dev = (fc_port_dev_t *)fcio->fcio_obuf;
1048 			port_dev->dev_did.port_id = port->did;
1049 			port_dev->dev_hard_addr.hard_addr =
1050 			    cfg[CFG_ASSIGN_ALPA].current;
1051 			port_dev->dev_state = port->ulp_statec;
1052 			bcopy((caddr_t)&port->wwpn,
1053 			    (caddr_t)&port_dev->dev_pwwn, 8);
1054 			bcopy((caddr_t)&port->wwnn,
1055 			    (caddr_t)&port_dev->dev_nwwn, 8);
1056 
1057 			if (hba->topology == TOPOLOGY_LOOP) {
1058 				for (i = 0; i < port->alpa_map[0]; i++) {
1059 			if (port->alpa_map[i + 1] == port->did) {
1060 				port_dev->dev_did.priv_lilp_posit =
1061 				    (uint8_t)(i & 0xff);
1062 				break;
1063 			}
1064 				}
1065 			}
1066 
1067 			port_dev->dev_type[0] = LE_SWAP32(0x00000120);
1068 			port_dev->dev_type[1] = LE_SWAP32(0x00000001);
1069 		}
1070 
1071 		break;
1072 	}
1073 
1074 	case FCIO_RESET_LINK:
1075 	{
1076 		uint8_t null_wwn[8];
1077 
1078 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1079 		    fcio->fcio_ilen != 8) {
1080 			rval = EINVAL;
1081 			break;
1082 		}
1083 
1084 		bzero(null_wwn, 8);
1085 
1086 		if (bcmp((uint8_t *)fcio->fcio_ibuf, null_wwn, 8) == 0) {
1087 			rval = emlxs_fca_reset(port, FC_FCA_LINK_RESET);
1088 
1089 			if (rval != FC_SUCCESS) {
1090 				fcio->fcio_errno = rval;
1091 				rval = EIO;
1092 			}
1093 		} else {
1094 			rval = ENOTSUP;
1095 		}
1096 		break;
1097 	}
1098 
1099 	case FCIO_RESET_HARD:
1100 	case FCIO_RESET_HARD_CORE:
1101 	{
1102 		rval = emlxs_fca_reset(port, FC_FCA_RESET);
1103 
1104 		if (rval != FC_SUCCESS) {
1105 			fcio->fcio_errno = rval;
1106 			rval = EIO;
1107 		}
1108 		break;
1109 	}
1110 
1111 	case FCIO_DOWNLOAD_FW:
1112 	{
1113 		fc_fca_pm_t	pm;
1114 
1115 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1116 		    fcio->fcio_ilen == 0) {
1117 			rval = EINVAL;
1118 			break;
1119 		}
1120 
1121 		bzero((caddr_t)&pm, sizeof (pm));
1122 
1123 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
1124 		pm.pm_cmd_code  = FC_PORT_DOWNLOAD_FW;
1125 		pm.pm_data_len  = fcio->fcio_ilen;
1126 		pm.pm_data_buf  = fcio->fcio_ibuf;
1127 
1128 		rval = emlxs_fca_port_manage(port, &pm);
1129 
1130 		if (rval != FC_SUCCESS) {
1131 			fcio->fcio_errno = rval;
1132 			rval = EIO;
1133 		}
1134 		break;
1135 	}
1136 
1137 	case FCIO_GET_FW_REV:
1138 	{
1139 		fc_fca_pm_t	pm;
1140 
1141 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1142 		    fcio->fcio_olen < FC_FW_REV_SIZE) {
1143 			rval = EINVAL;
1144 			break;
1145 		}
1146 
1147 		bzero((caddr_t)&pm, sizeof (pm));
1148 
1149 		pm.pm_cmd_flags = FC_FCA_PM_READ;
1150 		pm.pm_cmd_code  = FC_PORT_GET_FW_REV;
1151 		pm.pm_data_len  = fcio->fcio_olen;
1152 		pm.pm_data_buf  = fcio->fcio_obuf;
1153 
1154 		rval = emlxs_fca_port_manage(port, &pm);
1155 
1156 		if (rval != FC_SUCCESS) {
1157 			fcio->fcio_errno = rval;
1158 			rval = EIO;
1159 		}
1160 		break;
1161 	}
1162 
1163 	case FCIO_GET_FCODE_REV:
1164 	{
1165 		fc_fca_pm_t	pm;
1166 
1167 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1168 		    fcio->fcio_olen < FC_FCODE_REV_SIZE) {
1169 			rval = EINVAL;
1170 			break;
1171 		}
1172 
1173 		bzero((caddr_t)&pm, sizeof (pm));
1174 
1175 		pm.pm_cmd_flags = FC_FCA_PM_READ;
1176 		pm.pm_cmd_code  = FC_PORT_GET_FCODE_REV;
1177 		pm.pm_data_len  = fcio->fcio_olen;
1178 		pm.pm_data_buf  = fcio->fcio_obuf;
1179 
1180 		rval = emlxs_fca_port_manage(port, &pm);
1181 
1182 		if (rval != FC_SUCCESS) {
1183 			fcio->fcio_errno = rval;
1184 			rval = EIO;
1185 		}
1186 		break;
1187 	}
1188 
1189 	case FCIO_DOWNLOAD_FCODE:
1190 	{
1191 		fc_fca_pm_t	pm;
1192 
1193 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1194 		    fcio->fcio_ilen == 0) {
1195 			rval = EINVAL;
1196 			break;
1197 		}
1198 
1199 		bzero((caddr_t)&pm, sizeof (pm));
1200 
1201 		pm.pm_cmd_flags = FC_FCA_PM_WRITE;
1202 		pm.pm_cmd_code  = FC_PORT_DOWNLOAD_FCODE;
1203 		pm.pm_data_len  = fcio->fcio_ilen;
1204 		pm.pm_data_buf  = fcio->fcio_ibuf;
1205 
1206 		rval = emlxs_fca_port_manage(port, &pm);
1207 
1208 		if (rval != FC_SUCCESS) {
1209 			fcio->fcio_errno = rval;
1210 			rval = EIO;
1211 		}
1212 		break;
1213 	}
1214 
1215 	case FCIO_GET_ADAPTER_ATTRIBUTES:
1216 	{
1217 		if (use32) {
1218 			fc_hba_adapter_attributes32_t	*hba_attrs;
1219 
1220 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1221 			    fcio->fcio_olen <
1222 			    sizeof (fc_hba_adapter_attributes32_t)) {
1223 				rval = EINVAL;
1224 				break;
1225 			}
1226 
1227 			hba_attrs =
1228 			    (fc_hba_adapter_attributes32_t *)fcio->fcio_obuf;
1229 
1230 			hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
1231 			(void) strncpy(hba_attrs->Manufacturer, "Emulex",
1232 			    sizeof (hba_attrs->Manufacturer));
1233 			(void) strncpy(hba_attrs->SerialNumber, vpd->serial_num,
1234 			    sizeof (hba_attrs->SerialNumber));
1235 			(void) strncpy(hba_attrs->Model, hba->model_info.model,
1236 			    sizeof (hba_attrs->Model));
1237 			(void) strncpy(hba_attrs->ModelDescription,
1238 			    hba->model_info.model_desc,
1239 			    sizeof (hba_attrs->ModelDescription));
1240 			bcopy((caddr_t)&port->wwnn,
1241 			    (caddr_t)&hba_attrs->NodeWWN, 8);
1242 			(void) strncpy((caddr_t)hba_attrs->NodeSymbolicName,
1243 			    (caddr_t)port->snn,
1244 			    sizeof (hba_attrs->NodeSymbolicName));
1245 			(void) sprintf(hba_attrs->HardwareVersion, "%x",
1246 			    vpd->biuRev);
1247 			(void) sprintf(hba_attrs->DriverVersion, "%s (%s)",
1248 			    emlxs_version, emlxs_revision);
1249 			(void) strncpy(hba_attrs->OptionROMVersion,
1250 			    vpd->fcode_version,
1251 			    sizeof (hba_attrs->OptionROMVersion));
1252 			(void) sprintf(hba_attrs->FirmwareVersion, "%s (%s)",
1253 			    vpd->fw_version, vpd->fw_label);
1254 			(void) strncpy(hba_attrs->DriverName, DRIVER_NAME,
1255 			    sizeof (hba_attrs->DriverName));
1256 			hba_attrs->VendorSpecificID =
1257 			    ((hba->model_info.device_id << 16) |
1258 			    PCI_VENDOR_ID_EMULEX);
1259 			hba_attrs->NumberOfPorts = hba->num_of_ports;
1260 		} else {
1261 			fc_hba_adapter_attributes_t	*hba_attrs;
1262 
1263 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1264 			    fcio->fcio_olen <
1265 			    sizeof (fc_hba_adapter_attributes_t)) {
1266 				rval = EINVAL;
1267 				break;
1268 			}
1269 
1270 			hba_attrs =
1271 			    (fc_hba_adapter_attributes_t *)fcio->fcio_obuf;
1272 
1273 			hba_attrs->version = FC_HBA_ADAPTER_ATTRIBUTES_VERSION;
1274 			(void) strncpy(hba_attrs->Manufacturer, "Emulex",
1275 			    sizeof (hba_attrs->Manufacturer));
1276 			(void) strncpy(hba_attrs->SerialNumber, vpd->serial_num,
1277 			    sizeof (hba_attrs->SerialNumber));
1278 			(void) strncpy(hba_attrs->Model, hba->model_info.model,
1279 			    sizeof (hba_attrs->Model));
1280 			(void) strncpy(hba_attrs->ModelDescription,
1281 			    hba->model_info.model_desc,
1282 			    sizeof (hba_attrs->ModelDescription));
1283 			bcopy((caddr_t)&port->wwnn,
1284 			    (caddr_t)&hba_attrs->NodeWWN, 8);
1285 			(void) strncpy((caddr_t)hba_attrs->NodeSymbolicName,
1286 			    (caddr_t)port->snn,
1287 			    sizeof (hba_attrs->NodeSymbolicName));
1288 			(void) sprintf(hba_attrs->HardwareVersion, "%x",
1289 			    vpd->biuRev);
1290 			(void) sprintf(hba_attrs->DriverVersion, "%s (%s)",
1291 			    emlxs_version, emlxs_revision);
1292 			(void) strncpy(hba_attrs->OptionROMVersion,
1293 			    vpd->fcode_version,
1294 			    sizeof (hba_attrs->OptionROMVersion));
1295 			(void) sprintf(hba_attrs->FirmwareVersion, "%s (%s)",
1296 			    vpd->fw_version, vpd->fw_label);
1297 			(void) strncpy(hba_attrs->DriverName, DRIVER_NAME,
1298 			    sizeof (hba_attrs->DriverName));
1299 			hba_attrs->VendorSpecificID =
1300 			    ((hba->model_info.device_id << 16) |
1301 			    PCI_VENDOR_ID_EMULEX);
1302 			hba_attrs->NumberOfPorts = hba->num_of_ports;
1303 		}
1304 		break;
1305 	}
1306 
1307 	case FCIO_GET_ADAPTER_PORT_ATTRIBUTES:
1308 	{
1309 		if (use32) {
1310 			fc_hba_port_attributes32_t  *port_attrs;
1311 			uint32_t value1;
1312 			uint32_t value2;
1313 
1314 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1315 			    fcio->fcio_olen <
1316 			    sizeof (fc_hba_port_attributes32_t)) {
1317 				rval = EINVAL;
1318 				break;
1319 			}
1320 
1321 			port_attrs =
1322 			    (fc_hba_port_attributes32_t *)fcio->fcio_obuf;
1323 
1324 			port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
1325 			port_attrs->lastChange = 0;
1326 			port_attrs->fp_minor   = 0;
1327 			bcopy((caddr_t)&port->wwnn,
1328 			    (caddr_t)&port_attrs->NodeWWN, 8);
1329 			bcopy((caddr_t)&port->wwpn,
1330 			    (caddr_t)&port_attrs->PortWWN, 8);
1331 
1332 			if (hba->state <= FC_LINK_DOWN) {
1333 				/* port_attrs->PortFcId   */
1334 				/* port_attrs->PortType   */
1335 				/* port_attrs->PortSpeed  */
1336 				/* port_attrs->FabricName */
1337 				port_attrs->PortState =
1338 				    FC_HBA_PORTSTATE_OFFLINE;
1339 			} else {
1340 				port_attrs->PortFcId  = port->did;
1341 				port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
1342 
1343 				if (hba->topology == TOPOLOGY_LOOP) {
1344 					port_attrs->PortType =
1345 					    FC_HBA_PORTTYPE_LPORT;
1346 				} else {
1347 					port_attrs->PortType =
1348 					    FC_HBA_PORTTYPE_NPORT;
1349 				}
1350 
1351 				ndlp = emlxs_node_find_did(port, FABRIC_DID);
1352 
1353 				if (ndlp) {
1354 					bcopy(&ndlp->nlp_portname,
1355 					    (caddr_t)&port_attrs->FabricName,
1356 					    sizeof (port_attrs->FabricName));
1357 				}
1358 
1359 				switch (hba->linkspeed) {
1360 				case 0:
1361 					port_attrs->PortSpeed =
1362 					    HBA_PORTSPEED_1GBIT;
1363 					break;
1364 				case LA_1GHZ_LINK:
1365 					port_attrs->PortSpeed =
1366 					    HBA_PORTSPEED_1GBIT;
1367 					break;
1368 				case LA_2GHZ_LINK:
1369 					port_attrs->PortSpeed =
1370 					    HBA_PORTSPEED_2GBIT;
1371 					break;
1372 				case LA_4GHZ_LINK:
1373 					port_attrs->PortSpeed =
1374 					    HBA_PORTSPEED_4GBIT;
1375 					break;
1376 				case LA_8GHZ_LINK:
1377 					port_attrs->PortSpeed =
1378 					    HBA_PORTSPEED_8GBIT;
1379 					break;
1380 				case LA_10GHZ_LINK:
1381 					port_attrs->PortSpeed =
1382 					    HBA_PORTSPEED_10GBIT;
1383 					break;
1384 				default:
1385 					port_attrs->PortSpeed =
1386 					    HBA_PORTSPEED_UNKNOWN;
1387 				}
1388 			}
1389 
1390 			port_attrs->PortSupportedClassofService =
1391 			    LE_SWAP32(FC_NS_CLASS3);
1392 			(void) strncpy((caddr_t)port_attrs->PortSymbolicName,
1393 			    (caddr_t)port->spn,
1394 			    sizeof (port_attrs->PortSymbolicName));
1395 
1396 			/* Set the hba speed limit */
1397 			if (vpd->link_speed & LMT_10GB_CAPABLE) {
1398 				port_attrs->PortSupportedSpeed |=
1399 				    FC_HBA_PORTSPEED_10GBIT;
1400 			}
1401 			if (vpd->link_speed & LMT_8GB_CAPABLE) {
1402 				port_attrs->PortSupportedSpeed |=
1403 				    FC_HBA_PORTSPEED_8GBIT;
1404 			}
1405 			if (vpd->link_speed & LMT_4GB_CAPABLE) {
1406 				port_attrs->PortSupportedSpeed |=
1407 				    FC_HBA_PORTSPEED_4GBIT;
1408 			}
1409 			if (vpd->link_speed & LMT_2GB_CAPABLE) {
1410 				port_attrs->PortSupportedSpeed |=
1411 				    FC_HBA_PORTSPEED_2GBIT;
1412 			}
1413 			if (vpd->link_speed & LMT_1GB_CAPABLE) {
1414 				port_attrs->PortSupportedSpeed |=
1415 				    FC_HBA_PORTSPEED_1GBIT;
1416 			}
1417 
1418 			value1 = 0x00000120;
1419 			value2 = 0x00000001;
1420 
1421 			bcopy((caddr_t)&value1,
1422 			    (caddr_t)&port_attrs->PortSupportedFc4Types[0], 4);
1423 			bcopy((caddr_t)&value2,
1424 			    (caddr_t)&port_attrs->PortSupportedFc4Types[4], 4);
1425 
1426 			bcopy((caddr_t)&value1,
1427 			    (caddr_t)&port_attrs->PortActiveFc4Types[0], 4);
1428 			bcopy((caddr_t)&value2,
1429 			    (caddr_t)&port_attrs->PortActiveFc4Types[4], 4);
1430 
1431 			port_attrs->PortMaxFrameSize = FF_FRAME_SIZE;
1432 			port_attrs->NumberofDiscoveredPorts =
1433 			    emlxs_nport_count(port);
1434 
1435 		} else {
1436 
1437 			fc_hba_port_attributes_t  *port_attrs;
1438 			uint32_t value1;
1439 			uint32_t value2;
1440 
1441 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1442 			    fcio->fcio_olen <
1443 			    sizeof (fc_hba_port_attributes_t)) {
1444 				rval = EINVAL;
1445 				break;
1446 			}
1447 
1448 			port_attrs =
1449 			    (fc_hba_port_attributes_t *)fcio->fcio_obuf;
1450 
1451 			port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
1452 			port_attrs->lastChange = 0;
1453 			port_attrs->fp_minor   = 0;
1454 			bcopy((caddr_t)&port->wwnn,
1455 			    (caddr_t)&port_attrs->NodeWWN, 8);
1456 			bcopy((caddr_t)&port->wwpn,
1457 			    (caddr_t)&port_attrs->PortWWN, 8);
1458 
1459 			if (hba->state <= FC_LINK_DOWN) {
1460 				/* port_attrs->PortFcId   */
1461 				/* port_attrs->PortType   */
1462 				/* port_attrs->PortSpeed  */
1463 				/* port_attrs->FabricName */
1464 				port_attrs->PortState =
1465 				    FC_HBA_PORTSTATE_OFFLINE;
1466 			} else {
1467 				port_attrs->PortFcId  = port->did;
1468 				port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
1469 
1470 				if (hba->topology == TOPOLOGY_LOOP) {
1471 					port_attrs->PortType =
1472 					    FC_HBA_PORTTYPE_LPORT;
1473 				} else {
1474 					port_attrs->PortType =
1475 					    FC_HBA_PORTTYPE_NPORT;
1476 				}
1477 
1478 				ndlp = emlxs_node_find_did(port, FABRIC_DID);
1479 
1480 				if (ndlp) {
1481 					bcopy(&ndlp->nlp_portname,
1482 					    (caddr_t)&port_attrs->FabricName,
1483 					    sizeof (port_attrs->FabricName));
1484 				}
1485 
1486 				switch (hba->linkspeed) {
1487 				case 0:
1488 					port_attrs->PortSpeed =
1489 					    HBA_PORTSPEED_1GBIT;
1490 					break;
1491 				case LA_1GHZ_LINK:
1492 					port_attrs->PortSpeed =
1493 					    HBA_PORTSPEED_1GBIT;
1494 					break;
1495 				case LA_2GHZ_LINK:
1496 					port_attrs->PortSpeed =
1497 					    HBA_PORTSPEED_2GBIT;
1498 					break;
1499 				case LA_4GHZ_LINK:
1500 					port_attrs->PortSpeed =
1501 					    HBA_PORTSPEED_4GBIT;
1502 					break;
1503 				case LA_8GHZ_LINK:
1504 					port_attrs->PortSpeed =
1505 					    HBA_PORTSPEED_8GBIT;
1506 					break;
1507 				case LA_10GHZ_LINK:
1508 					port_attrs->PortSpeed =
1509 					    HBA_PORTSPEED_10GBIT;
1510 					break;
1511 				default:
1512 					port_attrs->PortSpeed =
1513 					    HBA_PORTSPEED_UNKNOWN;
1514 				}
1515 			}
1516 
1517 			port_attrs->PortSupportedClassofService =
1518 			    LE_SWAP32(FC_NS_CLASS3);
1519 			(void) strncpy((caddr_t)port_attrs->PortSymbolicName,
1520 			    (caddr_t)port->spn,
1521 			    sizeof (port_attrs->PortSymbolicName));
1522 
1523 			/* Set the hba speed limit */
1524 			if (vpd->link_speed & LMT_10GB_CAPABLE) {
1525 				port_attrs->PortSupportedSpeed |=
1526 				    FC_HBA_PORTSPEED_10GBIT;
1527 			}
1528 			if (vpd->link_speed & LMT_8GB_CAPABLE) {
1529 				port_attrs->PortSupportedSpeed |=
1530 				    FC_HBA_PORTSPEED_8GBIT;
1531 			}
1532 			if (vpd->link_speed & LMT_4GB_CAPABLE) {
1533 				port_attrs->PortSupportedSpeed |=
1534 				    FC_HBA_PORTSPEED_4GBIT;
1535 			}
1536 			if (vpd->link_speed & LMT_2GB_CAPABLE) {
1537 				port_attrs->PortSupportedSpeed |=
1538 				    FC_HBA_PORTSPEED_2GBIT;
1539 			}
1540 			if (vpd->link_speed & LMT_1GB_CAPABLE) {
1541 				port_attrs->PortSupportedSpeed |=
1542 				    FC_HBA_PORTSPEED_1GBIT;
1543 			}
1544 
1545 			value1 = 0x00000120;
1546 			value2 = 0x00000001;
1547 
1548 			bcopy((caddr_t)&value1,
1549 			    (caddr_t)&port_attrs->PortSupportedFc4Types[0], 4);
1550 			bcopy((caddr_t)&value2,
1551 			    (caddr_t)&port_attrs->PortSupportedFc4Types[4], 4);
1552 
1553 			bcopy((caddr_t)&value1,
1554 			    (caddr_t)&port_attrs->PortActiveFc4Types[0], 4);
1555 			bcopy((caddr_t)&value2,
1556 			    (caddr_t)&port_attrs->PortActiveFc4Types[4], 4);
1557 
1558 			port_attrs->PortMaxFrameSize = FF_FRAME_SIZE;
1559 			port_attrs->NumberofDiscoveredPorts =
1560 			    emlxs_nport_count(port);
1561 		}
1562 
1563 		break;
1564 	}
1565 
1566 	case FCIO_GET_NODE_ID:
1567 	{
1568 		fc_fca_pm_t	pm;
1569 
1570 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1571 		    fcio->fcio_olen < sizeof (fc_rnid_t)) {
1572 			rval = EINVAL;
1573 			break;
1574 		}
1575 
1576 		bzero((caddr_t)&pm, sizeof (pm));
1577 
1578 		pm.pm_cmd_flags = FC_FCA_PM_READ;
1579 		pm.pm_cmd_code  = FC_PORT_GET_NODE_ID;
1580 		pm.pm_data_len  = fcio->fcio_olen;
1581 		pm.pm_data_buf  = fcio->fcio_obuf;
1582 
1583 		rval = emlxs_fca_port_manage(port, &pm);
1584 
1585 		if (rval != FC_SUCCESS) {
1586 			fcio->fcio_errno = rval;
1587 			rval = EIO;
1588 		}
1589 		break;
1590 	}
1591 
1592 	case FCIO_SET_NODE_ID:
1593 	{
1594 		fc_fca_pm_t	pm;
1595 
1596 		if (fcio->fcio_xfer != FCIO_XFER_WRITE ||
1597 		    fcio->fcio_ilen < sizeof (fc_rnid_t)) {
1598 			rval = EINVAL;
1599 			break;
1600 		}
1601 
1602 		bzero((caddr_t)&pm, sizeof (pm));
1603 
1604 		pm.pm_cmd_flags = FC_FCA_PM_READ;
1605 		pm.pm_cmd_code  = FC_PORT_SET_NODE_ID;
1606 		pm.pm_data_len  = fcio->fcio_ilen;
1607 		pm.pm_data_buf  = fcio->fcio_ibuf;
1608 
1609 		rval = emlxs_fca_port_manage(port, &pm);
1610 
1611 		if (rval != FC_SUCCESS) {
1612 			fcio->fcio_errno = rval;
1613 			rval = EIO;
1614 		}
1615 		break;
1616 	}
1617 
1618 
1619 	case FCIO_GET_NUM_DEVS:
1620 	{
1621 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1622 		    fcio->fcio_olen < sizeof (uint32_t)) {
1623 			rval = EINVAL;
1624 			break;
1625 		}
1626 
1627 		*(uint32_t *)fcio->fcio_obuf = emlxs_nport_count(port);
1628 
1629 		break;
1630 	}
1631 
1632 	case FCIO_GET_DEV_LIST:
1633 	{
1634 		if (use32) {
1635 			fc_port_dev32_t *port_dev;
1636 			uint32_t max_count;
1637 			uint32_t i;
1638 			uint32_t j;
1639 			emlxs_node_t *nlp;
1640 			uint32_t nport_count;
1641 
1642 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1643 			    fcio->fcio_alen < sizeof (uint32_t)) {
1644 				rval = EINVAL;
1645 				break;
1646 			}
1647 
1648 			port_dev = (fc_port_dev32_t *)fcio->fcio_obuf;
1649 			max_count = fcio->fcio_olen / sizeof (fc_port_dev32_t);
1650 
1651 			rw_enter(&port->node_rwlock, RW_READER);
1652 
1653 			nport_count = emlxs_nport_count(port);
1654 			*(uint32_t *)fcio->fcio_abuf = nport_count;
1655 
1656 			if (nport_count == 0) {
1657 				rw_exit(&port->node_rwlock);
1658 
1659 				fcio->fcio_errno = FC_NO_MAP;
1660 				rval = EIO;
1661 				break;
1662 			}
1663 
1664 			if (nport_count > max_count) {
1665 				rw_exit(&port->node_rwlock);
1666 
1667 				fcio->fcio_errno = FC_TOOMANY;
1668 				rval = EIO;
1669 				break;
1670 			}
1671 
1672 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1673 				nlp = port->node_table[i];
1674 				while (nlp != NULL) {
1675 				if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) {
1676 					port_dev->dev_dtype = 0;
1677 					port_dev->dev_type[0] =
1678 					    BE_SWAP32(0x00000100);
1679 					port_dev->dev_state =
1680 					    PORT_DEVICE_LOGGED_IN;
1681 					port_dev->dev_did.port_id =
1682 					    nlp->nlp_DID;
1683 					port_dev->dev_did.priv_lilp_posit = 0;
1684 					port_dev->dev_hard_addr.hard_addr = 0;
1685 
1686 	if (hba->topology == TOPOLOGY_LOOP) {
1687 		for (j = 1; j < port->alpa_map[0]; j++) {
1688 			if (nlp->nlp_DID == port->alpa_map[j]) {
1689 				port_dev->dev_did.priv_lilp_posit = j-1;
1690 				break;
1691 			}
1692 		}
1693 		port_dev->dev_hard_addr.hard_addr = nlp->nlp_DID;
1694 	}
1695 
1696 					bcopy((caddr_t)&nlp->nlp_portname,
1697 					    (caddr_t)&port_dev->dev_pwwn, 8);
1698 					bcopy((caddr_t)&nlp->nlp_nodename,
1699 					    (caddr_t)&port_dev->dev_nwwn, 8);
1700 					port_dev++;
1701 				}
1702 
1703 				nlp = (NODELIST *) nlp->nlp_list_next;
1704 				}
1705 			}
1706 			rw_exit(&port->node_rwlock);
1707 
1708 		} else {
1709 
1710 			fc_port_dev_t *port_dev;
1711 			uint32_t max_count;
1712 			uint32_t i;
1713 			uint32_t j;
1714 			emlxs_node_t *nlp;
1715 			uint32_t nport_count;
1716 
1717 			if (fcio->fcio_xfer != FCIO_XFER_READ ||
1718 			    fcio->fcio_alen < sizeof (uint32_t)) {
1719 				rval = EINVAL;
1720 				break;
1721 			}
1722 
1723 			port_dev = (fc_port_dev_t *)fcio->fcio_obuf;
1724 			max_count = fcio->fcio_olen / sizeof (fc_port_dev_t);
1725 
1726 			rw_enter(&port->node_rwlock, RW_READER);
1727 
1728 			nport_count = emlxs_nport_count(port);
1729 			*(uint32_t *)fcio->fcio_abuf = nport_count;
1730 
1731 			if (nport_count == 0) {
1732 				rw_exit(&port->node_rwlock);
1733 
1734 				fcio->fcio_errno = FC_NO_MAP;
1735 				rval = EIO;
1736 				break;
1737 			}
1738 
1739 			if (nport_count > max_count) {
1740 				rw_exit(&port->node_rwlock);
1741 
1742 				fcio->fcio_errno = FC_TOOMANY;
1743 				rval = EIO;
1744 				break;
1745 			}
1746 
1747 			for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
1748 				nlp = port->node_table[i];
1749 				while (nlp != NULL) {
1750 				if ((nlp->nlp_DID & 0xFFF000) != 0xFFF000) {
1751 					port_dev->dev_dtype = 0;
1752 					port_dev->dev_type[0] =
1753 					    BE_SWAP32(0x00000100);
1754 					port_dev->dev_state =
1755 					    PORT_DEVICE_LOGGED_IN;
1756 					port_dev->dev_did.port_id =
1757 					    nlp->nlp_DID;
1758 					port_dev->dev_did.priv_lilp_posit = 0;
1759 					port_dev->dev_hard_addr.hard_addr = 0;
1760 
1761 	if (hba->topology == TOPOLOGY_LOOP) {
1762 		for (j = 1; j < port->alpa_map[0]; j++) {
1763 			if (nlp->nlp_DID == port->alpa_map[j]) {
1764 				port_dev->dev_did.priv_lilp_posit = j-1;
1765 				break;
1766 			}
1767 		}
1768 		port_dev->dev_hard_addr.hard_addr = nlp->nlp_DID;
1769 	}
1770 
1771 					bcopy((caddr_t)&nlp->nlp_portname,
1772 					    (caddr_t)&port_dev->dev_pwwn, 8);
1773 					bcopy((caddr_t)&nlp->nlp_nodename,
1774 					    (caddr_t)&port_dev->dev_nwwn, 8);
1775 					port_dev++;
1776 				}
1777 
1778 				nlp = (NODELIST *) nlp->nlp_list_next;
1779 				}
1780 			}
1781 			rw_exit(&port->node_rwlock);
1782 		}
1783 
1784 		break;
1785 	}
1786 
1787 	case FCIO_GET_LOGI_PARAMS:
1788 	{
1789 		uint8_t null_wwn[8];
1790 
1791 		if (fcio->fcio_ilen != sizeof (la_wwn_t) ||
1792 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0 ||
1793 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0) {
1794 			rval = EINVAL;
1795 			break;
1796 		}
1797 
1798 		bzero(null_wwn, 8);
1799 		wwpn = (uint8_t *)fcio->fcio_ibuf;
1800 
1801 		if ((bcmp((caddr_t)wwpn, (caddr_t)null_wwn, 8) == 0) ||
1802 		    (bcmp((caddr_t)wwpn, (caddr_t)&port->wwpn, 8) == 0)) {
1803 			bcopy((caddr_t)&port->sparam,
1804 			    (caddr_t)fcio->fcio_obuf, fcio->fcio_olen);
1805 		} else {
1806 			ndlp = emlxs_node_find_wwpn(port, wwpn);
1807 
1808 			if (ndlp) {
1809 				bcopy((caddr_t)&ndlp->sparm,
1810 				    (caddr_t)fcio->fcio_obuf,
1811 				    fcio->fcio_olen);
1812 			} else {
1813 				rval = ENXIO;
1814 			}
1815 		}
1816 
1817 		break;
1818 	}
1819 
1820 	case FCIO_GET_STATE:
1821 	{
1822 		uint8_t null_wwn[8];
1823 		uint32_t *statep;
1824 
1825 		if (fcio->fcio_ilen != 8 ||
1826 		    fcio->fcio_olen != 4 ||
1827 		    (fcio->fcio_xfer & FCIO_XFER_WRITE) == 0 ||
1828 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
1829 			rval = EINVAL;
1830 			break;
1831 		}
1832 
1833 		bzero(null_wwn, 8);
1834 		wwpn   = (uint8_t *)fcio->fcio_ibuf;
1835 		statep = (uint32_t *)fcio->fcio_obuf;
1836 
1837 		if ((bcmp((caddr_t)wwpn, (caddr_t)null_wwn, 8) == 0) ||
1838 		    (bcmp((caddr_t)wwpn, (caddr_t)&port->wwpn, 8) == 0)) {
1839 			*statep = PORT_DEVICE_VALID;
1840 		} else {
1841 			ndlp = emlxs_node_find_wwpn(port, wwpn);
1842 
1843 			if (ndlp) {
1844 				*statep = PORT_DEVICE_VALID;
1845 			} else {
1846 				*statep = PORT_DEVICE_INVALID;
1847 			}
1848 		}
1849 
1850 		break;
1851 	}
1852 
1853 	case FCIO_GET_TOPOLOGY:
1854 	{
1855 		uint32_t *tp;
1856 
1857 		if (fcio->fcio_olen != 4 ||
1858 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
1859 			rval = EINVAL;
1860 			break;
1861 		}
1862 
1863 		tp = (uint32_t *)fcio->fcio_obuf;
1864 
1865 		if (hba->state <= FC_LINK_DOWN) {
1866 			*tp = FC_TOP_UNKNOWN;
1867 		} else {
1868 			ndlp = emlxs_node_find_did(port, FABRIC_DID);
1869 
1870 			if (hba->topology == TOPOLOGY_LOOP) {
1871 				if (ndlp) {
1872 					*tp = FC_TOP_PUBLIC_LOOP;
1873 				} else {
1874 					*tp = FC_TOP_PRIVATE_LOOP;
1875 				}
1876 			} else {
1877 				if (ndlp) {
1878 					*tp = FC_TOP_FABRIC;
1879 				} else {
1880 					*tp = FC_TOP_PT_PT;
1881 				}
1882 			}
1883 		}
1884 
1885 		break;
1886 	}
1887 
1888 	case FCIO_LINK_STATUS:
1889 	{
1890 		fc_portid_t	*portid;
1891 		fc_rls_acc_t	*rls;
1892 		fc_fca_pm_t	pm;
1893 
1894 		if (fcio->fcio_ilen != sizeof (fc_portid_t) ||
1895 		    fcio->fcio_olen != sizeof (fc_rls_acc_t) ||
1896 		    fcio->fcio_xfer != FCIO_XFER_RW) {
1897 			rval = EINVAL;
1898 			break;
1899 		}
1900 
1901 		if ((fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_FPORT) &&
1902 		    (fcio->fcio_cmd_flags != FCIO_CFLAGS_RLS_DEST_NPORT)) {
1903 			rval = EINVAL;
1904 			break;
1905 		}
1906 
1907 		portid = (fc_portid_t *)fcio->fcio_ibuf;
1908 		rls    = (fc_rls_acc_t *)fcio->fcio_obuf;
1909 
1910 		if (portid->port_id == 0 || portid->port_id == port->did) {
1911 			bzero((caddr_t)&pm, sizeof (pm));
1912 
1913 			pm.pm_cmd_flags = FC_FCA_PM_READ;
1914 			pm.pm_cmd_code  = FC_PORT_RLS;
1915 			pm.pm_data_len  = sizeof (fc_rls_acc_t);
1916 			pm.pm_data_buf  = (caddr_t)rls;
1917 
1918 			rval = emlxs_fca_port_manage(port, &pm);
1919 
1920 			if (rval != FC_SUCCESS) {
1921 				fcio->fcio_errno = rval;
1922 				rval = EIO;
1923 			}
1924 		} else {
1925 			rval = ENOTSUP;
1926 		}
1927 		break;
1928 	}
1929 
1930 	case FCIO_GET_OTHER_ADAPTER_PORTS:
1931 	{
1932 		uint32_t	index;
1933 		char		*path;
1934 
1935 		if (fcio->fcio_olen < MAXPATHLEN ||
1936 		    fcio->fcio_ilen != sizeof (uint32_t)) {
1937 			rval = EINVAL;
1938 			break;
1939 		}
1940 
1941 		index = *(uint32_t *)fcio->fcio_ibuf;
1942 		path  = (char *)fcio->fcio_obuf;
1943 
1944 		if (index > hba->vpi_max) {
1945 			fcio->fcio_errno = FC_BADPORT;
1946 			rval = EFAULT;
1947 			break;
1948 		}
1949 
1950 		(void) ddi_pathname(hba->dip, path);
1951 
1952 		break;
1953 	}
1954 
1955 	case FCIO_GET_DISCOVERED_PORT_ATTRIBUTES:
1956 	{
1957 		uint32_t index;
1958 
1959 		if (fcio->fcio_xfer != FCIO_XFER_READ ||
1960 		    fcio->fcio_ilen < sizeof (uint32_t) ||
1961 		    fcio->fcio_olen < sizeof (fc_hba_port_attributes_t)) {
1962 			rval = EINVAL;
1963 			break;
1964 		}
1965 
1966 		index = *(uint32_t *)fcio->fcio_ibuf;
1967 		ndlp  = emlxs_node_find_index(port, index, 1);
1968 
1969 		if (!ndlp) {
1970 			fcio->fcio_errno = FC_OUTOFBOUNDS;
1971 			rval = EINVAL;
1972 			break;
1973 		}
1974 
1975 		goto get_node_attrs;
1976 	}
1977 
1978 	/* Same as FCIO_GET_DISCOVERED_PORT_ATTRIBUTES */
1979 	/* except WWPN is used instead of index */
1980 	case FCIO_GET_PORT_ATTRIBUTES:
1981 	{
1982 		emlxs_node_t *ndlp2;
1983 
1984 		if ((fcio->fcio_xfer != FCIO_XFER_READ) ||
1985 		    (fcio->fcio_ilen < 8) ||
1986 		    (fcio->fcio_olen < sizeof (fc_hba_port_attributes_t))) {
1987 			rval = EINVAL;
1988 			break;
1989 		}
1990 
1991 		wwpn  = (uint8_t *)fcio->fcio_ibuf;
1992 		ndlp  = emlxs_node_find_wwpn(port, wwpn);
1993 
1994 		if (!ndlp) {
1995 			fcio->fcio_errno = FC_NOMAP;
1996 			rval = EINVAL;
1997 			break;
1998 		}
1999 
2000 		/* Filter fabric ports */
2001 		if ((ndlp->nlp_DID & 0xFFF000) == 0xFFF000) {
2002 			fcio->fcio_errno = FC_NOMAP;
2003 			rval = EINVAL;
2004 			break;
2005 		}
2006 
2007 get_node_attrs:
2008 
2009 		port_attrs = (fc_hba_port_attributes_t *)fcio->fcio_obuf;
2010 
2011 		port_attrs->version    = FC_HBA_PORT_ATTRIBUTES_VERSION;
2012 		/* port_attrs->lastChange */
2013 		/* port_attrs->fp_minor   */
2014 		bcopy((caddr_t)&ndlp->nlp_nodename,
2015 		    (caddr_t)&port_attrs->NodeWWN, 8);
2016 		bcopy((caddr_t)&ndlp->nlp_portname,
2017 		    (caddr_t)&port_attrs->PortWWN, 8);
2018 
2019 		port_attrs->PortSpeed = HBA_PORTSPEED_UNKNOWN;
2020 		port_attrs->PortType  = FC_HBA_PORTTYPE_UNKNOWN;
2021 		port_attrs->PortState = FC_HBA_PORTSTATE_OFFLINE;
2022 
2023 		if (hba->state > FC_LINK_UP) {
2024 			ndlp2 = emlxs_node_find_did(port, FABRIC_DID);
2025 
2026 			port_attrs->PortFcId  = ndlp->nlp_DID;
2027 			port_attrs->PortState = FC_HBA_PORTSTATE_ONLINE;
2028 
2029 			/* no switch */
2030 			if (!ndlp2) {
2031 				if (hba->topology == TOPOLOGY_LOOP) {
2032 					port_attrs->PortType =
2033 					    FC_HBA_PORTTYPE_LPORT;
2034 				} else {
2035 					port_attrs->PortType =
2036 					    FC_HBA_PORTTYPE_PTP;
2037 				}
2038 
2039 				/* We share a common speed */
2040 				switch (hba->linkspeed) {
2041 				case 0:
2042 					port_attrs->PortSpeed =
2043 					    HBA_PORTSPEED_1GBIT;
2044 					break;
2045 				case LA_1GHZ_LINK:
2046 					port_attrs->PortSpeed =
2047 					    HBA_PORTSPEED_1GBIT;
2048 					break;
2049 				case LA_2GHZ_LINK:
2050 					port_attrs->PortSpeed =
2051 					    HBA_PORTSPEED_2GBIT;
2052 					break;
2053 				case LA_4GHZ_LINK:
2054 					port_attrs->PortSpeed =
2055 					    HBA_PORTSPEED_4GBIT;
2056 					break;
2057 				case LA_8GHZ_LINK:
2058 					port_attrs->PortSpeed =
2059 					    HBA_PORTSPEED_8GBIT;
2060 					break;
2061 				case LA_10GHZ_LINK:
2062 					port_attrs->PortSpeed =
2063 					    HBA_PORTSPEED_10GBIT;
2064 					break;
2065 				}
2066 			}
2067 			/* public loop */
2068 			else if (hba->topology == TOPOLOGY_LOOP) {
2069 				/* Check for common area and domain */
2070 				if ((ndlp->nlp_DID & 0xFFFF00) ==
2071 				    (port->did & 0xFFFF00)) {
2072 					port_attrs->PortType =
2073 					    FC_HBA_PORTTYPE_NLPORT;
2074 
2075 					/* We share a common speed */
2076 					switch (hba->linkspeed) {
2077 					case 0:
2078 						port_attrs->PortSpeed =
2079 						    HBA_PORTSPEED_1GBIT;
2080 						break;
2081 					case LA_1GHZ_LINK:
2082 						port_attrs->PortSpeed =
2083 						    HBA_PORTSPEED_1GBIT;
2084 						break;
2085 					case LA_2GHZ_LINK:
2086 						port_attrs->PortSpeed =
2087 						    HBA_PORTSPEED_2GBIT;
2088 						break;
2089 					case LA_4GHZ_LINK:
2090 						port_attrs->PortSpeed =
2091 						    HBA_PORTSPEED_4GBIT;
2092 						break;
2093 					case LA_8GHZ_LINK:
2094 						port_attrs->PortSpeed =
2095 						    HBA_PORTSPEED_8GBIT;
2096 						break;
2097 					case LA_10GHZ_LINK:
2098 						port_attrs->PortSpeed =
2099 						    HBA_PORTSPEED_10GBIT;
2100 						break;
2101 					}
2102 				}
2103 			}
2104 		}
2105 
2106 		port_attrs->PortSupportedClassofService =
2107 		    LE_SWAP32(FC_NS_CLASS3);
2108 		/* port_attrs->PortSymbolicName		*/
2109 		/* port_attrs->PortSupportedSpeed	*/
2110 		/* port_attrs->PortSupportedFc4Types	*/
2111 		/* port_attrs->PortActiveFc4Types	*/
2112 		/* port_attrs->PortMaxFrameSize		*/
2113 		/* port_attrs->NumberofDiscoveredPorts	*/
2114 
2115 		break;
2116 	}
2117 
2118 	case FCIO_GET_SYM_PNAME:
2119 	{
2120 		if (fcio->fcio_olen < (strlen(port->spn)+1) ||
2121 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
2122 			rval = EINVAL;
2123 			break;
2124 		}
2125 
2126 		(void) strcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->spn);
2127 
2128 		break;
2129 	}
2130 
2131 	case FCIO_GET_SYM_NNAME:
2132 	{
2133 		if (fcio->fcio_olen < (strlen(port->snn)+1) ||
2134 		    (fcio->fcio_xfer & FCIO_XFER_READ) == 0) {
2135 			rval = EINVAL;
2136 			break;
2137 		}
2138 
2139 		(void) strcpy((caddr_t)fcio->fcio_obuf, (caddr_t)port->snn);
2140 
2141 		break;
2142 	}
2143 
2144 	case FCIO_FORCE_DUMP:
2145 	{
2146 		rval = emlxs_fca_reset(port, FC_FCA_CORE);
2147 
2148 		if (rval != FC_SUCCESS) {
2149 			fcio->fcio_errno = rval;
2150 			rval = EIO;
2151 			break;
2152 		}
2153 
2154 		break;
2155 	}
2156 
2157 	case FCIO_GET_DUMP_SIZE:
2158 	{
2159 		fc_fca_pm_t pm;
2160 
2161 		if (fcio->fcio_olen != sizeof (uint32_t) ||
2162 		    fcio->fcio_xfer != FCIO_XFER_READ) {
2163 			rval = EINVAL;
2164 			break;
2165 		}
2166 
2167 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
2168 
2169 		pm.pm_data_len  = fcio->fcio_olen;
2170 		pm.pm_data_buf  = fcio->fcio_obuf;
2171 		pm.pm_cmd_code  = FC_PORT_GET_DUMP_SIZE;
2172 		pm.pm_cmd_flags = FC_FCA_PM_READ;
2173 
2174 		rval = emlxs_fca_port_manage(port, &pm);
2175 
2176 		if (rval != FC_SUCCESS) {
2177 			fcio->fcio_errno = rval;
2178 
2179 			if (rval == FC_INVALID_REQUEST) {
2180 				rval = ENOTTY;
2181 			} else {
2182 				rval = EIO;
2183 			}
2184 		}
2185 
2186 		break;
2187 	}
2188 
2189 	case FCIO_GET_DUMP:
2190 	{
2191 		fc_fca_pm_t pm;
2192 		uint32_t dump_size;
2193 
2194 		if (fcio->fcio_xfer != FCIO_XFER_READ) {
2195 			rval = EINVAL;
2196 			break;
2197 		}
2198 
2199 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
2200 
2201 		pm.pm_data_len  = sizeof (uint32_t);
2202 		pm.pm_data_buf  = (caddr_t)&dump_size;
2203 		pm.pm_cmd_code  = FC_PORT_GET_DUMP_SIZE;
2204 		pm.pm_cmd_flags = FC_FCA_PM_READ;
2205 
2206 		rval = emlxs_fca_port_manage(port, &pm);
2207 
2208 		if (rval != FC_SUCCESS) {
2209 			fcio->fcio_errno = rval;
2210 
2211 			if (rval == FC_INVALID_REQUEST) {
2212 				rval = ENOTTY;
2213 			} else {
2214 				rval = EIO;
2215 			}
2216 			break;
2217 		}
2218 
2219 		if (fcio->fcio_olen != dump_size) {
2220 			fcio->fcio_errno = FC_NOMEM;
2221 			rval = EINVAL;
2222 			break;
2223 		}
2224 
2225 		bzero((caddr_t)&pm, sizeof (fc_fca_pm_t));
2226 
2227 		pm.pm_data_len  = fcio->fcio_olen;
2228 		pm.pm_data_buf  = fcio->fcio_obuf;
2229 		pm.pm_cmd_code  = FC_PORT_GET_DUMP;
2230 		pm.pm_cmd_flags = FC_FCA_PM_READ;
2231 
2232 		rval = emlxs_fca_port_manage(port, &pm);
2233 
2234 		if (rval != FC_SUCCESS) {
2235 			fcio->fcio_errno = rval;
2236 
2237 			if (rval == FC_INVALID_REQUEST) {
2238 				rval = ENOTTY;
2239 			} else {
2240 				rval = EIO;
2241 			}
2242 		}
2243 
2244 		break;
2245 	}
2246 
2247 	case FCIO_SET_SYM_PNAME:
2248 	case FCIO_SET_SYM_NNAME:
2249 	case FCIO_DEV_LOGIN:
2250 	case FCIO_DEV_LOGOUT:
2251 	case FCIO_DEV_REMOVE:
2252 	case FCIO_NS:
2253 	case FCIO_SEND_NODE_ID:
2254 	case FCIO_GET_ADAPTER_PORT_STATS:
2255 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
2256 		    "%s: Unsupported FCIO command.",
2257 		    emlxs_fcio_xlate(fcio->fcio_cmd));
2258 		rval = ENOTSUP;
2259 		break;
2260 
2261 	default:
2262 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
2263 		    "Unknown FCIO command. (0x%x)", fcio->fcio_cmd);
2264 		rval = EFAULT;
2265 
2266 	}	/* switch() */
2267 
2268 done:
2269 
2270 	if (rval != 0 && fcio->fcio_errno == 0) {
2271 		fcio->fcio_errno = FC_FAILURE;
2272 	}
2273 
2274 	if (fcio->fcio_ibuf) {
2275 		if (ddi_copyout(fcio->fcio_ibuf, dfc->buf1, fcio->fcio_ilen,
2276 		    mode)) {
2277 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2278 			    "%s: %s: ddi_copyout failed. (size=%d)",
2279 			    emlxs_dfc_xlate(dfc->cmd),
2280 			    emlxs_fcio_xlate(dfc->data1), fcio->fcio_ilen);
2281 
2282 			rval = EFAULT;
2283 		}
2284 
2285 		kmem_free(fcio->fcio_ibuf, fcio->fcio_ilen);
2286 	}
2287 
2288 	if (fcio->fcio_obuf) {
2289 		if (ddi_copyout(fcio->fcio_obuf, dfc->buf2, fcio->fcio_olen,
2290 		    mode)) {
2291 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2292 			    "%s: %s: ddi_copyout failed. (size=%d)",
2293 			    emlxs_dfc_xlate(dfc->cmd),
2294 			    emlxs_fcio_xlate(dfc->data1), fcio->fcio_olen);
2295 
2296 			rval = EFAULT;
2297 		}
2298 
2299 		kmem_free(fcio->fcio_obuf, fcio->fcio_olen);
2300 	}
2301 
2302 	if (fcio->fcio_abuf) {
2303 		if (ddi_copyout(fcio->fcio_abuf, dfc->buf3, fcio->fcio_alen,
2304 		    mode)) {
2305 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2306 			    "%s: %s: ddi_copyout failed. (size=%d)",
2307 			    emlxs_dfc_xlate(dfc->cmd),
2308 			    emlxs_fcio_xlate(dfc->data1), fcio->fcio_alen);
2309 
2310 			rval = EFAULT;
2311 		}
2312 
2313 		kmem_free(fcio->fcio_abuf, fcio->fcio_alen);
2314 	}
2315 
2316 	if (ddi_copyout((void *)&fcio->fcio_errno, (void *)dfc->buf4,
2317 	    dfc->buf4_size, mode) != 0) {
2318 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2319 		    "%s: %s: ddi_copyout failed. (size=%d)",
2320 		    emlxs_dfc_xlate(dfc->cmd), emlxs_fcio_xlate(dfc->data1),
2321 		    dfc->buf4_size);
2322 
2323 			rval = EFAULT;
2324 	}
2325 
2326 	return (rval);
2327 
2328 } /* emlxs_fcio_manage() */
2329 
2330 #endif /* FCIO_SUPPORT */
2331 
2332 
2333 static int32_t
2334 emlxs_dfc_create_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
2335 {
2336 	emlxs_port_t	*port = &PPORT;
2337 	emlxs_config_t	*cfg = &CFG;
2338 	emlxs_port_t	*vport;
2339 	emlxs_port_t	*tport;
2340 	dfc_vportinfo_t	dfc_vport;
2341 	uint32_t	vpi;
2342 	uint32_t	options;
2343 	char		name[256];
2344 	uint8_t		wwn[8];
2345 
2346 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
2347 	    emlxs_dfc_xlate(dfc->cmd));
2348 
2349 	options = dfc->data1;
2350 
2351 	if (!dfc->buf1 || !dfc->buf1_size) {
2352 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2353 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
2354 
2355 		return (DFC_ARG_NULL);
2356 	}
2357 
2358 	if (dfc->buf1_size < sizeof (dfc_vportinfo_t)) {
2359 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2360 		    "%s: Buffer1 too small. (size=%d)",
2361 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
2362 
2363 		return (DFC_ARG_TOOSMALL);
2364 	}
2365 
2366 	/* Read the dfc_vport object */
2367 	if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_vport,
2368 	    sizeof (dfc_vportinfo_t), mode) != 0) {
2369 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2370 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
2371 
2372 		return (DFC_COPYIN_ERROR);
2373 	}
2374 
2375 	if (!(options & VPORT_OPT_AUTORETRY)) {
2376 		if (!(hba->flag & FC_NPIV_ENABLED)) {
2377 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2378 			    "%s: NPIV currently not enabled.",
2379 			    emlxs_dfc_xlate(dfc->cmd));
2380 
2381 			return (DFC_NPIV_DISABLED);
2382 		}
2383 
2384 		if (!(hba->flag & FC_NPIV_SUPPORTED)) {
2385 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2386 			    "%s: NPIV currently not supported.",
2387 			    emlxs_dfc_xlate(dfc->cmd));
2388 
2389 			return (DFC_NPIV_UNSUPPORTED);
2390 		}
2391 	}
2392 
2393 	/*
2394 	 * Only the same WWNN and WWPN can be re-created
2395 	 */
2396 	bzero(wwn, 8);
2397 	if (bcmp(wwn, dfc_vport.wwpn, 8) || bcmp(wwn, dfc_vport.wwnn, 0)) {
2398 		for (vpi = 1; vpi <= hba->vpi_max; vpi++) {
2399 			vport = &VPORT(vpi);
2400 
2401 			if ((bcmp((caddr_t)&vport->wwnn,
2402 			    (caddr_t)dfc_vport.wwnn, 8) == 0) &&
2403 			    (bcmp((caddr_t)&vport->wwpn,
2404 			    (caddr_t)dfc_vport.wwpn, 8) == 0)) {
2405 				if (!(vport->flag & EMLXS_PORT_CONFIG) &&
2406 				    (vport->flag & EMLXS_PORT_BOUND)) {
2407 					dfc_vport.vpi = vpi;
2408 					break;
2409 				} else {
2410 					EMLXS_MSGF(EMLXS_CONTEXT,
2411 					    &emlxs_dfc_error_msg,
2412 					    "%s: VPI already in use.",
2413 					    emlxs_dfc_xlate(dfc->cmd));
2414 
2415 					return (DFC_ARG_INVALID);
2416 				}
2417 			}
2418 		}
2419 	}
2420 
2421 	/* else auto assign */
2422 	/* Acquire a VPI */
2423 	if (dfc_vport.vpi == 0) {
2424 		/* Auto Assign VPI */
2425 		for (vpi = 1; vpi <= hba->vpi_max; vpi++) {
2426 			vport = &VPORT(vpi);
2427 
2428 			if (!(vport->flag & EMLXS_PORT_CONFIG)) {
2429 				break;
2430 			}
2431 		}
2432 
2433 		if (vpi > hba->vpi_max) {
2434 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2435 			    "%s: Out of resources.",
2436 			    emlxs_dfc_xlate(dfc->cmd));
2437 
2438 			return (DFC_DRVRES_ERROR);
2439 		}
2440 
2441 		dfc_vport.vpi = vpi;
2442 	}
2443 
2444 	/* Establish a WWPN */
2445 	bzero(wwn, 8);
2446 	if (!(bcmp(wwn, dfc_vport.wwpn, 8))) {
2447 		/* Generate new WWPN */
2448 		bcopy((caddr_t)&hba->wwpn, (caddr_t)dfc_vport.wwpn, 8);
2449 		dfc_vport.wwpn[0] = 0x20;
2450 		dfc_vport.wwpn[1] = (uint8_t)vpi;
2451 	} else {	/* use one provided */
2452 
2453 		/* Make sure WWPN is unique */
2454 		if (tport = emlxs_vport_find_wwpn(hba, dfc_vport.wwpn)) {
2455 			if ((tport->flag & EMLXS_PORT_CONFIG) &&
2456 			    (tport->flag & EMLXS_PORT_BOUND)) {
2457 				EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2458 				    "%s: WWPN already exists. vpi=%d",
2459 				    emlxs_dfc_xlate(dfc->cmd), vpi);
2460 				return (DFC_ARG_INVALID);
2461 			}
2462 		}
2463 	}
2464 
2465 	/* Establish a WWNN */
2466 	bzero(wwn, 8);
2467 	if (!(bcmp(wwn, dfc_vport.wwnn, 8))) {
2468 		/* Generate new WWNN */
2469 		bcopy((caddr_t)&hba->wwnn, (caddr_t)dfc_vport.wwnn, 8);
2470 		dfc_vport.wwnn[0] = 0x28;
2471 		dfc_vport.wwnn[1] = (uint8_t)vpi;
2472 	}
2473 	/* else use WWNN provided */
2474 
2475 	/* Generate the symbolic node name */
2476 	if (dfc_vport.snn[0]) {
2477 		(void) strcpy(name, dfc_vport.snn);
2478 		(void) sprintf(dfc_vport.snn, "%s %s", hba->snn, name);
2479 	} else {
2480 		(void) strcpy(dfc_vport.snn, hba->snn);
2481 	}
2482 
2483 	/* Generate the symbolic port name */
2484 	if (dfc_vport.spn[0]) {
2485 		(void) strcpy(name, dfc_vport.spn);
2486 		(void) sprintf(dfc_vport.spn, "%s VPort-%d VName-%s", hba->spn,
2487 		    vpi, name);
2488 	} else {
2489 		(void) sprintf(dfc_vport.spn, "%s VPort-%d", hba->spn, vpi);
2490 	}
2491 
2492 	dfc_vport.port_id = 0;
2493 	dfc_vport.ulp_statec = FC_STATE_OFFLINE;
2494 	dfc_vport.flags = VPORT_CONFIG;
2495 
2496 	/* Set the highest configured vpi */
2497 	if (dfc_vport.vpi >= hba->vpi_high) {
2498 		hba->vpi_high = dfc_vport.vpi;
2499 	}
2500 
2501 	/* Configure the port object */
2502 	bcopy((caddr_t)dfc_vport.wwnn, (caddr_t)&vport->wwnn, 8);
2503 	bcopy((caddr_t)dfc_vport.wwpn, (caddr_t)&vport->wwpn, 8);
2504 	(void) strncpy((caddr_t)vport->snn, (caddr_t)dfc_vport.snn, 256);
2505 	(void) strncpy((caddr_t)vport->spn, (caddr_t)dfc_vport.spn, 256);
2506 	vport->flag |= (EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLE);
2507 
2508 	/* Adjust restricted flags */
2509 	vport->options &= ~EMLXS_OPT_RESTRICT_MASK;
2510 	vport->flag &= ~EMLXS_PORT_RESTRICTED;
2511 	if (options & VPORT_OPT_RESTRICT) {
2512 		vport->options |= EMLXS_OPT_RESTRICT;
2513 		vport->flag |= EMLXS_PORT_RESTRICTED;
2514 		dfc_vport.flags |= VPORT_RESTRICTED;
2515 	} else if (options & VPORT_OPT_UNRESTRICT) {
2516 		vport->options |= EMLXS_OPT_UNRESTRICT;
2517 	} else if (cfg[CFG_VPORT_RESTRICTED].current) {
2518 		vport->flag |= EMLXS_PORT_RESTRICTED;
2519 		dfc_vport.flags |= VPORT_RESTRICTED;
2520 	}
2521 #ifdef SFCT_SUPPORT
2522 	if (vport->tgt_mode) {
2523 		emlxs_fct_bind_port(vport);
2524 	}
2525 #endif /* SFCT_SUPPORT */
2526 
2527 	if (ddi_copyout((void *)&dfc_vport, (void *)dfc->buf1,
2528 	    sizeof (dfc_vportinfo_t), mode) != 0) {
2529 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2530 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
2531 
2532 		return (DFC_COPYOUT_ERROR);
2533 	}
2534 
2535 	if (vport->flag & EMLXS_PORT_BOUND) {
2536 		/*
2537 		 * The same WWNN, WWPN and VPI has been re-created.
2538 		 * Bring up the vport now!
2539 		 */
2540 		emlxs_port_online(vport);
2541 	}
2542 
2543 	return (0);
2544 
2545 } /* emlxs_dfc_create_vport() */
2546 
2547 
2548 static int32_t
2549 emlxs_dfc_destroy_vport(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
2550 {
2551 	emlxs_port_t	*port = &PPORT;
2552 	emlxs_port_t	*vport;
2553 	uint8_t		wwpn[8];
2554 	fc_packet_t	*pkt = NULL;
2555 	uint32_t	rval = 0;
2556 	ELS_PKT		*els;
2557 	char		buffer[256];
2558 
2559 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
2560 	    emlxs_dfc_xlate(dfc->cmd));
2561 
2562 	if (!dfc->buf1 || !dfc->buf1_size) {
2563 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2564 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
2565 
2566 		rval = DFC_ARG_NULL;
2567 		goto done;
2568 	}
2569 
2570 	if (dfc->buf1_size < 8) {
2571 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2572 		    "%s: Buffer1 too small. (size=%d)",
2573 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
2574 
2575 		rval = DFC_ARG_TOOSMALL;
2576 		goto done;
2577 	}
2578 
2579 	/* Read the wwn object */
2580 	if (ddi_copyin((void *)dfc->buf1, (void *)wwpn, 8, mode) != 0) {
2581 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2582 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
2583 
2584 		rval = DFC_COPYIN_ERROR;
2585 		goto done;
2586 	}
2587 
2588 	/* Make sure WWPN is unique */
2589 	vport = emlxs_vport_find_wwpn(hba, wwpn);
2590 
2591 	/* Physical does not have EMLXS_PORT_CONFIG set */
2592 	if (!vport || !(vport->flag & EMLXS_PORT_CONFIG)) {
2593 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2594 		    "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd),
2595 		    emlxs_wwn_xlate(buffer, wwpn));
2596 
2597 		rval = DFC_ARG_INVALID;
2598 		goto done;
2599 	}
2600 
2601 	if (vport->did) {
2602 		/* Fabric Logout */
2603 		if (!(pkt = emlxs_pkt_alloc(vport,
2604 		    sizeof (uint32_t) + sizeof (LOGO),
2605 		    sizeof (FCP_RSP), 0, KM_NOSLEEP))) {
2606 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2607 			    "%s: Unable to allocate packet.",
2608 			    emlxs_dfc_xlate(dfc->cmd));
2609 
2610 			rval = DFC_SYSRES_ERROR;
2611 			goto done;
2612 		}
2613 
2614 		/* Make this a polled IO */
2615 		pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
2616 		pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
2617 		pkt->pkt_comp = NULL;
2618 
2619 		pkt->pkt_tran_type = FC_PKT_EXCHANGE;
2620 		pkt->pkt_timeout = 60;
2621 
2622 		/* Build the fc header */
2623 		pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID);
2624 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
2625 		pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(vport->did);
2626 		pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
2627 		pkt->pkt_cmd_fhdr.f_ctl =
2628 		    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
2629 		pkt->pkt_cmd_fhdr.seq_id = 0;
2630 		pkt->pkt_cmd_fhdr.df_ctl = 0;
2631 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
2632 		pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
2633 		pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
2634 		pkt->pkt_cmd_fhdr.ro = 0;
2635 
2636 		/* Build the command */
2637 		els = (ELS_PKT *) pkt->pkt_cmd;
2638 		els->elsCode = 0x05;	/* LOGO */
2639 		els->un.logo.un.nPortId32 = LE_SWAP32(vport->did);
2640 		bcopy(&vport->wwpn, &els->un.logo.portName, 8);
2641 
2642 		/*
2643 		 * Just send LOGO. Don't worry about result.
2644 		 * This is just a courtesy anyway.
2645 		 */
2646 		(void) emlxs_pkt_send(pkt, 1);
2647 
2648 
2649 		/* Take the port offline */
2650 		(void) emlxs_port_offline(vport, 0xffffffff);
2651 	}
2652 
2653 	vport->flag &= ~(EMLXS_PORT_CONFIG | EMLXS_PORT_ENABLE);
2654 
2655 	rval = 0;
2656 
2657 done:
2658 
2659 	if (pkt) {
2660 		emlxs_pkt_free(pkt);
2661 	}
2662 
2663 	return (rval);
2664 
2665 } /* emlxs_dfc_destroy_vport() */
2666 
2667 
2668 static int32_t
2669 emlxs_dfc_get_vportinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
2670 {
2671 	emlxs_port_t	*port = &PPORT;
2672 	emlxs_port_t	*vport;
2673 	dfc_vportinfo_t	*dfc_vport;
2674 	dfc_vportinfo_t	*dfc_vport_list = NULL;
2675 	uint32_t	i;
2676 	uint32_t	size;
2677 	uint32_t	max_count;
2678 	uint32_t	rval = DFC_SUCCESS;
2679 
2680 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
2681 	    emlxs_dfc_xlate(dfc->cmd));
2682 
2683 	if (!dfc->buf1 || !dfc->buf1_size) {
2684 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2685 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
2686 
2687 		return (DFC_ARG_NULL);
2688 	}
2689 
2690 	size = (sizeof (dfc_vportinfo_t) * MAX_VPORTS);
2691 
2692 	if (!(dfc_vport_list =
2693 	    (dfc_vportinfo_t *)kmem_zalloc(size, KM_NOSLEEP))) {
2694 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2695 		    "%s: Unable to allocate memory.",
2696 		    emlxs_dfc_xlate(dfc->cmd));
2697 
2698 		return (DFC_SYSRES_ERROR);
2699 	}
2700 
2701 	max_count = 0;
2702 	for (i = 0; i <= hba->vpi_max; i++) {
2703 		vport = &VPORT(i);
2704 		dfc_vport = &dfc_vport_list[i];
2705 
2706 		if (!(vport->flag & EMLXS_PORT_CONFIG)) {
2707 			continue;
2708 		}
2709 
2710 		bcopy(vport->snn, dfc_vport->snn, 256);
2711 		bcopy(vport->spn, dfc_vport->spn, 256);
2712 		bcopy(&vport->wwpn, dfc_vport->wwpn, 8);
2713 		bcopy(&vport->wwnn, dfc_vport->wwnn, 8);
2714 		dfc_vport->port_id = vport->did;
2715 		dfc_vport->vpi = vport->vpi;
2716 		dfc_vport->ulp_statec = vport->ulp_statec;
2717 		dfc_vport->flags = VPORT_CONFIG;
2718 
2719 		if (vport->flag & EMLXS_PORT_ENABLE) {
2720 			dfc_vport->flags |= VPORT_ENABLED;
2721 		}
2722 
2723 		if (vport->flag & EMLXS_PORT_BOUND) {
2724 			dfc_vport->flags |= VPORT_BOUND;
2725 		}
2726 
2727 		if (vport->flag & EMLXS_PORT_IP_UP) {
2728 			dfc_vport->flags |= VPORT_IP;
2729 		}
2730 
2731 		if (vport->flag & EMLXS_PORT_RESTRICTED) {
2732 			dfc_vport->flags |= VPORT_RESTRICTED;
2733 		}
2734 
2735 		max_count++;
2736 	}
2737 
2738 	max_count *= sizeof (dfc_vportinfo_t);
2739 
2740 	if (max_count > dfc->buf1_size) {
2741 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2742 		    "%s: Buffer1 too small. (%d > %d)",
2743 		    emlxs_dfc_xlate(dfc->cmd), max_count, dfc->buf1_size);
2744 
2745 		rval = DFC_ARG_TOOSMALL;
2746 		goto done;
2747 	}
2748 
2749 	if (ddi_copyout((void *)dfc_vport_list, (void *)dfc->buf1,
2750 	    dfc->buf1_size, mode) != 0) {
2751 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2752 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
2753 
2754 		rval = DFC_COPYOUT_ERROR;
2755 		goto done;
2756 	}
2757 
2758 done:
2759 
2760 	if (dfc_vport_list) {
2761 		kmem_free(dfc_vport_list, size);
2762 	}
2763 
2764 	return (rval);
2765 
2766 } /* emlxs_dfc_get_vportinfo() */
2767 
2768 
2769 static emlxs_port_t *
2770 emlxs_vport_find_wwpn(emlxs_hba_t *hba, uint8_t *wwpn)
2771 {
2772 	emlxs_port_t	*port;
2773 	NODELIST	*nlp;
2774 	int		i, j;
2775 
2776 	for (i = 0; i <= hba->vpi_max; i++) {
2777 		port = &VPORT(i);
2778 
2779 		/* Check Local N-port, including physical port */
2780 		if (bcmp(&port->wwpn, wwpn, 8) == 0) {
2781 			return (port);
2782 		}
2783 
2784 		/* Check Remote N-port */
2785 		rw_enter(&port->node_rwlock, RW_READER);
2786 		for (j = 0; j < EMLXS_NUM_HASH_QUES; j++) {
2787 			nlp = port->node_table[j];
2788 			while (nlp != NULL) {
2789 				/* Check Local N-port */
2790 				if (bcmp(&nlp->nlp_portname, wwpn, 8) == 0) {
2791 					rw_exit(&port->node_rwlock);
2792 					return (port);
2793 				}
2794 				nlp = nlp->nlp_list_next;
2795 			}
2796 		}
2797 
2798 		rw_exit(&port->node_rwlock);
2799 	}
2800 
2801 	return (0);
2802 
2803 } /* emlxs_vport_find_wwpn() */
2804 
2805 
2806 static int32_t
2807 emlxs_dfc_npiv_resource(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
2808 {
2809 	emlxs_port_t		*port = &PPORT;
2810 	dfc_vport_resource_t	vres;
2811 	MAILBOXQ		*mbq = NULL;
2812 	MAILBOX			*mb;
2813 	uint32_t		rval = DFC_SUCCESS;
2814 
2815 	if (!dfc->buf1 || !dfc->buf1_size) {
2816 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2817 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
2818 
2819 		return (DFC_ARG_NULL);
2820 	}
2821 
2822 	if (dfc->buf1_size < sizeof (dfc_vport_resource_t)) {
2823 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2824 		    "%s: Buffer1 too small. (size=%d)",
2825 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
2826 
2827 		return (DFC_ARG_TOOSMALL);
2828 	}
2829 
2830 	bzero(&vres, sizeof (dfc_vport_resource_t));
2831 
2832 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2833 		int i;
2834 		int total_rpi;
2835 		emlxs_port_t *vport;
2836 
2837 		total_rpi = 0;
2838 		for (i = 0; i < hba->sli.sli4.VPICount; i++) {
2839 			vport = &VPORT(i);
2840 			total_rpi += vport->VPIobj.rpi_online;
2841 		}
2842 
2843 		vres.vpi_max = hba->sli.sli4.VPICount - 1;
2844 		vres.vpi_inuse = (port->VPIobj.vfip == NULL) ? 0 :
2845 		    (port->VPIobj.vfip->vpi_online - 1);
2846 		vres.rpi_max = hba->sli.sli4.RPICount;
2847 		vres.rpi_inuse = total_rpi;
2848 
2849 		if (ddi_copyout((void *)&vres, (void *)dfc->buf1,
2850 		    sizeof (dfc_vport_resource_t), mode) != 0) {
2851 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2852 			    "%s: ddi_copyout failed.",
2853 			    emlxs_dfc_xlate(dfc->cmd));
2854 
2855 			rval = DFC_COPYOUT_ERROR;
2856 		}
2857 		return (rval);
2858 	}
2859 
2860 	mbq =
2861 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
2862 
2863 	mb = (MAILBOX *) mbq;
2864 
2865 	emlxs_mb_read_config(hba, mbq);
2866 
2867 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
2868 
2869 	if (rval == MBX_TIMEOUT) {
2870 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2871 		    "%s: Mailbox timed out. cmd=%x",
2872 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
2873 
2874 		rval = DFC_TIMEOUT;
2875 		goto done;
2876 	}
2877 
2878 	if (rval) {
2879 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2880 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
2881 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
2882 
2883 		rval = DFC_IO_ERROR;
2884 		goto done;
2885 	}
2886 
2887 	vres.vpi_max = mb->un.varRdConfig.max_vpi;
2888 	vres.vpi_inuse =
2889 	    (mb->un.varRdConfig.max_vpi <=
2890 	    mb->un.varRdConfig.avail_vpi) ? 0 : mb->un.varRdConfig.max_vpi -
2891 	    mb->un.varRdConfig.avail_vpi;
2892 
2893 	vres.rpi_max = mb->un.varRdConfig.max_rpi;
2894 	vres.rpi_inuse =
2895 	    (mb->un.varRdConfig.max_rpi <=
2896 	    mb->un.varRdConfig.avail_rpi) ? 0 : mb->un.varRdConfig.max_rpi -
2897 	    mb->un.varRdConfig.avail_rpi;
2898 
2899 	if (ddi_copyout((void *)&vres, (void *)dfc->buf1,
2900 	    sizeof (dfc_vport_resource_t), mode) != 0) {
2901 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2902 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
2903 
2904 		rval = DFC_COPYOUT_ERROR;
2905 	}
2906 
2907 done:
2908 
2909 	/* Free allocated mbox memory */
2910 	if (mbq) {
2911 		kmem_free(mbq, sizeof (MAILBOXQ));
2912 	}
2913 
2914 	return (rval);
2915 
2916 } /* emlxs_dfc_npiv_resource() */
2917 
2918 
2919 static int32_t
2920 emlxs_dfc_npiv_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
2921 {
2922 	emlxs_port_t	*port = &PPORT;
2923 	emlxs_port_t	*vport = &VPORT(hba->vpi_max);
2924 	emlxs_config_t	*cfg = &CFG;
2925 	fc_packet_t	*pkt = NULL;
2926 	fc_packet_t	*pkt1 = NULL;
2927 	ELS_PKT		*els;
2928 	LS_RJT		*lsrjt;
2929 	uint32_t	checklist = 0;
2930 	uint32_t	mask = 0;
2931 	uint32_t	rval = DFC_SUCCESS;
2932 	uint8_t		wwn[8];
2933 	emlxs_vpd_t	*vpd = &VPD;
2934 	int		i;
2935 
2936 	if (!dfc->buf1 || !dfc->buf1_size) {
2937 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2938 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
2939 
2940 		return (DFC_ARG_NULL);
2941 	}
2942 
2943 	if (dfc->buf1_size < sizeof (uint32_t)) {
2944 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
2945 		    "%s: Buffer1 too small. (size=%d)",
2946 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
2947 
2948 		return (DFC_ARG_TOOSMALL);
2949 	}
2950 
2951 	if (cfg[CFG_NPIV_ENABLE].current) {
2952 		checklist |= CL_NPIV_PARM_ENABLE;
2953 	}
2954 
2955 	if (hba->sli_mode >= 3) {
2956 		checklist |= CL_SLI3_ENABLE;
2957 	}
2958 
2959 
2960 	if ((vpd->feaLevelHigh >= 0x09) || (hba->sli_mode >= 4)) {
2961 		checklist |= CL_HBA_SUPPORT_NPIV;
2962 	}
2963 
2964 
2965 	if (hba->num_of_ports <= hba->vpi_max) {
2966 		checklist |= CL_HBA_HAS_RESOURCES;
2967 	}
2968 
2969 	if (hba->state < FC_LINK_UP) {
2970 		goto done;
2971 	}
2972 
2973 	checklist |= CL_HBA_LINKUP;
2974 
2975 	if (hba->topology == TOPOLOGY_LOOP) {
2976 		goto done;
2977 	}
2978 
2979 	if (!(hba->flag & FC_FABRIC_ATTACHED)) {
2980 		goto done;
2981 	}
2982 
2983 	checklist |= CL_P2P_TOPOLOGY;
2984 
2985 	if (!(hba->flag & FC_NPIV_SUPPORTED)) {
2986 		goto done;
2987 	}
2988 
2989 	checklist |= CL_FABRIC_SUPPORTS_NPIV;
2990 
2991 	mask =
2992 	    (CL_NPIV_PARM_ENABLE | CL_SLI3_ENABLE | CL_HBA_SUPPORT_NPIV |
2993 	    CL_HBA_HAS_RESOURCES);
2994 
2995 	/*
2996 	 * Check if those four conditions are met
2997 	 */
2998 	if ((checklist & mask) != mask) {
2999 		/*
3000 		 * One or more conditions are not met
3001 		 */
3002 		goto done;
3003 	}
3004 
3005 		/* Now check if fabric have resources */
3006 	for (i = 1; i <= hba->vpi_max; i++) {
3007 			vport = &VPORT(i);
3008 		if (vport->did) {
3009 				checklist |= CL_FABRIC_HAS_RESOURCES;
3010 				goto done;
3011 			}
3012 		}
3013 
3014 	vport->vpi = hba->vpi_max;
3015 	vport->hba = hba;
3016 
3017 	if (!(pkt = emlxs_pkt_alloc(vport,
3018 	    sizeof (uint32_t) + sizeof (SERV_PARM), sizeof (FCP_RSP),
3019 	    0, KM_NOSLEEP))) {
3020 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3021 		    "Unable to allocate packet.");
3022 		goto done;
3023 	}
3024 
3025 	/* Build (FDISC) the fc header */
3026 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID);
3027 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_UNSOL_CONTROL;
3028 	pkt->pkt_cmd_fhdr.s_id = 0;
3029 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3030 	pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE;
3031 	pkt->pkt_cmd_fhdr.seq_id = 0;
3032 	pkt->pkt_cmd_fhdr.df_ctl = 0;
3033 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
3034 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
3035 	pkt->pkt_cmd_fhdr.rx_id = 0xffff;
3036 	pkt->pkt_cmd_fhdr.ro = 0;
3037 
3038 	/* Build the command (FDISC) */
3039 	els = (ELS_PKT *) pkt->pkt_cmd;
3040 	els->elsCode = 0x04;	/* FLOGI - This will be changed automatically */
3041 				/* by the drive (See emlxs_send_els()) */
3042 
3043 	/* Copy latest service parameters to payload */
3044 	bcopy((void *)&port->sparam,
3045 	    (void *)&els->un.logi, sizeof (SERV_PARM));
3046 
3047 	bcopy((caddr_t)&hba->wwnn, (caddr_t)wwn, 8);
3048 	wwn[0] = 0x28;
3049 	wwn[1] = hba->vpi_max;
3050 	bcopy((caddr_t)wwn, (caddr_t)&els->un.logi.nodeName, 8);
3051 	bcopy((caddr_t)wwn, (caddr_t)&vport->wwnn, 8);
3052 
3053 	bcopy((caddr_t)&hba->wwpn, (caddr_t)wwn, 8);
3054 	wwn[0] = 0x20;
3055 	wwn[1] = hba->vpi_max;
3056 	bcopy((caddr_t)wwn, (caddr_t)&els->un.logi.portName, 8);
3057 	bcopy((caddr_t)wwn, (caddr_t)&vport->wwpn, 8);
3058 
3059 	bcopy((void *)&els->un.logi, (void *)&vport->sparam,
3060 	    sizeof (SERV_PARM));
3061 
3062 
3063 
3064 	/* Make this a polled IO */
3065 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
3066 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
3067 	pkt->pkt_comp = NULL;
3068 
3069 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
3070 	pkt->pkt_timeout = 60;
3071 
3072 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
3073 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3074 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
3075 
3076 		goto done;
3077 	}
3078 
3079 	if (pkt->pkt_state == FC_PKT_SUCCESS) {
3080 		if (!(pkt1 = emlxs_pkt_alloc(vport,
3081 		    sizeof (uint32_t) + sizeof (LOGO), sizeof (FCP_RSP),
3082 		    0, KM_NOSLEEP))) {
3083 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3084 			    "Unable to allocate LOGO packet.");
3085 			goto free_resc;
3086 		}
3087 
3088 		/* Make this a polled IO */
3089 		pkt1->pkt_tran_flags &= ~FC_TRAN_INTR;
3090 		pkt1->pkt_tran_flags |= FC_TRAN_NO_INTR;
3091 		pkt1->pkt_comp = NULL;
3092 
3093 		pkt1->pkt_tran_type = FC_PKT_EXCHANGE;
3094 		pkt1->pkt_timeout = 60;
3095 
3096 		/* Build (LOGO) the fc header */
3097 		pkt1->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(FABRIC_DID);
3098 		pkt1->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
3099 		pkt1->pkt_cmd_fhdr.s_id =
3100 		    LE_SWAP24_LO(pkt->pkt_resp_fhdr.d_id);
3101 		pkt1->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
3102 		pkt1->pkt_cmd_fhdr.f_ctl =
3103 		    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
3104 		pkt1->pkt_cmd_fhdr.seq_id = 0;
3105 		pkt1->pkt_cmd_fhdr.df_ctl = 0;
3106 		pkt1->pkt_cmd_fhdr.seq_cnt = 0;
3107 		pkt1->pkt_cmd_fhdr.ox_id = 0xFFFF;
3108 		pkt1->pkt_cmd_fhdr.rx_id = 0xFFFF;
3109 		pkt1->pkt_cmd_fhdr.ro = 0;
3110 
3111 		/* Build the command (LOGO) */
3112 		els = (ELS_PKT *) pkt1->pkt_cmd;
3113 		els->elsCode = 0x05;	/* LOGO */
3114 		els->un.logo.un.nPortId32 =
3115 		    LE_SWAP32(pkt->pkt_resp_fhdr.d_id);
3116 		bcopy((caddr_t)&hba->wwpn, (caddr_t)wwn, 8);
3117 		wwn[0] = 0x20;
3118 		wwn[1] = hba->vpi_max;
3119 		bcopy(wwn, &els->un.logo.portName, 8);
3120 
3121 		if (emlxs_pkt_send(pkt1, 1) != FC_SUCCESS) {
3122 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3123 			    "%s: Unable to send packet.",
3124 			    emlxs_dfc_xlate(dfc->cmd));
3125 
3126 			goto free_resc;
3127 		}
3128 
3129 		if (pkt1->pkt_state != FC_PKT_SUCCESS) {
3130 			if (pkt1->pkt_state == FC_PKT_TIMEOUT) {
3131 				EMLXS_MSGF(EMLXS_CONTEXT,
3132 				    &emlxs_dfc_error_msg,
3133 				    "%s: Pkt Transport error. Pkt Timeout.",
3134 				    emlxs_dfc_xlate(dfc->cmd));
3135 			} else {
3136 				EMLXS_MSGF(EMLXS_CONTEXT,
3137 				    &emlxs_dfc_error_msg,
3138 				    "%s: Pkt Transport error. state=%x",
3139 				    emlxs_dfc_xlate(dfc->cmd),
3140 				    pkt1->pkt_state);
3141 			}
3142 			goto free_resc;
3143 		}
3144 
3145 		checklist |= CL_FABRIC_HAS_RESOURCES;
3146 	} else if (pkt->pkt_state == FC_PKT_LS_RJT) {
3147 		lsrjt = (LS_RJT *) pkt->pkt_resp;
3148 		if (lsrjt->un.b.lsRjtRsnCodeExp != LSEXP_OUT_OF_RESOURCE) {
3149 			checklist |= CL_FABRIC_HAS_RESOURCES;
3150 		}
3151 	}
3152 
3153 	/*
3154 	 * Free up default RPIs and VPI
3155 	 */
3156 free_resc:
3157 
3158 	/* Unregister all nodes */
3159 	(void) emlxs_mb_unreg_node(vport, 0, 0, 0, 0);
3160 
3161 	(void) emlxs_mb_unreg_vpi(vport);
3162 
3163 done:
3164 	if (ddi_copyout((void *)&checklist, (void *)dfc->buf1,
3165 	    sizeof (uint32_t), mode) != 0) {
3166 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3167 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3168 		rval = DFC_COPYOUT_ERROR;
3169 	}
3170 
3171 	if (pkt) {
3172 		/* Free the pkt */
3173 		emlxs_pkt_free(pkt);
3174 	}
3175 
3176 	if (pkt1) {
3177 		/* Free the pkt */
3178 		emlxs_pkt_free(pkt1);
3179 	}
3180 
3181 	return (rval);
3182 
3183 } /* emlxs_dfc_npiv_test() */
3184 
3185 
3186 static int32_t
3187 emlxs_dfc_get_rev(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3188 {
3189 	emlxs_port_t	*port = &PPORT;
3190 	uint32_t	rev;
3191 
3192 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
3193 	    emlxs_dfc_xlate(dfc->cmd));
3194 
3195 	if (!dfc->buf1 || !dfc->buf1_size) {
3196 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3197 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3198 
3199 		return (DFC_ARG_NULL);
3200 	}
3201 
3202 	if (dfc->buf1_size < sizeof (uint32_t)) {
3203 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3204 		    "%s: Buffer1 too small. (size=%d)",
3205 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3206 
3207 		return (DFC_ARG_TOOSMALL);
3208 	}
3209 
3210 	rev = DFC_REV;
3211 
3212 	if (ddi_copyout((void *)&rev, (void *)dfc->buf1, sizeof (uint32_t),
3213 	    mode) != 0) {
3214 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3215 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3216 
3217 		return (DFC_COPYOUT_ERROR);
3218 	}
3219 
3220 	return (0);
3221 
3222 } /* emlxs_dfc_get_rev() */
3223 
3224 
3225 static int32_t
3226 emlxs_dfc_get_hbainfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3227 {
3228 	emlxs_port_t	*port = &PPORT;
3229 	emlxs_vpd_t	*vpd = &VPD;
3230 	emlxs_config_t	*cfg = &CFG;
3231 	dfc_hbainfo_t	hbainfo;
3232 	NODELIST	*ndlp;
3233 	char		pathname[256];
3234 
3235 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
3236 	    emlxs_dfc_xlate(dfc->cmd));
3237 
3238 	if (!dfc->buf1 || !dfc->buf1_size) {
3239 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3240 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3241 
3242 		return (DFC_ARG_NULL);
3243 	}
3244 
3245 	if (dfc->buf1_size < sizeof (dfc_hbainfo_t)) {
3246 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3247 		    "%s: Buffer1 too small. (size=%d)",
3248 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3249 
3250 		return (DFC_ARG_TOOSMALL);
3251 	}
3252 
3253 	bzero((void *) &hbainfo, sizeof (dfc_hbainfo_t));
3254 
3255 	(void) strncpy(hbainfo.vpd_serial_num, vpd->serial_num,
3256 	    sizeof (hbainfo.vpd_serial_num));
3257 	(void) strncpy(hbainfo.vpd_part_num, vpd->part_num,
3258 	    sizeof (hbainfo.vpd_part_num));
3259 	(void) strncpy(hbainfo.vpd_port_num, vpd->port_num,
3260 	    sizeof (hbainfo.vpd_port_num));
3261 	(void) strncpy(hbainfo.vpd_eng_change, vpd->eng_change,
3262 	    sizeof (hbainfo.vpd_eng_change));
3263 	(void) strncpy(hbainfo.vpd_manufacturer, vpd->manufacturer,
3264 	    sizeof (hbainfo.vpd_manufacturer));
3265 	(void) strncpy(hbainfo.vpd_model, vpd->model,
3266 	    sizeof (hbainfo.vpd_model));
3267 	(void) strncpy(hbainfo.vpd_model_desc, vpd->model_desc,
3268 	    sizeof (hbainfo.vpd_model_desc));
3269 	(void) strncpy(hbainfo.vpd_prog_types, vpd->prog_types,
3270 	    sizeof (hbainfo.vpd_prog_types));
3271 	(void) strncpy(hbainfo.vpd_id, vpd->id, sizeof (hbainfo.vpd_id));
3272 
3273 	hbainfo.device_id = hba->model_info.device_id;
3274 	hbainfo.vendor_id =
3275 	    ddi_get32(hba->pci_acc_handle,
3276 	    (uint32_t *)(hba->pci_addr + PCI_VENDOR_ID_REGISTER)) & 0xffff;
3277 
3278 	hbainfo.ports = hba->num_of_ports;
3279 	hbainfo.port_index = vpd->port_index;
3280 
3281 	bcopy(&hba->wwnn, hbainfo.wwnn, sizeof (hbainfo.wwnn));
3282 	(void) strncpy(hbainfo.snn, port->snn, sizeof (hbainfo.snn));
3283 
3284 	bcopy(&hba->wwpn, hbainfo.wwpn, sizeof (hbainfo.wwpn));
3285 	(void) strncpy(hbainfo.spn, port->spn, sizeof (hbainfo.spn));
3286 
3287 	hbainfo.biuRev = vpd->biuRev;
3288 	hbainfo.smRev = vpd->smRev;
3289 	hbainfo.smFwRev = vpd->smFwRev;
3290 	hbainfo.endecRev = vpd->endecRev;
3291 	hbainfo.rBit = vpd->rBit;
3292 	hbainfo.fcphHigh = vpd->fcphHigh;
3293 	hbainfo.fcphLow = vpd->fcphLow;
3294 	hbainfo.feaLevelHigh = vpd->feaLevelHigh;
3295 	hbainfo.feaLevelLow = vpd->feaLevelLow;
3296 
3297 	hbainfo.kern_rev = vpd->postKernRev;
3298 	(void) strncpy(hbainfo.kern_name, vpd->postKernName,
3299 	    sizeof (hbainfo.kern_name));
3300 
3301 	hbainfo.stub_rev = vpd->opFwRev;
3302 	(void) strncpy(hbainfo.stub_name, vpd->opFwName,
3303 	    sizeof (hbainfo.stub_name));
3304 
3305 	hbainfo.sli1_rev = vpd->sli1FwRev;
3306 	(void) strncpy(hbainfo.sli1_name, vpd->sli1FwName,
3307 	    sizeof (hbainfo.sli1_name));
3308 
3309 	hbainfo.sli2_rev = vpd->sli2FwRev;
3310 	(void) strncpy(hbainfo.sli2_name, vpd->sli2FwName,
3311 	    sizeof (hbainfo.sli2_name));
3312 
3313 	hbainfo.sli3_rev = vpd->sli3FwRev;
3314 	(void) strncpy(hbainfo.sli3_name, vpd->sli3FwName,
3315 	    sizeof (hbainfo.sli3_name));
3316 
3317 	hbainfo.sli4_rev = vpd->sli4FwRev;
3318 	(void) strncpy(hbainfo.sli4_name, vpd->sli4FwName,
3319 	    sizeof (hbainfo.sli4_name));
3320 
3321 	hbainfo.sli_mode = hba->sli_mode;
3322 	hbainfo.vpi_max  = hba->vpi_max;
3323 	hbainfo.vpi_high = hba->vpi_high;
3324 	hbainfo.flags = 0;
3325 
3326 	/* Set support flags */
3327 	hbainfo.flags  = HBA_FLAG_DYN_WWN;
3328 	hbainfo.flags |= HBA_FLAG_NPIV;
3329 
3330 #ifdef DHCHAP_SUPPORT
3331 	hbainfo.flags |= HBA_FLAG_DHCHAP;
3332 
3333 	if (cfg[CFG_AUTH_E2E].current) {
3334 		hbainfo.flags |= HBA_FLAG_E2E_AUTH;
3335 	}
3336 #endif	/* DHCHAP_SUPPORT */
3337 
3338 #ifdef SAN_DIAG_SUPPORT
3339 	hbainfo.flags |= HBA_FLAG_SAN_DIAG;
3340 #endif	/* SAN_DIAG_SUPPORT */
3341 
3342 #ifdef SFCT_SUPPORT
3343 	hbainfo.flags |= HBA_FLAG_TARGET_MODE;
3344 	if (hba->tgt_mode) {
3345 		hbainfo.flags |= HBA_FLAG_TARGET_MODE_ENA;
3346 	}
3347 #endif /* SFCT_SUPPORT */
3348 
3349 	hbainfo.flags |= HBA_FLAG_FCOE;
3350 
3351 	if (! (hba->model_info.flags & EMLXS_FCOE_SUPPORTED)) {
3352 		hbainfo.flags |= HBA_FLAG_PERSISTLINK;
3353 	}
3354 
3355 	(void) strncpy(hbainfo.fcode_version, vpd->fcode_version,
3356 	    sizeof (hbainfo.fcode_version));
3357 	(void) strncpy(hbainfo.boot_version, vpd->boot_version,
3358 	    sizeof (hbainfo.boot_version));
3359 	(void) strncpy(hbainfo.fw_version, vpd->fw_version,
3360 	    sizeof (hbainfo.fw_version));
3361 	(void) strncpy(hbainfo.drv_label, emlxs_label,
3362 	    sizeof (hbainfo.drv_label));
3363 	(void) strncpy(hbainfo.drv_module, emlxs_name,
3364 	    sizeof (hbainfo.drv_module));
3365 	(void) strncpy(hbainfo.drv_name, DRIVER_NAME,
3366 	    sizeof (hbainfo.drv_name));
3367 	(void) strncpy(hbainfo.drv_version, emlxs_version,
3368 	    sizeof (hbainfo.drv_version));
3369 	(void) strncpy(hbainfo.drv_revision, emlxs_revision,
3370 	    sizeof (hbainfo.drv_revision));
3371 	(void) strncpy(hbainfo.hostname, (char *)utsname.nodename,
3372 	    sizeof (hbainfo.hostname));
3373 
3374 	(void) ddi_pathname(hba->dip, pathname);
3375 	(void) sprintf(hbainfo.os_devname, "/devices%s", pathname);
3376 
3377 	if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
3378 		hbainfo.flags |= HBA_FLAG_OFFLINE;
3379 	}
3380 
3381 	hbainfo.drv_instance = hba->ddiinst;
3382 	hbainfo.port_id = port->did;
3383 	hbainfo.port_type = HBA_PORTTYPE_UNKNOWN;
3384 
3385 #ifdef MENLO_SUPPORT
3386 	if (hba->flag & FC_MENLO_MODE) {
3387 		hbainfo.topology  = LNK_MENLO_MAINTENANCE;
3388 	} else
3389 #endif /* MENLO_SUPPORT */
3390 
3391 	if (hba->state >= FC_LINK_UP) {
3392 		ndlp = emlxs_node_find_did(port, FABRIC_DID);
3393 
3394 		if (hba->topology == TOPOLOGY_LOOP) {
3395 			if (ndlp) {
3396 				hbainfo.port_type = HBA_PORTTYPE_NLPORT;
3397 				hbainfo.topology = LNK_PUBLIC_LOOP;
3398 			} else {
3399 				hbainfo.port_type = HBA_PORTTYPE_LPORT;
3400 				hbainfo.topology = LNK_LOOP;
3401 			}
3402 
3403 			hbainfo.alpa_count = port->alpa_map[0];
3404 			bcopy((void *)&port->alpa_map[1], hbainfo.alpa_map,
3405 			    hbainfo.alpa_count);
3406 		} else {
3407 			if (ndlp) {
3408 				hbainfo.port_type = HBA_PORTTYPE_NPORT;
3409 				hbainfo.topology = LNK_FABRIC;
3410 			} else {
3411 				hbainfo.port_type = HBA_PORTTYPE_PTP;
3412 				hbainfo.topology = LNK_PT2PT;
3413 			}
3414 		}
3415 
3416 		if (ndlp) {
3417 			bcopy(&ndlp->nlp_nodename, hbainfo.fabric_wwnn,
3418 			    sizeof (hbainfo.fabric_wwnn));
3419 			bcopy(&ndlp->nlp_portname, hbainfo.fabric_wwpn,
3420 			    sizeof (hbainfo.fabric_wwpn));
3421 		}
3422 
3423 		if (hba->linkspeed == LA_2GHZ_LINK) {
3424 			hbainfo.port_speed = HBA_PORTSPEED_2GBIT;
3425 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
3426 			hbainfo.port_speed = HBA_PORTSPEED_4GBIT;
3427 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
3428 			hbainfo.port_speed = HBA_PORTSPEED_8GBIT;
3429 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
3430 			hbainfo.port_speed = HBA_PORTSPEED_10GBIT;
3431 		} else {
3432 			hbainfo.port_speed = HBA_PORTSPEED_1GBIT;
3433 		}
3434 
3435 		hbainfo.node_count = port->node_count;
3436 	}
3437 
3438 	hbainfo.hard_alpa = cfg[CFG_ASSIGN_ALPA].current;
3439 	hbainfo.supported_cos = LE_SWAP32((FC_NS_CLASS3 | FC_NS_CLASS2));
3440 
3441 	hbainfo.supported_types[0] = LE_SWAP32(0x00000120);
3442 	hbainfo.supported_types[1] = LE_SWAP32(0x00000001);
3443 
3444 	hbainfo.active_types[0] = LE_SWAP32(0x00000120);
3445 	hbainfo.active_types[1] = LE_SWAP32(0x00000001);
3446 
3447 	if (!cfg[CFG_NETWORK_ON].current) {
3448 		hbainfo.active_types[0] &= ~(LE_SWAP32(0x00000020));
3449 	}
3450 
3451 	if (vpd->link_speed & LMT_10GB_CAPABLE) {
3452 		hbainfo.supported_speeds |= FC_HBA_PORTSPEED_10GBIT;
3453 	}
3454 	if (vpd->link_speed & LMT_8GB_CAPABLE) {
3455 		hbainfo.supported_speeds |= FC_HBA_PORTSPEED_8GBIT;
3456 	}
3457 	if (vpd->link_speed & LMT_4GB_CAPABLE) {
3458 		hbainfo.supported_speeds |= FC_HBA_PORTSPEED_4GBIT;
3459 	}
3460 	if (vpd->link_speed & LMT_2GB_CAPABLE) {
3461 		hbainfo.supported_speeds |= FC_HBA_PORTSPEED_2GBIT;
3462 	}
3463 	if (vpd->link_speed & LMT_1GB_CAPABLE) {
3464 		hbainfo.supported_speeds |= FC_HBA_PORTSPEED_1GBIT;
3465 	}
3466 
3467 	hbainfo.max_frame_size = FF_FRAME_SIZE;
3468 
3469 	if (hba->bus_type == SBUS_FC) {
3470 		hbainfo.flags |= HBA_FLAG_SBUS;
3471 	}
3472 
3473 	if (hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE)) {
3474 		hbainfo.flags |= HBA_FLAG_OFFLINE;
3475 		hbainfo.port_state = HBA_PORTSTATE_UNKNOWN;
3476 	} else if (hba->flag & FC_ONLINE_MODE) {
3477 		if (hba->flag & FC_LOOPBACK_MODE) {
3478 			hbainfo.port_state = HBA_PORTSTATE_LOOPBACK;
3479 		} else if (hba->state <= FC_LINK_DOWN) {
3480 			hbainfo.port_state = HBA_PORTSTATE_LINKDOWN;
3481 		}
3482 #ifdef MENLO_SUPPORT
3483 		else if (hba->flag & FC_MENLO_MODE) {
3484 			hbainfo.port_state = HBA_PORTSTATE_LINKDOWN;
3485 		}
3486 #endif /* MENLO_SUPPORT */
3487 		else {
3488 			hbainfo.port_state = HBA_PORTSTATE_ONLINE;
3489 		}
3490 	} else {
3491 		hbainfo.flags |= HBA_FLAG_OFFLINE;
3492 
3493 		if (hba->state == FC_ERROR) {
3494 			hbainfo.port_state = HBA_PORTSTATE_ERROR;
3495 		} else {
3496 			hbainfo.port_state = HBA_PORTSTATE_OFFLINE;
3497 		}
3498 	}
3499 
3500 	hbainfo.pci_function_number = hba->pci_function_number;
3501 	hbainfo.pci_device_number = hba->pci_device_number;
3502 	hbainfo.pci_bus_number = hba->pci_bus_number;
3503 
3504 	if (ddi_copyout((void *)&hbainfo, (void *)dfc->buf1,
3505 	    sizeof (dfc_hbainfo_t), mode) != 0) {
3506 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3507 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3508 
3509 		return (DFC_COPYOUT_ERROR);
3510 	}
3511 
3512 #ifdef FMA_SUPPORT
3513 	/* Access handle validation */
3514 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
3515 	    != DDI_FM_OK) {
3516 		EMLXS_MSGF(EMLXS_CONTEXT,
3517 		    &emlxs_invalid_access_handle_msg, NULL);
3518 		return (DFC_DRV_ERROR);
3519 	}
3520 #endif  /* FMA_SUPPORT */
3521 
3522 	return (0);
3523 
3524 } /* emlxs_dfc_get_hbainfo() */
3525 
3526 
3527 
3528 static int32_t
3529 emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3530 {
3531 	emlxs_port_t	*port = &PPORT;
3532 	dfc_hbastats_t	stats;
3533 	MAILBOX		*mb = NULL;
3534 	MAILBOXQ	*mbq = NULL;
3535 	uint32_t	rval = 0;
3536 
3537 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
3538 	    emlxs_dfc_xlate(dfc->cmd));
3539 
3540 	if (!dfc->buf1 || !dfc->buf1_size) {
3541 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3542 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3543 
3544 		return (DFC_ARG_NULL);
3545 	}
3546 
3547 	if (dfc->buf1_size < sizeof (dfc_hbastats_t)) {
3548 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3549 		    "%s: Buffer1 too small. (size=%d)",
3550 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3551 
3552 		return (DFC_ARG_TOOSMALL);
3553 	}
3554 
3555 	mbq =
3556 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
3557 
3558 	mb = (MAILBOX *)mbq;
3559 
3560 	emlxs_mb_read_status(hba, mbq);
3561 
3562 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
3563 
3564 	if (rval == MBX_TIMEOUT) {
3565 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3566 		    "%s: Mailbox timed out. cmd=%x",
3567 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
3568 
3569 		rval = DFC_TIMEOUT;
3570 		goto done;
3571 	}
3572 
3573 	if (rval) {
3574 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3575 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
3576 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
3577 
3578 		rval = DFC_IO_ERROR;
3579 		goto done;
3580 	}
3581 
3582 	bzero((void *) &stats, sizeof (dfc_hbastats_t));
3583 
3584 	stats.tx_frame_cnt = mb->un.varRdStatus.xmitFrameCnt;
3585 	stats.rx_frame_cnt = mb->un.varRdStatus.rcvFrameCnt;
3586 	stats.tx_kbyte_cnt = mb->un.varRdStatus.xmitByteCnt;
3587 	stats.rx_kbyte_cnt = mb->un.varRdStatus.rcvByteCnt;
3588 	stats.tx_seq_cnt = mb->un.varRdStatus.xmitSeqCnt;
3589 	stats.rx_seq_cnt = mb->un.varRdStatus.rcvSeqCnt;
3590 	stats.orig_exch_cnt = mb->un.varRdStatus.totalOrigExchanges;
3591 	stats.resp_exch_cnt = mb->un.varRdStatus.totalRespExchanges;
3592 	stats.pbsy_cnt = mb->un.varRdStatus.rcvPbsyCnt;
3593 	stats.fbsy_cnt = mb->un.varRdStatus.rcvFbsyCnt;
3594 
3595 	emlxs_mb_read_lnk_stat(hba, mbq);
3596 
3597 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
3598 
3599 	if (rval == MBX_TIMEOUT) {
3600 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3601 		    "%s: Mailbox timed out. cmd=%x",
3602 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
3603 
3604 		rval = DFC_TIMEOUT;
3605 		goto done;
3606 	}
3607 
3608 	if (rval) {
3609 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3610 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
3611 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
3612 
3613 		rval = DFC_IO_ERROR;
3614 		goto done;
3615 	}
3616 
3617 	stats.link_failure_cnt = mb->un.varRdLnk.linkFailureCnt;
3618 	stats.loss_sync_cnt = mb->un.varRdLnk.lossSyncCnt;
3619 	stats.loss_signal_cnt = mb->un.varRdLnk.lossSignalCnt;
3620 	stats.seq_error_cnt = mb->un.varRdLnk.primSeqErrCnt;
3621 	stats.inval_tx_word_cnt = mb->un.varRdLnk.invalidXmitWord;
3622 	stats.crc_error_cnt = mb->un.varRdLnk.crcCnt;
3623 	stats.seq_timeout_cnt = mb->un.varRdLnk.primSeqTimeout;
3624 	stats.elastic_overrun_cnt = mb->un.varRdLnk.elasticOverrun;
3625 	stats.arb_timeout_cnt = mb->un.varRdLnk.arbTimeout;
3626 	stats.rx_buf_credit = mb->un.varRdLnk.rxBufCredit;
3627 	stats.rx_buf_cnt = mb->un.varRdLnk.rxBufCreditCur;
3628 	stats.tx_buf_credit = mb->un.varRdLnk.txBufCredit;
3629 	stats.tx_buf_cnt = mb->un.varRdLnk.txBufCreditCur;
3630 	stats.EOFa_cnt = mb->un.varRdLnk.EOFaCnt;
3631 	stats.EOFdti_cnt = mb->un.varRdLnk.EOFdtiCnt;
3632 	stats.EOFni_cnt = mb->un.varRdLnk.EOFniCnt;
3633 	stats.SOFf_cnt = mb->un.varRdLnk.SOFfCnt;
3634 	stats.link_event_tag = hba->link_event_tag;
3635 	stats.last_reset_time = hba->timer_tics - hba->stats.ResetTime;
3636 	stats.port_type = HBA_PORTTYPE_UNKNOWN;
3637 
3638 #ifdef MENLO_SUPPORT
3639 	if (hba->flag & FC_MENLO_MODE) {
3640 		stats.topology = LNK_MENLO_MAINTENANCE;
3641 	} else
3642 #endif /* MENLO_SUPPORT */
3643 
3644 	if (hba->state >= FC_LINK_UP) {
3645 		if (hba->topology == TOPOLOGY_LOOP) {
3646 			if (hba->flag & FC_FABRIC_ATTACHED) {
3647 				stats.port_type = HBA_PORTTYPE_NLPORT;
3648 				stats.topology = LNK_PUBLIC_LOOP;
3649 			} else {
3650 				stats.port_type = HBA_PORTTYPE_LPORT;
3651 				stats.topology = LNK_LOOP;
3652 			}
3653 		} else {
3654 			if (hba->flag & FC_FABRIC_ATTACHED) {
3655 				stats.port_type = HBA_PORTTYPE_NPORT;
3656 				stats.topology = LNK_FABRIC;
3657 			} else {
3658 				stats.port_type = HBA_PORTTYPE_PTP;
3659 				stats.topology = LNK_PT2PT;
3660 			}
3661 		}
3662 
3663 		if (hba->linkspeed == LA_2GHZ_LINK) {
3664 			stats.link_speed = HBA_PORTSPEED_2GBIT;
3665 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
3666 			stats.link_speed = HBA_PORTSPEED_4GBIT;
3667 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
3668 			stats.link_speed = HBA_PORTSPEED_8GBIT;
3669 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
3670 			stats.link_speed = HBA_PORTSPEED_10GBIT;
3671 		} else {
3672 			stats.link_speed = HBA_PORTSPEED_1GBIT;
3673 		}
3674 	}
3675 
3676 	if (ddi_copyout((void *)&stats, (void *)dfc->buf1,
3677 	    sizeof (dfc_hbastats_t), mode) != 0) {
3678 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3679 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3680 
3681 		return (DFC_COPYOUT_ERROR);
3682 	}
3683 
3684 done:
3685 
3686 	/* Free allocated mbox memory */
3687 	if (mbq) {
3688 		kmem_free(mbq, sizeof (MAILBOXQ));
3689 	}
3690 
3691 	return (rval);
3692 
3693 } /* emlxs_dfc_get_hbastats() */
3694 
3695 
3696 
3697 static int32_t
3698 emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3699 {
3700 	emlxs_port_t	*port = &PPORT;
3701 	dfc_drvstats_t	stats;
3702 	uint32_t	rval = 0;
3703 
3704 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
3705 	    emlxs_dfc_xlate(dfc->cmd));
3706 
3707 	if (!dfc->buf1 || !dfc->buf1_size) {
3708 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3709 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3710 
3711 		return (DFC_ARG_NULL);
3712 	}
3713 
3714 	bzero((void *) &stats, sizeof (dfc_drvstats_t));
3715 
3716 	stats.LinkUp = hba->stats.LinkUp;
3717 	stats.LinkDown = hba->stats.LinkDown;
3718 	stats.LinkEvent = hba->stats.LinkEvent;
3719 	stats.LinkMultiEvent = hba->stats.LinkMultiEvent;
3720 
3721 	stats.MboxIssued = hba->stats.MboxIssued;
3722 	stats.MboxCompleted = hba->stats.MboxCompleted;
3723 	stats.MboxGood = hba->stats.MboxGood;
3724 	stats.MboxError = hba->stats.MboxError;
3725 	stats.MboxBusy = hba->stats.MboxBusy;
3726 	stats.MboxInvalid = hba->stats.MboxInvalid;
3727 
3728 	stats.IocbIssued[0] = hba->stats.IocbIssued[0];
3729 	stats.IocbIssued[1] = hba->stats.IocbIssued[1];
3730 	stats.IocbIssued[2] = hba->stats.IocbIssued[2];
3731 	stats.IocbIssued[3] = hba->stats.IocbIssued[3];
3732 	stats.IocbReceived[0] = hba->stats.IocbReceived[0];
3733 	stats.IocbReceived[1] = hba->stats.IocbReceived[1];
3734 	stats.IocbReceived[2] = hba->stats.IocbReceived[2];
3735 	stats.IocbReceived[3] = hba->stats.IocbReceived[3];
3736 	stats.IocbTxPut[0] = hba->stats.IocbTxPut[0];
3737 	stats.IocbTxPut[1] = hba->stats.IocbTxPut[1];
3738 	stats.IocbTxPut[2] = hba->stats.IocbTxPut[2];
3739 	stats.IocbTxPut[3] = hba->stats.IocbTxPut[3];
3740 	stats.IocbTxGet[0] = hba->stats.IocbTxGet[0];
3741 	stats.IocbTxGet[1] = hba->stats.IocbTxGet[1];
3742 	stats.IocbTxGet[2] = hba->stats.IocbTxGet[2];
3743 	stats.IocbTxGet[3] = hba->stats.IocbTxGet[3];
3744 	stats.IocbRingFull[0] = hba->stats.IocbRingFull[0];
3745 	stats.IocbRingFull[1] = hba->stats.IocbRingFull[1];
3746 	stats.IocbRingFull[2] = hba->stats.IocbRingFull[2];
3747 	stats.IocbRingFull[3] = hba->stats.IocbRingFull[3];
3748 
3749 	stats.IntrEvent[0] = hba->stats.IntrEvent[0];
3750 	stats.IntrEvent[1] = hba->stats.IntrEvent[1];
3751 	stats.IntrEvent[2] = hba->stats.IntrEvent[2];
3752 	stats.IntrEvent[3] = hba->stats.IntrEvent[3];
3753 	stats.IntrEvent[4] = hba->stats.IntrEvent[4];
3754 	stats.IntrEvent[5] = hba->stats.IntrEvent[5];
3755 	stats.IntrEvent[6] = hba->stats.IntrEvent[6];
3756 	stats.IntrEvent[7] = hba->stats.IntrEvent[7];
3757 
3758 	stats.FcpIssued = hba->stats.FcpIssued;
3759 	stats.FcpCompleted = hba->stats.FcpCompleted;
3760 	stats.FcpGood = hba->stats.FcpGood;
3761 	stats.FcpError = hba->stats.FcpError;
3762 
3763 	stats.FcpEvent = hba->stats.FcpEvent;
3764 	stats.FcpStray = hba->stats.FcpStray;
3765 
3766 	stats.ElsEvent = hba->stats.ElsEvent;
3767 	stats.ElsStray = hba->stats.ElsStray;
3768 
3769 	stats.ElsCmdIssued = hba->stats.ElsCmdIssued;
3770 	stats.ElsCmdCompleted = hba->stats.ElsCmdCompleted;
3771 	stats.ElsCmdGood = hba->stats.ElsCmdGood;
3772 	stats.ElsCmdError = hba->stats.ElsCmdError;
3773 
3774 	stats.ElsRspIssued = hba->stats.ElsRspIssued;
3775 	stats.ElsRspCompleted = hba->stats.ElsRspCompleted;
3776 
3777 	stats.ElsRcvEvent = hba->stats.ElsRcvEvent;
3778 	stats.ElsRcvError = hba->stats.ElsRcvError;
3779 	stats.ElsRcvDropped = hba->stats.ElsRcvDropped;
3780 	stats.ElsCmdReceived = hba->stats.ElsCmdReceived;
3781 	stats.ElsRscnReceived = hba->stats.ElsRscnReceived;
3782 	stats.ElsPlogiReceived = hba->stats.ElsPlogiReceived;
3783 	stats.ElsPrliReceived = hba->stats.ElsPrliReceived;
3784 	stats.ElsPrloReceived = hba->stats.ElsPrloReceived;
3785 	stats.ElsLogoReceived = hba->stats.ElsLogoReceived;
3786 	stats.ElsAdiscReceived = hba->stats.ElsAdiscReceived;
3787 	stats.ElsGenReceived = hba->stats.ElsGenReceived;
3788 
3789 	stats.CtEvent = hba->stats.CtEvent;
3790 	stats.CtStray = hba->stats.CtStray;
3791 
3792 	stats.CtCmdIssued = hba->stats.CtCmdIssued;
3793 	stats.CtCmdCompleted = hba->stats.CtCmdCompleted;
3794 	stats.CtCmdGood = hba->stats.CtCmdGood;
3795 	stats.CtCmdError = hba->stats.CtCmdError;
3796 
3797 	stats.CtRspIssued = hba->stats.CtRspIssued;
3798 	stats.CtRspCompleted = hba->stats.CtRspCompleted;
3799 
3800 	stats.CtRcvEvent = hba->stats.CtRcvEvent;
3801 	stats.CtRcvError = hba->stats.CtRcvError;
3802 	stats.CtRcvDropped = hba->stats.CtRcvDropped;
3803 	stats.CtCmdReceived = hba->stats.CtCmdReceived;
3804 
3805 	stats.IpEvent = hba->stats.IpEvent;
3806 	stats.IpStray = hba->stats.IpStray;
3807 
3808 	stats.IpSeqIssued = hba->stats.IpSeqIssued;
3809 	stats.IpSeqCompleted = hba->stats.IpSeqCompleted;
3810 	stats.IpSeqGood = hba->stats.IpSeqGood;
3811 	stats.IpSeqError = hba->stats.IpSeqError;
3812 
3813 	stats.IpBcastIssued = hba->stats.IpBcastIssued;
3814 	stats.IpBcastCompleted = hba->stats.IpBcastCompleted;
3815 	stats.IpBcastGood = hba->stats.IpBcastGood;
3816 	stats.IpBcastError = hba->stats.IpBcastError;
3817 
3818 	stats.IpRcvEvent = hba->stats.IpRcvEvent;
3819 	stats.IpDropped = hba->stats.IpDropped;
3820 	stats.IpSeqReceived = hba->stats.IpSeqReceived;
3821 	stats.IpBcastReceived = hba->stats.IpBcastReceived;
3822 
3823 	stats.IpUbPosted = hba->stats.IpUbPosted;
3824 	stats.ElsUbPosted = hba->stats.ElsUbPosted;
3825 	stats.CtUbPosted = hba->stats.CtUbPosted;
3826 
3827 #if (DFC_REV >= 2)
3828 	stats.IocbThrottled   = hba->stats.IocbThrottled;
3829 	stats.ElsAuthReceived = hba->stats.ElsAuthReceived;
3830 #endif
3831 
3832 	if (ddi_copyout((void *)&stats, (void *)dfc->buf1, dfc->buf1_size,
3833 	    mode) != 0) {
3834 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3835 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3836 
3837 		return (DFC_COPYOUT_ERROR);
3838 	}
3839 
3840 	return (rval);
3841 
3842 } /* emlxs_dfc_get_drvstats() */
3843 
3844 
3845 extern uint32_t
3846 emlxs_set_hba_mode(emlxs_hba_t *hba, uint32_t mode)
3847 {
3848 	emlxs_port_t	*port = &PPORT;
3849 	uint32_t	i;
3850 
3851 	mutex_enter(&EMLXS_PORT_LOCK);
3852 
3853 	/* Wait if adapter is in transition */
3854 	i = 0;
3855 	while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
3856 		if (i++ > 30) {
3857 			break;
3858 		}
3859 
3860 		mutex_exit(&EMLXS_PORT_LOCK);
3861 		delay(drv_usectohz(1000000));
3862 		mutex_enter(&EMLXS_PORT_LOCK);
3863 	}
3864 
3865 	switch (mode) {
3866 	case DDI_SHOW:
3867 		break;
3868 
3869 	case DDI_ONDI:
3870 		if (hba->flag & FC_OFFLINE_MODE) {
3871 			mutex_exit(&EMLXS_PORT_LOCK);
3872 			(void) emlxs_online(hba);
3873 			mutex_enter(&EMLXS_PORT_LOCK);
3874 		}
3875 		break;
3876 
3877 
3878 		/* Killed + Restart state */
3879 	case DDI_OFFDI:
3880 		if (hba->flag & FC_ONLINE_MODE) {
3881 			mutex_exit(&EMLXS_PORT_LOCK);
3882 
3883 			(void) emlxs_offline(hba);
3884 
3885 			/* Reset with restart */
3886 			EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
3887 
3888 			mutex_enter(&EMLXS_PORT_LOCK);
3889 		} else if (hba->state < FC_INIT_START) {
3890 			mutex_exit(&EMLXS_PORT_LOCK);
3891 
3892 			/* Reset with restart */
3893 			EMLXS_SLI_HBA_RESET(hba, 1, 1, 0);
3894 
3895 			mutex_enter(&EMLXS_PORT_LOCK);
3896 		}
3897 
3898 		break;
3899 
3900 		/* Killed + Reset state */
3901 	case DDI_WARMDI:
3902 		if (hba->flag & FC_ONLINE_MODE) {
3903 			mutex_exit(&EMLXS_PORT_LOCK);
3904 
3905 			(void) emlxs_offline(hba);
3906 
3907 			/* Reset with no restart */
3908 			EMLXS_SLI_HBA_RESET(hba, 0, 0, 0);
3909 
3910 			mutex_enter(&EMLXS_PORT_LOCK);
3911 		} else if (hba->state != FC_WARM_START) {
3912 			mutex_exit(&EMLXS_PORT_LOCK);
3913 
3914 			/* Reset with no restart */
3915 			EMLXS_SLI_HBA_RESET(hba, 0, 0, 0);
3916 
3917 			mutex_enter(&EMLXS_PORT_LOCK);
3918 		}
3919 
3920 		break;
3921 
3922 		/* Killed */
3923 	case DDI_DIAGDI:
3924 		if (hba->flag & FC_ONLINE_MODE) {
3925 			mutex_exit(&EMLXS_PORT_LOCK);
3926 
3927 			(void) emlxs_offline(hba);
3928 
3929 			mutex_enter(&EMLXS_PORT_LOCK);
3930 		} else if (hba->state != FC_KILLED) {
3931 			mutex_exit(&EMLXS_PORT_LOCK);
3932 
3933 			EMLXS_SLI_HBA_KILL(hba);
3934 
3935 			mutex_enter(&EMLXS_PORT_LOCK);
3936 		}
3937 
3938 		break;
3939 
3940 	default:
3941 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3942 		    "emlxs_set_hba_mode: Invalid mode. mode%x", mode);
3943 	}
3944 
3945 	/* Wait if adapter is in transition */
3946 	i = 0;
3947 	while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
3948 		if (i++ > 30) {
3949 			break;
3950 		}
3951 
3952 		mutex_exit(&EMLXS_PORT_LOCK);
3953 		delay(drv_usectohz(1000000));
3954 		mutex_enter(&EMLXS_PORT_LOCK);
3955 	}
3956 
3957 	/* Return current state */
3958 	if (hba->flag & FC_ONLINE_MODE) {
3959 		mode = DDI_ONDI;
3960 	} else if (hba->state == FC_KILLED) {
3961 		mode = DDI_DIAGDI;
3962 	} else if (hba->state == FC_WARM_START) {
3963 		mode = DDI_WARMDI;
3964 	} else {
3965 		mode = DDI_OFFDI;
3966 	}
3967 
3968 	mutex_exit(&EMLXS_PORT_LOCK);
3969 
3970 	return (mode);
3971 
3972 } /* emlxs_set_hba_mode() */
3973 
3974 
3975 static int32_t
3976 emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3977 {
3978 	emlxs_port_t	*port = &PPORT;
3979 	int32_t		rval = 0;
3980 	int32_t		flag;
3981 
3982 	if (!dfc->buf1 || !dfc->buf1_size) {
3983 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3984 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3985 
3986 		return (DFC_ARG_NULL);
3987 	}
3988 
3989 	if (dfc->buf1_size < sizeof (uint32_t)) {
3990 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3991 		    "%s: Buffer1 too small. (size=%d)",
3992 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3993 
3994 		return (DFC_ARG_TOOSMALL);
3995 	}
3996 
3997 	flag = emlxs_set_hba_mode(hba, dfc->flag);
3998 
3999 	if (ddi_copyout((void *)&flag, (void *)dfc->buf1, sizeof (uint32_t),
4000 	    mode) != 0) {
4001 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4002 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
4003 
4004 		return (DFC_COPYOUT_ERROR);
4005 	}
4006 
4007 	return (rval);
4008 
4009 } /* emlxs_dfc_set_diag() */
4010 
4011 
4012 
4013 static int32_t
4014 emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4015 {
4016 	emlxs_port_t	*port  = &PPORT;
4017 	MAILBOX		*mb    = NULL;
4018 	MAILBOXQ	*mbq   = NULL;
4019 	uint32_t	size  = 0;
4020 	MATCHMAP	*rx_mp = NULL;
4021 	MATCHMAP	*tx_mp = NULL;
4022 	uintptr_t	lptr;
4023 	int32_t		rval  = 0;
4024 	int32_t		mbxstatus = 0;
4025 	NODELIST	*ndlp;
4026 	uint32_t	did;
4027 	uint32_t	extsize = 0;
4028 	uint8_t		*extbuf  = NULL;
4029 
4030 	if (!dfc->buf1 || !dfc->buf1_size) {
4031 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4032 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4033 
4034 		return (DFC_ARG_NULL);
4035 	}
4036 
4037 	if (!dfc->buf2 || !dfc->buf2_size) {
4038 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4039 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
4040 
4041 		return (DFC_ARG_NULL);
4042 	}
4043 
4044 	if (dfc->buf1_size > MAILBOX_CMD_BSIZE) {
4045 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4046 		    "%s: Buffer1 too large. (size=%d)",
4047 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
4048 
4049 		return (DFC_ARG_TOOBIG);
4050 	}
4051 #ifdef MBOX_EXT_SUPPORT
4052 	if (dfc->buf3_size || dfc->buf4_size) {
4053 		if (dfc->buf3_size && !dfc->buf3) {
4054 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4055 			    "%s: Null buffer3 found.",
4056 			    emlxs_dfc_xlate(dfc->cmd));
4057 
4058 			return (DFC_ARG_NULL);
4059 		}
4060 
4061 		if (dfc->buf3_size > MBOX_EXTENSION_SIZE) {
4062 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4063 			    "%s: buffer3 too large. (size=%d)",
4064 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
4065 
4066 			return (DFC_ARG_TOOBIG);
4067 		}
4068 
4069 		if (dfc->buf4_size && !dfc->buf4) {
4070 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4071 			    "%s: Null buffer4 found.",
4072 			    emlxs_dfc_xlate(dfc->cmd));
4073 
4074 			return (DFC_ARG_NULL);
4075 		}
4076 
4077 		if (dfc->buf4_size > MBOX_EXTENSION_SIZE) {
4078 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4079 			    "%s: buffer4 too large. (size=%d)",
4080 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
4081 
4082 			return (DFC_ARG_TOOBIG);
4083 		}
4084 
4085 		extsize =
4086 		    (dfc->buf3_size >
4087 		    dfc->buf4_size) ? dfc->buf3_size : dfc->buf4_size;
4088 		extbuf =
4089 		    (uint8_t *)kmem_zalloc(extsize, KM_SLEEP);
4090 
4091 		if (dfc->buf3_size) {
4092 			if (ddi_copyin((void *)dfc->buf3, (void *)extbuf,
4093 			    dfc->buf3_size, mode) != 0) {
4094 				EMLXS_MSGF(EMLXS_CONTEXT,
4095 				    &emlxs_dfc_error_msg,
4096 				    "%s: ddi_copyin mbox extension data "
4097 				    "failed.", emlxs_dfc_xlate(dfc->cmd));
4098 
4099 				rval = DFC_COPYIN_ERROR;
4100 				goto done;
4101 			}
4102 		}
4103 	}
4104 #endif /* MBOX_EXT_SUPPORT */
4105 
4106 	mbq =
4107 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
4108 
4109 	mb = (MAILBOX *) mbq;
4110 
4111 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
4112 
4113 	if (ddi_copyin((void *)dfc->buf1, (void *)mb, dfc->buf1_size,
4114 	    mode) != 0) {
4115 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4116 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
4117 
4118 		rval = DFC_COPYIN_ERROR;
4119 		goto done;
4120 	}
4121 #ifdef _LP64
4122 	if ((mb->mbxCommand == MBX_READ_SPARM) ||
4123 	    (mb->mbxCommand == MBX_READ_RPI) ||
4124 	    (mb->mbxCommand == MBX_REG_LOGIN) ||
4125 	    (mb->mbxCommand == MBX_READ_LA) ||
4126 	    (mb->mbxCommand == MBX_RUN_BIU_DIAG)) {
4127 
4128 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4129 		    "%s: Invalid mailbox command. Must use 64bit version. "
4130 		    "cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4131 
4132 		/* Must use 64 bit versions of these mbox cmds */
4133 		rval = DFC_ARG_INVALID;
4134 		goto done;
4135 	}
4136 #endif
4137 
4138 	lptr = 0;
4139 	size = 0;
4140 	switch (mb->mbxCommand) {
4141 	/* Offline only */
4142 	case MBX_CONFIG_LINK:	/* 0x07 */
4143 	case MBX_PART_SLIM:	    /* 0x08 */
4144 	case MBX_CONFIG_RING:	/* 0x09 */
4145 	case MBX_DUMP_CONTEXT:	/* 0x18 */
4146 	case MBX_RUN_DIAGS:	    /* 0x19 */
4147 	case MBX_RESTART:	    /* 0x1A */
4148 	case MBX_SET_MASK:	    /* 0x20 */
4149 	case MBX_FLASH_WR_ULA:	/* 0x98 */
4150 		if (!(hba->flag & FC_OFFLINE_MODE)) {
4151 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4152 			    "%s: Adapter not offline. cmd=%x",
4153 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4154 
4155 			rval = DFC_ONLINE_ERROR;
4156 			goto done;
4157 		}
4158 		break;
4159 
4160 	/* Online / Offline */
4161 	case MBX_UNREG_LOGIN:	/* 0x14 */
4162 		ndlp = emlxs_node_find_rpi(port, mb->un.varUnregLogin.rpi);
4163 
4164 		if (ndlp) {
4165 			did = ndlp->nlp_DID;
4166 
4167 			/* remove it */
4168 			emlxs_node_rm(port, ndlp);
4169 
4170 			/*
4171 			 * If we just unregistered the host node then
4172 			 * clear the host DID
4173 			 */
4174 			if (did == port->did) {
4175 				port->did = 0;
4176 			}
4177 		} else {
4178 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4179 			    "%s: Node not found. cmd=%x rpi=%x",
4180 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand,
4181 			    mb->un.varUnregLogin.rpi);
4182 
4183 			/* Node does not exist */
4184 			rval = DFC_ARG_INVALID;
4185 			goto done;
4186 		}
4187 
4188 		/* Send it */
4189 		break;
4190 
4191 	case MBX_UNREG_D_ID:	/* 0x23 */
4192 
4193 		did = mb->un.varRegLogin.did;
4194 
4195 		if (did == 0) {
4196 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4197 			    "%s: Node not found. cmd=%x did=%x",
4198 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4199 
4200 			rval = DFC_ARG_INVALID;
4201 			goto done;
4202 		}
4203 
4204 		if (did == 0xffffffff) {
4205 			emlxs_node_destroy_all(port);
4206 			break;
4207 		}
4208 
4209 		/* Check for base node */
4210 		if (did == BCAST_DID) {
4211 			/* just flush base node */
4212 			(void) emlxs_tx_node_flush(port, &port->node_base,
4213 			    0, 0, 0);
4214 			(void) emlxs_chipq_node_flush(port, 0, &port->node_base,
4215 			    0);
4216 
4217 			/* Return now */
4218 			rval = 0;
4219 			goto done;
4220 		}
4221 
4222 		/* Make sure the node does already exist */
4223 		ndlp = emlxs_node_find_did(port, did);
4224 
4225 		if (ndlp) {
4226 			/* remove it */
4227 			emlxs_node_rm(port, ndlp);
4228 
4229 			/*
4230 			 * If we just unregistered the host node then
4231 			 * clear the host DID
4232 			 */
4233 			if (did == port->did) {
4234 				port->did = 0;
4235 			}
4236 		} else {
4237 
4238 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4239 			    "%s: Node not found. cmd=%x did=%x",
4240 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4241 
4242 			/* Node does not exist */
4243 			rval = DFC_ARG_INVALID;
4244 			goto done;
4245 		}
4246 
4247 		/* Send it */
4248 		break;
4249 
4250 	/* Online / Offline - with DMA */
4251 	case MBX_READ_EVENT_LOG:	/* 0x38 */
4252 		lptr =
4253 		    (uintptr_t)PADDR(mb->un.varRdEvtLog.un.sp64.addrHigh,
4254 		    mb->un.varRdEvtLog.un.sp64.addrLow);
4255 		size = (int)mb->un.varRdEvtLog.un.sp64.tus.f.bdeSize;
4256 
4257 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4258 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4259 			    "%s: Invalid BDE. cmd=%x",
4260 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4261 
4262 			rval = DFC_ARG_INVALID;
4263 			goto done;
4264 		}
4265 
4266 		/* Allocate receive buffer */
4267 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4268 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4269 			    "%s: Unable to allocate receive buffer. cmd=%x",
4270 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4271 
4272 			rval = DFC_DRVRES_ERROR;
4273 			goto done;
4274 		}
4275 
4276 		mb->un.varRdEvtLog.un.sp64.addrHigh = PADDR_HI(rx_mp->phys);
4277 		mb->un.varRdEvtLog.un.sp64.addrLow = PADDR_LO(rx_mp->phys);
4278 		mb->un.varRdEvtLog.un.sp64.tus.f.bdeFlags = 0;
4279 
4280 		break;
4281 
4282 	case MBX_READ_SPARM:	/* 0x0D */
4283 	case MBX_READ_SPARM64:	/* 0x8D */
4284 		lptr =
4285 		    (uintptr_t)PADDR(mb->un.varRdSparm.un.sp64.addrHigh,
4286 		    mb->un.varRdSparm.un.sp64.addrLow);
4287 		size = (int)mb->un.varRdSparm.un.sp64.tus.f.bdeSize;
4288 
4289 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4290 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4291 			    "%s: Invalid BDE. cmd=%x",
4292 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4293 
4294 			rval = DFC_ARG_INVALID;
4295 			goto done;
4296 		}
4297 
4298 		/* Allocate receive buffer */
4299 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4300 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4301 			    "%s: Unable to allocate receive buffer. cmd=%x",
4302 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4303 
4304 			rval = DFC_DRVRES_ERROR;
4305 			goto done;
4306 		}
4307 
4308 		mb->un.varRdSparm.un.sp64.addrHigh = PADDR_HI(rx_mp->phys);
4309 		mb->un.varRdSparm.un.sp64.addrLow = PADDR_LO(rx_mp->phys);
4310 		mb->un.varRdSparm.un.sp64.tus.f.bdeFlags = 0;
4311 
4312 		break;
4313 
4314 	case MBX_READ_RPI:	/* 0x0F */
4315 	case MBX_READ_RPI64:	/* 0x8F */
4316 		lptr =
4317 		    (uintptr_t)PADDR(mb->un.varRdRPI.un.sp64.addrHigh,
4318 		    mb->un.varRdRPI.un.sp64.addrLow);
4319 		size = (int)mb->un.varRdRPI.un.sp64.tus.f.bdeSize;
4320 
4321 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4322 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4323 			    "%s: Invalid BDE. cmd=%x",
4324 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4325 
4326 			rval = DFC_ARG_INVALID;
4327 			goto done;
4328 		}
4329 
4330 		/* Allocate receive buffer */
4331 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4332 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4333 			    "%s: Unable to allocate receive buffer. cmd=%x",
4334 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4335 
4336 			rval = DFC_DRVRES_ERROR;
4337 			goto done;
4338 		}
4339 
4340 		mb->un.varRdRPI.un.sp64.addrHigh = PADDR_HI(rx_mp->phys);
4341 		mb->un.varRdRPI.un.sp64.addrLow = PADDR_LO(rx_mp->phys);
4342 		mb->un.varRdRPI.un.sp64.tus.f.bdeFlags = 0;
4343 
4344 		break;
4345 
4346 	case MBX_RUN_BIU_DIAG:	 /* 0x04 */
4347 	case MBX_RUN_BIU_DIAG64: /* 0x84 */
4348 		lptr =
4349 		    (uintptr_t)PADDR(mb->un.varBIUdiag.un.s2.xmit_bde64.
4350 		    addrHigh, mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow);
4351 		size = (int)mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize;
4352 
4353 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4354 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4355 			    "%s: Invalid xmit BDE. cmd=%x",
4356 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4357 
4358 			rval = DFC_ARG_INVALID;
4359 			goto done;
4360 		}
4361 
4362 		/* Allocate xmit buffer */
4363 		if ((tx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4364 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4365 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4366 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4367 
4368 			rval = DFC_DRVRES_ERROR;
4369 			goto done;
4370 		}
4371 
4372 		/* Initialize the xmit buffer */
4373 		if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size,
4374 		    mode) != 0) {
4375 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4376 			    "%s: ddi_copyin failed. cmd=%x",
4377 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4378 
4379 			rval = DFC_COPYIN_ERROR;
4380 			goto done;
4381 		}
4382 		EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size,
4383 		    DDI_DMA_SYNC_FORDEV);
4384 
4385 		mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
4386 		    PADDR_HI(tx_mp->phys);
4387 		mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
4388 		    PADDR_LO(tx_mp->phys);
4389 		mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0;
4390 
4391 		/* Initialize the receive buffer */
4392 		lptr =
4393 		    (uintptr_t)PADDR(mb->un.varBIUdiag.un.s2.rcv_bde64.
4394 		    addrHigh, mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow);
4395 		size = (int)mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize;
4396 
4397 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4398 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4399 			    "%s: Invalid rcv BDE. cmd=%x",
4400 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4401 
4402 			rval = DFC_ARG_INVALID;
4403 			goto done;
4404 		}
4405 
4406 		/* Allocate receive buffer */
4407 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4408 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4409 			    "%s: Unable to allocate receive buffer. cmd=%x",
4410 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4411 
4412 			rval = DFC_DRVRES_ERROR;
4413 			goto done;
4414 		}
4415 
4416 		mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
4417 		    PADDR_HI(rx_mp->phys);
4418 		mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
4419 		    PADDR_LO(rx_mp->phys);
4420 		mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeFlags = 0;
4421 
4422 		break;
4423 
4424 	case MBX_REG_LOGIN:	/* 0x13 */
4425 	case MBX_REG_LOGIN64:	/* 0x93 */
4426 
4427 		did = mb->un.varRegLogin.did;
4428 
4429 		/* Check for invalid node ids to register */
4430 		if (did == 0 || (did & 0xff000000)) {
4431 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4432 			    "%s: Invalid node id. cmd=%x did=%x",
4433 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4434 
4435 			rval = DFC_ARG_INVALID;
4436 			goto done;
4437 		}
4438 
4439 		/* Check if the node limit has been reached */
4440 		if (port->node_count >= hba->max_nodes) {
4441 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4442 			    "%s: Too many nodes. cmd=%x",
4443 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4444 
4445 			rval = DFC_HBARES_ERROR;
4446 			goto done;
4447 		}
4448 
4449 		lptr =
4450 		    (uintptr_t)PADDR(mb->un.varRegLogin.un.sp64.addrHigh,
4451 		    mb->un.varRegLogin.un.sp64.addrLow);
4452 		size = (int)mb->un.varRegLogin.un.sp64.tus.f.bdeSize;
4453 
4454 		if (!lptr || (size > MEM_BUF_SIZE)) {
4455 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4456 			    "%s: Invalid BDE. cmd=%x",
4457 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4458 
4459 			rval = DFC_ARG_INVALID;
4460 			goto done;
4461 		}
4462 
4463 		/* Allocate xmit buffer */
4464 		if ((tx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4465 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4466 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4467 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4468 
4469 			rval = DFC_DRVRES_ERROR;
4470 			goto done;
4471 		}
4472 
4473 		/* Initialize the xmit buffer */
4474 		if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size,
4475 		    mode) != 0) {
4476 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4477 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4478 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4479 
4480 			rval = DFC_COPYIN_ERROR;
4481 			goto done;
4482 		}
4483 		EMLXS_MPDATA_SYNC(tx_mp->dma_handle, 0, size,
4484 		    DDI_DMA_SYNC_FORDEV);
4485 
4486 		mb->un.varRegLogin.un.sp64.addrHigh = PADDR_HI(tx_mp->phys);
4487 		mb->un.varRegLogin.un.sp64.addrLow = PADDR_LO(tx_mp->phys);
4488 		mb->un.varRegLogin.un.sp64.tus.f.bdeFlags = 0;
4489 
4490 		break;
4491 
4492 	case MBX_READ_LA:	/* 0x15 */
4493 	case MBX_READ_LA64:	/* 0x95 */
4494 		lptr =
4495 		    (uintptr_t)PADDR(mb->un.varReadLA.un.lilpBde64.
4496 		    addrHigh, mb->un.varReadLA.un.lilpBde64.addrLow);
4497 		size = (int)mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize;
4498 
4499 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4500 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4501 			    "%s: Invalid BDE. cmd=%x",
4502 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4503 
4504 			rval = DFC_ARG_INVALID;
4505 			goto done;
4506 		}
4507 
4508 		/* Allocate receive buffer */
4509 		if ((rx_mp = emlxs_mem_buf_alloc(hba, MEM_BUF_SIZE)) == 0) {
4510 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4511 			    "%s: Unable to allocate receive buffer. cmd=%x",
4512 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4513 
4514 			rval = DFC_DRVRES_ERROR;
4515 			goto done;
4516 		}
4517 
4518 		mb->un.varReadLA.un.lilpBde64.addrHigh =
4519 		    PADDR_HI(rx_mp->phys);
4520 		mb->un.varReadLA.un.lilpBde64.addrLow =
4521 		    PADDR_LO(rx_mp->phys);
4522 		mb->un.varReadLA.un.lilpBde64.tus.f.bdeFlags = 0;
4523 
4524 		break;
4525 
4526 
4527 		/* Do not allow these commands */
4528 	case MBX_CONFIG_PORT:	/* 0x88 */
4529 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4530 		    "%s: Command not allowed. cmd=%x",
4531 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4532 
4533 		rval = DFC_ARG_INVALID;
4534 		goto done;
4535 
4536 
4537 	/* Online / Offline */
4538 	default:
4539 		break;
4540 
4541 	}	/* switch() */
4542 
4543 	mb->mbxOwner = OWN_HOST;
4544 
4545 	/* Set or don't set the PASSTHRU bit. */
4546 	/* Setting will prevent the driver from processing it as its own */
4547 	switch (mb->mbxCommand) {
4548 	case MBX_REG_LOGIN:	/* 0x13 */
4549 	case MBX_REG_LOGIN64:	/* 0x93 */
4550 		break;
4551 
4552 	default:
4553 		mbq->flag |= MBQ_PASSTHRU;
4554 	}
4555 
4556 #ifdef MBOX_EXT_SUPPORT
4557 	if (extbuf) {
4558 		mbq->extbuf  = extbuf;
4559 		mbq->extsize = extsize;
4560 	}
4561 #endif /* MBOX_EXT_SUPPORT */
4562 
4563 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4564 	    "%s: %s sent.  (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd),
4565 	    emlxs_mb_cmd_xlate(mb->mbxCommand), mb->un.varWords[0],
4566 	    mb->un.varWords[1], mb->un.varWords[2], mb->un.varWords[3]);
4567 
4568 	/* issue the mbox cmd to the sli */
4569 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
4570 
4571 	if (mbxstatus) {
4572 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4573 		    "%s: %s failed. mbxstatus=0x%x",
4574 		    emlxs_dfc_xlate(dfc->cmd),
4575 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
4576 
4577 	}
4578 
4579 	if (ddi_copyout((void *)mb, (void *)dfc->buf2, dfc->buf2_size,
4580 	    mode) != 0) {
4581 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4582 		    "%s: ddi_copyout failed. cmd=%x",
4583 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4584 
4585 		rval = DFC_COPYOUT_ERROR;
4586 		goto done;
4587 	}
4588 
4589 	if (rx_mp) {
4590 		EMLXS_MPDATA_SYNC(rx_mp->dma_handle, 0, size,
4591 		    DDI_DMA_SYNC_FORKERNEL);
4592 
4593 		if (ddi_copyout((void *)rx_mp->virt, (void *)lptr, size,
4594 		    mode) != 0) {
4595 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4596 			    "%s: ddi_copyout failed for receive buffer. cmd=%x",
4597 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4598 
4599 			rval = DFC_COPYOUT_ERROR;
4600 			goto done;
4601 		}
4602 	}
4603 #ifdef MBOX_EXT_SUPPORT
4604 	/*  Any data needs to copy to mbox extension area */
4605 	if (dfc->buf4_size) {
4606 		if (ddi_copyout((void *)extbuf, (void *)dfc->buf4,
4607 		    dfc->buf4_size, mode) != 0) {
4608 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4609 			    "%s: ddi_copyout failed for mbox extension data.",
4610 			    emlxs_dfc_xlate(dfc->cmd));
4611 
4612 			rval = DFC_COPYIN_ERROR;
4613 			goto done;
4614 		}
4615 	}
4616 #endif /* MBOX_EXT_SUPPORT */
4617 
4618 	rval = 0;
4619 
4620 done:
4621 
4622 	/* Free allocated mbox memory */
4623 	if (extbuf) {
4624 		kmem_free(extbuf, extsize);
4625 	}
4626 
4627 	/* Free allocated mbox memory */
4628 	if (mbq) {
4629 		kmem_free(mbq, sizeof (MAILBOXQ));
4630 	}
4631 
4632 	/* Free allocated mbuf memory */
4633 	if (rx_mp) {
4634 #ifdef FMA_SUPPORT
4635 		if (!rval) {
4636 			if (emlxs_fm_check_dma_handle(hba, rx_mp->dma_handle)
4637 			    != DDI_FM_OK) {
4638 				EMLXS_MSGF(EMLXS_CONTEXT,
4639 				    &emlxs_invalid_dma_handle_msg,
4640 				    "emlxs_dfc_send_mbox: hdl=%p",
4641 				    rx_mp->dma_handle);
4642 				rval = DFC_IO_ERROR;
4643 			}
4644 		}
4645 #endif  /* FMA_SUPPORT */
4646 		emlxs_mem_buf_free(hba, rx_mp);
4647 	}
4648 
4649 	if (tx_mp) {
4650 #ifdef FMA_SUPPORT
4651 		if (!rval) {
4652 			if (emlxs_fm_check_dma_handle(hba, tx_mp->dma_handle)
4653 			    != DDI_FM_OK) {
4654 				EMLXS_MSGF(EMLXS_CONTEXT,
4655 				    &emlxs_invalid_dma_handle_msg,
4656 				    "emlxs_dfc_send_mbox: hdl=%p",
4657 				    tx_mp->dma_handle);
4658 				rval = DFC_IO_ERROR;
4659 			}
4660 		}
4661 #endif  /* FMA_SUPPORT */
4662 		emlxs_mem_buf_free(hba, tx_mp);
4663 	}
4664 
4665 	return (rval);
4666 
4667 } /* emlxs_dfc_send_mbox() */
4668 
4669 
4670 static int32_t
4671 emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4672 {
4673 	emlxs_port_t	*port = &PPORT;
4674 	uint32_t	offset;
4675 	uint32_t	cnt;
4676 	uint32_t	outsz;
4677 	uint32_t	i;
4678 	uint32_t	*buffer;
4679 	uint32_t	*bptr;
4680 	uint32_t	value;
4681 	uint32_t	size;
4682 	uint32_t	max = 4096;
4683 
4684 	offset = dfc->data1;
4685 	cnt = dfc->data2;
4686 	outsz = dfc->buf1_size;
4687 
4688 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4689 	    "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt);
4690 
4691 	if (!dfc->buf1_size || !dfc->buf1) {
4692 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4693 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4694 
4695 		return (DFC_ARG_NULL);
4696 	}
4697 
4698 	if (offset & 0x3) {
4699 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4700 		    "%s: Offset misaligned. (offset=%d)",
4701 		    emlxs_dfc_xlate(dfc->cmd), offset);
4702 
4703 		return (DFC_ARG_MISALIGNED);
4704 	}
4705 
4706 	if (cnt & 0x3) {
4707 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4708 		    "%s: Count misaligned. (count=%d)",
4709 		    emlxs_dfc_xlate(dfc->cmd), cnt);
4710 
4711 		return (DFC_ARG_MISALIGNED);
4712 	}
4713 
4714 	if (outsz & 0x3) {
4715 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4716 		    "%s: Output size misaligned. (size=%d)",
4717 		    emlxs_dfc_xlate(dfc->cmd), outsz);
4718 
4719 		return (DFC_ARG_MISALIGNED);
4720 	}
4721 
4722 	/* Get max PCI config range */
4723 	if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) {
4724 		max = 256;
4725 	} else {
4726 		max = 4096;
4727 	}
4728 
4729 	if ((cnt + offset) > max) {
4730 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4731 		    "%s: Offset+Count too large. (offset=%d count=%d max=%d)",
4732 		    emlxs_dfc_xlate(dfc->cmd), offset, cnt, max);
4733 
4734 		return (DFC_ARG_TOOBIG);
4735 	}
4736 
4737 	if (outsz > max) {
4738 		outsz = max;
4739 	}
4740 
4741 	if (cnt > outsz) {
4742 		cnt = outsz;
4743 	}
4744 
4745 	size = cnt;
4746 
4747 	if (!(buffer = (uint32_t *)kmem_zalloc(size, KM_NOSLEEP))) {
4748 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4749 		    "%s: Unable to allocate buffer.",
4750 		    emlxs_dfc_xlate(dfc->cmd));
4751 
4752 		return (DFC_SYSRES_ERROR);
4753 	}
4754 
4755 	bptr = buffer;
4756 	for (i = offset; i < (offset + cnt); i += 4) {
4757 		value =
4758 		    ddi_get32(hba->pci_acc_handle,
4759 		    (uint32_t *)(hba->pci_addr + i));
4760 		*bptr++ = BE_SWAP32(value);
4761 	}
4762 
4763 	if (ddi_copyout((void *)buffer, (void *)dfc->buf1, outsz, mode) != 0) {
4764 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4765 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
4766 
4767 		kmem_free(buffer, size);
4768 		return (DFC_COPYOUT_ERROR);
4769 	}
4770 
4771 	kmem_free(buffer, size);
4772 
4773 #ifdef FMA_SUPPORT
4774 	/* Access handle validation */
4775 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
4776 	    != DDI_FM_OK) {
4777 		EMLXS_MSGF(EMLXS_CONTEXT,
4778 		    &emlxs_invalid_access_handle_msg, NULL);
4779 		return (DFC_DRV_ERROR);
4780 	}
4781 #endif  /* FMA_SUPPORT */
4782 
4783 	return (0);
4784 
4785 } /* emlxs_dfc_read_pci() */
4786 
4787 
4788 static int32_t
4789 emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4790 {
4791 	emlxs_port_t	*port = &PPORT;
4792 	uint32_t	offset;
4793 	uint32_t	cnt;
4794 	uint32_t	value;
4795 	uint32_t	i;
4796 	uint32_t	max;
4797 	uint8_t		buffer[256];
4798 	uint32_t	*bptr;
4799 	uint16_t	word0;
4800 	uint16_t	word1;
4801 
4802 	offset = dfc->data1;
4803 	cnt = dfc->data2;
4804 
4805 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4806 	    "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt);
4807 
4808 	if (!dfc->buf1 || !dfc->buf1_size) {
4809 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4810 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4811 
4812 		return (DFC_ARG_NULL);
4813 	}
4814 
4815 	if (offset & 0x3) {
4816 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4817 		    "%s: Offset misaligned. (offset=%d)",
4818 		    emlxs_dfc_xlate(dfc->cmd), offset);
4819 
4820 		return (DFC_ARG_MISALIGNED);
4821 	}
4822 
4823 	if (cnt > dfc->buf1_size) {
4824 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4825 		    "%s: Count too large. (count=%d)",
4826 		    emlxs_dfc_xlate(dfc->cmd), cnt);
4827 
4828 		return (DFC_ARG_TOOBIG);
4829 	}
4830 
4831 	if (cnt & 0x3) {
4832 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4833 		    "%s: Count misaligned. (count=%d)",
4834 		    emlxs_dfc_xlate(dfc->cmd), cnt);
4835 
4836 		return (DFC_ARG_MISALIGNED);
4837 	}
4838 
4839 	/* Get max PCI config range */
4840 	if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) {
4841 		max = 256;
4842 	} else {
4843 		max = 4096;
4844 	}
4845 
4846 	if ((cnt + offset) > max) {
4847 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4848 		    "%s: Count+Offset too large. (offset=%d count=%d max=%d)",
4849 		    emlxs_dfc_xlate(dfc->cmd), offset, cnt, max);
4850 
4851 		return (DFC_ARG_TOOBIG);
4852 	}
4853 
4854 	bzero(buffer, sizeof (buffer));
4855 
4856 	if (ddi_copyin((void *)dfc->buf1, (void *)buffer, cnt, mode) != 0) {
4857 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4858 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
4859 
4860 		return (DFC_COPYIN_ERROR);
4861 	}
4862 
4863 	bptr = (uint32_t *)buffer;
4864 	for (i = offset; i < (offset + cnt); i += 4) {
4865 		value = *bptr++;
4866 		value = BE_SWAP32(value);
4867 
4868 		word0 = value & 0xFFFF;
4869 		word1 = value >> 16;
4870 
4871 		/*
4872 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
4873 		 * "%s: Writing. offset=%x cnt=%d value=%08x %04x %04x",
4874 		 * emlxs_dfc_xlate(dfc->cmd), i, value, word0, word1);
4875 		 */
4876 
4877 		/* word0 = PCIMEM_SHORT(word0); */
4878 		ddi_put16(hba->pci_acc_handle,
4879 		    (uint16_t *)(hba->pci_addr + i), (uint16_t)word0);
4880 
4881 		/* word1 = PCIMEM_SHORT(word1); */
4882 		ddi_put16(hba->pci_acc_handle,
4883 		    (uint16_t *)(hba->pci_addr + i + 2), (uint16_t)word1);
4884 	}
4885 
4886 #ifdef FMA_SUPPORT
4887 	/* Access handle validation */
4888 	if (emlxs_fm_check_acc_handle(hba, hba->pci_acc_handle)
4889 	    != DDI_FM_OK) {
4890 		EMLXS_MSGF(EMLXS_CONTEXT,
4891 		    &emlxs_invalid_access_handle_msg, NULL);
4892 		return (DFC_DRV_ERROR);
4893 	}
4894 #endif  /* FMA_SUPPORT */
4895 
4896 	return (0);
4897 
4898 } /* emlxs_dfc_write_pci() */
4899 
4900 
4901 static int32_t
4902 emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4903 {
4904 	emlxs_port_t	*port = &PPORT;
4905 	dfc_cfgparam_t	*cfgparam;
4906 	uint32_t	size;
4907 	uint32_t	count;
4908 	uint32_t	i;
4909 	int32_t		rval = 0;
4910 	emlxs_config_t	*cfg;
4911 
4912 	if (!dfc->buf1 || !dfc->buf1_size) {
4913 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4914 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4915 
4916 		return (DFC_ARG_NULL);
4917 	}
4918 
4919 	count = dfc->buf1_size / sizeof (dfc_cfgparam_t);
4920 
4921 	if (count > MAX_CFG_PARAM) {
4922 		count = MAX_CFG_PARAM;
4923 	}
4924 
4925 	if (count > NUM_CFG_PARAM) {
4926 		count = NUM_CFG_PARAM;
4927 	}
4928 
4929 	size = count * sizeof (dfc_cfgparam_t);
4930 
4931 	if (!(cfgparam = (dfc_cfgparam_t *)kmem_zalloc(size, KM_NOSLEEP))) {
4932 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4933 		    "%s: Unable to allocate cfgparm buffer.",
4934 		    emlxs_dfc_xlate(dfc->cmd));
4935 
4936 		return (DFC_SYSRES_ERROR);
4937 	}
4938 
4939 	cfg = &CFG;
4940 	for (i = 0; i < count; i++) {
4941 		(void) strncpy(cfgparam[i].a_string, cfg[i].string,
4942 		    sizeof (cfgparam[i].a_string));
4943 		cfgparam[i].a_low = cfg[i].low;
4944 		cfgparam[i].a_hi = cfg[i].hi;
4945 		cfgparam[i].a_default = cfg[i].def;
4946 		cfgparam[i].a_current = cfg[i].current;
4947 
4948 		if (!(cfg[i].flags & PARM_HIDDEN)) {
4949 			cfgparam[i].a_flag |= CFG_EXPORT;
4950 		}
4951 		cfgparam[i].a_flag |= CFG_COMMON;
4952 
4953 		/* Adjust a_flag based on the hba model */
4954 		switch (i) {
4955 			case CFG_NETWORK_ON:
4956 			case CFG_TOPOLOGY:
4957 			case CFG_LINK_SPEED:
4958 			case CFG_CR_DELAY:
4959 			case CFG_CR_COUNT:
4960 #ifdef SFCT_SUPPORT
4961 			case CFG_TARGET_MODE:
4962 #endif /* SFCT_SUPPORT */
4963 			if (!(hba->model_info.flags & EMLXS_FCOE_SUPPORTED)) {
4964 				cfgparam[i].a_flag |= CFG_APPLICABLE;
4965 			}
4966 			break;
4967 
4968 			case CFG_NUM_WQ:
4969 			if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
4970 				cfgparam[i].a_flag |= CFG_APPLICABLE;
4971 			}
4972 			break;
4973 
4974 			case CFG_PERSIST_LINKDOWN:
4975 			cfgparam[i].a_flag &= ~CFG_EXPORT;
4976 			break;
4977 
4978 			default:
4979 			cfgparam[i].a_flag |= CFG_APPLICABLE;
4980 			break;
4981 		}
4982 
4983 		if ((cfg[i].flags & PARM_DYNAMIC)) {
4984 			if ((cfg[i].flags & PARM_DYNAMIC_RESET) ==
4985 			    PARM_DYNAMIC_RESET) {
4986 				cfgparam[i].a_changestate = CFG_RESTART;
4987 			} else if ((cfg[i].flags & PARM_DYNAMIC_LINK) ==
4988 			    PARM_DYNAMIC_LINK) {
4989 				cfgparam[i].a_changestate = CFG_LINKRESET;
4990 			} else {
4991 				cfgparam[i].a_changestate = CFG_DYMANIC;
4992 			}
4993 		} else {
4994 			cfgparam[i].a_changestate = CFG_REBOOT;
4995 		}
4996 
4997 		(void) strncpy(cfgparam[i].a_help, cfg[i].help,
4998 		    sizeof (cfgparam[i].a_help));
4999 	}
5000 
5001 	if (ddi_copyout((void *)cfgparam, (void *)dfc->buf1, size, mode) != 0) {
5002 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5003 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
5004 
5005 		rval = DFC_COPYOUT_ERROR;
5006 	}
5007 
5008 	rval = 0;
5009 
5010 	kmem_free(cfgparam, size);
5011 
5012 	return (rval);
5013 
5014 } /* emlxs_dfc_get_cfg() */
5015 
5016 
5017 /* ARGSUSED */
5018 static int32_t
5019 emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5020 {
5021 	emlxs_port_t	*port = &PPORT;
5022 	uint32_t	index;
5023 	uint32_t	new_value;
5024 	uint32_t	rc;
5025 
5026 	index = dfc->data1;
5027 	new_value = dfc->data2;
5028 
5029 	rc = emlxs_set_parm(hba, index, new_value);
5030 
5031 	if (rc) {
5032 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5033 		    "%s: Unable to set parameter. code=%d",
5034 		    emlxs_dfc_xlate(dfc->cmd), rc);
5035 
5036 		switch (rc) {
5037 		case 2:
5038 			return (DFC_NPIV_ACTIVE);
5039 
5040 		default:
5041 			return (DFC_ARG_INVALID);
5042 		}
5043 	}
5044 
5045 	return (0);
5046 
5047 } /* emlxs_dfc_set_cfg() */
5048 
5049 
5050 static int32_t
5051 emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5052 {
5053 	emlxs_port_t	*port = &PPORT;
5054 	uint8_t		*rsp_buf;
5055 	uint8_t		*cmd_buf;
5056 	uint32_t	did;
5057 	uint32_t	rsp_size;
5058 	uint32_t	cmd_size;
5059 	uint32_t	timeout;
5060 	fc_packet_t	*pkt = NULL;
5061 	uint32_t	rval = 0;
5062 	dfc_destid_t	destid;
5063 	NODELIST	*nlp;
5064 	char		buffer[128];
5065 
5066 	cmd_buf = dfc->buf1;
5067 	cmd_size = dfc->buf1_size;
5068 	rsp_buf = dfc->buf2;
5069 	rsp_size = dfc->buf2_size;
5070 	timeout = dfc->data1;
5071 
5072 	if (timeout < (2 * hba->fc_ratov)) {
5073 		timeout = 2 * hba->fc_ratov;
5074 	}
5075 
5076 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5077 	    "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), cmd_size,
5078 	    rsp_size);
5079 
5080 
5081 	if (!cmd_size || !cmd_buf) {
5082 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5083 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5084 
5085 		rval = DFC_ARG_NULL;
5086 		goto done;
5087 	}
5088 
5089 	if (!rsp_size || !rsp_buf) {
5090 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5091 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
5092 
5093 		rval = DFC_ARG_NULL;
5094 		goto done;
5095 	}
5096 
5097 	if (!dfc->buf3 || !dfc->buf3_size) {
5098 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5099 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
5100 
5101 		rval = DFC_ARG_NULL;
5102 		goto done;
5103 	}
5104 
5105 	if (!dfc->buf4 || !dfc->buf4_size) {
5106 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5107 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
5108 
5109 		rval = DFC_ARG_NULL;
5110 		goto done;
5111 	}
5112 
5113 	if (rsp_size > MAX_CT_PAYLOAD) {
5114 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5115 		    "%s: Buffer2 too large. size=%d",
5116 		    emlxs_dfc_xlate(dfc->cmd), rsp_size);
5117 
5118 		rval = DFC_ARG_TOOBIG;
5119 		goto done;
5120 	}
5121 
5122 	if (cmd_size > MAX_CT_PAYLOAD) {
5123 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5124 		    "%s: Buffer1 too large. size=%d",
5125 		    emlxs_dfc_xlate(dfc->cmd), cmd_size);
5126 
5127 		rval = DFC_ARG_TOOBIG;
5128 		goto done;
5129 	}
5130 
5131 	if (dfc->buf3_size < sizeof (dfc_destid_t)) {
5132 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5133 		    "%s: Buffer3 too small. (size=%d)",
5134 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
5135 
5136 		rval = DFC_ARG_TOOSMALL;
5137 		goto done;
5138 	}
5139 
5140 	if (dfc->buf4_size < sizeof (uint32_t)) {
5141 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5142 		    "%s: Buffer4 too small. (size=%d)",
5143 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size);
5144 
5145 		rval = DFC_ARG_TOOSMALL;
5146 		goto done;
5147 	}
5148 
5149 	if (ddi_copyin((void *)dfc->buf3, (void *)&destid,
5150 	    sizeof (dfc_destid_t), mode) != 0) {
5151 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5152 		    "%s: Unable to read destination id.",
5153 		    emlxs_dfc_xlate(dfc->cmd));
5154 
5155 		rval = DFC_COPYIN_ERROR;
5156 		goto done;
5157 	}
5158 
5159 	if (destid.idType == 0) {
5160 		if ((nlp = emlxs_node_find_wwpn(port, destid.wwpn)) == NULL) {
5161 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5162 			    "%s: WWPN does not exists. %s",
5163 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
5164 			    destid.wwpn));
5165 
5166 			rval = DFC_ARG_INVALID;
5167 			goto done;
5168 		}
5169 		did = nlp->nlp_DID;
5170 	} else {
5171 		if (emlxs_node_find_did(port, destid.d_id) == NULL) {
5172 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5173 			    "%s: DID does not exist. did=%x",
5174 			    emlxs_dfc_xlate(dfc->cmd), destid.d_id);
5175 
5176 			rval = DFC_ARG_INVALID;
5177 			goto done;
5178 		}
5179 		did = destid.d_id;
5180 	}
5181 
5182 	if (did == 0) {
5183 		did = port->did;
5184 	}
5185 
5186 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) {
5187 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5188 		    "%s: Unable to allocate packet.",
5189 		    emlxs_dfc_xlate(dfc->cmd));
5190 
5191 		rval = DFC_SYSRES_ERROR;
5192 		goto done;
5193 	}
5194 
5195 	/* Make this a polled IO */
5196 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5197 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5198 	pkt->pkt_comp = NULL;
5199 
5200 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5201 	pkt->pkt_timeout = (timeout) ? timeout : 30;
5202 
5203 	/* Build the fc header */
5204 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
5205 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
5206 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
5207 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
5208 	pkt->pkt_cmd_fhdr.f_ctl =
5209 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5210 	pkt->pkt_cmd_fhdr.seq_id = 0;
5211 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5212 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5213 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5214 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5215 	pkt->pkt_cmd_fhdr.ro = 0;
5216 
5217 	/* Copy in the command buffer */
5218 	if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size,
5219 	    mode) != 0) {
5220 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5221 		    "%s: Unable to read command buffer.",
5222 		    emlxs_dfc_xlate(dfc->cmd));
5223 
5224 		rval = DFC_COPYIN_ERROR;
5225 		goto done;
5226 	}
5227 
5228 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5229 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5230 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
5231 
5232 		rval = DFC_IO_ERROR;
5233 		goto done;
5234 	}
5235 
5236 	if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
5237 	    (pkt->pkt_state != FC_PKT_FS_RJT)) {
5238 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5239 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5240 			    "Pkt Transport error. Pkt Timeout.");
5241 			rval = DFC_TIMEOUT;
5242 		} else {
5243 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5244 			    "Pkt Transport error. state=%x", pkt->pkt_state);
5245 			rval = DFC_IO_ERROR;
5246 		}
5247 		goto done;
5248 	}
5249 
5250 	if (ddi_copyout((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size,
5251 	    mode) != 0) {
5252 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5253 		    "%s: Unable to read response.",
5254 		    emlxs_dfc_xlate(dfc->cmd));
5255 
5256 		rval = DFC_COPYOUT_ERROR;
5257 		goto done;
5258 	}
5259 
5260 	rsp_size -= pkt->pkt_resp_resid;
5261 	if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf4, dfc->buf4_size,
5262 	    mode) != 0) {
5263 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5264 		    "%s: Unable to write response.",
5265 		    emlxs_dfc_xlate(dfc->cmd));
5266 
5267 		rval = DFC_COPYOUT_ERROR;
5268 		goto done;
5269 	}
5270 
5271 	rval = 0;
5272 
5273 done:
5274 
5275 	if (pkt) {
5276 		emlxs_pkt_free(pkt);
5277 	}
5278 
5279 	return (rval);
5280 
5281 } /* emlxs_dfc_send_ct() */
5282 
5283 
5284 static int32_t
5285 emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5286 {
5287 	emlxs_port_t	*port = &PPORT;
5288 	uint8_t		*cmd_buf;
5289 	uint32_t	rx_id;
5290 	uint32_t	cmd_size;
5291 	uint32_t	timeout;
5292 	fc_packet_t	*pkt = NULL;
5293 	uint32_t	rval = 0;
5294 
5295 	cmd_buf = dfc->buf1;
5296 	cmd_size = dfc->buf1_size;
5297 	rx_id = dfc->flag;
5298 	timeout = 2 * hba->fc_ratov;
5299 
5300 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: csize=%d",
5301 	    emlxs_dfc_xlate(dfc->cmd), cmd_size);
5302 
5303 	if (!cmd_size || !cmd_buf) {
5304 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5305 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5306 
5307 		rval = DFC_ARG_NULL;
5308 		goto done;
5309 	}
5310 
5311 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, 0, 0, KM_NOSLEEP))) {
5312 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5313 		    "%s: Unable to allocate packet.",
5314 		    emlxs_dfc_xlate(dfc->cmd));
5315 
5316 		rval = DFC_SYSRES_ERROR;
5317 		goto done;
5318 	}
5319 
5320 	/* Make this a polled IO */
5321 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5322 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5323 	pkt->pkt_comp = NULL;
5324 
5325 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
5326 	pkt->pkt_timeout = (timeout) ? timeout : 30;
5327 
5328 	/* Build the fc header */
5329 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(0);
5330 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_SOLICITED_CONTROL;
5331 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
5332 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
5333 	pkt->pkt_cmd_fhdr.f_ctl =
5334 	    F_CTL_LAST_SEQ | F_CTL_END_SEQ | F_CTL_XCHG_CONTEXT;
5335 	pkt->pkt_cmd_fhdr.seq_id = 0;
5336 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5337 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5338 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
5339 	pkt->pkt_cmd_fhdr.rx_id = rx_id;
5340 	pkt->pkt_cmd_fhdr.ro = 0;
5341 
5342 	/* Copy in the command buffer */
5343 	if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size,
5344 	    mode) != 0) {
5345 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5346 		    "%s: Unable to read command buffer.",
5347 		    emlxs_dfc_xlate(dfc->cmd));
5348 
5349 		rval = DFC_COPYIN_ERROR;
5350 		goto done;
5351 	}
5352 
5353 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5354 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5355 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
5356 
5357 		rval = DFC_IO_ERROR;
5358 		goto done;
5359 	}
5360 
5361 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
5362 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5363 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5364 			    "Pkt Transport error. Pkt Timeout.");
5365 			rval = DFC_TIMEOUT;
5366 		} else {
5367 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5368 			    "Pkt Transport error. state=%x", pkt->pkt_state);
5369 			rval = DFC_IO_ERROR;
5370 		}
5371 		goto done;
5372 	}
5373 
5374 	rval = 0;
5375 
5376 done:
5377 
5378 	if (pkt) {
5379 		emlxs_pkt_free(pkt);
5380 	}
5381 
5382 	return (rval);
5383 
5384 } /* emlxs_dfc_send_ct_rsp() */
5385 
5386 
5387 #ifdef MENLO_SUPPORT
5388 
5389 static int32_t
5390 emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5391 {
5392 	emlxs_port_t	*port = &PPORT;
5393 	uint8_t		*rsp_buf = NULL;
5394 	uint8_t		*cmd_buf = NULL;
5395 	uint32_t	rsp_size = 0;
5396 	uint32_t	cmd_size = 0;
5397 	uint32_t	rval = 0;
5398 
5399 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5400 	    "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size,
5401 	    dfc->buf2_size);
5402 
5403 	if (hba->model_info.device_id != PCI_DEVICE_ID_LP21000_M) {
5404 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5405 		    "%s: Menlo device not present. device=%x,%x",
5406 		    emlxs_dfc_xlate(dfc->cmd), hba->model_info.device_id,
5407 		    hba->model_info.ssdid);
5408 
5409 		rval = DFC_INVALID_ADAPTER;
5410 		goto done;
5411 	}
5412 
5413 	if (!dfc->buf1_size || !dfc->buf1) {
5414 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5415 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5416 
5417 		rval = DFC_ARG_NULL;
5418 		goto done;
5419 	}
5420 
5421 	if (!dfc->buf2_size || !dfc->buf2) {
5422 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5423 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
5424 
5425 		rval = DFC_ARG_NULL;
5426 		goto done;
5427 	}
5428 
5429 	if (!dfc->buf3 || !dfc->buf3_size) {
5430 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5431 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
5432 
5433 		rval = DFC_ARG_NULL;
5434 		goto done;
5435 	}
5436 
5437 	if (dfc->buf3_size < sizeof (uint32_t)) {
5438 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5439 		    "%s: Buffer3 too small. %d < %d",
5440 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size,
5441 		    sizeof (uint32_t));
5442 
5443 		rval = DFC_ARG_TOOSMALL;
5444 		goto done;
5445 	}
5446 
5447 	cmd_size  = dfc->buf1_size;
5448 	cmd_buf = (uint8_t *)kmem_zalloc(cmd_size,
5449 	    KM_SLEEP);
5450 
5451 	rsp_size  = dfc->buf2_size;
5452 	rsp_buf = (uint8_t *)kmem_zalloc(rsp_size,
5453 	    KM_SLEEP);
5454 
5455 	/* Read the command buffer */
5456 	if (ddi_copyin((void *)dfc->buf1, (void *)cmd_buf,
5457 	    cmd_size, mode) != 0) {
5458 		EMLXS_MSGF(EMLXS_CONTEXT,
5459 		    &emlxs_dfc_error_msg,
5460 		    "%s: Unable to read command buffer.",
5461 		    emlxs_dfc_xlate(dfc->cmd));
5462 
5463 		rval = DFC_COPYIN_ERROR;
5464 		goto done;
5465 	}
5466 
5467 	/* Send the command */
5468 	rval = emlxs_send_menlo_cmd(hba, cmd_buf, cmd_size,
5469 	    rsp_buf, &rsp_size);
5470 
5471 	if (rval == 0) {
5472 		/* Return the response */
5473 		if (ddi_copyout((void *)rsp_buf, (void *)dfc->buf2,
5474 		    rsp_size, mode) != 0) {
5475 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5476 			    "%s: Unable to write response.",
5477 			    emlxs_dfc_xlate(dfc->cmd));
5478 
5479 			rval = DFC_COPYOUT_ERROR;
5480 			goto done;
5481 		}
5482 
5483 		/* Return the response size */
5484 		if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf3,
5485 		    dfc->buf3_size, mode) != 0) {
5486 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5487 			    "%s: Unable to write response size.",
5488 			    emlxs_dfc_xlate(dfc->cmd));
5489 
5490 			rval = DFC_COPYOUT_ERROR;
5491 			goto done;
5492 		}
5493 	}
5494 
5495 done:
5496 
5497 	if (cmd_buf) {
5498 		kmem_free(cmd_buf, dfc->buf1_size);
5499 	}
5500 
5501 	if (rsp_buf) {
5502 		kmem_free(rsp_buf, dfc->buf2_size);
5503 	}
5504 
5505 	return (rval);
5506 
5507 } /* emlxs_dfc_send_menlo() */
5508 
5509 
5510 extern int32_t
5511 emlxs_send_menlo_cmd(emlxs_hba_t *hba, uint8_t *cmd_buf, uint32_t cmd_size,
5512     uint8_t *rsp_buf, uint32_t *rsp_size)
5513 {
5514 	emlxs_port_t		*port = &PPORT;
5515 	uint8_t			*data_buf = NULL;
5516 	uint32_t		data_size = 0;
5517 	fc_packet_t		*pkt = NULL;
5518 	int32_t			rval = 0;
5519 	menlo_set_cmd_t		set_cmd;
5520 	menlo_reset_cmd_t	reset_cmd;
5521 	uint32_t		rsp_code;
5522 	uint32_t		mm_mode = 0;
5523 	uint32_t		cmd_code;
5524 	clock_t			timeout;
5525 	MAILBOXQ		*mbq = NULL;
5526 	MAILBOX			*mb;
5527 	uint32_t		addr;
5528 	uint32_t		value;
5529 	uint32_t		mbxstatus;
5530 
5531 	cmd_code = *(uint32_t *)cmd_buf;
5532 	cmd_code = BE_SWAP32(cmd_code);
5533 
5534 	/* Look for Zephyr specific commands */
5535 	if (cmd_code & 0x80000000) {
5536 		bzero((uint8_t *)&reset_cmd, sizeof (menlo_reset_cmd_t));
5537 		bzero((uint8_t *)&set_cmd, sizeof (menlo_set_cmd_t));
5538 		bzero((uint8_t *)&rsp_code, sizeof (uint32_t));
5539 
5540 		/* Validate response buffer */
5541 		if (*rsp_size < sizeof (uint32_t)) {
5542 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5543 			    "emlxs_send_menlo_cmd: Response overrun.");
5544 			rval = DFC_RSP_BUF_OVERRUN;
5545 			goto done;
5546 		}
5547 
5548 		/* All of these responses will be 4 bytes only */
5549 		*rsp_size = sizeof (uint32_t);
5550 		rsp_code = 0;
5551 
5552 		/* Validate command buffer */
5553 		switch (cmd_code) {
5554 		case MENLO_CMD_RESET:
5555 			if (cmd_size < sizeof (menlo_reset_cmd_t)) {
5556 				EMLXS_MSGF(EMLXS_CONTEXT,
5557 				    &emlxs_dfc_error_msg,
5558 				    "emlxs_send_menlo_cmd: "
5559 				    "Invalid command size. %d < %d",
5560 				    cmd_size,
5561 				    sizeof (menlo_reset_cmd_t));
5562 				rval = DFC_ARG_INVALID;
5563 				goto done;
5564 			}
5565 			cmd_size = sizeof (menlo_reset_cmd_t);
5566 
5567 			/* Read the command buffer */
5568 			bcopy((void *)cmd_buf, (void *)&reset_cmd, cmd_size);
5569 
5570 			if (reset_cmd.firmware) {
5571 				/* MENLO_FW_GOLDEN */
5572 				value = 1;
5573 
5574 				EMLXS_MSGF(EMLXS_CONTEXT,
5575 				    &emlxs_dfc_detail_msg,
5576 				    "emlxs_send_menlo_cmd: Reset with Golden "
5577 				    "firmware requested.");
5578 
5579 			} else {
5580 				/* MENLO_FW_OPERATIONAL */
5581 				value = 0;
5582 
5583 				EMLXS_MSGF(EMLXS_CONTEXT,
5584 				    &emlxs_dfc_detail_msg,
5585 				    "emlxs_send_menlo_cmd: Reset with "
5586 				    "Operational firmware requested.");
5587 			}
5588 
5589 			addr  = 0x103007;
5590 
5591 			break;
5592 
5593 		case MENLO_CMD_SET_MODE:
5594 			if (cmd_size < sizeof (menlo_set_cmd_t)) {
5595 				EMLXS_MSGF(EMLXS_CONTEXT,
5596 				    &emlxs_dfc_error_msg,
5597 				    "emlxs_send_menlo_cmd: "
5598 				    "Invalid command size. %d < %d",
5599 				    cmd_size,
5600 				    sizeof (menlo_set_cmd_t));
5601 				rval = DFC_ARG_INVALID;
5602 				goto done;
5603 			}
5604 			cmd_size = sizeof (menlo_set_cmd_t);
5605 
5606 			/* Read the command buffer */
5607 			bcopy((void *)cmd_buf, (void *)&set_cmd, cmd_size);
5608 
5609 			if (set_cmd.value1) {
5610 				EMLXS_MSGF(EMLXS_CONTEXT,
5611 				    &emlxs_dfc_detail_msg,
5612 				    "emlxs_send_menlo_cmd: "
5613 				    "Maintenance mode enable requested.");
5614 
5615 				/* Make sure the mode flag is cleared */
5616 				if (hba->flag & FC_MENLO_MODE) {
5617 					mutex_enter(&EMLXS_PORT_LOCK);
5618 					hba->flag &= ~FC_MENLO_MODE;
5619 					mutex_exit(&EMLXS_PORT_LOCK);
5620 				}
5621 
5622 				mm_mode = 1;
5623 			} else {
5624 				EMLXS_MSGF(EMLXS_CONTEXT,
5625 				    &emlxs_dfc_detail_msg,
5626 				    "emlxs_send_menlo_cmd: "
5627 				    "Maintenance mode disable requested.");
5628 			}
5629 
5630 			addr  = 0x103107;
5631 			value = mm_mode;
5632 
5633 			break;
5634 
5635 		default:
5636 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5637 			    "emlxs_send_menlo_cmd: "
5638 			    "Invalid command. cmd=%x", cmd_code);
5639 			rval = DFC_ARG_INVALID;
5640 			goto done;
5641 		}
5642 
5643 		mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
5644 		    KM_SLEEP);
5645 
5646 		mb = (MAILBOX *) mbq;
5647 
5648 		/* Create the set_variable mailbox request */
5649 		emlxs_mb_set_var(hba, mbq, addr, value);
5650 
5651 		mbq->flag |= MBQ_PASSTHRU;
5652 
5653 		/* issue the mbox cmd to the sli */
5654 		mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
5655 
5656 		if (mbxstatus) {
5657 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5658 			    "emlxs_send_menlo_cmd: %s failed. mbxstatus=0x%x",
5659 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
5660 
5661 			if (mbxstatus == MBX_TIMEOUT) {
5662 				rval = DFC_TIMEOUT;
5663 			} else {
5664 				rval = DFC_IO_ERROR;
5665 			}
5666 			goto done;
5667 		}
5668 
5669 		bcopy((void *)&rsp_code, (void *)rsp_buf, *rsp_size);
5670 
5671 		/* Check if we need to wait for maintenance mode */
5672 		if (mm_mode && !(hba->flag & FC_MENLO_MODE)) {
5673 			/* Wait for link to come up in maintenance mode */
5674 			mutex_enter(&EMLXS_LINKUP_LOCK);
5675 
5676 			timeout = emlxs_timeout(hba, 30);
5677 
5678 			rval = 0;
5679 			while ((rval != -1) && !(hba->flag & FC_MENLO_MODE)) {
5680 				rval =
5681 				    cv_timedwait(&EMLXS_LINKUP_CV,
5682 				    &EMLXS_LINKUP_LOCK, timeout);
5683 			}
5684 
5685 			mutex_exit(&EMLXS_LINKUP_LOCK);
5686 
5687 			if (rval == -1) {
5688 				EMLXS_MSGF(EMLXS_CONTEXT,
5689 				    &emlxs_dfc_error_msg,
5690 				    "emlxs_send_menlo_cmd: "
5691 				    "Menlo maintenance mode error. Timeout.");
5692 
5693 				rval = DFC_TIMEOUT;
5694 				goto done;
5695 			}
5696 		}
5697 	} else {	/* Standard commands */
5698 
5699 		if (hba->state <= FC_LINK_DOWN) {
5700 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5701 			    "emlxs_send_menlo_cmd: Adapter link down.");
5702 
5703 			rval = DFC_LINKDOWN_ERROR;
5704 			goto done;
5705 		}
5706 
5707 		if (cmd_code == MENLO_CMD_FW_DOWNLOAD) {
5708 			/* Check cmd size */
5709 			/* Must be at least 12 bytes of command */
5710 			/* plus 4 bytes of data */
5711 			if (cmd_size < (12 + 4)) {
5712 				EMLXS_MSGF(EMLXS_CONTEXT,
5713 				    &emlxs_dfc_error_msg,
5714 				    "emlxs_send_menlo_cmd: "
5715 				    "Invalid command size. %d < %d",
5716 				    cmd_size,
5717 				    (12 + 4));
5718 
5719 				rval = DFC_ARG_INVALID;
5720 				goto done;
5721 			}
5722 
5723 			/* Extract data buffer from command buffer */
5724 			data_buf    = cmd_buf  + 12;
5725 			data_size   = cmd_size - 12;
5726 			cmd_size    = 12;
5727 		}
5728 
5729 		if (!(pkt = emlxs_pkt_alloc(port, cmd_size, *rsp_size, 0,
5730 		    KM_NOSLEEP))) {
5731 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5732 			    "emlxs_send_menlo_cmd: Unable to allocate packet.");
5733 
5734 			rval = DFC_SYSRES_ERROR;
5735 			goto done;
5736 		}
5737 
5738 		/* Make this a polled IO */
5739 		pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5740 		pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5741 		pkt->pkt_comp = NULL;
5742 		pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5743 		pkt->pkt_timeout = 30;
5744 
5745 		/* Build the fc header */
5746 		pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
5747 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
5748 		pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
5749 		pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
5750 		pkt->pkt_cmd_fhdr.f_ctl =
5751 		    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5752 		pkt->pkt_cmd_fhdr.seq_id = 0;
5753 		pkt->pkt_cmd_fhdr.df_ctl = 0;
5754 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
5755 		pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5756 		pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5757 		pkt->pkt_cmd_fhdr.ro = 0;
5758 
5759 		/* Copy in the command buffer */
5760 		bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size);
5761 
5762 		if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5763 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5764 			    "emlxs_send_menlo_cmd: Unable to send packet.");
5765 
5766 			rval = DFC_IO_ERROR;
5767 			goto done;
5768 		}
5769 
5770 		if (pkt->pkt_state != FC_PKT_SUCCESS) {
5771 			if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5772 				EMLXS_MSGF(EMLXS_CONTEXT,
5773 				    &emlxs_dfc_error_msg,
5774 				    "emlxs_send_menlo_cmd: "
5775 				    "Pkt Transport error. Pkt Timeout.");
5776 				rval = DFC_TIMEOUT;
5777 			} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
5778 			    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
5779 				EMLXS_MSGF(EMLXS_CONTEXT,
5780 				    &emlxs_dfc_error_msg,
5781 				    "emlxs_send_menlo_cmd: "
5782 				    "Pkt Transport error. Response overrun.");
5783 				rval = DFC_RSP_BUF_OVERRUN;
5784 			} else {
5785 				EMLXS_MSGF(EMLXS_CONTEXT,
5786 				    &emlxs_dfc_error_msg,
5787 				    "emlxs_send_menlo_cmd: "
5788 				    "Pkt Transport error. state=%x",
5789 				    pkt->pkt_state);
5790 				rval = DFC_IO_ERROR;
5791 			}
5792 			goto done;
5793 		}
5794 
5795 		if (cmd_code == MENLO_CMD_FW_DOWNLOAD) {
5796 			uint32_t *rsp;
5797 
5798 			/* Check response code */
5799 			rsp = (uint32_t *)pkt->pkt_resp;
5800 			rsp_code = *rsp;
5801 			rsp_code = BE_SWAP32(rsp_code);
5802 
5803 			if (rsp_code == MENLO_RSP_SUCCESS) {
5804 				/* Now transmit the data phase */
5805 
5806 				/* Save last rx_id */
5807 				uint32_t rx_id = pkt->pkt_cmd_fhdr.rx_id;
5808 
5809 				/* Free old pkt */
5810 				emlxs_pkt_free(pkt);
5811 
5812 				/* Allocate data pkt */
5813 				if (!(pkt = emlxs_pkt_alloc(port, data_size,
5814 				    *rsp_size, 0, KM_NOSLEEP))) {
5815 					EMLXS_MSGF(EMLXS_CONTEXT,
5816 					    &emlxs_dfc_error_msg,
5817 					    "emlxs_send_menlo_cmd: "
5818 					    "Unable to allocate data "
5819 					    "packet.");
5820 
5821 					rval = DFC_SYSRES_ERROR;
5822 					goto done;
5823 				}
5824 
5825 				/* Make this a polled IO */
5826 				pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5827 				pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5828 				pkt->pkt_comp = NULL;
5829 				pkt->pkt_tran_type = FC_PKT_OUTBOUND;
5830 				pkt->pkt_timeout = 30;
5831 
5832 				/* Build the fc header */
5833 				pkt->pkt_cmd_fhdr.d_id =
5834 				    LE_SWAP24_LO(EMLXS_MENLO_DID);
5835 				pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
5836 				pkt->pkt_cmd_fhdr.s_id =
5837 				    LE_SWAP24_LO(port->did);
5838 				pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
5839 				pkt->pkt_cmd_fhdr.f_ctl =
5840 				    F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
5841 				    F_CTL_SEQ_INITIATIVE;
5842 				pkt->pkt_cmd_fhdr.seq_id = 0;
5843 				pkt->pkt_cmd_fhdr.df_ctl = 0;
5844 				pkt->pkt_cmd_fhdr.seq_cnt = 0;
5845 				pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5846 				pkt->pkt_cmd_fhdr.rx_id = rx_id;
5847 				pkt->pkt_cmd_fhdr.ro = 0;
5848 
5849 				/* Copy in the data buffer */
5850 				bcopy((void *)data_buf, (void *)pkt->pkt_cmd,
5851 				    data_size);
5852 
5853 				if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5854 					EMLXS_MSGF(EMLXS_CONTEXT,
5855 					    &emlxs_dfc_error_msg,
5856 					    "emlxs_send_menlo_cmd: "
5857 					    "Unable to send data packet.");
5858 
5859 					rval = DFC_IO_ERROR;
5860 					goto done;
5861 				}
5862 
5863 				if (pkt->pkt_state != FC_PKT_SUCCESS) {
5864 					if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5865 						EMLXS_MSGF(EMLXS_CONTEXT,
5866 						    &emlxs_dfc_error_msg,
5867 						    "emlxs_send_menlo_cmd: "
5868 						    "Data Pkt Transport "
5869 						    "error. Pkt Timeout.");
5870 						rval = DFC_TIMEOUT;
5871 					} else if ((pkt->pkt_state ==
5872 					    FC_PKT_LOCAL_RJT) &&
5873 					    (pkt->pkt_reason ==
5874 					    FC_REASON_OVERRUN)) {
5875 						EMLXS_MSGF(EMLXS_CONTEXT,
5876 						    &emlxs_dfc_error_msg,
5877 						    "emlxs_send_menlo_cmd: "
5878 						    "Data Pkt Transport "
5879 						    "error. Response overrun.");
5880 						rval = DFC_RSP_BUF_OVERRUN;
5881 					} else {
5882 						EMLXS_MSGF(EMLXS_CONTEXT,
5883 						    &emlxs_dfc_error_msg,
5884 						    "emlxs_send_menlo_cmd: "
5885 						    "Data Pkt Transport "
5886 						    "error. state=%x",
5887 						    pkt->pkt_state);
5888 						rval = DFC_IO_ERROR;
5889 					}
5890 					goto done;
5891 				}
5892 			}
5893 		}
5894 
5895 		bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, *rsp_size);
5896 		*rsp_size = *rsp_size - pkt->pkt_resp_resid;
5897 	}
5898 
5899 	rval = 0;
5900 
5901 done:
5902 
5903 	if (pkt) {
5904 		emlxs_pkt_free(pkt);
5905 	}
5906 
5907 	if (mbq) {
5908 		kmem_free(mbq, sizeof (MAILBOXQ));
5909 	}
5910 
5911 	return (rval);
5912 
5913 } /* emlxs_send_menlo_cmd() */
5914 
5915 
5916 /* ARGSUSED */
5917 extern void
5918 emlxs_fcoe_attention_thread(emlxs_hba_t *hba,
5919     void *arg1, void *arg2)
5920 {
5921 	emlxs_port_t		*port = &PPORT;
5922 	menlo_init_rsp_t	*rsp;
5923 	menlo_get_cmd_t		*cmd;
5924 	fc_packet_t		*pkt = NULL;
5925 
5926 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_get_cmd_t),
5927 	    sizeof (menlo_init_rsp_t), 0, KM_NOSLEEP))) {
5928 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5929 		    "FCoE attention: Unable to allocate packet.");
5930 
5931 		return;
5932 	}
5933 
5934 	/* Make this a polled IO */
5935 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5936 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5937 	pkt->pkt_comp = NULL;
5938 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5939 	pkt->pkt_timeout = 30;
5940 
5941 	/* Build the fc header */
5942 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
5943 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
5944 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
5945 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
5946 	pkt->pkt_cmd_fhdr.f_ctl =
5947 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5948 	pkt->pkt_cmd_fhdr.seq_id = 0;
5949 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5950 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5951 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5952 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5953 	pkt->pkt_cmd_fhdr.ro = 0;
5954 
5955 	cmd = (menlo_get_cmd_t *)pkt->pkt_cmd;
5956 	cmd->code = MENLO_CMD_GET_INIT;
5957 	cmd->context = 0;
5958 	cmd->length = sizeof (menlo_init_rsp_t);
5959 
5960 	/* Little Endian Swap */
5961 	cmd->code = BE_SWAP32(cmd->code);
5962 	cmd->length = BE_SWAP32(cmd->length);
5963 
5964 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5965 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5966 		    "FCoE attention: Unable to send packet.");
5967 
5968 		goto done;
5969 	}
5970 
5971 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
5972 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5973 		    "FCoE attention: Pkt Transport error. state=%x",
5974 		    pkt->pkt_state);
5975 
5976 		goto done;
5977 	}
5978 
5979 	/* Check response code */
5980 	rsp = (menlo_init_rsp_t *)pkt->pkt_resp;
5981 	rsp->code = BE_SWAP32(rsp->code);
5982 
5983 	if (rsp->code != MENLO_RSP_SUCCESS) {
5984 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5985 		    "FCoE attention: FCOE Response error =%x", rsp->code);
5986 
5987 		goto done;
5988 	}
5989 
5990 	/* Little Endian Swap */
5991 	rsp->bb_credit = BE_SWAP32(rsp->bb_credit);
5992 	rsp->frame_size = BE_SWAP32(rsp->frame_size);
5993 	rsp->fw_version = BE_SWAP32(rsp->fw_version);
5994 	rsp->reset_status = BE_SWAP32(rsp->reset_status);
5995 	rsp->maint_status = BE_SWAP32(rsp->maint_status);
5996 	rsp->fw_type = BE_SWAP32(rsp->fw_type);
5997 	rsp->fru_data_valid = BE_SWAP32(rsp->fru_data_valid);
5998 
5999 	/* Log the event */
6000 	emlxs_log_fcoe_event(port, rsp);
6001 
6002 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6003 	    "MENLO_INIT: bb_credit      = 0x%x", rsp->bb_credit);
6004 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6005 	    "MENLO_INIT: frame_size     = 0x%x", rsp->frame_size);
6006 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6007 	    "MENLO_INIT: fw_version     = 0x%x", rsp->fw_version);
6008 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6009 	    "MENLO_INIT: reset_status   = 0x%x", rsp->reset_status);
6010 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6011 	    "MENLO_INIT: maint_status   = 0x%x", rsp->maint_status);
6012 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6013 	    "MENLO_INIT: fw_type        = 0x%x", rsp->fw_type);
6014 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
6015 	    "MENLO_INIT: fru_data_valid = 0x%x", rsp->fru_data_valid);
6016 
6017 	/* Perform attention checks */
6018 	if (rsp->fru_data_valid == 0) {
6019 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_error_msg,
6020 		    "Invalid FRU data found on adapter. "
6021 		    "Return adapter to Emulex for repair.");
6022 	}
6023 
6024 	switch (rsp->fw_type) {
6025 	case MENLO_FW_TYPE_GOLDEN:
6026 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_warning_msg,
6027 		    "FCoE chip is running Golden firmware. "
6028 		    "Update FCoE firmware immediately.");
6029 		break;
6030 
6031 	case MENLO_FW_TYPE_DIAG:
6032 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_notice_msg,
6033 		    "FCoE chip is running Diagnostic firmware. "
6034 		    "Operational use of the adapter is suspended.");
6035 		break;
6036 	}
6037 
6038 done:
6039 
6040 	if (pkt) {
6041 		emlxs_pkt_free(pkt);
6042 	}
6043 
6044 	return;
6045 
6046 } /* emlxs_fcoe_attention_thread() */
6047 
6048 #endif /* MENLO_SUPPORT */
6049 
6050 
6051 static int32_t
6052 emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6053 {
6054 	emlxs_port_t	*port = &PPORT;
6055 	uint32_t	offset;
6056 	uint32_t	cnt;
6057 	uint8_t		*buffer;
6058 	uint8_t		*bptr;
6059 	uint32_t	i;
6060 
6061 	if (hba->bus_type != SBUS_FC) {
6062 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6063 		    "%s: Invalid bus_type. (bus_type=%x)",
6064 		    emlxs_dfc_xlate(dfc->cmd), hba->bus_type);
6065 
6066 		return (DFC_ARG_INVALID);
6067 	}
6068 
6069 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6070 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6071 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6072 
6073 		return (DFC_ONLINE_ERROR);
6074 	}
6075 
6076 	if (!dfc->buf1 || !dfc->buf1_size) {
6077 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6078 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6079 
6080 		return (DFC_ARG_NULL);
6081 	}
6082 
6083 	offset = dfc->data1;
6084 	cnt = dfc->data2;
6085 
6086 	if (offset > (64 * 1024)) {
6087 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6088 		    "%s: Offset too large. (offset=%d)",
6089 		    emlxs_dfc_xlate(dfc->cmd), offset);
6090 
6091 		return (DFC_ARG_TOOBIG);
6092 	}
6093 
6094 	if (cnt > dfc->buf1_size) {
6095 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6096 		    "%s: Count too large. (count=%d)",
6097 		    emlxs_dfc_xlate(dfc->cmd), cnt);
6098 
6099 		return (DFC_ARG_TOOBIG);
6100 	}
6101 
6102 	if ((cnt + offset) > (64 * 1024)) {
6103 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6104 		    "%s: Count+Offset too large. (count=%d offset=%d)",
6105 		    emlxs_dfc_xlate(dfc->cmd), cnt, offset);
6106 
6107 		return (DFC_ARG_TOOBIG);
6108 	}
6109 
6110 	if (cnt == 0) {
6111 		return (0);
6112 	}
6113 
6114 	if ((buffer = (uint8_t *)kmem_zalloc(cnt, KM_NOSLEEP)) == NULL) {
6115 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6116 		    "%s: Unable to allocate buffer.",
6117 		    emlxs_dfc_xlate(dfc->cmd));
6118 
6119 		return (DFC_SYSRES_ERROR);
6120 	}
6121 
6122 	if (ddi_copyin((void *)dfc->buf1, (void *)buffer, cnt, mode) != 0) {
6123 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6124 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6125 
6126 		kmem_free(buffer, cnt);
6127 		return (DFC_COPYIN_ERROR);
6128 	}
6129 
6130 	bptr = buffer;
6131 	for (i = 0; i < cnt; i++) {
6132 		SBUS_WRITE_FLASH_COPY(hba, offset, *bptr);
6133 		offset++;
6134 		bptr++;
6135 	}
6136 
6137 	kmem_free(buffer, cnt);
6138 
6139 #ifdef FMA_SUPPORT
6140 	/* Access handle validation */
6141 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle)
6142 	    != DDI_FM_OK) {
6143 		EMLXS_MSGF(EMLXS_CONTEXT,
6144 		    &emlxs_invalid_access_handle_msg, NULL);
6145 		return (DFC_DRV_ERROR);
6146 	}
6147 #endif  /* FMA_SUPPORT */
6148 
6149 	return (0);
6150 
6151 } /* emlxs_dfc_write_flash() */
6152 
6153 
6154 static int32_t
6155 emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6156 {
6157 	emlxs_port_t	*port = &PPORT;
6158 	uint32_t	offset;
6159 	uint32_t	count;
6160 	uint32_t	outsz;
6161 	uint8_t		*buffer;
6162 	uint8_t		*bptr;
6163 	uint32_t	i;
6164 
6165 	if (hba->bus_type != SBUS_FC) {
6166 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6167 		    "%s: Invalid bus_type. (bus_type=%x)",
6168 		    emlxs_dfc_xlate(dfc->cmd), hba->bus_type);
6169 
6170 		return (DFC_ARG_INVALID);
6171 	}
6172 
6173 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6174 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6175 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6176 
6177 		return (DFC_ONLINE_ERROR);
6178 	}
6179 
6180 	if (!dfc->buf1 || !dfc->buf1_size) {
6181 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6182 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6183 
6184 		return (DFC_ARG_NULL);
6185 	}
6186 
6187 	offset = dfc->data1;
6188 	count = dfc->data2;
6189 	outsz = dfc->buf1_size;
6190 
6191 	if (offset > (64 * 1024)) {
6192 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6193 		    "%s: Offset too large. (offset=%d)",
6194 		    emlxs_dfc_xlate(dfc->cmd), offset);
6195 
6196 		return (DFC_ARG_TOOBIG);
6197 	}
6198 
6199 	if ((count + offset) > (64 * 1024)) {
6200 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6201 		    "%s: Count+Offset too large. (count=%d offset=%d)",
6202 		    emlxs_dfc_xlate(dfc->cmd), count, offset);
6203 
6204 		return (DFC_ARG_TOOBIG);
6205 	}
6206 
6207 	if (count < outsz) {
6208 		outsz = count;
6209 	}
6210 
6211 	if ((buffer = (uint8_t *)kmem_zalloc(outsz, KM_NOSLEEP)) == NULL) {
6212 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6213 		    "%s: Unable to allocate buffer.",
6214 		    emlxs_dfc_xlate(dfc->cmd));
6215 
6216 		return (DFC_SYSRES_ERROR);
6217 	}
6218 
6219 	bptr = buffer;
6220 	for (i = 0; i < outsz; i++) {
6221 		*bptr++ = SBUS_READ_FLASH_COPY(hba, offset++);
6222 	}
6223 
6224 	if (ddi_copyout((void *)buffer, (void *)dfc->buf1, outsz, mode) != 0) {
6225 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6226 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6227 
6228 		kmem_free(buffer, outsz);
6229 		return (DFC_COPYOUT_ERROR);
6230 	}
6231 
6232 	kmem_free(buffer, outsz);
6233 
6234 #ifdef FMA_SUPPORT
6235 	/* Access handle validation */
6236 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle)
6237 	    != DDI_FM_OK) {
6238 		EMLXS_MSGF(EMLXS_CONTEXT,
6239 		    &emlxs_invalid_access_handle_msg, NULL);
6240 		return (DFC_DRV_ERROR);
6241 	}
6242 #endif  /* FMA_SUPPORT */
6243 
6244 	return (0);
6245 
6246 } /* emlxs_dfc_read_flash() */
6247 
6248 
6249 static int32_t
6250 emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6251 {
6252 	emlxs_port_t	*port = &PPORT;
6253 	uint8_t		*rsp_buf;
6254 	uint8_t		*cmd_buf;
6255 	dfc_destid_t	destid;
6256 	uint32_t	rsp_size;
6257 	uint32_t	cmd_size;
6258 	uint32_t	timeout;
6259 	fc_packet_t	*pkt = NULL;
6260 	NODELIST	*ndlp;
6261 	uint32_t	did;
6262 	uint32_t	rval = 0;
6263 	char		buffer[128];
6264 
6265 	cmd_buf = dfc->buf1;
6266 	cmd_size = dfc->buf1_size;
6267 	rsp_buf = dfc->buf2;
6268 	rsp_size = dfc->buf2_size;
6269 
6270 	timeout = 2 * hba->fc_ratov;
6271 
6272 	if (!cmd_size || !cmd_buf) {
6273 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6274 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6275 
6276 		rval = DFC_ARG_NULL;
6277 		goto done;
6278 	}
6279 
6280 	if (!rsp_buf || !rsp_size) {
6281 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6282 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
6283 
6284 		rval = DFC_ARG_NULL;
6285 		goto done;
6286 	}
6287 
6288 	if (!dfc->buf3 || !dfc->buf3_size) {
6289 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6290 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
6291 
6292 		rval = DFC_ARG_NULL;
6293 		goto done;
6294 	}
6295 
6296 	if (dfc->buf3_size < sizeof (dfc_destid_t)) {
6297 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6298 		    "%s: Buffer3 too small. (size=%d)",
6299 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
6300 
6301 		rval = DFC_ARG_TOOSMALL;
6302 		goto done;
6303 	}
6304 
6305 	if (!dfc->buf4 || !dfc->buf4_size) {
6306 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6307 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
6308 
6309 		rval = DFC_ARG_NULL;
6310 		goto done;
6311 	}
6312 
6313 	if (dfc->buf4_size < sizeof (uint32_t)) {
6314 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6315 		    "%s: Buffer4 too small. (size=%d)",
6316 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size);
6317 
6318 		rval = DFC_ARG_TOOSMALL;
6319 		goto done;
6320 	}
6321 
6322 	if (ddi_copyin((void *)dfc->buf3, (void *)&destid,
6323 	    sizeof (dfc_destid_t), mode) != 0) {
6324 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6325 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6326 
6327 		rval = DFC_COPYIN_ERROR;
6328 		goto done;
6329 	}
6330 
6331 	if (destid.idType == 0) {
6332 		if ((ndlp = emlxs_node_find_wwpn(port, destid.wwpn)) == NULL) {
6333 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6334 			    "%s: WWPN does not exists. %s",
6335 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
6336 			    destid.wwpn));
6337 
6338 			rval = DFC_ARG_INVALID;
6339 			goto done;
6340 		}
6341 		did = ndlp->nlp_DID;
6342 	} else {
6343 		if (emlxs_node_find_did(port, destid.d_id) == NULL) {
6344 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6345 			    "%s: DID does not exist. did=%x",
6346 			    emlxs_dfc_xlate(dfc->cmd), destid.d_id);
6347 
6348 			rval = DFC_ARG_INVALID;
6349 			goto done;
6350 		}
6351 		did = destid.d_id;
6352 	}
6353 
6354 	if (did == 0) {
6355 		did = port->did;
6356 	}
6357 
6358 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) {
6359 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6360 		    "%s: Unable to allocate packet.",
6361 		    emlxs_dfc_xlate(dfc->cmd));
6362 
6363 		rval = DFC_SYSRES_ERROR;
6364 		goto done;
6365 	}
6366 
6367 	/* Make this a polled IO */
6368 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
6369 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6370 	pkt->pkt_comp = NULL;
6371 
6372 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6373 	pkt->pkt_timeout = (timeout) ? timeout : 30;
6374 
6375 	/* Build the fc header */
6376 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
6377 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
6378 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
6379 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
6380 	pkt->pkt_cmd_fhdr.f_ctl =
6381 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
6382 	pkt->pkt_cmd_fhdr.seq_id = 0;
6383 	pkt->pkt_cmd_fhdr.df_ctl = 0;
6384 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
6385 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
6386 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
6387 	pkt->pkt_cmd_fhdr.ro = 0;
6388 
6389 	/* Copy in the command buffer */
6390 	if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size,
6391 	    mode) != 0) {
6392 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6393 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6394 
6395 		rval = DFC_COPYIN_ERROR;
6396 		goto done;
6397 	}
6398 
6399 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
6400 		rval = DFC_IO_ERROR;
6401 		goto done;
6402 	}
6403 
6404 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
6405 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
6406 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6407 			    "Pkt Transport error. Pkt Timeout.");
6408 			rval = DFC_TIMEOUT;
6409 		} else {
6410 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6411 			    "Pkt Transport error. state=%x", pkt->pkt_state);
6412 			rval = DFC_IO_ERROR;
6413 		}
6414 		goto done;
6415 	}
6416 
6417 	rsp_size -= pkt->pkt_resp_resid;
6418 	if (ddi_copyout((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size,
6419 	    mode) != 0) {
6420 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6421 		    "%s: rsp_buf ddi_copyout failed.",
6422 		    emlxs_dfc_xlate(dfc->cmd));
6423 
6424 		rval = DFC_COPYOUT_ERROR;
6425 		goto done;
6426 	}
6427 
6428 	if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf4,
6429 	    sizeof (uint32_t), mode) != 0) {
6430 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6431 		    "%s: rsp_size ddi_copyout failed.",
6432 		    emlxs_dfc_xlate(dfc->cmd));
6433 
6434 		rval = DFC_COPYOUT_ERROR;
6435 		goto done;
6436 	}
6437 
6438 	rval = 0;
6439 
6440 done:
6441 	if (pkt) {
6442 		emlxs_pkt_free(pkt);
6443 	}
6444 
6445 	return (rval);
6446 
6447 } /* emlxs_dfc_send_els() */
6448 
6449 
6450 static int32_t
6451 emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6452 {
6453 	emlxs_port_t	*port = &PPORT;
6454 	dfc_ioinfo_t	ioinfo;
6455 	uint32_t	i;
6456 
6457 	if (!dfc->buf1 || !dfc->buf1_size) {
6458 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6459 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6460 
6461 		return (DFC_ARG_NULL);
6462 	}
6463 
6464 	if (dfc->buf1_size < sizeof (dfc_ioinfo_t)) {
6465 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6466 		    "%s: Buffer1 too small. (size=%d)",
6467 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6468 
6469 		return (DFC_ARG_TOOSMALL);
6470 	}
6471 
6472 	bzero(&ioinfo, sizeof (dfc_ioinfo_t));
6473 
6474 	ioinfo.a_mboxCmd = HBASTATS.MboxIssued;
6475 	ioinfo.a_mboxCmpl = HBASTATS.MboxCompleted;
6476 	ioinfo.a_mboxErr = HBASTATS.MboxError;
6477 
6478 	for (i = 0; i < hba->chan_count; i++) {
6479 		ioinfo.a_iocbCmd += HBASTATS.IocbIssued[i];
6480 		ioinfo.a_iocbRsp += HBASTATS.IocbReceived[i];
6481 	}
6482 
6483 	ioinfo.a_adapterIntr = HBASTATS.IntrEvent[0] + HBASTATS.IntrEvent[1] +
6484 	    HBASTATS.IntrEvent[2] + HBASTATS.IntrEvent[3] +
6485 	    HBASTATS.IntrEvent[4] + HBASTATS.IntrEvent[5] +
6486 	    HBASTATS.IntrEvent[6] + HBASTATS.IntrEvent[7];
6487 
6488 	ioinfo.a_fcpCmd = HBASTATS.FcpIssued;
6489 	ioinfo.a_fcpCmpl = HBASTATS.FcpCompleted;
6490 	ioinfo.a_fcpErr = HBASTATS.FcpCompleted - HBASTATS.FcpGood;
6491 
6492 	ioinfo.a_seqXmit = HBASTATS.IpSeqIssued;
6493 	ioinfo.a_seqRcv = HBASTATS.IpSeqReceived;
6494 	ioinfo.a_seqXmitErr = HBASTATS.IpSeqCompleted - HBASTATS.IpSeqGood;
6495 
6496 	ioinfo.a_bcastXmit = HBASTATS.IpBcastIssued;
6497 	ioinfo.a_bcastRcv = HBASTATS.IpBcastReceived;
6498 
6499 	ioinfo.a_elsXmit = HBASTATS.ElsCmdIssued;
6500 	ioinfo.a_elsRcv = HBASTATS.ElsCmdReceived;
6501 	ioinfo.a_elsXmitErr = HBASTATS.ElsCmdCompleted - HBASTATS.ElsCmdGood;
6502 
6503 	ioinfo.a_RSCNRcv = HBASTATS.ElsRscnReceived;
6504 
6505 	ioinfo.a_elsBufPost = HBASTATS.ElsUbPosted;
6506 	ioinfo.a_ipBufPost = HBASTATS.IpUbPosted;
6507 
6508 	ioinfo.a_cnt1 = 0;
6509 	ioinfo.a_cnt2 = 0;
6510 	ioinfo.a_cnt3 = 0;
6511 	ioinfo.a_cnt4 = 0;
6512 
6513 	if (ddi_copyout((void *)&ioinfo, (void *)dfc->buf1,
6514 	    sizeof (dfc_ioinfo_t), mode) != 0) {
6515 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6516 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6517 
6518 		return (DFC_COPYOUT_ERROR);
6519 	}
6520 
6521 	return (0);
6522 
6523 } /* emlxs_dfc_get_ioinfo() */
6524 
6525 
6526 static int32_t
6527 emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6528 {
6529 	emlxs_port_t	*port = &PPORT;
6530 	dfc_linkinfo_t	linkinfo;
6531 
6532 	if (!dfc->buf1 || !dfc->buf1_size) {
6533 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6534 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6535 
6536 		return (DFC_ARG_NULL);
6537 	}
6538 
6539 	if (dfc->buf1_size < sizeof (dfc_linkinfo_t)) {
6540 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6541 		    "%s: Buffer1 too small. (size=%d)",
6542 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6543 
6544 		return (DFC_ARG_TOOSMALL);
6545 	}
6546 
6547 	bzero(&linkinfo, sizeof (dfc_linkinfo_t));
6548 
6549 	linkinfo.a_linkEventTag = hba->link_event_tag;
6550 	linkinfo.a_linkUp = HBASTATS.LinkUp;
6551 	linkinfo.a_linkDown = HBASTATS.LinkDown;
6552 	linkinfo.a_linkMulti = HBASTATS.LinkMultiEvent;
6553 	linkinfo.a_DID = port->did;
6554 	linkinfo.a_topology = 0;
6555 
6556 	if (hba->state <= FC_LINK_DOWN) {
6557 		linkinfo.a_linkState = LNK_DOWN;
6558 	}
6559 #ifdef MENLO_SUPPORT
6560 	else if (hba->flag & FC_MENLO_MODE) {
6561 		linkinfo.a_linkState = LNK_DOWN;
6562 		linkinfo.a_topology  = LNK_MENLO_MAINTENANCE;
6563 
6564 	}
6565 #endif /* MENLO_SUPPORT */
6566 	else if (hba->state == FC_LINK_DOWN_PERSIST) {
6567 		linkinfo.a_linkState = LNK_DOWN_PERSIST;
6568 	} else if (hba->state < FC_READY) {
6569 		linkinfo.a_linkState = LNK_DISCOVERY;
6570 	} else {
6571 		linkinfo.a_linkState = LNK_READY;
6572 	}
6573 
6574 	if (linkinfo.a_linkState != LNK_DOWN) {
6575 		if (hba->topology == TOPOLOGY_LOOP) {
6576 			if (hba->flag & FC_FABRIC_ATTACHED) {
6577 				linkinfo.a_topology = LNK_PUBLIC_LOOP;
6578 			} else {
6579 				linkinfo.a_topology = LNK_LOOP;
6580 			}
6581 
6582 			linkinfo.a_alpa = port->did & 0xff;
6583 			linkinfo.a_alpaCnt = port->alpa_map[0];
6584 
6585 			if (linkinfo.a_alpaCnt > 127) {
6586 				linkinfo.a_alpaCnt = 127;
6587 			}
6588 
6589 			bcopy((void *)&port->alpa_map[0], linkinfo.a_alpaMap,
6590 			    linkinfo.a_alpaCnt+1);
6591 		} else {
6592 			if (hba->flag & FC_FABRIC_ATTACHED) {
6593 				linkinfo.a_topology = LNK_FABRIC;
6594 			} else {
6595 				linkinfo.a_topology = LNK_PT2PT;
6596 			}
6597 		}
6598 	}
6599 
6600 	bcopy(&hba->wwpn, linkinfo.a_wwpName, 8);
6601 	bcopy(&hba->wwnn, linkinfo.a_wwnName, 8);
6602 
6603 	if (ddi_copyout((void *)&linkinfo, (void *)dfc->buf1,
6604 	    sizeof (dfc_linkinfo_t), mode) != 0) {
6605 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6606 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6607 
6608 		return (DFC_COPYOUT_ERROR);
6609 	}
6610 
6611 	return (0);
6612 
6613 } /* emlxs_dfc_get_linkinfo() */
6614 
6615 #ifdef SFCT_SUPPORT
6616 static int32_t
6617 emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6618 {
6619 	emlxs_port_t		*port = &PPORT;
6620 	emlxs_tgtport_stat_t	*statp = &TGTPORTSTAT;
6621 	dfc_tgtport_stat_t	dfcstat;
6622 
6623 	if (!dfc->buf1 || !dfc->buf1_size) {
6624 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6625 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6626 
6627 		return (DFC_ARG_NULL);
6628 	}
6629 
6630 	if (dfc->buf1_size < sizeof (emlxs_tgtport_stat_t)) {
6631 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6632 		    "%s: Buffer1 too small. (size=%d)",
6633 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6634 
6635 		return (DFC_ARG_TOOSMALL);
6636 	}
6637 
6638 	bzero(&dfcstat, sizeof (dfcstat));
6639 
6640 	dfcstat.Version = DFC_TGTPORT_STAT_VERSION;
6641 
6642 	dfcstat.FctRcvDropped = statp->FctRcvDropped;
6643 	dfcstat.FctOverQDepth = statp->FctOverQDepth;
6644 	dfcstat.FctOutstandingIO = statp->FctOutstandingIO;
6645 	dfcstat.FctFailedPortRegister = statp->FctFailedPortRegister;
6646 	dfcstat.FctPortRegister = statp->FctPortRegister;
6647 	dfcstat.FctPortDeregister = statp->FctPortDeregister;
6648 
6649 	dfcstat.FctAbortSent = statp->FctAbortSent;
6650 	dfcstat.FctNoBuffer = statp->FctNoBuffer;
6651 	dfcstat.FctScsiStatusErr = statp->FctScsiStatusErr;
6652 	dfcstat.FctScsiQfullErr = statp->FctScsiQfullErr;
6653 	dfcstat.FctScsiResidOver = statp->FctScsiResidOver;
6654 	dfcstat.FctScsiResidUnder = statp->FctScsiResidUnder;
6655 	dfcstat.FctScsiSenseErr = statp->FctScsiSenseErr;
6656 
6657 	dfcstat.FctEvent = statp->FctEvent;
6658 	dfcstat.FctCompleted = statp->FctCompleted;
6659 	dfcstat.FctCmplGood = statp->FctCmplGood;
6660 	dfcstat.FctCmplError = statp->FctCmplError;
6661 	dfcstat.FctStray = statp->FctStray;
6662 
6663 	bcopy(&statp->FctP2IOWcnt[0], &dfcstat.FctP2IOWcnt[0],
6664 	    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6665 	bcopy(&statp->FctP2IORcnt[0], &dfcstat.FctP2IORcnt[0],
6666 	    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6667 	dfcstat.FctIOCmdCnt = statp->FctIOCmdCnt;
6668 	dfcstat.FctReadBytes = statp->FctReadBytes;
6669 	dfcstat.FctWriteBytes = statp->FctWriteBytes;
6670 	dfcstat.FctCmdReceived = statp->FctCmdReceived;
6671 
6672 	if (dfc->flag) {	/* Clear counters after read */
6673 		bzero(&statp->FctP2IOWcnt[0],
6674 		    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6675 		bzero(&statp->FctP2IORcnt[0],
6676 		    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6677 		statp->FctIOCmdCnt = 0;
6678 		statp->FctReadBytes = 0;
6679 		statp->FctWriteBytes = 0;
6680 		statp->FctCmdReceived = 0;
6681 	}
6682 	if (hba->state <= FC_LINK_DOWN) {
6683 		dfcstat.FctLinkState = LNK_DOWN;
6684 	}
6685 #ifdef MENLO_SUPPORT
6686 	else if (hba->flag & FC_MENLO_MODE) {
6687 		dfcstat.FctLinkState = LNK_DOWN;
6688 	}
6689 #endif /* MENLO_SUPPORT */
6690 	else if (hba->state < FC_READY) {
6691 		dfcstat.FctLinkState = LNK_DISCOVERY;
6692 	} else {
6693 		dfcstat.FctLinkState = LNK_READY;
6694 	}
6695 
6696 	if (ddi_copyout((void *)&dfcstat, (void *)dfc->buf1,
6697 	    sizeof (dfc_tgtport_stat_t), mode) != 0) {
6698 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6699 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6700 
6701 		return (DFC_COPYOUT_ERROR);
6702 	}
6703 
6704 	return (0);
6705 
6706 } /* emlxs_dfc_get_fctstat() */
6707 #endif /* SFCT_SUPPORT */
6708 
6709 static int32_t
6710 emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6711 {
6712 	emlxs_port_t	*port;
6713 	emlxs_config_t	*cfg = &CFG;
6714 	dfc_node_t	*dfc_node;
6715 	dfc_node_t	*dnp;
6716 	uint32_t	node_count;
6717 	NODELIST	*nlp;
6718 	uint32_t	size;
6719 	uint32_t	i;
6720 
6721 	port = &VPORT(dfc->data1);
6722 
6723 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
6724 	    emlxs_dfc_xlate(dfc->cmd));
6725 
6726 	if (!dfc->buf1 || !dfc->buf1_size) {
6727 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6728 		    "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6729 
6730 		return (DFC_ARG_NULL);
6731 	}
6732 
6733 	if (dfc->buf1_size < (sizeof (dfc_node_t) * MAX_NODES)) {
6734 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6735 		    "%s: Buffer1 too small. (size=%d)",
6736 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6737 
6738 		return (DFC_ARG_TOOSMALL);
6739 	}
6740 
6741 	if (!dfc->buf2 || !dfc->buf2_size) {
6742 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6743 		    "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
6744 
6745 		return (DFC_ARG_NULL);
6746 	}
6747 
6748 	if (dfc->buf2_size < sizeof (uint32_t)) {
6749 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6750 		    "%s: Buffer2 too small. (size=%d)",
6751 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
6752 
6753 		return (DFC_ARG_TOOSMALL);
6754 	}
6755 
6756 	node_count = port->node_count;
6757 
6758 	if (node_count == 0) {
6759 		return (0);
6760 	}
6761 
6762 	if (node_count > MAX_NODES) {
6763 		node_count = MAX_NODES;
6764 	}
6765 
6766 	size = node_count * sizeof (dfc_node_t);
6767 
6768 	if (!(dfc_node = (dfc_node_t *)kmem_zalloc(size, KM_NOSLEEP))) {
6769 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6770 		    "%s: Unable to allocate dfc_node.",
6771 		    emlxs_dfc_xlate(dfc->cmd));
6772 
6773 		return (DFC_SYSRES_ERROR);
6774 	}
6775 
6776 	dnp = dfc_node;
6777 
6778 	rw_enter(&port->node_rwlock, RW_READER);
6779 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
6780 		nlp = port->node_table[i];
6781 		while (nlp != NULL) {
6782 			dnp->port_id = nlp->nlp_DID;
6783 			dnp->rpi = nlp->nlp_Rpi;
6784 			dnp->xri = nlp->nlp_Xri;
6785 
6786 			bcopy((char *)&nlp->sparm, (char *)&dnp->sparm,
6787 			    sizeof (dnp->sparm));
6788 
6789 			if (nlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE) {
6790 				dnp->flags |= PORT_FLAG_FCP_TARGET;
6791 			}
6792 			if (nlp->nlp_fcp_info & NLP_FCP_INI_DEVICE) {
6793 				dnp->flags |= PORT_FLAG_FCP_INI;
6794 
6795 			}
6796 			if (nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
6797 				dnp->flags |= PORT_FLAG_FCP2;
6798 			}
6799 			if (cfg[CFG_NETWORK_ON].current && nlp->nlp_Xri) {
6800 				dnp->flags |= PORT_FLAG_IP;
6801 			}
6802 			if (nlp->nlp_fcp_info & NLP_EMLX_VPORT) {
6803 				dnp->flags |= PORT_FLAG_VPORT;
6804 			}
6805 
6806 			dnp++;
6807 			nlp = (NODELIST *) nlp->nlp_list_next;
6808 		}
6809 	}
6810 	rw_exit(&port->node_rwlock);
6811 
6812 	if (ddi_copyout((void *)dfc_node, (void *)dfc->buf1, size, mode) != 0) {
6813 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6814 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6815 
6816 		kmem_free(dfc_node, size);
6817 		return (DFC_COPYOUT_ERROR);
6818 	}
6819 
6820 	if (ddi_copyout((void *)&node_count, (void *)dfc->buf2,
6821 	    sizeof (uint32_t), mode) != 0) {
6822 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6823 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6824 
6825 		kmem_free(dfc_node, size);
6826 		return (DFC_COPYOUT_ERROR);
6827 	}
6828 
6829 	kmem_free(dfc_node, size);
6830 
6831 	return (0);
6832 
6833 } /* emlxs_dfc_get_nodeinfo() */
6834 
6835 
6836 static int32_t
6837 emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6838 {
6839 	emlxs_port_t	*port = &PPORT;
6840 	uint32_t	offset;
6841 	uint32_t	size;
6842 	uint32_t	max_size;
6843 	uint8_t		*buffer;
6844 	uint8_t		*slim;
6845 
6846 	offset = dfc->data1;
6847 	size = dfc->data2;
6848 
6849 	if (!dfc->buf1 || !dfc->buf1_size) {
6850 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6851 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6852 
6853 		return (DFC_ARG_NULL);
6854 	}
6855 
6856 	if (size > dfc->buf1_size) {
6857 		size = dfc->buf1_size;
6858 	}
6859 
6860 	if (offset % 4) {
6861 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6862 		    "%s: Offset misaligned. (offset=%d)",
6863 		    emlxs_dfc_xlate(dfc->cmd), offset);
6864 
6865 		return (DFC_ARG_MISALIGNED);
6866 	}
6867 
6868 	if (size % 4) {
6869 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6870 		    "%s: Size misaligned. (size=%d)",
6871 		    emlxs_dfc_xlate(dfc->cmd), size);
6872 
6873 		return (DFC_ARG_MISALIGNED);
6874 	}
6875 
6876 	if (hba->flag & FC_SLIM2_MODE) {
6877 		max_size = SLI2_SLIM2_SIZE;
6878 	} else {
6879 		max_size = 4096;
6880 	}
6881 
6882 	if (offset >= max_size) {
6883 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6884 		    "%s: Offset too large. (offset=%d)",
6885 		    emlxs_dfc_xlate(dfc->cmd), offset);
6886 
6887 		return (DFC_ARG_TOOBIG);
6888 	}
6889 
6890 	if ((size + offset) > max_size) {
6891 		size = (max_size - offset);
6892 	}
6893 
6894 	if (!(buffer = (uint8_t *)kmem_zalloc(size, KM_NOSLEEP))) {
6895 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6896 		    "%s: Unable to allocate buffer.",
6897 		    emlxs_dfc_xlate(dfc->cmd));
6898 
6899 		return (DFC_SYSRES_ERROR);
6900 	}
6901 
6902 	if (hba->flag & FC_SLIM2_MODE) {
6903 		slim = (uint8_t *)hba->sli.sli3.slim2.virt + offset;
6904 		BE_SWAP32_BCOPY((uint8_t *)slim, (uint8_t *)buffer, size);
6905 	} else {
6906 		slim = (uint8_t *)hba->sli.sli3.slim_addr + offset;
6907 		READ_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)slim,
6908 		    (size / 4));
6909 	}
6910 
6911 	if (ddi_copyout((void *)buffer, (void *)dfc->buf1, size, mode) != 0) {
6912 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6913 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6914 
6915 		kmem_free(buffer, size);
6916 		return (DFC_COPYOUT_ERROR);
6917 	}
6918 
6919 	kmem_free(buffer, size);
6920 
6921 #ifdef FMA_SUPPORT
6922 	/* Access handle validation */
6923 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
6924 	    != DDI_FM_OK) {
6925 		EMLXS_MSGF(EMLXS_CONTEXT,
6926 		    &emlxs_invalid_access_handle_msg, NULL);
6927 		return (DFC_DRV_ERROR);
6928 	}
6929 #endif  /* FMA_SUPPORT */
6930 
6931 	return (0);
6932 
6933 } /* emlxs_dfc_read_mem() */
6934 
6935 
6936 static int32_t
6937 emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6938 {
6939 	emlxs_port_t	*port = &PPORT;
6940 	uint32_t	offset;
6941 	uint32_t	size;
6942 	uint32_t	max_size;
6943 	uint8_t		*buffer;
6944 	uint8_t		*slim;
6945 
6946 	offset = dfc->data1;
6947 	size = dfc->data2;
6948 
6949 	if (!dfc->buf1 || !dfc->buf1_size) {
6950 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6951 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6952 
6953 		return (DFC_ARG_NULL);
6954 	}
6955 
6956 	if (size > dfc->buf1_size) {
6957 		size = dfc->buf1_size;
6958 	}
6959 
6960 	if (offset % 4) {
6961 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6962 		    "%s: Offset misaligned. (offset=%d)",
6963 		    emlxs_dfc_xlate(dfc->cmd), offset);
6964 
6965 		return (DFC_ARG_MISALIGNED);
6966 	}
6967 
6968 	if (size % 4) {
6969 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6970 		    "%s: Size misaligned. (szie=%d)",
6971 		    emlxs_dfc_xlate(dfc->cmd), size);
6972 
6973 		return (DFC_ARG_MISALIGNED);
6974 	}
6975 
6976 	if (hba->flag & FC_SLIM2_MODE) {
6977 		max_size = SLI2_SLIM2_SIZE;
6978 	} else {
6979 		max_size = 4096;
6980 	}
6981 
6982 	if (offset >= max_size) {
6983 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6984 		    "%s: Offset too large. (offset=%d)",
6985 		    emlxs_dfc_xlate(dfc->cmd), offset);
6986 
6987 		return (DFC_ARG_TOOBIG);
6988 	}
6989 
6990 	if ((size + offset) > max_size) {
6991 		size = (max_size - offset);
6992 	}
6993 
6994 	if (!(buffer = (uint8_t *)kmem_zalloc(size, KM_NOSLEEP))) {
6995 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6996 		    "%s: Unable to allocate buffer.",
6997 		    emlxs_dfc_xlate(dfc->cmd));
6998 
6999 		return (DFC_SYSRES_ERROR);
7000 	}
7001 
7002 	if (ddi_copyin((void *)dfc->buf1, (void *)buffer, size, mode) != 0) {
7003 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7004 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
7005 
7006 		kmem_free(buffer, size);
7007 		return (DFC_COPYIN_ERROR);
7008 	}
7009 
7010 	if (hba->flag & FC_SLIM2_MODE) {
7011 		slim = (uint8_t *)hba->sli.sli3.slim2.virt + offset;
7012 		BE_SWAP32_BCOPY((uint8_t *)buffer, (uint8_t *)slim, size);
7013 	} else {
7014 		slim = (uint8_t *)hba->sli.sli3.slim_addr + offset;
7015 		WRITE_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)slim,
7016 		    (size / 4));
7017 	}
7018 
7019 	kmem_free(buffer, size);
7020 
7021 #ifdef FMA_SUPPORT
7022 	/* Access handle validation */
7023 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
7024 	    != DDI_FM_OK) {
7025 		EMLXS_MSGF(EMLXS_CONTEXT,
7026 		    &emlxs_invalid_access_handle_msg, NULL);
7027 		return (DFC_DRV_ERROR);
7028 	}
7029 #endif  /* FMA_SUPPORT */
7030 
7031 	return (0);
7032 
7033 } /* emlxs_dfc_write_mem() */
7034 
7035 
7036 /* ARGSUSED */
7037 static int32_t
7038 emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7039 {
7040 	emlxs_port_t	*port = &PPORT;
7041 	uint32_t	offset;
7042 	uint32_t	value;
7043 
7044 	offset = dfc->data1;
7045 	value = dfc->data2;
7046 
7047 	if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
7048 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7049 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
7050 
7051 		return (DFC_FCOE_NOTSUPPORTED);
7052 	}
7053 
7054 	if (!(hba->flag & FC_OFFLINE_MODE)) {
7055 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7056 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
7057 
7058 		return (DFC_ONLINE_ERROR);
7059 	}
7060 
7061 	if (offset % 4) {
7062 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7063 		    "%s: Offset misaligned. (offset=%d)",
7064 		    emlxs_dfc_xlate(dfc->cmd), offset);
7065 
7066 		return (DFC_ARG_MISALIGNED);
7067 	}
7068 
7069 	if (offset > 255) {
7070 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7071 		    "%s: Offset too large. (offset=%d)",
7072 		    emlxs_dfc_xlate(dfc->cmd), offset);
7073 
7074 		return (DFC_ARG_TOOBIG);
7075 	}
7076 
7077 	WRITE_CSR_REG(hba, (hba->sli.sli3.csr_addr + offset), value);
7078 
7079 #ifdef FMA_SUPPORT
7080 	/* Access handle validation */
7081 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle)
7082 	    != DDI_FM_OK) {
7083 		EMLXS_MSGF(EMLXS_CONTEXT,
7084 		    &emlxs_invalid_access_handle_msg, NULL);
7085 		return (DFC_DRV_ERROR);
7086 	}
7087 #endif  /* FMA_SUPPORT */
7088 
7089 	return (0);
7090 
7091 } /* emlxs_dfc_write_ctlreg() */
7092 
7093 
7094 static int32_t
7095 emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7096 {
7097 	emlxs_port_t	*port = &PPORT;
7098 	uint32_t	offset;
7099 	uint32_t	value;
7100 
7101 	offset = dfc->data1;
7102 
7103 	if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
7104 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7105 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
7106 
7107 		return (DFC_FCOE_NOTSUPPORTED);
7108 	}
7109 
7110 	if (offset % 4) {
7111 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7112 		    "%s: Offset misaligned. (offset=%d)",
7113 		    emlxs_dfc_xlate(dfc->cmd), offset);
7114 
7115 		return (DFC_ARG_MISALIGNED);
7116 	}
7117 
7118 	if (offset > 255) {
7119 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7120 		    "%s: Offset too large. (offset=%d)",
7121 		    emlxs_dfc_xlate(dfc->cmd), offset);
7122 
7123 		return (DFC_ARG_TOOBIG);
7124 	}
7125 
7126 	if (!dfc->buf1 || !dfc->buf1_size) {
7127 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7128 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
7129 
7130 		return (DFC_ARG_NULL);
7131 	}
7132 
7133 	if (dfc->buf1_size < sizeof (uint32_t)) {
7134 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7135 		    "%s: Buffer1 too small. (size=%d)",
7136 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7137 
7138 		return (DFC_ARG_TOOSMALL);
7139 	}
7140 
7141 	value = READ_CSR_REG(hba, (hba->sli.sli3.csr_addr + offset));
7142 
7143 	if (ddi_copyout((void *)&value, (void *)dfc->buf1, sizeof (uint32_t),
7144 	    mode) != 0) {
7145 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7146 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7147 
7148 		return (DFC_COPYOUT_ERROR);
7149 	}
7150 
7151 #ifdef FMA_SUPPORT
7152 	/* Access handle validation */
7153 	if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle)
7154 	    != DDI_FM_OK) {
7155 		EMLXS_MSGF(EMLXS_CONTEXT,
7156 		    &emlxs_invalid_access_handle_msg, NULL);
7157 		return (DFC_DRV_ERROR);
7158 	}
7159 #endif  /* FMA_SUPPORT */
7160 
7161 	return (0);
7162 
7163 } /* emlxs_dfc_read_ctlreg() */
7164 
7165 
7166 static int32_t
7167 emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7168 {
7169 	emlxs_port_t		*port = &PPORT;
7170 	uint32_t		event;
7171 	uint32_t		enable;
7172 	uint32_t		pid;
7173 	uint32_t		count;
7174 	uint32_t		i;
7175 	emlxs_dfc_event_t	*dfc_event;
7176 
7177 	event = dfc->data1;
7178 	pid = dfc->data2;
7179 	enable = dfc->flag;
7180 
7181 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7182 	    "%s: %s. pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd),
7183 	    emlxs_dfc_event_xlate(event), pid, enable);
7184 
7185 	switch (event) {
7186 	case FC_REG_LINK_EVENT:
7187 	case FC_REG_RSCN_EVENT:
7188 	case FC_REG_CT_EVENT:
7189 	case FC_REG_DUMP_EVENT:
7190 	case FC_REG_TEMP_EVENT:
7191 	case FC_REG_VPORTRSCN_EVENT:
7192 	case FC_REG_FCOE_EVENT:
7193 		break;
7194 
7195 	case FC_REG_MULTIPULSE_EVENT:
7196 	default:
7197 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7198 		    "%s: %s. Invalid event. pid=%d enable=%d",
7199 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7200 		    pid, enable);
7201 
7202 		return (DFC_ARG_INVALID);
7203 	}
7204 
7205 	if (enable) {
7206 		if (dfc->buf1_size < sizeof (uint32_t)) {
7207 			dfc->buf1 = NULL;
7208 		} else if (!dfc->buf1) {
7209 			dfc->buf1_size = 0;
7210 		}
7211 
7212 		/* Make sure this pid/event is not already registered */
7213 		dfc_event = NULL;
7214 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7215 			dfc_event = &hba->dfc_event[i];
7216 
7217 			if (dfc_event->pid == pid &&
7218 			    dfc_event->event == event) {
7219 				break;
7220 			}
7221 		}
7222 
7223 		if (i == MAX_DFC_EVENTS) {
7224 			/* Find next available event object */
7225 			for (i = 0; i < MAX_DFC_EVENTS; i++) {
7226 				dfc_event = &hba->dfc_event[i];
7227 
7228 				if (!dfc_event->pid && !dfc_event->event) {
7229 					break;
7230 				}
7231 			}
7232 
7233 			/* Return if all event objects are busy */
7234 			if (i == MAX_DFC_EVENTS) {
7235 				EMLXS_MSGF(EMLXS_CONTEXT,
7236 				    &emlxs_dfc_error_msg,
7237 				    "%s: %s. Too many events registered. "
7238 				    "pid=%d enable=%d",
7239 				    emlxs_dfc_xlate(dfc->cmd),
7240 				    emlxs_dfc_event_xlate(event), pid,
7241 				    enable);
7242 
7243 				return (DFC_DRVRES_ERROR);
7244 			}
7245 		}
7246 
7247 		/* Initialize */
7248 		dfc_event->pid = pid;
7249 		dfc_event->event = event;
7250 		dfc_event->last_id = (uint32_t)-1;
7251 		dfc_event->dataout = NULL;
7252 		dfc_event->size = 0;
7253 		dfc_event->mode = 0;
7254 
7255 		(void) emlxs_get_dfc_event(port, dfc_event, 0);
7256 
7257 		if (dfc->buf1) {
7258 			if (ddi_copyout((void *)&dfc_event->last_id,
7259 			    dfc->buf1, sizeof (uint32_t), mode) != 0) {
7260 				EMLXS_MSGF(EMLXS_CONTEXT,
7261 				    &emlxs_dfc_error_msg,
7262 				    "%s: ddi_copyout failed.",
7263 				    emlxs_dfc_xlate(dfc->cmd));
7264 
7265 				return (DFC_COPYOUT_ERROR);
7266 			}
7267 		}
7268 
7269 		/*
7270 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7271 		 * "%s: %s. Enabled. pid=%d id=%d", emlxs_dfc_xlate(dfc->cmd),
7272 		 * emlxs_dfc_event_xlate(event), pid, dfc_event->last_id);
7273 		 */
7274 
7275 		hba->event_mask |= event;
7276 
7277 	} else {	/* Disable */
7278 
7279 		/* Find the event entry */
7280 		dfc_event = NULL;
7281 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7282 			dfc_event = &hba->dfc_event[i];
7283 
7284 			if (dfc_event->pid == pid &&
7285 			    dfc_event->event == event) {
7286 				break;
7287 			}
7288 		}
7289 
7290 		if (i == MAX_DFC_EVENTS) {
7291 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7292 			    "%s: %s. Event not registered. pid=%d enable=%d",
7293 			    emlxs_dfc_xlate(dfc->cmd),
7294 			    emlxs_dfc_event_xlate(event), pid, enable);
7295 
7296 			return (DFC_ARG_INVALID);
7297 		}
7298 
7299 		/* Kill the event thread if it is sleeping */
7300 		(void) emlxs_kill_dfc_event(port, dfc_event);
7301 
7302 		/* Count the number of pids still registered for this event */
7303 		count = 0;
7304 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7305 			dfc_event = &hba->dfc_event[i];
7306 
7307 			if (dfc_event->event == event) {
7308 				count++;
7309 			}
7310 		}
7311 
7312 		/* If no more pids need this event, */
7313 		/* then disable logging for this event */
7314 		if (count == 0) {
7315 			hba->event_mask &= ~event;
7316 		}
7317 	}
7318 
7319 	return (0);
7320 
7321 } /* emlxs_dfc_set_event() */
7322 
7323 
7324 static int32_t
7325 emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7326 {
7327 	emlxs_port_t	*port = &PPORT;
7328 	uint32_t	size;
7329 	int32_t		rval = 0;
7330 	HBA_EVENTINFO 	*event_buffer = NULL;
7331 	uint32_t	event_count = 0;
7332 	uint32_t	missed = 0;
7333 
7334 	if (!dfc->buf1 || !dfc->buf1_size) {
7335 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7336 		    "%s: Null buffer1 buffer.", emlxs_dfc_xlate(dfc->cmd));
7337 
7338 		return (DFC_ARG_NULL);
7339 	}
7340 
7341 	event_count = dfc->buf1_size / sizeof (HBA_EVENTINFO);
7342 
7343 	if (!event_count) {
7344 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7345 		    "%s: Buffer1 too small. (size=%d)",
7346 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7347 
7348 		return (DFC_ARG_TOOSMALL);
7349 	}
7350 
7351 	if (!dfc->buf2 || !dfc->buf2_size) {
7352 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7353 		    "%s: Null buffer2 buffer.", emlxs_dfc_xlate(dfc->cmd));
7354 
7355 		return (DFC_ARG_NULL);
7356 	}
7357 
7358 	if (dfc->buf2_size < sizeof (uint32_t)) {
7359 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7360 		    "%s: Buffer2 too small. (size=%d)",
7361 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
7362 
7363 		return (DFC_ARG_TOOSMALL);
7364 	}
7365 
7366 	if (!dfc->buf3 || !dfc->buf3_size) {
7367 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7368 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
7369 
7370 		return (DFC_ARG_NULL);
7371 	}
7372 
7373 	if (dfc->buf3_size < sizeof (uint32_t)) {
7374 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7375 		    "%s: Buffer3 too small. (size=%d)",
7376 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
7377 
7378 		return (DFC_ARG_TOOSMALL);
7379 	}
7380 
7381 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s called. max=%d",
7382 	    emlxs_dfc_xlate(dfc->cmd), event_count);
7383 
7384 	size = (event_count * sizeof (HBA_EVENTINFO));
7385 	event_buffer = (HBA_EVENTINFO *)kmem_zalloc(size, KM_SLEEP);
7386 
7387 	if (emlxs_get_dfc_eventinfo(port, event_buffer, &event_count,
7388 	    &missed) != 0) {
7389 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7390 		    "%s: emlxs_get_dfc_eventinfo failed.",
7391 		    emlxs_dfc_xlate(dfc->cmd));
7392 
7393 		rval = DFC_DRV_ERROR;
7394 		goto done;
7395 	}
7396 
7397 	if (event_count) {
7398 		if (ddi_copyout((void *)event_buffer, dfc->buf1,
7399 		    (event_count * sizeof (HBA_EVENTINFO)), mode) != 0) {
7400 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7401 			    "%s: ddi_copyout failed.",
7402 			    emlxs_dfc_xlate(dfc->cmd));
7403 
7404 			rval = DFC_COPYOUT_ERROR;
7405 			goto done;
7406 		}
7407 	}
7408 
7409 	if (ddi_copyout((void *)&event_count, dfc->buf2, sizeof (uint32_t),
7410 	    mode) != 0) {
7411 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7412 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7413 
7414 		rval = DFC_COPYOUT_ERROR;
7415 		goto done;
7416 	}
7417 
7418 	if (ddi_copyout((void *)&missed, dfc->buf3, sizeof (uint32_t),
7419 	    mode) != 0) {
7420 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7421 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7422 
7423 		rval = DFC_COPYOUT_ERROR;
7424 		goto done;
7425 	}
7426 
7427 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7428 	    "%s: events=%d missed=%d new=%d last_id=%d",
7429 	    emlxs_dfc_xlate(dfc->cmd), event_count, hba->hba_event.missed,
7430 	    hba->hba_event.new, hba->hba_event.last_id);
7431 
7432 done:
7433 
7434 	if (event_buffer) {
7435 		kmem_free(event_buffer, size);
7436 	}
7437 
7438 	return (rval);
7439 
7440 } /* emlxs_dfc_get_eventinfo() */
7441 
7442 
7443 static int32_t
7444 emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7445 {
7446 	emlxs_port_t		*port = &PPORT;
7447 	uint32_t		event;
7448 	uint32_t		pid;
7449 	uint32_t		sleep;
7450 	uint32_t		i;
7451 	int32_t			rval = DFC_SUCCESS;
7452 	emlxs_dfc_event_t	*dfc_event;
7453 
7454 	event = dfc->data1;
7455 	pid = dfc->data2;
7456 
7457 	if (!dfc->buf1_size) {
7458 		dfc->buf1 = NULL;
7459 	} else if (!dfc->buf1) {
7460 		dfc->buf1_size = 0;
7461 	}
7462 
7463 	if (dfc->buf2_size < sizeof (uint32_t)) {
7464 		dfc->buf2 = NULL;
7465 	} else if (!dfc->buf2) {
7466 		dfc->buf2_size = 0;
7467 	}
7468 
7469 	if (dfc->buf3_size < sizeof (uint32_t)) {
7470 		dfc->buf3 = NULL;
7471 	} else if (!dfc->buf3) {
7472 		dfc->buf3_size = 0;
7473 	}
7474 
7475 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7476 	    "%s: %s. pid=%d size=%d,%p rcv_size=%d,%p id=%d",
7477 	    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid,
7478 	    dfc->buf1_size, dfc->buf1, dfc->buf2_size, dfc->buf2, dfc->data3);
7479 
7480 	/* Find the event entry */
7481 	dfc_event = NULL;
7482 	for (i = 0; i < MAX_DFC_EVENTS; i++) {
7483 		dfc_event = &hba->dfc_event[i];
7484 
7485 		if (dfc_event->pid == pid && dfc_event->event == event) {
7486 			break;
7487 		}
7488 	}
7489 
7490 	if (i == MAX_DFC_EVENTS) {
7491 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7492 		    "%s: %s. Event not registered. pid=%d",
7493 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7494 		    pid);
7495 
7496 		return (DFC_ARG_INVALID);
7497 	}
7498 
7499 	if (!(hba->event_mask & dfc_event->event)) {
7500 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7501 		    "%s: %s. Event not registered. pid=%d",
7502 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7503 		    pid);
7504 
7505 		return (DFC_ARG_INVALID);
7506 	}
7507 
7508 	/* Initialize event buffer pointers */
7509 	dfc_event->dataout = dfc->buf1;
7510 	dfc_event->size = dfc->buf1_size;
7511 	dfc_event->last_id = dfc->data3;
7512 	dfc_event->mode = mode;
7513 
7514 	sleep = (dfc->flag & 0x01) ? 1 : 0;
7515 
7516 	if ((rval = emlxs_get_dfc_event(port, dfc_event, sleep))) {
7517 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7518 		    "%s: %s. Exiting. pid=%d rsize=%d id=%d rval=%d",
7519 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7520 		    pid, dfc_event->size, dfc_event->last_id, rval);
7521 
7522 		return (rval);
7523 	}
7524 
7525 	if (dfc->buf2) {
7526 		if (ddi_copyout((void *)&dfc_event->size, dfc->buf2,
7527 		    sizeof (uint32_t), mode) != 0) {
7528 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7529 			    "%s: ddi_copyout failed.",
7530 			    emlxs_dfc_xlate(dfc->cmd));
7531 
7532 			return (DFC_COPYOUT_ERROR);
7533 		}
7534 	}
7535 
7536 	if (dfc->buf3) {
7537 		if (ddi_copyout((void *)&dfc_event->last_id, dfc->buf3,
7538 		    sizeof (uint32_t), mode) != 0) {
7539 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7540 			    "%s: ddi_copyout failed.",
7541 			    emlxs_dfc_xlate(dfc->cmd));
7542 
7543 			return (DFC_COPYOUT_ERROR);
7544 		}
7545 	}
7546 
7547 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7548 	    "%s: %s. Completed. pid=%d rsize=%d id=%d",
7549 	    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid,
7550 	    dfc_event->size, dfc_event->last_id);
7551 
7552 	return (rval);
7553 
7554 } /* emlxs_dfc_get_event() */
7555 
7556 
7557 extern uint32_t
7558 emlxs_get_dump_region(emlxs_hba_t *hba, uint32_t region,
7559     uint8_t *buffer, uint32_t *psize)
7560 {
7561 	emlxs_port_t	*port = &PPORT;
7562 	uint32_t	size;
7563 	uint32_t	size_only;
7564 	uint32_t	rval = 0;
7565 	uint8_t		*memptr;
7566 	uint32_t	*wptr;
7567 
7568 	if (!buffer || !(*psize)) {
7569 		size_only = 1;
7570 		size = 0xffffffff;
7571 	} else {
7572 		size_only = 0;
7573 		size = *psize;
7574 	}
7575 
7576 	if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
7577 		if (region != 7) {
7578 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7579 			    "emlxs_get_dump_region: Invalid sli4 region. "
7580 			    "(id=%d)", region);
7581 
7582 			rval = DFC_ARG_INVALID;
7583 			goto done;
7584 		}
7585 	}
7586 
7587 	switch (region) {
7588 	case 0:	/* SLI Registers */
7589 
7590 		if (size < (4 * sizeof (uint32_t))) {
7591 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7592 			    "emlxs_get_dump_region: Buffer too small. "
7593 			    "(SLI Registers: size=%d)", size);
7594 
7595 			rval = DFC_ARG_TOOSMALL;
7596 			goto done;
7597 		}
7598 
7599 		size = (4 * sizeof (uint32_t));
7600 
7601 		if (size_only) {
7602 			break;
7603 		}
7604 
7605 		wptr = (uint32_t *)buffer;
7606 		wptr[0] = READ_CSR_REG(hba, FC_HA_REG(hba));
7607 		wptr[1] = READ_CSR_REG(hba, FC_CA_REG(hba));
7608 		wptr[2] = READ_CSR_REG(hba, FC_HS_REG(hba));
7609 		wptr[3] = READ_CSR_REG(hba, FC_HC_REG(hba));
7610 
7611 #ifdef FMA_SUPPORT
7612 		/* Access handle validation */
7613 		if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.csr_acc_handle)
7614 		    != DDI_FM_OK) {
7615 			EMLXS_MSGF(EMLXS_CONTEXT,
7616 			    &emlxs_invalid_access_handle_msg, NULL);
7617 			rval = DFC_DRV_ERROR;
7618 		}
7619 #endif  /* FMA_SUPPORT */
7620 
7621 		break;
7622 
7623 	case 1:	/* SLIM */
7624 
7625 		if (hba->flag & FC_SLIM2_MODE) {
7626 			size = MIN(SLI2_SLIM2_SIZE, size);
7627 		} else {
7628 			size = MIN(4096, size);
7629 		}
7630 
7631 		if (size_only) {
7632 			break;
7633 		}
7634 
7635 		if (hba->flag & FC_SLIM2_MODE) {
7636 			memptr = (uint8_t *)hba->sli.sli3.slim2.virt;
7637 			BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer,
7638 			    size);
7639 		} else {
7640 			memptr = (uint8_t *)hba->sli.sli3.slim_addr;
7641 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7642 			    (uint32_t *)memptr, (size / 4));
7643 #ifdef FMA_SUPPORT
7644 			/* Access handle validation */
7645 			if (emlxs_fm_check_acc_handle(hba,
7646 			    hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) {
7647 				EMLXS_MSGF(EMLXS_CONTEXT,
7648 				    &emlxs_invalid_access_handle_msg, NULL);
7649 				rval = DFC_DRV_ERROR;
7650 			}
7651 #endif  /* FMA_SUPPORT */
7652 		}
7653 
7654 		break;
7655 
7656 	case 2:	/* Port Control Block */
7657 
7658 		if (size < sizeof (PCB)) {
7659 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7660 			    "emlxs_get_dump_region: Buffer too small. "
7661 			    "(PCB: size=%d)", size);
7662 
7663 			rval = DFC_ARG_TOOSMALL;
7664 			goto done;
7665 		}
7666 
7667 		size = sizeof (PCB);
7668 
7669 		if (size_only) {
7670 			break;
7671 		}
7672 
7673 		memptr = (uint8_t *)&(((SLIM2 *)hba->sli.sli3.slim2.virt)->pcb);
7674 		BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size);
7675 		break;
7676 
7677 	case 3:	/* MailBox */
7678 
7679 		if (size < MAILBOX_CMD_BSIZE) {
7680 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7681 			    "emlxs_get_dump_region: Buffer too small. "
7682 			    "(Mailbox: size=%d)", size);
7683 
7684 			rval = DFC_ARG_TOOSMALL;
7685 			goto done;
7686 		}
7687 
7688 		size = MAILBOX_CMD_BSIZE;
7689 
7690 		if (size_only) {
7691 			break;
7692 		}
7693 
7694 		if (hba->flag & FC_SLIM2_MODE) {
7695 			memptr = (uint8_t *)hba->sli.sli3.slim2.virt;
7696 			BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer,
7697 			    size);
7698 		} else {
7699 			memptr = (uint8_t *)hba->sli.sli3.slim_addr;
7700 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7701 			    (uint32_t *)memptr, (size / 4));
7702 #ifdef FMA_SUPPORT
7703 			/* Access handle validation */
7704 			if (emlxs_fm_check_acc_handle(hba,
7705 			    hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) {
7706 				EMLXS_MSGF(EMLXS_CONTEXT,
7707 				    &emlxs_invalid_access_handle_msg, NULL);
7708 				rval = DFC_DRV_ERROR;
7709 			}
7710 #endif  /* FMA_SUPPORT */
7711 		}
7712 
7713 		break;
7714 
7715 	case 4:	/* Host Put/Get pointer array */
7716 
7717 		if (size < MAX_RINGS * sizeof (HGP)) {
7718 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7719 			    "emlxs_get_dump_region: Buffer too small. "
7720 			    "(HGP: size=%d)", size);
7721 
7722 			rval = DFC_ARG_TOOSMALL;
7723 			goto done;
7724 		}
7725 
7726 		size = MAX_RINGS * sizeof (HGP);
7727 
7728 		if (size_only) {
7729 			break;
7730 		}
7731 
7732 		{
7733 			memptr = (uint8_t *)hba->sli.sli3.slim_addr +
7734 			    hba->sli.sli3.hgp_ring_offset;
7735 
7736 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7737 			    (uint32_t *)memptr, (size / 4));
7738 #ifdef FMA_SUPPORT
7739 			/* Access handle validation */
7740 			if (emlxs_fm_check_acc_handle(hba,
7741 			    hba->sli.sli3.slim_acc_handle) != DDI_FM_OK) {
7742 				EMLXS_MSGF(EMLXS_CONTEXT,
7743 				    &emlxs_invalid_access_handle_msg, NULL);
7744 				rval = DFC_DRV_ERROR;
7745 			}
7746 #endif  /* FMA_SUPPORT */
7747 		}
7748 
7749 		break;
7750 
7751 	case 5:	/* Port  Get/Put pointer array */
7752 
7753 		if (size < MAX_RINGS * sizeof (PGP)) {
7754 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7755 			    "emlxs_get_dump_region: Buffer too small. "
7756 			    "(PGP: size=%d)", size);
7757 
7758 			rval = DFC_ARG_TOOSMALL;
7759 			goto done;
7760 		}
7761 
7762 		size = MAX_RINGS * sizeof (PGP);
7763 
7764 		if (size_only) {
7765 			break;
7766 		}
7767 
7768 		memptr = (uint8_t *)
7769 		    ((SLIM2 *)hba->sli.sli3.slim2.virt)->mbx.us.s2.port;
7770 		BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size);
7771 		break;
7772 
7773 	case 6:	/* Command/Response Ring */
7774 
7775 		if (size < SLI_IOCB_MAX_SIZE) {
7776 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7777 			    "emlxs_get_dump_region: Buffer too small. "
7778 			    "(Rings: size=%d)", size);
7779 
7780 			rval = DFC_ARG_TOOSMALL;
7781 			goto done;
7782 		}
7783 
7784 		size = SLI_IOCB_MAX_SIZE;
7785 
7786 		if (size_only) {
7787 			break;
7788 		}
7789 
7790 		memptr = (uint8_t *)((SLIM2 *)hba->sli.sli3.slim2.virt)->IOCBs;
7791 		BE_SWAP32_BCOPY((uint8_t *)memptr, (uint8_t *)buffer, size);
7792 		break;
7793 
7794 	case 7:	/* All driver specific structures */
7795 
7796 		if (size < sizeof (emlxs_hba_t)) {
7797 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7798 			    "emlxs_get_dump_region: Buffer too small. "
7799 			    "(Driver: size=%d)", size);
7800 
7801 			rval = DFC_ARG_TOOSMALL;
7802 			goto done;
7803 		}
7804 
7805 		size = sizeof (emlxs_hba_t);
7806 
7807 		if (size_only) {
7808 			break;
7809 		}
7810 
7811 		memptr = (uint8_t *)hba;
7812 		bcopy((void *)memptr, (void *)buffer, size);
7813 
7814 		break;
7815 
7816 	default:
7817 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7818 		    "emlxs_get_dump_region: Invalid region. (id=%d)", region);
7819 
7820 		rval = DFC_ARG_INVALID;
7821 	}
7822 
7823 done:
7824 
7825 	*psize = size;
7826 
7827 	return (rval);
7828 
7829 } /* emlxs_get_dump_region() */
7830 
7831 
7832 
7833 static int32_t
7834 emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7835 {
7836 	emlxs_port_t	*port = &PPORT;
7837 	uint32_t	size;
7838 	uint32_t	size_only = 0;
7839 	uint32_t	rval = 0;
7840 	uint8_t		*buffer = NULL;
7841 
7842 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7843 	    "%s: region=%d size=%d",
7844 	    emlxs_dfc_xlate(dfc->cmd), dfc->data1, dfc->buf1_size);
7845 
7846 	if (!dfc->buf1 || !dfc->buf1_size) {
7847 		size_only = 1;
7848 	}
7849 
7850 	if (!dfc->buf2 || !dfc->buf2_size) {
7851 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7852 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
7853 
7854 		return (DFC_ARG_NULL);
7855 	}
7856 
7857 	if (dfc->buf2_size < sizeof (uint32_t)) {
7858 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7859 		    "%s: Buffer2 too small. (size=%d)",
7860 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
7861 
7862 		return (DFC_ARG_TOOSMALL);
7863 	}
7864 
7865 	/* First get region size only */
7866 	size = 0;
7867 	rval = emlxs_get_dump_region(hba, dfc->data1, NULL, &size);
7868 
7869 	if (rval != 0) {
7870 		goto done;
7871 	}
7872 
7873 	if (!size_only) {
7874 		if (dfc->buf1_size < size) {
7875 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7876 			    "%s: Buffer1 too small. (size: %d < %d)",
7877 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size, size);
7878 
7879 			rval = DFC_ARG_TOOSMALL;
7880 			goto done;
7881 		}
7882 
7883 		buffer = (uint8_t *)kmem_zalloc(size, KM_SLEEP);
7884 
7885 		/* Get the region data */
7886 		rval = emlxs_get_dump_region(hba, dfc->data1, buffer, &size);
7887 
7888 		if (rval != 0) {
7889 			goto done;
7890 		}
7891 
7892 		/* Return the region data */
7893 		if (ddi_copyout((void *)buffer, (void *) dfc->buf1,
7894 		    size, mode) != 0) {
7895 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7896 			    "%s: ddi_copyout failed.",
7897 			    emlxs_dfc_xlate(dfc->cmd));
7898 
7899 			rval = DFC_COPYOUT_ERROR;
7900 			goto done;
7901 		}
7902 	}
7903 
7904 	/* Return the region size */
7905 	if (ddi_copyout((void *) &size, (void *) dfc->buf2,
7906 	    sizeof (uint32_t), mode) != 0) {
7907 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7908 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7909 
7910 		rval = DFC_COPYOUT_ERROR;
7911 		goto done;
7912 	}
7913 
7914 done:
7915 
7916 	if (buffer) {
7917 		kmem_free(buffer, size);
7918 	}
7919 
7920 	return (rval);
7921 
7922 } /* emlxs_dfc_get_dump_region() */
7923 
7924 
7925 
7926 #ifdef MENLO_SUPPORT
7927 static int32_t
7928 emlxs_dfc_menlo_port_offset(emlxs_hba_t *hba)
7929 {
7930 	uint32_t	cnt;
7931 	char		pathname[256];
7932 
7933 	(void) ddi_pathname(hba->dip, pathname);
7934 	cnt = strlen(pathname);
7935 	if ((cnt < 4) || (strcmp(&pathname[cnt-3], "0,1") != 0))
7936 		return (0);
7937 	return (1);
7938 }
7939 
7940 static int32_t
7941 emlxs_dfc_set_menlo_loopback(emlxs_hba_t *hba)
7942 {
7943 	emlxs_port_t *port = &PPORT;
7944 	MAILBOXQ *mbq = NULL;
7945 	MAILBOX *mb = NULL;
7946 	fc_packet_t *pkt = NULL;
7947 	uint32_t mbxstatus;
7948 	uint32_t i;
7949 	uint32_t offset;
7950 	uint32_t rval = 0;
7951 	menlo_cmd_t *cmd;
7952 
7953 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
7954 	    KM_SLEEP);
7955 
7956 	mb = (MAILBOX *)mbq;
7957 
7958 	/* SET MENLO maint mode */
7959 	/* Create the set_variable mailbox request */
7960 	emlxs_mb_set_var(hba, mbq, 0x103107, 1);
7961 
7962 	mbq->flag |= MBQ_PASSTHRU;
7963 
7964 	/* issue the mbox cmd to the sli */
7965 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
7966 
7967 	if (mbxstatus) {
7968 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7969 		    "%s: %s failed. mbxstatus=0x%x",
7970 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
7971 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
7972 
7973 		rval = DFC_IO_ERROR;
7974 		if (mbxstatus == MBX_TIMEOUT)
7975 			rval = DFC_TIMEOUT;
7976 		goto done;
7977 	}
7978 
7979 
7980 	/* Wait 30 sec for maint mode */
7981 	i = 0;
7982 	do {
7983 		if (i++ > 300) {
7984 			break;
7985 		}
7986 
7987 		delay(drv_usectohz(100000));
7988 
7989 	} while (!(hba->flag & FC_MENLO_MODE));
7990 
7991 	if (!(hba->flag & FC_MENLO_MODE)) {
7992 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7993 		    "%s: Unable to enter maint mode.",
7994 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7995 
7996 		rval = DFC_DRV_ERROR;
7997 		goto done;
7998 	}
7999 
8000 	offset = emlxs_dfc_menlo_port_offset(hba);
8001 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8002 	    "%s: Entered maint mode. Port offset: %d",
8003 	    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), offset);
8004 
8005 
8006 	/* Issue Menlo loopback command */
8007 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t),
8008 	    sizeof (uint32_t), 0, KM_NOSLEEP))) {
8009 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8010 		    "%s: Unable to allocate packet.",
8011 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8012 
8013 		rval = DFC_SYSRES_ERROR;
8014 		goto done;
8015 	}
8016 
8017 	/* Make this a polled IO */
8018 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
8019 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8020 	pkt->pkt_comp = NULL;
8021 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
8022 	pkt->pkt_timeout = 30;
8023 
8024 	/* Build the fc header */
8025 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
8026 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
8027 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
8028 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
8029 	pkt->pkt_cmd_fhdr.f_ctl =
8030 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
8031 	pkt->pkt_cmd_fhdr.seq_id = 0;
8032 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8033 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8034 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
8035 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
8036 	pkt->pkt_cmd_fhdr.ro = 0;
8037 
8038 	cmd = (menlo_cmd_t *)pkt->pkt_cmd;
8039 	cmd->code = BE_SWAP32(MENLO_CMD_LOOPBACK);
8040 	cmd->lb.context = BE_SWAP32(offset);
8041 	cmd->lb.type = BE_SWAP32(MENLO_LOOPBACK_ENABLE);
8042 
8043 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
8044 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8045 		    "%s: Unable to send packet.",
8046 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8047 
8048 		rval = DFC_IO_ERROR;
8049 		goto done;
8050 	}
8051 
8052 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8053 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8054 			EMLXS_MSGF(EMLXS_CONTEXT,
8055 			    &emlxs_dfc_error_msg,
8056 			    "%s: Pkt Transport error. Pkt Timeout.",
8057 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8058 			rval = DFC_TIMEOUT;
8059 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
8060 		    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
8061 			EMLXS_MSGF(EMLXS_CONTEXT,
8062 			    &emlxs_dfc_error_msg,
8063 			    "%s: Pkt Transport error. Rsp overrun.",
8064 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8065 			rval = DFC_RSP_BUF_OVERRUN;
8066 		} else {
8067 			EMLXS_MSGF(EMLXS_CONTEXT,
8068 			    &emlxs_dfc_error_msg,
8069 			    "%s: Pkt Transport error. state=%x",
8070 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8071 			    pkt->pkt_state);
8072 			rval = DFC_IO_ERROR;
8073 		}
8074 		goto done;
8075 	}
8076 
8077 
8078 	/* CLEAR MENLO maint mode */
8079 	/* Create the set_variable mailbox request */
8080 	emlxs_mb_set_var(hba, mbq, 0x103107, 0);
8081 
8082 	mbq->flag |= MBQ_PASSTHRU;
8083 
8084 	/* issue the mbox cmd to the sli */
8085 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8086 
8087 	if (mbxstatus) {
8088 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8089 		    "%s: %s failed. mbxstatus=0x%x",
8090 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8091 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
8092 
8093 		rval = DFC_IO_ERROR;
8094 		if (mbxstatus == MBX_TIMEOUT)
8095 			rval = DFC_TIMEOUT;
8096 	}
8097 
8098 	delay(drv_usectohz(1000000));
8099 	i = 0;
8100 	while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) {
8101 		delay(drv_usectohz(100000));
8102 		i++;
8103 
8104 		if (i == 300) {
8105 			rval = DFC_TIMEOUT;
8106 
8107 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8108 			    "%s: Linkup timeout.",
8109 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8110 
8111 			goto done;
8112 		}
8113 	}
8114 
8115 done:
8116 	/* Free allocated mbox memory */
8117 	if (mbq) {
8118 		kmem_free(mbq, sizeof (MAILBOXQ));
8119 	}
8120 	if (pkt) {
8121 		emlxs_pkt_free(pkt);
8122 	}
8123 	return (rval);
8124 }
8125 
8126 static int32_t
8127 emlxs_dfc_set_menlo_fte(emlxs_hba_t *hba)
8128 {
8129 	emlxs_port_t *port = &PPORT;
8130 	fc_packet_t *pkt = NULL;
8131 	uint32_t rval = 0;
8132 	menlo_cmd_t *cmd;
8133 
8134 
8135 	/* Issue Menlo loopback command */
8136 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t),
8137 	    sizeof (uint32_t), 0, KM_NOSLEEP))) {
8138 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8139 		    "%s: Unable to allocate packet.",
8140 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8141 
8142 		rval = DFC_SYSRES_ERROR;
8143 		goto done;
8144 	}
8145 
8146 	/* Make this a polled IO */
8147 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
8148 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8149 	pkt->pkt_comp = NULL;
8150 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
8151 	pkt->pkt_timeout = 30;
8152 
8153 	/* Build the fc header */
8154 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(EMLXS_MENLO_DID);
8155 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
8156 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
8157 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
8158 	pkt->pkt_cmd_fhdr.f_ctl =
8159 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
8160 	pkt->pkt_cmd_fhdr.seq_id = 0;
8161 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8162 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8163 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
8164 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
8165 	pkt->pkt_cmd_fhdr.ro = 0;
8166 
8167 	cmd = (menlo_cmd_t *)pkt->pkt_cmd;
8168 	cmd->code = BE_SWAP32(MENLO_CMD_FTE_INSERT);
8169 	cmd->fte_insert.fcid = BE_SWAP32(0);
8170 	bcopy((caddr_t)&port->wwpn, (caddr_t)cmd->fte_insert.wwpn, 8);
8171 
8172 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
8173 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8174 		    "%s: Unable to send packet.",
8175 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8176 
8177 		rval = DFC_IO_ERROR;
8178 		goto done;
8179 	}
8180 
8181 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8182 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8183 			EMLXS_MSGF(EMLXS_CONTEXT,
8184 			    &emlxs_dfc_error_msg,
8185 			    "%s: Pkt Transport error. Pkt Timeout.",
8186 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8187 			rval = DFC_TIMEOUT;
8188 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
8189 		    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
8190 			EMLXS_MSGF(EMLXS_CONTEXT,
8191 			    &emlxs_dfc_error_msg,
8192 			    "%s: Pkt Transport error. Rsp overrun.",
8193 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8194 			rval = DFC_RSP_BUF_OVERRUN;
8195 		} else {
8196 			EMLXS_MSGF(EMLXS_CONTEXT,
8197 			    &emlxs_dfc_error_msg,
8198 			    "%s: Pkt Transport error. state=%x",
8199 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8200 			    pkt->pkt_state);
8201 			rval = DFC_IO_ERROR;
8202 		}
8203 		goto done;
8204 	}
8205 
8206 
8207 done:
8208 	if (pkt) {
8209 		emlxs_pkt_free(pkt);
8210 	}
8211 	return (rval);
8212 }
8213 
8214 static int32_t
8215 emlxs_dfc_reset_menlo(emlxs_hba_t *hba)
8216 {
8217 	emlxs_port_t *port = &PPORT;
8218 	MAILBOXQ *mbq = NULL;
8219 	MAILBOX *mb = NULL;
8220 	uint32_t mbxstatus;
8221 	uint32_t rval = 0;
8222 
8223 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8224 	    KM_SLEEP);
8225 
8226 	mb = (MAILBOX *)mbq;
8227 
8228 	/* RESET MENLO */
8229 	/* Create the set_variable mailbox request */
8230 	emlxs_mb_set_var(hba, mbq, 0x103007, 0);
8231 
8232 	mbq->flag |= MBQ_PASSTHRU;
8233 
8234 	/* issue the mbox cmd to the sli */
8235 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8236 
8237 	if (mbxstatus) {
8238 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8239 		    "%s: %s failed. mbxstatus=0x%x",
8240 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8241 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
8242 
8243 		rval = DFC_IO_ERROR;
8244 		if (mbxstatus == MBX_TIMEOUT)
8245 			rval = DFC_TIMEOUT;
8246 		goto done;
8247 	}
8248 done:
8249 	/* Free allocated mbox memory */
8250 	if (mbq) {
8251 		kmem_free(mbq, sizeof (MAILBOXQ));
8252 	}
8253 	return (rval);
8254 }
8255 
8256 #endif /* MENLO_SUPPORT */
8257 
8258 /* ARGSUSED */
8259 static int32_t
8260 emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8261 {
8262 	emlxs_port_t	*port = &PPORT;
8263 	emlxs_config_t	*cfg = &CFG;
8264 	MAILBOXQ	*mbq = NULL;
8265 	MAILBOX		*mb = NULL;
8266 	uint32_t	rval = DFC_SUCCESS;
8267 	uint32_t	i;
8268 	uint32_t	timeout;
8269 	uint32_t	topology;
8270 	uint32_t	speed;
8271 	uint32_t	new_mode;
8272 	NODELIST	*ndlp;
8273 
8274 	if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
8275 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8276 		    "%s: FCoE not supported.", emlxs_dfc_xlate(dfc->cmd));
8277 
8278 		return (DFC_FCOE_NOTSUPPORTED);
8279 	}
8280 
8281 	/* Reinitialize the link */
8282 	switch (dfc->flag) {
8283 	case 0:	/* Disable */
8284 
8285 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8286 		    "%s: Disabling Loopback.", emlxs_dfc_xlate(dfc->cmd));
8287 
8288 		if (!(hba->flag & FC_LOOPBACK_MODE)) {
8289 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8290 			    "%s: Loopback already disabled.",
8291 			    emlxs_dfc_xlate(dfc->cmd));
8292 
8293 			return (rval);
8294 		}
8295 		goto resetdone;
8296 
8297 	case 1:	/* Internal loopback */
8298 		new_mode = FC_ILB_MODE;
8299 		topology = FLAGS_LOCAL_LB;
8300 		speed = 0;
8301 
8302 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8303 		    "%s: Enabling ILB.", emlxs_dfc_xlate(dfc->cmd));
8304 
8305 		/* Check if mode already set */
8306 		if ((hba->flag & FC_ILB_MODE)) {
8307 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8308 			    "%s: ILB mode already enabled.",
8309 			    emlxs_dfc_xlate(dfc->cmd));
8310 
8311 			return (rval);
8312 		}
8313 
8314 		break;
8315 
8316 	case 2:	/* External loopback */
8317 		new_mode = FC_ELB_MODE;
8318 		topology = FLAGS_TOPOLOGY_MODE_LOOP;
8319 		speed = cfg[CFG_LINK_SPEED].current;
8320 
8321 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8322 		    "%s: Enabling ELB.", emlxs_dfc_xlate(dfc->cmd));
8323 
8324 		/* Check if mode already set */
8325 		if ((hba->flag & FC_ELB_MODE)) {
8326 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8327 			    "%s: ELB mode already enabled.",
8328 			    emlxs_dfc_xlate(dfc->cmd));
8329 
8330 			return (rval);
8331 		}
8332 
8333 		break;
8334 
8335 	default:
8336 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8337 		    "%s: Invalid loopback mode. (mode=%x)",
8338 		    emlxs_dfc_xlate(dfc->cmd), dfc->flag);
8339 
8340 		return (DFC_ARG_INVALID);
8341 	}
8342 
8343 	/* Make sure adapter is online */
8344 	if (emlxs_online(hba)) {
8345 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8346 		    "%s: Unable to bring adapter online.",
8347 		    emlxs_dfc_xlate(dfc->cmd));
8348 
8349 		return (DFC_OFFLINE_ERROR);
8350 	}
8351 
8352 #ifdef MENLO_SUPPORT
8353 	if (hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) {
8354 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8355 		    "%s: Menlo support detected: mode:x%x",
8356 		    emlxs_dfc_xlate(dfc->cmd), new_mode);
8357 
8358 		if (new_mode == FC_ILB_MODE) {
8359 			rval = emlxs_dfc_set_menlo_loopback(hba);
8360 			if (rval)
8361 				goto done;
8362 		}
8363 	}
8364 #endif /* MENLO_SUPPORT */
8365 
8366 	mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8367 	    KM_SLEEP);
8368 
8369 	mb = (MAILBOX *) mbq;
8370 
8371 	/* Take the link down */
8372 	emlxs_mb_down_link(hba, mbq);
8373 
8374 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8375 
8376 	if (rval == MBX_TIMEOUT) {
8377 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8378 		    "%s: Mailbox timed out. cmd=%x",
8379 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
8380 
8381 		rval = DFC_TIMEOUT;
8382 		goto done;
8383 	}
8384 
8385 	if (rval) {
8386 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8387 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
8388 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
8389 
8390 		rval = DFC_IO_ERROR;
8391 		goto done;
8392 	}
8393 
8394 	/* Reinitialize the link */
8395 	emlxs_mb_init_link(hba, mbq, topology, speed);
8396 
8397 	/* Set the loopback mode and timer */
8398 	mutex_enter(&EMLXS_PORT_LOCK);
8399 	hba->flag |= new_mode;
8400 	hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo;
8401 	mutex_exit(&EMLXS_PORT_LOCK);
8402 
8403 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
8404 
8405 	if (rval == MBX_TIMEOUT) {
8406 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8407 		    "%s: Mailbox timed out. cmd=%x",
8408 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
8409 
8410 		rval = DFC_TIMEOUT;
8411 		goto done;
8412 	}
8413 
8414 	if (rval) {
8415 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8416 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
8417 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
8418 
8419 		rval = DFC_IO_ERROR;
8420 		goto done;
8421 	}
8422 
8423 	/*
8424 	 * Wait for adapter to come online.
8425 	 * Need *2 since we wait 1/2 sec in while loop.
8426 	 */
8427 	timeout = dfc->data1;
8428 	if (!timeout) {
8429 		timeout = 60 * 2;
8430 	} else {
8431 		timeout = timeout * 2;
8432 	}
8433 
8434 	i = 0;
8435 	while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) {
8436 		delay(drv_usectohz(500000));
8437 		i++;
8438 
8439 		if (i == timeout) {
8440 			rval = DFC_TIMEOUT;
8441 
8442 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8443 			    "%s: Linkup timeout.", emlxs_dfc_xlate(dfc->cmd));
8444 
8445 			goto done;
8446 		}
8447 	}
8448 
8449 	/* Create host node */
8450 	if (emlxs_mb_reg_did(port, port->did, (SERV_PARM *)&hba->sparam,
8451 	    NULL, NULL, NULL)) {
8452 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8453 		    "%s: Unable to register host node.",
8454 		    emlxs_dfc_xlate(dfc->cmd));
8455 
8456 		rval = DFC_DRV_ERROR;
8457 		goto done;
8458 	}
8459 
8460 	i = 0;
8461 	do {
8462 		if (i++ > 300) {
8463 			break;
8464 		}
8465 
8466 		delay(drv_usectohz(100000));
8467 
8468 	} while (!(ndlp = emlxs_node_find_did(port, port->did)));
8469 
8470 	if (!ndlp) {
8471 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8472 		    "%s: Unable to create host node.",
8473 		    emlxs_dfc_xlate(dfc->cmd));
8474 
8475 		rval = DFC_DRV_ERROR;
8476 		goto done;
8477 	}
8478 
8479 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8480 	    "%s: Node created. node=%p", emlxs_dfc_xlate(dfc->cmd), ndlp);
8481 
8482 #ifdef MENLO_SUPPORT
8483 	if (hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) {
8484 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8485 		    "%s: Menlo support detected: mode:x%x",
8486 		    emlxs_dfc_xlate(dfc->cmd), new_mode);
8487 
8488 		rval = emlxs_dfc_set_menlo_fte(hba);
8489 		if (rval)
8490 			goto done;
8491 	}
8492 #endif /* MENLO_SUPPORT */
8493 
8494 	/* Create host XRI */
8495 	(void) emlxs_create_xri(port, &hba->chan[hba->channel_ct], ndlp);
8496 
8497 	i = 0;
8498 	do {
8499 		if (i++ > 300) {
8500 			break;
8501 		}
8502 
8503 		delay(drv_usectohz(100000));
8504 
8505 	} while (!ndlp->nlp_Xri);
8506 
8507 	if (!ndlp->nlp_Xri) {
8508 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8509 		    "%s: Unable to create XRI.", emlxs_dfc_xlate(dfc->cmd));
8510 
8511 		rval = DFC_DRV_ERROR;
8512 		goto done;
8513 	}
8514 
8515 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8516 	    "%s: XRI created. xri=%x", emlxs_dfc_xlate(dfc->cmd),
8517 	    ndlp->nlp_Xri);
8518 done:
8519 	/* Free allocated mbox memory */
8520 	if (mbq) {
8521 		kmem_free(mbq, sizeof (MAILBOXQ));
8522 	}
8523 
8524 	if (rval) {
8525 resetdone:
8526 		/* Reset the adapter */
8527 #ifdef MENLO_SUPPORT
8528 		if (hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) {
8529 
8530 			rval = emlxs_dfc_reset_menlo(hba);
8531 
8532 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8533 			    "%s: Menlo reset: rval:x%x",
8534 			    emlxs_dfc_xlate(dfc->cmd), rval);
8535 	}
8536 #endif /* MENLO_SUPPORT */
8537 
8538 		/* Reset link whether we are bound to ULP or not */
8539 		(void) emlxs_reset_link(hba, 1, 1);
8540 	}
8541 
8542 	return (rval);
8543 } /* emlxs_dfc_loopback_mode() */
8544 
8545 
8546 static int32_t
8547 emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8548 {
8549 	emlxs_port_t	*port = &PPORT;
8550 	int32_t		rval = 0;
8551 	NODELIST	*ndlp;
8552 	clock_t		timeout;
8553 	fc_packet_t	*pkt = NULL;
8554 	SLI_CT_REQUEST	*CtCmd;
8555 	uint16_t	CtRsp;
8556 
8557 	if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
8558 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8559 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
8560 
8561 		return (DFC_FCOE_NOTSUPPORTED);
8562 	}
8563 
8564 	mutex_enter(&EMLXS_PORT_LOCK);
8565 	if (!(hba->flag & FC_LOOPBACK_MODE)) {
8566 		mutex_exit(&EMLXS_PORT_LOCK);
8567 
8568 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8569 		    "%s: Adapter not in loopback mode.",
8570 		    emlxs_dfc_xlate(dfc->cmd));
8571 
8572 		rval = DFC_DRV_ERROR;
8573 		goto done;
8574 	}
8575 	hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo;
8576 	mutex_exit(&EMLXS_PORT_LOCK);
8577 
8578 	if (!(hba->flag & FC_ONLINE_MODE)) {
8579 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8580 		    "%s: Adapter offline.", emlxs_dfc_xlate(dfc->cmd));
8581 
8582 		rval = DFC_OFFLINE_ERROR;
8583 		goto done;
8584 	}
8585 
8586 	if (hba->state < FC_LINK_UP) {
8587 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8588 		    "%s: Link not up.", emlxs_dfc_xlate(dfc->cmd));
8589 
8590 		rval = DFC_OFFLINE_ERROR;
8591 		goto done;
8592 	}
8593 
8594 	if (!dfc->buf1 || !dfc->buf1_size) {
8595 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8596 		    "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8597 
8598 		rval = DFC_ARG_NULL;
8599 		goto done;
8600 	}
8601 
8602 	if (!dfc->buf2 || !dfc->buf2_size) {
8603 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8604 		    "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8605 
8606 		rval = DFC_ARG_NULL;
8607 		goto done;
8608 	}
8609 
8610 	if (dfc->buf1_size > MAX_CT_PAYLOAD) {
8611 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8612 		    "%s: Buffer1 too large. (size=%d)",
8613 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8614 
8615 		rval = DFC_ARG_TOOBIG;
8616 		goto done;
8617 	}
8618 
8619 	/* Check if we have a node for ourselves */
8620 	ndlp = emlxs_node_find_did(port, port->did);
8621 
8622 	if (!ndlp) {
8623 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8624 		    "%s: Host node not found.", emlxs_dfc_xlate(dfc->cmd));
8625 
8626 		rval = DFC_ARG_INVALID;
8627 		goto done;
8628 	}
8629 
8630 	if (!ndlp->nlp_Xri) {
8631 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8632 		    "%s: Host XRI not found.", emlxs_dfc_xlate(dfc->cmd));
8633 
8634 		rval = DFC_DRV_ERROR;
8635 		goto done;
8636 	}
8637 
8638 	pkt = emlxs_pkt_alloc(port, dfc->buf1_size + 16,
8639 	    dfc->buf2_size + 16, 0, KM_SLEEP);
8640 
8641 	if (pkt == NULL) {
8642 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8643 		    "%s: Unable to allocate pkt.", emlxs_dfc_xlate(dfc->cmd));
8644 		rval = DFC_SYSRES_ERROR;
8645 		goto done;
8646 	}
8647 
8648 	CtCmd = (SLI_CT_REQUEST*)pkt->pkt_cmd;
8649 	CtRsp = SLI_CT_LOOPBACK;
8650 	CtCmd->CommandResponse.bits.CmdRsp = LE_SWAP16(CtRsp);
8651 
8652 	if (ddi_copyin((void *)dfc->buf1, (void *)&CtCmd->un.data,
8653 	    dfc->buf1_size, mode) != 0) {
8654 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8655 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8656 
8657 		rval = DFC_COPYIN_ERROR;
8658 		goto done;
8659 	}
8660 
8661 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
8662 	pkt->pkt_timeout = 2 * hba->fc_ratov;
8663 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8664 	pkt->pkt_comp = NULL;
8665 
8666 	pkt->pkt_cmd_fhdr.d_id = port->did;
8667 	pkt->pkt_cmd_fhdr.r_ctl = FC_SOL_CTL;
8668 	pkt->pkt_cmd_fhdr.s_id = port->did;
8669 	pkt->pkt_cmd_fhdr.type = FC_CT_TYPE;
8670 	pkt->pkt_cmd_fhdr.f_ctl = 0;
8671 	pkt->pkt_cmd_fhdr.seq_id = 0;
8672 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8673 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8674 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
8675 	pkt->pkt_cmd_fhdr.rx_id = ndlp->nlp_Xri;
8676 	pkt->pkt_cmd_fhdr.ro = 0;
8677 
8678 	mutex_enter(&EMLXS_PKT_LOCK);
8679 	timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15));
8680 
8681 	if (hba->loopback_pkt) {
8682 		rval = 0;
8683 		while ((rval != -1) && hba->loopback_pkt) {
8684 			rval =
8685 			    cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK,
8686 			    timeout);
8687 		}
8688 
8689 		if (rval == -1) {
8690 			mutex_exit(&EMLXS_PKT_LOCK);
8691 
8692 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8693 			    "Loopback busy timeout.");
8694 			rval = DFC_TIMEOUT;
8695 			goto done;
8696 		}
8697 	}
8698 	hba->loopback_pkt = (void *) pkt;
8699 	mutex_exit(&EMLXS_PKT_LOCK);
8700 
8701 	/* Send polled command */
8702 	if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) {
8703 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8704 		    "Pkt Transport error. ret=%x state=%x", rval,
8705 		    pkt->pkt_state);
8706 
8707 		rval = DFC_IO_ERROR;
8708 		goto done;
8709 	}
8710 
8711 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8712 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8713 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8714 			    "Pkt Transport error. Pkt Timeout.");
8715 			rval = DFC_TIMEOUT;
8716 		} else {
8717 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8718 			    "Pkt Transport error. state=%x", pkt->pkt_state);
8719 			rval = DFC_IO_ERROR;
8720 		}
8721 		goto done;
8722 	}
8723 
8724 	/* Wait for sequence completion */
8725 	mutex_enter(&EMLXS_PKT_LOCK);
8726 	rval = 0;
8727 	while ((rval != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) {
8728 		rval = cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout);
8729 	}
8730 	mutex_exit(&EMLXS_PKT_LOCK);
8731 
8732 	if (rval == -1) {
8733 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8734 		    "Loopback sequence timeout.");
8735 
8736 		rval = DFC_TIMEOUT;
8737 		goto done;
8738 	}
8739 
8740 	CtCmd = (SLI_CT_REQUEST*)pkt->pkt_resp;
8741 
8742 	if (ddi_copyout((void *)&CtCmd->un.data, (void *)dfc->buf2,
8743 	    dfc->buf2_size, mode) != 0) {
8744 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8745 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
8746 
8747 		rval = DFC_COPYOUT_ERROR;
8748 		goto done;
8749 	}
8750 
8751 	rval = 0;
8752 
8753 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Test completed.",
8754 	    emlxs_dfc_xlate(dfc->cmd));
8755 
8756 done:
8757 
8758 	if (rval) {
8759 		mutex_enter(&EMLXS_PKT_LOCK);
8760 		if (pkt && (hba->loopback_pkt == pkt)) {
8761 			hba->loopback_pkt = NULL;
8762 		}
8763 		mutex_exit(&EMLXS_PKT_LOCK);
8764 
8765 		/* Reset the adapter */
8766 		(void) emlxs_fca_reset(port, FC_FCA_LINK_RESET);
8767 	}
8768 
8769 	if (pkt) {
8770 		emlxs_pkt_free(pkt);
8771 	}
8772 
8773 	return (rval);
8774 
8775 } /* emlxs_dfc_loopback_test() */
8776 
8777 
8778 extern int32_t
8779 emlxs_dfc_handle_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
8780 {
8781 	emlxs_port_t	*port = &PPORT;
8782 	IOCB		*cmd;
8783 	emlxs_buf_t	*sbp;
8784 
8785 	cmd = &iocbq->iocb;
8786 
8787 	HBASTATS.CtEvent++;
8788 
8789 	sbp = (emlxs_buf_t *)iocbq->sbp;
8790 
8791 	if (!sbp) {
8792 		HBASTATS.CtStray++;
8793 
8794 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8795 		    "Stray interrupt. cmd=0x%x iotag=0x%x status=0x%x "
8796 		    "perr=0x%x", (uint32_t)cmd->ULPCOMMAND,
8797 		    (uint32_t)cmd->ULPIOTAG, cmd->ULPSTATUS,
8798 		    cmd->un.ulpWord[4]);
8799 
8800 		return (DFC_ARG_INVALID);
8801 	}
8802 
8803 	if (cp->channelno != hba->channel_ct) {
8804 		HBASTATS.CtStray++;
8805 
8806 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8807 		    "CT Event: Invalid IO Channel:%d iocbq=%p", cp->channelno,
8808 		    iocbq);
8809 
8810 		return (DFC_ARG_INVALID);
8811 	}
8812 
8813 	switch (cmd->ULPCOMMAND) {
8814 	case CMD_XMIT_SEQUENCE_CR:
8815 	case CMD_XMIT_SEQUENCE64_CR:
8816 	case CMD_XMIT_SEQUENCE_CX:
8817 	case CMD_XMIT_SEQUENCE64_CX:
8818 
8819 		HBASTATS.CtCmdCompleted++;
8820 
8821 		if (cmd->ULPSTATUS == 0) {
8822 			HBASTATS.CtCmdGood++;
8823 
8824 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
8825 			    "XMIT_SEQUENCE comp: status=0x%x",
8826 			    cmd->ULPSTATUS);
8827 		} else {
8828 			HBASTATS.CtCmdError++;
8829 
8830 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8831 			    "XMIT_SEQUENCE comp: status=0x%x [%08x,%08x]",
8832 			    cmd->ULPSTATUS, cmd->un.ulpWord[4],
8833 			    cmd->un.ulpWord[5]);
8834 		}
8835 
8836 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
8837 		    cmd->un.grsp.perr.statLocalError, 1);
8838 
8839 		break;
8840 
8841 	default:
8842 
8843 		HBASTATS.CtStray++;
8844 
8845 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8846 		    "Invalid iocb: cmd=0x%x", cmd->ULPCOMMAND);
8847 
8848 		emlxs_pkt_complete(sbp, cmd->ULPSTATUS,
8849 		    cmd->un.grsp.perr.statLocalError, 1);
8850 
8851 		break;
8852 
8853 	}	/* switch(cmd->ULPCOMMAND) */
8854 
8855 	return (0);
8856 
8857 } /* emlxs_dfc_handle_event() */
8858 
8859 
8860 /* ARGSUSED */
8861 extern int
8862 emlxs_dfc_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
8863     MATCHMAP *mp, uint32_t size)
8864 {
8865 	emlxs_hba_t	*hba = HBA;
8866 	IOCB		*iocb;
8867 	uint8_t		*bp;
8868 	fc_packet_t	*pkt;
8869 
8870 	iocb = &iocbq->iocb;
8871 	bp = (uint8_t *)mp->virt;
8872 
8873 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
8874 	    "CT Receive: cmd=%x status=0x%x ",
8875 	    iocb->ULPCOMMAND, iocb->ULPSTATUS);
8876 
8877 	/*
8878 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8879 	 * "CT Receive: payload=%p size=%d [%02x,%02x, %02x, %02x]", bp,
8880 	 * size, bp[0], bp[1], bp[2],bp[3]);
8881 	 */
8882 
8883 	/* Return payload */
8884 	mutex_enter(&EMLXS_PKT_LOCK);
8885 	if (hba->loopback_pkt) {
8886 		pkt = (fc_packet_t *)hba->loopback_pkt;
8887 		hba->loopback_pkt = NULL;
8888 
8889 		size = MIN(size, pkt->pkt_rsplen);
8890 		bcopy(bp, pkt->pkt_resp, size);
8891 		pkt->pkt_tran_flags |= FC_TRAN_COMPLETED;
8892 
8893 		cv_broadcast(&EMLXS_PKT_CV);
8894 	}
8895 	mutex_exit(&EMLXS_PKT_LOCK);
8896 
8897 	return (0);
8898 
8899 } /* emlxs_dfc_handle_unsol_req() */
8900 
8901 
8902 #ifdef DHCHAP_SUPPORT
8903 
8904 static int32_t
8905 emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8906 {
8907 	emlxs_port_t	*port = &PPORT;
8908 	uint8_t		lwwpn[8];
8909 	uint8_t		rwwpn[8];
8910 	int32_t		rval = 0;
8911 
8912 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
8913 	    emlxs_dfc_xlate(dfc->cmd));
8914 
8915 	if (!dfc->buf1 || !dfc->buf1_size) {
8916 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8917 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8918 
8919 		return (DFC_ARG_NULL);
8920 	}
8921 
8922 	if (dfc->buf1_size < 8) {
8923 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8924 		    "%s: Buffer1 too small. (size=%d)",
8925 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8926 
8927 		return (DFC_ARG_TOOSMALL);
8928 	}
8929 
8930 	if (!dfc->buf2 || !dfc->buf2_size) {
8931 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8932 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8933 
8934 		return (DFC_ARG_NULL);
8935 	}
8936 
8937 	if (dfc->buf2_size < 8) {
8938 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8939 		    "%s: Buffer2 too small. (size=%d)",
8940 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8941 
8942 		return (DFC_ARG_TOOSMALL);
8943 	}
8944 
8945 	/* Read the lwwpn */
8946 	if (ddi_copyin((void *)dfc->buf1, (void *)&lwwpn, 8, mode) != 0) {
8947 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8948 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8949 
8950 		return (DFC_COPYIN_ERROR);
8951 	}
8952 
8953 	/* Read the rwwpn */
8954 	if (ddi_copyin((void *)dfc->buf2, (void *)&rwwpn, 8, mode) != 0) {
8955 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8956 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8957 
8958 		return (DFC_COPYIN_ERROR);
8959 	}
8960 
8961 	/* Initiate authentication here */
8962 	rval = emlxs_dhc_init_auth(hba, lwwpn, rwwpn);
8963 
8964 	return (rval);
8965 
8966 } /* emlxs_dfc_init_auth() */
8967 
8968 
8969 static int32_t
8970 emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8971 {
8972 	emlxs_port_t		*port = &PPORT;
8973 	dfc_fcsp_config_t	fcsp_config;
8974 	uint32_t		rval = DFC_SUCCESS;
8975 
8976 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
8977 	    emlxs_dfc_xlate(dfc->cmd));
8978 
8979 	if (!dfc->buf1 || !dfc->buf1_size) {
8980 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8981 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8982 
8983 		return (DFC_ARG_NULL);
8984 	}
8985 
8986 	if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) {
8987 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8988 		    "%s: Buffer1 too small. (size=%d)",
8989 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8990 
8991 		return (DFC_ARG_TOOSMALL);
8992 	}
8993 
8994 	/* Read the fcsp_config */
8995 	if (ddi_copyin((void *)dfc->buf1, (void *)&fcsp_config,
8996 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
8997 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8998 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8999 
9000 		return (DFC_COPYIN_ERROR);
9001 	}
9002 
9003 	if ((rval = emlxs_dhc_get_auth_cfg(hba, &fcsp_config)) != 0) {
9004 		return (rval);
9005 	}
9006 
9007 	if (ddi_copyout((void *)&fcsp_config, (void *)dfc->buf1,
9008 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
9009 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9010 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
9011 
9012 		return (DFC_COPYOUT_ERROR);
9013 	}
9014 
9015 	return (0);
9016 
9017 } /* emlxs_dfc_get_auth_cfg() */
9018 
9019 
9020 
9021 static int32_t
9022 emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9023 {
9024 	emlxs_port_t		*port = &PPORT;
9025 	dfc_fcsp_config_t	fcsp_config;
9026 	dfc_password_t		dfc_pwd;
9027 	uint32_t		rval = DFC_SUCCESS;
9028 
9029 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9030 	    emlxs_dfc_xlate(dfc->cmd));
9031 
9032 	if (!dfc->buf1 || !dfc->buf1_size) {
9033 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9034 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9035 
9036 		return (DFC_ARG_NULL);
9037 	}
9038 
9039 	if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) {
9040 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9041 		    "%s: Buffer1 too small. (size=%d)",
9042 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9043 
9044 		return (DFC_ARG_TOOSMALL);
9045 	}
9046 
9047 	if (!dfc->buf2 || !dfc->buf2_size) {
9048 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9049 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
9050 
9051 		return (DFC_ARG_NULL);
9052 	}
9053 
9054 	if (dfc->buf2_size < sizeof (dfc_password_t)) {
9055 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9056 		    "%s: Buffer2 too small. (size=%d)",
9057 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9058 
9059 		return (DFC_ARG_TOOSMALL);
9060 	}
9061 
9062 	/* Read the fcsp_config */
9063 	if (ddi_copyin((void *)dfc->buf1, (void *)&fcsp_config,
9064 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
9065 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9066 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9067 
9068 		return (DFC_COPYIN_ERROR);
9069 	}
9070 
9071 	/* Read the password */
9072 	if (ddi_copyin((void *)dfc->buf2, (void *)&dfc_pwd,
9073 	    sizeof (dfc_password_t), mode) != 0) {
9074 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9075 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9076 
9077 		return (DFC_COPYIN_ERROR);
9078 	}
9079 
9080 	switch (dfc->flag) {
9081 	case EMLXS_AUTH_CFG_ADD:
9082 		rval = emlxs_dhc_add_auth_cfg(hba, &fcsp_config, &dfc_pwd);
9083 		break;
9084 
9085 	case EMLXS_AUTH_CFG_DELETE:
9086 		rval = emlxs_dhc_delete_auth_cfg(hba, &fcsp_config, &dfc_pwd);
9087 		break;
9088 	}
9089 
9090 	if (rval) {
9091 		return (rval);
9092 	}
9093 
9094 	if (ddi_copyout((void *)&fcsp_config, (void *)dfc->buf1,
9095 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
9096 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9097 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
9098 
9099 		return (DFC_COPYOUT_ERROR);
9100 	}
9101 
9102 	return (0);
9103 
9104 } /* emlxs_dfc_set_auth_cfg() */
9105 
9106 
9107 
9108 static int32_t
9109 emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9110 {
9111 	emlxs_port_t		*port = &PPORT;
9112 	dfc_auth_password_t	dfc_pwd;
9113 	uint32_t		rval = DFC_SUCCESS;
9114 
9115 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9116 	    emlxs_dfc_xlate(dfc->cmd));
9117 
9118 	if (!dfc->buf1 || !dfc->buf1_size) {
9119 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9120 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9121 
9122 		return (DFC_ARG_NULL);
9123 	}
9124 
9125 	if (dfc->buf1_size < sizeof (dfc_auth_password_t)) {
9126 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9127 		    "%s: Buffer1 too small. (size=%d)",
9128 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9129 
9130 		return (DFC_ARG_TOOSMALL);
9131 	}
9132 
9133 
9134 	/* Read the auth password */
9135 	if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_pwd,
9136 	    sizeof (dfc_auth_password_t), mode) != 0) {
9137 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9138 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9139 
9140 		return (DFC_COPYIN_ERROR);
9141 	}
9142 
9143 	if ((rval = emlxs_dhc_get_auth_key(hba, &dfc_pwd)) != 0) {
9144 		return (rval);
9145 	}
9146 
9147 	if (ddi_copyout((void *)&dfc_pwd, (void *)dfc->buf1,
9148 	    sizeof (dfc_auth_password_t), mode) != 0) {
9149 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9150 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
9151 
9152 		return (DFC_COPYOUT_ERROR);
9153 	}
9154 
9155 	return (0);
9156 
9157 } /* emlxs_dfc_get_auth_pwd() */
9158 
9159 
9160 static int32_t
9161 emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9162 {
9163 	emlxs_port_t		*port = &PPORT;
9164 	dfc_auth_password_t	dfc_pwd;
9165 	uint32_t		rval = DFC_SUCCESS;
9166 
9167 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9168 	    emlxs_dfc_xlate(dfc->cmd));
9169 
9170 	if (!dfc->buf1 || !dfc->buf1_size) {
9171 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9172 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9173 
9174 		return (DFC_ARG_NULL);
9175 	}
9176 
9177 	if (dfc->buf1_size < sizeof (dfc_auth_password_t)) {
9178 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9179 		    "%s: Buffer1 too small. (size=%d)",
9180 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9181 
9182 		return (DFC_ARG_TOOSMALL);
9183 	}
9184 
9185 	/* Read the auth password */
9186 	if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_pwd,
9187 	    sizeof (dfc_auth_password_t), mode) != 0) {
9188 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9189 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9190 
9191 		return (DFC_COPYIN_ERROR);
9192 	}
9193 
9194 	if ((rval = emlxs_dhc_set_auth_key(hba, &dfc_pwd))) {
9195 		return (rval);
9196 	}
9197 
9198 	if (ddi_copyout((void *)&dfc_pwd, (void *)dfc->buf1,
9199 	    sizeof (dfc_auth_password_t), mode) != 0) {
9200 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9201 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
9202 
9203 		return (DFC_COPYOUT_ERROR);
9204 	}
9205 
9206 	return (0);
9207 
9208 } /* emlxs_dfc_set_auth_pwd() */
9209 
9210 
9211 static int32_t
9212 emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9213 {
9214 	emlxs_port_t		*port = &PPORT;
9215 	dfc_auth_status_t	fcsp_status;
9216 	uint32_t		rval = DFC_SUCCESS;
9217 
9218 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9219 	    emlxs_dfc_xlate(dfc->cmd));
9220 
9221 	if (!dfc->buf1 || !dfc->buf1_size) {
9222 		EMLXS_MSGF(EMLXS_CONTEXT,
9223 		    &emlxs_dfc_error_msg, "%s: Null buffer1 found.",
9224 		    emlxs_dfc_xlate(dfc->cmd));
9225 
9226 		return (DFC_ARG_NULL);
9227 	}
9228 
9229 	if (dfc->buf1_size < sizeof (dfc_auth_status_t)) {
9230 		EMLXS_MSGF(EMLXS_CONTEXT,
9231 		    &emlxs_dfc_error_msg, "%s: Buffer too small. (size=%d)",
9232 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9233 
9234 		return (DFC_ARG_TOOSMALL);
9235 	}
9236 
9237 	/* Read the fcsp_config */
9238 	if (ddi_copyin((void *) dfc->buf1, (void *) &fcsp_status,
9239 	    sizeof (dfc_auth_status_t), mode) != 0) {
9240 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9241 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9242 
9243 		return (DFC_COPYIN_ERROR);
9244 	}
9245 
9246 	if ((rval = emlxs_dhc_get_auth_status(hba, &fcsp_status)) != 0) {
9247 		return (rval);
9248 	}
9249 
9250 	if (ddi_copyout((void *) &fcsp_status, (void *) dfc->buf1,
9251 	    sizeof (dfc_auth_status_t), mode) != 0) {
9252 		EMLXS_MSGF(EMLXS_CONTEXT,
9253 		    &emlxs_dfc_error_msg, "%s: ddi_copyout failed.",
9254 		    emlxs_dfc_xlate(dfc->cmd));
9255 
9256 		return (DFC_COPYOUT_ERROR);
9257 	}
9258 
9259 	return (0);
9260 
9261 } /* emlxs_dfc_get_auth_status() */
9262 
9263 
9264 static int32_t
9265 emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9266 {
9267 	emlxs_port_t		*port = &PPORT;
9268 	dfc_fcsp_config_t	*fcsp_cfg;
9269 	uint32_t		count;
9270 	uint32_t		size;
9271 	uint32_t		rval = DFC_SUCCESS;
9272 
9273 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9274 	    emlxs_dfc_xlate(dfc->cmd));
9275 
9276 	/* Lock cfg table while we do this */
9277 	/* This prevents the table from changing while we get a copy */
9278 	mutex_enter(&hba->auth_lock);
9279 
9280 	if (!dfc->buf2 || !dfc->buf2_size) {
9281 		EMLXS_MSGF(EMLXS_CONTEXT,
9282 		    &emlxs_dfc_error_msg, "%s: Null buffer2 found.",
9283 		    emlxs_dfc_xlate(dfc->cmd));
9284 
9285 		mutex_exit(&hba->auth_lock);
9286 		return (DFC_ARG_NULL);
9287 	}
9288 
9289 	if (dfc->buf2_size < sizeof (uint32_t)) {
9290 		EMLXS_MSGF(EMLXS_CONTEXT,
9291 		    &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)",
9292 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
9293 
9294 		mutex_exit(&hba->auth_lock);
9295 		return (DFC_ARG_TOOSMALL);
9296 	}
9297 
9298 	if (ddi_copyout((void *)&hba->auth_cfg_count, (void *)dfc->buf2,
9299 	    sizeof (uint32_t), mode) != 0) {
9300 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9301 		    "%s: ddi_copyout failed for table count. count=%d",
9302 		    emlxs_dfc_xlate(dfc->cmd), hba->auth_cfg_count);
9303 
9304 		mutex_exit(&hba->auth_lock);
9305 		return (DFC_COPYOUT_ERROR);
9306 	}
9307 
9308 	if (!dfc->buf1 || !dfc->buf1_size) {
9309 		mutex_exit(&hba->auth_lock);
9310 		return (DFC_SUCCESS);
9311 	}
9312 
9313 	/* Check table size */
9314 	count = dfc->buf1_size / sizeof (dfc_fcsp_config_t);
9315 	if (count < hba->auth_cfg_count) {
9316 		EMLXS_MSGF(EMLXS_CONTEXT,
9317 		    &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)",
9318 		    emlxs_dfc_xlate(dfc->cmd), count, hba->auth_cfg_count);
9319 
9320 		mutex_exit(&hba->auth_lock);
9321 		return (DFC_ARG_TOOSMALL);
9322 	}
9323 
9324 	size = hba->auth_cfg_count * sizeof (dfc_fcsp_config_t);
9325 
9326 	mutex_exit(&hba->auth_lock);
9327 
9328 	fcsp_cfg = (dfc_fcsp_config_t *)kmem_zalloc(size, KM_SLEEP);
9329 
9330 	mutex_enter(&hba->auth_lock);
9331 
9332 	if ((rval = emlxs_dhc_get_auth_cfg_table(hba, fcsp_cfg)) != 0) {
9333 		mutex_exit(&hba->auth_lock);
9334 		kmem_free(fcsp_cfg, size);
9335 		return (rval);
9336 	}
9337 
9338 	mutex_exit(&hba->auth_lock);
9339 
9340 	if (ddi_copyout((void *)fcsp_cfg, (void *)dfc->buf1, size, mode) != 0) {
9341 		EMLXS_MSGF(EMLXS_CONTEXT,
9342 		    &emlxs_dfc_error_msg, "%s: ddi_copyout failed.",
9343 		    emlxs_dfc_xlate(dfc->cmd));
9344 
9345 		kmem_free(fcsp_cfg, size);
9346 		return (DFC_COPYOUT_ERROR);
9347 	}
9348 
9349 	kmem_free(fcsp_cfg, size);
9350 	return (0);
9351 
9352 } /* emlxs_dfc_get_auth_cfg_table() */
9353 
9354 
9355 static int32_t
9356 emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9357 {
9358 	emlxs_port_t		*port = &PPORT;
9359 	dfc_auth_password_t	*auth_pwd;
9360 	uint32_t		count;
9361 	uint32_t		size;
9362 	uint32_t		rval = DFC_SUCCESS;
9363 
9364 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9365 	    emlxs_dfc_xlate(dfc->cmd));
9366 
9367 	/* Lock cfg table while we do this */
9368 	/* This prevents the table from changing while we get a copy */
9369 	mutex_enter(&hba->auth_lock);
9370 
9371 	if (!dfc->buf2 || !dfc->buf2_size) {
9372 		EMLXS_MSGF(EMLXS_CONTEXT,
9373 		    &emlxs_dfc_error_msg, "%s: Null buffer2 found.",
9374 		    emlxs_dfc_xlate(dfc->cmd));
9375 
9376 		mutex_exit(&hba->auth_lock);
9377 		return (DFC_ARG_NULL);
9378 	}
9379 
9380 	if (dfc->buf2_size < sizeof (uint32_t)) {
9381 		EMLXS_MSGF(EMLXS_CONTEXT,
9382 		    &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)",
9383 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
9384 
9385 		mutex_exit(&hba->auth_lock);
9386 		return (DFC_ARG_TOOSMALL);
9387 	}
9388 
9389 	if (ddi_copyout((void *)&hba->auth_key_count, (void *)dfc->buf2,
9390 	    sizeof (uint32_t), mode) != 0) {
9391 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9392 		    "%s: ddi_copyout failed for table count. count=%d",
9393 		    emlxs_dfc_xlate(dfc->cmd), hba->auth_key_count);
9394 
9395 		mutex_exit(&hba->auth_lock);
9396 		return (DFC_COPYOUT_ERROR);
9397 	}
9398 
9399 	if (!dfc->buf1 || !dfc->buf1_size) {
9400 		mutex_exit(&hba->auth_lock);
9401 		return (DFC_SUCCESS);
9402 	}
9403 
9404 	/* Check table size */
9405 	count = dfc->buf1_size / sizeof (dfc_auth_password_t);
9406 	if (count < hba->auth_key_count) {
9407 		EMLXS_MSGF(EMLXS_CONTEXT,
9408 		    &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)",
9409 		    emlxs_dfc_xlate(dfc->cmd), count, hba->auth_key_count);
9410 
9411 		mutex_exit(&hba->auth_lock);
9412 		return (DFC_ARG_TOOSMALL);
9413 	}
9414 
9415 	size = hba->auth_key_count * sizeof (dfc_auth_password_t);
9416 
9417 	mutex_exit(&hba->auth_lock);
9418 
9419 	auth_pwd = (dfc_auth_password_t *)kmem_zalloc(size, KM_SLEEP);
9420 
9421 	mutex_enter(&hba->auth_lock);
9422 
9423 	if ((rval = emlxs_dhc_get_auth_key_table(hba, auth_pwd)) != 0) {
9424 		mutex_exit(&hba->auth_lock);
9425 		kmem_free(auth_pwd, size);
9426 		return (rval);
9427 	}
9428 
9429 	mutex_exit(&hba->auth_lock);
9430 
9431 	if (ddi_copyout((void *)auth_pwd, (void *)dfc->buf1, size, mode) != 0) {
9432 		EMLXS_MSGF(EMLXS_CONTEXT,
9433 		    &emlxs_dfc_error_msg, "%s: ddi_copyout failed.",
9434 		    emlxs_dfc_xlate(dfc->cmd));
9435 
9436 		kmem_free(auth_pwd, size);
9437 		return (DFC_COPYOUT_ERROR);
9438 	}
9439 
9440 	kmem_free(auth_pwd, size);
9441 	return (0);
9442 
9443 } /* emlxs_dfc_get_auth_key_table() */
9444 
9445 
9446 
9447 #endif	/* DHCHAP_SUPPORT */
9448 
9449 #ifdef SAN_DIAG_SUPPORT
9450 static int32_t
9451 emlxs_dfc_sd_set_bucket(dfc_t *dfc, int32_t mode)
9452 {
9453 	uint32_t	type, search_type;
9454 	uint16_t	state;
9455 	int32_t		rval = DFC_SD_OK;
9456 
9457 	type = dfc->data1;
9458 	search_type = dfc->data2;
9459 
9460 	mutex_enter(&sd_bucket_mutex);
9461 	state = sd_bucket.state;
9462 	mutex_exit(&sd_bucket_mutex);
9463 
9464 	if (state == SD_COLLECTING)
9465 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9466 	else if ((search_type < SD_SEARCH_LINEAR) ||
9467 	    (search_type > SD_SEARCH_POWER_2))
9468 		rval = DFC_SD_ERROR_INVALID_ARG;
9469 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9470 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9471 	else {
9472 		(void) ddi_copyin(dfc->buf3, (void *) &sd_bucket,
9473 		    sizeof (sd_bucket_info_t), mode);
9474 		mutex_enter(&sd_bucket_mutex);
9475 		sd_bucket.state = SD_STOPPED;
9476 		mutex_exit(&sd_bucket_mutex);
9477 	}
9478 
9479 set_bucket_exit:
9480 	return (rval);
9481 }
9482 
9483 
9484 static int32_t
9485 emlxs_dfc_sd_destroy_bucket(dfc_t *dfc)
9486 {
9487 	uint32_t	type;
9488 	int32_t 	rval = DFC_SD_OK;
9489 
9490 	type = dfc->data1;
9491 
9492 	mutex_enter(&sd_bucket_mutex);
9493 
9494 	if (sd_bucket.search_type == 0)
9495 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9496 	else if (sd_bucket.state == SD_COLLECTING)
9497 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9498 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9499 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9500 	else
9501 		bzero((uint8_t *)&sd_bucket, sizeof (sd_bucket_info_t));
9502 
9503 destroy_bucket_exit:
9504 	mutex_exit(&sd_bucket_mutex);
9505 	return (rval);
9506 }
9507 
9508 
9509 static int32_t
9510 emlxs_dfc_sd_get_bucket(dfc_t *dfc, int32_t mode)
9511 {
9512 	uint32_t	type;
9513 	int32_t		rval = DFC_SD_OK;
9514 
9515 	type = dfc->data1;
9516 
9517 	if (sd_bucket.search_type == 0)
9518 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9519 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9520 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9521 	else
9522 		(void) ddi_copyout(&sd_bucket, dfc->buf3,
9523 		    sizeof (sd_bucket_info_t), mode);
9524 
9525 	return (rval);
9526 }
9527 
9528 
9529 static int32_t
9530 emlxs_dfc_sd_start_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9531 {
9532 	emlxs_port_t	*vport;
9533 	NODELIST	*nlp;
9534 	uint8_t		wwpn[8];
9535 	int32_t		rval = DFC_SD_OK;
9536 	int		i;
9537 
9538 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9539 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9540 		goto start_collect_exit;
9541 	}
9542 
9543 	if (sd_bucket.search_type == 0) {
9544 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9545 		goto start_collect_exit;
9546 	}
9547 
9548 	/* Read the wwn object */
9549 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9550 
9551 	/* Make sure WWPN is unique */
9552 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9553 
9554 	if (!vport) {
9555 		rval = DFC_SD_ERROR_INVALID_PORT;
9556 		goto start_collect_exit;
9557 	}
9558 
9559 	/* traverse list of nodes for this vport and reset counter */
9560 	rw_enter(&vport->node_rwlock, RW_READER);
9561 	if (vport->sd_io_latency_state == SD_COLLECTING) {
9562 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9563 		rw_exit(&vport->node_rwlock);
9564 		goto start_collect_exit;
9565 	}
9566 
9567 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9568 		nlp = vport->node_table[i];
9569 		while (nlp != NULL) {
9570 			bzero((void *)&nlp->sd_dev_bucket[0],
9571 			    sizeof (struct SD_time_stats_v0) *
9572 			    SD_IO_LATENCY_MAX_BUCKETS);
9573 
9574 			nlp = nlp->nlp_list_next;
9575 		}
9576 	}
9577 
9578 	vport->sd_io_latency_state = SD_COLLECTING;
9579 	rw_exit(&vport->node_rwlock);
9580 
9581 	mutex_enter(&sd_bucket_mutex);
9582 	sd_bucket.state = SD_COLLECTING;
9583 	mutex_exit(&sd_bucket_mutex);
9584 
9585 start_collect_exit:
9586 	return (rval);
9587 }
9588 
9589 
9590 static int32_t
9591 emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9592 {
9593 	emlxs_port_t	*vport;
9594 	emlxs_hba_t	*temp_hba;
9595 	uint8_t		wwpn[8];
9596 	int32_t		rval = DFC_SD_OK;
9597 	int		i, j;
9598 
9599 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9600 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9601 		goto stop_collect_exit;
9602 	}
9603 
9604 	if (sd_bucket.search_type == 0) {
9605 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9606 		goto stop_collect_exit;
9607 	}
9608 
9609 	/* Read the wwn object */
9610 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9611 
9612 	/* Make sure WWPN is unique */
9613 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9614 
9615 	if (!vport) {
9616 		rval = DFC_SD_ERROR_INVALID_PORT;
9617 		goto stop_collect_exit;
9618 	}
9619 
9620 	rw_enter(&vport->node_rwlock, RW_READER);
9621 	if (vport->sd_io_latency_state != SD_COLLECTING) {
9622 		rval = DFC_SD_ERROR_DATA_COLLECTION_NOT_ACTIVE;
9623 		rw_exit(&vport->node_rwlock);
9624 		goto stop_collect_exit;
9625 	}
9626 	vport->sd_io_latency_state = SD_STOPPED;
9627 	rw_exit(&vport->node_rwlock);
9628 
9629 	/* see if any other port is collecting io latency */
9630 	for (i = 0; i < emlxs_device.hba_count; i++) {
9631 		temp_hba = emlxs_device.hba[i];
9632 		for (j = 0; j < temp_hba->num_of_ports; j++) {
9633 			vport = &temp_hba->port[j];
9634 			if (vport->sd_io_latency_state == SD_COLLECTING)
9635 				goto stop_collect_exit;
9636 		}
9637 	}
9638 
9639 	/*
9640 	 * if we get here, that means no one else is collecting
9641 	 * io latency data.
9642 	 */
9643 	mutex_enter(&sd_bucket_mutex);
9644 	sd_bucket.state = SD_STOPPED;
9645 	mutex_exit(&sd_bucket_mutex);
9646 
9647 stop_collect_exit:
9648 	return (rval);
9649 }
9650 
9651 
9652 static int32_t
9653 emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9654 {
9655 	emlxs_port_t   *vport;
9656 	NODELIST	*nlp;
9657 	uint8_t		wwpn[8];
9658 	int32_t 	rval = DFC_SD_OK;
9659 	int		i;
9660 
9661 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9662 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9663 		goto reset_collect_exit;
9664 	}
9665 
9666 	if (sd_bucket.search_type == 0) {
9667 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9668 		goto reset_collect_exit;
9669 	}
9670 
9671 	/* Read the wwn object */
9672 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9673 
9674 	/* Make sure WWPN is unique */
9675 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9676 
9677 	if (!vport) {
9678 		rval = DFC_SD_ERROR_INVALID_PORT;
9679 		goto reset_collect_exit;
9680 	}
9681 
9682 	/* traverse list of nodes for this vport and reset counter */
9683 	rw_enter(&vport->node_rwlock, RW_READER);
9684 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9685 		nlp = vport->node_table[i];
9686 		while (nlp != NULL) {
9687 			bzero((void *)&nlp->sd_dev_bucket[0],
9688 			    sizeof (struct SD_time_stats_v0) *
9689 			    SD_IO_LATENCY_MAX_BUCKETS);
9690 
9691 			nlp = nlp->nlp_list_next;
9692 		}
9693 	}
9694 	rw_exit(&vport->node_rwlock);
9695 
9696 reset_collect_exit:
9697 	return (rval);
9698 }
9699 
9700 
9701 static int32_t
9702 emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9703 {
9704 	emlxs_port_t   *vport;
9705 	uint8_t		wwpn[8];
9706 	int		i, skip_bytes;
9707 	uint16_t	count;
9708 	uint32_t	bufsize, size_needed;
9709 	NODELIST	*nlp;
9710 	int32_t 	rval = DFC_SD_OK;
9711 
9712 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9713 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9714 		goto get_data_exit;
9715 	}
9716 
9717 	if (sd_bucket.search_type == 0) {
9718 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9719 		goto get_data_exit;
9720 	}
9721 
9722 	/* Read the wwn object */
9723 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9724 
9725 	/* Make sure WWPN is unique */
9726 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9727 
9728 	if (!vport) {
9729 		rval = DFC_SD_ERROR_INVALID_PORT;
9730 		goto get_data_exit;
9731 	}
9732 
9733 	bufsize = dfc->buf4_size;
9734 
9735 	/*
9736 	 * count # of targets to see if buffer is big enough
9737 	 */
9738 	count = 0;
9739 	rw_enter(&vport->node_rwlock, RW_READER);
9740 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9741 		nlp = vport->node_table[i];
9742 		while (nlp != NULL) {
9743 			count++;
9744 			nlp = nlp->nlp_list_next;
9745 		}
9746 	}
9747 	rw_exit(&vport->node_rwlock);
9748 
9749 	size_needed = count * (sizeof (HBA_WWN) +
9750 	    sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS);
9751 
9752 	if (bufsize < size_needed) {
9753 		rval = DFC_SD_ERROR_MORE_DATA_AVAIL;
9754 		goto update_count;	/* not enough space, return */
9755 	}
9756 
9757 	/*
9758 	 * return data collected, reset counter.
9759 	 */
9760 	count = 0;
9761 	skip_bytes = 0;
9762 	rw_enter(&vport->node_rwlock, RW_READER);
9763 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9764 		nlp = vport->node_table[i];
9765 		while (nlp != NULL) {
9766 			/* copy port name */
9767 			(void) ddi_copyout((void *)&nlp->nlp_portname,
9768 			    (void *)((char *)dfc->buf4 + skip_bytes),
9769 			    sizeof (HBA_WWN), mode);
9770 			skip_bytes += sizeof (HBA_WWN);
9771 
9772 			/* copy bucket data */
9773 			(void) ddi_copyout((void *)&nlp->sd_dev_bucket[0],
9774 			    (void *)((char *)dfc->buf4 + skip_bytes),
9775 			    sizeof (struct SD_time_stats_v0) *
9776 			    SD_IO_LATENCY_MAX_BUCKETS, mode);
9777 			skip_bytes += sizeof (struct SD_time_stats_v0) *
9778 			    SD_IO_LATENCY_MAX_BUCKETS;
9779 
9780 			bzero((void *)&nlp->sd_dev_bucket[0],
9781 			    sizeof (struct SD_time_stats_v0) *
9782 			    SD_IO_LATENCY_MAX_BUCKETS);
9783 
9784 			count++;
9785 			bufsize -= sizeof (struct SD_IO_Latency_Response);
9786 
9787 			nlp = nlp->nlp_list_next;
9788 		}
9789 	}
9790 	rw_exit(&vport->node_rwlock);
9791 
9792 update_count:
9793 	(void) ddi_copyout((void *)&count, (void *)dfc->buf2,
9794 	    sizeof (uint16_t), mode);
9795 
9796 get_data_exit:
9797 	return (rval);
9798 }
9799 
9800 
9801 static int32_t
9802 emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9803 {
9804 	emlxs_port_t		*vport;
9805 	uint8_t			wwpn[8];
9806 	uint32_t		event, pid, enable;
9807 	int32_t 		rval = DFC_SD_OK;
9808 	int			i, count;
9809 	emlxs_dfc_event_t	*dfc_event;
9810 
9811 	/*
9812 	 * The value of "event" has been shifted left based on
9813 	 * the category that the application gave to libdfc.
9814 	 *
9815 	 * This is so the old Event handling code won't mistakenly
9816 	 * grab an SD Event.
9817 	 */
9818 	event = dfc->data1;
9819 	pid = dfc->data3;
9820 	enable = dfc->flag;
9821 
9822 	/* Read the wwn object */
9823 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9824 
9825 	/* Make sure WWPN is unique */
9826 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9827 
9828 	if (!vport) {
9829 		rval = DFC_SD_ERROR_INVALID_PORT;
9830 		goto set_sd_event_exit;
9831 	}
9832 
9833 	if (enable) {
9834 		/* Find next available event object */
9835 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9836 			dfc_event = &vport->sd_events[i];
9837 
9838 			if (!dfc_event->pid && !dfc_event->event)
9839 				break;
9840 		}
9841 
9842 		/* Return if all event objects are busy */
9843 		if (i == MAX_DFC_EVENTS) {
9844 			rval = DFC_SD_ERROR_OUT_OF_HANDLES;
9845 			goto set_sd_event_exit;
9846 		}
9847 
9848 		/* Initialize */
9849 		/* TODO: Should we add SUBCAT in dfc_event ??? */
9850 		dfc_event->pid = pid;
9851 		dfc_event->event = event;
9852 		dfc_event->last_id = (uint32_t)-1;
9853 		dfc_event->dataout = NULL;
9854 		dfc_event->size = 0;
9855 		dfc_event->mode = 0;
9856 
9857 		(void) emlxs_get_sd_event(vport, dfc_event, 0);
9858 
9859 		if (dfc->buf1)
9860 			(void) ddi_copyout((void *) &dfc_event->last_id,
9861 			    dfc->buf1, sizeof (uint32_t), mode);
9862 
9863 		vport->sd_event_mask |= event;
9864 	} else { /* Disable */
9865 		/* find event entry */
9866 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9867 			dfc_event = &vport->sd_events[i];
9868 
9869 			if (dfc_event->pid  == pid && dfc_event->event == event)
9870 				break;
9871 		}
9872 
9873 		/* Return if not found */
9874 		if (i == MAX_DFC_EVENTS) {
9875 			rval = DFC_SD_ERROR_INVALID_ARG;
9876 			goto set_sd_event_exit;
9877 		}
9878 
9879 		/* Kill the event thread if it is sleeping */
9880 		(void) emlxs_kill_dfc_event(vport, dfc_event);
9881 
9882 		/* Count the number of pids still registered for this event */
9883 		count = 0;
9884 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9885 			dfc_event = &vport->sd_events[i];
9886 
9887 			if (dfc_event->event == event)
9888 				count++;
9889 		}
9890 
9891 		/*
9892 		 * If no more pids need this event,
9893 		 * then disable logging for this event
9894 		 */
9895 		if (count == 0)
9896 			vport->sd_event_mask &= ~event;
9897 	}
9898 
9899 set_sd_event_exit:
9900 	return (rval);
9901 } /* emlxs_dfc_sd_set_event */
9902 
9903 
9904 static int32_t
9905 emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9906 {
9907 	emlxs_port_t   *vport;
9908 	uint8_t		wwpn[8];
9909 	uint32_t	event, pid, sleep, i;
9910 	int32_t		rval = DFC_SD_OK;
9911 	emlxs_dfc_event_t *dfc_event;
9912 
9913 	event = dfc->data1;
9914 	pid = dfc->data2;
9915 
9916 	/* Read the wwn object */
9917 	(void) ddi_copyin((void *)dfc->buf4, (void *)wwpn, 8, mode);
9918 
9919 	/* Make sure WWPN is unique */
9920 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9921 
9922 	if (!vport) {
9923 		rval = DFC_SD_ERROR_INVALID_PORT;
9924 		goto get_sd_event_exit;
9925 	}
9926 
9927 	/* Find the event entry */
9928 	dfc_event = NULL;
9929 	for (i = 0; i < MAX_DFC_EVENTS; i++) {
9930 		dfc_event = &vport->sd_events[i];
9931 
9932 		if (dfc_event->pid == pid && dfc_event->event == event)
9933 			break;
9934 	}
9935 
9936 	if (i == MAX_DFC_EVENTS) {
9937 		rval = DFC_SD_ERROR_GENERIC;
9938 		goto get_sd_event_exit;
9939 	}
9940 
9941 	if (!(vport->sd_event_mask & dfc_event->event)) {
9942 		rval = DFC_SD_ERROR_GENERIC;
9943 		goto get_sd_event_exit;
9944 	}
9945 
9946 	/* Initialize event buffer pointers */
9947 	dfc_event->dataout = dfc->buf1;
9948 	dfc_event->size = dfc->buf1_size;
9949 	dfc_event->last_id = dfc->data3;
9950 	dfc_event->mode = mode;
9951 
9952 	sleep = (dfc->flag & 0x01) ? 1 : 0;
9953 
9954 	if (emlxs_get_sd_event(vport, dfc_event, sleep))
9955 		return (DFC_SD_ERROR_GENERIC);
9956 
9957 	/*
9958 	 * update rcv_size.
9959 	 */
9960 	if (dfc->buf2)
9961 		(void) ddi_copyout((void *) &dfc_event->size, dfc->buf2,
9962 		    sizeof (uint32_t), mode);
9963 
9964 	/*
9965 	 * update index
9966 	 */
9967 	if (dfc->buf3)
9968 		(void) ddi_copyout((void *) &dfc_event->last_id, dfc->buf3,
9969 		    sizeof (uint32_t), mode);
9970 
9971 get_sd_event_exit:
9972 	return (rval);
9973 } /* emlxs_dfc_sd_get_event */
9974 #endif
9975 
9976 static int32_t
9977 emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9978 {
9979 	emlxs_port_t			*port = &PPORT;
9980 	fc_packet_t			*pkt = NULL;
9981 	NODELIST			*ndlp;
9982 	FCP_CMND			*fcp_cmd;
9983 	FCP_RSP				*fcp_rsp;
9984 	void				*ptr;
9985 	char				buffer[64];
9986 	dfc_send_scsi_fcp_cmd_info_t	cmdinfo;
9987 	uint32_t			rval = 0;
9988 
9989 	/* cmd info */
9990 	if (!dfc->buf1 ||
9991 	    (dfc->buf1_size != sizeof (dfc_send_scsi_fcp_cmd_info_t))) {
9992 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9993 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9994 
9995 		rval = DFC_ARG_NULL;
9996 		goto done;
9997 	}
9998 
9999 	/* reqBuffer info */
10000 	if (!dfc->buf2 || (dfc->buf2_size != sizeof (FCP_CMND))) {
10001 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10002 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
10003 
10004 		rval = DFC_ARG_NULL;
10005 		goto done;
10006 	}
10007 
10008 	/* rspBuffer info, could be 0 for SCSI commands like TUR */
10009 	if (!dfc->buf3 && dfc->buf3_size) {
10010 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10011 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
10012 
10013 		rval = DFC_ARG_NULL;
10014 		goto done;
10015 	}
10016 
10017 	/* senseBuffer info */
10018 	if (!dfc->buf4 || !dfc->buf4_size) {
10019 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10020 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
10021 
10022 		rval = DFC_ARG_NULL;
10023 		goto done;
10024 	}
10025 
10026 	if (ddi_copyin((void *) dfc->buf1, (void *) &cmdinfo,
10027 	    sizeof (dfc_send_scsi_fcp_cmd_info_t), mode) != 0) {
10028 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10029 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
10030 
10031 		rval = DFC_COPYIN_ERROR;
10032 		goto done;
10033 	}
10034 
10035 	if (cmdinfo.ver == DFC_SEND_SCSI_FCP_V2) {
10036 		port =
10037 		    emlxs_vport_find_wwpn(hba, (uint8_t *)&cmdinfo.src_wwn);
10038 		if (port == NULL) {
10039 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10040 			    "%s: WWPN does not exists. %s",
10041 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
10042 			    (uint8_t *)&cmdinfo.src_wwn));
10043 
10044 			rval = DFC_ARG_INVALID;
10045 			goto done;
10046 		}
10047 	}
10048 
10049 	if ((ndlp = emlxs_node_find_wwpn(port,
10050 	    (uint8_t *)&cmdinfo.dst_wwn)) == NULL) {
10051 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10052 		    "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd),
10053 		    emlxs_wwn_xlate(buffer, (uint8_t *)&cmdinfo.dst_wwn));
10054 
10055 		rval = DFC_ARG_INVALID;
10056 		goto done;
10057 	}
10058 
10059 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (FCP_CMND), sizeof (FCP_RSP),
10060 	    dfc->buf3_size, KM_NOSLEEP))) {
10061 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10062 		    "%s: Unable to allocate packet.",
10063 		    emlxs_dfc_xlate(dfc->cmd));
10064 
10065 		rval = DFC_SYSRES_ERROR;
10066 		goto done;
10067 	}
10068 	fcp_cmd = (FCP_CMND *) pkt->pkt_cmd;
10069 	/* Copy in the command buffer */
10070 	if (ddi_copyin((void *)dfc->buf2, (void *)fcp_cmd, sizeof (FCP_CMND),
10071 	    mode) != 0) {
10072 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10073 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
10074 
10075 		rval = DFC_COPYIN_ERROR;
10076 		goto done;
10077 	}
10078 
10079 	/* Make this a polled IO */
10080 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
10081 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
10082 	pkt->pkt_comp = NULL;
10083 
10084 	/* Build the fc header */
10085 	pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID);
10086 	pkt->pkt_cmd_fhdr.r_ctl = FC_FCP_CMND;
10087 	pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
10088 	pkt->pkt_cmd_fhdr.type = FC_FCP_DATA;
10089 	pkt->pkt_cmd_fhdr.seq_id = 0;
10090 	pkt->pkt_cmd_fhdr.df_ctl = 0;
10091 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
10092 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
10093 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
10094 	pkt->pkt_cmd_fhdr.ro = 0;
10095 
10096 	pkt->pkt_timeout = 30;
10097 
10098 	if ((fcp_cmd->fcpCntl3 == WRITE_DATA) && dfc->buf3_size) {
10099 		pkt->pkt_tran_type = FC_PKT_FCP_WRITE;
10100 		if (ddi_copyin((void *)dfc->buf3, (void *)pkt->pkt_data,
10101 		    dfc->buf3_size, mode) != 0) {
10102 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10103 			    "%s: ddi_copyin failed.",
10104 			    emlxs_dfc_xlate(dfc->cmd));
10105 
10106 			rval = DFC_COPYIN_ERROR;
10107 			goto done;
10108 		}
10109 	} else {
10110 		pkt->pkt_tran_type = FC_PKT_FCP_READ;
10111 	}
10112 
10113 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
10114 		rval = DFC_IO_ERROR;
10115 		goto done;
10116 	}
10117 
10118 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
10119 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
10120 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10121 			    "Pkt Transport error. Pkt Timeout.");
10122 			rval = DFC_TIMEOUT;
10123 		} else {
10124 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10125 			    "Pkt Transport error. state=%x", pkt->pkt_state);
10126 			rval = DFC_IO_ERROR;
10127 		}
10128 		goto done;
10129 	}
10130 
10131 	if (pkt->pkt_data_resid) {
10132 		if (pkt->pkt_data_resid < dfc->buf3_size)
10133 			dfc->buf3_size -= pkt->pkt_data_resid;
10134 		else
10135 			dfc->buf3_size = 0;
10136 	}
10137 
10138 	SCSI_RSP_CNT(cmdinfo) = dfc->buf3_size;
10139 
10140 	fcp_rsp = (FCP_RSP *) pkt->pkt_resp;
10141 	/*
10142 	 * This is sense count for flag = 0.
10143 	 * It is fcp response size for flag = 1.
10144 	 */
10145 	if (dfc->flag) {
10146 		SCSI_SNS_CNT(cmdinfo) = 24 + LE_SWAP32(fcp_rsp->rspSnsLen) +
10147 		    LE_SWAP32(fcp_rsp->rspRspLen);
10148 		ptr = (void *)fcp_rsp;
10149 	} else {
10150 		SCSI_SNS_CNT(cmdinfo) = LE_SWAP32(fcp_rsp->rspSnsLen);
10151 		ptr = (void *)&fcp_rsp->rspSnsInfo[0];
10152 	}
10153 
10154 	if (ddi_copyout((void *) &cmdinfo, (void *) dfc->buf1,
10155 	    sizeof (dfc_send_scsi_fcp_cmd_info_t), mode) != 0) {
10156 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10157 		    "%s: rsp_buf ddi_copyout failed.",
10158 		    emlxs_dfc_xlate(dfc->cmd));
10159 
10160 		rval = DFC_COPYOUT_ERROR;
10161 		goto done;
10162 	}
10163 
10164 	if (SCSI_SNS_CNT(cmdinfo)) {
10165 		if (ddi_copyout(ptr, (void *)dfc->buf4, SCSI_SNS_CNT(cmdinfo),
10166 		    mode) != 0) {
10167 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10168 			    "%s: rsp_size ddi_copyout failed.",
10169 			    emlxs_dfc_xlate(dfc->cmd));
10170 
10171 			rval = DFC_COPYOUT_ERROR;
10172 			goto done;
10173 		}
10174 	}
10175 
10176 	if (SCSI_RSP_CNT(cmdinfo)) {
10177 		if (ddi_copyout((void *)pkt->pkt_data, (void *)dfc->buf3,
10178 		    SCSI_RSP_CNT(cmdinfo), mode) != 0) {
10179 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10180 			    "%s: rsp_size ddi_copyout failed.",
10181 			    emlxs_dfc_xlate(dfc->cmd));
10182 
10183 			rval = DFC_COPYOUT_ERROR;
10184 			goto done;
10185 		}
10186 	}
10187 
10188 
10189 	rval = 0;
10190 
10191 done:
10192 	if (pkt) {
10193 		emlxs_pkt_free(pkt);
10194 	}
10195 
10196 	return (rval);
10197 
10198 } /* emlxs_dfc_send_scsi_fcp() */
10199 
10200 
10201 static int32_t
10202 emlxs_dfc_get_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10203 {
10204 	emlxs_port_t		*port = &PPORT;
10205 	emlxs_config_t		*cfg = &CFG;
10206 	uint16_t		linkdown = 0;
10207 	uint32_t		rval = 0;
10208 
10209 	if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
10210 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10211 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
10212 
10213 		return (DFC_FCOE_NOTSUPPORTED);
10214 	}
10215 
10216 	if (!dfc->buf1 || !dfc->buf1_size) {
10217 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10218 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10219 
10220 		return (DFC_ARG_NULL);
10221 	}
10222 
10223 	linkdown = (uint16_t)cfg[CFG_PERSIST_LINKDOWN].current;
10224 	if (ddi_copyout((void *)&linkdown, dfc->buf1, dfc->buf1_size,
10225 	    mode) != 0) {
10226 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10227 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
10228 
10229 		return (DFC_COPYOUT_ERROR);
10230 	}
10231 
10232 	return (rval);
10233 
10234 } /* emlxs_dfc_get_persist_linkdown() */
10235 
10236 
10237 /*ARGSUSED*/
10238 static int32_t
10239 emlxs_dfc_set_persist_linkdown(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10240 {
10241 	emlxs_port_t		*port = &PPORT;
10242 	emlxs_config_t		*cfg = &CFG;
10243 	uint32_t		rval = 0;
10244 
10245 	if (hba->model_info.flags & EMLXS_FCOE_SUPPORTED) {
10246 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10247 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
10248 
10249 		return (DFC_FCOE_NOTSUPPORTED);
10250 	}
10251 
10252 	if (dfc->data1) {
10253 		cfg[CFG_PERSIST_LINKDOWN].current = 1;
10254 	} else {
10255 		cfg[CFG_PERSIST_LINKDOWN].current = 0;
10256 	}
10257 
10258 	return (rval);
10259 
10260 } /* emlxs_dfc_set_persist_linkdown() */
10261 
10262 
10263 static int32_t
10264 emlxs_dfc_get_fcflist(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10265 {
10266 	emlxs_port_t		*port = &PPORT;
10267 	DFC_FCoEFCFInfo_t	*fcflistentry;
10268 	DFC_FCoEFCFList_t	*fcflist;
10269 	FCFIobj_t		*fcfp;
10270 	uint32_t		size;
10271 	uint32_t		i;
10272 	uint32_t		count = 0;
10273 	uint32_t		rval = 0;
10274 
10275 	if (!dfc->buf1 || !dfc->buf1_size) {
10276 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10277 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10278 
10279 		return (DFC_ARG_NULL);
10280 	}
10281 
10282 	if (dfc->buf1_size < sizeof (DFC_FCoEFCFList_t)) {
10283 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10284 		    "%s: Buffer1 too small. (size=%d)",
10285 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10286 
10287 		return (DFC_ARG_TOOSMALL);
10288 	}
10289 
10290 	if (! (hba->model_info.flags & EMLXS_FCOE_SUPPORTED)) {
10291 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10292 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
10293 
10294 		return (DFC_FCOE_NOTSUPPORTED);
10295 	}
10296 
10297 	if (hba->state != FC_READY) {
10298 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10299 		    "%s: HBA not ready.", emlxs_dfc_xlate(dfc->cmd));
10300 
10301 		return (DFC_DRV_ERROR);
10302 	}
10303 
10304 	size = sizeof (DFC_FCoEFCFList_t) +
10305 	    hba->sli.sli4.fcftab.table_count * sizeof (DFC_FCoEFCFInfo_t);
10306 	fcflist = (DFC_FCoEFCFList_t *)kmem_zalloc(size, KM_SLEEP);
10307 
10308 	if (ddi_copyin(dfc->buf1, (void *)fcflist,
10309 	    sizeof (DFC_FCoEFCFList_t), mode) != 0) {
10310 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10311 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
10312 
10313 		rval = DFC_COPYIN_ERROR;
10314 		goto done;
10315 	}
10316 
10317 	fcflistentry = fcflist->entries;
10318 	mutex_enter(&EMLXS_FCF_LOCK);
10319 	fcfp = hba->sli.sli4.fcftab.table;
10320 	for (i = 0; i < hba->sli.sli4.fcftab.table_count; i++, fcfp++) {
10321 		if ((fcfp->state != FCFI_STATE_FREE) &&
10322 		    (fcfp->fcf_rec.fcf_valid)) {
10323 			fcflistentry->Priority = fcfp->fcf_rec.fip_priority;
10324 			if (fcfp->fcf_rec.fcf_available) {
10325 				fcflistentry->State = FCF_AVAILABLE_STATE;
10326 			}
10327 			fcflistentry->LKA_Period = fcfp->fcf_rec.fka_adv_period;
10328 
10329 			bcopy((void *)fcfp->fcf_rec.vlan_bitmap,
10330 			    (void *)fcflistentry->VLanBitMap, 512);
10331 			bcopy((void *)fcfp->fcf_rec.fc_map,
10332 			    (void *)fcflistentry->FC_Map, 3);
10333 			bcopy((void *)fcfp->fcf_rec.fabric_name_identifier,
10334 			    (void *)fcflistentry->FabricName, 8);
10335 			bcopy((void *)fcfp->fcf_rec.switch_name_identifier,
10336 			    (void *)fcflistentry->SwitchName, 8);
10337 			bcopy((void *)&fcfp->fcf_rec.fcf_mac_address_hi,
10338 			    (void *)fcflistentry->Mac, 6);
10339 
10340 			count++;
10341 			fcflistentry++;
10342 		}
10343 	}
10344 	mutex_exit(&EMLXS_FCF_LOCK);
10345 
10346 	fcflist->nActiveFCFs = hba->sli.sli4.fcftab.fcfi_count;
10347 
10348 	if (count > fcflist->numberOfEntries) {
10349 		rval = DFC_ARG_TOOSMALL;
10350 	}
10351 
10352 	i = sizeof (DFC_FCoEFCFList_t) +
10353 	    (fcflist->numberOfEntries - 1) * sizeof (DFC_FCoEFCFInfo_t);
10354 	fcflist->numberOfEntries = (uint16_t)count;
10355 
10356 	if (ddi_copyout((void *) fcflist, dfc->buf1,
10357 	    i, mode) != 0) {
10358 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10359 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
10360 
10361 		rval = DFC_COPYOUT_ERROR;
10362 		goto done;
10363 	}
10364 
10365 done:
10366 	kmem_free(fcflist, size);
10367 	return (rval);
10368 
10369 } /* emlxs_dfc_get_fcflist() */
10370 
10371 
10372 static int32_t
10373 emlxs_dfc_send_mbox4(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10374 {
10375 	emlxs_port_t	*port = &PPORT;
10376 	MAILBOX4	*mb4 = NULL;
10377 	MAILBOXQ	*mbq = NULL;
10378 	MBUF_INFO	bufinfo;
10379 	uint32_t	offset;
10380 	int32_t		mbxstatus = 0;
10381 	uint32_t	rval = 0;
10382 
10383 	if (!dfc->buf1 || !dfc->buf1_size) {
10384 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10385 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10386 
10387 		return (DFC_ARG_NULL);
10388 	}
10389 
10390 	if (!dfc->buf2 || !dfc->buf2_size) {
10391 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10392 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
10393 
10394 		return (DFC_ARG_NULL);
10395 	}
10396 
10397 	if ((dfc->buf1_size != sizeof (MAILBOX4)) &&
10398 	    (dfc->buf2_size != sizeof (MAILBOX4))) {
10399 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10400 		    "%s: Invalid buffer size. (size=%d)",
10401 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
10402 
10403 		return (DFC_ARG_INVALID);
10404 	}
10405 
10406 	if (dfc->buf3_size && !dfc->buf3) {
10407 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10408 		    "%s: NULL buffer3 found.",
10409 		    emlxs_dfc_xlate(dfc->cmd));
10410 
10411 		return (DFC_ARG_INVALID);
10412 	}
10413 
10414 	if (! (hba->model_info.flags & EMLXS_FCOE_SUPPORTED)) {
10415 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10416 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
10417 
10418 		return (DFC_FCOE_NOTSUPPORTED);
10419 	}
10420 
10421 	bzero(&bufinfo, sizeof (MBUF_INFO));
10422 	if (dfc->buf3_size) {
10423 		bufinfo.size = dfc->buf3_size;
10424 		bufinfo.flags = FC_MBUF_DMA | FC_MBUF_SNGLSG | FC_MBUF_DMA32;
10425 		bufinfo.align = ddi_ptob(hba->dip, 1L);
10426 		(void) emlxs_mem_alloc(hba, &bufinfo);
10427 
10428 		if (bufinfo.virt == NULL) {
10429 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10430 			    "%s: Unable to allocate buffer.",
10431 			    emlxs_dfc_xlate(dfc->cmd));
10432 
10433 			rval = DFC_SYSRES_ERROR;
10434 			goto done;
10435 		}
10436 
10437 		if (ddi_copyin((void *)dfc->buf3, (void *)bufinfo.virt,
10438 		    dfc->buf3_size, mode) != 0) {
10439 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10440 			    "%s: ddi_copyin failed", emlxs_dfc_xlate(dfc->cmd));
10441 
10442 			rval = DFC_COPYIN_ERROR;
10443 			goto done;
10444 		}
10445 	}
10446 
10447 	mbq =
10448 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10449 
10450 	mb4 = (MAILBOX4 *) mbq;
10451 
10452 	bzero((void *)mb4, sizeof (MAILBOX4));
10453 
10454 	if (ddi_copyin((void *)dfc->buf1, (void *)mb4, dfc->buf1_size,
10455 	    mode) != 0) {
10456 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10457 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
10458 
10459 		rval = DFC_COPYIN_ERROR;
10460 		goto done;
10461 	}
10462 
10463 	if (dfc->buf3_size) {
10464 		offset = dfc->data3;
10465 		mb4->un.varWords[offset-1] = PADDR_LO(bufinfo.phys);
10466 		mb4->un.varWords[offset] = PADDR_HI(bufinfo.phys);
10467 	}
10468 
10469 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
10470 	    "%s: %s sent.  (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd),
10471 	    emlxs_mb_cmd_xlate(mb4->mbxCommand), mb4->un.varWords[0],
10472 	    mb4->un.varWords[1], mb4->un.varWords[2], mb4->un.varWords[3]);
10473 
10474 	/* issue the mbox cmd to the sli */
10475 	mbxstatus = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10476 
10477 	if (mbxstatus) {
10478 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10479 		    "%s: %s failed. mbxstatus=0x%x",
10480 		    emlxs_dfc_xlate(dfc->cmd),
10481 		    emlxs_mb_cmd_xlate(mb4->mbxCommand), mbxstatus);
10482 	}
10483 
10484 	if (ddi_copyout((void *)mb4, (void *)dfc->buf2, dfc->buf2_size,
10485 	    mode) != 0) {
10486 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10487 		    "%s: ddi_copyout failed. cmd=%x",
10488 		    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10489 
10490 		rval = DFC_COPYOUT_ERROR;
10491 		goto done;
10492 	}
10493 
10494 	if (dfc->buf3_size) {
10495 		if (ddi_copyout((void *)bufinfo.virt, (void *)dfc->buf3,
10496 		    dfc->buf3_size, mode) != 0) {
10497 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10498 			    "%s: ddi_copyout failed. cmd=%x",
10499 			    emlxs_dfc_xlate(dfc->cmd), mb4->mbxCommand);
10500 
10501 			rval = DFC_COPYOUT_ERROR;
10502 			goto done;
10503 		}
10504 	}
10505 done:
10506 	/* Free allocated memory */
10507 	if (bufinfo.virt) {
10508 		emlxs_mem_free(hba, &bufinfo);
10509 	}
10510 
10511 	if (mbq) {
10512 		kmem_free(mbq, sizeof (MAILBOXQ));
10513 	}
10514 
10515 	return (rval);
10516 } /* emlxs_dfc_send_mbox4() */
10517 
10518 
10519 static int
10520 emlxs_dfc_rd_be_fcf(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10521 {
10522 	emlxs_port_t			*port = &PPORT;
10523 	MATCHMAP			*mp;
10524 	MAILBOX4			*mb  = NULL;
10525 	MAILBOXQ			*mbq = NULL;
10526 	IOCTL_FCOE_READ_FCF_TABLE	*fcf;
10527 	mbox_req_hdr_t			*hdr_req;
10528 	mbox_rsp_hdr_t			*hdr_rsp;
10529 	FCF_RECORD_t			*fcfrec;
10530 	uint32_t			rc = 0;
10531 	uint32_t			rval = 0;
10532 	uint16_t			index;
10533 
10534 	if (!dfc->buf1 || !dfc->buf1_size) {
10535 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10536 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
10537 
10538 		return (DFC_ARG_NULL);
10539 	}
10540 
10541 	mbq =
10542 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10543 
10544 	index = dfc->data1;
10545 	mb = (MAILBOX4 *)mbq;
10546 
10547 	bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
10548 
10549 	if ((mp = (MATCHMAP *)emlxs_mem_get(hba, MEM_BUF, 1)) == 0) {
10550 		rval = DFC_SYSRES_ERROR;
10551 		goto done;
10552 	}
10553 	bzero(mp->virt, mp->size);
10554 
10555 	/*
10556 	 * Signifies a non-embedded command
10557 	 */
10558 	mb->un.varSLIConfig.be.embedded = 0;
10559 	mbq->nonembed = (void *)mp;
10560 	mbq->mbox_cmpl = NULL;
10561 
10562 	mb->mbxCommand = MBX_SLI_CONFIG;
10563 	mb->mbxOwner = OWN_HOST;
10564 
10565 	hdr_req = (mbox_req_hdr_t *)mp->virt;
10566 	hdr_rsp = (mbox_rsp_hdr_t *)mp->virt;
10567 
10568 	hdr_req->subsystem = IOCTL_SUBSYSTEM_FCOE;
10569 	hdr_req->opcode = FCOE_OPCODE_READ_FCF_TABLE;
10570 	hdr_req->timeout = 0;
10571 	hdr_req->req_length = sizeof (IOCTL_FCOE_READ_FCF_TABLE);
10572 	fcf = (IOCTL_FCOE_READ_FCF_TABLE *)(hdr_req + 1);
10573 	fcf->params.request.fcf_index = index;
10574 
10575 	rc =  EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10576 	if (rc == MBX_SUCCESS) {
10577 		fcfrec = &fcf->params.response.fcf_entry[0];
10578 		if (ddi_copyout((void *)fcfrec, (void *)dfc->buf1,
10579 		    dfc->buf1_size, mode) != 0) {
10580 			rval = DFC_COPYOUT_ERROR;
10581 		}
10582 		if (ddi_copyout(
10583 		    (void *)&fcf->params.response.next_valid_fcf_index,
10584 		    (void *)dfc->buf2, dfc->buf2_size, mode) != 0) {
10585 			rval = DFC_COPYOUT_ERROR;
10586 		}
10587 	} else {
10588 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10589 		    "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd),
10590 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rc);
10591 
10592 		if ((rc == MBX_NONEMBED_ERROR) &&
10593 		    (hdr_rsp->status == MBX_RSP_STATUS_NO_FCF)) {
10594 			rval = DFC_FCOE_NO_DATA;
10595 		} else {
10596 			rval = DFC_IO_ERROR;
10597 		}
10598 	}
10599 done:
10600 	if (mp)
10601 		emlxs_mem_put(hba, MEM_BUF, (void *)mp);
10602 	if (mbq)
10603 		kmem_free(mbq, sizeof (MAILBOXQ));
10604 
10605 	return (rval);
10606 }
10607 
10608 
10609 /*ARGSUSED*/
10610 static int
10611 emlxs_dfc_set_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10612 {
10613 	emlxs_port_t				*port = &PPORT;
10614 	MAILBOXQ				*mbq = NULL;
10615 	MAILBOX4				*mb;
10616 	IOCTL_DCBX_SET_DCBX_MODE		*dcbx_mode;
10617 	uint32_t				port_num = 0;
10618 	uint32_t				rval = 0;
10619 
10620 	mbq =
10621 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10622 
10623 	mb = (MAILBOX4 *)mbq;
10624 
10625 	/*
10626 	 * Signifies an embedded command
10627 	 */
10628 	mb->un.varSLIConfig.be.embedded = 1;
10629 	mbq->mbox_cmpl = NULL;
10630 
10631 	mb->mbxCommand = MBX_SLI_CONFIG;
10632 	mb->mbxOwner = OWN_HOST;
10633 	mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ;
10634 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
10635 	    IOCTL_SUBSYSTEM_DCBX;
10636 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode =
10637 	    DCBX_OPCODE_SET_DCBX_MODE;
10638 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
10639 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
10640 	    sizeof (IOCTL_DCBX_SET_DCBX_MODE);
10641 	dcbx_mode = (IOCTL_DCBX_SET_DCBX_MODE *)&mb->un.varSLIConfig.payload;
10642 	dcbx_mode->params.request.port_num = (uint8_t)port_num;
10643 	dcbx_mode->params.request.dcbx_mode = dfc->data1;
10644 
10645 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
10646 	    "%s requested on port %d.", emlxs_dfc_xlate(dfc->cmd), port_num);
10647 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10648 	if (rval != MBX_SUCCESS) {
10649 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10650 		    "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd),
10651 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
10652 
10653 		rval = DFC_DRV_ERROR;
10654 	}
10655 
10656 done:
10657 	if (mbq)
10658 		kmem_free(mbq, sizeof (MAILBOXQ));
10659 
10660 	return (rval);
10661 }
10662 
10663 
10664 static int
10665 emlxs_dfc_get_be_dcbx(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10666 {
10667 	emlxs_port_t				*port = &PPORT;
10668 	MAILBOXQ				*mbq = NULL;
10669 	MAILBOX4				*mb;
10670 	IOCTL_DCBX_GET_DCBX_MODE		*dcbx_mode;
10671 	uint32_t				port_num = 0;
10672 	uint32_t				rval = 0;
10673 
10674 	mbq =
10675 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP);
10676 
10677 	mb = (MAILBOX4 *)mbq;
10678 
10679 	/*
10680 	 * Signifies an embedded command
10681 	 */
10682 	mb->un.varSLIConfig.be.embedded = 1;
10683 	mbq->mbox_cmpl = NULL;
10684 
10685 	mb->mbxCommand = MBX_SLI_CONFIG;
10686 	mb->mbxOwner = OWN_HOST;
10687 	mb->un.varSLIConfig.be.payload_length = IOCTL_HEADER_SZ;
10688 	mb->un.varSLIConfig.be.un_hdr.hdr_req.subsystem =
10689 	    IOCTL_SUBSYSTEM_DCBX;
10690 	mb->un.varSLIConfig.be.un_hdr.hdr_req.opcode =
10691 	    DCBX_OPCODE_GET_DCBX_MODE;
10692 	mb->un.varSLIConfig.be.un_hdr.hdr_req.timeout = 0;
10693 	mb->un.varSLIConfig.be.un_hdr.hdr_req.req_length =
10694 	    sizeof (IOCTL_DCBX_SET_DCBX_MODE);
10695 	dcbx_mode = (IOCTL_DCBX_GET_DCBX_MODE *)&mb->un.varSLIConfig.payload;
10696 	dcbx_mode->params.request.port_num = (uint8_t)port_num;
10697 
10698 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
10699 	    "%s requested on port %d.", emlxs_dfc_xlate(dfc->cmd), port_num);
10700 	rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0);
10701 	if (rval != MBX_SUCCESS) {
10702 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10703 		    "%s: %s failed. mbxstatus=0x%x", emlxs_dfc_xlate(dfc->cmd),
10704 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
10705 
10706 		rval = DFC_DRV_ERROR;
10707 		goto done;
10708 	}
10709 
10710 	if (ddi_copyout((void *)&dcbx_mode->params.response.dcbx_mode,
10711 	    (void *)dfc->buf1, dfc->buf1_size, mode) != 0) {
10712 		rval = DFC_COPYOUT_ERROR;
10713 	}
10714 
10715 done:
10716 	if (mbq)
10717 		kmem_free(mbq, sizeof (MAILBOXQ));
10718 
10719 	return (rval);
10720 }
10721 
10722 
10723 static int
10724 emlxs_dfc_get_qos(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
10725 {
10726 	emlxs_port_t	*port = &PPORT;
10727 	uint32_t	rval = 0;
10728 
10729 	if (! (hba->model_info.flags & EMLXS_FCOE_SUPPORTED)) {
10730 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10731 		    "%s: FCoE not  supported.", emlxs_dfc_xlate(dfc->cmd));
10732 
10733 		return (DFC_FCOE_NOTSUPPORTED);
10734 	}
10735 
10736 	if (dfc->buf1_size) {
10737 		if (ddi_copyout((void *)&hba->qos_linkspeed, (void *)dfc->buf1,
10738 		    dfc->buf1_size, mode) != 0) {
10739 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10740 			    "%s: ddi_copyout failed.",
10741 			    emlxs_dfc_xlate(dfc->cmd));
10742 
10743 			rval = DFC_COPYOUT_ERROR;
10744 			return (rval);
10745 		}
10746 	}
10747 
10748 	return (rval);
10749 
10750 } /* emlxs_dfc_get_qos() */
10751