xref: /onnv-gate/usr/src/uts/sun4u/ngdr/io/dr.c (revision 11474:857f9db4ef05)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51772Sjl139090  * Common Development and Distribution License (the "License").
61772Sjl139090  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
2111311SSurya.Prakki@Sun.COM 
220Sstevel@tonic-gate /*
23*11474SJonathan.Adams@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*
280Sstevel@tonic-gate  * PIM-DR layer of DR driver.  Provides interface between user
290Sstevel@tonic-gate  * level applications and the PSM-DR layer.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/note.h>
330Sstevel@tonic-gate #include <sys/debug.h>
340Sstevel@tonic-gate #include <sys/types.h>
350Sstevel@tonic-gate #include <sys/errno.h>
360Sstevel@tonic-gate #include <sys/cred.h>
370Sstevel@tonic-gate #include <sys/dditypes.h>
380Sstevel@tonic-gate #include <sys/devops.h>
390Sstevel@tonic-gate #include <sys/modctl.h>
400Sstevel@tonic-gate #include <sys/poll.h>
410Sstevel@tonic-gate #include <sys/conf.h>
420Sstevel@tonic-gate #include <sys/ddi.h>
430Sstevel@tonic-gate #include <sys/sunddi.h>
440Sstevel@tonic-gate #include <sys/sunndi.h>
450Sstevel@tonic-gate #include <sys/stat.h>
460Sstevel@tonic-gate #include <sys/kmem.h>
470Sstevel@tonic-gate #include <sys/processor.h>
480Sstevel@tonic-gate #include <sys/cpuvar.h>
490Sstevel@tonic-gate #include <sys/mem_config.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include <sys/autoconf.h>
520Sstevel@tonic-gate #include <sys/cmn_err.h>
530Sstevel@tonic-gate 
540Sstevel@tonic-gate #include <sys/ddi_impldefs.h>
550Sstevel@tonic-gate #include <sys/promif.h>
560Sstevel@tonic-gate #include <sys/machsystm.h>
570Sstevel@tonic-gate 
580Sstevel@tonic-gate #include <sys/dr.h>
590Sstevel@tonic-gate #include <sys/drmach.h>
600Sstevel@tonic-gate #include <sys/dr_util.h>
610Sstevel@tonic-gate 
620Sstevel@tonic-gate extern int		 nulldev();
630Sstevel@tonic-gate extern int		 nodev();
640Sstevel@tonic-gate extern struct memlist	*phys_install;
650Sstevel@tonic-gate 
660Sstevel@tonic-gate #ifdef DEBUG
670Sstevel@tonic-gate uint_t	dr_debug = 0;			/* dr.h for bit values */
680Sstevel@tonic-gate #endif /* DEBUG */
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * NOTE: state_str, nt_str and SBD_CMD_STR are only used in a debug
720Sstevel@tonic-gate  * kernel.  They are, however, referenced during both debug and non-debug
730Sstevel@tonic-gate  * compiles.
740Sstevel@tonic-gate  */
750Sstevel@tonic-gate 
760Sstevel@tonic-gate static char *state_str[] = {
770Sstevel@tonic-gate 	"EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED",
780Sstevel@tonic-gate 	"PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED",
790Sstevel@tonic-gate 	"FATAL"
800Sstevel@tonic-gate };
810Sstevel@tonic-gate 
820Sstevel@tonic-gate #define	SBD_CMD_STR(c) \
830Sstevel@tonic-gate 	(((c) == SBD_CMD_ASSIGN)	? "ASSIGN"	: \
840Sstevel@tonic-gate 	((c) == SBD_CMD_UNASSIGN)	? "UNASSIGN"	: \
850Sstevel@tonic-gate 	((c) == SBD_CMD_POWERON)	? "POWERON"	: \
860Sstevel@tonic-gate 	((c) == SBD_CMD_POWEROFF)	? "POWEROFF"	: \
870Sstevel@tonic-gate 	((c) == SBD_CMD_TEST)		? "TEST"	: \
880Sstevel@tonic-gate 	((c) == SBD_CMD_CONNECT)	? "CONNECT"	: \
890Sstevel@tonic-gate 	((c) == SBD_CMD_DISCONNECT)	? "DISCONNECT"	: \
900Sstevel@tonic-gate 	((c) == SBD_CMD_CONFIGURE)	? "CONFIGURE"	: \
910Sstevel@tonic-gate 	((c) == SBD_CMD_UNCONFIGURE)	? "UNCONFIGURE"	: \
920Sstevel@tonic-gate 	((c) == SBD_CMD_GETNCM)		? "GETNCM"	: \
930Sstevel@tonic-gate 	((c) == SBD_CMD_PASSTHRU)	? "PASSTHRU"	: \
940Sstevel@tonic-gate 	((c) == SBD_CMD_STATUS)		? "STATUS"	: "unknown")
950Sstevel@tonic-gate 
960Sstevel@tonic-gate #define	DR_GET_BOARD_DEVUNIT(sb, ut, un) (&((sb)->b_dev[NIX(ut)][un]))
970Sstevel@tonic-gate 
980Sstevel@tonic-gate #define	DR_MAKE_MINOR(i, b)	(((i) << 16) | (b))
990Sstevel@tonic-gate #define	DR_MINOR2INST(m)	(((m) >> 16) & 0xffff)
1000Sstevel@tonic-gate #define	DR_MINOR2BNUM(m)	((m) & 0xffff)
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros.  see sys/dr.h. */
1030Sstevel@tonic-gate static char *dr_ie_fmt = "dr.c %d";
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /* struct for drmach device name to sbd_comp_type_t mapping */
1060Sstevel@tonic-gate typedef	struct {
1070Sstevel@tonic-gate 	char		*s_devtype;
1080Sstevel@tonic-gate 	sbd_comp_type_t	s_nodetype;
1090Sstevel@tonic-gate } dr_devname_t;
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /* struct to map starfire device attributes - name:sbd_comp_type_t */
1120Sstevel@tonic-gate static	dr_devname_t	dr_devattr[] = {
1130Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_MEM,	SBD_COMP_MEM },
1140Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_CPU,	SBD_COMP_CPU },
1150Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_PCI,	SBD_COMP_IO },
1161772Sjl139090 #if defined(DRMACH_DEVTYPE_SBUS)
1170Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_SBUS,	SBD_COMP_IO },
1181772Sjl139090 #endif
1190Sstevel@tonic-gate #if defined(DRMACH_DEVTYPE_WCI)
1200Sstevel@tonic-gate 	{ DRMACH_DEVTYPE_WCI,	SBD_COMP_IO },
1210Sstevel@tonic-gate #endif
1220Sstevel@tonic-gate 	/* last s_devtype must be NULL, s_nodetype must be SBD_COMP_UNKNOWN */
1230Sstevel@tonic-gate 	{ NULL,			SBD_COMP_UNKNOWN }
1240Sstevel@tonic-gate };
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate /*
1270Sstevel@tonic-gate  * Per instance soft-state structure.
1280Sstevel@tonic-gate  */
1290Sstevel@tonic-gate typedef struct dr_softstate {
1300Sstevel@tonic-gate 	dev_info_t	*dip;
1310Sstevel@tonic-gate 	dr_board_t	*boards;
1320Sstevel@tonic-gate 	kmutex_t	i_lock;
1330Sstevel@tonic-gate 	int		 dr_initialized;
1340Sstevel@tonic-gate } dr_softstate_t;
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate /*
1370Sstevel@tonic-gate  * dr Global data elements
1380Sstevel@tonic-gate  */
1390Sstevel@tonic-gate struct dr_global {
1400Sstevel@tonic-gate 	dr_softstate_t	*softsp;	/* pointer to initialize soft state */
1410Sstevel@tonic-gate 	kmutex_t	lock;
1420Sstevel@tonic-gate } dr_g;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate dr_unsafe_devs_t	dr_unsafe_devs;
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate /*
1470Sstevel@tonic-gate  * Table of known passthru commands.
1480Sstevel@tonic-gate  */
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate struct {
1510Sstevel@tonic-gate 	char	*pt_name;
1520Sstevel@tonic-gate 	int	(*pt_func)(dr_handle_t *);
1530Sstevel@tonic-gate } pt_arr[] = {
1540Sstevel@tonic-gate 	"quiesce",		dr_pt_test_suspend,
1550Sstevel@tonic-gate };
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate int dr_modunload_okay = 0;		/* set to non-zero to allow unload */
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate  * State transition table.  States valid transitions for "board" state.
1610Sstevel@tonic-gate  * Recall that non-zero return value terminates operation, however
1620Sstevel@tonic-gate  * the herrno value is what really indicates an error , if any.
1630Sstevel@tonic-gate  */
1640Sstevel@tonic-gate static int
_cmd2index(int c)1650Sstevel@tonic-gate _cmd2index(int c)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate 	/*
1680Sstevel@tonic-gate 	 * Translate DR CMD to index into dr_state_transition.
1690Sstevel@tonic-gate 	 */
1700Sstevel@tonic-gate 	switch (c) {
1710Sstevel@tonic-gate 	case SBD_CMD_CONNECT:		return (0);
1720Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:	return (1);
1730Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:		return (2);
1740Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:	return (3);
1750Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:		return (4);
1760Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:		return (5);
1770Sstevel@tonic-gate 	case SBD_CMD_POWERON:		return (6);
1780Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:		return (7);
1790Sstevel@tonic-gate 	case SBD_CMD_TEST:		return (8);
1800Sstevel@tonic-gate 	default:			return (-1);
1810Sstevel@tonic-gate 	}
1820Sstevel@tonic-gate }
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate #define	CMD2INDEX(c)	_cmd2index(c)
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate static struct dr_state_trans {
1870Sstevel@tonic-gate 	int	x_cmd;
1880Sstevel@tonic-gate 	struct {
1890Sstevel@tonic-gate 		int	x_rv;		/* return value of pre_op */
1900Sstevel@tonic-gate 		int	x_err;		/* error, if any */
1910Sstevel@tonic-gate 	} x_op[DR_STATE_MAX];
1920Sstevel@tonic-gate } dr_state_transition[] = {
1930Sstevel@tonic-gate 	{ SBD_CMD_CONNECT,
1940Sstevel@tonic-gate 		{
1950Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
1960Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
1970Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
1980Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
1990Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
2000Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
2010Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2020Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2030Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2040Sstevel@tonic-gate 		}
2050Sstevel@tonic-gate 	},
2060Sstevel@tonic-gate 	{ SBD_CMD_DISCONNECT,
2070Sstevel@tonic-gate 		{
2080Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* empty */
2090Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
2100Sstevel@tonic-gate 			{ 0, 0 },			/* connected */
2110Sstevel@tonic-gate 			{ 0, 0 },			/* unconfigured */
2120Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
2130Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
2140Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2150Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2160Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2170Sstevel@tonic-gate 		}
2180Sstevel@tonic-gate 	},
2190Sstevel@tonic-gate 	{ SBD_CMD_CONFIGURE,
2200Sstevel@tonic-gate 		{
2210Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* empty */
2220Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* occupied */
2230Sstevel@tonic-gate 			{ 0, 0 },			/* connected */
2240Sstevel@tonic-gate 			{ 0, 0 },			/* unconfigured */
2250Sstevel@tonic-gate 			{ 0, 0 },			/* partial */
2260Sstevel@tonic-gate 			{ 0, 0 },			/* configured */
2270Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2280Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2290Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2300Sstevel@tonic-gate 		}
2310Sstevel@tonic-gate 	},
2320Sstevel@tonic-gate 	{ SBD_CMD_UNCONFIGURE,
2330Sstevel@tonic-gate 		{
2340Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* empty */
2350Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* occupied */
2360Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
2370Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
2380Sstevel@tonic-gate 			{ 0, 0 },			/* partial */
2390Sstevel@tonic-gate 			{ 0, 0 },			/* configured */
2400Sstevel@tonic-gate 			{ 0, 0 },			/* release */
2410Sstevel@tonic-gate 			{ 0, 0 },			/* unreferenced */
2420Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2430Sstevel@tonic-gate 		}
2440Sstevel@tonic-gate 	},
2450Sstevel@tonic-gate 	{ SBD_CMD_ASSIGN,
2460Sstevel@tonic-gate 		{
2470Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
2480Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
2490Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
2500Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
2510Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
2520Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
2530Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2540Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2550Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 	},
2580Sstevel@tonic-gate 	{ SBD_CMD_UNASSIGN,
2590Sstevel@tonic-gate 		{
2600Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
2610Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
2620Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
2630Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
2640Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
2650Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
2660Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2670Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2680Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2690Sstevel@tonic-gate 		}
2700Sstevel@tonic-gate 	},
2710Sstevel@tonic-gate 	{ SBD_CMD_POWERON,
2720Sstevel@tonic-gate 		{
2730Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
2740Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
2750Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
2760Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
2770Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
2780Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
2790Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2800Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2810Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2820Sstevel@tonic-gate 		}
2830Sstevel@tonic-gate 	},
2840Sstevel@tonic-gate 	{ SBD_CMD_POWEROFF,
2850Sstevel@tonic-gate 		{
2860Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
2870Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
2880Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
2890Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
2900Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
2910Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
2920Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
2930Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
2940Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
2950Sstevel@tonic-gate 		}
2960Sstevel@tonic-gate 	},
2970Sstevel@tonic-gate 	{ SBD_CMD_TEST,
2980Sstevel@tonic-gate 		{
2990Sstevel@tonic-gate 			{ 0, 0 },			/* empty */
3000Sstevel@tonic-gate 			{ 0, 0 },			/* occupied */
3010Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* connected */
3020Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unconfigured */
3030Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* partial */
3040Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* configured */
3050Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* release */
3060Sstevel@tonic-gate 			{ -1, ESBD_STATE },		/* unreferenced */
3070Sstevel@tonic-gate 			{ -1, ESBD_FATAL_STATE },	/* fatal */
3080Sstevel@tonic-gate 		}
3090Sstevel@tonic-gate 	},
3100Sstevel@tonic-gate };
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate /*
3130Sstevel@tonic-gate  * Global R/W lock to synchronize access across
3140Sstevel@tonic-gate  * multiple boards.  Users wanting multi-board access
3150Sstevel@tonic-gate  * must grab WRITE lock, others must grab READ lock.
3160Sstevel@tonic-gate  */
3170Sstevel@tonic-gate krwlock_t	dr_grwlock;
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate /*
3200Sstevel@tonic-gate  * Head of the boardlist used as a reference point for
3210Sstevel@tonic-gate  * locating board structs.
3220Sstevel@tonic-gate  * TODO: eliminate dr_boardlist
3230Sstevel@tonic-gate  */
3240Sstevel@tonic-gate dr_board_t	*dr_boardlist;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate  * DR support functions.
3280Sstevel@tonic-gate  */
3290Sstevel@tonic-gate static dr_devset_t	dr_dev2devset(sbd_comp_id_t *cid);
3300Sstevel@tonic-gate static int		dr_check_transition(dr_board_t *bp,
3310Sstevel@tonic-gate 					dr_devset_t *devsetp,
3320Sstevel@tonic-gate 					struct dr_state_trans *transp,
3330Sstevel@tonic-gate 					int cmd);
3340Sstevel@tonic-gate static int		dr_check_unit_attached(dr_common_unit_t *dp);
3350Sstevel@tonic-gate static sbd_error_t	*dr_init_devlists(dr_board_t *bp);
3360Sstevel@tonic-gate static void		dr_board_discovery(dr_board_t *bp);
3370Sstevel@tonic-gate static int		dr_board_init(dr_board_t *bp, dev_info_t *dip,
3380Sstevel@tonic-gate 					int bd);
3390Sstevel@tonic-gate static void		dr_board_destroy(dr_board_t *bp);
3400Sstevel@tonic-gate static void		dr_board_transition(dr_board_t *bp, dr_state_t st);
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate /*
3430Sstevel@tonic-gate  * DR driver (DDI) entry points.
3440Sstevel@tonic-gate  */
3450Sstevel@tonic-gate static int	dr_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd,
3460Sstevel@tonic-gate 				void *arg, void **result);
3470Sstevel@tonic-gate static int	dr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
3480Sstevel@tonic-gate static int	dr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
3490Sstevel@tonic-gate static int	dr_probe(dev_info_t *dip);
3500Sstevel@tonic-gate static int	dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
3510Sstevel@tonic-gate 				cred_t *cred_p, int *rval_p);
3520Sstevel@tonic-gate static int	dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p);
3530Sstevel@tonic-gate static int	dr_open(dev_t *dev, int flag, int otyp, cred_t *cred_p);
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate /*
3560Sstevel@tonic-gate  * DR command processing operations.
3570Sstevel@tonic-gate  */
3580Sstevel@tonic-gate 
3590Sstevel@tonic-gate static int	dr_copyin_iocmd(dr_handle_t *hp);
3600Sstevel@tonic-gate static int	dr_copyout_iocmd(dr_handle_t *hp);
3610Sstevel@tonic-gate static int	dr_copyout_errs(dr_handle_t *hp);
3620Sstevel@tonic-gate static int	dr_pre_op(dr_handle_t *hp);
3630Sstevel@tonic-gate static int	dr_post_op(dr_handle_t *hp);
3640Sstevel@tonic-gate static int	dr_exec_op(dr_handle_t *hp);
3650Sstevel@tonic-gate static void	dr_assign_board(dr_handle_t *hp);
3660Sstevel@tonic-gate static void	dr_unassign_board(dr_handle_t *hp);
3670Sstevel@tonic-gate static void	dr_connect(dr_handle_t *hp);
3680Sstevel@tonic-gate static int	dr_disconnect(dr_handle_t *hp);
3690Sstevel@tonic-gate static void	dr_dev_configure(dr_handle_t *hp);
3700Sstevel@tonic-gate static void	dr_dev_release(dr_handle_t *hp);
3710Sstevel@tonic-gate static int	dr_dev_unconfigure(dr_handle_t *hp);
3720Sstevel@tonic-gate static void	dr_dev_cancel(dr_handle_t *hp);
3730Sstevel@tonic-gate static int	dr_dev_status(dr_handle_t *hp);
3740Sstevel@tonic-gate static int	dr_get_ncm(dr_handle_t *hp);
3750Sstevel@tonic-gate static int	dr_pt_ioctl(dr_handle_t *hp);
3760Sstevel@tonic-gate static void	dr_poweron_board(dr_handle_t *hp);
3770Sstevel@tonic-gate static void	dr_poweroff_board(dr_handle_t *hp);
3780Sstevel@tonic-gate static void	dr_test_board(dr_handle_t *hp);
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate 
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate /*
3830Sstevel@tonic-gate  * Autoconfiguration data structures
3840Sstevel@tonic-gate  */
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate struct cb_ops dr_cb_ops = {
3870Sstevel@tonic-gate 	dr_open,	/* open */
3880Sstevel@tonic-gate 	dr_close,	/* close */
3890Sstevel@tonic-gate 	nodev,		/* strategy */
3900Sstevel@tonic-gate 	nodev,		/* print */
3910Sstevel@tonic-gate 	nodev,		/* dump */
3920Sstevel@tonic-gate 	nodev,		/* read */
3930Sstevel@tonic-gate 	nodev,		/* write */
3940Sstevel@tonic-gate 	dr_ioctl,	/* ioctl */
3950Sstevel@tonic-gate 	nodev,		/* devmap */
3960Sstevel@tonic-gate 	nodev,		/* mmap */
3970Sstevel@tonic-gate 	nodev,		/* segmap */
3980Sstevel@tonic-gate 	nochpoll,	/* chpoll */
3990Sstevel@tonic-gate 	ddi_prop_op,	/* cb_prop_op */
4000Sstevel@tonic-gate 	NULL,		/* struct streamtab */
4010Sstevel@tonic-gate 	D_NEW | D_MP | D_MTSAFE,	/* compatibility flags */
4020Sstevel@tonic-gate 	CB_REV,		/* Rev */
4030Sstevel@tonic-gate 	nodev,		/* cb_aread */
4040Sstevel@tonic-gate 	nodev		/* cb_awrite */
4050Sstevel@tonic-gate };
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate struct dev_ops dr_dev_ops = {
4080Sstevel@tonic-gate 	DEVO_REV,	/* build version */
4090Sstevel@tonic-gate 	0,		/* dev ref count */
4100Sstevel@tonic-gate 	dr_getinfo,	/* getinfo */
4110Sstevel@tonic-gate 	nulldev,	/* identify */
4120Sstevel@tonic-gate 	dr_probe,	/* probe */
4130Sstevel@tonic-gate 	dr_attach,	/* attach */
4140Sstevel@tonic-gate 	dr_detach,	/* detach */
4150Sstevel@tonic-gate 	nodev,		/* reset */
4160Sstevel@tonic-gate 	&dr_cb_ops,	/* cb_ops */
4170Sstevel@tonic-gate 	(struct bus_ops *)NULL, /* bus ops */
4187656SSherry.Moore@Sun.COM 	NULL,		/* power */
4197656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,	/* quiesce */
4200Sstevel@tonic-gate };
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate extern struct mod_ops mod_driverops;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate static struct modldrv modldrv = {
4250Sstevel@tonic-gate 	&mod_driverops,
4267656SSherry.Moore@Sun.COM 	"Dynamic Reconfiguration",
4270Sstevel@tonic-gate 	&dr_dev_ops
4280Sstevel@tonic-gate };
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate static struct modlinkage modlinkage = {
4310Sstevel@tonic-gate 	MODREV_1,
4320Sstevel@tonic-gate 	(void *)&modldrv,
4330Sstevel@tonic-gate 	NULL
4340Sstevel@tonic-gate };
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate /*
4370Sstevel@tonic-gate  * Driver entry points.
4380Sstevel@tonic-gate  */
4390Sstevel@tonic-gate int
_init(void)4400Sstevel@tonic-gate _init(void)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 	int	err;
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate 	/*
4450Sstevel@tonic-gate 	 * If you need to support multiple nodes (instances), then
4460Sstevel@tonic-gate 	 * whatever the maximum number of supported nodes is would
4470Sstevel@tonic-gate 	 * need to passed as the third parameter to ddi_soft_state_init().
4480Sstevel@tonic-gate 	 * Alternative would be to dynamically fini and re-init the
4490Sstevel@tonic-gate 	 * soft state structure each time a node is attached.
4500Sstevel@tonic-gate 	 */
4510Sstevel@tonic-gate 	err = ddi_soft_state_init((void **)&dr_g.softsp,
4527656SSherry.Moore@Sun.COM 	    sizeof (dr_softstate_t), 1);
4530Sstevel@tonic-gate 	if (err)
4540Sstevel@tonic-gate 		return (err);
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	mutex_init(&dr_g.lock, NULL, MUTEX_DRIVER, NULL);
4570Sstevel@tonic-gate 	rw_init(&dr_grwlock, NULL, RW_DEFAULT, NULL);
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	return (mod_install(&modlinkage));
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate int
_fini(void)4630Sstevel@tonic-gate _fini(void)
4640Sstevel@tonic-gate {
4650Sstevel@tonic-gate 	int	err;
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	if ((err = mod_remove(&modlinkage)) != 0)
4680Sstevel@tonic-gate 		return (err);
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	mutex_destroy(&dr_g.lock);
4710Sstevel@tonic-gate 	rw_destroy(&dr_grwlock);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	ddi_soft_state_fini((void **)&dr_g.softsp);
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	return (0);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4790Sstevel@tonic-gate _info(struct modinfo *modinfop)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4820Sstevel@tonic-gate }
4830Sstevel@tonic-gate 
4840Sstevel@tonic-gate /*ARGSUSED1*/
4850Sstevel@tonic-gate static int
dr_open(dev_t * dev,int flag,int otyp,cred_t * cred_p)4860Sstevel@tonic-gate dr_open(dev_t *dev, int flag, int otyp, cred_t *cred_p)
4870Sstevel@tonic-gate {
4880Sstevel@tonic-gate 	int		 instance;
4890Sstevel@tonic-gate 	dr_softstate_t	*softsp;
4900Sstevel@tonic-gate 	dr_board_t	*bp;
4910Sstevel@tonic-gate 	/*
4920Sstevel@tonic-gate 	 * Don't open unless we've attached.
4930Sstevel@tonic-gate 	 */
4940Sstevel@tonic-gate 	instance = DR_MINOR2INST(getminor(*dev));
4950Sstevel@tonic-gate 	softsp = ddi_get_soft_state(dr_g.softsp, instance);
4960Sstevel@tonic-gate 	if (softsp == NULL)
4970Sstevel@tonic-gate 		return (ENXIO);
4980Sstevel@tonic-gate 
4990Sstevel@tonic-gate 	mutex_enter(&softsp->i_lock);
5000Sstevel@tonic-gate 	if (!softsp->dr_initialized) {
5010Sstevel@tonic-gate 		int		 bd;
5020Sstevel@tonic-gate 		int		 rv = 0;
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 		bp = softsp->boards;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 		/* initialize each array element */
5070Sstevel@tonic-gate 		for (bd = 0; bd < MAX_BOARDS; bd++, bp++) {
5080Sstevel@tonic-gate 			rv = dr_board_init(bp, softsp->dip, bd);
5090Sstevel@tonic-gate 			if (rv)
5100Sstevel@tonic-gate 				break;
5110Sstevel@tonic-gate 		}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 		if (rv == 0) {
5140Sstevel@tonic-gate 			softsp->dr_initialized = 1;
5150Sstevel@tonic-gate 		} else {
5160Sstevel@tonic-gate 			/* destroy elements initialized thus far */
5170Sstevel@tonic-gate 			while (--bp >= softsp->boards)
5180Sstevel@tonic-gate 				dr_board_destroy(bp);
5190Sstevel@tonic-gate 
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 			/* TODO: should this be another errno val ? */
5220Sstevel@tonic-gate 			mutex_exit(&softsp->i_lock);
5230Sstevel@tonic-gate 			return (ENXIO);
5240Sstevel@tonic-gate 		}
5250Sstevel@tonic-gate 	}
5260Sstevel@tonic-gate 	mutex_exit(&softsp->i_lock);
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	bp = &softsp->boards[DR_MINOR2BNUM(getminor(*dev))];
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 	/*
5310Sstevel@tonic-gate 	 * prevent opening of a dyn-ap for a board
5320Sstevel@tonic-gate 	 * that does not exist
5330Sstevel@tonic-gate 	 */
5340Sstevel@tonic-gate 	if (!bp->b_assigned) {
5350Sstevel@tonic-gate 		if (drmach_board_lookup(bp->b_num, &bp->b_id) != 0)
5360Sstevel@tonic-gate 			return (ENODEV);
5370Sstevel@tonic-gate 	}
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	return (0);
5400Sstevel@tonic-gate }
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate /*ARGSUSED*/
5430Sstevel@tonic-gate static int
dr_close(dev_t dev,int flag,int otyp,cred_t * cred_p)5440Sstevel@tonic-gate dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p)
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate 	return (0);
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate /*
5501772Sjl139090  * Enable/disable DR features.
5510Sstevel@tonic-gate  */
5520Sstevel@tonic-gate int dr_enable = 1;
5530Sstevel@tonic-gate 
5540Sstevel@tonic-gate /*ARGSUSED3*/
5550Sstevel@tonic-gate static int
dr_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cred_p,int * rval_p)5560Sstevel@tonic-gate dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
5570Sstevel@tonic-gate 	cred_t *cred_p, int *rval_p)
5580Sstevel@tonic-gate {
5590Sstevel@tonic-gate 	static int	dr_dev_type_to_nt(char *);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	int		rv = 0;
5620Sstevel@tonic-gate 	int		instance;
5630Sstevel@tonic-gate 	int		bd;
5640Sstevel@tonic-gate 	dr_handle_t	*hp;
5650Sstevel@tonic-gate 	dr_softstate_t	*softsp;
5660Sstevel@tonic-gate 	static fn_t	f = "dr_ioctl";
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
5690Sstevel@tonic-gate 
5700Sstevel@tonic-gate 	instance = DR_MINOR2INST(getminor(dev));
5710Sstevel@tonic-gate 	softsp = ddi_get_soft_state(dr_g.softsp, instance);
5720Sstevel@tonic-gate 	if (softsp == NULL) {
5730Sstevel@tonic-gate 		cmn_err(CE_WARN, "dr%d: module not yet attached", instance);
5740Sstevel@tonic-gate 		return (ENXIO);
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 	if (!dr_enable) {
5780Sstevel@tonic-gate 		switch (cmd) {
5790Sstevel@tonic-gate 			case SBD_CMD_STATUS:
5800Sstevel@tonic-gate 			case SBD_CMD_GETNCM:
5810Sstevel@tonic-gate 			case SBD_CMD_PASSTHRU:
5820Sstevel@tonic-gate 				break;
5830Sstevel@tonic-gate 			default:
5840Sstevel@tonic-gate 				return (ENOTSUP);
5850Sstevel@tonic-gate 		}
5860Sstevel@tonic-gate 	}
5870Sstevel@tonic-gate 
5880Sstevel@tonic-gate 	bd = DR_MINOR2BNUM(getminor(dev));
5890Sstevel@tonic-gate 	if (bd >= MAX_BOARDS)
5900Sstevel@tonic-gate 		return (ENXIO);
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	/* get and initialize storage for new handle */
5930Sstevel@tonic-gate 	hp = GETSTRUCT(dr_handle_t, 1);
5940Sstevel@tonic-gate 	hp->h_bd = &softsp->boards[bd];
5950Sstevel@tonic-gate 	hp->h_err = NULL;
5960Sstevel@tonic-gate 	hp->h_dev = getminor(dev);
5970Sstevel@tonic-gate 	hp->h_cmd = cmd;
5980Sstevel@tonic-gate 	hp->h_mode = mode;
5990Sstevel@tonic-gate 	hp->h_iap = (sbd_ioctl_arg_t *)arg;
6000Sstevel@tonic-gate 
6010Sstevel@tonic-gate 	/* copy sbd command into handle */
6020Sstevel@tonic-gate 	rv = dr_copyin_iocmd(hp);
6030Sstevel@tonic-gate 	if (rv) {
6040Sstevel@tonic-gate 		FREESTRUCT(hp, dr_handle_t, 1);
6050Sstevel@tonic-gate 		return (EINVAL);
6060Sstevel@tonic-gate 	}
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	/* translate canonical name to component type */
6090Sstevel@tonic-gate 	if (hp->h_sbdcmd.cmd_cm.c_id.c_name[0] != '\0') {
6100Sstevel@tonic-gate 		hp->h_sbdcmd.cmd_cm.c_id.c_type =
6117656SSherry.Moore@Sun.COM 		    dr_dev_type_to_nt(hp->h_sbdcmd.cmd_cm.c_id.c_name);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 		PR_ALL("%s: c_name = %s, c_type = %d\n",
6147656SSherry.Moore@Sun.COM 		    f,
6157656SSherry.Moore@Sun.COM 		    hp->h_sbdcmd.cmd_cm.c_id.c_name,
6167656SSherry.Moore@Sun.COM 		    hp->h_sbdcmd.cmd_cm.c_id.c_type);
6170Sstevel@tonic-gate 	} else {
6180Sstevel@tonic-gate 		/*EMPTY*/
6190Sstevel@tonic-gate 		PR_ALL("%s: c_name is NULL\n", f);
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	/* determine scope of operation */
6230Sstevel@tonic-gate 	hp->h_devset = dr_dev2devset(&hp->h_sbdcmd.cmd_cm.c_id);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	switch (hp->h_cmd) {
6260Sstevel@tonic-gate 	case SBD_CMD_STATUS:
6270Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
6280Sstevel@tonic-gate 		/* no locks needed for these commands */
6290Sstevel@tonic-gate 		break;
6300Sstevel@tonic-gate 
6310Sstevel@tonic-gate 	default:
6320Sstevel@tonic-gate 		rw_enter(&dr_grwlock, RW_WRITER);
6330Sstevel@tonic-gate 		mutex_enter(&hp->h_bd->b_lock);
6340Sstevel@tonic-gate 
6350Sstevel@tonic-gate 		/*
6360Sstevel@tonic-gate 		 * If we're dealing with memory at all, then we have
6370Sstevel@tonic-gate 		 * to keep the "exclusive" global lock held.  This is
6380Sstevel@tonic-gate 		 * necessary since we will probably need to look at
6390Sstevel@tonic-gate 		 * multiple board structs.  Otherwise, we only have
6400Sstevel@tonic-gate 		 * to deal with the board in question and so can drop
6410Sstevel@tonic-gate 		 * the global lock to "shared".
6420Sstevel@tonic-gate 		 */
6430Sstevel@tonic-gate 		rv = DEVSET_IN_SET(hp->h_devset, SBD_COMP_MEM, DEVSET_ANYUNIT);
6440Sstevel@tonic-gate 		if (rv == 0)
6450Sstevel@tonic-gate 			rw_downgrade(&dr_grwlock);
6460Sstevel@tonic-gate 		break;
6470Sstevel@tonic-gate 	}
6480Sstevel@tonic-gate 	rv = 0;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	if (rv == 0)
6510Sstevel@tonic-gate 		rv = dr_pre_op(hp);
6520Sstevel@tonic-gate 	if (rv == 0)
6530Sstevel@tonic-gate 		rv = dr_exec_op(hp);
6540Sstevel@tonic-gate 	if (rv == 0)
6550Sstevel@tonic-gate 		rv = dr_post_op(hp);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (rv == -1)
6580Sstevel@tonic-gate 		rv = EIO;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	if (hp->h_err != NULL)
6610Sstevel@tonic-gate 		if (!(rv = dr_copyout_errs(hp)))
6620Sstevel@tonic-gate 			rv = EIO;
6630Sstevel@tonic-gate 
6640Sstevel@tonic-gate 	/* undo locking, if any, done before dr_pre_op */
6650Sstevel@tonic-gate 	switch (hp->h_cmd) {
6660Sstevel@tonic-gate 	case SBD_CMD_STATUS:
6670Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
6680Sstevel@tonic-gate 		break;
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:
6710Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:
6720Sstevel@tonic-gate 	case SBD_CMD_POWERON:
6730Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:
6740Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
6750Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
6760Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
6770Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
6780Sstevel@tonic-gate 		/* Board changed state. Log a sysevent. */
6790Sstevel@tonic-gate 		if (rv == 0)
6800Sstevel@tonic-gate 			(void) drmach_log_sysevent(hp->h_bd->b_num, "",
6817656SSherry.Moore@Sun.COM 			    SE_SLEEP, 1);
6820Sstevel@tonic-gate 		/* Fall through */
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 	default:
6850Sstevel@tonic-gate 		mutex_exit(&hp->h_bd->b_lock);
6860Sstevel@tonic-gate 		rw_exit(&dr_grwlock);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 	if (hp->h_opts.size != 0)
6900Sstevel@tonic-gate 		FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size);
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 	FREESTRUCT(hp, dr_handle_t, 1);
6930Sstevel@tonic-gate 
6940Sstevel@tonic-gate 	return (rv);
6950Sstevel@tonic-gate }
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate /*ARGSUSED*/
6980Sstevel@tonic-gate static int
dr_probe(dev_info_t * dip)6990Sstevel@tonic-gate dr_probe(dev_info_t *dip)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate static int
dr_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)7050Sstevel@tonic-gate dr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
7060Sstevel@tonic-gate {
7070Sstevel@tonic-gate 	int		rv, rv2;
7080Sstevel@tonic-gate 	int		bd;
7090Sstevel@tonic-gate 	int 		instance;
7100Sstevel@tonic-gate 	sbd_error_t	*err;
7110Sstevel@tonic-gate 	dr_softstate_t	*softsp;
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	instance = ddi_get_instance(dip);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate 	switch (cmd) {
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 	case DDI_ATTACH:
7180Sstevel@tonic-gate 
7190Sstevel@tonic-gate 		rw_enter(&dr_grwlock, RW_WRITER);
7200Sstevel@tonic-gate 
7210Sstevel@tonic-gate 		rv = ddi_soft_state_zalloc(dr_g.softsp, instance);
7220Sstevel@tonic-gate 		if (rv != DDI_SUCCESS) {
7230Sstevel@tonic-gate 			cmn_err(CE_WARN, "dr%d: failed to alloc soft-state",
7247656SSherry.Moore@Sun.COM 			    instance);
7250Sstevel@tonic-gate 			return (DDI_FAILURE);
7260Sstevel@tonic-gate 		}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 		/* initialize softstate structure */
7290Sstevel@tonic-gate 		softsp = ddi_get_soft_state(dr_g.softsp, instance);
7300Sstevel@tonic-gate 		softsp->dip = dip;
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 		mutex_init(&softsp->i_lock, NULL, MUTEX_DRIVER, NULL);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		/* allocate board array (aka boardlist) */
7350Sstevel@tonic-gate 		softsp->boards = GETSTRUCT(dr_board_t, MAX_BOARDS);
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 		/* TODO: eliminate dr_boardlist */
7380Sstevel@tonic-gate 		dr_boardlist = softsp->boards;
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 		/* initialize each array element */
7410Sstevel@tonic-gate 		rv = DDI_SUCCESS;
7420Sstevel@tonic-gate 		for (bd = 0; bd < MAX_BOARDS; bd++) {
7430Sstevel@tonic-gate 			dr_board_t	*bp = &softsp->boards[bd];
7440Sstevel@tonic-gate 			char		*p, *name;
7450Sstevel@tonic-gate 			int		 l, minor_num;
7460Sstevel@tonic-gate 
7470Sstevel@tonic-gate 			/*
7480Sstevel@tonic-gate 			 * initialized board attachment point path
7490Sstevel@tonic-gate 			 * (relative to pseudo) in a form immediately
7500Sstevel@tonic-gate 			 * reusable as an cfgadm command argument.
7510Sstevel@tonic-gate 			 * TODO: clean this up
7520Sstevel@tonic-gate 			 */
7530Sstevel@tonic-gate 			p = bp->b_path;
7540Sstevel@tonic-gate 			l = sizeof (bp->b_path);
7550Sstevel@tonic-gate 			(void) snprintf(p, l, "dr@%d:", instance);
7560Sstevel@tonic-gate 			while (*p != '\0') {
7570Sstevel@tonic-gate 				l--;
7580Sstevel@tonic-gate 				p++;
7590Sstevel@tonic-gate 			}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 			name = p;
7620Sstevel@tonic-gate 			err = drmach_board_name(bd, p, l);
7630Sstevel@tonic-gate 			if (err) {
7640Sstevel@tonic-gate 				sbd_err_clear(&err);
7650Sstevel@tonic-gate 				rv = DDI_FAILURE;
7660Sstevel@tonic-gate 				break;
7670Sstevel@tonic-gate 			}
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate 			minor_num = DR_MAKE_MINOR(instance, bd);
7700Sstevel@tonic-gate 			rv = ddi_create_minor_node(dip, name, S_IFCHR,
7717656SSherry.Moore@Sun.COM 			    minor_num, DDI_NT_SBD_ATTACHMENT_POINT, NULL);
7720Sstevel@tonic-gate 			if (rv != DDI_SUCCESS)
7730Sstevel@tonic-gate 				rv = DDI_FAILURE;
7740Sstevel@tonic-gate 		}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 		if (rv == DDI_SUCCESS) {
7770Sstevel@tonic-gate 			/*
7780Sstevel@tonic-gate 			 * Announce the node's presence.
7790Sstevel@tonic-gate 			 */
7800Sstevel@tonic-gate 			ddi_report_dev(dip);
7810Sstevel@tonic-gate 		} else {
7820Sstevel@tonic-gate 			ddi_remove_minor_node(dip, NULL);
7830Sstevel@tonic-gate 		}
7840Sstevel@tonic-gate 		/*
7850Sstevel@tonic-gate 		 * Init registered unsafe devs.
7860Sstevel@tonic-gate 		 */
7870Sstevel@tonic-gate 		dr_unsafe_devs.devnames = NULL;
7880Sstevel@tonic-gate 		rv2 = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip,
7897656SSherry.Moore@Sun.COM 		    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
7907656SSherry.Moore@Sun.COM 		    "unsupported-io-drivers", &dr_unsafe_devs.devnames,
7917656SSherry.Moore@Sun.COM 		    &dr_unsafe_devs.ndevs);
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 		if (rv2 != DDI_PROP_SUCCESS)
7940Sstevel@tonic-gate 			dr_unsafe_devs.ndevs = 0;
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 		rw_exit(&dr_grwlock);
7970Sstevel@tonic-gate 		return (rv);
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	default:
8000Sstevel@tonic-gate 		return (DDI_FAILURE);
8010Sstevel@tonic-gate 	}
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	/*NOTREACHED*/
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate static int
dr_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)8070Sstevel@tonic-gate dr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8080Sstevel@tonic-gate {
8090Sstevel@tonic-gate 	int 		instance;
8100Sstevel@tonic-gate 	dr_softstate_t	*softsp;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	switch (cmd) {
8130Sstevel@tonic-gate 	case DDI_DETACH:
8140Sstevel@tonic-gate 		if (!dr_modunload_okay)
8150Sstevel@tonic-gate 			return (DDI_FAILURE);
8160Sstevel@tonic-gate 
8170Sstevel@tonic-gate 		rw_enter(&dr_grwlock, RW_WRITER);
8180Sstevel@tonic-gate 
8190Sstevel@tonic-gate 		instance = ddi_get_instance(dip);
8200Sstevel@tonic-gate 		softsp = ddi_get_soft_state(dr_g.softsp, instance);
8210Sstevel@tonic-gate 
8220Sstevel@tonic-gate 		/* TODO: eliminate dr_boardlist */
8230Sstevel@tonic-gate 		ASSERT(softsp->boards == dr_boardlist);
8240Sstevel@tonic-gate 
8250Sstevel@tonic-gate 		/* remove all minor nodes */
8260Sstevel@tonic-gate 		ddi_remove_minor_node(dip, NULL);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 		if (softsp->dr_initialized) {
8290Sstevel@tonic-gate 			int bd;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 			for (bd = 0; bd < MAX_BOARDS; bd++)
8320Sstevel@tonic-gate 				dr_board_destroy(&softsp->boards[bd]);
8330Sstevel@tonic-gate 		}
8340Sstevel@tonic-gate 
8350Sstevel@tonic-gate 		FREESTRUCT(softsp->boards, dr_board_t, MAX_BOARDS);
8360Sstevel@tonic-gate 		mutex_destroy(&softsp->i_lock);
8370Sstevel@tonic-gate 		ddi_soft_state_free(dr_g.softsp, instance);
8380Sstevel@tonic-gate 
8390Sstevel@tonic-gate 		rw_exit(&dr_grwlock);
8400Sstevel@tonic-gate 		return (DDI_SUCCESS);
8410Sstevel@tonic-gate 
8420Sstevel@tonic-gate 	default:
8430Sstevel@tonic-gate 		return (DDI_FAILURE);
8440Sstevel@tonic-gate 	}
8450Sstevel@tonic-gate 	/*NOTREACHED*/
8460Sstevel@tonic-gate }
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate static int
dr_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** result)8490Sstevel@tonic-gate dr_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result)
8500Sstevel@tonic-gate {
8510Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip))
8520Sstevel@tonic-gate 
8530Sstevel@tonic-gate 	dev_t		dev = (dev_t)arg;
8540Sstevel@tonic-gate 	int		instance, error;
8550Sstevel@tonic-gate 	dr_softstate_t	*softsp;
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	*result = NULL;
8580Sstevel@tonic-gate 	error = DDI_SUCCESS;
8590Sstevel@tonic-gate 	instance = DR_MINOR2INST(getminor(dev));
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 	switch (cmd) {
8620Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
8630Sstevel@tonic-gate 		softsp = ddi_get_soft_state(dr_g.softsp, instance);
8640Sstevel@tonic-gate 		if (softsp == NULL)
8650Sstevel@tonic-gate 			return (DDI_FAILURE);
8660Sstevel@tonic-gate 		*result = (void *)softsp->dip;
8670Sstevel@tonic-gate 		break;
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
870930Smathue 		*result = (void *)(uintptr_t)instance;
8710Sstevel@tonic-gate 		break;
8720Sstevel@tonic-gate 
8730Sstevel@tonic-gate 	default:
8740Sstevel@tonic-gate 		error = DDI_FAILURE;
8750Sstevel@tonic-gate 		break;
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	return (error);
8790Sstevel@tonic-gate }
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate /*
8820Sstevel@tonic-gate  * DR operations.
8830Sstevel@tonic-gate  */
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate static int
dr_copyin_iocmd(dr_handle_t * hp)8860Sstevel@tonic-gate dr_copyin_iocmd(dr_handle_t *hp)
8870Sstevel@tonic-gate {
8880Sstevel@tonic-gate 	static fn_t	f = "dr_copyin_iocmd";
8890Sstevel@tonic-gate 	sbd_cmd_t	*scp = &hp->h_sbdcmd;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	if (hp->h_iap == NULL)
8920Sstevel@tonic-gate 		return (EINVAL);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	bzero((caddr_t)scp, sizeof (sbd_cmd_t));
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
8970Sstevel@tonic-gate 	if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) {
8980Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 		bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t));
9010Sstevel@tonic-gate 
9020Sstevel@tonic-gate 		if (ddi_copyin((void *)hp->h_iap, (void *)&scmd32,
9037656SSherry.Moore@Sun.COM 		    sizeof (sbd_cmd32_t), hp->h_mode)) {
9040Sstevel@tonic-gate 			cmn_err(CE_WARN,
9057656SSherry.Moore@Sun.COM 			    "%s: (32bit) failed to copyin "
9067656SSherry.Moore@Sun.COM 			    "sbdcmd-struct", f);
9070Sstevel@tonic-gate 			return (EFAULT);
9080Sstevel@tonic-gate 		}
9090Sstevel@tonic-gate 		scp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type;
9100Sstevel@tonic-gate 		scp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit;
9110Sstevel@tonic-gate 		bcopy(&scmd32.cmd_cm.c_id.c_name[0],
9127656SSherry.Moore@Sun.COM 		    &scp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME);
9130Sstevel@tonic-gate 		scp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags;
9140Sstevel@tonic-gate 		scp->cmd_cm.c_len = scmd32.cmd_cm.c_len;
915930Smathue 		scp->cmd_cm.c_opts = (caddr_t)(uintptr_t)scmd32.cmd_cm.c_opts;
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 		switch (hp->h_cmd) {
9180Sstevel@tonic-gate 		case SBD_CMD_STATUS:
9190Sstevel@tonic-gate 			scp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes;
9200Sstevel@tonic-gate 			scp->cmd_stat.s_statp =
9217656SSherry.Moore@Sun.COM 			    (caddr_t)(uintptr_t)scmd32.cmd_stat.s_statp;
9220Sstevel@tonic-gate 			break;
9230Sstevel@tonic-gate 		default:
9240Sstevel@tonic-gate 			break;
9250Sstevel@tonic-gate 
9260Sstevel@tonic-gate 		}
9270Sstevel@tonic-gate 	} else
9280Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
9290Sstevel@tonic-gate 	if (ddi_copyin((void *)hp->h_iap, (void *)scp,
9307656SSherry.Moore@Sun.COM 	    sizeof (sbd_cmd_t), hp->h_mode) != 0) {
9310Sstevel@tonic-gate 		cmn_err(CE_WARN,
9327656SSherry.Moore@Sun.COM 		    "%s: failed to copyin sbdcmd-struct", f);
9330Sstevel@tonic-gate 		return (EFAULT);
9340Sstevel@tonic-gate 	}
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	if ((hp->h_opts.size = scp->cmd_cm.c_len) != 0) {
9370Sstevel@tonic-gate 		hp->h_opts.copts = GETSTRUCT(char, scp->cmd_cm.c_len + 1);
9380Sstevel@tonic-gate 		++hp->h_opts.size;
9390Sstevel@tonic-gate 		if (ddi_copyin((void *)scp->cmd_cm.c_opts,
9407656SSherry.Moore@Sun.COM 		    (void *)hp->h_opts.copts,
9417656SSherry.Moore@Sun.COM 		    scp->cmd_cm.c_len, hp->h_mode) != 0) {
9420Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: failed to copyin options", f);
9430Sstevel@tonic-gate 			return (EFAULT);
9440Sstevel@tonic-gate 		}
9450Sstevel@tonic-gate 	}
9460Sstevel@tonic-gate 	return (0);
9470Sstevel@tonic-gate }
9480Sstevel@tonic-gate 
9490Sstevel@tonic-gate static int
dr_copyout_iocmd(dr_handle_t * hp)9500Sstevel@tonic-gate dr_copyout_iocmd(dr_handle_t *hp)
9510Sstevel@tonic-gate {
9520Sstevel@tonic-gate 	static fn_t	f = "dr_copyout_iocmd";
9530Sstevel@tonic-gate 	sbd_cmd_t	*scp = &hp->h_sbdcmd;
9540Sstevel@tonic-gate 
9550Sstevel@tonic-gate 	if (hp->h_iap == NULL)
9560Sstevel@tonic-gate 		return (EINVAL);
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
9590Sstevel@tonic-gate 	if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) {
9600Sstevel@tonic-gate 		sbd_cmd32_t	scmd32;
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type;
9630Sstevel@tonic-gate 		scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit;
9640Sstevel@tonic-gate 		bcopy(&scp->cmd_cm.c_id.c_name[0],
9657656SSherry.Moore@Sun.COM 		    &scmd32.cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME);
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 		scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags;
9680Sstevel@tonic-gate 		scmd32.cmd_cm.c_len = scp->cmd_cm.c_len;
969930Smathue 		scmd32.cmd_cm.c_opts = (caddr32_t)(uintptr_t)scp->cmd_cm.c_opts;
9700Sstevel@tonic-gate 
9710Sstevel@tonic-gate 		switch (hp->h_cmd) {
9720Sstevel@tonic-gate 		case SBD_CMD_GETNCM:
9730Sstevel@tonic-gate 			scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm;
9740Sstevel@tonic-gate 			break;
9750Sstevel@tonic-gate 		default:
9760Sstevel@tonic-gate 			break;
9770Sstevel@tonic-gate 		}
9780Sstevel@tonic-gate 
9790Sstevel@tonic-gate 		if (ddi_copyout((void *)&scmd32, (void *)hp->h_iap,
9807656SSherry.Moore@Sun.COM 		    sizeof (sbd_cmd32_t), hp->h_mode)) {
9810Sstevel@tonic-gate 			cmn_err(CE_WARN,
9827656SSherry.Moore@Sun.COM 			    "%s: (32bit) failed to copyout "
9837656SSherry.Moore@Sun.COM 			    "sbdcmd-struct", f);
9840Sstevel@tonic-gate 			return (EFAULT);
9850Sstevel@tonic-gate 		}
9860Sstevel@tonic-gate 	} else
9870Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
9880Sstevel@tonic-gate 	if (ddi_copyout((void *)scp, (void *)hp->h_iap,
9897656SSherry.Moore@Sun.COM 	    sizeof (sbd_cmd_t), hp->h_mode) != 0) {
9900Sstevel@tonic-gate 		cmn_err(CE_WARN,
9917656SSherry.Moore@Sun.COM 		    "%s: failed to copyout sbdcmd-struct", f);
9920Sstevel@tonic-gate 		return (EFAULT);
9930Sstevel@tonic-gate 	}
9940Sstevel@tonic-gate 
9950Sstevel@tonic-gate 	return (0);
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate static int
dr_copyout_errs(dr_handle_t * hp)9990Sstevel@tonic-gate dr_copyout_errs(dr_handle_t *hp)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	static fn_t	f = "dr_copyout_errs";
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	if (hp->h_err == NULL)
10040Sstevel@tonic-gate 		return (0);
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate 	if (hp->h_err->e_code) {
10070Sstevel@tonic-gate 		PR_ALL("%s: error %d %s",
10087656SSherry.Moore@Sun.COM 		    f, hp->h_err->e_code, hp->h_err->e_rsc);
10090Sstevel@tonic-gate 	}
10100Sstevel@tonic-gate 
10110Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
10120Sstevel@tonic-gate 	if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) {
10130Sstevel@tonic-gate 		sbd_error32_t	*serr32p;
10140Sstevel@tonic-gate 
10150Sstevel@tonic-gate 		serr32p = GETSTRUCT(sbd_error32_t, 1);
10160Sstevel@tonic-gate 
10170Sstevel@tonic-gate 		serr32p->e_code = hp->h_err->e_code;
10180Sstevel@tonic-gate 		bcopy(&hp->h_err->e_rsc[0], &serr32p->e_rsc[0],
10197656SSherry.Moore@Sun.COM 		    MAXPATHLEN);
10200Sstevel@tonic-gate 		if (ddi_copyout((void *)serr32p,
10217656SSherry.Moore@Sun.COM 		    (void *)&((sbd_ioctl_arg32_t *)hp->h_iap)->i_err,
10227656SSherry.Moore@Sun.COM 		    sizeof (sbd_error32_t), hp->h_mode)) {
10230Sstevel@tonic-gate 			cmn_err(CE_WARN,
10247656SSherry.Moore@Sun.COM 			    "%s: (32bit) failed to copyout", f);
10250Sstevel@tonic-gate 			return (EFAULT);
10260Sstevel@tonic-gate 		}
10270Sstevel@tonic-gate 		FREESTRUCT(serr32p, sbd_error32_t, 1);
10280Sstevel@tonic-gate 	} else
10290Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
10300Sstevel@tonic-gate 	if (ddi_copyout((void *)hp->h_err,
10317656SSherry.Moore@Sun.COM 	    (void *)&hp->h_iap->i_err,
10327656SSherry.Moore@Sun.COM 	    sizeof (sbd_error_t), hp->h_mode)) {
10330Sstevel@tonic-gate 		cmn_err(CE_WARN,
10347656SSherry.Moore@Sun.COM 		    "%s: failed to copyout", f);
10350Sstevel@tonic-gate 		return (EFAULT);
10360Sstevel@tonic-gate 	}
10370Sstevel@tonic-gate 
10380Sstevel@tonic-gate 	sbd_err_clear(&hp->h_err);
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate 	return (0);
10410Sstevel@tonic-gate 
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate /*
10450Sstevel@tonic-gate  * pre-op entry point must sbd_err_set_c(), if needed.
10460Sstevel@tonic-gate  * Return value of non-zero indicates failure.
10470Sstevel@tonic-gate  */
10480Sstevel@tonic-gate static int
dr_pre_op(dr_handle_t * hp)10490Sstevel@tonic-gate dr_pre_op(dr_handle_t *hp)
10500Sstevel@tonic-gate {
10510Sstevel@tonic-gate 	int		rv = 0, t;
10520Sstevel@tonic-gate 	int		cmd, serr = 0;
10530Sstevel@tonic-gate 	dr_devset_t	devset;
10540Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
10550Sstevel@tonic-gate 	dr_handle_t	*shp = hp;
10560Sstevel@tonic-gate 	static fn_t	f = "dr_pre_op";
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	cmd = hp->h_cmd;
10590Sstevel@tonic-gate 	devset = shp->h_devset;
10600Sstevel@tonic-gate 
1061930Smathue 	PR_ALL("%s (cmd = %s)...\n", f, SBD_CMD_STR(cmd));
10620Sstevel@tonic-gate 
10630Sstevel@tonic-gate 	hp->h_err = drmach_pre_op(cmd, bp->b_id, &hp->h_opts);
10640Sstevel@tonic-gate 	if (hp->h_err != NULL) {
10650Sstevel@tonic-gate 		PR_ALL("drmach_pre_op failed for cmd %s(%d)\n",
10667656SSherry.Moore@Sun.COM 		    SBD_CMD_STR(cmd), cmd);
10670Sstevel@tonic-gate 		return (-1);
10680Sstevel@tonic-gate 	}
10690Sstevel@tonic-gate 
10700Sstevel@tonic-gate 	/*
10710Sstevel@tonic-gate 	 * Check for valid state transitions.
10720Sstevel@tonic-gate 	 */
10730Sstevel@tonic-gate 	if ((t = CMD2INDEX(cmd)) != -1) {
10740Sstevel@tonic-gate 		struct dr_state_trans	*transp;
10750Sstevel@tonic-gate 		int			state_err;
10760Sstevel@tonic-gate 
10770Sstevel@tonic-gate 		transp = &dr_state_transition[t];
10780Sstevel@tonic-gate 		ASSERT(transp->x_cmd == cmd);
10790Sstevel@tonic-gate 
10800Sstevel@tonic-gate 		state_err = dr_check_transition(bp, &devset, transp, cmd);
10810Sstevel@tonic-gate 
10820Sstevel@tonic-gate 		if (state_err < 0) {
10830Sstevel@tonic-gate 			/*
10840Sstevel@tonic-gate 			 * Invalidate device.
10850Sstevel@tonic-gate 			 */
10860Sstevel@tonic-gate 			dr_op_err(CE_IGNORE, hp, ESBD_INVAL, NULL);
10870Sstevel@tonic-gate 			serr = -1;
10880Sstevel@tonic-gate 			PR_ALL("%s: invalid devset (0x%x)\n",
10897656SSherry.Moore@Sun.COM 			    f, (uint_t)devset);
10900Sstevel@tonic-gate 		} else if (state_err != 0) {
10910Sstevel@tonic-gate 			/*
10920Sstevel@tonic-gate 			 * State transition is not a valid one.
10930Sstevel@tonic-gate 			 */
10940Sstevel@tonic-gate 			dr_op_err(CE_IGNORE, hp,
10957656SSherry.Moore@Sun.COM 			    transp->x_op[state_err].x_err, NULL);
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 			serr = transp->x_op[state_err].x_rv;
10980Sstevel@tonic-gate 
10990Sstevel@tonic-gate 			PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n",
11007656SSherry.Moore@Sun.COM 			    f, state_str[state_err], state_err,
11017656SSherry.Moore@Sun.COM 			    SBD_CMD_STR(cmd), cmd);
11020Sstevel@tonic-gate 		} else {
11030Sstevel@tonic-gate 			shp->h_devset = devset;
11040Sstevel@tonic-gate 		}
11050Sstevel@tonic-gate 	}
11060Sstevel@tonic-gate 
11070Sstevel@tonic-gate 	if (serr) {
11080Sstevel@tonic-gate 		rv = -1;
11090Sstevel@tonic-gate 	}
11100Sstevel@tonic-gate 
11110Sstevel@tonic-gate 	return (rv);
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate static int
dr_post_op(dr_handle_t * hp)11150Sstevel@tonic-gate dr_post_op(dr_handle_t *hp)
11160Sstevel@tonic-gate {
11170Sstevel@tonic-gate 	int		rv = 0;
11180Sstevel@tonic-gate 	int		cmd;
11190Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
11200Sstevel@tonic-gate 	static fn_t	f = "dr_post_op";
11210Sstevel@tonic-gate 
11220Sstevel@tonic-gate 	cmd = hp->h_cmd;
11230Sstevel@tonic-gate 
1124930Smathue 	PR_ALL("%s (cmd = %s)...\n", f, SBD_CMD_STR(cmd));
11250Sstevel@tonic-gate 
11260Sstevel@tonic-gate 	/* errors should have been caught by now */
11270Sstevel@tonic-gate 	ASSERT(hp->h_err == NULL);
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	hp->h_err = drmach_post_op(cmd, bp->b_id, &hp->h_opts);
11300Sstevel@tonic-gate 	if (hp->h_err != NULL) {
11310Sstevel@tonic-gate 		PR_ALL("drmach_post_op failed for cmd %s(%d)\n",
11327656SSherry.Moore@Sun.COM 		    SBD_CMD_STR(cmd), cmd);
11330Sstevel@tonic-gate 		return (-1);
11340Sstevel@tonic-gate 	}
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 	switch (cmd) {
11370Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
11380Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
11390Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
11400Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
11410Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
11420Sstevel@tonic-gate 	case SBD_CMD_STATUS:
11430Sstevel@tonic-gate 		break;
11440Sstevel@tonic-gate 
11450Sstevel@tonic-gate 	default:
11460Sstevel@tonic-gate 		break;
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 
11490Sstevel@tonic-gate 	return (rv);
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate static int
dr_exec_op(dr_handle_t * hp)11530Sstevel@tonic-gate dr_exec_op(dr_handle_t *hp)
11540Sstevel@tonic-gate {
11550Sstevel@tonic-gate 	int		rv = 0;
11560Sstevel@tonic-gate 	static fn_t	f = "dr_exec_op";
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate 	/* errors should have been caught by now */
11590Sstevel@tonic-gate 	ASSERT(hp->h_err == NULL);
11600Sstevel@tonic-gate 
11610Sstevel@tonic-gate 	switch (hp->h_cmd) {
11620Sstevel@tonic-gate 	case SBD_CMD_ASSIGN:
11630Sstevel@tonic-gate 		dr_assign_board(hp);
11640Sstevel@tonic-gate 		break;
11650Sstevel@tonic-gate 
11660Sstevel@tonic-gate 	case SBD_CMD_UNASSIGN:
11670Sstevel@tonic-gate 		dr_unassign_board(hp);
11680Sstevel@tonic-gate 		break;
11690Sstevel@tonic-gate 
11700Sstevel@tonic-gate 	case SBD_CMD_POWEROFF:
11710Sstevel@tonic-gate 		dr_poweroff_board(hp);
11720Sstevel@tonic-gate 		break;
11730Sstevel@tonic-gate 
11740Sstevel@tonic-gate 	case SBD_CMD_POWERON:
11750Sstevel@tonic-gate 		dr_poweron_board(hp);
11760Sstevel@tonic-gate 		break;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	case SBD_CMD_TEST:
11790Sstevel@tonic-gate 		dr_test_board(hp);
11800Sstevel@tonic-gate 		break;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	case SBD_CMD_CONNECT:
11830Sstevel@tonic-gate 		dr_connect(hp);
11840Sstevel@tonic-gate 		break;
11850Sstevel@tonic-gate 
11860Sstevel@tonic-gate 	case SBD_CMD_CONFIGURE:
11870Sstevel@tonic-gate 		dr_dev_configure(hp);
11880Sstevel@tonic-gate 		break;
11890Sstevel@tonic-gate 
11900Sstevel@tonic-gate 	case SBD_CMD_UNCONFIGURE:
11910Sstevel@tonic-gate 		dr_dev_release(hp);
11920Sstevel@tonic-gate 		if (hp->h_err == NULL)
11930Sstevel@tonic-gate 			rv = dr_dev_unconfigure(hp);
11940Sstevel@tonic-gate 		else
11950Sstevel@tonic-gate 			dr_dev_cancel(hp);
11960Sstevel@tonic-gate 		break;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	case SBD_CMD_DISCONNECT:
11990Sstevel@tonic-gate 		rv = dr_disconnect(hp);
12000Sstevel@tonic-gate 		break;
12010Sstevel@tonic-gate 
12020Sstevel@tonic-gate 	case SBD_CMD_STATUS:
12030Sstevel@tonic-gate 		rv = dr_dev_status(hp);
12040Sstevel@tonic-gate 		break;
12050Sstevel@tonic-gate 
12060Sstevel@tonic-gate 	case SBD_CMD_GETNCM:
12070Sstevel@tonic-gate 		hp->h_sbdcmd.cmd_getncm.g_ncm = dr_get_ncm(hp);
12080Sstevel@tonic-gate 		rv = dr_copyout_iocmd(hp);
12090Sstevel@tonic-gate 		break;
12100Sstevel@tonic-gate 
12110Sstevel@tonic-gate 	case SBD_CMD_PASSTHRU:
12120Sstevel@tonic-gate 		rv = dr_pt_ioctl(hp);
12130Sstevel@tonic-gate 		break;
12140Sstevel@tonic-gate 
12150Sstevel@tonic-gate 	default:
12160Sstevel@tonic-gate 		cmn_err(CE_WARN,
12177656SSherry.Moore@Sun.COM 		    "%s: unknown command (%d)",
12187656SSherry.Moore@Sun.COM 		    f, hp->h_cmd);
12190Sstevel@tonic-gate 		break;
12200Sstevel@tonic-gate 	}
12210Sstevel@tonic-gate 
12220Sstevel@tonic-gate 	if (hp->h_err != NULL) {
12230Sstevel@tonic-gate 		rv = -1;
12240Sstevel@tonic-gate 	}
12250Sstevel@tonic-gate 
12260Sstevel@tonic-gate 	return (rv);
12270Sstevel@tonic-gate }
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate static void
dr_assign_board(dr_handle_t * hp)12300Sstevel@tonic-gate dr_assign_board(dr_handle_t *hp)
12310Sstevel@tonic-gate {
12320Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	hp->h_err = drmach_board_assign(bp->b_num, &bp->b_id);
12350Sstevel@tonic-gate 	if (hp->h_err == NULL) {
12360Sstevel@tonic-gate 		bp->b_assigned = 1;
12370Sstevel@tonic-gate 	}
12380Sstevel@tonic-gate }
12390Sstevel@tonic-gate 
12400Sstevel@tonic-gate static void
dr_unassign_board(dr_handle_t * hp)12410Sstevel@tonic-gate dr_unassign_board(dr_handle_t *hp)
12420Sstevel@tonic-gate {
12430Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
12440Sstevel@tonic-gate 
12450Sstevel@tonic-gate 	/*
12460Sstevel@tonic-gate 	 * Block out status during unassign.
12470Sstevel@tonic-gate 	 * Not doing cv_wait_sig here as starfire SSP software
12480Sstevel@tonic-gate 	 * ignores unassign failure and removes board from
12490Sstevel@tonic-gate 	 * domain mask causing system panic.
12500Sstevel@tonic-gate 	 * TODO: Change cv_wait to cv_wait_sig when SSP software
12510Sstevel@tonic-gate 	 * handles unassign failure.
12520Sstevel@tonic-gate 	 */
12530Sstevel@tonic-gate 	dr_lock_status(bp);
12540Sstevel@tonic-gate 
12550Sstevel@tonic-gate 	hp->h_err = drmach_board_unassign(bp->b_id);
12560Sstevel@tonic-gate 	if (hp->h_err == NULL) {
12570Sstevel@tonic-gate 		/*
12580Sstevel@tonic-gate 		 * clear drmachid_t handle; not valid after board unassign
12590Sstevel@tonic-gate 		 */
12600Sstevel@tonic-gate 		bp->b_id = 0;
12610Sstevel@tonic-gate 		bp->b_assigned = 0;
12620Sstevel@tonic-gate 	}
12630Sstevel@tonic-gate 
12640Sstevel@tonic-gate 	dr_unlock_status(bp);
12650Sstevel@tonic-gate }
12660Sstevel@tonic-gate 
12670Sstevel@tonic-gate static void
dr_poweron_board(dr_handle_t * hp)12680Sstevel@tonic-gate dr_poweron_board(dr_handle_t *hp)
12690Sstevel@tonic-gate {
12700Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
12710Sstevel@tonic-gate 
12720Sstevel@tonic-gate 	hp->h_err = drmach_board_poweron(bp->b_id);
12730Sstevel@tonic-gate }
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate static void
dr_poweroff_board(dr_handle_t * hp)12760Sstevel@tonic-gate dr_poweroff_board(dr_handle_t *hp)
12770Sstevel@tonic-gate {
12780Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	hp->h_err = drmach_board_poweroff(bp->b_id);
12810Sstevel@tonic-gate }
12820Sstevel@tonic-gate 
12830Sstevel@tonic-gate static void
dr_test_board(dr_handle_t * hp)12840Sstevel@tonic-gate dr_test_board(dr_handle_t *hp)
12850Sstevel@tonic-gate {
12860Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
12870Sstevel@tonic-gate 	hp->h_err = drmach_board_test(bp->b_id, &hp->h_opts,
12880Sstevel@tonic-gate 	    dr_cmd_flags(hp) & SBD_FLAG_FORCE);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate  * Create and populate the component nodes for a board.  Assumes that the
12930Sstevel@tonic-gate  * devlists for the board have been initialized.
12940Sstevel@tonic-gate  */
12950Sstevel@tonic-gate static void
dr_make_comp_nodes(dr_board_t * bp)12960Sstevel@tonic-gate dr_make_comp_nodes(dr_board_t *bp) {
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	int	i;
12990Sstevel@tonic-gate 
13000Sstevel@tonic-gate 	/*
13010Sstevel@tonic-gate 	 * Make nodes for the individual components on the board.
13020Sstevel@tonic-gate 	 * First we need to initialize memory unit data structures of board
13030Sstevel@tonic-gate 	 * structure.
13040Sstevel@tonic-gate 	 */
13050Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
13060Sstevel@tonic-gate 		dr_mem_unit_t *mp;
13070Sstevel@tonic-gate 
13080Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
13090Sstevel@tonic-gate 		dr_init_mem_unit(mp);
13100Sstevel@tonic-gate 	}
13110Sstevel@tonic-gate 
13120Sstevel@tonic-gate 	/*
13130Sstevel@tonic-gate 	 * Initialize cpu unit data structures.
13140Sstevel@tonic-gate 	 */
13150Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
13160Sstevel@tonic-gate 		dr_cpu_unit_t *cp;
13170Sstevel@tonic-gate 
13180Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
13190Sstevel@tonic-gate 		dr_init_cpu_unit(cp);
13200Sstevel@tonic-gate 	}
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate 	/*
13230Sstevel@tonic-gate 	 * Initialize io unit data structures.
13240Sstevel@tonic-gate 	 */
13250Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
13260Sstevel@tonic-gate 		dr_io_unit_t *ip;
13270Sstevel@tonic-gate 
13280Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
13290Sstevel@tonic-gate 		dr_init_io_unit(ip);
13300Sstevel@tonic-gate 	}
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 	dr_board_transition(bp, DR_STATE_CONNECTED);
13330Sstevel@tonic-gate 
13340Sstevel@tonic-gate 	bp->b_rstate = SBD_STAT_CONNECTED;
13350Sstevel@tonic-gate 	bp->b_ostate = SBD_STAT_UNCONFIGURED;
13360Sstevel@tonic-gate 	bp->b_cond = SBD_COND_OK;
13370Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *)&bp->b_time);
13380Sstevel@tonic-gate 
13390Sstevel@tonic-gate }
13400Sstevel@tonic-gate 
13410Sstevel@tonic-gate /*
13420Sstevel@tonic-gate  * Only do work if called to operate on an entire board
13430Sstevel@tonic-gate  * which doesn't already have components present.
13440Sstevel@tonic-gate  */
13450Sstevel@tonic-gate static void
dr_connect(dr_handle_t * hp)13460Sstevel@tonic-gate dr_connect(dr_handle_t *hp)
13470Sstevel@tonic-gate {
13480Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
13490Sstevel@tonic-gate 	static fn_t	f = "dr_connect";
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
13520Sstevel@tonic-gate 
13530Sstevel@tonic-gate 	if (DR_DEVS_PRESENT(bp)) {
13540Sstevel@tonic-gate 		/*
13550Sstevel@tonic-gate 		 * Board already has devices present.
13560Sstevel@tonic-gate 		 */
13571772Sjl139090 		PR_ALL("%s: devices already present (0x%lx)\n",
13587656SSherry.Moore@Sun.COM 		    f, DR_DEVS_PRESENT(bp));
13590Sstevel@tonic-gate 		return;
13600Sstevel@tonic-gate 	}
13610Sstevel@tonic-gate 
13620Sstevel@tonic-gate 	hp->h_err = drmach_board_connect(bp->b_id, &hp->h_opts);
13630Sstevel@tonic-gate 	if (hp->h_err)
13640Sstevel@tonic-gate 		return;
13650Sstevel@tonic-gate 
13660Sstevel@tonic-gate 	hp->h_err = dr_init_devlists(bp);
13670Sstevel@tonic-gate 	if (hp->h_err)
13680Sstevel@tonic-gate 		return;
13690Sstevel@tonic-gate 	else if (bp->b_ndev == 0) {
13700Sstevel@tonic-gate 		dr_op_err(CE_WARN, hp, ESBD_EMPTY_BD, bp->b_path);
13710Sstevel@tonic-gate 		return;
13720Sstevel@tonic-gate 	} else {
13730Sstevel@tonic-gate 		dr_make_comp_nodes(bp);
13740Sstevel@tonic-gate 		return;
13750Sstevel@tonic-gate 	}
13760Sstevel@tonic-gate 	/*NOTREACHED*/
13770Sstevel@tonic-gate }
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate static int
dr_disconnect(dr_handle_t * hp)13800Sstevel@tonic-gate dr_disconnect(dr_handle_t *hp)
13810Sstevel@tonic-gate {
13820Sstevel@tonic-gate 	int		i;
13830Sstevel@tonic-gate 	dr_devset_t	devset;
13840Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
13850Sstevel@tonic-gate 	static fn_t	f = "dr_disconnect";
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
13880Sstevel@tonic-gate 
13890Sstevel@tonic-gate 	/*
13900Sstevel@tonic-gate 	 * Only devices which are present, but
13910Sstevel@tonic-gate 	 * unattached can be disconnected.
13920Sstevel@tonic-gate 	 */
13930Sstevel@tonic-gate 	devset = hp->h_devset & DR_DEVS_PRESENT(bp) &
13947656SSherry.Moore@Sun.COM 	    DR_DEVS_UNATTACHED(bp);
13950Sstevel@tonic-gate 
13960Sstevel@tonic-gate 	if ((devset == 0) && DR_DEVS_PRESENT(bp)) {
13970Sstevel@tonic-gate 		dr_op_err(CE_IGNORE, hp, ESBD_EMPTY_BD, bp->b_path);
13980Sstevel@tonic-gate 		return (0);
13990Sstevel@tonic-gate 	}
14000Sstevel@tonic-gate 
14010Sstevel@tonic-gate 	/*
14020Sstevel@tonic-gate 	 * Block out status during disconnect.
14030Sstevel@tonic-gate 	 */
14040Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
14050Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK) {
14060Sstevel@tonic-gate 		if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) {
14070Sstevel@tonic-gate 			mutex_exit(&bp->b_slock);
14080Sstevel@tonic-gate 			return (EINTR);
14090Sstevel@tonic-gate 		}
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
14120Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
14130Sstevel@tonic-gate 
14140Sstevel@tonic-gate 	hp->h_err = drmach_board_disconnect(bp->b_id, &hp->h_opts);
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	DR_DEVS_DISCONNECT(bp, devset);
14170Sstevel@tonic-gate 
14180Sstevel@tonic-gate 	ASSERT((DR_DEVS_ATTACHED(bp) & devset) == 0);
14190Sstevel@tonic-gate 
14200Sstevel@tonic-gate 	/*
14210Sstevel@tonic-gate 	 * Update per-device state transitions.
14220Sstevel@tonic-gate 	 */
14230Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
14240Sstevel@tonic-gate 		dr_cpu_unit_t *cp;
14250Sstevel@tonic-gate 
14260Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i))
14270Sstevel@tonic-gate 			continue;
14280Sstevel@tonic-gate 
14290Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
14300Sstevel@tonic-gate 		if (dr_disconnect_cpu(cp) == 0)
14310Sstevel@tonic-gate 			dr_device_transition(&cp->sbc_cm, DR_STATE_EMPTY);
14320Sstevel@tonic-gate 		else if (cp->sbc_cm.sbdev_error != NULL)
14330Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &cp->sbc_cm.sbdev_error);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 		ASSERT(cp->sbc_cm.sbdev_error == NULL);
14360Sstevel@tonic-gate 	}
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
14390Sstevel@tonic-gate 		dr_mem_unit_t *mp;
14400Sstevel@tonic-gate 
14410Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i))
14420Sstevel@tonic-gate 			continue;
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
14450Sstevel@tonic-gate 		if (dr_disconnect_mem(mp) == 0)
14460Sstevel@tonic-gate 			dr_device_transition(&mp->sbm_cm, DR_STATE_EMPTY);
14470Sstevel@tonic-gate 		else if (mp->sbm_cm.sbdev_error != NULL)
14480Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &mp->sbm_cm.sbdev_error);
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 		ASSERT(mp->sbm_cm.sbdev_error == NULL);
14510Sstevel@tonic-gate 	}
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
14540Sstevel@tonic-gate 		dr_io_unit_t *ip;
14550Sstevel@tonic-gate 
14560Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i))
14570Sstevel@tonic-gate 			continue;
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
14600Sstevel@tonic-gate 		if (dr_disconnect_io(ip) == 0)
14610Sstevel@tonic-gate 			dr_device_transition(&ip->sbi_cm, DR_STATE_EMPTY);
14620Sstevel@tonic-gate 		else if (ip->sbi_cm.sbdev_error != NULL)
14630Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &ip->sbi_cm.sbdev_error);
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 		ASSERT(ip->sbi_cm.sbdev_error == NULL);
14660Sstevel@tonic-gate 	}
14670Sstevel@tonic-gate 	if (hp->h_err) {
14680Sstevel@tonic-gate 		/*
14690Sstevel@tonic-gate 		 * For certain errors, drmach_board_disconnect will mark
14700Sstevel@tonic-gate 		 * the board as unusable; in these cases the devtree must
14710Sstevel@tonic-gate 		 * be purged so that status calls will succeed.
14720Sstevel@tonic-gate 		 * XXX
14730Sstevel@tonic-gate 		 * This implementation checks for discrete error codes -
14740Sstevel@tonic-gate 		 * someday, the i/f to drmach_board_disconnect should be
14750Sstevel@tonic-gate 		 * changed to avoid the e_code testing.
14760Sstevel@tonic-gate 		 */
14770Sstevel@tonic-gate 		if ((hp->h_err->e_code == ESTC_MBXRPLY) ||
14787656SSherry.Moore@Sun.COM 		    (hp->h_err->e_code == ESTC_MBXRQST) ||
14797656SSherry.Moore@Sun.COM 		    (hp->h_err->e_code == ESTC_SMS_ERR_UNRECOVERABLE) ||
14807656SSherry.Moore@Sun.COM 		    (hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) ||
14817656SSherry.Moore@Sun.COM 		    (hp->h_err->e_code == ESTC_DEPROBE) ||
14827656SSherry.Moore@Sun.COM 		    (hp->h_err->e_code == EOPL_DEPROBE)) {
14830Sstevel@tonic-gate 			bp->b_ostate = SBD_STAT_UNCONFIGURED;
14840Sstevel@tonic-gate 			bp->b_busy = 0;
14850Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
14860Sstevel@tonic-gate 
14870Sstevel@tonic-gate 			if (drmach_board_deprobe(bp->b_id))
14880Sstevel@tonic-gate 				goto disconnect_done;
14890Sstevel@tonic-gate 			else
14900Sstevel@tonic-gate 				bp->b_ndev = 0;
14910Sstevel@tonic-gate 		}
14920Sstevel@tonic-gate 
14930Sstevel@tonic-gate 		/*
14940Sstevel@tonic-gate 		 * If the disconnect failed in a recoverable way,
14950Sstevel@tonic-gate 		 * more work is required.
14960Sstevel@tonic-gate 		 * XXX
14970Sstevel@tonic-gate 		 * This implementation checks for discrete error codes -
14980Sstevel@tonic-gate 		 * someday, the i/f to drmach_board_disconnect should be
14990Sstevel@tonic-gate 		 * changed to avoid the e_code testing.
15000Sstevel@tonic-gate 		 */
15010Sstevel@tonic-gate 		if ((hp->h_err->e_code == ESTC_MBXRQST) ||
15020Sstevel@tonic-gate 		    (hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) ||
15033354Sjl139090 		    (hp->h_err->e_code == ESTC_DEPROBE) ||
15043354Sjl139090 		    (hp->h_err->e_code == EOPL_DEPROBE)) {
15050Sstevel@tonic-gate 			/*
15060Sstevel@tonic-gate 			 * With this failure, the board has been deprobed
15070Sstevel@tonic-gate 			 * by IKP, and reprobed.  We've already gotten rid
15080Sstevel@tonic-gate 			 * of the old devtree, now we need to reconstruct it
15090Sstevel@tonic-gate 			 * based on the new IKP probe
15100Sstevel@tonic-gate 			 */
15110Sstevel@tonic-gate 			if (dr_init_devlists(bp) || (bp->b_ndev == 0))
15120Sstevel@tonic-gate 				goto disconnect_done;
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate 			dr_make_comp_nodes(bp);
15150Sstevel@tonic-gate 		}
15160Sstevel@tonic-gate 	}
15170Sstevel@tonic-gate 	/*
15180Sstevel@tonic-gate 	 * Once all the components on a board have been disconnect
15190Sstevel@tonic-gate 	 * the board's state can transition to disconnected and
15200Sstevel@tonic-gate 	 * we can allow the deprobe to take place.
15210Sstevel@tonic-gate 	 */
15220Sstevel@tonic-gate 	if (hp->h_err == NULL && DR_DEVS_PRESENT(bp) == 0) {
15230Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_OCCUPIED);
15240Sstevel@tonic-gate 		bp->b_rstate = SBD_STAT_DISCONNECTED;
15250Sstevel@tonic-gate 		bp->b_ostate = SBD_STAT_UNCONFIGURED;
15260Sstevel@tonic-gate 		bp->b_busy = 0;
15270Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&bp->b_time);
15280Sstevel@tonic-gate 
15290Sstevel@tonic-gate 		hp->h_err = drmach_board_deprobe(bp->b_id);
15300Sstevel@tonic-gate 
15310Sstevel@tonic-gate 		if (hp->h_err == NULL) {
15320Sstevel@tonic-gate 			bp->b_ndev = 0;
15330Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_EMPTY);
15340Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_EMPTY;
15350Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
15360Sstevel@tonic-gate 		}
15370Sstevel@tonic-gate 	}
15380Sstevel@tonic-gate 
15390Sstevel@tonic-gate disconnect_done:
15400Sstevel@tonic-gate 	dr_unlock_status(bp);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	return (0);
15430Sstevel@tonic-gate }
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate /*
15460Sstevel@tonic-gate  * Check if a particular device is a valid target of the current
15470Sstevel@tonic-gate  * operation. Return 1 if it is a valid target, and 0 otherwise.
15480Sstevel@tonic-gate  */
15490Sstevel@tonic-gate static int
dr_dev_is_target(dr_dev_unit_t * dp,int present_only,uint_t uset)15500Sstevel@tonic-gate dr_dev_is_target(dr_dev_unit_t *dp, int present_only, uint_t uset)
15510Sstevel@tonic-gate {
15520Sstevel@tonic-gate 	dr_common_unit_t *cp;
15530Sstevel@tonic-gate 	int		 is_present;
15540Sstevel@tonic-gate 	int		 is_attached;
15550Sstevel@tonic-gate 
15560Sstevel@tonic-gate 	cp = &dp->du_common;
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 	/* check if the user requested this device */
15590Sstevel@tonic-gate 	if ((uset & (1 << cp->sbdev_unum)) == 0) {
15600Sstevel@tonic-gate 		return (0);
15610Sstevel@tonic-gate 	}
15620Sstevel@tonic-gate 
15630Sstevel@tonic-gate 	is_present = DR_DEV_IS_PRESENT(cp) ? 1 : 0;
15640Sstevel@tonic-gate 	is_attached = DR_DEV_IS_ATTACHED(cp) ? 1 : 0;
15650Sstevel@tonic-gate 
15660Sstevel@tonic-gate 	/*
15670Sstevel@tonic-gate 	 * If the present_only flag is set, a valid target
15680Sstevel@tonic-gate 	 * must be present but not attached. Otherwise, it
15690Sstevel@tonic-gate 	 * must be both present and attached.
15700Sstevel@tonic-gate 	 */
15710Sstevel@tonic-gate 	if (is_present && (present_only ^ is_attached)) {
15720Sstevel@tonic-gate 		/* sanity check */
15730Sstevel@tonic-gate 		ASSERT(cp->sbdev_id != (drmachid_t)0);
15740Sstevel@tonic-gate 
15750Sstevel@tonic-gate 		return (1);
15760Sstevel@tonic-gate 	}
15770Sstevel@tonic-gate 
15780Sstevel@tonic-gate 	return (0);
15790Sstevel@tonic-gate }
15800Sstevel@tonic-gate 
15810Sstevel@tonic-gate static void
dr_dev_make_list(dr_handle_t * hp,sbd_comp_type_t type,int present_only,dr_common_unit_t *** devlist,int * devnum)15820Sstevel@tonic-gate dr_dev_make_list(dr_handle_t *hp, sbd_comp_type_t type, int present_only,
15830Sstevel@tonic-gate 	dr_common_unit_t ***devlist, int *devnum)
15840Sstevel@tonic-gate {
15850Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
15860Sstevel@tonic-gate 	int		 unum;
15870Sstevel@tonic-gate 	int		 nunits;
15880Sstevel@tonic-gate 	uint_t		 uset;
15890Sstevel@tonic-gate 	int		 len;
15900Sstevel@tonic-gate 	dr_common_unit_t **list, **wp;
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 	switch (type) {
15930Sstevel@tonic-gate 	case SBD_COMP_CPU:
15940Sstevel@tonic-gate 		nunits = MAX_CPU_UNITS_PER_BOARD;
15950Sstevel@tonic-gate 		break;
15960Sstevel@tonic-gate 	case SBD_COMP_MEM:
15970Sstevel@tonic-gate 		nunits = MAX_MEM_UNITS_PER_BOARD;
15980Sstevel@tonic-gate 		break;
15990Sstevel@tonic-gate 	case SBD_COMP_IO:
16000Sstevel@tonic-gate 		nunits = MAX_IO_UNITS_PER_BOARD;
16010Sstevel@tonic-gate 		break;
16020Sstevel@tonic-gate 	default:
16030Sstevel@tonic-gate 		/* catch this in debug kernels */
16040Sstevel@tonic-gate 		ASSERT(0);
16050Sstevel@tonic-gate 		break;
16060Sstevel@tonic-gate 	}
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	/* allocate list storage. */
16090Sstevel@tonic-gate 	len = sizeof (dr_common_unit_t *) * (nunits + 1);
16100Sstevel@tonic-gate 	list = kmem_zalloc(len, KM_SLEEP);
16110Sstevel@tonic-gate 
16120Sstevel@tonic-gate 	/* record length of storage in first element */
1613930Smathue 	*list++ = (dr_common_unit_t *)(uintptr_t)len;
16140Sstevel@tonic-gate 
16150Sstevel@tonic-gate 	/* get bit array signifying which units are to be involved */
16160Sstevel@tonic-gate 	uset = DEVSET_GET_UNITSET(hp->h_devset, type);
16170Sstevel@tonic-gate 
16180Sstevel@tonic-gate 	/*
16190Sstevel@tonic-gate 	 * Adjust the loop count for CPU devices since all cores
16200Sstevel@tonic-gate 	 * in a CMP will be examined in a single iteration.
16210Sstevel@tonic-gate 	 */
16220Sstevel@tonic-gate 	if (type == SBD_COMP_CPU) {
16230Sstevel@tonic-gate 		nunits = MAX_CMP_UNITS_PER_BOARD;
16240Sstevel@tonic-gate 	}
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 	/* populate list */
16270Sstevel@tonic-gate 	for (wp = list, unum = 0; unum < nunits; unum++) {
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 		dr_dev_unit_t	*dp;
16300Sstevel@tonic-gate 		int		core;
16310Sstevel@tonic-gate 		int		cunum;
16320Sstevel@tonic-gate 
16330Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, type, unum);
16340Sstevel@tonic-gate 		if (dr_dev_is_target(dp, present_only, uset)) {
16350Sstevel@tonic-gate 			*wp++ = &dp->du_common;
16360Sstevel@tonic-gate 		}
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 		/* further processing is only required for CPUs */
16390Sstevel@tonic-gate 		if (type != SBD_COMP_CPU) {
16400Sstevel@tonic-gate 			continue;
16410Sstevel@tonic-gate 		}
16420Sstevel@tonic-gate 
16430Sstevel@tonic-gate 		/*
16440Sstevel@tonic-gate 		 * Add any additional cores from the current CPU
16450Sstevel@tonic-gate 		 * device. This is to ensure that all the cores
16460Sstevel@tonic-gate 		 * are grouped together in the device list, and
16470Sstevel@tonic-gate 		 * consequently sequenced together during the actual
16480Sstevel@tonic-gate 		 * operation.
16490Sstevel@tonic-gate 		 */
16500Sstevel@tonic-gate 		for (core = 1; core < MAX_CORES_PER_CMP; core++) {
16510Sstevel@tonic-gate 
16520Sstevel@tonic-gate 			cunum = DR_CMP_CORE_UNUM(unum, core);
16530Sstevel@tonic-gate 			dp = DR_GET_BOARD_DEVUNIT(bp, type, cunum);
16540Sstevel@tonic-gate 
16550Sstevel@tonic-gate 			if (dr_dev_is_target(dp, present_only, uset)) {
16560Sstevel@tonic-gate 				*wp++ = &dp->du_common;
16570Sstevel@tonic-gate 			}
16580Sstevel@tonic-gate 		}
16590Sstevel@tonic-gate 	}
16600Sstevel@tonic-gate 
16610Sstevel@tonic-gate 	/* calculate number of units in list, return result and list pointer */
16620Sstevel@tonic-gate 	*devnum = wp - list;
16630Sstevel@tonic-gate 	*devlist = list;
16640Sstevel@tonic-gate }
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate static void
dr_dev_clean_up(dr_handle_t * hp,dr_common_unit_t ** list,int devnum)16670Sstevel@tonic-gate dr_dev_clean_up(dr_handle_t *hp, dr_common_unit_t **list, int devnum)
16680Sstevel@tonic-gate {
16690Sstevel@tonic-gate 	int len;
16700Sstevel@tonic-gate 	int n = 0;
16710Sstevel@tonic-gate 	dr_common_unit_t *cp, **rp = list;
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 	/*
16740Sstevel@tonic-gate 	 * move first encountered unit error to handle if handle
16750Sstevel@tonic-gate 	 * does not yet have a recorded error.
16760Sstevel@tonic-gate 	 */
16770Sstevel@tonic-gate 	if (hp->h_err == NULL) {
16780Sstevel@tonic-gate 		while (n++ < devnum) {
16790Sstevel@tonic-gate 			cp = *rp++;
16800Sstevel@tonic-gate 			if (cp->sbdev_error != NULL) {
16810Sstevel@tonic-gate 				hp->h_err = cp->sbdev_error;
16820Sstevel@tonic-gate 				cp->sbdev_error = NULL;
16830Sstevel@tonic-gate 				break;
16840Sstevel@tonic-gate 			}
16850Sstevel@tonic-gate 		}
16860Sstevel@tonic-gate 	}
16870Sstevel@tonic-gate 
16880Sstevel@tonic-gate 	/* free remaining unit errors */
16890Sstevel@tonic-gate 	while (n++ < devnum) {
16900Sstevel@tonic-gate 		cp = *rp++;
16910Sstevel@tonic-gate 		if (cp->sbdev_error != NULL) {
16920Sstevel@tonic-gate 			sbd_err_clear(&cp->sbdev_error);
16930Sstevel@tonic-gate 			cp->sbdev_error = NULL;
16940Sstevel@tonic-gate 		}
16950Sstevel@tonic-gate 	}
16960Sstevel@tonic-gate 
16970Sstevel@tonic-gate 	/* free list */
16980Sstevel@tonic-gate 	list -= 1;
1699930Smathue 	len = (int)(uintptr_t)list[0];
17000Sstevel@tonic-gate 	kmem_free(list, len);
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate static int
dr_dev_walk(dr_handle_t * hp,sbd_comp_type_t type,int present_only,int (* pre_op)(dr_handle_t *,dr_common_unit_t **,int),void (* op)(dr_handle_t *,dr_common_unit_t *),int (* post_op)(dr_handle_t *,dr_common_unit_t **,int),void (* board_op)(dr_handle_t *,dr_common_unit_t **,int))17040Sstevel@tonic-gate dr_dev_walk(dr_handle_t *hp, sbd_comp_type_t type, int present_only,
17050Sstevel@tonic-gate 		int (*pre_op)(dr_handle_t *, dr_common_unit_t **, int),
17060Sstevel@tonic-gate 		void (*op)(dr_handle_t *, dr_common_unit_t *),
17070Sstevel@tonic-gate 		int (*post_op)(dr_handle_t *, dr_common_unit_t **, int),
17080Sstevel@tonic-gate 		void (*board_op)(dr_handle_t *, dr_common_unit_t **, int))
17090Sstevel@tonic-gate {
17100Sstevel@tonic-gate 	int			  devnum, rv;
17110Sstevel@tonic-gate 	dr_common_unit_t	**devlist;
17120Sstevel@tonic-gate 
17130Sstevel@tonic-gate 	dr_dev_make_list(hp, type, present_only, &devlist, &devnum);
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 	rv = 0;
17160Sstevel@tonic-gate 	if (devnum > 0) {
17170Sstevel@tonic-gate 		rv = (*pre_op)(hp, devlist, devnum);
17180Sstevel@tonic-gate 		if (rv == 0) {
17190Sstevel@tonic-gate 			int n;
17200Sstevel@tonic-gate 
17210Sstevel@tonic-gate 			for (n = 0; n < devnum; n++)
17220Sstevel@tonic-gate 				(*op)(hp, devlist[n]);
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate 			rv = (*post_op)(hp, devlist, devnum);
17250Sstevel@tonic-gate 
17260Sstevel@tonic-gate 			(*board_op)(hp, devlist, devnum);
17270Sstevel@tonic-gate 		}
17280Sstevel@tonic-gate 	}
17290Sstevel@tonic-gate 
17300Sstevel@tonic-gate 	dr_dev_clean_up(hp, devlist, devnum);
17310Sstevel@tonic-gate 	return (rv);
17320Sstevel@tonic-gate }
17330Sstevel@tonic-gate 
17340Sstevel@tonic-gate /*ARGSUSED*/
17350Sstevel@tonic-gate static int
dr_dev_noop(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)17360Sstevel@tonic-gate dr_dev_noop(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum)
17370Sstevel@tonic-gate {
17380Sstevel@tonic-gate 	return (0);
17390Sstevel@tonic-gate }
17400Sstevel@tonic-gate 
17410Sstevel@tonic-gate static void
dr_attach_update_state(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)17420Sstevel@tonic-gate dr_attach_update_state(dr_handle_t *hp,
17430Sstevel@tonic-gate 	dr_common_unit_t **devlist, int devnum)
17440Sstevel@tonic-gate {
17450Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
17460Sstevel@tonic-gate 	int		i;
17470Sstevel@tonic-gate 	dr_devset_t	devs_unattached, devs_present;
17480Sstevel@tonic-gate 	static fn_t	f = "dr_post_attach_devlist";
17490Sstevel@tonic-gate 
17500Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
17510Sstevel@tonic-gate 		dr_common_unit_t *cp = devlist[i];
17520Sstevel@tonic-gate 
17530Sstevel@tonic-gate 		if (dr_check_unit_attached(cp) == -1) {
17540Sstevel@tonic-gate 			PR_ALL("%s: ERROR %s not attached\n",
17557656SSherry.Moore@Sun.COM 			    f, cp->sbdev_path);
17560Sstevel@tonic-gate 			continue;
17570Sstevel@tonic-gate 		}
17580Sstevel@tonic-gate 
17590Sstevel@tonic-gate 		DR_DEV_SET_ATTACHED(cp);
17600Sstevel@tonic-gate 
17610Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_CONFIGURED);
17620Sstevel@tonic-gate 		cp->sbdev_cond = SBD_COND_OK;
17630Sstevel@tonic-gate 	}
17640Sstevel@tonic-gate 
17650Sstevel@tonic-gate 	devs_present = DR_DEVS_PRESENT(bp);
17660Sstevel@tonic-gate 	devs_unattached = DR_DEVS_UNATTACHED(bp);
17670Sstevel@tonic-gate 
17680Sstevel@tonic-gate 	switch (bp->b_state) {
17690Sstevel@tonic-gate 	case DR_STATE_CONNECTED:
17700Sstevel@tonic-gate 	case DR_STATE_UNCONFIGURED:
17710Sstevel@tonic-gate 		ASSERT(devs_present);
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 		if (devs_unattached == 0) {
17740Sstevel@tonic-gate 			/*
17750Sstevel@tonic-gate 			 * All devices finally attached.
17760Sstevel@tonic-gate 			 */
17770Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONFIGURED);
17780Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
17790Sstevel@tonic-gate 			hp->h_bd->b_rstate = SBD_STAT_CONNECTED;
17800Sstevel@tonic-gate 			hp->h_bd->b_cond = SBD_COND_OK;
17810Sstevel@tonic-gate 			hp->h_bd->b_busy = 0;
17820Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
17830Sstevel@tonic-gate 		} else if (devs_present != devs_unattached) {
17840Sstevel@tonic-gate 			/*
17850Sstevel@tonic-gate 			 * Only some devices are fully attached.
17860Sstevel@tonic-gate 			 */
17870Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_PARTIAL);
17880Sstevel@tonic-gate 			hp->h_bd->b_rstate = SBD_STAT_CONNECTED;
17890Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
17900Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
17910Sstevel@tonic-gate 		}
17920Sstevel@tonic-gate 		break;
17930Sstevel@tonic-gate 
17940Sstevel@tonic-gate 	case DR_STATE_PARTIAL:
17950Sstevel@tonic-gate 		ASSERT(devs_present);
17960Sstevel@tonic-gate 		/*
17970Sstevel@tonic-gate 		 * All devices finally attached.
17980Sstevel@tonic-gate 		 */
17990Sstevel@tonic-gate 		if (devs_unattached == 0) {
18000Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONFIGURED);
18010Sstevel@tonic-gate 			hp->h_bd->b_rstate = SBD_STAT_CONNECTED;
18020Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
18030Sstevel@tonic-gate 			hp->h_bd->b_cond = SBD_COND_OK;
18040Sstevel@tonic-gate 			hp->h_bd->b_busy = 0;
18050Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
18060Sstevel@tonic-gate 		}
18070Sstevel@tonic-gate 		break;
18080Sstevel@tonic-gate 
18090Sstevel@tonic-gate 	default:
18100Sstevel@tonic-gate 		break;
18110Sstevel@tonic-gate 	}
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate static void
dr_dev_configure(dr_handle_t * hp)18150Sstevel@tonic-gate dr_dev_configure(dr_handle_t *hp)
18160Sstevel@tonic-gate {
18170Sstevel@tonic-gate 	int rv;
18180Sstevel@tonic-gate 
18190Sstevel@tonic-gate 	rv = dr_dev_walk(hp, SBD_COMP_CPU, 1,
18207656SSherry.Moore@Sun.COM 	    dr_pre_attach_cpu,
18217656SSherry.Moore@Sun.COM 	    dr_attach_cpu,
18227656SSherry.Moore@Sun.COM 	    dr_post_attach_cpu,
18237656SSherry.Moore@Sun.COM 	    dr_attach_update_state);
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	if (rv >= 0) {
18260Sstevel@tonic-gate 		rv = dr_dev_walk(hp, SBD_COMP_MEM, 1,
18277656SSherry.Moore@Sun.COM 		    dr_pre_attach_mem,
18287656SSherry.Moore@Sun.COM 		    dr_attach_mem,
18297656SSherry.Moore@Sun.COM 		    dr_post_attach_mem,
18307656SSherry.Moore@Sun.COM 		    dr_attach_update_state);
18310Sstevel@tonic-gate 	}
18320Sstevel@tonic-gate 
18330Sstevel@tonic-gate 	if (rv >= 0) {
18340Sstevel@tonic-gate 		(void) dr_dev_walk(hp, SBD_COMP_IO, 1,
18357656SSherry.Moore@Sun.COM 		    dr_pre_attach_io,
18367656SSherry.Moore@Sun.COM 		    dr_attach_io,
18377656SSherry.Moore@Sun.COM 		    dr_post_attach_io,
18387656SSherry.Moore@Sun.COM 		    dr_attach_update_state);
18390Sstevel@tonic-gate 	}
18400Sstevel@tonic-gate }
18410Sstevel@tonic-gate 
18420Sstevel@tonic-gate static void
dr_release_update_state(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)18430Sstevel@tonic-gate dr_release_update_state(dr_handle_t *hp,
18440Sstevel@tonic-gate 	dr_common_unit_t **devlist, int devnum)
18450Sstevel@tonic-gate {
18460Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devlist))
18470Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devnum))
18480Sstevel@tonic-gate 
18490Sstevel@tonic-gate 	dr_board_t *bp = hp->h_bd;
18500Sstevel@tonic-gate 
18510Sstevel@tonic-gate 	/*
18520Sstevel@tonic-gate 	 * If the entire board was released and all components
18530Sstevel@tonic-gate 	 * unreferenced then transfer it to the UNREFERENCED state.
18540Sstevel@tonic-gate 	 */
18550Sstevel@tonic-gate 	if ((bp->b_state != DR_STATE_RELEASE) &&
18567656SSherry.Moore@Sun.COM 	    (DR_DEVS_RELEASED(bp) == DR_DEVS_ATTACHED(bp))) {
18570Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_RELEASE);
18580Sstevel@tonic-gate 		hp->h_bd->b_busy = 1;
18590Sstevel@tonic-gate 	}
18600Sstevel@tonic-gate }
18610Sstevel@tonic-gate 
18620Sstevel@tonic-gate /* called by dr_release_done [below] and dr_release_mem_done [dr_mem.c] */
18630Sstevel@tonic-gate int
dr_release_dev_done(dr_common_unit_t * cp)18640Sstevel@tonic-gate dr_release_dev_done(dr_common_unit_t *cp)
18650Sstevel@tonic-gate {
18660Sstevel@tonic-gate 	if (cp->sbdev_state == DR_STATE_RELEASE) {
18670Sstevel@tonic-gate 		ASSERT(DR_DEV_IS_RELEASED(cp));
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 		DR_DEV_SET_UNREFERENCED(cp);
18700Sstevel@tonic-gate 
18710Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_UNREFERENCED);
18720Sstevel@tonic-gate 
18730Sstevel@tonic-gate 		return (0);
18740Sstevel@tonic-gate 	} else {
18750Sstevel@tonic-gate 		return (-1);
18760Sstevel@tonic-gate 	}
18770Sstevel@tonic-gate }
18780Sstevel@tonic-gate 
18790Sstevel@tonic-gate static void
dr_release_done(dr_handle_t * hp,dr_common_unit_t * cp)18800Sstevel@tonic-gate dr_release_done(dr_handle_t *hp, dr_common_unit_t *cp)
18810Sstevel@tonic-gate {
18820Sstevel@tonic-gate 	_NOTE(ARGUNUSED(hp))
18830Sstevel@tonic-gate 
18840Sstevel@tonic-gate 	dr_board_t		*bp;
18850Sstevel@tonic-gate 	static fn_t		f = "dr_release_done";
18860Sstevel@tonic-gate 
18870Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
18880Sstevel@tonic-gate 
18890Sstevel@tonic-gate 	/* get board pointer & sanity check */
18900Sstevel@tonic-gate 	bp = cp->sbdev_bp;
18910Sstevel@tonic-gate 	ASSERT(bp == hp->h_bd);
18920Sstevel@tonic-gate 
18930Sstevel@tonic-gate 	/*
18940Sstevel@tonic-gate 	 * Transfer the device which just completed its release
18950Sstevel@tonic-gate 	 * to the UNREFERENCED state.
18960Sstevel@tonic-gate 	 */
18970Sstevel@tonic-gate 	switch (cp->sbdev_type) {
18980Sstevel@tonic-gate 	case SBD_COMP_MEM:
18990Sstevel@tonic-gate 		dr_release_mem_done(cp);
19000Sstevel@tonic-gate 		break;
19010Sstevel@tonic-gate 
19020Sstevel@tonic-gate 	default:
19030Sstevel@tonic-gate 		DR_DEV_SET_RELEASED(cp);
19040Sstevel@tonic-gate 
19050Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_RELEASE);
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 		(void) dr_release_dev_done(cp);
19080Sstevel@tonic-gate 		break;
19090Sstevel@tonic-gate 	}
19100Sstevel@tonic-gate 
19110Sstevel@tonic-gate 	/*
19120Sstevel@tonic-gate 	 * If we're not already in the RELEASE state for this
19130Sstevel@tonic-gate 	 * board and we now have released all that were previously
19140Sstevel@tonic-gate 	 * attached, then transfer the board to the RELEASE state.
19150Sstevel@tonic-gate 	 */
19160Sstevel@tonic-gate 	if ((bp->b_state == DR_STATE_RELEASE) &&
19177656SSherry.Moore@Sun.COM 	    (DR_DEVS_RELEASED(bp) == DR_DEVS_UNREFERENCED(bp))) {
19180Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_UNREFERENCED);
19190Sstevel@tonic-gate 		bp->b_busy = 1;
19200Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&bp->b_time);
19210Sstevel@tonic-gate 	}
19220Sstevel@tonic-gate }
19230Sstevel@tonic-gate 
19240Sstevel@tonic-gate static void
dr_dev_release_mem(dr_handle_t * hp,dr_common_unit_t * dv)19250Sstevel@tonic-gate dr_dev_release_mem(dr_handle_t *hp, dr_common_unit_t *dv)
19260Sstevel@tonic-gate {
19270Sstevel@tonic-gate 	dr_release_mem(dv);
19280Sstevel@tonic-gate 	dr_release_done(hp, dv);
19290Sstevel@tonic-gate }
19300Sstevel@tonic-gate 
19310Sstevel@tonic-gate static void
dr_dev_release(dr_handle_t * hp)19320Sstevel@tonic-gate dr_dev_release(dr_handle_t *hp)
19330Sstevel@tonic-gate {
19340Sstevel@tonic-gate 	int rv;
19350Sstevel@tonic-gate 
19360Sstevel@tonic-gate 	hp->h_bd->b_busy = 1;
19370Sstevel@tonic-gate 
19380Sstevel@tonic-gate 	rv = dr_dev_walk(hp, SBD_COMP_CPU, 0,
19397656SSherry.Moore@Sun.COM 	    dr_pre_release_cpu,
19407656SSherry.Moore@Sun.COM 	    dr_release_done,
19417656SSherry.Moore@Sun.COM 	    dr_dev_noop,
19427656SSherry.Moore@Sun.COM 	    dr_release_update_state);
19430Sstevel@tonic-gate 
19440Sstevel@tonic-gate 	if (rv >= 0) {
19450Sstevel@tonic-gate 		rv = dr_dev_walk(hp, SBD_COMP_MEM, 0,
19467656SSherry.Moore@Sun.COM 		    dr_pre_release_mem,
19477656SSherry.Moore@Sun.COM 		    dr_dev_release_mem,
19487656SSherry.Moore@Sun.COM 		    dr_dev_noop,
19497656SSherry.Moore@Sun.COM 		    dr_release_update_state);
19500Sstevel@tonic-gate 	}
19510Sstevel@tonic-gate 
19520Sstevel@tonic-gate 	if (rv >= 0) {
19530Sstevel@tonic-gate 		rv = dr_dev_walk(hp, SBD_COMP_IO, 0,
19547656SSherry.Moore@Sun.COM 		    dr_pre_release_io,
19557656SSherry.Moore@Sun.COM 		    dr_release_done,
19567656SSherry.Moore@Sun.COM 		    dr_dev_noop,
19577656SSherry.Moore@Sun.COM 		    dr_release_update_state);
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	}
19600Sstevel@tonic-gate 
19610Sstevel@tonic-gate 	if (rv < 0)
19620Sstevel@tonic-gate 		hp->h_bd->b_busy = 0;
19630Sstevel@tonic-gate 	/* else, b_busy will be cleared in dr_detach_update_state() */
19640Sstevel@tonic-gate }
19650Sstevel@tonic-gate 
19660Sstevel@tonic-gate static void
dr_detach_update_state(dr_handle_t * hp,dr_common_unit_t ** devlist,int devnum)19670Sstevel@tonic-gate dr_detach_update_state(dr_handle_t *hp,
19680Sstevel@tonic-gate 	dr_common_unit_t **devlist, int devnum)
19690Sstevel@tonic-gate {
19700Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
19710Sstevel@tonic-gate 	int		i;
19720Sstevel@tonic-gate 	dr_state_t	bstate;
19730Sstevel@tonic-gate 	static fn_t	f = "dr_detach_update_state";
19740Sstevel@tonic-gate 
19750Sstevel@tonic-gate 	for (i = 0; i < devnum; i++) {
19760Sstevel@tonic-gate 		dr_common_unit_t *cp = devlist[i];
19770Sstevel@tonic-gate 
19780Sstevel@tonic-gate 		if (dr_check_unit_attached(cp) >= 0) {
19790Sstevel@tonic-gate 			/*
19800Sstevel@tonic-gate 			 * Device is still attached probably due
19810Sstevel@tonic-gate 			 * to an error.  Need to keep track of it.
19820Sstevel@tonic-gate 			 */
19830Sstevel@tonic-gate 			PR_ALL("%s: ERROR %s not detached\n",
19847656SSherry.Moore@Sun.COM 			    f, cp->sbdev_path);
19850Sstevel@tonic-gate 
19860Sstevel@tonic-gate 			continue;
19870Sstevel@tonic-gate 		}
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 		DR_DEV_CLR_ATTACHED(cp);
19900Sstevel@tonic-gate 		DR_DEV_CLR_RELEASED(cp);
19910Sstevel@tonic-gate 		DR_DEV_CLR_UNREFERENCED(cp);
19920Sstevel@tonic-gate 		dr_device_transition(cp, DR_STATE_UNCONFIGURED);
19930Sstevel@tonic-gate 	}
19940Sstevel@tonic-gate 
19950Sstevel@tonic-gate 	bstate = bp->b_state;
19960Sstevel@tonic-gate 	if (bstate != DR_STATE_UNCONFIGURED) {
19970Sstevel@tonic-gate 		if (DR_DEVS_PRESENT(bp) == DR_DEVS_UNATTACHED(bp)) {
19980Sstevel@tonic-gate 			/*
19990Sstevel@tonic-gate 			 * All devices are finally detached.
20000Sstevel@tonic-gate 			 */
20010Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_UNCONFIGURED);
20020Sstevel@tonic-gate 			hp->h_bd->b_ostate = SBD_STAT_UNCONFIGURED;
20030Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
20040Sstevel@tonic-gate 		} else if ((bp->b_state != DR_STATE_PARTIAL) &&
20057656SSherry.Moore@Sun.COM 		    (DR_DEVS_ATTACHED(bp) !=
20067656SSherry.Moore@Sun.COM 		    DR_DEVS_PRESENT(bp))) {
20070Sstevel@tonic-gate 			/*
20080Sstevel@tonic-gate 			 * Some devices remain attached.
20090Sstevel@tonic-gate 			 */
20100Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_PARTIAL);
20110Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
20120Sstevel@tonic-gate 		}
20130Sstevel@tonic-gate 
20140Sstevel@tonic-gate 		if ((hp->h_devset & DR_DEVS_UNATTACHED(bp)) == hp->h_devset)
20150Sstevel@tonic-gate 			hp->h_bd->b_busy = 0;
20160Sstevel@tonic-gate 	}
20170Sstevel@tonic-gate }
20180Sstevel@tonic-gate 
20190Sstevel@tonic-gate static int
dr_dev_unconfigure(dr_handle_t * hp)20200Sstevel@tonic-gate dr_dev_unconfigure(dr_handle_t *hp)
20210Sstevel@tonic-gate {
20220Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate 	/*
20250Sstevel@tonic-gate 	 * Block out status during IO unconfig.
20260Sstevel@tonic-gate 	 */
20270Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
20280Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK) {
20290Sstevel@tonic-gate 		if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) {
20300Sstevel@tonic-gate 			mutex_exit(&bp->b_slock);
20310Sstevel@tonic-gate 			return (EINTR);
20320Sstevel@tonic-gate 		}
20330Sstevel@tonic-gate 	}
20340Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
20350Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 	(void) dr_dev_walk(hp, SBD_COMP_IO, 0,
20387656SSherry.Moore@Sun.COM 	    dr_pre_detach_io,
20397656SSherry.Moore@Sun.COM 	    dr_detach_io,
20407656SSherry.Moore@Sun.COM 	    dr_post_detach_io,
20417656SSherry.Moore@Sun.COM 	    dr_detach_update_state);
20420Sstevel@tonic-gate 
20430Sstevel@tonic-gate 	dr_unlock_status(bp);
20440Sstevel@tonic-gate 
20450Sstevel@tonic-gate 	(void) dr_dev_walk(hp, SBD_COMP_CPU, 0,
20467656SSherry.Moore@Sun.COM 	    dr_pre_detach_cpu,
20477656SSherry.Moore@Sun.COM 	    dr_detach_cpu,
20487656SSherry.Moore@Sun.COM 	    dr_post_detach_cpu,
20497656SSherry.Moore@Sun.COM 	    dr_detach_update_state);
20500Sstevel@tonic-gate 
20510Sstevel@tonic-gate 	(void) dr_dev_walk(hp, SBD_COMP_MEM, 0,
20527656SSherry.Moore@Sun.COM 	    dr_pre_detach_mem,
20537656SSherry.Moore@Sun.COM 	    dr_detach_mem,
20547656SSherry.Moore@Sun.COM 	    dr_post_detach_mem,
20557656SSherry.Moore@Sun.COM 	    dr_detach_update_state);
20560Sstevel@tonic-gate 
20570Sstevel@tonic-gate 	return (0);
20580Sstevel@tonic-gate }
20590Sstevel@tonic-gate 
20600Sstevel@tonic-gate static void
dr_dev_cancel(dr_handle_t * hp)20610Sstevel@tonic-gate dr_dev_cancel(dr_handle_t *hp)
20620Sstevel@tonic-gate {
20630Sstevel@tonic-gate 	int		i;
20640Sstevel@tonic-gate 	dr_devset_t	devset;
20650Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
20660Sstevel@tonic-gate 	static fn_t	f = "dr_dev_cancel";
20670Sstevel@tonic-gate 
20680Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	/*
20710Sstevel@tonic-gate 	 * Only devices which have been "released" are
20720Sstevel@tonic-gate 	 * subject to cancellation.
20730Sstevel@tonic-gate 	 */
20740Sstevel@tonic-gate 	devset = hp->h_devset & DR_DEVS_RELEASED(bp);
20750Sstevel@tonic-gate 
20760Sstevel@tonic-gate 	/*
20770Sstevel@tonic-gate 	 * Nothing to do for CPUs or IO other than change back
20780Sstevel@tonic-gate 	 * their state.
20790Sstevel@tonic-gate 	 */
20800Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
20810Sstevel@tonic-gate 		dr_cpu_unit_t	*cp;
20820Sstevel@tonic-gate 		dr_state_t	nstate;
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i))
20850Sstevel@tonic-gate 			continue;
20860Sstevel@tonic-gate 
20870Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
20880Sstevel@tonic-gate 		if (dr_cancel_cpu(cp) == 0)
20890Sstevel@tonic-gate 			nstate = DR_STATE_CONFIGURED;
20900Sstevel@tonic-gate 		else
20910Sstevel@tonic-gate 			nstate = DR_STATE_FATAL;
20920Sstevel@tonic-gate 
20930Sstevel@tonic-gate 		dr_device_transition(&cp->sbc_cm, nstate);
20940Sstevel@tonic-gate 	}
20950Sstevel@tonic-gate 
20960Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
20970Sstevel@tonic-gate 		dr_io_unit_t *ip;
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i))
21000Sstevel@tonic-gate 			continue;
21010Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
21020Sstevel@tonic-gate 		dr_device_transition(&ip->sbi_cm, DR_STATE_CONFIGURED);
21030Sstevel@tonic-gate 	}
21040Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
21050Sstevel@tonic-gate 		dr_mem_unit_t	*mp;
21060Sstevel@tonic-gate 		dr_state_t	nstate;
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 		if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i))
21090Sstevel@tonic-gate 			continue;
21100Sstevel@tonic-gate 
21110Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
21120Sstevel@tonic-gate 		if (dr_cancel_mem(mp) == 0)
21130Sstevel@tonic-gate 			nstate = DR_STATE_CONFIGURED;
21140Sstevel@tonic-gate 		else
21150Sstevel@tonic-gate 			nstate = DR_STATE_FATAL;
21160Sstevel@tonic-gate 
21170Sstevel@tonic-gate 		dr_device_transition(&mp->sbm_cm, nstate);
21180Sstevel@tonic-gate 	}
21190Sstevel@tonic-gate 
21200Sstevel@tonic-gate 	PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset);
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	DR_DEVS_CANCEL(bp, devset);
21230Sstevel@tonic-gate 
21240Sstevel@tonic-gate 	if (DR_DEVS_RELEASED(bp) == 0) {
21250Sstevel@tonic-gate 		dr_state_t	new_state;
21260Sstevel@tonic-gate 		/*
21270Sstevel@tonic-gate 		 * If the board no longer has any released devices
21280Sstevel@tonic-gate 		 * than transfer it back to the CONFIG/PARTIAL state.
21290Sstevel@tonic-gate 		 */
21300Sstevel@tonic-gate 		if (DR_DEVS_ATTACHED(bp) == DR_DEVS_PRESENT(bp))
21310Sstevel@tonic-gate 			new_state = DR_STATE_CONFIGURED;
21320Sstevel@tonic-gate 		else
21330Sstevel@tonic-gate 			new_state = DR_STATE_PARTIAL;
21340Sstevel@tonic-gate 		if (bp->b_state != new_state) {
21350Sstevel@tonic-gate 			dr_board_transition(bp, new_state);
21360Sstevel@tonic-gate 		}
21370Sstevel@tonic-gate 		hp->h_bd->b_ostate = SBD_STAT_CONFIGURED;
21380Sstevel@tonic-gate 		hp->h_bd->b_busy = 0;
21390Sstevel@tonic-gate 		(void) drv_getparm(TIME, (void *)&hp->h_bd->b_time);
21400Sstevel@tonic-gate 	}
21410Sstevel@tonic-gate }
21420Sstevel@tonic-gate 
21430Sstevel@tonic-gate static int
dr_dev_status(dr_handle_t * hp)21440Sstevel@tonic-gate dr_dev_status(dr_handle_t *hp)
21450Sstevel@tonic-gate {
21460Sstevel@tonic-gate 	int		nstat, mode, ncm, sz, pbsz, pnstat;
21470Sstevel@tonic-gate 	dr_handle_t	*shp;
21480Sstevel@tonic-gate 	dr_devset_t	devset = 0;
21490Sstevel@tonic-gate 	sbd_stat_t	*dstatp = NULL;
21500Sstevel@tonic-gate 	sbd_dev_stat_t	*devstatp;
21510Sstevel@tonic-gate 	dr_board_t	*bp;
21520Sstevel@tonic-gate 	drmach_status_t	 pstat;
21530Sstevel@tonic-gate 	int		rv = 0;
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
21560Sstevel@tonic-gate 	int sz32 = 0;
21570Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
21580Sstevel@tonic-gate 
21590Sstevel@tonic-gate 	static fn_t	f = "dr_status";
21600Sstevel@tonic-gate 
21610Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
21620Sstevel@tonic-gate 
21630Sstevel@tonic-gate 	mode = hp->h_mode;
21640Sstevel@tonic-gate 	shp = hp;
21650Sstevel@tonic-gate 	devset = shp->h_devset;
21660Sstevel@tonic-gate 	bp = hp->h_bd;
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	/*
21690Sstevel@tonic-gate 	 * Block out disconnect, unassign, IO unconfigure and
21700Sstevel@tonic-gate 	 * devinfo branch creation during status.
21710Sstevel@tonic-gate 	 */
21720Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
21730Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK) {
21740Sstevel@tonic-gate 		if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) {
21750Sstevel@tonic-gate 			mutex_exit(&bp->b_slock);
21760Sstevel@tonic-gate 			return (EINTR);
21770Sstevel@tonic-gate 		}
21780Sstevel@tonic-gate 	}
21790Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
21800Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate 	ncm = 1;
21830Sstevel@tonic-gate 	if (hp->h_sbdcmd.cmd_cm.c_id.c_type == SBD_COMP_NONE) {
21840Sstevel@tonic-gate 		if (dr_cmd_flags(hp) & SBD_FLAG_ALLCMP) {
21850Sstevel@tonic-gate 		/*
21860Sstevel@tonic-gate 		 * Calculate the maximum number of components possible
21870Sstevel@tonic-gate 		 * for a board.  This number will be used to size the
21880Sstevel@tonic-gate 		 * status scratch buffer used by board and component
21890Sstevel@tonic-gate 		 * status functions.
21900Sstevel@tonic-gate 		 * This buffer may differ in size from what is provided
21910Sstevel@tonic-gate 		 * by the plugin, since the known component set on the
21920Sstevel@tonic-gate 		 * board may change between the plugin's GETNCM call, and
21930Sstevel@tonic-gate 		 * the status call.  Sizing will be adjusted to the plugin's
21940Sstevel@tonic-gate 		 * receptacle buffer at copyout time.
21950Sstevel@tonic-gate 		 */
21960Sstevel@tonic-gate 			ncm = MAX_CPU_UNITS_PER_BOARD +
21977656SSherry.Moore@Sun.COM 			    MAX_MEM_UNITS_PER_BOARD +
21987656SSherry.Moore@Sun.COM 			    MAX_IO_UNITS_PER_BOARD;
21990Sstevel@tonic-gate 
22000Sstevel@tonic-gate 		} else {
22010Sstevel@tonic-gate 			/*
22020Sstevel@tonic-gate 			 * In the case of c_type == SBD_COMP_NONE, and
22030Sstevel@tonic-gate 			 * SBD_FLAG_ALLCMP not specified, only the board
22040Sstevel@tonic-gate 			 * info is to be returned, no components.
22050Sstevel@tonic-gate 			 */
22060Sstevel@tonic-gate 			ncm = 0;
22070Sstevel@tonic-gate 			devset = 0;
22080Sstevel@tonic-gate 		}
22090Sstevel@tonic-gate 	}
22100Sstevel@tonic-gate 
22110Sstevel@tonic-gate 	sz = sizeof (sbd_stat_t);
22120Sstevel@tonic-gate 	if (ncm > 1)
22130Sstevel@tonic-gate 		sz += sizeof (sbd_dev_stat_t) * (ncm - 1);
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 
22160Sstevel@tonic-gate 	pbsz = (int)hp->h_sbdcmd.cmd_stat.s_nbytes;
22170Sstevel@tonic-gate 	pnstat = (pbsz - sizeof (sbd_stat_t))/sizeof (sbd_dev_stat_t);
22180Sstevel@tonic-gate 
22190Sstevel@tonic-gate 	/*
22200Sstevel@tonic-gate 	 * s_nbytes describes the size of the preallocated user
22210Sstevel@tonic-gate 	 * buffer into which the application is execting to
22220Sstevel@tonic-gate 	 * receive the sbd_stat_t and sbd_dev_stat_t structures.
22230Sstevel@tonic-gate 	 */
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	/*
22280Sstevel@tonic-gate 	 * More buffer space is required for the 64bit to 32bit
22290Sstevel@tonic-gate 	 * conversion of data structures.
22300Sstevel@tonic-gate 	 */
22310Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
22320Sstevel@tonic-gate 		sz32 = sizeof (sbd_stat32_t);
22330Sstevel@tonic-gate 		if (ncm > 1)
22340Sstevel@tonic-gate 			sz32  += sizeof (sbd_dev_stat32_t) * (ncm - 1);
22350Sstevel@tonic-gate 		pnstat = (pbsz - sizeof (sbd_stat32_t))/
22367656SSherry.Moore@Sun.COM 		    sizeof (sbd_dev_stat32_t);
22370Sstevel@tonic-gate 	}
22380Sstevel@tonic-gate 
22390Sstevel@tonic-gate 	sz += sz32;
22400Sstevel@tonic-gate #endif
22410Sstevel@tonic-gate 	/*
22420Sstevel@tonic-gate 	 * Since one sbd_dev_stat_t is included in the sbd_stat_t,
22430Sstevel@tonic-gate 	 * increment the plugin's nstat count.
22440Sstevel@tonic-gate 	 */
22450Sstevel@tonic-gate 	++pnstat;
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 	if (bp->b_id == 0) {
22480Sstevel@tonic-gate 		bzero(&pstat, sizeof (pstat));
22490Sstevel@tonic-gate 	} else {
22500Sstevel@tonic-gate 		sbd_error_t *err;
22510Sstevel@tonic-gate 
22520Sstevel@tonic-gate 		err = drmach_status(bp->b_id, &pstat);
22530Sstevel@tonic-gate 		if (err) {
22540Sstevel@tonic-gate 			DRERR_SET_C(&hp->h_err, &err);
22550Sstevel@tonic-gate 			rv = EIO;
22560Sstevel@tonic-gate 			goto status_done;
22570Sstevel@tonic-gate 		}
22580Sstevel@tonic-gate 	}
22590Sstevel@tonic-gate 
22600Sstevel@tonic-gate 	dstatp = (sbd_stat_t *)GETSTRUCT(char, sz);
22610Sstevel@tonic-gate 
22620Sstevel@tonic-gate 	devstatp = &dstatp->s_stat[0];
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	dstatp->s_board = bp->b_num;
22650Sstevel@tonic-gate 
22660Sstevel@tonic-gate 	/*
22670Sstevel@tonic-gate 	 * Detect transitions between empty and disconnected.
22680Sstevel@tonic-gate 	 */
22690Sstevel@tonic-gate 	if (!pstat.empty && (bp->b_rstate == SBD_STAT_EMPTY))
22700Sstevel@tonic-gate 		bp->b_rstate = SBD_STAT_DISCONNECTED;
22710Sstevel@tonic-gate 	else if (pstat.empty && (bp->b_rstate == SBD_STAT_DISCONNECTED))
22720Sstevel@tonic-gate 		bp->b_rstate = SBD_STAT_EMPTY;
22730Sstevel@tonic-gate 
22740Sstevel@tonic-gate 	dstatp->s_rstate = bp->b_rstate;
22750Sstevel@tonic-gate 	dstatp->s_ostate = bp->b_ostate;
22760Sstevel@tonic-gate 	dstatp->s_cond = bp->b_cond = pstat.cond;
22770Sstevel@tonic-gate 	dstatp->s_busy = bp->b_busy | pstat.busy;
22780Sstevel@tonic-gate 	dstatp->s_time = bp->b_time;
22790Sstevel@tonic-gate 	dstatp->s_power = pstat.powered;
22800Sstevel@tonic-gate 	dstatp->s_assigned = bp->b_assigned = pstat.assigned;
22810Sstevel@tonic-gate 	dstatp->s_nstat = nstat = 0;
22820Sstevel@tonic-gate 	bcopy(&pstat.type[0], &dstatp->s_type[0], SBD_TYPE_LEN);
22830Sstevel@tonic-gate 	bcopy(&pstat.info[0], &dstatp->s_info[0], SBD_MAX_INFO);
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 	devset &= DR_DEVS_PRESENT(bp);
22860Sstevel@tonic-gate 	if (devset == 0) {
22870Sstevel@tonic-gate 		/*
22880Sstevel@tonic-gate 		 * No device chosen.
22890Sstevel@tonic-gate 		 */
22900Sstevel@tonic-gate 		PR_ALL("%s: no device present\n", f);
22910Sstevel@tonic-gate 	}
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT))
22940Sstevel@tonic-gate 		if ((nstat = dr_cpu_status(hp, devset, devstatp)) > 0) {
22950Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
22960Sstevel@tonic-gate 			devstatp += nstat;
22970Sstevel@tonic-gate 		}
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT))
23000Sstevel@tonic-gate 		if ((nstat = dr_mem_status(hp, devset, devstatp)) > 0) {
23010Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
23020Sstevel@tonic-gate 			devstatp += nstat;
23030Sstevel@tonic-gate 		}
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT))
23060Sstevel@tonic-gate 		if ((nstat = dr_io_status(hp, devset, devstatp)) > 0) {
23070Sstevel@tonic-gate 			dstatp->s_nstat += nstat;
23080Sstevel@tonic-gate 			devstatp += nstat;
23090Sstevel@tonic-gate 		}
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	/*
23120Sstevel@tonic-gate 	 * Due to a possible change in number of components between
23130Sstevel@tonic-gate 	 * the time of plugin's GETNCM call and now, there may be
23140Sstevel@tonic-gate 	 * more or less components than the plugin's buffer can
23150Sstevel@tonic-gate 	 * hold.  Adjust s_nstat accordingly.
23160Sstevel@tonic-gate 	 */
23170Sstevel@tonic-gate 
23180Sstevel@tonic-gate 	dstatp->s_nstat = dstatp->s_nstat > pnstat ? pnstat : dstatp->s_nstat;
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL
23220Sstevel@tonic-gate 	if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) {
23230Sstevel@tonic-gate 		int		i, j;
23240Sstevel@tonic-gate 		sbd_stat32_t	*dstat32p;
23250Sstevel@tonic-gate 
23260Sstevel@tonic-gate 		dstat32p = (sbd_stat32_t *)devstatp;
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate 		/* Alignment Paranoia */
23290Sstevel@tonic-gate 		if ((ulong_t)dstat32p & 0x1) {
2330930Smathue 			PR_ALL("%s: alignment: sz=0x%lx dstat32p=0x%p\n",
233111311SSurya.Prakki@Sun.COM 			    f, sizeof (sbd_stat32_t), (void *)dstat32p);
23320Sstevel@tonic-gate 			DR_OP_INTERNAL_ERROR(hp);
23330Sstevel@tonic-gate 			rv = EINVAL;
23340Sstevel@tonic-gate 			goto status_done;
23350Sstevel@tonic-gate 		}
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 		/* paranoia: detect buffer overrun */
23380Sstevel@tonic-gate 		if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] >
23397656SSherry.Moore@Sun.COM 		    ((caddr_t)dstatp) + sz) {
23400Sstevel@tonic-gate 			DR_OP_INTERNAL_ERROR(hp);
23410Sstevel@tonic-gate 			rv = EINVAL;
23420Sstevel@tonic-gate 			goto status_done;
23430Sstevel@tonic-gate 		}
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 		/* copy sbd_stat_t structure members */
23460Sstevel@tonic-gate #define	_SBD_STAT(t, m) dstat32p->m = (t)dstatp->m
23470Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_board);
23480Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_rstate);
23490Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_ostate);
23500Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_cond);
23510Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_busy);
23520Sstevel@tonic-gate 		_SBD_STAT(time32_t, s_time);
23530Sstevel@tonic-gate 		_SBD_STAT(uint32_t, s_power);
23540Sstevel@tonic-gate 		_SBD_STAT(uint32_t, s_assigned);
23550Sstevel@tonic-gate 		_SBD_STAT(int32_t, s_nstat);
23560Sstevel@tonic-gate 		bcopy(&dstatp->s_type[0], &dstat32p->s_type[0],
23577656SSherry.Moore@Sun.COM 		    SBD_TYPE_LEN);
23580Sstevel@tonic-gate 		bcopy(&dstatp->s_info[0], &dstat32p->s_info[0],
23597656SSherry.Moore@Sun.COM 		    SBD_MAX_INFO);
23600Sstevel@tonic-gate #undef _SBD_STAT
23610Sstevel@tonic-gate 
23620Sstevel@tonic-gate 		for (i = 0; i < dstatp->s_nstat; i++) {
23630Sstevel@tonic-gate 			sbd_dev_stat_t		*dsp = &dstatp->s_stat[i];
23640Sstevel@tonic-gate 			sbd_dev_stat32_t	*ds32p = &dstat32p->s_stat[i];
23650Sstevel@tonic-gate #define	_SBD_DEV_STAT(t, m) ds32p->m = (t)dsp->m
23660Sstevel@tonic-gate 
23670Sstevel@tonic-gate 			/* copy sbd_cm_stat_t structure members */
23680Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_type);
23690Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_unit);
23700Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_ostate);
23710Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_cond);
23720Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_busy);
23730Sstevel@tonic-gate 			_SBD_DEV_STAT(int32_t, ds_suspend);
23740Sstevel@tonic-gate 			_SBD_DEV_STAT(time32_t, ds_time);
23750Sstevel@tonic-gate 			bcopy(&dsp->ds_name[0], &ds32p->ds_name[0],
23760Sstevel@tonic-gate 			    OBP_MAXPROPNAME);
23770Sstevel@tonic-gate 
23780Sstevel@tonic-gate 			switch (dsp->ds_type) {
23790Sstevel@tonic-gate 			case SBD_COMP_CPU:
23800Sstevel@tonic-gate 				/* copy sbd_cpu_stat_t structure members */
23810Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_isbootproc);
23820Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_cpuid);
23830Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_speed);
23840Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cpu.cs_ecache);
23850Sstevel@tonic-gate 				break;
23860Sstevel@tonic-gate 
23870Sstevel@tonic-gate 			case SBD_COMP_MEM:
23880Sstevel@tonic-gate 				/* copy sbd_mem_stat_t structure members */
23890Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_interleave);
23900Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_basepfn);
23910Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_totpages);
23920Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_detpages);
23930Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_pageslost);
23940Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_managed_pages);
23950Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_pages);
23960Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_first);
23970Sstevel@tonic-gate 				_SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_last);
23980Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_cage_enabled);
23990Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_mem.ms_peer_is_target);
24000Sstevel@tonic-gate 				bcopy(&dsp->d_mem.ms_peer_ap_id[0],
24017656SSherry.Moore@Sun.COM 				    &ds32p->d_mem.ms_peer_ap_id[0],
24027656SSherry.Moore@Sun.COM 				    sizeof (ds32p->d_mem.ms_peer_ap_id));
24030Sstevel@tonic-gate 				break;
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 			case SBD_COMP_IO:
24060Sstevel@tonic-gate 				/* copy sbd_io_stat_t structure members */
24070Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_io.is_referenced);
24080Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_io.is_unsafe_count);
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 				for (j = 0; j < SBD_MAX_UNSAFE; j++)
24110Sstevel@tonic-gate 					_SBD_DEV_STAT(int32_t,
24127656SSherry.Moore@Sun.COM 					    d_io.is_unsafe_list[j]);
24130Sstevel@tonic-gate 
24140Sstevel@tonic-gate 				bcopy(&dsp->d_io.is_pathname[0],
24150Sstevel@tonic-gate 				    &ds32p->d_io.is_pathname[0], MAXPATHLEN);
24160Sstevel@tonic-gate 				break;
24170Sstevel@tonic-gate 
24180Sstevel@tonic-gate 			case SBD_COMP_CMP:
24190Sstevel@tonic-gate 				/* copy sbd_cmp_stat_t structure members */
24200Sstevel@tonic-gate 				bcopy(&dsp->d_cmp.ps_cpuid[0],
24217656SSherry.Moore@Sun.COM 				    &ds32p->d_cmp.ps_cpuid[0],
24227656SSherry.Moore@Sun.COM 				    sizeof (ds32p->d_cmp.ps_cpuid));
24230Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cmp.ps_ncores);
24240Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cmp.ps_speed);
24250Sstevel@tonic-gate 				_SBD_DEV_STAT(int32_t, d_cmp.ps_ecache);
24260Sstevel@tonic-gate 				break;
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 			default:
24290Sstevel@tonic-gate 				cmn_err(CE_WARN, "%s: unknown dev type (%d)",
24300Sstevel@tonic-gate 				    f, (int)dsp->ds_type);
24310Sstevel@tonic-gate 				rv = EFAULT;
24320Sstevel@tonic-gate 				goto status_done;
24330Sstevel@tonic-gate 			}
24340Sstevel@tonic-gate #undef _SBD_DEV_STAT
24350Sstevel@tonic-gate 		}
24360Sstevel@tonic-gate 
24370Sstevel@tonic-gate 
24380Sstevel@tonic-gate 		if (ddi_copyout((void *)dstat32p,
24397656SSherry.Moore@Sun.COM 		    hp->h_sbdcmd.cmd_stat.s_statp, pbsz, mode) != 0) {
24400Sstevel@tonic-gate 			cmn_err(CE_WARN,
24417656SSherry.Moore@Sun.COM 			    "%s: failed to copyout status "
24427656SSherry.Moore@Sun.COM 			    "for board %d", f, bp->b_num);
24430Sstevel@tonic-gate 			rv = EFAULT;
24440Sstevel@tonic-gate 			goto status_done;
24450Sstevel@tonic-gate 		}
24460Sstevel@tonic-gate 	} else
24470Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */
24480Sstevel@tonic-gate 
24490Sstevel@tonic-gate 	if (ddi_copyout((void *)dstatp, hp->h_sbdcmd.cmd_stat.s_statp,
24507656SSherry.Moore@Sun.COM 	    pbsz, mode) != 0) {
24510Sstevel@tonic-gate 		cmn_err(CE_WARN,
24527656SSherry.Moore@Sun.COM 		    "%s: failed to copyout status for board %d",
24537656SSherry.Moore@Sun.COM 		    f, bp->b_num);
24540Sstevel@tonic-gate 		rv = EFAULT;
24550Sstevel@tonic-gate 		goto status_done;
24560Sstevel@tonic-gate 	}
24570Sstevel@tonic-gate 
24580Sstevel@tonic-gate status_done:
24590Sstevel@tonic-gate 	if (dstatp != NULL)
24600Sstevel@tonic-gate 		FREESTRUCT(dstatp, char, sz);
24610Sstevel@tonic-gate 
24620Sstevel@tonic-gate 	dr_unlock_status(bp);
24630Sstevel@tonic-gate 
24640Sstevel@tonic-gate 	return (rv);
24650Sstevel@tonic-gate }
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate static int
dr_get_ncm(dr_handle_t * hp)24680Sstevel@tonic-gate dr_get_ncm(dr_handle_t *hp)
24690Sstevel@tonic-gate {
24700Sstevel@tonic-gate 	int		i;
24710Sstevel@tonic-gate 	int		ncm = 0;
24720Sstevel@tonic-gate 	dr_devset_t	devset;
24730Sstevel@tonic-gate 
24740Sstevel@tonic-gate 	devset = DR_DEVS_PRESENT(hp->h_bd);
24750Sstevel@tonic-gate 	if (hp->h_sbdcmd.cmd_cm.c_id.c_type != SBD_COMP_NONE)
24760Sstevel@tonic-gate 		devset &= DEVSET(hp->h_sbdcmd.cmd_cm.c_id.c_type,
24777656SSherry.Moore@Sun.COM 		    DEVSET_ANYUNIT);
24780Sstevel@tonic-gate 
24790Sstevel@tonic-gate 	/*
24800Sstevel@tonic-gate 	 * Handle CPUs first to deal with possible CMP
24810Sstevel@tonic-gate 	 * devices. If the CPU is a CMP, we need to only
24820Sstevel@tonic-gate 	 * increment ncm once even if there are multiple
24830Sstevel@tonic-gate 	 * cores for that CMP present in the devset.
24840Sstevel@tonic-gate 	 */
24850Sstevel@tonic-gate 	for (i = 0; i < MAX_CMP_UNITS_PER_BOARD; i++) {
24860Sstevel@tonic-gate 		if (devset & DEVSET(SBD_COMP_CMP, i)) {
24870Sstevel@tonic-gate 			ncm++;
24880Sstevel@tonic-gate 		}
24890Sstevel@tonic-gate 	}
24900Sstevel@tonic-gate 
24910Sstevel@tonic-gate 	/* eliminate the CPU information from the devset */
24920Sstevel@tonic-gate 	devset &= ~(DEVSET(SBD_COMP_CMP, DEVSET_ANYUNIT));
24930Sstevel@tonic-gate 
24940Sstevel@tonic-gate 	for (i = 0; i < (sizeof (dr_devset_t) * 8); i++) {
24950Sstevel@tonic-gate 		ncm += devset & 0x1;
24960Sstevel@tonic-gate 		devset >>= 1;
24970Sstevel@tonic-gate 	}
24980Sstevel@tonic-gate 
24990Sstevel@tonic-gate 	return (ncm);
25000Sstevel@tonic-gate }
25010Sstevel@tonic-gate 
25020Sstevel@tonic-gate /* used by dr_mem.c */
25030Sstevel@tonic-gate /* TODO: eliminate dr_boardlist */
25040Sstevel@tonic-gate dr_board_t *
dr_lookup_board(int board_num)25050Sstevel@tonic-gate dr_lookup_board(int board_num)
25060Sstevel@tonic-gate {
25070Sstevel@tonic-gate 	dr_board_t *bp;
25080Sstevel@tonic-gate 
25090Sstevel@tonic-gate 	ASSERT(board_num >= 0 && board_num < MAX_BOARDS);
25100Sstevel@tonic-gate 
25110Sstevel@tonic-gate 	bp = &dr_boardlist[board_num];
25120Sstevel@tonic-gate 	ASSERT(bp->b_num == board_num);
25130Sstevel@tonic-gate 
25140Sstevel@tonic-gate 	return (bp);
25150Sstevel@tonic-gate }
25160Sstevel@tonic-gate 
25170Sstevel@tonic-gate static dr_dev_unit_t *
dr_get_dev_unit(dr_board_t * bp,sbd_comp_type_t nt,int unit_num)25180Sstevel@tonic-gate dr_get_dev_unit(dr_board_t *bp, sbd_comp_type_t nt, int unit_num)
25190Sstevel@tonic-gate {
25200Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
25210Sstevel@tonic-gate 
25220Sstevel@tonic-gate 	dp = DR_GET_BOARD_DEVUNIT(bp, nt, unit_num);
25230Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_bp == bp);
25240Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_unum == unit_num);
25250Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_type == nt);
25260Sstevel@tonic-gate 
25270Sstevel@tonic-gate 	return (dp);
25280Sstevel@tonic-gate }
25290Sstevel@tonic-gate 
25300Sstevel@tonic-gate dr_cpu_unit_t *
dr_get_cpu_unit(dr_board_t * bp,int unit_num)25310Sstevel@tonic-gate dr_get_cpu_unit(dr_board_t *bp, int unit_num)
25320Sstevel@tonic-gate {
25330Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 	ASSERT(unit_num >= 0 && unit_num < MAX_CPU_UNITS_PER_BOARD);
25360Sstevel@tonic-gate 
25370Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, SBD_COMP_CPU, unit_num);
25380Sstevel@tonic-gate 	return (&dp->du_cpu);
25390Sstevel@tonic-gate }
25400Sstevel@tonic-gate 
25410Sstevel@tonic-gate dr_mem_unit_t *
dr_get_mem_unit(dr_board_t * bp,int unit_num)25420Sstevel@tonic-gate dr_get_mem_unit(dr_board_t *bp, int unit_num)
25430Sstevel@tonic-gate {
25440Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
25450Sstevel@tonic-gate 
25460Sstevel@tonic-gate 	ASSERT(unit_num >= 0 && unit_num < MAX_MEM_UNITS_PER_BOARD);
25470Sstevel@tonic-gate 
25480Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, SBD_COMP_MEM, unit_num);
25490Sstevel@tonic-gate 	return (&dp->du_mem);
25500Sstevel@tonic-gate }
25510Sstevel@tonic-gate 
25520Sstevel@tonic-gate dr_io_unit_t *
dr_get_io_unit(dr_board_t * bp,int unit_num)25530Sstevel@tonic-gate dr_get_io_unit(dr_board_t *bp, int unit_num)
25540Sstevel@tonic-gate {
25550Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
25560Sstevel@tonic-gate 
25570Sstevel@tonic-gate 	ASSERT(unit_num >= 0 && unit_num < MAX_IO_UNITS_PER_BOARD);
25580Sstevel@tonic-gate 
25590Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, SBD_COMP_IO, unit_num);
25600Sstevel@tonic-gate 	return (&dp->du_io);
25610Sstevel@tonic-gate }
25620Sstevel@tonic-gate 
25630Sstevel@tonic-gate dr_common_unit_t *
dr_get_common_unit(dr_board_t * bp,sbd_comp_type_t nt,int unum)25640Sstevel@tonic-gate dr_get_common_unit(dr_board_t *bp, sbd_comp_type_t nt, int unum)
25650Sstevel@tonic-gate {
25660Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
25670Sstevel@tonic-gate 
25680Sstevel@tonic-gate 	dp = dr_get_dev_unit(bp, nt, unum);
25690Sstevel@tonic-gate 	return (&dp->du_common);
25700Sstevel@tonic-gate }
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate static dr_devset_t
dr_dev2devset(sbd_comp_id_t * cid)25730Sstevel@tonic-gate dr_dev2devset(sbd_comp_id_t *cid)
25740Sstevel@tonic-gate {
25750Sstevel@tonic-gate 	static fn_t	f = "dr_dev2devset";
25760Sstevel@tonic-gate 
25770Sstevel@tonic-gate 	dr_devset_t	devset;
25780Sstevel@tonic-gate 	int		unit = cid->c_unit;
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate 	switch (cid->c_type) {
25810Sstevel@tonic-gate 		case SBD_COMP_NONE:
25820Sstevel@tonic-gate 			devset =  DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT);
25830Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT);
25840Sstevel@tonic-gate 			devset |= DEVSET(SBD_COMP_IO,  DEVSET_ANYUNIT);
25851772Sjl139090 			PR_ALL("%s: COMP_NONE devset = 0x%lx\n", f, devset);
25860Sstevel@tonic-gate 			break;
25870Sstevel@tonic-gate 
25880Sstevel@tonic-gate 		case SBD_COMP_CPU:
25890Sstevel@tonic-gate 			if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) {
25900Sstevel@tonic-gate 				cmn_err(CE_WARN,
25917656SSherry.Moore@Sun.COM 				    "%s: invalid cpu unit# = %d",
25927656SSherry.Moore@Sun.COM 				    f, unit);
25930Sstevel@tonic-gate 				devset = 0;
25940Sstevel@tonic-gate 			} else {
25950Sstevel@tonic-gate 				/*
25960Sstevel@tonic-gate 				 * Generate a devset that includes all the
25970Sstevel@tonic-gate 				 * cores of a CMP device. If this is not a
25980Sstevel@tonic-gate 				 * CMP, the extra cores will be eliminated
25990Sstevel@tonic-gate 				 * later since they are not present. This is
26000Sstevel@tonic-gate 				 * also true for CMP devices that do not have
26010Sstevel@tonic-gate 				 * all cores active.
26020Sstevel@tonic-gate 				 */
26030Sstevel@tonic-gate 				devset = DEVSET(SBD_COMP_CMP, unit);
26040Sstevel@tonic-gate 			}
26050Sstevel@tonic-gate 
26061772Sjl139090 			PR_ALL("%s: CPU devset = 0x%lx\n", f, devset);
26070Sstevel@tonic-gate 			break;
26080Sstevel@tonic-gate 
26090Sstevel@tonic-gate 		case SBD_COMP_MEM:
26100Sstevel@tonic-gate 			if (unit == SBD_NULL_UNIT) {
26110Sstevel@tonic-gate 				unit = 0;
26120Sstevel@tonic-gate 				cid->c_unit = 0;
26130Sstevel@tonic-gate 			}
26140Sstevel@tonic-gate 
26150Sstevel@tonic-gate 			if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) {
26160Sstevel@tonic-gate 				cmn_err(CE_WARN,
26177656SSherry.Moore@Sun.COM 				    "%s: invalid mem unit# = %d",
26187656SSherry.Moore@Sun.COM 				    f, unit);
26190Sstevel@tonic-gate 				devset = 0;
26200Sstevel@tonic-gate 			} else
26210Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
26220Sstevel@tonic-gate 
26231772Sjl139090 			PR_ALL("%s: MEM devset = 0x%lx\n", f, devset);
26240Sstevel@tonic-gate 			break;
26250Sstevel@tonic-gate 
26260Sstevel@tonic-gate 		case SBD_COMP_IO:
26270Sstevel@tonic-gate 			if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) {
26280Sstevel@tonic-gate 				cmn_err(CE_WARN,
26297656SSherry.Moore@Sun.COM 				    "%s: invalid io unit# = %d",
26307656SSherry.Moore@Sun.COM 				    f, unit);
26310Sstevel@tonic-gate 				devset = 0;
26320Sstevel@tonic-gate 			} else
26330Sstevel@tonic-gate 				devset = DEVSET(cid->c_type, unit);
26340Sstevel@tonic-gate 
26351772Sjl139090 			PR_ALL("%s: IO devset = 0x%lx\n", f, devset);
26360Sstevel@tonic-gate 			break;
26370Sstevel@tonic-gate 
26380Sstevel@tonic-gate 		default:
26390Sstevel@tonic-gate 		case SBD_COMP_UNKNOWN:
26400Sstevel@tonic-gate 			devset = 0;
26410Sstevel@tonic-gate 			break;
26420Sstevel@tonic-gate 	}
26430Sstevel@tonic-gate 
26440Sstevel@tonic-gate 	return (devset);
26450Sstevel@tonic-gate }
26460Sstevel@tonic-gate 
26470Sstevel@tonic-gate /*
26480Sstevel@tonic-gate  * Converts a dynamic attachment point name to a SBD_COMP_* type.
26490Sstevel@tonic-gate  * Returns SDB_COMP_UNKNOWN if name is not recognized.
26500Sstevel@tonic-gate  */
26510Sstevel@tonic-gate static int
dr_dev_type_to_nt(char * type)26520Sstevel@tonic-gate dr_dev_type_to_nt(char *type)
26530Sstevel@tonic-gate {
26540Sstevel@tonic-gate 	int i;
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate 	for (i = 0; dr_devattr[i].s_nodetype != SBD_COMP_UNKNOWN; i++)
26570Sstevel@tonic-gate 		if (strcmp(dr_devattr[i].s_devtype, type) == 0)
26580Sstevel@tonic-gate 			break;
26590Sstevel@tonic-gate 
26600Sstevel@tonic-gate 	return (dr_devattr[i].s_nodetype);
26610Sstevel@tonic-gate }
26620Sstevel@tonic-gate 
26630Sstevel@tonic-gate /*
26640Sstevel@tonic-gate  * Converts a SBD_COMP_* type to a dynamic attachment point name.
26650Sstevel@tonic-gate  * Return NULL if SBD_COMP_ type is not recognized.
26660Sstevel@tonic-gate  */
26670Sstevel@tonic-gate char *
dr_nt_to_dev_type(int nt)26680Sstevel@tonic-gate dr_nt_to_dev_type(int nt)
26690Sstevel@tonic-gate {
26700Sstevel@tonic-gate 	int i;
26710Sstevel@tonic-gate 
26720Sstevel@tonic-gate 	for (i = 0; dr_devattr[i].s_nodetype != SBD_COMP_UNKNOWN; i++)
26730Sstevel@tonic-gate 		if (dr_devattr[i].s_nodetype == nt)
26740Sstevel@tonic-gate 			break;
26750Sstevel@tonic-gate 
26760Sstevel@tonic-gate 	return (dr_devattr[i].s_devtype);
26770Sstevel@tonic-gate }
26780Sstevel@tonic-gate 
26790Sstevel@tonic-gate 
26800Sstevel@tonic-gate /*
26810Sstevel@tonic-gate  * State transition policy is that if there is some component for which
26820Sstevel@tonic-gate  * the state transition is valid, then let it through. The exception is
26830Sstevel@tonic-gate  * SBD_CMD_DISCONNECT. On disconnect, the state transition must be valid
26840Sstevel@tonic-gate  * for ALL components.
26850Sstevel@tonic-gate  * Returns the state that is in error, if any.
26860Sstevel@tonic-gate  */
26870Sstevel@tonic-gate static int
dr_check_transition(dr_board_t * bp,dr_devset_t * devsetp,struct dr_state_trans * transp,int cmd)26880Sstevel@tonic-gate dr_check_transition(dr_board_t *bp, dr_devset_t *devsetp,
26890Sstevel@tonic-gate 			struct dr_state_trans *transp, int cmd)
26900Sstevel@tonic-gate {
26910Sstevel@tonic-gate 	int			s, ut;
26920Sstevel@tonic-gate 	int			state_err = 0;
26930Sstevel@tonic-gate 	dr_devset_t		devset;
26940Sstevel@tonic-gate 	dr_common_unit_t	*cp;
26950Sstevel@tonic-gate 	static fn_t		f = "dr_check_transition";
26960Sstevel@tonic-gate 
26970Sstevel@tonic-gate 	devset = *devsetp;
26980Sstevel@tonic-gate 
26990Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) {
27000Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) {
27010Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0)
27020Sstevel@tonic-gate 				continue;
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, SBD_COMP_CPU, ut);
27050Sstevel@tonic-gate 			s = (int)cp->sbdev_state;
27060Sstevel@tonic-gate 			if (!DR_DEV_IS_PRESENT(cp)) {
27070Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_CPU, ut);
27080Sstevel@tonic-gate 			} else {
27090Sstevel@tonic-gate 				if (transp->x_op[s].x_rv) {
27100Sstevel@tonic-gate 					if (!state_err)
27110Sstevel@tonic-gate 						state_err = s;
27120Sstevel@tonic-gate 					DEVSET_DEL(devset, SBD_COMP_CPU, ut);
27130Sstevel@tonic-gate 				}
27140Sstevel@tonic-gate 			}
27150Sstevel@tonic-gate 		}
27160Sstevel@tonic-gate 	}
27170Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) {
27180Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) {
27190Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0)
27200Sstevel@tonic-gate 				continue;
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, SBD_COMP_MEM, ut);
27230Sstevel@tonic-gate 			s = (int)cp->sbdev_state;
27240Sstevel@tonic-gate 			if (!DR_DEV_IS_PRESENT(cp)) {
27250Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_MEM, ut);
27260Sstevel@tonic-gate 			} else {
27270Sstevel@tonic-gate 				if (transp->x_op[s].x_rv) {
27280Sstevel@tonic-gate 					if (!state_err)
27290Sstevel@tonic-gate 						state_err = s;
27300Sstevel@tonic-gate 					DEVSET_DEL(devset, SBD_COMP_MEM, ut);
27310Sstevel@tonic-gate 				}
27320Sstevel@tonic-gate 			}
27330Sstevel@tonic-gate 		}
27340Sstevel@tonic-gate 	}
27350Sstevel@tonic-gate 	if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) {
27360Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) {
27370Sstevel@tonic-gate 			if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0)
27380Sstevel@tonic-gate 				continue;
27390Sstevel@tonic-gate 
27400Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, SBD_COMP_IO, ut);
27410Sstevel@tonic-gate 			s = (int)cp->sbdev_state;
27420Sstevel@tonic-gate 			if (!DR_DEV_IS_PRESENT(cp)) {
27430Sstevel@tonic-gate 				DEVSET_DEL(devset, SBD_COMP_IO, ut);
27440Sstevel@tonic-gate 			} else {
27450Sstevel@tonic-gate 				if (transp->x_op[s].x_rv) {
27460Sstevel@tonic-gate 					if (!state_err)
27470Sstevel@tonic-gate 						state_err = s;
27480Sstevel@tonic-gate 					DEVSET_DEL(devset, SBD_COMP_IO, ut);
27490Sstevel@tonic-gate 				}
27500Sstevel@tonic-gate 			}
27510Sstevel@tonic-gate 		}
27520Sstevel@tonic-gate 	}
27530Sstevel@tonic-gate 
27540Sstevel@tonic-gate 	PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n",
27557656SSherry.Moore@Sun.COM 	    f, (uint_t)*devsetp, (uint_t)devset);
27560Sstevel@tonic-gate 
27570Sstevel@tonic-gate 	*devsetp = devset;
27580Sstevel@tonic-gate 	/*
27590Sstevel@tonic-gate 	 * If there are some remaining components for which
27600Sstevel@tonic-gate 	 * this state transition is valid, then allow them
27610Sstevel@tonic-gate 	 * through, otherwise if none are left then return
27620Sstevel@tonic-gate 	 * the state error. The exception is SBD_CMD_DISCONNECT.
27630Sstevel@tonic-gate 	 * On disconnect, the state transition must be valid for ALL
27640Sstevel@tonic-gate 	 * components.
27650Sstevel@tonic-gate 	 */
27660Sstevel@tonic-gate 	if (cmd == SBD_CMD_DISCONNECT)
27670Sstevel@tonic-gate 		return (state_err);
27680Sstevel@tonic-gate 	return (devset ? 0 : state_err);
27690Sstevel@tonic-gate }
27700Sstevel@tonic-gate 
27710Sstevel@tonic-gate void
dr_device_transition(dr_common_unit_t * cp,dr_state_t st)27720Sstevel@tonic-gate dr_device_transition(dr_common_unit_t *cp, dr_state_t st)
27730Sstevel@tonic-gate {
27740Sstevel@tonic-gate 	PR_STATE("%s STATE %s(%d) -> %s(%d)\n",
27757656SSherry.Moore@Sun.COM 	    cp->sbdev_path,
27767656SSherry.Moore@Sun.COM 	    state_str[cp->sbdev_state], cp->sbdev_state,
27777656SSherry.Moore@Sun.COM 	    state_str[st], st);
27780Sstevel@tonic-gate 
27790Sstevel@tonic-gate 	cp->sbdev_state = st;
27800Sstevel@tonic-gate 	if (st == DR_STATE_CONFIGURED) {
27810Sstevel@tonic-gate 		cp->sbdev_ostate = SBD_STAT_CONFIGURED;
27820Sstevel@tonic-gate 		if (cp->sbdev_bp->b_ostate != SBD_STAT_CONFIGURED) {
27830Sstevel@tonic-gate 			cp->sbdev_bp->b_ostate = SBD_STAT_CONFIGURED;
27840Sstevel@tonic-gate 			(void) drv_getparm(TIME,
27857656SSherry.Moore@Sun.COM 			    (void *) &cp->sbdev_bp->b_time);
27860Sstevel@tonic-gate 		}
27870Sstevel@tonic-gate 	} else
27880Sstevel@tonic-gate 		cp->sbdev_ostate = SBD_STAT_UNCONFIGURED;
27890Sstevel@tonic-gate 
27900Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *) &cp->sbdev_time);
27910Sstevel@tonic-gate }
27920Sstevel@tonic-gate 
27930Sstevel@tonic-gate static void
dr_board_transition(dr_board_t * bp,dr_state_t st)27940Sstevel@tonic-gate dr_board_transition(dr_board_t *bp, dr_state_t st)
27950Sstevel@tonic-gate {
27960Sstevel@tonic-gate 	PR_STATE("BOARD %d STATE: %s(%d) -> %s(%d)\n",
27977656SSherry.Moore@Sun.COM 	    bp->b_num,
27987656SSherry.Moore@Sun.COM 	    state_str[bp->b_state], bp->b_state,
27997656SSherry.Moore@Sun.COM 	    state_str[st], st);
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	bp->b_state = st;
28020Sstevel@tonic-gate }
28030Sstevel@tonic-gate 
28040Sstevel@tonic-gate void
dr_op_err(int ce,dr_handle_t * hp,int code,char * fmt,...)28050Sstevel@tonic-gate dr_op_err(int ce, dr_handle_t *hp, int code, char *fmt, ...)
28060Sstevel@tonic-gate {
28070Sstevel@tonic-gate 	sbd_error_t	*err;
28080Sstevel@tonic-gate 	va_list		args;
28090Sstevel@tonic-gate 
28100Sstevel@tonic-gate 	va_start(args, fmt);
28110Sstevel@tonic-gate 	err = drerr_new_v(code, fmt, args);
28120Sstevel@tonic-gate 	va_end(args);
28130Sstevel@tonic-gate 
28140Sstevel@tonic-gate 	if (ce != CE_IGNORE)
28150Sstevel@tonic-gate 		sbd_err_log(err, ce);
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate 	DRERR_SET_C(&hp->h_err, &err);
28180Sstevel@tonic-gate }
28190Sstevel@tonic-gate 
28200Sstevel@tonic-gate void
dr_dev_err(int ce,dr_common_unit_t * cp,int code)28210Sstevel@tonic-gate dr_dev_err(int ce, dr_common_unit_t *cp, int code)
28220Sstevel@tonic-gate {
28230Sstevel@tonic-gate 	sbd_error_t	*err;
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate 	err = drerr_new(0, code, cp->sbdev_path, NULL);
28260Sstevel@tonic-gate 
28270Sstevel@tonic-gate 	if (ce != CE_IGNORE)
28280Sstevel@tonic-gate 		sbd_err_log(err, ce);
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	DRERR_SET_C(&cp->sbdev_error, &err);
28310Sstevel@tonic-gate }
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate /*
28340Sstevel@tonic-gate  * A callback routine.  Called from the drmach layer as a result of
28350Sstevel@tonic-gate  * call to drmach_board_find_devices from dr_init_devlists.
28360Sstevel@tonic-gate  */
28370Sstevel@tonic-gate static sbd_error_t *
dr_dev_found(void * data,const char * name,int unum,drmachid_t id)28380Sstevel@tonic-gate dr_dev_found(void *data, const char *name, int unum, drmachid_t id)
28390Sstevel@tonic-gate {
28400Sstevel@tonic-gate 	dr_board_t	*bp = data;
28410Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
28420Sstevel@tonic-gate 	int		 nt;
28430Sstevel@tonic-gate 	static fn_t	f = "dr_dev_found";
28440Sstevel@tonic-gate 
28450Sstevel@tonic-gate 	PR_ALL("%s (board = %d, name = %s, unum = %d, id = %p)...\n",
28467656SSherry.Moore@Sun.COM 	    f, bp->b_num, name, unum, id);
28470Sstevel@tonic-gate 
28480Sstevel@tonic-gate 	nt = dr_dev_type_to_nt((char *)name);
28490Sstevel@tonic-gate 	if (nt == SBD_COMP_UNKNOWN) {
28500Sstevel@tonic-gate 		/*
28510Sstevel@tonic-gate 		 * this should not happen.  When it does, it indicates
28520Sstevel@tonic-gate 		 * a missmatch in devices supported by the drmach layer
28530Sstevel@tonic-gate 		 * vs devices supported by this layer.
28540Sstevel@tonic-gate 		 */
28550Sstevel@tonic-gate 		return (DR_INTERNAL_ERROR());
28560Sstevel@tonic-gate 	}
28570Sstevel@tonic-gate 
28580Sstevel@tonic-gate 	dp = DR_GET_BOARD_DEVUNIT(bp, nt, unum);
28590Sstevel@tonic-gate 
28600Sstevel@tonic-gate 	/* sanity check */
28610Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_bp == bp);
28620Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_unum == unum);
28630Sstevel@tonic-gate 	ASSERT(dp->du_common.sbdev_type == nt);
28640Sstevel@tonic-gate 
28650Sstevel@tonic-gate 	/* render dynamic attachment point path of this unit */
28660Sstevel@tonic-gate 	(void) snprintf(dp->du_common.sbdev_path,
28677656SSherry.Moore@Sun.COM 	    sizeof (dp->du_common.sbdev_path),
28687656SSherry.Moore@Sun.COM 	    (nt == SBD_COMP_MEM ? "%s::%s" : "%s::%s%d"),
28697656SSherry.Moore@Sun.COM 	    bp->b_path, name, DR_UNUM2SBD_UNUM(unum, nt));
28700Sstevel@tonic-gate 
28710Sstevel@tonic-gate 	dp->du_common.sbdev_id = id;
28720Sstevel@tonic-gate 	DR_DEV_SET_PRESENT(&dp->du_common);
28730Sstevel@tonic-gate 
28740Sstevel@tonic-gate 	bp->b_ndev++;
28750Sstevel@tonic-gate 
28760Sstevel@tonic-gate 	return (NULL);
28770Sstevel@tonic-gate }
28780Sstevel@tonic-gate 
28790Sstevel@tonic-gate static sbd_error_t *
dr_init_devlists(dr_board_t * bp)28800Sstevel@tonic-gate dr_init_devlists(dr_board_t *bp)
28810Sstevel@tonic-gate {
28820Sstevel@tonic-gate 	int		i;
28830Sstevel@tonic-gate 	sbd_error_t	*err;
28840Sstevel@tonic-gate 	dr_dev_unit_t	*dp;
28850Sstevel@tonic-gate 	static fn_t	f = "dr_init_devlists";
28860Sstevel@tonic-gate 
28870Sstevel@tonic-gate 	PR_ALL("%s (%s)...\n", f, bp->b_path);
28880Sstevel@tonic-gate 
28890Sstevel@tonic-gate 	/* sanity check */
28900Sstevel@tonic-gate 	ASSERT(bp->b_ndev == 0);
28910Sstevel@tonic-gate 
28920Sstevel@tonic-gate 	DR_DEVS_DISCONNECT(bp, (uint_t)-1);
28930Sstevel@tonic-gate 
28940Sstevel@tonic-gate 	/*
28950Sstevel@tonic-gate 	 * This routine builds the board's devlist and initializes
28960Sstevel@tonic-gate 	 * the common portion of the unit data structures.
28970Sstevel@tonic-gate 	 * Note: because the common portion is considered
28980Sstevel@tonic-gate 	 * uninitialized, the dr_get_*_unit() routines can not
28990Sstevel@tonic-gate 	 * be used.
29000Sstevel@tonic-gate 	 */
29010Sstevel@tonic-gate 
29020Sstevel@tonic-gate 	/*
29030Sstevel@tonic-gate 	 * Clear out old entries, if any.
29040Sstevel@tonic-gate 	 */
29050Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
29060Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_CPU, i);
29070Sstevel@tonic-gate 
29080Sstevel@tonic-gate 		bzero(dp, sizeof (*dp));
29090Sstevel@tonic-gate 		dp->du_common.sbdev_bp = bp;
29100Sstevel@tonic-gate 		dp->du_common.sbdev_unum = i;
29110Sstevel@tonic-gate 		dp->du_common.sbdev_type = SBD_COMP_CPU;
29120Sstevel@tonic-gate 	}
29130Sstevel@tonic-gate 
29140Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
29150Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_MEM, i);
29160Sstevel@tonic-gate 
29170Sstevel@tonic-gate 		bzero(dp, sizeof (*dp));
29180Sstevel@tonic-gate 		dp->du_common.sbdev_bp = bp;
29190Sstevel@tonic-gate 		dp->du_common.sbdev_unum = i;
29200Sstevel@tonic-gate 		dp->du_common.sbdev_type = SBD_COMP_MEM;
29210Sstevel@tonic-gate 	}
29220Sstevel@tonic-gate 
29230Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
29240Sstevel@tonic-gate 		dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_IO, i);
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 		bzero(dp, sizeof (*dp));
29270Sstevel@tonic-gate 		dp->du_common.sbdev_bp = bp;
29280Sstevel@tonic-gate 		dp->du_common.sbdev_unum = i;
29290Sstevel@tonic-gate 		dp->du_common.sbdev_type = SBD_COMP_IO;
29300Sstevel@tonic-gate 	}
29310Sstevel@tonic-gate 
29320Sstevel@tonic-gate 	err = NULL;
29330Sstevel@tonic-gate 	if (bp->b_id) {
29340Sstevel@tonic-gate 		/* find devices on this board */
29350Sstevel@tonic-gate 		err = drmach_board_find_devices(
29367656SSherry.Moore@Sun.COM 		    bp->b_id, bp, dr_dev_found);
29370Sstevel@tonic-gate 	}
29380Sstevel@tonic-gate 
29390Sstevel@tonic-gate 	return (err);
29400Sstevel@tonic-gate }
29410Sstevel@tonic-gate 
29420Sstevel@tonic-gate /*
29430Sstevel@tonic-gate  * Return the unit number of the respective drmachid if
29440Sstevel@tonic-gate  * it's found to be attached.
29450Sstevel@tonic-gate  */
29460Sstevel@tonic-gate static int
dr_check_unit_attached(dr_common_unit_t * cp)29470Sstevel@tonic-gate dr_check_unit_attached(dr_common_unit_t *cp)
29480Sstevel@tonic-gate {
29490Sstevel@tonic-gate 	int		rv = 0;
29500Sstevel@tonic-gate 	processorid_t	cpuid;
29510Sstevel@tonic-gate 	uint64_t	basepa, endpa;
29520Sstevel@tonic-gate 	struct memlist	*ml;
29530Sstevel@tonic-gate 	extern struct memlist	*phys_install;
29540Sstevel@tonic-gate 	sbd_error_t	*err;
29550Sstevel@tonic-gate 	int		yes;
29560Sstevel@tonic-gate 	static fn_t	f = "dr_check_unit_attached";
29570Sstevel@tonic-gate 
29580Sstevel@tonic-gate 	switch (cp->sbdev_type) {
29590Sstevel@tonic-gate 	case SBD_COMP_CPU:
29600Sstevel@tonic-gate 		err = drmach_cpu_get_id(cp->sbdev_id, &cpuid);
29610Sstevel@tonic-gate 		if (err) {
29620Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
29630Sstevel@tonic-gate 			rv = -1;
29640Sstevel@tonic-gate 			break;
29650Sstevel@tonic-gate 		}
29660Sstevel@tonic-gate 		mutex_enter(&cpu_lock);
29670Sstevel@tonic-gate 		if (cpu_get(cpuid) == NULL)
29680Sstevel@tonic-gate 			rv = -1;
29690Sstevel@tonic-gate 		mutex_exit(&cpu_lock);
29700Sstevel@tonic-gate 		break;
29710Sstevel@tonic-gate 
29720Sstevel@tonic-gate 	case SBD_COMP_MEM:
29730Sstevel@tonic-gate 		err = drmach_mem_get_base_physaddr(cp->sbdev_id, &basepa);
29740Sstevel@tonic-gate 		if (err) {
29750Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
29760Sstevel@tonic-gate 			rv = -1;
29770Sstevel@tonic-gate 			break;
29780Sstevel@tonic-gate 		}
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate 		/*
29810Sstevel@tonic-gate 		 * basepa may not be on a alignment boundary, make it so.
29820Sstevel@tonic-gate 		 */
29830Sstevel@tonic-gate 		err = drmach_mem_get_slice_size(cp->sbdev_id, &endpa);
29840Sstevel@tonic-gate 		if (err) {
29850Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
29860Sstevel@tonic-gate 			rv = -1;
29870Sstevel@tonic-gate 			break;
29880Sstevel@tonic-gate 		}
29890Sstevel@tonic-gate 
29900Sstevel@tonic-gate 		basepa &= ~(endpa - 1);
29910Sstevel@tonic-gate 		endpa += basepa;
29920Sstevel@tonic-gate 
29930Sstevel@tonic-gate 		/*
29940Sstevel@tonic-gate 		 * Check if base address is in phys_install.
29950Sstevel@tonic-gate 		 */
29960Sstevel@tonic-gate 		memlist_read_lock();
2997*11474SJonathan.Adams@Sun.COM 		for (ml = phys_install; ml; ml = ml->ml_next)
2998*11474SJonathan.Adams@Sun.COM 			if ((endpa <= ml->ml_address) ||
2999*11474SJonathan.Adams@Sun.COM 			    (basepa >= (ml->ml_address + ml->ml_size)))
30000Sstevel@tonic-gate 				continue;
30010Sstevel@tonic-gate 			else
30020Sstevel@tonic-gate 				break;
30030Sstevel@tonic-gate 		memlist_read_unlock();
30040Sstevel@tonic-gate 		if (ml == NULL)
30050Sstevel@tonic-gate 			rv = -1;
30060Sstevel@tonic-gate 		break;
30070Sstevel@tonic-gate 
30080Sstevel@tonic-gate 	case SBD_COMP_IO:
30090Sstevel@tonic-gate 		err = drmach_io_is_attached(cp->sbdev_id, &yes);
30100Sstevel@tonic-gate 		if (err) {
30110Sstevel@tonic-gate 			DRERR_SET_C(&cp->sbdev_error, &err);
30120Sstevel@tonic-gate 			rv = -1;
30130Sstevel@tonic-gate 			break;
30140Sstevel@tonic-gate 		} else if (!yes)
30150Sstevel@tonic-gate 			rv = -1;
30160Sstevel@tonic-gate 		break;
30170Sstevel@tonic-gate 
30180Sstevel@tonic-gate 	default:
3019930Smathue 		PR_ALL("%s: unexpected nodetype(%d) for id 0x%p\n",
30207656SSherry.Moore@Sun.COM 		    f, cp->sbdev_type, cp->sbdev_id);
30210Sstevel@tonic-gate 		rv = -1;
30220Sstevel@tonic-gate 		break;
30230Sstevel@tonic-gate 	}
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate 	return (rv);
30260Sstevel@tonic-gate }
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate /*
30290Sstevel@tonic-gate  * See if drmach recognizes the passthru command.  DRMACH expects the
30300Sstevel@tonic-gate  * id to identify the thing to which the command is being applied.  Using
30310Sstevel@tonic-gate  * nonsense SBD terms, that information has been perversely encoded in the
30320Sstevel@tonic-gate  * c_id member of the sbd_cmd_t structure.  This logic reads those tea
30330Sstevel@tonic-gate  * leaves, finds the associated drmach id, then calls drmach to process
30340Sstevel@tonic-gate  * the passthru command.
30350Sstevel@tonic-gate  */
30360Sstevel@tonic-gate static int
dr_pt_try_drmach(dr_handle_t * hp)30370Sstevel@tonic-gate dr_pt_try_drmach(dr_handle_t *hp)
30380Sstevel@tonic-gate {
30390Sstevel@tonic-gate 	dr_board_t	*bp = hp->h_bd;
30400Sstevel@tonic-gate 	sbd_comp_id_t	*comp_id = &hp->h_sbdcmd.cmd_cm.c_id;
30410Sstevel@tonic-gate 	drmachid_t	 id;
30420Sstevel@tonic-gate 
30430Sstevel@tonic-gate 	if (comp_id->c_type == SBD_COMP_NONE) {
30440Sstevel@tonic-gate 		id = bp->b_id;
30450Sstevel@tonic-gate 	} else {
30460Sstevel@tonic-gate 		sbd_comp_type_t	 nt;
30470Sstevel@tonic-gate 
30480Sstevel@tonic-gate 		nt = dr_dev_type_to_nt(comp_id->c_name);
30490Sstevel@tonic-gate 		if (nt == SBD_COMP_UNKNOWN) {
30500Sstevel@tonic-gate 			dr_op_err(CE_IGNORE, hp, ESBD_INVAL, comp_id->c_name);
30510Sstevel@tonic-gate 			id = 0;
30520Sstevel@tonic-gate 		} else {
30530Sstevel@tonic-gate 			/* pt command applied to dynamic attachment point */
30540Sstevel@tonic-gate 			dr_common_unit_t *cp;
30550Sstevel@tonic-gate 			cp = dr_get_common_unit(bp, nt, comp_id->c_unit);
30560Sstevel@tonic-gate 			id = cp->sbdev_id;
30570Sstevel@tonic-gate 		}
30580Sstevel@tonic-gate 	}
30590Sstevel@tonic-gate 
30600Sstevel@tonic-gate 	if (hp->h_err == NULL)
30610Sstevel@tonic-gate 		hp->h_err = drmach_passthru(id, &hp->h_opts);
30620Sstevel@tonic-gate 
30630Sstevel@tonic-gate 	return (hp->h_err == NULL ? 0 : -1);
30640Sstevel@tonic-gate }
30650Sstevel@tonic-gate 
30660Sstevel@tonic-gate static int
dr_pt_ioctl(dr_handle_t * hp)30670Sstevel@tonic-gate dr_pt_ioctl(dr_handle_t *hp)
30680Sstevel@tonic-gate {
30690Sstevel@tonic-gate 	int		cmd, rv, len;
30700Sstevel@tonic-gate 	int32_t		sz;
30710Sstevel@tonic-gate 	int		found;
30720Sstevel@tonic-gate 	char		*copts;
30730Sstevel@tonic-gate 	static fn_t	f = "dr_pt_ioctl";
30740Sstevel@tonic-gate 
30750Sstevel@tonic-gate 	PR_ALL("%s...\n", f);
30760Sstevel@tonic-gate 
30770Sstevel@tonic-gate 	sz = hp->h_opts.size;
30780Sstevel@tonic-gate 	copts = hp->h_opts.copts;
30790Sstevel@tonic-gate 
30800Sstevel@tonic-gate 	if (sz == 0 || copts == (char *)NULL) {
30810Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s: invalid passthru args", f);
30820Sstevel@tonic-gate 		return (EINVAL);
30830Sstevel@tonic-gate 	}
30840Sstevel@tonic-gate 
30850Sstevel@tonic-gate 	found = 0;
30860Sstevel@tonic-gate 	for (cmd = 0; cmd < (sizeof (pt_arr) / sizeof (pt_arr[0])); cmd++) {
30870Sstevel@tonic-gate 		len = strlen(pt_arr[cmd].pt_name);
30880Sstevel@tonic-gate 		found = (strncmp(pt_arr[cmd].pt_name, copts, len) == 0);
30890Sstevel@tonic-gate 		if (found)
30900Sstevel@tonic-gate 			break;
30910Sstevel@tonic-gate 	}
30920Sstevel@tonic-gate 
30930Sstevel@tonic-gate 	if (found)
30940Sstevel@tonic-gate 		rv = (*pt_arr[cmd].pt_func)(hp);
30950Sstevel@tonic-gate 	else
30960Sstevel@tonic-gate 		rv = dr_pt_try_drmach(hp);
30970Sstevel@tonic-gate 
30980Sstevel@tonic-gate 	return (rv);
30990Sstevel@tonic-gate }
31000Sstevel@tonic-gate 
31010Sstevel@tonic-gate /*
31020Sstevel@tonic-gate  * Called at driver load time to determine the state and condition
31030Sstevel@tonic-gate  * of an existing board in the system.
31040Sstevel@tonic-gate  */
31050Sstevel@tonic-gate static void
dr_board_discovery(dr_board_t * bp)31060Sstevel@tonic-gate dr_board_discovery(dr_board_t *bp)
31070Sstevel@tonic-gate {
31080Sstevel@tonic-gate 	int			i;
31090Sstevel@tonic-gate 	dr_devset_t		devs_lost, devs_attached = 0;
31100Sstevel@tonic-gate 	dr_cpu_unit_t		*cp;
31110Sstevel@tonic-gate 	dr_mem_unit_t		*mp;
31120Sstevel@tonic-gate 	dr_io_unit_t		*ip;
31130Sstevel@tonic-gate 	static fn_t		f = "dr_board_discovery";
31140Sstevel@tonic-gate 
31150Sstevel@tonic-gate 	if (DR_DEVS_PRESENT(bp) == 0) {
31160Sstevel@tonic-gate 		PR_ALL("%s: board %d has no devices present\n",
31177656SSherry.Moore@Sun.COM 		    f, bp->b_num);
31180Sstevel@tonic-gate 		return;
31190Sstevel@tonic-gate 	}
31200Sstevel@tonic-gate 
31210Sstevel@tonic-gate 	/*
31220Sstevel@tonic-gate 	 * Check for existence of cpus.
31230Sstevel@tonic-gate 	 */
31240Sstevel@tonic-gate 	for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) {
31250Sstevel@tonic-gate 		cp = dr_get_cpu_unit(bp, i);
31260Sstevel@tonic-gate 
31270Sstevel@tonic-gate 		if (!DR_DEV_IS_PRESENT(&cp->sbc_cm))
31280Sstevel@tonic-gate 			continue;
31290Sstevel@tonic-gate 
31300Sstevel@tonic-gate 		if (dr_check_unit_attached(&cp->sbc_cm) >= 0) {
31310Sstevel@tonic-gate 			DR_DEV_SET_ATTACHED(&cp->sbc_cm);
31320Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_CPU, i);
31330Sstevel@tonic-gate 			PR_ALL("%s: board %d, cpu-unit %d - attached\n",
31347656SSherry.Moore@Sun.COM 			    f, bp->b_num, i);
31350Sstevel@tonic-gate 		}
31360Sstevel@tonic-gate 		dr_init_cpu_unit(cp);
31370Sstevel@tonic-gate 	}
31380Sstevel@tonic-gate 
31390Sstevel@tonic-gate 	/*
31400Sstevel@tonic-gate 	 * Check for existence of memory.
31410Sstevel@tonic-gate 	 */
31420Sstevel@tonic-gate 	for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) {
31430Sstevel@tonic-gate 		mp = dr_get_mem_unit(bp, i);
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 		if (!DR_DEV_IS_PRESENT(&mp->sbm_cm))
31460Sstevel@tonic-gate 			continue;
31470Sstevel@tonic-gate 
31480Sstevel@tonic-gate 		if (dr_check_unit_attached(&mp->sbm_cm) >= 0) {
31490Sstevel@tonic-gate 			DR_DEV_SET_ATTACHED(&mp->sbm_cm);
31500Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_MEM, i);
31510Sstevel@tonic-gate 			PR_ALL("%s: board %d, mem-unit %d - attached\n",
31527656SSherry.Moore@Sun.COM 			    f, bp->b_num, i);
31530Sstevel@tonic-gate 		}
31540Sstevel@tonic-gate 		dr_init_mem_unit(mp);
31550Sstevel@tonic-gate 	}
31560Sstevel@tonic-gate 
31570Sstevel@tonic-gate 	/*
31580Sstevel@tonic-gate 	 * Check for i/o state.
31590Sstevel@tonic-gate 	 */
31600Sstevel@tonic-gate 	for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) {
31610Sstevel@tonic-gate 		ip = dr_get_io_unit(bp, i);
31620Sstevel@tonic-gate 
31630Sstevel@tonic-gate 		if (!DR_DEV_IS_PRESENT(&ip->sbi_cm))
31640Sstevel@tonic-gate 			continue;
31650Sstevel@tonic-gate 
31660Sstevel@tonic-gate 		if (dr_check_unit_attached(&ip->sbi_cm) >= 0) {
31670Sstevel@tonic-gate 			/*
31680Sstevel@tonic-gate 			 * Found it!
31690Sstevel@tonic-gate 			 */
31700Sstevel@tonic-gate 			DR_DEV_SET_ATTACHED(&ip->sbi_cm);
31710Sstevel@tonic-gate 			DEVSET_ADD(devs_attached, SBD_COMP_IO, i);
31720Sstevel@tonic-gate 			PR_ALL("%s: board %d, io-unit %d - attached\n",
31737656SSherry.Moore@Sun.COM 			    f, bp->b_num, i);
31740Sstevel@tonic-gate 		}
31750Sstevel@tonic-gate 		dr_init_io_unit(ip);
31760Sstevel@tonic-gate 	}
31770Sstevel@tonic-gate 
31780Sstevel@tonic-gate 	DR_DEVS_CONFIGURE(bp, devs_attached);
31790Sstevel@tonic-gate 	if (devs_attached && ((devs_lost = DR_DEVS_UNATTACHED(bp)) != 0)) {
31800Sstevel@tonic-gate 		int		ut;
31810Sstevel@tonic-gate 		/*
31820Sstevel@tonic-gate 		 * It is not legal on board discovery to have a
31830Sstevel@tonic-gate 		 * board that is only partially attached.  A board
31840Sstevel@tonic-gate 		 * is either all attached or all connected.  If a
31850Sstevel@tonic-gate 		 * board has at least one attached device, then
31860Sstevel@tonic-gate 		 * the the remaining devices, if any, must have
31870Sstevel@tonic-gate 		 * been lost or disconnected.  These devices can
31880Sstevel@tonic-gate 		 * only be recovered by a full attach from scratch.
31890Sstevel@tonic-gate 		 * Note that devices previously in the unreferenced
31900Sstevel@tonic-gate 		 * state are subsequently lost until the next full
31910Sstevel@tonic-gate 		 * attach.  This is necessary since the driver unload
31920Sstevel@tonic-gate 		 * that must have occurred would have wiped out the
31930Sstevel@tonic-gate 		 * information necessary to re-configure the device
31940Sstevel@tonic-gate 		 * back online, e.g. memlist.
31950Sstevel@tonic-gate 		 */
31961772Sjl139090 		PR_ALL("%s: some devices LOST (0x%lx)...\n", f, devs_lost);
31970Sstevel@tonic-gate 
31980Sstevel@tonic-gate 		for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) {
31990Sstevel@tonic-gate 			if (!DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut))
32000Sstevel@tonic-gate 				continue;
32010Sstevel@tonic-gate 
32020Sstevel@tonic-gate 			cp = dr_get_cpu_unit(bp, ut);
32030Sstevel@tonic-gate 			dr_device_transition(&cp->sbc_cm, DR_STATE_EMPTY);
32040Sstevel@tonic-gate 		}
32050Sstevel@tonic-gate 
32060Sstevel@tonic-gate 		for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) {
32070Sstevel@tonic-gate 			if (!DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut))
32080Sstevel@tonic-gate 				continue;
32090Sstevel@tonic-gate 
32100Sstevel@tonic-gate 			mp = dr_get_mem_unit(bp, ut);
32110Sstevel@tonic-gate 			dr_device_transition(&mp->sbm_cm, DR_STATE_EMPTY);
32120Sstevel@tonic-gate 		}
32130Sstevel@tonic-gate 
32140Sstevel@tonic-gate 		for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) {
32150Sstevel@tonic-gate 			if (!DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut))
32160Sstevel@tonic-gate 				continue;
32170Sstevel@tonic-gate 
32180Sstevel@tonic-gate 			ip = dr_get_io_unit(bp, ut);
32190Sstevel@tonic-gate 			dr_device_transition(&ip->sbi_cm, DR_STATE_EMPTY);
32200Sstevel@tonic-gate 		}
32210Sstevel@tonic-gate 
32220Sstevel@tonic-gate 		DR_DEVS_DISCONNECT(bp, devs_lost);
32230Sstevel@tonic-gate 	}
32240Sstevel@tonic-gate }
32250Sstevel@tonic-gate 
32260Sstevel@tonic-gate static int
dr_board_init(dr_board_t * bp,dev_info_t * dip,int bd)32270Sstevel@tonic-gate dr_board_init(dr_board_t *bp, dev_info_t *dip, int bd)
32280Sstevel@tonic-gate {
32290Sstevel@tonic-gate 	sbd_error_t	*err;
32300Sstevel@tonic-gate 
32310Sstevel@tonic-gate 	mutex_init(&bp->b_lock, NULL, MUTEX_DRIVER, NULL);
32320Sstevel@tonic-gate 	mutex_init(&bp->b_slock, NULL, MUTEX_DRIVER, NULL);
32330Sstevel@tonic-gate 	cv_init(&bp->b_scv, NULL, CV_DRIVER, NULL);
32340Sstevel@tonic-gate 	bp->b_rstate = SBD_STAT_EMPTY;
32350Sstevel@tonic-gate 	bp->b_ostate = SBD_STAT_UNCONFIGURED;
32360Sstevel@tonic-gate 	bp->b_cond = SBD_COND_UNKNOWN;
32370Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *)&bp->b_time);
32380Sstevel@tonic-gate 
32390Sstevel@tonic-gate 	(void) drmach_board_lookup(bd, &bp->b_id);
32400Sstevel@tonic-gate 	bp->b_num = bd;
32410Sstevel@tonic-gate 	bp->b_dip = dip;
32420Sstevel@tonic-gate 
32430Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(dr_dev_unit_t,
32447656SSherry.Moore@Sun.COM 	    MAX_CPU_UNITS_PER_BOARD);
32450Sstevel@tonic-gate 
32460Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(dr_dev_unit_t,
32477656SSherry.Moore@Sun.COM 	    MAX_MEM_UNITS_PER_BOARD);
32480Sstevel@tonic-gate 
32490Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(dr_dev_unit_t,
32507656SSherry.Moore@Sun.COM 	    MAX_IO_UNITS_PER_BOARD);
32510Sstevel@tonic-gate 
32520Sstevel@tonic-gate 	/*
32530Sstevel@tonic-gate 	 * Initialize the devlists
32540Sstevel@tonic-gate 	 */
32550Sstevel@tonic-gate 	err = dr_init_devlists(bp);
32560Sstevel@tonic-gate 	if (err) {
32570Sstevel@tonic-gate 		sbd_err_clear(&err);
32580Sstevel@tonic-gate 		dr_board_destroy(bp);
32590Sstevel@tonic-gate 		return (-1);
32600Sstevel@tonic-gate 	} else if (bp->b_ndev == 0) {
32610Sstevel@tonic-gate 		dr_board_transition(bp, DR_STATE_EMPTY);
32620Sstevel@tonic-gate 	} else {
32630Sstevel@tonic-gate 		/*
32640Sstevel@tonic-gate 		 * Couldn't have made it down here without
32650Sstevel@tonic-gate 		 * having found at least one device.
32660Sstevel@tonic-gate 		 */
32670Sstevel@tonic-gate 		ASSERT(DR_DEVS_PRESENT(bp) != 0);
32680Sstevel@tonic-gate 		/*
32690Sstevel@tonic-gate 		 * Check the state of any possible devices on the
32700Sstevel@tonic-gate 		 * board.
32710Sstevel@tonic-gate 		 */
32720Sstevel@tonic-gate 		dr_board_discovery(bp);
32730Sstevel@tonic-gate 
32740Sstevel@tonic-gate 		bp->b_assigned = 1;
32750Sstevel@tonic-gate 
32760Sstevel@tonic-gate 		if (DR_DEVS_UNATTACHED(bp) == 0) {
32770Sstevel@tonic-gate 			/*
32780Sstevel@tonic-gate 			 * The board has no unattached devices, therefore
32790Sstevel@tonic-gate 			 * by reason of insanity it must be configured!
32800Sstevel@tonic-gate 			 */
32810Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONFIGURED);
32820Sstevel@tonic-gate 			bp->b_ostate = SBD_STAT_CONFIGURED;
32830Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_CONNECTED;
32840Sstevel@tonic-gate 			bp->b_cond = SBD_COND_OK;
32850Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
32860Sstevel@tonic-gate 		} else if (DR_DEVS_ATTACHED(bp)) {
32870Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_PARTIAL);
32880Sstevel@tonic-gate 			bp->b_ostate = SBD_STAT_CONFIGURED;
32890Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_CONNECTED;
32900Sstevel@tonic-gate 			bp->b_cond = SBD_COND_OK;
32910Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
32920Sstevel@tonic-gate 		} else {
32930Sstevel@tonic-gate 			dr_board_transition(bp, DR_STATE_CONNECTED);
32940Sstevel@tonic-gate 			bp->b_rstate = SBD_STAT_CONNECTED;
32950Sstevel@tonic-gate 			(void) drv_getparm(TIME, (void *)&bp->b_time);
32960Sstevel@tonic-gate 		}
32970Sstevel@tonic-gate 	}
32980Sstevel@tonic-gate 
32990Sstevel@tonic-gate 	return (0);
33000Sstevel@tonic-gate }
33010Sstevel@tonic-gate 
33020Sstevel@tonic-gate static void
dr_board_destroy(dr_board_t * bp)33030Sstevel@tonic-gate dr_board_destroy(dr_board_t *bp)
33040Sstevel@tonic-gate {
33050Sstevel@tonic-gate 	PR_ALL("dr_board_destroy: num %d, path %s\n",
33067656SSherry.Moore@Sun.COM 	    bp->b_num, bp->b_path);
33070Sstevel@tonic-gate 
33080Sstevel@tonic-gate 	dr_board_transition(bp, DR_STATE_EMPTY);
33090Sstevel@tonic-gate 	bp->b_rstate = SBD_STAT_EMPTY;
33100Sstevel@tonic-gate 	(void) drv_getparm(TIME, (void *)&bp->b_time);
33110Sstevel@tonic-gate 
33120Sstevel@tonic-gate 	/*
33130Sstevel@tonic-gate 	 * Free up MEM unit structs.
33140Sstevel@tonic-gate 	 */
33150Sstevel@tonic-gate 	FREESTRUCT(bp->b_dev[NIX(SBD_COMP_MEM)],
33167656SSherry.Moore@Sun.COM 	    dr_dev_unit_t, MAX_MEM_UNITS_PER_BOARD);
33170Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_MEM)] = NULL;
33180Sstevel@tonic-gate 	/*
33190Sstevel@tonic-gate 	 * Free up CPU unit structs.
33200Sstevel@tonic-gate 	 */
33210Sstevel@tonic-gate 	FREESTRUCT(bp->b_dev[NIX(SBD_COMP_CPU)],
33227656SSherry.Moore@Sun.COM 	    dr_dev_unit_t, MAX_CPU_UNITS_PER_BOARD);
33230Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_CPU)] = NULL;
33240Sstevel@tonic-gate 	/*
33250Sstevel@tonic-gate 	 * Free up IO unit structs.
33260Sstevel@tonic-gate 	 */
33270Sstevel@tonic-gate 	FREESTRUCT(bp->b_dev[NIX(SBD_COMP_IO)],
33287656SSherry.Moore@Sun.COM 	    dr_dev_unit_t, MAX_IO_UNITS_PER_BOARD);
33290Sstevel@tonic-gate 	bp->b_dev[NIX(SBD_COMP_IO)] = NULL;
33300Sstevel@tonic-gate 
33310Sstevel@tonic-gate 	mutex_destroy(&bp->b_lock);
33320Sstevel@tonic-gate 	mutex_destroy(&bp->b_slock);
33330Sstevel@tonic-gate 	cv_destroy(&bp->b_scv);
33340Sstevel@tonic-gate }
33350Sstevel@tonic-gate 
33360Sstevel@tonic-gate void
dr_lock_status(dr_board_t * bp)33370Sstevel@tonic-gate dr_lock_status(dr_board_t *bp)
33380Sstevel@tonic-gate {
33390Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
33400Sstevel@tonic-gate 	while (bp->b_sflags & DR_BSLOCK)
33410Sstevel@tonic-gate 		cv_wait(&bp->b_scv, &bp->b_slock);
33420Sstevel@tonic-gate 	bp->b_sflags |= DR_BSLOCK;
33430Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
33440Sstevel@tonic-gate }
33450Sstevel@tonic-gate 
33460Sstevel@tonic-gate void
dr_unlock_status(dr_board_t * bp)33470Sstevel@tonic-gate dr_unlock_status(dr_board_t *bp)
33480Sstevel@tonic-gate {
33490Sstevel@tonic-gate 	mutex_enter(&bp->b_slock);
33500Sstevel@tonic-gate 	bp->b_sflags &= ~DR_BSLOCK;
33510Sstevel@tonic-gate 	cv_signal(&bp->b_scv);
33520Sstevel@tonic-gate 	mutex_exit(&bp->b_slock);
33530Sstevel@tonic-gate }
33540Sstevel@tonic-gate 
33550Sstevel@tonic-gate /*
33560Sstevel@tonic-gate  * Extract flags passed via ioctl.
33570Sstevel@tonic-gate  */
33580Sstevel@tonic-gate int
dr_cmd_flags(dr_handle_t * hp)33590Sstevel@tonic-gate dr_cmd_flags(dr_handle_t *hp)
33600Sstevel@tonic-gate {
33610Sstevel@tonic-gate 	return (hp->h_sbdcmd.cmd_cm.c_flags);
33620Sstevel@tonic-gate }
3363