10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
57563SPrasad.Singamsetty@Sun.COM * Common Development and Distribution License (the "License").
67563SPrasad.Singamsetty@Sun.COM * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*11053SSurya.Prakki@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate #include "mhd_local.h"
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <ftw.h>
290Sstevel@tonic-gate #include <libgen.h>
300Sstevel@tonic-gate #include <sys/mhd.h>
310Sstevel@tonic-gate #include <sys/scsi/impl/uscsi.h>
320Sstevel@tonic-gate #include <sys/scsi/generic/commands.h>
330Sstevel@tonic-gate #include <sys/scsi/generic/inquiry.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate /*
360Sstevel@tonic-gate * manipulate drives
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate * null list constant
410Sstevel@tonic-gate */
420Sstevel@tonic-gate const mhd_drive_list_t mhd_null_list = MHD_NULL_LIST;
430Sstevel@tonic-gate
440Sstevel@tonic-gate /*
450Sstevel@tonic-gate * add drive to list
460Sstevel@tonic-gate */
470Sstevel@tonic-gate void
mhd_add_drive(mhd_drive_list_t * dlp,mhd_drive_t * dp)480Sstevel@tonic-gate mhd_add_drive(
490Sstevel@tonic-gate mhd_drive_list_t *dlp,
500Sstevel@tonic-gate mhd_drive_t *dp
510Sstevel@tonic-gate )
520Sstevel@tonic-gate {
530Sstevel@tonic-gate /* add drive to list */
540Sstevel@tonic-gate if (dlp->dl_ndrive >= dlp->dl_alloc) {
550Sstevel@tonic-gate dlp->dl_alloc += 10;
560Sstevel@tonic-gate dlp->dl_drives = Realloc(dlp->dl_drives,
570Sstevel@tonic-gate (dlp->dl_alloc * sizeof (*dlp->dl_drives)));
580Sstevel@tonic-gate }
590Sstevel@tonic-gate dlp->dl_drives[dlp->dl_ndrive++] = dp;
600Sstevel@tonic-gate }
610Sstevel@tonic-gate
620Sstevel@tonic-gate /*
630Sstevel@tonic-gate * delete drive from list
640Sstevel@tonic-gate */
650Sstevel@tonic-gate void
mhd_del_drive(mhd_drive_list_t * dlp,mhd_drive_t * dp)660Sstevel@tonic-gate mhd_del_drive(
670Sstevel@tonic-gate mhd_drive_list_t *dlp,
680Sstevel@tonic-gate mhd_drive_t *dp
690Sstevel@tonic-gate )
700Sstevel@tonic-gate {
710Sstevel@tonic-gate uint_t i;
720Sstevel@tonic-gate
730Sstevel@tonic-gate /* delete drive from list */
740Sstevel@tonic-gate for (i = 0; (i < dlp->dl_ndrive); ++i) {
750Sstevel@tonic-gate if (dlp->dl_drives[i] == dp)
760Sstevel@tonic-gate break;
770Sstevel@tonic-gate }
780Sstevel@tonic-gate assert(dlp->dl_drives[i] == dp);
790Sstevel@tonic-gate for (/* void */; (i < dlp->dl_ndrive); ++i)
800Sstevel@tonic-gate dlp->dl_drives[i] = dlp->dl_drives[i + 1];
810Sstevel@tonic-gate dlp->dl_ndrive--;
820Sstevel@tonic-gate }
830Sstevel@tonic-gate
840Sstevel@tonic-gate /*
850Sstevel@tonic-gate * free drive list
860Sstevel@tonic-gate */
870Sstevel@tonic-gate void
mhd_free_list(mhd_drive_list_t * dlp)880Sstevel@tonic-gate mhd_free_list(
890Sstevel@tonic-gate mhd_drive_list_t *dlp
900Sstevel@tonic-gate )
910Sstevel@tonic-gate {
920Sstevel@tonic-gate if (dlp->dl_drives != NULL)
930Sstevel@tonic-gate Free(dlp->dl_drives);
940Sstevel@tonic-gate (void) memset(dlp, 0, sizeof (*dlp));
950Sstevel@tonic-gate }
960Sstevel@tonic-gate
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate * manipulate drive state
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate int
mhd_state(mhd_drive_t * dp,mhd_state_t new_state,mhd_error_t * mhep)1010Sstevel@tonic-gate mhd_state(
1020Sstevel@tonic-gate mhd_drive_t *dp,
1030Sstevel@tonic-gate mhd_state_t new_state,
1040Sstevel@tonic-gate mhd_error_t *mhep
1050Sstevel@tonic-gate )
1060Sstevel@tonic-gate {
1070Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
1080Sstevel@tonic-gate mhd_state_t old_state = dp->dr_state;
1090Sstevel@tonic-gate
1100Sstevel@tonic-gate /* check lock */
1110Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
1120Sstevel@tonic-gate
1130Sstevel@tonic-gate /* set state and kick thread */
1140Sstevel@tonic-gate MHDPRINTF2(("%s: state 0x%x now 0x%x\n",
1150Sstevel@tonic-gate dp->dr_rname, dp->dr_state, new_state));
1160Sstevel@tonic-gate dp->dr_state = new_state;
1170Sstevel@tonic-gate mhd_cv_broadcast(&dp->dr_cv);
1180Sstevel@tonic-gate
1190Sstevel@tonic-gate /* if this is the last PROBING drive, disable any failfast */
1200Sstevel@tonic-gate if ((old_state & DRIVE_PROBING) && (! (new_state & DRIVE_PROBING))) {
1210Sstevel@tonic-gate mhd_drive_list_t *dlp = &sp->sr_drives;
1220Sstevel@tonic-gate uint_t cnt, i;
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate for (cnt = 0, i = 0; (i < dlp->dl_ndrive); ++i) {
1250Sstevel@tonic-gate if (dlp->dl_drives[i]->dr_state & DRIVE_PROBING)
1260Sstevel@tonic-gate ++cnt;
1270Sstevel@tonic-gate }
1280Sstevel@tonic-gate if (cnt == 0) {
1290Sstevel@tonic-gate mhd_error_t status = mhd_null_error;
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate if (mhep == NULL)
1320Sstevel@tonic-gate mhep = &status;
1330Sstevel@tonic-gate if (mhd_ff_disarm(sp, mhep) != 0) {
1340Sstevel@tonic-gate if (mhep == &status) {
1350Sstevel@tonic-gate mhde_perror(mhep, dp->dr_rname);
1360Sstevel@tonic-gate mhd_clrerror(mhep);
1370Sstevel@tonic-gate }
1380Sstevel@tonic-gate return (-1);
1390Sstevel@tonic-gate }
1400Sstevel@tonic-gate }
1410Sstevel@tonic-gate }
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate /* return success */
1440Sstevel@tonic-gate return (0);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate int
mhd_state_set(mhd_drive_t * dp,mhd_state_t new_state,mhd_error_t * mhep)1480Sstevel@tonic-gate mhd_state_set(
1490Sstevel@tonic-gate mhd_drive_t *dp,
1500Sstevel@tonic-gate mhd_state_t new_state,
1510Sstevel@tonic-gate mhd_error_t *mhep
1520Sstevel@tonic-gate )
1530Sstevel@tonic-gate {
1540Sstevel@tonic-gate return (mhd_state(dp, (dp->dr_state | new_state), mhep));
1550Sstevel@tonic-gate }
1560Sstevel@tonic-gate
1570Sstevel@tonic-gate static int
mhd_state_clr(mhd_drive_t * dp,mhd_state_t new_state,mhd_error_t * mhep)1580Sstevel@tonic-gate mhd_state_clr(
1590Sstevel@tonic-gate mhd_drive_t *dp,
1600Sstevel@tonic-gate mhd_state_t new_state,
1610Sstevel@tonic-gate mhd_error_t *mhep
1620Sstevel@tonic-gate )
1630Sstevel@tonic-gate {
1640Sstevel@tonic-gate return (mhd_state(dp, (dp->dr_state & ~new_state), mhep));
1650Sstevel@tonic-gate }
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate * idle a drive
1690Sstevel@tonic-gate */
1700Sstevel@tonic-gate int
mhd_idle(mhd_drive_t * dp,mhd_error_t * mhep)1710Sstevel@tonic-gate mhd_idle(
1720Sstevel@tonic-gate mhd_drive_t *dp,
1730Sstevel@tonic-gate mhd_error_t *mhep
1740Sstevel@tonic-gate )
1750Sstevel@tonic-gate {
1760Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
1770Sstevel@tonic-gate
1780Sstevel@tonic-gate /* check lock */
1790Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate /* wait for thread to idle */
1820Sstevel@tonic-gate for (;;) {
1830Sstevel@tonic-gate if (DRIVE_IS_IDLE(dp))
1840Sstevel@tonic-gate return (0);
1850Sstevel@tonic-gate if (mhd_state(dp, DRIVE_IDLING, mhep) != 0)
1860Sstevel@tonic-gate return (-1);
1870Sstevel@tonic-gate (void) mhd_cv_wait(&sp->sr_cv, &sp->sr_mx);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate /*
1920Sstevel@tonic-gate * reserve the drive
1930Sstevel@tonic-gate */
1940Sstevel@tonic-gate static int
mhd_reserve(mhd_drive_t * dp)1950Sstevel@tonic-gate mhd_reserve(
1960Sstevel@tonic-gate mhd_drive_t *dp
1970Sstevel@tonic-gate )
1980Sstevel@tonic-gate {
1990Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
2000Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
2010Sstevel@tonic-gate mhd_mhioctkown_t *tkp = &sp->sr_timeouts.mh_tk;
2020Sstevel@tonic-gate struct mhioctkown tkown;
2030Sstevel@tonic-gate int err;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /* check locks */
2060Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
2070Sstevel@tonic-gate assert(dp->dr_fd >= 0);
2080Sstevel@tonic-gate assert(dp->dr_state == DRIVE_RESERVING);
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate /* setup timeouts */
2110Sstevel@tonic-gate (void) memset(&tkown, 0, sizeof (tkown));
2120Sstevel@tonic-gate tkown.reinstate_resv_delay = tkp->reinstate_resv_delay;
2130Sstevel@tonic-gate tkown.min_ownership_delay = tkp->min_ownership_delay;
2140Sstevel@tonic-gate tkown.max_ownership_delay = tkp->max_ownership_delay;
2150Sstevel@tonic-gate
2160Sstevel@tonic-gate /* reserve drive */
2170Sstevel@tonic-gate if (! serial)
2180Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
2190Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCTKOWN, &tkown);
2200Sstevel@tonic-gate if (! serial)
2210Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
2220Sstevel@tonic-gate if (err != 0) {
2230Sstevel@tonic-gate mhd_perror("%s: MHIOCTKOWN", dp->dr_rname);
2240Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL);
2250Sstevel@tonic-gate dp->dr_errnum = errno;
2260Sstevel@tonic-gate return (-1);
2270Sstevel@tonic-gate }
2280Sstevel@tonic-gate
2290Sstevel@tonic-gate /* return success */
2300Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCTKOWN: succeeded\n", dp->dr_rname));
2310Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL);
2320Sstevel@tonic-gate return (0);
2330Sstevel@tonic-gate }
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate /*
2360Sstevel@tonic-gate * failfast the drive
2370Sstevel@tonic-gate */
2380Sstevel@tonic-gate static int
mhd_failfast(mhd_drive_t * dp)2390Sstevel@tonic-gate mhd_failfast(
2400Sstevel@tonic-gate mhd_drive_t *dp
2410Sstevel@tonic-gate )
2420Sstevel@tonic-gate {
2430Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
2440Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
2450Sstevel@tonic-gate int ff = sp->sr_timeouts.mh_ff;
2460Sstevel@tonic-gate char *release = ((ff == 0) ? " (release)" : "");
2470Sstevel@tonic-gate int err;
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate /* check locks */
2500Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
2510Sstevel@tonic-gate assert(dp->dr_fd >= 0);
2520Sstevel@tonic-gate assert(dp->dr_state == DRIVE_FAILFASTING);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate /* failfast drive */
2550Sstevel@tonic-gate if (! serial)
2560Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
2570Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCENFAILFAST, &ff);
2580Sstevel@tonic-gate if (! serial)
2590Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
2600Sstevel@tonic-gate if (err != 0) {
2610Sstevel@tonic-gate mhd_perror("%s: MHIOCENFAILFAST%s", dp->dr_rname, release);
2620Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL);
2630Sstevel@tonic-gate dp->dr_errnum = errno;
2640Sstevel@tonic-gate return (-1);
2650Sstevel@tonic-gate }
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate /* return success */
2680Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCENFAILFAST%s: succeeded\n",
2690Sstevel@tonic-gate dp->dr_rname, release));
2700Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL);
2710Sstevel@tonic-gate return (0);
2720Sstevel@tonic-gate }
2730Sstevel@tonic-gate
2740Sstevel@tonic-gate /*
2750Sstevel@tonic-gate * release the drive
2760Sstevel@tonic-gate */
2770Sstevel@tonic-gate static int
mhd_release(mhd_drive_t * dp)2780Sstevel@tonic-gate mhd_release(
2790Sstevel@tonic-gate mhd_drive_t *dp
2800Sstevel@tonic-gate )
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
2830Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
2840Sstevel@tonic-gate int ff = 0; /* disable failfast */
2850Sstevel@tonic-gate int err;
2860Sstevel@tonic-gate
2870Sstevel@tonic-gate /* check locks */
2880Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
2890Sstevel@tonic-gate assert(dp->dr_fd >= 0);
2900Sstevel@tonic-gate assert(dp->dr_state == DRIVE_RELEASING);
2910Sstevel@tonic-gate
2920Sstevel@tonic-gate /* disable failfast */
2930Sstevel@tonic-gate if (! serial)
2940Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
2950Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCENFAILFAST, &ff);
2960Sstevel@tonic-gate if (! serial)
2970Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
2980Sstevel@tonic-gate if (err != 0) {
2990Sstevel@tonic-gate mhd_perror("%s: MHIOCENFAILFAST (release)", dp->dr_rname);
3000Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL);
3010Sstevel@tonic-gate dp->dr_errnum = errno;
3020Sstevel@tonic-gate return (-1);
3030Sstevel@tonic-gate }
3040Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCENFAILFAST (release): succeeded\n",
3050Sstevel@tonic-gate dp->dr_rname));
3060Sstevel@tonic-gate
3070Sstevel@tonic-gate /* release drive */
3080Sstevel@tonic-gate if (! serial)
3090Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
3100Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCRELEASE, NULL);
3110Sstevel@tonic-gate if (! serial)
3120Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
3130Sstevel@tonic-gate if (err != 0) {
3140Sstevel@tonic-gate mhd_perror("%s: MHIOCRELEASE", dp->dr_rname);
3150Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL);
3160Sstevel@tonic-gate dp->dr_errnum = errno;
3170Sstevel@tonic-gate return (-1);
3180Sstevel@tonic-gate }
3190Sstevel@tonic-gate
3200Sstevel@tonic-gate /* return success */
3210Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCRELEASE: succeeded\n", dp->dr_rname));
3220Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL);
3230Sstevel@tonic-gate return (0);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate * probe the drive
3280Sstevel@tonic-gate */
3290Sstevel@tonic-gate static int
mhd_probe(mhd_drive_t * dp)3300Sstevel@tonic-gate mhd_probe(
3310Sstevel@tonic-gate mhd_drive_t *dp
3320Sstevel@tonic-gate )
3330Sstevel@tonic-gate {
3340Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
3350Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
3360Sstevel@tonic-gate int err;
3370Sstevel@tonic-gate mhd_msec_t now;
3380Sstevel@tonic-gate
3390Sstevel@tonic-gate /* check locks */
3400Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
3410Sstevel@tonic-gate assert(dp->dr_fd >= 0);
3420Sstevel@tonic-gate assert(dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING));
3430Sstevel@tonic-gate
3440Sstevel@tonic-gate /* get status (we may get dumped from PROBING here) */
3450Sstevel@tonic-gate if (! serial)
3460Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
3470Sstevel@tonic-gate err = ioctl(dp->dr_fd, MHIOCSTATUS, NULL);
3480Sstevel@tonic-gate now = mhd_time();
3490Sstevel@tonic-gate if (! serial)
3500Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
3510Sstevel@tonic-gate if (! (dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING)))
3520Sstevel@tonic-gate return (0);
3530Sstevel@tonic-gate
3540Sstevel@tonic-gate /* update status */
3550Sstevel@tonic-gate if (dp->dr_state & DRIVE_STATUSING) {
3560Sstevel@tonic-gate if (err == 1) {
3570Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCSTATUS: reserved\n",
3580Sstevel@tonic-gate dp->dr_rname));
3590Sstevel@tonic-gate dp->dr_errnum = MHD_E_RESERVED;
3600Sstevel@tonic-gate } else if (err != 0) {
3610Sstevel@tonic-gate mhd_perror("%s: MHIOCSTATUS", dp->dr_rname);
3620Sstevel@tonic-gate dp->dr_errnum = errno;
3630Sstevel@tonic-gate } else {
3640Sstevel@tonic-gate MHDPRINTF(("%s: MHIOCSTATUS: available\n",
3650Sstevel@tonic-gate dp->dr_rname));
3660Sstevel@tonic-gate dp->dr_errnum = 0;
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate (void) mhd_state_clr(dp, DRIVE_STATUSING, NULL);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate /* update time or die */
3720Sstevel@tonic-gate if (dp->dr_state & DRIVE_PROBING) {
3730Sstevel@tonic-gate /* check our drive */
3740Sstevel@tonic-gate if (err == 0) {
3750Sstevel@tonic-gate dp->dr_time = now;
3760Sstevel@tonic-gate } else if (err == 1) {
3770Sstevel@tonic-gate mhd_eprintf("%s: %s: reservation conflict\n",
3780Sstevel@tonic-gate sp->sr_name, dp->dr_rname);
3790Sstevel@tonic-gate mhd_ff_die(sp);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate /* check other drives */
3830Sstevel@tonic-gate mhd_ff_check(sp);
3840Sstevel@tonic-gate }
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate /* return success */
3870Sstevel@tonic-gate return (0);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate
3900Sstevel@tonic-gate /*
3910Sstevel@tonic-gate * cached controller map
3920Sstevel@tonic-gate */
3930Sstevel@tonic-gate typedef struct {
3940Sstevel@tonic-gate char *regexpr1;
3950Sstevel@tonic-gate uint_t tray;
3960Sstevel@tonic-gate uint_t bus;
3970Sstevel@tonic-gate char *regexpr2;
3980Sstevel@tonic-gate char *scan;
3990Sstevel@tonic-gate } mhd_ctlrmap_t;
4000Sstevel@tonic-gate
4010Sstevel@tonic-gate static rwlock_t ctlr_rw = DEFAULTRWLOCK;
4020Sstevel@tonic-gate static time_t ctlr_mtime = 0;
4030Sstevel@tonic-gate static size_t ctlr_num = 0;
4040Sstevel@tonic-gate static mhd_ctlrmap_t *ctlr_map = NULL;
4050Sstevel@tonic-gate
4060Sstevel@tonic-gate /*
4070Sstevel@tonic-gate * free up controller map
4080Sstevel@tonic-gate */
4090Sstevel@tonic-gate static void
free_map()4100Sstevel@tonic-gate free_map()
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate size_t i;
4130Sstevel@tonic-gate
4140Sstevel@tonic-gate assert(RW_WRITE_HELD(&ctlr_rw));
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate for (i = 0; (i < ctlr_num); ++i) {
4170Sstevel@tonic-gate mhd_ctlrmap_t *cmp = &ctlr_map[i];
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate if (cmp->regexpr1 != NULL)
4200Sstevel@tonic-gate Free(cmp->regexpr1);
4210Sstevel@tonic-gate if (cmp->regexpr2 != NULL)
4220Sstevel@tonic-gate Free(cmp->regexpr2);
4230Sstevel@tonic-gate if (cmp->scan != NULL)
4240Sstevel@tonic-gate Free(cmp->scan);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate if (ctlr_map != NULL)
4270Sstevel@tonic-gate Free(ctlr_map);
4280Sstevel@tonic-gate ctlr_num = 0;
4290Sstevel@tonic-gate ctlr_map = NULL;
4300Sstevel@tonic-gate }
4310Sstevel@tonic-gate
4320Sstevel@tonic-gate /*
4330Sstevel@tonic-gate * unlock controller map
4340Sstevel@tonic-gate */
4350Sstevel@tonic-gate static void
unlock_map()4360Sstevel@tonic-gate unlock_map()
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate assert(RW_WRITE_HELD(&ctlr_rw) | RW_READ_HELD(&ctlr_rw));
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate mhd_rw_unlock(&ctlr_rw);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate
4430Sstevel@tonic-gate /*
4440Sstevel@tonic-gate * update controller map and lock it
4450Sstevel@tonic-gate */
4460Sstevel@tonic-gate static int
update_map()4470Sstevel@tonic-gate update_map()
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate struct stat statbuf;
4500Sstevel@tonic-gate FILE *fp;
4510Sstevel@tonic-gate char line[256], expr1[256], expr2[256], scan[256];
4520Sstevel@tonic-gate unsigned tray, bus;
4530Sstevel@tonic-gate int rval = -1;
4540Sstevel@tonic-gate
4550Sstevel@tonic-gate /* see if map file has changed */
4560Sstevel@tonic-gate mhd_rw_rdlock(&ctlr_rw);
4570Sstevel@tonic-gate if (stat(METACTLRMAP, &statbuf) != 0) {
4580Sstevel@tonic-gate mhd_perror(METACTLRMAP);
4590Sstevel@tonic-gate goto out;
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate if (statbuf.st_mtime == ctlr_mtime) {
4620Sstevel@tonic-gate rval = 0;
4630Sstevel@tonic-gate goto out;
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate /* trade up to writer lock, check again */
4670Sstevel@tonic-gate mhd_rw_unlock(&ctlr_rw);
4680Sstevel@tonic-gate mhd_rw_wrlock(&ctlr_rw);
4690Sstevel@tonic-gate if (statbuf.st_mtime == ctlr_mtime) {
4700Sstevel@tonic-gate rval = 0;
4710Sstevel@tonic-gate goto out;
4720Sstevel@tonic-gate }
4730Sstevel@tonic-gate if (ctlr_mtime != 0)
4740Sstevel@tonic-gate mhd_eprintf("updating controller map\n");
4750Sstevel@tonic-gate ctlr_mtime = statbuf.st_mtime;
4760Sstevel@tonic-gate
4770Sstevel@tonic-gate /* toss existing cache */
4780Sstevel@tonic-gate free_map();
4790Sstevel@tonic-gate
4800Sstevel@tonic-gate /* parse md.ctlrmap */
4810Sstevel@tonic-gate if ((fp = fopen(METACTLRMAP, "r")) == NULL) {
4820Sstevel@tonic-gate mhd_perror(METACTLRMAP);
4830Sstevel@tonic-gate goto out;
4840Sstevel@tonic-gate }
4850Sstevel@tonic-gate clearerr(fp);
4860Sstevel@tonic-gate while (fgets(line, sizeof (line), fp) != NULL) {
4870Sstevel@tonic-gate char *regexpr1 = NULL;
4880Sstevel@tonic-gate char *regexpr2 = NULL;
4890Sstevel@tonic-gate mhd_ctlrmap_t *cmp;
4900Sstevel@tonic-gate
4910Sstevel@tonic-gate /* skip blank lines and comments */
4920Sstevel@tonic-gate if ((line[0] == '\0') || (line[0] == '\n') || (line[0] == '#'))
4930Sstevel@tonic-gate continue;
4940Sstevel@tonic-gate
4950Sstevel@tonic-gate /* parse line */
4960Sstevel@tonic-gate if (((sscanf(line, "\"%[^\"]\" %u %u \"%[^\"]\" \"%[^\"]\"",
4970Sstevel@tonic-gate expr1, &tray, &bus, expr2, scan)) != 5) ||
4980Sstevel@tonic-gate ((regexpr1 = regcmp(expr1, 0)) == NULL) ||
4990Sstevel@tonic-gate ((regexpr2 = regcmp(expr2, 0)) == NULL)) {
5000Sstevel@tonic-gate mhd_eprintf("%s: bad regex(es) '%s'\n",
5010Sstevel@tonic-gate METACTLRMAP, line);
5020Sstevel@tonic-gate if (regexpr1 != NULL)
5030Sstevel@tonic-gate Free(regexpr1);
5040Sstevel@tonic-gate if (regexpr2 != NULL)
5050Sstevel@tonic-gate Free(regexpr2);
5060Sstevel@tonic-gate continue;
5070Sstevel@tonic-gate }
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate /* add to cache */
5100Sstevel@tonic-gate ctlr_map = Realloc(ctlr_map,
5110Sstevel@tonic-gate ((ctlr_num + 1) * sizeof (*ctlr_map)));
5120Sstevel@tonic-gate cmp = &ctlr_map[ctlr_num++];
5130Sstevel@tonic-gate cmp->regexpr1 = regexpr1;
5140Sstevel@tonic-gate cmp->tray = tray;
5150Sstevel@tonic-gate cmp->bus = bus;
5160Sstevel@tonic-gate cmp->regexpr2 = regexpr2;
5170Sstevel@tonic-gate cmp->scan = Strdup(scan);
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate if (ferror(fp)) {
5200Sstevel@tonic-gate mhd_perror(METACTLRMAP);
5210Sstevel@tonic-gate (void) fclose(fp);
5220Sstevel@tonic-gate goto out;
5230Sstevel@tonic-gate }
5240Sstevel@tonic-gate if (fclose(fp) != 0) {
5250Sstevel@tonic-gate mhd_perror(METACTLRMAP);
5260Sstevel@tonic-gate goto out;
5270Sstevel@tonic-gate }
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate /* success */
5300Sstevel@tonic-gate rval = 0;
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate /* return success */
5330Sstevel@tonic-gate out:
5340Sstevel@tonic-gate if (rval != 0) {
5350Sstevel@tonic-gate mhd_rw_unlock(&ctlr_rw);
5360Sstevel@tonic-gate return (-1);
5370Sstevel@tonic-gate }
5380Sstevel@tonic-gate return (0);
5390Sstevel@tonic-gate }
5400Sstevel@tonic-gate
5410Sstevel@tonic-gate static char *
get_pln_ctlr_name(char * path)5420Sstevel@tonic-gate get_pln_ctlr_name(
5430Sstevel@tonic-gate char *path
5440Sstevel@tonic-gate )
5450Sstevel@tonic-gate {
5460Sstevel@tonic-gate char *devicesname, *p;
5470Sstevel@tonic-gate char retval[MAXPATHLEN];
5480Sstevel@tonic-gate
5490Sstevel@tonic-gate devicesname = Strdup(path);
5500Sstevel@tonic-gate if ((p = strrchr(devicesname, '/')) == NULL) {
5510Sstevel@tonic-gate Free(devicesname);
5520Sstevel@tonic-gate return (NULL);
5530Sstevel@tonic-gate }
5540Sstevel@tonic-gate
5550Sstevel@tonic-gate /* strip off the "ssd@..." portion of the devices name */
5560Sstevel@tonic-gate *p = '\0';
5570Sstevel@tonic-gate
5580Sstevel@tonic-gate /* strip off the "../../" in front of "devices" */
5590Sstevel@tonic-gate if ((p = strstr(devicesname, "/devices/")) == NULL) {
5600Sstevel@tonic-gate Free(devicesname);
5610Sstevel@tonic-gate return (NULL);
5620Sstevel@tonic-gate }
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate (void) snprintf(retval, sizeof (retval), "%s:ctlr", p);
5650Sstevel@tonic-gate Free(devicesname);
5660Sstevel@tonic-gate return (Strdup(retval));
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate
5690Sstevel@tonic-gate struct pln_cache {
5700Sstevel@tonic-gate char *pln_name;
5710Sstevel@tonic-gate enum mhd_ctlrtype_t ctype;
5720Sstevel@tonic-gate struct pln_cache *next;
5730Sstevel@tonic-gate };
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate static struct pln_cache *pln_cache_anchor = NULL;
5760Sstevel@tonic-gate static mutex_t mhd_pln_mx = DEFAULTMUTEX;
5770Sstevel@tonic-gate
5780Sstevel@tonic-gate /* singled threaded by caller */
5790Sstevel@tonic-gate static void
add_pln_cache(char * pln_name,enum mhd_ctlrtype_t ctype)5800Sstevel@tonic-gate add_pln_cache(
5810Sstevel@tonic-gate char *pln_name,
5820Sstevel@tonic-gate enum mhd_ctlrtype_t ctype
5830Sstevel@tonic-gate
5840Sstevel@tonic-gate )
5850Sstevel@tonic-gate {
5860Sstevel@tonic-gate struct pln_cache *p;
5870Sstevel@tonic-gate
5880Sstevel@tonic-gate p = Malloc(sizeof (*p));
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate p->pln_name = pln_name;
5910Sstevel@tonic-gate p->ctype = ctype;
5920Sstevel@tonic-gate p->next = pln_cache_anchor;
5930Sstevel@tonic-gate pln_cache_anchor = p;
5940Sstevel@tonic-gate }
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate /* singled threaded by caller */
5970Sstevel@tonic-gate static int
find_pln_cache(char * pln_name,enum mhd_ctlrtype_t * ctype_ret)5980Sstevel@tonic-gate find_pln_cache(
5990Sstevel@tonic-gate char *pln_name,
6000Sstevel@tonic-gate enum mhd_ctlrtype_t *ctype_ret
6010Sstevel@tonic-gate )
6020Sstevel@tonic-gate {
6030Sstevel@tonic-gate struct pln_cache *p;
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate for (p = pln_cache_anchor; p != NULL; p = p->next) {
6060Sstevel@tonic-gate if (strcmp(pln_name, p->pln_name) == 0) {
6070Sstevel@tonic-gate *ctype_ret = p->ctype;
6080Sstevel@tonic-gate return (1);
6090Sstevel@tonic-gate }
6100Sstevel@tonic-gate }
6110Sstevel@tonic-gate return (0);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate
6140Sstevel@tonic-gate static void
free_pln_cache(void)6150Sstevel@tonic-gate free_pln_cache(void)
6160Sstevel@tonic-gate {
6170Sstevel@tonic-gate struct pln_cache *p, *n = NULL;
6180Sstevel@tonic-gate
619*11053SSurya.Prakki@Sun.COM (void) mutex_lock(&mhd_pln_mx);
6200Sstevel@tonic-gate for (p = pln_cache_anchor; p != NULL; p = n) {
6210Sstevel@tonic-gate n = p->next;
6220Sstevel@tonic-gate Free(p->pln_name);
6230Sstevel@tonic-gate Free(p);
6240Sstevel@tonic-gate }
6250Sstevel@tonic-gate
6260Sstevel@tonic-gate pln_cache_anchor = NULL;
627*11053SSurya.Prakki@Sun.COM (void) mutex_unlock(&mhd_pln_mx);
6280Sstevel@tonic-gate }
6290Sstevel@tonic-gate
6300Sstevel@tonic-gate /*
6310Sstevel@tonic-gate * match on SSA Model 200.
6320Sstevel@tonic-gate */
6330Sstevel@tonic-gate static void
match_SSA200(mhd_drive_t * dp,char * path)6340Sstevel@tonic-gate match_SSA200(
6350Sstevel@tonic-gate mhd_drive_t *dp,
6360Sstevel@tonic-gate char *path
6370Sstevel@tonic-gate )
6380Sstevel@tonic-gate {
6390Sstevel@tonic-gate mhd_cinfo_t *cinfop = &dp->dr_drive_id.did_cinfo;
6400Sstevel@tonic-gate struct uscsi_cmd ucmd;
6410Sstevel@tonic-gate union scsi_cdb cdb;
6420Sstevel@tonic-gate struct scsi_inquiry inq;
6430Sstevel@tonic-gate int fd;
6440Sstevel@tonic-gate char *pln_ctlr_name;
6450Sstevel@tonic-gate enum mhd_ctlrtype_t ctype;
6460Sstevel@tonic-gate char *p;
6470Sstevel@tonic-gate
6480Sstevel@tonic-gate if ((pln_ctlr_name = get_pln_ctlr_name(path)) == NULL)
6490Sstevel@tonic-gate return;
6500Sstevel@tonic-gate
651*11053SSurya.Prakki@Sun.COM (void) mutex_lock(&mhd_pln_mx);
6520Sstevel@tonic-gate if (find_pln_cache(pln_ctlr_name, &ctype) == 1) {
653*11053SSurya.Prakki@Sun.COM (void) mutex_unlock(&mhd_pln_mx);
6540Sstevel@tonic-gate if (ctype != MHD_CTLR_SSA200)
6550Sstevel@tonic-gate return;
6560Sstevel@tonic-gate
6570Sstevel@tonic-gate /* over-ride for SSA200 */
6580Sstevel@tonic-gate cinfop->mhc_ctype = ctype;
6590Sstevel@tonic-gate cinfop->mhc_tray = cinfop->mhc_bus;
6600Sstevel@tonic-gate return;
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate if ((fd = open(pln_ctlr_name, (O_RDONLY|O_NDELAY), 0)) < 0) {
664*11053SSurya.Prakki@Sun.COM (void) mutex_unlock(&mhd_pln_mx);
6650Sstevel@tonic-gate Free(pln_ctlr_name);
6660Sstevel@tonic-gate return;
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate
6690Sstevel@tonic-gate (void) memset(&ucmd, 0, sizeof (ucmd));
6700Sstevel@tonic-gate (void) memset(&cdb, 0, sizeof (cdb));
6710Sstevel@tonic-gate (void) memset(&inq, 0, sizeof (inq));
6720Sstevel@tonic-gate cdb.scc_cmd = SCMD_INQUIRY;
6730Sstevel@tonic-gate cdb.g0_count0 = sizeof (inq);
6740Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
6750Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
6760Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&inq;
6770Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (inq);
6780Sstevel@tonic-gate ucmd.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_DIAGNOSE;
6790Sstevel@tonic-gate ucmd.uscsi_timeout = 30;
6800Sstevel@tonic-gate if (ioctl(fd, USCSICMD, &ucmd)) {
681*11053SSurya.Prakki@Sun.COM (void) mutex_unlock(&mhd_pln_mx);
6820Sstevel@tonic-gate (void) close(fd);
6830Sstevel@tonic-gate MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n",
6840Sstevel@tonic-gate pln_ctlr_name, errno));
6850Sstevel@tonic-gate Free(pln_ctlr_name);
6860Sstevel@tonic-gate return;
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate
6890Sstevel@tonic-gate (void) close(fd);
6900Sstevel@tonic-gate MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n", pln_ctlr_name));
6910Sstevel@tonic-gate
6920Sstevel@tonic-gate /* Make all trailing spaces be null char */
6930Sstevel@tonic-gate for (p = inq.inq_pid + sizeof (inq.inq_pid) - 1; p != inq.inq_pid;
6940Sstevel@tonic-gate p--) {
6950Sstevel@tonic-gate if (*p == '\0')
6960Sstevel@tonic-gate continue;
6970Sstevel@tonic-gate if (!isspace(*p))
6980Sstevel@tonic-gate break;
6990Sstevel@tonic-gate *p = '\0';
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate if (strncmp(inq.inq_pid, META_SSA200_PID, sizeof (inq.inq_pid)) != 0)
7030Sstevel@tonic-gate goto out;
7040Sstevel@tonic-gate
7050Sstevel@tonic-gate /* over-ride the ctype, and tray */
7060Sstevel@tonic-gate cinfop->mhc_ctype = MHD_CTLR_SSA200;
7070Sstevel@tonic-gate cinfop->mhc_tray = cinfop->mhc_bus;
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate out:
7100Sstevel@tonic-gate add_pln_cache(pln_ctlr_name, cinfop->mhc_ctype);
711*11053SSurya.Prakki@Sun.COM (void) mutex_unlock(&mhd_pln_mx);
7120Sstevel@tonic-gate }
7130Sstevel@tonic-gate
7140Sstevel@tonic-gate /*
7150Sstevel@tonic-gate * get controller info
7160Sstevel@tonic-gate */
7170Sstevel@tonic-gate static void
match_SSA100(mhd_drive_t * dp,char * path)7180Sstevel@tonic-gate match_SSA100(
7190Sstevel@tonic-gate mhd_drive_t *dp,
7200Sstevel@tonic-gate char *path
7210Sstevel@tonic-gate )
7220Sstevel@tonic-gate {
7230Sstevel@tonic-gate mhd_cinfo_t *cinfop = &dp->dr_drive_id.did_cinfo;
7240Sstevel@tonic-gate uint_t i;
7250Sstevel@tonic-gate char *p;
7260Sstevel@tonic-gate lloff_t wwn;
7270Sstevel@tonic-gate const char *fmt;
7280Sstevel@tonic-gate
7290Sstevel@tonic-gate /* update and lock controller map */
7300Sstevel@tonic-gate if (update_map() != 0)
7310Sstevel@tonic-gate return; /* give up */
7320Sstevel@tonic-gate assert(RW_WRITE_HELD(&ctlr_rw) || RW_READ_HELD(&ctlr_rw));
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate /* look for match in cache */
7350Sstevel@tonic-gate for (i = 0; (i < ctlr_num); ++i) {
7360Sstevel@tonic-gate mhd_ctlrmap_t *cmp = &ctlr_map[i];
7370Sstevel@tonic-gate
7380Sstevel@tonic-gate fmt = cmp->scan;
7390Sstevel@tonic-gate if ((regex(cmp->regexpr1, path) != NULL) &&
7400Sstevel@tonic-gate ((p = regex(cmp->regexpr2, path)) != NULL) &&
7410Sstevel@tonic-gate (sscanf(p, fmt,
7420Sstevel@tonic-gate (ulong_t *)&wwn._p._u, (ulong_t *)&wwn._p._l) == 2)) {
7430Sstevel@tonic-gate cinfop->mhc_ctype = MHD_CTLR_SSA100;
7440Sstevel@tonic-gate cinfop->mhc_tray = cmp->tray;
7450Sstevel@tonic-gate cinfop->mhc_bus = cmp->bus;
7460Sstevel@tonic-gate cinfop->mhc_wwn = wwn._f;
7470Sstevel@tonic-gate match_SSA200(dp, path);
7480Sstevel@tonic-gate break;
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate }
7510Sstevel@tonic-gate
7520Sstevel@tonic-gate /* unlock controller map */
7530Sstevel@tonic-gate unlock_map();
7540Sstevel@tonic-gate }
7550Sstevel@tonic-gate
7560Sstevel@tonic-gate /*
7570Sstevel@tonic-gate * get unique drive ID
7580Sstevel@tonic-gate */
7590Sstevel@tonic-gate static int
mhd_ident(mhd_drive_t * dp)7600Sstevel@tonic-gate mhd_ident(
7610Sstevel@tonic-gate mhd_drive_t *dp
7620Sstevel@tonic-gate )
7630Sstevel@tonic-gate {
7640Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
7650Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
7660Sstevel@tonic-gate struct uscsi_cmd ucmd;
7670Sstevel@tonic-gate union scsi_cdb cdb;
7680Sstevel@tonic-gate struct scsi_inquiry inq;
7697563SPrasad.Singamsetty@Sun.COM struct extvtoc vtoc_buf;
7700Sstevel@tonic-gate char path[MAXPATHLEN + 1];
7710Sstevel@tonic-gate int len;
7720Sstevel@tonic-gate int err;
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate /* check locks */
7750Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
7760Sstevel@tonic-gate assert(dp->dr_fd >= 0);
7770Sstevel@tonic-gate assert(dp->dr_state & DRIVE_IDENTING);
7780Sstevel@tonic-gate
7790Sstevel@tonic-gate /* reset ID */
7800Sstevel@tonic-gate (void) memset(&dp->dr_drive_id, 0, sizeof (dp->dr_drive_id));
7810Sstevel@tonic-gate
7820Sstevel@tonic-gate /* get serial number */
7830Sstevel@tonic-gate if (dp->dr_state & DRIVE_SERIALING) {
7840Sstevel@tonic-gate if (! serial)
7850Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
7860Sstevel@tonic-gate (void) memset(&ucmd, 0, sizeof (ucmd));
7870Sstevel@tonic-gate (void) memset(&cdb, 0, sizeof (cdb));
7880Sstevel@tonic-gate (void) memset(&inq, 0, sizeof (inq));
7890Sstevel@tonic-gate cdb.scc_cmd = SCMD_INQUIRY;
7900Sstevel@tonic-gate cdb.g0_count0 = sizeof (inq);
7910Sstevel@tonic-gate ucmd.uscsi_cdb = (caddr_t)&cdb;
7920Sstevel@tonic-gate ucmd.uscsi_cdblen = CDB_GROUP0;
7930Sstevel@tonic-gate ucmd.uscsi_bufaddr = (caddr_t)&inq;
7940Sstevel@tonic-gate ucmd.uscsi_buflen = sizeof (inq);
7950Sstevel@tonic-gate ucmd.uscsi_flags = USCSI_READ | USCSI_ISOLATE | USCSI_DIAGNOSE;
7960Sstevel@tonic-gate ucmd.uscsi_timeout = 30;
7970Sstevel@tonic-gate err = ioctl(dp->dr_fd, USCSICMD, &ucmd);
7980Sstevel@tonic-gate if (! serial)
7990Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
8000Sstevel@tonic-gate if (err != 0) {
8010Sstevel@tonic-gate MHDPRINTF((
8020Sstevel@tonic-gate "%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n",
8030Sstevel@tonic-gate dp->dr_rname, errno));
8040Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_SERIAL;
8050Sstevel@tonic-gate } else {
8060Sstevel@tonic-gate char *p, *e;
8070Sstevel@tonic-gate uint_t i;
8080Sstevel@tonic-gate
8090Sstevel@tonic-gate MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n",
8100Sstevel@tonic-gate dp->dr_rname));
8110Sstevel@tonic-gate dp->dr_drive_id.did_flags |= MHD_DID_SERIAL;
8120Sstevel@tonic-gate p = dp->dr_drive_id.did_serial;
8130Sstevel@tonic-gate e = p + sizeof (dp->dr_drive_id.did_serial);
8140Sstevel@tonic-gate for (i = 0;
8150Sstevel@tonic-gate ((i < sizeof (inq.inq_vid)) && (p < e)); ++i)
8160Sstevel@tonic-gate *p++ = inq.inq_vid[i];
8170Sstevel@tonic-gate for (i = 0;
8180Sstevel@tonic-gate ((i < sizeof (inq.inq_pid)) && (p < e)); ++i)
8190Sstevel@tonic-gate *p++ = inq.inq_pid[i];
8200Sstevel@tonic-gate for (i = 0;
8210Sstevel@tonic-gate ((i < sizeof (inq.inq_revision)) && (p < e)); ++i)
8220Sstevel@tonic-gate *p++ = inq.inq_revision[i];
8230Sstevel@tonic-gate for (i = 0;
8240Sstevel@tonic-gate ((i < sizeof (inq.inq_serial)) && (p < e)); ++i)
8250Sstevel@tonic-gate *p++ = inq.inq_serial[i];
8260Sstevel@tonic-gate assert(p == e);
8270Sstevel@tonic-gate for (p = dp->dr_drive_id.did_serial; (p < e); ++p) {
8280Sstevel@tonic-gate if (*p == '\0')
8290Sstevel@tonic-gate *p = ' ';
8300Sstevel@tonic-gate }
8310Sstevel@tonic-gate }
8320Sstevel@tonic-gate } else {
8330Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_SERIAL;
8340Sstevel@tonic-gate }
8350Sstevel@tonic-gate
8360Sstevel@tonic-gate /* get VTOC */
8370Sstevel@tonic-gate if (dp->dr_state & DRIVE_VTOCING) {
8380Sstevel@tonic-gate if (! serial)
8390Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
8400Sstevel@tonic-gate (void) memset(&vtoc_buf, 0, sizeof (vtoc_buf));
8417563SPrasad.Singamsetty@Sun.COM err = read_extvtoc(dp->dr_fd, &vtoc_buf);
8420Sstevel@tonic-gate if (! serial)
8430Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
8440Sstevel@tonic-gate if (err < 0) {
8457563SPrasad.Singamsetty@Sun.COM MHDPRINTF(("%s: read_extvtoc: failed errno %d\n",
8460Sstevel@tonic-gate dp->dr_rname, errno));
8470Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_TIME;
8480Sstevel@tonic-gate } else {
8497563SPrasad.Singamsetty@Sun.COM MHDPRINTF(("%s: read_extvtoc: success\n",
8500Sstevel@tonic-gate dp->dr_rname));
8510Sstevel@tonic-gate dp->dr_drive_id.did_flags |= MHD_DID_TIME;
8520Sstevel@tonic-gate dp->dr_drive_id.did_time = vtoc_buf.timestamp[0];
8530Sstevel@tonic-gate }
8540Sstevel@tonic-gate } else {
8550Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_TIME;
8560Sstevel@tonic-gate }
8570Sstevel@tonic-gate
8580Sstevel@tonic-gate /* get controller info */
8590Sstevel@tonic-gate if (dp->dr_state & DRIVE_CINFOING) {
8600Sstevel@tonic-gate if (! serial)
8610Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
8620Sstevel@tonic-gate len = readlink(dp->dr_rname0, path, (sizeof (path) - 1));
8630Sstevel@tonic-gate if (! serial)
8640Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
8650Sstevel@tonic-gate if (len >= sizeof (path)) {
8660Sstevel@tonic-gate len = -1;
8670Sstevel@tonic-gate errno = ENAMETOOLONG;
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate if (len < 0) {
8700Sstevel@tonic-gate MHDPRINTF(("%s: readlink: failed errno %d\n",
8710Sstevel@tonic-gate dp->dr_rname0, errno));
8720Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_CINFO;
8730Sstevel@tonic-gate } else {
8740Sstevel@tonic-gate MHDPRINTF(("%s: readlink: success\n",
8750Sstevel@tonic-gate dp->dr_rname0));
8760Sstevel@tonic-gate dp->dr_drive_id.did_flags |= MHD_DID_CINFO;
8770Sstevel@tonic-gate (void) memset(&dp->dr_drive_id.did_cinfo, 0,
8780Sstevel@tonic-gate sizeof (dp->dr_drive_id.did_cinfo));
8790Sstevel@tonic-gate match_SSA100(dp, path);
8800Sstevel@tonic-gate }
8810Sstevel@tonic-gate } else {
8820Sstevel@tonic-gate dp->dr_drive_id.did_flags &= ~MHD_DID_CINFO;
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate
8850Sstevel@tonic-gate /* return success */
8860Sstevel@tonic-gate (void) mhd_state_clr(dp, DRIVE_IDENTING, NULL);
8870Sstevel@tonic-gate return (0);
8880Sstevel@tonic-gate }
8890Sstevel@tonic-gate
8900Sstevel@tonic-gate /*
8910Sstevel@tonic-gate * disk thread
8920Sstevel@tonic-gate */
8930Sstevel@tonic-gate static void
mhd_drive_thread(mhd_drive_t * dp)8940Sstevel@tonic-gate mhd_drive_thread(
8950Sstevel@tonic-gate mhd_drive_t *dp
8960Sstevel@tonic-gate )
8970Sstevel@tonic-gate {
8980Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
8990Sstevel@tonic-gate
9000Sstevel@tonic-gate /* wait for dp->dr_thread to be filled in */
9010Sstevel@tonic-gate assert(sp != NULL);
9020Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
9030Sstevel@tonic-gate
9040Sstevel@tonic-gate /* forever */
9050Sstevel@tonic-gate for (;;) {
9060Sstevel@tonic-gate /* check locks */
9070Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
9080Sstevel@tonic-gate assert(dp->dr_thread == thr_self());
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate /* check for changed set */
9110Sstevel@tonic-gate if (sp != dp->dr_sp) {
9120Sstevel@tonic-gate MHDPRINTF2(("%s: changed from set '%s' to '%s'\n",
9130Sstevel@tonic-gate dp->dr_rname, sp->sr_name, dp->dr_sp->sr_name));
9140Sstevel@tonic-gate
9150Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
9160Sstevel@tonic-gate sp = dp->dr_sp;
9170Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
9180Sstevel@tonic-gate }
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate /* open drive, if necessary */
9210Sstevel@tonic-gate if ((dp->dr_fd < 0) && (! (DRIVE_IS_IDLE(dp) ||
9220Sstevel@tonic-gate (dp->dr_state == DRIVE_IDLING)))) {
9230Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate if (! serial)
9260Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
9270Sstevel@tonic-gate dp->dr_fd = open(dp->dr_rname0, (O_RDWR|O_NDELAY), 0);
9280Sstevel@tonic-gate if (! serial)
9290Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
9300Sstevel@tonic-gate if (dp->dr_fd < 0) {
9310Sstevel@tonic-gate mhd_perror("%s: open", dp->dr_rname);
9320Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_ERRORED, NULL);
9330Sstevel@tonic-gate dp->dr_errnum = errno;
9340Sstevel@tonic-gate }
9350Sstevel@tonic-gate continue;
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate
9380Sstevel@tonic-gate /* dispatch */
9390Sstevel@tonic-gate switch (dp->dr_state) {
9400Sstevel@tonic-gate case DRIVE_IDLE:
9410Sstevel@tonic-gate MHDPRINTF1(("%s: IDLE\n", dp->dr_rname));
9420Sstevel@tonic-gate break;
9430Sstevel@tonic-gate
9440Sstevel@tonic-gate case DRIVE_ERRORED:
9450Sstevel@tonic-gate MHDPRINTF1(("%s: ERRORED %d\n",
9460Sstevel@tonic-gate dp->dr_rname, dp->dr_errnum));
9470Sstevel@tonic-gate break;
9480Sstevel@tonic-gate
9490Sstevel@tonic-gate case DRIVE_IDLING:
9500Sstevel@tonic-gate (void) mhd_state(dp, DRIVE_IDLE, NULL);
9510Sstevel@tonic-gate continue;
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate case DRIVE_RESERVING:
9540Sstevel@tonic-gate MHDPRINTF1(("%s: RESERVING\n", dp->dr_rname));
9550Sstevel@tonic-gate (void) mhd_reserve(dp);
9560Sstevel@tonic-gate assert(DRIVE_IS_IDLE(dp));
9570Sstevel@tonic-gate continue;
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate case DRIVE_FAILFASTING:
9600Sstevel@tonic-gate MHDPRINTF1(("%s: FAILFASTING\n", dp->dr_rname));
9610Sstevel@tonic-gate (void) mhd_failfast(dp);
9620Sstevel@tonic-gate assert(DRIVE_IS_IDLE(dp));
9630Sstevel@tonic-gate continue;
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate case DRIVE_RELEASING:
9660Sstevel@tonic-gate MHDPRINTF1(("%s: RELEASING\n", dp->dr_rname));
9670Sstevel@tonic-gate (void) mhd_release(dp);
9680Sstevel@tonic-gate assert(DRIVE_IS_IDLE(dp));
9690Sstevel@tonic-gate continue;
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate /* non-exclusive states */
9720Sstevel@tonic-gate default:
9730Sstevel@tonic-gate assert(! (dp->dr_state &
9740Sstevel@tonic-gate (DRIVE_EXCLUSIVE_STATES & ~DRIVE_ERRORED)));
9750Sstevel@tonic-gate if (dp->dr_state & (DRIVE_PROBING | DRIVE_STATUSING)) {
9760Sstevel@tonic-gate MHDPRINTF1(("%s: PROBING\n", dp->dr_rname));
9770Sstevel@tonic-gate (void) mhd_probe(dp);
9780Sstevel@tonic-gate assert(! (dp->dr_state & DRIVE_STATUSING));
9790Sstevel@tonic-gate }
9800Sstevel@tonic-gate if (dp->dr_state & DRIVE_IDENTING) {
9810Sstevel@tonic-gate MHDPRINTF1(("%s: IDENTING\n", dp->dr_rname));
9820Sstevel@tonic-gate (void) mhd_ident(dp);
9830Sstevel@tonic-gate assert(! (dp->dr_state & DRIVE_IDENTING));
9840Sstevel@tonic-gate continue; /* in case we're probing */
9850Sstevel@tonic-gate }
9860Sstevel@tonic-gate break;
9870Sstevel@tonic-gate }
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate /* close drive, if possible */
9900Sstevel@tonic-gate if ((dp->dr_fd >= 0) && (DRIVE_IS_IDLE(dp))) {
9910Sstevel@tonic-gate int serial = (sp->sr_options & MHD_SERIAL);
9920Sstevel@tonic-gate
9930Sstevel@tonic-gate if (! serial)
9940Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
9950Sstevel@tonic-gate (void) close(dp->dr_fd); /* sd/ssd bug */
9960Sstevel@tonic-gate if (! serial)
9970Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
9980Sstevel@tonic-gate dp->dr_fd = -1;
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate /* wake up anybody waiting */
10020Sstevel@tonic-gate mhd_cv_broadcast(&sp->sr_cv);
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate /* see if anything happened */
10050Sstevel@tonic-gate if (! DRIVE_IS_IDLE(dp))
10060Sstevel@tonic-gate continue;
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate /* wait for something to happen */
10090Sstevel@tonic-gate if (! (dp->dr_state & DRIVE_PROBING)) {
10100Sstevel@tonic-gate mhd_cv_wait(&dp->dr_cv, &sp->sr_mx);
10110Sstevel@tonic-gate } else {
10120Sstevel@tonic-gate mhd_cv_timedwait(&dp->dr_cv, &sp->sr_mx,
10130Sstevel@tonic-gate (sp->sr_timeouts.mh_ff / 2));
10140Sstevel@tonic-gate }
10150Sstevel@tonic-gate }
10160Sstevel@tonic-gate }
10170Sstevel@tonic-gate
10180Sstevel@tonic-gate /*
10190Sstevel@tonic-gate * kick off drive thread
10200Sstevel@tonic-gate */
10210Sstevel@tonic-gate static int
mhd_thread_create(mhd_drive_t * dp,mhd_error_t * mhep)10220Sstevel@tonic-gate mhd_thread_create(
10230Sstevel@tonic-gate mhd_drive_t *dp,
10240Sstevel@tonic-gate mhd_error_t *mhep
10250Sstevel@tonic-gate )
10260Sstevel@tonic-gate {
10270Sstevel@tonic-gate mhd_drive_set_t *sp = dp->dr_sp;
10280Sstevel@tonic-gate thread_t thread = NULL;
10290Sstevel@tonic-gate int rval = 0;
10300Sstevel@tonic-gate
10310Sstevel@tonic-gate /* check lock and thread */
10320Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
10330Sstevel@tonic-gate assert(dp->dr_thread == NULL);
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate /* create thread */
10360Sstevel@tonic-gate if (thr_create(NULL, 0, (void *(*)(void *))mhd_drive_thread,
10370Sstevel@tonic-gate (void *)dp, (THR_DETACHED | THR_BOUND), &thread) != 0) {
10380Sstevel@tonic-gate rval = mhd_error(mhep, errno, "thr_create");
10390Sstevel@tonic-gate } else {
10400Sstevel@tonic-gate assert(thread != NULL);
10410Sstevel@tonic-gate dp->dr_thread = thread;
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate /* return success */
10450Sstevel@tonic-gate return (rval);
10460Sstevel@tonic-gate }
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate /*
10490Sstevel@tonic-gate * peel off s%u from name
10500Sstevel@tonic-gate */
10510Sstevel@tonic-gate static char *
diskname(const char * sname)10520Sstevel@tonic-gate diskname(
10530Sstevel@tonic-gate const char *sname
10540Sstevel@tonic-gate )
10550Sstevel@tonic-gate {
10560Sstevel@tonic-gate char *dname;
10570Sstevel@tonic-gate char *p, *e;
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate /* duplicate name */
10600Sstevel@tonic-gate if ((dname = Strdup(sname)) == NULL)
10610Sstevel@tonic-gate return (NULL);
10620Sstevel@tonic-gate
10630Sstevel@tonic-gate /* gobble number and 's' */
10640Sstevel@tonic-gate p = e = dname + strlen(dname) - 1;
10650Sstevel@tonic-gate for (; (p > dname); --p) {
10660Sstevel@tonic-gate if (!isdigit(*p))
10670Sstevel@tonic-gate break;
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate if ((p == e) || (p <= dname)) {
10700Sstevel@tonic-gate Free(dname);
10710Sstevel@tonic-gate return (NULL);
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate if (*p-- != 's') {
10740Sstevel@tonic-gate Free(dname);
10750Sstevel@tonic-gate return (NULL);
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate if ((p <= dname) || (!isdigit(*p))) {
10780Sstevel@tonic-gate Free(dname);
10790Sstevel@tonic-gate return (NULL);
10800Sstevel@tonic-gate }
10810Sstevel@tonic-gate *(++p) = '\0';
10820Sstevel@tonic-gate return (dname);
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate * create new drive
10870Sstevel@tonic-gate */
10880Sstevel@tonic-gate mhd_drive_t *
mhd_create_drive(mhd_drive_set_t * sp,char * rname,int * fdp,mhd_error_t * mhep)10890Sstevel@tonic-gate mhd_create_drive(
10900Sstevel@tonic-gate mhd_drive_set_t *sp, /* new set */
10910Sstevel@tonic-gate char *rname, /* raw drive name */
10920Sstevel@tonic-gate int *fdp, /* open device or -1 */
10930Sstevel@tonic-gate mhd_error_t *mhep /* returned error */
10940Sstevel@tonic-gate )
10950Sstevel@tonic-gate {
10960Sstevel@tonic-gate mhd_drive_t *dp = NULL;
10970Sstevel@tonic-gate char *rname0 = NULL;
10980Sstevel@tonic-gate
10990Sstevel@tonic-gate /* check locks */
11000Sstevel@tonic-gate assert(MUTEX_HELD(&sp->sr_mx));
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate /* if drive already exists */
11030Sstevel@tonic-gate if ((dp = mhd_find_drive(rname)) != NULL) {
11040Sstevel@tonic-gate mhd_drive_set_t *oldsp = dp->dr_sp;
11050Sstevel@tonic-gate
11060Sstevel@tonic-gate /* if set has changed, move drive */
11070Sstevel@tonic-gate if (oldsp != sp) {
11080Sstevel@tonic-gate mhd_mx_unlock(&sp->sr_mx);
11090Sstevel@tonic-gate mhd_mx_lock(&oldsp->sr_mx);
11100Sstevel@tonic-gate if (mhd_idle(dp, mhep) != 0) {
11110Sstevel@tonic-gate mhd_mx_unlock(&oldsp->sr_mx);
11120Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
11130Sstevel@tonic-gate return (NULL);
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate mhd_del_drive_from_set(dp);
11160Sstevel@tonic-gate mhd_mx_unlock(&oldsp->sr_mx);
11170Sstevel@tonic-gate mhd_mx_lock(&sp->sr_mx);
11180Sstevel@tonic-gate mhd_add_drive_to_set(sp, dp);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate /* return drive */
11220Sstevel@tonic-gate return (dp);
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate
11250Sstevel@tonic-gate /* build slice0 */
11260Sstevel@tonic-gate rname0 = Malloc(strlen(rname) + strlen("s0") + 1);
11270Sstevel@tonic-gate (void) strcpy(rname0, rname);
11280Sstevel@tonic-gate (void) strcat(rname0, "s0");
11290Sstevel@tonic-gate
11300Sstevel@tonic-gate /* allocate and initialize drive */
11310Sstevel@tonic-gate dp = Zalloc(sizeof (*dp));
11320Sstevel@tonic-gate dp->dr_sp = sp;
11330Sstevel@tonic-gate dp->dr_rname = Strdup(rname);
11340Sstevel@tonic-gate dp->dr_rname0 = rname0;
11350Sstevel@tonic-gate mhd_cv_init(&dp->dr_cv);
11360Sstevel@tonic-gate dp->dr_thread = NULL;
11370Sstevel@tonic-gate dp->dr_fd = -1;
11380Sstevel@tonic-gate dp->dr_state = DRIVE_IDLE;
11390Sstevel@tonic-gate
11400Sstevel@tonic-gate /* steal open drive */
11410Sstevel@tonic-gate if ((fdp != NULL) && (*fdp >= 0)) {
11420Sstevel@tonic-gate dp->dr_fd = *fdp;
11430Sstevel@tonic-gate *fdp = -1;
11440Sstevel@tonic-gate }
11450Sstevel@tonic-gate
11460Sstevel@tonic-gate /* add to set */
11470Sstevel@tonic-gate mhd_add_drive_to_set(sp, dp);
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate /* kick off drive thread */
11500Sstevel@tonic-gate if (mhd_thread_create(dp, mhep) != 0) {
11510Sstevel@tonic-gate Free(dp->dr_rname0);
11520Sstevel@tonic-gate Free(dp->dr_rname);
11530Sstevel@tonic-gate Free(dp);
11540Sstevel@tonic-gate return (NULL);
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate /* return drive */
11580Sstevel@tonic-gate return (dp);
11590Sstevel@tonic-gate }
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate /*
11620Sstevel@tonic-gate * find or create drive in any set
11630Sstevel@tonic-gate */
11640Sstevel@tonic-gate static mhd_drive_t *
mhd_create_drive_anyset(char * rname,int * fdp,mhd_error_t * mhep)11650Sstevel@tonic-gate mhd_create_drive_anyset(
11660Sstevel@tonic-gate char *rname,
11670Sstevel@tonic-gate int *fdp,
11680Sstevel@tonic-gate mhd_error_t *mhep
11690Sstevel@tonic-gate )
11700Sstevel@tonic-gate {
11710Sstevel@tonic-gate mhd_drive_set_t *null_sp = mhd_create_set(NULL, 0, NULL, NULL);
11720Sstevel@tonic-gate mhd_drive_t *dp;
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate /* check locks */
11750Sstevel@tonic-gate assert(null_sp != NULL);
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate /* drive already exists */
11780Sstevel@tonic-gate if ((dp = mhd_find_drive(rname)) != NULL)
11790Sstevel@tonic-gate return (dp);
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate /* add to null set */
11820Sstevel@tonic-gate mhd_mx_lock(&null_sp->sr_mx);
11830Sstevel@tonic-gate dp = mhd_create_drive(null_sp, rname, fdp, mhep);
11840Sstevel@tonic-gate mhd_mx_unlock(&null_sp->sr_mx);
11850Sstevel@tonic-gate
11860Sstevel@tonic-gate /* return drive */
11870Sstevel@tonic-gate return (dp);
11880Sstevel@tonic-gate }
11890Sstevel@tonic-gate
11900Sstevel@tonic-gate /*
11910Sstevel@tonic-gate * process a file in the tree walk
11920Sstevel@tonic-gate */
11930Sstevel@tonic-gate static int
do_disk(const char * path,const struct stat * statp,int type)11940Sstevel@tonic-gate do_disk(
11950Sstevel@tonic-gate const char *path,
11960Sstevel@tonic-gate const struct stat *statp,
11970Sstevel@tonic-gate int type
11980Sstevel@tonic-gate )
11990Sstevel@tonic-gate {
12000Sstevel@tonic-gate char *dname = NULL;
12010Sstevel@tonic-gate int fd = -1;
12020Sstevel@tonic-gate struct dk_cinfo cinfo;
12030Sstevel@tonic-gate mhd_error_t status = mhd_null_error;
12040Sstevel@tonic-gate
12050Sstevel@tonic-gate /* skip all but character devices */
12060Sstevel@tonic-gate if ((type != FTW_F) || (! S_ISCHR(statp->st_mode)) ||
12070Sstevel@tonic-gate ((dname = diskname(path)) == NULL)) {
12080Sstevel@tonic-gate return (0);
12090Sstevel@tonic-gate }
12100Sstevel@tonic-gate
12110Sstevel@tonic-gate /* see if drive already exists */
12120Sstevel@tonic-gate if (mhd_find_drive(dname) != NULL)
12130Sstevel@tonic-gate return (0);
12140Sstevel@tonic-gate
12150Sstevel@tonic-gate /* see if device is a disk */
12160Sstevel@tonic-gate if ((fd = open(path, (O_RDONLY|O_NDELAY), 0)) < 0)
12170Sstevel@tonic-gate goto out;
12180Sstevel@tonic-gate if (ioctl(fd, DKIOCINFO, &cinfo) != 0) {
12190Sstevel@tonic-gate switch (errno) {
12200Sstevel@tonic-gate case EINVAL:
12210Sstevel@tonic-gate case ENOTTY:
12220Sstevel@tonic-gate break;
12230Sstevel@tonic-gate default:
12240Sstevel@tonic-gate mhd_perror("DKIOCINFO: %s", path);
12250Sstevel@tonic-gate break;
12260Sstevel@tonic-gate }
12270Sstevel@tonic-gate goto out;
12280Sstevel@tonic-gate }
12290Sstevel@tonic-gate
12300Sstevel@tonic-gate /* skip CDROMs */
12310Sstevel@tonic-gate if (cinfo.dki_ctype == DKC_CDROM) {
12320Sstevel@tonic-gate (void) close(fd);
12330Sstevel@tonic-gate Free(dname);
12340Sstevel@tonic-gate return (0);
12350Sstevel@tonic-gate }
12360Sstevel@tonic-gate
12370Sstevel@tonic-gate /* put disk on list */
12380Sstevel@tonic-gate if (mhd_create_drive_anyset(dname, &fd, &status) == NULL) {
12390Sstevel@tonic-gate mhde_perror(&status, "");
12400Sstevel@tonic-gate goto out;
12410Sstevel@tonic-gate }
12420Sstevel@tonic-gate
12430Sstevel@tonic-gate /* cleanup, return success (no matter what) */
12440Sstevel@tonic-gate out:
12450Sstevel@tonic-gate if (dname != NULL)
12460Sstevel@tonic-gate Free(dname);
12470Sstevel@tonic-gate if (fd >= 0)
12480Sstevel@tonic-gate (void) close(fd);
12490Sstevel@tonic-gate mhd_clrerror(&status);
12500Sstevel@tonic-gate return (0);
12510Sstevel@tonic-gate }
12520Sstevel@tonic-gate
12530Sstevel@tonic-gate /*
12540Sstevel@tonic-gate * find or create all the drives under a given directory
12550Sstevel@tonic-gate */
12560Sstevel@tonic-gate int
mhd_create_drives(char * path,mhd_error_t * mhep)12570Sstevel@tonic-gate mhd_create_drives(
12580Sstevel@tonic-gate char *path,
12590Sstevel@tonic-gate mhd_error_t *mhep
12600Sstevel@tonic-gate )
12610Sstevel@tonic-gate {
12620Sstevel@tonic-gate /* default */
12630Sstevel@tonic-gate if ((path == NULL) || (*path == '\0'))
12640Sstevel@tonic-gate path = "/dev/rdsk";
12650Sstevel@tonic-gate
12660Sstevel@tonic-gate free_pln_cache();
12670Sstevel@tonic-gate
12680Sstevel@tonic-gate /* walk the directory, adding disks */
12690Sstevel@tonic-gate if (ftw(path, do_disk, 5) != 0)
12700Sstevel@tonic-gate return (mhd_error(mhep, errno, path));
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate /* return success */
12730Sstevel@tonic-gate return (0);
12740Sstevel@tonic-gate }
1275