1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* 30*0Sstevel@tonic-gate * safari system board DR module. 31*0Sstevel@tonic-gate */ 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate #include <sys/debug.h> 34*0Sstevel@tonic-gate #include <sys/types.h> 35*0Sstevel@tonic-gate #include <sys/errno.h> 36*0Sstevel@tonic-gate #include <sys/cred.h> 37*0Sstevel@tonic-gate #include <sys/dditypes.h> 38*0Sstevel@tonic-gate #include <sys/devops.h> 39*0Sstevel@tonic-gate #include <sys/modctl.h> 40*0Sstevel@tonic-gate #include <sys/poll.h> 41*0Sstevel@tonic-gate #include <sys/conf.h> 42*0Sstevel@tonic-gate #include <sys/ddi.h> 43*0Sstevel@tonic-gate #include <sys/sunddi.h> 44*0Sstevel@tonic-gate #include <sys/sunndi.h> 45*0Sstevel@tonic-gate #include <sys/ndi_impldefs.h> 46*0Sstevel@tonic-gate #include <sys/stat.h> 47*0Sstevel@tonic-gate #include <sys/kmem.h> 48*0Sstevel@tonic-gate #include <sys/cpuvar.h> 49*0Sstevel@tonic-gate #include <sys/mem_config.h> 50*0Sstevel@tonic-gate #include <sys/mem_cage.h> 51*0Sstevel@tonic-gate 52*0Sstevel@tonic-gate #include <sys/autoconf.h> 53*0Sstevel@tonic-gate #include <sys/cmn_err.h> 54*0Sstevel@tonic-gate 55*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 56*0Sstevel@tonic-gate #include <sys/machsystm.h> 57*0Sstevel@tonic-gate #include <sys/param.h> 58*0Sstevel@tonic-gate 59*0Sstevel@tonic-gate #include <sys/sbdpriv.h> 60*0Sstevel@tonic-gate #include <sys/sbd_io.h> 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate /* start sbd includes */ 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate #include <sys/systm.h> 65*0Sstevel@tonic-gate #include <sys/sysmacros.h> 66*0Sstevel@tonic-gate #include <sys/x_call.h> 67*0Sstevel@tonic-gate #include <sys/membar.h> 68*0Sstevel@tonic-gate #include <vm/seg_kmem.h> 69*0Sstevel@tonic-gate 70*0Sstevel@tonic-gate extern int nulldev(); 71*0Sstevel@tonic-gate extern int nodev(); 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate typedef struct { /* arg to sbd_get_handle */ 74*0Sstevel@tonic-gate dev_t dev; 75*0Sstevel@tonic-gate int cmd; 76*0Sstevel@tonic-gate int mode; 77*0Sstevel@tonic-gate sbd_ioctl_arg_t *ioargp; 78*0Sstevel@tonic-gate } sbd_init_arg_t; 79*0Sstevel@tonic-gate 80*0Sstevel@tonic-gate 81*0Sstevel@tonic-gate /* 82*0Sstevel@tonic-gate * sbd support operations. 83*0Sstevel@tonic-gate */ 84*0Sstevel@tonic-gate static void sbd_exec_op(sbd_handle_t *hp); 85*0Sstevel@tonic-gate static void sbd_dev_configure(sbd_handle_t *hp); 86*0Sstevel@tonic-gate static int sbd_dev_release(sbd_handle_t *hp); 87*0Sstevel@tonic-gate static int sbd_dev_unconfigure(sbd_handle_t *hp); 88*0Sstevel@tonic-gate static void sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, 89*0Sstevel@tonic-gate dev_info_t *dip, int unit); 90*0Sstevel@tonic-gate static void sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, 91*0Sstevel@tonic-gate dev_info_t *dip, int unit); 92*0Sstevel@tonic-gate static int sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit); 93*0Sstevel@tonic-gate static void sbd_cancel(sbd_handle_t *hp); 94*0Sstevel@tonic-gate void sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip); 95*0Sstevel@tonic-gate int sbd_dealloc_instance(sbd_board_t *sbp, int max_boards); 96*0Sstevel@tonic-gate int sbd_errno2ecode(int error); 97*0Sstevel@tonic-gate #pragma weak sbdp_cpu_get_impl 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate #ifdef DEBUG 100*0Sstevel@tonic-gate uint_t sbd_debug = (uint_t)0x0; 101*0Sstevel@tonic-gate 102*0Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS 103*0Sstevel@tonic-gate /* controls which errors are injected */ 104*0Sstevel@tonic-gate uint_t sbd_err_debug = (uint_t)0x0; 105*0Sstevel@tonic-gate 106*0Sstevel@tonic-gate /* controls printing about error injection */ 107*0Sstevel@tonic-gate uint_t sbd_print_errs = (uint_t)0x0; 108*0Sstevel@tonic-gate 109*0Sstevel@tonic-gate #endif /* SBD_DEBUG_ERRS */ 110*0Sstevel@tonic-gate 111*0Sstevel@tonic-gate #endif /* DEBUG */ 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate char *sbd_state_str[] = { 114*0Sstevel@tonic-gate "EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED", 115*0Sstevel@tonic-gate "PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED", 116*0Sstevel@tonic-gate "FATAL" 117*0Sstevel@tonic-gate }; 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate /* Note: this must be changed in tandem with sbd_ioctl.h */ 120*0Sstevel@tonic-gate char *sbd_ct_str[] = { 121*0Sstevel@tonic-gate "NONE", "CPU", "MEM", "IO", "UNKNOWN" 122*0Sstevel@tonic-gate }; 123*0Sstevel@tonic-gate 124*0Sstevel@tonic-gate /* Note: this must also be changed in tandem with sbd_ioctl.h */ 125*0Sstevel@tonic-gate #define SBD_CMD_STR(c) \ 126*0Sstevel@tonic-gate (((c) == SBD_CMD_ASSIGN) ? "ASSIGN" : \ 127*0Sstevel@tonic-gate ((c) == SBD_CMD_UNASSIGN) ? "UNASSIGN" : \ 128*0Sstevel@tonic-gate ((c) == SBD_CMD_POWERON) ? "POWERON" : \ 129*0Sstevel@tonic-gate ((c) == SBD_CMD_POWEROFF) ? "POWEROFF" : \ 130*0Sstevel@tonic-gate ((c) == SBD_CMD_TEST) ? "TEST" : \ 131*0Sstevel@tonic-gate ((c) == SBD_CMD_CONNECT) ? "CONNECT" : \ 132*0Sstevel@tonic-gate ((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \ 133*0Sstevel@tonic-gate ((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \ 134*0Sstevel@tonic-gate ((c) == SBD_CMD_DISCONNECT) ? "DISCONNECT" : \ 135*0Sstevel@tonic-gate ((c) == SBD_CMD_STATUS) ? "STATUS" : \ 136*0Sstevel@tonic-gate ((c) == SBD_CMD_GETNCM) ? "GETNCM" : \ 137*0Sstevel@tonic-gate ((c) == SBD_CMD_PASSTHRU) ? "PASSTHRU" : "unknown") 138*0Sstevel@tonic-gate 139*0Sstevel@tonic-gate /* 140*0Sstevel@tonic-gate * Defines and structures for device tree naming and mapping 141*0Sstevel@tonic-gate * to node types 142*0Sstevel@tonic-gate */ 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate sbd_devattr_t *sbd_devattr; 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* defines to access the attribute struct */ 147*0Sstevel@tonic-gate #define SBD_DEVNAME(i) sbd_devattr[i].s_devname 148*0Sstevel@tonic-gate #define SBD_OTYPE(i) sbd_devattr[(i)].s_obp_type 149*0Sstevel@tonic-gate #define SBD_COMP(i) sbd_devattr[i].s_dnodetype 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gate /* 152*0Sstevel@tonic-gate * State transition table. States valid transitions for "board" state. 153*0Sstevel@tonic-gate * Recall that non-zero return value terminates operation, however 154*0Sstevel@tonic-gate * the herrno value is what really indicates an error , if any. 155*0Sstevel@tonic-gate */ 156*0Sstevel@tonic-gate static int 157*0Sstevel@tonic-gate _cmd2index(int c) 158*0Sstevel@tonic-gate { 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * Translate DR CMD to index into sbd_state_transition. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate switch (c) { 163*0Sstevel@tonic-gate case SBD_CMD_CONNECT: return (0); 164*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: return (1); 165*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: return (2); 166*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: return (3); 167*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: return (4); 168*0Sstevel@tonic-gate case SBD_CMD_POWERON: return (5); 169*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: return (6); 170*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: return (7); 171*0Sstevel@tonic-gate case SBD_CMD_TEST: return (8); 172*0Sstevel@tonic-gate default: return (-1); 173*0Sstevel@tonic-gate } 174*0Sstevel@tonic-gate } 175*0Sstevel@tonic-gate 176*0Sstevel@tonic-gate #define CMD2INDEX(c) _cmd2index(c) 177*0Sstevel@tonic-gate 178*0Sstevel@tonic-gate static struct sbd_state_trans { 179*0Sstevel@tonic-gate int x_cmd; 180*0Sstevel@tonic-gate struct { 181*0Sstevel@tonic-gate int x_rv; /* return value of pre_op */ 182*0Sstevel@tonic-gate int x_err; /* errno, if any */ 183*0Sstevel@tonic-gate } x_op[SBD_NUM_STATES]; 184*0Sstevel@tonic-gate } sbd_state_transition[] = { 185*0Sstevel@tonic-gate { SBD_CMD_CONNECT, 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 188*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 189*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 190*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 191*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 192*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 193*0Sstevel@tonic-gate { 1, EIO }, /* release */ 194*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 195*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 196*0Sstevel@tonic-gate } 197*0Sstevel@tonic-gate }, 198*0Sstevel@tonic-gate { SBD_CMD_DISCONNECT, 199*0Sstevel@tonic-gate { 200*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 201*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 202*0Sstevel@tonic-gate { 0, 0 }, /* connected */ 203*0Sstevel@tonic-gate { 0, 0 }, /* unconfigured */ 204*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 205*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 206*0Sstevel@tonic-gate { 1, EIO }, /* release */ 207*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 208*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 209*0Sstevel@tonic-gate } 210*0Sstevel@tonic-gate }, 211*0Sstevel@tonic-gate { SBD_CMD_CONFIGURE, 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 214*0Sstevel@tonic-gate { 1, EIO }, /* occupied */ 215*0Sstevel@tonic-gate { 0, 0 }, /* connected */ 216*0Sstevel@tonic-gate { 0, 0 }, /* unconfigured */ 217*0Sstevel@tonic-gate { 0, 0 }, /* partial */ 218*0Sstevel@tonic-gate { 1, 0 }, /* configured */ 219*0Sstevel@tonic-gate { 0, 0 }, /* release */ 220*0Sstevel@tonic-gate { 0, 0 }, /* unreferenced */ 221*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 222*0Sstevel@tonic-gate } 223*0Sstevel@tonic-gate }, 224*0Sstevel@tonic-gate { SBD_CMD_UNCONFIGURE, 225*0Sstevel@tonic-gate { 226*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 227*0Sstevel@tonic-gate { 1, EIO }, /* occupied */ 228*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 229*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 230*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 231*0Sstevel@tonic-gate { 0, 0 }, /* configured */ 232*0Sstevel@tonic-gate { 0, 0 }, /* release */ 233*0Sstevel@tonic-gate { 0, 0 }, /* unreferenced */ 234*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 235*0Sstevel@tonic-gate } 236*0Sstevel@tonic-gate }, 237*0Sstevel@tonic-gate { SBD_CMD_POWEROFF, 238*0Sstevel@tonic-gate { 239*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 240*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 241*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 242*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 243*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 244*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 245*0Sstevel@tonic-gate { 1, EIO }, /* release */ 246*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 247*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 248*0Sstevel@tonic-gate } 249*0Sstevel@tonic-gate }, 250*0Sstevel@tonic-gate { SBD_CMD_POWERON, 251*0Sstevel@tonic-gate { 252*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 253*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 254*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 255*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 256*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 257*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 258*0Sstevel@tonic-gate { 1, EIO }, /* release */ 259*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 260*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate }, 263*0Sstevel@tonic-gate { SBD_CMD_UNASSIGN, 264*0Sstevel@tonic-gate { 265*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 266*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 267*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 268*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 269*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 270*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 271*0Sstevel@tonic-gate { 1, EIO }, /* release */ 272*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 273*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 274*0Sstevel@tonic-gate } 275*0Sstevel@tonic-gate }, 276*0Sstevel@tonic-gate { SBD_CMD_ASSIGN, 277*0Sstevel@tonic-gate { 278*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 279*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 280*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 281*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 282*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 283*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 284*0Sstevel@tonic-gate { 1, EIO }, /* release */ 285*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 286*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 287*0Sstevel@tonic-gate } 288*0Sstevel@tonic-gate }, 289*0Sstevel@tonic-gate { SBD_CMD_TEST, 290*0Sstevel@tonic-gate { 291*0Sstevel@tonic-gate { 1, EIO }, /* empty */ 292*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 293*0Sstevel@tonic-gate { 1, EIO }, /* connected */ 294*0Sstevel@tonic-gate { 1, EIO }, /* unconfigured */ 295*0Sstevel@tonic-gate { 1, EIO }, /* partial */ 296*0Sstevel@tonic-gate { 1, EIO }, /* configured */ 297*0Sstevel@tonic-gate { 1, EIO }, /* release */ 298*0Sstevel@tonic-gate { 1, EIO }, /* unreferenced */ 299*0Sstevel@tonic-gate { 1, EIO }, /* fatal */ 300*0Sstevel@tonic-gate } 301*0Sstevel@tonic-gate }, 302*0Sstevel@tonic-gate }; 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate /* 305*0Sstevel@tonic-gate * Global R/W lock to synchronize access across 306*0Sstevel@tonic-gate * multiple boards. Users wanting multi-board access 307*0Sstevel@tonic-gate * must grab WRITE lock, others must grab READ lock. 308*0Sstevel@tonic-gate */ 309*0Sstevel@tonic-gate krwlock_t sbd_grwlock; 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate /* 312*0Sstevel@tonic-gate * Global to determine if an event needs to be sent 313*0Sstevel@tonic-gate */ 314*0Sstevel@tonic-gate char send_event = 0; 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate /* 317*0Sstevel@tonic-gate * Required/Expected functions. 318*0Sstevel@tonic-gate */ 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate static sbd_handle_t *sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, 321*0Sstevel@tonic-gate intptr_t arg, sbd_init_arg_t *iap); 322*0Sstevel@tonic-gate static void sbd_release_handle(sbd_handle_t *hp); 323*0Sstevel@tonic-gate static int sbd_pre_op(sbd_handle_t *hp); 324*0Sstevel@tonic-gate static void sbd_post_op(sbd_handle_t *hp); 325*0Sstevel@tonic-gate static int sbd_probe_board(sbd_handle_t *hp); 326*0Sstevel@tonic-gate static int sbd_deprobe_board(sbd_handle_t *hp); 327*0Sstevel@tonic-gate static void sbd_connect(sbd_handle_t *hp); 328*0Sstevel@tonic-gate static void sbd_assign_board(sbd_handle_t *hp); 329*0Sstevel@tonic-gate static void sbd_unassign_board(sbd_handle_t *hp); 330*0Sstevel@tonic-gate static void sbd_poweron_board(sbd_handle_t *hp); 331*0Sstevel@tonic-gate static void sbd_poweroff_board(sbd_handle_t *hp); 332*0Sstevel@tonic-gate static void sbd_test_board(sbd_handle_t *hp); 333*0Sstevel@tonic-gate 334*0Sstevel@tonic-gate static int sbd_disconnect(sbd_handle_t *hp); 335*0Sstevel@tonic-gate static sbd_devlist_t *sbd_get_attach_devlist(sbd_handle_t *hp, 336*0Sstevel@tonic-gate int32_t *devnump, int32_t pass); 337*0Sstevel@tonic-gate static int sbd_pre_attach_devlist(sbd_handle_t *hp, 338*0Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 339*0Sstevel@tonic-gate static int sbd_post_attach_devlist(sbd_handle_t *hp, 340*0Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 341*0Sstevel@tonic-gate static sbd_devlist_t *sbd_get_release_devlist(sbd_handle_t *hp, 342*0Sstevel@tonic-gate int32_t *devnump, int32_t pass); 343*0Sstevel@tonic-gate static int sbd_pre_release_devlist(sbd_handle_t *hp, 344*0Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 345*0Sstevel@tonic-gate static int sbd_post_release_devlist(sbd_handle_t *hp, 346*0Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 347*0Sstevel@tonic-gate static void sbd_release_done(sbd_handle_t *hp, 348*0Sstevel@tonic-gate sbd_comp_type_t nodetype, 349*0Sstevel@tonic-gate dev_info_t *dip); 350*0Sstevel@tonic-gate static sbd_devlist_t *sbd_get_detach_devlist(sbd_handle_t *hp, 351*0Sstevel@tonic-gate int32_t *devnump, int32_t pass); 352*0Sstevel@tonic-gate static int sbd_pre_detach_devlist(sbd_handle_t *hp, 353*0Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 354*0Sstevel@tonic-gate static int sbd_post_detach_devlist(sbd_handle_t *hp, 355*0Sstevel@tonic-gate sbd_devlist_t *devlist, int32_t devnum); 356*0Sstevel@tonic-gate static void sbd_status(sbd_handle_t *hp); 357*0Sstevel@tonic-gate static void sbd_get_ncm(sbd_handle_t *hp); 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate 360*0Sstevel@tonic-gate /* 361*0Sstevel@tonic-gate * Support functions. 362*0Sstevel@tonic-gate */ 363*0Sstevel@tonic-gate static sbd_devset_t sbd_dev2devset(sbd_comp_id_t *cid); 364*0Sstevel@tonic-gate static int sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, 365*0Sstevel@tonic-gate sbd_cmd_t *cmdp, sbd_ioctl_arg_t *iap); 366*0Sstevel@tonic-gate static int sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, 367*0Sstevel@tonic-gate void *arg); 368*0Sstevel@tonic-gate static int sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, 369*0Sstevel@tonic-gate sbd_ioctl_arg_t *iap); 370*0Sstevel@tonic-gate static int sbd_check_transition(sbd_board_t *sbp, 371*0Sstevel@tonic-gate sbd_devset_t *devsetp, 372*0Sstevel@tonic-gate struct sbd_state_trans *transp); 373*0Sstevel@tonic-gate static sbd_devlist_t *sbd_get_devlist(sbd_handle_t *hp, 374*0Sstevel@tonic-gate sbd_board_t *sbp, 375*0Sstevel@tonic-gate sbd_comp_type_t nodetype, 376*0Sstevel@tonic-gate int max_units, uint_t uset, 377*0Sstevel@tonic-gate int *count, int present_only); 378*0Sstevel@tonic-gate static int sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, 379*0Sstevel@tonic-gate sbd_dev_stat_t *dsp); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate static int sbd_init_devlists(sbd_board_t *sbp); 382*0Sstevel@tonic-gate static int sbd_name_to_idx(char *name); 383*0Sstevel@tonic-gate static int sbd_otype_to_idx(char *otpye); 384*0Sstevel@tonic-gate static int sbd_setup_devlists(dev_info_t *dip, void *arg); 385*0Sstevel@tonic-gate static void sbd_init_mem_devlists(sbd_board_t *sbp); 386*0Sstevel@tonic-gate static void sbd_init_cpu_unit(sbd_board_t *sbp, int unit); 387*0Sstevel@tonic-gate static void sbd_board_discovery(sbd_board_t *sbp); 388*0Sstevel@tonic-gate static void sbd_board_init(sbd_board_t *sbp, 389*0Sstevel@tonic-gate sbd_softstate_t *softsp, 390*0Sstevel@tonic-gate int bd, dev_info_t *dip, int wnode); 391*0Sstevel@tonic-gate static void sbd_board_destroy(sbd_board_t *sbp); 392*0Sstevel@tonic-gate static int sbd_check_unit_attached(sbd_board_t *sbp, 393*0Sstevel@tonic-gate dev_info_t *dip, int unit, 394*0Sstevel@tonic-gate sbd_comp_type_t nodetype, sbderror_t *ep); 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate static sbd_state_t rstate_cvt(sbd_istate_t state); 397*0Sstevel@tonic-gate 398*0Sstevel@tonic-gate /* 399*0Sstevel@tonic-gate * Autoconfiguration data structures 400*0Sstevel@tonic-gate */ 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate extern struct mod_ops mod_miscops; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate static struct modlmisc modlmisc = { 405*0Sstevel@tonic-gate &mod_miscops, 406*0Sstevel@tonic-gate "System Board DR v%I%" 407*0Sstevel@tonic-gate }; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 410*0Sstevel@tonic-gate MODREV_1, 411*0Sstevel@tonic-gate (void *)&modlmisc, 412*0Sstevel@tonic-gate NULL 413*0Sstevel@tonic-gate }; 414*0Sstevel@tonic-gate 415*0Sstevel@tonic-gate static int sbd_instances = 0; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate /* 418*0Sstevel@tonic-gate * dr Global data elements 419*0Sstevel@tonic-gate */ 420*0Sstevel@tonic-gate sbd_global sbd_g; 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate /* 423*0Sstevel@tonic-gate * We want to be able to unload the module when we wish to do so, but we don't 424*0Sstevel@tonic-gate * want anything else to unload it. Unloading cannot occur until 425*0Sstevel@tonic-gate * sbd_teardown_instance is called by an explicit IOCTL into the parent node. 426*0Sstevel@tonic-gate * This support is for debugging purposes and should it be expected to work 427*0Sstevel@tonic-gate * on the field, it should be enhanced: 428*0Sstevel@tonic-gate * Currently, there is still a window where sbd_teardow_instance gets called, 429*0Sstevel@tonic-gate * sbd_prevent_unloading now = 0, the driver doesn't get unloaded, and 430*0Sstevel@tonic-gate * sbd_setup_instance gets called. This may cause a panic. 431*0Sstevel@tonic-gate */ 432*0Sstevel@tonic-gate int sbd_prevent_unloading = 1; 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate /* 435*0Sstevel@tonic-gate * Driver entry points. 436*0Sstevel@tonic-gate */ 437*0Sstevel@tonic-gate int 438*0Sstevel@tonic-gate _init(void) 439*0Sstevel@tonic-gate { 440*0Sstevel@tonic-gate int err; 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate /* 443*0Sstevel@tonic-gate * If you need to support multiple nodes (instances), then 444*0Sstevel@tonic-gate * whatever the maximum number of supported nodes is would 445*0Sstevel@tonic-gate * need to passed as the third parameter to ddi_soft_state_init(). 446*0Sstevel@tonic-gate * Alternative would be to dynamically fini and re-init the 447*0Sstevel@tonic-gate * soft state structure each time a node is attached. 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate err = ddi_soft_state_init((void **)&sbd_g.softsp, 450*0Sstevel@tonic-gate sizeof (sbd_softstate_t), SBD_MAX_INSTANCES); 451*0Sstevel@tonic-gate if (err) 452*0Sstevel@tonic-gate return (err); 453*0Sstevel@tonic-gate 454*0Sstevel@tonic-gate if ((err = mod_install(&modlinkage)) != 0) { 455*0Sstevel@tonic-gate ddi_soft_state_fini((void **)&sbd_g.softsp); 456*0Sstevel@tonic-gate return (err); 457*0Sstevel@tonic-gate } 458*0Sstevel@tonic-gate 459*0Sstevel@tonic-gate /* Get the array of names from platform helper routine */ 460*0Sstevel@tonic-gate sbd_devattr = sbdp_get_devattr(); 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate return (err); 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate 465*0Sstevel@tonic-gate int 466*0Sstevel@tonic-gate _fini(void) 467*0Sstevel@tonic-gate { 468*0Sstevel@tonic-gate int err; 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate if (sbd_prevent_unloading) 471*0Sstevel@tonic-gate return (DDI_FAILURE); 472*0Sstevel@tonic-gate 473*0Sstevel@tonic-gate ASSERT(sbd_instances == 0); 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate if ((err = mod_remove(&modlinkage)) != 0) 476*0Sstevel@tonic-gate return (err); 477*0Sstevel@tonic-gate 478*0Sstevel@tonic-gate ddi_soft_state_fini((void **)&sbd_g.softsp); 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate return (0); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate int 484*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 485*0Sstevel@tonic-gate { 486*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate int 490*0Sstevel@tonic-gate sbd_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, char *event) 491*0Sstevel@tonic-gate { 492*0Sstevel@tonic-gate int rv = 0, instance; 493*0Sstevel@tonic-gate sbd_handle_t *hp; 494*0Sstevel@tonic-gate sbd_softstate_t *softsp; 495*0Sstevel@tonic-gate sbd_init_arg_t init_arg; 496*0Sstevel@tonic-gate static fn_t f = "sbd_ioctl"; 497*0Sstevel@tonic-gate int dr_avail; 498*0Sstevel@tonic-gate 499*0Sstevel@tonic-gate PR_BYP("sbd_ioctl cmd=%x, arg=%x\n", cmd, arg); 500*0Sstevel@tonic-gate 501*0Sstevel@tonic-gate /* Note: this must also be changed in tandem with sbd_ioctl.h */ 502*0Sstevel@tonic-gate switch (cmd) { 503*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: 504*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 505*0Sstevel@tonic-gate case SBD_CMD_POWERON: 506*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: 507*0Sstevel@tonic-gate case SBD_CMD_TEST: 508*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 509*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 510*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 511*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 512*0Sstevel@tonic-gate case SBD_CMD_STATUS: 513*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 514*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 515*0Sstevel@tonic-gate break; 516*0Sstevel@tonic-gate default: 517*0Sstevel@tonic-gate return (ENOTTY); 518*0Sstevel@tonic-gate } 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate instance = SBD_GET_MINOR2INST(getminor(dev)); 521*0Sstevel@tonic-gate if ((softsp = (sbd_softstate_t *)GET_SOFTC(instance)) == NULL) { 522*0Sstevel@tonic-gate cmn_err(CE_WARN, 523*0Sstevel@tonic-gate "sbd:%s:%d: module not yet attached", 524*0Sstevel@tonic-gate f, instance); 525*0Sstevel@tonic-gate return (ENXIO); 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate 528*0Sstevel@tonic-gate init_arg.dev = dev; 529*0Sstevel@tonic-gate init_arg.cmd = cmd; 530*0Sstevel@tonic-gate init_arg.mode = mode; 531*0Sstevel@tonic-gate init_arg.ioargp = (sbd_ioctl_arg_t *)arg; 532*0Sstevel@tonic-gate 533*0Sstevel@tonic-gate hp = sbd_get_handle(dev, softsp, arg, &init_arg); 534*0Sstevel@tonic-gate /* Check to see if we support dr */ 535*0Sstevel@tonic-gate dr_avail = sbdp_dr_avail(); 536*0Sstevel@tonic-gate if (dr_avail != 1) { 537*0Sstevel@tonic-gate switch (hp->h_cmd) { 538*0Sstevel@tonic-gate case SBD_CMD_STATUS: 539*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 540*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 541*0Sstevel@tonic-gate break; 542*0Sstevel@tonic-gate default: 543*0Sstevel@tonic-gate sbd_release_handle(hp); 544*0Sstevel@tonic-gate return (ENOTSUP); 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate switch (hp->h_cmd) { 549*0Sstevel@tonic-gate case SBD_CMD_STATUS: 550*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 551*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 552*0Sstevel@tonic-gate /* no locks needed for these commands */ 553*0Sstevel@tonic-gate break; 554*0Sstevel@tonic-gate 555*0Sstevel@tonic-gate default: 556*0Sstevel@tonic-gate rw_enter(&sbd_grwlock, RW_WRITER); 557*0Sstevel@tonic-gate mutex_enter(&SBDH2BD(hp->h_sbd)->sb_mutex); 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * If we're dealing with memory at all, then we have 561*0Sstevel@tonic-gate * to keep the "exclusive" global lock held. This is 562*0Sstevel@tonic-gate * necessary since we will probably need to look at 563*0Sstevel@tonic-gate * multiple board structs. Otherwise, we only have 564*0Sstevel@tonic-gate * to deal with the board in question and so can drop 565*0Sstevel@tonic-gate * the global lock to "shared". 566*0Sstevel@tonic-gate */ 567*0Sstevel@tonic-gate /* 568*0Sstevel@tonic-gate * XXX This is incorrect. The sh_devset has not 569*0Sstevel@tonic-gate * been set at this point - it is 0. 570*0Sstevel@tonic-gate */ 571*0Sstevel@tonic-gate rv = DEVSET_IN_SET(HD2MACHHD(hp)->sh_devset, 572*0Sstevel@tonic-gate SBD_COMP_MEM, DEVSET_ANYUNIT); 573*0Sstevel@tonic-gate if (rv == 0) 574*0Sstevel@tonic-gate rw_downgrade(&sbd_grwlock); 575*0Sstevel@tonic-gate break; 576*0Sstevel@tonic-gate } 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate /* 579*0Sstevel@tonic-gate * Before any operations happen, reset the event flag 580*0Sstevel@tonic-gate */ 581*0Sstevel@tonic-gate send_event = 0; 582*0Sstevel@tonic-gate 583*0Sstevel@tonic-gate if (sbd_pre_op(hp) == 0) { 584*0Sstevel@tonic-gate sbd_exec_op(hp); 585*0Sstevel@tonic-gate sbd_post_op(hp); 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate rv = SBD_GET_ERRNO(SBD_HD2ERR(hp)); 589*0Sstevel@tonic-gate *event = send_event; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate /* undo locking, if any, done before sbd_pre_op */ 592*0Sstevel@tonic-gate switch (hp->h_cmd) { 593*0Sstevel@tonic-gate case SBD_CMD_STATUS: 594*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 595*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 596*0Sstevel@tonic-gate break; 597*0Sstevel@tonic-gate default: 598*0Sstevel@tonic-gate mutex_exit(&SBDH2BD(hp->h_sbd)->sb_mutex); 599*0Sstevel@tonic-gate rw_exit(&sbd_grwlock); 600*0Sstevel@tonic-gate } 601*0Sstevel@tonic-gate 602*0Sstevel@tonic-gate sbd_release_handle(hp); 603*0Sstevel@tonic-gate 604*0Sstevel@tonic-gate return (rv); 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate 607*0Sstevel@tonic-gate int 608*0Sstevel@tonic-gate sbd_setup_instance(int instance, dev_info_t *root, int max_boards, int wnode, 609*0Sstevel@tonic-gate caddr_t sbdp_arg) 610*0Sstevel@tonic-gate { 611*0Sstevel@tonic-gate int b; 612*0Sstevel@tonic-gate sbd_softstate_t *softsp; 613*0Sstevel@tonic-gate sbd_board_t *sbd_boardlist; 614*0Sstevel@tonic-gate static fn_t f = "sbd_setup_instance"; 615*0Sstevel@tonic-gate 616*0Sstevel@tonic-gate sbd_instances++; 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate if (sbdp_setup_instance(sbdp_arg) != DDI_SUCCESS) { 619*0Sstevel@tonic-gate sbd_instances--; 620*0Sstevel@tonic-gate return (DDI_FAILURE); 621*0Sstevel@tonic-gate } 622*0Sstevel@tonic-gate 623*0Sstevel@tonic-gate if (ALLOC_SOFTC(instance) != DDI_SUCCESS) { 624*0Sstevel@tonic-gate cmn_err(CE_WARN, 625*0Sstevel@tonic-gate "sbd:%s:%d: failed to alloc soft-state", 626*0Sstevel@tonic-gate f, instance); 627*0Sstevel@tonic-gate sbdp_teardown_instance(sbdp_arg); 628*0Sstevel@tonic-gate sbd_instances--; 629*0Sstevel@tonic-gate return (DDI_FAILURE); 630*0Sstevel@tonic-gate } 631*0Sstevel@tonic-gate 632*0Sstevel@tonic-gate softsp = (sbd_softstate_t *)GET_SOFTC(instance); 633*0Sstevel@tonic-gate 634*0Sstevel@tonic-gate if (softsp == NULL) { 635*0Sstevel@tonic-gate cmn_err(CE_WARN, 636*0Sstevel@tonic-gate "sbd:%s:%d: failed to get soft-state instance", 637*0Sstevel@tonic-gate f, instance); 638*0Sstevel@tonic-gate goto exit; 639*0Sstevel@tonic-gate } 640*0Sstevel@tonic-gate 641*0Sstevel@tonic-gate sbd_boardlist = GETSTRUCT(sbd_board_t, max_boards); 642*0Sstevel@tonic-gate if (sbd_boardlist == NULL) { 643*0Sstevel@tonic-gate cmn_err(CE_WARN, 644*0Sstevel@tonic-gate "sbd:%s: failed to alloc board list %d", 645*0Sstevel@tonic-gate f, instance); 646*0Sstevel@tonic-gate goto exit; 647*0Sstevel@tonic-gate } 648*0Sstevel@tonic-gate 649*0Sstevel@tonic-gate 650*0Sstevel@tonic-gate softsp->sbd_boardlist = (void *)sbd_boardlist; 651*0Sstevel@tonic-gate softsp->max_boards = max_boards; 652*0Sstevel@tonic-gate softsp->wnode = wnode; 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate 655*0Sstevel@tonic-gate for (b = 0; b < max_boards; b++) { 656*0Sstevel@tonic-gate sbd_board_init(sbd_boardlist++, softsp, b, root, wnode); 657*0Sstevel@tonic-gate } 658*0Sstevel@tonic-gate 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate return (DDI_SUCCESS); 661*0Sstevel@tonic-gate exit: 662*0Sstevel@tonic-gate (void) sbdp_teardown_instance(sbdp_arg); 663*0Sstevel@tonic-gate FREE_SOFTC(instance); 664*0Sstevel@tonic-gate sbd_instances--; 665*0Sstevel@tonic-gate return (DDI_FAILURE); 666*0Sstevel@tonic-gate } 667*0Sstevel@tonic-gate 668*0Sstevel@tonic-gate int 669*0Sstevel@tonic-gate sbd_teardown_instance(int instance, caddr_t sbdp_arg) 670*0Sstevel@tonic-gate { 671*0Sstevel@tonic-gate sbd_softstate_t *softsp; 672*0Sstevel@tonic-gate 673*0Sstevel@tonic-gate if (sbdp_teardown_instance(sbdp_arg) != DDI_SUCCESS) 674*0Sstevel@tonic-gate return (DDI_FAILURE); 675*0Sstevel@tonic-gate 676*0Sstevel@tonic-gate softsp = (sbd_softstate_t *)GET_SOFTC(instance); 677*0Sstevel@tonic-gate if (softsp == NULL) { 678*0Sstevel@tonic-gate return (DDI_FAILURE); 679*0Sstevel@tonic-gate } 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate (void) sbd_dealloc_instance((sbd_board_t *)softsp->sbd_boardlist, 682*0Sstevel@tonic-gate softsp->max_boards); 683*0Sstevel@tonic-gate 684*0Sstevel@tonic-gate FREE_SOFTC(instance); 685*0Sstevel@tonic-gate sbd_instances--; 686*0Sstevel@tonic-gate sbd_prevent_unloading = 0; 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate return (DDI_SUCCESS); 689*0Sstevel@tonic-gate } 690*0Sstevel@tonic-gate 691*0Sstevel@tonic-gate static void 692*0Sstevel@tonic-gate sbd_exec_op(sbd_handle_t *hp) 693*0Sstevel@tonic-gate { 694*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 695*0Sstevel@tonic-gate static fn_t f = "sbd_exec_op"; 696*0Sstevel@tonic-gate 697*0Sstevel@tonic-gate switch (hp->h_cmd) { 698*0Sstevel@tonic-gate int dev_canceled; 699*0Sstevel@tonic-gate 700*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 701*0Sstevel@tonic-gate if (sbd_probe_board(hp)) 702*0Sstevel@tonic-gate break; 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate sbd_connect(hp); 705*0Sstevel@tonic-gate break; 706*0Sstevel@tonic-gate 707*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 708*0Sstevel@tonic-gate sbd_dev_configure(hp); 709*0Sstevel@tonic-gate break; 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 712*0Sstevel@tonic-gate if (((dev_canceled = sbd_dev_release(hp)) == 0) && 713*0Sstevel@tonic-gate (SBD_GET_ERRNO(SBD_HD2ERR(hp)) == 0 && 714*0Sstevel@tonic-gate SBD_GET_ERR(SBD_HD2ERR(hp)) == 0)) 715*0Sstevel@tonic-gate dev_canceled = sbd_dev_unconfigure(hp); 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate if (dev_canceled) 718*0Sstevel@tonic-gate sbd_cancel(hp); 719*0Sstevel@tonic-gate break; 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 722*0Sstevel@tonic-gate mutex_enter(&sbp->sb_slock); 723*0Sstevel@tonic-gate if (sbd_disconnect(hp) == 0) 724*0Sstevel@tonic-gate (void) sbd_deprobe_board(hp); 725*0Sstevel@tonic-gate mutex_exit(&sbp->sb_slock); 726*0Sstevel@tonic-gate break; 727*0Sstevel@tonic-gate 728*0Sstevel@tonic-gate case SBD_CMD_STATUS: 729*0Sstevel@tonic-gate sbd_status(hp); 730*0Sstevel@tonic-gate break; 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 733*0Sstevel@tonic-gate sbd_get_ncm(hp); 734*0Sstevel@tonic-gate break; 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: 737*0Sstevel@tonic-gate sbd_assign_board(hp); 738*0Sstevel@tonic-gate break; 739*0Sstevel@tonic-gate 740*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 741*0Sstevel@tonic-gate sbd_unassign_board(hp); 742*0Sstevel@tonic-gate break; 743*0Sstevel@tonic-gate 744*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: 745*0Sstevel@tonic-gate sbd_poweroff_board(hp); 746*0Sstevel@tonic-gate break; 747*0Sstevel@tonic-gate 748*0Sstevel@tonic-gate case SBD_CMD_POWERON: 749*0Sstevel@tonic-gate sbd_poweron_board(hp); 750*0Sstevel@tonic-gate break; 751*0Sstevel@tonic-gate 752*0Sstevel@tonic-gate case SBD_CMD_TEST: 753*0Sstevel@tonic-gate sbd_test_board(hp); 754*0Sstevel@tonic-gate break; 755*0Sstevel@tonic-gate 756*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 757*0Sstevel@tonic-gate { 758*0Sstevel@tonic-gate int rv; 759*0Sstevel@tonic-gate sbdp_handle_t *hdp; 760*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 761*0Sstevel@tonic-gate sbdp_ioctl_arg_t ia, *iap; 762*0Sstevel@tonic-gate 763*0Sstevel@tonic-gate iap = &ia; 764*0Sstevel@tonic-gate 765*0Sstevel@tonic-gate iap->h_dev = hp->h_dev; 766*0Sstevel@tonic-gate iap->h_cmd = hp->h_cmd; 767*0Sstevel@tonic-gate iap->h_iap = (intptr_t)hp->h_iap; 768*0Sstevel@tonic-gate iap->h_mode = hp->h_mode; 769*0Sstevel@tonic-gate 770*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 771*0Sstevel@tonic-gate rv = sbdp_ioctl(hdp, iap); 772*0Sstevel@tonic-gate if (rv != 0) { 773*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 774*0Sstevel@tonic-gate ep->e_errno = rv; 775*0Sstevel@tonic-gate } 776*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 777*0Sstevel@tonic-gate break; 778*0Sstevel@tonic-gate } 779*0Sstevel@tonic-gate 780*0Sstevel@tonic-gate default: 781*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), ENOTTY); 782*0Sstevel@tonic-gate cmn_err(CE_WARN, 783*0Sstevel@tonic-gate "sbd:%s: unknown command (%d)", 784*0Sstevel@tonic-gate f, hp->h_cmd); 785*0Sstevel@tonic-gate break; 786*0Sstevel@tonic-gate 787*0Sstevel@tonic-gate } 788*0Sstevel@tonic-gate 789*0Sstevel@tonic-gate if (SBD_GET_ERR(SBD_HD2ERR(hp))) 790*0Sstevel@tonic-gate PR_BYP("XXX e_code=%d", SBD_GET_ERR(SBD_HD2ERR(hp))); 791*0Sstevel@tonic-gate if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) 792*0Sstevel@tonic-gate PR_BYP("XXX errno=%d", SBD_GET_ERRNO(SBD_HD2ERR(hp))); 793*0Sstevel@tonic-gate } 794*0Sstevel@tonic-gate 795*0Sstevel@tonic-gate sbd_comp_type_t 796*0Sstevel@tonic-gate sbd_get_devtype(sbd_handle_t *hp, dev_info_t *dip) 797*0Sstevel@tonic-gate { 798*0Sstevel@tonic-gate sbd_board_t *sbp = hp ? SBDH2BD(hp->h_sbd) : NULL; 799*0Sstevel@tonic-gate sbd_istate_t bstate; 800*0Sstevel@tonic-gate dev_info_t **devlist; 801*0Sstevel@tonic-gate int i; 802*0Sstevel@tonic-gate char device[OBP_MAXDRVNAME]; 803*0Sstevel@tonic-gate int devicelen; 804*0Sstevel@tonic-gate 805*0Sstevel@tonic-gate devicelen = sizeof (device); 806*0Sstevel@tonic-gate 807*0Sstevel@tonic-gate bstate = sbp ? SBD_BOARD_STATE(sbp) : SBD_STATE_EMPTY; 808*0Sstevel@tonic-gate /* 809*0Sstevel@tonic-gate * if the board's connected or configured, search the 810*0Sstevel@tonic-gate * devlists. Otherwise check the device tree 811*0Sstevel@tonic-gate */ 812*0Sstevel@tonic-gate switch (bstate) { 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate case SBD_STATE_CONNECTED: 815*0Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 816*0Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: 817*0Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 818*0Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)]; 819*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 820*0Sstevel@tonic-gate if (devlist[i] == dip) 821*0Sstevel@tonic-gate return (SBD_COMP_MEM); 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_CPU)]; 824*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) 825*0Sstevel@tonic-gate if (devlist[i] == dip) 826*0Sstevel@tonic-gate return (SBD_COMP_CPU); 827*0Sstevel@tonic-gate 828*0Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_IO)]; 829*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 830*0Sstevel@tonic-gate if (devlist[i] == dip) 831*0Sstevel@tonic-gate return (SBD_COMP_IO); 832*0Sstevel@tonic-gate /*FALLTHROUGH*/ 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate default: 835*0Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 836*0Sstevel@tonic-gate OBP_DEVICETYPE, (caddr_t)device, &devicelen)) 837*0Sstevel@tonic-gate break; 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 840*0Sstevel@tonic-gate if (strcmp(device, SBD_OTYPE(i)) != 0) 841*0Sstevel@tonic-gate continue; 842*0Sstevel@tonic-gate return (SBD_COMP(i)); 843*0Sstevel@tonic-gate } 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate break; 846*0Sstevel@tonic-gate } 847*0Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 848*0Sstevel@tonic-gate } 849*0Sstevel@tonic-gate 850*0Sstevel@tonic-gate static void 851*0Sstevel@tonic-gate sbd_dev_configure(sbd_handle_t *hp) 852*0Sstevel@tonic-gate { 853*0Sstevel@tonic-gate int n, unit; 854*0Sstevel@tonic-gate int32_t pass, devnum; 855*0Sstevel@tonic-gate dev_info_t *dip; 856*0Sstevel@tonic-gate sbd_devlist_t *devlist; 857*0Sstevel@tonic-gate sbdp_handle_t *hdp; 858*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 859*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate pass = 1; 862*0Sstevel@tonic-gate 863*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 864*0Sstevel@tonic-gate while ((devlist = sbd_get_attach_devlist(hp, &devnum, pass)) != NULL) { 865*0Sstevel@tonic-gate int err; 866*0Sstevel@tonic-gate 867*0Sstevel@tonic-gate err = sbd_pre_attach_devlist(hp, devlist, devnum); 868*0Sstevel@tonic-gate if (err < 0) { 869*0Sstevel@tonic-gate break; 870*0Sstevel@tonic-gate } else if (err > 0) { 871*0Sstevel@tonic-gate pass++; 872*0Sstevel@tonic-gate continue; 873*0Sstevel@tonic-gate } 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate for (n = 0; n < devnum; n++) { 876*0Sstevel@tonic-gate sbderror_t *ep; 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate ep = &devlist[n].dv_error; 879*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, 0); 880*0Sstevel@tonic-gate SBD_SET_ERR(ep, 0); 881*0Sstevel@tonic-gate dip = devlist[n].dv_dip; 882*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 885*0Sstevel@tonic-gate if (unit < 0) { 886*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 887*0Sstevel@tonic-gate break; 888*0Sstevel@tonic-gate } 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate switch (nodetype) { 891*0Sstevel@tonic-gate case SBD_COMP_MEM: 892*0Sstevel@tonic-gate sbd_attach_mem(hp, ep); 893*0Sstevel@tonic-gate if (SBD_GET_ERR(ep) == ESBD_CPUONLINE) { 894*0Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, 895*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 896*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 897*0Sstevel@tonic-gate return; 898*0Sstevel@tonic-gate } 899*0Sstevel@tonic-gate break; 900*0Sstevel@tonic-gate 901*0Sstevel@tonic-gate case SBD_COMP_CPU: 902*0Sstevel@tonic-gate sbd_attach_cpu(hp, ep, dip, unit); 903*0Sstevel@tonic-gate break; 904*0Sstevel@tonic-gate 905*0Sstevel@tonic-gate case SBD_COMP_IO: 906*0Sstevel@tonic-gate sbd_attach_io(hp, ep, dip, unit); 907*0Sstevel@tonic-gate break; 908*0Sstevel@tonic-gate 909*0Sstevel@tonic-gate default: 910*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, ENOTTY); 911*0Sstevel@tonic-gate break; 912*0Sstevel@tonic-gate } 913*0Sstevel@tonic-gate 914*0Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) 915*0Sstevel@tonic-gate continue; 916*0Sstevel@tonic-gate } 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate err = sbd_post_attach_devlist(hp, devlist, devnum); 919*0Sstevel@tonic-gate if (err < 0) 920*0Sstevel@tonic-gate break; 921*0Sstevel@tonic-gate 922*0Sstevel@tonic-gate pass++; 923*0Sstevel@tonic-gate } 924*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate 927*0Sstevel@tonic-gate static int 928*0Sstevel@tonic-gate sbd_dev_release(sbd_handle_t *hp) 929*0Sstevel@tonic-gate { 930*0Sstevel@tonic-gate int n, unit; 931*0Sstevel@tonic-gate int32_t pass, devnum; 932*0Sstevel@tonic-gate dev_info_t *dip; 933*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 934*0Sstevel@tonic-gate sbdp_handle_t *hdp; 935*0Sstevel@tonic-gate sbd_devlist_t *devlist; 936*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 937*0Sstevel@tonic-gate int err = 0; 938*0Sstevel@tonic-gate int dev_canceled; 939*0Sstevel@tonic-gate 940*0Sstevel@tonic-gate pass = 1; 941*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate sbp->sb_busy = 1; 944*0Sstevel@tonic-gate while ((devlist = 945*0Sstevel@tonic-gate sbd_get_release_devlist(hp, &devnum, pass)) != NULL) { 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate err = sbd_pre_release_devlist(hp, devlist, devnum); 948*0Sstevel@tonic-gate if (err < 0) { 949*0Sstevel@tonic-gate dev_canceled = 1; 950*0Sstevel@tonic-gate break; 951*0Sstevel@tonic-gate } else if (err > 0) { 952*0Sstevel@tonic-gate pass++; 953*0Sstevel@tonic-gate continue; 954*0Sstevel@tonic-gate } 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate dev_canceled = 0; 957*0Sstevel@tonic-gate for (n = 0; n < devnum; n++) { 958*0Sstevel@tonic-gate dip = devlist[n].dv_dip; 959*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 960*0Sstevel@tonic-gate 961*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 962*0Sstevel@tonic-gate if (unit < 0) { 963*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 964*0Sstevel@tonic-gate break; 965*0Sstevel@tonic-gate } 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate if ((nodetype == SBD_COMP_MEM) && 968*0Sstevel@tonic-gate sbd_release_mem(hp, dip, unit)) { 969*0Sstevel@tonic-gate 970*0Sstevel@tonic-gate dev_canceled++; 971*0Sstevel@tonic-gate } 972*0Sstevel@tonic-gate 973*0Sstevel@tonic-gate sbd_release_done(hp, nodetype, dip); 974*0Sstevel@tonic-gate } 975*0Sstevel@tonic-gate 976*0Sstevel@tonic-gate err = sbd_post_release_devlist(hp, devlist, devnum); 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate if (err < 0) 979*0Sstevel@tonic-gate break; 980*0Sstevel@tonic-gate 981*0Sstevel@tonic-gate if (dev_canceled) 982*0Sstevel@tonic-gate break; 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate pass++; 985*0Sstevel@tonic-gate } 986*0Sstevel@tonic-gate sbp->sb_busy = 0; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate if (dev_canceled) 991*0Sstevel@tonic-gate return (dev_canceled); 992*0Sstevel@tonic-gate 993*0Sstevel@tonic-gate return (err); 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate static int 997*0Sstevel@tonic-gate sbd_dev_unconfigure(sbd_handle_t *hp) 998*0Sstevel@tonic-gate { 999*0Sstevel@tonic-gate int n, unit; 1000*0Sstevel@tonic-gate int32_t pass, devnum; 1001*0Sstevel@tonic-gate dev_info_t *dip; 1002*0Sstevel@tonic-gate sbd_devlist_t *devlist; 1003*0Sstevel@tonic-gate sbdp_handle_t *hdp; 1004*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 1005*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1006*0Sstevel@tonic-gate int dev_canceled = 0; 1007*0Sstevel@tonic-gate static fn_t f = "sbd_dev_unconfigure"; 1008*0Sstevel@tonic-gate 1009*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate pass = 1; 1012*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 1013*0Sstevel@tonic-gate 1014*0Sstevel@tonic-gate while ((devlist = sbd_get_detach_devlist(hp, &devnum, pass)) != NULL) { 1015*0Sstevel@tonic-gate int err, detach_err = 0; 1016*0Sstevel@tonic-gate 1017*0Sstevel@tonic-gate err = sbd_pre_detach_devlist(hp, devlist, devnum); 1018*0Sstevel@tonic-gate if (err) { 1019*0Sstevel@tonic-gate /* 1020*0Sstevel@tonic-gate * Only cancel the operation for memory in 1021*0Sstevel@tonic-gate * case of failure. 1022*0Sstevel@tonic-gate */ 1023*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 1024*0Sstevel@tonic-gate if (nodetype == SBD_COMP_MEM) 1025*0Sstevel@tonic-gate dev_canceled = 1; 1026*0Sstevel@tonic-gate (void) sbd_post_detach_devlist(hp, devlist, devnum); 1027*0Sstevel@tonic-gate break; 1028*0Sstevel@tonic-gate } 1029*0Sstevel@tonic-gate 1030*0Sstevel@tonic-gate for (n = 0; n < devnum; n++) { 1031*0Sstevel@tonic-gate sbderror_t *ep; 1032*0Sstevel@tonic-gate 1033*0Sstevel@tonic-gate ep = &devlist[n].dv_error; 1034*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, 0); 1035*0Sstevel@tonic-gate SBD_SET_ERR(ep, 0); 1036*0Sstevel@tonic-gate dip = devlist[n].dv_dip; 1037*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 1038*0Sstevel@tonic-gate 1039*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 1040*0Sstevel@tonic-gate if (unit < 0) { 1041*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 1042*0Sstevel@tonic-gate break; 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate 1045*0Sstevel@tonic-gate switch (nodetype) { 1046*0Sstevel@tonic-gate case SBD_COMP_MEM: 1047*0Sstevel@tonic-gate dev_canceled = sbd_detach_mem(hp, ep, unit); 1048*0Sstevel@tonic-gate break; 1049*0Sstevel@tonic-gate 1050*0Sstevel@tonic-gate case SBD_COMP_CPU: 1051*0Sstevel@tonic-gate sbd_detach_cpu(hp, ep, dip, unit); 1052*0Sstevel@tonic-gate break; 1053*0Sstevel@tonic-gate 1054*0Sstevel@tonic-gate case SBD_COMP_IO: 1055*0Sstevel@tonic-gate sbd_detach_io(hp, ep, dip, unit); 1056*0Sstevel@tonic-gate break; 1057*0Sstevel@tonic-gate 1058*0Sstevel@tonic-gate default: 1059*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, ENOTTY); 1060*0Sstevel@tonic-gate break; 1061*0Sstevel@tonic-gate } 1062*0Sstevel@tonic-gate 1063*0Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) { 1064*0Sstevel@tonic-gate detach_err = -1; 1065*0Sstevel@tonic-gate break; 1066*0Sstevel@tonic-gate } 1067*0Sstevel@tonic-gate 1068*0Sstevel@tonic-gate } 1069*0Sstevel@tonic-gate err = sbd_post_detach_devlist(hp, devlist, devnum); 1070*0Sstevel@tonic-gate if ((err < 0) || (detach_err < 0)) 1071*0Sstevel@tonic-gate break; 1072*0Sstevel@tonic-gate 1073*0Sstevel@tonic-gate pass++; 1074*0Sstevel@tonic-gate } 1075*0Sstevel@tonic-gate 1076*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 1077*0Sstevel@tonic-gate return (dev_canceled); 1078*0Sstevel@tonic-gate } 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate int 1081*0Sstevel@tonic-gate sbd_errno2ecode(int error) 1082*0Sstevel@tonic-gate { 1083*0Sstevel@tonic-gate int rv; 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate switch (error) { 1086*0Sstevel@tonic-gate case EBUSY: 1087*0Sstevel@tonic-gate rv = ESBD_BUSY; 1088*0Sstevel@tonic-gate break; 1089*0Sstevel@tonic-gate case EINVAL: 1090*0Sstevel@tonic-gate rv = ESBD_INVAL; 1091*0Sstevel@tonic-gate break; 1092*0Sstevel@tonic-gate case EALREADY: 1093*0Sstevel@tonic-gate rv = ESBD_ALREADY; 1094*0Sstevel@tonic-gate break; 1095*0Sstevel@tonic-gate case ENODEV: 1096*0Sstevel@tonic-gate rv = ESBD_NODEV; 1097*0Sstevel@tonic-gate break; 1098*0Sstevel@tonic-gate case ENOMEM: 1099*0Sstevel@tonic-gate rv = ESBD_NOMEM; 1100*0Sstevel@tonic-gate break; 1101*0Sstevel@tonic-gate default: 1102*0Sstevel@tonic-gate rv = ESBD_INVAL; 1103*0Sstevel@tonic-gate } 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate return (rv); 1106*0Sstevel@tonic-gate } 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate static void 1109*0Sstevel@tonic-gate sbd_attach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) 1110*0Sstevel@tonic-gate { 1111*0Sstevel@tonic-gate int rv = 0; 1112*0Sstevel@tonic-gate processorid_t cpuid; 1113*0Sstevel@tonic-gate sbdp_handle_t *hdp; 1114*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1115*0Sstevel@tonic-gate static fn_t f = "sbd_attach_cpu"; 1116*0Sstevel@tonic-gate char *pathname; 1117*0Sstevel@tonic-gate 1118*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 1119*0Sstevel@tonic-gate 1120*0Sstevel@tonic-gate ASSERT(dip); 1121*0Sstevel@tonic-gate 1122*0Sstevel@tonic-gate /* 1123*0Sstevel@tonic-gate * With the introduction of CMP devices, the CPU nodes 1124*0Sstevel@tonic-gate * are no longer directly under the top node. Since 1125*0Sstevel@tonic-gate * there is no plan to support CPU attach in the near 1126*0Sstevel@tonic-gate * future, a branch configure operation is not required. 1127*0Sstevel@tonic-gate */ 1128*0Sstevel@tonic-gate 1129*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 1130*0Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 1131*0Sstevel@tonic-gate if (cpuid < 0) { 1132*0Sstevel@tonic-gate rv = -1; 1133*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 1134*0Sstevel@tonic-gate } else if ((rv = cpu_configure(cpuid)) != 0) { 1135*0Sstevel@tonic-gate cmn_err(CE_WARN, 1136*0Sstevel@tonic-gate "sbd:%s: cpu_configure for cpuid %d failed", 1137*0Sstevel@tonic-gate f, cpuid); 1138*0Sstevel@tonic-gate SBD_SET_ERR(ep, sbd_errno2ecode(rv)); 1139*0Sstevel@tonic-gate } 1140*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 1141*0Sstevel@tonic-gate 1142*0Sstevel@tonic-gate if (rv == 0) { 1143*0Sstevel@tonic-gate ASSERT(sbp->sb_cpupath[unit] != NULL); 1144*0Sstevel@tonic-gate pathname = sbp->sb_cpupath[unit]; 1145*0Sstevel@tonic-gate (void) ddi_pathname(dip, pathname); 1146*0Sstevel@tonic-gate } 1147*0Sstevel@tonic-gate } 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate /* 1150*0Sstevel@tonic-gate * translate errno 1151*0Sstevel@tonic-gate */ 1152*0Sstevel@tonic-gate void 1153*0Sstevel@tonic-gate sbd_errno_decode(int err, sbderror_t *ep, dev_info_t *dip) 1154*0Sstevel@tonic-gate { 1155*0Sstevel@tonic-gate ASSERT(err != 0); 1156*0Sstevel@tonic-gate 1157*0Sstevel@tonic-gate switch (err) { 1158*0Sstevel@tonic-gate case ENOMEM: 1159*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_NOMEM); 1160*0Sstevel@tonic-gate break; 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate case EBUSY: 1163*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_BUSY); 1164*0Sstevel@tonic-gate break; 1165*0Sstevel@tonic-gate 1166*0Sstevel@tonic-gate case EIO: 1167*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_IO); 1168*0Sstevel@tonic-gate break; 1169*0Sstevel@tonic-gate 1170*0Sstevel@tonic-gate case ENXIO: 1171*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_NODEV); 1172*0Sstevel@tonic-gate break; 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate case EINVAL: 1175*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INVAL); 1176*0Sstevel@tonic-gate break; 1177*0Sstevel@tonic-gate 1178*0Sstevel@tonic-gate case EFAULT: 1179*0Sstevel@tonic-gate default: 1180*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_FAULT); 1181*0Sstevel@tonic-gate break; 1182*0Sstevel@tonic-gate } 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate (void) ddi_pathname(dip, SBD_GET_ERRSTR(ep)); 1185*0Sstevel@tonic-gate } 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate static void 1188*0Sstevel@tonic-gate sbd_detach_cpu(sbd_handle_t *hp, sbderror_t *ep, dev_info_t *dip, int unit) 1189*0Sstevel@tonic-gate { 1190*0Sstevel@tonic-gate processorid_t cpuid; 1191*0Sstevel@tonic-gate int rv; 1192*0Sstevel@tonic-gate sbdp_handle_t *hdp; 1193*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1194*0Sstevel@tonic-gate sbd_error_t *spe; 1195*0Sstevel@tonic-gate static fn_t f = "sbd_detach_cpu"; 1196*0Sstevel@tonic-gate 1197*0Sstevel@tonic-gate ASSERT(MUTEX_HELD(&cpu_lock)); 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate ASSERT(dip); 1200*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 1201*0Sstevel@tonic-gate spe = hdp->h_err; 1202*0Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 1203*0Sstevel@tonic-gate if (cpuid < 0) { 1204*0Sstevel@tonic-gate SBD_GET_PERR(spe, ep); 1205*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 1206*0Sstevel@tonic-gate return; 1207*0Sstevel@tonic-gate } 1208*0Sstevel@tonic-gate 1209*0Sstevel@tonic-gate if ((rv = cpu_unconfigure(cpuid)) != 0) { 1210*0Sstevel@tonic-gate SBD_SET_ERR(ep, sbd_errno2ecode(rv)); 1211*0Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_cpupath[unit]); 1212*0Sstevel@tonic-gate cmn_err(CE_WARN, 1213*0Sstevel@tonic-gate "sbd:%s: cpu_unconfigure for cpu %d failed", 1214*0Sstevel@tonic-gate f, cpuid); 1215*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 1216*0Sstevel@tonic-gate return; 1217*0Sstevel@tonic-gate } 1218*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 1219*0Sstevel@tonic-gate 1220*0Sstevel@tonic-gate /* 1221*0Sstevel@tonic-gate * Since CPU nodes are no longer configured in CPU 1222*0Sstevel@tonic-gate * attach, the corresponding branch unconfigure 1223*0Sstevel@tonic-gate * operation that would be performed here is also 1224*0Sstevel@tonic-gate * no longer required. 1225*0Sstevel@tonic-gate */ 1226*0Sstevel@tonic-gate } 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate 1229*0Sstevel@tonic-gate int 1230*0Sstevel@tonic-gate sbd_detach_mem(sbd_handle_t *hp, sbderror_t *ep, int unit) 1231*0Sstevel@tonic-gate { 1232*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 1233*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1234*0Sstevel@tonic-gate int i, rv; 1235*0Sstevel@tonic-gate static fn_t f = "sbd_detach_mem"; 1236*0Sstevel@tonic-gate 1237*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate if (sbd_detach_memory(hp, ep, mp, unit)) { 1240*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: detach fail", f); 1241*0Sstevel@tonic-gate return (-1); 1242*0Sstevel@tonic-gate } 1243*0Sstevel@tonic-gate 1244*0Sstevel@tonic-gate /* 1245*0Sstevel@tonic-gate * Now detach mem devinfo nodes with status lock held. 1246*0Sstevel@tonic-gate */ 1247*0Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 1248*0Sstevel@tonic-gate dev_info_t *fdip = NULL; 1249*0Sstevel@tonic-gate 1250*0Sstevel@tonic-gate if (mp->sbm_dip[i] == NULL) 1251*0Sstevel@tonic-gate continue; 1252*0Sstevel@tonic-gate ASSERT(e_ddi_branch_held(mp->sbm_dip[i])); 1253*0Sstevel@tonic-gate mutex_enter(&sbp->sb_slock); 1254*0Sstevel@tonic-gate rv = e_ddi_branch_unconfigure(mp->sbm_dip[i], &fdip, 1255*0Sstevel@tonic-gate DEVI_BRANCH_EVENT); 1256*0Sstevel@tonic-gate mutex_exit(&sbp->sb_slock); 1257*0Sstevel@tonic-gate if (rv) { 1258*0Sstevel@tonic-gate /* 1259*0Sstevel@tonic-gate * If non-NULL, fdip is returned held and must be 1260*0Sstevel@tonic-gate * released. 1261*0Sstevel@tonic-gate */ 1262*0Sstevel@tonic-gate if (fdip != NULL) { 1263*0Sstevel@tonic-gate sbd_errno_decode(rv, ep, fdip); 1264*0Sstevel@tonic-gate ddi_release_devi(fdip); 1265*0Sstevel@tonic-gate } else { 1266*0Sstevel@tonic-gate sbd_errno_decode(rv, ep, mp->sbm_dip[i]); 1267*0Sstevel@tonic-gate } 1268*0Sstevel@tonic-gate } 1269*0Sstevel@tonic-gate } 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate return (0); 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate 1274*0Sstevel@tonic-gate /* start beginning of sbd.c */ 1275*0Sstevel@tonic-gate 1276*0Sstevel@tonic-gate /* 1277*0Sstevel@tonic-gate * MDR memory support - somewhat disabled for now. 1278*0Sstevel@tonic-gate * UNSAFE unsafe driver code - I don't think we want this. 1279*0Sstevel@tonic-gate * need to check. 1280*0Sstevel@tonic-gate * DEVNODE This driver creates attachment points for individual 1281*0Sstevel@tonic-gate * components as well as boards. We only need board 1282*0Sstevel@tonic-gate * support. 1283*0Sstevel@tonic-gate * DEV2DEVSET Put only present devices in devset. 1284*0Sstevel@tonic-gate */ 1285*0Sstevel@tonic-gate 1286*0Sstevel@tonic-gate 1287*0Sstevel@tonic-gate static sbd_state_t 1288*0Sstevel@tonic-gate rstate_cvt(sbd_istate_t state) 1289*0Sstevel@tonic-gate { 1290*0Sstevel@tonic-gate sbd_state_t cs; 1291*0Sstevel@tonic-gate 1292*0Sstevel@tonic-gate switch (state) { 1293*0Sstevel@tonic-gate case SBD_STATE_EMPTY: 1294*0Sstevel@tonic-gate cs = SBD_STAT_EMPTY; 1295*0Sstevel@tonic-gate break; 1296*0Sstevel@tonic-gate case SBD_STATE_OCCUPIED: 1297*0Sstevel@tonic-gate case SBD_STATE_FATAL: 1298*0Sstevel@tonic-gate cs = SBD_STAT_DISCONNECTED; 1299*0Sstevel@tonic-gate break; 1300*0Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 1301*0Sstevel@tonic-gate case SBD_STATE_CONNECTED: 1302*0Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 1303*0Sstevel@tonic-gate case SBD_STATE_PARTIAL: 1304*0Sstevel@tonic-gate case SBD_STATE_RELEASE: 1305*0Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: 1306*0Sstevel@tonic-gate cs = SBD_STAT_CONNECTED; 1307*0Sstevel@tonic-gate break; 1308*0Sstevel@tonic-gate default: 1309*0Sstevel@tonic-gate cs = SBD_STAT_NONE; 1310*0Sstevel@tonic-gate break; 1311*0Sstevel@tonic-gate } 1312*0Sstevel@tonic-gate 1313*0Sstevel@tonic-gate return (cs); 1314*0Sstevel@tonic-gate } 1315*0Sstevel@tonic-gate 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate sbd_state_t 1318*0Sstevel@tonic-gate ostate_cvt(sbd_istate_t state) 1319*0Sstevel@tonic-gate { 1320*0Sstevel@tonic-gate sbd_state_t cs; 1321*0Sstevel@tonic-gate 1322*0Sstevel@tonic-gate switch (state) { 1323*0Sstevel@tonic-gate case SBD_STATE_EMPTY: 1324*0Sstevel@tonic-gate case SBD_STATE_OCCUPIED: 1325*0Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 1326*0Sstevel@tonic-gate case SBD_STATE_CONNECTED: 1327*0Sstevel@tonic-gate case SBD_STATE_FATAL: 1328*0Sstevel@tonic-gate cs = SBD_STAT_UNCONFIGURED; 1329*0Sstevel@tonic-gate break; 1330*0Sstevel@tonic-gate case SBD_STATE_PARTIAL: 1331*0Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 1332*0Sstevel@tonic-gate case SBD_STATE_RELEASE: 1333*0Sstevel@tonic-gate case SBD_STATE_UNREFERENCED: 1334*0Sstevel@tonic-gate cs = SBD_STAT_CONFIGURED; 1335*0Sstevel@tonic-gate break; 1336*0Sstevel@tonic-gate default: 1337*0Sstevel@tonic-gate cs = SBD_STAT_NONE; 1338*0Sstevel@tonic-gate break; 1339*0Sstevel@tonic-gate } 1340*0Sstevel@tonic-gate 1341*0Sstevel@tonic-gate return (cs); 1342*0Sstevel@tonic-gate } 1343*0Sstevel@tonic-gate 1344*0Sstevel@tonic-gate int 1345*0Sstevel@tonic-gate sbd_dealloc_instance(sbd_board_t *sbp, int max_boards) 1346*0Sstevel@tonic-gate { 1347*0Sstevel@tonic-gate int b; 1348*0Sstevel@tonic-gate sbd_board_t *list = sbp; 1349*0Sstevel@tonic-gate static fn_t f = "sbd_dealloc_instance"; 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 1352*0Sstevel@tonic-gate 1353*0Sstevel@tonic-gate if (sbp == NULL) { 1354*0Sstevel@tonic-gate return (-1); 1355*0Sstevel@tonic-gate } 1356*0Sstevel@tonic-gate 1357*0Sstevel@tonic-gate for (b = 0; b < max_boards; b++) { 1358*0Sstevel@tonic-gate sbd_board_destroy(sbp++); 1359*0Sstevel@tonic-gate } 1360*0Sstevel@tonic-gate 1361*0Sstevel@tonic-gate FREESTRUCT(list, sbd_board_t, max_boards); 1362*0Sstevel@tonic-gate 1363*0Sstevel@tonic-gate return (0); 1364*0Sstevel@tonic-gate } 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate static sbd_devset_t 1367*0Sstevel@tonic-gate sbd_dev2devset(sbd_comp_id_t *cid) 1368*0Sstevel@tonic-gate { 1369*0Sstevel@tonic-gate static fn_t f = "sbd_dev2devset"; 1370*0Sstevel@tonic-gate 1371*0Sstevel@tonic-gate sbd_devset_t devset; 1372*0Sstevel@tonic-gate int unit = cid->c_unit; 1373*0Sstevel@tonic-gate 1374*0Sstevel@tonic-gate switch (cid->c_type) { 1375*0Sstevel@tonic-gate case SBD_COMP_NONE: 1376*0Sstevel@tonic-gate devset = DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT); 1377*0Sstevel@tonic-gate devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT); 1378*0Sstevel@tonic-gate devset |= DEVSET(SBD_COMP_IO, DEVSET_ANYUNIT); 1379*0Sstevel@tonic-gate break; 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate case SBD_COMP_CPU: 1382*0Sstevel@tonic-gate if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) { 1383*0Sstevel@tonic-gate PR_ALL("%s: invalid cpu unit# = %d", 1384*0Sstevel@tonic-gate f, unit); 1385*0Sstevel@tonic-gate devset = 0; 1386*0Sstevel@tonic-gate } else 1387*0Sstevel@tonic-gate /* 1388*0Sstevel@tonic-gate * Generate a devset that includes all the 1389*0Sstevel@tonic-gate * cores of a CMP device. If this is not a 1390*0Sstevel@tonic-gate * CMP, the extra cores will be eliminated 1391*0Sstevel@tonic-gate * later since they are not present. This is 1392*0Sstevel@tonic-gate * also true for CMP devices that do not have 1393*0Sstevel@tonic-gate * all cores active. 1394*0Sstevel@tonic-gate */ 1395*0Sstevel@tonic-gate devset = DEVSET(SBD_COMP_CMP, unit); 1396*0Sstevel@tonic-gate 1397*0Sstevel@tonic-gate break; 1398*0Sstevel@tonic-gate 1399*0Sstevel@tonic-gate case SBD_COMP_MEM: 1400*0Sstevel@tonic-gate 1401*0Sstevel@tonic-gate if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) { 1402*0Sstevel@tonic-gate #ifdef XXX_jeffco 1403*0Sstevel@tonic-gate PR_ALL("%s: invalid mem unit# = %d", 1404*0Sstevel@tonic-gate f, unit); 1405*0Sstevel@tonic-gate devset = 0; 1406*0Sstevel@tonic-gate #endif 1407*0Sstevel@tonic-gate devset = DEVSET(cid->c_type, 0); 1408*0Sstevel@tonic-gate PR_ALL("%s: adjusted MEM devset = 0x%x\n", 1409*0Sstevel@tonic-gate f, devset); 1410*0Sstevel@tonic-gate } else 1411*0Sstevel@tonic-gate devset = DEVSET(cid->c_type, unit); 1412*0Sstevel@tonic-gate break; 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate case SBD_COMP_IO: 1415*0Sstevel@tonic-gate if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) { 1416*0Sstevel@tonic-gate PR_ALL("%s: invalid io unit# = %d", 1417*0Sstevel@tonic-gate f, unit); 1418*0Sstevel@tonic-gate devset = 0; 1419*0Sstevel@tonic-gate } else 1420*0Sstevel@tonic-gate devset = DEVSET(cid->c_type, unit); 1421*0Sstevel@tonic-gate 1422*0Sstevel@tonic-gate break; 1423*0Sstevel@tonic-gate 1424*0Sstevel@tonic-gate default: 1425*0Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 1426*0Sstevel@tonic-gate devset = 0; 1427*0Sstevel@tonic-gate break; 1428*0Sstevel@tonic-gate } 1429*0Sstevel@tonic-gate 1430*0Sstevel@tonic-gate return (devset); 1431*0Sstevel@tonic-gate } 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate /* 1434*0Sstevel@tonic-gate * Simple mutex for covering handle list ops as it is only 1435*0Sstevel@tonic-gate * used "infrequently". No need to add another mutex to the sbd_board_t. 1436*0Sstevel@tonic-gate */ 1437*0Sstevel@tonic-gate static kmutex_t sbd_handle_list_mutex; 1438*0Sstevel@tonic-gate 1439*0Sstevel@tonic-gate static sbd_handle_t * 1440*0Sstevel@tonic-gate sbd_get_handle(dev_t dev, sbd_softstate_t *softsp, intptr_t arg, 1441*0Sstevel@tonic-gate sbd_init_arg_t *iap) 1442*0Sstevel@tonic-gate { 1443*0Sstevel@tonic-gate sbd_handle_t *hp; 1444*0Sstevel@tonic-gate sbderror_t *ep; 1445*0Sstevel@tonic-gate sbd_priv_handle_t *shp; 1446*0Sstevel@tonic-gate sbd_board_t *sbp = softsp->sbd_boardlist; 1447*0Sstevel@tonic-gate int board; 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate board = SBDGETSLOT(dev); 1450*0Sstevel@tonic-gate ASSERT(board < softsp->max_boards); 1451*0Sstevel@tonic-gate sbp += board; 1452*0Sstevel@tonic-gate 1453*0Sstevel@tonic-gate /* 1454*0Sstevel@tonic-gate * Brand-new handle. 1455*0Sstevel@tonic-gate */ 1456*0Sstevel@tonic-gate shp = kmem_zalloc(sizeof (sbd_priv_handle_t), KM_SLEEP); 1457*0Sstevel@tonic-gate shp->sh_arg = (void *)arg; 1458*0Sstevel@tonic-gate 1459*0Sstevel@tonic-gate hp = MACHHD2HD(shp); 1460*0Sstevel@tonic-gate 1461*0Sstevel@tonic-gate ep = &shp->sh_err; 1462*0Sstevel@tonic-gate 1463*0Sstevel@tonic-gate hp->h_err = ep; 1464*0Sstevel@tonic-gate hp->h_sbd = (void *) sbp; 1465*0Sstevel@tonic-gate hp->h_dev = iap->dev; 1466*0Sstevel@tonic-gate hp->h_cmd = iap->cmd; 1467*0Sstevel@tonic-gate hp->h_mode = iap->mode; 1468*0Sstevel@tonic-gate sbd_init_err(ep); 1469*0Sstevel@tonic-gate 1470*0Sstevel@tonic-gate mutex_enter(&sbd_handle_list_mutex); 1471*0Sstevel@tonic-gate shp->sh_next = sbp->sb_handle; 1472*0Sstevel@tonic-gate sbp->sb_handle = shp; 1473*0Sstevel@tonic-gate mutex_exit(&sbd_handle_list_mutex); 1474*0Sstevel@tonic-gate 1475*0Sstevel@tonic-gate return (hp); 1476*0Sstevel@tonic-gate } 1477*0Sstevel@tonic-gate 1478*0Sstevel@tonic-gate void 1479*0Sstevel@tonic-gate sbd_init_err(sbderror_t *ep) 1480*0Sstevel@tonic-gate { 1481*0Sstevel@tonic-gate ep->e_errno = 0; 1482*0Sstevel@tonic-gate ep->e_code = 0; 1483*0Sstevel@tonic-gate ep->e_rsc[0] = '\0'; 1484*0Sstevel@tonic-gate } 1485*0Sstevel@tonic-gate 1486*0Sstevel@tonic-gate int 1487*0Sstevel@tonic-gate sbd_set_err_in_hdl(sbd_handle_t *hp, sbderror_t *ep) 1488*0Sstevel@tonic-gate { 1489*0Sstevel@tonic-gate sbderror_t *hep = SBD_HD2ERR(hp); 1490*0Sstevel@tonic-gate 1491*0Sstevel@tonic-gate /* 1492*0Sstevel@tonic-gate * If there is an error logged already, don't rewrite it 1493*0Sstevel@tonic-gate */ 1494*0Sstevel@tonic-gate if (SBD_GET_ERR(hep) || SBD_GET_ERRNO(hep)) { 1495*0Sstevel@tonic-gate return (0); 1496*0Sstevel@tonic-gate } 1497*0Sstevel@tonic-gate 1498*0Sstevel@tonic-gate if (SBD_GET_ERR(ep) || SBD_GET_ERRNO(ep)) { 1499*0Sstevel@tonic-gate SBD_SET_ERR(hep, SBD_GET_ERR(ep)); 1500*0Sstevel@tonic-gate SBD_SET_ERRNO(hep, SBD_GET_ERRNO(ep)); 1501*0Sstevel@tonic-gate SBD_SET_ERRSTR(hep, SBD_GET_ERRSTR(ep)); 1502*0Sstevel@tonic-gate return (0); 1503*0Sstevel@tonic-gate } 1504*0Sstevel@tonic-gate 1505*0Sstevel@tonic-gate return (-1); 1506*0Sstevel@tonic-gate } 1507*0Sstevel@tonic-gate 1508*0Sstevel@tonic-gate static void 1509*0Sstevel@tonic-gate sbd_release_handle(sbd_handle_t *hp) 1510*0Sstevel@tonic-gate { 1511*0Sstevel@tonic-gate sbd_priv_handle_t *shp, **shpp; 1512*0Sstevel@tonic-gate sbd_board_t *sbp; 1513*0Sstevel@tonic-gate static fn_t f = "sbd_release_handle"; 1514*0Sstevel@tonic-gate 1515*0Sstevel@tonic-gate if (hp == NULL) 1516*0Sstevel@tonic-gate return; 1517*0Sstevel@tonic-gate 1518*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 1519*0Sstevel@tonic-gate 1520*0Sstevel@tonic-gate shp = HD2MACHHD(hp); 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate mutex_enter(&sbd_handle_list_mutex); 1523*0Sstevel@tonic-gate /* 1524*0Sstevel@tonic-gate * Locate the handle in the board's reference list. 1525*0Sstevel@tonic-gate */ 1526*0Sstevel@tonic-gate for (shpp = &sbp->sb_handle; (*shpp) && ((*shpp) != shp); 1527*0Sstevel@tonic-gate shpp = &((*shpp)->sh_next)) 1528*0Sstevel@tonic-gate /* empty */; 1529*0Sstevel@tonic-gate 1530*0Sstevel@tonic-gate if (*shpp == NULL) { 1531*0Sstevel@tonic-gate cmn_err(CE_PANIC, 1532*0Sstevel@tonic-gate "sbd:%s: handle not found in board %d", 1533*0Sstevel@tonic-gate f, sbp->sb_num); 1534*0Sstevel@tonic-gate /*NOTREACHED*/ 1535*0Sstevel@tonic-gate } else { 1536*0Sstevel@tonic-gate *shpp = shp->sh_next; 1537*0Sstevel@tonic-gate } 1538*0Sstevel@tonic-gate mutex_exit(&sbd_handle_list_mutex); 1539*0Sstevel@tonic-gate 1540*0Sstevel@tonic-gate if (hp->h_opts.copts != NULL) { 1541*0Sstevel@tonic-gate FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size); 1542*0Sstevel@tonic-gate } 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate FREESTRUCT(shp, sbd_priv_handle_t, 1); 1545*0Sstevel@tonic-gate } 1546*0Sstevel@tonic-gate 1547*0Sstevel@tonic-gate sbdp_handle_t * 1548*0Sstevel@tonic-gate sbd_get_sbdp_handle(sbd_board_t *sbp, sbd_handle_t *hp) 1549*0Sstevel@tonic-gate { 1550*0Sstevel@tonic-gate sbdp_handle_t *hdp; 1551*0Sstevel@tonic-gate 1552*0Sstevel@tonic-gate hdp = kmem_zalloc(sizeof (sbdp_handle_t), KM_SLEEP); 1553*0Sstevel@tonic-gate hdp->h_err = kmem_zalloc(sizeof (sbd_error_t), KM_SLEEP); 1554*0Sstevel@tonic-gate if (sbp == NULL) { 1555*0Sstevel@tonic-gate hdp->h_board = -1; 1556*0Sstevel@tonic-gate hdp->h_wnode = -1; 1557*0Sstevel@tonic-gate } else { 1558*0Sstevel@tonic-gate hdp->h_board = sbp->sb_num; 1559*0Sstevel@tonic-gate hdp->h_wnode = sbp->sb_wnode; 1560*0Sstevel@tonic-gate } 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate if (hp == NULL) { 1563*0Sstevel@tonic-gate hdp->h_flags = 0; 1564*0Sstevel@tonic-gate hdp->h_opts = NULL; 1565*0Sstevel@tonic-gate } else { 1566*0Sstevel@tonic-gate hdp->h_flags = SBD_2_SBDP_FLAGS(hp->h_flags); 1567*0Sstevel@tonic-gate hdp->h_opts = &hp->h_opts; 1568*0Sstevel@tonic-gate } 1569*0Sstevel@tonic-gate 1570*0Sstevel@tonic-gate return (hdp); 1571*0Sstevel@tonic-gate } 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate void 1574*0Sstevel@tonic-gate sbd_release_sbdp_handle(sbdp_handle_t *hdp) 1575*0Sstevel@tonic-gate { 1576*0Sstevel@tonic-gate if (hdp == NULL) 1577*0Sstevel@tonic-gate return; 1578*0Sstevel@tonic-gate 1579*0Sstevel@tonic-gate kmem_free(hdp->h_err, sizeof (sbd_error_t)); 1580*0Sstevel@tonic-gate kmem_free(hdp, sizeof (sbdp_handle_t)); 1581*0Sstevel@tonic-gate } 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate void 1584*0Sstevel@tonic-gate sbd_reset_error_sbdph(sbdp_handle_t *hdp) 1585*0Sstevel@tonic-gate { 1586*0Sstevel@tonic-gate if ((hdp != NULL) && (hdp->h_err != NULL)) { 1587*0Sstevel@tonic-gate bzero(hdp->h_err, sizeof (sbd_error_t)); 1588*0Sstevel@tonic-gate } 1589*0Sstevel@tonic-gate } 1590*0Sstevel@tonic-gate 1591*0Sstevel@tonic-gate static int 1592*0Sstevel@tonic-gate sbd_copyin_ioarg(sbd_handle_t *hp, int mode, int cmd, sbd_cmd_t *cmdp, 1593*0Sstevel@tonic-gate sbd_ioctl_arg_t *iap) 1594*0Sstevel@tonic-gate { 1595*0Sstevel@tonic-gate static fn_t f = "sbd_copyin_ioarg"; 1596*0Sstevel@tonic-gate 1597*0Sstevel@tonic-gate if (iap == NULL) 1598*0Sstevel@tonic-gate return (EINVAL); 1599*0Sstevel@tonic-gate 1600*0Sstevel@tonic-gate bzero((caddr_t)cmdp, sizeof (sbd_cmd_t)); 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1603*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1604*0Sstevel@tonic-gate sbd_cmd32_t scmd32; 1605*0Sstevel@tonic-gate 1606*0Sstevel@tonic-gate bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t)); 1607*0Sstevel@tonic-gate 1608*0Sstevel@tonic-gate if (ddi_copyin((void *)iap, (void *)&scmd32, 1609*0Sstevel@tonic-gate sizeof (sbd_cmd32_t), mode)) { 1610*0Sstevel@tonic-gate cmn_err(CE_WARN, 1611*0Sstevel@tonic-gate "sbd:%s: (32bit) failed to copyin " 1612*0Sstevel@tonic-gate "sbdcmd-struct", f); 1613*0Sstevel@tonic-gate return (EFAULT); 1614*0Sstevel@tonic-gate } 1615*0Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type; 1616*0Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit; 1617*0Sstevel@tonic-gate bcopy(&scmd32.cmd_cm.c_id.c_name[0], 1618*0Sstevel@tonic-gate &cmdp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME); 1619*0Sstevel@tonic-gate cmdp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags; 1620*0Sstevel@tonic-gate cmdp->cmd_cm.c_len = scmd32.cmd_cm.c_len; 1621*0Sstevel@tonic-gate cmdp->cmd_cm.c_opts = (caddr_t)scmd32.cmd_cm.c_opts; 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate if (cmd == SBD_CMD_PASSTHRU) { 1624*0Sstevel@tonic-gate PR_BYP("passthru copyin: iap=%p, sz=%d", iap, 1625*0Sstevel@tonic-gate sizeof (sbd_cmd32_t)); 1626*0Sstevel@tonic-gate PR_BYP("passthru copyin: c_opts=%p, c_len=%d", 1627*0Sstevel@tonic-gate scmd32.cmd_cm.c_opts, 1628*0Sstevel@tonic-gate scmd32.cmd_cm.c_len); 1629*0Sstevel@tonic-gate } 1630*0Sstevel@tonic-gate 1631*0Sstevel@tonic-gate switch (cmd) { 1632*0Sstevel@tonic-gate case SBD_CMD_STATUS: 1633*0Sstevel@tonic-gate cmdp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes; 1634*0Sstevel@tonic-gate cmdp->cmd_stat.s_statp = 1635*0Sstevel@tonic-gate (caddr_t)scmd32.cmd_stat.s_statp; 1636*0Sstevel@tonic-gate break; 1637*0Sstevel@tonic-gate default: 1638*0Sstevel@tonic-gate break; 1639*0Sstevel@tonic-gate 1640*0Sstevel@tonic-gate } 1641*0Sstevel@tonic-gate } else 1642*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1643*0Sstevel@tonic-gate if (ddi_copyin((void *)iap, (void *)cmdp, 1644*0Sstevel@tonic-gate sizeof (sbd_cmd_t), mode) != 0) { 1645*0Sstevel@tonic-gate cmn_err(CE_WARN, 1646*0Sstevel@tonic-gate "sbd:%s: failed to copyin sbd cmd_t struct", f); 1647*0Sstevel@tonic-gate return (EFAULT); 1648*0Sstevel@tonic-gate } 1649*0Sstevel@tonic-gate /* 1650*0Sstevel@tonic-gate * A user may set platform specific options so we need to 1651*0Sstevel@tonic-gate * copy them in 1652*0Sstevel@tonic-gate */ 1653*0Sstevel@tonic-gate if ((cmd != SBD_CMD_STATUS) && ((hp->h_opts.size = cmdp->cmd_cm.c_len) 1654*0Sstevel@tonic-gate > 0)) { 1655*0Sstevel@tonic-gate hp->h_opts.size += 1; /* For null termination of string. */ 1656*0Sstevel@tonic-gate hp->h_opts.copts = GETSTRUCT(char, hp->h_opts.size); 1657*0Sstevel@tonic-gate if (ddi_copyin((void *)cmdp->cmd_cm.c_opts, 1658*0Sstevel@tonic-gate (void *)hp->h_opts.copts, 1659*0Sstevel@tonic-gate cmdp->cmd_cm.c_len, hp->h_mode) != 0) { 1660*0Sstevel@tonic-gate /* copts is freed in sbd_release_handle(). */ 1661*0Sstevel@tonic-gate cmn_err(CE_WARN, 1662*0Sstevel@tonic-gate "sbd:%s: failed to copyin options", f); 1663*0Sstevel@tonic-gate return (EFAULT); 1664*0Sstevel@tonic-gate } 1665*0Sstevel@tonic-gate } 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate return (0); 1668*0Sstevel@tonic-gate } 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate static int 1671*0Sstevel@tonic-gate sbd_copyout_ioarg(int mode, int cmd, sbd_cmd_t *scp, sbd_ioctl_arg_t *iap) 1672*0Sstevel@tonic-gate { 1673*0Sstevel@tonic-gate static fn_t f = "sbd_copyout_ioarg"; 1674*0Sstevel@tonic-gate 1675*0Sstevel@tonic-gate if ((iap == NULL) || (scp == NULL)) 1676*0Sstevel@tonic-gate return (EINVAL); 1677*0Sstevel@tonic-gate 1678*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1679*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1680*0Sstevel@tonic-gate sbd_cmd32_t scmd32; 1681*0Sstevel@tonic-gate 1682*0Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type; 1683*0Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit; 1684*0Sstevel@tonic-gate bcopy(scp->cmd_cm.c_id.c_name, 1685*0Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_name, OBP_MAXPROPNAME); 1686*0Sstevel@tonic-gate 1687*0Sstevel@tonic-gate scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags; 1688*0Sstevel@tonic-gate 1689*0Sstevel@tonic-gate switch (cmd) { 1690*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 1691*0Sstevel@tonic-gate scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm; 1692*0Sstevel@tonic-gate break; 1693*0Sstevel@tonic-gate default: 1694*0Sstevel@tonic-gate break; 1695*0Sstevel@tonic-gate } 1696*0Sstevel@tonic-gate 1697*0Sstevel@tonic-gate if (ddi_copyout((void *)&scmd32, (void *)iap, 1698*0Sstevel@tonic-gate sizeof (sbd_cmd32_t), mode)) { 1699*0Sstevel@tonic-gate cmn_err(CE_WARN, 1700*0Sstevel@tonic-gate "sbd:%s: (32bit) failed to copyout " 1701*0Sstevel@tonic-gate "sbdcmd struct", f); 1702*0Sstevel@tonic-gate return (EFAULT); 1703*0Sstevel@tonic-gate } 1704*0Sstevel@tonic-gate } else 1705*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1706*0Sstevel@tonic-gate if (ddi_copyout((void *)scp, (void *)iap, 1707*0Sstevel@tonic-gate sizeof (sbd_cmd_t), mode) != 0) { 1708*0Sstevel@tonic-gate cmn_err(CE_WARN, 1709*0Sstevel@tonic-gate "sbd:%s: failed to copyout sbdcmd struct", f); 1710*0Sstevel@tonic-gate return (EFAULT); 1711*0Sstevel@tonic-gate } 1712*0Sstevel@tonic-gate 1713*0Sstevel@tonic-gate return (0); 1714*0Sstevel@tonic-gate } 1715*0Sstevel@tonic-gate 1716*0Sstevel@tonic-gate static int 1717*0Sstevel@tonic-gate sbd_copyout_errs(int mode, sbd_ioctl_arg_t *iap, void *arg) 1718*0Sstevel@tonic-gate { 1719*0Sstevel@tonic-gate static fn_t f = "sbd_copyout_errs"; 1720*0Sstevel@tonic-gate sbd_ioctl_arg_t *uap; 1721*0Sstevel@tonic-gate 1722*0Sstevel@tonic-gate uap = (sbd_ioctl_arg_t *)arg; 1723*0Sstevel@tonic-gate 1724*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1725*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 1726*0Sstevel@tonic-gate sbd_error32_t err32; 1727*0Sstevel@tonic-gate sbd_ioctl_arg32_t *uap32; 1728*0Sstevel@tonic-gate 1729*0Sstevel@tonic-gate uap32 = (sbd_ioctl_arg32_t *)arg; 1730*0Sstevel@tonic-gate 1731*0Sstevel@tonic-gate err32.e_code = iap->ie_code; 1732*0Sstevel@tonic-gate (void) strcpy(err32.e_rsc, iap->ie_rsc); 1733*0Sstevel@tonic-gate 1734*0Sstevel@tonic-gate if (ddi_copyout((void *)&err32, (void *)&uap32->i_err, 1735*0Sstevel@tonic-gate sizeof (sbd_error32_t), mode)) { 1736*0Sstevel@tonic-gate cmn_err(CE_WARN, 1737*0Sstevel@tonic-gate "sbd:%s: failed to copyout ioctl32 errs", 1738*0Sstevel@tonic-gate f); 1739*0Sstevel@tonic-gate return (EFAULT); 1740*0Sstevel@tonic-gate } 1741*0Sstevel@tonic-gate } else 1742*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1743*0Sstevel@tonic-gate if (ddi_copyout((void *)&iap->i_err, (void *)&uap->i_err, 1744*0Sstevel@tonic-gate sizeof (sbd_error_t), mode) != 0) { 1745*0Sstevel@tonic-gate cmn_err(CE_WARN, 1746*0Sstevel@tonic-gate "sbd:%s: failed to copyout ioctl errs", f); 1747*0Sstevel@tonic-gate return (EFAULT); 1748*0Sstevel@tonic-gate } 1749*0Sstevel@tonic-gate 1750*0Sstevel@tonic-gate return (0); 1751*0Sstevel@tonic-gate } 1752*0Sstevel@tonic-gate 1753*0Sstevel@tonic-gate /* 1754*0Sstevel@tonic-gate * State transition policy is that if at least one 1755*0Sstevel@tonic-gate * device cannot make the transition, then none of 1756*0Sstevel@tonic-gate * the requested devices are allowed to transition. 1757*0Sstevel@tonic-gate * 1758*0Sstevel@tonic-gate * Returns the state that is in error, if any. 1759*0Sstevel@tonic-gate */ 1760*0Sstevel@tonic-gate static int 1761*0Sstevel@tonic-gate sbd_check_transition(sbd_board_t *sbp, sbd_devset_t *devsetp, 1762*0Sstevel@tonic-gate struct sbd_state_trans *transp) 1763*0Sstevel@tonic-gate { 1764*0Sstevel@tonic-gate int s, ut; 1765*0Sstevel@tonic-gate int state_err = 0; 1766*0Sstevel@tonic-gate sbd_devset_t devset; 1767*0Sstevel@tonic-gate static fn_t f = "sbd_check_transition"; 1768*0Sstevel@tonic-gate 1769*0Sstevel@tonic-gate devset = *devsetp; 1770*0Sstevel@tonic-gate 1771*0Sstevel@tonic-gate if (!devset) { 1772*0Sstevel@tonic-gate /* 1773*0Sstevel@tonic-gate * Transition does not deal with any components. 1774*0Sstevel@tonic-gate * This is the case for addboard/deleteboard. 1775*0Sstevel@tonic-gate */ 1776*0Sstevel@tonic-gate PR_ALL("%s: no devs: requested devset = 0x%x," 1777*0Sstevel@tonic-gate " final devset = 0x%x\n", 1778*0Sstevel@tonic-gate f, (uint_t)*devsetp, (uint_t)devset); 1779*0Sstevel@tonic-gate 1780*0Sstevel@tonic-gate return (0); 1781*0Sstevel@tonic-gate } 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 1784*0Sstevel@tonic-gate for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) { 1785*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0) 1786*0Sstevel@tonic-gate continue; 1787*0Sstevel@tonic-gate s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, ut); 1788*0Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 1789*0Sstevel@tonic-gate if (!state_err) 1790*0Sstevel@tonic-gate state_err = s; 1791*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, ut); 1792*0Sstevel@tonic-gate } 1793*0Sstevel@tonic-gate } 1794*0Sstevel@tonic-gate } 1795*0Sstevel@tonic-gate 1796*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 1797*0Sstevel@tonic-gate for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) { 1798*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0) 1799*0Sstevel@tonic-gate continue; 1800*0Sstevel@tonic-gate s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_CPU, ut); 1801*0Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 1802*0Sstevel@tonic-gate if (!state_err) 1803*0Sstevel@tonic-gate state_err = s; 1804*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, ut); 1805*0Sstevel@tonic-gate } 1806*0Sstevel@tonic-gate } 1807*0Sstevel@tonic-gate } 1808*0Sstevel@tonic-gate 1809*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 1810*0Sstevel@tonic-gate for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) { 1811*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0) 1812*0Sstevel@tonic-gate continue; 1813*0Sstevel@tonic-gate s = (int)SBD_DEVICE_STATE(sbp, SBD_COMP_IO, ut); 1814*0Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 1815*0Sstevel@tonic-gate if (!state_err) 1816*0Sstevel@tonic-gate state_err = s; 1817*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, ut); 1818*0Sstevel@tonic-gate } 1819*0Sstevel@tonic-gate } 1820*0Sstevel@tonic-gate } 1821*0Sstevel@tonic-gate 1822*0Sstevel@tonic-gate PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n", 1823*0Sstevel@tonic-gate f, (uint_t)*devsetp, (uint_t)devset); 1824*0Sstevel@tonic-gate 1825*0Sstevel@tonic-gate *devsetp = devset; 1826*0Sstevel@tonic-gate /* 1827*0Sstevel@tonic-gate * If there are some remaining components for which 1828*0Sstevel@tonic-gate * this state transition is valid, then allow them 1829*0Sstevel@tonic-gate * through, otherwise if none are left then return 1830*0Sstevel@tonic-gate * the state error. 1831*0Sstevel@tonic-gate */ 1832*0Sstevel@tonic-gate return (devset ? 0 : state_err); 1833*0Sstevel@tonic-gate } 1834*0Sstevel@tonic-gate 1835*0Sstevel@tonic-gate /* 1836*0Sstevel@tonic-gate * pre-op entry point must SET_ERRNO(), if needed. 1837*0Sstevel@tonic-gate * Return value of non-zero indicates failure. 1838*0Sstevel@tonic-gate */ 1839*0Sstevel@tonic-gate static int 1840*0Sstevel@tonic-gate sbd_pre_op(sbd_handle_t *hp) 1841*0Sstevel@tonic-gate { 1842*0Sstevel@tonic-gate int rv = 0, t; 1843*0Sstevel@tonic-gate int cmd, serr = 0; 1844*0Sstevel@tonic-gate sbd_devset_t devset; 1845*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1846*0Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 1847*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 1848*0Sstevel@tonic-gate sbd_cmd_t *cmdp; 1849*0Sstevel@tonic-gate static fn_t f = "sbd_pre_op"; 1850*0Sstevel@tonic-gate 1851*0Sstevel@tonic-gate cmd = hp->h_cmd; 1852*0Sstevel@tonic-gate devset = shp->sh_devset; 1853*0Sstevel@tonic-gate 1854*0Sstevel@tonic-gate switch (cmd) { 1855*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 1856*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 1857*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 1858*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 1859*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: 1860*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 1861*0Sstevel@tonic-gate case SBD_CMD_POWERON: 1862*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: 1863*0Sstevel@tonic-gate case SBD_CMD_TEST: 1864*0Sstevel@tonic-gate /* ioctls allowed if caller has write permission */ 1865*0Sstevel@tonic-gate if (!(hp->h_mode & FWRITE)) { 1866*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, EPERM); 1867*0Sstevel@tonic-gate return (-1); 1868*0Sstevel@tonic-gate } 1869*0Sstevel@tonic-gate 1870*0Sstevel@tonic-gate default: 1871*0Sstevel@tonic-gate break; 1872*0Sstevel@tonic-gate } 1873*0Sstevel@tonic-gate 1874*0Sstevel@tonic-gate hp->h_iap = GETSTRUCT(sbd_ioctl_arg_t, 1); 1875*0Sstevel@tonic-gate rv = sbd_copyin_ioarg(hp, hp->h_mode, cmd, 1876*0Sstevel@tonic-gate (sbd_cmd_t *)hp->h_iap, shp->sh_arg); 1877*0Sstevel@tonic-gate if (rv) { 1878*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, rv); 1879*0Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 1880*0Sstevel@tonic-gate hp->h_iap = NULL; 1881*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: copyin fail", f); 1882*0Sstevel@tonic-gate return (-1); 1883*0Sstevel@tonic-gate } else { 1884*0Sstevel@tonic-gate cmdp = (sbd_cmd_t *)hp->h_iap; 1885*0Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_name[0] != '\0') { 1886*0Sstevel@tonic-gate 1887*0Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_type = SBD_COMP(sbd_name_to_idx( 1888*0Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_name)); 1889*0Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_MEM) { 1890*0Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_unit == -1) 1891*0Sstevel@tonic-gate cmdp->cmd_cm.c_id.c_unit = 0; 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate } 1894*0Sstevel@tonic-gate devset = shp->sh_orig_devset = shp->sh_devset = 1895*0Sstevel@tonic-gate sbd_dev2devset(&cmdp->cmd_cm.c_id); 1896*0Sstevel@tonic-gate if (devset == 0) { 1897*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, EINVAL); 1898*0Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 1899*0Sstevel@tonic-gate hp->h_iap = NULL; 1900*0Sstevel@tonic-gate return (-1); 1901*0Sstevel@tonic-gate } 1902*0Sstevel@tonic-gate } 1903*0Sstevel@tonic-gate 1904*0Sstevel@tonic-gate /* 1905*0Sstevel@tonic-gate * Always turn on these bits ala Sunfire DR. 1906*0Sstevel@tonic-gate */ 1907*0Sstevel@tonic-gate hp->h_flags |= SBD_FLAG_DEVI_FORCE; 1908*0Sstevel@tonic-gate 1909*0Sstevel@tonic-gate if (cmdp->cmd_cm.c_flags & SBD_FLAG_FORCE) 1910*0Sstevel@tonic-gate hp->h_flags |= SBD_IOCTL_FLAG_FORCE; 1911*0Sstevel@tonic-gate 1912*0Sstevel@tonic-gate /* 1913*0Sstevel@tonic-gate * Check for valid state transitions. 1914*0Sstevel@tonic-gate */ 1915*0Sstevel@tonic-gate if (!serr && ((t = CMD2INDEX(cmd)) != -1)) { 1916*0Sstevel@tonic-gate struct sbd_state_trans *transp; 1917*0Sstevel@tonic-gate int state_err; 1918*0Sstevel@tonic-gate 1919*0Sstevel@tonic-gate transp = &sbd_state_transition[t]; 1920*0Sstevel@tonic-gate ASSERT(transp->x_cmd == cmd); 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate state_err = sbd_check_transition(sbp, &devset, transp); 1923*0Sstevel@tonic-gate 1924*0Sstevel@tonic-gate if (state_err < 0) { 1925*0Sstevel@tonic-gate /* 1926*0Sstevel@tonic-gate * Invalidate device. 1927*0Sstevel@tonic-gate */ 1928*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, ENOTTY); 1929*0Sstevel@tonic-gate serr = -1; 1930*0Sstevel@tonic-gate PR_ALL("%s: invalid devset (0x%x)\n", 1931*0Sstevel@tonic-gate f, (uint_t)devset); 1932*0Sstevel@tonic-gate } else if (state_err != 0) { 1933*0Sstevel@tonic-gate /* 1934*0Sstevel@tonic-gate * State transition is not a valid one. 1935*0Sstevel@tonic-gate */ 1936*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, transp->x_op[state_err].x_err); 1937*0Sstevel@tonic-gate serr = transp->x_op[state_err].x_rv; 1938*0Sstevel@tonic-gate PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n", 1939*0Sstevel@tonic-gate f, sbd_state_str[state_err], state_err, 1940*0Sstevel@tonic-gate SBD_CMD_STR(cmd), cmd); 1941*0Sstevel@tonic-gate } 1942*0Sstevel@tonic-gate if (serr && SBD_GET_ERRNO(ep) != 0) { 1943*0Sstevel@tonic-gate /* 1944*0Sstevel@tonic-gate * A state transition error occurred. 1945*0Sstevel@tonic-gate */ 1946*0Sstevel@tonic-gate if (serr < 0) { 1947*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_INVAL); 1948*0Sstevel@tonic-gate } else { 1949*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_STATE); 1950*0Sstevel@tonic-gate } 1951*0Sstevel@tonic-gate PR_ALL("%s: invalid state transition\n", f); 1952*0Sstevel@tonic-gate } else { 1953*0Sstevel@tonic-gate shp->sh_devset = devset; 1954*0Sstevel@tonic-gate } 1955*0Sstevel@tonic-gate } 1956*0Sstevel@tonic-gate 1957*0Sstevel@tonic-gate if (serr && !rv && hp->h_iap) { 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate /* 1960*0Sstevel@tonic-gate * There was a state error. We successfully copied 1961*0Sstevel@tonic-gate * in the ioctl argument, so let's fill in the 1962*0Sstevel@tonic-gate * error and copy it back out. 1963*0Sstevel@tonic-gate */ 1964*0Sstevel@tonic-gate 1965*0Sstevel@tonic-gate if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) 1966*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, EIO); 1967*0Sstevel@tonic-gate 1968*0Sstevel@tonic-gate SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, 1969*0Sstevel@tonic-gate ep->e_code, 1970*0Sstevel@tonic-gate ep->e_rsc); 1971*0Sstevel@tonic-gate (void) sbd_copyout_errs(hp->h_mode, hp->h_iap, shp->sh_arg); 1972*0Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 1973*0Sstevel@tonic-gate hp->h_iap = NULL; 1974*0Sstevel@tonic-gate rv = -1; 1975*0Sstevel@tonic-gate } 1976*0Sstevel@tonic-gate 1977*0Sstevel@tonic-gate return (rv); 1978*0Sstevel@tonic-gate } 1979*0Sstevel@tonic-gate 1980*0Sstevel@tonic-gate static void 1981*0Sstevel@tonic-gate sbd_post_op(sbd_handle_t *hp) 1982*0Sstevel@tonic-gate { 1983*0Sstevel@tonic-gate int cmd; 1984*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 1985*0Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 1986*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 1987*0Sstevel@tonic-gate 1988*0Sstevel@tonic-gate cmd = hp->h_cmd; 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate switch (cmd) { 1991*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 1992*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 1993*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 1994*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 1995*0Sstevel@tonic-gate sbp->sb_time = gethrestime_sec(); 1996*0Sstevel@tonic-gate break; 1997*0Sstevel@tonic-gate 1998*0Sstevel@tonic-gate default: 1999*0Sstevel@tonic-gate break; 2000*0Sstevel@tonic-gate } 2001*0Sstevel@tonic-gate 2002*0Sstevel@tonic-gate if (SBD_GET_ERR(ep) && SBD_GET_ERRNO(ep) == 0) { 2003*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, EIO); 2004*0Sstevel@tonic-gate } 2005*0Sstevel@tonic-gate 2006*0Sstevel@tonic-gate if (shp->sh_arg != NULL) { 2007*0Sstevel@tonic-gate 2008*0Sstevel@tonic-gate if (SBD_GET_ERR(ep) != ESBD_NOERROR) { 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate SBD_SET_IOCTL_ERR(&hp->h_iap->i_err, 2011*0Sstevel@tonic-gate ep->e_code, 2012*0Sstevel@tonic-gate ep->e_rsc); 2013*0Sstevel@tonic-gate 2014*0Sstevel@tonic-gate (void) sbd_copyout_errs(hp->h_mode, hp->h_iap, 2015*0Sstevel@tonic-gate shp->sh_arg); 2016*0Sstevel@tonic-gate } 2017*0Sstevel@tonic-gate 2018*0Sstevel@tonic-gate if (hp->h_iap != NULL) { 2019*0Sstevel@tonic-gate FREESTRUCT(hp->h_iap, sbd_ioctl_arg_t, 1); 2020*0Sstevel@tonic-gate hp->h_iap = NULL; 2021*0Sstevel@tonic-gate } 2022*0Sstevel@tonic-gate } 2023*0Sstevel@tonic-gate } 2024*0Sstevel@tonic-gate 2025*0Sstevel@tonic-gate static int 2026*0Sstevel@tonic-gate sbd_probe_board(sbd_handle_t *hp) 2027*0Sstevel@tonic-gate { 2028*0Sstevel@tonic-gate int rv; 2029*0Sstevel@tonic-gate sbd_board_t *sbp; 2030*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2031*0Sstevel@tonic-gate static fn_t f = "sbd_probe_board"; 2032*0Sstevel@tonic-gate 2033*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2034*0Sstevel@tonic-gate 2035*0Sstevel@tonic-gate ASSERT(sbp != NULL); 2036*0Sstevel@tonic-gate PR_ALL("%s for board %d", f, sbp->sb_num); 2037*0Sstevel@tonic-gate 2038*0Sstevel@tonic-gate 2039*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2040*0Sstevel@tonic-gate 2041*0Sstevel@tonic-gate if ((rv = sbdp_connect_board(hdp)) != 0) { 2042*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2043*0Sstevel@tonic-gate 2044*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2045*0Sstevel@tonic-gate } 2046*0Sstevel@tonic-gate 2047*0Sstevel@tonic-gate /* 2048*0Sstevel@tonic-gate * We need to force a recache after the connect. The cached 2049*0Sstevel@tonic-gate * info may be incorrect 2050*0Sstevel@tonic-gate */ 2051*0Sstevel@tonic-gate mutex_enter(&sbp->sb_flags_mutex); 2052*0Sstevel@tonic-gate sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 2053*0Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 2054*0Sstevel@tonic-gate 2055*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_PROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2056*0Sstevel@tonic-gate ESGT_PROBE, NULL); 2057*0Sstevel@tonic-gate 2058*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate return (rv); 2061*0Sstevel@tonic-gate } 2062*0Sstevel@tonic-gate 2063*0Sstevel@tonic-gate static int 2064*0Sstevel@tonic-gate sbd_deprobe_board(sbd_handle_t *hp) 2065*0Sstevel@tonic-gate { 2066*0Sstevel@tonic-gate int rv; 2067*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2068*0Sstevel@tonic-gate sbd_board_t *sbp; 2069*0Sstevel@tonic-gate static fn_t f = "sbd_deprobe_board"; 2070*0Sstevel@tonic-gate 2071*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 2072*0Sstevel@tonic-gate 2073*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2074*0Sstevel@tonic-gate 2075*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2076*0Sstevel@tonic-gate 2077*0Sstevel@tonic-gate if ((rv = sbdp_disconnect_board(hdp)) != 0) { 2078*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2079*0Sstevel@tonic-gate 2080*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2081*0Sstevel@tonic-gate } 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate mutex_enter(&sbp->sb_flags_mutex); 2084*0Sstevel@tonic-gate sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 2085*0Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 2086*0Sstevel@tonic-gate 2087*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_DEPROBE_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2088*0Sstevel@tonic-gate ESGT_DEPROBE, NULL); 2089*0Sstevel@tonic-gate 2090*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2091*0Sstevel@tonic-gate return (rv); 2092*0Sstevel@tonic-gate } 2093*0Sstevel@tonic-gate 2094*0Sstevel@tonic-gate /* 2095*0Sstevel@tonic-gate * Check if a CPU node is part of a CMP. 2096*0Sstevel@tonic-gate */ 2097*0Sstevel@tonic-gate int 2098*0Sstevel@tonic-gate sbd_is_cmp_child(dev_info_t *dip) 2099*0Sstevel@tonic-gate { 2100*0Sstevel@tonic-gate dev_info_t *pdip; 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate if (strcmp(ddi_node_name(dip), "cpu") != 0) { 2103*0Sstevel@tonic-gate return (0); 2104*0Sstevel@tonic-gate } 2105*0Sstevel@tonic-gate 2106*0Sstevel@tonic-gate pdip = ddi_get_parent(dip); 2107*0Sstevel@tonic-gate 2108*0Sstevel@tonic-gate ASSERT(pdip); 2109*0Sstevel@tonic-gate 2110*0Sstevel@tonic-gate if (strcmp(ddi_node_name(pdip), "cmp") == 0) { 2111*0Sstevel@tonic-gate return (1); 2112*0Sstevel@tonic-gate } 2113*0Sstevel@tonic-gate 2114*0Sstevel@tonic-gate return (0); 2115*0Sstevel@tonic-gate } 2116*0Sstevel@tonic-gate 2117*0Sstevel@tonic-gate /* 2118*0Sstevel@tonic-gate * Returns the nodetype if dip is a top dip on the board of 2119*0Sstevel@tonic-gate * interest or SBD_COMP_UNKNOWN otherwise 2120*0Sstevel@tonic-gate */ 2121*0Sstevel@tonic-gate static sbd_comp_type_t 2122*0Sstevel@tonic-gate get_node_type(sbd_board_t *sbp, dev_info_t *dip, int *unitp) 2123*0Sstevel@tonic-gate { 2124*0Sstevel@tonic-gate int idx, unit; 2125*0Sstevel@tonic-gate sbd_handle_t *hp; 2126*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2127*0Sstevel@tonic-gate char otype[OBP_MAXDRVNAME]; 2128*0Sstevel@tonic-gate int otypelen; 2129*0Sstevel@tonic-gate 2130*0Sstevel@tonic-gate ASSERT(sbp); 2131*0Sstevel@tonic-gate 2132*0Sstevel@tonic-gate if (unitp) 2133*0Sstevel@tonic-gate *unitp = -1; 2134*0Sstevel@tonic-gate 2135*0Sstevel@tonic-gate hp = MACHBD2HD(sbp); 2136*0Sstevel@tonic-gate 2137*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2138*0Sstevel@tonic-gate if (sbdp_get_board_num(hdp, dip) != sbp->sb_num) { 2139*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2140*0Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 2141*0Sstevel@tonic-gate } 2142*0Sstevel@tonic-gate 2143*0Sstevel@tonic-gate /* 2144*0Sstevel@tonic-gate * sbdp_get_unit_num will return (-1) for cmp as there 2145*0Sstevel@tonic-gate * is no "device_type" property associated with cmp. 2146*0Sstevel@tonic-gate * Therefore we will just skip getting unit number for 2147*0Sstevel@tonic-gate * cmp. Callers of this function need to check the 2148*0Sstevel@tonic-gate * value set in unitp before using it to dereference 2149*0Sstevel@tonic-gate * an array. 2150*0Sstevel@tonic-gate */ 2151*0Sstevel@tonic-gate if (strcmp(ddi_node_name(dip), "cmp") == 0) { 2152*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2153*0Sstevel@tonic-gate return (SBD_COMP_CMP); 2154*0Sstevel@tonic-gate } 2155*0Sstevel@tonic-gate 2156*0Sstevel@tonic-gate otypelen = sizeof (otype); 2157*0Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 2158*0Sstevel@tonic-gate OBP_DEVICETYPE, (caddr_t)otype, &otypelen)) { 2159*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2160*0Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 2161*0Sstevel@tonic-gate } 2162*0Sstevel@tonic-gate 2163*0Sstevel@tonic-gate idx = sbd_otype_to_idx(otype); 2164*0Sstevel@tonic-gate 2165*0Sstevel@tonic-gate if (SBD_COMP(idx) == SBD_COMP_UNKNOWN) { 2166*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2167*0Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 2168*0Sstevel@tonic-gate } 2169*0Sstevel@tonic-gate 2170*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 2171*0Sstevel@tonic-gate if (unit == -1) { 2172*0Sstevel@tonic-gate cmn_err(CE_WARN, 2173*0Sstevel@tonic-gate "get_node_type: %s unit fail %p", otype, (void *)dip); 2174*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2175*0Sstevel@tonic-gate return (SBD_COMP_UNKNOWN); 2176*0Sstevel@tonic-gate } 2177*0Sstevel@tonic-gate 2178*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2179*0Sstevel@tonic-gate 2180*0Sstevel@tonic-gate if (unitp) 2181*0Sstevel@tonic-gate *unitp = unit; 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate return (SBD_COMP(idx)); 2184*0Sstevel@tonic-gate } 2185*0Sstevel@tonic-gate 2186*0Sstevel@tonic-gate typedef struct { 2187*0Sstevel@tonic-gate sbd_board_t *sbp; 2188*0Sstevel@tonic-gate int nmc; 2189*0Sstevel@tonic-gate int hold; 2190*0Sstevel@tonic-gate } walk_tree_t; 2191*0Sstevel@tonic-gate 2192*0Sstevel@tonic-gate static int 2193*0Sstevel@tonic-gate sbd_setup_devlists(dev_info_t *dip, void *arg) 2194*0Sstevel@tonic-gate { 2195*0Sstevel@tonic-gate walk_tree_t *wp; 2196*0Sstevel@tonic-gate dev_info_t **devlist = NULL; 2197*0Sstevel@tonic-gate char *pathname = NULL; 2198*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 2199*0Sstevel@tonic-gate static fn_t f = "sbd_setup_devlists"; 2200*0Sstevel@tonic-gate sbd_board_t *sbp; 2201*0Sstevel@tonic-gate int unit; 2202*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 2203*0Sstevel@tonic-gate 2204*0Sstevel@tonic-gate ASSERT(dip); 2205*0Sstevel@tonic-gate 2206*0Sstevel@tonic-gate wp = (walk_tree_t *)arg; 2207*0Sstevel@tonic-gate 2208*0Sstevel@tonic-gate if (wp == NULL) { 2209*0Sstevel@tonic-gate PR_ALL("%s:bad arg\n", f); 2210*0Sstevel@tonic-gate return (DDI_WALK_TERMINATE); 2211*0Sstevel@tonic-gate } 2212*0Sstevel@tonic-gate 2213*0Sstevel@tonic-gate sbp = wp->sbp; 2214*0Sstevel@tonic-gate 2215*0Sstevel@tonic-gate nodetype = get_node_type(sbp, dip, &unit); 2216*0Sstevel@tonic-gate 2217*0Sstevel@tonic-gate switch (nodetype) { 2218*0Sstevel@tonic-gate 2219*0Sstevel@tonic-gate case SBD_COMP_CPU: 2220*0Sstevel@tonic-gate pathname = sbp->sb_cpupath[unit]; 2221*0Sstevel@tonic-gate break; 2222*0Sstevel@tonic-gate 2223*0Sstevel@tonic-gate case SBD_COMP_MEM: 2224*0Sstevel@tonic-gate pathname = sbp->sb_mempath[unit]; 2225*0Sstevel@tonic-gate break; 2226*0Sstevel@tonic-gate 2227*0Sstevel@tonic-gate case SBD_COMP_IO: 2228*0Sstevel@tonic-gate pathname = sbp->sb_iopath[unit]; 2229*0Sstevel@tonic-gate break; 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate case SBD_COMP_CMP: 2232*0Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 2233*0Sstevel@tonic-gate /* 2234*0Sstevel@tonic-gate * This dip is not of interest to us 2235*0Sstevel@tonic-gate */ 2236*0Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2237*0Sstevel@tonic-gate 2238*0Sstevel@tonic-gate default: 2239*0Sstevel@tonic-gate ASSERT(0); 2240*0Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2241*0Sstevel@tonic-gate } 2242*0Sstevel@tonic-gate 2243*0Sstevel@tonic-gate /* 2244*0Sstevel@tonic-gate * dip's parent is being held busy by ddi_walk_devs(), 2245*0Sstevel@tonic-gate * so dip doesn't have to be held while calling ddi_pathname() 2246*0Sstevel@tonic-gate */ 2247*0Sstevel@tonic-gate if (pathname) { 2248*0Sstevel@tonic-gate (void) ddi_pathname(dip, pathname); 2249*0Sstevel@tonic-gate } 2250*0Sstevel@tonic-gate 2251*0Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(nodetype)]; 2252*0Sstevel@tonic-gate 2253*0Sstevel@tonic-gate /* 2254*0Sstevel@tonic-gate * The branch rooted at dip should already be held, 2255*0Sstevel@tonic-gate * unless we are dealing with a core of a CMP. 2256*0Sstevel@tonic-gate */ 2257*0Sstevel@tonic-gate ASSERT(sbd_is_cmp_child(dip) || e_ddi_branch_held(dip)); 2258*0Sstevel@tonic-gate devlist[unit] = dip; 2259*0Sstevel@tonic-gate 2260*0Sstevel@tonic-gate /* 2261*0Sstevel@tonic-gate * This test is required if multiple devices are considered 2262*0Sstevel@tonic-gate * as one. This is the case for memory-controller nodes. 2263*0Sstevel@tonic-gate */ 2264*0Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, nodetype, unit)) { 2265*0Sstevel@tonic-gate sbp->sb_ndev++; 2266*0Sstevel@tonic-gate SBD_DEV_SET_PRESENT(sbp, nodetype, unit); 2267*0Sstevel@tonic-gate } 2268*0Sstevel@tonic-gate 2269*0Sstevel@tonic-gate if (nodetype == SBD_COMP_MEM) { 2270*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 2271*0Sstevel@tonic-gate ASSERT(wp->nmc < SBD_NUM_MC_PER_BOARD); 2272*0Sstevel@tonic-gate mp->sbm_dip[wp->nmc++] = dip; 2273*0Sstevel@tonic-gate } 2274*0Sstevel@tonic-gate 2275*0Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 2276*0Sstevel@tonic-gate } 2277*0Sstevel@tonic-gate 2278*0Sstevel@tonic-gate /* 2279*0Sstevel@tonic-gate * This routine is used to construct the memory devlist. 2280*0Sstevel@tonic-gate * In Starcat and Serengeti platforms, a system board can contain up to 2281*0Sstevel@tonic-gate * four memory controllers (MC). The MCs have been programmed by POST for 2282*0Sstevel@tonic-gate * optimum memory interleaving amongst their peers on the same board. 2283*0Sstevel@tonic-gate * This DR driver does not support deinterleaving. Therefore, the smallest 2284*0Sstevel@tonic-gate * unit of memory that can be manipulated by this driver is all of the 2285*0Sstevel@tonic-gate * memory on a board. Because of this restriction, a board's memory devlist 2286*0Sstevel@tonic-gate * is populated with only one of the four (possible) MC dnodes on that board. 2287*0Sstevel@tonic-gate * Care must be taken to ensure that the selected MC dnode represents the 2288*0Sstevel@tonic-gate * lowest physical address to which memory on the board will respond to. 2289*0Sstevel@tonic-gate * This is required in order to preserve the semantics of 2290*0Sstevel@tonic-gate * sbdp_get_base_physaddr() when applied to a MC dnode stored in the 2291*0Sstevel@tonic-gate * memory devlist. 2292*0Sstevel@tonic-gate */ 2293*0Sstevel@tonic-gate static void 2294*0Sstevel@tonic-gate sbd_init_mem_devlists(sbd_board_t *sbp) 2295*0Sstevel@tonic-gate { 2296*0Sstevel@tonic-gate dev_info_t **devlist; 2297*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 2298*0Sstevel@tonic-gate dev_info_t *mc_dip; 2299*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2300*0Sstevel@tonic-gate uint64_t mc_pa, lowest_pa; 2301*0Sstevel@tonic-gate int i; 2302*0Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 2303*0Sstevel@tonic-gate 2304*0Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(SBD_COMP_MEM)]; 2305*0Sstevel@tonic-gate 2306*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, 0); 2307*0Sstevel@tonic-gate 2308*0Sstevel@tonic-gate mc_dip = mp->sbm_dip[0]; 2309*0Sstevel@tonic-gate if (mc_dip == NULL) 2310*0Sstevel@tonic-gate return; /* No MC dips found for this board */ 2311*0Sstevel@tonic-gate 2312*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2313*0Sstevel@tonic-gate 2314*0Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) { 2315*0Sstevel@tonic-gate /* TODO: log complaint about dnode */ 2316*0Sstevel@tonic-gate 2317*0Sstevel@tonic-gate pretend_no_mem: 2318*0Sstevel@tonic-gate /* 2319*0Sstevel@tonic-gate * We are here because sbdphw_get_base_physaddr() failed. 2320*0Sstevel@tonic-gate * Although it is very unlikely to happen, it did. Lucky us. 2321*0Sstevel@tonic-gate * Since we can no longer examine _all_ of the MCs on this 2322*0Sstevel@tonic-gate * board to determine which one is programmed to the lowest 2323*0Sstevel@tonic-gate * physical address, we cannot involve any of the MCs on 2324*0Sstevel@tonic-gate * this board in DR operations. To ensure this, we pretend 2325*0Sstevel@tonic-gate * that this board does not contain any memory. 2326*0Sstevel@tonic-gate * 2327*0Sstevel@tonic-gate * Paranoia: clear the dev_present mask. 2328*0Sstevel@tonic-gate */ 2329*0Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, 0)) { 2330*0Sstevel@tonic-gate ASSERT(sbp->sb_ndev != 0); 2331*0Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, 0); 2332*0Sstevel@tonic-gate sbp->sb_ndev--; 2333*0Sstevel@tonic-gate } 2334*0Sstevel@tonic-gate 2335*0Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 2336*0Sstevel@tonic-gate mp->sbm_dip[i] = NULL; 2337*0Sstevel@tonic-gate } 2338*0Sstevel@tonic-gate 2339*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2340*0Sstevel@tonic-gate return; 2341*0Sstevel@tonic-gate } 2342*0Sstevel@tonic-gate 2343*0Sstevel@tonic-gate /* assume this one will win. */ 2344*0Sstevel@tonic-gate devlist[0] = mc_dip; 2345*0Sstevel@tonic-gate mp->sbm_cm.sbdev_dip = mc_dip; 2346*0Sstevel@tonic-gate lowest_pa = mc_pa; 2347*0Sstevel@tonic-gate 2348*0Sstevel@tonic-gate /* 2349*0Sstevel@tonic-gate * We know the base physical address of one of the MC devices. Now 2350*0Sstevel@tonic-gate * we will enumerate through all of the remaining MC devices on 2351*0Sstevel@tonic-gate * the board to find which of them is programmed to the lowest 2352*0Sstevel@tonic-gate * physical address. 2353*0Sstevel@tonic-gate */ 2354*0Sstevel@tonic-gate for (i = 1; i < SBD_NUM_MC_PER_BOARD; i++) { 2355*0Sstevel@tonic-gate mc_dip = mp->sbm_dip[i]; 2356*0Sstevel@tonic-gate if (mc_dip == NULL) { 2357*0Sstevel@tonic-gate break; 2358*0Sstevel@tonic-gate } 2359*0Sstevel@tonic-gate 2360*0Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, mc_dip, &mc_pa)) { 2361*0Sstevel@tonic-gate cmn_err(CE_NOTE, "No mem on board %d unit %d", 2362*0Sstevel@tonic-gate sbp->sb_num, i); 2363*0Sstevel@tonic-gate break; 2364*0Sstevel@tonic-gate } 2365*0Sstevel@tonic-gate if (mc_pa < lowest_pa) { 2366*0Sstevel@tonic-gate mp->sbm_cm.sbdev_dip = mc_dip; 2367*0Sstevel@tonic-gate devlist[0] = mc_dip; 2368*0Sstevel@tonic-gate lowest_pa = mc_pa; 2369*0Sstevel@tonic-gate } 2370*0Sstevel@tonic-gate } 2371*0Sstevel@tonic-gate 2372*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2373*0Sstevel@tonic-gate } 2374*0Sstevel@tonic-gate 2375*0Sstevel@tonic-gate static int 2376*0Sstevel@tonic-gate sbd_name_to_idx(char *name) 2377*0Sstevel@tonic-gate { 2378*0Sstevel@tonic-gate int idx; 2379*0Sstevel@tonic-gate 2380*0Sstevel@tonic-gate for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) { 2381*0Sstevel@tonic-gate if (strcmp(name, SBD_DEVNAME(idx)) == 0) { 2382*0Sstevel@tonic-gate break; 2383*0Sstevel@tonic-gate } 2384*0Sstevel@tonic-gate } 2385*0Sstevel@tonic-gate 2386*0Sstevel@tonic-gate return (idx); 2387*0Sstevel@tonic-gate } 2388*0Sstevel@tonic-gate 2389*0Sstevel@tonic-gate static int 2390*0Sstevel@tonic-gate sbd_otype_to_idx(char *otype) 2391*0Sstevel@tonic-gate { 2392*0Sstevel@tonic-gate int idx; 2393*0Sstevel@tonic-gate 2394*0Sstevel@tonic-gate for (idx = 0; SBD_COMP(idx) != SBD_COMP_UNKNOWN; idx++) { 2395*0Sstevel@tonic-gate 2396*0Sstevel@tonic-gate if (strcmp(otype, SBD_OTYPE(idx)) == 0) { 2397*0Sstevel@tonic-gate break; 2398*0Sstevel@tonic-gate } 2399*0Sstevel@tonic-gate } 2400*0Sstevel@tonic-gate 2401*0Sstevel@tonic-gate return (idx); 2402*0Sstevel@tonic-gate } 2403*0Sstevel@tonic-gate 2404*0Sstevel@tonic-gate static int 2405*0Sstevel@tonic-gate sbd_init_devlists(sbd_board_t *sbp) 2406*0Sstevel@tonic-gate { 2407*0Sstevel@tonic-gate int i; 2408*0Sstevel@tonic-gate sbd_dev_unit_t *dp; 2409*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 2410*0Sstevel@tonic-gate walk_tree_t *wp, walk = {0}; 2411*0Sstevel@tonic-gate dev_info_t *pdip; 2412*0Sstevel@tonic-gate static fn_t f = "sbd_init_devlists"; 2413*0Sstevel@tonic-gate 2414*0Sstevel@tonic-gate PR_ALL("%s (board = %d)...\n", f, sbp->sb_num); 2415*0Sstevel@tonic-gate 2416*0Sstevel@tonic-gate wp = &walk; 2417*0Sstevel@tonic-gate 2418*0Sstevel@tonic-gate SBD_DEVS_DISCONNECT(sbp, (uint_t)-1); 2419*0Sstevel@tonic-gate 2420*0Sstevel@tonic-gate /* 2421*0Sstevel@tonic-gate * Clear out old entries, if any. 2422*0Sstevel@tonic-gate */ 2423*0Sstevel@tonic-gate 2424*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 2425*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL; 2426*0Sstevel@tonic-gate dp = (sbd_dev_unit_t *)SBD_GET_BOARD_MEMUNIT(sbp, i); 2427*0Sstevel@tonic-gate dp->u_common.sbdev_sbp = sbp; 2428*0Sstevel@tonic-gate dp->u_common.sbdev_unum = i; 2429*0Sstevel@tonic-gate dp->u_common.sbdev_type = SBD_COMP_MEM; 2430*0Sstevel@tonic-gate } 2431*0Sstevel@tonic-gate 2432*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, 0); 2433*0Sstevel@tonic-gate ASSERT(mp != NULL); 2434*0Sstevel@tonic-gate for (i = 0; i < SBD_NUM_MC_PER_BOARD; i++) { 2435*0Sstevel@tonic-gate mp->sbm_dip[i] = NULL; 2436*0Sstevel@tonic-gate } 2437*0Sstevel@tonic-gate 2438*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2439*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_CPU)][i] = NULL; 2440*0Sstevel@tonic-gate dp = (sbd_dev_unit_t *)SBD_GET_BOARD_CPUUNIT(sbp, i); 2441*0Sstevel@tonic-gate dp->u_common.sbdev_sbp = sbp; 2442*0Sstevel@tonic-gate dp->u_common.sbdev_unum = i; 2443*0Sstevel@tonic-gate dp->u_common.sbdev_type = SBD_COMP_CPU; 2444*0Sstevel@tonic-gate } 2445*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 2446*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_IO)][i] = NULL; 2447*0Sstevel@tonic-gate dp = (sbd_dev_unit_t *)SBD_GET_BOARD_IOUNIT(sbp, i); 2448*0Sstevel@tonic-gate dp->u_common.sbdev_sbp = sbp; 2449*0Sstevel@tonic-gate dp->u_common.sbdev_unum = i; 2450*0Sstevel@tonic-gate dp->u_common.sbdev_type = SBD_COMP_IO; 2451*0Sstevel@tonic-gate } 2452*0Sstevel@tonic-gate 2453*0Sstevel@tonic-gate wp->sbp = sbp; 2454*0Sstevel@tonic-gate wp->nmc = 0; 2455*0Sstevel@tonic-gate sbp->sb_ndev = 0; 2456*0Sstevel@tonic-gate 2457*0Sstevel@tonic-gate /* 2458*0Sstevel@tonic-gate * ddi_walk_devs() requires that topdip's parent be held. 2459*0Sstevel@tonic-gate */ 2460*0Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 2461*0Sstevel@tonic-gate if (pdip) { 2462*0Sstevel@tonic-gate ndi_hold_devi(pdip); 2463*0Sstevel@tonic-gate ndi_devi_enter(pdip, &i); 2464*0Sstevel@tonic-gate } 2465*0Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, sbd_setup_devlists, (void *) wp); 2466*0Sstevel@tonic-gate if (pdip) { 2467*0Sstevel@tonic-gate ndi_devi_exit(pdip, i); 2468*0Sstevel@tonic-gate ndi_rele_devi(pdip); 2469*0Sstevel@tonic-gate } 2470*0Sstevel@tonic-gate 2471*0Sstevel@tonic-gate /* 2472*0Sstevel@tonic-gate * There is no point checking all the components if there 2473*0Sstevel@tonic-gate * are no devices. 2474*0Sstevel@tonic-gate */ 2475*0Sstevel@tonic-gate if (sbp->sb_ndev == 0) { 2476*0Sstevel@tonic-gate sbp->sb_memaccess_ok = 0; 2477*0Sstevel@tonic-gate return (sbp->sb_ndev); 2478*0Sstevel@tonic-gate } 2479*0Sstevel@tonic-gate 2480*0Sstevel@tonic-gate /* 2481*0Sstevel@tonic-gate * Initialize cpu sections before calling sbd_init_mem_devlists 2482*0Sstevel@tonic-gate * which will access the mmus. 2483*0Sstevel@tonic-gate */ 2484*0Sstevel@tonic-gate sbp->sb_memaccess_ok = 1; 2485*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2486*0Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) { 2487*0Sstevel@tonic-gate sbd_init_cpu_unit(sbp, i); 2488*0Sstevel@tonic-gate if (sbd_connect_cpu(sbp, i)) { 2489*0Sstevel@tonic-gate SBD_SET_ERR(HD2MACHERR(MACHBD2HD(sbp)), 2490*0Sstevel@tonic-gate ESBD_CPUSTART); 2491*0Sstevel@tonic-gate } 2492*0Sstevel@tonic-gate 2493*0Sstevel@tonic-gate } 2494*0Sstevel@tonic-gate } 2495*0Sstevel@tonic-gate 2496*0Sstevel@tonic-gate if (sbp->sb_memaccess_ok) { 2497*0Sstevel@tonic-gate sbd_init_mem_devlists(sbp); 2498*0Sstevel@tonic-gate } else { 2499*0Sstevel@tonic-gate cmn_err(CE_WARN, "unable to access memory on board %d", 2500*0Sstevel@tonic-gate sbp->sb_num); 2501*0Sstevel@tonic-gate } 2502*0Sstevel@tonic-gate 2503*0Sstevel@tonic-gate return (sbp->sb_ndev); 2504*0Sstevel@tonic-gate } 2505*0Sstevel@tonic-gate 2506*0Sstevel@tonic-gate static void 2507*0Sstevel@tonic-gate sbd_init_cpu_unit(sbd_board_t *sbp, int unit) 2508*0Sstevel@tonic-gate { 2509*0Sstevel@tonic-gate sbd_istate_t new_state; 2510*0Sstevel@tonic-gate sbd_cpu_unit_t *cp; 2511*0Sstevel@tonic-gate int cpuid; 2512*0Sstevel@tonic-gate dev_info_t *dip; 2513*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2514*0Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 2515*0Sstevel@tonic-gate extern kmutex_t cpu_lock; 2516*0Sstevel@tonic-gate 2517*0Sstevel@tonic-gate if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_CPU, unit)) { 2518*0Sstevel@tonic-gate new_state = SBD_STATE_CONFIGURED; 2519*0Sstevel@tonic-gate } else if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, unit)) { 2520*0Sstevel@tonic-gate new_state = SBD_STATE_CONNECTED; 2521*0Sstevel@tonic-gate } else { 2522*0Sstevel@tonic-gate new_state = SBD_STATE_EMPTY; 2523*0Sstevel@tonic-gate } 2524*0Sstevel@tonic-gate 2525*0Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][unit]; 2526*0Sstevel@tonic-gate 2527*0Sstevel@tonic-gate cp = SBD_GET_BOARD_CPUUNIT(sbp, unit); 2528*0Sstevel@tonic-gate 2529*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2530*0Sstevel@tonic-gate 2531*0Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 2532*0Sstevel@tonic-gate 2533*0Sstevel@tonic-gate cp->sbc_cpu_id = cpuid; 2534*0Sstevel@tonic-gate 2535*0Sstevel@tonic-gate if (&sbdp_cpu_get_impl) 2536*0Sstevel@tonic-gate cp->sbc_cpu_impl = sbdp_cpu_get_impl(hdp, dip); 2537*0Sstevel@tonic-gate else 2538*0Sstevel@tonic-gate cp->sbc_cpu_impl = -1; 2539*0Sstevel@tonic-gate 2540*0Sstevel@tonic-gate mutex_enter(&cpu_lock); 2541*0Sstevel@tonic-gate if ((cpuid >= 0) && cpu[cpuid]) 2542*0Sstevel@tonic-gate cp->sbc_cpu_flags = cpu[cpuid]->cpu_flags; 2543*0Sstevel@tonic-gate else 2544*0Sstevel@tonic-gate cp->sbc_cpu_flags = CPU_OFFLINE | CPU_POWEROFF; 2545*0Sstevel@tonic-gate mutex_exit(&cpu_lock); 2546*0Sstevel@tonic-gate 2547*0Sstevel@tonic-gate sbd_cpu_set_prop(cp, dip); 2548*0Sstevel@tonic-gate 2549*0Sstevel@tonic-gate cp->sbc_cm.sbdev_cond = sbd_get_comp_cond(dip); 2550*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2551*0Sstevel@tonic-gate 2552*0Sstevel@tonic-gate /* 2553*0Sstevel@tonic-gate * Any changes to the cpu should be performed above 2554*0Sstevel@tonic-gate * this call to ensure the cpu is fully initialized 2555*0Sstevel@tonic-gate * before transitioning to the new state. 2556*0Sstevel@tonic-gate */ 2557*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, unit, new_state); 2558*0Sstevel@tonic-gate } 2559*0Sstevel@tonic-gate 2560*0Sstevel@tonic-gate /* 2561*0Sstevel@tonic-gate * Only do work if called to operate on an entire board 2562*0Sstevel@tonic-gate * which doesn't already have components present. 2563*0Sstevel@tonic-gate */ 2564*0Sstevel@tonic-gate static void 2565*0Sstevel@tonic-gate sbd_connect(sbd_handle_t *hp) 2566*0Sstevel@tonic-gate { 2567*0Sstevel@tonic-gate sbd_board_t *sbp; 2568*0Sstevel@tonic-gate sbderror_t *ep; 2569*0Sstevel@tonic-gate static fn_t f = "sbd_connect"; 2570*0Sstevel@tonic-gate 2571*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2572*0Sstevel@tonic-gate 2573*0Sstevel@tonic-gate PR_ALL("%s board %d\n", f, sbp->sb_num); 2574*0Sstevel@tonic-gate 2575*0Sstevel@tonic-gate ep = HD2MACHERR(hp); 2576*0Sstevel@tonic-gate 2577*0Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp)) { 2578*0Sstevel@tonic-gate /* 2579*0Sstevel@tonic-gate * Board already has devices present. 2580*0Sstevel@tonic-gate */ 2581*0Sstevel@tonic-gate PR_ALL("%s: devices already present (0x%x)\n", 2582*0Sstevel@tonic-gate f, SBD_DEVS_PRESENT(sbp)); 2583*0Sstevel@tonic-gate SBD_SET_ERRNO(ep, EINVAL); 2584*0Sstevel@tonic-gate return; 2585*0Sstevel@tonic-gate } 2586*0Sstevel@tonic-gate 2587*0Sstevel@tonic-gate if (sbd_init_devlists(sbp) == 0) { 2588*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: no devices present on board %d", 2589*0Sstevel@tonic-gate f, sbp->sb_num); 2590*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_NODEV); 2591*0Sstevel@tonic-gate return; 2592*0Sstevel@tonic-gate } else { 2593*0Sstevel@tonic-gate int i; 2594*0Sstevel@tonic-gate 2595*0Sstevel@tonic-gate /* 2596*0Sstevel@tonic-gate * Initialize mem-unit section of board structure. 2597*0Sstevel@tonic-gate */ 2598*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 2599*0Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) 2600*0Sstevel@tonic-gate sbd_init_mem_unit(sbp, i, SBD_HD2ERR(hp)); 2601*0Sstevel@tonic-gate 2602*0Sstevel@tonic-gate /* 2603*0Sstevel@tonic-gate * Initialize sb_io sections. 2604*0Sstevel@tonic-gate */ 2605*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 2606*0Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i)) 2607*0Sstevel@tonic-gate sbd_init_io_unit(sbp, i); 2608*0Sstevel@tonic-gate 2609*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED); 2610*0Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 2611*0Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 2612*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 2613*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_CONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2614*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2615*0Sstevel@tonic-gate } 2616*0Sstevel@tonic-gate } 2617*0Sstevel@tonic-gate 2618*0Sstevel@tonic-gate static int 2619*0Sstevel@tonic-gate sbd_disconnect(sbd_handle_t *hp) 2620*0Sstevel@tonic-gate { 2621*0Sstevel@tonic-gate int i; 2622*0Sstevel@tonic-gate sbd_devset_t devset; 2623*0Sstevel@tonic-gate sbd_board_t *sbp; 2624*0Sstevel@tonic-gate static fn_t f = "sbd_disconnect it"; 2625*0Sstevel@tonic-gate 2626*0Sstevel@tonic-gate PR_ALL("%s ...\n", f); 2627*0Sstevel@tonic-gate 2628*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2629*0Sstevel@tonic-gate 2630*0Sstevel@tonic-gate /* 2631*0Sstevel@tonic-gate * Only devices which are present, but 2632*0Sstevel@tonic-gate * unattached can be disconnected. 2633*0Sstevel@tonic-gate */ 2634*0Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_PRESENT(sbp) & 2635*0Sstevel@tonic-gate SBD_DEVS_UNATTACHED(sbp); 2636*0Sstevel@tonic-gate 2637*0Sstevel@tonic-gate ASSERT((SBD_DEVS_ATTACHED(sbp) & devset) == 0); 2638*0Sstevel@tonic-gate 2639*0Sstevel@tonic-gate /* 2640*0Sstevel@tonic-gate * Update per-device state transitions. 2641*0Sstevel@tonic-gate */ 2642*0Sstevel@tonic-gate 2643*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) 2644*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) { 2645*0Sstevel@tonic-gate if (sbd_disconnect_mem(hp, i) == 0) { 2646*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 2647*0Sstevel@tonic-gate SBD_STATE_EMPTY); 2648*0Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i); 2649*0Sstevel@tonic-gate } 2650*0Sstevel@tonic-gate } 2651*0Sstevel@tonic-gate 2652*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) 2653*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) { 2654*0Sstevel@tonic-gate if (sbd_disconnect_cpu(hp, i) == 0) { 2655*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 2656*0Sstevel@tonic-gate SBD_STATE_EMPTY); 2657*0Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_CPU, i); 2658*0Sstevel@tonic-gate } 2659*0Sstevel@tonic-gate } 2660*0Sstevel@tonic-gate 2661*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) 2662*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, i)) { 2663*0Sstevel@tonic-gate if (sbd_disconnect_io(hp, i) == 0) { 2664*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i, 2665*0Sstevel@tonic-gate SBD_STATE_EMPTY); 2666*0Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_IO, i); 2667*0Sstevel@tonic-gate } 2668*0Sstevel@tonic-gate } 2669*0Sstevel@tonic-gate 2670*0Sstevel@tonic-gate /* 2671*0Sstevel@tonic-gate * Once all the components on a board have been disconnect 2672*0Sstevel@tonic-gate * the board's state can transition to disconnected and 2673*0Sstevel@tonic-gate * we can allow the deprobe to take place. 2674*0Sstevel@tonic-gate */ 2675*0Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp) == 0) { 2676*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_OCCUPIED); 2677*0Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_DISCONNECTED; 2678*0Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 2679*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 2680*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_DISCONNECT_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2681*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2682*0Sstevel@tonic-gate return (0); 2683*0Sstevel@tonic-gate } else { 2684*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: could not disconnect devices on board %d", 2685*0Sstevel@tonic-gate f, sbp->sb_num); 2686*0Sstevel@tonic-gate return (-1); 2687*0Sstevel@tonic-gate } 2688*0Sstevel@tonic-gate } 2689*0Sstevel@tonic-gate 2690*0Sstevel@tonic-gate static void 2691*0Sstevel@tonic-gate sbd_test_board(sbd_handle_t *hp) 2692*0Sstevel@tonic-gate { 2693*0Sstevel@tonic-gate sbd_board_t *sbp; 2694*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2695*0Sstevel@tonic-gate 2696*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2697*0Sstevel@tonic-gate 2698*0Sstevel@tonic-gate PR_ALL("sbd_test_board: board %d\n", sbp->sb_num); 2699*0Sstevel@tonic-gate 2700*0Sstevel@tonic-gate 2701*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2702*0Sstevel@tonic-gate 2703*0Sstevel@tonic-gate if (sbdp_test_board(hdp, &hp->h_opts) != 0) { 2704*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2705*0Sstevel@tonic-gate 2706*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2707*0Sstevel@tonic-gate } 2708*0Sstevel@tonic-gate 2709*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_TEST_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2710*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2711*0Sstevel@tonic-gate 2712*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2713*0Sstevel@tonic-gate } 2714*0Sstevel@tonic-gate 2715*0Sstevel@tonic-gate static void 2716*0Sstevel@tonic-gate sbd_assign_board(sbd_handle_t *hp) 2717*0Sstevel@tonic-gate { 2718*0Sstevel@tonic-gate sbd_board_t *sbp; 2719*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2720*0Sstevel@tonic-gate 2721*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2722*0Sstevel@tonic-gate 2723*0Sstevel@tonic-gate PR_ALL("sbd_assign_board: board %d\n", sbp->sb_num); 2724*0Sstevel@tonic-gate 2725*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2726*0Sstevel@tonic-gate 2727*0Sstevel@tonic-gate if (sbdp_assign_board(hdp) != 0) { 2728*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2729*0Sstevel@tonic-gate 2730*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2731*0Sstevel@tonic-gate } 2732*0Sstevel@tonic-gate 2733*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2734*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2735*0Sstevel@tonic-gate 2736*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2737*0Sstevel@tonic-gate } 2738*0Sstevel@tonic-gate 2739*0Sstevel@tonic-gate static void 2740*0Sstevel@tonic-gate sbd_unassign_board(sbd_handle_t *hp) 2741*0Sstevel@tonic-gate { 2742*0Sstevel@tonic-gate sbd_board_t *sbp; 2743*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2744*0Sstevel@tonic-gate 2745*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2746*0Sstevel@tonic-gate 2747*0Sstevel@tonic-gate PR_ALL("sbd_unassign_board: board %d\n", sbp->sb_num); 2748*0Sstevel@tonic-gate 2749*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2750*0Sstevel@tonic-gate 2751*0Sstevel@tonic-gate if (sbdp_unassign_board(hdp) != 0) { 2752*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2753*0Sstevel@tonic-gate 2754*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2755*0Sstevel@tonic-gate } 2756*0Sstevel@tonic-gate 2757*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_ASSIGN_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2758*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2759*0Sstevel@tonic-gate 2760*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2761*0Sstevel@tonic-gate } 2762*0Sstevel@tonic-gate 2763*0Sstevel@tonic-gate static void 2764*0Sstevel@tonic-gate sbd_poweron_board(sbd_handle_t *hp) 2765*0Sstevel@tonic-gate { 2766*0Sstevel@tonic-gate sbd_board_t *sbp; 2767*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2768*0Sstevel@tonic-gate 2769*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2770*0Sstevel@tonic-gate 2771*0Sstevel@tonic-gate PR_ALL("sbd_poweron_board: %d\n", sbp->sb_num); 2772*0Sstevel@tonic-gate 2773*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2774*0Sstevel@tonic-gate 2775*0Sstevel@tonic-gate if (sbdp_poweron_board(hdp) != 0) { 2776*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2777*0Sstevel@tonic-gate 2778*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2779*0Sstevel@tonic-gate } 2780*0Sstevel@tonic-gate 2781*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_POWERON_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2782*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2783*0Sstevel@tonic-gate 2784*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2785*0Sstevel@tonic-gate } 2786*0Sstevel@tonic-gate 2787*0Sstevel@tonic-gate static void 2788*0Sstevel@tonic-gate sbd_poweroff_board(sbd_handle_t *hp) 2789*0Sstevel@tonic-gate { 2790*0Sstevel@tonic-gate sbd_board_t *sbp; 2791*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2792*0Sstevel@tonic-gate 2793*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2794*0Sstevel@tonic-gate 2795*0Sstevel@tonic-gate PR_ALL("sbd_poweroff_board: %d\n", sbp->sb_num); 2796*0Sstevel@tonic-gate 2797*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2798*0Sstevel@tonic-gate 2799*0Sstevel@tonic-gate if (sbdp_poweroff_board(hdp) != 0) { 2800*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2801*0Sstevel@tonic-gate 2802*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2803*0Sstevel@tonic-gate } 2804*0Sstevel@tonic-gate 2805*0Sstevel@tonic-gate SBD_INJECT_ERR(SBD_POWEROFF_BOARD_PSEUDO_ERR, hp->h_err, EIO, 2806*0Sstevel@tonic-gate ESBD_INTERNAL, NULL); 2807*0Sstevel@tonic-gate 2808*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2809*0Sstevel@tonic-gate } 2810*0Sstevel@tonic-gate 2811*0Sstevel@tonic-gate 2812*0Sstevel@tonic-gate /* 2813*0Sstevel@tonic-gate * Return a list of the dip's of devices that are 2814*0Sstevel@tonic-gate * either present and attached, or present only but 2815*0Sstevel@tonic-gate * not yet attached for the given board. 2816*0Sstevel@tonic-gate */ 2817*0Sstevel@tonic-gate sbd_devlist_t * 2818*0Sstevel@tonic-gate sbd_get_devlist(sbd_handle_t *hp, sbd_board_t *sbp, sbd_comp_type_t nodetype, 2819*0Sstevel@tonic-gate int max_units, uint_t uset, int *count, int present_only) 2820*0Sstevel@tonic-gate { 2821*0Sstevel@tonic-gate int i, ix; 2822*0Sstevel@tonic-gate sbd_devlist_t *ret_devlist; 2823*0Sstevel@tonic-gate dev_info_t **devlist; 2824*0Sstevel@tonic-gate sbdp_handle_t *hdp; 2825*0Sstevel@tonic-gate 2826*0Sstevel@tonic-gate *count = 0; 2827*0Sstevel@tonic-gate ret_devlist = GETSTRUCT(sbd_devlist_t, max_units); 2828*0Sstevel@tonic-gate devlist = sbp->sb_devlist[NIX(nodetype)]; 2829*0Sstevel@tonic-gate /* 2830*0Sstevel@tonic-gate * Turn into binary value since we're going 2831*0Sstevel@tonic-gate * to be using XOR for a comparison. 2832*0Sstevel@tonic-gate * if (present_only) then 2833*0Sstevel@tonic-gate * dev must be PRESENT, but NOT ATTACHED. 2834*0Sstevel@tonic-gate * else 2835*0Sstevel@tonic-gate * dev must be PRESENT AND ATTACHED. 2836*0Sstevel@tonic-gate * endif 2837*0Sstevel@tonic-gate */ 2838*0Sstevel@tonic-gate if (present_only) 2839*0Sstevel@tonic-gate present_only = 1; 2840*0Sstevel@tonic-gate 2841*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 2842*0Sstevel@tonic-gate 2843*0Sstevel@tonic-gate for (i = ix = 0; (i < max_units) && uset; i++) { 2844*0Sstevel@tonic-gate int ut, is_present, is_attached; 2845*0Sstevel@tonic-gate dev_info_t *dip; 2846*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 2847*0Sstevel@tonic-gate int nunits, distance, j; 2848*0Sstevel@tonic-gate 2849*0Sstevel@tonic-gate /* 2850*0Sstevel@tonic-gate * For CMPs, we would like to perform DR operation on 2851*0Sstevel@tonic-gate * all the cores before moving onto the next chip. 2852*0Sstevel@tonic-gate * Therefore, when constructing the devlist, we process 2853*0Sstevel@tonic-gate * all the cores together. 2854*0Sstevel@tonic-gate */ 2855*0Sstevel@tonic-gate if (nodetype == SBD_COMP_CPU) { 2856*0Sstevel@tonic-gate /* 2857*0Sstevel@tonic-gate * Number of units to process in the inner loop 2858*0Sstevel@tonic-gate */ 2859*0Sstevel@tonic-gate nunits = MAX_CORES_PER_CMP; 2860*0Sstevel@tonic-gate /* 2861*0Sstevel@tonic-gate * The distance between the units in the 2862*0Sstevel@tonic-gate * board's sb_devlist structure. 2863*0Sstevel@tonic-gate */ 2864*0Sstevel@tonic-gate distance = MAX_CMP_UNITS_PER_BOARD; 2865*0Sstevel@tonic-gate } else { 2866*0Sstevel@tonic-gate nunits = 1; 2867*0Sstevel@tonic-gate distance = 0; 2868*0Sstevel@tonic-gate } 2869*0Sstevel@tonic-gate 2870*0Sstevel@tonic-gate for (j = 0; j < nunits; j++) { 2871*0Sstevel@tonic-gate if ((dip = devlist[i + j * distance]) == NULL) 2872*0Sstevel@tonic-gate continue; 2873*0Sstevel@tonic-gate 2874*0Sstevel@tonic-gate ut = sbdp_get_unit_num(hdp, dip); 2875*0Sstevel@tonic-gate 2876*0Sstevel@tonic-gate if (ut == -1) { 2877*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 2878*0Sstevel@tonic-gate PR_ALL("sbd_get_devlist bad unit %d" 2879*0Sstevel@tonic-gate " code %d errno %d", 2880*0Sstevel@tonic-gate i, ep->e_code, ep->e_errno); 2881*0Sstevel@tonic-gate } 2882*0Sstevel@tonic-gate 2883*0Sstevel@tonic-gate if ((uset & (1 << ut)) == 0) 2884*0Sstevel@tonic-gate continue; 2885*0Sstevel@tonic-gate uset &= ~(1 << ut); 2886*0Sstevel@tonic-gate is_present = SBD_DEV_IS_PRESENT(sbp, nodetype, ut) ? 2887*0Sstevel@tonic-gate 1 : 0; 2888*0Sstevel@tonic-gate is_attached = SBD_DEV_IS_ATTACHED(sbp, nodetype, ut) ? 2889*0Sstevel@tonic-gate 1 : 0; 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gate if (is_present && (present_only ^ is_attached)) { 2892*0Sstevel@tonic-gate ret_devlist[ix].dv_dip = dip; 2893*0Sstevel@tonic-gate sbd_init_err(&ret_devlist[ix].dv_error); 2894*0Sstevel@tonic-gate ix++; 2895*0Sstevel@tonic-gate } 2896*0Sstevel@tonic-gate } 2897*0Sstevel@tonic-gate } 2898*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 2899*0Sstevel@tonic-gate 2900*0Sstevel@tonic-gate if ((*count = ix) == 0) { 2901*0Sstevel@tonic-gate FREESTRUCT(ret_devlist, sbd_devlist_t, max_units); 2902*0Sstevel@tonic-gate ret_devlist = NULL; 2903*0Sstevel@tonic-gate } 2904*0Sstevel@tonic-gate 2905*0Sstevel@tonic-gate return (ret_devlist); 2906*0Sstevel@tonic-gate } 2907*0Sstevel@tonic-gate 2908*0Sstevel@tonic-gate static sbd_devlist_t * 2909*0Sstevel@tonic-gate sbd_get_attach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 2910*0Sstevel@tonic-gate { 2911*0Sstevel@tonic-gate sbd_board_t *sbp; 2912*0Sstevel@tonic-gate uint_t uset; 2913*0Sstevel@tonic-gate sbd_devset_t devset; 2914*0Sstevel@tonic-gate sbd_devlist_t *attach_devlist; 2915*0Sstevel@tonic-gate static int next_pass = 1; 2916*0Sstevel@tonic-gate static fn_t f = "sbd_get_attach_devlist"; 2917*0Sstevel@tonic-gate 2918*0Sstevel@tonic-gate PR_ALL("%s (pass = %d)...\n", f, pass); 2919*0Sstevel@tonic-gate 2920*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 2921*0Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset; 2922*0Sstevel@tonic-gate 2923*0Sstevel@tonic-gate *devnump = 0; 2924*0Sstevel@tonic-gate attach_devlist = NULL; 2925*0Sstevel@tonic-gate 2926*0Sstevel@tonic-gate /* 2927*0Sstevel@tonic-gate * We switch on next_pass for the cases where a board 2928*0Sstevel@tonic-gate * does not contain a particular type of component. 2929*0Sstevel@tonic-gate * In these situations we don't want to return NULL 2930*0Sstevel@tonic-gate * prematurely. We need to check other devices and 2931*0Sstevel@tonic-gate * we don't want to check the same type multiple times. 2932*0Sstevel@tonic-gate * For example, if there were no cpus, then on pass 1 2933*0Sstevel@tonic-gate * we would drop through and return the memory nodes. 2934*0Sstevel@tonic-gate * However, on pass 2 we would switch back to the memory 2935*0Sstevel@tonic-gate * nodes thereby returning them twice! Using next_pass 2936*0Sstevel@tonic-gate * forces us down to the end (or next item). 2937*0Sstevel@tonic-gate */ 2938*0Sstevel@tonic-gate if (pass == 1) 2939*0Sstevel@tonic-gate next_pass = 1; 2940*0Sstevel@tonic-gate 2941*0Sstevel@tonic-gate switch (next_pass) { 2942*0Sstevel@tonic-gate case 1: 2943*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 2944*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 2945*0Sstevel@tonic-gate 2946*0Sstevel@tonic-gate attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_CPU, 2947*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, 2948*0Sstevel@tonic-gate uset, devnump, 1); 2949*0Sstevel@tonic-gate 2950*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 2951*0Sstevel@tonic-gate if (!devset || attach_devlist) { 2952*0Sstevel@tonic-gate next_pass = 2; 2953*0Sstevel@tonic-gate return (attach_devlist); 2954*0Sstevel@tonic-gate } 2955*0Sstevel@tonic-gate /* 2956*0Sstevel@tonic-gate * If the caller is interested in the entire 2957*0Sstevel@tonic-gate * board, but there aren't any cpus, then just 2958*0Sstevel@tonic-gate * fall through to check for the next component. 2959*0Sstevel@tonic-gate */ 2960*0Sstevel@tonic-gate } 2961*0Sstevel@tonic-gate /*FALLTHROUGH*/ 2962*0Sstevel@tonic-gate 2963*0Sstevel@tonic-gate case 2: 2964*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 2965*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 2966*0Sstevel@tonic-gate 2967*0Sstevel@tonic-gate attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_MEM, 2968*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD, 2969*0Sstevel@tonic-gate uset, devnump, 1); 2970*0Sstevel@tonic-gate 2971*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 2972*0Sstevel@tonic-gate if (!devset || attach_devlist) { 2973*0Sstevel@tonic-gate next_pass = 3; 2974*0Sstevel@tonic-gate return (attach_devlist); 2975*0Sstevel@tonic-gate } 2976*0Sstevel@tonic-gate /* 2977*0Sstevel@tonic-gate * If the caller is interested in the entire 2978*0Sstevel@tonic-gate * board, but there isn't any memory, then 2979*0Sstevel@tonic-gate * just fall through to next component. 2980*0Sstevel@tonic-gate */ 2981*0Sstevel@tonic-gate } 2982*0Sstevel@tonic-gate /*FALLTHROUGH*/ 2983*0Sstevel@tonic-gate 2984*0Sstevel@tonic-gate 2985*0Sstevel@tonic-gate case 3: 2986*0Sstevel@tonic-gate next_pass = -1; 2987*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 2988*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 2989*0Sstevel@tonic-gate 2990*0Sstevel@tonic-gate attach_devlist = sbd_get_devlist(hp, sbp, SBD_COMP_IO, 2991*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD, 2992*0Sstevel@tonic-gate uset, devnump, 1); 2993*0Sstevel@tonic-gate 2994*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 2995*0Sstevel@tonic-gate if (!devset || attach_devlist) { 2996*0Sstevel@tonic-gate next_pass = 4; 2997*0Sstevel@tonic-gate return (attach_devlist); 2998*0Sstevel@tonic-gate } 2999*0Sstevel@tonic-gate } 3000*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3001*0Sstevel@tonic-gate 3002*0Sstevel@tonic-gate default: 3003*0Sstevel@tonic-gate *devnump = 0; 3004*0Sstevel@tonic-gate return (NULL); 3005*0Sstevel@tonic-gate } 3006*0Sstevel@tonic-gate /*NOTREACHED*/ 3007*0Sstevel@tonic-gate } 3008*0Sstevel@tonic-gate 3009*0Sstevel@tonic-gate static int 3010*0Sstevel@tonic-gate sbd_pre_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3011*0Sstevel@tonic-gate int32_t devnum) 3012*0Sstevel@tonic-gate { 3013*0Sstevel@tonic-gate int max_units = 0, rv = 0; 3014*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 3015*0Sstevel@tonic-gate static fn_t f = "sbd_pre_attach_devlist"; 3016*0Sstevel@tonic-gate 3017*0Sstevel@tonic-gate /* 3018*0Sstevel@tonic-gate * In this driver, all entries in a devlist[] are 3019*0Sstevel@tonic-gate * of the same nodetype. 3020*0Sstevel@tonic-gate */ 3021*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3022*0Sstevel@tonic-gate 3023*0Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3024*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3025*0Sstevel@tonic-gate 3026*0Sstevel@tonic-gate switch (nodetype) { 3027*0Sstevel@tonic-gate 3028*0Sstevel@tonic-gate case SBD_COMP_MEM: 3029*0Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 3030*0Sstevel@tonic-gate rv = sbd_pre_attach_mem(hp, devlist, devnum); 3031*0Sstevel@tonic-gate break; 3032*0Sstevel@tonic-gate 3033*0Sstevel@tonic-gate case SBD_COMP_CPU: 3034*0Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 3035*0Sstevel@tonic-gate rv = sbd_pre_attach_cpu(hp, devlist, devnum); 3036*0Sstevel@tonic-gate break; 3037*0Sstevel@tonic-gate 3038*0Sstevel@tonic-gate case SBD_COMP_IO: 3039*0Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 3040*0Sstevel@tonic-gate break; 3041*0Sstevel@tonic-gate 3042*0Sstevel@tonic-gate default: 3043*0Sstevel@tonic-gate rv = -1; 3044*0Sstevel@tonic-gate break; 3045*0Sstevel@tonic-gate } 3046*0Sstevel@tonic-gate 3047*0Sstevel@tonic-gate if (rv && max_units) { 3048*0Sstevel@tonic-gate int i; 3049*0Sstevel@tonic-gate /* 3050*0Sstevel@tonic-gate * Need to clean up devlist 3051*0Sstevel@tonic-gate * if pre-op is going to fail. 3052*0Sstevel@tonic-gate */ 3053*0Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 3054*0Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3055*0Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 3056*0Sstevel@tonic-gate } else { 3057*0Sstevel@tonic-gate break; 3058*0Sstevel@tonic-gate } 3059*0Sstevel@tonic-gate } 3060*0Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 3061*0Sstevel@tonic-gate } 3062*0Sstevel@tonic-gate 3063*0Sstevel@tonic-gate /* 3064*0Sstevel@tonic-gate * If an error occurred, return "continue" 3065*0Sstevel@tonic-gate * indication so that we can continue attaching 3066*0Sstevel@tonic-gate * as much as possible. 3067*0Sstevel@tonic-gate */ 3068*0Sstevel@tonic-gate return (rv ? -1 : 0); 3069*0Sstevel@tonic-gate } 3070*0Sstevel@tonic-gate 3071*0Sstevel@tonic-gate static int 3072*0Sstevel@tonic-gate sbd_post_attach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3073*0Sstevel@tonic-gate int32_t devnum) 3074*0Sstevel@tonic-gate { 3075*0Sstevel@tonic-gate int i, max_units = 0, rv = 0; 3076*0Sstevel@tonic-gate sbd_devset_t devs_unattached, devs_present; 3077*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 3078*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3079*0Sstevel@tonic-gate sbdp_handle_t *hdp; 3080*0Sstevel@tonic-gate static fn_t f = "sbd_post_attach_devlist"; 3081*0Sstevel@tonic-gate 3082*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 3083*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3084*0Sstevel@tonic-gate 3085*0Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3086*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3087*0Sstevel@tonic-gate 3088*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 3089*0Sstevel@tonic-gate 3090*0Sstevel@tonic-gate /* 3091*0Sstevel@tonic-gate * Need to free up devlist[] created earlier in 3092*0Sstevel@tonic-gate * sbd_get_attach_devlist(). 3093*0Sstevel@tonic-gate */ 3094*0Sstevel@tonic-gate switch (nodetype) { 3095*0Sstevel@tonic-gate case SBD_COMP_CPU: 3096*0Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 3097*0Sstevel@tonic-gate rv = sbd_post_attach_cpu(hp, devlist, devnum); 3098*0Sstevel@tonic-gate break; 3099*0Sstevel@tonic-gate 3100*0Sstevel@tonic-gate 3101*0Sstevel@tonic-gate case SBD_COMP_MEM: 3102*0Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 3103*0Sstevel@tonic-gate 3104*0Sstevel@tonic-gate rv = sbd_post_attach_mem(hp, devlist, devnum); 3105*0Sstevel@tonic-gate break; 3106*0Sstevel@tonic-gate 3107*0Sstevel@tonic-gate case SBD_COMP_IO: 3108*0Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 3109*0Sstevel@tonic-gate break; 3110*0Sstevel@tonic-gate 3111*0Sstevel@tonic-gate default: 3112*0Sstevel@tonic-gate rv = -1; 3113*0Sstevel@tonic-gate break; 3114*0Sstevel@tonic-gate } 3115*0Sstevel@tonic-gate 3116*0Sstevel@tonic-gate 3117*0Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 3118*0Sstevel@tonic-gate int unit; 3119*0Sstevel@tonic-gate dev_info_t *dip; 3120*0Sstevel@tonic-gate sbderror_t *ep; 3121*0Sstevel@tonic-gate 3122*0Sstevel@tonic-gate ep = &devlist[i].dv_error; 3123*0Sstevel@tonic-gate 3124*0Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) 3125*0Sstevel@tonic-gate continue; 3126*0Sstevel@tonic-gate 3127*0Sstevel@tonic-gate dip = devlist[i].dv_dip; 3128*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 3129*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 3130*0Sstevel@tonic-gate 3131*0Sstevel@tonic-gate if (unit == -1) { 3132*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 3133*0Sstevel@tonic-gate continue; 3134*0Sstevel@tonic-gate } 3135*0Sstevel@tonic-gate 3136*0Sstevel@tonic-gate unit = sbd_check_unit_attached(sbp, dip, unit, nodetype, ep); 3137*0Sstevel@tonic-gate 3138*0Sstevel@tonic-gate if (unit == -1) { 3139*0Sstevel@tonic-gate PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not attached\n", 3140*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], sbp->sb_num, i); 3141*0Sstevel@tonic-gate continue; 3142*0Sstevel@tonic-gate } 3143*0Sstevel@tonic-gate 3144*0Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, nodetype, unit); 3145*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, nodetype, unit, 3146*0Sstevel@tonic-gate SBD_STATE_CONFIGURED); 3147*0Sstevel@tonic-gate } 3148*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3149*0Sstevel@tonic-gate 3150*0Sstevel@tonic-gate if (rv) { 3151*0Sstevel@tonic-gate PR_ALL("%s: errno %d, ecode %d during attach\n", 3152*0Sstevel@tonic-gate f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 3153*0Sstevel@tonic-gate SBD_GET_ERR(HD2MACHERR(hp))); 3154*0Sstevel@tonic-gate } 3155*0Sstevel@tonic-gate 3156*0Sstevel@tonic-gate devs_present = SBD_DEVS_PRESENT(sbp); 3157*0Sstevel@tonic-gate devs_unattached = SBD_DEVS_UNATTACHED(sbp); 3158*0Sstevel@tonic-gate 3159*0Sstevel@tonic-gate switch (SBD_BOARD_STATE(sbp)) { 3160*0Sstevel@tonic-gate case SBD_STATE_CONNECTED: 3161*0Sstevel@tonic-gate case SBD_STATE_UNCONFIGURED: 3162*0Sstevel@tonic-gate ASSERT(devs_present); 3163*0Sstevel@tonic-gate 3164*0Sstevel@tonic-gate if (devs_unattached == 0) { 3165*0Sstevel@tonic-gate /* 3166*0Sstevel@tonic-gate * All devices finally attached. 3167*0Sstevel@tonic-gate */ 3168*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 3169*0Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 3170*0Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_CONFIGURED; 3171*0Sstevel@tonic-gate } else if (devs_present != devs_unattached) { 3172*0Sstevel@tonic-gate /* 3173*0Sstevel@tonic-gate * Only some devices are fully attached. 3174*0Sstevel@tonic-gate */ 3175*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 3176*0Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 3177*0Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_UNCONFIGURED; 3178*0Sstevel@tonic-gate } 3179*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 3180*0Sstevel@tonic-gate break; 3181*0Sstevel@tonic-gate 3182*0Sstevel@tonic-gate case SBD_STATE_PARTIAL: 3183*0Sstevel@tonic-gate ASSERT(devs_present); 3184*0Sstevel@tonic-gate /* 3185*0Sstevel@tonic-gate * All devices finally attached. 3186*0Sstevel@tonic-gate */ 3187*0Sstevel@tonic-gate if (devs_unattached == 0) { 3188*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 3189*0Sstevel@tonic-gate sbp->sb_rstate = SBD_STAT_CONNECTED; 3190*0Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_CONFIGURED; 3191*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 3192*0Sstevel@tonic-gate } 3193*0Sstevel@tonic-gate break; 3194*0Sstevel@tonic-gate 3195*0Sstevel@tonic-gate default: 3196*0Sstevel@tonic-gate break; 3197*0Sstevel@tonic-gate } 3198*0Sstevel@tonic-gate 3199*0Sstevel@tonic-gate if (max_units && devlist) { 3200*0Sstevel@tonic-gate int i; 3201*0Sstevel@tonic-gate 3202*0Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 3203*0Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3204*0Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 3205*0Sstevel@tonic-gate } else { 3206*0Sstevel@tonic-gate break; 3207*0Sstevel@tonic-gate } 3208*0Sstevel@tonic-gate } 3209*0Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 3210*0Sstevel@tonic-gate } 3211*0Sstevel@tonic-gate 3212*0Sstevel@tonic-gate /* 3213*0Sstevel@tonic-gate * Our policy is to attach all components that are 3214*0Sstevel@tonic-gate * possible, thus we always return "success" on the 3215*0Sstevel@tonic-gate * pre and post operations. 3216*0Sstevel@tonic-gate */ 3217*0Sstevel@tonic-gate return (0); 3218*0Sstevel@tonic-gate } 3219*0Sstevel@tonic-gate 3220*0Sstevel@tonic-gate /* 3221*0Sstevel@tonic-gate * We only need to "release" cpu and memory devices. 3222*0Sstevel@tonic-gate */ 3223*0Sstevel@tonic-gate static sbd_devlist_t * 3224*0Sstevel@tonic-gate sbd_get_release_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 3225*0Sstevel@tonic-gate { 3226*0Sstevel@tonic-gate sbd_board_t *sbp; 3227*0Sstevel@tonic-gate uint_t uset; 3228*0Sstevel@tonic-gate sbd_devset_t devset; 3229*0Sstevel@tonic-gate sbd_devlist_t *release_devlist; 3230*0Sstevel@tonic-gate static int next_pass = 1; 3231*0Sstevel@tonic-gate static fn_t f = "sbd_get_release_devlist"; 3232*0Sstevel@tonic-gate 3233*0Sstevel@tonic-gate PR_ALL("%s (pass = %d)...\n", f, pass); 3234*0Sstevel@tonic-gate 3235*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 3236*0Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset; 3237*0Sstevel@tonic-gate 3238*0Sstevel@tonic-gate *devnump = 0; 3239*0Sstevel@tonic-gate release_devlist = NULL; 3240*0Sstevel@tonic-gate 3241*0Sstevel@tonic-gate /* 3242*0Sstevel@tonic-gate * We switch on next_pass for the cases where a board 3243*0Sstevel@tonic-gate * does not contain a particular type of component. 3244*0Sstevel@tonic-gate * In these situations we don't want to return NULL 3245*0Sstevel@tonic-gate * prematurely. We need to check other devices and 3246*0Sstevel@tonic-gate * we don't want to check the same type multiple times. 3247*0Sstevel@tonic-gate * For example, if there were no cpus, then on pass 1 3248*0Sstevel@tonic-gate * we would drop through and return the memory nodes. 3249*0Sstevel@tonic-gate * However, on pass 2 we would switch back to the memory 3250*0Sstevel@tonic-gate * nodes thereby returning them twice! Using next_pass 3251*0Sstevel@tonic-gate * forces us down to the end (or next item). 3252*0Sstevel@tonic-gate */ 3253*0Sstevel@tonic-gate if (pass == 1) 3254*0Sstevel@tonic-gate next_pass = 1; 3255*0Sstevel@tonic-gate 3256*0Sstevel@tonic-gate switch (next_pass) { 3257*0Sstevel@tonic-gate case 1: 3258*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 3259*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 3260*0Sstevel@tonic-gate 3261*0Sstevel@tonic-gate release_devlist = sbd_get_devlist(hp, sbp, 3262*0Sstevel@tonic-gate SBD_COMP_MEM, 3263*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD, 3264*0Sstevel@tonic-gate uset, devnump, 0); 3265*0Sstevel@tonic-gate 3266*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 3267*0Sstevel@tonic-gate if (!devset || release_devlist) { 3268*0Sstevel@tonic-gate next_pass = 2; 3269*0Sstevel@tonic-gate return (release_devlist); 3270*0Sstevel@tonic-gate } 3271*0Sstevel@tonic-gate /* 3272*0Sstevel@tonic-gate * If the caller is interested in the entire 3273*0Sstevel@tonic-gate * board, but there isn't any memory, then 3274*0Sstevel@tonic-gate * just fall through to next component. 3275*0Sstevel@tonic-gate */ 3276*0Sstevel@tonic-gate } 3277*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3278*0Sstevel@tonic-gate 3279*0Sstevel@tonic-gate 3280*0Sstevel@tonic-gate case 2: 3281*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 3282*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 3283*0Sstevel@tonic-gate 3284*0Sstevel@tonic-gate release_devlist = sbd_get_devlist(hp, sbp, 3285*0Sstevel@tonic-gate SBD_COMP_CPU, 3286*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, 3287*0Sstevel@tonic-gate uset, devnump, 0); 3288*0Sstevel@tonic-gate 3289*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 3290*0Sstevel@tonic-gate if (!devset || release_devlist) { 3291*0Sstevel@tonic-gate next_pass = 3; 3292*0Sstevel@tonic-gate return (release_devlist); 3293*0Sstevel@tonic-gate } 3294*0Sstevel@tonic-gate /* 3295*0Sstevel@tonic-gate * If the caller is interested in the entire 3296*0Sstevel@tonic-gate * board, but there aren't any cpus, then just 3297*0Sstevel@tonic-gate * fall through to check for the next component. 3298*0Sstevel@tonic-gate */ 3299*0Sstevel@tonic-gate } 3300*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3301*0Sstevel@tonic-gate 3302*0Sstevel@tonic-gate 3303*0Sstevel@tonic-gate case 3: 3304*0Sstevel@tonic-gate next_pass = -1; 3305*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 3306*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 3307*0Sstevel@tonic-gate 3308*0Sstevel@tonic-gate release_devlist = sbd_get_devlist(hp, sbp, 3309*0Sstevel@tonic-gate SBD_COMP_IO, 3310*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD, 3311*0Sstevel@tonic-gate uset, devnump, 0); 3312*0Sstevel@tonic-gate 3313*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 3314*0Sstevel@tonic-gate if (!devset || release_devlist) { 3315*0Sstevel@tonic-gate next_pass = 4; 3316*0Sstevel@tonic-gate return (release_devlist); 3317*0Sstevel@tonic-gate } 3318*0Sstevel@tonic-gate } 3319*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3320*0Sstevel@tonic-gate 3321*0Sstevel@tonic-gate default: 3322*0Sstevel@tonic-gate *devnump = 0; 3323*0Sstevel@tonic-gate return (NULL); 3324*0Sstevel@tonic-gate } 3325*0Sstevel@tonic-gate /*NOTREACHED*/ 3326*0Sstevel@tonic-gate } 3327*0Sstevel@tonic-gate 3328*0Sstevel@tonic-gate static int 3329*0Sstevel@tonic-gate sbd_pre_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3330*0Sstevel@tonic-gate int32_t devnum) 3331*0Sstevel@tonic-gate { 3332*0Sstevel@tonic-gate int max_units = 0, rv = 0; 3333*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 3334*0Sstevel@tonic-gate static fn_t f = "sbd_pre_release_devlist"; 3335*0Sstevel@tonic-gate 3336*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3337*0Sstevel@tonic-gate 3338*0Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3339*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3340*0Sstevel@tonic-gate 3341*0Sstevel@tonic-gate switch (nodetype) { 3342*0Sstevel@tonic-gate case SBD_COMP_CPU: { 3343*0Sstevel@tonic-gate int i, mem_present = 0; 3344*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3345*0Sstevel@tonic-gate sbd_devset_t devset; 3346*0Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 3347*0Sstevel@tonic-gate 3348*0Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 3349*0Sstevel@tonic-gate 3350*0Sstevel@tonic-gate devset = shp->sh_orig_devset; 3351*0Sstevel@tonic-gate 3352*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 3353*0Sstevel@tonic-gate /* 3354*0Sstevel@tonic-gate * if client also requested to unconfigure memory 3355*0Sstevel@tonic-gate * the we allow the operation. Therefore 3356*0Sstevel@tonic-gate * we need to warranty that memory gets unconfig 3357*0Sstevel@tonic-gate * before cpus 3358*0Sstevel@tonic-gate */ 3359*0Sstevel@tonic-gate 3360*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) { 3361*0Sstevel@tonic-gate continue; 3362*0Sstevel@tonic-gate } 3363*0Sstevel@tonic-gate if (SBD_DEV_IS_ATTACHED(sbp, SBD_COMP_MEM, i)) { 3364*0Sstevel@tonic-gate mem_present = 1; 3365*0Sstevel@tonic-gate break; 3366*0Sstevel@tonic-gate } 3367*0Sstevel@tonic-gate } 3368*0Sstevel@tonic-gate if (mem_present) { 3369*0Sstevel@tonic-gate sbderror_t *ep = SBD_HD2ERR(hp); 3370*0Sstevel@tonic-gate SBD_SET_ERR(ep, ESBD_MEMONLINE); 3371*0Sstevel@tonic-gate SBD_SET_ERRSTR(ep, sbp->sb_mempath[i]); 3372*0Sstevel@tonic-gate rv = -1; 3373*0Sstevel@tonic-gate } else { 3374*0Sstevel@tonic-gate rv = sbd_pre_release_cpu(hp, devlist, devnum); 3375*0Sstevel@tonic-gate } 3376*0Sstevel@tonic-gate 3377*0Sstevel@tonic-gate break; 3378*0Sstevel@tonic-gate 3379*0Sstevel@tonic-gate } 3380*0Sstevel@tonic-gate case SBD_COMP_MEM: 3381*0Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 3382*0Sstevel@tonic-gate rv = sbd_pre_release_mem(hp, devlist, devnum); 3383*0Sstevel@tonic-gate break; 3384*0Sstevel@tonic-gate 3385*0Sstevel@tonic-gate 3386*0Sstevel@tonic-gate case SBD_COMP_IO: 3387*0Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 3388*0Sstevel@tonic-gate rv = sbd_pre_release_io(hp, devlist, devnum); 3389*0Sstevel@tonic-gate break; 3390*0Sstevel@tonic-gate 3391*0Sstevel@tonic-gate default: 3392*0Sstevel@tonic-gate rv = -1; 3393*0Sstevel@tonic-gate break; 3394*0Sstevel@tonic-gate } 3395*0Sstevel@tonic-gate 3396*0Sstevel@tonic-gate if (rv && max_units) { 3397*0Sstevel@tonic-gate int i; 3398*0Sstevel@tonic-gate 3399*0Sstevel@tonic-gate /* 3400*0Sstevel@tonic-gate * the individual pre_release component routines should 3401*0Sstevel@tonic-gate * have set the error in the handle. No need to set it 3402*0Sstevel@tonic-gate * here 3403*0Sstevel@tonic-gate * 3404*0Sstevel@tonic-gate * Need to clean up dynamically allocated devlist 3405*0Sstevel@tonic-gate * if pre-op is going to fail. 3406*0Sstevel@tonic-gate */ 3407*0Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 3408*0Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3409*0Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 3410*0Sstevel@tonic-gate } else { 3411*0Sstevel@tonic-gate break; 3412*0Sstevel@tonic-gate } 3413*0Sstevel@tonic-gate } 3414*0Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 3415*0Sstevel@tonic-gate } 3416*0Sstevel@tonic-gate 3417*0Sstevel@tonic-gate return (rv ? -1 : 0); 3418*0Sstevel@tonic-gate } 3419*0Sstevel@tonic-gate 3420*0Sstevel@tonic-gate static int 3421*0Sstevel@tonic-gate sbd_post_release_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3422*0Sstevel@tonic-gate int32_t devnum) 3423*0Sstevel@tonic-gate { 3424*0Sstevel@tonic-gate int i, max_units = 0; 3425*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 3426*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3427*0Sstevel@tonic-gate sbdp_handle_t *hdp; 3428*0Sstevel@tonic-gate sbd_error_t *spe; 3429*0Sstevel@tonic-gate static fn_t f = "sbd_post_release_devlist"; 3430*0Sstevel@tonic-gate 3431*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3432*0Sstevel@tonic-gate ASSERT(nodetype >= SBD_COMP_CPU && nodetype <= SBD_COMP_IO); 3433*0Sstevel@tonic-gate 3434*0Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3435*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3436*0Sstevel@tonic-gate 3437*0Sstevel@tonic-gate /* 3438*0Sstevel@tonic-gate * Need to free up devlist[] created earlier in 3439*0Sstevel@tonic-gate * sbd_get_release_devlist(). 3440*0Sstevel@tonic-gate */ 3441*0Sstevel@tonic-gate switch (nodetype) { 3442*0Sstevel@tonic-gate case SBD_COMP_CPU: 3443*0Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 3444*0Sstevel@tonic-gate break; 3445*0Sstevel@tonic-gate 3446*0Sstevel@tonic-gate case SBD_COMP_MEM: 3447*0Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 3448*0Sstevel@tonic-gate break; 3449*0Sstevel@tonic-gate 3450*0Sstevel@tonic-gate case SBD_COMP_IO: 3451*0Sstevel@tonic-gate /* 3452*0Sstevel@tonic-gate * Need to check if specific I/O is referenced and 3453*0Sstevel@tonic-gate * fail post-op. 3454*0Sstevel@tonic-gate */ 3455*0Sstevel@tonic-gate 3456*0Sstevel@tonic-gate if (sbd_check_io_refs(hp, devlist, devnum) > 0) { 3457*0Sstevel@tonic-gate PR_IO("%s: error - I/O devices ref'd\n", f); 3458*0Sstevel@tonic-gate } 3459*0Sstevel@tonic-gate 3460*0Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 3461*0Sstevel@tonic-gate break; 3462*0Sstevel@tonic-gate 3463*0Sstevel@tonic-gate default: 3464*0Sstevel@tonic-gate { 3465*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: invalid nodetype (%d)", 3466*0Sstevel@tonic-gate f, (int)nodetype); 3467*0Sstevel@tonic-gate SBD_SET_ERR(HD2MACHERR(hp), ESBD_INVAL); 3468*0Sstevel@tonic-gate } 3469*0Sstevel@tonic-gate break; 3470*0Sstevel@tonic-gate } 3471*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 3472*0Sstevel@tonic-gate spe = hdp->h_err; 3473*0Sstevel@tonic-gate 3474*0Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 3475*0Sstevel@tonic-gate int unit; 3476*0Sstevel@tonic-gate sbderror_t *ep; 3477*0Sstevel@tonic-gate 3478*0Sstevel@tonic-gate ep = &devlist[i].dv_error; 3479*0Sstevel@tonic-gate 3480*0Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) { 3481*0Sstevel@tonic-gate continue; 3482*0Sstevel@tonic-gate } 3483*0Sstevel@tonic-gate 3484*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, devlist[i].dv_dip); 3485*0Sstevel@tonic-gate if (unit == -1) { 3486*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 3487*0Sstevel@tonic-gate PR_ALL("%s bad unit num: %d code %d", 3488*0Sstevel@tonic-gate f, unit, spe->e_code); 3489*0Sstevel@tonic-gate continue; 3490*0Sstevel@tonic-gate } 3491*0Sstevel@tonic-gate } 3492*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3493*0Sstevel@tonic-gate 3494*0Sstevel@tonic-gate if (SBD_GET_ERRNO(SBD_HD2ERR(hp))) { 3495*0Sstevel@tonic-gate PR_ALL("%s: errno %d, ecode %d during release\n", 3496*0Sstevel@tonic-gate f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 3497*0Sstevel@tonic-gate SBD_GET_ERR(SBD_HD2ERR(hp))); 3498*0Sstevel@tonic-gate } 3499*0Sstevel@tonic-gate 3500*0Sstevel@tonic-gate if (max_units && devlist) { 3501*0Sstevel@tonic-gate int i; 3502*0Sstevel@tonic-gate 3503*0Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 3504*0Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3505*0Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 3506*0Sstevel@tonic-gate } else { 3507*0Sstevel@tonic-gate break; 3508*0Sstevel@tonic-gate } 3509*0Sstevel@tonic-gate } 3510*0Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 3511*0Sstevel@tonic-gate } 3512*0Sstevel@tonic-gate 3513*0Sstevel@tonic-gate return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0); 3514*0Sstevel@tonic-gate } 3515*0Sstevel@tonic-gate 3516*0Sstevel@tonic-gate static void 3517*0Sstevel@tonic-gate sbd_release_dev_done(sbd_board_t *sbp, sbd_comp_type_t nodetype, int unit) 3518*0Sstevel@tonic-gate { 3519*0Sstevel@tonic-gate SBD_DEV_SET_UNREFERENCED(sbp, nodetype, unit); 3520*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, nodetype, unit, SBD_STATE_UNREFERENCED); 3521*0Sstevel@tonic-gate } 3522*0Sstevel@tonic-gate 3523*0Sstevel@tonic-gate static void 3524*0Sstevel@tonic-gate sbd_release_done(sbd_handle_t *hp, sbd_comp_type_t nodetype, dev_info_t *dip) 3525*0Sstevel@tonic-gate { 3526*0Sstevel@tonic-gate int unit; 3527*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3528*0Sstevel@tonic-gate sbderror_t *ep; 3529*0Sstevel@tonic-gate static fn_t f = "sbd_release_done"; 3530*0Sstevel@tonic-gate sbdp_handle_t *hdp; 3531*0Sstevel@tonic-gate 3532*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 3533*0Sstevel@tonic-gate 3534*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 3535*0Sstevel@tonic-gate ep = SBD_HD2ERR(hp); 3536*0Sstevel@tonic-gate 3537*0Sstevel@tonic-gate if ((unit = sbdp_get_unit_num(hdp, dip)) < 0) { 3538*0Sstevel@tonic-gate cmn_err(CE_WARN, 3539*0Sstevel@tonic-gate "sbd:%s: unable to get unit for dip (0x%p)", 3540*0Sstevel@tonic-gate f, (void *)dip); 3541*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 3542*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3543*0Sstevel@tonic-gate return; 3544*0Sstevel@tonic-gate } 3545*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3546*0Sstevel@tonic-gate 3547*0Sstevel@tonic-gate /* 3548*0Sstevel@tonic-gate * Transfer the device which just completed its release 3549*0Sstevel@tonic-gate * to the UNREFERENCED state. 3550*0Sstevel@tonic-gate */ 3551*0Sstevel@tonic-gate switch (nodetype) { 3552*0Sstevel@tonic-gate 3553*0Sstevel@tonic-gate case SBD_COMP_MEM: 3554*0Sstevel@tonic-gate sbd_release_mem_done((void *)hp, unit); 3555*0Sstevel@tonic-gate break; 3556*0Sstevel@tonic-gate 3557*0Sstevel@tonic-gate default: 3558*0Sstevel@tonic-gate sbd_release_dev_done(sbp, nodetype, unit); 3559*0Sstevel@tonic-gate break; 3560*0Sstevel@tonic-gate } 3561*0Sstevel@tonic-gate 3562*0Sstevel@tonic-gate /* 3563*0Sstevel@tonic-gate * If the entire board was released and all components 3564*0Sstevel@tonic-gate * unreferenced then transfer it to the UNREFERENCED state. 3565*0Sstevel@tonic-gate */ 3566*0Sstevel@tonic-gate if (SBD_DEVS_RELEASED(sbp) == SBD_DEVS_UNREFERENCED(sbp)) { 3567*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNREFERENCED); 3568*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 3569*0Sstevel@tonic-gate } 3570*0Sstevel@tonic-gate } 3571*0Sstevel@tonic-gate 3572*0Sstevel@tonic-gate static sbd_devlist_t * 3573*0Sstevel@tonic-gate sbd_get_detach_devlist(sbd_handle_t *hp, int32_t *devnump, int32_t pass) 3574*0Sstevel@tonic-gate { 3575*0Sstevel@tonic-gate sbd_board_t *sbp; 3576*0Sstevel@tonic-gate uint_t uset; 3577*0Sstevel@tonic-gate sbd_devset_t devset; 3578*0Sstevel@tonic-gate sbd_devlist_t *detach_devlist; 3579*0Sstevel@tonic-gate static int next_pass = 1; 3580*0Sstevel@tonic-gate static fn_t f = "sbd_get_detach_devlist"; 3581*0Sstevel@tonic-gate 3582*0Sstevel@tonic-gate PR_ALL("%s (pass = %d)...\n", f, pass); 3583*0Sstevel@tonic-gate 3584*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 3585*0Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset; 3586*0Sstevel@tonic-gate 3587*0Sstevel@tonic-gate *devnump = 0; 3588*0Sstevel@tonic-gate detach_devlist = NULL; 3589*0Sstevel@tonic-gate 3590*0Sstevel@tonic-gate /* 3591*0Sstevel@tonic-gate * We switch on next_pass for the cases where a board 3592*0Sstevel@tonic-gate * does not contain a particular type of component. 3593*0Sstevel@tonic-gate * In these situations we don't want to return NULL 3594*0Sstevel@tonic-gate * prematurely. We need to check other devices and 3595*0Sstevel@tonic-gate * we don't want to check the same type multiple times. 3596*0Sstevel@tonic-gate * For example, if there were no cpus, then on pass 1 3597*0Sstevel@tonic-gate * we would drop through and return the memory nodes. 3598*0Sstevel@tonic-gate * However, on pass 2 we would switch back to the memory 3599*0Sstevel@tonic-gate * nodes thereby returning them twice! Using next_pass 3600*0Sstevel@tonic-gate * forces us down to the end (or next item). 3601*0Sstevel@tonic-gate */ 3602*0Sstevel@tonic-gate if (pass == 1) 3603*0Sstevel@tonic-gate next_pass = 1; 3604*0Sstevel@tonic-gate 3605*0Sstevel@tonic-gate switch (next_pass) { 3606*0Sstevel@tonic-gate case 1: 3607*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 3608*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_MEM); 3609*0Sstevel@tonic-gate 3610*0Sstevel@tonic-gate detach_devlist = sbd_get_devlist(hp, sbp, 3611*0Sstevel@tonic-gate SBD_COMP_MEM, 3612*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD, 3613*0Sstevel@tonic-gate uset, devnump, 0); 3614*0Sstevel@tonic-gate 3615*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 3616*0Sstevel@tonic-gate if (!devset || detach_devlist) { 3617*0Sstevel@tonic-gate next_pass = 2; 3618*0Sstevel@tonic-gate return (detach_devlist); 3619*0Sstevel@tonic-gate } 3620*0Sstevel@tonic-gate /* 3621*0Sstevel@tonic-gate * If the caller is interested in the entire 3622*0Sstevel@tonic-gate * board, but there isn't any memory, then 3623*0Sstevel@tonic-gate * just fall through to next component. 3624*0Sstevel@tonic-gate */ 3625*0Sstevel@tonic-gate } 3626*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3627*0Sstevel@tonic-gate 3628*0Sstevel@tonic-gate case 2: 3629*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 3630*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_CPU); 3631*0Sstevel@tonic-gate 3632*0Sstevel@tonic-gate detach_devlist = sbd_get_devlist(hp, sbp, 3633*0Sstevel@tonic-gate SBD_COMP_CPU, 3634*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD, 3635*0Sstevel@tonic-gate uset, devnump, 0); 3636*0Sstevel@tonic-gate 3637*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, DEVSET_ANYUNIT); 3638*0Sstevel@tonic-gate if (!devset || detach_devlist) { 3639*0Sstevel@tonic-gate next_pass = 2; 3640*0Sstevel@tonic-gate return (detach_devlist); 3641*0Sstevel@tonic-gate } 3642*0Sstevel@tonic-gate /* 3643*0Sstevel@tonic-gate * If the caller is interested in the entire 3644*0Sstevel@tonic-gate * board, but there aren't any cpus, then just 3645*0Sstevel@tonic-gate * fall through to check for the next component. 3646*0Sstevel@tonic-gate */ 3647*0Sstevel@tonic-gate } 3648*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3649*0Sstevel@tonic-gate 3650*0Sstevel@tonic-gate case 3: 3651*0Sstevel@tonic-gate next_pass = -1; 3652*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 3653*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(devset, SBD_COMP_IO); 3654*0Sstevel@tonic-gate 3655*0Sstevel@tonic-gate detach_devlist = sbd_get_devlist(hp, sbp, 3656*0Sstevel@tonic-gate SBD_COMP_IO, 3657*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD, 3658*0Sstevel@tonic-gate uset, devnump, 0); 3659*0Sstevel@tonic-gate 3660*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, DEVSET_ANYUNIT); 3661*0Sstevel@tonic-gate if (!devset || detach_devlist) { 3662*0Sstevel@tonic-gate next_pass = 4; 3663*0Sstevel@tonic-gate return (detach_devlist); 3664*0Sstevel@tonic-gate } 3665*0Sstevel@tonic-gate } 3666*0Sstevel@tonic-gate /*FALLTHROUGH*/ 3667*0Sstevel@tonic-gate 3668*0Sstevel@tonic-gate default: 3669*0Sstevel@tonic-gate *devnump = 0; 3670*0Sstevel@tonic-gate return (NULL); 3671*0Sstevel@tonic-gate } 3672*0Sstevel@tonic-gate /*NOTREACHED*/ 3673*0Sstevel@tonic-gate } 3674*0Sstevel@tonic-gate 3675*0Sstevel@tonic-gate static int 3676*0Sstevel@tonic-gate sbd_pre_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3677*0Sstevel@tonic-gate int32_t devnum) 3678*0Sstevel@tonic-gate { 3679*0Sstevel@tonic-gate int rv = 0; 3680*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 3681*0Sstevel@tonic-gate static fn_t f = "sbd_pre_detach_devlist"; 3682*0Sstevel@tonic-gate 3683*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3684*0Sstevel@tonic-gate 3685*0Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3686*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3687*0Sstevel@tonic-gate 3688*0Sstevel@tonic-gate switch (nodetype) { 3689*0Sstevel@tonic-gate case SBD_COMP_CPU: 3690*0Sstevel@tonic-gate rv = sbd_pre_detach_cpu(hp, devlist, devnum); 3691*0Sstevel@tonic-gate break; 3692*0Sstevel@tonic-gate 3693*0Sstevel@tonic-gate case SBD_COMP_MEM: 3694*0Sstevel@tonic-gate rv = sbd_pre_detach_mem(hp, devlist, devnum); 3695*0Sstevel@tonic-gate break; 3696*0Sstevel@tonic-gate 3697*0Sstevel@tonic-gate case SBD_COMP_IO: 3698*0Sstevel@tonic-gate rv = sbd_pre_detach_io(hp, devlist, devnum); 3699*0Sstevel@tonic-gate break; 3700*0Sstevel@tonic-gate 3701*0Sstevel@tonic-gate default: 3702*0Sstevel@tonic-gate rv = -1; 3703*0Sstevel@tonic-gate break; 3704*0Sstevel@tonic-gate } 3705*0Sstevel@tonic-gate 3706*0Sstevel@tonic-gate /* 3707*0Sstevel@tonic-gate * We want to continue attempting to detach 3708*0Sstevel@tonic-gate * other components. 3709*0Sstevel@tonic-gate */ 3710*0Sstevel@tonic-gate return (rv); 3711*0Sstevel@tonic-gate } 3712*0Sstevel@tonic-gate 3713*0Sstevel@tonic-gate static int 3714*0Sstevel@tonic-gate sbd_post_detach_devlist(sbd_handle_t *hp, sbd_devlist_t *devlist, 3715*0Sstevel@tonic-gate int32_t devnum) 3716*0Sstevel@tonic-gate { 3717*0Sstevel@tonic-gate int i, max_units = 0, rv = 0; 3718*0Sstevel@tonic-gate sbd_comp_type_t nodetype; 3719*0Sstevel@tonic-gate sbd_board_t *sbp; 3720*0Sstevel@tonic-gate sbd_istate_t bstate; 3721*0Sstevel@tonic-gate static fn_t f = "sbd_post_detach_devlist"; 3722*0Sstevel@tonic-gate sbdp_handle_t *hdp; 3723*0Sstevel@tonic-gate 3724*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 3725*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, devlist->dv_dip); 3726*0Sstevel@tonic-gate 3727*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 3728*0Sstevel@tonic-gate 3729*0Sstevel@tonic-gate PR_ALL("%s (nt = %s(%d), num = %d)...\n", 3730*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], (int)nodetype, devnum); 3731*0Sstevel@tonic-gate 3732*0Sstevel@tonic-gate /* 3733*0Sstevel@tonic-gate * Need to free up devlist[] created earlier in 3734*0Sstevel@tonic-gate * sbd_get_detach_devlist(). 3735*0Sstevel@tonic-gate */ 3736*0Sstevel@tonic-gate switch (nodetype) { 3737*0Sstevel@tonic-gate case SBD_COMP_CPU: 3738*0Sstevel@tonic-gate max_units = MAX_CPU_UNITS_PER_BOARD; 3739*0Sstevel@tonic-gate rv = sbd_post_detach_cpu(hp, devlist, devnum); 3740*0Sstevel@tonic-gate break; 3741*0Sstevel@tonic-gate 3742*0Sstevel@tonic-gate case SBD_COMP_MEM: 3743*0Sstevel@tonic-gate max_units = MAX_MEM_UNITS_PER_BOARD; 3744*0Sstevel@tonic-gate rv = sbd_post_detach_mem(hp, devlist, devnum); 3745*0Sstevel@tonic-gate break; 3746*0Sstevel@tonic-gate 3747*0Sstevel@tonic-gate case SBD_COMP_IO: 3748*0Sstevel@tonic-gate max_units = MAX_IO_UNITS_PER_BOARD; 3749*0Sstevel@tonic-gate rv = sbd_post_detach_io(hp, devlist, devnum); 3750*0Sstevel@tonic-gate break; 3751*0Sstevel@tonic-gate 3752*0Sstevel@tonic-gate default: 3753*0Sstevel@tonic-gate rv = -1; 3754*0Sstevel@tonic-gate break; 3755*0Sstevel@tonic-gate } 3756*0Sstevel@tonic-gate 3757*0Sstevel@tonic-gate 3758*0Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 3759*0Sstevel@tonic-gate int unit; 3760*0Sstevel@tonic-gate sbderror_t *ep; 3761*0Sstevel@tonic-gate dev_info_t *dip; 3762*0Sstevel@tonic-gate 3763*0Sstevel@tonic-gate ep = &devlist[i].dv_error; 3764*0Sstevel@tonic-gate 3765*0Sstevel@tonic-gate if (sbd_set_err_in_hdl(hp, ep) == 0) 3766*0Sstevel@tonic-gate continue; 3767*0Sstevel@tonic-gate 3768*0Sstevel@tonic-gate dip = devlist[i].dv_dip; 3769*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 3770*0Sstevel@tonic-gate if (unit == -1) { 3771*0Sstevel@tonic-gate if (hp->h_flags & SBD_IOCTL_FLAG_FORCE) 3772*0Sstevel@tonic-gate continue; 3773*0Sstevel@tonic-gate else { 3774*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 3775*0Sstevel@tonic-gate break; 3776*0Sstevel@tonic-gate } 3777*0Sstevel@tonic-gate } 3778*0Sstevel@tonic-gate nodetype = sbd_get_devtype(hp, dip); 3779*0Sstevel@tonic-gate 3780*0Sstevel@tonic-gate if (sbd_check_unit_attached(sbp, dip, unit, nodetype, 3781*0Sstevel@tonic-gate ep) >= 0) { 3782*0Sstevel@tonic-gate /* 3783*0Sstevel@tonic-gate * Device is still attached probably due 3784*0Sstevel@tonic-gate * to an error. Need to keep track of it. 3785*0Sstevel@tonic-gate */ 3786*0Sstevel@tonic-gate PR_ALL("%s: ERROR (nt=%s, b=%d, u=%d) not detached\n", 3787*0Sstevel@tonic-gate f, sbd_ct_str[(int)nodetype], sbp->sb_num, 3788*0Sstevel@tonic-gate unit); 3789*0Sstevel@tonic-gate continue; 3790*0Sstevel@tonic-gate } 3791*0Sstevel@tonic-gate 3792*0Sstevel@tonic-gate SBD_DEV_CLR_ATTACHED(sbp, nodetype, unit); 3793*0Sstevel@tonic-gate SBD_DEV_CLR_RELEASED(sbp, nodetype, unit); 3794*0Sstevel@tonic-gate SBD_DEV_CLR_UNREFERENCED(sbp, nodetype, unit); 3795*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, nodetype, unit, 3796*0Sstevel@tonic-gate SBD_STATE_UNCONFIGURED); 3797*0Sstevel@tonic-gate } 3798*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3799*0Sstevel@tonic-gate 3800*0Sstevel@tonic-gate bstate = SBD_BOARD_STATE(sbp); 3801*0Sstevel@tonic-gate if (bstate != SBD_STATE_UNCONFIGURED) { 3802*0Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp) == SBD_DEVS_UNATTACHED(sbp)) { 3803*0Sstevel@tonic-gate /* 3804*0Sstevel@tonic-gate * All devices are finally detached. 3805*0Sstevel@tonic-gate */ 3806*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_UNCONFIGURED); 3807*0Sstevel@tonic-gate } else if ((SBD_BOARD_STATE(sbp) != SBD_STATE_PARTIAL) && 3808*0Sstevel@tonic-gate SBD_DEVS_ATTACHED(sbp)) { 3809*0Sstevel@tonic-gate /* 3810*0Sstevel@tonic-gate * Some devices remain attached. 3811*0Sstevel@tonic-gate */ 3812*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 3813*0Sstevel@tonic-gate } 3814*0Sstevel@tonic-gate } 3815*0Sstevel@tonic-gate 3816*0Sstevel@tonic-gate if (rv) { 3817*0Sstevel@tonic-gate PR_ALL("%s: errno %d, ecode %d during detach\n", 3818*0Sstevel@tonic-gate f, SBD_GET_ERRNO(SBD_HD2ERR(hp)), 3819*0Sstevel@tonic-gate SBD_GET_ERR(HD2MACHERR(hp))); 3820*0Sstevel@tonic-gate } 3821*0Sstevel@tonic-gate 3822*0Sstevel@tonic-gate if (max_units && devlist) { 3823*0Sstevel@tonic-gate int i; 3824*0Sstevel@tonic-gate 3825*0Sstevel@tonic-gate for (i = 0; i < max_units; i++) { 3826*0Sstevel@tonic-gate if (SBD_GET_ERRSTR(&devlist[i].dv_error)) { 3827*0Sstevel@tonic-gate SBD_FREE_ERR(&devlist[i].dv_error); 3828*0Sstevel@tonic-gate } else { 3829*0Sstevel@tonic-gate break; 3830*0Sstevel@tonic-gate } 3831*0Sstevel@tonic-gate } 3832*0Sstevel@tonic-gate FREESTRUCT(devlist, sbd_devlist_t, max_units); 3833*0Sstevel@tonic-gate } 3834*0Sstevel@tonic-gate 3835*0Sstevel@tonic-gate return (SBD_GET_ERRNO(SBD_HD2ERR(hp)) ? -1 : 0); 3836*0Sstevel@tonic-gate } 3837*0Sstevel@tonic-gate 3838*0Sstevel@tonic-gate /* 3839*0Sstevel@tonic-gate * Return the unit number of the respective dip if 3840*0Sstevel@tonic-gate * it's found to be attached. 3841*0Sstevel@tonic-gate */ 3842*0Sstevel@tonic-gate static int 3843*0Sstevel@tonic-gate sbd_check_unit_attached(sbd_board_t *sbp, dev_info_t *dip, int unit, 3844*0Sstevel@tonic-gate sbd_comp_type_t nodetype, sbderror_t *ep) 3845*0Sstevel@tonic-gate { 3846*0Sstevel@tonic-gate int rv = -1; 3847*0Sstevel@tonic-gate processorid_t cpuid; 3848*0Sstevel@tonic-gate uint64_t basepa, endpa; 3849*0Sstevel@tonic-gate struct memlist *ml; 3850*0Sstevel@tonic-gate extern struct memlist *phys_install; 3851*0Sstevel@tonic-gate sbdp_handle_t *hdp; 3852*0Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 3853*0Sstevel@tonic-gate static fn_t f = "sbd_check_unit_attached"; 3854*0Sstevel@tonic-gate 3855*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 3856*0Sstevel@tonic-gate 3857*0Sstevel@tonic-gate switch (nodetype) { 3858*0Sstevel@tonic-gate 3859*0Sstevel@tonic-gate case SBD_COMP_CPU: 3860*0Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 3861*0Sstevel@tonic-gate if (cpuid < 0) { 3862*0Sstevel@tonic-gate break; 3863*0Sstevel@tonic-gate } 3864*0Sstevel@tonic-gate mutex_enter(&cpu_lock); 3865*0Sstevel@tonic-gate if (cpu_get(cpuid) != NULL) 3866*0Sstevel@tonic-gate rv = unit; 3867*0Sstevel@tonic-gate mutex_exit(&cpu_lock); 3868*0Sstevel@tonic-gate break; 3869*0Sstevel@tonic-gate 3870*0Sstevel@tonic-gate case SBD_COMP_MEM: 3871*0Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) { 3872*0Sstevel@tonic-gate break; 3873*0Sstevel@tonic-gate } 3874*0Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, dip, &endpa)) { 3875*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f); 3876*0Sstevel@tonic-gate break; 3877*0Sstevel@tonic-gate } 3878*0Sstevel@tonic-gate 3879*0Sstevel@tonic-gate basepa &= ~(endpa - 1); 3880*0Sstevel@tonic-gate endpa += basepa; 3881*0Sstevel@tonic-gate /* 3882*0Sstevel@tonic-gate * Check if base address is in phys_install. 3883*0Sstevel@tonic-gate */ 3884*0Sstevel@tonic-gate memlist_read_lock(); 3885*0Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) 3886*0Sstevel@tonic-gate if ((endpa <= ml->address) || 3887*0Sstevel@tonic-gate (basepa >= (ml->address + ml->size))) 3888*0Sstevel@tonic-gate continue; 3889*0Sstevel@tonic-gate else 3890*0Sstevel@tonic-gate break; 3891*0Sstevel@tonic-gate memlist_read_unlock(); 3892*0Sstevel@tonic-gate if (ml != NULL) 3893*0Sstevel@tonic-gate rv = unit; 3894*0Sstevel@tonic-gate break; 3895*0Sstevel@tonic-gate 3896*0Sstevel@tonic-gate case SBD_COMP_IO: 3897*0Sstevel@tonic-gate { 3898*0Sstevel@tonic-gate dev_info_t *tdip, *pdip; 3899*0Sstevel@tonic-gate 3900*0Sstevel@tonic-gate tdip = dip; 3901*0Sstevel@tonic-gate 3902*0Sstevel@tonic-gate /* 3903*0Sstevel@tonic-gate * ddi_walk_devs() requires that topdip's parent be held. 3904*0Sstevel@tonic-gate */ 3905*0Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 3906*0Sstevel@tonic-gate if (pdip) { 3907*0Sstevel@tonic-gate ndi_hold_devi(pdip); 3908*0Sstevel@tonic-gate ndi_devi_enter(pdip, &rv); 3909*0Sstevel@tonic-gate } 3910*0Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, sbd_check_io_attached, 3911*0Sstevel@tonic-gate (void *)&tdip); 3912*0Sstevel@tonic-gate if (pdip) { 3913*0Sstevel@tonic-gate ndi_devi_exit(pdip, rv); 3914*0Sstevel@tonic-gate ndi_rele_devi(pdip); 3915*0Sstevel@tonic-gate } 3916*0Sstevel@tonic-gate 3917*0Sstevel@tonic-gate if (tdip == NULL) 3918*0Sstevel@tonic-gate rv = unit; 3919*0Sstevel@tonic-gate else 3920*0Sstevel@tonic-gate rv = -1; 3921*0Sstevel@tonic-gate break; 3922*0Sstevel@tonic-gate } 3923*0Sstevel@tonic-gate 3924*0Sstevel@tonic-gate default: 3925*0Sstevel@tonic-gate PR_ALL("%s: unexpected nodetype(%d) for dip 0x%p\n", 3926*0Sstevel@tonic-gate f, nodetype, (void *)dip); 3927*0Sstevel@tonic-gate rv = -1; 3928*0Sstevel@tonic-gate break; 3929*0Sstevel@tonic-gate } 3930*0Sstevel@tonic-gate 3931*0Sstevel@tonic-gate /* 3932*0Sstevel@tonic-gate * Save the error that sbdp sent us and report it 3933*0Sstevel@tonic-gate */ 3934*0Sstevel@tonic-gate if (rv == -1) 3935*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, ep); 3936*0Sstevel@tonic-gate 3937*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3938*0Sstevel@tonic-gate 3939*0Sstevel@tonic-gate return (rv); 3940*0Sstevel@tonic-gate } 3941*0Sstevel@tonic-gate 3942*0Sstevel@tonic-gate /* 3943*0Sstevel@tonic-gate * Return memhandle, if in fact, this memunit is the owner of 3944*0Sstevel@tonic-gate * a scheduled memory delete. 3945*0Sstevel@tonic-gate */ 3946*0Sstevel@tonic-gate int 3947*0Sstevel@tonic-gate sbd_get_memhandle(sbd_handle_t *hp, dev_info_t *dip, memhandle_t *mhp) 3948*0Sstevel@tonic-gate { 3949*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 3950*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 3951*0Sstevel@tonic-gate sbdp_handle_t *hdp; 3952*0Sstevel@tonic-gate int unit; 3953*0Sstevel@tonic-gate static fn_t f = "sbd_get_memhandle"; 3954*0Sstevel@tonic-gate 3955*0Sstevel@tonic-gate PR_MEM("%s...\n", f); 3956*0Sstevel@tonic-gate 3957*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 3958*0Sstevel@tonic-gate 3959*0Sstevel@tonic-gate unit = sbdp_get_unit_num(hdp, dip); 3960*0Sstevel@tonic-gate if (unit == -1) { 3961*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 3962*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3963*0Sstevel@tonic-gate return (-1); 3964*0Sstevel@tonic-gate } 3965*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 3966*0Sstevel@tonic-gate 3967*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, unit); 3968*0Sstevel@tonic-gate 3969*0Sstevel@tonic-gate if (mp->sbm_flags & SBD_MFLAG_RELOWNER) { 3970*0Sstevel@tonic-gate *mhp = mp->sbm_memhandle; 3971*0Sstevel@tonic-gate return (0); 3972*0Sstevel@tonic-gate } else { 3973*0Sstevel@tonic-gate SBD_SET_ERR(SBD_HD2ERR(hp), ESBD_INTERNAL); 3974*0Sstevel@tonic-gate SBD_SET_ERRSTR(SBD_HD2ERR(hp), sbp->sb_mempath[unit]); 3975*0Sstevel@tonic-gate return (-1); 3976*0Sstevel@tonic-gate } 3977*0Sstevel@tonic-gate /*NOTREACHED*/ 3978*0Sstevel@tonic-gate } 3979*0Sstevel@tonic-gate 3980*0Sstevel@tonic-gate 3981*0Sstevel@tonic-gate static int 3982*0Sstevel@tonic-gate sbd_cpu_cnt(sbd_handle_t *hp, sbd_devset_t devset) 3983*0Sstevel@tonic-gate { 3984*0Sstevel@tonic-gate int c, cix; 3985*0Sstevel@tonic-gate sbd_board_t *sbp; 3986*0Sstevel@tonic-gate 3987*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 3988*0Sstevel@tonic-gate 3989*0Sstevel@tonic-gate /* 3990*0Sstevel@tonic-gate * Only look for requested devices that are actually present. 3991*0Sstevel@tonic-gate */ 3992*0Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 3993*0Sstevel@tonic-gate 3994*0Sstevel@tonic-gate for (c = cix = 0; c < MAX_CMP_UNITS_PER_BOARD; c++) { 3995*0Sstevel@tonic-gate /* 3996*0Sstevel@tonic-gate * Index for core 1 , if exists. 3997*0Sstevel@tonic-gate * With the current implementation it is 3998*0Sstevel@tonic-gate * MAX_CMP_UNITS_PER_BOARD off from core 0. 3999*0Sstevel@tonic-gate * The calculation will need to change if 4000*0Sstevel@tonic-gate * the assumption is no longer true. 4001*0Sstevel@tonic-gate */ 4002*0Sstevel@tonic-gate int c1 = c + MAX_CMP_UNITS_PER_BOARD; 4003*0Sstevel@tonic-gate 4004*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CMP, c) == 0) { 4005*0Sstevel@tonic-gate continue; 4006*0Sstevel@tonic-gate } 4007*0Sstevel@tonic-gate 4008*0Sstevel@tonic-gate /* 4009*0Sstevel@tonic-gate * Check to see if the dip(s) exist for this chip 4010*0Sstevel@tonic-gate */ 4011*0Sstevel@tonic-gate if ((sbp->sb_devlist[NIX(SBD_COMP_CMP)][c] == NULL) && 4012*0Sstevel@tonic-gate (sbp->sb_devlist[NIX(SBD_COMP_CMP)][c1] == NULL)) 4013*0Sstevel@tonic-gate continue; 4014*0Sstevel@tonic-gate 4015*0Sstevel@tonic-gate cix++; 4016*0Sstevel@tonic-gate } 4017*0Sstevel@tonic-gate 4018*0Sstevel@tonic-gate return (cix); 4019*0Sstevel@tonic-gate } 4020*0Sstevel@tonic-gate 4021*0Sstevel@tonic-gate static int 4022*0Sstevel@tonic-gate sbd_mem_cnt(sbd_handle_t *hp, sbd_devset_t devset) 4023*0Sstevel@tonic-gate { 4024*0Sstevel@tonic-gate int i, ix; 4025*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 4026*0Sstevel@tonic-gate 4027*0Sstevel@tonic-gate /* 4028*0Sstevel@tonic-gate * Only look for requested devices that are actually present. 4029*0Sstevel@tonic-gate */ 4030*0Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 4031*0Sstevel@tonic-gate 4032*0Sstevel@tonic-gate for (i = ix = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4033*0Sstevel@tonic-gate dev_info_t *dip; 4034*0Sstevel@tonic-gate 4035*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, i) == 0) { 4036*0Sstevel@tonic-gate continue; 4037*0Sstevel@tonic-gate } 4038*0Sstevel@tonic-gate 4039*0Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i]; 4040*0Sstevel@tonic-gate if (dip == NULL) 4041*0Sstevel@tonic-gate continue; 4042*0Sstevel@tonic-gate 4043*0Sstevel@tonic-gate ix++; 4044*0Sstevel@tonic-gate } 4045*0Sstevel@tonic-gate 4046*0Sstevel@tonic-gate return (ix); 4047*0Sstevel@tonic-gate } 4048*0Sstevel@tonic-gate 4049*0Sstevel@tonic-gate /* 4050*0Sstevel@tonic-gate * NOTE: This routine is only partially smart about multiple 4051*0Sstevel@tonic-gate * mem-units. Need to make mem-status structure smart 4052*0Sstevel@tonic-gate * about them also. 4053*0Sstevel@tonic-gate */ 4054*0Sstevel@tonic-gate static int 4055*0Sstevel@tonic-gate sbd_mem_status(sbd_handle_t *hp, sbd_devset_t devset, sbd_dev_stat_t *dsp) 4056*0Sstevel@tonic-gate { 4057*0Sstevel@tonic-gate int m, mix, rv; 4058*0Sstevel@tonic-gate memdelstat_t mdst; 4059*0Sstevel@tonic-gate memquery_t mq; 4060*0Sstevel@tonic-gate sbd_board_t *sbp; 4061*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 4062*0Sstevel@tonic-gate sbd_mem_stat_t *msp; 4063*0Sstevel@tonic-gate extern int kcage_on; 4064*0Sstevel@tonic-gate int i; 4065*0Sstevel@tonic-gate static fn_t f = "sbd_mem_status"; 4066*0Sstevel@tonic-gate 4067*0Sstevel@tonic-gate sbp = SBDH2BD(hp->h_sbd); 4068*0Sstevel@tonic-gate 4069*0Sstevel@tonic-gate /* 4070*0Sstevel@tonic-gate * Check the present devset and access the dip with 4071*0Sstevel@tonic-gate * status lock held to protect agains a concurrent 4072*0Sstevel@tonic-gate * unconfigure or disconnect thread. 4073*0Sstevel@tonic-gate */ 4074*0Sstevel@tonic-gate mutex_enter(&sbp->sb_slock); 4075*0Sstevel@tonic-gate 4076*0Sstevel@tonic-gate /* 4077*0Sstevel@tonic-gate * Only look for requested devices that are actually present. 4078*0Sstevel@tonic-gate */ 4079*0Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 4080*0Sstevel@tonic-gate 4081*0Sstevel@tonic-gate for (m = mix = 0; m < MAX_MEM_UNITS_PER_BOARD; m++) { 4082*0Sstevel@tonic-gate dev_info_t *dip; 4083*0Sstevel@tonic-gate 4084*0Sstevel@tonic-gate 4085*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, m) == 0) 4086*0Sstevel@tonic-gate continue; 4087*0Sstevel@tonic-gate 4088*0Sstevel@tonic-gate /* 4089*0Sstevel@tonic-gate * Check to make sure the memory unit is in a state 4090*0Sstevel@tonic-gate * where its fully initialized. 4091*0Sstevel@tonic-gate */ 4092*0Sstevel@tonic-gate if (SBD_DEVICE_STATE(sbp, SBD_COMP_MEM, m) == SBD_STATE_EMPTY) 4093*0Sstevel@tonic-gate continue; 4094*0Sstevel@tonic-gate 4095*0Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][m]; 4096*0Sstevel@tonic-gate if (dip == NULL) 4097*0Sstevel@tonic-gate continue; 4098*0Sstevel@tonic-gate 4099*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, m); 4100*0Sstevel@tonic-gate 4101*0Sstevel@tonic-gate msp = &dsp->d_mem; 4102*0Sstevel@tonic-gate 4103*0Sstevel@tonic-gate bzero((caddr_t)msp, sizeof (*msp)); 4104*0Sstevel@tonic-gate msp->ms_type = SBD_COMP_MEM; 4105*0Sstevel@tonic-gate 4106*0Sstevel@tonic-gate /* 4107*0Sstevel@tonic-gate * The plugin expects -1 for the mem unit 4108*0Sstevel@tonic-gate */ 4109*0Sstevel@tonic-gate msp->ms_cm.c_id.c_unit = -1; 4110*0Sstevel@tonic-gate 4111*0Sstevel@tonic-gate /* 4112*0Sstevel@tonic-gate * Get the memory name from what sbdp gave us 4113*0Sstevel@tonic-gate */ 4114*0Sstevel@tonic-gate for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 4115*0Sstevel@tonic-gate if (SBD_COMP(i) == SBD_COMP_MEM) { 4116*0Sstevel@tonic-gate (void) strcpy(msp->ms_name, SBD_DEVNAME(i)); 4117*0Sstevel@tonic-gate } 4118*0Sstevel@tonic-gate } 4119*0Sstevel@tonic-gate msp->ms_cm.c_cond = mp->sbm_cm.sbdev_cond; 4120*0Sstevel@tonic-gate msp->ms_cm.c_busy = mp->sbm_cm.sbdev_busy; 4121*0Sstevel@tonic-gate msp->ms_cm.c_time = mp->sbm_cm.sbdev_time; 4122*0Sstevel@tonic-gate 4123*0Sstevel@tonic-gate /* XXX revisit this after memory conversion */ 4124*0Sstevel@tonic-gate msp->ms_ostate = ostate_cvt(SBD_DEVICE_STATE( 4125*0Sstevel@tonic-gate sbp, SBD_COMP_MEM, m)); 4126*0Sstevel@tonic-gate 4127*0Sstevel@tonic-gate msp->ms_basepfn = mp->sbm_basepfn; 4128*0Sstevel@tonic-gate msp->ms_pageslost = mp->sbm_pageslost; 4129*0Sstevel@tonic-gate msp->ms_cage_enabled = kcage_on; 4130*0Sstevel@tonic-gate msp->ms_interleave = mp->sbm_interleave; 4131*0Sstevel@tonic-gate 4132*0Sstevel@tonic-gate if (mp->sbm_flags & SBD_MFLAG_RELOWNER) 4133*0Sstevel@tonic-gate rv = kphysm_del_status(mp->sbm_memhandle, &mdst); 4134*0Sstevel@tonic-gate else 4135*0Sstevel@tonic-gate rv = KPHYSM_EHANDLE; /* force 'if' to fail */ 4136*0Sstevel@tonic-gate 4137*0Sstevel@tonic-gate if (rv == KPHYSM_OK) { 4138*0Sstevel@tonic-gate msp->ms_totpages += mdst.phys_pages; 4139*0Sstevel@tonic-gate 4140*0Sstevel@tonic-gate /* 4141*0Sstevel@tonic-gate * Any pages above managed is "free", 4142*0Sstevel@tonic-gate * i.e. it's collected. 4143*0Sstevel@tonic-gate */ 4144*0Sstevel@tonic-gate msp->ms_detpages += (uint_t)(mdst.collected + 4145*0Sstevel@tonic-gate mdst.phys_pages - 4146*0Sstevel@tonic-gate mdst.managed); 4147*0Sstevel@tonic-gate } else { 4148*0Sstevel@tonic-gate msp->ms_totpages += (uint_t)mp->sbm_npages; 4149*0Sstevel@tonic-gate 4150*0Sstevel@tonic-gate /* 4151*0Sstevel@tonic-gate * If we're UNREFERENCED or UNCONFIGURED, 4152*0Sstevel@tonic-gate * then the number of detached pages is 4153*0Sstevel@tonic-gate * however many pages are on the board. 4154*0Sstevel@tonic-gate * I.e. detached = not in use by OS. 4155*0Sstevel@tonic-gate */ 4156*0Sstevel@tonic-gate switch (msp->ms_cm.c_ostate) { 4157*0Sstevel@tonic-gate /* 4158*0Sstevel@tonic-gate * changed to use cfgadm states 4159*0Sstevel@tonic-gate * 4160*0Sstevel@tonic-gate * was: 4161*0Sstevel@tonic-gate * case SFDR_STATE_UNREFERENCED: 4162*0Sstevel@tonic-gate * case SFDR_STATE_UNCONFIGURED: 4163*0Sstevel@tonic-gate */ 4164*0Sstevel@tonic-gate case SBD_STAT_UNCONFIGURED: 4165*0Sstevel@tonic-gate msp->ms_detpages = msp->ms_totpages; 4166*0Sstevel@tonic-gate break; 4167*0Sstevel@tonic-gate 4168*0Sstevel@tonic-gate default: 4169*0Sstevel@tonic-gate break; 4170*0Sstevel@tonic-gate } 4171*0Sstevel@tonic-gate } 4172*0Sstevel@tonic-gate 4173*0Sstevel@tonic-gate rv = kphysm_del_span_query(mp->sbm_basepfn, 4174*0Sstevel@tonic-gate mp->sbm_npages, &mq); 4175*0Sstevel@tonic-gate if (rv == KPHYSM_OK) { 4176*0Sstevel@tonic-gate msp->ms_managed_pages = mq.managed; 4177*0Sstevel@tonic-gate msp->ms_noreloc_pages = mq.nonrelocatable; 4178*0Sstevel@tonic-gate msp->ms_noreloc_first = mq.first_nonrelocatable; 4179*0Sstevel@tonic-gate msp->ms_noreloc_last = mq.last_nonrelocatable; 4180*0Sstevel@tonic-gate msp->ms_cm.c_sflags = 0; 4181*0Sstevel@tonic-gate if (mq.nonrelocatable) { 4182*0Sstevel@tonic-gate SBD_SET_SUSPEND(SBD_CMD_UNCONFIGURE, 4183*0Sstevel@tonic-gate dsp->ds_suspend); 4184*0Sstevel@tonic-gate } 4185*0Sstevel@tonic-gate } else { 4186*0Sstevel@tonic-gate PR_MEM("%s: kphysm_del_span_query() = %d\n", f, rv); 4187*0Sstevel@tonic-gate } 4188*0Sstevel@tonic-gate 4189*0Sstevel@tonic-gate mix++; 4190*0Sstevel@tonic-gate dsp++; 4191*0Sstevel@tonic-gate } 4192*0Sstevel@tonic-gate 4193*0Sstevel@tonic-gate mutex_exit(&sbp->sb_slock); 4194*0Sstevel@tonic-gate 4195*0Sstevel@tonic-gate return (mix); 4196*0Sstevel@tonic-gate } 4197*0Sstevel@tonic-gate 4198*0Sstevel@tonic-gate static void 4199*0Sstevel@tonic-gate sbd_cancel(sbd_handle_t *hp) 4200*0Sstevel@tonic-gate { 4201*0Sstevel@tonic-gate int i; 4202*0Sstevel@tonic-gate sbd_devset_t devset; 4203*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 4204*0Sstevel@tonic-gate static fn_t f = "sbd_cancel"; 4205*0Sstevel@tonic-gate int rv; 4206*0Sstevel@tonic-gate 4207*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 4208*0Sstevel@tonic-gate 4209*0Sstevel@tonic-gate /* 4210*0Sstevel@tonic-gate * Only devices which have been "released" are 4211*0Sstevel@tonic-gate * subject to cancellation. 4212*0Sstevel@tonic-gate */ 4213*0Sstevel@tonic-gate devset = HD2MACHHD(hp)->sh_devset & SBD_DEVS_UNREFERENCED(sbp); 4214*0Sstevel@tonic-gate 4215*0Sstevel@tonic-gate /* 4216*0Sstevel@tonic-gate * Nothing to do for CPUs or IO other than change back 4217*0Sstevel@tonic-gate * their state. 4218*0Sstevel@tonic-gate */ 4219*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 4220*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) 4221*0Sstevel@tonic-gate continue; 4222*0Sstevel@tonic-gate if (sbd_cancel_cpu(hp, i) != SBD_CPUERR_FATAL) { 4223*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 4224*0Sstevel@tonic-gate SBD_STATE_CONFIGURED); 4225*0Sstevel@tonic-gate } else { 4226*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, i, 4227*0Sstevel@tonic-gate SBD_STATE_FATAL); 4228*0Sstevel@tonic-gate } 4229*0Sstevel@tonic-gate } 4230*0Sstevel@tonic-gate 4231*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 4232*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i)) 4233*0Sstevel@tonic-gate continue; 4234*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, i, 4235*0Sstevel@tonic-gate SBD_STATE_CONFIGURED); 4236*0Sstevel@tonic-gate } 4237*0Sstevel@tonic-gate 4238*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4239*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) 4240*0Sstevel@tonic-gate continue; 4241*0Sstevel@tonic-gate if ((rv = sbd_cancel_mem(hp, i)) == 0) { 4242*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 4243*0Sstevel@tonic-gate SBD_STATE_CONFIGURED); 4244*0Sstevel@tonic-gate } else if (rv == -1) { 4245*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, i, 4246*0Sstevel@tonic-gate SBD_STATE_FATAL); 4247*0Sstevel@tonic-gate } 4248*0Sstevel@tonic-gate } 4249*0Sstevel@tonic-gate 4250*0Sstevel@tonic-gate PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset); 4251*0Sstevel@tonic-gate 4252*0Sstevel@tonic-gate SBD_DEVS_CANCEL(sbp, devset); 4253*0Sstevel@tonic-gate 4254*0Sstevel@tonic-gate if (SBD_DEVS_UNREFERENCED(sbp) == 0) { 4255*0Sstevel@tonic-gate sbd_istate_t new_state; 4256*0Sstevel@tonic-gate /* 4257*0Sstevel@tonic-gate * If the board no longer has any released devices 4258*0Sstevel@tonic-gate * than transfer it back to the CONFIG/PARTIAL state. 4259*0Sstevel@tonic-gate */ 4260*0Sstevel@tonic-gate if (SBD_DEVS_ATTACHED(sbp) == SBD_DEVS_PRESENT(sbp)) 4261*0Sstevel@tonic-gate new_state = SBD_STATE_CONFIGURED; 4262*0Sstevel@tonic-gate else 4263*0Sstevel@tonic-gate new_state = SBD_STATE_PARTIAL; 4264*0Sstevel@tonic-gate if (SBD_BOARD_STATE(sbp) != new_state) { 4265*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, new_state); 4266*0Sstevel@tonic-gate } 4267*0Sstevel@tonic-gate sbp->sb_ostate = SBD_STAT_CONFIGURED; 4268*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&sbp->sb_time); 4269*0Sstevel@tonic-gate } 4270*0Sstevel@tonic-gate } 4271*0Sstevel@tonic-gate 4272*0Sstevel@tonic-gate static void 4273*0Sstevel@tonic-gate sbd_get_ncm(sbd_handle_t *hp) 4274*0Sstevel@tonic-gate { 4275*0Sstevel@tonic-gate sbd_devset_t devset; 4276*0Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 4277*0Sstevel@tonic-gate sbd_cmd_t *cmdp = (sbd_cmd_t *)hp->h_iap; 4278*0Sstevel@tonic-gate int error; 4279*0Sstevel@tonic-gate 4280*0Sstevel@tonic-gate /* pre_op restricted the devices to those selected by the ioctl */ 4281*0Sstevel@tonic-gate devset = shp->sh_devset; 4282*0Sstevel@tonic-gate 4283*0Sstevel@tonic-gate cmdp->cmd_getncm.g_ncm = sbd_cpu_cnt(hp, devset) 4284*0Sstevel@tonic-gate + sbd_io_cnt(hp, devset) + sbd_mem_cnt(hp, devset); 4285*0Sstevel@tonic-gate 4286*0Sstevel@tonic-gate error = sbd_copyout_ioarg(hp->h_mode, hp->h_cmd, cmdp, 4287*0Sstevel@tonic-gate (sbd_ioctl_arg_t *)shp->sh_arg); 4288*0Sstevel@tonic-gate 4289*0Sstevel@tonic-gate if (error != 0) 4290*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), error); 4291*0Sstevel@tonic-gate } 4292*0Sstevel@tonic-gate 4293*0Sstevel@tonic-gate static void 4294*0Sstevel@tonic-gate sbd_status(sbd_handle_t *hp) 4295*0Sstevel@tonic-gate { 4296*0Sstevel@tonic-gate int nstat, mode, ncm, sz, cksz; 4297*0Sstevel@tonic-gate sbd_priv_handle_t *shp = HD2MACHHD(hp); 4298*0Sstevel@tonic-gate sbd_devset_t devset; 4299*0Sstevel@tonic-gate sbd_board_t *sbp = SBDH2BD(hp->h_sbd); 4300*0Sstevel@tonic-gate sbd_stat_t *dstatp; 4301*0Sstevel@tonic-gate sbd_cmd_t *cmdp = (sbd_cmd_t *)hp->h_iap; 4302*0Sstevel@tonic-gate sbdp_handle_t *hdp; 4303*0Sstevel@tonic-gate sbd_dev_stat_t *devstatp; 4304*0Sstevel@tonic-gate 4305*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4306*0Sstevel@tonic-gate int sz32; 4307*0Sstevel@tonic-gate sbd_stat32_t *dstat32p; 4308*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 4309*0Sstevel@tonic-gate 4310*0Sstevel@tonic-gate static fn_t f = "sbd_status"; 4311*0Sstevel@tonic-gate 4312*0Sstevel@tonic-gate mode = hp->h_mode; 4313*0Sstevel@tonic-gate devset = shp->sh_devset; 4314*0Sstevel@tonic-gate 4315*0Sstevel@tonic-gate devset &= SBD_DEVS_PRESENT(sbp); 4316*0Sstevel@tonic-gate 4317*0Sstevel@tonic-gate if (cmdp->cmd_cm.c_id.c_type == SBD_COMP_NONE) { 4318*0Sstevel@tonic-gate if (cmdp->cmd_cm.c_flags & SBD_FLAG_ALLCMP) { 4319*0Sstevel@tonic-gate /* 4320*0Sstevel@tonic-gate * Get the number of components "ncm" on the board. 4321*0Sstevel@tonic-gate * Calculate size of buffer required to store one 4322*0Sstevel@tonic-gate * sbd_stat_t structure plus ncm-1 sbd_dev_stat_t 4323*0Sstevel@tonic-gate * structures. Note that sbd_stat_t already contains 4324*0Sstevel@tonic-gate * one sbd_dev_stat_t, so only an additional ncm-1 4325*0Sstevel@tonic-gate * sbd_dev_stat_t structures need to be accounted for 4326*0Sstevel@tonic-gate * in the calculation when more than one component 4327*0Sstevel@tonic-gate * is present. 4328*0Sstevel@tonic-gate */ 4329*0Sstevel@tonic-gate ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) + 4330*0Sstevel@tonic-gate sbd_mem_cnt(hp, devset); 4331*0Sstevel@tonic-gate 4332*0Sstevel@tonic-gate } else { 4333*0Sstevel@tonic-gate /* 4334*0Sstevel@tonic-gate * In the case of c_type == SBD_COMP_NONE, and 4335*0Sstevel@tonic-gate * SBD_FLAG_ALLCMP not specified, only the board 4336*0Sstevel@tonic-gate * info is to be returned, no components. 4337*0Sstevel@tonic-gate */ 4338*0Sstevel@tonic-gate ncm = 0; 4339*0Sstevel@tonic-gate devset = 0; 4340*0Sstevel@tonic-gate } 4341*0Sstevel@tonic-gate } else { 4342*0Sstevel@tonic-gate /* Confirm that only one component is selected. */ 4343*0Sstevel@tonic-gate ncm = sbd_cpu_cnt(hp, devset) + sbd_io_cnt(hp, devset) + 4344*0Sstevel@tonic-gate sbd_mem_cnt(hp, devset); 4345*0Sstevel@tonic-gate if (ncm != 1) { 4346*0Sstevel@tonic-gate PR_ALL("%s: expected ncm of 1, got %d, devset 0x%x\n", 4347*0Sstevel@tonic-gate f, ncm, devset); 4348*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4349*0Sstevel@tonic-gate return; 4350*0Sstevel@tonic-gate } 4351*0Sstevel@tonic-gate } 4352*0Sstevel@tonic-gate 4353*0Sstevel@tonic-gate sz = sizeof (sbd_stat_t); 4354*0Sstevel@tonic-gate if (ncm > 1) 4355*0Sstevel@tonic-gate sz += sizeof (sbd_dev_stat_t) * (ncm - 1); 4356*0Sstevel@tonic-gate 4357*0Sstevel@tonic-gate cksz = sz; 4358*0Sstevel@tonic-gate 4359*0Sstevel@tonic-gate /* 4360*0Sstevel@tonic-gate * s_nbytes describes the size of the preallocated user 4361*0Sstevel@tonic-gate * buffer into which the application is executing to 4362*0Sstevel@tonic-gate * receive the sbd_stat_t and sbd_dev_stat_t structures. 4363*0Sstevel@tonic-gate * This buffer must be at least the required (sz) size. 4364*0Sstevel@tonic-gate */ 4365*0Sstevel@tonic-gate 4366*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4367*0Sstevel@tonic-gate 4368*0Sstevel@tonic-gate /* 4369*0Sstevel@tonic-gate * More buffer space is required for the 64bit to 32bit 4370*0Sstevel@tonic-gate * conversion of data structures. 4371*0Sstevel@tonic-gate */ 4372*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 4373*0Sstevel@tonic-gate sz32 = sizeof (sbd_stat32_t); 4374*0Sstevel@tonic-gate if (ncm > 1) 4375*0Sstevel@tonic-gate sz32 += sizeof (sbd_dev_stat32_t) * (ncm - 1); 4376*0Sstevel@tonic-gate cksz = sz32; 4377*0Sstevel@tonic-gate } else 4378*0Sstevel@tonic-gate sz32 = 0; 4379*0Sstevel@tonic-gate #endif 4380*0Sstevel@tonic-gate 4381*0Sstevel@tonic-gate if ((int)cmdp->cmd_stat.s_nbytes < cksz) { 4382*0Sstevel@tonic-gate PR_ALL("%s: ncm=%d s_nbytes = 0x%x\n", f, ncm, 4383*0Sstevel@tonic-gate cmdp->cmd_stat.s_nbytes); 4384*0Sstevel@tonic-gate PR_ALL("%s: expected size of 0x%x\n", f, cksz); 4385*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4386*0Sstevel@tonic-gate return; 4387*0Sstevel@tonic-gate } 4388*0Sstevel@tonic-gate 4389*0Sstevel@tonic-gate dstatp = kmem_zalloc(sz, KM_SLEEP); 4390*0Sstevel@tonic-gate devstatp = &dstatp->s_stat[0]; 4391*0Sstevel@tonic-gate 4392*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4393*0Sstevel@tonic-gate if (sz32 != 0) 4394*0Sstevel@tonic-gate dstat32p = kmem_zalloc(sz32, KM_SLEEP); 4395*0Sstevel@tonic-gate #endif 4396*0Sstevel@tonic-gate 4397*0Sstevel@tonic-gate /* 4398*0Sstevel@tonic-gate * if connected or better, provide cached status if available, 4399*0Sstevel@tonic-gate * otherwise call sbdp for status 4400*0Sstevel@tonic-gate */ 4401*0Sstevel@tonic-gate mutex_enter(&sbp->sb_flags_mutex); 4402*0Sstevel@tonic-gate switch (sbp->sb_state) { 4403*0Sstevel@tonic-gate 4404*0Sstevel@tonic-gate case SBD_STATE_CONNECTED: 4405*0Sstevel@tonic-gate case SBD_STATE_PARTIAL: 4406*0Sstevel@tonic-gate case SBD_STATE_CONFIGURED: 4407*0Sstevel@tonic-gate if (sbp->sb_flags & SBD_BOARD_STATUS_CACHED) { 4408*0Sstevel@tonic-gate bcopy(&sbp->sb_stat, dstatp, sizeof (sbd_stat_t)); 4409*0Sstevel@tonic-gate dstatp->s_rstate = rstate_cvt(sbp->sb_state); 4410*0Sstevel@tonic-gate dstatp->s_ostate = ostate_cvt(sbp->sb_state); 4411*0Sstevel@tonic-gate dstatp->s_busy = sbp->sb_busy; 4412*0Sstevel@tonic-gate dstatp->s_time = sbp->sb_time; 4413*0Sstevel@tonic-gate dstatp->s_cond = sbp->sb_cond; 4414*0Sstevel@tonic-gate break; 4415*0Sstevel@tonic-gate } 4416*0Sstevel@tonic-gate /*FALLTHROUGH*/ 4417*0Sstevel@tonic-gate 4418*0Sstevel@tonic-gate default: 4419*0Sstevel@tonic-gate sbp->sb_flags &= ~SBD_BOARD_STATUS_CACHED; 4420*0Sstevel@tonic-gate dstatp->s_board = sbp->sb_num; 4421*0Sstevel@tonic-gate dstatp->s_ostate = ostate_cvt(sbp->sb_state); 4422*0Sstevel@tonic-gate dstatp->s_time = sbp->sb_time; 4423*0Sstevel@tonic-gate 4424*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 4425*0Sstevel@tonic-gate 4426*0Sstevel@tonic-gate if (sbdp_get_board_status(hdp, dstatp) != 0) { 4427*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, SBD_HD2ERR(hp)); 4428*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 4429*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4430*0Sstevel@tonic-gate if (sz32 != 0) 4431*0Sstevel@tonic-gate kmem_free(dstat32p, sz32); 4432*0Sstevel@tonic-gate #endif 4433*0Sstevel@tonic-gate kmem_free(dstatp, sz); 4434*0Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 4435*0Sstevel@tonic-gate return; 4436*0Sstevel@tonic-gate } 4437*0Sstevel@tonic-gate /* 4438*0Sstevel@tonic-gate * Do not cache status if the busy flag has 4439*0Sstevel@tonic-gate * been set by the call to sbdp_get_board_status(). 4440*0Sstevel@tonic-gate */ 4441*0Sstevel@tonic-gate if (!dstatp->s_busy) { 4442*0Sstevel@tonic-gate /* Can get board busy flag now */ 4443*0Sstevel@tonic-gate dstatp->s_busy = sbp->sb_busy; 4444*0Sstevel@tonic-gate sbp->sb_cond = (sbd_cond_t)dstatp->s_cond; 4445*0Sstevel@tonic-gate bcopy(dstatp, &sbp->sb_stat, 4446*0Sstevel@tonic-gate sizeof (sbd_stat_t)); 4447*0Sstevel@tonic-gate sbp->sb_flags |= SBD_BOARD_STATUS_CACHED; 4448*0Sstevel@tonic-gate } 4449*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 4450*0Sstevel@tonic-gate break; 4451*0Sstevel@tonic-gate } 4452*0Sstevel@tonic-gate mutex_exit(&sbp->sb_flags_mutex); 4453*0Sstevel@tonic-gate 4454*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) 4455*0Sstevel@tonic-gate if ((nstat = sbd_cpu_flags(hp, devset, devstatp)) > 0) { 4456*0Sstevel@tonic-gate dstatp->s_nstat += nstat; 4457*0Sstevel@tonic-gate devstatp += nstat; 4458*0Sstevel@tonic-gate } 4459*0Sstevel@tonic-gate 4460*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) 4461*0Sstevel@tonic-gate if ((nstat = sbd_mem_status(hp, devset, devstatp)) > 0) { 4462*0Sstevel@tonic-gate dstatp->s_nstat += nstat; 4463*0Sstevel@tonic-gate devstatp += nstat; 4464*0Sstevel@tonic-gate } 4465*0Sstevel@tonic-gate 4466*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) 4467*0Sstevel@tonic-gate if ((nstat = sbd_io_status(hp, devset, devstatp)) > 0) { 4468*0Sstevel@tonic-gate dstatp->s_nstat += nstat; 4469*0Sstevel@tonic-gate devstatp += nstat; 4470*0Sstevel@tonic-gate } 4471*0Sstevel@tonic-gate 4472*0Sstevel@tonic-gate /* paranoia: detect buffer overrun */ 4473*0Sstevel@tonic-gate if ((caddr_t)devstatp > ((caddr_t)dstatp) + sz) { 4474*0Sstevel@tonic-gate PR_ALL("%s: buffer overrun\n", f); 4475*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4476*0Sstevel@tonic-gate if (sz32 != 0) 4477*0Sstevel@tonic-gate kmem_free(dstat32p, sz32); 4478*0Sstevel@tonic-gate #endif 4479*0Sstevel@tonic-gate kmem_free(dstatp, sz); 4480*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4481*0Sstevel@tonic-gate return; 4482*0Sstevel@tonic-gate } 4483*0Sstevel@tonic-gate 4484*0Sstevel@tonic-gate /* if necessary, move data into intermediate device status buffer */ 4485*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4486*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 4487*0Sstevel@tonic-gate int i, j; 4488*0Sstevel@tonic-gate 4489*0Sstevel@tonic-gate ASSERT(sz32 != 0); 4490*0Sstevel@tonic-gate /* paranoia: detect buffer overrun */ 4491*0Sstevel@tonic-gate if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] > 4492*0Sstevel@tonic-gate ((caddr_t)dstat32p) + sz32) { 4493*0Sstevel@tonic-gate cmn_err(CE_WARN, 4494*0Sstevel@tonic-gate "sbd:%s: buffer32 overrun", f); 4495*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4496*0Sstevel@tonic-gate if (sz32 != 0) 4497*0Sstevel@tonic-gate kmem_free(dstat32p, sz32); 4498*0Sstevel@tonic-gate #endif 4499*0Sstevel@tonic-gate kmem_free(dstatp, sz); 4500*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EINVAL); 4501*0Sstevel@tonic-gate return; 4502*0Sstevel@tonic-gate } 4503*0Sstevel@tonic-gate 4504*0Sstevel@tonic-gate /* 4505*0Sstevel@tonic-gate * initialize 32 bit sbd board status structure 4506*0Sstevel@tonic-gate */ 4507*0Sstevel@tonic-gate dstat32p->s_board = (int32_t)dstatp->s_board; 4508*0Sstevel@tonic-gate dstat32p->s_nstat = (int32_t)dstatp->s_nstat; 4509*0Sstevel@tonic-gate dstat32p->s_rstate = dstatp->s_rstate; 4510*0Sstevel@tonic-gate dstat32p->s_ostate = dstatp->s_ostate; 4511*0Sstevel@tonic-gate dstat32p->s_cond = dstatp->s_cond; 4512*0Sstevel@tonic-gate dstat32p->s_busy = dstatp->s_busy; 4513*0Sstevel@tonic-gate dstat32p->s_time = dstatp->s_time; 4514*0Sstevel@tonic-gate dstat32p->s_assigned = dstatp->s_assigned; 4515*0Sstevel@tonic-gate dstat32p->s_power = dstatp->s_power; 4516*0Sstevel@tonic-gate dstat32p->s_platopts = (int32_t)dstatp->s_platopts; 4517*0Sstevel@tonic-gate (void) strcpy(dstat32p->s_type, dstatp->s_type); 4518*0Sstevel@tonic-gate 4519*0Sstevel@tonic-gate for (i = 0; i < dstatp->s_nstat; i++) { 4520*0Sstevel@tonic-gate sbd_dev_stat_t *dsp = &dstatp->s_stat[i]; 4521*0Sstevel@tonic-gate sbd_dev_stat32_t *ds32p = &dstat32p->s_stat[i]; 4522*0Sstevel@tonic-gate 4523*0Sstevel@tonic-gate /* 4524*0Sstevel@tonic-gate * copy common data for the device 4525*0Sstevel@tonic-gate */ 4526*0Sstevel@tonic-gate ds32p->d_cm.ci_type = (int32_t)dsp->d_cm.ci_type; 4527*0Sstevel@tonic-gate ds32p->d_cm.ci_unit = (int32_t)dsp->d_cm.ci_unit; 4528*0Sstevel@tonic-gate ds32p->d_cm.c_ostate = (int32_t)dsp->d_cm.c_ostate; 4529*0Sstevel@tonic-gate ds32p->d_cm.c_cond = (int32_t)dsp->d_cm.c_cond; 4530*0Sstevel@tonic-gate ds32p->d_cm.c_busy = (int32_t)dsp->d_cm.c_busy; 4531*0Sstevel@tonic-gate ds32p->d_cm.c_time = (time32_t)dsp->d_cm.c_time; 4532*0Sstevel@tonic-gate ds32p->d_cm.c_sflags = (int32_t)dsp->d_cm.c_sflags; 4533*0Sstevel@tonic-gate (void) strcpy(ds32p->d_cm.ci_name, dsp->d_cm.ci_name); 4534*0Sstevel@tonic-gate 4535*0Sstevel@tonic-gate /* copy type specific data for the device */ 4536*0Sstevel@tonic-gate switch (dsp->d_cm.ci_type) { 4537*0Sstevel@tonic-gate 4538*0Sstevel@tonic-gate case SBD_COMP_CPU: 4539*0Sstevel@tonic-gate ds32p->d_cpu.cs_isbootproc = 4540*0Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_isbootproc; 4541*0Sstevel@tonic-gate ds32p->d_cpu.cs_cpuid = 4542*0Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_cpuid; 4543*0Sstevel@tonic-gate ds32p->d_cpu.cs_speed = 4544*0Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_speed; 4545*0Sstevel@tonic-gate ds32p->d_cpu.cs_ecache = 4546*0Sstevel@tonic-gate (int32_t)dsp->d_cpu.cs_ecache; 4547*0Sstevel@tonic-gate break; 4548*0Sstevel@tonic-gate 4549*0Sstevel@tonic-gate case SBD_COMP_MEM: 4550*0Sstevel@tonic-gate ds32p->d_mem.ms_type = 4551*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_type; 4552*0Sstevel@tonic-gate ds32p->d_mem.ms_ostate = 4553*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_ostate; 4554*0Sstevel@tonic-gate ds32p->d_mem.ms_cond = 4555*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_cond; 4556*0Sstevel@tonic-gate ds32p->d_mem.ms_interleave = 4557*0Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_interleave; 4558*0Sstevel@tonic-gate ds32p->d_mem.ms_basepfn = 4559*0Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_basepfn; 4560*0Sstevel@tonic-gate ds32p->d_mem.ms_totpages = 4561*0Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_totpages; 4562*0Sstevel@tonic-gate ds32p->d_mem.ms_detpages = 4563*0Sstevel@tonic-gate (uint32_t)dsp->d_mem.ms_detpages; 4564*0Sstevel@tonic-gate ds32p->d_mem.ms_pageslost = 4565*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_pageslost; 4566*0Sstevel@tonic-gate ds32p->d_mem.ms_managed_pages = 4567*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_managed_pages; 4568*0Sstevel@tonic-gate ds32p->d_mem.ms_noreloc_pages = 4569*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_noreloc_pages; 4570*0Sstevel@tonic-gate ds32p->d_mem.ms_noreloc_first = 4571*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_noreloc_first; 4572*0Sstevel@tonic-gate ds32p->d_mem.ms_noreloc_last = 4573*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_noreloc_last; 4574*0Sstevel@tonic-gate ds32p->d_mem.ms_cage_enabled = 4575*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_cage_enabled; 4576*0Sstevel@tonic-gate ds32p->d_mem.ms_peer_is_target = 4577*0Sstevel@tonic-gate (int32_t)dsp->d_mem.ms_peer_is_target; 4578*0Sstevel@tonic-gate (void) strcpy(ds32p->d_mem.ms_peer_ap_id, 4579*0Sstevel@tonic-gate dsp->d_mem.ms_peer_ap_id); 4580*0Sstevel@tonic-gate break; 4581*0Sstevel@tonic-gate 4582*0Sstevel@tonic-gate 4583*0Sstevel@tonic-gate case SBD_COMP_IO: 4584*0Sstevel@tonic-gate 4585*0Sstevel@tonic-gate ds32p->d_io.is_type = 4586*0Sstevel@tonic-gate (int32_t)dsp->d_io.is_type; 4587*0Sstevel@tonic-gate ds32p->d_io.is_unsafe_count = 4588*0Sstevel@tonic-gate (int32_t)dsp->d_io.is_unsafe_count; 4589*0Sstevel@tonic-gate ds32p->d_io.is_referenced = 4590*0Sstevel@tonic-gate (int32_t)dsp->d_io.is_referenced; 4591*0Sstevel@tonic-gate for (j = 0; j < SBD_MAX_UNSAFE; j++) 4592*0Sstevel@tonic-gate ds32p->d_io.is_unsafe_list[j] = 4593*0Sstevel@tonic-gate (int32_t) 4594*0Sstevel@tonic-gate ds32p->d_io.is_unsafe_list[j]; 4595*0Sstevel@tonic-gate bcopy(dsp->d_io.is_pathname, 4596*0Sstevel@tonic-gate ds32p->d_io.is_pathname, MAXPATHLEN); 4597*0Sstevel@tonic-gate break; 4598*0Sstevel@tonic-gate 4599*0Sstevel@tonic-gate case SBD_COMP_CMP: 4600*0Sstevel@tonic-gate /* copy sbd_cmp_stat_t structure members */ 4601*0Sstevel@tonic-gate bcopy(&dsp->d_cmp.ps_cpuid[0], 4602*0Sstevel@tonic-gate &ds32p->d_cmp.ps_cpuid[0], 4603*0Sstevel@tonic-gate sizeof (ds32p->d_cmp.ps_cpuid)); 4604*0Sstevel@tonic-gate ds32p->d_cmp.ps_ncores = 4605*0Sstevel@tonic-gate (int32_t)dsp->d_cmp.ps_ncores; 4606*0Sstevel@tonic-gate ds32p->d_cmp.ps_speed = 4607*0Sstevel@tonic-gate (int32_t)dsp->d_cmp.ps_speed; 4608*0Sstevel@tonic-gate ds32p->d_cmp.ps_ecache = 4609*0Sstevel@tonic-gate (int32_t)dsp->d_cmp.ps_ecache; 4610*0Sstevel@tonic-gate break; 4611*0Sstevel@tonic-gate 4612*0Sstevel@tonic-gate default: 4613*0Sstevel@tonic-gate cmn_err(CE_WARN, 4614*0Sstevel@tonic-gate "sbd:%s: unknown dev type (%d)", f, 4615*0Sstevel@tonic-gate (int)dsp->d_cm.c_id.c_type); 4616*0Sstevel@tonic-gate break; 4617*0Sstevel@tonic-gate } 4618*0Sstevel@tonic-gate } 4619*0Sstevel@tonic-gate 4620*0Sstevel@tonic-gate if (ddi_copyout((void *)dstat32p, 4621*0Sstevel@tonic-gate cmdp->cmd_stat.s_statp, sz32, mode) != 0) { 4622*0Sstevel@tonic-gate cmn_err(CE_WARN, 4623*0Sstevel@tonic-gate "sbd:%s: failed to copyout status " 4624*0Sstevel@tonic-gate "for board %d", f, sbp->sb_num); 4625*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT); 4626*0Sstevel@tonic-gate } 4627*0Sstevel@tonic-gate } else 4628*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 4629*0Sstevel@tonic-gate if (ddi_copyout((void *)dstatp, cmdp->cmd_stat.s_statp, 4630*0Sstevel@tonic-gate sz, mode) != 0) { 4631*0Sstevel@tonic-gate cmn_err(CE_WARN, 4632*0Sstevel@tonic-gate "sbd:%s: failed to copyout status for board %d", 4633*0Sstevel@tonic-gate f, sbp->sb_num); 4634*0Sstevel@tonic-gate SBD_SET_ERRNO(SBD_HD2ERR(hp), EFAULT); 4635*0Sstevel@tonic-gate } 4636*0Sstevel@tonic-gate 4637*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 4638*0Sstevel@tonic-gate if (sz32 != 0) 4639*0Sstevel@tonic-gate kmem_free(dstat32p, sz32); 4640*0Sstevel@tonic-gate #endif 4641*0Sstevel@tonic-gate kmem_free(dstatp, sz); 4642*0Sstevel@tonic-gate } 4643*0Sstevel@tonic-gate 4644*0Sstevel@tonic-gate /* 4645*0Sstevel@tonic-gate * Called at driver load time to determine the state and condition 4646*0Sstevel@tonic-gate * of an existing board in the system. 4647*0Sstevel@tonic-gate */ 4648*0Sstevel@tonic-gate static void 4649*0Sstevel@tonic-gate sbd_board_discovery(sbd_board_t *sbp) 4650*0Sstevel@tonic-gate { 4651*0Sstevel@tonic-gate int i; 4652*0Sstevel@tonic-gate dev_info_t *dip; 4653*0Sstevel@tonic-gate sbd_devset_t devs_lost, devs_attached = 0; 4654*0Sstevel@tonic-gate extern kmutex_t cpu_lock; 4655*0Sstevel@tonic-gate sbdp_handle_t *hdp; 4656*0Sstevel@tonic-gate static fn_t f = "sbd_board_discovery"; 4657*0Sstevel@tonic-gate sbderror_t error, *ep; 4658*0Sstevel@tonic-gate sbd_handle_t *hp = MACHBD2HD(sbp); 4659*0Sstevel@tonic-gate 4660*0Sstevel@tonic-gate if (SBD_DEVS_PRESENT(sbp) == 0) { 4661*0Sstevel@tonic-gate PR_ALL("%s: board %d has no devices present\n", 4662*0Sstevel@tonic-gate f, sbp->sb_num); 4663*0Sstevel@tonic-gate return; 4664*0Sstevel@tonic-gate } 4665*0Sstevel@tonic-gate 4666*0Sstevel@tonic-gate ep = &error; 4667*0Sstevel@tonic-gate bzero(ep, sizeof (sbderror_t)); 4668*0Sstevel@tonic-gate 4669*0Sstevel@tonic-gate /* 4670*0Sstevel@tonic-gate * Check for existence of cpus. 4671*0Sstevel@tonic-gate */ 4672*0Sstevel@tonic-gate 4673*0Sstevel@tonic-gate hdp = sbd_get_sbdp_handle(sbp, hp); 4674*0Sstevel@tonic-gate 4675*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 4676*0Sstevel@tonic-gate processorid_t cpuid; 4677*0Sstevel@tonic-gate 4678*0Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_CPU, i)) 4679*0Sstevel@tonic-gate continue; 4680*0Sstevel@tonic-gate 4681*0Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_CPU)][i]; 4682*0Sstevel@tonic-gate 4683*0Sstevel@tonic-gate if (dip != NULL) { 4684*0Sstevel@tonic-gate cpuid = sbdp_get_cpuid(hdp, dip); 4685*0Sstevel@tonic-gate 4686*0Sstevel@tonic-gate if (cpuid < 0) { 4687*0Sstevel@tonic-gate SBD_GET_PERR(hdp->h_err, 4688*0Sstevel@tonic-gate ep); 4689*0Sstevel@tonic-gate continue; 4690*0Sstevel@tonic-gate } 4691*0Sstevel@tonic-gate 4692*0Sstevel@tonic-gate mutex_enter(&cpu_lock); /* needed to call cpu_get() */ 4693*0Sstevel@tonic-gate if (cpu_get(cpuid)) { 4694*0Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_CPU, i); 4695*0Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_CPU, i); 4696*0Sstevel@tonic-gate PR_ALL("%s: board %d, cpuid %d - attached\n", 4697*0Sstevel@tonic-gate f, sbp->sb_num, cpuid); 4698*0Sstevel@tonic-gate } 4699*0Sstevel@tonic-gate mutex_exit(&cpu_lock); 4700*0Sstevel@tonic-gate sbd_init_cpu_unit(sbp, i); 4701*0Sstevel@tonic-gate } 4702*0Sstevel@tonic-gate } 4703*0Sstevel@tonic-gate 4704*0Sstevel@tonic-gate /* 4705*0Sstevel@tonic-gate * Check for existence of memory. 4706*0Sstevel@tonic-gate */ 4707*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4708*0Sstevel@tonic-gate uint64_t basepa, endpa; 4709*0Sstevel@tonic-gate struct memlist *ml; 4710*0Sstevel@tonic-gate extern struct memlist *phys_install; 4711*0Sstevel@tonic-gate 4712*0Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) 4713*0Sstevel@tonic-gate continue; 4714*0Sstevel@tonic-gate 4715*0Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_MEM)][i]; 4716*0Sstevel@tonic-gate if (dip == NULL) 4717*0Sstevel@tonic-gate continue; 4718*0Sstevel@tonic-gate 4719*0Sstevel@tonic-gate if (sbdphw_get_base_physaddr(hdp, dip, &basepa)) { 4720*0Sstevel@tonic-gate /* omit phantom memory controllers on I/O boards */ 4721*0Sstevel@tonic-gate if (SBD_DEV_IS_PRESENT(sbp, SBD_COMP_MEM, i)) { 4722*0Sstevel@tonic-gate ASSERT(sbp->sb_ndev != 0); 4723*0Sstevel@tonic-gate SBD_DEV_CLR_PRESENT(sbp, SBD_COMP_MEM, i); 4724*0Sstevel@tonic-gate sbp->sb_ndev--; 4725*0Sstevel@tonic-gate } 4726*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)][i] = NULL; 4727*0Sstevel@tonic-gate continue; 4728*0Sstevel@tonic-gate } 4729*0Sstevel@tonic-gate 4730*0Sstevel@tonic-gate /* 4731*0Sstevel@tonic-gate * basepa may not be on a alignment boundary, make it so. 4732*0Sstevel@tonic-gate */ 4733*0Sstevel@tonic-gate if (sbdp_get_mem_alignment(hdp, dip, &endpa)) { 4734*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s sbdp_get_mem_alignment fail", f); 4735*0Sstevel@tonic-gate continue; 4736*0Sstevel@tonic-gate } 4737*0Sstevel@tonic-gate 4738*0Sstevel@tonic-gate basepa &= ~(endpa - 1); 4739*0Sstevel@tonic-gate endpa += basepa; 4740*0Sstevel@tonic-gate 4741*0Sstevel@tonic-gate /* 4742*0Sstevel@tonic-gate * Check if base address is in phys_install. 4743*0Sstevel@tonic-gate */ 4744*0Sstevel@tonic-gate memlist_read_lock(); 4745*0Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) 4746*0Sstevel@tonic-gate if ((endpa <= ml->address) || 4747*0Sstevel@tonic-gate (basepa >= (ml->address + ml->size))) 4748*0Sstevel@tonic-gate continue; 4749*0Sstevel@tonic-gate else 4750*0Sstevel@tonic-gate break; 4751*0Sstevel@tonic-gate memlist_read_unlock(); 4752*0Sstevel@tonic-gate 4753*0Sstevel@tonic-gate if (ml) { 4754*0Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_MEM, i); 4755*0Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_MEM, i); 4756*0Sstevel@tonic-gate PR_ALL("%s: board %d, mem-unit %d - attached\n", 4757*0Sstevel@tonic-gate f, sbp->sb_num, i); 4758*0Sstevel@tonic-gate } 4759*0Sstevel@tonic-gate sbd_init_mem_unit(sbp, i, ep); 4760*0Sstevel@tonic-gate } 4761*0Sstevel@tonic-gate sbd_release_sbdp_handle(hdp); 4762*0Sstevel@tonic-gate 4763*0Sstevel@tonic-gate /* 4764*0Sstevel@tonic-gate * If so far we have found an error, we just log it but continue 4765*0Sstevel@tonic-gate */ 4766*0Sstevel@tonic-gate if (SBD_GET_ERRNO(ep) != 0) 4767*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s errno has occurred: errno %d", f, 4768*0Sstevel@tonic-gate SBD_GET_ERRNO(ep)); 4769*0Sstevel@tonic-gate 4770*0Sstevel@tonic-gate /* 4771*0Sstevel@tonic-gate * Check for i/o state. 4772*0Sstevel@tonic-gate */ 4773*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 4774*0Sstevel@tonic-gate 4775*0Sstevel@tonic-gate if (!SBD_DEV_IS_PRESENT(sbp, SBD_COMP_IO, i)) 4776*0Sstevel@tonic-gate continue; 4777*0Sstevel@tonic-gate 4778*0Sstevel@tonic-gate dip = sbp->sb_devlist[NIX(SBD_COMP_IO)][i]; 4779*0Sstevel@tonic-gate if (dip == NULL) 4780*0Sstevel@tonic-gate continue; 4781*0Sstevel@tonic-gate 4782*0Sstevel@tonic-gate ASSERT(e_ddi_branch_held(dip)); 4783*0Sstevel@tonic-gate 4784*0Sstevel@tonic-gate /* 4785*0Sstevel@tonic-gate * XXX Is the devstate check needed ? 4786*0Sstevel@tonic-gate */ 4787*0Sstevel@tonic-gate if (i_ddi_node_state(dip) >= DS_ATTACHED || 4788*0Sstevel@tonic-gate ddi_get_devstate(dip) == DDI_DEVSTATE_UP) { 4789*0Sstevel@tonic-gate 4790*0Sstevel@tonic-gate /* 4791*0Sstevel@tonic-gate * Found it! 4792*0Sstevel@tonic-gate */ 4793*0Sstevel@tonic-gate SBD_DEV_SET_ATTACHED(sbp, SBD_COMP_IO, i); 4794*0Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_IO, i); 4795*0Sstevel@tonic-gate PR_ALL("%s: board %d, io-unit %d - attached\n", 4796*0Sstevel@tonic-gate f, sbp->sb_num, i); 4797*0Sstevel@tonic-gate } 4798*0Sstevel@tonic-gate sbd_init_io_unit(sbp, i); 4799*0Sstevel@tonic-gate } 4800*0Sstevel@tonic-gate 4801*0Sstevel@tonic-gate SBD_DEVS_CONFIGURE(sbp, devs_attached); 4802*0Sstevel@tonic-gate if (devs_attached && ((devs_lost = SBD_DEVS_UNATTACHED(sbp)) != 0)) { 4803*0Sstevel@tonic-gate int ut; 4804*0Sstevel@tonic-gate /* 4805*0Sstevel@tonic-gate * A prior comment stated that a partially configured 4806*0Sstevel@tonic-gate * board was not permitted. The Serengeti architecture 4807*0Sstevel@tonic-gate * makes this possible, so the SB_DEVS_DISCONNECT 4808*0Sstevel@tonic-gate * at the end of this block has been removed. 4809*0Sstevel@tonic-gate */ 4810*0Sstevel@tonic-gate 4811*0Sstevel@tonic-gate PR_ALL("%s: some devices not configured (0x%x)...\n", 4812*0Sstevel@tonic-gate f, devs_lost); 4813*0Sstevel@tonic-gate 4814*0Sstevel@tonic-gate for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) 4815*0Sstevel@tonic-gate if (DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) { 4816*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_CPU, 4817*0Sstevel@tonic-gate ut, SBD_STATE_UNCONFIGURED); 4818*0Sstevel@tonic-gate } 4819*0Sstevel@tonic-gate 4820*0Sstevel@tonic-gate for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) 4821*0Sstevel@tonic-gate if (DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut)) { 4822*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_MEM, 4823*0Sstevel@tonic-gate ut, SBD_STATE_UNCONFIGURED); 4824*0Sstevel@tonic-gate } 4825*0Sstevel@tonic-gate 4826*0Sstevel@tonic-gate for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) 4827*0Sstevel@tonic-gate if (DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut)) { 4828*0Sstevel@tonic-gate SBD_DEVICE_TRANSITION(sbp, SBD_COMP_IO, 4829*0Sstevel@tonic-gate ut, SBD_STATE_UNCONFIGURED); 4830*0Sstevel@tonic-gate } 4831*0Sstevel@tonic-gate } 4832*0Sstevel@tonic-gate } 4833*0Sstevel@tonic-gate 4834*0Sstevel@tonic-gate static int 4835*0Sstevel@tonic-gate hold_rele_branch(dev_info_t *rdip, void *arg) 4836*0Sstevel@tonic-gate { 4837*0Sstevel@tonic-gate walk_tree_t *wp = (walk_tree_t *)arg; 4838*0Sstevel@tonic-gate 4839*0Sstevel@tonic-gate ASSERT(wp && (wp->hold == 0 || wp->hold == 1)); 4840*0Sstevel@tonic-gate 4841*0Sstevel@tonic-gate switch (get_node_type(wp->sbp, rdip, NULL)) { 4842*0Sstevel@tonic-gate case SBD_COMP_CMP: 4843*0Sstevel@tonic-gate case SBD_COMP_MEM: 4844*0Sstevel@tonic-gate case SBD_COMP_IO: 4845*0Sstevel@tonic-gate break; 4846*0Sstevel@tonic-gate case SBD_COMP_CPU: 4847*0Sstevel@tonic-gate 4848*0Sstevel@tonic-gate /* 4849*0Sstevel@tonic-gate * All CPU nodes under CMP nodes should have 4850*0Sstevel@tonic-gate * gotten pruned when the CMP node was first 4851*0Sstevel@tonic-gate * encountered. 4852*0Sstevel@tonic-gate */ 4853*0Sstevel@tonic-gate ASSERT(!sbd_is_cmp_child(rdip)); 4854*0Sstevel@tonic-gate 4855*0Sstevel@tonic-gate break; 4856*0Sstevel@tonic-gate 4857*0Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 4858*0Sstevel@tonic-gate /* Not of interest to us */ 4859*0Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 4860*0Sstevel@tonic-gate default: 4861*0Sstevel@tonic-gate ASSERT(0); 4862*0Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 4863*0Sstevel@tonic-gate } 4864*0Sstevel@tonic-gate 4865*0Sstevel@tonic-gate if (wp->hold) { 4866*0Sstevel@tonic-gate ASSERT(!e_ddi_branch_held(rdip)); 4867*0Sstevel@tonic-gate e_ddi_branch_hold(rdip); 4868*0Sstevel@tonic-gate } else { 4869*0Sstevel@tonic-gate ASSERT(e_ddi_branch_held(rdip)); 4870*0Sstevel@tonic-gate e_ddi_branch_rele(rdip); 4871*0Sstevel@tonic-gate } 4872*0Sstevel@tonic-gate 4873*0Sstevel@tonic-gate return (DDI_WALK_PRUNECHILD); 4874*0Sstevel@tonic-gate } 4875*0Sstevel@tonic-gate 4876*0Sstevel@tonic-gate static void 4877*0Sstevel@tonic-gate sbd_board_init(sbd_board_t *sbp, sbd_softstate_t *softsp, 4878*0Sstevel@tonic-gate int bd, dev_info_t *top_dip, int wnode) 4879*0Sstevel@tonic-gate { 4880*0Sstevel@tonic-gate int i; 4881*0Sstevel@tonic-gate dev_info_t *pdip; 4882*0Sstevel@tonic-gate int circ; 4883*0Sstevel@tonic-gate walk_tree_t walk = {0}; 4884*0Sstevel@tonic-gate 4885*0Sstevel@tonic-gate mutex_init(&sbp->sb_mutex, NULL, MUTEX_DRIVER, NULL); 4886*0Sstevel@tonic-gate mutex_init(&sbp->sb_flags_mutex, NULL, MUTEX_DRIVER, NULL); 4887*0Sstevel@tonic-gate mutex_init(&sbp->sb_slock, NULL, MUTEX_DRIVER, NULL); 4888*0Sstevel@tonic-gate 4889*0Sstevel@tonic-gate sbp->sb_ref = 0; 4890*0Sstevel@tonic-gate sbp->sb_num = bd; 4891*0Sstevel@tonic-gate sbp->sb_time = gethrestime_sec(); 4892*0Sstevel@tonic-gate /* 4893*0Sstevel@tonic-gate * For serengeti, top_dip doesn't need to be held because 4894*0Sstevel@tonic-gate * sbp i.e. sbd_board_t will be destroyed in sbd_teardown_instance() 4895*0Sstevel@tonic-gate * before top_dip detaches. For Daktari, top_dip is the 4896*0Sstevel@tonic-gate * root node which never has to be held. 4897*0Sstevel@tonic-gate */ 4898*0Sstevel@tonic-gate sbp->sb_topdip = top_dip; 4899*0Sstevel@tonic-gate sbp->sb_cpuid = -1; 4900*0Sstevel@tonic-gate sbp->sb_softsp = (void *) softsp; 4901*0Sstevel@tonic-gate sbp->sb_cond = SBD_COND_UNKNOWN; 4902*0Sstevel@tonic-gate sbp->sb_wnode = wnode; 4903*0Sstevel@tonic-gate sbp->sb_memaccess_ok = 1; 4904*0Sstevel@tonic-gate 4905*0Sstevel@tonic-gate ASSERT(MAX_IO_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 4906*0Sstevel@tonic-gate ASSERT(MAX_CPU_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 4907*0Sstevel@tonic-gate ASSERT(MAX_MEM_UNITS_PER_BOARD <= SBD_MAX_UNITS_PER_BOARD); 4908*0Sstevel@tonic-gate 4909*0Sstevel@tonic-gate /* 4910*0Sstevel@tonic-gate * Allocate the devlist for cpus. 4911*0Sstevel@tonic-gate */ 4912*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_CPU)] = GETSTRUCT(dev_info_t *, 4913*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 4914*0Sstevel@tonic-gate 4915*0Sstevel@tonic-gate /* 4916*0Sstevel@tonic-gate * Allocate the devlist for mem. 4917*0Sstevel@tonic-gate */ 4918*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)] = GETSTRUCT(dev_info_t *, 4919*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 4920*0Sstevel@tonic-gate 4921*0Sstevel@tonic-gate /* 4922*0Sstevel@tonic-gate * Allocate the devlist for io. 4923*0Sstevel@tonic-gate */ 4924*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_IO)] = GETSTRUCT(dev_info_t *, 4925*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 4926*0Sstevel@tonic-gate 4927*0Sstevel@tonic-gate 4928*0Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(sbd_dev_unit_t, 4929*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 4930*0Sstevel@tonic-gate 4931*0Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(sbd_dev_unit_t, 4932*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 4933*0Sstevel@tonic-gate 4934*0Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(sbd_dev_unit_t, 4935*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 4936*0Sstevel@tonic-gate 4937*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 4938*0Sstevel@tonic-gate sbp->sb_cpupath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4939*0Sstevel@tonic-gate } 4940*0Sstevel@tonic-gate 4941*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 4942*0Sstevel@tonic-gate sbp->sb_mempath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4943*0Sstevel@tonic-gate } 4944*0Sstevel@tonic-gate 4945*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 4946*0Sstevel@tonic-gate sbp->sb_iopath[i] = kmem_zalloc(MAXPATHLEN, KM_SLEEP); 4947*0Sstevel@tonic-gate } 4948*0Sstevel@tonic-gate 4949*0Sstevel@tonic-gate /* 4950*0Sstevel@tonic-gate * Walk the device tree, find all top dips on this board and 4951*0Sstevel@tonic-gate * hold the branches rooted at them 4952*0Sstevel@tonic-gate */ 4953*0Sstevel@tonic-gate ASSERT(sbp->sb_topdip); 4954*0Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 4955*0Sstevel@tonic-gate if (pdip) 4956*0Sstevel@tonic-gate ndi_devi_enter(pdip, &circ); 4957*0Sstevel@tonic-gate walk.sbp = sbp; 4958*0Sstevel@tonic-gate walk.hold = 1; 4959*0Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk); 4960*0Sstevel@tonic-gate if (pdip) 4961*0Sstevel@tonic-gate ndi_devi_exit(pdip, circ); 4962*0Sstevel@tonic-gate 4963*0Sstevel@tonic-gate /* 4964*0Sstevel@tonic-gate * Initialize the devlists 4965*0Sstevel@tonic-gate */ 4966*0Sstevel@tonic-gate if (sbd_init_devlists(sbp) == 0) { 4967*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY); 4968*0Sstevel@tonic-gate } else { 4969*0Sstevel@tonic-gate /* 4970*0Sstevel@tonic-gate * Couldn't have made it down here without 4971*0Sstevel@tonic-gate * having found at least one device. 4972*0Sstevel@tonic-gate */ 4973*0Sstevel@tonic-gate ASSERT(SBD_DEVS_PRESENT(sbp) != 0); 4974*0Sstevel@tonic-gate /* 4975*0Sstevel@tonic-gate * Check the state of any possible devices on the 4976*0Sstevel@tonic-gate * board. 4977*0Sstevel@tonic-gate */ 4978*0Sstevel@tonic-gate sbd_board_discovery(sbp); 4979*0Sstevel@tonic-gate 4980*0Sstevel@tonic-gate if (SBD_DEVS_UNATTACHED(sbp) == 0) { 4981*0Sstevel@tonic-gate /* 4982*0Sstevel@tonic-gate * The board has no unattached devices, therefore 4983*0Sstevel@tonic-gate * by reason of insanity it must be configured! 4984*0Sstevel@tonic-gate */ 4985*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONFIGURED); 4986*0Sstevel@tonic-gate sbp->sb_cond = SBD_COND_OK; 4987*0Sstevel@tonic-gate } else if (SBD_DEVS_ATTACHED(sbp)) { 4988*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_PARTIAL); 4989*0Sstevel@tonic-gate } else { 4990*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_CONNECTED); 4991*0Sstevel@tonic-gate } 4992*0Sstevel@tonic-gate } 4993*0Sstevel@tonic-gate } 4994*0Sstevel@tonic-gate 4995*0Sstevel@tonic-gate static void 4996*0Sstevel@tonic-gate sbd_board_destroy(sbd_board_t *sbp) 4997*0Sstevel@tonic-gate { 4998*0Sstevel@tonic-gate int i; 4999*0Sstevel@tonic-gate dev_info_t *pdip; 5000*0Sstevel@tonic-gate int circ; 5001*0Sstevel@tonic-gate walk_tree_t walk = {0}; 5002*0Sstevel@tonic-gate 5003*0Sstevel@tonic-gate SBD_BOARD_TRANSITION(sbp, SBD_STATE_EMPTY); 5004*0Sstevel@tonic-gate 5005*0Sstevel@tonic-gate #ifdef DEBUG 5006*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 5007*0Sstevel@tonic-gate sbd_mem_unit_t *mp; 5008*0Sstevel@tonic-gate 5009*0Sstevel@tonic-gate mp = SBD_GET_BOARD_MEMUNIT(sbp, i); 5010*0Sstevel@tonic-gate ASSERT(mp->sbm_mlist == NULL); 5011*0Sstevel@tonic-gate } 5012*0Sstevel@tonic-gate #endif /* DEBUG */ 5013*0Sstevel@tonic-gate 5014*0Sstevel@tonic-gate /* 5015*0Sstevel@tonic-gate * Free up MEM unit structs. 5016*0Sstevel@tonic-gate */ 5017*0Sstevel@tonic-gate FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_MEM)], 5018*0Sstevel@tonic-gate sbd_dev_unit_t, MAX_MEM_UNITS_PER_BOARD); 5019*0Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_MEM)] = NULL; 5020*0Sstevel@tonic-gate 5021*0Sstevel@tonic-gate /* 5022*0Sstevel@tonic-gate * Free up CPU unit structs. 5023*0Sstevel@tonic-gate */ 5024*0Sstevel@tonic-gate FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_CPU)], 5025*0Sstevel@tonic-gate sbd_dev_unit_t, MAX_CPU_UNITS_PER_BOARD); 5026*0Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_CPU)] = NULL; 5027*0Sstevel@tonic-gate 5028*0Sstevel@tonic-gate /* 5029*0Sstevel@tonic-gate * Free up IO unit structs. 5030*0Sstevel@tonic-gate */ 5031*0Sstevel@tonic-gate FREESTRUCT(sbp->sb_dev[NIX(SBD_COMP_IO)], 5032*0Sstevel@tonic-gate sbd_dev_unit_t, MAX_IO_UNITS_PER_BOARD); 5033*0Sstevel@tonic-gate sbp->sb_dev[NIX(SBD_COMP_IO)] = NULL; 5034*0Sstevel@tonic-gate 5035*0Sstevel@tonic-gate /* 5036*0Sstevel@tonic-gate * free up CPU devlists. 5037*0Sstevel@tonic-gate */ 5038*0Sstevel@tonic-gate 5039*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 5040*0Sstevel@tonic-gate kmem_free((caddr_t)sbp->sb_cpupath[i], MAXPATHLEN); 5041*0Sstevel@tonic-gate } 5042*0Sstevel@tonic-gate FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_CPU)], dev_info_t *, 5043*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 5044*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_CPU)] = NULL; 5045*0Sstevel@tonic-gate 5046*0Sstevel@tonic-gate /* 5047*0Sstevel@tonic-gate * free up MEM devlists. 5048*0Sstevel@tonic-gate */ 5049*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 5050*0Sstevel@tonic-gate kmem_free((caddr_t)sbp->sb_mempath[i], MAXPATHLEN); 5051*0Sstevel@tonic-gate } 5052*0Sstevel@tonic-gate FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_MEM)], dev_info_t *, 5053*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 5054*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_MEM)] = NULL; 5055*0Sstevel@tonic-gate 5056*0Sstevel@tonic-gate /* 5057*0Sstevel@tonic-gate * free up IO devlists. 5058*0Sstevel@tonic-gate */ 5059*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 5060*0Sstevel@tonic-gate kmem_free((caddr_t)sbp->sb_iopath[i], MAXPATHLEN); 5061*0Sstevel@tonic-gate } 5062*0Sstevel@tonic-gate FREESTRUCT(sbp->sb_devlist[NIX(SBD_COMP_IO)], dev_info_t *, 5063*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 5064*0Sstevel@tonic-gate sbp->sb_devlist[NIX(SBD_COMP_IO)] = NULL; 5065*0Sstevel@tonic-gate 5066*0Sstevel@tonic-gate /* 5067*0Sstevel@tonic-gate * Release all branches held earlier 5068*0Sstevel@tonic-gate */ 5069*0Sstevel@tonic-gate ASSERT(sbp->sb_topdip); 5070*0Sstevel@tonic-gate pdip = ddi_get_parent(sbp->sb_topdip); 5071*0Sstevel@tonic-gate if (pdip) 5072*0Sstevel@tonic-gate ndi_devi_enter(pdip, &circ); 5073*0Sstevel@tonic-gate walk.sbp = sbp; 5074*0Sstevel@tonic-gate walk.hold = 0; 5075*0Sstevel@tonic-gate ddi_walk_devs(sbp->sb_topdip, hold_rele_branch, (void *)&walk); 5076*0Sstevel@tonic-gate if (pdip) 5077*0Sstevel@tonic-gate ndi_devi_exit(pdip, circ); 5078*0Sstevel@tonic-gate 5079*0Sstevel@tonic-gate mutex_destroy(&sbp->sb_slock); 5080*0Sstevel@tonic-gate mutex_destroy(&sbp->sb_flags_mutex); 5081*0Sstevel@tonic-gate mutex_destroy(&sbp->sb_mutex); 5082*0Sstevel@tonic-gate } 5083*0Sstevel@tonic-gate 5084*0Sstevel@tonic-gate sbd_comp_type_t 5085*0Sstevel@tonic-gate sbd_cm_type(char *name) 5086*0Sstevel@tonic-gate { 5087*0Sstevel@tonic-gate sbd_comp_type_t type = SBD_COMP_UNKNOWN; 5088*0Sstevel@tonic-gate int i; 5089*0Sstevel@tonic-gate 5090*0Sstevel@tonic-gate /* look up type in table */ 5091*0Sstevel@tonic-gate for (i = 0; SBD_COMP(i) != SBD_COMP_UNKNOWN; i++) { 5092*0Sstevel@tonic-gate if (strcmp(name, SBD_OTYPE(i)) == 0) { 5093*0Sstevel@tonic-gate type = SBD_COMP(i); 5094*0Sstevel@tonic-gate break; 5095*0Sstevel@tonic-gate } 5096*0Sstevel@tonic-gate } 5097*0Sstevel@tonic-gate 5098*0Sstevel@tonic-gate return (type); 5099*0Sstevel@tonic-gate } 5100*0Sstevel@tonic-gate 5101*0Sstevel@tonic-gate /* 5102*0Sstevel@tonic-gate * There are certain cases where obp marks components as failed 5103*0Sstevel@tonic-gate * If the status is ok the node won't have any status property. It 5104*0Sstevel@tonic-gate * is only there if the status is other than ok. 5105*0Sstevel@tonic-gate * 5106*0Sstevel@tonic-gate * The translation is as follows: 5107*0Sstevel@tonic-gate * If there is no status prop, the the cond is SBD_COND_OK 5108*0Sstevel@tonic-gate * If we find a status prop but can't get to it then cond is SBD_COND_UNKNOWN 5109*0Sstevel@tonic-gate * if we find a stat and it is failed the cond is SBD_COND_FAILED 5110*0Sstevel@tonic-gate * If the stat is disabled, the cond is SBD_COND_UNUSABLE 5111*0Sstevel@tonic-gate * Otherwise we return con as SBD_COND_OK 5112*0Sstevel@tonic-gate */ 5113*0Sstevel@tonic-gate sbd_cond_t 5114*0Sstevel@tonic-gate sbd_get_comp_cond(dev_info_t *dip) 5115*0Sstevel@tonic-gate { 5116*0Sstevel@tonic-gate int len; 5117*0Sstevel@tonic-gate char *status_buf; 5118*0Sstevel@tonic-gate static const char *status = "status"; 5119*0Sstevel@tonic-gate static const char *failed = "fail"; 5120*0Sstevel@tonic-gate static const char *disabled = "disabled"; 5121*0Sstevel@tonic-gate 5122*0Sstevel@tonic-gate if (dip == NULL) { 5123*0Sstevel@tonic-gate PR_BYP("dip is NULL\n"); 5124*0Sstevel@tonic-gate return (SBD_COND_UNKNOWN); 5125*0Sstevel@tonic-gate } 5126*0Sstevel@tonic-gate 5127*0Sstevel@tonic-gate if (ddi_getproplen(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, 5128*0Sstevel@tonic-gate (char *)status, &len) != DDI_PROP_SUCCESS) { 5129*0Sstevel@tonic-gate PR_CPU("status in sbd is ok\n"); 5130*0Sstevel@tonic-gate return (SBD_COND_OK); 5131*0Sstevel@tonic-gate } 5132*0Sstevel@tonic-gate 5133*0Sstevel@tonic-gate status_buf = kmem_zalloc(sizeof (char) * OBP_MAXPROPNAME, KM_SLEEP); 5134*0Sstevel@tonic-gate if (ddi_getlongprop_buf(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS, 5135*0Sstevel@tonic-gate (char *)status, status_buf, &len) != DDI_PROP_SUCCESS) { 5136*0Sstevel@tonic-gate PR_CPU("status in sbd is unknown\n"); 5137*0Sstevel@tonic-gate return (SBD_COND_UNKNOWN); 5138*0Sstevel@tonic-gate } 5139*0Sstevel@tonic-gate 5140*0Sstevel@tonic-gate if (strncmp(status_buf, failed, strlen(failed)) == 0) { 5141*0Sstevel@tonic-gate PR_CPU("status in sbd is failed\n"); 5142*0Sstevel@tonic-gate kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 5143*0Sstevel@tonic-gate return (SBD_COND_FAILED); 5144*0Sstevel@tonic-gate } 5145*0Sstevel@tonic-gate 5146*0Sstevel@tonic-gate if (strcmp(status_buf, disabled) == 0) { 5147*0Sstevel@tonic-gate PR_CPU("status in sbd is unusable\n"); 5148*0Sstevel@tonic-gate kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 5149*0Sstevel@tonic-gate return (SBD_COND_UNUSABLE); 5150*0Sstevel@tonic-gate } 5151*0Sstevel@tonic-gate 5152*0Sstevel@tonic-gate kmem_free(status_buf, sizeof (char) * OBP_MAXPROPNAME); 5153*0Sstevel@tonic-gate return (SBD_COND_OK); 5154*0Sstevel@tonic-gate } 5155*0Sstevel@tonic-gate 5156*0Sstevel@tonic-gate #ifdef SBD_DEBUG_ERRS 5157*0Sstevel@tonic-gate 5158*0Sstevel@tonic-gate /* function to simulate errors throughout the sbd code */ 5159*0Sstevel@tonic-gate void 5160*0Sstevel@tonic-gate sbd_inject_err(int error, sbderror_t *ep, int Errno, int ecode, 5161*0Sstevel@tonic-gate char *rsc) 5162*0Sstevel@tonic-gate { 5163*0Sstevel@tonic-gate static fn_t f = "sbd_inject_err"; 5164*0Sstevel@tonic-gate 5165*0Sstevel@tonic-gate if (sbd_err_debug == 0) 5166*0Sstevel@tonic-gate return; 5167*0Sstevel@tonic-gate 5168*0Sstevel@tonic-gate if (ep == NULL) { 5169*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s ep is NULL", f); 5170*0Sstevel@tonic-gate return; 5171*0Sstevel@tonic-gate } 5172*0Sstevel@tonic-gate 5173*0Sstevel@tonic-gate if (SBD_GET_ERRNO(ep) != 0) { 5174*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s errno already set to %d", f, 5175*0Sstevel@tonic-gate SBD_GET_ERRNO(ep)); 5176*0Sstevel@tonic-gate return; 5177*0Sstevel@tonic-gate } 5178*0Sstevel@tonic-gate 5179*0Sstevel@tonic-gate if (SBD_GET_ERR(ep) != 0) { 5180*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s code already set to %d", f, 5181*0Sstevel@tonic-gate SBD_GET_ERR(ep)); 5182*0Sstevel@tonic-gate return; 5183*0Sstevel@tonic-gate } 5184*0Sstevel@tonic-gate 5185*0Sstevel@tonic-gate if ((sbd_err_debug & (1 << error)) != 0) { 5186*0Sstevel@tonic-gate ep->e_errno = Errno; 5187*0Sstevel@tonic-gate ep->e_code = ecode; 5188*0Sstevel@tonic-gate 5189*0Sstevel@tonic-gate if (rsc != NULL) 5190*0Sstevel@tonic-gate bcopy((caddr_t)rsc, 5191*0Sstevel@tonic-gate (caddr_t)ep->e_rsc, 5192*0Sstevel@tonic-gate sizeof (ep->e_rsc)); 5193*0Sstevel@tonic-gate 5194*0Sstevel@tonic-gate if (Errno != 0) 5195*0Sstevel@tonic-gate PR_ERR_ERRNO("%s set errno to %d", f, ep->e_errno); 5196*0Sstevel@tonic-gate 5197*0Sstevel@tonic-gate if (ecode != 0) 5198*0Sstevel@tonic-gate PR_ERR_ECODE("%s set ecode to %d", f, ep->e_code); 5199*0Sstevel@tonic-gate 5200*0Sstevel@tonic-gate if (rsc != NULL) 5201*0Sstevel@tonic-gate PR_ERR_RSC("%s set rsc to %s", f, ep->e_rsc); 5202*0Sstevel@tonic-gate } 5203*0Sstevel@tonic-gate } 5204*0Sstevel@tonic-gate #endif 5205