summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorNiklas Hallqvist <niklas@cvs.openbsd.org>1999-01-11 14:49:46 +0000
committerNiklas Hallqvist <niklas@cvs.openbsd.org>1999-01-11 14:49:46 +0000
commit716d3f670d9a4abe5b033357cc6f14e632348acf (patch)
tree8fae0e7cac442a7c0be3b3b0f747ba1691481a49 /sbin
parent3cb3ef4a25f75d713469261851ef2cb4ac4f691e (diff)
Control RAIDframe
Diffstat (limited to 'sbin')
-rw-r--r--sbin/Makefile6
-rw-r--r--sbin/raidctl/Makefile17
-rw-r--r--sbin/raidctl/raidctl.8570
-rw-r--r--sbin/raidctl/raidctl.c390
-rw-r--r--sbin/raidctl/rf_configure.c610
-rw-r--r--sbin/raidctl/rf_utility.c62
-rw-r--r--sbin/raidctl/rf_utility.h50
7 files changed, 1702 insertions, 3 deletions
diff --git a/sbin/Makefile b/sbin/Makefile
index f871048ff61..d15e6234f8d 100644
--- a/sbin/Makefile
+++ b/sbin/Makefile
@@ -1,12 +1,12 @@
-# $OpenBSD: Makefile,v 1.36 1998/12/21 03:35:14 deraadt Exp $
+# $OpenBSD: Makefile,v 1.37 1999/01/11 14:49:42 niklas Exp $
# Not ported: XNSrouted enpload scsiformat startslip
# Missing: icheck
SUBDIR= badsect ccdconfig disklabel dmesg fsck ifconfig init ipf ipfstat \
ipnat ipsecadm isakmpd kbd mknod modload modunload mount mountd \
- ncheck_ffs nfsd nfsiod nologin photurisd ping quotacheck reboot \
- route routed savecore scan_ffs scsi shutdown slattach startkey \
+ ncheck_ffs nfsd nfsiod nologin photurisd ping quotacheck raidctl \
+ reboot route routed savecore scan_ffs scsi shutdown slattach startkey \
swapon ttyflags umount
# support for various file systems
diff --git a/sbin/raidctl/Makefile b/sbin/raidctl/Makefile
new file mode 100644
index 00000000000..e0fc9f237b7
--- /dev/null
+++ b/sbin/raidctl/Makefile
@@ -0,0 +1,17 @@
+# $OpenBSD: Makefile,v 1.1 1999/01/11 14:49:43 niklas Exp $
+
+PROG= raidctl
+SRCS= rf_configure.c rf_layout.c rf_strutils.c raidctl.c
+MAN= raidctl.8
+
+CFLAGS += -Wall
+
+LOOKHERE = ${.CURDIR}/../../sys/dev/raidframe
+
+CFLAGS+= -DCSRG_BASED -DNARROWPROTO -DRF_UTILITY=1 -DSIMULATE=1 -I${LOOKHERE}
+.PATH: ${LOOKHERE}
+
+DPADD= ${LIBUTIL}
+LDADD= -lutil
+
+.include <bsd.prog.mk>
diff --git a/sbin/raidctl/raidctl.8 b/sbin/raidctl/raidctl.8
new file mode 100644
index 00000000000..f9ecb3ce602
--- /dev/null
+++ b/sbin/raidctl/raidctl.8
@@ -0,0 +1,570 @@
+.\" $OpenBSD: raidctl.8,v 1.1 1999/01/11 14:49:44 niklas Exp $
+.\"
+.\"
+.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Greg Oster
+.\"
+.\" 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. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the NetBSD
+.\" Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\" contributors may be used to endorse or promote products derived
+.\" from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+.\"
+.\"
+.\" Copyright (c) 1995 Carnegie-Mellon University.
+.\" All rights reserved.
+.\"
+.\" Author: Mark Holland
+.\"
+.\" Permission to use, copy, modify and distribute this software and
+.\" its documentation is hereby granted, provided that both the copyright
+.\" notice and this permission notice appear in all copies of the
+.\" software, derivative works or modified versions, and any portions
+.\" thereof, and that both notices appear in supporting documentation.
+.\"
+.\" CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+.\" CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+.\" FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+.\"
+.\" Carnegie Mellon requests users of this software to return to
+.\"
+.\" Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+.\" School of Computer Science
+.\" Carnegie Mellon University
+.\" Pittsburgh PA 15213-3890
+.\"
+.\" any improvements or extensions that they make and grant Carnegie the
+.\" rights to redistribute these changes.
+.\"
+.Dd November 6, 1998
+.Dt RAIDCTL 8
+.Os
+.Sh NAME
+.Nm raidctl
+.Nd configuration utility for the RAIDframe disk driver
+.Sh SYNOPSIS
+.Nm
+.Fl c Ar config_file Ar dev
+.Nm ""
+.Fl C Ar dev
+.Nm ""
+.Fl f Ar component Ar dev
+.Nm ""
+.Fl F Ar component Ar dev
+.Nm ""
+.Fl r Ar dev
+.Nm ""
+.Fl R Ar dev
+.Nm ""
+.Fl s Ar dev
+.Nm ""
+.Fl u Ar dev
+.Sh DESCRIPTION
+.Nm
+is the user-land control program for
+.Xr raid 4 , Ns
+the RAIDframe disk device.
+.Nm
+is primarily used to dynamically configure and unconfigure RAIDframe disk
+devices. For more information about the RAIDframe disk device, see
+.Xr raid 4 .
+.Pp
+This document assumes the reader has at least rudimentary knowledge of
+RAID and RAID concepts.
+.Pp
+The command-line options for
+.Nm
+are as follows:
+.Bl -tag -width indent
+.It Fl c Ar config_file Ar dev
+Configure the RAIDframe device
+.Ar dev
+according to the configuration given in
+.Ar config_file .
+A description of the contents of
+.Ar config_file
+is given later.
+.It Fl C Ar dev
+Initiate a copyback of reconstructed data from a spare disk to
+it's original disk. This is performed after a component has failed,
+and the failed drive has been reconstructed onto a spare drive.
+.It Fl f Ar component Ar dev
+This marks the specified
+.Ar component
+as having failed, but does not initiate a reconstruction of that
+component.
+.It Fl F Ar component Ar dev
+Fails the specified
+.Ar component
+of the device, and immediately begin a reconstruction of the failed
+disk onto an available hot spare. This is the mechanism used to start
+the reconstruction process if a component does have a hardware failure.
+.It Fl r Ar dev
+Re-write the parity on the device. This
+.Ar MUST
+be done before the RAID device is labeled and before
+filesystems are created on the RAID device, and is normally used after
+a system crash (and before a
+.Xr fsck 8 ) Ns
+to ensure the integrity of the parity.
+.It Fl R Ar dev
+Check the status of component reconstruction. The output indicates
+the amount of progress achieved in reconstructing a failed component.
+.It Fl s Ar dev
+Display the status of the RAIDframe device for each of the components
+and spares.
+.It Fl u Ar dev
+Unconfigure the RAIDframe device.
+.El
+.Pp
+The device used by
+.Nm
+is specified by
+.Ar dev .
+.Ar dev
+may be either the full name of the device, e.g. /dev/rraid0d,
+for the i386 architecture, and /dev/rraid0c
+for all others, or just simply raid0 (for /dev/rraid0d).
+.Pp
+The format of the configuration file is complex, and
+only an abbreviated treatment is given here. In the configuration
+files, a
+.Sq #
+indicates the beginning of a comment.
+.Pp
+There are 4 required sections of a configuration file, and 2
+optional components. Each section begins with a
+.Sq START ,
+followed by
+the section name, and the confuration parameters associated with that
+section. The first section is the
+.Sq array
+section, and it specifies
+the number of rows, columns, and spare disks in the RAID array. For
+example:
+.Bd -unfilled -offset indent
+START array
+1 3 0
+.Ed
+.Pp
+indicates an array with 1 row, 3 columns, and 0 spare disks. Note
+that allthough multi-dimenstional arrays may be specified, they are
+.Ar NOT
+supported in the driver.
+.Pp
+The second section, the
+.Sq disks
+section, specifies the actual
+components of the device. For example:
+.Bd -unfilled -offset indent
+START disks
+/dev/sd0e
+/dev/sd1e
+/dev/sd2e
+.Ed
+.Pp
+specifies the three component disks to be used in the RAID device. If
+any of the specified drives cannot be found when the RAID device is
+configured, then they will be marked as
+.Sq failed ,
+and the system will
+operate in degraded mode. Note that it is
+.Ar imperative
+that the order of the components in the configuration file does not
+change between configurations of a RAID device. Changing the order
+of the components (at least at the time of this writing) will result in
+data loss.
+.Pp
+The next section, which is the
+.Sq spare
+section, is optional, and, if
+present, specifies the devices to be used as
+.Sq hot spares
+-- devices
+which are on-line, but are not actively used by the RAID driver unless
+one of the main components fail. A simple
+.Sq spare
+section might be:
+.Bd -unfilled -offset indent
+START spare
+/dev/sd3e
+.Ed
+.Pp
+for a configuration with a single spare component. If no spare drives
+are to be used in the configuration, then the
+.Sq spare
+section may be ommitted.
+.Pp
+The next section is the
+.Sq layout
+section. This section describes the
+general layout parameters for the RAID device, and provides such
+information as sectors per stripe unit, stripe units per parity unit,
+stripe units per reconstruction unit, and the parity configuration to
+use. This section might look like:
+.Bd -unfilled -offset indent
+START layout
+# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level
+32 1 1 5
+.Ed
+.Pp
+The sectors per stripe unit specifies, in blocks, the interleave
+factor; i.e. the number of contiguous sectors to be written to each
+component for a single stripe. Appropriate selection of this value
+(32 in this example) is the subject of much research in RAID
+architectures. The stripe units per parity unit and
+stripe units per reconstruction unit are normally each set to 1.
+While certain values above 1 are permitted, a discussion of valid
+values and the consequences of using anything other than 1 are outside
+the scope of this document. The last value in this section (5 in this
+example) indicates the parity configuration desired. Valid entries
+include:
+.Bl -tag -width inde
+.It 0
+RAID level 0. No parity, only simple striping.
+.It 1
+RAID level 1. Mirroring.
+.It 4
+RAID level 4. Striping across components, with parity stored on the
+last component.
+.It 5
+RAID level 5. Striping across components, parity distributed across
+all components.
+.El
+.Pp
+There are other valid entries here, including those for Even-Odd
+parity, RAID level 5 with rotated sparing, Chained declustering,
+and Interleaved declustering, but as of this writing the code for
+those parity operations has not been tested with
+.Ox .
+.Pp
+The next required section is the
+.Sq queue
+section. This is most often
+specified as:
+.Bd -unfilled -offset indent
+START queue
+fifo 1
+.Ed
+.Pp
+where the queueing method is specified as fifo (first-in, first-out),
+and the size of the per-component queue is limited to 1 requests. A
+value of 1 is quite conservative here, and values of 100 or more may
+been used to increase the driver performance.
+Other queuing methods may also be specified, but a discussion of them
+is beyond the scope of this document.
+.Pp
+The final section, the
+.Sq debug section, is optional. For more details
+on this the reader is referred to the RAIDframe documentation
+dissussed in the
+.Sx HISTORY
+section.
+
+See
+.Sx EXAMPLES
+for a more complete configuration file example.
+
+.Sh EXAMPLES
+
+The examples in this section will focus on a RAID 5 configuration.
+Other RAID configurations will behave similarly. It is highly
+recommended that before using the RAID driver for real filesystems
+that the system administrator(s) have used
+.Ar all
+of the options for
+.Nm ,
+and that they understand how the component reconstruction process
+works. While this example is not created as a tutorial, the steps
+shown here can be easily dupilicated using four equal-sized partitions
+from any number of disks (including all four from a single disk).
+.Pp
+The primary uses of
+.Nm
+is to configure and unconfigure
+.Xr raid 4
+devices. To configure the device, a configuration
+file which looks something like:
+.Bd -unfilled -offset indent
+START array
+# numRow numCol numSpare
+1 3 1
+
+START disks
+/dev/sd1e
+/dev/sd2e
+/dev/sd3e
+
+START spare
+/dev/sd4e
+
+START layout
+# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_5
+32 1 1 5
+
+START queue
+fifo 100
+.Ed
+.Pp
+is first created. In short, this configuration file specifies a RAID
+5 configuration consisting of the disks /dev/sd1e, /dev/sd2e, and
+/dev/sd3e, with /dev/sd4e available as a
+.Sq hot spare
+in case one of
+the three main drives should fail. If the above configuration is in a
+file called
+.Sq rfconfig ,
+raid device 0 can be configured with:
+.Bd -unfilled -offset indent
+raidctl -c rfconfig raid0
+.Ed
+.Pp
+The above is equivalent to the following:
+.Bd -unfilled -offset indent
+raidctl -c rfconfig /dev/rraid0d
+.Ed
+.Pp
+on the i386 architecture. On all other architectures, /dev/rraid0c
+is used in place of /dev/rraid0d.
+.Pp
+To see how the device is doing, the following will show the status:
+.Bd -unfilled -offset indent
+raidctl -s raid0
+.Ed
+.Pp
+The output will look something like:
+.Bd -unfilled -offset indent
+Components:
+ /dev/sd1e: optimal
+ /dev/sd2e: optimal
+ /dev/sd3e: optimal
+Spares:
+ /dev/sd4e [0][0]: spare
+.Ed
+.Pp
+This indicates that all is well with the RAID array. If this is the first
+time this RAID array has been configured, or the system is just being
+brought up after an unclean shutdown, it is necessary to
+ensure that the parity values are correct. This can be done via:
+.Bd -unfilled -offset indent
+raidctl -r raid0
+.Ed
+.Pp
+Once this is done, it is then safe to perform
+.Xr disklabel 8 , Ns
+.Xr newfs 8 , Ns
+or
+.Xr fsck 8
+on the device or its filesystems.
+.Pp
+If for some reason
+(perhaps to test reconstruction) it is necessary to pretend a drive
+has failed, the following will perform that function:
+.Bd -unfilled -offset indent
+raidctl -f /dev/sd2e raid0
+.Ed
+.Pp
+The system will then be performing all operations in degraded mode,
+were missing data is re-computed from existing data and the parity.
+In this case, obtaining the status of raid0 will return:
+.Bd -unfilled -offset indent
+Components:
+ /dev/sd1e: optimal
+ /dev/sd2e: failed
+ /dev/sd3e: optimal
+Spares:
+ /dev/sd4e [0][0]: spare
+.Ed
+.Pp
+Note that with the use of
+.Fl f
+a reconstruction has not been started. To both fail the disk and
+start a reconstruction, the
+.Fl F
+option must be used. (The
+.Fl f
+option may be used first, and then the
+.Fl F
+option used later, on the same disk, if desired.)
+Immediately after the reconstruction is started, the status will report:
+.Bd -unfilled -offset indent
+Components:
+ /dev/sd1e: optimal
+ /dev/sd2e: reconstructing
+ /dev/sd3e: optimal
+Spares:
+ /dev/sd4e [0][0]: used_spare
+.Ed
+.Pp
+This indicates that a reconstruction is in progress. To find out how
+the reconstruction is progressing the
+.Fl R
+option may be used. This will indicate the progress in terms of the
+percentage of the reconstruction that is completed. When the
+reconstruction is finished the
+.Fl s
+option will show:
+.Bd -unfilled -offset indent
+Components:
+ /dev/sd1e: optimal
+ /dev/sd2e: spared
+ /dev/sd3e: optimal
+Spares:
+ /dev/sd4e [0][0]: used_spare
+.Ed
+.Pp
+At this point there are at least two options. First, if /dev/sd2e is
+known to be good (i.e. the failure was either caused by
+.Fl f
+or
+.Fl F ,
+or the failed disk was replaced), then a copyback of the data can
+be initiated with the
+.Fl C
+option. In this example, this would copy the entire contents of
+/dev/sd4e to /dev/sd2e. Once the copyback procedure is complete, the
+status of the device would be:
+.Bd -unfilled -offset indent
+Components:
+ /dev/sd1e: optimal
+ /dev/sd2e: optimal
+ /dev/sd3e: optimal
+Spares:
+ /dev/sd4e [0][0]: spare
+.Ed
+.Pp
+and the system is back to normal operation.
+.Pp
+The second option after the reconstruction is to simply use /dev/sd4e
+in place of /dev/sd2e in the configuration file. For example, the
+configuration file (in part) might now look like:
+.Bd -unfilled -offset indent
+START array
+1 3 0
+
+START drives
+/dev/sd1e
+/dev/sd4e
+/dev/sd3e
+.Ed
+.Pp
+This can be done as /dev/sd4e is completely interchangeable with
+/dev/sd2e at this point. Note that extreme care must be taken when
+changing the order of the drives in a configuration. This is one of
+the few instances where the devices and/or their orderings can be
+changed without loss of data! In general, the ordering of components
+in a configuration file should
+.Ar never
+be changed.
+.Pp
+The final operation performed by
+.Nm
+is to unconfigure a
+.Xr raid 4
+device. This is accomplished via a simple:
+.Bd -unfilled -offset indent
+raidctl -u raid0
+.Ed
+.Pp
+at which point the device is ready to be reconfigured.
+.Sh WARNINGS
+Certain RAID levels (1, 4, 5, 6, and others) can protect against some
+data loss due to component failure. However the loss of two
+components of a RAID 4 or 5 system, or the loss of a single component
+of a RAID 0 system will result in the entire filesystem being lost.
+RAID is
+.Ar NOT
+a substitute for good backup practices.
+.Pp
+Recomputation of parity
+.Ar MUST
+be performed whenever there is a chance that it may have been
+compromised. This includes after system crashes, or before a RAID
+device has been used for the first time. Failure to keep parity
+correct will be catastrophic should a component ever fail -- it is
+better to use RAID 0 and get the additional space and speed, than it
+is to use parity, but not keep the parity correct. At least with RAID
+0 there is no perception of increased data security.
+.Pp
+.Sh FILES
+.Bl -tag -width /dev/XXrXraidX -compact
+.It Pa /dev/{,r}raid*
+.Nm
+device special files.
+.El
+.Pp
+.Sh SEE ALSO
+.Xr raid 4 ,
+.Xr ccd 4 ,
+.Xr rc 8
+.Sh HISTORY
+RAIDframe is a framework for rapid prototyping of RAID structures
+developed by the folks at the Parallel Data Laboratory at Carnegie
+Mellon University (CMU).
+A more complete description of the internals and functionality of
+RAIDframe is found in the paper "RAIDframe: A Rapid Prototyping Tool
+for RAID Systems", by William V. Courtright II, Garth Gibson, Mark
+Holland, LeAnn Neal Reilly, and Jim Zelenka, and published by the
+Parallel Data Laboratory of Carnegie Mellon University.
+.Pp
+The
+.Nm
+command first appeared as a program in CMU's RAIDframe v1.1 distribution. This
+version of
+.Nm
+is a complete re-write, and first appeared in
+.Nx 1.4 .
+.Sh COPYRIGHT
+.Bd -unfilled
+
+The RAIDframe Copyright is as follows:
+
+Copyright (c) 1994-1996 Carnegie-Mellon University.
+All rights reserved.
+
+Permission to use, copy, modify and distribute this software and
+its documentation is hereby granted, provided that both the copyright
+notice and this permission notice appear in all copies of the
+software, derivative works or modified versions, and any portions
+thereof, and that both notices appear in supporting documentation.
+
+CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+
+Carnegie Mellon requests users of this software to return to
+
+ Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ School of Computer Science
+ Carnegie Mellon University
+ Pittsburgh PA 15213-3890
+
+any improvements or extensions that they make and grant Carnegie the
+rights to redistribute these changes.
+
+.Ed
diff --git a/sbin/raidctl/raidctl.c b/sbin/raidctl/raidctl.c
new file mode 100644
index 00000000000..9c49a61bfbd
--- /dev/null
+++ b/sbin/raidctl/raidctl.c
@@ -0,0 +1,390 @@
+/* $OpenBSD: raidctl.c,v 1.1 1999/01/11 14:49:44 niklas Exp $ */
+
+/*-
+ * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Greg Oster
+ *
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the NetBSD
+ * Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+
+ This program is a re-write of the original rf_ctrl program
+ distributed by CMU with RAIDframe 1.1.
+
+ This program is the user-land interface to the RAIDframe kernel
+ driver in NetBSD.
+
+ */
+
+#include <sys/param.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <util.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <err.h>
+#include <sys/types.h>
+#include <string.h>
+#include <sys/disklabel.h>
+#include <machine/disklabel.h>
+#include "rf_raidframe.h"
+
+extern char *__progname;
+
+int main __P((int, char *[]));
+static void do_ioctl __P((int, unsigned long, void *, char *));
+static void rf_configure __P((int, char*));
+static char *device_status __P((RF_DiskStatus_t));
+static void rf_get_device_status __P((int));
+static void rf_fail_disk __P((int, char *, int));
+static void usage __P((void));
+
+int
+main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ int ch;
+ int num_options;
+ unsigned long action;
+ char config_filename[PATH_MAX];
+ char dev_name[PATH_MAX];
+ char name[PATH_MAX];
+ char component_to_fail[PATH_MAX];
+ int do_recon;
+ int raidID;
+ int rawpart;
+ int recon_percent_done;
+ struct stat st;
+ int fd;
+
+ num_options = 0;
+ action = 0;
+ do_recon = 0;
+
+ while ((ch = getopt(argc, argv, "c:Cf:F:rRsu")) != -1)
+ switch(ch) {
+ case 'c':
+ strncpy(config_filename,optarg,PATH_MAX);
+ action = RAIDFRAME_CONFIGURE;
+ num_options++;
+ break;
+ case 'C':
+ action = RAIDFRAME_COPYBACK;
+ num_options++;
+ break;
+ case 'f':
+ action = RAIDFRAME_FAIL_DISK;
+ do_recon = 0;
+ strncpy(component_to_fail, optarg, PATH_MAX);
+ num_options++;
+ break;
+ case 'F':
+ action = RAIDFRAME_FAIL_DISK;
+ do_recon = 1;
+ strncpy(component_to_fail, optarg, PATH_MAX);
+ num_options++;
+ break;
+ case 'r':
+ action = RAIDFRAME_REWRITEPARITY;
+ num_options++;
+ break;
+ case 'R':
+ action = RAIDFRAME_CHECKRECON;
+ num_options++;
+ break;
+ case 's':
+ action = RAIDFRAME_GET_INFO;
+ num_options++;
+ break;
+ case 'u':
+ action = RAIDFRAME_SHUTDOWN;
+ num_options++;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if ((num_options > 1) || (argc == NULL))
+ usage();
+
+ strncpy(name,argv[0],PATH_MAX);
+
+ if ((name[0] == '/') || (name[0] == '.')) {
+ /* they've (apparently) given a full path... */
+ strncpy(dev_name, name, PATH_MAX);
+ } else {
+ if (isdigit(name[strlen(name)-1])) {
+ rawpart = getrawpartition();
+ snprintf(dev_name,PATH_MAX,"/dev/%s%c",name,
+ 'a'+rawpart);
+ } else {
+ snprintf(dev_name,PATH_MAX,"/dev/%s",name);
+ }
+ }
+
+ if (stat(dev_name, &st) != 0) {
+ fprintf(stderr,"%s: stat failure on: %s\n",
+ __progname,dev_name);
+ return (errno);
+ }
+ if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
+ fprintf(stderr,"%s: invalid device: %s\n",
+ __progname,dev_name);
+ return (EINVAL);
+ }
+
+ raidID = RF_DEV2RAIDID(st.st_rdev);
+
+ if ((fd = open( dev_name, O_RDWR, 0640)) < 0) {
+ fprintf(stderr, "%s: unable to open device file: %s\n",
+ __progname, dev_name);
+ exit(1);
+ }
+
+
+ switch(action) {
+ case RAIDFRAME_CONFIGURE:
+ rf_configure(fd, config_filename);
+ break;
+ case RAIDFRAME_COPYBACK:
+ printf("Copyback.\n");
+ do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK");
+ break;
+ case RAIDFRAME_FAIL_DISK:
+ rf_fail_disk(fd,component_to_fail,do_recon);
+ break;
+ case RAIDFRAME_REWRITEPARITY:
+ printf("Initiating re-write of parity\n");
+ do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
+ "RAIDFRAME_REWRITEPARITY");
+ break;
+ case RAIDFRAME_CHECKRECON:
+ do_ioctl(fd, RAIDFRAME_CHECKRECON, &recon_percent_done,
+ "RAIDFRAME_CHECKRECON");
+ printf("Reconstruction is %d%% complete.\n",
+ recon_percent_done);
+ break;
+ case RAIDFRAME_GET_INFO:
+ rf_get_device_status(fd);
+ break;
+ case RAIDFRAME_SHUTDOWN:
+ do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
+ break;
+ default:
+ break;
+ }
+
+ close(fd);
+ exit(0);
+}
+
+static void
+do_ioctl(fd, command, arg, ioctl_name)
+ int fd;
+ unsigned long command;
+ void *arg;
+ char *ioctl_name;
+{
+ if (ioctl(fd, command, arg) < 0) {
+ warn("ioctl (%s) failed", ioctl_name);
+ exit(1);
+ }
+}
+
+
+static void
+rf_configure(fd,config_file)
+ int fd;
+ char *config_file;
+{
+ void *generic;
+ RF_Config_t cfg;
+
+ if (rf_MakeConfig( config_file, &cfg ) < 0) {
+ fprintf(stderr,"%s: unable to create RAIDframe %s\n",
+ __progname, "configuration structure\n");
+ exit(1);
+ }
+
+ /*
+
+ Note the extra level of redirection needed here, since
+ what we really want to pass in is a pointer to the pointer to
+ the configuration structure.
+
+ */
+
+ generic = (void *) &cfg;
+ do_ioctl(fd,RAIDFRAME_CONFIGURE,&generic,"RAIDFRAME_CONFIGURE");
+#if 0
+ if (ioctl(fd, RAIDFRAME_CONFIGURE, &generic) < 0) {
+ warn("ioctl (RAIDFRAME_CONFIGURE): failed\n");
+ exit(1);
+ }
+#endif
+}
+
+static char *
+device_status(status)
+ RF_DiskStatus_t status;
+{
+ static char status_string[256];
+
+ switch (status) {
+ case rf_ds_optimal:
+ strcpy(status_string,"optimal");
+ break;
+ case rf_ds_failed:
+ strcpy(status_string,"failed");
+ break;
+ case rf_ds_reconstructing:
+ strcpy(status_string,"reconstructing");
+ break;
+ case rf_ds_dist_spared:
+ strcpy(status_string,"dist_spared");
+ break;
+ case rf_ds_spared:
+ strcpy(status_string,"spared");
+ break;
+ case rf_ds_spare:
+ strcpy(status_string,"spare");
+ break;
+ case rf_ds_used_spare:
+ strcpy(status_string,"used_spare");
+ break;
+ default:
+ strcpy(status_string,"UNKNOWN");
+ break;
+ }
+ return(status_string);
+}
+
+static void
+rf_get_device_status(fd)
+ int fd;
+{
+ RF_DeviceConfig_t device_config;
+ void *cfg_ptr;
+ int i;
+
+ cfg_ptr = &device_config;
+
+ do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
+
+ printf("Components:\n");
+ for(i=0; i < device_config.ndevs; i++) {
+ printf("%20s: %s\n", device_config.devs[i].devname,
+ device_status(device_config.devs[i].status));
+ }
+ if (device_config.nspares > 0) {
+ printf("Spares:\n");
+ for(i=0; i < device_config.nspares; i++) {
+ printf("%20s [%d][%d]: %s\n",
+ device_config.spares[i].devname,
+ device_config.spares[i].spareRow,
+ device_config.spares[i].spareCol,
+ device_status(device_config.spares[i].status));
+ }
+ } else {
+ printf("No spares.\n");
+ }
+
+}
+
+static void
+rf_fail_disk(fd, component_to_fail, do_recon)
+ int fd;
+ char *component_to_fail;
+ int do_recon;
+{
+ struct rf_recon_req recon_request;
+ RF_DeviceConfig_t device_config;
+ void *cfg_ptr;
+ int i;
+ int found;
+ int component_num;
+
+ component_num = -1;
+
+ /* Assuming a full path spec... */
+ cfg_ptr = &device_config;
+ do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr,
+ "RAIDFRAME_GET_INFO");
+ found = 0;
+ for(i=0; i < device_config.ndevs; i++) {
+ if (strncmp(component_to_fail,
+ device_config.devs[i].devname,
+ PATH_MAX)==0) {
+ found = 1;
+ component_num = i;
+ }
+ }
+ if (!found) {
+ fprintf(stderr,"%s: %s is not a component %s",
+ __progname, component_to_fail,
+ "of this device\n");
+ exit(1);
+ }
+
+ recon_request.row = component_num / device_config.cols;
+ recon_request.col = component_num % device_config.cols;
+ if (do_recon) {
+ recon_request.flags = RF_FDFLAGS_RECON;
+ } else {
+ recon_request.flags = RF_FDFLAGS_NONE;
+ }
+ do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request,
+ "RAIDFRAME_FAIL_DISK");
+
+}
+
+static void
+usage()
+{
+ fprintf(stderr, "usage: %s -c config_file dev\n", __progname);
+ fprintf(stderr, " %s -C dev\n", __progname);
+ fprintf(stderr, " %s -f component dev\n", __progname);
+ fprintf(stderr, " %s -F component dev\n", __progname);
+ fprintf(stderr, " %s -r dev\n", __progname);
+ fprintf(stderr, " %s -R dev\n", __progname);
+ fprintf(stderr, " %s -s dev\n", __progname);
+ fprintf(stderr, " %s -u dev\n", __progname);
+ exit(1);
+ /* NOTREACHED */
+}
diff --git a/sbin/raidctl/rf_configure.c b/sbin/raidctl/rf_configure.c
new file mode 100644
index 00000000000..6e0f28e6a1d
--- /dev/null
+++ b/sbin/raidctl/rf_configure.c
@@ -0,0 +1,610 @@
+/* $OpenBSD: rf_configure.c,v 1.1 1999/01/11 14:49:44 niklas Exp $ */
+
+/*
+ * Copyright (c) 1995 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Mark Holland
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/***************************************************************
+ *
+ * rf_configure.c -- code related to configuring the raidframe system
+ *
+ * configuration is complicated by the fact that we want the same
+ * driver to work both in the kernel and at user level. In the
+ * kernel, we can't read the configuration file, so we configure
+ * by running a user-level program that reads the config file,
+ * creates a data structure describing the configuration and
+ * passes it into the kernel via an ioctl. Since we want the config
+ * code to be common between the two versions of the driver, we
+ * configure using the same two-step process when running at
+ * user level. Of course, at user level, the config structure is
+ * passed directly to the config routine, rather than via ioctl.
+ *
+ * This file is not compiled into the kernel, so we have no
+ * need for KERNEL ifdefs.
+ *
+ **************************************************************/
+
+/* $Locker: $
+ * $Log: rf_configure.c,v $
+ * Revision 1.1 1999/01/11 14:49:44 niklas
+ * Control RAIDframe
+ *
+ * Revision 1.1.1.2 1998/11/23 21:35:58 niklas
+ * NetBSD-current 981123
+ *
+ * Revision 1.2 1998/11/23 00:18:40 mrg
+ * fix compile errors on the alpha.
+ *
+ * Revision 1.1 1998/11/13 04:34:02 oster
+ *
+ * RAIDframe, version 1.1, from the Parallel Data Laboratory at
+ * Carnegie Mellon University. Full RAID implementation, including
+ * levels 0, 1, 4, 5, 6, parity logging, and a few other goodies.
+ * Ported to NetBSD by Greg Oster.
+ *
+ * raidctl is our userland configuration tool for RAIDframe.
+ *
+ * Revision 1.42 1996/08/09 18:47:47 jimz
+ * major -> dev_major
+ *
+ * Revision 1.41 1996/07/29 14:05:12 jimz
+ * fix numPUs/numRUs confusion (everything is now numRUs)
+ * clean up some commenting, return values
+ *
+ * Revision 1.40 1996/07/27 23:36:08 jimz
+ * Solaris port of simulator
+ *
+ * Revision 1.39 1996/07/27 18:39:45 jimz
+ * cleanup sweep
+ *
+ * Revision 1.38 1996/07/18 22:57:14 jimz
+ * port simulator to AIX
+ *
+ * Revision 1.37 1996/06/19 14:58:02 jimz
+ * move layout-specific config parsing hooks into RF_LayoutSW_t
+ * table in rf_layout.c
+ *
+ * Revision 1.36 1996/06/17 14:38:33 jimz
+ * properly #if out RF_DEMO code
+ * fix bug in MakeConfig that was causing weird behavior
+ * in configuration routines (config was not zeroed at start)
+ * clean up genplot handling of stacks
+ *
+ * Revision 1.35 1996/06/05 19:38:32 jimz
+ * fixed up disk queueing types config
+ * added sstf disk queueing
+ * fixed exit bug on diskthreads (ref-ing bad mem)
+ *
+ * Revision 1.34 1996/06/03 23:28:26 jimz
+ * more bugfixes
+ * check in tree to sync for IPDS runs with current bugfixes
+ * there still may be a problem with threads in the script test
+ * getting I/Os stuck- not trivially reproducible (runs ~50 times
+ * in a row without getting stuck)
+ *
+ * Revision 1.33 1996/06/02 17:31:48 jimz
+ * Moved a lot of global stuff into array structure, where it belongs.
+ * Fixed up paritylogging, pss modules in this manner. Some general
+ * code cleanup. Removed lots of dead code, some dead files.
+ *
+ * Revision 1.32 1996/05/30 23:22:16 jimz
+ * bugfixes of serialization, timing problems
+ * more cleanup
+ *
+ * Revision 1.31 1996/05/30 11:29:41 jimz
+ * Numerous bug fixes. Stripe lock release code disagreed with the taking code
+ * about when stripes should be locked (I made it consistent: no parity, no lock)
+ * There was a lot of extra serialization of I/Os which I've removed- a lot of
+ * it was to calculate values for the cache code, which is no longer with us.
+ * More types, function, macro cleanup. Added code to properly quiesce the array
+ * on shutdown. Made a lot of stuff array-specific which was (bogusly) general
+ * before. Fixed memory allocation, freeing bugs.
+ *
+ * Revision 1.30 1996/05/27 18:56:37 jimz
+ * more code cleanup
+ * better typing
+ * compiles in all 3 environments
+ *
+ * Revision 1.29 1996/05/24 01:59:45 jimz
+ * another checkpoint in code cleanup for release
+ * time to sync kernel tree
+ *
+ * Revision 1.28 1996/05/18 19:51:34 jimz
+ * major code cleanup- fix syntax, make some types consistent,
+ * add prototypes, clean out dead code, et cetera
+ *
+ * Revision 1.27 1995/12/12 18:10:06 jimz
+ * MIN -> RF_MIN, MAX -> RF_MAX, ASSERT -> RF_ASSERT
+ * fix 80-column brain damage in comments
+ *
+ * Revision 1.26 1995/12/01 15:16:36 root
+ * added copyright info
+ *
+ */
+
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "rf_raid.h"
+#include "rf_raidframe.h"
+#include "rf_utils.h"
+#include "rf_general.h"
+#include "rf_decluster.h"
+#include "rf_configure.h"
+#include "rf_sys.h"
+
+/*
+
+ XXX we include this here so we don't need to drag rf_debugMem.c into
+ the picture... This is userland, afterall...
+
+ */
+
+/* XXX sucky hack to override the defn. of RF_Malloc as given in
+rf_debugMem.c... but I *really* don't want (nor need) to link with
+that file here in userland.. GO
+*/
+
+#undef RF_Malloc
+#define RF_Malloc(_p_, _size_, _cast_) \
+ { \
+ _p_ = _cast_ malloc((u_long)_size_); \
+ bzero((char *)_p_, _size_); \
+ }
+
+
+
+#ifndef SIMULATE
+static unsigned int dev_name2num(char *s);
+static unsigned int osf_dev_name2num(char *s);
+#endif
+static int rf_search_file_for_start_of(char *string, char *buf, int len,
+ FILE *fp);
+static int rf_get_next_nonblank_line(char *buf, int len, FILE *fp,
+ char *errmsg);
+
+/* called from user level to read the configuration file and create
+ * a configuration control structure. This is used in the user-level
+ * version of the driver, and in the user-level program that configures
+ * the system via ioctl.
+ */
+int rf_MakeConfig(configname, cfgPtr)
+ char *configname;
+ RF_Config_t *cfgPtr;
+{
+ int numscanned, val, r, c, retcode, aa, bb, cc;
+ char buf[256], buf1[256], *cp;
+ RF_LayoutSW_t *lp;
+ FILE *fp;
+
+ bzero((char *)cfgPtr, sizeof(RF_Config_t));
+
+ fp = fopen(configname, "r");
+ if (!fp) {
+ RF_ERRORMSG1("Can't open config file %s\n",configname);
+ return(-1);
+ }
+
+ rewind(fp);
+ if (rf_search_file_for_start_of("array", buf, 256, fp)) {
+ RF_ERRORMSG1("Unable to find start of \"array\" params in config file %s\n",configname);
+ retcode = -1; goto out;
+ }
+ rf_get_next_nonblank_line(buf, 256, fp, "Config file error (\"array\" section): unable to get numRow and numCol\n");
+ /*
+ * wackiness with aa, bb, cc to get around size problems on different platforms
+ */
+ numscanned = sscanf(buf,"%d %d %d", &aa, &bb, &cc);
+ if (numscanned != 3) {
+ RF_ERRORMSG("Config file error (\"array\" section): unable to get numRow, numCol, numSpare\n");
+ retcode = -1; goto out;
+ }
+ cfgPtr->numRow = (RF_RowCol_t)aa;
+ cfgPtr->numCol = (RF_RowCol_t)bb;
+ cfgPtr->numSpare = (RF_RowCol_t)cc;
+
+ /* debug section is optional */
+ for (c=0; c<RF_MAXDBGV; c++)
+ cfgPtr->debugVars[c][0] = '\0';
+ rewind(fp);
+ if (!rf_search_file_for_start_of("debug", buf, 256, fp)) {
+ for (c=0; c < RF_MAXDBGV; c++) {
+ if (rf_get_next_nonblank_line(buf, 256, fp, NULL)) break;
+ cp = rf_find_non_white(buf);
+ if (!strncmp(cp, "START", strlen("START"))) break;
+ (void) strcpy(&cfgPtr->debugVars[c][0], cp);
+ }
+ }
+
+ rewind(fp);
+ strcpy(cfgPtr->diskQueueType,"fifo");
+ cfgPtr->maxOutstandingDiskReqs = 1;
+ /* scan the file for the block related to disk queues */
+ if (rf_search_file_for_start_of("queue",buf,256,fp)) {
+ RF_ERRORMSG2("[No disk queue discipline specified in config file %s. Using %s.]\n",configname, cfgPtr->diskQueueType);
+ } else {
+ if (rf_get_next_nonblank_line(buf, 256, fp, NULL)) {
+ RF_ERRORMSG2("[No disk queue discipline specified in config file %s. Using %s.]\n",configname, cfgPtr->diskQueueType);
+ }
+ }
+
+ /* the queue specifier line contains two entries:
+ * 1st char of first word specifies queue to be used
+ * 2nd word specifies max num reqs that can be outstanding on the disk itself (typically 1)
+ */
+ if (sscanf(buf,"%s %d",buf1,&val)!=2) {
+ RF_ERRORMSG1("Can't determine queue type and/or max outstanding reqs from line: %s",buf);
+ RF_ERRORMSG2("Using %s-%d\n", cfgPtr->diskQueueType, cfgPtr->maxOutstandingDiskReqs);
+ } else {
+ char *c;
+ bcopy(buf1, cfgPtr->diskQueueType, RF_MIN(sizeof(cfgPtr->diskQueueType), strlen(buf1)+1));
+ for(c=buf1;*c;c++) {
+ if (*c == ' ') {
+ *c = '\0';
+ break;
+ }
+ }
+ cfgPtr->maxOutstandingDiskReqs = val;
+ }
+
+ rewind(fp);
+
+
+ if (rf_search_file_for_start_of("disks",buf,256,fp)) {
+ RF_ERRORMSG1("Can't find \"disks\" section in config file %s\n",configname);
+ retcode = -1; goto out;
+ }
+
+ for (r=0; r<cfgPtr->numRow; r++) {
+ for (c=0; c<cfgPtr->numCol; c++) {
+ if (rf_get_next_nonblank_line(&cfgPtr->devnames[r][c][0], 50, fp, NULL)) {
+ RF_ERRORMSG2("Config file error: unable to get device file for disk at row %d col %d\n",r,c);
+ retcode = -1; goto out;
+ }
+#ifndef SIMULATE
+ val = dev_name2num(&cfgPtr->devnames[r][c][0]);
+
+ if (val < 0) {
+ RF_ERRORMSG3("Config file error: can't get dev num (dev file '%s') for disk at row %d c %d\n",
+ &cfgPtr->devnames[r][c][0],r,c);
+ retcode = -1; goto out;
+ } else cfgPtr->devs[r][c] = val;
+#endif /* !SIMULATE */
+ }
+ }
+
+ /* "spare" section is optional */
+ rewind(fp);
+ if (rf_search_file_for_start_of("spare",buf,256,fp)) cfgPtr->numSpare =0;
+ for (c = 0; c < cfgPtr->numSpare; c++) {
+ if (rf_get_next_nonblank_line(&cfgPtr->spare_names[c][0], 256, fp, NULL)) {
+ RF_ERRORMSG1("Config file error: unable to get device file for spare disk %d\n",c);
+ retcode = -1; goto out;
+ }
+#ifndef SIMULATE
+ val = dev_name2num(&cfgPtr->spare_names[c][0]);
+ if (val < 0) {
+ RF_ERRORMSG2("Config file error: can't get dev num (dev file '%s') for spare disk %d\n",
+ &cfgPtr->spare_names[c][0],c);
+ retcode = -1; goto out;
+ } else cfgPtr->spare_devs[c] = val;
+#endif /* !SIMULATE */
+ }
+
+ /* scan the file for the block related to layout */
+ rewind(fp);
+ if (rf_search_file_for_start_of("layout",buf,256,fp)) {
+ RF_ERRORMSG1("Can't find \"layout\" section in configuration file %s\n",configname);
+ retcode = -1; goto out;
+ }
+ if (rf_get_next_nonblank_line(buf, 256, fp, NULL)) {
+ RF_ERRORMSG("Config file error (\"layout\" section): unable to find common layout param line\n");
+ retcode = -1; goto out;
+ }
+ c = sscanf(buf,"%d %d %d %c", &aa, &bb, &cc, &cfgPtr->parityConfig);
+ cfgPtr->sectPerSU = (RF_SectorNum_t)aa;
+ cfgPtr->SUsPerPU = (RF_StripeNum_t)bb;
+ cfgPtr->SUsPerRU = (RF_StripeNum_t)cc;
+ if (c != 4) {
+ RF_ERRORMSG("Unable to scan common layout line\n");
+ retcode = -1; goto out;
+ }
+ lp = rf_GetLayout(cfgPtr->parityConfig);
+ if (lp == NULL) {
+ RF_ERRORMSG1("Unknown parity config '%c'\n", cfgPtr->parityConfig);
+ retcode = -1;
+ goto out;
+ }
+
+ /* XXX who cares.. it's not going into the kernel, so we should ignore this... */
+#ifndef KERNEL
+ retcode = lp->MakeLayoutSpecific(fp, cfgPtr, lp->makeLayoutSpecificArg);
+#endif
+out:
+ fclose(fp);
+ if (retcode < 0)
+ retcode = errno = EINVAL;
+ else
+ errno = retcode;
+ return(retcode);
+}
+
+
+/* used in architectures such as RAID0 where there is no layout-specific
+ * information to be passed into the configuration code.
+ */
+int rf_MakeLayoutSpecificNULL(fp, cfgPtr, ignored)
+ FILE *fp;
+ RF_Config_t *cfgPtr;
+ void *ignored;
+{
+ cfgPtr->layoutSpecificSize = 0;
+ cfgPtr->layoutSpecific = NULL;
+ return(0);
+}
+
+int rf_MakeLayoutSpecificDeclustered(configfp, cfgPtr, arg)
+ FILE *configfp;
+ RF_Config_t *cfgPtr;
+ void *arg;
+{
+ int b, v, k, r, lambda, norotate, i, val, distSpare;
+ char *cfgBuf, *bdfile, *p, *smname;
+ char buf[256], smbuf[256];
+ FILE *fp;
+
+ distSpare = *((int *)arg);
+
+ /* get the block design file name */
+ if (rf_get_next_nonblank_line(buf,256,configfp,"Can't find block design file name in config file\n"))
+ return(EINVAL);
+ bdfile = rf_find_non_white(buf);
+ if (bdfile[strlen(bdfile)-1] == '\n') {
+ /* strip newline char */
+ bdfile[strlen(bdfile)-1] = '\0';
+ }
+
+ /* open bd file, check validity of configuration */
+ if ((fp = fopen(bdfile,"r"))==NULL) {
+ RF_ERRORMSG1("RAID: config error: Can't open layout table file %s\n",bdfile);
+ return(EINVAL);
+ }
+
+ fgets(buf,256,fp);
+ i = sscanf(buf,"%u %u %u %u %u %u",&b,&v,&k,&r,&lambda,&norotate);
+ if (i == 5)
+ norotate = 0; /* no-rotate flag is optional */
+ else if (i != 6) {
+ RF_ERRORMSG("Unable to parse header line in block design file\n");
+ return(EINVAL);
+ }
+
+ /* set the sparemap directory. In the in-kernel version, there's a daemon
+ * that's responsible for finding the sparemaps
+ */
+ if (distSpare) {
+ if (rf_get_next_nonblank_line(smbuf,256,configfp,"Can't find sparemap file name in config file\n"))
+ return(EINVAL);
+ smname = rf_find_non_white(smbuf);
+ if (smname[strlen(smname)-1] == '\n') {
+ /* strip newline char */
+ smname[strlen(smname)-1] = '\0';
+ }
+ }
+ else {
+ smbuf[0] = '\0';
+ smname = smbuf;
+ }
+
+ /* allocate a buffer to hold the configuration info */
+ cfgPtr->layoutSpecificSize = RF_SPAREMAP_NAME_LEN + 6 * sizeof(int) + b * k;
+ /* can't use RF_Malloc here b/c debugMem module not yet init'd */
+ cfgBuf = (char *) malloc(cfgPtr->layoutSpecificSize);
+ cfgPtr->layoutSpecific = (void *) cfgBuf;
+ p = cfgBuf;
+
+ /* install name of sparemap file */
+ for (i=0; smname[i]; i++)
+ *p++ = smname[i];
+ /* pad with zeros */
+ while (i<RF_SPAREMAP_NAME_LEN) {
+ *p++ = '\0';
+ i++;
+ }
+
+ /*
+ * fill in the buffer with the block design parameters
+ * and then the block design itself
+ */
+ *( (int *) p) = b; p += sizeof(int);
+ *( (int *) p) = v; p += sizeof(int);
+ *( (int *) p) = k; p += sizeof(int);
+ *( (int *) p) = r; p += sizeof(int);
+ *( (int *) p) = lambda; p += sizeof(int);
+ *( (int *) p) = norotate; p += sizeof(int);
+
+ while (fscanf(fp,"%d",&val) == 1)
+ *p++ = (char) val;
+ fclose(fp);
+ if (p - cfgBuf != cfgPtr->layoutSpecificSize) {
+ RF_ERRORMSG2("Size mismatch creating layout specific data: is %d sb %d bytes\n",(int)(p-cfgBuf),(int)(6*sizeof(int)+b*k));
+ return(EINVAL);
+ }
+ return(0);
+}
+
+
+/****************************************************************************
+ *
+ * utilities
+ *
+ ***************************************************************************/
+#ifndef SIMULATE
+/* convert a device file name to a device number */
+static unsigned int dev_name2num(s)
+ char *s;
+{
+ struct stat buf;
+
+ if (stat(s, &buf) < 0) return(osf_dev_name2num(s));
+ else return(buf.st_rdev);
+}
+
+/* converts an osf/1 style device name to a device number. We use this
+ * only if the stat of the device file fails.
+ */
+static unsigned int osf_dev_name2num(s)
+ char *s;
+{
+ int num;
+ char part_ch, lun_ch;
+ unsigned int bus, target, lun, part, dev_major;
+
+ dev_major = RF_SCSI_DISK_MAJOR;
+ if (sscanf(s,"/dev/rrz%d%c", &num, &part_ch) == 2) {
+ bus = num>>3;
+ target = num & 0x7;
+ part = part_ch - 'a';
+ lun = 0;
+ } else if (sscanf(s,"/dev/rrz%c%d%c", &lun_ch, &num, &part_ch) == 3) {
+ bus = num>>3;
+ target = num & 0x7;
+ part = part_ch - 'a';
+ lun = lun_ch - 'a' + 1;
+ } else {
+ RF_ERRORMSG1("Unable to parse disk dev file name %s\n",s);
+ return(-1);
+ }
+
+ return( (dev_major<<20) | (bus<<14) | (target<<10) | (lun<<6) | part );
+}
+#endif
+
+/* searches a file for a line that says "START string", where string is
+ * specified as a parameter
+ */
+static int rf_search_file_for_start_of(string, buf, len, fp)
+ char *string;
+ char *buf;
+ int len;
+ FILE *fp;
+{
+ char *p;
+
+ while (1) {
+ if (fgets(buf, len, fp) == NULL) return(-1);
+ p = rf_find_non_white(buf);
+ if (!strncmp(p, "START", strlen("START"))) {
+ p = rf_find_white(p);
+ p = rf_find_non_white(p);
+ if (!strncmp(p, string, strlen(string))) return(0);
+ }
+ }
+}
+
+/* reads from file fp into buf until it finds an interesting line */
+int rf_get_next_nonblank_line(buf, len, fp, errmsg)
+ char *buf;
+ int len;
+ FILE *fp;
+ char *errmsg;
+{
+ char *p;
+
+ while (fgets(buf,256,fp) != NULL) {
+ p = rf_find_non_white(buf);
+ if (*p == '\n' || *p == '\0' || *p == '#') continue;
+ return(0);
+ }
+ if (errmsg) RF_ERRORMSG(errmsg);
+ return(1);
+}
+
+/* Allocates an array for the spare table, and initializes it from a file.
+ * In the user-level version, this is called when recon is initiated.
+ * When/if I move recon into the kernel, there'll be a daemon that does
+ * an ioctl into raidframe which will block until a spare table is needed.
+ * When it returns, it will read a spare table from the file system,
+ * pass it into the kernel via a different ioctl, and then block again
+ * on the original ioctl.
+ *
+ * This is specific to the declustered layout, but doesn't belong in
+ * rf_decluster.c because it uses stuff that can't be compiled into
+ * the kernel, and it needs to be compiled into the user-level sparemap daemon.
+ *
+ */
+void *rf_ReadSpareTable(req, fname)
+ RF_SparetWait_t *req;
+ char *fname;
+{
+ int i, j, numFound, linecount, tableNum, tupleNum, spareDisk, spareBlkOffset;
+ char buf[1024], targString[100], errString[100];
+ RF_SpareTableEntry_t **table;
+ FILE *fp;
+
+ /* allocate and initialize the table */
+ RF_Malloc(table, req->TablesPerSpareRegion * sizeof(RF_SpareTableEntry_t *), (RF_SpareTableEntry_t **));
+ for (i=0; i<req->TablesPerSpareRegion; i++) {
+ RF_Malloc(table[i], req->BlocksPerTable * sizeof(RF_SpareTableEntry_t), (RF_SpareTableEntry_t *));
+ for (j=0; j<req->BlocksPerTable; j++) table[i][j].spareDisk = table[i][j].spareBlockOffsetInSUs = -1;
+ }
+
+ /* 2. open sparemap file, sanity check */
+ if ((fp = fopen(fname,"r"))==NULL) {
+ fprintf(stderr,"rf_ReadSpareTable: Can't open sparemap file %s\n",fname); return(NULL);
+ }
+ if (rf_get_next_nonblank_line(buf,1024,fp,"Invalid sparemap file: can't find header line\n"))
+ return(NULL);
+ if (buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = '\0';
+
+ sprintf(targString, "fdisk %d\n", req->fcol);
+ sprintf(errString, "Invalid sparemap file: can't find \"fdisk %d\" line\n",req->fcol);
+ while (1) {
+ rf_get_next_nonblank_line(buf,1024,fp,errString);
+ if (!strncmp(buf,targString,strlen(targString))) break;
+ }
+
+ /* no more blank lines or comments allowed now */
+ linecount = req->TablesPerSpareRegion * req->TableDepthInPUs;
+ for (i=0; i<linecount; i++) {
+ numFound = fscanf(fp," %d %d %d %d",&tableNum, &tupleNum, &spareDisk, &spareBlkOffset);
+ if (numFound != 4) {
+ fprintf(stderr,"Sparemap file prematurely exhausted after %d of %d lines\n",i,linecount); return(NULL);
+ }
+ RF_ASSERT(tableNum >= 0 && tableNum < req->TablesPerSpareRegion);
+ RF_ASSERT(tupleNum >= 0 && tupleNum < req->BlocksPerTable);
+ RF_ASSERT(spareDisk >= 0 && spareDisk < req->C);
+ RF_ASSERT(spareBlkOffset >= 0 && spareBlkOffset < req->SpareSpaceDepthPerRegionInSUs / req->SUsPerPU);
+
+ table[tableNum][tupleNum].spareDisk = spareDisk;
+ table[tableNum][tupleNum].spareBlockOffsetInSUs = spareBlkOffset * req->SUsPerPU;
+ }
+
+ fclose(fp);
+ return((void *) table);
+}
diff --git a/sbin/raidctl/rf_utility.c b/sbin/raidctl/rf_utility.c
new file mode 100644
index 00000000000..f2e816ab0aa
--- /dev/null
+++ b/sbin/raidctl/rf_utility.c
@@ -0,0 +1,62 @@
+/* $OpenBSD: rf_utility.c,v 1.1 1999/01/11 14:49:45 niklas Exp $ */
+
+/*
+ * rf_utility.c
+ */
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Jim Zelenka
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * define symbols for raidframe utils which share .c files with
+ * raidframe proper
+ */
+
+#include "rf_utility.h"
+
+#ifdef RF_DBG_OPTION
+#undef RF_DBG_OPTION
+#endif /* RF_DBG_OPTION */
+
+#ifdef __STDC__
+#define RF_DBG_OPTION(_option_,_defval_) long rf_##_option_ = _defval_;
+#else /* __STDC__ */
+#define RF_DBG_OPTION(_option_,_defval_) long rf_/**/_option_ = _defval_;
+#endif /* __STDC__ */
+#include "rf_optnames.h"
+
+int rf_mutex_init(m)
+ int *m;
+{
+ *m = 0;
+ return(0);
+}
+
+int rf_mutex_destroy(m)
+ int *m;
+{
+ *m = 0;
+ return(0);
+}
diff --git a/sbin/raidctl/rf_utility.h b/sbin/raidctl/rf_utility.h
new file mode 100644
index 00000000000..c4baca55f92
--- /dev/null
+++ b/sbin/raidctl/rf_utility.h
@@ -0,0 +1,50 @@
+/* $OpenBSD: rf_utility.h,v 1.1 1999/01/11 14:49:45 niklas Exp $ */
+
+/*
+ * rf_utility.h
+ */
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Jim Zelenka
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+/*
+ * defs for raidframe utils which share .c files with
+ * raidframe proper
+ */
+
+#ifndef _RF__RF_UTILITY_H_
+#define _RF__RF_UTILITY_H_
+
+#include "rf_options.h"
+
+#define rf_create_managed_mutex(a,b) 0
+#define rf_create_managed_cond(a,b) 0
+
+#define RF_DECLARE_MUTEX(m) int m;
+#define RF_DECLARE_EXTERN_MUTEX(m) extern int m;
+#define RF_LOCK_MUTEX(m)
+#define RF_UNLOCK_MUTEX(m)
+
+#endif /* !_RF__RF_UTILITY_H_ */