4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include "mhd_local.h"
31 #include <sys/scsi/impl/uscsi.h>
32 #include <sys/scsi/generic/commands.h>
33 #include <sys/scsi/generic/inquiry.h>
42 const mhd_drive_list_t mhd_null_list
= MHD_NULL_LIST
;
49 mhd_drive_list_t
*dlp
,
53 /* add drive to list */
54 if (dlp
->dl_ndrive
>= dlp
->dl_alloc
) {
56 dlp
->dl_drives
= Realloc(dlp
->dl_drives
,
57 (dlp
->dl_alloc
* sizeof (*dlp
->dl_drives
)));
59 dlp
->dl_drives
[dlp
->dl_ndrive
++] = dp
;
63 * delete drive from list
67 mhd_drive_list_t
*dlp
,
73 /* delete drive from list */
74 for (i
= 0; (i
< dlp
->dl_ndrive
); ++i
) {
75 if (dlp
->dl_drives
[i
] == dp
)
78 assert(dlp
->dl_drives
[i
] == dp
);
79 for (/* void */; (i
< dlp
->dl_ndrive
); ++i
)
80 dlp
->dl_drives
[i
] = dlp
->dl_drives
[i
+ 1];
92 if (dlp
->dl_drives
!= NULL
)
94 (void) memset(dlp
, 0, sizeof (*dlp
));
98 * manipulate drive state
103 mhd_state_t new_state
,
107 mhd_drive_set_t
*sp
= dp
->dr_sp
;
108 mhd_state_t old_state
= dp
->dr_state
;
111 assert(MUTEX_HELD(&sp
->sr_mx
));
113 /* set state and kick thread */
114 MHDPRINTF2(("%s: state 0x%x now 0x%x\n",
115 dp
->dr_rname
, dp
->dr_state
, new_state
));
116 dp
->dr_state
= new_state
;
117 mhd_cv_broadcast(&dp
->dr_cv
);
119 /* if this is the last PROBING drive, disable any failfast */
120 if ((old_state
& DRIVE_PROBING
) && (! (new_state
& DRIVE_PROBING
))) {
121 mhd_drive_list_t
*dlp
= &sp
->sr_drives
;
124 for (cnt
= 0, i
= 0; (i
< dlp
->dl_ndrive
); ++i
) {
125 if (dlp
->dl_drives
[i
]->dr_state
& DRIVE_PROBING
)
129 mhd_error_t status
= mhd_null_error
;
133 if (mhd_ff_disarm(sp
, mhep
) != 0) {
134 if (mhep
== &status
) {
135 mhde_perror(mhep
, dp
->dr_rname
);
150 mhd_state_t new_state
,
154 return (mhd_state(dp
, (dp
->dr_state
| new_state
), mhep
));
160 mhd_state_t new_state
,
164 return (mhd_state(dp
, (dp
->dr_state
& ~new_state
), mhep
));
176 mhd_drive_set_t
*sp
= dp
->dr_sp
;
179 assert(MUTEX_HELD(&sp
->sr_mx
));
181 /* wait for thread to idle */
183 if (DRIVE_IS_IDLE(dp
))
185 if (mhd_state(dp
, DRIVE_IDLING
, mhep
) != 0)
187 (void) mhd_cv_wait(&sp
->sr_cv
, &sp
->sr_mx
);
199 mhd_drive_set_t
*sp
= dp
->dr_sp
;
200 int serial
= (sp
->sr_options
& MHD_SERIAL
);
201 mhd_mhioctkown_t
*tkp
= &sp
->sr_timeouts
.mh_tk
;
202 struct mhioctkown tkown
;
206 assert(MUTEX_HELD(&sp
->sr_mx
));
207 assert(dp
->dr_fd
>= 0);
208 assert(dp
->dr_state
== DRIVE_RESERVING
);
211 (void) memset(&tkown
, 0, sizeof (tkown
));
212 tkown
.reinstate_resv_delay
= tkp
->reinstate_resv_delay
;
213 tkown
.min_ownership_delay
= tkp
->min_ownership_delay
;
214 tkown
.max_ownership_delay
= tkp
->max_ownership_delay
;
218 mhd_mx_unlock(&sp
->sr_mx
);
219 err
= ioctl(dp
->dr_fd
, MHIOCTKOWN
, &tkown
);
221 mhd_mx_lock(&sp
->sr_mx
);
223 mhd_perror("%s: MHIOCTKOWN", dp
->dr_rname
);
224 (void) mhd_state(dp
, DRIVE_ERRORED
, NULL
);
225 dp
->dr_errnum
= errno
;
230 MHDPRINTF(("%s: MHIOCTKOWN: succeeded\n", dp
->dr_rname
));
231 (void) mhd_state(dp
, DRIVE_IDLE
, NULL
);
243 mhd_drive_set_t
*sp
= dp
->dr_sp
;
244 int serial
= (sp
->sr_options
& MHD_SERIAL
);
245 int ff
= sp
->sr_timeouts
.mh_ff
;
246 char *release
= ((ff
== 0) ? " (release)" : "");
250 assert(MUTEX_HELD(&sp
->sr_mx
));
251 assert(dp
->dr_fd
>= 0);
252 assert(dp
->dr_state
== DRIVE_FAILFASTING
);
256 mhd_mx_unlock(&sp
->sr_mx
);
257 err
= ioctl(dp
->dr_fd
, MHIOCENFAILFAST
, &ff
);
259 mhd_mx_lock(&sp
->sr_mx
);
261 mhd_perror("%s: MHIOCENFAILFAST%s", dp
->dr_rname
, release
);
262 (void) mhd_state(dp
, DRIVE_ERRORED
, NULL
);
263 dp
->dr_errnum
= errno
;
268 MHDPRINTF(("%s: MHIOCENFAILFAST%s: succeeded\n",
269 dp
->dr_rname
, release
));
270 (void) mhd_state(dp
, DRIVE_IDLE
, NULL
);
282 mhd_drive_set_t
*sp
= dp
->dr_sp
;
283 int serial
= (sp
->sr_options
& MHD_SERIAL
);
284 int ff
= 0; /* disable failfast */
288 assert(MUTEX_HELD(&sp
->sr_mx
));
289 assert(dp
->dr_fd
>= 0);
290 assert(dp
->dr_state
== DRIVE_RELEASING
);
292 /* disable failfast */
294 mhd_mx_unlock(&sp
->sr_mx
);
295 err
= ioctl(dp
->dr_fd
, MHIOCENFAILFAST
, &ff
);
297 mhd_mx_lock(&sp
->sr_mx
);
299 mhd_perror("%s: MHIOCENFAILFAST (release)", dp
->dr_rname
);
300 (void) mhd_state(dp
, DRIVE_ERRORED
, NULL
);
301 dp
->dr_errnum
= errno
;
304 MHDPRINTF(("%s: MHIOCENFAILFAST (release): succeeded\n",
309 mhd_mx_unlock(&sp
->sr_mx
);
310 err
= ioctl(dp
->dr_fd
, MHIOCRELEASE
, NULL
);
312 mhd_mx_lock(&sp
->sr_mx
);
314 mhd_perror("%s: MHIOCRELEASE", dp
->dr_rname
);
315 (void) mhd_state(dp
, DRIVE_ERRORED
, NULL
);
316 dp
->dr_errnum
= errno
;
321 MHDPRINTF(("%s: MHIOCRELEASE: succeeded\n", dp
->dr_rname
));
322 (void) mhd_state(dp
, DRIVE_IDLE
, NULL
);
334 mhd_drive_set_t
*sp
= dp
->dr_sp
;
335 int serial
= (sp
->sr_options
& MHD_SERIAL
);
340 assert(MUTEX_HELD(&sp
->sr_mx
));
341 assert(dp
->dr_fd
>= 0);
342 assert(dp
->dr_state
& (DRIVE_PROBING
| DRIVE_STATUSING
));
344 /* get status (we may get dumped from PROBING here) */
346 mhd_mx_unlock(&sp
->sr_mx
);
347 err
= ioctl(dp
->dr_fd
, MHIOCSTATUS
, NULL
);
350 mhd_mx_lock(&sp
->sr_mx
);
351 if (! (dp
->dr_state
& (DRIVE_PROBING
| DRIVE_STATUSING
)))
355 if (dp
->dr_state
& DRIVE_STATUSING
) {
357 MHDPRINTF(("%s: MHIOCSTATUS: reserved\n",
359 dp
->dr_errnum
= MHD_E_RESERVED
;
360 } else if (err
!= 0) {
361 mhd_perror("%s: MHIOCSTATUS", dp
->dr_rname
);
362 dp
->dr_errnum
= errno
;
364 MHDPRINTF(("%s: MHIOCSTATUS: available\n",
368 (void) mhd_state_clr(dp
, DRIVE_STATUSING
, NULL
);
371 /* update time or die */
372 if (dp
->dr_state
& DRIVE_PROBING
) {
373 /* check our drive */
376 } else if (err
== 1) {
377 mhd_eprintf("%s: %s: reservation conflict\n",
378 sp
->sr_name
, dp
->dr_rname
);
382 /* check other drives */
391 * cached controller map
401 static rwlock_t ctlr_rw
= DEFAULTRWLOCK
;
402 static time_t ctlr_mtime
= 0;
403 static size_t ctlr_num
= 0;
404 static mhd_ctlrmap_t
*ctlr_map
= NULL
;
407 * free up controller map
414 assert(RW_WRITE_HELD(&ctlr_rw
));
416 for (i
= 0; (i
< ctlr_num
); ++i
) {
417 mhd_ctlrmap_t
*cmp
= &ctlr_map
[i
];
419 if (cmp
->regexpr1
!= NULL
)
421 if (cmp
->regexpr2
!= NULL
)
423 if (cmp
->scan
!= NULL
)
426 if (ctlr_map
!= NULL
)
433 * unlock controller map
438 assert(RW_WRITE_HELD(&ctlr_rw
) | RW_READ_HELD(&ctlr_rw
));
440 mhd_rw_unlock(&ctlr_rw
);
444 * update controller map and lock it
451 char line
[256], expr1
[256], expr2
[256], scan
[256];
455 /* see if map file has changed */
456 mhd_rw_rdlock(&ctlr_rw
);
457 if (stat(METACTLRMAP
, &statbuf
) != 0) {
458 mhd_perror(METACTLRMAP
);
461 if (statbuf
.st_mtime
== ctlr_mtime
) {
466 /* trade up to writer lock, check again */
467 mhd_rw_unlock(&ctlr_rw
);
468 mhd_rw_wrlock(&ctlr_rw
);
469 if (statbuf
.st_mtime
== ctlr_mtime
) {
474 mhd_eprintf("updating controller map\n");
475 ctlr_mtime
= statbuf
.st_mtime
;
477 /* toss existing cache */
480 /* parse md.ctlrmap */
481 if ((fp
= fopen(METACTLRMAP
, "r")) == NULL
) {
482 mhd_perror(METACTLRMAP
);
486 while (fgets(line
, sizeof (line
), fp
) != NULL
) {
487 char *regexpr1
= NULL
;
488 char *regexpr2
= NULL
;
491 /* skip blank lines and comments */
492 if ((line
[0] == '\0') || (line
[0] == '\n') || (line
[0] == '#'))
496 if (((sscanf(line
, "\"%[^\"]\" %u %u \"%[^\"]\" \"%[^\"]\"",
497 expr1
, &tray
, &bus
, expr2
, scan
)) != 5) ||
498 ((regexpr1
= regcmp(expr1
, 0)) == NULL
) ||
499 ((regexpr2
= regcmp(expr2
, 0)) == NULL
)) {
500 mhd_eprintf("%s: bad regex(es) '%s'\n",
502 if (regexpr1
!= NULL
)
504 if (regexpr2
!= NULL
)
510 ctlr_map
= Realloc(ctlr_map
,
511 ((ctlr_num
+ 1) * sizeof (*ctlr_map
)));
512 cmp
= &ctlr_map
[ctlr_num
++];
513 cmp
->regexpr1
= regexpr1
;
516 cmp
->regexpr2
= regexpr2
;
517 cmp
->scan
= Strdup(scan
);
520 mhd_perror(METACTLRMAP
);
524 if (fclose(fp
) != 0) {
525 mhd_perror(METACTLRMAP
);
535 mhd_rw_unlock(&ctlr_rw
);
546 char *devicesname
, *p
;
547 char retval
[MAXPATHLEN
];
549 devicesname
= Strdup(path
);
550 if ((p
= strrchr(devicesname
, '/')) == NULL
) {
555 /* strip off the "ssd@..." portion of the devices name */
558 /* strip off the "../../" in front of "devices" */
559 if ((p
= strstr(devicesname
, "/devices/")) == NULL
) {
564 (void) snprintf(retval
, sizeof (retval
), "%s:ctlr", p
);
566 return (Strdup(retval
));
571 enum mhd_ctlrtype_t ctype
;
572 struct pln_cache
*next
;
575 static struct pln_cache
*pln_cache_anchor
= NULL
;
576 static mutex_t mhd_pln_mx
= DEFAULTMUTEX
;
578 /* singled threaded by caller */
582 enum mhd_ctlrtype_t ctype
588 p
= Malloc(sizeof (*p
));
590 p
->pln_name
= pln_name
;
592 p
->next
= pln_cache_anchor
;
593 pln_cache_anchor
= p
;
596 /* singled threaded by caller */
600 enum mhd_ctlrtype_t
*ctype_ret
605 for (p
= pln_cache_anchor
; p
!= NULL
; p
= p
->next
) {
606 if (strcmp(pln_name
, p
->pln_name
) == 0) {
607 *ctype_ret
= p
->ctype
;
617 struct pln_cache
*p
, *n
= NULL
;
619 (void) mutex_lock(&mhd_pln_mx
);
620 for (p
= pln_cache_anchor
; p
!= NULL
; p
= n
) {
626 pln_cache_anchor
= NULL
;
627 (void) mutex_unlock(&mhd_pln_mx
);
631 * match on SSA Model 200.
639 mhd_cinfo_t
*cinfop
= &dp
->dr_drive_id
.did_cinfo
;
640 struct uscsi_cmd ucmd
;
642 struct scsi_inquiry inq
;
645 enum mhd_ctlrtype_t ctype
;
648 if ((pln_ctlr_name
= get_pln_ctlr_name(path
)) == NULL
)
651 (void) mutex_lock(&mhd_pln_mx
);
652 if (find_pln_cache(pln_ctlr_name
, &ctype
) == 1) {
653 (void) mutex_unlock(&mhd_pln_mx
);
654 if (ctype
!= MHD_CTLR_SSA200
)
657 /* over-ride for SSA200 */
658 cinfop
->mhc_ctype
= ctype
;
659 cinfop
->mhc_tray
= cinfop
->mhc_bus
;
663 if ((fd
= open(pln_ctlr_name
, (O_RDONLY
|O_NDELAY
), 0)) < 0) {
664 (void) mutex_unlock(&mhd_pln_mx
);
669 (void) memset(&ucmd
, 0, sizeof (ucmd
));
670 (void) memset(&cdb
, 0, sizeof (cdb
));
671 (void) memset(&inq
, 0, sizeof (inq
));
672 cdb
.scc_cmd
= SCMD_INQUIRY
;
673 cdb
.g0_count0
= sizeof (inq
);
674 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
675 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
676 ucmd
.uscsi_bufaddr
= (caddr_t
)&inq
;
677 ucmd
.uscsi_buflen
= sizeof (inq
);
678 ucmd
.uscsi_flags
= USCSI_READ
| USCSI_ISOLATE
| USCSI_DIAGNOSE
;
679 ucmd
.uscsi_timeout
= 30;
680 if (ioctl(fd
, USCSICMD
, &ucmd
)) {
681 (void) mutex_unlock(&mhd_pln_mx
);
683 MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n",
684 pln_ctlr_name
, errno
));
690 MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n", pln_ctlr_name
));
692 /* Make all trailing spaces be null char */
693 for (p
= inq
.inq_pid
+ sizeof (inq
.inq_pid
) - 1; p
!= inq
.inq_pid
;
702 if (strncmp(inq
.inq_pid
, META_SSA200_PID
, sizeof (inq
.inq_pid
)) != 0)
705 /* over-ride the ctype, and tray */
706 cinfop
->mhc_ctype
= MHD_CTLR_SSA200
;
707 cinfop
->mhc_tray
= cinfop
->mhc_bus
;
710 add_pln_cache(pln_ctlr_name
, cinfop
->mhc_ctype
);
711 (void) mutex_unlock(&mhd_pln_mx
);
715 * get controller info
723 mhd_cinfo_t
*cinfop
= &dp
->dr_drive_id
.did_cinfo
;
729 /* update and lock controller map */
730 if (update_map() != 0)
731 return; /* give up */
732 assert(RW_WRITE_HELD(&ctlr_rw
) || RW_READ_HELD(&ctlr_rw
));
734 /* look for match in cache */
735 for (i
= 0; (i
< ctlr_num
); ++i
) {
736 mhd_ctlrmap_t
*cmp
= &ctlr_map
[i
];
739 if ((regex(cmp
->regexpr1
, path
) != NULL
) &&
740 ((p
= regex(cmp
->regexpr2
, path
)) != NULL
) &&
742 (ulong_t
*)&wwn
._p
._u
, (ulong_t
*)&wwn
._p
._l
) == 2)) {
743 cinfop
->mhc_ctype
= MHD_CTLR_SSA100
;
744 cinfop
->mhc_tray
= cmp
->tray
;
745 cinfop
->mhc_bus
= cmp
->bus
;
746 cinfop
->mhc_wwn
= wwn
._f
;
747 match_SSA200(dp
, path
);
752 /* unlock controller map */
757 * get unique drive ID
764 mhd_drive_set_t
*sp
= dp
->dr_sp
;
765 int serial
= (sp
->sr_options
& MHD_SERIAL
);
766 struct uscsi_cmd ucmd
;
768 struct scsi_inquiry inq
;
769 struct extvtoc vtoc_buf
;
770 char path
[MAXPATHLEN
+ 1];
775 assert(MUTEX_HELD(&sp
->sr_mx
));
776 assert(dp
->dr_fd
>= 0);
777 assert(dp
->dr_state
& DRIVE_IDENTING
);
780 (void) memset(&dp
->dr_drive_id
, 0, sizeof (dp
->dr_drive_id
));
782 /* get serial number */
783 if (dp
->dr_state
& DRIVE_SERIALING
) {
785 mhd_mx_unlock(&sp
->sr_mx
);
786 (void) memset(&ucmd
, 0, sizeof (ucmd
));
787 (void) memset(&cdb
, 0, sizeof (cdb
));
788 (void) memset(&inq
, 0, sizeof (inq
));
789 cdb
.scc_cmd
= SCMD_INQUIRY
;
790 cdb
.g0_count0
= sizeof (inq
);
791 ucmd
.uscsi_cdb
= (caddr_t
)&cdb
;
792 ucmd
.uscsi_cdblen
= CDB_GROUP0
;
793 ucmd
.uscsi_bufaddr
= (caddr_t
)&inq
;
794 ucmd
.uscsi_buflen
= sizeof (inq
);
795 ucmd
.uscsi_flags
= USCSI_READ
| USCSI_ISOLATE
| USCSI_DIAGNOSE
;
796 ucmd
.uscsi_timeout
= 30;
797 err
= ioctl(dp
->dr_fd
, USCSICMD
, &ucmd
);
799 mhd_mx_lock(&sp
->sr_mx
);
802 "%s: USCSICMD(SCMD_INQUIRY): failed errno %d\n",
803 dp
->dr_rname
, errno
));
804 dp
->dr_drive_id
.did_flags
&= ~MHD_DID_SERIAL
;
809 MHDPRINTF(("%s: USCSICMD(SCMD_INQUIRY): success\n",
811 dp
->dr_drive_id
.did_flags
|= MHD_DID_SERIAL
;
812 p
= dp
->dr_drive_id
.did_serial
;
813 e
= p
+ sizeof (dp
->dr_drive_id
.did_serial
);
815 ((i
< sizeof (inq
.inq_vid
)) && (p
< e
)); ++i
)
816 *p
++ = inq
.inq_vid
[i
];
818 ((i
< sizeof (inq
.inq_pid
)) && (p
< e
)); ++i
)
819 *p
++ = inq
.inq_pid
[i
];
821 ((i
< sizeof (inq
.inq_revision
)) && (p
< e
)); ++i
)
822 *p
++ = inq
.inq_revision
[i
];
824 ((i
< sizeof (inq
.inq_serial
)) && (p
< e
)); ++i
)
825 *p
++ = inq
.inq_serial
[i
];
827 for (p
= dp
->dr_drive_id
.did_serial
; (p
< e
); ++p
) {
833 dp
->dr_drive_id
.did_flags
&= ~MHD_DID_SERIAL
;
837 if (dp
->dr_state
& DRIVE_VTOCING
) {
839 mhd_mx_unlock(&sp
->sr_mx
);
840 (void) memset(&vtoc_buf
, 0, sizeof (vtoc_buf
));
841 err
= read_extvtoc(dp
->dr_fd
, &vtoc_buf
);
843 mhd_mx_lock(&sp
->sr_mx
);
845 MHDPRINTF(("%s: read_extvtoc: failed errno %d\n",
846 dp
->dr_rname
, errno
));
847 dp
->dr_drive_id
.did_flags
&= ~MHD_DID_TIME
;
849 MHDPRINTF(("%s: read_extvtoc: success\n",
851 dp
->dr_drive_id
.did_flags
|= MHD_DID_TIME
;
852 dp
->dr_drive_id
.did_time
= vtoc_buf
.timestamp
[0];
855 dp
->dr_drive_id
.did_flags
&= ~MHD_DID_TIME
;
858 /* get controller info */
859 if (dp
->dr_state
& DRIVE_CINFOING
) {
861 mhd_mx_unlock(&sp
->sr_mx
);
862 len
= readlink(dp
->dr_rname0
, path
, (sizeof (path
) - 1));
864 mhd_mx_lock(&sp
->sr_mx
);
865 if (len
>= sizeof (path
)) {
867 errno
= ENAMETOOLONG
;
870 MHDPRINTF(("%s: readlink: failed errno %d\n",
871 dp
->dr_rname0
, errno
));
872 dp
->dr_drive_id
.did_flags
&= ~MHD_DID_CINFO
;
874 MHDPRINTF(("%s: readlink: success\n",
876 dp
->dr_drive_id
.did_flags
|= MHD_DID_CINFO
;
877 (void) memset(&dp
->dr_drive_id
.did_cinfo
, 0,
878 sizeof (dp
->dr_drive_id
.did_cinfo
));
879 match_SSA100(dp
, path
);
882 dp
->dr_drive_id
.did_flags
&= ~MHD_DID_CINFO
;
886 (void) mhd_state_clr(dp
, DRIVE_IDENTING
, NULL
);
898 mhd_drive_set_t
*sp
= dp
->dr_sp
;
900 /* wait for dp->dr_thread to be filled in */
902 mhd_mx_lock(&sp
->sr_mx
);
907 assert(MUTEX_HELD(&sp
->sr_mx
));
908 assert(dp
->dr_thread
== thr_self());
910 /* check for changed set */
911 if (sp
!= dp
->dr_sp
) {
912 MHDPRINTF2(("%s: changed from set '%s' to '%s'\n",
913 dp
->dr_rname
, sp
->sr_name
, dp
->dr_sp
->sr_name
));
915 mhd_mx_unlock(&sp
->sr_mx
);
917 mhd_mx_lock(&sp
->sr_mx
);
920 /* open drive, if necessary */
921 if ((dp
->dr_fd
< 0) && (! (DRIVE_IS_IDLE(dp
) ||
922 (dp
->dr_state
== DRIVE_IDLING
)))) {
923 int serial
= (sp
->sr_options
& MHD_SERIAL
);
926 mhd_mx_unlock(&sp
->sr_mx
);
927 dp
->dr_fd
= open(dp
->dr_rname0
, (O_RDWR
|O_NDELAY
), 0);
929 mhd_mx_lock(&sp
->sr_mx
);
931 mhd_perror("%s: open", dp
->dr_rname
);
932 (void) mhd_state(dp
, DRIVE_ERRORED
, NULL
);
933 dp
->dr_errnum
= errno
;
939 switch (dp
->dr_state
) {
941 MHDPRINTF1(("%s: IDLE\n", dp
->dr_rname
));
945 MHDPRINTF1(("%s: ERRORED %d\n",
946 dp
->dr_rname
, dp
->dr_errnum
));
950 (void) mhd_state(dp
, DRIVE_IDLE
, NULL
);
953 case DRIVE_RESERVING
:
954 MHDPRINTF1(("%s: RESERVING\n", dp
->dr_rname
));
955 (void) mhd_reserve(dp
);
956 assert(DRIVE_IS_IDLE(dp
));
959 case DRIVE_FAILFASTING
:
960 MHDPRINTF1(("%s: FAILFASTING\n", dp
->dr_rname
));
961 (void) mhd_failfast(dp
);
962 assert(DRIVE_IS_IDLE(dp
));
965 case DRIVE_RELEASING
:
966 MHDPRINTF1(("%s: RELEASING\n", dp
->dr_rname
));
967 (void) mhd_release(dp
);
968 assert(DRIVE_IS_IDLE(dp
));
971 /* non-exclusive states */
973 assert(! (dp
->dr_state
&
974 (DRIVE_EXCLUSIVE_STATES
& ~DRIVE_ERRORED
)));
975 if (dp
->dr_state
& (DRIVE_PROBING
| DRIVE_STATUSING
)) {
976 MHDPRINTF1(("%s: PROBING\n", dp
->dr_rname
));
977 (void) mhd_probe(dp
);
978 assert(! (dp
->dr_state
& DRIVE_STATUSING
));
980 if (dp
->dr_state
& DRIVE_IDENTING
) {
981 MHDPRINTF1(("%s: IDENTING\n", dp
->dr_rname
));
982 (void) mhd_ident(dp
);
983 assert(! (dp
->dr_state
& DRIVE_IDENTING
));
984 continue; /* in case we're probing */
989 /* close drive, if possible */
990 if ((dp
->dr_fd
>= 0) && (DRIVE_IS_IDLE(dp
))) {
991 int serial
= (sp
->sr_options
& MHD_SERIAL
);
994 mhd_mx_unlock(&sp
->sr_mx
);
995 (void) close(dp
->dr_fd
); /* sd/ssd bug */
997 mhd_mx_lock(&sp
->sr_mx
);
1001 /* wake up anybody waiting */
1002 mhd_cv_broadcast(&sp
->sr_cv
);
1004 /* see if anything happened */
1005 if (! DRIVE_IS_IDLE(dp
))
1008 /* wait for something to happen */
1009 if (! (dp
->dr_state
& DRIVE_PROBING
)) {
1010 mhd_cv_wait(&dp
->dr_cv
, &sp
->sr_mx
);
1012 mhd_cv_timedwait(&dp
->dr_cv
, &sp
->sr_mx
,
1013 (sp
->sr_timeouts
.mh_ff
/ 2));
1019 * kick off drive thread
1027 mhd_drive_set_t
*sp
= dp
->dr_sp
;
1028 thread_t thread
= NULL
;
1031 /* check lock and thread */
1032 assert(MUTEX_HELD(&sp
->sr_mx
));
1033 assert(dp
->dr_thread
== NULL
);
1036 if (thr_create(NULL
, 0, (void *(*)(void *))mhd_drive_thread
,
1037 (void *)dp
, (THR_DETACHED
| THR_BOUND
), &thread
) != 0) {
1038 rval
= mhd_error(mhep
, errno
, "thr_create");
1040 assert(thread
!= NULL
);
1041 dp
->dr_thread
= thread
;
1044 /* return success */
1049 * peel off s%u from name
1059 /* duplicate name */
1060 if ((dname
= Strdup(sname
)) == NULL
)
1063 /* gobble number and 's' */
1064 p
= e
= dname
+ strlen(dname
) - 1;
1065 for (; (p
> dname
); --p
) {
1069 if ((p
== e
) || (p
<= dname
)) {
1077 if ((p
<= dname
) || (!isdigit(*p
))) {
1090 mhd_drive_set_t
*sp
, /* new set */
1091 char *rname
, /* raw drive name */
1092 int *fdp
, /* open device or -1 */
1093 mhd_error_t
*mhep
/* returned error */
1096 mhd_drive_t
*dp
= NULL
;
1097 char *rname0
= NULL
;
1100 assert(MUTEX_HELD(&sp
->sr_mx
));
1102 /* if drive already exists */
1103 if ((dp
= mhd_find_drive(rname
)) != NULL
) {
1104 mhd_drive_set_t
*oldsp
= dp
->dr_sp
;
1106 /* if set has changed, move drive */
1108 mhd_mx_unlock(&sp
->sr_mx
);
1109 mhd_mx_lock(&oldsp
->sr_mx
);
1110 if (mhd_idle(dp
, mhep
) != 0) {
1111 mhd_mx_unlock(&oldsp
->sr_mx
);
1112 mhd_mx_lock(&sp
->sr_mx
);
1115 mhd_del_drive_from_set(dp
);
1116 mhd_mx_unlock(&oldsp
->sr_mx
);
1117 mhd_mx_lock(&sp
->sr_mx
);
1118 mhd_add_drive_to_set(sp
, dp
);
1126 rname0
= Malloc(strlen(rname
) + strlen("s0") + 1);
1127 (void) strcpy(rname0
, rname
);
1128 (void) strcat(rname0
, "s0");
1130 /* allocate and initialize drive */
1131 dp
= Zalloc(sizeof (*dp
));
1133 dp
->dr_rname
= Strdup(rname
);
1134 dp
->dr_rname0
= rname0
;
1135 mhd_cv_init(&dp
->dr_cv
);
1136 dp
->dr_thread
= NULL
;
1138 dp
->dr_state
= DRIVE_IDLE
;
1140 /* steal open drive */
1141 if ((fdp
!= NULL
) && (*fdp
>= 0)) {
1147 mhd_add_drive_to_set(sp
, dp
);
1149 /* kick off drive thread */
1150 if (mhd_thread_create(dp
, mhep
) != 0) {
1151 Free(dp
->dr_rname0
);
1162 * find or create drive in any set
1164 static mhd_drive_t
*
1165 mhd_create_drive_anyset(
1171 mhd_drive_set_t
*null_sp
= mhd_create_set(NULL
, 0, NULL
, NULL
);
1175 assert(null_sp
!= NULL
);
1177 /* drive already exists */
1178 if ((dp
= mhd_find_drive(rname
)) != NULL
)
1181 /* add to null set */
1182 mhd_mx_lock(&null_sp
->sr_mx
);
1183 dp
= mhd_create_drive(null_sp
, rname
, fdp
, mhep
);
1184 mhd_mx_unlock(&null_sp
->sr_mx
);
1191 * process a file in the tree walk
1196 const struct stat
*statp
,
1202 struct dk_cinfo cinfo
;
1203 mhd_error_t status
= mhd_null_error
;
1205 /* skip all but character devices */
1206 if ((type
!= FTW_F
) || (! S_ISCHR(statp
->st_mode
)) ||
1207 ((dname
= diskname(path
)) == NULL
)) {
1211 /* see if drive already exists */
1212 if (mhd_find_drive(dname
) != NULL
)
1215 /* see if device is a disk */
1216 if ((fd
= open(path
, (O_RDONLY
|O_NDELAY
), 0)) < 0)
1218 if (ioctl(fd
, DKIOCINFO
, &cinfo
) != 0) {
1224 mhd_perror("DKIOCINFO: %s", path
);
1231 if (cinfo
.dki_ctype
== DKC_CDROM
) {
1237 /* put disk on list */
1238 if (mhd_create_drive_anyset(dname
, &fd
, &status
) == NULL
) {
1239 mhde_perror(&status
, "");
1243 /* cleanup, return success (no matter what) */
1249 mhd_clrerror(&status
);
1254 * find or create all the drives under a given directory
1263 if ((path
== NULL
) || (*path
== '\0'))
1268 /* walk the directory, adding disks */
1269 if (ftw(path
, do_disk
, 5) != 0)
1270 return (mhd_error(mhep
, errno
, path
));
1272 /* return success */