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 	return (0);
3490 
3491 } /* emlxs_dfc_get_hbainfo() */
3492 
3493 
3494 
3495 static int32_t
3496 emlxs_dfc_get_hbastats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3497 {
3498 	emlxs_port_t	*port = &PPORT;
3499 	dfc_hbastats_t	stats;
3500 	MAILBOX		*mb = NULL;
3501 	MAILBOXQ	*mbq = NULL;
3502 	uint32_t	rval = 0;
3503 
3504 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
3505 	    emlxs_dfc_xlate(dfc->cmd));
3506 
3507 	if (!dfc->buf1 || !dfc->buf1_size) {
3508 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3509 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3510 
3511 		return (DFC_ARG_NULL);
3512 	}
3513 
3514 	if (dfc->buf1_size < sizeof (dfc_hbastats_t)) {
3515 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3516 		    "%s: Buffer1 too small. (size=%d)",
3517 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3518 
3519 		return (DFC_ARG_TOOSMALL);
3520 	}
3521 
3522 	if ((mbq =
3523 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) {
3524 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3525 		    "%s: Unable to allocate mailbox buffer.",
3526 		    emlxs_dfc_xlate(dfc->cmd));
3527 
3528 		return (DFC_SYSRES_ERROR);
3529 	}
3530 
3531 	mb = (MAILBOX *)mbq;
3532 
3533 	emlxs_mb_read_status(hba, mb);
3534 
3535 	rval = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
3536 
3537 	if (rval == MBX_TIMEOUT) {
3538 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3539 		    "%s: Mailbox timed out. cmd=%x",
3540 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
3541 
3542 		rval = DFC_TIMEOUT;
3543 		goto done;
3544 	}
3545 
3546 	if (rval) {
3547 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3548 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
3549 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
3550 
3551 		rval = DFC_IO_ERROR;
3552 		goto done;
3553 	}
3554 
3555 	bzero((void *) &stats, sizeof (dfc_hbastats_t));
3556 
3557 	stats.tx_frame_cnt = mb->un.varRdStatus.xmitFrameCnt;
3558 	stats.rx_frame_cnt = mb->un.varRdStatus.rcvFrameCnt;
3559 	stats.tx_kbyte_cnt = mb->un.varRdStatus.xmitByteCnt;
3560 	stats.rx_kbyte_cnt = mb->un.varRdStatus.rcvByteCnt;
3561 	stats.tx_seq_cnt = mb->un.varRdStatus.xmitSeqCnt;
3562 	stats.rx_seq_cnt = mb->un.varRdStatus.rcvSeqCnt;
3563 	stats.orig_exch_cnt = mb->un.varRdStatus.totalOrigExchanges;
3564 	stats.resp_exch_cnt = mb->un.varRdStatus.totalRespExchanges;
3565 	stats.pbsy_cnt = mb->un.varRdStatus.rcvPbsyCnt;
3566 	stats.fbsy_cnt = mb->un.varRdStatus.rcvFbsyCnt;
3567 
3568 	emlxs_mb_read_lnk_stat(hba, mb);
3569 
3570 	rval = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
3571 
3572 	if (rval == MBX_TIMEOUT) {
3573 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3574 		    "%s: Mailbox timed out. cmd=%x",
3575 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
3576 
3577 		rval = DFC_TIMEOUT;
3578 		goto done;
3579 	}
3580 
3581 	if (rval) {
3582 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3583 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
3584 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
3585 
3586 		rval = DFC_IO_ERROR;
3587 		goto done;
3588 	}
3589 
3590 	stats.link_failure_cnt = mb->un.varRdLnk.linkFailureCnt;
3591 	stats.loss_sync_cnt = mb->un.varRdLnk.lossSyncCnt;
3592 	stats.loss_signal_cnt = mb->un.varRdLnk.lossSignalCnt;
3593 	stats.seq_error_cnt = mb->un.varRdLnk.primSeqErrCnt;
3594 	stats.inval_tx_word_cnt = mb->un.varRdLnk.invalidXmitWord;
3595 	stats.crc_error_cnt = mb->un.varRdLnk.crcCnt;
3596 	stats.seq_timeout_cnt = mb->un.varRdLnk.primSeqTimeout;
3597 	stats.elastic_overrun_cnt = mb->un.varRdLnk.elasticOverrun;
3598 	stats.arb_timeout_cnt = mb->un.varRdLnk.arbTimeout;
3599 	stats.rx_buf_credit = mb->un.varRdLnk.rxBufCredit;
3600 	stats.rx_buf_cnt = mb->un.varRdLnk.rxBufCreditCur;
3601 	stats.tx_buf_credit = mb->un.varRdLnk.txBufCredit;
3602 	stats.tx_buf_cnt = mb->un.varRdLnk.txBufCreditCur;
3603 	stats.EOFa_cnt = mb->un.varRdLnk.EOFaCnt;
3604 	stats.EOFdti_cnt = mb->un.varRdLnk.EOFdtiCnt;
3605 	stats.EOFni_cnt = mb->un.varRdLnk.EOFniCnt;
3606 	stats.SOFf_cnt = mb->un.varRdLnk.SOFfCnt;
3607 	stats.link_event_tag = hba->link_event_tag;
3608 	stats.last_reset_time = hba->timer_tics - hba->stats.ResetTime;
3609 	stats.port_type = HBA_PORTTYPE_UNKNOWN;
3610 
3611 #ifdef MENLO_SUPPORT
3612 	if (hba->flag & FC_MENLO_MODE) {
3613 		stats.topology = LNK_MENLO_MAINTENANCE;
3614 	} else
3615 #endif /* MENLO_SUPPORT */
3616 
3617 	if (hba->state >= FC_LINK_UP) {
3618 		if (hba->topology == TOPOLOGY_LOOP) {
3619 			if (hba->flag & FC_FABRIC_ATTACHED) {
3620 				stats.port_type = HBA_PORTTYPE_NLPORT;
3621 				stats.topology = LNK_PUBLIC_LOOP;
3622 			} else {
3623 				stats.port_type = HBA_PORTTYPE_LPORT;
3624 				stats.topology = LNK_LOOP;
3625 			}
3626 		} else {
3627 			if (hba->flag & FC_FABRIC_ATTACHED) {
3628 				stats.port_type = HBA_PORTTYPE_NPORT;
3629 				stats.topology = LNK_FABRIC;
3630 			} else {
3631 				stats.port_type = HBA_PORTTYPE_PTP;
3632 				stats.topology = LNK_PT2PT;
3633 			}
3634 		}
3635 
3636 		if (hba->linkspeed == LA_2GHZ_LINK) {
3637 			stats.link_speed = HBA_PORTSPEED_2GBIT;
3638 		} else if (hba->linkspeed == LA_4GHZ_LINK) {
3639 			stats.link_speed = HBA_PORTSPEED_4GBIT;
3640 		} else if (hba->linkspeed == LA_8GHZ_LINK) {
3641 			stats.link_speed = HBA_PORTSPEED_8GBIT;
3642 		} else if (hba->linkspeed == LA_10GHZ_LINK) {
3643 			stats.link_speed = HBA_PORTSPEED_10GBIT;
3644 		} else {
3645 			stats.link_speed = HBA_PORTSPEED_1GBIT;
3646 		}
3647 	}
3648 
3649 	if (ddi_copyout((void *)&stats, (void *)dfc->buf1,
3650 	    sizeof (dfc_hbastats_t), mode) != 0) {
3651 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3652 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3653 
3654 		return (DFC_COPYOUT_ERROR);
3655 	}
3656 
3657 done:
3658 
3659 	/* Free allocated mbox memory */
3660 	if (mbq) {
3661 		kmem_free(mbq, sizeof (MAILBOXQ));
3662 	}
3663 
3664 	return (rval);
3665 
3666 } /* emlxs_dfc_get_hbastats() */
3667 
3668 
3669 
3670 static int32_t
3671 emlxs_dfc_get_drvstats(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3672 {
3673 	emlxs_port_t	*port = &PPORT;
3674 	dfc_drvstats_t	stats;
3675 	uint32_t	rval = 0;
3676 
3677 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
3678 	    emlxs_dfc_xlate(dfc->cmd));
3679 
3680 	if (!dfc->buf1 || !dfc->buf1_size) {
3681 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3682 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3683 
3684 		return (DFC_ARG_NULL);
3685 	}
3686 
3687 	bzero((void *) &stats, sizeof (dfc_drvstats_t));
3688 
3689 	stats.LinkUp = hba->stats.LinkUp;
3690 	stats.LinkDown = hba->stats.LinkDown;
3691 	stats.LinkEvent = hba->stats.LinkEvent;
3692 	stats.LinkMultiEvent = hba->stats.LinkMultiEvent;
3693 
3694 	stats.MboxIssued = hba->stats.MboxIssued;
3695 	stats.MboxCompleted = hba->stats.MboxCompleted;
3696 	stats.MboxGood = hba->stats.MboxGood;
3697 	stats.MboxError = hba->stats.MboxError;
3698 	stats.MboxBusy = hba->stats.MboxBusy;
3699 	stats.MboxInvalid = hba->stats.MboxInvalid;
3700 
3701 	stats.IocbIssued[0] = hba->stats.IocbIssued[0];
3702 	stats.IocbIssued[1] = hba->stats.IocbIssued[1];
3703 	stats.IocbIssued[2] = hba->stats.IocbIssued[2];
3704 	stats.IocbIssued[3] = hba->stats.IocbIssued[3];
3705 	stats.IocbReceived[0] = hba->stats.IocbReceived[0];
3706 	stats.IocbReceived[1] = hba->stats.IocbReceived[1];
3707 	stats.IocbReceived[2] = hba->stats.IocbReceived[2];
3708 	stats.IocbReceived[3] = hba->stats.IocbReceived[3];
3709 	stats.IocbTxPut[0] = hba->stats.IocbTxPut[0];
3710 	stats.IocbTxPut[1] = hba->stats.IocbTxPut[1];
3711 	stats.IocbTxPut[2] = hba->stats.IocbTxPut[2];
3712 	stats.IocbTxPut[3] = hba->stats.IocbTxPut[3];
3713 	stats.IocbTxGet[0] = hba->stats.IocbTxGet[0];
3714 	stats.IocbTxGet[1] = hba->stats.IocbTxGet[1];
3715 	stats.IocbTxGet[2] = hba->stats.IocbTxGet[2];
3716 	stats.IocbTxGet[3] = hba->stats.IocbTxGet[3];
3717 	stats.IocbRingFull[0] = hba->stats.IocbRingFull[0];
3718 	stats.IocbRingFull[1] = hba->stats.IocbRingFull[1];
3719 	stats.IocbRingFull[2] = hba->stats.IocbRingFull[2];
3720 	stats.IocbRingFull[3] = hba->stats.IocbRingFull[3];
3721 
3722 	stats.IntrEvent[0] = hba->stats.IntrEvent[0];
3723 	stats.IntrEvent[1] = hba->stats.IntrEvent[1];
3724 	stats.IntrEvent[2] = hba->stats.IntrEvent[2];
3725 	stats.IntrEvent[3] = hba->stats.IntrEvent[3];
3726 	stats.IntrEvent[4] = hba->stats.IntrEvent[4];
3727 	stats.IntrEvent[5] = hba->stats.IntrEvent[5];
3728 	stats.IntrEvent[6] = hba->stats.IntrEvent[6];
3729 	stats.IntrEvent[7] = hba->stats.IntrEvent[7];
3730 
3731 	stats.FcpIssued = hba->stats.FcpIssued;
3732 	stats.FcpCompleted = hba->stats.FcpCompleted;
3733 	stats.FcpGood = hba->stats.FcpGood;
3734 	stats.FcpError = hba->stats.FcpError;
3735 
3736 	stats.FcpEvent = hba->stats.FcpEvent;
3737 	stats.FcpStray = hba->stats.FcpStray;
3738 
3739 	stats.ElsEvent = hba->stats.ElsEvent;
3740 	stats.ElsStray = hba->stats.ElsStray;
3741 
3742 	stats.ElsCmdIssued = hba->stats.ElsCmdIssued;
3743 	stats.ElsCmdCompleted = hba->stats.ElsCmdCompleted;
3744 	stats.ElsCmdGood = hba->stats.ElsCmdGood;
3745 	stats.ElsCmdError = hba->stats.ElsCmdError;
3746 
3747 	stats.ElsRspIssued = hba->stats.ElsRspIssued;
3748 	stats.ElsRspCompleted = hba->stats.ElsRspCompleted;
3749 
3750 	stats.ElsRcvEvent = hba->stats.ElsRcvEvent;
3751 	stats.ElsRcvError = hba->stats.ElsRcvError;
3752 	stats.ElsRcvDropped = hba->stats.ElsRcvDropped;
3753 	stats.ElsCmdReceived = hba->stats.ElsCmdReceived;
3754 	stats.ElsRscnReceived = hba->stats.ElsRscnReceived;
3755 	stats.ElsPlogiReceived = hba->stats.ElsPlogiReceived;
3756 	stats.ElsPrliReceived = hba->stats.ElsPrliReceived;
3757 	stats.ElsPrloReceived = hba->stats.ElsPrloReceived;
3758 	stats.ElsLogoReceived = hba->stats.ElsLogoReceived;
3759 	stats.ElsAdiscReceived = hba->stats.ElsAdiscReceived;
3760 	stats.ElsGenReceived = hba->stats.ElsGenReceived;
3761 
3762 	stats.CtEvent = hba->stats.CtEvent;
3763 	stats.CtStray = hba->stats.CtStray;
3764 
3765 	stats.CtCmdIssued = hba->stats.CtCmdIssued;
3766 	stats.CtCmdCompleted = hba->stats.CtCmdCompleted;
3767 	stats.CtCmdGood = hba->stats.CtCmdGood;
3768 	stats.CtCmdError = hba->stats.CtCmdError;
3769 
3770 	stats.CtRspIssued = hba->stats.CtRspIssued;
3771 	stats.CtRspCompleted = hba->stats.CtRspCompleted;
3772 
3773 	stats.CtRcvEvent = hba->stats.CtRcvEvent;
3774 	stats.CtRcvError = hba->stats.CtRcvError;
3775 	stats.CtRcvDropped = hba->stats.CtRcvDropped;
3776 	stats.CtCmdReceived = hba->stats.CtCmdReceived;
3777 
3778 	stats.IpEvent = hba->stats.IpEvent;
3779 	stats.IpStray = hba->stats.IpStray;
3780 
3781 	stats.IpSeqIssued = hba->stats.IpSeqIssued;
3782 	stats.IpSeqCompleted = hba->stats.IpSeqCompleted;
3783 	stats.IpSeqGood = hba->stats.IpSeqGood;
3784 	stats.IpSeqError = hba->stats.IpSeqError;
3785 
3786 	stats.IpBcastIssued = hba->stats.IpBcastIssued;
3787 	stats.IpBcastCompleted = hba->stats.IpBcastCompleted;
3788 	stats.IpBcastGood = hba->stats.IpBcastGood;
3789 	stats.IpBcastError = hba->stats.IpBcastError;
3790 
3791 	stats.IpRcvEvent = hba->stats.IpRcvEvent;
3792 	stats.IpDropped = hba->stats.IpDropped;
3793 	stats.IpSeqReceived = hba->stats.IpSeqReceived;
3794 	stats.IpBcastReceived = hba->stats.IpBcastReceived;
3795 
3796 	stats.IpUbPosted = hba->stats.IpUbPosted;
3797 	stats.ElsUbPosted = hba->stats.ElsUbPosted;
3798 	stats.CtUbPosted = hba->stats.CtUbPosted;
3799 
3800 #if (DFC_REV >= 2)
3801 	stats.IocbThrottled   = hba->stats.IocbThrottled;
3802 	stats.ElsAuthReceived = hba->stats.ElsAuthReceived;
3803 #endif
3804 
3805 	if (ddi_copyout((void *)&stats, (void *)dfc->buf1, dfc->buf1_size,
3806 	    mode) != 0) {
3807 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3808 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3809 
3810 		return (DFC_COPYOUT_ERROR);
3811 	}
3812 
3813 	return (rval);
3814 
3815 } /* emlxs_dfc_get_drvstats() */
3816 
3817 
3818 extern uint32_t
3819 emlxs_set_hba_mode(emlxs_hba_t *hba, uint32_t mode)
3820 {
3821 	emlxs_port_t	*port = &PPORT;
3822 	uint32_t	i;
3823 
3824 	mutex_enter(&EMLXS_PORT_LOCK);
3825 
3826 	/* Wait if adapter is in transition */
3827 	i = 0;
3828 	while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
3829 		if (i++ > 30) {
3830 			break;
3831 		}
3832 
3833 		mutex_exit(&EMLXS_PORT_LOCK);
3834 		delay(drv_usectohz(1000000));
3835 		mutex_enter(&EMLXS_PORT_LOCK);
3836 	}
3837 
3838 	switch (mode) {
3839 	case DDI_SHOW:
3840 		break;
3841 
3842 	case DDI_ONDI:
3843 		if (hba->flag & FC_OFFLINE_MODE) {
3844 			mutex_exit(&EMLXS_PORT_LOCK);
3845 			(void) emlxs_online(hba);
3846 			mutex_enter(&EMLXS_PORT_LOCK);
3847 		}
3848 		break;
3849 
3850 
3851 		/* Killed + Restart state */
3852 	case DDI_OFFDI:
3853 		if (hba->flag & FC_ONLINE_MODE) {
3854 			mutex_exit(&EMLXS_PORT_LOCK);
3855 
3856 			(void) emlxs_offline(hba);
3857 
3858 			/* Reset with restart */
3859 			emlxs_sli_hba_reset(hba, 1, 1);
3860 
3861 			mutex_enter(&EMLXS_PORT_LOCK);
3862 		} else if (hba->state < FC_INIT_START) {
3863 			mutex_exit(&EMLXS_PORT_LOCK);
3864 
3865 			/* Reset with restart */
3866 			emlxs_sli_hba_reset(hba, 1, 1);
3867 
3868 			mutex_enter(&EMLXS_PORT_LOCK);
3869 		}
3870 
3871 		break;
3872 
3873 		/* Killed + Reset state */
3874 	case DDI_WARMDI:
3875 		if (hba->flag & FC_ONLINE_MODE) {
3876 			mutex_exit(&EMLXS_PORT_LOCK);
3877 
3878 			(void) emlxs_offline(hba);
3879 
3880 			/* Reset with no restart */
3881 			emlxs_sli_hba_reset(hba, 0, 0);
3882 
3883 			mutex_enter(&EMLXS_PORT_LOCK);
3884 		} else if (hba->state != FC_WARM_START) {
3885 			mutex_exit(&EMLXS_PORT_LOCK);
3886 
3887 			/* Reset with no restart */
3888 			emlxs_sli_hba_reset(hba, 0, 0);
3889 
3890 			mutex_enter(&EMLXS_PORT_LOCK);
3891 		}
3892 
3893 		break;
3894 
3895 		/* Killed */
3896 	case DDI_DIAGDI:
3897 		if (hba->flag & FC_ONLINE_MODE) {
3898 			mutex_exit(&EMLXS_PORT_LOCK);
3899 
3900 			(void) emlxs_offline(hba);
3901 
3902 			mutex_enter(&EMLXS_PORT_LOCK);
3903 		} else if (hba->state != FC_KILLED) {
3904 			mutex_exit(&EMLXS_PORT_LOCK);
3905 
3906 			emlxs_sli_offline(hba);
3907 
3908 			mutex_enter(&EMLXS_PORT_LOCK);
3909 		}
3910 
3911 		break;
3912 
3913 	default:
3914 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3915 		    "emlxs_set_hba_mode: Invalid mode. mode%x", mode);
3916 	}
3917 
3918 	/* Wait if adapter is in transition */
3919 	i = 0;
3920 	while ((hba->flag & (FC_ONLINING_MODE | FC_OFFLINING_MODE))) {
3921 		if (i++ > 30) {
3922 			break;
3923 		}
3924 
3925 		mutex_exit(&EMLXS_PORT_LOCK);
3926 		delay(drv_usectohz(1000000));
3927 		mutex_enter(&EMLXS_PORT_LOCK);
3928 	}
3929 
3930 	/* Return current state */
3931 	if (hba->flag & FC_ONLINE_MODE) {
3932 		mode = DDI_ONDI;
3933 	} else if (hba->state == FC_KILLED) {
3934 		mode = DDI_DIAGDI;
3935 	} else if (hba->state == FC_WARM_START) {
3936 		mode = DDI_WARMDI;
3937 	} else {
3938 		mode = DDI_OFFDI;
3939 	}
3940 
3941 	mutex_exit(&EMLXS_PORT_LOCK);
3942 
3943 	return (mode);
3944 
3945 } /* emlxs_set_hba_mode() */
3946 
3947 
3948 static int32_t
3949 emlxs_dfc_set_diag(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3950 {
3951 	emlxs_port_t	*port = &PPORT;
3952 	int32_t		rval = 0;
3953 	int32_t		flag;
3954 
3955 	if (!dfc->buf1 || !dfc->buf1_size) {
3956 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3957 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
3958 
3959 		return (DFC_ARG_NULL);
3960 	}
3961 
3962 	if (dfc->buf1_size < sizeof (uint32_t)) {
3963 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3964 		    "%s: Buffer1 too small. (size=%d)",
3965 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
3966 
3967 		return (DFC_ARG_TOOSMALL);
3968 	}
3969 
3970 	flag = emlxs_set_hba_mode(hba, dfc->flag);
3971 
3972 	if (ddi_copyout((void *)&flag, (void *)dfc->buf1, sizeof (uint32_t),
3973 	    mode) != 0) {
3974 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
3975 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
3976 
3977 		return (DFC_COPYOUT_ERROR);
3978 	}
3979 
3980 	return (rval);
3981 
3982 } /* emlxs_dfc_set_diag() */
3983 
3984 
3985 
3986 static int32_t
3987 emlxs_dfc_send_mbox(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
3988 {
3989 	emlxs_port_t	*port  = &PPORT;
3990 	MAILBOX		*mb    = NULL;
3991 	MAILBOXQ	*mbq   = NULL;
3992 	uint32_t	size  = 0;
3993 	MATCHMAP	*rx_mp = NULL;
3994 	MATCHMAP	*tx_mp = NULL;
3995 	uintptr_t	lptr;
3996 	int32_t		rval  = 0;
3997 	int32_t		mbxstatus = 0;
3998 	NODELIST	*ndlp;
3999 	uint32_t	did;
4000 	uint32_t	extsize = 0;
4001 	uint8_t		*extbuf  = NULL;
4002 
4003 	if (!dfc->buf1 || !dfc->buf1_size) {
4004 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4005 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4006 
4007 		return (DFC_ARG_NULL);
4008 	}
4009 
4010 	if (!dfc->buf2 || !dfc->buf2_size) {
4011 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4012 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
4013 
4014 		return (DFC_ARG_NULL);
4015 	}
4016 
4017 	if (dfc->buf1_size > MAILBOX_CMD_BSIZE) {
4018 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4019 		    "%s: Buffer1 too large. (size=%d)",
4020 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
4021 
4022 		return (DFC_ARG_TOOBIG);
4023 	}
4024 #ifdef MBOX_EXT_SUPPORT
4025 	if (dfc->buf3_size || dfc->buf4_size) {
4026 		if (dfc->buf3_size && !dfc->buf3) {
4027 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4028 			    "%s: Null buffer3 found.",
4029 			    emlxs_dfc_xlate(dfc->cmd));
4030 
4031 			return (DFC_ARG_NULL);
4032 		}
4033 
4034 		if (dfc->buf3_size > MBOX_EXTENSION_SIZE) {
4035 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4036 			    "%s: buffer3 too large. (size=%d)",
4037 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
4038 
4039 			return (DFC_ARG_TOOBIG);
4040 		}
4041 
4042 		if (dfc->buf4_size && !dfc->buf4) {
4043 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4044 			    "%s: Null buffer4 found.",
4045 			    emlxs_dfc_xlate(dfc->cmd));
4046 
4047 			return (DFC_ARG_NULL);
4048 		}
4049 
4050 		if (dfc->buf4_size > MBOX_EXTENSION_SIZE) {
4051 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4052 			    "%s: buffer4 too large. (size=%d)",
4053 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
4054 
4055 			return (DFC_ARG_TOOBIG);
4056 		}
4057 
4058 		extsize =
4059 		    (dfc->buf3_size >
4060 		    dfc->buf4_size) ? dfc->buf3_size : dfc->buf4_size;
4061 		if ((extbuf =
4062 		    (uint8_t *)kmem_zalloc(extsize, KM_SLEEP)) == 0) {
4063 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4064 			    "%s: Unable to allocate mailbox extension buffer.",
4065 			    emlxs_dfc_xlate(dfc->cmd));
4066 
4067 			return (DFC_SYSRES_ERROR);
4068 		}
4069 
4070 		if (dfc->buf3_size) {
4071 			if (ddi_copyin((void *)dfc->buf3, (void *)extbuf,
4072 			    dfc->buf3_size, mode) != 0) {
4073 				EMLXS_MSGF(EMLXS_CONTEXT,
4074 				    &emlxs_dfc_error_msg,
4075 				    "%s: ddi_copyin mbox extension data "
4076 				    "failed.", emlxs_dfc_xlate(dfc->cmd));
4077 
4078 				rval = DFC_COPYIN_ERROR;
4079 				goto done;
4080 			}
4081 		}
4082 	}
4083 #endif /* MBOX_EXT_SUPPORT */
4084 
4085 	if ((mbq =
4086 	    (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ), KM_SLEEP)) == 0) {
4087 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4088 		    "%s: Unable to allocate mailbox buffer.",
4089 		    emlxs_dfc_xlate(dfc->cmd));
4090 
4091 		rval = DFC_SYSRES_ERROR;
4092 		goto done;
4093 	}
4094 
4095 	mb = (MAILBOX *) mbq;
4096 
4097 	bzero((void *) mb, MAILBOX_CMD_BSIZE);
4098 
4099 	if (ddi_copyin((void *)dfc->buf1, (void *)mb, dfc->buf1_size,
4100 	    mode) != 0) {
4101 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4102 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
4103 
4104 		rval = DFC_COPYIN_ERROR;
4105 		goto done;
4106 	}
4107 #ifdef _LP64
4108 	if ((mb->mbxCommand == MBX_READ_SPARM) ||
4109 	    (mb->mbxCommand == MBX_READ_RPI) ||
4110 	    (mb->mbxCommand == MBX_REG_LOGIN) ||
4111 	    (mb->mbxCommand == MBX_READ_LA) ||
4112 	    (mb->mbxCommand == MBX_RUN_BIU_DIAG)) {
4113 
4114 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4115 		    "%s: Invalid mailbox command. Must use 64bit version. "
4116 		    "cmd=%x", emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4117 
4118 		/* Must use 64 bit versions of these mbox cmds */
4119 		rval = DFC_ARG_INVALID;
4120 		goto done;
4121 	}
4122 #endif
4123 
4124 	lptr = 0;
4125 	size = 0;
4126 	switch (mb->mbxCommand) {
4127 	/* Offline only */
4128 	case MBX_CONFIG_LINK:	/* 0x07 */
4129 	case MBX_PART_SLIM:	    /* 0x08 */
4130 	case MBX_CONFIG_RING:	/* 0x09 */
4131 	case MBX_DUMP_CONTEXT:	/* 0x18 */
4132 	case MBX_RUN_DIAGS:	    /* 0x19 */
4133 	case MBX_RESTART:	    /* 0x1A */
4134 	case MBX_SET_MASK:	    /* 0x20 */
4135 	case MBX_FLASH_WR_ULA:	/* 0x98 */
4136 		if (!(hba->flag & FC_OFFLINE_MODE)) {
4137 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4138 			    "%s: Adapter not offline. cmd=%x",
4139 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4140 
4141 			rval = DFC_ONLINE_ERROR;
4142 			goto done;
4143 		}
4144 		break;
4145 
4146 	/* Online / Offline */
4147 	case MBX_UNREG_LOGIN:	/* 0x14 */
4148 		ndlp = emlxs_node_find_rpi(port, mb->un.varUnregLogin.rpi);
4149 
4150 		if (ndlp) {
4151 			did = ndlp->nlp_DID;
4152 
4153 			/* remove it */
4154 			emlxs_node_rm(port, ndlp);
4155 
4156 			/*
4157 			 * If we just unregistered the host node then
4158 			 * clear the host DID
4159 			 */
4160 			if (did == port->did) {
4161 				port->did = 0;
4162 			}
4163 		} else {
4164 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4165 			    "%s: Node not found. cmd=%x rpi=%x",
4166 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand,
4167 			    mb->un.varUnregLogin.rpi);
4168 
4169 			/* Node does not exist */
4170 			rval = DFC_ARG_INVALID;
4171 			goto done;
4172 		}
4173 
4174 		/* Send it */
4175 		break;
4176 
4177 	case MBX_UNREG_D_ID:	/* 0x23 */
4178 
4179 		did = mb->un.varRegLogin.did;
4180 
4181 		if (did == 0) {
4182 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4183 			    "%s: Node not found. cmd=%x did=%x",
4184 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4185 
4186 			rval = DFC_ARG_INVALID;
4187 			goto done;
4188 		}
4189 
4190 		if (did == 0xffffffff) {
4191 			emlxs_node_destroy_all(port);
4192 			break;
4193 		}
4194 
4195 		/* Check for base node */
4196 		if (did == Bcast_DID) {
4197 			/* just flush base node */
4198 			(void) emlxs_tx_node_flush(port, &port->node_base,
4199 			    0, 0, 0);
4200 			(void) emlxs_chipq_node_flush(port, 0, &port->node_base,
4201 			    0);
4202 
4203 			/* Return now */
4204 			rval = 0;
4205 			goto done;
4206 		}
4207 
4208 		/* Make sure the node does already exist */
4209 		ndlp = emlxs_node_find_did(port, did);
4210 
4211 		if (ndlp) {
4212 			/* remove it */
4213 			emlxs_node_rm(port, ndlp);
4214 
4215 			/*
4216 			 * If we just unregistered the host node then
4217 			 * clear the host DID
4218 			 */
4219 			if (did == port->did) {
4220 				port->did = 0;
4221 			}
4222 		} else {
4223 
4224 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4225 			    "%s: Node not found. cmd=%x did=%x",
4226 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4227 
4228 			/* Node does not exist */
4229 			rval = DFC_ARG_INVALID;
4230 			goto done;
4231 		}
4232 
4233 		/* Send it */
4234 		break;
4235 
4236 	/* Online / Offline - with DMA */
4237 	case MBX_READ_EVENT_LOG:	/* 0x38 */
4238 		lptr =
4239 		    (uintptr_t)getPaddr(mb->un.varRdEvtLog.un.sp64.addrHigh,
4240 		    mb->un.varRdEvtLog.un.sp64.addrLow);
4241 		size = (int)mb->un.varRdEvtLog.un.sp64.tus.f.bdeSize;
4242 
4243 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4244 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4245 			    "%s: Invalid BDE. cmd=%x",
4246 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4247 
4248 			rval = DFC_ARG_INVALID;
4249 			goto done;
4250 		}
4251 
4252 		/* Allocate receive buffer */
4253 		if ((rx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4254 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4255 			    "%s: Unable to allocate receive buffer. cmd=%x",
4256 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4257 
4258 			rval = DFC_DRVRES_ERROR;
4259 			goto done;
4260 		}
4261 
4262 		mb->un.varRdEvtLog.un.sp64.addrHigh = putPaddrHigh(rx_mp->phys);
4263 		mb->un.varRdEvtLog.un.sp64.addrLow = putPaddrLow(rx_mp->phys);
4264 		mb->un.varRdEvtLog.un.sp64.tus.f.bdeFlags = 0;
4265 
4266 		break;
4267 
4268 	case MBX_READ_SPARM:	/* 0x0D */
4269 	case MBX_READ_SPARM64:	/* 0x8D */
4270 		lptr =
4271 		    (uintptr_t)getPaddr(mb->un.varRdSparm.un.sp64.addrHigh,
4272 		    mb->un.varRdSparm.un.sp64.addrLow);
4273 		size = (int)mb->un.varRdSparm.un.sp64.tus.f.bdeSize;
4274 
4275 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4276 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4277 			    "%s: Invalid BDE. cmd=%x",
4278 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4279 
4280 			rval = DFC_ARG_INVALID;
4281 			goto done;
4282 		}
4283 
4284 		/* Allocate receive buffer */
4285 		if ((rx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4286 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4287 			    "%s: Unable to allocate receive buffer. cmd=%x",
4288 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4289 
4290 			rval = DFC_DRVRES_ERROR;
4291 			goto done;
4292 		}
4293 
4294 		mb->un.varRdSparm.un.sp64.addrHigh = putPaddrHigh(rx_mp->phys);
4295 		mb->un.varRdSparm.un.sp64.addrLow = putPaddrLow(rx_mp->phys);
4296 		mb->un.varRdSparm.un.sp64.tus.f.bdeFlags = 0;
4297 
4298 		break;
4299 
4300 	case MBX_READ_RPI:	/* 0x0F */
4301 	case MBX_READ_RPI64:	/* 0x8F */
4302 		lptr =
4303 		    (uintptr_t)getPaddr(mb->un.varRdRPI.un.sp64.addrHigh,
4304 		    mb->un.varRdRPI.un.sp64.addrLow);
4305 		size = (int)mb->un.varRdRPI.un.sp64.tus.f.bdeSize;
4306 
4307 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4308 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4309 			    "%s: Invalid BDE. cmd=%x",
4310 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4311 
4312 			rval = DFC_ARG_INVALID;
4313 			goto done;
4314 		}
4315 
4316 		/* Allocate receive buffer */
4317 		if ((rx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4318 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4319 			    "%s: Unable to allocate receive buffer. cmd=%x",
4320 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4321 
4322 			rval = DFC_DRVRES_ERROR;
4323 			goto done;
4324 		}
4325 
4326 		mb->un.varRdRPI.un.sp64.addrHigh = putPaddrHigh(rx_mp->phys);
4327 		mb->un.varRdRPI.un.sp64.addrLow = putPaddrLow(rx_mp->phys);
4328 		mb->un.varRdRPI.un.sp64.tus.f.bdeFlags = 0;
4329 
4330 		break;
4331 
4332 	case MBX_RUN_BIU_DIAG:	 /* 0x04 */
4333 	case MBX_RUN_BIU_DIAG64: /* 0x84 */
4334 		lptr =
4335 		    (uintptr_t)getPaddr(mb->un.varBIUdiag.un.s2.xmit_bde64.
4336 		    addrHigh, mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow);
4337 		size = (int)mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeSize;
4338 
4339 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4340 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4341 			    "%s: Invalid xmit BDE. cmd=%x",
4342 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4343 
4344 			rval = DFC_ARG_INVALID;
4345 			goto done;
4346 		}
4347 
4348 		/* Allocate xmit buffer */
4349 		if ((tx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4350 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4351 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4352 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4353 
4354 			rval = DFC_DRVRES_ERROR;
4355 			goto done;
4356 		}
4357 
4358 		/* Initialize the xmit buffer */
4359 		if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size,
4360 		    mode) != 0) {
4361 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4362 			    "%s: ddi_copyin failed. cmd=%x",
4363 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4364 
4365 			rval = DFC_COPYIN_ERROR;
4366 			goto done;
4367 		}
4368 		emlxs_mpdata_sync(tx_mp->dma_handle, 0, size,
4369 		    DDI_DMA_SYNC_FORDEV);
4370 
4371 		mb->un.varBIUdiag.un.s2.xmit_bde64.addrHigh =
4372 		    putPaddrHigh(tx_mp->phys);
4373 		mb->un.varBIUdiag.un.s2.xmit_bde64.addrLow =
4374 		    putPaddrLow(tx_mp->phys);
4375 		mb->un.varBIUdiag.un.s2.xmit_bde64.tus.f.bdeFlags = 0;
4376 
4377 		/* Initialize the receive buffer */
4378 		lptr =
4379 		    (uintptr_t)getPaddr(mb->un.varBIUdiag.un.s2.rcv_bde64.
4380 		    addrHigh, mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow);
4381 		size = (int)mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeSize;
4382 
4383 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4384 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4385 			    "%s: Invalid rcv BDE. cmd=%x",
4386 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4387 
4388 			rval = DFC_ARG_INVALID;
4389 			goto done;
4390 		}
4391 
4392 		/* Allocate receive buffer */
4393 		if ((rx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4394 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4395 			    "%s: Unable to allocate receive buffer. cmd=%x",
4396 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4397 
4398 			rval = DFC_DRVRES_ERROR;
4399 			goto done;
4400 		}
4401 
4402 		mb->un.varBIUdiag.un.s2.rcv_bde64.addrHigh =
4403 		    putPaddrHigh(rx_mp->phys);
4404 		mb->un.varBIUdiag.un.s2.rcv_bde64.addrLow =
4405 		    putPaddrLow(rx_mp->phys);
4406 		mb->un.varBIUdiag.un.s2.rcv_bde64.tus.f.bdeFlags = 0;
4407 
4408 		break;
4409 
4410 	case MBX_REG_LOGIN:	/* 0x13 */
4411 	case MBX_REG_LOGIN64:	/* 0x93 */
4412 
4413 		did = mb->un.varRegLogin.did;
4414 
4415 		/* Check for invalid node ids to register */
4416 		if (did == 0 || (did & 0xff000000)) {
4417 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4418 			    "%s: Invalid node id. cmd=%x did=%x",
4419 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand, did);
4420 
4421 			rval = DFC_ARG_INVALID;
4422 			goto done;
4423 		}
4424 
4425 		/* Check if the node limit has been reached */
4426 		if (port->node_count >= hba->max_nodes) {
4427 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4428 			    "%s: Too many nodes. cmd=%x",
4429 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4430 
4431 			rval = DFC_HBARES_ERROR;
4432 			goto done;
4433 		}
4434 
4435 		lptr =
4436 		    (uintptr_t)getPaddr(mb->un.varRegLogin.un.sp64.addrHigh,
4437 		    mb->un.varRegLogin.un.sp64.addrLow);
4438 		size = (int)mb->un.varRegLogin.un.sp64.tus.f.bdeSize;
4439 
4440 		if (!lptr || (size > MEM_BUF_SIZE)) {
4441 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4442 			    "%s: Invalid BDE. cmd=%x",
4443 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4444 
4445 			rval = DFC_ARG_INVALID;
4446 			goto done;
4447 		}
4448 
4449 		/* Allocate xmit buffer */
4450 		if ((tx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4451 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4452 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4453 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4454 
4455 			rval = DFC_DRVRES_ERROR;
4456 			goto done;
4457 		}
4458 
4459 		/* Initialize the xmit buffer */
4460 		if (ddi_copyin((void *)lptr, (void *)tx_mp->virt, size,
4461 		    mode) != 0) {
4462 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4463 			    "%s: Unable to allocate xmit buffer. cmd=%x",
4464 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4465 
4466 			rval = DFC_COPYIN_ERROR;
4467 			goto done;
4468 		}
4469 		emlxs_mpdata_sync(tx_mp->dma_handle, 0, size,
4470 		    DDI_DMA_SYNC_FORDEV);
4471 
4472 		mb->un.varRegLogin.un.sp64.addrHigh = putPaddrHigh(tx_mp->phys);
4473 		mb->un.varRegLogin.un.sp64.addrLow = putPaddrLow(tx_mp->phys);
4474 		mb->un.varRegLogin.un.sp64.tus.f.bdeFlags = 0;
4475 
4476 		break;
4477 
4478 	case MBX_READ_LA:	/* 0x15 */
4479 	case MBX_READ_LA64:	/* 0x95 */
4480 		lptr =
4481 		    (uintptr_t)getPaddr(mb->un.varReadLA.un.lilpBde64.
4482 		    addrHigh, mb->un.varReadLA.un.lilpBde64.addrLow);
4483 		size = (int)mb->un.varReadLA.un.lilpBde64.tus.f.bdeSize;
4484 
4485 		if (!lptr || !size || (size > MEM_BUF_SIZE)) {
4486 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4487 			    "%s: Invalid BDE. cmd=%x",
4488 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4489 
4490 			rval = DFC_ARG_INVALID;
4491 			goto done;
4492 		}
4493 
4494 		/* Allocate receive buffer */
4495 		if ((rx_mp = (MATCHMAP *)emlxs_mem_buf_alloc(hba)) == 0) {
4496 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4497 			    "%s: Unable to allocate receive buffer. cmd=%x",
4498 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4499 
4500 			rval = DFC_DRVRES_ERROR;
4501 			goto done;
4502 		}
4503 
4504 		mb->un.varReadLA.un.lilpBde64.addrHigh =
4505 		    putPaddrHigh(rx_mp->phys);
4506 		mb->un.varReadLA.un.lilpBde64.addrLow =
4507 		    putPaddrLow(rx_mp->phys);
4508 		mb->un.varReadLA.un.lilpBde64.tus.f.bdeFlags = 0;
4509 
4510 		break;
4511 
4512 
4513 		/* Do not allow these commands */
4514 	case MBX_CONFIG_PORT:	/* 0x88 */
4515 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4516 		    "%s: Command not allowed. cmd=%x",
4517 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4518 
4519 		rval = DFC_ARG_INVALID;
4520 		goto done;
4521 
4522 
4523 	/* Online / Offline */
4524 	default:
4525 		break;
4526 
4527 	}	/* switch() */
4528 
4529 	mb->mbxOwner = OWN_HOST;
4530 
4531 	/* Set or don't set the PASSTHRU bit. */
4532 	/* Setting will prevent the driver from processing it as its own */
4533 	switch (mb->mbxCommand) {
4534 	case MBX_REG_LOGIN:	/* 0x13 */
4535 	case MBX_REG_LOGIN64:	/* 0x93 */
4536 		break;
4537 
4538 	default:
4539 		mbq->flag |= MBQ_PASSTHRU;
4540 	}
4541 
4542 #ifdef MBOX_EXT_SUPPORT
4543 	if (extbuf) {
4544 		mbq->extbuf  = extbuf;
4545 		mbq->extsize = extsize;
4546 	}
4547 #endif /* MBOX_EXT_SUPPORT */
4548 
4549 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4550 	    "%s: %s sent.  (%x %x %x %x)", emlxs_dfc_xlate(dfc->cmd),
4551 	    emlxs_mb_cmd_xlate(mb->mbxCommand), mb->un.varWords[0],
4552 	    mb->un.varWords[1], mb->un.varWords[2], mb->un.varWords[3]);
4553 
4554 	/* issue the mbox cmd to the sli */
4555 	mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
4556 
4557 	if (mbxstatus) {
4558 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4559 		    "%s: %s failed. mbxstatus=0x%x",
4560 		    emlxs_dfc_xlate(dfc->cmd),
4561 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
4562 
4563 	}
4564 
4565 	if (ddi_copyout((void *)mb, (void *)dfc->buf2, dfc->buf2_size,
4566 	    mode) != 0) {
4567 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4568 		    "%s: ddi_copyout failed. cmd=%x",
4569 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4570 
4571 		rval = DFC_COPYOUT_ERROR;
4572 		goto done;
4573 	}
4574 
4575 	if (rx_mp) {
4576 		emlxs_mpdata_sync(rx_mp->dma_handle, 0, size,
4577 		    DDI_DMA_SYNC_FORKERNEL);
4578 
4579 		if (ddi_copyout((void *)rx_mp->virt, (void *)lptr, size,
4580 		    mode) != 0) {
4581 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4582 			    "%s: ddi_copyout failed for receive buffer. cmd=%x",
4583 			    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
4584 
4585 			rval = DFC_COPYOUT_ERROR;
4586 			goto done;
4587 		}
4588 	}
4589 #ifdef MBOX_EXT_SUPPORT
4590 	/*  Any data needs to copy to mbox extension area */
4591 	if (dfc->buf4_size) {
4592 		if (ddi_copyout((void *)extbuf, (void *)dfc->buf4,
4593 		    dfc->buf4_size, mode) != 0) {
4594 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4595 			    "%s: ddi_copyout failed for mbox extension data.",
4596 			    emlxs_dfc_xlate(dfc->cmd));
4597 
4598 			rval = DFC_COPYIN_ERROR;
4599 			goto done;
4600 		}
4601 	}
4602 #endif /* MBOX_EXT_SUPPORT */
4603 
4604 	rval = 0;
4605 
4606 done:
4607 
4608 	/* Free allocated mbox memory */
4609 	if (extbuf) {
4610 		kmem_free(extbuf, extsize);
4611 	}
4612 
4613 	/* Free allocated mbox memory */
4614 	if (mbq) {
4615 		kmem_free(mbq, sizeof (MAILBOXQ));
4616 	}
4617 
4618 	/* Free allocated mbuf memory */
4619 	if (rx_mp) {
4620 		(void) emlxs_mem_buf_free(hba, (uint8_t *)rx_mp);
4621 	}
4622 
4623 	if (tx_mp) {
4624 		(void) emlxs_mem_buf_free(hba, (uint8_t *)tx_mp);
4625 	}
4626 
4627 	return (rval);
4628 
4629 } /* emlxs_dfc_send_mbox() */
4630 
4631 
4632 static int32_t
4633 emlxs_dfc_read_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4634 {
4635 	emlxs_port_t	*port = &PPORT;
4636 	uint32_t	offset;
4637 	uint32_t	cnt;
4638 	uint32_t	outsz;
4639 	uint32_t	i;
4640 	uint32_t	*buffer;
4641 	uint32_t	*bptr;
4642 	uint32_t	value;
4643 	uint32_t	size;
4644 	uint32_t	max = 4096;
4645 
4646 	offset = dfc->data1;
4647 	cnt = dfc->data2;
4648 	outsz = dfc->buf1_size;
4649 
4650 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4651 	    "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt);
4652 
4653 	if (!dfc->buf1_size || !dfc->buf1) {
4654 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4655 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4656 
4657 		return (DFC_ARG_NULL);
4658 	}
4659 
4660 	if (offset & 0x3) {
4661 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4662 		    "%s: Offset misaligned. (offset=%d)",
4663 		    emlxs_dfc_xlate(dfc->cmd), offset);
4664 
4665 		return (DFC_ARG_MISALIGNED);
4666 	}
4667 
4668 	if (cnt & 0x3) {
4669 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4670 		    "%s: Count misaligned. (count=%d)",
4671 		    emlxs_dfc_xlate(dfc->cmd), cnt);
4672 
4673 		return (DFC_ARG_MISALIGNED);
4674 	}
4675 
4676 	if (outsz & 0x3) {
4677 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4678 		    "%s: Output size misaligned. (size=%d)",
4679 		    emlxs_dfc_xlate(dfc->cmd), outsz);
4680 
4681 		return (DFC_ARG_MISALIGNED);
4682 	}
4683 
4684 	/* Get max PCI config range */
4685 	if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) {
4686 		max = 256;
4687 	} else {
4688 		max = 4096;
4689 	}
4690 
4691 	if ((cnt + offset) > max) {
4692 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4693 		    "%s: Offset+Count too large. (offset=%d count=%d max=%d)",
4694 		    emlxs_dfc_xlate(dfc->cmd), offset, cnt, max);
4695 
4696 		return (DFC_ARG_TOOBIG);
4697 	}
4698 
4699 	if (outsz > max) {
4700 		outsz = max;
4701 	}
4702 
4703 	if (cnt > outsz) {
4704 		cnt = outsz;
4705 	}
4706 
4707 	size = cnt;
4708 
4709 	if (!(buffer = (uint32_t *)kmem_zalloc(size, KM_NOSLEEP))) {
4710 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4711 		    "%s: Unable to allocate buffer.",
4712 		    emlxs_dfc_xlate(dfc->cmd));
4713 
4714 		return (DFC_SYSRES_ERROR);
4715 	}
4716 
4717 	bptr = buffer;
4718 	for (i = offset; i < (offset + cnt); i += 4) {
4719 		value =
4720 		    ddi_get32(hba->pci_acc_handle,
4721 		    (uint32_t *)(hba->pci_addr + i));
4722 		*bptr++ = PCIMEM_LONG(value);
4723 	}
4724 
4725 	if (ddi_copyout((void *)buffer, (void *)dfc->buf1, outsz, mode) != 0) {
4726 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4727 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
4728 
4729 		kmem_free(buffer, size);
4730 		return (DFC_COPYOUT_ERROR);
4731 	}
4732 
4733 	kmem_free(buffer, size);
4734 	return (0);
4735 
4736 } /* emlxs_dfc_read_pci() */
4737 
4738 
4739 static int32_t
4740 emlxs_dfc_write_pci(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4741 {
4742 	emlxs_port_t	*port = &PPORT;
4743 	uint32_t	offset;
4744 	uint32_t	cnt;
4745 	uint32_t	value;
4746 	uint32_t	i;
4747 	uint32_t	max;
4748 	uint8_t		buffer[256];
4749 	uint32_t	*bptr;
4750 	uint16_t	word0;
4751 	uint16_t	word1;
4752 
4753 	offset = dfc->data1;
4754 	cnt = dfc->data2;
4755 
4756 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4757 	    "%s: offset=%x count=%d", emlxs_dfc_xlate(dfc->cmd), offset, cnt);
4758 
4759 	if (!dfc->buf1 || !dfc->buf1_size) {
4760 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4761 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4762 
4763 		return (DFC_ARG_NULL);
4764 	}
4765 
4766 	if (offset & 0x3) {
4767 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4768 		    "%s: Offset misaligned. (offset=%d)",
4769 		    emlxs_dfc_xlate(dfc->cmd), offset);
4770 
4771 		return (DFC_ARG_MISALIGNED);
4772 	}
4773 
4774 	if (cnt > dfc->buf1_size) {
4775 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4776 		    "%s: Count too large. (count=%d)",
4777 		    emlxs_dfc_xlate(dfc->cmd), cnt);
4778 
4779 		return (DFC_ARG_TOOBIG);
4780 	}
4781 
4782 	if (cnt & 0x3) {
4783 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4784 		    "%s: Count misaligned. (count=%d)",
4785 		    emlxs_dfc_xlate(dfc->cmd), cnt);
4786 
4787 		return (DFC_ARG_MISALIGNED);
4788 	}
4789 
4790 	/* Get max PCI config range */
4791 	if (hba->model_info.chip <= EMLXS_HELIOS_CHIP) {
4792 		max = 256;
4793 	} else {
4794 		max = 4096;
4795 	}
4796 
4797 	if ((cnt + offset) > max) {
4798 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4799 		    "%s: Count+Offset too large. (offset=%d count=%d max=%d)",
4800 		    emlxs_dfc_xlate(dfc->cmd), offset, cnt, max);
4801 
4802 		return (DFC_ARG_TOOBIG);
4803 	}
4804 
4805 	bzero(buffer, sizeof (buffer));
4806 
4807 	if (ddi_copyin((void *)dfc->buf1, (void *)buffer, cnt, mode) != 0) {
4808 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4809 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
4810 
4811 		return (DFC_COPYIN_ERROR);
4812 	}
4813 
4814 	bptr = (uint32_t *)buffer;
4815 	for (i = offset; i < (offset + cnt); i += 4) {
4816 		value = *bptr++;
4817 		value = PCIMEM_LONG(value);
4818 
4819 		word0 = value & 0xFFFF;
4820 		word1 = value >> 16;
4821 
4822 		/*
4823 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
4824 		 * "%s: Writing. offset=%x cnt=%d value=%08x %04x %04x",
4825 		 * emlxs_dfc_xlate(dfc->cmd), i, value, word0, word1);
4826 		 */
4827 
4828 		/* word0 = PCIMEM_SHORT(word0); */
4829 		ddi_put16(hba->pci_acc_handle,
4830 		    (uint16_t *)(hba->pci_addr + i), (uint16_t)word0);
4831 
4832 		/* word1 = PCIMEM_SHORT(word1); */
4833 		ddi_put16(hba->pci_acc_handle,
4834 		    (uint16_t *)(hba->pci_addr + i + 2), (uint16_t)word1);
4835 	}
4836 
4837 	return (0);
4838 
4839 } /* emlxs_dfc_write_pci() */
4840 
4841 
4842 static int32_t
4843 emlxs_dfc_get_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4844 {
4845 	emlxs_port_t	*port = &PPORT;
4846 	dfc_cfgparam_t	*cfgparam;
4847 	uint32_t	size;
4848 	uint32_t	count;
4849 	uint32_t	i;
4850 	int32_t		rval = 0;
4851 	emlxs_config_t	*cfg;
4852 
4853 	if (!dfc->buf1 || !dfc->buf1_size) {
4854 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4855 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4856 
4857 		return (DFC_ARG_NULL);
4858 	}
4859 
4860 	count = dfc->buf1_size / sizeof (dfc_cfgparam_t);
4861 
4862 	if (count > MAX_CFG_PARAM) {
4863 		count = MAX_CFG_PARAM;
4864 	}
4865 
4866 	if (count > NUM_CFG_PARAM) {
4867 		count = NUM_CFG_PARAM;
4868 	}
4869 
4870 	size = count * sizeof (dfc_cfgparam_t);
4871 
4872 	if (!(cfgparam = (dfc_cfgparam_t *)kmem_zalloc(size, KM_NOSLEEP))) {
4873 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4874 		    "%s: Unable to allocate cfgparm buffer.",
4875 		    emlxs_dfc_xlate(dfc->cmd));
4876 
4877 		return (DFC_SYSRES_ERROR);
4878 	}
4879 
4880 	cfg = &CFG;
4881 	for (i = 0; i < count; i++) {
4882 		(void) strncpy(cfgparam[i].a_string, cfg[i].string,
4883 		    sizeof (cfgparam[i].a_string));
4884 		cfgparam[i].a_low = cfg[i].low;
4885 		cfgparam[i].a_hi = cfg[i].hi;
4886 		cfgparam[i].a_default = cfg[i].def;
4887 		cfgparam[i].a_current = cfg[i].current;
4888 
4889 		if (!(cfg[i].flags & PARM_HIDDEN)) {
4890 			cfgparam[i].a_flag |= CFG_EXPORT;
4891 		}
4892 
4893 		if ((cfg[i].flags & PARM_DYNAMIC)) {
4894 			if ((cfg[i].flags & PARM_DYNAMIC_RESET) ==
4895 			    PARM_DYNAMIC_RESET) {
4896 				cfgparam[i].a_changestate = CFG_RESTART;
4897 			} else if ((cfg[i].flags & PARM_DYNAMIC_LINK) ==
4898 			    PARM_DYNAMIC_LINK) {
4899 				cfgparam[i].a_changestate = CFG_LINKRESET;
4900 			} else {
4901 				cfgparam[i].a_changestate = CFG_DYMANIC;
4902 			}
4903 		} else {
4904 			cfgparam[i].a_changestate = CFG_REBOOT;
4905 		}
4906 
4907 		(void) strncpy(cfgparam[i].a_help, cfg[i].help,
4908 		    sizeof (cfgparam[i].a_help));
4909 	}
4910 
4911 	if (ddi_copyout((void *)cfgparam, (void *)dfc->buf1, size, mode) != 0) {
4912 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4913 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
4914 
4915 		rval = DFC_COPYOUT_ERROR;
4916 	}
4917 
4918 	rval = 0;
4919 
4920 	kmem_free(cfgparam, size);
4921 
4922 	return (rval);
4923 
4924 } /* emlxs_dfc_get_cfg() */
4925 
4926 
4927 /* ARGSUSED */
4928 static int32_t
4929 emlxs_dfc_set_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4930 {
4931 	emlxs_port_t	*port = &PPORT;
4932 	uint32_t	index;
4933 	uint32_t	new_value;
4934 	uint32_t	rc;
4935 
4936 	index = dfc->data1;
4937 	new_value = dfc->data2;
4938 
4939 	rc = emlxs_set_parm(hba, index, new_value);
4940 
4941 	if (rc) {
4942 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4943 		    "%s: Unable to set parameter. code=%d",
4944 		    emlxs_dfc_xlate(dfc->cmd), rc);
4945 
4946 		switch (rc) {
4947 		case 2:
4948 			return (DFC_NPIV_ACTIVE);
4949 
4950 		default:
4951 			return (DFC_ARG_INVALID);
4952 		}
4953 	}
4954 
4955 	return (0);
4956 
4957 } /* emlxs_dfc_set_cfg() */
4958 
4959 
4960 static int32_t
4961 emlxs_dfc_send_ct(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
4962 {
4963 	emlxs_port_t	*port = &PPORT;
4964 	uint8_t		*rsp_buf;
4965 	uint8_t		*cmd_buf;
4966 	uint32_t	did;
4967 	uint32_t	rsp_size;
4968 	uint32_t	cmd_size;
4969 	uint32_t	timeout;
4970 	fc_packet_t	*pkt = NULL;
4971 	uint32_t	rval = 0;
4972 	dfc_destid_t	destid;
4973 	NODELIST	*nlp;
4974 	char		buffer[128];
4975 
4976 	cmd_buf = dfc->buf1;
4977 	cmd_size = dfc->buf1_size;
4978 	rsp_buf = dfc->buf2;
4979 	rsp_size = dfc->buf2_size;
4980 	timeout = dfc->data1;
4981 
4982 	if (timeout < (2 * hba->fc_ratov)) {
4983 		timeout = 2 * hba->fc_ratov;
4984 	}
4985 
4986 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
4987 	    "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), cmd_size,
4988 	    rsp_size);
4989 
4990 
4991 	if (!cmd_size || !cmd_buf) {
4992 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
4993 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
4994 
4995 		rval = DFC_ARG_NULL;
4996 		goto done;
4997 	}
4998 
4999 	if (!rsp_size || !rsp_buf) {
5000 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5001 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
5002 
5003 		rval = DFC_ARG_NULL;
5004 		goto done;
5005 	}
5006 
5007 	if (!dfc->buf3 || !dfc->buf3_size) {
5008 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5009 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
5010 
5011 		rval = DFC_ARG_NULL;
5012 		goto done;
5013 	}
5014 
5015 	if (!dfc->buf4 || !dfc->buf4_size) {
5016 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5017 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
5018 
5019 		rval = DFC_ARG_NULL;
5020 		goto done;
5021 	}
5022 
5023 	if (rsp_size > MAX_CT_PAYLOAD) {
5024 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5025 		    "%s: Buffer2 too large. size=%d",
5026 		    emlxs_dfc_xlate(dfc->cmd), rsp_size);
5027 
5028 		rval = DFC_ARG_TOOBIG;
5029 		goto done;
5030 	}
5031 
5032 	if (cmd_size > MAX_CT_PAYLOAD) {
5033 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5034 		    "%s: Buffer1 too large. size=%d",
5035 		    emlxs_dfc_xlate(dfc->cmd), cmd_size);
5036 
5037 		rval = DFC_ARG_TOOBIG;
5038 		goto done;
5039 	}
5040 
5041 	if (dfc->buf3_size < sizeof (dfc_destid_t)) {
5042 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5043 		    "%s: Buffer3 too small. (size=%d)",
5044 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
5045 
5046 		rval = DFC_ARG_TOOSMALL;
5047 		goto done;
5048 	}
5049 
5050 	if (dfc->buf4_size < sizeof (uint32_t)) {
5051 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5052 		    "%s: Buffer4 too small. (size=%d)",
5053 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size);
5054 
5055 		rval = DFC_ARG_TOOSMALL;
5056 		goto done;
5057 	}
5058 
5059 	if (ddi_copyin((void *)dfc->buf3, (void *)&destid,
5060 	    sizeof (dfc_destid_t), mode) != 0) {
5061 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5062 		    "%s: Unable to read destination id.",
5063 		    emlxs_dfc_xlate(dfc->cmd));
5064 
5065 		rval = DFC_COPYIN_ERROR;
5066 		goto done;
5067 	}
5068 
5069 	if (destid.idType == 0) {
5070 		if ((nlp = emlxs_node_find_wwpn(port, destid.wwpn)) == NULL) {
5071 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5072 			    "%s: WWPN does not exists. %s",
5073 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
5074 			    destid.wwpn));
5075 
5076 			rval = DFC_ARG_INVALID;
5077 			goto done;
5078 		}
5079 		did = nlp->nlp_DID;
5080 	} else {
5081 		if (emlxs_node_find_did(port, destid.d_id) == NULL) {
5082 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5083 			    "%s: DID does not exist. did=%x",
5084 			    emlxs_dfc_xlate(dfc->cmd), destid.d_id);
5085 
5086 			rval = DFC_ARG_INVALID;
5087 			goto done;
5088 		}
5089 		did = destid.d_id;
5090 	}
5091 
5092 	if (did == 0) {
5093 		did = port->did;
5094 	}
5095 
5096 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) {
5097 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5098 		    "%s: Unable to allocate packet.",
5099 		    emlxs_dfc_xlate(dfc->cmd));
5100 
5101 		rval = DFC_SYSRES_ERROR;
5102 		goto done;
5103 	}
5104 
5105 	/* Make this a polled IO */
5106 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5107 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5108 	pkt->pkt_comp = NULL;
5109 
5110 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5111 	pkt->pkt_timeout = (timeout) ? timeout : 30;
5112 
5113 	/* Build the fc header */
5114 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(did);
5115 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
5116 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
5117 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
5118 	pkt->pkt_cmd_fhdr.f_ctl =
5119 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5120 	pkt->pkt_cmd_fhdr.seq_id = 0;
5121 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5122 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5123 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5124 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5125 	pkt->pkt_cmd_fhdr.ro = 0;
5126 
5127 	/* Copy in the command buffer */
5128 	if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size,
5129 	    mode) != 0) {
5130 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5131 		    "%s: Unable to read command buffer.",
5132 		    emlxs_dfc_xlate(dfc->cmd));
5133 
5134 		rval = DFC_COPYIN_ERROR;
5135 		goto done;
5136 	}
5137 
5138 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5139 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5140 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
5141 
5142 		rval = DFC_IO_ERROR;
5143 		goto done;
5144 	}
5145 
5146 	if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
5147 	    (pkt->pkt_state != FC_PKT_FS_RJT)) {
5148 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5149 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5150 			    "Pkt Transport error. Pkt Timeout.");
5151 			rval = DFC_TIMEOUT;
5152 		} else {
5153 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5154 			    "Pkt Transport error. state=%x", pkt->pkt_state);
5155 			rval = DFC_IO_ERROR;
5156 		}
5157 		goto done;
5158 	}
5159 
5160 	if (ddi_copyout((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size,
5161 	    mode) != 0) {
5162 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5163 		    "%s: Unable to read response.",
5164 		    emlxs_dfc_xlate(dfc->cmd));
5165 
5166 		rval = DFC_COPYOUT_ERROR;
5167 		goto done;
5168 	}
5169 
5170 	rsp_size -= pkt->pkt_resp_resid;
5171 	if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf4, dfc->buf4_size,
5172 	    mode) != 0) {
5173 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5174 		    "%s: Unable to write response.",
5175 		    emlxs_dfc_xlate(dfc->cmd));
5176 
5177 		rval = DFC_COPYOUT_ERROR;
5178 		goto done;
5179 	}
5180 
5181 	rval = 0;
5182 
5183 done:
5184 
5185 	if (pkt) {
5186 		emlxs_pkt_free(pkt);
5187 	}
5188 
5189 	return (rval);
5190 
5191 } /* emlxs_dfc_send_ct() */
5192 
5193 
5194 static int32_t
5195 emlxs_dfc_send_ct_rsp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5196 {
5197 	emlxs_port_t	*port = &PPORT;
5198 	uint8_t		*cmd_buf;
5199 	uint32_t	rx_id;
5200 	uint32_t	cmd_size;
5201 	uint32_t	timeout;
5202 	fc_packet_t	*pkt = NULL;
5203 	uint32_t	rval = 0;
5204 
5205 	cmd_buf = dfc->buf1;
5206 	cmd_size = dfc->buf1_size;
5207 	rx_id = dfc->flag;
5208 	timeout = 2 * hba->fc_ratov;
5209 
5210 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s: csize=%d",
5211 	    emlxs_dfc_xlate(dfc->cmd), cmd_size);
5212 
5213 	if (!cmd_size || !cmd_buf) {
5214 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5215 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5216 
5217 		rval = DFC_ARG_NULL;
5218 		goto done;
5219 	}
5220 
5221 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, 0, 0, KM_NOSLEEP))) {
5222 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5223 		    "%s: Unable to allocate packet.",
5224 		    emlxs_dfc_xlate(dfc->cmd));
5225 
5226 		rval = DFC_SYSRES_ERROR;
5227 		goto done;
5228 	}
5229 
5230 	/* Make this a polled IO */
5231 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5232 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5233 	pkt->pkt_comp = NULL;
5234 
5235 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
5236 	pkt->pkt_timeout = (timeout) ? timeout : 30;
5237 
5238 	/* Build the fc header */
5239 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(0);
5240 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_SOLICITED_CONTROL;
5241 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
5242 	pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
5243 	pkt->pkt_cmd_fhdr.f_ctl =
5244 	    F_CTL_LAST_SEQ | F_CTL_END_SEQ | F_CTL_XCHG_CONTEXT;
5245 	pkt->pkt_cmd_fhdr.seq_id = 0;
5246 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5247 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5248 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
5249 	pkt->pkt_cmd_fhdr.rx_id = rx_id;
5250 	pkt->pkt_cmd_fhdr.ro = 0;
5251 
5252 	/* Copy in the command buffer */
5253 	if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size,
5254 	    mode) != 0) {
5255 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5256 		    "%s: Unable to read command buffer.",
5257 		    emlxs_dfc_xlate(dfc->cmd));
5258 
5259 		rval = DFC_COPYIN_ERROR;
5260 		goto done;
5261 	}
5262 
5263 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5264 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5265 		    "%s: Unable to send packet.", emlxs_dfc_xlate(dfc->cmd));
5266 
5267 		rval = DFC_IO_ERROR;
5268 		goto done;
5269 	}
5270 
5271 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
5272 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5273 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5274 			    "Pkt Transport error. Pkt Timeout.");
5275 			rval = DFC_TIMEOUT;
5276 		} else {
5277 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5278 			    "Pkt Transport error. state=%x", pkt->pkt_state);
5279 			rval = DFC_IO_ERROR;
5280 		}
5281 		goto done;
5282 	}
5283 
5284 	rval = 0;
5285 
5286 done:
5287 
5288 	if (pkt) {
5289 		emlxs_pkt_free(pkt);
5290 	}
5291 
5292 	return (rval);
5293 
5294 } /* emlxs_dfc_send_ct_rsp() */
5295 
5296 
5297 #ifdef MENLO_SUPPORT
5298 
5299 static int32_t
5300 emlxs_dfc_send_menlo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5301 {
5302 	emlxs_port_t	*port = &PPORT;
5303 	uint8_t		*rsp_buf = NULL;
5304 	uint8_t		*cmd_buf = NULL;
5305 	uint32_t	rsp_size = 0;
5306 	uint32_t	cmd_size = 0;
5307 	uint32_t	rval = 0;
5308 
5309 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5310 	    "%s: csize=%d rsize=%d", emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size,
5311 	    dfc->buf2_size);
5312 
5313 	if (hba->model_info.device_id != PCI_DEVICE_ID_LP21000_M) {
5314 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5315 		    "%s: Menlo device not present. device=%x,%x",
5316 		    emlxs_dfc_xlate(dfc->cmd), hba->model_info.device_id,
5317 		    hba->model_info.ssdid);
5318 
5319 		rval = DFC_INVALID_ADAPTER;
5320 		goto done;
5321 	}
5322 
5323 	if (!dfc->buf1_size || !dfc->buf1) {
5324 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5325 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
5326 
5327 		rval = DFC_ARG_NULL;
5328 		goto done;
5329 	}
5330 
5331 	if (!dfc->buf2_size || !dfc->buf2) {
5332 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5333 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
5334 
5335 		rval = DFC_ARG_NULL;
5336 		goto done;
5337 	}
5338 
5339 	if (!dfc->buf3 || !dfc->buf3_size) {
5340 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5341 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
5342 
5343 		rval = DFC_ARG_NULL;
5344 		goto done;
5345 	}
5346 
5347 	if (dfc->buf3_size < sizeof (uint32_t)) {
5348 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5349 		    "%s: Buffer3 too small. %d < %d",
5350 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size,
5351 		    sizeof (uint32_t));
5352 
5353 		rval = DFC_ARG_TOOSMALL;
5354 		goto done;
5355 	}
5356 
5357 	cmd_size  = dfc->buf1_size;
5358 	if ((cmd_buf = (uint8_t *)kmem_zalloc(cmd_size,
5359 	    KM_SLEEP)) == 0) {
5360 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5361 		    "%s: Unable to allocate command buffer.",
5362 		    emlxs_dfc_xlate(dfc->cmd));
5363 
5364 		rval = DFC_SYSRES_ERROR;
5365 		goto done;
5366 	}
5367 
5368 	rsp_size  = dfc->buf2_size;
5369 	if ((rsp_buf = (uint8_t *)kmem_zalloc(rsp_size,
5370 	    KM_SLEEP)) == 0) {
5371 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5372 		    "%s: Unable to allocate response buffer.",
5373 		    emlxs_dfc_xlate(dfc->cmd));
5374 
5375 		rval = DFC_SYSRES_ERROR;
5376 		goto done;
5377 	}
5378 
5379 	/* Read the command buffer */
5380 	if (ddi_copyin((void *)dfc->buf1, (void *)cmd_buf,
5381 	    cmd_size, mode) != 0) {
5382 		EMLXS_MSGF(EMLXS_CONTEXT,
5383 		    &emlxs_dfc_error_msg,
5384 		    "%s: Unable to read command buffer.",
5385 		    emlxs_dfc_xlate(dfc->cmd));
5386 
5387 		rval = DFC_COPYIN_ERROR;
5388 		goto done;
5389 	}
5390 
5391 	/* Send the command */
5392 	rval = emlxs_send_menlo_cmd(hba, cmd_buf, cmd_size,
5393 	    rsp_buf, &rsp_size);
5394 
5395 	if (rval == 0) {
5396 		/* Return the response */
5397 		if (ddi_copyout((void *)rsp_buf, (void *)dfc->buf2,
5398 		    rsp_size, mode) != 0) {
5399 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5400 			    "%s: Unable to write response.",
5401 			    emlxs_dfc_xlate(dfc->cmd));
5402 
5403 			rval = DFC_COPYOUT_ERROR;
5404 			goto done;
5405 		}
5406 
5407 		/* Return the response size */
5408 		if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf3,
5409 		    dfc->buf3_size, mode) != 0) {
5410 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5411 			    "%s: Unable to write response size.",
5412 			    emlxs_dfc_xlate(dfc->cmd));
5413 
5414 			rval = DFC_COPYOUT_ERROR;
5415 			goto done;
5416 		}
5417 	}
5418 
5419 done:
5420 
5421 	if (cmd_buf) {
5422 		kmem_free(cmd_buf, dfc->buf1_size);
5423 	}
5424 
5425 	if (rsp_buf) {
5426 		kmem_free(rsp_buf, dfc->buf2_size);
5427 	}
5428 
5429 	return (rval);
5430 
5431 } /* emlxs_dfc_send_menlo() */
5432 
5433 
5434 extern int32_t
5435 emlxs_send_menlo_cmd(emlxs_hba_t *hba, uint8_t *cmd_buf, uint32_t cmd_size,
5436     uint8_t *rsp_buf, uint32_t *rsp_size)
5437 {
5438 	emlxs_port_t		*port = &PPORT;
5439 	uint8_t			*data_buf = NULL;
5440 	uint32_t		data_size = 0;
5441 	fc_packet_t		*pkt = NULL;
5442 	uint32_t		rval = 0;
5443 	menlo_set_cmd_t		set_cmd;
5444 	menlo_reset_cmd_t	reset_cmd;
5445 	uint32_t		rsp_code;
5446 	uint32_t		mm_mode = 0;
5447 	uint32_t		cmd_code;
5448 	clock_t			timeout;
5449 	MAILBOXQ		*mbq = NULL;
5450 	MAILBOX			*mb;
5451 	uint32_t		addr;
5452 	uint32_t		value;
5453 	uint32_t		mbxstatus;
5454 
5455 	cmd_code = *(uint32_t *)cmd_buf;
5456 	cmd_code = SWAP_LONG(cmd_code);
5457 
5458 	/* Look for Zephyr specific commands */
5459 	if (cmd_code & 0x80000000) {
5460 		bzero((uint8_t *)&reset_cmd, sizeof (menlo_reset_cmd_t));
5461 		bzero((uint8_t *)&set_cmd, sizeof (menlo_set_cmd_t));
5462 		bzero((uint8_t *)&rsp_code, sizeof (uint32_t));
5463 
5464 		/* Validate response buffer */
5465 		if (*rsp_size < sizeof (uint32_t)) {
5466 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5467 			    "emlxs_send_menlo_cmd: Response overrun.");
5468 			rval = DFC_RSP_BUF_OVERRUN;
5469 			goto done;
5470 		}
5471 
5472 		/* All of these responses will be 4 bytes only */
5473 		*rsp_size = sizeof (uint32_t);
5474 		rsp_code = 0;
5475 
5476 		/* Validate command buffer */
5477 		switch (cmd_code) {
5478 		case MENLO_CMD_RESET:
5479 			if (cmd_size < sizeof (menlo_reset_cmd_t)) {
5480 				EMLXS_MSGF(EMLXS_CONTEXT,
5481 				    &emlxs_dfc_error_msg,
5482 				    "emlxs_send_menlo_cmd: "
5483 				    "Invalid command size. %d < %d",
5484 				    cmd_size,
5485 				    sizeof (menlo_reset_cmd_t));
5486 				rval = DFC_ARG_INVALID;
5487 				goto done;
5488 			}
5489 			cmd_size = sizeof (menlo_reset_cmd_t);
5490 
5491 			/* Read the command buffer */
5492 			bcopy((void *)cmd_buf, (void *)&reset_cmd, cmd_size);
5493 
5494 			if (reset_cmd.firmware) {
5495 				/* MENLO_FW_GOLDEN */
5496 				value = 1;
5497 
5498 				EMLXS_MSGF(EMLXS_CONTEXT,
5499 				    &emlxs_dfc_detail_msg,
5500 				    "emlxs_send_menlo_cmd: Reset with Golden "
5501 				    "firmware requested.");
5502 
5503 			} else {
5504 				/* MENLO_FW_OPERATIONAL */
5505 				value = 0;
5506 
5507 				EMLXS_MSGF(EMLXS_CONTEXT,
5508 				    &emlxs_dfc_detail_msg,
5509 				    "emlxs_send_menlo_cmd: Reset with "
5510 				    "Operational firmware requested.");
5511 			}
5512 
5513 			addr  = 0x103007;
5514 
5515 			break;
5516 
5517 		case MENLO_CMD_SET_MODE:
5518 			if (cmd_size < sizeof (menlo_set_cmd_t)) {
5519 				EMLXS_MSGF(EMLXS_CONTEXT,
5520 				    &emlxs_dfc_error_msg,
5521 				    "emlxs_send_menlo_cmd: "
5522 				    "Invalid command size. %d < %d",
5523 				    cmd_size,
5524 				    sizeof (menlo_set_cmd_t));
5525 				rval = DFC_ARG_INVALID;
5526 				goto done;
5527 			}
5528 			cmd_size = sizeof (menlo_set_cmd_t);
5529 
5530 			/* Read the command buffer */
5531 			bcopy((void *)cmd_buf, (void *)&set_cmd, cmd_size);
5532 
5533 			if (set_cmd.value1) {
5534 				EMLXS_MSGF(EMLXS_CONTEXT,
5535 				    &emlxs_dfc_detail_msg,
5536 				    "emlxs_send_menlo_cmd: "
5537 				    "Maintenance mode enable requested.");
5538 
5539 				/* Make sure the mode flag is cleared */
5540 				if (hba->flag & FC_MENLO_MODE) {
5541 					mutex_enter(&EMLXS_PORT_LOCK);
5542 					hba->flag &= ~FC_MENLO_MODE;
5543 					mutex_exit(&EMLXS_PORT_LOCK);
5544 				}
5545 
5546 				mm_mode = 1;
5547 			} else {
5548 				EMLXS_MSGF(EMLXS_CONTEXT,
5549 				    &emlxs_dfc_detail_msg,
5550 				    "emlxs_send_menlo_cmd: "
5551 				    "Maintenance mode disable requested.");
5552 			}
5553 
5554 			addr  = 0x103107;
5555 			value = mm_mode;
5556 
5557 			break;
5558 
5559 		default:
5560 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5561 			    "emlxs_send_menlo_cmd: "
5562 			    "Invalid command. cmd=%x", cmd_code);
5563 			rval = DFC_ARG_INVALID;
5564 			goto done;
5565 		}
5566 
5567 		if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
5568 		    KM_SLEEP)) == 0) {
5569 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5570 			    "emlxs_send_menlo_cmd: "
5571 			    "Unable to allocate mailbox buffer.");
5572 
5573 			rval = DFC_SYSRES_ERROR;
5574 			goto done;
5575 		}
5576 
5577 		mb = (MAILBOX *) mbq;
5578 
5579 		/* Create the set_variable mailbox request */
5580 		emlxs_mb_set_var(hba, mb, addr, value);
5581 
5582 		mbq->flag |= MBQ_PASSTHRU;
5583 
5584 		/* issue the mbox cmd to the sli */
5585 		mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
5586 
5587 		if (mbxstatus) {
5588 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5589 			    "emlxs_send_menlo_cmd: %s failed. mbxstatus=0x%x",
5590 			    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
5591 
5592 			if (mbxstatus == MBX_TIMEOUT) {
5593 				rval = DFC_TIMEOUT;
5594 			} else {
5595 				rval = DFC_IO_ERROR;
5596 			}
5597 			goto done;
5598 		}
5599 
5600 		bcopy((void *)&rsp_code, (void *)rsp_buf, *rsp_size);
5601 
5602 		/* Check if we need to wait for maintenance mode */
5603 		if (mm_mode && !(hba->flag & FC_MENLO_MODE)) {
5604 			/* Wait for link to come up in maintenance mode */
5605 			mutex_enter(&EMLXS_LINKUP_LOCK);
5606 
5607 			timeout = emlxs_timeout(hba, 30);
5608 
5609 			rval = 0;
5610 			while ((rval != -1) && !(hba->flag & FC_MENLO_MODE)) {
5611 				rval =
5612 				    cv_timedwait(&EMLXS_LINKUP_CV,
5613 				    &EMLXS_LINKUP_LOCK, timeout);
5614 			}
5615 
5616 			mutex_exit(&EMLXS_LINKUP_LOCK);
5617 
5618 			if (rval == -1) {
5619 				EMLXS_MSGF(EMLXS_CONTEXT,
5620 				    &emlxs_dfc_error_msg,
5621 				    "emlxs_send_menlo_cmd: "
5622 				    "Menlo maintenance mode error. Timeout.");
5623 
5624 				rval = DFC_TIMEOUT;
5625 				goto done;
5626 			}
5627 		}
5628 	} else {	/* Standard commands */
5629 
5630 		if (hba->state <= FC_LINK_DOWN) {
5631 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5632 			    "emlxs_send_menlo_cmd: Adapter link down.");
5633 
5634 			rval = DFC_LINKDOWN_ERROR;
5635 			goto done;
5636 		}
5637 
5638 		if (cmd_code == MENLO_CMD_FW_DOWNLOAD) {
5639 			/* Check cmd size */
5640 			/* Must be at least 12 bytes of command */
5641 			/* plus 4 bytes of data */
5642 			if (cmd_size < (12 + 4)) {
5643 				EMLXS_MSGF(EMLXS_CONTEXT,
5644 				    &emlxs_dfc_error_msg,
5645 				    "emlxs_send_menlo_cmd: "
5646 				    "Invalid command size. %d < %d",
5647 				    cmd_size,
5648 				    (12 + 4));
5649 
5650 				rval = DFC_ARG_INVALID;
5651 				goto done;
5652 			}
5653 
5654 			/* Extract data buffer from command buffer */
5655 			data_buf    = cmd_buf  + 12;
5656 			data_size   = cmd_size - 12;
5657 			cmd_size    = 12;
5658 		}
5659 
5660 		if (!(pkt = emlxs_pkt_alloc(port, cmd_size, *rsp_size, 0,
5661 		    KM_NOSLEEP))) {
5662 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5663 			    "emlxs_send_menlo_cmd: Unable to allocate packet.");
5664 
5665 			rval = DFC_SYSRES_ERROR;
5666 			goto done;
5667 		}
5668 
5669 		/* Make this a polled IO */
5670 		pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5671 		pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5672 		pkt->pkt_comp = NULL;
5673 		pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5674 		pkt->pkt_timeout = 30;
5675 
5676 		/* Build the fc header */
5677 		pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(EMLXS_MENLO_DID);
5678 		pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
5679 		pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
5680 		pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
5681 		pkt->pkt_cmd_fhdr.f_ctl =
5682 		    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5683 		pkt->pkt_cmd_fhdr.seq_id = 0;
5684 		pkt->pkt_cmd_fhdr.df_ctl = 0;
5685 		pkt->pkt_cmd_fhdr.seq_cnt = 0;
5686 		pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5687 		pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5688 		pkt->pkt_cmd_fhdr.ro = 0;
5689 
5690 		/* Copy in the command buffer */
5691 		bcopy((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size);
5692 
5693 		if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5694 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5695 			    "emlxs_send_menlo_cmd: Unable to send packet.");
5696 
5697 			rval = DFC_IO_ERROR;
5698 			goto done;
5699 		}
5700 
5701 		if (pkt->pkt_state != FC_PKT_SUCCESS) {
5702 			if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5703 				EMLXS_MSGF(EMLXS_CONTEXT,
5704 				    &emlxs_dfc_error_msg,
5705 				    "emlxs_send_menlo_cmd: "
5706 				    "Pkt Transport error. Pkt Timeout.");
5707 				rval = DFC_TIMEOUT;
5708 			} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
5709 			    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
5710 				EMLXS_MSGF(EMLXS_CONTEXT,
5711 				    &emlxs_dfc_error_msg,
5712 				    "emlxs_send_menlo_cmd: "
5713 				    "Pkt Transport error. Response overrun.");
5714 				rval = DFC_RSP_BUF_OVERRUN;
5715 			} else {
5716 				EMLXS_MSGF(EMLXS_CONTEXT,
5717 				    &emlxs_dfc_error_msg,
5718 				    "emlxs_send_menlo_cmd: "
5719 				    "Pkt Transport error. state=%x",
5720 				    pkt->pkt_state);
5721 				rval = DFC_IO_ERROR;
5722 			}
5723 			goto done;
5724 		}
5725 
5726 		if (cmd_code == MENLO_CMD_FW_DOWNLOAD) {
5727 			uint32_t *rsp;
5728 
5729 			/* Check response code */
5730 			rsp = (uint32_t *)pkt->pkt_resp;
5731 			rsp_code = *rsp;
5732 			rsp_code = SWAP_LONG(rsp_code);
5733 
5734 			if (rsp_code == MENLO_RSP_SUCCESS) {
5735 				/* Now transmit the data phase */
5736 
5737 				/* Save last rx_id */
5738 				uint32_t rx_id = pkt->pkt_cmd_fhdr.rx_id;
5739 
5740 				/* Free old pkt */
5741 				emlxs_pkt_free(pkt);
5742 
5743 				/* Allocate data pkt */
5744 				if (!(pkt = emlxs_pkt_alloc(port, data_size,
5745 				    *rsp_size, 0, KM_NOSLEEP))) {
5746 					EMLXS_MSGF(EMLXS_CONTEXT,
5747 					    &emlxs_dfc_error_msg,
5748 					    "emlxs_send_menlo_cmd: "
5749 					    "Unable to allocate data "
5750 					    "packet.");
5751 
5752 					rval = DFC_SYSRES_ERROR;
5753 					goto done;
5754 				}
5755 
5756 				/* Make this a polled IO */
5757 				pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5758 				pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5759 				pkt->pkt_comp = NULL;
5760 				pkt->pkt_tran_type = FC_PKT_OUTBOUND;
5761 				pkt->pkt_timeout = 30;
5762 
5763 				/* Build the fc header */
5764 				pkt->pkt_cmd_fhdr.d_id =
5765 				    SWAP_DATA24_LO(EMLXS_MENLO_DID);
5766 				pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
5767 				pkt->pkt_cmd_fhdr.s_id =
5768 				    SWAP_DATA24_LO(port->did);
5769 				pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
5770 				pkt->pkt_cmd_fhdr.f_ctl =
5771 				    F_CTL_FIRST_SEQ | F_CTL_END_SEQ |
5772 				    F_CTL_SEQ_INITIATIVE;
5773 				pkt->pkt_cmd_fhdr.seq_id = 0;
5774 				pkt->pkt_cmd_fhdr.df_ctl = 0;
5775 				pkt->pkt_cmd_fhdr.seq_cnt = 0;
5776 				pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5777 				pkt->pkt_cmd_fhdr.rx_id = rx_id;
5778 				pkt->pkt_cmd_fhdr.ro = 0;
5779 
5780 				/* Copy in the data buffer */
5781 				bcopy((void *)data_buf, (void *)pkt->pkt_cmd,
5782 				    data_size);
5783 
5784 				if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5785 					EMLXS_MSGF(EMLXS_CONTEXT,
5786 					    &emlxs_dfc_error_msg,
5787 					    "emlxs_send_menlo_cmd: "
5788 					    "Unable to send data packet.");
5789 
5790 					rval = DFC_IO_ERROR;
5791 					goto done;
5792 				}
5793 
5794 				if (pkt->pkt_state != FC_PKT_SUCCESS) {
5795 					if (pkt->pkt_state == FC_PKT_TIMEOUT) {
5796 						EMLXS_MSGF(EMLXS_CONTEXT,
5797 						    &emlxs_dfc_error_msg,
5798 						    "emlxs_send_menlo_cmd: "
5799 						    "Data Pkt Transport "
5800 						    "error. Pkt Timeout.");
5801 						rval = DFC_TIMEOUT;
5802 					} else if ((pkt->pkt_state ==
5803 					    FC_PKT_LOCAL_RJT) &&
5804 					    (pkt->pkt_reason ==
5805 					    FC_REASON_OVERRUN)) {
5806 						EMLXS_MSGF(EMLXS_CONTEXT,
5807 						    &emlxs_dfc_error_msg,
5808 						    "emlxs_send_menlo_cmd: "
5809 						    "Data Pkt Transport "
5810 						    "error. Response overrun.");
5811 						rval = DFC_RSP_BUF_OVERRUN;
5812 					} else {
5813 						EMLXS_MSGF(EMLXS_CONTEXT,
5814 						    &emlxs_dfc_error_msg,
5815 						    "emlxs_send_menlo_cmd: "
5816 						    "Data Pkt Transport "
5817 						    "error. state=%x",
5818 						    pkt->pkt_state);
5819 						rval = DFC_IO_ERROR;
5820 					}
5821 					goto done;
5822 				}
5823 			}
5824 		}
5825 
5826 		bcopy((void *)pkt->pkt_resp, (void *)rsp_buf, *rsp_size);
5827 		*rsp_size = *rsp_size - pkt->pkt_resp_resid;
5828 	}
5829 
5830 	rval = 0;
5831 
5832 done:
5833 
5834 	if (pkt) {
5835 		emlxs_pkt_free(pkt);
5836 	}
5837 
5838 	if (mbq) {
5839 		kmem_free(mbq, sizeof (MAILBOXQ));
5840 	}
5841 
5842 	return (rval);
5843 
5844 } /* emlxs_send_menlo_cmd() */
5845 
5846 
5847 /* ARGSUSED */
5848 extern void
5849 emlxs_fcoe_attention_thread(emlxs_hba_t *hba,
5850     void *arg1, void *arg2)
5851 {
5852 	emlxs_port_t		*port = &PPORT;
5853 	menlo_init_rsp_t	*rsp;
5854 	menlo_get_cmd_t		*cmd;
5855 	fc_packet_t		*pkt = NULL;
5856 
5857 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_get_cmd_t),
5858 	    sizeof (menlo_init_rsp_t), 0, KM_NOSLEEP))) {
5859 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5860 		    "FCoE attention: Unable to allocate packet.");
5861 
5862 		return;
5863 	}
5864 
5865 	/* Make this a polled IO */
5866 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
5867 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
5868 	pkt->pkt_comp = NULL;
5869 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
5870 	pkt->pkt_timeout = 30;
5871 
5872 	/* Build the fc header */
5873 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(EMLXS_MENLO_DID);
5874 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
5875 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
5876 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
5877 	pkt->pkt_cmd_fhdr.f_ctl =
5878 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
5879 	pkt->pkt_cmd_fhdr.seq_id = 0;
5880 	pkt->pkt_cmd_fhdr.df_ctl = 0;
5881 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
5882 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
5883 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
5884 	pkt->pkt_cmd_fhdr.ro = 0;
5885 
5886 	cmd = (menlo_get_cmd_t *)pkt->pkt_cmd;
5887 	cmd->code = MENLO_CMD_GET_INIT;
5888 	cmd->context = 0;
5889 	cmd->length = sizeof (menlo_init_rsp_t);
5890 
5891 	/* Little Endian Swap */
5892 	cmd->code = SWAP_LONG(cmd->code);
5893 	cmd->length = SWAP_LONG(cmd->length);
5894 
5895 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
5896 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5897 		    "FCoE attention: Unable to send packet.");
5898 
5899 		goto done;
5900 	}
5901 
5902 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
5903 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5904 		    "FCoE attention: Pkt Transport error. state=%x",
5905 		    pkt->pkt_state);
5906 
5907 		goto done;
5908 	}
5909 
5910 	/* Check response code */
5911 	rsp = (menlo_init_rsp_t *)pkt->pkt_resp;
5912 	rsp->code = SWAP_LONG(rsp->code);
5913 
5914 	if (rsp->code != MENLO_RSP_SUCCESS) {
5915 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5916 		    "FCoE attention: FCOE Response error =%x", rsp->code);
5917 
5918 		goto done;
5919 	}
5920 
5921 	/* Little Endian Swap */
5922 	rsp->bb_credit = SWAP_LONG(rsp->bb_credit);
5923 	rsp->frame_size = SWAP_LONG(rsp->frame_size);
5924 	rsp->fw_version = SWAP_LONG(rsp->fw_version);
5925 	rsp->reset_status = SWAP_LONG(rsp->reset_status);
5926 	rsp->maint_status = SWAP_LONG(rsp->maint_status);
5927 	rsp->fw_type = SWAP_LONG(rsp->fw_type);
5928 	rsp->fru_data_valid = SWAP_LONG(rsp->fru_data_valid);
5929 
5930 	/* Log the event */
5931 	emlxs_log_fcoe_event(port, rsp);
5932 
5933 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5934 	    "MENLO_INIT: bb_credit      = 0x%x", rsp->bb_credit);
5935 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5936 	    "MENLO_INIT: frame_size     = 0x%x", rsp->frame_size);
5937 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5938 	    "MENLO_INIT: fw_version     = 0x%x", rsp->fw_version);
5939 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5940 	    "MENLO_INIT: reset_status   = 0x%x", rsp->reset_status);
5941 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5942 	    "MENLO_INIT: maint_status   = 0x%x", rsp->maint_status);
5943 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5944 	    "MENLO_INIT: fw_type        = 0x%x", rsp->fw_type);
5945 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
5946 	    "MENLO_INIT: fru_data_valid = 0x%x", rsp->fru_data_valid);
5947 
5948 	/* Perform attention checks */
5949 	if (rsp->fru_data_valid == 0) {
5950 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_error_msg,
5951 		    "Invalid FRU data found on adapter. "
5952 		    "Return adapter to Emulex for repair.");
5953 	}
5954 
5955 	switch (rsp->fw_type) {
5956 	case MENLO_FW_TYPE_GOLDEN:
5957 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_warning_msg,
5958 		    "FCoE chip is running Golden firmware. "
5959 		    "Update FCoE firmware immediately.");
5960 		break;
5961 
5962 	case MENLO_FW_TYPE_DIAG:
5963 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_adapter_notice_msg,
5964 		    "FCoE chip is running Diagnostic firmware. "
5965 		    "Operational use of the adapter is suspended.");
5966 		break;
5967 	}
5968 
5969 done:
5970 
5971 	if (pkt) {
5972 		emlxs_pkt_free(pkt);
5973 	}
5974 
5975 	return;
5976 
5977 } /* emlxs_fcoe_attention_thread() */
5978 
5979 #endif /* MENLO_SUPPORT */
5980 
5981 
5982 static int32_t
5983 emlxs_dfc_write_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
5984 {
5985 	emlxs_port_t	*port = &PPORT;
5986 	uint32_t	offset;
5987 	uint32_t	cnt;
5988 	uint8_t		*buffer;
5989 	uint8_t		*bptr;
5990 	uint32_t	i;
5991 
5992 	if (hba->bus_type != SBUS_FC) {
5993 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
5994 		    "%s: Invalid bus_type. (bus_type=%x)",
5995 		    emlxs_dfc_xlate(dfc->cmd), hba->bus_type);
5996 
5997 		return (DFC_ARG_INVALID);
5998 	}
5999 
6000 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6001 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6002 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6003 
6004 		return (DFC_ONLINE_ERROR);
6005 	}
6006 
6007 	if (!dfc->buf1 || !dfc->buf1_size) {
6008 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6009 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6010 
6011 		return (DFC_ARG_NULL);
6012 	}
6013 
6014 	offset = dfc->data1;
6015 	cnt = dfc->data2;
6016 
6017 	if (offset > (64 * 1024)) {
6018 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6019 		    "%s: Offset too large. (offset=%d)",
6020 		    emlxs_dfc_xlate(dfc->cmd), offset);
6021 
6022 		return (DFC_ARG_TOOBIG);
6023 	}
6024 
6025 	if (cnt > dfc->buf1_size) {
6026 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6027 		    "%s: Count too large. (count=%d)",
6028 		    emlxs_dfc_xlate(dfc->cmd), cnt);
6029 
6030 		return (DFC_ARG_TOOBIG);
6031 	}
6032 
6033 	if ((cnt + offset) > (64 * 1024)) {
6034 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6035 		    "%s: Count+Offset too large. (count=%d offset=%d)",
6036 		    emlxs_dfc_xlate(dfc->cmd), cnt, offset);
6037 
6038 		return (DFC_ARG_TOOBIG);
6039 	}
6040 
6041 	if (cnt == 0) {
6042 		return (0);
6043 	}
6044 
6045 	if ((buffer = (uint8_t *)kmem_zalloc(cnt, KM_NOSLEEP)) == NULL) {
6046 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6047 		    "%s: Unable to allocate buffer.",
6048 		    emlxs_dfc_xlate(dfc->cmd));
6049 
6050 		return (DFC_SYSRES_ERROR);
6051 	}
6052 
6053 	if (ddi_copyin((void *)dfc->buf1, (void *)buffer, cnt, mode) != 0) {
6054 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6055 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6056 
6057 		kmem_free(buffer, cnt);
6058 		return (DFC_COPYIN_ERROR);
6059 	}
6060 
6061 	bptr = buffer;
6062 	for (i = 0; i < cnt; i++) {
6063 		SBUS_WRITE_FLASH_COPY(hba, offset, *bptr);
6064 		offset++;
6065 		bptr++;
6066 	}
6067 
6068 	kmem_free(buffer, cnt);
6069 
6070 	return (0);
6071 
6072 } /* emlxs_dfc_write_flash() */
6073 
6074 
6075 static int32_t
6076 emlxs_dfc_read_flash(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6077 {
6078 	emlxs_port_t	*port = &PPORT;
6079 	uint32_t	offset;
6080 	uint32_t	count;
6081 	uint32_t	outsz;
6082 	uint8_t		*buffer;
6083 	uint8_t		*bptr;
6084 	uint32_t	i;
6085 
6086 	if (hba->bus_type != SBUS_FC) {
6087 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6088 		    "%s: Invalid bus_type. (bus_type=%x)",
6089 		    emlxs_dfc_xlate(dfc->cmd), hba->bus_type);
6090 
6091 		return (DFC_ARG_INVALID);
6092 	}
6093 
6094 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6095 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6096 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6097 
6098 		return (DFC_ONLINE_ERROR);
6099 	}
6100 
6101 	if (!dfc->buf1 || !dfc->buf1_size) {
6102 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6103 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6104 
6105 		return (DFC_ARG_NULL);
6106 	}
6107 
6108 	offset = dfc->data1;
6109 	count = dfc->data2;
6110 	outsz = dfc->buf1_size;
6111 
6112 	if (offset > (64 * 1024)) {
6113 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6114 		    "%s: Offset too large. (offset=%d)",
6115 		    emlxs_dfc_xlate(dfc->cmd), offset);
6116 
6117 		return (DFC_ARG_TOOBIG);
6118 	}
6119 
6120 	if ((count + offset) > (64 * 1024)) {
6121 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6122 		    "%s: Count+Offset too large. (count=%d offset=%d)",
6123 		    emlxs_dfc_xlate(dfc->cmd), count, offset);
6124 
6125 		return (DFC_ARG_TOOBIG);
6126 	}
6127 
6128 	if (count < outsz) {
6129 		outsz = count;
6130 	}
6131 
6132 	if ((buffer = (uint8_t *)kmem_zalloc(outsz, KM_NOSLEEP)) == NULL) {
6133 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6134 		    "%s: Unable to allocate buffer.",
6135 		    emlxs_dfc_xlate(dfc->cmd));
6136 
6137 		return (DFC_SYSRES_ERROR);
6138 	}
6139 
6140 	bptr = buffer;
6141 	for (i = 0; i < outsz; i++) {
6142 		*bptr++ = SBUS_READ_FLASH_COPY(hba, offset++);
6143 	}
6144 
6145 	if (ddi_copyout((void *)buffer, (void *)dfc->buf1, outsz, mode) != 0) {
6146 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6147 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6148 
6149 		kmem_free(buffer, outsz);
6150 		return (DFC_COPYOUT_ERROR);
6151 	}
6152 
6153 	kmem_free(buffer, outsz);
6154 
6155 	return (0);
6156 
6157 } /* emlxs_dfc_read_flash() */
6158 
6159 
6160 static int32_t
6161 emlxs_dfc_send_els(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6162 {
6163 	emlxs_port_t	*port = &PPORT;
6164 	uint8_t		*rsp_buf;
6165 	uint8_t		*cmd_buf;
6166 	dfc_destid_t	destid;
6167 	uint32_t	rsp_size;
6168 	uint32_t	cmd_size;
6169 	uint32_t	timeout;
6170 	fc_packet_t	*pkt = NULL;
6171 	NODELIST	*ndlp;
6172 	uint32_t	did;
6173 	uint32_t	rval = 0;
6174 	char		buffer[128];
6175 
6176 	cmd_buf = dfc->buf1;
6177 	cmd_size = dfc->buf1_size;
6178 	rsp_buf = dfc->buf2;
6179 	rsp_size = dfc->buf2_size;
6180 
6181 	timeout = 2 * hba->fc_ratov;
6182 
6183 	if (!cmd_size || !cmd_buf) {
6184 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6185 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6186 
6187 		rval = DFC_ARG_NULL;
6188 		goto done;
6189 	}
6190 
6191 	if (!rsp_buf || !rsp_size) {
6192 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6193 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
6194 
6195 		rval = DFC_ARG_NULL;
6196 		goto done;
6197 	}
6198 
6199 	if (!dfc->buf3 || !dfc->buf3_size) {
6200 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6201 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
6202 
6203 		rval = DFC_ARG_NULL;
6204 		goto done;
6205 	}
6206 
6207 	if (dfc->buf3_size < sizeof (dfc_destid_t)) {
6208 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6209 		    "%s: Buffer3 too small. (size=%d)",
6210 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
6211 
6212 		rval = DFC_ARG_TOOSMALL;
6213 		goto done;
6214 	}
6215 
6216 	if (!dfc->buf4 || !dfc->buf4_size) {
6217 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6218 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
6219 
6220 		rval = DFC_ARG_NULL;
6221 		goto done;
6222 	}
6223 
6224 	if (dfc->buf4_size < sizeof (uint32_t)) {
6225 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6226 		    "%s: Buffer4 too small. (size=%d)",
6227 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf4_size);
6228 
6229 		rval = DFC_ARG_TOOSMALL;
6230 		goto done;
6231 	}
6232 
6233 	if (ddi_copyin((void *)dfc->buf3, (void *)&destid,
6234 	    sizeof (dfc_destid_t), mode) != 0) {
6235 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6236 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6237 
6238 		rval = DFC_COPYIN_ERROR;
6239 		goto done;
6240 	}
6241 
6242 	if (destid.idType == 0) {
6243 		if ((ndlp = emlxs_node_find_wwpn(port, destid.wwpn)) == NULL) {
6244 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6245 			    "%s: WWPN does not exists. %s",
6246 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
6247 			    destid.wwpn));
6248 
6249 			rval = DFC_ARG_INVALID;
6250 			goto done;
6251 		}
6252 		did = ndlp->nlp_DID;
6253 	} else {
6254 		if (emlxs_node_find_did(port, destid.d_id) == NULL) {
6255 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6256 			    "%s: DID does not exist. did=%x",
6257 			    emlxs_dfc_xlate(dfc->cmd), destid.d_id);
6258 
6259 			rval = DFC_ARG_INVALID;
6260 			goto done;
6261 		}
6262 		did = destid.d_id;
6263 	}
6264 
6265 	if (did == 0) {
6266 		did = port->did;
6267 	}
6268 
6269 	if (!(pkt = emlxs_pkt_alloc(port, cmd_size, rsp_size, 0, KM_NOSLEEP))) {
6270 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6271 		    "%s: Unable to allocate packet.",
6272 		    emlxs_dfc_xlate(dfc->cmd));
6273 
6274 		rval = DFC_SYSRES_ERROR;
6275 		goto done;
6276 	}
6277 
6278 	/* Make this a polled IO */
6279 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
6280 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
6281 	pkt->pkt_comp = NULL;
6282 
6283 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
6284 	pkt->pkt_timeout = (timeout) ? timeout : 30;
6285 
6286 	/* Build the fc header */
6287 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(did);
6288 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
6289 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
6290 	pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
6291 	pkt->pkt_cmd_fhdr.f_ctl =
6292 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
6293 	pkt->pkt_cmd_fhdr.seq_id = 0;
6294 	pkt->pkt_cmd_fhdr.df_ctl = 0;
6295 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
6296 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
6297 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
6298 	pkt->pkt_cmd_fhdr.ro = 0;
6299 
6300 	/* Copy in the command buffer */
6301 	if (ddi_copyin((void *)cmd_buf, (void *)pkt->pkt_cmd, cmd_size,
6302 	    mode) != 0) {
6303 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6304 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6305 
6306 		rval = DFC_COPYIN_ERROR;
6307 		goto done;
6308 	}
6309 
6310 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
6311 		rval = DFC_IO_ERROR;
6312 		goto done;
6313 	}
6314 
6315 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
6316 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
6317 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6318 			    "Pkt Transport error. Pkt Timeout.");
6319 			rval = DFC_TIMEOUT;
6320 		} else {
6321 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6322 			    "Pkt Transport error. state=%x", pkt->pkt_state);
6323 			rval = DFC_IO_ERROR;
6324 		}
6325 		goto done;
6326 	}
6327 
6328 	rsp_size -= pkt->pkt_resp_resid;
6329 	if (ddi_copyout((void *)pkt->pkt_resp, (void *)rsp_buf, rsp_size,
6330 	    mode) != 0) {
6331 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6332 		    "%s: rsp_buf ddi_copyout failed.",
6333 		    emlxs_dfc_xlate(dfc->cmd));
6334 
6335 		rval = DFC_COPYOUT_ERROR;
6336 		goto done;
6337 	}
6338 
6339 	if (ddi_copyout((void *)&rsp_size, (void *)dfc->buf4,
6340 	    sizeof (uint32_t), mode) != 0) {
6341 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6342 		    "%s: rsp_size ddi_copyout failed.",
6343 		    emlxs_dfc_xlate(dfc->cmd));
6344 
6345 		rval = DFC_COPYOUT_ERROR;
6346 		goto done;
6347 	}
6348 
6349 	rval = 0;
6350 
6351 done:
6352 	if (pkt) {
6353 		emlxs_pkt_free(pkt);
6354 	}
6355 
6356 	return (rval);
6357 
6358 } /* emlxs_dfc_send_els() */
6359 
6360 
6361 static int32_t
6362 emlxs_dfc_get_ioinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6363 {
6364 	emlxs_port_t	*port = &PPORT;
6365 	dfc_ioinfo_t	ioinfo;
6366 	uint32_t	i;
6367 
6368 	if (!dfc->buf1 || !dfc->buf1_size) {
6369 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6370 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6371 
6372 		return (DFC_ARG_NULL);
6373 	}
6374 
6375 	if (dfc->buf1_size < sizeof (dfc_ioinfo_t)) {
6376 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6377 		    "%s: Buffer1 too small. (size=%d)",
6378 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6379 
6380 		return (DFC_ARG_TOOSMALL);
6381 	}
6382 
6383 	bzero(&ioinfo, sizeof (dfc_ioinfo_t));
6384 
6385 	ioinfo.a_mboxCmd = HBASTATS.MboxIssued;
6386 	ioinfo.a_mboxCmpl = HBASTATS.MboxCompleted;
6387 	ioinfo.a_mboxErr = HBASTATS.MboxError;
6388 
6389 	for (i = 0; i < MAX_RINGS; i++) {
6390 		ioinfo.a_iocbCmd += HBASTATS.IocbIssued[i];
6391 		ioinfo.a_iocbRsp += HBASTATS.IocbReceived[i];
6392 	}
6393 
6394 	ioinfo.a_adapterIntr = HBASTATS.IntrEvent[0] + HBASTATS.IntrEvent[1] +
6395 	    HBASTATS.IntrEvent[2] + HBASTATS.IntrEvent[3] +
6396 	    HBASTATS.IntrEvent[4] + HBASTATS.IntrEvent[5] +
6397 	    HBASTATS.IntrEvent[6] + HBASTATS.IntrEvent[7];
6398 
6399 	ioinfo.a_fcpCmd = HBASTATS.FcpIssued;
6400 	ioinfo.a_fcpCmpl = HBASTATS.FcpCompleted;
6401 	ioinfo.a_fcpErr = HBASTATS.FcpCompleted - HBASTATS.FcpGood;
6402 
6403 	ioinfo.a_seqXmit = HBASTATS.IpSeqIssued;
6404 	ioinfo.a_seqRcv = HBASTATS.IpSeqReceived;
6405 	ioinfo.a_seqXmitErr = HBASTATS.IpSeqCompleted - HBASTATS.IpSeqGood;
6406 
6407 	ioinfo.a_bcastXmit = HBASTATS.IpBcastIssued;
6408 	ioinfo.a_bcastRcv = HBASTATS.IpBcastReceived;
6409 
6410 	ioinfo.a_elsXmit = HBASTATS.ElsCmdIssued;
6411 	ioinfo.a_elsRcv = HBASTATS.ElsCmdReceived;
6412 	ioinfo.a_elsXmitErr = HBASTATS.ElsCmdCompleted - HBASTATS.ElsCmdGood;
6413 
6414 	ioinfo.a_RSCNRcv = HBASTATS.ElsRscnReceived;
6415 
6416 	ioinfo.a_elsBufPost = HBASTATS.ElsUbPosted;
6417 	ioinfo.a_ipBufPost = HBASTATS.IpUbPosted;
6418 
6419 	ioinfo.a_cnt1 = 0;
6420 	ioinfo.a_cnt2 = 0;
6421 	ioinfo.a_cnt3 = 0;
6422 	ioinfo.a_cnt4 = 0;
6423 
6424 	if (ddi_copyout((void *)&ioinfo, (void *)dfc->buf1,
6425 	    sizeof (dfc_ioinfo_t), mode) != 0) {
6426 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6427 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6428 
6429 		return (DFC_COPYOUT_ERROR);
6430 	}
6431 
6432 	return (0);
6433 
6434 } /* emlxs_dfc_get_ioinfo() */
6435 
6436 
6437 static int32_t
6438 emlxs_dfc_get_linkinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6439 {
6440 	emlxs_port_t	*port = &PPORT;
6441 	dfc_linkinfo_t	linkinfo;
6442 
6443 	if (!dfc->buf1 || !dfc->buf1_size) {
6444 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6445 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6446 
6447 		return (DFC_ARG_NULL);
6448 	}
6449 
6450 	if (dfc->buf1_size < sizeof (dfc_linkinfo_t)) {
6451 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6452 		    "%s: Buffer1 too small. (size=%d)",
6453 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6454 
6455 		return (DFC_ARG_TOOSMALL);
6456 	}
6457 
6458 	bzero(&linkinfo, sizeof (dfc_linkinfo_t));
6459 
6460 	linkinfo.a_linkEventTag = hba->link_event_tag;
6461 	linkinfo.a_linkUp = HBASTATS.LinkUp;
6462 	linkinfo.a_linkDown = HBASTATS.LinkDown;
6463 	linkinfo.a_linkMulti = HBASTATS.LinkMultiEvent;
6464 	linkinfo.a_DID = port->did;
6465 	linkinfo.a_topology = 0;
6466 
6467 	if (hba->state <= FC_LINK_DOWN) {
6468 		linkinfo.a_linkState = LNK_DOWN;
6469 	}
6470 #ifdef MENLO_SUPPORT
6471 	else if (hba->flag & FC_MENLO_MODE) {
6472 		linkinfo.a_linkState = LNK_DOWN;
6473 		linkinfo.a_topology  = LNK_MENLO_MAINTENANCE;
6474 
6475 	}
6476 #endif /* MENLO_SUPPORT */
6477 	else if (hba->state < FC_READY) {
6478 		linkinfo.a_linkState = LNK_DISCOVERY;
6479 	} else {
6480 		linkinfo.a_linkState = LNK_READY;
6481 	}
6482 
6483 	if (linkinfo.a_linkState != LNK_DOWN) {
6484 		if (hba->topology == TOPOLOGY_LOOP) {
6485 			if (hba->flag & FC_FABRIC_ATTACHED) {
6486 				linkinfo.a_topology = LNK_PUBLIC_LOOP;
6487 			} else {
6488 				linkinfo.a_topology = LNK_LOOP;
6489 			}
6490 
6491 			linkinfo.a_alpa = port->did & 0xff;
6492 			linkinfo.a_alpaCnt = port->alpa_map[0];
6493 
6494 			if (linkinfo.a_alpaCnt > 127) {
6495 				linkinfo.a_alpaCnt = 127;
6496 			}
6497 
6498 			bcopy((void *)&port->alpa_map[0], linkinfo.a_alpaMap,
6499 			    linkinfo.a_alpaCnt + 1);
6500 		} else {
6501 			if (hba->flag & FC_FABRIC_ATTACHED) {
6502 				linkinfo.a_topology = LNK_FABRIC;
6503 			} else {
6504 				linkinfo.a_topology = LNK_PT2PT;
6505 			}
6506 		}
6507 	}
6508 
6509 	bcopy(&hba->wwpn, linkinfo.a_wwpName, 8);
6510 	bcopy(&hba->wwnn, linkinfo.a_wwnName, 8);
6511 
6512 	if (ddi_copyout((void *)&linkinfo, (void *)dfc->buf1,
6513 	    sizeof (dfc_linkinfo_t), mode) != 0) {
6514 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6515 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6516 
6517 		return (DFC_COPYOUT_ERROR);
6518 	}
6519 
6520 	return (0);
6521 
6522 } /* emlxs_dfc_get_linkinfo() */
6523 
6524 #ifdef SFCT_SUPPORT
6525 static int32_t
6526 emlxs_dfc_get_fctstat(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6527 {
6528 	emlxs_port_t		*port = &PPORT;
6529 	emlxs_tgtport_stat_t	*statp = &TGTPORTSTAT;
6530 	dfc_tgtport_stat_t	dfcstat;
6531 
6532 	if (!dfc->buf1 || !dfc->buf1_size) {
6533 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6534 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6535 
6536 		return (DFC_ARG_NULL);
6537 	}
6538 
6539 	if (dfc->buf1_size < sizeof (emlxs_tgtport_stat_t)) {
6540 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6541 		    "%s: Buffer1 too small. (size=%d)",
6542 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6543 
6544 		return (DFC_ARG_TOOSMALL);
6545 	}
6546 
6547 	bzero(&dfcstat, sizeof (dfcstat));
6548 
6549 	dfcstat.Version = DFC_TGTPORT_STAT_VERSION;
6550 
6551 	dfcstat.FctRcvDropped = statp->FctRcvDropped;
6552 	dfcstat.FctOverQDepth = statp->FctOverQDepth;
6553 	dfcstat.FctOutstandingIO = statp->FctOutstandingIO;
6554 	dfcstat.FctFailedPortRegister = statp->FctFailedPortRegister;
6555 	dfcstat.FctPortRegister = statp->FctPortRegister;
6556 	dfcstat.FctPortDeregister = statp->FctPortDeregister;
6557 
6558 	dfcstat.FctAbortSent = statp->FctAbortSent;
6559 	dfcstat.FctNoBuffer = statp->FctNoBuffer;
6560 	dfcstat.FctScsiStatusErr = statp->FctScsiStatusErr;
6561 	dfcstat.FctScsiQfullErr = statp->FctScsiQfullErr;
6562 	dfcstat.FctScsiResidOver = statp->FctScsiResidOver;
6563 	dfcstat.FctScsiResidUnder = statp->FctScsiResidUnder;
6564 	dfcstat.FctScsiSenseErr = statp->FctScsiSenseErr;
6565 
6566 	dfcstat.FctEvent = statp->FctEvent;
6567 	dfcstat.FctCompleted = statp->FctCompleted;
6568 	dfcstat.FctCmplGood = statp->FctCmplGood;
6569 	dfcstat.FctCmplError = statp->FctCmplError;
6570 	dfcstat.FctStray = statp->FctStray;
6571 
6572 	bcopy(&statp->FctP2IOWcnt[0], &dfcstat.FctP2IOWcnt[0],
6573 	    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6574 	bcopy(&statp->FctP2IORcnt[0], &dfcstat.FctP2IORcnt[0],
6575 	    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6576 	dfcstat.FctIOCmdCnt = statp->FctIOCmdCnt;
6577 	dfcstat.FctReadBytes = statp->FctReadBytes;
6578 	dfcstat.FctWriteBytes = statp->FctWriteBytes;
6579 	dfcstat.FctCmdReceived = statp->FctCmdReceived;
6580 
6581 	if (dfc->flag) {	/* Clear counters after read */
6582 		bzero(&statp->FctP2IOWcnt[0],
6583 		    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6584 		bzero(&statp->FctP2IORcnt[0],
6585 		    (sizeof (uint64_t) * MAX_TGTPORT_IOCNT));
6586 		statp->FctIOCmdCnt = 0;
6587 		statp->FctReadBytes = 0;
6588 		statp->FctWriteBytes = 0;
6589 		statp->FctCmdReceived = 0;
6590 	}
6591 	if (hba->state <= FC_LINK_DOWN) {
6592 		dfcstat.FctLinkState = LNK_DOWN;
6593 	}
6594 #ifdef MENLO_SUPPORT
6595 	else if (hba->flag & FC_MENLO_MODE) {
6596 		dfcstat.FctLinkState = LNK_DOWN;
6597 	}
6598 #endif /* MENLO_SUPPORT */
6599 	else if (hba->state < FC_READY) {
6600 		dfcstat.FctLinkState = LNK_DISCOVERY;
6601 	} else {
6602 		dfcstat.FctLinkState = LNK_READY;
6603 	}
6604 
6605 	if (ddi_copyout((void *)&dfcstat, (void *)dfc->buf1,
6606 	    sizeof (dfc_tgtport_stat_t), mode) != 0) {
6607 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6608 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6609 
6610 		return (DFC_COPYOUT_ERROR);
6611 	}
6612 
6613 	return (0);
6614 
6615 } /* emlxs_dfc_get_fctstat() */
6616 #endif /* SFCT_SUPPORT */
6617 
6618 static int32_t
6619 emlxs_dfc_get_nodeinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6620 {
6621 	emlxs_port_t	*port;
6622 	emlxs_config_t	*cfg = &CFG;
6623 	dfc_node_t	*dfc_node;
6624 	dfc_node_t	*dnp;
6625 	uint32_t	node_count;
6626 	NODELIST	*nlp;
6627 	uint32_t	size;
6628 	uint32_t	i;
6629 
6630 	port = &VPORT(dfc->data1);
6631 
6632 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
6633 	    emlxs_dfc_xlate(dfc->cmd));
6634 
6635 	if (!dfc->buf1 || !dfc->buf1_size) {
6636 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6637 		    "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6638 
6639 		return (DFC_ARG_NULL);
6640 	}
6641 
6642 	if (dfc->buf1_size < (sizeof (dfc_node_t) * MAX_NODES)) {
6643 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6644 		    "%s: Buffer1 too small. (size=%d)",
6645 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
6646 
6647 		return (DFC_ARG_TOOSMALL);
6648 	}
6649 
6650 	if (!dfc->buf2 || !dfc->buf2_size) {
6651 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6652 		    "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
6653 
6654 		return (DFC_ARG_NULL);
6655 	}
6656 
6657 	if (dfc->buf2_size < sizeof (uint32_t)) {
6658 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6659 		    "%s: Buffer2 too small. (size=%d)",
6660 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
6661 
6662 		return (DFC_ARG_TOOSMALL);
6663 	}
6664 
6665 	node_count = port->node_count;
6666 
6667 	if (node_count == 0) {
6668 		return (0);
6669 	}
6670 
6671 	if (node_count > MAX_NODES) {
6672 		node_count = MAX_NODES;
6673 	}
6674 
6675 	size = node_count * sizeof (dfc_node_t);
6676 
6677 	if (!(dfc_node = (dfc_node_t *)kmem_zalloc(size, KM_NOSLEEP))) {
6678 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6679 		    "%s: Unable to allocate dfc_node.",
6680 		    emlxs_dfc_xlate(dfc->cmd));
6681 
6682 		return (DFC_SYSRES_ERROR);
6683 	}
6684 
6685 	dnp = dfc_node;
6686 
6687 	rw_enter(&port->node_rwlock, RW_READER);
6688 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
6689 		nlp = port->node_table[i];
6690 		while (nlp != NULL) {
6691 			dnp->port_id = nlp->nlp_DID;
6692 			dnp->rpi = nlp->nlp_Rpi;
6693 			dnp->xri = nlp->nlp_Xri;
6694 
6695 			bcopy((char *)&nlp->sparm, (char *)&dnp->sparm,
6696 			    sizeof (dnp->sparm));
6697 
6698 			if (nlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE) {
6699 				dnp->flags |= PORT_FLAG_FCP_TARGET;
6700 			}
6701 			if (nlp->nlp_fcp_info & NLP_FCP_INI_DEVICE) {
6702 				dnp->flags |= PORT_FLAG_FCP_INI;
6703 
6704 			}
6705 			if (nlp->nlp_fcp_info & NLP_FCP_2_DEVICE) {
6706 				dnp->flags |= PORT_FLAG_FCP2;
6707 			}
6708 			if (cfg[CFG_NETWORK_ON].current && nlp->nlp_Xri) {
6709 				dnp->flags |= PORT_FLAG_IP;
6710 			}
6711 			if (nlp->nlp_fcp_info & NLP_EMLX_VPORT) {
6712 				dnp->flags |= PORT_FLAG_VPORT;
6713 			}
6714 
6715 			dnp++;
6716 			nlp = (NODELIST *) nlp->nlp_list_next;
6717 		}
6718 	}
6719 	rw_exit(&port->node_rwlock);
6720 
6721 	if (ddi_copyout((void *)dfc_node, (void *)dfc->buf1, size, mode) != 0) {
6722 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6723 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6724 
6725 		kmem_free(dfc_node, size);
6726 		return (DFC_COPYOUT_ERROR);
6727 	}
6728 
6729 	if (ddi_copyout((void *)&node_count, (void *)dfc->buf2,
6730 	    sizeof (uint32_t), mode) != 0) {
6731 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6732 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6733 
6734 		kmem_free(dfc_node, size);
6735 		return (DFC_COPYOUT_ERROR);
6736 	}
6737 
6738 	kmem_free(dfc_node, size);
6739 
6740 	return (0);
6741 
6742 } /* emlxs_dfc_get_nodeinfo() */
6743 
6744 
6745 static int32_t
6746 emlxs_dfc_read_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6747 {
6748 	emlxs_port_t	*port = &PPORT;
6749 	uint32_t	offset;
6750 	uint32_t	size;
6751 	uint32_t	max_size;
6752 	uint8_t		*buffer;
6753 	uint8_t		*slim;
6754 
6755 	offset = dfc->data1;
6756 	size = dfc->data2;
6757 
6758 	if (!dfc->buf1 || !dfc->buf1_size) {
6759 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6760 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6761 
6762 		return (DFC_ARG_NULL);
6763 	}
6764 
6765 	if (size > dfc->buf1_size) {
6766 		size = dfc->buf1_size;
6767 	}
6768 
6769 	if (offset % 4) {
6770 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6771 		    "%s: Offset misaligned. (offset=%d)",
6772 		    emlxs_dfc_xlate(dfc->cmd), offset);
6773 
6774 		return (DFC_ARG_MISALIGNED);
6775 	}
6776 
6777 	if (size % 4) {
6778 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6779 		    "%s: Size misaligned. (size=%d)",
6780 		    emlxs_dfc_xlate(dfc->cmd), size);
6781 
6782 		return (DFC_ARG_MISALIGNED);
6783 	}
6784 
6785 	if (hba->flag & FC_SLIM2_MODE) {
6786 		max_size = SLI2_SLIM2_SIZE;
6787 	} else {
6788 		max_size = 4096;
6789 	}
6790 
6791 	if (offset >= max_size) {
6792 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6793 		    "%s: Offset too large. (offset=%d)",
6794 		    emlxs_dfc_xlate(dfc->cmd), offset);
6795 
6796 		return (DFC_ARG_TOOBIG);
6797 	}
6798 
6799 	if ((size + offset) > max_size) {
6800 		size = (max_size - offset);
6801 	}
6802 
6803 	if (!(buffer = (uint8_t *)kmem_zalloc(size, KM_NOSLEEP))) {
6804 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6805 		    "%s: Unable to allocate buffer.",
6806 		    emlxs_dfc_xlate(dfc->cmd));
6807 
6808 		return (DFC_SYSRES_ERROR);
6809 	}
6810 
6811 	if (hba->flag & FC_SLIM2_MODE) {
6812 		slim = (uint8_t *)hba->slim2.virt + offset;
6813 		emlxs_pcimem_bcopy((uint32_t *)slim, (uint32_t *)buffer,
6814 		    size);
6815 	} else {
6816 		slim = (uint8_t *)hba->slim_addr + offset;
6817 		READ_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)slim,
6818 		    (size / 4));
6819 	}
6820 
6821 	if (ddi_copyout((void *)buffer, (void *)dfc->buf1, size, mode) != 0) {
6822 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6823 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
6824 
6825 		kmem_free(buffer, size);
6826 		return (DFC_COPYOUT_ERROR);
6827 	}
6828 
6829 	kmem_free(buffer, size);
6830 
6831 	return (0);
6832 
6833 } /* emlxs_dfc_read_mem() */
6834 
6835 
6836 static int32_t
6837 emlxs_dfc_write_mem(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6838 {
6839 	emlxs_port_t	*port = &PPORT;
6840 	uint32_t	offset;
6841 	uint32_t	size;
6842 	uint32_t	max_size;
6843 	uint8_t		*buffer;
6844 	uint8_t		*slim;
6845 
6846 	offset = dfc->data1;
6847 	size = dfc->data2;
6848 
6849 	if (!dfc->buf1 || !dfc->buf1_size) {
6850 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6851 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6852 
6853 		return (DFC_ARG_NULL);
6854 	}
6855 
6856 	if (size > dfc->buf1_size) {
6857 		size = dfc->buf1_size;
6858 	}
6859 
6860 	if (offset % 4) {
6861 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6862 		    "%s: Offset misaligned. (offset=%d)",
6863 		    emlxs_dfc_xlate(dfc->cmd), offset);
6864 
6865 		return (DFC_ARG_MISALIGNED);
6866 	}
6867 
6868 	if (size % 4) {
6869 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6870 		    "%s: Size misaligned. (szie=%d)",
6871 		    emlxs_dfc_xlate(dfc->cmd), size);
6872 
6873 		return (DFC_ARG_MISALIGNED);
6874 	}
6875 
6876 	if (hba->flag & FC_SLIM2_MODE) {
6877 		max_size = SLI2_SLIM2_SIZE;
6878 	} else {
6879 		max_size = 4096;
6880 	}
6881 
6882 	if (offset >= max_size) {
6883 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6884 		    "%s: Offset too large. (offset=%d)",
6885 		    emlxs_dfc_xlate(dfc->cmd), offset);
6886 
6887 		return (DFC_ARG_TOOBIG);
6888 	}
6889 
6890 	if ((size + offset) > max_size) {
6891 		size = (max_size - offset);
6892 	}
6893 
6894 	if (!(buffer = (uint8_t *)kmem_zalloc(size, KM_NOSLEEP))) {
6895 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6896 		    "%s: Unable to allocate buffer.",
6897 		    emlxs_dfc_xlate(dfc->cmd));
6898 
6899 		return (DFC_SYSRES_ERROR);
6900 	}
6901 
6902 	if (ddi_copyin((void *)dfc->buf1, (void *)buffer, size, mode) != 0) {
6903 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6904 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
6905 
6906 		kmem_free(buffer, size);
6907 		return (DFC_COPYIN_ERROR);
6908 	}
6909 
6910 	if (hba->flag & FC_SLIM2_MODE) {
6911 		slim = (uint8_t *)hba->slim2.virt + offset;
6912 		emlxs_pcimem_bcopy((uint32_t *)buffer, (uint32_t *)slim,
6913 		    size);
6914 	} else {
6915 		slim = (uint8_t *)hba->slim_addr + offset;
6916 		WRITE_SLIM_COPY(hba, (uint32_t *)buffer, (uint32_t *)slim,
6917 		    (size / 4));
6918 	}
6919 
6920 	kmem_free(buffer, size);
6921 
6922 	return (0);
6923 
6924 } /* emlxs_dfc_write_mem() */
6925 
6926 
6927 /* ARGSUSED */
6928 static int32_t
6929 emlxs_dfc_write_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6930 {
6931 	emlxs_port_t	*port = &PPORT;
6932 	uint32_t	offset;
6933 	uint32_t	value;
6934 
6935 	offset = dfc->data1;
6936 	value = dfc->data2;
6937 
6938 	if (!(hba->flag & FC_OFFLINE_MODE)) {
6939 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6940 		    "%s: Adapter not offline.", emlxs_dfc_xlate(dfc->cmd));
6941 
6942 		return (DFC_ONLINE_ERROR);
6943 	}
6944 
6945 	if (offset % 4) {
6946 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6947 		    "%s: Offset misaligned. (offset=%d)",
6948 		    emlxs_dfc_xlate(dfc->cmd), offset);
6949 
6950 		return (DFC_ARG_MISALIGNED);
6951 	}
6952 
6953 	if (offset > 255) {
6954 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6955 		    "%s: Offset too large. (offset=%d)",
6956 		    emlxs_dfc_xlate(dfc->cmd), offset);
6957 
6958 		return (DFC_ARG_TOOBIG);
6959 	}
6960 
6961 	WRITE_CSR_REG(hba, (hba->csr_addr + offset), value);
6962 
6963 	return (0);
6964 
6965 } /* emlxs_dfc_write_ctlreg() */
6966 
6967 
6968 static int32_t
6969 emlxs_dfc_read_ctlreg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
6970 {
6971 	emlxs_port_t	*port = &PPORT;
6972 	uint32_t	offset;
6973 	uint32_t	value;
6974 
6975 	offset = dfc->data1;
6976 
6977 	if (offset % 4) {
6978 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6979 		    "%s: Offset misaligned. (offset=%d)",
6980 		    emlxs_dfc_xlate(dfc->cmd), offset);
6981 
6982 		return (DFC_ARG_MISALIGNED);
6983 	}
6984 
6985 	if (offset > 255) {
6986 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6987 		    "%s: Offset too large. (offset=%d)",
6988 		    emlxs_dfc_xlate(dfc->cmd), offset);
6989 
6990 		return (DFC_ARG_TOOBIG);
6991 	}
6992 
6993 	if (!dfc->buf1 || !dfc->buf1_size) {
6994 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
6995 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
6996 
6997 		return (DFC_ARG_NULL);
6998 	}
6999 
7000 	if (dfc->buf1_size < sizeof (uint32_t)) {
7001 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7002 		    "%s: Buffer1 too small. (size=%d)",
7003 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7004 
7005 		return (DFC_ARG_TOOSMALL);
7006 	}
7007 
7008 	value = READ_CSR_REG(hba, (hba->csr_addr + offset));
7009 
7010 	if (ddi_copyout((void *)&value, (void *)dfc->buf1, sizeof (uint32_t),
7011 	    mode) != 0) {
7012 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7013 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7014 
7015 		return (DFC_COPYOUT_ERROR);
7016 	}
7017 
7018 	return (0);
7019 
7020 } /* emlxs_dfc_read_ctlreg() */
7021 
7022 
7023 static int32_t
7024 emlxs_dfc_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7025 {
7026 	emlxs_port_t		*port = &PPORT;
7027 	uint32_t		event;
7028 	uint32_t		enable;
7029 	uint32_t		pid;
7030 	uint32_t		count;
7031 	uint32_t		i;
7032 	emlxs_dfc_event_t	*dfc_event;
7033 
7034 	event = dfc->data1;
7035 	pid = dfc->data2;
7036 	enable = dfc->flag;
7037 
7038 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7039 	    "%s: %s. pid=%d enable=%d", emlxs_dfc_xlate(dfc->cmd),
7040 	    emlxs_dfc_event_xlate(event), pid, enable);
7041 
7042 	switch (event) {
7043 	case FC_REG_LINK_EVENT:
7044 	case FC_REG_RSCN_EVENT:
7045 	case FC_REG_CT_EVENT:
7046 	case FC_REG_DUMP_EVENT:
7047 	case FC_REG_TEMP_EVENT:
7048 	case FC_REG_VPORTRSCN_EVENT:
7049 	case FC_REG_FCOE_EVENT:
7050 		break;
7051 
7052 	case FC_REG_MULTIPULSE_EVENT:
7053 	default:
7054 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7055 		    "%s: %s. Invalid event. pid=%d enable=%d",
7056 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7057 		    pid, enable);
7058 
7059 		return (DFC_ARG_INVALID);
7060 	}
7061 
7062 	if (enable) {
7063 		if (dfc->buf1_size < sizeof (uint32_t)) {
7064 			dfc->buf1 = NULL;
7065 		} else if (!dfc->buf1) {
7066 			dfc->buf1_size = 0;
7067 		}
7068 
7069 		/* Make sure this pid/event is not already registered */
7070 		dfc_event = NULL;
7071 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7072 			dfc_event = &hba->dfc_event[i];
7073 
7074 			if (dfc_event->pid == pid &&
7075 			    dfc_event->event == event) {
7076 				break;
7077 			}
7078 		}
7079 
7080 		if (i == MAX_DFC_EVENTS) {
7081 			/* Find next available event object */
7082 			for (i = 0; i < MAX_DFC_EVENTS; i++) {
7083 				dfc_event = &hba->dfc_event[i];
7084 
7085 				if (!dfc_event->pid && !dfc_event->event) {
7086 					break;
7087 				}
7088 			}
7089 
7090 			/* Return if all event objects are busy */
7091 			if (i == MAX_DFC_EVENTS) {
7092 				EMLXS_MSGF(EMLXS_CONTEXT,
7093 				    &emlxs_dfc_error_msg,
7094 				    "%s: %s. Too many events registered. "
7095 				    "pid=%d enable=%d",
7096 				    emlxs_dfc_xlate(dfc->cmd),
7097 				    emlxs_dfc_event_xlate(event), pid,
7098 				    enable);
7099 
7100 				return (DFC_DRVRES_ERROR);
7101 			}
7102 		}
7103 
7104 		/* Initialize */
7105 		dfc_event->pid = pid;
7106 		dfc_event->event = event;
7107 		dfc_event->last_id = (uint32_t)-1;
7108 		dfc_event->dataout = NULL;
7109 		dfc_event->size = 0;
7110 		dfc_event->mode = 0;
7111 
7112 		(void) emlxs_get_dfc_event(port, dfc_event, 0);
7113 
7114 		if (dfc->buf1) {
7115 			if (ddi_copyout((void *)&dfc_event->last_id,
7116 			    dfc->buf1, sizeof (uint32_t), mode) != 0) {
7117 				EMLXS_MSGF(EMLXS_CONTEXT,
7118 				    &emlxs_dfc_error_msg,
7119 				    "%s: ddi_copyout failed.",
7120 				    emlxs_dfc_xlate(dfc->cmd));
7121 
7122 				return (DFC_COPYOUT_ERROR);
7123 			}
7124 		}
7125 
7126 		/*
7127 		 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7128 		 * "%s: %s. Enabled. pid=%d id=%d", emlxs_dfc_xlate(dfc->cmd),
7129 		 * emlxs_dfc_event_xlate(event), pid, dfc_event->last_id);
7130 		 */
7131 
7132 		hba->log_events |= event;
7133 	} else {	/* Disable */
7134 
7135 		/* Find the event entry */
7136 		dfc_event = NULL;
7137 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7138 			dfc_event = &hba->dfc_event[i];
7139 
7140 			if (dfc_event->pid == pid &&
7141 			    dfc_event->event == event) {
7142 				break;
7143 			}
7144 		}
7145 
7146 		if (i == MAX_DFC_EVENTS) {
7147 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7148 			    "%s: %s. Event not registered. pid=%d enable=%d",
7149 			    emlxs_dfc_xlate(dfc->cmd),
7150 			    emlxs_dfc_event_xlate(event), pid, enable);
7151 
7152 			return (DFC_ARG_INVALID);
7153 		}
7154 
7155 		/* Kill the event thread if it is sleeping */
7156 		(void) emlxs_kill_dfc_event(port, dfc_event);
7157 
7158 		/* Count the number of pids still registered for this event */
7159 		count = 0;
7160 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
7161 			dfc_event = &hba->dfc_event[i];
7162 
7163 			if (dfc_event->event == event) {
7164 				count++;
7165 			}
7166 		}
7167 
7168 		/* If no more pids need this event, */
7169 		/* then disable logging for this event */
7170 		if (count == 0) {
7171 			hba->log_events &= ~event;
7172 		}
7173 	}
7174 
7175 	return (0);
7176 
7177 } /* emlxs_dfc_set_event() */
7178 
7179 
7180 static int32_t
7181 emlxs_dfc_get_eventinfo(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7182 {
7183 	emlxs_port_t	*port = &PPORT;
7184 	uint32_t	size;
7185 	int32_t		rval = 0;
7186 	HBA_EVENTINFO 	*event_buffer = NULL;
7187 	uint32_t	event_count = 0;
7188 	uint32_t	missed = 0;
7189 
7190 	if (!dfc->buf1 || !dfc->buf1_size) {
7191 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7192 		    "%s: Null buffer1 buffer.", emlxs_dfc_xlate(dfc->cmd));
7193 
7194 		return (DFC_ARG_NULL);
7195 	}
7196 
7197 	event_count = dfc->buf1_size / sizeof (HBA_EVENTINFO);
7198 
7199 	if (!event_count) {
7200 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7201 		    "%s: Buffer1 too small. (size=%d)",
7202 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
7203 
7204 		return (DFC_ARG_TOOSMALL);
7205 	}
7206 
7207 	if (!dfc->buf2 || !dfc->buf2_size) {
7208 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7209 		    "%s: Null buffer2 buffer.", emlxs_dfc_xlate(dfc->cmd));
7210 
7211 		return (DFC_ARG_NULL);
7212 	}
7213 
7214 	if (dfc->buf2_size < sizeof (uint32_t)) {
7215 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7216 		    "%s: Buffer2 too small. (size=%d)",
7217 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
7218 
7219 		return (DFC_ARG_TOOSMALL);
7220 	}
7221 
7222 	if (!dfc->buf3 || !dfc->buf3_size) {
7223 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7224 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
7225 
7226 		return (DFC_ARG_NULL);
7227 	}
7228 
7229 	if (dfc->buf3_size < sizeof (uint32_t)) {
7230 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7231 		    "%s: Buffer3 too small. (size=%d)",
7232 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf3_size);
7233 
7234 		return (DFC_ARG_TOOSMALL);
7235 	}
7236 
7237 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s called. max=%d",
7238 	    emlxs_dfc_xlate(dfc->cmd), event_count);
7239 
7240 	size = (event_count * sizeof (HBA_EVENTINFO));
7241 	if (!(event_buffer = (HBA_EVENTINFO *)kmem_zalloc(size, KM_SLEEP))) {
7242 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7243 		    "%s: Unable to allocate buffer. size=%d",
7244 		    emlxs_dfc_xlate(dfc->cmd), size);
7245 
7246 		return (DFC_SYSRES_ERROR);
7247 	}
7248 
7249 	if (emlxs_get_dfc_eventinfo(port, event_buffer, &event_count,
7250 	    &missed) != 0) {
7251 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7252 		    "%s: emlxs_get_dfc_eventinfo failed.",
7253 		    emlxs_dfc_xlate(dfc->cmd));
7254 
7255 		rval = DFC_DRV_ERROR;
7256 		goto done;
7257 	}
7258 
7259 	if (event_count) {
7260 		if (ddi_copyout((void *)event_buffer, dfc->buf1,
7261 		    (event_count * sizeof (HBA_EVENTINFO)), mode) != 0) {
7262 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7263 			    "%s: ddi_copyout failed.",
7264 			    emlxs_dfc_xlate(dfc->cmd));
7265 
7266 			rval = DFC_COPYOUT_ERROR;
7267 			goto done;
7268 		}
7269 	}
7270 
7271 	if (ddi_copyout((void *)&event_count, dfc->buf2, sizeof (uint32_t),
7272 	    mode) != 0) {
7273 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7274 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7275 
7276 		rval = DFC_COPYOUT_ERROR;
7277 		goto done;
7278 	}
7279 
7280 	if (ddi_copyout((void *)&missed, dfc->buf3, sizeof (uint32_t),
7281 	    mode) != 0) {
7282 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7283 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7284 
7285 		rval = DFC_COPYOUT_ERROR;
7286 		goto done;
7287 	}
7288 
7289 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7290 	    "%s: events=%d missed=%d new=%d last_id=%d",
7291 	    emlxs_dfc_xlate(dfc->cmd), event_count, hba->hba_event.missed,
7292 	    hba->hba_event.new, hba->hba_event.last_id);
7293 
7294 done:
7295 
7296 	if (event_buffer) {
7297 		kmem_free(event_buffer, size);
7298 	}
7299 
7300 	return (rval);
7301 
7302 } /* emlxs_dfc_get_eventinfo() */
7303 
7304 
7305 static int32_t
7306 emlxs_dfc_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7307 {
7308 	emlxs_port_t		*port = &PPORT;
7309 	uint32_t		event;
7310 	uint32_t		pid;
7311 	uint32_t		sleep;
7312 	uint32_t		i;
7313 	int32_t			rval = DFC_SUCCESS;
7314 	emlxs_dfc_event_t	*dfc_event;
7315 
7316 	event = dfc->data1;
7317 	pid = dfc->data2;
7318 
7319 	if (!dfc->buf1_size) {
7320 		dfc->buf1 = NULL;
7321 	} else if (!dfc->buf1) {
7322 		dfc->buf1_size = 0;
7323 	}
7324 
7325 	if (dfc->buf2_size < sizeof (uint32_t)) {
7326 		dfc->buf2 = NULL;
7327 	} else if (!dfc->buf2) {
7328 		dfc->buf2_size = 0;
7329 	}
7330 
7331 	if (dfc->buf3_size < sizeof (uint32_t)) {
7332 		dfc->buf3 = NULL;
7333 	} else if (!dfc->buf3) {
7334 		dfc->buf3_size = 0;
7335 	}
7336 
7337 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7338 	    "%s: %s. pid=%d size=%d,%p rcv_size=%d,%p id=%d",
7339 	    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid,
7340 	    dfc->buf1_size, dfc->buf1, dfc->buf2_size, dfc->buf2, dfc->data3);
7341 
7342 	/* Find the event entry */
7343 	dfc_event = NULL;
7344 	for (i = 0; i < MAX_DFC_EVENTS; i++) {
7345 		dfc_event = &hba->dfc_event[i];
7346 
7347 		if (dfc_event->pid == pid && dfc_event->event == event) {
7348 			break;
7349 		}
7350 	}
7351 
7352 	if (i == MAX_DFC_EVENTS) {
7353 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7354 		    "%s: %s. Event not registered. pid=%d",
7355 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7356 		    pid);
7357 
7358 		return (DFC_ARG_INVALID);
7359 	}
7360 
7361 	if (!(hba->log_events & dfc_event->event)) {
7362 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7363 		    "%s: %s. Event not registered. pid=%d",
7364 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7365 		    pid);
7366 
7367 		return (DFC_ARG_INVALID);
7368 	}
7369 
7370 	/* Initialize event buffer pointers */
7371 	dfc_event->dataout = dfc->buf1;
7372 	dfc_event->size = dfc->buf1_size;
7373 	dfc_event->last_id = dfc->data3;
7374 	dfc_event->mode = mode;
7375 
7376 	sleep = (dfc->flag & 0x01) ? 1 : 0;
7377 
7378 	if ((rval = emlxs_get_dfc_event(port, dfc_event, sleep))) {
7379 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7380 		    "%s: %s. Exiting. pid=%d rsize=%d id=%d rval=%d",
7381 		    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event),
7382 		    pid, dfc_event->size, dfc_event->last_id, rval);
7383 
7384 		return (rval);
7385 	}
7386 
7387 	if (dfc->buf2) {
7388 		if (ddi_copyout((void *)&dfc_event->size, dfc->buf2,
7389 		    sizeof (uint32_t), mode) != 0) {
7390 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7391 			    "%s: ddi_copyout failed.",
7392 			    emlxs_dfc_xlate(dfc->cmd));
7393 
7394 			return (DFC_COPYOUT_ERROR);
7395 		}
7396 	}
7397 
7398 	if (dfc->buf3) {
7399 		if (ddi_copyout((void *)&dfc_event->last_id, dfc->buf3,
7400 		    sizeof (uint32_t), mode) != 0) {
7401 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7402 			    "%s: ddi_copyout failed.",
7403 			    emlxs_dfc_xlate(dfc->cmd));
7404 
7405 			return (DFC_COPYOUT_ERROR);
7406 		}
7407 	}
7408 
7409 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
7410 	    "%s: %s. Completed. pid=%d rsize=%d id=%d",
7411 	    emlxs_dfc_xlate(dfc->cmd), emlxs_dfc_event_xlate(event), pid,
7412 	    dfc_event->size, dfc_event->last_id);
7413 
7414 	return (rval);
7415 
7416 } /* emlxs_dfc_get_event() */
7417 
7418 
7419 extern uint32_t
7420 emlxs_get_dump_region(emlxs_hba_t *hba, uint32_t region,
7421     uint8_t *buffer, uint32_t *psize)
7422 {
7423 	emlxs_port_t	*port = &PPORT;
7424 	uint32_t	size;
7425 	uint32_t	size_only;
7426 	uint32_t	rval = 0;
7427 	uint8_t		*memptr;
7428 	uint32_t	*wptr;
7429 
7430 	if (!buffer || !(*psize)) {
7431 		size_only = 1;
7432 		size = 0xffffffff;
7433 	} else {
7434 		size_only = 0;
7435 		size = *psize;
7436 	}
7437 
7438 	switch (region) {
7439 	case 0:	/* SLI Registers */
7440 
7441 		if (size < (4 * sizeof (uint32_t))) {
7442 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7443 			    "emlxs_get_dump_region: Buffer too small. "
7444 			    "(SLI Registers: size=%d)", size);
7445 
7446 			rval = DFC_ARG_TOOSMALL;
7447 			goto done;
7448 		}
7449 
7450 		size = (4 * sizeof (uint32_t));
7451 
7452 		if (size_only) {
7453 			break;
7454 		}
7455 
7456 		wptr = (uint32_t *)buffer;
7457 		wptr[0] = READ_CSR_REG(hba, FC_HA_REG(hba, hba->csr_addr));
7458 		wptr[1] = READ_CSR_REG(hba, FC_CA_REG(hba, hba->csr_addr));
7459 		wptr[2] = READ_CSR_REG(hba, FC_HS_REG(hba, hba->csr_addr));
7460 		wptr[3] = READ_CSR_REG(hba, FC_HC_REG(hba, hba->csr_addr));
7461 
7462 		break;
7463 
7464 	case 1:	/* SLIM */
7465 
7466 		if (hba->flag & FC_SLIM2_MODE) {
7467 			size = MIN(SLI2_SLIM2_SIZE, size);
7468 		} else {
7469 			size = MIN(4096, size);
7470 		}
7471 
7472 		if (size_only) {
7473 			break;
7474 		}
7475 
7476 		if (hba->flag & FC_SLIM2_MODE) {
7477 			memptr = (uint8_t *)hba->slim2.virt;
7478 			emlxs_pcimem_bcopy((uint32_t *)memptr,
7479 			    (uint32_t *)buffer, size);
7480 		} else {
7481 			memptr = (uint8_t *)hba->slim_addr;
7482 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7483 			    (uint32_t *)memptr, (size / 4));
7484 		}
7485 
7486 		break;
7487 
7488 	case 2:	/* Port Control Block */
7489 
7490 		if (size < sizeof (PCB)) {
7491 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7492 			    "emlxs_get_dump_region: Buffer too small. "
7493 			    "(PCB: size=%d)", size);
7494 
7495 			rval = DFC_ARG_TOOSMALL;
7496 			goto done;
7497 		}
7498 
7499 		size = sizeof (PCB);
7500 
7501 		if (size_only) {
7502 			break;
7503 		}
7504 
7505 		memptr = (uint8_t *)&(((SLIM2 *)hba->slim2.virt)->pcb);
7506 		emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer,
7507 		    size);
7508 
7509 		break;
7510 
7511 	case 3:	/* MailBox */
7512 
7513 		if (size < MAILBOX_CMD_BSIZE) {
7514 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7515 			    "emlxs_get_dump_region: Buffer too small. "
7516 			    "(Mailbox: size=%d)", size);
7517 
7518 			rval = DFC_ARG_TOOSMALL;
7519 			goto done;
7520 		}
7521 
7522 		size = MAILBOX_CMD_BSIZE;
7523 
7524 		if (size_only) {
7525 			break;
7526 		}
7527 
7528 		if (hba->flag & FC_SLIM2_MODE) {
7529 			memptr = (uint8_t *)hba->slim2.virt;
7530 			emlxs_pcimem_bcopy((uint32_t *)memptr,
7531 			    (uint32_t *)buffer, size);
7532 		} else {
7533 			memptr = (uint8_t *)hba->slim_addr;
7534 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7535 			    (uint32_t *)memptr, (size / 4));
7536 		}
7537 
7538 		break;
7539 
7540 	case 4:	/* Host Put/Get pointer array */
7541 
7542 		if (size < MAX_RINGS * sizeof (HGP)) {
7543 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7544 			    "emlxs_get_dump_region: Buffer too small. "
7545 			    "(HGP: size=%d)", size);
7546 
7547 			rval = DFC_ARG_TOOSMALL;
7548 			goto done;
7549 		}
7550 
7551 		size = MAX_RINGS * sizeof (HGP);
7552 
7553 		if (size_only) {
7554 			break;
7555 		}
7556 
7557 		{
7558 			memptr =
7559 			    (uint8_t *)hba->slim_addr + hba->hgp_ring_offset;
7560 			READ_SLIM_COPY(hba, (uint32_t *)buffer,
7561 			    (uint32_t *)memptr, (size / 4));
7562 		}
7563 
7564 		break;
7565 
7566 	case 5:	/* Port  Get/Put pointer array */
7567 
7568 		if (size < MAX_RINGS * sizeof (PGP)) {
7569 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7570 			    "emlxs_get_dump_region: Buffer too small. "
7571 			    "(PGP: size=%d)", size);
7572 
7573 			rval = DFC_ARG_TOOSMALL;
7574 			goto done;
7575 		}
7576 
7577 		size = MAX_RINGS * sizeof (PGP);
7578 
7579 		if (size_only) {
7580 			break;
7581 		}
7582 
7583 		memptr =
7584 		    (uint8_t *)((SLIM2 *)hba->slim2.virt)->mbx.us.s2.port;
7585 		emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer,
7586 		    size);
7587 
7588 		break;
7589 
7590 	case 6:	/* Command/Response Ring */
7591 
7592 		if (size < SLI_IOCB_MAX_SIZE) {
7593 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7594 			    "emlxs_get_dump_region: Buffer too small. "
7595 			    "(Rings: size=%d)", size);
7596 
7597 			rval = DFC_ARG_TOOSMALL;
7598 			goto done;
7599 		}
7600 
7601 		size = SLI_IOCB_MAX_SIZE;
7602 
7603 		if (size_only) {
7604 			break;
7605 		}
7606 
7607 		memptr = (uint8_t *)((SLIM2 *)hba->slim2.virt)->IOCBs;
7608 		emlxs_pcimem_bcopy((uint32_t *)memptr, (uint32_t *)buffer,
7609 		    size);
7610 
7611 		break;
7612 
7613 	case 7:	/* All driver specific structures */
7614 
7615 		if (size < sizeof (emlxs_hba_t)) {
7616 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7617 			    "emlxs_get_dump_region: Buffer too small. "
7618 			    "(Driver: size=%d)", size);
7619 
7620 			rval = DFC_ARG_TOOSMALL;
7621 			goto done;
7622 		}
7623 
7624 		size = sizeof (emlxs_hba_t);
7625 
7626 		if (size_only) {
7627 			break;
7628 		}
7629 
7630 		memptr = (uint8_t *)hba;
7631 		bcopy((void *)memptr, (void *)buffer, size);
7632 
7633 		break;
7634 
7635 	default:
7636 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7637 		    "emlxs_get_dump_region: Invalid region. (id=%d)", region);
7638 
7639 		rval = DFC_ARG_INVALID;
7640 	}
7641 
7642 done:
7643 
7644 	*psize = size;
7645 
7646 	return (rval);
7647 
7648 } /* emlxs_get_dump_region() */
7649 
7650 
7651 
7652 static int32_t
7653 emlxs_dfc_get_dump_region(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
7654 {
7655 	emlxs_port_t	*port = &PPORT;
7656 	uint32_t	size;
7657 	uint32_t	size_only = 0;
7658 	uint32_t	rval = 0;
7659 	uint8_t		*buffer = NULL;
7660 
7661 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
7662 	    "%s: region=%d size=%d",
7663 	    emlxs_dfc_xlate(dfc->cmd), dfc->data1, dfc->buf1_size);
7664 
7665 	if (!dfc->buf1 || !dfc->buf1_size) {
7666 		size_only = 1;
7667 	}
7668 
7669 	if (!dfc->buf2 || !dfc->buf2_size) {
7670 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7671 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
7672 
7673 		return (DFC_ARG_NULL);
7674 	}
7675 
7676 	if (dfc->buf2_size < sizeof (uint32_t)) {
7677 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7678 		    "%s: Buffer2 too small. (size=%d)",
7679 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
7680 
7681 		return (DFC_ARG_TOOSMALL);
7682 	}
7683 
7684 	/* First get region size only */
7685 	size = 0;
7686 	rval = emlxs_get_dump_region(hba, dfc->data1, NULL, &size);
7687 
7688 	if (rval != 0) {
7689 		goto done;
7690 	}
7691 
7692 	if (!size_only) {
7693 		if (dfc->buf1_size < size) {
7694 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7695 			    "%s: Buffer1 too small. (size: %d < %d)",
7696 			    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size, size);
7697 
7698 			rval = DFC_ARG_TOOSMALL;
7699 			goto done;
7700 		}
7701 
7702 		if (!(buffer = (uint8_t *)kmem_zalloc(size, KM_SLEEP))) {
7703 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7704 			    "%s: Unable to allocate buffer. size=%d",
7705 			    emlxs_dfc_xlate(dfc->cmd), size);
7706 
7707 			rval = DFC_SYSRES_ERROR;
7708 			goto done;
7709 		}
7710 
7711 		/* Get the region data */
7712 		rval = emlxs_get_dump_region(hba, dfc->data1, buffer, &size);
7713 
7714 		if (rval != 0) {
7715 			goto done;
7716 		}
7717 
7718 		/* Return the region data */
7719 		if (ddi_copyout((void *)buffer, (void *) dfc->buf1,
7720 		    size, mode) != 0) {
7721 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7722 			    "%s: ddi_copyout failed.",
7723 			    emlxs_dfc_xlate(dfc->cmd));
7724 
7725 			rval = DFC_COPYOUT_ERROR;
7726 			goto done;
7727 		}
7728 	}
7729 
7730 	/* Return the region size */
7731 	if (ddi_copyout((void *) &size, (void *) dfc->buf2,
7732 	    sizeof (uint32_t), mode) != 0) {
7733 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7734 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
7735 
7736 		rval = DFC_COPYOUT_ERROR;
7737 		goto done;
7738 	}
7739 
7740 done:
7741 
7742 	if (buffer) {
7743 		kmem_free(buffer, size);
7744 	}
7745 
7746 	return (rval);
7747 
7748 } /* emlxs_dfc_get_dump_region() */
7749 
7750 
7751 
7752 #ifdef MENLO_SUPPORT
7753 static int32_t
7754 emlxs_dfc_menlo_port_offset(emlxs_hba_t *hba)
7755 {
7756 	uint32_t	cnt;
7757 	char		pathname[256];
7758 
7759 	(void) ddi_pathname(hba->dip, pathname);
7760 	cnt = strlen(pathname);
7761 	if ((cnt < 4) || (strcmp(&pathname[cnt-3], "0,1") != 0))
7762 		return (0);
7763 	return (1);
7764 }
7765 
7766 static int32_t
7767 emlxs_dfc_set_menlo_loopback(emlxs_hba_t *hba)
7768 {
7769 	emlxs_port_t *port = &PPORT;
7770 	MAILBOXQ *mbq = NULL;
7771 	MAILBOX *mb = NULL;
7772 	fc_packet_t *pkt = NULL;
7773 	uint32_t mbxstatus;
7774 	uint32_t i;
7775 	uint32_t offset;
7776 	uint32_t rval = 0;
7777 	menlo_cmd_t *cmd;
7778 
7779 	if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
7780 	    KM_SLEEP)) == 0) {
7781 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7782 		    "%s: Unable to allocate mailbox buffer.",
7783 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7784 
7785 		rval = DFC_SYSRES_ERROR;
7786 		goto done;
7787 	}
7788 
7789 	mb = (MAILBOX *)mbq;
7790 
7791 	/* SET MENLO maint mode */
7792 	/* Create the set_variable mailbox request */
7793 	emlxs_mb_set_var(hba, mb, 0x103107, 1);
7794 
7795 	mbq->flag |= MBQ_PASSTHRU;
7796 
7797 	/* issue the mbox cmd to the sli */
7798 	mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
7799 
7800 	if (mbxstatus) {
7801 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7802 		    "%s: %s failed. mbxstatus=0x%x",
7803 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
7804 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
7805 
7806 		rval = DFC_IO_ERROR;
7807 		if (mbxstatus == MBX_TIMEOUT)
7808 			rval = DFC_TIMEOUT;
7809 		goto done;
7810 	}
7811 
7812 
7813 	/* Wait 30 sec for maint mode */
7814 	i = 0;
7815 	do {
7816 		if (i++ > 300) {
7817 			break;
7818 		}
7819 
7820 		delay(drv_usectohz(100000));
7821 
7822 	} while (!(hba->flag & FC_MENLO_MODE));
7823 
7824 	if (!(hba->flag & FC_MENLO_MODE)) {
7825 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7826 		    "%s: Unable to enter maint mode.",
7827 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7828 
7829 		rval = DFC_DRV_ERROR;
7830 		goto done;
7831 	}
7832 
7833 	offset = emlxs_dfc_menlo_port_offset(hba);
7834 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7835 	    "%s: Entered maint mode. Port offset: %d",
7836 	    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE), offset);
7837 
7838 
7839 	/* Issue Menlo loopback command */
7840 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t),
7841 	    sizeof (uint32_t), 0, KM_NOSLEEP))) {
7842 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7843 		    "%s: Unable to allocate packet.",
7844 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7845 
7846 		rval = DFC_SYSRES_ERROR;
7847 		goto done;
7848 	}
7849 
7850 	/* Make this a polled IO */
7851 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
7852 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
7853 	pkt->pkt_comp = NULL;
7854 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
7855 	pkt->pkt_timeout = 30;
7856 
7857 	/* Build the fc header */
7858 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(EMLXS_MENLO_DID);
7859 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
7860 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
7861 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
7862 	pkt->pkt_cmd_fhdr.f_ctl =
7863 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
7864 	pkt->pkt_cmd_fhdr.seq_id = 0;
7865 	pkt->pkt_cmd_fhdr.df_ctl = 0;
7866 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
7867 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
7868 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
7869 	pkt->pkt_cmd_fhdr.ro = 0;
7870 
7871 	cmd = (menlo_cmd_t *)pkt->pkt_cmd;
7872 	cmd->code = SWAP_LONG(MENLO_CMD_LOOPBACK);
7873 	cmd->lb.context = SWAP_LONG(offset);
7874 	cmd->lb.type = SWAP_LONG(MENLO_LOOPBACK_ENABLE);
7875 
7876 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
7877 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7878 		    "%s: Unable to send packet.",
7879 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7880 
7881 		rval = DFC_IO_ERROR;
7882 		goto done;
7883 	}
7884 
7885 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
7886 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
7887 			EMLXS_MSGF(EMLXS_CONTEXT,
7888 			    &emlxs_dfc_error_msg,
7889 			    "%s: Pkt Transport error. Pkt Timeout.",
7890 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7891 			rval = DFC_TIMEOUT;
7892 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
7893 		    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
7894 			EMLXS_MSGF(EMLXS_CONTEXT,
7895 			    &emlxs_dfc_error_msg,
7896 			    "%s: Pkt Transport error. Rsp overrun.",
7897 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7898 			rval = DFC_RSP_BUF_OVERRUN;
7899 		} else {
7900 			EMLXS_MSGF(EMLXS_CONTEXT,
7901 			    &emlxs_dfc_error_msg,
7902 			    "%s: Pkt Transport error. state=%x",
7903 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
7904 			    pkt->pkt_state);
7905 			rval = DFC_IO_ERROR;
7906 		}
7907 		goto done;
7908 	}
7909 
7910 
7911 	/* CLEAR MENLO maint mode */
7912 	/* Create the set_variable mailbox request */
7913 	emlxs_mb_set_var(hba, mb, 0x103107, 0);
7914 
7915 	mbq->flag |= MBQ_PASSTHRU;
7916 
7917 	/* issue the mbox cmd to the sli */
7918 	mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
7919 
7920 	if (mbxstatus) {
7921 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7922 		    "%s: %s failed. mbxstatus=0x%x",
7923 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
7924 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
7925 
7926 		rval = DFC_IO_ERROR;
7927 		if (mbxstatus == MBX_TIMEOUT)
7928 			rval = DFC_TIMEOUT;
7929 	}
7930 
7931 	delay(drv_usectohz(1000000));
7932 	i = 0;
7933 	while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) {
7934 		delay(drv_usectohz(100000));
7935 		i++;
7936 
7937 		if (i == 300) {
7938 			rval = DFC_TIMEOUT;
7939 
7940 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7941 			    "%s: Linkup timeout.",
7942 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7943 
7944 			goto done;
7945 		}
7946 	}
7947 
7948 done:
7949 	/* Free allocated mbox memory */
7950 	if (mbq) {
7951 		kmem_free(mbq, sizeof (MAILBOXQ));
7952 	}
7953 	if (pkt) {
7954 		emlxs_pkt_free(pkt);
7955 	}
7956 	return (rval);
7957 }
7958 
7959 static int32_t
7960 emlxs_dfc_set_menlo_fte(emlxs_hba_t *hba)
7961 {
7962 	emlxs_port_t *port = &PPORT;
7963 	fc_packet_t *pkt = NULL;
7964 	uint32_t rval = 0;
7965 	menlo_cmd_t *cmd;
7966 
7967 
7968 	/* Issue Menlo loopback command */
7969 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (menlo_cmd_t),
7970 	    sizeof (uint32_t), 0, KM_NOSLEEP))) {
7971 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
7972 		    "%s: Unable to allocate packet.",
7973 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
7974 
7975 		rval = DFC_SYSRES_ERROR;
7976 		goto done;
7977 	}
7978 
7979 	/* Make this a polled IO */
7980 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
7981 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
7982 	pkt->pkt_comp = NULL;
7983 	pkt->pkt_tran_type = FC_PKT_EXCHANGE;
7984 	pkt->pkt_timeout = 30;
7985 
7986 	/* Build the fc header */
7987 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(EMLXS_MENLO_DID);
7988 	pkt->pkt_cmd_fhdr.r_ctl = R_CTL_COMMAND;
7989 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
7990 	pkt->pkt_cmd_fhdr.type = EMLXS_MENLO_TYPE;
7991 	pkt->pkt_cmd_fhdr.f_ctl =
7992 	    F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
7993 	pkt->pkt_cmd_fhdr.seq_id = 0;
7994 	pkt->pkt_cmd_fhdr.df_ctl = 0;
7995 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
7996 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
7997 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
7998 	pkt->pkt_cmd_fhdr.ro = 0;
7999 
8000 	cmd = (menlo_cmd_t *)pkt->pkt_cmd;
8001 	cmd->code = SWAP_LONG(MENLO_CMD_FTE_INSERT);
8002 	cmd->fte_insert.fcid = SWAP_LONG(0);
8003 	bcopy((caddr_t)&port->wwpn, (caddr_t)cmd->fte_insert.wwpn, 8);
8004 
8005 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
8006 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8007 		    "%s: Unable to send packet.",
8008 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8009 
8010 		rval = DFC_IO_ERROR;
8011 		goto done;
8012 	}
8013 
8014 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8015 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8016 			EMLXS_MSGF(EMLXS_CONTEXT,
8017 			    &emlxs_dfc_error_msg,
8018 			    "%s: Pkt Transport error. Pkt Timeout.",
8019 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8020 			rval = DFC_TIMEOUT;
8021 		} else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
8022 		    (pkt->pkt_reason == FC_REASON_OVERRUN)) {
8023 			EMLXS_MSGF(EMLXS_CONTEXT,
8024 			    &emlxs_dfc_error_msg,
8025 			    "%s: Pkt Transport error. Rsp overrun.",
8026 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8027 			rval = DFC_RSP_BUF_OVERRUN;
8028 		} else {
8029 			EMLXS_MSGF(EMLXS_CONTEXT,
8030 			    &emlxs_dfc_error_msg,
8031 			    "%s: Pkt Transport error. state=%x",
8032 			    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8033 			    pkt->pkt_state);
8034 			rval = DFC_IO_ERROR;
8035 		}
8036 		goto done;
8037 	}
8038 
8039 
8040 done:
8041 	if (pkt) {
8042 		emlxs_pkt_free(pkt);
8043 	}
8044 	return (rval);
8045 }
8046 
8047 static int32_t
8048 emlxs_dfc_reset_menlo(emlxs_hba_t *hba)
8049 {
8050 	emlxs_port_t *port = &PPORT;
8051 	MAILBOXQ *mbq = NULL;
8052 	MAILBOX *mb = NULL;
8053 	uint32_t mbxstatus;
8054 	uint32_t rval = 0;
8055 
8056 	if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8057 	    KM_SLEEP)) == 0) {
8058 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8059 		    "%s: Unable to allocate mailbox buffer.",
8060 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE));
8061 
8062 		rval = DFC_SYSRES_ERROR;
8063 		goto done;
8064 	}
8065 
8066 	mb = (MAILBOX *)mbq;
8067 
8068 	/* RESET MENLO */
8069 	/* Create the set_variable mailbox request */
8070 	emlxs_mb_set_var(hba, mb, 0x103007, 0);
8071 
8072 	mbq->flag |= MBQ_PASSTHRU;
8073 
8074 	/* issue the mbox cmd to the sli */
8075 	mbxstatus = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
8076 
8077 	if (mbxstatus) {
8078 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8079 		    "%s: %s failed. mbxstatus=0x%x",
8080 		    emlxs_dfc_xlate(EMLXS_LOOPBACK_MODE),
8081 		    emlxs_mb_cmd_xlate(mb->mbxCommand), mbxstatus);
8082 
8083 		rval = DFC_IO_ERROR;
8084 		if (mbxstatus == MBX_TIMEOUT)
8085 			rval = DFC_TIMEOUT;
8086 		goto done;
8087 	}
8088 done:
8089 	/* Free allocated mbox memory */
8090 	if (mbq) {
8091 		kmem_free(mbq, sizeof (MAILBOXQ));
8092 	}
8093 	return (rval);
8094 }
8095 
8096 #endif /* MENLO_SUPPORT */
8097 
8098 /* ARGSUSED */
8099 static int32_t
8100 emlxs_dfc_loopback_mode(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8101 {
8102 	emlxs_port_t	*port = &PPORT;
8103 	emlxs_config_t	*cfg = &CFG;
8104 	MAILBOXQ	*mbq = NULL;
8105 	MAILBOX		*mb = NULL;
8106 	uint32_t	rval = DFC_SUCCESS;
8107 	uint32_t	i;
8108 	uint32_t	timeout;
8109 	uint32_t	topology;
8110 	uint32_t	speed;
8111 	uint32_t	new_mode;
8112 	NODELIST	*ndlp;
8113 
8114 	/* Reinitialize the link */
8115 	switch (dfc->flag) {
8116 	case 0:	/* Disable */
8117 
8118 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8119 		    "%s: Disabling Loopback.", emlxs_dfc_xlate(dfc->cmd));
8120 
8121 		if (!(hba->flag & FC_LOOPBACK_MODE)) {
8122 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8123 			    "%s: Loopback already disabled.",
8124 			    emlxs_dfc_xlate(dfc->cmd));
8125 
8126 			return (rval);
8127 		}
8128 		goto resetdone;
8129 
8130 	case 1:	/* Internal loopback */
8131 		new_mode = FC_ILB_MODE;
8132 		topology = FLAGS_LOCAL_LB;
8133 		speed = 0;
8134 
8135 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8136 		    "%s: Enabling ILB.", emlxs_dfc_xlate(dfc->cmd));
8137 
8138 		/* Check if mode already set */
8139 		if ((hba->flag & FC_ILB_MODE)) {
8140 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8141 			    "%s: ILB mode already enabled.",
8142 			    emlxs_dfc_xlate(dfc->cmd));
8143 
8144 			return (rval);
8145 		}
8146 
8147 		break;
8148 
8149 	case 2:	/* External loopback */
8150 		new_mode = FC_ELB_MODE;
8151 		topology = FLAGS_TOPOLOGY_MODE_LOOP;
8152 		speed = cfg[CFG_LINK_SPEED].current;
8153 
8154 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8155 		    "%s: Enabling ELB.", emlxs_dfc_xlate(dfc->cmd));
8156 
8157 		/* Check if mode already set */
8158 		if ((hba->flag & FC_ELB_MODE)) {
8159 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8160 			    "%s: ELB mode already enabled.",
8161 			    emlxs_dfc_xlate(dfc->cmd));
8162 
8163 			return (rval);
8164 		}
8165 
8166 		break;
8167 
8168 	default:
8169 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8170 		    "%s: Invalid loopback mode. (mode=%x)",
8171 		    emlxs_dfc_xlate(dfc->cmd), dfc->flag);
8172 
8173 		return (DFC_ARG_INVALID);
8174 	}
8175 
8176 	/* Make sure adapter is online */
8177 	if (emlxs_online(hba)) {
8178 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8179 		    "%s: Unable to bring adapter online.",
8180 		    emlxs_dfc_xlate(dfc->cmd));
8181 
8182 		return (DFC_OFFLINE_ERROR);
8183 	}
8184 
8185 #ifdef MENLO_SUPPORT
8186 	if (hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) {
8187 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8188 		    "%s: Menlo support detected: mode:x%x",
8189 		    emlxs_dfc_xlate(dfc->cmd), new_mode);
8190 
8191 		if (new_mode == FC_ILB_MODE) {
8192 			rval = emlxs_dfc_set_menlo_loopback(hba);
8193 			if (rval)
8194 				goto done;
8195 		}
8196 	}
8197 #endif /* MENLO_SUPPORT */
8198 
8199 	if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
8200 	    KM_SLEEP)) == 0) {
8201 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8202 		    "%s: Unable to allocate mailbox buffer.",
8203 		    emlxs_dfc_xlate(dfc->cmd));
8204 
8205 		rval = DFC_SYSRES_ERROR;
8206 		goto done;
8207 	}
8208 
8209 	mb = (MAILBOX *) mbq;
8210 
8211 	/* Take the link down */
8212 	emlxs_mb_down_link(hba, mb);
8213 
8214 	rval = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
8215 
8216 	if (rval == MBX_TIMEOUT) {
8217 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8218 		    "%s: Mailbox timed out. cmd=%x",
8219 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
8220 
8221 		rval = DFC_TIMEOUT;
8222 		goto done;
8223 	}
8224 
8225 	if (rval) {
8226 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8227 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
8228 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
8229 
8230 		rval = DFC_IO_ERROR;
8231 		goto done;
8232 	}
8233 
8234 	/* Reinitialize the link */
8235 	emlxs_mb_init_link(hba, mb, topology, speed);
8236 
8237 	/* Set the loopback mode and timer */
8238 	mutex_enter(&EMLXS_PORT_LOCK);
8239 	hba->flag |= new_mode;
8240 	hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo;
8241 	mutex_exit(&EMLXS_PORT_LOCK);
8242 
8243 	rval = emlxs_sli_issue_mbox_cmd(hba, mb, MBX_WAIT, 0);
8244 
8245 	if (rval == MBX_TIMEOUT) {
8246 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8247 		    "%s: Mailbox timed out. cmd=%x",
8248 		    emlxs_dfc_xlate(dfc->cmd), mb->mbxCommand);
8249 
8250 		rval = DFC_TIMEOUT;
8251 		goto done;
8252 	}
8253 
8254 	if (rval) {
8255 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8256 		    "%s: %s failed. status=%x", emlxs_dfc_xlate(dfc->cmd),
8257 		    emlxs_mb_cmd_xlate(mb->mbxCommand), rval);
8258 
8259 		rval = DFC_IO_ERROR;
8260 		goto done;
8261 	}
8262 
8263 	/*
8264 	 * Wait for adapter to come online.
8265 	 * Need *2 since we wait 1/2 sec in while loop.
8266 	 */
8267 	timeout = dfc->data1;
8268 	if (!timeout) {
8269 		timeout = 60 * 2;
8270 	} else {
8271 		timeout = timeout * 2;
8272 	}
8273 
8274 	i = 0;
8275 	while ((hba->state < FC_LINK_UP) && (hba->state != FC_ERROR)) {
8276 		delay(drv_usectohz(500000));
8277 		i++;
8278 
8279 		if (i == timeout) {
8280 			rval = DFC_TIMEOUT;
8281 
8282 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8283 			    "%s: Linkup timeout.", emlxs_dfc_xlate(dfc->cmd));
8284 
8285 			goto done;
8286 		}
8287 	}
8288 
8289 	/* Create host node */
8290 	if (emlxs_mb_reg_did(port, port->did, (SERV_PARM *)&hba->sparam,
8291 	    NULL, NULL, NULL)) {
8292 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8293 		    "%s: Unable to register host node.",
8294 		    emlxs_dfc_xlate(dfc->cmd));
8295 
8296 		rval = DFC_DRV_ERROR;
8297 		goto done;
8298 	}
8299 
8300 	i = 0;
8301 	do {
8302 		if (i++ > 300) {
8303 			break;
8304 		}
8305 
8306 		delay(drv_usectohz(100000));
8307 
8308 	} while (!(ndlp = emlxs_node_find_did(port, port->did)));
8309 
8310 	if (!ndlp) {
8311 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8312 		    "%s: Unable to create host node.",
8313 		    emlxs_dfc_xlate(dfc->cmd));
8314 
8315 		rval = DFC_DRV_ERROR;
8316 		goto done;
8317 	}
8318 
8319 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8320 	    "%s: Node created. node=%p", emlxs_dfc_xlate(dfc->cmd), ndlp);
8321 
8322 #ifdef MENLO_SUPPORT
8323 	if (hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) {
8324 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8325 		    "%s: Menlo support detected: mode:x%x",
8326 		    emlxs_dfc_xlate(dfc->cmd), new_mode);
8327 
8328 		rval = emlxs_dfc_set_menlo_fte(hba);
8329 		if (rval)
8330 			goto done;
8331 	}
8332 #endif /* MENLO_SUPPORT */
8333 
8334 	/* Create host XRI */
8335 	(void) emlxs_create_xri(port, &hba->ring[FC_CT_RING], ndlp);
8336 
8337 	i = 0;
8338 	do {
8339 		if (i++ > 300) {
8340 			break;
8341 		}
8342 
8343 		delay(drv_usectohz(100000));
8344 
8345 	} while (!ndlp->nlp_Xri);
8346 
8347 	if (!ndlp->nlp_Xri) {
8348 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8349 		    "%s: Unable to create XRI.", emlxs_dfc_xlate(dfc->cmd));
8350 
8351 		rval = DFC_DRV_ERROR;
8352 		goto done;
8353 	}
8354 
8355 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8356 	    "%s: XRI created. xri=%x", emlxs_dfc_xlate(dfc->cmd),
8357 	    ndlp->nlp_Xri);
8358 done:
8359 	/* Free allocated mbox memory */
8360 	if (mbq) {
8361 		kmem_free(mbq, sizeof (MAILBOXQ));
8362 	}
8363 
8364 	if (rval) {
8365 resetdone:
8366 		/* Reset the adapter */
8367 #ifdef MENLO_SUPPORT
8368 		if (hba->model_info.device_id == PCI_DEVICE_ID_LP21000_M) {
8369 
8370 			rval = emlxs_dfc_reset_menlo(hba);
8371 
8372 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8373 			    "%s: Menlo reset: rval:x%x",
8374 			    emlxs_dfc_xlate(dfc->cmd), rval);
8375 	}
8376 #endif /* MENLO_SUPPORT */
8377 
8378 		/* Reset link whether we are bound to ULP or not */
8379 		(void) emlxs_reset_link(hba, 1);
8380 	}
8381 
8382 	return (rval);
8383 } /* emlxs_dfc_loopback_mode() */
8384 
8385 
8386 static int32_t
8387 emlxs_dfc_loopback_test(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8388 {
8389 	emlxs_port_t	*port = &PPORT;
8390 	uint32_t	rval = 0;
8391 	NODELIST	*ndlp;
8392 	clock_t		timeout;
8393 	fc_packet_t	*pkt = NULL;
8394 	SLI_CT_REQUEST	*CtCmd;
8395 	uint16_t	CtRsp;
8396 
8397 	mutex_enter(&EMLXS_PORT_LOCK);
8398 	if (!(hba->flag & FC_LOOPBACK_MODE)) {
8399 		mutex_exit(&EMLXS_PORT_LOCK);
8400 
8401 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8402 		    "%s: Adapter not in loopback mode.",
8403 		    emlxs_dfc_xlate(dfc->cmd));
8404 
8405 		rval = DFC_DRV_ERROR;
8406 		goto done;
8407 	}
8408 	hba->loopback_tics = hba->timer_tics + emlxs_loopback_tmo;
8409 	mutex_exit(&EMLXS_PORT_LOCK);
8410 
8411 	if (!(hba->flag & FC_ONLINE_MODE)) {
8412 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8413 		    "%s: Adapter offline.", emlxs_dfc_xlate(dfc->cmd));
8414 
8415 		rval = DFC_OFFLINE_ERROR;
8416 		goto done;
8417 	}
8418 
8419 	if (hba->state < FC_LINK_UP) {
8420 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8421 		    "%s: Link not up.", emlxs_dfc_xlate(dfc->cmd));
8422 
8423 		rval = DFC_OFFLINE_ERROR;
8424 		goto done;
8425 	}
8426 
8427 	if (!dfc->buf1 || !dfc->buf1_size) {
8428 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8429 		    "%s: NULL buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8430 
8431 		rval = DFC_ARG_NULL;
8432 		goto done;
8433 	}
8434 
8435 	if (!dfc->buf2 || !dfc->buf2_size) {
8436 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8437 		    "%s: NULL buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8438 
8439 		rval = DFC_ARG_NULL;
8440 		goto done;
8441 	}
8442 
8443 	if (dfc->buf1_size > MAX_CT_PAYLOAD) {
8444 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8445 		    "%s: Buffer1 too large. (size=%d)",
8446 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8447 
8448 		rval = DFC_ARG_TOOBIG;
8449 		goto done;
8450 	}
8451 
8452 	/* Check if we have a node for ourselves */
8453 	ndlp = emlxs_node_find_did(port, port->did);
8454 
8455 	if (!ndlp) {
8456 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8457 		    "%s: Host node not found.", emlxs_dfc_xlate(dfc->cmd));
8458 
8459 		rval = DFC_ARG_INVALID;
8460 		goto done;
8461 	}
8462 
8463 	if (!ndlp->nlp_Xri) {
8464 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8465 		    "%s: Host XRI not found.", emlxs_dfc_xlate(dfc->cmd));
8466 
8467 		rval = DFC_DRV_ERROR;
8468 		goto done;
8469 	}
8470 
8471 	if (!(pkt = emlxs_pkt_alloc(port, dfc->buf1_size + 16,
8472 	    dfc->buf2_size + 16, 0, KM_SLEEP))) {
8473 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8474 		    "%s: Unable to allocate pkt.", emlxs_dfc_xlate(dfc->cmd));
8475 
8476 		rval = DFC_SYSRES_ERROR;
8477 		goto done;
8478 	}
8479 
8480 	CtCmd = (SLI_CT_REQUEST*)pkt->pkt_cmd;
8481 	CtRsp = SLI_CT_LOOPBACK;
8482 	CtCmd->CommandResponse.bits.CmdRsp = SWAP_DATA16(CtRsp);
8483 
8484 	if (ddi_copyin((void *)dfc->buf1, (void *)&CtCmd->un.data,
8485 	    dfc->buf1_size, mode) != 0) {
8486 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8487 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8488 
8489 		rval = DFC_COPYIN_ERROR;
8490 		goto done;
8491 	}
8492 
8493 	pkt->pkt_tran_type = FC_PKT_OUTBOUND;
8494 	pkt->pkt_timeout = 2 * hba->fc_ratov;
8495 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
8496 	pkt->pkt_comp = NULL;
8497 
8498 	pkt->pkt_cmd_fhdr.d_id = port->did;
8499 	pkt->pkt_cmd_fhdr.r_ctl = FC_SOL_CTL;
8500 	pkt->pkt_cmd_fhdr.s_id = port->did;
8501 	pkt->pkt_cmd_fhdr.type = FC_CT_TYPE;
8502 	pkt->pkt_cmd_fhdr.f_ctl = 0;
8503 	pkt->pkt_cmd_fhdr.seq_id = 0;
8504 	pkt->pkt_cmd_fhdr.df_ctl = 0;
8505 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
8506 	pkt->pkt_cmd_fhdr.ox_id = 0xffff;
8507 	pkt->pkt_cmd_fhdr.rx_id = ndlp->nlp_Xri;
8508 	pkt->pkt_cmd_fhdr.ro = 0;
8509 
8510 	mutex_enter(&EMLXS_PKT_LOCK);
8511 	timeout = emlxs_timeout(hba, (pkt->pkt_timeout + 15));
8512 
8513 	if (hba->loopback_pkt) {
8514 		rval = 0;
8515 		while ((rval != -1) && hba->loopback_pkt) {
8516 			rval =
8517 			    cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK,
8518 			    timeout);
8519 		}
8520 
8521 		if (rval == -1) {
8522 			mutex_exit(&EMLXS_PKT_LOCK);
8523 
8524 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8525 			    "Loopback busy timeout.");
8526 			rval = DFC_TIMEOUT;
8527 			goto done;
8528 		}
8529 	}
8530 	hba->loopback_pkt = (void *) pkt;
8531 	mutex_exit(&EMLXS_PKT_LOCK);
8532 
8533 	/* Send polled command */
8534 	if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) {
8535 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8536 		    "Pkt Transport error. ret=%x state=%x", rval,
8537 		    pkt->pkt_state);
8538 
8539 		rval = DFC_IO_ERROR;
8540 		goto done;
8541 	}
8542 
8543 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
8544 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
8545 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8546 			    "Pkt Transport error. Pkt Timeout.");
8547 			rval = DFC_TIMEOUT;
8548 		} else {
8549 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8550 			    "Pkt Transport error. state=%x", pkt->pkt_state);
8551 			rval = DFC_IO_ERROR;
8552 		}
8553 		goto done;
8554 	}
8555 
8556 	/* Wait for sequence completion */
8557 	mutex_enter(&EMLXS_PKT_LOCK);
8558 	rval = 0;
8559 	while ((rval != -1) && !(pkt->pkt_tran_flags & FC_TRAN_COMPLETED)) {
8560 		rval = cv_timedwait(&EMLXS_PKT_CV, &EMLXS_PKT_LOCK, timeout);
8561 	}
8562 	mutex_exit(&EMLXS_PKT_LOCK);
8563 
8564 	if (rval == -1) {
8565 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8566 		    "Loopback sequence timeout.");
8567 
8568 		rval = DFC_TIMEOUT;
8569 		goto done;
8570 	}
8571 
8572 	CtCmd = (SLI_CT_REQUEST*)pkt->pkt_resp;
8573 
8574 	if (ddi_copyout((void *)&CtCmd->un.data, (void *)dfc->buf2,
8575 	    dfc->buf2_size, mode) != 0) {
8576 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8577 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
8578 
8579 		rval = DFC_COPYOUT_ERROR;
8580 		goto done;
8581 	}
8582 
8583 	rval = 0;
8584 
8585 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg, "%s: Test completed.",
8586 	    emlxs_dfc_xlate(dfc->cmd));
8587 
8588 done:
8589 
8590 	if (rval) {
8591 		mutex_enter(&EMLXS_PKT_LOCK);
8592 		if (pkt && (hba->loopback_pkt == pkt)) {
8593 			hba->loopback_pkt = NULL;
8594 		}
8595 		mutex_exit(&EMLXS_PKT_LOCK);
8596 
8597 		/* Reset the adapter */
8598 		(void) emlxs_reset(port, FC_FCA_LINK_RESET);
8599 	}
8600 
8601 	if (pkt) {
8602 		emlxs_pkt_free(pkt);
8603 	}
8604 
8605 	return (rval);
8606 
8607 } /* emlxs_dfc_loopback_test() */
8608 
8609 
8610 extern int32_t
8611 emlxs_dfc_handle_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq)
8612 {
8613 	emlxs_port_t	*port = &PPORT;
8614 	IOCB		*cmd;
8615 	emlxs_buf_t	*sbp;
8616 
8617 	cmd = &iocbq->iocb;
8618 
8619 	HBASTATS.CtEvent++;
8620 
8621 	sbp = (emlxs_buf_t *)iocbq->sbp;
8622 
8623 	if (!sbp) {
8624 		HBASTATS.CtStray++;
8625 
8626 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8627 		    "Stray interrupt. cmd=0x%x iotag=0x%x status=0x%x "
8628 		    "perr=0x%x", (uint32_t)cmd->ulpCommand,
8629 		    (uint32_t)cmd->ulpIoTag, cmd->ulpStatus,
8630 		    cmd->un.ulpWord[4]);
8631 
8632 		return (DFC_ARG_INVALID);
8633 	}
8634 
8635 	if (rp->ringno != FC_CT_RING) {
8636 		HBASTATS.CtStray++;
8637 
8638 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8639 		    "CT Event: Invalid ring: ring=%d iocbq=%p", rp->ringno,
8640 		    iocbq);
8641 
8642 		return (DFC_ARG_INVALID);
8643 	}
8644 
8645 	switch (cmd->ulpCommand) {
8646 	case CMD_XMIT_SEQUENCE_CR:
8647 	case CMD_XMIT_SEQUENCE64_CR:
8648 	case CMD_XMIT_SEQUENCE_CX:
8649 	case CMD_XMIT_SEQUENCE64_CX:
8650 
8651 		HBASTATS.CtCmdCompleted++;
8652 
8653 		if (cmd->ulpStatus == 0) {
8654 			HBASTATS.CtCmdGood++;
8655 
8656 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
8657 			    "XMIT_SEQUENCE comp: status=0x%x",
8658 			    cmd->ulpStatus);
8659 		} else {
8660 			HBASTATS.CtCmdError++;
8661 
8662 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8663 			    "XMIT_SEQUENCE comp: status=0x%x [%08x,%08x]",
8664 			    cmd->ulpStatus, cmd->un.ulpWord[4],
8665 			    cmd->un.ulpWord[5]);
8666 		}
8667 
8668 		emlxs_pkt_complete(sbp, cmd->ulpStatus,
8669 		    cmd->un.grsp.perr.statLocalError, 1);
8670 
8671 		break;
8672 
8673 	default:
8674 
8675 		HBASTATS.CtStray++;
8676 
8677 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8678 		    "Invalid iocb: cmd=0x%x", cmd->ulpCommand);
8679 
8680 		emlxs_pkt_complete(sbp, cmd->ulpStatus,
8681 		    cmd->un.grsp.perr.statLocalError, 1);
8682 
8683 		break;
8684 
8685 	}	/* switch(cmd->ulpCommand) */
8686 
8687 	return (0);
8688 
8689 } /* emlxs_dfc_handle_event() */
8690 
8691 
8692 /* ARGSUSED */
8693 extern int
8694 emlxs_dfc_handle_unsol_req(emlxs_port_t *port, RING *rp, IOCBQ *iocbq,
8695     MATCHMAP *mp, uint32_t size)
8696 {
8697 	emlxs_hba_t	*hba = HBA;
8698 	IOCB		*iocb;
8699 	uint8_t		*bp;
8700 	fc_packet_t	*pkt;
8701 
8702 	iocb = &iocbq->iocb;
8703 	bp = (uint8_t *)mp->virt;
8704 
8705 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg,
8706 	    "CT Receive: cmd=%x status=0x%x ",
8707 	    iocb->ulpCommand, iocb->ulpStatus);
8708 
8709 	/*
8710 	 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_debug_msg,
8711 	 * "CT Receive: payload=%p size=%d [%02x,%02x, %02x, %02x]", bp,
8712 	 * size, bp[0], bp[1], bp[2],bp[3]);
8713 	 */
8714 
8715 	/* Return payload */
8716 	mutex_enter(&EMLXS_PKT_LOCK);
8717 	if (hba->loopback_pkt) {
8718 		pkt = (fc_packet_t *)hba->loopback_pkt;
8719 		hba->loopback_pkt = NULL;
8720 
8721 		size = MIN(size, pkt->pkt_rsplen);
8722 		bcopy(bp, pkt->pkt_resp, size);
8723 		pkt->pkt_tran_flags |= FC_TRAN_COMPLETED;
8724 
8725 		cv_broadcast(&EMLXS_PKT_CV);
8726 	}
8727 	mutex_exit(&EMLXS_PKT_LOCK);
8728 
8729 	return (0);
8730 
8731 } /* emlxs_dfc_handle_unsol_req() */
8732 
8733 
8734 #ifdef DHCHAP_SUPPORT
8735 
8736 static int32_t
8737 emlxs_dfc_init_auth(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8738 {
8739 	emlxs_port_t	*port = &PPORT;
8740 	uint8_t		lwwpn[8];
8741 	uint8_t		rwwpn[8];
8742 	int32_t		rval = 0;
8743 
8744 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
8745 	    emlxs_dfc_xlate(dfc->cmd));
8746 
8747 	if (!dfc->buf1 || !dfc->buf1_size) {
8748 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8749 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8750 
8751 		return (DFC_ARG_NULL);
8752 	}
8753 
8754 	if (dfc->buf1_size < 8) {
8755 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8756 		    "%s: Buffer1 too small. (size=%d)",
8757 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8758 
8759 		return (DFC_ARG_TOOSMALL);
8760 	}
8761 
8762 	if (!dfc->buf2 || !dfc->buf2_size) {
8763 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8764 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8765 
8766 		return (DFC_ARG_NULL);
8767 	}
8768 
8769 	if (dfc->buf2_size < 8) {
8770 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8771 		    "%s: Buffer2 too small. (size=%d)",
8772 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8773 
8774 		return (DFC_ARG_TOOSMALL);
8775 	}
8776 
8777 	/* Read the lwwpn */
8778 	if (ddi_copyin((void *)dfc->buf1, (void *)&lwwpn, 8, mode) != 0) {
8779 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8780 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8781 
8782 		return (DFC_COPYIN_ERROR);
8783 	}
8784 
8785 	/* Read the rwwpn */
8786 	if (ddi_copyin((void *)dfc->buf2, (void *)&rwwpn, 8, mode) != 0) {
8787 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8788 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8789 
8790 		return (DFC_COPYIN_ERROR);
8791 	}
8792 
8793 	/* Initiate authentication here */
8794 	rval = emlxs_dhc_init_auth(hba, lwwpn, rwwpn);
8795 
8796 	return (rval);
8797 
8798 } /* emlxs_dfc_init_auth() */
8799 
8800 
8801 static int32_t
8802 emlxs_dfc_get_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8803 {
8804 	emlxs_port_t		*port = &PPORT;
8805 	dfc_fcsp_config_t	fcsp_config;
8806 	uint32_t		rval = DFC_SUCCESS;
8807 
8808 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
8809 	    emlxs_dfc_xlate(dfc->cmd));
8810 
8811 	if (!dfc->buf1 || !dfc->buf1_size) {
8812 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8813 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8814 
8815 		return (DFC_ARG_NULL);
8816 	}
8817 
8818 	if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) {
8819 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8820 		    "%s: Buffer1 too small. (size=%d)",
8821 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8822 
8823 		return (DFC_ARG_TOOSMALL);
8824 	}
8825 
8826 	/* Read the fcsp_config */
8827 	if (ddi_copyin((void *)dfc->buf1, (void *)&fcsp_config,
8828 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
8829 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8830 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8831 
8832 		return (DFC_COPYIN_ERROR);
8833 	}
8834 
8835 	if ((rval = emlxs_dhc_get_auth_cfg(hba, &fcsp_config)) != 0) {
8836 		return (rval);
8837 	}
8838 
8839 	if (ddi_copyout((void *)&fcsp_config, (void *)dfc->buf1,
8840 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
8841 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8842 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
8843 
8844 		return (DFC_COPYOUT_ERROR);
8845 	}
8846 
8847 	return (0);
8848 
8849 } /* emlxs_dfc_get_auth_cfg() */
8850 
8851 
8852 
8853 static int32_t
8854 emlxs_dfc_set_auth_cfg(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8855 {
8856 	emlxs_port_t		*port = &PPORT;
8857 	dfc_fcsp_config_t	fcsp_config;
8858 	dfc_password_t		dfc_pwd;
8859 	uint32_t		rval = DFC_SUCCESS;
8860 
8861 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
8862 	    emlxs_dfc_xlate(dfc->cmd));
8863 
8864 	if (!dfc->buf1 || !dfc->buf1_size) {
8865 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8866 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8867 
8868 		return (DFC_ARG_NULL);
8869 	}
8870 
8871 	if (dfc->buf1_size < sizeof (dfc_fcsp_config_t)) {
8872 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8873 		    "%s: Buffer1 too small. (size=%d)",
8874 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8875 
8876 		return (DFC_ARG_TOOSMALL);
8877 	}
8878 
8879 	if (!dfc->buf2 || !dfc->buf2_size) {
8880 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8881 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
8882 
8883 		return (DFC_ARG_NULL);
8884 	}
8885 
8886 	if (dfc->buf2_size < sizeof (dfc_password_t)) {
8887 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8888 		    "%s: Buffer2 too small. (size=%d)",
8889 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8890 
8891 		return (DFC_ARG_TOOSMALL);
8892 	}
8893 
8894 	/* Read the fcsp_config */
8895 	if (ddi_copyin((void *)dfc->buf1, (void *)&fcsp_config,
8896 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
8897 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8898 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8899 
8900 		return (DFC_COPYIN_ERROR);
8901 	}
8902 
8903 	/* Read the password */
8904 	if (ddi_copyin((void *)dfc->buf2, (void *)&dfc_pwd,
8905 	    sizeof (dfc_password_t), mode) != 0) {
8906 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8907 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8908 
8909 		return (DFC_COPYIN_ERROR);
8910 	}
8911 
8912 	switch (dfc->flag) {
8913 	case EMLXS_AUTH_CFG_ADD:
8914 		rval = emlxs_dhc_add_auth_cfg(hba, &fcsp_config, &dfc_pwd);
8915 		break;
8916 
8917 	case EMLXS_AUTH_CFG_DELETE:
8918 		rval = emlxs_dhc_delete_auth_cfg(hba, &fcsp_config, &dfc_pwd);
8919 		break;
8920 	}
8921 
8922 	if (rval) {
8923 		return (rval);
8924 	}
8925 
8926 	if (ddi_copyout((void *)&fcsp_config, (void *)dfc->buf1,
8927 	    sizeof (dfc_fcsp_config_t), mode) != 0) {
8928 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8929 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
8930 
8931 		return (DFC_COPYOUT_ERROR);
8932 	}
8933 
8934 	return (0);
8935 
8936 } /* emlxs_dfc_set_auth_cfg() */
8937 
8938 
8939 
8940 static int32_t
8941 emlxs_dfc_get_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8942 {
8943 	emlxs_port_t		*port = &PPORT;
8944 	dfc_auth_password_t	dfc_pwd;
8945 	uint32_t		rval = DFC_SUCCESS;
8946 
8947 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
8948 	    emlxs_dfc_xlate(dfc->cmd));
8949 
8950 	if (!dfc->buf1 || !dfc->buf1_size) {
8951 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8952 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
8953 
8954 		return (DFC_ARG_NULL);
8955 	}
8956 
8957 	if (dfc->buf1_size < sizeof (dfc_auth_password_t)) {
8958 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8959 		    "%s: Buffer1 too small. (size=%d)",
8960 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
8961 
8962 		return (DFC_ARG_TOOSMALL);
8963 	}
8964 
8965 
8966 	/* Read the auth password */
8967 	if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_pwd,
8968 	    sizeof (dfc_auth_password_t), mode) != 0) {
8969 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8970 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
8971 
8972 		return (DFC_COPYIN_ERROR);
8973 	}
8974 
8975 	if ((rval = emlxs_dhc_get_auth_key(hba, &dfc_pwd)) != 0) {
8976 		return (rval);
8977 	}
8978 
8979 	if (ddi_copyout((void *)&dfc_pwd, (void *)dfc->buf1,
8980 	    sizeof (dfc_auth_password_t), mode) != 0) {
8981 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
8982 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
8983 
8984 		return (DFC_COPYOUT_ERROR);
8985 	}
8986 
8987 	return (0);
8988 
8989 } /* emlxs_dfc_get_auth_pwd() */
8990 
8991 
8992 static int32_t
8993 emlxs_dfc_set_auth_pwd(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
8994 {
8995 	emlxs_port_t		*port = &PPORT;
8996 	dfc_auth_password_t	dfc_pwd;
8997 	uint32_t		rval = DFC_SUCCESS;
8998 
8999 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9000 	    emlxs_dfc_xlate(dfc->cmd));
9001 
9002 	if (!dfc->buf1 || !dfc->buf1_size) {
9003 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9004 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9005 
9006 		return (DFC_ARG_NULL);
9007 	}
9008 
9009 	if (dfc->buf1_size < sizeof (dfc_auth_password_t)) {
9010 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9011 		    "%s: Buffer1 too small. (size=%d)",
9012 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9013 
9014 		return (DFC_ARG_TOOSMALL);
9015 	}
9016 
9017 	/* Read the auth password */
9018 	if (ddi_copyin((void *)dfc->buf1, (void *)&dfc_pwd,
9019 	    sizeof (dfc_auth_password_t), mode) != 0) {
9020 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9021 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9022 
9023 		return (DFC_COPYIN_ERROR);
9024 	}
9025 
9026 	if ((rval = emlxs_dhc_set_auth_key(hba, &dfc_pwd))) {
9027 		return (rval);
9028 	}
9029 
9030 	if (ddi_copyout((void *)&dfc_pwd, (void *)dfc->buf1,
9031 	    sizeof (dfc_auth_password_t), mode) != 0) {
9032 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9033 		    "%s: ddi_copyout failed.", emlxs_dfc_xlate(dfc->cmd));
9034 
9035 		return (DFC_COPYOUT_ERROR);
9036 	}
9037 
9038 	return (0);
9039 
9040 } /* emlxs_dfc_set_auth_pwd() */
9041 
9042 
9043 static int32_t
9044 emlxs_dfc_get_auth_status(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9045 {
9046 	emlxs_port_t		*port = &PPORT;
9047 	dfc_auth_status_t	fcsp_status;
9048 	uint32_t		rval = DFC_SUCCESS;
9049 
9050 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9051 	    emlxs_dfc_xlate(dfc->cmd));
9052 
9053 	if (!dfc->buf1 || !dfc->buf1_size) {
9054 		EMLXS_MSGF(EMLXS_CONTEXT,
9055 		    &emlxs_dfc_error_msg, "%s: Null buffer1 found.",
9056 		    emlxs_dfc_xlate(dfc->cmd));
9057 
9058 		return (DFC_ARG_NULL);
9059 	}
9060 
9061 	if (dfc->buf1_size < sizeof (dfc_auth_status_t)) {
9062 		EMLXS_MSGF(EMLXS_CONTEXT,
9063 		    &emlxs_dfc_error_msg, "%s: Buffer too small. (size=%d)",
9064 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf1_size);
9065 
9066 		return (DFC_ARG_TOOSMALL);
9067 	}
9068 
9069 	/* Read the fcsp_config */
9070 	if (ddi_copyin((void *) dfc->buf1, (void *) &fcsp_status,
9071 	    sizeof (dfc_auth_status_t), mode) != 0) {
9072 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9073 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9074 
9075 		return (DFC_COPYIN_ERROR);
9076 	}
9077 
9078 	if ((rval = emlxs_dhc_get_auth_status(hba, &fcsp_status)) != 0) {
9079 		return (rval);
9080 	}
9081 
9082 	if (ddi_copyout((void *) &fcsp_status, (void *) dfc->buf1,
9083 	    sizeof (dfc_auth_status_t), mode) != 0) {
9084 		EMLXS_MSGF(EMLXS_CONTEXT,
9085 		    &emlxs_dfc_error_msg, "%s: ddi_copyout failed.",
9086 		    emlxs_dfc_xlate(dfc->cmd));
9087 
9088 		return (DFC_COPYOUT_ERROR);
9089 	}
9090 
9091 	return (0);
9092 
9093 } /* emlxs_dfc_get_auth_status() */
9094 
9095 
9096 static int32_t
9097 emlxs_dfc_get_auth_cfg_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9098 {
9099 	emlxs_port_t		*port = &PPORT;
9100 	dfc_fcsp_config_t	*fcsp_cfg;
9101 	uint32_t		count;
9102 	uint32_t		size;
9103 	uint32_t		rval = DFC_SUCCESS;
9104 
9105 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9106 	    emlxs_dfc_xlate(dfc->cmd));
9107 
9108 	/* Lock cfg table while we do this */
9109 	/* This prevents the table from changing while we get a copy */
9110 	mutex_enter(&hba->auth_lock);
9111 
9112 	if (!dfc->buf2 || !dfc->buf2_size) {
9113 		EMLXS_MSGF(EMLXS_CONTEXT,
9114 		    &emlxs_dfc_error_msg, "%s: Null buffer2 found.",
9115 		    emlxs_dfc_xlate(dfc->cmd));
9116 
9117 		mutex_exit(&hba->auth_lock);
9118 		return (DFC_ARG_NULL);
9119 	}
9120 
9121 	if (dfc->buf2_size < sizeof (uint32_t)) {
9122 		EMLXS_MSGF(EMLXS_CONTEXT,
9123 		    &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)",
9124 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
9125 
9126 		mutex_exit(&hba->auth_lock);
9127 		return (DFC_ARG_TOOSMALL);
9128 	}
9129 
9130 	if (ddi_copyout((void *)&hba->auth_cfg_count, (void *)dfc->buf2,
9131 	    sizeof (uint32_t), mode) != 0) {
9132 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9133 		    "%s: ddi_copyout failed for table count. count=%d",
9134 		    emlxs_dfc_xlate(dfc->cmd), hba->auth_cfg_count);
9135 
9136 		mutex_exit(&hba->auth_lock);
9137 		return (DFC_COPYOUT_ERROR);
9138 	}
9139 
9140 	if (!dfc->buf1 || !dfc->buf1_size) {
9141 		mutex_exit(&hba->auth_lock);
9142 		return (DFC_SUCCESS);
9143 	}
9144 
9145 	/* Check table size */
9146 	count = dfc->buf1_size / sizeof (dfc_fcsp_config_t);
9147 	if (count < hba->auth_cfg_count) {
9148 		EMLXS_MSGF(EMLXS_CONTEXT,
9149 		    &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)",
9150 		    emlxs_dfc_xlate(dfc->cmd), count, hba->auth_cfg_count);
9151 
9152 		mutex_exit(&hba->auth_lock);
9153 		return (DFC_ARG_TOOSMALL);
9154 	}
9155 
9156 	size = hba->auth_cfg_count * sizeof (dfc_fcsp_config_t);
9157 	if (!(fcsp_cfg = (dfc_fcsp_config_t *)kmem_zalloc(size, KM_SLEEP))) {
9158 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9159 		    "%s: Unable to allocate table buffer.",
9160 		    emlxs_dfc_xlate(dfc->cmd));
9161 
9162 		mutex_exit(&hba->auth_lock);
9163 		return (DFC_SYSRES_ERROR);
9164 	}
9165 
9166 	if ((rval = emlxs_dhc_get_auth_cfg_table(hba, fcsp_cfg)) != 0) {
9167 		mutex_exit(&hba->auth_lock);
9168 		kmem_free(fcsp_cfg, size);
9169 		return (rval);
9170 	}
9171 
9172 	mutex_exit(&hba->auth_lock);
9173 
9174 	if (ddi_copyout((void *)fcsp_cfg, (void *)dfc->buf1, size, mode) != 0) {
9175 		EMLXS_MSGF(EMLXS_CONTEXT,
9176 		    &emlxs_dfc_error_msg, "%s: ddi_copyout failed.",
9177 		    emlxs_dfc_xlate(dfc->cmd));
9178 
9179 		kmem_free(fcsp_cfg, size);
9180 		return (DFC_COPYOUT_ERROR);
9181 	}
9182 
9183 	kmem_free(fcsp_cfg, size);
9184 	return (0);
9185 
9186 } /* emlxs_dfc_get_auth_cfg_table() */
9187 
9188 
9189 static int32_t
9190 emlxs_dfc_get_auth_key_table(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9191 {
9192 	emlxs_port_t		*port = &PPORT;
9193 	dfc_auth_password_t	*auth_pwd;
9194 	uint32_t		count;
9195 	uint32_t		size;
9196 	uint32_t		rval = DFC_SUCCESS;
9197 
9198 	EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_detail_msg, "%s requested.",
9199 	    emlxs_dfc_xlate(dfc->cmd));
9200 
9201 	/* Lock cfg table while we do this */
9202 	/* This prevents the table from changing while we get a copy */
9203 	mutex_enter(&hba->auth_lock);
9204 
9205 	if (!dfc->buf2 || !dfc->buf2_size) {
9206 		EMLXS_MSGF(EMLXS_CONTEXT,
9207 		    &emlxs_dfc_error_msg, "%s: Null buffer2 found.",
9208 		    emlxs_dfc_xlate(dfc->cmd));
9209 
9210 		mutex_exit(&hba->auth_lock);
9211 		return (DFC_ARG_NULL);
9212 	}
9213 
9214 	if (dfc->buf2_size < sizeof (uint32_t)) {
9215 		EMLXS_MSGF(EMLXS_CONTEXT,
9216 		    &emlxs_dfc_error_msg, "%s: Buffer2 too small. (size=%d)",
9217 		    emlxs_dfc_xlate(dfc->cmd), dfc->buf2_size);
9218 
9219 		mutex_exit(&hba->auth_lock);
9220 		return (DFC_ARG_TOOSMALL);
9221 	}
9222 
9223 	if (ddi_copyout((void *)&hba->auth_key_count, (void *)dfc->buf2,
9224 	    sizeof (uint32_t), mode) != 0) {
9225 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9226 		    "%s: ddi_copyout failed for table count. count=%d",
9227 		    emlxs_dfc_xlate(dfc->cmd), hba->auth_key_count);
9228 
9229 		mutex_exit(&hba->auth_lock);
9230 		return (DFC_COPYOUT_ERROR);
9231 	}
9232 
9233 	if (!dfc->buf1 || !dfc->buf1_size) {
9234 		mutex_exit(&hba->auth_lock);
9235 		return (DFC_SUCCESS);
9236 	}
9237 
9238 	/* Check table size */
9239 	count = dfc->buf1_size / sizeof (dfc_auth_password_t);
9240 	if (count < hba->auth_key_count) {
9241 		EMLXS_MSGF(EMLXS_CONTEXT,
9242 		    &emlxs_dfc_error_msg, "%s: Buffer1 too small. (%d < %d)",
9243 		    emlxs_dfc_xlate(dfc->cmd), count, hba->auth_key_count);
9244 
9245 		mutex_exit(&hba->auth_lock);
9246 		return (DFC_ARG_TOOSMALL);
9247 	}
9248 
9249 	size = hba->auth_key_count * sizeof (dfc_auth_password_t);
9250 	if (!(auth_pwd = (dfc_auth_password_t *)kmem_zalloc(size, KM_SLEEP))) {
9251 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9252 		    "%s: Unable to allocate table buffer.",
9253 		    emlxs_dfc_xlate(dfc->cmd));
9254 
9255 		mutex_exit(&hba->auth_lock);
9256 		return (DFC_SYSRES_ERROR);
9257 	}
9258 
9259 	if ((rval = emlxs_dhc_get_auth_key_table(hba, auth_pwd)) != 0) {
9260 		mutex_exit(&hba->auth_lock);
9261 		kmem_free(auth_pwd, size);
9262 		return (rval);
9263 	}
9264 
9265 	mutex_exit(&hba->auth_lock);
9266 
9267 	if (ddi_copyout((void *)auth_pwd, (void *)dfc->buf1, size, mode) != 0) {
9268 		EMLXS_MSGF(EMLXS_CONTEXT,
9269 		    &emlxs_dfc_error_msg, "%s: ddi_copyout failed.",
9270 		    emlxs_dfc_xlate(dfc->cmd));
9271 
9272 		kmem_free(auth_pwd, size);
9273 		return (DFC_COPYOUT_ERROR);
9274 	}
9275 
9276 	kmem_free(auth_pwd, size);
9277 	return (0);
9278 
9279 } /* emlxs_dfc_get_auth_key_table() */
9280 
9281 
9282 
9283 #endif	/* DHCHAP_SUPPORT */
9284 
9285 #ifdef SAN_DIAG_SUPPORT
9286 static int32_t
9287 emlxs_dfc_sd_set_bucket(dfc_t *dfc, int32_t mode)
9288 {
9289 	uint32_t	type, search_type;
9290 	uint16_t	state;
9291 	int32_t		rval = DFC_SD_OK;
9292 
9293 	type = dfc->data1;
9294 	search_type = dfc->data2;
9295 
9296 	mutex_enter(&sd_bucket_mutex);
9297 	state = sd_bucket.state;
9298 	mutex_exit(&sd_bucket_mutex);
9299 
9300 	if (state == SD_COLLECTING)
9301 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9302 	else if ((search_type < SD_SEARCH_LINEAR) ||
9303 	    (search_type > SD_SEARCH_POWER_2))
9304 		rval = DFC_SD_ERROR_INVALID_ARG;
9305 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9306 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9307 	else {
9308 		(void) ddi_copyin(dfc->buf3, (void *) &sd_bucket,
9309 		    sizeof (sd_bucket_info_t), mode);
9310 		mutex_enter(&sd_bucket_mutex);
9311 		sd_bucket.state = SD_STOPPED;
9312 		mutex_exit(&sd_bucket_mutex);
9313 	}
9314 
9315 set_bucket_exit:
9316 	return (rval);
9317 }
9318 
9319 
9320 static int32_t
9321 emlxs_dfc_sd_destroy_bucket(dfc_t *dfc)
9322 {
9323 	uint32_t	type;
9324 	int32_t 	rval = DFC_SD_OK;
9325 
9326 	type = dfc->data1;
9327 
9328 	mutex_enter(&sd_bucket_mutex);
9329 
9330 	if (sd_bucket.search_type == 0)
9331 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9332 	else if (sd_bucket.state == SD_COLLECTING)
9333 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9334 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9335 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9336 	else
9337 		bzero((uint8_t *)&sd_bucket, sizeof (sd_bucket_info_t));
9338 
9339 destroy_bucket_exit:
9340 	mutex_exit(&sd_bucket_mutex);
9341 	return (rval);
9342 }
9343 
9344 
9345 static int32_t
9346 emlxs_dfc_sd_get_bucket(dfc_t *dfc, int32_t mode)
9347 {
9348 	uint32_t	type;
9349 	int32_t		rval = DFC_SD_OK;
9350 
9351 	type = dfc->data1;
9352 
9353 	if (sd_bucket.search_type == 0)
9354 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9355 	else if (type != SD_SCSI_IO_LATENCY_TYPE)
9356 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9357 	else
9358 		(void) ddi_copyout(&sd_bucket, dfc->buf3,
9359 		    sizeof (sd_bucket_info_t), mode);
9360 
9361 	return (rval);
9362 }
9363 
9364 
9365 static int32_t
9366 emlxs_dfc_sd_start_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9367 {
9368 	emlxs_port_t	*vport;
9369 	NODELIST	*nlp;
9370 	uint8_t		wwpn[8];
9371 	int32_t		rval = DFC_SD_OK;
9372 	int		i;
9373 
9374 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9375 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9376 		goto start_collect_exit;
9377 	}
9378 
9379 	if (sd_bucket.search_type == 0) {
9380 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9381 		goto start_collect_exit;
9382 	}
9383 
9384 	/* Read the wwn object */
9385 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9386 
9387 	/* Make sure WWPN is unique */
9388 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9389 
9390 	if (!vport) {
9391 		rval = DFC_SD_ERROR_INVALID_PORT;
9392 		goto start_collect_exit;
9393 	}
9394 
9395 	/* traverse list of nodes for this vport and reset counter */
9396 	rw_enter(&vport->node_rwlock, RW_READER);
9397 	if (vport->sd_io_latency_state == SD_COLLECTING) {
9398 		rval = DFC_SD_ERROR_DATA_COLLECTION_ACTIVE;
9399 		rw_exit(&vport->node_rwlock);
9400 		goto start_collect_exit;
9401 	}
9402 
9403 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9404 		nlp = vport->node_table[i];
9405 		while (nlp != NULL) {
9406 			bzero((void *)&nlp->sd_dev_bucket[0],
9407 			    sizeof (struct SD_time_stats_v0) *
9408 			    SD_IO_LATENCY_MAX_BUCKETS);
9409 
9410 			nlp = nlp->nlp_list_next;
9411 		}
9412 	}
9413 
9414 	vport->sd_io_latency_state = SD_COLLECTING;
9415 	rw_exit(&vport->node_rwlock);
9416 
9417 	mutex_enter(&sd_bucket_mutex);
9418 	sd_bucket.state = SD_COLLECTING;
9419 	mutex_exit(&sd_bucket_mutex);
9420 
9421 start_collect_exit:
9422 	return (rval);
9423 }
9424 
9425 
9426 static int32_t
9427 emlxs_dfc_sd_stop_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9428 {
9429 	emlxs_port_t	*vport;
9430 	emlxs_hba_t	*temp_hba;
9431 	uint8_t		wwpn[8];
9432 	int32_t		rval = DFC_SD_OK;
9433 	int		i, j;
9434 
9435 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9436 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9437 		goto stop_collect_exit;
9438 	}
9439 
9440 	if (sd_bucket.search_type == 0) {
9441 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9442 		goto stop_collect_exit;
9443 	}
9444 
9445 	/* Read the wwn object */
9446 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9447 
9448 	/* Make sure WWPN is unique */
9449 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9450 
9451 	if (!vport) {
9452 		rval = DFC_SD_ERROR_INVALID_PORT;
9453 		goto stop_collect_exit;
9454 	}
9455 
9456 	rw_enter(&vport->node_rwlock, RW_READER);
9457 	if (vport->sd_io_latency_state != SD_COLLECTING) {
9458 		rval = DFC_SD_ERROR_DATA_COLLECTION_NOT_ACTIVE;
9459 		rw_exit(&vport->node_rwlock);
9460 		goto stop_collect_exit;
9461 	}
9462 	vport->sd_io_latency_state = SD_STOPPED;
9463 	rw_exit(&vport->node_rwlock);
9464 
9465 	/* see if any other port is collecting io latency */
9466 	for (i = 0; i < emlxs_device.hba_count; i++) {
9467 		temp_hba = emlxs_device.hba[i];
9468 		for (j = 0; j < temp_hba->num_of_ports; j++) {
9469 			vport = &temp_hba->port[j];
9470 			if (vport->sd_io_latency_state == SD_COLLECTING)
9471 				goto stop_collect_exit;
9472 		}
9473 	}
9474 
9475 	/*
9476 	 * if we get here, that means no one else is collecting
9477 	 * io latency data.
9478 	 */
9479 	mutex_enter(&sd_bucket_mutex);
9480 	sd_bucket.state = SD_STOPPED;
9481 	mutex_exit(&sd_bucket_mutex);
9482 
9483 stop_collect_exit:
9484 	return (rval);
9485 }
9486 
9487 
9488 static int32_t
9489 emlxs_dfc_sd_reset_collection(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9490 {
9491 	emlxs_port_t   *vport;
9492 	NODELIST	*nlp;
9493 	uint8_t		wwpn[8];
9494 	int32_t 	rval = DFC_SD_OK;
9495 	int		i;
9496 
9497 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9498 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9499 		goto reset_collect_exit;
9500 	}
9501 
9502 	if (sd_bucket.search_type == 0) {
9503 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9504 		goto reset_collect_exit;
9505 	}
9506 
9507 	/* Read the wwn object */
9508 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9509 
9510 	/* Make sure WWPN is unique */
9511 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9512 
9513 	if (!vport) {
9514 		rval = DFC_SD_ERROR_INVALID_PORT;
9515 		goto reset_collect_exit;
9516 	}
9517 
9518 	/* traverse list of nodes for this vport and reset counter */
9519 	rw_enter(&vport->node_rwlock, RW_READER);
9520 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9521 		nlp = vport->node_table[i];
9522 		while (nlp != NULL) {
9523 			bzero((void *)&nlp->sd_dev_bucket[0],
9524 			    sizeof (struct SD_time_stats_v0) *
9525 			    SD_IO_LATENCY_MAX_BUCKETS);
9526 
9527 			nlp = nlp->nlp_list_next;
9528 		}
9529 	}
9530 	rw_exit(&vport->node_rwlock);
9531 
9532 reset_collect_exit:
9533 	return (rval);
9534 }
9535 
9536 
9537 static int32_t
9538 emlxs_dfc_sd_get_data(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9539 {
9540 	emlxs_port_t   *vport;
9541 	uint8_t		wwpn[8];
9542 	int		i, skip_bytes;
9543 	uint16_t	count;
9544 	uint32_t	bufsize, size_needed;
9545 	NODELIST	*nlp;
9546 	int32_t 	rval = DFC_SD_OK;
9547 
9548 	if (dfc->data1 != SD_SCSI_IO_LATENCY_TYPE) {
9549 		rval = DFC_SD_ERROR_NOT_SUPPORTED;
9550 		goto get_data_exit;
9551 	}
9552 
9553 	if (sd_bucket.search_type == 0) {
9554 		rval = DFC_SD_ERROR_BUCKET_NOT_SET;
9555 		goto get_data_exit;
9556 	}
9557 
9558 	/* Read the wwn object */
9559 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9560 
9561 	/* Make sure WWPN is unique */
9562 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9563 
9564 	if (!vport) {
9565 		rval = DFC_SD_ERROR_INVALID_PORT;
9566 		goto get_data_exit;
9567 	}
9568 
9569 	bufsize = dfc->buf4_size;
9570 
9571 	/*
9572 	 * count # of targets to see if buffer is big enough
9573 	 */
9574 	count = 0;
9575 	rw_enter(&vport->node_rwlock, RW_READER);
9576 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9577 		nlp = vport->node_table[i];
9578 		while (nlp != NULL) {
9579 			count++;
9580 			nlp = nlp->nlp_list_next;
9581 		}
9582 	}
9583 	rw_exit(&vport->node_rwlock);
9584 
9585 	size_needed = count * (sizeof (HBA_WWN) +
9586 	    sizeof (struct SD_time_stats_v0) * SD_IO_LATENCY_MAX_BUCKETS);
9587 
9588 	if (bufsize < size_needed) {
9589 		rval = DFC_SD_ERROR_MORE_DATA_AVAIL;
9590 		goto update_count;	/* not enough space, return */
9591 	}
9592 
9593 	/*
9594 	 * return data collected, reset counter.
9595 	 */
9596 	count = 0;
9597 	skip_bytes = 0;
9598 	rw_enter(&vport->node_rwlock, RW_READER);
9599 	for (i = 0; i < EMLXS_NUM_HASH_QUES; i++) {
9600 		nlp = vport->node_table[i];
9601 		while (nlp != NULL) {
9602 			/* copy port name */
9603 			(void) ddi_copyout((void *)&nlp->nlp_portname,
9604 			    (void *)((char *)dfc->buf4 + skip_bytes),
9605 			    sizeof (HBA_WWN), mode);
9606 			skip_bytes += sizeof (HBA_WWN);
9607 
9608 			/* copy bucket data */
9609 			(void) ddi_copyout((void *)&nlp->sd_dev_bucket[0],
9610 			    (void *)((char *)dfc->buf4 + skip_bytes),
9611 			    sizeof (struct SD_time_stats_v0) *
9612 			    SD_IO_LATENCY_MAX_BUCKETS, mode);
9613 			skip_bytes += sizeof (struct SD_time_stats_v0) *
9614 			    SD_IO_LATENCY_MAX_BUCKETS;
9615 
9616 			bzero((void *)&nlp->sd_dev_bucket[0],
9617 			    sizeof (struct SD_time_stats_v0) *
9618 			    SD_IO_LATENCY_MAX_BUCKETS);
9619 
9620 			count++;
9621 			bufsize -= sizeof (struct SD_IO_Latency_Response);
9622 
9623 			nlp = nlp->nlp_list_next;
9624 		}
9625 	}
9626 	rw_exit(&vport->node_rwlock);
9627 
9628 update_count:
9629 	(void) ddi_copyout((void *)&count, (void *)dfc->buf2,
9630 	    sizeof (uint16_t), mode);
9631 
9632 get_data_exit:
9633 	return (rval);
9634 }
9635 
9636 
9637 static int32_t
9638 emlxs_dfc_sd_set_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9639 {
9640 	emlxs_port_t		*vport;
9641 	uint8_t			wwpn[8];
9642 	uint32_t		event, pid, enable;
9643 	int32_t 		rval = DFC_SD_OK;
9644 	int			i, count;
9645 	emlxs_dfc_event_t	*dfc_event;
9646 
9647 	/*
9648 	 * The value of "event" has been shifted left based on
9649 	 * the category that the application gave to libdfc.
9650 	 *
9651 	 * This is so the old Event handling code won't mistakenly
9652 	 * grab an SD Event.
9653 	 */
9654 	event = dfc->data1;
9655 	pid = dfc->data3;
9656 	enable = dfc->flag;
9657 
9658 	/* Read the wwn object */
9659 	(void) ddi_copyin((void *)dfc->buf3, (void *)wwpn, 8, mode);
9660 
9661 	/* Make sure WWPN is unique */
9662 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9663 
9664 	if (!vport) {
9665 		rval = DFC_SD_ERROR_INVALID_PORT;
9666 		goto set_sd_event_exit;
9667 	}
9668 
9669 	if (enable) {
9670 		/* Find next available event object */
9671 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9672 			dfc_event = &vport->sd_events[i];
9673 
9674 			if (!dfc_event->pid && !dfc_event->event)
9675 				break;
9676 		}
9677 
9678 		/* Return if all event objects are busy */
9679 		if (i == MAX_DFC_EVENTS) {
9680 			rval = DFC_SD_ERROR_OUT_OF_HANDLES;
9681 			goto set_sd_event_exit;
9682 		}
9683 
9684 		/* Initialize */
9685 		/* TODO: Should we add SUBCAT in dfc_event ??? */
9686 		dfc_event->pid = pid;
9687 		dfc_event->event = event;
9688 		dfc_event->last_id = (uint32_t)-1;
9689 		dfc_event->dataout = NULL;
9690 		dfc_event->size = 0;
9691 		dfc_event->mode = 0;
9692 
9693 		(void) emlxs_get_sd_event(vport, dfc_event, 0);
9694 
9695 		if (dfc->buf1)
9696 			(void) ddi_copyout((void *) &dfc_event->last_id,
9697 			    dfc->buf1, sizeof (uint32_t), mode);
9698 
9699 		vport->sd_reg_events |= event;
9700 	} else { /* Disable */
9701 		/* find event entry */
9702 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9703 			dfc_event = &vport->sd_events[i];
9704 
9705 			if (dfc_event->pid  == pid && dfc_event->event == event)
9706 				break;
9707 		}
9708 
9709 		/* Return if not found */
9710 		if (i == MAX_DFC_EVENTS) {
9711 			rval = DFC_SD_ERROR_INVALID_ARG;
9712 			goto set_sd_event_exit;
9713 		}
9714 
9715 		/* Kill the event thread if it is sleeping */
9716 		(void) emlxs_kill_dfc_event(vport, dfc_event);
9717 
9718 		/* Count the number of pids still registered for this event */
9719 		count = 0;
9720 		for (i = 0; i < MAX_DFC_EVENTS; i++) {
9721 			dfc_event = &vport->sd_events[i];
9722 
9723 			if (dfc_event->event == event)
9724 				count++;
9725 		}
9726 
9727 		/*
9728 		 * If no more pids need this event,
9729 		 * then disable logging for this event
9730 		 */
9731 		if (count == 0)
9732 			vport->sd_reg_events &= ~event;
9733 	}
9734 
9735 set_sd_event_exit:
9736 	return (rval);
9737 } /* emlxs_dfc_sd_set_event */
9738 
9739 
9740 static int32_t
9741 emlxs_dfc_sd_get_event(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9742 {
9743 	emlxs_port_t   *vport;
9744 	uint8_t		wwpn[8];
9745 	uint32_t	event, pid, sleep, i;
9746 	int32_t		rval = DFC_SD_OK;
9747 	emlxs_dfc_event_t *dfc_event;
9748 
9749 	event = dfc->data1;
9750 	pid = dfc->data2;
9751 
9752 	/* Read the wwn object */
9753 	(void) ddi_copyin((void *)dfc->buf4, (void *)wwpn, 8, mode);
9754 
9755 	/* Make sure WWPN is unique */
9756 	vport = emlxs_vport_find_wwpn(hba, wwpn);
9757 
9758 	if (!vport) {
9759 		rval = DFC_SD_ERROR_INVALID_PORT;
9760 		goto get_sd_event_exit;
9761 	}
9762 
9763 	/* Find the event entry */
9764 	dfc_event = NULL;
9765 	for (i = 0; i < MAX_DFC_EVENTS; i++) {
9766 		dfc_event = &vport->sd_events[i];
9767 
9768 		if (dfc_event->pid == pid && dfc_event->event == event)
9769 			break;
9770 	}
9771 
9772 	if (i == MAX_DFC_EVENTS) {
9773 		rval = DFC_SD_ERROR_GENERIC;
9774 		goto get_sd_event_exit;
9775 	}
9776 
9777 	if (!(vport->sd_reg_events & dfc_event->event)) {
9778 		rval = DFC_SD_ERROR_GENERIC;
9779 		goto get_sd_event_exit;
9780 	}
9781 
9782 	/* Initialize event buffer pointers */
9783 	dfc_event->dataout = dfc->buf1;
9784 	dfc_event->size = dfc->buf1_size;
9785 	dfc_event->last_id = dfc->data3;
9786 	dfc_event->mode = mode;
9787 
9788 	sleep = (dfc->flag & 0x01) ? 1 : 0;
9789 
9790 	if (emlxs_get_sd_event(vport, dfc_event, sleep))
9791 		return (DFC_SD_ERROR_GENERIC);
9792 
9793 	/*
9794 	 * update rcv_size.
9795 	 */
9796 	if (dfc->buf2)
9797 		(void) ddi_copyout((void *) &dfc_event->size, dfc->buf2,
9798 		    sizeof (uint32_t), mode);
9799 
9800 	/*
9801 	 * update index
9802 	 */
9803 	if (dfc->buf3)
9804 		(void) ddi_copyout((void *) &dfc_event->last_id, dfc->buf3,
9805 		    sizeof (uint32_t), mode);
9806 
9807 get_sd_event_exit:
9808 	return (rval);
9809 } /* emlxs_dfc_sd_get_event */
9810 #endif
9811 
9812 static int32_t
9813 emlxs_dfc_send_scsi_fcp(emlxs_hba_t *hba, dfc_t *dfc, int32_t mode)
9814 {
9815 	emlxs_port_t			*port = &PPORT;
9816 	fc_packet_t			*pkt = NULL;
9817 	NODELIST			*ndlp;
9818 	FCP_CMND			*fcp_cmd;
9819 	FCP_RSP				*fcp_rsp;
9820 	void				*ptr;
9821 	char				buffer[64];
9822 	dfc_send_scsi_fcp_cmd_info_t	cmdinfo;
9823 	uint32_t			rval = 0;
9824 
9825 	/* cmd info */
9826 	if (!dfc->buf1 ||
9827 	    (dfc->buf1_size != sizeof (dfc_send_scsi_fcp_cmd_info_t))) {
9828 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9829 		    "%s: Null buffer1 found.", emlxs_dfc_xlate(dfc->cmd));
9830 
9831 		rval = DFC_ARG_NULL;
9832 		goto done;
9833 	}
9834 
9835 	/* reqBuffer info */
9836 	if (!dfc->buf2 || (dfc->buf2_size != sizeof (FCP_CMND))) {
9837 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9838 		    "%s: Null buffer2 found.", emlxs_dfc_xlate(dfc->cmd));
9839 
9840 		rval = DFC_ARG_NULL;
9841 		goto done;
9842 	}
9843 
9844 	/* rspBuffer info, could be 0 for SCSI commands like TUR */
9845 	if (!dfc->buf3 && dfc->buf3_size) {
9846 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9847 		    "%s: Null buffer3 found.", emlxs_dfc_xlate(dfc->cmd));
9848 
9849 		rval = DFC_ARG_NULL;
9850 		goto done;
9851 	}
9852 
9853 	/* senseBuffer info */
9854 	if (!dfc->buf4 || !dfc->buf4_size) {
9855 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9856 		    "%s: Null buffer4 found.", emlxs_dfc_xlate(dfc->cmd));
9857 
9858 		rval = DFC_ARG_NULL;
9859 		goto done;
9860 	}
9861 
9862 	if (ddi_copyin((void *) dfc->buf1, (void *) &cmdinfo,
9863 	    sizeof (dfc_send_scsi_fcp_cmd_info_t), mode) != 0) {
9864 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9865 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9866 
9867 		rval = DFC_COPYIN_ERROR;
9868 		goto done;
9869 	}
9870 #ifdef NPIV_SUPPORT
9871 	if (cmdinfo.ver == DFC_SEND_SCSI_FCP_V2) {
9872 		port =
9873 		    emlxs_vport_find_wwpn(hba, (uint8_t *)&cmdinfo.src_wwn);
9874 		if (port == NULL) {
9875 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9876 			    "%s: WWPN does not exists. %s",
9877 			    emlxs_dfc_xlate(dfc->cmd), emlxs_wwn_xlate(buffer,
9878 			    (uint8_t *)&cmdinfo.src_wwn));
9879 
9880 			rval = DFC_ARG_INVALID;
9881 			goto done;
9882 		}
9883 	}
9884 #endif /* NPIV_SUPPORT */
9885 
9886 	if ((ndlp = emlxs_node_find_wwpn(port,
9887 	    (uint8_t *)&cmdinfo.dst_wwn)) == NULL) {
9888 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9889 		    "%s: WWPN does not exists. %s", emlxs_dfc_xlate(dfc->cmd),
9890 		    emlxs_wwn_xlate(buffer, (uint8_t *)&cmdinfo.dst_wwn));
9891 
9892 		rval = DFC_ARG_INVALID;
9893 		goto done;
9894 	}
9895 
9896 	if (!(pkt = emlxs_pkt_alloc(port, sizeof (FCP_CMND), sizeof (FCP_RSP),
9897 	    dfc->buf3_size, KM_NOSLEEP))) {
9898 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9899 		    "%s: Unable to allocate packet.",
9900 		    emlxs_dfc_xlate(dfc->cmd));
9901 
9902 		rval = DFC_SYSRES_ERROR;
9903 		goto done;
9904 	}
9905 	fcp_cmd = (FCP_CMND *) pkt->pkt_cmd;
9906 	/* Copy in the command buffer */
9907 	if (ddi_copyin((void *)dfc->buf2, (void *)fcp_cmd, sizeof (FCP_CMND),
9908 	    mode) != 0) {
9909 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9910 		    "%s: ddi_copyin failed.", emlxs_dfc_xlate(dfc->cmd));
9911 
9912 		rval = DFC_COPYIN_ERROR;
9913 		goto done;
9914 	}
9915 
9916 	/* Make this a polled IO */
9917 	pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
9918 	pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
9919 	pkt->pkt_comp = NULL;
9920 
9921 	/* Build the fc header */
9922 	pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(ndlp->nlp_DID);
9923 	pkt->pkt_cmd_fhdr.r_ctl = FC_FCP_CMND;
9924 	pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did);
9925 	pkt->pkt_cmd_fhdr.type = FC_FCP_DATA;
9926 	pkt->pkt_cmd_fhdr.seq_id = 0;
9927 	pkt->pkt_cmd_fhdr.df_ctl = 0;
9928 	pkt->pkt_cmd_fhdr.seq_cnt = 0;
9929 	pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
9930 	pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
9931 	pkt->pkt_cmd_fhdr.ro = 0;
9932 
9933 	pkt->pkt_timeout = 30;
9934 
9935 	if ((fcp_cmd->fcpCntl3 == WRITE_DATA) && dfc->buf3_size) {
9936 		pkt->pkt_tran_type = FC_PKT_FCP_WRITE;
9937 		if (ddi_copyin((void *)dfc->buf3, (void *)pkt->pkt_data,
9938 		    dfc->buf3_size, mode) != 0) {
9939 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9940 			    "%s: ddi_copyin failed.",
9941 			    emlxs_dfc_xlate(dfc->cmd));
9942 
9943 			rval = DFC_COPYIN_ERROR;
9944 			goto done;
9945 		}
9946 	} else {
9947 		pkt->pkt_tran_type = FC_PKT_FCP_READ;
9948 	}
9949 
9950 	if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
9951 		rval = DFC_IO_ERROR;
9952 		goto done;
9953 	}
9954 
9955 	if (pkt->pkt_state != FC_PKT_SUCCESS) {
9956 		if (pkt->pkt_state == FC_PKT_TIMEOUT) {
9957 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9958 			    "Pkt Transport error. Pkt Timeout.");
9959 			rval = DFC_TIMEOUT;
9960 		} else {
9961 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9962 			    "Pkt Transport error. state=%x", pkt->pkt_state);
9963 			rval = DFC_IO_ERROR;
9964 		}
9965 		goto done;
9966 	}
9967 
9968 	if (pkt->pkt_data_resid) {
9969 		if (pkt->pkt_data_resid < dfc->buf3_size)
9970 			dfc->buf3_size -= pkt->pkt_data_resid;
9971 		else
9972 			dfc->buf3_size = 0;
9973 	}
9974 
9975 	SCSI_RSP_CNT(cmdinfo) = dfc->buf3_size;
9976 
9977 	fcp_rsp = (FCP_RSP *) pkt->pkt_resp;
9978 	/*
9979 	 * This is sense count for flag = 0.
9980 	 * It is fcp response size for flag = 1.
9981 	 */
9982 	if (dfc->flag) {
9983 		SCSI_SNS_CNT(cmdinfo) = 24 + SWAP_DATA32(fcp_rsp->rspSnsLen) +
9984 		    SWAP_DATA32(fcp_rsp->rspRspLen);
9985 		ptr = (void *)fcp_rsp;
9986 	} else {
9987 		SCSI_SNS_CNT(cmdinfo) = SWAP_DATA32(fcp_rsp->rspSnsLen);
9988 		ptr = (void *)&fcp_rsp->rspSnsInfo[0];
9989 	}
9990 
9991 	if (ddi_copyout((void *) &cmdinfo, (void *) dfc->buf1,
9992 	    sizeof (dfc_send_scsi_fcp_cmd_info_t), mode) != 0) {
9993 		EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
9994 		    "%s: rsp_buf ddi_copyout failed.",
9995 		    emlxs_dfc_xlate(dfc->cmd));
9996 
9997 		rval = DFC_COPYOUT_ERROR;
9998 		goto done;
9999 	}
10000 
10001 	if (SCSI_SNS_CNT(cmdinfo)) {
10002 		if (ddi_copyout(ptr, (void *)dfc->buf4, SCSI_SNS_CNT(cmdinfo),
10003 		    mode) != 0) {
10004 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10005 			    "%s: rsp_size ddi_copyout failed.",
10006 			    emlxs_dfc_xlate(dfc->cmd));
10007 
10008 			rval = DFC_COPYOUT_ERROR;
10009 			goto done;
10010 		}
10011 	}
10012 
10013 	if (SCSI_RSP_CNT(cmdinfo)) {
10014 		if (ddi_copyout((void *)pkt->pkt_data, (void *)dfc->buf3,
10015 		    SCSI_RSP_CNT(cmdinfo), mode) != 0) {
10016 			EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_dfc_error_msg,
10017 			    "%s: rsp_size ddi_copyout failed.",
10018 			    emlxs_dfc_xlate(dfc->cmd));
10019 
10020 			rval = DFC_COPYOUT_ERROR;
10021 			goto done;
10022 		}
10023 	}
10024 
10025 
10026 	rval = 0;
10027 
10028 done:
10029 	if (pkt) {
10030 		emlxs_pkt_free(pkt);
10031 	}
10032 
10033 	return (rval);
10034 
10035 } /* emlxs_dfc_send_scsi_fcp() */
10036 
10037 #endif	/* DFC_SUPPORT */
10038