1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21fcf3ce44SJohn Forte 
22*4c3888b8SHans Rosenfeld /* Copyright 2015 QLogic Corporation */
23fcf3ce44SJohn Forte 
24fcf3ce44SJohn Forte /*
25*4c3888b8SHans Rosenfeld  * Copyright (c) 2008, 2011, Oracle and/or its affiliates. All rights reserved.
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28fcf3ce44SJohn Forte /*
29fcf3ce44SJohn Forte  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
30fcf3ce44SJohn Forte  * Fibre Channel Adapter (FCA) driver IOCTL source file.
31fcf3ce44SJohn Forte  *
32fcf3ce44SJohn Forte  * ***********************************************************************
33fcf3ce44SJohn Forte  * *									**
34fcf3ce44SJohn Forte  * *				NOTICE					**
35*4c3888b8SHans Rosenfeld  * *		COPYRIGHT (C) 1996-2015 QLOGIC CORPORATION		**
36fcf3ce44SJohn Forte  * *			ALL RIGHTS RESERVED				**
37fcf3ce44SJohn Forte  * *									**
38fcf3ce44SJohn Forte  * ***********************************************************************
39fcf3ce44SJohn Forte  *
40fcf3ce44SJohn Forte  */
41fcf3ce44SJohn Forte 
42fcf3ce44SJohn Forte #include <ql_apps.h>
43fcf3ce44SJohn Forte #include <ql_api.h>
44fcf3ce44SJohn Forte #include <ql_debug.h>
45fcf3ce44SJohn Forte #include <ql_init.h>
46fcf3ce44SJohn Forte #include <ql_ioctl.h>
47fcf3ce44SJohn Forte #include <ql_mbx.h>
48*4c3888b8SHans Rosenfeld #include <ql_nx.h>
49fcf3ce44SJohn Forte #include <ql_xioctl.h>
50fcf3ce44SJohn Forte 
51fcf3ce44SJohn Forte /*
52fcf3ce44SJohn Forte  * Local Function Prototypes.
53fcf3ce44SJohn Forte  */
54fcf3ce44SJohn Forte static int ql_busy_notification(ql_adapter_state_t *);
55fcf3ce44SJohn Forte static int ql_idle_notification(ql_adapter_state_t *);
56fcf3ce44SJohn Forte static int ql_get_feature_bits(ql_adapter_state_t *ha, uint16_t *features);
57fcf3ce44SJohn Forte static int ql_set_feature_bits(ql_adapter_state_t *ha, uint16_t features);
58fcf3ce44SJohn Forte static int ql_set_nvram_adapter_defaults(ql_adapter_state_t *ha);
59fcf3ce44SJohn Forte static void ql_load_nvram(ql_adapter_state_t *ha, uint8_t addr,
60fcf3ce44SJohn Forte     uint16_t value);
61fcf3ce44SJohn Forte static int ql_24xx_load_nvram(ql_adapter_state_t *, uint32_t, uint32_t);
62fcf3ce44SJohn Forte static int ql_adm_op(ql_adapter_state_t *, void *, int);
63fcf3ce44SJohn Forte static int ql_adm_adapter_info(ql_adapter_state_t *, ql_adm_op_t *, int);
64fcf3ce44SJohn Forte static int ql_adm_extended_logging(ql_adapter_state_t *, ql_adm_op_t *);
65fcf3ce44SJohn Forte static int ql_adm_device_list(ql_adapter_state_t *, ql_adm_op_t *, int);
66fcf3ce44SJohn Forte static int ql_adm_update_properties(ql_adapter_state_t *);
67fcf3ce44SJohn Forte static int ql_adm_prop_update_int(ql_adapter_state_t *, ql_adm_op_t *, int);
68fcf3ce44SJohn Forte static int ql_adm_loop_reset(ql_adapter_state_t *);
69fcf3ce44SJohn Forte static int ql_adm_fw_dump(ql_adapter_state_t *, ql_adm_op_t *, void *, int);
70*4c3888b8SHans Rosenfeld static int ql_adm_fw_t_dump(ql_adapter_state_t *);
71*4c3888b8SHans Rosenfeld static int ql_adm_beacon(ql_adapter_state_t *, ql_adm_op_t *);
72fcf3ce44SJohn Forte static int ql_adm_nvram_dump(ql_adapter_state_t *, ql_adm_op_t *, int);
73fcf3ce44SJohn Forte static int ql_adm_nvram_load(ql_adapter_state_t *, ql_adm_op_t *, int);
74fcf3ce44SJohn Forte static int ql_adm_flash_load(ql_adapter_state_t *, ql_adm_op_t *, int);
75fcf3ce44SJohn Forte static int ql_adm_vpd_dump(ql_adapter_state_t *, ql_adm_op_t *, int);
76fcf3ce44SJohn Forte static int ql_adm_vpd_load(ql_adapter_state_t *, ql_adm_op_t *, int);
77fcf3ce44SJohn Forte static int ql_adm_vpd_gettag(ql_adapter_state_t *, ql_adm_op_t *, int);
78fcf3ce44SJohn Forte static int ql_adm_updfwmodule(ql_adapter_state_t *, ql_adm_op_t *, int);
79fcf3ce44SJohn Forte static uint8_t *ql_vpd_findtag(ql_adapter_state_t *, uint8_t *, int8_t *);
80fcf3ce44SJohn Forte 
81fcf3ce44SJohn Forte /* ************************************************************************ */
82fcf3ce44SJohn Forte /*				cb_ops functions			    */
83fcf3ce44SJohn Forte /* ************************************************************************ */
84fcf3ce44SJohn Forte 
85fcf3ce44SJohn Forte /*
86fcf3ce44SJohn Forte  * ql_open
87fcf3ce44SJohn Forte  *	opens device
88fcf3ce44SJohn Forte  *
89fcf3ce44SJohn Forte  * Input:
90fcf3ce44SJohn Forte  *	dev_p = device pointer
91fcf3ce44SJohn Forte  *	flags = open flags
92fcf3ce44SJohn Forte  *	otype = open type
93fcf3ce44SJohn Forte  *	cred_p = credentials pointer
94fcf3ce44SJohn Forte  *
95fcf3ce44SJohn Forte  * Returns:
96fcf3ce44SJohn Forte  *	0 = success
97fcf3ce44SJohn Forte  *
98fcf3ce44SJohn Forte  * Context:
99fcf3ce44SJohn Forte  *	Kernel context.
100fcf3ce44SJohn Forte  */
101fcf3ce44SJohn Forte /* ARGSUSED */
102fcf3ce44SJohn Forte int
ql_open(dev_t * dev_p,int flags,int otyp,cred_t * cred_p)103fcf3ce44SJohn Forte ql_open(dev_t *dev_p, int flags, int otyp, cred_t *cred_p)
104fcf3ce44SJohn Forte {
105fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha;
106fcf3ce44SJohn Forte 	int			rval = 0;
107fcf3ce44SJohn Forte 
108fcf3ce44SJohn Forte 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(*dev_p));
109fcf3ce44SJohn Forte 	if (ha == NULL) {
110*4c3888b8SHans Rosenfeld 		QL_PRINT_2(NULL, "failed, no adapter\n");
111fcf3ce44SJohn Forte 		return (ENXIO);
112fcf3ce44SJohn Forte 	}
113fcf3ce44SJohn Forte 
114*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
115fcf3ce44SJohn Forte 
116fcf3ce44SJohn Forte 	/* Allow only character opens */
117fcf3ce44SJohn Forte 	if (otyp != OTYP_CHR) {
118*4c3888b8SHans Rosenfeld 		QL_PRINT_2(ha, "failed, open type\n");
119fcf3ce44SJohn Forte 		return (EINVAL);
120fcf3ce44SJohn Forte 	}
121fcf3ce44SJohn Forte 
122fcf3ce44SJohn Forte 	ADAPTER_STATE_LOCK(ha);
123fcf3ce44SJohn Forte 	if (flags & FEXCL && ha->flags & QL_OPENED) {
124fcf3ce44SJohn Forte 		ADAPTER_STATE_UNLOCK(ha);
125fcf3ce44SJohn Forte 		rval = EBUSY;
126fcf3ce44SJohn Forte 	} else {
127fcf3ce44SJohn Forte 		ha->flags |= QL_OPENED;
128fcf3ce44SJohn Forte 		ADAPTER_STATE_UNLOCK(ha);
129fcf3ce44SJohn Forte 	}
130fcf3ce44SJohn Forte 
131fcf3ce44SJohn Forte 	if (rval != 0) {
132fcf3ce44SJohn Forte 		EL(ha, "failed, rval = %xh\n", rval);
133fcf3ce44SJohn Forte 	} else {
134fcf3ce44SJohn Forte 		/*EMPTY*/
135*4c3888b8SHans Rosenfeld 		QL_PRINT_3(ha, "done\n");
136fcf3ce44SJohn Forte 	}
137fcf3ce44SJohn Forte 	return (rval);
138fcf3ce44SJohn Forte }
139fcf3ce44SJohn Forte 
140fcf3ce44SJohn Forte /*
141fcf3ce44SJohn Forte  * ql_close
142fcf3ce44SJohn Forte  *	opens device
143fcf3ce44SJohn Forte  *
144fcf3ce44SJohn Forte  * Input:
145fcf3ce44SJohn Forte  *	dev_p = device pointer
146fcf3ce44SJohn Forte  *	flags = open flags
147fcf3ce44SJohn Forte  *	otype = open type
148fcf3ce44SJohn Forte  *	cred_p = credentials pointer
149fcf3ce44SJohn Forte  *
150fcf3ce44SJohn Forte  * Returns:
151fcf3ce44SJohn Forte  *	0 = success
152fcf3ce44SJohn Forte  *
153fcf3ce44SJohn Forte  * Context:
154fcf3ce44SJohn Forte  *	Kernel context.
155fcf3ce44SJohn Forte  */
156fcf3ce44SJohn Forte /* ARGSUSED */
157fcf3ce44SJohn Forte int
ql_close(dev_t dev,int flags,int otyp,cred_t * cred_p)158fcf3ce44SJohn Forte ql_close(dev_t dev, int flags, int otyp, cred_t *cred_p)
159fcf3ce44SJohn Forte {
160fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha;
161fcf3ce44SJohn Forte 	int			rval = 0;
162fcf3ce44SJohn Forte 
163fcf3ce44SJohn Forte 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(dev));
164fcf3ce44SJohn Forte 	if (ha == NULL) {
165*4c3888b8SHans Rosenfeld 		QL_PRINT_2(ha, "failed, no adapter\n");
166fcf3ce44SJohn Forte 		return (ENXIO);
167fcf3ce44SJohn Forte 	}
168fcf3ce44SJohn Forte 
169*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
170fcf3ce44SJohn Forte 
171fcf3ce44SJohn Forte 	if (otyp != OTYP_CHR) {
172*4c3888b8SHans Rosenfeld 		QL_PRINT_2(ha, "failed, open type\n");
173fcf3ce44SJohn Forte 		return (EINVAL);
174fcf3ce44SJohn Forte 	}
175fcf3ce44SJohn Forte 
176fcf3ce44SJohn Forte 	ADAPTER_STATE_LOCK(ha);
177fcf3ce44SJohn Forte 	ha->flags &= ~QL_OPENED;
178fcf3ce44SJohn Forte 	ADAPTER_STATE_UNLOCK(ha);
179fcf3ce44SJohn Forte 
180fcf3ce44SJohn Forte 	if (rval != 0) {
181fcf3ce44SJohn Forte 		EL(ha, "failed, rval = %xh\n", rval);
182fcf3ce44SJohn Forte 	} else {
183fcf3ce44SJohn Forte 		/*EMPTY*/
184*4c3888b8SHans Rosenfeld 		QL_PRINT_3(ha, "done\n");
185fcf3ce44SJohn Forte 	}
186fcf3ce44SJohn Forte 	return (rval);
187fcf3ce44SJohn Forte }
188fcf3ce44SJohn Forte 
189fcf3ce44SJohn Forte /*
190fcf3ce44SJohn Forte  * ql_ioctl
191fcf3ce44SJohn Forte  *	control a character device
192fcf3ce44SJohn Forte  *
193fcf3ce44SJohn Forte  * Input:
194fcf3ce44SJohn Forte  *	dev = device number
195fcf3ce44SJohn Forte  *	cmd = function to perform
196fcf3ce44SJohn Forte  *	arg = data type varies with request
197fcf3ce44SJohn Forte  *	mode = flags
198fcf3ce44SJohn Forte  *	cred_p = credentials pointer
199fcf3ce44SJohn Forte  *	rval_p = pointer to result value
200fcf3ce44SJohn Forte  *
201fcf3ce44SJohn Forte  * Returns:
202fcf3ce44SJohn Forte  *	0 = success
203fcf3ce44SJohn Forte  *
204fcf3ce44SJohn Forte  * Context:
205fcf3ce44SJohn Forte  *	Kernel context.
206fcf3ce44SJohn Forte  */
207fcf3ce44SJohn Forte /* ARGSUSED */
208fcf3ce44SJohn Forte int
ql_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)209fcf3ce44SJohn Forte ql_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
210fcf3ce44SJohn Forte     int *rval_p)
211fcf3ce44SJohn Forte {
212fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha;
213fcf3ce44SJohn Forte 	int			rval = 0;
214fcf3ce44SJohn Forte 
215fcf3ce44SJohn Forte 	if (ddi_in_panic()) {
216*4c3888b8SHans Rosenfeld 		QL_PRINT_2(NULL, "ql_ioctl: ddi_in_panic exit\n");
217fcf3ce44SJohn Forte 		return (ENOPROTOOPT);
218fcf3ce44SJohn Forte 	}
219fcf3ce44SJohn Forte 
220fcf3ce44SJohn Forte 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(dev));
221fcf3ce44SJohn Forte 	if (ha == NULL)	{
222*4c3888b8SHans Rosenfeld 		QL_PRINT_2(ha, "failed, no adapter\n");
223fcf3ce44SJohn Forte 		return (ENXIO);
224fcf3ce44SJohn Forte 	}
225fcf3ce44SJohn Forte 
226*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
227fcf3ce44SJohn Forte 
228fcf3ce44SJohn Forte 	/*
229fcf3ce44SJohn Forte 	 * Quick clean exit for qla2x00 foapi calls which are
230fcf3ce44SJohn Forte 	 * not supported in qlc.
231fcf3ce44SJohn Forte 	 */
232fcf3ce44SJohn Forte 	if (cmd >= QL_FOAPI_START && cmd <= QL_FOAPI_END) {
233*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "failed, fo api not supported\n");
234fcf3ce44SJohn Forte 		return (ENOTTY);
235fcf3ce44SJohn Forte 	}
236fcf3ce44SJohn Forte 
237fcf3ce44SJohn Forte 	/* PWR management busy. */
238fcf3ce44SJohn Forte 	rval = ql_busy_notification(ha);
239fcf3ce44SJohn Forte 	if (rval != FC_SUCCESS)	 {
240fcf3ce44SJohn Forte 		EL(ha, "failed, ql_busy_notification\n");
241fcf3ce44SJohn Forte 		return (ENXIO);
242fcf3ce44SJohn Forte 	}
243fcf3ce44SJohn Forte 
244fcf3ce44SJohn Forte 	rval = ql_xioctl(ha, cmd, arg, mode, cred_p, rval_p);
245fcf3ce44SJohn Forte 	if (rval == ENOPROTOOPT || rval == EINVAL) {
246fcf3ce44SJohn Forte 		switch (cmd) {
24716dd44c2SDaniel Beauregard 		case QL_GET_ADAPTER_FEATURE_BITS: {
248fcf3ce44SJohn Forte 			uint16_t bits;
249fcf3ce44SJohn Forte 
250fcf3ce44SJohn Forte 			rval = ql_get_feature_bits(ha, &bits);
251fcf3ce44SJohn Forte 
252fcf3ce44SJohn Forte 			if (!rval && ddi_copyout((void *)&bits, (void *)arg,
253fcf3ce44SJohn Forte 			    sizeof (bits), mode)) {
254fcf3ce44SJohn Forte 				rval = EFAULT;
255fcf3ce44SJohn Forte 			}
256fcf3ce44SJohn Forte 			break;
257fcf3ce44SJohn Forte 		}
258fcf3ce44SJohn Forte 
25916dd44c2SDaniel Beauregard 		case QL_SET_ADAPTER_FEATURE_BITS: {
260fcf3ce44SJohn Forte 			uint16_t bits;
261fcf3ce44SJohn Forte 
262fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, (void *)&bits,
263fcf3ce44SJohn Forte 			    sizeof (bits), mode)) {
264fcf3ce44SJohn Forte 				rval = EFAULT;
265fcf3ce44SJohn Forte 				break;
266fcf3ce44SJohn Forte 			}
267fcf3ce44SJohn Forte 
268fcf3ce44SJohn Forte 			rval = ql_set_feature_bits(ha, bits);
269fcf3ce44SJohn Forte 			break;
270fcf3ce44SJohn Forte 		}
271fcf3ce44SJohn Forte 
272fcf3ce44SJohn Forte 		case QL_SET_ADAPTER_NVRAM_DEFAULTS:
273fcf3ce44SJohn Forte 			rval = ql_set_nvram_adapter_defaults(ha);
274fcf3ce44SJohn Forte 			break;
275fcf3ce44SJohn Forte 
276fcf3ce44SJohn Forte 		case QL_UTIL_LOAD:
277fcf3ce44SJohn Forte 			rval = ql_nv_util_load(ha, (void *)arg, mode);
278fcf3ce44SJohn Forte 			break;
279fcf3ce44SJohn Forte 
280fcf3ce44SJohn Forte 		case QL_UTIL_DUMP:
281fcf3ce44SJohn Forte 			rval = ql_nv_util_dump(ha, (void *)arg, mode);
282fcf3ce44SJohn Forte 			break;
283fcf3ce44SJohn Forte 
284fcf3ce44SJohn Forte 		case QL_ADM_OP:
285fcf3ce44SJohn Forte 			rval = ql_adm_op(ha, (void *)arg, mode);
286fcf3ce44SJohn Forte 			break;
287fcf3ce44SJohn Forte 
288fcf3ce44SJohn Forte 		default:
289fcf3ce44SJohn Forte 			EL(ha, "unknown command = %d\n", cmd);
290fcf3ce44SJohn Forte 			rval = ENOTTY;
291fcf3ce44SJohn Forte 			break;
292fcf3ce44SJohn Forte 		}
293fcf3ce44SJohn Forte 	}
294fcf3ce44SJohn Forte 
295fcf3ce44SJohn Forte 	/* PWR management idle. */
296fcf3ce44SJohn Forte 	(void) ql_idle_notification(ha);
297fcf3ce44SJohn Forte 
298fcf3ce44SJohn Forte 	if (rval != 0) {
299f885d00fSDaniel Beauregard 		/*
300f885d00fSDaniel Beauregard 		 * Don't show failures caused by pps polling for
301f885d00fSDaniel Beauregard 		 * non-existant virtual ports.
302f885d00fSDaniel Beauregard 		 */
303f885d00fSDaniel Beauregard 		if (cmd != EXT_CC_VPORT_CMD) {
304f885d00fSDaniel Beauregard 			EL(ha, "failed, cmd=%d rval=%d\n", cmd, rval);
305f885d00fSDaniel Beauregard 		}
306fcf3ce44SJohn Forte 	} else {
307fcf3ce44SJohn Forte 		/*EMPTY*/
308*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "done\n");
309fcf3ce44SJohn Forte 	}
310fcf3ce44SJohn Forte 	return (rval);
311fcf3ce44SJohn Forte }
312fcf3ce44SJohn Forte 
313fcf3ce44SJohn Forte /*
314fcf3ce44SJohn Forte  * ql_busy_notification
315fcf3ce44SJohn Forte  *	Adapter busy notification.
316fcf3ce44SJohn Forte  *
317fcf3ce44SJohn Forte  * Input:
318fcf3ce44SJohn Forte  *	ha = adapter state pointer.
319fcf3ce44SJohn Forte  *
320fcf3ce44SJohn Forte  * Returns:
321fcf3ce44SJohn Forte  *	FC_SUCCESS
322fcf3ce44SJohn Forte  *	FC_FAILURE
323fcf3ce44SJohn Forte  *
324fcf3ce44SJohn Forte  * Context:
325fcf3ce44SJohn Forte  *	Kernel context.
326fcf3ce44SJohn Forte  */
327fcf3ce44SJohn Forte static int
ql_busy_notification(ql_adapter_state_t * ha)328fcf3ce44SJohn Forte ql_busy_notification(ql_adapter_state_t *ha)
329fcf3ce44SJohn Forte {
330fcf3ce44SJohn Forte 	if (!ha->pm_capable) {
331fcf3ce44SJohn Forte 		return (FC_SUCCESS);
332fcf3ce44SJohn Forte 	}
333fcf3ce44SJohn Forte 
334*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
335fcf3ce44SJohn Forte 
336fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
337*4c3888b8SHans Rosenfeld 	ha->pm_busy++;
338fcf3ce44SJohn Forte 	QL_PM_UNLOCK(ha);
339fcf3ce44SJohn Forte 
340fcf3ce44SJohn Forte 	if (pm_busy_component(ha->dip, 0) != DDI_SUCCESS) {
341fcf3ce44SJohn Forte 		QL_PM_LOCK(ha);
342*4c3888b8SHans Rosenfeld 		if (ha->pm_busy) {
343*4c3888b8SHans Rosenfeld 			ha->pm_busy--;
344*4c3888b8SHans Rosenfeld 		}
345fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
346fcf3ce44SJohn Forte 
347fcf3ce44SJohn Forte 		EL(ha, "pm_busy_component failed = %xh\n", FC_FAILURE);
348fcf3ce44SJohn Forte 		return (FC_FAILURE);
349fcf3ce44SJohn Forte 	}
350fcf3ce44SJohn Forte 
351fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
352fcf3ce44SJohn Forte 	if (ha->power_level != PM_LEVEL_D0) {
353fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
354fcf3ce44SJohn Forte 		if (pm_raise_power(ha->dip, 0, 1) != DDI_SUCCESS) {
355fcf3ce44SJohn Forte 			QL_PM_LOCK(ha);
356*4c3888b8SHans Rosenfeld 			if (ha->pm_busy) {
357*4c3888b8SHans Rosenfeld 				ha->pm_busy--;
358*4c3888b8SHans Rosenfeld 			}
359fcf3ce44SJohn Forte 			QL_PM_UNLOCK(ha);
360fcf3ce44SJohn Forte 			return (FC_FAILURE);
361fcf3ce44SJohn Forte 		}
362fcf3ce44SJohn Forte 	} else {
363fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
364fcf3ce44SJohn Forte 	}
365fcf3ce44SJohn Forte 
366*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
367fcf3ce44SJohn Forte 
368fcf3ce44SJohn Forte 	return (FC_SUCCESS);
369fcf3ce44SJohn Forte }
370fcf3ce44SJohn Forte 
371fcf3ce44SJohn Forte /*
372fcf3ce44SJohn Forte  * ql_idle_notification
373fcf3ce44SJohn Forte  *	Adapter idle notification.
374fcf3ce44SJohn Forte  *
375fcf3ce44SJohn Forte  * Input:
376fcf3ce44SJohn Forte  *	ha = adapter state pointer.
377fcf3ce44SJohn Forte  *
378fcf3ce44SJohn Forte  * Returns:
379fcf3ce44SJohn Forte  *	FC_SUCCESS
380fcf3ce44SJohn Forte  *	FC_FAILURE
381fcf3ce44SJohn Forte  *
382fcf3ce44SJohn Forte  * Context:
383fcf3ce44SJohn Forte  *	Kernel context.
384fcf3ce44SJohn Forte  */
385fcf3ce44SJohn Forte static int
ql_idle_notification(ql_adapter_state_t * ha)386fcf3ce44SJohn Forte ql_idle_notification(ql_adapter_state_t *ha)
387fcf3ce44SJohn Forte {
388fcf3ce44SJohn Forte 	if (!ha->pm_capable) {
389fcf3ce44SJohn Forte 		return (FC_SUCCESS);
390fcf3ce44SJohn Forte 	}
391fcf3ce44SJohn Forte 
392*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
393fcf3ce44SJohn Forte 
394fcf3ce44SJohn Forte 	if (pm_idle_component(ha->dip, 0) != DDI_SUCCESS) {
395fcf3ce44SJohn Forte 		EL(ha, "pm_idle_component failed = %xh\n", FC_FAILURE);
396fcf3ce44SJohn Forte 		return (FC_FAILURE);
397fcf3ce44SJohn Forte 	}
398fcf3ce44SJohn Forte 
399fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
400*4c3888b8SHans Rosenfeld 	if (ha->pm_busy) {
401*4c3888b8SHans Rosenfeld 		ha->pm_busy--;
402*4c3888b8SHans Rosenfeld 	}
403fcf3ce44SJohn Forte 	QL_PM_UNLOCK(ha);
404fcf3ce44SJohn Forte 
405*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
406fcf3ce44SJohn Forte 
407fcf3ce44SJohn Forte 	return (FC_SUCCESS);
408fcf3ce44SJohn Forte }
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte /*
411fcf3ce44SJohn Forte  * Get adapter feature bits from NVRAM
412fcf3ce44SJohn Forte  */
413fcf3ce44SJohn Forte static int
ql_get_feature_bits(ql_adapter_state_t * ha,uint16_t * features)414fcf3ce44SJohn Forte ql_get_feature_bits(ql_adapter_state_t *ha, uint16_t *features)
415fcf3ce44SJohn Forte {
416fcf3ce44SJohn Forte 	int			count;
417fcf3ce44SJohn Forte 	volatile uint16_t	data;
418fcf3ce44SJohn Forte 	uint32_t		nv_cmd;
419fcf3ce44SJohn Forte 	uint32_t		start_addr;
420fcf3ce44SJohn Forte 	int			rval;
421fcf3ce44SJohn Forte 	uint32_t		offset = offsetof(nvram_t, adapter_features);
422fcf3ce44SJohn Forte 
423*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
424fcf3ce44SJohn Forte 
425*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
426fcf3ce44SJohn Forte 		EL(ha, "Not supported for 24xx\n");
427fcf3ce44SJohn Forte 		return (EINVAL);
428fcf3ce44SJohn Forte 	}
429fcf3ce44SJohn Forte 
430fcf3ce44SJohn Forte 	/*
431fcf3ce44SJohn Forte 	 * The offset can't be greater than max of 8 bits and
432fcf3ce44SJohn Forte 	 * the following code breaks if the offset isn't at
433fcf3ce44SJohn Forte 	 * 2 byte boundary.
434fcf3ce44SJohn Forte 	 */
435fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
436fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
437fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
438fcf3ce44SJohn Forte 		return (EIO);
439fcf3ce44SJohn Forte 	}
440fcf3ce44SJohn Forte 
441fcf3ce44SJohn Forte 	/*
442fcf3ce44SJohn Forte 	 * Have the most significant 3 bits represent the read operation
443fcf3ce44SJohn Forte 	 * followed by the 8 bits representing the offset at which we
444fcf3ce44SJohn Forte 	 * are going to perform the read operation
445fcf3ce44SJohn Forte 	 */
446fcf3ce44SJohn Forte 	offset >>= 1;
447fcf3ce44SJohn Forte 	offset += start_addr;
448fcf3ce44SJohn Forte 	nv_cmd = (offset << 16) | NV_READ_OP;
449fcf3ce44SJohn Forte 	nv_cmd <<= 5;
450fcf3ce44SJohn Forte 
451fcf3ce44SJohn Forte 	/*
452fcf3ce44SJohn Forte 	 * Select the chip and feed the command and address
453fcf3ce44SJohn Forte 	 */
454fcf3ce44SJohn Forte 	for (count = 0; count < 11; count++) {
455fcf3ce44SJohn Forte 		if (nv_cmd & BIT_31) {
456fcf3ce44SJohn Forte 			ql_nv_write(ha, NV_DATA_OUT);
457fcf3ce44SJohn Forte 		} else {
458fcf3ce44SJohn Forte 			ql_nv_write(ha, 0);
459fcf3ce44SJohn Forte 		}
460fcf3ce44SJohn Forte 		nv_cmd <<= 1;
461fcf3ce44SJohn Forte 	}
462fcf3ce44SJohn Forte 
463fcf3ce44SJohn Forte 	*features = 0;
464fcf3ce44SJohn Forte 	for (count = 0; count < 16; count++) {
465fcf3ce44SJohn Forte 		WRT16_IO_REG(ha, nvram, NV_SELECT | NV_CLOCK);
466fcf3ce44SJohn Forte 		ql_nv_delay();
467fcf3ce44SJohn Forte 
468fcf3ce44SJohn Forte 		data = RD16_IO_REG(ha, nvram);
469fcf3ce44SJohn Forte 		*features <<= 1;
470fcf3ce44SJohn Forte 		if (data & NV_DATA_IN) {
471fcf3ce44SJohn Forte 			*features = (uint16_t)(*features | 0x1);
472fcf3ce44SJohn Forte 		}
473fcf3ce44SJohn Forte 
474fcf3ce44SJohn Forte 		WRT16_IO_REG(ha, nvram, NV_SELECT);
475fcf3ce44SJohn Forte 		ql_nv_delay();
476fcf3ce44SJohn Forte 	}
477fcf3ce44SJohn Forte 
478fcf3ce44SJohn Forte 	/*
479fcf3ce44SJohn Forte 	 * Deselect the chip
480fcf3ce44SJohn Forte 	 */
481fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
482fcf3ce44SJohn Forte 
483fcf3ce44SJohn Forte 	ql_release_nvram(ha);
484fcf3ce44SJohn Forte 
485*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
486fcf3ce44SJohn Forte 
487fcf3ce44SJohn Forte 	return (0);
488fcf3ce44SJohn Forte }
489fcf3ce44SJohn Forte 
490fcf3ce44SJohn Forte /*
491fcf3ce44SJohn Forte  * Set adapter feature bits in NVRAM
492fcf3ce44SJohn Forte  */
493fcf3ce44SJohn Forte static int
ql_set_feature_bits(ql_adapter_state_t * ha,uint16_t features)494fcf3ce44SJohn Forte ql_set_feature_bits(ql_adapter_state_t *ha, uint16_t features)
495fcf3ce44SJohn Forte {
496fcf3ce44SJohn Forte 	int		rval;
497fcf3ce44SJohn Forte 	uint32_t	count;
498fcf3ce44SJohn Forte 	nvram_t		*nv;
499fcf3ce44SJohn Forte 	uint16_t	*wptr;
500fcf3ce44SJohn Forte 	uint8_t		*bptr;
501fcf3ce44SJohn Forte 	uint8_t		csum;
502fcf3ce44SJohn Forte 	uint32_t	start_addr;
503fcf3ce44SJohn Forte 
504*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
505fcf3ce44SJohn Forte 
506*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
507fcf3ce44SJohn Forte 		EL(ha, "Not supported for 24xx\n");
508fcf3ce44SJohn Forte 		return (EINVAL);
509fcf3ce44SJohn Forte 	}
510fcf3ce44SJohn Forte 
511fcf3ce44SJohn Forte 	nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
512fcf3ce44SJohn Forte 	if (nv == NULL) {
513fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
514fcf3ce44SJohn Forte 		return (ENOMEM);
515fcf3ce44SJohn Forte 	}
516fcf3ce44SJohn Forte 
517fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
518fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
519fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
520fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (*nv));
521fcf3ce44SJohn Forte 		return (EIO);
522fcf3ce44SJohn Forte 	}
523fcf3ce44SJohn Forte 	rval = 0;
524fcf3ce44SJohn Forte 
525fcf3ce44SJohn Forte 	/*
526fcf3ce44SJohn Forte 	 * Read off the whole NVRAM
527fcf3ce44SJohn Forte 	 */
528fcf3ce44SJohn Forte 	wptr = (uint16_t *)nv;
529fcf3ce44SJohn Forte 	csum = 0;
530fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
531fcf3ce44SJohn Forte 		*wptr = (uint16_t)ql_get_nvram_word(ha, count + start_addr);
532fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)*wptr);
533fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
534fcf3ce44SJohn Forte 		wptr++;
535fcf3ce44SJohn Forte 	}
536fcf3ce44SJohn Forte 
537fcf3ce44SJohn Forte 	/*
538fcf3ce44SJohn Forte 	 * If the checksum is BAD then fail it right here.
539fcf3ce44SJohn Forte 	 */
540fcf3ce44SJohn Forte 	if (csum) {
541fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (*nv));
542fcf3ce44SJohn Forte 		ql_release_nvram(ha);
543fcf3ce44SJohn Forte 		return (EBADF);
544fcf3ce44SJohn Forte 	}
545fcf3ce44SJohn Forte 
546fcf3ce44SJohn Forte 	nv->adapter_features[0] = (uint8_t)((features & 0xFF00) >> 8);
547fcf3ce44SJohn Forte 	nv->adapter_features[1] = (uint8_t)(features & 0xFF);
548fcf3ce44SJohn Forte 
549fcf3ce44SJohn Forte 	/*
550fcf3ce44SJohn Forte 	 * Recompute the chesksum now
551fcf3ce44SJohn Forte 	 */
552fcf3ce44SJohn Forte 	bptr = (uint8_t *)nv;
553fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) - 1; count++) {
554fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + *bptr++);
555fcf3ce44SJohn Forte 	}
556fcf3ce44SJohn Forte 	csum = (uint8_t)(~csum + 1);
557fcf3ce44SJohn Forte 	nv->checksum = csum;
558fcf3ce44SJohn Forte 
559fcf3ce44SJohn Forte 	/*
560fcf3ce44SJohn Forte 	 * Now load the NVRAM
561fcf3ce44SJohn Forte 	 */
562fcf3ce44SJohn Forte 	wptr = (uint16_t *)nv;
563fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
564fcf3ce44SJohn Forte 		ql_load_nvram(ha, (uint8_t)(count + start_addr), *wptr++);
565fcf3ce44SJohn Forte 	}
566fcf3ce44SJohn Forte 
567fcf3ce44SJohn Forte 	/*
568fcf3ce44SJohn Forte 	 * Read NVRAM and verify the contents
569fcf3ce44SJohn Forte 	 */
570fcf3ce44SJohn Forte 	wptr = (uint16_t *)nv;
571fcf3ce44SJohn Forte 	csum = 0;
572fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
573fcf3ce44SJohn Forte 		if (ql_get_nvram_word(ha, count + start_addr) != *wptr) {
574fcf3ce44SJohn Forte 			rval = EIO;
575fcf3ce44SJohn Forte 			break;
576fcf3ce44SJohn Forte 		}
577fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)*wptr);
578fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
579fcf3ce44SJohn Forte 		wptr++;
580fcf3ce44SJohn Forte 	}
581fcf3ce44SJohn Forte 
582fcf3ce44SJohn Forte 	if (csum) {
583fcf3ce44SJohn Forte 		rval = EINVAL;
584fcf3ce44SJohn Forte 	}
585fcf3ce44SJohn Forte 
586fcf3ce44SJohn Forte 	kmem_free(nv, sizeof (*nv));
587fcf3ce44SJohn Forte 	ql_release_nvram(ha);
588fcf3ce44SJohn Forte 
589*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
590fcf3ce44SJohn Forte 
591fcf3ce44SJohn Forte 	return (rval);
592fcf3ce44SJohn Forte }
593fcf3ce44SJohn Forte 
594fcf3ce44SJohn Forte /*
595fcf3ce44SJohn Forte  * Fix this function to update just feature bits and checksum in NVRAM
596fcf3ce44SJohn Forte  */
597fcf3ce44SJohn Forte static int
ql_set_nvram_adapter_defaults(ql_adapter_state_t * ha)598fcf3ce44SJohn Forte ql_set_nvram_adapter_defaults(ql_adapter_state_t *ha)
599fcf3ce44SJohn Forte {
600fcf3ce44SJohn Forte 	int		rval;
601fcf3ce44SJohn Forte 	uint32_t	count;
602fcf3ce44SJohn Forte 	uint32_t	start_addr;
603fcf3ce44SJohn Forte 
604*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
605fcf3ce44SJohn Forte 
606fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
607fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
608fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
609fcf3ce44SJohn Forte 		return (EIO);
610fcf3ce44SJohn Forte 	}
611fcf3ce44SJohn Forte 	rval = 0;
612fcf3ce44SJohn Forte 
613*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
614fcf3ce44SJohn Forte 		nvram_24xx_t	*nv;
615fcf3ce44SJohn Forte 		uint32_t	*longptr;
616fcf3ce44SJohn Forte 		uint32_t	csum = 0;
617fcf3ce44SJohn Forte 
618fcf3ce44SJohn Forte 		nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
619fcf3ce44SJohn Forte 		if (nv == NULL) {
620fcf3ce44SJohn Forte 			EL(ha, "failed, kmem_zalloc\n");
621fcf3ce44SJohn Forte 			return (ENOMEM);
622fcf3ce44SJohn Forte 		}
623fcf3ce44SJohn Forte 
624fcf3ce44SJohn Forte 		nv->nvram_version[0] = LSB(ICB_24XX_VERSION);
625fcf3ce44SJohn Forte 		nv->nvram_version[1] = MSB(ICB_24XX_VERSION);
626fcf3ce44SJohn Forte 
627fcf3ce44SJohn Forte 		nv->version[0] = 1;
628fcf3ce44SJohn Forte 		nv->max_frame_length[1] = 8;
629fcf3ce44SJohn Forte 		nv->execution_throttle[0] = 16;
630fcf3ce44SJohn Forte 		nv->login_retry_count[0] = 8;
631fcf3ce44SJohn Forte 
632fcf3ce44SJohn Forte 		nv->firmware_options_1[0] = BIT_2 | BIT_1;
633fcf3ce44SJohn Forte 		nv->firmware_options_1[1] = BIT_5;
634fcf3ce44SJohn Forte 		nv->firmware_options_2[0] = BIT_5;
635fcf3ce44SJohn Forte 		nv->firmware_options_2[1] = BIT_4;
636fcf3ce44SJohn Forte 		nv->firmware_options_3[1] = BIT_6;
637fcf3ce44SJohn Forte 
638fcf3ce44SJohn Forte 		/*
639fcf3ce44SJohn Forte 		 * Set default host adapter parameters
640fcf3ce44SJohn Forte 		 */
641fcf3ce44SJohn Forte 		nv->host_p[0] = BIT_4 | BIT_1;
642fcf3ce44SJohn Forte 		nv->host_p[1] = BIT_3 | BIT_2;
643fcf3ce44SJohn Forte 		nv->reset_delay = 5;
644fcf3ce44SJohn Forte 		nv->max_luns_per_target[0] = 128;
645fcf3ce44SJohn Forte 		nv->port_down_retry_count[0] = 30;
646fcf3ce44SJohn Forte 		nv->link_down_timeout[0] = 30;
647fcf3ce44SJohn Forte 
648fcf3ce44SJohn Forte 		/*
649fcf3ce44SJohn Forte 		 * compute the chesksum now
650fcf3ce44SJohn Forte 		 */
651fcf3ce44SJohn Forte 		longptr = (uint32_t *)nv;
652fcf3ce44SJohn Forte 		csum = 0;
653*4c3888b8SHans Rosenfeld 		for (count = 0; count < (sizeof (nvram_24xx_t) / 4) - 1;
654*4c3888b8SHans Rosenfeld 		    count++) {
655fcf3ce44SJohn Forte 			csum += *longptr;
656fcf3ce44SJohn Forte 			longptr++;
657fcf3ce44SJohn Forte 		}
658fcf3ce44SJohn Forte 		csum = (uint32_t)(~csum + 1);
659fcf3ce44SJohn Forte 		LITTLE_ENDIAN_32((long)csum);
660fcf3ce44SJohn Forte 		*longptr = csum;
661fcf3ce44SJohn Forte 
662fcf3ce44SJohn Forte 		/*
663fcf3ce44SJohn Forte 		 * Now load the NVRAM
664fcf3ce44SJohn Forte 		 */
665fcf3ce44SJohn Forte 		longptr = (uint32_t *)nv;
666fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_24xx_t) / 4; count++) {
667fcf3ce44SJohn Forte 			(void) ql_24xx_load_nvram(ha,
668fcf3ce44SJohn Forte 			    (uint32_t)(count + start_addr), *longptr++);
669fcf3ce44SJohn Forte 		}
670fcf3ce44SJohn Forte 
671fcf3ce44SJohn Forte 		/*
672fcf3ce44SJohn Forte 		 * Read NVRAM and verify the contents
673fcf3ce44SJohn Forte 		 */
674fcf3ce44SJohn Forte 		csum = 0;
675fcf3ce44SJohn Forte 		longptr = (uint32_t *)nv;
676fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_24xx_t) / 4; count++) {
677fcf3ce44SJohn Forte 			rval = ql_24xx_read_flash(ha, count + start_addr,
678fcf3ce44SJohn Forte 			    longptr);
679fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
680fcf3ce44SJohn Forte 				EL(ha, "24xx_read_flash failed=%xh\n", rval);
681fcf3ce44SJohn Forte 				break;
682fcf3ce44SJohn Forte 			}
683fcf3ce44SJohn Forte 			csum += *longptr;
684fcf3ce44SJohn Forte 		}
685fcf3ce44SJohn Forte 
686fcf3ce44SJohn Forte 		if (csum) {
687fcf3ce44SJohn Forte 			rval = EINVAL;
688fcf3ce44SJohn Forte 		}
689fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (nvram_24xx_t));
690fcf3ce44SJohn Forte 	} else {
691fcf3ce44SJohn Forte 		nvram_t		*nv;
692fcf3ce44SJohn Forte 		uint16_t	*wptr;
693fcf3ce44SJohn Forte 		uint8_t		*bptr;
694fcf3ce44SJohn Forte 		uint8_t		csum;
695fcf3ce44SJohn Forte 
696fcf3ce44SJohn Forte 		nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
697fcf3ce44SJohn Forte 		if (nv == NULL) {
698fcf3ce44SJohn Forte 			EL(ha, "failed, kmem_zalloc\n");
699fcf3ce44SJohn Forte 			return (ENOMEM);
700fcf3ce44SJohn Forte 		}
701fcf3ce44SJohn Forte 		/*
702fcf3ce44SJohn Forte 		 * Set default initialization control block.
703fcf3ce44SJohn Forte 		 */
704fcf3ce44SJohn Forte 		nv->parameter_block_version = ICB_VERSION;
705fcf3ce44SJohn Forte 		nv->firmware_options[0] = BIT_4 | BIT_3 | BIT_2 | BIT_1;
706fcf3ce44SJohn Forte 		nv->firmware_options[1] = BIT_7 | BIT_5 | BIT_2;
707fcf3ce44SJohn Forte 
708fcf3ce44SJohn Forte 		nv->max_frame_length[1] = 4;
709fcf3ce44SJohn Forte 		nv->max_iocb_allocation[1] = 1;
710fcf3ce44SJohn Forte 		nv->execution_throttle[0] = 16;
711fcf3ce44SJohn Forte 		nv->login_retry_count = 8;
712fcf3ce44SJohn Forte 		nv->port_name[0] = 33;
713fcf3ce44SJohn Forte 		nv->port_name[3] = 224;
714fcf3ce44SJohn Forte 		nv->port_name[4] = 139;
715fcf3ce44SJohn Forte 		nv->login_timeout = 4;
716fcf3ce44SJohn Forte 
717fcf3ce44SJohn Forte 		/*
718fcf3ce44SJohn Forte 		 * Set default host adapter parameters
719fcf3ce44SJohn Forte 		 */
720fcf3ce44SJohn Forte 		nv->host_p[0] = BIT_1;
721fcf3ce44SJohn Forte 		nv->host_p[1] = BIT_2;
722fcf3ce44SJohn Forte 		nv->reset_delay = 5;
723fcf3ce44SJohn Forte 		nv->port_down_retry_count = 8;
724fcf3ce44SJohn Forte 		nv->maximum_luns_per_target[0] = 8;
725fcf3ce44SJohn Forte 
726fcf3ce44SJohn Forte 		/*
727fcf3ce44SJohn Forte 		 * compute the chesksum now
728fcf3ce44SJohn Forte 		 */
729fcf3ce44SJohn Forte 		bptr = (uint8_t *)nv;
730fcf3ce44SJohn Forte 		csum = 0;
731fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_t) - 1; count++) {
732fcf3ce44SJohn Forte 			csum = (uint8_t)(csum + *bptr++);
733fcf3ce44SJohn Forte 		}
734fcf3ce44SJohn Forte 		csum = (uint8_t)(~csum + 1);
735fcf3ce44SJohn Forte 		nv->checksum = csum;
736fcf3ce44SJohn Forte 
737fcf3ce44SJohn Forte 		/*
738fcf3ce44SJohn Forte 		 * Now load the NVRAM
739fcf3ce44SJohn Forte 		 */
740fcf3ce44SJohn Forte 		wptr = (uint16_t *)nv;
741fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_t) / 2; count++) {
742fcf3ce44SJohn Forte 			ql_load_nvram(ha, (uint8_t)(count + start_addr),
743fcf3ce44SJohn Forte 			    *wptr++);
744fcf3ce44SJohn Forte 		}
745fcf3ce44SJohn Forte 
746fcf3ce44SJohn Forte 		/*
747fcf3ce44SJohn Forte 		 * Read NVRAM and verify the contents
748fcf3ce44SJohn Forte 		 */
749fcf3ce44SJohn Forte 		wptr = (uint16_t *)nv;
750fcf3ce44SJohn Forte 		csum = 0;
751fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_t) / 2; count++) {
752fcf3ce44SJohn Forte 			if (ql_get_nvram_word(ha, count + start_addr) !=
753fcf3ce44SJohn Forte 			    *wptr) {
754fcf3ce44SJohn Forte 				rval = EIO;
755fcf3ce44SJohn Forte 				break;
756fcf3ce44SJohn Forte 			}
757fcf3ce44SJohn Forte 			csum = (uint8_t)(csum + (uint8_t)*wptr);
758fcf3ce44SJohn Forte 			csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
759fcf3ce44SJohn Forte 			wptr++;
760fcf3ce44SJohn Forte 		}
761fcf3ce44SJohn Forte 		if (csum) {
762fcf3ce44SJohn Forte 			rval = EINVAL;
763fcf3ce44SJohn Forte 		}
764fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (*nv));
765fcf3ce44SJohn Forte 	}
766fcf3ce44SJohn Forte 	ql_release_nvram(ha);
767fcf3ce44SJohn Forte 
768*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
769fcf3ce44SJohn Forte 
770fcf3ce44SJohn Forte 	return (rval);
771fcf3ce44SJohn Forte }
772fcf3ce44SJohn Forte 
773fcf3ce44SJohn Forte static void
ql_load_nvram(ql_adapter_state_t * ha,uint8_t addr,uint16_t value)774fcf3ce44SJohn Forte ql_load_nvram(ql_adapter_state_t *ha, uint8_t addr, uint16_t value)
775fcf3ce44SJohn Forte {
776fcf3ce44SJohn Forte 	int			count;
777fcf3ce44SJohn Forte 	volatile uint16_t	word;
778fcf3ce44SJohn Forte 	volatile uint32_t	nv_cmd;
779fcf3ce44SJohn Forte 
780fcf3ce44SJohn Forte 	ql_nv_write(ha, NV_DATA_OUT);
781fcf3ce44SJohn Forte 	ql_nv_write(ha, 0);
782fcf3ce44SJohn Forte 	ql_nv_write(ha, 0);
783fcf3ce44SJohn Forte 
784fcf3ce44SJohn Forte 	for (word = 0; word < 8; word++) {
785fcf3ce44SJohn Forte 		ql_nv_write(ha, NV_DATA_OUT);
786fcf3ce44SJohn Forte 	}
787fcf3ce44SJohn Forte 
788fcf3ce44SJohn Forte 	/*
789fcf3ce44SJohn Forte 	 * Deselect the chip
790fcf3ce44SJohn Forte 	 */
791fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
792fcf3ce44SJohn Forte 	ql_nv_delay();
793fcf3ce44SJohn Forte 
794fcf3ce44SJohn Forte 	/*
795fcf3ce44SJohn Forte 	 * Erase Location
796fcf3ce44SJohn Forte 	 */
797fcf3ce44SJohn Forte 	nv_cmd = (addr << 16) | NV_ERASE_OP;
798fcf3ce44SJohn Forte 	nv_cmd <<= 5;
799fcf3ce44SJohn Forte 	for (count = 0; count < 11; count++) {
800fcf3ce44SJohn Forte 		if (nv_cmd & BIT_31) {
801fcf3ce44SJohn Forte 			ql_nv_write(ha, NV_DATA_OUT);
802fcf3ce44SJohn Forte 		} else {
803fcf3ce44SJohn Forte 			ql_nv_write(ha, 0);
804fcf3ce44SJohn Forte 		}
805fcf3ce44SJohn Forte 		nv_cmd <<= 1;
806fcf3ce44SJohn Forte 	}
807fcf3ce44SJohn Forte 
808fcf3ce44SJohn Forte 	/*
809fcf3ce44SJohn Forte 	 * Wait for Erase to Finish
810fcf3ce44SJohn Forte 	 */
811fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
812fcf3ce44SJohn Forte 	ql_nv_delay();
813fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_SELECT);
814fcf3ce44SJohn Forte 	word = 0;
815fcf3ce44SJohn Forte 	while ((word & NV_DATA_IN) == 0) {
816fcf3ce44SJohn Forte 		ql_nv_delay();
817fcf3ce44SJohn Forte 		word = RD16_IO_REG(ha, nvram);
818fcf3ce44SJohn Forte 	}
819fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
820fcf3ce44SJohn Forte 	ql_nv_delay();
821fcf3ce44SJohn Forte 
822fcf3ce44SJohn Forte 	/*
823fcf3ce44SJohn Forte 	 * Write data now
824fcf3ce44SJohn Forte 	 */
825fcf3ce44SJohn Forte 	nv_cmd = (addr << 16) | NV_WRITE_OP;
826fcf3ce44SJohn Forte 	nv_cmd |= value;
827fcf3ce44SJohn Forte 	nv_cmd <<= 5;
828fcf3ce44SJohn Forte 	for (count = 0; count < 27; count++) {
829fcf3ce44SJohn Forte 		if (nv_cmd & BIT_31) {
830fcf3ce44SJohn Forte 			ql_nv_write(ha, NV_DATA_OUT);
831fcf3ce44SJohn Forte 		} else {
832fcf3ce44SJohn Forte 			ql_nv_write(ha, 0);
833fcf3ce44SJohn Forte 		}
834fcf3ce44SJohn Forte 		nv_cmd <<= 1;
835fcf3ce44SJohn Forte 	}
836fcf3ce44SJohn Forte 
837fcf3ce44SJohn Forte 	/*
838fcf3ce44SJohn Forte 	 * Wait for NVRAM to become ready
839fcf3ce44SJohn Forte 	 */
840fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
841fcf3ce44SJohn Forte 	ql_nv_delay();
842fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_SELECT);
843fcf3ce44SJohn Forte 	word = 0;
844fcf3ce44SJohn Forte 	while ((word & NV_DATA_IN) == 0) {
845fcf3ce44SJohn Forte 		ql_nv_delay();
846fcf3ce44SJohn Forte 		word = RD16_IO_REG(ha, nvram);
847fcf3ce44SJohn Forte 	}
848fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
849fcf3ce44SJohn Forte 	ql_nv_delay();
850fcf3ce44SJohn Forte 
851fcf3ce44SJohn Forte 	/*
852fcf3ce44SJohn Forte 	 * Disable writes
853fcf3ce44SJohn Forte 	 */
854fcf3ce44SJohn Forte 	ql_nv_write(ha, NV_DATA_OUT);
855fcf3ce44SJohn Forte 	for (count = 0; count < 10; count++) {
856fcf3ce44SJohn Forte 		ql_nv_write(ha, 0);
857fcf3ce44SJohn Forte 	}
858fcf3ce44SJohn Forte 
859fcf3ce44SJohn Forte 	/*
860fcf3ce44SJohn Forte 	 * Deselect the chip now
861fcf3ce44SJohn Forte 	 */
862fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
863fcf3ce44SJohn Forte }
864fcf3ce44SJohn Forte 
865fcf3ce44SJohn Forte /*
866fcf3ce44SJohn Forte  * ql_24xx_load_nvram
867fcf3ce44SJohn Forte  *	Enable NVRAM and writes a 32bit word to ISP24xx NVRAM.
868fcf3ce44SJohn Forte  *
869fcf3ce44SJohn Forte  * Input:
870fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
871fcf3ce44SJohn Forte  *	addr:	NVRAM address.
872fcf3ce44SJohn Forte  *	value:	data.
873fcf3ce44SJohn Forte  *
874fcf3ce44SJohn Forte  * Returns:
875fcf3ce44SJohn Forte  *	ql local function return status code.
876fcf3ce44SJohn Forte  *
877fcf3ce44SJohn Forte  * Context:
878fcf3ce44SJohn Forte  *	Kernel context.
879fcf3ce44SJohn Forte  */
880fcf3ce44SJohn Forte static int
ql_24xx_load_nvram(ql_adapter_state_t * ha,uint32_t addr,uint32_t value)881fcf3ce44SJohn Forte ql_24xx_load_nvram(ql_adapter_state_t *ha, uint32_t addr, uint32_t value)
882fcf3ce44SJohn Forte {
883fcf3ce44SJohn Forte 	int	rval;
884fcf3ce44SJohn Forte 
885fcf3ce44SJohn Forte 	/* Enable flash write. */
886*4c3888b8SHans Rosenfeld 	if (!(CFG_IST(ha, CFG_FCOE_SUPPORT))) {
8875dfd244aSDaniel Beauregard 		WRT32_IO_REG(ha, ctrl_status,
8885dfd244aSDaniel Beauregard 		    RD32_IO_REG(ha, ctrl_status) | ISP_FLASH_ENABLE);
8895dfd244aSDaniel Beauregard 		RD32_IO_REG(ha, ctrl_status);	/* PCI Posting. */
8905dfd244aSDaniel Beauregard 	}
891fcf3ce44SJohn Forte 
892fcf3ce44SJohn Forte 	/* Disable NVRAM write-protection. */
893*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_CTRL_24XX)) {
894fcf3ce44SJohn Forte 		(void) ql_24xx_write_flash(ha, NVRAM_CONF_ADDR | 0x101, 0);
895fcf3ce44SJohn Forte 	} else {
8965dfd244aSDaniel Beauregard 		if ((rval = ql_24xx_unprotect_flash(ha)) != QL_SUCCESS) {
8975dfd244aSDaniel Beauregard 			EL(ha, "unprotect_flash failed, rval=%xh\n", rval);
8985dfd244aSDaniel Beauregard 			return (rval);
8995dfd244aSDaniel Beauregard 		}
900fcf3ce44SJohn Forte 	}
901fcf3ce44SJohn Forte 
902fcf3ce44SJohn Forte 	/* Write to flash. */
903fcf3ce44SJohn Forte 	rval = ql_24xx_write_flash(ha, addr, value);
904fcf3ce44SJohn Forte 
905fcf3ce44SJohn Forte 	/* Enable NVRAM write-protection. */
906*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_CTRL_24XX)) {
907fcf3ce44SJohn Forte 		/* TODO: Check if 0x8c is correct -- sb: 0x9c ? */
908fcf3ce44SJohn Forte 		(void) ql_24xx_write_flash(ha, NVRAM_CONF_ADDR | 0x101, 0x8c);
909fcf3ce44SJohn Forte 	} else {
910fcf3ce44SJohn Forte 		ql_24xx_protect_flash(ha);
911fcf3ce44SJohn Forte 	}
912fcf3ce44SJohn Forte 
913fcf3ce44SJohn Forte 	/* Disable flash write. */
9145dfd244aSDaniel Beauregard 	if (!(CFG_IST(ha, CFG_CTRL_81XX))) {
9155dfd244aSDaniel Beauregard 		WRT32_IO_REG(ha, ctrl_status,
9165dfd244aSDaniel Beauregard 		    RD32_IO_REG(ha, ctrl_status) & ~ISP_FLASH_ENABLE);
9175dfd244aSDaniel Beauregard 		RD32_IO_REG(ha, ctrl_status);	/* PCI Posting. */
9185dfd244aSDaniel Beauregard 	}
919fcf3ce44SJohn Forte 
920fcf3ce44SJohn Forte 	return (rval);
921fcf3ce44SJohn Forte }
922fcf3ce44SJohn Forte 
923fcf3ce44SJohn Forte /*
924fcf3ce44SJohn Forte  * ql_nv_util_load
925fcf3ce44SJohn Forte  *	Loads NVRAM from application.
926fcf3ce44SJohn Forte  *
927fcf3ce44SJohn Forte  * Input:
928fcf3ce44SJohn Forte  *	ha = adapter state pointer.
929fcf3ce44SJohn Forte  *	bp = user buffer address.
930fcf3ce44SJohn Forte  *
931fcf3ce44SJohn Forte  * Returns:
932fcf3ce44SJohn Forte  *
933fcf3ce44SJohn Forte  * Context:
934fcf3ce44SJohn Forte  *	Kernel context.
935fcf3ce44SJohn Forte  */
936fcf3ce44SJohn Forte int
ql_nv_util_load(ql_adapter_state_t * ha,void * bp,int mode)937fcf3ce44SJohn Forte ql_nv_util_load(ql_adapter_state_t *ha, void *bp, int mode)
938fcf3ce44SJohn Forte {
939fcf3ce44SJohn Forte 	uint8_t		cnt;
940fcf3ce44SJohn Forte 	void		*nv;
941fcf3ce44SJohn Forte 	uint16_t	*wptr;
942fcf3ce44SJohn Forte 	uint16_t	data;
943c1fad183SDaniel Beauregard 	uint32_t	start_addr, *lptr, data32;
944fcf3ce44SJohn Forte 	nvram_t		*nptr;
945fcf3ce44SJohn Forte 	int		rval;
946fcf3ce44SJohn Forte 
947*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
948fcf3ce44SJohn Forte 
949c1fad183SDaniel Beauregard 	if ((nv = kmem_zalloc(ha->nvram_cache->size, KM_SLEEP)) == NULL) {
950fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
951fcf3ce44SJohn Forte 		return (ENOMEM);
952fcf3ce44SJohn Forte 	}
953fcf3ce44SJohn Forte 
954c1fad183SDaniel Beauregard 	if (ddi_copyin(bp, nv, ha->nvram_cache->size, mode) != 0) {
955fcf3ce44SJohn Forte 		EL(ha, "Buffer copy failed\n");
956c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
957fcf3ce44SJohn Forte 		return (EFAULT);
958fcf3ce44SJohn Forte 	}
959fcf3ce44SJohn Forte 
960fcf3ce44SJohn Forte 	/* See if the buffer passed to us looks sane */
961fcf3ce44SJohn Forte 	nptr = (nvram_t *)nv;
962fcf3ce44SJohn Forte 	if (nptr->id[0] != 'I' || nptr->id[1] != 'S' || nptr->id[2] != 'P' ||
963fcf3ce44SJohn Forte 	    nptr->id[3] != ' ') {
964fcf3ce44SJohn Forte 		EL(ha, "failed, buffer sanity check\n");
965c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
966fcf3ce44SJohn Forte 		return (EINVAL);
967fcf3ce44SJohn Forte 	}
968fcf3ce44SJohn Forte 
969fcf3ce44SJohn Forte 	/* Quiesce I/O */
970fcf3ce44SJohn Forte 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
971fcf3ce44SJohn Forte 		EL(ha, "ql_stall_driver failed\n");
972c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
973fcf3ce44SJohn Forte 		return (EBUSY);
974fcf3ce44SJohn Forte 	}
975fcf3ce44SJohn Forte 
976fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
977fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
978fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
979c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
980fcf3ce44SJohn Forte 		ql_restart_driver(ha);
981fcf3ce44SJohn Forte 		return (EIO);
982fcf3ce44SJohn Forte 	}
983fcf3ce44SJohn Forte 
984fcf3ce44SJohn Forte 	/* Load NVRAM. */
985*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_CTRL_252780818283)) {
986fcf3ce44SJohn Forte 		GLOBAL_HW_UNLOCK();
9875dfd244aSDaniel Beauregard 		start_addr &= ~ha->flash_data_addr;
9885dfd244aSDaniel Beauregard 		start_addr <<= 2;
989c1fad183SDaniel Beauregard 		if ((rval = ql_r_m_w_flash(ha, bp, ha->nvram_cache->size,
990c1fad183SDaniel Beauregard 		    start_addr, mode)) != QL_SUCCESS) {
991fcf3ce44SJohn Forte 			EL(ha, "nvram load failed, rval = %0xh\n", rval);
992fcf3ce44SJohn Forte 		}
993fcf3ce44SJohn Forte 		GLOBAL_HW_LOCK();
994*4c3888b8SHans Rosenfeld 	} else if (CFG_IST(ha, CFG_CTRL_24XX)) {
995fcf3ce44SJohn Forte 		lptr = (uint32_t *)nv;
996c1fad183SDaniel Beauregard 		for (cnt = 0; cnt < ha->nvram_cache->size / 4; cnt++) {
997fcf3ce44SJohn Forte 			data32 = *lptr++;
998fcf3ce44SJohn Forte 			LITTLE_ENDIAN_32(&data32);
999fcf3ce44SJohn Forte 			rval = ql_24xx_load_nvram(ha, cnt + start_addr,
1000fcf3ce44SJohn Forte 			    data32);
1001fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
1002fcf3ce44SJohn Forte 				EL(ha, "failed, 24xx_load_nvram=%xh\n", rval);
1003fcf3ce44SJohn Forte 				break;
1004fcf3ce44SJohn Forte 			}
1005fcf3ce44SJohn Forte 		}
1006fcf3ce44SJohn Forte 	} else {
1007fcf3ce44SJohn Forte 		wptr = (uint16_t *)nv;
1008c1fad183SDaniel Beauregard 		for (cnt = 0; cnt < ha->nvram_cache->size / 2; cnt++) {
1009fcf3ce44SJohn Forte 			data = *wptr++;
1010fcf3ce44SJohn Forte 			LITTLE_ENDIAN_16(&data);
1011fcf3ce44SJohn Forte 			ql_load_nvram(ha, (uint8_t)(cnt + start_addr), data);
1012fcf3ce44SJohn Forte 		}
1013fcf3ce44SJohn Forte 	}
1014c1fad183SDaniel Beauregard 	/* switch to the new one */
1015c1fad183SDaniel Beauregard 	kmem_free(ha->nvram_cache->cache, ha->nvram_cache->size);
1016c1fad183SDaniel Beauregard 	ha->nvram_cache->cache = (void *)nptr;
1017c1fad183SDaniel Beauregard 
1018fcf3ce44SJohn Forte 	ql_release_nvram(ha);
1019fcf3ce44SJohn Forte 	ql_restart_driver(ha);
1020fcf3ce44SJohn Forte 
1021*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1022fcf3ce44SJohn Forte 
1023fcf3ce44SJohn Forte 	if (rval == QL_SUCCESS) {
1024fcf3ce44SJohn Forte 		return (0);
1025fcf3ce44SJohn Forte 	}
1026fcf3ce44SJohn Forte 
1027fcf3ce44SJohn Forte 	return (EFAULT);
1028fcf3ce44SJohn Forte }
1029fcf3ce44SJohn Forte 
1030fcf3ce44SJohn Forte /*
1031fcf3ce44SJohn Forte  * ql_nv_util_dump
1032fcf3ce44SJohn Forte  *	Dumps NVRAM to application.
1033fcf3ce44SJohn Forte  *
1034fcf3ce44SJohn Forte  * Input:
1035fcf3ce44SJohn Forte  *	ha = adapter state pointer.
1036fcf3ce44SJohn Forte  *	bp = user buffer address.
1037fcf3ce44SJohn Forte  *
1038fcf3ce44SJohn Forte  * Returns:
1039fcf3ce44SJohn Forte  *
1040fcf3ce44SJohn Forte  * Context:
1041fcf3ce44SJohn Forte  *	Kernel context.
1042fcf3ce44SJohn Forte  */
1043fcf3ce44SJohn Forte int
ql_nv_util_dump(ql_adapter_state_t * ha,void * bp,int mode)1044fcf3ce44SJohn Forte ql_nv_util_dump(ql_adapter_state_t *ha, void *bp, int mode)
1045fcf3ce44SJohn Forte {
1046fcf3ce44SJohn Forte 	uint32_t	start_addr;
1047fcf3ce44SJohn Forte 	int		rval2, rval = 0;
1048fcf3ce44SJohn Forte 
1049*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1050fcf3ce44SJohn Forte 
1051c1fad183SDaniel Beauregard 	if (ha->nvram_cache == NULL ||
1052c92b35bbSToomas Soome 	    ha->nvram_cache->size == 0 ||
1053c1fad183SDaniel Beauregard 	    ha->nvram_cache->cache == NULL) {
1054fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
1055fcf3ce44SJohn Forte 		return (ENOMEM);
1056c1fad183SDaniel Beauregard 	} else if (ha->nvram_cache->valid != 1) {
1057fcf3ce44SJohn Forte 
1058c1fad183SDaniel Beauregard 		/* Quiesce I/O */
1059c1fad183SDaniel Beauregard 		if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
1060c1fad183SDaniel Beauregard 			EL(ha, "ql_stall_driver failed\n");
1061c1fad183SDaniel Beauregard 			return (EBUSY);
1062c1fad183SDaniel Beauregard 		}
1063fcf3ce44SJohn Forte 
1064c1fad183SDaniel Beauregard 		rval2 = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
1065c1fad183SDaniel Beauregard 		if (rval2 != QL_SUCCESS) {
1066c1fad183SDaniel Beauregard 			EL(ha, "failed, ql_lock_nvram=%xh\n", rval2);
1067c1fad183SDaniel Beauregard 			ql_restart_driver(ha);
1068c1fad183SDaniel Beauregard 			return (EIO);
1069c1fad183SDaniel Beauregard 		}
1070c1fad183SDaniel Beauregard 		rval2 = ql_get_nvram(ha, ha->nvram_cache->cache,
1071c1fad183SDaniel Beauregard 		    start_addr, ha->nvram_cache->size);
1072c1fad183SDaniel Beauregard 		if (rval2 != QL_SUCCESS) {
1073c1fad183SDaniel Beauregard 			rval = rval2;
1074c1fad183SDaniel Beauregard 		} else {
1075c1fad183SDaniel Beauregard 			ha->nvram_cache->valid = 1;
1076c1fad183SDaniel Beauregard 			EL(ha, "nvram cache now valid.");
1077c1fad183SDaniel Beauregard 		}
1078c1fad183SDaniel Beauregard 
1079c1fad183SDaniel Beauregard 		ql_release_nvram(ha);
1080fcf3ce44SJohn Forte 		ql_restart_driver(ha);
1081c1fad183SDaniel Beauregard 
1082c1fad183SDaniel Beauregard 		if (rval != 0) {
1083c1fad183SDaniel Beauregard 			EL(ha, "failed to dump nvram, rval=%x\n", rval);
1084c1fad183SDaniel Beauregard 			return (rval);
1085c1fad183SDaniel Beauregard 		}
1086fcf3ce44SJohn Forte 	}
1087fcf3ce44SJohn Forte 
1088c1fad183SDaniel Beauregard 	if (ddi_copyout(ha->nvram_cache->cache, bp,
1089c1fad183SDaniel Beauregard 	    ha->nvram_cache->size, mode) != 0) {
1090c1fad183SDaniel Beauregard 		EL(ha, "Buffer copy failed\n");
1091c1fad183SDaniel Beauregard 		return (EFAULT);
1092c1fad183SDaniel Beauregard 	}
1093c1fad183SDaniel Beauregard 
1094*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1095c1fad183SDaniel Beauregard 
1096c1fad183SDaniel Beauregard 	return (0);
1097c1fad183SDaniel Beauregard }
1098c1fad183SDaniel Beauregard 
1099c1fad183SDaniel Beauregard int
ql_get_nvram(ql_adapter_state_t * ha,void * dest_addr,uint32_t src_addr,uint32_t size)1100c1fad183SDaniel Beauregard ql_get_nvram(ql_adapter_state_t *ha, void *dest_addr, uint32_t src_addr,
1101c1fad183SDaniel Beauregard     uint32_t size)
1102c1fad183SDaniel Beauregard {
1103c1fad183SDaniel Beauregard 	int rval = QL_SUCCESS;
1104c1fad183SDaniel Beauregard 	int cnt;
1105fcf3ce44SJohn Forte 	/* Dump NVRAM. */
1106*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
1107c1fad183SDaniel Beauregard 		uint32_t	*lptr = (uint32_t *)dest_addr;
1108fcf3ce44SJohn Forte 
1109c1fad183SDaniel Beauregard 		for (cnt = 0; cnt < size / 4; cnt++) {
1110c1fad183SDaniel Beauregard 			rval = ql_24xx_read_flash(ha, src_addr++, lptr);
1111c1fad183SDaniel Beauregard 			if (rval != QL_SUCCESS) {
1112c1fad183SDaniel Beauregard 				EL(ha, "read_flash failed=%xh\n", rval);
1113fcf3ce44SJohn Forte 				rval = EAGAIN;
1114fcf3ce44SJohn Forte 				break;
1115fcf3ce44SJohn Forte 			}
1116fcf3ce44SJohn Forte 			LITTLE_ENDIAN_32(lptr);
1117fcf3ce44SJohn Forte 			lptr++;
1118fcf3ce44SJohn Forte 		}
1119fcf3ce44SJohn Forte 	} else {
1120fcf3ce44SJohn Forte 		uint16_t	data;
1121c1fad183SDaniel Beauregard 		uint16_t	*wptr = (uint16_t *)dest_addr;
1122fcf3ce44SJohn Forte 
1123c1fad183SDaniel Beauregard 		for (cnt = 0; cnt < size / 2; cnt++) {
1124fcf3ce44SJohn Forte 			data = (uint16_t)ql_get_nvram_word(ha, cnt +
1125c1fad183SDaniel Beauregard 			    src_addr);
1126fcf3ce44SJohn Forte 			LITTLE_ENDIAN_16(&data);
1127fcf3ce44SJohn Forte 			*wptr++ = data;
1128fcf3ce44SJohn Forte 		}
1129fcf3ce44SJohn Forte 	}
1130c1fad183SDaniel Beauregard 	return (rval);
1131fcf3ce44SJohn Forte }
1132fcf3ce44SJohn Forte 
1133fcf3ce44SJohn Forte /*
1134fcf3ce44SJohn Forte  * ql_vpd_load
1135fcf3ce44SJohn Forte  *	Loads VPD from application.
1136fcf3ce44SJohn Forte  *
1137fcf3ce44SJohn Forte  * Input:
1138fcf3ce44SJohn Forte  *	ha = adapter state pointer.
1139fcf3ce44SJohn Forte  *	bp = user buffer address.
1140fcf3ce44SJohn Forte  *
1141fcf3ce44SJohn Forte  * Returns:
1142fcf3ce44SJohn Forte  *
1143fcf3ce44SJohn Forte  * Context:
1144fcf3ce44SJohn Forte  *	Kernel context.
1145fcf3ce44SJohn Forte  */
1146fcf3ce44SJohn Forte int
ql_vpd_load(ql_adapter_state_t * ha,void * bp,int mode)1147fcf3ce44SJohn Forte ql_vpd_load(ql_adapter_state_t *ha, void *bp, int mode)
1148fcf3ce44SJohn Forte {
1149fcf3ce44SJohn Forte 	uint8_t		cnt;
1150fcf3ce44SJohn Forte 	uint8_t		*vpd, *vpdptr, *vbuf;
1151fcf3ce44SJohn Forte 	uint32_t	start_addr, vpd_size, *lptr, data32;
1152fcf3ce44SJohn Forte 	int		rval;
1153fcf3ce44SJohn Forte 
1154*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1155fcf3ce44SJohn Forte 
1156*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
1157fcf3ce44SJohn Forte 		EL(ha, "unsupported adapter feature\n");
1158fcf3ce44SJohn Forte 		return (ENOTSUP);
1159fcf3ce44SJohn Forte 	}
1160fcf3ce44SJohn Forte 
1161fcf3ce44SJohn Forte 	vpd_size = QL_24XX_VPD_SIZE;
1162fcf3ce44SJohn Forte 
1163fcf3ce44SJohn Forte 	if ((vpd = kmem_zalloc(vpd_size, KM_SLEEP)) == NULL) {
1164fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
1165fcf3ce44SJohn Forte 		return (ENOMEM);
1166fcf3ce44SJohn Forte 	}
1167fcf3ce44SJohn Forte 
1168fcf3ce44SJohn Forte 	if (ddi_copyin(bp, vpd, vpd_size, mode) != 0) {
1169fcf3ce44SJohn Forte 		EL(ha, "Buffer copy failed\n");
1170fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1171fcf3ce44SJohn Forte 		return (EFAULT);
1172fcf3ce44SJohn Forte 	}
1173fcf3ce44SJohn Forte 
1174fcf3ce44SJohn Forte 	/* Sanity check the user supplied data via checksum */
1175fcf3ce44SJohn Forte 	if ((vpdptr = ql_vpd_findtag(ha, vpd, "RV")) == NULL) {
1176fcf3ce44SJohn Forte 		EL(ha, "vpd RV tag missing\n");
1177fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1178fcf3ce44SJohn Forte 		return (EINVAL);
1179fcf3ce44SJohn Forte 	}
1180fcf3ce44SJohn Forte 
1181fcf3ce44SJohn Forte 	vpdptr += 3;
1182fcf3ce44SJohn Forte 	cnt = 0;
1183fcf3ce44SJohn Forte 	vbuf = vpd;
1184fcf3ce44SJohn Forte 	while (vbuf <= vpdptr) {
1185fcf3ce44SJohn Forte 		cnt += *vbuf++;
1186fcf3ce44SJohn Forte 	}
1187fcf3ce44SJohn Forte 	if (cnt != 0) {
1188fcf3ce44SJohn Forte 		EL(ha, "mismatched checksum, cal=%xh, passed=%xh\n",
1189fcf3ce44SJohn Forte 		    (uint8_t)cnt, (uintptr_t)vpdptr);
1190fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1191fcf3ce44SJohn Forte 		return (EINVAL);
1192fcf3ce44SJohn Forte 	}
1193fcf3ce44SJohn Forte 
1194fcf3ce44SJohn Forte 	/* Quiesce I/O */
1195fcf3ce44SJohn Forte 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
1196fcf3ce44SJohn Forte 		EL(ha, "ql_stall_driver failed\n");
1197fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1198fcf3ce44SJohn Forte 		return (EBUSY);
1199fcf3ce44SJohn Forte 	}
1200fcf3ce44SJohn Forte 
1201fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_VPD_DATA);
1202fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
1203fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
1204fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1205fcf3ce44SJohn Forte 		ql_restart_driver(ha);
1206fcf3ce44SJohn Forte 		return (EIO);
1207fcf3ce44SJohn Forte 	}
1208fcf3ce44SJohn Forte 
1209fcf3ce44SJohn Forte 	/* Load VPD. */
1210*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_CTRL_252780818283)) {
1211fcf3ce44SJohn Forte 		GLOBAL_HW_UNLOCK();
12125dfd244aSDaniel Beauregard 		start_addr &= ~ha->flash_data_addr;
12135dfd244aSDaniel Beauregard 		start_addr <<= 2;
12145dfd244aSDaniel Beauregard 		if ((rval = ql_r_m_w_flash(ha, bp, vpd_size, start_addr,
12155dfd244aSDaniel Beauregard 		    mode)) != QL_SUCCESS) {
1216fcf3ce44SJohn Forte 			EL(ha, "vpd load error: %xh\n", rval);
1217fcf3ce44SJohn Forte 		}
1218fcf3ce44SJohn Forte 		GLOBAL_HW_LOCK();
1219fcf3ce44SJohn Forte 	} else {
1220fcf3ce44SJohn Forte 		lptr = (uint32_t *)vpd;
1221fcf3ce44SJohn Forte 		for (cnt = 0; cnt < vpd_size / 4; cnt++) {
1222fcf3ce44SJohn Forte 			data32 = *lptr++;
1223fcf3ce44SJohn Forte 			LITTLE_ENDIAN_32(&data32);
1224fcf3ce44SJohn Forte 			rval = ql_24xx_load_nvram(ha, cnt + start_addr,
1225fcf3ce44SJohn Forte 			    data32);
1226fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
1227fcf3ce44SJohn Forte 				EL(ha, "failed, 24xx_load_nvram=%xh\n", rval);
1228fcf3ce44SJohn Forte 				break;
1229fcf3ce44SJohn Forte 			}
1230fcf3ce44SJohn Forte 		}
1231fcf3ce44SJohn Forte 	}
1232fcf3ce44SJohn Forte 
1233fcf3ce44SJohn Forte 	kmem_free(vpd, vpd_size);
1234fcf3ce44SJohn Forte 
1235fcf3ce44SJohn Forte 	/* Update the vcache */
1236fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
1237fcf3ce44SJohn Forte 		EL(ha, "failed, load\n");
1238fcf3ce44SJohn Forte 	} else if ((ha->vcache == NULL) && ((ha->vcache =
1239fcf3ce44SJohn Forte 	    kmem_zalloc(vpd_size, KM_SLEEP)) == NULL)) {
1240fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc2\n");
1241fcf3ce44SJohn Forte 	} else if (ddi_copyin(bp, ha->vcache, vpd_size, mode) != 0) {
1242fcf3ce44SJohn Forte 		EL(ha, "Buffer copy2 failed\n");
1243fcf3ce44SJohn Forte 		kmem_free(ha->vcache, vpd_size);
1244fcf3ce44SJohn Forte 		ha->vcache = NULL;
1245fcf3ce44SJohn Forte 	}
1246fcf3ce44SJohn Forte 
1247fcf3ce44SJohn Forte 	ql_release_nvram(ha);
1248fcf3ce44SJohn Forte 	ql_restart_driver(ha);
1249fcf3ce44SJohn Forte 
1250*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1251fcf3ce44SJohn Forte 
1252fcf3ce44SJohn Forte 	if (rval == QL_SUCCESS) {
1253fcf3ce44SJohn Forte 		return (0);
1254fcf3ce44SJohn Forte 	}
1255fcf3ce44SJohn Forte 
1256fcf3ce44SJohn Forte 	return (EFAULT);
1257fcf3ce44SJohn Forte }
1258fcf3ce44SJohn Forte 
1259fcf3ce44SJohn Forte /*
1260fcf3ce44SJohn Forte  * ql_vpd_dump
1261fcf3ce44SJohn Forte  *	Dumps VPD to application buffer.
1262fcf3ce44SJohn Forte  *
1263fcf3ce44SJohn Forte  * Input:
1264fcf3ce44SJohn Forte  *	ha = adapter state pointer.
1265fcf3ce44SJohn Forte  *	bp = user buffer address.
1266fcf3ce44SJohn Forte  *
1267fcf3ce44SJohn Forte  * Returns:
1268fcf3ce44SJohn Forte  *
1269fcf3ce44SJohn Forte  * Context:
1270fcf3ce44SJohn Forte  *	Kernel context.
1271fcf3ce44SJohn Forte  */
1272fcf3ce44SJohn Forte int
ql_vpd_dump(ql_adapter_state_t * ha,void * bp,int mode)1273fcf3ce44SJohn Forte ql_vpd_dump(ql_adapter_state_t *ha, void *bp, int mode)
1274fcf3ce44SJohn Forte {
1275fcf3ce44SJohn Forte 	uint8_t		cnt;
1276fcf3ce44SJohn Forte 	void		*vpd;
1277fcf3ce44SJohn Forte 	uint32_t	start_addr, vpd_size, *lptr;
1278fcf3ce44SJohn Forte 	int		rval = 0;
1279fcf3ce44SJohn Forte 
1280*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
1281fcf3ce44SJohn Forte 
1282*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
1283fcf3ce44SJohn Forte 		EL(ha, "unsupported adapter feature\n");
1284fcf3ce44SJohn Forte 		return (EACCES);
1285fcf3ce44SJohn Forte 	}
1286fcf3ce44SJohn Forte 
1287fcf3ce44SJohn Forte 	vpd_size = QL_24XX_VPD_SIZE;
1288fcf3ce44SJohn Forte 
1289fcf3ce44SJohn Forte 	if (ha->vcache != NULL) {
1290fcf3ce44SJohn Forte 		/* copy back the vpd cache data */
1291fcf3ce44SJohn Forte 		if (ddi_copyout(ha->vcache, bp, vpd_size, mode) != 0) {
1292fcf3ce44SJohn Forte 			EL(ha, "Buffer copy failed\n");
1293fcf3ce44SJohn Forte 			rval = EFAULT;
1294fcf3ce44SJohn Forte 		}
1295fcf3ce44SJohn Forte 		return (rval);
1296fcf3ce44SJohn Forte 	}
1297fcf3ce44SJohn Forte 
1298fcf3ce44SJohn Forte 	if ((vpd = kmem_zalloc(vpd_size, KM_SLEEP)) == NULL) {
1299fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
1300fcf3ce44SJohn Forte 		return (ENOMEM);
1301fcf3ce44SJohn Forte 	}
1302fcf3ce44SJohn Forte 
1303fcf3ce44SJohn Forte 	/* Quiesce I/O */
1304fcf3ce44SJohn Forte 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
1305fcf3ce44SJohn Forte 		EL(ha, "ql_stall_driver failed\n");
1306fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1307fcf3ce44SJohn Forte 		return (EBUSY);
1308fcf3ce44SJohn Forte 	}
1309fcf3ce44SJohn Forte 
1310fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_VPD_DATA);
1311fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
1312fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
1313fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1314fcf3ce44SJohn Forte 		ql_restart_driver(ha);
1315fcf3ce44SJohn Forte 		return (EIO);
1316fcf3ce44SJohn Forte 	}
1317fcf3ce44SJohn Forte 
1318fcf3ce44SJohn Forte 	/* Dump VPD. */
1319fcf3ce44SJohn Forte 	lptr = (uint32_t *)vpd;
1320fcf3ce44SJohn Forte 
1321fcf3ce44SJohn Forte 	for (cnt = 0; cnt < vpd_size / 4; cnt++) {
1322fcf3ce44SJohn Forte 		rval = ql_24xx_read_flash(ha, start_addr++, lptr);
1323fcf3ce44SJohn Forte 		if (rval != QL_SUCCESS) {
1324fcf3ce44SJohn Forte 			EL(ha, "read_flash failed=%xh\n", rval);
1325fcf3ce44SJohn Forte 			rval = EAGAIN;
1326fcf3ce44SJohn Forte 			break;
1327fcf3ce44SJohn Forte 		}
1328fcf3ce44SJohn Forte 		LITTLE_ENDIAN_32(lptr);
1329fcf3ce44SJohn Forte 		lptr++;
1330fcf3ce44SJohn Forte 	}
1331fcf3ce44SJohn Forte 
1332fcf3ce44SJohn Forte 	ql_release_nvram(ha);
1333fcf3ce44SJohn Forte 	ql_restart_driver(ha);
1334fcf3ce44SJohn Forte 
1335fcf3ce44SJohn Forte 	if (ddi_copyout(vpd, bp, vpd_size, mode) != 0) {
1336fcf3ce44SJohn Forte 		EL(ha, "Buffer copy failed\n");
1337fcf3ce44SJohn Forte 		kmem_free(vpd, vpd_size);
1338fcf3ce44SJohn Forte 		return (EFAULT);
1339fcf3ce44SJohn Forte 	}
1340fcf3ce44SJohn Forte 
1341fcf3ce44SJohn Forte 	ha->vcache = vpd;
1342fcf3ce44SJohn Forte 
1343*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "done\n");
1344fcf3ce44SJohn Forte 
1345fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
1346fcf3ce44SJohn Forte 		return (EFAULT);
1347fcf3ce44SJohn Forte 	} else {
1348fcf3ce44SJohn Forte 		return (0);
1349fcf3ce44SJohn Forte 	}
1350fcf3ce44SJohn Forte }
1351fcf3ce44SJohn Forte 
1352fcf3ce44SJohn Forte /*
1353fcf3ce44SJohn Forte  * ql_vpd_findtag
1354fcf3ce44SJohn Forte  *	Search the passed vpd buffer for the requested VPD tag type.
1355fcf3ce44SJohn Forte  *
1356fcf3ce44SJohn Forte  * Input:
1357fcf3ce44SJohn Forte  *	ha	= adapter state pointer.
1358fcf3ce44SJohn Forte  *	vpdbuf	= Pointer to start of the buffer to search
1359fcf3ce44SJohn Forte  *	op	= VPD opcode to find (must be NULL terminated).
1360fcf3ce44SJohn Forte  *
1361fcf3ce44SJohn Forte  * Returns:
1362fcf3ce44SJohn Forte  *	Pointer to the opcode in the buffer if opcode found.
1363fcf3ce44SJohn Forte  *	NULL if opcode is not found.
1364fcf3ce44SJohn Forte  *
1365fcf3ce44SJohn Forte  * Context:
1366fcf3ce44SJohn Forte  *	Kernel context.
1367fcf3ce44SJohn Forte  */
1368fcf3ce44SJohn Forte static uint8_t *
ql_vpd_findtag(ql_adapter_state_t * ha,uint8_t * vpdbuf,int8_t * opcode)1369fcf3ce44SJohn Forte ql_vpd_findtag(ql_adapter_state_t *ha, uint8_t *vpdbuf, int8_t *opcode)
1370fcf3ce44SJohn Forte {
1371fcf3ce44SJohn Forte 	uint8_t		*vpd = vpdbuf;
1372fcf3ce44SJohn Forte 	uint8_t		*end = vpdbuf + QL_24XX_VPD_SIZE;
1373fcf3ce44SJohn Forte 	uint32_t	found = 0;
1374fcf3ce44SJohn Forte 
1375*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
1376fcf3ce44SJohn Forte 
1377fcf3ce44SJohn Forte 	if (vpdbuf == NULL || opcode == NULL) {
1378fcf3ce44SJohn Forte 		EL(ha, "null parameter passed!\n");
1379fcf3ce44SJohn Forte 		return (NULL);
1380fcf3ce44SJohn Forte 	}
1381fcf3ce44SJohn Forte 
1382fcf3ce44SJohn Forte 	while (vpd < end) {
1383fcf3ce44SJohn Forte 
1384fcf3ce44SJohn Forte 		/* check for end of vpd */
1385fcf3ce44SJohn Forte 		if (vpd[0] == VPD_TAG_END) {
1386fcf3ce44SJohn Forte 			if (opcode[0] == VPD_TAG_END) {
1387fcf3ce44SJohn Forte 				found = 1;
1388fcf3ce44SJohn Forte 			} else {
1389fcf3ce44SJohn Forte 				found = 0;
1390fcf3ce44SJohn Forte 			}
1391fcf3ce44SJohn Forte 			break;
1392fcf3ce44SJohn Forte 		}
1393fcf3ce44SJohn Forte 
1394fcf3ce44SJohn Forte 		/* check opcode */
1395fcf3ce44SJohn Forte 		if (bcmp(opcode, vpd, strlen(opcode)) == 0) {
1396fcf3ce44SJohn Forte 			/* found opcode requested */
1397fcf3ce44SJohn Forte 			found = 1;
1398fcf3ce44SJohn Forte 			break;
1399fcf3ce44SJohn Forte 		}
1400fcf3ce44SJohn Forte 
1401fcf3ce44SJohn Forte 		/*
1402fcf3ce44SJohn Forte 		 * Didn't find the opcode, so calculate start of
1403fcf3ce44SJohn Forte 		 * next tag. Depending on the current tag type,
1404fcf3ce44SJohn Forte 		 * the length field can be 1 or 2 bytes
1405fcf3ce44SJohn Forte 		 */
1406fcf3ce44SJohn Forte 		if (!(strncmp((char *)vpd, (char *)VPD_TAG_PRODID, 1))) {
1407fcf3ce44SJohn Forte 			vpd += (vpd[2] << 8) + vpd[1] + 3;
1408fcf3ce44SJohn Forte 		} else if (*vpd == VPD_TAG_LRT || *vpd == VPD_TAG_LRTC) {
1409fcf3ce44SJohn Forte 			vpd += 3;
1410fcf3ce44SJohn Forte 		} else {
1411fcf3ce44SJohn Forte 			vpd += vpd[2] +3;
1412fcf3ce44SJohn Forte 		}
1413fcf3ce44SJohn Forte 	}
1414fcf3ce44SJohn Forte 
1415*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "done\n");
1416fcf3ce44SJohn Forte 
1417fcf3ce44SJohn Forte 	return (found == 1 ? vpd : NULL);
1418fcf3ce44SJohn Forte }
1419fcf3ce44SJohn Forte 
1420fcf3ce44SJohn Forte /*
1421fcf3ce44SJohn Forte  * ql_vpd_lookup
1422fcf3ce44SJohn Forte  *	Return the VPD data for the request VPD tag
1423fcf3ce44SJohn Forte  *
1424fcf3ce44SJohn Forte  * Input:
1425fcf3ce44SJohn Forte  *	ha	= adapter state pointer.
1426fcf3ce44SJohn Forte  *	opcode	= VPD opcode to find (must be NULL terminated).
1427fcf3ce44SJohn Forte  *	bp	= Pointer to returned data buffer.
1428fcf3ce44SJohn Forte  *	bplen	= Length of returned data buffer.
1429fcf3ce44SJohn Forte  *
1430fcf3ce44SJohn Forte  * Returns:
1431fcf3ce44SJohn Forte  *	Length of data copied into returned data buffer.
1432fcf3ce44SJohn Forte  *		>0 = VPD data field (NULL terminated)
1433fcf3ce44SJohn Forte  *		 0 = no data.
1434fcf3ce44SJohn Forte  *		-1 = Could not find opcode in vpd buffer / error.
1435fcf3ce44SJohn Forte  *
1436fcf3ce44SJohn Forte  * Context:
1437fcf3ce44SJohn Forte  *	Kernel context.
1438fcf3ce44SJohn Forte  *
1439fcf3ce44SJohn Forte  * NB: The opcode buffer and the bp buffer *could* be the same buffer!
1440fcf3ce44SJohn Forte  *
1441fcf3ce44SJohn Forte  */
1442fcf3ce44SJohn Forte int32_t
ql_vpd_lookup(ql_adapter_state_t * ha,uint8_t * opcode,uint8_t * bp,int32_t bplen)1443fcf3ce44SJohn Forte ql_vpd_lookup(ql_adapter_state_t *ha, uint8_t *opcode, uint8_t *bp,
1444fcf3ce44SJohn Forte     int32_t bplen)
1445fcf3ce44SJohn Forte {
1446fcf3ce44SJohn Forte 	uint8_t		*vpd;
1447fcf3ce44SJohn Forte 	uint8_t		*vpdbuf;
1448fcf3ce44SJohn Forte 	int32_t		len = -1;
1449fcf3ce44SJohn Forte 
1450*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "started\n");
1451fcf3ce44SJohn Forte 
1452fcf3ce44SJohn Forte 	if (opcode == NULL || bp == NULL || bplen < 1) {
1453fcf3ce44SJohn Forte 		EL(ha, "invalid parameter passed: opcode=%ph, "
1454fcf3ce44SJohn Forte 		    "bp=%ph, bplen=%xh\n", opcode, bp, bplen);
1455fcf3ce44SJohn Forte 		return (len);
1456fcf3ce44SJohn Forte 	}
1457fcf3ce44SJohn Forte 
1458*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
1459fcf3ce44SJohn Forte 		return (len);
1460fcf3ce44SJohn Forte 	}
1461fcf3ce44SJohn Forte 
1462fcf3ce44SJohn Forte 	if ((vpdbuf = (uint8_t *)kmem_zalloc(QL_24XX_VPD_SIZE,
1463fcf3ce44SJohn Forte 	    KM_SLEEP)) == NULL) {
1464fcf3ce44SJohn Forte 		EL(ha, "unable to allocate vpd memory\n");
1465fcf3ce44SJohn Forte 		return (len);
1466fcf3ce44SJohn Forte 	}
1467fcf3ce44SJohn Forte 
1468fcf3ce44SJohn Forte 	if ((ql_vpd_dump(ha, vpdbuf, (int)FKIOCTL)) != 0) {
1469fcf3ce44SJohn Forte 		kmem_free(vpdbuf, QL_24XX_VPD_SIZE);
1470fcf3ce44SJohn Forte 		EL(ha, "unable to retrieve VPD data\n");
1471fcf3ce44SJohn Forte 		return (len);
1472fcf3ce44SJohn Forte 	}
1473fcf3ce44SJohn Forte 
1474fcf3ce44SJohn Forte 	if ((vpd = ql_vpd_findtag(ha, vpdbuf, (int8_t *)opcode)) != NULL) {
1475fcf3ce44SJohn Forte 		/*
1476fcf3ce44SJohn Forte 		 * Found the tag
1477fcf3ce44SJohn Forte 		 */
1478fcf3ce44SJohn Forte 		if (*opcode == VPD_TAG_END || *opcode == VPD_TAG_LRT ||
1479fcf3ce44SJohn Forte 		    *opcode == VPD_TAG_LRTC) {
1480fcf3ce44SJohn Forte 			/*
1481fcf3ce44SJohn Forte 			 * we found it, but the tag doesn't have a data
1482fcf3ce44SJohn Forte 			 * field.
1483fcf3ce44SJohn Forte 			 */
1484fcf3ce44SJohn Forte 			len = 0;
1485fcf3ce44SJohn Forte 		} else if (!(strncmp((char *)vpd, (char *)
1486fcf3ce44SJohn Forte 		    VPD_TAG_PRODID, 1))) {
1487fcf3ce44SJohn Forte 			len = vpd[2] << 8;
1488fcf3ce44SJohn Forte 			len += vpd[1];
1489fcf3ce44SJohn Forte 		} else {
1490fcf3ce44SJohn Forte 			len = vpd[2];
1491fcf3ce44SJohn Forte 		}
1492fcf3ce44SJohn Forte 
1493fcf3ce44SJohn Forte 		/*
1494fcf3ce44SJohn Forte 		 * make sure that the vpd len doesn't exceed the
1495fcf3ce44SJohn Forte 		 * vpd end
1496fcf3ce44SJohn Forte 		 */
1497*4c3888b8SHans Rosenfeld 		if (vpd + len > vpdbuf + QL_24XX_VPD_SIZE) {
1498fcf3ce44SJohn Forte 			EL(ha, "vpd tag len (%xh) exceeds vpd buffer "
1499fcf3ce44SJohn Forte 			    "length\n", len);
1500fcf3ce44SJohn Forte 			len = -1;
1501fcf3ce44SJohn Forte 		}
1502fcf3ce44SJohn Forte 	}
1503fcf3ce44SJohn Forte 
1504fcf3ce44SJohn Forte 	if (len >= 0) {
1505fcf3ce44SJohn Forte 		/*
1506fcf3ce44SJohn Forte 		 * make sure we don't exceed callers buffer space len
1507fcf3ce44SJohn Forte 		 */
1508fcf3ce44SJohn Forte 		if (len > bplen) {
1509*4c3888b8SHans Rosenfeld 			len = bplen - 1;
1510fcf3ce44SJohn Forte 		}
1511fcf3ce44SJohn Forte 
1512fcf3ce44SJohn Forte 		/* copy the data back */
1513*4c3888b8SHans Rosenfeld 		(void) strncpy((int8_t *)bp, (int8_t *)(vpd + 3), (int64_t)len);
1514c92b35bbSToomas Soome 		bp[len] = 0;
1515fcf3ce44SJohn Forte 	} else {
1516fcf3ce44SJohn Forte 		/* error -- couldn't find tag */
1517c92b35bbSToomas Soome 		bp[0] = 0;
1518c92b35bbSToomas Soome 		if (opcode[1] != 0) {
1519fcf3ce44SJohn Forte 			EL(ha, "unable to find tag '%s'\n", opcode);
1520fcf3ce44SJohn Forte 		} else {
1521fcf3ce44SJohn Forte 			EL(ha, "unable to find tag '%xh'\n", opcode[0]);
1522fcf3ce44SJohn Forte 		}
1523fcf3ce44SJohn Forte 	}
1524fcf3ce44SJohn Forte 
1525fcf3ce44SJohn Forte 	kmem_free(vpdbuf, QL_24XX_VPD_SIZE);
1526fcf3ce44SJohn Forte 
1527*4c3888b8SHans Rosenfeld 	QL_PRINT_3(ha, "done\n");
1528fcf3ce44SJohn Forte 
1529fcf3ce44SJohn Forte 	return (len);
1530fcf3ce44SJohn Forte }
1531fcf3ce44SJohn Forte 
15325dfd244aSDaniel Beauregard /*
15335dfd244aSDaniel Beauregard  * ql_r_m_w_flash
15345dfd244aSDaniel Beauregard  *	Read modify write from user space to flash.
15355dfd244aSDaniel Beauregard  *
15365dfd244aSDaniel Beauregard  * Input:
15375dfd244aSDaniel Beauregard  *	ha:	adapter state pointer.
15385dfd244aSDaniel Beauregard  *	dp:	source byte pointer.
15395dfd244aSDaniel Beauregard  *	bc:	byte count.
15405dfd244aSDaniel Beauregard  *	faddr:	flash byte address.
15415dfd244aSDaniel Beauregard  *	mode:	flags.
15425dfd244aSDaniel Beauregard  *
15435dfd244aSDaniel Beauregard  * Returns:
15445dfd244aSDaniel Beauregard  *	ql local function return status code.
15455dfd244aSDaniel Beauregard  *
15465dfd244aSDaniel Beauregard  * Context:
15475dfd244aSDaniel Beauregard  *	Kernel context.
15485dfd244aSDaniel Beauregard  */
15495dfd244aSDaniel Beauregard int
ql_r_m_w_flash(ql_adapter_state_t * ha,caddr_t dp,uint32_t bc,uint32_t faddr,int mode)15505dfd244aSDaniel Beauregard ql_r_m_w_flash(ql_adapter_state_t *ha, caddr_t dp, uint32_t bc, uint32_t faddr,
15515dfd244aSDaniel Beauregard     int mode)
1552fcf3ce44SJohn Forte {
1553fcf3ce44SJohn Forte 	uint8_t		*bp;
15545dfd244aSDaniel Beauregard 	uint32_t	xfer, bsize, saddr, ofst;
15555dfd244aSDaniel Beauregard 	int		rval = 0;
15565dfd244aSDaniel Beauregard 
1557*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started, dp=%ph, faddr=%xh, bc=%xh\n",
1558*4c3888b8SHans Rosenfeld 	    (void *)dp, faddr, bc);
15595dfd244aSDaniel Beauregard 
15605dfd244aSDaniel Beauregard 	bsize = ha->xioctl->fdesc.block_size;
15615dfd244aSDaniel Beauregard 	saddr = faddr & ~(bsize - 1);
15625dfd244aSDaniel Beauregard 	ofst = faddr & (bsize - 1);
1563fcf3ce44SJohn Forte 
1564fcf3ce44SJohn Forte 	if ((bp = kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
15655dfd244aSDaniel Beauregard 		EL(ha, "kmem_zalloc=null\n");
15665dfd244aSDaniel Beauregard 		return (QL_MEMORY_ALLOC_FAILED);
1567fcf3ce44SJohn Forte 	}
1568fcf3ce44SJohn Forte 
15695dfd244aSDaniel Beauregard 	while (bc) {
15705dfd244aSDaniel Beauregard 		xfer = bc > bsize ? bsize : bc;
15715dfd244aSDaniel Beauregard 		if (ofst + xfer > bsize) {
15725dfd244aSDaniel Beauregard 			xfer = bsize - ofst;
15735dfd244aSDaniel Beauregard 		}
1574*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "dp=%ph, saddr=%xh, bc=%xh, "
1575*4c3888b8SHans Rosenfeld 		    "ofst=%xh, xfer=%xh\n", (void *)dp, saddr,
15765dfd244aSDaniel Beauregard 		    bc, ofst, xfer);
15775dfd244aSDaniel Beauregard 
15785dfd244aSDaniel Beauregard 		if (ofst || xfer < bsize) {
15795dfd244aSDaniel Beauregard 			/* Dump Flash sector. */
15805dfd244aSDaniel Beauregard 			if ((rval = ql_dump_fcode(ha, bp, bsize, saddr)) !=
15815dfd244aSDaniel Beauregard 			    QL_SUCCESS) {
15825dfd244aSDaniel Beauregard 				EL(ha, "dump_flash status=%x\n", rval);
15835dfd244aSDaniel Beauregard 				break;
15845dfd244aSDaniel Beauregard 			}
15855dfd244aSDaniel Beauregard 		}
1586fcf3ce44SJohn Forte 
1587fcf3ce44SJohn Forte 		/* Set new data. */
15885dfd244aSDaniel Beauregard 		if ((rval = ddi_copyin(dp, (caddr_t)(bp + ofst), xfer,
15895dfd244aSDaniel Beauregard 		    mode)) != 0) {
15905dfd244aSDaniel Beauregard 			EL(ha, "ddi_copyin status=%xh, dp=%ph, ofst=%xh, "
15915dfd244aSDaniel Beauregard 			    "xfer=%xh\n", rval, (void *)dp, ofst, xfer);
15925dfd244aSDaniel Beauregard 			rval = QL_FUNCTION_FAILED;
15935dfd244aSDaniel Beauregard 			break;
15945dfd244aSDaniel Beauregard 		}
1595fcf3ce44SJohn Forte 
1596fcf3ce44SJohn Forte 		/* Write to flash. */
15975dfd244aSDaniel Beauregard 		if ((rval = ql_load_fcode(ha, bp, bsize, saddr)) !=
15985dfd244aSDaniel Beauregard 		    QL_SUCCESS) {
15995dfd244aSDaniel Beauregard 			EL(ha, "load_flash status=%x\n", rval);
16005dfd244aSDaniel Beauregard 			break;
16015dfd244aSDaniel Beauregard 		}
16025dfd244aSDaniel Beauregard 		bc -= xfer;
16035dfd244aSDaniel Beauregard 		dp += xfer;
16045dfd244aSDaniel Beauregard 		saddr += bsize;
16055dfd244aSDaniel Beauregard 		ofst = 0;
1606fcf3ce44SJohn Forte 	}
1607fcf3ce44SJohn Forte 
1608fcf3ce44SJohn Forte 	kmem_free(bp, bsize);
1609fcf3ce44SJohn Forte 
1610*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
16115dfd244aSDaniel Beauregard 
1612fcf3ce44SJohn Forte 	return (rval);
1613fcf3ce44SJohn Forte }
1614fcf3ce44SJohn Forte 
1615fcf3ce44SJohn Forte /*
1616fcf3ce44SJohn Forte  * ql_adm_op
1617fcf3ce44SJohn Forte  *	Performs qladm utility operations
1618fcf3ce44SJohn Forte  *
1619fcf3ce44SJohn Forte  * Input:
1620fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
1621fcf3ce44SJohn Forte  *	arg:	driver_op_t structure pointer.
1622fcf3ce44SJohn Forte  *	mode:	flags.
1623fcf3ce44SJohn Forte  *
1624fcf3ce44SJohn Forte  * Returns:
1625fcf3ce44SJohn Forte  *
1626fcf3ce44SJohn Forte  * Context:
1627fcf3ce44SJohn Forte  *	Kernel context.
1628fcf3ce44SJohn Forte  */
1629fcf3ce44SJohn Forte static int
ql_adm_op(ql_adapter_state_t * ha,void * arg,int mode)1630fcf3ce44SJohn Forte ql_adm_op(ql_adapter_state_t *ha, void *arg, int mode)
1631fcf3ce44SJohn Forte {
1632fcf3ce44SJohn Forte 	ql_adm_op_t		dop;
1633fcf3ce44SJohn Forte 	int			rval = 0;
1634fcf3ce44SJohn Forte 
1635fcf3ce44SJohn Forte 	if (ddi_copyin(arg, &dop, sizeof (ql_adm_op_t), mode) != 0) {
1636fcf3ce44SJohn Forte 		EL(ha, "failed, driver_op_t ddi_copyin\n");
1637fcf3ce44SJohn Forte 		return (EFAULT);
1638fcf3ce44SJohn Forte 	}
1639fcf3ce44SJohn Forte 
1640*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started, cmd=%xh, buffer=%llx,"
1641*4c3888b8SHans Rosenfeld 	    " length=%xh, option=%xh\n", dop.cmd, dop.buffer,
1642fcf3ce44SJohn Forte 	    dop.length, dop.option);
1643fcf3ce44SJohn Forte 
1644fcf3ce44SJohn Forte 	switch (dop.cmd) {
1645fcf3ce44SJohn Forte 	case QL_ADAPTER_INFO:
1646fcf3ce44SJohn Forte 		rval = ql_adm_adapter_info(ha, &dop, mode);
1647fcf3ce44SJohn Forte 		break;
1648fcf3ce44SJohn Forte 
1649fcf3ce44SJohn Forte 	case QL_EXTENDED_LOGGING:
1650fcf3ce44SJohn Forte 		rval = ql_adm_extended_logging(ha, &dop);
1651fcf3ce44SJohn Forte 		break;
1652fcf3ce44SJohn Forte 
1653fcf3ce44SJohn Forte 	case QL_LOOP_RESET:
1654fcf3ce44SJohn Forte 		rval = ql_adm_loop_reset(ha);
1655fcf3ce44SJohn Forte 		break;
1656fcf3ce44SJohn Forte 
1657fcf3ce44SJohn Forte 	case QL_DEVICE_LIST:
1658fcf3ce44SJohn Forte 		rval = ql_adm_device_list(ha, &dop, mode);
1659fcf3ce44SJohn Forte 		break;
1660fcf3ce44SJohn Forte 
1661fcf3ce44SJohn Forte 	case QL_PROP_UPDATE_INT:
1662fcf3ce44SJohn Forte 		rval = ql_adm_prop_update_int(ha, &dop, mode);
1663fcf3ce44SJohn Forte 		break;
1664fcf3ce44SJohn Forte 
1665fcf3ce44SJohn Forte 	case QL_UPDATE_PROPERTIES:
1666fcf3ce44SJohn Forte 		rval = ql_adm_update_properties(ha);
1667fcf3ce44SJohn Forte 		break;
1668fcf3ce44SJohn Forte 
1669fcf3ce44SJohn Forte 	case QL_FW_DUMP:
1670fcf3ce44SJohn Forte 		rval = ql_adm_fw_dump(ha, &dop, arg, mode);
1671fcf3ce44SJohn Forte 		break;
1672fcf3ce44SJohn Forte 
1673*4c3888b8SHans Rosenfeld 	case QL_FW_DUMP_TRIGGER:
1674*4c3888b8SHans Rosenfeld 		rval = ql_adm_fw_t_dump(ha);
1675*4c3888b8SHans Rosenfeld 		break;
1676*4c3888b8SHans Rosenfeld 
1677*4c3888b8SHans Rosenfeld 	case QL_BEACON_ENABLE:
1678*4c3888b8SHans Rosenfeld 	case QL_BEACON_DISABLE:
1679*4c3888b8SHans Rosenfeld 		rval = ql_adm_beacon(ha, &dop);
1680*4c3888b8SHans Rosenfeld 		break;
1681*4c3888b8SHans Rosenfeld 
1682fcf3ce44SJohn Forte 	case QL_NVRAM_LOAD:
1683fcf3ce44SJohn Forte 		rval = ql_adm_nvram_load(ha, &dop, mode);
1684fcf3ce44SJohn Forte 		break;
1685fcf3ce44SJohn Forte 
1686fcf3ce44SJohn Forte 	case QL_NVRAM_DUMP:
1687fcf3ce44SJohn Forte 		rval = ql_adm_nvram_dump(ha, &dop, mode);
1688fcf3ce44SJohn Forte 		break;
1689fcf3ce44SJohn Forte 
1690fcf3ce44SJohn Forte 	case QL_FLASH_LOAD:
1691fcf3ce44SJohn Forte 		rval = ql_adm_flash_load(ha, &dop, mode);
1692fcf3ce44SJohn Forte 		break;
1693fcf3ce44SJohn Forte 
1694fcf3ce44SJohn Forte 	case QL_VPD_LOAD:
1695fcf3ce44SJohn Forte 		rval = ql_adm_vpd_load(ha, &dop, mode);
1696fcf3ce44SJohn Forte 		break;
1697fcf3ce44SJohn Forte 
1698fcf3ce44SJohn Forte 	case QL_VPD_DUMP:
1699fcf3ce44SJohn Forte 		rval = ql_adm_vpd_dump(ha, &dop, mode);
1700fcf3ce44SJohn Forte 		break;
1701fcf3ce44SJohn Forte 
1702fcf3ce44SJohn Forte 	case QL_VPD_GETTAG:
1703fcf3ce44SJohn Forte 		rval = ql_adm_vpd_gettag(ha, &dop, mode);
1704fcf3ce44SJohn Forte 		break;
1705fcf3ce44SJohn Forte 
1706fcf3ce44SJohn Forte 	case QL_UPD_FWMODULE:
1707fcf3ce44SJohn Forte 		rval = ql_adm_updfwmodule(ha, &dop, mode);
1708fcf3ce44SJohn Forte 		break;
1709fcf3ce44SJohn Forte 
1710fcf3ce44SJohn Forte 	default:
1711fcf3ce44SJohn Forte 		EL(ha, "unsupported driver op cmd: %x\n", dop.cmd);
1712fcf3ce44SJohn Forte 		return (EINVAL);
1713fcf3ce44SJohn Forte 	}
1714fcf3ce44SJohn Forte 
1715*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1716fcf3ce44SJohn Forte 
1717fcf3ce44SJohn Forte 	return (rval);
1718fcf3ce44SJohn Forte }
1719fcf3ce44SJohn Forte 
1720fcf3ce44SJohn Forte /*
1721fcf3ce44SJohn Forte  * ql_adm_adapter_info
1722fcf3ce44SJohn Forte  *	Performs qladm QL_ADAPTER_INFO command
1723fcf3ce44SJohn Forte  *
1724fcf3ce44SJohn Forte  * Input:
1725fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
1726fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
1727fcf3ce44SJohn Forte  *	mode:	flags.
1728fcf3ce44SJohn Forte  *
1729fcf3ce44SJohn Forte  * Returns:
1730fcf3ce44SJohn Forte  *
1731fcf3ce44SJohn Forte  * Context:
1732fcf3ce44SJohn Forte  *	Kernel context.
1733fcf3ce44SJohn Forte  */
1734fcf3ce44SJohn Forte static int
ql_adm_adapter_info(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)1735fcf3ce44SJohn Forte ql_adm_adapter_info(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
1736fcf3ce44SJohn Forte {
1737fcf3ce44SJohn Forte 	ql_adapter_info_t	hba;
1738fcf3ce44SJohn Forte 	uint8_t			*dp;
1739fcf3ce44SJohn Forte 	uint32_t		length;
1740fcf3ce44SJohn Forte 	int			rval, i;
1741fcf3ce44SJohn Forte 
1742*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1743fcf3ce44SJohn Forte 
1744fcf3ce44SJohn Forte 	hba.device_id = ha->device_id;
1745fcf3ce44SJohn Forte 
1746*4c3888b8SHans Rosenfeld 	dp = ha->loginparams.nport_ww_name.raw_wwn;
1747fcf3ce44SJohn Forte 	bcopy(dp, hba.wwpn, 8);
1748fcf3ce44SJohn Forte 
1749fcf3ce44SJohn Forte 	hba.d_id = ha->d_id.b24;
1750fcf3ce44SJohn Forte 
1751fcf3ce44SJohn Forte 	if (ha->xioctl->fdesc.flash_size == 0 &&
1752*4c3888b8SHans Rosenfeld 	    !(CFG_IST(ha, CFG_CTRL_22XX) && !ha->subven_id)) {
1753fcf3ce44SJohn Forte 		if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
1754fcf3ce44SJohn Forte 			EL(ha, "ql_stall_driver failed\n");
1755fcf3ce44SJohn Forte 			return (EBUSY);
1756fcf3ce44SJohn Forte 		}
1757fcf3ce44SJohn Forte 
17585dfd244aSDaniel Beauregard 		if ((rval = ql_setup_fcache(ha)) != QL_SUCCESS) {
1759fcf3ce44SJohn Forte 			EL(ha, "ql_setup_flash failed=%xh\n", rval);
1760fcf3ce44SJohn Forte 			if (rval == QL_FUNCTION_TIMEOUT) {
1761fcf3ce44SJohn Forte 				return (EBUSY);
1762fcf3ce44SJohn Forte 			}
1763fcf3ce44SJohn Forte 			return (EIO);
1764fcf3ce44SJohn Forte 		}
1765fcf3ce44SJohn Forte 
1766fcf3ce44SJohn Forte 		/* Resume I/O */
1767*4c3888b8SHans Rosenfeld 		if (CFG_IST(ha, CFG_ISP_FW_TYPE_2)) {
1768fcf3ce44SJohn Forte 			ql_restart_driver(ha);
1769fcf3ce44SJohn Forte 		} else {
1770fcf3ce44SJohn Forte 			EL(ha, "isp_abort_needed for restart\n");
1771fcf3ce44SJohn Forte 			ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
1772fcf3ce44SJohn Forte 			    DRIVER_STALL);
1773fcf3ce44SJohn Forte 		}
1774fcf3ce44SJohn Forte 	}
1775fcf3ce44SJohn Forte 	hba.flash_size = ha->xioctl->fdesc.flash_size;
1776fcf3ce44SJohn Forte 
1777fcf3ce44SJohn Forte 	(void) strcpy(hba.driver_ver, QL_VERSION);
1778fcf3ce44SJohn Forte 
1779fcf3ce44SJohn Forte 	(void) sprintf(hba.fw_ver, "%d.%d.%d", ha->fw_major_version,
1780fcf3ce44SJohn Forte 	    ha->fw_minor_version, ha->fw_subminor_version);
1781fcf3ce44SJohn Forte 
1782fcf3ce44SJohn Forte 	bzero(hba.fcode_ver, sizeof (hba.fcode_ver));
1783fcf3ce44SJohn Forte 
1784fcf3ce44SJohn Forte 	/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
1785fcf3ce44SJohn Forte 	rval = ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
178616dd44c2SDaniel Beauregard 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&dp, &i);
1787fcf3ce44SJohn Forte 	length = i;
1788fcf3ce44SJohn Forte 	if (rval != DDI_PROP_SUCCESS) {
1789fcf3ce44SJohn Forte 		EL(ha, "failed, ddi_getlongprop=%xh\n", rval);
1790fcf3ce44SJohn Forte 	} else {
1791fcf3ce44SJohn Forte 		if (length > (uint32_t)sizeof (hba.fcode_ver)) {
1792fcf3ce44SJohn Forte 			length = sizeof (hba.fcode_ver) - 1;
1793fcf3ce44SJohn Forte 		}
1794fcf3ce44SJohn Forte 		bcopy((void *)dp, (void *)hba.fcode_ver, length);
1795fcf3ce44SJohn Forte 		kmem_free(dp, length);
1796fcf3ce44SJohn Forte 	}
1797fcf3ce44SJohn Forte 
1798fcf3ce44SJohn Forte 	if (ddi_copyout((void *)&hba, (void *)(uintptr_t)dop->buffer,
179916dd44c2SDaniel Beauregard 	    dop->length, mode) != 0) {
1800fcf3ce44SJohn Forte 		EL(ha, "failed, ddi_copyout\n");
1801fcf3ce44SJohn Forte 		return (EFAULT);
1802fcf3ce44SJohn Forte 	}
1803fcf3ce44SJohn Forte 
1804*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1805fcf3ce44SJohn Forte 
1806fcf3ce44SJohn Forte 	return (0);
1807fcf3ce44SJohn Forte }
1808fcf3ce44SJohn Forte 
1809fcf3ce44SJohn Forte /*
1810fcf3ce44SJohn Forte  * ql_adm_extended_logging
1811fcf3ce44SJohn Forte  *	Performs qladm QL_EXTENDED_LOGGING command
1812fcf3ce44SJohn Forte  *
1813fcf3ce44SJohn Forte  * Input:
1814fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
1815fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
1816fcf3ce44SJohn Forte  *
1817fcf3ce44SJohn Forte  * Returns:
1818fcf3ce44SJohn Forte  *
1819fcf3ce44SJohn Forte  * Context:
1820fcf3ce44SJohn Forte  *	Kernel context.
1821fcf3ce44SJohn Forte  */
1822fcf3ce44SJohn Forte static int
ql_adm_extended_logging(ql_adapter_state_t * ha,ql_adm_op_t * dop)1823fcf3ce44SJohn Forte ql_adm_extended_logging(ql_adapter_state_t *ha, ql_adm_op_t *dop)
1824fcf3ce44SJohn Forte {
1825fcf3ce44SJohn Forte 	char	prop_name[MAX_PROP_LENGTH];
1826fcf3ce44SJohn Forte 	int	rval;
1827fcf3ce44SJohn Forte 
1828*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1829fcf3ce44SJohn Forte 
1830fcf3ce44SJohn Forte 	(void) sprintf(prop_name, "hba%d-extended-logging", ha->instance);
1831fcf3ce44SJohn Forte 
1832fcf3ce44SJohn Forte 	/*LINTED [Solaris DDI_DEV_T_NONE Lint warning]*/
1833fcf3ce44SJohn Forte 	rval = ddi_prop_update_int(DDI_DEV_T_NONE, ha->dip, prop_name,
1834fcf3ce44SJohn Forte 	    (int)dop->option);
1835fcf3ce44SJohn Forte 	if (rval != DDI_PROP_SUCCESS) {
1836fcf3ce44SJohn Forte 		EL(ha, "failed, prop_update = %xh\n", rval);
1837fcf3ce44SJohn Forte 		return (EINVAL);
1838fcf3ce44SJohn Forte 	} else {
1839fcf3ce44SJohn Forte 		dop->option ?
1840fcf3ce44SJohn Forte 		    (ha->cfg_flags |= CFG_ENABLE_EXTENDED_LOGGING) :
1841fcf3ce44SJohn Forte 		    (ha->cfg_flags &= ~CFG_ENABLE_EXTENDED_LOGGING);
1842fcf3ce44SJohn Forte 	}
1843fcf3ce44SJohn Forte 
1844*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1845fcf3ce44SJohn Forte 
1846fcf3ce44SJohn Forte 	return (0);
1847fcf3ce44SJohn Forte }
1848fcf3ce44SJohn Forte 
1849fcf3ce44SJohn Forte /*
1850fcf3ce44SJohn Forte  * ql_adm_loop_reset
1851fcf3ce44SJohn Forte  *	Performs qladm QL_LOOP_RESET command
1852fcf3ce44SJohn Forte  *
1853fcf3ce44SJohn Forte  * Input:
1854fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
1855fcf3ce44SJohn Forte  *
1856fcf3ce44SJohn Forte  * Returns:
1857fcf3ce44SJohn Forte  *
1858fcf3ce44SJohn Forte  * Context:
1859fcf3ce44SJohn Forte  *	Kernel context.
1860fcf3ce44SJohn Forte  */
1861fcf3ce44SJohn Forte static int
ql_adm_loop_reset(ql_adapter_state_t * ha)1862fcf3ce44SJohn Forte ql_adm_loop_reset(ql_adapter_state_t *ha)
1863fcf3ce44SJohn Forte {
1864fcf3ce44SJohn Forte 	int	rval;
1865fcf3ce44SJohn Forte 
1866*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1867fcf3ce44SJohn Forte 
1868*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_CTRL_82XX)) {
1869*4c3888b8SHans Rosenfeld 		rval = ql_8021_fw_reload(ha);
1870*4c3888b8SHans Rosenfeld 		ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED, 0);
1871*4c3888b8SHans Rosenfeld 		if (rval != QL_SUCCESS) {
1872*4c3888b8SHans Rosenfeld 			EL(ha, "failed, ql_8021_fw_reload=%xh\n", rval);
1873*4c3888b8SHans Rosenfeld 			return (EIO);
1874*4c3888b8SHans Rosenfeld 		}
1875*4c3888b8SHans Rosenfeld 	} else {
1876*4c3888b8SHans Rosenfeld 		if (ha->task_daemon_flags & LOOP_DOWN) {
1877*4c3888b8SHans Rosenfeld 			(void) ql_full_login_lip(ha);
1878*4c3888b8SHans Rosenfeld 		} else if ((rval = ql_full_login_lip(ha)) != QL_SUCCESS) {
1879*4c3888b8SHans Rosenfeld 			EL(ha, "failed, ql_initiate_lip=%xh\n", rval);
1880*4c3888b8SHans Rosenfeld 			return (EIO);
1881*4c3888b8SHans Rosenfeld 		}
1882fcf3ce44SJohn Forte 	}
1883fcf3ce44SJohn Forte 
1884*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1885fcf3ce44SJohn Forte 
1886fcf3ce44SJohn Forte 	return (0);
1887fcf3ce44SJohn Forte }
1888fcf3ce44SJohn Forte 
1889fcf3ce44SJohn Forte /*
1890fcf3ce44SJohn Forte  * ql_adm_device_list
1891fcf3ce44SJohn Forte  *	Performs qladm QL_DEVICE_LIST command
1892fcf3ce44SJohn Forte  *
1893fcf3ce44SJohn Forte  * Input:
1894fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
1895fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
1896fcf3ce44SJohn Forte  *	mode:	flags.
1897fcf3ce44SJohn Forte  *
1898fcf3ce44SJohn Forte  * Returns:
1899fcf3ce44SJohn Forte  *
1900fcf3ce44SJohn Forte  * Context:
1901fcf3ce44SJohn Forte  *	Kernel context.
1902fcf3ce44SJohn Forte  */
1903fcf3ce44SJohn Forte static int
ql_adm_device_list(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)1904fcf3ce44SJohn Forte ql_adm_device_list(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
1905fcf3ce44SJohn Forte {
1906fcf3ce44SJohn Forte 	ql_device_info_t	dev;
1907fcf3ce44SJohn Forte 	ql_link_t		*link;
1908fcf3ce44SJohn Forte 	ql_tgt_t		*tq;
1909fcf3ce44SJohn Forte 	uint32_t		index, cnt;
1910fcf3ce44SJohn Forte 
1911*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1912fcf3ce44SJohn Forte 
1913fcf3ce44SJohn Forte 	cnt = 0;
1914fcf3ce44SJohn Forte 	dev.address = 0xffffffff;
1915fcf3ce44SJohn Forte 
1916fcf3ce44SJohn Forte 	/* Scan port list for requested target and fill in the values */
1917fcf3ce44SJohn Forte 	for (link = NULL, index = 0;
1918fcf3ce44SJohn Forte 	    index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
1919fcf3ce44SJohn Forte 		for (link = ha->dev[index].first; link != NULL;
1920fcf3ce44SJohn Forte 		    link = link->next) {
1921fcf3ce44SJohn Forte 			tq = link->base_address;
1922fcf3ce44SJohn Forte 
1923fcf3ce44SJohn Forte 			if (!VALID_TARGET_ID(ha, tq->loop_id)) {
1924fcf3ce44SJohn Forte 				continue;
1925fcf3ce44SJohn Forte 			}
1926fcf3ce44SJohn Forte 			if (cnt != dop->option) {
1927fcf3ce44SJohn Forte 				cnt++;
1928fcf3ce44SJohn Forte 				continue;
1929fcf3ce44SJohn Forte 			}
1930fcf3ce44SJohn Forte 			/* fill in the values */
1931fcf3ce44SJohn Forte 			bcopy(tq->port_name, dev.wwpn, 8);
1932fcf3ce44SJohn Forte 			dev.address = tq->d_id.b24;
1933fcf3ce44SJohn Forte 			dev.loop_id = tq->loop_id;
1934fcf3ce44SJohn Forte 			if (tq->flags & TQF_TAPE_DEVICE) {
1935fcf3ce44SJohn Forte 				dev.type = FCT_TAPE;
1936fcf3ce44SJohn Forte 			} else if (tq->flags & TQF_INITIATOR_DEVICE) {
1937fcf3ce44SJohn Forte 				dev.type = FCT_INITIATOR;
1938fcf3ce44SJohn Forte 			} else {
1939fcf3ce44SJohn Forte 				dev.type = FCT_TARGET;
1940fcf3ce44SJohn Forte 			}
1941fcf3ce44SJohn Forte 			break;
1942fcf3ce44SJohn Forte 		}
1943fcf3ce44SJohn Forte 	}
1944fcf3ce44SJohn Forte 
1945fcf3ce44SJohn Forte 	if (ddi_copyout((void *)&dev, (void *)(uintptr_t)dop->buffer,
194616dd44c2SDaniel Beauregard 	    dop->length, mode) != 0) {
1947fcf3ce44SJohn Forte 		EL(ha, "failed, ddi_copyout\n");
1948fcf3ce44SJohn Forte 		return (EFAULT);
1949fcf3ce44SJohn Forte 	}
1950fcf3ce44SJohn Forte 
1951*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
1952fcf3ce44SJohn Forte 
1953fcf3ce44SJohn Forte 	return (0);
1954fcf3ce44SJohn Forte }
1955fcf3ce44SJohn Forte 
1956fcf3ce44SJohn Forte /*
1957fcf3ce44SJohn Forte  * ql_adm_update_properties
1958fcf3ce44SJohn Forte  *	Performs qladm QL_UPDATE_PROPERTIES command
1959fcf3ce44SJohn Forte  *
1960fcf3ce44SJohn Forte  * Input:
1961fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
1962fcf3ce44SJohn Forte  *
1963fcf3ce44SJohn Forte  * Returns:
1964fcf3ce44SJohn Forte  *
1965fcf3ce44SJohn Forte  * Context:
1966fcf3ce44SJohn Forte  *	Kernel context.
1967fcf3ce44SJohn Forte  */
1968fcf3ce44SJohn Forte static int
ql_adm_update_properties(ql_adapter_state_t * ha)1969fcf3ce44SJohn Forte ql_adm_update_properties(ql_adapter_state_t *ha)
1970fcf3ce44SJohn Forte {
1971fcf3ce44SJohn Forte 	ql_comb_init_cb_t	init_ctrl_blk;
1972fcf3ce44SJohn Forte 	ql_comb_ip_init_cb_t	ip_init_ctrl_blk;
1973fcf3ce44SJohn Forte 
1974*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
1975fcf3ce44SJohn Forte 
1976fcf3ce44SJohn Forte 	/* Stall driver instance. */
1977fcf3ce44SJohn Forte 	(void) ql_stall_driver(ha, 0);
1978fcf3ce44SJohn Forte 
1979fcf3ce44SJohn Forte 	/* Save init control blocks. */
1980fcf3ce44SJohn Forte 	bcopy(&ha->init_ctrl_blk, &init_ctrl_blk, sizeof (ql_comb_init_cb_t));
1981fcf3ce44SJohn Forte 	bcopy(&ha->ip_init_ctrl_blk, &ip_init_ctrl_blk,
1982fcf3ce44SJohn Forte 	    sizeof (ql_comb_ip_init_cb_t));
1983fcf3ce44SJohn Forte 
1984fcf3ce44SJohn Forte 	/* Update PCI configration. */
1985fcf3ce44SJohn Forte 	(void) ql_pci_sbus_config(ha);
1986fcf3ce44SJohn Forte 
1987fcf3ce44SJohn Forte 	/* Get configuration properties. */
1988fcf3ce44SJohn Forte 	(void) ql_nvram_config(ha);
1989fcf3ce44SJohn Forte 
1990fcf3ce44SJohn Forte 	/* Check for init firmware required. */
1991fcf3ce44SJohn Forte 	if (bcmp(&ha->init_ctrl_blk, &init_ctrl_blk,
1992fcf3ce44SJohn Forte 	    sizeof (ql_comb_init_cb_t)) != 0 ||
1993fcf3ce44SJohn Forte 	    bcmp(&ha->ip_init_ctrl_blk, &ip_init_ctrl_blk,
1994fcf3ce44SJohn Forte 	    sizeof (ql_comb_ip_init_cb_t)) != 0) {
1995fcf3ce44SJohn Forte 
1996fcf3ce44SJohn Forte 		EL(ha, "isp_abort_needed\n");
1997fcf3ce44SJohn Forte 		ha->loop_down_timer = LOOP_DOWN_TIMER_START;
1998fcf3ce44SJohn Forte 		TASK_DAEMON_LOCK(ha);
1999fcf3ce44SJohn Forte 		ha->task_daemon_flags |= LOOP_DOWN | ISP_ABORT_NEEDED;
2000fcf3ce44SJohn Forte 		TASK_DAEMON_UNLOCK(ha);
2001fcf3ce44SJohn Forte 	}
2002fcf3ce44SJohn Forte 
2003fcf3ce44SJohn Forte 	/* Update AEN queue. */
2004fcf3ce44SJohn Forte 	if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
2005fcf3ce44SJohn Forte 		ql_enqueue_aen(ha, MBA_PORT_UPDATE, NULL);
2006fcf3ce44SJohn Forte 	}
2007fcf3ce44SJohn Forte 
2008fcf3ce44SJohn Forte 	/* Restart driver instance. */
2009fcf3ce44SJohn Forte 	ql_restart_driver(ha);
2010fcf3ce44SJohn Forte 
2011*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2012fcf3ce44SJohn Forte 
2013fcf3ce44SJohn Forte 	return (0);
2014fcf3ce44SJohn Forte }
2015fcf3ce44SJohn Forte 
2016fcf3ce44SJohn Forte /*
2017fcf3ce44SJohn Forte  * ql_adm_prop_update_int
2018fcf3ce44SJohn Forte  *	Performs qladm QL_PROP_UPDATE_INT command
2019fcf3ce44SJohn Forte  *
2020fcf3ce44SJohn Forte  * Input:
2021fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2022fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2023fcf3ce44SJohn Forte  *	mode:	flags.
2024fcf3ce44SJohn Forte  *
2025fcf3ce44SJohn Forte  * Returns:
2026fcf3ce44SJohn Forte  *
2027fcf3ce44SJohn Forte  * Context:
2028fcf3ce44SJohn Forte  *	Kernel context.
2029fcf3ce44SJohn Forte  */
2030fcf3ce44SJohn Forte static int
ql_adm_prop_update_int(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2031fcf3ce44SJohn Forte ql_adm_prop_update_int(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2032fcf3ce44SJohn Forte {
2033fcf3ce44SJohn Forte 	char	*prop_name;
2034fcf3ce44SJohn Forte 	int	rval;
2035fcf3ce44SJohn Forte 
2036*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2037fcf3ce44SJohn Forte 
2038fcf3ce44SJohn Forte 	prop_name = kmem_zalloc(dop->length, KM_SLEEP);
2039fcf3ce44SJohn Forte 	if (prop_name == NULL) {
2040fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
2041fcf3ce44SJohn Forte 		return (ENOMEM);
2042fcf3ce44SJohn Forte 	}
2043fcf3ce44SJohn Forte 
2044fcf3ce44SJohn Forte 	if (ddi_copyin((void *)(uintptr_t)dop->buffer, prop_name, dop->length,
2045fcf3ce44SJohn Forte 	    mode) != 0) {
2046fcf3ce44SJohn Forte 		EL(ha, "failed, prop_name ddi_copyin\n");
2047fcf3ce44SJohn Forte 		kmem_free(prop_name, dop->length);
2048fcf3ce44SJohn Forte 		return (EFAULT);
2049fcf3ce44SJohn Forte 	}
2050fcf3ce44SJohn Forte 
2051fcf3ce44SJohn Forte 	/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
2052fcf3ce44SJohn Forte 	if ((rval = ddi_prop_update_int(DDI_DEV_T_NONE, ha->dip, prop_name,
2053fcf3ce44SJohn Forte 	    (int)dop->option)) != DDI_PROP_SUCCESS) {
2054fcf3ce44SJohn Forte 		EL(ha, "failed, prop_update=%xh\n", rval);
2055fcf3ce44SJohn Forte 		kmem_free(prop_name, dop->length);
2056fcf3ce44SJohn Forte 		return (EINVAL);
2057fcf3ce44SJohn Forte 	}
2058fcf3ce44SJohn Forte 
2059fcf3ce44SJohn Forte 	kmem_free(prop_name, dop->length);
2060fcf3ce44SJohn Forte 
2061*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2062fcf3ce44SJohn Forte 
2063fcf3ce44SJohn Forte 	return (0);
2064fcf3ce44SJohn Forte }
2065fcf3ce44SJohn Forte 
2066fcf3ce44SJohn Forte /*
2067fcf3ce44SJohn Forte  * ql_adm_fw_dump
2068fcf3ce44SJohn Forte  *	Performs qladm QL_FW_DUMP command
2069fcf3ce44SJohn Forte  *
2070fcf3ce44SJohn Forte  * Input:
2071fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2072fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2073fcf3ce44SJohn Forte  *	udop:	user space ql_adm_op_t structure pointer.
2074fcf3ce44SJohn Forte  *	mode:	flags.
2075fcf3ce44SJohn Forte  *
2076fcf3ce44SJohn Forte  * Returns:
2077fcf3ce44SJohn Forte  *
2078fcf3ce44SJohn Forte  * Context:
2079fcf3ce44SJohn Forte  *	Kernel context.
2080fcf3ce44SJohn Forte  */
2081fcf3ce44SJohn Forte static int
ql_adm_fw_dump(ql_adapter_state_t * ha,ql_adm_op_t * dop,void * udop,int mode)2082fcf3ce44SJohn Forte ql_adm_fw_dump(ql_adapter_state_t *ha, ql_adm_op_t *dop, void *udop, int mode)
2083fcf3ce44SJohn Forte {
2084fcf3ce44SJohn Forte 	caddr_t	dmp;
2085fcf3ce44SJohn Forte 
2086*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2087fcf3ce44SJohn Forte 
2088fcf3ce44SJohn Forte 	if (dop->length < ha->risc_dump_size) {
2089fcf3ce44SJohn Forte 		EL(ha, "failed, incorrect length=%xh, size=%xh\n",
2090fcf3ce44SJohn Forte 		    dop->length, ha->risc_dump_size);
2091fcf3ce44SJohn Forte 		return (EINVAL);
2092fcf3ce44SJohn Forte 	}
2093fcf3ce44SJohn Forte 
209416dd44c2SDaniel Beauregard 	if (ha->ql_dump_state & QL_DUMP_VALID) {
2095fcf3ce44SJohn Forte 		dmp = kmem_zalloc(ha->risc_dump_size, KM_SLEEP);
2096fcf3ce44SJohn Forte 		if (dmp == NULL) {
2097fcf3ce44SJohn Forte 			EL(ha, "failed, kmem_zalloc\n");
2098fcf3ce44SJohn Forte 			return (ENOMEM);
2099fcf3ce44SJohn Forte 		}
2100fcf3ce44SJohn Forte 
2101fcf3ce44SJohn Forte 		dop->length = (uint32_t)ql_ascii_fw_dump(ha, dmp);
2102fcf3ce44SJohn Forte 		if (ddi_copyout((void *)dmp, (void *)(uintptr_t)dop->buffer,
2103fcf3ce44SJohn Forte 		    dop->length, mode) != 0) {
2104fcf3ce44SJohn Forte 			EL(ha, "failed, ddi_copyout\n");
2105fcf3ce44SJohn Forte 			kmem_free(dmp, ha->risc_dump_size);
2106fcf3ce44SJohn Forte 			return (EFAULT);
2107fcf3ce44SJohn Forte 		}
2108fcf3ce44SJohn Forte 
2109fcf3ce44SJohn Forte 		kmem_free(dmp, ha->risc_dump_size);
211016dd44c2SDaniel Beauregard 		ha->ql_dump_state |= QL_DUMP_UPLOADED;
2111fcf3ce44SJohn Forte 
2112fcf3ce44SJohn Forte 	} else {
2113fcf3ce44SJohn Forte 		EL(ha, "failed, no dump file\n");
2114fcf3ce44SJohn Forte 		dop->length = 0;
2115fcf3ce44SJohn Forte 	}
2116fcf3ce44SJohn Forte 
2117fcf3ce44SJohn Forte 	if (ddi_copyout(dop, udop, sizeof (ql_adm_op_t), mode) != 0) {
2118fcf3ce44SJohn Forte 		EL(ha, "failed, driver_op_t ddi_copyout\n");
2119fcf3ce44SJohn Forte 		return (EFAULT);
2120fcf3ce44SJohn Forte 	}
2121fcf3ce44SJohn Forte 
2122*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2123fcf3ce44SJohn Forte 
2124fcf3ce44SJohn Forte 	return (0);
2125fcf3ce44SJohn Forte }
2126fcf3ce44SJohn Forte 
2127*4c3888b8SHans Rosenfeld /*
2128*4c3888b8SHans Rosenfeld  * ql_adm_fw_t_dump
2129*4c3888b8SHans Rosenfeld  *	Performs qladm QL_FW_DUMP_TRIGGER command
2130*4c3888b8SHans Rosenfeld  *
2131*4c3888b8SHans Rosenfeld  * Input:
2132*4c3888b8SHans Rosenfeld  *	ha:	adapter state pointer.
2133*4c3888b8SHans Rosenfeld  *
2134*4c3888b8SHans Rosenfeld  * Returns:
2135*4c3888b8SHans Rosenfeld  *
2136*4c3888b8SHans Rosenfeld  * Context:
2137*4c3888b8SHans Rosenfeld  *	Kernel context.
2138*4c3888b8SHans Rosenfeld  */
2139*4c3888b8SHans Rosenfeld static int
ql_adm_fw_t_dump(ql_adapter_state_t * ha)2140*4c3888b8SHans Rosenfeld ql_adm_fw_t_dump(ql_adapter_state_t *ha)
2141*4c3888b8SHans Rosenfeld {
2142*4c3888b8SHans Rosenfeld 	int	rval;
2143*4c3888b8SHans Rosenfeld 
2144*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2145*4c3888b8SHans Rosenfeld 
2146*4c3888b8SHans Rosenfeld 	if (ha->ql_dump_state & QL_DUMP_VALID) {
2147*4c3888b8SHans Rosenfeld 		EL(ha, "Already contains a dump file\n");
2148*4c3888b8SHans Rosenfeld 		return (EINVAL);
2149*4c3888b8SHans Rosenfeld 	}
2150*4c3888b8SHans Rosenfeld 	rval = ql_dump_firmware(ha);
2151*4c3888b8SHans Rosenfeld 
2152*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2153*4c3888b8SHans Rosenfeld 
2154*4c3888b8SHans Rosenfeld 	if (rval == QL_SUCCESS || rval == QL_DATA_EXISTS) {
2155*4c3888b8SHans Rosenfeld 		return (0);
2156*4c3888b8SHans Rosenfeld 	}
2157*4c3888b8SHans Rosenfeld 	return (EFAULT);
2158*4c3888b8SHans Rosenfeld }
2159*4c3888b8SHans Rosenfeld 
2160*4c3888b8SHans Rosenfeld /*
2161*4c3888b8SHans Rosenfeld  * ql_adm_beacon
2162*4c3888b8SHans Rosenfeld  *      Performs qladm QL_BEACON_ENABLE/DISABLE command
2163*4c3888b8SHans Rosenfeld  *
2164*4c3888b8SHans Rosenfeld  * Input:
2165*4c3888b8SHans Rosenfeld  *      ha:     adapter state pointer.
2166*4c3888b8SHans Rosenfeld  *	dop:	ql_adm_op_t structure pointer.
2167*4c3888b8SHans Rosenfeld  *
2168*4c3888b8SHans Rosenfeld  * Returns:
2169*4c3888b8SHans Rosenfeld  *
2170*4c3888b8SHans Rosenfeld  * Context:
2171*4c3888b8SHans Rosenfeld  *      Kernel context.
2172*4c3888b8SHans Rosenfeld  */
2173*4c3888b8SHans Rosenfeld static int
ql_adm_beacon(ql_adapter_state_t * ha,ql_adm_op_t * dop)2174*4c3888b8SHans Rosenfeld ql_adm_beacon(ql_adapter_state_t *ha, ql_adm_op_t *dop)
2175*4c3888b8SHans Rosenfeld {
2176*4c3888b8SHans Rosenfeld 	int		rval;
2177*4c3888b8SHans Rosenfeld 	ql_mbx_data_t	mr;
2178*4c3888b8SHans Rosenfeld 
2179*4c3888b8SHans Rosenfeld 	if (!CFG_IST(ha, CFG_CTRL_82XX)) {
2180*4c3888b8SHans Rosenfeld 		return (EIO);
2181*4c3888b8SHans Rosenfeld 	}
2182*4c3888b8SHans Rosenfeld 
2183*4c3888b8SHans Rosenfeld 	rval = ql_diag_beacon(ha, dop->cmd, &mr);
2184*4c3888b8SHans Rosenfeld 
2185*4c3888b8SHans Rosenfeld 	if (rval == QL_SUCCESS) {
2186*4c3888b8SHans Rosenfeld 		return (0);
2187*4c3888b8SHans Rosenfeld 	}
2188*4c3888b8SHans Rosenfeld 
2189*4c3888b8SHans Rosenfeld 	return (rval);
2190*4c3888b8SHans Rosenfeld }
2191*4c3888b8SHans Rosenfeld 
2192*4c3888b8SHans Rosenfeld 
2193fcf3ce44SJohn Forte /*
2194fcf3ce44SJohn Forte  * ql_adm_nvram_dump
2195fcf3ce44SJohn Forte  *	Performs qladm QL_NVRAM_DUMP command
2196fcf3ce44SJohn Forte  *
2197fcf3ce44SJohn Forte  * Input:
2198fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2199fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2200fcf3ce44SJohn Forte  *	mode:	flags.
2201fcf3ce44SJohn Forte  *
2202fcf3ce44SJohn Forte  * Returns:
2203fcf3ce44SJohn Forte  *
2204fcf3ce44SJohn Forte  * Context:
2205fcf3ce44SJohn Forte  *	Kernel context.
2206fcf3ce44SJohn Forte  */
2207fcf3ce44SJohn Forte static int
ql_adm_nvram_dump(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2208fcf3ce44SJohn Forte ql_adm_nvram_dump(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2209fcf3ce44SJohn Forte {
2210fcf3ce44SJohn Forte 	int		rval;
2211fcf3ce44SJohn Forte 
2212*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2213fcf3ce44SJohn Forte 
2214c1fad183SDaniel Beauregard 	if (dop->length < ha->nvram_cache->size) {
2215c1fad183SDaniel Beauregard 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
2216c1fad183SDaniel Beauregard 		    ha->nvram_cache->size);
2217fcf3ce44SJohn Forte 		return (EINVAL);
2218fcf3ce44SJohn Forte 	}
2219fcf3ce44SJohn Forte 
2220fcf3ce44SJohn Forte 	if ((rval = ql_nv_util_dump(ha, (void *)(uintptr_t)dop->buffer,
2221fcf3ce44SJohn Forte 	    mode)) != 0) {
2222fcf3ce44SJohn Forte 		EL(ha, "failed, ql_nv_util_dump\n");
2223fcf3ce44SJohn Forte 	} else {
2224fcf3ce44SJohn Forte 		/*EMPTY*/
2225*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "done\n");
2226fcf3ce44SJohn Forte 	}
2227fcf3ce44SJohn Forte 
2228fcf3ce44SJohn Forte 	return (rval);
2229fcf3ce44SJohn Forte }
2230fcf3ce44SJohn Forte 
2231fcf3ce44SJohn Forte /*
2232fcf3ce44SJohn Forte  * ql_adm_nvram_load
2233fcf3ce44SJohn Forte  *	Performs qladm QL_NVRAM_LOAD command
2234fcf3ce44SJohn Forte  *
2235fcf3ce44SJohn Forte  * Input:
2236fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2237fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2238fcf3ce44SJohn Forte  *	mode:	flags.
2239fcf3ce44SJohn Forte  *
2240fcf3ce44SJohn Forte  * Returns:
2241fcf3ce44SJohn Forte  *
2242fcf3ce44SJohn Forte  * Context:
2243fcf3ce44SJohn Forte  *	Kernel context.
2244fcf3ce44SJohn Forte  */
2245fcf3ce44SJohn Forte static int
ql_adm_nvram_load(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2246fcf3ce44SJohn Forte ql_adm_nvram_load(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2247fcf3ce44SJohn Forte {
2248fcf3ce44SJohn Forte 	int		rval;
2249fcf3ce44SJohn Forte 
2250*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2251fcf3ce44SJohn Forte 
2252c1fad183SDaniel Beauregard 	if (dop->length < ha->nvram_cache->size) {
2253c1fad183SDaniel Beauregard 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
2254c1fad183SDaniel Beauregard 		    ha->nvram_cache->size);
2255fcf3ce44SJohn Forte 		return (EINVAL);
2256fcf3ce44SJohn Forte 	}
2257fcf3ce44SJohn Forte 
2258fcf3ce44SJohn Forte 	if ((rval = ql_nv_util_load(ha, (void *)(uintptr_t)dop->buffer,
2259fcf3ce44SJohn Forte 	    mode)) != 0) {
2260fcf3ce44SJohn Forte 		EL(ha, "failed, ql_nv_util_dump\n");
2261fcf3ce44SJohn Forte 	} else {
2262fcf3ce44SJohn Forte 		/*EMPTY*/
2263*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "done\n");
2264fcf3ce44SJohn Forte 	}
2265fcf3ce44SJohn Forte 
2266fcf3ce44SJohn Forte 	return (rval);
2267fcf3ce44SJohn Forte }
2268fcf3ce44SJohn Forte 
2269fcf3ce44SJohn Forte /*
2270fcf3ce44SJohn Forte  * ql_adm_flash_load
2271fcf3ce44SJohn Forte  *	Performs qladm QL_FLASH_LOAD command
2272fcf3ce44SJohn Forte  *
2273fcf3ce44SJohn Forte  * Input:
2274fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2275fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2276fcf3ce44SJohn Forte  *	mode:	flags.
2277fcf3ce44SJohn Forte  *
2278fcf3ce44SJohn Forte  * Returns:
2279fcf3ce44SJohn Forte  *
2280fcf3ce44SJohn Forte  * Context:
2281fcf3ce44SJohn Forte  *	Kernel context.
2282fcf3ce44SJohn Forte  */
2283fcf3ce44SJohn Forte static int
ql_adm_flash_load(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2284fcf3ce44SJohn Forte ql_adm_flash_load(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2285fcf3ce44SJohn Forte {
2286fcf3ce44SJohn Forte 	uint8_t	*dp;
2287fcf3ce44SJohn Forte 	int	rval;
2288fcf3ce44SJohn Forte 
2289*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2290fcf3ce44SJohn Forte 
2291fcf3ce44SJohn Forte 	if ((dp = kmem_zalloc(dop->length, KM_SLEEP)) == NULL) {
2292fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
2293fcf3ce44SJohn Forte 		return (ENOMEM);
2294fcf3ce44SJohn Forte 	}
2295fcf3ce44SJohn Forte 
2296fcf3ce44SJohn Forte 	if (ddi_copyin((void *)(uintptr_t)dop->buffer, dp, dop->length,
2297fcf3ce44SJohn Forte 	    mode) != 0) {
2298fcf3ce44SJohn Forte 		EL(ha, "ddi_copyin failed\n");
2299fcf3ce44SJohn Forte 		kmem_free(dp, dop->length);
2300fcf3ce44SJohn Forte 		return (EFAULT);
2301fcf3ce44SJohn Forte 	}
2302fcf3ce44SJohn Forte 
2303fcf3ce44SJohn Forte 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
2304fcf3ce44SJohn Forte 		EL(ha, "ql_stall_driver failed\n");
2305fcf3ce44SJohn Forte 		kmem_free(dp, dop->length);
2306fcf3ce44SJohn Forte 		return (EBUSY);
2307fcf3ce44SJohn Forte 	}
2308fcf3ce44SJohn Forte 
2309*4c3888b8SHans Rosenfeld 	rval = (CFG_IST(ha, CFG_ISP_FW_TYPE_2) ?
2310fcf3ce44SJohn Forte 	    ql_24xx_load_flash(ha, dp, dop->length, dop->option) :
2311fcf3ce44SJohn Forte 	    ql_load_flash(ha, dp, dop->length));
2312fcf3ce44SJohn Forte 
2313fcf3ce44SJohn Forte 	ql_restart_driver(ha);
2314fcf3ce44SJohn Forte 
2315fcf3ce44SJohn Forte 	kmem_free(dp, dop->length);
2316fcf3ce44SJohn Forte 
2317fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
2318fcf3ce44SJohn Forte 		EL(ha, "failed\n");
2319fcf3ce44SJohn Forte 		return (EIO);
2320fcf3ce44SJohn Forte 	}
2321fcf3ce44SJohn Forte 
2322*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2323fcf3ce44SJohn Forte 
2324fcf3ce44SJohn Forte 	return (0);
2325fcf3ce44SJohn Forte }
2326fcf3ce44SJohn Forte 
2327fcf3ce44SJohn Forte /*
2328fcf3ce44SJohn Forte  * ql_adm_vpd_dump
2329fcf3ce44SJohn Forte  *	Performs qladm QL_VPD_DUMP command
2330fcf3ce44SJohn Forte  *
2331fcf3ce44SJohn Forte  * Input:
2332fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2333fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2334fcf3ce44SJohn Forte  *	mode:	flags.
2335fcf3ce44SJohn Forte  *
2336fcf3ce44SJohn Forte  * Returns:
2337fcf3ce44SJohn Forte  *
2338fcf3ce44SJohn Forte  * Context:
2339fcf3ce44SJohn Forte  *	Kernel context.
2340fcf3ce44SJohn Forte  */
2341fcf3ce44SJohn Forte static int
ql_adm_vpd_dump(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2342fcf3ce44SJohn Forte ql_adm_vpd_dump(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2343fcf3ce44SJohn Forte {
2344fcf3ce44SJohn Forte 	int		rval;
2345fcf3ce44SJohn Forte 
2346*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2347fcf3ce44SJohn Forte 
2348*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
2349fcf3ce44SJohn Forte 		EL(ha, "hba does not support VPD\n");
2350fcf3ce44SJohn Forte 		return (EINVAL);
2351fcf3ce44SJohn Forte 	}
2352fcf3ce44SJohn Forte 
2353fcf3ce44SJohn Forte 	if (dop->length < QL_24XX_VPD_SIZE) {
2354fcf3ce44SJohn Forte 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
2355fcf3ce44SJohn Forte 		    QL_24XX_VPD_SIZE);
2356fcf3ce44SJohn Forte 		return (EINVAL);
2357fcf3ce44SJohn Forte 	}
2358fcf3ce44SJohn Forte 
235916dd44c2SDaniel Beauregard 	if ((rval = ql_vpd_dump(ha, (void *)(uintptr_t)dop->buffer, mode))
236016dd44c2SDaniel Beauregard 	    != 0) {
2361fcf3ce44SJohn Forte 		EL(ha, "failed, ql_vpd_dump\n");
2362fcf3ce44SJohn Forte 	} else {
2363fcf3ce44SJohn Forte 		/*EMPTY*/
2364*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "done\n");
2365fcf3ce44SJohn Forte 	}
2366fcf3ce44SJohn Forte 
2367fcf3ce44SJohn Forte 	return (rval);
2368fcf3ce44SJohn Forte }
2369fcf3ce44SJohn Forte 
2370fcf3ce44SJohn Forte /*
2371fcf3ce44SJohn Forte  * ql_adm_vpd_load
2372fcf3ce44SJohn Forte  *	Performs qladm QL_VPD_LOAD command
2373fcf3ce44SJohn Forte  *
2374fcf3ce44SJohn Forte  * Input:
2375fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2376fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2377fcf3ce44SJohn Forte  *	mode:	flags.
2378fcf3ce44SJohn Forte  *
2379fcf3ce44SJohn Forte  * Returns:
2380fcf3ce44SJohn Forte  *
2381fcf3ce44SJohn Forte  * Context:
2382fcf3ce44SJohn Forte  *	Kernel context.
2383fcf3ce44SJohn Forte  */
2384fcf3ce44SJohn Forte static int
ql_adm_vpd_load(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2385fcf3ce44SJohn Forte ql_adm_vpd_load(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2386fcf3ce44SJohn Forte {
2387fcf3ce44SJohn Forte 	int		rval;
2388fcf3ce44SJohn Forte 
2389*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2390fcf3ce44SJohn Forte 
2391*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
2392fcf3ce44SJohn Forte 		EL(ha, "hba does not support VPD\n");
2393fcf3ce44SJohn Forte 		return (EINVAL);
2394fcf3ce44SJohn Forte 	}
2395fcf3ce44SJohn Forte 
2396fcf3ce44SJohn Forte 	if (dop->length < QL_24XX_VPD_SIZE) {
2397fcf3ce44SJohn Forte 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
2398fcf3ce44SJohn Forte 		    QL_24XX_VPD_SIZE);
2399fcf3ce44SJohn Forte 		return (EINVAL);
2400fcf3ce44SJohn Forte 	}
2401fcf3ce44SJohn Forte 
240216dd44c2SDaniel Beauregard 	if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)dop->buffer, mode))
240316dd44c2SDaniel Beauregard 	    != 0) {
2404fcf3ce44SJohn Forte 		EL(ha, "failed, ql_vpd_dump\n");
2405fcf3ce44SJohn Forte 	} else {
2406fcf3ce44SJohn Forte 		/*EMPTY*/
2407*4c3888b8SHans Rosenfeld 		QL_PRINT_9(ha, "done\n");
2408fcf3ce44SJohn Forte 	}
2409fcf3ce44SJohn Forte 
2410fcf3ce44SJohn Forte 	return (rval);
2411fcf3ce44SJohn Forte }
2412fcf3ce44SJohn Forte 
2413fcf3ce44SJohn Forte /*
2414fcf3ce44SJohn Forte  * ql_adm_vpd_gettag
2415fcf3ce44SJohn Forte  *	Performs qladm QL_VPD_GETTAG command
2416fcf3ce44SJohn Forte  *
2417fcf3ce44SJohn Forte  * Input:
2418fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2419fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2420fcf3ce44SJohn Forte  *	mode:	flags.
2421fcf3ce44SJohn Forte  *
2422fcf3ce44SJohn Forte  * Returns:
2423fcf3ce44SJohn Forte  *
2424fcf3ce44SJohn Forte  * Context:
2425fcf3ce44SJohn Forte  *	Kernel context.
2426fcf3ce44SJohn Forte  */
2427fcf3ce44SJohn Forte static int
ql_adm_vpd_gettag(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2428fcf3ce44SJohn Forte ql_adm_vpd_gettag(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2429fcf3ce44SJohn Forte {
2430fcf3ce44SJohn Forte 	int		rval = 0;
2431fcf3ce44SJohn Forte 	uint8_t		*lbuf;
2432fcf3ce44SJohn Forte 
2433*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2434fcf3ce44SJohn Forte 
2435*4c3888b8SHans Rosenfeld 	if (CFG_IST(ha, CFG_ISP_FW_TYPE_1)) {
2436fcf3ce44SJohn Forte 		EL(ha, "hba does not support VPD\n");
2437fcf3ce44SJohn Forte 		return (EINVAL);
2438fcf3ce44SJohn Forte 	}
2439fcf3ce44SJohn Forte 
2440fcf3ce44SJohn Forte 	if ((lbuf = (uint8_t *)kmem_zalloc(dop->length, KM_SLEEP)) == NULL) {
2441fcf3ce44SJohn Forte 		EL(ha, "mem alloc failure of %xh bytes\n", dop->length);
2442fcf3ce44SJohn Forte 		rval = EFAULT;
2443fcf3ce44SJohn Forte 	} else {
2444fcf3ce44SJohn Forte 		if (ddi_copyin((void *)(uintptr_t)dop->buffer, lbuf,
2445fcf3ce44SJohn Forte 		    dop->length, mode) != 0) {
2446fcf3ce44SJohn Forte 			EL(ha, "ddi_copyin failed\n");
2447fcf3ce44SJohn Forte 			kmem_free(lbuf, dop->length);
2448fcf3ce44SJohn Forte 			return (EFAULT);
2449fcf3ce44SJohn Forte 		}
2450fcf3ce44SJohn Forte 
2451fcf3ce44SJohn Forte 		if ((rval = ql_vpd_lookup(ha, lbuf, lbuf, (int32_t)
2452fcf3ce44SJohn Forte 		    dop->length)) < 0) {
2453fcf3ce44SJohn Forte 			EL(ha, "failed vpd_lookup\n");
2454fcf3ce44SJohn Forte 		} else {
2455fcf3ce44SJohn Forte 			if (ddi_copyout(lbuf, (void *)(uintptr_t)dop->buffer,
2456*4c3888b8SHans Rosenfeld 			    strlen((int8_t *)lbuf) + 1, mode) != 0) {
2457fcf3ce44SJohn Forte 				EL(ha, "failed, ddi_copyout\n");
2458fcf3ce44SJohn Forte 				rval = EFAULT;
2459fcf3ce44SJohn Forte 			} else {
2460fcf3ce44SJohn Forte 				rval = 0;
2461fcf3ce44SJohn Forte 			}
2462fcf3ce44SJohn Forte 		}
2463fcf3ce44SJohn Forte 		kmem_free(lbuf, dop->length);
2464fcf3ce44SJohn Forte 	}
2465fcf3ce44SJohn Forte 
2466*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2467fcf3ce44SJohn Forte 
2468fcf3ce44SJohn Forte 	return (rval);
2469fcf3ce44SJohn Forte }
2470fcf3ce44SJohn Forte 
2471fcf3ce44SJohn Forte /*
2472fcf3ce44SJohn Forte  * ql_adm_updfwmodule
2473fcf3ce44SJohn Forte  *	Performs qladm QL_UPD_FWMODULE command
2474fcf3ce44SJohn Forte  *
2475fcf3ce44SJohn Forte  * Input:
2476fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
2477fcf3ce44SJohn Forte  *	dop:	ql_adm_op_t structure pointer.
2478fcf3ce44SJohn Forte  *	mode:	flags.
2479fcf3ce44SJohn Forte  *
2480fcf3ce44SJohn Forte  * Returns:
2481fcf3ce44SJohn Forte  *
2482fcf3ce44SJohn Forte  * Context:
2483fcf3ce44SJohn Forte  *	Kernel context.
2484fcf3ce44SJohn Forte  */
2485fcf3ce44SJohn Forte /* ARGSUSED */
2486fcf3ce44SJohn Forte static int
ql_adm_updfwmodule(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)2487fcf3ce44SJohn Forte ql_adm_updfwmodule(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
2488fcf3ce44SJohn Forte {
2489fcf3ce44SJohn Forte 	int			rval = DDI_SUCCESS;
2490fcf3ce44SJohn Forte 	ql_link_t		*link;
2491fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha2 = NULL;
2492fcf3ce44SJohn Forte 	uint16_t		fw_class = (uint16_t)dop->option;
2493fcf3ce44SJohn Forte 
2494*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "started\n");
2495fcf3ce44SJohn Forte 
2496fcf3ce44SJohn Forte 	/* zero the firmware module reference count */
2497fcf3ce44SJohn Forte 	for (link = ql_hba.first; link != NULL; link = link->next) {
2498fcf3ce44SJohn Forte 		ha2 = link->base_address;
2499fcf3ce44SJohn Forte 		if (fw_class == ha2->fw_class) {
2500fcf3ce44SJohn Forte 			if ((rval = ddi_modclose(ha2->fw_module)) !=
2501fcf3ce44SJohn Forte 			    DDI_SUCCESS) {
2502fcf3ce44SJohn Forte 				EL(ha2, "modclose rval=%xh\n", rval);
2503fcf3ce44SJohn Forte 				break;
2504fcf3ce44SJohn Forte 			}
2505fcf3ce44SJohn Forte 			ha2->fw_module = NULL;
2506fcf3ce44SJohn Forte 		}
2507fcf3ce44SJohn Forte 	}
2508fcf3ce44SJohn Forte 
2509fcf3ce44SJohn Forte 	/* reload the f/w modules */
2510fcf3ce44SJohn Forte 	for (link = ql_hba.first; link != NULL; link = link->next) {
2511fcf3ce44SJohn Forte 		ha2 = link->base_address;
2512fcf3ce44SJohn Forte 
2513c92b35bbSToomas Soome 		if ((fw_class == ha2->fw_class) && (ha2->fw_class == 0)) {
2514fcf3ce44SJohn Forte 			if ((rval = (int32_t)ql_fwmodule_resolve(ha2)) !=
2515fcf3ce44SJohn Forte 			    QL_SUCCESS) {
2516fcf3ce44SJohn Forte 				EL(ha2, "unable to load f/w module: '%x' "
2517fcf3ce44SJohn Forte 				    "(rval=%xh)\n", ha2->fw_class, rval);
2518fcf3ce44SJohn Forte 				rval = EFAULT;
2519fcf3ce44SJohn Forte 			} else {
2520fcf3ce44SJohn Forte 				EL(ha2, "f/w module updated: '%x'\n",
2521fcf3ce44SJohn Forte 				    ha2->fw_class);
2522fcf3ce44SJohn Forte 			}
2523fcf3ce44SJohn Forte 
2524fcf3ce44SJohn Forte 			EL(ha2, "isp abort needed (%d)\n", ha->instance);
2525fcf3ce44SJohn Forte 
2526fcf3ce44SJohn Forte 			ql_awaken_task_daemon(ha2, NULL, ISP_ABORT_NEEDED, 0);
2527fcf3ce44SJohn Forte 
2528fcf3ce44SJohn Forte 			rval = 0;
2529fcf3ce44SJohn Forte 		}
2530fcf3ce44SJohn Forte 	}
2531fcf3ce44SJohn Forte 
2532*4c3888b8SHans Rosenfeld 	QL_PRINT_9(ha, "done\n");
2533fcf3ce44SJohn Forte 
2534fcf3ce44SJohn Forte 	return (rval);
2535fcf3ce44SJohn Forte }
2536