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