10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * CDDL HEADER START 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * The contents of this file are subject to the terms of the 50Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 60Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 70Sstevel@tonic-gate * with the License. 80Sstevel@tonic-gate * 90Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 100Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 110Sstevel@tonic-gate * See the License for the specific language governing permissions 120Sstevel@tonic-gate * and limitations under the License. 130Sstevel@tonic-gate * 140Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 150Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 160Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 170Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 180Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 190Sstevel@tonic-gate * 200Sstevel@tonic-gate * CDDL HEADER END 210Sstevel@tonic-gate */ 220Sstevel@tonic-gate /* 230Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 240Sstevel@tonic-gate * Use is subject to license terms. 250Sstevel@tonic-gate */ 260Sstevel@tonic-gate 270Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 280Sstevel@tonic-gate 290Sstevel@tonic-gate /* 300Sstevel@tonic-gate * safari system board DR module. 310Sstevel@tonic-gate */ 320Sstevel@tonic-gate 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/ndi_impldefs.h> 460Sstevel@tonic-gate #include <sys/stat.h> 470Sstevel@tonic-gate #include <sys/kmem.h> 480Sstevel@tonic-gate #include <sys/cpuvar.h> 490Sstevel@tonic-gate #include <sys/mem_config.h> 500Sstevel@tonic-gate #include <sys/mem_cage.h> 510Sstevel@tonic-gate 520Sstevel@tonic-gate #include <sys/autoconf.h> 530Sstevel@tonic-gate #include <sys/cmn_err.h> 540Sstevel@tonic-gate 550Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 560Sstevel@tonic-gate #include <sys/machsystm.h> 570Sstevel@tonic-gate #include <sys/param.h> 580Sstevel@tonic-gate 590Sstevel@tonic-gate #include <sys/sbdpriv.h> 600Sstevel@tonic-gate #include <sys/sbd_io.h> 610Sstevel@tonic-gate 620Sstevel@tonic-gate /* start sbd includes */ 630Sstevel@tonic-gate 640Sstevel@tonic-gate #include <sys/systm.h> 650Sstevel@tonic-gate #include <sys/sysmacros.h> 660Sstevel@tonic-gate #include <sys/x_call.h> 670Sstevel@tonic-gate #include <sys/membar.h> 680Sstevel@tonic-gate #include <vm/seg_kmem.h> 690Sstevel@tonic-gate 700Sstevel@tonic-gate extern int nulldev(); 710Sstevel@tonic-gate extern int nodev(); 720Sstevel@tonic-gate 730Sstevel@tonic-gate typedef struct { /* arg to sbd_get_handle */ 740Sstevel@tonic-gate dev_t dev; 750Sstevel@tonic-gate int cmd; 760Sstevel@tonic-gate int mode; 770Sstevel@tonic-gate sbd_ioctl_arg_t *ioargp; 780Sstevel@tonic-gate } sbd_init_arg_t; 790Sstevel@tonic-gate 800Sstevel@tonic-gate 810Sstevel@tonic-gate /* 820Sstevel@tonic-gate * sbd support operations. 830Sstevel@tonic-gate */ 840Sstevel@tonic-gate static void sbd_exec_op(sbd_handle_t *hp); 850Sstevel@tonic-gate static void sbd_dev_configure(sbd_handle_t *hp); 860Sstevel@tonic-gate static int sbd_dev_release(sbd_handle_t *hp); 870Sstevel@tonic-gate static int sbd_dev_unconfigure(sbd_handle_t *hp); 880Sstevel@tonic-gate static void sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, 890Sstevel@tonic-gate dev_info_t *dip, int unit); 900Sstevel@tonic-gate static void sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, 910Sstevel@tonic-gate dev_info_t *dip, int unit); 920Sstevel@tonic-gate static int sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit); 930Sstevel@tonic-gate static void sbd_cancel(sbd_handle_t *hp); 940Sstevel@tonic-gate void sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip); 950Sstevel@tonic-gate int sbd_dealloc_instance(sbd_board_t *sbp, int max_boards); 960Sstevel@tonic-gate int sbd_errno2ecode(int error); 970Sstevel@tonic-gate #pragma weak sbdp_cpu_get_impl 980Sstevel@tonic-gate 990Sstevel@tonic-gate #ifdef DEBUG 1000Sstevel@tonic-gate uint_t sbd_debug = (uint_t)0x0; 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS 1030Sstevel@tonic-gate /* controls which errors are injected */ 1040Sstevel@tonic-gate uint_t sbd_err_debug = (uint_t)0x0; 1050Sstevel@tonic-gate 1060Sstevel@tonic-gate /* controls printing about error injection */ 1070Sstevel@tonic-gate uint_t sbd_print_errs = (uint_t)0x0; 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate #endif /* SBD_DEBUG_ERRS */ 1100Sstevel@tonic-gate 1110Sstevel@tonic-gate #endif /* DEBUG */ 1120Sstevel@tonic-gate 1130Sstevel@tonic-gate char *sbd_state_str[] = { 1140Sstevel@tonic-gate "EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED", 1150Sstevel@tonic-gate "PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED", 1160Sstevel@tonic-gate "FATAL" 1170Sstevel@tonic-gate }; 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate /* Note: this must be changed in tandem with sbd_ioctl.h */ 1200Sstevel@tonic-gate char *sbd_ct_str[] = { 1210Sstevel@tonic-gate "NONE", "CPU", "MEM", "IO", "UNKNOWN" 1220Sstevel@tonic-gate }; 1230Sstevel@tonic-gate 1240Sstevel@tonic-gate /* Note: this must also be changed in tandem with sbd_ioctl.h */ 1250Sstevel@tonic-gate #define SBD_CMD_STR(c) \ 1260Sstevel@tonic-gate (((c) == SBD_CMD_ASSIGN) ? "ASSIGN" : \ 1270Sstevel@tonic-gate ((c) == SBD_CMD_UNASSIGN) ? "UNASSIGN" : \ 1280Sstevel@tonic-gate ((c) == SBD_CMD_POWERON) ? "POWERON" : \ 1290Sstevel@tonic-gate ((c) == SBD_CMD_POWEROFF) ? "POWEROFF" : \ 1300Sstevel@tonic-gate ((c) == SBD_CMD_TEST) ? "TEST" : \ 1310Sstevel@tonic-gate ((c) == SBD_CMD_CONNECT) ? "CONNECT" : \ 1320Sstevel@tonic-gate ((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \ 1330Sstevel@tonic-gate ((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \ 1340Sstevel@tonic-gate ((c) == SBD_CMD_DISCONNECT) ? "DISCONNECT" : \ 1350Sstevel@tonic-gate ((c) == SBD_CMD_STATUS) ? "STATUS" : \ 1360Sstevel@tonic-gate ((c) == SBD_CMD_GETNCM) ? "GETNCM" : \ 1370Sstevel@tonic-gate ((c) == SBD_CMD_PASSTHRU) ? "PASSTHRU" : "unknown") 1380Sstevel@tonic-gate 1390Sstevel@tonic-gate /* 1400Sstevel@tonic-gate * Defines and structures for device tree naming and mapping 1410Sstevel@tonic-gate * to node types 1420Sstevel@tonic-gate */ 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate sbd_devattr_t *sbd_devattr; 1450Sstevel@tonic-gate 1460Sstevel@tonic-gate /* defines to access the attribute struct */ 1470Sstevel@tonic-gate #define SBD_DEVNAME(i) sbd_devattr[i].s_devname 1480Sstevel@tonic-gate #define SBD_OTYPE(i) sbd_devattr[(i)].s_obp_type 1490Sstevel@tonic-gate #define SBD_COMP(i) sbd_devattr[i].s_dnodetype 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate /* 1520Sstevel@tonic-gate * State transition table. States valid transitions for "board" state. 1530Sstevel@tonic-gate * Recall that non-zero return value terminates operation, however 1540Sstevel@tonic-gate * the herrno value is what really indicates an error , if any. 1550Sstevel@tonic-gate */ 1560Sstevel@tonic-gate static int 1570Sstevel@tonic-gate _cmd2index(int c) 1580Sstevel@tonic-gate { 1590Sstevel@tonic-gate /* 1600Sstevel@tonic-gate * Translate DR CMD to index into sbd_state_transition. 1610Sstevel@tonic-gate */ 1620Sstevel@tonic-gate switch (c) { 1630Sstevel@tonic-gate case SBD_CMD_CONNECT: return (0); 1640Sstevel@tonic-gate case SBD_CMD_DISCONNECT: return (1); 1650Sstevel@tonic-gate case SBD_CMD_CONFIGURE: return (2); 1660Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: return (3); 1670Sstevel@tonic-gate case SBD_CMD_POWEROFF: return (4); 1680Sstevel@tonic-gate case SBD_CMD_POWERON: return (5); 1690Sstevel@tonic-gate case SBD_CMD_UNASSIGN: return (6); 1700Sstevel@tonic-gate case SBD_CMD_ASSIGN: return (7); 1710Sstevel@tonic-gate case SBD_CMD_TEST: return (8); 1720Sstevel@tonic-gate default: return (-1); 1730Sstevel@tonic-gate } 1740Sstevel@tonic-gate } 1750Sstevel@tonic-gate 1760Sstevel@tonic-gate #define CMD2INDEX(c) _cmd2index(c) 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate static struct sbd_state_trans { 1790Sstevel@tonic-gate int x_cmd; 1800Sstevel@tonic-gate struct { 1810Sstevel@tonic-gate int x_rv; /* return value of pre_op */ 1820Sstevel@tonic-gate int x_err; /* errno, if any */ 1830Sstevel@tonic-gate } x_op[SBD_NUM_STATES]; 1840Sstevel@tonic-gate } sbd_state_transition[] = { 1850Sstevel@tonic-gate { SBD_CMD_CONNECT, 1860Sstevel@tonic-gate { 1870Sstevel@tonic-gate { 0, 0 }, /* empty */ 1880Sstevel@tonic-gate { 0, 0 }, /* occupied */ 1890Sstevel@tonic-gate { 1, EIO }, /* connected */ 1900Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 1910Sstevel@tonic-gate { 1, EIO }, /* partial */ 1920Sstevel@tonic-gate { 1, EIO }, /* configured */ 1930Sstevel@tonic-gate { 1, EIO }, /* release */ 1940Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 1950Sstevel@tonic-gate { 1, EIO }, /* fatal */ 1960Sstevel@tonic-gate } 1970Sstevel@tonic-gate }, 1980Sstevel@tonic-gate { SBD_CMD_DISCONNECT, 1990Sstevel@tonic-gate { 2000Sstevel@tonic-gate { 1, EIO }, /* empty */ 2010Sstevel@tonic-gate { 0, 0 }, /* occupied */ 2020Sstevel@tonic-gate { 0, 0 }, /* connected */ 2030Sstevel@tonic-gate { 0, 0 }, /* unconfigured */ 2040Sstevel@tonic-gate { 1, EIO }, /* partial */ 2050Sstevel@tonic-gate { 1, EIO }, /* configured */ 2060Sstevel@tonic-gate { 1, EIO }, /* release */ 2070Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 2080Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2090Sstevel@tonic-gate } 2100Sstevel@tonic-gate }, 2110Sstevel@tonic-gate { SBD_CMD_CONFIGURE, 2120Sstevel@tonic-gate { 2130Sstevel@tonic-gate { 1, EIO }, /* empty */ 2140Sstevel@tonic-gate { 1, EIO }, /* occupied */ 2150Sstevel@tonic-gate { 0, 0 }, /* connected */ 2160Sstevel@tonic-gate { 0, 0 }, /* unconfigured */ 2170Sstevel@tonic-gate { 0, 0 }, /* partial */ 2180Sstevel@tonic-gate { 1, 0 }, /* configured */ 2190Sstevel@tonic-gate { 0, 0 }, /* release */ 2200Sstevel@tonic-gate { 0, 0 }, /* unreferenced */ 2210Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2220Sstevel@tonic-gate } 2230Sstevel@tonic-gate }, 2240Sstevel@tonic-gate { SBD_CMD_UNCONFIGURE, 2250Sstevel@tonic-gate { 2260Sstevel@tonic-gate { 1, EIO }, /* empty */ 2270Sstevel@tonic-gate { 1, EIO }, /* occupied */ 2280Sstevel@tonic-gate { 1, EIO }, /* connected */ 2290Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 2300Sstevel@tonic-gate { 1, EIO }, /* partial */ 2310Sstevel@tonic-gate { 0, 0 }, /* configured */ 2320Sstevel@tonic-gate { 0, 0 }, /* release */ 2330Sstevel@tonic-gate { 0, 0 }, /* unreferenced */ 2340Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2350Sstevel@tonic-gate } 2360Sstevel@tonic-gate }, 2370Sstevel@tonic-gate { SBD_CMD_POWEROFF, 2380Sstevel@tonic-gate { 2390Sstevel@tonic-gate { 1, EIO }, /* empty */ 2400Sstevel@tonic-gate { 0, 0 }, /* occupied */ 2410Sstevel@tonic-gate { 1, EIO }, /* connected */ 2420Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 2430Sstevel@tonic-gate { 1, EIO }, /* partial */ 2440Sstevel@tonic-gate { 1, EIO }, /* configured */ 2450Sstevel@tonic-gate { 1, EIO }, /* release */ 2460Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 2470Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2480Sstevel@tonic-gate } 2490Sstevel@tonic-gate }, 2500Sstevel@tonic-gate { SBD_CMD_POWERON, 2510Sstevel@tonic-gate { 2520Sstevel@tonic-gate { 1, EIO }, /* empty */ 2530Sstevel@tonic-gate { 0, 0 }, /* occupied */ 2540Sstevel@tonic-gate { 1, EIO }, /* connected */ 2550Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 2560Sstevel@tonic-gate { 1, EIO }, /* partial */ 2570Sstevel@tonic-gate { 1, EIO }, /* configured */ 2580Sstevel@tonic-gate { 1, EIO }, /* release */ 2590Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 2600Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2610Sstevel@tonic-gate } 2620Sstevel@tonic-gate }, 2630Sstevel@tonic-gate { SBD_CMD_UNASSIGN, 2640Sstevel@tonic-gate { 2650Sstevel@tonic-gate { 1, EIO }, /* empty */ 2660Sstevel@tonic-gate { 0, 0 }, /* occupied */ 2670Sstevel@tonic-gate { 1, EIO }, /* connected */ 2680Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 2690Sstevel@tonic-gate { 1, EIO }, /* partial */ 2700Sstevel@tonic-gate { 1, EIO }, /* configured */ 2710Sstevel@tonic-gate { 1, EIO }, /* release */ 2720Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 2730Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2740Sstevel@tonic-gate } 2750Sstevel@tonic-gate }, 2760Sstevel@tonic-gate { SBD_CMD_ASSIGN, 2770Sstevel@tonic-gate { 2780Sstevel@tonic-gate { 1, EIO }, /* empty */ 2790Sstevel@tonic-gate { 0, 0 }, /* occupied */ 2800Sstevel@tonic-gate { 1, EIO }, /* connected */ 2810Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 2820Sstevel@tonic-gate { 1, EIO }, /* partial */ 2830Sstevel@tonic-gate { 1, EIO }, /* configured */ 2840Sstevel@tonic-gate { 1, EIO }, /* release */ 2850Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 2860Sstevel@tonic-gate { 1, EIO }, /* fatal */ 2870Sstevel@tonic-gate } 2880Sstevel@tonic-gate }, 2890Sstevel@tonic-gate { SBD_CMD_TEST, 2900Sstevel@tonic-gate { 2910Sstevel@tonic-gate { 1, EIO }, /* empty */ 2920Sstevel@tonic-gate { 0, 0 }, /* occupied */ 2930Sstevel@tonic-gate { 1, EIO }, /* connected */ 2940Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 2950Sstevel@tonic-gate { 1, EIO }, /* partial */ 2960Sstevel@tonic-gate { 1, EIO }, /* configured */ 2970Sstevel@tonic-gate { 1, EIO }, /* release */ 2980Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 2990Sstevel@tonic-gate { 1, EIO }, /* fatal */ 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate }, 3020Sstevel@tonic-gate }; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* 3050Sstevel@tonic-gate * Global R/W lock to synchronize access across 3060Sstevel@tonic-gate * multiple boards. Users wanting multi-board access 3070Sstevel@tonic-gate * must grab WRITE lock, others must grab READ lock. 3080Sstevel@tonic-gate */ 3090Sstevel@tonic-gate krwlock_t sbd_grwlock; 3100Sstevel@tonic-gate 3110Sstevel@tonic-gate /* 3120Sstevel@tonic-gate * Global to determine if an event needs to be sent 3130Sstevel@tonic-gate */ 3140Sstevel@tonic-gate char send_event = 0; 3150Sstevel@tonic-gate 3160Sstevel@tonic-gate /* 3170Sstevel@tonic-gate * Required/Expected functions. 3180Sstevel@tonic-gate */ 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate static sbd_handle_t *sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, 3210Sstevel@tonic-gate intptr_t arg, sbd_init_arg_t *iap); 3220Sstevel@tonic-gate static void sbd_release_handle(sbd_handle_t *hp); 3230Sstevel@tonic-gate static int sbd_pre_op(sbd_handle_t *hp); 3240Sstevel@tonic-gate static void sbd_post_op(sbd_handle_t *hp); 3250Sstevel@tonic-gate static int sbd_probe_board(sbd_handle_t *hp); 3260Sstevel@tonic-gate static int sbd_deprobe_board(sbd_handle_t *hp); 3270Sstevel@tonic-gate static void sbd_connect(sbd_handle_t *hp); 3280Sstevel@tonic-gate static void sbd_assign_board(sbd_handle_t *hp); 3290Sstevel@tonic-gate static void sbd_unassign_board(sbd_handle_t *hp); 3300Sstevel@tonic-gate static void sbd_poweron_board(sbd_handle_t *hp); 3310Sstevel@tonic-gate static void sbd_poweroff_board(sbd_handle_t *hp); 3320Sstevel@tonic-gate static void sbd_test_board(sbd_handle_t *hp); 3330Sstevel@tonic-gate 3340Sstevel@tonic-gate static int sbd_disconnect(sbd_handle_t *hp); 3350Sstevel@tonic-gate static sbd_devlist_t *sbd_get_attach_devlist(sbd_handle_t *hp, 3360Sstevel@tonic-gate int32_t *devnump, int32_t pass); 3370Sstevel@tonic-gate static int sbd_pre_attach_devlist(sbd_handle_t *hp, 3380Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 3390Sstevel@tonic-gate static int sbd_post_attach_devlist(sbd_handle_t *hp, 3400Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 3410Sstevel@tonic-gate static sbd_devlist_t *sbd_get_release_devlist(sbd_handle_t *hp, 3420Sstevel@tonic-gate int32_t *devnump, int32_t pass); 3430Sstevel@tonic-gate static int sbd_pre_release_devlist(sbd_handle_t *hp, 3440Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 3450Sstevel@tonic-gate static int sbd_post_release_devlist(sbd_handle_t *hp, 3460Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 3470Sstevel@tonic-gate static void sbd_release_done(sbd_handle_t *hp, 3480Sstevel@tonic-gate sbd_comp_type_t nodetype, 3490Sstevel@tonic-gate dev_info_t *dip); 3500Sstevel@tonic-gate static sbd_devlist_t *sbd_get_detach_devlist(sbd_handle_t *hp, 3510Sstevel@tonic-gate int32_t *devnump, int32_t pass); 3520Sstevel@tonic-gate static int sbd_pre_detach_devlist(sbd_handle_t *hp, 3530Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 3540Sstevel@tonic-gate static int sbd_post_detach_devlist(sbd_handle_t *hp, 3550Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 3560Sstevel@tonic-gate static void sbd_status(sbd_handle_t *hp); 3570Sstevel@tonic-gate static void sbd_get_ncm(sbd_handle_t *hp); 3580Sstevel@tonic-gate 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * Support functions. 3620Sstevel@tonic-gate */ 3630Sstevel@tonic-gate static sbd_devset_t sbd_dev2devset(sbd_comp_id_t *cid); 3640Sstevel@tonic-gate static int sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, 3650Sstevel@tonic-gate sbd_cmd_t *cmdp, sbd_ioctl_arg_t *iap); 3660Sstevel@tonic-gate static int sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, 3670Sstevel@tonic-gate void *arg); 3680Sstevel@tonic-gate static int sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, 3690Sstevel@tonic-gate sbd_ioctl_arg_t *iap); 3700Sstevel@tonic-gate static int sbd_check_transition(sbd_board_t *sbp, 3710Sstevel@tonic-gate sbd_devset_t *devsetp, 3720Sstevel@tonic-gate struct sbd_state_trans *transp); 3730Sstevel@tonic-gate static sbd_devlist_t *sbd_get_devlist(sbd_handle_t *hp, 3740Sstevel@tonic-gate sbd_board_t *sbp, 3750Sstevel@tonic-gate sbd_comp_type_t nodetype, 3760Sstevel@tonic-gate int max_units, uint_t uset, 3770Sstevel@tonic-gate int *count, int present_only); 3780Sstevel@tonic-gate static int sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, 3790Sstevel@tonic-gate sbd_dev_stat_t *dsp); 3800Sstevel@tonic-gate 3810Sstevel@tonic-gate static int sbd_init_devlists(sbd_board_t *sbp); 3820Sstevel@tonic-gate static int sbd_name_to_idx(char *name); 3830Sstevel@tonic-gate static int sbd_otype_to_idx(char *otpye); 3840Sstevel@tonic-gate static int sbd_setup_devlists(dev_info_t *dip, void *arg); 3850Sstevel@tonic-gate static void sbd_init_mem_devlists(sbd_board_t *sbp); 3860Sstevel@tonic-gate static void sbd_init_cpu_unit(sbd_board_t *sbp, int unit); 3870Sstevel@tonic-gate static void sbd_board_discovery(sbd_board_t *sbp); 3880Sstevel@tonic-gate static void sbd_board_init(sbd_board_t *sbp, 3890Sstevel@tonic-gate sbd_softstate_t *softsp, 3900Sstevel@tonic-gate int bd, dev_info_t *dip, int wnode); 3910Sstevel@tonic-gate static void sbd_board_destroy(sbd_board_t *sbp); 3920Sstevel@tonic-gate static int sbd_check_unit_attached(sbd_board_t *sbp, 3930Sstevel@tonic-gate dev_info_t *dip, int unit, 3940Sstevel@tonic-gate sbd_comp_type_t nodetype, sbderror_t *ep); 3950Sstevel@tonic-gate 3960Sstevel@tonic-gate static sbd_state_t rstate_cvt(sbd_istate_t state); 3970Sstevel@tonic-gate 3980Sstevel@tonic-gate /* 3990Sstevel@tonic-gate * Autoconfiguration data structures 4000Sstevel@tonic-gate */ 4010Sstevel@tonic-gate 4020Sstevel@tonic-gate extern struct mod_ops mod_miscops; 4030Sstevel@tonic-gate 4040Sstevel@tonic-gate static struct modlmisc modlmisc = { 4050Sstevel@tonic-gate &mod_miscops, 4060Sstevel@tonic-gate "System Board DR v%I%" 4070Sstevel@tonic-gate }; 4080Sstevel@tonic-gate 4090Sstevel@tonic-gate static struct modlinkage modlinkage = { 4100Sstevel@tonic-gate MODREV_1, 4110Sstevel@tonic-gate (void *)&modlmisc, 4120Sstevel@tonic-gate NULL 4130Sstevel@tonic-gate }; 4140Sstevel@tonic-gate 4150Sstevel@tonic-gate static int sbd_instances = 0; 4160Sstevel@tonic-gate 4170Sstevel@tonic-gate /* 4180Sstevel@tonic-gate * dr Global data elements 4190Sstevel@tonic-gate */ 4200Sstevel@tonic-gate sbd_global sbd_g; 4210Sstevel@tonic-gate 4220Sstevel@tonic-gate /* 4230Sstevel@tonic-gate * We want to be able to unload the module when we wish to do so, but we don't 4240Sstevel@tonic-gate * want anything else to unload it. Unloading cannot occur until 4250Sstevel@tonic-gate * sbd_teardown_instance is called by an explicit IOCTL into the parent node. 4260Sstevel@tonic-gate * This support is for debugging purposes and should it be expected to work 4270Sstevel@tonic-gate * on the field, it should be enhanced: 4280Sstevel@tonic-gate * Currently, there is still a window where sbd_teardow_instance gets called, 4290Sstevel@tonic-gate * sbd_prevent_unloading now = 0, the driver doesn't get unloaded, and 4300Sstevel@tonic-gate * sbd_setup_instance gets called. This may cause a panic. 4310Sstevel@tonic-gate */ 4320Sstevel@tonic-gate int sbd_prevent_unloading = 1; 4330Sstevel@tonic-gate 4340Sstevel@tonic-gate /* 4350Sstevel@tonic-gate * Driver entry points. 4360Sstevel@tonic-gate */ 4370Sstevel@tonic-gate int 4380Sstevel@tonic-gate _init(void) 4390Sstevel@tonic-gate { 4400Sstevel@tonic-gate int err; 4410Sstevel@tonic-gate 4420Sstevel@tonic-gate /* 4430Sstevel@tonic-gate * If you need to support multiple nodes (instances), then 4440Sstevel@tonic-gate * whatever the maximum number of supported nodes is would 4450Sstevel@tonic-gate * need to passed as the third parameter to ddi_soft_state_init(). 4460Sstevel@tonic-gate * Alternative would be to dynamically fini and re-init the 4470Sstevel@tonic-gate * soft state structure each time a node is attached. 4480Sstevel@tonic-gate */ 4490Sstevel@tonic-gate err = ddi_soft_state_init((void **)&sbd_g.softsp, 4500Sstevel@tonic-gate sizeof (sbd_softstate_t), SBD_MAX_INSTANCES); 4510Sstevel@tonic-gate if (err) 4520Sstevel@tonic-gate return (err); 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate if ((err = mod_install(&modlinkage)) != 0) { 4550Sstevel@tonic-gate ddi_soft_state_fini((void **)&sbd_g.softsp); 4560Sstevel@tonic-gate return (err); 4570Sstevel@tonic-gate } 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate /* Get the array of names from platform helper routine */ 4600Sstevel@tonic-gate sbd_devattr = sbdp_get_devattr(); 4610Sstevel@tonic-gate 4620Sstevel@tonic-gate return (err); 4630Sstevel@tonic-gate } 4640Sstevel@tonic-gate 4650Sstevel@tonic-gate int 4660Sstevel@tonic-gate _fini(void) 4670Sstevel@tonic-gate { 4680Sstevel@tonic-gate int err; 4690Sstevel@tonic-gate 4700Sstevel@tonic-gate if (sbd_prevent_unloading) 4710Sstevel@tonic-gate return (DDI_FAILURE); 4720Sstevel@tonic-gate 4730Sstevel@tonic-gate ASSERT(sbd_instances == 0); 4740Sstevel@tonic-gate 4750Sstevel@tonic-gate if ((err = mod_remove(&modlinkage)) != 0) 4760Sstevel@tonic-gate return (err); 4770Sstevel@tonic-gate 4780Sstevel@tonic-gate ddi_soft_state_fini((void **)&sbd_g.softsp); 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate return (0); 4810Sstevel@tonic-gate } 4820Sstevel@tonic-gate 4830Sstevel@tonic-gate int 4840Sstevel@tonic-gate _info(struct modinfo *modinfop) 4850Sstevel@tonic-gate { 4860Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 4870Sstevel@tonic-gate } 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate int 4900Sstevel@tonic-gate sbd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, char *event) 4910Sstevel@tonic-gate { 4920Sstevel@tonic-gate int rv = 0, instance; 4930Sstevel@tonic-gate sbd_handle_t *hp; 4940Sstevel@tonic-gate sbd_softstate_t *softsp; 4950Sstevel@tonic-gate sbd_init_arg_t init_arg; 4960Sstevel@tonic-gate static fn_t f = "sbd_ioctl"; 4970Sstevel@tonic-gate int dr_avail; 4980Sstevel@tonic-gate 499*930Smathue PR_BYP("sbd_ioctl cmd=%x, arg=%lx\n", cmd, arg); 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate /* Note: this must also be changed in tandem with sbd_ioctl.h */ 5020Sstevel@tonic-gate switch (cmd) { 5030Sstevel@tonic-gate case SBD_CMD_ASSIGN: 5040Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 5050Sstevel@tonic-gate case SBD_CMD_POWERON: 5060Sstevel@tonic-gate case SBD_CMD_POWEROFF: 5070Sstevel@tonic-gate case SBD_CMD_TEST: 5080Sstevel@tonic-gate case SBD_CMD_CONNECT: 5090Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 5100Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 5110Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 5120Sstevel@tonic-gate case SBD_CMD_STATUS: 5130Sstevel@tonic-gate case SBD_CMD_GETNCM: 5140Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 5150Sstevel@tonic-gate break; 5160Sstevel@tonic-gate default: 5170Sstevel@tonic-gate return (ENOTTY); 5180Sstevel@tonic-gate } 5190Sstevel@tonic-gate 5200Sstevel@tonic-gate instance = SBD_GET_MINOR2INST(getminor(dev)); 5210Sstevel@tonic-gate if ((softsp = (sbd_softstate_t *)GET_SOFTC(instance)) == NULL) { 5220Sstevel@tonic-gate cmn_err(CE_WARN, 5230Sstevel@tonic-gate "sbd:%s:%d: module not yet attached", 5240Sstevel@tonic-gate f, instance); 5250Sstevel@tonic-gate return (ENXIO); 5260Sstevel@tonic-gate } 5270Sstevel@tonic-gate 5280Sstevel@tonic-gate init_arg.dev = dev; 5290Sstevel@tonic-gate init_arg.cmd = cmd; 5300Sstevel@tonic-gate init_arg.mode = mode; 5310Sstevel@tonic-gate init_arg.ioargp = (sbd_ioctl_arg_t *)arg; 5320Sstevel@tonic-gate 5330Sstevel@tonic-gate hp = sbd_get_handle(dev, softsp, arg, &init_arg); 5340Sstevel@tonic-gate /* Check to see if we support dr */ 5350Sstevel@tonic-gate dr_avail = sbdp_dr_avail(); 5360Sstevel@tonic-gate if (dr_avail != 1) { 5370Sstevel@tonic-gate switch (hp->h_cmd) { 5380Sstevel@tonic-gate case SBD_CMD_STATUS: 5390Sstevel@tonic-gate case SBD_CMD_GETNCM: 5400Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 5410Sstevel@tonic-gate break; 5420Sstevel@tonic-gate default: 5430Sstevel@tonic-gate sbd_release_handle(hp); 5440Sstevel@tonic-gate return (ENOTSUP); 5450Sstevel@tonic-gate } 5460Sstevel@tonic-gate } 5470Sstevel@tonic-gate 5480Sstevel@tonic-gate switch (hp->h_cmd) { 5490Sstevel@tonic-gate case SBD_CMD_STATUS: 5500Sstevel@tonic-gate case SBD_CMD_GETNCM: 5510Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 5520Sstevel@tonic-gate /* no locks needed for these commands */ 5530Sstevel@tonic-gate break; 5540Sstevel@tonic-gate 5550Sstevel@tonic-gate default: 5560Sstevel@tonic-gate rw_enter(&sbd_grwlock, RW_WRITER); 5570Sstevel@tonic-gate mutex_enter(&SBDH2BD(hp->h_sbd)->sb_mutex); 5580Sstevel@tonic-gate 5590Sstevel@tonic-gate /* 5600Sstevel@tonic-gate * If we're dealing with memory at all, then we have 5610Sstevel@tonic-gate * to keep the "exclusive" global lock held. This is 5620Sstevel@tonic-gate * necessary since we will probably need to look at 5630Sstevel@tonic-gate * multiple board structs. Otherwise, we only have 5640Sstevel@tonic-gate * to deal with the board in question and so can drop 5650Sstevel@tonic-gate * the global lock to "shared". 5660Sstevel@tonic-gate */ 5670Sstevel@tonic-gate /* 5680Sstevel@tonic-gate * XXX This is incorrect. The sh_devset has not 5690Sstevel@tonic-gate * been set at this point - it is 0. 5700Sstevel@tonic-gate */ 5710Sstevel@tonic-gate rv = DEVSET_IN_SET(HD2MACHHD(hp)->sh_devset, 5720Sstevel@tonic-gate SBD_COMP_MEM, DEVSET_ANYUNIT); 5730Sstevel@tonic-gate if (rv == 0) 5740Sstevel@tonic-gate rw_downgrade(&sbd_grwlock); 5750Sstevel@tonic-gate break; 5760Sstevel@tonic-gate } 5770Sstevel@tonic-gate 5780Sstevel@tonic-gate /* 5790Sstevel@tonic-gate * Before any operations happen, reset the event flag 5800Sstevel@tonic-gate */ 5810Sstevel@tonic-gate send_event = 0; 5820Sstevel@tonic-gate 5830Sstevel@tonic-gate if (sbd_pre_op(hp) == 0) { 5840Sstevel@tonic-gate sbd_exec_op(hp); 5850Sstevel@tonic-gate sbd_post_op(hp); 5860Sstevel@tonic-gate } 5870Sstevel@tonic-gate 5880Sstevel@tonic-gate rv = SBD_GET_ERRNO(SBD_HD2ERR(hp)); 5890Sstevel@tonic-gate *event = send_event; 5900Sstevel@tonic-gate 5910Sstevel@tonic-gate /* undo locking, if any, done before sbd_pre_op */ 5920Sstevel@tonic-gate switch (hp->h_cmd) { 5930Sstevel@tonic-gate case SBD_CMD_STATUS: 5940Sstevel@tonic-gate case SBD_CMD_GETNCM: 5950Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 5960Sstevel@tonic-gate break; 5970Sstevel@tonic-gate default: 5980Sstevel@tonic-gate mutex_exit(&SBDH2BD(hp->h_sbd)->sb_mutex); 5990Sstevel@tonic-gate rw_exit(&sbd_grwlock); 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate 6020Sstevel@tonic-gate sbd_release_handle(hp); 6030Sstevel@tonic-gate 6040Sstevel@tonic-gate return (rv); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate int 6080Sstevel@tonic-gate sbd_setup_instance(int instance, dev_info_t *root, int max_boards, int wnode, 6090Sstevel@tonic-gate caddr_t sbdp_arg) 6100Sstevel@tonic-gate { 6110Sstevel@tonic-gate int b; 6120Sstevel@tonic-gate sbd_softstate_t *softsp; 6130Sstevel@tonic-gate sbd_board_t *sbd_boardlist; 6140Sstevel@tonic-gate static fn_t f = "sbd_setup_instance"; 6150Sstevel@tonic-gate 6160Sstevel@tonic-gate sbd_instances++; 6170Sstevel@tonic-gate 6180Sstevel@tonic-gate if (sbdp_setup_instance(sbdp_arg) != DDI_SUCCESS) { 6190Sstevel@tonic-gate sbd_instances--; 6200Sstevel@tonic-gate return (DDI_FAILURE); 6210Sstevel@tonic-gate } 6220Sstevel@tonic-gate 6230Sstevel@tonic-gate if (ALLOC_SOFTC(instance) != DDI_SUCCESS) { 6240Sstevel@tonic-gate cmn_err(CE_WARN, 6250Sstevel@tonic-gate "sbd:%s:%d: failed to alloc soft-state", 6260Sstevel@tonic-gate f, instance); 6270Sstevel@tonic-gate sbdp_teardown_instance(sbdp_arg); 6280Sstevel@tonic-gate sbd_instances--; 6290Sstevel@tonic-gate return (DDI_FAILURE); 6300Sstevel@tonic-gate } 6310Sstevel@tonic-gate 6320Sstevel@tonic-gate softsp = (sbd_softstate_t *)GET_SOFTC(instance); 6330Sstevel@tonic-gate 6340Sstevel@tonic-gate if (softsp == NULL) { 6350Sstevel@tonic-gate cmn_err(CE_WARN, 6360Sstevel@tonic-gate "sbd:%s:%d: failed to get soft-state instance", 6370Sstevel@tonic-gate f, instance); 6380Sstevel@tonic-gate goto exit; 6390Sstevel@tonic-gate } 6400Sstevel@tonic-gate 6410Sstevel@tonic-gate sbd_boardlist = GETSTRUCT(sbd_board_t, max_boards); 6420Sstevel@tonic-gate if (sbd_boardlist == NULL) { 6430Sstevel@tonic-gate cmn_err(CE_WARN, 6440Sstevel@tonic-gate "sbd:%s: failed to alloc board list %d", 6450Sstevel@tonic-gate f, instance); 6460Sstevel@tonic-gate goto exit; 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate 6490Sstevel@tonic-gate 6500Sstevel@tonic-gate softsp->sbd_boardlist = (void *)sbd_boardlist; 6510Sstevel@tonic-gate softsp->max_boards = max_boards; 6520Sstevel@tonic-gate softsp->wnode = wnode; 6530Sstevel@tonic-gate 6540Sstevel@tonic-gate 6550Sstevel@tonic-gate for (b = 0; b < max_boards; b++) { 6560Sstevel@tonic-gate sbd_board_init(sbd_boardlist++, softsp, b, root, wnode); 6570Sstevel@tonic-gate } 6580Sstevel@tonic-gate 6590Sstevel@tonic-gate 6600Sstevel@tonic-gate return (DDI_SUCCESS); 6610Sstevel@tonic-gate exit: 6620Sstevel@tonic-gate (void) sbdp_teardown_instance(sbdp_arg); 6630Sstevel@tonic-gate FREE_SOFTC(instance); 6640Sstevel@tonic-gate sbd_instances--; 6650Sstevel@tonic-gate return (DDI_FAILURE); 6660Sstevel@tonic-gate } 6670Sstevel@tonic-gate 6680Sstevel@tonic-gate int 6690Sstevel@tonic-gate sbd_teardown_instance(int instance, caddr_t sbdp_arg) 6700Sstevel@tonic-gate { 6710Sstevel@tonic-gate sbd_softstate_t *softsp; 6720Sstevel@tonic-gate 6730Sstevel@tonic-gate if (sbdp_teardown_instance(sbdp_arg) != DDI_SUCCESS) 6740Sstevel@tonic-gate return (DDI_FAILURE); 6750Sstevel@tonic-gate 6760Sstevel@tonic-gate softsp = (sbd_softstate_t *)GET_SOFTC(instance); 6770Sstevel@tonic-gate if (softsp == NULL) { 6780Sstevel@tonic-gate return (DDI_FAILURE); 6790Sstevel@tonic-gate } 6800Sstevel@tonic-gate 6810Sstevel@tonic-gate (void) sbd_dealloc_instance((sbd_board_t *)softsp->sbd_boardlist, 6820Sstevel@tonic-gate softsp->max_boards); 6830Sstevel@tonic-gate 6840Sstevel@tonic-gate FREE_SOFTC(instance); 6850Sstevel@tonic-gate sbd_instances--; 6860Sstevel@tonic-gate sbd_prevent_unloading = 0; 6870Sstevel@tonic-gate 6880Sstevel@tonic-gate return (DDI_SUCCESS); 6890Sstevel@tonic-gate } 6900Sstevel@tonic-gate 6910Sstevel@tonic-gate static void 6920Sstevel@tonic-gate sbd_exec_op(sbd_handle_t *hp) 6930Sstevel@tonic-gate { 6940Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 6950Sstevel@tonic-gate static fn_t f = "sbd_exec_op"; 6960Sstevel@tonic-gate 6970Sstevel@tonic-gate switch (hp->h_cmd) { 6980Sstevel@tonic-gate int dev_canceled; 6990Sstevel@tonic-gate 7000Sstevel@tonic-gate case SBD_CMD_CONNECT: 7010Sstevel@tonic-gate if (sbd_probe_board(hp)) 7020Sstevel@tonic-gate break; 7030Sstevel@tonic-gate 7040Sstevel@tonic-gate sbd_connect(hp); 7050Sstevel@tonic-gate break; 7060Sstevel@tonic-gate 7070Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 7080Sstevel@tonic-gate sbd_dev_configure(hp); 7090Sstevel@tonic-gate break; 7100Sstevel@tonic-gate 7110Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 7120Sstevel@tonic-gate if (((dev_canceled = sbd_dev_release(hp)) == 0) && 7130Sstevel@tonic-gate (SBD_GET_ERRNO(SBD_HD2ERR(hp)) == 0 && 7140Sstevel@tonic-gate SBD_GET_ERR(SBD_HD2ERR(hp)) == 0)) 7150Sstevel@tonic-gate dev_canceled = sbd_dev_unconfigure(hp); 7160Sstevel@tonic-gate 7170Sstevel@tonic-gate if (dev_canceled) 7180Sstevel@tonic-gate sbd_cancel(hp); 7190Sstevel@tonic-gate break; 7200Sstevel@tonic-gate 7210Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 7220Sstevel@tonic-gate mutex_enter(&sbp->sb_slock); 7230Sstevel@tonic-gate if (sbd_disconnect(hp) == 0) 7240Sstevel@tonic-gate (void) sbd_deprobe_board(hp); 7250Sstevel@tonic-gate mutex_exit(&sbp->sb_slock); 7260Sstevel@tonic-gate break; 7270Sstevel@tonic-gate 7280Sstevel@tonic-gate case SBD_CMD_STATUS: 7290Sstevel@tonic-gate sbd_status(hp); 7300Sstevel@tonic-gate break; 7310Sstevel@tonic-gate 7320Sstevel@tonic-gate case SBD_CMD_GETNCM: 7330Sstevel@tonic-gate sbd_get_ncm(hp); 7340Sstevel@tonic-gate break; 7350Sstevel@tonic-gate 7360Sstevel@tonic-gate case SBD_CMD_ASSIGN: 7370Sstevel@tonic-gate sbd_assign_board(hp); 7380Sstevel@tonic-gate break; 7390Sstevel@tonic-gate 7400Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 7410Sstevel@tonic-gate sbd_unassign_board(hp); 7420Sstevel@tonic-gate break; 7430Sstevel@tonic-gate 7440Sstevel@tonic-gate case SBD_CMD_POWEROFF: 7450Sstevel@tonic-gate sbd_poweroff_board(hp); 7460Sstevel@tonic-gate break; 7470Sstevel@tonic-gate 7480Sstevel@tonic-gate case SBD_CMD_POWERON: 7490Sstevel@tonic-gate sbd_poweron_board(hp); 7500Sstevel@tonic-gate break; 7510Sstevel@tonic-gate 7520Sstevel@tonic-gate case SBD_CMD_TEST: 7530Sstevel@tonic-gate sbd_test_board(hp); 7540Sstevel@tonic-gate break; 7550Sstevel@tonic-gate 7560Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 7570Sstevel@tonic-gate { 7580Sstevel@tonic-gate int rv; 7590Sstevel@tonic-gate sbdp_handle_t *hdp; 7600Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 7610Sstevel@tonic-gate sbdp_ioctl_arg_t ia, *iap; 7620Sstevel@tonic-gate 7630Sstevel@tonic-gate iap = &ia; 7640Sstevel@tonic-gate 7650Sstevel@tonic-gate iap->h_dev = hp->h_dev; 7660Sstevel@tonic-gate iap->h_cmd = hp->h_cmd; 7670Sstevel@tonic-gate iap->h_iap = (intptr_t)hp->h_iap; 7680Sstevel@tonic-gate iap->h_mode = hp->h_mode; 7690Sstevel@tonic-gate 7700Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 7710Sstevel@tonic-gate rv = sbdp_ioctl(hdp, iap); 7720Sstevel@tonic-gate if (rv != 0) { 7730Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 7740Sstevel@tonic-gate ep->e_errno = rv; 7750Sstevel@tonic-gate } 7760Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 7770Sstevel@tonic-gate break; 7780Sstevel@tonic-gate } 7790Sstevel@tonic-gate 7800Sstevel@tonic-gate default: 7810Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), ENOTTY); 7820Sstevel@tonic-gate cmn_err(CE_WARN, 7830Sstevel@tonic-gate "sbd:%s: unknown command (%d)", 7840Sstevel@tonic-gate f, hp->h_cmd); 7850Sstevel@tonic-gate break; 7860Sstevel@tonic-gate 7870Sstevel@tonic-gate } 7880Sstevel@tonic-gate 7890Sstevel@tonic-gate if (SBD_GET_ERR(SBD_HD2ERR(hp))) 7900Sstevel@tonic-gate PR_BYP("XXX e_code=%d", SBD_GET_ERR(SBD_HD2ERR(hp))); 7910Sstevel@tonic-gate if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) 7920Sstevel@tonic-gate PR_BYP("XXX errno=%d", SBD_GET_ERRNO(SBD_HD2ERR(hp))); 7930Sstevel@tonic-gate } 7940Sstevel@tonic-gate 7950Sstevel@tonic-gate sbd_comp_type_t 7960Sstevel@tonic-gate sbd_get_devtype(sbd_handle_t *hp, dev_info_t *dip) 7970Sstevel@tonic-gate { 7980Sstevel@tonic-gate sbd_board_t *sbp = hp ? SBDH2BD(hp->h_sbd) : NULL; 7990Sstevel@tonic-gate sbd_istate_t bstate; 8000Sstevel@tonic-gate dev_info_t **devlist; 8010Sstevel@tonic-gate int i; 8020Sstevel@tonic-gate char device[OBP_MAXDRVNAME]; 8030Sstevel@tonic-gate int devicelen; 8040Sstevel@tonic-gate 8050Sstevel@tonic-gate devicelen = sizeof (device); 8060Sstevel@tonic-gate 8070Sstevel@tonic-gate bstate = sbp ? SBD_BOARD_STATE(sbp) : SBD_STATE_EMPTY; 8080Sstevel@tonic-gate /* 8090Sstevel@tonic-gate * if the board's connected or configured, search the 8100Sstevel@tonic-gate * devlists. Otherwise check the device tree 8110Sstevel@tonic-gate */ 8120Sstevel@tonic-gate switch (bstate) { 8130Sstevel@tonic-gate 8140Sstevel@tonic-gate case SBD_STATE_CONNECTED: 8150Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 8160Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: 8170Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 8180Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)]; 8190Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 8200Sstevel@tonic-gate if (devlist[i] == dip) 8210Sstevel@tonic-gate return (SBD_COMP_MEM); 8220Sstevel@tonic-gate 8230Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_CPU)]; 8240Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) 8250Sstevel@tonic-gate if (devlist[i] == dip) 8260Sstevel@tonic-gate return (SBD_COMP_CPU); 8270Sstevel@tonic-gate 8280Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_IO)]; 8290Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 8300Sstevel@tonic-gate if (devlist[i] == dip) 8310Sstevel@tonic-gate return (SBD_COMP_IO); 8320Sstevel@tonic-gate /*FALLTHROUGH*/ 8330Sstevel@tonic-gate 8340Sstevel@tonic-gate default: 8350Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 8360Sstevel@tonic-gate OBP_DEVICETYPE, (caddr_t)device, &devicelen)) 8370Sstevel@tonic-gate break; 8380Sstevel@tonic-gate 8390Sstevel@tonic-gate for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 8400Sstevel@tonic-gate if (strcmp(device, SBD_OTYPE(i)) != 0) 8410Sstevel@tonic-gate continue; 8420Sstevel@tonic-gate return (SBD_COMP(i)); 8430Sstevel@tonic-gate } 8440Sstevel@tonic-gate 8450Sstevel@tonic-gate break; 8460Sstevel@tonic-gate } 8470Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 8480Sstevel@tonic-gate } 8490Sstevel@tonic-gate 8500Sstevel@tonic-gate static void 8510Sstevel@tonic-gate sbd_dev_configure(sbd_handle_t *hp) 8520Sstevel@tonic-gate { 8530Sstevel@tonic-gate int n, unit; 8540Sstevel@tonic-gate int32_t pass, devnum; 8550Sstevel@tonic-gate dev_info_t *dip; 8560Sstevel@tonic-gate sbd_devlist_t *devlist; 8570Sstevel@tonic-gate sbdp_handle_t *hdp; 8580Sstevel@tonic-gate sbd_comp_type_t nodetype; 8590Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 8600Sstevel@tonic-gate 8610Sstevel@tonic-gate pass = 1; 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 8640Sstevel@tonic-gate while ((devlist = sbd_get_attach_devlist(hp, &devnum, pass)) != NULL) { 8650Sstevel@tonic-gate int err; 8660Sstevel@tonic-gate 8670Sstevel@tonic-gate err = sbd_pre_attach_devlist(hp, devlist, devnum); 8680Sstevel@tonic-gate if (err < 0) { 8690Sstevel@tonic-gate break; 8700Sstevel@tonic-gate } else if (err > 0) { 8710Sstevel@tonic-gate pass++; 8720Sstevel@tonic-gate continue; 8730Sstevel@tonic-gate } 8740Sstevel@tonic-gate 8750Sstevel@tonic-gate for (n = 0; n < devnum; n++) { 8760Sstevel@tonic-gate sbderror_t *ep; 8770Sstevel@tonic-gate 8780Sstevel@tonic-gate ep = &devlist[n].dv_error; 8790Sstevel@tonic-gate SBD_SET_ERRNO(ep, 0); 8800Sstevel@tonic-gate SBD_SET_ERR(ep, 0); 8810Sstevel@tonic-gate dip = devlist[n].dv_dip; 8820Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 8830Sstevel@tonic-gate 8840Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 8850Sstevel@tonic-gate if (unit < 0) { 8860Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 8870Sstevel@tonic-gate break; 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate switch (nodetype) { 8910Sstevel@tonic-gate case SBD_COMP_MEM: 8920Sstevel@tonic-gate sbd_attach_mem(hp, ep); 8930Sstevel@tonic-gate if (SBD_GET_ERR(ep) == ESBD_CPUONLINE) { 8940Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, 8950Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 8960Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 8970Sstevel@tonic-gate return; 8980Sstevel@tonic-gate } 8990Sstevel@tonic-gate break; 9000Sstevel@tonic-gate 9010Sstevel@tonic-gate case SBD_COMP_CPU: 9020Sstevel@tonic-gate sbd_attach_cpu(hp, ep, dip, unit); 9030Sstevel@tonic-gate break; 9040Sstevel@tonic-gate 9050Sstevel@tonic-gate case SBD_COMP_IO: 9060Sstevel@tonic-gate sbd_attach_io(hp, ep, dip, unit); 9070Sstevel@tonic-gate break; 9080Sstevel@tonic-gate 9090Sstevel@tonic-gate default: 9100Sstevel@tonic-gate SBD_SET_ERRNO(ep, ENOTTY); 9110Sstevel@tonic-gate break; 9120Sstevel@tonic-gate } 9130Sstevel@tonic-gate 9140Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) 9150Sstevel@tonic-gate continue; 9160Sstevel@tonic-gate } 9170Sstevel@tonic-gate 9180Sstevel@tonic-gate err = sbd_post_attach_devlist(hp, devlist, devnum); 9190Sstevel@tonic-gate if (err < 0) 9200Sstevel@tonic-gate break; 9210Sstevel@tonic-gate 9220Sstevel@tonic-gate pass++; 9230Sstevel@tonic-gate } 9240Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 9250Sstevel@tonic-gate } 9260Sstevel@tonic-gate 9270Sstevel@tonic-gate static int 9280Sstevel@tonic-gate sbd_dev_release(sbd_handle_t *hp) 9290Sstevel@tonic-gate { 9300Sstevel@tonic-gate int n, unit; 9310Sstevel@tonic-gate int32_t pass, devnum; 9320Sstevel@tonic-gate dev_info_t *dip; 9330Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 9340Sstevel@tonic-gate sbdp_handle_t *hdp; 9350Sstevel@tonic-gate sbd_devlist_t *devlist; 9360Sstevel@tonic-gate sbd_comp_type_t nodetype; 9370Sstevel@tonic-gate int err = 0; 9380Sstevel@tonic-gate int dev_canceled; 9390Sstevel@tonic-gate 9400Sstevel@tonic-gate pass = 1; 9410Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 9420Sstevel@tonic-gate 9430Sstevel@tonic-gate sbp->sb_busy = 1; 9440Sstevel@tonic-gate while ((devlist = 9450Sstevel@tonic-gate sbd_get_release_devlist(hp, &devnum, pass)) != NULL) { 9460Sstevel@tonic-gate 9470Sstevel@tonic-gate err = sbd_pre_release_devlist(hp, devlist, devnum); 9480Sstevel@tonic-gate if (err < 0) { 9490Sstevel@tonic-gate dev_canceled = 1; 9500Sstevel@tonic-gate break; 9510Sstevel@tonic-gate } else if (err > 0) { 9520Sstevel@tonic-gate pass++; 9530Sstevel@tonic-gate continue; 9540Sstevel@tonic-gate } 9550Sstevel@tonic-gate 9560Sstevel@tonic-gate dev_canceled = 0; 9570Sstevel@tonic-gate for (n = 0; n < devnum; n++) { 9580Sstevel@tonic-gate dip = devlist[n].dv_dip; 9590Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 9600Sstevel@tonic-gate 9610Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 9620Sstevel@tonic-gate if (unit < 0) { 9630Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 9640Sstevel@tonic-gate break; 9650Sstevel@tonic-gate } 9660Sstevel@tonic-gate 9670Sstevel@tonic-gate if ((nodetype == SBD_COMP_MEM) && 9680Sstevel@tonic-gate sbd_release_mem(hp, dip, unit)) { 9690Sstevel@tonic-gate 9700Sstevel@tonic-gate dev_canceled++; 9710Sstevel@tonic-gate } 9720Sstevel@tonic-gate 9730Sstevel@tonic-gate sbd_release_done(hp, nodetype, dip); 9740Sstevel@tonic-gate } 9750Sstevel@tonic-gate 9760Sstevel@tonic-gate err = sbd_post_release_devlist(hp, devlist, devnum); 9770Sstevel@tonic-gate 9780Sstevel@tonic-gate if (err < 0) 9790Sstevel@tonic-gate break; 9800Sstevel@tonic-gate 9810Sstevel@tonic-gate if (dev_canceled) 9820Sstevel@tonic-gate break; 9830Sstevel@tonic-gate 9840Sstevel@tonic-gate pass++; 9850Sstevel@tonic-gate } 9860Sstevel@tonic-gate sbp->sb_busy = 0; 9870Sstevel@tonic-gate 9880Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 9890Sstevel@tonic-gate 9900Sstevel@tonic-gate if (dev_canceled) 9910Sstevel@tonic-gate return (dev_canceled); 9920Sstevel@tonic-gate 9930Sstevel@tonic-gate return (err); 9940Sstevel@tonic-gate } 9950Sstevel@tonic-gate 9960Sstevel@tonic-gate static int 9970Sstevel@tonic-gate sbd_dev_unconfigure(sbd_handle_t *hp) 9980Sstevel@tonic-gate { 9990Sstevel@tonic-gate int n, unit; 10000Sstevel@tonic-gate int32_t pass, devnum; 10010Sstevel@tonic-gate dev_info_t *dip; 10020Sstevel@tonic-gate sbd_devlist_t *devlist; 10030Sstevel@tonic-gate sbdp_handle_t *hdp; 10040Sstevel@tonic-gate sbd_comp_type_t nodetype; 10050Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 10060Sstevel@tonic-gate int dev_canceled = 0; 10070Sstevel@tonic-gate static fn_t f = "sbd_dev_unconfigure"; 10080Sstevel@tonic-gate 10090Sstevel@tonic-gate PR_ALL("%s...\n", f); 10100Sstevel@tonic-gate 10110Sstevel@tonic-gate pass = 1; 10120Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 10130Sstevel@tonic-gate 10140Sstevel@tonic-gate while ((devlist = sbd_get_detach_devlist(hp, &devnum, pass)) != NULL) { 10150Sstevel@tonic-gate int err, detach_err = 0; 10160Sstevel@tonic-gate 10170Sstevel@tonic-gate err = sbd_pre_detach_devlist(hp, devlist, devnum); 10180Sstevel@tonic-gate if (err) { 10190Sstevel@tonic-gate /* 10200Sstevel@tonic-gate * Only cancel the operation for memory in 10210Sstevel@tonic-gate * case of failure. 10220Sstevel@tonic-gate */ 10230Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 10240Sstevel@tonic-gate if (nodetype == SBD_COMP_MEM) 10250Sstevel@tonic-gate dev_canceled = 1; 10260Sstevel@tonic-gate (void) sbd_post_detach_devlist(hp, devlist, devnum); 10270Sstevel@tonic-gate break; 10280Sstevel@tonic-gate } 10290Sstevel@tonic-gate 10300Sstevel@tonic-gate for (n = 0; n < devnum; n++) { 10310Sstevel@tonic-gate sbderror_t *ep; 10320Sstevel@tonic-gate 10330Sstevel@tonic-gate ep = &devlist[n].dv_error; 10340Sstevel@tonic-gate SBD_SET_ERRNO(ep, 0); 10350Sstevel@tonic-gate SBD_SET_ERR(ep, 0); 10360Sstevel@tonic-gate dip = devlist[n].dv_dip; 10370Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 10380Sstevel@tonic-gate 10390Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 10400Sstevel@tonic-gate if (unit < 0) { 10410Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 10420Sstevel@tonic-gate break; 10430Sstevel@tonic-gate } 10440Sstevel@tonic-gate 10450Sstevel@tonic-gate switch (nodetype) { 10460Sstevel@tonic-gate case SBD_COMP_MEM: 10470Sstevel@tonic-gate dev_canceled = sbd_detach_mem(hp, ep, unit); 10480Sstevel@tonic-gate break; 10490Sstevel@tonic-gate 10500Sstevel@tonic-gate case SBD_COMP_CPU: 10510Sstevel@tonic-gate sbd_detach_cpu(hp, ep, dip, unit); 10520Sstevel@tonic-gate break; 10530Sstevel@tonic-gate 10540Sstevel@tonic-gate case SBD_COMP_IO: 10550Sstevel@tonic-gate sbd_detach_io(hp, ep, dip, unit); 10560Sstevel@tonic-gate break; 10570Sstevel@tonic-gate 10580Sstevel@tonic-gate default: 10590Sstevel@tonic-gate SBD_SET_ERRNO(ep, ENOTTY); 10600Sstevel@tonic-gate break; 10610Sstevel@tonic-gate } 10620Sstevel@tonic-gate 10630Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) { 10640Sstevel@tonic-gate detach_err = -1; 10650Sstevel@tonic-gate break; 10660Sstevel@tonic-gate } 10670Sstevel@tonic-gate 10680Sstevel@tonic-gate } 10690Sstevel@tonic-gate err = sbd_post_detach_devlist(hp, devlist, devnum); 10700Sstevel@tonic-gate if ((err < 0) || (detach_err < 0)) 10710Sstevel@tonic-gate break; 10720Sstevel@tonic-gate 10730Sstevel@tonic-gate pass++; 10740Sstevel@tonic-gate } 10750Sstevel@tonic-gate 10760Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 10770Sstevel@tonic-gate return (dev_canceled); 10780Sstevel@tonic-gate } 10790Sstevel@tonic-gate 10800Sstevel@tonic-gate int 10810Sstevel@tonic-gate sbd_errno2ecode(int error) 10820Sstevel@tonic-gate { 10830Sstevel@tonic-gate int rv; 10840Sstevel@tonic-gate 10850Sstevel@tonic-gate switch (error) { 10860Sstevel@tonic-gate case EBUSY: 10870Sstevel@tonic-gate rv = ESBD_BUSY; 10880Sstevel@tonic-gate break; 10890Sstevel@tonic-gate case EINVAL: 10900Sstevel@tonic-gate rv = ESBD_INVAL; 10910Sstevel@tonic-gate break; 10920Sstevel@tonic-gate case EALREADY: 10930Sstevel@tonic-gate rv = ESBD_ALREADY; 10940Sstevel@tonic-gate break; 10950Sstevel@tonic-gate case ENODEV: 10960Sstevel@tonic-gate rv = ESBD_NODEV; 10970Sstevel@tonic-gate break; 10980Sstevel@tonic-gate case ENOMEM: 10990Sstevel@tonic-gate rv = ESBD_NOMEM; 11000Sstevel@tonic-gate break; 11010Sstevel@tonic-gate default: 11020Sstevel@tonic-gate rv = ESBD_INVAL; 11030Sstevel@tonic-gate } 11040Sstevel@tonic-gate 11050Sstevel@tonic-gate return (rv); 11060Sstevel@tonic-gate } 11070Sstevel@tonic-gate 11080Sstevel@tonic-gate static void 11090Sstevel@tonic-gate sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) 11100Sstevel@tonic-gate { 11110Sstevel@tonic-gate int rv = 0; 11120Sstevel@tonic-gate processorid_t cpuid; 11130Sstevel@tonic-gate sbdp_handle_t *hdp; 11140Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 11150Sstevel@tonic-gate static fn_t f = "sbd_attach_cpu"; 11160Sstevel@tonic-gate char *pathname; 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 11190Sstevel@tonic-gate 11200Sstevel@tonic-gate ASSERT(dip); 11210Sstevel@tonic-gate 11220Sstevel@tonic-gate /* 11230Sstevel@tonic-gate * With the introduction of CMP devices, the CPU nodes 11240Sstevel@tonic-gate * are no longer directly under the top node. Since 11250Sstevel@tonic-gate * there is no plan to support CPU attach in the near 11260Sstevel@tonic-gate * future, a branch configure operation is not required. 11270Sstevel@tonic-gate */ 11280Sstevel@tonic-gate 11290Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 11300Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 11310Sstevel@tonic-gate if (cpuid < 0) { 11320Sstevel@tonic-gate rv = -1; 11330Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 11340Sstevel@tonic-gate } else if ((rv = cpu_configure(cpuid)) != 0) { 11350Sstevel@tonic-gate cmn_err(CE_WARN, 11360Sstevel@tonic-gate "sbd:%s: cpu_configure for cpuid %d failed", 11370Sstevel@tonic-gate f, cpuid); 11380Sstevel@tonic-gate SBD_SET_ERR(ep, sbd_errno2ecode(rv)); 11390Sstevel@tonic-gate } 11400Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 11410Sstevel@tonic-gate 11420Sstevel@tonic-gate if (rv == 0) { 11430Sstevel@tonic-gate ASSERT(sbp->sb_cpupath[unit] != NULL); 11440Sstevel@tonic-gate pathname = sbp->sb_cpupath[unit]; 11450Sstevel@tonic-gate (void) ddi_pathname(dip, pathname); 11460Sstevel@tonic-gate } 11470Sstevel@tonic-gate } 11480Sstevel@tonic-gate 11490Sstevel@tonic-gate /* 11500Sstevel@tonic-gate * translate errno 11510Sstevel@tonic-gate */ 11520Sstevel@tonic-gate void 11530Sstevel@tonic-gate sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip) 11540Sstevel@tonic-gate { 11550Sstevel@tonic-gate ASSERT(err != 0); 11560Sstevel@tonic-gate 11570Sstevel@tonic-gate switch (err) { 11580Sstevel@tonic-gate case ENOMEM: 11590Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_NOMEM); 11600Sstevel@tonic-gate break; 11610Sstevel@tonic-gate 11620Sstevel@tonic-gate case EBUSY: 11630Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_BUSY); 11640Sstevel@tonic-gate break; 11650Sstevel@tonic-gate 11660Sstevel@tonic-gate case EIO: 11670Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_IO); 11680Sstevel@tonic-gate break; 11690Sstevel@tonic-gate 11700Sstevel@tonic-gate case ENXIO: 11710Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_NODEV); 11720Sstevel@tonic-gate break; 11730Sstevel@tonic-gate 11740Sstevel@tonic-gate case EINVAL: 11750Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INVAL); 11760Sstevel@tonic-gate break; 11770Sstevel@tonic-gate 11780Sstevel@tonic-gate case EFAULT: 11790Sstevel@tonic-gate default: 11800Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_FAULT); 11810Sstevel@tonic-gate break; 11820Sstevel@tonic-gate } 11830Sstevel@tonic-gate 11840Sstevel@tonic-gate (void) ddi_pathname(dip, SBD_GET_ERRSTR(ep)); 11850Sstevel@tonic-gate } 11860Sstevel@tonic-gate 11870Sstevel@tonic-gate static void 11880Sstevel@tonic-gate sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) 11890Sstevel@tonic-gate { 11900Sstevel@tonic-gate processorid_t cpuid; 11910Sstevel@tonic-gate int rv; 11920Sstevel@tonic-gate sbdp_handle_t *hdp; 11930Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 11940Sstevel@tonic-gate sbd_error_t *spe; 11950Sstevel@tonic-gate static fn_t f = "sbd_detach_cpu"; 11960Sstevel@tonic-gate 11970Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 11980Sstevel@tonic-gate 11990Sstevel@tonic-gate ASSERT(dip); 12000Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 12010Sstevel@tonic-gate spe = hdp->h_err; 12020Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 12030Sstevel@tonic-gate if (cpuid < 0) { 12040Sstevel@tonic-gate SBD_GET_PERR(spe, ep); 12050Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 12060Sstevel@tonic-gate return; 12070Sstevel@tonic-gate } 12080Sstevel@tonic-gate 12090Sstevel@tonic-gate if ((rv = cpu_unconfigure(cpuid)) != 0) { 12100Sstevel@tonic-gate SBD_SET_ERR(ep, sbd_errno2ecode(rv)); 12110Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]); 12120Sstevel@tonic-gate cmn_err(CE_WARN, 12130Sstevel@tonic-gate "sbd:%s: cpu_unconfigure for cpu %d failed", 12140Sstevel@tonic-gate f, cpuid); 12150Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 12160Sstevel@tonic-gate return; 12170Sstevel@tonic-gate } 12180Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 12190Sstevel@tonic-gate 12200Sstevel@tonic-gate /* 12210Sstevel@tonic-gate * Since CPU nodes are no longer configured in CPU 12220Sstevel@tonic-gate * attach, the corresponding branch unconfigure 12230Sstevel@tonic-gate * operation that would be performed here is also 12240Sstevel@tonic-gate * no longer required. 12250Sstevel@tonic-gate */ 12260Sstevel@tonic-gate } 12270Sstevel@tonic-gate 12280Sstevel@tonic-gate 12290Sstevel@tonic-gate int 12300Sstevel@tonic-gate sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit) 12310Sstevel@tonic-gate { 12320Sstevel@tonic-gate sbd_mem_unit_t *mp; 12330Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 12340Sstevel@tonic-gate int i, rv; 12350Sstevel@tonic-gate static fn_t f = "sbd_detach_mem"; 12360Sstevel@tonic-gate 12370Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 12380Sstevel@tonic-gate 12390Sstevel@tonic-gate if (sbd_detach_memory(hp, ep, mp, unit)) { 12400Sstevel@tonic-gate cmn_err(CE_WARN, "%s: detach fail", f); 12410Sstevel@tonic-gate return (-1); 12420Sstevel@tonic-gate } 12430Sstevel@tonic-gate 12440Sstevel@tonic-gate /* 12450Sstevel@tonic-gate * Now detach mem devinfo nodes with status lock held. 12460Sstevel@tonic-gate */ 12470Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 12480Sstevel@tonic-gate dev_info_t *fdip = NULL; 12490Sstevel@tonic-gate 12500Sstevel@tonic-gate if (mp->sbm_dip[i] == NULL) 12510Sstevel@tonic-gate continue; 12520Sstevel@tonic-gate ASSERT(e_ddi_branch_held(mp->sbm_dip[i])); 12530Sstevel@tonic-gate mutex_enter(&sbp->sb_slock); 12540Sstevel@tonic-gate rv = e_ddi_branch_unconfigure(mp->sbm_dip[i], &fdip, 12550Sstevel@tonic-gate DEVI_BRANCH_EVENT); 12560Sstevel@tonic-gate mutex_exit(&sbp->sb_slock); 12570Sstevel@tonic-gate if (rv) { 12580Sstevel@tonic-gate /* 12590Sstevel@tonic-gate * If non-NULL, fdip is returned held and must be 12600Sstevel@tonic-gate * released. 12610Sstevel@tonic-gate */ 12620Sstevel@tonic-gate if (fdip != NULL) { 12630Sstevel@tonic-gate sbd_errno_decode(rv, ep, fdip); 12640Sstevel@tonic-gate ddi_release_devi(fdip); 12650Sstevel@tonic-gate } else { 12660Sstevel@tonic-gate sbd_errno_decode(rv, ep, mp->sbm_dip[i]); 12670Sstevel@tonic-gate } 12680Sstevel@tonic-gate } 12690Sstevel@tonic-gate } 12700Sstevel@tonic-gate 12710Sstevel@tonic-gate return (0); 12720Sstevel@tonic-gate } 12730Sstevel@tonic-gate 12740Sstevel@tonic-gate /* start beginning of sbd.c */ 12750Sstevel@tonic-gate 12760Sstevel@tonic-gate /* 12770Sstevel@tonic-gate * MDR memory support - somewhat disabled for now. 12780Sstevel@tonic-gate * UNSAFE unsafe driver code - I don't think we want this. 12790Sstevel@tonic-gate * need to check. 12800Sstevel@tonic-gate * DEVNODE This driver creates attachment points for individual 12810Sstevel@tonic-gate * components as well as boards. We only need board 12820Sstevel@tonic-gate * support. 12830Sstevel@tonic-gate * DEV2DEVSET Put only present devices in devset. 12840Sstevel@tonic-gate */ 12850Sstevel@tonic-gate 12860Sstevel@tonic-gate 12870Sstevel@tonic-gate static sbd_state_t 12880Sstevel@tonic-gate rstate_cvt(sbd_istate_t state) 12890Sstevel@tonic-gate { 12900Sstevel@tonic-gate sbd_state_t cs; 12910Sstevel@tonic-gate 12920Sstevel@tonic-gate switch (state) { 12930Sstevel@tonic-gate case SBD_STATE_EMPTY: 12940Sstevel@tonic-gate cs = SBD_STAT_EMPTY; 12950Sstevel@tonic-gate break; 12960Sstevel@tonic-gate case SBD_STATE_OCCUPIED: 12970Sstevel@tonic-gate case SBD_STATE_FATAL: 12980Sstevel@tonic-gate cs = SBD_STAT_DISCONNECTED; 12990Sstevel@tonic-gate break; 13000Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 13010Sstevel@tonic-gate case SBD_STATE_CONNECTED: 13020Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 13030Sstevel@tonic-gate case SBD_STATE_PARTIAL: 13040Sstevel@tonic-gate case SBD_STATE_RELEASE: 13050Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: 13060Sstevel@tonic-gate cs = SBD_STAT_CONNECTED; 13070Sstevel@tonic-gate break; 13080Sstevel@tonic-gate default: 13090Sstevel@tonic-gate cs = SBD_STAT_NONE; 13100Sstevel@tonic-gate break; 13110Sstevel@tonic-gate } 13120Sstevel@tonic-gate 13130Sstevel@tonic-gate return (cs); 13140Sstevel@tonic-gate } 13150Sstevel@tonic-gate 13160Sstevel@tonic-gate 13170Sstevel@tonic-gate sbd_state_t 13180Sstevel@tonic-gate ostate_cvt(sbd_istate_t state) 13190Sstevel@tonic-gate { 13200Sstevel@tonic-gate sbd_state_t cs; 13210Sstevel@tonic-gate 13220Sstevel@tonic-gate switch (state) { 13230Sstevel@tonic-gate case SBD_STATE_EMPTY: 13240Sstevel@tonic-gate case SBD_STATE_OCCUPIED: 13250Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 13260Sstevel@tonic-gate case SBD_STATE_CONNECTED: 13270Sstevel@tonic-gate case SBD_STATE_FATAL: 13280Sstevel@tonic-gate cs = SBD_STAT_UNCONFIGURED; 13290Sstevel@tonic-gate break; 13300Sstevel@tonic-gate case SBD_STATE_PARTIAL: 13310Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 13320Sstevel@tonic-gate case SBD_STATE_RELEASE: 13330Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: 13340Sstevel@tonic-gate cs = SBD_STAT_CONFIGURED; 13350Sstevel@tonic-gate break; 13360Sstevel@tonic-gate default: 13370Sstevel@tonic-gate cs = SBD_STAT_NONE; 13380Sstevel@tonic-gate break; 13390Sstevel@tonic-gate } 13400Sstevel@tonic-gate 13410Sstevel@tonic-gate return (cs); 13420Sstevel@tonic-gate } 13430Sstevel@tonic-gate 13440Sstevel@tonic-gate int 13450Sstevel@tonic-gate sbd_dealloc_instance(sbd_board_t *sbp, int max_boards) 13460Sstevel@tonic-gate { 13470Sstevel@tonic-gate int b; 13480Sstevel@tonic-gate sbd_board_t *list = sbp; 13490Sstevel@tonic-gate static fn_t f = "sbd_dealloc_instance"; 13500Sstevel@tonic-gate 13510Sstevel@tonic-gate PR_ALL("%s...\n", f); 13520Sstevel@tonic-gate 13530Sstevel@tonic-gate if (sbp == NULL) { 13540Sstevel@tonic-gate return (-1); 13550Sstevel@tonic-gate } 13560Sstevel@tonic-gate 13570Sstevel@tonic-gate for (b = 0; b < max_boards; b++) { 13580Sstevel@tonic-gate sbd_board_destroy(sbp++); 13590Sstevel@tonic-gate } 13600Sstevel@tonic-gate 13610Sstevel@tonic-gate FREESTRUCT(list, sbd_board_t, max_boards); 13620Sstevel@tonic-gate 13630Sstevel@tonic-gate return (0); 13640Sstevel@tonic-gate } 13650Sstevel@tonic-gate 13660Sstevel@tonic-gate static sbd_devset_t 13670Sstevel@tonic-gate sbd_dev2devset(sbd_comp_id_t *cid) 13680Sstevel@tonic-gate { 13690Sstevel@tonic-gate static fn_t f = "sbd_dev2devset"; 13700Sstevel@tonic-gate 13710Sstevel@tonic-gate sbd_devset_t devset; 13720Sstevel@tonic-gate int unit = cid->c_unit; 13730Sstevel@tonic-gate 13740Sstevel@tonic-gate switch (cid->c_type) { 13750Sstevel@tonic-gate case SBD_COMP_NONE: 13760Sstevel@tonic-gate devset = DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT); 13770Sstevel@tonic-gate devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT); 13780Sstevel@tonic-gate devset |= DEVSET(SBD_COMP_IO, DEVSET_ANYUNIT); 13790Sstevel@tonic-gate break; 13800Sstevel@tonic-gate 13810Sstevel@tonic-gate case SBD_COMP_CPU: 13820Sstevel@tonic-gate if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) { 13830Sstevel@tonic-gate PR_ALL("%s: invalid cpu unit# = %d", 13840Sstevel@tonic-gate f, unit); 13850Sstevel@tonic-gate devset = 0; 13860Sstevel@tonic-gate } else 13870Sstevel@tonic-gate /* 13880Sstevel@tonic-gate * Generate a devset that includes all the 13890Sstevel@tonic-gate * cores of a CMP device. If this is not a 13900Sstevel@tonic-gate * CMP, the extra cores will be eliminated 13910Sstevel@tonic-gate * later since they are not present. This is 13920Sstevel@tonic-gate * also true for CMP devices that do not have 13930Sstevel@tonic-gate * all cores active. 13940Sstevel@tonic-gate */ 13950Sstevel@tonic-gate devset = DEVSET(SBD_COMP_CMP, unit); 13960Sstevel@tonic-gate 13970Sstevel@tonic-gate break; 13980Sstevel@tonic-gate 13990Sstevel@tonic-gate case SBD_COMP_MEM: 14000Sstevel@tonic-gate 14010Sstevel@tonic-gate if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) { 14020Sstevel@tonic-gate #ifdef XXX_jeffco 14030Sstevel@tonic-gate PR_ALL("%s: invalid mem unit# = %d", 14040Sstevel@tonic-gate f, unit); 14050Sstevel@tonic-gate devset = 0; 14060Sstevel@tonic-gate #endif 14070Sstevel@tonic-gate devset = DEVSET(cid->c_type, 0); 14080Sstevel@tonic-gate PR_ALL("%s: adjusted MEM devset = 0x%x\n", 14090Sstevel@tonic-gate f, devset); 14100Sstevel@tonic-gate } else 14110Sstevel@tonic-gate devset = DEVSET(cid->c_type, unit); 14120Sstevel@tonic-gate break; 14130Sstevel@tonic-gate 14140Sstevel@tonic-gate case SBD_COMP_IO: 14150Sstevel@tonic-gate if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) { 14160Sstevel@tonic-gate PR_ALL("%s: invalid io unit# = %d", 14170Sstevel@tonic-gate f, unit); 14180Sstevel@tonic-gate devset = 0; 14190Sstevel@tonic-gate } else 14200Sstevel@tonic-gate devset = DEVSET(cid->c_type, unit); 14210Sstevel@tonic-gate 14220Sstevel@tonic-gate break; 14230Sstevel@tonic-gate 14240Sstevel@tonic-gate default: 14250Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 14260Sstevel@tonic-gate devset = 0; 14270Sstevel@tonic-gate break; 14280Sstevel@tonic-gate } 14290Sstevel@tonic-gate 14300Sstevel@tonic-gate return (devset); 14310Sstevel@tonic-gate } 14320Sstevel@tonic-gate 14330Sstevel@tonic-gate /* 14340Sstevel@tonic-gate * Simple mutex for covering handle list ops as it is only 14350Sstevel@tonic-gate * used "infrequently". No need to add another mutex to the sbd_board_t. 14360Sstevel@tonic-gate */ 14370Sstevel@tonic-gate static kmutex_t sbd_handle_list_mutex; 14380Sstevel@tonic-gate 14390Sstevel@tonic-gate static sbd_handle_t * 14400Sstevel@tonic-gate sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, intptr_t arg, 14410Sstevel@tonic-gate sbd_init_arg_t *iap) 14420Sstevel@tonic-gate { 14430Sstevel@tonic-gate sbd_handle_t *hp; 14440Sstevel@tonic-gate sbderror_t *ep; 14450Sstevel@tonic-gate sbd_priv_handle_t *shp; 14460Sstevel@tonic-gate sbd_board_t *sbp = softsp->sbd_boardlist; 14470Sstevel@tonic-gate int board; 14480Sstevel@tonic-gate 14490Sstevel@tonic-gate board = SBDGETSLOT(dev); 14500Sstevel@tonic-gate ASSERT(board < softsp->max_boards); 14510Sstevel@tonic-gate sbp += board; 14520Sstevel@tonic-gate 14530Sstevel@tonic-gate /* 14540Sstevel@tonic-gate * Brand-new handle. 14550Sstevel@tonic-gate */ 14560Sstevel@tonic-gate shp = kmem_zalloc(sizeof (sbd_priv_handle_t), KM_SLEEP); 14570Sstevel@tonic-gate shp->sh_arg = (void *)arg; 14580Sstevel@tonic-gate 14590Sstevel@tonic-gate hp = MACHHD2HD(shp); 14600Sstevel@tonic-gate 14610Sstevel@tonic-gate ep = &shp->sh_err; 14620Sstevel@tonic-gate 14630Sstevel@tonic-gate hp->h_err = ep; 14640Sstevel@tonic-gate hp->h_sbd = (void *) sbp; 14650Sstevel@tonic-gate hp->h_dev = iap->dev; 14660Sstevel@tonic-gate hp->h_cmd = iap->cmd; 14670Sstevel@tonic-gate hp->h_mode = iap->mode; 14680Sstevel@tonic-gate sbd_init_err(ep); 14690Sstevel@tonic-gate 14700Sstevel@tonic-gate mutex_enter(&sbd_handle_list_mutex); 14710Sstevel@tonic-gate shp->sh_next = sbp->sb_handle; 14720Sstevel@tonic-gate sbp->sb_handle = shp; 14730Sstevel@tonic-gate mutex_exit(&sbd_handle_list_mutex); 14740Sstevel@tonic-gate 14750Sstevel@tonic-gate return (hp); 14760Sstevel@tonic-gate } 14770Sstevel@tonic-gate 14780Sstevel@tonic-gate void 14790Sstevel@tonic-gate sbd_init_err(sbderror_t *ep) 14800Sstevel@tonic-gate { 14810Sstevel@tonic-gate ep->e_errno = 0; 14820Sstevel@tonic-gate ep->e_code = 0; 14830Sstevel@tonic-gate ep->e_rsc[0] = '\0'; 14840Sstevel@tonic-gate } 14850Sstevel@tonic-gate 14860Sstevel@tonic-gate int 14870Sstevel@tonic-gate sbd_set_err_in_hdl(sbd_handle_t *hp, sbderror_t *ep) 14880Sstevel@tonic-gate { 14890Sstevel@tonic-gate sbderror_t *hep = SBD_HD2ERR(hp); 14900Sstevel@tonic-gate 14910Sstevel@tonic-gate /* 14920Sstevel@tonic-gate * If there is an error logged already, don't rewrite it 14930Sstevel@tonic-gate */ 14940Sstevel@tonic-gate if (SBD_GET_ERR(hep) || SBD_GET_ERRNO(hep)) { 14950Sstevel@tonic-gate return (0); 14960Sstevel@tonic-gate } 14970Sstevel@tonic-gate 14980Sstevel@tonic-gate if (SBD_GET_ERR(ep) || SBD_GET_ERRNO(ep)) { 14990Sstevel@tonic-gate SBD_SET_ERR(hep, SBD_GET_ERR(ep)); 15000Sstevel@tonic-gate SBD_SET_ERRNO(hep, SBD_GET_ERRNO(ep)); 15010Sstevel@tonic-gate SBD_SET_ERRSTR(hep, SBD_GET_ERRSTR(ep)); 15020Sstevel@tonic-gate return (0); 15030Sstevel@tonic-gate } 15040Sstevel@tonic-gate 15050Sstevel@tonic-gate return (-1); 15060Sstevel@tonic-gate } 15070Sstevel@tonic-gate 15080Sstevel@tonic-gate static void 15090Sstevel@tonic-gate sbd_release_handle(sbd_handle_t *hp) 15100Sstevel@tonic-gate { 15110Sstevel@tonic-gate sbd_priv_handle_t *shp, **shpp; 15120Sstevel@tonic-gate sbd_board_t *sbp; 15130Sstevel@tonic-gate static fn_t f = "sbd_release_handle"; 15140Sstevel@tonic-gate 15150Sstevel@tonic-gate if (hp == NULL) 15160Sstevel@tonic-gate return; 15170Sstevel@tonic-gate 15180Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 15190Sstevel@tonic-gate 15200Sstevel@tonic-gate shp = HD2MACHHD(hp); 15210Sstevel@tonic-gate 15220Sstevel@tonic-gate mutex_enter(&sbd_handle_list_mutex); 15230Sstevel@tonic-gate /* 15240Sstevel@tonic-gate * Locate the handle in the board's reference list. 15250Sstevel@tonic-gate */ 15260Sstevel@tonic-gate for (shpp = &sbp->sb_handle; (*shpp) && ((*shpp) != shp); 15270Sstevel@tonic-gate shpp = &((*shpp)->sh_next)) 15280Sstevel@tonic-gate /* empty */; 15290Sstevel@tonic-gate 15300Sstevel@tonic-gate if (*shpp == NULL) { 15310Sstevel@tonic-gate cmn_err(CE_PANIC, 15320Sstevel@tonic-gate "sbd:%s: handle not found in board %d", 15330Sstevel@tonic-gate f, sbp->sb_num); 15340Sstevel@tonic-gate /*NOTREACHED*/ 15350Sstevel@tonic-gate } else { 15360Sstevel@tonic-gate *shpp = shp->sh_next; 15370Sstevel@tonic-gate } 15380Sstevel@tonic-gate mutex_exit(&sbd_handle_list_mutex); 15390Sstevel@tonic-gate 15400Sstevel@tonic-gate if (hp->h_opts.copts != NULL) { 15410Sstevel@tonic-gate FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size); 15420Sstevel@tonic-gate } 15430Sstevel@tonic-gate 15440Sstevel@tonic-gate FREESTRUCT(shp, sbd_priv_handle_t, 1); 15450Sstevel@tonic-gate } 15460Sstevel@tonic-gate 15470Sstevel@tonic-gate sbdp_handle_t * 15480Sstevel@tonic-gate sbd_get_sbdp_handle(sbd_board_t *sbp, sbd_handle_t *hp) 15490Sstevel@tonic-gate { 15500Sstevel@tonic-gate sbdp_handle_t *hdp; 15510Sstevel@tonic-gate 15520Sstevel@tonic-gate hdp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP); 15530Sstevel@tonic-gate hdp->h_err = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP); 15540Sstevel@tonic-gate if (sbp == NULL) { 15550Sstevel@tonic-gate hdp->h_board = -1; 15560Sstevel@tonic-gate hdp->h_wnode = -1; 15570Sstevel@tonic-gate } else { 15580Sstevel@tonic-gate hdp->h_board = sbp->sb_num; 15590Sstevel@tonic-gate hdp->h_wnode = sbp->sb_wnode; 15600Sstevel@tonic-gate } 15610Sstevel@tonic-gate 15620Sstevel@tonic-gate if (hp == NULL) { 15630Sstevel@tonic-gate hdp->h_flags = 0; 15640Sstevel@tonic-gate hdp->h_opts = NULL; 15650Sstevel@tonic-gate } else { 15660Sstevel@tonic-gate hdp->h_flags = SBD_2_SBDP_FLAGS(hp->h_flags); 15670Sstevel@tonic-gate hdp->h_opts = &hp->h_opts; 15680Sstevel@tonic-gate } 15690Sstevel@tonic-gate 15700Sstevel@tonic-gate return (hdp); 15710Sstevel@tonic-gate } 15720Sstevel@tonic-gate 15730Sstevel@tonic-gate void 15740Sstevel@tonic-gate sbd_release_sbdp_handle(sbdp_handle_t *hdp) 15750Sstevel@tonic-gate { 15760Sstevel@tonic-gate if (hdp == NULL) 15770Sstevel@tonic-gate return; 15780Sstevel@tonic-gate 15790Sstevel@tonic-gate kmem_free(hdp->h_err, sizeof (sbd_error_t)); 15800Sstevel@tonic-gate kmem_free(hdp, sizeof (sbdp_handle_t)); 15810Sstevel@tonic-gate } 15820Sstevel@tonic-gate 15830Sstevel@tonic-gate void 15840Sstevel@tonic-gate sbd_reset_error_sbdph(sbdp_handle_t *hdp) 15850Sstevel@tonic-gate { 15860Sstevel@tonic-gate if ((hdp != NULL) && (hdp->h_err != NULL)) { 15870Sstevel@tonic-gate bzero(hdp->h_err, sizeof (sbd_error_t)); 15880Sstevel@tonic-gate } 15890Sstevel@tonic-gate } 15900Sstevel@tonic-gate 15910Sstevel@tonic-gate static int 15920Sstevel@tonic-gate sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, sbd_cmd_t *cmdp, 15930Sstevel@tonic-gate sbd_ioctl_arg_t *iap) 15940Sstevel@tonic-gate { 15950Sstevel@tonic-gate static fn_t f = "sbd_copyin_ioarg"; 15960Sstevel@tonic-gate 15970Sstevel@tonic-gate if (iap == NULL) 15980Sstevel@tonic-gate return (EINVAL); 15990Sstevel@tonic-gate 16000Sstevel@tonic-gate bzero((caddr_t)cmdp, sizeof (sbd_cmd_t)); 16010Sstevel@tonic-gate 16020Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 16030Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 16040Sstevel@tonic-gate sbd_cmd32_t scmd32; 16050Sstevel@tonic-gate 16060Sstevel@tonic-gate bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t)); 16070Sstevel@tonic-gate 16080Sstevel@tonic-gate if (ddi_copyin((void *)iap, (void *)&scmd32, 16090Sstevel@tonic-gate sizeof (sbd_cmd32_t), mode)) { 16100Sstevel@tonic-gate cmn_err(CE_WARN, 16110Sstevel@tonic-gate "sbd:%s: (32bit) failed to copyin " 16120Sstevel@tonic-gate "sbdcmd-struct", f); 16130Sstevel@tonic-gate return (EFAULT); 16140Sstevel@tonic-gate } 16150Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type; 16160Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit; 16170Sstevel@tonic-gate bcopy(&scmd32.cmd_cm.c_id.c_name[0], 16180Sstevel@tonic-gate &cmdp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME); 16190Sstevel@tonic-gate cmdp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags; 16200Sstevel@tonic-gate cmdp->cmd_cm.c_len = scmd32.cmd_cm.c_len; 1621*930Smathue cmdp->cmd_cm.c_opts = (caddr_t)(uintptr_t)scmd32.cmd_cm.c_opts; 16220Sstevel@tonic-gate 16230Sstevel@tonic-gate if (cmd == SBD_CMD_PASSTHRU) { 1624*930Smathue PR_BYP("passthru copyin: iap=%p, sz=%ld", iap, 16250Sstevel@tonic-gate sizeof (sbd_cmd32_t)); 1626*930Smathue PR_BYP("passthru copyin: c_opts=%x, c_len=%d", 16270Sstevel@tonic-gate scmd32.cmd_cm.c_opts, 16280Sstevel@tonic-gate scmd32.cmd_cm.c_len); 16290Sstevel@tonic-gate } 16300Sstevel@tonic-gate 16310Sstevel@tonic-gate switch (cmd) { 16320Sstevel@tonic-gate case SBD_CMD_STATUS: 16330Sstevel@tonic-gate cmdp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes; 16340Sstevel@tonic-gate cmdp->cmd_stat.s_statp = 1635*930Smathue (caddr_t)(uintptr_t)scmd32.cmd_stat.s_statp; 16360Sstevel@tonic-gate break; 16370Sstevel@tonic-gate default: 16380Sstevel@tonic-gate break; 16390Sstevel@tonic-gate 16400Sstevel@tonic-gate } 16410Sstevel@tonic-gate } else 16420Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 16430Sstevel@tonic-gate if (ddi_copyin((void *)iap, (void *)cmdp, 16440Sstevel@tonic-gate sizeof (sbd_cmd_t), mode) != 0) { 16450Sstevel@tonic-gate cmn_err(CE_WARN, 16460Sstevel@tonic-gate "sbd:%s: failed to copyin sbd cmd_t struct", f); 16470Sstevel@tonic-gate return (EFAULT); 16480Sstevel@tonic-gate } 16490Sstevel@tonic-gate /* 16500Sstevel@tonic-gate * A user may set platform specific options so we need to 16510Sstevel@tonic-gate * copy them in 16520Sstevel@tonic-gate */ 16530Sstevel@tonic-gate if ((cmd != SBD_CMD_STATUS) && ((hp->h_opts.size = cmdp->cmd_cm.c_len) 16540Sstevel@tonic-gate > 0)) { 16550Sstevel@tonic-gate hp->h_opts.size += 1; /* For null termination of string. */ 16560Sstevel@tonic-gate hp->h_opts.copts = GETSTRUCT(char, hp->h_opts.size); 16570Sstevel@tonic-gate if (ddi_copyin((void *)cmdp->cmd_cm.c_opts, 16580Sstevel@tonic-gate (void *)hp->h_opts.copts, 16590Sstevel@tonic-gate cmdp->cmd_cm.c_len, hp->h_mode) != 0) { 16600Sstevel@tonic-gate /* copts is freed in sbd_release_handle(). */ 16610Sstevel@tonic-gate cmn_err(CE_WARN, 16620Sstevel@tonic-gate "sbd:%s: failed to copyin options", f); 16630Sstevel@tonic-gate return (EFAULT); 16640Sstevel@tonic-gate } 16650Sstevel@tonic-gate } 16660Sstevel@tonic-gate 16670Sstevel@tonic-gate return (0); 16680Sstevel@tonic-gate } 16690Sstevel@tonic-gate 16700Sstevel@tonic-gate static int 16710Sstevel@tonic-gate sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, sbd_ioctl_arg_t *iap) 16720Sstevel@tonic-gate { 16730Sstevel@tonic-gate static fn_t f = "sbd_copyout_ioarg"; 16740Sstevel@tonic-gate 16750Sstevel@tonic-gate if ((iap == NULL) || (scp == NULL)) 16760Sstevel@tonic-gate return (EINVAL); 16770Sstevel@tonic-gate 16780Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 16790Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 16800Sstevel@tonic-gate sbd_cmd32_t scmd32; 16810Sstevel@tonic-gate 16820Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type; 16830Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit; 16840Sstevel@tonic-gate bcopy(scp->cmd_cm.c_id.c_name, 16850Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_name, OBP_MAXPROPNAME); 16860Sstevel@tonic-gate 16870Sstevel@tonic-gate scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags; 16880Sstevel@tonic-gate 16890Sstevel@tonic-gate switch (cmd) { 16900Sstevel@tonic-gate case SBD_CMD_GETNCM: 16910Sstevel@tonic-gate scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm; 16920Sstevel@tonic-gate break; 16930Sstevel@tonic-gate default: 16940Sstevel@tonic-gate break; 16950Sstevel@tonic-gate } 16960Sstevel@tonic-gate 16970Sstevel@tonic-gate if (ddi_copyout((void *)&scmd32, (void *)iap, 16980Sstevel@tonic-gate sizeof (sbd_cmd32_t), mode)) { 16990Sstevel@tonic-gate cmn_err(CE_WARN, 17000Sstevel@tonic-gate "sbd:%s: (32bit) failed to copyout " 17010Sstevel@tonic-gate "sbdcmd struct", f); 17020Sstevel@tonic-gate return (EFAULT); 17030Sstevel@tonic-gate } 17040Sstevel@tonic-gate } else 17050Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 17060Sstevel@tonic-gate if (ddi_copyout((void *)scp, (void *)iap, 17070Sstevel@tonic-gate sizeof (sbd_cmd_t), mode) != 0) { 17080Sstevel@tonic-gate cmn_err(CE_WARN, 17090Sstevel@tonic-gate "sbd:%s: failed to copyout sbdcmd struct", f); 17100Sstevel@tonic-gate return (EFAULT); 17110Sstevel@tonic-gate } 17120Sstevel@tonic-gate 17130Sstevel@tonic-gate return (0); 17140Sstevel@tonic-gate } 17150Sstevel@tonic-gate 17160Sstevel@tonic-gate static int 17170Sstevel@tonic-gate sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, void *arg) 17180Sstevel@tonic-gate { 17190Sstevel@tonic-gate static fn_t f = "sbd_copyout_errs"; 17200Sstevel@tonic-gate sbd_ioctl_arg_t *uap; 17210Sstevel@tonic-gate 17220Sstevel@tonic-gate uap = (sbd_ioctl_arg_t *)arg; 17230Sstevel@tonic-gate 17240Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 17250Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 17260Sstevel@tonic-gate sbd_error32_t err32; 17270Sstevel@tonic-gate sbd_ioctl_arg32_t *uap32; 17280Sstevel@tonic-gate 17290Sstevel@tonic-gate uap32 = (sbd_ioctl_arg32_t *)arg; 17300Sstevel@tonic-gate 17310Sstevel@tonic-gate err32.e_code = iap->ie_code; 17320Sstevel@tonic-gate (void) strcpy(err32.e_rsc, iap->ie_rsc); 17330Sstevel@tonic-gate 17340Sstevel@tonic-gate if (ddi_copyout((void *)&err32, (void *)&uap32->i_err, 17350Sstevel@tonic-gate sizeof (sbd_error32_t), mode)) { 17360Sstevel@tonic-gate cmn_err(CE_WARN, 17370Sstevel@tonic-gate "sbd:%s: failed to copyout ioctl32 errs", 17380Sstevel@tonic-gate f); 17390Sstevel@tonic-gate return (EFAULT); 17400Sstevel@tonic-gate } 17410Sstevel@tonic-gate } else 17420Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 17430Sstevel@tonic-gate if (ddi_copyout((void *)&iap->i_err, (void *)&uap->i_err, 17440Sstevel@tonic-gate sizeof (sbd_error_t), mode) != 0) { 17450Sstevel@tonic-gate cmn_err(CE_WARN, 17460Sstevel@tonic-gate "sbd:%s: failed to copyout ioctl errs", f); 17470Sstevel@tonic-gate return (EFAULT); 17480Sstevel@tonic-gate } 17490Sstevel@tonic-gate 17500Sstevel@tonic-gate return (0); 17510Sstevel@tonic-gate } 17520Sstevel@tonic-gate 17530Sstevel@tonic-gate /* 17540Sstevel@tonic-gate * State transition policy is that if at least one 17550Sstevel@tonic-gate * device cannot make the transition, then none of 17560Sstevel@tonic-gate * the requested devices are allowed to transition. 17570Sstevel@tonic-gate * 17580Sstevel@tonic-gate * Returns the state that is in error, if any. 17590Sstevel@tonic-gate */ 17600Sstevel@tonic-gate static int 17610Sstevel@tonic-gate sbd_check_transition(sbd_board_t *sbp, sbd_devset_t *devsetp, 17620Sstevel@tonic-gate struct sbd_state_trans *transp) 17630Sstevel@tonic-gate { 17640Sstevel@tonic-gate int s, ut; 17650Sstevel@tonic-gate int state_err = 0; 17660Sstevel@tonic-gate sbd_devset_t devset; 17670Sstevel@tonic-gate static fn_t f = "sbd_check_transition"; 17680Sstevel@tonic-gate 17690Sstevel@tonic-gate devset = *devsetp; 17700Sstevel@tonic-gate 17710Sstevel@tonic-gate if (!devset) { 17720Sstevel@tonic-gate /* 17730Sstevel@tonic-gate * Transition does not deal with any components. 17740Sstevel@tonic-gate * This is the case for addboard/deleteboard. 17750Sstevel@tonic-gate */ 17760Sstevel@tonic-gate PR_ALL("%s: no devs: requested devset = 0x%x," 17770Sstevel@tonic-gate " final devset = 0x%x\n", 17780Sstevel@tonic-gate f, (uint_t)*devsetp, (uint_t)devset); 17790Sstevel@tonic-gate 17800Sstevel@tonic-gate return (0); 17810Sstevel@tonic-gate } 17820Sstevel@tonic-gate 17830Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 17840Sstevel@tonic-gate for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) { 17850Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0) 17860Sstevel@tonic-gate continue; 17870Sstevel@tonic-gate s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, ut); 17880Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 17890Sstevel@tonic-gate if (!state_err) 17900Sstevel@tonic-gate state_err = s; 17910Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, ut); 17920Sstevel@tonic-gate } 17930Sstevel@tonic-gate } 17940Sstevel@tonic-gate } 17950Sstevel@tonic-gate 17960Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 17970Sstevel@tonic-gate for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) { 17980Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0) 17990Sstevel@tonic-gate continue; 18000Sstevel@tonic-gate s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, ut); 18010Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 18020Sstevel@tonic-gate if (!state_err) 18030Sstevel@tonic-gate state_err = s; 18040Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, ut); 18050Sstevel@tonic-gate } 18060Sstevel@tonic-gate } 18070Sstevel@tonic-gate } 18080Sstevel@tonic-gate 18090Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 18100Sstevel@tonic-gate for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) { 18110Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0) 18120Sstevel@tonic-gate continue; 18130Sstevel@tonic-gate s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_IO, ut); 18140Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 18150Sstevel@tonic-gate if (!state_err) 18160Sstevel@tonic-gate state_err = s; 18170Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, ut); 18180Sstevel@tonic-gate } 18190Sstevel@tonic-gate } 18200Sstevel@tonic-gate } 18210Sstevel@tonic-gate 18220Sstevel@tonic-gate PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n", 18230Sstevel@tonic-gate f, (uint_t)*devsetp, (uint_t)devset); 18240Sstevel@tonic-gate 18250Sstevel@tonic-gate *devsetp = devset; 18260Sstevel@tonic-gate /* 18270Sstevel@tonic-gate * If there are some remaining components for which 18280Sstevel@tonic-gate * this state transition is valid, then allow them 18290Sstevel@tonic-gate * through, otherwise if none are left then return 18300Sstevel@tonic-gate * the state error. 18310Sstevel@tonic-gate */ 18320Sstevel@tonic-gate return (devset ? 0 : state_err); 18330Sstevel@tonic-gate } 18340Sstevel@tonic-gate 18350Sstevel@tonic-gate /* 18360Sstevel@tonic-gate * pre-op entry point must SET_ERRNO(), if needed. 18370Sstevel@tonic-gate * Return value of non-zero indicates failure. 18380Sstevel@tonic-gate */ 18390Sstevel@tonic-gate static int 18400Sstevel@tonic-gate sbd_pre_op(sbd_handle_t *hp) 18410Sstevel@tonic-gate { 18420Sstevel@tonic-gate int rv = 0, t; 18430Sstevel@tonic-gate int cmd, serr = 0; 18440Sstevel@tonic-gate sbd_devset_t devset; 18450Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 18460Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 18470Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 18480Sstevel@tonic-gate sbd_cmd_t *cmdp; 18490Sstevel@tonic-gate static fn_t f = "sbd_pre_op"; 18500Sstevel@tonic-gate 18510Sstevel@tonic-gate cmd = hp->h_cmd; 18520Sstevel@tonic-gate devset = shp->sh_devset; 18530Sstevel@tonic-gate 18540Sstevel@tonic-gate switch (cmd) { 18550Sstevel@tonic-gate case SBD_CMD_CONNECT: 18560Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 18570Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 18580Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 18590Sstevel@tonic-gate case SBD_CMD_ASSIGN: 18600Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 18610Sstevel@tonic-gate case SBD_CMD_POWERON: 18620Sstevel@tonic-gate case SBD_CMD_POWEROFF: 18630Sstevel@tonic-gate case SBD_CMD_TEST: 18640Sstevel@tonic-gate /* ioctls allowed if caller has write permission */ 18650Sstevel@tonic-gate if (!(hp->h_mode & FWRITE)) { 18660Sstevel@tonic-gate SBD_SET_ERRNO(ep, EPERM); 18670Sstevel@tonic-gate return (-1); 18680Sstevel@tonic-gate } 18690Sstevel@tonic-gate 18700Sstevel@tonic-gate default: 18710Sstevel@tonic-gate break; 18720Sstevel@tonic-gate } 18730Sstevel@tonic-gate 18740Sstevel@tonic-gate hp->h_iap = GETSTRUCT(sbd_ioctl_arg_t, 1); 18750Sstevel@tonic-gate rv = sbd_copyin_ioarg(hp, hp->h_mode, cmd, 18760Sstevel@tonic-gate (sbd_cmd_t *)hp->h_iap, shp->sh_arg); 18770Sstevel@tonic-gate if (rv) { 18780Sstevel@tonic-gate SBD_SET_ERRNO(ep, rv); 18790Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 18800Sstevel@tonic-gate hp->h_iap = NULL; 18810Sstevel@tonic-gate cmn_err(CE_WARN, "%s: copyin fail", f); 18820Sstevel@tonic-gate return (-1); 18830Sstevel@tonic-gate } else { 18840Sstevel@tonic-gate cmdp = (sbd_cmd_t *)hp->h_iap; 18850Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_name[0] != '\0') { 18860Sstevel@tonic-gate 18870Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_type = SBD_COMP(sbd_name_to_idx( 18880Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_name)); 18890Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_MEM) { 18900Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_unit == -1) 18910Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_unit = 0; 18920Sstevel@tonic-gate } 18930Sstevel@tonic-gate } 18940Sstevel@tonic-gate devset = shp->sh_orig_devset = shp->sh_devset = 18950Sstevel@tonic-gate sbd_dev2devset(&cmdp->cmd_cm.c_id); 18960Sstevel@tonic-gate if (devset == 0) { 18970Sstevel@tonic-gate SBD_SET_ERRNO(ep, EINVAL); 18980Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 18990Sstevel@tonic-gate hp->h_iap = NULL; 19000Sstevel@tonic-gate return (-1); 19010Sstevel@tonic-gate } 19020Sstevel@tonic-gate } 19030Sstevel@tonic-gate 19040Sstevel@tonic-gate /* 19050Sstevel@tonic-gate * Always turn on these bits ala Sunfire DR. 19060Sstevel@tonic-gate */ 19070Sstevel@tonic-gate hp->h_flags |= SBD_FLAG_DEVI_FORCE; 19080Sstevel@tonic-gate 19090Sstevel@tonic-gate if (cmdp->cmd_cm.c_flags & SBD_FLAG_FORCE) 19100Sstevel@tonic-gate hp->h_flags |= SBD_IOCTL_FLAG_FORCE; 19110Sstevel@tonic-gate 19120Sstevel@tonic-gate /* 19130Sstevel@tonic-gate * Check for valid state transitions. 19140Sstevel@tonic-gate */ 19150Sstevel@tonic-gate if (!serr && ((t = CMD2INDEX(cmd)) != -1)) { 19160Sstevel@tonic-gate struct sbd_state_trans *transp; 19170Sstevel@tonic-gate int state_err; 19180Sstevel@tonic-gate 19190Sstevel@tonic-gate transp = &sbd_state_transition[t]; 19200Sstevel@tonic-gate ASSERT(transp->x_cmd == cmd); 19210Sstevel@tonic-gate 19220Sstevel@tonic-gate state_err = sbd_check_transition(sbp, &devset, transp); 19230Sstevel@tonic-gate 19240Sstevel@tonic-gate if (state_err < 0) { 19250Sstevel@tonic-gate /* 19260Sstevel@tonic-gate * Invalidate device. 19270Sstevel@tonic-gate */ 19280Sstevel@tonic-gate SBD_SET_ERRNO(ep, ENOTTY); 19290Sstevel@tonic-gate serr = -1; 19300Sstevel@tonic-gate PR_ALL("%s: invalid devset (0x%x)\n", 19310Sstevel@tonic-gate f, (uint_t)devset); 19320Sstevel@tonic-gate } else if (state_err != 0) { 19330Sstevel@tonic-gate /* 19340Sstevel@tonic-gate * State transition is not a valid one. 19350Sstevel@tonic-gate */ 19360Sstevel@tonic-gate SBD_SET_ERRNO(ep, transp->x_op[state_err].x_err); 19370Sstevel@tonic-gate serr = transp->x_op[state_err].x_rv; 19380Sstevel@tonic-gate PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n", 19390Sstevel@tonic-gate f, sbd_state_str[state_err], state_err, 19400Sstevel@tonic-gate SBD_CMD_STR(cmd), cmd); 19410Sstevel@tonic-gate } 19420Sstevel@tonic-gate if (serr && SBD_GET_ERRNO(ep) != 0) { 19430Sstevel@tonic-gate /* 19440Sstevel@tonic-gate * A state transition error occurred. 19450Sstevel@tonic-gate */ 19460Sstevel@tonic-gate if (serr < 0) { 19470Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INVAL); 19480Sstevel@tonic-gate } else { 19490Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_STATE); 19500Sstevel@tonic-gate } 19510Sstevel@tonic-gate PR_ALL("%s: invalid state transition\n", f); 19520Sstevel@tonic-gate } else { 19530Sstevel@tonic-gate shp->sh_devset = devset; 19540Sstevel@tonic-gate } 19550Sstevel@tonic-gate } 19560Sstevel@tonic-gate 19570Sstevel@tonic-gate if (serr && !rv && hp->h_iap) { 19580Sstevel@tonic-gate 19590Sstevel@tonic-gate /* 19600Sstevel@tonic-gate * There was a state error. We successfully copied 19610Sstevel@tonic-gate * in the ioctl argument, so let's fill in the 19620Sstevel@tonic-gate * error and copy it back out. 19630Sstevel@tonic-gate */ 19640Sstevel@tonic-gate 19650Sstevel@tonic-gate if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) 19660Sstevel@tonic-gate SBD_SET_ERRNO(ep, EIO); 19670Sstevel@tonic-gate 19680Sstevel@tonic-gate SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, 19690Sstevel@tonic-gate ep->e_code, 19700Sstevel@tonic-gate ep->e_rsc); 19710Sstevel@tonic-gate (void) sbd_copyout_errs(hp->h_mode, hp->h_iap, shp->sh_arg); 19720Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 19730Sstevel@tonic-gate hp->h_iap = NULL; 19740Sstevel@tonic-gate rv = -1; 19750Sstevel@tonic-gate } 19760Sstevel@tonic-gate 19770Sstevel@tonic-gate return (rv); 19780Sstevel@tonic-gate } 19790Sstevel@tonic-gate 19800Sstevel@tonic-gate static void 19810Sstevel@tonic-gate sbd_post_op(sbd_handle_t *hp) 19820Sstevel@tonic-gate { 19830Sstevel@tonic-gate int cmd; 19840Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 19850Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 19860Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 19870Sstevel@tonic-gate 19880Sstevel@tonic-gate cmd = hp->h_cmd; 19890Sstevel@tonic-gate 19900Sstevel@tonic-gate switch (cmd) { 19910Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 19920Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 19930Sstevel@tonic-gate case SBD_CMD_CONNECT: 19940Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 19950Sstevel@tonic-gate sbp->sb_time = gethrestime_sec(); 19960Sstevel@tonic-gate break; 19970Sstevel@tonic-gate 19980Sstevel@tonic-gate default: 19990Sstevel@tonic-gate break; 20000Sstevel@tonic-gate } 20010Sstevel@tonic-gate 20020Sstevel@tonic-gate if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) { 20030Sstevel@tonic-gate SBD_SET_ERRNO(ep, EIO); 20040Sstevel@tonic-gate } 20050Sstevel@tonic-gate 20060Sstevel@tonic-gate if (shp->sh_arg != NULL) { 20070Sstevel@tonic-gate 20080Sstevel@tonic-gate if (SBD_GET_ERR(ep) != ESBD_NOERROR) { 20090Sstevel@tonic-gate 20100Sstevel@tonic-gate SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, 20110Sstevel@tonic-gate ep->e_code, 20120Sstevel@tonic-gate ep->e_rsc); 20130Sstevel@tonic-gate 20140Sstevel@tonic-gate (void) sbd_copyout_errs(hp->h_mode, hp->h_iap, 20150Sstevel@tonic-gate shp->sh_arg); 20160Sstevel@tonic-gate } 20170Sstevel@tonic-gate 20180Sstevel@tonic-gate if (hp->h_iap != NULL) { 20190Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 20200Sstevel@tonic-gate hp->h_iap = NULL; 20210Sstevel@tonic-gate } 20220Sstevel@tonic-gate } 20230Sstevel@tonic-gate } 20240Sstevel@tonic-gate 20250Sstevel@tonic-gate static int 20260Sstevel@tonic-gate sbd_probe_board(sbd_handle_t *hp) 20270Sstevel@tonic-gate { 20280Sstevel@tonic-gate int rv; 20290Sstevel@tonic-gate sbd_board_t *sbp; 20300Sstevel@tonic-gate sbdp_handle_t *hdp; 20310Sstevel@tonic-gate static fn_t f = "sbd_probe_board"; 20320Sstevel@tonic-gate 20330Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 20340Sstevel@tonic-gate 20350Sstevel@tonic-gate ASSERT(sbp != NULL); 20360Sstevel@tonic-gate PR_ALL("%s for board %d", f, sbp->sb_num); 20370Sstevel@tonic-gate 20380Sstevel@tonic-gate 20390Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 20400Sstevel@tonic-gate 20410Sstevel@tonic-gate if ((rv = sbdp_connect_board(hdp)) != 0) { 20420Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 20430Sstevel@tonic-gate 20440Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 20450Sstevel@tonic-gate } 20460Sstevel@tonic-gate 20470Sstevel@tonic-gate /* 20480Sstevel@tonic-gate * We need to force a recache after the connect. The cached 20490Sstevel@tonic-gate * info may be incorrect 20500Sstevel@tonic-gate */ 20510Sstevel@tonic-gate mutex_enter(&sbp->sb_flags_mutex); 20520Sstevel@tonic-gate sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 20530Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 20540Sstevel@tonic-gate 20550Sstevel@tonic-gate SBD_INJECT_ERR(SBD_PROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO, 20560Sstevel@tonic-gate ESGT_PROBE, NULL); 20570Sstevel@tonic-gate 20580Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 20590Sstevel@tonic-gate 20600Sstevel@tonic-gate return (rv); 20610Sstevel@tonic-gate } 20620Sstevel@tonic-gate 20630Sstevel@tonic-gate static int 20640Sstevel@tonic-gate sbd_deprobe_board(sbd_handle_t *hp) 20650Sstevel@tonic-gate { 20660Sstevel@tonic-gate int rv; 20670Sstevel@tonic-gate sbdp_handle_t *hdp; 20680Sstevel@tonic-gate sbd_board_t *sbp; 20690Sstevel@tonic-gate static fn_t f = "sbd_deprobe_board"; 20700Sstevel@tonic-gate 20710Sstevel@tonic-gate PR_ALL("%s...\n", f); 20720Sstevel@tonic-gate 20730Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 20740Sstevel@tonic-gate 20750Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 20760Sstevel@tonic-gate 20770Sstevel@tonic-gate if ((rv = sbdp_disconnect_board(hdp)) != 0) { 20780Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 20790Sstevel@tonic-gate 20800Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 20810Sstevel@tonic-gate } 20820Sstevel@tonic-gate 20830Sstevel@tonic-gate mutex_enter(&sbp->sb_flags_mutex); 20840Sstevel@tonic-gate sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 20850Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 20860Sstevel@tonic-gate 20870Sstevel@tonic-gate SBD_INJECT_ERR(SBD_DEPROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO, 20880Sstevel@tonic-gate ESGT_DEPROBE, NULL); 20890Sstevel@tonic-gate 20900Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 20910Sstevel@tonic-gate return (rv); 20920Sstevel@tonic-gate } 20930Sstevel@tonic-gate 20940Sstevel@tonic-gate /* 20950Sstevel@tonic-gate * Check if a CPU node is part of a CMP. 20960Sstevel@tonic-gate */ 20970Sstevel@tonic-gate int 20980Sstevel@tonic-gate sbd_is_cmp_child(dev_info_t *dip) 20990Sstevel@tonic-gate { 21000Sstevel@tonic-gate dev_info_t *pdip; 21010Sstevel@tonic-gate 21020Sstevel@tonic-gate if (strcmp(ddi_node_name(dip), "cpu") != 0) { 21030Sstevel@tonic-gate return (0); 21040Sstevel@tonic-gate } 21050Sstevel@tonic-gate 21060Sstevel@tonic-gate pdip = ddi_get_parent(dip); 21070Sstevel@tonic-gate 21080Sstevel@tonic-gate ASSERT(pdip); 21090Sstevel@tonic-gate 21100Sstevel@tonic-gate if (strcmp(ddi_node_name(pdip), "cmp") == 0) { 21110Sstevel@tonic-gate return (1); 21120Sstevel@tonic-gate } 21130Sstevel@tonic-gate 21140Sstevel@tonic-gate return (0); 21150Sstevel@tonic-gate } 21160Sstevel@tonic-gate 21170Sstevel@tonic-gate /* 21180Sstevel@tonic-gate * Returns the nodetype if dip is a top dip on the board of 21190Sstevel@tonic-gate * interest or SBD_COMP_UNKNOWN otherwise 21200Sstevel@tonic-gate */ 21210Sstevel@tonic-gate static sbd_comp_type_t 21220Sstevel@tonic-gate get_node_type(sbd_board_t *sbp, dev_info_t *dip, int *unitp) 21230Sstevel@tonic-gate { 21240Sstevel@tonic-gate int idx, unit; 21250Sstevel@tonic-gate sbd_handle_t *hp; 21260Sstevel@tonic-gate sbdp_handle_t *hdp; 21270Sstevel@tonic-gate char otype[OBP_MAXDRVNAME]; 21280Sstevel@tonic-gate int otypelen; 21290Sstevel@tonic-gate 21300Sstevel@tonic-gate ASSERT(sbp); 21310Sstevel@tonic-gate 21320Sstevel@tonic-gate if (unitp) 21330Sstevel@tonic-gate *unitp = -1; 21340Sstevel@tonic-gate 21350Sstevel@tonic-gate hp = MACHBD2HD(sbp); 21360Sstevel@tonic-gate 21370Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 21380Sstevel@tonic-gate if (sbdp_get_board_num(hdp, dip) != sbp->sb_num) { 21390Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 21400Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 21410Sstevel@tonic-gate } 21420Sstevel@tonic-gate 21430Sstevel@tonic-gate /* 21440Sstevel@tonic-gate * sbdp_get_unit_num will return (-1) for cmp as there 21450Sstevel@tonic-gate * is no "device_type" property associated with cmp. 21460Sstevel@tonic-gate * Therefore we will just skip getting unit number for 21470Sstevel@tonic-gate * cmp. Callers of this function need to check the 21480Sstevel@tonic-gate * value set in unitp before using it to dereference 21490Sstevel@tonic-gate * an array. 21500Sstevel@tonic-gate */ 21510Sstevel@tonic-gate if (strcmp(ddi_node_name(dip), "cmp") == 0) { 21520Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 21530Sstevel@tonic-gate return (SBD_COMP_CMP); 21540Sstevel@tonic-gate } 21550Sstevel@tonic-gate 21560Sstevel@tonic-gate otypelen = sizeof (otype); 21570Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 21580Sstevel@tonic-gate OBP_DEVICETYPE, (caddr_t)otype, &otypelen)) { 21590Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 21600Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 21610Sstevel@tonic-gate } 21620Sstevel@tonic-gate 21630Sstevel@tonic-gate idx = sbd_otype_to_idx(otype); 21640Sstevel@tonic-gate 21650Sstevel@tonic-gate if (SBD_COMP(idx) == SBD_COMP_UNKNOWN) { 21660Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 21670Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 21680Sstevel@tonic-gate } 21690Sstevel@tonic-gate 21700Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 21710Sstevel@tonic-gate if (unit == -1) { 21720Sstevel@tonic-gate cmn_err(CE_WARN, 21730Sstevel@tonic-gate "get_node_type: %s unit fail %p", otype, (void *)dip); 21740Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 21750Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 21760Sstevel@tonic-gate } 21770Sstevel@tonic-gate 21780Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 21790Sstevel@tonic-gate 21800Sstevel@tonic-gate if (unitp) 21810Sstevel@tonic-gate *unitp = unit; 21820Sstevel@tonic-gate 21830Sstevel@tonic-gate return (SBD_COMP(idx)); 21840Sstevel@tonic-gate } 21850Sstevel@tonic-gate 21860Sstevel@tonic-gate typedef struct { 21870Sstevel@tonic-gate sbd_board_t *sbp; 21880Sstevel@tonic-gate int nmc; 21890Sstevel@tonic-gate int hold; 21900Sstevel@tonic-gate } walk_tree_t; 21910Sstevel@tonic-gate 21920Sstevel@tonic-gate static int 21930Sstevel@tonic-gate sbd_setup_devlists(dev_info_t *dip, void *arg) 21940Sstevel@tonic-gate { 21950Sstevel@tonic-gate walk_tree_t *wp; 21960Sstevel@tonic-gate dev_info_t **devlist = NULL; 21970Sstevel@tonic-gate char *pathname = NULL; 21980Sstevel@tonic-gate sbd_mem_unit_t *mp; 21990Sstevel@tonic-gate static fn_t f = "sbd_setup_devlists"; 22000Sstevel@tonic-gate sbd_board_t *sbp; 22010Sstevel@tonic-gate int unit; 22020Sstevel@tonic-gate sbd_comp_type_t nodetype; 22030Sstevel@tonic-gate 22040Sstevel@tonic-gate ASSERT(dip); 22050Sstevel@tonic-gate 22060Sstevel@tonic-gate wp = (walk_tree_t *)arg; 22070Sstevel@tonic-gate 22080Sstevel@tonic-gate if (wp == NULL) { 22090Sstevel@tonic-gate PR_ALL("%s:bad arg\n", f); 22100Sstevel@tonic-gate return (DDI_WALK_TERMINATE); 22110Sstevel@tonic-gate } 22120Sstevel@tonic-gate 22130Sstevel@tonic-gate sbp = wp->sbp; 22140Sstevel@tonic-gate 22150Sstevel@tonic-gate nodetype = get_node_type(sbp, dip, &unit); 22160Sstevel@tonic-gate 22170Sstevel@tonic-gate switch (nodetype) { 22180Sstevel@tonic-gate 22190Sstevel@tonic-gate case SBD_COMP_CPU: 22200Sstevel@tonic-gate pathname = sbp->sb_cpupath[unit]; 22210Sstevel@tonic-gate break; 22220Sstevel@tonic-gate 22230Sstevel@tonic-gate case SBD_COMP_MEM: 22240Sstevel@tonic-gate pathname = sbp->sb_mempath[unit]; 22250Sstevel@tonic-gate break; 22260Sstevel@tonic-gate 22270Sstevel@tonic-gate case SBD_COMP_IO: 22280Sstevel@tonic-gate pathname = sbp->sb_iopath[unit]; 22290Sstevel@tonic-gate break; 22300Sstevel@tonic-gate 22310Sstevel@tonic-gate case SBD_COMP_CMP: 22320Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 22330Sstevel@tonic-gate /* 22340Sstevel@tonic-gate * This dip is not of interest to us 22350Sstevel@tonic-gate */ 22360Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 22370Sstevel@tonic-gate 22380Sstevel@tonic-gate default: 22390Sstevel@tonic-gate ASSERT(0); 22400Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 22410Sstevel@tonic-gate } 22420Sstevel@tonic-gate 22430Sstevel@tonic-gate /* 22440Sstevel@tonic-gate * dip's parent is being held busy by ddi_walk_devs(), 22450Sstevel@tonic-gate * so dip doesn't have to be held while calling ddi_pathname() 22460Sstevel@tonic-gate */ 22470Sstevel@tonic-gate if (pathname) { 22480Sstevel@tonic-gate (void) ddi_pathname(dip, pathname); 22490Sstevel@tonic-gate } 22500Sstevel@tonic-gate 22510Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(nodetype)]; 22520Sstevel@tonic-gate 22530Sstevel@tonic-gate /* 22540Sstevel@tonic-gate * The branch rooted at dip should already be held, 22550Sstevel@tonic-gate * unless we are dealing with a core of a CMP. 22560Sstevel@tonic-gate */ 22570Sstevel@tonic-gate ASSERT(sbd_is_cmp_child(dip) || e_ddi_branch_held(dip)); 22580Sstevel@tonic-gate devlist[unit] = dip; 22590Sstevel@tonic-gate 22600Sstevel@tonic-gate /* 22610Sstevel@tonic-gate * This test is required if multiple devices are considered 22620Sstevel@tonic-gate * as one. This is the case for memory-controller nodes. 22630Sstevel@tonic-gate */ 22640Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, nodetype, unit)) { 22650Sstevel@tonic-gate sbp->sb_ndev++; 22660Sstevel@tonic-gate SBD_DEV_SET_PRESENT(sbp, nodetype, unit); 22670Sstevel@tonic-gate } 22680Sstevel@tonic-gate 22690Sstevel@tonic-gate if (nodetype == SBD_COMP_MEM) { 22700Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 22710Sstevel@tonic-gate ASSERT(wp->nmc < SBD_NUM_MC_PER_BOARD); 22720Sstevel@tonic-gate mp->sbm_dip[wp->nmc++] = dip; 22730Sstevel@tonic-gate } 22740Sstevel@tonic-gate 22750Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 22760Sstevel@tonic-gate } 22770Sstevel@tonic-gate 22780Sstevel@tonic-gate /* 22790Sstevel@tonic-gate * This routine is used to construct the memory devlist. 22800Sstevel@tonic-gate * In Starcat and Serengeti platforms, a system board can contain up to 22810Sstevel@tonic-gate * four memory controllers (MC). The MCs have been programmed by POST for 22820Sstevel@tonic-gate * optimum memory interleaving amongst their peers on the same board. 22830Sstevel@tonic-gate * This DR driver does not support deinterleaving. Therefore, the smallest 22840Sstevel@tonic-gate * unit of memory that can be manipulated by this driver is all of the 22850Sstevel@tonic-gate * memory on a board. Because of this restriction, a board's memory devlist 22860Sstevel@tonic-gate * is populated with only one of the four (possible) MC dnodes on that board. 22870Sstevel@tonic-gate * Care must be taken to ensure that the selected MC dnode represents the 22880Sstevel@tonic-gate * lowest physical address to which memory on the board will respond to. 22890Sstevel@tonic-gate * This is required in order to preserve the semantics of 22900Sstevel@tonic-gate * sbdp_get_base_physaddr() when applied to a MC dnode stored in the 22910Sstevel@tonic-gate * memory devlist. 22920Sstevel@tonic-gate */ 22930Sstevel@tonic-gate static void 22940Sstevel@tonic-gate sbd_init_mem_devlists(sbd_board_t *sbp) 22950Sstevel@tonic-gate { 22960Sstevel@tonic-gate dev_info_t **devlist; 22970Sstevel@tonic-gate sbd_mem_unit_t *mp; 22980Sstevel@tonic-gate dev_info_t *mc_dip; 22990Sstevel@tonic-gate sbdp_handle_t *hdp; 23000Sstevel@tonic-gate uint64_t mc_pa, lowest_pa; 23010Sstevel@tonic-gate int i; 23020Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 23030Sstevel@tonic-gate 23040Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)]; 23050Sstevel@tonic-gate 23060Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, 0); 23070Sstevel@tonic-gate 23080Sstevel@tonic-gate mc_dip = mp->sbm_dip[0]; 23090Sstevel@tonic-gate if (mc_dip == NULL) 23100Sstevel@tonic-gate return; /* No MC dips found for this board */ 23110Sstevel@tonic-gate 23120Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 23130Sstevel@tonic-gate 23140Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) { 23150Sstevel@tonic-gate /* TODO: log complaint about dnode */ 23160Sstevel@tonic-gate 23170Sstevel@tonic-gate pretend_no_mem: 23180Sstevel@tonic-gate /* 23190Sstevel@tonic-gate * We are here because sbdphw_get_base_physaddr() failed. 23200Sstevel@tonic-gate * Although it is very unlikely to happen, it did. Lucky us. 23210Sstevel@tonic-gate * Since we can no longer examine _all_ of the MCs on this 23220Sstevel@tonic-gate * board to determine which one is programmed to the lowest 23230Sstevel@tonic-gate * physical address, we cannot involve any of the MCs on 23240Sstevel@tonic-gate * this board in DR operations. To ensure this, we pretend 23250Sstevel@tonic-gate * that this board does not contain any memory. 23260Sstevel@tonic-gate * 23270Sstevel@tonic-gate * Paranoia: clear the dev_present mask. 23280Sstevel@tonic-gate */ 23290Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, 0)) { 23300Sstevel@tonic-gate ASSERT(sbp->sb_ndev != 0); 23310Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, 0); 23320Sstevel@tonic-gate sbp->sb_ndev--; 23330Sstevel@tonic-gate } 23340Sstevel@tonic-gate 23350Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 23360Sstevel@tonic-gate mp->sbm_dip[i] = NULL; 23370Sstevel@tonic-gate } 23380Sstevel@tonic-gate 23390Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 23400Sstevel@tonic-gate return; 23410Sstevel@tonic-gate } 23420Sstevel@tonic-gate 23430Sstevel@tonic-gate /* assume this one will win. */ 23440Sstevel@tonic-gate devlist[0] = mc_dip; 23450Sstevel@tonic-gate mp->sbm_cm.sbdev_dip = mc_dip; 23460Sstevel@tonic-gate lowest_pa = mc_pa; 23470Sstevel@tonic-gate 23480Sstevel@tonic-gate /* 23490Sstevel@tonic-gate * We know the base physical address of one of the MC devices. Now 23500Sstevel@tonic-gate * we will enumerate through all of the remaining MC devices on 23510Sstevel@tonic-gate * the board to find which of them is programmed to the lowest 23520Sstevel@tonic-gate * physical address. 23530Sstevel@tonic-gate */ 23540Sstevel@tonic-gate for (i = 1; i < SBD_NUM_MC_PER_BOARD; i++) { 23550Sstevel@tonic-gate mc_dip = mp->sbm_dip[i]; 23560Sstevel@tonic-gate if (mc_dip == NULL) { 23570Sstevel@tonic-gate break; 23580Sstevel@tonic-gate } 23590Sstevel@tonic-gate 23600Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) { 23610Sstevel@tonic-gate cmn_err(CE_NOTE, "No mem on board %d unit %d", 23620Sstevel@tonic-gate sbp->sb_num, i); 23630Sstevel@tonic-gate break; 23640Sstevel@tonic-gate } 23650Sstevel@tonic-gate if (mc_pa < lowest_pa) { 23660Sstevel@tonic-gate mp->sbm_cm.sbdev_dip = mc_dip; 23670Sstevel@tonic-gate devlist[0] = mc_dip; 23680Sstevel@tonic-gate lowest_pa = mc_pa; 23690Sstevel@tonic-gate } 23700Sstevel@tonic-gate } 23710Sstevel@tonic-gate 23720Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 23730Sstevel@tonic-gate } 23740Sstevel@tonic-gate 23750Sstevel@tonic-gate static int 23760Sstevel@tonic-gate sbd_name_to_idx(char *name) 23770Sstevel@tonic-gate { 23780Sstevel@tonic-gate int idx; 23790Sstevel@tonic-gate 23800Sstevel@tonic-gate for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) { 23810Sstevel@tonic-gate if (strcmp(name, SBD_DEVNAME(idx)) == 0) { 23820Sstevel@tonic-gate break; 23830Sstevel@tonic-gate } 23840Sstevel@tonic-gate } 23850Sstevel@tonic-gate 23860Sstevel@tonic-gate return (idx); 23870Sstevel@tonic-gate } 23880Sstevel@tonic-gate 23890Sstevel@tonic-gate static int 23900Sstevel@tonic-gate sbd_otype_to_idx(char *otype) 23910Sstevel@tonic-gate { 23920Sstevel@tonic-gate int idx; 23930Sstevel@tonic-gate 23940Sstevel@tonic-gate for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) { 23950Sstevel@tonic-gate 23960Sstevel@tonic-gate if (strcmp(otype, SBD_OTYPE(idx)) == 0) { 23970Sstevel@tonic-gate break; 23980Sstevel@tonic-gate } 23990Sstevel@tonic-gate } 24000Sstevel@tonic-gate 24010Sstevel@tonic-gate return (idx); 24020Sstevel@tonic-gate } 24030Sstevel@tonic-gate 24040Sstevel@tonic-gate static int 24050Sstevel@tonic-gate sbd_init_devlists(sbd_board_t *sbp) 24060Sstevel@tonic-gate { 24070Sstevel@tonic-gate int i; 24080Sstevel@tonic-gate sbd_dev_unit_t *dp; 24090Sstevel@tonic-gate sbd_mem_unit_t *mp; 24100Sstevel@tonic-gate walk_tree_t *wp, walk = {0}; 24110Sstevel@tonic-gate dev_info_t *pdip; 24120Sstevel@tonic-gate static fn_t f = "sbd_init_devlists"; 24130Sstevel@tonic-gate 24140Sstevel@tonic-gate PR_ALL("%s (board = %d)...\n", f, sbp->sb_num); 24150Sstevel@tonic-gate 24160Sstevel@tonic-gate wp = &walk; 24170Sstevel@tonic-gate 24180Sstevel@tonic-gate SBD_DEVS_DISCONNECT(sbp, (uint_t)-1); 24190Sstevel@tonic-gate 24200Sstevel@tonic-gate /* 24210Sstevel@tonic-gate * Clear out old entries, if any. 24220Sstevel@tonic-gate */ 24230Sstevel@tonic-gate 24240Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 24250Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL; 24260Sstevel@tonic-gate dp = (sbd_dev_unit_t *)SBD_GET_BOARD_MEMUNIT(sbp, i); 24270Sstevel@tonic-gate dp->u_common.sbdev_sbp = sbp; 24280Sstevel@tonic-gate dp->u_common.sbdev_unum = i; 24290Sstevel@tonic-gate dp->u_common.sbdev_type = SBD_COMP_MEM; 24300Sstevel@tonic-gate } 24310Sstevel@tonic-gate 24320Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, 0); 24330Sstevel@tonic-gate ASSERT(mp != NULL); 24340Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 24350Sstevel@tonic-gate mp->sbm_dip[i] = NULL; 24360Sstevel@tonic-gate } 24370Sstevel@tonic-gate 24380Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 24390Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_CPU)][i] = NULL; 24400Sstevel@tonic-gate dp = (sbd_dev_unit_t *)SBD_GET_BOARD_CPUUNIT(sbp, i); 24410Sstevel@tonic-gate dp->u_common.sbdev_sbp = sbp; 24420Sstevel@tonic-gate dp->u_common.sbdev_unum = i; 24430Sstevel@tonic-gate dp->u_common.sbdev_type = SBD_COMP_CPU; 24440Sstevel@tonic-gate } 24450Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 24460Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_IO)][i] = NULL; 24470Sstevel@tonic-gate dp = (sbd_dev_unit_t *)SBD_GET_BOARD_IOUNIT(sbp, i); 24480Sstevel@tonic-gate dp->u_common.sbdev_sbp = sbp; 24490Sstevel@tonic-gate dp->u_common.sbdev_unum = i; 24500Sstevel@tonic-gate dp->u_common.sbdev_type = SBD_COMP_IO; 24510Sstevel@tonic-gate } 24520Sstevel@tonic-gate 24530Sstevel@tonic-gate wp->sbp = sbp; 24540Sstevel@tonic-gate wp->nmc = 0; 24550Sstevel@tonic-gate sbp->sb_ndev = 0; 24560Sstevel@tonic-gate 24570Sstevel@tonic-gate /* 24580Sstevel@tonic-gate * ddi_walk_devs() requires that topdip's parent be held. 24590Sstevel@tonic-gate */ 24600Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 24610Sstevel@tonic-gate if (pdip) { 24620Sstevel@tonic-gate ndi_hold_devi(pdip); 24630Sstevel@tonic-gate ndi_devi_enter(pdip, &i); 24640Sstevel@tonic-gate } 24650Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, sbd_setup_devlists, (void *) wp); 24660Sstevel@tonic-gate if (pdip) { 24670Sstevel@tonic-gate ndi_devi_exit(pdip, i); 24680Sstevel@tonic-gate ndi_rele_devi(pdip); 24690Sstevel@tonic-gate } 24700Sstevel@tonic-gate 24710Sstevel@tonic-gate /* 24720Sstevel@tonic-gate * There is no point checking all the components if there 24730Sstevel@tonic-gate * are no devices. 24740Sstevel@tonic-gate */ 24750Sstevel@tonic-gate if (sbp->sb_ndev == 0) { 24760Sstevel@tonic-gate sbp->sb_memaccess_ok = 0; 24770Sstevel@tonic-gate return (sbp->sb_ndev); 24780Sstevel@tonic-gate } 24790Sstevel@tonic-gate 24800Sstevel@tonic-gate /* 24810Sstevel@tonic-gate * Initialize cpu sections before calling sbd_init_mem_devlists 24820Sstevel@tonic-gate * which will access the mmus. 24830Sstevel@tonic-gate */ 24840Sstevel@tonic-gate sbp->sb_memaccess_ok = 1; 24850Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 24860Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) { 24870Sstevel@tonic-gate sbd_init_cpu_unit(sbp, i); 24880Sstevel@tonic-gate if (sbd_connect_cpu(sbp, i)) { 24890Sstevel@tonic-gate SBD_SET_ERR(HD2MACHERR(MACHBD2HD(sbp)), 24900Sstevel@tonic-gate ESBD_CPUSTART); 24910Sstevel@tonic-gate } 24920Sstevel@tonic-gate 24930Sstevel@tonic-gate } 24940Sstevel@tonic-gate } 24950Sstevel@tonic-gate 24960Sstevel@tonic-gate if (sbp->sb_memaccess_ok) { 24970Sstevel@tonic-gate sbd_init_mem_devlists(sbp); 24980Sstevel@tonic-gate } else { 24990Sstevel@tonic-gate cmn_err(CE_WARN, "unable to access memory on board %d", 25000Sstevel@tonic-gate sbp->sb_num); 25010Sstevel@tonic-gate } 25020Sstevel@tonic-gate 25030Sstevel@tonic-gate return (sbp->sb_ndev); 25040Sstevel@tonic-gate } 25050Sstevel@tonic-gate 25060Sstevel@tonic-gate static void 25070Sstevel@tonic-gate sbd_init_cpu_unit(sbd_board_t *sbp, int unit) 25080Sstevel@tonic-gate { 25090Sstevel@tonic-gate sbd_istate_t new_state; 25100Sstevel@tonic-gate sbd_cpu_unit_t *cp; 25110Sstevel@tonic-gate int cpuid; 25120Sstevel@tonic-gate dev_info_t *dip; 25130Sstevel@tonic-gate sbdp_handle_t *hdp; 25140Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 25150Sstevel@tonic-gate extern kmutex_t cpu_lock; 25160Sstevel@tonic-gate 25170Sstevel@tonic-gate if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, unit)) { 25180Sstevel@tonic-gate new_state = SBD_STATE_CONFIGURED; 25190Sstevel@tonic-gate } else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, unit)) { 25200Sstevel@tonic-gate new_state = SBD_STATE_CONNECTED; 25210Sstevel@tonic-gate } else { 25220Sstevel@tonic-gate new_state = SBD_STATE_EMPTY; 25230Sstevel@tonic-gate } 25240Sstevel@tonic-gate 25250Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit]; 25260Sstevel@tonic-gate 25270Sstevel@tonic-gate cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 25280Sstevel@tonic-gate 25290Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 25300Sstevel@tonic-gate 25310Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 25320Sstevel@tonic-gate 25330Sstevel@tonic-gate cp->sbc_cpu_id = cpuid; 25340Sstevel@tonic-gate 25350Sstevel@tonic-gate if (&sbdp_cpu_get_impl) 25360Sstevel@tonic-gate cp->sbc_cpu_impl = sbdp_cpu_get_impl(hdp, dip); 25370Sstevel@tonic-gate else 25380Sstevel@tonic-gate cp->sbc_cpu_impl = -1; 25390Sstevel@tonic-gate 25400Sstevel@tonic-gate mutex_enter(&cpu_lock); 25410Sstevel@tonic-gate if ((cpuid >= 0) && cpu[cpuid]) 25420Sstevel@tonic-gate cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 25430Sstevel@tonic-gate else 25440Sstevel@tonic-gate cp->sbc_cpu_flags = CPU_OFFLINE | CPU_POWEROFF; 25450Sstevel@tonic-gate mutex_exit(&cpu_lock); 25460Sstevel@tonic-gate 25470Sstevel@tonic-gate sbd_cpu_set_prop(cp, dip); 25480Sstevel@tonic-gate 25490Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = sbd_get_comp_cond(dip); 25500Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 25510Sstevel@tonic-gate 25520Sstevel@tonic-gate /* 25530Sstevel@tonic-gate * Any changes to the cpu should be performed above 25540Sstevel@tonic-gate * this call to ensure the cpu is fully initialized 25550Sstevel@tonic-gate * before transitioning to the new state. 25560Sstevel@tonic-gate */ 25570Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, unit, new_state); 25580Sstevel@tonic-gate } 25590Sstevel@tonic-gate 25600Sstevel@tonic-gate /* 25610Sstevel@tonic-gate * Only do work if called to operate on an entire board 25620Sstevel@tonic-gate * which doesn't already have components present. 25630Sstevel@tonic-gate */ 25640Sstevel@tonic-gate static void 25650Sstevel@tonic-gate sbd_connect(sbd_handle_t *hp) 25660Sstevel@tonic-gate { 25670Sstevel@tonic-gate sbd_board_t *sbp; 25680Sstevel@tonic-gate sbderror_t *ep; 25690Sstevel@tonic-gate static fn_t f = "sbd_connect"; 25700Sstevel@tonic-gate 25710Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 25720Sstevel@tonic-gate 25730Sstevel@tonic-gate PR_ALL("%s board %d\n", f, sbp->sb_num); 25740Sstevel@tonic-gate 25750Sstevel@tonic-gate ep = HD2MACHERR(hp); 25760Sstevel@tonic-gate 25770Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp)) { 25780Sstevel@tonic-gate /* 25790Sstevel@tonic-gate * Board already has devices present. 25800Sstevel@tonic-gate */ 25810Sstevel@tonic-gate PR_ALL("%s: devices already present (0x%x)\n", 25820Sstevel@tonic-gate f, SBD_DEVS_PRESENT(sbp)); 25830Sstevel@tonic-gate SBD_SET_ERRNO(ep, EINVAL); 25840Sstevel@tonic-gate return; 25850Sstevel@tonic-gate } 25860Sstevel@tonic-gate 25870Sstevel@tonic-gate if (sbd_init_devlists(sbp) == 0) { 25880Sstevel@tonic-gate cmn_err(CE_WARN, "%s: no devices present on board %d", 25890Sstevel@tonic-gate f, sbp->sb_num); 25900Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_NODEV); 25910Sstevel@tonic-gate return; 25920Sstevel@tonic-gate } else { 25930Sstevel@tonic-gate int i; 25940Sstevel@tonic-gate 25950Sstevel@tonic-gate /* 25960Sstevel@tonic-gate * Initialize mem-unit section of board structure. 25970Sstevel@tonic-gate */ 25980Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 25990Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) 26000Sstevel@tonic-gate sbd_init_mem_unit(sbp, i, SBD_HD2ERR(hp)); 26010Sstevel@tonic-gate 26020Sstevel@tonic-gate /* 26030Sstevel@tonic-gate * Initialize sb_io sections. 26040Sstevel@tonic-gate */ 26050Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 26060Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i)) 26070Sstevel@tonic-gate sbd_init_io_unit(sbp, i); 26080Sstevel@tonic-gate 26090Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED); 26100Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 26110Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 26120Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 26130Sstevel@tonic-gate SBD_INJECT_ERR(SBD_CONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO, 26140Sstevel@tonic-gate ESBD_INTERNAL, NULL); 26150Sstevel@tonic-gate } 26160Sstevel@tonic-gate } 26170Sstevel@tonic-gate 26180Sstevel@tonic-gate static int 26190Sstevel@tonic-gate sbd_disconnect(sbd_handle_t *hp) 26200Sstevel@tonic-gate { 26210Sstevel@tonic-gate int i; 26220Sstevel@tonic-gate sbd_devset_t devset; 26230Sstevel@tonic-gate sbd_board_t *sbp; 26240Sstevel@tonic-gate static fn_t f = "sbd_disconnect it"; 26250Sstevel@tonic-gate 26260Sstevel@tonic-gate PR_ALL("%s ...\n", f); 26270Sstevel@tonic-gate 26280Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 26290Sstevel@tonic-gate 26300Sstevel@tonic-gate /* 26310Sstevel@tonic-gate * Only devices which are present, but 26320Sstevel@tonic-gate * unattached can be disconnected. 26330Sstevel@tonic-gate */ 26340Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_PRESENT(sbp) & 26350Sstevel@tonic-gate SBD_DEVS_UNATTACHED(sbp); 26360Sstevel@tonic-gate 26370Sstevel@tonic-gate ASSERT((SBD_DEVS_ATTACHED(sbp) & devset) == 0); 26380Sstevel@tonic-gate 26390Sstevel@tonic-gate /* 26400Sstevel@tonic-gate * Update per-device state transitions. 26410Sstevel@tonic-gate */ 26420Sstevel@tonic-gate 26430Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 26440Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) { 26450Sstevel@tonic-gate if (sbd_disconnect_mem(hp, i) == 0) { 26460Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 26470Sstevel@tonic-gate SBD_STATE_EMPTY); 26480Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i); 26490Sstevel@tonic-gate } 26500Sstevel@tonic-gate } 26510Sstevel@tonic-gate 26520Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) 26530Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) { 26540Sstevel@tonic-gate if (sbd_disconnect_cpu(hp, i) == 0) { 26550Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 26560Sstevel@tonic-gate SBD_STATE_EMPTY); 26570Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_CPU, i); 26580Sstevel@tonic-gate } 26590Sstevel@tonic-gate } 26600Sstevel@tonic-gate 26610Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 26620Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, i)) { 26630Sstevel@tonic-gate if (sbd_disconnect_io(hp, i) == 0) { 26640Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i, 26650Sstevel@tonic-gate SBD_STATE_EMPTY); 26660Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_IO, i); 26670Sstevel@tonic-gate } 26680Sstevel@tonic-gate } 26690Sstevel@tonic-gate 26700Sstevel@tonic-gate /* 26710Sstevel@tonic-gate * Once all the components on a board have been disconnect 26720Sstevel@tonic-gate * the board's state can transition to disconnected and 26730Sstevel@tonic-gate * we can allow the deprobe to take place. 26740Sstevel@tonic-gate */ 26750Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp) == 0) { 26760Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_OCCUPIED); 26770Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_DISCONNECTED; 26780Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 26790Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 26800Sstevel@tonic-gate SBD_INJECT_ERR(SBD_DISCONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO, 26810Sstevel@tonic-gate ESBD_INTERNAL, NULL); 26820Sstevel@tonic-gate return (0); 26830Sstevel@tonic-gate } else { 26840Sstevel@tonic-gate cmn_err(CE_WARN, "%s: could not disconnect devices on board %d", 26850Sstevel@tonic-gate f, sbp->sb_num); 26860Sstevel@tonic-gate return (-1); 26870Sstevel@tonic-gate } 26880Sstevel@tonic-gate } 26890Sstevel@tonic-gate 26900Sstevel@tonic-gate static void 26910Sstevel@tonic-gate sbd_test_board(sbd_handle_t *hp) 26920Sstevel@tonic-gate { 26930Sstevel@tonic-gate sbd_board_t *sbp; 26940Sstevel@tonic-gate sbdp_handle_t *hdp; 26950Sstevel@tonic-gate 26960Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 26970Sstevel@tonic-gate 26980Sstevel@tonic-gate PR_ALL("sbd_test_board: board %d\n", sbp->sb_num); 26990Sstevel@tonic-gate 27000Sstevel@tonic-gate 27010Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 27020Sstevel@tonic-gate 27030Sstevel@tonic-gate if (sbdp_test_board(hdp, &hp->h_opts) != 0) { 27040Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 27050Sstevel@tonic-gate 27060Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 27070Sstevel@tonic-gate } 27080Sstevel@tonic-gate 27090Sstevel@tonic-gate SBD_INJECT_ERR(SBD_TEST_BOARD_PSEUDO_ERR, hp->h_err, EIO, 27100Sstevel@tonic-gate ESBD_INTERNAL, NULL); 27110Sstevel@tonic-gate 27120Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 27130Sstevel@tonic-gate } 27140Sstevel@tonic-gate 27150Sstevel@tonic-gate static void 27160Sstevel@tonic-gate sbd_assign_board(sbd_handle_t *hp) 27170Sstevel@tonic-gate { 27180Sstevel@tonic-gate sbd_board_t *sbp; 27190Sstevel@tonic-gate sbdp_handle_t *hdp; 27200Sstevel@tonic-gate 27210Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 27220Sstevel@tonic-gate 27230Sstevel@tonic-gate PR_ALL("sbd_assign_board: board %d\n", sbp->sb_num); 27240Sstevel@tonic-gate 27250Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 27260Sstevel@tonic-gate 27270Sstevel@tonic-gate if (sbdp_assign_board(hdp) != 0) { 27280Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 27290Sstevel@tonic-gate 27300Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 27310Sstevel@tonic-gate } 27320Sstevel@tonic-gate 27330Sstevel@tonic-gate SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO, 27340Sstevel@tonic-gate ESBD_INTERNAL, NULL); 27350Sstevel@tonic-gate 27360Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 27370Sstevel@tonic-gate } 27380Sstevel@tonic-gate 27390Sstevel@tonic-gate static void 27400Sstevel@tonic-gate sbd_unassign_board(sbd_handle_t *hp) 27410Sstevel@tonic-gate { 27420Sstevel@tonic-gate sbd_board_t *sbp; 27430Sstevel@tonic-gate sbdp_handle_t *hdp; 27440Sstevel@tonic-gate 27450Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 27460Sstevel@tonic-gate 27470Sstevel@tonic-gate PR_ALL("sbd_unassign_board: board %d\n", sbp->sb_num); 27480Sstevel@tonic-gate 27490Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 27500Sstevel@tonic-gate 27510Sstevel@tonic-gate if (sbdp_unassign_board(hdp) != 0) { 27520Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 27530Sstevel@tonic-gate 27540Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 27550Sstevel@tonic-gate } 27560Sstevel@tonic-gate 27570Sstevel@tonic-gate SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO, 27580Sstevel@tonic-gate ESBD_INTERNAL, NULL); 27590Sstevel@tonic-gate 27600Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 27610Sstevel@tonic-gate } 27620Sstevel@tonic-gate 27630Sstevel@tonic-gate static void 27640Sstevel@tonic-gate sbd_poweron_board(sbd_handle_t *hp) 27650Sstevel@tonic-gate { 27660Sstevel@tonic-gate sbd_board_t *sbp; 27670Sstevel@tonic-gate sbdp_handle_t *hdp; 27680Sstevel@tonic-gate 27690Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 27700Sstevel@tonic-gate 27710Sstevel@tonic-gate PR_ALL("sbd_poweron_board: %d\n", sbp->sb_num); 27720Sstevel@tonic-gate 27730Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 27740Sstevel@tonic-gate 27750Sstevel@tonic-gate if (sbdp_poweron_board(hdp) != 0) { 27760Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 27770Sstevel@tonic-gate 27780Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 27790Sstevel@tonic-gate } 27800Sstevel@tonic-gate 27810Sstevel@tonic-gate SBD_INJECT_ERR(SBD_POWERON_BOARD_PSEUDO_ERR, hp->h_err, EIO, 27820Sstevel@tonic-gate ESBD_INTERNAL, NULL); 27830Sstevel@tonic-gate 27840Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 27850Sstevel@tonic-gate } 27860Sstevel@tonic-gate 27870Sstevel@tonic-gate static void 27880Sstevel@tonic-gate sbd_poweroff_board(sbd_handle_t *hp) 27890Sstevel@tonic-gate { 27900Sstevel@tonic-gate sbd_board_t *sbp; 27910Sstevel@tonic-gate sbdp_handle_t *hdp; 27920Sstevel@tonic-gate 27930Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 27940Sstevel@tonic-gate 27950Sstevel@tonic-gate PR_ALL("sbd_poweroff_board: %d\n", sbp->sb_num); 27960Sstevel@tonic-gate 27970Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 27980Sstevel@tonic-gate 27990Sstevel@tonic-gate if (sbdp_poweroff_board(hdp) != 0) { 28000Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 28010Sstevel@tonic-gate 28020Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 28030Sstevel@tonic-gate } 28040Sstevel@tonic-gate 28050Sstevel@tonic-gate SBD_INJECT_ERR(SBD_POWEROFF_BOARD_PSEUDO_ERR, hp->h_err, EIO, 28060Sstevel@tonic-gate ESBD_INTERNAL, NULL); 28070Sstevel@tonic-gate 28080Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 28090Sstevel@tonic-gate } 28100Sstevel@tonic-gate 28110Sstevel@tonic-gate 28120Sstevel@tonic-gate /* 28130Sstevel@tonic-gate * Return a list of the dip's of devices that are 28140Sstevel@tonic-gate * either present and attached, or present only but 28150Sstevel@tonic-gate * not yet attached for the given board. 28160Sstevel@tonic-gate */ 28170Sstevel@tonic-gate sbd_devlist_t * 28180Sstevel@tonic-gate sbd_get_devlist(sbd_handle_t *hp, sbd_board_t *sbp, sbd_comp_type_t nodetype, 28190Sstevel@tonic-gate int max_units, uint_t uset, int *count, int present_only) 28200Sstevel@tonic-gate { 28210Sstevel@tonic-gate int i, ix; 28220Sstevel@tonic-gate sbd_devlist_t *ret_devlist; 28230Sstevel@tonic-gate dev_info_t **devlist; 28240Sstevel@tonic-gate sbdp_handle_t *hdp; 28250Sstevel@tonic-gate 28260Sstevel@tonic-gate *count = 0; 28270Sstevel@tonic-gate ret_devlist = GETSTRUCT(sbd_devlist_t, max_units); 28280Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(nodetype)]; 28290Sstevel@tonic-gate /* 28300Sstevel@tonic-gate * Turn into binary value since we're going 28310Sstevel@tonic-gate * to be using XOR for a comparison. 28320Sstevel@tonic-gate * if (present_only) then 28330Sstevel@tonic-gate * dev must be PRESENT, but NOT ATTACHED. 28340Sstevel@tonic-gate * else 28350Sstevel@tonic-gate * dev must be PRESENT AND ATTACHED. 28360Sstevel@tonic-gate * endif 28370Sstevel@tonic-gate */ 28380Sstevel@tonic-gate if (present_only) 28390Sstevel@tonic-gate present_only = 1; 28400Sstevel@tonic-gate 28410Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 28420Sstevel@tonic-gate 28430Sstevel@tonic-gate for (i = ix = 0; (i < max_units) && uset; i++) { 28440Sstevel@tonic-gate int ut, is_present, is_attached; 28450Sstevel@tonic-gate dev_info_t *dip; 28460Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 28470Sstevel@tonic-gate int nunits, distance, j; 28480Sstevel@tonic-gate 28490Sstevel@tonic-gate /* 28500Sstevel@tonic-gate * For CMPs, we would like to perform DR operation on 28510Sstevel@tonic-gate * all the cores before moving onto the next chip. 28520Sstevel@tonic-gate * Therefore, when constructing the devlist, we process 28530Sstevel@tonic-gate * all the cores together. 28540Sstevel@tonic-gate */ 28550Sstevel@tonic-gate if (nodetype == SBD_COMP_CPU) { 28560Sstevel@tonic-gate /* 28570Sstevel@tonic-gate * Number of units to process in the inner loop 28580Sstevel@tonic-gate */ 28590Sstevel@tonic-gate nunits = MAX_CORES_PER_CMP; 28600Sstevel@tonic-gate /* 28610Sstevel@tonic-gate * The distance between the units in the 28620Sstevel@tonic-gate * board's sb_devlist structure. 28630Sstevel@tonic-gate */ 28640Sstevel@tonic-gate distance = MAX_CMP_UNITS_PER_BOARD; 28650Sstevel@tonic-gate } else { 28660Sstevel@tonic-gate nunits = 1; 28670Sstevel@tonic-gate distance = 0; 28680Sstevel@tonic-gate } 28690Sstevel@tonic-gate 28700Sstevel@tonic-gate for (j = 0; j < nunits; j++) { 28710Sstevel@tonic-gate if ((dip = devlist[i + j * distance]) == NULL) 28720Sstevel@tonic-gate continue; 28730Sstevel@tonic-gate 28740Sstevel@tonic-gate ut = sbdp_get_unit_num(hdp, dip); 28750Sstevel@tonic-gate 28760Sstevel@tonic-gate if (ut == -1) { 28770Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 28780Sstevel@tonic-gate PR_ALL("sbd_get_devlist bad unit %d" 28790Sstevel@tonic-gate " code %d errno %d", 28800Sstevel@tonic-gate i, ep->e_code, ep->e_errno); 28810Sstevel@tonic-gate } 28820Sstevel@tonic-gate 28830Sstevel@tonic-gate if ((uset & (1 << ut)) == 0) 28840Sstevel@tonic-gate continue; 28850Sstevel@tonic-gate uset &= ~(1 << ut); 28860Sstevel@tonic-gate is_present = SBD_DEV_IS_PRESENT(sbp, nodetype, ut) ? 28870Sstevel@tonic-gate 1 : 0; 28880Sstevel@tonic-gate is_attached = SBD_DEV_IS_ATTACHED(sbp, nodetype, ut) ? 28890Sstevel@tonic-gate 1 : 0; 28900Sstevel@tonic-gate 28910Sstevel@tonic-gate if (is_present && (present_only ^ is_attached)) { 28920Sstevel@tonic-gate ret_devlist[ix].dv_dip = dip; 28930Sstevel@tonic-gate sbd_init_err(&ret_devlist[ix].dv_error); 28940Sstevel@tonic-gate ix++; 28950Sstevel@tonic-gate } 28960Sstevel@tonic-gate } 28970Sstevel@tonic-gate } 28980Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 28990Sstevel@tonic-gate 29000Sstevel@tonic-gate if ((*count = ix) == 0) { 29010Sstevel@tonic-gate FREESTRUCT(ret_devlist, sbd_devlist_t, max_units); 29020Sstevel@tonic-gate ret_devlist = NULL; 29030Sstevel@tonic-gate } 29040Sstevel@tonic-gate 29050Sstevel@tonic-gate return (ret_devlist); 29060Sstevel@tonic-gate } 29070Sstevel@tonic-gate 29080Sstevel@tonic-gate static sbd_devlist_t * 29090Sstevel@tonic-gate sbd_get_attach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 29100Sstevel@tonic-gate { 29110Sstevel@tonic-gate sbd_board_t *sbp; 29120Sstevel@tonic-gate uint_t uset; 29130Sstevel@tonic-gate sbd_devset_t devset; 29140Sstevel@tonic-gate sbd_devlist_t *attach_devlist; 29150Sstevel@tonic-gate static int next_pass = 1; 29160Sstevel@tonic-gate static fn_t f = "sbd_get_attach_devlist"; 29170Sstevel@tonic-gate 29180Sstevel@tonic-gate PR_ALL("%s (pass = %d)...\n", f, pass); 29190Sstevel@tonic-gate 29200Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 29210Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset; 29220Sstevel@tonic-gate 29230Sstevel@tonic-gate *devnump = 0; 29240Sstevel@tonic-gate attach_devlist = NULL; 29250Sstevel@tonic-gate 29260Sstevel@tonic-gate /* 29270Sstevel@tonic-gate * We switch on next_pass for the cases where a board 29280Sstevel@tonic-gate * does not contain a particular type of component. 29290Sstevel@tonic-gate * In these situations we don't want to return NULL 29300Sstevel@tonic-gate * prematurely. We need to check other devices and 29310Sstevel@tonic-gate * we don't want to check the same type multiple times. 29320Sstevel@tonic-gate * For example, if there were no cpus, then on pass 1 29330Sstevel@tonic-gate * we would drop through and return the memory nodes. 29340Sstevel@tonic-gate * However, on pass 2 we would switch back to the memory 29350Sstevel@tonic-gate * nodes thereby returning them twice! Using next_pass 29360Sstevel@tonic-gate * forces us down to the end (or next item). 29370Sstevel@tonic-gate */ 29380Sstevel@tonic-gate if (pass == 1) 29390Sstevel@tonic-gate next_pass = 1; 29400Sstevel@tonic-gate 29410Sstevel@tonic-gate switch (next_pass) { 29420Sstevel@tonic-gate case 1: 29430Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 29440Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 29450Sstevel@tonic-gate 29460Sstevel@tonic-gate attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_CPU, 29470Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, 29480Sstevel@tonic-gate uset, devnump, 1); 29490Sstevel@tonic-gate 29500Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 29510Sstevel@tonic-gate if (!devset || attach_devlist) { 29520Sstevel@tonic-gate next_pass = 2; 29530Sstevel@tonic-gate return (attach_devlist); 29540Sstevel@tonic-gate } 29550Sstevel@tonic-gate /* 29560Sstevel@tonic-gate * If the caller is interested in the entire 29570Sstevel@tonic-gate * board, but there aren't any cpus, then just 29580Sstevel@tonic-gate * fall through to check for the next component. 29590Sstevel@tonic-gate */ 29600Sstevel@tonic-gate } 29610Sstevel@tonic-gate /*FALLTHROUGH*/ 29620Sstevel@tonic-gate 29630Sstevel@tonic-gate case 2: 29640Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 29650Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 29660Sstevel@tonic-gate 29670Sstevel@tonic-gate attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_MEM, 29680Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD, 29690Sstevel@tonic-gate uset, devnump, 1); 29700Sstevel@tonic-gate 29710Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 29720Sstevel@tonic-gate if (!devset || attach_devlist) { 29730Sstevel@tonic-gate next_pass = 3; 29740Sstevel@tonic-gate return (attach_devlist); 29750Sstevel@tonic-gate } 29760Sstevel@tonic-gate /* 29770Sstevel@tonic-gate * If the caller is interested in the entire 29780Sstevel@tonic-gate * board, but there isn't any memory, then 29790Sstevel@tonic-gate * just fall through to next component. 29800Sstevel@tonic-gate */ 29810Sstevel@tonic-gate } 29820Sstevel@tonic-gate /*FALLTHROUGH*/ 29830Sstevel@tonic-gate 29840Sstevel@tonic-gate 29850Sstevel@tonic-gate case 3: 29860Sstevel@tonic-gate next_pass = -1; 29870Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 29880Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 29890Sstevel@tonic-gate 29900Sstevel@tonic-gate attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_IO, 29910Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD, 29920Sstevel@tonic-gate uset, devnump, 1); 29930Sstevel@tonic-gate 29940Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 29950Sstevel@tonic-gate if (!devset || attach_devlist) { 29960Sstevel@tonic-gate next_pass = 4; 29970Sstevel@tonic-gate return (attach_devlist); 29980Sstevel@tonic-gate } 29990Sstevel@tonic-gate } 30000Sstevel@tonic-gate /*FALLTHROUGH*/ 30010Sstevel@tonic-gate 30020Sstevel@tonic-gate default: 30030Sstevel@tonic-gate *devnump = 0; 30040Sstevel@tonic-gate return (NULL); 30050Sstevel@tonic-gate } 30060Sstevel@tonic-gate /*NOTREACHED*/ 30070Sstevel@tonic-gate } 30080Sstevel@tonic-gate 30090Sstevel@tonic-gate static int 30100Sstevel@tonic-gate sbd_pre_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 30110Sstevel@tonic-gate int32_t devnum) 30120Sstevel@tonic-gate { 30130Sstevel@tonic-gate int max_units = 0, rv = 0; 30140Sstevel@tonic-gate sbd_comp_type_t nodetype; 30150Sstevel@tonic-gate static fn_t f = "sbd_pre_attach_devlist"; 30160Sstevel@tonic-gate 30170Sstevel@tonic-gate /* 30180Sstevel@tonic-gate * In this driver, all entries in a devlist[] are 30190Sstevel@tonic-gate * of the same nodetype. 30200Sstevel@tonic-gate */ 30210Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 30220Sstevel@tonic-gate 30230Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 30240Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 30250Sstevel@tonic-gate 30260Sstevel@tonic-gate switch (nodetype) { 30270Sstevel@tonic-gate 30280Sstevel@tonic-gate case SBD_COMP_MEM: 30290Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 30300Sstevel@tonic-gate rv = sbd_pre_attach_mem(hp, devlist, devnum); 30310Sstevel@tonic-gate break; 30320Sstevel@tonic-gate 30330Sstevel@tonic-gate case SBD_COMP_CPU: 30340Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 30350Sstevel@tonic-gate rv = sbd_pre_attach_cpu(hp, devlist, devnum); 30360Sstevel@tonic-gate break; 30370Sstevel@tonic-gate 30380Sstevel@tonic-gate case SBD_COMP_IO: 30390Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 30400Sstevel@tonic-gate break; 30410Sstevel@tonic-gate 30420Sstevel@tonic-gate default: 30430Sstevel@tonic-gate rv = -1; 30440Sstevel@tonic-gate break; 30450Sstevel@tonic-gate } 30460Sstevel@tonic-gate 30470Sstevel@tonic-gate if (rv && max_units) { 30480Sstevel@tonic-gate int i; 30490Sstevel@tonic-gate /* 30500Sstevel@tonic-gate * Need to clean up devlist 30510Sstevel@tonic-gate * if pre-op is going to fail. 30520Sstevel@tonic-gate */ 30530Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 30540Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 30550Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 30560Sstevel@tonic-gate } else { 30570Sstevel@tonic-gate break; 30580Sstevel@tonic-gate } 30590Sstevel@tonic-gate } 30600Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 30610Sstevel@tonic-gate } 30620Sstevel@tonic-gate 30630Sstevel@tonic-gate /* 30640Sstevel@tonic-gate * If an error occurred, return "continue" 30650Sstevel@tonic-gate * indication so that we can continue attaching 30660Sstevel@tonic-gate * as much as possible. 30670Sstevel@tonic-gate */ 30680Sstevel@tonic-gate return (rv ? -1 : 0); 30690Sstevel@tonic-gate } 30700Sstevel@tonic-gate 30710Sstevel@tonic-gate static int 30720Sstevel@tonic-gate sbd_post_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 30730Sstevel@tonic-gate int32_t devnum) 30740Sstevel@tonic-gate { 30750Sstevel@tonic-gate int i, max_units = 0, rv = 0; 30760Sstevel@tonic-gate sbd_devset_t devs_unattached, devs_present; 30770Sstevel@tonic-gate sbd_comp_type_t nodetype; 30780Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 30790Sstevel@tonic-gate sbdp_handle_t *hdp; 30800Sstevel@tonic-gate static fn_t f = "sbd_post_attach_devlist"; 30810Sstevel@tonic-gate 30820Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 30830Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 30840Sstevel@tonic-gate 30850Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 30860Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 30870Sstevel@tonic-gate 30880Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 30890Sstevel@tonic-gate 30900Sstevel@tonic-gate /* 30910Sstevel@tonic-gate * Need to free up devlist[] created earlier in 30920Sstevel@tonic-gate * sbd_get_attach_devlist(). 30930Sstevel@tonic-gate */ 30940Sstevel@tonic-gate switch (nodetype) { 30950Sstevel@tonic-gate case SBD_COMP_CPU: 30960Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 30970Sstevel@tonic-gate rv = sbd_post_attach_cpu(hp, devlist, devnum); 30980Sstevel@tonic-gate break; 30990Sstevel@tonic-gate 31000Sstevel@tonic-gate 31010Sstevel@tonic-gate case SBD_COMP_MEM: 31020Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 31030Sstevel@tonic-gate 31040Sstevel@tonic-gate rv = sbd_post_attach_mem(hp, devlist, devnum); 31050Sstevel@tonic-gate break; 31060Sstevel@tonic-gate 31070Sstevel@tonic-gate case SBD_COMP_IO: 31080Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 31090Sstevel@tonic-gate break; 31100Sstevel@tonic-gate 31110Sstevel@tonic-gate default: 31120Sstevel@tonic-gate rv = -1; 31130Sstevel@tonic-gate break; 31140Sstevel@tonic-gate } 31150Sstevel@tonic-gate 31160Sstevel@tonic-gate 31170Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 31180Sstevel@tonic-gate int unit; 31190Sstevel@tonic-gate dev_info_t *dip; 31200Sstevel@tonic-gate sbderror_t *ep; 31210Sstevel@tonic-gate 31220Sstevel@tonic-gate ep = &devlist[i].dv_error; 31230Sstevel@tonic-gate 31240Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) 31250Sstevel@tonic-gate continue; 31260Sstevel@tonic-gate 31270Sstevel@tonic-gate dip = devlist[i].dv_dip; 31280Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 31290Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 31300Sstevel@tonic-gate 31310Sstevel@tonic-gate if (unit == -1) { 31320Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 31330Sstevel@tonic-gate continue; 31340Sstevel@tonic-gate } 31350Sstevel@tonic-gate 31360Sstevel@tonic-gate unit = sbd_check_unit_attached(sbp, dip, unit, nodetype, ep); 31370Sstevel@tonic-gate 31380Sstevel@tonic-gate if (unit == -1) { 31390Sstevel@tonic-gate PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not attached\n", 31400Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], sbp->sb_num, i); 31410Sstevel@tonic-gate continue; 31420Sstevel@tonic-gate } 31430Sstevel@tonic-gate 31440Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, nodetype, unit); 31450Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, nodetype, unit, 31460Sstevel@tonic-gate SBD_STATE_CONFIGURED); 31470Sstevel@tonic-gate } 31480Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 31490Sstevel@tonic-gate 31500Sstevel@tonic-gate if (rv) { 31510Sstevel@tonic-gate PR_ALL("%s: errno %d, ecode %d during attach\n", 31520Sstevel@tonic-gate f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 31530Sstevel@tonic-gate SBD_GET_ERR(HD2MACHERR(hp))); 31540Sstevel@tonic-gate } 31550Sstevel@tonic-gate 31560Sstevel@tonic-gate devs_present = SBD_DEVS_PRESENT(sbp); 31570Sstevel@tonic-gate devs_unattached = SBD_DEVS_UNATTACHED(sbp); 31580Sstevel@tonic-gate 31590Sstevel@tonic-gate switch (SBD_BOARD_STATE(sbp)) { 31600Sstevel@tonic-gate case SBD_STATE_CONNECTED: 31610Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 31620Sstevel@tonic-gate ASSERT(devs_present); 31630Sstevel@tonic-gate 31640Sstevel@tonic-gate if (devs_unattached == 0) { 31650Sstevel@tonic-gate /* 31660Sstevel@tonic-gate * All devices finally attached. 31670Sstevel@tonic-gate */ 31680Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 31690Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 31700Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_CONFIGURED; 31710Sstevel@tonic-gate } else if (devs_present != devs_unattached) { 31720Sstevel@tonic-gate /* 31730Sstevel@tonic-gate * Only some devices are fully attached. 31740Sstevel@tonic-gate */ 31750Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 31760Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 31770Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 31780Sstevel@tonic-gate } 31790Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 31800Sstevel@tonic-gate break; 31810Sstevel@tonic-gate 31820Sstevel@tonic-gate case SBD_STATE_PARTIAL: 31830Sstevel@tonic-gate ASSERT(devs_present); 31840Sstevel@tonic-gate /* 31850Sstevel@tonic-gate * All devices finally attached. 31860Sstevel@tonic-gate */ 31870Sstevel@tonic-gate if (devs_unattached == 0) { 31880Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 31890Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 31900Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_CONFIGURED; 31910Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 31920Sstevel@tonic-gate } 31930Sstevel@tonic-gate break; 31940Sstevel@tonic-gate 31950Sstevel@tonic-gate default: 31960Sstevel@tonic-gate break; 31970Sstevel@tonic-gate } 31980Sstevel@tonic-gate 31990Sstevel@tonic-gate if (max_units && devlist) { 32000Sstevel@tonic-gate int i; 32010Sstevel@tonic-gate 32020Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 32030Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 32040Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 32050Sstevel@tonic-gate } else { 32060Sstevel@tonic-gate break; 32070Sstevel@tonic-gate } 32080Sstevel@tonic-gate } 32090Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 32100Sstevel@tonic-gate } 32110Sstevel@tonic-gate 32120Sstevel@tonic-gate /* 32130Sstevel@tonic-gate * Our policy is to attach all components that are 32140Sstevel@tonic-gate * possible, thus we always return "success" on the 32150Sstevel@tonic-gate * pre and post operations. 32160Sstevel@tonic-gate */ 32170Sstevel@tonic-gate return (0); 32180Sstevel@tonic-gate } 32190Sstevel@tonic-gate 32200Sstevel@tonic-gate /* 32210Sstevel@tonic-gate * We only need to "release" cpu and memory devices. 32220Sstevel@tonic-gate */ 32230Sstevel@tonic-gate static sbd_devlist_t * 32240Sstevel@tonic-gate sbd_get_release_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 32250Sstevel@tonic-gate { 32260Sstevel@tonic-gate sbd_board_t *sbp; 32270Sstevel@tonic-gate uint_t uset; 32280Sstevel@tonic-gate sbd_devset_t devset; 32290Sstevel@tonic-gate sbd_devlist_t *release_devlist; 32300Sstevel@tonic-gate static int next_pass = 1; 32310Sstevel@tonic-gate static fn_t f = "sbd_get_release_devlist"; 32320Sstevel@tonic-gate 32330Sstevel@tonic-gate PR_ALL("%s (pass = %d)...\n", f, pass); 32340Sstevel@tonic-gate 32350Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 32360Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset; 32370Sstevel@tonic-gate 32380Sstevel@tonic-gate *devnump = 0; 32390Sstevel@tonic-gate release_devlist = NULL; 32400Sstevel@tonic-gate 32410Sstevel@tonic-gate /* 32420Sstevel@tonic-gate * We switch on next_pass for the cases where a board 32430Sstevel@tonic-gate * does not contain a particular type of component. 32440Sstevel@tonic-gate * In these situations we don't want to return NULL 32450Sstevel@tonic-gate * prematurely. We need to check other devices and 32460Sstevel@tonic-gate * we don't want to check the same type multiple times. 32470Sstevel@tonic-gate * For example, if there were no cpus, then on pass 1 32480Sstevel@tonic-gate * we would drop through and return the memory nodes. 32490Sstevel@tonic-gate * However, on pass 2 we would switch back to the memory 32500Sstevel@tonic-gate * nodes thereby returning them twice! Using next_pass 32510Sstevel@tonic-gate * forces us down to the end (or next item). 32520Sstevel@tonic-gate */ 32530Sstevel@tonic-gate if (pass == 1) 32540Sstevel@tonic-gate next_pass = 1; 32550Sstevel@tonic-gate 32560Sstevel@tonic-gate switch (next_pass) { 32570Sstevel@tonic-gate case 1: 32580Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 32590Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 32600Sstevel@tonic-gate 32610Sstevel@tonic-gate release_devlist = sbd_get_devlist(hp, sbp, 32620Sstevel@tonic-gate SBD_COMP_MEM, 32630Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD, 32640Sstevel@tonic-gate uset, devnump, 0); 32650Sstevel@tonic-gate 32660Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 32670Sstevel@tonic-gate if (!devset || release_devlist) { 32680Sstevel@tonic-gate next_pass = 2; 32690Sstevel@tonic-gate return (release_devlist); 32700Sstevel@tonic-gate } 32710Sstevel@tonic-gate /* 32720Sstevel@tonic-gate * If the caller is interested in the entire 32730Sstevel@tonic-gate * board, but there isn't any memory, then 32740Sstevel@tonic-gate * just fall through to next component. 32750Sstevel@tonic-gate */ 32760Sstevel@tonic-gate } 32770Sstevel@tonic-gate /*FALLTHROUGH*/ 32780Sstevel@tonic-gate 32790Sstevel@tonic-gate 32800Sstevel@tonic-gate case 2: 32810Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 32820Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 32830Sstevel@tonic-gate 32840Sstevel@tonic-gate release_devlist = sbd_get_devlist(hp, sbp, 32850Sstevel@tonic-gate SBD_COMP_CPU, 32860Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, 32870Sstevel@tonic-gate uset, devnump, 0); 32880Sstevel@tonic-gate 32890Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 32900Sstevel@tonic-gate if (!devset || release_devlist) { 32910Sstevel@tonic-gate next_pass = 3; 32920Sstevel@tonic-gate return (release_devlist); 32930Sstevel@tonic-gate } 32940Sstevel@tonic-gate /* 32950Sstevel@tonic-gate * If the caller is interested in the entire 32960Sstevel@tonic-gate * board, but there aren't any cpus, then just 32970Sstevel@tonic-gate * fall through to check for the next component. 32980Sstevel@tonic-gate */ 32990Sstevel@tonic-gate } 33000Sstevel@tonic-gate /*FALLTHROUGH*/ 33010Sstevel@tonic-gate 33020Sstevel@tonic-gate 33030Sstevel@tonic-gate case 3: 33040Sstevel@tonic-gate next_pass = -1; 33050Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 33060Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 33070Sstevel@tonic-gate 33080Sstevel@tonic-gate release_devlist = sbd_get_devlist(hp, sbp, 33090Sstevel@tonic-gate SBD_COMP_IO, 33100Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD, 33110Sstevel@tonic-gate uset, devnump, 0); 33120Sstevel@tonic-gate 33130Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 33140Sstevel@tonic-gate if (!devset || release_devlist) { 33150Sstevel@tonic-gate next_pass = 4; 33160Sstevel@tonic-gate return (release_devlist); 33170Sstevel@tonic-gate } 33180Sstevel@tonic-gate } 33190Sstevel@tonic-gate /*FALLTHROUGH*/ 33200Sstevel@tonic-gate 33210Sstevel@tonic-gate default: 33220Sstevel@tonic-gate *devnump = 0; 33230Sstevel@tonic-gate return (NULL); 33240Sstevel@tonic-gate } 33250Sstevel@tonic-gate /*NOTREACHED*/ 33260Sstevel@tonic-gate } 33270Sstevel@tonic-gate 33280Sstevel@tonic-gate static int 33290Sstevel@tonic-gate sbd_pre_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 33300Sstevel@tonic-gate int32_t devnum) 33310Sstevel@tonic-gate { 33320Sstevel@tonic-gate int max_units = 0, rv = 0; 33330Sstevel@tonic-gate sbd_comp_type_t nodetype; 33340Sstevel@tonic-gate static fn_t f = "sbd_pre_release_devlist"; 33350Sstevel@tonic-gate 33360Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 33370Sstevel@tonic-gate 33380Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 33390Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 33400Sstevel@tonic-gate 33410Sstevel@tonic-gate switch (nodetype) { 33420Sstevel@tonic-gate case SBD_COMP_CPU: { 33430Sstevel@tonic-gate int i, mem_present = 0; 33440Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 33450Sstevel@tonic-gate sbd_devset_t devset; 33460Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 33470Sstevel@tonic-gate 33480Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 33490Sstevel@tonic-gate 33500Sstevel@tonic-gate devset = shp->sh_orig_devset; 33510Sstevel@tonic-gate 33520Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 33530Sstevel@tonic-gate /* 33540Sstevel@tonic-gate * if client also requested to unconfigure memory 33550Sstevel@tonic-gate * the we allow the operation. Therefore 33560Sstevel@tonic-gate * we need to warranty that memory gets unconfig 33570Sstevel@tonic-gate * before cpus 33580Sstevel@tonic-gate */ 33590Sstevel@tonic-gate 33600Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) { 33610Sstevel@tonic-gate continue; 33620Sstevel@tonic-gate } 33630Sstevel@tonic-gate if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, i)) { 33640Sstevel@tonic-gate mem_present = 1; 33650Sstevel@tonic-gate break; 33660Sstevel@tonic-gate } 33670Sstevel@tonic-gate } 33680Sstevel@tonic-gate if (mem_present) { 33690Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 33700Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_MEMONLINE); 33710Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]); 33720Sstevel@tonic-gate rv = -1; 33730Sstevel@tonic-gate } else { 33740Sstevel@tonic-gate rv = sbd_pre_release_cpu(hp, devlist, devnum); 33750Sstevel@tonic-gate } 33760Sstevel@tonic-gate 33770Sstevel@tonic-gate break; 33780Sstevel@tonic-gate 33790Sstevel@tonic-gate } 33800Sstevel@tonic-gate case SBD_COMP_MEM: 33810Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 33820Sstevel@tonic-gate rv = sbd_pre_release_mem(hp, devlist, devnum); 33830Sstevel@tonic-gate break; 33840Sstevel@tonic-gate 33850Sstevel@tonic-gate 33860Sstevel@tonic-gate case SBD_COMP_IO: 33870Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 33880Sstevel@tonic-gate rv = sbd_pre_release_io(hp, devlist, devnum); 33890Sstevel@tonic-gate break; 33900Sstevel@tonic-gate 33910Sstevel@tonic-gate default: 33920Sstevel@tonic-gate rv = -1; 33930Sstevel@tonic-gate break; 33940Sstevel@tonic-gate } 33950Sstevel@tonic-gate 33960Sstevel@tonic-gate if (rv && max_units) { 33970Sstevel@tonic-gate int i; 33980Sstevel@tonic-gate 33990Sstevel@tonic-gate /* 34000Sstevel@tonic-gate * the individual pre_release component routines should 34010Sstevel@tonic-gate * have set the error in the handle. No need to set it 34020Sstevel@tonic-gate * here 34030Sstevel@tonic-gate * 34040Sstevel@tonic-gate * Need to clean up dynamically allocated devlist 34050Sstevel@tonic-gate * if pre-op is going to fail. 34060Sstevel@tonic-gate */ 34070Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 34080Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 34090Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 34100Sstevel@tonic-gate } else { 34110Sstevel@tonic-gate break; 34120Sstevel@tonic-gate } 34130Sstevel@tonic-gate } 34140Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 34150Sstevel@tonic-gate } 34160Sstevel@tonic-gate 34170Sstevel@tonic-gate return (rv ? -1 : 0); 34180Sstevel@tonic-gate } 34190Sstevel@tonic-gate 34200Sstevel@tonic-gate static int 34210Sstevel@tonic-gate sbd_post_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 34220Sstevel@tonic-gate int32_t devnum) 34230Sstevel@tonic-gate { 34240Sstevel@tonic-gate int i, max_units = 0; 34250Sstevel@tonic-gate sbd_comp_type_t nodetype; 34260Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 34270Sstevel@tonic-gate sbdp_handle_t *hdp; 34280Sstevel@tonic-gate sbd_error_t *spe; 34290Sstevel@tonic-gate static fn_t f = "sbd_post_release_devlist"; 34300Sstevel@tonic-gate 34310Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 34320Sstevel@tonic-gate ASSERT(nodetype >= SBD_COMP_CPU && nodetype <= SBD_COMP_IO); 34330Sstevel@tonic-gate 34340Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 34350Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 34360Sstevel@tonic-gate 34370Sstevel@tonic-gate /* 34380Sstevel@tonic-gate * Need to free up devlist[] created earlier in 34390Sstevel@tonic-gate * sbd_get_release_devlist(). 34400Sstevel@tonic-gate */ 34410Sstevel@tonic-gate switch (nodetype) { 34420Sstevel@tonic-gate case SBD_COMP_CPU: 34430Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 34440Sstevel@tonic-gate break; 34450Sstevel@tonic-gate 34460Sstevel@tonic-gate case SBD_COMP_MEM: 34470Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 34480Sstevel@tonic-gate break; 34490Sstevel@tonic-gate 34500Sstevel@tonic-gate case SBD_COMP_IO: 34510Sstevel@tonic-gate /* 34520Sstevel@tonic-gate * Need to check if specific I/O is referenced and 34530Sstevel@tonic-gate * fail post-op. 34540Sstevel@tonic-gate */ 34550Sstevel@tonic-gate 34560Sstevel@tonic-gate if (sbd_check_io_refs(hp, devlist, devnum) > 0) { 34570Sstevel@tonic-gate PR_IO("%s: error - I/O devices ref'd\n", f); 34580Sstevel@tonic-gate } 34590Sstevel@tonic-gate 34600Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 34610Sstevel@tonic-gate break; 34620Sstevel@tonic-gate 34630Sstevel@tonic-gate default: 34640Sstevel@tonic-gate { 34650Sstevel@tonic-gate cmn_err(CE_WARN, "%s: invalid nodetype (%d)", 34660Sstevel@tonic-gate f, (int)nodetype); 34670Sstevel@tonic-gate SBD_SET_ERR(HD2MACHERR(hp), ESBD_INVAL); 34680Sstevel@tonic-gate } 34690Sstevel@tonic-gate break; 34700Sstevel@tonic-gate } 34710Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 34720Sstevel@tonic-gate spe = hdp->h_err; 34730Sstevel@tonic-gate 34740Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 34750Sstevel@tonic-gate int unit; 34760Sstevel@tonic-gate sbderror_t *ep; 34770Sstevel@tonic-gate 34780Sstevel@tonic-gate ep = &devlist[i].dv_error; 34790Sstevel@tonic-gate 34800Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) { 34810Sstevel@tonic-gate continue; 34820Sstevel@tonic-gate } 34830Sstevel@tonic-gate 34840Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, devlist[i].dv_dip); 34850Sstevel@tonic-gate if (unit == -1) { 34860Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 34870Sstevel@tonic-gate PR_ALL("%s bad unit num: %d code %d", 34880Sstevel@tonic-gate f, unit, spe->e_code); 34890Sstevel@tonic-gate continue; 34900Sstevel@tonic-gate } 34910Sstevel@tonic-gate } 34920Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 34930Sstevel@tonic-gate 34940Sstevel@tonic-gate if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) { 34950Sstevel@tonic-gate PR_ALL("%s: errno %d, ecode %d during release\n", 34960Sstevel@tonic-gate f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 34970Sstevel@tonic-gate SBD_GET_ERR(SBD_HD2ERR(hp))); 34980Sstevel@tonic-gate } 34990Sstevel@tonic-gate 35000Sstevel@tonic-gate if (max_units && devlist) { 35010Sstevel@tonic-gate int i; 35020Sstevel@tonic-gate 35030Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 35040Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 35050Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 35060Sstevel@tonic-gate } else { 35070Sstevel@tonic-gate break; 35080Sstevel@tonic-gate } 35090Sstevel@tonic-gate } 35100Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 35110Sstevel@tonic-gate } 35120Sstevel@tonic-gate 35130Sstevel@tonic-gate return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0); 35140Sstevel@tonic-gate } 35150Sstevel@tonic-gate 35160Sstevel@tonic-gate static void 35170Sstevel@tonic-gate sbd_release_dev_done(sbd_board_t *sbp, sbd_comp_type_t nodetype, int unit) 35180Sstevel@tonic-gate { 35190Sstevel@tonic-gate SBD_DEV_SET_UNREFERENCED(sbp, nodetype, unit); 35200Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, nodetype, unit, SBD_STATE_UNREFERENCED); 35210Sstevel@tonic-gate } 35220Sstevel@tonic-gate 35230Sstevel@tonic-gate static void 35240Sstevel@tonic-gate sbd_release_done(sbd_handle_t *hp, sbd_comp_type_t nodetype, dev_info_t *dip) 35250Sstevel@tonic-gate { 35260Sstevel@tonic-gate int unit; 35270Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 35280Sstevel@tonic-gate sbderror_t *ep; 35290Sstevel@tonic-gate static fn_t f = "sbd_release_done"; 35300Sstevel@tonic-gate sbdp_handle_t *hdp; 35310Sstevel@tonic-gate 35320Sstevel@tonic-gate PR_ALL("%s...\n", f); 35330Sstevel@tonic-gate 35340Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 35350Sstevel@tonic-gate ep = SBD_HD2ERR(hp); 35360Sstevel@tonic-gate 35370Sstevel@tonic-gate if ((unit = sbdp_get_unit_num(hdp, dip)) < 0) { 35380Sstevel@tonic-gate cmn_err(CE_WARN, 35390Sstevel@tonic-gate "sbd:%s: unable to get unit for dip (0x%p)", 35400Sstevel@tonic-gate f, (void *)dip); 35410Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 35420Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 35430Sstevel@tonic-gate return; 35440Sstevel@tonic-gate } 35450Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 35460Sstevel@tonic-gate 35470Sstevel@tonic-gate /* 35480Sstevel@tonic-gate * Transfer the device which just completed its release 35490Sstevel@tonic-gate * to the UNREFERENCED state. 35500Sstevel@tonic-gate */ 35510Sstevel@tonic-gate switch (nodetype) { 35520Sstevel@tonic-gate 35530Sstevel@tonic-gate case SBD_COMP_MEM: 35540Sstevel@tonic-gate sbd_release_mem_done((void *)hp, unit); 35550Sstevel@tonic-gate break; 35560Sstevel@tonic-gate 35570Sstevel@tonic-gate default: 35580Sstevel@tonic-gate sbd_release_dev_done(sbp, nodetype, unit); 35590Sstevel@tonic-gate break; 35600Sstevel@tonic-gate } 35610Sstevel@tonic-gate 35620Sstevel@tonic-gate /* 35630Sstevel@tonic-gate * If the entire board was released and all components 35640Sstevel@tonic-gate * unreferenced then transfer it to the UNREFERENCED state. 35650Sstevel@tonic-gate */ 35660Sstevel@tonic-gate if (SBD_DEVS_RELEASED(sbp) == SBD_DEVS_UNREFERENCED(sbp)) { 35670Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNREFERENCED); 35680Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 35690Sstevel@tonic-gate } 35700Sstevel@tonic-gate } 35710Sstevel@tonic-gate 35720Sstevel@tonic-gate static sbd_devlist_t * 35730Sstevel@tonic-gate sbd_get_detach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 35740Sstevel@tonic-gate { 35750Sstevel@tonic-gate sbd_board_t *sbp; 35760Sstevel@tonic-gate uint_t uset; 35770Sstevel@tonic-gate sbd_devset_t devset; 35780Sstevel@tonic-gate sbd_devlist_t *detach_devlist; 35790Sstevel@tonic-gate static int next_pass = 1; 35800Sstevel@tonic-gate static fn_t f = "sbd_get_detach_devlist"; 35810Sstevel@tonic-gate 35820Sstevel@tonic-gate PR_ALL("%s (pass = %d)...\n", f, pass); 35830Sstevel@tonic-gate 35840Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 35850Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset; 35860Sstevel@tonic-gate 35870Sstevel@tonic-gate *devnump = 0; 35880Sstevel@tonic-gate detach_devlist = NULL; 35890Sstevel@tonic-gate 35900Sstevel@tonic-gate /* 35910Sstevel@tonic-gate * We switch on next_pass for the cases where a board 35920Sstevel@tonic-gate * does not contain a particular type of component. 35930Sstevel@tonic-gate * In these situations we don't want to return NULL 35940Sstevel@tonic-gate * prematurely. We need to check other devices and 35950Sstevel@tonic-gate * we don't want to check the same type multiple times. 35960Sstevel@tonic-gate * For example, if there were no cpus, then on pass 1 35970Sstevel@tonic-gate * we would drop through and return the memory nodes. 35980Sstevel@tonic-gate * However, on pass 2 we would switch back to the memory 35990Sstevel@tonic-gate * nodes thereby returning them twice! Using next_pass 36000Sstevel@tonic-gate * forces us down to the end (or next item). 36010Sstevel@tonic-gate */ 36020Sstevel@tonic-gate if (pass == 1) 36030Sstevel@tonic-gate next_pass = 1; 36040Sstevel@tonic-gate 36050Sstevel@tonic-gate switch (next_pass) { 36060Sstevel@tonic-gate case 1: 36070Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 36080Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 36090Sstevel@tonic-gate 36100Sstevel@tonic-gate detach_devlist = sbd_get_devlist(hp, sbp, 36110Sstevel@tonic-gate SBD_COMP_MEM, 36120Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD, 36130Sstevel@tonic-gate uset, devnump, 0); 36140Sstevel@tonic-gate 36150Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 36160Sstevel@tonic-gate if (!devset || detach_devlist) { 36170Sstevel@tonic-gate next_pass = 2; 36180Sstevel@tonic-gate return (detach_devlist); 36190Sstevel@tonic-gate } 36200Sstevel@tonic-gate /* 36210Sstevel@tonic-gate * If the caller is interested in the entire 36220Sstevel@tonic-gate * board, but there isn't any memory, then 36230Sstevel@tonic-gate * just fall through to next component. 36240Sstevel@tonic-gate */ 36250Sstevel@tonic-gate } 36260Sstevel@tonic-gate /*FALLTHROUGH*/ 36270Sstevel@tonic-gate 36280Sstevel@tonic-gate case 2: 36290Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 36300Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 36310Sstevel@tonic-gate 36320Sstevel@tonic-gate detach_devlist = sbd_get_devlist(hp, sbp, 36330Sstevel@tonic-gate SBD_COMP_CPU, 36340Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, 36350Sstevel@tonic-gate uset, devnump, 0); 36360Sstevel@tonic-gate 36370Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 36380Sstevel@tonic-gate if (!devset || detach_devlist) { 36390Sstevel@tonic-gate next_pass = 2; 36400Sstevel@tonic-gate return (detach_devlist); 36410Sstevel@tonic-gate } 36420Sstevel@tonic-gate /* 36430Sstevel@tonic-gate * If the caller is interested in the entire 36440Sstevel@tonic-gate * board, but there aren't any cpus, then just 36450Sstevel@tonic-gate * fall through to check for the next component. 36460Sstevel@tonic-gate */ 36470Sstevel@tonic-gate } 36480Sstevel@tonic-gate /*FALLTHROUGH*/ 36490Sstevel@tonic-gate 36500Sstevel@tonic-gate case 3: 36510Sstevel@tonic-gate next_pass = -1; 36520Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 36530Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 36540Sstevel@tonic-gate 36550Sstevel@tonic-gate detach_devlist = sbd_get_devlist(hp, sbp, 36560Sstevel@tonic-gate SBD_COMP_IO, 36570Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD, 36580Sstevel@tonic-gate uset, devnump, 0); 36590Sstevel@tonic-gate 36600Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 36610Sstevel@tonic-gate if (!devset || detach_devlist) { 36620Sstevel@tonic-gate next_pass = 4; 36630Sstevel@tonic-gate return (detach_devlist); 36640Sstevel@tonic-gate } 36650Sstevel@tonic-gate } 36660Sstevel@tonic-gate /*FALLTHROUGH*/ 36670Sstevel@tonic-gate 36680Sstevel@tonic-gate default: 36690Sstevel@tonic-gate *devnump = 0; 36700Sstevel@tonic-gate return (NULL); 36710Sstevel@tonic-gate } 36720Sstevel@tonic-gate /*NOTREACHED*/ 36730Sstevel@tonic-gate } 36740Sstevel@tonic-gate 36750Sstevel@tonic-gate static int 36760Sstevel@tonic-gate sbd_pre_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 36770Sstevel@tonic-gate int32_t devnum) 36780Sstevel@tonic-gate { 36790Sstevel@tonic-gate int rv = 0; 36800Sstevel@tonic-gate sbd_comp_type_t nodetype; 36810Sstevel@tonic-gate static fn_t f = "sbd_pre_detach_devlist"; 36820Sstevel@tonic-gate 36830Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 36840Sstevel@tonic-gate 36850Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 36860Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 36870Sstevel@tonic-gate 36880Sstevel@tonic-gate switch (nodetype) { 36890Sstevel@tonic-gate case SBD_COMP_CPU: 36900Sstevel@tonic-gate rv = sbd_pre_detach_cpu(hp, devlist, devnum); 36910Sstevel@tonic-gate break; 36920Sstevel@tonic-gate 36930Sstevel@tonic-gate case SBD_COMP_MEM: 36940Sstevel@tonic-gate rv = sbd_pre_detach_mem(hp, devlist, devnum); 36950Sstevel@tonic-gate break; 36960Sstevel@tonic-gate 36970Sstevel@tonic-gate case SBD_COMP_IO: 36980Sstevel@tonic-gate rv = sbd_pre_detach_io(hp, devlist, devnum); 36990Sstevel@tonic-gate break; 37000Sstevel@tonic-gate 37010Sstevel@tonic-gate default: 37020Sstevel@tonic-gate rv = -1; 37030Sstevel@tonic-gate break; 37040Sstevel@tonic-gate } 37050Sstevel@tonic-gate 37060Sstevel@tonic-gate /* 37070Sstevel@tonic-gate * We want to continue attempting to detach 37080Sstevel@tonic-gate * other components. 37090Sstevel@tonic-gate */ 37100Sstevel@tonic-gate return (rv); 37110Sstevel@tonic-gate } 37120Sstevel@tonic-gate 37130Sstevel@tonic-gate static int 37140Sstevel@tonic-gate sbd_post_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 37150Sstevel@tonic-gate int32_t devnum) 37160Sstevel@tonic-gate { 37170Sstevel@tonic-gate int i, max_units = 0, rv = 0; 37180Sstevel@tonic-gate sbd_comp_type_t nodetype; 37190Sstevel@tonic-gate sbd_board_t *sbp; 37200Sstevel@tonic-gate sbd_istate_t bstate; 37210Sstevel@tonic-gate static fn_t f = "sbd_post_detach_devlist"; 37220Sstevel@tonic-gate sbdp_handle_t *hdp; 37230Sstevel@tonic-gate 37240Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 37250Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 37260Sstevel@tonic-gate 37270Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 37280Sstevel@tonic-gate 37290Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 37300Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 37310Sstevel@tonic-gate 37320Sstevel@tonic-gate /* 37330Sstevel@tonic-gate * Need to free up devlist[] created earlier in 37340Sstevel@tonic-gate * sbd_get_detach_devlist(). 37350Sstevel@tonic-gate */ 37360Sstevel@tonic-gate switch (nodetype) { 37370Sstevel@tonic-gate case SBD_COMP_CPU: 37380Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 37390Sstevel@tonic-gate rv = sbd_post_detach_cpu(hp, devlist, devnum); 37400Sstevel@tonic-gate break; 37410Sstevel@tonic-gate 37420Sstevel@tonic-gate case SBD_COMP_MEM: 37430Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 37440Sstevel@tonic-gate rv = sbd_post_detach_mem(hp, devlist, devnum); 37450Sstevel@tonic-gate break; 37460Sstevel@tonic-gate 37470Sstevel@tonic-gate case SBD_COMP_IO: 37480Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 37490Sstevel@tonic-gate rv = sbd_post_detach_io(hp, devlist, devnum); 37500Sstevel@tonic-gate break; 37510Sstevel@tonic-gate 37520Sstevel@tonic-gate default: 37530Sstevel@tonic-gate rv = -1; 37540Sstevel@tonic-gate break; 37550Sstevel@tonic-gate } 37560Sstevel@tonic-gate 37570Sstevel@tonic-gate 37580Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 37590Sstevel@tonic-gate int unit; 37600Sstevel@tonic-gate sbderror_t *ep; 37610Sstevel@tonic-gate dev_info_t *dip; 37620Sstevel@tonic-gate 37630Sstevel@tonic-gate ep = &devlist[i].dv_error; 37640Sstevel@tonic-gate 37650Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) 37660Sstevel@tonic-gate continue; 37670Sstevel@tonic-gate 37680Sstevel@tonic-gate dip = devlist[i].dv_dip; 37690Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 37700Sstevel@tonic-gate if (unit == -1) { 37710Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 37720Sstevel@tonic-gate continue; 37730Sstevel@tonic-gate else { 37740Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 37750Sstevel@tonic-gate break; 37760Sstevel@tonic-gate } 37770Sstevel@tonic-gate } 37780Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 37790Sstevel@tonic-gate 37800Sstevel@tonic-gate if (sbd_check_unit_attached(sbp, dip, unit, nodetype, 37810Sstevel@tonic-gate ep) >= 0) { 37820Sstevel@tonic-gate /* 37830Sstevel@tonic-gate * Device is still attached probably due 37840Sstevel@tonic-gate * to an error. Need to keep track of it. 37850Sstevel@tonic-gate */ 37860Sstevel@tonic-gate PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not detached\n", 37870Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], sbp->sb_num, 37880Sstevel@tonic-gate unit); 37890Sstevel@tonic-gate continue; 37900Sstevel@tonic-gate } 37910Sstevel@tonic-gate 37920Sstevel@tonic-gate SBD_DEV_CLR_ATTACHED(sbp, nodetype, unit); 37930Sstevel@tonic-gate SBD_DEV_CLR_RELEASED(sbp, nodetype, unit); 37940Sstevel@tonic-gate SBD_DEV_CLR_UNREFERENCED(sbp, nodetype, unit); 37950Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, nodetype, unit, 37960Sstevel@tonic-gate SBD_STATE_UNCONFIGURED); 37970Sstevel@tonic-gate } 37980Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 37990Sstevel@tonic-gate 38000Sstevel@tonic-gate bstate = SBD_BOARD_STATE(sbp); 38010Sstevel@tonic-gate if (bstate != SBD_STATE_UNCONFIGURED) { 38020Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp) == SBD_DEVS_UNATTACHED(sbp)) { 38030Sstevel@tonic-gate /* 38040Sstevel@tonic-gate * All devices are finally detached. 38050Sstevel@tonic-gate */ 38060Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNCONFIGURED); 38070Sstevel@tonic-gate } else if ((SBD_BOARD_STATE(sbp) != SBD_STATE_PARTIAL) && 38080Sstevel@tonic-gate SBD_DEVS_ATTACHED(sbp)) { 38090Sstevel@tonic-gate /* 38100Sstevel@tonic-gate * Some devices remain attached. 38110Sstevel@tonic-gate */ 38120Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 38130Sstevel@tonic-gate } 38140Sstevel@tonic-gate } 38150Sstevel@tonic-gate 38160Sstevel@tonic-gate if (rv) { 38170Sstevel@tonic-gate PR_ALL("%s: errno %d, ecode %d during detach\n", 38180Sstevel@tonic-gate f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 38190Sstevel@tonic-gate SBD_GET_ERR(HD2MACHERR(hp))); 38200Sstevel@tonic-gate } 38210Sstevel@tonic-gate 38220Sstevel@tonic-gate if (max_units && devlist) { 38230Sstevel@tonic-gate int i; 38240Sstevel@tonic-gate 38250Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 38260Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 38270Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 38280Sstevel@tonic-gate } else { 38290Sstevel@tonic-gate break; 38300Sstevel@tonic-gate } 38310Sstevel@tonic-gate } 38320Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 38330Sstevel@tonic-gate } 38340Sstevel@tonic-gate 38350Sstevel@tonic-gate return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0); 38360Sstevel@tonic-gate } 38370Sstevel@tonic-gate 38380Sstevel@tonic-gate /* 38390Sstevel@tonic-gate * Return the unit number of the respective dip if 38400Sstevel@tonic-gate * it's found to be attached. 38410Sstevel@tonic-gate */ 38420Sstevel@tonic-gate static int 38430Sstevel@tonic-gate sbd_check_unit_attached(sbd_board_t *sbp, dev_info_t *dip, int unit, 38440Sstevel@tonic-gate sbd_comp_type_t nodetype, sbderror_t *ep) 38450Sstevel@tonic-gate { 38460Sstevel@tonic-gate int rv = -1; 38470Sstevel@tonic-gate processorid_t cpuid; 38480Sstevel@tonic-gate uint64_t basepa, endpa; 38490Sstevel@tonic-gate struct memlist *ml; 38500Sstevel@tonic-gate extern struct memlist *phys_install; 38510Sstevel@tonic-gate sbdp_handle_t *hdp; 38520Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 38530Sstevel@tonic-gate static fn_t f = "sbd_check_unit_attached"; 38540Sstevel@tonic-gate 38550Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 38560Sstevel@tonic-gate 38570Sstevel@tonic-gate switch (nodetype) { 38580Sstevel@tonic-gate 38590Sstevel@tonic-gate case SBD_COMP_CPU: 38600Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 38610Sstevel@tonic-gate if (cpuid < 0) { 38620Sstevel@tonic-gate break; 38630Sstevel@tonic-gate } 38640Sstevel@tonic-gate mutex_enter(&cpu_lock); 38650Sstevel@tonic-gate if (cpu_get(cpuid) != NULL) 38660Sstevel@tonic-gate rv = unit; 38670Sstevel@tonic-gate mutex_exit(&cpu_lock); 38680Sstevel@tonic-gate break; 38690Sstevel@tonic-gate 38700Sstevel@tonic-gate case SBD_COMP_MEM: 38710Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) { 38720Sstevel@tonic-gate break; 38730Sstevel@tonic-gate } 38740Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, dip, &endpa)) { 38750Sstevel@tonic-gate cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f); 38760Sstevel@tonic-gate break; 38770Sstevel@tonic-gate } 38780Sstevel@tonic-gate 38790Sstevel@tonic-gate basepa &= ~(endpa - 1); 38800Sstevel@tonic-gate endpa += basepa; 38810Sstevel@tonic-gate /* 38820Sstevel@tonic-gate * Check if base address is in phys_install. 38830Sstevel@tonic-gate */ 38840Sstevel@tonic-gate memlist_read_lock(); 38850Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) 38860Sstevel@tonic-gate if ((endpa <= ml->address) || 38870Sstevel@tonic-gate (basepa >= (ml->address + ml->size))) 38880Sstevel@tonic-gate continue; 38890Sstevel@tonic-gate else 38900Sstevel@tonic-gate break; 38910Sstevel@tonic-gate memlist_read_unlock(); 38920Sstevel@tonic-gate if (ml != NULL) 38930Sstevel@tonic-gate rv = unit; 38940Sstevel@tonic-gate break; 38950Sstevel@tonic-gate 38960Sstevel@tonic-gate case SBD_COMP_IO: 38970Sstevel@tonic-gate { 38980Sstevel@tonic-gate dev_info_t *tdip, *pdip; 38990Sstevel@tonic-gate 39000Sstevel@tonic-gate tdip = dip; 39010Sstevel@tonic-gate 39020Sstevel@tonic-gate /* 39030Sstevel@tonic-gate * ddi_walk_devs() requires that topdip's parent be held. 39040Sstevel@tonic-gate */ 39050Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 39060Sstevel@tonic-gate if (pdip) { 39070Sstevel@tonic-gate ndi_hold_devi(pdip); 39080Sstevel@tonic-gate ndi_devi_enter(pdip, &rv); 39090Sstevel@tonic-gate } 39100Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, sbd_check_io_attached, 39110Sstevel@tonic-gate (void *)&tdip); 39120Sstevel@tonic-gate if (pdip) { 39130Sstevel@tonic-gate ndi_devi_exit(pdip, rv); 39140Sstevel@tonic-gate ndi_rele_devi(pdip); 39150Sstevel@tonic-gate } 39160Sstevel@tonic-gate 39170Sstevel@tonic-gate if (tdip == NULL) 39180Sstevel@tonic-gate rv = unit; 39190Sstevel@tonic-gate else 39200Sstevel@tonic-gate rv = -1; 39210Sstevel@tonic-gate break; 39220Sstevel@tonic-gate } 39230Sstevel@tonic-gate 39240Sstevel@tonic-gate default: 39250Sstevel@tonic-gate PR_ALL("%s: unexpected nodetype(%d) for dip 0x%p\n", 39260Sstevel@tonic-gate f, nodetype, (void *)dip); 39270Sstevel@tonic-gate rv = -1; 39280Sstevel@tonic-gate break; 39290Sstevel@tonic-gate } 39300Sstevel@tonic-gate 39310Sstevel@tonic-gate /* 39320Sstevel@tonic-gate * Save the error that sbdp sent us and report it 39330Sstevel@tonic-gate */ 39340Sstevel@tonic-gate if (rv == -1) 39350Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 39360Sstevel@tonic-gate 39370Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 39380Sstevel@tonic-gate 39390Sstevel@tonic-gate return (rv); 39400Sstevel@tonic-gate } 39410Sstevel@tonic-gate 39420Sstevel@tonic-gate /* 39430Sstevel@tonic-gate * Return memhandle, if in fact, this memunit is the owner of 39440Sstevel@tonic-gate * a scheduled memory delete. 39450Sstevel@tonic-gate */ 39460Sstevel@tonic-gate int 39470Sstevel@tonic-gate sbd_get_memhandle(sbd_handle_t *hp, dev_info_t *dip, memhandle_t *mhp) 39480Sstevel@tonic-gate { 39490Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 39500Sstevel@tonic-gate sbd_mem_unit_t *mp; 39510Sstevel@tonic-gate sbdp_handle_t *hdp; 39520Sstevel@tonic-gate int unit; 39530Sstevel@tonic-gate static fn_t f = "sbd_get_memhandle"; 39540Sstevel@tonic-gate 39550Sstevel@tonic-gate PR_MEM("%s...\n", f); 39560Sstevel@tonic-gate 39570Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 39580Sstevel@tonic-gate 39590Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 39600Sstevel@tonic-gate if (unit == -1) { 39610Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 39620Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 39630Sstevel@tonic-gate return (-1); 39640Sstevel@tonic-gate } 39650Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 39660Sstevel@tonic-gate 39670Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 39680Sstevel@tonic-gate 39690Sstevel@tonic-gate if (mp->sbm_flags & SBD_MFLAG_RELOWNER) { 39700Sstevel@tonic-gate *mhp = mp->sbm_memhandle; 39710Sstevel@tonic-gate return (0); 39720Sstevel@tonic-gate } else { 39730Sstevel@tonic-gate SBD_SET_ERR(SBD_HD2ERR(hp), ESBD_INTERNAL); 39740Sstevel@tonic-gate SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]); 39750Sstevel@tonic-gate return (-1); 39760Sstevel@tonic-gate } 39770Sstevel@tonic-gate /*NOTREACHED*/ 39780Sstevel@tonic-gate } 39790Sstevel@tonic-gate 39800Sstevel@tonic-gate 39810Sstevel@tonic-gate static int 39820Sstevel@tonic-gate sbd_cpu_cnt(sbd_handle_t *hp, sbd_devset_t devset) 39830Sstevel@tonic-gate { 39840Sstevel@tonic-gate int c, cix; 39850Sstevel@tonic-gate sbd_board_t *sbp; 39860Sstevel@tonic-gate 39870Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 39880Sstevel@tonic-gate 39890Sstevel@tonic-gate /* 39900Sstevel@tonic-gate * Only look for requested devices that are actually present. 39910Sstevel@tonic-gate */ 39920Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 39930Sstevel@tonic-gate 39940Sstevel@tonic-gate for (c = cix = 0; c < MAX_CMP_UNITS_PER_BOARD; c++) { 39950Sstevel@tonic-gate /* 39960Sstevel@tonic-gate * Index for core 1 , if exists. 39970Sstevel@tonic-gate * With the current implementation it is 39980Sstevel@tonic-gate * MAX_CMP_UNITS_PER_BOARD off from core 0. 39990Sstevel@tonic-gate * The calculation will need to change if 40000Sstevel@tonic-gate * the assumption is no longer true. 40010Sstevel@tonic-gate */ 40020Sstevel@tonic-gate int c1 = c + MAX_CMP_UNITS_PER_BOARD; 40030Sstevel@tonic-gate 40040Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CMP, c) == 0) { 40050Sstevel@tonic-gate continue; 40060Sstevel@tonic-gate } 40070Sstevel@tonic-gate 40080Sstevel@tonic-gate /* 40090Sstevel@tonic-gate * Check to see if the dip(s) exist for this chip 40100Sstevel@tonic-gate */ 40110Sstevel@tonic-gate if ((sbp->sb_devlist[NIX(SBD_COMP_CMP)][c] == NULL) && 40120Sstevel@tonic-gate (sbp->sb_devlist[NIX(SBD_COMP_CMP)][c1] == NULL)) 40130Sstevel@tonic-gate continue; 40140Sstevel@tonic-gate 40150Sstevel@tonic-gate cix++; 40160Sstevel@tonic-gate } 40170Sstevel@tonic-gate 40180Sstevel@tonic-gate return (cix); 40190Sstevel@tonic-gate } 40200Sstevel@tonic-gate 40210Sstevel@tonic-gate static int 40220Sstevel@tonic-gate sbd_mem_cnt(sbd_handle_t *hp, sbd_devset_t devset) 40230Sstevel@tonic-gate { 40240Sstevel@tonic-gate int i, ix; 40250Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 40260Sstevel@tonic-gate 40270Sstevel@tonic-gate /* 40280Sstevel@tonic-gate * Only look for requested devices that are actually present. 40290Sstevel@tonic-gate */ 40300Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 40310Sstevel@tonic-gate 40320Sstevel@tonic-gate for (i = ix = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 40330Sstevel@tonic-gate dev_info_t *dip; 40340Sstevel@tonic-gate 40350Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i) == 0) { 40360Sstevel@tonic-gate continue; 40370Sstevel@tonic-gate } 40380Sstevel@tonic-gate 40390Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i]; 40400Sstevel@tonic-gate if (dip == NULL) 40410Sstevel@tonic-gate continue; 40420Sstevel@tonic-gate 40430Sstevel@tonic-gate ix++; 40440Sstevel@tonic-gate } 40450Sstevel@tonic-gate 40460Sstevel@tonic-gate return (ix); 40470Sstevel@tonic-gate } 40480Sstevel@tonic-gate 40490Sstevel@tonic-gate /* 40500Sstevel@tonic-gate * NOTE: This routine is only partially smart about multiple 40510Sstevel@tonic-gate * mem-units. Need to make mem-status structure smart 40520Sstevel@tonic-gate * about them also. 40530Sstevel@tonic-gate */ 40540Sstevel@tonic-gate static int 40550Sstevel@tonic-gate sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp) 40560Sstevel@tonic-gate { 40570Sstevel@tonic-gate int m, mix, rv; 40580Sstevel@tonic-gate memdelstat_t mdst; 40590Sstevel@tonic-gate memquery_t mq; 40600Sstevel@tonic-gate sbd_board_t *sbp; 40610Sstevel@tonic-gate sbd_mem_unit_t *mp; 40620Sstevel@tonic-gate sbd_mem_stat_t *msp; 40630Sstevel@tonic-gate extern int kcage_on; 40640Sstevel@tonic-gate int i; 40650Sstevel@tonic-gate static fn_t f = "sbd_mem_status"; 40660Sstevel@tonic-gate 40670Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 40680Sstevel@tonic-gate 40690Sstevel@tonic-gate /* 40700Sstevel@tonic-gate * Check the present devset and access the dip with 40710Sstevel@tonic-gate * status lock held to protect agains a concurrent 40720Sstevel@tonic-gate * unconfigure or disconnect thread. 40730Sstevel@tonic-gate */ 40740Sstevel@tonic-gate mutex_enter(&sbp->sb_slock); 40750Sstevel@tonic-gate 40760Sstevel@tonic-gate /* 40770Sstevel@tonic-gate * Only look for requested devices that are actually present. 40780Sstevel@tonic-gate */ 40790Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 40800Sstevel@tonic-gate 40810Sstevel@tonic-gate for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) { 40820Sstevel@tonic-gate dev_info_t *dip; 40830Sstevel@tonic-gate 40840Sstevel@tonic-gate 40850Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0) 40860Sstevel@tonic-gate continue; 40870Sstevel@tonic-gate 40880Sstevel@tonic-gate /* 40890Sstevel@tonic-gate * Check to make sure the memory unit is in a state 40900Sstevel@tonic-gate * where its fully initialized. 40910Sstevel@tonic-gate */ 40920Sstevel@tonic-gate if (SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, m) == SBD_STATE_EMPTY) 40930Sstevel@tonic-gate continue; 40940Sstevel@tonic-gate 40950Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][m]; 40960Sstevel@tonic-gate if (dip == NULL) 40970Sstevel@tonic-gate continue; 40980Sstevel@tonic-gate 40990Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, m); 41000Sstevel@tonic-gate 41010Sstevel@tonic-gate msp = &dsp->d_mem; 41020Sstevel@tonic-gate 41030Sstevel@tonic-gate bzero((caddr_t)msp, sizeof (*msp)); 41040Sstevel@tonic-gate msp->ms_type = SBD_COMP_MEM; 41050Sstevel@tonic-gate 41060Sstevel@tonic-gate /* 41070Sstevel@tonic-gate * The plugin expects -1 for the mem unit 41080Sstevel@tonic-gate */ 41090Sstevel@tonic-gate msp->ms_cm.c_id.c_unit = -1; 41100Sstevel@tonic-gate 41110Sstevel@tonic-gate /* 41120Sstevel@tonic-gate * Get the memory name from what sbdp gave us 41130Sstevel@tonic-gate */ 41140Sstevel@tonic-gate for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 41150Sstevel@tonic-gate if (SBD_COMP(i) == SBD_COMP_MEM) { 41160Sstevel@tonic-gate (void) strcpy(msp->ms_name, SBD_DEVNAME(i)); 41170Sstevel@tonic-gate } 41180Sstevel@tonic-gate } 41190Sstevel@tonic-gate msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond; 41200Sstevel@tonic-gate msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy; 41210Sstevel@tonic-gate msp->ms_cm.c_time = mp->sbm_cm.sbdev_time; 41220Sstevel@tonic-gate 41230Sstevel@tonic-gate /* XXX revisit this after memory conversion */ 41240Sstevel@tonic-gate msp->ms_ostate = ostate_cvt(SBD_DEVICE_STATE( 41250Sstevel@tonic-gate sbp, SBD_COMP_MEM, m)); 41260Sstevel@tonic-gate 41270Sstevel@tonic-gate msp->ms_basepfn = mp->sbm_basepfn; 41280Sstevel@tonic-gate msp->ms_pageslost = mp->sbm_pageslost; 41290Sstevel@tonic-gate msp->ms_cage_enabled = kcage_on; 41300Sstevel@tonic-gate msp->ms_interleave = mp->sbm_interleave; 41310Sstevel@tonic-gate 41320Sstevel@tonic-gate if (mp->sbm_flags & SBD_MFLAG_RELOWNER) 41330Sstevel@tonic-gate rv = kphysm_del_status(mp->sbm_memhandle, &mdst); 41340Sstevel@tonic-gate else 41350Sstevel@tonic-gate rv = KPHYSM_EHANDLE; /* force 'if' to fail */ 41360Sstevel@tonic-gate 41370Sstevel@tonic-gate if (rv == KPHYSM_OK) { 41380Sstevel@tonic-gate msp->ms_totpages += mdst.phys_pages; 41390Sstevel@tonic-gate 41400Sstevel@tonic-gate /* 41410Sstevel@tonic-gate * Any pages above managed is "free", 41420Sstevel@tonic-gate * i.e. it's collected. 41430Sstevel@tonic-gate */ 41440Sstevel@tonic-gate msp->ms_detpages += (uint_t)(mdst.collected + 41450Sstevel@tonic-gate mdst.phys_pages - 41460Sstevel@tonic-gate mdst.managed); 41470Sstevel@tonic-gate } else { 41480Sstevel@tonic-gate msp->ms_totpages += (uint_t)mp->sbm_npages; 41490Sstevel@tonic-gate 41500Sstevel@tonic-gate /* 41510Sstevel@tonic-gate * If we're UNREFERENCED or UNCONFIGURED, 41520Sstevel@tonic-gate * then the number of detached pages is 41530Sstevel@tonic-gate * however many pages are on the board. 41540Sstevel@tonic-gate * I.e. detached = not in use by OS. 41550Sstevel@tonic-gate */ 41560Sstevel@tonic-gate switch (msp->ms_cm.c_ostate) { 41570Sstevel@tonic-gate /* 41580Sstevel@tonic-gate * changed to use cfgadm states 41590Sstevel@tonic-gate * 41600Sstevel@tonic-gate * was: 41610Sstevel@tonic-gate * case SFDR_STATE_UNREFERENCED: 41620Sstevel@tonic-gate * case SFDR_STATE_UNCONFIGURED: 41630Sstevel@tonic-gate */ 41640Sstevel@tonic-gate case SBD_STAT_UNCONFIGURED: 41650Sstevel@tonic-gate msp->ms_detpages = msp->ms_totpages; 41660Sstevel@tonic-gate break; 41670Sstevel@tonic-gate 41680Sstevel@tonic-gate default: 41690Sstevel@tonic-gate break; 41700Sstevel@tonic-gate } 41710Sstevel@tonic-gate } 41720Sstevel@tonic-gate 41730Sstevel@tonic-gate rv = kphysm_del_span_query(mp->sbm_basepfn, 41740Sstevel@tonic-gate mp->sbm_npages, &mq); 41750Sstevel@tonic-gate if (rv == KPHYSM_OK) { 41760Sstevel@tonic-gate msp->ms_managed_pages = mq.managed; 41770Sstevel@tonic-gate msp->ms_noreloc_pages = mq.nonrelocatable; 41780Sstevel@tonic-gate msp->ms_noreloc_first = mq.first_nonrelocatable; 41790Sstevel@tonic-gate msp->ms_noreloc_last = mq.last_nonrelocatable; 41800Sstevel@tonic-gate msp->ms_cm.c_sflags = 0; 41810Sstevel@tonic-gate if (mq.nonrelocatable) { 41820Sstevel@tonic-gate SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE, 41830Sstevel@tonic-gate dsp->ds_suspend); 41840Sstevel@tonic-gate } 41850Sstevel@tonic-gate } else { 41860Sstevel@tonic-gate PR_MEM("%s: kphysm_del_span_query() = %d\n", f, rv); 41870Sstevel@tonic-gate } 41880Sstevel@tonic-gate 41890Sstevel@tonic-gate mix++; 41900Sstevel@tonic-gate dsp++; 41910Sstevel@tonic-gate } 41920Sstevel@tonic-gate 41930Sstevel@tonic-gate mutex_exit(&sbp->sb_slock); 41940Sstevel@tonic-gate 41950Sstevel@tonic-gate return (mix); 41960Sstevel@tonic-gate } 41970Sstevel@tonic-gate 41980Sstevel@tonic-gate static void 41990Sstevel@tonic-gate sbd_cancel(sbd_handle_t *hp) 42000Sstevel@tonic-gate { 42010Sstevel@tonic-gate int i; 42020Sstevel@tonic-gate sbd_devset_t devset; 42030Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 42040Sstevel@tonic-gate static fn_t f = "sbd_cancel"; 42050Sstevel@tonic-gate int rv; 42060Sstevel@tonic-gate 42070Sstevel@tonic-gate PR_ALL("%s...\n", f); 42080Sstevel@tonic-gate 42090Sstevel@tonic-gate /* 42100Sstevel@tonic-gate * Only devices which have been "released" are 42110Sstevel@tonic-gate * subject to cancellation. 42120Sstevel@tonic-gate */ 42130Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_UNREFERENCED(sbp); 42140Sstevel@tonic-gate 42150Sstevel@tonic-gate /* 42160Sstevel@tonic-gate * Nothing to do for CPUs or IO other than change back 42170Sstevel@tonic-gate * their state. 42180Sstevel@tonic-gate */ 42190Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 42200Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) 42210Sstevel@tonic-gate continue; 42220Sstevel@tonic-gate if (sbd_cancel_cpu(hp, i) != SBD_CPUERR_FATAL) { 42230Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 42240Sstevel@tonic-gate SBD_STATE_CONFIGURED); 42250Sstevel@tonic-gate } else { 42260Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 42270Sstevel@tonic-gate SBD_STATE_FATAL); 42280Sstevel@tonic-gate } 42290Sstevel@tonic-gate } 42300Sstevel@tonic-gate 42310Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 42320Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i)) 42330Sstevel@tonic-gate continue; 42340Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i, 42350Sstevel@tonic-gate SBD_STATE_CONFIGURED); 42360Sstevel@tonic-gate } 42370Sstevel@tonic-gate 42380Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 42390Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) 42400Sstevel@tonic-gate continue; 42410Sstevel@tonic-gate if ((rv = sbd_cancel_mem(hp, i)) == 0) { 42420Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 42430Sstevel@tonic-gate SBD_STATE_CONFIGURED); 42440Sstevel@tonic-gate } else if (rv == -1) { 42450Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 42460Sstevel@tonic-gate SBD_STATE_FATAL); 42470Sstevel@tonic-gate } 42480Sstevel@tonic-gate } 42490Sstevel@tonic-gate 42500Sstevel@tonic-gate PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset); 42510Sstevel@tonic-gate 42520Sstevel@tonic-gate SBD_DEVS_CANCEL(sbp, devset); 42530Sstevel@tonic-gate 42540Sstevel@tonic-gate if (SBD_DEVS_UNREFERENCED(sbp) == 0) { 42550Sstevel@tonic-gate sbd_istate_t new_state; 42560Sstevel@tonic-gate /* 42570Sstevel@tonic-gate * If the board no longer has any released devices 42580Sstevel@tonic-gate * than transfer it back to the CONFIG/PARTIAL state. 42590Sstevel@tonic-gate */ 42600Sstevel@tonic-gate if (SBD_DEVS_ATTACHED(sbp) == SBD_DEVS_PRESENT(sbp)) 42610Sstevel@tonic-gate new_state = SBD_STATE_CONFIGURED; 42620Sstevel@tonic-gate else 42630Sstevel@tonic-gate new_state = SBD_STATE_PARTIAL; 42640Sstevel@tonic-gate if (SBD_BOARD_STATE(sbp) != new_state) { 42650Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, new_state); 42660Sstevel@tonic-gate } 42670Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_CONFIGURED; 42680Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 42690Sstevel@tonic-gate } 42700Sstevel@tonic-gate } 42710Sstevel@tonic-gate 42720Sstevel@tonic-gate static void 42730Sstevel@tonic-gate sbd_get_ncm(sbd_handle_t *hp) 42740Sstevel@tonic-gate { 42750Sstevel@tonic-gate sbd_devset_t devset; 42760Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 42770Sstevel@tonic-gate sbd_cmd_t *cmdp = (sbd_cmd_t *)hp->h_iap; 42780Sstevel@tonic-gate int error; 42790Sstevel@tonic-gate 42800Sstevel@tonic-gate /* pre_op restricted the devices to those selected by the ioctl */ 42810Sstevel@tonic-gate devset = shp->sh_devset; 42820Sstevel@tonic-gate 42830Sstevel@tonic-gate cmdp->cmd_getncm.g_ncm = sbd_cpu_cnt(hp, devset) 42840Sstevel@tonic-gate + sbd_io_cnt(hp, devset) + sbd_mem_cnt(hp, devset); 42850Sstevel@tonic-gate 42860Sstevel@tonic-gate error = sbd_copyout_ioarg(hp->h_mode, hp->h_cmd, cmdp, 42870Sstevel@tonic-gate (sbd_ioctl_arg_t *)shp->sh_arg); 42880Sstevel@tonic-gate 42890Sstevel@tonic-gate if (error != 0) 42900Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), error); 42910Sstevel@tonic-gate } 42920Sstevel@tonic-gate 42930Sstevel@tonic-gate static void 42940Sstevel@tonic-gate sbd_status(sbd_handle_t *hp) 42950Sstevel@tonic-gate { 42960Sstevel@tonic-gate int nstat, mode, ncm, sz, cksz; 42970Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 42980Sstevel@tonic-gate sbd_devset_t devset; 42990Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 43000Sstevel@tonic-gate sbd_stat_t *dstatp; 43010Sstevel@tonic-gate sbd_cmd_t *cmdp = (sbd_cmd_t *)hp->h_iap; 43020Sstevel@tonic-gate sbdp_handle_t *hdp; 43030Sstevel@tonic-gate sbd_dev_stat_t *devstatp; 43040Sstevel@tonic-gate 43050Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 43060Sstevel@tonic-gate int sz32; 43070Sstevel@tonic-gate sbd_stat32_t *dstat32p; 43080Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 43090Sstevel@tonic-gate 43100Sstevel@tonic-gate static fn_t f = "sbd_status"; 43110Sstevel@tonic-gate 43120Sstevel@tonic-gate mode = hp->h_mode; 43130Sstevel@tonic-gate devset = shp->sh_devset; 43140Sstevel@tonic-gate 43150Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 43160Sstevel@tonic-gate 43170Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_NONE) { 43180Sstevel@tonic-gate if (cmdp->cmd_cm.c_flags & SBD_FLAG_ALLCMP) { 43190Sstevel@tonic-gate /* 43200Sstevel@tonic-gate * Get the number of components "ncm" on the board. 43210Sstevel@tonic-gate * Calculate size of buffer required to store one 43220Sstevel@tonic-gate * sbd_stat_t structure plus ncm-1 sbd_dev_stat_t 43230Sstevel@tonic-gate * structures. Note that sbd_stat_t already contains 43240Sstevel@tonic-gate * one sbd_dev_stat_t, so only an additional ncm-1 43250Sstevel@tonic-gate * sbd_dev_stat_t structures need to be accounted for 43260Sstevel@tonic-gate * in the calculation when more than one component 43270Sstevel@tonic-gate * is present. 43280Sstevel@tonic-gate */ 43290Sstevel@tonic-gate ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) + 43300Sstevel@tonic-gate sbd_mem_cnt(hp, devset); 43310Sstevel@tonic-gate 43320Sstevel@tonic-gate } else { 43330Sstevel@tonic-gate /* 43340Sstevel@tonic-gate * In the case of c_type == SBD_COMP_NONE, and 43350Sstevel@tonic-gate * SBD_FLAG_ALLCMP not specified, only the board 43360Sstevel@tonic-gate * info is to be returned, no components. 43370Sstevel@tonic-gate */ 43380Sstevel@tonic-gate ncm = 0; 43390Sstevel@tonic-gate devset = 0; 43400Sstevel@tonic-gate } 43410Sstevel@tonic-gate } else { 43420Sstevel@tonic-gate /* Confirm that only one component is selected. */ 43430Sstevel@tonic-gate ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) + 43440Sstevel@tonic-gate sbd_mem_cnt(hp, devset); 43450Sstevel@tonic-gate if (ncm != 1) { 43460Sstevel@tonic-gate PR_ALL("%s: expected ncm of 1, got %d, devset 0x%x\n", 43470Sstevel@tonic-gate f, ncm, devset); 43480Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 43490Sstevel@tonic-gate return; 43500Sstevel@tonic-gate } 43510Sstevel@tonic-gate } 43520Sstevel@tonic-gate 43530Sstevel@tonic-gate sz = sizeof (sbd_stat_t); 43540Sstevel@tonic-gate if (ncm > 1) 43550Sstevel@tonic-gate sz += sizeof (sbd_dev_stat_t) * (ncm - 1); 43560Sstevel@tonic-gate 43570Sstevel@tonic-gate cksz = sz; 43580Sstevel@tonic-gate 43590Sstevel@tonic-gate /* 43600Sstevel@tonic-gate * s_nbytes describes the size of the preallocated user 43610Sstevel@tonic-gate * buffer into which the application is executing to 43620Sstevel@tonic-gate * receive the sbd_stat_t and sbd_dev_stat_t structures. 43630Sstevel@tonic-gate * This buffer must be at least the required (sz) size. 43640Sstevel@tonic-gate */ 43650Sstevel@tonic-gate 43660Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 43670Sstevel@tonic-gate 43680Sstevel@tonic-gate /* 43690Sstevel@tonic-gate * More buffer space is required for the 64bit to 32bit 43700Sstevel@tonic-gate * conversion of data structures. 43710Sstevel@tonic-gate */ 43720Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 43730Sstevel@tonic-gate sz32 = sizeof (sbd_stat32_t); 43740Sstevel@tonic-gate if (ncm > 1) 43750Sstevel@tonic-gate sz32 += sizeof (sbd_dev_stat32_t) * (ncm - 1); 43760Sstevel@tonic-gate cksz = sz32; 43770Sstevel@tonic-gate } else 43780Sstevel@tonic-gate sz32 = 0; 43790Sstevel@tonic-gate #endif 43800Sstevel@tonic-gate 43810Sstevel@tonic-gate if ((int)cmdp->cmd_stat.s_nbytes < cksz) { 43820Sstevel@tonic-gate PR_ALL("%s: ncm=%d s_nbytes = 0x%x\n", f, ncm, 43830Sstevel@tonic-gate cmdp->cmd_stat.s_nbytes); 43840Sstevel@tonic-gate PR_ALL("%s: expected size of 0x%x\n", f, cksz); 43850Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 43860Sstevel@tonic-gate return; 43870Sstevel@tonic-gate } 43880Sstevel@tonic-gate 43890Sstevel@tonic-gate dstatp = kmem_zalloc(sz, KM_SLEEP); 43900Sstevel@tonic-gate devstatp = &dstatp->s_stat[0]; 43910Sstevel@tonic-gate 43920Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 43930Sstevel@tonic-gate if (sz32 != 0) 43940Sstevel@tonic-gate dstat32p = kmem_zalloc(sz32, KM_SLEEP); 43950Sstevel@tonic-gate #endif 43960Sstevel@tonic-gate 43970Sstevel@tonic-gate /* 43980Sstevel@tonic-gate * if connected or better, provide cached status if available, 43990Sstevel@tonic-gate * otherwise call sbdp for status 44000Sstevel@tonic-gate */ 44010Sstevel@tonic-gate mutex_enter(&sbp->sb_flags_mutex); 44020Sstevel@tonic-gate switch (sbp->sb_state) { 44030Sstevel@tonic-gate 44040Sstevel@tonic-gate case SBD_STATE_CONNECTED: 44050Sstevel@tonic-gate case SBD_STATE_PARTIAL: 44060Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 44070Sstevel@tonic-gate if (sbp->sb_flags & SBD_BOARD_STATUS_CACHED) { 44080Sstevel@tonic-gate bcopy(&sbp->sb_stat, dstatp, sizeof (sbd_stat_t)); 44090Sstevel@tonic-gate dstatp->s_rstate = rstate_cvt(sbp->sb_state); 44100Sstevel@tonic-gate dstatp->s_ostate = ostate_cvt(sbp->sb_state); 44110Sstevel@tonic-gate dstatp->s_busy = sbp->sb_busy; 44120Sstevel@tonic-gate dstatp->s_time = sbp->sb_time; 44130Sstevel@tonic-gate dstatp->s_cond = sbp->sb_cond; 44140Sstevel@tonic-gate break; 44150Sstevel@tonic-gate } 44160Sstevel@tonic-gate /*FALLTHROUGH*/ 44170Sstevel@tonic-gate 44180Sstevel@tonic-gate default: 44190Sstevel@tonic-gate sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 44200Sstevel@tonic-gate dstatp->s_board = sbp->sb_num; 44210Sstevel@tonic-gate dstatp->s_ostate = ostate_cvt(sbp->sb_state); 44220Sstevel@tonic-gate dstatp->s_time = sbp->sb_time; 44230Sstevel@tonic-gate 44240Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 44250Sstevel@tonic-gate 44260Sstevel@tonic-gate if (sbdp_get_board_status(hdp, dstatp) != 0) { 44270Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 44280Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 44290Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 44300Sstevel@tonic-gate if (sz32 != 0) 44310Sstevel@tonic-gate kmem_free(dstat32p, sz32); 44320Sstevel@tonic-gate #endif 44330Sstevel@tonic-gate kmem_free(dstatp, sz); 44340Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 44350Sstevel@tonic-gate return; 44360Sstevel@tonic-gate } 44370Sstevel@tonic-gate /* 44380Sstevel@tonic-gate * Do not cache status if the busy flag has 44390Sstevel@tonic-gate * been set by the call to sbdp_get_board_status(). 44400Sstevel@tonic-gate */ 44410Sstevel@tonic-gate if (!dstatp->s_busy) { 44420Sstevel@tonic-gate /* Can get board busy flag now */ 44430Sstevel@tonic-gate dstatp->s_busy = sbp->sb_busy; 44440Sstevel@tonic-gate sbp->sb_cond = (sbd_cond_t)dstatp->s_cond; 44450Sstevel@tonic-gate bcopy(dstatp, &sbp->sb_stat, 44460Sstevel@tonic-gate sizeof (sbd_stat_t)); 44470Sstevel@tonic-gate sbp->sb_flags |= SBD_BOARD_STATUS_CACHED; 44480Sstevel@tonic-gate } 44490Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 44500Sstevel@tonic-gate break; 44510Sstevel@tonic-gate } 44520Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 44530Sstevel@tonic-gate 44540Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) 44550Sstevel@tonic-gate if ((nstat = sbd_cpu_flags(hp, devset, devstatp)) > 0) { 44560Sstevel@tonic-gate dstatp->s_nstat += nstat; 44570Sstevel@tonic-gate devstatp += nstat; 44580Sstevel@tonic-gate } 44590Sstevel@tonic-gate 44600Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) 44610Sstevel@tonic-gate if ((nstat = sbd_mem_status(hp, devset, devstatp)) > 0) { 44620Sstevel@tonic-gate dstatp->s_nstat += nstat; 44630Sstevel@tonic-gate devstatp += nstat; 44640Sstevel@tonic-gate } 44650Sstevel@tonic-gate 44660Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) 44670Sstevel@tonic-gate if ((nstat = sbd_io_status(hp, devset, devstatp)) > 0) { 44680Sstevel@tonic-gate dstatp->s_nstat += nstat; 44690Sstevel@tonic-gate devstatp += nstat; 44700Sstevel@tonic-gate } 44710Sstevel@tonic-gate 44720Sstevel@tonic-gate /* paranoia: detect buffer overrun */ 44730Sstevel@tonic-gate if ((caddr_t)devstatp > ((caddr_t)dstatp) + sz) { 44740Sstevel@tonic-gate PR_ALL("%s: buffer overrun\n", f); 44750Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 44760Sstevel@tonic-gate if (sz32 != 0) 44770Sstevel@tonic-gate kmem_free(dstat32p, sz32); 44780Sstevel@tonic-gate #endif 44790Sstevel@tonic-gate kmem_free(dstatp, sz); 44800Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 44810Sstevel@tonic-gate return; 44820Sstevel@tonic-gate } 44830Sstevel@tonic-gate 44840Sstevel@tonic-gate /* if necessary, move data into intermediate device status buffer */ 44850Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 44860Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 44870Sstevel@tonic-gate int i, j; 44880Sstevel@tonic-gate 44890Sstevel@tonic-gate ASSERT(sz32 != 0); 44900Sstevel@tonic-gate /* paranoia: detect buffer overrun */ 44910Sstevel@tonic-gate if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] > 44920Sstevel@tonic-gate ((caddr_t)dstat32p) + sz32) { 44930Sstevel@tonic-gate cmn_err(CE_WARN, 44940Sstevel@tonic-gate "sbd:%s: buffer32 overrun", f); 44950Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 44960Sstevel@tonic-gate if (sz32 != 0) 44970Sstevel@tonic-gate kmem_free(dstat32p, sz32); 44980Sstevel@tonic-gate #endif 44990Sstevel@tonic-gate kmem_free(dstatp, sz); 45000Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 45010Sstevel@tonic-gate return; 45020Sstevel@tonic-gate } 45030Sstevel@tonic-gate 45040Sstevel@tonic-gate /* 45050Sstevel@tonic-gate * initialize 32 bit sbd board status structure 45060Sstevel@tonic-gate */ 45070Sstevel@tonic-gate dstat32p->s_board = (int32_t)dstatp->s_board; 45080Sstevel@tonic-gate dstat32p->s_nstat = (int32_t)dstatp->s_nstat; 45090Sstevel@tonic-gate dstat32p->s_rstate = dstatp->s_rstate; 45100Sstevel@tonic-gate dstat32p->s_ostate = dstatp->s_ostate; 45110Sstevel@tonic-gate dstat32p->s_cond = dstatp->s_cond; 45120Sstevel@tonic-gate dstat32p->s_busy = dstatp->s_busy; 45130Sstevel@tonic-gate dstat32p->s_time = dstatp->s_time; 45140Sstevel@tonic-gate dstat32p->s_assigned = dstatp->s_assigned; 45150Sstevel@tonic-gate dstat32p->s_power = dstatp->s_power; 45160Sstevel@tonic-gate dstat32p->s_platopts = (int32_t)dstatp->s_platopts; 45170Sstevel@tonic-gate (void) strcpy(dstat32p->s_type, dstatp->s_type); 45180Sstevel@tonic-gate 45190Sstevel@tonic-gate for (i = 0; i < dstatp->s_nstat; i++) { 45200Sstevel@tonic-gate sbd_dev_stat_t *dsp = &dstatp->s_stat[i]; 45210Sstevel@tonic-gate sbd_dev_stat32_t *ds32p = &dstat32p->s_stat[i]; 45220Sstevel@tonic-gate 45230Sstevel@tonic-gate /* 45240Sstevel@tonic-gate * copy common data for the device 45250Sstevel@tonic-gate */ 45260Sstevel@tonic-gate ds32p->d_cm.ci_type = (int32_t)dsp->d_cm.ci_type; 45270Sstevel@tonic-gate ds32p->d_cm.ci_unit = (int32_t)dsp->d_cm.ci_unit; 45280Sstevel@tonic-gate ds32p->d_cm.c_ostate = (int32_t)dsp->d_cm.c_ostate; 45290Sstevel@tonic-gate ds32p->d_cm.c_cond = (int32_t)dsp->d_cm.c_cond; 45300Sstevel@tonic-gate ds32p->d_cm.c_busy = (int32_t)dsp->d_cm.c_busy; 45310Sstevel@tonic-gate ds32p->d_cm.c_time = (time32_t)dsp->d_cm.c_time; 45320Sstevel@tonic-gate ds32p->d_cm.c_sflags = (int32_t)dsp->d_cm.c_sflags; 45330Sstevel@tonic-gate (void) strcpy(ds32p->d_cm.ci_name, dsp->d_cm.ci_name); 45340Sstevel@tonic-gate 45350Sstevel@tonic-gate /* copy type specific data for the device */ 45360Sstevel@tonic-gate switch (dsp->d_cm.ci_type) { 45370Sstevel@tonic-gate 45380Sstevel@tonic-gate case SBD_COMP_CPU: 45390Sstevel@tonic-gate ds32p->d_cpu.cs_isbootproc = 45400Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_isbootproc; 45410Sstevel@tonic-gate ds32p->d_cpu.cs_cpuid = 45420Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_cpuid; 45430Sstevel@tonic-gate ds32p->d_cpu.cs_speed = 45440Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_speed; 45450Sstevel@tonic-gate ds32p->d_cpu.cs_ecache = 45460Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_ecache; 45470Sstevel@tonic-gate break; 45480Sstevel@tonic-gate 45490Sstevel@tonic-gate case SBD_COMP_MEM: 45500Sstevel@tonic-gate ds32p->d_mem.ms_type = 45510Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_type; 45520Sstevel@tonic-gate ds32p->d_mem.ms_ostate = 45530Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_ostate; 45540Sstevel@tonic-gate ds32p->d_mem.ms_cond = 45550Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_cond; 45560Sstevel@tonic-gate ds32p->d_mem.ms_interleave = 45570Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_interleave; 45580Sstevel@tonic-gate ds32p->d_mem.ms_basepfn = 45590Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_basepfn; 45600Sstevel@tonic-gate ds32p->d_mem.ms_totpages = 45610Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_totpages; 45620Sstevel@tonic-gate ds32p->d_mem.ms_detpages = 45630Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_detpages; 45640Sstevel@tonic-gate ds32p->d_mem.ms_pageslost = 45650Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_pageslost; 45660Sstevel@tonic-gate ds32p->d_mem.ms_managed_pages = 45670Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_managed_pages; 45680Sstevel@tonic-gate ds32p->d_mem.ms_noreloc_pages = 45690Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_noreloc_pages; 45700Sstevel@tonic-gate ds32p->d_mem.ms_noreloc_first = 45710Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_noreloc_first; 45720Sstevel@tonic-gate ds32p->d_mem.ms_noreloc_last = 45730Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_noreloc_last; 45740Sstevel@tonic-gate ds32p->d_mem.ms_cage_enabled = 45750Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_cage_enabled; 45760Sstevel@tonic-gate ds32p->d_mem.ms_peer_is_target = 45770Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_peer_is_target; 45780Sstevel@tonic-gate (void) strcpy(ds32p->d_mem.ms_peer_ap_id, 45790Sstevel@tonic-gate dsp->d_mem.ms_peer_ap_id); 45800Sstevel@tonic-gate break; 45810Sstevel@tonic-gate 45820Sstevel@tonic-gate 45830Sstevel@tonic-gate case SBD_COMP_IO: 45840Sstevel@tonic-gate 45850Sstevel@tonic-gate ds32p->d_io.is_type = 45860Sstevel@tonic-gate (int32_t)dsp->d_io.is_type; 45870Sstevel@tonic-gate ds32p->d_io.is_unsafe_count = 45880Sstevel@tonic-gate (int32_t)dsp->d_io.is_unsafe_count; 45890Sstevel@tonic-gate ds32p->d_io.is_referenced = 45900Sstevel@tonic-gate (int32_t)dsp->d_io.is_referenced; 45910Sstevel@tonic-gate for (j = 0; j < SBD_MAX_UNSAFE; j++) 45920Sstevel@tonic-gate ds32p->d_io.is_unsafe_list[j] = 45930Sstevel@tonic-gate (int32_t) 45940Sstevel@tonic-gate ds32p->d_io.is_unsafe_list[j]; 45950Sstevel@tonic-gate bcopy(dsp->d_io.is_pathname, 45960Sstevel@tonic-gate ds32p->d_io.is_pathname, MAXPATHLEN); 45970Sstevel@tonic-gate break; 45980Sstevel@tonic-gate 45990Sstevel@tonic-gate case SBD_COMP_CMP: 46000Sstevel@tonic-gate /* copy sbd_cmp_stat_t structure members */ 46010Sstevel@tonic-gate bcopy(&dsp->d_cmp.ps_cpuid[0], 46020Sstevel@tonic-gate &ds32p->d_cmp.ps_cpuid[0], 46030Sstevel@tonic-gate sizeof (ds32p->d_cmp.ps_cpuid)); 46040Sstevel@tonic-gate ds32p->d_cmp.ps_ncores = 46050Sstevel@tonic-gate (int32_t)dsp->d_cmp.ps_ncores; 46060Sstevel@tonic-gate ds32p->d_cmp.ps_speed = 46070Sstevel@tonic-gate (int32_t)dsp->d_cmp.ps_speed; 46080Sstevel@tonic-gate ds32p->d_cmp.ps_ecache = 46090Sstevel@tonic-gate (int32_t)dsp->d_cmp.ps_ecache; 46100Sstevel@tonic-gate break; 46110Sstevel@tonic-gate 46120Sstevel@tonic-gate default: 46130Sstevel@tonic-gate cmn_err(CE_WARN, 46140Sstevel@tonic-gate "sbd:%s: unknown dev type (%d)", f, 46150Sstevel@tonic-gate (int)dsp->d_cm.c_id.c_type); 46160Sstevel@tonic-gate break; 46170Sstevel@tonic-gate } 46180Sstevel@tonic-gate } 46190Sstevel@tonic-gate 46200Sstevel@tonic-gate if (ddi_copyout((void *)dstat32p, 46210Sstevel@tonic-gate cmdp->cmd_stat.s_statp, sz32, mode) != 0) { 46220Sstevel@tonic-gate cmn_err(CE_WARN, 46230Sstevel@tonic-gate "sbd:%s: failed to copyout status " 46240Sstevel@tonic-gate "for board %d", f, sbp->sb_num); 46250Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT); 46260Sstevel@tonic-gate } 46270Sstevel@tonic-gate } else 46280Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 46290Sstevel@tonic-gate if (ddi_copyout((void *)dstatp, cmdp->cmd_stat.s_statp, 46300Sstevel@tonic-gate sz, mode) != 0) { 46310Sstevel@tonic-gate cmn_err(CE_WARN, 46320Sstevel@tonic-gate "sbd:%s: failed to copyout status for board %d", 46330Sstevel@tonic-gate f, sbp->sb_num); 46340Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT); 46350Sstevel@tonic-gate } 46360Sstevel@tonic-gate 46370Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 46380Sstevel@tonic-gate if (sz32 != 0) 46390Sstevel@tonic-gate kmem_free(dstat32p, sz32); 46400Sstevel@tonic-gate #endif 46410Sstevel@tonic-gate kmem_free(dstatp, sz); 46420Sstevel@tonic-gate } 46430Sstevel@tonic-gate 46440Sstevel@tonic-gate /* 46450Sstevel@tonic-gate * Called at driver load time to determine the state and condition 46460Sstevel@tonic-gate * of an existing board in the system. 46470Sstevel@tonic-gate */ 46480Sstevel@tonic-gate static void 46490Sstevel@tonic-gate sbd_board_discovery(sbd_board_t *sbp) 46500Sstevel@tonic-gate { 46510Sstevel@tonic-gate int i; 46520Sstevel@tonic-gate dev_info_t *dip; 46530Sstevel@tonic-gate sbd_devset_t devs_lost, devs_attached = 0; 46540Sstevel@tonic-gate extern kmutex_t cpu_lock; 46550Sstevel@tonic-gate sbdp_handle_t *hdp; 46560Sstevel@tonic-gate static fn_t f = "sbd_board_discovery"; 46570Sstevel@tonic-gate sbderror_t error, *ep; 46580Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 46590Sstevel@tonic-gate 46600Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp) == 0) { 46610Sstevel@tonic-gate PR_ALL("%s: board %d has no devices present\n", 46620Sstevel@tonic-gate f, sbp->sb_num); 46630Sstevel@tonic-gate return; 46640Sstevel@tonic-gate } 46650Sstevel@tonic-gate 46660Sstevel@tonic-gate ep = &error; 46670Sstevel@tonic-gate bzero(ep, sizeof (sbderror_t)); 46680Sstevel@tonic-gate 46690Sstevel@tonic-gate /* 46700Sstevel@tonic-gate * Check for existence of cpus. 46710Sstevel@tonic-gate */ 46720Sstevel@tonic-gate 46730Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 46740Sstevel@tonic-gate 46750Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 46760Sstevel@tonic-gate processorid_t cpuid; 46770Sstevel@tonic-gate 46780Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) 46790Sstevel@tonic-gate continue; 46800Sstevel@tonic-gate 46810Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][i]; 46820Sstevel@tonic-gate 46830Sstevel@tonic-gate if (dip != NULL) { 46840Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 46850Sstevel@tonic-gate 46860Sstevel@tonic-gate if (cpuid < 0) { 46870Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, 46880Sstevel@tonic-gate ep); 46890Sstevel@tonic-gate continue; 46900Sstevel@tonic-gate } 46910Sstevel@tonic-gate 46920Sstevel@tonic-gate mutex_enter(&cpu_lock); /* needed to call cpu_get() */ 46930Sstevel@tonic-gate if (cpu_get(cpuid)) { 46940Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_CPU, i); 46950Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_CPU, i); 46960Sstevel@tonic-gate PR_ALL("%s: board %d, cpuid %d - attached\n", 46970Sstevel@tonic-gate f, sbp->sb_num, cpuid); 46980Sstevel@tonic-gate } 46990Sstevel@tonic-gate mutex_exit(&cpu_lock); 47000Sstevel@tonic-gate sbd_init_cpu_unit(sbp, i); 47010Sstevel@tonic-gate } 47020Sstevel@tonic-gate } 47030Sstevel@tonic-gate 47040Sstevel@tonic-gate /* 47050Sstevel@tonic-gate * Check for existence of memory. 47060Sstevel@tonic-gate */ 47070Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 47080Sstevel@tonic-gate uint64_t basepa, endpa; 47090Sstevel@tonic-gate struct memlist *ml; 47100Sstevel@tonic-gate extern struct memlist *phys_install; 47110Sstevel@tonic-gate 47120Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) 47130Sstevel@tonic-gate continue; 47140Sstevel@tonic-gate 47150Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i]; 47160Sstevel@tonic-gate if (dip == NULL) 47170Sstevel@tonic-gate continue; 47180Sstevel@tonic-gate 47190Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) { 47200Sstevel@tonic-gate /* omit phantom memory controllers on I/O boards */ 47210Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) { 47220Sstevel@tonic-gate ASSERT(sbp->sb_ndev != 0); 47230Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i); 47240Sstevel@tonic-gate sbp->sb_ndev--; 47250Sstevel@tonic-gate } 47260Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL; 47270Sstevel@tonic-gate continue; 47280Sstevel@tonic-gate } 47290Sstevel@tonic-gate 47300Sstevel@tonic-gate /* 47310Sstevel@tonic-gate * basepa may not be on a alignment boundary, make it so. 47320Sstevel@tonic-gate */ 47330Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, dip, &endpa)) { 47340Sstevel@tonic-gate cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f); 47350Sstevel@tonic-gate continue; 47360Sstevel@tonic-gate } 47370Sstevel@tonic-gate 47380Sstevel@tonic-gate basepa &= ~(endpa - 1); 47390Sstevel@tonic-gate endpa += basepa; 47400Sstevel@tonic-gate 47410Sstevel@tonic-gate /* 47420Sstevel@tonic-gate * Check if base address is in phys_install. 47430Sstevel@tonic-gate */ 47440Sstevel@tonic-gate memlist_read_lock(); 47450Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) 47460Sstevel@tonic-gate if ((endpa <= ml->address) || 47470Sstevel@tonic-gate (basepa >= (ml->address + ml->size))) 47480Sstevel@tonic-gate continue; 47490Sstevel@tonic-gate else 47500Sstevel@tonic-gate break; 47510Sstevel@tonic-gate memlist_read_unlock(); 47520Sstevel@tonic-gate 47530Sstevel@tonic-gate if (ml) { 47540Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_MEM, i); 47550Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_MEM, i); 47560Sstevel@tonic-gate PR_ALL("%s: board %d, mem-unit %d - attached\n", 47570Sstevel@tonic-gate f, sbp->sb_num, i); 47580Sstevel@tonic-gate } 47590Sstevel@tonic-gate sbd_init_mem_unit(sbp, i, ep); 47600Sstevel@tonic-gate } 47610Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 47620Sstevel@tonic-gate 47630Sstevel@tonic-gate /* 47640Sstevel@tonic-gate * If so far we have found an error, we just log it but continue 47650Sstevel@tonic-gate */ 47660Sstevel@tonic-gate if (SBD_GET_ERRNO(ep) != 0) 47670Sstevel@tonic-gate cmn_err(CE_WARN, "%s errno has occurred: errno %d", f, 47680Sstevel@tonic-gate SBD_GET_ERRNO(ep)); 47690Sstevel@tonic-gate 47700Sstevel@tonic-gate /* 47710Sstevel@tonic-gate * Check for i/o state. 47720Sstevel@tonic-gate */ 47730Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 47740Sstevel@tonic-gate 47750Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i)) 47760Sstevel@tonic-gate continue; 47770Sstevel@tonic-gate 47780Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i]; 47790Sstevel@tonic-gate if (dip == NULL) 47800Sstevel@tonic-gate continue; 47810Sstevel@tonic-gate 47820Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 47830Sstevel@tonic-gate 47840Sstevel@tonic-gate /* 47850Sstevel@tonic-gate * XXX Is the devstate check needed ? 47860Sstevel@tonic-gate */ 47870Sstevel@tonic-gate if (i_ddi_node_state(dip) >= DS_ATTACHED || 47880Sstevel@tonic-gate ddi_get_devstate(dip) == DDI_DEVSTATE_UP) { 47890Sstevel@tonic-gate 47900Sstevel@tonic-gate /* 47910Sstevel@tonic-gate * Found it! 47920Sstevel@tonic-gate */ 47930Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_IO, i); 47940Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_IO, i); 47950Sstevel@tonic-gate PR_ALL("%s: board %d, io-unit %d - attached\n", 47960Sstevel@tonic-gate f, sbp->sb_num, i); 47970Sstevel@tonic-gate } 47980Sstevel@tonic-gate sbd_init_io_unit(sbp, i); 47990Sstevel@tonic-gate } 48000Sstevel@tonic-gate 48010Sstevel@tonic-gate SBD_DEVS_CONFIGURE(sbp, devs_attached); 48020Sstevel@tonic-gate if (devs_attached && ((devs_lost = SBD_DEVS_UNATTACHED(sbp)) != 0)) { 48030Sstevel@tonic-gate int ut; 48040Sstevel@tonic-gate /* 48050Sstevel@tonic-gate * A prior comment stated that a partially configured 48060Sstevel@tonic-gate * board was not permitted. The Serengeti architecture 48070Sstevel@tonic-gate * makes this possible, so the SB_DEVS_DISCONNECT 48080Sstevel@tonic-gate * at the end of this block has been removed. 48090Sstevel@tonic-gate */ 48100Sstevel@tonic-gate 48110Sstevel@tonic-gate PR_ALL("%s: some devices not configured (0x%x)...\n", 48120Sstevel@tonic-gate f, devs_lost); 48130Sstevel@tonic-gate 48140Sstevel@tonic-gate for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) 48150Sstevel@tonic-gate if (DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) { 48160Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, 48170Sstevel@tonic-gate ut, SBD_STATE_UNCONFIGURED); 48180Sstevel@tonic-gate } 48190Sstevel@tonic-gate 48200Sstevel@tonic-gate for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) 48210Sstevel@tonic-gate if (DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut)) { 48220Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 48230Sstevel@tonic-gate ut, SBD_STATE_UNCONFIGURED); 48240Sstevel@tonic-gate } 48250Sstevel@tonic-gate 48260Sstevel@tonic-gate for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) 48270Sstevel@tonic-gate if (DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut)) { 48280Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, 48290Sstevel@tonic-gate ut, SBD_STATE_UNCONFIGURED); 48300Sstevel@tonic-gate } 48310Sstevel@tonic-gate } 48320Sstevel@tonic-gate } 48330Sstevel@tonic-gate 48340Sstevel@tonic-gate static int 48350Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg) 48360Sstevel@tonic-gate { 48370Sstevel@tonic-gate walk_tree_t *wp = (walk_tree_t *)arg; 48380Sstevel@tonic-gate 48390Sstevel@tonic-gate ASSERT(wp && (wp->hold == 0 || wp->hold == 1)); 48400Sstevel@tonic-gate 48410Sstevel@tonic-gate switch (get_node_type(wp->sbp, rdip, NULL)) { 48420Sstevel@tonic-gate case SBD_COMP_CMP: 48430Sstevel@tonic-gate case SBD_COMP_MEM: 48440Sstevel@tonic-gate case SBD_COMP_IO: 48450Sstevel@tonic-gate break; 48460Sstevel@tonic-gate case SBD_COMP_CPU: 48470Sstevel@tonic-gate 48480Sstevel@tonic-gate /* 48490Sstevel@tonic-gate * All CPU nodes under CMP nodes should have 48500Sstevel@tonic-gate * gotten pruned when the CMP node was first 48510Sstevel@tonic-gate * encountered. 48520Sstevel@tonic-gate */ 48530Sstevel@tonic-gate ASSERT(!sbd_is_cmp_child(rdip)); 48540Sstevel@tonic-gate 48550Sstevel@tonic-gate break; 48560Sstevel@tonic-gate 48570Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 48580Sstevel@tonic-gate /* Not of interest to us */ 48590Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 48600Sstevel@tonic-gate default: 48610Sstevel@tonic-gate ASSERT(0); 48620Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 48630Sstevel@tonic-gate } 48640Sstevel@tonic-gate 48650Sstevel@tonic-gate if (wp->hold) { 48660Sstevel@tonic-gate ASSERT(!e_ddi_branch_held(rdip)); 48670Sstevel@tonic-gate e_ddi_branch_hold(rdip); 48680Sstevel@tonic-gate } else { 48690Sstevel@tonic-gate ASSERT(e_ddi_branch_held(rdip)); 48700Sstevel@tonic-gate e_ddi_branch_rele(rdip); 48710Sstevel@tonic-gate } 48720Sstevel@tonic-gate 48730Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 48740Sstevel@tonic-gate } 48750Sstevel@tonic-gate 48760Sstevel@tonic-gate static void 48770Sstevel@tonic-gate sbd_board_init(sbd_board_t *sbp, sbd_softstate_t *softsp, 48780Sstevel@tonic-gate int bd, dev_info_t *top_dip, int wnode) 48790Sstevel@tonic-gate { 48800Sstevel@tonic-gate int i; 48810Sstevel@tonic-gate dev_info_t *pdip; 48820Sstevel@tonic-gate int circ; 48830Sstevel@tonic-gate walk_tree_t walk = {0}; 48840Sstevel@tonic-gate 48850Sstevel@tonic-gate mutex_init(&sbp->sb_mutex, NULL, MUTEX_DRIVER, NULL); 48860Sstevel@tonic-gate mutex_init(&sbp->sb_flags_mutex, NULL, MUTEX_DRIVER, NULL); 48870Sstevel@tonic-gate mutex_init(&sbp->sb_slock, NULL, MUTEX_DRIVER, NULL); 48880Sstevel@tonic-gate 48890Sstevel@tonic-gate sbp->sb_ref = 0; 48900Sstevel@tonic-gate sbp->sb_num = bd; 48910Sstevel@tonic-gate sbp->sb_time = gethrestime_sec(); 48920Sstevel@tonic-gate /* 48930Sstevel@tonic-gate * For serengeti, top_dip doesn't need to be held because 48940Sstevel@tonic-gate * sbp i.e. sbd_board_t will be destroyed in sbd_teardown_instance() 48950Sstevel@tonic-gate * before top_dip detaches. For Daktari, top_dip is the 48960Sstevel@tonic-gate * root node which never has to be held. 48970Sstevel@tonic-gate */ 48980Sstevel@tonic-gate sbp->sb_topdip = top_dip; 48990Sstevel@tonic-gate sbp->sb_cpuid = -1; 49000Sstevel@tonic-gate sbp->sb_softsp = (void *) softsp; 49010Sstevel@tonic-gate sbp->sb_cond = SBD_COND_UNKNOWN; 49020Sstevel@tonic-gate sbp->sb_wnode = wnode; 49030Sstevel@tonic-gate sbp->sb_memaccess_ok = 1; 49040Sstevel@tonic-gate 49050Sstevel@tonic-gate ASSERT(MAX_IO_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 49060Sstevel@tonic-gate ASSERT(MAX_CPU_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 49070Sstevel@tonic-gate ASSERT(MAX_MEM_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 49080Sstevel@tonic-gate 49090Sstevel@tonic-gate /* 49100Sstevel@tonic-gate * Allocate the devlist for cpus. 49110Sstevel@tonic-gate */ 49120Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_CPU)] = GETSTRUCT(dev_info_t *, 49130Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 49140Sstevel@tonic-gate 49150Sstevel@tonic-gate /* 49160Sstevel@tonic-gate * Allocate the devlist for mem. 49170Sstevel@tonic-gate */ 49180Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)] = GETSTRUCT(dev_info_t *, 49190Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 49200Sstevel@tonic-gate 49210Sstevel@tonic-gate /* 49220Sstevel@tonic-gate * Allocate the devlist for io. 49230Sstevel@tonic-gate */ 49240Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_IO)] = GETSTRUCT(dev_info_t *, 49250Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 49260Sstevel@tonic-gate 49270Sstevel@tonic-gate 49280Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(sbd_dev_unit_t, 49290Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 49300Sstevel@tonic-gate 49310Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(sbd_dev_unit_t, 49320Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 49330Sstevel@tonic-gate 49340Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(sbd_dev_unit_t, 49350Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 49360Sstevel@tonic-gate 49370Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 49380Sstevel@tonic-gate sbp->sb_cpupath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 49390Sstevel@tonic-gate } 49400Sstevel@tonic-gate 49410Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 49420Sstevel@tonic-gate sbp->sb_mempath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 49430Sstevel@tonic-gate } 49440Sstevel@tonic-gate 49450Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 49460Sstevel@tonic-gate sbp->sb_iopath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 49470Sstevel@tonic-gate } 49480Sstevel@tonic-gate 49490Sstevel@tonic-gate /* 49500Sstevel@tonic-gate * Walk the device tree, find all top dips on this board and 49510Sstevel@tonic-gate * hold the branches rooted at them 49520Sstevel@tonic-gate */ 49530Sstevel@tonic-gate ASSERT(sbp->sb_topdip); 49540Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 49550Sstevel@tonic-gate if (pdip) 49560Sstevel@tonic-gate ndi_devi_enter(pdip, &circ); 49570Sstevel@tonic-gate walk.sbp = sbp; 49580Sstevel@tonic-gate walk.hold = 1; 49590Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk); 49600Sstevel@tonic-gate if (pdip) 49610Sstevel@tonic-gate ndi_devi_exit(pdip, circ); 49620Sstevel@tonic-gate 49630Sstevel@tonic-gate /* 49640Sstevel@tonic-gate * Initialize the devlists 49650Sstevel@tonic-gate */ 49660Sstevel@tonic-gate if (sbd_init_devlists(sbp) == 0) { 49670Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY); 49680Sstevel@tonic-gate } else { 49690Sstevel@tonic-gate /* 49700Sstevel@tonic-gate * Couldn't have made it down here without 49710Sstevel@tonic-gate * having found at least one device. 49720Sstevel@tonic-gate */ 49730Sstevel@tonic-gate ASSERT(SBD_DEVS_PRESENT(sbp) != 0); 49740Sstevel@tonic-gate /* 49750Sstevel@tonic-gate * Check the state of any possible devices on the 49760Sstevel@tonic-gate * board. 49770Sstevel@tonic-gate */ 49780Sstevel@tonic-gate sbd_board_discovery(sbp); 49790Sstevel@tonic-gate 49800Sstevel@tonic-gate if (SBD_DEVS_UNATTACHED(sbp) == 0) { 49810Sstevel@tonic-gate /* 49820Sstevel@tonic-gate * The board has no unattached devices, therefore 49830Sstevel@tonic-gate * by reason of insanity it must be configured! 49840Sstevel@tonic-gate */ 49850Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 49860Sstevel@tonic-gate sbp->sb_cond = SBD_COND_OK; 49870Sstevel@tonic-gate } else if (SBD_DEVS_ATTACHED(sbp)) { 49880Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 49890Sstevel@tonic-gate } else { 49900Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED); 49910Sstevel@tonic-gate } 49920Sstevel@tonic-gate } 49930Sstevel@tonic-gate } 49940Sstevel@tonic-gate 49950Sstevel@tonic-gate static void 49960Sstevel@tonic-gate sbd_board_destroy(sbd_board_t *sbp) 49970Sstevel@tonic-gate { 49980Sstevel@tonic-gate int i; 49990Sstevel@tonic-gate dev_info_t *pdip; 50000Sstevel@tonic-gate int circ; 50010Sstevel@tonic-gate walk_tree_t walk = {0}; 50020Sstevel@tonic-gate 50030Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY); 50040Sstevel@tonic-gate 50050Sstevel@tonic-gate #ifdef DEBUG 50060Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 50070Sstevel@tonic-gate sbd_mem_unit_t *mp; 50080Sstevel@tonic-gate 50090Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, i); 50100Sstevel@tonic-gate ASSERT(mp->sbm_mlist == NULL); 50110Sstevel@tonic-gate } 50120Sstevel@tonic-gate #endif /* DEBUG */ 50130Sstevel@tonic-gate 50140Sstevel@tonic-gate /* 50150Sstevel@tonic-gate * Free up MEM unit structs. 50160Sstevel@tonic-gate */ 50170Sstevel@tonic-gate FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_MEM)], 50180Sstevel@tonic-gate sbd_dev_unit_t, MAX_MEM_UNITS_PER_BOARD); 50190Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_MEM)] = NULL; 50200Sstevel@tonic-gate 50210Sstevel@tonic-gate /* 50220Sstevel@tonic-gate * Free up CPU unit structs. 50230Sstevel@tonic-gate */ 50240Sstevel@tonic-gate FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_CPU)], 50250Sstevel@tonic-gate sbd_dev_unit_t, MAX_CPU_UNITS_PER_BOARD); 50260Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_CPU)] = NULL; 50270Sstevel@tonic-gate 50280Sstevel@tonic-gate /* 50290Sstevel@tonic-gate * Free up IO unit structs. 50300Sstevel@tonic-gate */ 50310Sstevel@tonic-gate FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_IO)], 50320Sstevel@tonic-gate sbd_dev_unit_t, MAX_IO_UNITS_PER_BOARD); 50330Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_IO)] = NULL; 50340Sstevel@tonic-gate 50350Sstevel@tonic-gate /* 50360Sstevel@tonic-gate * free up CPU devlists. 50370Sstevel@tonic-gate */ 50380Sstevel@tonic-gate 50390Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 50400Sstevel@tonic-gate kmem_free((caddr_t)sbp->sb_cpupath[i], MAXPATHLEN); 50410Sstevel@tonic-gate } 50420Sstevel@tonic-gate FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_CPU)], dev_info_t *, 50430Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 50440Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_CPU)] = NULL; 50450Sstevel@tonic-gate 50460Sstevel@tonic-gate /* 50470Sstevel@tonic-gate * free up MEM devlists. 50480Sstevel@tonic-gate */ 50490Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 50500Sstevel@tonic-gate kmem_free((caddr_t)sbp->sb_mempath[i], MAXPATHLEN); 50510Sstevel@tonic-gate } 50520Sstevel@tonic-gate FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_MEM)], dev_info_t *, 50530Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 50540Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)] = NULL; 50550Sstevel@tonic-gate 50560Sstevel@tonic-gate /* 50570Sstevel@tonic-gate * free up IO devlists. 50580Sstevel@tonic-gate */ 50590Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 50600Sstevel@tonic-gate kmem_free((caddr_t)sbp->sb_iopath[i], MAXPATHLEN); 50610Sstevel@tonic-gate } 50620Sstevel@tonic-gate FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_IO)], dev_info_t *, 50630Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 50640Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_IO)] = NULL; 50650Sstevel@tonic-gate 50660Sstevel@tonic-gate /* 50670Sstevel@tonic-gate * Release all branches held earlier 50680Sstevel@tonic-gate */ 50690Sstevel@tonic-gate ASSERT(sbp->sb_topdip); 50700Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 50710Sstevel@tonic-gate if (pdip) 50720Sstevel@tonic-gate ndi_devi_enter(pdip, &circ); 50730Sstevel@tonic-gate walk.sbp = sbp; 50740Sstevel@tonic-gate walk.hold = 0; 50750Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk); 50760Sstevel@tonic-gate if (pdip) 50770Sstevel@tonic-gate ndi_devi_exit(pdip, circ); 50780Sstevel@tonic-gate 50790Sstevel@tonic-gate mutex_destroy(&sbp->sb_slock); 50800Sstevel@tonic-gate mutex_destroy(&sbp->sb_flags_mutex); 50810Sstevel@tonic-gate mutex_destroy(&sbp->sb_mutex); 50820Sstevel@tonic-gate } 50830Sstevel@tonic-gate 50840Sstevel@tonic-gate sbd_comp_type_t 50850Sstevel@tonic-gate sbd_cm_type(char *name) 50860Sstevel@tonic-gate { 50870Sstevel@tonic-gate sbd_comp_type_t type = SBD_COMP_UNKNOWN; 50880Sstevel@tonic-gate int i; 50890Sstevel@tonic-gate 50900Sstevel@tonic-gate /* look up type in table */ 50910Sstevel@tonic-gate for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 50920Sstevel@tonic-gate if (strcmp(name, SBD_OTYPE(i)) == 0) { 50930Sstevel@tonic-gate type = SBD_COMP(i); 50940Sstevel@tonic-gate break; 50950Sstevel@tonic-gate } 50960Sstevel@tonic-gate } 50970Sstevel@tonic-gate 50980Sstevel@tonic-gate return (type); 50990Sstevel@tonic-gate } 51000Sstevel@tonic-gate 51010Sstevel@tonic-gate /* 51020Sstevel@tonic-gate * There are certain cases where obp marks components as failed 51030Sstevel@tonic-gate * If the status is ok the node won't have any status property. It 51040Sstevel@tonic-gate * is only there if the status is other than ok. 51050Sstevel@tonic-gate * 51060Sstevel@tonic-gate * The translation is as follows: 51070Sstevel@tonic-gate * If there is no status prop, the the cond is SBD_COND_OK 51080Sstevel@tonic-gate * If we find a status prop but can't get to it then cond is SBD_COND_UNKNOWN 51090Sstevel@tonic-gate * if we find a stat and it is failed the cond is SBD_COND_FAILED 51100Sstevel@tonic-gate * If the stat is disabled, the cond is SBD_COND_UNUSABLE 51110Sstevel@tonic-gate * Otherwise we return con as SBD_COND_OK 51120Sstevel@tonic-gate */ 51130Sstevel@tonic-gate sbd_cond_t 51140Sstevel@tonic-gate sbd_get_comp_cond(dev_info_t *dip) 51150Sstevel@tonic-gate { 51160Sstevel@tonic-gate int len; 51170Sstevel@tonic-gate char *status_buf; 51180Sstevel@tonic-gate static const char *status = "status"; 51190Sstevel@tonic-gate static const char *failed = "fail"; 51200Sstevel@tonic-gate static const char *disabled = "disabled"; 51210Sstevel@tonic-gate 51220Sstevel@tonic-gate if (dip == NULL) { 51230Sstevel@tonic-gate PR_BYP("dip is NULL\n"); 51240Sstevel@tonic-gate return (SBD_COND_UNKNOWN); 51250Sstevel@tonic-gate } 51260Sstevel@tonic-gate 51270Sstevel@tonic-gate if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 51280Sstevel@tonic-gate (char *)status, &len) != DDI_PROP_SUCCESS) { 51290Sstevel@tonic-gate PR_CPU("status in sbd is ok\n"); 51300Sstevel@tonic-gate return (SBD_COND_OK); 51310Sstevel@tonic-gate } 51320Sstevel@tonic-gate 51330Sstevel@tonic-gate status_buf = kmem_zalloc(sizeof (char) * OBP_MAXPROPNAME, KM_SLEEP); 5134506Scth if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 51350Sstevel@tonic-gate (char *)status, status_buf, &len) != DDI_PROP_SUCCESS) { 51360Sstevel@tonic-gate PR_CPU("status in sbd is unknown\n"); 51370Sstevel@tonic-gate return (SBD_COND_UNKNOWN); 51380Sstevel@tonic-gate } 51390Sstevel@tonic-gate 51400Sstevel@tonic-gate if (strncmp(status_buf, failed, strlen(failed)) == 0) { 51410Sstevel@tonic-gate PR_CPU("status in sbd is failed\n"); 51420Sstevel@tonic-gate kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 51430Sstevel@tonic-gate return (SBD_COND_FAILED); 51440Sstevel@tonic-gate } 51450Sstevel@tonic-gate 51460Sstevel@tonic-gate if (strcmp(status_buf, disabled) == 0) { 51470Sstevel@tonic-gate PR_CPU("status in sbd is unusable\n"); 51480Sstevel@tonic-gate kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 51490Sstevel@tonic-gate return (SBD_COND_UNUSABLE); 51500Sstevel@tonic-gate } 51510Sstevel@tonic-gate 51520Sstevel@tonic-gate kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 51530Sstevel@tonic-gate return (SBD_COND_OK); 51540Sstevel@tonic-gate } 51550Sstevel@tonic-gate 51560Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS 51570Sstevel@tonic-gate 51580Sstevel@tonic-gate /* function to simulate errors throughout the sbd code */ 51590Sstevel@tonic-gate void 51600Sstevel@tonic-gate sbd_inject_err(int error, sbderror_t *ep, int Errno, int ecode, 51610Sstevel@tonic-gate char *rsc) 51620Sstevel@tonic-gate { 51630Sstevel@tonic-gate static fn_t f = "sbd_inject_err"; 51640Sstevel@tonic-gate 51650Sstevel@tonic-gate if (sbd_err_debug == 0) 51660Sstevel@tonic-gate return; 51670Sstevel@tonic-gate 51680Sstevel@tonic-gate if (ep == NULL) { 51690Sstevel@tonic-gate cmn_err(CE_WARN, "%s ep is NULL", f); 51700Sstevel@tonic-gate return; 51710Sstevel@tonic-gate } 51720Sstevel@tonic-gate 51730Sstevel@tonic-gate if (SBD_GET_ERRNO(ep) != 0) { 51740Sstevel@tonic-gate cmn_err(CE_WARN, "%s errno already set to %d", f, 51750Sstevel@tonic-gate SBD_GET_ERRNO(ep)); 51760Sstevel@tonic-gate return; 51770Sstevel@tonic-gate } 51780Sstevel@tonic-gate 51790Sstevel@tonic-gate if (SBD_GET_ERR(ep) != 0) { 51800Sstevel@tonic-gate cmn_err(CE_WARN, "%s code already set to %d", f, 51810Sstevel@tonic-gate SBD_GET_ERR(ep)); 51820Sstevel@tonic-gate return; 51830Sstevel@tonic-gate } 51840Sstevel@tonic-gate 51850Sstevel@tonic-gate if ((sbd_err_debug & (1 << error)) != 0) { 51860Sstevel@tonic-gate ep->e_errno = Errno; 51870Sstevel@tonic-gate ep->e_code = ecode; 51880Sstevel@tonic-gate 51890Sstevel@tonic-gate if (rsc != NULL) 51900Sstevel@tonic-gate bcopy((caddr_t)rsc, 51910Sstevel@tonic-gate (caddr_t)ep->e_rsc, 51920Sstevel@tonic-gate sizeof (ep->e_rsc)); 51930Sstevel@tonic-gate 51940Sstevel@tonic-gate if (Errno != 0) 51950Sstevel@tonic-gate PR_ERR_ERRNO("%s set errno to %d", f, ep->e_errno); 51960Sstevel@tonic-gate 51970Sstevel@tonic-gate if (ecode != 0) 51980Sstevel@tonic-gate PR_ERR_ECODE("%s set ecode to %d", f, ep->e_code); 51990Sstevel@tonic-gate 52000Sstevel@tonic-gate if (rsc != NULL) 52010Sstevel@tonic-gate PR_ERR_RSC("%s set rsc to %s", f, ep->e_rsc); 52020Sstevel@tonic-gate } 52030Sstevel@tonic-gate } 52040Sstevel@tonic-gate #endif 5205