1*a3114836SGerry Liu /* 2*a3114836SGerry Liu * CDDL HEADER START 3*a3114836SGerry Liu * 4*a3114836SGerry Liu * The contents of this file are subject to the terms of the 5*a3114836SGerry Liu * Common Development and Distribution License (the "License"). 6*a3114836SGerry Liu * You may not use this file except in compliance with the License. 7*a3114836SGerry Liu * 8*a3114836SGerry Liu * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*a3114836SGerry Liu * or http://www.opensolaris.org/os/licensing. 10*a3114836SGerry Liu * See the License for the specific language governing permissions 11*a3114836SGerry Liu * and limitations under the License. 12*a3114836SGerry Liu * 13*a3114836SGerry Liu * When distributing Covered Code, include this CDDL HEADER in each 14*a3114836SGerry Liu * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*a3114836SGerry Liu * If applicable, add the following below this CDDL HEADER, with the 16*a3114836SGerry Liu * fields enclosed by brackets "[]" replaced with your own identifying 17*a3114836SGerry Liu * information: Portions Copyright [yyyy] [name of copyright owner] 18*a3114836SGerry Liu * 19*a3114836SGerry Liu * CDDL HEADER END 20*a3114836SGerry Liu */ 21*a3114836SGerry Liu 22*a3114836SGerry Liu /* 23*a3114836SGerry Liu * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 24*a3114836SGerry Liu * Use is subject to license terms. 25*a3114836SGerry Liu */ 26*a3114836SGerry Liu 27*a3114836SGerry Liu /* 28*a3114836SGerry Liu * I/O support routines for DR 29*a3114836SGerry Liu */ 30*a3114836SGerry Liu 31*a3114836SGerry Liu #include <sys/types.h> 32*a3114836SGerry Liu #include <sys/cmn_err.h> 33*a3114836SGerry Liu #include <sys/debug.h> 34*a3114836SGerry Liu #include <sys/errno.h> 35*a3114836SGerry Liu #include <sys/dditypes.h> 36*a3114836SGerry Liu #include <sys/ddi.h> 37*a3114836SGerry Liu #include <sys/sunddi.h> 38*a3114836SGerry Liu #include <sys/sunndi.h> 39*a3114836SGerry Liu #include <sys/ndi_impldefs.h> 40*a3114836SGerry Liu #include <sys/kmem.h> 41*a3114836SGerry Liu #include <sys/promif.h> 42*a3114836SGerry Liu #include <sys/sysmacros.h> 43*a3114836SGerry Liu #include <sys/archsystm.h> 44*a3114836SGerry Liu #include <sys/machsystm.h> 45*a3114836SGerry Liu 46*a3114836SGerry Liu #include <sys/dr.h> 47*a3114836SGerry Liu #include <sys/dr_util.h> 48*a3114836SGerry Liu #include <sys/drmach.h> 49*a3114836SGerry Liu 50*a3114836SGerry Liu void 51*a3114836SGerry Liu dr_init_io_unit(dr_io_unit_t *ip) 52*a3114836SGerry Liu { 53*a3114836SGerry Liu dr_state_t new_state; 54*a3114836SGerry Liu 55*a3114836SGerry Liu if (DR_DEV_IS_ATTACHED(&ip->sbi_cm)) { 56*a3114836SGerry Liu new_state = DR_STATE_CONFIGURED; 57*a3114836SGerry Liu ip->sbi_cm.sbdev_cond = SBD_COND_OK; 58*a3114836SGerry Liu } else if (DR_DEV_IS_PRESENT(&ip->sbi_cm)) { 59*a3114836SGerry Liu new_state = DR_STATE_CONNECTED; 60*a3114836SGerry Liu ip->sbi_cm.sbdev_cond = SBD_COND_OK; 61*a3114836SGerry Liu } else { 62*a3114836SGerry Liu new_state = DR_STATE_EMPTY; 63*a3114836SGerry Liu } 64*a3114836SGerry Liu dr_device_transition(&ip->sbi_cm, new_state); 65*a3114836SGerry Liu } 66*a3114836SGerry Liu 67*a3114836SGerry Liu /*ARGSUSED*/ 68*a3114836SGerry Liu void 69*a3114836SGerry Liu dr_attach_io(dr_handle_t *hp, dr_common_unit_t *cp) 70*a3114836SGerry Liu { 71*a3114836SGerry Liu sbd_error_t *err; 72*a3114836SGerry Liu 73*a3114836SGerry Liu dr_lock_status(hp->h_bd); 74*a3114836SGerry Liu err = drmach_configure(cp->sbdev_id, 0); 75*a3114836SGerry Liu dr_unlock_status(hp->h_bd); 76*a3114836SGerry Liu 77*a3114836SGerry Liu if (!err) 78*a3114836SGerry Liu err = drmach_io_post_attach(cp->sbdev_id); 79*a3114836SGerry Liu 80*a3114836SGerry Liu if (err) 81*a3114836SGerry Liu DRERR_SET_C(&cp->sbdev_error, &err); 82*a3114836SGerry Liu } 83*a3114836SGerry Liu 84*a3114836SGerry Liu /* 85*a3114836SGerry Liu * remove device nodes for the branch indicated by cp 86*a3114836SGerry Liu */ 87*a3114836SGerry Liu /*ARGSUSED*/ 88*a3114836SGerry Liu void 89*a3114836SGerry Liu dr_detach_io(dr_handle_t *hp, dr_common_unit_t *cp) 90*a3114836SGerry Liu { 91*a3114836SGerry Liu sbd_error_t *err; 92*a3114836SGerry Liu 93*a3114836SGerry Liu err = drmach_unconfigure(cp->sbdev_id, 0); 94*a3114836SGerry Liu 95*a3114836SGerry Liu if (!err) 96*a3114836SGerry Liu err = drmach_unconfigure(cp->sbdev_id, DEVI_BRANCH_DESTROY); 97*a3114836SGerry Liu 98*a3114836SGerry Liu if (!err) 99*a3114836SGerry Liu err = drmach_io_post_release(cp->sbdev_id); 100*a3114836SGerry Liu 101*a3114836SGerry Liu if (err) { 102*a3114836SGerry Liu dr_device_transition(cp, DR_STATE_CONFIGURED); 103*a3114836SGerry Liu DRERR_SET_C(&cp->sbdev_error, &err); 104*a3114836SGerry Liu } 105*a3114836SGerry Liu } 106*a3114836SGerry Liu 107*a3114836SGerry Liu /*ARGSUSED*/ 108*a3114836SGerry Liu int 109*a3114836SGerry Liu dr_disconnect_io(dr_io_unit_t *ip) 110*a3114836SGerry Liu { 111*a3114836SGerry Liu return (0); 112*a3114836SGerry Liu } 113*a3114836SGerry Liu 114*a3114836SGerry Liu /*ARGSUSED*/ 115*a3114836SGerry Liu int 116*a3114836SGerry Liu dr_pre_attach_io(dr_handle_t *hp, 117*a3114836SGerry Liu dr_common_unit_t **devlist, int devnum) 118*a3114836SGerry Liu { 119*a3114836SGerry Liu int d; 120*a3114836SGerry Liu 121*a3114836SGerry Liu for (d = 0; d < devnum; d++) { 122*a3114836SGerry Liu dr_common_unit_t *cp = devlist[d]; 123*a3114836SGerry Liu 124*a3114836SGerry Liu cmn_err(CE_CONT, "OS configure %s", cp->sbdev_path); 125*a3114836SGerry Liu } 126*a3114836SGerry Liu 127*a3114836SGerry Liu return (0); 128*a3114836SGerry Liu } 129*a3114836SGerry Liu 130*a3114836SGerry Liu /*ARGSUSED*/ 131*a3114836SGerry Liu int 132*a3114836SGerry Liu dr_post_attach_io(dr_handle_t *hp, 133*a3114836SGerry Liu dr_common_unit_t **devlist, int devnum) 134*a3114836SGerry Liu { 135*a3114836SGerry Liu return (0); 136*a3114836SGerry Liu } 137*a3114836SGerry Liu 138*a3114836SGerry Liu static int 139*a3114836SGerry Liu dr_check_io_refs(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 140*a3114836SGerry Liu { 141*a3114836SGerry Liu register int i, reftotal = 0; 142*a3114836SGerry Liu static fn_t f = "dr_check_io_refs"; 143*a3114836SGerry Liu 144*a3114836SGerry Liu for (i = 0; i < devnum; i++) { 145*a3114836SGerry Liu dr_io_unit_t *ip = (dr_io_unit_t *)devlist[i]; 146*a3114836SGerry Liu dev_info_t *dip; 147*a3114836SGerry Liu int ref; 148*a3114836SGerry Liu int refcount_non_gldv3; 149*a3114836SGerry Liu sbd_error_t *err; 150*a3114836SGerry Liu 151*a3114836SGerry Liu err = drmach_get_dip(ip->sbi_cm.sbdev_id, &dip); 152*a3114836SGerry Liu if (err) 153*a3114836SGerry Liu DRERR_SET_C(&ip->sbi_cm.sbdev_error, &err); 154*a3114836SGerry Liu else if (dip != NULL) { 155*a3114836SGerry Liu ref = 0; 156*a3114836SGerry Liu refcount_non_gldv3 = 0; 157*a3114836SGerry Liu ASSERT(e_ddi_branch_held(dip)); 158*a3114836SGerry Liu dr_check_devices(dip, &ref, hp, NULL, NULL, 159*a3114836SGerry Liu 0, &refcount_non_gldv3); 160*a3114836SGerry Liu ASSERT(refcount_non_gldv3 >= 0); 161*a3114836SGerry Liu ASSERT(ref >= refcount_non_gldv3); 162*a3114836SGerry Liu /* 163*a3114836SGerry Liu * Ignore reference counts of non-gldv3 network devices 164*a3114836SGerry Liu * as Crossbow creates reference counts for non-active 165*a3114836SGerry Liu * (unplumbed) instances. Reference count check in 166*a3114836SGerry Liu * detach() known to prevent device from detaching 167*a3114836SGerry Liu * as necessary. 168*a3114836SGerry Liu */ 169*a3114836SGerry Liu ref -= refcount_non_gldv3; 170*a3114836SGerry Liu hp->h_err = NULL; 171*a3114836SGerry Liu if (ref) { 172*a3114836SGerry Liu dr_dev_err(CE_WARN, &ip->sbi_cm, ESBD_BUSY); 173*a3114836SGerry Liu } 174*a3114836SGerry Liu PR_IO("%s: dip(%s) ref = %d\n", 175*a3114836SGerry Liu f, ddi_get_name(dip), ref); 176*a3114836SGerry Liu reftotal += ref; 177*a3114836SGerry Liu } else { 178*a3114836SGerry Liu PR_IO("%s: NO dip for id (0x%x)\n", 179*a3114836SGerry Liu f, (uint_t)(uintptr_t)ip->sbi_cm.sbdev_id); 180*a3114836SGerry Liu } 181*a3114836SGerry Liu } 182*a3114836SGerry Liu 183*a3114836SGerry Liu return (reftotal); 184*a3114836SGerry Liu } 185*a3114836SGerry Liu 186*a3114836SGerry Liu int 187*a3114836SGerry Liu dr_pre_release_io(dr_handle_t *hp, 188*a3114836SGerry Liu dr_common_unit_t **devlist, int devnum) 189*a3114836SGerry Liu { 190*a3114836SGerry Liu static fn_t f = "dr_pre_release_io"; 191*a3114836SGerry Liu int d; 192*a3114836SGerry Liu 193*a3114836SGerry Liu ASSERT(devnum > 0); 194*a3114836SGerry Liu 195*a3114836SGerry Liu /* fail if any I/O device pre-release fails */ 196*a3114836SGerry Liu for (d = 0; d < devnum; d++) { 197*a3114836SGerry Liu dr_io_unit_t *ip = (dr_io_unit_t *)devlist[d]; 198*a3114836SGerry Liu 199*a3114836SGerry Liu if ((hp->h_err = drmach_io_pre_release( 200*a3114836SGerry Liu ip->sbi_cm.sbdev_id)) != 0) { 201*a3114836SGerry Liu return (-1); 202*a3114836SGerry Liu } 203*a3114836SGerry Liu } 204*a3114836SGerry Liu 205*a3114836SGerry Liu for (d = 0; d < devnum; d++) { 206*a3114836SGerry Liu dr_io_unit_t *ip = (dr_io_unit_t *)devlist[d]; 207*a3114836SGerry Liu sbd_error_t *err; 208*a3114836SGerry Liu 209*a3114836SGerry Liu err = drmach_release(ip->sbi_cm.sbdev_id); 210*a3114836SGerry Liu if (err) { 211*a3114836SGerry Liu DRERR_SET_C(&ip->sbi_cm.sbdev_error, 212*a3114836SGerry Liu &err); 213*a3114836SGerry Liu return (-1); 214*a3114836SGerry Liu } 215*a3114836SGerry Liu } 216*a3114836SGerry Liu 217*a3114836SGerry Liu /* fail if any I/O devices are still referenced */ 218*a3114836SGerry Liu if (dr_check_io_refs(hp, devlist, devnum) > 0) { 219*a3114836SGerry Liu PR_IO("%s: failed - I/O devices ref'd\n", f); 220*a3114836SGerry Liu 221*a3114836SGerry Liu /* recover before return error */ 222*a3114836SGerry Liu for (d = 0; d < devnum; d++) { 223*a3114836SGerry Liu dr_io_unit_t *ip = (dr_io_unit_t *)devlist[d]; 224*a3114836SGerry Liu sbd_error_t *err; 225*a3114836SGerry Liu err = drmach_io_unrelease(ip->sbi_cm.sbdev_id); 226*a3114836SGerry Liu if (err) { 227*a3114836SGerry Liu DRERR_SET_C(&ip->sbi_cm.sbdev_error, &err); 228*a3114836SGerry Liu return (-1); 229*a3114836SGerry Liu } 230*a3114836SGerry Liu } 231*a3114836SGerry Liu return (-1); 232*a3114836SGerry Liu } 233*a3114836SGerry Liu return (0); 234*a3114836SGerry Liu } 235*a3114836SGerry Liu 236*a3114836SGerry Liu /*ARGSUSED*/ 237*a3114836SGerry Liu int 238*a3114836SGerry Liu dr_pre_detach_io(dr_handle_t *hp, 239*a3114836SGerry Liu dr_common_unit_t **devlist, int devnum) 240*a3114836SGerry Liu { 241*a3114836SGerry Liu int d; 242*a3114836SGerry Liu 243*a3114836SGerry Liu ASSERT(devnum > 0); 244*a3114836SGerry Liu 245*a3114836SGerry Liu for (d = 0; d < devnum; d++) { 246*a3114836SGerry Liu dr_common_unit_t *cp = devlist[d]; 247*a3114836SGerry Liu 248*a3114836SGerry Liu cmn_err(CE_CONT, "OS unconfigure %s", cp->sbdev_path); 249*a3114836SGerry Liu } 250*a3114836SGerry Liu 251*a3114836SGerry Liu return (0); 252*a3114836SGerry Liu } 253*a3114836SGerry Liu 254*a3114836SGerry Liu /*ARGSUSED*/ 255*a3114836SGerry Liu int 256*a3114836SGerry Liu dr_post_detach_io(dr_handle_t *hp, dr_common_unit_t **devlist, int devnum) 257*a3114836SGerry Liu { 258*a3114836SGerry Liu register int i; 259*a3114836SGerry Liu int rv = 0; 260*a3114836SGerry Liu static fn_t f = "dr_post_detach_io"; 261*a3114836SGerry Liu 262*a3114836SGerry Liu ASSERT(devnum > 0); 263*a3114836SGerry Liu for (i = 0; i < devnum; i++) { 264*a3114836SGerry Liu dr_common_unit_t *cp = devlist[i]; 265*a3114836SGerry Liu if (cp->sbdev_error != NULL) { 266*a3114836SGerry Liu PR_IO("%s: Failed\n", f); 267*a3114836SGerry Liu rv = -1; 268*a3114836SGerry Liu break; 269*a3114836SGerry Liu } 270*a3114836SGerry Liu } 271*a3114836SGerry Liu return (rv); 272*a3114836SGerry Liu } 273*a3114836SGerry Liu 274*a3114836SGerry Liu static void 275*a3114836SGerry Liu dr_get_comp_cond(dr_io_unit_t *ip, dev_info_t *dip) 276*a3114836SGerry Liu { 277*a3114836SGerry Liu if (dip == NULL) { 278*a3114836SGerry Liu ip->sbi_cm.sbdev_cond = SBD_COND_UNKNOWN; 279*a3114836SGerry Liu return; 280*a3114836SGerry Liu } 281*a3114836SGerry Liu 282*a3114836SGerry Liu if (DEVI(dip)->devi_flags & DEVI_RETIRED) { 283*a3114836SGerry Liu ip->sbi_cm.sbdev_cond = SBD_COND_FAILED; 284*a3114836SGerry Liu return; 285*a3114836SGerry Liu } 286*a3114836SGerry Liu 287*a3114836SGerry Liu if (DR_DEV_IS_ATTACHED(&ip->sbi_cm)) { 288*a3114836SGerry Liu ip->sbi_cm.sbdev_cond = SBD_COND_OK; 289*a3114836SGerry Liu } else if (DR_DEV_IS_PRESENT(&ip->sbi_cm)) { 290*a3114836SGerry Liu ip->sbi_cm.sbdev_cond = SBD_COND_OK; 291*a3114836SGerry Liu } 292*a3114836SGerry Liu } 293*a3114836SGerry Liu 294*a3114836SGerry Liu int 295*a3114836SGerry Liu dr_io_status(dr_handle_t *hp, dr_devset_t devset, sbd_dev_stat_t *dsp) 296*a3114836SGerry Liu { 297*a3114836SGerry Liu int i, ix; 298*a3114836SGerry Liu dr_board_t *bp; 299*a3114836SGerry Liu sbd_io_stat_t *isp; 300*a3114836SGerry Liu dr_io_unit_t *ip; 301*a3114836SGerry Liu 302*a3114836SGerry Liu bp = hp->h_bd; 303*a3114836SGerry Liu 304*a3114836SGerry Liu /* 305*a3114836SGerry Liu * Only look for requested devices that are actually present. 306*a3114836SGerry Liu */ 307*a3114836SGerry Liu devset &= DR_DEVS_PRESENT(bp); 308*a3114836SGerry Liu 309*a3114836SGerry Liu for (i = ix = 0; i < MAX_IO_UNITS_PER_BOARD; i++) { 310*a3114836SGerry Liu drmachid_t id; 311*a3114836SGerry Liu dev_info_t *dip; 312*a3114836SGerry Liu sbd_error_t *err; 313*a3114836SGerry Liu drmach_status_t pstat; 314*a3114836SGerry Liu 315*a3114836SGerry Liu if (DEVSET_IN_SET(devset, SBD_COMP_IO, i) == 0) 316*a3114836SGerry Liu continue; 317*a3114836SGerry Liu 318*a3114836SGerry Liu ip = dr_get_io_unit(bp, i); 319*a3114836SGerry Liu 320*a3114836SGerry Liu if (ip->sbi_cm.sbdev_state == DR_STATE_EMPTY) { 321*a3114836SGerry Liu /* present, but not fully initialized */ 322*a3114836SGerry Liu continue; 323*a3114836SGerry Liu } 324*a3114836SGerry Liu 325*a3114836SGerry Liu id = ip->sbi_cm.sbdev_id; 326*a3114836SGerry Liu if (id == (drmachid_t)0) 327*a3114836SGerry Liu continue; 328*a3114836SGerry Liu 329*a3114836SGerry Liu err = drmach_status(ip->sbi_cm.sbdev_id, &pstat); 330*a3114836SGerry Liu if (err) { 331*a3114836SGerry Liu DRERR_SET_C(&ip->sbi_cm.sbdev_error, &err); 332*a3114836SGerry Liu return (-1); 333*a3114836SGerry Liu } 334*a3114836SGerry Liu 335*a3114836SGerry Liu dip = NULL; 336*a3114836SGerry Liu err = drmach_get_dip(id, &dip); 337*a3114836SGerry Liu if (err) { 338*a3114836SGerry Liu /* catch this in debug kernels */ 339*a3114836SGerry Liu ASSERT(0); 340*a3114836SGerry Liu 341*a3114836SGerry Liu sbd_err_clear(&err); 342*a3114836SGerry Liu continue; 343*a3114836SGerry Liu } 344*a3114836SGerry Liu 345*a3114836SGerry Liu isp = &dsp->d_io; 346*a3114836SGerry Liu bzero((caddr_t)isp, sizeof (*isp)); 347*a3114836SGerry Liu 348*a3114836SGerry Liu isp->is_cm.c_id.c_type = ip->sbi_cm.sbdev_type; 349*a3114836SGerry Liu isp->is_cm.c_id.c_unit = ip->sbi_cm.sbdev_unum; 350*a3114836SGerry Liu (void) strlcpy(isp->is_cm.c_id.c_name, pstat.type, 351*a3114836SGerry Liu sizeof (isp->is_cm.c_id.c_name)); 352*a3114836SGerry Liu 353*a3114836SGerry Liu dr_get_comp_cond(ip, dip); 354*a3114836SGerry Liu isp->is_cm.c_cond = ip->sbi_cm.sbdev_cond; 355*a3114836SGerry Liu isp->is_cm.c_busy = ip->sbi_cm.sbdev_busy | pstat.busy; 356*a3114836SGerry Liu isp->is_cm.c_time = ip->sbi_cm.sbdev_time; 357*a3114836SGerry Liu isp->is_cm.c_ostate = ip->sbi_cm.sbdev_ostate; 358*a3114836SGerry Liu isp->is_cm.c_sflags = 0; 359*a3114836SGerry Liu 360*a3114836SGerry Liu if (dip == NULL) { 361*a3114836SGerry Liu isp->is_pathname[0] = '\0'; 362*a3114836SGerry Liu isp->is_referenced = 0; 363*a3114836SGerry Liu isp->is_unsafe_count = 0; 364*a3114836SGerry Liu } else { 365*a3114836SGerry Liu int refcount = 0, idx = 0; 366*a3114836SGerry Liu uint64_t unsafe_devs[SBD_MAX_UNSAFE]; 367*a3114836SGerry Liu 368*a3114836SGerry Liu ASSERT(e_ddi_branch_held(dip)); 369*a3114836SGerry Liu (void) ddi_pathname(dip, isp->is_pathname); 370*a3114836SGerry Liu 371*a3114836SGerry Liu /* check reference and unsafe counts on devices */ 372*a3114836SGerry Liu isp->is_unsafe_count = 0; 373*a3114836SGerry Liu dr_check_devices(dip, &refcount, hp, unsafe_devs, 374*a3114836SGerry Liu &idx, SBD_MAX_UNSAFE, NULL); 375*a3114836SGerry Liu while (idx > 0) { 376*a3114836SGerry Liu isp->is_unsafe_list[idx-1] = unsafe_devs[idx-1]; 377*a3114836SGerry Liu --idx; 378*a3114836SGerry Liu } 379*a3114836SGerry Liu 380*a3114836SGerry Liu isp->is_referenced = (refcount == 0) ? 0 : 1; 381*a3114836SGerry Liu 382*a3114836SGerry Liu hp->h_err = NULL; 383*a3114836SGerry Liu } 384*a3114836SGerry Liu ix++; 385*a3114836SGerry Liu dsp++; 386*a3114836SGerry Liu } 387*a3114836SGerry Liu 388*a3114836SGerry Liu return (ix); 389*a3114836SGerry Liu } 390