Subject: Re: port bio(4) and bioctl(8) from openbsd ?
To: None <tech-kern@NetBSD.org>
From: Manuel Bouyer <bouyer@antioche.eu.org>
List: tech-kern
Date: 04/21/2007 15:48:08
--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Here's my latest patch about this.
I've an issue with lock usage in bio(4):
there is a bio_lock, which is a kmutex_t to protect the internal structures
of bio(4). A disk driver (for example mfi(4)) will also have its own
lock to protect its structure; and will probably call bio_register()
and bio_unregister() with this lock held.
The callback from bio(4) to mfi(4) shall be called with bio_lock held, to
avoid having the entry removed from under its feets (it's not the
case right now, but as nothing calls bio_unregister() for now, it's
safe).
Now we could have this deadlock (theorically; because mfi doesn't have
a mfi_detach):
mfi_detach() takes the mfi mutex, and calls bio_unregister() which takes
bio_lock.
bioioctl() takes bio_lock, and call backs in mfi(4) which will want to
take the mfi mutex.
I'm not a multithread expert programmer. How is such case handled usually ?
I think mfi_detach() should take bio_lock itself, so it can take locks
in an order which can avoid the deadlock. Or the callback in mfi could
release bio_lock itself before trying to take the mfi mutex, but I can't
see how to avoid the race in which the mfi device could dissapear between
releasing bio_lock and taking the mfi mutex at this point. Any idea ?
--
Manuel Bouyer <bouyer@antioche.eu.org>
NetBSD: 26 ans d'experience feront toujours la difference
--
--mP3DRpeJDSE+ciuQ
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff
Index: distrib/sets/lists/base/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/base/mi,v
retrieving revision 1.700
diff -u -r1.700 mi
--- distrib/sets/lists/base/mi 8 Apr 2007 09:35:24 -0000 1.700
+++ distrib/sets/lists/base/mi 21 Apr 2007 13:26:12 -0000
@@ -123,6 +123,7 @@
./sbin/amrctl base-sysutil-root
./sbin/apmlabel base-sysutil-root
./sbin/atactl base-sysutil-root
+./sbin/bioctl base-sysutil-root
./sbin/badsect base-sysutil-root
./sbin/brconfig base-netutil-root
./sbin/ccdconfig base-sysutil-root
Index: distrib/sets/lists/comp/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/comp/mi,v
retrieving revision 1.1019
diff -u -r1.1019 mi
--- distrib/sets/lists/comp/mi 1 Apr 2007 18:52:28 -0000 1.1019
+++ distrib/sets/lists/comp/mi 21 Apr 2007 13:26:12 -0000
@@ -155,6 +155,7 @@
./usr/include/dev/auconv.h comp-obsolete obsolete
./usr/include/dev/audio_if.h comp-obsolete obsolete
./usr/include/dev/audiovar.h comp-obsolete obsolete
+./usr/include/dev/biovar.h comp-c-include
./usr/include/dev/bluetooth comp-c-include
./usr/include/dev/bluetooth/btdev.h comp-c-include
./usr/include/dev/bluetooth/bthidev.h comp-c-include
Index: distrib/sets/lists/man/mi
===================================================================
RCS file: /cvsroot/src/distrib/sets/lists/man/mi,v
retrieving revision 1.988
diff -u -r1.988 mi
--- distrib/sets/lists/man/mi 8 Apr 2007 09:35:25 -0000 1.988
+++ distrib/sets/lists/man/mi 21 Apr 2007 13:26:13 -0000
@@ -720,6 +720,7 @@
./usr/share/man/cat4/bge.0 man-sys-catman .cat
./usr/share/man/cat4/bha.0 man-sys-catman .cat
./usr/share/man/cat4/bicc.0 man-sys-catman .cat
+./usr/share/man/cat4/bio.0 man-sys-catman .cat
./usr/share/man/cat4/bktr.0 man-sys-catman .cat
./usr/share/man/cat4/bluetooth.0 man-sys-catman .cat
./usr/share/man/cat4/bmtphy.0 man-sys-catman .cat
@@ -1802,6 +1803,7 @@
./usr/share/man/cat8/badsect.0 man-sysutil-catman .cat
./usr/share/man/cat8/bebox/MAKEDEV.0 man-obsolete obsolete
./usr/share/man/cat8/bebox/makedev.0 man-obsolete obsolete
+./usr/share/man/cat8/bioctl.0 man-sysutil-catman .cat
./usr/share/man/cat8/boot.0 man-sysutil-catman .cat
./usr/share/man/cat8/bootparamd.0 man-bootserver-catman .cat
./usr/share/man/cat8/bootpd.0 man-bootserver-catman .cat
@@ -3154,6 +3156,7 @@
./usr/share/man/man4/bge.4 man-sys-man .man
./usr/share/man/man4/bha.4 man-sys-man .man
./usr/share/man/man4/bicc.4 man-sys-man .man
+./usr/share/man/man4/bio.4 man-sys-man .man
./usr/share/man/man4/bktr.4 man-sys-man .man
./usr/share/man/man4/bluetooth.4 man-sys-man .man
./usr/share/man/man4/bmtphy.4 man-sys-man .man
@@ -4235,6 +4238,7 @@
./usr/share/man/man8/badsect.8 man-sysutil-man .man
./usr/share/man/man8/bebox/MAKEDEV.8 man-obsolete obsolete
./usr/share/man/man8/bebox/makedev.8 man-obsolete obsolete
+./usr/share/man/man8/bioctl.8 man-sysutil-man .man
./usr/share/man/man8/boot.8 man-sysutil-man .man
./usr/share/man/man8/bootparamd.8 man-bootserver-man .man
./usr/share/man/man8/bootpd.8 man-bootserver-man .man
Index: sbin/Makefile
===================================================================
RCS file: /cvsroot/src/sbin/Makefile,v
retrieving revision 1.104
diff -u -r1.104 Makefile
--- sbin/Makefile 6 Mar 2007 11:28:45 -0000 1.104
+++ sbin/Makefile 21 Apr 2007 13:26:51 -0000
@@ -6,8 +6,8 @@
.include <bsd.own.mk>
-SUBDIR= amrctl apmlabel atactl badsect bim brconfig ccdconfig disklabel \
- dkctl dkscan_bsdlabel dmesg \
+SUBDIR= amrctl apmlabel atactl badsect bim bioctl brconfig ccdconfig \
+ disklabel dkctl dkscan_bsdlabel dmesg \
drvctl edlabel fastboot fdisk fsck fsirand gpt ifconfig init ldconfig \
mbrlabel mknod modload modunload mount newbtconf nologin \
pdisk ping pppoectl raidctl reboot rcorder rndctl route routed \
Index: share/man/man4/Makefile
===================================================================
RCS file: /cvsroot/src/share/man/man4/Makefile,v
retrieving revision 1.423
diff -u -r1.423 Makefile
--- share/man/man4/Makefile 25 Mar 2007 09:11:56 -0000 1.423
+++ share/man/man4/Makefile 21 Apr 2007 13:26:52 -0000
@@ -8,7 +8,7 @@
ath.4 atppc.4 attimer.4 atw.4 \
auacer.4 audio.4 audiocs.4 auich.4 \
auixp.4 autri.4 auvia.4 awi.4 azalia.4 \
- bba.4 bce.4 be.4 bge.4 bnx.4 bha.4 bktr.4 bluetooth.4 bmtphy.4 \
+ bba.4 bce.4 be.4 bge.4 bnx.4 bha.4 bio.4 bktr.4 bluetooth.4 bmtphy.4 \
bpf.4 brgphy.4 bridge.4 bthidev.4 bthub.4 btkbd.4 btms.4 btsco.4 \
btuart.4 cac.4 cardbus.4 carp.4 ccd.4 cd.4 \
cec.4 cgd.4 cfb.4 ch.4 ciphy.4 ciss.4 clcs.4 clct.4 clnp.4 \
Index: share/man/man4/bio.4
===================================================================
RCS file: share/man/man4/bio.4
diff -N share/man/man4/bio.4
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ share/man/man4/bio.4 21 Apr 2007 13:26:52 -0000
@@ -0,0 +1,124 @@
+.\" $NetBSD: $
+.\" $OpenBSD: bio.4,v 1.19 2006/09/20 22:22:37 jmc Exp $
+.\"
+.\" Copyright (c) 2002 Niklas Hallqvist
+.\" Copyright (c) 2006 Marco Peereboom
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd April 8, 2007
+.Dt BIO 4
+.Os
+.Sh NAME
+.Nm bio
+.Nd Block IO ioctl tunnel pseudo-device
+.Sh SYNOPSIS
+.Cd "pseudo-device bio"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides userland applications
+.Xr ioctl 2
+access to devices otherwise not found as
+.Pa /dev
+nodes.
+The
+.Pa /dev/bio
+device node operates by delegating ioctl
+calls to a requested device driver.
+Only drivers which have registered with the
+.Nm
+device can be accessed via this interface.
+.Pp
+The following device drivers register with
+.Nm
+for volume management:
+.Pp
+.Bl -tag -width ciss(4)XX -offset indent -compact
+.\" .It Xr ami 4
+.\" American Megatrends Inc. MegaRAID PATA/SATA/SCSI RAID controller
+.\" .It Xr arc 4
+.\" Areca Technology Corporation SATA RAID controller
+.\" .It Xr ciss 4
+.\" Compaq Smart ARRAY 5/6 SAS/SATA/SCSI RAID controller
+.It Xr mfi 4
+LSI Logic & Dell MegaRAID SAS RAID controller
+.El
+.Pp
+The following ioctl calls apply to the
+.Nm bio
+device:
+.Bl -tag -width BIOCCAPABILITIES
+.It Dv BIOCLOCATE
+Locate a named device and give back a cookie to the application
+for subsequent ioctl calls.
+The cookie is used to tunnel further ioctls to the right device.
+.It Dv BIOCINQ
+Retrieve number of volumes and physical disks for a specific device.
+.It Dv BIOCDISK
+Retrieve detailed information for the specified physical disk.
+Information returned can include status, size, channel, target, lun,
+vendor name, serial number and processor device (ses or safte).
+.It Dv BIOCVOL
+Retrieve detailed information for the specified volume.
+Information returned can include status, size, RAID level, number of disks,
+device name association (sd?) and vendor name.
+.It Dv BIOCALARM
+Control the alarm beeper on the device.
+Supported states are: disable alarm, enable alarm, silence alarm, status and
+test alarm.
+.Pp
+Note: These options might not be supported on all hardware.
+.It Dv BIOCBLINK
+Blink an LED of the specified physical disk.
+Supported blink states are: blink LED, unblink LED and blink alarm LED.
+.Pp
+Note: This option is only supported if the disk is governed by ses(4) or
+safte(4) and the hardware supports hardware blinking.
+.It Dv BIOCSETSTATE
+Alter the state of specified physical disk.
+Supported states are: create hot-spare, online disk and offline disk.
+.El
+.Sh FILES
+.Bl -tag -width /dev/bio -compact
+.It Pa /dev/bio
+ioctl tunnel device
+.El
+.Sh SEE ALSO
+.Xr ioctl 2 ,
+.Xr bioctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Ox 3.2 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Niklas Hallqvist Aq niklas@openbsd.org .
+The API was written by
+.An Marco Peereboom Aq marco@openbsd.org .
Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.137
diff -u -r1.137 GENERIC
--- sys/arch/amd64/conf/GENERIC 20 Mar 2007 21:29:28 -0000 1.137
+++ sys/arch/amd64/conf/GENERIC 21 Apr 2007 13:26:54 -0000
@@ -881,6 +881,7 @@
pseudo-device swcrypto # software crypto implementation
# disk/mass storage pseudo-devices
+pseudo-device bio # RAID control device driver
pseudo-device ccd 4 # concatenated/striped disk devices
#pseudo-device cgd 4 # cryptographic disk devices
pseudo-device raid 8 # RAIDframe disk driver
Index: sys/conf/files
===================================================================
RCS file: /cvsroot/src/sys/conf/files,v
retrieving revision 1.837
diff -u -r1.837 files
--- sys/conf/files 14 Apr 2007 19:33:29 -0000 1.837
+++ sys/conf/files 21 Apr 2007 13:27:03 -0000
@@ -1144,6 +1144,7 @@
defpseudo ksyms
defpseudo nullcons
defpseudo lockstat
+defpseudo bio: sysmon_envsys
defpseudo loop: ifnet
defpseudo sl: ifnet
@@ -1242,6 +1243,7 @@
file dev/audio.c audio | midi | midibus needs-flag
file dev/audiobell.c audiobell
file dev/aurateconv.c aurateconv needs-flag
+file dev/bio.c bio needs-flag
file dev/ccd.c ccd needs-flag
file dev/cgd.c cgd needs-flag
file dev/cgd_crypto.c cgd
Index: sys/conf/majors
===================================================================
RCS file: /cvsroot/src/sys/conf/majors,v
retrieving revision 1.33
diff -u -r1.33 majors
--- sys/conf/majors 20 Mar 2007 16:37:12 -0000 1.33
+++ sys/conf/majors 21 Apr 2007 13:27:03 -0000
@@ -30,4 +30,5 @@
device-major puffs char 178 puffs
device-major srt char 179 srt
device-major drm char 180 drmbase
+device-major bio char 181 bio
device-major twa char 187 twa
Index: sys/dev/Makefile
===================================================================
RCS file: /cvsroot/src/sys/dev/Makefile,v
retrieving revision 1.24
diff -u -r1.24 Makefile
--- sys/dev/Makefile 7 Sep 2006 00:20:28 -0000 1.24
+++ sys/dev/Makefile 21 Apr 2007 13:27:03 -0000
@@ -6,6 +6,6 @@
INCSDIR= /usr/include/dev
# Only install includes which are used by userland
-INCS= ccdvar.h cgdvar.h fssvar.h kttcpio.h lockstat.h md.h vndvar.h
+INCS= biovar.h ccdvar.h cgdvar.h fssvar.h kttcpio.h lockstat.h md.h vndvar.h
.include <bsd.kinc.mk>
Index: sys/dev/bio.c
===================================================================
RCS file: sys/dev/bio.c
diff -N sys/dev/bio.c
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/bio.c 21 Apr 2007 13:27:03 -0000
@@ -0,0 +1,187 @@
+/* $NetBSD: $ */
+/* $OpenBSD: bio.c,v 1.9 2007/03/20 02:35:55 marco Exp $ */
+
+/*
+ * Copyright (c) 2002 Niklas Hallqvist. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* A device controller ioctl tunnelling device. */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: $");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/device.h>
+#include <sys/event.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+#include <sys/queue.h>
+#include <sys/systm.h>
+#include <sys/mutex.h>
+
+#include <dev/biovar.h>
+
+struct bio_mapping {
+ LIST_ENTRY(bio_mapping) bm_link;
+ struct device *bm_dev;
+ int (*bm_ioctl)(struct device *, u_long, void *);
+};
+
+LIST_HEAD(, bio_mapping) bios = LIST_HEAD_INITIALIZER(bios);
+static kmutex_t bio_lock;
+
+void bioattach(int);
+int bioclose(dev_t, int, int, struct lwp *);
+int bioioctl(dev_t, u_long, void *, int, struct lwp *);
+int bioopen(dev_t, int, int, struct lwp *);
+
+int bio_delegate_ioctl(struct bio_mapping *, u_long, void *);
+struct bio_mapping *bio_lookup(char *);
+int bio_validate(void *);
+
+const struct cdevsw bio_cdevsw = {
+ bioopen, bioclose, noread, nowrite, bioioctl,
+ nostop, notty, nopoll, nommap, nokqfilter, 0
+};
+
+
+void
+bioattach(int nunits)
+{
+ mutex_init(&bio_lock, MUTEX_DRIVER, IPL_BIO);
+}
+
+int
+bioopen(dev_t dev, int flags, int mode, struct lwp *l)
+{
+ return (0);
+}
+
+int
+bioclose(dev_t dev, int flags, int mode, struct lwp *l)
+{
+ return (0);
+}
+
+int
+bioioctl(dev_t dev, u_long cmd, void *addr, int flag, struct lwp *l)
+{
+ struct bio_locate *locate;
+ struct bio_common *common;
+ char name[16];
+ int error;
+
+ switch (cmd) {
+ case BIOCLOCATE:
+ locate = (struct bio_locate *)addr;
+ error = copyinstr(locate->bl_name, name, 16, NULL);
+ if (error != 0)
+ return (error);
+ locate->bl_cookie = bio_lookup(name);
+ if (locate->bl_cookie == NULL)
+ return (ENOENT);
+ break;
+
+ default:
+ common = (struct bio_common *)addr;
+ if (!bio_validate(common->bc_cookie)) {
+ return (ENOENT);
+ }
+ error = bio_delegate_ioctl(
+ (struct bio_mapping *)common->bc_cookie, cmd, addr);
+ return (error);
+ }
+ return (0);
+}
+
+int
+bio_register(struct device *dev, int (*ioctl)(struct device *, u_long, void *))
+{
+ struct bio_mapping *bm;
+
+ MALLOC(bm, struct bio_mapping *, sizeof *bm, M_DEVBUF, M_NOWAIT);
+ if (bm == NULL)
+ return (ENOMEM);
+ bm->bm_dev = dev;
+ bm->bm_ioctl = ioctl;
+ mutex_enter(&bio_lock);
+ LIST_INSERT_HEAD(&bios, bm, bm_link);
+ mutex_exit(&bio_lock);
+ return (0);
+}
+
+void
+bio_unregister(struct device *dev)
+{
+ struct bio_mapping *bm, *next;
+
+ mutex_enter(&bio_lock);
+ for (bm = LIST_FIRST(&bios); bm != NULL; bm = next) {
+ next = LIST_NEXT(bm, bm_link);
+
+ if (dev == bm->bm_dev) {
+ LIST_REMOVE(bm, bm_link);
+ free(bm, M_DEVBUF);
+ }
+ }
+ mutex_exit(&bio_lock);
+}
+
+struct bio_mapping *
+bio_lookup(char *name)
+{
+ struct bio_mapping *bm;
+
+ mutex_enter(&bio_lock);
+ LIST_FOREACH(bm, &bios, bm_link) {
+ if (strcmp(name, bm->bm_dev->dv_xname) == 0) {
+ mutex_exit(&bio_lock);
+ return (bm);
+ }
+ }
+ mutex_exit(&bio_lock);
+ return (NULL);
+}
+
+int
+bio_validate(void *cookie)
+{
+ struct bio_mapping *bm;
+
+ mutex_enter(&bio_lock);
+ LIST_FOREACH(bm, &bios, bm_link) {
+ if (bm == cookie) {
+ mutex_exit(&bio_lock);
+ return (1);
+ }
+ }
+ mutex_exit(&bio_lock);
+ return (0);
+}
+
+int
+bio_delegate_ioctl(struct bio_mapping *bm, u_long cmd, void *addr)
+{
+ return (bm->bm_ioctl(bm->bm_dev, cmd, addr));
+}
Index: sys/dev/biovar.h
===================================================================
RCS file: sys/dev/biovar.h
diff -N sys/dev/biovar.h
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ sys/dev/biovar.h 21 Apr 2007 13:27:03 -0000
@@ -0,0 +1,191 @@
+/* $NetBSD: $ */
+/* $OpenBSD: biovar.h,v 1.26 2007/03/19 03:02:08 marco Exp $ */
+
+/*
+ * Copyright (c) 2002 Niklas Hallqvist. All rights reserved.
+ * Copyright (c) 2005 Marco Peereboom. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * Devices getting ioctls through this interface should use ioctl class 'B'
+ * and command numbers starting from 32, lower ones are reserved for generic
+ * ioctls. All ioctl data must be structures which start with a void *
+ * cookie.
+ */
+
+#include <sys/types.h>
+
+struct bio_common {
+ void *bc_cookie;
+};
+
+/* convert name to a cookie */
+#define BIOCLOCATE _IOWR('B', 0, struct bio_locate)
+struct bio_locate {
+ void *bl_cookie;
+ char *bl_name;
+};
+
+#ifdef _KERNEL
+int bio_register(struct device *, int (*)(struct device *, u_long,
+ void *));
+void bio_unregister(struct device *);
+#endif
+
+#define BIOCINQ _IOWR('B', 32, struct bioc_inq)
+struct bioc_inq {
+ void *bi_cookie;
+
+ char bi_dev[16]; /* controller device */
+ int bi_novol; /* nr of volumes */
+ int bi_nodisk; /* nr of total disks */
+};
+
+#define BIOCDISK _IOWR('B', 33, struct bioc_disk)
+/* structure that represents a disk in a RAID volume */
+struct bioc_disk {
+ void *bd_cookie;
+
+ u_int16_t bd_channel;
+ u_int16_t bd_target;
+ u_int16_t bd_lun;
+ u_int16_t bd_other_id; /* unused for now */
+
+ int bd_volid; /* associate with volume */
+ int bd_diskid; /* virtual disk */
+ int bd_status; /* current status */
+#define BIOC_SDONLINE 0x00
+#define BIOC_SDONLINE_S "Online"
+#define BIOC_SDOFFLINE 0x01
+#define BIOC_SDOFFLINE_S "Offline"
+#define BIOC_SDFAILED 0x02
+#define BIOC_SDFAILED_S "Failed"
+#define BIOC_SDREBUILD 0x03
+#define BIOC_SDREBUILD_S "Rebuild"
+#define BIOC_SDHOTSPARE 0x04
+#define BIOC_SDHOTSPARE_S "Hot spare"
+#define BIOC_SDUNUSED 0x05
+#define BIOC_SDUNUSED_S "Unused"
+#define BIOC_SDSCRUB 0x06
+#define BIOC_SDSCRUB_S "Scrubbing"
+#define BIOC_SDINVALID 0xff
+#define BIOC_SDINVALID_S "Invalid"
+ size_t bd_size; /* size of the disk */
+
+ char bd_vendor[32]; /* scsi string */
+ char bd_serial[32]; /* serial number */
+ char bd_procdev[16]; /* processor device */
+};
+
+#define BIOCVOL _IOWR('B', 34, struct bioc_vol)
+/* structure that represents a RAID volume */
+struct bioc_vol {
+ void *bv_cookie;
+ int bv_volid; /* volume id */
+
+ int16_t bv_percent; /* percent done operation */
+ u_int16_t bv_seconds; /* seconds of progress so far */
+
+ int bv_status; /* current status */
+#define BIOC_SVONLINE 0x00
+#define BIOC_SVONLINE_S "Online"
+#define BIOC_SVOFFLINE 0x01
+#define BIOC_SVOFFLINE_S "Offline"
+#define BIOC_SVDEGRADED 0x02
+#define BIOC_SVDEGRADED_S "Degraded"
+#define BIOC_SVBUILDING 0x03
+#define BIOC_SVBUILDING_S "Building"
+#define BIOC_SVSCRUB 0x04
+#define BIOC_SVSCRUB_S "Scrubbing"
+#define BIOC_SVREBUILD 0x05
+#define BIOC_SVREBUILD_S "Rebuild"
+#define BIOC_SVINVALID 0xff
+#define BIOC_SVINVALID_S "Invalid"
+ size_t bv_size; /* size of the disk */
+ int bv_level; /* raid level */
+ int bv_nodisk; /* nr of drives */
+
+ char bv_dev[16]; /* device */
+ char bv_vendor[32]; /* scsi string */
+};
+
+#define BIOCALARM _IOWR('B', 35, struct bioc_alarm)
+struct bioc_alarm {
+ void *ba_cookie;
+ int ba_opcode;
+
+ int ba_status; /* only used with get state */
+#define BIOC_SADISABLE 0x00 /* disable alarm */
+#define BIOC_SAENABLE 0x01 /* enable alarm */
+#define BIOC_SASILENCE 0x02 /* silence alarm */
+#define BIOC_GASTATUS 0x03 /* get status */
+#define BIOC_SATEST 0x04 /* test alarm */
+};
+
+#define BIOCBLINK _IOWR('B', 36, struct bioc_blink)
+struct bioc_blink {
+ void *bb_cookie;
+ u_int16_t bb_channel;
+ u_int16_t bb_target;
+
+ int bb_status; /* current status */
+#define BIOC_SBUNBLINK 0x00 /* disable blinking */
+#define BIOC_SBBLINK 0x01 /* enable blink */
+#define BIOC_SBALARM 0x02 /* enable alarm blink */
+};
+
+#define BIOCSETSTATE _IOWR('B', 37, struct bioc_setstate)
+struct bioc_setstate {
+ void *bs_cookie;
+ u_int16_t bs_channel;
+ u_int16_t bs_target;
+ u_int16_t bs_lun;
+ u_int16_t bs_other_id; /* unused for now */
+
+ int bs_status; /* change to this status */
+#define BIOC_SSONLINE 0x00 /* online disk */
+#define BIOC_SSOFFLINE 0x01 /* offline disk */
+#define BIOC_SSHOTSPARE 0x02 /* mark as hotspare */
+#define BIOC_SSREBUILD 0x03 /* rebuild on this disk */
+ int bs_volid; /* volume id for rebuild */
+};
+
+#define BIOCCREATERAID _IOWR('B', 38, struct bioc_createraid)
+struct bioc_createraid {
+ void *bc_cookie;
+ char *bc_dev_list;
+ u_int16_t bc_dev_list_len;
+ u_int16_t bc_level;
+};
+
+/* kernel and userspace defines */
+#define BIOC_INQ 0x0001
+#define BIOC_DISK 0x0002
+#define BIOC_VOL 0x0004
+#define BIOC_ALARM 0x0008
+#define BIOC_BLINK 0x0010
+#define BIOC_SETSTATE 0x0020
+#define BIOC_CREATERAID 0x0040
+
+/* user space defines */
+#define BIOC_DEVLIST 0x10000
Index: sys/dev/ic/mfi.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/mfi.c,v
retrieving revision 1.3
diff -u -r1.3 mfi.c
--- sys/dev/ic/mfi.c 4 Mar 2007 06:01:58 -0000 1.3
+++ sys/dev/ic/mfi.c 21 Apr 2007 13:27:03 -0000
@@ -19,7 +19,7 @@
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: mfi.c,v 1.3 2007/03/04 06:01:58 christos Exp $");
-/* #include "bio.h" XXX */
+#include "bio.h"
#include <sys/param.h>
#include <sys/systm.h>
@@ -46,7 +46,6 @@
#if NBIO > 0
#include <dev/biovar.h>
-#include <sys/sensors.h>
#endif /* NBIO > 0 */
#ifdef MFI_DEBUG
@@ -103,7 +102,10 @@
int mfi_ioctl_setstate(struct mfi_softc *, struct bioc_setstate *);
int mfi_bio_hs(struct mfi_softc *, int, int, void *);
int mfi_create_sensors(struct mfi_softc *);
-void mfi_refresh_sensors(void *);
+int mfi_sensor_gtredata(struct sysmon_envsys *,
+ struct envsys_tre_data *);
+int mfi_sensor_streinfo(struct sysmon_envsys *,
+ struct envsys_basic_info *);
#endif /* NBIO > 0 */
struct mfi_ccb *
@@ -586,8 +588,6 @@
TAILQ_INIT(&sc->sc_ccb_freeq);
- /* rw_init(&sc->sc_lock, "mfi_lock"); XXX */
-
status = mfi_read(sc, MFI_OMSG0);
sc->sc_max_cmds = status & MFI_STATE_MAXCMD_MASK;
sc->sc_max_sgl = (status & MFI_STATE_MAXSGL_MASK) >> 16;
@@ -693,7 +693,6 @@
panic("%s: controller registration failed", DEVNAME(sc));
else
sc->sc_ioctl = mfi_ioctl;
-
if (mfi_create_sensors(sc) != 0)
aprint_error("%s: unable to create sensors\n", DEVNAME(sc));
#endif /* NBIO > 0 */
@@ -1300,10 +1299,9 @@
struct mfi_softc *sc = (struct mfi_softc *)dev;
int error = 0;
+ int s = splbio();
DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl ", DEVNAME(sc));
- rw_enter_write(&sc->sc_lock);
-
switch (cmd) {
case BIOCINQ:
DNPRINTF(MFI_D_IOCTL, "inq\n");
@@ -1339,8 +1337,7 @@
DNPRINTF(MFI_D_IOCTL, " invalid ioctl\n");
error = EINVAL;
}
-
- rw_exit_write(&sc->sc_lock);
+ splx(s);
return (error);
}
@@ -1468,7 +1465,7 @@
struct mfi_array *ar;
struct mfi_ld_cfg *ld;
struct mfi_pd_details *pd;
- struct scsi_inquiry_data *inqbuf;
+ struct scsipi_inquiry_data *inqbuf;
char vend[8+16+4+1];
int i, rv = EINVAL;
int arr, vol, disk;
@@ -1478,7 +1475,7 @@
DNPRINTF(MFI_D_IOCTL, "%s: mfi_ioctl_disk %#x\n",
DEVNAME(sc), bd->bd_diskid);
- pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
+ pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK | M_ZERO);
/* send single element command to retrieve size for full structure */
cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
@@ -1554,6 +1551,7 @@
/* get the remaining fields */
*((uint16_t *)&mbox) = ar[arr].pd[disk].mar_pd.mfp_id;
+ memset(pd, 0, sizeof(*pd));
if (mfi_mgmt(sc, MR_DCMD_PD_GET_INFO, MFI_DATA_IN,
sizeof *pd, pd, mbox))
goto freeme;
@@ -1563,7 +1561,7 @@
/* if pd->mpd_enc_idx is 0 then it is not in an enclosure */
bd->bd_channel = pd->mpd_enc_idx;
- inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
+ inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data;
memcpy(vend, inqbuf->vendor, sizeof vend - 1);
vend[sizeof vend - 1] = '\0';
strlcpy(bd->bd_vendor, vend, sizeof(bd->bd_vendor));
@@ -1761,7 +1759,7 @@
struct mfi_pd_details *pd;
struct bioc_disk *sdhs;
struct bioc_vol *vdhs;
- struct scsi_inquiry_data *inqbuf;
+ struct scsipi_inquiry_data *inqbuf;
char vend[8+16+4+1];
int i, rv = EINVAL;
uint32_t size;
@@ -1772,7 +1770,7 @@
if (!bio_hs)
return (EINVAL);
- pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK);
+ pd = malloc(sizeof *pd, M_DEVBUF, M_WAITOK | M_ZERO);
/* send single element command to retrieve size for full structure */
cfg = malloc(sizeof *cfg, M_DEVBUF, M_WAITOK);
@@ -1832,8 +1830,8 @@
sdhs->bd_size = pd->mpd_size / 2; /* XXX why? / 2 */
sdhs->bd_channel = pd->mpd_enc_idx;
sdhs->bd_target = pd->mpd_enc_slot;
- inqbuf = (struct scsi_inquiry_data *)&pd->mpd_inq_data;
- memcpy(vend, inqbuf->vendor, sizeof vend - 1);
+ inqbuf = (struct scsipi_inquiry_data *)&pd->mpd_inq_data;
+ memcpy(vend, inqbuf->vendor, sizeof(vend) - 1);
vend[sizeof vend - 1] = '\0';
strlcpy(sdhs->bd_vendor, vend, sizeof(sdhs->bd_vendor));
break;
@@ -1854,97 +1852,110 @@
int
mfi_create_sensors(struct mfi_softc *sc)
{
- struct device *dev;
- struct scsibus_softc *ssc;
int i;
+ struct envsys_range env_ranges[2];
+ int nsensors = sc->sc_ld_cnt;
- TAILQ_FOREACH(dev, &alldevs, dv_list) {
- if (dev->dv_parent != &sc->sc_dev)
- continue;
-
- /* check if this is the scsibus for the logical disks */
- ssc = (struct scsibus_softc *)dev;
- if (ssc->adapter_link == &sc->sc_link)
- break;
+ env_ranges[0].low = 0;
+ env_ranges[0].high = nsensors;
+ env_ranges[0].units = ENVSYS_DRIVE;
+ env_ranges[1].low = 1;
+ env_ranges[1].high = 0;
+ env_ranges[1].units = 0;
+
+ sc->sc_sensor_data =
+ malloc(sizeof(struct envsys_tre_data) * nsensors,
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (sc->sc_sensor_data == NULL) {
+ aprint_error("%s: can't allocate envsys_tre_data\n",
+ DEVNAME(sc));
+ return(ENOMEM);
}
-
- if (ssc == NULL)
- return (1);
-
- sc->sc_sensors = malloc(sizeof(struct sensor) * sc->sc_ld_cnt,
- M_DEVBUF, M_WAITOK);
- if (sc->sc_sensors == NULL)
- return (1);
- bzero(sc->sc_sensors, sizeof(struct sensor) * sc->sc_ld_cnt);
-
- for (i = 0; i < sc->sc_ld_cnt; i++) {
- if (ssc->sc_link[i][0] == NULL)
- goto bad;
-
- dev = ssc->sc_link[i][0]->device_softc;
-
- sc->sc_sensors[i].type = SENSOR_DRIVE;
- sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
-
- strlcpy(sc->sc_sensors[i].device, DEVNAME(sc),
- sizeof(sc->sc_sensors[i].device));
- strlcpy(sc->sc_sensors[i].desc, dev->dv_xname,
- sizeof(sc->sc_sensors[i].desc));
-
- sensor_add(&sc->sc_sensors[i]);
+ sc->sc_sensor_info =
+ malloc(sizeof(struct envsys_basic_info) * nsensors,
+ M_DEVBUF, M_NOWAIT | M_ZERO);
+ if (sc->sc_sensor_info == NULL) {
+ aprint_error("%s: can't allocate envsys_basic_info\n",
+ DEVNAME(sc));
+ return(ENOMEM);
+ }
+ for (i = 0; i < nsensors; i++) {
+ sc->sc_sensor_data[i].sensor = i;
+ sc->sc_sensor_data[i].units = ENVSYS_DRIVE;
+ sc->sc_sensor_data[i].validflags = ENVSYS_FVALID;
+ sc->sc_sensor_data[i].warnflags = ENVSYS_WARN_OK;
+ sc->sc_sensor_info[i].sensor = i;
+ sc->sc_sensor_info[i].units = ENVSYS_DRIVE;
+ sc->sc_sensor_info[i].validflags = ENVSYS_FVALID;
+ /* logical drives */
+ snprintf(sc->sc_sensor_info[i].desc,
+ sizeof(sc->sc_sensor_info[i].desc), "%s:%d",
+ DEVNAME(sc), i);
+ }
+ sc->sc_ranges = env_ranges;
+ sc->sc_envsys.sme_cookie = sc;
+ sc->sc_envsys.sme_gtredata = mfi_sensor_gtredata;
+ sc->sc_envsys.sme_streinfo = mfi_sensor_streinfo;
+ sc->sc_envsys.sme_nsensors = sc->sc_ld_cnt;
+ sc->sc_envsys.sme_envsys_version = 1000;
+ if (sysmon_envsys_register(&sc->sc_envsys)) {
+ printf("%s: unable to register with sysmon\n", DEVNAME(sc));
+ return(1);
}
-
- if (sensor_task_register(sc, mfi_refresh_sensors, 10) != 0)
- goto bad;
-
return (0);
-
-bad:
- while (--i >= 0)
- sensor_del(&sc->sc_sensors[i]);
- free(sc->sc_sensors, M_DEVBUF);
-
- return (1);
}
-void
-mfi_refresh_sensors(void *arg)
+int
+mfi_sensor_gtredata(struct sysmon_envsys *sme, struct envsys_tre_data *tred)
{
- struct mfi_softc *sc = arg;
- int i;
+ struct mfi_softc *sc = sme->sme_cookie;
struct bioc_vol bv;
+ int s;
+ if (tred->sensor >= sc->sc_ld_cnt || tred->sensor < 0)
+ return EINVAL;
- for (i = 0; i < sc->sc_ld_cnt; i++) {
- bzero(&bv, sizeof(bv));
- bv.bv_volid = i;
- if (mfi_ioctl_vol(sc, &bv))
- return;
-
- switch(bv.bv_status) {
- case BIOC_SVOFFLINE:
- sc->sc_sensors[i].value = SENSOR_DRIVE_FAIL;
- sc->sc_sensors[i].status = SENSOR_S_CRIT;
- break;
+ bzero(&bv, sizeof(bv));
+ bv.bv_volid = tred->sensor;
+ s = splbio();
+ if (mfi_ioctl_vol(sc, &bv)) {
+ splx(s);
+ return EIO;
+ }
+ splx(s);
- case BIOC_SVDEGRADED:
- sc->sc_sensors[i].value = SENSOR_DRIVE_PFAIL;
- sc->sc_sensors[i].status = SENSOR_S_WARN;
- break;
+ switch(bv.bv_status) {
+ case BIOC_SVOFFLINE:
+ tred->cur.data_us = ENVSYS_DRIVE_FAIL;
+ tred->warnflags = ENVSYS_WARN_CRITOVER;
+ break;
- case BIOC_SVSCRUB:
- case BIOC_SVONLINE:
- sc->sc_sensors[i].value = SENSOR_DRIVE_ONLINE;
- sc->sc_sensors[i].status = SENSOR_S_OK;
- break;
+ case BIOC_SVDEGRADED:
+ tred->cur.data_us = ENVSYS_DRIVE_PFAIL;
+ tred->warnflags = ENVSYS_WARN_OVER;
+ break;
- case BIOC_SVINVALID:
- /* FALLTRHOUGH */
- default:
- sc->sc_sensors[i].value = 0; /* unknown */
- sc->sc_sensors[i].status = SENSOR_S_UNKNOWN;
- }
+ case BIOC_SVSCRUB:
+ case BIOC_SVONLINE:
+ tred->cur.data_us = ENVSYS_DRIVE_ONLINE;
+ tred->warnflags = ENVSYS_WARN_OK;
+ break;
+ case BIOC_SVINVALID:
+ /* FALLTRHOUGH */
+ default:
+ tred->cur.data_us = 0; /* unknown */
+ tred->warnflags = ENVSYS_WARN_CRITOVER;
}
+ tred->validflags = ENVSYS_FVALID | ENVSYS_FCURVALID;
+ tred->units = ENVSYS_DRIVE;
+ return 0;
+}
+
+int
+mfi_sensor_streinfo(struct sysmon_envsys *sme, struct envsys_basic_info *binfo)
+{
+ binfo->validflags = 0;
+ return 0;
}
#endif /* NBIO > 0 */
Index: sys/dev/ic/mfivar.h
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/mfivar.h,v
retrieving revision 1.3
diff -u -r1.3 mfivar.h
--- sys/dev/ic/mfivar.h 4 Mar 2007 06:01:58 -0000 1.3
+++ sys/dev/ic/mfivar.h 21 Apr 2007 13:27:03 -0000
@@ -16,6 +16,9 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include <dev/sysmon/sysmonvar.h>
+#include <sys/envsys.h>
+
#define DEVNAME(_s) ((_s)->sc_dev.dv_xname)
/* #define MFI_DEBUG */
@@ -142,7 +145,11 @@
struct mfi_ccb_list sc_ccb_freeq;
- struct sensor *sc_sensors;
+ struct sysmon_envsys sc_envsys;
+#define sc_ranges sc_envsys.sme_ranges
+#define sc_sensor_info sc_envsys.sme_sensor_info
+#define sc_sensor_data sc_envsys.sme_sensor_data
+
};
int mfi_attach(struct mfi_softc *sc);
Index: sys/sys/envsys.h
===================================================================
RCS file: /cvsroot/src/sys/sys/envsys.h,v
retrieving revision 1.10
diff -u -r1.10 envsys.h
--- sys/sys/envsys.h 15 Mar 2006 11:22:23 -0000 1.10
+++ sys/sys/envsys.h 21 Apr 2007 13:27:06 -0000
@@ -95,16 +95,34 @@
ENVSYS_SAMPHOUR,
ENVSYS_INDICATOR, /* boolean indicator */
ENVSYS_INTEGER, /* generic integer return */
+ ENVSYS_DRIVE, /* disk status */
ENVSYS_NSENSORS
};
+/* drive status */
+#define ENVSYS_DRIVE_EMPTY 1
+#define ENVSYS_DRIVE_READY 2
+#define ENVSYS_DRIVE_POWERUP 3
+#define ENVSYS_DRIVE_ONLINE 4
+#define ENVSYS_DRIVE_IDLE 5
+#define ENVSYS_DRIVE_ACTIVE 6
+#define ENVSYS_DRIVE_REBUILD 7
+#define ENVSYS_DRIVE_POWERDOWN 8
+#define ENVSYS_DRIVE_FAIL 9
+#define ENVSYS_DRIVE_PFAIL 10
+
#ifdef ENVSYSUNITNAMES
static const char * const envsysunitnames[] = {
"degC", "RPM", "VAC", "V", "Ohms", "W",
- "A", "Wh", "Ah", "bool", "integer", "Unk"
+ "A", "Wh", "Ah", "bool", "integer", "drive", "Unk"
+};
+static const char * const envsysdrivestatus[] = {
+ "unknown", "empty", "ready", "powering up", "online", "idle", "active",
+ "rebuilding", "powering down", "failed", "degraded"
};
#endif
+
/* flags for validflags */
#define ENVSYS_FVALID 0x00000001 /* sensor is valid */
#define ENVSYS_FCURVALID 0x00000002 /* cur for this sens is valid */
Index: usr.sbin/envstat/envstat.c
===================================================================
RCS file: /cvsroot/src/usr.sbin/envstat/envstat.c,v
retrieving revision 1.23
diff -u -r1.23 envstat.c
--- usr.sbin/envstat/envstat.c 31 Aug 2006 10:25:04 -0000 1.23
+++ usr.sbin/envstat/envstat.c 21 Apr 2007 13:27:11 -0000
@@ -231,6 +231,9 @@
/* different units need some magic */
switch (ebis[i].units)
{
+ case ENVSYS_DRIVE:
+ printf(": drive %s",
+ envsysdrivestatus[etds[i].cur.data_us]);
case ENVSYS_INDICATOR:
break;
case ENVSYS_INTEGER:
@@ -319,6 +322,10 @@
}
switch(etds[i].units) {
+ case ENVSYS_DRIVE:
+ printf(" %*.*s", (int)width, (int)width,
+ envsysdrivestatus[etds[i].cur.data_us]);
+ break;
case ENVSYS_INDICATOR:
printf(" %*.*s", (int)width, (int)width,
etds[i].cur.data_us ? "ON" : "OFF");
--- /dev/null 2007-04-21 15:19:30.000000000 +0200
+++ sbin/bioctl/Makefile 2007-04-08 20:01:44.000000000 +0200
@@ -0,0 +1,10 @@
+# $OpenBSD: Makefile,v 1.8 2006/11/26 11:31:08 deraadt Exp $
+
+PROG= bioctl
+SRCS= bioctl.c strtonum.c
+MAN= bioctl.8
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.prog.mk>
--- /dev/null 2007-04-21 15:19:30.000000000 +0200
+++ sbin/bioctl/bioctl.8 2007-04-08 23:46:55.000000000 +0200
@@ -0,0 +1,164 @@
+.\" $NetBSD: $
+.\" $OpenBSD: bioctl.8,v 1.43 2007/03/20 06:12:11 jmc Exp $
+.\"
+.\" Copyright (c) 2004, 2005 Marco Peereboom
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+.\" ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd April 8, 2007
+.Dt BIOCTL 8
+.Os
+.Sh NAME
+.Nm bioctl
+.Nd RAID management interface
+.Sh SYNOPSIS
+.Nm bioctl
+.Bk -words
+.Op Fl Dhiv
+.Op Fl a Ar alarm-function
+.Op Fl b Ar channel:target[.lun]
+.Op Fl c Ar raidlevel
+.Op Fl H Ar channel:target[.lun]
+.Op Fl l Ar special[,special[,...]]
+.Op Fl u Ar channel:target[.lun]
+.Ar device
+.Ek
+.Sh DESCRIPTION
+RAID device drivers which support management functionality can
+register their services with the
+.Xr bio 4
+driver.
+.Nm bioctl
+then can be used to maintain RAID volumes.
+.Pp
+The options are as follows:
+.Bl -tag -width Ds
+.It Fl a Ar alarm-function
+Control the RAID card's alarm functionality, if supported.
+.Ar alarm-function
+may be one of:
+.Pp
+.Bl -tag -width disable -compact
+.It Ar disable
+Disable the alarm on the RAID controller.
+.It Ar enable
+Enable the alarm on the RAID controller.
+.It Ar get
+Retrieve the current alarm state (enabled or disabled).
+.It Ar silence | Ar quiet
+Silence the alarm if it is currently beeping.
+.El
+.Pp
+The
+.Ar alarm-function
+may be specified as given above,
+or by the first letter only
+(e.g. -a e).
+.It Fl b Ar channel:target[.lun]
+Instruct the device at
+.Ar channel:target[.lun]
+to start blinking, if there is
+.Xr ses 4
+or
+.Xr safte 4
+support in the enclosure.
+.It Fl c Ar raidlevel
+Create a
+.Xr softraid 4
+device of level
+.Ar raidlevel .
+The device must begin with
+.Dq softraid
+followed by a number.
+.It Fl D
+Enable debug output.
+.It Fl H Ar channel:target[.lun]
+If the device at
+.Ar channel:target[.lun]
+is currently marked
+.Dq Unused ,
+promote it to being a
+.Dq Hot Spare .
+.It Fl h
+Where necessary, produce "human-readable" output.
+Use unit suffixes: Byte, Kilobyte, Megabyte,
+Gigabyte, Terabyte, Petabyte, Exabyte in order to reduce the number of
+digits to four or less.
+.It Fl i
+Enumerate the selected RAID devices.
+.It Fl l Ar special[,special[,...]]
+Use
+.Ar special
+device list to create within the
+.Xr softraid 4
+framework.
+Requires
+.Fl c .
+.It Fl u Ar channel:target[.lun]
+Instruct the device at
+.Ar channel:target[.lun]
+to cease blinking, if there is
+.Xr ses 4
+or
+.Xr safte 4
+support in the enclosure.
+.It Fl v
+Be more verbose in output.
+.It Ar device
+Select a drive by name (e.g. sd0) or a RAID controller by name (e.g. ami0).
+For operations which will be performed against
+.Xr ses 4
+or
+.Xr safte 4
+enclosures, it is also possible to directly specify the enclosure name
+(e.g. safte0).
+.El
+.Sh EXAMPLES
+The following command, executed from the command line, shows the status of
+the logical drives on the RAID controller:
+.Bd -literal
+# bioctl -h mfi0
+Volume Status Size Device
+ mfi0 0 Online 74G mfi0 RAID1
+ 0 Online 75G 1:0.0 noencl <ATA WDC WD800JD-75MS1E04>
+ 1 Online 75G 1:1.0 noencl <ATA WDC WD800JD-75MS1E04>
+ mfi0 1 Online 697G mfi0 RAID5
+ 0 Online 233G 1:3.0 noencl <ATA WDC WD2500JS-75N2E04>
+ 1 Online 233G 1:2.0 noencl <ATA WDC WD2500JS-75N2E04>
+ 2 Online 233G 1:4.0 noencl <ATA WDC WD2500JS-75N2E04>
+ 3 Online 233G 1:5.0 noencl <ATA WDC WD2500JS-75N2E04>
+.Ed
+.Sh SEE ALSO
+.Xr bio 4 ,
+.Xr mfi 4 ,
+.Sh BUGS
+the softraid stuff available at this time.
+.Sh HISTORY
+The
+.Nm
+command first appeared in
+.Ox 3.8 .
+.Sh AUTHORS
+The
+.Nm
+interface was written by
+.An Marco Peereboom Aq marco@openbsd.org .
--- /dev/null 2007-04-21 15:19:30.000000000 +0200
+++ sbin/bioctl/bioctl.c 2007-04-08 20:34:31.000000000 +0200
@@ -0,0 +1,661 @@
+/* $NetBSD: $ */
+/* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */
+
+/*
+ * Copyright (c) 2004, 2005 Marco Peereboom
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: raidctl.c,v 1.38 2005/06/02 00:06:14 lukem Exp $");
+#endif
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+// #include <scsi/scsipi_disk.h>
+// #include <scsi/scsipi_all.h>
+#include <dev/biovar.h>
+
+#include <errno.h>
+#include <err.h>
+#include <fcntl.h>
+#include <util.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <util.h>
+#include "strtonum.h"
+
+struct locator {
+ int channel;
+ int target;
+ int lun;
+};
+
+void usage(void);
+const char *str2locator(const char *, struct locator *);
+void cleanup(void);
+
+void bio_inq(char *);
+void bio_alarm(char *);
+void bio_setstate(char *);
+void bio_setblink(char *, char *, int);
+void bio_blink(char *, int, int);
+void bio_createraid(u_int16_t, char *);
+
+int devh = -1;
+int debug;
+int human;
+int verbose;
+
+struct bio_locate bl;
+
+int
+main(int argc, char *argv[])
+{
+ extern char *optarg;
+ u_int64_t func = 0;
+ /* u_int64_t subfunc = 0; XXX */
+ char *bioc_dev = NULL, *sd_dev = NULL;
+ char /* *realname = NULL, XXX */ *al_arg = NULL;
+ char *bl_arg = NULL, *dev_list = NULL;
+ int ch, rv, blink = 0; /* XXX GCC */
+ u_int16_t cr_level = 0; /* XXX GCC */
+
+ if (argc < 2)
+ usage();
+
+ while ((ch = getopt(argc, argv, "b:c:l:u:H:ha:Div")) != -1) {
+ switch (ch) {
+ case 'a': /* alarm */
+ func |= BIOC_ALARM;
+ al_arg = optarg;
+ break;
+ case 'b': /* blink */
+ func |= BIOC_BLINK;
+ blink = BIOC_SBBLINK;
+ bl_arg = optarg;
+ break;
+ case 'c': /* create */
+ func |= BIOC_CREATERAID;
+ cr_level = atoi(optarg);
+ break;
+ case 'u': /* unblink */
+ func |= BIOC_BLINK;
+ blink = BIOC_SBUNBLINK;
+ bl_arg = optarg;
+ break;
+ case 'D': /* debug */
+ debug = 1;
+ break;
+ case 'H': /* set hotspare */
+ func |= BIOC_SETSTATE;
+ al_arg = optarg;
+ break;
+ case 'h':
+ human = 1;
+ break;
+ case 'i': /* inquiry */
+ func |= BIOC_INQ;
+ break;
+ case 'l': /* device list */
+ func |= BIOC_DEVLIST;
+ dev_list = optarg;
+ break;
+ case 'v':
+ verbose = 1;
+ break;
+ default:
+ usage();
+ /* NOTREACHED */
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if (func == 0)
+ func |= BIOC_INQ;
+#if 0
+ /* if at least glob sd[0-9]*, it is a drive identifier */
+ if (strncmp(argv[0], "sd", 2) == 0 && strlen(argv[0]) > 2 &&
+ isdigit((int)argv[0][2]))
+ sd_dev = argv[0];
+ else
+#endif
+ bioc_dev = argv[0];
+
+ if (bioc_dev) {
+ devh = open("/dev/bio", O_RDWR);
+ if (devh == -1)
+ err(1, "Can't open %s", "/dev/bio");
+
+ bl.bl_name = bioc_dev;
+ rv = ioctl(devh, BIOCLOCATE, &bl);
+ if (rv == -1)
+ errx(1, "Can't locate %s device via %s",
+ bl.bl_name, "/dev/bio");
+ }
+#if 0
+ else if (sd_dev) {
+ devh = opendev(sd_dev, O_RDWR, OPENDEV_PART, &realname);
+ if (devh == -1)
+ err(1, "Can't open %s", sd_dev);
+ }
+#endif
+ else
+ errx(1, "need -d or -f parameter");
+
+ if (debug)
+ warnx("cookie = %p", bl.bl_cookie);
+
+ if (func & BIOC_INQ) {
+ bio_inq(sd_dev);
+ } else if (func == BIOC_ALARM) {
+ bio_alarm(al_arg);
+ } else if (func == BIOC_BLINK) {
+ bio_setblink(sd_dev, bl_arg, blink);
+ } else if (func == BIOC_SETSTATE) {
+ bio_setstate(al_arg);
+ } else if (func & BIOC_CREATERAID || func & BIOC_DEVLIST) {
+ if (!(func & BIOC_CREATERAID))
+ errx(1, "need -c parameter");
+ if (!(func & BIOC_DEVLIST))
+ errx(1, "need -l parameter");
+ if (sd_dev)
+ errx(1, "can't use sd device");
+ bio_createraid(cr_level, dev_list);
+ }
+
+ return (0);
+}
+
+void
+usage(void)
+{
+ extern char *__progname;
+
+ fprintf(stderr,
+ "usage: %s [-Dhiv] [-a alarm-function] "
+ "[-b channel:target[.lun]]\n"
+ "\t[-c raidlevel] [-H channel:target[.lun]]\n"
+ "\t[-l special[,special[,...]]] "
+ "[-u channel:target[.lun]] device\n", __progname);
+
+ exit(1);
+}
+
+const char *
+str2locator(const char *string, struct locator *location)
+{
+ const char *errstr;
+ char parse[80], *targ, *lun;
+
+ strlcpy(parse, string, sizeof parse);
+ targ = strchr(parse, ':');
+ if (targ == NULL)
+ return ("target not specified");
+ *targ++ = '\0';
+
+ lun = strchr(targ, '.');
+ if (lun != NULL) {
+ *lun++ = '\0';
+ location->lun = strtonum(lun, 0, 256, &errstr);
+ if (errstr)
+ return (errstr);
+ } else
+ location->lun = 0;
+
+ location->target = strtonum(targ, 0, 256, &errstr);
+ if (errstr)
+ return (errstr);
+ location->channel = strtonum(parse, 0, 256, &errstr);
+ if (errstr)
+ return (errstr);
+ return (NULL);
+}
+
+void
+bio_inq(char *name)
+{
+ const char *status;
+ char size[64], scsiname[16], volname[32];
+ char percent[10], seconds[20];
+ int rv, i, d, volheader, hotspare, unused;
+ char encname[16], serial[32];
+ struct bioc_disk bd;
+ struct bioc_inq bi;
+ struct bioc_vol bv;
+
+ memset(&bi, 0, sizeof(bi));
+
+ if (debug)
+ printf("bio_inq\n");
+
+ bi.bi_cookie = bl.bl_cookie;
+
+ rv = ioctl(devh, BIOCINQ, &bi);
+ if (rv == -1) {
+ warn("BIOCINQ");
+ return;
+ }
+
+ if (debug)
+ printf("bio_inq { %p, %s, %d, %d }\n",
+ bi.bi_cookie,
+ bi.bi_dev,
+ bi.bi_novol,
+ bi.bi_nodisk);
+
+ volheader = 0;
+ for (i = 0; i < bi.bi_novol; i++) {
+ memset(&bv, 0, sizeof(bv));
+ bv.bv_cookie = bl.bl_cookie;
+ bv.bv_volid = i;
+ bv.bv_percent = -1;
+ bv.bv_seconds = 0;
+
+ rv = ioctl(devh, BIOCVOL, &bv);
+ if (rv == -1) {
+ warn("BIOCVOL");
+ return;
+ }
+
+ if (name && strcmp(name, bv.bv_dev) != 0)
+ continue;
+
+ if (!volheader) {
+ volheader = 1;
+ printf("%-7s %-10s %14s %-8s\n",
+ "Volume", "Status", "Size", "Device");
+ }
+
+ percent[0] = '\0';
+ seconds[0] = '\0';
+ if (bv.bv_percent != -1)
+ snprintf(percent, sizeof percent,
+ " %d%% done", bv.bv_percent);
+ if (bv.bv_seconds)
+ snprintf(seconds, sizeof seconds,
+ " %u seconds", bv.bv_seconds);
+ switch (bv.bv_status) {
+ case BIOC_SVONLINE:
+ status = BIOC_SVONLINE_S;
+ break;
+ case BIOC_SVOFFLINE:
+ status = BIOC_SVOFFLINE_S;
+ break;
+ case BIOC_SVDEGRADED:
+ status = BIOC_SVDEGRADED_S;
+ break;
+ case BIOC_SVBUILDING:
+ status = BIOC_SVBUILDING_S;
+ break;
+ case BIOC_SVREBUILD:
+ status = BIOC_SVREBUILD_S;
+ break;
+ case BIOC_SVSCRUB:
+ status = BIOC_SVSCRUB_S;
+ break;
+ case BIOC_SVINVALID:
+ default:
+ status = BIOC_SVINVALID_S;
+ }
+
+ snprintf(volname, sizeof volname, "%s %u",
+ bi.bi_dev, bv.bv_volid);
+
+ if (bv.bv_level == -1 && bv.bv_nodisk == 1) {
+ hotspare = 1;
+ unused = 0;
+ } else if (bv.bv_level == -2 && bv.bv_nodisk == 1) {
+ unused = 1;
+ hotspare = 0;
+ } else {
+ unused = 0;
+ hotspare = 0;
+
+ if (human)
+ humanize_number(size, 5,
+ (int64_t)bv.bv_size, "", HN_AUTOSCALE,
+ HN_B | HN_NOSPACE | HN_DECIMAL);
+ else
+ snprintf(size, sizeof size, "%14llu",
+ (long long unsigned int)bv.bv_size);
+ printf("%7s %-10s %14s %-7s RAID%u%s%s\n",
+ volname, status, size, bv.bv_dev,
+ bv.bv_level, percent, seconds);
+ }
+
+ for (d = 0; d < bv.bv_nodisk; d++) {
+ memset(&bd, 0, sizeof(bd));
+ bd.bd_cookie = bl.bl_cookie;
+ bd.bd_diskid = d;
+ bd.bd_volid = i;
+
+ rv = ioctl(devh, BIOCDISK, &bd);
+ if (rv == -1) {
+ warn("BIOCDISK");
+ return;
+ }
+
+ switch (bd.bd_status) {
+ case BIOC_SDONLINE:
+ status = BIOC_SDONLINE_S;
+ break;
+ case BIOC_SDOFFLINE:
+ status = BIOC_SDOFFLINE_S;
+ break;
+ case BIOC_SDFAILED:
+ status = BIOC_SDFAILED_S;
+ break;
+ case BIOC_SDREBUILD:
+ status = BIOC_SDREBUILD_S;
+ break;
+ case BIOC_SDHOTSPARE:
+ status = BIOC_SDHOTSPARE_S;
+ break;
+ case BIOC_SDUNUSED:
+ status = BIOC_SDUNUSED_S;
+ break;
+ case BIOC_SDSCRUB:
+ status = BIOC_SDSCRUB_S;
+ break;
+ case BIOC_SDINVALID:
+ default:
+ status = BIOC_SDINVALID_S;
+ }
+
+ if (hotspare || unused)
+ ; /* use volname from parent volume */
+ else
+ snprintf(volname, sizeof volname, " %3u",
+ bd.bd_diskid);
+
+ if (human)
+ humanize_number(size, 5,
+ bd.bd_size, "", HN_AUTOSCALE,
+ HN_B | HN_NOSPACE | HN_DECIMAL);
+ else
+ snprintf(size, sizeof size, "%14llu",
+ (long long unsigned int)bd.bd_size);
+ snprintf(scsiname, sizeof scsiname,
+ "%u:%u.%u",
+ bd.bd_channel, bd.bd_target, bd.bd_lun);
+ if (bd.bd_procdev[0])
+ strlcpy(encname, bd.bd_procdev, sizeof encname);
+ else
+ strlcpy(encname, "noencl", sizeof encname);
+ if (bd.bd_serial[0])
+ strlcpy(serial, bd.bd_serial, sizeof serial);
+ else
+ strlcpy(serial, "unknown serial", sizeof serial);
+
+ printf("%7s %-10s %14s %-7s %-6s <%s>\n",
+ volname, status, size, scsiname, encname,
+ bd.bd_vendor);
+ if (verbose)
+ printf("%7s %-10s %14s %-7s %-6s '%s'\n",
+ "", "", "", "", "", serial);
+ }
+ }
+}
+
+void
+bio_alarm(char *arg)
+{
+ int rv;
+ struct bioc_alarm ba;
+
+ ba.ba_cookie = bl.bl_cookie;
+
+ switch (arg[0]) {
+ case 'q': /* silence alarm */
+ /* FALLTHROUGH */
+ case 's':
+ ba.ba_opcode = BIOC_SASILENCE;
+ break;
+
+ case 'e': /* enable alarm */
+ ba.ba_opcode = BIOC_SAENABLE;
+ break;
+
+ case 'd': /* disable alarm */
+ ba.ba_opcode = BIOC_SADISABLE;
+ break;
+
+ case 't': /* test alarm */
+ ba.ba_opcode = BIOC_SATEST;
+ break;
+
+ case 'g': /* get alarm state */
+ ba.ba_opcode = BIOC_GASTATUS;
+ break;
+
+ default:
+ warnx("invalid alarm function: %s", arg);
+ return;
+ }
+
+ rv = ioctl(devh, BIOCALARM, &ba);
+ if (rv == -1) {
+ warn("BIOCALARM");
+ return;
+ }
+
+ if (arg[0] == 'g') {
+ printf("alarm is currently %s\n",
+ ba.ba_status ? "enabled" : "disabled");
+
+ }
+}
+
+void
+bio_setstate(char *arg)
+{
+ struct bioc_setstate bs;
+ struct locator location;
+ const char *errstr;
+ int rv;
+
+ errstr = str2locator(arg, &location);
+ if (errstr)
+ errx(1, "Target %s: %s", arg, errstr);
+
+ bs.bs_cookie = bl.bl_cookie;
+ bs.bs_status = BIOC_SSHOTSPARE;
+ bs.bs_channel = location.channel;
+ bs.bs_target = location.target;
+ bs.bs_lun = location.lun;
+
+ rv = ioctl(devh, BIOCSETSTATE, &bs);
+ if (rv == -1) {
+ warn("BIOCSETSTATE");
+ return;
+ }
+}
+
+void
+bio_setblink(char *name, char *arg, int blink)
+{
+ struct locator location;
+ struct bioc_inq bi;
+ struct bioc_vol bv;
+ struct bioc_disk bd;
+ struct bioc_blink bb;
+ const char *errstr;
+ int v, d, rv;
+
+ errstr = str2locator(arg, &location);
+ if (errstr)
+ errx(1, "Target %s: %s", arg, errstr);
+
+ /* try setting blink on the device directly */
+ memset(&bb, 0, sizeof(bb));
+ bb.bb_cookie = bl.bl_cookie;
+ bb.bb_status = blink;
+ bb.bb_target = location.target;
+ bb.bb_channel = location.channel;
+ rv = ioctl(devh, BIOCBLINK, &bb);
+ if (rv == 0)
+ return;
+
+ /* if the blink didnt work, try to find something that will */
+
+ memset(&bi, 0, sizeof(bi));
+ bi.bi_cookie = bl.bl_cookie;
+ rv = ioctl(devh, BIOCINQ, &bi);
+ if (rv == -1) {
+ warn("BIOCINQ");
+ return;
+ }
+
+ for (v = 0; v < bi.bi_novol; v++) {
+ memset(&bv, 0, sizeof(bv));
+ bv.bv_cookie = bl.bl_cookie;
+ bv.bv_volid = v;
+ rv = ioctl(devh, BIOCVOL, &bv);
+ if (rv == -1) {
+ warn("BIOCVOL");
+ return;
+ }
+
+ if (name && strcmp(name, bv.bv_dev) != 0)
+ continue;
+
+ for (d = 0; d < bv.bv_nodisk; d++) {
+ memset(&bd, 0, sizeof(bd));
+ bd.bd_cookie = bl.bl_cookie;
+ bd.bd_volid = v;
+ bd.bd_diskid = d;
+
+ rv = ioctl(devh, BIOCDISK, &bd);
+ if (rv == -1) {
+ warn("BIOCDISK");
+ return;
+ }
+
+ if (bd.bd_channel == location.channel &&
+ bd.bd_target == location.target &&
+ bd.bd_lun == location.lun) {
+ if (bd.bd_procdev[0] != '\0') {
+ bio_blink(bd.bd_procdev,
+ location.target, blink);
+ } else
+ warnx("Disk %s is not in an enclosure", arg);
+ return;
+ }
+ }
+ }
+
+ warnx("Disk %s does not exist", arg);
+ return;
+}
+
+void
+bio_blink(char *enclosure, int target, int blinktype)
+{
+ int bioh;
+ struct bio_locate bio;
+ struct bioc_blink blink;
+ int rv;
+
+ bioh = open("/dev/bio", O_RDWR);
+ if (bioh == -1)
+ err(1, "Can't open %s", "/dev/bio");
+
+ bio.bl_name = enclosure;
+ rv = ioctl(bioh, BIOCLOCATE, &bio);
+ if (rv == -1)
+ errx(1, "Can't locate %s device via %s", enclosure, "/dev/bio");
+
+ memset(&blink, 0, sizeof(blink));
+ blink.bb_cookie = bio.bl_cookie;
+ blink.bb_status = blinktype;
+ blink.bb_target = target;
+
+ rv = ioctl(bioh, BIOCBLINK, &blink);
+ if (rv == -1)
+ warn("BIOCBLINK");
+
+ close(bioh);
+}
+
+void
+bio_createraid(u_int16_t level, char *dev_list)
+{
+ struct bioc_createraid create;
+ int rv;
+ u_int16_t min_disks = 0;
+
+ if (debug)
+ printf("bio_createraid\n");
+
+ if (!dev_list)
+ errx(1, "no devices specified");
+
+ switch (level) {
+ case 0:
+ min_disks = 1;
+ break;
+ case 1:
+ min_disks = 2;
+ break;
+ default:
+ errx(1, "unsuported raid level");
+ }
+
+ /* XXX validate device list for real */
+#if 0
+ if (strncmp(dev_list, "sd", 2) == 0 && strlen(dev_list) > 2 &&
+ isdigit(dev_list[2])) {
+ if (strlen(dev_list) != 3)
+ errx(1, "only one device supported");
+
+ if (debug)
+ printf("bio_createraid: dev_list: %s\n", dev_list);
+ }
+ else
+ errx(1, "no sd device specified");
+#endif
+
+ memset(&create, 0, sizeof(create));
+ create.bc_cookie = bl.bl_cookie;
+ create.bc_level = level;
+ create.bc_dev_list_len = strlen(dev_list);
+ create.bc_dev_list = dev_list;
+
+ rv = ioctl(devh, BIOCCREATERAID, &create);
+ if (rv == -1) {
+ warn("BIOCCREATERAID");
+ return;
+ }
+}
--- /dev/null 2007-04-21 15:19:30.000000000 +0200
+++ sbin/bioctl/strtonum.c 2007-04-08 20:19:10.000000000 +0200
@@ -0,0 +1,72 @@
+/* $NetBSD: $ */
+/* $OpenBSD: strtonum.c,v 1.6 2004/08/03 19:38:01 millert Exp $ */
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: raidctl.c,v 1.38 2005/06/02 00:06:14 lukem Exp $");
+#endif
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include "strtonum.h"
+
+#define INVALID 1
+#define TOOSMALL 2
+#define TOOLARGE 3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+ const char **errstrp)
+{
+ long long ll = 0;
+ char *ep;
+ int error = 0;
+ struct errval {
+ const char *errstr;
+ int err;
+ } ev[4] = {
+ { NULL, 0 },
+ { "invalid", EINVAL },
+ { "too small", ERANGE },
+ { "too large", ERANGE },
+ };
+
+ ev[0].err = errno;
+ errno = 0;
+ if (minval > maxval)
+ error = INVALID;
+ else {
+ ll = strtoll(numstr, &ep, 10);
+ if (numstr == ep || *ep != '\0')
+ error = INVALID;
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ error = TOOSMALL;
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ error = TOOLARGE;
+ }
+ if (errstrp != NULL)
+ *errstrp = ev[error].errstr;
+ errno = ev[error].err;
+ if (error)
+ ll = 0;
+
+ return (ll);
+}
--- /dev/null 2007-04-21 15:19:30.000000000 +0200
+++ sbin/bioctl/strtonum.h 2007-04-08 20:03:33.000000000 +0200
@@ -0,0 +1,4 @@
+/* $NetBSD: $ */
+
+long long strtonum(const char *, long long, long long, const char **);
+
--mP3DRpeJDSE+ciuQ--