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