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