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