xref: /onnv-gate/usr/src/cmd/lvm/rpc.metamhd/mhd_drive.c (revision 11053:f33a1c7f3155)
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