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 2004 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 * PIM-DR layer of DR driver. Provides interface between user 31*0Sstevel@tonic-gate * level applications and the PSM-DR layer. 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate 34*0Sstevel@tonic-gate #include <sys/note.h> 35*0Sstevel@tonic-gate #include <sys/debug.h> 36*0Sstevel@tonic-gate #include <sys/types.h> 37*0Sstevel@tonic-gate #include <sys/errno.h> 38*0Sstevel@tonic-gate #include <sys/cred.h> 39*0Sstevel@tonic-gate #include <sys/dditypes.h> 40*0Sstevel@tonic-gate #include <sys/devops.h> 41*0Sstevel@tonic-gate #include <sys/modctl.h> 42*0Sstevel@tonic-gate #include <sys/poll.h> 43*0Sstevel@tonic-gate #include <sys/conf.h> 44*0Sstevel@tonic-gate #include <sys/ddi.h> 45*0Sstevel@tonic-gate #include <sys/sunddi.h> 46*0Sstevel@tonic-gate #include <sys/sunndi.h> 47*0Sstevel@tonic-gate #include <sys/stat.h> 48*0Sstevel@tonic-gate #include <sys/kmem.h> 49*0Sstevel@tonic-gate #include <sys/processor.h> 50*0Sstevel@tonic-gate #include <sys/cpuvar.h> 51*0Sstevel@tonic-gate #include <sys/mem_config.h> 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate #include <sys/autoconf.h> 54*0Sstevel@tonic-gate #include <sys/cmn_err.h> 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 57*0Sstevel@tonic-gate #include <sys/promif.h> 58*0Sstevel@tonic-gate #include <sys/machsystm.h> 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate #include <sys/dr.h> 61*0Sstevel@tonic-gate #include <sys/drmach.h> 62*0Sstevel@tonic-gate #include <sys/dr_util.h> 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate extern int nulldev(); 65*0Sstevel@tonic-gate extern int nodev(); 66*0Sstevel@tonic-gate extern struct memlist *phys_install; 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #ifdef DEBUG 69*0Sstevel@tonic-gate uint_t dr_debug = 0; /* dr.h for bit values */ 70*0Sstevel@tonic-gate #endif /* DEBUG */ 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gate /* 73*0Sstevel@tonic-gate * NOTE: state_str, nt_str and SBD_CMD_STR are only used in a debug 74*0Sstevel@tonic-gate * kernel. They are, however, referenced during both debug and non-debug 75*0Sstevel@tonic-gate * compiles. 76*0Sstevel@tonic-gate */ 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate static char *state_str[] = { 79*0Sstevel@tonic-gate "EMPTY", "OCCUPIED", "CONNECTED", "UNCONFIGURED", 80*0Sstevel@tonic-gate "PARTIAL", "CONFIGURED", "RELEASE", "UNREFERENCED", 81*0Sstevel@tonic-gate "FATAL" 82*0Sstevel@tonic-gate }; 83*0Sstevel@tonic-gate 84*0Sstevel@tonic-gate #define SBD_CMD_STR(c) \ 85*0Sstevel@tonic-gate (((c) == SBD_CMD_ASSIGN) ? "ASSIGN" : \ 86*0Sstevel@tonic-gate ((c) == SBD_CMD_UNASSIGN) ? "UNASSIGN" : \ 87*0Sstevel@tonic-gate ((c) == SBD_CMD_POWERON) ? "POWERON" : \ 88*0Sstevel@tonic-gate ((c) == SBD_CMD_POWEROFF) ? "POWEROFF" : \ 89*0Sstevel@tonic-gate ((c) == SBD_CMD_TEST) ? "TEST" : \ 90*0Sstevel@tonic-gate ((c) == SBD_CMD_CONNECT) ? "CONNECT" : \ 91*0Sstevel@tonic-gate ((c) == SBD_CMD_DISCONNECT) ? "DISCONNECT" : \ 92*0Sstevel@tonic-gate ((c) == SBD_CMD_CONFIGURE) ? "CONFIGURE" : \ 93*0Sstevel@tonic-gate ((c) == SBD_CMD_UNCONFIGURE) ? "UNCONFIGURE" : \ 94*0Sstevel@tonic-gate ((c) == SBD_CMD_GETNCM) ? "GETNCM" : \ 95*0Sstevel@tonic-gate ((c) == SBD_CMD_PASSTHRU) ? "PASSTHRU" : \ 96*0Sstevel@tonic-gate ((c) == SBD_CMD_STATUS) ? "STATUS" : "unknown") 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate #define DR_GET_BOARD_DEVUNIT(sb, ut, un) (&((sb)->b_dev[NIX(ut)][un])) 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate #define DR_MAKE_MINOR(i, b) (((i) << 16) | (b)) 101*0Sstevel@tonic-gate #define DR_MINOR2INST(m) (((m) >> 16) & 0xffff) 102*0Sstevel@tonic-gate #define DR_MINOR2BNUM(m) ((m) & 0xffff) 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate /* for the DR*INTERNAL_ERROR macros. see sys/dr.h. */ 105*0Sstevel@tonic-gate static char *dr_ie_fmt = "dr.c %d"; 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate /* struct for drmach device name to sbd_comp_type_t mapping */ 108*0Sstevel@tonic-gate typedef struct { 109*0Sstevel@tonic-gate char *s_devtype; 110*0Sstevel@tonic-gate sbd_comp_type_t s_nodetype; 111*0Sstevel@tonic-gate } dr_devname_t; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* struct to map starfire device attributes - name:sbd_comp_type_t */ 114*0Sstevel@tonic-gate static dr_devname_t dr_devattr[] = { 115*0Sstevel@tonic-gate { DRMACH_DEVTYPE_MEM, SBD_COMP_MEM }, 116*0Sstevel@tonic-gate { DRMACH_DEVTYPE_CPU, SBD_COMP_CPU }, 117*0Sstevel@tonic-gate { DRMACH_DEVTYPE_PCI, SBD_COMP_IO }, 118*0Sstevel@tonic-gate { DRMACH_DEVTYPE_SBUS, SBD_COMP_IO }, 119*0Sstevel@tonic-gate #if defined(DRMACH_DEVTYPE_WCI) 120*0Sstevel@tonic-gate { DRMACH_DEVTYPE_WCI, SBD_COMP_IO }, 121*0Sstevel@tonic-gate #endif 122*0Sstevel@tonic-gate /* last s_devtype must be NULL, s_nodetype must be SBD_COMP_UNKNOWN */ 123*0Sstevel@tonic-gate { NULL, SBD_COMP_UNKNOWN } 124*0Sstevel@tonic-gate }; 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate /* 127*0Sstevel@tonic-gate * Per instance soft-state structure. 128*0Sstevel@tonic-gate */ 129*0Sstevel@tonic-gate typedef struct dr_softstate { 130*0Sstevel@tonic-gate dev_info_t *dip; 131*0Sstevel@tonic-gate dr_board_t *boards; 132*0Sstevel@tonic-gate kmutex_t i_lock; 133*0Sstevel@tonic-gate int dr_initialized; 134*0Sstevel@tonic-gate } dr_softstate_t; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate /* 137*0Sstevel@tonic-gate * dr Global data elements 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate struct dr_global { 140*0Sstevel@tonic-gate dr_softstate_t *softsp; /* pointer to initialize soft state */ 141*0Sstevel@tonic-gate kmutex_t lock; 142*0Sstevel@tonic-gate } dr_g; 143*0Sstevel@tonic-gate 144*0Sstevel@tonic-gate dr_unsafe_devs_t dr_unsafe_devs; 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* 147*0Sstevel@tonic-gate * Table of known passthru commands. 148*0Sstevel@tonic-gate */ 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate struct { 151*0Sstevel@tonic-gate char *pt_name; 152*0Sstevel@tonic-gate int (*pt_func)(dr_handle_t *); 153*0Sstevel@tonic-gate } pt_arr[] = { 154*0Sstevel@tonic-gate "quiesce", dr_pt_test_suspend, 155*0Sstevel@tonic-gate }; 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate int dr_modunload_okay = 0; /* set to non-zero to allow unload */ 158*0Sstevel@tonic-gate 159*0Sstevel@tonic-gate /* 160*0Sstevel@tonic-gate * State transition table. States valid transitions for "board" state. 161*0Sstevel@tonic-gate * Recall that non-zero return value terminates operation, however 162*0Sstevel@tonic-gate * the herrno value is what really indicates an error , if any. 163*0Sstevel@tonic-gate */ 164*0Sstevel@tonic-gate static int 165*0Sstevel@tonic-gate _cmd2index(int c) 166*0Sstevel@tonic-gate { 167*0Sstevel@tonic-gate /* 168*0Sstevel@tonic-gate * Translate DR CMD to index into dr_state_transition. 169*0Sstevel@tonic-gate */ 170*0Sstevel@tonic-gate switch (c) { 171*0Sstevel@tonic-gate case SBD_CMD_CONNECT: return (0); 172*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: return (1); 173*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: return (2); 174*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: return (3); 175*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: return (4); 176*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: return (5); 177*0Sstevel@tonic-gate case SBD_CMD_POWERON: return (6); 178*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: return (7); 179*0Sstevel@tonic-gate case SBD_CMD_TEST: return (8); 180*0Sstevel@tonic-gate default: return (-1); 181*0Sstevel@tonic-gate } 182*0Sstevel@tonic-gate } 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate #define CMD2INDEX(c) _cmd2index(c) 185*0Sstevel@tonic-gate 186*0Sstevel@tonic-gate static struct dr_state_trans { 187*0Sstevel@tonic-gate int x_cmd; 188*0Sstevel@tonic-gate struct { 189*0Sstevel@tonic-gate int x_rv; /* return value of pre_op */ 190*0Sstevel@tonic-gate int x_err; /* error, if any */ 191*0Sstevel@tonic-gate } x_op[DR_STATE_MAX]; 192*0Sstevel@tonic-gate } dr_state_transition[] = { 193*0Sstevel@tonic-gate { SBD_CMD_CONNECT, 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 196*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 197*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 198*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 199*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 200*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 201*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 202*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 203*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 204*0Sstevel@tonic-gate } 205*0Sstevel@tonic-gate }, 206*0Sstevel@tonic-gate { SBD_CMD_DISCONNECT, 207*0Sstevel@tonic-gate { 208*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* empty */ 209*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 210*0Sstevel@tonic-gate { 0, 0 }, /* connected */ 211*0Sstevel@tonic-gate { 0, 0 }, /* unconfigured */ 212*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 213*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 214*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 215*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 216*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate }, 219*0Sstevel@tonic-gate { SBD_CMD_CONFIGURE, 220*0Sstevel@tonic-gate { 221*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* empty */ 222*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* occupied */ 223*0Sstevel@tonic-gate { 0, 0 }, /* connected */ 224*0Sstevel@tonic-gate { 0, 0 }, /* unconfigured */ 225*0Sstevel@tonic-gate { 0, 0 }, /* partial */ 226*0Sstevel@tonic-gate { 0, 0 }, /* configured */ 227*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 228*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 229*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate }, 232*0Sstevel@tonic-gate { SBD_CMD_UNCONFIGURE, 233*0Sstevel@tonic-gate { 234*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* empty */ 235*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* occupied */ 236*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 237*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 238*0Sstevel@tonic-gate { 0, 0 }, /* partial */ 239*0Sstevel@tonic-gate { 0, 0 }, /* configured */ 240*0Sstevel@tonic-gate { 0, 0 }, /* release */ 241*0Sstevel@tonic-gate { 0, 0 }, /* unreferenced */ 242*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 243*0Sstevel@tonic-gate } 244*0Sstevel@tonic-gate }, 245*0Sstevel@tonic-gate { SBD_CMD_ASSIGN, 246*0Sstevel@tonic-gate { 247*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 248*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 249*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 250*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 251*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 252*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 253*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 254*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 255*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 256*0Sstevel@tonic-gate } 257*0Sstevel@tonic-gate }, 258*0Sstevel@tonic-gate { SBD_CMD_UNASSIGN, 259*0Sstevel@tonic-gate { 260*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 261*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 262*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 263*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 264*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 265*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 266*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 267*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 268*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 269*0Sstevel@tonic-gate } 270*0Sstevel@tonic-gate }, 271*0Sstevel@tonic-gate { SBD_CMD_POWERON, 272*0Sstevel@tonic-gate { 273*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 274*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 275*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 276*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 277*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 278*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 279*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 280*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 281*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 282*0Sstevel@tonic-gate } 283*0Sstevel@tonic-gate }, 284*0Sstevel@tonic-gate { SBD_CMD_POWEROFF, 285*0Sstevel@tonic-gate { 286*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 287*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 288*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 289*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 290*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 291*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 292*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 293*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 294*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate }, 297*0Sstevel@tonic-gate { SBD_CMD_TEST, 298*0Sstevel@tonic-gate { 299*0Sstevel@tonic-gate { 0, 0 }, /* empty */ 300*0Sstevel@tonic-gate { 0, 0 }, /* occupied */ 301*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* connected */ 302*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unconfigured */ 303*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* partial */ 304*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* configured */ 305*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* release */ 306*0Sstevel@tonic-gate { -1, ESBD_STATE }, /* unreferenced */ 307*0Sstevel@tonic-gate { -1, ESBD_FATAL_STATE }, /* fatal */ 308*0Sstevel@tonic-gate } 309*0Sstevel@tonic-gate }, 310*0Sstevel@tonic-gate }; 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * Global R/W lock to synchronize access across 314*0Sstevel@tonic-gate * multiple boards. Users wanting multi-board access 315*0Sstevel@tonic-gate * must grab WRITE lock, others must grab READ lock. 316*0Sstevel@tonic-gate */ 317*0Sstevel@tonic-gate krwlock_t dr_grwlock; 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gate /* 320*0Sstevel@tonic-gate * Head of the boardlist used as a reference point for 321*0Sstevel@tonic-gate * locating board structs. 322*0Sstevel@tonic-gate * TODO: eliminate dr_boardlist 323*0Sstevel@tonic-gate */ 324*0Sstevel@tonic-gate dr_board_t *dr_boardlist; 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate /* 327*0Sstevel@tonic-gate * DR support functions. 328*0Sstevel@tonic-gate */ 329*0Sstevel@tonic-gate static dr_devset_t dr_dev2devset(sbd_comp_id_t *cid); 330*0Sstevel@tonic-gate static int dr_check_transition(dr_board_t *bp, 331*0Sstevel@tonic-gate dr_devset_t *devsetp, 332*0Sstevel@tonic-gate struct dr_state_trans *transp, 333*0Sstevel@tonic-gate int cmd); 334*0Sstevel@tonic-gate static int dr_check_unit_attached(dr_common_unit_t *dp); 335*0Sstevel@tonic-gate static sbd_error_t *dr_init_devlists(dr_board_t *bp); 336*0Sstevel@tonic-gate static void dr_board_discovery(dr_board_t *bp); 337*0Sstevel@tonic-gate static int dr_board_init(dr_board_t *bp, dev_info_t *dip, 338*0Sstevel@tonic-gate int bd); 339*0Sstevel@tonic-gate static void dr_board_destroy(dr_board_t *bp); 340*0Sstevel@tonic-gate static void dr_board_transition(dr_board_t *bp, dr_state_t st); 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * DR driver (DDI) entry points. 344*0Sstevel@tonic-gate */ 345*0Sstevel@tonic-gate static int dr_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, 346*0Sstevel@tonic-gate void *arg, void **result); 347*0Sstevel@tonic-gate static int dr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 348*0Sstevel@tonic-gate static int dr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 349*0Sstevel@tonic-gate static int dr_probe(dev_info_t *dip); 350*0Sstevel@tonic-gate static int dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 351*0Sstevel@tonic-gate cred_t *cred_p, int *rval_p); 352*0Sstevel@tonic-gate static int dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p); 353*0Sstevel@tonic-gate static int dr_open(dev_t *dev, int flag, int otyp, cred_t *cred_p); 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate /* 356*0Sstevel@tonic-gate * DR command processing operations. 357*0Sstevel@tonic-gate */ 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gate static int dr_copyin_iocmd(dr_handle_t *hp); 360*0Sstevel@tonic-gate static int dr_copyout_iocmd(dr_handle_t *hp); 361*0Sstevel@tonic-gate static int dr_copyout_errs(dr_handle_t *hp); 362*0Sstevel@tonic-gate static int dr_pre_op(dr_handle_t *hp); 363*0Sstevel@tonic-gate static int dr_post_op(dr_handle_t *hp); 364*0Sstevel@tonic-gate static int dr_exec_op(dr_handle_t *hp); 365*0Sstevel@tonic-gate static void dr_assign_board(dr_handle_t *hp); 366*0Sstevel@tonic-gate static void dr_unassign_board(dr_handle_t *hp); 367*0Sstevel@tonic-gate static void dr_connect(dr_handle_t *hp); 368*0Sstevel@tonic-gate static int dr_disconnect(dr_handle_t *hp); 369*0Sstevel@tonic-gate static void dr_dev_configure(dr_handle_t *hp); 370*0Sstevel@tonic-gate static void dr_dev_release(dr_handle_t *hp); 371*0Sstevel@tonic-gate static int dr_dev_unconfigure(dr_handle_t *hp); 372*0Sstevel@tonic-gate static void dr_dev_cancel(dr_handle_t *hp); 373*0Sstevel@tonic-gate static int dr_dev_status(dr_handle_t *hp); 374*0Sstevel@tonic-gate static int dr_get_ncm(dr_handle_t *hp); 375*0Sstevel@tonic-gate static int dr_pt_ioctl(dr_handle_t *hp); 376*0Sstevel@tonic-gate static void dr_poweron_board(dr_handle_t *hp); 377*0Sstevel@tonic-gate static void dr_poweroff_board(dr_handle_t *hp); 378*0Sstevel@tonic-gate static void dr_test_board(dr_handle_t *hp); 379*0Sstevel@tonic-gate 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gate /* 383*0Sstevel@tonic-gate * Autoconfiguration data structures 384*0Sstevel@tonic-gate */ 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate struct cb_ops dr_cb_ops = { 387*0Sstevel@tonic-gate dr_open, /* open */ 388*0Sstevel@tonic-gate dr_close, /* close */ 389*0Sstevel@tonic-gate nodev, /* strategy */ 390*0Sstevel@tonic-gate nodev, /* print */ 391*0Sstevel@tonic-gate nodev, /* dump */ 392*0Sstevel@tonic-gate nodev, /* read */ 393*0Sstevel@tonic-gate nodev, /* write */ 394*0Sstevel@tonic-gate dr_ioctl, /* ioctl */ 395*0Sstevel@tonic-gate nodev, /* devmap */ 396*0Sstevel@tonic-gate nodev, /* mmap */ 397*0Sstevel@tonic-gate nodev, /* segmap */ 398*0Sstevel@tonic-gate nochpoll, /* chpoll */ 399*0Sstevel@tonic-gate ddi_prop_op, /* cb_prop_op */ 400*0Sstevel@tonic-gate NULL, /* struct streamtab */ 401*0Sstevel@tonic-gate D_NEW | D_MP | D_MTSAFE, /* compatibility flags */ 402*0Sstevel@tonic-gate CB_REV, /* Rev */ 403*0Sstevel@tonic-gate nodev, /* cb_aread */ 404*0Sstevel@tonic-gate nodev /* cb_awrite */ 405*0Sstevel@tonic-gate }; 406*0Sstevel@tonic-gate 407*0Sstevel@tonic-gate struct dev_ops dr_dev_ops = { 408*0Sstevel@tonic-gate DEVO_REV, /* build version */ 409*0Sstevel@tonic-gate 0, /* dev ref count */ 410*0Sstevel@tonic-gate dr_getinfo, /* getinfo */ 411*0Sstevel@tonic-gate nulldev, /* identify */ 412*0Sstevel@tonic-gate dr_probe, /* probe */ 413*0Sstevel@tonic-gate dr_attach, /* attach */ 414*0Sstevel@tonic-gate dr_detach, /* detach */ 415*0Sstevel@tonic-gate nodev, /* reset */ 416*0Sstevel@tonic-gate &dr_cb_ops, /* cb_ops */ 417*0Sstevel@tonic-gate (struct bus_ops *)NULL, /* bus ops */ 418*0Sstevel@tonic-gate NULL /* power */ 419*0Sstevel@tonic-gate }; 420*0Sstevel@tonic-gate 421*0Sstevel@tonic-gate extern struct mod_ops mod_driverops; 422*0Sstevel@tonic-gate 423*0Sstevel@tonic-gate static struct modldrv modldrv = { 424*0Sstevel@tonic-gate &mod_driverops, 425*0Sstevel@tonic-gate "Dynamic Reconfiguration %I%", 426*0Sstevel@tonic-gate &dr_dev_ops 427*0Sstevel@tonic-gate }; 428*0Sstevel@tonic-gate 429*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 430*0Sstevel@tonic-gate MODREV_1, 431*0Sstevel@tonic-gate (void *)&modldrv, 432*0Sstevel@tonic-gate NULL 433*0Sstevel@tonic-gate }; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * Driver entry points. 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate int 439*0Sstevel@tonic-gate _init(void) 440*0Sstevel@tonic-gate { 441*0Sstevel@tonic-gate int err; 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate /* 444*0Sstevel@tonic-gate * If you need to support multiple nodes (instances), then 445*0Sstevel@tonic-gate * whatever the maximum number of supported nodes is would 446*0Sstevel@tonic-gate * need to passed as the third parameter to ddi_soft_state_init(). 447*0Sstevel@tonic-gate * Alternative would be to dynamically fini and re-init the 448*0Sstevel@tonic-gate * soft state structure each time a node is attached. 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate err = ddi_soft_state_init((void **)&dr_g.softsp, 451*0Sstevel@tonic-gate sizeof (dr_softstate_t), 1); 452*0Sstevel@tonic-gate if (err) 453*0Sstevel@tonic-gate return (err); 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate mutex_init(&dr_g.lock, NULL, MUTEX_DRIVER, NULL); 456*0Sstevel@tonic-gate rw_init(&dr_grwlock, NULL, RW_DEFAULT, NULL); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate return (mod_install(&modlinkage)); 459*0Sstevel@tonic-gate } 460*0Sstevel@tonic-gate 461*0Sstevel@tonic-gate int 462*0Sstevel@tonic-gate _fini(void) 463*0Sstevel@tonic-gate { 464*0Sstevel@tonic-gate int err; 465*0Sstevel@tonic-gate 466*0Sstevel@tonic-gate if ((err = mod_remove(&modlinkage)) != 0) 467*0Sstevel@tonic-gate return (err); 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate mutex_destroy(&dr_g.lock); 470*0Sstevel@tonic-gate rw_destroy(&dr_grwlock); 471*0Sstevel@tonic-gate 472*0Sstevel@tonic-gate ddi_soft_state_fini((void **)&dr_g.softsp); 473*0Sstevel@tonic-gate 474*0Sstevel@tonic-gate return (0); 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate 477*0Sstevel@tonic-gate int 478*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 479*0Sstevel@tonic-gate { 480*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate /*ARGSUSED1*/ 484*0Sstevel@tonic-gate static int 485*0Sstevel@tonic-gate dr_open(dev_t *dev, int flag, int otyp, cred_t *cred_p) 486*0Sstevel@tonic-gate { 487*0Sstevel@tonic-gate int instance; 488*0Sstevel@tonic-gate dr_softstate_t *softsp; 489*0Sstevel@tonic-gate dr_board_t *bp; 490*0Sstevel@tonic-gate /* 491*0Sstevel@tonic-gate * Don't open unless we've attached. 492*0Sstevel@tonic-gate */ 493*0Sstevel@tonic-gate instance = DR_MINOR2INST(getminor(*dev)); 494*0Sstevel@tonic-gate softsp = ddi_get_soft_state(dr_g.softsp, instance); 495*0Sstevel@tonic-gate if (softsp == NULL) 496*0Sstevel@tonic-gate return (ENXIO); 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate mutex_enter(&softsp->i_lock); 499*0Sstevel@tonic-gate if (!softsp->dr_initialized) { 500*0Sstevel@tonic-gate int bd; 501*0Sstevel@tonic-gate int rv = 0; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate bp = softsp->boards; 504*0Sstevel@tonic-gate 505*0Sstevel@tonic-gate /* initialize each array element */ 506*0Sstevel@tonic-gate for (bd = 0; bd < MAX_BOARDS; bd++, bp++) { 507*0Sstevel@tonic-gate rv = dr_board_init(bp, softsp->dip, bd); 508*0Sstevel@tonic-gate if (rv) 509*0Sstevel@tonic-gate break; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate if (rv == 0) { 513*0Sstevel@tonic-gate softsp->dr_initialized = 1; 514*0Sstevel@tonic-gate } else { 515*0Sstevel@tonic-gate /* destroy elements initialized thus far */ 516*0Sstevel@tonic-gate while (--bp >= softsp->boards) 517*0Sstevel@tonic-gate dr_board_destroy(bp); 518*0Sstevel@tonic-gate 519*0Sstevel@tonic-gate 520*0Sstevel@tonic-gate /* TODO: should this be another errno val ? */ 521*0Sstevel@tonic-gate mutex_exit(&softsp->i_lock); 522*0Sstevel@tonic-gate return (ENXIO); 523*0Sstevel@tonic-gate } 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate mutex_exit(&softsp->i_lock); 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate bp = &softsp->boards[DR_MINOR2BNUM(getminor(*dev))]; 528*0Sstevel@tonic-gate 529*0Sstevel@tonic-gate /* 530*0Sstevel@tonic-gate * prevent opening of a dyn-ap for a board 531*0Sstevel@tonic-gate * that does not exist 532*0Sstevel@tonic-gate */ 533*0Sstevel@tonic-gate if (!bp->b_assigned) { 534*0Sstevel@tonic-gate if (drmach_board_lookup(bp->b_num, &bp->b_id) != 0) 535*0Sstevel@tonic-gate return (ENODEV); 536*0Sstevel@tonic-gate } 537*0Sstevel@tonic-gate 538*0Sstevel@tonic-gate return (0); 539*0Sstevel@tonic-gate } 540*0Sstevel@tonic-gate 541*0Sstevel@tonic-gate /*ARGSUSED*/ 542*0Sstevel@tonic-gate static int 543*0Sstevel@tonic-gate dr_close(dev_t dev, int flag, int otyp, cred_t *cred_p) 544*0Sstevel@tonic-gate { 545*0Sstevel@tonic-gate return (0); 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate /* 549*0Sstevel@tonic-gate * Enable/disable Starcat DR features. 550*0Sstevel@tonic-gate */ 551*0Sstevel@tonic-gate #ifndef _STARFIRE 552*0Sstevel@tonic-gate int dr_enable = 1; 553*0Sstevel@tonic-gate int slot1_dr_enable = 1; 554*0Sstevel@tonic-gate #endif /* _STARFIRE */ 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate /*ARGSUSED3*/ 557*0Sstevel@tonic-gate static int 558*0Sstevel@tonic-gate dr_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 559*0Sstevel@tonic-gate cred_t *cred_p, int *rval_p) 560*0Sstevel@tonic-gate { 561*0Sstevel@tonic-gate static int dr_dev_type_to_nt(char *); 562*0Sstevel@tonic-gate 563*0Sstevel@tonic-gate int rv = 0; 564*0Sstevel@tonic-gate int instance; 565*0Sstevel@tonic-gate int bd; 566*0Sstevel@tonic-gate dr_handle_t *hp; 567*0Sstevel@tonic-gate dr_softstate_t *softsp; 568*0Sstevel@tonic-gate static fn_t f = "dr_ioctl"; 569*0Sstevel@tonic-gate 570*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate instance = DR_MINOR2INST(getminor(dev)); 573*0Sstevel@tonic-gate softsp = ddi_get_soft_state(dr_g.softsp, instance); 574*0Sstevel@tonic-gate if (softsp == NULL) { 575*0Sstevel@tonic-gate cmn_err(CE_WARN, "dr%d: module not yet attached", instance); 576*0Sstevel@tonic-gate return (ENXIO); 577*0Sstevel@tonic-gate } 578*0Sstevel@tonic-gate 579*0Sstevel@tonic-gate #ifndef _STARFIRE 580*0Sstevel@tonic-gate if (!dr_enable) { 581*0Sstevel@tonic-gate switch (cmd) { 582*0Sstevel@tonic-gate case SBD_CMD_STATUS: 583*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 584*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 585*0Sstevel@tonic-gate break; 586*0Sstevel@tonic-gate default: 587*0Sstevel@tonic-gate return (ENOTSUP); 588*0Sstevel@tonic-gate } 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate #endif /* _STARFIRE */ 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate bd = DR_MINOR2BNUM(getminor(dev)); 593*0Sstevel@tonic-gate if (bd >= MAX_BOARDS) 594*0Sstevel@tonic-gate return (ENXIO); 595*0Sstevel@tonic-gate 596*0Sstevel@tonic-gate #ifndef _STARFIRE 597*0Sstevel@tonic-gate if (!slot1_dr_enable && (bd & 0x1)) { 598*0Sstevel@tonic-gate switch (cmd) { 599*0Sstevel@tonic-gate case SBD_CMD_STATUS: 600*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 601*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 602*0Sstevel@tonic-gate break; 603*0Sstevel@tonic-gate default: 604*0Sstevel@tonic-gate return (ENOTSUP); 605*0Sstevel@tonic-gate } 606*0Sstevel@tonic-gate } 607*0Sstevel@tonic-gate #endif /* _STARFIRE */ 608*0Sstevel@tonic-gate 609*0Sstevel@tonic-gate /* get and initialize storage for new handle */ 610*0Sstevel@tonic-gate hp = GETSTRUCT(dr_handle_t, 1); 611*0Sstevel@tonic-gate hp->h_bd = &softsp->boards[bd]; 612*0Sstevel@tonic-gate hp->h_err = NULL; 613*0Sstevel@tonic-gate hp->h_dev = getminor(dev); 614*0Sstevel@tonic-gate hp->h_cmd = cmd; 615*0Sstevel@tonic-gate hp->h_mode = mode; 616*0Sstevel@tonic-gate hp->h_iap = (sbd_ioctl_arg_t *)arg; 617*0Sstevel@tonic-gate 618*0Sstevel@tonic-gate /* copy sbd command into handle */ 619*0Sstevel@tonic-gate rv = dr_copyin_iocmd(hp); 620*0Sstevel@tonic-gate if (rv) { 621*0Sstevel@tonic-gate FREESTRUCT(hp, dr_handle_t, 1); 622*0Sstevel@tonic-gate return (EINVAL); 623*0Sstevel@tonic-gate } 624*0Sstevel@tonic-gate 625*0Sstevel@tonic-gate /* translate canonical name to component type */ 626*0Sstevel@tonic-gate if (hp->h_sbdcmd.cmd_cm.c_id.c_name[0] != '\0') { 627*0Sstevel@tonic-gate hp->h_sbdcmd.cmd_cm.c_id.c_type = 628*0Sstevel@tonic-gate dr_dev_type_to_nt(hp->h_sbdcmd.cmd_cm.c_id.c_name); 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate PR_ALL("%s: c_name = %s, c_type = %d\n", 631*0Sstevel@tonic-gate f, 632*0Sstevel@tonic-gate hp->h_sbdcmd.cmd_cm.c_id.c_name, 633*0Sstevel@tonic-gate hp->h_sbdcmd.cmd_cm.c_id.c_type); 634*0Sstevel@tonic-gate } else { 635*0Sstevel@tonic-gate /*EMPTY*/ 636*0Sstevel@tonic-gate PR_ALL("%s: c_name is NULL\n", f); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate 639*0Sstevel@tonic-gate /* determine scope of operation */ 640*0Sstevel@tonic-gate hp->h_devset = dr_dev2devset(&hp->h_sbdcmd.cmd_cm.c_id); 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate switch (hp->h_cmd) { 643*0Sstevel@tonic-gate case SBD_CMD_STATUS: 644*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 645*0Sstevel@tonic-gate /* no locks needed for these commands */ 646*0Sstevel@tonic-gate break; 647*0Sstevel@tonic-gate 648*0Sstevel@tonic-gate default: 649*0Sstevel@tonic-gate rw_enter(&dr_grwlock, RW_WRITER); 650*0Sstevel@tonic-gate mutex_enter(&hp->h_bd->b_lock); 651*0Sstevel@tonic-gate 652*0Sstevel@tonic-gate /* 653*0Sstevel@tonic-gate * If we're dealing with memory at all, then we have 654*0Sstevel@tonic-gate * to keep the "exclusive" global lock held. This is 655*0Sstevel@tonic-gate * necessary since we will probably need to look at 656*0Sstevel@tonic-gate * multiple board structs. Otherwise, we only have 657*0Sstevel@tonic-gate * to deal with the board in question and so can drop 658*0Sstevel@tonic-gate * the global lock to "shared". 659*0Sstevel@tonic-gate */ 660*0Sstevel@tonic-gate rv = DEVSET_IN_SET(hp->h_devset, SBD_COMP_MEM, DEVSET_ANYUNIT); 661*0Sstevel@tonic-gate if (rv == 0) 662*0Sstevel@tonic-gate rw_downgrade(&dr_grwlock); 663*0Sstevel@tonic-gate break; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate rv = 0; 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate if (rv == 0) 668*0Sstevel@tonic-gate rv = dr_pre_op(hp); 669*0Sstevel@tonic-gate if (rv == 0) 670*0Sstevel@tonic-gate rv = dr_exec_op(hp); 671*0Sstevel@tonic-gate if (rv == 0) 672*0Sstevel@tonic-gate rv = dr_post_op(hp); 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate if (rv == -1) 675*0Sstevel@tonic-gate rv = EIO; 676*0Sstevel@tonic-gate 677*0Sstevel@tonic-gate if (hp->h_err != NULL) 678*0Sstevel@tonic-gate if (!(rv = dr_copyout_errs(hp))) 679*0Sstevel@tonic-gate rv = EIO; 680*0Sstevel@tonic-gate 681*0Sstevel@tonic-gate /* undo locking, if any, done before dr_pre_op */ 682*0Sstevel@tonic-gate switch (hp->h_cmd) { 683*0Sstevel@tonic-gate case SBD_CMD_STATUS: 684*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 685*0Sstevel@tonic-gate break; 686*0Sstevel@tonic-gate 687*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: 688*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 689*0Sstevel@tonic-gate case SBD_CMD_POWERON: 690*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: 691*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 692*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 693*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 694*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 695*0Sstevel@tonic-gate /* Board changed state. Log a sysevent. */ 696*0Sstevel@tonic-gate if (rv == 0) 697*0Sstevel@tonic-gate (void) drmach_log_sysevent(hp->h_bd->b_num, "", 698*0Sstevel@tonic-gate SE_SLEEP, 1); 699*0Sstevel@tonic-gate /* Fall through */ 700*0Sstevel@tonic-gate 701*0Sstevel@tonic-gate default: 702*0Sstevel@tonic-gate mutex_exit(&hp->h_bd->b_lock); 703*0Sstevel@tonic-gate rw_exit(&dr_grwlock); 704*0Sstevel@tonic-gate } 705*0Sstevel@tonic-gate 706*0Sstevel@tonic-gate if (hp->h_opts.size != 0) 707*0Sstevel@tonic-gate FREESTRUCT(hp->h_opts.copts, char, hp->h_opts.size); 708*0Sstevel@tonic-gate 709*0Sstevel@tonic-gate FREESTRUCT(hp, dr_handle_t, 1); 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate return (rv); 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate 714*0Sstevel@tonic-gate /*ARGSUSED*/ 715*0Sstevel@tonic-gate static int 716*0Sstevel@tonic-gate dr_probe(dev_info_t *dip) 717*0Sstevel@tonic-gate { 718*0Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 719*0Sstevel@tonic-gate } 720*0Sstevel@tonic-gate 721*0Sstevel@tonic-gate static int 722*0Sstevel@tonic-gate dr_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 723*0Sstevel@tonic-gate { 724*0Sstevel@tonic-gate int rv, rv2; 725*0Sstevel@tonic-gate int bd; 726*0Sstevel@tonic-gate int instance; 727*0Sstevel@tonic-gate sbd_error_t *err; 728*0Sstevel@tonic-gate dr_softstate_t *softsp; 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate instance = ddi_get_instance(dip); 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate switch (cmd) { 733*0Sstevel@tonic-gate 734*0Sstevel@tonic-gate case DDI_ATTACH: 735*0Sstevel@tonic-gate 736*0Sstevel@tonic-gate rw_enter(&dr_grwlock, RW_WRITER); 737*0Sstevel@tonic-gate 738*0Sstevel@tonic-gate rv = ddi_soft_state_zalloc(dr_g.softsp, instance); 739*0Sstevel@tonic-gate if (rv != DDI_SUCCESS) { 740*0Sstevel@tonic-gate cmn_err(CE_WARN, "dr%d: failed to alloc soft-state", 741*0Sstevel@tonic-gate instance); 742*0Sstevel@tonic-gate return (DDI_FAILURE); 743*0Sstevel@tonic-gate } 744*0Sstevel@tonic-gate 745*0Sstevel@tonic-gate /* initialize softstate structure */ 746*0Sstevel@tonic-gate softsp = ddi_get_soft_state(dr_g.softsp, instance); 747*0Sstevel@tonic-gate softsp->dip = dip; 748*0Sstevel@tonic-gate 749*0Sstevel@tonic-gate mutex_init(&softsp->i_lock, NULL, MUTEX_DRIVER, NULL); 750*0Sstevel@tonic-gate 751*0Sstevel@tonic-gate /* allocate board array (aka boardlist) */ 752*0Sstevel@tonic-gate softsp->boards = GETSTRUCT(dr_board_t, MAX_BOARDS); 753*0Sstevel@tonic-gate 754*0Sstevel@tonic-gate /* TODO: eliminate dr_boardlist */ 755*0Sstevel@tonic-gate dr_boardlist = softsp->boards; 756*0Sstevel@tonic-gate 757*0Sstevel@tonic-gate /* initialize each array element */ 758*0Sstevel@tonic-gate rv = DDI_SUCCESS; 759*0Sstevel@tonic-gate for (bd = 0; bd < MAX_BOARDS; bd++) { 760*0Sstevel@tonic-gate dr_board_t *bp = &softsp->boards[bd]; 761*0Sstevel@tonic-gate char *p, *name; 762*0Sstevel@tonic-gate int l, minor_num; 763*0Sstevel@tonic-gate 764*0Sstevel@tonic-gate /* 765*0Sstevel@tonic-gate * initialized board attachment point path 766*0Sstevel@tonic-gate * (relative to pseudo) in a form immediately 767*0Sstevel@tonic-gate * reusable as an cfgadm command argument. 768*0Sstevel@tonic-gate * TODO: clean this up 769*0Sstevel@tonic-gate */ 770*0Sstevel@tonic-gate p = bp->b_path; 771*0Sstevel@tonic-gate l = sizeof (bp->b_path); 772*0Sstevel@tonic-gate (void) snprintf(p, l, "dr@%d:", instance); 773*0Sstevel@tonic-gate while (*p != '\0') { 774*0Sstevel@tonic-gate l--; 775*0Sstevel@tonic-gate p++; 776*0Sstevel@tonic-gate } 777*0Sstevel@tonic-gate 778*0Sstevel@tonic-gate name = p; 779*0Sstevel@tonic-gate err = drmach_board_name(bd, p, l); 780*0Sstevel@tonic-gate if (err) { 781*0Sstevel@tonic-gate sbd_err_clear(&err); 782*0Sstevel@tonic-gate rv = DDI_FAILURE; 783*0Sstevel@tonic-gate break; 784*0Sstevel@tonic-gate } 785*0Sstevel@tonic-gate 786*0Sstevel@tonic-gate minor_num = DR_MAKE_MINOR(instance, bd); 787*0Sstevel@tonic-gate rv = ddi_create_minor_node(dip, name, S_IFCHR, 788*0Sstevel@tonic-gate minor_num, DDI_NT_SBD_ATTACHMENT_POINT, NULL); 789*0Sstevel@tonic-gate if (rv != DDI_SUCCESS) 790*0Sstevel@tonic-gate rv = DDI_FAILURE; 791*0Sstevel@tonic-gate } 792*0Sstevel@tonic-gate 793*0Sstevel@tonic-gate if (rv == DDI_SUCCESS) { 794*0Sstevel@tonic-gate /* 795*0Sstevel@tonic-gate * Announce the node's presence. 796*0Sstevel@tonic-gate */ 797*0Sstevel@tonic-gate ddi_report_dev(dip); 798*0Sstevel@tonic-gate } else { 799*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 800*0Sstevel@tonic-gate } 801*0Sstevel@tonic-gate /* 802*0Sstevel@tonic-gate * Init registered unsafe devs. 803*0Sstevel@tonic-gate */ 804*0Sstevel@tonic-gate dr_unsafe_devs.devnames = NULL; 805*0Sstevel@tonic-gate rv2 = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 806*0Sstevel@tonic-gate DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, 807*0Sstevel@tonic-gate "unsupported-io-drivers", &dr_unsafe_devs.devnames, 808*0Sstevel@tonic-gate &dr_unsafe_devs.ndevs); 809*0Sstevel@tonic-gate 810*0Sstevel@tonic-gate if (rv2 != DDI_PROP_SUCCESS) 811*0Sstevel@tonic-gate dr_unsafe_devs.ndevs = 0; 812*0Sstevel@tonic-gate 813*0Sstevel@tonic-gate rw_exit(&dr_grwlock); 814*0Sstevel@tonic-gate return (rv); 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate default: 817*0Sstevel@tonic-gate return (DDI_FAILURE); 818*0Sstevel@tonic-gate } 819*0Sstevel@tonic-gate 820*0Sstevel@tonic-gate /*NOTREACHED*/ 821*0Sstevel@tonic-gate } 822*0Sstevel@tonic-gate 823*0Sstevel@tonic-gate static int 824*0Sstevel@tonic-gate dr_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 825*0Sstevel@tonic-gate { 826*0Sstevel@tonic-gate int instance; 827*0Sstevel@tonic-gate dr_softstate_t *softsp; 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate switch (cmd) { 830*0Sstevel@tonic-gate case DDI_DETACH: 831*0Sstevel@tonic-gate if (!dr_modunload_okay) 832*0Sstevel@tonic-gate return (DDI_FAILURE); 833*0Sstevel@tonic-gate 834*0Sstevel@tonic-gate rw_enter(&dr_grwlock, RW_WRITER); 835*0Sstevel@tonic-gate 836*0Sstevel@tonic-gate instance = ddi_get_instance(dip); 837*0Sstevel@tonic-gate softsp = ddi_get_soft_state(dr_g.softsp, instance); 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /* TODO: eliminate dr_boardlist */ 840*0Sstevel@tonic-gate ASSERT(softsp->boards == dr_boardlist); 841*0Sstevel@tonic-gate 842*0Sstevel@tonic-gate /* remove all minor nodes */ 843*0Sstevel@tonic-gate ddi_remove_minor_node(dip, NULL); 844*0Sstevel@tonic-gate 845*0Sstevel@tonic-gate if (softsp->dr_initialized) { 846*0Sstevel@tonic-gate int bd; 847*0Sstevel@tonic-gate 848*0Sstevel@tonic-gate for (bd = 0; bd < MAX_BOARDS; bd++) 849*0Sstevel@tonic-gate dr_board_destroy(&softsp->boards[bd]); 850*0Sstevel@tonic-gate } 851*0Sstevel@tonic-gate 852*0Sstevel@tonic-gate FREESTRUCT(softsp->boards, dr_board_t, MAX_BOARDS); 853*0Sstevel@tonic-gate mutex_destroy(&softsp->i_lock); 854*0Sstevel@tonic-gate ddi_soft_state_free(dr_g.softsp, instance); 855*0Sstevel@tonic-gate 856*0Sstevel@tonic-gate rw_exit(&dr_grwlock); 857*0Sstevel@tonic-gate return (DDI_SUCCESS); 858*0Sstevel@tonic-gate 859*0Sstevel@tonic-gate default: 860*0Sstevel@tonic-gate return (DDI_FAILURE); 861*0Sstevel@tonic-gate } 862*0Sstevel@tonic-gate /*NOTREACHED*/ 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate static int 866*0Sstevel@tonic-gate dr_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 867*0Sstevel@tonic-gate { 868*0Sstevel@tonic-gate _NOTE(ARGUNUSED(dip)) 869*0Sstevel@tonic-gate 870*0Sstevel@tonic-gate dev_t dev = (dev_t)arg; 871*0Sstevel@tonic-gate int instance, error; 872*0Sstevel@tonic-gate dr_softstate_t *softsp; 873*0Sstevel@tonic-gate 874*0Sstevel@tonic-gate *result = NULL; 875*0Sstevel@tonic-gate error = DDI_SUCCESS; 876*0Sstevel@tonic-gate instance = DR_MINOR2INST(getminor(dev)); 877*0Sstevel@tonic-gate 878*0Sstevel@tonic-gate switch (cmd) { 879*0Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 880*0Sstevel@tonic-gate softsp = ddi_get_soft_state(dr_g.softsp, instance); 881*0Sstevel@tonic-gate if (softsp == NULL) 882*0Sstevel@tonic-gate return (DDI_FAILURE); 883*0Sstevel@tonic-gate *result = (void *)softsp->dip; 884*0Sstevel@tonic-gate break; 885*0Sstevel@tonic-gate 886*0Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 887*0Sstevel@tonic-gate *result = (void *)instance; 888*0Sstevel@tonic-gate break; 889*0Sstevel@tonic-gate 890*0Sstevel@tonic-gate default: 891*0Sstevel@tonic-gate error = DDI_FAILURE; 892*0Sstevel@tonic-gate break; 893*0Sstevel@tonic-gate } 894*0Sstevel@tonic-gate 895*0Sstevel@tonic-gate return (error); 896*0Sstevel@tonic-gate } 897*0Sstevel@tonic-gate 898*0Sstevel@tonic-gate /* 899*0Sstevel@tonic-gate * DR operations. 900*0Sstevel@tonic-gate */ 901*0Sstevel@tonic-gate 902*0Sstevel@tonic-gate static int 903*0Sstevel@tonic-gate dr_copyin_iocmd(dr_handle_t *hp) 904*0Sstevel@tonic-gate { 905*0Sstevel@tonic-gate static fn_t f = "dr_copyin_iocmd"; 906*0Sstevel@tonic-gate sbd_cmd_t *scp = &hp->h_sbdcmd; 907*0Sstevel@tonic-gate 908*0Sstevel@tonic-gate if (hp->h_iap == NULL) 909*0Sstevel@tonic-gate return (EINVAL); 910*0Sstevel@tonic-gate 911*0Sstevel@tonic-gate bzero((caddr_t)scp, sizeof (sbd_cmd_t)); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 914*0Sstevel@tonic-gate if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) { 915*0Sstevel@tonic-gate sbd_cmd32_t scmd32; 916*0Sstevel@tonic-gate 917*0Sstevel@tonic-gate bzero((caddr_t)&scmd32, sizeof (sbd_cmd32_t)); 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate if (ddi_copyin((void *)hp->h_iap, (void *)&scmd32, 920*0Sstevel@tonic-gate sizeof (sbd_cmd32_t), hp->h_mode)) { 921*0Sstevel@tonic-gate cmn_err(CE_WARN, 922*0Sstevel@tonic-gate "%s: (32bit) failed to copyin " 923*0Sstevel@tonic-gate "sbdcmd-struct", f); 924*0Sstevel@tonic-gate return (EFAULT); 925*0Sstevel@tonic-gate } 926*0Sstevel@tonic-gate scp->cmd_cm.c_id.c_type = scmd32.cmd_cm.c_id.c_type; 927*0Sstevel@tonic-gate scp->cmd_cm.c_id.c_unit = scmd32.cmd_cm.c_id.c_unit; 928*0Sstevel@tonic-gate bcopy(&scmd32.cmd_cm.c_id.c_name[0], 929*0Sstevel@tonic-gate &scp->cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME); 930*0Sstevel@tonic-gate scp->cmd_cm.c_flags = scmd32.cmd_cm.c_flags; 931*0Sstevel@tonic-gate scp->cmd_cm.c_len = scmd32.cmd_cm.c_len; 932*0Sstevel@tonic-gate scp->cmd_cm.c_opts = (caddr_t)scmd32.cmd_cm.c_opts; 933*0Sstevel@tonic-gate 934*0Sstevel@tonic-gate switch (hp->h_cmd) { 935*0Sstevel@tonic-gate case SBD_CMD_STATUS: 936*0Sstevel@tonic-gate scp->cmd_stat.s_nbytes = scmd32.cmd_stat.s_nbytes; 937*0Sstevel@tonic-gate scp->cmd_stat.s_statp = 938*0Sstevel@tonic-gate (caddr_t)scmd32.cmd_stat.s_statp; 939*0Sstevel@tonic-gate break; 940*0Sstevel@tonic-gate default: 941*0Sstevel@tonic-gate break; 942*0Sstevel@tonic-gate 943*0Sstevel@tonic-gate } 944*0Sstevel@tonic-gate } else 945*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 946*0Sstevel@tonic-gate if (ddi_copyin((void *)hp->h_iap, (void *)scp, 947*0Sstevel@tonic-gate sizeof (sbd_cmd_t), hp->h_mode) != 0) { 948*0Sstevel@tonic-gate cmn_err(CE_WARN, 949*0Sstevel@tonic-gate "%s: failed to copyin sbdcmd-struct", f); 950*0Sstevel@tonic-gate return (EFAULT); 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate if ((hp->h_opts.size = scp->cmd_cm.c_len) != 0) { 954*0Sstevel@tonic-gate hp->h_opts.copts = GETSTRUCT(char, scp->cmd_cm.c_len + 1); 955*0Sstevel@tonic-gate ++hp->h_opts.size; 956*0Sstevel@tonic-gate if (ddi_copyin((void *)scp->cmd_cm.c_opts, 957*0Sstevel@tonic-gate (void *)hp->h_opts.copts, 958*0Sstevel@tonic-gate scp->cmd_cm.c_len, hp->h_mode) != 0) { 959*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: failed to copyin options", f); 960*0Sstevel@tonic-gate return (EFAULT); 961*0Sstevel@tonic-gate } 962*0Sstevel@tonic-gate } 963*0Sstevel@tonic-gate return (0); 964*0Sstevel@tonic-gate } 965*0Sstevel@tonic-gate 966*0Sstevel@tonic-gate static int 967*0Sstevel@tonic-gate dr_copyout_iocmd(dr_handle_t *hp) 968*0Sstevel@tonic-gate { 969*0Sstevel@tonic-gate static fn_t f = "dr_copyout_iocmd"; 970*0Sstevel@tonic-gate sbd_cmd_t *scp = &hp->h_sbdcmd; 971*0Sstevel@tonic-gate 972*0Sstevel@tonic-gate if (hp->h_iap == NULL) 973*0Sstevel@tonic-gate return (EINVAL); 974*0Sstevel@tonic-gate 975*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 976*0Sstevel@tonic-gate if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) { 977*0Sstevel@tonic-gate sbd_cmd32_t scmd32; 978*0Sstevel@tonic-gate 979*0Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_type = scp->cmd_cm.c_id.c_type; 980*0Sstevel@tonic-gate scmd32.cmd_cm.c_id.c_unit = scp->cmd_cm.c_id.c_unit; 981*0Sstevel@tonic-gate bcopy(&scp->cmd_cm.c_id.c_name[0], 982*0Sstevel@tonic-gate &scmd32.cmd_cm.c_id.c_name[0], OBP_MAXPROPNAME); 983*0Sstevel@tonic-gate 984*0Sstevel@tonic-gate scmd32.cmd_cm.c_flags = scp->cmd_cm.c_flags; 985*0Sstevel@tonic-gate scmd32.cmd_cm.c_len = scp->cmd_cm.c_len; 986*0Sstevel@tonic-gate scmd32.cmd_cm.c_opts = (caddr32_t)scp->cmd_cm.c_opts; 987*0Sstevel@tonic-gate 988*0Sstevel@tonic-gate switch (hp->h_cmd) { 989*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 990*0Sstevel@tonic-gate scmd32.cmd_getncm.g_ncm = scp->cmd_getncm.g_ncm; 991*0Sstevel@tonic-gate break; 992*0Sstevel@tonic-gate default: 993*0Sstevel@tonic-gate break; 994*0Sstevel@tonic-gate } 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate if (ddi_copyout((void *)&scmd32, (void *)hp->h_iap, 997*0Sstevel@tonic-gate sizeof (sbd_cmd32_t), hp->h_mode)) { 998*0Sstevel@tonic-gate cmn_err(CE_WARN, 999*0Sstevel@tonic-gate "%s: (32bit) failed to copyout " 1000*0Sstevel@tonic-gate "sbdcmd-struct", f); 1001*0Sstevel@tonic-gate return (EFAULT); 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate } else 1004*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1005*0Sstevel@tonic-gate if (ddi_copyout((void *)scp, (void *)hp->h_iap, 1006*0Sstevel@tonic-gate sizeof (sbd_cmd_t), hp->h_mode) != 0) { 1007*0Sstevel@tonic-gate cmn_err(CE_WARN, 1008*0Sstevel@tonic-gate "%s: failed to copyout sbdcmd-struct", f); 1009*0Sstevel@tonic-gate return (EFAULT); 1010*0Sstevel@tonic-gate } 1011*0Sstevel@tonic-gate 1012*0Sstevel@tonic-gate return (0); 1013*0Sstevel@tonic-gate } 1014*0Sstevel@tonic-gate 1015*0Sstevel@tonic-gate static int 1016*0Sstevel@tonic-gate dr_copyout_errs(dr_handle_t *hp) 1017*0Sstevel@tonic-gate { 1018*0Sstevel@tonic-gate static fn_t f = "dr_copyout_errs"; 1019*0Sstevel@tonic-gate 1020*0Sstevel@tonic-gate if (hp->h_err == NULL) 1021*0Sstevel@tonic-gate return (0); 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate if (hp->h_err->e_code) { 1024*0Sstevel@tonic-gate PR_ALL("%s: error %d %s", 1025*0Sstevel@tonic-gate f, hp->h_err->e_code, hp->h_err->e_rsc); 1026*0Sstevel@tonic-gate } 1027*0Sstevel@tonic-gate 1028*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 1029*0Sstevel@tonic-gate if (ddi_model_convert_from(hp->h_mode & FMODELS) == DDI_MODEL_ILP32) { 1030*0Sstevel@tonic-gate sbd_error32_t *serr32p; 1031*0Sstevel@tonic-gate 1032*0Sstevel@tonic-gate serr32p = GETSTRUCT(sbd_error32_t, 1); 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate serr32p->e_code = hp->h_err->e_code; 1035*0Sstevel@tonic-gate bcopy(&hp->h_err->e_rsc[0], &serr32p->e_rsc[0], 1036*0Sstevel@tonic-gate MAXPATHLEN); 1037*0Sstevel@tonic-gate if (ddi_copyout((void *)serr32p, 1038*0Sstevel@tonic-gate (void *)&((sbd_ioctl_arg32_t *)hp->h_iap)->i_err, 1039*0Sstevel@tonic-gate sizeof (sbd_error32_t), hp->h_mode)) { 1040*0Sstevel@tonic-gate cmn_err(CE_WARN, 1041*0Sstevel@tonic-gate "%s: (32bit) failed to copyout", f); 1042*0Sstevel@tonic-gate return (EFAULT); 1043*0Sstevel@tonic-gate } 1044*0Sstevel@tonic-gate FREESTRUCT(serr32p, sbd_error32_t, 1); 1045*0Sstevel@tonic-gate } else 1046*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 1047*0Sstevel@tonic-gate if (ddi_copyout((void *)hp->h_err, 1048*0Sstevel@tonic-gate (void *)&hp->h_iap->i_err, 1049*0Sstevel@tonic-gate sizeof (sbd_error_t), hp->h_mode)) { 1050*0Sstevel@tonic-gate cmn_err(CE_WARN, 1051*0Sstevel@tonic-gate "%s: failed to copyout", f); 1052*0Sstevel@tonic-gate return (EFAULT); 1053*0Sstevel@tonic-gate } 1054*0Sstevel@tonic-gate 1055*0Sstevel@tonic-gate sbd_err_clear(&hp->h_err); 1056*0Sstevel@tonic-gate 1057*0Sstevel@tonic-gate return (0); 1058*0Sstevel@tonic-gate 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate /* 1062*0Sstevel@tonic-gate * pre-op entry point must sbd_err_set_c(), if needed. 1063*0Sstevel@tonic-gate * Return value of non-zero indicates failure. 1064*0Sstevel@tonic-gate */ 1065*0Sstevel@tonic-gate static int 1066*0Sstevel@tonic-gate dr_pre_op(dr_handle_t *hp) 1067*0Sstevel@tonic-gate { 1068*0Sstevel@tonic-gate int rv = 0, t; 1069*0Sstevel@tonic-gate int cmd, serr = 0; 1070*0Sstevel@tonic-gate dr_devset_t devset; 1071*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1072*0Sstevel@tonic-gate dr_handle_t *shp = hp; 1073*0Sstevel@tonic-gate static fn_t f = "dr_pre_op"; 1074*0Sstevel@tonic-gate 1075*0Sstevel@tonic-gate cmd = hp->h_cmd; 1076*0Sstevel@tonic-gate devset = shp->h_devset; 1077*0Sstevel@tonic-gate 1078*0Sstevel@tonic-gate PR_ALL("%s (cmd = %s)...\n", f, (uint_t)SBD_CMD_STR(cmd)); 1079*0Sstevel@tonic-gate 1080*0Sstevel@tonic-gate hp->h_err = drmach_pre_op(cmd, bp->b_id, &hp->h_opts); 1081*0Sstevel@tonic-gate if (hp->h_err != NULL) { 1082*0Sstevel@tonic-gate PR_ALL("drmach_pre_op failed for cmd %s(%d)\n", 1083*0Sstevel@tonic-gate SBD_CMD_STR(cmd), cmd); 1084*0Sstevel@tonic-gate return (-1); 1085*0Sstevel@tonic-gate } 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate /* 1088*0Sstevel@tonic-gate * Check for valid state transitions. 1089*0Sstevel@tonic-gate */ 1090*0Sstevel@tonic-gate if ((t = CMD2INDEX(cmd)) != -1) { 1091*0Sstevel@tonic-gate struct dr_state_trans *transp; 1092*0Sstevel@tonic-gate int state_err; 1093*0Sstevel@tonic-gate 1094*0Sstevel@tonic-gate transp = &dr_state_transition[t]; 1095*0Sstevel@tonic-gate ASSERT(transp->x_cmd == cmd); 1096*0Sstevel@tonic-gate 1097*0Sstevel@tonic-gate state_err = dr_check_transition(bp, &devset, transp, cmd); 1098*0Sstevel@tonic-gate 1099*0Sstevel@tonic-gate if (state_err < 0) { 1100*0Sstevel@tonic-gate /* 1101*0Sstevel@tonic-gate * Invalidate device. 1102*0Sstevel@tonic-gate */ 1103*0Sstevel@tonic-gate dr_op_err(CE_IGNORE, hp, ESBD_INVAL, NULL); 1104*0Sstevel@tonic-gate serr = -1; 1105*0Sstevel@tonic-gate PR_ALL("%s: invalid devset (0x%x)\n", 1106*0Sstevel@tonic-gate f, (uint_t)devset); 1107*0Sstevel@tonic-gate } else if (state_err != 0) { 1108*0Sstevel@tonic-gate /* 1109*0Sstevel@tonic-gate * State transition is not a valid one. 1110*0Sstevel@tonic-gate */ 1111*0Sstevel@tonic-gate dr_op_err(CE_IGNORE, hp, 1112*0Sstevel@tonic-gate transp->x_op[state_err].x_err, NULL); 1113*0Sstevel@tonic-gate 1114*0Sstevel@tonic-gate serr = transp->x_op[state_err].x_rv; 1115*0Sstevel@tonic-gate 1116*0Sstevel@tonic-gate PR_ALL("%s: invalid state %s(%d) for cmd %s(%d)\n", 1117*0Sstevel@tonic-gate f, state_str[state_err], state_err, 1118*0Sstevel@tonic-gate SBD_CMD_STR(cmd), cmd); 1119*0Sstevel@tonic-gate } else { 1120*0Sstevel@tonic-gate shp->h_devset = devset; 1121*0Sstevel@tonic-gate } 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate if (serr) { 1125*0Sstevel@tonic-gate rv = -1; 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate return (rv); 1129*0Sstevel@tonic-gate } 1130*0Sstevel@tonic-gate 1131*0Sstevel@tonic-gate static int 1132*0Sstevel@tonic-gate dr_post_op(dr_handle_t *hp) 1133*0Sstevel@tonic-gate { 1134*0Sstevel@tonic-gate int rv = 0; 1135*0Sstevel@tonic-gate int cmd; 1136*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1137*0Sstevel@tonic-gate static fn_t f = "dr_post_op"; 1138*0Sstevel@tonic-gate 1139*0Sstevel@tonic-gate cmd = hp->h_cmd; 1140*0Sstevel@tonic-gate 1141*0Sstevel@tonic-gate PR_ALL("%s (cmd = %s)...\n", f, (uint_t)SBD_CMD_STR(cmd)); 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate /* errors should have been caught by now */ 1144*0Sstevel@tonic-gate ASSERT(hp->h_err == NULL); 1145*0Sstevel@tonic-gate 1146*0Sstevel@tonic-gate hp->h_err = drmach_post_op(cmd, bp->b_id, &hp->h_opts); 1147*0Sstevel@tonic-gate if (hp->h_err != NULL) { 1148*0Sstevel@tonic-gate PR_ALL("drmach_post_op failed for cmd %s(%d)\n", 1149*0Sstevel@tonic-gate SBD_CMD_STR(cmd), cmd); 1150*0Sstevel@tonic-gate return (-1); 1151*0Sstevel@tonic-gate } 1152*0Sstevel@tonic-gate 1153*0Sstevel@tonic-gate switch (cmd) { 1154*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 1155*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 1156*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 1157*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 1158*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 1159*0Sstevel@tonic-gate case SBD_CMD_STATUS: 1160*0Sstevel@tonic-gate break; 1161*0Sstevel@tonic-gate 1162*0Sstevel@tonic-gate default: 1163*0Sstevel@tonic-gate break; 1164*0Sstevel@tonic-gate } 1165*0Sstevel@tonic-gate 1166*0Sstevel@tonic-gate return (rv); 1167*0Sstevel@tonic-gate } 1168*0Sstevel@tonic-gate 1169*0Sstevel@tonic-gate static int 1170*0Sstevel@tonic-gate dr_exec_op(dr_handle_t *hp) 1171*0Sstevel@tonic-gate { 1172*0Sstevel@tonic-gate int rv = 0; 1173*0Sstevel@tonic-gate static fn_t f = "dr_exec_op"; 1174*0Sstevel@tonic-gate 1175*0Sstevel@tonic-gate /* errors should have been caught by now */ 1176*0Sstevel@tonic-gate ASSERT(hp->h_err == NULL); 1177*0Sstevel@tonic-gate 1178*0Sstevel@tonic-gate switch (hp->h_cmd) { 1179*0Sstevel@tonic-gate case SBD_CMD_ASSIGN: 1180*0Sstevel@tonic-gate dr_assign_board(hp); 1181*0Sstevel@tonic-gate break; 1182*0Sstevel@tonic-gate 1183*0Sstevel@tonic-gate case SBD_CMD_UNASSIGN: 1184*0Sstevel@tonic-gate dr_unassign_board(hp); 1185*0Sstevel@tonic-gate break; 1186*0Sstevel@tonic-gate 1187*0Sstevel@tonic-gate case SBD_CMD_POWEROFF: 1188*0Sstevel@tonic-gate dr_poweroff_board(hp); 1189*0Sstevel@tonic-gate break; 1190*0Sstevel@tonic-gate 1191*0Sstevel@tonic-gate case SBD_CMD_POWERON: 1192*0Sstevel@tonic-gate dr_poweron_board(hp); 1193*0Sstevel@tonic-gate break; 1194*0Sstevel@tonic-gate 1195*0Sstevel@tonic-gate case SBD_CMD_TEST: 1196*0Sstevel@tonic-gate dr_test_board(hp); 1197*0Sstevel@tonic-gate break; 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate case SBD_CMD_CONNECT: 1200*0Sstevel@tonic-gate dr_connect(hp); 1201*0Sstevel@tonic-gate break; 1202*0Sstevel@tonic-gate 1203*0Sstevel@tonic-gate case SBD_CMD_CONFIGURE: 1204*0Sstevel@tonic-gate dr_dev_configure(hp); 1205*0Sstevel@tonic-gate break; 1206*0Sstevel@tonic-gate 1207*0Sstevel@tonic-gate case SBD_CMD_UNCONFIGURE: 1208*0Sstevel@tonic-gate dr_dev_release(hp); 1209*0Sstevel@tonic-gate if (hp->h_err == NULL) 1210*0Sstevel@tonic-gate rv = dr_dev_unconfigure(hp); 1211*0Sstevel@tonic-gate else 1212*0Sstevel@tonic-gate dr_dev_cancel(hp); 1213*0Sstevel@tonic-gate break; 1214*0Sstevel@tonic-gate 1215*0Sstevel@tonic-gate case SBD_CMD_DISCONNECT: 1216*0Sstevel@tonic-gate rv = dr_disconnect(hp); 1217*0Sstevel@tonic-gate break; 1218*0Sstevel@tonic-gate 1219*0Sstevel@tonic-gate case SBD_CMD_STATUS: 1220*0Sstevel@tonic-gate rv = dr_dev_status(hp); 1221*0Sstevel@tonic-gate break; 1222*0Sstevel@tonic-gate 1223*0Sstevel@tonic-gate case SBD_CMD_GETNCM: 1224*0Sstevel@tonic-gate hp->h_sbdcmd.cmd_getncm.g_ncm = dr_get_ncm(hp); 1225*0Sstevel@tonic-gate rv = dr_copyout_iocmd(hp); 1226*0Sstevel@tonic-gate break; 1227*0Sstevel@tonic-gate 1228*0Sstevel@tonic-gate case SBD_CMD_PASSTHRU: 1229*0Sstevel@tonic-gate rv = dr_pt_ioctl(hp); 1230*0Sstevel@tonic-gate break; 1231*0Sstevel@tonic-gate 1232*0Sstevel@tonic-gate default: 1233*0Sstevel@tonic-gate cmn_err(CE_WARN, 1234*0Sstevel@tonic-gate "%s: unknown command (%d)", 1235*0Sstevel@tonic-gate f, hp->h_cmd); 1236*0Sstevel@tonic-gate break; 1237*0Sstevel@tonic-gate } 1238*0Sstevel@tonic-gate 1239*0Sstevel@tonic-gate if (hp->h_err != NULL) { 1240*0Sstevel@tonic-gate rv = -1; 1241*0Sstevel@tonic-gate } 1242*0Sstevel@tonic-gate 1243*0Sstevel@tonic-gate return (rv); 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate static void 1247*0Sstevel@tonic-gate dr_assign_board(dr_handle_t *hp) 1248*0Sstevel@tonic-gate { 1249*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1250*0Sstevel@tonic-gate 1251*0Sstevel@tonic-gate hp->h_err = drmach_board_assign(bp->b_num, &bp->b_id); 1252*0Sstevel@tonic-gate if (hp->h_err == NULL) { 1253*0Sstevel@tonic-gate bp->b_assigned = 1; 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate } 1256*0Sstevel@tonic-gate 1257*0Sstevel@tonic-gate static void 1258*0Sstevel@tonic-gate dr_unassign_board(dr_handle_t *hp) 1259*0Sstevel@tonic-gate { 1260*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1261*0Sstevel@tonic-gate 1262*0Sstevel@tonic-gate /* 1263*0Sstevel@tonic-gate * Block out status during unassign. 1264*0Sstevel@tonic-gate * Not doing cv_wait_sig here as starfire SSP software 1265*0Sstevel@tonic-gate * ignores unassign failure and removes board from 1266*0Sstevel@tonic-gate * domain mask causing system panic. 1267*0Sstevel@tonic-gate * TODO: Change cv_wait to cv_wait_sig when SSP software 1268*0Sstevel@tonic-gate * handles unassign failure. 1269*0Sstevel@tonic-gate */ 1270*0Sstevel@tonic-gate dr_lock_status(bp); 1271*0Sstevel@tonic-gate 1272*0Sstevel@tonic-gate hp->h_err = drmach_board_unassign(bp->b_id); 1273*0Sstevel@tonic-gate if (hp->h_err == NULL) { 1274*0Sstevel@tonic-gate /* 1275*0Sstevel@tonic-gate * clear drmachid_t handle; not valid after board unassign 1276*0Sstevel@tonic-gate */ 1277*0Sstevel@tonic-gate bp->b_id = 0; 1278*0Sstevel@tonic-gate bp->b_assigned = 0; 1279*0Sstevel@tonic-gate } 1280*0Sstevel@tonic-gate 1281*0Sstevel@tonic-gate dr_unlock_status(bp); 1282*0Sstevel@tonic-gate } 1283*0Sstevel@tonic-gate 1284*0Sstevel@tonic-gate static void 1285*0Sstevel@tonic-gate dr_poweron_board(dr_handle_t *hp) 1286*0Sstevel@tonic-gate { 1287*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1288*0Sstevel@tonic-gate 1289*0Sstevel@tonic-gate hp->h_err = drmach_board_poweron(bp->b_id); 1290*0Sstevel@tonic-gate } 1291*0Sstevel@tonic-gate 1292*0Sstevel@tonic-gate static void 1293*0Sstevel@tonic-gate dr_poweroff_board(dr_handle_t *hp) 1294*0Sstevel@tonic-gate { 1295*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1296*0Sstevel@tonic-gate 1297*0Sstevel@tonic-gate hp->h_err = drmach_board_poweroff(bp->b_id); 1298*0Sstevel@tonic-gate } 1299*0Sstevel@tonic-gate 1300*0Sstevel@tonic-gate static void 1301*0Sstevel@tonic-gate dr_test_board(dr_handle_t *hp) 1302*0Sstevel@tonic-gate { 1303*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1304*0Sstevel@tonic-gate hp->h_err = drmach_board_test(bp->b_id, &hp->h_opts, 1305*0Sstevel@tonic-gate dr_cmd_flags(hp) & SBD_FLAG_FORCE); 1306*0Sstevel@tonic-gate } 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate /* 1309*0Sstevel@tonic-gate * Create and populate the component nodes for a board. Assumes that the 1310*0Sstevel@tonic-gate * devlists for the board have been initialized. 1311*0Sstevel@tonic-gate */ 1312*0Sstevel@tonic-gate static void 1313*0Sstevel@tonic-gate dr_make_comp_nodes(dr_board_t *bp) { 1314*0Sstevel@tonic-gate 1315*0Sstevel@tonic-gate int i; 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate /* 1318*0Sstevel@tonic-gate * Make nodes for the individual components on the board. 1319*0Sstevel@tonic-gate * First we need to initialize memory unit data structures of board 1320*0Sstevel@tonic-gate * structure. 1321*0Sstevel@tonic-gate */ 1322*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 1323*0Sstevel@tonic-gate dr_mem_unit_t *mp; 1324*0Sstevel@tonic-gate 1325*0Sstevel@tonic-gate mp = dr_get_mem_unit(bp, i); 1326*0Sstevel@tonic-gate dr_init_mem_unit(mp); 1327*0Sstevel@tonic-gate } 1328*0Sstevel@tonic-gate 1329*0Sstevel@tonic-gate /* 1330*0Sstevel@tonic-gate * Initialize cpu unit data structures. 1331*0Sstevel@tonic-gate */ 1332*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 1333*0Sstevel@tonic-gate dr_cpu_unit_t *cp; 1334*0Sstevel@tonic-gate 1335*0Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, i); 1336*0Sstevel@tonic-gate dr_init_cpu_unit(cp); 1337*0Sstevel@tonic-gate } 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate /* 1340*0Sstevel@tonic-gate * Initialize io unit data structures. 1341*0Sstevel@tonic-gate */ 1342*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 1343*0Sstevel@tonic-gate dr_io_unit_t *ip; 1344*0Sstevel@tonic-gate 1345*0Sstevel@tonic-gate ip = dr_get_io_unit(bp, i); 1346*0Sstevel@tonic-gate dr_init_io_unit(ip); 1347*0Sstevel@tonic-gate } 1348*0Sstevel@tonic-gate 1349*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_CONNECTED); 1350*0Sstevel@tonic-gate 1351*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_CONNECTED; 1352*0Sstevel@tonic-gate bp->b_ostate = SBD_STAT_UNCONFIGURED; 1353*0Sstevel@tonic-gate bp->b_cond = SBD_COND_OK; 1354*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 1355*0Sstevel@tonic-gate 1356*0Sstevel@tonic-gate } 1357*0Sstevel@tonic-gate 1358*0Sstevel@tonic-gate /* 1359*0Sstevel@tonic-gate * Only do work if called to operate on an entire board 1360*0Sstevel@tonic-gate * which doesn't already have components present. 1361*0Sstevel@tonic-gate */ 1362*0Sstevel@tonic-gate static void 1363*0Sstevel@tonic-gate dr_connect(dr_handle_t *hp) 1364*0Sstevel@tonic-gate { 1365*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1366*0Sstevel@tonic-gate static fn_t f = "dr_connect"; 1367*0Sstevel@tonic-gate 1368*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 1369*0Sstevel@tonic-gate 1370*0Sstevel@tonic-gate if (DR_DEVS_PRESENT(bp)) { 1371*0Sstevel@tonic-gate /* 1372*0Sstevel@tonic-gate * Board already has devices present. 1373*0Sstevel@tonic-gate */ 1374*0Sstevel@tonic-gate PR_ALL("%s: devices already present (0x%x)\n", 1375*0Sstevel@tonic-gate f, DR_DEVS_PRESENT(bp)); 1376*0Sstevel@tonic-gate return; 1377*0Sstevel@tonic-gate } 1378*0Sstevel@tonic-gate 1379*0Sstevel@tonic-gate hp->h_err = drmach_board_connect(bp->b_id, &hp->h_opts); 1380*0Sstevel@tonic-gate if (hp->h_err) 1381*0Sstevel@tonic-gate return; 1382*0Sstevel@tonic-gate 1383*0Sstevel@tonic-gate hp->h_err = dr_init_devlists(bp); 1384*0Sstevel@tonic-gate if (hp->h_err) 1385*0Sstevel@tonic-gate return; 1386*0Sstevel@tonic-gate else if (bp->b_ndev == 0) { 1387*0Sstevel@tonic-gate dr_op_err(CE_WARN, hp, ESBD_EMPTY_BD, bp->b_path); 1388*0Sstevel@tonic-gate return; 1389*0Sstevel@tonic-gate } else { 1390*0Sstevel@tonic-gate dr_make_comp_nodes(bp); 1391*0Sstevel@tonic-gate return; 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate /*NOTREACHED*/ 1394*0Sstevel@tonic-gate } 1395*0Sstevel@tonic-gate 1396*0Sstevel@tonic-gate static int 1397*0Sstevel@tonic-gate dr_disconnect(dr_handle_t *hp) 1398*0Sstevel@tonic-gate { 1399*0Sstevel@tonic-gate int i; 1400*0Sstevel@tonic-gate dr_devset_t devset; 1401*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1402*0Sstevel@tonic-gate static fn_t f = "dr_disconnect"; 1403*0Sstevel@tonic-gate 1404*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 1405*0Sstevel@tonic-gate 1406*0Sstevel@tonic-gate /* 1407*0Sstevel@tonic-gate * Only devices which are present, but 1408*0Sstevel@tonic-gate * unattached can be disconnected. 1409*0Sstevel@tonic-gate */ 1410*0Sstevel@tonic-gate devset = hp->h_devset & DR_DEVS_PRESENT(bp) & 1411*0Sstevel@tonic-gate DR_DEVS_UNATTACHED(bp); 1412*0Sstevel@tonic-gate 1413*0Sstevel@tonic-gate if ((devset == 0) && DR_DEVS_PRESENT(bp)) { 1414*0Sstevel@tonic-gate dr_op_err(CE_IGNORE, hp, ESBD_EMPTY_BD, bp->b_path); 1415*0Sstevel@tonic-gate return (0); 1416*0Sstevel@tonic-gate } 1417*0Sstevel@tonic-gate 1418*0Sstevel@tonic-gate /* 1419*0Sstevel@tonic-gate * Block out status during disconnect. 1420*0Sstevel@tonic-gate */ 1421*0Sstevel@tonic-gate mutex_enter(&bp->b_slock); 1422*0Sstevel@tonic-gate while (bp->b_sflags & DR_BSLOCK) { 1423*0Sstevel@tonic-gate if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) { 1424*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 1425*0Sstevel@tonic-gate return (EINTR); 1426*0Sstevel@tonic-gate } 1427*0Sstevel@tonic-gate } 1428*0Sstevel@tonic-gate bp->b_sflags |= DR_BSLOCK; 1429*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate hp->h_err = drmach_board_disconnect(bp->b_id, &hp->h_opts); 1432*0Sstevel@tonic-gate 1433*0Sstevel@tonic-gate DR_DEVS_DISCONNECT(bp, devset); 1434*0Sstevel@tonic-gate 1435*0Sstevel@tonic-gate ASSERT((DR_DEVS_ATTACHED(bp) & devset) == 0); 1436*0Sstevel@tonic-gate 1437*0Sstevel@tonic-gate /* 1438*0Sstevel@tonic-gate * Update per-device state transitions. 1439*0Sstevel@tonic-gate */ 1440*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 1441*0Sstevel@tonic-gate dr_cpu_unit_t *cp; 1442*0Sstevel@tonic-gate 1443*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) 1444*0Sstevel@tonic-gate continue; 1445*0Sstevel@tonic-gate 1446*0Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, i); 1447*0Sstevel@tonic-gate if (dr_disconnect_cpu(cp) == 0) 1448*0Sstevel@tonic-gate dr_device_transition(&cp->sbc_cm, DR_STATE_EMPTY); 1449*0Sstevel@tonic-gate else if (cp->sbc_cm.sbdev_error != NULL) 1450*0Sstevel@tonic-gate DRERR_SET_C(&hp->h_err, &cp->sbc_cm.sbdev_error); 1451*0Sstevel@tonic-gate 1452*0Sstevel@tonic-gate ASSERT(cp->sbc_cm.sbdev_error == NULL); 1453*0Sstevel@tonic-gate } 1454*0Sstevel@tonic-gate 1455*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 1456*0Sstevel@tonic-gate dr_mem_unit_t *mp; 1457*0Sstevel@tonic-gate 1458*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) 1459*0Sstevel@tonic-gate continue; 1460*0Sstevel@tonic-gate 1461*0Sstevel@tonic-gate mp = dr_get_mem_unit(bp, i); 1462*0Sstevel@tonic-gate if (dr_disconnect_mem(mp) == 0) 1463*0Sstevel@tonic-gate dr_device_transition(&mp->sbm_cm, DR_STATE_EMPTY); 1464*0Sstevel@tonic-gate else if (mp->sbm_cm.sbdev_error != NULL) 1465*0Sstevel@tonic-gate DRERR_SET_C(&hp->h_err, &mp->sbm_cm.sbdev_error); 1466*0Sstevel@tonic-gate 1467*0Sstevel@tonic-gate ASSERT(mp->sbm_cm.sbdev_error == NULL); 1468*0Sstevel@tonic-gate } 1469*0Sstevel@tonic-gate 1470*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 1471*0Sstevel@tonic-gate dr_io_unit_t *ip; 1472*0Sstevel@tonic-gate 1473*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i)) 1474*0Sstevel@tonic-gate continue; 1475*0Sstevel@tonic-gate 1476*0Sstevel@tonic-gate ip = dr_get_io_unit(bp, i); 1477*0Sstevel@tonic-gate if (dr_disconnect_io(ip) == 0) 1478*0Sstevel@tonic-gate dr_device_transition(&ip->sbi_cm, DR_STATE_EMPTY); 1479*0Sstevel@tonic-gate else if (ip->sbi_cm.sbdev_error != NULL) 1480*0Sstevel@tonic-gate DRERR_SET_C(&hp->h_err, &ip->sbi_cm.sbdev_error); 1481*0Sstevel@tonic-gate 1482*0Sstevel@tonic-gate ASSERT(ip->sbi_cm.sbdev_error == NULL); 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate if (hp->h_err) { 1485*0Sstevel@tonic-gate /* 1486*0Sstevel@tonic-gate * For certain errors, drmach_board_disconnect will mark 1487*0Sstevel@tonic-gate * the board as unusable; in these cases the devtree must 1488*0Sstevel@tonic-gate * be purged so that status calls will succeed. 1489*0Sstevel@tonic-gate * XXX 1490*0Sstevel@tonic-gate * This implementation checks for discrete error codes - 1491*0Sstevel@tonic-gate * someday, the i/f to drmach_board_disconnect should be 1492*0Sstevel@tonic-gate * changed to avoid the e_code testing. 1493*0Sstevel@tonic-gate */ 1494*0Sstevel@tonic-gate if ((hp->h_err->e_code == ESTC_MBXRPLY) || 1495*0Sstevel@tonic-gate (hp->h_err->e_code == ESTC_MBXRQST) || 1496*0Sstevel@tonic-gate (hp->h_err->e_code == ESTC_SMS_ERR_UNRECOVERABLE) || 1497*0Sstevel@tonic-gate (hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) || 1498*0Sstevel@tonic-gate (hp->h_err->e_code == ESTC_DEPROBE)) { 1499*0Sstevel@tonic-gate bp->b_ostate = SBD_STAT_UNCONFIGURED; 1500*0Sstevel@tonic-gate bp->b_busy = 0; 1501*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 1502*0Sstevel@tonic-gate 1503*0Sstevel@tonic-gate if (drmach_board_deprobe(bp->b_id)) 1504*0Sstevel@tonic-gate goto disconnect_done; 1505*0Sstevel@tonic-gate else 1506*0Sstevel@tonic-gate bp->b_ndev = 0; 1507*0Sstevel@tonic-gate } 1508*0Sstevel@tonic-gate 1509*0Sstevel@tonic-gate /* 1510*0Sstevel@tonic-gate * If the disconnect failed in a recoverable way, 1511*0Sstevel@tonic-gate * more work is required. 1512*0Sstevel@tonic-gate * XXX 1513*0Sstevel@tonic-gate * This implementation checks for discrete error codes - 1514*0Sstevel@tonic-gate * someday, the i/f to drmach_board_disconnect should be 1515*0Sstevel@tonic-gate * changed to avoid the e_code testing. 1516*0Sstevel@tonic-gate */ 1517*0Sstevel@tonic-gate if ((hp->h_err->e_code == ESTC_MBXRQST) || 1518*0Sstevel@tonic-gate (hp->h_err->e_code == ESTC_SMS_ERR_RECOVERABLE) || 1519*0Sstevel@tonic-gate (hp->h_err->e_code == ESTC_DEPROBE)) { 1520*0Sstevel@tonic-gate /* 1521*0Sstevel@tonic-gate * With this failure, the board has been deprobed 1522*0Sstevel@tonic-gate * by IKP, and reprobed. We've already gotten rid 1523*0Sstevel@tonic-gate * of the old devtree, now we need to reconstruct it 1524*0Sstevel@tonic-gate * based on the new IKP probe 1525*0Sstevel@tonic-gate */ 1526*0Sstevel@tonic-gate if (dr_init_devlists(bp) || (bp->b_ndev == 0)) 1527*0Sstevel@tonic-gate goto disconnect_done; 1528*0Sstevel@tonic-gate 1529*0Sstevel@tonic-gate dr_make_comp_nodes(bp); 1530*0Sstevel@tonic-gate } 1531*0Sstevel@tonic-gate } 1532*0Sstevel@tonic-gate /* 1533*0Sstevel@tonic-gate * Once all the components on a board have been disconnect 1534*0Sstevel@tonic-gate * the board's state can transition to disconnected and 1535*0Sstevel@tonic-gate * we can allow the deprobe to take place. 1536*0Sstevel@tonic-gate */ 1537*0Sstevel@tonic-gate if (hp->h_err == NULL && DR_DEVS_PRESENT(bp) == 0) { 1538*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_OCCUPIED); 1539*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_DISCONNECTED; 1540*0Sstevel@tonic-gate bp->b_ostate = SBD_STAT_UNCONFIGURED; 1541*0Sstevel@tonic-gate bp->b_busy = 0; 1542*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate hp->h_err = drmach_board_deprobe(bp->b_id); 1545*0Sstevel@tonic-gate 1546*0Sstevel@tonic-gate if (hp->h_err == NULL) { 1547*0Sstevel@tonic-gate bp->b_ndev = 0; 1548*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_EMPTY); 1549*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_EMPTY; 1550*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 1551*0Sstevel@tonic-gate } 1552*0Sstevel@tonic-gate } 1553*0Sstevel@tonic-gate 1554*0Sstevel@tonic-gate disconnect_done: 1555*0Sstevel@tonic-gate dr_unlock_status(bp); 1556*0Sstevel@tonic-gate 1557*0Sstevel@tonic-gate return (0); 1558*0Sstevel@tonic-gate } 1559*0Sstevel@tonic-gate 1560*0Sstevel@tonic-gate /* 1561*0Sstevel@tonic-gate * Check if a particular device is a valid target of the current 1562*0Sstevel@tonic-gate * operation. Return 1 if it is a valid target, and 0 otherwise. 1563*0Sstevel@tonic-gate */ 1564*0Sstevel@tonic-gate static int 1565*0Sstevel@tonic-gate dr_dev_is_target(dr_dev_unit_t *dp, int present_only, uint_t uset) 1566*0Sstevel@tonic-gate { 1567*0Sstevel@tonic-gate dr_common_unit_t *cp; 1568*0Sstevel@tonic-gate int is_present; 1569*0Sstevel@tonic-gate int is_attached; 1570*0Sstevel@tonic-gate 1571*0Sstevel@tonic-gate cp = &dp->du_common; 1572*0Sstevel@tonic-gate 1573*0Sstevel@tonic-gate /* check if the user requested this device */ 1574*0Sstevel@tonic-gate if ((uset & (1 << cp->sbdev_unum)) == 0) { 1575*0Sstevel@tonic-gate return (0); 1576*0Sstevel@tonic-gate } 1577*0Sstevel@tonic-gate 1578*0Sstevel@tonic-gate is_present = DR_DEV_IS_PRESENT(cp) ? 1 : 0; 1579*0Sstevel@tonic-gate is_attached = DR_DEV_IS_ATTACHED(cp) ? 1 : 0; 1580*0Sstevel@tonic-gate 1581*0Sstevel@tonic-gate /* 1582*0Sstevel@tonic-gate * If the present_only flag is set, a valid target 1583*0Sstevel@tonic-gate * must be present but not attached. Otherwise, it 1584*0Sstevel@tonic-gate * must be both present and attached. 1585*0Sstevel@tonic-gate */ 1586*0Sstevel@tonic-gate if (is_present && (present_only ^ is_attached)) { 1587*0Sstevel@tonic-gate /* sanity check */ 1588*0Sstevel@tonic-gate ASSERT(cp->sbdev_id != (drmachid_t)0); 1589*0Sstevel@tonic-gate 1590*0Sstevel@tonic-gate return (1); 1591*0Sstevel@tonic-gate } 1592*0Sstevel@tonic-gate 1593*0Sstevel@tonic-gate return (0); 1594*0Sstevel@tonic-gate } 1595*0Sstevel@tonic-gate 1596*0Sstevel@tonic-gate static void 1597*0Sstevel@tonic-gate dr_dev_make_list(dr_handle_t *hp, sbd_comp_type_t type, int present_only, 1598*0Sstevel@tonic-gate dr_common_unit_t ***devlist, int *devnum) 1599*0Sstevel@tonic-gate { 1600*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1601*0Sstevel@tonic-gate int unum; 1602*0Sstevel@tonic-gate int nunits; 1603*0Sstevel@tonic-gate uint_t uset; 1604*0Sstevel@tonic-gate int len; 1605*0Sstevel@tonic-gate dr_common_unit_t **list, **wp; 1606*0Sstevel@tonic-gate 1607*0Sstevel@tonic-gate switch (type) { 1608*0Sstevel@tonic-gate case SBD_COMP_CPU: 1609*0Sstevel@tonic-gate nunits = MAX_CPU_UNITS_PER_BOARD; 1610*0Sstevel@tonic-gate break; 1611*0Sstevel@tonic-gate case SBD_COMP_MEM: 1612*0Sstevel@tonic-gate nunits = MAX_MEM_UNITS_PER_BOARD; 1613*0Sstevel@tonic-gate break; 1614*0Sstevel@tonic-gate case SBD_COMP_IO: 1615*0Sstevel@tonic-gate nunits = MAX_IO_UNITS_PER_BOARD; 1616*0Sstevel@tonic-gate break; 1617*0Sstevel@tonic-gate default: 1618*0Sstevel@tonic-gate /* catch this in debug kernels */ 1619*0Sstevel@tonic-gate ASSERT(0); 1620*0Sstevel@tonic-gate break; 1621*0Sstevel@tonic-gate } 1622*0Sstevel@tonic-gate 1623*0Sstevel@tonic-gate /* allocate list storage. */ 1624*0Sstevel@tonic-gate len = sizeof (dr_common_unit_t *) * (nunits + 1); 1625*0Sstevel@tonic-gate list = kmem_zalloc(len, KM_SLEEP); 1626*0Sstevel@tonic-gate 1627*0Sstevel@tonic-gate /* record length of storage in first element */ 1628*0Sstevel@tonic-gate *list++ = (dr_common_unit_t *)len; 1629*0Sstevel@tonic-gate 1630*0Sstevel@tonic-gate /* get bit array signifying which units are to be involved */ 1631*0Sstevel@tonic-gate uset = DEVSET_GET_UNITSET(hp->h_devset, type); 1632*0Sstevel@tonic-gate 1633*0Sstevel@tonic-gate /* 1634*0Sstevel@tonic-gate * Adjust the loop count for CPU devices since all cores 1635*0Sstevel@tonic-gate * in a CMP will be examined in a single iteration. 1636*0Sstevel@tonic-gate */ 1637*0Sstevel@tonic-gate if (type == SBD_COMP_CPU) { 1638*0Sstevel@tonic-gate nunits = MAX_CMP_UNITS_PER_BOARD; 1639*0Sstevel@tonic-gate } 1640*0Sstevel@tonic-gate 1641*0Sstevel@tonic-gate /* populate list */ 1642*0Sstevel@tonic-gate for (wp = list, unum = 0; unum < nunits; unum++) { 1643*0Sstevel@tonic-gate 1644*0Sstevel@tonic-gate dr_dev_unit_t *dp; 1645*0Sstevel@tonic-gate int core; 1646*0Sstevel@tonic-gate int cunum; 1647*0Sstevel@tonic-gate 1648*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, type, unum); 1649*0Sstevel@tonic-gate if (dr_dev_is_target(dp, present_only, uset)) { 1650*0Sstevel@tonic-gate *wp++ = &dp->du_common; 1651*0Sstevel@tonic-gate } 1652*0Sstevel@tonic-gate 1653*0Sstevel@tonic-gate /* further processing is only required for CPUs */ 1654*0Sstevel@tonic-gate if (type != SBD_COMP_CPU) { 1655*0Sstevel@tonic-gate continue; 1656*0Sstevel@tonic-gate } 1657*0Sstevel@tonic-gate 1658*0Sstevel@tonic-gate /* 1659*0Sstevel@tonic-gate * Add any additional cores from the current CPU 1660*0Sstevel@tonic-gate * device. This is to ensure that all the cores 1661*0Sstevel@tonic-gate * are grouped together in the device list, and 1662*0Sstevel@tonic-gate * consequently sequenced together during the actual 1663*0Sstevel@tonic-gate * operation. 1664*0Sstevel@tonic-gate */ 1665*0Sstevel@tonic-gate for (core = 1; core < MAX_CORES_PER_CMP; core++) { 1666*0Sstevel@tonic-gate 1667*0Sstevel@tonic-gate cunum = DR_CMP_CORE_UNUM(unum, core); 1668*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, type, cunum); 1669*0Sstevel@tonic-gate 1670*0Sstevel@tonic-gate if (dr_dev_is_target(dp, present_only, uset)) { 1671*0Sstevel@tonic-gate *wp++ = &dp->du_common; 1672*0Sstevel@tonic-gate } 1673*0Sstevel@tonic-gate } 1674*0Sstevel@tonic-gate } 1675*0Sstevel@tonic-gate 1676*0Sstevel@tonic-gate /* calculate number of units in list, return result and list pointer */ 1677*0Sstevel@tonic-gate *devnum = wp - list; 1678*0Sstevel@tonic-gate *devlist = list; 1679*0Sstevel@tonic-gate } 1680*0Sstevel@tonic-gate 1681*0Sstevel@tonic-gate static void 1682*0Sstevel@tonic-gate dr_dev_clean_up(dr_handle_t *hp, dr_common_unit_t **list, int devnum) 1683*0Sstevel@tonic-gate { 1684*0Sstevel@tonic-gate int len; 1685*0Sstevel@tonic-gate int n = 0; 1686*0Sstevel@tonic-gate dr_common_unit_t *cp, **rp = list; 1687*0Sstevel@tonic-gate 1688*0Sstevel@tonic-gate /* 1689*0Sstevel@tonic-gate * move first encountered unit error to handle if handle 1690*0Sstevel@tonic-gate * does not yet have a recorded error. 1691*0Sstevel@tonic-gate */ 1692*0Sstevel@tonic-gate if (hp->h_err == NULL) { 1693*0Sstevel@tonic-gate while (n++ < devnum) { 1694*0Sstevel@tonic-gate cp = *rp++; 1695*0Sstevel@tonic-gate if (cp->sbdev_error != NULL) { 1696*0Sstevel@tonic-gate hp->h_err = cp->sbdev_error; 1697*0Sstevel@tonic-gate cp->sbdev_error = NULL; 1698*0Sstevel@tonic-gate break; 1699*0Sstevel@tonic-gate } 1700*0Sstevel@tonic-gate } 1701*0Sstevel@tonic-gate } 1702*0Sstevel@tonic-gate 1703*0Sstevel@tonic-gate /* free remaining unit errors */ 1704*0Sstevel@tonic-gate while (n++ < devnum) { 1705*0Sstevel@tonic-gate cp = *rp++; 1706*0Sstevel@tonic-gate if (cp->sbdev_error != NULL) { 1707*0Sstevel@tonic-gate sbd_err_clear(&cp->sbdev_error); 1708*0Sstevel@tonic-gate cp->sbdev_error = NULL; 1709*0Sstevel@tonic-gate } 1710*0Sstevel@tonic-gate } 1711*0Sstevel@tonic-gate 1712*0Sstevel@tonic-gate /* free list */ 1713*0Sstevel@tonic-gate list -= 1; 1714*0Sstevel@tonic-gate len = (int)list[0]; 1715*0Sstevel@tonic-gate kmem_free(list, len); 1716*0Sstevel@tonic-gate } 1717*0Sstevel@tonic-gate 1718*0Sstevel@tonic-gate static int 1719*0Sstevel@tonic-gate dr_dev_walk(dr_handle_t *hp, sbd_comp_type_t type, int present_only, 1720*0Sstevel@tonic-gate int (*pre_op)(dr_handle_t *, dr_common_unit_t **, int), 1721*0Sstevel@tonic-gate void (*op)(dr_handle_t *, dr_common_unit_t *), 1722*0Sstevel@tonic-gate int (*post_op)(dr_handle_t *, dr_common_unit_t **, int), 1723*0Sstevel@tonic-gate void (*board_op)(dr_handle_t *, dr_common_unit_t **, int)) 1724*0Sstevel@tonic-gate { 1725*0Sstevel@tonic-gate int devnum, rv; 1726*0Sstevel@tonic-gate dr_common_unit_t **devlist; 1727*0Sstevel@tonic-gate 1728*0Sstevel@tonic-gate dr_dev_make_list(hp, type, present_only, &devlist, &devnum); 1729*0Sstevel@tonic-gate 1730*0Sstevel@tonic-gate rv = 0; 1731*0Sstevel@tonic-gate if (devnum > 0) { 1732*0Sstevel@tonic-gate rv = (*pre_op)(hp, devlist, devnum); 1733*0Sstevel@tonic-gate if (rv == 0) { 1734*0Sstevel@tonic-gate int n; 1735*0Sstevel@tonic-gate 1736*0Sstevel@tonic-gate for (n = 0; n < devnum; n++) 1737*0Sstevel@tonic-gate (*op)(hp, devlist[n]); 1738*0Sstevel@tonic-gate 1739*0Sstevel@tonic-gate rv = (*post_op)(hp, devlist, devnum); 1740*0Sstevel@tonic-gate 1741*0Sstevel@tonic-gate (*board_op)(hp, devlist, devnum); 1742*0Sstevel@tonic-gate } 1743*0Sstevel@tonic-gate } 1744*0Sstevel@tonic-gate 1745*0Sstevel@tonic-gate dr_dev_clean_up(hp, devlist, devnum); 1746*0Sstevel@tonic-gate return (rv); 1747*0Sstevel@tonic-gate } 1748*0Sstevel@tonic-gate 1749*0Sstevel@tonic-gate /*ARGSUSED*/ 1750*0Sstevel@tonic-gate static int 1751*0Sstevel@tonic-gate dr_dev_noop(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 1752*0Sstevel@tonic-gate { 1753*0Sstevel@tonic-gate return (0); 1754*0Sstevel@tonic-gate } 1755*0Sstevel@tonic-gate 1756*0Sstevel@tonic-gate static void 1757*0Sstevel@tonic-gate dr_attach_update_state(dr_handle_t *hp, 1758*0Sstevel@tonic-gate dr_common_unit_t **devlist, int devnum) 1759*0Sstevel@tonic-gate { 1760*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1761*0Sstevel@tonic-gate int i; 1762*0Sstevel@tonic-gate dr_devset_t devs_unattached, devs_present; 1763*0Sstevel@tonic-gate static fn_t f = "dr_post_attach_devlist"; 1764*0Sstevel@tonic-gate 1765*0Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 1766*0Sstevel@tonic-gate dr_common_unit_t *cp = devlist[i]; 1767*0Sstevel@tonic-gate 1768*0Sstevel@tonic-gate if (dr_check_unit_attached(cp) == -1) { 1769*0Sstevel@tonic-gate PR_ALL("%s: ERROR %s not attached\n", 1770*0Sstevel@tonic-gate f, cp->sbdev_path); 1771*0Sstevel@tonic-gate continue; 1772*0Sstevel@tonic-gate } 1773*0Sstevel@tonic-gate 1774*0Sstevel@tonic-gate DR_DEV_SET_ATTACHED(cp); 1775*0Sstevel@tonic-gate 1776*0Sstevel@tonic-gate dr_device_transition(cp, DR_STATE_CONFIGURED); 1777*0Sstevel@tonic-gate cp->sbdev_cond = SBD_COND_OK; 1778*0Sstevel@tonic-gate } 1779*0Sstevel@tonic-gate 1780*0Sstevel@tonic-gate devs_present = DR_DEVS_PRESENT(bp); 1781*0Sstevel@tonic-gate devs_unattached = DR_DEVS_UNATTACHED(bp); 1782*0Sstevel@tonic-gate 1783*0Sstevel@tonic-gate switch (bp->b_state) { 1784*0Sstevel@tonic-gate case DR_STATE_CONNECTED: 1785*0Sstevel@tonic-gate case DR_STATE_UNCONFIGURED: 1786*0Sstevel@tonic-gate ASSERT(devs_present); 1787*0Sstevel@tonic-gate 1788*0Sstevel@tonic-gate if (devs_unattached == 0) { 1789*0Sstevel@tonic-gate /* 1790*0Sstevel@tonic-gate * All devices finally attached. 1791*0Sstevel@tonic-gate */ 1792*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_CONFIGURED); 1793*0Sstevel@tonic-gate hp->h_bd->b_ostate = SBD_STAT_CONFIGURED; 1794*0Sstevel@tonic-gate hp->h_bd->b_rstate = SBD_STAT_CONNECTED; 1795*0Sstevel@tonic-gate hp->h_bd->b_cond = SBD_COND_OK; 1796*0Sstevel@tonic-gate hp->h_bd->b_busy = 0; 1797*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); 1798*0Sstevel@tonic-gate } else if (devs_present != devs_unattached) { 1799*0Sstevel@tonic-gate /* 1800*0Sstevel@tonic-gate * Only some devices are fully attached. 1801*0Sstevel@tonic-gate */ 1802*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_PARTIAL); 1803*0Sstevel@tonic-gate hp->h_bd->b_rstate = SBD_STAT_CONNECTED; 1804*0Sstevel@tonic-gate hp->h_bd->b_ostate = SBD_STAT_CONFIGURED; 1805*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); 1806*0Sstevel@tonic-gate } 1807*0Sstevel@tonic-gate break; 1808*0Sstevel@tonic-gate 1809*0Sstevel@tonic-gate case DR_STATE_PARTIAL: 1810*0Sstevel@tonic-gate ASSERT(devs_present); 1811*0Sstevel@tonic-gate /* 1812*0Sstevel@tonic-gate * All devices finally attached. 1813*0Sstevel@tonic-gate */ 1814*0Sstevel@tonic-gate if (devs_unattached == 0) { 1815*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_CONFIGURED); 1816*0Sstevel@tonic-gate hp->h_bd->b_rstate = SBD_STAT_CONNECTED; 1817*0Sstevel@tonic-gate hp->h_bd->b_ostate = SBD_STAT_CONFIGURED; 1818*0Sstevel@tonic-gate hp->h_bd->b_cond = SBD_COND_OK; 1819*0Sstevel@tonic-gate hp->h_bd->b_busy = 0; 1820*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); 1821*0Sstevel@tonic-gate } 1822*0Sstevel@tonic-gate break; 1823*0Sstevel@tonic-gate 1824*0Sstevel@tonic-gate default: 1825*0Sstevel@tonic-gate break; 1826*0Sstevel@tonic-gate } 1827*0Sstevel@tonic-gate } 1828*0Sstevel@tonic-gate 1829*0Sstevel@tonic-gate static void 1830*0Sstevel@tonic-gate dr_dev_configure(dr_handle_t *hp) 1831*0Sstevel@tonic-gate { 1832*0Sstevel@tonic-gate int rv; 1833*0Sstevel@tonic-gate 1834*0Sstevel@tonic-gate rv = dr_dev_walk(hp, SBD_COMP_CPU, 1, 1835*0Sstevel@tonic-gate dr_pre_attach_cpu, 1836*0Sstevel@tonic-gate dr_attach_cpu, 1837*0Sstevel@tonic-gate dr_post_attach_cpu, 1838*0Sstevel@tonic-gate dr_attach_update_state); 1839*0Sstevel@tonic-gate 1840*0Sstevel@tonic-gate if (rv >= 0) { 1841*0Sstevel@tonic-gate rv = dr_dev_walk(hp, SBD_COMP_MEM, 1, 1842*0Sstevel@tonic-gate dr_pre_attach_mem, 1843*0Sstevel@tonic-gate dr_attach_mem, 1844*0Sstevel@tonic-gate dr_post_attach_mem, 1845*0Sstevel@tonic-gate dr_attach_update_state); 1846*0Sstevel@tonic-gate } 1847*0Sstevel@tonic-gate 1848*0Sstevel@tonic-gate if (rv >= 0) { 1849*0Sstevel@tonic-gate (void) dr_dev_walk(hp, SBD_COMP_IO, 1, 1850*0Sstevel@tonic-gate dr_pre_attach_io, 1851*0Sstevel@tonic-gate dr_attach_io, 1852*0Sstevel@tonic-gate dr_post_attach_io, 1853*0Sstevel@tonic-gate dr_attach_update_state); 1854*0Sstevel@tonic-gate } 1855*0Sstevel@tonic-gate } 1856*0Sstevel@tonic-gate 1857*0Sstevel@tonic-gate static void 1858*0Sstevel@tonic-gate dr_release_update_state(dr_handle_t *hp, 1859*0Sstevel@tonic-gate dr_common_unit_t **devlist, int devnum) 1860*0Sstevel@tonic-gate { 1861*0Sstevel@tonic-gate _NOTE(ARGUNUSED(devlist)) 1862*0Sstevel@tonic-gate _NOTE(ARGUNUSED(devnum)) 1863*0Sstevel@tonic-gate 1864*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1865*0Sstevel@tonic-gate 1866*0Sstevel@tonic-gate /* 1867*0Sstevel@tonic-gate * If the entire board was released and all components 1868*0Sstevel@tonic-gate * unreferenced then transfer it to the UNREFERENCED state. 1869*0Sstevel@tonic-gate */ 1870*0Sstevel@tonic-gate if ((bp->b_state != DR_STATE_RELEASE) && 1871*0Sstevel@tonic-gate (DR_DEVS_RELEASED(bp) == DR_DEVS_ATTACHED(bp))) { 1872*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_RELEASE); 1873*0Sstevel@tonic-gate hp->h_bd->b_busy = 1; 1874*0Sstevel@tonic-gate } 1875*0Sstevel@tonic-gate } 1876*0Sstevel@tonic-gate 1877*0Sstevel@tonic-gate /* called by dr_release_done [below] and dr_release_mem_done [dr_mem.c] */ 1878*0Sstevel@tonic-gate int 1879*0Sstevel@tonic-gate dr_release_dev_done(dr_common_unit_t *cp) 1880*0Sstevel@tonic-gate { 1881*0Sstevel@tonic-gate if (cp->sbdev_state == DR_STATE_RELEASE) { 1882*0Sstevel@tonic-gate ASSERT(DR_DEV_IS_RELEASED(cp)); 1883*0Sstevel@tonic-gate 1884*0Sstevel@tonic-gate DR_DEV_SET_UNREFERENCED(cp); 1885*0Sstevel@tonic-gate 1886*0Sstevel@tonic-gate dr_device_transition(cp, DR_STATE_UNREFERENCED); 1887*0Sstevel@tonic-gate 1888*0Sstevel@tonic-gate return (0); 1889*0Sstevel@tonic-gate } else { 1890*0Sstevel@tonic-gate return (-1); 1891*0Sstevel@tonic-gate } 1892*0Sstevel@tonic-gate } 1893*0Sstevel@tonic-gate 1894*0Sstevel@tonic-gate static void 1895*0Sstevel@tonic-gate dr_release_done(dr_handle_t *hp, dr_common_unit_t *cp) 1896*0Sstevel@tonic-gate { 1897*0Sstevel@tonic-gate _NOTE(ARGUNUSED(hp)) 1898*0Sstevel@tonic-gate 1899*0Sstevel@tonic-gate dr_board_t *bp; 1900*0Sstevel@tonic-gate static fn_t f = "dr_release_done"; 1901*0Sstevel@tonic-gate 1902*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 1903*0Sstevel@tonic-gate 1904*0Sstevel@tonic-gate /* get board pointer & sanity check */ 1905*0Sstevel@tonic-gate bp = cp->sbdev_bp; 1906*0Sstevel@tonic-gate ASSERT(bp == hp->h_bd); 1907*0Sstevel@tonic-gate 1908*0Sstevel@tonic-gate /* 1909*0Sstevel@tonic-gate * Transfer the device which just completed its release 1910*0Sstevel@tonic-gate * to the UNREFERENCED state. 1911*0Sstevel@tonic-gate */ 1912*0Sstevel@tonic-gate switch (cp->sbdev_type) { 1913*0Sstevel@tonic-gate case SBD_COMP_MEM: 1914*0Sstevel@tonic-gate dr_release_mem_done(cp); 1915*0Sstevel@tonic-gate break; 1916*0Sstevel@tonic-gate 1917*0Sstevel@tonic-gate default: 1918*0Sstevel@tonic-gate DR_DEV_SET_RELEASED(cp); 1919*0Sstevel@tonic-gate 1920*0Sstevel@tonic-gate dr_device_transition(cp, DR_STATE_RELEASE); 1921*0Sstevel@tonic-gate 1922*0Sstevel@tonic-gate (void) dr_release_dev_done(cp); 1923*0Sstevel@tonic-gate break; 1924*0Sstevel@tonic-gate } 1925*0Sstevel@tonic-gate 1926*0Sstevel@tonic-gate /* 1927*0Sstevel@tonic-gate * If we're not already in the RELEASE state for this 1928*0Sstevel@tonic-gate * board and we now have released all that were previously 1929*0Sstevel@tonic-gate * attached, then transfer the board to the RELEASE state. 1930*0Sstevel@tonic-gate */ 1931*0Sstevel@tonic-gate if ((bp->b_state == DR_STATE_RELEASE) && 1932*0Sstevel@tonic-gate (DR_DEVS_RELEASED(bp) == DR_DEVS_UNREFERENCED(bp))) { 1933*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_UNREFERENCED); 1934*0Sstevel@tonic-gate bp->b_busy = 1; 1935*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 1936*0Sstevel@tonic-gate } 1937*0Sstevel@tonic-gate } 1938*0Sstevel@tonic-gate 1939*0Sstevel@tonic-gate static void 1940*0Sstevel@tonic-gate dr_dev_release_mem(dr_handle_t *hp, dr_common_unit_t *dv) 1941*0Sstevel@tonic-gate { 1942*0Sstevel@tonic-gate dr_release_mem(dv); 1943*0Sstevel@tonic-gate dr_release_done(hp, dv); 1944*0Sstevel@tonic-gate } 1945*0Sstevel@tonic-gate 1946*0Sstevel@tonic-gate static void 1947*0Sstevel@tonic-gate dr_dev_release(dr_handle_t *hp) 1948*0Sstevel@tonic-gate { 1949*0Sstevel@tonic-gate int rv; 1950*0Sstevel@tonic-gate 1951*0Sstevel@tonic-gate hp->h_bd->b_busy = 1; 1952*0Sstevel@tonic-gate 1953*0Sstevel@tonic-gate rv = dr_dev_walk(hp, SBD_COMP_CPU, 0, 1954*0Sstevel@tonic-gate dr_pre_release_cpu, 1955*0Sstevel@tonic-gate dr_release_done, 1956*0Sstevel@tonic-gate dr_dev_noop, 1957*0Sstevel@tonic-gate dr_release_update_state); 1958*0Sstevel@tonic-gate 1959*0Sstevel@tonic-gate if (rv >= 0) { 1960*0Sstevel@tonic-gate rv = dr_dev_walk(hp, SBD_COMP_MEM, 0, 1961*0Sstevel@tonic-gate dr_pre_release_mem, 1962*0Sstevel@tonic-gate dr_dev_release_mem, 1963*0Sstevel@tonic-gate dr_dev_noop, 1964*0Sstevel@tonic-gate dr_release_update_state); 1965*0Sstevel@tonic-gate } 1966*0Sstevel@tonic-gate 1967*0Sstevel@tonic-gate if (rv >= 0) { 1968*0Sstevel@tonic-gate rv = dr_dev_walk(hp, SBD_COMP_IO, 0, 1969*0Sstevel@tonic-gate dr_pre_release_io, 1970*0Sstevel@tonic-gate dr_release_done, 1971*0Sstevel@tonic-gate dr_dev_noop, 1972*0Sstevel@tonic-gate dr_release_update_state); 1973*0Sstevel@tonic-gate 1974*0Sstevel@tonic-gate } 1975*0Sstevel@tonic-gate 1976*0Sstevel@tonic-gate if (rv < 0) 1977*0Sstevel@tonic-gate hp->h_bd->b_busy = 0; 1978*0Sstevel@tonic-gate /* else, b_busy will be cleared in dr_detach_update_state() */ 1979*0Sstevel@tonic-gate } 1980*0Sstevel@tonic-gate 1981*0Sstevel@tonic-gate static void 1982*0Sstevel@tonic-gate dr_detach_update_state(dr_handle_t *hp, 1983*0Sstevel@tonic-gate dr_common_unit_t **devlist, int devnum) 1984*0Sstevel@tonic-gate { 1985*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 1986*0Sstevel@tonic-gate int i; 1987*0Sstevel@tonic-gate dr_state_t bstate; 1988*0Sstevel@tonic-gate static fn_t f = "dr_detach_update_state"; 1989*0Sstevel@tonic-gate 1990*0Sstevel@tonic-gate for (i = 0; i < devnum; i++) { 1991*0Sstevel@tonic-gate dr_common_unit_t *cp = devlist[i]; 1992*0Sstevel@tonic-gate 1993*0Sstevel@tonic-gate if (dr_check_unit_attached(cp) >= 0) { 1994*0Sstevel@tonic-gate /* 1995*0Sstevel@tonic-gate * Device is still attached probably due 1996*0Sstevel@tonic-gate * to an error. Need to keep track of it. 1997*0Sstevel@tonic-gate */ 1998*0Sstevel@tonic-gate PR_ALL("%s: ERROR %s not detached\n", 1999*0Sstevel@tonic-gate f, cp->sbdev_path); 2000*0Sstevel@tonic-gate 2001*0Sstevel@tonic-gate continue; 2002*0Sstevel@tonic-gate } 2003*0Sstevel@tonic-gate 2004*0Sstevel@tonic-gate DR_DEV_CLR_ATTACHED(cp); 2005*0Sstevel@tonic-gate DR_DEV_CLR_RELEASED(cp); 2006*0Sstevel@tonic-gate DR_DEV_CLR_UNREFERENCED(cp); 2007*0Sstevel@tonic-gate dr_device_transition(cp, DR_STATE_UNCONFIGURED); 2008*0Sstevel@tonic-gate } 2009*0Sstevel@tonic-gate 2010*0Sstevel@tonic-gate bstate = bp->b_state; 2011*0Sstevel@tonic-gate if (bstate != DR_STATE_UNCONFIGURED) { 2012*0Sstevel@tonic-gate if (DR_DEVS_PRESENT(bp) == DR_DEVS_UNATTACHED(bp)) { 2013*0Sstevel@tonic-gate /* 2014*0Sstevel@tonic-gate * All devices are finally detached. 2015*0Sstevel@tonic-gate */ 2016*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_UNCONFIGURED); 2017*0Sstevel@tonic-gate hp->h_bd->b_ostate = SBD_STAT_UNCONFIGURED; 2018*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); 2019*0Sstevel@tonic-gate } else if ((bp->b_state != DR_STATE_PARTIAL) && 2020*0Sstevel@tonic-gate (DR_DEVS_ATTACHED(bp) != 2021*0Sstevel@tonic-gate DR_DEVS_PRESENT(bp))) { 2022*0Sstevel@tonic-gate /* 2023*0Sstevel@tonic-gate * Some devices remain attached. 2024*0Sstevel@tonic-gate */ 2025*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_PARTIAL); 2026*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); 2027*0Sstevel@tonic-gate } 2028*0Sstevel@tonic-gate 2029*0Sstevel@tonic-gate if ((hp->h_devset & DR_DEVS_UNATTACHED(bp)) == hp->h_devset) 2030*0Sstevel@tonic-gate hp->h_bd->b_busy = 0; 2031*0Sstevel@tonic-gate } 2032*0Sstevel@tonic-gate } 2033*0Sstevel@tonic-gate 2034*0Sstevel@tonic-gate static int 2035*0Sstevel@tonic-gate dr_dev_unconfigure(dr_handle_t *hp) 2036*0Sstevel@tonic-gate { 2037*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 2038*0Sstevel@tonic-gate 2039*0Sstevel@tonic-gate /* 2040*0Sstevel@tonic-gate * Block out status during IO unconfig. 2041*0Sstevel@tonic-gate */ 2042*0Sstevel@tonic-gate mutex_enter(&bp->b_slock); 2043*0Sstevel@tonic-gate while (bp->b_sflags & DR_BSLOCK) { 2044*0Sstevel@tonic-gate if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) { 2045*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 2046*0Sstevel@tonic-gate return (EINTR); 2047*0Sstevel@tonic-gate } 2048*0Sstevel@tonic-gate } 2049*0Sstevel@tonic-gate bp->b_sflags |= DR_BSLOCK; 2050*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 2051*0Sstevel@tonic-gate 2052*0Sstevel@tonic-gate (void) dr_dev_walk(hp, SBD_COMP_IO, 0, 2053*0Sstevel@tonic-gate dr_pre_detach_io, 2054*0Sstevel@tonic-gate dr_detach_io, 2055*0Sstevel@tonic-gate dr_post_detach_io, 2056*0Sstevel@tonic-gate dr_detach_update_state); 2057*0Sstevel@tonic-gate 2058*0Sstevel@tonic-gate dr_unlock_status(bp); 2059*0Sstevel@tonic-gate 2060*0Sstevel@tonic-gate (void) dr_dev_walk(hp, SBD_COMP_CPU, 0, 2061*0Sstevel@tonic-gate dr_pre_detach_cpu, 2062*0Sstevel@tonic-gate dr_detach_cpu, 2063*0Sstevel@tonic-gate dr_post_detach_cpu, 2064*0Sstevel@tonic-gate dr_detach_update_state); 2065*0Sstevel@tonic-gate 2066*0Sstevel@tonic-gate (void) dr_dev_walk(hp, SBD_COMP_MEM, 0, 2067*0Sstevel@tonic-gate dr_pre_detach_mem, 2068*0Sstevel@tonic-gate dr_detach_mem, 2069*0Sstevel@tonic-gate dr_post_detach_mem, 2070*0Sstevel@tonic-gate dr_detach_update_state); 2071*0Sstevel@tonic-gate 2072*0Sstevel@tonic-gate return (0); 2073*0Sstevel@tonic-gate } 2074*0Sstevel@tonic-gate 2075*0Sstevel@tonic-gate static void 2076*0Sstevel@tonic-gate dr_dev_cancel(dr_handle_t *hp) 2077*0Sstevel@tonic-gate { 2078*0Sstevel@tonic-gate int i; 2079*0Sstevel@tonic-gate dr_devset_t devset; 2080*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 2081*0Sstevel@tonic-gate static fn_t f = "dr_dev_cancel"; 2082*0Sstevel@tonic-gate 2083*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 2084*0Sstevel@tonic-gate 2085*0Sstevel@tonic-gate /* 2086*0Sstevel@tonic-gate * Only devices which have been "released" are 2087*0Sstevel@tonic-gate * subject to cancellation. 2088*0Sstevel@tonic-gate */ 2089*0Sstevel@tonic-gate devset = hp->h_devset & DR_DEVS_RELEASED(bp); 2090*0Sstevel@tonic-gate 2091*0Sstevel@tonic-gate /* 2092*0Sstevel@tonic-gate * Nothing to do for CPUs or IO other than change back 2093*0Sstevel@tonic-gate * their state. 2094*0Sstevel@tonic-gate */ 2095*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2096*0Sstevel@tonic-gate dr_cpu_unit_t *cp; 2097*0Sstevel@tonic-gate dr_state_t nstate; 2098*0Sstevel@tonic-gate 2099*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_CPU, i)) 2100*0Sstevel@tonic-gate continue; 2101*0Sstevel@tonic-gate 2102*0Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, i); 2103*0Sstevel@tonic-gate if (dr_cancel_cpu(cp) == 0) 2104*0Sstevel@tonic-gate nstate = DR_STATE_CONFIGURED; 2105*0Sstevel@tonic-gate else 2106*0Sstevel@tonic-gate nstate = DR_STATE_FATAL; 2107*0Sstevel@tonic-gate 2108*0Sstevel@tonic-gate dr_device_transition(&cp->sbc_cm, nstate); 2109*0Sstevel@tonic-gate } 2110*0Sstevel@tonic-gate 2111*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 2112*0Sstevel@tonic-gate dr_io_unit_t *ip; 2113*0Sstevel@tonic-gate 2114*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_IO, i)) 2115*0Sstevel@tonic-gate continue; 2116*0Sstevel@tonic-gate ip = dr_get_io_unit(bp, i); 2117*0Sstevel@tonic-gate dr_device_transition(&ip->sbi_cm, DR_STATE_CONFIGURED); 2118*0Sstevel@tonic-gate } 2119*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 2120*0Sstevel@tonic-gate dr_mem_unit_t *mp; 2121*0Sstevel@tonic-gate dr_state_t nstate; 2122*0Sstevel@tonic-gate 2123*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devset, SBD_COMP_MEM, i)) 2124*0Sstevel@tonic-gate continue; 2125*0Sstevel@tonic-gate 2126*0Sstevel@tonic-gate mp = dr_get_mem_unit(bp, i); 2127*0Sstevel@tonic-gate if (dr_cancel_mem(mp) == 0) 2128*0Sstevel@tonic-gate nstate = DR_STATE_CONFIGURED; 2129*0Sstevel@tonic-gate else 2130*0Sstevel@tonic-gate nstate = DR_STATE_FATAL; 2131*0Sstevel@tonic-gate 2132*0Sstevel@tonic-gate dr_device_transition(&mp->sbm_cm, nstate); 2133*0Sstevel@tonic-gate } 2134*0Sstevel@tonic-gate 2135*0Sstevel@tonic-gate PR_ALL("%s: unreleasing devset (0x%x)\n", f, (uint_t)devset); 2136*0Sstevel@tonic-gate 2137*0Sstevel@tonic-gate DR_DEVS_CANCEL(bp, devset); 2138*0Sstevel@tonic-gate 2139*0Sstevel@tonic-gate if (DR_DEVS_RELEASED(bp) == 0) { 2140*0Sstevel@tonic-gate dr_state_t new_state; 2141*0Sstevel@tonic-gate /* 2142*0Sstevel@tonic-gate * If the board no longer has any released devices 2143*0Sstevel@tonic-gate * than transfer it back to the CONFIG/PARTIAL state. 2144*0Sstevel@tonic-gate */ 2145*0Sstevel@tonic-gate if (DR_DEVS_ATTACHED(bp) == DR_DEVS_PRESENT(bp)) 2146*0Sstevel@tonic-gate new_state = DR_STATE_CONFIGURED; 2147*0Sstevel@tonic-gate else 2148*0Sstevel@tonic-gate new_state = DR_STATE_PARTIAL; 2149*0Sstevel@tonic-gate if (bp->b_state != new_state) { 2150*0Sstevel@tonic-gate dr_board_transition(bp, new_state); 2151*0Sstevel@tonic-gate } 2152*0Sstevel@tonic-gate hp->h_bd->b_ostate = SBD_STAT_CONFIGURED; 2153*0Sstevel@tonic-gate hp->h_bd->b_busy = 0; 2154*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&hp->h_bd->b_time); 2155*0Sstevel@tonic-gate } 2156*0Sstevel@tonic-gate } 2157*0Sstevel@tonic-gate 2158*0Sstevel@tonic-gate static int 2159*0Sstevel@tonic-gate dr_dev_status(dr_handle_t *hp) 2160*0Sstevel@tonic-gate { 2161*0Sstevel@tonic-gate int nstat, mode, ncm, sz, pbsz, pnstat; 2162*0Sstevel@tonic-gate dr_handle_t *shp; 2163*0Sstevel@tonic-gate dr_devset_t devset = 0; 2164*0Sstevel@tonic-gate sbd_stat_t *dstatp = NULL; 2165*0Sstevel@tonic-gate sbd_dev_stat_t *devstatp; 2166*0Sstevel@tonic-gate dr_board_t *bp; 2167*0Sstevel@tonic-gate drmach_status_t pstat; 2168*0Sstevel@tonic-gate int rv = 0; 2169*0Sstevel@tonic-gate 2170*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2171*0Sstevel@tonic-gate int sz32 = 0; 2172*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 2173*0Sstevel@tonic-gate 2174*0Sstevel@tonic-gate static fn_t f = "dr_status"; 2175*0Sstevel@tonic-gate 2176*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 2177*0Sstevel@tonic-gate 2178*0Sstevel@tonic-gate mode = hp->h_mode; 2179*0Sstevel@tonic-gate shp = hp; 2180*0Sstevel@tonic-gate devset = shp->h_devset; 2181*0Sstevel@tonic-gate bp = hp->h_bd; 2182*0Sstevel@tonic-gate 2183*0Sstevel@tonic-gate /* 2184*0Sstevel@tonic-gate * Block out disconnect, unassign, IO unconfigure and 2185*0Sstevel@tonic-gate * devinfo branch creation during status. 2186*0Sstevel@tonic-gate */ 2187*0Sstevel@tonic-gate mutex_enter(&bp->b_slock); 2188*0Sstevel@tonic-gate while (bp->b_sflags & DR_BSLOCK) { 2189*0Sstevel@tonic-gate if (cv_wait_sig(&bp->b_scv, &bp->b_slock) == 0) { 2190*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 2191*0Sstevel@tonic-gate return (EINTR); 2192*0Sstevel@tonic-gate } 2193*0Sstevel@tonic-gate } 2194*0Sstevel@tonic-gate bp->b_sflags |= DR_BSLOCK; 2195*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 2196*0Sstevel@tonic-gate 2197*0Sstevel@tonic-gate ncm = 1; 2198*0Sstevel@tonic-gate if (hp->h_sbdcmd.cmd_cm.c_id.c_type == SBD_COMP_NONE) { 2199*0Sstevel@tonic-gate if (dr_cmd_flags(hp) & SBD_FLAG_ALLCMP) { 2200*0Sstevel@tonic-gate /* 2201*0Sstevel@tonic-gate * Calculate the maximum number of components possible 2202*0Sstevel@tonic-gate * for a board. This number will be used to size the 2203*0Sstevel@tonic-gate * status scratch buffer used by board and component 2204*0Sstevel@tonic-gate * status functions. 2205*0Sstevel@tonic-gate * This buffer may differ in size from what is provided 2206*0Sstevel@tonic-gate * by the plugin, since the known component set on the 2207*0Sstevel@tonic-gate * board may change between the plugin's GETNCM call, and 2208*0Sstevel@tonic-gate * the status call. Sizing will be adjusted to the plugin's 2209*0Sstevel@tonic-gate * receptacle buffer at copyout time. 2210*0Sstevel@tonic-gate */ 2211*0Sstevel@tonic-gate ncm = MAX_CPU_UNITS_PER_BOARD + 2212*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD + 2213*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD; 2214*0Sstevel@tonic-gate 2215*0Sstevel@tonic-gate } else { 2216*0Sstevel@tonic-gate /* 2217*0Sstevel@tonic-gate * In the case of c_type == SBD_COMP_NONE, and 2218*0Sstevel@tonic-gate * SBD_FLAG_ALLCMP not specified, only the board 2219*0Sstevel@tonic-gate * info is to be returned, no components. 2220*0Sstevel@tonic-gate */ 2221*0Sstevel@tonic-gate ncm = 0; 2222*0Sstevel@tonic-gate devset = 0; 2223*0Sstevel@tonic-gate } 2224*0Sstevel@tonic-gate } 2225*0Sstevel@tonic-gate 2226*0Sstevel@tonic-gate sz = sizeof (sbd_stat_t); 2227*0Sstevel@tonic-gate if (ncm > 1) 2228*0Sstevel@tonic-gate sz += sizeof (sbd_dev_stat_t) * (ncm - 1); 2229*0Sstevel@tonic-gate 2230*0Sstevel@tonic-gate 2231*0Sstevel@tonic-gate pbsz = (int)hp->h_sbdcmd.cmd_stat.s_nbytes; 2232*0Sstevel@tonic-gate pnstat = (pbsz - sizeof (sbd_stat_t))/sizeof (sbd_dev_stat_t); 2233*0Sstevel@tonic-gate 2234*0Sstevel@tonic-gate /* 2235*0Sstevel@tonic-gate * s_nbytes describes the size of the preallocated user 2236*0Sstevel@tonic-gate * buffer into which the application is execting to 2237*0Sstevel@tonic-gate * receive the sbd_stat_t and sbd_dev_stat_t structures. 2238*0Sstevel@tonic-gate */ 2239*0Sstevel@tonic-gate 2240*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2241*0Sstevel@tonic-gate 2242*0Sstevel@tonic-gate /* 2243*0Sstevel@tonic-gate * More buffer space is required for the 64bit to 32bit 2244*0Sstevel@tonic-gate * conversion of data structures. 2245*0Sstevel@tonic-gate */ 2246*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 2247*0Sstevel@tonic-gate sz32 = sizeof (sbd_stat32_t); 2248*0Sstevel@tonic-gate if (ncm > 1) 2249*0Sstevel@tonic-gate sz32 += sizeof (sbd_dev_stat32_t) * (ncm - 1); 2250*0Sstevel@tonic-gate pnstat = (pbsz - sizeof (sbd_stat32_t))/ 2251*0Sstevel@tonic-gate sizeof (sbd_dev_stat32_t); 2252*0Sstevel@tonic-gate } 2253*0Sstevel@tonic-gate 2254*0Sstevel@tonic-gate sz += sz32; 2255*0Sstevel@tonic-gate #endif 2256*0Sstevel@tonic-gate /* 2257*0Sstevel@tonic-gate * Since one sbd_dev_stat_t is included in the sbd_stat_t, 2258*0Sstevel@tonic-gate * increment the plugin's nstat count. 2259*0Sstevel@tonic-gate */ 2260*0Sstevel@tonic-gate ++pnstat; 2261*0Sstevel@tonic-gate 2262*0Sstevel@tonic-gate if (bp->b_id == 0) { 2263*0Sstevel@tonic-gate bzero(&pstat, sizeof (pstat)); 2264*0Sstevel@tonic-gate } else { 2265*0Sstevel@tonic-gate sbd_error_t *err; 2266*0Sstevel@tonic-gate 2267*0Sstevel@tonic-gate err = drmach_status(bp->b_id, &pstat); 2268*0Sstevel@tonic-gate if (err) { 2269*0Sstevel@tonic-gate DRERR_SET_C(&hp->h_err, &err); 2270*0Sstevel@tonic-gate rv = EIO; 2271*0Sstevel@tonic-gate goto status_done; 2272*0Sstevel@tonic-gate } 2273*0Sstevel@tonic-gate } 2274*0Sstevel@tonic-gate 2275*0Sstevel@tonic-gate dstatp = (sbd_stat_t *)GETSTRUCT(char, sz); 2276*0Sstevel@tonic-gate 2277*0Sstevel@tonic-gate devstatp = &dstatp->s_stat[0]; 2278*0Sstevel@tonic-gate 2279*0Sstevel@tonic-gate dstatp->s_board = bp->b_num; 2280*0Sstevel@tonic-gate 2281*0Sstevel@tonic-gate /* 2282*0Sstevel@tonic-gate * Detect transitions between empty and disconnected. 2283*0Sstevel@tonic-gate */ 2284*0Sstevel@tonic-gate if (!pstat.empty && (bp->b_rstate == SBD_STAT_EMPTY)) 2285*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_DISCONNECTED; 2286*0Sstevel@tonic-gate else if (pstat.empty && (bp->b_rstate == SBD_STAT_DISCONNECTED)) 2287*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_EMPTY; 2288*0Sstevel@tonic-gate 2289*0Sstevel@tonic-gate dstatp->s_rstate = bp->b_rstate; 2290*0Sstevel@tonic-gate dstatp->s_ostate = bp->b_ostate; 2291*0Sstevel@tonic-gate dstatp->s_cond = bp->b_cond = pstat.cond; 2292*0Sstevel@tonic-gate dstatp->s_busy = bp->b_busy | pstat.busy; 2293*0Sstevel@tonic-gate dstatp->s_time = bp->b_time; 2294*0Sstevel@tonic-gate dstatp->s_power = pstat.powered; 2295*0Sstevel@tonic-gate dstatp->s_assigned = bp->b_assigned = pstat.assigned; 2296*0Sstevel@tonic-gate dstatp->s_nstat = nstat = 0; 2297*0Sstevel@tonic-gate bcopy(&pstat.type[0], &dstatp->s_type[0], SBD_TYPE_LEN); 2298*0Sstevel@tonic-gate bcopy(&pstat.info[0], &dstatp->s_info[0], SBD_MAX_INFO); 2299*0Sstevel@tonic-gate 2300*0Sstevel@tonic-gate devset &= DR_DEVS_PRESENT(bp); 2301*0Sstevel@tonic-gate if (devset == 0) { 2302*0Sstevel@tonic-gate /* 2303*0Sstevel@tonic-gate * No device chosen. 2304*0Sstevel@tonic-gate */ 2305*0Sstevel@tonic-gate PR_ALL("%s: no device present\n", f); 2306*0Sstevel@tonic-gate } 2307*0Sstevel@tonic-gate 2308*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) 2309*0Sstevel@tonic-gate if ((nstat = dr_cpu_status(hp, devset, devstatp)) > 0) { 2310*0Sstevel@tonic-gate dstatp->s_nstat += nstat; 2311*0Sstevel@tonic-gate devstatp += nstat; 2312*0Sstevel@tonic-gate } 2313*0Sstevel@tonic-gate 2314*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) 2315*0Sstevel@tonic-gate if ((nstat = dr_mem_status(hp, devset, devstatp)) > 0) { 2316*0Sstevel@tonic-gate dstatp->s_nstat += nstat; 2317*0Sstevel@tonic-gate devstatp += nstat; 2318*0Sstevel@tonic-gate } 2319*0Sstevel@tonic-gate 2320*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) 2321*0Sstevel@tonic-gate if ((nstat = dr_io_status(hp, devset, devstatp)) > 0) { 2322*0Sstevel@tonic-gate dstatp->s_nstat += nstat; 2323*0Sstevel@tonic-gate devstatp += nstat; 2324*0Sstevel@tonic-gate } 2325*0Sstevel@tonic-gate 2326*0Sstevel@tonic-gate /* 2327*0Sstevel@tonic-gate * Due to a possible change in number of components between 2328*0Sstevel@tonic-gate * the time of plugin's GETNCM call and now, there may be 2329*0Sstevel@tonic-gate * more or less components than the plugin's buffer can 2330*0Sstevel@tonic-gate * hold. Adjust s_nstat accordingly. 2331*0Sstevel@tonic-gate */ 2332*0Sstevel@tonic-gate 2333*0Sstevel@tonic-gate dstatp->s_nstat = dstatp->s_nstat > pnstat ? pnstat : dstatp->s_nstat; 2334*0Sstevel@tonic-gate 2335*0Sstevel@tonic-gate 2336*0Sstevel@tonic-gate #ifdef _MULTI_DATAMODEL 2337*0Sstevel@tonic-gate if (ddi_model_convert_from(mode & FMODELS) == DDI_MODEL_ILP32) { 2338*0Sstevel@tonic-gate int i, j; 2339*0Sstevel@tonic-gate sbd_stat32_t *dstat32p; 2340*0Sstevel@tonic-gate 2341*0Sstevel@tonic-gate dstat32p = (sbd_stat32_t *)devstatp; 2342*0Sstevel@tonic-gate 2343*0Sstevel@tonic-gate /* Alignment Paranoia */ 2344*0Sstevel@tonic-gate if ((ulong_t)dstat32p & 0x1) { 2345*0Sstevel@tonic-gate PR_ALL("%s: alignment: sz=0x%x dstat32p=0x%x\n", 2346*0Sstevel@tonic-gate f, sizeof (sbd_stat32_t), dstat32p); 2347*0Sstevel@tonic-gate DR_OP_INTERNAL_ERROR(hp); 2348*0Sstevel@tonic-gate rv = EINVAL; 2349*0Sstevel@tonic-gate goto status_done; 2350*0Sstevel@tonic-gate } 2351*0Sstevel@tonic-gate 2352*0Sstevel@tonic-gate /* paranoia: detect buffer overrun */ 2353*0Sstevel@tonic-gate if ((caddr_t)&dstat32p->s_stat[dstatp->s_nstat] > 2354*0Sstevel@tonic-gate ((caddr_t)dstatp) + sz) { 2355*0Sstevel@tonic-gate DR_OP_INTERNAL_ERROR(hp); 2356*0Sstevel@tonic-gate rv = EINVAL; 2357*0Sstevel@tonic-gate goto status_done; 2358*0Sstevel@tonic-gate } 2359*0Sstevel@tonic-gate 2360*0Sstevel@tonic-gate /* copy sbd_stat_t structure members */ 2361*0Sstevel@tonic-gate #define _SBD_STAT(t, m) dstat32p->m = (t)dstatp->m 2362*0Sstevel@tonic-gate _SBD_STAT(int32_t, s_board); 2363*0Sstevel@tonic-gate _SBD_STAT(int32_t, s_rstate); 2364*0Sstevel@tonic-gate _SBD_STAT(int32_t, s_ostate); 2365*0Sstevel@tonic-gate _SBD_STAT(int32_t, s_cond); 2366*0Sstevel@tonic-gate _SBD_STAT(int32_t, s_busy); 2367*0Sstevel@tonic-gate _SBD_STAT(time32_t, s_time); 2368*0Sstevel@tonic-gate _SBD_STAT(uint32_t, s_power); 2369*0Sstevel@tonic-gate _SBD_STAT(uint32_t, s_assigned); 2370*0Sstevel@tonic-gate _SBD_STAT(int32_t, s_nstat); 2371*0Sstevel@tonic-gate bcopy(&dstatp->s_type[0], &dstat32p->s_type[0], 2372*0Sstevel@tonic-gate SBD_TYPE_LEN); 2373*0Sstevel@tonic-gate bcopy(&dstatp->s_info[0], &dstat32p->s_info[0], 2374*0Sstevel@tonic-gate SBD_MAX_INFO); 2375*0Sstevel@tonic-gate #undef _SBD_STAT 2376*0Sstevel@tonic-gate 2377*0Sstevel@tonic-gate for (i = 0; i < dstatp->s_nstat; i++) { 2378*0Sstevel@tonic-gate sbd_dev_stat_t *dsp = &dstatp->s_stat[i]; 2379*0Sstevel@tonic-gate sbd_dev_stat32_t *ds32p = &dstat32p->s_stat[i]; 2380*0Sstevel@tonic-gate #define _SBD_DEV_STAT(t, m) ds32p->m = (t)dsp->m 2381*0Sstevel@tonic-gate 2382*0Sstevel@tonic-gate /* copy sbd_cm_stat_t structure members */ 2383*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, ds_type); 2384*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, ds_unit); 2385*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, ds_ostate); 2386*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, ds_cond); 2387*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, ds_busy); 2388*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, ds_suspend); 2389*0Sstevel@tonic-gate _SBD_DEV_STAT(time32_t, ds_time); 2390*0Sstevel@tonic-gate bcopy(&dsp->ds_name[0], &ds32p->ds_name[0], 2391*0Sstevel@tonic-gate OBP_MAXPROPNAME); 2392*0Sstevel@tonic-gate 2393*0Sstevel@tonic-gate switch (dsp->ds_type) { 2394*0Sstevel@tonic-gate case SBD_COMP_CPU: 2395*0Sstevel@tonic-gate /* copy sbd_cpu_stat_t structure members */ 2396*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cpu.cs_isbootproc); 2397*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cpu.cs_cpuid); 2398*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cpu.cs_speed); 2399*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cpu.cs_ecache); 2400*0Sstevel@tonic-gate break; 2401*0Sstevel@tonic-gate 2402*0Sstevel@tonic-gate case SBD_COMP_MEM: 2403*0Sstevel@tonic-gate /* copy sbd_mem_stat_t structure members */ 2404*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_mem.ms_interleave); 2405*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_basepfn); 2406*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_totpages); 2407*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_detpages); 2408*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_mem.ms_pageslost); 2409*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_managed_pages); 2410*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_pages); 2411*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_first); 2412*0Sstevel@tonic-gate _SBD_DEV_STAT(uint32_t, d_mem.ms_noreloc_last); 2413*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_mem.ms_cage_enabled); 2414*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_mem.ms_peer_is_target); 2415*0Sstevel@tonic-gate bcopy(&dsp->d_mem.ms_peer_ap_id[0], 2416*0Sstevel@tonic-gate &ds32p->d_mem.ms_peer_ap_id[0], 2417*0Sstevel@tonic-gate sizeof (ds32p->d_mem.ms_peer_ap_id)); 2418*0Sstevel@tonic-gate break; 2419*0Sstevel@tonic-gate 2420*0Sstevel@tonic-gate case SBD_COMP_IO: 2421*0Sstevel@tonic-gate /* copy sbd_io_stat_t structure members */ 2422*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_io.is_referenced); 2423*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_io.is_unsafe_count); 2424*0Sstevel@tonic-gate 2425*0Sstevel@tonic-gate for (j = 0; j < SBD_MAX_UNSAFE; j++) 2426*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, 2427*0Sstevel@tonic-gate d_io.is_unsafe_list[j]); 2428*0Sstevel@tonic-gate 2429*0Sstevel@tonic-gate bcopy(&dsp->d_io.is_pathname[0], 2430*0Sstevel@tonic-gate &ds32p->d_io.is_pathname[0], MAXPATHLEN); 2431*0Sstevel@tonic-gate break; 2432*0Sstevel@tonic-gate 2433*0Sstevel@tonic-gate case SBD_COMP_CMP: 2434*0Sstevel@tonic-gate /* copy sbd_cmp_stat_t structure members */ 2435*0Sstevel@tonic-gate bcopy(&dsp->d_cmp.ps_cpuid[0], 2436*0Sstevel@tonic-gate &ds32p->d_cmp.ps_cpuid[0], 2437*0Sstevel@tonic-gate sizeof (ds32p->d_cmp.ps_cpuid)); 2438*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cmp.ps_ncores); 2439*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cmp.ps_speed); 2440*0Sstevel@tonic-gate _SBD_DEV_STAT(int32_t, d_cmp.ps_ecache); 2441*0Sstevel@tonic-gate break; 2442*0Sstevel@tonic-gate 2443*0Sstevel@tonic-gate default: 2444*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: unknown dev type (%d)", 2445*0Sstevel@tonic-gate f, (int)dsp->ds_type); 2446*0Sstevel@tonic-gate rv = EFAULT; 2447*0Sstevel@tonic-gate goto status_done; 2448*0Sstevel@tonic-gate } 2449*0Sstevel@tonic-gate #undef _SBD_DEV_STAT 2450*0Sstevel@tonic-gate } 2451*0Sstevel@tonic-gate 2452*0Sstevel@tonic-gate 2453*0Sstevel@tonic-gate if (ddi_copyout((void *)dstat32p, 2454*0Sstevel@tonic-gate hp->h_sbdcmd.cmd_stat.s_statp, pbsz, mode) != 0) { 2455*0Sstevel@tonic-gate cmn_err(CE_WARN, 2456*0Sstevel@tonic-gate "%s: failed to copyout status " 2457*0Sstevel@tonic-gate "for board %d", f, bp->b_num); 2458*0Sstevel@tonic-gate rv = EFAULT; 2459*0Sstevel@tonic-gate goto status_done; 2460*0Sstevel@tonic-gate } 2461*0Sstevel@tonic-gate } else 2462*0Sstevel@tonic-gate #endif /* _MULTI_DATAMODEL */ 2463*0Sstevel@tonic-gate 2464*0Sstevel@tonic-gate if (ddi_copyout((void *)dstatp, hp->h_sbdcmd.cmd_stat.s_statp, 2465*0Sstevel@tonic-gate pbsz, mode) != 0) { 2466*0Sstevel@tonic-gate cmn_err(CE_WARN, 2467*0Sstevel@tonic-gate "%s: failed to copyout status for board %d", 2468*0Sstevel@tonic-gate f, bp->b_num); 2469*0Sstevel@tonic-gate rv = EFAULT; 2470*0Sstevel@tonic-gate goto status_done; 2471*0Sstevel@tonic-gate } 2472*0Sstevel@tonic-gate 2473*0Sstevel@tonic-gate status_done: 2474*0Sstevel@tonic-gate if (dstatp != NULL) 2475*0Sstevel@tonic-gate FREESTRUCT(dstatp, char, sz); 2476*0Sstevel@tonic-gate 2477*0Sstevel@tonic-gate dr_unlock_status(bp); 2478*0Sstevel@tonic-gate 2479*0Sstevel@tonic-gate return (rv); 2480*0Sstevel@tonic-gate } 2481*0Sstevel@tonic-gate 2482*0Sstevel@tonic-gate static int 2483*0Sstevel@tonic-gate dr_get_ncm(dr_handle_t *hp) 2484*0Sstevel@tonic-gate { 2485*0Sstevel@tonic-gate int i; 2486*0Sstevel@tonic-gate int ncm = 0; 2487*0Sstevel@tonic-gate dr_devset_t devset; 2488*0Sstevel@tonic-gate 2489*0Sstevel@tonic-gate devset = DR_DEVS_PRESENT(hp->h_bd); 2490*0Sstevel@tonic-gate if (hp->h_sbdcmd.cmd_cm.c_id.c_type != SBD_COMP_NONE) 2491*0Sstevel@tonic-gate devset &= DEVSET(hp->h_sbdcmd.cmd_cm.c_id.c_type, 2492*0Sstevel@tonic-gate DEVSET_ANYUNIT); 2493*0Sstevel@tonic-gate 2494*0Sstevel@tonic-gate /* 2495*0Sstevel@tonic-gate * Handle CPUs first to deal with possible CMP 2496*0Sstevel@tonic-gate * devices. If the CPU is a CMP, we need to only 2497*0Sstevel@tonic-gate * increment ncm once even if there are multiple 2498*0Sstevel@tonic-gate * cores for that CMP present in the devset. 2499*0Sstevel@tonic-gate */ 2500*0Sstevel@tonic-gate for (i = 0; i < MAX_CMP_UNITS_PER_BOARD; i++) { 2501*0Sstevel@tonic-gate if (devset & DEVSET(SBD_COMP_CMP, i)) { 2502*0Sstevel@tonic-gate ncm++; 2503*0Sstevel@tonic-gate } 2504*0Sstevel@tonic-gate } 2505*0Sstevel@tonic-gate 2506*0Sstevel@tonic-gate /* eliminate the CPU information from the devset */ 2507*0Sstevel@tonic-gate devset &= ~(DEVSET(SBD_COMP_CMP, DEVSET_ANYUNIT)); 2508*0Sstevel@tonic-gate 2509*0Sstevel@tonic-gate for (i = 0; i < (sizeof (dr_devset_t) * 8); i++) { 2510*0Sstevel@tonic-gate ncm += devset & 0x1; 2511*0Sstevel@tonic-gate devset >>= 1; 2512*0Sstevel@tonic-gate } 2513*0Sstevel@tonic-gate 2514*0Sstevel@tonic-gate return (ncm); 2515*0Sstevel@tonic-gate } 2516*0Sstevel@tonic-gate 2517*0Sstevel@tonic-gate /* used by dr_mem.c */ 2518*0Sstevel@tonic-gate /* TODO: eliminate dr_boardlist */ 2519*0Sstevel@tonic-gate dr_board_t * 2520*0Sstevel@tonic-gate dr_lookup_board(int board_num) 2521*0Sstevel@tonic-gate { 2522*0Sstevel@tonic-gate dr_board_t *bp; 2523*0Sstevel@tonic-gate 2524*0Sstevel@tonic-gate ASSERT(board_num >= 0 && board_num < MAX_BOARDS); 2525*0Sstevel@tonic-gate 2526*0Sstevel@tonic-gate bp = &dr_boardlist[board_num]; 2527*0Sstevel@tonic-gate ASSERT(bp->b_num == board_num); 2528*0Sstevel@tonic-gate 2529*0Sstevel@tonic-gate return (bp); 2530*0Sstevel@tonic-gate } 2531*0Sstevel@tonic-gate 2532*0Sstevel@tonic-gate static dr_dev_unit_t * 2533*0Sstevel@tonic-gate dr_get_dev_unit(dr_board_t *bp, sbd_comp_type_t nt, int unit_num) 2534*0Sstevel@tonic-gate { 2535*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2536*0Sstevel@tonic-gate 2537*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, nt, unit_num); 2538*0Sstevel@tonic-gate ASSERT(dp->du_common.sbdev_bp == bp); 2539*0Sstevel@tonic-gate ASSERT(dp->du_common.sbdev_unum == unit_num); 2540*0Sstevel@tonic-gate ASSERT(dp->du_common.sbdev_type == nt); 2541*0Sstevel@tonic-gate 2542*0Sstevel@tonic-gate return (dp); 2543*0Sstevel@tonic-gate } 2544*0Sstevel@tonic-gate 2545*0Sstevel@tonic-gate dr_cpu_unit_t * 2546*0Sstevel@tonic-gate dr_get_cpu_unit(dr_board_t *bp, int unit_num) 2547*0Sstevel@tonic-gate { 2548*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2549*0Sstevel@tonic-gate 2550*0Sstevel@tonic-gate ASSERT(unit_num >= 0 && unit_num < MAX_CPU_UNITS_PER_BOARD); 2551*0Sstevel@tonic-gate 2552*0Sstevel@tonic-gate dp = dr_get_dev_unit(bp, SBD_COMP_CPU, unit_num); 2553*0Sstevel@tonic-gate return (&dp->du_cpu); 2554*0Sstevel@tonic-gate } 2555*0Sstevel@tonic-gate 2556*0Sstevel@tonic-gate dr_mem_unit_t * 2557*0Sstevel@tonic-gate dr_get_mem_unit(dr_board_t *bp, int unit_num) 2558*0Sstevel@tonic-gate { 2559*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2560*0Sstevel@tonic-gate 2561*0Sstevel@tonic-gate ASSERT(unit_num >= 0 && unit_num < MAX_MEM_UNITS_PER_BOARD); 2562*0Sstevel@tonic-gate 2563*0Sstevel@tonic-gate dp = dr_get_dev_unit(bp, SBD_COMP_MEM, unit_num); 2564*0Sstevel@tonic-gate return (&dp->du_mem); 2565*0Sstevel@tonic-gate } 2566*0Sstevel@tonic-gate 2567*0Sstevel@tonic-gate dr_io_unit_t * 2568*0Sstevel@tonic-gate dr_get_io_unit(dr_board_t *bp, int unit_num) 2569*0Sstevel@tonic-gate { 2570*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2571*0Sstevel@tonic-gate 2572*0Sstevel@tonic-gate ASSERT(unit_num >= 0 && unit_num < MAX_IO_UNITS_PER_BOARD); 2573*0Sstevel@tonic-gate 2574*0Sstevel@tonic-gate dp = dr_get_dev_unit(bp, SBD_COMP_IO, unit_num); 2575*0Sstevel@tonic-gate return (&dp->du_io); 2576*0Sstevel@tonic-gate } 2577*0Sstevel@tonic-gate 2578*0Sstevel@tonic-gate dr_common_unit_t * 2579*0Sstevel@tonic-gate dr_get_common_unit(dr_board_t *bp, sbd_comp_type_t nt, int unum) 2580*0Sstevel@tonic-gate { 2581*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2582*0Sstevel@tonic-gate 2583*0Sstevel@tonic-gate dp = dr_get_dev_unit(bp, nt, unum); 2584*0Sstevel@tonic-gate return (&dp->du_common); 2585*0Sstevel@tonic-gate } 2586*0Sstevel@tonic-gate 2587*0Sstevel@tonic-gate static dr_devset_t 2588*0Sstevel@tonic-gate dr_dev2devset(sbd_comp_id_t *cid) 2589*0Sstevel@tonic-gate { 2590*0Sstevel@tonic-gate static fn_t f = "dr_dev2devset"; 2591*0Sstevel@tonic-gate 2592*0Sstevel@tonic-gate dr_devset_t devset; 2593*0Sstevel@tonic-gate int unit = cid->c_unit; 2594*0Sstevel@tonic-gate 2595*0Sstevel@tonic-gate switch (cid->c_type) { 2596*0Sstevel@tonic-gate case SBD_COMP_NONE: 2597*0Sstevel@tonic-gate devset = DEVSET(SBD_COMP_CPU, DEVSET_ANYUNIT); 2598*0Sstevel@tonic-gate devset |= DEVSET(SBD_COMP_MEM, DEVSET_ANYUNIT); 2599*0Sstevel@tonic-gate devset |= DEVSET(SBD_COMP_IO, DEVSET_ANYUNIT); 2600*0Sstevel@tonic-gate PR_ALL("%s: COMP_NONE devset = 0x%x\n", f, devset); 2601*0Sstevel@tonic-gate break; 2602*0Sstevel@tonic-gate 2603*0Sstevel@tonic-gate case SBD_COMP_CPU: 2604*0Sstevel@tonic-gate if ((unit > MAX_CPU_UNITS_PER_BOARD) || (unit < 0)) { 2605*0Sstevel@tonic-gate cmn_err(CE_WARN, 2606*0Sstevel@tonic-gate "%s: invalid cpu unit# = %d", 2607*0Sstevel@tonic-gate f, unit); 2608*0Sstevel@tonic-gate devset = 0; 2609*0Sstevel@tonic-gate } else { 2610*0Sstevel@tonic-gate /* 2611*0Sstevel@tonic-gate * Generate a devset that includes all the 2612*0Sstevel@tonic-gate * cores of a CMP device. If this is not a 2613*0Sstevel@tonic-gate * CMP, the extra cores will be eliminated 2614*0Sstevel@tonic-gate * later since they are not present. This is 2615*0Sstevel@tonic-gate * also true for CMP devices that do not have 2616*0Sstevel@tonic-gate * all cores active. 2617*0Sstevel@tonic-gate */ 2618*0Sstevel@tonic-gate devset = DEVSET(SBD_COMP_CMP, unit); 2619*0Sstevel@tonic-gate } 2620*0Sstevel@tonic-gate 2621*0Sstevel@tonic-gate PR_ALL("%s: CPU devset = 0x%x\n", f, devset); 2622*0Sstevel@tonic-gate break; 2623*0Sstevel@tonic-gate 2624*0Sstevel@tonic-gate case SBD_COMP_MEM: 2625*0Sstevel@tonic-gate if (unit == SBD_NULL_UNIT) { 2626*0Sstevel@tonic-gate unit = 0; 2627*0Sstevel@tonic-gate cid->c_unit = 0; 2628*0Sstevel@tonic-gate } 2629*0Sstevel@tonic-gate 2630*0Sstevel@tonic-gate if ((unit > MAX_MEM_UNITS_PER_BOARD) || (unit < 0)) { 2631*0Sstevel@tonic-gate cmn_err(CE_WARN, 2632*0Sstevel@tonic-gate "%s: invalid mem unit# = %d", 2633*0Sstevel@tonic-gate f, unit); 2634*0Sstevel@tonic-gate devset = 0; 2635*0Sstevel@tonic-gate } else 2636*0Sstevel@tonic-gate devset = DEVSET(cid->c_type, unit); 2637*0Sstevel@tonic-gate 2638*0Sstevel@tonic-gate PR_ALL("%s: MEM devset = 0x%x\n", f, devset); 2639*0Sstevel@tonic-gate break; 2640*0Sstevel@tonic-gate 2641*0Sstevel@tonic-gate case SBD_COMP_IO: 2642*0Sstevel@tonic-gate if ((unit > MAX_IO_UNITS_PER_BOARD) || (unit < 0)) { 2643*0Sstevel@tonic-gate cmn_err(CE_WARN, 2644*0Sstevel@tonic-gate "%s: invalid io unit# = %d", 2645*0Sstevel@tonic-gate f, unit); 2646*0Sstevel@tonic-gate devset = 0; 2647*0Sstevel@tonic-gate } else 2648*0Sstevel@tonic-gate devset = DEVSET(cid->c_type, unit); 2649*0Sstevel@tonic-gate 2650*0Sstevel@tonic-gate PR_ALL("%s: IO devset = 0x%x\n", f, devset); 2651*0Sstevel@tonic-gate break; 2652*0Sstevel@tonic-gate 2653*0Sstevel@tonic-gate default: 2654*0Sstevel@tonic-gate case SBD_COMP_UNKNOWN: 2655*0Sstevel@tonic-gate devset = 0; 2656*0Sstevel@tonic-gate break; 2657*0Sstevel@tonic-gate } 2658*0Sstevel@tonic-gate 2659*0Sstevel@tonic-gate return (devset); 2660*0Sstevel@tonic-gate } 2661*0Sstevel@tonic-gate 2662*0Sstevel@tonic-gate /* 2663*0Sstevel@tonic-gate * Converts a dynamic attachment point name to a SBD_COMP_* type. 2664*0Sstevel@tonic-gate * Returns SDB_COMP_UNKNOWN if name is not recognized. 2665*0Sstevel@tonic-gate */ 2666*0Sstevel@tonic-gate static int 2667*0Sstevel@tonic-gate dr_dev_type_to_nt(char *type) 2668*0Sstevel@tonic-gate { 2669*0Sstevel@tonic-gate int i; 2670*0Sstevel@tonic-gate 2671*0Sstevel@tonic-gate for (i = 0; dr_devattr[i].s_nodetype != SBD_COMP_UNKNOWN; i++) 2672*0Sstevel@tonic-gate if (strcmp(dr_devattr[i].s_devtype, type) == 0) 2673*0Sstevel@tonic-gate break; 2674*0Sstevel@tonic-gate 2675*0Sstevel@tonic-gate return (dr_devattr[i].s_nodetype); 2676*0Sstevel@tonic-gate } 2677*0Sstevel@tonic-gate 2678*0Sstevel@tonic-gate /* 2679*0Sstevel@tonic-gate * Converts a SBD_COMP_* type to a dynamic attachment point name. 2680*0Sstevel@tonic-gate * Return NULL if SBD_COMP_ type is not recognized. 2681*0Sstevel@tonic-gate */ 2682*0Sstevel@tonic-gate char * 2683*0Sstevel@tonic-gate dr_nt_to_dev_type(int nt) 2684*0Sstevel@tonic-gate { 2685*0Sstevel@tonic-gate int i; 2686*0Sstevel@tonic-gate 2687*0Sstevel@tonic-gate for (i = 0; dr_devattr[i].s_nodetype != SBD_COMP_UNKNOWN; i++) 2688*0Sstevel@tonic-gate if (dr_devattr[i].s_nodetype == nt) 2689*0Sstevel@tonic-gate break; 2690*0Sstevel@tonic-gate 2691*0Sstevel@tonic-gate return (dr_devattr[i].s_devtype); 2692*0Sstevel@tonic-gate } 2693*0Sstevel@tonic-gate 2694*0Sstevel@tonic-gate 2695*0Sstevel@tonic-gate /* 2696*0Sstevel@tonic-gate * State transition policy is that if there is some component for which 2697*0Sstevel@tonic-gate * the state transition is valid, then let it through. The exception is 2698*0Sstevel@tonic-gate * SBD_CMD_DISCONNECT. On disconnect, the state transition must be valid 2699*0Sstevel@tonic-gate * for ALL components. 2700*0Sstevel@tonic-gate * Returns the state that is in error, if any. 2701*0Sstevel@tonic-gate */ 2702*0Sstevel@tonic-gate static int 2703*0Sstevel@tonic-gate dr_check_transition(dr_board_t *bp, dr_devset_t *devsetp, 2704*0Sstevel@tonic-gate struct dr_state_trans *transp, int cmd) 2705*0Sstevel@tonic-gate { 2706*0Sstevel@tonic-gate int s, ut; 2707*0Sstevel@tonic-gate int state_err = 0; 2708*0Sstevel@tonic-gate dr_devset_t devset; 2709*0Sstevel@tonic-gate dr_common_unit_t *cp; 2710*0Sstevel@tonic-gate static fn_t f = "dr_check_transition"; 2711*0Sstevel@tonic-gate 2712*0Sstevel@tonic-gate devset = *devsetp; 2713*0Sstevel@tonic-gate 2714*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, DEVSET_ANYUNIT)) { 2715*0Sstevel@tonic-gate for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) { 2716*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_CPU, ut) == 0) 2717*0Sstevel@tonic-gate continue; 2718*0Sstevel@tonic-gate 2719*0Sstevel@tonic-gate cp = dr_get_common_unit(bp, SBD_COMP_CPU, ut); 2720*0Sstevel@tonic-gate s = (int)cp->sbdev_state; 2721*0Sstevel@tonic-gate if (!DR_DEV_IS_PRESENT(cp)) { 2722*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, ut); 2723*0Sstevel@tonic-gate } else { 2724*0Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 2725*0Sstevel@tonic-gate if (!state_err) 2726*0Sstevel@tonic-gate state_err = s; 2727*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_CPU, ut); 2728*0Sstevel@tonic-gate } 2729*0Sstevel@tonic-gate } 2730*0Sstevel@tonic-gate } 2731*0Sstevel@tonic-gate } 2732*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, DEVSET_ANYUNIT)) { 2733*0Sstevel@tonic-gate for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) { 2734*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_MEM, ut) == 0) 2735*0Sstevel@tonic-gate continue; 2736*0Sstevel@tonic-gate 2737*0Sstevel@tonic-gate cp = dr_get_common_unit(bp, SBD_COMP_MEM, ut); 2738*0Sstevel@tonic-gate s = (int)cp->sbdev_state; 2739*0Sstevel@tonic-gate if (!DR_DEV_IS_PRESENT(cp)) { 2740*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, ut); 2741*0Sstevel@tonic-gate } else { 2742*0Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 2743*0Sstevel@tonic-gate if (!state_err) 2744*0Sstevel@tonic-gate state_err = s; 2745*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_MEM, ut); 2746*0Sstevel@tonic-gate } 2747*0Sstevel@tonic-gate } 2748*0Sstevel@tonic-gate } 2749*0Sstevel@tonic-gate } 2750*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, DEVSET_ANYUNIT)) { 2751*0Sstevel@tonic-gate for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) { 2752*0Sstevel@tonic-gate if (DEVSET_IN_SET(devset, SBD_COMP_IO, ut) == 0) 2753*0Sstevel@tonic-gate continue; 2754*0Sstevel@tonic-gate 2755*0Sstevel@tonic-gate cp = dr_get_common_unit(bp, SBD_COMP_IO, ut); 2756*0Sstevel@tonic-gate s = (int)cp->sbdev_state; 2757*0Sstevel@tonic-gate if (!DR_DEV_IS_PRESENT(cp)) { 2758*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, ut); 2759*0Sstevel@tonic-gate } else { 2760*0Sstevel@tonic-gate if (transp->x_op[s].x_rv) { 2761*0Sstevel@tonic-gate if (!state_err) 2762*0Sstevel@tonic-gate state_err = s; 2763*0Sstevel@tonic-gate DEVSET_DEL(devset, SBD_COMP_IO, ut); 2764*0Sstevel@tonic-gate } 2765*0Sstevel@tonic-gate } 2766*0Sstevel@tonic-gate } 2767*0Sstevel@tonic-gate } 2768*0Sstevel@tonic-gate 2769*0Sstevel@tonic-gate PR_ALL("%s: requested devset = 0x%x, final devset = 0x%x\n", 2770*0Sstevel@tonic-gate f, (uint_t)*devsetp, (uint_t)devset); 2771*0Sstevel@tonic-gate 2772*0Sstevel@tonic-gate *devsetp = devset; 2773*0Sstevel@tonic-gate /* 2774*0Sstevel@tonic-gate * If there are some remaining components for which 2775*0Sstevel@tonic-gate * this state transition is valid, then allow them 2776*0Sstevel@tonic-gate * through, otherwise if none are left then return 2777*0Sstevel@tonic-gate * the state error. The exception is SBD_CMD_DISCONNECT. 2778*0Sstevel@tonic-gate * On disconnect, the state transition must be valid for ALL 2779*0Sstevel@tonic-gate * components. 2780*0Sstevel@tonic-gate */ 2781*0Sstevel@tonic-gate if (cmd == SBD_CMD_DISCONNECT) 2782*0Sstevel@tonic-gate return (state_err); 2783*0Sstevel@tonic-gate return (devset ? 0 : state_err); 2784*0Sstevel@tonic-gate } 2785*0Sstevel@tonic-gate 2786*0Sstevel@tonic-gate void 2787*0Sstevel@tonic-gate dr_device_transition(dr_common_unit_t *cp, dr_state_t st) 2788*0Sstevel@tonic-gate { 2789*0Sstevel@tonic-gate PR_STATE("%s STATE %s(%d) -> %s(%d)\n", 2790*0Sstevel@tonic-gate cp->sbdev_path, 2791*0Sstevel@tonic-gate state_str[cp->sbdev_state], cp->sbdev_state, 2792*0Sstevel@tonic-gate state_str[st], st); 2793*0Sstevel@tonic-gate 2794*0Sstevel@tonic-gate cp->sbdev_state = st; 2795*0Sstevel@tonic-gate if (st == DR_STATE_CONFIGURED) { 2796*0Sstevel@tonic-gate cp->sbdev_ostate = SBD_STAT_CONFIGURED; 2797*0Sstevel@tonic-gate if (cp->sbdev_bp->b_ostate != SBD_STAT_CONFIGURED) { 2798*0Sstevel@tonic-gate cp->sbdev_bp->b_ostate = SBD_STAT_CONFIGURED; 2799*0Sstevel@tonic-gate (void) drv_getparm(TIME, 2800*0Sstevel@tonic-gate (void *) &cp->sbdev_bp->b_time); 2801*0Sstevel@tonic-gate } 2802*0Sstevel@tonic-gate } else 2803*0Sstevel@tonic-gate cp->sbdev_ostate = SBD_STAT_UNCONFIGURED; 2804*0Sstevel@tonic-gate 2805*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *) &cp->sbdev_time); 2806*0Sstevel@tonic-gate } 2807*0Sstevel@tonic-gate 2808*0Sstevel@tonic-gate static void 2809*0Sstevel@tonic-gate dr_board_transition(dr_board_t *bp, dr_state_t st) 2810*0Sstevel@tonic-gate { 2811*0Sstevel@tonic-gate PR_STATE("BOARD %d STATE: %s(%d) -> %s(%d)\n", 2812*0Sstevel@tonic-gate bp->b_num, 2813*0Sstevel@tonic-gate state_str[bp->b_state], bp->b_state, 2814*0Sstevel@tonic-gate state_str[st], st); 2815*0Sstevel@tonic-gate 2816*0Sstevel@tonic-gate bp->b_state = st; 2817*0Sstevel@tonic-gate } 2818*0Sstevel@tonic-gate 2819*0Sstevel@tonic-gate void 2820*0Sstevel@tonic-gate dr_op_err(int ce, dr_handle_t *hp, int code, char *fmt, ...) 2821*0Sstevel@tonic-gate { 2822*0Sstevel@tonic-gate sbd_error_t *err; 2823*0Sstevel@tonic-gate va_list args; 2824*0Sstevel@tonic-gate 2825*0Sstevel@tonic-gate va_start(args, fmt); 2826*0Sstevel@tonic-gate err = drerr_new_v(code, fmt, args); 2827*0Sstevel@tonic-gate va_end(args); 2828*0Sstevel@tonic-gate 2829*0Sstevel@tonic-gate if (ce != CE_IGNORE) 2830*0Sstevel@tonic-gate sbd_err_log(err, ce); 2831*0Sstevel@tonic-gate 2832*0Sstevel@tonic-gate DRERR_SET_C(&hp->h_err, &err); 2833*0Sstevel@tonic-gate } 2834*0Sstevel@tonic-gate 2835*0Sstevel@tonic-gate void 2836*0Sstevel@tonic-gate dr_dev_err(int ce, dr_common_unit_t *cp, int code) 2837*0Sstevel@tonic-gate { 2838*0Sstevel@tonic-gate sbd_error_t *err; 2839*0Sstevel@tonic-gate 2840*0Sstevel@tonic-gate err = drerr_new(0, code, cp->sbdev_path, NULL); 2841*0Sstevel@tonic-gate 2842*0Sstevel@tonic-gate if (ce != CE_IGNORE) 2843*0Sstevel@tonic-gate sbd_err_log(err, ce); 2844*0Sstevel@tonic-gate 2845*0Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 2846*0Sstevel@tonic-gate } 2847*0Sstevel@tonic-gate 2848*0Sstevel@tonic-gate /* 2849*0Sstevel@tonic-gate * A callback routine. Called from the drmach layer as a result of 2850*0Sstevel@tonic-gate * call to drmach_board_find_devices from dr_init_devlists. 2851*0Sstevel@tonic-gate */ 2852*0Sstevel@tonic-gate static sbd_error_t * 2853*0Sstevel@tonic-gate dr_dev_found(void *data, const char *name, int unum, drmachid_t id) 2854*0Sstevel@tonic-gate { 2855*0Sstevel@tonic-gate dr_board_t *bp = data; 2856*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2857*0Sstevel@tonic-gate int nt; 2858*0Sstevel@tonic-gate static fn_t f = "dr_dev_found"; 2859*0Sstevel@tonic-gate 2860*0Sstevel@tonic-gate PR_ALL("%s (board = %d, name = %s, unum = %d, id = %p)...\n", 2861*0Sstevel@tonic-gate f, bp->b_num, name, unum, id); 2862*0Sstevel@tonic-gate 2863*0Sstevel@tonic-gate nt = dr_dev_type_to_nt((char *)name); 2864*0Sstevel@tonic-gate if (nt == SBD_COMP_UNKNOWN) { 2865*0Sstevel@tonic-gate /* 2866*0Sstevel@tonic-gate * this should not happen. When it does, it indicates 2867*0Sstevel@tonic-gate * a missmatch in devices supported by the drmach layer 2868*0Sstevel@tonic-gate * vs devices supported by this layer. 2869*0Sstevel@tonic-gate */ 2870*0Sstevel@tonic-gate return (DR_INTERNAL_ERROR()); 2871*0Sstevel@tonic-gate } 2872*0Sstevel@tonic-gate 2873*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, nt, unum); 2874*0Sstevel@tonic-gate 2875*0Sstevel@tonic-gate /* sanity check */ 2876*0Sstevel@tonic-gate ASSERT(dp->du_common.sbdev_bp == bp); 2877*0Sstevel@tonic-gate ASSERT(dp->du_common.sbdev_unum == unum); 2878*0Sstevel@tonic-gate ASSERT(dp->du_common.sbdev_type == nt); 2879*0Sstevel@tonic-gate 2880*0Sstevel@tonic-gate /* render dynamic attachment point path of this unit */ 2881*0Sstevel@tonic-gate (void) snprintf(dp->du_common.sbdev_path, 2882*0Sstevel@tonic-gate sizeof (dp->du_common.sbdev_path), 2883*0Sstevel@tonic-gate (nt == SBD_COMP_MEM ? "%s::%s" : "%s::%s%d"), 2884*0Sstevel@tonic-gate bp->b_path, name, DR_UNUM2SBD_UNUM(unum)); 2885*0Sstevel@tonic-gate 2886*0Sstevel@tonic-gate dp->du_common.sbdev_id = id; 2887*0Sstevel@tonic-gate DR_DEV_SET_PRESENT(&dp->du_common); 2888*0Sstevel@tonic-gate 2889*0Sstevel@tonic-gate bp->b_ndev++; 2890*0Sstevel@tonic-gate 2891*0Sstevel@tonic-gate return (NULL); 2892*0Sstevel@tonic-gate } 2893*0Sstevel@tonic-gate 2894*0Sstevel@tonic-gate static sbd_error_t * 2895*0Sstevel@tonic-gate dr_init_devlists(dr_board_t *bp) 2896*0Sstevel@tonic-gate { 2897*0Sstevel@tonic-gate int i; 2898*0Sstevel@tonic-gate sbd_error_t *err; 2899*0Sstevel@tonic-gate dr_dev_unit_t *dp; 2900*0Sstevel@tonic-gate static fn_t f = "dr_init_devlists"; 2901*0Sstevel@tonic-gate 2902*0Sstevel@tonic-gate PR_ALL("%s (%s)...\n", f, bp->b_path); 2903*0Sstevel@tonic-gate 2904*0Sstevel@tonic-gate /* sanity check */ 2905*0Sstevel@tonic-gate ASSERT(bp->b_ndev == 0); 2906*0Sstevel@tonic-gate 2907*0Sstevel@tonic-gate DR_DEVS_DISCONNECT(bp, (uint_t)-1); 2908*0Sstevel@tonic-gate 2909*0Sstevel@tonic-gate /* 2910*0Sstevel@tonic-gate * This routine builds the board's devlist and initializes 2911*0Sstevel@tonic-gate * the common portion of the unit data structures. 2912*0Sstevel@tonic-gate * Note: because the common portion is considered 2913*0Sstevel@tonic-gate * uninitialized, the dr_get_*_unit() routines can not 2914*0Sstevel@tonic-gate * be used. 2915*0Sstevel@tonic-gate */ 2916*0Sstevel@tonic-gate 2917*0Sstevel@tonic-gate /* 2918*0Sstevel@tonic-gate * Clear out old entries, if any. 2919*0Sstevel@tonic-gate */ 2920*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 2921*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_CPU, i); 2922*0Sstevel@tonic-gate 2923*0Sstevel@tonic-gate bzero(dp, sizeof (*dp)); 2924*0Sstevel@tonic-gate dp->du_common.sbdev_bp = bp; 2925*0Sstevel@tonic-gate dp->du_common.sbdev_unum = i; 2926*0Sstevel@tonic-gate dp->du_common.sbdev_type = SBD_COMP_CPU; 2927*0Sstevel@tonic-gate } 2928*0Sstevel@tonic-gate 2929*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 2930*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_MEM, i); 2931*0Sstevel@tonic-gate 2932*0Sstevel@tonic-gate bzero(dp, sizeof (*dp)); 2933*0Sstevel@tonic-gate dp->du_common.sbdev_bp = bp; 2934*0Sstevel@tonic-gate dp->du_common.sbdev_unum = i; 2935*0Sstevel@tonic-gate dp->du_common.sbdev_type = SBD_COMP_MEM; 2936*0Sstevel@tonic-gate } 2937*0Sstevel@tonic-gate 2938*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 2939*0Sstevel@tonic-gate dp = DR_GET_BOARD_DEVUNIT(bp, SBD_COMP_IO, i); 2940*0Sstevel@tonic-gate 2941*0Sstevel@tonic-gate bzero(dp, sizeof (*dp)); 2942*0Sstevel@tonic-gate dp->du_common.sbdev_bp = bp; 2943*0Sstevel@tonic-gate dp->du_common.sbdev_unum = i; 2944*0Sstevel@tonic-gate dp->du_common.sbdev_type = SBD_COMP_IO; 2945*0Sstevel@tonic-gate } 2946*0Sstevel@tonic-gate 2947*0Sstevel@tonic-gate err = NULL; 2948*0Sstevel@tonic-gate if (bp->b_id) { 2949*0Sstevel@tonic-gate /* find devices on this board */ 2950*0Sstevel@tonic-gate err = drmach_board_find_devices( 2951*0Sstevel@tonic-gate bp->b_id, bp, dr_dev_found); 2952*0Sstevel@tonic-gate } 2953*0Sstevel@tonic-gate 2954*0Sstevel@tonic-gate return (err); 2955*0Sstevel@tonic-gate } 2956*0Sstevel@tonic-gate 2957*0Sstevel@tonic-gate /* 2958*0Sstevel@tonic-gate * Return the unit number of the respective drmachid if 2959*0Sstevel@tonic-gate * it's found to be attached. 2960*0Sstevel@tonic-gate */ 2961*0Sstevel@tonic-gate static int 2962*0Sstevel@tonic-gate dr_check_unit_attached(dr_common_unit_t *cp) 2963*0Sstevel@tonic-gate { 2964*0Sstevel@tonic-gate int rv = 0; 2965*0Sstevel@tonic-gate processorid_t cpuid; 2966*0Sstevel@tonic-gate uint64_t basepa, endpa; 2967*0Sstevel@tonic-gate struct memlist *ml; 2968*0Sstevel@tonic-gate extern struct memlist *phys_install; 2969*0Sstevel@tonic-gate sbd_error_t *err; 2970*0Sstevel@tonic-gate int yes; 2971*0Sstevel@tonic-gate static fn_t f = "dr_check_unit_attached"; 2972*0Sstevel@tonic-gate 2973*0Sstevel@tonic-gate switch (cp->sbdev_type) { 2974*0Sstevel@tonic-gate case SBD_COMP_CPU: 2975*0Sstevel@tonic-gate err = drmach_cpu_get_id(cp->sbdev_id, &cpuid); 2976*0Sstevel@tonic-gate if (err) { 2977*0Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 2978*0Sstevel@tonic-gate rv = -1; 2979*0Sstevel@tonic-gate break; 2980*0Sstevel@tonic-gate } 2981*0Sstevel@tonic-gate mutex_enter(&cpu_lock); 2982*0Sstevel@tonic-gate if (cpu_get(cpuid) == NULL) 2983*0Sstevel@tonic-gate rv = -1; 2984*0Sstevel@tonic-gate mutex_exit(&cpu_lock); 2985*0Sstevel@tonic-gate break; 2986*0Sstevel@tonic-gate 2987*0Sstevel@tonic-gate case SBD_COMP_MEM: 2988*0Sstevel@tonic-gate err = drmach_mem_get_base_physaddr(cp->sbdev_id, &basepa); 2989*0Sstevel@tonic-gate if (err) { 2990*0Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 2991*0Sstevel@tonic-gate rv = -1; 2992*0Sstevel@tonic-gate break; 2993*0Sstevel@tonic-gate } 2994*0Sstevel@tonic-gate 2995*0Sstevel@tonic-gate /* 2996*0Sstevel@tonic-gate * basepa may not be on a alignment boundary, make it so. 2997*0Sstevel@tonic-gate */ 2998*0Sstevel@tonic-gate err = drmach_mem_get_slice_size(cp->sbdev_id, &endpa); 2999*0Sstevel@tonic-gate if (err) { 3000*0Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3001*0Sstevel@tonic-gate rv = -1; 3002*0Sstevel@tonic-gate break; 3003*0Sstevel@tonic-gate } 3004*0Sstevel@tonic-gate 3005*0Sstevel@tonic-gate basepa &= ~(endpa - 1); 3006*0Sstevel@tonic-gate endpa += basepa; 3007*0Sstevel@tonic-gate 3008*0Sstevel@tonic-gate /* 3009*0Sstevel@tonic-gate * Check if base address is in phys_install. 3010*0Sstevel@tonic-gate */ 3011*0Sstevel@tonic-gate memlist_read_lock(); 3012*0Sstevel@tonic-gate for (ml = phys_install; ml; ml = ml->next) 3013*0Sstevel@tonic-gate if ((endpa <= ml->address) || 3014*0Sstevel@tonic-gate (basepa >= (ml->address + ml->size))) 3015*0Sstevel@tonic-gate continue; 3016*0Sstevel@tonic-gate else 3017*0Sstevel@tonic-gate break; 3018*0Sstevel@tonic-gate memlist_read_unlock(); 3019*0Sstevel@tonic-gate if (ml == NULL) 3020*0Sstevel@tonic-gate rv = -1; 3021*0Sstevel@tonic-gate break; 3022*0Sstevel@tonic-gate 3023*0Sstevel@tonic-gate case SBD_COMP_IO: 3024*0Sstevel@tonic-gate err = drmach_io_is_attached(cp->sbdev_id, &yes); 3025*0Sstevel@tonic-gate if (err) { 3026*0Sstevel@tonic-gate DRERR_SET_C(&cp->sbdev_error, &err); 3027*0Sstevel@tonic-gate rv = -1; 3028*0Sstevel@tonic-gate break; 3029*0Sstevel@tonic-gate } else if (!yes) 3030*0Sstevel@tonic-gate rv = -1; 3031*0Sstevel@tonic-gate break; 3032*0Sstevel@tonic-gate 3033*0Sstevel@tonic-gate default: 3034*0Sstevel@tonic-gate PR_ALL("%s: unexpected nodetype(%d) for id 0x%x\n", 3035*0Sstevel@tonic-gate f, cp->sbdev_type, cp->sbdev_id); 3036*0Sstevel@tonic-gate rv = -1; 3037*0Sstevel@tonic-gate break; 3038*0Sstevel@tonic-gate } 3039*0Sstevel@tonic-gate 3040*0Sstevel@tonic-gate return (rv); 3041*0Sstevel@tonic-gate } 3042*0Sstevel@tonic-gate 3043*0Sstevel@tonic-gate /* 3044*0Sstevel@tonic-gate * See if drmach recognizes the passthru command. DRMACH expects the 3045*0Sstevel@tonic-gate * id to identify the thing to which the command is being applied. Using 3046*0Sstevel@tonic-gate * nonsense SBD terms, that information has been perversely encoded in the 3047*0Sstevel@tonic-gate * c_id member of the sbd_cmd_t structure. This logic reads those tea 3048*0Sstevel@tonic-gate * leaves, finds the associated drmach id, then calls drmach to process 3049*0Sstevel@tonic-gate * the passthru command. 3050*0Sstevel@tonic-gate */ 3051*0Sstevel@tonic-gate static int 3052*0Sstevel@tonic-gate dr_pt_try_drmach(dr_handle_t *hp) 3053*0Sstevel@tonic-gate { 3054*0Sstevel@tonic-gate dr_board_t *bp = hp->h_bd; 3055*0Sstevel@tonic-gate sbd_comp_id_t *comp_id = &hp->h_sbdcmd.cmd_cm.c_id; 3056*0Sstevel@tonic-gate drmachid_t id; 3057*0Sstevel@tonic-gate 3058*0Sstevel@tonic-gate if (comp_id->c_type == SBD_COMP_NONE) { 3059*0Sstevel@tonic-gate id = bp->b_id; 3060*0Sstevel@tonic-gate } else { 3061*0Sstevel@tonic-gate sbd_comp_type_t nt; 3062*0Sstevel@tonic-gate 3063*0Sstevel@tonic-gate nt = dr_dev_type_to_nt(comp_id->c_name); 3064*0Sstevel@tonic-gate if (nt == SBD_COMP_UNKNOWN) { 3065*0Sstevel@tonic-gate dr_op_err(CE_IGNORE, hp, ESBD_INVAL, comp_id->c_name); 3066*0Sstevel@tonic-gate id = 0; 3067*0Sstevel@tonic-gate } else { 3068*0Sstevel@tonic-gate /* pt command applied to dynamic attachment point */ 3069*0Sstevel@tonic-gate dr_common_unit_t *cp; 3070*0Sstevel@tonic-gate cp = dr_get_common_unit(bp, nt, comp_id->c_unit); 3071*0Sstevel@tonic-gate id = cp->sbdev_id; 3072*0Sstevel@tonic-gate } 3073*0Sstevel@tonic-gate } 3074*0Sstevel@tonic-gate 3075*0Sstevel@tonic-gate if (hp->h_err == NULL) 3076*0Sstevel@tonic-gate hp->h_err = drmach_passthru(id, &hp->h_opts); 3077*0Sstevel@tonic-gate 3078*0Sstevel@tonic-gate return (hp->h_err == NULL ? 0 : -1); 3079*0Sstevel@tonic-gate } 3080*0Sstevel@tonic-gate 3081*0Sstevel@tonic-gate static int 3082*0Sstevel@tonic-gate dr_pt_ioctl(dr_handle_t *hp) 3083*0Sstevel@tonic-gate { 3084*0Sstevel@tonic-gate int cmd, rv, len; 3085*0Sstevel@tonic-gate int32_t sz; 3086*0Sstevel@tonic-gate int found; 3087*0Sstevel@tonic-gate char *copts; 3088*0Sstevel@tonic-gate static fn_t f = "dr_pt_ioctl"; 3089*0Sstevel@tonic-gate 3090*0Sstevel@tonic-gate PR_ALL("%s...\n", f); 3091*0Sstevel@tonic-gate 3092*0Sstevel@tonic-gate sz = hp->h_opts.size; 3093*0Sstevel@tonic-gate copts = hp->h_opts.copts; 3094*0Sstevel@tonic-gate 3095*0Sstevel@tonic-gate if (sz == 0 || copts == (char *)NULL) { 3096*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s: invalid passthru args", f); 3097*0Sstevel@tonic-gate return (EINVAL); 3098*0Sstevel@tonic-gate } 3099*0Sstevel@tonic-gate 3100*0Sstevel@tonic-gate found = 0; 3101*0Sstevel@tonic-gate for (cmd = 0; cmd < (sizeof (pt_arr) / sizeof (pt_arr[0])); cmd++) { 3102*0Sstevel@tonic-gate len = strlen(pt_arr[cmd].pt_name); 3103*0Sstevel@tonic-gate found = (strncmp(pt_arr[cmd].pt_name, copts, len) == 0); 3104*0Sstevel@tonic-gate if (found) 3105*0Sstevel@tonic-gate break; 3106*0Sstevel@tonic-gate } 3107*0Sstevel@tonic-gate 3108*0Sstevel@tonic-gate if (found) 3109*0Sstevel@tonic-gate rv = (*pt_arr[cmd].pt_func)(hp); 3110*0Sstevel@tonic-gate else 3111*0Sstevel@tonic-gate rv = dr_pt_try_drmach(hp); 3112*0Sstevel@tonic-gate 3113*0Sstevel@tonic-gate return (rv); 3114*0Sstevel@tonic-gate } 3115*0Sstevel@tonic-gate 3116*0Sstevel@tonic-gate /* 3117*0Sstevel@tonic-gate * Called at driver load time to determine the state and condition 3118*0Sstevel@tonic-gate * of an existing board in the system. 3119*0Sstevel@tonic-gate */ 3120*0Sstevel@tonic-gate static void 3121*0Sstevel@tonic-gate dr_board_discovery(dr_board_t *bp) 3122*0Sstevel@tonic-gate { 3123*0Sstevel@tonic-gate int i; 3124*0Sstevel@tonic-gate dr_devset_t devs_lost, devs_attached = 0; 3125*0Sstevel@tonic-gate dr_cpu_unit_t *cp; 3126*0Sstevel@tonic-gate dr_mem_unit_t *mp; 3127*0Sstevel@tonic-gate dr_io_unit_t *ip; 3128*0Sstevel@tonic-gate static fn_t f = "dr_board_discovery"; 3129*0Sstevel@tonic-gate 3130*0Sstevel@tonic-gate if (DR_DEVS_PRESENT(bp) == 0) { 3131*0Sstevel@tonic-gate PR_ALL("%s: board %d has no devices present\n", 3132*0Sstevel@tonic-gate f, bp->b_num); 3133*0Sstevel@tonic-gate return; 3134*0Sstevel@tonic-gate } 3135*0Sstevel@tonic-gate 3136*0Sstevel@tonic-gate /* 3137*0Sstevel@tonic-gate * Check for existence of cpus. 3138*0Sstevel@tonic-gate */ 3139*0Sstevel@tonic-gate for (i = 0; i < MAX_CPU_UNITS_PER_BOARD; i++) { 3140*0Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, i); 3141*0Sstevel@tonic-gate 3142*0Sstevel@tonic-gate if (!DR_DEV_IS_PRESENT(&cp->sbc_cm)) 3143*0Sstevel@tonic-gate continue; 3144*0Sstevel@tonic-gate 3145*0Sstevel@tonic-gate if (dr_check_unit_attached(&cp->sbc_cm) >= 0) { 3146*0Sstevel@tonic-gate DR_DEV_SET_ATTACHED(&cp->sbc_cm); 3147*0Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_CPU, i); 3148*0Sstevel@tonic-gate PR_ALL("%s: board %d, cpu-unit %d - attached\n", 3149*0Sstevel@tonic-gate f, bp->b_num, i); 3150*0Sstevel@tonic-gate } 3151*0Sstevel@tonic-gate dr_init_cpu_unit(cp); 3152*0Sstevel@tonic-gate } 3153*0Sstevel@tonic-gate 3154*0Sstevel@tonic-gate /* 3155*0Sstevel@tonic-gate * Check for existence of memory. 3156*0Sstevel@tonic-gate */ 3157*0Sstevel@tonic-gate for (i = 0; i < MAX_MEM_UNITS_PER_BOARD; i++) { 3158*0Sstevel@tonic-gate mp = dr_get_mem_unit(bp, i); 3159*0Sstevel@tonic-gate 3160*0Sstevel@tonic-gate if (!DR_DEV_IS_PRESENT(&mp->sbm_cm)) 3161*0Sstevel@tonic-gate continue; 3162*0Sstevel@tonic-gate 3163*0Sstevel@tonic-gate if (dr_check_unit_attached(&mp->sbm_cm) >= 0) { 3164*0Sstevel@tonic-gate DR_DEV_SET_ATTACHED(&mp->sbm_cm); 3165*0Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_MEM, i); 3166*0Sstevel@tonic-gate PR_ALL("%s: board %d, mem-unit %d - attached\n", 3167*0Sstevel@tonic-gate f, bp->b_num, i); 3168*0Sstevel@tonic-gate } 3169*0Sstevel@tonic-gate dr_init_mem_unit(mp); 3170*0Sstevel@tonic-gate } 3171*0Sstevel@tonic-gate 3172*0Sstevel@tonic-gate /* 3173*0Sstevel@tonic-gate * Check for i/o state. 3174*0Sstevel@tonic-gate */ 3175*0Sstevel@tonic-gate for (i = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 3176*0Sstevel@tonic-gate ip = dr_get_io_unit(bp, i); 3177*0Sstevel@tonic-gate 3178*0Sstevel@tonic-gate if (!DR_DEV_IS_PRESENT(&ip->sbi_cm)) 3179*0Sstevel@tonic-gate continue; 3180*0Sstevel@tonic-gate 3181*0Sstevel@tonic-gate if (dr_check_unit_attached(&ip->sbi_cm) >= 0) { 3182*0Sstevel@tonic-gate /* 3183*0Sstevel@tonic-gate * Found it! 3184*0Sstevel@tonic-gate */ 3185*0Sstevel@tonic-gate DR_DEV_SET_ATTACHED(&ip->sbi_cm); 3186*0Sstevel@tonic-gate DEVSET_ADD(devs_attached, SBD_COMP_IO, i); 3187*0Sstevel@tonic-gate PR_ALL("%s: board %d, io-unit %d - attached\n", 3188*0Sstevel@tonic-gate f, bp->b_num, i); 3189*0Sstevel@tonic-gate } 3190*0Sstevel@tonic-gate dr_init_io_unit(ip); 3191*0Sstevel@tonic-gate } 3192*0Sstevel@tonic-gate 3193*0Sstevel@tonic-gate DR_DEVS_CONFIGURE(bp, devs_attached); 3194*0Sstevel@tonic-gate if (devs_attached && ((devs_lost = DR_DEVS_UNATTACHED(bp)) != 0)) { 3195*0Sstevel@tonic-gate int ut; 3196*0Sstevel@tonic-gate /* 3197*0Sstevel@tonic-gate * It is not legal on board discovery to have a 3198*0Sstevel@tonic-gate * board that is only partially attached. A board 3199*0Sstevel@tonic-gate * is either all attached or all connected. If a 3200*0Sstevel@tonic-gate * board has at least one attached device, then 3201*0Sstevel@tonic-gate * the the remaining devices, if any, must have 3202*0Sstevel@tonic-gate * been lost or disconnected. These devices can 3203*0Sstevel@tonic-gate * only be recovered by a full attach from scratch. 3204*0Sstevel@tonic-gate * Note that devices previously in the unreferenced 3205*0Sstevel@tonic-gate * state are subsequently lost until the next full 3206*0Sstevel@tonic-gate * attach. This is necessary since the driver unload 3207*0Sstevel@tonic-gate * that must have occurred would have wiped out the 3208*0Sstevel@tonic-gate * information necessary to re-configure the device 3209*0Sstevel@tonic-gate * back online, e.g. memlist. 3210*0Sstevel@tonic-gate */ 3211*0Sstevel@tonic-gate PR_ALL("%s: some devices LOST (0x%x)...\n", f, devs_lost); 3212*0Sstevel@tonic-gate 3213*0Sstevel@tonic-gate for (ut = 0; ut < MAX_CPU_UNITS_PER_BOARD; ut++) { 3214*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devs_lost, SBD_COMP_CPU, ut)) 3215*0Sstevel@tonic-gate continue; 3216*0Sstevel@tonic-gate 3217*0Sstevel@tonic-gate cp = dr_get_cpu_unit(bp, ut); 3218*0Sstevel@tonic-gate dr_device_transition(&cp->sbc_cm, DR_STATE_EMPTY); 3219*0Sstevel@tonic-gate } 3220*0Sstevel@tonic-gate 3221*0Sstevel@tonic-gate for (ut = 0; ut < MAX_MEM_UNITS_PER_BOARD; ut++) { 3222*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devs_lost, SBD_COMP_MEM, ut)) 3223*0Sstevel@tonic-gate continue; 3224*0Sstevel@tonic-gate 3225*0Sstevel@tonic-gate mp = dr_get_mem_unit(bp, ut); 3226*0Sstevel@tonic-gate dr_device_transition(&mp->sbm_cm, DR_STATE_EMPTY); 3227*0Sstevel@tonic-gate } 3228*0Sstevel@tonic-gate 3229*0Sstevel@tonic-gate for (ut = 0; ut < MAX_IO_UNITS_PER_BOARD; ut++) { 3230*0Sstevel@tonic-gate if (!DEVSET_IN_SET(devs_lost, SBD_COMP_IO, ut)) 3231*0Sstevel@tonic-gate continue; 3232*0Sstevel@tonic-gate 3233*0Sstevel@tonic-gate ip = dr_get_io_unit(bp, ut); 3234*0Sstevel@tonic-gate dr_device_transition(&ip->sbi_cm, DR_STATE_EMPTY); 3235*0Sstevel@tonic-gate } 3236*0Sstevel@tonic-gate 3237*0Sstevel@tonic-gate DR_DEVS_DISCONNECT(bp, devs_lost); 3238*0Sstevel@tonic-gate } 3239*0Sstevel@tonic-gate } 3240*0Sstevel@tonic-gate 3241*0Sstevel@tonic-gate static int 3242*0Sstevel@tonic-gate dr_board_init(dr_board_t *bp, dev_info_t *dip, int bd) 3243*0Sstevel@tonic-gate { 3244*0Sstevel@tonic-gate sbd_error_t *err; 3245*0Sstevel@tonic-gate 3246*0Sstevel@tonic-gate mutex_init(&bp->b_lock, NULL, MUTEX_DRIVER, NULL); 3247*0Sstevel@tonic-gate mutex_init(&bp->b_slock, NULL, MUTEX_DRIVER, NULL); 3248*0Sstevel@tonic-gate cv_init(&bp->b_scv, NULL, CV_DRIVER, NULL); 3249*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_EMPTY; 3250*0Sstevel@tonic-gate bp->b_ostate = SBD_STAT_UNCONFIGURED; 3251*0Sstevel@tonic-gate bp->b_cond = SBD_COND_UNKNOWN; 3252*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 3253*0Sstevel@tonic-gate 3254*0Sstevel@tonic-gate (void) drmach_board_lookup(bd, &bp->b_id); 3255*0Sstevel@tonic-gate bp->b_num = bd; 3256*0Sstevel@tonic-gate bp->b_dip = dip; 3257*0Sstevel@tonic-gate 3258*0Sstevel@tonic-gate bp->b_dev[NIX(SBD_COMP_CPU)] = GETSTRUCT(dr_dev_unit_t, 3259*0Sstevel@tonic-gate MAX_CPU_UNITS_PER_BOARD); 3260*0Sstevel@tonic-gate 3261*0Sstevel@tonic-gate bp->b_dev[NIX(SBD_COMP_MEM)] = GETSTRUCT(dr_dev_unit_t, 3262*0Sstevel@tonic-gate MAX_MEM_UNITS_PER_BOARD); 3263*0Sstevel@tonic-gate 3264*0Sstevel@tonic-gate bp->b_dev[NIX(SBD_COMP_IO)] = GETSTRUCT(dr_dev_unit_t, 3265*0Sstevel@tonic-gate MAX_IO_UNITS_PER_BOARD); 3266*0Sstevel@tonic-gate 3267*0Sstevel@tonic-gate /* 3268*0Sstevel@tonic-gate * Initialize the devlists 3269*0Sstevel@tonic-gate */ 3270*0Sstevel@tonic-gate err = dr_init_devlists(bp); 3271*0Sstevel@tonic-gate if (err) { 3272*0Sstevel@tonic-gate sbd_err_clear(&err); 3273*0Sstevel@tonic-gate dr_board_destroy(bp); 3274*0Sstevel@tonic-gate return (-1); 3275*0Sstevel@tonic-gate } else if (bp->b_ndev == 0) { 3276*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_EMPTY); 3277*0Sstevel@tonic-gate } else { 3278*0Sstevel@tonic-gate /* 3279*0Sstevel@tonic-gate * Couldn't have made it down here without 3280*0Sstevel@tonic-gate * having found at least one device. 3281*0Sstevel@tonic-gate */ 3282*0Sstevel@tonic-gate ASSERT(DR_DEVS_PRESENT(bp) != 0); 3283*0Sstevel@tonic-gate /* 3284*0Sstevel@tonic-gate * Check the state of any possible devices on the 3285*0Sstevel@tonic-gate * board. 3286*0Sstevel@tonic-gate */ 3287*0Sstevel@tonic-gate dr_board_discovery(bp); 3288*0Sstevel@tonic-gate 3289*0Sstevel@tonic-gate bp->b_assigned = 1; 3290*0Sstevel@tonic-gate 3291*0Sstevel@tonic-gate if (DR_DEVS_UNATTACHED(bp) == 0) { 3292*0Sstevel@tonic-gate /* 3293*0Sstevel@tonic-gate * The board has no unattached devices, therefore 3294*0Sstevel@tonic-gate * by reason of insanity it must be configured! 3295*0Sstevel@tonic-gate */ 3296*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_CONFIGURED); 3297*0Sstevel@tonic-gate bp->b_ostate = SBD_STAT_CONFIGURED; 3298*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_CONNECTED; 3299*0Sstevel@tonic-gate bp->b_cond = SBD_COND_OK; 3300*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 3301*0Sstevel@tonic-gate } else if (DR_DEVS_ATTACHED(bp)) { 3302*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_PARTIAL); 3303*0Sstevel@tonic-gate bp->b_ostate = SBD_STAT_CONFIGURED; 3304*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_CONNECTED; 3305*0Sstevel@tonic-gate bp->b_cond = SBD_COND_OK; 3306*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 3307*0Sstevel@tonic-gate } else { 3308*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_CONNECTED); 3309*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_CONNECTED; 3310*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 3311*0Sstevel@tonic-gate } 3312*0Sstevel@tonic-gate } 3313*0Sstevel@tonic-gate 3314*0Sstevel@tonic-gate return (0); 3315*0Sstevel@tonic-gate } 3316*0Sstevel@tonic-gate 3317*0Sstevel@tonic-gate static void 3318*0Sstevel@tonic-gate dr_board_destroy(dr_board_t *bp) 3319*0Sstevel@tonic-gate { 3320*0Sstevel@tonic-gate PR_ALL("dr_board_destroy: num %d, path %s\n", 3321*0Sstevel@tonic-gate bp->b_num, bp->b_path); 3322*0Sstevel@tonic-gate 3323*0Sstevel@tonic-gate dr_board_transition(bp, DR_STATE_EMPTY); 3324*0Sstevel@tonic-gate bp->b_rstate = SBD_STAT_EMPTY; 3325*0Sstevel@tonic-gate (void) drv_getparm(TIME, (void *)&bp->b_time); 3326*0Sstevel@tonic-gate 3327*0Sstevel@tonic-gate /* 3328*0Sstevel@tonic-gate * Free up MEM unit structs. 3329*0Sstevel@tonic-gate */ 3330*0Sstevel@tonic-gate FREESTRUCT(bp->b_dev[NIX(SBD_COMP_MEM)], 3331*0Sstevel@tonic-gate dr_dev_unit_t, MAX_MEM_UNITS_PER_BOARD); 3332*0Sstevel@tonic-gate bp->b_dev[NIX(SBD_COMP_MEM)] = NULL; 3333*0Sstevel@tonic-gate /* 3334*0Sstevel@tonic-gate * Free up CPU unit structs. 3335*0Sstevel@tonic-gate */ 3336*0Sstevel@tonic-gate FREESTRUCT(bp->b_dev[NIX(SBD_COMP_CPU)], 3337*0Sstevel@tonic-gate dr_dev_unit_t, MAX_CPU_UNITS_PER_BOARD); 3338*0Sstevel@tonic-gate bp->b_dev[NIX(SBD_COMP_CPU)] = NULL; 3339*0Sstevel@tonic-gate /* 3340*0Sstevel@tonic-gate * Free up IO unit structs. 3341*0Sstevel@tonic-gate */ 3342*0Sstevel@tonic-gate FREESTRUCT(bp->b_dev[NIX(SBD_COMP_IO)], 3343*0Sstevel@tonic-gate dr_dev_unit_t, MAX_IO_UNITS_PER_BOARD); 3344*0Sstevel@tonic-gate bp->b_dev[NIX(SBD_COMP_IO)] = NULL; 3345*0Sstevel@tonic-gate 3346*0Sstevel@tonic-gate mutex_destroy(&bp->b_lock); 3347*0Sstevel@tonic-gate mutex_destroy(&bp->b_slock); 3348*0Sstevel@tonic-gate cv_destroy(&bp->b_scv); 3349*0Sstevel@tonic-gate } 3350*0Sstevel@tonic-gate 3351*0Sstevel@tonic-gate void 3352*0Sstevel@tonic-gate dr_lock_status(dr_board_t *bp) 3353*0Sstevel@tonic-gate { 3354*0Sstevel@tonic-gate mutex_enter(&bp->b_slock); 3355*0Sstevel@tonic-gate while (bp->b_sflags & DR_BSLOCK) 3356*0Sstevel@tonic-gate cv_wait(&bp->b_scv, &bp->b_slock); 3357*0Sstevel@tonic-gate bp->b_sflags |= DR_BSLOCK; 3358*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 3359*0Sstevel@tonic-gate } 3360*0Sstevel@tonic-gate 3361*0Sstevel@tonic-gate void 3362*0Sstevel@tonic-gate dr_unlock_status(dr_board_t *bp) 3363*0Sstevel@tonic-gate { 3364*0Sstevel@tonic-gate mutex_enter(&bp->b_slock); 3365*0Sstevel@tonic-gate bp->b_sflags &= ~DR_BSLOCK; 3366*0Sstevel@tonic-gate cv_signal(&bp->b_scv); 3367*0Sstevel@tonic-gate mutex_exit(&bp->b_slock); 3368*0Sstevel@tonic-gate } 3369*0Sstevel@tonic-gate 3370*0Sstevel@tonic-gate /* 3371*0Sstevel@tonic-gate * Extract flags passed via ioctl. 3372*0Sstevel@tonic-gate */ 3373*0Sstevel@tonic-gate int 3374*0Sstevel@tonic-gate dr_cmd_flags(dr_handle_t *hp) 3375*0Sstevel@tonic-gate { 3376*0Sstevel@tonic-gate return (hp->h_sbdcmd.cmd_cm.c_flags); 3377*0Sstevel@tonic-gate } 3378