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 2015 QLogic Corporation */
23 
24 /*
25  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
26  */
27 
28 /*
29  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
30  */
31 
32 /*
33  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
34  *
35  * ***********************************************************************
36  * *									**
37  * *				NOTICE					**
38  * *		COPYRIGHT (C) 1996-2015 QLOGIC CORPORATION		**
39  * *			ALL RIGHTS RESERVED				**
40  * *									**
41  * ***********************************************************************
42  *
43  */
44 
45 #include <ql_apps.h>
46 #include <ql_api.h>
47 #include <ql_debug.h>
48 #include <ql_init.h>
49 #include <ql_iocb.h>
50 #include <ql_ioctl.h>
51 #include <ql_mbx.h>
52 #include <ql_nx.h>
53 #include <ql_xioctl.h>
54 
55 /*
56  * Local data
57  */
58 
59 /*
60  * Local prototypes
61  */
62 static int ql_sdm_ioctl(ql_adapter_state_t *, int, void *, int);
63 static int ql_sdm_setup(ql_adapter_state_t *, EXT_IOCTL **, void *, int,
64     boolean_t (*)(EXT_IOCTL *));
65 static boolean_t ql_validate_signature(EXT_IOCTL *);
66 static int ql_sdm_return(ql_adapter_state_t *, EXT_IOCTL *, void *, int);
67 static void ql_query(ql_adapter_state_t *, EXT_IOCTL *, int);
68 static void ql_qry_hba_node(ql_adapter_state_t *, EXT_IOCTL *, int);
69 static void ql_qry_hba_port(ql_adapter_state_t *, EXT_IOCTL *, int);
70 static void ql_qry_disc_port(ql_adapter_state_t *, EXT_IOCTL *, int);
71 static void ql_qry_disc_tgt(ql_adapter_state_t *, EXT_IOCTL *, int);
72 static void ql_qry_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
73 static void ql_qry_chip(ql_adapter_state_t *, EXT_IOCTL *, int);
74 static void ql_qry_driver(ql_adapter_state_t *, EXT_IOCTL *, int);
75 static void ql_fcct(ql_adapter_state_t *, EXT_IOCTL *, int);
76 static void ql_aen_reg(ql_adapter_state_t *, EXT_IOCTL *, int);
77 static void ql_aen_get(ql_adapter_state_t *, EXT_IOCTL *, int);
78 static void ql_scsi_passthru(ql_adapter_state_t *, EXT_IOCTL *, int);
79 static void ql_wwpn_to_scsiaddr(ql_adapter_state_t *, EXT_IOCTL *, int);
80 static void ql_host_idx(ql_adapter_state_t *, EXT_IOCTL *, int);
81 static void ql_host_drvname(ql_adapter_state_t *, EXT_IOCTL *, int);
82 static void ql_read_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
83 static void ql_write_nvram(ql_adapter_state_t *, EXT_IOCTL *, int);
84 static void ql_read_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
85 static void ql_write_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
86 static void ql_write_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
87 static void ql_read_vpd(ql_adapter_state_t *, EXT_IOCTL *, int);
88 static void ql_diagnostic_loopback(ql_adapter_state_t *, EXT_IOCTL *, int);
89 static void ql_send_els_rnid(ql_adapter_state_t *, EXT_IOCTL *, int);
90 static void ql_set_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
91 static void ql_get_host_data(ql_adapter_state_t *, EXT_IOCTL *, int);
92 static void ql_qry_cna_port(ql_adapter_state_t *, EXT_IOCTL *, int);
93 
94 static int ql_lun_count(ql_adapter_state_t *, ql_tgt_t *);
95 static int ql_report_lun(ql_adapter_state_t *, ql_tgt_t *);
96 static int ql_inq_scan(ql_adapter_state_t *, ql_tgt_t *, int);
97 static int ql_inq(ql_adapter_state_t *, ql_tgt_t *, int, ql_mbx_iocb_t *,
98     uint32_t);
99 static uint32_t	ql_get_buffer_data(caddr_t, caddr_t, uint32_t, int);
100 static uint32_t ql_send_buffer_data(caddr_t, caddr_t, uint32_t, int);
101 static int ql_24xx_flash_desc(ql_adapter_state_t *);
102 static int ql_setup_flash(ql_adapter_state_t *);
103 static ql_tgt_t *ql_find_port(ql_adapter_state_t *, uint8_t *, uint16_t);
104 static int ql_flash_fcode_load(ql_adapter_state_t *, void *, uint32_t, int);
105 static int ql_flash_fcode_dump(ql_adapter_state_t *, void *, uint32_t,
106     uint32_t, int);
107 static int ql_program_flash_address(ql_adapter_state_t *, uint32_t,
108     uint8_t);
109 static void ql_set_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
110 static void ql_get_rnid_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
111 static int ql_reset_statistics(ql_adapter_state_t *, EXT_IOCTL *);
112 static void ql_get_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
113 static void ql_get_statistics_fc(ql_adapter_state_t *, EXT_IOCTL *, int);
114 static void ql_get_statistics_fc4(ql_adapter_state_t *, EXT_IOCTL *, int);
115 static void ql_set_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
116 static void ql_get_led_state(ql_adapter_state_t *, EXT_IOCTL *, int);
117 static void ql_drive_led(ql_adapter_state_t *, uint32_t);
118 static int ql_setup_led(ql_adapter_state_t *);
119 static int ql_wrapup_led(ql_adapter_state_t *);
120 static void ql_get_port_summary(ql_adapter_state_t *, EXT_IOCTL *, int);
121 static void ql_get_target_id(ql_adapter_state_t *, EXT_IOCTL *, int);
122 static void ql_get_sfp(ql_adapter_state_t *, EXT_IOCTL *, int);
123 static int ql_dump_sfp(ql_adapter_state_t *, void *, int);
124 static ql_fcache_t *ql_setup_fnode(ql_adapter_state_t *);
125 static void ql_get_fcache(ql_adapter_state_t *, EXT_IOCTL *, int);
126 static void ql_get_fcache_ex(ql_adapter_state_t *, EXT_IOCTL *, int);
127 void ql_update_fcache(ql_adapter_state_t *, uint8_t *, uint32_t);
128 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
129 static void ql_flash_layout_table(ql_adapter_state_t *, uint32_t);
130 static void ql_process_flt(ql_adapter_state_t *, uint32_t);
131 static void ql_flash_nvram_defaults(ql_adapter_state_t *);
132 static void ql_port_param(ql_adapter_state_t *, EXT_IOCTL *, int);
133 static int ql_check_pci(ql_adapter_state_t *, ql_fcache_t *, uint32_t *);
134 static void ql_get_pci_data(ql_adapter_state_t *, EXT_IOCTL *, int);
135 static void ql_get_fwfcetrace(ql_adapter_state_t *, EXT_IOCTL *, int);
136 static void ql_get_fwexttrace(ql_adapter_state_t *, EXT_IOCTL *, int);
137 static void ql_menlo_reset(ql_adapter_state_t *, EXT_IOCTL *, int);
138 static void ql_menlo_get_fw_version(ql_adapter_state_t *, EXT_IOCTL *, int);
139 static void ql_menlo_update_fw(ql_adapter_state_t *, EXT_IOCTL *, int);
140 static void ql_menlo_manage_info(ql_adapter_state_t *, EXT_IOCTL *, int);
141 static int ql_suspend_hba(ql_adapter_state_t *, uint32_t);
142 static void ql_restart_hba(ql_adapter_state_t *);
143 static void ql_get_vp_cnt_id(ql_adapter_state_t *, EXT_IOCTL *, int);
144 static void ql_vp_ioctl(ql_adapter_state_t *, EXT_IOCTL *, int);
145 static void ql_qry_vport(ql_adapter_state_t *, EXT_IOCTL *, int);
146 static void ql_access_flash(ql_adapter_state_t *, EXT_IOCTL *, int);
147 static void ql_reset_cmd(ql_adapter_state_t *, EXT_IOCTL *);
148 static void ql_update_flash_caches(ql_adapter_state_t *);
149 static void ql_get_dcbx_parameters(ql_adapter_state_t *, EXT_IOCTL *, int);
150 static void ql_get_xgmac_statistics(ql_adapter_state_t *, EXT_IOCTL *, int);
151 static void ql_get_fcf_list(ql_adapter_state_t *, EXT_IOCTL *, int);
152 static void ql_get_resource_counts(ql_adapter_state_t *, EXT_IOCTL *, int);
153 static void ql_qry_adapter_versions(ql_adapter_state_t *, EXT_IOCTL *, int);
154 static void ql_get_temperature(ql_adapter_state_t *, EXT_IOCTL *, int);
155 static void ql_dump_cmd(ql_adapter_state_t *, EXT_IOCTL *, int);
156 static void ql_serdes_reg(ql_adapter_state_t *, EXT_IOCTL *, int);
157 static void ql_serdes_reg_ex(ql_adapter_state_t *, EXT_IOCTL *, int);
158 static void ql_els_passthru(ql_adapter_state_t *, EXT_IOCTL *, int);
159 static void ql_flash_update_caps(ql_adapter_state_t *, EXT_IOCTL *, int);
160 static void ql_get_bbcr_data(ql_adapter_state_t *, EXT_IOCTL *, int);
161 static void ql_get_priv_stats(ql_adapter_state_t *, EXT_IOCTL *, int);
162 
163 /* ******************************************************************** */
164 /*			External IOCTL support.				*/
165 /* ******************************************************************** */
166 
167 /*
168  * ql_alloc_xioctl_resource
169  *	Allocates resources needed by module code.
170  *
171  * Input:
172  *	ha:		adapter state pointer.
173  *
174  * Returns:
175  *	SYS_ERRNO
176  *
177  * Context:
178  *	Kernel context.
179  */
180 int
ql_alloc_xioctl_resource(ql_adapter_state_t * ha)181 ql_alloc_xioctl_resource(ql_adapter_state_t *ha)
182 {
183 	ql_xioctl_t	*xp;
184 
185 	QL_PRINT_9(ha, "started\n");
186 
187 	if (ha->xioctl != NULL) {
188 		QL_PRINT_9(ha, "already allocated done\n",
189 		    ha->instance);
190 		return (0);
191 	}
192 
193 	xp = kmem_zalloc(sizeof (ql_xioctl_t), KM_SLEEP);
194 	if (xp == NULL) {
195 		EL(ha, "failed, kmem_zalloc\n");
196 		return (ENOMEM);
197 	}
198 	ha->xioctl = xp;
199 
200 	/* Allocate AEN tracking buffer */
201 	xp->aen_tracking_queue = kmem_zalloc(EXT_DEF_MAX_AEN_QUEUE *
202 	    sizeof (EXT_ASYNC_EVENT), KM_SLEEP);
203 	if (xp->aen_tracking_queue == NULL) {
204 		EL(ha, "failed, kmem_zalloc-2\n");
205 		ql_free_xioctl_resource(ha);
206 		return (ENOMEM);
207 	}
208 
209 	QL_PRINT_9(ha, "done\n");
210 
211 	return (0);
212 }
213 
214 /*
215  * ql_free_xioctl_resource
216  *	Frees resources used by module code.
217  *
218  * Input:
219  *	ha:		adapter state pointer.
220  *
221  * Context:
222  *	Kernel context.
223  */
224 void
ql_free_xioctl_resource(ql_adapter_state_t * ha)225 ql_free_xioctl_resource(ql_adapter_state_t *ha)
226 {
227 	ql_xioctl_t	*xp = ha->xioctl;
228 
229 	QL_PRINT_9(ha, "started\n");
230 
231 	if (xp == NULL) {
232 		QL_PRINT_9(ha, "already freed\n");
233 		return;
234 	}
235 
236 	if (xp->aen_tracking_queue != NULL) {
237 		kmem_free(xp->aen_tracking_queue, EXT_DEF_MAX_AEN_QUEUE *
238 		    sizeof (EXT_ASYNC_EVENT));
239 		xp->aen_tracking_queue = NULL;
240 	}
241 
242 	kmem_free(xp, sizeof (ql_xioctl_t));
243 	ha->xioctl = NULL;
244 
245 	QL_PRINT_9(ha, "done\n");
246 }
247 
248 /*
249  * ql_xioctl
250  *	External IOCTL processing.
251  *
252  * Input:
253  *	ha:	adapter state pointer.
254  *	cmd:	function to perform
255  *	arg:	data type varies with request
256  *	mode:	flags
257  *	cred_p:	credentials pointer
258  *	rval_p:	pointer to result value
259  *
260  * Returns:
261  *	0:		success
262  *	ENXIO:		No such device or address
263  *	ENOPROTOOPT:	Protocol not available
264  *
265  * Context:
266  *	Kernel context.
267  */
268 /* ARGSUSED */
269 int
ql_xioctl(ql_adapter_state_t * ha,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)270 ql_xioctl(ql_adapter_state_t *ha, int cmd, intptr_t arg, int mode,
271     cred_t *cred_p, int *rval_p)
272 {
273 	int	rval;
274 
275 	QL_PRINT_9(ha, "started, cmd=%d\n", cmd);
276 
277 	if (ha->xioctl == NULL) {
278 		QL_PRINT_9(ha, "no context\n");
279 		return (ENXIO);
280 	}
281 
282 	switch (cmd) {
283 	case EXT_CC_QUERY:
284 	case EXT_CC_SEND_FCCT_PASSTHRU:
285 	case EXT_CC_REG_AEN:
286 	case EXT_CC_GET_AEN:
287 	case EXT_CC_SEND_SCSI_PASSTHRU:
288 	case EXT_CC_WWPN_TO_SCSIADDR:
289 	case EXT_CC_SEND_ELS_RNID:
290 	case EXT_CC_SET_DATA:
291 	case EXT_CC_GET_DATA:
292 	case EXT_CC_HOST_IDX:
293 	case EXT_CC_READ_NVRAM:
294 	case EXT_CC_UPDATE_NVRAM:
295 	case EXT_CC_READ_OPTION_ROM:
296 	case EXT_CC_READ_OPTION_ROM_EX:
297 	case EXT_CC_UPDATE_OPTION_ROM:
298 	case EXT_CC_UPDATE_OPTION_ROM_EX:
299 	case EXT_CC_GET_VPD:
300 	case EXT_CC_SET_VPD:
301 	case EXT_CC_LOOPBACK:
302 	case EXT_CC_GET_FCACHE:
303 	case EXT_CC_GET_FCACHE_EX:
304 	case EXT_CC_HOST_DRVNAME:
305 	case EXT_CC_GET_SFP_DATA:
306 	case EXT_CC_PORT_PARAM:
307 	case EXT_CC_GET_PCI_DATA:
308 	case EXT_CC_GET_FWEXTTRACE:
309 	case EXT_CC_GET_FWFCETRACE:
310 	case EXT_CC_GET_VP_CNT_ID:
311 	case EXT_CC_VPORT_CMD:
312 	case EXT_CC_ACCESS_FLASH:
313 	case EXT_CC_RESET_FW:
314 	case EXT_CC_MENLO_MANAGE_INFO:
315 	case EXT_CC_I2C_DATA:
316 	case EXT_CC_DUMP:
317 	case EXT_CC_SERDES_REG_OP:
318 	case EXT_CC_VF_STATE:
319 	case EXT_CC_SERDES_REG_OP_EX:
320 	case EXT_CC_ELS_PASSTHRU_OS:
321 	case EXT_CC_FLASH_UPDATE_CAPS_OS:
322 	case EXT_CC_GET_BBCR_DATA_OS:
323 		rval = ql_sdm_ioctl(ha, cmd, (void *)arg, mode);
324 		break;
325 	default:
326 		/* function not supported. */
327 		EL(ha, "function=%d not supported\n", cmd);
328 		rval = ENOPROTOOPT;
329 	}
330 
331 	QL_PRINT_9(ha, "done\n");
332 
333 	return (rval);
334 }
335 
336 /*
337  * ql_sdm_ioctl
338  *	Provides ioctl functions for SAN/Device Management functions
339  *	AKA External Ioctl functions.
340  *
341  * Input:
342  *	ha:		adapter state pointer.
343  *	ioctl_code:	ioctl function to perform
344  *	arg:		Pointer to EXT_IOCTL cmd data in application land.
345  *	mode:		flags
346  *
347  * Returns:
348  *	0:	success
349  *	ENOMEM:	Alloc of local EXT_IOCTL struct failed.
350  *	EFAULT:	Copyin of caller's EXT_IOCTL struct failed or
351  *		copyout of EXT_IOCTL status info failed.
352  *	EINVAL:	Signature or version of caller's EXT_IOCTL invalid.
353  *	EBUSY:	Device busy
354  *
355  * Context:
356  *	Kernel context.
357  */
358 static int
ql_sdm_ioctl(ql_adapter_state_t * ha,int ioctl_code,void * arg,int mode)359 ql_sdm_ioctl(ql_adapter_state_t *ha, int ioctl_code, void *arg, int mode)
360 {
361 	EXT_IOCTL		*cmd;
362 	int			rval;
363 	ql_adapter_state_t	*vha;
364 
365 	QL_PRINT_9(ha, "started\n");
366 
367 	/* Copy argument structure (EXT_IOCTL) from application land. */
368 	if ((rval = ql_sdm_setup(ha, &cmd, arg, mode,
369 	    ql_validate_signature)) != 0) {
370 		/*
371 		 * a non-zero value at this time means a problem getting
372 		 * the requested information from application land, just
373 		 * return the error code and hope for the best.
374 		 */
375 		EL(ha, "failed, sdm_setup\n");
376 		return (rval);
377 	}
378 
379 	/*
380 	 * Map the physical ha ptr (which the ioctl is called with)
381 	 * to the virtual ha that the caller is addressing.
382 	 */
383 	if (ha->flags & VP_ENABLED) {
384 		/* Check that it is within range. */
385 		if (cmd->HbaSelect > ha->max_vports) {
386 			EL(ha, "Invalid HbaSelect vp index: %xh\n",
387 			    cmd->HbaSelect);
388 			cmd->Status = EXT_STATUS_INVALID_VPINDEX;
389 			cmd->ResponseLen = 0;
390 			return (EFAULT);
391 		}
392 		/*
393 		 * Special case: HbaSelect == 0 is physical ha
394 		 */
395 		if (cmd->HbaSelect != 0) {
396 			vha = ha->vp_next;
397 			while (vha != NULL) {
398 				if (vha->vp_index == cmd->HbaSelect) {
399 					ha = vha;
400 					break;
401 				}
402 				vha = vha->vp_next;
403 			}
404 			/*
405 			 * The specified vp index may be valid(within range)
406 			 * but it's not in the list. Currently this is all
407 			 * we can say.
408 			 */
409 			if (vha == NULL || !(vha->flags & VP_ENABLED)) {
410 				cmd->Status = EXT_STATUS_INVALID_VPINDEX;
411 				cmd->ResponseLen = 0;
412 				return (EFAULT);
413 			}
414 		}
415 	}
416 
417 	/*
418 	 * If driver is suspended, stalled, or powered down rtn BUSY
419 	 */
420 	if (ha->flags & ADAPTER_SUSPENDED ||
421 	    (ha->task_daemon_flags & (DRIVER_STALL | ISP_ABORT_NEEDED |
422 	    ABORT_ISP_ACTIVE | LOOP_RESYNC_NEEDED | LOOP_RESYNC_ACTIVE)) ||
423 	    ha->power_level != PM_LEVEL_D0) {
424 		EL(ha, " %s\n", ha->flags & ADAPTER_SUSPENDED ?
425 		    "driver suspended" :
426 		    (ha->task_daemon_flags & (DRIVER_STALL | ISP_ABORT_NEEDED |
427 		    ABORT_ISP_ACTIVE | LOOP_RESYNC_NEEDED |
428 		    LOOP_RESYNC_ACTIVE) ? "driver stalled" :
429 		    "FCA powered down"));
430 		cmd->Status = EXT_STATUS_BUSY;
431 		cmd->ResponseLen = 0;
432 		rval = EBUSY;
433 
434 		/* Return results to caller */
435 		if ((ql_sdm_return(ha, cmd, arg, mode)) == -1) {
436 			EL(ha, "failed, sdm_return\n");
437 			rval = EFAULT;
438 		}
439 		return (rval);
440 	}
441 
442 	switch (ioctl_code) {
443 	case EXT_CC_QUERY_OS:
444 		ql_query(ha, cmd, mode);
445 		break;
446 	case EXT_CC_SEND_FCCT_PASSTHRU_OS:
447 		ql_fcct(ha, cmd, mode);
448 		break;
449 	case EXT_CC_REG_AEN_OS:
450 		ql_aen_reg(ha, cmd, mode);
451 		break;
452 	case EXT_CC_GET_AEN_OS:
453 		ql_aen_get(ha, cmd, mode);
454 		break;
455 	case EXT_CC_GET_DATA_OS:
456 		ql_get_host_data(ha, cmd, mode);
457 		break;
458 	case EXT_CC_SET_DATA_OS:
459 		ql_set_host_data(ha, cmd, mode);
460 		break;
461 	case EXT_CC_SEND_ELS_RNID_OS:
462 		ql_send_els_rnid(ha, cmd, mode);
463 		break;
464 	case EXT_CC_SCSI_PASSTHRU_OS:
465 		ql_scsi_passthru(ha, cmd, mode);
466 		break;
467 	case EXT_CC_WWPN_TO_SCSIADDR_OS:
468 		ql_wwpn_to_scsiaddr(ha, cmd, mode);
469 		break;
470 	case EXT_CC_HOST_IDX_OS:
471 		ql_host_idx(ha, cmd, mode);
472 		break;
473 	case EXT_CC_HOST_DRVNAME_OS:
474 		ql_host_drvname(ha, cmd, mode);
475 		break;
476 	case EXT_CC_READ_NVRAM_OS:
477 		ql_read_nvram(ha, cmd, mode);
478 		break;
479 	case EXT_CC_UPDATE_NVRAM_OS:
480 		ql_write_nvram(ha, cmd, mode);
481 		break;
482 	case EXT_CC_READ_OPTION_ROM_OS:
483 	case EXT_CC_READ_OPTION_ROM_EX_OS:
484 		ql_read_flash(ha, cmd, mode);
485 		break;
486 	case EXT_CC_UPDATE_OPTION_ROM_OS:
487 	case EXT_CC_UPDATE_OPTION_ROM_EX_OS:
488 		ql_write_flash(ha, cmd, mode);
489 		break;
490 	case EXT_CC_LOOPBACK_OS:
491 		ql_diagnostic_loopback(ha, cmd, mode);
492 		break;
493 	case EXT_CC_GET_VPD_OS:
494 		ql_read_vpd(ha, cmd, mode);
495 		break;
496 	case EXT_CC_SET_VPD_OS:
497 		ql_write_vpd(ha, cmd, mode);
498 		break;
499 	case EXT_CC_GET_FCACHE_OS:
500 		ql_get_fcache(ha, cmd, mode);
501 		break;
502 	case EXT_CC_GET_FCACHE_EX_OS:
503 		ql_get_fcache_ex(ha, cmd, mode);
504 		break;
505 	case EXT_CC_GET_SFP_DATA_OS:
506 		ql_get_sfp(ha, cmd, mode);
507 		break;
508 	case EXT_CC_PORT_PARAM_OS:
509 		ql_port_param(ha, cmd, mode);
510 		break;
511 	case EXT_CC_GET_PCI_DATA_OS:
512 		ql_get_pci_data(ha, cmd, mode);
513 		break;
514 	case EXT_CC_GET_FWEXTTRACE_OS:
515 		ql_get_fwexttrace(ha, cmd, mode);
516 		break;
517 	case EXT_CC_GET_FWFCETRACE_OS:
518 		ql_get_fwfcetrace(ha, cmd, mode);
519 		break;
520 	case EXT_CC_MENLO_RESET:
521 		ql_menlo_reset(ha, cmd, mode);
522 		break;
523 	case EXT_CC_MENLO_GET_FW_VERSION:
524 		ql_menlo_get_fw_version(ha, cmd, mode);
525 		break;
526 	case EXT_CC_MENLO_UPDATE_FW:
527 		ql_menlo_update_fw(ha, cmd, mode);
528 		break;
529 	case EXT_CC_MENLO_MANAGE_INFO:
530 		ql_menlo_manage_info(ha, cmd, mode);
531 		break;
532 	case EXT_CC_GET_VP_CNT_ID_OS:
533 		ql_get_vp_cnt_id(ha, cmd, mode);
534 		break;
535 	case EXT_CC_VPORT_CMD_OS:
536 		ql_vp_ioctl(ha, cmd, mode);
537 		break;
538 	case EXT_CC_ACCESS_FLASH_OS:
539 		ql_access_flash(ha, cmd, mode);
540 		break;
541 	case EXT_CC_RESET_FW_OS:
542 		ql_reset_cmd(ha, cmd);
543 		break;
544 	case EXT_CC_I2C_DATA:
545 		ql_get_temperature(ha, cmd, mode);
546 		break;
547 	case EXT_CC_DUMP_OS:
548 		ql_dump_cmd(ha, cmd, mode);
549 		break;
550 	case EXT_CC_SERDES_REG_OP:
551 		ql_serdes_reg(ha, cmd, mode);
552 		break;
553 	case EXT_CC_SERDES_REG_OP_EX:
554 		ql_serdes_reg_ex(ha, cmd, mode);
555 		break;
556 	case EXT_CC_ELS_PASSTHRU_OS:
557 		ql_els_passthru(ha, cmd, mode);
558 		break;
559 	case EXT_CC_FLASH_UPDATE_CAPS_OS:
560 		ql_flash_update_caps(ha, cmd, mode);
561 		break;
562 	case EXT_CC_GET_BBCR_DATA_OS:
563 		ql_get_bbcr_data(ha, cmd, mode);
564 		break;
565 	default:
566 		/* function not supported. */
567 		EL(ha, "failed, function not supported=%d\n", ioctl_code);
568 
569 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
570 		cmd->ResponseLen = 0;
571 		break;
572 	}
573 
574 	/* Return results to caller */
575 	if (ql_sdm_return(ha, cmd, arg, mode) == -1) {
576 		EL(ha, "failed, sdm_return\n");
577 		return (EFAULT);
578 	}
579 
580 	QL_PRINT_9(ha, "done\n");
581 
582 	return (0);
583 }
584 
585 /*
586  * ql_sdm_setup
587  *	Make a local copy of the EXT_IOCTL struct and validate it.
588  *
589  * Input:
590  *	ha:		adapter state pointer.
591  *	cmd_struct:	Pointer to location to store local adrs of EXT_IOCTL.
592  *	arg:		Address of application EXT_IOCTL cmd data
593  *	mode:		flags
594  *	val_sig:	Pointer to a function to validate the ioctl signature.
595  *
596  * Returns:
597  *	0:		success
598  *	EFAULT:		Copy in error of application EXT_IOCTL struct.
599  *	EINVAL:		Invalid version, signature.
600  *	ENOMEM:		Local allocation of EXT_IOCTL failed.
601  *
602  * Context:
603  *	Kernel context.
604  */
605 static int
ql_sdm_setup(ql_adapter_state_t * ha,EXT_IOCTL ** cmd_struct,void * arg,int mode,boolean_t (* val_sig)(EXT_IOCTL *))606 ql_sdm_setup(ql_adapter_state_t *ha, EXT_IOCTL **cmd_struct, void *arg,
607     int mode, boolean_t (*val_sig)(EXT_IOCTL *))
608 {
609 	int		rval;
610 	EXT_IOCTL	*cmd;
611 
612 	QL_PRINT_9(ha, "started\n");
613 
614 	/* Allocate local memory for EXT_IOCTL. */
615 	*cmd_struct = NULL;
616 	cmd = (EXT_IOCTL *)kmem_zalloc(sizeof (EXT_IOCTL), KM_SLEEP);
617 	if (cmd == NULL) {
618 		EL(ha, "failed, kmem_zalloc\n");
619 		return (ENOMEM);
620 	}
621 	/* Get argument structure. */
622 	rval = ddi_copyin(arg, (void *)cmd, sizeof (EXT_IOCTL), mode);
623 	if (rval != 0) {
624 		EL(ha, "failed, ddi_copyin\n");
625 		rval = EFAULT;
626 	} else {
627 		/*
628 		 * Check signature and the version.
629 		 * If either are not valid then neither is the
630 		 * structure so don't attempt to return any error status
631 		 * because we can't trust what caller's arg points to.
632 		 * Just return the errno.
633 		 */
634 		if (val_sig(cmd) == 0) {
635 			EL(ha, "failed, signature\n");
636 			rval = EINVAL;
637 		} else if (cmd->Version > EXT_VERSION) {
638 			EL(ha, "failed, version\n");
639 			rval = EINVAL;
640 		}
641 	}
642 
643 	if (rval == 0) {
644 		QL_PRINT_9(ha, "done\n");
645 		*cmd_struct = cmd;
646 		cmd->Status = EXT_STATUS_OK;
647 		cmd->DetailStatus = 0;
648 	} else {
649 		kmem_free((void *)cmd, sizeof (EXT_IOCTL));
650 	}
651 
652 	return (rval);
653 }
654 
655 /*
656  * ql_validate_signature
657  *	Validate the signature string for an external ioctl call.
658  *
659  * Input:
660  *	sg:	Pointer to EXT_IOCTL signature to validate.
661  *
662  * Returns:
663  *	B_TRUE:		Signature is valid.
664  *	B_FALSE:	Signature is NOT valid.
665  *
666  * Context:
667  *	Kernel context.
668  */
669 static boolean_t
ql_validate_signature(EXT_IOCTL * cmd_struct)670 ql_validate_signature(EXT_IOCTL *cmd_struct)
671 {
672 	/*
673 	 * Check signature.
674 	 *
675 	 * If signature is not valid then neither is the rest of
676 	 * the structure (e.g., can't trust it), so don't attempt
677 	 * to return any error status other than the errno.
678 	 */
679 	if (bcmp(&cmd_struct->Signature, "QLOGIC", 6) != 0) {
680 		QL_PRINT_2(NULL, "failed,\n");
681 		return (B_FALSE);
682 	}
683 
684 	return (B_TRUE);
685 }
686 
687 /*
688  * ql_sdm_return
689  *	Copies return data/status to application land for
690  *	ioctl call using the SAN/Device Management EXT_IOCTL call interface.
691  *
692  * Input:
693  *	ha:		adapter state pointer.
694  *	cmd:		Pointer to kernel copy of requestor's EXT_IOCTL struct.
695  *	ioctl_code:	ioctl function to perform
696  *	arg:		EXT_IOCTL cmd data in application land.
697  *	mode:		flags
698  *
699  * Returns:
700  *	0:	success
701  *	EFAULT:	Copy out error.
702  *
703  * Context:
704  *	Kernel context.
705  */
706 /* ARGSUSED */
707 static int
ql_sdm_return(ql_adapter_state_t * ha,EXT_IOCTL * cmd,void * arg,int mode)708 ql_sdm_return(ql_adapter_state_t *ha, EXT_IOCTL *cmd, void *arg, int mode)
709 {
710 	int	rval = 0;
711 
712 	QL_PRINT_9(ha, "started\n");
713 
714 	rval |= ddi_copyout((void *)&cmd->ResponseLen,
715 	    (void *)&(((EXT_IOCTL*)arg)->ResponseLen), sizeof (uint32_t),
716 	    mode);
717 
718 	rval |= ddi_copyout((void *)&cmd->Status,
719 	    (void *)&(((EXT_IOCTL*)arg)->Status),
720 	    sizeof (cmd->Status), mode);
721 	rval |= ddi_copyout((void *)&cmd->DetailStatus,
722 	    (void *)&(((EXT_IOCTL*)arg)->DetailStatus),
723 	    sizeof (cmd->DetailStatus), mode);
724 
725 	kmem_free((void *)cmd, sizeof (EXT_IOCTL));
726 
727 	if (rval != 0) {
728 		/* Some copyout operation failed */
729 		EL(ha, "failed, ddi_copyout\n");
730 		return (EFAULT);
731 	}
732 
733 	QL_PRINT_9(ha, "done\n");
734 
735 	return (0);
736 }
737 
738 /*
739  * ql_query
740  *	Performs all EXT_CC_QUERY functions.
741  *
742  * Input:
743  *	ha:	adapter state pointer.
744  *	cmd:	Local EXT_IOCTL cmd struct pointer.
745  *	mode:	flags.
746  *
747  * Returns:
748  *	None, request status indicated in cmd->Status.
749  *
750  * Context:
751  *	Kernel context.
752  */
753 static void
ql_query(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)754 ql_query(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
755 {
756 	QL_PRINT_9(ha, "started, cmd=%d\n",
757 	    cmd->SubCode);
758 
759 	/* case off on command subcode */
760 	switch (cmd->SubCode) {
761 	case EXT_SC_QUERY_HBA_NODE:
762 		ql_qry_hba_node(ha, cmd, mode);
763 		break;
764 	case EXT_SC_QUERY_HBA_PORT:
765 		ql_qry_hba_port(ha, cmd, mode);
766 		break;
767 	case EXT_SC_QUERY_DISC_PORT:
768 		ql_qry_disc_port(ha, cmd, mode);
769 		break;
770 	case EXT_SC_QUERY_DISC_TGT:
771 		ql_qry_disc_tgt(ha, cmd, mode);
772 		break;
773 	case EXT_SC_QUERY_DRIVER:
774 		ql_qry_driver(ha, cmd, mode);
775 		break;
776 	case EXT_SC_QUERY_FW:
777 		ql_qry_fw(ha, cmd, mode);
778 		break;
779 	case EXT_SC_QUERY_CHIP:
780 		ql_qry_chip(ha, cmd, mode);
781 		break;
782 	case EXT_SC_QUERY_CNA_PORT:
783 		ql_qry_cna_port(ha, cmd, mode);
784 		break;
785 	case EXT_SC_QUERY_ADAPTER_VERSIONS:
786 		ql_qry_adapter_versions(ha, cmd, mode);
787 		break;
788 	case EXT_SC_QUERY_DISC_LUN:
789 	default:
790 		/* function not supported. */
791 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
792 		EL(ha, "failed, Unsupported Subcode=%xh\n",
793 		    cmd->SubCode);
794 		break;
795 	}
796 
797 	QL_PRINT_9(ha, "done\n");
798 }
799 
800 /*
801  * ql_qry_hba_node
802  *	Performs EXT_SC_QUERY_HBA_NODE subfunction.
803  *
804  * Input:
805  *	ha:	adapter state pointer.
806  *	cmd:	EXT_IOCTL cmd struct pointer.
807  *	mode:	flags.
808  *
809  * Returns:
810  *	None, request status indicated in cmd->Status.
811  *
812  * Context:
813  *	Kernel context.
814  */
815 static void
ql_qry_hba_node(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)816 ql_qry_hba_node(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
817 {
818 	EXT_HBA_NODE	tmp_node = {0};
819 	uint_t		len;
820 	caddr_t		bufp;
821 
822 	QL_PRINT_9(ha, "started\n");
823 
824 	if (cmd->ResponseLen < sizeof (EXT_HBA_NODE)) {
825 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
826 		cmd->DetailStatus = sizeof (EXT_HBA_NODE);
827 		EL(ha, "failed, ResponseLen < EXT_HBA_NODE, "
828 		    "Len=%xh\n", cmd->ResponseLen);
829 		cmd->ResponseLen = 0;
830 		return;
831 	}
832 
833 	/* fill in the values */
834 
835 	bcopy(ha->loginparams.node_ww_name.raw_wwn, tmp_node.WWNN,
836 	    EXT_DEF_WWN_NAME_SIZE);
837 
838 	(void) sprintf((char *)(tmp_node.Manufacturer), "QLogic Corporation");
839 
840 	(void) sprintf((char *)(tmp_node.Model), "%x", ha->device_id);
841 
842 	bcopy(&tmp_node.WWNN[5], tmp_node.SerialNum, 3);
843 
844 	(void) sprintf((char *)(tmp_node.DriverVersion), QL_VERSION);
845 
846 	if (CFG_IST(ha, CFG_SBUS_CARD)) {
847 		size_t		verlen;
848 		uint16_t	w;
849 		char		*tmpptr;
850 
851 		verlen = strlen((char *)(tmp_node.DriverVersion));
852 		if (verlen + 5 > EXT_DEF_MAX_STR_SIZE) {
853 			EL(ha, "failed, No room for fpga version string\n");
854 		} else {
855 			w = (uint16_t)ddi_get16(ha->sbus_fpga_dev_handle,
856 			    (uint16_t *)
857 			    (ha->sbus_fpga_iobase + FPGA_REVISION));
858 
859 			tmpptr = (char *)&(tmp_node.DriverVersion[verlen + 1]);
860 			if (tmpptr == NULL) {
861 				EL(ha, "Unable to insert fpga version str\n");
862 			} else {
863 				(void) sprintf(tmpptr, "%d.%d",
864 				    ((w & 0xf0) >> 4), (w & 0x0f));
865 				tmp_node.DriverAttr |= EXT_CC_HBA_NODE_SBUS;
866 			}
867 		}
868 	}
869 
870 	(void) sprintf((char *)(tmp_node.FWVersion), "%01d.%02d.%02d",
871 	    ha->fw_major_version, ha->fw_minor_version,
872 	    ha->fw_subminor_version);
873 
874 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
875 		switch (ha->fw_attributes) {
876 		case FWATTRIB_EF:
877 			(void) strcat((char *)(tmp_node.FWVersion), " EF");
878 			break;
879 		case FWATTRIB_TP:
880 			(void) strcat((char *)(tmp_node.FWVersion), " TP");
881 			break;
882 		case FWATTRIB_IP:
883 			(void) strcat((char *)(tmp_node.FWVersion), " IP");
884 			break;
885 		case FWATTRIB_IPX:
886 			(void) strcat((char *)(tmp_node.FWVersion), " IPX");
887 			break;
888 		case FWATTRIB_FL:
889 			(void) strcat((char *)(tmp_node.FWVersion), " FL");
890 			break;
891 		case FWATTRIB_FPX:
892 			(void) strcat((char *)(tmp_node.FWVersion), " FLX");
893 			break;
894 		default:
895 			break;
896 		}
897 	}
898 
899 	/* FCode version. */
900 	/*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
901 	if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip, PROP_LEN_AND_VAL_ALLOC |
902 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
903 	    (int *)&len) == DDI_PROP_SUCCESS) {
904 		if (len < EXT_DEF_MAX_STR_SIZE) {
905 			bcopy(bufp, tmp_node.OptRomVersion, len);
906 		} else {
907 			bcopy(bufp, tmp_node.OptRomVersion,
908 			    EXT_DEF_MAX_STR_SIZE - 1);
909 			tmp_node.OptRomVersion[EXT_DEF_MAX_STR_SIZE - 1] =
910 			    '\0';
911 		}
912 		kmem_free(bufp, len);
913 	} else {
914 		(void) sprintf((char *)tmp_node.OptRomVersion, "0");
915 	}
916 	tmp_node.PortCount = 1;
917 	tmp_node.InterfaceType = EXT_DEF_FC_INTF_TYPE;
918 
919 	tmp_node.MpiVersion[0] = ha->mpi_fw_major_version;
920 	tmp_node.MpiVersion[1] = ha->mpi_fw_minor_version;
921 	tmp_node.MpiVersion[2] = ha->mpi_fw_subminor_version;
922 	tmp_node.PepFwVersion[0] = ha->phy_fw_major_version;
923 	tmp_node.PepFwVersion[1] = ha->phy_fw_minor_version;
924 	tmp_node.PepFwVersion[2] = ha->phy_fw_subminor_version;
925 	if (ddi_copyout((void *)&tmp_node,
926 	    (void *)(uintptr_t)(cmd->ResponseAdr),
927 	    sizeof (EXT_HBA_NODE), mode) != 0) {
928 		cmd->Status = EXT_STATUS_COPY_ERR;
929 		cmd->ResponseLen = 0;
930 		EL(ha, "failed, ddi_copyout\n");
931 	} else {
932 		cmd->ResponseLen = sizeof (EXT_HBA_NODE);
933 		QL_PRINT_9(ha, "done\n");
934 	}
935 }
936 
937 /*
938  * ql_qry_hba_port
939  *	Performs EXT_SC_QUERY_HBA_PORT subfunction.
940  *
941  * Input:
942  *	ha:	adapter state pointer.
943  *	cmd:	EXT_IOCTL cmd struct pointer.
944  *	mode:	flags.
945  *
946  * Returns:
947  *	None, request status indicated in cmd->Status.
948  *
949  * Context:
950  *	Kernel context.
951  */
952 static void
ql_qry_hba_port(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)953 ql_qry_hba_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
954 {
955 	ql_link_t	*link;
956 	ql_tgt_t	*tq;
957 	ql_mbx_data_t	mr = {0};
958 	EXT_HBA_PORT	tmp_port = {0};
959 	int		rval;
960 	uint16_t	port_cnt, tgt_cnt, index;
961 
962 	QL_PRINT_9(ha, "started\n");
963 
964 	if (cmd->ResponseLen < sizeof (EXT_HBA_PORT)) {
965 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
966 		cmd->DetailStatus = sizeof (EXT_HBA_PORT);
967 		EL(ha, "failed, ResponseLen < EXT_HBA_NODE, Len=%xh\n",
968 		    cmd->ResponseLen);
969 		cmd->ResponseLen = 0;
970 		return;
971 	}
972 
973 	/* fill in the values */
974 
975 	bcopy(ha->loginparams.nport_ww_name.raw_wwn, tmp_port.WWPN,
976 	    EXT_DEF_WWN_NAME_SIZE);
977 	tmp_port.Id[0] = 0;
978 	tmp_port.Id[1] = ha->d_id.b.domain;
979 	tmp_port.Id[2] = ha->d_id.b.area;
980 	tmp_port.Id[3] = ha->d_id.b.al_pa;
981 
982 	/* For now we are initiator only driver */
983 	tmp_port.Type = EXT_DEF_INITIATOR_DEV;
984 
985 	if (ha->task_daemon_flags & LOOP_DOWN) {
986 		tmp_port.State = EXT_DEF_HBA_LOOP_DOWN;
987 	} else if (DRIVER_SUSPENDED(ha)) {
988 		tmp_port.State = EXT_DEF_HBA_SUSPENDED;
989 	} else {
990 		tmp_port.State = EXT_DEF_HBA_OK;
991 	}
992 
993 	if (ha->flags & POINT_TO_POINT) {
994 		tmp_port.Mode = EXT_DEF_P2P_MODE;
995 	} else {
996 		tmp_port.Mode = EXT_DEF_LOOP_MODE;
997 	}
998 	/*
999 	 * fill in the portspeed values.
1000 	 *
1001 	 * default to not yet negotiated state
1002 	 */
1003 	tmp_port.PortSpeed = EXT_PORTSPEED_NOT_NEGOTIATED;
1004 
1005 	if (tmp_port.State == EXT_DEF_HBA_OK) {
1006 		switch (ha->iidma_rate) {
1007 		case IIDMA_RATE_1GB:
1008 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_1GBIT;
1009 			break;
1010 		case IIDMA_RATE_2GB:
1011 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_2GBIT;
1012 			break;
1013 		case IIDMA_RATE_4GB:
1014 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_4GBIT;
1015 			break;
1016 		case IIDMA_RATE_8GB:
1017 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_8GBIT;
1018 			break;
1019 		case IIDMA_RATE_10GB:
1020 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_10GBIT;
1021 			break;
1022 		case IIDMA_RATE_16GB:
1023 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_16GBIT;
1024 			break;
1025 		case IIDMA_RATE_32GB:
1026 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_32GBIT;
1027 			break;
1028 		default:
1029 			tmp_port.PortSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
1030 			EL(ha, "failed, data rate=%xh\n", mr.mb[1]);
1031 			break;
1032 		}
1033 	}
1034 
1035 	/* Report all supported port speeds */
1036 	if (CFG_IST(ha, CFG_CTRL_25XX)) {
1037 		tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_8GBIT |
1038 		    EXT_DEF_PORTSPEED_4GBIT | EXT_DEF_PORTSPEED_2GBIT |
1039 		    EXT_DEF_PORTSPEED_1GBIT);
1040 		/*
1041 		 * Correct supported speeds based on type of
1042 		 * sfp that is present
1043 		 */
1044 		switch (ha->sfp_stat) {
1045 		case 1:
1046 			/* no sfp detected */
1047 			break;
1048 		case 2:
1049 		case 4:
1050 			/* 4GB sfp */
1051 			tmp_port.PortSupportedSpeed &=
1052 			    ~EXT_DEF_PORTSPEED_8GBIT;
1053 			break;
1054 		case 3:
1055 		case 5:
1056 			/* 8GB sfp */
1057 			tmp_port.PortSupportedSpeed &=
1058 			    ~EXT_DEF_PORTSPEED_1GBIT;
1059 			break;
1060 		default:
1061 			EL(ha, "sfp_stat: %xh\n", ha->sfp_stat);
1062 			break;
1063 
1064 		}
1065 	} else if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
1066 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_10GBIT;
1067 	} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
1068 		tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_4GBIT |
1069 		    EXT_DEF_PORTSPEED_2GBIT | EXT_DEF_PORTSPEED_1GBIT);
1070 	} else if (CFG_IST(ha, CFG_CTRL_23XX)) {
1071 		tmp_port.PortSupportedSpeed = (EXT_DEF_PORTSPEED_2GBIT |
1072 		    EXT_DEF_PORTSPEED_1GBIT);
1073 	} else if (CFG_IST(ha, CFG_CTRL_63XX)) {
1074 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_2GBIT;
1075 	} else if (CFG_IST(ha, CFG_CTRL_22XX)) {
1076 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_1GBIT;
1077 	} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
1078 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_4GBIT |
1079 		    EXT_DEF_PORTSPEED_8GBIT | EXT_DEF_PORTSPEED_16GBIT;
1080 	} else if (CFG_IST(ha, CFG_CTRL_27XX)) {
1081 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_4GBIT |
1082 		    EXT_DEF_PORTSPEED_8GBIT | EXT_DEF_PORTSPEED_16GBIT |
1083 		    EXT_DEF_PORTSPEED_32GBIT;
1084 	} else {
1085 		tmp_port.PortSupportedSpeed = EXT_DEF_PORTSPEED_UNKNOWN;
1086 		EL(ha, "unknown HBA type: %xh\n", ha->device_id);
1087 	}
1088 
1089 	if (ha->task_daemon_flags & LOOP_DOWN) {
1090 		(void) ql_get_firmware_state(ha, NULL);
1091 	}
1092 
1093 	tmp_port.LinkState1 = ha->fw_state[1];
1094 	tmp_port.LinkState2 = LSB(ha->sfp_stat);
1095 	tmp_port.LinkState3 = ha->fw_state[3];
1096 	tmp_port.LinkState6 = ha->fw_state[6];
1097 
1098 	port_cnt = 0;
1099 	tgt_cnt = 0;
1100 
1101 	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
1102 		for (link = ha->dev[index].first; link != NULL;
1103 		    link = link->next) {
1104 			tq = link->base_address;
1105 
1106 			if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1107 			    tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
1108 				continue;
1109 			}
1110 
1111 			if (tq->flags & (TQF_RSCN_RCVD | TQF_IIDMA_NEEDED |
1112 			    TQF_NEED_AUTHENTICATION | TQF_PLOGI_PROGRS)) {
1113 				continue;
1114 			}
1115 
1116 			port_cnt++;
1117 			if ((tq->flags & TQF_INITIATOR_DEVICE) == 0) {
1118 				tgt_cnt++;
1119 			}
1120 		}
1121 	}
1122 
1123 	tmp_port.DiscPortCount = port_cnt;
1124 	tmp_port.DiscTargetCount = tgt_cnt;
1125 
1126 	tmp_port.DiscPortNameType = EXT_DEF_USE_NODE_NAME;
1127 
1128 	rval = ddi_copyout((void *)&tmp_port,
1129 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1130 	    sizeof (EXT_HBA_PORT), mode);
1131 	if (rval != 0) {
1132 		cmd->Status = EXT_STATUS_COPY_ERR;
1133 		cmd->ResponseLen = 0;
1134 		EL(ha, "failed, ddi_copyout\n");
1135 	} else {
1136 		cmd->ResponseLen = sizeof (EXT_HBA_PORT);
1137 		QL_PRINT_9(ha, "done, ports=%d, targets=%d\n",
1138 		    ha->instance, port_cnt, tgt_cnt);
1139 	}
1140 }
1141 
1142 /*
1143  * ql_qry_disc_port
1144  *	Performs EXT_SC_QUERY_DISC_PORT subfunction.
1145  *
1146  * Input:
1147  *	ha:	adapter state pointer.
1148  *	cmd:	EXT_IOCTL cmd struct pointer.
1149  *	mode:	flags.
1150  *
1151  *	cmd->Instance = Port instance in fcport chain.
1152  *
1153  * Returns:
1154  *	None, request status indicated in cmd->Status.
1155  *
1156  * Context:
1157  *	Kernel context.
1158  */
1159 static void
ql_qry_disc_port(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1160 ql_qry_disc_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1161 {
1162 	EXT_DISC_PORT	tmp_port = {0};
1163 	ql_link_t	*link;
1164 	ql_tgt_t	*tq;
1165 	uint16_t	index;
1166 	uint16_t	inst = 0;
1167 
1168 	QL_PRINT_9(ha, "started\n");
1169 
1170 	if (cmd->ResponseLen < sizeof (EXT_DISC_PORT)) {
1171 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1172 		cmd->DetailStatus = sizeof (EXT_DISC_PORT);
1173 		EL(ha, "failed, ResponseLen < EXT_DISC_PORT, Len=%xh\n",
1174 		    cmd->ResponseLen);
1175 		cmd->ResponseLen = 0;
1176 		return;
1177 	}
1178 
1179 	for (link = NULL, index = 0;
1180 	    index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1181 		for (link = ha->dev[index].first; link != NULL;
1182 		    link = link->next) {
1183 			tq = link->base_address;
1184 
1185 			if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1186 			    tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
1187 				continue;
1188 			}
1189 
1190 			if (tq->flags & (TQF_RSCN_RCVD | TQF_IIDMA_NEEDED |
1191 			    TQF_NEED_AUTHENTICATION | TQF_PLOGI_PROGRS)) {
1192 				continue;
1193 			}
1194 
1195 			if (inst != cmd->Instance) {
1196 				inst++;
1197 				continue;
1198 			}
1199 
1200 			/* fill in the values */
1201 			bcopy(tq->node_name, tmp_port.WWNN,
1202 			    EXT_DEF_WWN_NAME_SIZE);
1203 			bcopy(tq->port_name, tmp_port.WWPN,
1204 			    EXT_DEF_WWN_NAME_SIZE);
1205 
1206 			break;
1207 		}
1208 	}
1209 
1210 	if (link == NULL) {
1211 		/* no matching device */
1212 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1213 		EL(ha, "failed, port not found port=%d\n", cmd->Instance);
1214 		cmd->ResponseLen = 0;
1215 		return;
1216 	}
1217 
1218 	tmp_port.Id[0] = 0;
1219 	tmp_port.Id[1] = tq->d_id.b.domain;
1220 	tmp_port.Id[2] = tq->d_id.b.area;
1221 	tmp_port.Id[3] = tq->d_id.b.al_pa;
1222 
1223 	tmp_port.Type = 0;
1224 	if (tq->flags & TQF_INITIATOR_DEVICE) {
1225 		tmp_port.Type = (uint16_t)(tmp_port.Type |
1226 		    EXT_DEF_INITIATOR_DEV);
1227 	} else if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1228 		(void) ql_inq_scan(ha, tq, 1);
1229 	} else if (tq->flags & TQF_TAPE_DEVICE) {
1230 		tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TAPE_DEV);
1231 	}
1232 
1233 	if (tq->flags & TQF_FABRIC_DEVICE) {
1234 		tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_FABRIC_DEV);
1235 	} else {
1236 		tmp_port.Type = (uint16_t)(tmp_port.Type | EXT_DEF_TARGET_DEV);
1237 	}
1238 
1239 	tmp_port.Status = 0;
1240 	tmp_port.Bus = 0;  /* Hard-coded for Solaris */
1241 
1242 	bcopy(tq->port_name, &tmp_port.TargetId, 8);
1243 
1244 	if (ddi_copyout((void *)&tmp_port,
1245 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1246 	    sizeof (EXT_DISC_PORT), mode) != 0) {
1247 		cmd->Status = EXT_STATUS_COPY_ERR;
1248 		cmd->ResponseLen = 0;
1249 		EL(ha, "failed, ddi_copyout\n");
1250 	} else {
1251 		cmd->ResponseLen = sizeof (EXT_DISC_PORT);
1252 		QL_PRINT_9(ha, "done\n");
1253 	}
1254 }
1255 
1256 /*
1257  * ql_qry_disc_tgt
1258  *	Performs EXT_SC_QUERY_DISC_TGT subfunction.
1259  *
1260  * Input:
1261  *	ha:		adapter state pointer.
1262  *	cmd:		EXT_IOCTL cmd struct pointer.
1263  *	mode:		flags.
1264  *
1265  *	cmd->Instance = Port instance in fcport chain.
1266  *
1267  * Returns:
1268  *	None, request status indicated in cmd->Status.
1269  *
1270  * Context:
1271  *	Kernel context.
1272  */
1273 static void
ql_qry_disc_tgt(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1274 ql_qry_disc_tgt(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1275 {
1276 	EXT_DISC_TARGET	tmp_tgt = {0};
1277 	ql_link_t	*link;
1278 	ql_tgt_t	*tq;
1279 	uint16_t	index;
1280 	uint16_t	inst = 0;
1281 
1282 	QL_PRINT_9(ha, "started, target=%d\n",
1283 	    cmd->Instance);
1284 
1285 	if (cmd->ResponseLen < sizeof (EXT_DISC_TARGET)) {
1286 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1287 		cmd->DetailStatus = sizeof (EXT_DISC_TARGET);
1288 		EL(ha, "failed, ResponseLen < EXT_DISC_TARGET, Len=%xh\n",
1289 		    cmd->ResponseLen);
1290 		cmd->ResponseLen = 0;
1291 		return;
1292 	}
1293 
1294 	/* Scan port list for requested target and fill in the values */
1295 	for (link = NULL, index = 0;
1296 	    index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1297 		for (link = ha->dev[index].first; link != NULL;
1298 		    link = link->next) {
1299 			tq = link->base_address;
1300 
1301 			if (!VALID_TARGET_ID(ha, tq->loop_id) ||
1302 			    tq->flags & TQF_INITIATOR_DEVICE ||
1303 			    tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
1304 				continue;
1305 			}
1306 			if (inst != cmd->Instance) {
1307 				inst++;
1308 				continue;
1309 			}
1310 
1311 			/* fill in the values */
1312 			bcopy(tq->node_name, tmp_tgt.WWNN,
1313 			    EXT_DEF_WWN_NAME_SIZE);
1314 			bcopy(tq->port_name, tmp_tgt.WWPN,
1315 			    EXT_DEF_WWN_NAME_SIZE);
1316 
1317 			break;
1318 		}
1319 	}
1320 
1321 	if (link == NULL) {
1322 		/* no matching device */
1323 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1324 		cmd->DetailStatus = EXT_DSTATUS_TARGET;
1325 		EL(ha, "failed, not found target=%d\n", cmd->Instance);
1326 		cmd->ResponseLen = 0;
1327 		return;
1328 	}
1329 	tmp_tgt.Id[0] = 0;
1330 	tmp_tgt.Id[1] = tq->d_id.b.domain;
1331 	tmp_tgt.Id[2] = tq->d_id.b.area;
1332 	tmp_tgt.Id[3] = tq->d_id.b.al_pa;
1333 
1334 	tmp_tgt.LunCount = (uint16_t)ql_lun_count(ha, tq);
1335 
1336 	if ((tq->flags & TQF_TAPE_DEVICE) == 0) {
1337 		(void) ql_inq_scan(ha, tq, 1);
1338 	}
1339 
1340 	tmp_tgt.Type = 0;
1341 	if (tq->flags & TQF_TAPE_DEVICE) {
1342 		tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TAPE_DEV);
1343 	}
1344 
1345 	if (tq->flags & TQF_FABRIC_DEVICE) {
1346 		tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_FABRIC_DEV);
1347 	} else {
1348 		tmp_tgt.Type = (uint16_t)(tmp_tgt.Type | EXT_DEF_TARGET_DEV);
1349 	}
1350 
1351 	tmp_tgt.Status = 0;
1352 
1353 	tmp_tgt.Bus = 0;  /* Hard-coded for Solaris. */
1354 
1355 	bcopy(tq->port_name, &tmp_tgt.TargetId, 8);
1356 
1357 	if (ddi_copyout((void *)&tmp_tgt,
1358 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1359 	    sizeof (EXT_DISC_TARGET), mode) != 0) {
1360 		cmd->Status = EXT_STATUS_COPY_ERR;
1361 		cmd->ResponseLen = 0;
1362 		EL(ha, "failed, ddi_copyout\n");
1363 	} else {
1364 		cmd->ResponseLen = sizeof (EXT_DISC_TARGET);
1365 		QL_PRINT_9(ha, "done\n");
1366 	}
1367 }
1368 
1369 /*
1370  * ql_qry_fw
1371  *	Performs EXT_SC_QUERY_FW subfunction.
1372  *
1373  * Input:
1374  *	ha:	adapter state pointer.
1375  *	cmd:	EXT_IOCTL cmd struct pointer.
1376  *	mode:	flags.
1377  *
1378  * Returns:
1379  *	None, request status indicated in cmd->Status.
1380  *
1381  * Context:
1382  *	Kernel context.
1383  */
1384 static void
ql_qry_fw(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1385 ql_qry_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1386 {
1387 	EXT_FW		fw_info = {0};
1388 
1389 	QL_PRINT_9(ha, "started\n");
1390 
1391 	if (cmd->ResponseLen < sizeof (EXT_FW)) {
1392 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1393 		cmd->DetailStatus = sizeof (EXT_FW);
1394 		EL(ha, "failed, ResponseLen < EXT_FW, Len=%xh\n",
1395 		    cmd->ResponseLen);
1396 		cmd->ResponseLen = 0;
1397 		return;
1398 	}
1399 
1400 	(void) sprintf((char *)(fw_info.Version), "%d.%02d.%02d",
1401 	    ha->fw_major_version, ha->fw_minor_version,
1402 	    ha->fw_subminor_version);
1403 
1404 	fw_info.Attrib = ha->fw_attributes;
1405 
1406 	if (ddi_copyout((void *)&fw_info,
1407 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1408 	    sizeof (EXT_FW), mode) != 0) {
1409 		cmd->Status = EXT_STATUS_COPY_ERR;
1410 		cmd->ResponseLen = 0;
1411 		EL(ha, "failed, ddi_copyout\n");
1412 		return;
1413 	} else {
1414 		cmd->ResponseLen = sizeof (EXT_FW);
1415 		QL_PRINT_9(ha, "done\n");
1416 	}
1417 }
1418 
1419 /*
1420  * ql_qry_chip
1421  *	Performs EXT_SC_QUERY_CHIP subfunction.
1422  *
1423  * Input:
1424  *	ha:	adapter state pointer.
1425  *	cmd:	EXT_IOCTL cmd struct pointer.
1426  *	mode:	flags.
1427  *
1428  * Returns:
1429  *	None, request status indicated in cmd->Status.
1430  *
1431  * Context:
1432  *	Kernel context.
1433  */
1434 static void
ql_qry_chip(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1435 ql_qry_chip(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1436 {
1437 	EXT_CHIP	chip = {0};
1438 	uint16_t	PciDevNumber;
1439 
1440 	QL_PRINT_9(ha, "started\n");
1441 
1442 	if (cmd->ResponseLen < sizeof (EXT_CHIP)) {
1443 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1444 		cmd->DetailStatus = sizeof (EXT_CHIP);
1445 		EL(ha, "failed, ResponseLen < EXT_CHIP, Len=%xh\n",
1446 		    cmd->ResponseLen);
1447 		cmd->ResponseLen = 0;
1448 		return;
1449 	}
1450 
1451 	chip.VendorId = ha->ven_id;
1452 	chip.DeviceId = ha->device_id;
1453 	chip.SubVendorId = ha->subven_id;
1454 	chip.SubSystemId = ha->subsys_id;
1455 	chip.IoAddr = ql_pci_config_get32(ha, PCI_CONF_BASE0);
1456 	chip.IoAddrLen = 0x100;
1457 	chip.MemAddr = ql_pci_config_get32(ha, PCI_CONF_BASE1);
1458 	chip.MemAddrLen = 0x100;
1459 	chip.ChipRevID = ha->rev_id;
1460 	chip.FuncNo = ha->pci_function_number;
1461 	chip.PciBusNumber = (uint16_t)
1462 	    ((ha->pci_bus_addr & PCI_REG_BUS_M) >> PCI_REG_BUS_SHIFT);
1463 
1464 	PciDevNumber = (uint16_t)
1465 	    ((ha->pci_bus_addr & PCI_REG_DEV_M) >> PCI_REG_DEV_SHIFT);
1466 	chip.PciSlotNumber = (uint16_t)(((PciDevNumber << 3) & 0xF8) |
1467 	    (chip.FuncNo & 0x7));
1468 
1469 	if (ddi_copyout((void *)&chip,
1470 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1471 	    sizeof (EXT_CHIP), mode) != 0) {
1472 		cmd->Status = EXT_STATUS_COPY_ERR;
1473 		cmd->ResponseLen = 0;
1474 		EL(ha, "failed, ddi_copyout\n");
1475 	} else {
1476 		cmd->ResponseLen = sizeof (EXT_CHIP);
1477 		QL_PRINT_9(ha, "done\n");
1478 	}
1479 }
1480 
1481 /*
1482  * ql_qry_driver
1483  *	Performs EXT_SC_QUERY_DRIVER subfunction.
1484  *
1485  * Input:
1486  *	ha:	adapter state pointer.
1487  *	cmd:	EXT_IOCTL cmd struct pointer.
1488  *	mode:	flags.
1489  *
1490  * Returns:
1491  *	None, request status indicated in cmd->Status.
1492  *
1493  * Context:
1494  *	Kernel context.
1495  */
1496 static void
ql_qry_driver(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1497 ql_qry_driver(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1498 {
1499 	EXT_DRIVER	qd = {0};
1500 
1501 	QL_PRINT_9(ha, "started\n");
1502 
1503 	if (cmd->ResponseLen < sizeof (EXT_DRIVER)) {
1504 		cmd->Status = EXT_STATUS_DATA_OVERRUN;
1505 		cmd->DetailStatus = sizeof (EXT_DRIVER);
1506 		EL(ha, "failed, ResponseLen < EXT_DRIVER, Len=%xh\n",
1507 		    cmd->ResponseLen);
1508 		cmd->ResponseLen = 0;
1509 		return;
1510 	}
1511 
1512 	(void) strcpy((void *)&qd.Version[0], QL_VERSION);
1513 	qd.NumOfBus = 1;	/* Fixed for Solaris */
1514 	qd.TargetsPerBus = (uint16_t)
1515 	    (CFG_IST(ha, (CFG_ISP_FW_TYPE_2 | CFG_EXT_FW_INTERFACE)) ?
1516 	    MAX_24_FIBRE_DEVICES : MAX_22_FIBRE_DEVICES);
1517 	qd.LunsPerTarget = 2030;
1518 	qd.MaxTransferLen = QL_DMA_MAX_XFER_SIZE;
1519 	qd.MaxDataSegments = QL_DMA_SG_LIST_LENGTH;
1520 
1521 	if (ddi_copyout((void *)&qd, (void *)(uintptr_t)cmd->ResponseAdr,
1522 	    sizeof (EXT_DRIVER), mode) != 0) {
1523 		cmd->Status = EXT_STATUS_COPY_ERR;
1524 		cmd->ResponseLen = 0;
1525 		EL(ha, "failed, ddi_copyout\n");
1526 	} else {
1527 		cmd->ResponseLen = sizeof (EXT_DRIVER);
1528 		QL_PRINT_9(ha, "done\n");
1529 	}
1530 }
1531 
1532 /*
1533  * ql_fcct
1534  *	IOCTL management server FC-CT passthrough.
1535  *
1536  * Input:
1537  *	ha:	adapter state pointer.
1538  *	cmd:	User space CT arguments pointer.
1539  *	mode:	flags.
1540  *
1541  * Returns:
1542  *	None, request status indicated in cmd->Status.
1543  *
1544  * Context:
1545  *	Kernel context.
1546  */
1547 static void
ql_fcct(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1548 ql_fcct(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1549 {
1550 	ql_mbx_iocb_t		*pkt;
1551 	ql_mbx_data_t		mr;
1552 	dma_mem_t		*dma_mem;
1553 	caddr_t			pld;
1554 	uint32_t		pkt_size, pld_byte_cnt, *long_ptr;
1555 	int			rval;
1556 	ql_ct_iu_preamble_t	*ct;
1557 	ql_xioctl_t		*xp = ha->xioctl;
1558 	ql_tgt_t		tq;
1559 	uint16_t		comp_status, loop_id;
1560 
1561 	QL_PRINT_9(ha, "started\n");
1562 
1563 	/* Get CT argument structure. */
1564 	if ((ha->topology & QL_FABRIC_CONNECTION) == 0) {
1565 		EL(ha, "failed, No switch\n");
1566 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1567 		cmd->ResponseLen = 0;
1568 		return;
1569 	}
1570 
1571 	if (DRIVER_SUSPENDED(ha)) {
1572 		EL(ha, "failed, LOOP_NOT_READY\n");
1573 		cmd->Status = EXT_STATUS_BUSY;
1574 		cmd->ResponseLen = 0;
1575 		return;
1576 	}
1577 
1578 	/* Login management server device. */
1579 	if ((xp->flags & QL_MGMT_SERVER_LOGIN) == 0) {
1580 		tq.d_id.b.al_pa = 0xfa;
1581 		tq.d_id.b.area = 0xff;
1582 		tq.d_id.b.domain = 0xff;
1583 		tq.loop_id = (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
1584 		    MANAGEMENT_SERVER_24XX_LOOP_ID :
1585 		    MANAGEMENT_SERVER_LOOP_ID);
1586 		rval = ql_login_fport(ha, &tq, tq.loop_id, LFF_NO_PRLI, &mr);
1587 		if (rval != QL_SUCCESS) {
1588 			EL(ha, "failed, server login\n");
1589 			cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
1590 			cmd->ResponseLen = 0;
1591 			return;
1592 		} else {
1593 			xp->flags |= QL_MGMT_SERVER_LOGIN;
1594 		}
1595 	}
1596 
1597 	QL_PRINT_9(ha, "cmd\n");
1598 	QL_DUMP_9(cmd, 8, sizeof (EXT_IOCTL));
1599 
1600 	/* Allocate a DMA Memory Descriptor */
1601 	dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
1602 	if (dma_mem == NULL) {
1603 		EL(ha, "failed, kmem_zalloc\n");
1604 		cmd->Status = EXT_STATUS_NO_MEMORY;
1605 		cmd->ResponseLen = 0;
1606 		return;
1607 	}
1608 	/* Determine maximum buffer size. */
1609 	if (cmd->RequestLen < cmd->ResponseLen) {
1610 		pld_byte_cnt = cmd->ResponseLen;
1611 	} else {
1612 		pld_byte_cnt = cmd->RequestLen;
1613 	}
1614 
1615 	/* Allocate command block. */
1616 	pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_byte_cnt);
1617 	pkt = kmem_zalloc(pkt_size, KM_SLEEP);
1618 	if (pkt == NULL) {
1619 		EL(ha, "failed, kmem_zalloc\n");
1620 		cmd->Status = EXT_STATUS_NO_MEMORY;
1621 		cmd->ResponseLen = 0;
1622 		return;
1623 	}
1624 	pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
1625 
1626 	/* Get command payload data. */
1627 	if (ql_get_buffer_data((caddr_t)(uintptr_t)cmd->RequestAdr, pld,
1628 	    cmd->RequestLen, mode) != cmd->RequestLen) {
1629 		EL(ha, "failed, get_buffer_data\n");
1630 		kmem_free(pkt, pkt_size);
1631 		cmd->Status = EXT_STATUS_COPY_ERR;
1632 		cmd->ResponseLen = 0;
1633 		return;
1634 	}
1635 
1636 	/* Get DMA memory for the IOCB */
1637 	if (ql_get_dma_mem(ha, dma_mem, pkt_size, LITTLE_ENDIAN_DMA,
1638 	    QL_DMA_RING_ALIGN) != QL_SUCCESS) {
1639 		cmn_err(CE_WARN, "%sDMA memory "
1640 		    "alloc failed", QL_NAME);
1641 		kmem_free(pkt, pkt_size);
1642 		kmem_free(dma_mem, sizeof (dma_mem_t));
1643 		cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1644 		cmd->ResponseLen = 0;
1645 		return;
1646 	}
1647 
1648 	/* Copy out going payload data to IOCB DMA buffer. */
1649 	ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
1650 	    (uint8_t *)dma_mem->bp, pld_byte_cnt, DDI_DEV_AUTOINCR);
1651 
1652 	/* Sync IOCB DMA buffer. */
1653 	(void) ddi_dma_sync(dma_mem->dma_handle, 0, pld_byte_cnt,
1654 	    DDI_DMA_SYNC_FORDEV);
1655 
1656 	/*
1657 	 * Setup IOCB
1658 	 */
1659 	ct = (ql_ct_iu_preamble_t *)pld;
1660 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
1661 		pkt->ms24.entry_type = CT_PASSTHRU_TYPE;
1662 		pkt->ms24.entry_count = 1;
1663 
1664 		pkt->ms24.vp_index = ha->vp_index;
1665 
1666 		/* Set loop ID */
1667 		pkt->ms24.n_port_hdl = (uint16_t)
1668 		    (ct->gs_type == GS_TYPE_DIR_SERVER ?
1669 		    LE_16(SNS_24XX_HDL) :
1670 		    LE_16(MANAGEMENT_SERVER_24XX_LOOP_ID));
1671 
1672 		/* Set ISP command timeout. */
1673 		pkt->ms24.timeout = LE_16(120);
1674 
1675 		/* Set cmd/response data segment counts. */
1676 		pkt->ms24.cmd_dseg_count = LE_16(1);
1677 		pkt->ms24.resp_dseg_count = LE_16(1);
1678 
1679 		/* Load ct cmd byte count. */
1680 		pkt->ms24.cmd_byte_count = LE_32(cmd->RequestLen);
1681 
1682 		/* Load ct rsp byte count. */
1683 		pkt->ms24.resp_byte_count = LE_32(cmd->ResponseLen);
1684 
1685 		long_ptr = (uint32_t *)&pkt->ms24.dseg;
1686 
1687 		/* Load MS command entry data segments. */
1688 		*long_ptr++ = (uint32_t)
1689 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1690 		*long_ptr++ = (uint32_t)
1691 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1692 		*long_ptr++ = (uint32_t)(LE_32(cmd->RequestLen));
1693 
1694 		/* Load MS response entry data segments. */
1695 		*long_ptr++ = (uint32_t)
1696 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1697 		*long_ptr++ = (uint32_t)
1698 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1699 		*long_ptr = (uint32_t)LE_32(cmd->ResponseLen);
1700 
1701 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1702 		    sizeof (ql_mbx_iocb_t));
1703 
1704 		comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
1705 		if (comp_status == CS_DATA_UNDERRUN) {
1706 			if ((BE_16(ct->max_residual_size)) == 0) {
1707 				comp_status = CS_COMPLETE;
1708 			}
1709 		}
1710 
1711 		if (rval != QL_SUCCESS || (pkt->sts24.entry_status & 0x3c) !=
1712 		    0) {
1713 			EL(ha, "failed, I/O timeout or "
1714 			    "es=%xh, ss_l=%xh, rval=%xh\n",
1715 			    pkt->sts24.entry_status,
1716 			    pkt->sts24.scsi_status_l, rval);
1717 			kmem_free(pkt, pkt_size);
1718 			ql_free_dma_resource(ha, dma_mem);
1719 			kmem_free(dma_mem, sizeof (dma_mem_t));
1720 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1721 			cmd->ResponseLen = 0;
1722 			return;
1723 		}
1724 	} else {
1725 		pkt->ms.entry_type = MS_TYPE;
1726 		pkt->ms.entry_count = 1;
1727 
1728 		/* Set loop ID */
1729 		loop_id = (uint16_t)(ct->gs_type == GS_TYPE_DIR_SERVER ?
1730 		    SIMPLE_NAME_SERVER_LOOP_ID : MANAGEMENT_SERVER_LOOP_ID);
1731 		if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
1732 			pkt->ms.loop_id_l = LSB(loop_id);
1733 			pkt->ms.loop_id_h = MSB(loop_id);
1734 		} else {
1735 			pkt->ms.loop_id_h = LSB(loop_id);
1736 		}
1737 
1738 		/* Set ISP command timeout. */
1739 		pkt->ms.timeout = LE_16(120);
1740 
1741 		/* Set data segment counts. */
1742 		pkt->ms.cmd_dseg_count_l = 1;
1743 		pkt->ms.total_dseg_count = LE_16(2);
1744 
1745 		/* Response total byte count. */
1746 		pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen);
1747 		pkt->ms.dseg[1].length = LE_32(cmd->ResponseLen);
1748 
1749 		/* Command total byte count. */
1750 		pkt->ms.cmd_byte_count = LE_32(cmd->RequestLen);
1751 		pkt->ms.dseg[0].length = LE_32(cmd->RequestLen);
1752 
1753 		/* Load command/response data segments. */
1754 		pkt->ms.dseg[0].address[0] = (uint32_t)
1755 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1756 		pkt->ms.dseg[0].address[1] = (uint32_t)
1757 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1758 		pkt->ms.dseg[1].address[0] = (uint32_t)
1759 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
1760 		pkt->ms.dseg[1].address[1] = (uint32_t)
1761 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
1762 
1763 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
1764 		    sizeof (ql_mbx_iocb_t));
1765 
1766 		comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
1767 		if (comp_status == CS_DATA_UNDERRUN) {
1768 			if ((BE_16(ct->max_residual_size)) == 0) {
1769 				comp_status = CS_COMPLETE;
1770 			}
1771 		}
1772 		if (rval != QL_SUCCESS || (pkt->sts.entry_status & 0x7e) != 0) {
1773 			EL(ha, "failed, I/O timeout or "
1774 			    "es=%xh, rval=%xh\n", pkt->sts.entry_status, rval);
1775 			kmem_free(pkt, pkt_size);
1776 			ql_free_dma_resource(ha, dma_mem);
1777 			kmem_free(dma_mem, sizeof (dma_mem_t));
1778 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
1779 			cmd->ResponseLen = 0;
1780 			return;
1781 		}
1782 	}
1783 
1784 	/* Sync in coming DMA buffer. */
1785 	(void) ddi_dma_sync(dma_mem->dma_handle, 0,
1786 	    pld_byte_cnt, DDI_DMA_SYNC_FORKERNEL);
1787 	/* Copy in coming DMA data. */
1788 	ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
1789 	    (uint8_t *)dma_mem->bp, pld_byte_cnt,
1790 	    DDI_DEV_AUTOINCR);
1791 
1792 	/* Copy response payload from DMA buffer to application. */
1793 	if (cmd->ResponseLen != 0) {
1794 		QL_PRINT_9(ha, "ResponseLen=%d\n",
1795 		    cmd->ResponseLen);
1796 		QL_DUMP_9(pld, 8, cmd->ResponseLen);
1797 
1798 		/* Send response payload. */
1799 		if (ql_send_buffer_data(pld,
1800 		    (caddr_t)(uintptr_t)cmd->ResponseAdr,
1801 		    cmd->ResponseLen, mode) != cmd->ResponseLen) {
1802 			EL(ha, "failed, send_buffer_data\n");
1803 			cmd->Status = EXT_STATUS_COPY_ERR;
1804 			cmd->ResponseLen = 0;
1805 		}
1806 	}
1807 
1808 	kmem_free(pkt, pkt_size);
1809 	ql_free_dma_resource(ha, dma_mem);
1810 	kmem_free(dma_mem, sizeof (dma_mem_t));
1811 
1812 	QL_PRINT_9(ha, "done\n");
1813 }
1814 
1815 /*
1816  * ql_aen_reg
1817  *	IOCTL management server Asynchronous Event Tracking Enable/Disable.
1818  *
1819  * Input:
1820  *	ha:	adapter state pointer.
1821  *	cmd:	EXT_IOCTL cmd struct pointer.
1822  *	mode:	flags.
1823  *
1824  * Returns:
1825  *	None, request status indicated in cmd->Status.
1826  *
1827  * Context:
1828  *	Kernel context.
1829  */
1830 static void
ql_aen_reg(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1831 ql_aen_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1832 {
1833 	EXT_REG_AEN	reg_struct;
1834 	int		rval = 0;
1835 	ql_xioctl_t	*xp = ha->xioctl;
1836 
1837 	QL_PRINT_9(ha, "started\n");
1838 
1839 	rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &reg_struct,
1840 	    cmd->RequestLen, mode);
1841 
1842 	if (rval == 0) {
1843 		if (reg_struct.Enable) {
1844 			xp->flags |= QL_AEN_TRACKING_ENABLE;
1845 		} else {
1846 			xp->flags &= ~QL_AEN_TRACKING_ENABLE;
1847 			/* Empty the queue. */
1848 			INTR_LOCK(ha);
1849 			xp->aen_q_head = 0;
1850 			xp->aen_q_tail = 0;
1851 			INTR_UNLOCK(ha);
1852 		}
1853 		QL_PRINT_9(ha, "done\n");
1854 	} else {
1855 		cmd->Status = EXT_STATUS_COPY_ERR;
1856 		EL(ha, "failed, ddi_copyin\n");
1857 	}
1858 }
1859 
1860 /*
1861  * ql_aen_get
1862  *	IOCTL management server Asynchronous Event Record Transfer.
1863  *
1864  * Input:
1865  *	ha:	adapter state pointer.
1866  *	cmd:	EXT_IOCTL cmd struct pointer.
1867  *	mode:	flags.
1868  *
1869  * Returns:
1870  *	None, request status indicated in cmd->Status.
1871  *
1872  * Context:
1873  *	Kernel context.
1874  */
1875 static void
ql_aen_get(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)1876 ql_aen_get(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
1877 {
1878 	uint32_t	out_size;
1879 	EXT_ASYNC_EVENT	*tmp_q;
1880 	EXT_ASYNC_EVENT	aen[EXT_DEF_MAX_AEN_QUEUE];
1881 	uint8_t		i;
1882 	uint8_t		queue_cnt;
1883 	uint8_t		request_cnt;
1884 	ql_xioctl_t	*xp = ha->xioctl;
1885 
1886 	QL_PRINT_9(ha, "started\n");
1887 
1888 	/* Compute the number of events that can be returned */
1889 	request_cnt = (uint8_t)(cmd->ResponseLen / sizeof (EXT_ASYNC_EVENT));
1890 
1891 	if (request_cnt < EXT_DEF_MAX_AEN_QUEUE) {
1892 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
1893 		cmd->DetailStatus = EXT_DEF_MAX_AEN_QUEUE;
1894 		EL(ha, "failed, request_cnt < EXT_DEF_MAX_AEN_QUEUE, "
1895 		    "Len=%xh\n", request_cnt);
1896 		cmd->ResponseLen = 0;
1897 		return;
1898 	}
1899 
1900 	/* 1st: Make a local copy of the entire queue content. */
1901 	tmp_q = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1902 	queue_cnt = 0;
1903 
1904 	INTR_LOCK(ha);
1905 	i = xp->aen_q_head;
1906 
1907 	for (; queue_cnt < EXT_DEF_MAX_AEN_QUEUE; ) {
1908 		if (tmp_q[i].AsyncEventCode != 0) {
1909 			bcopy(&tmp_q[i], &aen[queue_cnt],
1910 			    sizeof (EXT_ASYNC_EVENT));
1911 			queue_cnt++;
1912 			tmp_q[i].AsyncEventCode = 0; /* empty out the slot */
1913 		}
1914 		if (i == xp->aen_q_tail) {
1915 			/* done. */
1916 			break;
1917 		}
1918 		i++;
1919 		if (i == EXT_DEF_MAX_AEN_QUEUE) {
1920 			i = 0;
1921 		}
1922 	}
1923 
1924 	/* Empty the queue. */
1925 	xp->aen_q_head = 0;
1926 	xp->aen_q_tail = 0;
1927 
1928 	INTR_UNLOCK(ha);
1929 
1930 	/* 2nd: Now transfer the queue content to user buffer */
1931 	/* Copy the entire queue to user's buffer. */
1932 	out_size = (uint32_t)(queue_cnt * sizeof (EXT_ASYNC_EVENT));
1933 	if (queue_cnt == 0) {
1934 		cmd->ResponseLen = 0;
1935 	} else if (ddi_copyout((void *)&aen[0],
1936 	    (void *)(uintptr_t)(cmd->ResponseAdr),
1937 	    out_size, mode) != 0) {
1938 		cmd->Status = EXT_STATUS_COPY_ERR;
1939 		cmd->ResponseLen = 0;
1940 		EL(ha, "failed, ddi_copyout\n");
1941 	} else {
1942 		cmd->ResponseLen = out_size;
1943 		QL_PRINT_9(ha, "done\n");
1944 	}
1945 }
1946 
1947 /*
1948  * ql_enqueue_aen
1949  *
1950  * Input:
1951  *	ha:		adapter state pointer.
1952  *	event_code:	async event code of the event to add to queue.
1953  *	payload:	event payload for the queue.
1954  *	INTR_LOCK must be already obtained.
1955  *
1956  * Context:
1957  *	Interrupt or Kernel context, no mailbox commands allowed.
1958  */
1959 void
ql_enqueue_aen(ql_adapter_state_t * ha,uint16_t event_code,void * payload)1960 ql_enqueue_aen(ql_adapter_state_t *ha, uint16_t event_code, void *payload)
1961 {
1962 	uint8_t			new_entry;	/* index to current entry */
1963 	uint16_t		*mbx;
1964 	EXT_ASYNC_EVENT		*aen_queue;
1965 	ql_xioctl_t		*xp = ha->xioctl;
1966 
1967 	QL_PRINT_9(ha, "started, event_code=%d\n",
1968 	    event_code);
1969 
1970 	if (xp == NULL) {
1971 		QL_PRINT_9(ha, "no context\n");
1972 		return;
1973 	}
1974 	aen_queue = (EXT_ASYNC_EVENT *)xp->aen_tracking_queue;
1975 
1976 	if (aen_queue[xp->aen_q_tail].AsyncEventCode != 0) {
1977 		/* Need to change queue pointers to make room. */
1978 
1979 		/* Increment tail for adding new entry. */
1980 		xp->aen_q_tail++;
1981 		if (xp->aen_q_tail == EXT_DEF_MAX_AEN_QUEUE) {
1982 			xp->aen_q_tail = 0;
1983 		}
1984 		if (xp->aen_q_head == xp->aen_q_tail) {
1985 			/*
1986 			 * We're overwriting the oldest entry, so need to
1987 			 * update the head pointer.
1988 			 */
1989 			xp->aen_q_head++;
1990 			if (xp->aen_q_head == EXT_DEF_MAX_AEN_QUEUE) {
1991 				xp->aen_q_head = 0;
1992 			}
1993 		}
1994 	}
1995 
1996 	new_entry = xp->aen_q_tail;
1997 	aen_queue[new_entry].AsyncEventCode = event_code;
1998 
1999 	/* Update payload */
2000 	if (payload != NULL) {
2001 		switch (event_code) {
2002 		case MBA_LIP_OCCURRED:
2003 		case MBA_LOOP_UP:
2004 		case MBA_LOOP_DOWN:
2005 		case MBA_LIP_F8:
2006 		case MBA_LIP_RESET:
2007 		case MBA_PORT_UPDATE:
2008 			break;
2009 		case MBA_RSCN_UPDATE:
2010 			mbx = (uint16_t *)payload;
2011 			/* al_pa */
2012 			aen_queue[new_entry].Payload.RSCN.RSCNInfo[0] =
2013 			    LSB(mbx[2]);
2014 			/* area */
2015 			aen_queue[new_entry].Payload.RSCN.RSCNInfo[1] =
2016 			    MSB(mbx[2]);
2017 			/* domain */
2018 			aen_queue[new_entry].Payload.RSCN.RSCNInfo[2] =
2019 			    LSB(mbx[1]);
2020 			/* save in big endian */
2021 			BIG_ENDIAN_24(&aen_queue[new_entry].
2022 			    Payload.RSCN.RSCNInfo[0]);
2023 
2024 			aen_queue[new_entry].Payload.RSCN.AddrFormat =
2025 			    MSB(mbx[1]);
2026 
2027 			break;
2028 		default:
2029 			/* Not supported */
2030 			EL(ha, "failed, event code not supported=%xh\n",
2031 			    event_code);
2032 			aen_queue[new_entry].AsyncEventCode = 0;
2033 			break;
2034 		}
2035 	}
2036 
2037 	QL_PRINT_9(ha, "done\n");
2038 }
2039 
2040 /*
2041  * ql_scsi_passthru
2042  *	IOCTL SCSI passthrough.
2043  *
2044  * Input:
2045  *	ha:	adapter state pointer.
2046  *	cmd:	User space SCSI command pointer.
2047  *	mode:	flags.
2048  *
2049  * Returns:
2050  *	None, request status indicated in cmd->Status.
2051  *
2052  * Context:
2053  *	Kernel context.
2054  */
2055 static void
ql_scsi_passthru(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2056 ql_scsi_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2057 {
2058 	ql_mbx_iocb_t		*pkt;
2059 	ql_mbx_data_t		mr;
2060 	dma_mem_t		*dma_mem;
2061 	caddr_t			pld;
2062 	uint32_t		pkt_size, pld_size;
2063 	uint16_t		qlnt, retries, cnt, cnt2;
2064 	uint8_t			*name;
2065 	EXT_FC_SCSI_PASSTHRU	*ufc_req;
2066 	EXT_SCSI_PASSTHRU	*usp_req;
2067 	int			rval;
2068 	union _passthru {
2069 		EXT_SCSI_PASSTHRU	sp_cmd;
2070 		EXT_FC_SCSI_PASSTHRU	fc_cmd;
2071 	} pt_req;		/* Passthru request */
2072 	uint32_t		status, sense_sz = 0;
2073 	ql_tgt_t		*tq = NULL;
2074 	EXT_SCSI_PASSTHRU	*sp_req = &pt_req.sp_cmd;
2075 	EXT_FC_SCSI_PASSTHRU	*fc_req = &pt_req.fc_cmd;
2076 
2077 	/* SCSI request struct for SCSI passthrough IOs. */
2078 	struct {
2079 		uint16_t	lun;
2080 		uint16_t	sense_length;	/* Sense buffer size */
2081 		size_t		resid;		/* Residual */
2082 		uint8_t		*cdbp;		/* Requestor's CDB */
2083 		uint8_t		*u_sense;	/* Requestor's sense buffer */
2084 		uint8_t		cdb_len;	/* Requestor's CDB length */
2085 		uint8_t		direction;
2086 	} scsi_req;
2087 
2088 	struct {
2089 		uint8_t		*rsp_info;
2090 		uint8_t		*req_sense_data;
2091 		uint32_t	residual_length;
2092 		uint32_t	rsp_info_length;
2093 		uint32_t	req_sense_length;
2094 		uint16_t	comp_status;
2095 		uint8_t		state_flags_l;
2096 		uint8_t		state_flags_h;
2097 		uint8_t		scsi_status_l;
2098 		uint8_t		scsi_status_h;
2099 	} sts;
2100 
2101 	QL_PRINT_9(ha, "started\n");
2102 
2103 	/* Verify Sub Code and set cnt to needed request size. */
2104 	if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2105 		pld_size = sizeof (EXT_SCSI_PASSTHRU);
2106 	} else if (cmd->SubCode == EXT_SC_SEND_FC_SCSI_PASSTHRU) {
2107 		pld_size = sizeof (EXT_FC_SCSI_PASSTHRU);
2108 	} else {
2109 		EL(ha, "failed, invalid SubCode=%xh\n", cmd->SubCode);
2110 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
2111 		cmd->ResponseLen = 0;
2112 		return;
2113 	}
2114 
2115 	dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
2116 	if (dma_mem == NULL) {
2117 		EL(ha, "failed, kmem_zalloc\n");
2118 		cmd->Status = EXT_STATUS_NO_MEMORY;
2119 		cmd->ResponseLen = 0;
2120 		return;
2121 	}
2122 	/*  Verify the size of and copy in the passthru request structure. */
2123 	if (cmd->RequestLen != pld_size) {
2124 		/* Return error */
2125 		EL(ha, "failed, RequestLen != cnt, is=%xh, expected=%xh\n",
2126 		    cmd->RequestLen, pld_size);
2127 		cmd->Status = EXT_STATUS_INVALID_PARAM;
2128 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2129 		cmd->ResponseLen = 0;
2130 		return;
2131 	}
2132 
2133 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr, &pt_req,
2134 	    pld_size, mode) != 0) {
2135 		EL(ha, "failed, ddi_copyin\n");
2136 		cmd->Status = EXT_STATUS_COPY_ERR;
2137 		cmd->ResponseLen = 0;
2138 		return;
2139 	}
2140 
2141 	/*
2142 	 * Find fc_port from SCSI PASSTHRU structure fill in the scsi_req
2143 	 * request data structure.
2144 	 */
2145 	if (cmd->SubCode == EXT_SC_SEND_SCSI_PASSTHRU) {
2146 		scsi_req.lun = sp_req->TargetAddr.Lun;
2147 		scsi_req.sense_length = sizeof (sp_req->SenseData);
2148 		scsi_req.cdbp = &sp_req->Cdb[0];
2149 		scsi_req.cdb_len = sp_req->CdbLength;
2150 		scsi_req.direction = sp_req->Direction;
2151 		usp_req = (EXT_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2152 		scsi_req.u_sense = &usp_req->SenseData[0];
2153 		cmd->DetailStatus = EXT_DSTATUS_TARGET;
2154 
2155 		qlnt = QLNT_PORT;
2156 		name = (uint8_t *)&sp_req->TargetAddr.Target;
2157 		QL_PRINT_9(ha, "SubCode=%xh, Target=%lld\n",
2158 		    ha->instance, cmd->SubCode, sp_req->TargetAddr.Target);
2159 		tq = ql_find_port(ha, name, qlnt);
2160 	} else {
2161 		/*
2162 		 * Must be FC PASSTHRU, verified above.
2163 		 */
2164 		if (fc_req->FCScsiAddr.DestType == EXT_DEF_DESTTYPE_WWPN) {
2165 			qlnt = QLNT_PORT;
2166 			name = &fc_req->FCScsiAddr.DestAddr.WWPN[0];
2167 			QL_PRINT_9(ha, "SubCode=%xh, "
2168 			    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2169 			    ha->instance, cmd->SubCode, name[0], name[1],
2170 			    name[2], name[3], name[4], name[5], name[6],
2171 			    name[7]);
2172 			tq = ql_find_port(ha, name, qlnt);
2173 		} else if (fc_req->FCScsiAddr.DestType ==
2174 		    EXT_DEF_DESTTYPE_WWNN) {
2175 			qlnt = QLNT_NODE;
2176 			name = &fc_req->FCScsiAddr.DestAddr.WWNN[0];
2177 			QL_PRINT_9(ha, "SubCode=%xh, "
2178 			    "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
2179 			    ha->instance, cmd->SubCode, name[0], name[1],
2180 			    name[2], name[3], name[4], name[5], name[6],
2181 			    name[7]);
2182 			tq = ql_find_port(ha, name, qlnt);
2183 		} else if (fc_req->FCScsiAddr.DestType ==
2184 		    EXT_DEF_DESTTYPE_PORTID) {
2185 			qlnt = QLNT_PID;
2186 			name = &fc_req->FCScsiAddr.DestAddr.Id[0];
2187 			QL_PRINT_9(ha, "SubCode=%xh, PID="
2188 			    "%02x%02x%02x\n", cmd->SubCode,
2189 			    name[0], name[1], name[2]);
2190 			tq = ql_find_port(ha, name, qlnt);
2191 		} else {
2192 			EL(ha, "failed, SubCode=%xh invalid DestType=%xh\n",
2193 			    cmd->SubCode, fc_req->FCScsiAddr.DestType);
2194 			cmd->Status = EXT_STATUS_INVALID_PARAM;
2195 			cmd->ResponseLen = 0;
2196 			return;
2197 		}
2198 		scsi_req.lun = fc_req->FCScsiAddr.Lun;
2199 		scsi_req.sense_length = sizeof (fc_req->SenseData);
2200 		scsi_req.cdbp = &sp_req->Cdb[0];
2201 		scsi_req.cdb_len = sp_req->CdbLength;
2202 		ufc_req = (EXT_FC_SCSI_PASSTHRU *)(uintptr_t)cmd->RequestAdr;
2203 		scsi_req.u_sense = &ufc_req->SenseData[0];
2204 		scsi_req.direction = fc_req->Direction;
2205 	}
2206 
2207 	if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
2208 		EL(ha, "failed, fc_port not found\n");
2209 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2210 		cmd->ResponseLen = 0;
2211 		return;
2212 	}
2213 
2214 	if (tq->flags & TQF_NEED_AUTHENTICATION) {
2215 		EL(ha, "target not available; loopid=%xh\n", tq->loop_id);
2216 		cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
2217 		cmd->ResponseLen = 0;
2218 		return;
2219 	}
2220 
2221 	/* Allocate command block. */
2222 	if ((scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN ||
2223 	    scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_OUT) &&
2224 	    cmd->ResponseLen) {
2225 		pld_size = cmd->ResponseLen;
2226 		pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + pld_size);
2227 		pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2228 		if (pkt == NULL) {
2229 			EL(ha, "failed, kmem_zalloc\n");
2230 			cmd->Status = EXT_STATUS_NO_MEMORY;
2231 			cmd->ResponseLen = 0;
2232 			return;
2233 		}
2234 		pld = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
2235 
2236 		/* Get DMA memory for the IOCB */
2237 		if (ql_get_dma_mem(ha, dma_mem, pld_size, LITTLE_ENDIAN_DMA,
2238 		    QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
2239 			cmn_err(CE_WARN, "%srequest queue DMA memory "
2240 			    "alloc failed", QL_NAME);
2241 			kmem_free(pkt, pkt_size);
2242 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
2243 			cmd->ResponseLen = 0;
2244 			return;
2245 		}
2246 
2247 		if (scsi_req.direction == EXT_DEF_SCSI_PASSTHRU_DATA_IN) {
2248 			scsi_req.direction = (uint8_t)
2249 			    (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2250 			    CF_RD : CF_DATA_IN | CF_STAG);
2251 		} else {
2252 			scsi_req.direction = (uint8_t)
2253 			    (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2254 			    CF_WR : CF_DATA_OUT | CF_STAG);
2255 			cmd->ResponseLen = 0;
2256 
2257 			/* Get command payload. */
2258 			if (ql_get_buffer_data(
2259 			    (caddr_t)(uintptr_t)cmd->ResponseAdr,
2260 			    pld, pld_size, mode) != pld_size) {
2261 				EL(ha, "failed, get_buffer_data\n");
2262 				cmd->Status = EXT_STATUS_COPY_ERR;
2263 
2264 				kmem_free(pkt, pkt_size);
2265 				ql_free_dma_resource(ha, dma_mem);
2266 				kmem_free(dma_mem, sizeof (dma_mem_t));
2267 				return;
2268 			}
2269 
2270 			/* Copy out going data to DMA buffer. */
2271 			ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
2272 			    (uint8_t *)dma_mem->bp, pld_size,
2273 			    DDI_DEV_AUTOINCR);
2274 
2275 			/* Sync DMA buffer. */
2276 			(void) ddi_dma_sync(dma_mem->dma_handle, 0,
2277 			    dma_mem->size, DDI_DMA_SYNC_FORDEV);
2278 		}
2279 	} else {
2280 		scsi_req.direction = (uint8_t)
2281 		    (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ? 0 : CF_STAG);
2282 		cmd->ResponseLen = 0;
2283 
2284 		pkt_size = sizeof (ql_mbx_iocb_t);
2285 		pkt = kmem_zalloc(pkt_size, KM_SLEEP);
2286 		if (pkt == NULL) {
2287 			EL(ha, "failed, kmem_zalloc-2\n");
2288 			cmd->Status = EXT_STATUS_NO_MEMORY;
2289 			return;
2290 		}
2291 		pld = NULL;
2292 		pld_size = 0;
2293 	}
2294 
2295 	/* retries = ha->port_down_retry_count; */
2296 	retries = 1;
2297 	cmd->Status = EXT_STATUS_OK;
2298 	cmd->DetailStatus = EXT_DSTATUS_NOADNL_INFO;
2299 
2300 	QL_PRINT_9(ha, "SCSI cdb\n");
2301 	QL_DUMP_9(scsi_req.cdbp, 8, scsi_req.cdb_len);
2302 
2303 	do {
2304 		if (DRIVER_SUSPENDED(ha)) {
2305 			sts.comp_status = CS_LOOP_DOWN_ABORT;
2306 			break;
2307 		}
2308 
2309 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
2310 			uint64_t		lun_addr = 0;
2311 			fcp_ent_addr_t		*fcp_ent_addr = 0;
2312 
2313 			pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
2314 			pkt->cmd24.entry_count = 1;
2315 
2316 			/* Set LUN number and address method */
2317 			lun_addr = ql_get_lun_addr(tq, scsi_req.lun);
2318 			fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
2319 
2320 			pkt->cmd24.fcp_lun[2] =
2321 			    lobyte(fcp_ent_addr->ent_addr_0);
2322 			pkt->cmd24.fcp_lun[3] =
2323 			    hibyte(fcp_ent_addr->ent_addr_0);
2324 			pkt->cmd24.fcp_lun[0] =
2325 			    lobyte(fcp_ent_addr->ent_addr_1);
2326 			pkt->cmd24.fcp_lun[1] =
2327 			    hibyte(fcp_ent_addr->ent_addr_1);
2328 			pkt->cmd24.fcp_lun[6] =
2329 			    lobyte(fcp_ent_addr->ent_addr_2);
2330 			pkt->cmd24.fcp_lun[7] =
2331 			    hibyte(fcp_ent_addr->ent_addr_2);
2332 			pkt->cmd24.fcp_lun[4] =
2333 			    lobyte(fcp_ent_addr->ent_addr_3);
2334 			pkt->cmd24.fcp_lun[5] =
2335 			    hibyte(fcp_ent_addr->ent_addr_3);
2336 
2337 			/* Set N_port handle */
2338 			pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
2339 
2340 			/* Set VP Index */
2341 			pkt->cmd24.vp_index = ha->vp_index;
2342 
2343 			/* Set target ID */
2344 			pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
2345 			pkt->cmd24.target_id[1] = tq->d_id.b.area;
2346 			pkt->cmd24.target_id[2] = tq->d_id.b.domain;
2347 
2348 			/* Set ISP command timeout. */
2349 			pkt->cmd24.timeout = (uint16_t)LE_16(15);
2350 
2351 			/* Load SCSI CDB */
2352 			ddi_rep_put8(ha->req_q[0]->req_ring.acc_handle,
2353 			    scsi_req.cdbp, pkt->cmd24.scsi_cdb,
2354 			    scsi_req.cdb_len, DDI_DEV_AUTOINCR);
2355 			for (cnt = 0; cnt < MAX_CMDSZ;
2356 			    cnt = (uint16_t)(cnt + 4)) {
2357 				ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
2358 				    + cnt, 4);
2359 			}
2360 
2361 			/* Set tag queue control flags */
2362 			pkt->cmd24.task = TA_STAG;
2363 
2364 			if (pld_size) {
2365 				/* Set transfer direction. */
2366 				pkt->cmd24.control_flags = scsi_req.direction;
2367 
2368 				/* Set data segment count. */
2369 				pkt->cmd24.dseg_count = LE_16(1);
2370 
2371 				/* Load total byte count. */
2372 				pkt->cmd24.total_byte_count = LE_32(pld_size);
2373 
2374 				/* Load data descriptor. */
2375 				pkt->cmd24.dseg.address[0] = (uint32_t)
2376 				    LE_32(LSD(dma_mem->cookie.dmac_laddress));
2377 				pkt->cmd24.dseg.address[1] = (uint32_t)
2378 				    LE_32(MSD(dma_mem->cookie.dmac_laddress));
2379 				pkt->cmd24.dseg.length = LE_32(pld_size);
2380 			}
2381 		} else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
2382 			pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
2383 			pkt->cmd3.entry_count = 1;
2384 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2385 				pkt->cmd3.target_l = LSB(tq->loop_id);
2386 				pkt->cmd3.target_h = MSB(tq->loop_id);
2387 			} else {
2388 				pkt->cmd3.target_h = LSB(tq->loop_id);
2389 			}
2390 			pkt->cmd3.lun_l = LSB(scsi_req.lun);
2391 			pkt->cmd3.lun_h = MSB(scsi_req.lun);
2392 			pkt->cmd3.control_flags_l = scsi_req.direction;
2393 			pkt->cmd3.timeout = LE_16(15);
2394 			for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2395 				pkt->cmd3.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2396 			}
2397 			if (pld_size) {
2398 				pkt->cmd3.dseg_count = LE_16(1);
2399 				pkt->cmd3.byte_count = LE_32(pld_size);
2400 				pkt->cmd3.dseg[0].address[0] = (uint32_t)
2401 				    LE_32(LSD(dma_mem->cookie.dmac_laddress));
2402 				pkt->cmd3.dseg[0].address[1] = (uint32_t)
2403 				    LE_32(MSD(dma_mem->cookie.dmac_laddress));
2404 				pkt->cmd3.dseg[0].length = LE_32(pld_size);
2405 			}
2406 		} else {
2407 			pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
2408 			pkt->cmd.entry_count = 1;
2409 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
2410 				pkt->cmd.target_l = LSB(tq->loop_id);
2411 				pkt->cmd.target_h = MSB(tq->loop_id);
2412 			} else {
2413 				pkt->cmd.target_h = LSB(tq->loop_id);
2414 			}
2415 			pkt->cmd.lun_l = LSB(scsi_req.lun);
2416 			pkt->cmd.lun_h = MSB(scsi_req.lun);
2417 			pkt->cmd.control_flags_l = scsi_req.direction;
2418 			pkt->cmd.timeout = LE_16(15);
2419 			for (cnt = 0; cnt < scsi_req.cdb_len; cnt++) {
2420 				pkt->cmd.scsi_cdb[cnt] = scsi_req.cdbp[cnt];
2421 			}
2422 			if (pld_size) {
2423 				pkt->cmd.dseg_count = LE_16(1);
2424 				pkt->cmd.byte_count = LE_32(pld_size);
2425 				pkt->cmd.dseg[0].address = (uint32_t)
2426 				    LE_32(LSD(dma_mem->cookie.dmac_laddress));
2427 				pkt->cmd.dseg[0].length = LE_32(pld_size);
2428 			}
2429 		}
2430 		/* Go issue command and wait for completion. */
2431 		QL_PRINT_9(ha, "request pkt\n");
2432 		QL_DUMP_9(pkt, 8, pkt_size);
2433 
2434 		status = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size);
2435 
2436 		if (pld_size) {
2437 			/* Sync in coming DMA buffer. */
2438 			(void) ddi_dma_sync(dma_mem->dma_handle, 0,
2439 			    dma_mem->size, DDI_DMA_SYNC_FORKERNEL);
2440 			/* Copy in coming DMA data. */
2441 			ddi_rep_get8(dma_mem->acc_handle, (uint8_t *)pld,
2442 			    (uint8_t *)dma_mem->bp, pld_size,
2443 			    DDI_DEV_AUTOINCR);
2444 		}
2445 
2446 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
2447 			pkt->sts24.entry_status = (uint8_t)
2448 			    (pkt->sts24.entry_status & 0x3c);
2449 		} else {
2450 			pkt->sts.entry_status = (uint8_t)
2451 			    (pkt->sts.entry_status & 0x7e);
2452 		}
2453 
2454 		if (status == QL_SUCCESS && pkt->sts.entry_status != 0) {
2455 			EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
2456 			    pkt->sts.entry_status, tq->d_id.b24);
2457 			status = QL_FUNCTION_PARAMETER_ERROR;
2458 		}
2459 
2460 		sts.comp_status = (uint16_t)
2461 		    (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2462 		    LE_16(pkt->sts24.comp_status) :
2463 		    LE_16(pkt->sts.comp_status));
2464 
2465 		/*
2466 		 * We have verified about all the request that can be so far.
2467 		 * Now we need to start verification of our ability to
2468 		 * actually issue the CDB.
2469 		 */
2470 		if (DRIVER_SUSPENDED(ha)) {
2471 			sts.comp_status = CS_LOOP_DOWN_ABORT;
2472 			break;
2473 		} else if (status == QL_SUCCESS &&
2474 		    (sts.comp_status == CS_PORT_LOGGED_OUT ||
2475 		    sts.comp_status == CS_PORT_UNAVAILABLE)) {
2476 			EL(ha, "login retry d_id=%xh\n", tq->d_id.b24);
2477 			if (tq->flags & TQF_FABRIC_DEVICE) {
2478 				rval = ql_login_fport(ha, tq, tq->loop_id,
2479 				    LFF_NO_PLOGI, &mr);
2480 				if (rval != QL_SUCCESS) {
2481 					EL(ha, "failed, login_fport=%xh, "
2482 					    "d_id=%xh\n", rval, tq->d_id.b24);
2483 				}
2484 			} else {
2485 				rval = ql_login_lport(ha, tq, tq->loop_id,
2486 				    LLF_NONE);
2487 				if (rval != QL_SUCCESS) {
2488 					EL(ha, "failed, login_lport=%xh, "
2489 					    "d_id=%xh\n", rval, tq->d_id.b24);
2490 				}
2491 			}
2492 		} else {
2493 			break;
2494 		}
2495 
2496 		bzero((caddr_t)pkt, sizeof (ql_mbx_iocb_t));
2497 
2498 	} while (retries--);
2499 
2500 	if (sts.comp_status == CS_LOOP_DOWN_ABORT) {
2501 		/* Cannot issue command now, maybe later */
2502 		EL(ha, "failed, suspended\n");
2503 		kmem_free(pkt, pkt_size);
2504 		ql_free_dma_resource(ha, dma_mem);
2505 		kmem_free(dma_mem, sizeof (dma_mem_t));
2506 		cmd->Status = EXT_STATUS_SUSPENDED;
2507 		cmd->ResponseLen = 0;
2508 		return;
2509 	}
2510 
2511 	if (status != QL_SUCCESS) {
2512 		/* Command error */
2513 		EL(ha, "failed, I/O\n");
2514 		kmem_free(pkt, pkt_size);
2515 		ql_free_dma_resource(ha, dma_mem);
2516 		kmem_free(dma_mem, sizeof (dma_mem_t));
2517 		cmd->Status = EXT_STATUS_ERR;
2518 		cmd->DetailStatus = status;
2519 		cmd->ResponseLen = 0;
2520 		return;
2521 	}
2522 
2523 	/* Setup status. */
2524 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
2525 		sts.scsi_status_l = pkt->sts24.scsi_status_l;
2526 		sts.scsi_status_h = pkt->sts24.scsi_status_h;
2527 
2528 		/* Setup residuals. */
2529 		sts.residual_length = LE_32(pkt->sts24.residual_length);
2530 
2531 		/* Setup state flags. */
2532 		sts.state_flags_l = pkt->sts24.state_flags_l;
2533 		sts.state_flags_h = pkt->sts24.state_flags_h;
2534 		if (pld_size && sts.comp_status != CS_DATA_UNDERRUN) {
2535 			sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2536 			    SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2537 			    SF_XFERRED_DATA | SF_GOT_STATUS);
2538 		} else {
2539 			sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2540 			    SF_GOT_BUS | SF_GOT_TARGET | SF_SENT_CMD |
2541 			    SF_GOT_STATUS);
2542 		}
2543 		if (scsi_req.direction & CF_WR) {
2544 			sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2545 			    SF_DATA_OUT);
2546 		} else if (scsi_req.direction & CF_RD) {
2547 			sts.state_flags_l = (uint8_t)(sts.state_flags_l |
2548 			    SF_DATA_IN);
2549 		}
2550 		sts.state_flags_l = (uint8_t)(sts.state_flags_l | SF_SIMPLE_Q);
2551 
2552 		/* Setup FCP response info. */
2553 		sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2554 		    LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
2555 		sts.rsp_info = &pkt->sts24.rsp_sense_data[0];
2556 		for (cnt = 0; cnt < sts.rsp_info_length;
2557 		    cnt = (uint16_t)(cnt + 4)) {
2558 			ql_chg_endian(sts.rsp_info + cnt, 4);
2559 		}
2560 
2561 		/* Setup sense data. */
2562 		if (sts.scsi_status_h & FCP_SNS_LEN_VALID) {
2563 			sts.req_sense_length =
2564 			    LE_32(pkt->sts24.fcp_sense_length);
2565 			sts.state_flags_h = (uint8_t)(sts.state_flags_h |
2566 			    SF_ARQ_DONE);
2567 		} else {
2568 			sts.req_sense_length = 0;
2569 		}
2570 		sts.req_sense_data =
2571 		    &pkt->sts24.rsp_sense_data[sts.rsp_info_length];
2572 		cnt2 = (uint16_t)(((uintptr_t)pkt + sizeof (sts_24xx_entry_t)) -
2573 		    (uintptr_t)sts.req_sense_data);
2574 		for (cnt = 0; cnt < cnt2; cnt = (uint16_t)(cnt + 4)) {
2575 			ql_chg_endian(sts.req_sense_data + cnt, 4);
2576 		}
2577 	} else {
2578 		sts.scsi_status_l = pkt->sts.scsi_status_l;
2579 		sts.scsi_status_h = pkt->sts.scsi_status_h;
2580 
2581 		/* Setup residuals. */
2582 		sts.residual_length = LE_32(pkt->sts.residual_length);
2583 
2584 		/* Setup state flags. */
2585 		sts.state_flags_l = pkt->sts.state_flags_l;
2586 		sts.state_flags_h = pkt->sts.state_flags_h;
2587 
2588 		/* Setup FCP response info. */
2589 		sts.rsp_info_length = sts.scsi_status_h & FCP_RSP_LEN_VALID ?
2590 		    LE_16(pkt->sts.rsp_info_length) : 0;
2591 		sts.rsp_info = &pkt->sts.rsp_info[0];
2592 
2593 		/* Setup sense data. */
2594 		sts.req_sense_length = sts.scsi_status_h & FCP_SNS_LEN_VALID ?
2595 		    LE_16(pkt->sts.req_sense_length) : 0;
2596 		sts.req_sense_data = &pkt->sts.req_sense_data[0];
2597 	}
2598 
2599 	QL_PRINT_9(ha, "response pkt\n");
2600 	QL_DUMP_9(&pkt->sts, 8, sizeof (sts_entry_t));
2601 
2602 	switch (sts.comp_status) {
2603 	case CS_INCOMPLETE:
2604 	case CS_ABORTED:
2605 	case CS_DEVICE_UNAVAILABLE:
2606 	case CS_PORT_UNAVAILABLE:
2607 	case CS_PORT_LOGGED_OUT:
2608 	case CS_PORT_CONFIG_CHG:
2609 	case CS_PORT_BUSY:
2610 	case CS_LOOP_DOWN_ABORT:
2611 		cmd->Status = EXT_STATUS_BUSY;
2612 		break;
2613 	case CS_RESET:
2614 	case CS_QUEUE_FULL:
2615 		cmd->Status = EXT_STATUS_ERR;
2616 		break;
2617 	case CS_TIMEOUT:
2618 		cmd->Status = EXT_STATUS_ERR;
2619 		break;
2620 	case CS_DATA_OVERRUN:
2621 		cmd->Status = EXT_STATUS_DATA_OVERRUN;
2622 		break;
2623 	case CS_DATA_UNDERRUN:
2624 		cmd->Status = EXT_STATUS_DATA_UNDERRUN;
2625 		break;
2626 	}
2627 
2628 	/*
2629 	 * If non data transfer commands fix tranfer counts.
2630 	 */
2631 	if (scsi_req.cdbp[0] == SCMD_TEST_UNIT_READY ||
2632 	    scsi_req.cdbp[0] == SCMD_REZERO_UNIT ||
2633 	    scsi_req.cdbp[0] == SCMD_SEEK ||
2634 	    scsi_req.cdbp[0] == SCMD_SEEK_G1 ||
2635 	    scsi_req.cdbp[0] == SCMD_RESERVE ||
2636 	    scsi_req.cdbp[0] == SCMD_RELEASE ||
2637 	    scsi_req.cdbp[0] == SCMD_START_STOP ||
2638 	    scsi_req.cdbp[0] == SCMD_DOORLOCK ||
2639 	    scsi_req.cdbp[0] == SCMD_VERIFY ||
2640 	    scsi_req.cdbp[0] == SCMD_WRITE_FILE_MARK ||
2641 	    scsi_req.cdbp[0] == SCMD_VERIFY_G0 ||
2642 	    scsi_req.cdbp[0] == SCMD_SPACE ||
2643 	    scsi_req.cdbp[0] == SCMD_ERASE ||
2644 	    (scsi_req.cdbp[0] == SCMD_FORMAT &&
2645 	    (scsi_req.cdbp[1] & FPB_DATA) == 0)) {
2646 		/*
2647 		 * Non data transfer command, clear sts_entry residual
2648 		 * length.
2649 		 */
2650 		sts.residual_length = 0;
2651 		cmd->ResponseLen = 0;
2652 		if (sts.comp_status == CS_DATA_UNDERRUN) {
2653 			sts.comp_status = CS_COMPLETE;
2654 			cmd->Status = EXT_STATUS_OK;
2655 		}
2656 	} else {
2657 		cmd->ResponseLen = pld_size;
2658 	}
2659 
2660 	/* Correct ISP completion status */
2661 	if (sts.comp_status == CS_COMPLETE && sts.scsi_status_l == 0 &&
2662 	    (sts.scsi_status_h & FCP_RSP_MASK) == 0) {
2663 		QL_PRINT_9(ha, "Correct completion\n",
2664 		    ha->instance);
2665 		scsi_req.resid = 0;
2666 	} else if (sts.comp_status == CS_DATA_UNDERRUN) {
2667 		QL_PRINT_9(ha, "Correct UNDERRUN\n",
2668 		    ha->instance);
2669 		scsi_req.resid = sts.residual_length;
2670 		if (sts.scsi_status_h & FCP_RESID_UNDER) {
2671 			cmd->Status = (uint32_t)EXT_STATUS_OK;
2672 
2673 			cmd->ResponseLen = (uint32_t)
2674 			    (pld_size - scsi_req.resid);
2675 		} else {
2676 			EL(ha, "failed, Transfer ERROR\n");
2677 			cmd->Status = EXT_STATUS_ERR;
2678 			cmd->ResponseLen = 0;
2679 		}
2680 	} else {
2681 		QL_PRINT_9(ha, "error d_id=%xh, comp_status=%xh, "
2682 		    "scsi_status_h=%xh, scsi_status_l=%xh\n",
2683 		    tq->d_id.b24, sts.comp_status, sts.scsi_status_h,
2684 		    sts.scsi_status_l);
2685 
2686 		scsi_req.resid = pld_size;
2687 		/*
2688 		 * Handle residual count on SCSI check
2689 		 * condition.
2690 		 *
2691 		 * - If Residual Under / Over is set, use the
2692 		 *   Residual Transfer Length field in IOCB.
2693 		 * - If Residual Under / Over is not set, and
2694 		 *   Transferred Data bit is set in State Flags
2695 		 *   field of IOCB, report residual value of 0
2696 		 *   (you may want to do this for tape
2697 		 *   Write-type commands only). This takes care
2698 		 *   of logical end of tape problem and does
2699 		 *   not break Unit Attention.
2700 		 * - If Residual Under / Over is not set, and
2701 		 *   Transferred Data bit is not set in State
2702 		 *   Flags, report residual value equal to
2703 		 *   original data transfer length.
2704 		 */
2705 		if (sts.scsi_status_l & STATUS_CHECK) {
2706 			cmd->Status = EXT_STATUS_SCSI_STATUS;
2707 			cmd->DetailStatus = sts.scsi_status_l;
2708 			if (sts.scsi_status_h &
2709 			    (FCP_RESID_OVER | FCP_RESID_UNDER)) {
2710 				scsi_req.resid = sts.residual_length;
2711 			} else if (sts.state_flags_h &
2712 			    STATE_XFERRED_DATA) {
2713 				scsi_req.resid = 0;
2714 			}
2715 		}
2716 	}
2717 
2718 	if (sts.scsi_status_l & STATUS_CHECK &&
2719 	    sts.scsi_status_h & FCP_SNS_LEN_VALID &&
2720 	    sts.req_sense_length) {
2721 		/*
2722 		 * Check condition with vaild sense data flag set and sense
2723 		 * length != 0
2724 		 */
2725 		if (sts.req_sense_length > scsi_req.sense_length) {
2726 			sense_sz = scsi_req.sense_length;
2727 		} else {
2728 			sense_sz = sts.req_sense_length;
2729 		}
2730 
2731 		EL(ha, "failed, Check Condition Status, d_id=%xh\n",
2732 		    tq->d_id.b24);
2733 		QL_DUMP_2(sts.req_sense_data, 8, sts.req_sense_length);
2734 
2735 		if (ddi_copyout(sts.req_sense_data, scsi_req.u_sense,
2736 		    (size_t)sense_sz, mode) != 0) {
2737 			EL(ha, "failed, request sense ddi_copyout\n");
2738 		}
2739 
2740 		cmd->Status = EXT_STATUS_SCSI_STATUS;
2741 		cmd->DetailStatus = sts.scsi_status_l;
2742 	}
2743 
2744 	/* Copy response payload from DMA buffer to application. */
2745 	if (scsi_req.direction & (CF_RD | CF_DATA_IN) &&
2746 	    cmd->ResponseLen != 0) {
2747 		QL_PRINT_9(ha, "Data Return resid=%lu, "
2748 		    "byte_count=%u, ResponseLen=%xh\n",
2749 		    scsi_req.resid, pld_size, cmd->ResponseLen);
2750 		QL_DUMP_9(pld, 8, cmd->ResponseLen);
2751 
2752 		/* Send response payload. */
2753 		if (ql_send_buffer_data(pld,
2754 		    (caddr_t)(uintptr_t)cmd->ResponseAdr,
2755 		    cmd->ResponseLen, mode) != cmd->ResponseLen) {
2756 			EL(ha, "failed, send_buffer_data\n");
2757 			cmd->Status = EXT_STATUS_COPY_ERR;
2758 			cmd->ResponseLen = 0;
2759 		}
2760 	}
2761 
2762 	if (cmd->Status != EXT_STATUS_OK) {
2763 		EL(ha, "failed, cmd->Status=%xh, comp_status=%xh, "
2764 		    "d_id=%xh\n", cmd->Status, sts.comp_status, tq->d_id.b24);
2765 	} else {
2766 		/*EMPTY*/
2767 		QL_PRINT_9(ha, "done, ResponseLen=%d\n",
2768 		    ha->instance, cmd->ResponseLen);
2769 	}
2770 
2771 	kmem_free(pkt, pkt_size);
2772 	ql_free_dma_resource(ha, dma_mem);
2773 	kmem_free(dma_mem, sizeof (dma_mem_t));
2774 }
2775 
2776 /*
2777  * ql_wwpn_to_scsiaddr
2778  *
2779  * Input:
2780  *	ha:	adapter state pointer.
2781  *	cmd:	EXT_IOCTL cmd struct pointer.
2782  *	mode:	flags.
2783  *
2784  * Context:
2785  *	Kernel context.
2786  */
2787 static void
ql_wwpn_to_scsiaddr(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2788 ql_wwpn_to_scsiaddr(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2789 {
2790 	int		status;
2791 	uint8_t		wwpn[EXT_DEF_WWN_NAME_SIZE];
2792 	EXT_SCSI_ADDR	*tmp_addr;
2793 	ql_tgt_t	*tq;
2794 
2795 	QL_PRINT_9(ha, "started\n");
2796 
2797 	if (cmd->RequestLen != EXT_DEF_WWN_NAME_SIZE) {
2798 		/* Return error */
2799 		EL(ha, "incorrect RequestLen\n");
2800 		cmd->Status = EXT_STATUS_INVALID_PARAM;
2801 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
2802 		return;
2803 	}
2804 
2805 	status = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, wwpn,
2806 	    cmd->RequestLen, mode);
2807 
2808 	if (status != 0) {
2809 		cmd->Status = EXT_STATUS_COPY_ERR;
2810 		EL(ha, "failed, ddi_copyin\n");
2811 		return;
2812 	}
2813 
2814 	tq = ql_find_port(ha, wwpn, QLNT_PORT);
2815 
2816 	if (tq == NULL || tq->flags & TQF_INITIATOR_DEVICE) {
2817 		/* no matching device */
2818 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
2819 		EL(ha, "failed, device not found\n");
2820 		return;
2821 	}
2822 
2823 	/* Copy out the IDs found.  For now we can only return target ID. */
2824 	tmp_addr = (EXT_SCSI_ADDR *)(uintptr_t)cmd->ResponseAdr;
2825 
2826 	status = ddi_copyout((void *)wwpn, (void *)&tmp_addr->Target, 8, mode);
2827 
2828 	if (status != 0) {
2829 		cmd->Status = EXT_STATUS_COPY_ERR;
2830 		EL(ha, "failed, ddi_copyout\n");
2831 	} else {
2832 		cmd->Status = EXT_STATUS_OK;
2833 		QL_PRINT_9(ha, "done\n");
2834 	}
2835 }
2836 
2837 /*
2838  * ql_host_idx
2839  *	Gets host order index.
2840  *
2841  * Input:
2842  *	ha:	adapter state pointer.
2843  *	cmd:	EXT_IOCTL cmd struct pointer.
2844  *	mode:	flags.
2845  *
2846  * Returns:
2847  *	None, request status indicated in cmd->Status.
2848  *
2849  * Context:
2850  *	Kernel context.
2851  */
2852 static void
ql_host_idx(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2853 ql_host_idx(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2854 {
2855 	uint16_t	idx;
2856 
2857 	QL_PRINT_9(ha, "started\n");
2858 
2859 	if (cmd->ResponseLen < sizeof (uint16_t)) {
2860 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2861 		cmd->DetailStatus = sizeof (uint16_t);
2862 		EL(ha, "failed, ResponseLen < Len=%xh\n", cmd->ResponseLen);
2863 		cmd->ResponseLen = 0;
2864 		return;
2865 	}
2866 
2867 	idx = (uint16_t)ha->instance;
2868 
2869 	if (ddi_copyout((void *)&idx, (void *)(uintptr_t)(cmd->ResponseAdr),
2870 	    sizeof (uint16_t), mode) != 0) {
2871 		cmd->Status = EXT_STATUS_COPY_ERR;
2872 		cmd->ResponseLen = 0;
2873 		EL(ha, "failed, ddi_copyout\n");
2874 	} else {
2875 		cmd->ResponseLen = sizeof (uint16_t);
2876 		QL_PRINT_9(ha, "done\n");
2877 	}
2878 }
2879 
2880 /*
2881  * ql_host_drvname
2882  *	Gets host driver name
2883  *
2884  * Input:
2885  *	ha:	adapter state pointer.
2886  *	cmd:	EXT_IOCTL cmd struct pointer.
2887  *	mode:	flags.
2888  *
2889  * Returns:
2890  *	None, request status indicated in cmd->Status.
2891  *
2892  * Context:
2893  *	Kernel context.
2894  */
2895 static void
ql_host_drvname(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2896 ql_host_drvname(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2897 {
2898 
2899 	char		drvname[] = QL_NAME;
2900 	uint32_t	qlnamelen;
2901 
2902 	QL_PRINT_9(ha, "started\n");
2903 
2904 	qlnamelen = (uint32_t)(strlen(QL_NAME) + 1);
2905 
2906 	if (cmd->ResponseLen < qlnamelen) {
2907 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2908 		cmd->DetailStatus = qlnamelen;
2909 		EL(ha, "failed, ResponseLen: %xh, needed: %xh\n",
2910 		    cmd->ResponseLen, qlnamelen);
2911 		cmd->ResponseLen = 0;
2912 		return;
2913 	}
2914 
2915 	if (ddi_copyout((void *)&drvname,
2916 	    (void *)(uintptr_t)(cmd->ResponseAdr),
2917 	    qlnamelen, mode) != 0) {
2918 		cmd->Status = EXT_STATUS_COPY_ERR;
2919 		cmd->ResponseLen = 0;
2920 		EL(ha, "failed, ddi_copyout\n");
2921 	} else {
2922 		cmd->ResponseLen = qlnamelen - 1;
2923 	}
2924 
2925 	QL_PRINT_9(ha, "done\n");
2926 }
2927 
2928 /*
2929  * ql_read_nvram
2930  *	Get NVRAM contents.
2931  *
2932  * Input:
2933  *	ha:	adapter state pointer.
2934  *	cmd:	EXT_IOCTL cmd struct pointer.
2935  *	mode:	flags.
2936  *
2937  * Returns:
2938  *	None, request status indicated in cmd->Status.
2939  *
2940  * Context:
2941  *	Kernel context.
2942  */
2943 static void
ql_read_nvram(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2944 ql_read_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2945 {
2946 
2947 	QL_PRINT_9(ha, "started\n");
2948 
2949 	if (cmd->ResponseLen < ha->nvram_cache->size) {
2950 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2951 		cmd->DetailStatus = ha->nvram_cache->size;
2952 		EL(ha, "failed, ResponseLen != NVRAM, Len=%xh\n",
2953 		    cmd->ResponseLen);
2954 		cmd->ResponseLen = 0;
2955 		return;
2956 	}
2957 
2958 	/* Get NVRAM data. */
2959 	if (ql_nv_util_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
2960 	    mode) != 0) {
2961 		cmd->Status = EXT_STATUS_COPY_ERR;
2962 		cmd->ResponseLen = 0;
2963 		EL(ha, "failed, copy error\n");
2964 	} else {
2965 		cmd->ResponseLen = ha->nvram_cache->size;
2966 		QL_PRINT_9(ha, "done\n");
2967 	}
2968 }
2969 
2970 /*
2971  * ql_write_nvram
2972  *	Loads NVRAM contents.
2973  *
2974  * Input:
2975  *	ha:	adapter state pointer.
2976  *	cmd:	EXT_IOCTL cmd struct pointer.
2977  *	mode:	flags.
2978  *
2979  * Returns:
2980  *	None, request status indicated in cmd->Status.
2981  *
2982  * Context:
2983  *	Kernel context.
2984  */
2985 static void
ql_write_nvram(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)2986 ql_write_nvram(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
2987 {
2988 
2989 	QL_PRINT_9(ha, "started\n");
2990 
2991 	if (cmd->RequestLen < ha->nvram_cache->size) {
2992 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
2993 		cmd->DetailStatus = ha->nvram_cache->size;
2994 		EL(ha, "failed, RequestLen != NVRAM, Len=%xh\n",
2995 		    cmd->RequestLen);
2996 		return;
2997 	}
2998 
2999 	/* Load NVRAM data. */
3000 	if (ql_nv_util_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
3001 	    mode) != 0) {
3002 		cmd->Status = EXT_STATUS_COPY_ERR;
3003 		EL(ha, "failed, copy error\n");
3004 	} else {
3005 		/*EMPTY*/
3006 		QL_PRINT_9(ha, "done\n");
3007 	}
3008 }
3009 
3010 /*
3011  * ql_write_vpd
3012  *	Loads VPD contents.
3013  *
3014  * Input:
3015  *	ha:	adapter state pointer.
3016  *	cmd:	EXT_IOCTL cmd struct pointer.
3017  *	mode:	flags.
3018  *
3019  * Returns:
3020  *	None, request status indicated in cmd->Status.
3021  *
3022  * Context:
3023  *	Kernel context.
3024  */
3025 static void
ql_write_vpd(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3026 ql_write_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3027 {
3028 	QL_PRINT_9(ha, "started\n");
3029 
3030 	int32_t		rval = 0;
3031 
3032 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3033 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
3034 		EL(ha, "failed, invalid request for HBA\n");
3035 		return;
3036 	}
3037 
3038 	if (cmd->RequestLen < QL_24XX_VPD_SIZE) {
3039 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3040 		cmd->DetailStatus = QL_24XX_VPD_SIZE;
3041 		EL(ha, "failed, RequestLen != VPD len, len passed=%xh\n",
3042 		    cmd->RequestLen);
3043 		return;
3044 	}
3045 
3046 	/* Load VPD data. */
3047 	if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)(cmd->RequestAdr),
3048 	    mode)) != 0) {
3049 		cmd->Status = EXT_STATUS_COPY_ERR;
3050 		cmd->DetailStatus = rval;
3051 		EL(ha, "failed, errno=%x\n", rval);
3052 	} else {
3053 		/*EMPTY*/
3054 		QL_PRINT_9(ha, "done\n");
3055 	}
3056 }
3057 
3058 /*
3059  * ql_read_vpd
3060  *	Dumps VPD contents.
3061  *
3062  * Input:
3063  *	ha:	adapter state pointer.
3064  *	cmd:	EXT_IOCTL cmd struct pointer.
3065  *	mode:	flags.
3066  *
3067  * Returns:
3068  *	None, request status indicated in cmd->Status.
3069  *
3070  * Context:
3071  *	Kernel context.
3072  */
3073 static void
ql_read_vpd(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3074 ql_read_vpd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3075 {
3076 	QL_PRINT_9(ha, "started\n");
3077 
3078 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3079 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
3080 		EL(ha, "failed, invalid request for HBA\n");
3081 		return;
3082 	}
3083 
3084 	if (cmd->ResponseLen < QL_24XX_VPD_SIZE) {
3085 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3086 		cmd->DetailStatus = QL_24XX_VPD_SIZE;
3087 		EL(ha, "failed, ResponseLen < VPD len, len passed=%xh\n",
3088 		    cmd->ResponseLen);
3089 		return;
3090 	}
3091 
3092 	/* Dump VPD data. */
3093 	if ((ql_vpd_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
3094 	    mode)) != 0) {
3095 		cmd->Status = EXT_STATUS_COPY_ERR;
3096 		EL(ha, "failed,\n");
3097 	} else {
3098 		/*EMPTY*/
3099 		QL_PRINT_9(ha, "done\n");
3100 	}
3101 }
3102 
3103 /*
3104  * ql_get_fcache
3105  *	Dumps flash cache contents.
3106  *
3107  * Input:
3108  *	ha:	adapter state pointer.
3109  *	cmd:	EXT_IOCTL cmd struct pointer.
3110  *	mode:	flags.
3111  *
3112  * Returns:
3113  *	None, request status indicated in cmd->Status.
3114  *
3115  * Context:
3116  *	Kernel context.
3117  */
3118 static void
ql_get_fcache(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3119 ql_get_fcache(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3120 {
3121 	uint32_t	bsize, boff, types, cpsize, hsize;
3122 	ql_fcache_t	*fptr;
3123 
3124 	QL_PRINT_9(ha, "started\n");
3125 
3126 	if (ha->fcache == NULL) {
3127 		cmd->Status = EXT_STATUS_ERR;
3128 		EL(ha, "failed, adapter fcache not setup\n");
3129 		return;
3130 	}
3131 
3132 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3133 		bsize = 100;
3134 	} else {
3135 		bsize = 400;
3136 	}
3137 
3138 	if (cmd->ResponseLen < bsize) {
3139 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3140 		cmd->DetailStatus = bsize;
3141 		EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3142 		    bsize, cmd->ResponseLen);
3143 		return;
3144 	}
3145 
3146 	boff = 0;
3147 	bsize = 0;
3148 	fptr = ha->fcache;
3149 
3150 	/*
3151 	 * For backwards compatibility, get one of each image type
3152 	 */
3153 	types = (FTYPE_BIOS | FTYPE_FCODE | FTYPE_EFI);
3154 	while ((fptr != NULL) && (fptr->buf != NULL) && (types != 0)) {
3155 		/* Get the next image */
3156 		if ((fptr = ql_get_fbuf(ha->fcache, types)) != NULL) {
3157 
3158 			cpsize = (fptr->buflen < 100 ? fptr->buflen : 100);
3159 
3160 			if (ddi_copyout(fptr->buf,
3161 			    (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3162 			    cpsize, mode) != 0) {
3163 				EL(ha, "ddicopy failed, done\n");
3164 				cmd->Status = EXT_STATUS_COPY_ERR;
3165 				cmd->DetailStatus = 0;
3166 				return;
3167 			}
3168 			boff += 100;
3169 			bsize += cpsize;
3170 			types &= ~(fptr->type);
3171 		}
3172 	}
3173 
3174 	/*
3175 	 * Get the firmware image -- it needs to be last in the
3176 	 * buffer at offset 300 for backwards compatibility. Also for
3177 	 * backwards compatibility, the pci header is stripped off.
3178 	 */
3179 	if ((fptr = ql_get_fbuf(ha->fcache, FTYPE_FW)) != NULL) {
3180 
3181 		hsize = sizeof (pci_header_t) + sizeof (pci_data_t);
3182 		if (hsize > fptr->buflen) {
3183 			EL(ha, "header size (%xh) exceeds buflen (%xh)\n",
3184 			    hsize, fptr->buflen);
3185 			cmd->Status = EXT_STATUS_COPY_ERR;
3186 			cmd->DetailStatus = 0;
3187 			return;
3188 		}
3189 
3190 		cpsize = ((fptr->buflen - hsize) < 100 ?
3191 		    fptr->buflen - hsize : 100);
3192 
3193 		if (ddi_copyout(fptr->buf + hsize,
3194 		    (void *)(uintptr_t)(cmd->ResponseAdr + 300),
3195 		    cpsize, mode) != 0) {
3196 			EL(ha, "fw ddicopy failed, done\n");
3197 			cmd->Status = EXT_STATUS_COPY_ERR;
3198 			cmd->DetailStatus = 0;
3199 			return;
3200 		}
3201 		bsize += 100;
3202 	}
3203 
3204 	cmd->Status = EXT_STATUS_OK;
3205 	cmd->DetailStatus = bsize;
3206 
3207 	QL_PRINT_9(ha, "done\n");
3208 }
3209 
3210 /*
3211  * ql_get_fcache_ex
3212  *	Dumps flash cache contents.
3213  *
3214  * Input:
3215  *	ha:	adapter state pointer.
3216  *	cmd:	EXT_IOCTL cmd struct pointer.
3217  *	mode:	flags.
3218  *
3219  * Returns:
3220  *	None, request status indicated in cmd->Status.
3221  *
3222  * Context:
3223  *	Kernel context.
3224  */
3225 static void
ql_get_fcache_ex(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3226 ql_get_fcache_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3227 {
3228 	uint32_t	bsize = 0;
3229 	uint32_t	boff = 0;
3230 	ql_fcache_t	*fptr;
3231 
3232 	QL_PRINT_9(ha, "started\n");
3233 
3234 	if (ha->fcache == NULL) {
3235 		cmd->Status = EXT_STATUS_ERR;
3236 		EL(ha, "failed, adapter fcache not setup\n");
3237 		return;
3238 	}
3239 
3240 	/* Make sure user passed enough buffer space */
3241 	for (fptr = ha->fcache; fptr != NULL; fptr = fptr->next) {
3242 		bsize += FBUFSIZE;
3243 	}
3244 
3245 	if (cmd->ResponseLen < bsize) {
3246 		if (cmd->ResponseLen != 0) {
3247 			EL(ha, "failed, ResponseLen < %d, len passed=%xh\n",
3248 			    bsize, cmd->ResponseLen);
3249 		}
3250 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
3251 		cmd->DetailStatus = bsize;
3252 		return;
3253 	}
3254 
3255 	boff = 0;
3256 	fptr = ha->fcache;
3257 	while ((fptr != NULL) && (fptr->buf != NULL)) {
3258 		/* Get the next image */
3259 		if (ddi_copyout(fptr->buf,
3260 		    (void *)(uintptr_t)(cmd->ResponseAdr + boff),
3261 		    (fptr->buflen < FBUFSIZE ? fptr->buflen : FBUFSIZE),
3262 		    mode) != 0) {
3263 			EL(ha, "failed, ddicopy at %xh, done\n", boff);
3264 			cmd->Status = EXT_STATUS_COPY_ERR;
3265 			cmd->DetailStatus = 0;
3266 			return;
3267 		}
3268 		boff += FBUFSIZE;
3269 		fptr = fptr->next;
3270 	}
3271 
3272 	cmd->Status = EXT_STATUS_OK;
3273 	cmd->DetailStatus = bsize;
3274 
3275 	QL_PRINT_9(ha, "done\n");
3276 }
3277 
3278 /*
3279  * ql_read_flash
3280  *	Get flash contents.
3281  *
3282  * Input:
3283  *	ha:	adapter state pointer.
3284  *	cmd:	EXT_IOCTL cmd struct pointer.
3285  *	mode:	flags.
3286  *
3287  * Returns:
3288  *	None, request status indicated in cmd->Status.
3289  *
3290  * Context:
3291  *	Kernel context.
3292  */
3293 static void
ql_read_flash(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3294 ql_read_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3295 {
3296 	ql_xioctl_t	*xp = ha->xioctl;
3297 
3298 	QL_PRINT_9(ha, "started\n");
3299 
3300 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) &&
3301 	    ql_stall_driver(ha, 0) != QL_SUCCESS) {
3302 		EL(ha, "ql_stall_driver failed\n");
3303 		ql_restart_driver(ha);
3304 		cmd->Status = EXT_STATUS_BUSY;
3305 		cmd->DetailStatus = xp->fdesc.flash_size;
3306 		cmd->ResponseLen = 0;
3307 		return;
3308 	}
3309 
3310 	if (ql_setup_fcache(ha) != QL_SUCCESS) {
3311 		cmd->Status = EXT_STATUS_ERR;
3312 		cmd->DetailStatus = xp->fdesc.flash_size;
3313 		EL(ha, "failed, ResponseLen=%xh, flash size=%xh\n",
3314 		    cmd->ResponseLen, xp->fdesc.flash_size);
3315 		cmd->ResponseLen = 0;
3316 	} else {
3317 		/* adjust read size to flash size */
3318 		if (cmd->ResponseLen > xp->fdesc.flash_size) {
3319 			EL(ha, "adjusting req=%xh, max=%xh\n",
3320 			    cmd->ResponseLen, xp->fdesc.flash_size);
3321 			cmd->ResponseLen = xp->fdesc.flash_size;
3322 		}
3323 
3324 		/* Get flash data. */
3325 		if (ql_flash_fcode_dump(ha,
3326 		    (void *)(uintptr_t)(cmd->ResponseAdr),
3327 		    (size_t)(cmd->ResponseLen), 0, mode) != 0) {
3328 			cmd->Status = EXT_STATUS_COPY_ERR;
3329 			cmd->ResponseLen = 0;
3330 			EL(ha, "failed,\n");
3331 		}
3332 	}
3333 
3334 	/* Resume I/O */
3335 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3336 		EL(ha, "isp_abort_needed for restart\n");
3337 		ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
3338 		    DRIVER_STALL);
3339 	}
3340 
3341 	QL_PRINT_9(ha, "done\n");
3342 }
3343 
3344 /*
3345  * ql_write_flash
3346  *	Loads flash contents.
3347  *
3348  * Input:
3349  *	ha:	adapter state pointer.
3350  *	cmd:	EXT_IOCTL cmd struct pointer.
3351  *	mode:	flags.
3352  *
3353  * Returns:
3354  *	None, request status indicated in cmd->Status.
3355  *
3356  * Context:
3357  *	Kernel context.
3358  */
3359 static void
ql_write_flash(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3360 ql_write_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3361 {
3362 	ql_xioctl_t	*xp = ha->xioctl;
3363 
3364 	QL_PRINT_9(ha, "started\n");
3365 
3366 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) &&
3367 	    ql_stall_driver(ha, 0) != QL_SUCCESS) {
3368 		EL(ha, "ql_stall_driver failed\n");
3369 		ql_restart_driver(ha);
3370 		cmd->Status = EXT_STATUS_BUSY;
3371 		cmd->DetailStatus = xp->fdesc.flash_size;
3372 		cmd->ResponseLen = 0;
3373 		return;
3374 	}
3375 
3376 	if (ql_setup_fcache(ha) != QL_SUCCESS) {
3377 		cmd->Status = EXT_STATUS_ERR;
3378 		cmd->DetailStatus = xp->fdesc.flash_size;
3379 		EL(ha, "failed, RequestLen=%xh, size=%xh\n",
3380 		    cmd->RequestLen, xp->fdesc.flash_size);
3381 		cmd->ResponseLen = 0;
3382 	} else {
3383 		/* Load flash data. */
3384 		if (cmd->RequestLen > xp->fdesc.flash_size) {
3385 			cmd->Status = EXT_STATUS_ERR;
3386 			cmd->DetailStatus = xp->fdesc.flash_size;
3387 			EL(ha, "failed, RequestLen=%xh, flash size=%xh\n",
3388 			    cmd->RequestLen, xp->fdesc.flash_size);
3389 		} else if (ql_flash_fcode_load(ha,
3390 		    (void *)(uintptr_t)(cmd->RequestAdr),
3391 		    (size_t)(cmd->RequestLen), mode) != 0) {
3392 			cmd->Status = EXT_STATUS_COPY_ERR;
3393 			EL(ha, "failed,\n");
3394 		}
3395 	}
3396 
3397 	/* Resume I/O */
3398 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3399 		EL(ha, "isp_abort_needed for restart\n");
3400 		ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
3401 		    DRIVER_STALL);
3402 	}
3403 
3404 	QL_PRINT_9(ha, "done\n");
3405 }
3406 
3407 /*
3408  * ql_diagnostic_loopback
3409  *	Performs EXT_CC_LOOPBACK Command
3410  *
3411  * Input:
3412  *	ha:	adapter state pointer.
3413  *	cmd:	Local EXT_IOCTL cmd struct pointer.
3414  *	mode:	flags.
3415  *
3416  * Returns:
3417  *	None, request status indicated in cmd->Status.
3418  *
3419  * Context:
3420  *	Kernel context.
3421  */
3422 static void
ql_diagnostic_loopback(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3423 ql_diagnostic_loopback(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3424 {
3425 	EXT_LOOPBACK_REQ	plbreq;
3426 	EXT_LOOPBACK_RSP	plbrsp;
3427 	ql_mbx_data_t		mr;
3428 	uint32_t		rval, timer, bpsize;
3429 	caddr_t			bp, pld;
3430 	uint16_t		opt;
3431 	boolean_t		loop_up;
3432 
3433 	QL_PRINT_9(ha, "started\n");
3434 
3435 	/* Get loop back request. */
3436 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
3437 	    (void *)&plbreq, sizeof (EXT_LOOPBACK_REQ), mode) != 0) {
3438 		EL(ha, "failed, ddi_copyin\n");
3439 		cmd->Status = EXT_STATUS_COPY_ERR;
3440 		cmd->ResponseLen = 0;
3441 		return;
3442 	}
3443 
3444 	/* Check transfer length fits in buffer. */
3445 	if (plbreq.BufferLength < plbreq.TransferCount) {
3446 		EL(ha, "failed, BufferLength=%d, xfercnt=%d\n",
3447 
3448 		    plbreq.BufferLength, plbreq.TransferCount);
3449 		cmd->Status = EXT_STATUS_INVALID_PARAM;
3450 		cmd->ResponseLen = 0;
3451 		return;
3452 	}
3453 
3454 	/* Allocate command memory. */
3455 	bpsize = plbreq.TransferCount + 4; /* Include opcode size */
3456 	bp = kmem_zalloc(bpsize, KM_SLEEP);
3457 	if (bp == NULL) {
3458 		EL(ha, "failed, kmem_zalloc\n");
3459 		cmd->Status = EXT_STATUS_NO_MEMORY;
3460 		cmd->ResponseLen = 0;
3461 		return;
3462 	}
3463 	pld = bp + 4;
3464 	*bp = 0x10;	/* opcode */
3465 
3466 	/* Get loopback data. */
3467 	if (ql_get_buffer_data((caddr_t)(uintptr_t)plbreq.BufferAddress,
3468 	    pld, plbreq.TransferCount, mode) != plbreq.TransferCount) {
3469 		EL(ha, "failed, ddi_copyin-2\n");
3470 		kmem_free(bp, bpsize);
3471 		cmd->Status = EXT_STATUS_COPY_ERR;
3472 		cmd->ResponseLen = 0;
3473 		return;
3474 	}
3475 
3476 	if (LOOP_RECONFIGURE(ha) ||
3477 	    ql_stall_driver(ha, 0) != QL_SUCCESS) {
3478 		EL(ha, "failed, LOOP_NOT_READY\n");
3479 		ql_restart_driver(ha);
3480 		kmem_free(bp, bpsize);
3481 		cmd->Status = EXT_STATUS_BUSY;
3482 		cmd->ResponseLen = 0;
3483 		return;
3484 	}
3485 	loop_up = ha->task_daemon_flags & LOOP_DOWN ? B_FALSE : B_TRUE;
3486 
3487 	/* Shutdown IP. */
3488 	if (ha->flags & IP_INITIALIZED) {
3489 		(void) ql_shutdown_ip(ha);
3490 	}
3491 
3492 	/* determine topology so we can send the loopback or the echo */
3493 	/* Echo is supported on 2300's only and above */
3494 
3495 	ADAPTER_STATE_LOCK(ha);
3496 	ha->flags |= LOOPBACK_ACTIVE;
3497 	ADAPTER_STATE_UNLOCK(ha);
3498 
3499 	opt = plbreq.Options;
3500 
3501 	if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
3502 		opt = (uint16_t)(plbreq.Options & MBC_LOOPBACK_POINT_MASK);
3503 		if (loop_up && opt == MBC_LOOPBACK_POINT_EXTERNAL) {
3504 			if (plbreq.TransferCount > 252) {
3505 				EL(ha, "transfer count (%d) > 252\n",
3506 				    plbreq.TransferCount);
3507 				ql_restart_driver(ha);
3508 				kmem_free(bp, bpsize);
3509 				cmd->Status = EXT_STATUS_INVALID_PARAM;
3510 				cmd->ResponseLen = 0;
3511 				return;
3512 			}
3513 			plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD;
3514 			rval = ql_diag_echo(ha, pld, plbreq.TransferCount,
3515 			    MBC_ECHO_ELS, &mr);
3516 		} else {
3517 			if (CFG_IST(ha, CFG_LOOP_POINT_SUPPORT)) {
3518 				(void) ql_set_loop_point(ha, opt);
3519 			}
3520 			plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD;
3521 			rval = ql_diag_loopback(ha, pld, plbreq.TransferCount,
3522 			    opt, plbreq.IterationCount, &mr);
3523 			if (mr.mb[0] == 0x4005 && mr.mb[1] == 0x17) {
3524 				(void) ql_abort_isp(ha);
3525 			}
3526 			if (CFG_IST(ha, CFG_LOOP_POINT_SUPPORT)) {
3527 				(void) ql_set_loop_point(ha, 0);
3528 			}
3529 		}
3530 	} else {
3531 		if (loop_up && (ha->topology & QL_F_PORT) &&
3532 		    CFG_IST(ha, CFG_LB_ECHO_SUPPORT)) {
3533 			QL_PRINT_9(ha, "F_PORT topology -- using "
3534 			    "echo\n");
3535 			plbrsp.CommandSent = INT_DEF_LB_ECHO_CMD;
3536 			if ((rval = ql_diag_echo(ha, bp, bpsize,
3537 			    (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_1) ?
3538 			    MBC_ECHO_64BIT : MBC_ECHO_ELS), &mr)) !=
3539 			    QL_SUCCESS) {
3540 				rval = ql_diag_echo(ha, pld,
3541 				    plbreq.TransferCount,
3542 				    (uint16_t)(CFG_IST(ha, CFG_ISP_FW_TYPE_1) ?
3543 				    MBC_ECHO_64BIT : 0), &mr);
3544 			}
3545 		} else {
3546 			plbrsp.CommandSent = INT_DEF_LB_LOOPBACK_CMD;
3547 			if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
3548 				opt = (uint16_t)(opt | MBC_LOOPBACK_64BIT);
3549 			}
3550 			rval = ql_diag_loopback(ha, pld, plbreq.TransferCount,
3551 			    opt, plbreq.IterationCount, &mr);
3552 		}
3553 	}
3554 	ADAPTER_STATE_LOCK(ha);
3555 	ha->flags &= ~LOOPBACK_ACTIVE;
3556 	ADAPTER_STATE_UNLOCK(ha);
3557 
3558 	ql_restart_driver(ha);
3559 	if (loop_up && opt == MBC_LOOPBACK_POINT_INTERNAL) {
3560 		timer = 30;
3561 		do {
3562 			delay(100);
3563 		} while (timer-- && LOOP_NOT_READY(ha));
3564 	}
3565 
3566 	/* Restart IP if it was shutdown. */
3567 	if (ha->flags & IP_ENABLED && !(ha->flags & IP_INITIALIZED)) {
3568 		(void) ql_initialize_ip(ha);
3569 		ql_isp_rcvbuf(ha);
3570 	}
3571 
3572 	if (rval != QL_SUCCESS) {
3573 		EL(ha, "failed, diagnostic_loopback_mbx=%xh\n", rval);
3574 		kmem_free(bp, bpsize);
3575 		cmd->Status = EXT_STATUS_MAILBOX;
3576 		cmd->DetailStatus = rval;
3577 		cmd->ResponseLen = 0;
3578 		return;
3579 	}
3580 
3581 	/* Return loopback data. */
3582 	if (ql_send_buffer_data(pld, (caddr_t)(uintptr_t)plbreq.BufferAddress,
3583 	    plbreq.TransferCount, mode) != plbreq.TransferCount) {
3584 		EL(ha, "failed, ddi_copyout\n");
3585 		kmem_free(bp, bpsize);
3586 		cmd->Status = EXT_STATUS_COPY_ERR;
3587 		cmd->ResponseLen = 0;
3588 		return;
3589 	}
3590 	kmem_free(bp, bpsize);
3591 
3592 	/* Return loopback results. */
3593 	plbrsp.BufferAddress = plbreq.BufferAddress;
3594 	plbrsp.BufferLength = plbreq.TransferCount;
3595 	plbrsp.CompletionStatus = mr.mb[0];
3596 
3597 	if (plbrsp.CommandSent == INT_DEF_LB_ECHO_CMD) {
3598 		plbrsp.CrcErrorCount = 0;
3599 		plbrsp.DisparityErrorCount = 0;
3600 		plbrsp.FrameLengthErrorCount = 0;
3601 		plbrsp.IterationCountLastError = 0;
3602 	} else {
3603 		plbrsp.CrcErrorCount = mr.mb[1];
3604 		plbrsp.DisparityErrorCount = mr.mb[2];
3605 		plbrsp.FrameLengthErrorCount = mr.mb[3];
3606 		plbrsp.IterationCountLastError =
3607 		    SHORT_TO_LONG(mr.mb[18], mr.mb[19]);
3608 	}
3609 
3610 	rval = ddi_copyout((void *)&plbrsp,
3611 	    (void *)(uintptr_t)cmd->ResponseAdr,
3612 	    sizeof (EXT_LOOPBACK_RSP), mode);
3613 	if (rval != 0) {
3614 		EL(ha, "failed, ddi_copyout-2\n");
3615 		cmd->Status = EXT_STATUS_COPY_ERR;
3616 		cmd->ResponseLen = 0;
3617 		return;
3618 	}
3619 	cmd->ResponseLen = sizeof (EXT_LOOPBACK_RSP);
3620 
3621 	QL_PRINT_9(ha, "done\n");
3622 }
3623 
3624 /*
3625  * ql_set_loop_point
3626  *	Setup loop point for port configuration.
3627  *
3628  * Input:
3629  *	ha:	adapter state structure.
3630  *	opt:	loop point option.
3631  *
3632  * Returns:
3633  *	ql local function return status code.
3634  *
3635  * Context:
3636  *	Kernel context.
3637  */
3638 int
ql_set_loop_point(ql_adapter_state_t * ha,uint16_t opt)3639 ql_set_loop_point(ql_adapter_state_t *ha, uint16_t opt)
3640 {
3641 	ql_mbx_data_t	mr;
3642 	int		rval;
3643 	uint32_t	timer;
3644 
3645 	QL_PRINT_9(ha, "started\n");
3646 
3647 	/*
3648 	 * We get the current port config, modify the loopback field and
3649 	 * write it back out.
3650 	 */
3651 	if ((rval = ql_get_port_config(ha, &mr)) != QL_SUCCESS) {
3652 		EL(ha, "get_port_config status=%xh\n", rval);
3653 		return (rval);
3654 	}
3655 	/*
3656 	 * Set the loopback mode field while maintaining the others.
3657 	 */
3658 	mr.mb[1] = (uint16_t)(mr.mb[1] & ~LOOPBACK_MODE_FIELD_MASK);
3659 	if (opt == MBC_LOOPBACK_POINT_INTERNAL) {
3660 		mr.mb[1] = (uint16_t)(mr.mb[1] | LOOPBACK_MODE_INTERNAL);
3661 	} else if (CFG_IST(ha, CFG_CTRL_80XX) &&
3662 	    opt == MBC_LOOPBACK_POINT_EXTERNAL) {
3663 		mr.mb[1] = (uint16_t)(mr.mb[1] | LOOPBACK_MODE_EXTERNAL);
3664 	}
3665 	/*
3666 	 * Changing the port configuration will cause the port state to cycle
3667 	 * down and back up. The indication that this has happened is that
3668 	 * the point to point flag gets set.
3669 	 */
3670 	ADAPTER_STATE_LOCK(ha);
3671 	ha->flags &= ~POINT_TO_POINT;
3672 	ADAPTER_STATE_UNLOCK(ha);
3673 	if ((rval = ql_set_port_config(ha, &mr)) != QL_SUCCESS) {
3674 		EL(ha, "set_port_config status=%xh\n", rval);
3675 	}
3676 
3677 	/* wait for a while */
3678 	for (timer = opt ? 10 : 0; timer; timer--) {
3679 		if (ha->flags & POINT_TO_POINT) {
3680 			break;
3681 		}
3682 		/* Delay for 1000000 usec (1 second). */
3683 		ql_delay(ha, 1000000);
3684 	}
3685 
3686 	QL_PRINT_9(ha, "done\n");
3687 
3688 	return (rval);
3689 }
3690 
3691 /*
3692  * ql_send_els_rnid
3693  *	IOCTL for extended link service RNID command.
3694  *
3695  * Input:
3696  *	ha:	adapter state pointer.
3697  *	cmd:	User space CT arguments pointer.
3698  *	mode:	flags.
3699  *
3700  * Returns:
3701  *	None, request status indicated in cmd->Status.
3702  *
3703  * Context:
3704  *	Kernel context.
3705  */
3706 static void
ql_send_els_rnid(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3707 ql_send_els_rnid(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3708 {
3709 	EXT_RNID_REQ	tmp_rnid;
3710 	port_id_t	tmp_fcid;
3711 	caddr_t		tmp_buf, bptr;
3712 	uint32_t	copy_len;
3713 	ql_tgt_t	*tq = NULL;
3714 	EXT_RNID_DATA	rnid_data;
3715 	uint32_t	loop_ready_wait = 10 * 60 * 10;
3716 	int		rval = 0;
3717 	uint32_t	local_hba = 0;
3718 
3719 	QL_PRINT_9(ha, "started\n");
3720 
3721 	if (DRIVER_SUSPENDED(ha)) {
3722 		EL(ha, "failed, LOOP_NOT_READY\n");
3723 		cmd->Status = EXT_STATUS_BUSY;
3724 		cmd->ResponseLen = 0;
3725 		return;
3726 	}
3727 
3728 	if (cmd->RequestLen != sizeof (EXT_RNID_REQ)) {
3729 		/* parameter error */
3730 		EL(ha, "failed, RequestLen < EXT_RNID_REQ, Len=%xh\n",
3731 		    cmd->RequestLen);
3732 		cmd->Status = EXT_STATUS_INVALID_PARAM;
3733 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
3734 		cmd->ResponseLen = 0;
3735 		return;
3736 	}
3737 
3738 	if (ddi_copyin((void*)(uintptr_t)cmd->RequestAdr,
3739 	    &tmp_rnid, cmd->RequestLen, mode) != 0) {
3740 		EL(ha, "failed, ddi_copyin\n");
3741 		cmd->Status = EXT_STATUS_COPY_ERR;
3742 		cmd->ResponseLen = 0;
3743 		return;
3744 	}
3745 
3746 	/* Find loop ID of the device */
3747 	if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWNN) {
3748 		bptr = (caddr_t)ha->loginparams.node_ww_name.raw_wwn;
3749 		if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWNN,
3750 		    EXT_DEF_WWN_NAME_SIZE) == 0) {
3751 			local_hba = 1;
3752 		} else {
3753 			tq = ql_find_port(ha,
3754 			    (uint8_t *)tmp_rnid.Addr.FcAddr.WWNN, QLNT_NODE);
3755 		}
3756 	} else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_WWPN) {
3757 		bptr = (caddr_t)ha->loginparams.nport_ww_name.raw_wwn;
3758 		if (bcmp((void *)bptr, (void *)tmp_rnid.Addr.FcAddr.WWPN,
3759 		    EXT_DEF_WWN_NAME_SIZE) == 0) {
3760 			local_hba = 1;
3761 		} else {
3762 			tq = ql_find_port(ha,
3763 			    (uint8_t *)tmp_rnid.Addr.FcAddr.WWPN, QLNT_PORT);
3764 		}
3765 	} else if (tmp_rnid.Addr.Type == EXT_DEF_TYPE_PORTID) {
3766 		/*
3767 		 * Copy caller's d_id to tmp space.
3768 		 */
3769 		bcopy(&tmp_rnid.Addr.FcAddr.Id[1], tmp_fcid.r.d_id,
3770 		    EXT_DEF_PORTID_SIZE_ACTUAL);
3771 		BIG_ENDIAN_24(&tmp_fcid.r.d_id[0]);
3772 
3773 		if (bcmp((void *)&ha->d_id, (void *)tmp_fcid.r.d_id,
3774 		    EXT_DEF_PORTID_SIZE_ACTUAL) == 0) {
3775 			local_hba = 1;
3776 		} else {
3777 			tq = ql_find_port(ha, (uint8_t *)tmp_fcid.r.d_id,
3778 			    QLNT_PID);
3779 		}
3780 	}
3781 
3782 	/* Allocate memory for command. */
3783 	tmp_buf = kmem_zalloc(SEND_RNID_RSP_SIZE, KM_SLEEP);
3784 	if (tmp_buf == NULL) {
3785 		EL(ha, "failed, kmem_zalloc\n");
3786 		cmd->Status = EXT_STATUS_NO_MEMORY;
3787 		cmd->ResponseLen = 0;
3788 		return;
3789 	}
3790 
3791 	if (local_hba) {
3792 		rval = ql_get_rnid_params(ha, SEND_RNID_RSP_SIZE, tmp_buf);
3793 		if (rval != QL_SUCCESS) {
3794 			EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
3795 			kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3796 			cmd->Status = EXT_STATUS_ERR;
3797 			cmd->ResponseLen = 0;
3798 			return;
3799 		}
3800 
3801 		/* Save gotten RNID data. */
3802 		bcopy(tmp_buf, &rnid_data, sizeof (EXT_RNID_DATA));
3803 
3804 		/* Now build the Send RNID response */
3805 		tmp_buf[0] = (char)(EXT_DEF_RNID_DFORMAT_TOPO_DISC);
3806 		tmp_buf[1] = (2 * EXT_DEF_WWN_NAME_SIZE);
3807 		tmp_buf[2] = 0;
3808 		tmp_buf[3] = sizeof (EXT_RNID_DATA);
3809 		bcopy(ha->loginparams.nport_ww_name.raw_wwn, &tmp_buf[4],
3810 		    EXT_DEF_WWN_NAME_SIZE);
3811 		bcopy(ha->loginparams.node_ww_name.raw_wwn,
3812 		    &tmp_buf[4 + EXT_DEF_WWN_NAME_SIZE],
3813 		    EXT_DEF_WWN_NAME_SIZE);
3814 		bcopy((uint8_t *)&rnid_data,
3815 		    &tmp_buf[4 + 2 * EXT_DEF_WWN_NAME_SIZE],
3816 		    sizeof (EXT_RNID_DATA));
3817 	} else {
3818 		if (tq == NULL) {
3819 			/* no matching device */
3820 			EL(ha, "failed, device not found\n");
3821 			kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3822 			cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
3823 			cmd->DetailStatus = EXT_DSTATUS_TARGET;
3824 			cmd->ResponseLen = 0;
3825 			return;
3826 		}
3827 
3828 		/* Send command */
3829 		rval = ql_send_rnid_els(ha, tq->loop_id,
3830 		    (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE, tmp_buf);
3831 		if (rval != QL_SUCCESS) {
3832 			EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n",
3833 			    rval, tq->loop_id);
3834 			while (LOOP_NOT_READY(ha)) {
3835 				ql_delay(ha, 100000);
3836 				if (loop_ready_wait-- == 0) {
3837 					EL(ha, "failed, loop not ready\n");
3838 					cmd->Status = EXT_STATUS_ERR;
3839 					cmd->ResponseLen = 0;
3840 				}
3841 			}
3842 			rval = ql_send_rnid_els(ha, tq->loop_id,
3843 			    (uint8_t)tmp_rnid.DataFormat, SEND_RNID_RSP_SIZE,
3844 			    tmp_buf);
3845 			if (rval != QL_SUCCESS) {
3846 				/* error */
3847 				EL(ha, "failed, send_rnid_mbx=%xh, id=%xh\n",
3848 				    rval, tq->loop_id);
3849 				kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3850 				cmd->Status = EXT_STATUS_ERR;
3851 				cmd->ResponseLen = 0;
3852 				return;
3853 			}
3854 		}
3855 	}
3856 
3857 	/* Copy the response */
3858 	copy_len = (cmd->ResponseLen > SEND_RNID_RSP_SIZE) ?
3859 	    SEND_RNID_RSP_SIZE : cmd->ResponseLen;
3860 
3861 	if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)cmd->ResponseAdr,
3862 	    copy_len, mode) != copy_len) {
3863 		cmd->Status = EXT_STATUS_COPY_ERR;
3864 		EL(ha, "failed, ddi_copyout\n");
3865 	} else {
3866 		cmd->ResponseLen = copy_len;
3867 		if (copy_len < SEND_RNID_RSP_SIZE) {
3868 			cmd->Status = EXT_STATUS_DATA_OVERRUN;
3869 			EL(ha, "failed, EXT_STATUS_DATA_OVERRUN\n");
3870 
3871 		} else if (cmd->ResponseLen > SEND_RNID_RSP_SIZE) {
3872 			cmd->Status = EXT_STATUS_DATA_UNDERRUN;
3873 			EL(ha, "failed, EXT_STATUS_DATA_UNDERRUN\n");
3874 		} else {
3875 			cmd->Status = EXT_STATUS_OK;
3876 			QL_PRINT_9(ha, "done\n",
3877 			    ha->instance);
3878 		}
3879 	}
3880 
3881 	kmem_free(tmp_buf, SEND_RNID_RSP_SIZE);
3882 }
3883 
3884 /*
3885  * ql_set_host_data
3886  *	Process IOCTL subcommand to set host/adapter related data.
3887  *
3888  * Input:
3889  *	ha:	adapter state pointer.
3890  *	cmd:	User space CT arguments pointer.
3891  *	mode:	flags.
3892  *
3893  * Returns:
3894  *	None, request status indicated in cmd->Status.
3895  *
3896  * Context:
3897  *	Kernel context.
3898  */
3899 static void
ql_set_host_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3900 ql_set_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3901 {
3902 	QL_PRINT_9(ha, "started, SubCode=%d\n",
3903 	    cmd->SubCode);
3904 
3905 	/*
3906 	 * case off on command subcode
3907 	 */
3908 	switch (cmd->SubCode) {
3909 	case EXT_SC_SET_RNID:
3910 		ql_set_rnid_parameters(ha, cmd, mode);
3911 		break;
3912 	case EXT_SC_RST_STATISTICS:
3913 		(void) ql_reset_statistics(ha, cmd);
3914 		break;
3915 	case EXT_SC_SET_BEACON_STATE:
3916 		ql_set_led_state(ha, cmd, mode);
3917 		break;
3918 	case EXT_SC_SET_PARMS:
3919 	case EXT_SC_SET_BUS_MODE:
3920 	case EXT_SC_SET_DR_DUMP_BUF:
3921 	case EXT_SC_SET_RISC_CODE:
3922 	case EXT_SC_SET_FLASH_RAM:
3923 	case EXT_SC_SET_LUN_BITMASK:
3924 	case EXT_SC_SET_RETRY_CNT:
3925 	case EXT_SC_SET_RTIN:
3926 	case EXT_SC_SET_FC_LUN_BITMASK:
3927 	case EXT_SC_ADD_TARGET_DEVICE:
3928 	case EXT_SC_SWAP_TARGET_DEVICE:
3929 	case EXT_SC_SET_SEL_TIMEOUT:
3930 	default:
3931 		/* function not supported. */
3932 		EL(ha, "failed, function not supported=%d\n", cmd->SubCode);
3933 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
3934 		break;
3935 	}
3936 
3937 	if (cmd->Status != EXT_STATUS_OK) {
3938 		EL(ha, "failed, Status=%d\n", cmd->Status);
3939 	} else {
3940 		/*EMPTY*/
3941 		QL_PRINT_9(ha, "done\n");
3942 	}
3943 }
3944 
3945 /*
3946  * ql_get_host_data
3947  *	Performs EXT_CC_GET_DATA subcommands.
3948  *
3949  * Input:
3950  *	ha:	adapter state pointer.
3951  *	cmd:	Local EXT_IOCTL cmd struct pointer.
3952  *	mode:	flags.
3953  *
3954  * Returns:
3955  *	None, request status indicated in cmd->Status.
3956  *
3957  * Context:
3958  *	Kernel context.
3959  */
3960 static void
ql_get_host_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)3961 ql_get_host_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
3962 {
3963 	int	out_size = 0;
3964 
3965 	QL_PRINT_9(ha, "started, SubCode=%d\n",
3966 	    cmd->SubCode);
3967 
3968 	/* case off on command subcode */
3969 	switch (cmd->SubCode) {
3970 	case EXT_SC_GET_STATISTICS:
3971 		out_size = sizeof (EXT_HBA_PORT_STAT);
3972 		break;
3973 	case EXT_SC_GET_FC_STATISTICS:
3974 		out_size = sizeof (EXT_HBA_PORT_STAT);
3975 		break;
3976 	case EXT_SC_GET_PORT_SUMMARY:
3977 		out_size = sizeof (EXT_DEVICEDATA);
3978 		break;
3979 	case EXT_SC_GET_RNID:
3980 		out_size = sizeof (EXT_RNID_DATA);
3981 		break;
3982 	case EXT_SC_GET_TARGET_ID:
3983 		out_size = sizeof (EXT_DEST_ADDR);
3984 		break;
3985 	case EXT_SC_GET_BEACON_STATE:
3986 		out_size = sizeof (EXT_BEACON_CONTROL);
3987 		break;
3988 	case EXT_SC_GET_FC4_STATISTICS:
3989 		out_size = sizeof (EXT_HBA_FC4STATISTICS);
3990 		break;
3991 	case EXT_SC_GET_DCBX_PARAM:
3992 		out_size = EXT_DEF_DCBX_PARAM_BUF_SIZE;
3993 		break;
3994 	case EXT_SC_GET_RESOURCE_CNTS:
3995 		out_size = sizeof (EXT_RESOURCE_CNTS);
3996 		break;
3997 	case EXT_SC_GET_FCF_LIST:
3998 		out_size = sizeof (EXT_FCF_LIST);
3999 		break;
4000 	case EXT_SC_GET_PRIV_STATS:
4001 		out_size = cmd->ResponseLen;
4002 		break;
4003 	case EXT_SC_GET_SCSI_ADDR:
4004 	case EXT_SC_GET_ERR_DETECTIONS:
4005 	case EXT_SC_GET_BUS_MODE:
4006 	case EXT_SC_GET_DR_DUMP_BUF:
4007 	case EXT_SC_GET_RISC_CODE:
4008 	case EXT_SC_GET_FLASH_RAM:
4009 	case EXT_SC_GET_LINK_STATUS:
4010 	case EXT_SC_GET_LOOP_ID:
4011 	case EXT_SC_GET_LUN_BITMASK:
4012 	case EXT_SC_GET_PORT_DATABASE:
4013 	case EXT_SC_GET_PORT_DATABASE_MEM:
4014 	case EXT_SC_GET_POSITION_MAP:
4015 	case EXT_SC_GET_RETRY_CNT:
4016 	case EXT_SC_GET_RTIN:
4017 	case EXT_SC_GET_FC_LUN_BITMASK:
4018 	case EXT_SC_GET_SEL_TIMEOUT:
4019 	default:
4020 		/* function not supported. */
4021 		EL(ha, "failed, function not supported=%d\n", cmd->SubCode);
4022 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
4023 		cmd->ResponseLen = 0;
4024 		return;
4025 	}
4026 
4027 	if (cmd->ResponseLen < out_size) {
4028 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
4029 		cmd->DetailStatus = out_size;
4030 		EL(ha, "failed, ResponseLen=%xh, size=%xh\n",
4031 		    cmd->ResponseLen, out_size);
4032 		cmd->ResponseLen = 0;
4033 		return;
4034 	}
4035 
4036 	switch (cmd->SubCode) {
4037 	case EXT_SC_GET_RNID:
4038 		ql_get_rnid_parameters(ha, cmd, mode);
4039 		break;
4040 	case EXT_SC_GET_STATISTICS:
4041 		ql_get_statistics(ha, cmd, mode);
4042 		break;
4043 	case EXT_SC_GET_FC_STATISTICS:
4044 		ql_get_statistics_fc(ha, cmd, mode);
4045 		break;
4046 	case EXT_SC_GET_FC4_STATISTICS:
4047 		ql_get_statistics_fc4(ha, cmd, mode);
4048 		break;
4049 	case EXT_SC_GET_PORT_SUMMARY:
4050 		ql_get_port_summary(ha, cmd, mode);
4051 		break;
4052 	case EXT_SC_GET_TARGET_ID:
4053 		ql_get_target_id(ha, cmd, mode);
4054 		break;
4055 	case EXT_SC_GET_BEACON_STATE:
4056 		ql_get_led_state(ha, cmd, mode);
4057 		break;
4058 	case EXT_SC_GET_DCBX_PARAM:
4059 		ql_get_dcbx_parameters(ha, cmd, mode);
4060 		break;
4061 	case EXT_SC_GET_FCF_LIST:
4062 		ql_get_fcf_list(ha, cmd, mode);
4063 		break;
4064 	case EXT_SC_GET_RESOURCE_CNTS:
4065 		ql_get_resource_counts(ha, cmd, mode);
4066 		break;
4067 	case EXT_SC_GET_PRIV_STATS:
4068 		ql_get_priv_stats(ha, cmd, mode);
4069 		break;
4070 	}
4071 
4072 	if (cmd->Status != EXT_STATUS_OK) {
4073 		EL(ha, "failed, Status=%d\n", cmd->Status);
4074 	} else {
4075 		/*EMPTY*/
4076 		QL_PRINT_9(ha, "done\n");
4077 	}
4078 }
4079 
4080 /* ******************************************************************** */
4081 /*			Helper Functions				*/
4082 /* ******************************************************************** */
4083 
4084 /*
4085  * ql_lun_count
4086  *	Get numbers of LUNS on target.
4087  *
4088  * Input:
4089  *	ha:	adapter state pointer.
4090  *	q:	device queue pointer.
4091  *
4092  * Returns:
4093  *	Number of LUNs.
4094  *
4095  * Context:
4096  *	Kernel context.
4097  */
4098 static int
ql_lun_count(ql_adapter_state_t * ha,ql_tgt_t * tq)4099 ql_lun_count(ql_adapter_state_t *ha, ql_tgt_t *tq)
4100 {
4101 	int	cnt;
4102 
4103 	QL_PRINT_9(ha, "started\n");
4104 
4105 	/* Bypass LUNs that failed. */
4106 	cnt = ql_report_lun(ha, tq);
4107 	if (cnt == 0) {
4108 		cnt = ql_inq_scan(ha, tq, ha->maximum_luns_per_target);
4109 	}
4110 
4111 	QL_PRINT_9(ha, "done\n");
4112 
4113 	return (cnt);
4114 }
4115 
4116 /*
4117  * ql_report_lun
4118  *	Get numbers of LUNS using report LUN command.
4119  *
4120  * Input:
4121  *	ha:	adapter state pointer.
4122  *	q:	target queue pointer.
4123  *
4124  * Returns:
4125  *	Number of LUNs.
4126  *
4127  * Context:
4128  *	Kernel context.
4129  */
4130 static int
ql_report_lun(ql_adapter_state_t * ha,ql_tgt_t * tq)4131 ql_report_lun(ql_adapter_state_t *ha, ql_tgt_t *tq)
4132 {
4133 	int			rval;
4134 	uint8_t			retries;
4135 	ql_mbx_iocb_t		*pkt;
4136 	ql_rpt_lun_lst_t	*rpt;
4137 	dma_mem_t		dma_mem;
4138 	uint32_t		pkt_size, cnt;
4139 	uint16_t		comp_status;
4140 	uint8_t			scsi_status_h, scsi_status_l, *reqs;
4141 
4142 	QL_PRINT_9(ha, "started\n");
4143 
4144 	if (DRIVER_SUSPENDED(ha)) {
4145 		EL(ha, "failed, LOOP_NOT_READY\n");
4146 		return (0);
4147 	}
4148 
4149 	pkt_size = sizeof (ql_mbx_iocb_t) + sizeof (ql_rpt_lun_lst_t);
4150 	pkt = kmem_zalloc(pkt_size, KM_SLEEP);
4151 	if (pkt == NULL) {
4152 		EL(ha, "failed, kmem_zalloc\n");
4153 		return (0);
4154 	}
4155 	rpt = (ql_rpt_lun_lst_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t));
4156 
4157 	/* Get DMA memory for the IOCB */
4158 	if (ql_get_dma_mem(ha, &dma_mem, sizeof (ql_rpt_lun_lst_t),
4159 	    LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) {
4160 		cmn_err(CE_WARN, "%s(%d) DMA memory "
4161 		    "alloc failed", QL_NAME, ha->instance);
4162 		kmem_free(pkt, pkt_size);
4163 		return (0);
4164 	}
4165 
4166 	for (retries = 0; retries < 4; retries++) {
4167 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4168 			pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
4169 			pkt->cmd24.entry_count = 1;
4170 
4171 			/* Set N_port handle */
4172 			pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
4173 
4174 			/* Set target ID */
4175 			pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
4176 			pkt->cmd24.target_id[1] = tq->d_id.b.area;
4177 			pkt->cmd24.target_id[2] = tq->d_id.b.domain;
4178 
4179 			/* Set Virtual Port ID */
4180 			pkt->cmd24.vp_index = ha->vp_index;
4181 
4182 			/* Set ISP command timeout. */
4183 			pkt->cmd24.timeout = LE_16(15);
4184 
4185 			/* Load SCSI CDB */
4186 			pkt->cmd24.scsi_cdb[0] = SCMD_REPORT_LUNS;
4187 			pkt->cmd24.scsi_cdb[6] =
4188 			    MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4189 			pkt->cmd24.scsi_cdb[7] =
4190 			    LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4191 			pkt->cmd24.scsi_cdb[8] =
4192 			    MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4193 			pkt->cmd24.scsi_cdb[9] =
4194 			    LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4195 			for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) {
4196 				ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
4197 				    + cnt, 4);
4198 			}
4199 
4200 			/* Set tag queue control flags */
4201 			pkt->cmd24.task = TA_STAG;
4202 
4203 			/* Set transfer direction. */
4204 			pkt->cmd24.control_flags = CF_RD;
4205 
4206 			/* Set data segment count. */
4207 			pkt->cmd24.dseg_count = LE_16(1);
4208 
4209 			/* Load total byte count. */
4210 			/* Load data descriptor. */
4211 			pkt->cmd24.dseg.address[0] = (uint32_t)
4212 			    LE_32(LSD(dma_mem.cookie.dmac_laddress));
4213 			pkt->cmd24.dseg.address[1] = (uint32_t)
4214 			    LE_32(MSD(dma_mem.cookie.dmac_laddress));
4215 			pkt->cmd24.total_byte_count =
4216 			    LE_32(sizeof (ql_rpt_lun_lst_t));
4217 			pkt->cmd24.dseg.length =
4218 			    LE_32(sizeof (ql_rpt_lun_lst_t));
4219 		} else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
4220 			pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
4221 			pkt->cmd3.entry_count = 1;
4222 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4223 				pkt->cmd3.target_l = LSB(tq->loop_id);
4224 				pkt->cmd3.target_h = MSB(tq->loop_id);
4225 			} else {
4226 				pkt->cmd3.target_h = LSB(tq->loop_id);
4227 			}
4228 			pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG;
4229 			pkt->cmd3.timeout = LE_16(15);
4230 			pkt->cmd3.dseg_count = LE_16(1);
4231 			pkt->cmd3.scsi_cdb[0] = SCMD_REPORT_LUNS;
4232 			pkt->cmd3.scsi_cdb[6] =
4233 			    MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4234 			pkt->cmd3.scsi_cdb[7] =
4235 			    LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4236 			pkt->cmd3.scsi_cdb[8] =
4237 			    MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4238 			pkt->cmd3.scsi_cdb[9] =
4239 			    LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4240 			pkt->cmd3.byte_count =
4241 			    LE_32(sizeof (ql_rpt_lun_lst_t));
4242 			pkt->cmd3.dseg[0].address[0] = (uint32_t)
4243 			    LE_32(LSD(dma_mem.cookie.dmac_laddress));
4244 			pkt->cmd3.dseg[0].address[1] = (uint32_t)
4245 			    LE_32(MSD(dma_mem.cookie.dmac_laddress));
4246 			pkt->cmd3.dseg[0].length =
4247 			    LE_32(sizeof (ql_rpt_lun_lst_t));
4248 		} else {
4249 			pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
4250 			pkt->cmd.entry_count = 1;
4251 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4252 				pkt->cmd.target_l = LSB(tq->loop_id);
4253 				pkt->cmd.target_h = MSB(tq->loop_id);
4254 			} else {
4255 				pkt->cmd.target_h = LSB(tq->loop_id);
4256 			}
4257 			pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG;
4258 			pkt->cmd.timeout = LE_16(15);
4259 			pkt->cmd.dseg_count = LE_16(1);
4260 			pkt->cmd.scsi_cdb[0] = SCMD_REPORT_LUNS;
4261 			pkt->cmd.scsi_cdb[6] =
4262 			    MSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4263 			pkt->cmd.scsi_cdb[7] =
4264 			    LSB(MSW(sizeof (ql_rpt_lun_lst_t)));
4265 			pkt->cmd.scsi_cdb[8] =
4266 			    MSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4267 			pkt->cmd.scsi_cdb[9] =
4268 			    LSB(LSW(sizeof (ql_rpt_lun_lst_t)));
4269 			pkt->cmd.byte_count =
4270 			    LE_32(sizeof (ql_rpt_lun_lst_t));
4271 			pkt->cmd.dseg[0].address = (uint32_t)
4272 			    LE_32(LSD(dma_mem.cookie.dmac_laddress));
4273 			pkt->cmd.dseg[0].length =
4274 			    LE_32(sizeof (ql_rpt_lun_lst_t));
4275 		}
4276 
4277 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
4278 		    sizeof (ql_mbx_iocb_t));
4279 
4280 		/* Sync in coming DMA buffer. */
4281 		(void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size,
4282 		    DDI_DMA_SYNC_FORKERNEL);
4283 		/* Copy in coming DMA data. */
4284 		ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)rpt,
4285 		    (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR);
4286 
4287 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4288 			pkt->sts24.entry_status = (uint8_t)
4289 			    (pkt->sts24.entry_status & 0x3c);
4290 			comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
4291 			scsi_status_h = pkt->sts24.scsi_status_h;
4292 			scsi_status_l = pkt->sts24.scsi_status_l;
4293 			cnt = scsi_status_h & FCP_RSP_LEN_VALID ?
4294 			    LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
4295 			reqs = &pkt->sts24.rsp_sense_data[cnt];
4296 		} else {
4297 			pkt->sts.entry_status = (uint8_t)
4298 			    (pkt->sts.entry_status & 0x7e);
4299 			comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
4300 			scsi_status_h = pkt->sts.scsi_status_h;
4301 			scsi_status_l = pkt->sts.scsi_status_l;
4302 			reqs = &pkt->sts.req_sense_data[0];
4303 		}
4304 		if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) {
4305 			EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
4306 			    pkt->sts.entry_status, tq->d_id.b24);
4307 			rval = QL_FUNCTION_PARAMETER_ERROR;
4308 		}
4309 
4310 		if (rval != QL_SUCCESS || comp_status != CS_COMPLETE ||
4311 		    scsi_status_l & STATUS_CHECK) {
4312 			/* Device underrun, treat as OK. */
4313 			if (rval == QL_SUCCESS &&
4314 			    comp_status == CS_DATA_UNDERRUN &&
4315 			    scsi_status_h & FCP_RESID_UNDER) {
4316 				break;
4317 			}
4318 
4319 			EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, "
4320 			    "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24,
4321 			    comp_status, scsi_status_h, scsi_status_l);
4322 
4323 			if (rval == QL_SUCCESS) {
4324 				if ((comp_status == CS_TIMEOUT) ||
4325 				    (comp_status == CS_PORT_UNAVAILABLE) ||
4326 				    (comp_status == CS_PORT_LOGGED_OUT)) {
4327 					rval = QL_FUNCTION_TIMEOUT;
4328 					break;
4329 				}
4330 				rval = QL_FUNCTION_FAILED;
4331 			} else if (rval == QL_ABORTED) {
4332 				break;
4333 			}
4334 
4335 			if (scsi_status_l & STATUS_CHECK) {
4336 				EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh"
4337 				    "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
4338 				    "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0],
4339 				    reqs[1], reqs[2], reqs[3], reqs[4],
4340 				    reqs[5], reqs[6], reqs[7], reqs[8],
4341 				    reqs[9], reqs[10], reqs[11], reqs[12],
4342 				    reqs[13], reqs[14], reqs[15], reqs[16],
4343 				    reqs[17]);
4344 			}
4345 		} else {
4346 			break;
4347 		}
4348 		bzero((caddr_t)pkt, pkt_size);
4349 	}
4350 
4351 	if (rval != QL_SUCCESS) {
4352 		EL(ha, "failed=%xh\n", rval);
4353 		rval = 0;
4354 	} else {
4355 		QL_PRINT_9(ha, "LUN list\n");
4356 		QL_DUMP_9(rpt, 8, rpt->hdr.len + 8);
4357 		rval = (int)(BE_32(rpt->hdr.len) / 8);
4358 	}
4359 
4360 	kmem_free(pkt, pkt_size);
4361 	ql_free_dma_resource(ha, &dma_mem);
4362 
4363 	QL_PRINT_9(ha, "done\n");
4364 
4365 	return (rval);
4366 }
4367 
4368 /*
4369  * ql_inq_scan
4370  *	Get numbers of LUNS using inquiry command.
4371  *
4372  * Input:
4373  *	ha:		adapter state pointer.
4374  *	tq:		target queue pointer.
4375  *	count:		scan for the number of existing LUNs.
4376  *
4377  * Returns:
4378  *	Number of LUNs.
4379  *
4380  * Context:
4381  *	Kernel context.
4382  */
4383 static int
ql_inq_scan(ql_adapter_state_t * ha,ql_tgt_t * tq,int count)4384 ql_inq_scan(ql_adapter_state_t *ha, ql_tgt_t *tq, int count)
4385 {
4386 	int		lun, cnt, rval;
4387 	ql_mbx_iocb_t	*pkt;
4388 	uint8_t		*inq;
4389 	uint32_t	pkt_size;
4390 
4391 	QL_PRINT_9(ha, "started\n");
4392 
4393 	pkt_size = sizeof (ql_mbx_iocb_t) + INQ_DATA_SIZE;
4394 	pkt = kmem_zalloc(pkt_size, KM_SLEEP);
4395 	if (pkt == NULL) {
4396 		EL(ha, "failed, kmem_zalloc\n");
4397 		return (0);
4398 	}
4399 	inq = (uint8_t *)((caddr_t)pkt + sizeof (ql_mbx_iocb_t));
4400 
4401 	cnt = 0;
4402 	for (lun = 0; lun < MAX_LUNS; lun++) {
4403 
4404 		if (DRIVER_SUSPENDED(ha)) {
4405 			rval = QL_LOOP_DOWN;
4406 			cnt = 0;
4407 			break;
4408 		}
4409 
4410 		rval = ql_inq(ha, tq, lun, pkt, INQ_DATA_SIZE);
4411 		if (rval == QL_SUCCESS) {
4412 			switch (*inq) {
4413 			case DTYPE_DIRECT:
4414 			case DTYPE_PROCESSOR:	/* Appliance. */
4415 			case DTYPE_WORM:
4416 			case DTYPE_RODIRECT:
4417 			case DTYPE_SCANNER:
4418 			case DTYPE_OPTICAL:
4419 			case DTYPE_CHANGER:
4420 			case DTYPE_ESI:
4421 				cnt++;
4422 				break;
4423 			case DTYPE_SEQUENTIAL:
4424 				cnt++;
4425 				tq->flags |= TQF_TAPE_DEVICE;
4426 				break;
4427 			default:
4428 				QL_PRINT_9(ha, "failed, "
4429 				    "unsupported device id=%xh, lun=%d, "
4430 				    "type=%xh\n", tq->loop_id,
4431 				    lun, *inq);
4432 				break;
4433 			}
4434 
4435 			if (*inq == DTYPE_ESI || cnt >= count) {
4436 				break;
4437 			}
4438 		} else if (rval == QL_ABORTED || rval == QL_FUNCTION_TIMEOUT) {
4439 			cnt = 0;
4440 			break;
4441 		}
4442 	}
4443 
4444 	kmem_free(pkt, pkt_size);
4445 
4446 	QL_PRINT_9(ha, "done\n");
4447 
4448 	return (cnt);
4449 }
4450 
4451 /*
4452  * ql_inq
4453  *	Issue inquiry command.
4454  *
4455  * Input:
4456  *	ha:		adapter state pointer.
4457  *	tq:		target queue pointer.
4458  *	lun:		LUN number.
4459  *	pkt:		command and buffer pointer.
4460  *	inq_len:	amount of inquiry data.
4461  *
4462  * Returns:
4463  *	ql local function return status code.
4464  *
4465  * Context:
4466  *	Kernel context.
4467  */
4468 static int
ql_inq(ql_adapter_state_t * ha,ql_tgt_t * tq,int lun,ql_mbx_iocb_t * pkt,uint32_t inq_len)4469 ql_inq(ql_adapter_state_t *ha, ql_tgt_t *tq, int lun, ql_mbx_iocb_t *pkt,
4470     uint32_t inq_len)
4471 {
4472 	dma_mem_t	dma_mem;
4473 	int		rval, retries;
4474 	uint32_t	pkt_size, cnt;
4475 	uint16_t	comp_status;
4476 	uint8_t		scsi_status_h, scsi_status_l, *reqs;
4477 	caddr_t		inq_data;
4478 	uint64_t	lun_addr;
4479 	fcp_ent_addr_t	*fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
4480 
4481 	QL_PRINT_9(ha, "started\n");
4482 
4483 	if (DRIVER_SUSPENDED(ha)) {
4484 		EL(ha, "failed, loop down\n");
4485 		return (QL_FUNCTION_TIMEOUT);
4486 	}
4487 
4488 	pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t) + inq_len);
4489 	bzero((caddr_t)pkt, pkt_size);
4490 
4491 	inq_data = (caddr_t)pkt + sizeof (ql_mbx_iocb_t);
4492 
4493 	/* Get DMA memory for the IOCB */
4494 	if (ql_get_dma_mem(ha, &dma_mem, inq_len,
4495 	    LITTLE_ENDIAN_DMA, QL_DMA_RING_ALIGN) != QL_SUCCESS) {
4496 		cmn_err(CE_WARN, "%s(%d) DMA memory "
4497 		    "alloc failed", QL_NAME, ha->instance);
4498 		return (0);
4499 	}
4500 
4501 	for (retries = 0; retries < 4; retries++) {
4502 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4503 			pkt->cmd24.entry_type = IOCB_CMD_TYPE_7;
4504 			pkt->cmd24.entry_count = 1;
4505 
4506 			/* Set LUN number */
4507 			lun_addr = ql_get_lun_addr(tq, lun);
4508 			fcp_ent_addr = (fcp_ent_addr_t *)&lun_addr;
4509 			pkt->cmd24.fcp_lun[2] =
4510 			    lobyte(fcp_ent_addr->ent_addr_0);
4511 			pkt->cmd24.fcp_lun[3] =
4512 			    hibyte(fcp_ent_addr->ent_addr_0);
4513 			pkt->cmd24.fcp_lun[0] =
4514 			    lobyte(fcp_ent_addr->ent_addr_1);
4515 			pkt->cmd24.fcp_lun[1] =
4516 			    hibyte(fcp_ent_addr->ent_addr_1);
4517 			pkt->cmd24.fcp_lun[6] =
4518 			    lobyte(fcp_ent_addr->ent_addr_2);
4519 			pkt->cmd24.fcp_lun[7] =
4520 			    hibyte(fcp_ent_addr->ent_addr_2);
4521 			pkt->cmd24.fcp_lun[4] =
4522 			    lobyte(fcp_ent_addr->ent_addr_3);
4523 			pkt->cmd24.fcp_lun[5] =
4524 			    hibyte(fcp_ent_addr->ent_addr_3);
4525 
4526 			/* Set N_port handle */
4527 			pkt->cmd24.n_port_hdl = (uint16_t)LE_16(tq->loop_id);
4528 
4529 			/* Set target ID */
4530 			pkt->cmd24.target_id[0] = tq->d_id.b.al_pa;
4531 			pkt->cmd24.target_id[1] = tq->d_id.b.area;
4532 			pkt->cmd24.target_id[2] = tq->d_id.b.domain;
4533 
4534 			/* Set Virtual Port ID */
4535 			pkt->cmd24.vp_index = ha->vp_index;
4536 
4537 			/* Set ISP command timeout. */
4538 			pkt->cmd24.timeout = LE_16(15);
4539 
4540 			/* Load SCSI CDB */
4541 			pkt->cmd24.scsi_cdb[0] = SCMD_INQUIRY;
4542 			pkt->cmd24.scsi_cdb[4] = LSB(LSW(inq_len));
4543 			for (cnt = 0; cnt < MAX_CMDSZ; cnt += 4) {
4544 				ql_chg_endian((uint8_t *)&pkt->cmd24.scsi_cdb
4545 				    + cnt, 4);
4546 			}
4547 
4548 			/* Set tag queue control flags */
4549 			pkt->cmd24.task = TA_STAG;
4550 
4551 			/* Set transfer direction. */
4552 			pkt->cmd24.control_flags = CF_RD;
4553 
4554 			/* Set data segment count. */
4555 			pkt->cmd24.dseg_count = LE_16(1);
4556 
4557 			/* Load total byte count. */
4558 			pkt->cmd24.total_byte_count = LE_32(inq_len);
4559 
4560 			/* Load data descriptor. */
4561 			pkt->cmd24.dseg.address[0] = (uint32_t)
4562 			    LE_32(LSD(dma_mem.cookie.dmac_laddress));
4563 			pkt->cmd24.dseg.address[1] = (uint32_t)
4564 			    LE_32(MSD(dma_mem.cookie.dmac_laddress));
4565 			pkt->cmd24.dseg.length = LE_32(inq_len);
4566 		} else if (CFG_IST(ha, CFG_ENABLE_64BIT_ADDRESSING)) {
4567 			pkt->cmd3.entry_type = IOCB_CMD_TYPE_3;
4568 			cnt = CMD_TYPE_3_DATA_SEGMENTS;
4569 
4570 			pkt->cmd3.entry_count = 1;
4571 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4572 				pkt->cmd3.target_l = LSB(tq->loop_id);
4573 				pkt->cmd3.target_h = MSB(tq->loop_id);
4574 			} else {
4575 				pkt->cmd3.target_h = LSB(tq->loop_id);
4576 			}
4577 			pkt->cmd3.lun_l = LSB(lun);
4578 			pkt->cmd3.lun_h = MSB(lun);
4579 			pkt->cmd3.control_flags_l = CF_DATA_IN | CF_STAG;
4580 			pkt->cmd3.timeout = LE_16(15);
4581 			pkt->cmd3.scsi_cdb[0] = SCMD_INQUIRY;
4582 			pkt->cmd3.scsi_cdb[4] = LSB(LSW(inq_len));
4583 			pkt->cmd3.dseg_count = LE_16(1);
4584 			pkt->cmd3.byte_count = LE_32(inq_len);
4585 			pkt->cmd3.dseg[0].address[0] = (uint32_t)
4586 			    LE_32(LSD(dma_mem.cookie.dmac_laddress));
4587 			pkt->cmd3.dseg[0].address[1] = (uint32_t)
4588 			    LE_32(MSD(dma_mem.cookie.dmac_laddress));
4589 			pkt->cmd3.dseg[0].length = LE_32(inq_len);
4590 		} else {
4591 			pkt->cmd.entry_type = IOCB_CMD_TYPE_2;
4592 			cnt = CMD_TYPE_2_DATA_SEGMENTS;
4593 
4594 			pkt->cmd.entry_count = 1;
4595 			if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
4596 				pkt->cmd.target_l = LSB(tq->loop_id);
4597 				pkt->cmd.target_h = MSB(tq->loop_id);
4598 			} else {
4599 				pkt->cmd.target_h = LSB(tq->loop_id);
4600 			}
4601 			pkt->cmd.lun_l = LSB(lun);
4602 			pkt->cmd.lun_h = MSB(lun);
4603 			pkt->cmd.control_flags_l = CF_DATA_IN | CF_STAG;
4604 			pkt->cmd.timeout = LE_16(15);
4605 			pkt->cmd.scsi_cdb[0] = SCMD_INQUIRY;
4606 			pkt->cmd.scsi_cdb[4] = LSB(LSW(inq_len));
4607 			pkt->cmd.dseg_count = LE_16(1);
4608 			pkt->cmd.byte_count = LE_32(inq_len);
4609 			pkt->cmd.dseg[0].address = (uint32_t)
4610 			    LE_32(LSD(dma_mem.cookie.dmac_laddress));
4611 			pkt->cmd.dseg[0].length = LE_32(inq_len);
4612 		}
4613 
4614 /*		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, pkt_size); */
4615 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
4616 		    sizeof (ql_mbx_iocb_t));
4617 
4618 		/* Sync in coming IOCB DMA buffer. */
4619 		(void) ddi_dma_sync(dma_mem.dma_handle, 0, dma_mem.size,
4620 		    DDI_DMA_SYNC_FORKERNEL);
4621 		/* Copy in coming DMA data. */
4622 		ddi_rep_get8(dma_mem.acc_handle, (uint8_t *)inq_data,
4623 		    (uint8_t *)dma_mem.bp, dma_mem.size, DDI_DEV_AUTOINCR);
4624 
4625 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
4626 			pkt->sts24.entry_status = (uint8_t)
4627 			    (pkt->sts24.entry_status & 0x3c);
4628 			comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
4629 			scsi_status_h = pkt->sts24.scsi_status_h;
4630 			scsi_status_l = pkt->sts24.scsi_status_l;
4631 			cnt = scsi_status_h & FCP_RSP_LEN_VALID ?
4632 			    LE_32(pkt->sts24.fcp_rsp_data_length) : 0;
4633 			reqs = &pkt->sts24.rsp_sense_data[cnt];
4634 		} else {
4635 			pkt->sts.entry_status = (uint8_t)
4636 			    (pkt->sts.entry_status & 0x7e);
4637 			comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
4638 			scsi_status_h = pkt->sts.scsi_status_h;
4639 			scsi_status_l = pkt->sts.scsi_status_l;
4640 			reqs = &pkt->sts.req_sense_data[0];
4641 		}
4642 		if (rval == QL_SUCCESS && pkt->sts.entry_status != 0) {
4643 			EL(ha, "failed, entry_status=%xh, d_id=%xh\n",
4644 			    pkt->sts.entry_status, tq->d_id.b24);
4645 			rval = QL_FUNCTION_PARAMETER_ERROR;
4646 		}
4647 
4648 		if (rval != QL_SUCCESS || comp_status != CS_COMPLETE ||
4649 		    scsi_status_l & STATUS_CHECK) {
4650 			EL(ha, "failed, issue_iocb=%xh, d_id=%xh, cs=%xh, "
4651 			    "ss_h=%xh, ss_l=%xh\n", rval, tq->d_id.b24,
4652 			    comp_status, scsi_status_h, scsi_status_l);
4653 
4654 			if (rval == QL_SUCCESS) {
4655 				if ((comp_status == CS_TIMEOUT) ||
4656 				    (comp_status == CS_PORT_UNAVAILABLE) ||
4657 				    (comp_status == CS_PORT_LOGGED_OUT)) {
4658 					rval = QL_FUNCTION_TIMEOUT;
4659 					break;
4660 				}
4661 				rval = QL_FUNCTION_FAILED;
4662 			}
4663 
4664 			if (scsi_status_l & STATUS_CHECK) {
4665 				EL(ha, "STATUS_CHECK Sense Data\n%2xh%3xh"
4666 				    "%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh%3xh"
4667 				    "%3xh%3xh%3xh%3xh%3xh%3xh%3xh\n", reqs[0],
4668 				    reqs[1], reqs[2], reqs[3], reqs[4],
4669 				    reqs[5], reqs[6], reqs[7], reqs[8],
4670 				    reqs[9], reqs[10], reqs[11], reqs[12],
4671 				    reqs[13], reqs[14], reqs[15], reqs[16],
4672 				    reqs[17]);
4673 			}
4674 		} else {
4675 			break;
4676 		}
4677 	}
4678 	ql_free_dma_resource(ha, &dma_mem);
4679 
4680 	QL_PRINT_9(ha, "done\n");
4681 
4682 	return (rval);
4683 }
4684 
4685 /*
4686  * ql_get_buffer_data
4687  *	Copies data from user space to kernal buffer.
4688  *
4689  * Input:
4690  *	src:	User source buffer address.
4691  *	dst:	Kernal destination buffer address.
4692  *	size:	Amount of data.
4693  *	mode:	flags.
4694  *
4695  * Returns:
4696  *	Returns number of bytes transferred.
4697  *
4698  * Context:
4699  *	Kernel context.
4700  */
4701 static uint32_t
ql_get_buffer_data(caddr_t src,caddr_t dst,uint32_t size,int mode)4702 ql_get_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode)
4703 {
4704 	uint32_t	cnt;
4705 
4706 	for (cnt = 0; cnt < size; cnt++) {
4707 		if (ddi_copyin(src++, dst++, 1, mode) != 0) {
4708 			QL_PRINT_2(NULL, "failed, ddi_copyin\n");
4709 			break;
4710 		}
4711 	}
4712 
4713 	return (cnt);
4714 }
4715 
4716 /*
4717  * ql_send_buffer_data
4718  *	Copies data from kernal buffer to user space.
4719  *
4720  * Input:
4721  *	src:	Kernal source buffer address.
4722  *	dst:	User destination buffer address.
4723  *	size:	Amount of data.
4724  *	mode:	flags.
4725  *
4726  * Returns:
4727  *	Returns number of bytes transferred.
4728  *
4729  * Context:
4730  *	Kernel context.
4731  */
4732 static uint32_t
ql_send_buffer_data(caddr_t src,caddr_t dst,uint32_t size,int mode)4733 ql_send_buffer_data(caddr_t src, caddr_t dst, uint32_t size, int mode)
4734 {
4735 	uint32_t	cnt;
4736 
4737 	for (cnt = 0; cnt < size; cnt++) {
4738 		if (ddi_copyout(src++, dst++, 1, mode) != 0) {
4739 			QL_PRINT_2(NULL, "failed, ddi_copyin\n");
4740 			break;
4741 		}
4742 	}
4743 
4744 	return (cnt);
4745 }
4746 
4747 /*
4748  * ql_find_port
4749  *	Locates device queue.
4750  *
4751  * Input:
4752  *	ha:	adapter state pointer.
4753  *	name:	device port name.
4754  *
4755  * Returns:
4756  *	Returns target queue pointer.
4757  *
4758  * Context:
4759  *	Kernel context.
4760  */
4761 static ql_tgt_t *
ql_find_port(ql_adapter_state_t * ha,uint8_t * name,uint16_t type)4762 ql_find_port(ql_adapter_state_t *ha, uint8_t *name, uint16_t type)
4763 {
4764 	ql_link_t	*link;
4765 	ql_tgt_t	*tq;
4766 	uint16_t	index;
4767 
4768 	/* Scan port list for requested target */
4769 	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
4770 		for (link = ha->dev[index].first; link != NULL;
4771 		    link = link->next) {
4772 			tq = link->base_address;
4773 
4774 			switch (type) {
4775 			case QLNT_LOOP_ID:
4776 				if (bcmp(name, &tq->loop_id,
4777 				    sizeof (uint16_t)) == 0) {
4778 					return (tq);
4779 				}
4780 				break;
4781 			case QLNT_PORT:
4782 				if (bcmp(name, tq->port_name, 8) == 0) {
4783 					return (tq);
4784 				}
4785 				break;
4786 			case QLNT_NODE:
4787 				if (bcmp(name, tq->node_name, 8) == 0) {
4788 					return (tq);
4789 				}
4790 				break;
4791 			case QLNT_PID:
4792 				if (bcmp(name, tq->d_id.r.d_id,
4793 				    sizeof (tq->d_id.r.d_id)) == 0) {
4794 					return (tq);
4795 				}
4796 				break;
4797 			default:
4798 				EL(ha, "failed, invalid type=%d\n", type);
4799 				return (NULL);
4800 			}
4801 		}
4802 	}
4803 
4804 	return (NULL);
4805 }
4806 
4807 /*
4808  * ql_24xx_flash_desc
4809  *	Get flash descriptor table.
4810  *
4811  * Input:
4812  *	ha:		adapter state pointer.
4813  *
4814  * Returns:
4815  *	ql local function return status code.
4816  *
4817  * Context:
4818  *	Kernel context.
4819  */
4820 static int
ql_24xx_flash_desc(ql_adapter_state_t * ha)4821 ql_24xx_flash_desc(ql_adapter_state_t *ha)
4822 {
4823 	uint32_t	cnt;
4824 	uint16_t	chksum, *bp, data;
4825 	int		rval;
4826 	flash_desc_t	*fdesc;
4827 	ql_xioctl_t	*xp = ha->xioctl;
4828 
4829 	QL_PRINT_9(ha, "started\n");
4830 
4831 	if (ha->flash_desc_addr == 0) {
4832 		QL_PRINT_9(ha, "desc ptr=0\n");
4833 		return (QL_FUNCTION_FAILED);
4834 	}
4835 
4836 	if ((fdesc = kmem_zalloc(sizeof (flash_desc_t), KM_SLEEP)) == NULL) {
4837 		EL(ha, "kmem_zalloc=null\n");
4838 		return (QL_MEMORY_ALLOC_FAILED);
4839 	}
4840 	rval = ql_dump_fcode(ha, (uint8_t *)fdesc, sizeof (flash_desc_t),
4841 	    ha->flash_desc_addr << 2);
4842 	if (rval != QL_SUCCESS) {
4843 		EL(ha, "read status=%xh\n", rval);
4844 		kmem_free(fdesc, sizeof (flash_desc_t));
4845 		return (rval);
4846 	}
4847 
4848 	chksum = 0;
4849 	bp = (uint16_t *)fdesc;
4850 	for (cnt = 0; cnt < (sizeof (flash_desc_t)) / 2; cnt++) {
4851 		data = *bp++;
4852 		LITTLE_ENDIAN_16(&data);
4853 		chksum += data;
4854 	}
4855 
4856 	LITTLE_ENDIAN_32(&fdesc->flash_valid);
4857 	LITTLE_ENDIAN_16(&fdesc->flash_version);
4858 	LITTLE_ENDIAN_16(&fdesc->flash_len);
4859 	LITTLE_ENDIAN_16(&fdesc->flash_checksum);
4860 	LITTLE_ENDIAN_16(&fdesc->flash_manuf);
4861 	LITTLE_ENDIAN_16(&fdesc->flash_id);
4862 	LITTLE_ENDIAN_32(&fdesc->block_size);
4863 	LITTLE_ENDIAN_32(&fdesc->alt_block_size);
4864 	LITTLE_ENDIAN_32(&fdesc->flash_size);
4865 	LITTLE_ENDIAN_32(&fdesc->write_enable_data);
4866 	LITTLE_ENDIAN_32(&fdesc->read_timeout);
4867 
4868 	/* flash size in desc table is in 1024 bytes */
4869 	fdesc->flash_size = fdesc->flash_size * 0x400;
4870 
4871 	if (chksum != 0 || fdesc->flash_valid != FLASH_DESC_VAILD ||
4872 	    fdesc->flash_version != FLASH_DESC_VERSION) {
4873 		EL(ha, "invalid descriptor table\n");
4874 		kmem_free(fdesc, sizeof (flash_desc_t));
4875 		return (QL_FUNCTION_FAILED);
4876 	}
4877 
4878 	bcopy(fdesc, &xp->fdesc, sizeof (flash_desc_t));
4879 	kmem_free(fdesc, sizeof (flash_desc_t));
4880 
4881 	QL_PRINT_9(ha, "done\n");
4882 
4883 	return (QL_SUCCESS);
4884 }
4885 
4886 /*
4887  * ql_setup_flash
4888  *	Gets the manufacturer and id number of the flash chip, and
4889  *	sets up the size parameter.
4890  *
4891  * Input:
4892  *	ha:	adapter state pointer.
4893  *
4894  * Returns:
4895  *	int:	ql local function return status code.
4896  *
4897  * Context:
4898  *	Kernel context.
4899  */
4900 static int
ql_setup_flash(ql_adapter_state_t * ha)4901 ql_setup_flash(ql_adapter_state_t *ha)
4902 {
4903 	ql_xioctl_t	*xp = ha->xioctl;
4904 	int		rval = QL_SUCCESS;
4905 
4906 	if (xp->fdesc.flash_size != 0) {
4907 		return (rval);
4908 	}
4909 
4910 	if (CFG_IST(ha, CFG_CTRL_22XX) && !ha->subven_id) {
4911 		return (QL_FUNCTION_FAILED);
4912 	}
4913 
4914 	if (CFG_IST(ha, CFG_CTRL_252780818283)) {
4915 		/*
4916 		 * Temporarily set the ha->xioctl->fdesc.flash_size to
4917 		 * 25xx flash size to avoid failing of ql_dump_focde.
4918 		 */
4919 		if (CFG_IST(ha, CFG_CTRL_278083)) {
4920 			ha->xioctl->fdesc.flash_size = 0x1000000;
4921 		} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
4922 			ha->xioctl->fdesc.flash_size = 0x800000;
4923 		} else if (CFG_IST(ha, CFG_CTRL_25XX)) {
4924 			ha->xioctl->fdesc.flash_size = 0x200000;
4925 		} else {
4926 			ha->xioctl->fdesc.flash_size = 0x400000;
4927 		}
4928 
4929 		if (ql_24xx_flash_desc(ha) == QL_SUCCESS) {
4930 			EL(ha, "flash desc table ok, exit\n");
4931 			return (rval);
4932 		}
4933 		if (CFG_IST(ha, CFG_CTRL_82XX)) {
4934 			xp->fdesc.flash_manuf = MXIC_FLASH;
4935 			xp->fdesc.flash_id = MXIC_FLASHID_25LXX;
4936 			xp->fdesc.flash_len = 0x17;
4937 		} else {
4938 			(void) ql_24xx_flash_id(ha);
4939 		}
4940 
4941 	} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
4942 		(void) ql_24xx_flash_id(ha);
4943 	} else {
4944 		ql_flash_enable(ha);
4945 
4946 		ql_write_flash_byte(ha, 0x5555, 0xaa);
4947 		ql_write_flash_byte(ha, 0x2aaa, 0x55);
4948 		ql_write_flash_byte(ha, 0x5555, 0x90);
4949 		xp->fdesc.flash_manuf = (uint8_t)ql_read_flash_byte(ha, 0x0000);
4950 
4951 		if (CFG_IST(ha, CFG_SBUS_CARD)) {
4952 			ql_write_flash_byte(ha, 0xaaaa, 0xaa);
4953 			ql_write_flash_byte(ha, 0x5555, 0x55);
4954 			ql_write_flash_byte(ha, 0xaaaa, 0x90);
4955 			xp->fdesc.flash_id = (uint16_t)
4956 			    ql_read_flash_byte(ha, 0x0002);
4957 		} else {
4958 			ql_write_flash_byte(ha, 0x5555, 0xaa);
4959 			ql_write_flash_byte(ha, 0x2aaa, 0x55);
4960 			ql_write_flash_byte(ha, 0x5555, 0x90);
4961 			xp->fdesc.flash_id = (uint16_t)
4962 			    ql_read_flash_byte(ha, 0x0001);
4963 		}
4964 
4965 		ql_write_flash_byte(ha, 0x5555, 0xaa);
4966 		ql_write_flash_byte(ha, 0x2aaa, 0x55);
4967 		ql_write_flash_byte(ha, 0x5555, 0xf0);
4968 
4969 		ql_flash_disable(ha);
4970 	}
4971 
4972 	/* Default flash descriptor table. */
4973 	xp->fdesc.write_statusreg_cmd = 1;
4974 	xp->fdesc.write_enable_bits = 0;
4975 	xp->fdesc.unprotect_sector_cmd = 0;
4976 	xp->fdesc.protect_sector_cmd = 0;
4977 	xp->fdesc.write_disable_bits = 0xbc;
4978 	xp->fdesc.block_size = 0x10000;
4979 	xp->fdesc.erase_cmd = 0xd8;
4980 
4981 	switch (xp->fdesc.flash_manuf) {
4982 	case AMD_FLASH:
4983 		switch (xp->fdesc.flash_id) {
4984 		case SPAN_FLASHID_16384K:
4985 			if (xp->fdesc.flash_len == 0x18) {
4986 				xp->fdesc.flash_size = 0x1000000;
4987 			} else {
4988 				rval = QL_FUNCTION_FAILED;
4989 			}
4990 			break;
4991 		case SPAN_FLASHID_2048K:
4992 			xp->fdesc.flash_size = 0x200000;
4993 			break;
4994 		case AMD_FLASHID_1024K:
4995 			xp->fdesc.flash_size = 0x100000;
4996 			break;
4997 		case AMD_FLASHID_512K:
4998 		case AMD_FLASHID_512Kt:
4999 		case AMD_FLASHID_512Kb:
5000 			if (CFG_IST(ha, CFG_SBUS_CARD)) {
5001 				xp->fdesc.flash_size = QL_SBUS_FCODE_SIZE;
5002 			} else {
5003 				xp->fdesc.flash_size = 0x80000;
5004 			}
5005 			break;
5006 		case AMD_FLASHID_128K:
5007 			xp->fdesc.flash_size = 0x20000;
5008 			break;
5009 		default:
5010 			rval = QL_FUNCTION_FAILED;
5011 			break;
5012 		}
5013 		break;
5014 	case ST_FLASH:
5015 		switch (xp->fdesc.flash_id) {
5016 		case ST_FLASHID_128K:
5017 			xp->fdesc.flash_size = 0x20000;
5018 			break;
5019 		case ST_FLASHID_512K:
5020 			xp->fdesc.flash_size = 0x80000;
5021 			break;
5022 		case ST_FLASHID_M25PXX:
5023 			if (xp->fdesc.flash_len == 0x14) {
5024 				xp->fdesc.flash_size = 0x100000;
5025 			} else if (xp->fdesc.flash_len == 0x15) {
5026 				xp->fdesc.flash_size = 0x200000;
5027 			} else {
5028 				rval = QL_FUNCTION_FAILED;
5029 			}
5030 			break;
5031 		case ST_FLASHID_N25QXXX:
5032 			if (xp->fdesc.flash_len == 0x18) {
5033 				xp->fdesc.flash_size = 0x1000000;
5034 			} else {
5035 				rval = QL_FUNCTION_FAILED;
5036 			}
5037 			break;
5038 		default:
5039 			rval = QL_FUNCTION_FAILED;
5040 			break;
5041 		}
5042 		break;
5043 	case SST_FLASH:
5044 		switch (xp->fdesc.flash_id) {
5045 		case SST_FLASHID_128K:
5046 			xp->fdesc.flash_size = 0x20000;
5047 			break;
5048 		case SST_FLASHID_1024K_A:
5049 			xp->fdesc.flash_size = 0x100000;
5050 			xp->fdesc.block_size = 0x8000;
5051 			xp->fdesc.erase_cmd = 0x52;
5052 			break;
5053 		case SST_FLASHID_1024K:
5054 		case SST_FLASHID_1024K_B:
5055 			xp->fdesc.flash_size = 0x100000;
5056 			break;
5057 		case SST_FLASHID_2048K:
5058 			xp->fdesc.flash_size = 0x200000;
5059 			break;
5060 		default:
5061 			rval = QL_FUNCTION_FAILED;
5062 			break;
5063 		}
5064 		break;
5065 	case MXIC_FLASH:
5066 		switch (xp->fdesc.flash_id) {
5067 		case MXIC_FLASHID_512K:
5068 			xp->fdesc.flash_size = 0x80000;
5069 			break;
5070 		case MXIC_FLASHID_1024K:
5071 			xp->fdesc.flash_size = 0x100000;
5072 			break;
5073 		case MXIC_FLASHID_25LXX:
5074 			xp->fdesc.write_disable_bits = 0xbc;
5075 			if (xp->fdesc.flash_len == 0x14) {
5076 				xp->fdesc.flash_size = 0x100000;
5077 			} else if (xp->fdesc.flash_len == 0x15) {
5078 				xp->fdesc.flash_size = 0x200000;
5079 			} else if (xp->fdesc.flash_len == 0x16) {
5080 				xp->fdesc.flash_size = 0x400000;
5081 			} else if (xp->fdesc.flash_len == 0x17) {
5082 				xp->fdesc.flash_size = 0x800000;
5083 			} else if (xp->fdesc.flash_len == 0x18) {
5084 				xp->fdesc.flash_size = 0x1000000;
5085 			} else {
5086 				rval = QL_FUNCTION_FAILED;
5087 			}
5088 			break;
5089 		default:
5090 			rval = QL_FUNCTION_FAILED;
5091 			break;
5092 		}
5093 		break;
5094 	case ATMEL_FLASH:
5095 		switch (xp->fdesc.flash_id) {
5096 		case ATMEL_FLASHID_1024K:
5097 			xp->fdesc.flash_size = 0x100000;
5098 			xp->fdesc.write_disable_bits = 0xbc;
5099 			xp->fdesc.unprotect_sector_cmd = 0x39;
5100 			xp->fdesc.protect_sector_cmd = 0x36;
5101 			break;
5102 		default:
5103 			rval = QL_FUNCTION_FAILED;
5104 			break;
5105 		}
5106 		break;
5107 	case WINBOND_FLASH:
5108 		switch (xp->fdesc.flash_id) {
5109 		case WINBOND_FLASHID:
5110 			if (xp->fdesc.flash_len == 0x15) {
5111 				xp->fdesc.flash_size = 0x200000;
5112 			} else if (xp->fdesc.flash_len == 0x16) {
5113 				xp->fdesc.flash_size = 0x400000;
5114 			} else if (xp->fdesc.flash_len == 0x17) {
5115 				xp->fdesc.flash_size = 0x800000;
5116 			} else if (xp->fdesc.flash_len == 0x18) {
5117 				xp->fdesc.flash_size = 0x1000000;
5118 			} else {
5119 				rval = QL_FUNCTION_FAILED;
5120 			}
5121 			break;
5122 		default:
5123 			rval = QL_FUNCTION_FAILED;
5124 			break;
5125 		}
5126 		break;
5127 	case INTEL_FLASH:
5128 		switch (xp->fdesc.flash_id) {
5129 		case INTEL_FLASHID:
5130 			if (xp->fdesc.flash_len == 0x11) {
5131 				xp->fdesc.flash_size = 0x200000;
5132 			} else if (xp->fdesc.flash_len == 0x12) {
5133 				xp->fdesc.flash_size = 0x400000;
5134 			} else if (xp->fdesc.flash_len == 0x13) {
5135 				xp->fdesc.flash_size = 0x800000;
5136 			} else {
5137 				rval = QL_FUNCTION_FAILED;
5138 			}
5139 			break;
5140 		default:
5141 			rval = QL_FUNCTION_FAILED;
5142 			break;
5143 		}
5144 		break;
5145 	case EON_FLASH:
5146 		switch (xp->fdesc.flash_id) {
5147 		case EON_FLASHID_EN25QXXX:
5148 			if (xp->fdesc.flash_len == 0x18) {
5149 				xp->fdesc.flash_size = 0x1000000;
5150 			} else {
5151 				rval = QL_FUNCTION_FAILED;
5152 			}
5153 			break;
5154 		default:
5155 			rval = QL_FUNCTION_FAILED;
5156 			break;
5157 		}
5158 		break;
5159 	default:
5160 		rval = QL_FUNCTION_FAILED;
5161 		break;
5162 	}
5163 
5164 	/* Try flash table later. */
5165 	if (rval != QL_SUCCESS && CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5166 		EL(ha, "no default id\n");
5167 		return (QL_SUCCESS);
5168 	}
5169 
5170 	/*
5171 	 * hack for non std 2312/2322 and 6312/6322 boards. hardware people
5172 	 * need to use either the 128k flash chip (original), or something
5173 	 * larger. For driver purposes, we'll treat it as a 128k flash chip.
5174 	 */
5175 	if ((ha->device_id == 0x2312 || ha->device_id == 0x6312 ||
5176 	    ha->device_id == 0x2322 || ha->device_id == 0x6322) &&
5177 	    (xp->fdesc.flash_size > 0x20000) &&
5178 	    (CFG_IST(ha, CFG_SBUS_CARD) == 0)) {
5179 		EL(ha, "chip exceeds max size: %xh, using 128k\n",
5180 		    xp->fdesc.flash_size);
5181 		xp->fdesc.flash_size = 0x20000;
5182 	}
5183 
5184 	if (rval == QL_SUCCESS) {
5185 		EL(ha, "man_id=%xh, flash_id=%xh, size=%xh\n",
5186 		    xp->fdesc.flash_manuf, xp->fdesc.flash_id,
5187 		    xp->fdesc.flash_size);
5188 	} else {
5189 		EL(ha, "unsupported mfr / type: man_id=%xh, flash_id=%xh\n",
5190 		    xp->fdesc.flash_manuf, xp->fdesc.flash_id);
5191 	}
5192 
5193 	return (rval);
5194 }
5195 
5196 /*
5197  * ql_flash_fcode_load
5198  *	Loads fcode data into flash from application.
5199  *
5200  * Input:
5201  *	ha:	adapter state pointer.
5202  *	bp:	user buffer address.
5203  *	size:	user buffer size.
5204  *	mode:	flags
5205  *
5206  * Returns:
5207  *
5208  * Context:
5209  *	Kernel context.
5210  */
5211 static int
ql_flash_fcode_load(ql_adapter_state_t * ha,void * bp,uint32_t bsize,int mode)5212 ql_flash_fcode_load(ql_adapter_state_t *ha, void *bp, uint32_t bsize,
5213     int mode)
5214 {
5215 	uint8_t		*bfp;
5216 	ql_xioctl_t	*xp = ha->xioctl;
5217 	int		rval = 0;
5218 
5219 	QL_PRINT_9(ha, "started\n");
5220 
5221 	if (bsize > xp->fdesc.flash_size) {
5222 		EL(ha, "failed, bufsize: %xh, flash size: %xh\n", bsize,
5223 		    xp->fdesc.flash_size);
5224 		return (ENOMEM);
5225 	}
5226 
5227 	if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
5228 		EL(ha, "failed, kmem_zalloc\n");
5229 		rval = ENOMEM;
5230 	} else {
5231 		if (ddi_copyin(bp, bfp, bsize, mode) != 0) {
5232 			EL(ha, "failed, ddi_copyin\n");
5233 			rval = EFAULT;
5234 		} else if (ql_load_fcode(ha, bfp, bsize, 0) != QL_SUCCESS) {
5235 			EL(ha, "failed, load_fcode\n");
5236 			rval = EFAULT;
5237 		} else {
5238 			/* Reset caches on all adapter instances. */
5239 			ql_update_flash_caches(ha);
5240 			rval = 0;
5241 		}
5242 		kmem_free(bfp, bsize);
5243 	}
5244 
5245 	QL_PRINT_9(ha, "done\n");
5246 
5247 	return (rval);
5248 }
5249 
5250 /*
5251  * ql_load_fcode
5252  *	Loads fcode in to flash.
5253  *
5254  * Input:
5255  *	ha:	adapter state pointer.
5256  *	dp:	data pointer.
5257  *	size:	data length.
5258  *	addr:	flash byte address.
5259  *
5260  * Returns:
5261  *	ql local function return status code.
5262  *
5263  * Context:
5264  *	Kernel context.
5265  */
5266 int
ql_load_fcode(ql_adapter_state_t * ha,uint8_t * dp,uint32_t size,uint32_t addr)5267 ql_load_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size, uint32_t addr)
5268 {
5269 	uint32_t	cnt;
5270 	int		rval;
5271 
5272 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5273 		return (ql_24xx_load_flash(ha, dp, size, addr));
5274 	}
5275 
5276 	QL_PRINT_9(ha, "started\n");
5277 
5278 	if (CFG_IST(ha, CFG_SBUS_CARD)) {
5279 		/*
5280 		 * sbus has an additional check to make
5281 		 * sure they don't brick the HBA.
5282 		 */
5283 		if (dp[0] != 0xf1) {
5284 			EL(ha, "failed, incorrect fcode for sbus\n");
5285 			return (QL_FUNCTION_PARAMETER_ERROR);
5286 		}
5287 	}
5288 
5289 	GLOBAL_HW_LOCK();
5290 
5291 	/* Enable Flash Read/Write. */
5292 	ql_flash_enable(ha);
5293 
5294 	/* Erase flash prior to write. */
5295 	rval = ql_erase_flash(ha, 0);
5296 
5297 	if (rval == QL_SUCCESS) {
5298 		/* Write fcode data to flash. */
5299 		for (cnt = 0; cnt < (uint32_t)size; cnt++) {
5300 			/* Allow other system activity. */
5301 			if (cnt % 0x1000 == 0) {
5302 				drv_usecwait(1);
5303 			}
5304 			rval = ql_program_flash_address(ha, addr++, *dp++);
5305 			if (rval != QL_SUCCESS)
5306 				break;
5307 		}
5308 	}
5309 
5310 	ql_flash_disable(ha);
5311 
5312 	GLOBAL_HW_UNLOCK();
5313 
5314 	if (rval != QL_SUCCESS) {
5315 		EL(ha, "failed, rval=%xh\n", rval);
5316 	} else {
5317 		/*EMPTY*/
5318 		QL_PRINT_9(ha, "done\n");
5319 	}
5320 	return (rval);
5321 }
5322 
5323 /*
5324  * ql_flash_fcode_dump
5325  *	Dumps FLASH to application.
5326  *
5327  * Input:
5328  *	ha:	adapter state pointer.
5329  *	bp:	user buffer address.
5330  *	bsize:	user buffer size
5331  *	faddr:	flash byte address
5332  *	mode:	flags
5333  *
5334  * Returns:
5335  *
5336  * Context:
5337  *	Kernel context.
5338  */
5339 static int
ql_flash_fcode_dump(ql_adapter_state_t * ha,void * bp,uint32_t bsize,uint32_t faddr,int mode)5340 ql_flash_fcode_dump(ql_adapter_state_t *ha, void *bp, uint32_t bsize,
5341     uint32_t faddr, int mode)
5342 {
5343 	uint8_t		*bfp;
5344 	int		rval;
5345 	ql_xioctl_t	*xp = ha->xioctl;
5346 
5347 	QL_PRINT_9(ha, "started\n");
5348 
5349 	/* adjust max read size to flash size */
5350 	if (bsize > xp->fdesc.flash_size) {
5351 		EL(ha, "adjusting req=%xh, max=%xh\n", bsize,
5352 		    xp->fdesc.flash_size);
5353 		bsize = xp->fdesc.flash_size;
5354 	}
5355 
5356 	if ((bfp = (uint8_t *)kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
5357 		EL(ha, "failed, kmem_zalloc\n");
5358 		rval = ENOMEM;
5359 	} else {
5360 		/* Dump Flash fcode. */
5361 		rval = ql_dump_fcode(ha, bfp, bsize, faddr);
5362 
5363 		if (rval != QL_SUCCESS) {
5364 			EL(ha, "failed, dump_fcode = %x\n", rval);
5365 			rval = EFAULT;
5366 		} else if (ddi_copyout(bfp, bp, bsize, mode) != 0) {
5367 			EL(ha, "failed, ddi_copyout\n");
5368 			rval = EFAULT;
5369 		} else {
5370 			rval = 0;
5371 		}
5372 		kmem_free(bfp, bsize);
5373 	}
5374 
5375 	QL_PRINT_9(ha, "done\n");
5376 
5377 	return (rval);
5378 }
5379 
5380 /*
5381  * ql_dump_fcode
5382  *	Dumps fcode from flash.
5383  *
5384  * Input:
5385  *	ha:		adapter state pointer.
5386  *	dp:		data pointer.
5387  *	size:		data length in bytes.
5388  *	startpos:	starting position in flash (byte address).
5389  *
5390  * Returns:
5391  *	ql local function return status code.
5392  *
5393  * Context:
5394  *	Kernel context.
5395  *
5396  */
5397 int
ql_dump_fcode(ql_adapter_state_t * ha,uint8_t * dp,uint32_t size,uint32_t startpos)5398 ql_dump_fcode(ql_adapter_state_t *ha, uint8_t *dp, uint32_t size,
5399     uint32_t startpos)
5400 {
5401 	uint32_t	cnt, data, addr;
5402 	uint8_t		bp[4], *src;
5403 	int		fp_rval, rval = QL_SUCCESS;
5404 	dma_mem_t	mem;
5405 
5406 	QL_PRINT_9(ha, "started\n");
5407 
5408 	/* make sure startpos+size doesn't exceed flash */
5409 	if (size + startpos > ha->xioctl->fdesc.flash_size) {
5410 		EL(ha, "exceeded flash range, sz=%xh, stp=%xh, flsz=%xh\n",
5411 		    size, startpos, ha->xioctl->fdesc.flash_size);
5412 		return (QL_FUNCTION_PARAMETER_ERROR);
5413 	}
5414 
5415 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5416 		/* check start addr is 32 bit aligned for 24xx */
5417 		if ((startpos & 0x3) != 0) {
5418 			rval = ql_24xx_read_flash(ha,
5419 			    ha->flash_data_addr | startpos >> 2, &data);
5420 			if (rval != QL_SUCCESS) {
5421 				EL(ha, "failed2, rval = %xh\n", rval);
5422 				return (rval);
5423 			}
5424 			bp[0] = LSB(LSW(data));
5425 			bp[1] = MSB(LSW(data));
5426 			bp[2] = LSB(MSW(data));
5427 			bp[3] = MSB(MSW(data));
5428 			while (size && startpos & 0x3) {
5429 				*dp++ = bp[startpos & 0x3];
5430 				startpos++;
5431 				size--;
5432 			}
5433 			if (size == 0) {
5434 				QL_PRINT_9(ha, "done2\n",
5435 				    ha->instance);
5436 				return (rval);
5437 			}
5438 		}
5439 
5440 		/* adjust 24xx start addr for 32 bit words */
5441 		addr = startpos / 4 | ha->flash_data_addr;
5442 	}
5443 
5444 	bzero(&mem, sizeof (dma_mem_t));
5445 	/* Check for Fast page is supported */
5446 	if ((ha->pha->task_daemon_flags & FIRMWARE_UP) &&
5447 	    (CFG_IST(ha, CFG_FLASH_DMA_SUPPORT))) {
5448 		fp_rval = QL_SUCCESS;
5449 		/* Setup DMA buffer. */
5450 		rval = ql_get_dma_mem(ha, &mem, size,
5451 		    LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN);
5452 		if (rval != QL_SUCCESS) {
5453 			EL(ha, "failed, ql_get_dma_mem=%xh\n",
5454 			    rval);
5455 			return (ENOMEM);
5456 		}
5457 	} else {
5458 		fp_rval = QL_NOT_SUPPORTED;
5459 	}
5460 
5461 	GLOBAL_HW_LOCK();
5462 
5463 	/* Enable Flash Read/Write. */
5464 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
5465 		ql_flash_enable(ha);
5466 	}
5467 
5468 	/* Read fcode data from flash. */
5469 	while (size) {
5470 		/* Allow other system activity. */
5471 		if (size % 0x1000 == 0) {
5472 			ql_delay(ha, 10000);
5473 		}
5474 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
5475 			if (fp_rval == QL_SUCCESS && (addr & 0x3f) == 0) {
5476 				cnt = (size + 3) >> 2;
5477 				fp_rval = ql_rd_risc_ram(ha, addr,
5478 				    mem.cookie.dmac_laddress, cnt);
5479 				if (fp_rval == QL_SUCCESS) {
5480 					for (src = mem.bp; size; size--) {
5481 						*dp++ = *src++;
5482 					}
5483 					addr += cnt;
5484 					continue;
5485 				}
5486 			}
5487 			rval = ql_24xx_read_flash(ha, addr++,
5488 			    &data);
5489 			if (rval != QL_SUCCESS) {
5490 				break;
5491 			}
5492 			bp[0] = LSB(LSW(data));
5493 			bp[1] = MSB(LSW(data));
5494 			bp[2] = LSB(MSW(data));
5495 			bp[3] = MSB(MSW(data));
5496 			for (cnt = 0; size && cnt < 4; size--) {
5497 				*dp++ = bp[cnt++];
5498 			}
5499 		} else {
5500 			*dp++ = (uint8_t)ql_read_flash_byte(ha, startpos++);
5501 			size--;
5502 		}
5503 	}
5504 
5505 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
5506 		ql_flash_disable(ha);
5507 	}
5508 
5509 	GLOBAL_HW_UNLOCK();
5510 
5511 	if (mem.dma_handle != NULL) {
5512 		ql_free_dma_resource(ha, &mem);
5513 	}
5514 
5515 	if (rval != QL_SUCCESS) {
5516 		EL(ha, "failed, rval = %xh\n", rval);
5517 	} else {
5518 		/*EMPTY*/
5519 		QL_PRINT_9(ha, "done\n");
5520 	}
5521 	return (rval);
5522 }
5523 
5524 /*
5525  * ql_program_flash_address
5526  *	Program flash address.
5527  *
5528  * Input:
5529  *	ha:	adapter state pointer.
5530  *	addr:	flash byte address.
5531  *	data:	data to be written to flash.
5532  *
5533  * Returns:
5534  *	ql local function return status code.
5535  *
5536  * Context:
5537  *	Kernel context.
5538  */
5539 static int
ql_program_flash_address(ql_adapter_state_t * ha,uint32_t addr,uint8_t data)5540 ql_program_flash_address(ql_adapter_state_t *ha, uint32_t addr,
5541     uint8_t data)
5542 {
5543 	int	rval;
5544 
5545 	/* Write Program Command Sequence */
5546 	if (CFG_IST(ha, CFG_SBUS_CARD)) {
5547 		ql_write_flash_byte(ha, 0x5555, 0xa0);
5548 		ql_write_flash_byte(ha, addr, data);
5549 	} else {
5550 		ql_write_flash_byte(ha, 0x5555, 0xaa);
5551 		ql_write_flash_byte(ha, 0x2aaa, 0x55);
5552 		ql_write_flash_byte(ha, 0x5555, 0xa0);
5553 		ql_write_flash_byte(ha, addr, data);
5554 	}
5555 
5556 	/* Wait for write to complete. */
5557 	rval = ql_poll_flash(ha, addr, data);
5558 
5559 	if (rval != QL_SUCCESS) {
5560 		EL(ha, "failed, rval=%xh\n", rval);
5561 	}
5562 	return (rval);
5563 }
5564 
5565 /*
5566  * ql_set_rnid_parameters
5567  *	Set RNID parameters.
5568  *
5569  * Input:
5570  *	ha:	adapter state pointer.
5571  *	cmd:	User space CT arguments pointer.
5572  *	mode:	flags.
5573  */
5574 static void
ql_set_rnid_parameters(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5575 ql_set_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5576 {
5577 	EXT_SET_RNID_REQ	tmp_set;
5578 	EXT_RNID_DATA		*tmp_buf;
5579 	int			rval = 0;
5580 
5581 	QL_PRINT_9(ha, "started\n");
5582 
5583 	if (DRIVER_SUSPENDED(ha)) {
5584 		EL(ha, "failed, LOOP_NOT_READY\n");
5585 		cmd->Status = EXT_STATUS_BUSY;
5586 		cmd->ResponseLen = 0;
5587 		return;
5588 	}
5589 
5590 	cmd->ResponseLen = 0; /* NO response to caller. */
5591 	if (cmd->RequestLen != sizeof (EXT_SET_RNID_REQ)) {
5592 		/* parameter error */
5593 		EL(ha, "failed, RequestLen < EXT_SET_RNID_REQ, Len=%xh\n",
5594 		    cmd->RequestLen);
5595 		cmd->Status = EXT_STATUS_INVALID_PARAM;
5596 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
5597 		cmd->ResponseLen = 0;
5598 		return;
5599 	}
5600 
5601 	rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &tmp_set,
5602 	    cmd->RequestLen, mode);
5603 	if (rval != 0) {
5604 		EL(ha, "failed, ddi_copyin\n");
5605 		cmd->Status = EXT_STATUS_COPY_ERR;
5606 		cmd->ResponseLen = 0;
5607 		return;
5608 	}
5609 
5610 	/* Allocate memory for command. */
5611 	tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP);
5612 	if (tmp_buf == NULL) {
5613 		EL(ha, "failed, kmem_zalloc\n");
5614 		cmd->Status = EXT_STATUS_NO_MEMORY;
5615 		cmd->ResponseLen = 0;
5616 		return;
5617 	}
5618 
5619 	rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA),
5620 	    (caddr_t)tmp_buf);
5621 	if (rval != QL_SUCCESS) {
5622 		/* error */
5623 		EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
5624 		kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5625 		cmd->Status = EXT_STATUS_ERR;
5626 		cmd->ResponseLen = 0;
5627 		return;
5628 	}
5629 
5630 	/* Now set the requested params. */
5631 	bcopy(tmp_set.IPVersion, tmp_buf->IPVersion, 2);
5632 	bcopy(tmp_set.UDPPortNumber, tmp_buf->UDPPortNumber, 2);
5633 	bcopy(tmp_set.IPAddress, tmp_buf->IPAddress, 16);
5634 
5635 	rval = ql_set_rnid_params(ha, sizeof (EXT_RNID_DATA),
5636 	    (caddr_t)tmp_buf);
5637 	if (rval != QL_SUCCESS) {
5638 		/* error */
5639 		EL(ha, "failed, set_rnid_params_mbx=%xh\n", rval);
5640 		cmd->Status = EXT_STATUS_ERR;
5641 		cmd->ResponseLen = 0;
5642 	}
5643 
5644 	kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5645 
5646 	QL_PRINT_9(ha, "done\n");
5647 }
5648 
5649 /*
5650  * ql_get_rnid_parameters
5651  *	Get RNID parameters.
5652  *
5653  * Input:
5654  *	ha:	adapter state pointer.
5655  *	cmd:	User space CT arguments pointer.
5656  *	mode:	flags.
5657  */
5658 static void
ql_get_rnid_parameters(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5659 ql_get_rnid_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5660 {
5661 	EXT_RNID_DATA	*tmp_buf;
5662 	uint32_t	rval;
5663 
5664 	QL_PRINT_9(ha, "started\n");
5665 
5666 	if (DRIVER_SUSPENDED(ha)) {
5667 		EL(ha, "failed, LOOP_NOT_READY\n");
5668 		cmd->Status = EXT_STATUS_BUSY;
5669 		cmd->ResponseLen = 0;
5670 		return;
5671 	}
5672 
5673 	/* Allocate memory for command. */
5674 	tmp_buf = kmem_zalloc(sizeof (EXT_RNID_DATA), KM_SLEEP);
5675 	if (tmp_buf == NULL) {
5676 		EL(ha, "failed, kmem_zalloc\n");
5677 		cmd->Status = EXT_STATUS_NO_MEMORY;
5678 		cmd->ResponseLen = 0;
5679 		return;
5680 	}
5681 
5682 	/* Send command */
5683 	rval = ql_get_rnid_params(ha, sizeof (EXT_RNID_DATA),
5684 	    (caddr_t)tmp_buf);
5685 	if (rval != QL_SUCCESS) {
5686 		/* error */
5687 		EL(ha, "failed, get_rnid_params_mbx=%xh\n", rval);
5688 		kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5689 		cmd->Status = EXT_STATUS_ERR;
5690 		cmd->ResponseLen = 0;
5691 		return;
5692 	}
5693 
5694 	/* Copy the response */
5695 	if (ql_send_buffer_data((caddr_t)tmp_buf,
5696 	    (caddr_t)(uintptr_t)cmd->ResponseAdr,
5697 	    sizeof (EXT_RNID_DATA), mode) != sizeof (EXT_RNID_DATA)) {
5698 		EL(ha, "failed, ddi_copyout\n");
5699 		cmd->Status = EXT_STATUS_COPY_ERR;
5700 		cmd->ResponseLen = 0;
5701 	} else {
5702 		QL_PRINT_9(ha, "done\n");
5703 		cmd->ResponseLen = sizeof (EXT_RNID_DATA);
5704 	}
5705 
5706 	kmem_free(tmp_buf, sizeof (EXT_RNID_DATA));
5707 }
5708 
5709 /*
5710  * ql_reset_statistics
5711  *	Performs EXT_SC_RST_STATISTICS subcommand. of EXT_CC_SET_DATA.
5712  *
5713  * Input:
5714  *	ha:	adapter state pointer.
5715  *	cmd:	Local EXT_IOCTL cmd struct pointer.
5716  *
5717  * Returns:
5718  *	None, request status indicated in cmd->Status.
5719  *
5720  * Context:
5721  *	Kernel context.
5722  */
5723 static int
ql_reset_statistics(ql_adapter_state_t * ha,EXT_IOCTL * cmd)5724 ql_reset_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd)
5725 {
5726 	ql_xioctl_t		*xp = ha->xioctl;
5727 	int			rval = 0;
5728 
5729 	QL_PRINT_9(ha, "started\n");
5730 
5731 	if (DRIVER_SUSPENDED(ha)) {
5732 		EL(ha, "failed, LOOP_NOT_READY\n");
5733 		cmd->Status = EXT_STATUS_BUSY;
5734 		cmd->ResponseLen = 0;
5735 		return (QL_FUNCTION_SUSPENDED);
5736 	}
5737 
5738 	rval = ql_reset_link_status(ha);
5739 	if (rval != QL_SUCCESS) {
5740 		EL(ha, "failed, reset_link_status_mbx=%xh\n", rval);
5741 		cmd->Status = EXT_STATUS_MAILBOX;
5742 		cmd->DetailStatus = rval;
5743 		cmd->ResponseLen = 0;
5744 	}
5745 
5746 	TASK_DAEMON_LOCK(ha);
5747 	xp->IosRequested = 0;
5748 	xp->BytesRequested = 0;
5749 	xp->IOInputRequests = 0;
5750 	xp->IOOutputRequests = 0;
5751 	xp->IOControlRequests = 0;
5752 	xp->IOInputMByteCnt = 0;
5753 	xp->IOOutputMByteCnt = 0;
5754 	xp->IOOutputByteCnt = 0;
5755 	xp->IOInputByteCnt = 0;
5756 	TASK_DAEMON_UNLOCK(ha);
5757 
5758 	INTR_LOCK(ha);
5759 	xp->ControllerErrorCount = 0;
5760 	xp->DeviceErrorCount = 0;
5761 	xp->TotalLipResets = 0;
5762 	xp->TotalInterrupts = 0;
5763 	INTR_UNLOCK(ha);
5764 
5765 	QL_PRINT_9(ha, "done\n");
5766 
5767 	return (rval);
5768 }
5769 
5770 /*
5771  * ql_get_statistics
5772  *	Performs EXT_SC_GET_STATISTICS subcommand. of EXT_CC_GET_DATA.
5773  *
5774  * Input:
5775  *	ha:	adapter state pointer.
5776  *	cmd:	Local EXT_IOCTL cmd struct pointer.
5777  *	mode:	flags.
5778  *
5779  * Returns:
5780  *	None, request status indicated in cmd->Status.
5781  *
5782  * Context:
5783  *	Kernel context.
5784  */
5785 static void
ql_get_statistics(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5786 ql_get_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5787 {
5788 	EXT_HBA_PORT_STAT	ps = {0};
5789 	ql_link_stats_t		*ls;
5790 	int			rval;
5791 	ql_xioctl_t		*xp = ha->xioctl;
5792 	int			retry = 10;
5793 
5794 	QL_PRINT_9(ha, "started\n");
5795 
5796 	while (ha->task_daemon_flags &
5797 	    (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) {
5798 		ql_delay(ha, 10000000);	/* 10 second delay */
5799 
5800 		retry--;
5801 
5802 		if (retry == 0) { /* effectively 100 seconds */
5803 			EL(ha, "failed, LOOP_NOT_READY\n");
5804 			cmd->Status = EXT_STATUS_BUSY;
5805 			cmd->ResponseLen = 0;
5806 			return;
5807 		}
5808 	}
5809 
5810 	/* Allocate memory for command. */
5811 	ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP);
5812 	if (ls == NULL) {
5813 		EL(ha, "failed, kmem_zalloc\n");
5814 		cmd->Status = EXT_STATUS_NO_MEMORY;
5815 		cmd->ResponseLen = 0;
5816 		return;
5817 	}
5818 
5819 	/*
5820 	 * I think these are supposed to be port statistics
5821 	 * the loop ID or port ID should be in cmd->Instance.
5822 	 */
5823 	rval = ql_get_status_counts(ha, (uint16_t)
5824 	    (ha->task_daemon_flags & LOOP_DOWN ? 0xFF : ha->loop_id),
5825 	    sizeof (ql_link_stats_t), (caddr_t)ls, 0);
5826 	if (rval != QL_SUCCESS) {
5827 		EL(ha, "failed, get_link_status=%xh, id=%xh\n", rval,
5828 		    ha->loop_id);
5829 		cmd->Status = EXT_STATUS_MAILBOX;
5830 		cmd->DetailStatus = rval;
5831 		cmd->ResponseLen = 0;
5832 	} else {
5833 		ps.ControllerErrorCount = xp->ControllerErrorCount;
5834 		ps.DeviceErrorCount = xp->DeviceErrorCount;
5835 		ps.IoCount = (uint32_t)(xp->IOInputRequests +
5836 		    xp->IOOutputRequests + xp->IOControlRequests);
5837 		ps.MBytesCount = (uint32_t)(xp->IOInputMByteCnt +
5838 		    xp->IOOutputMByteCnt);
5839 		ps.LipResetCount = xp->TotalLipResets;
5840 		ps.InterruptCount = xp->TotalInterrupts;
5841 		ps.LinkFailureCount = LE_32(ls->link_fail_cnt);
5842 		ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt);
5843 		ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt);
5844 		ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt);
5845 		ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt);
5846 		ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt);
5847 
5848 		rval = ddi_copyout((void *)&ps,
5849 		    (void *)(uintptr_t)cmd->ResponseAdr,
5850 		    sizeof (EXT_HBA_PORT_STAT), mode);
5851 		if (rval != 0) {
5852 			EL(ha, "failed, ddi_copyout\n");
5853 			cmd->Status = EXT_STATUS_COPY_ERR;
5854 			cmd->ResponseLen = 0;
5855 		} else {
5856 			cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT);
5857 		}
5858 	}
5859 
5860 	kmem_free(ls, sizeof (ql_link_stats_t));
5861 
5862 	QL_PRINT_9(ha, "done\n");
5863 }
5864 
5865 /*
5866  * ql_get_statistics_fc
5867  *	Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA.
5868  *
5869  * Input:
5870  *	ha:	adapter state pointer.
5871  *	cmd:	Local EXT_IOCTL cmd struct pointer.
5872  *	mode:	flags.
5873  *
5874  * Returns:
5875  *	None, request status indicated in cmd->Status.
5876  *
5877  * Context:
5878  *	Kernel context.
5879  */
5880 static void
ql_get_statistics_fc(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5881 ql_get_statistics_fc(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5882 {
5883 	EXT_HBA_PORT_STAT	ps = {0};
5884 	ql_link_stats_t		*ls;
5885 	int			rval;
5886 	uint16_t		qlnt;
5887 	EXT_DEST_ADDR		pextdestaddr;
5888 	uint8_t			*name;
5889 	ql_tgt_t		*tq = NULL;
5890 	int			retry = 10;
5891 
5892 	QL_PRINT_9(ha, "started\n");
5893 
5894 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
5895 	    (void *)&pextdestaddr, sizeof (EXT_DEST_ADDR), mode) != 0) {
5896 		EL(ha, "failed, ddi_copyin\n");
5897 		cmd->Status = EXT_STATUS_COPY_ERR;
5898 		cmd->ResponseLen = 0;
5899 		return;
5900 	}
5901 
5902 	qlnt = QLNT_PORT;
5903 	name = pextdestaddr.DestAddr.WWPN;
5904 
5905 	QL_PRINT_9(ha, "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
5906 	    ha->instance, name[0], name[1], name[2], name[3], name[4],
5907 	    name[5], name[6], name[7]);
5908 
5909 	tq = ql_find_port(ha, name, qlnt);
5910 
5911 	if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
5912 		EL(ha, "failed, fc_port not found\n");
5913 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
5914 		cmd->ResponseLen = 0;
5915 		return;
5916 	}
5917 
5918 	while (ha->task_daemon_flags &
5919 	    (ABORT_ISP_ACTIVE | LOOP_RESYNC_ACTIVE | DRIVER_STALL)) {
5920 		ql_delay(ha, 10000000);	/* 10 second delay */
5921 
5922 		retry--;
5923 
5924 		if (retry == 0) { /* effectively 100 seconds */
5925 			EL(ha, "failed, LOOP_NOT_READY\n");
5926 			cmd->Status = EXT_STATUS_BUSY;
5927 			cmd->ResponseLen = 0;
5928 			return;
5929 		}
5930 	}
5931 
5932 	/* Allocate memory for command. */
5933 	ls = kmem_zalloc(sizeof (ql_link_stats_t), KM_SLEEP);
5934 	if (ls == NULL) {
5935 		EL(ha, "failed, kmem_zalloc\n");
5936 		cmd->Status = EXT_STATUS_NO_MEMORY;
5937 		cmd->ResponseLen = 0;
5938 		return;
5939 	}
5940 
5941 	rval = ql_get_link_status(ha, tq->loop_id, sizeof (ql_link_stats_t),
5942 	    (caddr_t)ls, 0);
5943 	if (rval != QL_SUCCESS) {
5944 		EL(ha, "failed, get_link_status=%xh, d_id=%xh\n", rval,
5945 		    tq->d_id.b24);
5946 		cmd->Status = EXT_STATUS_MAILBOX;
5947 		cmd->DetailStatus = rval;
5948 		cmd->ResponseLen = 0;
5949 	} else {
5950 		ps.LinkFailureCount = LE_32(ls->link_fail_cnt);
5951 		ps.LossOfSyncCount = LE_32(ls->sync_loss_cnt);
5952 		ps.LossOfSignalsCount = LE_32(ls->signal_loss_cnt);
5953 		ps.PrimitiveSeqProtocolErrorCount = LE_32(ls->prot_err_cnt);
5954 		ps.InvalidTransmissionWordCount = LE_32(ls->inv_xmit_cnt);
5955 		ps.InvalidCRCCount = LE_32(ls->inv_crc_cnt);
5956 
5957 		rval = ddi_copyout((void *)&ps,
5958 		    (void *)(uintptr_t)cmd->ResponseAdr,
5959 		    sizeof (EXT_HBA_PORT_STAT), mode);
5960 
5961 		if (rval != 0) {
5962 			EL(ha, "failed, ddi_copyout\n");
5963 			cmd->Status = EXT_STATUS_COPY_ERR;
5964 			cmd->ResponseLen = 0;
5965 		} else {
5966 			cmd->ResponseLen = sizeof (EXT_HBA_PORT_STAT);
5967 		}
5968 	}
5969 
5970 	kmem_free(ls, sizeof (ql_link_stats_t));
5971 
5972 	QL_PRINT_9(ha, "done\n");
5973 }
5974 
5975 /*
5976  * ql_get_statistics_fc4
5977  *	Performs EXT_SC_GET_FC_STATISTICS subcommand. of EXT_CC_GET_DATA.
5978  *
5979  * Input:
5980  *	ha:	adapter state pointer.
5981  *	cmd:	Local EXT_IOCTL cmd struct pointer.
5982  *	mode:	flags.
5983  *
5984  * Returns:
5985  *	None, request status indicated in cmd->Status.
5986  *
5987  * Context:
5988  *	Kernel context.
5989  */
5990 static void
ql_get_statistics_fc4(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)5991 ql_get_statistics_fc4(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
5992 {
5993 	uint32_t		rval;
5994 	EXT_HBA_FC4STATISTICS	fc4stats = {0};
5995 	ql_xioctl_t		*xp = ha->xioctl;
5996 
5997 	QL_PRINT_9(ha, "started\n");
5998 
5999 	fc4stats.InputRequests = xp->IOInputRequests;
6000 	fc4stats.OutputRequests = xp->IOOutputRequests;
6001 	fc4stats.ControlRequests = xp->IOControlRequests;
6002 	fc4stats.InputMegabytes = xp->IOInputMByteCnt;
6003 	fc4stats.OutputMegabytes = xp->IOOutputMByteCnt;
6004 
6005 	rval = ddi_copyout((void *)&fc4stats,
6006 	    (void *)(uintptr_t)cmd->ResponseAdr,
6007 	    sizeof (EXT_HBA_FC4STATISTICS), mode);
6008 
6009 	if (rval != 0) {
6010 		EL(ha, "failed, ddi_copyout\n");
6011 		cmd->Status = EXT_STATUS_COPY_ERR;
6012 		cmd->ResponseLen = 0;
6013 	} else {
6014 		cmd->ResponseLen = sizeof (EXT_HBA_FC4STATISTICS);
6015 	}
6016 
6017 	QL_PRINT_9(ha, "done\n");
6018 }
6019 
6020 /*
6021  * ql_set_led_state
6022  *	Performs EXT_SET_BEACON_STATE subcommand of EXT_CC_SET_DATA.
6023  *
6024  * Input:
6025  *	ha:	adapter state pointer.
6026  *	cmd:	Local EXT_IOCTL cmd struct pointer.
6027  *	mode:	flags.
6028  *
6029  * Returns:
6030  *	None, request status indicated in cmd->Status.
6031  *
6032  * Context:
6033  *	Kernel context.
6034  */
6035 static void
ql_set_led_state(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)6036 ql_set_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6037 {
6038 	EXT_BEACON_CONTROL	bstate;
6039 	int			rval;
6040 	ql_mbx_data_t		mr;
6041 
6042 	QL_PRINT_9(ha, "started\n");
6043 
6044 	if (cmd->RequestLen < sizeof (EXT_BEACON_CONTROL)) {
6045 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6046 		cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL);
6047 		EL(ha, "done - failed, RequestLen < EXT_BEACON_CONTROL,"
6048 		    " Len=%xh\n", cmd->RequestLen);
6049 		cmd->ResponseLen = 0;
6050 		return;
6051 	}
6052 
6053 	if (!CFG_IST(ha, CFG_SET_LEDS_SUPPORT)) {
6054 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
6055 		cmd->DetailStatus = 0;
6056 		EL(ha, "done - failed, Invalid function for HBA model\n");
6057 		cmd->ResponseLen = 0;
6058 		return;
6059 	}
6060 
6061 	rval = ddi_copyin((void*)(uintptr_t)cmd->RequestAdr, &bstate,
6062 	    cmd->RequestLen, mode);
6063 
6064 	if (rval != 0) {
6065 		cmd->Status = EXT_STATUS_COPY_ERR;
6066 		EL(ha, "done -  failed, ddi_copyin\n");
6067 		return;
6068 	}
6069 
6070 	switch (bstate.State) {
6071 	case EXT_DEF_GRN_BLINK_OFF:	/* turn beacon off */
6072 		if (ha->ledstate.BeaconState == BEACON_OFF) {
6073 			/* not quite an error -- LED state is already off */
6074 			cmd->Status = EXT_STATUS_OK;
6075 			EL(ha, "LED off request -- LED is already off\n");
6076 			break;
6077 		}
6078 
6079 		if (CFG_IST(ha, CFG_CTRL_82XX)) {
6080 			rval = ql_diag_beacon(ha, QL_BEACON_DISABLE,
6081 			    &mr);
6082 
6083 			if (rval == QL_SUCCESS) {
6084 				ha->ledstate.BeaconState = BEACON_OFF;
6085 				ha->ledstate.LEDflags = LED_ALL_OFF;
6086 				cmd->Status = EXT_STATUS_OK;
6087 			} else {
6088 				cmd->Status = EXT_STATUS_ERR;
6089 				EL(ha, "failed, disable beacon request %xh\n",
6090 				    bstate.State);
6091 			}
6092 			break;
6093 		}
6094 
6095 		ha->ledstate.BeaconState = BEACON_OFF;
6096 		ha->ledstate.LEDflags = LED_ALL_OFF;
6097 
6098 		if ((rval = ql_wrapup_led(ha)) != QL_SUCCESS) {
6099 			cmd->Status = EXT_STATUS_MAILBOX;
6100 		} else {
6101 			cmd->Status = EXT_STATUS_OK;
6102 		}
6103 		break;
6104 
6105 	case EXT_DEF_GRN_BLINK_ON:	/* turn beacon on */
6106 		if (ha->ledstate.BeaconState == BEACON_ON) {
6107 			/* not quite an error -- LED state is already on */
6108 			cmd->Status = EXT_STATUS_OK;
6109 			EL(ha, "LED on request  - LED is already on\n");
6110 			break;
6111 		}
6112 
6113 		if (CFG_IST(ha, CFG_CTRL_82XX)) {
6114 			rval = ql_diag_beacon(ha, QL_BEACON_ENABLE,
6115 			    &mr);
6116 
6117 			if (rval == QL_SUCCESS) {
6118 				ha->ledstate.BeaconState = BEACON_ON;
6119 				ha->ledstate.LEDflags = LED_GREEN;
6120 				cmd->Status = EXT_STATUS_OK;
6121 			} else {
6122 				cmd->Status = EXT_STATUS_ERR;
6123 				EL(ha, "failed, enable beacon request %xh\n",
6124 				    bstate.State);
6125 			}
6126 			break;
6127 		}
6128 
6129 		if ((rval = ql_setup_led(ha)) != QL_SUCCESS) {
6130 			cmd->Status = EXT_STATUS_MAILBOX;
6131 			break;
6132 		}
6133 
6134 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
6135 			ha->ledstate.LEDflags = LED_YELLOW_24 | LED_AMBER_24;
6136 		} else {
6137 			ha->ledstate.LEDflags = LED_GREEN;
6138 		}
6139 		ha->ledstate.BeaconState = BEACON_ON;
6140 
6141 		cmd->Status = EXT_STATUS_OK;
6142 		break;
6143 	default:
6144 		cmd->Status = EXT_STATUS_ERR;
6145 		EL(ha, "failed, unknown state request %xh\n", bstate.State);
6146 		break;
6147 	}
6148 
6149 	QL_PRINT_9(ha, "done\n");
6150 }
6151 
6152 /*
6153  * ql_get_led_state
6154  *	Performs EXT_GET_BEACON_STATE subcommand of EXT_CC_GET_DATA.
6155  *
6156  * Input:
6157  *	ha:	adapter state pointer.
6158  *	cmd:	Local EXT_IOCTL cmd struct pointer.
6159  *	mode:	flags.
6160  *
6161  * Returns:
6162  *	None, request status indicated in cmd->Status.
6163  *
6164  * Context:
6165  *	Kernel context.
6166  */
6167 static void
ql_get_led_state(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)6168 ql_get_led_state(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6169 {
6170 	EXT_BEACON_CONTROL	bstate = {0};
6171 	uint32_t		rval;
6172 
6173 	QL_PRINT_9(ha, "started\n");
6174 
6175 	if (cmd->ResponseLen < sizeof (EXT_BEACON_CONTROL)) {
6176 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6177 		cmd->DetailStatus = sizeof (EXT_BEACON_CONTROL);
6178 		EL(ha, "done - failed, ResponseLen < EXT_BEACON_CONTROL,"
6179 		    "Len=%xh\n", cmd->ResponseLen);
6180 		cmd->ResponseLen = 0;
6181 		return;
6182 	}
6183 
6184 	if (!CFG_IST(ha, CFG_SET_LEDS_SUPPORT)) {
6185 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
6186 		cmd->DetailStatus = 0;
6187 		EL(ha, "done - failed, Invalid function for HBA model\n");
6188 		cmd->ResponseLen = 0;
6189 		return;
6190 	}
6191 
6192 	if (ha->task_daemon_flags & ABORT_ISP_ACTIVE) {
6193 		cmd->Status = EXT_STATUS_BUSY;
6194 		EL(ha, "done -  failed, isp abort active\n");
6195 		cmd->ResponseLen = 0;
6196 		return;
6197 	}
6198 
6199 	/* inform the user of the current beacon state (off or on) */
6200 	bstate.State = ha->ledstate.BeaconState;
6201 
6202 	rval = ddi_copyout((void *)&bstate,
6203 	    (void *)(uintptr_t)cmd->ResponseAdr,
6204 	    sizeof (EXT_BEACON_CONTROL), mode);
6205 
6206 	if (rval != 0) {
6207 		EL(ha, "failed, ddi_copyout\n");
6208 		cmd->Status = EXT_STATUS_COPY_ERR;
6209 		cmd->ResponseLen = 0;
6210 	} else {
6211 		cmd->Status = EXT_STATUS_OK;
6212 		cmd->ResponseLen = sizeof (EXT_BEACON_CONTROL);
6213 	}
6214 
6215 	QL_PRINT_9(ha, "done\n");
6216 }
6217 
6218 /*
6219  * ql_blink_led
6220  *	Determine the next state of the LED and drive it
6221  *
6222  * Input:
6223  *	ha:	adapter state pointer.
6224  *
6225  * Context:
6226  *	Interrupt context.
6227  */
6228 void
ql_blink_led(ql_adapter_state_t * ha)6229 ql_blink_led(ql_adapter_state_t *ha)
6230 {
6231 	uint32_t	nextstate;
6232 	ql_mbx_data_t	mr;
6233 
6234 	QL_PRINT_9(ha, "started\n");
6235 
6236 	if (ha->ledstate.BeaconState == BEACON_ON) {
6237 		if (CFG_IST(ha, CFG_CTRL_2363 | CFG_CTRL_2425)) {
6238 			/* determine the next led state */
6239 			if (CFG_IST(ha, CFG_CTRL_2425)) {
6240 				nextstate = (ha->ledstate.LEDflags) &
6241 				    (~(RD32_IO_REG(ha, gpiod)));
6242 			} else {
6243 				nextstate = (ha->ledstate.LEDflags) &
6244 				    (~(RD16_IO_REG(ha, gpiod)));
6245 			}
6246 
6247 			/* turn the led on or off */
6248 			ql_drive_led(ha, nextstate);
6249 		} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
6250 			if (ha->ledstate.flags & LED_ACTIVE) {
6251 				mr.mb[1] = 0x2000;
6252 				mr.mb[2] = 0x4000;
6253 				ha->ledstate.flags &= ~LED_ACTIVE;
6254 			} else {
6255 				mr.mb[1] = 0x4000;
6256 				mr.mb[2] = 0x2000;
6257 				ha->ledstate.flags |= LED_ACTIVE;
6258 			}
6259 			(void) ql_set_led_config(ha, &mr);
6260 		} else if (CFG_IST(ha, CFG_CTRL_80XX)) {
6261 			if (ha->ledstate.flags & LED_ACTIVE) {
6262 				mr.mb[1] = 0x4000;
6263 				mr.mb[2] = 0x2000;
6264 				mr.mb[3] = 0x4000;
6265 				mr.mb[4] = 0x4000;
6266 				mr.mb[5] = 0;
6267 				mr.mb[6] = 0x2000;
6268 				(void) ql_set_led_config(ha, &mr);
6269 				ha->ledstate.flags &= ~LED_ACTIVE;
6270 			} else {
6271 				mr.mb[1] = 0x4000;
6272 				mr.mb[2] = 0x4000;
6273 				mr.mb[3] = 0x4000;
6274 				mr.mb[4] = 0x2000;
6275 				mr.mb[5] = 0;
6276 				mr.mb[6] = 0x2000;
6277 				(void) ql_set_led_config(ha, &mr);
6278 				ha->ledstate.flags |= LED_ACTIVE;
6279 			}
6280 		} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
6281 			if (ha->ledstate.flags & LED_ACTIVE) {
6282 				(void) ql_write_remote_reg(ha,
6283 				    ha->ledstate.select,
6284 				    0x40004000);
6285 				(void) ql_write_remote_reg(ha,
6286 				    ha->ledstate.select + 4,
6287 				    0x40004000);
6288 				ha->ledstate.flags &= ~LED_ACTIVE;
6289 			} else {
6290 				(void) ql_write_remote_reg(ha,
6291 				    ha->ledstate.select,
6292 				    0x40002000);
6293 				(void) ql_write_remote_reg(ha,
6294 				    ha->ledstate.select + 4,
6295 				    0x40002000);
6296 				ha->ledstate.flags |= LED_ACTIVE;
6297 			}
6298 		} else if (!CFG_IST(ha, CFG_CTRL_27XX)) {
6299 			EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6300 		}
6301 	}
6302 
6303 	QL_PRINT_9(ha, "done\n");
6304 }
6305 
6306 /*
6307  * ql_drive_led
6308  *	drive the led's as determined by LEDflags
6309  *
6310  * Input:
6311  *	ha:		adapter state pointer.
6312  *	LEDflags:	LED flags
6313  *
6314  * Context:
6315  *	Kernel/Interrupt context.
6316  */
6317 static void
ql_drive_led(ql_adapter_state_t * ha,uint32_t LEDflags)6318 ql_drive_led(ql_adapter_state_t *ha, uint32_t LEDflags)
6319 {
6320 	QL_PRINT_9(ha, "started\n");
6321 
6322 	if (CFG_IST(ha, CFG_CTRL_2363)) {
6323 
6324 		uint16_t	gpio_enable, gpio_data;
6325 
6326 		/* setup to send new data */
6327 		gpio_enable = (uint16_t)RD16_IO_REG(ha, gpioe);
6328 		gpio_enable = (uint16_t)(gpio_enable | LED_MASK);
6329 		WRT16_IO_REG(ha, gpioe, gpio_enable);
6330 
6331 		/* read current data and clear out old led data */
6332 		gpio_data = (uint16_t)RD16_IO_REG(ha, gpiod);
6333 		gpio_data = (uint16_t)(gpio_data & ~LED_MASK);
6334 
6335 		/* set in the new led data. */
6336 		gpio_data = (uint16_t)(gpio_data | LEDflags);
6337 
6338 		/* write out the new led data */
6339 		WRT16_IO_REG(ha, gpiod, gpio_data);
6340 
6341 	} else if (CFG_IST(ha, CFG_CTRL_2425)) {
6342 		uint32_t	gpio_data;
6343 
6344 		/* setup to send new data */
6345 		gpio_data = RD32_IO_REG(ha, gpiod);
6346 		gpio_data |= LED_MASK_UPDATE_24;
6347 		WRT32_IO_REG(ha, gpiod, gpio_data);
6348 
6349 		/* read current data and clear out old led data */
6350 		gpio_data = RD32_IO_REG(ha, gpiod);
6351 		gpio_data &= ~LED_MASK_COLORS_24;
6352 
6353 		/* set in the new led data */
6354 		gpio_data |= LEDflags;
6355 
6356 		/* write out the new led data */
6357 		WRT32_IO_REG(ha, gpiod, gpio_data);
6358 
6359 	} else {
6360 		EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6361 	}
6362 
6363 	QL_PRINT_9(ha, "done\n");
6364 }
6365 
6366 /*
6367  * ql_setup_led
6368  *	Setup LED for driver control
6369  *
6370  * Input:
6371  *	ha:	adapter state pointer.
6372  *
6373  * Context:
6374  *	Kernel/Interrupt context.
6375  */
6376 static int
ql_setup_led(ql_adapter_state_t * ha)6377 ql_setup_led(ql_adapter_state_t *ha)
6378 {
6379 	int		rval = QL_SUCCESS;
6380 	ql_mbx_data_t	mr;
6381 
6382 	QL_PRINT_9(ha, "started\n");
6383 
6384 	if (CFG_IST(ha, CFG_CTRL_2363 | CFG_CTRL_2425)) {
6385 		/* decouple the LED control from the fw */
6386 		rval = ql_get_firmware_option(ha, &mr);
6387 		if (rval != QL_SUCCESS) {
6388 			EL(ha, "failed, get_firmware_option=%xh\n", rval);
6389 			return (rval);
6390 		}
6391 
6392 		/* set the appropriate options */
6393 		mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_GPIO);
6394 
6395 		/* send it back to the firmware */
6396 		rval = ql_set_firmware_option(ha, &mr);
6397 		if (rval != QL_SUCCESS) {
6398 			EL(ha, "failed, set_firmware_option=%xh\n", rval);
6399 			return (rval);
6400 		}
6401 
6402 		/* initally, turn the LED's off */
6403 		ql_drive_led(ha, LED_ALL_OFF);
6404 
6405 	} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
6406 		(void) ql_get_led_config(ha, &ha->ledstate.cfg);
6407 		mr.mb[1] = 0x2000;
6408 		mr.mb[2] = 0x2000;
6409 		rval = ql_set_led_config(ha, &mr);
6410 
6411 	} else if (CFG_IST(ha, CFG_CTRL_80XX)) {
6412 		/* Save initial value */
6413 		rval = ql_get_led_config(ha, &ha->ledstate.cfg);
6414 		if (rval != QL_SUCCESS) {
6415 			EL(ha, "failed, get_led_config=%xh\n", rval);
6416 			return (rval);
6417 		}
6418 		mr.mb[1] = 0x4000;
6419 		mr.mb[2] = 0x4000;
6420 		mr.mb[3] = 0x4000;
6421 		mr.mb[4] = 0x2000;
6422 		mr.mb[5] = 0;
6423 		mr.mb[6] = 0x2000;
6424 		rval = ql_set_led_config(ha, &mr);
6425 
6426 	} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
6427 		rval = ql_get_firmware_option(ha, &mr);
6428 		if (rval != QL_SUCCESS) {
6429 			EL(ha, "failed, get_firmware_option=%xh\n", rval);
6430 			return (rval);
6431 		}
6432 
6433 		mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_LEDS);
6434 
6435 		rval = ql_set_firmware_option(ha, &mr);
6436 		if (rval != QL_SUCCESS) {
6437 			EL(ha, "failed, set_firmware_option=%xh\n", rval);
6438 			return (rval);
6439 		}
6440 
6441 		(void) ql_write_remote_reg(ha, ha->ledstate.select,
6442 		    0x40002000);
6443 		(void) ql_write_remote_reg(ha, ha->ledstate.select + 4,
6444 		    0x40002000);
6445 
6446 	} else if (CFG_IST(ha, CFG_CTRL_27XX)) {
6447 		/* take control of LED */
6448 		rval = ql_get_firmware_option(ha, &mr);
6449 		if (rval != QL_SUCCESS) {
6450 			EL(ha, "failed, get_firmware_option=%xh\n", rval);
6451 			return (rval);
6452 		}
6453 
6454 		mr.mb[1] = (uint16_t)(mr.mb[1] | FO1_DISABLE_LEDS);
6455 
6456 		rval = ql_set_firmware_option(ha, &mr);
6457 		if (rval != QL_SUCCESS) {
6458 			EL(ha, "failed, set_firmware_option=%xh\n", rval);
6459 			return (rval);
6460 		}
6461 
6462 		mr.mb[1] = 0xf;
6463 		mr.mb[2] = 0x230;
6464 		mr.mb[3] = 0x230;
6465 		mr.mb[4] = 0x4000;
6466 		rval = ql_led_config(ha, &mr);
6467 		if (rval != QL_SUCCESS) {
6468 			EL(ha, "failed, led_config=%xh\n", rval);
6469 			return (rval);
6470 		}
6471 	} else {
6472 		EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6473 	}
6474 	ha->ledstate.flags |= LED_ACTIVE;
6475 
6476 	QL_PRINT_9(ha, "done\n");
6477 
6478 	return (rval);
6479 }
6480 
6481 /*
6482  * ql_wrapup_led
6483  *	Return LED control to the firmware
6484  *
6485  * Input:
6486  *	ha:	adapter state pointer.
6487  *
6488  * Context:
6489  *	Kernel/Interrupt context.
6490  */
6491 static int
ql_wrapup_led(ql_adapter_state_t * ha)6492 ql_wrapup_led(ql_adapter_state_t *ha)
6493 {
6494 	int		rval = QL_SUCCESS;
6495 	ql_mbx_data_t	mr;
6496 
6497 	QL_PRINT_9(ha, "started\n");
6498 
6499 
6500 	if (CFG_IST(ha, CFG_CTRL_2363 | CFG_CTRL_2425)) {
6501 		uint32_t	gpio_data;
6502 
6503 		/* Turn all LED's off */
6504 		ql_drive_led(ha, LED_ALL_OFF);
6505 
6506 		if (CFG_IST(ha, CFG_CTRL_2425)) {
6507 			/* disable the LED update mask */
6508 			gpio_data = RD32_IO_REG(ha, gpiod);
6509 			gpio_data &= ~LED_MASK_UPDATE_24;
6510 
6511 			/* write out the data */
6512 			WRT32_IO_REG(ha, gpiod, gpio_data);
6513 			/* give LED control back to the f/w */
6514 		}
6515 		rval = ql_get_firmware_option(ha, &mr);
6516 		if (rval != QL_SUCCESS) {
6517 			EL(ha, "failed, get_firmware_option=%xh\n", rval);
6518 			return (rval);
6519 		}
6520 
6521 		mr.mb[1] = (uint16_t)(mr.mb[1] & ~FO1_DISABLE_GPIO);
6522 
6523 		rval = ql_set_firmware_option(ha, &mr);
6524 		if (rval != QL_SUCCESS) {
6525 			EL(ha, "failed, set_firmware_option=%xh\n", rval);
6526 			return (rval);
6527 		}
6528 	} else if (CFG_IST(ha, CFG_CTRL_8081)) {
6529 		rval = ql_set_led_config(ha, &ha->ledstate.cfg);
6530 
6531 	} else if (CFG_IST(ha, CFG_CTRL_2783)) {
6532 		/* give LED control back to the f/w */
6533 		rval = ql_get_firmware_option(ha, &mr);
6534 		if (rval != QL_SUCCESS) {
6535 			EL(ha, "failed, get_firmware_option=%xh\n", rval);
6536 			return (rval);
6537 		}
6538 
6539 		mr.mb[1] = (uint16_t)(mr.mb[1] & ~FO1_DISABLE_LEDS);
6540 
6541 		rval = ql_set_firmware_option(ha, &mr);
6542 		if (rval != QL_SUCCESS) {
6543 			EL(ha, "failed, set_firmware_option=%xh\n", rval);
6544 			return (rval);
6545 		}
6546 
6547 	} else {
6548 		EL(ha, "unsupported HBA: %xh\n", ha->device_id);
6549 	}
6550 
6551 	QL_PRINT_9(ha, "done\n");
6552 
6553 	return (rval);
6554 }
6555 
6556 /*
6557  * ql_get_port_summary
6558  *	Performs EXT_SC_GET_PORT_SUMMARY subcommand. of EXT_CC_GET_DATA.
6559  *
6560  *	The EXT_IOCTL->RequestAdr points to a single
6561  *	UINT32 which identifies the device type.
6562  *
6563  * Input:
6564  *	ha:	adapter state pointer.
6565  *	cmd:	Local EXT_IOCTL cmd struct pointer.
6566  *	mode:	flags.
6567  *
6568  * Returns:
6569  *	None, request status indicated in cmd->Status.
6570  *
6571  * Context:
6572  *	Kernel context.
6573  */
6574 static void
ql_get_port_summary(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)6575 ql_get_port_summary(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6576 {
6577 	EXT_DEVICEDATA		dd = {0};
6578 	EXT_DEVICEDATA		*uddp;
6579 	ql_link_t		*link;
6580 	ql_tgt_t		*tq;
6581 	uint32_t		rlen, dev_type, index;
6582 	int			rval = 0;
6583 	EXT_DEVICEDATAENTRY	*uddep, *ddep;
6584 
6585 	QL_PRINT_9(ha, "started\n");
6586 
6587 	ddep = &dd.EntryList[0];
6588 
6589 	/*
6590 	 * Get the type of device the requestor is looking for.
6591 	 *
6592 	 * We ignore this for now.
6593 	 */
6594 	rval = ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
6595 	    (void *)&dev_type, sizeof (dev_type), mode);
6596 	if (rval != 0) {
6597 		cmd->Status = EXT_STATUS_COPY_ERR;
6598 		cmd->ResponseLen = 0;
6599 		EL(ha, "failed, ddi_copyin\n");
6600 		return;
6601 	}
6602 	/*
6603 	 * Count the number of entries to be returned. Count devices
6604 	 * that are offlline, but have been persistently bound.
6605 	 */
6606 	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
6607 		for (link = ha->dev[index].first; link != NULL;
6608 		    link = link->next) {
6609 			tq = link->base_address;
6610 			if (tq->flags & TQF_INITIATOR_DEVICE ||
6611 			    !VALID_TARGET_ID(ha, tq->loop_id)) {
6612 				continue;	/* Skip this one */
6613 			}
6614 			dd.TotalDevices++;
6615 		}
6616 	}
6617 	/*
6618 	 * Compute the number of entries that can be returned
6619 	 * based upon the size of caller's response buffer.
6620 	 */
6621 	dd.ReturnListEntryCount = 0;
6622 	if (dd.TotalDevices == 0) {
6623 		rlen = sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY);
6624 	} else {
6625 		rlen = (uint32_t)(sizeof (EXT_DEVICEDATA) +
6626 		    (sizeof (EXT_DEVICEDATAENTRY) * (dd.TotalDevices - 1)));
6627 	}
6628 	if (rlen > cmd->ResponseLen) {
6629 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
6630 		cmd->DetailStatus = rlen;
6631 		EL(ha, "failed, rlen > ResponseLen, rlen=%d, Len=%d\n",
6632 		    rlen, cmd->ResponseLen);
6633 		cmd->ResponseLen = 0;
6634 		return;
6635 	}
6636 	cmd->ResponseLen = 0;
6637 	uddp = (EXT_DEVICEDATA *)(uintptr_t)cmd->ResponseAdr;
6638 	uddep = &uddp->EntryList[0];
6639 	for (index = 0; index < DEVICE_HEAD_LIST_SIZE; index++) {
6640 		for (link = ha->dev[index].first; link != NULL;
6641 		    link = link->next) {
6642 			tq = link->base_address;
6643 			if (tq->flags & TQF_INITIATOR_DEVICE ||
6644 			    !VALID_TARGET_ID(ha, tq->loop_id) ||
6645 			    tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
6646 				continue;	/* Skip this one */
6647 			}
6648 
6649 			bzero((void *)ddep, sizeof (EXT_DEVICEDATAENTRY));
6650 
6651 			bcopy(tq->node_name, ddep->NodeWWN, 8);
6652 			bcopy(tq->port_name, ddep->PortWWN, 8);
6653 
6654 			ddep->PortID[0] = tq->d_id.b.domain;
6655 			ddep->PortID[1] = tq->d_id.b.area;
6656 			ddep->PortID[2] = tq->d_id.b.al_pa;
6657 
6658 			bcopy(tq->port_name,
6659 			    (caddr_t)&ddep->TargetAddress.Target, 8);
6660 
6661 			ddep->DeviceFlags = tq->flags;
6662 			ddep->LoopID = tq->loop_id;
6663 			QL_PRINT_9(ha, "Tgt=%lld, loop=%xh, "
6664 			    "wwnn=%02x%02x%02x%02x%02x%02x%02x%02x, "
6665 			    "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
6666 			    ha->instance, ddep->TargetAddress.Target,
6667 			    ddep->LoopID, ddep->NodeWWN[0], ddep->NodeWWN[1],
6668 			    ddep->NodeWWN[2], ddep->NodeWWN[3],
6669 			    ddep->NodeWWN[4], ddep->NodeWWN[5],
6670 			    ddep->NodeWWN[6], ddep->NodeWWN[7],
6671 			    ddep->PortWWN[0], ddep->PortWWN[1],
6672 			    ddep->PortWWN[2], ddep->PortWWN[3],
6673 			    ddep->PortWWN[4], ddep->PortWWN[5],
6674 			    ddep->PortWWN[6], ddep->PortWWN[7]);
6675 			rval = ddi_copyout((void *)ddep, (void *)uddep,
6676 			    sizeof (EXT_DEVICEDATAENTRY), mode);
6677 
6678 			if (rval != 0) {
6679 				cmd->Status = EXT_STATUS_COPY_ERR;
6680 				cmd->ResponseLen = 0;
6681 				EL(ha, "failed, ddi_copyout\n");
6682 				break;
6683 			}
6684 			dd.ReturnListEntryCount++;
6685 			uddep++;
6686 			cmd->ResponseLen += (uint32_t)
6687 			    sizeof (EXT_DEVICEDATAENTRY);
6688 		}
6689 	}
6690 	rval = ddi_copyout((void *)&dd, (void *)uddp,
6691 	    sizeof (EXT_DEVICEDATA) - sizeof (EXT_DEVICEDATAENTRY), mode);
6692 
6693 	if (rval != 0) {
6694 		cmd->Status = EXT_STATUS_COPY_ERR;
6695 		cmd->ResponseLen = 0;
6696 		EL(ha, "failed, ddi_copyout-2\n");
6697 	} else {
6698 		cmd->ResponseLen += (uint32_t)sizeof (EXT_DEVICEDATAENTRY);
6699 		QL_PRINT_9(ha, "done\n");
6700 	}
6701 }
6702 
6703 /*
6704  * ql_get_target_id
6705  *	Performs EXT_SC_GET_TARGET_ID subcommand. of EXT_CC_GET_DATA.
6706  *
6707  * Input:
6708  *	ha:	adapter state pointer.
6709  *	cmd:	Local EXT_IOCTL cmd struct pointer.
6710  *	mode:	flags.
6711  *
6712  * Returns:
6713  *	None, request status indicated in cmd->Status.
6714  *
6715  * Context:
6716  *	Kernel context.
6717  */
6718 static void
ql_get_target_id(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)6719 ql_get_target_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
6720 {
6721 	uint32_t		rval;
6722 	uint16_t		qlnt;
6723 	EXT_DEST_ADDR		extdestaddr = {0};
6724 	uint8_t			*name;
6725 	uint8_t			wwpn[EXT_DEF_WWN_NAME_SIZE];
6726 	ql_tgt_t		*tq;
6727 
6728 	QL_PRINT_9(ha, "started\n");
6729 
6730 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
6731 	    (void*)wwpn, sizeof (EXT_DEST_ADDR), mode) != 0) {
6732 		EL(ha, "failed, ddi_copyin\n");
6733 		cmd->Status = EXT_STATUS_COPY_ERR;
6734 		cmd->ResponseLen = 0;
6735 		return;
6736 	}
6737 
6738 	qlnt = QLNT_PORT;
6739 	name = wwpn;
6740 	QL_PRINT_9(ha, "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
6741 	    ha->instance, name[0], name[1], name[2], name[3], name[4],
6742 	    name[5], name[6], name[7]);
6743 
6744 	tq = ql_find_port(ha, name, qlnt);
6745 	if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id)) {
6746 		EL(ha, "failed, fc_port not found\n");
6747 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
6748 		cmd->ResponseLen = 0;
6749 		return;
6750 	}
6751 
6752 	bcopy(tq->port_name, (caddr_t)&extdestaddr.DestAddr.ScsiAddr.Target, 8);
6753 
6754 	rval = ddi_copyout((void *)&extdestaddr,
6755 	    (void *)(uintptr_t)cmd->ResponseAdr, sizeof (EXT_DEST_ADDR), mode);
6756 	if (rval != 0) {
6757 		EL(ha, "failed, ddi_copyout\n");
6758 		cmd->Status = EXT_STATUS_COPY_ERR;
6759 		cmd->ResponseLen = 0;
6760 	}
6761 
6762 	QL_PRINT_9(ha, "done\n");
6763 }
6764 
6765 /*
6766  * ql_setup_fcache
6767  *	Populates selected flash sections into the cache
6768  *
6769  * Input:
6770  *	ha = adapter state pointer.
6771  *
6772  * Returns:
6773  *	ql local function return status code.
6774  *
6775  * Context:
6776  *	Kernel context.
6777  *
6778  * Note:
6779  *	Driver must be in stalled state prior to entering or
6780  *	add code to this function prior to calling ql_setup_flash()
6781  */
6782 int
ql_setup_fcache(ql_adapter_state_t * ha)6783 ql_setup_fcache(ql_adapter_state_t *ha)
6784 {
6785 	int		rval;
6786 	uint32_t	freadpos = 0;
6787 	uint32_t	fw_done = 0;
6788 	ql_fcache_t	*head = NULL;
6789 	ql_fcache_t	*tail = NULL;
6790 	ql_fcache_t	*ftmp;
6791 
6792 	QL_PRINT_10(ha, "started cfg=0x%llx\n", ha->cfg_flags);
6793 
6794 	/* If we already have populated it, rtn */
6795 	if (ha->fcache != NULL) {
6796 		EL(ha, "buffer already populated\n");
6797 		return (QL_SUCCESS);
6798 	}
6799 
6800 	ql_flash_nvram_defaults(ha);
6801 
6802 	if ((rval = ql_setup_flash(ha)) != QL_SUCCESS) {
6803 		EL(ha, "unable to setup flash; rval=%xh\n", rval);
6804 		return (rval);
6805 	}
6806 
6807 	while (freadpos != 0xffffffff) {
6808 		/* Allocate & populate this node */
6809 		if ((ftmp = ql_setup_fnode(ha)) == NULL) {
6810 			EL(ha, "node alloc failed\n");
6811 			rval = QL_FUNCTION_FAILED;
6812 			break;
6813 		}
6814 
6815 		/* link in the new node */
6816 		if (head == NULL) {
6817 			head = tail = ftmp;
6818 		} else {
6819 			tail->next = ftmp;
6820 			tail = ftmp;
6821 		}
6822 
6823 		/* Do the firmware node first for 24xx/25xx's */
6824 		if (fw_done == 0) {
6825 			if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
6826 				freadpos = ha->flash_fw_addr << 2;
6827 			}
6828 			fw_done = 1;
6829 		}
6830 
6831 		if ((rval = ql_dump_fcode(ha, ftmp->buf, FBUFSIZE,
6832 		    freadpos)) != QL_SUCCESS) {
6833 			EL(ha, "failed, 24xx dump_fcode"
6834 			    " pos=%xh rval=%xh\n", freadpos, rval);
6835 			rval = QL_FUNCTION_FAILED;
6836 			break;
6837 		}
6838 
6839 		/* checkout the pci data / format */
6840 		if (ql_check_pci(ha, ftmp, &freadpos)) {
6841 			EL(ha, "flash header incorrect\n");
6842 			rval = QL_FUNCTION_FAILED;
6843 			break;
6844 		}
6845 	}
6846 
6847 	if (rval != QL_SUCCESS) {
6848 		/* release all resources we have */
6849 		ftmp = head;
6850 		while (ftmp != NULL) {
6851 			tail = ftmp->next;
6852 			kmem_free(ftmp->buf, FBUFSIZE);
6853 			kmem_free(ftmp, sizeof (ql_fcache_t));
6854 			ftmp = tail;
6855 		}
6856 
6857 		EL(ha, "failed, done\n");
6858 	} else {
6859 		ha->fcache = head;
6860 		QL_PRINT_10(ha, "done\n");
6861 	}
6862 
6863 	return (rval);
6864 }
6865 
6866 /*
6867  * ql_update_fcache
6868  *	re-populates updated flash into the fcache. If
6869  *	fcache does not exist (e.g., flash was empty/invalid on
6870  *	boot), this routine will create and the populate it.
6871  *
6872  * Input:
6873  *	ha	= adapter state pointer.
6874  *	*bpf	= Pointer to flash buffer.
6875  *	bsize	= Size of flash buffer.
6876  *
6877  * Returns:
6878  *
6879  * Context:
6880  *	Kernel context.
6881  */
6882 void
ql_update_fcache(ql_adapter_state_t * ha,uint8_t * bfp,uint32_t bsize)6883 ql_update_fcache(ql_adapter_state_t *ha, uint8_t *bfp, uint32_t bsize)
6884 {
6885 	int		rval = QL_SUCCESS;
6886 	uint32_t	freadpos = 0;
6887 	uint32_t	fw_done = 0;
6888 	ql_fcache_t	*head = NULL;
6889 	ql_fcache_t	*tail = NULL;
6890 	ql_fcache_t	*ftmp;
6891 
6892 	QL_PRINT_3(ha, "started\n");
6893 
6894 	while (freadpos != 0xffffffff) {
6895 
6896 		/* Allocate & populate this node */
6897 
6898 		if ((ftmp = ql_setup_fnode(ha)) == NULL) {
6899 			EL(ha, "node alloc failed\n");
6900 			rval = QL_FUNCTION_FAILED;
6901 			break;
6902 		}
6903 
6904 		/* link in the new node */
6905 		if (head == NULL) {
6906 			head = tail = ftmp;
6907 		} else {
6908 			tail->next = ftmp;
6909 			tail = ftmp;
6910 		}
6911 
6912 		/* Do the firmware node first for 24xx's */
6913 		if (fw_done == 0) {
6914 			if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
6915 				freadpos = ha->flash_fw_addr << 2;
6916 			}
6917 			fw_done = 1;
6918 		}
6919 
6920 		/* read in first FBUFSIZE bytes of this flash section */
6921 		if (freadpos + FBUFSIZE > bsize) {
6922 			EL(ha, "passed buffer too small; fr=%xh, bsize=%xh\n",
6923 			    freadpos, bsize);
6924 			rval = QL_FUNCTION_FAILED;
6925 			break;
6926 		}
6927 		bcopy(bfp + freadpos, ftmp->buf, FBUFSIZE);
6928 
6929 		/* checkout the pci data / format */
6930 		if (ql_check_pci(ha, ftmp, &freadpos)) {
6931 			EL(ha, "flash header incorrect\n");
6932 			rval = QL_FUNCTION_FAILED;
6933 			break;
6934 		}
6935 	}
6936 
6937 	if (rval != QL_SUCCESS) {
6938 		/*
6939 		 * release all resources we have
6940 		 */
6941 		ql_fcache_rel(head);
6942 		EL(ha, "failed, done\n");
6943 	} else {
6944 		/*
6945 		 * Release previous fcache resources and update with new
6946 		 */
6947 		ql_fcache_rel(ha->fcache);
6948 		ha->fcache = head;
6949 
6950 		QL_PRINT_3(ha, "done\n");
6951 	}
6952 }
6953 
6954 /*
6955  * ql_setup_fnode
6956  *	Allocates fcache node
6957  *
6958  * Input:
6959  *	ha = adapter state pointer.
6960  *	node = point to allocated fcache node (NULL = failed)
6961  *
6962  * Returns:
6963  *
6964  * Context:
6965  *	Kernel context.
6966  *
6967  * Note:
6968  *	Driver must be in stalled state prior to entering or
6969  *	add code to this function prior to calling ql_setup_flash()
6970  */
6971 static ql_fcache_t *
ql_setup_fnode(ql_adapter_state_t * ha)6972 ql_setup_fnode(ql_adapter_state_t *ha)
6973 {
6974 	ql_fcache_t	*fnode = NULL;
6975 
6976 	if ((fnode = (ql_fcache_t *)(kmem_zalloc(sizeof (ql_fcache_t),
6977 	    KM_SLEEP))) == NULL) {
6978 		EL(ha, "fnode alloc failed\n");
6979 		fnode = NULL;
6980 	} else if ((fnode->buf = (uint8_t *)(kmem_zalloc(FBUFSIZE,
6981 	    KM_SLEEP))) == NULL) {
6982 		EL(ha, "buf alloc failed\n");
6983 		kmem_free(fnode, sizeof (ql_fcache_t));
6984 		fnode = NULL;
6985 	} else {
6986 		fnode->buflen = FBUFSIZE;
6987 	}
6988 
6989 	return (fnode);
6990 }
6991 
6992 /*
6993  * ql_fcache_rel
6994  *	Releases the fcache resources
6995  *
6996  * Input:
6997  *	ha	= adapter state pointer.
6998  *	head	= Pointer to fcache linked list
6999  *
7000  * Returns:
7001  *
7002  * Context:
7003  *	Kernel context.
7004  *
7005  */
7006 void
ql_fcache_rel(ql_fcache_t * head)7007 ql_fcache_rel(ql_fcache_t *head)
7008 {
7009 	ql_fcache_t	*ftmp = head;
7010 	ql_fcache_t	*tail;
7011 
7012 	/* release all resources we have */
7013 	while (ftmp != NULL) {
7014 		tail = ftmp->next;
7015 		kmem_free(ftmp->buf, FBUFSIZE);
7016 		kmem_free(ftmp, sizeof (ql_fcache_t));
7017 		ftmp = tail;
7018 	}
7019 }
7020 
7021 /*
7022  * ql_update_flash_caches
7023  *	Updates driver flash caches
7024  *
7025  * Input:
7026  *	ha:	adapter state pointer.
7027  *
7028  * Context:
7029  *	Kernel context.
7030  */
7031 static void
ql_update_flash_caches(ql_adapter_state_t * ha)7032 ql_update_flash_caches(ql_adapter_state_t *ha)
7033 {
7034 	uint32_t		len;
7035 	ql_link_t		*link;
7036 	ql_adapter_state_t	*ha2;
7037 
7038 	QL_PRINT_3(ha, "started\n");
7039 
7040 	/* Get base path length. */
7041 	for (len = (uint32_t)strlen(ha->devpath); len; len--) {
7042 		if (ha->devpath[len] == ',' ||
7043 		    ha->devpath[len] == '@') {
7044 			break;
7045 		}
7046 	}
7047 
7048 	/* Reset fcache on all adapter instances. */
7049 	for (link = ql_hba.first; link != NULL; link = link->next) {
7050 		ha2 = link->base_address;
7051 
7052 		if (strncmp(ha->devpath, ha2->devpath, len) != 0) {
7053 			continue;
7054 		}
7055 
7056 		ql_fcache_rel(ha2->fcache);
7057 		ha2->fcache = NULL;
7058 
7059 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
7060 			if (ha2->vcache != NULL) {
7061 				kmem_free(ha2->vcache, QL_24XX_VPD_SIZE);
7062 				ha2->vcache = NULL;
7063 			}
7064 		}
7065 
7066 		(void) ql_setup_fcache(ha2);
7067 	}
7068 
7069 	QL_PRINT_3(ha, "done\n");
7070 }
7071 
7072 /*
7073  * ql_get_fbuf
7074  *	Search the fcache list for the type specified
7075  *
7076  * Input:
7077  *	fptr	= Pointer to fcache linked list
7078  *	ftype	= Type of image to be returned.
7079  *
7080  * Returns:
7081  *	Pointer to ql_fcache_t.
7082  *	NULL means not found.
7083  *
7084  * Context:
7085  *	Kernel context.
7086  *
7087  *
7088  */
7089 ql_fcache_t *
ql_get_fbuf(ql_fcache_t * fptr,uint32_t ftype)7090 ql_get_fbuf(ql_fcache_t *fptr, uint32_t ftype)
7091 {
7092 	while (fptr != NULL) {
7093 		/* does this image meet criteria? */
7094 		if (ftype & fptr->type) {
7095 			break;
7096 		}
7097 		fptr = fptr->next;
7098 	}
7099 	return (fptr);
7100 }
7101 
7102 /*
7103  * ql_check_pci
7104  *
7105  *	checks the passed buffer for a valid pci signature and
7106  *	expected (and in range) pci length values.
7107  *
7108  *	For firmware type, a pci header is added since the image in
7109  *	the flash does not have one (!!!).
7110  *
7111  *	On successful pci check, nextpos adjusted to next pci header.
7112  *
7113  * Returns:
7114  *	-1 --> last pci image
7115  *	0 --> pci header valid
7116  *	1 --> pci header invalid.
7117  *
7118  * Context:
7119  *	Kernel context.
7120  */
7121 static int
ql_check_pci(ql_adapter_state_t * ha,ql_fcache_t * fcache,uint32_t * nextpos)7122 ql_check_pci(ql_adapter_state_t *ha, ql_fcache_t *fcache, uint32_t *nextpos)
7123 {
7124 	pci_header_t	*pcih;
7125 	pci_data_t	*pcid;
7126 	uint32_t	doff;
7127 	uint8_t		*pciinfo;
7128 
7129 	QL_PRINT_3(ha, "started\n");
7130 
7131 	if (fcache != NULL) {
7132 		pciinfo = fcache->buf;
7133 	} else {
7134 		EL(ha, "failed, null fcache ptr passed\n");
7135 		return (1);
7136 	}
7137 
7138 	if (pciinfo == NULL) {
7139 		EL(ha, "failed, null pciinfo ptr passed\n");
7140 		return (1);
7141 	}
7142 
7143 	if (CFG_IST(ha, CFG_SBUS_CARD)) {
7144 		caddr_t	bufp;
7145 		uint_t	len;
7146 
7147 		if (pciinfo[0] != SBUS_CODE_FCODE) {
7148 			EL(ha, "failed, unable to detect sbus fcode\n");
7149 			return (1);
7150 		}
7151 		fcache->type = FTYPE_FCODE;
7152 
7153 		/*LINTED [Solaris DDI_DEV_T_ANY Lint error]*/
7154 		if (ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
7155 		    PROP_LEN_AND_VAL_ALLOC | DDI_PROP_DONTPASS |
7156 		    DDI_PROP_CANSLEEP, "version", (caddr_t)&bufp,
7157 		    (int *)&len) == DDI_PROP_SUCCESS) {
7158 
7159 			(void) snprintf(fcache->verstr,
7160 			    FCHBA_OPTION_ROM_VERSION_LEN, "%s", bufp);
7161 			kmem_free(bufp, len);
7162 		}
7163 
7164 		*nextpos = 0xffffffff;
7165 
7166 		QL_PRINT_3(ha, "CFG_SBUS_CARD, done\n");
7167 
7168 		return (0);
7169 	}
7170 
7171 	if (*nextpos == ha->flash_fw_addr << 2) {
7172 
7173 		pci_header_t	fwh = {0};
7174 		pci_data_t	fwd = {0};
7175 		uint8_t		*buf, *bufp;
7176 
7177 		/*
7178 		 * Build a pci header for the firmware module
7179 		 */
7180 		if ((buf = (uint8_t *)(kmem_zalloc(FBUFSIZE, KM_SLEEP))) ==
7181 		    NULL) {
7182 			EL(ha, "failed, unable to allocate buffer\n");
7183 			return (1);
7184 		}
7185 
7186 		fwh.signature[0] = PCI_HEADER0;
7187 		fwh.signature[1] = PCI_HEADER1;
7188 		fwh.dataoffset[0] = LSB(sizeof (pci_header_t));
7189 		fwh.dataoffset[1] = MSB(sizeof (pci_header_t));
7190 
7191 		fwd.signature[0] = 'P';
7192 		fwd.signature[1] = 'C';
7193 		fwd.signature[2] = 'I';
7194 		fwd.signature[3] = 'R';
7195 		fwd.codetype = PCI_CODE_FW;
7196 		fwd.pcidatalen[0] = LSB(sizeof (pci_data_t));
7197 		fwd.pcidatalen[1] = MSB(sizeof (pci_data_t));
7198 
7199 		bufp = buf;
7200 		bcopy(&fwh, bufp, sizeof (pci_header_t));
7201 		bufp += sizeof (pci_header_t);
7202 		bcopy(&fwd, bufp, sizeof (pci_data_t));
7203 		bufp += sizeof (pci_data_t);
7204 
7205 		bcopy(fcache->buf, bufp, (FBUFSIZE - sizeof (pci_header_t) -
7206 		    sizeof (pci_data_t)));
7207 		bcopy(buf, fcache->buf, FBUFSIZE);
7208 
7209 		fcache->type = FTYPE_FW;
7210 
7211 		(void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN,
7212 		    "%d.%02d.%02d", fcache->buf[19], fcache->buf[23],
7213 		    fcache->buf[27]);
7214 
7215 		*nextpos = ha->boot_code_addr << 2;
7216 		kmem_free(buf, FBUFSIZE);
7217 
7218 		QL_PRINT_3(ha, "FTYPE_FW, done\n");
7219 
7220 		return (0);
7221 	}
7222 
7223 	/* get to the pci header image length */
7224 	pcih = (pci_header_t *)pciinfo;
7225 
7226 	doff = pcih->dataoffset[0] | (pcih->dataoffset[1] << 8);
7227 
7228 	/* some header section sanity check */
7229 	if (pcih->signature[0] != PCI_HEADER0 ||
7230 	    pcih->signature[1] != PCI_HEADER1 || doff > 50) {
7231 		EL(ha, "buffer format error: s0=%xh, s1=%xh, off=%xh\n",
7232 		    pcih->signature[0], pcih->signature[1], doff);
7233 		return (1);
7234 	}
7235 
7236 	pcid = (pci_data_t *)(pciinfo + doff);
7237 
7238 	/* a slight sanity data section check */
7239 	if (pcid->signature[0] != 'P' || pcid->signature[1] != 'C' ||
7240 	    pcid->signature[2] != 'I' || pcid->signature[3] != 'R') {
7241 		EL(ha, "failed, data sig mismatch!\n");
7242 		return (1);
7243 	}
7244 
7245 	if (pcid->indicator == PCI_IND_LAST_IMAGE) {
7246 		QL_PRINT_3(ha, "last image\n");
7247 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
7248 			ql_flash_layout_table(ha, *nextpos +
7249 			    (pcid->imagelength[0] | (pcid->imagelength[1] <<
7250 			    8)) * PCI_SECTOR_SIZE);
7251 			(void) ql_24xx_flash_desc(ha);
7252 		}
7253 		*nextpos = 0xffffffff;
7254 	} else {
7255 		/* adjust the next flash read start position */
7256 		*nextpos += (pcid->imagelength[0] |
7257 		    (pcid->imagelength[1] << 8)) * PCI_SECTOR_SIZE;
7258 	}
7259 
7260 	switch (pcid->codetype) {
7261 	case PCI_CODE_X86PC:
7262 		fcache->type = FTYPE_BIOS;
7263 		break;
7264 	case PCI_CODE_FCODE:
7265 		fcache->type = FTYPE_FCODE;
7266 		break;
7267 	case PCI_CODE_EFI:
7268 		fcache->type = FTYPE_EFI;
7269 		break;
7270 	case PCI_CODE_HPPA:
7271 		fcache->type = FTYPE_HPPA;
7272 		break;
7273 	default:
7274 		fcache->type = FTYPE_UNKNOWN;
7275 		break;
7276 	}
7277 
7278 	(void) snprintf(fcache->verstr, FCHBA_OPTION_ROM_VERSION_LEN,
7279 	    "%d.%02d", pcid->revisionlevel[1], pcid->revisionlevel[0]);
7280 
7281 	QL_PRINT_3(ha, "done\n");
7282 
7283 	return (0);
7284 }
7285 
7286 /*
7287  * ql_flash_layout_table
7288  *	Obtains flash addresses from table
7289  *
7290  * Input:
7291  *	ha:		adapter state pointer.
7292  *	flt_paddr:	flash layout pointer address.
7293  *
7294  * Context:
7295  *	Kernel context.
7296  */
7297 static void
ql_flash_layout_table(ql_adapter_state_t * ha,uint32_t flt_paddr)7298 ql_flash_layout_table(ql_adapter_state_t *ha, uint32_t flt_paddr)
7299 {
7300 	ql_flt_ptr_t	*fptr;
7301 	uint8_t		*bp;
7302 	int		rval;
7303 	uint32_t	len, faddr, cnt;
7304 	uint16_t	chksum, w16;
7305 
7306 	QL_PRINT_9(ha, "started\n");
7307 
7308 	/* Process flash layout table header */
7309 	len = sizeof (ql_flt_ptr_t);
7310 	if ((bp = kmem_zalloc(len, KM_SLEEP)) == NULL) {
7311 		EL(ha, "kmem_zalloc=null\n");
7312 		return;
7313 	}
7314 
7315 	/* Process pointer to flash layout table */
7316 	if ((rval = ql_dump_fcode(ha, bp, len, flt_paddr)) != QL_SUCCESS) {
7317 		EL(ha, "fptr dump_flash pos=%xh, status=%xh\n", flt_paddr,
7318 		    rval);
7319 		kmem_free(bp, len);
7320 		return;
7321 	}
7322 	fptr = (ql_flt_ptr_t *)bp;
7323 
7324 	/* Verify pointer to flash layout table. */
7325 	for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7326 		w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]);
7327 		chksum += w16;
7328 	}
7329 	if (chksum != 0 || fptr->sig[0] != 'Q' || fptr->sig[1] != 'F' ||
7330 	    fptr->sig[2] != 'L' || fptr->sig[3] != 'T') {
7331 		EL(ha, "ptr chksum=%xh, sig=%c%c%c%c \n",
7332 		    chksum, fptr->sig[0],
7333 		    fptr->sig[1], fptr->sig[2], fptr->sig[3]);
7334 		kmem_free(bp, len);
7335 		return;
7336 	}
7337 	faddr = CHAR_TO_LONG(fptr->addr[0], fptr->addr[1], fptr->addr[2],
7338 	    fptr->addr[3]);
7339 
7340 	kmem_free(bp, len);
7341 
7342 	ql_process_flt(ha, faddr);
7343 
7344 	QL_PRINT_9(ha, "done\n");
7345 }
7346 
7347 /*
7348  * ql_process_flt
7349  *	Obtains flash addresses from flash layout table
7350  *
7351  * Input:
7352  *	ha:	adapter state pointer.
7353  *	faddr:	flash layout table byte address.
7354  *
7355  * Context:
7356  *	Kernel context.
7357  */
7358 static void
ql_process_flt(ql_adapter_state_t * ha,uint32_t faddr)7359 ql_process_flt(ql_adapter_state_t *ha, uint32_t faddr)
7360 {
7361 	ql_flt_hdr_t	*fhdr;
7362 	ql_flt_region_t	*frgn;
7363 	uint8_t		*bp, *eaddr, nv_rg, vpd_rg;
7364 	int		rval;
7365 	uint32_t	len, cnt, fe_addr;
7366 	uint16_t	chksum, w16;
7367 
7368 	QL_PRINT_9(ha, "started faddr=%xh\n", faddr);
7369 
7370 	/* Process flash layout table header */
7371 	if ((bp = kmem_zalloc(FLASH_LAYOUT_TABLE_SIZE, KM_SLEEP)) == NULL) {
7372 		EL(ha, "kmem_zalloc=null\n");
7373 		return;
7374 	}
7375 	fhdr = (ql_flt_hdr_t *)bp;
7376 
7377 	/* Process flash layout table. */
7378 	if ((rval = ql_dump_fcode(ha, bp, FLASH_LAYOUT_TABLE_SIZE, faddr)) !=
7379 	    QL_SUCCESS) {
7380 		EL(ha, "fhdr dump_flash pos=%xh, status=%xh\n", faddr, rval);
7381 		kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7382 		return;
7383 	}
7384 
7385 	/* Verify flash layout table. */
7386 	len = (uint32_t)(CHAR_TO_SHORT(fhdr->len[0], fhdr->len[1]) +
7387 	    sizeof (ql_flt_hdr_t) + sizeof (ql_flt_region_t));
7388 	if (len > FLASH_LAYOUT_TABLE_SIZE) {
7389 		chksum = 0xffff;
7390 	} else {
7391 		for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7392 			w16 = (uint16_t)CHAR_TO_SHORT(bp[cnt], bp[cnt + 1]);
7393 			chksum += w16;
7394 		}
7395 	}
7396 	w16 = CHAR_TO_SHORT(fhdr->version[0], fhdr->version[1]);
7397 	if (chksum != 0 || w16 != 1) {
7398 		EL(ha, "table chksum=%xh, version=%d\n", chksum, w16);
7399 		kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7400 		return;
7401 	}
7402 	eaddr = bp + len;
7403 
7404 	/* Process Function/Port Configuration Map. */
7405 	nv_rg = vpd_rg = 0;
7406 	if (CFG_IST(ha, CFG_CTRL_82XX)) {
7407 		uint16_t	i;
7408 		uint8_t		*mbp = eaddr;
7409 		ql_fp_cfg_map_t	*cmp = (ql_fp_cfg_map_t *)mbp;
7410 
7411 		len = (uint32_t)(CHAR_TO_SHORT(cmp->hdr.len[0],
7412 		    cmp->hdr.len[1]));
7413 		if (len > FLASH_LAYOUT_TABLE_SIZE) {
7414 			chksum = 0xffff;
7415 		} else {
7416 			for (chksum = 0, cnt = 0; cnt < len; cnt += 2) {
7417 				w16 = (uint16_t)CHAR_TO_SHORT(mbp[cnt],
7418 				    mbp[cnt + 1]);
7419 				chksum += w16;
7420 			}
7421 		}
7422 		w16 = CHAR_TO_SHORT(cmp->hdr.version[0], cmp->hdr.version[1]);
7423 		if (chksum != 0 || w16 != 1 ||
7424 		    cmp->hdr.Signature[0] != 'F' ||
7425 		    cmp->hdr.Signature[1] != 'P' ||
7426 		    cmp->hdr.Signature[2] != 'C' ||
7427 		    cmp->hdr.Signature[3] != 'M') {
7428 			EL(ha, "cfg_map chksum=%xh, version=%d, "
7429 			    "sig=%c%c%c%c \n", chksum, w16,
7430 			    cmp->hdr.Signature[0], cmp->hdr.Signature[1],
7431 			    cmp->hdr.Signature[2], cmp->hdr.Signature[3]);
7432 		} else {
7433 			cnt = (uint16_t)
7434 			    (CHAR_TO_SHORT(cmp->hdr.NumberEntries[0],
7435 			    cmp->hdr.NumberEntries[1]));
7436 			/* Locate entry for function. */
7437 			for (i = 0; i < cnt; i++) {
7438 				if (cmp->cfg[i].FunctionType == FT_FC &&
7439 				    cmp->cfg[i].FunctionNumber[0] ==
7440 				    ha->pci_function_number &&
7441 				    cmp->cfg[i].FunctionNumber[1] == 0) {
7442 					nv_rg = cmp->cfg[i].ConfigRegion;
7443 					vpd_rg = cmp->cfg[i].VpdRegion;
7444 					break;
7445 				}
7446 			}
7447 
7448 			if (nv_rg == 0 || vpd_rg == 0) {
7449 				EL(ha, "cfg_map nv_rg=%d, vpd_rg=%d\n", nv_rg,
7450 				    vpd_rg);
7451 				nv_rg = vpd_rg = 0;
7452 			}
7453 		}
7454 	}
7455 
7456 	/* Process flash layout table regions */
7457 	for (frgn = (ql_flt_region_t *)(bp + sizeof (ql_flt_hdr_t));
7458 	    (uint8_t *)frgn < eaddr; frgn++) {
7459 		faddr = CHAR_TO_LONG(frgn->beg_addr[0], frgn->beg_addr[1],
7460 		    frgn->beg_addr[2], frgn->beg_addr[3]);
7461 		faddr >>= 2;
7462 		fe_addr = CHAR_TO_LONG(frgn->end_addr[0], frgn->end_addr[1],
7463 		    frgn->end_addr[2], frgn->end_addr[3]);
7464 		fe_addr >>= 2;
7465 
7466 		switch (frgn->region) {
7467 		case FLASH_8021_BOOTLOADER_REGION:
7468 			ha->bootloader_addr = faddr;
7469 			ha->bootloader_size = (fe_addr - faddr) + 1;
7470 			QL_PRINT_9(ha, "bootloader_addr=%xh, "
7471 			    "size=%xh\n", faddr,
7472 			    ha->bootloader_size);
7473 			break;
7474 		case FLASH_FW_REGION:
7475 		case FLASH_8021_FW_REGION:
7476 			ha->flash_fw_addr = faddr;
7477 			ha->flash_fw_size = (fe_addr - faddr) + 1;
7478 			QL_PRINT_9(ha, "flash_fw_addr=%xh, "
7479 			    "size=%xh\n", faddr,
7480 			    ha->flash_fw_size);
7481 			break;
7482 		case FLASH_GOLDEN_FW_REGION:
7483 		case FLASH_8021_GOLDEN_FW_REGION:
7484 			ha->flash_golden_fw_addr = faddr;
7485 			QL_PRINT_9(ha, "flash_golden_fw_addr=%xh\n",
7486 			    ha->instance, faddr);
7487 			break;
7488 		case FLASH_8021_VPD_REGION:
7489 			if (!vpd_rg || vpd_rg == FLASH_8021_VPD_REGION) {
7490 				ha->flash_vpd_addr = faddr;
7491 				QL_PRINT_9(ha, "8021_flash_vpd_"
7492 				    "addr=%xh\n", faddr);
7493 			}
7494 			break;
7495 		case FLASH_VPD_0_REGION:
7496 			if (vpd_rg) {
7497 				if (vpd_rg == FLASH_VPD_0_REGION) {
7498 					ha->flash_vpd_addr = faddr;
7499 					QL_PRINT_9(ha, "vpd_rg  "
7500 					    "flash_vpd_addr=%xh\n",
7501 					    ha->instance, faddr);
7502 				}
7503 			} else if (ha->function_number == 0 &&
7504 			    !(CFG_IST(ha, CFG_CTRL_82XX))) {
7505 				ha->flash_vpd_addr = faddr;
7506 				QL_PRINT_9(ha, "flash_vpd_addr=%xh"
7507 				    "\n", faddr);
7508 			}
7509 			break;
7510 		case FLASH_NVRAM_0_REGION:
7511 			if (nv_rg) {
7512 				if (nv_rg == FLASH_NVRAM_0_REGION) {
7513 					ADAPTER_STATE_LOCK(ha);
7514 					ha->function_number = 0;
7515 					ADAPTER_STATE_UNLOCK(ha);
7516 					ha->flash_nvram_addr = faddr;
7517 					QL_PRINT_9(ha, "nv_rg "
7518 					    "flash_nvram_addr=%xh\n",
7519 					    ha->instance, faddr);
7520 				}
7521 			} else if (ha->function_number == 0) {
7522 				ha->flash_nvram_addr = faddr;
7523 				QL_PRINT_9(ha, "flash_nvram_addr="
7524 				    "%xh\n", faddr);
7525 			}
7526 			break;
7527 		case FLASH_VPD_1_REGION:
7528 			if (vpd_rg) {
7529 				if (vpd_rg == FLASH_VPD_1_REGION) {
7530 					ha->flash_vpd_addr = faddr;
7531 					QL_PRINT_9(ha, "vpd_rg "
7532 					    "flash_vpd_addr=%xh\n",
7533 					    ha->instance, faddr);
7534 				}
7535 			} else if (ha->function_number &&
7536 			    !(CFG_IST(ha, CFG_CTRL_82XX))) {
7537 				ha->flash_vpd_addr = faddr;
7538 				QL_PRINT_9(ha, "flash_vpd_addr=%xh"
7539 				    "\n", faddr);
7540 			}
7541 			break;
7542 		case FLASH_NVRAM_1_REGION:
7543 			if (nv_rg) {
7544 				if (nv_rg == FLASH_NVRAM_1_REGION) {
7545 					ADAPTER_STATE_LOCK(ha);
7546 					ha->function_number = 1;
7547 					ADAPTER_STATE_UNLOCK(ha);
7548 					ha->flash_nvram_addr = faddr;
7549 					QL_PRINT_9(ha, "nv_rg "
7550 					    "flash_nvram_addr=%xh\n",
7551 					    ha->instance, faddr);
7552 				}
7553 			} else if (ha->function_number) {
7554 				ha->flash_nvram_addr = faddr;
7555 				QL_PRINT_9(ha, "flash_nvram_addr="
7556 				    "%xh\n", faddr);
7557 			}
7558 			break;
7559 		case FLASH_DESC_TABLE_REGION:
7560 			if (!(CFG_IST(ha, CFG_CTRL_82XX))) {
7561 				ha->flash_desc_addr = faddr;
7562 				QL_PRINT_9(ha, "flash_desc_addr="
7563 				    "%xh\n", faddr);
7564 			}
7565 			break;
7566 		case FLASH_ERROR_LOG_0_REGION:
7567 			if (ha->function_number == 0) {
7568 				ha->flash_errlog_start = faddr;
7569 				QL_PRINT_9(ha, "flash_errlog_addr="
7570 				    "%xh\n", faddr);
7571 			}
7572 			break;
7573 		case FLASH_ERROR_LOG_1_REGION:
7574 			if (ha->function_number) {
7575 				ha->flash_errlog_start = faddr;
7576 				QL_PRINT_9(ha, "flash_errlog_addr="
7577 				    "%xh\n", faddr);
7578 			}
7579 			break;
7580 		default:
7581 			break;
7582 		}
7583 	}
7584 	kmem_free(bp, FLASH_LAYOUT_TABLE_SIZE);
7585 
7586 	QL_PRINT_9(ha, "done\n");
7587 }
7588 
7589 /*
7590  * ql_flash_nvram_defaults
7591  *	Flash default addresses.
7592  *
7593  * Input:
7594  *	ha:		adapter state pointer.
7595  *
7596  * Returns:
7597  *	ql local function return status code.
7598  *
7599  * Context:
7600  *	Kernel context.
7601  */
7602 static void
ql_flash_nvram_defaults(ql_adapter_state_t * ha)7603 ql_flash_nvram_defaults(ql_adapter_state_t *ha)
7604 {
7605 	QL_PRINT_10(ha, "started\n");
7606 
7607 	if (ha->function_number == 3) {
7608 		if (CFG_IST(ha, CFG_CTRL_27XX)) {
7609 			ha->flash_nvram_addr = NVRAM_2700_FUNC3_ADDR;
7610 			ha->flash_vpd_addr = VPD_2700_FUNC3_ADDR;
7611 			ha->ledstate.select = BEACON_2700_FUNC3_ADDR;
7612 			ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7613 			ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7614 			ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7615 			ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7616 			ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7617 		} else {
7618 			EL(ha, "unassigned flash fn%d addr: %x\n",
7619 			    ha->function_number, ha->device_id);
7620 		}
7621 	} else if (ha->function_number == 2) {
7622 		if (CFG_IST(ha, CFG_CTRL_27XX)) {
7623 			ha->flash_nvram_addr = NVRAM_2700_FUNC2_ADDR;
7624 			ha->flash_vpd_addr = VPD_2700_FUNC2_ADDR;
7625 			ha->ledstate.select = BEACON_2700_FUNC2_ADDR;
7626 			ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7627 			ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7628 			ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7629 			ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7630 			ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7631 		} else {
7632 			EL(ha, "unassigned flash fn%d addr: %x\n",
7633 			    ha->function_number, ha->device_id);
7634 		}
7635 	} else if (ha->function_number == 1) {
7636 		if (CFG_IST(ha, CFG_CTRL_23XX) ||
7637 		    (CFG_IST(ha, CFG_CTRL_63XX))) {
7638 			ha->flash_nvram_addr = NVRAM_2300_FUNC1_ADDR;
7639 			ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR;
7640 			ha->boot_code_addr = FLASH_2300_BOOT_CODE_ADDR;
7641 		} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
7642 			ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7643 			ha->flash_nvram_addr = NVRAM_2400_FUNC1_ADDR;
7644 			ha->flash_vpd_addr = VPD_2400_FUNC1_ADDR;
7645 			ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_1;
7646 			ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE;
7647 			ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR;
7648 			ha->boot_code_addr = FLASH_2400_BOOT_CODE_ADDR;
7649 		} else if (CFG_IST(ha, CFG_CTRL_25XX)) {
7650 			ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7651 			ha->flash_nvram_addr = NVRAM_2500_FUNC1_ADDR;
7652 			ha->flash_vpd_addr = VPD_2500_FUNC1_ADDR;
7653 			ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_1;
7654 			ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE;
7655 			ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR;
7656 			ha->boot_code_addr = FLASH_2500_BOOT_CODE_ADDR;
7657 		} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
7658 			ha->flash_data_addr = FLASH_8100_DATA_ADDR;
7659 			ha->flash_nvram_addr = NVRAM_8100_FUNC1_ADDR;
7660 			ha->flash_vpd_addr = VPD_8100_FUNC1_ADDR;
7661 			ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_1;
7662 			ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE;
7663 			ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR;
7664 			ha->boot_code_addr = FLASH_8100_BOOT_CODE_ADDR;
7665 		} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
7666 			ha->flash_data_addr = 0;
7667 			ha->flash_nvram_addr = NVRAM_8021_FUNC1_ADDR;
7668 			ha->flash_vpd_addr = VPD_8021_FUNC1_ADDR;
7669 			ha->flash_errlog_start = 0;
7670 			ha->flash_desc_addr = FLASH_8021_DESCRIPTOR_TABLE;
7671 			ha->flash_fw_addr = FLASH_8021_FIRMWARE_ADDR;
7672 			ha->flash_fw_size = FLASH_8021_FIRMWARE_SIZE;
7673 			ha->bootloader_addr = FLASH_8021_BOOTLOADER_ADDR;
7674 			ha->bootloader_size = FLASH_8021_BOOTLOADER_SIZE;
7675 			ha->boot_code_addr = FLASH_8021_BOOT_CODE_ADDR;
7676 		} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
7677 			ha->flash_nvram_addr = NVRAM_8300_FC_FUNC1_ADDR;
7678 			ha->flash_vpd_addr = VPD_8300_FC_FUNC1_ADDR;
7679 			ha->ledstate.select = BEACON_8300_FC_FUNC1_ADDR;
7680 			ha->flash_errlog_start = FLASH_8300_ERRLOG_START_ADDR_1;
7681 			ha->flash_data_addr = FLASH_8300_DATA_ADDR;
7682 			ha->flash_desc_addr = FLASH_8300_DESCRIPTOR_TABLE;
7683 			ha->flash_fw_addr = FLASH_8300_FC_FIRMWARE_ADDR;
7684 			ha->flash_fw_size = FLASH_8300_FIRMWARE_SIZE;
7685 			ha->bootloader_addr = FLASH_8300_BOOTLOADER_ADDR;
7686 			ha->bootloader_size = FLASH_8300_BOOTLOADER_SIZE;
7687 			ha->boot_code_addr = FLASH_8300_BOOT_CODE_ADDR;
7688 		} else if (CFG_IST(ha, CFG_CTRL_27XX)) {
7689 			ha->flash_nvram_addr = NVRAM_2700_FUNC1_ADDR;
7690 			ha->flash_vpd_addr = VPD_2700_FUNC1_ADDR;
7691 			ha->ledstate.select = BEACON_2700_FUNC1_ADDR;
7692 			ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7693 			ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7694 			ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7695 			ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7696 			ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7697 		} else {
7698 			EL(ha, "unassigned flash fn%d addr: %x\n",
7699 			    ha->function_number, ha->device_id);
7700 		}
7701 	} else if (ha->function_number == 0) {
7702 		if (CFG_IST(ha, CFG_CTRL_22XX)) {
7703 			ha->flash_nvram_addr = NVRAM_2200_FUNC0_ADDR;
7704 			ha->flash_fw_addr = FLASH_2200_FIRMWARE_ADDR;
7705 			ha->boot_code_addr = FLASH_2200_BOOT_CODE_ADDR;
7706 		} else if (CFG_IST(ha, CFG_CTRL_23XX) ||
7707 		    (CFG_IST(ha, CFG_CTRL_63XX))) {
7708 			ha->flash_nvram_addr = NVRAM_2300_FUNC0_ADDR;
7709 			ha->flash_fw_addr = FLASH_2300_FIRMWARE_ADDR;
7710 			ha->boot_code_addr = FLASH_2300_BOOT_CODE_ADDR;
7711 		} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
7712 			ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7713 			ha->flash_nvram_addr = NVRAM_2400_FUNC0_ADDR;
7714 			ha->flash_vpd_addr = VPD_2400_FUNC0_ADDR;
7715 			ha->flash_errlog_start = FLASH_2400_ERRLOG_START_ADDR_0;
7716 			ha->flash_desc_addr = FLASH_2400_DESCRIPTOR_TABLE;
7717 			ha->flash_fw_addr = FLASH_2400_FIRMWARE_ADDR;
7718 			ha->boot_code_addr = FLASH_2400_BOOT_CODE_ADDR;
7719 		} else if (CFG_IST(ha, CFG_CTRL_25XX)) {
7720 			ha->flash_data_addr = FLASH_24_25_DATA_ADDR;
7721 			ha->flash_nvram_addr = NVRAM_2500_FUNC0_ADDR;
7722 			ha->flash_vpd_addr = VPD_2500_FUNC0_ADDR;
7723 			ha->flash_errlog_start = FLASH_2500_ERRLOG_START_ADDR_0;
7724 			ha->flash_desc_addr = FLASH_2500_DESCRIPTOR_TABLE;
7725 			ha->flash_fw_addr = FLASH_2500_FIRMWARE_ADDR;
7726 			ha->boot_code_addr = FLASH_2500_BOOT_CODE_ADDR;
7727 		} else if (CFG_IST(ha, CFG_CTRL_81XX)) {
7728 			ha->flash_data_addr = FLASH_8100_DATA_ADDR;
7729 			ha->flash_nvram_addr = NVRAM_8100_FUNC0_ADDR;
7730 			ha->flash_vpd_addr = VPD_8100_FUNC0_ADDR;
7731 			ha->flash_errlog_start = FLASH_8100_ERRLOG_START_ADDR_0;
7732 			ha->flash_desc_addr = FLASH_8100_DESCRIPTOR_TABLE;
7733 			ha->flash_fw_addr = FLASH_8100_FIRMWARE_ADDR;
7734 			ha->boot_code_addr = FLASH_8100_BOOT_CODE_ADDR;
7735 		} else if (CFG_IST(ha, CFG_CTRL_82XX)) {
7736 			ha->flash_data_addr = 0;
7737 			ha->flash_nvram_addr = NVRAM_8021_FUNC0_ADDR;
7738 			ha->flash_vpd_addr = VPD_8021_FUNC0_ADDR;
7739 			ha->flash_errlog_start = 0;
7740 			ha->flash_desc_addr = FLASH_8021_DESCRIPTOR_TABLE;
7741 			ha->flash_fw_addr = FLASH_8021_FIRMWARE_ADDR;
7742 			ha->flash_fw_size = FLASH_8021_FIRMWARE_SIZE;
7743 			ha->bootloader_addr = FLASH_8021_BOOTLOADER_ADDR;
7744 			ha->bootloader_size = FLASH_8021_BOOTLOADER_SIZE;
7745 			ha->boot_code_addr = FLASH_8021_BOOT_CODE_ADDR;
7746 		} else if (CFG_IST(ha, CFG_CTRL_83XX)) {
7747 			ha->flash_nvram_addr = NVRAM_8300_FC_FUNC0_ADDR;
7748 			ha->flash_vpd_addr = VPD_8300_FC_FUNC0_ADDR;
7749 			ha->ledstate.select = BEACON_8300_FCOE_FUNC0_ADDR;
7750 			ha->flash_errlog_start = FLASH_8300_ERRLOG_START_ADDR_0;
7751 			ha->flash_data_addr = FLASH_8300_DATA_ADDR;
7752 			ha->flash_desc_addr = FLASH_8300_DESCRIPTOR_TABLE;
7753 			ha->flash_fw_addr = FLASH_8300_FC_FIRMWARE_ADDR;
7754 			ha->flash_fw_size = FLASH_8300_FIRMWARE_SIZE;
7755 			ha->bootloader_addr = FLASH_8300_BOOTLOADER_ADDR;
7756 			ha->bootloader_size = FLASH_8300_BOOTLOADER_SIZE;
7757 			ha->boot_code_addr = FLASH_8300_BOOT_CODE_ADDR;
7758 		} else if (CFG_IST(ha, CFG_CTRL_27XX)) {
7759 			ha->flash_nvram_addr = NVRAM_2700_FUNC0_ADDR;
7760 			ha->flash_vpd_addr = VPD_2700_FUNC0_ADDR;
7761 			ha->ledstate.select = BEACON_2700_FUNC0_ADDR;
7762 			ha->flash_data_addr = FLASH_2700_DATA_ADDR;
7763 			ha->flash_desc_addr = FLASH_2700_DESCRIPTOR_TABLE;
7764 			ha->flash_fw_addr = FLASH_2700_FIRMWARE_ADDR;
7765 			ha->flash_fw_size = FLASH_2700_FIRMWARE_SIZE;
7766 			ha->boot_code_addr = FLASH_2700_BOOT_CODE_ADDR;
7767 		} else {
7768 			EL(ha, "unassigned flash fn%d addr: %x\n",
7769 			    ha->function_number, ha->device_id);
7770 		}
7771 	} else {
7772 		EL(ha, "known function=%d, device_id=%x\n",
7773 		    ha->function_number, ha->device_id);
7774 	}
7775 	QL_PRINT_10(ha, "done\n");
7776 }
7777 
7778 /*
7779  * ql_get_sfp
7780  *	Returns sfp data to sdmapi caller
7781  *
7782  * Input:
7783  *	ha:	adapter state pointer.
7784  *	cmd:	Local EXT_IOCTL cmd struct pointer.
7785  *	mode:	flags.
7786  *
7787  * Returns:
7788  *	None, request status indicated in cmd->Status.
7789  *
7790  * Context:
7791  *	Kernel context.
7792  */
7793 static void
ql_get_sfp(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7794 ql_get_sfp(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7795 {
7796 	QL_PRINT_9(ha, "started\n");
7797 
7798 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
7799 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
7800 		EL(ha, "failed, invalid request for HBA\n");
7801 		return;
7802 	}
7803 
7804 	if (cmd->ResponseLen < QL_24XX_SFP_SIZE) {
7805 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
7806 		cmd->DetailStatus = QL_24XX_SFP_SIZE;
7807 		EL(ha, "failed, ResponseLen < SFP len, len passed=%xh\n",
7808 		    cmd->ResponseLen);
7809 		return;
7810 	}
7811 
7812 	/* Dump SFP data in user buffer */
7813 	if ((ql_dump_sfp(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
7814 	    mode)) != 0) {
7815 		cmd->Status = EXT_STATUS_COPY_ERR;
7816 		EL(ha, "failed, copy error\n");
7817 	} else {
7818 		cmd->Status = EXT_STATUS_OK;
7819 	}
7820 
7821 	QL_PRINT_9(ha, "done\n");
7822 }
7823 
7824 /*
7825  * ql_dump_sfp
7826  *	Dumps SFP.
7827  *
7828  * Input:
7829  *	ha:	adapter state pointer.
7830  *	bp:	buffer address.
7831  *	mode:	flags
7832  *
7833  * Returns:
7834  *
7835  * Context:
7836  *	Kernel context.
7837  */
7838 static int
ql_dump_sfp(ql_adapter_state_t * ha,void * bp,int mode)7839 ql_dump_sfp(ql_adapter_state_t *ha, void *bp, int mode)
7840 {
7841 	dma_mem_t	mem;
7842 	uint32_t	cnt;
7843 	int		rval2, rval = 0;
7844 	uint32_t	dxfer;
7845 
7846 	QL_PRINT_9(ha, "started\n");
7847 
7848 	/* Get memory for SFP. */
7849 
7850 	if ((rval2 = ql_get_dma_mem(ha, &mem, 64, LITTLE_ENDIAN_DMA,
7851 	    QL_DMA_DATA_ALIGN)) != QL_SUCCESS) {
7852 		EL(ha, "failed, ql_get_dma_mem=%xh\n", rval2);
7853 		return (ENOMEM);
7854 	}
7855 
7856 	for (cnt = 0; cnt < QL_24XX_SFP_SIZE; cnt += mem.size) {
7857 		rval2 = ql_read_sfp(ha, &mem,
7858 		    (uint16_t)(cnt < 256 ? 0xA0 : 0xA2),
7859 		    (uint16_t)(cnt & 0xff));
7860 		if (rval2 != QL_SUCCESS) {
7861 			EL(ha, "failed, read_sfp=%xh\n", rval2);
7862 			rval = EFAULT;
7863 			break;
7864 		}
7865 
7866 		/* copy the data back */
7867 		if ((dxfer = ql_send_buffer_data(mem.bp, bp, mem.size,
7868 		    mode)) != mem.size) {
7869 			/* ddi copy error */
7870 			EL(ha, "failed, ddi copy; byte cnt = %xh", dxfer);
7871 			rval = EFAULT;
7872 			break;
7873 		}
7874 
7875 		/* adjust the buffer pointer */
7876 		bp = (caddr_t)bp + mem.size;
7877 	}
7878 
7879 	ql_free_phys(ha, &mem);
7880 
7881 	QL_PRINT_9(ha, "done\n");
7882 
7883 	return (rval);
7884 }
7885 
7886 /*
7887  * ql_port_param
7888  *	Retrieves or sets the firmware port speed settings
7889  *
7890  * Input:
7891  *	ha:	adapter state pointer.
7892  *	cmd:	Local EXT_IOCTL cmd struct pointer.
7893  *	mode:	flags.
7894  *
7895  * Returns:
7896  *	None, request status indicated in cmd->Status.
7897  *
7898  * Context:
7899  *	Kernel context.
7900  *
7901  */
7902 static void
ql_port_param(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)7903 ql_port_param(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
7904 {
7905 	uint8_t			*name;
7906 	ql_tgt_t		*tq;
7907 	EXT_PORT_PARAM		port_param = {0};
7908 	uint32_t		rval = QL_SUCCESS;
7909 	uint32_t		idma_rate;
7910 
7911 	QL_PRINT_9(ha, "started\n");
7912 
7913 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
7914 		EL(ha, "invalid request for this HBA\n");
7915 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
7916 		cmd->ResponseLen = 0;
7917 		return;
7918 	}
7919 
7920 	if (LOOP_NOT_READY(ha)) {
7921 		EL(ha, "failed, loop not ready\n");
7922 		cmd->Status = EXT_STATUS_DEVICE_OFFLINE;
7923 		cmd->ResponseLen = 0;
7924 		return;
7925 	}
7926 
7927 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
7928 	    (void*)&port_param, sizeof (EXT_PORT_PARAM), mode) != 0) {
7929 		EL(ha, "failed, ddi_copyin\n");
7930 		cmd->Status = EXT_STATUS_COPY_ERR;
7931 		cmd->ResponseLen = 0;
7932 		return;
7933 	}
7934 
7935 	if (port_param.FCScsiAddr.DestType != EXT_DEF_DESTTYPE_WWPN) {
7936 		EL(ha, "Unsupported dest lookup type: %xh\n",
7937 		    port_param.FCScsiAddr.DestType);
7938 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
7939 		cmd->ResponseLen = 0;
7940 		return;
7941 	}
7942 
7943 	name = port_param.FCScsiAddr.DestAddr.WWPN;
7944 
7945 	QL_PRINT_9(ha, "wwpn=%02x%02x%02x%02x%02x%02x%02x%02x\n",
7946 	    ha->instance, name[0], name[1], name[2], name[3], name[4],
7947 	    name[5], name[6], name[7]);
7948 
7949 	tq = ql_find_port(ha, name, (uint16_t)QLNT_PORT);
7950 	if (tq == NULL || !VALID_TARGET_ID(ha, tq->loop_id) ||
7951 	    tq->d_id.b24 == FS_MANAGEMENT_SERVER) {
7952 		EL(ha, "failed, fc_port not found\n");
7953 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
7954 		cmd->ResponseLen = 0;
7955 		return;
7956 	}
7957 
7958 	cmd->Status = EXT_STATUS_OK;
7959 	cmd->DetailStatus = EXT_STATUS_OK;
7960 
7961 	switch (port_param.Mode) {
7962 	case EXT_IIDMA_MODE_GET:
7963 		/*
7964 		 * Report the firmware's port rate for the wwpn
7965 		 */
7966 		rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate,
7967 		    port_param.Mode);
7968 
7969 		if (rval != QL_SUCCESS) {
7970 			EL(ha, "iidma get failed: %xh\n", rval);
7971 			cmd->Status = EXT_STATUS_MAILBOX;
7972 			cmd->DetailStatus = rval;
7973 			cmd->ResponseLen = 0;
7974 		} else {
7975 			switch (idma_rate) {
7976 			case IIDMA_RATE_1GB:
7977 				port_param.Speed =
7978 				    EXT_DEF_PORTSPEED_1GBIT;
7979 				break;
7980 			case IIDMA_RATE_2GB:
7981 				port_param.Speed =
7982 				    EXT_DEF_PORTSPEED_2GBIT;
7983 				break;
7984 			case IIDMA_RATE_4GB:
7985 				port_param.Speed =
7986 				    EXT_DEF_PORTSPEED_4GBIT;
7987 				break;
7988 			case IIDMA_RATE_8GB:
7989 				port_param.Speed =
7990 				    EXT_DEF_PORTSPEED_8GBIT;
7991 				break;
7992 			case IIDMA_RATE_10GB:
7993 				port_param.Speed =
7994 				    EXT_DEF_PORTSPEED_10GBIT;
7995 				break;
7996 			case IIDMA_RATE_16GB:
7997 				port_param.Speed =
7998 				    EXT_DEF_PORTSPEED_16GBIT;
7999 				break;
8000 			case IIDMA_RATE_32GB:
8001 				port_param.Speed =
8002 				    EXT_DEF_PORTSPEED_32GBIT;
8003 				break;
8004 			default:
8005 				port_param.Speed =
8006 				    EXT_DEF_PORTSPEED_UNKNOWN;
8007 				EL(ha, "failed, Port speed rate=%xh\n",
8008 				    idma_rate);
8009 				break;
8010 			}
8011 
8012 			/* Copy back the data */
8013 			rval = ddi_copyout((void *)&port_param,
8014 			    (void *)(uintptr_t)cmd->ResponseAdr,
8015 			    sizeof (EXT_PORT_PARAM), mode);
8016 
8017 			if (rval != 0) {
8018 				cmd->Status = EXT_STATUS_COPY_ERR;
8019 				cmd->ResponseLen = 0;
8020 				EL(ha, "failed, ddi_copyout\n");
8021 			} else {
8022 				cmd->ResponseLen = (uint32_t)
8023 				    sizeof (EXT_PORT_PARAM);
8024 			}
8025 		}
8026 		break;
8027 
8028 	case EXT_IIDMA_MODE_SET:
8029 		/*
8030 		 * Set the firmware's port rate for the wwpn
8031 		 */
8032 		switch (port_param.Speed) {
8033 		case EXT_DEF_PORTSPEED_1GBIT:
8034 			idma_rate = IIDMA_RATE_1GB;
8035 			break;
8036 		case EXT_DEF_PORTSPEED_2GBIT:
8037 			idma_rate = IIDMA_RATE_2GB;
8038 			break;
8039 		case EXT_DEF_PORTSPEED_4GBIT:
8040 			idma_rate = IIDMA_RATE_4GB;
8041 			break;
8042 		case EXT_DEF_PORTSPEED_8GBIT:
8043 			idma_rate = IIDMA_RATE_8GB;
8044 			break;
8045 		case EXT_DEF_PORTSPEED_10GBIT:
8046 			idma_rate = IIDMA_RATE_10GB;
8047 			break;
8048 		case EXT_DEF_PORTSPEED_16GBIT:
8049 			idma_rate = IIDMA_RATE_16GB;
8050 			break;
8051 		case EXT_DEF_PORTSPEED_32GBIT:
8052 			idma_rate = IIDMA_RATE_32GB;
8053 			break;
8054 		default:
8055 			EL(ha, "invalid set iidma rate: %x\n",
8056 			    port_param.Speed);
8057 			cmd->Status = EXT_STATUS_INVALID_PARAM;
8058 			cmd->ResponseLen = 0;
8059 			rval = QL_PARAMETER_ERROR;
8060 			break;
8061 		}
8062 
8063 		if (rval == QL_SUCCESS) {
8064 			rval = ql_iidma_rate(ha, tq->loop_id, &idma_rate,
8065 			    port_param.Mode);
8066 			if (rval != QL_SUCCESS) {
8067 				EL(ha, "iidma set failed: %xh\n", rval);
8068 				cmd->Status = EXT_STATUS_MAILBOX;
8069 				cmd->DetailStatus = rval;
8070 				cmd->ResponseLen = 0;
8071 			}
8072 		}
8073 		break;
8074 	default:
8075 		EL(ha, "invalid mode specified: %x\n", port_param.Mode);
8076 		cmd->Status = EXT_STATUS_INVALID_PARAM;
8077 		cmd->ResponseLen = 0;
8078 		cmd->DetailStatus = 0;
8079 		break;
8080 	}
8081 
8082 	QL_PRINT_9(ha, "done\n");
8083 }
8084 
8085 /*
8086  * ql_get_fwexttrace
8087  *	Dumps f/w extended trace buffer
8088  *
8089  * Input:
8090  *	ha:	adapter state pointer.
8091  *	bp:	buffer address.
8092  *	mode:	flags
8093  *
8094  * Returns:
8095  *
8096  * Context:
8097  *	Kernel context.
8098  */
8099 /* ARGSUSED */
8100 static void
ql_get_fwexttrace(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8101 ql_get_fwexttrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8102 {
8103 	int	rval;
8104 	caddr_t	payload;
8105 
8106 	QL_PRINT_9(ha, "started\n");
8107 
8108 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
8109 		EL(ha, "invalid request for this HBA\n");
8110 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8111 		cmd->ResponseLen = 0;
8112 		return;
8113 	}
8114 
8115 	if ((CFG_IST(ha, CFG_ENABLE_FWEXTTRACE) == 0) ||
8116 	    (ha->fwexttracebuf.bp == NULL)) {
8117 		EL(ha, "f/w extended trace is not enabled\n");
8118 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8119 		cmd->ResponseLen = 0;
8120 		return;
8121 	}
8122 
8123 	if (cmd->ResponseLen < FWEXTSIZE) {
8124 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8125 		cmd->DetailStatus = FWEXTSIZE;
8126 		EL(ha, "failed, ResponseLen (%xh) < %xh (FWEXTSIZE)\n",
8127 		    cmd->ResponseLen, FWEXTSIZE);
8128 		cmd->ResponseLen = 0;
8129 		return;
8130 	}
8131 
8132 	/* Time Stamp */
8133 	rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_INSERT_TIME_STAMP,
8134 	    NULL);
8135 	if (rval != QL_SUCCESS) {
8136 		EL(ha, "f/w extended trace insert"
8137 		    "time stamp failed: %xh\n", rval);
8138 		cmd->Status = EXT_STATUS_ERR;
8139 		cmd->ResponseLen = 0;
8140 		return;
8141 	}
8142 
8143 	/* Disable Tracing */
8144 	rval = ql_fw_etrace(ha, &ha->fwexttracebuf, FTO_EXT_TRACE_DISABLE,
8145 	    NULL);
8146 	if (rval != QL_SUCCESS) {
8147 		EL(ha, "f/w extended trace disable failed: %xh\n", rval);
8148 		cmd->Status = EXT_STATUS_ERR;
8149 		cmd->ResponseLen = 0;
8150 		return;
8151 	}
8152 
8153 	/* Allocate payload buffer */
8154 	payload = kmem_zalloc(FWEXTSIZE, KM_SLEEP);
8155 	if (payload == NULL) {
8156 		EL(ha, "failed, kmem_zalloc\n");
8157 		cmd->Status = EXT_STATUS_NO_MEMORY;
8158 		cmd->ResponseLen = 0;
8159 		return;
8160 	}
8161 
8162 	/* Sync DMA buffer. */
8163 	(void) ddi_dma_sync(ha->fwexttracebuf.dma_handle, 0,
8164 	    FWEXTSIZE, DDI_DMA_SYNC_FORKERNEL);
8165 
8166 	/* Copy trace buffer data. */
8167 	ddi_rep_get8(ha->fwexttracebuf.acc_handle, (uint8_t *)payload,
8168 	    (uint8_t *)ha->fwexttracebuf.bp, FWEXTSIZE,
8169 	    DDI_DEV_AUTOINCR);
8170 
8171 	/* Send payload to application. */
8172 	if (ql_send_buffer_data(payload, (caddr_t)(uintptr_t)cmd->ResponseAdr,
8173 	    cmd->ResponseLen, mode) != cmd->ResponseLen) {
8174 		EL(ha, "failed, send_buffer_data\n");
8175 		cmd->Status = EXT_STATUS_COPY_ERR;
8176 		cmd->ResponseLen = 0;
8177 	} else {
8178 		cmd->Status = EXT_STATUS_OK;
8179 	}
8180 
8181 	kmem_free(payload, FWEXTSIZE);
8182 
8183 	QL_PRINT_9(ha, "done\n");
8184 }
8185 
8186 /*
8187  * ql_get_fwfcetrace
8188  *	Dumps f/w fibre channel event trace buffer
8189  *
8190  * Input:
8191  *	ha:	adapter state pointer.
8192  *	bp:	buffer address.
8193  *	mode:	flags
8194  *
8195  * Returns:
8196  *
8197  * Context:
8198  *	Kernel context.
8199  */
8200 /* ARGSUSED */
8201 static void
ql_get_fwfcetrace(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8202 ql_get_fwfcetrace(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8203 {
8204 	int			rval;
8205 	caddr_t			fce_trace_p;
8206 	ql_mbx_data_t		mr;
8207 	EXT_FW_FCE_TRACE	*fce_trace;
8208 	size_t			cnt;
8209 	uint32_t		*bp;
8210 
8211 	QL_PRINT_9(ha, "started\n");
8212 
8213 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
8214 		EL(ha, "invalid request for this HBA\n");
8215 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8216 		cmd->ResponseLen = 0;
8217 		return;
8218 	}
8219 
8220 	if ((CFG_IST(ha, CFG_ENABLE_FWFCETRACE) == 0) ||
8221 	    (ha->fwfcetracebuf.bp == NULL)) {
8222 		EL(ha, "f/w FCE trace is not enabled\n");
8223 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8224 		cmd->ResponseLen = 0;
8225 		return;
8226 	}
8227 
8228 	if (cmd->ResponseLen < FWFCESIZE) {
8229 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8230 		cmd->DetailStatus = FWFCESIZE;
8231 		EL(ha, "failed, ResponseLen (%xh) < %xh (FWFCESIZE)\n",
8232 		    cmd->ResponseLen, FWFCESIZE);
8233 		cmd->ResponseLen = 0;
8234 		return;
8235 	}
8236 
8237 	/* Disable Tracing */
8238 	rval = ql_fw_etrace(ha, &ha->fwfcetracebuf, FTO_FCE_TRACE_DISABLE, &mr);
8239 	if (rval != QL_SUCCESS) {
8240 		EL(ha, "f/w FCE trace disable failed: %xh\n", rval);
8241 		cmd->Status = EXT_STATUS_ERR;
8242 		cmd->ResponseLen = 0;
8243 		return;
8244 	}
8245 
8246 	/* Allocate payload buffer */
8247 	fce_trace = kmem_zalloc(FWFCESIZE, KM_SLEEP);
8248 	if (fce_trace == NULL) {
8249 		EL(ha, "failed, kmem_zalloc\n");
8250 		cmd->Status = EXT_STATUS_NO_MEMORY;
8251 		cmd->ResponseLen = 0;
8252 		return;
8253 	}
8254 	fce_trace_p = (caddr_t)&fce_trace->TraceData[0];
8255 
8256 	/* Copy In Ponter and Base Pointer values */
8257 	fce_trace->Registers[0] = mr.mb[2];
8258 	fce_trace->Registers[1] = mr.mb[3];
8259 	fce_trace->Registers[2] = mr.mb[4];
8260 	fce_trace->Registers[3] = mr.mb[5];
8261 
8262 	fce_trace->Registers[4] = LSW(ha->fwexttracebuf.cookies->dmac_address);
8263 	fce_trace->Registers[5] = MSW(ha->fwexttracebuf.cookies->dmac_address);
8264 	fce_trace->Registers[6] = LSW(ha->fwexttracebuf.cookies->dmac_notused);
8265 	fce_trace->Registers[7] = MSW(ha->fwexttracebuf.cookies->dmac_notused);
8266 
8267 	/* Copy FCE Trace Enable Registers */
8268 	fce_trace->Registers[8] = ha->fw_fce_trace_enable.mb[0];
8269 	fce_trace->Registers[9] = ha->fw_fce_trace_enable.mb[2];
8270 	fce_trace->Registers[10] = ha->fw_fce_trace_enable.mb[3];
8271 	fce_trace->Registers[11] = ha->fw_fce_trace_enable.mb[4];
8272 	fce_trace->Registers[12] = ha->fw_fce_trace_enable.mb[5];
8273 	fce_trace->Registers[13] = ha->fw_fce_trace_enable.mb[6];
8274 
8275 	/* Sync DMA buffer. */
8276 	(void) ddi_dma_sync(ha->fwfcetracebuf.dma_handle, 0,
8277 	    FWFCESIZE, DDI_DMA_SYNC_FORKERNEL);
8278 
8279 	/* Copy trace buffer data. */
8280 	ddi_rep_get8(ha->fwfcetracebuf.acc_handle, (uint8_t *)fce_trace_p,
8281 	    (uint8_t *)ha->fwfcetracebuf.bp, FWFCESIZE,
8282 	    DDI_DEV_AUTOINCR);
8283 
8284 	/* Swap bytes in buffer in case of Big Endian */
8285 	bp = (uint32_t *)&fce_trace->TraceData[0];
8286 	for (cnt = 0; cnt < (FWFCESIZE / sizeof (uint32_t)); cnt++) {
8287 		LITTLE_ENDIAN_32(bp);
8288 		bp++;
8289 	}
8290 
8291 	/* Send payload to application. */
8292 	if (ql_send_buffer_data((caddr_t)fce_trace,
8293 	    (caddr_t)(uintptr_t)cmd->ResponseAdr,
8294 	    cmd->ResponseLen, mode) != cmd->ResponseLen) {
8295 		EL(ha, "failed, send_buffer_data\n");
8296 		cmd->Status = EXT_STATUS_COPY_ERR;
8297 		cmd->ResponseLen = 0;
8298 	} else {
8299 		cmd->Status = EXT_STATUS_OK;
8300 	}
8301 
8302 	/* Re-enable Tracing */
8303 	bzero(ha->fwfcetracebuf.bp, ha->fwfcetracebuf.size);
8304 	if ((rval = ql_fw_etrace(ha, &ha->fwfcetracebuf,
8305 	    FTO_FCE_TRACE_ENABLE, &mr)) != QL_SUCCESS) {
8306 		EL(ha, "fcetrace enable failed: %xh\n", rval);
8307 	} else {
8308 		ha->fw_fce_trace_enable = mr;
8309 		EL(ha, "FCE Trace Re-Enabled\n");
8310 	}
8311 
8312 	kmem_free(fce_trace, FWFCESIZE);
8313 
8314 	QL_PRINT_9(ha, "done\n");
8315 }
8316 
8317 /*
8318  * ql_get_pci_data
8319  *	Retrieves pci config space data
8320  *
8321  * Input:
8322  *	ha:	adapter state pointer.
8323  *	cmd:	Local EXT_IOCTL cmd struct pointer.
8324  *	mode:	flags.
8325  *
8326  * Returns:
8327  *	None, request status indicated in cmd->Status.
8328  *
8329  * Context:
8330  *	Kernel context.
8331  *
8332  */
8333 static void
ql_get_pci_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8334 ql_get_pci_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8335 {
8336 	uint8_t		cap_ptr;
8337 	uint8_t		cap_id;
8338 	uint32_t	buf_size = 256;
8339 
8340 	QL_PRINT_9(ha, "started\n");
8341 
8342 	/*
8343 	 * First check the "Capabilities List" bit of the status register.
8344 	 */
8345 	if (ql_pci_config_get16(ha, PCI_CONF_STAT) & PCI_STAT_CAP) {
8346 		/*
8347 		 * Now get the capability pointer
8348 		 */
8349 		cap_ptr = (uint8_t)ql_pci_config_get8(ha, PCI_CONF_CAP_PTR);
8350 		while (cap_ptr != PCI_CAP_NEXT_PTR_NULL) {
8351 			/*
8352 			 * Check for the pcie capability.
8353 			 */
8354 			cap_id = (uint8_t)ql_pci_config_get8(ha, cap_ptr);
8355 			if (cap_id == PCI_CAP_ID_PCI_E) {
8356 				buf_size = 4096;
8357 				break;
8358 			}
8359 			cap_ptr = (uint8_t)ql_pci_config_get8(ha,
8360 			    (cap_ptr + PCI_CAP_NEXT_PTR));
8361 		}
8362 	}
8363 
8364 	if (cmd->ResponseLen < buf_size) {
8365 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8366 		cmd->DetailStatus = buf_size;
8367 		EL(ha, "failed ResponseLen < buf_size, len passed=%xh\n",
8368 		    cmd->ResponseLen);
8369 		return;
8370 	}
8371 
8372 	/* Dump PCI config data. */
8373 	if ((ql_pci_dump(ha, (void *)(uintptr_t)(cmd->ResponseAdr),
8374 	    buf_size, mode)) != 0) {
8375 		cmd->Status = EXT_STATUS_COPY_ERR;
8376 		cmd->DetailStatus = 0;
8377 		EL(ha, "failed, copy err pci_dump\n");
8378 	} else {
8379 		cmd->Status = EXT_STATUS_OK;
8380 		cmd->DetailStatus = buf_size;
8381 	}
8382 
8383 	QL_PRINT_9(ha, "done\n");
8384 }
8385 
8386 /*
8387  * ql_pci_dump
8388  *	Dumps PCI config data to application buffer.
8389  *
8390  * Input:
8391  *	ha = adapter state pointer.
8392  *	bp = user buffer address.
8393  *
8394  * Returns:
8395  *
8396  * Context:
8397  *	Kernel context.
8398  */
8399 int
ql_pci_dump(ql_adapter_state_t * ha,uint32_t * bp,uint32_t pci_size,int mode)8400 ql_pci_dump(ql_adapter_state_t *ha, uint32_t *bp, uint32_t pci_size, int mode)
8401 {
8402 	uint32_t	pci_os;
8403 	uint32_t	*ptr32, *org_ptr32;
8404 
8405 	QL_PRINT_9(ha, "started\n");
8406 
8407 	ptr32 = kmem_zalloc(pci_size, KM_SLEEP);
8408 	if (ptr32 == NULL) {
8409 		EL(ha, "failed kmem_zalloc\n");
8410 		return (ENOMEM);
8411 	}
8412 
8413 	/* store the initial value of ptr32 */
8414 	org_ptr32 = ptr32;
8415 	for (pci_os = 0; pci_os < pci_size; pci_os += 4) {
8416 		*ptr32 = (uint32_t)ql_pci_config_get32(ha, pci_os);
8417 		LITTLE_ENDIAN_32(ptr32);
8418 		ptr32++;
8419 	}
8420 
8421 	if (ddi_copyout((void *)org_ptr32, (void *)bp, pci_size, mode) !=
8422 	    0) {
8423 		EL(ha, "failed ddi_copyout\n");
8424 		kmem_free(org_ptr32, pci_size);
8425 		return (EFAULT);
8426 	}
8427 
8428 	QL_DUMP_9(org_ptr32, 8, pci_size);
8429 
8430 	kmem_free(org_ptr32, pci_size);
8431 
8432 	QL_PRINT_9(ha, "done\n");
8433 
8434 	return (0);
8435 }
8436 
8437 /*
8438  * ql_menlo_reset
8439  *	Reset Menlo
8440  *
8441  * Input:
8442  *	ha:	adapter state pointer.
8443  *	bp:	buffer address.
8444  *	mode:	flags
8445  *
8446  * Returns:
8447  *
8448  * Context:
8449  *	Kernel context.
8450  */
8451 static void
ql_menlo_reset(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8452 ql_menlo_reset(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8453 {
8454 	EXT_MENLO_RESET	rst;
8455 	ql_mbx_data_t	mr;
8456 	int		rval;
8457 
8458 	QL_PRINT_9(ha, "started\n");
8459 
8460 	if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8461 		EL(ha, "failed, invalid request for HBA\n");
8462 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8463 		cmd->ResponseLen = 0;
8464 		return;
8465 	}
8466 
8467 	/*
8468 	 * TODO: only vp_index 0 can do this (?)
8469 	 */
8470 
8471 	/*  Verify the size of request structure. */
8472 	if (cmd->RequestLen < sizeof (EXT_MENLO_RESET)) {
8473 		/* Return error */
8474 		EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8475 		    sizeof (EXT_MENLO_RESET));
8476 		cmd->Status = EXT_STATUS_INVALID_PARAM;
8477 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8478 		cmd->ResponseLen = 0;
8479 		return;
8480 	}
8481 
8482 	/* Get reset request. */
8483 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
8484 	    (void *)&rst, sizeof (EXT_MENLO_RESET), mode) != 0) {
8485 		EL(ha, "failed, ddi_copyin\n");
8486 		cmd->Status = EXT_STATUS_COPY_ERR;
8487 		cmd->ResponseLen = 0;
8488 		return;
8489 	}
8490 
8491 	/* Wait for I/O to stop and daemon to stall. */
8492 	if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8493 		EL(ha, "ql_stall_driver failed\n");
8494 		ql_restart_hba(ha);
8495 		cmd->Status = EXT_STATUS_BUSY;
8496 		cmd->ResponseLen = 0;
8497 		return;
8498 	}
8499 
8500 	rval = ql_reset_menlo(ha, &mr, rst.Flags);
8501 	if (rval != QL_SUCCESS) {
8502 		EL(ha, "failed, status=%xh\n", rval);
8503 		cmd->Status = EXT_STATUS_MAILBOX;
8504 		cmd->DetailStatus = rval;
8505 		cmd->ResponseLen = 0;
8506 	} else if (mr.mb[1] != 0) {
8507 		EL(ha, "failed, substatus=%d\n", mr.mb[1]);
8508 		cmd->Status = EXT_STATUS_ERR;
8509 		cmd->DetailStatus = mr.mb[1];
8510 		cmd->ResponseLen = 0;
8511 	}
8512 
8513 	ql_restart_hba(ha);
8514 
8515 	QL_PRINT_9(ha, "done\n");
8516 }
8517 
8518 /*
8519  * ql_menlo_get_fw_version
8520  *	Get Menlo firmware version.
8521  *
8522  * Input:
8523  *	ha:	adapter state pointer.
8524  *	bp:	buffer address.
8525  *	mode:	flags
8526  *
8527  * Returns:
8528  *
8529  * Context:
8530  *	Kernel context.
8531  */
8532 static void
ql_menlo_get_fw_version(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8533 ql_menlo_get_fw_version(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8534 {
8535 	int				rval;
8536 	ql_mbx_iocb_t			*pkt;
8537 	EXT_MENLO_GET_FW_VERSION	ver = {0};
8538 
8539 	QL_PRINT_9(ha, "started\n");
8540 
8541 	if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8542 		EL(ha, "failed, invalid request for HBA\n");
8543 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8544 		cmd->ResponseLen = 0;
8545 		return;
8546 	}
8547 
8548 	if (cmd->ResponseLen < sizeof (EXT_MENLO_GET_FW_VERSION)) {
8549 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
8550 		cmd->DetailStatus = sizeof (EXT_MENLO_GET_FW_VERSION);
8551 		EL(ha, "ResponseLen=%d < %d\n", cmd->ResponseLen,
8552 		    sizeof (EXT_MENLO_GET_FW_VERSION));
8553 		cmd->ResponseLen = 0;
8554 		return;
8555 	}
8556 
8557 	/* Allocate packet. */
8558 	pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8559 	if (pkt == NULL) {
8560 		EL(ha, "failed, kmem_zalloc\n");
8561 		cmd->Status = EXT_STATUS_NO_MEMORY;
8562 		cmd->ResponseLen = 0;
8563 		return;
8564 	}
8565 
8566 	pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
8567 	pkt->mvfy.entry_count = 1;
8568 	pkt->mvfy.options_status = LE_16(VMF_DO_NOT_UPDATE_FW);
8569 
8570 	rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8571 	LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
8572 	LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
8573 	ver.FwVersion = LE_32(pkt->mvfy.fw_version);
8574 
8575 	if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 ||
8576 	    pkt->mvfy.options_status != CS_COMPLETE) {
8577 		/* Command error */
8578 		EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8579 		    pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status,
8580 		    pkt->mvfy.failure_code);
8581 		cmd->Status = EXT_STATUS_ERR;
8582 		cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8583 		    QL_FUNCTION_FAILED;
8584 		cmd->ResponseLen = 0;
8585 	} else if (ddi_copyout((void *)&ver,
8586 	    (void *)(uintptr_t)cmd->ResponseAdr,
8587 	    sizeof (EXT_MENLO_GET_FW_VERSION), mode) != 0) {
8588 		EL(ha, "failed, ddi_copyout\n");
8589 		cmd->Status = EXT_STATUS_COPY_ERR;
8590 		cmd->ResponseLen = 0;
8591 	} else {
8592 		cmd->ResponseLen = sizeof (EXT_MENLO_GET_FW_VERSION);
8593 	}
8594 
8595 	kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8596 
8597 	QL_PRINT_9(ha, "done\n");
8598 }
8599 
8600 /*
8601  * ql_menlo_update_fw
8602  *	Get Menlo update firmware.
8603  *
8604  * Input:
8605  *	ha:	adapter state pointer.
8606  *	bp:	buffer address.
8607  *	mode:	flags
8608  *
8609  * Returns:
8610  *
8611  * Context:
8612  *	Kernel context.
8613  */
8614 static void
ql_menlo_update_fw(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8615 ql_menlo_update_fw(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8616 {
8617 	ql_mbx_iocb_t		*pkt;
8618 	dma_mem_t		*dma_mem;
8619 	EXT_MENLO_UPDATE_FW	fw;
8620 	uint32_t		*ptr32;
8621 	int			rval;
8622 
8623 	QL_PRINT_9(ha, "started\n");
8624 
8625 	if ((CFG_IST(ha, CFG_CTRL_MENLO)) == 0) {
8626 		EL(ha, "failed, invalid request for HBA\n");
8627 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8628 		cmd->ResponseLen = 0;
8629 		return;
8630 	}
8631 
8632 	/*
8633 	 * TODO: only vp_index 0 can do this (?)
8634 	 */
8635 
8636 	/*  Verify the size of request structure. */
8637 	if (cmd->RequestLen < sizeof (EXT_MENLO_UPDATE_FW)) {
8638 		/* Return error */
8639 		EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8640 		    sizeof (EXT_MENLO_UPDATE_FW));
8641 		cmd->Status = EXT_STATUS_INVALID_PARAM;
8642 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8643 		cmd->ResponseLen = 0;
8644 		return;
8645 	}
8646 
8647 	/* Get update fw request. */
8648 	if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr, (caddr_t)&fw,
8649 	    sizeof (EXT_MENLO_UPDATE_FW), mode) != 0) {
8650 		EL(ha, "failed, ddi_copyin\n");
8651 		cmd->Status = EXT_STATUS_COPY_ERR;
8652 		cmd->ResponseLen = 0;
8653 		return;
8654 	}
8655 
8656 	/* Wait for I/O to stop and daemon to stall. */
8657 	if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
8658 		EL(ha, "ql_stall_driver failed\n");
8659 		ql_restart_hba(ha);
8660 		cmd->Status = EXT_STATUS_BUSY;
8661 		cmd->ResponseLen = 0;
8662 		return;
8663 	}
8664 
8665 	/* Allocate packet. */
8666 	dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
8667 	if (dma_mem == NULL) {
8668 		EL(ha, "failed, kmem_zalloc\n");
8669 		cmd->Status = EXT_STATUS_NO_MEMORY;
8670 		cmd->ResponseLen = 0;
8671 		return;
8672 	}
8673 	pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8674 	if (pkt == NULL) {
8675 		EL(ha, "failed, kmem_zalloc\n");
8676 		kmem_free(dma_mem, sizeof (dma_mem_t));
8677 		ql_restart_hba(ha);
8678 		cmd->Status = EXT_STATUS_NO_MEMORY;
8679 		cmd->ResponseLen = 0;
8680 		return;
8681 	}
8682 
8683 	/* Get DMA memory for the IOCB */
8684 	if (ql_get_dma_mem(ha, dma_mem, fw.TotalByteCount, LITTLE_ENDIAN_DMA,
8685 	    QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
8686 		cmn_err(CE_WARN, "%srequest queue DMA memory "
8687 		    "alloc failed", QL_NAME);
8688 		kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8689 		kmem_free(dma_mem, sizeof (dma_mem_t));
8690 		ql_restart_hba(ha);
8691 		cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
8692 		cmd->ResponseLen = 0;
8693 		return;
8694 	}
8695 
8696 	/* Get firmware data. */
8697 	if (ql_get_buffer_data((caddr_t)(uintptr_t)fw.pFwDataBytes, dma_mem->bp,
8698 	    fw.TotalByteCount, mode) != fw.TotalByteCount) {
8699 		EL(ha, "failed, get_buffer_data\n");
8700 		ql_free_dma_resource(ha, dma_mem);
8701 		kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8702 		kmem_free(dma_mem, sizeof (dma_mem_t));
8703 		ql_restart_hba(ha);
8704 		cmd->Status = EXT_STATUS_COPY_ERR;
8705 		cmd->ResponseLen = 0;
8706 		return;
8707 	}
8708 
8709 	/* Sync DMA buffer. */
8710 	(void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size,
8711 	    DDI_DMA_SYNC_FORDEV);
8712 
8713 	pkt->mvfy.entry_type = VERIFY_MENLO_TYPE;
8714 	pkt->mvfy.entry_count = 1;
8715 	pkt->mvfy.options_status = (uint16_t)LE_16(fw.Flags);
8716 	ptr32 = dma_mem->bp;
8717 	pkt->mvfy.fw_version = LE_32(ptr32[2]);
8718 	pkt->mvfy.fw_size = LE_32(fw.TotalByteCount);
8719 	pkt->mvfy.fw_sequence_size = LE_32(fw.TotalByteCount);
8720 	pkt->mvfy.dseg_count = LE_16(1);
8721 	pkt->mvfy.dseg.address[0] = (uint32_t)
8722 	    LE_32(LSD(dma_mem->cookie.dmac_laddress));
8723 	pkt->mvfy.dseg.address[1] = (uint32_t)
8724 	    LE_32(MSD(dma_mem->cookie.dmac_laddress));
8725 	pkt->mvfy.dseg.length = LE_32(fw.TotalByteCount);
8726 
8727 	rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8728 	LITTLE_ENDIAN_16(&pkt->mvfy.options_status);
8729 	LITTLE_ENDIAN_16(&pkt->mvfy.failure_code);
8730 
8731 	if (rval != QL_SUCCESS || (pkt->mvfy.entry_status & 0x3c) != 0 ||
8732 	    pkt->mvfy.options_status != CS_COMPLETE) {
8733 		/* Command error */
8734 		EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8735 		    pkt->mvfy.entry_status & 0x3c, pkt->mvfy.options_status,
8736 		    pkt->mvfy.failure_code);
8737 		cmd->Status = EXT_STATUS_ERR;
8738 		cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8739 		    QL_FUNCTION_FAILED;
8740 		cmd->ResponseLen = 0;
8741 	}
8742 
8743 	ql_free_dma_resource(ha, dma_mem);
8744 	kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8745 	kmem_free(dma_mem, sizeof (dma_mem_t));
8746 	ql_restart_hba(ha);
8747 
8748 	QL_PRINT_9(ha, "done\n");
8749 }
8750 
8751 /*
8752  * ql_menlo_manage_info
8753  *	Get Menlo manage info.
8754  *
8755  * Input:
8756  *	ha:	adapter state pointer.
8757  *	bp:	buffer address.
8758  *	mode:	flags
8759  *
8760  * Returns:
8761  *
8762  * Context:
8763  *	Kernel context.
8764  */
8765 static void
ql_menlo_manage_info(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)8766 ql_menlo_manage_info(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
8767 {
8768 	ql_mbx_iocb_t		*pkt;
8769 	dma_mem_t		*dma_mem = NULL;
8770 	EXT_MENLO_MANAGE_INFO	info;
8771 	int			rval;
8772 
8773 	QL_PRINT_9(ha, "started\n");
8774 
8775 
8776 	/* The call is only supported for Schultz right now */
8777 	if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
8778 		ql_get_xgmac_statistics(ha, cmd, mode);
8779 		QL_PRINT_9(ha, "CFG_FCOE_SUPPORT done\n");
8780 		return;
8781 	}
8782 
8783 	if (!CFG_IST(ha, CFG_CTRL_MENLO)) {
8784 		EL(ha, "failed, invalid request for HBA\n");
8785 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
8786 		cmd->ResponseLen = 0;
8787 		return;
8788 	}
8789 
8790 	/*  Verify the size of request structure. */
8791 	if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) {
8792 		/* Return error */
8793 		EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
8794 		    sizeof (EXT_MENLO_MANAGE_INFO));
8795 		cmd->Status = EXT_STATUS_INVALID_PARAM;
8796 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
8797 		cmd->ResponseLen = 0;
8798 		return;
8799 	}
8800 
8801 	/* Get manage info request. */
8802 	if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
8803 	    (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) {
8804 		EL(ha, "failed, ddi_copyin\n");
8805 		cmd->Status = EXT_STATUS_COPY_ERR;
8806 		cmd->ResponseLen = 0;
8807 		return;
8808 	}
8809 
8810 	/* Allocate packet. */
8811 	pkt = kmem_zalloc(sizeof (ql_mbx_iocb_t), KM_SLEEP);
8812 	if (pkt == NULL) {
8813 		EL(ha, "failed, kmem_zalloc\n");
8814 		ql_restart_driver(ha);
8815 		cmd->Status = EXT_STATUS_NO_MEMORY;
8816 		cmd->ResponseLen = 0;
8817 		return;
8818 	}
8819 
8820 	pkt->mdata.entry_type = MENLO_DATA_TYPE;
8821 	pkt->mdata.entry_count = 1;
8822 	pkt->mdata.options_status = (uint16_t)LE_16(info.Operation);
8823 
8824 	/* Get DMA memory for the IOCB */
8825 	if (info.Operation == MENLO_OP_READ_MEM ||
8826 	    info.Operation == MENLO_OP_WRITE_MEM) {
8827 		pkt->mdata.total_byte_count = LE_32(info.TotalByteCount);
8828 		pkt->mdata.parameter_1 =
8829 		    LE_32(info.Parameters.ap.MenloMemory.StartingAddr);
8830 		dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t),
8831 		    KM_SLEEP);
8832 		if (dma_mem == NULL) {
8833 			EL(ha, "failed, kmem_zalloc\n");
8834 			kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8835 			cmd->Status = EXT_STATUS_NO_MEMORY;
8836 			cmd->ResponseLen = 0;
8837 			return;
8838 		}
8839 		if (ql_get_dma_mem(ha, dma_mem, info.TotalByteCount,
8840 		    LITTLE_ENDIAN_DMA, QL_DMA_DATA_ALIGN) != QL_SUCCESS) {
8841 			cmn_err(CE_WARN, "%srequest queue DMA memory "
8842 			    "alloc failed", QL_NAME);
8843 			kmem_free(dma_mem, sizeof (dma_mem_t));
8844 			kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8845 			cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
8846 			cmd->ResponseLen = 0;
8847 			return;
8848 		}
8849 		if (info.Operation == MENLO_OP_WRITE_MEM) {
8850 			/* Get data. */
8851 			if (ql_get_buffer_data(
8852 			    (caddr_t)(uintptr_t)info.pDataBytes,
8853 			    dma_mem->bp, info.TotalByteCount, mode) !=
8854 			    info.TotalByteCount) {
8855 				EL(ha, "failed, get_buffer_data\n");
8856 				ql_free_dma_resource(ha, dma_mem);
8857 				kmem_free(dma_mem, sizeof (dma_mem_t));
8858 				kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8859 				cmd->Status = EXT_STATUS_COPY_ERR;
8860 				cmd->ResponseLen = 0;
8861 				return;
8862 			}
8863 			(void) ddi_dma_sync(dma_mem->dma_handle, 0,
8864 			    dma_mem->size, DDI_DMA_SYNC_FORDEV);
8865 		}
8866 		pkt->mdata.dseg_count = LE_16(1);
8867 		pkt->mdata.dseg.address[0] = (uint32_t)
8868 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
8869 		pkt->mdata.dseg.address[1] = (uint32_t)
8870 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
8871 		pkt->mdata.dseg.length = LE_32(info.TotalByteCount);
8872 	} else if (info.Operation & MENLO_OP_CHANGE_CONFIG) {
8873 		pkt->mdata.parameter_1 =
8874 		    LE_32(info.Parameters.ap.MenloConfig.ConfigParamID);
8875 		pkt->mdata.parameter_2 =
8876 		    LE_32(info.Parameters.ap.MenloConfig.ConfigParamData0);
8877 		pkt->mdata.parameter_3 =
8878 		    LE_32(info.Parameters.ap.MenloConfig.ConfigParamData1);
8879 	} else if (info.Operation & MENLO_OP_GET_INFO) {
8880 		pkt->mdata.parameter_1 =
8881 		    LE_32(info.Parameters.ap.MenloInfo.InfoDataType);
8882 		pkt->mdata.parameter_2 =
8883 		    LE_32(info.Parameters.ap.MenloInfo.InfoContext);
8884 	}
8885 
8886 	rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt, sizeof (ql_mbx_iocb_t));
8887 	LITTLE_ENDIAN_16(&pkt->mdata.options_status);
8888 	LITTLE_ENDIAN_16(&pkt->mdata.failure_code);
8889 
8890 	if (rval != QL_SUCCESS || (pkt->mdata.entry_status & 0x3c) != 0 ||
8891 	    pkt->mdata.options_status != CS_COMPLETE) {
8892 		/* Command error */
8893 		EL(ha, "failed, status=%xh, es=%xh, cs=%xh, fc=%xh\n", rval,
8894 		    pkt->mdata.entry_status & 0x3c, pkt->mdata.options_status,
8895 		    pkt->mdata.failure_code);
8896 		cmd->Status = EXT_STATUS_ERR;
8897 		cmd->DetailStatus = rval != QL_SUCCESS ? rval :
8898 		    QL_FUNCTION_FAILED;
8899 		cmd->ResponseLen = 0;
8900 	} else if (info.Operation == MENLO_OP_READ_MEM) {
8901 		(void) ddi_dma_sync(dma_mem->dma_handle, 0, dma_mem->size,
8902 		    DDI_DMA_SYNC_FORKERNEL);
8903 		if (ql_send_buffer_data((caddr_t)(uintptr_t)info.pDataBytes,
8904 		    dma_mem->bp, info.TotalByteCount, mode) !=
8905 		    info.TotalByteCount) {
8906 			cmd->Status = EXT_STATUS_COPY_ERR;
8907 			cmd->ResponseLen = 0;
8908 		}
8909 	}
8910 
8911 	ql_free_dma_resource(ha, dma_mem);
8912 	kmem_free(dma_mem, sizeof (dma_mem_t));
8913 	kmem_free(pkt, sizeof (ql_mbx_iocb_t));
8914 
8915 	QL_PRINT_9(ha, "done\n");
8916 }
8917 
8918 /*
8919  * ql_suspend_hba
8920  *	Suspends all adapter ports.
8921  *
8922  * Input:
8923  *	ha:		adapter state pointer.
8924  *	options:	BIT_0 --> leave driver stalled on exit if
8925  *				  failed.
8926  *
8927  * Returns:
8928  *	ql local function return status code.
8929  *
8930  * Context:
8931  *	Kernel context.
8932  */
8933 static int
ql_suspend_hba(ql_adapter_state_t * ha,uint32_t opt)8934 ql_suspend_hba(ql_adapter_state_t *ha, uint32_t opt)
8935 {
8936 	ql_adapter_state_t	*ha2;
8937 	ql_link_t		*link;
8938 	int			rval = QL_SUCCESS;
8939 
8940 	/* Quiesce I/O on all adapter ports */
8941 	for (link = ql_hba.first; link != NULL; link = link->next) {
8942 		ha2 = link->base_address;
8943 
8944 		if (ha2->fru_hba_index != ha->fru_hba_index) {
8945 			continue;
8946 		}
8947 
8948 		if ((rval = ql_stall_driver(ha2, opt)) != QL_SUCCESS) {
8949 			EL(ha, "ql_stall_driver status=%xh\n", rval);
8950 			break;
8951 		}
8952 	}
8953 
8954 	return (rval);
8955 }
8956 
8957 /*
8958  * ql_restart_hba
8959  *	Restarts adapter.
8960  *
8961  * Input:
8962  *	ha:	adapter state pointer.
8963  *
8964  * Context:
8965  *	Kernel context.
8966  */
8967 static void
ql_restart_hba(ql_adapter_state_t * ha)8968 ql_restart_hba(ql_adapter_state_t *ha)
8969 {
8970 	ql_adapter_state_t	*ha2;
8971 	ql_link_t		*link;
8972 
8973 	/* Resume I/O on all adapter ports */
8974 	for (link = ql_hba.first; link != NULL; link = link->next) {
8975 		ha2 = link->base_address;
8976 
8977 		if (ha2->fru_hba_index != ha->fru_hba_index) {
8978 			continue;
8979 		}
8980 
8981 		ql_restart_driver(ha2);
8982 	}
8983 }
8984 
8985 /*
8986  * ql_get_vp_cnt_id
8987  *	Retrieves pci config space data
8988  *
8989  * Input:
8990  *	ha:	adapter state pointer.
8991  *	cmd:	Local EXT_IOCTL cmd struct pointer.
8992  *	mode:	flags.
8993  *
8994  * Returns:
8995  *	None, request status indicated in cmd->Status.
8996  *
8997  * Context:
8998  *	Kernel context.
8999  *
9000  */
9001 static void
ql_get_vp_cnt_id(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9002 ql_get_vp_cnt_id(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9003 {
9004 	ql_adapter_state_t	*vha;
9005 	PEXT_VPORT_ID_CNT	ptmp_vp;
9006 	int			id = 0;
9007 	int			rval;
9008 	char			name[MAXPATHLEN];
9009 
9010 	QL_PRINT_9(ha, "started\n");
9011 
9012 	/*
9013 	 * To be backward compatible with older API
9014 	 * check for the size of old EXT_VPORT_ID_CNT
9015 	 */
9016 	if (cmd->ResponseLen < sizeof (EXT_VPORT_ID_CNT) &&
9017 	    (cmd->ResponseLen != EXT_OLD_VPORT_ID_CNT_SIZE)) {
9018 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9019 		cmd->DetailStatus = sizeof (EXT_VPORT_ID_CNT);
9020 		EL(ha, "failed, ResponseLen < EXT_VPORT_ID_CNT, Len=%xh\n",
9021 		    cmd->ResponseLen);
9022 		cmd->ResponseLen = 0;
9023 		return;
9024 	}
9025 
9026 	ptmp_vp = (EXT_VPORT_ID_CNT *)
9027 	    kmem_zalloc(sizeof (EXT_VPORT_ID_CNT), KM_SLEEP);
9028 	if (ptmp_vp == NULL) {
9029 		EL(ha, "failed, kmem_zalloc\n");
9030 		cmd->ResponseLen = 0;
9031 		return;
9032 	}
9033 	vha = ha->vp_next;
9034 	while (vha != NULL) {
9035 		ptmp_vp->VpCnt++;
9036 		ptmp_vp->VpId[id] = vha->vp_index;
9037 		(void) ddi_pathname(vha->dip, name);
9038 		(void) strncpy((char *)ptmp_vp->vp_path[id], name,
9039 		    (sizeof (ptmp_vp->vp_path[id]) -1));
9040 		ptmp_vp->VpDrvInst[id] = (int32_t)vha->instance;
9041 		id++;
9042 		vha = vha->vp_next;
9043 	}
9044 	rval = ddi_copyout((void *)ptmp_vp,
9045 	    (void *)(uintptr_t)(cmd->ResponseAdr),
9046 	    cmd->ResponseLen, mode);
9047 	if (rval != 0) {
9048 		cmd->Status = EXT_STATUS_COPY_ERR;
9049 		cmd->ResponseLen = 0;
9050 		EL(ha, "failed, ddi_copyout\n");
9051 	} else {
9052 		cmd->ResponseLen = sizeof (EXT_VPORT_ID_CNT);
9053 		QL_PRINT_9(ha, "done, vport_cnt=%d\n",
9054 		    ha->instance, ptmp_vp->VpCnt);
9055 	}
9056 	kmem_free(ptmp_vp, sizeof (EXT_VPORT_ID_CNT));
9057 }
9058 
9059 /*
9060  * ql_vp_ioctl
9061  *	Performs all EXT_CC_VPORT_CMD functions.
9062  *
9063  * Input:
9064  *	ha:	adapter state pointer.
9065  *	cmd:	Local EXT_IOCTL cmd struct pointer.
9066  *	mode:	flags.
9067  *
9068  * Returns:
9069  *	None, request status indicated in cmd->Status.
9070  *
9071  * Context:
9072  *	Kernel context.
9073  */
9074 static void
ql_vp_ioctl(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9075 ql_vp_ioctl(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9076 {
9077 	QL_PRINT_9(ha, "started, cmd=%d\n",
9078 	    cmd->SubCode);
9079 
9080 	/* case off on command subcode */
9081 	switch (cmd->SubCode) {
9082 	case EXT_VF_SC_VPORT_GETINFO:
9083 		ql_qry_vport(ha, cmd, mode);
9084 		break;
9085 	default:
9086 		/* function not supported. */
9087 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
9088 		EL(ha, "failed, Unsupported Subcode=%xh\n",
9089 		    cmd->SubCode);
9090 		break;
9091 	}
9092 
9093 	QL_PRINT_9(ha, "done\n");
9094 }
9095 
9096 /*
9097  * ql_qry_vport
9098  *	Performs EXT_VF_SC_VPORT_GETINFO subfunction.
9099  *
9100  * Input:
9101  *	ha:	adapter state pointer.
9102  *	cmd:	EXT_IOCTL cmd struct pointer.
9103  *	mode:	flags.
9104  *
9105  * Returns:
9106  *	None, request status indicated in cmd->Status.
9107  *
9108  * Context:
9109  *	Kernel context.
9110  */
9111 static void
ql_qry_vport(ql_adapter_state_t * vha,EXT_IOCTL * cmd,int mode)9112 ql_qry_vport(ql_adapter_state_t *vha, EXT_IOCTL *cmd, int mode)
9113 {
9114 	ql_adapter_state_t	*tmp_vha;
9115 	EXT_VPORT_INFO		tmp_vport = {0};
9116 
9117 	QL_PRINT_9(vha, "started\n", vha->instance);
9118 
9119 	if (cmd->ResponseLen < sizeof (EXT_VPORT_INFO)) {
9120 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9121 		cmd->DetailStatus = sizeof (EXT_VPORT_INFO);
9122 		EL(vha, "failed, ResponseLen < EXT_VPORT_INFO, Len=%xh\n",
9123 		    cmd->ResponseLen);
9124 		cmd->ResponseLen = 0;
9125 		return;
9126 	}
9127 
9128 	/* Fill in the vport information. */
9129 	bcopy(vha->loginparams.node_ww_name.raw_wwn, tmp_vport.wwnn,
9130 	    EXT_DEF_WWN_NAME_SIZE);
9131 	bcopy(vha->loginparams.nport_ww_name.raw_wwn, tmp_vport.wwpn,
9132 	    EXT_DEF_WWN_NAME_SIZE);
9133 	tmp_vport.state = vha->state;
9134 	tmp_vport.id = vha->vp_index;
9135 
9136 	tmp_vha = vha->pha->vp_next;
9137 	while (tmp_vha != NULL) {
9138 		tmp_vport.used++;
9139 		tmp_vha = tmp_vha->vp_next;
9140 	}
9141 
9142 	if (vha->max_vports > tmp_vport.used) {
9143 		tmp_vport.free = vha->max_vports - tmp_vport.used;
9144 	}
9145 
9146 	if (ddi_copyout((void *)&tmp_vport,
9147 	    (void *)(uintptr_t)(cmd->ResponseAdr),
9148 	    sizeof (EXT_VPORT_INFO), mode) != 0) {
9149 		cmd->Status = EXT_STATUS_COPY_ERR;
9150 		cmd->ResponseLen = 0;
9151 		EL(vha, "failed, ddi_copyout\n");
9152 	} else {
9153 		cmd->ResponseLen = sizeof (EXT_VPORT_INFO);
9154 		QL_PRINT_9(vha, "done\n", vha->instance);
9155 	}
9156 }
9157 
9158 /*
9159  * ql_access_flash
9160  *	Performs all EXT_CC_ACCESS_FLASH_OS functions.
9161  *
9162  * Input:
9163  *	pi:	port info pointer.
9164  *	cmd:	Local EXT_IOCTL cmd struct pointer.
9165  *	mode:	flags.
9166  *
9167  * Returns:
9168  *	None, request status indicated in cmd->Status.
9169  *
9170  * Context:
9171  *	Kernel context.
9172  */
9173 static void
ql_access_flash(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9174 ql_access_flash(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9175 {
9176 	int	rval;
9177 
9178 	QL_PRINT_9(ha, "started\n");
9179 
9180 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1) &&
9181 	    ql_stall_driver(ha, 0) != QL_SUCCESS) {
9182 		EL(ha, "ql_stall_driver failed\n");
9183 		ql_restart_driver(ha);
9184 		cmd->Status = EXT_STATUS_BUSY;
9185 		cmd->ResponseLen = 0;
9186 		return;
9187 	}
9188 
9189 	switch (cmd->SubCode) {
9190 	case EXT_SC_FLASH_READ:
9191 		if ((rval = ql_flash_fcode_dump(ha,
9192 		    (void *)(uintptr_t)(cmd->ResponseAdr),
9193 		    (size_t)(cmd->ResponseLen), cmd->Reserved1, mode)) != 0) {
9194 			cmd->Status = EXT_STATUS_COPY_ERR;
9195 			cmd->ResponseLen = 0;
9196 			EL(ha, "flash_fcode_dump status=%xh\n", rval);
9197 		}
9198 		break;
9199 	case EXT_SC_FLASH_WRITE:
9200 		if ((rval = ql_r_m_w_flash(ha,
9201 		    (void *)(uintptr_t)(cmd->RequestAdr),
9202 		    (size_t)(cmd->RequestLen), cmd->Reserved1, mode)) !=
9203 		    QL_SUCCESS) {
9204 			cmd->Status = EXT_STATUS_COPY_ERR;
9205 			cmd->ResponseLen = 0;
9206 			EL(ha, "r_m_w_flash status=%xh\n", rval);
9207 		} else {
9208 			/* Reset caches on all adapter instances. */
9209 			ql_update_flash_caches(ha);
9210 		}
9211 		break;
9212 	default:
9213 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9214 		cmd->Status = EXT_STATUS_ERR;
9215 		cmd->ResponseLen = 0;
9216 		break;
9217 	}
9218 
9219 	/* Resume I/O */
9220 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
9221 		EL(ha, "isp_abort_needed for restart\n");
9222 		ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
9223 		    DRIVER_STALL);
9224 	}
9225 
9226 	QL_PRINT_9(ha, "done\n");
9227 }
9228 
9229 /*
9230  * ql_reset_cmd
9231  *	Performs all EXT_CC_RESET_FW_OS functions.
9232  *
9233  * Input:
9234  *	ha:	adapter state pointer.
9235  *	cmd:	Local EXT_IOCTL cmd struct pointer.
9236  *
9237  * Returns:
9238  *	None, request status indicated in cmd->Status.
9239  *
9240  * Context:
9241  *	Kernel context.
9242  */
9243 static void
ql_reset_cmd(ql_adapter_state_t * ha,EXT_IOCTL * cmd)9244 ql_reset_cmd(ql_adapter_state_t *ha, EXT_IOCTL *cmd)
9245 {
9246 	uint8_t	timer;
9247 
9248 	QL_PRINT_9(ha, "started\n");
9249 
9250 	switch (cmd->SubCode) {
9251 	case EXT_SC_RESET_FC_FW:
9252 		if (CFG_IST(ha, CFG_CTRL_82XX)) {
9253 			(void) ql_8021_reset_fw(ha);
9254 		} else {
9255 			EL(ha, "isp_abort_needed\n");
9256 			ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0);
9257 		}
9258 		for (timer = 180; timer; timer--) {
9259 			ql_awaken_task_daemon(ha, NULL, 0, 0);
9260 			/* Delay for 1 second. */
9261 			delay(100);
9262 			if (!(ha->task_daemon_flags & (ISP_ABORT_NEEDED |
9263 			    ABORT_ISP_ACTIVE | LOOP_RESYNC_NEEDED |
9264 			    LOOP_RESYNC_ACTIVE))) {
9265 				break;
9266 			}
9267 		}
9268 		break;
9269 	case EXT_SC_RESET_MPI_FW:
9270 		if (!(CFG_IST(ha, CFG_CTRL_8081))) {
9271 			EL(ha, "invalid request for HBA\n");
9272 			cmd->Status = EXT_STATUS_INVALID_REQUEST;
9273 			cmd->ResponseLen = 0;
9274 		} else {
9275 			ADAPTER_STATE_LOCK(ha);
9276 			ha->flags |= DISABLE_NIC_FW_DMP;
9277 			ADAPTER_STATE_UNLOCK(ha);
9278 
9279 			/* Wait for I/O to stop and daemon to stall. */
9280 			if (ql_suspend_hba(ha, 0) != QL_SUCCESS) {
9281 				EL(ha, "ql_suspend_hba failed\n");
9282 				cmd->Status = EXT_STATUS_BUSY;
9283 				cmd->ResponseLen = 0;
9284 			} else if (ql_restart_mpi(ha) != QL_SUCCESS) {
9285 				cmd->Status = EXT_STATUS_ERR;
9286 				cmd->ResponseLen = 0;
9287 			} else {
9288 				/*
9289 				 * While the restart_mpi mailbox cmd may be
9290 				 * done the MPI is not. Wait at least 6 sec. or
9291 				 * exit if the loop comes up.
9292 				 */
9293 				for (timer = 6; timer; timer--) {
9294 					if (!(ha->task_daemon_flags &
9295 					    LOOP_DOWN)) {
9296 						break;
9297 					}
9298 					/* Delay for 1 second. */
9299 					ql_delay(ha, 1000000);
9300 				}
9301 			}
9302 			ql_restart_hba(ha);
9303 
9304 			ADAPTER_STATE_LOCK(ha);
9305 			ha->flags &= ~DISABLE_NIC_FW_DMP;
9306 			ADAPTER_STATE_UNLOCK(ha);
9307 		}
9308 		break;
9309 	default:
9310 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9311 		cmd->Status = EXT_STATUS_ERR;
9312 		cmd->ResponseLen = 0;
9313 		break;
9314 	}
9315 
9316 	QL_PRINT_9(ha, "done\n");
9317 }
9318 
9319 /*
9320  * ql_get_dcbx_parameters
9321  *	Get DCBX parameters.
9322  *
9323  * Input:
9324  *	ha:	adapter state pointer.
9325  *	cmd:	User space CT arguments pointer.
9326  *	mode:	flags.
9327  */
9328 static void
ql_get_dcbx_parameters(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9329 ql_get_dcbx_parameters(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9330 {
9331 	uint8_t		*tmp_buf;
9332 	int		rval;
9333 
9334 	QL_PRINT_9(ha, "started\n");
9335 
9336 	if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
9337 		EL(ha, "invalid request for HBA\n");
9338 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
9339 		cmd->ResponseLen = 0;
9340 		return;
9341 	}
9342 
9343 	/* Allocate memory for command. */
9344 	tmp_buf = kmem_zalloc(EXT_DEF_DCBX_PARAM_BUF_SIZE, KM_SLEEP);
9345 	if (tmp_buf == NULL) {
9346 		EL(ha, "failed, kmem_zalloc\n");
9347 		cmd->Status = EXT_STATUS_NO_MEMORY;
9348 		cmd->ResponseLen = 0;
9349 		return;
9350 	}
9351 	/* Send command */
9352 	rval = ql_get_dcbx_params(ha, EXT_DEF_DCBX_PARAM_BUF_SIZE,
9353 	    (caddr_t)tmp_buf);
9354 	if (rval != QL_SUCCESS) {
9355 		/* error */
9356 		EL(ha, "failed, get_dcbx_params_mbx=%xh\n", rval);
9357 		kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE);
9358 		cmd->Status = EXT_STATUS_ERR;
9359 		cmd->ResponseLen = 0;
9360 		return;
9361 	}
9362 
9363 	/* Copy the response */
9364 	if (ql_send_buffer_data((caddr_t)tmp_buf,
9365 	    (caddr_t)(uintptr_t)cmd->ResponseAdr,
9366 	    EXT_DEF_DCBX_PARAM_BUF_SIZE, mode) != EXT_DEF_DCBX_PARAM_BUF_SIZE) {
9367 		EL(ha, "failed, ddi_copyout\n");
9368 		cmd->Status = EXT_STATUS_COPY_ERR;
9369 		cmd->ResponseLen = 0;
9370 	} else {
9371 		cmd->ResponseLen = EXT_DEF_DCBX_PARAM_BUF_SIZE;
9372 		QL_PRINT_9(ha, "done\n");
9373 	}
9374 	kmem_free(tmp_buf, EXT_DEF_DCBX_PARAM_BUF_SIZE);
9375 
9376 }
9377 
9378 /*
9379  * ql_qry_cna_port
9380  *	Performs EXT_SC_QUERY_CNA_PORT subfunction.
9381  *
9382  * Input:
9383  *	ha:	adapter state pointer.
9384  *	cmd:	EXT_IOCTL cmd struct pointer.
9385  *	mode:	flags.
9386  *
9387  * Returns:
9388  *	None, request status indicated in cmd->Status.
9389  *
9390  * Context:
9391  *	Kernel context.
9392  */
9393 static void
ql_qry_cna_port(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9394 ql_qry_cna_port(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9395 {
9396 	EXT_CNA_PORT	cna_port = {0};
9397 
9398 	QL_PRINT_9(ha, "started\n");
9399 
9400 	if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
9401 		EL(ha, "invalid request for HBA\n");
9402 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
9403 		cmd->ResponseLen = 0;
9404 		return;
9405 	}
9406 
9407 	if (cmd->ResponseLen < sizeof (EXT_CNA_PORT)) {
9408 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9409 		cmd->DetailStatus = sizeof (EXT_CNA_PORT);
9410 		EL(ha, "failed, ResponseLen < EXT_CNA_PORT, Len=%xh\n",
9411 		    cmd->ResponseLen);
9412 		cmd->ResponseLen = 0;
9413 		return;
9414 	}
9415 
9416 	cna_port.VLanId = ha->fcoe_vlan_id;
9417 	cna_port.FabricParam = ha->fabric_params;
9418 	bcopy(ha->fcoe_vnport_mac, cna_port.VNPortMACAddress,
9419 	    EXT_DEF_MAC_ADDRESS_SIZE);
9420 
9421 	if (ddi_copyout((void *)&cna_port,
9422 	    (void *)(uintptr_t)(cmd->ResponseAdr),
9423 	    sizeof (EXT_CNA_PORT), mode) != 0) {
9424 		cmd->Status = EXT_STATUS_COPY_ERR;
9425 		cmd->ResponseLen = 0;
9426 		EL(ha, "failed, ddi_copyout\n");
9427 	} else {
9428 		cmd->ResponseLen = sizeof (EXT_CNA_PORT);
9429 		QL_PRINT_9(ha, "done\n");
9430 	}
9431 }
9432 
9433 /*
9434  * ql_qry_adapter_versions
9435  *	Performs EXT_SC_QUERY_ADAPTER_VERSIONS subfunction.
9436  *
9437  * Input:
9438  *	ha:	adapter state pointer.
9439  *	cmd:	EXT_IOCTL cmd struct pointer.
9440  *	mode:	flags.
9441  *
9442  * Returns:
9443  *	None, request status indicated in cmd->Status.
9444  *
9445  * Context:
9446  *	Kernel context.
9447  */
9448 static void
ql_qry_adapter_versions(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9449 ql_qry_adapter_versions(ql_adapter_state_t *ha, EXT_IOCTL *cmd,
9450     int mode)
9451 {
9452 	uint8_t				is_8142, mpi_cap;
9453 	uint32_t			ver_len, transfer_size;
9454 	PEXT_ADAPTERREGIONVERSION	padapter_ver = NULL;
9455 
9456 	QL_PRINT_9(ha, "started\n");
9457 
9458 	/* 8142s do not have a EDC PHY firmware. */
9459 	mpi_cap = (uint8_t)(ha->mpi_capability_list >> 8);
9460 
9461 	is_8142 = 0;
9462 	/* Sizeof (Length + Reserved) = 8 Bytes */
9463 	if (mpi_cap == 0x02 || mpi_cap == 0x04) {
9464 		ver_len = (sizeof (EXT_REGIONVERSION) * (NO_OF_VERSIONS - 1))
9465 		    + 8;
9466 		is_8142 = 1;
9467 	} else {
9468 		ver_len = (sizeof (EXT_REGIONVERSION) * NO_OF_VERSIONS) + 8;
9469 	}
9470 
9471 	/* Allocate local memory for EXT_ADAPTERREGIONVERSION */
9472 	padapter_ver = (EXT_ADAPTERREGIONVERSION *)kmem_zalloc(ver_len,
9473 	    KM_SLEEP);
9474 
9475 	if (padapter_ver == NULL) {
9476 		EL(ha, "failed, kmem_zalloc\n");
9477 		cmd->Status = EXT_STATUS_NO_MEMORY;
9478 		cmd->ResponseLen = 0;
9479 		return;
9480 	}
9481 
9482 	padapter_ver->Length = 1;
9483 	/* Copy MPI version */
9484 	padapter_ver->RegionVersion[0].Region =
9485 	    EXT_OPT_ROM_REGION_MPI_RISC_FW;
9486 	padapter_ver->RegionVersion[0].Version[0] =
9487 	    ha->mpi_fw_major_version;
9488 	padapter_ver->RegionVersion[0].Version[1] =
9489 	    ha->mpi_fw_minor_version;
9490 	padapter_ver->RegionVersion[0].Version[2] =
9491 	    ha->mpi_fw_subminor_version;
9492 	padapter_ver->RegionVersion[0].VersionLength = 3;
9493 	padapter_ver->RegionVersion[0].Location = RUNNING_VERSION;
9494 
9495 	if (!is_8142) {
9496 		padapter_ver->RegionVersion[1].Region =
9497 		    EXT_OPT_ROM_REGION_EDC_PHY_FW;
9498 		padapter_ver->RegionVersion[1].Version[0] =
9499 		    ha->phy_fw_major_version;
9500 		padapter_ver->RegionVersion[1].Version[1] =
9501 		    ha->phy_fw_minor_version;
9502 		padapter_ver->RegionVersion[1].Version[2] =
9503 		    ha->phy_fw_subminor_version;
9504 		padapter_ver->RegionVersion[1].VersionLength = 3;
9505 		padapter_ver->RegionVersion[1].Location = RUNNING_VERSION;
9506 		padapter_ver->Length = NO_OF_VERSIONS;
9507 	}
9508 
9509 	if (cmd->ResponseLen < ver_len) {
9510 		EL(ha, "failed, ResponseLen < ver_len, ",
9511 		    "RespLen=%xh ver_len=%xh\n", cmd->ResponseLen, ver_len);
9512 		/* Calculate the No. of valid versions being returned. */
9513 		padapter_ver->Length = (uint32_t)
9514 		    ((cmd->ResponseLen - 8) / sizeof (EXT_REGIONVERSION));
9515 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9516 		cmd->DetailStatus = ver_len;
9517 		transfer_size = cmd->ResponseLen;
9518 	} else {
9519 		transfer_size = ver_len;
9520 	}
9521 
9522 	if (ddi_copyout((void *)padapter_ver,
9523 	    (void *)(uintptr_t)(cmd->ResponseAdr),
9524 	    transfer_size, mode) != 0) {
9525 		cmd->Status = EXT_STATUS_COPY_ERR;
9526 		cmd->ResponseLen = 0;
9527 		EL(ha, "failed, ddi_copyout\n");
9528 	} else {
9529 		cmd->ResponseLen = ver_len;
9530 		QL_PRINT_9(ha, "done\n");
9531 	}
9532 
9533 	kmem_free(padapter_ver, ver_len);
9534 }
9535 
9536 /*
9537  * ql_get_xgmac_statistics
9538  *	Get XgMac information
9539  *
9540  * Input:
9541  *	ha:	adapter state pointer.
9542  *	cmd:	EXT_IOCTL cmd struct pointer.
9543  *	mode:	flags.
9544  *
9545  * Returns:
9546  *	None, request status indicated in cmd->Status.
9547  *
9548  * Context:
9549  *	Kernel context.
9550  */
9551 static void
ql_get_xgmac_statistics(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9552 ql_get_xgmac_statistics(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9553 {
9554 	int			rval;
9555 	uint32_t		size;
9556 	int8_t			*tmp_buf;
9557 	EXT_MENLO_MANAGE_INFO	info;
9558 
9559 	QL_PRINT_9(ha, "started\n");
9560 
9561 	/*  Verify the size of request structure. */
9562 	if (cmd->RequestLen < sizeof (EXT_MENLO_MANAGE_INFO)) {
9563 		/* Return error */
9564 		EL(ha, "RequestLen=%d < %d\n", cmd->RequestLen,
9565 		    sizeof (EXT_MENLO_MANAGE_INFO));
9566 		cmd->Status = EXT_STATUS_INVALID_PARAM;
9567 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
9568 		cmd->ResponseLen = 0;
9569 		return;
9570 	}
9571 
9572 	/* Get manage info request. */
9573 	if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
9574 	    (caddr_t)&info, sizeof (EXT_MENLO_MANAGE_INFO), mode) != 0) {
9575 		EL(ha, "failed, ddi_copyin\n");
9576 		cmd->Status = EXT_STATUS_COPY_ERR;
9577 		cmd->ResponseLen = 0;
9578 		return;
9579 	}
9580 
9581 	size = info.TotalByteCount;
9582 	if (!size) {
9583 		/* parameter error */
9584 		cmd->Status = EXT_STATUS_INVALID_PARAM;
9585 		cmd->DetailStatus = 0;
9586 		EL(ha, "failed, size=%xh\n", size);
9587 		cmd->ResponseLen = 0;
9588 		return;
9589 	}
9590 
9591 	/* Allocate memory for command. */
9592 	tmp_buf = kmem_zalloc(size, KM_SLEEP);
9593 	if (tmp_buf == NULL) {
9594 		EL(ha, "failed, kmem_zalloc\n");
9595 		cmd->Status = EXT_STATUS_NO_MEMORY;
9596 		cmd->ResponseLen = 0;
9597 		return;
9598 	}
9599 
9600 	if (!(info.Operation & MENLO_OP_GET_INFO)) {
9601 		EL(ha, "Invalid request for 81XX\n");
9602 		kmem_free(tmp_buf, size);
9603 		cmd->Status = EXT_STATUS_ERR;
9604 		cmd->ResponseLen = 0;
9605 		return;
9606 	}
9607 
9608 	rval = ql_get_xgmac_stats(ha, size, (caddr_t)tmp_buf);
9609 
9610 	if (rval != QL_SUCCESS) {
9611 		/* error */
9612 		EL(ha, "failed, get_xgmac_stats =%xh\n", rval);
9613 		kmem_free(tmp_buf, size);
9614 		cmd->Status = EXT_STATUS_ERR;
9615 		cmd->ResponseLen = 0;
9616 		return;
9617 	}
9618 
9619 	if (ql_send_buffer_data(tmp_buf, (caddr_t)(uintptr_t)info.pDataBytes,
9620 	    size, mode) != size) {
9621 		EL(ha, "failed, ddi_copyout\n");
9622 		cmd->Status = EXT_STATUS_COPY_ERR;
9623 		cmd->ResponseLen = 0;
9624 	} else {
9625 		cmd->ResponseLen = info.TotalByteCount;
9626 		QL_PRINT_9(ha, "done\n");
9627 	}
9628 	kmem_free(tmp_buf, size);
9629 	QL_PRINT_9(ha, "done\n");
9630 }
9631 
9632 /*
9633  * ql_get_fcf_list
9634  *	Get FCF list.
9635  *
9636  * Input:
9637  *	ha:	adapter state pointer.
9638  *	cmd:	User space CT arguments pointer.
9639  *	mode:	flags.
9640  */
9641 static void
ql_get_fcf_list(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9642 ql_get_fcf_list(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9643 {
9644 	uint8_t			*tmp_buf;
9645 	int			rval;
9646 	EXT_FCF_LIST		fcf_list = {0};
9647 	ql_fcf_list_desc_t	mb_fcf_list = {0};
9648 
9649 	QL_PRINT_9(ha, "started\n");
9650 
9651 	if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
9652 		EL(ha, "invalid request for HBA\n");
9653 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
9654 		cmd->ResponseLen = 0;
9655 		return;
9656 	}
9657 	/* Get manage info request. */
9658 	if (ddi_copyin((caddr_t)(uintptr_t)cmd->RequestAdr,
9659 	    (caddr_t)&fcf_list, sizeof (EXT_FCF_LIST), mode) != 0) {
9660 		EL(ha, "failed, ddi_copyin\n");
9661 		cmd->Status = EXT_STATUS_COPY_ERR;
9662 		cmd->ResponseLen = 0;
9663 		return;
9664 	}
9665 
9666 	if (!(fcf_list.BufSize)) {
9667 		/* Return error */
9668 		EL(ha, "failed, fcf_list BufSize is=%xh\n",
9669 		    fcf_list.BufSize);
9670 		cmd->Status = EXT_STATUS_INVALID_PARAM;
9671 		cmd->ResponseLen = 0;
9672 		return;
9673 	}
9674 	/* Allocate memory for command. */
9675 	tmp_buf = kmem_zalloc(fcf_list.BufSize, KM_SLEEP);
9676 	if (tmp_buf == NULL) {
9677 		EL(ha, "failed, kmem_zalloc\n");
9678 		cmd->Status = EXT_STATUS_NO_MEMORY;
9679 		cmd->ResponseLen = 0;
9680 		return;
9681 	}
9682 	/* build the descriptor */
9683 	if (fcf_list.Options) {
9684 		mb_fcf_list.options = FCF_LIST_RETURN_ONE;
9685 	} else {
9686 		mb_fcf_list.options = FCF_LIST_RETURN_ALL;
9687 	}
9688 	mb_fcf_list.fcf_index = (uint16_t)fcf_list.FcfIndex;
9689 	mb_fcf_list.buffer_size = fcf_list.BufSize;
9690 
9691 	/* Send command */
9692 	rval = ql_get_fcf_list_mbx(ha, &mb_fcf_list, (caddr_t)tmp_buf);
9693 	if (rval != QL_SUCCESS) {
9694 		/* error */
9695 		EL(ha, "failed, get_fcf_list_mbx=%xh\n", rval);
9696 		kmem_free(tmp_buf, fcf_list.BufSize);
9697 		cmd->Status = EXT_STATUS_ERR;
9698 		cmd->ResponseLen = 0;
9699 		return;
9700 	}
9701 
9702 	/* Copy the response */
9703 	if (ql_send_buffer_data((caddr_t)tmp_buf,
9704 	    (caddr_t)(uintptr_t)cmd->ResponseAdr,
9705 	    fcf_list.BufSize, mode) != fcf_list.BufSize) {
9706 		EL(ha, "failed, ddi_copyout\n");
9707 		cmd->Status = EXT_STATUS_COPY_ERR;
9708 		cmd->ResponseLen = 0;
9709 	} else {
9710 		cmd->ResponseLen = mb_fcf_list.buffer_size;
9711 		QL_PRINT_9(ha, "done\n");
9712 	}
9713 
9714 	kmem_free(tmp_buf, fcf_list.BufSize);
9715 }
9716 
9717 /*
9718  * ql_get_resource_counts
9719  *	Get Resource counts:
9720  *
9721  * Input:
9722  *	ha:	adapter state pointer.
9723  *	cmd:	User space CT arguments pointer.
9724  *	mode:	flags.
9725  */
9726 static void
ql_get_resource_counts(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9727 ql_get_resource_counts(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9728 {
9729 	int			rval;
9730 	ql_mbx_data_t		mr;
9731 	EXT_RESOURCE_CNTS	tmp_rc_cnt = {0};
9732 
9733 	QL_PRINT_9(ha, "started\n");
9734 
9735 	if (cmd->ResponseLen < sizeof (EXT_RESOURCE_CNTS)) {
9736 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9737 		cmd->DetailStatus = sizeof (EXT_RESOURCE_CNTS);
9738 		EL(ha, "failed, ResponseLen < EXT_RESOURCE_CNTS, "
9739 		    "Len=%xh\n", cmd->ResponseLen);
9740 		cmd->ResponseLen = 0;
9741 		return;
9742 	}
9743 
9744 	rval = ql_get_resource_cnts(ha, &mr);
9745 	if (rval != QL_SUCCESS) {
9746 		EL(ha, "resource cnt mbx failed\n");
9747 		cmd->Status = EXT_STATUS_ERR;
9748 		cmd->ResponseLen = 0;
9749 		return;
9750 	}
9751 
9752 	tmp_rc_cnt.OrgTgtXchgCtrlCnt = (uint32_t)mr.mb[1];
9753 	tmp_rc_cnt.CurTgtXchgCtrlCnt = (uint32_t)mr.mb[2];
9754 	tmp_rc_cnt.CurXchgCtrlCnt = (uint32_t)mr.mb[3];
9755 	tmp_rc_cnt.OrgXchgCtrlCnt = (uint32_t)mr.mb[6];
9756 	tmp_rc_cnt.CurIocbBufCnt = (uint32_t)mr.mb[7];
9757 	tmp_rc_cnt.OrgIocbBufCnt = (uint32_t)mr.mb[10];
9758 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
9759 		tmp_rc_cnt.NoOfSupVPs = (uint32_t)mr.mb[11];
9760 	}
9761 	if (CFG_IST(ha, CFG_FCOE_SUPPORT)) {
9762 		tmp_rc_cnt.NoOfSupFCFs = (uint32_t)mr.mb[12];
9763 	}
9764 
9765 	rval = ddi_copyout((void *)&tmp_rc_cnt,
9766 	    (void *)(uintptr_t)(cmd->ResponseAdr),
9767 	    sizeof (EXT_RESOURCE_CNTS), mode);
9768 	if (rval != 0) {
9769 		cmd->Status = EXT_STATUS_COPY_ERR;
9770 		cmd->ResponseLen = 0;
9771 		EL(ha, "failed, ddi_copyout\n");
9772 	} else {
9773 		cmd->ResponseLen = sizeof (EXT_RESOURCE_CNTS);
9774 		QL_PRINT_9(ha, "done\n");
9775 	}
9776 }
9777 
9778 /*
9779  * ql_get_temperature
9780  *	Get ASIC temperature data
9781  *
9782  * Input:
9783  *	ha:	adapter state pointer.
9784  *	cmd:	EXT_IOCTL cmd struct pointer.
9785  *	mode:	flags
9786  *
9787  * Returns:
9788  *	None, request status indicated in cmd->Status.
9789  *
9790  * Context:
9791  *	Kernel context.
9792  */
9793 static void
ql_get_temperature(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9794 ql_get_temperature(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9795 {
9796 	ql_mbx_data_t	mr;
9797 	int		rval = 0;
9798 	EXT_BOARD_TEMP	board_temp = {0};
9799 
9800 	QL_PRINT_9(ha, "started\n");
9801 
9802 	if (!(ha->fw_ext_attributes & TEMP_SUPPORT_ISP)) {
9803 		EL(ha, "invalid request for HBA\n");
9804 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
9805 		cmd->ResponseLen = 0;
9806 		return;
9807 	}
9808 
9809 	if (cmd->ResponseLen < sizeof (EXT_BOARD_TEMP)) {
9810 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9811 		cmd->DetailStatus = sizeof (EXT_BOARD_TEMP);
9812 		EL(ha, "failed, ResponseLen < EXT_BOARD_TEMP, "
9813 		    "Len=%xh \n", cmd->ResponseLen);
9814 		cmd->ResponseLen = 0;
9815 		return;
9816 	}
9817 
9818 	switch (cmd->SubCode) {
9819 	case EXT_SC_GET_BOARD_TEMP:
9820 		rval = ql_get_temp(ha, &mr);
9821 		if (rval != QL_SUCCESS) {
9822 			/* error */
9823 			EL(ha, "failed, get_temperature_mbx=%xh\n", rval);
9824 			cmd->Status = EXT_STATUS_ERR;
9825 			cmd->ResponseLen = 0;
9826 			break;
9827 		}
9828 		board_temp.IntTemp = mr.mb[1];
9829 
9830 		rval = ddi_copyout((void *)&board_temp,
9831 		    (void *)(uintptr_t)(cmd->ResponseAdr),
9832 		    sizeof (EXT_BOARD_TEMP), mode);
9833 		if (rval != 0) {
9834 			cmd->Status = EXT_STATUS_COPY_ERR;
9835 			cmd->ResponseLen = 0;
9836 			EL(ha, "failed, ddi_copyout\n");
9837 		} else {
9838 			cmd->ResponseLen = sizeof (EXT_BOARD_TEMP);
9839 		}
9840 		break;
9841 	default:
9842 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9843 		cmd->Status = EXT_STATUS_ERR;
9844 		cmd->ResponseLen = 0;
9845 		break;
9846 	}
9847 
9848 	QL_PRINT_9(ha, "done\n");
9849 }
9850 
9851 /*
9852  * ql_dump_cmd
9853  *	Performs all EXT_CC_DUMP_OS functions.
9854  *
9855  * Input:
9856  *	ha:	adapter state pointer.
9857  *	cmd:	Local EXT_IOCTL cmd struct pointer.
9858  *
9859  * Returns:
9860  *	None, request status indicated in cmd->Status.
9861  *
9862  * Context:
9863  *	Kernel context.
9864  */
9865 static void
ql_dump_cmd(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9866 ql_dump_cmd(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9867 {
9868 	caddr_t		dump;
9869 	uint32_t	sdm_valid_dump = 0;
9870 	int		rval = 0;
9871 
9872 	QL_PRINT_9(ha, "started\n");
9873 
9874 	if (ha->ql_dump_state & QL_DUMP_VALID &&
9875 	    !(ha->ql_dump_state & QL_DUMP_UPLOADED) &&
9876 	    ha->ql_dump_state != 0) {
9877 		sdm_valid_dump = 1;
9878 	} else {
9879 		EL(ha, "dump does not exist for instance %d (%x, %p)\n",
9880 		    ha->instance, ha->ql_dump_state, ha->ql_dump_ptr);
9881 	}
9882 
9883 	cmd->Status = EXT_STATUS_OK;
9884 	cmd->DetailStatus = 0;
9885 
9886 	switch (cmd->SubCode) {
9887 	case EXT_SC_DUMP_SIZE:
9888 		cmd->ResponseLen = 0;
9889 		if (sdm_valid_dump) {
9890 			cmd->DetailStatus = ha->risc_dump_size;
9891 		}
9892 		break;
9893 	case EXT_SC_DUMP_READ:
9894 		if (!sdm_valid_dump) {
9895 			cmd->Status = EXT_STATUS_INVALID_REQUEST;
9896 			cmd->ResponseLen = 0;
9897 			break;
9898 		}
9899 
9900 		if (cmd->ResponseLen < ha->risc_dump_size) {
9901 			cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
9902 			cmd->DetailStatus = ha->risc_dump_size;
9903 			EL(ha, "failed, ResponseLen < %x, "
9904 			    "Len=%xh\n", ha->risc_dump_size,
9905 			    cmd->ResponseLen);
9906 			break;
9907 		}
9908 
9909 		ADAPTER_STATE_LOCK(ha);
9910 		ha->flags |= DISABLE_NIC_FW_DMP;
9911 		ADAPTER_STATE_UNLOCK(ha);
9912 
9913 		QL_DUMP_LOCK(ha);
9914 
9915 		dump = kmem_zalloc(ha->risc_dump_size, KM_SLEEP);
9916 		cmd->ResponseLen = (uint32_t)ql_ascii_fw_dump(ha, dump);
9917 
9918 		if ((rval = ddi_copyout((void *)dump,
9919 		    (void *)(uintptr_t)(cmd->ResponseAdr), cmd->ResponseLen,
9920 		    mode)) != 0) {
9921 			ha->ql_dump_state &= ~QL_DUMP_UPLOADED;
9922 			EL(ha, "failed, ddi_copyout\n");
9923 			cmd->Status = EXT_STATUS_COPY_ERR;
9924 			cmd->ResponseLen = 0;
9925 		} else {
9926 			ha->ql_dump_state |= QL_DUMP_UPLOADED;
9927 		}
9928 
9929 		kmem_free(dump, ha->risc_dump_size);
9930 
9931 		QL_DUMP_UNLOCK(ha);
9932 
9933 		ADAPTER_STATE_LOCK(ha);
9934 		ha->flags &= ~DISABLE_NIC_FW_DMP;
9935 		ADAPTER_STATE_UNLOCK(ha);
9936 		break;
9937 	case EXT_SC_DUMP_TRIGGER:
9938 		cmd->ResponseLen = 0;
9939 
9940 		ADAPTER_STATE_LOCK(ha);
9941 		ha->flags |= DISABLE_NIC_FW_DMP;
9942 		ADAPTER_STATE_UNLOCK(ha);
9943 
9944 		if (sdm_valid_dump) {
9945 			cmd->Status = EXT_STATUS_INVALID_REQUEST;
9946 			EL(ha, "Existing dump file needs to be retrieved.\n");
9947 		} else {
9948 			rval = ql_dump_firmware(ha);
9949 
9950 			if (rval != QL_SUCCESS && rval != QL_DATA_EXISTS) {
9951 				cmd->Status = EXT_STATUS_ERR;
9952 			}
9953 		}
9954 
9955 		ADAPTER_STATE_LOCK(ha);
9956 		ha->flags &= ~DISABLE_NIC_FW_DMP;
9957 		ADAPTER_STATE_UNLOCK(ha);
9958 		break;
9959 	default:
9960 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
9961 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
9962 		cmd->ResponseLen = 0;
9963 		break;
9964 	}
9965 
9966 	QL_PRINT_9(ha, "done\n");
9967 }
9968 
9969 /*
9970  * ql_serdes_reg
9971  *	Performs all EXT_CC_SERDES_REG_OP functions.
9972  *
9973  * Input:
9974  *	ha:	adapter state pointer.
9975  *	cmd:	EXT_IOCTL cmd struct pointer.
9976  *	mode:	flags
9977  *
9978  * Returns:
9979  *	None, request status indicated in cmd->Status.
9980  *
9981  * Context:
9982  *	Kernel context.
9983  */
9984 static void
ql_serdes_reg(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)9985 ql_serdes_reg(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
9986 {
9987 	ql_mbx_data_t	mr = {0};
9988 	int		rval = 0;
9989 	EXT_SERDES_REG	serdes_reg = {0};
9990 
9991 	QL_PRINT_9(ha, "started\n");
9992 
9993 	/* Check if request valid for HBA */
9994 	if (!(CFG_IST(ha, CFG_SERDES_SUPPORT))) {
9995 		EL(ha, "invalid request for HBA\n");
9996 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
9997 		cmd->ResponseLen = 0;
9998 		return;
9999 	}
10000 
10001 	/* Copy in the request structure. */
10002 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
10003 	    (void *)&serdes_reg, sizeof (EXT_SERDES_REG), mode) != 0) {
10004 		EL(ha, "failed, ddi_copyin\n");
10005 		cmd->Status = EXT_STATUS_COPY_ERR;
10006 		cmd->ResponseLen = 0;
10007 		return;
10008 	}
10009 
10010 	switch (cmd->SubCode) {
10011 	case EXT_SC_WRITE_SERDES_REG:
10012 		mr.mb[1] = serdes_reg.addr;
10013 		mr.mb[2] = LSB(serdes_reg.val);
10014 		mr.mb[3] = 0;
10015 		mr.mb[4] = MSB(serdes_reg.val);
10016 		if ((rval = ql_write_serdes(ha, &mr)) != QL_SUCCESS) {
10017 			/* error */
10018 			EL(ha, "failed, write_serdes_mbx=%xh\n", rval);
10019 			cmd->Status = EXT_STATUS_ERR;
10020 			cmd->ResponseLen = 0;
10021 			break;
10022 		} else {
10023 			cmd->Status = EXT_STATUS_OK;
10024 		}
10025 		break;
10026 	case EXT_SC_READ_SERDES_REG:
10027 		/* Verify the size of response structure. */
10028 		if (cmd->ResponseLen < sizeof (EXT_SERDES_REG)) {
10029 			cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10030 			cmd->DetailStatus = sizeof (EXT_SERDES_REG);
10031 			EL(ha, "failed, ResponseLen < EXT_SERDES_REG, "
10032 			    "Len=%xh \n", cmd->ResponseLen);
10033 			cmd->ResponseLen = 0;
10034 			break;
10035 		}
10036 		mr.mb[1] = serdes_reg.addr;
10037 		if ((rval = ql_read_serdes(ha, &mr)) != QL_SUCCESS) {
10038 			/* error */
10039 			EL(ha, "failed, read_serdes_mbx=%xh\n", rval);
10040 			cmd->Status = EXT_STATUS_ERR;
10041 			cmd->ResponseLen = 0;
10042 			break;
10043 		}
10044 		serdes_reg.val = CHAR_TO_SHORT(LSB(mr.mb[1]), LSB(mr.mb[2]));
10045 		/* Copy back the response data */
10046 		if (ddi_copyout((void *)&serdes_reg,
10047 		    (void *)(uintptr_t)(cmd->ResponseAdr),
10048 		    sizeof (EXT_SERDES_REG), mode) != 0) {
10049 			cmd->Status = EXT_STATUS_COPY_ERR;
10050 			cmd->ResponseLen = 0;
10051 			EL(ha, "failed, ddi_copyout\n");
10052 		} else {
10053 			cmd->Status = EXT_STATUS_OK;
10054 			cmd->ResponseLen = sizeof (EXT_SERDES_REG);
10055 		}
10056 		break;
10057 	default:
10058 		/* Subcode not supported. */
10059 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
10060 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
10061 		cmd->ResponseLen = 0;
10062 		break;
10063 	}
10064 
10065 	QL_PRINT_9(ha, "done\n");
10066 }
10067 
10068 /*
10069  * ql_serdes_reg_ex
10070  *	Performs all EXT_CC_SERDES_REG_OP_EX functions.
10071  *
10072  * Input:
10073  *	ha:	adapter state pointer.
10074  *	cmd:	EXT_IOCTL cmd struct pointer.
10075  *	mode:	flags
10076  *
10077  * Returns:
10078  *	None, request status indicated in cmd->Status.
10079  *
10080  * Context:
10081  *	Kernel context.
10082  */
10083 static void
ql_serdes_reg_ex(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)10084 ql_serdes_reg_ex(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10085 {
10086 	ql_mbx_data_t		mr = {0};
10087 	int			rval = 0;
10088 	EXT_SERDES_REG_EX	serdes_reg_ex = {0};
10089 
10090 	QL_PRINT_9(ha, "started\n");
10091 
10092 	/* Check if request valid for HBA */
10093 	if (!(CFG_IST(ha, CFG_SERDES_SUPPORT))) {
10094 		EL(ha, "invalid request for HBA\n");
10095 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
10096 		cmd->ResponseLen = 0;
10097 		return;
10098 	}
10099 
10100 	/* Copy in the request structure. */
10101 	if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
10102 	    (void *)&serdes_reg_ex, sizeof (EXT_SERDES_REG_EX), mode) != 0) {
10103 		EL(ha, "failed, ddi_copyin\n");
10104 		cmd->Status = EXT_STATUS_COPY_ERR;
10105 		cmd->ResponseLen = 0;
10106 		return;
10107 	}
10108 
10109 	switch (cmd->SubCode) {
10110 	case EXT_SC_WRITE_SERDES_REG:
10111 		mr.mb[3] = LSW(serdes_reg_ex.addr);
10112 		mr.mb[4] = MSW(serdes_reg_ex.addr);
10113 		mr.mb[5] = LSW(serdes_reg_ex.val);
10114 		mr.mb[6] = MSW(serdes_reg_ex.val);
10115 		if ((rval = ql_write_serdes(ha, &mr)) != QL_SUCCESS) {
10116 			/* error */
10117 			EL(ha, "failed, write_serdes_mbx=%xh\n", rval);
10118 			cmd->Status = EXT_STATUS_ERR;
10119 			cmd->ResponseLen = 0;
10120 			break;
10121 		} else {
10122 			cmd->Status = EXT_STATUS_OK;
10123 		}
10124 		break;
10125 	case EXT_SC_READ_SERDES_REG:
10126 		/* Verify the size of response structure. */
10127 		if (cmd->ResponseLen < sizeof (EXT_SERDES_REG_EX)) {
10128 			cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10129 			cmd->DetailStatus = sizeof (EXT_SERDES_REG_EX);
10130 			EL(ha, "failed, ResponseLen < EXT_SERDES_REG_EX, "
10131 			    "Len=%xh\n", cmd->ResponseLen);
10132 			cmd->ResponseLen = 0;
10133 			break;
10134 		}
10135 		mr.mb[3] = LSW(serdes_reg_ex.addr);
10136 		mr.mb[4] = MSW(serdes_reg_ex.addr);
10137 		if ((rval = ql_read_serdes(ha, &mr)) != QL_SUCCESS) {
10138 			/* error */
10139 			EL(ha, "failed, read_serdes_mbx=%xh\n", rval);
10140 			cmd->Status = EXT_STATUS_ERR;
10141 			cmd->ResponseLen = 0;
10142 			break;
10143 		}
10144 		serdes_reg_ex.val = SHORT_TO_LONG(mr.mb[1], mr.mb[2]);
10145 		/* Copy back the response data */
10146 		if (ddi_copyout((void *)&serdes_reg_ex,
10147 		    (void *)(uintptr_t)(cmd->ResponseAdr),
10148 		    sizeof (EXT_SERDES_REG_EX), mode) != 0) {
10149 			cmd->Status = EXT_STATUS_COPY_ERR;
10150 			cmd->ResponseLen = 0;
10151 			EL(ha, "failed, ddi_copyout\n");
10152 		} else {
10153 			cmd->Status = EXT_STATUS_OK;
10154 			cmd->ResponseLen = sizeof (EXT_SERDES_REG_EX);
10155 		}
10156 		break;
10157 	default:
10158 		/* Subcode not supported. */
10159 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
10160 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
10161 		cmd->ResponseLen = 0;
10162 		break;
10163 	}
10164 
10165 	QL_PRINT_9(ha, "done\n");
10166 }
10167 
10168 /*
10169  * ql_els_passthru
10170  *	IOCTL for extended link service passthru command.
10171  *
10172  * Input:
10173  *	ha:	adapter state pointer.
10174  *	cmd:	User space CT arguments pointer.
10175  *	mode:	flags.
10176  *
10177  * Returns:
10178  *	None, request status indicated in cmd->Status.
10179  *
10180  * Context:
10181  *	Kernel context.
10182  */
10183 static void
ql_els_passthru(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)10184 ql_els_passthru(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10185 {
10186 	ql_mbx_iocb_t		*pkt;
10187 	dma_mem_t		*dma_mem;
10188 	caddr_t			bp, pld;
10189 	uint32_t		pkt_size, pld_byte_cnt, cmd_size, *long_ptr;
10190 	EXT_ELS_PT_REQ		*pt_req;
10191 	boolean_t		local_hba = B_FALSE;
10192 	ql_tgt_t		*tq = NULL;
10193 	port_id_t		tmp_fcid;
10194 	int			rval;
10195 	uint16_t		comp_status;
10196 
10197 	QL_PRINT_9(ha, "started\n");
10198 
10199 	if (DRIVER_SUSPENDED(ha)) {
10200 		EL(ha, "failed, LOOP_NOT_READY\n");
10201 		cmd->Status = EXT_STATUS_BUSY;
10202 		cmd->ResponseLen = 0;
10203 		return;
10204 	}
10205 
10206 	if (cmd->RequestLen < sizeof (EXT_ELS_PT_REQ)) {
10207 		/* parameter error */
10208 		EL(ha, "failed, RequestLen < EXT_ELS_PT_REQ, Len=%xh\n",
10209 		    cmd->RequestLen);
10210 		cmd->Status = EXT_STATUS_INVALID_PARAM;
10211 		cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
10212 		cmd->ResponseLen = 0;
10213 		return;
10214 	}
10215 
10216 	/* Allocate memory for command. */
10217 	bp = kmem_zalloc(cmd->RequestLen, KM_SLEEP);
10218 
10219 	if (ddi_copyin((void*)(uintptr_t)cmd->RequestAdr,
10220 	    bp, cmd->RequestLen, mode) != 0) {
10221 		EL(ha, "failed, ddi_copyin\n");
10222 		kmem_free(bp, cmd->RequestLen);
10223 		cmd->Status = EXT_STATUS_COPY_ERR;
10224 		cmd->ResponseLen = 0;
10225 		return;
10226 	}
10227 	pt_req = (EXT_ELS_PT_REQ *)bp;
10228 
10229 	QL_PRINT_9(ha, "EXT_ELS_PT_REQ\n");
10230 	QL_DUMP_9((uint8_t *)pt_req, 8, sizeof (EXT_ELS_PT_REQ));
10231 
10232 	/* Find loop ID of the device */
10233 	if (pt_req->ValidMask & EXT_DEF_WWPN_VALID) {
10234 		if (bcmp(ha->loginparams.nport_ww_name.raw_wwn, pt_req->WWPN,
10235 		    EXT_DEF_WWN_NAME_SIZE) == 0) {
10236 			local_hba = B_TRUE;
10237 		} else {
10238 			tq = ql_find_port(ha, pt_req->WWPN, QLNT_PORT);
10239 		}
10240 	} else if (pt_req->ValidMask & EXT_DEF_PID_VALID) {
10241 		/*
10242 		 * Copy caller's d_id to tmp space.
10243 		 */
10244 		bcopy(&pt_req->Id[1], tmp_fcid.r.d_id,
10245 		    EXT_DEF_PORTID_SIZE_ACTUAL);
10246 		BIG_ENDIAN_24(&tmp_fcid.r.d_id[0]);
10247 
10248 		if (bcmp((void *)&ha->d_id, (void *)tmp_fcid.r.d_id,
10249 		    EXT_DEF_PORTID_SIZE_ACTUAL) == 0) {
10250 			local_hba = B_TRUE;
10251 		} else {
10252 			tq = ql_find_port(ha, (uint8_t *)tmp_fcid.r.d_id,
10253 			    QLNT_PID);
10254 		}
10255 	} else if (pt_req->ValidMask & EXT_DEF_WWNN_VALID) {
10256 		if (bcmp(ha->loginparams.node_ww_name.raw_wwn, pt_req->WWNN,
10257 		    EXT_DEF_WWN_NAME_SIZE) == 0) {
10258 			local_hba = B_TRUE;
10259 		} else {
10260 			tq = ql_find_port(ha, pt_req->WWNN, QLNT_NODE);
10261 		}
10262 	}
10263 
10264 	if (local_hba == B_TRUE) {
10265 		EL(ha, "failed, els to adapter\n");
10266 		kmem_free(bp, cmd->RequestLen);
10267 		cmd->Status = EXT_STATUS_ERR;
10268 		cmd->ResponseLen = 0;
10269 		return;
10270 	}
10271 
10272 	if (tq == NULL) {
10273 		/* no matching device */
10274 		EL(ha, "failed, device not found\n");
10275 		kmem_free(bp, cmd->RequestLen);
10276 		cmd->Status = EXT_STATUS_DEV_NOT_FOUND;
10277 		cmd->DetailStatus = EXT_DSTATUS_TARGET;
10278 		cmd->ResponseLen = 0;
10279 		return;
10280 	}
10281 
10282 	/* Allocate a DMA Memory Descriptor */
10283 	dma_mem = (dma_mem_t *)kmem_zalloc(sizeof (dma_mem_t), KM_SLEEP);
10284 	if (dma_mem == NULL) {
10285 		EL(ha, "failed, kmem_zalloc\n");
10286 		kmem_free(bp, cmd->RequestLen);
10287 		cmd->Status = EXT_STATUS_NO_MEMORY;
10288 		cmd->ResponseLen = 0;
10289 		return;
10290 	}
10291 	/* Determine maximum buffer size. */
10292 	cmd_size = cmd->RequestLen - sizeof (EXT_ELS_PT_REQ);
10293 	pld_byte_cnt = cmd_size < cmd->ResponseLen ? cmd->ResponseLen :
10294 	    cmd_size;
10295 	pld = (caddr_t)(bp + sizeof (EXT_ELS_PT_REQ));
10296 
10297 	/* Allocate command block. */
10298 	pkt_size = (uint32_t)(sizeof (ql_mbx_iocb_t));
10299 	pkt = kmem_zalloc(pkt_size, KM_SLEEP);
10300 	if (pkt == NULL) {
10301 		EL(ha, "failed, kmem_zalloc\n");
10302 		kmem_free(dma_mem, sizeof (dma_mem_t));
10303 		kmem_free(bp, cmd->RequestLen);
10304 		cmd->Status = EXT_STATUS_NO_MEMORY;
10305 		cmd->ResponseLen = 0;
10306 		return;
10307 	}
10308 
10309 	/* Get DMA memory for the payload */
10310 	if (ql_get_dma_mem(ha, dma_mem, pld_byte_cnt, LITTLE_ENDIAN_DMA,
10311 	    QL_DMA_RING_ALIGN) != QL_SUCCESS) {
10312 		cmn_err(CE_WARN, "%sDMA memory alloc failed", QL_NAME);
10313 		kmem_free(pkt, pkt_size);
10314 		kmem_free(dma_mem, sizeof (dma_mem_t));
10315 		kmem_free(bp, cmd->RequestLen);
10316 		cmd->Status = EXT_STATUS_MS_NO_RESPONSE;
10317 		cmd->ResponseLen = 0;
10318 		return;
10319 	}
10320 
10321 	/* Copy out going payload data to IOCB DMA buffer. */
10322 	ddi_rep_put8(dma_mem->acc_handle, (uint8_t *)pld,
10323 	    (uint8_t *)dma_mem->bp, cmd_size, DDI_DEV_AUTOINCR);
10324 
10325 	/* Sync IOCB DMA buffer. */
10326 	(void) ddi_dma_sync(dma_mem->dma_handle, 0, cmd_size,
10327 	    DDI_DMA_SYNC_FORDEV);
10328 
10329 	/*
10330 	 * Setup IOCB
10331 	 */
10332 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
10333 		pkt->els.entry_type = ELS_PASSTHRU_TYPE;
10334 		pkt->els.entry_count = 1;
10335 
10336 		/* Set loop ID */
10337 		pkt->els.n_port_hdl = tq->loop_id;
10338 
10339 		/* Set cmd/response data segment counts. */
10340 		pkt->els.xmt_dseg_count = LE_16(1);
10341 		pkt->els.vp_index = ha->vp_index;
10342 		pkt->els.rcv_dseg_count = LE_16(1);
10343 
10344 		pkt->els.els_cmd_opcode = pld[0];
10345 
10346 		pkt->els.d_id_7_0 = tq->d_id.b.al_pa;
10347 		pkt->els.d_id_15_8 = tq->d_id.b.area;
10348 		pkt->els.d_id_23_16 = tq->d_id.b.domain;
10349 
10350 		pkt->els.s_id_7_0 = ha->d_id.b.al_pa;
10351 		pkt->els.s_id_15_8 = ha->d_id.b.area;
10352 		pkt->els.s_id_23_16 = ha->d_id.b.domain;
10353 
10354 		/* Load rsp byte count. */
10355 		pkt->els.rcv_payld_data_bcnt = LE_32(cmd->ResponseLen);
10356 
10357 		/* Load cmd byte count. */
10358 		pkt->els.xmt_payld_data_bcnt = LE_32(cmd_size);
10359 
10360 		long_ptr = (uint32_t *)&pkt->els.dseg;
10361 
10362 		/* Load MS command entry data segments. */
10363 		*long_ptr++ = (uint32_t)
10364 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
10365 		*long_ptr++ = (uint32_t)
10366 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
10367 		*long_ptr++ = LE_32(cmd_size);
10368 
10369 		/* Load MS response entry data segments. */
10370 		*long_ptr++ = (uint32_t)
10371 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
10372 		*long_ptr++ = (uint32_t)
10373 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
10374 		*long_ptr = LE_32(cmd->ResponseLen);
10375 
10376 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
10377 		    sizeof (ql_mbx_iocb_t));
10378 
10379 		comp_status = (uint16_t)LE_16(pkt->sts24.comp_status);
10380 		if (rval == QL_SUCCESS && comp_status == CS_DATA_UNDERRUN) {
10381 			comp_status = CS_COMPLETE;
10382 		}
10383 		if (rval != QL_SUCCESS ||
10384 		    (pkt->sts24.entry_status & 0x3c) != 0 ||
10385 		    comp_status != CS_COMPLETE) {
10386 			EL(ha, "failed, I/O timeout, cs=%xh, es=%xh, "
10387 			    "rval=%xh\n",
10388 			    comp_status, pkt->sts24.entry_status, rval);
10389 			ql_free_dma_resource(ha, dma_mem);
10390 			kmem_free(pkt, pkt_size);
10391 			kmem_free(dma_mem, sizeof (dma_mem_t));
10392 			kmem_free(bp, cmd->RequestLen);
10393 			cmd->Status = EXT_STATUS_ERR;
10394 			cmd->ResponseLen = 0;
10395 			return;
10396 		}
10397 	} else {
10398 		pkt->ms.entry_type = MS_TYPE;
10399 		pkt->ms.entry_count = 1;
10400 
10401 		/* Set loop ID */
10402 		if (CFG_IST(ha, CFG_EXT_FW_INTERFACE)) {
10403 			pkt->ms.loop_id_l = LSB(tq->loop_id);
10404 			pkt->ms.loop_id_h = MSB(tq->loop_id);
10405 		} else {
10406 			pkt->ms.loop_id_h = LSB(tq->loop_id);
10407 		}
10408 
10409 		pkt->ms.control_flags_h = CF_ELS_PASSTHROUGH;
10410 
10411 		/* Set ISP command timeout. */
10412 		pkt->ms.timeout = LE_16(120);
10413 
10414 		/* Set data segment counts. */
10415 		pkt->ms.cmd_dseg_count_l = 1;
10416 		pkt->ms.total_dseg_count = LE_16(2);
10417 
10418 		/* Response total byte count. */
10419 		pkt->ms.resp_byte_count = LE_32(cmd->ResponseLen);
10420 		pkt->ms.dseg[1].length = LE_32(cmd->ResponseLen);
10421 
10422 		/* Command total byte count. */
10423 		pkt->ms.cmd_byte_count = LE_32(cmd_size);
10424 		pkt->ms.dseg[0].length = LE_32(cmd_size);
10425 
10426 		/* Load command/response data segments. */
10427 		pkt->ms.dseg[0].address[0] = (uint32_t)
10428 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
10429 		pkt->ms.dseg[0].address[1] = (uint32_t)
10430 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
10431 		pkt->ms.dseg[1].address[0] = (uint32_t)
10432 		    LE_32(LSD(dma_mem->cookie.dmac_laddress));
10433 		pkt->ms.dseg[1].address[1] = (uint32_t)
10434 		    LE_32(MSD(dma_mem->cookie.dmac_laddress));
10435 
10436 		rval = ql_issue_mbx_iocb(ha, (caddr_t)pkt,
10437 		    sizeof (ql_mbx_iocb_t));
10438 
10439 		comp_status = (uint16_t)LE_16(pkt->sts.comp_status);
10440 		if (rval == QL_SUCCESS && comp_status == CS_DATA_UNDERRUN) {
10441 			comp_status = CS_COMPLETE;
10442 		}
10443 		if (rval != QL_SUCCESS ||
10444 		    (pkt->sts.entry_status & 0x7e) != 0 ||
10445 		    comp_status != CS_COMPLETE) {
10446 			EL(ha, "failed, I/O timeout, cs=%xh, es=%xh, "
10447 			    "rval=%xh\n",
10448 			    comp_status, pkt->sts.entry_status, rval);
10449 			ql_free_dma_resource(ha, dma_mem);
10450 			kmem_free(pkt, pkt_size);
10451 			kmem_free(dma_mem, sizeof (dma_mem_t));
10452 			kmem_free(bp, cmd->RequestLen);
10453 			cmd->Status = EXT_STATUS_ERR;
10454 			cmd->ResponseLen = 0;
10455 			return;
10456 		}
10457 	}
10458 
10459 	/* Sync payload DMA buffer. */
10460 	(void) ddi_dma_sync(dma_mem->dma_handle, 0, cmd->ResponseLen,
10461 	    DDI_DMA_SYNC_FORKERNEL);
10462 
10463 	if (ql_send_buffer_data(dma_mem->bp,
10464 	    (caddr_t)(uintptr_t)cmd->ResponseAdr,
10465 	    cmd->ResponseLen, mode) != cmd->ResponseLen) {
10466 		cmd->Status = EXT_STATUS_COPY_ERR;
10467 		EL(ha, "failed, ddi_copyout\n");
10468 	} else {
10469 		QL_PRINT_9(ha, "els_rsp\n");
10470 		QL_DUMP_9(pld, 8, cmd->ResponseLen);
10471 		cmd->Status = EXT_STATUS_OK;
10472 		QL_PRINT_9(ha, "done\n");
10473 	}
10474 
10475 	ql_free_dma_resource(ha, dma_mem);
10476 	kmem_free(pkt, pkt_size);
10477 	kmem_free(dma_mem, sizeof (dma_mem_t));
10478 	kmem_free(bp, cmd->RequestLen);
10479 }
10480 
10481 /*
10482  * ql_flash_update_caps
10483  *	IOCTL for flash update capabilities command.
10484  *
10485  * Input:
10486  *	ha:	adapter state pointer.
10487  *	cmd:	User space CT arguments pointer.
10488  *	mode:	flags.
10489  *
10490  * Returns:
10491  *	None, request status indicated in cmd->Status.
10492  *
10493  * Context:
10494  *	Kernel context.
10495  */
10496 static void
ql_flash_update_caps(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)10497 ql_flash_update_caps(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10498 {
10499 	int			rval;
10500 	uint64_t		cb;
10501 	EXT_FLASH_UPDATE_CAPS	caps = {0};
10502 
10503 	QL_PRINT_9(ha, "started\n");
10504 
10505 	cb = LONG_TO_LLONG(ha->fw_attributes, ha->fw_ext_attributes);
10506 
10507 	switch (cmd->SubCode) {
10508 	case EXT_SC_GET_FLASH_UPDATE_CAPS:
10509 		if (cmd->ResponseLen < sizeof (EXT_FLASH_UPDATE_CAPS)) {
10510 			cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10511 			cmd->DetailStatus = sizeof (EXT_FLASH_UPDATE_CAPS);
10512 			EL(ha, "failed, ResponseLen < 0x%x, Len=0x%x\n",
10513 			    sizeof (EXT_FLASH_UPDATE_CAPS), cmd->ResponseLen);
10514 			cmd->ResponseLen = 0;
10515 			return;
10516 		}
10517 		caps.Capabilities = cb;
10518 		caps.OutageDuration = 300;	/* seconds */
10519 
10520 		rval = ddi_copyout((void *)&caps,
10521 		    (void *)(uintptr_t)(cmd->ResponseAdr),
10522 		    sizeof (EXT_FLASH_UPDATE_CAPS), mode);
10523 		if (rval != 0) {
10524 			cmd->Status = EXT_STATUS_COPY_ERR;
10525 			cmd->ResponseLen = 0;
10526 			EL(ha, "failed, ddi_copyout\n");
10527 		} else {
10528 			cmd->ResponseLen = sizeof (EXT_FLASH_UPDATE_CAPS);
10529 		}
10530 		break;
10531 	case EXT_SC_SET_FLASH_UPDATE_CAPS:
10532 		if (cmd->RequestLen < sizeof (EXT_FLASH_UPDATE_CAPS)) {
10533 			/* parameter error */
10534 			EL(ha, "failed, RequestLen < EXT_FLASH_UPDATE_CAPS, "
10535 			    "Len=%xh\n", cmd->RequestLen);
10536 			cmd->Status = EXT_STATUS_INVALID_PARAM;
10537 			cmd->DetailStatus = EXT_DSTATUS_REQUEST_LEN;
10538 			cmd->ResponseLen = 0;
10539 			return;
10540 		}
10541 
10542 		/* Copy in the request structure. */
10543 		if (ddi_copyin((void *)(uintptr_t)cmd->RequestAdr,
10544 		    (void *)&caps, sizeof (EXT_FLASH_UPDATE_CAPS), mode) != 0) {
10545 			EL(ha, "failed, ddi_copyin\n");
10546 			cmd->Status = EXT_STATUS_COPY_ERR;
10547 			cmd->ResponseLen = 0;
10548 			return;
10549 		}
10550 
10551 		if (cb != caps.Capabilities || caps.OutageDuration < 300) {
10552 			cmd->Status = EXT_STATUS_ERR;
10553 			cmd->ResponseLen = 0;
10554 		}
10555 		break;
10556 	default:
10557 		/* Subcode not supported. */
10558 		EL(ha, "unknown subcode=%xh\n", cmd->SubCode);
10559 		cmd->Status = EXT_STATUS_UNSUPPORTED_SUBCODE;
10560 		cmd->ResponseLen = 0;
10561 		break;
10562 	}
10563 
10564 	QL_PRINT_9(ha, "done\n");
10565 }
10566 
10567 /*
10568  * ql_get_bbcr_data
10569  *	IOCTL for get buffer to buffer credits command.
10570  *
10571  * Input:
10572  *	ha:	adapter state pointer.
10573  *	cmd:	User space CT arguments pointer.
10574  *	mode:	flags.
10575  *
10576  * Returns:
10577  *	None, request status indicated in cmd->Status.
10578  *
10579  * Context:
10580  *	Kernel context.
10581  */
10582 static void
ql_get_bbcr_data(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)10583 ql_get_bbcr_data(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10584 {
10585 	int		rval;
10586 	ql_mbx_data_t	mr;
10587 	EXT_BBCR_DATA	bb = {0};
10588 
10589 	QL_PRINT_9(ha, "started\n");
10590 
10591 	if (cmd->ResponseLen < sizeof (EXT_BBCR_DATA)) {
10592 		cmd->Status = EXT_STATUS_BUFFER_TOO_SMALL;
10593 		cmd->DetailStatus = sizeof (EXT_BBCR_DATA);
10594 		EL(ha, "failed, ResponseLen < 0x%x, Len=0x%x\n",
10595 		    sizeof (EXT_BBCR_DATA), cmd->ResponseLen);
10596 		cmd->ResponseLen = 0;
10597 		return;
10598 	}
10599 
10600 	if (!(CFG_IST(ha, CFG_BBCR_SUPPORT))) {
10601 		EL(ha, "invalid request for HBA\n");
10602 		cmd->Status = EXT_STATUS_INVALID_REQUEST;
10603 		cmd->ResponseLen = 0;
10604 		return;
10605 	}
10606 	if (ha->task_daemon_flags & LOOP_DOWN) {
10607 		rval = ql_get_adapter_id(ha, &mr);
10608 		ha->bbcr_initial = LSB(mr.mb[15]);
10609 		ha->bbcr_runtime = MSB(mr.mb[15]);
10610 		bb.ConfiguredBBSCN = ha->bbcr_initial & BBCR_INITIAL_MASK;
10611 		bb.NegotiatedBBSCN = ha->bbcr_runtime & BBCR_RUNTIME_MASK;
10612 		bb.Status = EXT_DEF_BBCR_STATUS_UNKNOWN;
10613 		bb.State = EXT_DEF_BBCR_STATE_OFFLINE;
10614 		if (rval == 0x4005) {
10615 			bb.mbx1 = mr.mb[1];
10616 		}
10617 	} else {
10618 		bb.ConfiguredBBSCN = ha->bbcr_initial & BBCR_INITIAL_MASK;
10619 		bb.NegotiatedBBSCN = ha->bbcr_runtime & BBCR_RUNTIME_MASK;
10620 
10621 		if (bb.ConfiguredBBSCN) {
10622 			bb.Status = EXT_DEF_BBCR_STATUS_ENABLED;
10623 			if (bb.NegotiatedBBSCN &&
10624 			    !(ha->bbcr_runtime & BBCR_RUNTIME_REJECT)) {
10625 				bb.State = EXT_DEF_BBCR_STATE_ONLINE;
10626 			} else {
10627 				bb.State = EXT_DEF_BBCR_STATE_OFFLINE;
10628 				if (ha->bbcr_runtime & BBCR_RUNTIME_REJECT) {
10629 					bb.OfflineReasonCode =
10630 					    EXT_DEF_BBCR_REASON_LOGIN_REJECT;
10631 				} else {
10632 					bb.OfflineReasonCode =
10633 					    EXT_DEF_BBCR_REASON_SWITCH;
10634 				}
10635 			}
10636 		} else {
10637 			bb.Status = EXT_DEF_BBCR_STATUS_DISABLED;
10638 		}
10639 	}
10640 
10641 	rval = ddi_copyout((void *)&bb, (void *)(uintptr_t)(cmd->ResponseAdr),
10642 	    sizeof (EXT_BBCR_DATA), mode);
10643 	if (rval != 0) {
10644 		cmd->Status = EXT_STATUS_COPY_ERR;
10645 		cmd->ResponseLen = 0;
10646 		EL(ha, "failed, ddi_copyout\n");
10647 	} else {
10648 		cmd->ResponseLen = sizeof (EXT_BBCR_DATA);
10649 	}
10650 
10651 	QL_PRINT_9(ha, "done\n");
10652 }
10653 
10654 /*
10655  * ql_get_priv_stats
10656  *	Performs EXT_SC_GET_PRIV_STATS subcommand. of EXT_CC_GET_DATA.
10657  *
10658  * Input:
10659  *	ha:	adapter state pointer.
10660  *	cmd:	Local EXT_IOCTL cmd struct pointer.
10661  *	mode:	flags.
10662  *
10663  * Returns:
10664  *	None, request status indicated in cmd->Status.
10665  *
10666  * Context:
10667  *	Kernel context.
10668  */
10669 static void
ql_get_priv_stats(ql_adapter_state_t * ha,EXT_IOCTL * cmd,int mode)10670 ql_get_priv_stats(ql_adapter_state_t *ha, EXT_IOCTL *cmd, int mode)
10671 {
10672 	uint8_t	*ls;
10673 	int	rval;
10674 	int	retry = 10;
10675 
10676 	QL_PRINT_9(ha, "started\n");
10677 
10678 	while (ha->task_daemon_flags & (DRIVER_STALL | ABORT_ISP_ACTIVE |
10679 	    LOOP_RESYNC_ACTIVE)) {
10680 		ql_delay(ha, 10000000);	/* 10 second delay */
10681 
10682 		retry--;
10683 
10684 		if (retry == 0) { /* effectively 100 seconds */
10685 			EL(ha, "failed, LOOP_NOT_READY\n");
10686 			cmd->Status = EXT_STATUS_BUSY;
10687 			cmd->ResponseLen = 0;
10688 			return;
10689 		}
10690 	}
10691 
10692 	/* Allocate memory for command. */
10693 	ls = kmem_zalloc(cmd->ResponseLen, KM_SLEEP);
10694 
10695 	/*
10696 	 * I think these are supposed to be port statistics
10697 	 * the loop ID or port ID should be in cmd->Instance.
10698 	 */
10699 	rval = ql_get_status_counts(ha,
10700 	    ha->task_daemon_flags & LOOP_DOWN ? 0xFF : ha->loop_id,
10701 	    cmd->ResponseLen, (caddr_t)ls, 0);
10702 	if (rval != QL_SUCCESS) {
10703 		EL(ha, "failed, get_link_status=%xh, id=%xh\n", rval,
10704 		    ha->loop_id);
10705 		cmd->Status = EXT_STATUS_MAILBOX;
10706 		cmd->DetailStatus = rval;
10707 		cmd->ResponseLen = 0;
10708 	} else {
10709 		rval = ddi_copyout((void *)&ls,
10710 		    (void *)(uintptr_t)cmd->ResponseAdr, cmd->ResponseLen,
10711 		    mode);
10712 		if (rval != 0) {
10713 			EL(ha, "failed, ddi_copyout\n");
10714 			cmd->Status = EXT_STATUS_COPY_ERR;
10715 			cmd->ResponseLen = 0;
10716 		}
10717 	}
10718 
10719 	kmem_free(ls, cmd->ResponseLen);
10720 
10721 	QL_PRINT_9(ha, "done\n");
10722 }
10723