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