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