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