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 /* Copyright 2010 QLogic Corporation */
23 
24 /*
25  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26  */
27 
28 #pragma ident	"Copyright 2010 QLogic Corporation; ql_xioctl.c"
29 
30 /*
31  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
32  *
33  * ***********************************************************************
34  * *									**
35  * *				NOTICE					**
36  * *		COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION		**
37  * *			ALL RIGHTS RESERVED				**
38  * *									**
39  * ***********************************************************************
40  *
41  */
42 
43 #include <ql_apps.h>
44 #include <ql_api.h>
45 #include <ql_debug.h>
46 #include <ql_init.h>
47 #include <ql_iocb.h>
48 #include <ql_ioctl.h>
49 #include <ql_mbx.h>
50 #include <ql_xioctl.h>
51 
52 /*
53  * Local data
54  */
55 
56 /*
57  * Local prototypes
58  */
59 static int ql_sdm_ioctl(ql_adapter_state_t *, int, void *, int);
60 static int ql_sdm_setup(ql_adapter_state_t *, EXT_IOCTL **, void *, int,
61     boolean_t (*)(EXT_IOCTL *));
62 static boolean_t ql_validate_signature(EXT_IOCTL *);
63 static int ql_sdm_return(ql_adapter_state_t *, EXT_IOCTL *, void *, int);
64 static void ql_query(ql_adapter_state_t *, EXT_IOCTL *, int);
65 static void ql_qry_hba_node(ql_adapter_state_t *, EXT_IOCTL *, int);
66 static void ql_qry_hba_port(ql_adapter_state_t *, EXT_IOCTL *, int);
67 static void ql_qry_disc_port(ql_adapter_state_t *, EXT_IOCTL *, int);
68 static void ql_qry_disc_tgt(ql_adapter_state_t *, EXT_IOCTL *, int);
69 static void ql_qry_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
70 static void ql_qry_chip(ql_adapter_state_t *, EXT_IOCTL *, int);
71 static void ql_qry_driver(ql_adapter_state_t *, EXT_IOCTL *, int);
72 static void ql_fcct(ql_adapter_state_t *, EXT_IOCTL *, int);
73 static void ql_aen_reg(ql_adapter_state_t *, EXT_IOCTL *, int);
74 static void ql_aen_get(ql_adapter_state_t *, EXT_IOCTL *, int);
75 static void ql_scsi_passthru(ql_adapter_state_t *, EXT_IOCTL *, int);
76 static void ql_wwpn_to_scsiaddr(ql_adapter_state_t *, EXT_IOCTL *, int);
77 static void ql_host_idx(ql_adapter_state_t *, EXT_IOCTL *, int);
78 static void ql_host_drvname(ql_adapter_state_t *, EXT_IOCTL *, int);
79 static void ql_read_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
80 static void ql_write_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
81 static void ql_read_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
82 static void ql_write_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
83 static void ql_write_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
84 static void ql_read_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
85 static void ql_diagnostic_loopback(ql_adapter_state_t *, EXT_IOCTL *, int);
86 static void ql_send_els_rnid(ql_adapter_state_t *, EXT_IOCTL *, int);
87 static void ql_set_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
88 static void ql_get_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
89 static void ql_qry_cna_port(ql_adapter_state_t *, EXT_IOCTL *, int);
90 
91 static int ql_lun_count(ql_adapter_state_t *, ql_tgt_t *);
92 static int ql_report_lun(ql_adapter_state_t *, ql_tgt_t *);
93 static int ql_inq_scan(ql_adapter_state_t *, ql_tgt_t *, int);
94 static int ql_inq(ql_adapter_state_t *, ql_tgt_t *, int, ql_mbx_iocb_t *,
95     uint8_t);
96 static uint32_t	ql_get_buffer_data(caddr_t, caddr_t, uint32_t, int);
97 static uint32_t ql_send_buffer_data(caddr_t, caddr_t, uint32_t, int);
98 static int ql_24xx_flash_desc(ql_adapter_state_t *);
99 static int ql_setup_flash(ql_adapter_state_t *);
100 static ql_tgt_t *ql_find_port(ql_adapter_state_t *, uint8_t *, uint16_t);
101 static int ql_flash_fcode_load(ql_adapter_state_t *, void *, uint32_t, int);
102 static int ql_flash_fcode_dump(ql_adapter_state_t *, void *, uint32_t,
103     uint32_t, int);
104 static int ql_program_flash_address(ql_adapter_state_t *, uint32_t,
105     uint8_t);
106 static void ql_set_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
107 static void ql_get_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
108 static int ql_reset_statistics(ql_adapter_state_t *, EXT_IOCTL *);
109 static void ql_get_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
110 static void ql_get_statistics_fc(ql_adapter_state_t *, EXT_IOCTL *, int);
111 static void ql_get_statistics_fc4(ql_adapter_state_t *, EXT_IOCTL *, int);
112 static void ql_set_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
113 static void ql_get_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
114 static void ql_drive_led(ql_adapter_state_t *, uint32_t);
115 static uint32_t ql_setup_led(ql_adapter_state_t *);
116 static uint32_t ql_wrapup_led(ql_adapter_state_t *);
117 static void ql_get_port_summary(ql_adapter_state_t *, EXT_IOCTL *, int);
118 static void ql_get_target_id(ql_adapter_state_t *, EXT_IOCTL *, int);
119 static void ql_get_sfp(ql_adapter_state_t *, EXT_IOCTL *, int);
120 static int ql_dump_sfp(ql_adapter_state_t *, void *, int);
121 static ql_fcache_t *ql_setup_fnode(ql_adapter_state_t *);
122 static void ql_get_fcache(ql_adapter_state_t *, EXT_IOCTL *, int);
123 static void ql_get_fcache_ex(ql_adapter_state_t *, EXT_IOCTL *, int);
124 void ql_update_fcache(ql_adapter_state_t *, uint8_t *, uint32_t);
125 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
126 static void ql_flash_layout_table(ql_adapter_state_t *, uint32_t);
127 static void ql_process_flt(ql_adapter_state_t *, uint32_t);
128 static void ql_flash_nvram_defaults(ql_adapter_state_t *);
129 static void ql_port_param(ql_adapter_state_t *, EXT_IOCTL *, int);
130 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
131 static void ql_get_pci_data(ql_adapter_state_t *, EXT_IOCTL *, int);
132 static void ql_get_fwfcetrace(ql_adapter_state_t *, EXT_IOCTL *, int);
133 static void ql_get_fwexttrace(ql_adapter_state_t *, EXT_IOCTL *, int);
134 static void ql_menlo_reset(ql_adapter_state_t *, EXT_IOCTL *, int);
135 static void ql_menlo_get_fw_version(ql_adapter_state_t *, EXT_IOCTL *, int);
136 static void ql_menlo_update_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
137 static void ql_menlo_manage_info(ql_adapter_state_t *, EXT_IOCTL *, int);
138 static int ql_suspend_hba(ql_adapter_state_t *, uint32_t);
139 static void ql_restart_hba(ql_adapter_state_t *);
140 static void ql_get_vp_cnt_id(ql_adapter_state_t *, EXT_IOCTL *, int);
141 static void ql_vp_ioctl(ql_adapter_state_t *, EXT_IOCTL *, int);
142 static void ql_qry_vport(ql_adapter_state_t *, EXT_IOCTL *, int);
143 static void ql_access_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
144 static void ql_reset_cmd(ql_adapter_state_t *, EXT_IOCTL *);
145 static void ql_update_flash_caches(ql_adapter_state_t *);
146 static void ql_get_dcbx_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
147 static void ql_get_xgmac_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
148 static void ql_get_fcf_list(ql_adapter_state_t *, EXT_IOCTL *, int);
149 static void ql_get_resource_counts(ql_adapter_state_t *, EXT_IOCTL *, int);
150 static void ql_qry_adapter_versions(ql_adapter_state_t *, EXT_IOCTL *, int);
151 static int ql_set_loop_point(ql_adapter_state_t *, uint16_t);
152 
153 /* ******************************************************************** */
154 /*			External IOCTL support.				*/
155 /* ******************************************************************** */
156 
157 /*
158  * ql_alloc_xioctl_resource
159  *	Allocates resources needed by module code.
160  *
161  * Input:
162  *	ha:		adapter state pointer.
163  *
164  * Returns:
165  *	SYS_ERRNO
166  *
167  * Context:
168  *	Kernel context.
169  */
170 int
171 ql_alloc_xioctl_resource(ql_adapter_state_t *ha)
172 {
173 	ql_xioctl_t	*xp;
174 
175 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
176 
177 	if (ha->xioctl != NULL) {
178 		QL_PRINT_9(CE_CONT, "(%d): already allocated done\n",
179 		    ha->instance);
180 		return (0);
181 	}
182 
183 	xp = kmem_zalloc(sizeof (ql_xioctl_t), KM_SLEEP);
184 	if (xp == NULL) {
185 		EL(ha, "failed, kmem_zalloc\n");
186 		return (ENOMEM);
187 	}
188 	ha->xioctl = xp;
189 
190 	/* Allocate AEN tracking buffer */
191 	xp->aen_tracking_queue = kmem_zalloc(EXT_DEF_MAX_AEN_QUEUE *
192 	    sizeof (EXT_ASYNC_EVENT), KM_SLEEP);
193 	if (xp->aen_tracking_queue == NULL) {
194 		EL(ha, "failed, kmem_zalloc-2\n");
195 		ql_free_xioctl_resource(ha);
196 		return (ENOMEM);
197 	}
198 
199 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
200 
201 	return (0);
202 }
203 
204 /*
205  * ql_free_xioctl_resource
206  *	Frees resources used by module code.
207  *
208  * Input:
209  *	ha:		adapter state pointer.
210  *
211  * Context:
212  *	Kernel context.
213  */
214 void
215 ql_free_xioctl_resource(ql_adapter_state_t *ha)
216 {
217 	ql_xioctl_t	*xp = ha->xioctl;
218 
219 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
220 
221 	if (xp == NULL) {
222 		QL_PRINT_9(CE_CONT, "(%d): already freed\n", ha->instance);
223 		return;
224 	}
225 
226 	if (xp->aen_tracking_queue != NULL) {
227 		kmem_free(xp->aen_tracking_queue, EXT_DEF_MAX_AEN_QUEUE *
228 		    sizeof (EXT_ASYNC_EVENT));
229 		xp->aen_tracking_queue = NULL;
230 	}
231 
232 	kmem_free(xp, sizeof (ql_xioctl_t));
233 	ha->xioctl = NULL;
234 
235 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
236 }
237 
238 /*
239  * ql_xioctl
240  *	External IOCTL processing.
241  *
242  * Input:
243  *	ha:	adapter state pointer.
244  *	cmd:	function to perform
245  *	arg:	data type varies with request
246  *	mode:	flags
247  *	cred_p:	credentials pointer
248  *	rval_p:	pointer to result value
249  *
250  * Returns:
251  *	0:		success
252  *	ENXIO:		No such device or address
253  *	ENOPROTOOPT:	Protocol not available
254  *
255  * Context:
256  *	Kernel context.
257  */
258 /* ARGSUSED */
259 int
260 ql_xioctl(ql_adapter_state_t *ha, int cmd, intptr_t arg, int mode,
261     cred_t *cred_p, int *rval_p)
262 {
263 	int	rval;
264 
265 	QL_PRINT_9(CE_CONT, "(%d): started, cmd=%d\n", ha->instance, cmd);
266 
267 	if (ha->xioctl == NULL) {
268 		QL_PRINT_9(CE_CONT, "(%d): no context\n", ha->instance);
269 		return (ENXIO);
270 	}
271 
272 	switch (cmd) {
273 	case EXT_CC_QUERY:
274 	case EXT_CC_SEND_FCCT_PASSTHRU:
275 	case EXT_CC_REG_AEN:
276 	case EXT_CC_GET_AEN:
277 	case EXT_CC_SEND_SCSI_PASSTHRU:
278 	case EXT_CC_WWPN_TO_SCSIADDR:
279 	case EXT_CC_SEND_ELS_RNID:
280 	case EXT_CC_SET_DATA:
281 	case EXT_CC_GET_DATA:
282 	case EXT_CC_HOST_IDX:
283 	case EXT_CC_READ_NVRAM:
284 	case EXT_CC_UPDATE_NVRAM:
285 	case EXT_CC_READ_OPTION_ROM:
286 	case EXT_CC_READ_OPTION_ROM_EX:
287 	case EXT_CC_UPDATE_OPTION_ROM:
288 	case EXT_CC_UPDATE_OPTION_ROM_EX:
289 	case EXT_CC_GET_VPD:
290 	case EXT_CC_SET_VPD:
291 	case EXT_CC_LOOPBACK:
292 	case EXT_CC_GET_FCACHE:
293 	case EXT_CC_GET_FCACHE_EX:
294 	case EXT_CC_HOST_DRVNAME:
295 	case EXT_CC_GET_SFP_DATA:
296 	case EXT_CC_PORT_PARAM:
297 	case EXT_CC_GET_PCI_DATA:
298 	case EXT_CC_GET_FWEXTTRACE:
299 	case EXT_CC_GET_FWFCETRACE:
300 	case EXT_CC_GET_VP_CNT_ID:
301 	case EXT_CC_VPORT_CMD:
302 	case EXT_CC_ACCESS_FLASH:
303 	case EXT_CC_RESET_FW:
304 	case EXT_CC_MENLO_MANAGE_INFO:
305 		rval = ql_sdm_ioctl(ha, cmd, (void *)arg, mode);
306 		break;
307 	default:
308 		/* function not supported. */
309 		EL(ha, "function=%d not supported\n", cmd);
310 		rval = ENOPROTOOPT;
311 	}
312 
313 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
314 
315 	return (rval);
316 }
317 
318 /*
319  * ql_sdm_ioctl
320  *	Provides ioctl functions for SAN/Device Management functions
321  *	AKA External Ioctl functions.
322  *
323  * Input:
324  *	ha:		adapter state pointer.
325  *	ioctl_code:	ioctl function to perform
326  *	arg:		Pointer to EXT_IOCTL cmd data in application land.
327  *	mode:		flags
328  *
329  * Returns:
330  *	0:	success
331  *	ENOMEM:	Alloc of local EXT_IOCTL struct failed.
332  *	EFAULT:	Copyin of caller's EXT_IOCTL struct failed or
333  *		copyout of EXT_IOCTL status info failed.
334  *	EINVAL:	Signature or version of caller's EXT_IOCTL invalid.
335  *	EBUSY:	Device busy
336  *
337  * Context:
338  *	Kernel context.
339  */
340 static int
341 ql_sdm_ioctl(ql_adapter_state_t *ha, int ioctl_code, void *arg, int mode)
342 {
343 	EXT_IOCTL		*cmd;
344 	int			rval;
345 	ql_adapter_state_t	*vha;
346 
347 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
348 
349 	/* Copy argument structure (EXT_IOCTL) from application land. */
350 	if ((rval = ql_sdm_setup(ha, &cmd, arg, mode,
351 	    ql_validate_signature)) != 0) {
352 		/*
353 		 * a non-zero value at this time means a problem getting
354 		 * the requested information from application land, just
355 		 * return the error code and hope for the best.
356 		 */
357 		EL(ha, "failed, sdm_setup\n");
358 		return (rval);
359 	}
360 
361 	/*
362 	 * Map the physical ha ptr (which the ioctl is called with)
363 	 * to the virtual ha that the caller is addressing.
364 	 */
365 	if (ha->flags & VP_ENABLED) {
366 		/* Check that it is within range. */
367 		if (cmd->HbaSelect > (CFG_IST(ha, CFG_CTRL_2422) ?
368 		    MAX_24_VIRTUAL_PORTS : MAX_25_VIRTUAL_PORTS)) {
369 			EL(ha, "Invalid HbaSelect vp index: %xh\n",
370 			    cmd->HbaSelect);
371 			cmd->Status = EXT_STATUS_INVALID_VPINDEX;
372 			cmd->ResponseLen = 0;
373 			return (EFAULT);
374 		}
375 		/*
376 		 * Special case: HbaSelect == 0 is physical ha
377 		 */
378 		if (cmd->HbaSelect != 0) {
379 			vha = ha->vp_next;
380 			while (vha != NULL) {
381 				if (vha->vp_index == cmd->HbaSelect) {
382 					ha = vha;
383 					break;
384 				}
385 				vha = vha->vp_next;
386 			}
387 			/*
388 			 * The specified vp index may be valid(within range)
389 			 * but it's not in the list. Currently this is all
390 			 * we can say.
391 			 */
392 			if (vha == NULL) {
393 				cmd->Status = EXT_STATUS_INVALID_VPINDEX;
394 				cmd->ResponseLen = 0;
395 				return (EFAULT);
396 			}
397 		}
398 	}
399 
400 	/*
401 	 * If driver is suspended, stalled, or powered down rtn BUSY
402 	 */
403 	if (ha->flags & ADAPTER_SUSPENDED ||
404 	    ha->task_daemon_flags & DRIVER_STALL ||
405 	    ha->power_level != PM_LEVEL_D0) {
406 		EL(ha, " %s\n", ha->flags & ADAPTER_SUSPENDED ?
407 		    "driver suspended" :
408 		    (ha->task_daemon_flags & DRIVER_STALL ? "driver stalled" :
409 		    "FCA powered down"));
410 		cmd->Status = EXT_STATUS_BUSY;
411 		cmd->ResponseLen = 0;
412 		rval = EBUSY;
413 
414 		/* Return results to caller */
415 		if ((ql_sdm_return(ha, cmd, arg, mode)) == -1) {
416 			EL(ha, "failed, sdm_return\n");
417 			rval = EFAULT;
418 		}
419 		return (rval);
420 	}
421 
422 	switch (ioctl_code) {
423 	case EXT_CC_QUERY_OS:
424 		ql_query(ha, cmd, mode);
425 		break;
426 	case EXT_CC_SEND_FCCT_PASSTHRU_OS:
427 		ql_fcct(ha, cmd, mode);
428 		break;
429 	case EXT_CC_REG_AEN_OS:
430 		ql_aen_reg(ha, cmd, mode);
431 		break;
432 	case EXT_CC_GET_AEN_OS:
433 		ql_aen_get(ha, cmd, mode);
434 		break;
435 	case EXT_CC_GET_DATA_OS:
436 		ql_get_host_data(ha, cmd, mode);
437 		break;
438 	case EXT_CC_SET_DATA_OS:
439 		ql_set_host_data(ha, cmd, mode);
440 		break;
441 	case EXT_CC_SEND_ELS_RNID_OS:
442 		ql_send_els_rnid(ha, cmd, mode);
443 		break;
444 	case EXT_CC_SCSI_PASSTHRU_OS:
445 		ql_scsi_passthru(ha, cmd, mode);
446 		break;
447 	case EXT_CC_WWPN_TO_SCSIADDR_OS:
448 		ql_wwpn_to_scsiaddr(ha, cmd, mode);
449 		break;
450 	case EXT_CC_HOST_IDX_OS:
451 		ql_host_idx(ha, cmd, mode);
452 		break;
453 	case EXT_CC_HOST_DRVNAME_OS:
454 		ql_host_drvname(ha, cmd, mode);
455 		break;
456 	case EXT_CC_READ_NVRAM_OS:
457 		ql_read_nvram(ha, cmd, mode);
458 		break;
459 	case EXT_CC_UPDATE_NVRAM_OS:
460 		ql_write_nvram(ha, cmd, mode);
461 		break;
462 	case EXT_CC_READ_OPTION_ROM_OS:
463 	case EXT_CC_READ_OPTION_ROM_EX_OS:
464 		ql_read_flash(ha, cmd, mode);
465 		break;
466 	case EXT_CC_UPDATE_OPTION_ROM_OS:
467 	case EXT_CC_UPDATE_OPTION_ROM_EX_OS:
468 		ql_write_flash(ha, cmd, mode);
469 		break;
470 	case EXT_CC_LOOPBACK_OS:
471 		ql_diagnostic_loopback(ha, cmd, mode);
472 		break;
473 	case EXT_CC_GET_VPD_OS:
474 		ql_read_vpd(ha, cmd, mode);
475 		break;
476 	case EXT_CC_SET_VPD_OS:
477 		ql_write_vpd(ha, cmd, mode);
478 		break;
479 	case EXT_CC_GET_FCACHE_OS:
480 		ql_get_fcache(ha, cmd, mode);
481 		break;
482 	case EXT_CC_GET_FCACHE_EX_OS:
483 		ql_get_fcache_ex(ha, cmd, mode);
484 		break;
485 	case EXT_CC_GET_SFP_DATA_OS:
486 		ql_get_sfp(ha, cmd, mode);
487 		break;
488 	case EXT_CC_PORT_PARAM_OS:
489 		ql_port_param(ha, cmd, mode);
490 		break;
491 	case EXT_CC_GET_PCI_DATA_OS:
492 		ql_get_pci_data(ha, cmd, mode);
493 		break;
494 	case EXT_CC_GET_FWEXTTRACE_OS:
495 		ql_get_fwexttrace(ha, cmd, mode);
496 		break;
497 	case EXT_CC_GET_FWFCETRACE_OS:
498 		ql_get_fwfcetrace(ha, cmd, mode);
499 		break;
500 	case EXT_CC_MENLO_RESET:
501 		ql_menlo_reset(ha, cmd, mode);
502 		break;
503 	case EXT_CC_MENLO_GET_FW_VERSION:
504 		ql_menlo_get_fw_version(ha, cmd, mode);
505 		break;
506 	case EXT_CC_MENLO_UPDATE_FW:
507 		ql_menlo_update_fw(ha, cmd, mode);
508 		break;
509 	case EXT_CC_MENLO_MANAGE_INFO:
510 		ql_menlo_manage_info(ha, cmd, mode);
511 		break;
512 	case EXT_CC_GET_VP_CNT_ID_OS:
513 		ql_get_vp_cnt_id(ha, cmd, mode);
514 		break;
515 	case EXT_CC_VPORT_CMD_OS:
516 		ql_vp_ioctl(ha, cmd, mode);
517 		break;
518 	case EXT_CC_ACCESS_FLASH_OS:
519 		ql_access_flash(ha, cmd, mode);
520 		break;
521 	case EXT_CC_RESET_FW_OS:
522 		ql_reset_cmd(ha, cmd);
523 		break;
524 	default:
525 		/* function not supported. */
526 		EL(ha, "failed, function not supported=%d\n", ioctl_code);
527 
528 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
529 		cmd->ResponseLen = 0;
530 		break;
531 	}
532 
533 	/* Return results to caller */
534 	if (ql_sdm_return(ha, cmd, arg, mode) == -1) {
535 		EL(ha, "failed, sdm_return\n");
536 		return (EFAULT);
537 	}
538 
539 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
540 
541 	return (0);
542 }
543 
544 /*
545  * ql_sdm_setup
546  *	Make a local copy of the EXT_IOCTL struct and validate it.
547  *
548  * Input:
549  *	ha:		adapter state pointer.
550  *	cmd_struct:	Pointer to location to store local adrs of EXT_IOCTL.
551  *	arg:		Address of application EXT_IOCTL cmd data
552  *	mode:		flags
553  *	val_sig:	Pointer to a function to validate the ioctl signature.
554  *
555  * Returns:
556  *	0:		success
557  *	EFAULT:		Copy in error of application EXT_IOCTL struct.
558  *	EINVAL:		Invalid version, signature.
559  *	ENOMEM:		Local allocation of EXT_IOCTL failed.
560  *
561  * Context:
562  *	Kernel context.
563  */
564 static int
565 ql_sdm_setup(ql_adapter_state_t *ha, EXT_IOCTL **cmd_struct, void *arg,
566     int mode, boolean_t (*val_sig)(EXT_IOCTL *))
567 {
568 	int		rval;
569 	EXT_IOCTL	*cmd;
570 
571 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
572 
573 	/* Allocate local memory for EXT_IOCTL. */
574 	*cmd_struct = NULL;
575 	cmd = (EXT_IOCTL *)kmem_zalloc(sizeof (EXT_IOCTL), KM_SLEEP);
576 	if (cmd == NULL) {
577 		EL(ha, "failed, kmem_zalloc\n");
578 		return (ENOMEM);
579 	}
580 	/* Get argument structure. */
581 	rval = ddi_copyin(arg, (void *)cmd, sizeof (EXT_IOCTL), mode);
582 	if (rval != 0) {
583 		EL(ha, "failed, ddi_copyin\n");
584 		rval = EFAULT;
585 	} else {
586 		/*
587 		 * Check signature and the version.
588 		 * If either are not valid then neither is the
589 		 * structure so don't attempt to return any error status
590 		 * because we can't trust what caller's arg points to.
591 		 * Just return the errno.
592 		 */
593 		if (val_sig(cmd) == 0) {
594 			EL(ha, "failed, signature\n");
595 			rval = EINVAL;
596 		} else if (cmd->Version > EXT_VERSION) {
597 			EL(ha, "failed, version\n");
598 			rval = EINVAL;
599 		}
600 	}
601 
602 	if (rval == 0) {
603 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
604 		*cmd_struct = cmd;
605 		cmd->Status = EXT_STATUS_OK;
606 		cmd->DetailStatus = 0;
607 	} else {
608 		kmem_free((void *)cmd, sizeof (EXT_IOCTL));
609 	}
610 
611 	return (rval);
612 }
613 
614 /*
615  * ql_validate_signature
616  *	Validate the signature string for an external ioctl call.
617  *
618  * Input:
619  *	sg:	Pointer to EXT_IOCTL signature to validate.
620  *
621  * Returns:
622  *	B_TRUE:		Signature is valid.
623  *	B_FALSE:	Signature is NOT valid.
624  *
625  * Context:
626  *	Kernel context.
627  */
628 static boolean_t
629 ql_validate_signature(EXT_IOCTL *cmd_struct)
630 {
631 	/*
632 	 * Check signature.
633 	 *
634 	 * If signature is not valid then neither is the rest of
635 	 * the structure (e.g., can't trust it), so don't attempt
636 	 * to return any error status other than the errno.
637 	 */
638 	if (bcmp(&cmd_struct->Signature, "QLOGIC", 6) != 0) {
639 		QL_PRINT_2(CE_CONT, "failed,\n");
640 		return (B_FALSE);
641 	}
642 
643 	return (B_TRUE);
644 }
645 
646 /*
647  * ql_sdm_return
648  *	Copies return data/status to application land for
649  *	ioctl call using the SAN/Device Management EXT_IOCTL call interface.
650  *
651  * Input:
652  *	ha:		adapter state pointer.
653  *	cmd:		Pointer to kernel copy of requestor's EXT_IOCTL struct.
654  *	ioctl_code:	ioctl function to perform
655  *	arg:		EXT_IOCTL cmd data in application land.
656  *	mode:		flags
657  *
658  * Returns:
659  *	0:	success
660  *	EFAULT:	Copy out error.
661  *
662  * Context:
663  *	Kernel context.
664  */
665 /* ARGSUSED */
666 static int
667 ql_sdm_return(ql_adapter_state_t *ha, EXT_IOCTL *cmd, void *arg, int mode)
668 {
669 	int	rval = 0;
670 
671 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
672 
673 	rval |= ddi_copyout((void *)&cmd->ResponseLen,
674 	    (void *)&(((EXT_IOCTL*)arg)->ResponseLen), sizeof (uint32_t),
675 	    mode);
676 
677 	rval |= ddi_copyout((void *)&cmd->Status,
678 	    (void *)&(((EXT_IOCTL*)arg)->Status),
679 	    sizeof (cmd->Status), mode);
680 	rval |= ddi_copyout((void *)&cmd->DetailStatus,
681 	    (void *)&(((EXT_IOCTL*)arg)->DetailStatus),
682 	    sizeof (cmd->DetailStatus), mode);
683 
684 	kmem_free((void *)cmd, sizeof (EXT_IOCTL));
685 
686 	if (rval != 0) {
687 		/* Some copyout operation failed */
688 		EL(ha, "failed, ddi_copyout\n");
689 		return (EFAULT);
690 	}
691 
692 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
693 
694 	return (0);
695 }
696 
697 /*
698  * ql_query
699  *	Performs all EXT_CC_QUERY functions.
700  *
701  * Input:
702  *	ha:	adapter state pointer.
703  *	cmd:	Local EXT_IOCTL cmd struct pointer.
704  *	mode:	flags.
705  *
706  * Returns:
707  *	None, request status indicated in cmd->Status.
708  *
709  * Context:
710  *	Kernel context.
711  */
712 static void
713 ql_query(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
714 {
715 	QL_PRINT_9(CE_CONT, "(%d): started, cmd=%d\n", ha->instance,
716 	    cmd->SubCode);
717 
718 	/* case off on command subcode */
719 	switch (cmd->SubCode) {
720 	case EXT_SC_QUERY_HBA_NODE:
721 		ql_qry_hba_node(ha, cmd, mode);
722 		break;
723 	case EXT_SC_QUERY_HBA_PORT:
724 		ql_qry_hba_port(ha, cmd, mode);
725 		break;
726 	case EXT_SC_QUERY_DISC_PORT:
727 		ql_qry_disc_port(ha, cmd, mode);
728 		break;
729 	case EXT_SC_QUERY_DISC_TGT:
730 		ql_qry_disc_tgt(ha, cmd, mode);
731 		break;
732 	case EXT_SC_QUERY_DRIVER:
733 		ql_qry_driver(ha, cmd, mode);
734 		break;
735 	case EXT_SC_QUERY_FW:
736 		ql_qry_fw(ha, cmd, mode);
737 		break;
738 	case EXT_SC_QUERY_CHIP:
739 		ql_qry_chip(ha, cmd, mode);
740 		break;
741 	case EXT_SC_QUERY_CNA_PORT:
742 		ql_qry_cna_port(ha, cmd, mode);
743 		break;
744 	case EXT_SC_QUERY_ADAPTER_VERSIONS:
745 		ql_qry_adapter_versions(ha, cmd, mode);
746 		break;
747 	case EXT_SC_QUERY_DISC_LUN:
748 	default:
749 		/* function not supported. */
750 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
751 		EL(ha, "failed, Unsupported Subcode=%xh\n",
752 		    cmd->SubCode);
753 		break;
754 	}
755 
756 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
757 }
758 
759 /*
760  * ql_qry_hba_node
761  *	Performs EXT_SC_QUERY_HBA_NODE subfunction.
762  *
763  * Input:
764  *	ha:	adapter state pointer.
765  *	cmd:	EXT_IOCTL cmd struct pointer.
766  *	mode:	flags.
767  *
768  * Returns:
769  *	None, request status indicated in cmd->Status.
770  *
771  * Context:
772  *	Kernel context.
773  */
774 static void
775 ql_qry_hba_node(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
776 {
777 	EXT_HBA_NODE	tmp_node = {0};
778 	uint_t		len;
779 	caddr_t		bufp;
780 
781 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
782 
783 	if (cmd->ResponseLen < sizeof (EXT_HBA_NODE)) {
784 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
785 		cmd->DetailStatus = sizeof (EXT_HBA_NODE);
786 		EL(ha, "failed, ResponseLen < EXT_HBA_NODE, "
787 		    "Len=%xh\n", cmd->ResponseLen);
788 		cmd->ResponseLen = 0;
789 		return;
790 	}
791 
792 	/* fill in the values */
793 
794 	bcopy(ha->loginparams.node_ww_name.raw_wwn, tmp_node.WWNN,
795 	    EXT_DEF_WWN_NAME_SIZE);
796 
797 	(void) sprintf((char *)(tmp_node.Manufacturer), "QLogic Corporation");
798 
799 	(void) sprintf((char *)(tmp_node.Model), "%x", ha->device_id);
800 
801 	bcopy(&tmp_node.WWNN[5], tmp_node.SerialNum, 3);
802 
803 	(void) sprintf((char *)(tmp_node.DriverVersion), QL_VERSION);
804 
805 	if (CFG_IST(ha, CFG_SBUS_CARD)) {
806 		size_t		verlen;
807 		uint16_t	w;
808 		char		*tmpptr;
809 
810 		verlen = strlen((char *)(tmp_node.DriverVersion));
811 		if (verlen + 5 > EXT_DEF_MAX_STR_SIZE) {
812 			EL(ha, "failed, No room for fpga version string\n");
813 		} else {
814 			w = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
815 			    (uint16_t *)
816 			    (ha->sbus_fpga_iobase + FPGA_REVISION));
817 
818 			tmpptr = (char *)&(tmp_node.DriverVersion[verlen+1]);
819 			if (tmpptr == NULL) {
820 				EL(ha, "Unable to insert fpga version str\n");
821 			} else {
822 				(void) sprintf(tmpptr, "%d.%d",
823 				    ((w & 0xf0) >> 4), (w & 0x0f));
824 				tmp_node.DriverAttr |= EXT_CC_HBA_NODE_SBUS;
825 			}
826 		}
827 	}
828 
829 	(void) sprintf((char *)(tmp_node.FWVersion), "%01d.%02d.%02d",
830 	    ha->fw_major_version, ha->fw_minor_version,
831 	    ha->fw_subminor_version);
832 
833 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
834 		switch (ha->fw_attributes) {
835 		case FWATTRIB_EF:
836 			(void) strcat((char *)(tmp_node.FWVersion), " EF");
837 			break;
838 		case FWATTRIB_TP:
839 			(void) strcat((char *)(tmp_node.FWVersion), " TP");
840 			break;
841 		case FWATTRIB_IP:
842 			(void) strcat((char *)(tmp_node.FWVersion), " IP");
843 			break;
844 		case FWATTRIB_IPX:
845 			(void) strcat((char *)(tmp_node.FWVersion), " IPX");
846 			break;
847 		case FWATTRIB_FL:
848 			(void) strcat((char *)(tmp_node.FWVersion), " FL");
849 			break;
850 		case FWATTRIB_FPX:
851 			(void) strcat((char *)(tmp_node.FWVersion), " FLX");
852 			break;
853 		default:
854 			break;
855 		}
856 	}
857 
858 	/* FCode version. */
859 	/*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
860 	if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip, PROP_LEN_AND_VAL_ALLOC |
861 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
862 	    (int *)&len) == DDI_PROP_SUCCESS) {
863 		if (len < EXT_DEF_MAX_STR_SIZE) {
864 			bcopy(bufp, tmp_node.OptRomVersion, len);
865 		} else {
866 			bcopy(bufp, tmp_node.OptRomVersion,
867 			    EXT_DEF_MAX_STR_SIZE - 1);
868 			tmp_node.OptRomVersion[EXT_DEF_MAX_STR_SIZE - 1] =
869 			    '\0';
870 		}
871 		kmem_free(bufp, len);
872 	} else {
873 		(void) sprintf((char *)tmp_node.OptRomVersion, "0");
874 	}
875 	tmp_node.PortCount = 1;
876 	tmp_node.InterfaceType = EXT_DEF_FC_INTF_TYPE;
877 
878 	if (ddi_copyout((void *)&tmp_node,
879 	    (void *)(uintptr_t)(cmd->ResponseAdr),
880 	    sizeof (EXT_HBA_NODE), mode) != 0) {
881 		cmd->Status = EXT_STATUS_COPY_ERR;
882 		cmd->ResponseLen = 0;
883 		EL(ha, "failed, ddi_copyout\n");
884 	} else {
885 		cmd->ResponseLen = sizeof (EXT_HBA_NODE);
886 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
887 	}
888 }
889 
890 /*
891  * ql_qry_hba_port
892  *	Performs EXT_SC_QUERY_HBA_PORT subfunction.
893  *
894  * Input:
895  *	ha:	adapter state pointer.
896  *	cmd:	EXT_IOCTL cmd struct pointer.
897  *	mode:	flags.
898  *
899  * Returns:
900  *	None, request status indicated in cmd->Status.
901  *
902  * Context:
903  *	Kernel context.
904  */
905 static void
906 ql_qry_hba_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
907 {
908 	ql_link_t	*link;
909 	ql_tgt_t	*tq;
910 	ql_mbx_data_t	mr;
911 	EXT_HBA_PORT	tmp_port = {0};
912 	int		rval;
913 	uint16_t	port_cnt, tgt_cnt, index;
914 
915 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
916 
917 	if (cmd->ResponseLen < sizeof (EXT_HBA_PORT)) {
918 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
919 		cmd->DetailStatus = sizeof (EXT_HBA_PORT);
920 		EL(ha, "failed, ResponseLen < EXT_HBA_NODE, Len=%xh\n",
921 		    cmd->ResponseLen);
922 		cmd->ResponseLen = 0;
923 		return;
924 	}
925 
926 	/* fill in the values */
927 
928 	bcopy(ha->loginparams.nport_ww_name.raw_wwn, tmp_port.WWPN,
929 	    EXT_DEF_WWN_NAME_SIZE);
930 	tmp_port.Id[0] = 0;
931 	tmp_port.Id[1] = ha->d_id.b.domain;
932 	tmp_port.Id[2] = ha->d_id.b.area;
933 	tmp_port.Id[3] = ha->d_id.b.al_pa;
934 
935 	/* For now we are initiator only driver */
936 	tmp_port.Type = EXT_DEF_INITIATOR_DEV;
937 
938 	if (ha->task_daemon_flags & LOOP_DOWN) {
939 		tmp_port.State = EXT_DEF_HBA_LOOP_DOWN;
940 	} else if (DRIVER_SUSPENDED(ha)) {
941 		tmp_port.State = EXT_DEF_HBA_SUSPENDED;
942 	} else {
943 		tmp_port.State = EXT_DEF_HBA_OK;
944 	}
945 
946 	if (ha->flags & POINT_TO_POINT) {
947 		tmp_port.Mode = EXT_DEF_P2P_MODE;
948 	} else {
949 		tmp_port.Mode = EXT_DEF_LOOP_MODE;
950 	}
951 	/*
952 	 * fill in the portspeed values.
953 	 *
954 	 * default to not yet negotiated state
955 	 */
956 	tmp_port.PortSpeed = EXT_PORTSPEED_NOT_NEGOTIATED;
957 
958 	if (tmp_port.State == EXT_DEF_HBA_OK) {
959 		switch (ha->iidma_rate) {
960 		case IIDMA_RATE_1GB:
961 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_1GBIT;
962 			break;
963 		case IIDMA_RATE_2GB:
964 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_2GBIT;
965 			break;
966 		case IIDMA_RATE_4GB:
967 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_4GBIT;
968 			break;
969 		case IIDMA_RATE_8GB:
970 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_8GBIT;
971 			break;
972 		case IIDMA_RATE_10GB:
973 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_10GBIT;
974 			break;
975 		default:
976 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
977 			EL(ha, "failed, data rate=%xh\n", mr.mb[1]);
978 			break;
979 		}
980 	}
981 
982 	/* Report all supported port speeds */
983 	if (CFG_IST(ha, CFG_CTRL_25XX)) {
984 		tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_8GBIT |
985 		    EXT_DEF_PORTSPEED_4GBIT | EXT_DEF_PORTSPEED_2GBIT |
986 		    EXT_DEF_PORTSPEED_1GBIT);
987 		/*
988 		 * Correct supported speeds based on type of
989 		 * sfp that is present
990 		 */
991 		switch (ha->sfp_stat) {
992 		case 1:
993 			/* no sfp detected */
994 			break;
995 		case 2:
996 		case 4:
997 			/* 4GB sfp */
998 			tmp_port.PortSupportedSpeed &=
999 			    ~EXT_DEF_PORTSPEED_8GBIT;
1000 			break;
1001 		case 3:
1002 		case 5:
1003 			/* 8GB sfp */
1004 			tmp_port.PortSupportedSpeed &=
1005 			    ~EXT_DEF_PORTSPEED_1GBIT;
1006 			break;
1007 		default:
1008 			EL(ha, "sfp_stat: %xh\n", ha->sfp_stat);
1009 			break;
1010 
1011 		}
1012 	} else if (CFG_IST(ha, CFG_CTRL_8081)) {
1013 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_10GBIT;
1014 	} else if (CFG_IST(ha, CFG_CTRL_2422)) {
1015 		tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_4GBIT |
1016 		    EXT_DEF_PORTSPEED_2GBIT | EXT_DEF_PORTSPEED_1GBIT);
1017 	} else if (CFG_IST(ha, CFG_CTRL_2300)) {
1018 		tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_2GBIT |
1019 		    EXT_DEF_PORTSPEED_1GBIT);
1020 	} else if (CFG_IST(ha, CFG_CTRL_6322)) {
1021 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_2GBIT;
1022 	} else if (CFG_IST(ha, CFG_CTRL_2200)) {
1023 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_1GBIT;
1024 	} else {
1025 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
1026 		EL(ha, "unknown HBA type: %xh\n", ha->device_id);
1027 	}
1028 	tmp_port.LinkState2 = LSB(ha->sfp_stat);
1029 	port_cnt = 0;
1030 	tgt_cnt = 0;
1031 
1032 	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
1033 		for (link = ha->dev[index].first; link != NULL;
1034 		    link = link->next) {
1035 			tq = link->base_address;
1036 
1037 			if (!VALID_TARGET_ID(ha, tq->loop_id)) {
1038 				continue;
1039 			}
1040 
1041 			port_cnt++;
1042 			if ((tq->flags & TQF_INITIATOR_DEVICE) == 0) {
1043 				tgt_cnt++;
1044 			}
1045 		}
1046 	}
1047 
1048 	tmp_port.DiscPortCount = port_cnt;
1049 	tmp_port.DiscTargetCount = tgt_cnt;
1050 
1051 	tmp_port.DiscPortNameType = EXT_DEF_USE_NODE_NAME;
1052 
1053 	rval = ddi_copyout((void *)&tmp_port,
1054 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1055 	    sizeof (EXT_HBA_PORT), mode);
1056 	if (rval != 0) {
1057 		cmd->Status = EXT_STATUS_COPY_ERR;
1058 		cmd->ResponseLen = 0;
1059 		EL(ha, "failed, ddi_copyout\n");
1060 	} else {
1061 		cmd->ResponseLen = sizeof (EXT_HBA_PORT);
1062 		QL_PRINT_9(CE_CONT, "(%d): done, ports=%d, targets=%d\n",
1063 		    ha->instance, port_cnt, tgt_cnt);
1064 	}
1065 }
1066 
1067 /*
1068  * ql_qry_disc_port
1069  *	Performs EXT_SC_QUERY_DISC_PORT subfunction.
1070  *
1071  * Input:
1072  *	ha:	adapter state pointer.
1073  *	cmd:	EXT_IOCTL cmd struct pointer.
1074  *	mode:	flags.
1075  *
1076  *	cmd->Instance = Port instance in fcport chain.
1077  *
1078  * Returns:
1079  *	None, request status indicated in cmd->Status.
1080  *
1081  * Context:
1082  *	Kernel context.
1083  */
1084 static void
1085 ql_qry_disc_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1086 {
1087 	EXT_DISC_PORT	tmp_port = {0};
1088 	ql_link_t	*link;
1089 	ql_tgt_t	*tq;
1090 	uint16_t	index;
1091 	uint16_t	inst = 0;
1092 
1093 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1094 
1095 	if (cmd->ResponseLen < sizeof (EXT_DISC_PORT)) {
1096 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1097 		cmd->DetailStatus = sizeof (EXT_DISC_PORT);
1098 		EL(ha, "failed, ResponseLen < EXT_DISC_PORT, Len=%xh\n",
1099 		    cmd->ResponseLen);
1100 		cmd->ResponseLen = 0;
1101 		return;
1102 	}
1103 
1104 	for (link = NULL, index = 0;
1105 	    index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1106 		for (link = ha->dev[index].first; link != NULL;
1107 		    link = link->next) {
1108 			tq = link->base_address;
1109 
1110 			if (!VALID_TARGET_ID(ha, tq->loop_id)) {
1111 				continue;
1112 			}
1113 			if (inst != cmd->Instance) {
1114 				inst++;
1115 				continue;
1116 			}
1117 
1118 			/* fill in the values */
1119 			bcopy(tq->node_name, tmp_port.WWNN,
1120 			    EXT_DEF_WWN_NAME_SIZE);
1121 			bcopy(tq->port_name, tmp_port.WWPN,
1122 			    EXT_DEF_WWN_NAME_SIZE);
1123 
1124 			break;
1125 		}
1126 	}
1127 
1128 	if (link == NULL) {
1129 		/* no matching device */
1130 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1131 		EL(ha, "failed, port not found port=%d\n", cmd->Instance);
1132 		cmd->ResponseLen = 0;
1133 		return;
1134 	}
1135 
1136 	tmp_port.Id[0] = 0;
1137 	tmp_port.Id[1] = tq->d_id.b.domain;
1138 	tmp_port.Id[2] = tq->d_id.b.area;
1139 	tmp_port.Id[3] = tq->d_id.b.al_pa;
1140 
1141 	tmp_port.Type = 0;
1142 	if (tq->flags & TQF_INITIATOR_DEVICE) {
1143 		tmp_port.Type = (uint16_t)(tmp_port.Type |
1144 		    EXT_DEF_INITIATOR_DEV);
1145 	} else if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1146 		(void) ql_inq_scan(ha, tq, 1);
1147 	} else if (tq->flags & TQF_TAPE_DEVICE) {
1148 		tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TAPE_DEV);
1149 	}
1150 
1151 	if (tq->flags & TQF_FABRIC_DEVICE) {
1152 		tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_FABRIC_DEV);
1153 	} else {
1154 		tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TARGET_DEV);
1155 	}
1156 
1157 	tmp_port.Status = 0;
1158 	tmp_port.Bus = 0;  /* Hard-coded for Solaris */
1159 
1160 	bcopy(tq->port_name, &tmp_port.TargetId, 8);
1161 
1162 	if (ddi_copyout((void *)&tmp_port,
1163 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1164 	    sizeof (EXT_DISC_PORT), mode) != 0) {
1165 		cmd->Status = EXT_STATUS_COPY_ERR;
1166 		cmd->ResponseLen = 0;
1167 		EL(ha, "failed, ddi_copyout\n");
1168 	} else {
1169 		cmd->ResponseLen = sizeof (EXT_DISC_PORT);
1170 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1171 	}
1172 }
1173 
1174 /*
1175  * ql_qry_disc_tgt
1176  *	Performs EXT_SC_QUERY_DISC_TGT subfunction.
1177  *
1178  * Input:
1179  *	ha:		adapter state pointer.
1180  *	cmd:		EXT_IOCTL cmd struct pointer.
1181  *	mode:		flags.
1182  *
1183  *	cmd->Instance = Port instance in fcport chain.
1184  *
1185  * Returns:
1186  *	None, request status indicated in cmd->Status.
1187  *
1188  * Context:
1189  *	Kernel context.
1190  */
1191 static void
1192 ql_qry_disc_tgt(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1193 {
1194 	EXT_DISC_TARGET	tmp_tgt = {0};
1195 	ql_link_t	*link;
1196 	ql_tgt_t	*tq;
1197 	uint16_t	index;
1198 	uint16_t	inst = 0;
1199 
1200 	QL_PRINT_9(CE_CONT, "(%d): started, target=%d\n", ha->instance,
1201 	    cmd->Instance);
1202 
1203 	if (cmd->ResponseLen < sizeof (EXT_DISC_TARGET)) {
1204 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1205 		cmd->DetailStatus = sizeof (EXT_DISC_TARGET);
1206 		EL(ha, "failed, ResponseLen < EXT_DISC_TARGET, Len=%xh\n",
1207 		    cmd->ResponseLen);
1208 		cmd->ResponseLen = 0;
1209 		return;
1210 	}
1211 
1212 	/* Scan port list for requested target and fill in the values */
1213 	for (link = NULL, index = 0;
1214 	    index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1215 		for (link = ha->dev[index].first; link != NULL;
1216 		    link = link->next) {
1217 			tq = link->base_address;
1218 
1219 			if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1220 			    tq->flags & TQF_INITIATOR_DEVICE) {
1221 				continue;
1222 			}
1223 			if (inst != cmd->Instance) {
1224 				inst++;
1225 				continue;
1226 			}
1227 
1228 			/* fill in the values */
1229 			bcopy(tq->node_name, tmp_tgt.WWNN,
1230 			    EXT_DEF_WWN_NAME_SIZE);
1231 			bcopy(tq->port_name, tmp_tgt.WWPN,
1232 			    EXT_DEF_WWN_NAME_SIZE);
1233 
1234 			break;
1235 		}
1236 	}
1237 
1238 	if (link == NULL) {
1239 		/* no matching device */
1240 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1241 		cmd->DetailStatus = EXT_DSTATUS_TARGET;
1242 		EL(ha, "failed, not found target=%d\n", cmd->Instance);
1243 		cmd->ResponseLen = 0;
1244 		return;
1245 	}
1246 	tmp_tgt.Id[0] = 0;
1247 	tmp_tgt.Id[1] = tq->d_id.b.domain;
1248 	tmp_tgt.Id[2] = tq->d_id.b.area;
1249 	tmp_tgt.Id[3] = tq->d_id.b.al_pa;
1250 
1251 	tmp_tgt.LunCount = (uint16_t)ql_lun_count(ha, tq);
1252 
1253 	if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1254 		(void) ql_inq_scan(ha, tq, 1);
1255 	}
1256 
1257 	tmp_tgt.Type = 0;
1258 	if (tq->flags & TQF_TAPE_DEVICE) {
1259 		tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TAPE_DEV);
1260 	}
1261 
1262 	if (tq->flags & TQF_FABRIC_DEVICE) {
1263 		tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_FABRIC_DEV);
1264 	} else {
1265 		tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TARGET_DEV);
1266 	}
1267 
1268 	tmp_tgt.Status = 0;
1269 
1270 	tmp_tgt.Bus = 0;  /* Hard-coded for Solaris. */
1271 
1272 	bcopy(tq->port_name, &tmp_tgt.TargetId, 8);
1273 
1274 	if (ddi_copyout((void *)&tmp_tgt,
1275 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1276 	    sizeof (EXT_DISC_TARGET), mode) != 0) {
1277 		cmd->Status = EXT_STATUS_COPY_ERR;
1278 		cmd->ResponseLen = 0;
1279 		EL(ha, "failed, ddi_copyout\n");
1280 	} else {
1281 		cmd->ResponseLen = sizeof (EXT_DISC_TARGET);
1282 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1283 	}
1284 }
1285 
1286 /*
1287  * ql_qry_fw
1288  *	Performs EXT_SC_QUERY_FW subfunction.
1289  *
1290  * Input:
1291  *	ha:	adapter state pointer.
1292  *	cmd:	EXT_IOCTL cmd struct pointer.
1293  *	mode:	flags.
1294  *
1295  * Returns:
1296  *	None, request status indicated in cmd->Status.
1297  *
1298  * Context:
1299  *	Kernel context.
1300  */
1301 static void
1302 ql_qry_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1303 {
1304 	EXT_FW		fw_info = {0};
1305 
1306 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1307 
1308 	if (cmd->ResponseLen < sizeof (EXT_FW)) {
1309 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1310 		cmd->DetailStatus = sizeof (EXT_FW);
1311 		EL(ha, "failed, ResponseLen < EXT_FW, Len=%xh\n",
1312 		    cmd->ResponseLen);
1313 		cmd->ResponseLen = 0;
1314 		return;
1315 	}
1316 
1317 	(void) sprintf((char *)(fw_info.Version), "%d.%02d.%02d",
1318 	    ha->fw_major_version, ha->fw_minor_version,
1319 	    ha->fw_subminor_version);
1320 
1321 	fw_info.Attrib = ha->fw_attributes;
1322 
1323 	if (ddi_copyout((void *)&fw_info,
1324 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1325 	    sizeof (EXT_FW), mode) != 0) {
1326 		cmd->Status = EXT_STATUS_COPY_ERR;
1327 		cmd->ResponseLen = 0;
1328 		EL(ha, "failed, ddi_copyout\n");
1329 		return;
1330 	} else {
1331 		cmd->ResponseLen = sizeof (EXT_FW);
1332 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1333 	}
1334 }
1335 
1336 /*
1337  * ql_qry_chip
1338  *	Performs EXT_SC_QUERY_CHIP subfunction.
1339  *
1340  * Input:
1341  *	ha:	adapter state pointer.
1342  *	cmd:	EXT_IOCTL cmd struct pointer.
1343  *	mode:	flags.
1344  *
1345  * Returns:
1346  *	None, request status indicated in cmd->Status.
1347  *
1348  * Context:
1349  *	Kernel context.
1350  */
1351 static void
1352 ql_qry_chip(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1353 {
1354 	EXT_CHIP	chip = {0};
1355 
1356 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1357 
1358 	if (cmd->ResponseLen < sizeof (EXT_CHIP)) {
1359 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1360 		cmd->DetailStatus = sizeof (EXT_CHIP);
1361 		EL(ha, "failed, ResponseLen < EXT_CHIP, Len=%xh\n",
1362 		    cmd->ResponseLen);
1363 		cmd->ResponseLen = 0;
1364 		return;
1365 	}
1366 
1367 	chip.VendorId = ha->ven_id;
1368 	chip.DeviceId = ha->device_id;
1369 	chip.SubVendorId = ha->subven_id;
1370 	chip.SubSystemId = ha->subsys_id;
1371 	chip.IoAddr = ql_pci_config_get32(ha, PCI_CONF_BASE0);
1372 	chip.IoAddrLen = 0x100;
1373 	chip.MemAddr = ql_pci_config_get32(ha, PCI_CONF_BASE1);
1374 	chip.MemAddrLen = 0x100;
1375 	chip.ChipRevID = ha->rev_id;
1376 	if (ha->flags & FUNCTION_1) {
1377 		chip.FuncNo = 1;
1378 	}
1379 
1380 	if (ddi_copyout((void *)&chip,
1381 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1382 	    sizeof (EXT_CHIP), mode) != 0) {
1383 		cmd->Status = EXT_STATUS_COPY_ERR;
1384 		cmd->ResponseLen = 0;
1385 		EL(ha, "failed, ddi_copyout\n");
1386 	} else {
1387 		cmd->ResponseLen = sizeof (EXT_CHIP);
1388 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1389 	}
1390 }
1391 
1392 /*
1393  * ql_qry_driver
1394  *	Performs EXT_SC_QUERY_DRIVER subfunction.
1395  *
1396  * Input:
1397  *	ha:	adapter state pointer.
1398  *	cmd:	EXT_IOCTL cmd struct pointer.
1399  *	mode:	flags.
1400  *
1401  * Returns:
1402  *	None, request status indicated in cmd->Status.
1403  *
1404  * Context:
1405  *	Kernel context.
1406  */
1407 static void
1408 ql_qry_driver(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1409 {
1410 	EXT_DRIVER	qd = {0};
1411 
1412 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1413 
1414 	if (cmd->ResponseLen < sizeof (EXT_DRIVER)) {
1415 		cmd->Status = EXT_STATUS_DATA_OVERRUN;
1416 		cmd->DetailStatus = sizeof (EXT_DRIVER);
1417 		EL(ha, "failed, ResponseLen < EXT_DRIVER, Len=%xh\n",
1418 		    cmd->ResponseLen);
1419 		cmd->ResponseLen = 0;
1420 		return;
1421 	}
1422 
1423 	(void) strcpy((void *)&qd.Version[0], QL_VERSION);
1424 	qd.NumOfBus = 1;	/* Fixed for Solaris */
1425 	qd.TargetsPerBus = (uint16_t)
1426 	    (CFG_IST(ha, (CFG_CTRL_24258081 | CFG_EXT_FW_INTERFACE)) ?
1427 	    MAX_24_FIBRE_DEVICES : MAX_22_FIBRE_DEVICES);
1428 	qd.LunsPerTarget = 2030;
1429 	qd.MaxTransferLen = QL_DMA_MAX_XFER_SIZE;
1430 	qd.MaxDataSegments = QL_DMA_SG_LIST_LENGTH;
1431 
1432 	if (ddi_copyout((void *)&qd, (void *)(uintptr_t)cmd->ResponseAdr,
1433 	    sizeof (EXT_DRIVER), mode) != 0) {
1434 		cmd->Status = EXT_STATUS_COPY_ERR;
1435 		cmd->ResponseLen = 0;
1436 		EL(ha, "failed, ddi_copyout\n");
1437 	} else {
1438 		cmd->ResponseLen = sizeof (EXT_DRIVER);
1439 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1440 	}
1441 }
1442 
1443 /*
1444  * ql_fcct
1445  *	IOCTL management server FC-CT passthrough.
1446  *
1447  * Input:
1448  *	ha:	adapter state pointer.
1449  *	cmd:	User space CT arguments pointer.
1450  *	mode:	flags.
1451  *
1452  * Returns:
1453  *	None, request status indicated in cmd->Status.
1454  *
1455  * Context:
1456  *	Kernel context.
1457  */
1458 static void
1459 ql_fcct(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1460 {
1461 	ql_mbx_iocb_t		*pkt;
1462 	ql_mbx_data_t		mr;
1463 	dma_mem_t		*dma_mem;
1464 	caddr_t			pld;
1465 	uint32_t		pkt_size, pld_byte_cnt, *long_ptr;
1466 	int			rval;
1467 	ql_ct_iu_preamble_t	*ct;
1468 	ql_xioctl_t		*xp = ha->xioctl;
1469 	ql_tgt_t		tq;
1470 	uint16_t		comp_status, loop_id;
1471 
1472 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1473 
1474 	/* Get CT argument structure. */
1475 	if ((ha->topology & QL_SNS_CONNECTION) == 0) {
1476 		EL(ha, "failed, No switch\n");
1477 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1478 		cmd->ResponseLen = 0;
1479 		return;
1480 	}
1481 
1482 	if (DRIVER_SUSPENDED(ha)) {
1483 		EL(ha, "failed, LOOP_NOT_READY\n");
1484 		cmd->Status = EXT_STATUS_BUSY;
1485 		cmd->ResponseLen = 0;
1486 		return;
1487 	}
1488 
1489 	/* Login management server device. */
1490 	if ((xp->flags & QL_MGMT_SERVER_LOGIN) == 0) {
1491 		tq.d_id.b.al_pa = 0xfa;
1492 		tq.d_id.b.area = 0xff;
1493 		tq.d_id.b.domain = 0xff;
1494 		tq.loop_id = (uint16_t)(CFG_IST(ha, CFG_CTRL_24258081) ?
1495 		    MANAGEMENT_SERVER_24XX_LOOP_ID :
1496 		    MANAGEMENT_SERVER_LOOP_ID);
1497 		rval = ql_login_fport(ha, &tq, tq.loop_id, LFF_NO_PRLI, &mr);
1498 		if (rval != QL_SUCCESS) {
1499 			EL(ha, "failed, server login\n");
1500 			cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1501 			cmd->ResponseLen = 0;
1502 			return;
1503 		} else {
1504 			xp->flags |= QL_MGMT_SERVER_LOGIN;
1505 		}
1506 	}
1507 
1508 	QL_PRINT_9(CE_CONT, "(%d): cmd\n", ha->instance);
1509 	QL_DUMP_9(cmd, 8, sizeof (EXT_IOCTL));
1510 
1511 	/* Allocate a DMA Memory Descriptor */
1512 	dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
1513 	if (dma_mem == NULL) {
1514 		EL(ha, "failed, kmem_zalloc\n");
1515 		cmd->Status = EXT_STATUS_NO_MEMORY;
1516 		cmd->ResponseLen = 0;
1517 		return;
1518 	}
1519 	/* Determine maximum buffer size. */
1520 	if (cmd->RequestLen < cmd->ResponseLen) {
1521 		pld_byte_cnt = cmd->ResponseLen;
1522 	} else {
1523 		pld_byte_cnt = cmd->RequestLen;
1524 	}
1525 
1526 	/* Allocate command block. */
1527 	pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_byte_cnt);
1528 	pkt = kmem_zalloc(pkt_size, KM_SLEEP);
1529 	if (pkt == NULL) {
1530 		EL(ha, "failed, kmem_zalloc\n");
1531 		cmd->Status = EXT_STATUS_NO_MEMORY;
1532 		cmd->ResponseLen = 0;
1533 		return;
1534 	}
1535 	pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
1536 
1537 	/* Get command payload data. */
1538 	if (ql_get_buffer_data((caddr_t)(uintptr_t)cmd->RequestAdr, pld,
1539 	    cmd->RequestLen, mode) != cmd->RequestLen) {
1540 		EL(ha, "failed, get_buffer_data\n");
1541 		kmem_free(pkt, pkt_size);
1542 		cmd->Status = EXT_STATUS_COPY_ERR;
1543 		cmd->ResponseLen = 0;
1544 		return;
1545 	}
1546 
1547 	/* Get DMA memory for the IOCB */
1548 	if (ql_get_dma_mem(ha, dma_mem, pkt_size, LITTLE_ENDIAN_DMA,
1549 	    QL_DMA_RING_ALIGN) != QL_SUCCESS) {
1550 		cmn_err(CE_WARN, "%s(%d): DMA memory "
1551 		    "alloc failed", QL_NAME, ha->instance);
1552 		kmem_free(pkt, pkt_size);
1553 		kmem_free(dma_mem, sizeof (dma_mem_t));
1554 		cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1555 		cmd->ResponseLen = 0;
1556 		return;
1557 	}
1558 
1559 	/* Copy out going payload data to IOCB DMA buffer. */
1560 	ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
1561 	    (uint8_t *)dma_mem->bp, pld_byte_cnt, DDI_DEV_AUTOINCR);
1562 
1563 	/* Sync IOCB DMA buffer. */
1564 	(void) ddi_dma_sync(dma_mem->dma_handle, 0, pld_byte_cnt,
1565 	    DDI_DMA_SYNC_FORDEV);
1566 
1567 	/*
1568 	 * Setup IOCB
1569 	 */
1570 	ct = (ql_ct_iu_preamble_t *)pld;
1571 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
1572 		pkt->ms24.entry_type = CT_PASSTHRU_TYPE;
1573 		pkt->ms24.entry_count = 1;
1574 
1575 		pkt->ms24.vp_index = ha->vp_index;
1576 
1577 		/* Set loop ID */
1578 		pkt->ms24.n_port_hdl = (uint16_t)
1579 		    (ct->gs_type == GS_TYPE_DIR_SERVER ?
1580 		    LE_16(SNS_24XX_HDL) :
1581 		    LE_16(MANAGEMENT_SERVER_24XX_LOOP_ID));
1582 
1583 		/* Set ISP command timeout. */
1584 		pkt->ms24.timeout = LE_16(120);
1585 
1586 		/* Set cmd/response data segment counts. */
1587 		pkt->ms24.cmd_dseg_count = LE_16(1);
1588 		pkt->ms24.resp_dseg_count = LE_16(1);
1589 
1590 		/* Load ct cmd byte count. */
1591 		pkt->ms24.cmd_byte_count = LE_32(cmd->RequestLen);
1592 
1593 		/* Load ct rsp byte count. */
1594 		pkt->ms24.resp_byte_count = LE_32(cmd->ResponseLen);
1595 
1596 		long_ptr = (uint32_t *)&pkt->ms24.dseg_0_address;
1597 
1598 		/* Load MS command entry data segments. */
1599 		*long_ptr++ = (uint32_t)
1600 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1601 		*long_ptr++ = (uint32_t)
1602 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1603 		*long_ptr++ = (uint32_t)(LE_32(cmd->RequestLen));
1604 
1605 		/* Load MS response entry data segments. */
1606 		*long_ptr++ = (uint32_t)
1607 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1608 		*long_ptr++ = (uint32_t)
1609 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1610 		*long_ptr = (uint32_t)LE_32(cmd->ResponseLen);
1611 
1612 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1613 		    sizeof (ql_mbx_iocb_t));
1614 
1615 		comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
1616 		if (comp_status == CS_DATA_UNDERRUN) {
1617 			if ((BE_16(ct->max_residual_size)) == 0) {
1618 				comp_status = CS_COMPLETE;
1619 			}
1620 		}
1621 
1622 		if (rval != QL_SUCCESS || (pkt->sts24.entry_status & 0x3c) !=
1623 		    0) {
1624 			EL(ha, "failed, I/O timeout or "
1625 			    "es=%xh, ss_l=%xh, rval=%xh\n",
1626 			    pkt->sts24.entry_status,
1627 			    pkt->sts24.scsi_status_l, rval);
1628 			kmem_free(pkt, pkt_size);
1629 			ql_free_dma_resource(ha, dma_mem);
1630 			kmem_free(dma_mem, sizeof (dma_mem_t));
1631 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1632 			cmd->ResponseLen = 0;
1633 			return;
1634 		}
1635 	} else {
1636 		pkt->ms.entry_type = MS_TYPE;
1637 		pkt->ms.entry_count = 1;
1638 
1639 		/* Set loop ID */
1640 		loop_id = (uint16_t)(ct->gs_type == GS_TYPE_DIR_SERVER ?
1641 		    SIMPLE_NAME_SERVER_LOOP_ID : MANAGEMENT_SERVER_LOOP_ID);
1642 		if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
1643 			pkt->ms.loop_id_l = LSB(loop_id);
1644 			pkt->ms.loop_id_h = MSB(loop_id);
1645 		} else {
1646 			pkt->ms.loop_id_h = LSB(loop_id);
1647 		}
1648 
1649 		/* Set ISP command timeout. */
1650 		pkt->ms.timeout = LE_16(120);
1651 
1652 		/* Set data segment counts. */
1653 		pkt->ms.cmd_dseg_count_l = 1;
1654 		pkt->ms.total_dseg_count = LE_16(2);
1655 
1656 		/* Response total byte count. */
1657 		pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen);
1658 		pkt->ms.dseg_1_length = LE_32(cmd->ResponseLen);
1659 
1660 		/* Command total byte count. */
1661 		pkt->ms.cmd_byte_count = LE_32(cmd->RequestLen);
1662 		pkt->ms.dseg_0_length = LE_32(cmd->RequestLen);
1663 
1664 		/* Load command/response data segments. */
1665 		pkt->ms.dseg_0_address[0] = (uint32_t)
1666 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1667 		pkt->ms.dseg_0_address[1] = (uint32_t)
1668 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1669 		pkt->ms.dseg_1_address[0] = (uint32_t)
1670 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1671 		pkt->ms.dseg_1_address[1] = (uint32_t)
1672 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1673 
1674 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1675 		    sizeof (ql_mbx_iocb_t));
1676 
1677 		comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
1678 		if (comp_status == CS_DATA_UNDERRUN) {
1679 			if ((BE_16(ct->max_residual_size)) == 0) {
1680 				comp_status = CS_COMPLETE;
1681 			}
1682 		}
1683 		if (rval != QL_SUCCESS || (pkt->sts.entry_status & 0x7e) != 0) {
1684 			EL(ha, "failed, I/O timeout or "
1685 			    "es=%xh, rval=%xh\n", pkt->sts.entry_status, rval);
1686 			kmem_free(pkt, pkt_size);
1687 			ql_free_dma_resource(ha, dma_mem);
1688 			kmem_free(dma_mem, sizeof (dma_mem_t));
1689 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1690 			cmd->ResponseLen = 0;
1691 			return;
1692 		}
1693 	}
1694 
1695 	/* Sync in coming DMA buffer. */
1696 	(void) ddi_dma_sync(dma_mem->dma_handle, 0,
1697 	    pld_byte_cnt, DDI_DMA_SYNC_FORKERNEL);
1698 	/* Copy in coming DMA data. */
1699 	ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
1700 	    (uint8_t *)dma_mem->bp, pld_byte_cnt,
1701 	    DDI_DEV_AUTOINCR);
1702 
1703 	/* Copy response payload from DMA buffer to application. */
1704 	if (cmd->ResponseLen != 0) {
1705 		QL_PRINT_9(CE_CONT, "(%d): ResponseLen=%d\n", ha->instance,
1706 		    cmd->ResponseLen);
1707 		QL_DUMP_9(pld, 8, cmd->ResponseLen);
1708 
1709 		/* Send response payload. */
1710 		if (ql_send_buffer_data(pld,
1711 		    (caddr_t)(uintptr_t)cmd->ResponseAdr,
1712 		    cmd->ResponseLen, mode) != cmd->ResponseLen) {
1713 			EL(ha, "failed, send_buffer_data\n");
1714 			cmd->Status = EXT_STATUS_COPY_ERR;
1715 			cmd->ResponseLen = 0;
1716 		}
1717 	}
1718 
1719 	kmem_free(pkt, pkt_size);
1720 	ql_free_dma_resource(ha, dma_mem);
1721 	kmem_free(dma_mem, sizeof (dma_mem_t));
1722 
1723 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1724 }
1725 
1726 /*
1727  * ql_aen_reg
1728  *	IOCTL management server Asynchronous Event Tracking Enable/Disable.
1729  *
1730  * Input:
1731  *	ha:	adapter state pointer.
1732  *	cmd:	EXT_IOCTL cmd struct pointer.
1733  *	mode:	flags.
1734  *
1735  * Returns:
1736  *	None, request status indicated in cmd->Status.
1737  *
1738  * Context:
1739  *	Kernel context.
1740  */
1741 static void
1742 ql_aen_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1743 {
1744 	EXT_REG_AEN	reg_struct;
1745 	int		rval = 0;
1746 	ql_xioctl_t	*xp = ha->xioctl;
1747 
1748 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1749 
1750 	rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &reg_struct,
1751 	    cmd->RequestLen, mode);
1752 
1753 	if (rval == 0) {
1754 		if (reg_struct.Enable) {
1755 			xp->flags |= QL_AEN_TRACKING_ENABLE;
1756 		} else {
1757 			xp->flags &= ~QL_AEN_TRACKING_ENABLE;
1758 			/* Empty the queue. */
1759 			INTR_LOCK(ha);
1760 			xp->aen_q_head = 0;
1761 			xp->aen_q_tail = 0;
1762 			INTR_UNLOCK(ha);
1763 		}
1764 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1765 	} else {
1766 		cmd->Status = EXT_STATUS_COPY_ERR;
1767 		EL(ha, "failed, ddi_copyin\n");
1768 	}
1769 }
1770 
1771 /*
1772  * ql_aen_get
1773  *	IOCTL management server Asynchronous Event Record Transfer.
1774  *
1775  * Input:
1776  *	ha:	adapter state pointer.
1777  *	cmd:	EXT_IOCTL cmd struct pointer.
1778  *	mode:	flags.
1779  *
1780  * Returns:
1781  *	None, request status indicated in cmd->Status.
1782  *
1783  * Context:
1784  *	Kernel context.
1785  */
1786 static void
1787 ql_aen_get(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1788 {
1789 	uint32_t	out_size;
1790 	EXT_ASYNC_EVENT	*tmp_q;
1791 	EXT_ASYNC_EVENT	aen[EXT_DEF_MAX_AEN_QUEUE];
1792 	uint8_t		i;
1793 	uint8_t		queue_cnt;
1794 	uint8_t		request_cnt;
1795 	ql_xioctl_t	*xp = ha->xioctl;
1796 
1797 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1798 
1799 	/* Compute the number of events that can be returned */
1800 	request_cnt = (uint8_t)(cmd->ResponseLen / sizeof (EXT_ASYNC_EVENT));
1801 
1802 	if (request_cnt < EXT_DEF_MAX_AEN_QUEUE) {
1803 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1804 		cmd->DetailStatus = EXT_DEF_MAX_AEN_QUEUE;
1805 		EL(ha, "failed, request_cnt < EXT_DEF_MAX_AEN_QUEUE, "
1806 		    "Len=%xh\n", request_cnt);
1807 		cmd->ResponseLen = 0;
1808 		return;
1809 	}
1810 
1811 	/* 1st: Make a local copy of the entire queue content. */
1812 	tmp_q = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1813 	queue_cnt = 0;
1814 
1815 	INTR_LOCK(ha);
1816 	i = xp->aen_q_head;
1817 
1818 	for (; queue_cnt < EXT_DEF_MAX_AEN_QUEUE; ) {
1819 		if (tmp_q[i].AsyncEventCode != 0) {
1820 			bcopy(&tmp_q[i], &aen[queue_cnt],
1821 			    sizeof (EXT_ASYNC_EVENT));
1822 			queue_cnt++;
1823 			tmp_q[i].AsyncEventCode = 0; /* empty out the slot */
1824 		}
1825 		if (i == xp->aen_q_tail) {
1826 			/* done. */
1827 			break;
1828 		}
1829 		i++;
1830 		if (i == EXT_DEF_MAX_AEN_QUEUE) {
1831 			i = 0;
1832 		}
1833 	}
1834 
1835 	/* Empty the queue. */
1836 	xp->aen_q_head = 0;
1837 	xp->aen_q_tail = 0;
1838 
1839 	INTR_UNLOCK(ha);
1840 
1841 	/* 2nd: Now transfer the queue content to user buffer */
1842 	/* Copy the entire queue to user's buffer. */
1843 	out_size = (uint32_t)(queue_cnt * sizeof (EXT_ASYNC_EVENT));
1844 	if (queue_cnt == 0) {
1845 		cmd->ResponseLen = 0;
1846 	} else if (ddi_copyout((void *)&aen[0],
1847 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1848 	    out_size, mode) != 0) {
1849 		cmd->Status = EXT_STATUS_COPY_ERR;
1850 		cmd->ResponseLen = 0;
1851 		EL(ha, "failed, ddi_copyout\n");
1852 	} else {
1853 		cmd->ResponseLen = out_size;
1854 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1855 	}
1856 }
1857 
1858 /*
1859  * ql_enqueue_aen
1860  *
1861  * Input:
1862  *	ha:		adapter state pointer.
1863  *	event_code:	async event code of the event to add to queue.
1864  *	payload:	event payload for the queue.
1865  *	INTR_LOCK must be already obtained.
1866  *
1867  * Context:
1868  *	Interrupt or Kernel context, no mailbox commands allowed.
1869  */
1870 void
1871 ql_enqueue_aen(ql_adapter_state_t *ha, uint16_t event_code, void *payload)
1872 {
1873 	uint8_t			new_entry;	/* index to current entry */
1874 	uint16_t		*mbx;
1875 	EXT_ASYNC_EVENT		*aen_queue;
1876 	ql_xioctl_t		*xp = ha->xioctl;
1877 
1878 	QL_PRINT_9(CE_CONT, "(%d): started, event_code=%d\n", ha->instance,
1879 	    event_code);
1880 
1881 	if (xp == NULL) {
1882 		QL_PRINT_9(CE_CONT, "(%d): no context\n", ha->instance);
1883 		return;
1884 	}
1885 	aen_queue = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1886 
1887 	if (aen_queue[xp->aen_q_tail].AsyncEventCode != NULL) {
1888 		/* Need to change queue pointers to make room. */
1889 
1890 		/* Increment tail for adding new entry. */
1891 		xp->aen_q_tail++;
1892 		if (xp->aen_q_tail == EXT_DEF_MAX_AEN_QUEUE) {
1893 			xp->aen_q_tail = 0;
1894 		}
1895 		if (xp->aen_q_head == xp->aen_q_tail) {
1896 			/*
1897 			 * We're overwriting the oldest entry, so need to
1898 			 * update the head pointer.
1899 			 */
1900 			xp->aen_q_head++;
1901 			if (xp->aen_q_head == EXT_DEF_MAX_AEN_QUEUE) {
1902 				xp->aen_q_head = 0;
1903 			}
1904 		}
1905 	}
1906 
1907 	new_entry = xp->aen_q_tail;
1908 	aen_queue[new_entry].AsyncEventCode = event_code;
1909 
1910 	/* Update payload */
1911 	if (payload != NULL) {
1912 		switch (event_code) {
1913 		case MBA_LIP_OCCURRED:
1914 		case MBA_LOOP_UP:
1915 		case MBA_LOOP_DOWN:
1916 		case MBA_LIP_F8:
1917 		case MBA_LIP_RESET:
1918 		case MBA_PORT_UPDATE:
1919 			break;
1920 		case MBA_RSCN_UPDATE:
1921 			mbx = (uint16_t *)payload;
1922 			/* al_pa */
1923 			aen_queue[new_entry].Payload.RSCN.RSCNInfo[0] =
1924 			    LSB(mbx[2]);
1925 			/* area */
1926 			aen_queue[new_entry].Payload.RSCN.RSCNInfo[1] =
1927 			    MSB(mbx[2]);
1928 			/* domain */
1929 			aen_queue[new_entry].Payload.RSCN.RSCNInfo[2] =
1930 			    LSB(mbx[1]);
1931 			/* save in big endian */
1932 			BIG_ENDIAN_24(&aen_queue[new_entry].
1933 			    Payload.RSCN.RSCNInfo[0]);
1934 
1935 			aen_queue[new_entry].Payload.RSCN.AddrFormat =
1936 			    MSB(mbx[1]);
1937 
1938 			break;
1939 		default:
1940 			/* Not supported */
1941 			EL(ha, "failed, event code not supported=%xh\n",
1942 			    event_code);
1943 			aen_queue[new_entry].AsyncEventCode = 0;
1944 			break;
1945 		}
1946 	}
1947 
1948 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1949 }
1950 
1951 /*
1952  * ql_scsi_passthru
1953  *	IOCTL SCSI passthrough.
1954  *
1955  * Input:
1956  *	ha:	adapter state pointer.
1957  *	cmd:	User space SCSI command pointer.
1958  *	mode:	flags.
1959  *
1960  * Returns:
1961  *	None, request status indicated in cmd->Status.
1962  *
1963  * Context:
1964  *	Kernel context.
1965  */
1966 static void
1967 ql_scsi_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1968 {
1969 	ql_mbx_iocb_t		*pkt;
1970 	ql_mbx_data_t		mr;
1971 	dma_mem_t		*dma_mem;
1972 	caddr_t			pld;
1973 	uint32_t		pkt_size, pld_size;
1974 	uint16_t		qlnt, retries, cnt, cnt2;
1975 	uint8_t			*name;
1976 	EXT_FC_SCSI_PASSTHRU	*ufc_req;
1977 	EXT_SCSI_PASSTHRU	*usp_req;
1978 	int			rval;
1979 	union _passthru {
1980 		EXT_SCSI_PASSTHRU	sp_cmd;
1981 		EXT_FC_SCSI_PASSTHRU	fc_cmd;
1982 	} pt_req;		/* Passthru request */
1983 	uint32_t		status, sense_sz = 0;
1984 	ql_tgt_t		*tq = NULL;
1985 	EXT_SCSI_PASSTHRU	*sp_req = &pt_req.sp_cmd;
1986 	EXT_FC_SCSI_PASSTHRU	*fc_req = &pt_req.fc_cmd;
1987 
1988 	/* SCSI request struct for SCSI passthrough IOs. */
1989 	struct {
1990 		uint16_t	lun;
1991 		uint16_t	sense_length;	/* Sense buffer size */
1992 		size_t		resid;		/* Residual */
1993 		uint8_t		*cdbp;		/* Requestor's CDB */
1994 		uint8_t		*u_sense;	/* Requestor's sense buffer */
1995 		uint8_t		cdb_len;	/* Requestor's CDB length */
1996 		uint8_t		direction;
1997 	} scsi_req;
1998 
1999 	struct {
2000 		uint8_t		*rsp_info;
2001 		uint8_t		*req_sense_data;
2002 		uint32_t	residual_length;
2003 		uint32_t	rsp_info_length;
2004 		uint32_t	req_sense_length;
2005 		uint16_t	comp_status;
2006 		uint8_t		state_flags_l;
2007 		uint8_t		state_flags_h;
2008 		uint8_t		scsi_status_l;
2009 		uint8_t		scsi_status_h;
2010 	} sts;
2011 
2012 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2013 
2014 	/* Verify Sub Code and set cnt to needed request size. */
2015 	if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2016 		pld_size = sizeof (EXT_SCSI_PASSTHRU);
2017 	} else if (cmd->SubCode == EXT_SC_SEND_FC_SCSI_PASSTHRU) {
2018 		pld_size = sizeof (EXT_FC_SCSI_PASSTHRU);
2019 	} else {
2020 		EL(ha, "failed, invalid SubCode=%xh\n", cmd->SubCode);
2021 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
2022 		cmd->ResponseLen = 0;
2023 		return;
2024 	}
2025 
2026 	dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
2027 	if (dma_mem == NULL) {
2028 		EL(ha, "failed, kmem_zalloc\n");
2029 		cmd->Status = EXT_STATUS_NO_MEMORY;
2030 		cmd->ResponseLen = 0;
2031 		return;
2032 	}
2033 	/*  Verify the size of and copy in the passthru request structure. */
2034 	if (cmd->RequestLen != pld_size) {
2035 		/* Return error */
2036 		EL(ha, "failed, RequestLen != cnt, is=%xh, expected=%xh\n",
2037 		    cmd->RequestLen, pld_size);
2038 		cmd->Status = EXT_STATUS_INVALID_PARAM;
2039 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2040 		cmd->ResponseLen = 0;
2041 		return;
2042 	}
2043 
2044 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, &pt_req,
2045 	    pld_size, mode) != 0) {
2046 		EL(ha, "failed, ddi_copyin\n");
2047 		cmd->Status = EXT_STATUS_COPY_ERR;
2048 		cmd->ResponseLen = 0;
2049 		return;
2050 	}
2051 
2052 	/*
2053 	 * Find fc_port from SCSI PASSTHRU structure fill in the scsi_req
2054 	 * request data structure.
2055 	 */
2056 	if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2057 		scsi_req.lun = sp_req->TargetAddr.Lun;
2058 		scsi_req.sense_length = sizeof (sp_req->SenseData);
2059 		scsi_req.cdbp = &sp_req->Cdb[0];
2060 		scsi_req.cdb_len = sp_req->CdbLength;
2061 		scsi_req.direction = sp_req->Direction;
2062 		usp_req = (EXT_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2063 		scsi_req.u_sense = &usp_req->SenseData[0];
2064 		cmd->DetailStatus = EXT_DSTATUS_TARGET;
2065 
2066 		qlnt = QLNT_PORT;
2067 		name = (uint8_t *)&sp_req->TargetAddr.Target;
2068 		QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, Target=%lld\n",
2069 		    ha->instance, cmd->SubCode, sp_req->TargetAddr.Target);
2070 		tq = ql_find_port(ha, name, qlnt);
2071 	} else {
2072 		/*
2073 		 * Must be FC PASSTHRU, verified above.
2074 		 */
2075 		if (fc_req->FCScsiAddr.DestType == EXT_DEF_DESTTYPE_WWPN) {
2076 			qlnt = QLNT_PORT;
2077 			name = &fc_req->FCScsiAddr.DestAddr.WWPN[0];
2078 			QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, "
2079 			    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2080 			    ha->instance, cmd->SubCode, name[0], name[1],
2081 			    name[2], name[3], name[4], name[5], name[6],
2082 			    name[7]);
2083 			tq = ql_find_port(ha, name, qlnt);
2084 		} else if (fc_req->FCScsiAddr.DestType ==
2085 		    EXT_DEF_DESTTYPE_WWNN) {
2086 			qlnt = QLNT_NODE;
2087 			name = &fc_req->FCScsiAddr.DestAddr.WWNN[0];
2088 			QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, "
2089 			    "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2090 			    ha->instance, cmd->SubCode, name[0], name[1],
2091 			    name[2], name[3], name[4], name[5], name[6],
2092 			    name[7]);
2093 			tq = ql_find_port(ha, name, qlnt);
2094 		} else if (fc_req->FCScsiAddr.DestType ==
2095 		    EXT_DEF_DESTTYPE_PORTID) {
2096 			qlnt = QLNT_PID;
2097 			name = &fc_req->FCScsiAddr.DestAddr.Id[0];
2098 			QL_PRINT_9(CE_CONT, "(%d): SubCode=%xh, PID="
2099 			    "%02x%02x%02x\n", ha->instance, cmd->SubCode,
2100 			    name[0], name[1], name[2]);
2101 			tq = ql_find_port(ha, name, qlnt);
2102 		} else {
2103 			EL(ha, "failed, SubCode=%xh invalid DestType=%xh\n",
2104 			    cmd->SubCode, fc_req->FCScsiAddr.DestType);
2105 			cmd->Status = EXT_STATUS_INVALID_PARAM;
2106 			cmd->ResponseLen = 0;
2107 			return;
2108 		}
2109 		scsi_req.lun = fc_req->FCScsiAddr.Lun;
2110 		scsi_req.sense_length = sizeof (fc_req->SenseData);
2111 		scsi_req.cdbp = &sp_req->Cdb[0];
2112 		scsi_req.cdb_len = sp_req->CdbLength;
2113 		ufc_req = (EXT_FC_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2114 		scsi_req.u_sense = &ufc_req->SenseData[0];
2115 		scsi_req.direction = fc_req->Direction;
2116 	}
2117 
2118 	if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
2119 		EL(ha, "failed, fc_port not found\n");
2120 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2121 		cmd->ResponseLen = 0;
2122 		return;
2123 	}
2124 
2125 	if (tq->flags & TQF_NEED_AUTHENTICATION) {
2126 		EL(ha, "target not available; loopid=%xh\n", tq->loop_id);
2127 		cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
2128 		cmd->ResponseLen = 0;
2129 		return;
2130 	}
2131 
2132 	/* Allocate command block. */
2133 	if ((scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN ||
2134 	    scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) &&
2135 	    cmd->ResponseLen) {
2136 		pld_size = cmd->ResponseLen;
2137 		pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_size);
2138 		pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2139 		if (pkt == NULL) {
2140 			EL(ha, "failed, kmem_zalloc\n");
2141 			cmd->Status = EXT_STATUS_NO_MEMORY;
2142 			cmd->ResponseLen = 0;
2143 			return;
2144 		}
2145 		pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
2146 
2147 		/* Get DMA memory for the IOCB */
2148 		if (ql_get_dma_mem(ha, dma_mem, pld_size, LITTLE_ENDIAN_DMA,
2149 		    QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
2150 			cmn_err(CE_WARN, "%s(%d): request queue DMA memory "
2151 			    "alloc failed", QL_NAME, ha->instance);
2152 			kmem_free(pkt, pkt_size);
2153 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
2154 			cmd->ResponseLen = 0;
2155 			return;
2156 		}
2157 
2158 		if (scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) {
2159 			scsi_req.direction = (uint8_t)
2160 			    (CFG_IST(ha, CFG_CTRL_24258081) ?
2161 			    CF_RD : CF_DATA_IN | CF_STAG);
2162 		} else {
2163 			scsi_req.direction = (uint8_t)
2164 			    (CFG_IST(ha, CFG_CTRL_24258081) ?
2165 			    CF_WR : CF_DATA_OUT | CF_STAG);
2166 			cmd->ResponseLen = 0;
2167 
2168 			/* Get command payload. */
2169 			if (ql_get_buffer_data(
2170 			    (caddr_t)(uintptr_t)cmd->ResponseAdr,
2171 			    pld, pld_size, mode) != pld_size) {
2172 				EL(ha, "failed, get_buffer_data\n");
2173 				cmd->Status = EXT_STATUS_COPY_ERR;
2174 
2175 				kmem_free(pkt, pkt_size);
2176 				ql_free_dma_resource(ha, dma_mem);
2177 				kmem_free(dma_mem, sizeof (dma_mem_t));
2178 				return;
2179 			}
2180 
2181 			/* Copy out going data to DMA buffer. */
2182 			ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
2183 			    (uint8_t *)dma_mem->bp, pld_size,
2184 			    DDI_DEV_AUTOINCR);
2185 
2186 			/* Sync DMA buffer. */
2187 			(void) ddi_dma_sync(dma_mem->dma_handle, 0,
2188 			    dma_mem->size, DDI_DMA_SYNC_FORDEV);
2189 		}
2190 	} else {
2191 		scsi_req.direction = (uint8_t)
2192 		    (CFG_IST(ha, CFG_CTRL_24258081) ? 0 : CF_STAG);
2193 		cmd->ResponseLen = 0;
2194 
2195 		pkt_size = sizeof (ql_mbx_iocb_t);
2196 		pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2197 		if (pkt == NULL) {
2198 			EL(ha, "failed, kmem_zalloc-2\n");
2199 			cmd->Status = EXT_STATUS_NO_MEMORY;
2200 			return;
2201 		}
2202 		pld = NULL;
2203 		pld_size = 0;
2204 	}
2205 
2206 	/* retries = ha->port_down_retry_count; */
2207 	retries = 1;
2208 	cmd->Status = EXT_STATUS_OK;
2209 	cmd->DetailStatus = EXT_DSTATUS_NOADNL_INFO;
2210 
2211 	QL_PRINT_9(CE_CONT, "(%d): SCSI cdb\n", ha->instance);
2212 	QL_DUMP_9(scsi_req.cdbp, 8, scsi_req.cdb_len);
2213 
2214 	do {
2215 		if (DRIVER_SUSPENDED(ha)) {
2216 			sts.comp_status = CS_LOOP_DOWN_ABORT;
2217 			break;
2218 		}
2219 
2220 		if (CFG_IST(ha, CFG_CTRL_24258081)) {
2221 			pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
2222 			pkt->cmd24.entry_count = 1;
2223 
2224 			/* Set LUN number */
2225 			pkt->cmd24.fcp_lun[2] = LSB(scsi_req.lun);
2226 			pkt->cmd24.fcp_lun[3] = MSB(scsi_req.lun);
2227 
2228 			/* Set N_port handle */
2229 			pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
2230 
2231 			/* Set VP Index */
2232 			pkt->cmd24.vp_index = ha->vp_index;
2233 
2234 			/* Set target ID */
2235 			pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
2236 			pkt->cmd24.target_id[1] = tq->d_id.b.area;
2237 			pkt->cmd24.target_id[2] = tq->d_id.b.domain;
2238 
2239 			/* Set ISP command timeout. */
2240 			pkt->cmd24.timeout = (uint16_t)LE_16(15);
2241 
2242 			/* Load SCSI CDB */
2243 			ddi_rep_put8(ha->hba_buf.acc_handle, scsi_req.cdbp,
2244 			    pkt->cmd24.scsi_cdb, scsi_req.cdb_len,
2245 			    DDI_DEV_AUTOINCR);
2246 			for (cnt = 0; cnt < MAX_CMDSZ;
2247 			    cnt = (uint16_t)(cnt + 4)) {
2248 				ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
2249 				    + cnt, 4);
2250 			}
2251 
2252 			/* Set tag queue control flags */
2253 			pkt->cmd24.task = TA_STAG;
2254 
2255 			if (pld_size) {
2256 				/* Set transfer direction. */
2257 				pkt->cmd24.control_flags = scsi_req.direction;
2258 
2259 				/* Set data segment count. */
2260 				pkt->cmd24.dseg_count = LE_16(1);
2261 
2262 				/* Load total byte count. */
2263 				pkt->cmd24.total_byte_count = LE_32(pld_size);
2264 
2265 				/* Load data descriptor. */
2266 				pkt->cmd24.dseg_0_address[0] = (uint32_t)
2267 				    LE_32(LSD(dma_mem->cookie.dmac_laddress));
2268 				pkt->cmd24.dseg_0_address[1] = (uint32_t)
2269 				    LE_32(MSD(dma_mem->cookie.dmac_laddress));
2270 				pkt->cmd24.dseg_0_length = LE_32(pld_size);
2271 			}
2272 		} else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
2273 			pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
2274 			pkt->cmd3.entry_count = 1;
2275 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2276 				pkt->cmd3.target_l = LSB(tq->loop_id);
2277 				pkt->cmd3.target_h = MSB(tq->loop_id);
2278 			} else {
2279 				pkt->cmd3.target_h = LSB(tq->loop_id);
2280 			}
2281 			pkt->cmd3.lun_l = LSB(scsi_req.lun);
2282 			pkt->cmd3.lun_h = MSB(scsi_req.lun);
2283 			pkt->cmd3.control_flags_l = scsi_req.direction;
2284 			pkt->cmd3.timeout = LE_16(15);
2285 			for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2286 				pkt->cmd3.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2287 			}
2288 			if (pld_size) {
2289 				pkt->cmd3.dseg_count = LE_16(1);
2290 				pkt->cmd3.byte_count = LE_32(pld_size);
2291 				pkt->cmd3.dseg_0_address[0] = (uint32_t)
2292 				    LE_32(LSD(dma_mem->cookie.dmac_laddress));
2293 				pkt->cmd3.dseg_0_address[1] = (uint32_t)
2294 				    LE_32(MSD(dma_mem->cookie.dmac_laddress));
2295 				pkt->cmd3.dseg_0_length = LE_32(pld_size);
2296 			}
2297 		} else {
2298 			pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
2299 			pkt->cmd.entry_count = 1;
2300 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2301 				pkt->cmd.target_l = LSB(tq->loop_id);
2302 				pkt->cmd.target_h = MSB(tq->loop_id);
2303 			} else {
2304 				pkt->cmd.target_h = LSB(tq->loop_id);
2305 			}
2306 			pkt->cmd.lun_l = LSB(scsi_req.lun);
2307 			pkt->cmd.lun_h = MSB(scsi_req.lun);
2308 			pkt->cmd.control_flags_l = scsi_req.direction;
2309 			pkt->cmd.timeout = LE_16(15);
2310 			for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2311 				pkt->cmd.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2312 			}
2313 			if (pld_size) {
2314 				pkt->cmd.dseg_count = LE_16(1);
2315 				pkt->cmd.byte_count = LE_32(pld_size);
2316 				pkt->cmd.dseg_0_address = (uint32_t)
2317 				    LE_32(LSD(dma_mem->cookie.dmac_laddress));
2318 				pkt->cmd.dseg_0_length = LE_32(pld_size);
2319 			}
2320 		}
2321 		/* Go issue command and wait for completion. */
2322 		QL_PRINT_9(CE_CONT, "(%d): request pkt\n", ha->instance);
2323 		QL_DUMP_9(pkt, 8, pkt_size);
2324 
2325 		status = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size);
2326 
2327 		if (pld_size) {
2328 			/* Sync in coming DMA buffer. */
2329 			(void) ddi_dma_sync(dma_mem->dma_handle, 0,
2330 			    dma_mem->size, DDI_DMA_SYNC_FORKERNEL);
2331 			/* Copy in coming DMA data. */
2332 			ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
2333 			    (uint8_t *)dma_mem->bp, pld_size,
2334 			    DDI_DEV_AUTOINCR);
2335 		}
2336 
2337 		if (CFG_IST(ha, CFG_CTRL_24258081)) {
2338 			pkt->sts24.entry_status = (uint8_t)
2339 			    (pkt->sts24.entry_status & 0x3c);
2340 		} else {
2341 			pkt->sts.entry_status = (uint8_t)
2342 			    (pkt->sts.entry_status & 0x7e);
2343 		}
2344 
2345 		if (status == QL_SUCCESS && pkt->sts.entry_status != 0) {
2346 			EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
2347 			    pkt->sts.entry_status, tq->d_id.b24);
2348 			status = QL_FUNCTION_PARAMETER_ERROR;
2349 		}
2350 
2351 		sts.comp_status = (uint16_t)(CFG_IST(ha, CFG_CTRL_24258081) ?
2352 		    LE_16(pkt->sts24.comp_status) :
2353 		    LE_16(pkt->sts.comp_status));
2354 
2355 		/*
2356 		 * We have verified about all the request that can be so far.
2357 		 * Now we need to start verification of our ability to
2358 		 * actually issue the CDB.
2359 		 */
2360 		if (DRIVER_SUSPENDED(ha)) {
2361 			sts.comp_status = CS_LOOP_DOWN_ABORT;
2362 			break;
2363 		} else if (status == QL_SUCCESS &&
2364 		    (sts.comp_status == CS_PORT_LOGGED_OUT ||
2365 		    sts.comp_status == CS_PORT_UNAVAILABLE)) {
2366 			EL(ha, "login retry d_id=%xh\n", tq->d_id.b24);
2367 			if (tq->flags & TQF_FABRIC_DEVICE) {
2368 				rval = ql_login_fport(ha, tq, tq->loop_id,
2369 				    LFF_NO_PLOGI, &mr);
2370 				if (rval != QL_SUCCESS) {
2371 					EL(ha, "failed, login_fport=%xh, "
2372 					    "d_id=%xh\n", rval, tq->d_id.b24);
2373 				}
2374 			} else {
2375 				rval = ql_login_lport(ha, tq, tq->loop_id,
2376 				    LLF_NONE);
2377 				if (rval != QL_SUCCESS) {
2378 					EL(ha, "failed, login_lport=%xh, "
2379 					    "d_id=%xh\n", rval, tq->d_id.b24);
2380 				}
2381 			}
2382 		} else {
2383 			break;
2384 		}
2385 
2386 		bzero((caddr_t)pkt, sizeof (ql_mbx_iocb_t));
2387 
2388 	} while (retries--);
2389 
2390 	if (sts.comp_status == CS_LOOP_DOWN_ABORT) {
2391 		/* Cannot issue command now, maybe later */
2392 		EL(ha, "failed, suspended\n");
2393 		kmem_free(pkt, pkt_size);
2394 		ql_free_dma_resource(ha, dma_mem);
2395 		kmem_free(dma_mem, sizeof (dma_mem_t));
2396 		cmd->Status = EXT_STATUS_SUSPENDED;
2397 		cmd->ResponseLen = 0;
2398 		return;
2399 	}
2400 
2401 	if (status != QL_SUCCESS) {
2402 		/* Command error */
2403 		EL(ha, "failed, I/O\n");
2404 		kmem_free(pkt, pkt_size);
2405 		ql_free_dma_resource(ha, dma_mem);
2406 		kmem_free(dma_mem, sizeof (dma_mem_t));
2407 		cmd->Status = EXT_STATUS_ERR;
2408 		cmd->DetailStatus = status;
2409 		cmd->ResponseLen = 0;
2410 		return;
2411 	}
2412 
2413 	/* Setup status. */
2414 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
2415 		sts.scsi_status_l = pkt->sts24.scsi_status_l;
2416 		sts.scsi_status_h = pkt->sts24.scsi_status_h;
2417 
2418 		/* Setup residuals. */
2419 		sts.residual_length = LE_32(pkt->sts24.residual_length);
2420 
2421 		/* Setup state flags. */
2422 		sts.state_flags_l = pkt->sts24.state_flags_l;
2423 		sts.state_flags_h = pkt->sts24.state_flags_h;
2424 		if (pld_size && sts.comp_status != CS_DATA_UNDERRUN) {
2425 			sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2426 			    SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2427 			    SF_XFERRED_DATA | SF_GOT_STATUS);
2428 		} else {
2429 			sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2430 			    SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2431 			    SF_GOT_STATUS);
2432 		}
2433 		if (scsi_req.direction & CF_WR) {
2434 			sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2435 			    SF_DATA_OUT);
2436 		} else if (scsi_req.direction & CF_RD) {
2437 			sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2438 			    SF_DATA_IN);
2439 		}
2440 		sts.state_flags_l = (uint8_t)(sts.state_flags_l | SF_SIMPLE_Q);
2441 
2442 		/* Setup FCP response info. */
2443 		sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2444 		    LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
2445 		sts.rsp_info = &pkt->sts24.rsp_sense_data[0];
2446 		for (cnt = 0; cnt < sts.rsp_info_length;
2447 		    cnt = (uint16_t)(cnt + 4)) {
2448 			ql_chg_endian(sts.rsp_info + cnt, 4);
2449 		}
2450 
2451 		/* Setup sense data. */
2452 		if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2453 			sts.req_sense_length =
2454 			    LE_32(pkt->sts24.fcp_sense_length);
2455 			sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2456 			    SF_ARQ_DONE);
2457 		} else {
2458 			sts.req_sense_length = 0;
2459 		}
2460 		sts.req_sense_data =
2461 		    &pkt->sts24.rsp_sense_data[sts.rsp_info_length];
2462 		cnt2 = (uint16_t)(((uintptr_t)pkt + sizeof (sts_24xx_entry_t)) -
2463 		    (uintptr_t)sts.req_sense_data);
2464 		for (cnt = 0; cnt < cnt2; cnt = (uint16_t)(cnt + 4)) {
2465 			ql_chg_endian(sts.req_sense_data + cnt, 4);
2466 		}
2467 	} else {
2468 		sts.scsi_status_l = pkt->sts.scsi_status_l;
2469 		sts.scsi_status_h = pkt->sts.scsi_status_h;
2470 
2471 		/* Setup residuals. */
2472 		sts.residual_length = LE_32(pkt->sts.residual_length);
2473 
2474 		/* Setup state flags. */
2475 		sts.state_flags_l = pkt->sts.state_flags_l;
2476 		sts.state_flags_h = pkt->sts.state_flags_h;
2477 
2478 		/* Setup FCP response info. */
2479 		sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2480 		    LE_16(pkt->sts.rsp_info_length) : 0;
2481 		sts.rsp_info = &pkt->sts.rsp_info[0];
2482 
2483 		/* Setup sense data. */
2484 		sts.req_sense_length = sts.scsi_status_h & FCP_SNS_LEN_VALID ?
2485 		    LE_16(pkt->sts.req_sense_length) : 0;
2486 		sts.req_sense_data = &pkt->sts.req_sense_data[0];
2487 	}
2488 
2489 	QL_PRINT_9(CE_CONT, "(%d): response pkt\n", ha->instance);
2490 	QL_DUMP_9(&pkt->sts, 8, sizeof (sts_entry_t));
2491 
2492 	switch (sts.comp_status) {
2493 	case CS_INCOMPLETE:
2494 	case CS_ABORTED:
2495 	case CS_DEVICE_UNAVAILABLE:
2496 	case CS_PORT_UNAVAILABLE:
2497 	case CS_PORT_LOGGED_OUT:
2498 	case CS_PORT_CONFIG_CHG:
2499 	case CS_PORT_BUSY:
2500 	case CS_LOOP_DOWN_ABORT:
2501 		cmd->Status = EXT_STATUS_BUSY;
2502 		break;
2503 	case CS_RESET:
2504 	case CS_QUEUE_FULL:
2505 		cmd->Status = EXT_STATUS_ERR;
2506 		break;
2507 	case CS_TIMEOUT:
2508 		cmd->Status = EXT_STATUS_ERR;
2509 		break;
2510 	case CS_DATA_OVERRUN:
2511 		cmd->Status = EXT_STATUS_DATA_OVERRUN;
2512 		break;
2513 	case CS_DATA_UNDERRUN:
2514 		cmd->Status = EXT_STATUS_DATA_UNDERRUN;
2515 		break;
2516 	}
2517 
2518 	/*
2519 	 * If non data transfer commands fix tranfer counts.
2520 	 */
2521 	if (scsi_req.cdbp[0] == SCMD_TEST_UNIT_READY ||
2522 	    scsi_req.cdbp[0] == SCMD_REZERO_UNIT ||
2523 	    scsi_req.cdbp[0] == SCMD_SEEK ||
2524 	    scsi_req.cdbp[0] == SCMD_SEEK_G1 ||
2525 	    scsi_req.cdbp[0] == SCMD_RESERVE ||
2526 	    scsi_req.cdbp[0] == SCMD_RELEASE ||
2527 	    scsi_req.cdbp[0] == SCMD_START_STOP ||
2528 	    scsi_req.cdbp[0] == SCMD_DOORLOCK ||
2529 	    scsi_req.cdbp[0] == SCMD_VERIFY ||
2530 	    scsi_req.cdbp[0] == SCMD_WRITE_FILE_MARK ||
2531 	    scsi_req.cdbp[0] == SCMD_VERIFY_G0 ||
2532 	    scsi_req.cdbp[0] == SCMD_SPACE ||
2533 	    scsi_req.cdbp[0] == SCMD_ERASE ||
2534 	    (scsi_req.cdbp[0] == SCMD_FORMAT &&
2535 	    (scsi_req.cdbp[1] & FPB_DATA) == 0)) {
2536 		/*
2537 		 * Non data transfer command, clear sts_entry residual
2538 		 * length.
2539 		 */
2540 		sts.residual_length = 0;
2541 		cmd->ResponseLen = 0;
2542 		if (sts.comp_status == CS_DATA_UNDERRUN) {
2543 			sts.comp_status = CS_COMPLETE;
2544 			cmd->Status = EXT_STATUS_OK;
2545 		}
2546 	} else {
2547 		cmd->ResponseLen = pld_size;
2548 	}
2549 
2550 	/* Correct ISP completion status */
2551 	if (sts.comp_status == CS_COMPLETE && sts.scsi_status_l == 0 &&
2552 	    (sts.scsi_status_h & FCP_RSP_MASK) == 0) {
2553 		QL_PRINT_9(CE_CONT, "(%d): Correct completion\n",
2554 		    ha->instance);
2555 		scsi_req.resid = 0;
2556 	} else if (sts.comp_status == CS_DATA_UNDERRUN) {
2557 		QL_PRINT_9(CE_CONT, "(%d): Correct UNDERRUN\n",
2558 		    ha->instance);
2559 		scsi_req.resid = sts.residual_length;
2560 		if (sts.scsi_status_h & FCP_RESID_UNDER) {
2561 			cmd->Status = (uint32_t)EXT_STATUS_OK;
2562 
2563 			cmd->ResponseLen = (uint32_t)
2564 			    (pld_size - scsi_req.resid);
2565 		} else {
2566 			EL(ha, "failed, Transfer ERROR\n");
2567 			cmd->Status = EXT_STATUS_ERR;
2568 			cmd->ResponseLen = 0;
2569 		}
2570 	} else {
2571 		QL_PRINT_9(CE_CONT, "(%d): error d_id=%xh, comp_status=%xh, "
2572 		    "scsi_status_h=%xh, scsi_status_l=%xh\n", ha->instance,
2573 		    tq->d_id.b24, sts.comp_status, sts.scsi_status_h,
2574 		    sts.scsi_status_l);
2575 
2576 		scsi_req.resid = pld_size;
2577 		/*
2578 		 * Handle residual count on SCSI check
2579 		 * condition.
2580 		 *
2581 		 * - If Residual Under / Over is set, use the
2582 		 *   Residual Transfer Length field in IOCB.
2583 		 * - If Residual Under / Over is not set, and
2584 		 *   Transferred Data bit is set in State Flags
2585 		 *   field of IOCB, report residual value of 0
2586 		 *   (you may want to do this for tape
2587 		 *   Write-type commands only). This takes care
2588 		 *   of logical end of tape problem and does
2589 		 *   not break Unit Attention.
2590 		 * - If Residual Under / Over is not set, and
2591 		 *   Transferred Data bit is not set in State
2592 		 *   Flags, report residual value equal to
2593 		 *   original data transfer length.
2594 		 */
2595 		if (sts.scsi_status_l & STATUS_CHECK) {
2596 			cmd->Status = EXT_STATUS_SCSI_STATUS;
2597 			cmd->DetailStatus = sts.scsi_status_l;
2598 			if (sts.scsi_status_h &
2599 			    (FCP_RESID_OVER | FCP_RESID_UNDER)) {
2600 				scsi_req.resid = sts.residual_length;
2601 			} else if (sts.state_flags_h &
2602 			    STATE_XFERRED_DATA) {
2603 				scsi_req.resid = 0;
2604 			}
2605 		}
2606 	}
2607 
2608 	if (sts.scsi_status_l & STATUS_CHECK &&
2609 	    sts.scsi_status_h & FCP_SNS_LEN_VALID &&
2610 	    sts.req_sense_length) {
2611 		/*
2612 		 * Check condition with vaild sense data flag set and sense
2613 		 * length != 0
2614 		 */
2615 		if (sts.req_sense_length > scsi_req.sense_length) {
2616 			sense_sz = scsi_req.sense_length;
2617 		} else {
2618 			sense_sz = sts.req_sense_length;
2619 		}
2620 
2621 		EL(ha, "failed, Check Condition Status, d_id=%xh\n",
2622 		    tq->d_id.b24);
2623 		QL_DUMP_2(sts.req_sense_data, 8, sts.req_sense_length);
2624 
2625 		if (ddi_copyout(sts.req_sense_data, scsi_req.u_sense,
2626 		    (size_t)sense_sz, mode) != 0) {
2627 			EL(ha, "failed, request sense ddi_copyout\n");
2628 		}
2629 
2630 		cmd->Status = EXT_STATUS_SCSI_STATUS;
2631 		cmd->DetailStatus = sts.scsi_status_l;
2632 	}
2633 
2634 	/* Copy response payload from DMA buffer to application. */
2635 	if (scsi_req.direction & (CF_RD | CF_DATA_IN) &&
2636 	    cmd->ResponseLen != 0) {
2637 		QL_PRINT_9(CE_CONT, "(%d): Data Return resid=%lu, "
2638 		    "byte_count=%u, ResponseLen=%xh\n", ha->instance,
2639 		    scsi_req.resid, pld_size, cmd->ResponseLen);
2640 		QL_DUMP_9(pld, 8, cmd->ResponseLen);
2641 
2642 		/* Send response payload. */
2643 		if (ql_send_buffer_data(pld,
2644 		    (caddr_t)(uintptr_t)cmd->ResponseAdr,
2645 		    cmd->ResponseLen, mode) != cmd->ResponseLen) {
2646 			EL(ha, "failed, send_buffer_data\n");
2647 			cmd->Status = EXT_STATUS_COPY_ERR;
2648 			cmd->ResponseLen = 0;
2649 		}
2650 	}
2651 
2652 	if (cmd->Status != EXT_STATUS_OK) {
2653 		EL(ha, "failed, cmd->Status=%xh, comp_status=%xh, "
2654 		    "d_id=%xh\n", cmd->Status, sts.comp_status, tq->d_id.b24);
2655 	} else {
2656 		/*EMPTY*/
2657 		QL_PRINT_9(CE_CONT, "(%d): done, ResponseLen=%d\n",
2658 		    ha->instance, cmd->ResponseLen);
2659 	}
2660 
2661 	kmem_free(pkt, pkt_size);
2662 	ql_free_dma_resource(ha, dma_mem);
2663 	kmem_free(dma_mem, sizeof (dma_mem_t));
2664 }
2665 
2666 /*
2667  * ql_wwpn_to_scsiaddr
2668  *
2669  * Input:
2670  *	ha:	adapter state pointer.
2671  *	cmd:	EXT_IOCTL cmd struct pointer.
2672  *	mode:	flags.
2673  *
2674  * Context:
2675  *	Kernel context.
2676  */
2677 static void
2678 ql_wwpn_to_scsiaddr(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2679 {
2680 	int		status;
2681 	uint8_t		wwpn[EXT_DEF_WWN_NAME_SIZE];
2682 	EXT_SCSI_ADDR	*tmp_addr;
2683 	ql_tgt_t	*tq;
2684 
2685 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2686 
2687 	if (cmd->RequestLen != EXT_DEF_WWN_NAME_SIZE) {
2688 		/* Return error */
2689 		EL(ha, "incorrect RequestLen\n");
2690 		cmd->Status = EXT_STATUS_INVALID_PARAM;
2691 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2692 		return;
2693 	}
2694 
2695 	status = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, wwpn,
2696 	    cmd->RequestLen, mode);
2697 
2698 	if (status != 0) {
2699 		cmd->Status = EXT_STATUS_COPY_ERR;
2700 		EL(ha, "failed, ddi_copyin\n");
2701 		return;
2702 	}
2703 
2704 	tq = ql_find_port(ha, wwpn, QLNT_PORT);
2705 
2706 	if (tq == NULL || tq->flags & TQF_INITIATOR_DEVICE) {
2707 		/* no matching device */
2708 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2709 		EL(ha, "failed, device not found\n");
2710 		return;
2711 	}
2712 
2713 	/* Copy out the IDs found.  For now we can only return target ID. */
2714 	tmp_addr = (EXT_SCSI_ADDR *)(uintptr_t)cmd->ResponseAdr;
2715 
2716 	status = ddi_copyout((void *)wwpn, (void *)&tmp_addr->Target, 8, mode);
2717 
2718 	if (status != 0) {
2719 		cmd->Status = EXT_STATUS_COPY_ERR;
2720 		EL(ha, "failed, ddi_copyout\n");
2721 	} else {
2722 		cmd->Status = EXT_STATUS_OK;
2723 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2724 	}
2725 }
2726 
2727 /*
2728  * ql_host_idx
2729  *	Gets host order index.
2730  *
2731  * Input:
2732  *	ha:	adapter state pointer.
2733  *	cmd:	EXT_IOCTL cmd struct pointer.
2734  *	mode:	flags.
2735  *
2736  * Returns:
2737  *	None, request status indicated in cmd->Status.
2738  *
2739  * Context:
2740  *	Kernel context.
2741  */
2742 static void
2743 ql_host_idx(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2744 {
2745 	uint16_t	idx;
2746 
2747 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2748 
2749 	if (cmd->ResponseLen < sizeof (uint16_t)) {
2750 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2751 		cmd->DetailStatus = sizeof (uint16_t);
2752 		EL(ha, "failed, ResponseLen < Len=%xh\n", cmd->ResponseLen);
2753 		cmd->ResponseLen = 0;
2754 		return;
2755 	}
2756 
2757 	idx = (uint16_t)ha->instance;
2758 
2759 	if (ddi_copyout((void *)&idx, (void *)(uintptr_t)(cmd->ResponseAdr),
2760 	    sizeof (uint16_t), mode) != 0) {
2761 		cmd->Status = EXT_STATUS_COPY_ERR;
2762 		cmd->ResponseLen = 0;
2763 		EL(ha, "failed, ddi_copyout\n");
2764 	} else {
2765 		cmd->ResponseLen = sizeof (uint16_t);
2766 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2767 	}
2768 }
2769 
2770 /*
2771  * ql_host_drvname
2772  *	Gets host driver name
2773  *
2774  * Input:
2775  *	ha:	adapter state pointer.
2776  *	cmd:	EXT_IOCTL cmd struct pointer.
2777  *	mode:	flags.
2778  *
2779  * Returns:
2780  *	None, request status indicated in cmd->Status.
2781  *
2782  * Context:
2783  *	Kernel context.
2784  */
2785 static void
2786 ql_host_drvname(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2787 {
2788 
2789 	char		drvname[] = QL_NAME;
2790 	uint32_t	qlnamelen;
2791 
2792 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2793 
2794 	qlnamelen = (uint32_t)(strlen(QL_NAME)+1);
2795 
2796 	if (cmd->ResponseLen < qlnamelen) {
2797 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2798 		cmd->DetailStatus = qlnamelen;
2799 		EL(ha, "failed, ResponseLen: %xh, needed: %xh\n",
2800 		    cmd->ResponseLen, qlnamelen);
2801 		cmd->ResponseLen = 0;
2802 		return;
2803 	}
2804 
2805 	if (ddi_copyout((void *)&drvname,
2806 	    (void *)(uintptr_t)(cmd->ResponseAdr),
2807 	    qlnamelen, mode) != 0) {
2808 		cmd->Status = EXT_STATUS_COPY_ERR;
2809 		cmd->ResponseLen = 0;
2810 		EL(ha, "failed, ddi_copyout\n");
2811 	} else {
2812 		cmd->ResponseLen = qlnamelen-1;
2813 	}
2814 
2815 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2816 }
2817 
2818 /*
2819  * ql_read_nvram
2820  *	Get NVRAM contents.
2821  *
2822  * Input:
2823  *	ha:	adapter state pointer.
2824  *	cmd:	EXT_IOCTL cmd struct pointer.
2825  *	mode:	flags.
2826  *
2827  * Returns:
2828  *	None, request status indicated in cmd->Status.
2829  *
2830  * Context:
2831  *	Kernel context.
2832  */
2833 static void
2834 ql_read_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2835 {
2836 
2837 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2838 
2839 	if (cmd->ResponseLen < ha->nvram_cache->size) {
2840 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2841 		cmd->DetailStatus = ha->nvram_cache->size;
2842 		EL(ha, "failed, ResponseLen != NVRAM, Len=%xh\n",
2843 		    cmd->ResponseLen);
2844 		cmd->ResponseLen = 0;
2845 		return;
2846 	}
2847 
2848 	/* Get NVRAM data. */
2849 	if (ql_nv_util_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
2850 	    mode) != 0) {
2851 		cmd->Status = EXT_STATUS_COPY_ERR;
2852 		cmd->ResponseLen = 0;
2853 		EL(ha, "failed, copy error\n");
2854 	} else {
2855 		cmd->ResponseLen = ha->nvram_cache->size;
2856 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2857 	}
2858 }
2859 
2860 /*
2861  * ql_write_nvram
2862  *	Loads NVRAM contents.
2863  *
2864  * Input:
2865  *	ha:	adapter state pointer.
2866  *	cmd:	EXT_IOCTL cmd struct pointer.
2867  *	mode:	flags.
2868  *
2869  * Returns:
2870  *	None, request status indicated in cmd->Status.
2871  *
2872  * Context:
2873  *	Kernel context.
2874  */
2875 static void
2876 ql_write_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2877 {
2878 
2879 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2880 
2881 	if (cmd->RequestLen < ha->nvram_cache->size) {
2882 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2883 		cmd->DetailStatus = ha->nvram_cache->size;
2884 		EL(ha, "failed, RequestLen != NVRAM, Len=%xh\n",
2885 		    cmd->RequestLen);
2886 		return;
2887 	}
2888 
2889 	/* Load NVRAM data. */
2890 	if (ql_nv_util_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
2891 	    mode) != 0) {
2892 		cmd->Status = EXT_STATUS_COPY_ERR;
2893 		EL(ha, "failed, copy error\n");
2894 	} else {
2895 		/*EMPTY*/
2896 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2897 	}
2898 }
2899 
2900 /*
2901  * ql_write_vpd
2902  *	Loads VPD contents.
2903  *
2904  * Input:
2905  *	ha:	adapter state pointer.
2906  *	cmd:	EXT_IOCTL cmd struct pointer.
2907  *	mode:	flags.
2908  *
2909  * Returns:
2910  *	None, request status indicated in cmd->Status.
2911  *
2912  * Context:
2913  *	Kernel context.
2914  */
2915 static void
2916 ql_write_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2917 {
2918 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2919 
2920 	int32_t		rval = 0;
2921 
2922 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
2923 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
2924 		EL(ha, "failed, invalid request for HBA\n");
2925 		return;
2926 	}
2927 
2928 	if (cmd->RequestLen < QL_24XX_VPD_SIZE) {
2929 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2930 		cmd->DetailStatus = QL_24XX_VPD_SIZE;
2931 		EL(ha, "failed, RequestLen != VPD len, len passed=%xh\n",
2932 		    cmd->RequestLen);
2933 		return;
2934 	}
2935 
2936 	/* Load VPD data. */
2937 	if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
2938 	    mode)) != 0) {
2939 		cmd->Status = EXT_STATUS_COPY_ERR;
2940 		cmd->DetailStatus = rval;
2941 		EL(ha, "failed, errno=%x\n", rval);
2942 	} else {
2943 		/*EMPTY*/
2944 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2945 	}
2946 }
2947 
2948 /*
2949  * ql_read_vpd
2950  *	Dumps VPD contents.
2951  *
2952  * Input:
2953  *	ha:	adapter state pointer.
2954  *	cmd:	EXT_IOCTL cmd struct pointer.
2955  *	mode:	flags.
2956  *
2957  * Returns:
2958  *	None, request status indicated in cmd->Status.
2959  *
2960  * Context:
2961  *	Kernel context.
2962  */
2963 static void
2964 ql_read_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2965 {
2966 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
2967 
2968 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
2969 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
2970 		EL(ha, "failed, invalid request for HBA\n");
2971 		return;
2972 	}
2973 
2974 	if (cmd->ResponseLen < QL_24XX_VPD_SIZE) {
2975 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2976 		cmd->DetailStatus = QL_24XX_VPD_SIZE;
2977 		EL(ha, "failed, ResponseLen < VPD len, len passed=%xh\n",
2978 		    cmd->ResponseLen);
2979 		return;
2980 	}
2981 
2982 	/* Dump VPD data. */
2983 	if ((ql_vpd_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
2984 	    mode)) != 0) {
2985 		cmd->Status = EXT_STATUS_COPY_ERR;
2986 		EL(ha, "failed,\n");
2987 	} else {
2988 		/*EMPTY*/
2989 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
2990 	}
2991 }
2992 
2993 /*
2994  * ql_get_fcache
2995  *	Dumps flash cache contents.
2996  *
2997  * Input:
2998  *	ha:	adapter state pointer.
2999  *	cmd:	EXT_IOCTL cmd struct pointer.
3000  *	mode:	flags.
3001  *
3002  * Returns:
3003  *	None, request status indicated in cmd->Status.
3004  *
3005  * Context:
3006  *	Kernel context.
3007  */
3008 static void
3009 ql_get_fcache(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3010 {
3011 	uint32_t	bsize, boff, types, cpsize, hsize;
3012 	ql_fcache_t	*fptr;
3013 
3014 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3015 
3016 	CACHE_LOCK(ha);
3017 
3018 	if (ha->fcache == NULL) {
3019 		CACHE_UNLOCK(ha);
3020 		cmd->Status = EXT_STATUS_ERR;
3021 		EL(ha, "failed, adapter fcache not setup\n");
3022 		return;
3023 	}
3024 
3025 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
3026 		bsize = 100;
3027 	} else {
3028 		bsize = 400;
3029 	}
3030 
3031 	if (cmd->ResponseLen < bsize) {
3032 		CACHE_UNLOCK(ha);
3033 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3034 		cmd->DetailStatus = bsize;
3035 		EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3036 		    bsize, cmd->ResponseLen);
3037 		return;
3038 	}
3039 
3040 	boff = 0;
3041 	bsize = 0;
3042 	fptr = ha->fcache;
3043 
3044 	/*
3045 	 * For backwards compatibility, get one of each image type
3046 	 */
3047 	types = (FTYPE_BIOS | FTYPE_FCODE | FTYPE_EFI);
3048 	while ((fptr != NULL) && (fptr->buf != NULL) && (types != 0)) {
3049 		/* Get the next image */
3050 		if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) {
3051 
3052 			cpsize = (fptr->buflen < 100 ? fptr->buflen : 100);
3053 
3054 			if (ddi_copyout(fptr->buf,
3055 			    (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3056 			    cpsize, mode) != 0) {
3057 				CACHE_UNLOCK(ha);
3058 				EL(ha, "ddicopy failed, done\n");
3059 				cmd->Status = EXT_STATUS_COPY_ERR;
3060 				cmd->DetailStatus = 0;
3061 				return;
3062 			}
3063 			boff += 100;
3064 			bsize += cpsize;
3065 			types &= ~(fptr->type);
3066 		}
3067 	}
3068 
3069 	/*
3070 	 * Get the firmware image -- it needs to be last in the
3071 	 * buffer at offset 300 for backwards compatibility. Also for
3072 	 * backwards compatibility, the pci header is stripped off.
3073 	 */
3074 	if ((fptr = ql_get_fbuf(ha->fcache, FTYPE_FW)) != NULL) {
3075 
3076 		hsize = sizeof (pci_header_t) + sizeof (pci_data_t);
3077 		if (hsize > fptr->buflen) {
3078 			CACHE_UNLOCK(ha);
3079 			EL(ha, "header size (%xh) exceeds buflen (%xh)\n",
3080 			    hsize, fptr->buflen);
3081 			cmd->Status = EXT_STATUS_COPY_ERR;
3082 			cmd->DetailStatus = 0;
3083 			return;
3084 		}
3085 
3086 		cpsize = ((fptr->buflen - hsize) < 100 ?
3087 		    fptr->buflen - hsize : 100);
3088 
3089 		if (ddi_copyout(fptr->buf+hsize,
3090 		    (void *)(uintptr_t)(cmd->ResponseAdr + 300),
3091 		    cpsize, mode) != 0) {
3092 			CACHE_UNLOCK(ha);
3093 			EL(ha, "fw ddicopy failed, done\n");
3094 			cmd->Status = EXT_STATUS_COPY_ERR;
3095 			cmd->DetailStatus = 0;
3096 			return;
3097 		}
3098 		bsize += 100;
3099 	}
3100 
3101 	CACHE_UNLOCK(ha);
3102 	cmd->Status = EXT_STATUS_OK;
3103 	cmd->DetailStatus = bsize;
3104 
3105 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3106 }
3107 
3108 /*
3109  * ql_get_fcache_ex
3110  *	Dumps flash cache contents.
3111  *
3112  * Input:
3113  *	ha:	adapter state pointer.
3114  *	cmd:	EXT_IOCTL cmd struct pointer.
3115  *	mode:	flags.
3116  *
3117  * Returns:
3118  *	None, request status indicated in cmd->Status.
3119  *
3120  * Context:
3121  *	Kernel context.
3122  */
3123 static void
3124 ql_get_fcache_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3125 {
3126 	uint32_t	bsize = 0;
3127 	uint32_t	boff = 0;
3128 	ql_fcache_t	*fptr;
3129 
3130 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3131 
3132 	CACHE_LOCK(ha);
3133 	if (ha->fcache == NULL) {
3134 		CACHE_UNLOCK(ha);
3135 		cmd->Status = EXT_STATUS_ERR;
3136 		EL(ha, "failed, adapter fcache not setup\n");
3137 		return;
3138 	}
3139 
3140 	/* Make sure user passed enough buffer space */
3141 	for (fptr = ha->fcache; fptr != NULL; fptr = fptr->next) {
3142 		bsize += FBUFSIZE;
3143 	}
3144 
3145 	if (cmd->ResponseLen < bsize) {
3146 		CACHE_UNLOCK(ha);
3147 		if (cmd->ResponseLen != 0) {
3148 			EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3149 			    bsize, cmd->ResponseLen);
3150 		}
3151 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3152 		cmd->DetailStatus = bsize;
3153 		return;
3154 	}
3155 
3156 	boff = 0;
3157 	fptr = ha->fcache;
3158 	while ((fptr != NULL) && (fptr->buf != NULL)) {
3159 		/* Get the next image */
3160 		if (ddi_copyout(fptr->buf,
3161 		    (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3162 		    (fptr->buflen < FBUFSIZE ? fptr->buflen : FBUFSIZE),
3163 		    mode) != 0) {
3164 			CACHE_UNLOCK(ha);
3165 			EL(ha, "failed, ddicopy at %xh, done\n", boff);
3166 			cmd->Status = EXT_STATUS_COPY_ERR;
3167 			cmd->DetailStatus = 0;
3168 			return;
3169 		}
3170 		boff += FBUFSIZE;
3171 		fptr = fptr->next;
3172 	}
3173 
3174 	CACHE_UNLOCK(ha);
3175 	cmd->Status = EXT_STATUS_OK;
3176 	cmd->DetailStatus = bsize;
3177 
3178 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3179 }
3180 
3181 /*