xref: /onnv-gate/usr/src/uts/common/io/fibre-channel/fca/qlc/ql_ioctl.c (revision 12279:f13874aa8143)
17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM  * CDDL HEADER START
37836SJohn.Forte@Sun.COM  *
47836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM  *
87836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM  * and limitations under the License.
127836SJohn.Forte@Sun.COM  *
137836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM  *
197836SJohn.Forte@Sun.COM  * CDDL HEADER END
207836SJohn.Forte@Sun.COM  */
217836SJohn.Forte@Sun.COM 
2211541SDaniel.Beauregard@Sun.COM /* Copyright 2010 QLogic Corporation */
237836SJohn.Forte@Sun.COM 
247836SJohn.Forte@Sun.COM /*
25*12279SDaniel.Beauregard@Sun.COM  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
267836SJohn.Forte@Sun.COM  */
277836SJohn.Forte@Sun.COM 
2811541SDaniel.Beauregard@Sun.COM #pragma ident	"Copyright 2010 QLogic Corporation; ql_ioctl.c"
297836SJohn.Forte@Sun.COM 
307836SJohn.Forte@Sun.COM /*
317836SJohn.Forte@Sun.COM  * ISP2xxx Solaris Fibre Channel Adapter (FCA) driver source file.
327836SJohn.Forte@Sun.COM  * Fibre Channel Adapter (FCA) driver IOCTL source file.
337836SJohn.Forte@Sun.COM  *
347836SJohn.Forte@Sun.COM  * ***********************************************************************
357836SJohn.Forte@Sun.COM  * *									**
367836SJohn.Forte@Sun.COM  * *				NOTICE					**
3711541SDaniel.Beauregard@Sun.COM  * *		COPYRIGHT (C) 1996-2010 QLOGIC CORPORATION		**
387836SJohn.Forte@Sun.COM  * *			ALL RIGHTS RESERVED				**
397836SJohn.Forte@Sun.COM  * *									**
407836SJohn.Forte@Sun.COM  * ***********************************************************************
417836SJohn.Forte@Sun.COM  *
427836SJohn.Forte@Sun.COM  */
437836SJohn.Forte@Sun.COM 
447836SJohn.Forte@Sun.COM #include <ql_apps.h>
457836SJohn.Forte@Sun.COM #include <ql_api.h>
467836SJohn.Forte@Sun.COM #include <ql_debug.h>
477836SJohn.Forte@Sun.COM #include <ql_init.h>
487836SJohn.Forte@Sun.COM #include <ql_ioctl.h>
497836SJohn.Forte@Sun.COM #include <ql_mbx.h>
507836SJohn.Forte@Sun.COM #include <ql_xioctl.h>
517836SJohn.Forte@Sun.COM 
527836SJohn.Forte@Sun.COM /*
537836SJohn.Forte@Sun.COM  * Local Function Prototypes.
547836SJohn.Forte@Sun.COM  */
557836SJohn.Forte@Sun.COM static int ql_busy_notification(ql_adapter_state_t *);
567836SJohn.Forte@Sun.COM static int ql_idle_notification(ql_adapter_state_t *);
577836SJohn.Forte@Sun.COM static int ql_get_feature_bits(ql_adapter_state_t *ha, uint16_t *features);
587836SJohn.Forte@Sun.COM static int ql_set_feature_bits(ql_adapter_state_t *ha, uint16_t features);
597836SJohn.Forte@Sun.COM static int ql_set_nvram_adapter_defaults(ql_adapter_state_t *ha);
607836SJohn.Forte@Sun.COM static void ql_load_nvram(ql_adapter_state_t *ha, uint8_t addr,
617836SJohn.Forte@Sun.COM     uint16_t value);
627836SJohn.Forte@Sun.COM static int ql_24xx_load_nvram(ql_adapter_state_t *, uint32_t, uint32_t);
637836SJohn.Forte@Sun.COM static int ql_adm_op(ql_adapter_state_t *, void *, int);
647836SJohn.Forte@Sun.COM static int ql_adm_adapter_info(ql_adapter_state_t *, ql_adm_op_t *, int);
657836SJohn.Forte@Sun.COM static int ql_adm_extended_logging(ql_adapter_state_t *, ql_adm_op_t *);
667836SJohn.Forte@Sun.COM static int ql_adm_device_list(ql_adapter_state_t *, ql_adm_op_t *, int);
677836SJohn.Forte@Sun.COM static int ql_adm_update_properties(ql_adapter_state_t *);
687836SJohn.Forte@Sun.COM static int ql_adm_prop_update_int(ql_adapter_state_t *, ql_adm_op_t *, int);
697836SJohn.Forte@Sun.COM static int ql_adm_loop_reset(ql_adapter_state_t *);
707836SJohn.Forte@Sun.COM static int ql_adm_fw_dump(ql_adapter_state_t *, ql_adm_op_t *, void *, int);
717836SJohn.Forte@Sun.COM static int ql_adm_nvram_dump(ql_adapter_state_t *, ql_adm_op_t *, int);
727836SJohn.Forte@Sun.COM static int ql_adm_nvram_load(ql_adapter_state_t *, ql_adm_op_t *, int);
737836SJohn.Forte@Sun.COM static int ql_adm_flash_load(ql_adapter_state_t *, ql_adm_op_t *, int);
747836SJohn.Forte@Sun.COM static int ql_adm_vpd_dump(ql_adapter_state_t *, ql_adm_op_t *, int);
757836SJohn.Forte@Sun.COM static int ql_adm_vpd_load(ql_adapter_state_t *, ql_adm_op_t *, int);
767836SJohn.Forte@Sun.COM static int ql_adm_vpd_gettag(ql_adapter_state_t *, ql_adm_op_t *, int);
777836SJohn.Forte@Sun.COM static int ql_adm_updfwmodule(ql_adapter_state_t *, ql_adm_op_t *, int);
787836SJohn.Forte@Sun.COM static uint8_t *ql_vpd_findtag(ql_adapter_state_t *, uint8_t *, int8_t *);
797836SJohn.Forte@Sun.COM 
807836SJohn.Forte@Sun.COM /* ************************************************************************ */
817836SJohn.Forte@Sun.COM /*				cb_ops functions			    */
827836SJohn.Forte@Sun.COM /* ************************************************************************ */
837836SJohn.Forte@Sun.COM 
847836SJohn.Forte@Sun.COM /*
857836SJohn.Forte@Sun.COM  * ql_open
867836SJohn.Forte@Sun.COM  *	opens device
877836SJohn.Forte@Sun.COM  *
887836SJohn.Forte@Sun.COM  * Input:
897836SJohn.Forte@Sun.COM  *	dev_p = device pointer
907836SJohn.Forte@Sun.COM  *	flags = open flags
917836SJohn.Forte@Sun.COM  *	otype = open type
927836SJohn.Forte@Sun.COM  *	cred_p = credentials pointer
937836SJohn.Forte@Sun.COM  *
947836SJohn.Forte@Sun.COM  * Returns:
957836SJohn.Forte@Sun.COM  *	0 = success
967836SJohn.Forte@Sun.COM  *
977836SJohn.Forte@Sun.COM  * Context:
987836SJohn.Forte@Sun.COM  *	Kernel context.
997836SJohn.Forte@Sun.COM  */
1007836SJohn.Forte@Sun.COM /* ARGSUSED */
1017836SJohn.Forte@Sun.COM int
ql_open(dev_t * dev_p,int flags,int otyp,cred_t * cred_p)1027836SJohn.Forte@Sun.COM ql_open(dev_t *dev_p, int flags, int otyp, cred_t *cred_p)
1037836SJohn.Forte@Sun.COM {
1047836SJohn.Forte@Sun.COM 	ql_adapter_state_t	*ha;
1057836SJohn.Forte@Sun.COM 	int			rval = 0;
1067836SJohn.Forte@Sun.COM 
1077836SJohn.Forte@Sun.COM 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(*dev_p));
1087836SJohn.Forte@Sun.COM 	if (ha == NULL) {
1097836SJohn.Forte@Sun.COM 		QL_PRINT_2(CE_CONT, "failed, no adapter\n");
1107836SJohn.Forte@Sun.COM 		return (ENXIO);
1117836SJohn.Forte@Sun.COM 	}
1127836SJohn.Forte@Sun.COM 
1137836SJohn.Forte@Sun.COM 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
1147836SJohn.Forte@Sun.COM 
1157836SJohn.Forte@Sun.COM 	/* Allow only character opens */
1167836SJohn.Forte@Sun.COM 	if (otyp != OTYP_CHR) {
1177836SJohn.Forte@Sun.COM 		QL_PRINT_2(CE_CONT, "(%d): failed, open type\n",
1187836SJohn.Forte@Sun.COM 		    ha->instance);
1197836SJohn.Forte@Sun.COM 		return (EINVAL);
1207836SJohn.Forte@Sun.COM 	}
1217836SJohn.Forte@Sun.COM 
1227836SJohn.Forte@Sun.COM 	ADAPTER_STATE_LOCK(ha);
1237836SJohn.Forte@Sun.COM 	if (flags & FEXCL && ha->flags & QL_OPENED) {
1247836SJohn.Forte@Sun.COM 		ADAPTER_STATE_UNLOCK(ha);
1257836SJohn.Forte@Sun.COM 		rval = EBUSY;
1267836SJohn.Forte@Sun.COM 	} else {
1277836SJohn.Forte@Sun.COM 		ha->flags |= QL_OPENED;
1287836SJohn.Forte@Sun.COM 		ADAPTER_STATE_UNLOCK(ha);
1297836SJohn.Forte@Sun.COM 	}
1307836SJohn.Forte@Sun.COM 
1317836SJohn.Forte@Sun.COM 	if (rval != 0) {
1327836SJohn.Forte@Sun.COM 		EL(ha, "failed, rval = %xh\n", rval);
1337836SJohn.Forte@Sun.COM 	} else {
1347836SJohn.Forte@Sun.COM 		/*EMPTY*/
1357836SJohn.Forte@Sun.COM 		QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1367836SJohn.Forte@Sun.COM 	}
1377836SJohn.Forte@Sun.COM 	return (rval);
1387836SJohn.Forte@Sun.COM }
1397836SJohn.Forte@Sun.COM 
1407836SJohn.Forte@Sun.COM /*
1417836SJohn.Forte@Sun.COM  * ql_close
1427836SJohn.Forte@Sun.COM  *	opens device
1437836SJohn.Forte@Sun.COM  *
1447836SJohn.Forte@Sun.COM  * Input:
1457836SJohn.Forte@Sun.COM  *	dev_p = device pointer
1467836SJohn.Forte@Sun.COM  *	flags = open flags
1477836SJohn.Forte@Sun.COM  *	otype = open type
1487836SJohn.Forte@Sun.COM  *	cred_p = credentials pointer
1497836SJohn.Forte@Sun.COM  *
1507836SJohn.Forte@Sun.COM  * Returns:
1517836SJohn.Forte@Sun.COM  *	0 = success
1527836SJohn.Forte@Sun.COM  *
1537836SJohn.Forte@Sun.COM  * Context:
1547836SJohn.Forte@Sun.COM  *	Kernel context.
1557836SJohn.Forte@Sun.COM  */
1567836SJohn.Forte@Sun.COM /* ARGSUSED */
1577836SJohn.Forte@Sun.COM int
ql_close(dev_t dev,int flags,int otyp,cred_t * cred_p)1587836SJohn.Forte@Sun.COM ql_close(dev_t dev, int flags, int otyp, cred_t *cred_p)
1597836SJohn.Forte@Sun.COM {
1607836SJohn.Forte@Sun.COM 	ql_adapter_state_t	*ha;
1617836SJohn.Forte@Sun.COM 	int			rval = 0;
1627836SJohn.Forte@Sun.COM 
1637836SJohn.Forte@Sun.COM 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(dev));
1647836SJohn.Forte@Sun.COM 	if (ha == NULL) {
1657836SJohn.Forte@Sun.COM 		QL_PRINT_2(CE_CONT, "failed, no adapter\n");
1667836SJohn.Forte@Sun.COM 		return (ENXIO);
1677836SJohn.Forte@Sun.COM 	}
1687836SJohn.Forte@Sun.COM 
1697836SJohn.Forte@Sun.COM 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
1707836SJohn.Forte@Sun.COM 
1717836SJohn.Forte@Sun.COM 	if (otyp != OTYP_CHR) {
1727836SJohn.Forte@Sun.COM 		QL_PRINT_2(CE_CONT, "(%d): failed, open type\n",
1737836SJohn.Forte@Sun.COM 		    ha->instance);
1747836SJohn.Forte@Sun.COM 		return (EINVAL);
1757836SJohn.Forte@Sun.COM 	}
1767836SJohn.Forte@Sun.COM 
1777836SJohn.Forte@Sun.COM 	ADAPTER_STATE_LOCK(ha);
1787836SJohn.Forte@Sun.COM 	ha->flags &= ~QL_OPENED;
1797836SJohn.Forte@Sun.COM 	ADAPTER_STATE_UNLOCK(ha);
1807836SJohn.Forte@Sun.COM 
1817836SJohn.Forte@Sun.COM 	if (rval != 0) {
1827836SJohn.Forte@Sun.COM 		EL(ha, "failed, rval = %xh\n", rval);
1837836SJohn.Forte@Sun.COM 	} else {
1847836SJohn.Forte@Sun.COM 		/*EMPTY*/
1857836SJohn.Forte@Sun.COM 		QL_PRINT_3(CE_CONT, "(%d): done\n", ha->instance);
1867836SJohn.Forte@Sun.COM 	}
1877836SJohn.Forte@Sun.COM 	return (rval);
1887836SJohn.Forte@Sun.COM }
1897836SJohn.Forte@Sun.COM 
1907836SJohn.Forte@Sun.COM /*
1917836SJohn.Forte@Sun.COM  * ql_ioctl
1927836SJohn.Forte@Sun.COM  *	control a character device
1937836SJohn.Forte@Sun.COM  *
1947836SJohn.Forte@Sun.COM  * Input:
1957836SJohn.Forte@Sun.COM  *	dev = device number
1967836SJohn.Forte@Sun.COM  *	cmd = function to perform
1977836SJohn.Forte@Sun.COM  *	arg = data type varies with request
1987836SJohn.Forte@Sun.COM  *	mode = flags
1997836SJohn.Forte@Sun.COM  *	cred_p = credentials pointer
2007836SJohn.Forte@Sun.COM  *	rval_p = pointer to result value
2017836SJohn.Forte@Sun.COM  *
2027836SJohn.Forte@Sun.COM  * Returns:
2037836SJohn.Forte@Sun.COM  *	0 = success
2047836SJohn.Forte@Sun.COM  *
2057836SJohn.Forte@Sun.COM  * Context:
2067836SJohn.Forte@Sun.COM  *	Kernel context.
2077836SJohn.Forte@Sun.COM  */
2087836SJohn.Forte@Sun.COM /* ARGSUSED */
2097836SJohn.Forte@Sun.COM int
ql_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)2107836SJohn.Forte@Sun.COM ql_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cred_p,
2117836SJohn.Forte@Sun.COM     int *rval_p)
2127836SJohn.Forte@Sun.COM {
2137836SJohn.Forte@Sun.COM 	ql_adapter_state_t	*ha;
2147836SJohn.Forte@Sun.COM 	int			rval = 0;
2157836SJohn.Forte@Sun.COM 
2167836SJohn.Forte@Sun.COM 	if (ddi_in_panic()) {
2179446SDaniel.Beauregard@Sun.COM 		QL_PRINT_2(CE_CONT, "ql_ioctl: ddi_in_panic exit\n");
2187836SJohn.Forte@Sun.COM 		return (ENOPROTOOPT);
2197836SJohn.Forte@Sun.COM 	}
2207836SJohn.Forte@Sun.COM 
2217836SJohn.Forte@Sun.COM 	ha = ddi_get_soft_state(ql_state, (int32_t)getminor(dev));
2227836SJohn.Forte@Sun.COM 	if (ha == NULL)	{
2237836SJohn.Forte@Sun.COM 		QL_PRINT_2(CE_CONT, "failed, no adapter\n");
2247836SJohn.Forte@Sun.COM 		return (ENXIO);
2257836SJohn.Forte@Sun.COM 	}
2267836SJohn.Forte@Sun.COM 
2277836SJohn.Forte@Sun.COM 	QL_PRINT_3(CE_CONT, "(%d): started\n", ha->instance);
2287836SJohn.Forte@Sun.COM 
2297836SJohn.Forte@Sun.COM 	/*
2307836SJohn.Forte@Sun.COM 	 * Quick clean exit for qla2x00 foapi calls which are
2317836SJohn.Forte@Sun.COM 	 * not supported in qlc.
2327836SJohn.Forte@Sun.COM 	 */
2337836SJohn.Forte@Sun.COM 	if (cmd >= QL_FOAPI_START && cmd <= QL_FOAPI_END) {
2347836SJohn.Forte@Sun.COM 		QL_PRINT_9(CE_CONT, "failed, fo api not supported\n");
2357836SJohn.Forte@Sun.COM 		return (ENOTTY);
2367836SJohn.Forte@Sun.COM 	}
2377836SJohn.Forte@Sun.COM 
2387836SJohn.Forte@Sun.COM 	/* PWR management busy. */
2397836SJohn.Forte@Sun.COM 	rval = ql_busy_notification(ha);
2407836SJohn.Forte@Sun.COM 	if (rval != FC_SUCCESS)	 {
2417836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_busy_notification\n");
2427836SJohn.Forte@Sun.COM 		return (ENXIO);
2437836SJohn.Forte@Sun.COM 	}
2447836SJohn.Forte@Sun.COM 
2457836SJohn.Forte@Sun.COM 	rval = ql_xioctl(ha, cmd, arg, mode, cred_p, rval_p);
2467836SJohn.Forte@Sun.COM 	if (rval == ENOPROTOOPT || rval == EINVAL) {
2477836SJohn.Forte@Sun.COM 		switch (cmd) {
2489156SDaniel.Beauregard@Sun.COM 		case QL_GET_ADAPTER_FEATURE_BITS: {
2497836SJohn.Forte@Sun.COM 			uint16_t bits;
2507836SJohn.Forte@Sun.COM 
2517836SJohn.Forte@Sun.COM 			rval = ql_get_feature_bits(ha, &bits);
2527836SJohn.Forte@Sun.COM 
2537836SJohn.Forte@Sun.COM 			if (!rval && ddi_copyout((void *)&bits, (void *)arg,
2547836SJohn.Forte@Sun.COM 			    sizeof (bits), mode)) {
2557836SJohn.Forte@Sun.COM 				rval = EFAULT;
2567836SJohn.Forte@Sun.COM 			}
2577836SJohn.Forte@Sun.COM 			break;
2587836SJohn.Forte@Sun.COM 		}
2597836SJohn.Forte@Sun.COM 
2609156SDaniel.Beauregard@Sun.COM 		case QL_SET_ADAPTER_FEATURE_BITS: {
2617836SJohn.Forte@Sun.COM 			uint16_t bits;
2627836SJohn.Forte@Sun.COM 
2637836SJohn.Forte@Sun.COM 			if (ddi_copyin((void *)arg, (void *)&bits,
2647836SJohn.Forte@Sun.COM 			    sizeof (bits), mode)) {
2657836SJohn.Forte@Sun.COM 				rval = EFAULT;
2667836SJohn.Forte@Sun.COM 				break;
2677836SJohn.Forte@Sun.COM 			}
2687836SJohn.Forte@Sun.COM 
2697836SJohn.Forte@Sun.COM 			rval = ql_set_feature_bits(ha, bits);
2707836SJohn.Forte@Sun.COM 			break;
2717836SJohn.Forte@Sun.COM 		}
2727836SJohn.Forte@Sun.COM 
2737836SJohn.Forte@Sun.COM 		case QL_SET_ADAPTER_NVRAM_DEFAULTS:
2747836SJohn.Forte@Sun.COM 			rval = ql_set_nvram_adapter_defaults(ha);
2757836SJohn.Forte@Sun.COM 			break;
2767836SJohn.Forte@Sun.COM 
2777836SJohn.Forte@Sun.COM 		case QL_UTIL_LOAD:
2787836SJohn.Forte@Sun.COM 			rval = ql_nv_util_load(ha, (void *)arg, mode);
2797836SJohn.Forte@Sun.COM 			break;
2807836SJohn.Forte@Sun.COM 
2817836SJohn.Forte@Sun.COM 		case QL_UTIL_DUMP:
2827836SJohn.Forte@Sun.COM 			rval = ql_nv_util_dump(ha, (void *)arg, mode);
2837836SJohn.Forte@Sun.COM 			break;
2847836SJohn.Forte@Sun.COM 
2857836SJohn.Forte@Sun.COM 		case QL_ADM_OP:
2867836SJohn.Forte@Sun.COM 			rval = ql_adm_op(ha, (void *)arg, mode);
2877836SJohn.Forte@Sun.COM 			break;
2887836SJohn.Forte@Sun.COM 
2897836SJohn.Forte@Sun.COM 		default:
2907836SJohn.Forte@Sun.COM 			EL(ha, "unknown command = %d\n", cmd);
2917836SJohn.Forte@Sun.COM 			rval = ENOTTY;
2927836SJohn.Forte@Sun.COM 			break;
2937836SJohn.Forte@Sun.COM 		}
2947836SJohn.Forte@Sun.COM 	}
2957836SJohn.Forte@Sun.COM 
2967836SJohn.Forte@Sun.COM 	/* PWR management idle. */
2977836SJohn.Forte@Sun.COM 	(void) ql_idle_notification(ha);
2987836SJohn.Forte@Sun.COM 
2997836SJohn.Forte@Sun.COM 	if (rval != 0) {
300*12279SDaniel.Beauregard@Sun.COM 		/*
301*12279SDaniel.Beauregard@Sun.COM 		 * Don't show failures caused by pps polling for
302*12279SDaniel.Beauregard@Sun.COM 		 * non-existant virtual ports.
303*12279SDaniel.Beauregard@Sun.COM 		 */
304*12279SDaniel.Beauregard@Sun.COM 		if (cmd != EXT_CC_VPORT_CMD) {
305*12279SDaniel.Beauregard@Sun.COM 			EL(ha, "failed, cmd=%d rval=%d\n", cmd, rval);
306*12279SDaniel.Beauregard@Sun.COM 		}
3077836SJohn.Forte@Sun.COM 	} else {
3087836SJohn.Forte@Sun.COM 		/*EMPTY*/
3097836SJohn.Forte@Sun.COM 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3107836SJohn.Forte@Sun.COM 	}
3117836SJohn.Forte@Sun.COM 	return (rval);
3127836SJohn.Forte@Sun.COM }
3137836SJohn.Forte@Sun.COM 
3147836SJohn.Forte@Sun.COM /*
3157836SJohn.Forte@Sun.COM  * ql_busy_notification
3167836SJohn.Forte@Sun.COM  *	Adapter busy notification.
3177836SJohn.Forte@Sun.COM  *
3187836SJohn.Forte@Sun.COM  * Input:
3197836SJohn.Forte@Sun.COM  *	ha = adapter state pointer.
3207836SJohn.Forte@Sun.COM  *
3217836SJohn.Forte@Sun.COM  * Returns:
3227836SJohn.Forte@Sun.COM  *	FC_SUCCESS
3237836SJohn.Forte@Sun.COM  *	FC_FAILURE
3247836SJohn.Forte@Sun.COM  *
3257836SJohn.Forte@Sun.COM  * Context:
3267836SJohn.Forte@Sun.COM  *	Kernel context.
3277836SJohn.Forte@Sun.COM  */
3287836SJohn.Forte@Sun.COM static int
ql_busy_notification(ql_adapter_state_t * ha)3297836SJohn.Forte@Sun.COM ql_busy_notification(ql_adapter_state_t *ha)
3307836SJohn.Forte@Sun.COM {
3317836SJohn.Forte@Sun.COM 	if (!ha->pm_capable) {
3327836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
3337836SJohn.Forte@Sun.COM 	}
3347836SJohn.Forte@Sun.COM 
3357836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3367836SJohn.Forte@Sun.COM 
3377836SJohn.Forte@Sun.COM 	QL_PM_LOCK(ha);
3387836SJohn.Forte@Sun.COM 	ha->busy++;
3397836SJohn.Forte@Sun.COM 	QL_PM_UNLOCK(ha);
3407836SJohn.Forte@Sun.COM 
3417836SJohn.Forte@Sun.COM 	if (pm_busy_component(ha->dip, 0) != DDI_SUCCESS) {
3427836SJohn.Forte@Sun.COM 		QL_PM_LOCK(ha);
3437836SJohn.Forte@Sun.COM 		ha->busy--;
3447836SJohn.Forte@Sun.COM 		QL_PM_UNLOCK(ha);
3457836SJohn.Forte@Sun.COM 
3467836SJohn.Forte@Sun.COM 		EL(ha, "pm_busy_component failed = %xh\n", FC_FAILURE);
3477836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
3487836SJohn.Forte@Sun.COM 	}
3497836SJohn.Forte@Sun.COM 
3507836SJohn.Forte@Sun.COM 	QL_PM_LOCK(ha);
3517836SJohn.Forte@Sun.COM 	if (ha->power_level != PM_LEVEL_D0) {
3527836SJohn.Forte@Sun.COM 		QL_PM_UNLOCK(ha);
3537836SJohn.Forte@Sun.COM 		if (pm_raise_power(ha->dip, 0, 1) != DDI_SUCCESS) {
3547836SJohn.Forte@Sun.COM 			QL_PM_LOCK(ha);
3557836SJohn.Forte@Sun.COM 			ha->busy--;
3567836SJohn.Forte@Sun.COM 			QL_PM_UNLOCK(ha);
3577836SJohn.Forte@Sun.COM 			return (FC_FAILURE);
3587836SJohn.Forte@Sun.COM 		}
3597836SJohn.Forte@Sun.COM 	} else {
3607836SJohn.Forte@Sun.COM 		QL_PM_UNLOCK(ha);
3617836SJohn.Forte@Sun.COM 	}
3627836SJohn.Forte@Sun.COM 
3637836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
3647836SJohn.Forte@Sun.COM 
3657836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
3667836SJohn.Forte@Sun.COM }
3677836SJohn.Forte@Sun.COM 
3687836SJohn.Forte@Sun.COM /*
3697836SJohn.Forte@Sun.COM  * ql_idle_notification
3707836SJohn.Forte@Sun.COM  *	Adapter idle notification.
3717836SJohn.Forte@Sun.COM  *
3727836SJohn.Forte@Sun.COM  * Input:
3737836SJohn.Forte@Sun.COM  *	ha = adapter state pointer.
3747836SJohn.Forte@Sun.COM  *
3757836SJohn.Forte@Sun.COM  * Returns:
3767836SJohn.Forte@Sun.COM  *	FC_SUCCESS
3777836SJohn.Forte@Sun.COM  *	FC_FAILURE
3787836SJohn.Forte@Sun.COM  *
3797836SJohn.Forte@Sun.COM  * Context:
3807836SJohn.Forte@Sun.COM  *	Kernel context.
3817836SJohn.Forte@Sun.COM  */
3827836SJohn.Forte@Sun.COM static int
ql_idle_notification(ql_adapter_state_t * ha)3837836SJohn.Forte@Sun.COM ql_idle_notification(ql_adapter_state_t *ha)
3847836SJohn.Forte@Sun.COM {
3857836SJohn.Forte@Sun.COM 	if (!ha->pm_capable) {
3867836SJohn.Forte@Sun.COM 		return (FC_SUCCESS);
3877836SJohn.Forte@Sun.COM 	}
3887836SJohn.Forte@Sun.COM 
3897836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
3907836SJohn.Forte@Sun.COM 
3917836SJohn.Forte@Sun.COM 	if (pm_idle_component(ha->dip, 0) != DDI_SUCCESS) {
3927836SJohn.Forte@Sun.COM 		EL(ha, "pm_idle_component failed = %xh\n", FC_FAILURE);
3937836SJohn.Forte@Sun.COM 		return (FC_FAILURE);
3947836SJohn.Forte@Sun.COM 	}
3957836SJohn.Forte@Sun.COM 
3967836SJohn.Forte@Sun.COM 	QL_PM_LOCK(ha);
3977836SJohn.Forte@Sun.COM 	ha->busy--;
3987836SJohn.Forte@Sun.COM 	QL_PM_UNLOCK(ha);
3997836SJohn.Forte@Sun.COM 
4007836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
4017836SJohn.Forte@Sun.COM 
4027836SJohn.Forte@Sun.COM 	return (FC_SUCCESS);
4037836SJohn.Forte@Sun.COM }
4047836SJohn.Forte@Sun.COM 
4057836SJohn.Forte@Sun.COM /*
4067836SJohn.Forte@Sun.COM  * Get adapter feature bits from NVRAM
4077836SJohn.Forte@Sun.COM  */
4087836SJohn.Forte@Sun.COM static int
ql_get_feature_bits(ql_adapter_state_t * ha,uint16_t * features)4097836SJohn.Forte@Sun.COM ql_get_feature_bits(ql_adapter_state_t *ha, uint16_t *features)
4107836SJohn.Forte@Sun.COM {
4117836SJohn.Forte@Sun.COM 	int			count;
4127836SJohn.Forte@Sun.COM 	volatile uint16_t	data;
4137836SJohn.Forte@Sun.COM 	uint32_t		nv_cmd;
4147836SJohn.Forte@Sun.COM 	uint32_t		start_addr;
4157836SJohn.Forte@Sun.COM 	int			rval;
4167836SJohn.Forte@Sun.COM 	uint32_t		offset = offsetof(nvram_t, adapter_features);
4177836SJohn.Forte@Sun.COM 
4187836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
4197836SJohn.Forte@Sun.COM 
42011924SDaniel.Beauregard@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
4217836SJohn.Forte@Sun.COM 		EL(ha, "Not supported for 24xx\n");
4227836SJohn.Forte@Sun.COM 		return (EINVAL);
4237836SJohn.Forte@Sun.COM 	}
4247836SJohn.Forte@Sun.COM 
4257836SJohn.Forte@Sun.COM 	/*
4267836SJohn.Forte@Sun.COM 	 * The offset can't be greater than max of 8 bits and
4277836SJohn.Forte@Sun.COM 	 * the following code breaks if the offset isn't at
4287836SJohn.Forte@Sun.COM 	 * 2 byte boundary.
4297836SJohn.Forte@Sun.COM 	 */
4307836SJohn.Forte@Sun.COM 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
4317836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
4327836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
4337836SJohn.Forte@Sun.COM 		return (EIO);
4347836SJohn.Forte@Sun.COM 	}
4357836SJohn.Forte@Sun.COM 
4367836SJohn.Forte@Sun.COM 	/*
4377836SJohn.Forte@Sun.COM 	 * Have the most significant 3 bits represent the read operation
4387836SJohn.Forte@Sun.COM 	 * followed by the 8 bits representing the offset at which we
4397836SJohn.Forte@Sun.COM 	 * are going to perform the read operation
4407836SJohn.Forte@Sun.COM 	 */
4417836SJohn.Forte@Sun.COM 	offset >>= 1;
4427836SJohn.Forte@Sun.COM 	offset += start_addr;
4437836SJohn.Forte@Sun.COM 	nv_cmd = (offset << 16) | NV_READ_OP;
4447836SJohn.Forte@Sun.COM 	nv_cmd <<= 5;
4457836SJohn.Forte@Sun.COM 
4467836SJohn.Forte@Sun.COM 	/*
4477836SJohn.Forte@Sun.COM 	 * Select the chip and feed the command and address
4487836SJohn.Forte@Sun.COM 	 */
4497836SJohn.Forte@Sun.COM 	for (count = 0; count < 11; count++) {
4507836SJohn.Forte@Sun.COM 		if (nv_cmd & BIT_31) {
4517836SJohn.Forte@Sun.COM 			ql_nv_write(ha, NV_DATA_OUT);
4527836SJohn.Forte@Sun.COM 		} else {
4537836SJohn.Forte@Sun.COM 			ql_nv_write(ha, 0);
4547836SJohn.Forte@Sun.COM 		}
4557836SJohn.Forte@Sun.COM 		nv_cmd <<= 1;
4567836SJohn.Forte@Sun.COM 	}
4577836SJohn.Forte@Sun.COM 
4587836SJohn.Forte@Sun.COM 	*features = 0;
4597836SJohn.Forte@Sun.COM 	for (count = 0; count < 16; count++) {
4607836SJohn.Forte@Sun.COM 		WRT16_IO_REG(ha, nvram, NV_SELECT | NV_CLOCK);
4617836SJohn.Forte@Sun.COM 		ql_nv_delay();
4627836SJohn.Forte@Sun.COM 
4637836SJohn.Forte@Sun.COM 		data = RD16_IO_REG(ha, nvram);
4647836SJohn.Forte@Sun.COM 		*features <<= 1;
4657836SJohn.Forte@Sun.COM 		if (data & NV_DATA_IN) {
4667836SJohn.Forte@Sun.COM 			*features = (uint16_t)(*features | 0x1);
4677836SJohn.Forte@Sun.COM 		}
4687836SJohn.Forte@Sun.COM 
4697836SJohn.Forte@Sun.COM 		WRT16_IO_REG(ha, nvram, NV_SELECT);
4707836SJohn.Forte@Sun.COM 		ql_nv_delay();
4717836SJohn.Forte@Sun.COM 	}
4727836SJohn.Forte@Sun.COM 
4737836SJohn.Forte@Sun.COM 	/*
4747836SJohn.Forte@Sun.COM 	 * Deselect the chip
4757836SJohn.Forte@Sun.COM 	 */
4767836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
4777836SJohn.Forte@Sun.COM 
4787836SJohn.Forte@Sun.COM 	ql_release_nvram(ha);
4797836SJohn.Forte@Sun.COM 
4807836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
4817836SJohn.Forte@Sun.COM 
4827836SJohn.Forte@Sun.COM 	return (0);
4837836SJohn.Forte@Sun.COM }
4847836SJohn.Forte@Sun.COM 
4857836SJohn.Forte@Sun.COM /*
4867836SJohn.Forte@Sun.COM  * Set adapter feature bits in NVRAM
4877836SJohn.Forte@Sun.COM  */
4887836SJohn.Forte@Sun.COM static int
ql_set_feature_bits(ql_adapter_state_t * ha,uint16_t features)4897836SJohn.Forte@Sun.COM ql_set_feature_bits(ql_adapter_state_t *ha, uint16_t features)
4907836SJohn.Forte@Sun.COM {
4917836SJohn.Forte@Sun.COM 	int		rval;
4927836SJohn.Forte@Sun.COM 	uint32_t	count;
4937836SJohn.Forte@Sun.COM 	nvram_t		*nv;
4947836SJohn.Forte@Sun.COM 	uint16_t	*wptr;
4957836SJohn.Forte@Sun.COM 	uint8_t		*bptr;
4967836SJohn.Forte@Sun.COM 	uint8_t		csum;
4977836SJohn.Forte@Sun.COM 	uint32_t	start_addr;
4987836SJohn.Forte@Sun.COM 
4997836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
5007836SJohn.Forte@Sun.COM 
50111924SDaniel.Beauregard@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
5027836SJohn.Forte@Sun.COM 		EL(ha, "Not supported for 24xx\n");
5037836SJohn.Forte@Sun.COM 		return (EINVAL);
5047836SJohn.Forte@Sun.COM 	}
5057836SJohn.Forte@Sun.COM 
5067836SJohn.Forte@Sun.COM 	nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
5077836SJohn.Forte@Sun.COM 	if (nv == NULL) {
5087836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
5097836SJohn.Forte@Sun.COM 		return (ENOMEM);
5107836SJohn.Forte@Sun.COM 	}
5117836SJohn.Forte@Sun.COM 
5127836SJohn.Forte@Sun.COM 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
5137836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
5147836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
5157836SJohn.Forte@Sun.COM 		kmem_free(nv, sizeof (*nv));
5167836SJohn.Forte@Sun.COM 		return (EIO);
5177836SJohn.Forte@Sun.COM 	}
5187836SJohn.Forte@Sun.COM 	rval = 0;
5197836SJohn.Forte@Sun.COM 
5207836SJohn.Forte@Sun.COM 	/*
5217836SJohn.Forte@Sun.COM 	 * Read off the whole NVRAM
5227836SJohn.Forte@Sun.COM 	 */
5237836SJohn.Forte@Sun.COM 	wptr = (uint16_t *)nv;
5247836SJohn.Forte@Sun.COM 	csum = 0;
5257836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
5267836SJohn.Forte@Sun.COM 		*wptr = (uint16_t)ql_get_nvram_word(ha, count + start_addr);
5277836SJohn.Forte@Sun.COM 		csum = (uint8_t)(csum + (uint8_t)*wptr);
5287836SJohn.Forte@Sun.COM 		csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
5297836SJohn.Forte@Sun.COM 		wptr++;
5307836SJohn.Forte@Sun.COM 	}
5317836SJohn.Forte@Sun.COM 
5327836SJohn.Forte@Sun.COM 	/*
5337836SJohn.Forte@Sun.COM 	 * If the checksum is BAD then fail it right here.
5347836SJohn.Forte@Sun.COM 	 */
5357836SJohn.Forte@Sun.COM 	if (csum) {
5367836SJohn.Forte@Sun.COM 		kmem_free(nv, sizeof (*nv));
5377836SJohn.Forte@Sun.COM 		ql_release_nvram(ha);
5387836SJohn.Forte@Sun.COM 		return (EBADF);
5397836SJohn.Forte@Sun.COM 	}
5407836SJohn.Forte@Sun.COM 
5417836SJohn.Forte@Sun.COM 	nv->adapter_features[0] = (uint8_t)((features & 0xFF00) >> 8);
5427836SJohn.Forte@Sun.COM 	nv->adapter_features[1] = (uint8_t)(features & 0xFF);
5437836SJohn.Forte@Sun.COM 
5447836SJohn.Forte@Sun.COM 	/*
5457836SJohn.Forte@Sun.COM 	 * Recompute the chesksum now
5467836SJohn.Forte@Sun.COM 	 */
5477836SJohn.Forte@Sun.COM 	bptr = (uint8_t *)nv;
5487836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (nvram_t) - 1; count++) {
5497836SJohn.Forte@Sun.COM 		csum = (uint8_t)(csum + *bptr++);
5507836SJohn.Forte@Sun.COM 	}
5517836SJohn.Forte@Sun.COM 	csum = (uint8_t)(~csum + 1);
5527836SJohn.Forte@Sun.COM 	nv->checksum = csum;
5537836SJohn.Forte@Sun.COM 
5547836SJohn.Forte@Sun.COM 	/*
5557836SJohn.Forte@Sun.COM 	 * Now load the NVRAM
5567836SJohn.Forte@Sun.COM 	 */
5577836SJohn.Forte@Sun.COM 	wptr = (uint16_t *)nv;
5587836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
5597836SJohn.Forte@Sun.COM 		ql_load_nvram(ha, (uint8_t)(count + start_addr), *wptr++);
5607836SJohn.Forte@Sun.COM 	}
5617836SJohn.Forte@Sun.COM 
5627836SJohn.Forte@Sun.COM 	/*
5637836SJohn.Forte@Sun.COM 	 * Read NVRAM and verify the contents
5647836SJohn.Forte@Sun.COM 	 */
5657836SJohn.Forte@Sun.COM 	wptr = (uint16_t *)nv;
5667836SJohn.Forte@Sun.COM 	csum = 0;
5677836SJohn.Forte@Sun.COM 	for (count = 0; count < sizeof (nvram_t) / 2; count++) {
5687836SJohn.Forte@Sun.COM 		if (ql_get_nvram_word(ha, count + start_addr) != *wptr) {
5697836SJohn.Forte@Sun.COM 			rval = EIO;
5707836SJohn.Forte@Sun.COM 			break;
5717836SJohn.Forte@Sun.COM 		}
5727836SJohn.Forte@Sun.COM 		csum = (uint8_t)(csum + (uint8_t)*wptr);
5737836SJohn.Forte@Sun.COM 		csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
5747836SJohn.Forte@Sun.COM 		wptr++;
5757836SJohn.Forte@Sun.COM 	}
5767836SJohn.Forte@Sun.COM 
5777836SJohn.Forte@Sun.COM 	if (csum) {
5787836SJohn.Forte@Sun.COM 		rval = EINVAL;
5797836SJohn.Forte@Sun.COM 	}
5807836SJohn.Forte@Sun.COM 
5817836SJohn.Forte@Sun.COM 	kmem_free(nv, sizeof (*nv));
5827836SJohn.Forte@Sun.COM 	ql_release_nvram(ha);
5837836SJohn.Forte@Sun.COM 
5847836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
5857836SJohn.Forte@Sun.COM 
5867836SJohn.Forte@Sun.COM 	return (rval);
5877836SJohn.Forte@Sun.COM }
5887836SJohn.Forte@Sun.COM 
5897836SJohn.Forte@Sun.COM /*
5907836SJohn.Forte@Sun.COM  * Fix this function to update just feature bits and checksum in NVRAM
5917836SJohn.Forte@Sun.COM  */
5927836SJohn.Forte@Sun.COM static int
ql_set_nvram_adapter_defaults(ql_adapter_state_t * ha)5937836SJohn.Forte@Sun.COM ql_set_nvram_adapter_defaults(ql_adapter_state_t *ha)
5947836SJohn.Forte@Sun.COM {
5957836SJohn.Forte@Sun.COM 	int		rval;
5967836SJohn.Forte@Sun.COM 	uint32_t	count;
5977836SJohn.Forte@Sun.COM 	uint32_t	start_addr;
5987836SJohn.Forte@Sun.COM 
5997836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
6007836SJohn.Forte@Sun.COM 
6017836SJohn.Forte@Sun.COM 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
6027836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
6037836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
6047836SJohn.Forte@Sun.COM 		return (EIO);
6057836SJohn.Forte@Sun.COM 	}
6067836SJohn.Forte@Sun.COM 	rval = 0;
6077836SJohn.Forte@Sun.COM 
60811924SDaniel.Beauregard@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
6097836SJohn.Forte@Sun.COM 		nvram_24xx_t	*nv;
6107836SJohn.Forte@Sun.COM 		uint32_t	*longptr;
6117836SJohn.Forte@Sun.COM 		uint32_t	csum = 0;
6127836SJohn.Forte@Sun.COM 
6137836SJohn.Forte@Sun.COM 		nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
6147836SJohn.Forte@Sun.COM 		if (nv == NULL) {
6157836SJohn.Forte@Sun.COM 			EL(ha, "failed, kmem_zalloc\n");
6167836SJohn.Forte@Sun.COM 			return (ENOMEM);
6177836SJohn.Forte@Sun.COM 		}
6187836SJohn.Forte@Sun.COM 
6197836SJohn.Forte@Sun.COM 		nv->nvram_version[0] = LSB(ICB_24XX_VERSION);
6207836SJohn.Forte@Sun.COM 		nv->nvram_version[1] = MSB(ICB_24XX_VERSION);
6217836SJohn.Forte@Sun.COM 
6227836SJohn.Forte@Sun.COM 		nv->version[0] = 1;
6237836SJohn.Forte@Sun.COM 		nv->max_frame_length[1] = 8;
6247836SJohn.Forte@Sun.COM 		nv->execution_throttle[0] = 16;
6257836SJohn.Forte@Sun.COM 		nv->login_retry_count[0] = 8;
6267836SJohn.Forte@Sun.COM 
6277836SJohn.Forte@Sun.COM 		nv->firmware_options_1[0] = BIT_2 | BIT_1;
6287836SJohn.Forte@Sun.COM 		nv->firmware_options_1[1] = BIT_5;
6297836SJohn.Forte@Sun.COM 		nv->firmware_options_2[0] = BIT_5;
6307836SJohn.Forte@Sun.COM 		nv->firmware_options_2[1] = BIT_4;
6317836SJohn.Forte@Sun.COM 		nv->firmware_options_3[1] = BIT_6;
6327836SJohn.Forte@Sun.COM 
6337836SJohn.Forte@Sun.COM 		/*
6347836SJohn.Forte@Sun.COM 		 * Set default host adapter parameters
6357836SJohn.Forte@Sun.COM 		 */
6367836SJohn.Forte@Sun.COM 		nv->host_p[0] = BIT_4 | BIT_1;
6377836SJohn.Forte@Sun.COM 		nv->host_p[1] = BIT_3 | BIT_2;
6387836SJohn.Forte@Sun.COM 		nv->reset_delay = 5;
6397836SJohn.Forte@Sun.COM 		nv->max_luns_per_target[0] = 128;
6407836SJohn.Forte@Sun.COM 		nv->port_down_retry_count[0] = 30;
6417836SJohn.Forte@Sun.COM 		nv->link_down_timeout[0] = 30;
6427836SJohn.Forte@Sun.COM 
6437836SJohn.Forte@Sun.COM 		/*
6447836SJohn.Forte@Sun.COM 		 * compute the chesksum now
6457836SJohn.Forte@Sun.COM 		 */
6467836SJohn.Forte@Sun.COM 		longptr = (uint32_t *)nv;
6477836SJohn.Forte@Sun.COM 		csum = 0;
6487836SJohn.Forte@Sun.COM 		for (count = 0; count < (sizeof (nvram_24xx_t)/4)-1; count++) {
6497836SJohn.Forte@Sun.COM 			csum += *longptr;
6507836SJohn.Forte@Sun.COM 			longptr++;
6517836SJohn.Forte@Sun.COM 		}
6527836SJohn.Forte@Sun.COM 		csum = (uint32_t)(~csum + 1);
6537836SJohn.Forte@Sun.COM 		LITTLE_ENDIAN_32((long)csum);
6547836SJohn.Forte@Sun.COM 		*longptr = csum;
6557836SJohn.Forte@Sun.COM 
6567836SJohn.Forte@Sun.COM 		/*
6577836SJohn.Forte@Sun.COM 		 * Now load the NVRAM
6587836SJohn.Forte@Sun.COM 		 */
6597836SJohn.Forte@Sun.COM 		longptr = (uint32_t *)nv;
6607836SJohn.Forte@Sun.COM 		for (count = 0; count < sizeof (nvram_24xx_t) / 4; count++) {
6617836SJohn.Forte@Sun.COM 			(void) ql_24xx_load_nvram(ha,
6627836SJohn.Forte@Sun.COM 			    (uint32_t)(count + start_addr), *longptr++);
6637836SJohn.Forte@Sun.COM 		}
6647836SJohn.Forte@Sun.COM 
6657836SJohn.Forte@Sun.COM 		/*
6667836SJohn.Forte@Sun.COM 		 * Read NVRAM and verify the contents
6677836SJohn.Forte@Sun.COM 		 */
6687836SJohn.Forte@Sun.COM 		csum = 0;
6697836SJohn.Forte@Sun.COM 		longptr = (uint32_t *)nv;
6707836SJohn.Forte@Sun.COM 		for (count = 0; count < sizeof (nvram_24xx_t) / 4; count++) {
6717836SJohn.Forte@Sun.COM 			rval = ql_24xx_read_flash(ha, count + start_addr,
6727836SJohn.Forte@Sun.COM 			    longptr);
6737836SJohn.Forte@Sun.COM 			if (rval != QL_SUCCESS) {
6747836SJohn.Forte@Sun.COM 				EL(ha, "24xx_read_flash failed=%xh\n", rval);
6757836SJohn.Forte@Sun.COM 				break;
6767836SJohn.Forte@Sun.COM 			}
6777836SJohn.Forte@Sun.COM 			csum += *longptr;
6787836SJohn.Forte@Sun.COM 		}
6797836SJohn.Forte@Sun.COM 
6807836SJohn.Forte@Sun.COM 		if (csum) {
6817836SJohn.Forte@Sun.COM 			rval = EINVAL;
6827836SJohn.Forte@Sun.COM 		}
6837836SJohn.Forte@Sun.COM 		kmem_free(nv, sizeof (nvram_24xx_t));
6847836SJohn.Forte@Sun.COM 	} else {
6857836SJohn.Forte@Sun.COM 		nvram_t		*nv;
6867836SJohn.Forte@Sun.COM 		uint16_t	*wptr;
6877836SJohn.Forte@Sun.COM 		uint8_t		*bptr;
6887836SJohn.Forte@Sun.COM 		uint8_t		csum;
6897836SJohn.Forte@Sun.COM 
6907836SJohn.Forte@Sun.COM 		nv = kmem_zalloc(sizeof (*nv), KM_SLEEP);
6917836SJohn.Forte@Sun.COM 		if (nv == NULL) {
6927836SJohn.Forte@Sun.COM 			EL(ha, "failed, kmem_zalloc\n");
6937836SJohn.Forte@Sun.COM 			return (ENOMEM);
6947836SJohn.Forte@Sun.COM 		}
6957836SJohn.Forte@Sun.COM 		/*
6967836SJohn.Forte@Sun.COM 		 * Set default initialization control block.
6977836SJohn.Forte@Sun.COM 		 */
6987836SJohn.Forte@Sun.COM 		nv->parameter_block_version = ICB_VERSION;
6997836SJohn.Forte@Sun.COM 		nv->firmware_options[0] = BIT_4 | BIT_3 | BIT_2 | BIT_1;
7007836SJohn.Forte@Sun.COM 		nv->firmware_options[1] = BIT_7 | BIT_5 | BIT_2;
7017836SJohn.Forte@Sun.COM 
7027836SJohn.Forte@Sun.COM 		nv->max_frame_length[1] = 4;
7037836SJohn.Forte@Sun.COM 		nv->max_iocb_allocation[1] = 1;
7047836SJohn.Forte@Sun.COM 		nv->execution_throttle[0] = 16;
7057836SJohn.Forte@Sun.COM 		nv->login_retry_count = 8;
7067836SJohn.Forte@Sun.COM 		nv->port_name[0] = 33;
7077836SJohn.Forte@Sun.COM 		nv->port_name[3] = 224;
7087836SJohn.Forte@Sun.COM 		nv->port_name[4] = 139;
7097836SJohn.Forte@Sun.COM 		nv->login_timeout = 4;
7107836SJohn.Forte@Sun.COM 
7117836SJohn.Forte@Sun.COM 		/*
7127836SJohn.Forte@Sun.COM 		 * Set default host adapter parameters
7137836SJohn.Forte@Sun.COM 		 */
7147836SJohn.Forte@Sun.COM 		nv->host_p[0] = BIT_1;
7157836SJohn.Forte@Sun.COM 		nv->host_p[1] = BIT_2;
7167836SJohn.Forte@Sun.COM 		nv->reset_delay = 5;
7177836SJohn.Forte@Sun.COM 		nv->port_down_retry_count = 8;
7187836SJohn.Forte@Sun.COM 		nv->maximum_luns_per_target[0] = 8;
7197836SJohn.Forte@Sun.COM 
7207836SJohn.Forte@Sun.COM 		/*
7217836SJohn.Forte@Sun.COM 		 * compute the chesksum now
7227836SJohn.Forte@Sun.COM 		 */
7237836SJohn.Forte@Sun.COM 		bptr = (uint8_t *)nv;
7247836SJohn.Forte@Sun.COM 		csum = 0;
7257836SJohn.Forte@Sun.COM 		for (count = 0; count < sizeof (nvram_t) - 1; count++) {
7267836SJohn.Forte@Sun.COM 			csum = (uint8_t)(csum + *bptr++);
7277836SJohn.Forte@Sun.COM 		}
7287836SJohn.Forte@Sun.COM 		csum = (uint8_t)(~csum + 1);
7297836SJohn.Forte@Sun.COM 		nv->checksum = csum;
7307836SJohn.Forte@Sun.COM 
7317836SJohn.Forte@Sun.COM 		/*
7327836SJohn.Forte@Sun.COM 		 * Now load the NVRAM
7337836SJohn.Forte@Sun.COM 		 */
7347836SJohn.Forte@Sun.COM 		wptr = (uint16_t *)nv;
7357836SJohn.Forte@Sun.COM 		for (count = 0; count < sizeof (nvram_t) / 2; count++) {
7367836SJohn.Forte@Sun.COM 			ql_load_nvram(ha, (uint8_t)(count + start_addr),
7377836SJohn.Forte@Sun.COM 			    *wptr++);
7387836SJohn.Forte@Sun.COM 		}
7397836SJohn.Forte@Sun.COM 
7407836SJohn.Forte@Sun.COM 		/*
7417836SJohn.Forte@Sun.COM 		 * Read NVRAM and verify the contents
7427836SJohn.Forte@Sun.COM 		 */
7437836SJohn.Forte@Sun.COM 		wptr = (uint16_t *)nv;
7447836SJohn.Forte@Sun.COM 		csum = 0;
7457836SJohn.Forte@Sun.COM 		for (count = 0; count < sizeof (nvram_t) / 2; count++) {
7467836SJohn.Forte@Sun.COM 			if (ql_get_nvram_word(ha, count + start_addr) !=
7477836SJohn.Forte@Sun.COM 			    *wptr) {
7487836SJohn.Forte@Sun.COM 				rval = EIO;
7497836SJohn.Forte@Sun.COM 				break;
7507836SJohn.Forte@Sun.COM 			}
7517836SJohn.Forte@Sun.COM 			csum = (uint8_t)(csum + (uint8_t)*wptr);
7527836SJohn.Forte@Sun.COM 			csum = (uint8_t)(csum + (uint8_t)(*wptr >> 8));
7537836SJohn.Forte@Sun.COM 			wptr++;
7547836SJohn.Forte@Sun.COM 		}
7557836SJohn.Forte@Sun.COM 		if (csum) {
7567836SJohn.Forte@Sun.COM 			rval = EINVAL;
7577836SJohn.Forte@Sun.COM 		}
7587836SJohn.Forte@Sun.COM 		kmem_free(nv, sizeof (*nv));
7597836SJohn.Forte@Sun.COM 	}
7607836SJohn.Forte@Sun.COM 	ql_release_nvram(ha);
7617836SJohn.Forte@Sun.COM 
7627836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
7637836SJohn.Forte@Sun.COM 
7647836SJohn.Forte@Sun.COM 	return (rval);
7657836SJohn.Forte@Sun.COM }
7667836SJohn.Forte@Sun.COM 
7677836SJohn.Forte@Sun.COM static void
ql_load_nvram(ql_adapter_state_t * ha,uint8_t addr,uint16_t value)7687836SJohn.Forte@Sun.COM ql_load_nvram(ql_adapter_state_t *ha, uint8_t addr, uint16_t value)
7697836SJohn.Forte@Sun.COM {
7707836SJohn.Forte@Sun.COM 	int			count;
7717836SJohn.Forte@Sun.COM 	volatile uint16_t	word;
7727836SJohn.Forte@Sun.COM 	volatile uint32_t	nv_cmd;
7737836SJohn.Forte@Sun.COM 
7747836SJohn.Forte@Sun.COM 	ql_nv_write(ha, NV_DATA_OUT);
7757836SJohn.Forte@Sun.COM 	ql_nv_write(ha, 0);
7767836SJohn.Forte@Sun.COM 	ql_nv_write(ha, 0);
7777836SJohn.Forte@Sun.COM 
7787836SJohn.Forte@Sun.COM 	for (word = 0; word < 8; word++) {
7797836SJohn.Forte@Sun.COM 		ql_nv_write(ha, NV_DATA_OUT);
7807836SJohn.Forte@Sun.COM 	}
7817836SJohn.Forte@Sun.COM 
7827836SJohn.Forte@Sun.COM 	/*
7837836SJohn.Forte@Sun.COM 	 * Deselect the chip
7847836SJohn.Forte@Sun.COM 	 */
7857836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
7867836SJohn.Forte@Sun.COM 	ql_nv_delay();
7877836SJohn.Forte@Sun.COM 
7887836SJohn.Forte@Sun.COM 	/*
7897836SJohn.Forte@Sun.COM 	 * Erase Location
7907836SJohn.Forte@Sun.COM 	 */
7917836SJohn.Forte@Sun.COM 	nv_cmd = (addr << 16) | NV_ERASE_OP;
7927836SJohn.Forte@Sun.COM 	nv_cmd <<= 5;
7937836SJohn.Forte@Sun.COM 	for (count = 0; count < 11; count++) {
7947836SJohn.Forte@Sun.COM 		if (nv_cmd & BIT_31) {
7957836SJohn.Forte@Sun.COM 			ql_nv_write(ha, NV_DATA_OUT);
7967836SJohn.Forte@Sun.COM 		} else {
7977836SJohn.Forte@Sun.COM 			ql_nv_write(ha, 0);
7987836SJohn.Forte@Sun.COM 		}
7997836SJohn.Forte@Sun.COM 		nv_cmd <<= 1;
8007836SJohn.Forte@Sun.COM 	}
8017836SJohn.Forte@Sun.COM 
8027836SJohn.Forte@Sun.COM 	/*
8037836SJohn.Forte@Sun.COM 	 * Wait for Erase to Finish
8047836SJohn.Forte@Sun.COM 	 */
8057836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
8067836SJohn.Forte@Sun.COM 	ql_nv_delay();
8077836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_SELECT);
8087836SJohn.Forte@Sun.COM 	word = 0;
8097836SJohn.Forte@Sun.COM 	while ((word & NV_DATA_IN) == 0) {
8107836SJohn.Forte@Sun.COM 		ql_nv_delay();
8117836SJohn.Forte@Sun.COM 		word = RD16_IO_REG(ha, nvram);
8127836SJohn.Forte@Sun.COM 	}
8137836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
8147836SJohn.Forte@Sun.COM 	ql_nv_delay();
8157836SJohn.Forte@Sun.COM 
8167836SJohn.Forte@Sun.COM 	/*
8177836SJohn.Forte@Sun.COM 	 * Write data now
8187836SJohn.Forte@Sun.COM 	 */
8197836SJohn.Forte@Sun.COM 	nv_cmd = (addr << 16) | NV_WRITE_OP;
8207836SJohn.Forte@Sun.COM 	nv_cmd |= value;
8217836SJohn.Forte@Sun.COM 	nv_cmd <<= 5;
8227836SJohn.Forte@Sun.COM 	for (count = 0; count < 27; count++) {
8237836SJohn.Forte@Sun.COM 		if (nv_cmd & BIT_31) {
8247836SJohn.Forte@Sun.COM 			ql_nv_write(ha, NV_DATA_OUT);
8257836SJohn.Forte@Sun.COM 		} else {
8267836SJohn.Forte@Sun.COM 			ql_nv_write(ha, 0);
8277836SJohn.Forte@Sun.COM 		}
8287836SJohn.Forte@Sun.COM 		nv_cmd <<= 1;
8297836SJohn.Forte@Sun.COM 	}
8307836SJohn.Forte@Sun.COM 
8317836SJohn.Forte@Sun.COM 	/*
8327836SJohn.Forte@Sun.COM 	 * Wait for NVRAM to become ready
8337836SJohn.Forte@Sun.COM 	 */
8347836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
8357836SJohn.Forte@Sun.COM 	ql_nv_delay();
8367836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_SELECT);
8377836SJohn.Forte@Sun.COM 	word = 0;
8387836SJohn.Forte@Sun.COM 	while ((word & NV_DATA_IN) == 0) {
8397836SJohn.Forte@Sun.COM 		ql_nv_delay();
8407836SJohn.Forte@Sun.COM 		word = RD16_IO_REG(ha, nvram);
8417836SJohn.Forte@Sun.COM 	}
8427836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
8437836SJohn.Forte@Sun.COM 	ql_nv_delay();
8447836SJohn.Forte@Sun.COM 
8457836SJohn.Forte@Sun.COM 	/*
8467836SJohn.Forte@Sun.COM 	 * Disable writes
8477836SJohn.Forte@Sun.COM 	 */
8487836SJohn.Forte@Sun.COM 	ql_nv_write(ha, NV_DATA_OUT);
8497836SJohn.Forte@Sun.COM 	for (count = 0; count < 10; count++) {
8507836SJohn.Forte@Sun.COM 		ql_nv_write(ha, 0);
8517836SJohn.Forte@Sun.COM 	}
8527836SJohn.Forte@Sun.COM 
8537836SJohn.Forte@Sun.COM 	/*
8547836SJohn.Forte@Sun.COM 	 * Deselect the chip now
8557836SJohn.Forte@Sun.COM 	 */
8567836SJohn.Forte@Sun.COM 	WRT16_IO_REG(ha, nvram, NV_DESELECT);
8577836SJohn.Forte@Sun.COM }
8587836SJohn.Forte@Sun.COM 
8597836SJohn.Forte@Sun.COM /*
8607836SJohn.Forte@Sun.COM  * ql_24xx_load_nvram
8617836SJohn.Forte@Sun.COM  *	Enable NVRAM and writes a 32bit word to ISP24xx NVRAM.
8627836SJohn.Forte@Sun.COM  *
8637836SJohn.Forte@Sun.COM  * Input:
8647836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
8657836SJohn.Forte@Sun.COM  *	addr:	NVRAM address.
8667836SJohn.Forte@Sun.COM  *	value:	data.
8677836SJohn.Forte@Sun.COM  *
8687836SJohn.Forte@Sun.COM  * Returns:
8697836SJohn.Forte@Sun.COM  *	ql local function return status code.
8707836SJohn.Forte@Sun.COM  *
8717836SJohn.Forte@Sun.COM  * Context:
8727836SJohn.Forte@Sun.COM  *	Kernel context.
8737836SJohn.Forte@Sun.COM  */
8747836SJohn.Forte@Sun.COM static int
ql_24xx_load_nvram(ql_adapter_state_t * ha,uint32_t addr,uint32_t value)8757836SJohn.Forte@Sun.COM ql_24xx_load_nvram(ql_adapter_state_t *ha, uint32_t addr, uint32_t value)
8767836SJohn.Forte@Sun.COM {
8777836SJohn.Forte@Sun.COM 	int	rval;
8787836SJohn.Forte@Sun.COM 
8797836SJohn.Forte@Sun.COM 	/* Enable flash write. */
88011924SDaniel.Beauregard@Sun.COM 	if (!(CFG_IST(ha, CFG_CTRL_8081))) {
8819446SDaniel.Beauregard@Sun.COM 		WRT32_IO_REG(ha, ctrl_status,
8829446SDaniel.Beauregard@Sun.COM 		    RD32_IO_REG(ha, ctrl_status) | ISP_FLASH_ENABLE);
8839446SDaniel.Beauregard@Sun.COM 		RD32_IO_REG(ha, ctrl_status);	/* PCI Posting. */
8849446SDaniel.Beauregard@Sun.COM 	}
8857836SJohn.Forte@Sun.COM 
8867836SJohn.Forte@Sun.COM 	/* Disable NVRAM write-protection. */
8877836SJohn.Forte@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_2422)) {
8887836SJohn.Forte@Sun.COM 		(void) ql_24xx_write_flash(ha, NVRAM_CONF_ADDR | 0x101, 0);
8897836SJohn.Forte@Sun.COM 	} else {
8909446SDaniel.Beauregard@Sun.COM 		if ((rval = ql_24xx_unprotect_flash(ha)) != QL_SUCCESS) {
8919446SDaniel.Beauregard@Sun.COM 			EL(ha, "unprotect_flash failed, rval=%xh\n", rval);
8929446SDaniel.Beauregard@Sun.COM 			return (rval);
8939446SDaniel.Beauregard@Sun.COM 		}
8947836SJohn.Forte@Sun.COM 	}
8957836SJohn.Forte@Sun.COM 
8967836SJohn.Forte@Sun.COM 	/* Write to flash. */
8977836SJohn.Forte@Sun.COM 	rval = ql_24xx_write_flash(ha, addr, value);
8987836SJohn.Forte@Sun.COM 
8997836SJohn.Forte@Sun.COM 	/* Enable NVRAM write-protection. */
9007836SJohn.Forte@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_2422)) {
9017836SJohn.Forte@Sun.COM 		/* TODO: Check if 0x8c is correct -- sb: 0x9c ? */
9027836SJohn.Forte@Sun.COM 		(void) ql_24xx_write_flash(ha, NVRAM_CONF_ADDR | 0x101, 0x8c);
9037836SJohn.Forte@Sun.COM 	} else {
9047836SJohn.Forte@Sun.COM 		ql_24xx_protect_flash(ha);
9057836SJohn.Forte@Sun.COM 	}
9067836SJohn.Forte@Sun.COM 
9077836SJohn.Forte@Sun.COM 	/* Disable flash write. */
9089446SDaniel.Beauregard@Sun.COM 	if (!(CFG_IST(ha, CFG_CTRL_81XX))) {
9099446SDaniel.Beauregard@Sun.COM 		WRT32_IO_REG(ha, ctrl_status,
9109446SDaniel.Beauregard@Sun.COM 		    RD32_IO_REG(ha, ctrl_status) & ~ISP_FLASH_ENABLE);
9119446SDaniel.Beauregard@Sun.COM 		RD32_IO_REG(ha, ctrl_status);	/* PCI Posting. */
9129446SDaniel.Beauregard@Sun.COM 	}
9137836SJohn.Forte@Sun.COM 
9147836SJohn.Forte@Sun.COM 	return (rval);
9157836SJohn.Forte@Sun.COM }
9167836SJohn.Forte@Sun.COM 
9177836SJohn.Forte@Sun.COM /*
9187836SJohn.Forte@Sun.COM  * ql_nv_util_load
9197836SJohn.Forte@Sun.COM  *	Loads NVRAM from application.
9207836SJohn.Forte@Sun.COM  *
9217836SJohn.Forte@Sun.COM  * Input:
9227836SJohn.Forte@Sun.COM  *	ha = adapter state pointer.
9237836SJohn.Forte@Sun.COM  *	bp = user buffer address.
9247836SJohn.Forte@Sun.COM  *
9257836SJohn.Forte@Sun.COM  * Returns:
9267836SJohn.Forte@Sun.COM  *
9277836SJohn.Forte@Sun.COM  * Context:
9287836SJohn.Forte@Sun.COM  *	Kernel context.
9297836SJohn.Forte@Sun.COM  */
9307836SJohn.Forte@Sun.COM int
ql_nv_util_load(ql_adapter_state_t * ha,void * bp,int mode)9317836SJohn.Forte@Sun.COM ql_nv_util_load(ql_adapter_state_t *ha, void *bp, int mode)
9327836SJohn.Forte@Sun.COM {
9337836SJohn.Forte@Sun.COM 	uint8_t		cnt;
9347836SJohn.Forte@Sun.COM 	void		*nv;
9357836SJohn.Forte@Sun.COM 	uint16_t	*wptr;
9367836SJohn.Forte@Sun.COM 	uint16_t	data;
93711541SDaniel.Beauregard@Sun.COM 	uint32_t	start_addr, *lptr, data32;
9387836SJohn.Forte@Sun.COM 	nvram_t		*nptr;
9397836SJohn.Forte@Sun.COM 	int		rval;
9407836SJohn.Forte@Sun.COM 
9417836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
9427836SJohn.Forte@Sun.COM 
94311541SDaniel.Beauregard@Sun.COM 	if ((nv = kmem_zalloc(ha->nvram_cache->size, KM_SLEEP)) == NULL) {
9447836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
9457836SJohn.Forte@Sun.COM 		return (ENOMEM);
9467836SJohn.Forte@Sun.COM 	}
9477836SJohn.Forte@Sun.COM 
94811541SDaniel.Beauregard@Sun.COM 	if (ddi_copyin(bp, nv, ha->nvram_cache->size, mode) != 0) {
9497836SJohn.Forte@Sun.COM 		EL(ha, "Buffer copy failed\n");
95011541SDaniel.Beauregard@Sun.COM 		kmem_free(nv, ha->nvram_cache->size);
9517836SJohn.Forte@Sun.COM 		return (EFAULT);
9527836SJohn.Forte@Sun.COM 	}
9537836SJohn.Forte@Sun.COM 
9547836SJohn.Forte@Sun.COM 	/* See if the buffer passed to us looks sane */
9557836SJohn.Forte@Sun.COM 	nptr = (nvram_t *)nv;
9567836SJohn.Forte@Sun.COM 	if (nptr->id[0] != 'I' || nptr->id[1] != 'S' || nptr->id[2] != 'P' ||
9577836SJohn.Forte@Sun.COM 	    nptr->id[3] != ' ') {
9587836SJohn.Forte@Sun.COM 		EL(ha, "failed, buffer sanity check\n");
95911541SDaniel.Beauregard@Sun.COM 		kmem_free(nv, ha->nvram_cache->size);
9607836SJohn.Forte@Sun.COM 		return (EINVAL);
9617836SJohn.Forte@Sun.COM 	}
9627836SJohn.Forte@Sun.COM 
9637836SJohn.Forte@Sun.COM 	/* Quiesce I/O */
9647836SJohn.Forte@Sun.COM 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
9657836SJohn.Forte@Sun.COM 		EL(ha, "ql_stall_driver failed\n");
96611541SDaniel.Beauregard@Sun.COM 		kmem_free(nv, ha->nvram_cache->size);
9677836SJohn.Forte@Sun.COM 		return (EBUSY);
9687836SJohn.Forte@Sun.COM 	}
9697836SJohn.Forte@Sun.COM 
9707836SJohn.Forte@Sun.COM 	rval = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
9717836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
9727836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
97311541SDaniel.Beauregard@Sun.COM 		kmem_free(nv, ha->nvram_cache->size);
9747836SJohn.Forte@Sun.COM 		ql_restart_driver(ha);
9757836SJohn.Forte@Sun.COM 		return (EIO);
9767836SJohn.Forte@Sun.COM 	}
9777836SJohn.Forte@Sun.COM 
9787836SJohn.Forte@Sun.COM 	/* Load NVRAM. */
97911924SDaniel.Beauregard@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_258081)) {
9807836SJohn.Forte@Sun.COM 		GLOBAL_HW_UNLOCK();
9819446SDaniel.Beauregard@Sun.COM 		start_addr &= ~ha->flash_data_addr;
9829446SDaniel.Beauregard@Sun.COM 		start_addr <<= 2;
98311541SDaniel.Beauregard@Sun.COM 		if ((rval = ql_r_m_w_flash(ha, bp, ha->nvram_cache->size,
98411541SDaniel.Beauregard@Sun.COM 		    start_addr, mode)) != QL_SUCCESS) {
9857836SJohn.Forte@Sun.COM 			EL(ha, "nvram load failed, rval = %0xh\n", rval);
9867836SJohn.Forte@Sun.COM 		}
9877836SJohn.Forte@Sun.COM 		GLOBAL_HW_LOCK();
9887836SJohn.Forte@Sun.COM 	} else if (CFG_IST(ha, CFG_CTRL_2422)) {
9897836SJohn.Forte@Sun.COM 		lptr = (uint32_t *)nv;
99011541SDaniel.Beauregard@Sun.COM 		for (cnt = 0; cnt < ha->nvram_cache->size / 4; cnt++) {
9917836SJohn.Forte@Sun.COM 			data32 = *lptr++;
9927836SJohn.Forte@Sun.COM 			LITTLE_ENDIAN_32(&data32);
9937836SJohn.Forte@Sun.COM 			rval = ql_24xx_load_nvram(ha, cnt + start_addr,
9947836SJohn.Forte@Sun.COM 			    data32);
9957836SJohn.Forte@Sun.COM 			if (rval != QL_SUCCESS) {
9967836SJohn.Forte@Sun.COM 				EL(ha, "failed, 24xx_load_nvram=%xh\n", rval);
9977836SJohn.Forte@Sun.COM 				break;
9987836SJohn.Forte@Sun.COM 			}
9997836SJohn.Forte@Sun.COM 		}
10007836SJohn.Forte@Sun.COM 	} else {
10017836SJohn.Forte@Sun.COM 		wptr = (uint16_t *)nv;
100211541SDaniel.Beauregard@Sun.COM 		for (cnt = 0; cnt < ha->nvram_cache->size / 2; cnt++) {
10037836SJohn.Forte@Sun.COM 			data = *wptr++;
10047836SJohn.Forte@Sun.COM 			LITTLE_ENDIAN_16(&data);
10057836SJohn.Forte@Sun.COM 			ql_load_nvram(ha, (uint8_t)(cnt + start_addr), data);
10067836SJohn.Forte@Sun.COM 		}
10077836SJohn.Forte@Sun.COM 	}
100811541SDaniel.Beauregard@Sun.COM 	/* switch to the new one */
100911541SDaniel.Beauregard@Sun.COM 	NVRAM_CACHE_LOCK(ha);
10107836SJohn.Forte@Sun.COM 
101111541SDaniel.Beauregard@Sun.COM 	kmem_free(ha->nvram_cache->cache, ha->nvram_cache->size);
101211541SDaniel.Beauregard@Sun.COM 	ha->nvram_cache->cache = (void *)nptr;
101311541SDaniel.Beauregard@Sun.COM 
101411541SDaniel.Beauregard@Sun.COM 	NVRAM_CACHE_UNLOCK(ha);
101511541SDaniel.Beauregard@Sun.COM 
10167836SJohn.Forte@Sun.COM 	ql_release_nvram(ha);
10177836SJohn.Forte@Sun.COM 	ql_restart_driver(ha);
10187836SJohn.Forte@Sun.COM 
10197836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
10207836SJohn.Forte@Sun.COM 
10217836SJohn.Forte@Sun.COM 	if (rval == QL_SUCCESS) {
10227836SJohn.Forte@Sun.COM 		return (0);
10237836SJohn.Forte@Sun.COM 	}
10247836SJohn.Forte@Sun.COM 
10257836SJohn.Forte@Sun.COM 	return (EFAULT);
10267836SJohn.Forte@Sun.COM }
10277836SJohn.Forte@Sun.COM 
10287836SJohn.Forte@Sun.COM /*
10297836SJohn.Forte@Sun.COM  * ql_nv_util_dump
10307836SJohn.Forte@Sun.COM  *	Dumps NVRAM to application.
10317836SJohn.Forte@Sun.COM  *
10327836SJohn.Forte@Sun.COM  * Input:
10337836SJohn.Forte@Sun.COM  *	ha = adapter state pointer.
10347836SJohn.Forte@Sun.COM  *	bp = user buffer address.
10357836SJohn.Forte@Sun.COM  *
10367836SJohn.Forte@Sun.COM  * Returns:
10377836SJohn.Forte@Sun.COM  *
10387836SJohn.Forte@Sun.COM  * Context:
10397836SJohn.Forte@Sun.COM  *	Kernel context.
10407836SJohn.Forte@Sun.COM  */
10417836SJohn.Forte@Sun.COM int
ql_nv_util_dump(ql_adapter_state_t * ha,void * bp,int mode)10427836SJohn.Forte@Sun.COM ql_nv_util_dump(ql_adapter_state_t *ha, void *bp, int mode)
10437836SJohn.Forte@Sun.COM {
10447836SJohn.Forte@Sun.COM 	uint32_t	start_addr;
10457836SJohn.Forte@Sun.COM 	int		rval2, rval = 0;
10467836SJohn.Forte@Sun.COM 
10477836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
10487836SJohn.Forte@Sun.COM 
104911541SDaniel.Beauregard@Sun.COM 	if (ha->nvram_cache == NULL ||
105011541SDaniel.Beauregard@Sun.COM 	    ha->nvram_cache->size == NULL ||
105111541SDaniel.Beauregard@Sun.COM 	    ha->nvram_cache->cache == NULL) {
10527836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
10537836SJohn.Forte@Sun.COM 		return (ENOMEM);
105411541SDaniel.Beauregard@Sun.COM 	} else if (ha->nvram_cache->valid != 1) {
105511541SDaniel.Beauregard@Sun.COM 
105611541SDaniel.Beauregard@Sun.COM 		/* Quiesce I/O */
105711541SDaniel.Beauregard@Sun.COM 		if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
105811541SDaniel.Beauregard@Sun.COM 			EL(ha, "ql_stall_driver failed\n");
105911541SDaniel.Beauregard@Sun.COM 			return (EBUSY);
106011541SDaniel.Beauregard@Sun.COM 		}
106111541SDaniel.Beauregard@Sun.COM 
106211541SDaniel.Beauregard@Sun.COM 		rval2 = ql_lock_nvram(ha, &start_addr, LNF_NVRAM_DATA);
106311541SDaniel.Beauregard@Sun.COM 		if (rval2 != QL_SUCCESS) {
106411541SDaniel.Beauregard@Sun.COM 			EL(ha, "failed, ql_lock_nvram=%xh\n", rval2);
106511541SDaniel.Beauregard@Sun.COM 			ql_restart_driver(ha);
106611541SDaniel.Beauregard@Sun.COM 			return (EIO);
106711541SDaniel.Beauregard@Sun.COM 		}
106811541SDaniel.Beauregard@Sun.COM 		NVRAM_CACHE_LOCK(ha);
10697836SJohn.Forte@Sun.COM 
107011541SDaniel.Beauregard@Sun.COM 		rval2 = ql_get_nvram(ha, ha->nvram_cache->cache,
107111541SDaniel.Beauregard@Sun.COM 		    start_addr, ha->nvram_cache->size);
107211541SDaniel.Beauregard@Sun.COM 		if (rval2 != QL_SUCCESS) {
107311541SDaniel.Beauregard@Sun.COM 			rval = rval2;
107411541SDaniel.Beauregard@Sun.COM 		} else {
107511541SDaniel.Beauregard@Sun.COM 			ha->nvram_cache->valid = 1;
107611541SDaniel.Beauregard@Sun.COM 			EL(ha, "nvram cache now valid.");
107711541SDaniel.Beauregard@Sun.COM 		}
107811541SDaniel.Beauregard@Sun.COM 
107911541SDaniel.Beauregard@Sun.COM 		NVRAM_CACHE_UNLOCK(ha);
108011541SDaniel.Beauregard@Sun.COM 
108111541SDaniel.Beauregard@Sun.COM 		ql_release_nvram(ha);
108211541SDaniel.Beauregard@Sun.COM 		ql_restart_driver(ha);
108311541SDaniel.Beauregard@Sun.COM 
108411541SDaniel.Beauregard@Sun.COM 		if (rval != 0) {
108511541SDaniel.Beauregard@Sun.COM 			EL(ha, "failed to dump nvram, rval=%x\n", rval);
108611541SDaniel.Beauregard@Sun.COM 			return (rval);
108711541SDaniel.Beauregard@Sun.COM 		}
10887836SJohn.Forte@Sun.COM 	}
10897836SJohn.Forte@Sun.COM 
109011541SDaniel.Beauregard@Sun.COM 	if (ddi_copyout(ha->nvram_cache->cache, bp,
109111541SDaniel.Beauregard@Sun.COM 	    ha->nvram_cache->size, mode) != 0) {
109211541SDaniel.Beauregard@Sun.COM 		EL(ha, "Buffer copy failed\n");
109311541SDaniel.Beauregard@Sun.COM 		return (EFAULT);
10947836SJohn.Forte@Sun.COM 	}
10957836SJohn.Forte@Sun.COM 
109611541SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
109711541SDaniel.Beauregard@Sun.COM 
109811541SDaniel.Beauregard@Sun.COM 	return (0);
109911541SDaniel.Beauregard@Sun.COM }
110011541SDaniel.Beauregard@Sun.COM 
110111541SDaniel.Beauregard@Sun.COM int
ql_get_nvram(ql_adapter_state_t * ha,void * dest_addr,uint32_t src_addr,uint32_t size)110211541SDaniel.Beauregard@Sun.COM ql_get_nvram(ql_adapter_state_t *ha, void *dest_addr, uint32_t src_addr,
110311541SDaniel.Beauregard@Sun.COM     uint32_t size)
110411541SDaniel.Beauregard@Sun.COM {
110511541SDaniel.Beauregard@Sun.COM 	int rval = QL_SUCCESS;
110611541SDaniel.Beauregard@Sun.COM 	int cnt;
11077836SJohn.Forte@Sun.COM 	/* Dump NVRAM. */
110811924SDaniel.Beauregard@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_24258081)) {
110911541SDaniel.Beauregard@Sun.COM 		uint32_t	*lptr = (uint32_t *)dest_addr;
11107836SJohn.Forte@Sun.COM 
111111541SDaniel.Beauregard@Sun.COM 		for (cnt = 0; cnt < size / 4; cnt++) {
111211541SDaniel.Beauregard@Sun.COM 			rval = ql_24xx_read_flash(ha, src_addr++, lptr);
111311541SDaniel.Beauregard@Sun.COM 			if (rval != QL_SUCCESS) {
111411541SDaniel.Beauregard@Sun.COM 				EL(ha, "read_flash failed=%xh\n", rval);
11157836SJohn.Forte@Sun.COM 				rval = EAGAIN;
11167836SJohn.Forte@Sun.COM 				break;
11177836SJohn.Forte@Sun.COM 			}
11187836SJohn.Forte@Sun.COM 			LITTLE_ENDIAN_32(lptr);
11197836SJohn.Forte@Sun.COM 			lptr++;
11207836SJohn.Forte@Sun.COM 		}
11217836SJohn.Forte@Sun.COM 	} else {
11227836SJohn.Forte@Sun.COM 		uint16_t	data;
112311541SDaniel.Beauregard@Sun.COM 		uint16_t	*wptr = (uint16_t *)dest_addr;
11247836SJohn.Forte@Sun.COM 
112511541SDaniel.Beauregard@Sun.COM 		for (cnt = 0; cnt < size / 2; cnt++) {
11267836SJohn.Forte@Sun.COM 			data = (uint16_t)ql_get_nvram_word(ha, cnt +
112711541SDaniel.Beauregard@Sun.COM 			    src_addr);
11287836SJohn.Forte@Sun.COM 			LITTLE_ENDIAN_16(&data);
11297836SJohn.Forte@Sun.COM 			*wptr++ = data;
11307836SJohn.Forte@Sun.COM 		}
11317836SJohn.Forte@Sun.COM 	}
113211541SDaniel.Beauregard@Sun.COM 	return (rval);
11337836SJohn.Forte@Sun.COM }
11347836SJohn.Forte@Sun.COM 
11357836SJohn.Forte@Sun.COM /*
11367836SJohn.Forte@Sun.COM  * ql_vpd_load
11377836SJohn.Forte@Sun.COM  *	Loads VPD from application.
11387836SJohn.Forte@Sun.COM  *
11397836SJohn.Forte@Sun.COM  * Input:
11407836SJohn.Forte@Sun.COM  *	ha = adapter state pointer.
11417836SJohn.Forte@Sun.COM  *	bp = user buffer address.
11427836SJohn.Forte@Sun.COM  *
11437836SJohn.Forte@Sun.COM  * Returns:
11447836SJohn.Forte@Sun.COM  *
11457836SJohn.Forte@Sun.COM  * Context:
11467836SJohn.Forte@Sun.COM  *	Kernel context.
11477836SJohn.Forte@Sun.COM  */
11487836SJohn.Forte@Sun.COM int
ql_vpd_load(ql_adapter_state_t * ha,void * bp,int mode)11497836SJohn.Forte@Sun.COM ql_vpd_load(ql_adapter_state_t *ha, void *bp, int mode)
11507836SJohn.Forte@Sun.COM {
11517836SJohn.Forte@Sun.COM 	uint8_t		cnt;
11527836SJohn.Forte@Sun.COM 	uint8_t		*vpd, *vpdptr, *vbuf;
11537836SJohn.Forte@Sun.COM 	uint32_t	start_addr, vpd_size, *lptr, data32;
11547836SJohn.Forte@Sun.COM 	int		rval;
11557836SJohn.Forte@Sun.COM 
11567836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
11577836SJohn.Forte@Sun.COM 
115811924SDaniel.Beauregard@Sun.COM 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
11597836SJohn.Forte@Sun.COM 		EL(ha, "unsupported adapter feature\n");
11607836SJohn.Forte@Sun.COM 		return (ENOTSUP);
11617836SJohn.Forte@Sun.COM 	}
11627836SJohn.Forte@Sun.COM 
11637836SJohn.Forte@Sun.COM 	vpd_size = QL_24XX_VPD_SIZE;
11647836SJohn.Forte@Sun.COM 
11657836SJohn.Forte@Sun.COM 	if ((vpd = kmem_zalloc(vpd_size, KM_SLEEP)) == NULL) {
11667836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
11677836SJohn.Forte@Sun.COM 		return (ENOMEM);
11687836SJohn.Forte@Sun.COM 	}
11697836SJohn.Forte@Sun.COM 
11707836SJohn.Forte@Sun.COM 	if (ddi_copyin(bp, vpd, vpd_size, mode) != 0) {
11717836SJohn.Forte@Sun.COM 		EL(ha, "Buffer copy failed\n");
11727836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
11737836SJohn.Forte@Sun.COM 		return (EFAULT);
11747836SJohn.Forte@Sun.COM 	}
11757836SJohn.Forte@Sun.COM 
11767836SJohn.Forte@Sun.COM 	/* Sanity check the user supplied data via checksum */
11777836SJohn.Forte@Sun.COM 	if ((vpdptr = ql_vpd_findtag(ha, vpd, "RV")) == NULL) {
11787836SJohn.Forte@Sun.COM 		EL(ha, "vpd RV tag missing\n");
11797836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
11807836SJohn.Forte@Sun.COM 		return (EINVAL);
11817836SJohn.Forte@Sun.COM 	}
11827836SJohn.Forte@Sun.COM 
11837836SJohn.Forte@Sun.COM 	vpdptr += 3;
11847836SJohn.Forte@Sun.COM 	cnt = 0;
11857836SJohn.Forte@Sun.COM 	vbuf = vpd;
11867836SJohn.Forte@Sun.COM 	while (vbuf <= vpdptr) {
11877836SJohn.Forte@Sun.COM 		cnt += *vbuf++;
11887836SJohn.Forte@Sun.COM 	}
11897836SJohn.Forte@Sun.COM 	if (cnt != 0) {
11907836SJohn.Forte@Sun.COM 		EL(ha, "mismatched checksum, cal=%xh, passed=%xh\n",
11917836SJohn.Forte@Sun.COM 		    (uint8_t)cnt, (uintptr_t)vpdptr);
11927836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
11937836SJohn.Forte@Sun.COM 		return (EINVAL);
11947836SJohn.Forte@Sun.COM 	}
11957836SJohn.Forte@Sun.COM 
11967836SJohn.Forte@Sun.COM 	/* Quiesce I/O */
11977836SJohn.Forte@Sun.COM 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
11987836SJohn.Forte@Sun.COM 		EL(ha, "ql_stall_driver failed\n");
11997836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
12007836SJohn.Forte@Sun.COM 		return (EBUSY);
12017836SJohn.Forte@Sun.COM 	}
12027836SJohn.Forte@Sun.COM 
12037836SJohn.Forte@Sun.COM 	rval = ql_lock_nvram(ha, &start_addr, LNF_VPD_DATA);
12047836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
12057836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
12067836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
12077836SJohn.Forte@Sun.COM 		ql_restart_driver(ha);
12087836SJohn.Forte@Sun.COM 		return (EIO);
12097836SJohn.Forte@Sun.COM 	}
12107836SJohn.Forte@Sun.COM 
12117836SJohn.Forte@Sun.COM 	/* Load VPD. */
121211924SDaniel.Beauregard@Sun.COM 	if (CFG_IST(ha, CFG_CTRL_258081)) {
12137836SJohn.Forte@Sun.COM 		GLOBAL_HW_UNLOCK();
12149446SDaniel.Beauregard@Sun.COM 		start_addr &= ~ha->flash_data_addr;
12159446SDaniel.Beauregard@Sun.COM 		start_addr <<= 2;
12169446SDaniel.Beauregard@Sun.COM 		if ((rval = ql_r_m_w_flash(ha, bp, vpd_size, start_addr,
12179446SDaniel.Beauregard@Sun.COM 		    mode)) != QL_SUCCESS) {
12187836SJohn.Forte@Sun.COM 			EL(ha, "vpd load error: %xh\n", rval);
12197836SJohn.Forte@Sun.COM 		}
12207836SJohn.Forte@Sun.COM 		GLOBAL_HW_LOCK();
12217836SJohn.Forte@Sun.COM 	} else {
12227836SJohn.Forte@Sun.COM 		lptr = (uint32_t *)vpd;
12237836SJohn.Forte@Sun.COM 		for (cnt = 0; cnt < vpd_size / 4; cnt++) {
12247836SJohn.Forte@Sun.COM 			data32 = *lptr++;
12257836SJohn.Forte@Sun.COM 			LITTLE_ENDIAN_32(&data32);
12267836SJohn.Forte@Sun.COM 			rval = ql_24xx_load_nvram(ha, cnt + start_addr,
12277836SJohn.Forte@Sun.COM 			    data32);
12287836SJohn.Forte@Sun.COM 			if (rval != QL_SUCCESS) {
12297836SJohn.Forte@Sun.COM 				EL(ha, "failed, 24xx_load_nvram=%xh\n", rval);
12307836SJohn.Forte@Sun.COM 				break;
12317836SJohn.Forte@Sun.COM 			}
12327836SJohn.Forte@Sun.COM 		}
12337836SJohn.Forte@Sun.COM 	}
12347836SJohn.Forte@Sun.COM 
12357836SJohn.Forte@Sun.COM 	kmem_free(vpd, vpd_size);
12367836SJohn.Forte@Sun.COM 
12377836SJohn.Forte@Sun.COM 	/* Update the vcache */
12387836SJohn.Forte@Sun.COM 	CACHE_LOCK(ha);
12397836SJohn.Forte@Sun.COM 
12407836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
12417836SJohn.Forte@Sun.COM 		EL(ha, "failed, load\n");
12427836SJohn.Forte@Sun.COM 	} else if ((ha->vcache == NULL) && ((ha->vcache =
12437836SJohn.Forte@Sun.COM 	    kmem_zalloc(vpd_size, KM_SLEEP)) == NULL)) {
12447836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc2\n");
12457836SJohn.Forte@Sun.COM 	} else if (ddi_copyin(bp, ha->vcache, vpd_size, mode) != 0) {
12467836SJohn.Forte@Sun.COM 		EL(ha, "Buffer copy2 failed\n");
12477836SJohn.Forte@Sun.COM 		kmem_free(ha->vcache, vpd_size);
12487836SJohn.Forte@Sun.COM 		ha->vcache = NULL;
12497836SJohn.Forte@Sun.COM 	}
12507836SJohn.Forte@Sun.COM 
12517836SJohn.Forte@Sun.COM 	CACHE_UNLOCK(ha);
12527836SJohn.Forte@Sun.COM 
12537836SJohn.Forte@Sun.COM 	ql_release_nvram(ha);
12547836SJohn.Forte@Sun.COM 	ql_restart_driver(ha);
12557836SJohn.Forte@Sun.COM 
12567836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
12577836SJohn.Forte@Sun.COM 
12587836SJohn.Forte@Sun.COM 	if (rval == QL_SUCCESS) {
12597836SJohn.Forte@Sun.COM 		return (0);
12607836SJohn.Forte@Sun.COM 	}
12617836SJohn.Forte@Sun.COM 
12627836SJohn.Forte@Sun.COM 	return (EFAULT);
12637836SJohn.Forte@Sun.COM }
12647836SJohn.Forte@Sun.COM 
12657836SJohn.Forte@Sun.COM /*
12667836SJohn.Forte@Sun.COM  * ql_vpd_dump
12677836SJohn.Forte@Sun.COM  *	Dumps VPD to application buffer.
12687836SJohn.Forte@Sun.COM  *
12697836SJohn.Forte@Sun.COM  * Input:
12707836SJohn.Forte@Sun.COM  *	ha = adapter state pointer.
12717836SJohn.Forte@Sun.COM  *	bp = user buffer address.
12727836SJohn.Forte@Sun.COM  *
12737836SJohn.Forte@Sun.COM  * Returns:
12747836SJohn.Forte@Sun.COM  *
12757836SJohn.Forte@Sun.COM  * Context:
12767836SJohn.Forte@Sun.COM  *	Kernel context.
12777836SJohn.Forte@Sun.COM  */
12787836SJohn.Forte@Sun.COM int
ql_vpd_dump(ql_adapter_state_t * ha,void * bp,int mode)12797836SJohn.Forte@Sun.COM ql_vpd_dump(ql_adapter_state_t *ha, void *bp, int mode)
12807836SJohn.Forte@Sun.COM {
12817836SJohn.Forte@Sun.COM 	uint8_t		cnt;
12827836SJohn.Forte@Sun.COM 	void		*vpd;
12837836SJohn.Forte@Sun.COM 	uint32_t	start_addr, vpd_size, *lptr;
12847836SJohn.Forte@Sun.COM 	int		rval = 0;
12857836SJohn.Forte@Sun.COM 
12867836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
12877836SJohn.Forte@Sun.COM 
128811924SDaniel.Beauregard@Sun.COM 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
12897836SJohn.Forte@Sun.COM 		EL(ha, "unsupported adapter feature\n");
12907836SJohn.Forte@Sun.COM 		return (EACCES);
12917836SJohn.Forte@Sun.COM 	}
12927836SJohn.Forte@Sun.COM 
12937836SJohn.Forte@Sun.COM 	vpd_size = QL_24XX_VPD_SIZE;
12947836SJohn.Forte@Sun.COM 
12957836SJohn.Forte@Sun.COM 	CACHE_LOCK(ha);
12967836SJohn.Forte@Sun.COM 
12977836SJohn.Forte@Sun.COM 	if (ha->vcache != NULL) {
12987836SJohn.Forte@Sun.COM 		/* copy back the vpd cache data */
12997836SJohn.Forte@Sun.COM 		if (ddi_copyout(ha->vcache, bp, vpd_size, mode) != 0) {
13007836SJohn.Forte@Sun.COM 			EL(ha, "Buffer copy failed\n");
13017836SJohn.Forte@Sun.COM 			rval = EFAULT;
13027836SJohn.Forte@Sun.COM 		}
13037836SJohn.Forte@Sun.COM 		CACHE_UNLOCK(ha);
13047836SJohn.Forte@Sun.COM 		return (rval);
13057836SJohn.Forte@Sun.COM 	}
13067836SJohn.Forte@Sun.COM 
13077836SJohn.Forte@Sun.COM 	if ((vpd = kmem_zalloc(vpd_size, KM_SLEEP)) == NULL) {
13087836SJohn.Forte@Sun.COM 		CACHE_UNLOCK(ha);
13097836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
13107836SJohn.Forte@Sun.COM 		return (ENOMEM);
13117836SJohn.Forte@Sun.COM 	}
13127836SJohn.Forte@Sun.COM 
13137836SJohn.Forte@Sun.COM 	/* Quiesce I/O */
13147836SJohn.Forte@Sun.COM 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
13157836SJohn.Forte@Sun.COM 		CACHE_UNLOCK(ha);
13167836SJohn.Forte@Sun.COM 		EL(ha, "ql_stall_driver failed\n");
13177836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
13187836SJohn.Forte@Sun.COM 		return (EBUSY);
13197836SJohn.Forte@Sun.COM 	}
13207836SJohn.Forte@Sun.COM 
13217836SJohn.Forte@Sun.COM 	rval = ql_lock_nvram(ha, &start_addr, LNF_VPD_DATA);
13227836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
13237836SJohn.Forte@Sun.COM 		CACHE_UNLOCK(ha);
13247836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_lock_nvram=%xh\n", rval);
13257836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
13267836SJohn.Forte@Sun.COM 		ql_restart_driver(ha);
13277836SJohn.Forte@Sun.COM 		return (EIO);
13287836SJohn.Forte@Sun.COM 	}
13297836SJohn.Forte@Sun.COM 
13307836SJohn.Forte@Sun.COM 	/* Dump VPD. */
13317836SJohn.Forte@Sun.COM 	lptr = (uint32_t *)vpd;
13327836SJohn.Forte@Sun.COM 
13337836SJohn.Forte@Sun.COM 	for (cnt = 0; cnt < vpd_size / 4; cnt++) {
13347836SJohn.Forte@Sun.COM 		rval = ql_24xx_read_flash(ha, start_addr++, lptr);
13357836SJohn.Forte@Sun.COM 		if (rval != QL_SUCCESS) {
13367836SJohn.Forte@Sun.COM 			EL(ha, "read_flash failed=%xh\n", rval);
13377836SJohn.Forte@Sun.COM 			rval = EAGAIN;
13387836SJohn.Forte@Sun.COM 			break;
13397836SJohn.Forte@Sun.COM 		}
13407836SJohn.Forte@Sun.COM 		LITTLE_ENDIAN_32(lptr);
13417836SJohn.Forte@Sun.COM 		lptr++;
13427836SJohn.Forte@Sun.COM 	}
13437836SJohn.Forte@Sun.COM 
13447836SJohn.Forte@Sun.COM 	ql_release_nvram(ha);
13457836SJohn.Forte@Sun.COM 	ql_restart_driver(ha);
13467836SJohn.Forte@Sun.COM 
13477836SJohn.Forte@Sun.COM 	if (ddi_copyout(vpd, bp, vpd_size, mode) != 0) {
13487836SJohn.Forte@Sun.COM 		CACHE_UNLOCK(ha);
13497836SJohn.Forte@Sun.COM 		EL(ha, "Buffer copy failed\n");
13507836SJohn.Forte@Sun.COM 		kmem_free(vpd, vpd_size);
13517836SJohn.Forte@Sun.COM 		return (EFAULT);
13527836SJohn.Forte@Sun.COM 	}
13537836SJohn.Forte@Sun.COM 
13547836SJohn.Forte@Sun.COM 	ha->vcache = vpd;
13557836SJohn.Forte@Sun.COM 
13567836SJohn.Forte@Sun.COM 	CACHE_UNLOCK(ha);
13577836SJohn.Forte@Sun.COM 
13587836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
13597836SJohn.Forte@Sun.COM 
13607836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
13617836SJohn.Forte@Sun.COM 		return (EFAULT);
13627836SJohn.Forte@Sun.COM 	} else {
13637836SJohn.Forte@Sun.COM 		return (0);
13647836SJohn.Forte@Sun.COM 	}
13657836SJohn.Forte@Sun.COM }
13667836SJohn.Forte@Sun.COM 
13677836SJohn.Forte@Sun.COM /*
13687836SJohn.Forte@Sun.COM  * ql_vpd_findtag
13697836SJohn.Forte@Sun.COM  *	Search the passed vpd buffer for the requested VPD tag type.
13707836SJohn.Forte@Sun.COM  *
13717836SJohn.Forte@Sun.COM  * Input:
13727836SJohn.Forte@Sun.COM  *	ha	= adapter state pointer.
13737836SJohn.Forte@Sun.COM  *	vpdbuf	= Pointer to start of the buffer to search
13747836SJohn.Forte@Sun.COM  *	op	= VPD opcode to find (must be NULL terminated).
13757836SJohn.Forte@Sun.COM  *
13767836SJohn.Forte@Sun.COM  * Returns:
13777836SJohn.Forte@Sun.COM  *	Pointer to the opcode in the buffer if opcode found.
13787836SJohn.Forte@Sun.COM  *	NULL if opcode is not found.
13797836SJohn.Forte@Sun.COM  *
13807836SJohn.Forte@Sun.COM  * Context:
13817836SJohn.Forte@Sun.COM  *	Kernel context.
13827836SJohn.Forte@Sun.COM  */
13837836SJohn.Forte@Sun.COM static uint8_t *
ql_vpd_findtag(ql_adapter_state_t * ha,uint8_t * vpdbuf,int8_t * opcode)13847836SJohn.Forte@Sun.COM ql_vpd_findtag(ql_adapter_state_t *ha, uint8_t *vpdbuf, int8_t *opcode)
13857836SJohn.Forte@Sun.COM {
13867836SJohn.Forte@Sun.COM 	uint8_t		*vpd = vpdbuf;
13877836SJohn.Forte@Sun.COM 	uint8_t		*end = vpdbuf + QL_24XX_VPD_SIZE;
13887836SJohn.Forte@Sun.COM 	uint32_t	found = 0;
13897836SJohn.Forte@Sun.COM 
13907836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
13917836SJohn.Forte@Sun.COM 
13927836SJohn.Forte@Sun.COM 	if (vpdbuf == NULL || opcode == NULL) {
13937836SJohn.Forte@Sun.COM 		EL(ha, "null parameter passed!\n");
13947836SJohn.Forte@Sun.COM 		return (NULL);
13957836SJohn.Forte@Sun.COM 	}
13967836SJohn.Forte@Sun.COM 
13977836SJohn.Forte@Sun.COM 	while (vpd < end) {
13987836SJohn.Forte@Sun.COM 
13997836SJohn.Forte@Sun.COM 		/* check for end of vpd */
14007836SJohn.Forte@Sun.COM 		if (vpd[0] == VPD_TAG_END) {
14017836SJohn.Forte@Sun.COM 			if (opcode[0] == VPD_TAG_END) {
14027836SJohn.Forte@Sun.COM 				found = 1;
14037836SJohn.Forte@Sun.COM 			} else {
14047836SJohn.Forte@Sun.COM 				found = 0;
14057836SJohn.Forte@Sun.COM 			}
14067836SJohn.Forte@Sun.COM 			break;
14077836SJohn.Forte@Sun.COM 		}
14087836SJohn.Forte@Sun.COM 
14097836SJohn.Forte@Sun.COM 		/* check opcode */
14107836SJohn.Forte@Sun.COM 		if (bcmp(opcode, vpd, strlen(opcode)) == 0) {
14117836SJohn.Forte@Sun.COM 			/* found opcode requested */
14127836SJohn.Forte@Sun.COM 			found = 1;
14137836SJohn.Forte@Sun.COM 			break;
14147836SJohn.Forte@Sun.COM 		}
14157836SJohn.Forte@Sun.COM 
14167836SJohn.Forte@Sun.COM 		/*
14177836SJohn.Forte@Sun.COM 		 * Didn't find the opcode, so calculate start of
14187836SJohn.Forte@Sun.COM 		 * next tag. Depending on the current tag type,
14197836SJohn.Forte@Sun.COM 		 * the length field can be 1 or 2 bytes
14207836SJohn.Forte@Sun.COM 		 */
14217836SJohn.Forte@Sun.COM 		if (!(strncmp((char *)vpd, (char *)VPD_TAG_PRODID, 1))) {
14227836SJohn.Forte@Sun.COM 			vpd += (vpd[2] << 8) + vpd[1] + 3;
14237836SJohn.Forte@Sun.COM 		} else if (*vpd == VPD_TAG_LRT || *vpd == VPD_TAG_LRTC) {
14247836SJohn.Forte@Sun.COM 			vpd += 3;
14257836SJohn.Forte@Sun.COM 		} else {
14267836SJohn.Forte@Sun.COM 			vpd += vpd[2] +3;
14277836SJohn.Forte@Sun.COM 		}
14287836SJohn.Forte@Sun.COM 	}
14297836SJohn.Forte@Sun.COM 
14309446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
14317836SJohn.Forte@Sun.COM 
14327836SJohn.Forte@Sun.COM 	return (found == 1 ? vpd : NULL);
14337836SJohn.Forte@Sun.COM }
14347836SJohn.Forte@Sun.COM 
14357836SJohn.Forte@Sun.COM /*
14367836SJohn.Forte@Sun.COM  * ql_vpd_lookup
14377836SJohn.Forte@Sun.COM  *	Return the VPD data for the request VPD tag
14387836SJohn.Forte@Sun.COM  *
14397836SJohn.Forte@Sun.COM  * Input:
14407836SJohn.Forte@Sun.COM  *	ha	= adapter state pointer.
14417836SJohn.Forte@Sun.COM  *	opcode	= VPD opcode to find (must be NULL terminated).
14427836SJohn.Forte@Sun.COM  *	bp	= Pointer to returned data buffer.
14437836SJohn.Forte@Sun.COM  *	bplen	= Length of returned data buffer.
14447836SJohn.Forte@Sun.COM  *
14457836SJohn.Forte@Sun.COM  * Returns:
14467836SJohn.Forte@Sun.COM  *	Length of data copied into returned data buffer.
14477836SJohn.Forte@Sun.COM  *		>0 = VPD data field (NULL terminated)
14487836SJohn.Forte@Sun.COM  *		 0 = no data.
14497836SJohn.Forte@Sun.COM  *		-1 = Could not find opcode in vpd buffer / error.
14507836SJohn.Forte@Sun.COM  *
14517836SJohn.Forte@Sun.COM  * Context:
14527836SJohn.Forte@Sun.COM  *	Kernel context.
14537836SJohn.Forte@Sun.COM  *
14547836SJohn.Forte@Sun.COM  * NB: The opcode buffer and the bp buffer *could* be the same buffer!
14557836SJohn.Forte@Sun.COM  *
14567836SJohn.Forte@Sun.COM  */
14577836SJohn.Forte@Sun.COM int32_t
ql_vpd_lookup(ql_adapter_state_t * ha,uint8_t * opcode,uint8_t * bp,int32_t bplen)14587836SJohn.Forte@Sun.COM ql_vpd_lookup(ql_adapter_state_t *ha, uint8_t *opcode, uint8_t *bp,
14597836SJohn.Forte@Sun.COM     int32_t bplen)
14607836SJohn.Forte@Sun.COM {
14617836SJohn.Forte@Sun.COM 	uint8_t		*vpd;
14627836SJohn.Forte@Sun.COM 	uint8_t		*vpdbuf;
14637836SJohn.Forte@Sun.COM 	int32_t		len = -1;
14647836SJohn.Forte@Sun.COM 
14657836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
14667836SJohn.Forte@Sun.COM 
14677836SJohn.Forte@Sun.COM 	if (opcode == NULL || bp == NULL || bplen < 1) {
14687836SJohn.Forte@Sun.COM 		EL(ha, "invalid parameter passed: opcode=%ph, "
14697836SJohn.Forte@Sun.COM 		    "bp=%ph, bplen=%xh\n", opcode, bp, bplen);
14707836SJohn.Forte@Sun.COM 		return (len);
14717836SJohn.Forte@Sun.COM 	}
14727836SJohn.Forte@Sun.COM 
147311924SDaniel.Beauregard@Sun.COM 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
14747836SJohn.Forte@Sun.COM 		return (len);
14757836SJohn.Forte@Sun.COM 	}
14767836SJohn.Forte@Sun.COM 
14777836SJohn.Forte@Sun.COM 	if ((vpdbuf = (uint8_t *)kmem_zalloc(QL_24XX_VPD_SIZE,
14787836SJohn.Forte@Sun.COM 	    KM_SLEEP)) == NULL) {
14797836SJohn.Forte@Sun.COM 		EL(ha, "unable to allocate vpd memory\n");
14807836SJohn.Forte@Sun.COM 		return (len);
14817836SJohn.Forte@Sun.COM 	}
14827836SJohn.Forte@Sun.COM 
14837836SJohn.Forte@Sun.COM 	if ((ql_vpd_dump(ha, vpdbuf, (int)FKIOCTL)) != 0) {
14847836SJohn.Forte@Sun.COM 		kmem_free(vpdbuf, QL_24XX_VPD_SIZE);
14857836SJohn.Forte@Sun.COM 		EL(ha, "unable to retrieve VPD data\n");
14867836SJohn.Forte@Sun.COM 		return (len);
14877836SJohn.Forte@Sun.COM 	}
14887836SJohn.Forte@Sun.COM 
14897836SJohn.Forte@Sun.COM 	if ((vpd = ql_vpd_findtag(ha, vpdbuf, (int8_t *)opcode)) != NULL) {
14907836SJohn.Forte@Sun.COM 		/*
14917836SJohn.Forte@Sun.COM 		 * Found the tag
14927836SJohn.Forte@Sun.COM 		 */
14937836SJohn.Forte@Sun.COM 		if (*opcode == VPD_TAG_END || *opcode == VPD_TAG_LRT ||
14947836SJohn.Forte@Sun.COM 		    *opcode == VPD_TAG_LRTC) {
14957836SJohn.Forte@Sun.COM 			/*
14967836SJohn.Forte@Sun.COM 			 * we found it, but the tag doesn't have a data
14977836SJohn.Forte@Sun.COM 			 * field.
14987836SJohn.Forte@Sun.COM 			 */
14997836SJohn.Forte@Sun.COM 			len = 0;
15007836SJohn.Forte@Sun.COM 		} else if (!(strncmp((char *)vpd, (char *)
15017836SJohn.Forte@Sun.COM 		    VPD_TAG_PRODID, 1))) {
15027836SJohn.Forte@Sun.COM 			len = vpd[2] << 8;
15037836SJohn.Forte@Sun.COM 			len += vpd[1];
15047836SJohn.Forte@Sun.COM 		} else {
15057836SJohn.Forte@Sun.COM 			len = vpd[2];
15067836SJohn.Forte@Sun.COM 		}
15077836SJohn.Forte@Sun.COM 
15087836SJohn.Forte@Sun.COM 		/*
15097836SJohn.Forte@Sun.COM 		 * make sure that the vpd len doesn't exceed the
15107836SJohn.Forte@Sun.COM 		 * vpd end
15117836SJohn.Forte@Sun.COM 		 */
15127836SJohn.Forte@Sun.COM 		if (vpd+len > vpdbuf + QL_24XX_VPD_SIZE) {
15137836SJohn.Forte@Sun.COM 			EL(ha, "vpd tag len (%xh) exceeds vpd buffer "
15147836SJohn.Forte@Sun.COM 			    "length\n", len);
15157836SJohn.Forte@Sun.COM 			len = -1;
15167836SJohn.Forte@Sun.COM 		}
15177836SJohn.Forte@Sun.COM 	}
15187836SJohn.Forte@Sun.COM 
15197836SJohn.Forte@Sun.COM 	if (len >= 0) {
15207836SJohn.Forte@Sun.COM 		/*
15217836SJohn.Forte@Sun.COM 		 * make sure we don't exceed callers buffer space len
15227836SJohn.Forte@Sun.COM 		 */
15237836SJohn.Forte@Sun.COM 		if (len > bplen) {
15247836SJohn.Forte@Sun.COM 			len = bplen-1;
15257836SJohn.Forte@Sun.COM 		}
15267836SJohn.Forte@Sun.COM 
15277836SJohn.Forte@Sun.COM 		/* copy the data back */
15287836SJohn.Forte@Sun.COM 		(void) strncpy((int8_t *)bp, (int8_t *)(vpd+3), (int64_t)len);
15297836SJohn.Forte@Sun.COM 		bp[len] = NULL;
15307836SJohn.Forte@Sun.COM 	} else {
15317836SJohn.Forte@Sun.COM 		/* error -- couldn't find tag */
15327836SJohn.Forte@Sun.COM 		bp[0] = NULL;
15337836SJohn.Forte@Sun.COM 		if (opcode[1] != NULL) {
15347836SJohn.Forte@Sun.COM 			EL(ha, "unable to find tag '%s'\n", opcode);
15357836SJohn.Forte@Sun.COM 		} else {
15367836SJohn.Forte@Sun.COM 			EL(ha, "unable to find tag '%xh'\n", opcode[0]);
15377836SJohn.Forte@Sun.COM 		}
15387836SJohn.Forte@Sun.COM 	}
15397836SJohn.Forte@Sun.COM 
15407836SJohn.Forte@Sun.COM 	kmem_free(vpdbuf, QL_24XX_VPD_SIZE);
15417836SJohn.Forte@Sun.COM 
15429446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
15437836SJohn.Forte@Sun.COM 
15447836SJohn.Forte@Sun.COM 	return (len);
15457836SJohn.Forte@Sun.COM }
15467836SJohn.Forte@Sun.COM 
15479446SDaniel.Beauregard@Sun.COM /*
15489446SDaniel.Beauregard@Sun.COM  * ql_r_m_w_flash
15499446SDaniel.Beauregard@Sun.COM  *	Read modify write from user space to flash.
15509446SDaniel.Beauregard@Sun.COM  *
15519446SDaniel.Beauregard@Sun.COM  * Input:
15529446SDaniel.Beauregard@Sun.COM  *	ha:	adapter state pointer.
15539446SDaniel.Beauregard@Sun.COM  *	dp:	source byte pointer.
15549446SDaniel.Beauregard@Sun.COM  *	bc:	byte count.
15559446SDaniel.Beauregard@Sun.COM  *	faddr:	flash byte address.
15569446SDaniel.Beauregard@Sun.COM  *	mode:	flags.
15579446SDaniel.Beauregard@Sun.COM  *
15589446SDaniel.Beauregard@Sun.COM  * Returns:
15599446SDaniel.Beauregard@Sun.COM  *	ql local function return status code.
15609446SDaniel.Beauregard@Sun.COM  *
15619446SDaniel.Beauregard@Sun.COM  * Context:
15629446SDaniel.Beauregard@Sun.COM  *	Kernel context.
15639446SDaniel.Beauregard@Sun.COM  */
15649446SDaniel.Beauregard@Sun.COM int
ql_r_m_w_flash(ql_adapter_state_t * ha,caddr_t dp,uint32_t bc,uint32_t faddr,int mode)15659446SDaniel.Beauregard@Sun.COM ql_r_m_w_flash(ql_adapter_state_t *ha, caddr_t dp, uint32_t bc, uint32_t faddr,
15669446SDaniel.Beauregard@Sun.COM     int mode)
15677836SJohn.Forte@Sun.COM {
15687836SJohn.Forte@Sun.COM 	uint8_t		*bp;
15699446SDaniel.Beauregard@Sun.COM 	uint32_t	xfer, bsize, saddr, ofst;
15709446SDaniel.Beauregard@Sun.COM 	int		rval = 0;
15719446SDaniel.Beauregard@Sun.COM 
15729446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started, dp=%ph, faddr=%xh, bc=%xh\n",
15739446SDaniel.Beauregard@Sun.COM 	    ha->instance, (void *)dp, faddr, bc);
15749446SDaniel.Beauregard@Sun.COM 
15759446SDaniel.Beauregard@Sun.COM 	bsize = ha->xioctl->fdesc.block_size;
15769446SDaniel.Beauregard@Sun.COM 	saddr = faddr & ~(bsize - 1);
15779446SDaniel.Beauregard@Sun.COM 	ofst = faddr & (bsize - 1);
15787836SJohn.Forte@Sun.COM 
15797836SJohn.Forte@Sun.COM 	if ((bp = kmem_zalloc(bsize, KM_SLEEP)) == NULL) {
15809446SDaniel.Beauregard@Sun.COM 		EL(ha, "kmem_zalloc=null\n");
15819446SDaniel.Beauregard@Sun.COM 		return (QL_MEMORY_ALLOC_FAILED);
15827836SJohn.Forte@Sun.COM 	}
15837836SJohn.Forte@Sun.COM 
15849446SDaniel.Beauregard@Sun.COM 	while (bc) {
15859446SDaniel.Beauregard@Sun.COM 		xfer = bc > bsize ? bsize : bc;
15869446SDaniel.Beauregard@Sun.COM 		if (ofst + xfer > bsize) {
15879446SDaniel.Beauregard@Sun.COM 			xfer = bsize - ofst;
15889446SDaniel.Beauregard@Sun.COM 		}
15899446SDaniel.Beauregard@Sun.COM 		QL_PRINT_9(CE_CONT, "(%d): dp=%ph, saddr=%xh, bc=%xh, "
15909446SDaniel.Beauregard@Sun.COM 		    "ofst=%xh, xfer=%xh\n", ha->instance, (void *)dp, saddr,
15919446SDaniel.Beauregard@Sun.COM 		    bc, ofst, xfer);
15927836SJohn.Forte@Sun.COM 
15939446SDaniel.Beauregard@Sun.COM 		if (ofst || xfer < bsize) {
15949446SDaniel.Beauregard@Sun.COM 			/* Dump Flash sector. */
15959446SDaniel.Beauregard@Sun.COM 			if ((rval = ql_dump_fcode(ha, bp, bsize, saddr)) !=
15969446SDaniel.Beauregard@Sun.COM 			    QL_SUCCESS) {
15979446SDaniel.Beauregard@Sun.COM 				EL(ha, "dump_flash status=%x\n", rval);
15989446SDaniel.Beauregard@Sun.COM 				break;
15999446SDaniel.Beauregard@Sun.COM 			}
16009446SDaniel.Beauregard@Sun.COM 		}
16019446SDaniel.Beauregard@Sun.COM 
16027836SJohn.Forte@Sun.COM 		/* Set new data. */
16039446SDaniel.Beauregard@Sun.COM 		if ((rval = ddi_copyin(dp, (caddr_t)(bp + ofst), xfer,
16049446SDaniel.Beauregard@Sun.COM 		    mode)) != 0) {
16059446SDaniel.Beauregard@Sun.COM 			EL(ha, "ddi_copyin status=%xh, dp=%ph, ofst=%xh, "
16069446SDaniel.Beauregard@Sun.COM 			    "xfer=%xh\n", rval, (void *)dp, ofst, xfer);
16079446SDaniel.Beauregard@Sun.COM 			rval = QL_FUNCTION_FAILED;
16089446SDaniel.Beauregard@Sun.COM 			break;
16099446SDaniel.Beauregard@Sun.COM 		}
16107836SJohn.Forte@Sun.COM 
16117836SJohn.Forte@Sun.COM 		/* Write to flash. */
16129446SDaniel.Beauregard@Sun.COM 		if ((rval = ql_load_fcode(ha, bp, bsize, saddr)) !=
16139446SDaniel.Beauregard@Sun.COM 		    QL_SUCCESS) {
16149446SDaniel.Beauregard@Sun.COM 			EL(ha, "load_flash status=%x\n", rval);
16159446SDaniel.Beauregard@Sun.COM 			break;
16169446SDaniel.Beauregard@Sun.COM 		}
16179446SDaniel.Beauregard@Sun.COM 		bc -= xfer;
16189446SDaniel.Beauregard@Sun.COM 		dp += xfer;
16199446SDaniel.Beauregard@Sun.COM 		saddr += bsize;
16209446SDaniel.Beauregard@Sun.COM 		ofst = 0;
16217836SJohn.Forte@Sun.COM 	}
16227836SJohn.Forte@Sun.COM 
16237836SJohn.Forte@Sun.COM 	kmem_free(bp, bsize);
16247836SJohn.Forte@Sun.COM 
16259446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
16269446SDaniel.Beauregard@Sun.COM 
16277836SJohn.Forte@Sun.COM 	return (rval);
16287836SJohn.Forte@Sun.COM }
16297836SJohn.Forte@Sun.COM 
16307836SJohn.Forte@Sun.COM /*
16317836SJohn.Forte@Sun.COM  * ql_adm_op
16327836SJohn.Forte@Sun.COM  *	Performs qladm utility operations
16337836SJohn.Forte@Sun.COM  *
16347836SJohn.Forte@Sun.COM  * Input:
16357836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
16367836SJohn.Forte@Sun.COM  *	arg:	driver_op_t structure pointer.
16377836SJohn.Forte@Sun.COM  *	mode:	flags.
16387836SJohn.Forte@Sun.COM  *
16397836SJohn.Forte@Sun.COM  * Returns:
16407836SJohn.Forte@Sun.COM  *
16417836SJohn.Forte@Sun.COM  * Context:
16427836SJohn.Forte@Sun.COM  *	Kernel context.
16437836SJohn.Forte@Sun.COM  */
16447836SJohn.Forte@Sun.COM static int
ql_adm_op(ql_adapter_state_t * ha,void * arg,int mode)16457836SJohn.Forte@Sun.COM ql_adm_op(ql_adapter_state_t *ha, void *arg, int mode)
16467836SJohn.Forte@Sun.COM {
16477836SJohn.Forte@Sun.COM 	ql_adm_op_t		dop;
16487836SJohn.Forte@Sun.COM 	int			rval = 0;
16497836SJohn.Forte@Sun.COM 
16507836SJohn.Forte@Sun.COM 	if (ddi_copyin(arg, &dop, sizeof (ql_adm_op_t), mode) != 0) {
16517836SJohn.Forte@Sun.COM 		EL(ha, "failed, driver_op_t ddi_copyin\n");
16527836SJohn.Forte@Sun.COM 		return (EFAULT);
16537836SJohn.Forte@Sun.COM 	}
16547836SJohn.Forte@Sun.COM 
16559446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started, cmd=%xh, buffer=%llx,"
16567836SJohn.Forte@Sun.COM 	    " length=%xh, option=%xh\n", ha->instance, dop.cmd, dop.buffer,
16577836SJohn.Forte@Sun.COM 	    dop.length, dop.option);
16587836SJohn.Forte@Sun.COM 
16597836SJohn.Forte@Sun.COM 	switch (dop.cmd) {
16607836SJohn.Forte@Sun.COM 	case QL_ADAPTER_INFO:
16617836SJohn.Forte@Sun.COM 		rval = ql_adm_adapter_info(ha, &dop, mode);
16627836SJohn.Forte@Sun.COM 		break;
16637836SJohn.Forte@Sun.COM 
16647836SJohn.Forte@Sun.COM 	case QL_EXTENDED_LOGGING:
16657836SJohn.Forte@Sun.COM 		rval = ql_adm_extended_logging(ha, &dop);
16667836SJohn.Forte@Sun.COM 		break;
16677836SJohn.Forte@Sun.COM 
16687836SJohn.Forte@Sun.COM 	case QL_LOOP_RESET:
16697836SJohn.Forte@Sun.COM 		rval = ql_adm_loop_reset(ha);
16707836SJohn.Forte@Sun.COM 		break;
16717836SJohn.Forte@Sun.COM 
16727836SJohn.Forte@Sun.COM 	case QL_DEVICE_LIST:
16737836SJohn.Forte@Sun.COM 		rval = ql_adm_device_list(ha, &dop, mode);
16747836SJohn.Forte@Sun.COM 		break;
16757836SJohn.Forte@Sun.COM 
16767836SJohn.Forte@Sun.COM 	case QL_PROP_UPDATE_INT:
16777836SJohn.Forte@Sun.COM 		rval = ql_adm_prop_update_int(ha, &dop, mode);
16787836SJohn.Forte@Sun.COM 		break;
16797836SJohn.Forte@Sun.COM 
16807836SJohn.Forte@Sun.COM 	case QL_UPDATE_PROPERTIES:
16817836SJohn.Forte@Sun.COM 		rval = ql_adm_update_properties(ha);
16827836SJohn.Forte@Sun.COM 		break;
16837836SJohn.Forte@Sun.COM 
16847836SJohn.Forte@Sun.COM 	case QL_FW_DUMP:
16857836SJohn.Forte@Sun.COM 		rval = ql_adm_fw_dump(ha, &dop, arg, mode);
16867836SJohn.Forte@Sun.COM 		break;
16877836SJohn.Forte@Sun.COM 
16887836SJohn.Forte@Sun.COM 	case QL_NVRAM_LOAD:
16897836SJohn.Forte@Sun.COM 		rval = ql_adm_nvram_load(ha, &dop, mode);
16907836SJohn.Forte@Sun.COM 		break;
16917836SJohn.Forte@Sun.COM 
16927836SJohn.Forte@Sun.COM 	case QL_NVRAM_DUMP:
16937836SJohn.Forte@Sun.COM 		rval = ql_adm_nvram_dump(ha, &dop, mode);
16947836SJohn.Forte@Sun.COM 		break;
16957836SJohn.Forte@Sun.COM 
16967836SJohn.Forte@Sun.COM 	case QL_FLASH_LOAD:
16977836SJohn.Forte@Sun.COM 		rval = ql_adm_flash_load(ha, &dop, mode);
16987836SJohn.Forte@Sun.COM 		break;
16997836SJohn.Forte@Sun.COM 
17007836SJohn.Forte@Sun.COM 	case QL_VPD_LOAD:
17017836SJohn.Forte@Sun.COM 		rval = ql_adm_vpd_load(ha, &dop, mode);
17027836SJohn.Forte@Sun.COM 		break;
17037836SJohn.Forte@Sun.COM 
17047836SJohn.Forte@Sun.COM 	case QL_VPD_DUMP:
17057836SJohn.Forte@Sun.COM 		rval = ql_adm_vpd_dump(ha, &dop, mode);
17067836SJohn.Forte@Sun.COM 		break;
17077836SJohn.Forte@Sun.COM 
17087836SJohn.Forte@Sun.COM 	case QL_VPD_GETTAG:
17097836SJohn.Forte@Sun.COM 		rval = ql_adm_vpd_gettag(ha, &dop, mode);
17107836SJohn.Forte@Sun.COM 		break;
17117836SJohn.Forte@Sun.COM 
17127836SJohn.Forte@Sun.COM 	case QL_UPD_FWMODULE:
17137836SJohn.Forte@Sun.COM 		rval = ql_adm_updfwmodule(ha, &dop, mode);
17147836SJohn.Forte@Sun.COM 		break;
17157836SJohn.Forte@Sun.COM 
17167836SJohn.Forte@Sun.COM 	default:
17177836SJohn.Forte@Sun.COM 		EL(ha, "unsupported driver op cmd: %x\n", dop.cmd);
17187836SJohn.Forte@Sun.COM 		return (EINVAL);
17197836SJohn.Forte@Sun.COM 	}
17207836SJohn.Forte@Sun.COM 
17217836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
17227836SJohn.Forte@Sun.COM 
17237836SJohn.Forte@Sun.COM 	return (rval);
17247836SJohn.Forte@Sun.COM }
17257836SJohn.Forte@Sun.COM 
17267836SJohn.Forte@Sun.COM /*
17277836SJohn.Forte@Sun.COM  * ql_adm_adapter_info
17287836SJohn.Forte@Sun.COM  *	Performs qladm QL_ADAPTER_INFO command
17297836SJohn.Forte@Sun.COM  *
17307836SJohn.Forte@Sun.COM  * Input:
17317836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
17327836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
17337836SJohn.Forte@Sun.COM  *	mode:	flags.
17347836SJohn.Forte@Sun.COM  *
17357836SJohn.Forte@Sun.COM  * Returns:
17367836SJohn.Forte@Sun.COM  *
17377836SJohn.Forte@Sun.COM  * Context:
17387836SJohn.Forte@Sun.COM  *	Kernel context.
17397836SJohn.Forte@Sun.COM  */
17407836SJohn.Forte@Sun.COM static int
ql_adm_adapter_info(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)17417836SJohn.Forte@Sun.COM ql_adm_adapter_info(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
17427836SJohn.Forte@Sun.COM {
17437836SJohn.Forte@Sun.COM 	ql_adapter_info_t	hba;
17447836SJohn.Forte@Sun.COM 	uint8_t			*dp;
17457836SJohn.Forte@Sun.COM 	uint32_t		length;
17467836SJohn.Forte@Sun.COM 	int			rval, i;
17477836SJohn.Forte@Sun.COM 
17487836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
17497836SJohn.Forte@Sun.COM 
17507836SJohn.Forte@Sun.COM 	hba.device_id = ha->device_id;
17517836SJohn.Forte@Sun.COM 
175211924SDaniel.Beauregard@Sun.COM 	dp = CFG_IST(ha, CFG_CTRL_24258081) ?
17537836SJohn.Forte@Sun.COM 	    &ha->init_ctrl_blk.cb24.port_name[0] :
17547836SJohn.Forte@Sun.COM 	    &ha->init_ctrl_blk.cb.port_name[0];
17557836SJohn.Forte@Sun.COM 	bcopy(dp, hba.wwpn, 8);
17567836SJohn.Forte@Sun.COM 
17577836SJohn.Forte@Sun.COM 	hba.d_id = ha->d_id.b24;
17587836SJohn.Forte@Sun.COM 
17597836SJohn.Forte@Sun.COM 	if (ha->xioctl->fdesc.flash_size == 0 &&
17607836SJohn.Forte@Sun.COM 	    !(CFG_IST(ha, CFG_CTRL_2200) && !ha->subven_id)) {
17617836SJohn.Forte@Sun.COM 		if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
17627836SJohn.Forte@Sun.COM 			EL(ha, "ql_stall_driver failed\n");
17637836SJohn.Forte@Sun.COM 			return (EBUSY);
17647836SJohn.Forte@Sun.COM 		}
17657836SJohn.Forte@Sun.COM 
17669446SDaniel.Beauregard@Sun.COM 		if ((rval = ql_setup_fcache(ha)) != QL_SUCCESS) {
17677836SJohn.Forte@Sun.COM 			EL(ha, "ql_setup_flash failed=%xh\n", rval);
17687836SJohn.Forte@Sun.COM 			if (rval == QL_FUNCTION_TIMEOUT) {
17697836SJohn.Forte@Sun.COM 				return (EBUSY);
17707836SJohn.Forte@Sun.COM 			}
17717836SJohn.Forte@Sun.COM 			return (EIO);
17727836SJohn.Forte@Sun.COM 		}
17737836SJohn.Forte@Sun.COM 
17747836SJohn.Forte@Sun.COM 		/* Resume I/O */
177511924SDaniel.Beauregard@Sun.COM 		if (CFG_IST(ha, CFG_CTRL_24258081)) {
17767836SJohn.Forte@Sun.COM 			ql_restart_driver(ha);
17777836SJohn.Forte@Sun.COM 		} else {
17787836SJohn.Forte@Sun.COM 			EL(ha, "isp_abort_needed for restart\n");
17797836SJohn.Forte@Sun.COM 			ql_awaken_task_daemon(ha, NULL, ISP_ABORT_NEEDED,
17807836SJohn.Forte@Sun.COM 			    DRIVER_STALL);
17817836SJohn.Forte@Sun.COM 		}
17827836SJohn.Forte@Sun.COM 	}
17837836SJohn.Forte@Sun.COM 	hba.flash_size = ha->xioctl->fdesc.flash_size;
17847836SJohn.Forte@Sun.COM 
17857836SJohn.Forte@Sun.COM 	(void) strcpy(hba.driver_ver, QL_VERSION);
17867836SJohn.Forte@Sun.COM 
17877836SJohn.Forte@Sun.COM 	(void) sprintf(hba.fw_ver, "%d.%d.%d", ha->fw_major_version,
17887836SJohn.Forte@Sun.COM 	    ha->fw_minor_version, ha->fw_subminor_version);
17897836SJohn.Forte@Sun.COM 
17907836SJohn.Forte@Sun.COM 	bzero(hba.fcode_ver, sizeof (hba.fcode_ver));
17917836SJohn.Forte@Sun.COM 
17927836SJohn.Forte@Sun.COM 	/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
17937836SJohn.Forte@Sun.COM 	rval = ddi_getlongprop(DDI_DEV_T_ANY, ha->dip,
17949156SDaniel.Beauregard@Sun.COM 	    DDI_PROP_DONTPASS | DDI_PROP_CANSLEEP, "version", (caddr_t)&dp, &i);
17957836SJohn.Forte@Sun.COM 	length = i;
17967836SJohn.Forte@Sun.COM 	if (rval != DDI_PROP_SUCCESS) {
17977836SJohn.Forte@Sun.COM 		EL(ha, "failed, ddi_getlongprop=%xh\n", rval);
17987836SJohn.Forte@Sun.COM 	} else {
17997836SJohn.Forte@Sun.COM 		if (length > (uint32_t)sizeof (hba.fcode_ver)) {
18007836SJohn.Forte@Sun.COM 			length = sizeof (hba.fcode_ver) - 1;
18017836SJohn.Forte@Sun.COM 		}
18027836SJohn.Forte@Sun.COM 		bcopy((void *)dp, (void *)hba.fcode_ver, length);
18037836SJohn.Forte@Sun.COM 		kmem_free(dp, length);
18047836SJohn.Forte@Sun.COM 	}
18057836SJohn.Forte@Sun.COM 
18067836SJohn.Forte@Sun.COM 	if (ddi_copyout((void *)&hba, (void *)(uintptr_t)dop->buffer,
18079156SDaniel.Beauregard@Sun.COM 	    dop->length, mode) != 0) {
18087836SJohn.Forte@Sun.COM 		EL(ha, "failed, ddi_copyout\n");
18097836SJohn.Forte@Sun.COM 		return (EFAULT);
18107836SJohn.Forte@Sun.COM 	}
18117836SJohn.Forte@Sun.COM 
18127836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
18137836SJohn.Forte@Sun.COM 
18147836SJohn.Forte@Sun.COM 	return (0);
18157836SJohn.Forte@Sun.COM }
18167836SJohn.Forte@Sun.COM 
18177836SJohn.Forte@Sun.COM /*
18187836SJohn.Forte@Sun.COM  * ql_adm_extended_logging
18197836SJohn.Forte@Sun.COM  *	Performs qladm QL_EXTENDED_LOGGING command
18207836SJohn.Forte@Sun.COM  *
18217836SJohn.Forte@Sun.COM  * Input:
18227836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
18237836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
18247836SJohn.Forte@Sun.COM  *
18257836SJohn.Forte@Sun.COM  * Returns:
18267836SJohn.Forte@Sun.COM  *
18277836SJohn.Forte@Sun.COM  * Context:
18287836SJohn.Forte@Sun.COM  *	Kernel context.
18297836SJohn.Forte@Sun.COM  */
18307836SJohn.Forte@Sun.COM static int
ql_adm_extended_logging(ql_adapter_state_t * ha,ql_adm_op_t * dop)18317836SJohn.Forte@Sun.COM ql_adm_extended_logging(ql_adapter_state_t *ha, ql_adm_op_t *dop)
18327836SJohn.Forte@Sun.COM {
18337836SJohn.Forte@Sun.COM 	char	prop_name[MAX_PROP_LENGTH];
18347836SJohn.Forte@Sun.COM 	int	rval;
18357836SJohn.Forte@Sun.COM 
18367836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
18377836SJohn.Forte@Sun.COM 
18387836SJohn.Forte@Sun.COM 	(void) sprintf(prop_name, "hba%d-extended-logging", ha->instance);
18397836SJohn.Forte@Sun.COM 
18407836SJohn.Forte@Sun.COM 	/*LINTED [Solaris DDI_DEV_T_NONE Lint warning]*/
18417836SJohn.Forte@Sun.COM 	rval = ddi_prop_update_int(DDI_DEV_T_NONE, ha->dip, prop_name,
18427836SJohn.Forte@Sun.COM 	    (int)dop->option);
18437836SJohn.Forte@Sun.COM 	if (rval != DDI_PROP_SUCCESS) {
18447836SJohn.Forte@Sun.COM 		EL(ha, "failed, prop_update = %xh\n", rval);
18457836SJohn.Forte@Sun.COM 		return (EINVAL);
18467836SJohn.Forte@Sun.COM 	} else {
18477836SJohn.Forte@Sun.COM 		dop->option ?
18487836SJohn.Forte@Sun.COM 		    (ha->cfg_flags |= CFG_ENABLE_EXTENDED_LOGGING) :
18497836SJohn.Forte@Sun.COM 		    (ha->cfg_flags &= ~CFG_ENABLE_EXTENDED_LOGGING);
18507836SJohn.Forte@Sun.COM 	}
18517836SJohn.Forte@Sun.COM 
18527836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
18537836SJohn.Forte@Sun.COM 
18547836SJohn.Forte@Sun.COM 	return (0);
18557836SJohn.Forte@Sun.COM }
18567836SJohn.Forte@Sun.COM 
18577836SJohn.Forte@Sun.COM /*
18587836SJohn.Forte@Sun.COM  * ql_adm_loop_reset
18597836SJohn.Forte@Sun.COM  *	Performs qladm QL_LOOP_RESET command
18607836SJohn.Forte@Sun.COM  *
18617836SJohn.Forte@Sun.COM  * Input:
18627836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
18637836SJohn.Forte@Sun.COM  *
18647836SJohn.Forte@Sun.COM  * Returns:
18657836SJohn.Forte@Sun.COM  *
18667836SJohn.Forte@Sun.COM  * Context:
18677836SJohn.Forte@Sun.COM  *	Kernel context.
18687836SJohn.Forte@Sun.COM  */
18697836SJohn.Forte@Sun.COM static int
ql_adm_loop_reset(ql_adapter_state_t * ha)18707836SJohn.Forte@Sun.COM ql_adm_loop_reset(ql_adapter_state_t *ha)
18717836SJohn.Forte@Sun.COM {
18727836SJohn.Forte@Sun.COM 	int	rval;
18737836SJohn.Forte@Sun.COM 
18747836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
18757836SJohn.Forte@Sun.COM 
18767836SJohn.Forte@Sun.COM 	if (ha->task_daemon_flags & LOOP_DOWN) {
18777836SJohn.Forte@Sun.COM 		(void) ql_full_login_lip(ha);
18787836SJohn.Forte@Sun.COM 	} else if ((rval = ql_full_login_lip(ha)) != QL_SUCCESS) {
18797836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_initiate_lip=%xh\n", rval);
18807836SJohn.Forte@Sun.COM 		return (EIO);
18817836SJohn.Forte@Sun.COM 	}
18827836SJohn.Forte@Sun.COM 
18837836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
18847836SJohn.Forte@Sun.COM 
18857836SJohn.Forte@Sun.COM 	return (0);
18867836SJohn.Forte@Sun.COM }
18877836SJohn.Forte@Sun.COM 
18887836SJohn.Forte@Sun.COM /*
18897836SJohn.Forte@Sun.COM  * ql_adm_device_list
18907836SJohn.Forte@Sun.COM  *	Performs qladm QL_DEVICE_LIST command
18917836SJohn.Forte@Sun.COM  *
18927836SJohn.Forte@Sun.COM  * Input:
18937836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
18947836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
18957836SJohn.Forte@Sun.COM  *	mode:	flags.
18967836SJohn.Forte@Sun.COM  *
18977836SJohn.Forte@Sun.COM  * Returns:
18987836SJohn.Forte@Sun.COM  *
18997836SJohn.Forte@Sun.COM  * Context:
19007836SJohn.Forte@Sun.COM  *	Kernel context.
19017836SJohn.Forte@Sun.COM  */
19027836SJohn.Forte@Sun.COM static int
ql_adm_device_list(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)19037836SJohn.Forte@Sun.COM ql_adm_device_list(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
19047836SJohn.Forte@Sun.COM {
19057836SJohn.Forte@Sun.COM 	ql_device_info_t	dev;
19067836SJohn.Forte@Sun.COM 	ql_link_t		*link;
19077836SJohn.Forte@Sun.COM 	ql_tgt_t		*tq;
19087836SJohn.Forte@Sun.COM 	uint32_t		index, cnt;
19097836SJohn.Forte@Sun.COM 
19107836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
19117836SJohn.Forte@Sun.COM 
19127836SJohn.Forte@Sun.COM 	cnt = 0;
19137836SJohn.Forte@Sun.COM 	dev.address = 0xffffffff;
19147836SJohn.Forte@Sun.COM 
19157836SJohn.Forte@Sun.COM 	/* Scan port list for requested target and fill in the values */
19167836SJohn.Forte@Sun.COM 	for (link = NULL, index = 0;
19177836SJohn.Forte@Sun.COM 	    index < DEVICE_HEAD_LIST_SIZE && link == NULL; index++) {
19187836SJohn.Forte@Sun.COM 		for (link = ha->dev[index].first; link != NULL;
19197836SJohn.Forte@Sun.COM 		    link = link->next) {
19207836SJohn.Forte@Sun.COM 			tq = link->base_address;
19217836SJohn.Forte@Sun.COM 
19227836SJohn.Forte@Sun.COM 			if (!VALID_TARGET_ID(ha, tq->loop_id)) {
19237836SJohn.Forte@Sun.COM 				continue;
19247836SJohn.Forte@Sun.COM 			}
19257836SJohn.Forte@Sun.COM 			if (cnt != dop->option) {
19267836SJohn.Forte@Sun.COM 				cnt++;
19277836SJohn.Forte@Sun.COM 				continue;
19287836SJohn.Forte@Sun.COM 			}
19297836SJohn.Forte@Sun.COM 			/* fill in the values */
19307836SJohn.Forte@Sun.COM 			bcopy(tq->port_name, dev.wwpn, 8);
19317836SJohn.Forte@Sun.COM 			dev.address = tq->d_id.b24;
19327836SJohn.Forte@Sun.COM 			dev.loop_id = tq->loop_id;
19337836SJohn.Forte@Sun.COM 			if (tq->flags & TQF_TAPE_DEVICE) {
19347836SJohn.Forte@Sun.COM 				dev.type = FCT_TAPE;
19357836SJohn.Forte@Sun.COM 			} else if (tq->flags & TQF_INITIATOR_DEVICE) {
19367836SJohn.Forte@Sun.COM 				dev.type = FCT_INITIATOR;
19377836SJohn.Forte@Sun.COM 			} else {
19387836SJohn.Forte@Sun.COM 				dev.type = FCT_TARGET;
19397836SJohn.Forte@Sun.COM 			}
19407836SJohn.Forte@Sun.COM 			break;
19417836SJohn.Forte@Sun.COM 		}
19427836SJohn.Forte@Sun.COM 	}
19437836SJohn.Forte@Sun.COM 
19447836SJohn.Forte@Sun.COM 	if (ddi_copyout((void *)&dev, (void *)(uintptr_t)dop->buffer,
19459156SDaniel.Beauregard@Sun.COM 	    dop->length, mode) != 0) {
19467836SJohn.Forte@Sun.COM 		EL(ha, "failed, ddi_copyout\n");
19477836SJohn.Forte@Sun.COM 		return (EFAULT);
19487836SJohn.Forte@Sun.COM 	}
19497836SJohn.Forte@Sun.COM 
19507836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
19517836SJohn.Forte@Sun.COM 
19527836SJohn.Forte@Sun.COM 	return (0);
19537836SJohn.Forte@Sun.COM }
19547836SJohn.Forte@Sun.COM 
19557836SJohn.Forte@Sun.COM /*
19567836SJohn.Forte@Sun.COM  * ql_adm_update_properties
19577836SJohn.Forte@Sun.COM  *	Performs qladm QL_UPDATE_PROPERTIES command
19587836SJohn.Forte@Sun.COM  *
19597836SJohn.Forte@Sun.COM  * Input:
19607836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
19617836SJohn.Forte@Sun.COM  *
19627836SJohn.Forte@Sun.COM  * Returns:
19637836SJohn.Forte@Sun.COM  *
19647836SJohn.Forte@Sun.COM  * Context:
19657836SJohn.Forte@Sun.COM  *	Kernel context.
19667836SJohn.Forte@Sun.COM  */
19677836SJohn.Forte@Sun.COM static int
ql_adm_update_properties(ql_adapter_state_t * ha)19687836SJohn.Forte@Sun.COM ql_adm_update_properties(ql_adapter_state_t *ha)
19697836SJohn.Forte@Sun.COM {
19707836SJohn.Forte@Sun.COM 	ql_comb_init_cb_t	init_ctrl_blk;
19717836SJohn.Forte@Sun.COM 	ql_comb_ip_init_cb_t	ip_init_ctrl_blk;
19727836SJohn.Forte@Sun.COM 
19737836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
19747836SJohn.Forte@Sun.COM 
19757836SJohn.Forte@Sun.COM 	/* Stall driver instance. */
19767836SJohn.Forte@Sun.COM 	(void) ql_stall_driver(ha, 0);
19777836SJohn.Forte@Sun.COM 
19787836SJohn.Forte@Sun.COM 	/* Save init control blocks. */
19797836SJohn.Forte@Sun.COM 	bcopy(&ha->init_ctrl_blk, &init_ctrl_blk, sizeof (ql_comb_init_cb_t));
19807836SJohn.Forte@Sun.COM 	bcopy(&ha->ip_init_ctrl_blk, &ip_init_ctrl_blk,
19817836SJohn.Forte@Sun.COM 	    sizeof (ql_comb_ip_init_cb_t));
19827836SJohn.Forte@Sun.COM 
19837836SJohn.Forte@Sun.COM 	/* Update PCI configration. */
19847836SJohn.Forte@Sun.COM 	(void) ql_pci_sbus_config(ha);
19857836SJohn.Forte@Sun.COM 
19867836SJohn.Forte@Sun.COM 	/* Get configuration properties. */
19877836SJohn.Forte@Sun.COM 	(void) ql_nvram_config(ha);
19887836SJohn.Forte@Sun.COM 
19897836SJohn.Forte@Sun.COM 	/* Check for init firmware required. */
19907836SJohn.Forte@Sun.COM 	if (bcmp(&ha->init_ctrl_blk, &init_ctrl_blk,
19917836SJohn.Forte@Sun.COM 	    sizeof (ql_comb_init_cb_t)) != 0 ||
19927836SJohn.Forte@Sun.COM 	    bcmp(&ha->ip_init_ctrl_blk, &ip_init_ctrl_blk,
19937836SJohn.Forte@Sun.COM 	    sizeof (ql_comb_ip_init_cb_t)) != 0) {
19947836SJohn.Forte@Sun.COM 
19957836SJohn.Forte@Sun.COM 		EL(ha, "isp_abort_needed\n");
19967836SJohn.Forte@Sun.COM 		ha->loop_down_timer = LOOP_DOWN_TIMER_START;
19977836SJohn.Forte@Sun.COM 		TASK_DAEMON_LOCK(ha);
19987836SJohn.Forte@Sun.COM 		ha->task_daemon_flags |= LOOP_DOWN | ISP_ABORT_NEEDED;
19997836SJohn.Forte@Sun.COM 		TASK_DAEMON_UNLOCK(ha);
20007836SJohn.Forte@Sun.COM 	}
20017836SJohn.Forte@Sun.COM 
20027836SJohn.Forte@Sun.COM 	/* Update AEN queue. */
20037836SJohn.Forte@Sun.COM 	if (ha->xioctl->flags & QL_AEN_TRACKING_ENABLE) {
20047836SJohn.Forte@Sun.COM 		ql_enqueue_aen(ha, MBA_PORT_UPDATE, NULL);
20057836SJohn.Forte@Sun.COM 	}
20067836SJohn.Forte@Sun.COM 
20077836SJohn.Forte@Sun.COM 	/* Restart driver instance. */
20087836SJohn.Forte@Sun.COM 	ql_restart_driver(ha);
20097836SJohn.Forte@Sun.COM 
20107836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
20117836SJohn.Forte@Sun.COM 
20127836SJohn.Forte@Sun.COM 	return (0);
20137836SJohn.Forte@Sun.COM }
20147836SJohn.Forte@Sun.COM 
20157836SJohn.Forte@Sun.COM /*
20167836SJohn.Forte@Sun.COM  * ql_adm_prop_update_int
20177836SJohn.Forte@Sun.COM  *	Performs qladm QL_PROP_UPDATE_INT command
20187836SJohn.Forte@Sun.COM  *
20197836SJohn.Forte@Sun.COM  * Input:
20207836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
20217836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
20227836SJohn.Forte@Sun.COM  *	mode:	flags.
20237836SJohn.Forte@Sun.COM  *
20247836SJohn.Forte@Sun.COM  * Returns:
20257836SJohn.Forte@Sun.COM  *
20267836SJohn.Forte@Sun.COM  * Context:
20277836SJohn.Forte@Sun.COM  *	Kernel context.
20287836SJohn.Forte@Sun.COM  */
20297836SJohn.Forte@Sun.COM static int
ql_adm_prop_update_int(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)20307836SJohn.Forte@Sun.COM ql_adm_prop_update_int(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
20317836SJohn.Forte@Sun.COM {
20327836SJohn.Forte@Sun.COM 	char	*prop_name;
20337836SJohn.Forte@Sun.COM 	int	rval;
20347836SJohn.Forte@Sun.COM 
20357836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
20367836SJohn.Forte@Sun.COM 
20377836SJohn.Forte@Sun.COM 	prop_name = kmem_zalloc(dop->length, KM_SLEEP);
20387836SJohn.Forte@Sun.COM 	if (prop_name == NULL) {
20397836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
20407836SJohn.Forte@Sun.COM 		return (ENOMEM);
20417836SJohn.Forte@Sun.COM 	}
20427836SJohn.Forte@Sun.COM 
20437836SJohn.Forte@Sun.COM 	if (ddi_copyin((void *)(uintptr_t)dop->buffer, prop_name, dop->length,
20447836SJohn.Forte@Sun.COM 	    mode) != 0) {
20457836SJohn.Forte@Sun.COM 		EL(ha, "failed, prop_name ddi_copyin\n");
20467836SJohn.Forte@Sun.COM 		kmem_free(prop_name, dop->length);
20477836SJohn.Forte@Sun.COM 		return (EFAULT);
20487836SJohn.Forte@Sun.COM 	}
20497836SJohn.Forte@Sun.COM 
20507836SJohn.Forte@Sun.COM 	/*LINTED [Solaris DDI_DEV_T_ANY Lint warning]*/
20517836SJohn.Forte@Sun.COM 	if ((rval = ddi_prop_update_int(DDI_DEV_T_NONE, ha->dip, prop_name,
20527836SJohn.Forte@Sun.COM 	    (int)dop->option)) != DDI_PROP_SUCCESS) {
20537836SJohn.Forte@Sun.COM 		EL(ha, "failed, prop_update=%xh\n", rval);
20547836SJohn.Forte@Sun.COM 		kmem_free(prop_name, dop->length);
20557836SJohn.Forte@Sun.COM 		return (EINVAL);
20567836SJohn.Forte@Sun.COM 	}
20577836SJohn.Forte@Sun.COM 
20587836SJohn.Forte@Sun.COM 	kmem_free(prop_name, dop->length);
20597836SJohn.Forte@Sun.COM 
20607836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
20617836SJohn.Forte@Sun.COM 
20627836SJohn.Forte@Sun.COM 	return (0);
20637836SJohn.Forte@Sun.COM }
20647836SJohn.Forte@Sun.COM 
20657836SJohn.Forte@Sun.COM /*
20667836SJohn.Forte@Sun.COM  * ql_adm_fw_dump
20677836SJohn.Forte@Sun.COM  *	Performs qladm QL_FW_DUMP command
20687836SJohn.Forte@Sun.COM  *
20697836SJohn.Forte@Sun.COM  * Input:
20707836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
20717836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
20727836SJohn.Forte@Sun.COM  *	udop:	user space ql_adm_op_t structure pointer.
20737836SJohn.Forte@Sun.COM  *	mode:	flags.
20747836SJohn.Forte@Sun.COM  *
20757836SJohn.Forte@Sun.COM  * Returns:
20767836SJohn.Forte@Sun.COM  *
20777836SJohn.Forte@Sun.COM  * Context:
20787836SJohn.Forte@Sun.COM  *	Kernel context.
20797836SJohn.Forte@Sun.COM  */
20807836SJohn.Forte@Sun.COM static int
ql_adm_fw_dump(ql_adapter_state_t * ha,ql_adm_op_t * dop,void * udop,int mode)20817836SJohn.Forte@Sun.COM ql_adm_fw_dump(ql_adapter_state_t *ha, ql_adm_op_t *dop, void *udop, int mode)
20827836SJohn.Forte@Sun.COM {
20837836SJohn.Forte@Sun.COM 	caddr_t	dmp;
20847836SJohn.Forte@Sun.COM 
20857836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
20867836SJohn.Forte@Sun.COM 
20877836SJohn.Forte@Sun.COM 	if (dop->length < ha->risc_dump_size) {
20887836SJohn.Forte@Sun.COM 		EL(ha, "failed, incorrect length=%xh, size=%xh\n",
20897836SJohn.Forte@Sun.COM 		    dop->length, ha->risc_dump_size);
20907836SJohn.Forte@Sun.COM 		return (EINVAL);
20917836SJohn.Forte@Sun.COM 	}
20927836SJohn.Forte@Sun.COM 
20939156SDaniel.Beauregard@Sun.COM 	if (ha->ql_dump_state & QL_DUMP_VALID) {
20947836SJohn.Forte@Sun.COM 		dmp = kmem_zalloc(ha->risc_dump_size, KM_SLEEP);
20957836SJohn.Forte@Sun.COM 		if (dmp == NULL) {
20967836SJohn.Forte@Sun.COM 			EL(ha, "failed, kmem_zalloc\n");
20977836SJohn.Forte@Sun.COM 			return (ENOMEM);
20987836SJohn.Forte@Sun.COM 		}
20997836SJohn.Forte@Sun.COM 
21007836SJohn.Forte@Sun.COM 		dop->length = (uint32_t)ql_ascii_fw_dump(ha, dmp);
21017836SJohn.Forte@Sun.COM 		if (ddi_copyout((void *)dmp, (void *)(uintptr_t)dop->buffer,
21027836SJohn.Forte@Sun.COM 		    dop->length, mode) != 0) {
21037836SJohn.Forte@Sun.COM 			EL(ha, "failed, ddi_copyout\n");
21047836SJohn.Forte@Sun.COM 			kmem_free(dmp, ha->risc_dump_size);
21057836SJohn.Forte@Sun.COM 			return (EFAULT);
21067836SJohn.Forte@Sun.COM 		}
21077836SJohn.Forte@Sun.COM 
21087836SJohn.Forte@Sun.COM 		kmem_free(dmp, ha->risc_dump_size);
21099156SDaniel.Beauregard@Sun.COM 		ha->ql_dump_state |= QL_DUMP_UPLOADED;
21107836SJohn.Forte@Sun.COM 
21117836SJohn.Forte@Sun.COM 	} else {
21127836SJohn.Forte@Sun.COM 		EL(ha, "failed, no dump file\n");
21137836SJohn.Forte@Sun.COM 		dop->length = 0;
21147836SJohn.Forte@Sun.COM 	}
21157836SJohn.Forte@Sun.COM 
21167836SJohn.Forte@Sun.COM 	if (ddi_copyout(dop, udop, sizeof (ql_adm_op_t), mode) != 0) {
21177836SJohn.Forte@Sun.COM 		EL(ha, "failed, driver_op_t ddi_copyout\n");
21187836SJohn.Forte@Sun.COM 		return (EFAULT);
21197836SJohn.Forte@Sun.COM 	}
21207836SJohn.Forte@Sun.COM 
21217836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
21227836SJohn.Forte@Sun.COM 
21237836SJohn.Forte@Sun.COM 	return (0);
21247836SJohn.Forte@Sun.COM }
21257836SJohn.Forte@Sun.COM 
21267836SJohn.Forte@Sun.COM /*
21277836SJohn.Forte@Sun.COM  * ql_adm_nvram_dump
21287836SJohn.Forte@Sun.COM  *	Performs qladm QL_NVRAM_DUMP command
21297836SJohn.Forte@Sun.COM  *
21307836SJohn.Forte@Sun.COM  * Input:
21317836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
21327836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
21337836SJohn.Forte@Sun.COM  *	mode:	flags.
21347836SJohn.Forte@Sun.COM  *
21357836SJohn.Forte@Sun.COM  * Returns:
21367836SJohn.Forte@Sun.COM  *
21377836SJohn.Forte@Sun.COM  * Context:
21387836SJohn.Forte@Sun.COM  *	Kernel context.
21397836SJohn.Forte@Sun.COM  */
21407836SJohn.Forte@Sun.COM static int
ql_adm_nvram_dump(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)21417836SJohn.Forte@Sun.COM ql_adm_nvram_dump(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
21427836SJohn.Forte@Sun.COM {
21437836SJohn.Forte@Sun.COM 	int		rval;
21447836SJohn.Forte@Sun.COM 
21457836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
21467836SJohn.Forte@Sun.COM 
214711541SDaniel.Beauregard@Sun.COM 	if (dop->length < ha->nvram_cache->size) {
214811541SDaniel.Beauregard@Sun.COM 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
214911541SDaniel.Beauregard@Sun.COM 		    ha->nvram_cache->size);
21507836SJohn.Forte@Sun.COM 		return (EINVAL);
21517836SJohn.Forte@Sun.COM 	}
21527836SJohn.Forte@Sun.COM 
21537836SJohn.Forte@Sun.COM 	if ((rval = ql_nv_util_dump(ha, (void *)(uintptr_t)dop->buffer,
21547836SJohn.Forte@Sun.COM 	    mode)) != 0) {
21557836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_nv_util_dump\n");
21567836SJohn.Forte@Sun.COM 	} else {
21577836SJohn.Forte@Sun.COM 		/*EMPTY*/
21587836SJohn.Forte@Sun.COM 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
21597836SJohn.Forte@Sun.COM 	}
21607836SJohn.Forte@Sun.COM 
21617836SJohn.Forte@Sun.COM 	return (rval);
21627836SJohn.Forte@Sun.COM }
21637836SJohn.Forte@Sun.COM 
21647836SJohn.Forte@Sun.COM /*
21657836SJohn.Forte@Sun.COM  * ql_adm_nvram_load
21667836SJohn.Forte@Sun.COM  *	Performs qladm QL_NVRAM_LOAD command
21677836SJohn.Forte@Sun.COM  *
21687836SJohn.Forte@Sun.COM  * Input:
21697836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
21707836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
21717836SJohn.Forte@Sun.COM  *	mode:	flags.
21727836SJohn.Forte@Sun.COM  *
21737836SJohn.Forte@Sun.COM  * Returns:
21747836SJohn.Forte@Sun.COM  *
21757836SJohn.Forte@Sun.COM  * Context:
21767836SJohn.Forte@Sun.COM  *	Kernel context.
21777836SJohn.Forte@Sun.COM  */
21787836SJohn.Forte@Sun.COM static int
ql_adm_nvram_load(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)21797836SJohn.Forte@Sun.COM ql_adm_nvram_load(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
21807836SJohn.Forte@Sun.COM {
21817836SJohn.Forte@Sun.COM 	int		rval;
21827836SJohn.Forte@Sun.COM 
21837836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
21847836SJohn.Forte@Sun.COM 
218511541SDaniel.Beauregard@Sun.COM 	if (dop->length < ha->nvram_cache->size) {
218611541SDaniel.Beauregard@Sun.COM 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
218711541SDaniel.Beauregard@Sun.COM 		    ha->nvram_cache->size);
21887836SJohn.Forte@Sun.COM 		return (EINVAL);
21897836SJohn.Forte@Sun.COM 	}
21907836SJohn.Forte@Sun.COM 
21917836SJohn.Forte@Sun.COM 	if ((rval = ql_nv_util_load(ha, (void *)(uintptr_t)dop->buffer,
21927836SJohn.Forte@Sun.COM 	    mode)) != 0) {
21937836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_nv_util_dump\n");
21947836SJohn.Forte@Sun.COM 	} else {
21957836SJohn.Forte@Sun.COM 		/*EMPTY*/
21967836SJohn.Forte@Sun.COM 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
21977836SJohn.Forte@Sun.COM 	}
21987836SJohn.Forte@Sun.COM 
21997836SJohn.Forte@Sun.COM 	return (rval);
22007836SJohn.Forte@Sun.COM }
22017836SJohn.Forte@Sun.COM 
22027836SJohn.Forte@Sun.COM /*
22037836SJohn.Forte@Sun.COM  * ql_adm_flash_load
22047836SJohn.Forte@Sun.COM  *	Performs qladm QL_FLASH_LOAD command
22057836SJohn.Forte@Sun.COM  *
22067836SJohn.Forte@Sun.COM  * Input:
22077836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
22087836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
22097836SJohn.Forte@Sun.COM  *	mode:	flags.
22107836SJohn.Forte@Sun.COM  *
22117836SJohn.Forte@Sun.COM  * Returns:
22127836SJohn.Forte@Sun.COM  *
22137836SJohn.Forte@Sun.COM  * Context:
22147836SJohn.Forte@Sun.COM  *	Kernel context.
22157836SJohn.Forte@Sun.COM  */
22167836SJohn.Forte@Sun.COM static int
ql_adm_flash_load(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)22177836SJohn.Forte@Sun.COM ql_adm_flash_load(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
22187836SJohn.Forte@Sun.COM {
22197836SJohn.Forte@Sun.COM 	uint8_t	*dp;
22207836SJohn.Forte@Sun.COM 	int	rval;
22217836SJohn.Forte@Sun.COM 
22227836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
22237836SJohn.Forte@Sun.COM 
22247836SJohn.Forte@Sun.COM 	if ((dp = kmem_zalloc(dop->length, KM_SLEEP)) == NULL) {
22257836SJohn.Forte@Sun.COM 		EL(ha, "failed, kmem_zalloc\n");
22267836SJohn.Forte@Sun.COM 		return (ENOMEM);
22277836SJohn.Forte@Sun.COM 	}
22287836SJohn.Forte@Sun.COM 
22297836SJohn.Forte@Sun.COM 	if (ddi_copyin((void *)(uintptr_t)dop->buffer, dp, dop->length,
22307836SJohn.Forte@Sun.COM 	    mode) != 0) {
22317836SJohn.Forte@Sun.COM 		EL(ha, "ddi_copyin failed\n");
22327836SJohn.Forte@Sun.COM 		kmem_free(dp, dop->length);
22337836SJohn.Forte@Sun.COM 		return (EFAULT);
22347836SJohn.Forte@Sun.COM 	}
22357836SJohn.Forte@Sun.COM 
22367836SJohn.Forte@Sun.COM 	if (ql_stall_driver(ha, 0) != QL_SUCCESS) {
22377836SJohn.Forte@Sun.COM 		EL(ha, "ql_stall_driver failed\n");
22387836SJohn.Forte@Sun.COM 		kmem_free(dp, dop->length);
22397836SJohn.Forte@Sun.COM 		return (EBUSY);
22407836SJohn.Forte@Sun.COM 	}
22417836SJohn.Forte@Sun.COM 
224211924SDaniel.Beauregard@Sun.COM 	rval = (CFG_IST(ha, CFG_CTRL_24258081) ?
22437836SJohn.Forte@Sun.COM 	    ql_24xx_load_flash(ha, dp, dop->length, dop->option) :
22447836SJohn.Forte@Sun.COM 	    ql_load_flash(ha, dp, dop->length));
22457836SJohn.Forte@Sun.COM 
22467836SJohn.Forte@Sun.COM 	ql_restart_driver(ha);
22477836SJohn.Forte@Sun.COM 
22487836SJohn.Forte@Sun.COM 	kmem_free(dp, dop->length);
22497836SJohn.Forte@Sun.COM 
22507836SJohn.Forte@Sun.COM 	if (rval != QL_SUCCESS) {
22517836SJohn.Forte@Sun.COM 		EL(ha, "failed\n");
22527836SJohn.Forte@Sun.COM 		return (EIO);
22537836SJohn.Forte@Sun.COM 	}
22547836SJohn.Forte@Sun.COM 
22557836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
22567836SJohn.Forte@Sun.COM 
22577836SJohn.Forte@Sun.COM 	return (0);
22587836SJohn.Forte@Sun.COM }
22597836SJohn.Forte@Sun.COM 
22607836SJohn.Forte@Sun.COM /*
22617836SJohn.Forte@Sun.COM  * ql_adm_vpd_dump
22627836SJohn.Forte@Sun.COM  *	Performs qladm QL_VPD_DUMP command
22637836SJohn.Forte@Sun.COM  *
22647836SJohn.Forte@Sun.COM  * Input:
22657836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
22667836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
22677836SJohn.Forte@Sun.COM  *	mode:	flags.
22687836SJohn.Forte@Sun.COM  *
22697836SJohn.Forte@Sun.COM  * Returns:
22707836SJohn.Forte@Sun.COM  *
22717836SJohn.Forte@Sun.COM  * Context:
22727836SJohn.Forte@Sun.COM  *	Kernel context.
22737836SJohn.Forte@Sun.COM  */
22747836SJohn.Forte@Sun.COM static int
ql_adm_vpd_dump(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)22757836SJohn.Forte@Sun.COM ql_adm_vpd_dump(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
22767836SJohn.Forte@Sun.COM {
22777836SJohn.Forte@Sun.COM 	int		rval;
22787836SJohn.Forte@Sun.COM 
22797836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
22807836SJohn.Forte@Sun.COM 
228111924SDaniel.Beauregard@Sun.COM 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
22827836SJohn.Forte@Sun.COM 		EL(ha, "hba does not support VPD\n");
22837836SJohn.Forte@Sun.COM 		return (EINVAL);
22847836SJohn.Forte@Sun.COM 	}
22857836SJohn.Forte@Sun.COM 
22867836SJohn.Forte@Sun.COM 	if (dop->length < QL_24XX_VPD_SIZE) {
22877836SJohn.Forte@Sun.COM 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
22887836SJohn.Forte@Sun.COM 		    QL_24XX_VPD_SIZE);
22897836SJohn.Forte@Sun.COM 		return (EINVAL);
22907836SJohn.Forte@Sun.COM 	}
22917836SJohn.Forte@Sun.COM 
22929156SDaniel.Beauregard@Sun.COM 	if ((rval = ql_vpd_dump(ha, (void *)(uintptr_t)dop->buffer, mode))
22939156SDaniel.Beauregard@Sun.COM 	    != 0) {
22947836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_vpd_dump\n");
22957836SJohn.Forte@Sun.COM 	} else {
22967836SJohn.Forte@Sun.COM 		/*EMPTY*/
22977836SJohn.Forte@Sun.COM 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
22987836SJohn.Forte@Sun.COM 	}
22997836SJohn.Forte@Sun.COM 
23007836SJohn.Forte@Sun.COM 	return (rval);
23017836SJohn.Forte@Sun.COM }
23027836SJohn.Forte@Sun.COM 
23037836SJohn.Forte@Sun.COM /*
23047836SJohn.Forte@Sun.COM  * ql_adm_vpd_load
23057836SJohn.Forte@Sun.COM  *	Performs qladm QL_VPD_LOAD command
23067836SJohn.Forte@Sun.COM  *
23077836SJohn.Forte@Sun.COM  * Input:
23087836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
23097836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
23107836SJohn.Forte@Sun.COM  *	mode:	flags.
23117836SJohn.Forte@Sun.COM  *
23127836SJohn.Forte@Sun.COM  * Returns:
23137836SJohn.Forte@Sun.COM  *
23147836SJohn.Forte@Sun.COM  * Context:
23157836SJohn.Forte@Sun.COM  *	Kernel context.
23167836SJohn.Forte@Sun.COM  */
23177836SJohn.Forte@Sun.COM static int
ql_adm_vpd_load(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)23187836SJohn.Forte@Sun.COM ql_adm_vpd_load(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
23197836SJohn.Forte@Sun.COM {
23207836SJohn.Forte@Sun.COM 	int		rval;
23217836SJohn.Forte@Sun.COM 
23227836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
23237836SJohn.Forte@Sun.COM 
232411924SDaniel.Beauregard@Sun.COM 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
23257836SJohn.Forte@Sun.COM 		EL(ha, "hba does not support VPD\n");
23267836SJohn.Forte@Sun.COM 		return (EINVAL);
23277836SJohn.Forte@Sun.COM 	}
23287836SJohn.Forte@Sun.COM 
23297836SJohn.Forte@Sun.COM 	if (dop->length < QL_24XX_VPD_SIZE) {
23307836SJohn.Forte@Sun.COM 		EL(ha, "failed, length=%xh, size=%xh\n", dop->length,
23317836SJohn.Forte@Sun.COM 		    QL_24XX_VPD_SIZE);
23327836SJohn.Forte@Sun.COM 		return (EINVAL);
23337836SJohn.Forte@Sun.COM 	}
23347836SJohn.Forte@Sun.COM 
23359156SDaniel.Beauregard@Sun.COM 	if ((rval = ql_vpd_load(ha, (void *)(uintptr_t)dop->buffer, mode))
23369156SDaniel.Beauregard@Sun.COM 	    != 0) {
23377836SJohn.Forte@Sun.COM 		EL(ha, "failed, ql_vpd_dump\n");
23387836SJohn.Forte@Sun.COM 	} else {
23397836SJohn.Forte@Sun.COM 		/*EMPTY*/
23407836SJohn.Forte@Sun.COM 		QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
23417836SJohn.Forte@Sun.COM 	}
23427836SJohn.Forte@Sun.COM 
23437836SJohn.Forte@Sun.COM 	return (rval);
23447836SJohn.Forte@Sun.COM }
23457836SJohn.Forte@Sun.COM 
23467836SJohn.Forte@Sun.COM /*
23477836SJohn.Forte@Sun.COM  * ql_adm_vpd_gettag
23487836SJohn.Forte@Sun.COM  *	Performs qladm QL_VPD_GETTAG command
23497836SJohn.Forte@Sun.COM  *
23507836SJohn.Forte@Sun.COM  * Input:
23517836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
23527836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
23537836SJohn.Forte@Sun.COM  *	mode:	flags.
23547836SJohn.Forte@Sun.COM  *
23557836SJohn.Forte@Sun.COM  * Returns:
23567836SJohn.Forte@Sun.COM  *
23577836SJohn.Forte@Sun.COM  * Context:
23587836SJohn.Forte@Sun.COM  *	Kernel context.
23597836SJohn.Forte@Sun.COM  */
23607836SJohn.Forte@Sun.COM static int
ql_adm_vpd_gettag(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)23617836SJohn.Forte@Sun.COM ql_adm_vpd_gettag(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
23627836SJohn.Forte@Sun.COM {
23637836SJohn.Forte@Sun.COM 	int		rval = 0;
23647836SJohn.Forte@Sun.COM 	uint8_t		*lbuf;
23657836SJohn.Forte@Sun.COM 
23667836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
23677836SJohn.Forte@Sun.COM 
236811924SDaniel.Beauregard@Sun.COM 	if ((CFG_IST(ha, CFG_CTRL_24258081)) == 0) {
23697836SJohn.Forte@Sun.COM 		EL(ha, "hba does not support VPD\n");
23707836SJohn.Forte@Sun.COM 		return (EINVAL);
23717836SJohn.Forte@Sun.COM 	}
23727836SJohn.Forte@Sun.COM 
23737836SJohn.Forte@Sun.COM 	if ((lbuf = (uint8_t *)kmem_zalloc(dop->length, KM_SLEEP)) == NULL) {
23747836SJohn.Forte@Sun.COM 		EL(ha, "mem alloc failure of %xh bytes\n", dop->length);
23757836SJohn.Forte@Sun.COM 		rval = EFAULT;
23767836SJohn.Forte@Sun.COM 	} else {
23777836SJohn.Forte@Sun.COM 		if (ddi_copyin((void *)(uintptr_t)dop->buffer, lbuf,
23787836SJohn.Forte@Sun.COM 		    dop->length, mode) != 0) {
23797836SJohn.Forte@Sun.COM 			EL(ha, "ddi_copyin failed\n");
23807836SJohn.Forte@Sun.COM 			kmem_free(lbuf, dop->length);
23817836SJohn.Forte@Sun.COM 			return (EFAULT);
23827836SJohn.Forte@Sun.COM 		}
23837836SJohn.Forte@Sun.COM 
23847836SJohn.Forte@Sun.COM 		if ((rval = ql_vpd_lookup(ha, lbuf, lbuf, (int32_t)
23857836SJohn.Forte@Sun.COM 		    dop->length)) < 0) {
23867836SJohn.Forte@Sun.COM 			EL(ha, "failed vpd_lookup\n");
23877836SJohn.Forte@Sun.COM 		} else {
23887836SJohn.Forte@Sun.COM 			if (ddi_copyout(lbuf, (void *)(uintptr_t)dop->buffer,
23897836SJohn.Forte@Sun.COM 			    strlen((int8_t *)lbuf)+1, mode) != 0) {
23907836SJohn.Forte@Sun.COM 				EL(ha, "failed, ddi_copyout\n");
23917836SJohn.Forte@Sun.COM 				rval = EFAULT;
23927836SJohn.Forte@Sun.COM 			} else {
23937836SJohn.Forte@Sun.COM 				rval = 0;
23947836SJohn.Forte@Sun.COM 			}
23957836SJohn.Forte@Sun.COM 		}
23967836SJohn.Forte@Sun.COM 		kmem_free(lbuf, dop->length);
23977836SJohn.Forte@Sun.COM 	}
23987836SJohn.Forte@Sun.COM 
23999446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
24007836SJohn.Forte@Sun.COM 
24017836SJohn.Forte@Sun.COM 	return (rval);
24027836SJohn.Forte@Sun.COM }
24037836SJohn.Forte@Sun.COM 
24047836SJohn.Forte@Sun.COM /*
24057836SJohn.Forte@Sun.COM  * ql_adm_updfwmodule
24067836SJohn.Forte@Sun.COM  *	Performs qladm QL_UPD_FWMODULE command
24077836SJohn.Forte@Sun.COM  *
24087836SJohn.Forte@Sun.COM  * Input:
24097836SJohn.Forte@Sun.COM  *	ha:	adapter state pointer.
24107836SJohn.Forte@Sun.COM  *	dop:	ql_adm_op_t structure pointer.
24117836SJohn.Forte@Sun.COM  *	mode:	flags.
24127836SJohn.Forte@Sun.COM  *
24137836SJohn.Forte@Sun.COM  * Returns:
24147836SJohn.Forte@Sun.COM  *
24157836SJohn.Forte@Sun.COM  * Context:
24167836SJohn.Forte@Sun.COM  *	Kernel context.
24177836SJohn.Forte@Sun.COM  */
24187836SJohn.Forte@Sun.COM /* ARGSUSED */
24197836SJohn.Forte@Sun.COM static int
ql_adm_updfwmodule(ql_adapter_state_t * ha,ql_adm_op_t * dop,int mode)24207836SJohn.Forte@Sun.COM ql_adm_updfwmodule(ql_adapter_state_t *ha, ql_adm_op_t *dop, int mode)
24217836SJohn.Forte@Sun.COM {
24227836SJohn.Forte@Sun.COM 	int			rval = DDI_SUCCESS;
24237836SJohn.Forte@Sun.COM 	ql_link_t		*link;
24247836SJohn.Forte@Sun.COM 	ql_adapter_state_t	*ha2 = NULL;
24257836SJohn.Forte@Sun.COM 	uint16_t		fw_class = (uint16_t)dop->option;
24267836SJohn.Forte@Sun.COM 
24277836SJohn.Forte@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): started\n", ha->instance);
24287836SJohn.Forte@Sun.COM 
24297836SJohn.Forte@Sun.COM 	/* zero the firmware module reference count */
24307836SJohn.Forte@Sun.COM 	for (link = ql_hba.first; link != NULL; link = link->next) {
24317836SJohn.Forte@Sun.COM 		ha2 = link->base_address;
24327836SJohn.Forte@Sun.COM 		if (fw_class == ha2->fw_class) {
24337836SJohn.Forte@Sun.COM 			if ((rval = ddi_modclose(ha2->fw_module)) !=
24347836SJohn.Forte@Sun.COM 			    DDI_SUCCESS) {
24357836SJohn.Forte@Sun.COM 				EL(ha2, "modclose rval=%xh\n", rval);
24367836SJohn.Forte@Sun.COM 				break;
24377836SJohn.Forte@Sun.COM 			}
24387836SJohn.Forte@Sun.COM 			ha2->fw_module = NULL;
24397836SJohn.Forte@Sun.COM 		}
24407836SJohn.Forte@Sun.COM 	}
24417836SJohn.Forte@Sun.COM 
24427836SJohn.Forte@Sun.COM 	/* reload the f/w modules */
24437836SJohn.Forte@Sun.COM 	for (link = ql_hba.first; link != NULL; link = link->next) {
24447836SJohn.Forte@Sun.COM 		ha2 = link->base_address;
24457836SJohn.Forte@Sun.COM 
24467836SJohn.Forte@Sun.COM 		if ((fw_class == ha2->fw_class) && (ha2->fw_class == NULL)) {
24477836SJohn.Forte@Sun.COM 			if ((rval = (int32_t)ql_fwmodule_resolve(ha2)) !=
24487836SJohn.Forte@Sun.COM 			    QL_SUCCESS) {
24497836SJohn.Forte@Sun.COM 				EL(ha2, "unable to load f/w module: '%x' "
24507836SJohn.Forte@Sun.COM 				    "(rval=%xh)\n", ha2->fw_class, rval);
24517836SJohn.Forte@Sun.COM 				rval = EFAULT;
24527836SJohn.Forte@Sun.COM 			} else {
24537836SJohn.Forte@Sun.COM 				EL(ha2, "f/w module updated: '%x'\n",
24547836SJohn.Forte@Sun.COM 				    ha2->fw_class);
24557836SJohn.Forte@Sun.COM 			}
24567836SJohn.Forte@Sun.COM 
24577836SJohn.Forte@Sun.COM 			EL(ha2, "isp abort needed (%d)\n", ha->instance);
24587836SJohn.Forte@Sun.COM 
24597836SJohn.Forte@Sun.COM 			ql_awaken_task_daemon(ha2, NULL, ISP_ABORT_NEEDED, 0);
24607836SJohn.Forte@Sun.COM 
24617836SJohn.Forte@Sun.COM 			rval = 0;
24627836SJohn.Forte@Sun.COM 		}
24637836SJohn.Forte@Sun.COM 	}
24647836SJohn.Forte@Sun.COM 
24659446SDaniel.Beauregard@Sun.COM 	QL_PRINT_9(CE_CONT, "(%d): done\n", ha->instance);
24667836SJohn.Forte@Sun.COM 
24677836SJohn.Forte@Sun.COM 	return (rval);
24687836SJohn.Forte@Sun.COM }
2469