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 2003 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 #include "mhd_local.h" 30*0Sstevel@tonic-gate 31*0Sstevel@tonic-gate #include <ftw.h> 32*0Sstevel@tonic-gate #include <libgen.h> 33*0Sstevel@tonic-gate #include <sys/mhd.h> 34*0Sstevel@tonic-gate #include <sys/scsi/impl/uscsi.h> 35*0Sstevel@tonic-gate #include <sys/scsi/generic/commands.h> 36*0Sstevel@tonic-gate #include <sys/scsi/generic/inquiry.h> 37*0Sstevel@tonic-gate 38*0Sstevel@tonic-gate /* 39*0Sstevel@tonic-gate * manipulate drives 40*0Sstevel@tonic-gate */ 41*0Sstevel@tonic-gate 42*0Sstevel@tonic-gate /* 43*0Sstevel@tonic-gate * null list constant 44*0Sstevel@tonic-gate */ 45*0Sstevel@tonic-gate const mhd_drive_list_t mhd_null_list = MHD_NULL_LIST; 46*0Sstevel@tonic-gate 47*0Sstevel@tonic-gate /* 48*0Sstevel@tonic-gate * add drive to list 49*0Sstevel@tonic-gate */ 50*0Sstevel@tonic-gate void 51*0Sstevel@tonic-gate mhd_add_drive( 52*0Sstevel@tonic-gate mhd_drive_list_t *dlp, 53*0Sstevel@tonic-gate mhd_drive_t *dp 54*0Sstevel@tonic-gate ) 55*0Sstevel@tonic-gate { 56*0Sstevel@tonic-gate /* add drive to list */ 57*0Sstevel@tonic-gate if (dlp->dl_ndrive >= dlp->dl_alloc) { 58*0Sstevel@tonic-gate dlp->dl_alloc += 10; 59*0Sstevel@tonic-gate dlp->dl_drives = Realloc(dlp->dl_drives, 60*0Sstevel@tonic-gate (dlp->dl_alloc * sizeof (*dlp->dl_drives))); 61*0Sstevel@tonic-gate } 62*0Sstevel@tonic-gate dlp->dl_drives[dlp->dl_ndrive++] = dp; 63*0Sstevel@tonic-gate } 64*0Sstevel@tonic-gate 65*0Sstevel@tonic-gate /* 66*0Sstevel@tonic-gate * delete drive from list 67*0Sstevel@tonic-gate */ 68*0Sstevel@tonic-gate void 69*0Sstevel@tonic-gate mhd_del_drive( 70*0Sstevel@tonic-gate mhd_drive_list_t *dlp, 71*0Sstevel@tonic-gate mhd_drive_t *dp 72*0Sstevel@tonic-gate ) 73*0Sstevel@tonic-gate { 74*0Sstevel@tonic-gate uint_t i; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate /* delete drive from list */ 77*0Sstevel@tonic-gate for (i = 0; (i < dlp->dl_ndrive); ++i) { 78*0Sstevel@tonic-gate if (dlp->dl_drives[i] == dp) 79*0Sstevel@tonic-gate break; 80*0Sstevel@tonic-gate } 81*0Sstevel@tonic-gate assert(dlp->dl_drives[i] == dp); 82*0Sstevel@tonic-gate for (/* void */; (i < dlp->dl_ndrive); ++i) 83*0Sstevel@tonic-gate dlp->dl_drives[i] = dlp->dl_drives[i + 1]; 84*0Sstevel@tonic-gate dlp->dl_ndrive--; 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate /* 88*0Sstevel@tonic-gate * free drive list 89*0Sstevel@tonic-gate */ 90*0Sstevel@tonic-gate void 91*0Sstevel@tonic-gate mhd_free_list( 92*0Sstevel@tonic-gate mhd_drive_list_t *dlp 93*0Sstevel@tonic-gate ) 94*0Sstevel@tonic-gate { 95*0Sstevel@tonic-gate if (dlp->dl_drives != NULL) 96*0Sstevel@tonic-gate Free(dlp->dl_drives); 97*0Sstevel@tonic-gate (void) memset(dlp, 0, sizeof (*dlp)); 98*0Sstevel@tonic-gate } 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate /* 101*0Sstevel@tonic-gate * manipulate drive state 102*0Sstevel@tonic-gate */ 103*0Sstevel@tonic-gate int 104*0Sstevel@tonic-gate mhd_state( 105*0Sstevel@tonic-gate mhd_drive_t *dp, 106*0Sstevel@tonic-gate mhd_state_t new_state, 107*0Sstevel@tonic-gate mhd_error_t *mhep 108*0Sstevel@tonic-gate ) 109*0Sstevel@tonic-gate { 110*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 111*0Sstevel@tonic-gate mhd_state_t old_state = dp->dr_state; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate /* check lock */ 114*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 115*0Sstevel@tonic-gate 116*0Sstevel@tonic-gate /* set state and kick thread */ 117*0Sstevel@tonic-gate MHDPRINTF2(("%s: state 0x%x now 0x%x\n", 118*0Sstevel@tonic-gate dp->dr_rname, dp->dr_state, new_state)); 119*0Sstevel@tonic-gate dp->dr_state = new_state; 120*0Sstevel@tonic-gate mhd_cv_broadcast(&dp->dr_cv); 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate /* if this is the last PROBING drive, disable any failfast */ 123*0Sstevel@tonic-gate if ((old_state & DRIVE_PROBING) && (! (new_state & DRIVE_PROBING))) { 124*0Sstevel@tonic-gate mhd_drive_list_t *dlp = &sp->sr_drives; 125*0Sstevel@tonic-gate uint_t cnt, i; 126*0Sstevel@tonic-gate 127*0Sstevel@tonic-gate for (cnt = 0, i = 0; (i < dlp->dl_ndrive); ++i) { 128*0Sstevel@tonic-gate if (dlp->dl_drives[i]->dr_state & DRIVE_PROBING) 129*0Sstevel@tonic-gate ++cnt; 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate if (cnt == 0) { 132*0Sstevel@tonic-gate mhd_error_t status = mhd_null_error; 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate if (mhep == NULL) 135*0Sstevel@tonic-gate mhep = &status; 136*0Sstevel@tonic-gate if (mhd_ff_disarm(sp, mhep) != 0) { 137*0Sstevel@tonic-gate if (mhep == &status) { 138*0Sstevel@tonic-gate mhde_perror(mhep, dp->dr_rname); 139*0Sstevel@tonic-gate mhd_clrerror(mhep); 140*0Sstevel@tonic-gate } 141*0Sstevel@tonic-gate return (-1); 142*0Sstevel@tonic-gate } 143*0Sstevel@tonic-gate } 144*0Sstevel@tonic-gate } 145*0Sstevel@tonic-gate 146*0Sstevel@tonic-gate /* return success */ 147*0Sstevel@tonic-gate return (0); 148*0Sstevel@tonic-gate } 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate int 151*0Sstevel@tonic-gate mhd_state_set( 152*0Sstevel@tonic-gate mhd_drive_t *dp, 153*0Sstevel@tonic-gate mhd_state_t new_state, 154*0Sstevel@tonic-gate mhd_error_t *mhep 155*0Sstevel@tonic-gate ) 156*0Sstevel@tonic-gate { 157*0Sstevel@tonic-gate return (mhd_state(dp, (dp->dr_state | new_state), mhep)); 158*0Sstevel@tonic-gate } 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate static int 161*0Sstevel@tonic-gate mhd_state_clr( 162*0Sstevel@tonic-gate mhd_drive_t *dp, 163*0Sstevel@tonic-gate mhd_state_t new_state, 164*0Sstevel@tonic-gate mhd_error_t *mhep 165*0Sstevel@tonic-gate ) 166*0Sstevel@tonic-gate { 167*0Sstevel@tonic-gate return (mhd_state(dp, (dp->dr_state & ~new_state), mhep)); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate /* 171*0Sstevel@tonic-gate * idle a drive 172*0Sstevel@tonic-gate */ 173*0Sstevel@tonic-gate int 174*0Sstevel@tonic-gate mhd_idle( 175*0Sstevel@tonic-gate mhd_drive_t *dp, 176*0Sstevel@tonic-gate mhd_error_t *mhep 177*0Sstevel@tonic-gate ) 178*0Sstevel@tonic-gate { 179*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 180*0Sstevel@tonic-gate 181*0Sstevel@tonic-gate /* check lock */ 182*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gate /* wait for thread to idle */ 185*0Sstevel@tonic-gate for (;;) { 186*0Sstevel@tonic-gate if (DRIVE_IS_IDLE(dp)) 187*0Sstevel@tonic-gate return (0); 188*0Sstevel@tonic-gate if (mhd_state(dp, DRIVE_IDLING, mhep) != 0) 189*0Sstevel@tonic-gate return (-1); 190*0Sstevel@tonic-gate (void) mhd_cv_wait(&sp->sr_cv, &sp->sr_mx); 191*0Sstevel@tonic-gate } 192*0Sstevel@tonic-gate } 193*0Sstevel@tonic-gate 194*0Sstevel@tonic-gate /* 195*0Sstevel@tonic-gate * reserve the drive 196*0Sstevel@tonic-gate */ 197*0Sstevel@tonic-gate static int 198*0Sstevel@tonic-gate mhd_reserve( 199*0Sstevel@tonic-gate mhd_drive_t *dp 200*0Sstevel@tonic-gate ) 201*0Sstevel@tonic-gate { 202*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 203*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 204*0Sstevel@tonic-gate mhd_mhioctkown_t *tkp = &sp->sr_timeouts.mh_tk; 205*0Sstevel@tonic-gate struct mhioctkown tkown; 206*0Sstevel@tonic-gate int err; 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gate /* check locks */ 209*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 210*0Sstevel@tonic-gate assert(dp->dr_fd >= 0); 211*0Sstevel@tonic-gate assert(dp->dr_state == DRIVE_RESERVING); 212*0Sstevel@tonic-gate 213*0Sstevel@tonic-gate /* setup timeouts */ 214*0Sstevel@tonic-gate (void) memset(&tkown, 0, sizeof (tkown)); 215*0Sstevel@tonic-gate tkown.reinstate_resv_delay = tkp->reinstate_resv_delay; 216*0Sstevel@tonic-gate tkown.min_ownership_delay = tkp->min_ownership_delay; 217*0Sstevel@tonic-gate tkown.max_ownership_delay = tkp->max_ownership_delay; 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate /* reserve drive */ 220*0Sstevel@tonic-gate if (! serial) 221*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 222*0Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCTKOWN, &tkown); 223*0Sstevel@tonic-gate if (! serial) 224*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 225*0Sstevel@tonic-gate if (err != 0) { 226*0Sstevel@tonic-gate mhd_perror("%s: MHIOCTKOWN", dp->dr_rname); 227*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL); 228*0Sstevel@tonic-gate dp->dr_errnum = errno; 229*0Sstevel@tonic-gate return (-1); 230*0Sstevel@tonic-gate } 231*0Sstevel@tonic-gate 232*0Sstevel@tonic-gate /* return success */ 233*0Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCTKOWN: succeeded\n", dp->dr_rname)); 234*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL); 235*0Sstevel@tonic-gate return (0); 236*0Sstevel@tonic-gate } 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gate /* 239*0Sstevel@tonic-gate * failfast the drive 240*0Sstevel@tonic-gate */ 241*0Sstevel@tonic-gate static int 242*0Sstevel@tonic-gate mhd_failfast( 243*0Sstevel@tonic-gate mhd_drive_t *dp 244*0Sstevel@tonic-gate ) 245*0Sstevel@tonic-gate { 246*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 247*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 248*0Sstevel@tonic-gate int ff = sp->sr_timeouts.mh_ff; 249*0Sstevel@tonic-gate char *release = ((ff == 0) ? " (release)" : ""); 250*0Sstevel@tonic-gate int err; 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate /* check locks */ 253*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 254*0Sstevel@tonic-gate assert(dp->dr_fd >= 0); 255*0Sstevel@tonic-gate assert(dp->dr_state == DRIVE_FAILFASTING); 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate /* failfast drive */ 258*0Sstevel@tonic-gate if (! serial) 259*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 260*0Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCENFAILFAST, &ff); 261*0Sstevel@tonic-gate if (! serial) 262*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 263*0Sstevel@tonic-gate if (err != 0) { 264*0Sstevel@tonic-gate mhd_perror("%s: MHIOCENFAILFAST%s", dp->dr_rname, release); 265*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL); 266*0Sstevel@tonic-gate dp->dr_errnum = errno; 267*0Sstevel@tonic-gate return (-1); 268*0Sstevel@tonic-gate } 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate /* return success */ 271*0Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCENFAILFAST%s: succeeded\n", 272*0Sstevel@tonic-gate dp->dr_rname, release)); 273*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL); 274*0Sstevel@tonic-gate return (0); 275*0Sstevel@tonic-gate } 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate /* 278*0Sstevel@tonic-gate * release the drive 279*0Sstevel@tonic-gate */ 280*0Sstevel@tonic-gate static int 281*0Sstevel@tonic-gate mhd_release( 282*0Sstevel@tonic-gate mhd_drive_t *dp 283*0Sstevel@tonic-gate ) 284*0Sstevel@tonic-gate { 285*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 286*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 287*0Sstevel@tonic-gate int ff = 0; /* disable failfast */ 288*0Sstevel@tonic-gate int err; 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate /* check locks */ 291*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 292*0Sstevel@tonic-gate assert(dp->dr_fd >= 0); 293*0Sstevel@tonic-gate assert(dp->dr_state == DRIVE_RELEASING); 294*0Sstevel@tonic-gate 295*0Sstevel@tonic-gate /* disable failfast */ 296*0Sstevel@tonic-gate if (! serial) 297*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 298*0Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCENFAILFAST, &ff); 299*0Sstevel@tonic-gate if (! serial) 300*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 301*0Sstevel@tonic-gate if (err != 0) { 302*0Sstevel@tonic-gate mhd_perror("%s: MHIOCENFAILFAST (release)", dp->dr_rname); 303*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL); 304*0Sstevel@tonic-gate dp->dr_errnum = errno; 305*0Sstevel@tonic-gate return (-1); 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCENFAILFAST (release): succeeded\n", 308*0Sstevel@tonic-gate dp->dr_rname)); 309*0Sstevel@tonic-gate 310*0Sstevel@tonic-gate /* release drive */ 311*0Sstevel@tonic-gate if (! serial) 312*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 313*0Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCRELEASE, NULL); 314*0Sstevel@tonic-gate if (! serial) 315*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 316*0Sstevel@tonic-gate if (err != 0) { 317*0Sstevel@tonic-gate mhd_perror("%s: MHIOCRELEASE", dp->dr_rname); 318*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL); 319*0Sstevel@tonic-gate dp->dr_errnum = errno; 320*0Sstevel@tonic-gate return (-1); 321*0Sstevel@tonic-gate } 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gate /* return success */ 324*0Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCRELEASE: succeeded\n", dp->dr_rname)); 325*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL); 326*0Sstevel@tonic-gate return (0); 327*0Sstevel@tonic-gate } 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate /* 330*0Sstevel@tonic-gate * probe the drive 331*0Sstevel@tonic-gate */ 332*0Sstevel@tonic-gate static int 333*0Sstevel@tonic-gate mhd_probe( 334*0Sstevel@tonic-gate mhd_drive_t *dp 335*0Sstevel@tonic-gate ) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 338*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 339*0Sstevel@tonic-gate int err; 340*0Sstevel@tonic-gate mhd_msec_t now; 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* check locks */ 343*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 344*0Sstevel@tonic-gate assert(dp->dr_fd >= 0); 345*0Sstevel@tonic-gate assert(dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING)); 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gate /* get status (we may get dumped from PROBING here) */ 348*0Sstevel@tonic-gate if (! serial) 349*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 350*0Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCSTATUS, NULL); 351*0Sstevel@tonic-gate now = mhd_time(); 352*0Sstevel@tonic-gate if (! serial) 353*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 354*0Sstevel@tonic-gate if (! (dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING))) 355*0Sstevel@tonic-gate return (0); 356*0Sstevel@tonic-gate 357*0Sstevel@tonic-gate /* update status */ 358*0Sstevel@tonic-gate if (dp->dr_state & DRIVE_STATUSING) { 359*0Sstevel@tonic-gate if (err == 1) { 360*0Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCSTATUS: reserved\n", 361*0Sstevel@tonic-gate dp->dr_rname)); 362*0Sstevel@tonic-gate dp->dr_errnum = MHD_E_RESERVED; 363*0Sstevel@tonic-gate } else if (err != 0) { 364*0Sstevel@tonic-gate mhd_perror("%s: MHIOCSTATUS", dp->dr_rname); 365*0Sstevel@tonic-gate dp->dr_errnum = errno; 366*0Sstevel@tonic-gate } else { 367*0Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCSTATUS: available\n", 368*0Sstevel@tonic-gate dp->dr_rname)); 369*0Sstevel@tonic-gate dp->dr_errnum = 0; 370*0Sstevel@tonic-gate } 371*0Sstevel@tonic-gate (void) mhd_state_clr(dp, DRIVE_STATUSING, NULL); 372*0Sstevel@tonic-gate } 373*0Sstevel@tonic-gate 374*0Sstevel@tonic-gate /* update time or die */ 375*0Sstevel@tonic-gate if (dp->dr_state & DRIVE_PROBING) { 376*0Sstevel@tonic-gate /* check our drive */ 377*0Sstevel@tonic-gate if (err == 0) { 378*0Sstevel@tonic-gate dp->dr_time = now; 379*0Sstevel@tonic-gate } else if (err == 1) { 380*0Sstevel@tonic-gate mhd_eprintf("%s: %s: reservation conflict\n", 381*0Sstevel@tonic-gate sp->sr_name, dp->dr_rname); 382*0Sstevel@tonic-gate mhd_ff_die(sp); 383*0Sstevel@tonic-gate } 384*0Sstevel@tonic-gate 385*0Sstevel@tonic-gate /* check other drives */ 386*0Sstevel@tonic-gate mhd_ff_check(sp); 387*0Sstevel@tonic-gate } 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate /* return success */ 390*0Sstevel@tonic-gate return (0); 391*0Sstevel@tonic-gate } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate /* 394*0Sstevel@tonic-gate * cached controller map 395*0Sstevel@tonic-gate */ 396*0Sstevel@tonic-gate typedef struct { 397*0Sstevel@tonic-gate char *regexpr1; 398*0Sstevel@tonic-gate uint_t tray; 399*0Sstevel@tonic-gate uint_t bus; 400*0Sstevel@tonic-gate char *regexpr2; 401*0Sstevel@tonic-gate char *scan; 402*0Sstevel@tonic-gate } mhd_ctlrmap_t; 403*0Sstevel@tonic-gate 404*0Sstevel@tonic-gate static rwlock_t ctlr_rw = DEFAULTRWLOCK; 405*0Sstevel@tonic-gate static time_t ctlr_mtime = 0; 406*0Sstevel@tonic-gate static size_t ctlr_num = 0; 407*0Sstevel@tonic-gate static mhd_ctlrmap_t *ctlr_map = NULL; 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate /* 410*0Sstevel@tonic-gate * free up controller map 411*0Sstevel@tonic-gate */ 412*0Sstevel@tonic-gate static void 413*0Sstevel@tonic-gate free_map() 414*0Sstevel@tonic-gate { 415*0Sstevel@tonic-gate size_t i; 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate assert(RW_WRITE_HELD(&ctlr_rw)); 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate for (i = 0; (i < ctlr_num); ++i) { 420*0Sstevel@tonic-gate mhd_ctlrmap_t *cmp = &ctlr_map[i]; 421*0Sstevel@tonic-gate 422*0Sstevel@tonic-gate if (cmp->regexpr1 != NULL) 423*0Sstevel@tonic-gate Free(cmp->regexpr1); 424*0Sstevel@tonic-gate if (cmp->regexpr2 != NULL) 425*0Sstevel@tonic-gate Free(cmp->regexpr2); 426*0Sstevel@tonic-gate if (cmp->scan != NULL) 427*0Sstevel@tonic-gate Free(cmp->scan); 428*0Sstevel@tonic-gate } 429*0Sstevel@tonic-gate if (ctlr_map != NULL) 430*0Sstevel@tonic-gate Free(ctlr_map); 431*0Sstevel@tonic-gate ctlr_num = 0; 432*0Sstevel@tonic-gate ctlr_map = NULL; 433*0Sstevel@tonic-gate } 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate /* 436*0Sstevel@tonic-gate * unlock controller map 437*0Sstevel@tonic-gate */ 438*0Sstevel@tonic-gate static void 439*0Sstevel@tonic-gate unlock_map() 440*0Sstevel@tonic-gate { 441*0Sstevel@tonic-gate assert(RW_WRITE_HELD(&ctlr_rw) | RW_READ_HELD(&ctlr_rw)); 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate mhd_rw_unlock(&ctlr_rw); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate /* 447*0Sstevel@tonic-gate * update controller map and lock it 448*0Sstevel@tonic-gate */ 449*0Sstevel@tonic-gate static int 450*0Sstevel@tonic-gate update_map() 451*0Sstevel@tonic-gate { 452*0Sstevel@tonic-gate struct stat statbuf; 453*0Sstevel@tonic-gate FILE *fp; 454*0Sstevel@tonic-gate char line[256], expr1[256], expr2[256], scan[256]; 455*0Sstevel@tonic-gate unsigned tray, bus; 456*0Sstevel@tonic-gate int rval = -1; 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate /* see if map file has changed */ 459*0Sstevel@tonic-gate mhd_rw_rdlock(&ctlr_rw); 460*0Sstevel@tonic-gate if (stat(METACTLRMAP, &statbuf) != 0) { 461*0Sstevel@tonic-gate mhd_perror(METACTLRMAP); 462*0Sstevel@tonic-gate goto out; 463*0Sstevel@tonic-gate } 464*0Sstevel@tonic-gate if (statbuf.st_mtime == ctlr_mtime) { 465*0Sstevel@tonic-gate rval = 0; 466*0Sstevel@tonic-gate goto out; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate 469*0Sstevel@tonic-gate /* trade up to writer lock, check again */ 470*0Sstevel@tonic-gate mhd_rw_unlock(&ctlr_rw); 471*0Sstevel@tonic-gate mhd_rw_wrlock(&ctlr_rw); 472*0Sstevel@tonic-gate if (statbuf.st_mtime == ctlr_mtime) { 473*0Sstevel@tonic-gate rval = 0; 474*0Sstevel@tonic-gate goto out; 475*0Sstevel@tonic-gate } 476*0Sstevel@tonic-gate if (ctlr_mtime != 0) 477*0Sstevel@tonic-gate mhd_eprintf("updating controller map\n"); 478*0Sstevel@tonic-gate ctlr_mtime = statbuf.st_mtime; 479*0Sstevel@tonic-gate 480*0Sstevel@tonic-gate /* toss existing cache */ 481*0Sstevel@tonic-gate free_map(); 482*0Sstevel@tonic-gate 483*0Sstevel@tonic-gate /* parse md.ctlrmap */ 484*0Sstevel@tonic-gate if ((fp = fopen(METACTLRMAP, "r")) == NULL) { 485*0Sstevel@tonic-gate mhd_perror(METACTLRMAP); 486*0Sstevel@tonic-gate goto out; 487*0Sstevel@tonic-gate } 488*0Sstevel@tonic-gate clearerr(fp); 489*0Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) { 490*0Sstevel@tonic-gate char *regexpr1 = NULL; 491*0Sstevel@tonic-gate char *regexpr2 = NULL; 492*0Sstevel@tonic-gate mhd_ctlrmap_t *cmp; 493*0Sstevel@tonic-gate 494*0Sstevel@tonic-gate /* skip blank lines and comments */ 495*0Sstevel@tonic-gate if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '#')) 496*0Sstevel@tonic-gate continue; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate /* parse line */ 499*0Sstevel@tonic-gate if (((sscanf(line, "\"%[^\"]\" %u %u \"%[^\"]\" \"%[^\"]\"", 500*0Sstevel@tonic-gate expr1, &tray, &bus, expr2, scan)) != 5) || 501*0Sstevel@tonic-gate ((regexpr1 = regcmp(expr1, 0)) == NULL) || 502*0Sstevel@tonic-gate ((regexpr2 = regcmp(expr2, 0)) == NULL)) { 503*0Sstevel@tonic-gate mhd_eprintf("%s: bad regex(es) '%s'\n", 504*0Sstevel@tonic-gate METACTLRMAP, line); 505*0Sstevel@tonic-gate if (regexpr1 != NULL) 506*0Sstevel@tonic-gate Free(regexpr1); 507*0Sstevel@tonic-gate if (regexpr2 != NULL) 508*0Sstevel@tonic-gate Free(regexpr2); 509*0Sstevel@tonic-gate continue; 510*0Sstevel@tonic-gate } 511*0Sstevel@tonic-gate 512*0Sstevel@tonic-gate /* add to cache */ 513*0Sstevel@tonic-gate ctlr_map = Realloc(ctlr_map, 514*0Sstevel@tonic-gate ((ctlr_num + 1) * sizeof (*ctlr_map))); 515*0Sstevel@tonic-gate cmp = &ctlr_map[ctlr_num++]; 516*0Sstevel@tonic-gate cmp->regexpr1 = regexpr1; 517*0Sstevel@tonic-gate cmp->tray = tray; 518*0Sstevel@tonic-gate cmp->bus = bus; 519*0Sstevel@tonic-gate cmp->regexpr2 = regexpr2; 520*0Sstevel@tonic-gate cmp->scan = Strdup(scan); 521*0Sstevel@tonic-gate } 522*0Sstevel@tonic-gate if (ferror(fp)) { 523*0Sstevel@tonic-gate mhd_perror(METACTLRMAP); 524*0Sstevel@tonic-gate (void) fclose(fp); 525*0Sstevel@tonic-gate goto out; 526*0Sstevel@tonic-gate } 527*0Sstevel@tonic-gate if (fclose(fp) != 0) { 528*0Sstevel@tonic-gate mhd_perror(METACTLRMAP); 529*0Sstevel@tonic-gate goto out; 530*0Sstevel@tonic-gate } 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate /* success */ 533*0Sstevel@tonic-gate rval = 0; 534*0Sstevel@tonic-gate 535*0Sstevel@tonic-gate /* return success */ 536*0Sstevel@tonic-gate out: 537*0Sstevel@tonic-gate if (rval != 0) { 538*0Sstevel@tonic-gate mhd_rw_unlock(&ctlr_rw); 539*0Sstevel@tonic-gate return (-1); 540*0Sstevel@tonic-gate } 541*0Sstevel@tonic-gate return (0); 542*0Sstevel@tonic-gate } 543*0Sstevel@tonic-gate 544*0Sstevel@tonic-gate static char * 545*0Sstevel@tonic-gate get_pln_ctlr_name( 546*0Sstevel@tonic-gate char *path 547*0Sstevel@tonic-gate ) 548*0Sstevel@tonic-gate { 549*0Sstevel@tonic-gate char *devicesname, *p; 550*0Sstevel@tonic-gate char retval[MAXPATHLEN]; 551*0Sstevel@tonic-gate 552*0Sstevel@tonic-gate devicesname = Strdup(path); 553*0Sstevel@tonic-gate if ((p = strrchr(devicesname, '/')) == NULL) { 554*0Sstevel@tonic-gate Free(devicesname); 555*0Sstevel@tonic-gate return (NULL); 556*0Sstevel@tonic-gate } 557*0Sstevel@tonic-gate 558*0Sstevel@tonic-gate /* strip off the "ssd@..." portion of the devices name */ 559*0Sstevel@tonic-gate *p = '\0'; 560*0Sstevel@tonic-gate 561*0Sstevel@tonic-gate /* strip off the "../../" in front of "devices" */ 562*0Sstevel@tonic-gate if ((p = strstr(devicesname, "/devices/")) == NULL) { 563*0Sstevel@tonic-gate Free(devicesname); 564*0Sstevel@tonic-gate return (NULL); 565*0Sstevel@tonic-gate } 566*0Sstevel@tonic-gate 567*0Sstevel@tonic-gate (void) snprintf(retval, sizeof (retval), "%s:ctlr", p); 568*0Sstevel@tonic-gate Free(devicesname); 569*0Sstevel@tonic-gate return (Strdup(retval)); 570*0Sstevel@tonic-gate } 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate struct pln_cache { 573*0Sstevel@tonic-gate char *pln_name; 574*0Sstevel@tonic-gate enum mhd_ctlrtype_t ctype; 575*0Sstevel@tonic-gate struct pln_cache *next; 576*0Sstevel@tonic-gate }; 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate static struct pln_cache *pln_cache_anchor = NULL; 579*0Sstevel@tonic-gate static mutex_t mhd_pln_mx = DEFAULTMUTEX; 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate /* singled threaded by caller */ 582*0Sstevel@tonic-gate static void 583*0Sstevel@tonic-gate add_pln_cache( 584*0Sstevel@tonic-gate char *pln_name, 585*0Sstevel@tonic-gate enum mhd_ctlrtype_t ctype 586*0Sstevel@tonic-gate 587*0Sstevel@tonic-gate ) 588*0Sstevel@tonic-gate { 589*0Sstevel@tonic-gate struct pln_cache *p; 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate p = Malloc(sizeof (*p)); 592*0Sstevel@tonic-gate 593*0Sstevel@tonic-gate p->pln_name = pln_name; 594*0Sstevel@tonic-gate p->ctype = ctype; 595*0Sstevel@tonic-gate p->next = pln_cache_anchor; 596*0Sstevel@tonic-gate pln_cache_anchor = p; 597*0Sstevel@tonic-gate } 598*0Sstevel@tonic-gate 599*0Sstevel@tonic-gate /* singled threaded by caller */ 600*0Sstevel@tonic-gate static int 601*0Sstevel@tonic-gate find_pln_cache( 602*0Sstevel@tonic-gate char *pln_name, 603*0Sstevel@tonic-gate enum mhd_ctlrtype_t *ctype_ret 604*0Sstevel@tonic-gate ) 605*0Sstevel@tonic-gate { 606*0Sstevel@tonic-gate struct pln_cache *p; 607*0Sstevel@tonic-gate 608*0Sstevel@tonic-gate for (p = pln_cache_anchor; p != NULL; p = p->next) { 609*0Sstevel@tonic-gate if (strcmp(pln_name, p->pln_name) == 0) { 610*0Sstevel@tonic-gate *ctype_ret = p->ctype; 611*0Sstevel@tonic-gate return (1); 612*0Sstevel@tonic-gate } 613*0Sstevel@tonic-gate } 614*0Sstevel@tonic-gate return (0); 615*0Sstevel@tonic-gate } 616*0Sstevel@tonic-gate 617*0Sstevel@tonic-gate static void 618*0Sstevel@tonic-gate free_pln_cache(void) 619*0Sstevel@tonic-gate { 620*0Sstevel@tonic-gate struct pln_cache *p, *n = NULL; 621*0Sstevel@tonic-gate 622*0Sstevel@tonic-gate mutex_lock(&mhd_pln_mx); 623*0Sstevel@tonic-gate for (p = pln_cache_anchor; p != NULL; p = n) { 624*0Sstevel@tonic-gate n = p->next; 625*0Sstevel@tonic-gate Free(p->pln_name); 626*0Sstevel@tonic-gate Free(p); 627*0Sstevel@tonic-gate } 628*0Sstevel@tonic-gate 629*0Sstevel@tonic-gate pln_cache_anchor = NULL; 630*0Sstevel@tonic-gate mutex_unlock(&mhd_pln_mx); 631*0Sstevel@tonic-gate } 632*0Sstevel@tonic-gate 633*0Sstevel@tonic-gate /* 634*0Sstevel@tonic-gate * match on SSA Model 200. 635*0Sstevel@tonic-gate */ 636*0Sstevel@tonic-gate static void 637*0Sstevel@tonic-gate match_SSA200( 638*0Sstevel@tonic-gate mhd_drive_t *dp, 639*0Sstevel@tonic-gate char *path 640*0Sstevel@tonic-gate ) 641*0Sstevel@tonic-gate { 642*0Sstevel@tonic-gate mhd_cinfo_t *cinfop = &dp->dr_drive_id.did_cinfo; 643*0Sstevel@tonic-gate struct uscsi_cmd ucmd; 644*0Sstevel@tonic-gate union scsi_cdb cdb; 645*0Sstevel@tonic-gate struct scsi_inquiry inq; 646*0Sstevel@tonic-gate int fd; 647*0Sstevel@tonic-gate char *pln_ctlr_name; 648*0Sstevel@tonic-gate enum mhd_ctlrtype_t ctype; 649*0Sstevel@tonic-gate char *p; 650*0Sstevel@tonic-gate 651*0Sstevel@tonic-gate if ((pln_ctlr_name = get_pln_ctlr_name(path)) == NULL) 652*0Sstevel@tonic-gate return; 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate mutex_lock(&mhd_pln_mx); 655*0Sstevel@tonic-gate if (find_pln_cache(pln_ctlr_name, &ctype) == 1) { 656*0Sstevel@tonic-gate mutex_unlock(&mhd_pln_mx); 657*0Sstevel@tonic-gate if (ctype != MHD_CTLR_SSA200) 658*0Sstevel@tonic-gate return; 659*0Sstevel@tonic-gate 660*0Sstevel@tonic-gate /* over-ride for SSA200 */ 661*0Sstevel@tonic-gate cinfop->mhc_ctype = ctype; 662*0Sstevel@tonic-gate cinfop->mhc_tray = cinfop->mhc_bus; 663*0Sstevel@tonic-gate return; 664*0Sstevel@tonic-gate } 665*0Sstevel@tonic-gate 666*0Sstevel@tonic-gate if ((fd = open(pln_ctlr_name, (O_RDONLY|O_NDELAY), 0)) < 0) { 667*0Sstevel@tonic-gate mutex_unlock(&mhd_pln_mx); 668*0Sstevel@tonic-gate Free(pln_ctlr_name); 669*0Sstevel@tonic-gate return; 670*0Sstevel@tonic-gate } 671*0Sstevel@tonic-gate 672*0Sstevel@tonic-gate (void) memset(&ucmd, 0, sizeof (ucmd)); 673*0Sstevel@tonic-gate (void) memset(&cdb, 0, sizeof (cdb)); 674*0Sstevel@tonic-gate (void) memset(&inq, 0, sizeof (inq)); 675*0Sstevel@tonic-gate cdb.scc_cmd = SCMD_INQUIRY; 676*0Sstevel@tonic-gate cdb.g0_count0 = sizeof (inq); 677*0Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 678*0Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 679*0Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&inq; 680*0Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (inq); 681*0Sstevel@tonic-gate ucmd.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_DIAGNOSE; 682*0Sstevel@tonic-gate ucmd.uscsi_timeout = 30; 683*0Sstevel@tonic-gate if (ioctl(fd, USCSICMD, &ucmd)) { 684*0Sstevel@tonic-gate mutex_unlock(&mhd_pln_mx); 685*0Sstevel@tonic-gate (void) close(fd); 686*0Sstevel@tonic-gate MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n", 687*0Sstevel@tonic-gate pln_ctlr_name, errno)); 688*0Sstevel@tonic-gate Free(pln_ctlr_name); 689*0Sstevel@tonic-gate return; 690*0Sstevel@tonic-gate } 691*0Sstevel@tonic-gate 692*0Sstevel@tonic-gate (void) close(fd); 693*0Sstevel@tonic-gate MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n", pln_ctlr_name)); 694*0Sstevel@tonic-gate 695*0Sstevel@tonic-gate /* Make all trailing spaces be null char */ 696*0Sstevel@tonic-gate for (p = inq.inq_pid + sizeof (inq.inq_pid) - 1; p != inq.inq_pid; 697*0Sstevel@tonic-gate p--) { 698*0Sstevel@tonic-gate if (*p == '\0') 699*0Sstevel@tonic-gate continue; 700*0Sstevel@tonic-gate if (!isspace(*p)) 701*0Sstevel@tonic-gate break; 702*0Sstevel@tonic-gate *p = '\0'; 703*0Sstevel@tonic-gate } 704*0Sstevel@tonic-gate 705*0Sstevel@tonic-gate if (strncmp(inq.inq_pid, META_SSA200_PID, sizeof (inq.inq_pid)) != 0) 706*0Sstevel@tonic-gate goto out; 707*0Sstevel@tonic-gate 708*0Sstevel@tonic-gate /* over-ride the ctype, and tray */ 709*0Sstevel@tonic-gate cinfop->mhc_ctype = MHD_CTLR_SSA200; 710*0Sstevel@tonic-gate cinfop->mhc_tray = cinfop->mhc_bus; 711*0Sstevel@tonic-gate 712*0Sstevel@tonic-gate out: 713*0Sstevel@tonic-gate add_pln_cache(pln_ctlr_name, cinfop->mhc_ctype); 714*0Sstevel@tonic-gate mutex_unlock(&mhd_pln_mx); 715*0Sstevel@tonic-gate } 716*0Sstevel@tonic-gate 717*0Sstevel@tonic-gate /* 718*0Sstevel@tonic-gate * get controller info 719*0Sstevel@tonic-gate */ 720*0Sstevel@tonic-gate static void 721*0Sstevel@tonic-gate match_SSA100( 722*0Sstevel@tonic-gate mhd_drive_t *dp, 723*0Sstevel@tonic-gate char *path 724*0Sstevel@tonic-gate ) 725*0Sstevel@tonic-gate { 726*0Sstevel@tonic-gate mhd_cinfo_t *cinfop = &dp->dr_drive_id.did_cinfo; 727*0Sstevel@tonic-gate uint_t i; 728*0Sstevel@tonic-gate char *p; 729*0Sstevel@tonic-gate lloff_t wwn; 730*0Sstevel@tonic-gate const char *fmt; 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate /* update and lock controller map */ 733*0Sstevel@tonic-gate if (update_map() != 0) 734*0Sstevel@tonic-gate return; /* give up */ 735*0Sstevel@tonic-gate assert(RW_WRITE_HELD(&ctlr_rw) || RW_READ_HELD(&ctlr_rw)); 736*0Sstevel@tonic-gate 737*0Sstevel@tonic-gate /* look for match in cache */ 738*0Sstevel@tonic-gate for (i = 0; (i < ctlr_num); ++i) { 739*0Sstevel@tonic-gate mhd_ctlrmap_t *cmp = &ctlr_map[i]; 740*0Sstevel@tonic-gate 741*0Sstevel@tonic-gate fmt = cmp->scan; 742*0Sstevel@tonic-gate if ((regex(cmp->regexpr1, path) != NULL) && 743*0Sstevel@tonic-gate ((p = regex(cmp->regexpr2, path)) != NULL) && 744*0Sstevel@tonic-gate (sscanf(p, fmt, 745*0Sstevel@tonic-gate (ulong_t *)&wwn._p._u, (ulong_t *)&wwn._p._l) == 2)) { 746*0Sstevel@tonic-gate cinfop->mhc_ctype = MHD_CTLR_SSA100; 747*0Sstevel@tonic-gate cinfop->mhc_tray = cmp->tray; 748*0Sstevel@tonic-gate cinfop->mhc_bus = cmp->bus; 749*0Sstevel@tonic-gate cinfop->mhc_wwn = wwn._f; 750*0Sstevel@tonic-gate match_SSA200(dp, path); 751*0Sstevel@tonic-gate break; 752*0Sstevel@tonic-gate } 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate 755*0Sstevel@tonic-gate /* unlock controller map */ 756*0Sstevel@tonic-gate unlock_map(); 757*0Sstevel@tonic-gate } 758*0Sstevel@tonic-gate 759*0Sstevel@tonic-gate /* 760*0Sstevel@tonic-gate * get unique drive ID 761*0Sstevel@tonic-gate */ 762*0Sstevel@tonic-gate static int 763*0Sstevel@tonic-gate mhd_ident( 764*0Sstevel@tonic-gate mhd_drive_t *dp 765*0Sstevel@tonic-gate ) 766*0Sstevel@tonic-gate { 767*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 768*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 769*0Sstevel@tonic-gate struct uscsi_cmd ucmd; 770*0Sstevel@tonic-gate union scsi_cdb cdb; 771*0Sstevel@tonic-gate struct scsi_inquiry inq; 772*0Sstevel@tonic-gate struct vtoc vtoc_buf; 773*0Sstevel@tonic-gate char path[MAXPATHLEN + 1]; 774*0Sstevel@tonic-gate int len; 775*0Sstevel@tonic-gate int err; 776*0Sstevel@tonic-gate 777*0Sstevel@tonic-gate /* check locks */ 778*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 779*0Sstevel@tonic-gate assert(dp->dr_fd >= 0); 780*0Sstevel@tonic-gate assert(dp->dr_state & DRIVE_IDENTING); 781*0Sstevel@tonic-gate 782*0Sstevel@tonic-gate /* reset ID */ 783*0Sstevel@tonic-gate (void) memset(&dp->dr_drive_id, 0, sizeof (dp->dr_drive_id)); 784*0Sstevel@tonic-gate 785*0Sstevel@tonic-gate /* get serial number */ 786*0Sstevel@tonic-gate if (dp->dr_state & DRIVE_SERIALING) { 787*0Sstevel@tonic-gate if (! serial) 788*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 789*0Sstevel@tonic-gate (void) memset(&ucmd, 0, sizeof (ucmd)); 790*0Sstevel@tonic-gate (void) memset(&cdb, 0, sizeof (cdb)); 791*0Sstevel@tonic-gate (void) memset(&inq, 0, sizeof (inq)); 792*0Sstevel@tonic-gate cdb.scc_cmd = SCMD_INQUIRY; 793*0Sstevel@tonic-gate cdb.g0_count0 = sizeof (inq); 794*0Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb; 795*0Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0; 796*0Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&inq; 797*0Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (inq); 798*0Sstevel@tonic-gate ucmd.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_DIAGNOSE; 799*0Sstevel@tonic-gate ucmd.uscsi_timeout = 30; 800*0Sstevel@tonic-gate err = ioctl(dp->dr_fd, USCSICMD, &ucmd); 801*0Sstevel@tonic-gate if (! serial) 802*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 803*0Sstevel@tonic-gate if (err != 0) { 804*0Sstevel@tonic-gate MHDPRINTF(( 805*0Sstevel@tonic-gate "%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n", 806*0Sstevel@tonic-gate dp->dr_rname, errno)); 807*0Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_SERIAL; 808*0Sstevel@tonic-gate } else { 809*0Sstevel@tonic-gate char *p, *e; 810*0Sstevel@tonic-gate uint_t i; 811*0Sstevel@tonic-gate 812*0Sstevel@tonic-gate MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n", 813*0Sstevel@tonic-gate dp->dr_rname)); 814*0Sstevel@tonic-gate dp->dr_drive_id.did_flags |= MHD_DID_SERIAL; 815*0Sstevel@tonic-gate p = dp->dr_drive_id.did_serial; 816*0Sstevel@tonic-gate e = p + sizeof (dp->dr_drive_id.did_serial); 817*0Sstevel@tonic-gate for (i = 0; 818*0Sstevel@tonic-gate ((i < sizeof (inq.inq_vid)) && (p < e)); ++i) 819*0Sstevel@tonic-gate *p++ = inq.inq_vid[i]; 820*0Sstevel@tonic-gate for (i = 0; 821*0Sstevel@tonic-gate ((i < sizeof (inq.inq_pid)) && (p < e)); ++i) 822*0Sstevel@tonic-gate *p++ = inq.inq_pid[i]; 823*0Sstevel@tonic-gate for (i = 0; 824*0Sstevel@tonic-gate ((i < sizeof (inq.inq_revision)) && (p < e)); ++i) 825*0Sstevel@tonic-gate *p++ = inq.inq_revision[i]; 826*0Sstevel@tonic-gate for (i = 0; 827*0Sstevel@tonic-gate ((i < sizeof (inq.inq_serial)) && (p < e)); ++i) 828*0Sstevel@tonic-gate *p++ = inq.inq_serial[i]; 829*0Sstevel@tonic-gate assert(p == e); 830*0Sstevel@tonic-gate for (p = dp->dr_drive_id.did_serial; (p < e); ++p) { 831*0Sstevel@tonic-gate if (*p == '\0') 832*0Sstevel@tonic-gate *p = ' '; 833*0Sstevel@tonic-gate } 834*0Sstevel@tonic-gate } 835*0Sstevel@tonic-gate } else { 836*0Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_SERIAL; 837*0Sstevel@tonic-gate } 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /* get VTOC */ 840*0Sstevel@tonic-gate if (dp->dr_state & DRIVE_VTOCING) { 841*0Sstevel@tonic-gate if (! serial) 842*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 843*0Sstevel@tonic-gate (void) memset(&vtoc_buf, 0, sizeof (vtoc_buf)); 844*0Sstevel@tonic-gate err = read_vtoc(dp->dr_fd, &vtoc_buf); 845*0Sstevel@tonic-gate if (! serial) 846*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 847*0Sstevel@tonic-gate if (err < 0) { 848*0Sstevel@tonic-gate MHDPRINTF(("%s: read_vtoc: failed errno %d\n", 849*0Sstevel@tonic-gate dp->dr_rname, errno)); 850*0Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_TIME; 851*0Sstevel@tonic-gate } else { 852*0Sstevel@tonic-gate MHDPRINTF(("%s: read_vtoc: success\n", 853*0Sstevel@tonic-gate dp->dr_rname)); 854*0Sstevel@tonic-gate dp->dr_drive_id.did_flags |= MHD_DID_TIME; 855*0Sstevel@tonic-gate dp->dr_drive_id.did_time = vtoc_buf.timestamp[0]; 856*0Sstevel@tonic-gate } 857*0Sstevel@tonic-gate } else { 858*0Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_TIME; 859*0Sstevel@tonic-gate } 860*0Sstevel@tonic-gate 861*0Sstevel@tonic-gate /* get controller info */ 862*0Sstevel@tonic-gate if (dp->dr_state & DRIVE_CINFOING) { 863*0Sstevel@tonic-gate if (! serial) 864*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 865*0Sstevel@tonic-gate len = readlink(dp->dr_rname0, path, (sizeof (path) - 1)); 866*0Sstevel@tonic-gate if (! serial) 867*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 868*0Sstevel@tonic-gate if (len >= sizeof (path)) { 869*0Sstevel@tonic-gate len = -1; 870*0Sstevel@tonic-gate errno = ENAMETOOLONG; 871*0Sstevel@tonic-gate } 872*0Sstevel@tonic-gate if (len < 0) { 873*0Sstevel@tonic-gate MHDPRINTF(("%s: readlink: failed errno %d\n", 874*0Sstevel@tonic-gate dp->dr_rname0, errno)); 875*0Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_CINFO; 876*0Sstevel@tonic-gate } else { 877*0Sstevel@tonic-gate MHDPRINTF(("%s: readlink: success\n", 878*0Sstevel@tonic-gate dp->dr_rname0)); 879*0Sstevel@tonic-gate dp->dr_drive_id.did_flags |= MHD_DID_CINFO; 880*0Sstevel@tonic-gate (void) memset(&dp->dr_drive_id.did_cinfo, 0, 881*0Sstevel@tonic-gate sizeof (dp->dr_drive_id.did_cinfo)); 882*0Sstevel@tonic-gate match_SSA100(dp, path); 883*0Sstevel@tonic-gate } 884*0Sstevel@tonic-gate } else { 885*0Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_CINFO; 886*0Sstevel@tonic-gate } 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate /* return success */ 889*0Sstevel@tonic-gate (void) mhd_state_clr(dp, DRIVE_IDENTING, NULL); 890*0Sstevel@tonic-gate return (0); 891*0Sstevel@tonic-gate } 892*0Sstevel@tonic-gate 893*0Sstevel@tonic-gate /* 894*0Sstevel@tonic-gate * disk thread 895*0Sstevel@tonic-gate */ 896*0Sstevel@tonic-gate static void 897*0Sstevel@tonic-gate mhd_drive_thread( 898*0Sstevel@tonic-gate mhd_drive_t *dp 899*0Sstevel@tonic-gate ) 900*0Sstevel@tonic-gate { 901*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 902*0Sstevel@tonic-gate 903*0Sstevel@tonic-gate /* wait for dp->dr_thread to be filled in */ 904*0Sstevel@tonic-gate assert(sp != NULL); 905*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 906*0Sstevel@tonic-gate 907*0Sstevel@tonic-gate /* forever */ 908*0Sstevel@tonic-gate for (;;) { 909*0Sstevel@tonic-gate /* check locks */ 910*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 911*0Sstevel@tonic-gate assert(dp->dr_thread == thr_self()); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate /* check for changed set */ 914*0Sstevel@tonic-gate if (sp != dp->dr_sp) { 915*0Sstevel@tonic-gate MHDPRINTF2(("%s: changed from set '%s' to '%s'\n", 916*0Sstevel@tonic-gate dp->dr_rname, sp->sr_name, dp->dr_sp->sr_name)); 917*0Sstevel@tonic-gate 918*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 919*0Sstevel@tonic-gate sp = dp->dr_sp; 920*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 921*0Sstevel@tonic-gate } 922*0Sstevel@tonic-gate 923*0Sstevel@tonic-gate /* open drive, if necessary */ 924*0Sstevel@tonic-gate if ((dp->dr_fd < 0) && (! (DRIVE_IS_IDLE(dp) || 925*0Sstevel@tonic-gate (dp->dr_state == DRIVE_IDLING)))) { 926*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate if (! serial) 929*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 930*0Sstevel@tonic-gate dp->dr_fd = open(dp->dr_rname0, (O_RDWR|O_NDELAY), 0); 931*0Sstevel@tonic-gate if (! serial) 932*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 933*0Sstevel@tonic-gate if (dp->dr_fd < 0) { 934*0Sstevel@tonic-gate mhd_perror("%s: open", dp->dr_rname); 935*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL); 936*0Sstevel@tonic-gate dp->dr_errnum = errno; 937*0Sstevel@tonic-gate } 938*0Sstevel@tonic-gate continue; 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate /* dispatch */ 942*0Sstevel@tonic-gate switch (dp->dr_state) { 943*0Sstevel@tonic-gate case DRIVE_IDLE: 944*0Sstevel@tonic-gate MHDPRINTF1(("%s: IDLE\n", dp->dr_rname)); 945*0Sstevel@tonic-gate break; 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate case DRIVE_ERRORED: 948*0Sstevel@tonic-gate MHDPRINTF1(("%s: ERRORED %d\n", 949*0Sstevel@tonic-gate dp->dr_rname, dp->dr_errnum)); 950*0Sstevel@tonic-gate break; 951*0Sstevel@tonic-gate 952*0Sstevel@tonic-gate case DRIVE_IDLING: 953*0Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL); 954*0Sstevel@tonic-gate continue; 955*0Sstevel@tonic-gate 956*0Sstevel@tonic-gate case DRIVE_RESERVING: 957*0Sstevel@tonic-gate MHDPRINTF1(("%s: RESERVING\n", dp->dr_rname)); 958*0Sstevel@tonic-gate (void) mhd_reserve(dp); 959*0Sstevel@tonic-gate assert(DRIVE_IS_IDLE(dp)); 960*0Sstevel@tonic-gate continue; 961*0Sstevel@tonic-gate 962*0Sstevel@tonic-gate case DRIVE_FAILFASTING: 963*0Sstevel@tonic-gate MHDPRINTF1(("%s: FAILFASTING\n", dp->dr_rname)); 964*0Sstevel@tonic-gate (void) mhd_failfast(dp); 965*0Sstevel@tonic-gate assert(DRIVE_IS_IDLE(dp)); 966*0Sstevel@tonic-gate continue; 967*0Sstevel@tonic-gate 968*0Sstevel@tonic-gate case DRIVE_RELEASING: 969*0Sstevel@tonic-gate MHDPRINTF1(("%s: RELEASING\n", dp->dr_rname)); 970*0Sstevel@tonic-gate (void) mhd_release(dp); 971*0Sstevel@tonic-gate assert(DRIVE_IS_IDLE(dp)); 972*0Sstevel@tonic-gate continue; 973*0Sstevel@tonic-gate 974*0Sstevel@tonic-gate /* non-exclusive states */ 975*0Sstevel@tonic-gate default: 976*0Sstevel@tonic-gate assert(! (dp->dr_state & 977*0Sstevel@tonic-gate (DRIVE_EXCLUSIVE_STATES & ~DRIVE_ERRORED))); 978*0Sstevel@tonic-gate if (dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING)) { 979*0Sstevel@tonic-gate MHDPRINTF1(("%s: PROBING\n", dp->dr_rname)); 980*0Sstevel@tonic-gate (void) mhd_probe(dp); 981*0Sstevel@tonic-gate assert(! (dp->dr_state & DRIVE_STATUSING)); 982*0Sstevel@tonic-gate } 983*0Sstevel@tonic-gate if (dp->dr_state & DRIVE_IDENTING) { 984*0Sstevel@tonic-gate MHDPRINTF1(("%s: IDENTING\n", dp->dr_rname)); 985*0Sstevel@tonic-gate (void) mhd_ident(dp); 986*0Sstevel@tonic-gate assert(! (dp->dr_state & DRIVE_IDENTING)); 987*0Sstevel@tonic-gate continue; /* in case we're probing */ 988*0Sstevel@tonic-gate } 989*0Sstevel@tonic-gate break; 990*0Sstevel@tonic-gate } 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate /* close drive, if possible */ 993*0Sstevel@tonic-gate if ((dp->dr_fd >= 0) && (DRIVE_IS_IDLE(dp))) { 994*0Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL); 995*0Sstevel@tonic-gate 996*0Sstevel@tonic-gate if (! serial) 997*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 998*0Sstevel@tonic-gate (void) close(dp->dr_fd); /* sd/ssd bug */ 999*0Sstevel@tonic-gate if (! serial) 1000*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 1001*0Sstevel@tonic-gate dp->dr_fd = -1; 1002*0Sstevel@tonic-gate } 1003*0Sstevel@tonic-gate 1004*0Sstevel@tonic-gate /* wake up anybody waiting */ 1005*0Sstevel@tonic-gate mhd_cv_broadcast(&sp->sr_cv); 1006*0Sstevel@tonic-gate 1007*0Sstevel@tonic-gate /* see if anything happened */ 1008*0Sstevel@tonic-gate if (! DRIVE_IS_IDLE(dp)) 1009*0Sstevel@tonic-gate continue; 1010*0Sstevel@tonic-gate 1011*0Sstevel@tonic-gate /* wait for something to happen */ 1012*0Sstevel@tonic-gate if (! (dp->dr_state & DRIVE_PROBING)) { 1013*0Sstevel@tonic-gate mhd_cv_wait(&dp->dr_cv, &sp->sr_mx); 1014*0Sstevel@tonic-gate } else { 1015*0Sstevel@tonic-gate mhd_cv_timedwait(&dp->dr_cv, &sp->sr_mx, 1016*0Sstevel@tonic-gate (sp->sr_timeouts.mh_ff / 2)); 1017*0Sstevel@tonic-gate } 1018*0Sstevel@tonic-gate } 1019*0Sstevel@tonic-gate } 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate /* 1022*0Sstevel@tonic-gate * kick off drive thread 1023*0Sstevel@tonic-gate */ 1024*0Sstevel@tonic-gate static int 1025*0Sstevel@tonic-gate mhd_thread_create( 1026*0Sstevel@tonic-gate mhd_drive_t *dp, 1027*0Sstevel@tonic-gate mhd_error_t *mhep 1028*0Sstevel@tonic-gate ) 1029*0Sstevel@tonic-gate { 1030*0Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp; 1031*0Sstevel@tonic-gate thread_t thread = NULL; 1032*0Sstevel@tonic-gate int rval = 0; 1033*0Sstevel@tonic-gate 1034*0Sstevel@tonic-gate /* check lock and thread */ 1035*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 1036*0Sstevel@tonic-gate assert(dp->dr_thread == NULL); 1037*0Sstevel@tonic-gate 1038*0Sstevel@tonic-gate /* create thread */ 1039*0Sstevel@tonic-gate if (thr_create(NULL, 0, (void *(*)(void *))mhd_drive_thread, 1040*0Sstevel@tonic-gate (void *)dp, (THR_DETACHED | THR_BOUND), &thread) != 0) { 1041*0Sstevel@tonic-gate rval = mhd_error(mhep, errno, "thr_create"); 1042*0Sstevel@tonic-gate } else { 1043*0Sstevel@tonic-gate assert(thread != NULL); 1044*0Sstevel@tonic-gate dp->dr_thread = thread; 1045*0Sstevel@tonic-gate } 1046*0Sstevel@tonic-gate 1047*0Sstevel@tonic-gate /* return success */ 1048*0Sstevel@tonic-gate return (rval); 1049*0Sstevel@tonic-gate } 1050*0Sstevel@tonic-gate 1051*0Sstevel@tonic-gate /* 1052*0Sstevel@tonic-gate * peel off s%u from name 1053*0Sstevel@tonic-gate */ 1054*0Sstevel@tonic-gate static char * 1055*0Sstevel@tonic-gate diskname( 1056*0Sstevel@tonic-gate const char *sname 1057*0Sstevel@tonic-gate ) 1058*0Sstevel@tonic-gate { 1059*0Sstevel@tonic-gate char *dname; 1060*0Sstevel@tonic-gate char *p, *e; 1061*0Sstevel@tonic-gate 1062*0Sstevel@tonic-gate /* duplicate name */ 1063*0Sstevel@tonic-gate if ((dname = Strdup(sname)) == NULL) 1064*0Sstevel@tonic-gate return (NULL); 1065*0Sstevel@tonic-gate 1066*0Sstevel@tonic-gate /* gobble number and 's' */ 1067*0Sstevel@tonic-gate p = e = dname + strlen(dname) - 1; 1068*0Sstevel@tonic-gate for (; (p > dname); --p) { 1069*0Sstevel@tonic-gate if (!isdigit(*p)) 1070*0Sstevel@tonic-gate break; 1071*0Sstevel@tonic-gate } 1072*0Sstevel@tonic-gate if ((p == e) || (p <= dname)) { 1073*0Sstevel@tonic-gate Free(dname); 1074*0Sstevel@tonic-gate return (NULL); 1075*0Sstevel@tonic-gate } 1076*0Sstevel@tonic-gate if (*p-- != 's') { 1077*0Sstevel@tonic-gate Free(dname); 1078*0Sstevel@tonic-gate return (NULL); 1079*0Sstevel@tonic-gate } 1080*0Sstevel@tonic-gate if ((p <= dname) || (!isdigit(*p))) { 1081*0Sstevel@tonic-gate Free(dname); 1082*0Sstevel@tonic-gate return (NULL); 1083*0Sstevel@tonic-gate } 1084*0Sstevel@tonic-gate *(++p) = '\0'; 1085*0Sstevel@tonic-gate return (dname); 1086*0Sstevel@tonic-gate } 1087*0Sstevel@tonic-gate 1088*0Sstevel@tonic-gate /* 1089*0Sstevel@tonic-gate * create new drive 1090*0Sstevel@tonic-gate */ 1091*0Sstevel@tonic-gate mhd_drive_t * 1092*0Sstevel@tonic-gate mhd_create_drive( 1093*0Sstevel@tonic-gate mhd_drive_set_t *sp, /* new set */ 1094*0Sstevel@tonic-gate char *rname, /* raw drive name */ 1095*0Sstevel@tonic-gate int *fdp, /* open device or -1 */ 1096*0Sstevel@tonic-gate mhd_error_t *mhep /* returned error */ 1097*0Sstevel@tonic-gate ) 1098*0Sstevel@tonic-gate { 1099*0Sstevel@tonic-gate mhd_drive_t *dp = NULL; 1100*0Sstevel@tonic-gate char *rname0 = NULL; 1101*0Sstevel@tonic-gate 1102*0Sstevel@tonic-gate /* check locks */ 1103*0Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx)); 1104*0Sstevel@tonic-gate 1105*0Sstevel@tonic-gate /* if drive already exists */ 1106*0Sstevel@tonic-gate if ((dp = mhd_find_drive(rname)) != NULL) { 1107*0Sstevel@tonic-gate mhd_drive_set_t *oldsp = dp->dr_sp; 1108*0Sstevel@tonic-gate 1109*0Sstevel@tonic-gate /* if set has changed, move drive */ 1110*0Sstevel@tonic-gate if (oldsp != sp) { 1111*0Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx); 1112*0Sstevel@tonic-gate mhd_mx_lock(&oldsp->sr_mx); 1113*0Sstevel@tonic-gate if (mhd_idle(dp, mhep) != 0) { 1114*0Sstevel@tonic-gate mhd_mx_unlock(&oldsp->sr_mx); 1115*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 1116*0Sstevel@tonic-gate return (NULL); 1117*0Sstevel@tonic-gate } 1118*0Sstevel@tonic-gate mhd_del_drive_from_set(dp); 1119*0Sstevel@tonic-gate mhd_mx_unlock(&oldsp->sr_mx); 1120*0Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx); 1121*0Sstevel@tonic-gate mhd_add_drive_to_set(sp, dp); 1122*0Sstevel@tonic-gate } 1123*0Sstevel@tonic-gate 1124*0Sstevel@tonic-gate /* return drive */ 1125*0Sstevel@tonic-gate return (dp); 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate /* build slice0 */ 1129*0Sstevel@tonic-gate rname0 = Malloc(strlen(rname) + strlen("s0") + 1); 1130*0Sstevel@tonic-gate (void) strcpy(rname0, rname); 1131*0Sstevel@tonic-gate (void) strcat(rname0, "s0"); 1132*0Sstevel@tonic-gate 1133*0Sstevel@tonic-gate /* allocate and initialize drive */ 1134*0Sstevel@tonic-gate dp = Zalloc(sizeof (*dp)); 1135*0Sstevel@tonic-gate dp->dr_sp = sp; 1136*0Sstevel@tonic-gate dp->dr_rname = Strdup(rname); 1137*0Sstevel@tonic-gate dp->dr_rname0 = rname0; 1138*0Sstevel@tonic-gate mhd_cv_init(&dp->dr_cv); 1139*0Sstevel@tonic-gate dp->dr_thread = NULL; 1140*0Sstevel@tonic-gate dp->dr_fd = -1; 1141*0Sstevel@tonic-gate dp->dr_state = DRIVE_IDLE; 1142*0Sstevel@tonic-gate 1143*0Sstevel@tonic-gate /* steal open drive */ 1144*0Sstevel@tonic-gate if ((fdp != NULL) && (*fdp >= 0)) { 1145*0Sstevel@tonic-gate dp->dr_fd = *fdp; 1146*0Sstevel@tonic-gate *fdp = -1; 1147*0Sstevel@tonic-gate } 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate /* add to set */ 1150*0Sstevel@tonic-gate mhd_add_drive_to_set(sp, dp); 1151*0Sstevel@tonic-gate 1152*0Sstevel@tonic-gate /* kick off drive thread */ 1153*0Sstevel@tonic-gate if (mhd_thread_create(dp, mhep) != 0) { 1154*0Sstevel@tonic-gate Free(dp->dr_rname0); 1155*0Sstevel@tonic-gate Free(dp->dr_rname); 1156*0Sstevel@tonic-gate Free(dp); 1157*0Sstevel@tonic-gate return (NULL); 1158*0Sstevel@tonic-gate } 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate /* return drive */ 1161*0Sstevel@tonic-gate return (dp); 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate /* 1165*0Sstevel@tonic-gate * find or create drive in any set 1166*0Sstevel@tonic-gate */ 1167*0Sstevel@tonic-gate static mhd_drive_t * 1168*0Sstevel@tonic-gate mhd_create_drive_anyset( 1169*0Sstevel@tonic-gate char *rname, 1170*0Sstevel@tonic-gate int *fdp, 1171*0Sstevel@tonic-gate mhd_error_t *mhep 1172*0Sstevel@tonic-gate ) 1173*0Sstevel@tonic-gate { 1174*0Sstevel@tonic-gate mhd_drive_set_t *null_sp = mhd_create_set(NULL, 0, NULL, NULL); 1175*0Sstevel@tonic-gate mhd_drive_t *dp; 1176*0Sstevel@tonic-gate 1177*0Sstevel@tonic-gate /* check locks */ 1178*0Sstevel@tonic-gate assert(null_sp != NULL); 1179*0Sstevel@tonic-gate 1180*0Sstevel@tonic-gate /* drive already exists */ 1181*0Sstevel@tonic-gate if ((dp = mhd_find_drive(rname)) != NULL) 1182*0Sstevel@tonic-gate return (dp); 1183*0Sstevel@tonic-gate 1184*0Sstevel@tonic-gate /* add to null set */ 1185*0Sstevel@tonic-gate mhd_mx_lock(&null_sp->sr_mx); 1186*0Sstevel@tonic-gate dp = mhd_create_drive(null_sp, rname, fdp, mhep); 1187*0Sstevel@tonic-gate mhd_mx_unlock(&null_sp->sr_mx); 1188*0Sstevel@tonic-gate 1189*0Sstevel@tonic-gate /* return drive */ 1190*0Sstevel@tonic-gate return (dp); 1191*0Sstevel@tonic-gate } 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate /* 1194*0Sstevel@tonic-gate * process a file in the tree walk 1195*0Sstevel@tonic-gate */ 1196*0Sstevel@tonic-gate static int 1197*0Sstevel@tonic-gate do_disk( 1198*0Sstevel@tonic-gate const char *path, 1199*0Sstevel@tonic-gate const struct stat *statp, 1200*0Sstevel@tonic-gate int type 1201*0Sstevel@tonic-gate ) 1202*0Sstevel@tonic-gate { 1203*0Sstevel@tonic-gate char *dname = NULL; 1204*0Sstevel@tonic-gate int fd = -1; 1205*0Sstevel@tonic-gate struct dk_cinfo cinfo; 1206*0Sstevel@tonic-gate mhd_error_t status = mhd_null_error; 1207*0Sstevel@tonic-gate 1208*0Sstevel@tonic-gate /* skip all but character devices */ 1209*0Sstevel@tonic-gate if ((type != FTW_F) || (! S_ISCHR(statp->st_mode)) || 1210*0Sstevel@tonic-gate ((dname = diskname(path)) == NULL)) { 1211*0Sstevel@tonic-gate return (0); 1212*0Sstevel@tonic-gate } 1213*0Sstevel@tonic-gate 1214*0Sstevel@tonic-gate /* see if drive already exists */ 1215*0Sstevel@tonic-gate if (mhd_find_drive(dname) != NULL) 1216*0Sstevel@tonic-gate return (0); 1217*0Sstevel@tonic-gate 1218*0Sstevel@tonic-gate /* see if device is a disk */ 1219*0Sstevel@tonic-gate if ((fd = open(path, (O_RDONLY|O_NDELAY), 0)) < 0) 1220*0Sstevel@tonic-gate goto out; 1221*0Sstevel@tonic-gate if (ioctl(fd, DKIOCINFO, &cinfo) != 0) { 1222*0Sstevel@tonic-gate switch (errno) { 1223*0Sstevel@tonic-gate case EINVAL: 1224*0Sstevel@tonic-gate case ENOTTY: 1225*0Sstevel@tonic-gate break; 1226*0Sstevel@tonic-gate default: 1227*0Sstevel@tonic-gate mhd_perror("DKIOCINFO: %s", path); 1228*0Sstevel@tonic-gate break; 1229*0Sstevel@tonic-gate } 1230*0Sstevel@tonic-gate goto out; 1231*0Sstevel@tonic-gate } 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate /* skip CDROMs */ 1234*0Sstevel@tonic-gate if (cinfo.dki_ctype == DKC_CDROM) { 1235*0Sstevel@tonic-gate (void) close(fd); 1236*0Sstevel@tonic-gate Free(dname); 1237*0Sstevel@tonic-gate return (0); 1238*0Sstevel@tonic-gate } 1239*0Sstevel@tonic-gate 1240*0Sstevel@tonic-gate /* put disk on list */ 1241*0Sstevel@tonic-gate if (mhd_create_drive_anyset(dname, &fd, &status) == NULL) { 1242*0Sstevel@tonic-gate mhde_perror(&status, ""); 1243*0Sstevel@tonic-gate goto out; 1244*0Sstevel@tonic-gate } 1245*0Sstevel@tonic-gate 1246*0Sstevel@tonic-gate /* cleanup, return success (no matter what) */ 1247*0Sstevel@tonic-gate out: 1248*0Sstevel@tonic-gate if (dname != NULL) 1249*0Sstevel@tonic-gate Free(dname); 1250*0Sstevel@tonic-gate if (fd >= 0) 1251*0Sstevel@tonic-gate (void) close(fd); 1252*0Sstevel@tonic-gate mhd_clrerror(&status); 1253*0Sstevel@tonic-gate return (0); 1254*0Sstevel@tonic-gate } 1255*0Sstevel@tonic-gate 1256*0Sstevel@tonic-gate /* 1257*0Sstevel@tonic-gate * find or create all the drives under a given directory 1258*0Sstevel@tonic-gate */ 1259*0Sstevel@tonic-gate int 1260*0Sstevel@tonic-gate mhd_create_drives( 1261*0Sstevel@tonic-gate char *path, 1262*0Sstevel@tonic-gate mhd_error_t *mhep 1263*0Sstevel@tonic-gate ) 1264*0Sstevel@tonic-gate { 1265*0Sstevel@tonic-gate /* default */ 1266*0Sstevel@tonic-gate if ((path == NULL) || (*path == '\0')) 1267*0Sstevel@tonic-gate path = "/dev/rdsk"; 1268*0Sstevel@tonic-gate 1269*0Sstevel@tonic-gate free_pln_cache(); 1270*0Sstevel@tonic-gate 1271*0Sstevel@tonic-gate /* walk the directory, adding disks */ 1272*0Sstevel@tonic-gate if (ftw(path, do_disk, 5) != 0) 1273*0Sstevel@tonic-gate return (mhd_error(mhep, errno, path)); 1274*0Sstevel@tonic-gate 1275*0Sstevel@tonic-gate /* return success */ 1276*0Sstevel@tonic-gate return (0); 1277*0Sstevel@tonic-gate } 1278