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 
22c1fad183SDaniel Beauregard /* Copyright 2010 QLogic Corporation */
23fcf3ce44SJohn Forte 
24fcf3ce44SJohn Forte /*
25f885d00fSDaniel Beauregard  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
26fcf3ce44SJohn Forte  */
27fcf3ce44SJohn Forte 
28c1fad183SDaniel Beauregard #pragma ident	"Copyright 2010 QLogic Corporation; ql_ioctl.c"
29fcf3ce44SJohn Forte 
30fcf3ce44SJohn Forte /*
31fcf3ce44SJohn Forte  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
32fcf3ce44SJohn Forte  * Fibre Channel Adapter (FCA) driver IOCTL source file.
33fcf3ce44SJohn Forte  *
34fcf3ce44SJohn Forte  * ***********************************************************************
35fcf3ce44SJohn Forte  * *									**
36fcf3ce44SJohn Forte  * *				NOTICE					**
37c1fad183SDaniel Beauregard  * *		COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION		**
38fcf3ce44SJohn Forte  * *			ALL RIGHTS RESERVED				**
39fcf3ce44SJohn Forte  * *									**
40fcf3ce44SJohn Forte  * ***********************************************************************
41fcf3ce44SJohn Forte  *
42fcf3ce44SJohn Forte  */
43fcf3ce44SJohn Forte 
44fcf3ce44SJohn Forte #include <ql_apps.h>
45fcf3ce44SJohn Forte #include <ql_api.h>
46fcf3ce44SJohn Forte #include <ql_debug.h>
47fcf3ce44SJohn Forte #include <ql_init.h>
48fcf3ce44SJohn Forte #include <ql_ioctl.h>
49fcf3ce44SJohn Forte #include <ql_mbx.h>
50fcf3ce44SJohn Forte #include <ql_xioctl.h>
51fcf3ce44SJohn Forte 
52fcf3ce44SJohn Forte /*
53fcf3ce44SJohn Forte  * Local Function Prototypes.
54fcf3ce44SJohn Forte  */
55fcf3ce44SJohn Forte static int ql_busy_notification(ql_adapter_state_t *);
56fcf3ce44SJohn Forte static int ql_idle_notification(ql_adapter_state_t *);
57fcf3ce44SJohn Forte static int ql_get_feature_bits(ql_adapter_state_t *ha, uint16_t *features);
58fcf3ce44SJohn Forte static int ql_set_feature_bits(ql_adapter_state_t *ha, uint16_t features);
59fcf3ce44SJohn Forte static int ql_set_nvram_adapter_defaults(ql_adapter_state_t *ha);
60fcf3ce44SJohn Forte static void ql_load_nvram(ql_adapter_state_t *ha, uint8_t addr,
61fcf3ce44SJohn Forte     uint16_t value);
62fcf3ce44SJohn Forte static int ql_24xx_load_nvram(ql_adapter_state_t *, uint32_t, uint32_t);
63fcf3ce44SJohn Forte static int ql_adm_op(ql_adapter_state_t *, void *, int);
64fcf3ce44SJohn Forte static int ql_adm_adapter_info(ql_adapter_state_t *, ql_adm_op_t *, int);
65fcf3ce44SJohn Forte static int ql_adm_extended_logging(ql_adapter_state_t *, ql_adm_op_t *);
66fcf3ce44SJohn Forte static int ql_adm_device_list(ql_adapter_state_t *, ql_adm_op_t *, int);
67fcf3ce44SJohn Forte static int ql_adm_update_properties(ql_adapter_state_t *);
68fcf3ce44SJohn Forte static int ql_adm_prop_update_int(ql_adapter_state_t *, ql_adm_op_t *, int);
69fcf3ce44SJohn Forte static int ql_adm_loop_reset(ql_adapter_state_t *);
70fcf3ce44SJohn Forte static int ql_adm_fw_dump(ql_adapter_state_t *, ql_adm_op_t *, void *, int);
71fcf3ce44SJohn Forte static int ql_adm_nvram_dump(ql_adapter_state_t *, ql_adm_op_t *, int);
72fcf3ce44SJohn Forte static int ql_adm_nvram_load(ql_adapter_state_t *, ql_adm_op_t *, int);
73fcf3ce44SJohn Forte static int ql_adm_flash_load(ql_adapter_state_t *, ql_adm_op_t *, int);
74fcf3ce44SJohn Forte static int ql_adm_vpd_dump(ql_adapter_state_t *, ql_adm_op_t *, int);
75fcf3ce44SJohn Forte static int ql_adm_vpd_load(ql_adapter_state_t *, ql_adm_op_t *, int);
76fcf3ce44SJohn Forte static int ql_adm_vpd_gettag(ql_adapter_state_t *, ql_adm_op_t *, int);
77fcf3ce44SJohn Forte static int ql_adm_updfwmodule(ql_adapter_state_t *, ql_adm_op_t *, int);
78fcf3ce44SJohn Forte static uint8_t *ql_vpd_findtag(ql_adapter_state_t *, uint8_t *, int8_t *);
79fcf3ce44SJohn Forte 
80fcf3ce44SJohn Forte /* ************************************************************************ */
81fcf3ce44SJohn Forte /*				cb_ops functions			    */
82fcf3ce44SJohn Forte /* ************************************************************************ */
83fcf3ce44SJohn Forte 
84fcf3ce44SJohn Forte /*
85fcf3ce44SJohn Forte  * ql_open
86fcf3ce44SJohn Forte  *	opens device
87fcf3ce44SJohn Forte  *
88fcf3ce44SJohn Forte  * Input:
89fcf3ce44SJohn Forte  *	dev_p = device pointer
90fcf3ce44SJohn Forte  *	flags = open flags
91fcf3ce44SJohn Forte  *	otype = open type
92fcf3ce44SJohn Forte  *	cred_p = credentials pointer
93fcf3ce44SJohn Forte  *
94fcf3ce44SJohn Forte  * Returns:
95fcf3ce44SJohn Forte  *	0 = success
96fcf3ce44SJohn Forte  *
97fcf3ce44SJohn Forte  * Context:
98fcf3ce44SJohn Forte  *	Kernel context.
99fcf3ce44SJohn Forte  */
100fcf3ce44SJohn Forte /* ARGSUSED */
101fcf3ce44SJohn Forte int
ql_open(dev_t * dev_p,int flags,int otyp,cred_t * cred_p)102fcf3ce44SJohn Forte ql_open(dev_t *dev_p, int flags, int otyp, cred_t *cred_p)
103fcf3ce44SJohn Forte {
104fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha;
105fcf3ce44SJohn Forte 	int			rval = 0;
106fcf3ce44SJohn Forte 
107fcf3ce44SJohn Forte 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(*dev_p));
108fcf3ce44SJohn Forte 	if (ha == NULL) {
109fcf3ce44SJohn Forte 		QL_PRINT_2(CE_CONT, "failed, no adapter\n");
110fcf3ce44SJohn Forte 		return (ENXIO);
111fcf3ce44SJohn Forte 	}
112fcf3ce44SJohn Forte 
113fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
114fcf3ce44SJohn Forte 
115fcf3ce44SJohn Forte 	/* Allow only character opens */
116fcf3ce44SJohn Forte 	if (otyp != OTYP_CHR) {
117fcf3ce44SJohn Forte 		QL_PRINT_2(CE_CONT, "(%d): failed, open type\n",
118fcf3ce44SJohn Forte 		    ha->instance);
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*/
135fcf3ce44SJohn Forte 		QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
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) {
165fcf3ce44SJohn Forte 		QL_PRINT_2(CE_CONT, "failed, no adapter\n");
166fcf3ce44SJohn Forte 		return (ENXIO);
167fcf3ce44SJohn Forte 	}
168fcf3ce44SJohn Forte 
169fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
170fcf3ce44SJohn Forte 
171fcf3ce44SJohn Forte 	if (otyp != OTYP_CHR) {
172fcf3ce44SJohn Forte 		QL_PRINT_2(CE_CONT, "(%d): failed, open type\n",
173fcf3ce44SJohn Forte 		    ha->instance);
174fcf3ce44SJohn Forte 		return (EINVAL);
175fcf3ce44SJohn Forte 	}
176fcf3ce44SJohn Forte 
177fcf3ce44SJohn Forte 	ADAPTER_STATE_LOCK(ha);
178fcf3ce44SJohn Forte 	ha->flags &= ~QL_OPENED;
179fcf3ce44SJohn Forte 	ADAPTER_STATE_UNLOCK(ha);
180fcf3ce44SJohn Forte 
181fcf3ce44SJohn Forte 	if (rval != 0) {
182fcf3ce44SJohn Forte 		EL(ha, "failed, rval = %xh\n", rval);
183fcf3ce44SJohn Forte 	} else {
184fcf3ce44SJohn Forte 		/*EMPTY*/
185fcf3ce44SJohn Forte 		QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
186fcf3ce44SJohn Forte 	}
187fcf3ce44SJohn Forte 	return (rval);
188fcf3ce44SJohn Forte }
189fcf3ce44SJohn Forte 
190fcf3ce44SJohn Forte /*
191fcf3ce44SJohn Forte  * ql_ioctl
192fcf3ce44SJohn Forte  *	control a character device
193fcf3ce44SJohn Forte  *
194fcf3ce44SJohn Forte  * Input:
195fcf3ce44SJohn Forte  *	dev = device number
196fcf3ce44SJohn Forte  *	cmd = function to perform
197fcf3ce44SJohn Forte  *	arg = data type varies with request
198fcf3ce44SJohn Forte  *	mode = flags
199fcf3ce44SJohn Forte  *	cred_p = credentials pointer
200fcf3ce44SJohn Forte  *	rval_p = pointer to result value
201fcf3ce44SJohn Forte  *
202fcf3ce44SJohn Forte  * Returns:
203fcf3ce44SJohn Forte  *	0 = success
204fcf3ce44SJohn Forte  *
205fcf3ce44SJohn Forte  * Context:
206fcf3ce44SJohn Forte  *	Kernel context.
207fcf3ce44SJohn Forte  */
208fcf3ce44SJohn Forte /* ARGSUSED */
209fcf3ce44SJohn Forte int
ql_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)210fcf3ce44SJohn Forte ql_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
211fcf3ce44SJohn Forte     int *rval_p)
212fcf3ce44SJohn Forte {
213fcf3ce44SJohn Forte 	ql_adapter_state_t	*ha;
214fcf3ce44SJohn Forte 	int			rval = 0;
215fcf3ce44SJohn Forte 
216fcf3ce44SJohn Forte 	if (ddi_in_panic()) {
2175dfd244aSDaniel Beauregard 		QL_PRINT_2(CE_CONT, "ql_ioctl: ddi_in_panic exit\n");
218fcf3ce44SJohn Forte 		return (ENOPROTOOPT);
219fcf3ce44SJohn Forte 	}
220fcf3ce44SJohn Forte 
221fcf3ce44SJohn Forte 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(dev));
222fcf3ce44SJohn Forte 	if (ha == NULL)	{
223fcf3ce44SJohn Forte 		QL_PRINT_2(CE_CONT, "failed, no adapter\n");
224fcf3ce44SJohn Forte 		return (ENXIO);
225fcf3ce44SJohn Forte 	}
226fcf3ce44SJohn Forte 
227fcf3ce44SJohn Forte 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
228fcf3ce44SJohn Forte 
229fcf3ce44SJohn Forte 	/*
230fcf3ce44SJohn Forte 	 * Quick clean exit for qla2x00 foapi calls which are
231fcf3ce44SJohn Forte 	 * not supported in qlc.
232fcf3ce44SJohn Forte 	 */
233fcf3ce44SJohn Forte 	if (cmd >= QL_FOAPI_START && cmd <= QL_FOAPI_END) {
234fcf3ce44SJohn Forte 		QL_PRINT_9(CE_CONT, "failed, fo api not supported\n");
235fcf3ce44SJohn Forte 		return (ENOTTY);
236fcf3ce44SJohn Forte 	}
237fcf3ce44SJohn Forte 
238fcf3ce44SJohn Forte 	/* PWR management busy. */
239fcf3ce44SJohn Forte 	rval = ql_busy_notification(ha);
240fcf3ce44SJohn Forte 	if (rval != FC_SUCCESS)	 {
241fcf3ce44SJohn Forte 		EL(ha, "failed, ql_busy_notification\n");
242fcf3ce44SJohn Forte 		return (ENXIO);
243fcf3ce44SJohn Forte 	}
244fcf3ce44SJohn Forte 
245fcf3ce44SJohn Forte 	rval = ql_xioctl(ha, cmd, arg, mode, cred_p, rval_p);
246fcf3ce44SJohn Forte 	if (rval == ENOPROTOOPT || rval == EINVAL) {
247fcf3ce44SJohn Forte 		switch (cmd) {
24816dd44c2SDaniel Beauregard 		case QL_GET_ADAPTER_FEATURE_BITS: {
249fcf3ce44SJohn Forte 			uint16_t bits;
250fcf3ce44SJohn Forte 
251fcf3ce44SJohn Forte 			rval = ql_get_feature_bits(ha, &bits);
252fcf3ce44SJohn Forte 
253fcf3ce44SJohn Forte 			if (!rval && ddi_copyout((void *)&bits, (void *)arg,
254fcf3ce44SJohn Forte 			    sizeof (bits), mode)) {
255fcf3ce44SJohn Forte 				rval = EFAULT;
256fcf3ce44SJohn Forte 			}
257fcf3ce44SJohn Forte 			break;
258fcf3ce44SJohn Forte 		}
259fcf3ce44SJohn Forte 
26016dd44c2SDaniel Beauregard 		case QL_SET_ADAPTER_FEATURE_BITS: {
261fcf3ce44SJohn Forte 			uint16_t bits;
262fcf3ce44SJohn Forte 
263fcf3ce44SJohn Forte 			if (ddi_copyin((void *)arg, (void *)&bits,
264fcf3ce44SJohn Forte 			    sizeof (bits), mode)) {
265fcf3ce44SJohn Forte 				rval = EFAULT;
266fcf3ce44SJohn Forte 				break;
267fcf3ce44SJohn Forte 			}
268fcf3ce44SJohn Forte 
269fcf3ce44SJohn Forte 			rval = ql_set_feature_bits(ha, bits);
270fcf3ce44SJohn Forte 			break;
271fcf3ce44SJohn Forte 		}
272fcf3ce44SJohn Forte 
273fcf3ce44SJohn Forte 		case QL_SET_ADAPTER_NVRAM_DEFAULTS:
274fcf3ce44SJohn Forte 			rval = ql_set_nvram_adapter_defaults(ha);
275fcf3ce44SJohn Forte 			break;
276fcf3ce44SJohn Forte 
277fcf3ce44SJohn Forte 		case QL_UTIL_LOAD:
278fcf3ce44SJohn Forte 			rval = ql_nv_util_load(ha, (void *)arg, mode);
279fcf3ce44SJohn Forte 			break;
280fcf3ce44SJohn Forte 
281fcf3ce44SJohn Forte 		case QL_UTIL_DUMP:
282fcf3ce44SJohn Forte 			rval = ql_nv_util_dump(ha, (void *)arg, mode);
283fcf3ce44SJohn Forte 			break;
284fcf3ce44SJohn Forte 
285fcf3ce44SJohn Forte 		case QL_ADM_OP:
286fcf3ce44SJohn Forte 			rval = ql_adm_op(ha, (void *)arg, mode);
287fcf3ce44SJohn Forte 			break;
288fcf3ce44SJohn Forte 
289fcf3ce44SJohn Forte 		default:
290fcf3ce44SJohn Forte 			EL(ha, "unknown command = %d\n", cmd);
291fcf3ce44SJohn Forte 			rval = ENOTTY;
292fcf3ce44SJohn Forte 			break;
293fcf3ce44SJohn Forte 		}
294fcf3ce44SJohn Forte 	}
295fcf3ce44SJohn Forte 
296fcf3ce44SJohn Forte 	/* PWR management idle. */
297fcf3ce44SJohn Forte 	(void) ql_idle_notification(ha);
298fcf3ce44SJohn Forte 
299fcf3ce44SJohn Forte 	if (rval != 0) {
300f885d00fSDaniel Beauregard 		/*
301f885d00fSDaniel Beauregard 		 * Don't show failures caused by pps polling for
302f885d00fSDaniel Beauregard 		 * non-existant virtual ports.
303f885d00fSDaniel Beauregard 		 */
304f885d00fSDaniel Beauregard 		if (cmd != EXT_CC_VPORT_CMD) {
305f885d00fSDaniel Beauregard 			EL(ha, "failed, cmd=%d rval=%d\n", cmd, rval);
306f885d00fSDaniel Beauregard 		}
307fcf3ce44SJohn Forte 	} else {
308fcf3ce44SJohn Forte 		/*EMPTY*/
309fcf3ce44SJohn Forte 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
310fcf3ce44SJohn Forte 	}
311fcf3ce44SJohn Forte 	return (rval);
312fcf3ce44SJohn Forte }
313fcf3ce44SJohn Forte 
314fcf3ce44SJohn Forte /*
315fcf3ce44SJohn Forte  * ql_busy_notification
316fcf3ce44SJohn Forte  *	Adapter busy notification.
317fcf3ce44SJohn Forte  *
318fcf3ce44SJohn Forte  * Input:
319fcf3ce44SJohn Forte  *	ha = adapter state pointer.
320fcf3ce44SJohn Forte  *
321fcf3ce44SJohn Forte  * Returns:
322fcf3ce44SJohn Forte  *	FC_SUCCESS
323fcf3ce44SJohn Forte  *	FC_FAILURE
324fcf3ce44SJohn Forte  *
325fcf3ce44SJohn Forte  * Context:
326fcf3ce44SJohn Forte  *	Kernel context.
327fcf3ce44SJohn Forte  */
328fcf3ce44SJohn Forte static int
ql_busy_notification(ql_adapter_state_t * ha)329fcf3ce44SJohn Forte ql_busy_notification(ql_adapter_state_t *ha)
330fcf3ce44SJohn Forte {
331fcf3ce44SJohn Forte 	if (!ha->pm_capable) {
332fcf3ce44SJohn Forte 		return (FC_SUCCESS);
333fcf3ce44SJohn Forte 	}
334fcf3ce44SJohn Forte 
335fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
336fcf3ce44SJohn Forte 
337fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
338fcf3ce44SJohn Forte 	ha->busy++;
339fcf3ce44SJohn Forte 	QL_PM_UNLOCK(ha);
340fcf3ce44SJohn Forte 
341fcf3ce44SJohn Forte 	if (pm_busy_component(ha->dip, 0) != DDI_SUCCESS) {
342fcf3ce44SJohn Forte 		QL_PM_LOCK(ha);
343fcf3ce44SJohn Forte 		ha->busy--;
344fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
345fcf3ce44SJohn Forte 
346fcf3ce44SJohn Forte 		EL(ha, "pm_busy_component failed = %xh\n", FC_FAILURE);
347fcf3ce44SJohn Forte 		return (FC_FAILURE);
348fcf3ce44SJohn Forte 	}
349fcf3ce44SJohn Forte 
350fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
351fcf3ce44SJohn Forte 	if (ha->power_level != PM_LEVEL_D0) {
352fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
353fcf3ce44SJohn Forte 		if (pm_raise_power(ha->dip, 0, 1) != DDI_SUCCESS) {
354fcf3ce44SJohn Forte 			QL_PM_LOCK(ha);
355fcf3ce44SJohn Forte 			ha->busy--;
356fcf3ce44SJohn Forte 			QL_PM_UNLOCK(ha);
357fcf3ce44SJohn Forte 			return (FC_FAILURE);
358fcf3ce44SJohn Forte 		}
359fcf3ce44SJohn Forte 	} else {
360fcf3ce44SJohn Forte 		QL_PM_UNLOCK(ha);
361fcf3ce44SJohn Forte 	}
362fcf3ce44SJohn Forte 
363fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
364fcf3ce44SJohn Forte 
365fcf3ce44SJohn Forte 	return (FC_SUCCESS);
366fcf3ce44SJohn Forte }
367fcf3ce44SJohn Forte 
368fcf3ce44SJohn Forte /*
369fcf3ce44SJohn Forte  * ql_idle_notification
370fcf3ce44SJohn Forte  *	Adapter idle notification.
371fcf3ce44SJohn Forte  *
372fcf3ce44SJohn Forte  * Input:
373fcf3ce44SJohn Forte  *	ha = adapter state pointer.
374fcf3ce44SJohn Forte  *
375fcf3ce44SJohn Forte  * Returns:
376fcf3ce44SJohn Forte  *	FC_SUCCESS
377fcf3ce44SJohn Forte  *	FC_FAILURE
378fcf3ce44SJohn Forte  *
379fcf3ce44SJohn Forte  * Context:
380fcf3ce44SJohn Forte  *	Kernel context.
381fcf3ce44SJohn Forte  */
382fcf3ce44SJohn Forte static int
ql_idle_notification(ql_adapter_state_t * ha)383fcf3ce44SJohn Forte ql_idle_notification(ql_adapter_state_t *ha)
384fcf3ce44SJohn Forte {
385fcf3ce44SJohn Forte 	if (!ha->pm_capable) {
386fcf3ce44SJohn Forte 		return (FC_SUCCESS);
387fcf3ce44SJohn Forte 	}
388fcf3ce44SJohn Forte 
389fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
390fcf3ce44SJohn Forte 
391fcf3ce44SJohn Forte 	if (pm_idle_component(ha->dip, 0) != DDI_SUCCESS) {
392fcf3ce44SJohn Forte 		EL(ha, "pm_idle_component failed = %xh\n", FC_FAILURE);
393fcf3ce44SJohn Forte 		return (FC_FAILURE);
394fcf3ce44SJohn Forte 	}
395fcf3ce44SJohn Forte 
396fcf3ce44SJohn Forte 	QL_PM_LOCK(ha);
397fcf3ce44SJohn Forte 	ha->busy--;
398fcf3ce44SJohn Forte 	QL_PM_UNLOCK(ha);
399fcf3ce44SJohn Forte 
400fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
401fcf3ce44SJohn Forte 
402fcf3ce44SJohn Forte 	return (FC_SUCCESS);
403fcf3ce44SJohn Forte }
404fcf3ce44SJohn Forte 
405fcf3ce44SJohn Forte /*
406fcf3ce44SJohn Forte  * Get adapter feature bits from NVRAM
407fcf3ce44SJohn Forte  */
408fcf3ce44SJohn Forte static int
ql_get_feature_bits(ql_adapter_state_t * ha,uint16_t * features)409fcf3ce44SJohn Forte ql_get_feature_bits(ql_adapter_state_t *ha, uint16_t *features)
410fcf3ce44SJohn Forte {
411fcf3ce44SJohn Forte 	int			count;
412fcf3ce44SJohn Forte 	volatile uint16_t	data;
413fcf3ce44SJohn Forte 	uint32_t		nv_cmd;
414fcf3ce44SJohn Forte 	uint32_t		start_addr;
415fcf3ce44SJohn Forte 	int			rval;
416fcf3ce44SJohn Forte 	uint32_t		offset = offsetof(nvram_t, adapter_features);
417fcf3ce44SJohn Forte 
418fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
419fcf3ce44SJohn Forte 
420eb82ff87SDaniel Beauregard 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
421fcf3ce44SJohn Forte 		EL(ha, "Not supported for 24xx\n");
422fcf3ce44SJohn Forte 		return (EINVAL);
423fcf3ce44SJohn Forte 	}
424fcf3ce44SJohn Forte 
425fcf3ce44SJohn Forte 	/*
426fcf3ce44SJohn Forte 	 * The offset can't be greater than max of 8 bits and
427fcf3ce44SJohn Forte 	 * the following code breaks if the offset isn't at
428fcf3ce44SJohn Forte 	 * 2 byte boundary.
429fcf3ce44SJohn Forte 	 */
430fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
431fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
432fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
433fcf3ce44SJohn Forte 		return (EIO);
434fcf3ce44SJohn Forte 	}
435fcf3ce44SJohn Forte 
436fcf3ce44SJohn Forte 	/*
437fcf3ce44SJohn Forte 	 * Have the most significant 3 bits represent the read operation
438fcf3ce44SJohn Forte 	 * followed by the 8 bits representing the offset at which we
439fcf3ce44SJohn Forte 	 * are going to perform the read operation
440fcf3ce44SJohn Forte 	 */
441fcf3ce44SJohn Forte 	offset >>= 1;
442fcf3ce44SJohn Forte 	offset += start_addr;
443fcf3ce44SJohn Forte 	nv_cmd = (offset << 16) | NV_READ_OP;
444fcf3ce44SJohn Forte 	nv_cmd <<= 5;
445fcf3ce44SJohn Forte 
446fcf3ce44SJohn Forte 	/*
447fcf3ce44SJohn Forte 	 * Select the chip and feed the command and address
448fcf3ce44SJohn Forte 	 */
449fcf3ce44SJohn Forte 	for (count = 0; count < 11; count++) {
450fcf3ce44SJohn Forte 		if (nv_cmd & BIT_31) {
451fcf3ce44SJohn Forte 			ql_nv_write(ha, NV_DATA_OUT);
452fcf3ce44SJohn Forte 		} else {
453fcf3ce44SJohn Forte 			ql_nv_write(ha, 0);
454fcf3ce44SJohn Forte 		}
455fcf3ce44SJohn Forte 		nv_cmd <<= 1;
456fcf3ce44SJohn Forte 	}
457fcf3ce44SJohn Forte 
458fcf3ce44SJohn Forte 	*features = 0;
459fcf3ce44SJohn Forte 	for (count = 0; count < 16; count++) {
460fcf3ce44SJohn Forte 		WRT16_IO_REG(ha, nvram, NV_SELECT | NV_CLOCK);
461fcf3ce44SJohn Forte 		ql_nv_delay();
462fcf3ce44SJohn Forte 
463fcf3ce44SJohn Forte 		data = RD16_IO_REG(ha, nvram);
464fcf3ce44SJohn Forte 		*features <<= 1;
465fcf3ce44SJohn Forte 		if (data & NV_DATA_IN) {
466fcf3ce44SJohn Forte 			*features = (uint16_t)(*features | 0x1);
467fcf3ce44SJohn Forte 		}
468fcf3ce44SJohn Forte 
469fcf3ce44SJohn Forte 		WRT16_IO_REG(ha, nvram, NV_SELECT);
470fcf3ce44SJohn Forte 		ql_nv_delay();
471fcf3ce44SJohn Forte 	}
472fcf3ce44SJohn Forte 
473fcf3ce44SJohn Forte 	/*
474fcf3ce44SJohn Forte 	 * Deselect the chip
475fcf3ce44SJohn Forte 	 */
476fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
477fcf3ce44SJohn Forte 
478fcf3ce44SJohn Forte 	ql_release_nvram(ha);
479fcf3ce44SJohn Forte 
480fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
481fcf3ce44SJohn Forte 
482fcf3ce44SJohn Forte 	return (0);
483fcf3ce44SJohn Forte }
484fcf3ce44SJohn Forte 
485fcf3ce44SJohn Forte /*
486fcf3ce44SJohn Forte  * Set adapter feature bits in NVRAM
487fcf3ce44SJohn Forte  */
488fcf3ce44SJohn Forte static int
ql_set_feature_bits(ql_adapter_state_t * ha,uint16_t features)489fcf3ce44SJohn Forte ql_set_feature_bits(ql_adapter_state_t *ha, uint16_t features)
490fcf3ce44SJohn Forte {
491fcf3ce44SJohn Forte 	int		rval;
492fcf3ce44SJohn Forte 	uint32_t	count;
493fcf3ce44SJohn Forte 	nvram_t		*nv;
494fcf3ce44SJohn Forte 	uint16_t	*wptr;
495fcf3ce44SJohn Forte 	uint8_t		*bptr;
496fcf3ce44SJohn Forte 	uint8_t		csum;
497fcf3ce44SJohn Forte 	uint32_t	start_addr;
498fcf3ce44SJohn Forte 
499fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
500fcf3ce44SJohn Forte 
501eb82ff87SDaniel Beauregard 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
502fcf3ce44SJohn Forte 		EL(ha, "Not supported for 24xx\n");
503fcf3ce44SJohn Forte 		return (EINVAL);
504fcf3ce44SJohn Forte 	}
505fcf3ce44SJohn Forte 
506fcf3ce44SJohn Forte 	nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
507fcf3ce44SJohn Forte 	if (nv == NULL) {
508fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
509fcf3ce44SJohn Forte 		return (ENOMEM);
510fcf3ce44SJohn Forte 	}
511fcf3ce44SJohn Forte 
512fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
513fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
514fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
515fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (*nv));
516fcf3ce44SJohn Forte 		return (EIO);
517fcf3ce44SJohn Forte 	}
518fcf3ce44SJohn Forte 	rval = 0;
519fcf3ce44SJohn Forte 
520fcf3ce44SJohn Forte 	/*
521fcf3ce44SJohn Forte 	 * Read off the whole NVRAM
522fcf3ce44SJohn Forte 	 */
523fcf3ce44SJohn Forte 	wptr = (uint16_t *)nv;
524fcf3ce44SJohn Forte 	csum = 0;
525fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
526fcf3ce44SJohn Forte 		*wptr = (uint16_t)ql_get_nvram_word(ha, count + start_addr);
527fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)*wptr);
528fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
529fcf3ce44SJohn Forte 		wptr++;
530fcf3ce44SJohn Forte 	}
531fcf3ce44SJohn Forte 
532fcf3ce44SJohn Forte 	/*
533fcf3ce44SJohn Forte 	 * If the checksum is BAD then fail it right here.
534fcf3ce44SJohn Forte 	 */
535fcf3ce44SJohn Forte 	if (csum) {
536fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (*nv));
537fcf3ce44SJohn Forte 		ql_release_nvram(ha);
538fcf3ce44SJohn Forte 		return (EBADF);
539fcf3ce44SJohn Forte 	}
540fcf3ce44SJohn Forte 
541fcf3ce44SJohn Forte 	nv->adapter_features[0] = (uint8_t)((features & 0xFF00) >> 8);
542fcf3ce44SJohn Forte 	nv->adapter_features[1] = (uint8_t)(features & 0xFF);
543fcf3ce44SJohn Forte 
544fcf3ce44SJohn Forte 	/*
545fcf3ce44SJohn Forte 	 * Recompute the chesksum now
546fcf3ce44SJohn Forte 	 */
547fcf3ce44SJohn Forte 	bptr = (uint8_t *)nv;
548fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) - 1; count++) {
549fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + *bptr++);
550fcf3ce44SJohn Forte 	}
551fcf3ce44SJohn Forte 	csum = (uint8_t)(~csum + 1);
552fcf3ce44SJohn Forte 	nv->checksum = csum;
553fcf3ce44SJohn Forte 
554fcf3ce44SJohn Forte 	/*
555fcf3ce44SJohn Forte 	 * Now load the NVRAM
556fcf3ce44SJohn Forte 	 */
557fcf3ce44SJohn Forte 	wptr = (uint16_t *)nv;
558fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
559fcf3ce44SJohn Forte 		ql_load_nvram(ha, (uint8_t)(count + start_addr), *wptr++);
560fcf3ce44SJohn Forte 	}
561fcf3ce44SJohn Forte 
562fcf3ce44SJohn Forte 	/*
563fcf3ce44SJohn Forte 	 * Read NVRAM and verify the contents
564fcf3ce44SJohn Forte 	 */
565fcf3ce44SJohn Forte 	wptr = (uint16_t *)nv;
566fcf3ce44SJohn Forte 	csum = 0;
567fcf3ce44SJohn Forte 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
568fcf3ce44SJohn Forte 		if (ql_get_nvram_word(ha, count + start_addr) != *wptr) {
569fcf3ce44SJohn Forte 			rval = EIO;
570fcf3ce44SJohn Forte 			break;
571fcf3ce44SJohn Forte 		}
572fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)*wptr);
573fcf3ce44SJohn Forte 		csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
574fcf3ce44SJohn Forte 		wptr++;
575fcf3ce44SJohn Forte 	}
576fcf3ce44SJohn Forte 
577fcf3ce44SJohn Forte 	if (csum) {
578fcf3ce44SJohn Forte 		rval = EINVAL;
579fcf3ce44SJohn Forte 	}
580fcf3ce44SJohn Forte 
581fcf3ce44SJohn Forte 	kmem_free(nv, sizeof (*nv));
582fcf3ce44SJohn Forte 	ql_release_nvram(ha);
583fcf3ce44SJohn Forte 
584fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
585fcf3ce44SJohn Forte 
586fcf3ce44SJohn Forte 	return (rval);
587fcf3ce44SJohn Forte }
588fcf3ce44SJohn Forte 
589fcf3ce44SJohn Forte /*
590fcf3ce44SJohn Forte  * Fix this function to update just feature bits and checksum in NVRAM
591fcf3ce44SJohn Forte  */
592fcf3ce44SJohn Forte static int
ql_set_nvram_adapter_defaults(ql_adapter_state_t * ha)593fcf3ce44SJohn Forte ql_set_nvram_adapter_defaults(ql_adapter_state_t *ha)
594fcf3ce44SJohn Forte {
595fcf3ce44SJohn Forte 	int		rval;
596fcf3ce44SJohn Forte 	uint32_t	count;
597fcf3ce44SJohn Forte 	uint32_t	start_addr;
598fcf3ce44SJohn Forte 
599fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
600fcf3ce44SJohn Forte 
601fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
602fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
603fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
604fcf3ce44SJohn Forte 		return (EIO);
605fcf3ce44SJohn Forte 	}
606fcf3ce44SJohn Forte 	rval = 0;
607fcf3ce44SJohn Forte 
608eb82ff87SDaniel Beauregard 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
609fcf3ce44SJohn Forte 		nvram_24xx_t	*nv;
610fcf3ce44SJohn Forte 		uint32_t	*longptr;
611fcf3ce44SJohn Forte 		uint32_t	csum = 0;
612fcf3ce44SJohn Forte 
613fcf3ce44SJohn Forte 		nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
614fcf3ce44SJohn Forte 		if (nv == NULL) {
615fcf3ce44SJohn Forte 			EL(ha, "failed, kmem_zalloc\n");
616fcf3ce44SJohn Forte 			return (ENOMEM);
617fcf3ce44SJohn Forte 		}
618fcf3ce44SJohn Forte 
619fcf3ce44SJohn Forte 		nv->nvram_version[0] = LSB(ICB_24XX_VERSION);
620fcf3ce44SJohn Forte 		nv->nvram_version[1] = MSB(ICB_24XX_VERSION);
621fcf3ce44SJohn Forte 
622fcf3ce44SJohn Forte 		nv->version[0] = 1;
623fcf3ce44SJohn Forte 		nv->max_frame_length[1] = 8;
624fcf3ce44SJohn Forte 		nv->execution_throttle[0] = 16;
625fcf3ce44SJohn Forte 		nv->login_retry_count[0] = 8;
626fcf3ce44SJohn Forte 
627fcf3ce44SJohn Forte 		nv->firmware_options_1[0] = BIT_2 | BIT_1;
628fcf3ce44SJohn Forte 		nv->firmware_options_1[1] = BIT_5;
629fcf3ce44SJohn Forte 		nv->firmware_options_2[0] = BIT_5;
630fcf3ce44SJohn Forte 		nv->firmware_options_2[1] = BIT_4;
631fcf3ce44SJohn Forte 		nv->firmware_options_3[1] = BIT_6;
632fcf3ce44SJohn Forte 
633fcf3ce44SJohn Forte 		/*
634fcf3ce44SJohn Forte 		 * Set default host adapter parameters
635fcf3ce44SJohn Forte 		 */
636fcf3ce44SJohn Forte 		nv->host_p[0] = BIT_4 | BIT_1;
637fcf3ce44SJohn Forte 		nv->host_p[1] = BIT_3 | BIT_2;
638fcf3ce44SJohn Forte 		nv->reset_delay = 5;
639fcf3ce44SJohn Forte 		nv->max_luns_per_target[0] = 128;
640fcf3ce44SJohn Forte 		nv->port_down_retry_count[0] = 30;
641fcf3ce44SJohn Forte 		nv->link_down_timeout[0] = 30;
642fcf3ce44SJohn Forte 
643fcf3ce44SJohn Forte 		/*
644fcf3ce44SJohn Forte 		 * compute the chesksum now
645fcf3ce44SJohn Forte 		 */
646fcf3ce44SJohn Forte 		longptr = (uint32_t *)nv;
647fcf3ce44SJohn Forte 		csum = 0;
648fcf3ce44SJohn Forte 		for (count = 0; count < (sizeof (nvram_24xx_t)/4)-1; count++) {
649fcf3ce44SJohn Forte 			csum += *longptr;
650fcf3ce44SJohn Forte 			longptr++;
651fcf3ce44SJohn Forte 		}
652fcf3ce44SJohn Forte 		csum = (uint32_t)(~csum + 1);
653fcf3ce44SJohn Forte 		LITTLE_ENDIAN_32((long)csum);
654fcf3ce44SJohn Forte 		*longptr = csum;
655fcf3ce44SJohn Forte 
656fcf3ce44SJohn Forte 		/*
657fcf3ce44SJohn Forte 		 * Now load the NVRAM
658fcf3ce44SJohn Forte 		 */
659fcf3ce44SJohn Forte 		longptr = (uint32_t *)nv;
660fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_24xx_t) / 4; count++) {
661fcf3ce44SJohn Forte 			(void) ql_24xx_load_nvram(ha,
662fcf3ce44SJohn Forte 			    (uint32_t)(count + start_addr), *longptr++);
663fcf3ce44SJohn Forte 		}
664fcf3ce44SJohn Forte 
665fcf3ce44SJohn Forte 		/*
666fcf3ce44SJohn Forte 		 * Read NVRAM and verify the contents
667fcf3ce44SJohn Forte 		 */
668fcf3ce44SJohn Forte 		csum = 0;
669fcf3ce44SJohn Forte 		longptr = (uint32_t *)nv;
670fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_24xx_t) / 4; count++) {
671fcf3ce44SJohn Forte 			rval = ql_24xx_read_flash(ha, count + start_addr,
672fcf3ce44SJohn Forte 			    longptr);
673fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
674fcf3ce44SJohn Forte 				EL(ha, "24xx_read_flash failed=%xh\n", rval);
675fcf3ce44SJohn Forte 				break;
676fcf3ce44SJohn Forte 			}
677fcf3ce44SJohn Forte 			csum += *longptr;
678fcf3ce44SJohn Forte 		}
679fcf3ce44SJohn Forte 
680fcf3ce44SJohn Forte 		if (csum) {
681fcf3ce44SJohn Forte 			rval = EINVAL;
682fcf3ce44SJohn Forte 		}
683fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (nvram_24xx_t));
684fcf3ce44SJohn Forte 	} else {
685fcf3ce44SJohn Forte 		nvram_t		*nv;
686fcf3ce44SJohn Forte 		uint16_t	*wptr;
687fcf3ce44SJohn Forte 		uint8_t		*bptr;
688fcf3ce44SJohn Forte 		uint8_t		csum;
689fcf3ce44SJohn Forte 
690fcf3ce44SJohn Forte 		nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
691fcf3ce44SJohn Forte 		if (nv == NULL) {
692fcf3ce44SJohn Forte 			EL(ha, "failed, kmem_zalloc\n");
693fcf3ce44SJohn Forte 			return (ENOMEM);
694fcf3ce44SJohn Forte 		}
695fcf3ce44SJohn Forte 		/*
696fcf3ce44SJohn Forte 		 * Set default initialization control block.
697fcf3ce44SJohn Forte 		 */
698fcf3ce44SJohn Forte 		nv->parameter_block_version = ICB_VERSION;
699fcf3ce44SJohn Forte 		nv->firmware_options[0] = BIT_4 | BIT_3 | BIT_2 | BIT_1;
700fcf3ce44SJohn Forte 		nv->firmware_options[1] = BIT_7 | BIT_5 | BIT_2;
701fcf3ce44SJohn Forte 
702fcf3ce44SJohn Forte 		nv->max_frame_length[1] = 4;
703fcf3ce44SJohn Forte 		nv->max_iocb_allocation[1] = 1;
704fcf3ce44SJohn Forte 		nv->execution_throttle[0] = 16;
705fcf3ce44SJohn Forte 		nv->login_retry_count = 8;
706fcf3ce44SJohn Forte 		nv->port_name[0] = 33;
707fcf3ce44SJohn Forte 		nv->port_name[3] = 224;
708fcf3ce44SJohn Forte 		nv->port_name[4] = 139;
709fcf3ce44SJohn Forte 		nv->login_timeout = 4;
710fcf3ce44SJohn Forte 
711fcf3ce44SJohn Forte 		/*
712fcf3ce44SJohn Forte 		 * Set default host adapter parameters
713fcf3ce44SJohn Forte 		 */
714fcf3ce44SJohn Forte 		nv->host_p[0] = BIT_1;
715fcf3ce44SJohn Forte 		nv->host_p[1] = BIT_2;
716fcf3ce44SJohn Forte 		nv->reset_delay = 5;
717fcf3ce44SJohn Forte 		nv->port_down_retry_count = 8;
718fcf3ce44SJohn Forte 		nv->maximum_luns_per_target[0] = 8;
719fcf3ce44SJohn Forte 
720fcf3ce44SJohn Forte 		/*
721fcf3ce44SJohn Forte 		 * compute the chesksum now
722fcf3ce44SJohn Forte 		 */
723fcf3ce44SJohn Forte 		bptr = (uint8_t *)nv;
724fcf3ce44SJohn Forte 		csum = 0;
725fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_t) - 1; count++) {
726fcf3ce44SJohn Forte 			csum = (uint8_t)(csum + *bptr++);
727fcf3ce44SJohn Forte 		}
728fcf3ce44SJohn Forte 		csum = (uint8_t)(~csum + 1);
729fcf3ce44SJohn Forte 		nv->checksum = csum;
730fcf3ce44SJohn Forte 
731fcf3ce44SJohn Forte 		/*
732fcf3ce44SJohn Forte 		 * Now load the NVRAM
733fcf3ce44SJohn Forte 		 */
734fcf3ce44SJohn Forte 		wptr = (uint16_t *)nv;
735fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_t) / 2; count++) {
736fcf3ce44SJohn Forte 			ql_load_nvram(ha, (uint8_t)(count + start_addr),
737fcf3ce44SJohn Forte 			    *wptr++);
738fcf3ce44SJohn Forte 		}
739fcf3ce44SJohn Forte 
740fcf3ce44SJohn Forte 		/*
741fcf3ce44SJohn Forte 		 * Read NVRAM and verify the contents
742fcf3ce44SJohn Forte 		 */
743fcf3ce44SJohn Forte 		wptr = (uint16_t *)nv;
744fcf3ce44SJohn Forte 		csum = 0;
745fcf3ce44SJohn Forte 		for (count = 0; count < sizeof (nvram_t) / 2; count++) {
746fcf3ce44SJohn Forte 			if (ql_get_nvram_word(ha, count + start_addr) !=
747fcf3ce44SJohn Forte 			    *wptr) {
748fcf3ce44SJohn Forte 				rval = EIO;
749fcf3ce44SJohn Forte 				break;
750fcf3ce44SJohn Forte 			}
751fcf3ce44SJohn Forte 			csum = (uint8_t)(csum + (uint8_t)*wptr);
752fcf3ce44SJohn Forte 			csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
753fcf3ce44SJohn Forte 			wptr++;
754fcf3ce44SJohn Forte 		}
755fcf3ce44SJohn Forte 		if (csum) {
756fcf3ce44SJohn Forte 			rval = EINVAL;
757fcf3ce44SJohn Forte 		}
758fcf3ce44SJohn Forte 		kmem_free(nv, sizeof (*nv));
759fcf3ce44SJohn Forte 	}
760fcf3ce44SJohn Forte 	ql_release_nvram(ha);
761fcf3ce44SJohn Forte 
762fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
763fcf3ce44SJohn Forte 
764fcf3ce44SJohn Forte 	return (rval);
765fcf3ce44SJohn Forte }
766fcf3ce44SJohn Forte 
767fcf3ce44SJohn Forte static void
ql_load_nvram(ql_adapter_state_t * ha,uint8_t addr,uint16_t value)768fcf3ce44SJohn Forte ql_load_nvram(ql_adapter_state_t *ha, uint8_t addr, uint16_t value)
769fcf3ce44SJohn Forte {
770fcf3ce44SJohn Forte 	int			count;
771fcf3ce44SJohn Forte 	volatile uint16_t	word;
772fcf3ce44SJohn Forte 	volatile uint32_t	nv_cmd;
773fcf3ce44SJohn Forte 
774fcf3ce44SJohn Forte 	ql_nv_write(ha, NV_DATA_OUT);
775fcf3ce44SJohn Forte 	ql_nv_write(ha, 0);
776fcf3ce44SJohn Forte 	ql_nv_write(ha, 0);
777fcf3ce44SJohn Forte 
778fcf3ce44SJohn Forte 	for (word = 0; word < 8; word++) {
779fcf3ce44SJohn Forte 		ql_nv_write(ha, NV_DATA_OUT);
780fcf3ce44SJohn Forte 	}
781fcf3ce44SJohn Forte 
782fcf3ce44SJohn Forte 	/*
783fcf3ce44SJohn Forte 	 * Deselect the chip
784fcf3ce44SJohn Forte 	 */
785fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
786fcf3ce44SJohn Forte 	ql_nv_delay();
787fcf3ce44SJohn Forte 
788fcf3ce44SJohn Forte 	/*
789fcf3ce44SJohn Forte 	 * Erase Location
790fcf3ce44SJohn Forte 	 */
791fcf3ce44SJohn Forte 	nv_cmd = (addr << 16) | NV_ERASE_OP;
792fcf3ce44SJohn Forte 	nv_cmd <<= 5;
793fcf3ce44SJohn Forte 	for (count = 0; count < 11; count++) {
794fcf3ce44SJohn Forte 		if (nv_cmd & BIT_31) {
795fcf3ce44SJohn Forte 			ql_nv_write(ha, NV_DATA_OUT);
796fcf3ce44SJohn Forte 		} else {
797fcf3ce44SJohn Forte 			ql_nv_write(ha, 0);
798fcf3ce44SJohn Forte 		}
799fcf3ce44SJohn Forte 		nv_cmd <<= 1;
800fcf3ce44SJohn Forte 	}
801fcf3ce44SJohn Forte 
802fcf3ce44SJohn Forte 	/*
803fcf3ce44SJohn Forte 	 * Wait for Erase to Finish
804fcf3ce44SJohn Forte 	 */
805fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
806fcf3ce44SJohn Forte 	ql_nv_delay();
807fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_SELECT);
808fcf3ce44SJohn Forte 	word = 0;
809fcf3ce44SJohn Forte 	while ((word & NV_DATA_IN) == 0) {
810fcf3ce44SJohn Forte 		ql_nv_delay();
811fcf3ce44SJohn Forte 		word = RD16_IO_REG(ha, nvram);
812fcf3ce44SJohn Forte 	}
813fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
814fcf3ce44SJohn Forte 	ql_nv_delay();
815fcf3ce44SJohn Forte 
816fcf3ce44SJohn Forte 	/*
817fcf3ce44SJohn Forte 	 * Write data now
818fcf3ce44SJohn Forte 	 */
819fcf3ce44SJohn Forte 	nv_cmd = (addr << 16) | NV_WRITE_OP;
820fcf3ce44SJohn Forte 	nv_cmd |= value;
821fcf3ce44SJohn Forte 	nv_cmd <<= 5;
822fcf3ce44SJohn Forte 	for (count = 0; count < 27; count++) {
823fcf3ce44SJohn Forte 		if (nv_cmd & BIT_31) {
824fcf3ce44SJohn Forte 			ql_nv_write(ha, NV_DATA_OUT);
825fcf3ce44SJohn Forte 		} else {
826fcf3ce44SJohn Forte 			ql_nv_write(ha, 0);
827fcf3ce44SJohn Forte 		}
828fcf3ce44SJohn Forte 		nv_cmd <<= 1;
829fcf3ce44SJohn Forte 	}
830fcf3ce44SJohn Forte 
831fcf3ce44SJohn Forte 	/*
832fcf3ce44SJohn Forte 	 * Wait for NVRAM to become ready
833fcf3ce44SJohn Forte 	 */
834fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
835fcf3ce44SJohn Forte 	ql_nv_delay();
836fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_SELECT);
837fcf3ce44SJohn Forte 	word = 0;
838fcf3ce44SJohn Forte 	while ((word & NV_DATA_IN) == 0) {
839fcf3ce44SJohn Forte 		ql_nv_delay();
840fcf3ce44SJohn Forte 		word = RD16_IO_REG(ha, nvram);
841fcf3ce44SJohn Forte 	}
842fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
843fcf3ce44SJohn Forte 	ql_nv_delay();
844fcf3ce44SJohn Forte 
845fcf3ce44SJohn Forte 	/*
846fcf3ce44SJohn Forte 	 * Disable writes
847fcf3ce44SJohn Forte 	 */
848fcf3ce44SJohn Forte 	ql_nv_write(ha, NV_DATA_OUT);
849fcf3ce44SJohn Forte 	for (count = 0; count < 10; count++) {
850fcf3ce44SJohn Forte 		ql_nv_write(ha, 0);
851fcf3ce44SJohn Forte 	}
852fcf3ce44SJohn Forte 
853fcf3ce44SJohn Forte 	/*
854fcf3ce44SJohn Forte 	 * Deselect the chip now
855fcf3ce44SJohn Forte 	 */
856fcf3ce44SJohn Forte 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
857fcf3ce44SJohn Forte }
858fcf3ce44SJohn Forte 
859fcf3ce44SJohn Forte /*
860fcf3ce44SJohn Forte  * ql_24xx_load_nvram
861fcf3ce44SJohn Forte  *	Enable NVRAM and writes a 32bit word to ISP24xx NVRAM.
862fcf3ce44SJohn Forte  *
863fcf3ce44SJohn Forte  * Input:
864fcf3ce44SJohn Forte  *	ha:	adapter state pointer.
865fcf3ce44SJohn Forte  *	addr:	NVRAM address.
866fcf3ce44SJohn Forte  *	value:	data.
867fcf3ce44SJohn Forte  *
868fcf3ce44SJohn Forte  * Returns:
869fcf3ce44SJohn Forte  *	ql local function return status code.
870fcf3ce44SJohn Forte  *
871fcf3ce44SJohn Forte  * Context:
872fcf3ce44SJohn Forte  *	Kernel context.
873fcf3ce44SJohn Forte  */
874fcf3ce44SJohn Forte static int
ql_24xx_load_nvram(ql_adapter_state_t * ha,uint32_t addr,uint32_t value)875fcf3ce44SJohn Forte ql_24xx_load_nvram(ql_adapter_state_t *ha, uint32_t addr, uint32_t value)
876fcf3ce44SJohn Forte {
877fcf3ce44SJohn Forte 	int	rval;
878fcf3ce44SJohn Forte 
879fcf3ce44SJohn Forte 	/* Enable flash write. */
880eb82ff87SDaniel Beauregard 	if (!(CFG_IST(ha, CFG_CTRL_8081))) {
8815dfd244aSDaniel Beauregard 		WRT32_IO_REG(ha, ctrl_status,
8825dfd244aSDaniel Beauregard 		    RD32_IO_REG(ha, ctrl_status) | ISP_FLASH_ENABLE);
8835dfd244aSDaniel Beauregard 		RD32_IO_REG(ha, ctrl_status);	/* PCI Posting. */
8845dfd244aSDaniel Beauregard 	}
885fcf3ce44SJohn Forte 
886fcf3ce44SJohn Forte 	/* Disable NVRAM write-protection. */
887fcf3ce44SJohn Forte 	if (CFG_IST(ha, CFG_CTRL_2422)) {
888fcf3ce44SJohn Forte 		(void) ql_24xx_write_flash(ha, NVRAM_CONF_ADDR | 0x101, 0);
889fcf3ce44SJohn Forte 	} else {
8905dfd244aSDaniel Beauregard 		if ((rval = ql_24xx_unprotect_flash(ha)) != QL_SUCCESS) {
8915dfd244aSDaniel Beauregard 			EL(ha, "unprotect_flash failed, rval=%xh\n", rval);
8925dfd244aSDaniel Beauregard 			return (rval);
8935dfd244aSDaniel Beauregard 		}
894fcf3ce44SJohn Forte 	}
895fcf3ce44SJohn Forte 
896fcf3ce44SJohn Forte 	/* Write to flash. */
897fcf3ce44SJohn Forte 	rval = ql_24xx_write_flash(ha, addr, value);
898fcf3ce44SJohn Forte 
899fcf3ce44SJohn Forte 	/* Enable NVRAM write-protection. */
900fcf3ce44SJohn Forte 	if (CFG_IST(ha, CFG_CTRL_2422)) {
901fcf3ce44SJohn Forte 		/* TODO: Check if 0x8c is correct -- sb: 0x9c ? */
902fcf3ce44SJohn Forte 		(void) ql_24xx_write_flash(ha, NVRAM_CONF_ADDR | 0x101, 0x8c);
903fcf3ce44SJohn Forte 	} else {
904fcf3ce44SJohn Forte 		ql_24xx_protect_flash(ha);
905fcf3ce44SJohn Forte 	}
906fcf3ce44SJohn Forte 
907fcf3ce44SJohn Forte 	/* Disable flash write. */
9085dfd244aSDaniel Beauregard 	if (!(CFG_IST(ha, CFG_CTRL_81XX))) {
9095dfd244aSDaniel Beauregard 		WRT32_IO_REG(ha, ctrl_status,
9105dfd244aSDaniel Beauregard 		    RD32_IO_REG(ha, ctrl_status) & ~ISP_FLASH_ENABLE);
9115dfd244aSDaniel Beauregard 		RD32_IO_REG(ha, ctrl_status);	/* PCI Posting. */
9125dfd244aSDaniel Beauregard 	}
913fcf3ce44SJohn Forte 
914fcf3ce44SJohn Forte 	return (rval);
915fcf3ce44SJohn Forte }
916fcf3ce44SJohn Forte 
917fcf3ce44SJohn Forte /*
918fcf3ce44SJohn Forte  * ql_nv_util_load
919fcf3ce44SJohn Forte  *	Loads NVRAM from application.
920fcf3ce44SJohn Forte  *
921fcf3ce44SJohn Forte  * Input:
922fcf3ce44SJohn Forte  *	ha = adapter state pointer.
923fcf3ce44SJohn Forte  *	bp = user buffer address.
924fcf3ce44SJohn Forte  *
925fcf3ce44SJohn Forte  * Returns:
926fcf3ce44SJohn Forte  *
927fcf3ce44SJohn Forte  * Context:
928fcf3ce44SJohn Forte  *	Kernel context.
929fcf3ce44SJohn Forte  */
930fcf3ce44SJohn Forte int
ql_nv_util_load(ql_adapter_state_t * ha,void * bp,int mode)931fcf3ce44SJohn Forte ql_nv_util_load(ql_adapter_state_t *ha, void *bp, int mode)
932fcf3ce44SJohn Forte {
933fcf3ce44SJohn Forte 	uint8_t		cnt;
934fcf3ce44SJohn Forte 	void		*nv;
935fcf3ce44SJohn Forte 	uint16_t	*wptr;
936fcf3ce44SJohn Forte 	uint16_t	data;
937c1fad183SDaniel Beauregard 	uint32_t	start_addr, *lptr, data32;
938fcf3ce44SJohn Forte 	nvram_t		*nptr;
939fcf3ce44SJohn Forte 	int		rval;
940fcf3ce44SJohn Forte 
941fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
942fcf3ce44SJohn Forte 
943c1fad183SDaniel Beauregard 	if ((nv = kmem_zalloc(ha->nvram_cache->size, KM_SLEEP)) == NULL) {
944fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
945fcf3ce44SJohn Forte 		return (ENOMEM);
946fcf3ce44SJohn Forte 	}
947fcf3ce44SJohn Forte 
948c1fad183SDaniel Beauregard 	if (ddi_copyin(bp, nv, ha->nvram_cache->size, mode) != 0) {
949fcf3ce44SJohn Forte 		EL(ha, "Buffer copy failed\n");
950c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
951fcf3ce44SJohn Forte 		return (EFAULT);
952fcf3ce44SJohn Forte 	}
953fcf3ce44SJohn Forte 
954fcf3ce44SJohn Forte 	/* See if the buffer passed to us looks sane */
955fcf3ce44SJohn Forte 	nptr = (nvram_t *)nv;
956fcf3ce44SJohn Forte 	if (nptr->id[0] != 'I' || nptr->id[1] != 'S' || nptr->id[2] != 'P' ||
957fcf3ce44SJohn Forte 	    nptr->id[3] != ' ') {
958fcf3ce44SJohn Forte 		EL(ha, "failed, buffer sanity check\n");
959c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
960fcf3ce44SJohn Forte 		return (EINVAL);
961fcf3ce44SJohn Forte 	}
962fcf3ce44SJohn Forte 
963fcf3ce44SJohn Forte 	/* Quiesce I/O */
964fcf3ce44SJohn Forte 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
965fcf3ce44SJohn Forte 		EL(ha, "ql_stall_driver failed\n");
966c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
967fcf3ce44SJohn Forte 		return (EBUSY);
968fcf3ce44SJohn Forte 	}
969fcf3ce44SJohn Forte 
970fcf3ce44SJohn Forte 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
971fcf3ce44SJohn Forte 	if (rval != QL_SUCCESS) {
972fcf3ce44SJohn Forte 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
973c1fad183SDaniel Beauregard 		kmem_free(nv, ha->nvram_cache->size);
974fcf3ce44SJohn Forte 		ql_restart_driver(ha);
975fcf3ce44SJohn Forte 		return (EIO);
976fcf3ce44SJohn Forte 	}
977fcf3ce44SJohn Forte 
978fcf3ce44SJohn Forte 	/* Load NVRAM. */
979eb82ff87SDaniel Beauregard 	if (CFG_IST(ha, CFG_CTRL_258081)) {
980fcf3ce44SJohn Forte 		GLOBAL_HW_UNLOCK();
9815dfd244aSDaniel Beauregard 		start_addr &= ~ha->flash_data_addr;
9825dfd244aSDaniel Beauregard 		start_addr <<= 2;
983c1fad183SDaniel Beauregard 		if ((rval = ql_r_m_w_flash(ha, bp, ha->nvram_cache->size,
984c1fad183SDaniel Beauregard 		    start_addr, mode)) != QL_SUCCESS) {
985fcf3ce44SJohn Forte 			EL(ha, "nvram load failed, rval = %0xh\n", rval);
986fcf3ce44SJohn Forte 		}
987fcf3ce44SJohn Forte 		GLOBAL_HW_LOCK();
988fcf3ce44SJohn Forte 	} else if (CFG_IST(ha, CFG_CTRL_2422)) {
989fcf3ce44SJohn Forte 		lptr = (uint32_t *)nv;
990c1fad183SDaniel Beauregard 		for (cnt = 0; cnt < ha->nvram_cache->size / 4; cnt++) {
991fcf3ce44SJohn Forte 			data32 = *lptr++;
992fcf3ce44SJohn Forte 			LITTLE_ENDIAN_32(&data32);
993fcf3ce44SJohn Forte 			rval = ql_24xx_load_nvram(ha, cnt + start_addr,
994fcf3ce44SJohn Forte 			    data32);
995fcf3ce44SJohn Forte 			if (rval != QL_SUCCESS) {
996fcf3ce44SJohn Forte 				EL(ha, "failed, 24xx_load_nvram=%xh\n", rval);
997fcf3ce44SJohn Forte 				break;
998fcf3ce44SJohn Forte 			}
999fcf3ce44SJohn Forte 		}
1000fcf3ce44SJohn Forte 	} else {
1001fcf3ce44SJohn Forte 		wptr = (uint16_t *)nv;
1002c1fad183SDaniel Beauregard 		for (cnt = 0; cnt < ha->nvram_cache->size / 2; cnt++) {
1003fcf3ce44SJohn Forte 			data = *wptr++;
1004fcf3ce44SJohn Forte 			LITTLE_ENDIAN_16(&data);
1005fcf3ce44SJohn Forte 			ql_load_nvram(ha, (uint8_t)(cnt + start_addr), data);
1006fcf3ce44SJohn Forte 		}
1007fcf3ce44SJohn Forte 	}
1008c1fad183SDaniel Beauregard 	/* switch to the new one */
1009c1fad183SDaniel Beauregard 	NVRAM_CACHE_LOCK(ha);
1010c1fad183SDaniel Beauregard 
1011c1fad183SDaniel Beauregard 	kmem_free(ha->nvram_cache->cache, ha->nvram_cache->size);
1012c1fad183SDaniel Beauregard 	ha->nvram_cache->cache = (void *)nptr;
1013c1fad183SDaniel Beauregard 
1014c1fad183SDaniel Beauregard 	NVRAM_CACHE_UNLOCK(ha);
1015fcf3ce44SJohn Forte 
1016fcf3ce44SJohn Forte 	ql_release_nvram(ha);
1017fcf3ce44SJohn Forte 	ql_restart_driver(ha);
1018fcf3ce44SJohn Forte 
1019fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
1020fcf3ce44SJohn Forte 
1021fcf3ce44SJohn Forte 	if (rval == QL_SUCCESS) {
1022fcf3ce44SJohn Forte 		return (0);
1023fcf3ce44SJohn Forte 	}
1024fcf3ce44SJohn Forte 
1025fcf3ce44SJohn Forte 	return (EFAULT);
1026fcf3ce44SJohn Forte }
1027fcf3ce44SJohn Forte 
1028fcf3ce44SJohn Forte /*
1029fcf3ce44SJohn Forte  * ql_nv_util_dump
1030fcf3ce44SJohn Forte  *	Dumps NVRAM to application.
1031fcf3ce44SJohn Forte  *
1032fcf3ce44SJohn Forte  * Input:
1033fcf3ce44SJohn Forte  *	ha = adapter state pointer.
1034fcf3ce44SJohn Forte  *	bp = user buffer address.
1035fcf3ce44SJohn Forte  *
1036fcf3ce44SJohn Forte  * Returns:
1037fcf3ce44SJohn Forte  *
1038fcf3ce44SJohn Forte  * Context:
1039fcf3ce44SJohn Forte  *	Kernel context.
1040fcf3ce44SJohn Forte  */
1041fcf3ce44SJohn Forte int
ql_nv_util_dump(ql_adapter_state_t * ha,void * bp,int mode)1042fcf3ce44SJohn Forte ql_nv_util_dump(ql_adapter_state_t *ha, void *bp, int mode)
1043fcf3ce44SJohn Forte {
1044fcf3ce44SJohn Forte 	uint32_t	start_addr;
1045fcf3ce44SJohn Forte 	int		rval2, rval = 0;
1046fcf3ce44SJohn Forte 
1047fcf3ce44SJohn Forte 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
1048fcf3ce44SJohn Forte 
1049c1fad183SDaniel Beauregard 	if (ha->nvram_cache == NULL ||
1050*c92b35bbSToomas Soome 	    ha->nvram_cache->size == 0 ||
1051c1fad183SDaniel Beauregard 	    ha->nvram_cache->cache == NULL) {
1052fcf3ce44SJohn Forte 		EL(ha, "failed, kmem_zalloc\n");
1053fcf3ce44SJohn Forte 		return (ENOMEM);
1054c1fad183SDaniel Beauregard 	} else if (ha->nvram_cache->valid != 1) {
1055fcf3ce44SJohn Forte 
1056c1fad183SDaniel Beauregard 		/* Quiesce I/O */
1057c1fad183SDaniel Beauregard 		if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
1058c1fad183SDaniel Beauregard 			EL(ha, "ql_stall_driver failed\n");
1059c1fad183SDaniel Beauregard 			return (EBUSY);
1060c1fad183SDaniel Beauregard 		}
1061fcf3ce44SJohn Forte 
1062c1fad183SDaniel Beauregard 		rval2 = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
1063c1fad183SDaniel Beauregard 		if (rval2 != QL_SUCCESS) {
1064c1fad183SDaniel Beauregard 			EL(ha, "failed, ql_lock_nvram=%xh\n", rval2);
1065c1fad183SDaniel Beauregard 			ql_restart_driver(ha);
1066c1fad183SDaniel Beauregard 			return (EIO);
1067c1fad183SDaniel Beauregard 		}
1068c1fad183SDaniel Beauregard 		NVRAM_CACHE_LOCK(ha);
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 {
1075