xref: /netbsd-src/sbin/raidctl/raidctl.c (revision 0301df00b372519ebb5434db4a1d0a6bffee041a)
1*0301df00Srillig /*      $NetBSD: raidctl.c,v 1.86 2024/11/05 20:07:41 rillig Exp $   */
2a53c712bSthorpej 
3f675e35dSoster /*-
4f675e35dSoster  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
5f675e35dSoster  * All rights reserved.
6f675e35dSoster  *
7f675e35dSoster  * This code is derived from software contributed to The NetBSD Foundation
8f675e35dSoster  * by Greg Oster
9f675e35dSoster  *
10f675e35dSoster  * Redistribution and use in source and binary forms, with or without
11f675e35dSoster  * modification, are permitted provided that the following conditions
12f675e35dSoster  * are met:
13f675e35dSoster  * 1. Redistributions of source code must retain the above copyright
14f675e35dSoster  *    notice, this list of conditions and the following disclaimer.
15f675e35dSoster  * 2. Redistributions in binary form must reproduce the above copyright
16f675e35dSoster  *    notice, this list of conditions and the following disclaimer in the
17f675e35dSoster  *    documentation and/or other materials provided with the distribution.
18f675e35dSoster  *
19f675e35dSoster  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f675e35dSoster  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f675e35dSoster  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f675e35dSoster  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f675e35dSoster  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f675e35dSoster  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f675e35dSoster  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f675e35dSoster  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f675e35dSoster  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f675e35dSoster  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f675e35dSoster  * POSSIBILITY OF SUCH DAMAGE.
30f675e35dSoster  */
31f675e35dSoster 
32f675e35dSoster /*
33a53c712bSthorpej  * This program is a re-write of the original rf_ctrl program
34a53c712bSthorpej  * distributed by CMU with RAIDframe 1.1.
35a53c712bSthorpej  *
36a53c712bSthorpej  * This program is the user-land interface to the RAIDframe kernel
37a53c712bSthorpej  * driver in NetBSD.
38f675e35dSoster  */
39c2a3b5ecSagc #include <sys/cdefs.h>
40c2a3b5ecSagc 
41c2a3b5ecSagc #ifndef lint
42*0301df00Srillig __RCSID("$NetBSD: raidctl.c,v 1.86 2024/11/05 20:07:41 rillig Exp $");
43c2a3b5ecSagc #endif
44c2a3b5ecSagc 
45f675e35dSoster 
46f675e35dSoster #include <sys/param.h>
47f675e35dSoster #include <sys/ioctl.h>
48f675e35dSoster #include <sys/stat.h>
49a53c712bSthorpej #include <sys/disklabel.h>
50a53c712bSthorpej 
51f675e35dSoster #include <ctype.h>
52f675e35dSoster #include <err.h>
5393bf4aaeSmjacob #include <errno.h>
544e9651baSlukem #include <fcntl.h>
554e9651baSlukem #include <stdio.h>
56ae9b468dSoster #include <stdlib.h>
574e9651baSlukem #include <string.h>
58e304a25cSchristos #include <inttypes.h>
59543c143bSoster #include <unistd.h>
604e9651baSlukem #include <util.h>
61543c143bSoster 
62541d521aSoster #include <dev/raidframe/raidframevar.h>
63541d521aSoster #include <dev/raidframe/raidframeio.h>
64541d521aSoster #include "rf_configure.h"
65db818c53Spooka #include "prog_ops.h"
66f675e35dSoster 
67a6071800Soster #ifndef RAIDFRAME_REMOVE_COMPONENT
68a6071800Soster #define RAIDFRAME_REMOVE_COMPONENT RAIDFRAME_REMOVE_HOT_SPARE
69a6071800Soster #endif
70a6071800Soster 
71d73b978aSkre #define	CONFIGURE_TEST	1	/* must be different from any raidframe ioctl */
72d73b978aSkre 
73f0121f1fSxtraeme void	do_ioctl(int, u_long, void *, const char *);
74f0121f1fSxtraeme static  void rf_configure(int, char*, int);
75f0121f1fSxtraeme static  const char *device_status(RF_DiskStatus_t);
76f0121f1fSxtraeme static  void rf_get_device_status(int);
77f0121f1fSxtraeme static	void rf_output_configuration(int, const char *);
78f0121f1fSxtraeme static  void get_component_number(int, char *, int *, int *);
79f0121f1fSxtraeme static  void rf_fail_disk(int, char *, int);
80baa8e84bSjoerg __dead static  void usage(void);
81f0121f1fSxtraeme static  void get_component_label(int, char *);
82f0121f1fSxtraeme static  void set_component_label(int, char *);
83f0121f1fSxtraeme static  void init_component_labels(int, int);
84f0121f1fSxtraeme static  void set_autoconfig(int, int, char *);
85f0121f1fSxtraeme static  void add_hot_spare(int, char *);
86a6071800Soster static  void remove_component(int, char *);
87f0121f1fSxtraeme static  void rebuild_in_place(int, char *);
88f0121f1fSxtraeme static  void check_status(int,int);
89f0121f1fSxtraeme static  void check_parity(int,int, char *);
90f0121f1fSxtraeme static  void do_meter(int, u_long);
91f0121f1fSxtraeme static  void get_bar(char *, double, int);
927b743cfcSmrg static  void get_time_string(char *, size_t, int);
93f1a1ad33Sjld static  void rf_output_pmstat(int, int);
94f1a1ad33Sjld static  void rf_pm_configure(int, int, char *, int[]);
9574ff9ea8Soster static  void rf_simple_create(int, int, char *[]);
96e304a25cSchristos static  unsigned int xstrtouint(const char *);
97c714a07dSoster 
98a53c712bSthorpej int verbose;
99f675e35dSoster 
10052334fd8Schristos static const char *rootpart[] = { "No", "Force", "Soft", "*invalid*" };
10152334fd8Schristos 
102edc4e844Smlelstv static void
103edc4e844Smlelstv get_comp(char *buf, char *arg, size_t bufsz)
104edc4e844Smlelstv {
105edc4e844Smlelstv 	if (getfsspecname(buf, bufsz, arg) == NULL)
106edc4e844Smlelstv 		errx(1,"%s",buf);
107edc4e844Smlelstv }
108edc4e844Smlelstv 
109f675e35dSoster int
110f0121f1fSxtraeme main(int argc,char *argv[])
111f675e35dSoster {
112f1a1ad33Sjld 	int ch, i;
113f675e35dSoster 	int num_options;
114f675e35dSoster 	unsigned long action;
115f675e35dSoster 	char config_filename[PATH_MAX];
116f675e35dSoster 	char dev_name[PATH_MAX];
117f675e35dSoster 	char name[PATH_MAX];
118ae9b468dSoster 	char component[PATH_MAX];
1195aee30c0Soster 	char autoconf[10];
120f1a1ad33Sjld 	char *parityconf = NULL;
121f1a1ad33Sjld 	int parityparams[3];
122364e3039Slukem 	int do_output;
123f675e35dSoster 	int do_recon;
124d0740fb3Soster 	int do_rewrite;
125f675e35dSoster 	int raidID;
126ae9b468dSoster 	int serial_number;
127f675e35dSoster 	struct stat st;
128f675e35dSoster 	int fd;
129ae9b468dSoster 	int force;
1306fccd7abSsimonb 	int openmode;
131c4e0e8f4Schristos 	int last_unit;
13274ff9ea8Soster 	struct timeval tv;
133f675e35dSoster 
134f675e35dSoster 	num_options = 0;
135f675e35dSoster 	action = 0;
136364e3039Slukem 	do_output = 0;
137f675e35dSoster 	do_recon = 0;
138d0740fb3Soster 	do_rewrite = 0;
1399a1b8a3bSlukem 	serial_number = 0;
140ae9b468dSoster 	force = 0;
141c4e0e8f4Schristos 	last_unit = 0;
1426fccd7abSsimonb 	openmode = O_RDWR;	/* default to read/write */
143f675e35dSoster 
14474ff9ea8Soster 	if (argc > 5) {
14574ff9ea8Soster 		/* we have at least 5 args, so it might be a simplified config */
14674ff9ea8Soster 
14774ff9ea8Soster 		strlcpy(name, argv[1], sizeof(name));
14874ff9ea8Soster 		fd = opendisk(name, openmode, dev_name, sizeof(dev_name), 0);
14974ff9ea8Soster 		if (fd != -1) {
15074ff9ea8Soster 			/* we were able to open the device... */
15174ff9ea8Soster 			if (fstat(fd, &st) == -1)
15274ff9ea8Soster 				err(1, "stat failure on: %s", dev_name);
15374ff9ea8Soster 			if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
15474ff9ea8Soster 				err(1, "invalid device: %s", dev_name);
15574ff9ea8Soster 
15674ff9ea8Soster 			raidID = DISKUNIT(st.st_rdev);
15774ff9ea8Soster 			if (strncmp(argv[2],"create",6)==0) {
15874ff9ea8Soster 				rf_simple_create(fd,argc-3,&argv[3]);
15974ff9ea8Soster 
16074ff9ea8Soster 				/* set serial number, set autoconfig, init parity */
16174ff9ea8Soster 
16274ff9ea8Soster 				if (gettimeofday(&tv,NULL) == -1) {
16374ff9ea8Soster 					serial_number = 12345777;
16474ff9ea8Soster 				} else {
16574ff9ea8Soster 					serial_number = tv.tv_sec;
16674ff9ea8Soster 				}
16774ff9ea8Soster 				init_component_labels(fd, serial_number);
16874ff9ea8Soster 				strlcpy(autoconf, "yes", sizeof(autoconf));
16974ff9ea8Soster 				set_autoconfig(fd, raidID, autoconf);
17074ff9ea8Soster 
17174ff9ea8Soster 			} else
17274ff9ea8Soster 				usage();
17374ff9ea8Soster 
17474ff9ea8Soster 			close(fd);
17574ff9ea8Soster 			exit(0);
17674ff9ea8Soster 		}
17774ff9ea8Soster 
17874ff9ea8Soster 		/* otherwise we go back to regular parsing */
17974ff9ea8Soster 	}
18074ff9ea8Soster 
181d73b978aSkre 	while ((ch = getopt(argc, argv,
182a075d61bSrillig 	    "a:A:c:C:f:F:g:GiI:l:LmM:r:R:sSpPt:uU:v")) != -1)
183f675e35dSoster 		switch (ch) {
184ae9b468dSoster 		case 'a':
185ae9b468dSoster 			action = RAIDFRAME_ADD_HOT_SPARE;
186edc4e844Smlelstv 			get_comp(component, optarg, sizeof(component));
187ae9b468dSoster 			num_options++;
188ae9b468dSoster 			break;
1895aee30c0Soster 		case 'A':
1905aee30c0Soster 			action = RAIDFRAME_SET_AUTOCONFIG;
19184490858Sitojun 			strlcpy(autoconf, optarg, sizeof(autoconf));
1925aee30c0Soster 			num_options++;
1935aee30c0Soster 			break;
194f675e35dSoster 		case 'c':
195f675e35dSoster 			action = RAIDFRAME_CONFIGURE;
19684490858Sitojun 			strlcpy(config_filename, optarg,
19784490858Sitojun 			    sizeof(config_filename));
19853d349a1Soster 			force = 0;
199f675e35dSoster 			num_options++;
200f675e35dSoster 			break;
201f675e35dSoster 		case 'C':
20284490858Sitojun 			strlcpy(config_filename, optarg,
20384490858Sitojun 			    sizeof(config_filename));
20453d349a1Soster 			action = RAIDFRAME_CONFIGURE;
20553d349a1Soster 			force = 1;
206f675e35dSoster 			num_options++;
207f675e35dSoster 			break;
208f675e35dSoster 		case 'f':
209f675e35dSoster 			action = RAIDFRAME_FAIL_DISK;
210edc4e844Smlelstv 			get_comp(component, optarg, sizeof(component));
21153d349a1Soster 			do_recon = 0;
212f675e35dSoster 			num_options++;
213f675e35dSoster 			break;
214f675e35dSoster 		case 'F':
215f675e35dSoster 			action = RAIDFRAME_FAIL_DISK;
216edc4e844Smlelstv 			get_comp(component, optarg, sizeof(component));
21753d349a1Soster 			do_recon = 1;
218ae9b468dSoster 			num_options++;
219ae9b468dSoster 			break;
220ae9b468dSoster 		case 'g':
221ae9b468dSoster 			action = RAIDFRAME_GET_COMPONENT_LABEL;
222edc4e844Smlelstv 			get_comp(component, optarg, sizeof(component));
2236fccd7abSsimonb 			openmode = O_RDONLY;
224ae9b468dSoster 			num_options++;
225ae9b468dSoster 			break;
226364e3039Slukem 		case 'G':
227364e3039Slukem 			action = RAIDFRAME_GET_INFO;
2286fccd7abSsimonb 			openmode = O_RDONLY;
229364e3039Slukem 			do_output = 1;
230364e3039Slukem 			num_options++;
231364e3039Slukem 			break;
23253d349a1Soster 		case 'i':
23353d349a1Soster 			action = RAIDFRAME_REWRITEPARITY;
23453d349a1Soster 			num_options++;
23553d349a1Soster 			break;
236ae9b468dSoster 		case 'I':
237ae9b468dSoster 			action = RAIDFRAME_INIT_LABELS;
238e304a25cSchristos 			serial_number = xstrtouint(optarg);
239ae9b468dSoster 			num_options++;
240ae9b468dSoster 			break;
2416b2ddebeSoster 		case 'l':
2426b2ddebeSoster 			action = RAIDFRAME_SET_COMPONENT_LABEL;
2436b2ddebeSoster 			get_comp(component, optarg, sizeof(component));
2446b2ddebeSoster 			num_options++;
2456b2ddebeSoster 			break;
2467464f2ddSoster 		case 'L':
2477464f2ddSoster 			action = RAIDFRAME_RESCAN;
2487464f2ddSoster 			num_options++;
2497464f2ddSoster 			break;
250f1a1ad33Sjld 		case 'm':
251f1a1ad33Sjld 			action = RAIDFRAME_PARITYMAP_STATUS;
252f1a1ad33Sjld 			openmode = O_RDONLY;
253f1a1ad33Sjld 			num_options++;
254f1a1ad33Sjld 			break;
255f1a1ad33Sjld 		case 'M':
256f1a1ad33Sjld 			action = RAIDFRAME_PARITYMAP_SET_DISABLE;
257f1a1ad33Sjld 			parityconf = strdup(optarg);
258f1a1ad33Sjld 			num_options++;
25905c0668eSmanu 			/* XXXjld: should rf_pm_configure do the strtol()s? */
260f1a1ad33Sjld 			i = 0;
261f1a1ad33Sjld 			while (i < 3 && optind < argc &&
262*0301df00Srillig 			    isdigit((unsigned char)argv[optind][0]))
263e304a25cSchristos 				parityparams[i++] = xstrtouint(argv[optind++]);
264f1a1ad33Sjld 			while (i < 3)
265f1a1ad33Sjld 				parityparams[i++] = 0;
266f1a1ad33Sjld 			break;
267681f9ba5Skre 		case 'p':
268681f9ba5Skre 			action = RAIDFRAME_CHECK_PARITY;
269681f9ba5Skre 			openmode = O_RDONLY;
270681f9ba5Skre 			num_options++;
271681f9ba5Skre 			break;
272681f9ba5Skre 		case 'P':
273681f9ba5Skre 			action = RAIDFRAME_CHECK_PARITY;
274681f9ba5Skre 			do_rewrite = 1;
275681f9ba5Skre 			num_options++;
276681f9ba5Skre 			break;
277f675e35dSoster 		case 'r':
278a6071800Soster 			action = RAIDFRAME_REMOVE_COMPONENT;
279edc4e844Smlelstv 			get_comp(component, optarg, sizeof(component));
280f675e35dSoster 			num_options++;
281f675e35dSoster 			break;
282f675e35dSoster 		case 'R':
283edc4e844Smlelstv 			get_comp(component, optarg, sizeof(component));
28453d349a1Soster 			action = RAIDFRAME_REBUILD_IN_PLACE;
285f675e35dSoster 			num_options++;
286f675e35dSoster 			break;
287f675e35dSoster 		case 's':
288f675e35dSoster 			action = RAIDFRAME_GET_INFO;
2896fccd7abSsimonb 			openmode = O_RDONLY;
290f675e35dSoster 			num_options++;
291f675e35dSoster 			break;
29253d349a1Soster 		case 'S':
29364ad6c88Soster 			action = RAIDFRAME_CHECK_RECON_STATUS_EXT;
2946fccd7abSsimonb 			openmode = O_RDONLY;
295f675e35dSoster 			num_options++;
296f675e35dSoster 			break;
297d73b978aSkre 		case 't':
298d73b978aSkre 			action = CONFIGURE_TEST;
299d73b978aSkre 			strlcpy(config_filename, optarg,
300d73b978aSkre 			    sizeof(config_filename));
301d73b978aSkre 			num_options++;
302d73b978aSkre 			break;
30353d349a1Soster 		case 'u':
30453d349a1Soster 			action = RAIDFRAME_SHUTDOWN;
305ae9b468dSoster 			num_options++;
306ae9b468dSoster 			break;
307c4e0e8f4Schristos 		case 'U':
308c4e0e8f4Schristos 			action = RAIDFRAME_SET_LAST_UNIT;
309c4e0e8f4Schristos 			num_options++;
310c4e0e8f4Schristos 			last_unit = atoi(optarg);
311c4e0e8f4Schristos 			if (last_unit < 0)
312c4e0e8f4Schristos 				errx(1, "Bad last unit %s", optarg);
313c4e0e8f4Schristos 			break;
314c714a07dSoster 		case 'v':
315c714a07dSoster 			verbose = 1;
316c714a07dSoster 			/* Don't bump num_options, as '-v' is not
317c714a07dSoster 			   an option like the others */
318c714a07dSoster 			/* num_options++; */
319c714a07dSoster 			break;
320f675e35dSoster 		default:
321f675e35dSoster 			usage();
322f675e35dSoster 		}
323f675e35dSoster 	argc -= optind;
324f675e35dSoster 	argv += optind;
325f675e35dSoster 
326d73b978aSkre 	if (num_options > 1)
327d73b978aSkre 		usage();
328d73b978aSkre 
329d73b978aSkre 	if (action == CONFIGURE_TEST) {
330d73b978aSkre 		RF_Config_t cfg;
331d73b978aSkre 
332d73b978aSkre 		if (argc != 0)
333d73b978aSkre 			usage();
334d73b978aSkre 		if (rf_MakeConfig(config_filename, &cfg) != 0)
335d73b978aSkre 			exit(1);
336d73b978aSkre 		exit(0);;
337d73b978aSkre 	}
338d73b978aSkre 
339d73b978aSkre 	if (argc != 1)
340f675e35dSoster 		usage();
341f675e35dSoster 
342db818c53Spooka 	if (prog_init && prog_init() == -1)
343db818c53Spooka 		err(1, "init failed");
344db818c53Spooka 
34584490858Sitojun 	strlcpy(name, argv[0], sizeof(name));
3464f5a394dSpooka 	fd = opendisk1(name, openmode, dev_name, sizeof(dev_name), 0,
347db818c53Spooka 	    prog_open);
34813a59406Schristos 	if (fd == -1)
34913a59406Schristos 		err(1, "Unable to open device file: %s", name);
350a804f479Spooka 	if (prog_fstat(fd, &st) == -1)
35113a59406Schristos 		err(1, "stat failure on: %s", dev_name);
35213a59406Schristos 	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
35313a59406Schristos 		err(1, "invalid device: %s", dev_name);
354f675e35dSoster 
35591ffb9ffSoster 	raidID = DISKUNIT(st.st_rdev);
356f675e35dSoster 
357f675e35dSoster 	switch (action) {
358ae9b468dSoster 	case RAIDFRAME_ADD_HOT_SPARE:
359ae9b468dSoster 		add_hot_spare(fd, component);
360ae9b468dSoster 		break;
361a6071800Soster 	case RAIDFRAME_REMOVE_COMPONENT:
362a6071800Soster 		remove_component(fd, component);
36353d349a1Soster 		break;
364f675e35dSoster 	case RAIDFRAME_CONFIGURE:
365ae9b468dSoster 		rf_configure(fd, config_filename, force);
366f675e35dSoster 		break;
3675aee30c0Soster 	case RAIDFRAME_SET_AUTOCONFIG:
3685aee30c0Soster 		set_autoconfig(fd, raidID, autoconf);
3695aee30c0Soster 		break;
370f675e35dSoster 	case RAIDFRAME_FAIL_DISK:
371ae9b468dSoster 		rf_fail_disk(fd, component, do_recon);
372ae9b468dSoster 		break;
373ae9b468dSoster 	case RAIDFRAME_SET_COMPONENT_LABEL:
374ae9b468dSoster 		set_component_label(fd, component);
375ae9b468dSoster 		break;
376ae9b468dSoster 	case RAIDFRAME_GET_COMPONENT_LABEL:
377ae9b468dSoster 		get_component_label(fd, component);
378ae9b468dSoster 		break;
379ae9b468dSoster 	case RAIDFRAME_INIT_LABELS:
380ae9b468dSoster 		init_component_labels(fd, serial_number);
381f675e35dSoster 		break;
382f675e35dSoster 	case RAIDFRAME_REWRITEPARITY:
383f675e35dSoster 		printf("Initiating re-write of parity\n");
384f675e35dSoster 		do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
385f675e35dSoster 			 "RAIDFRAME_REWRITEPARITY");
386c714a07dSoster 		if (verbose) {
387c714a07dSoster 			sleep(3); /* XXX give it time to get started */
388c714a07dSoster 			printf("Parity Re-write status:\n");
38964ad6c88Soster 			do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
390c714a07dSoster 		}
391f675e35dSoster 		break;
39264ad6c88Soster 	case RAIDFRAME_CHECK_RECON_STATUS_EXT:
3933a374be7Soster 		check_status(fd,1);
394f675e35dSoster 		break;
395f675e35dSoster 	case RAIDFRAME_GET_INFO:
396364e3039Slukem 		if (do_output)
397364e3039Slukem 			rf_output_configuration(fd, dev_name);
398364e3039Slukem 		else
399f675e35dSoster 			rf_get_device_status(fd);
400f675e35dSoster 		break;
401f1a1ad33Sjld 	case RAIDFRAME_PARITYMAP_STATUS:
402f1a1ad33Sjld 		rf_output_pmstat(fd, raidID);
403f1a1ad33Sjld 		break;
404f1a1ad33Sjld 	case RAIDFRAME_PARITYMAP_SET_DISABLE:
405f1a1ad33Sjld 		rf_pm_configure(fd, raidID, parityconf, parityparams);
406f1a1ad33Sjld 		break;
40753d349a1Soster 	case RAIDFRAME_REBUILD_IN_PLACE:
40853d349a1Soster 		rebuild_in_place(fd, component);
40953d349a1Soster 		break;
410d0740fb3Soster 	case RAIDFRAME_CHECK_PARITY:
411c714a07dSoster 		check_parity(fd, do_rewrite, dev_name);
412d0740fb3Soster 		break;
413f675e35dSoster 	case RAIDFRAME_SHUTDOWN:
414f675e35dSoster 		do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
415f675e35dSoster 		break;
416c4e0e8f4Schristos 	case RAIDFRAME_SET_LAST_UNIT:
417c4e0e8f4Schristos 		do_ioctl(fd, RAIDFRAME_SET_LAST_UNIT, &last_unit,
418c4e0e8f4Schristos 		    "RAIDFRAME_SET_LAST_UNIT");
419c4e0e8f4Schristos 		break;
4207464f2ddSoster 	case RAIDFRAME_RESCAN:
4217464f2ddSoster 		do_ioctl(fd, RAIDFRAME_RESCAN, NULL, "RAIDFRAME_RESCAN");
4227464f2ddSoster 		break;
423f675e35dSoster 	default:
424f675e35dSoster 		break;
425f675e35dSoster 	}
426f675e35dSoster 
427db818c53Spooka 	prog_close(fd);
428f675e35dSoster 	exit(0);
429f675e35dSoster }
430f675e35dSoster 
431c714a07dSoster void
432f0121f1fSxtraeme do_ioctl(int fd, unsigned long command, void *arg, const char *ioctl_name)
433f675e35dSoster {
434db818c53Spooka 	if (prog_ioctl(fd, command, arg) == -1)
43513a59406Schristos 		err(1, "ioctl (%s) failed", ioctl_name);
436f675e35dSoster }
437f675e35dSoster 
438f675e35dSoster 
439f675e35dSoster static void
440f0121f1fSxtraeme rf_configure(int fd, char *config_file, int force)
441f675e35dSoster {
442f675e35dSoster 	void *generic;
443f675e35dSoster 	RF_Config_t cfg;
444f675e35dSoster 
44513a59406Schristos 	if (rf_MakeConfig( config_file, &cfg ) != 0)
44613a59406Schristos 		err(1, "Unable to create RAIDframe configuration structure");
447f675e35dSoster 
44853d349a1Soster 	cfg.force = force;
44953d349a1Soster 
450f675e35dSoster 	/*
451a53c712bSthorpej 	 * Note the extra level of redirection needed here, since
452a53c712bSthorpej 	 * what we really want to pass in is a pointer to the pointer to
453a53c712bSthorpej 	 * the configuration structure.
454f675e35dSoster 	 */
455f675e35dSoster 
45613a59406Schristos 	generic = &cfg;
457f675e35dSoster 	do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE");
458f675e35dSoster }
459f675e35dSoster 
460a53c712bSthorpej static const char *
461f0121f1fSxtraeme device_status(RF_DiskStatus_t status)
462f675e35dSoster {
463f675e35dSoster 
464f675e35dSoster 	switch (status) {
465f675e35dSoster 	case rf_ds_optimal:
466a53c712bSthorpej 		return ("optimal");
467f675e35dSoster 	case rf_ds_failed:
468a53c712bSthorpej 		return ("failed");
469f675e35dSoster 	case rf_ds_reconstructing:
470a53c712bSthorpej 		return ("reconstructing");
471f675e35dSoster 	case rf_ds_dist_spared:
472a53c712bSthorpej 		return ("dist_spared");
473f675e35dSoster 	case rf_ds_spared:
474a53c712bSthorpej 		return ("spared");
475f675e35dSoster 	case rf_ds_spare:
476a53c712bSthorpej 		return ("spare");
477f675e35dSoster 	case rf_ds_used_spare:
478a53c712bSthorpej 		return ("used_spare");
479f675e35dSoster 	default:
480a53c712bSthorpej 		return ("UNKNOWN");
481f675e35dSoster 	}
482a53c712bSthorpej 	/* NOTREACHED */
483f675e35dSoster }
484f675e35dSoster 
485f675e35dSoster static void
486f0121f1fSxtraeme rf_get_device_status(int fd)
487f675e35dSoster {
488f675e35dSoster 	RF_DeviceConfig_t device_config;
489f675e35dSoster 	void *cfg_ptr;
490225f5a8bSoster 	int is_clean;
4913a8aa0a4Smlelstv 	int i, nspares;
492f675e35dSoster 
493f675e35dSoster 	cfg_ptr = &device_config;
494f675e35dSoster 
495f675e35dSoster 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
496f675e35dSoster 
497f675e35dSoster 	printf("Components:\n");
498f675e35dSoster 	for(i=0; i < device_config.ndevs; i++) {
499f675e35dSoster 		printf("%20s: %s\n", device_config.devs[i].devname,
500f675e35dSoster 		       device_status(device_config.devs[i].status));
501f675e35dSoster 	}
5023a8aa0a4Smlelstv 
503dacdd9d9Smlelstv 	nspares = MIN(device_config.nspares,
5043a8aa0a4Smlelstv 	                __arraycount(device_config.spares));
5053a8aa0a4Smlelstv 
5063a8aa0a4Smlelstv 	if (nspares > 0) {
507f675e35dSoster 		printf("Spares:\n");
5083a8aa0a4Smlelstv 		for(i=0; i < nspares; i++) {
509ae9b468dSoster 			printf("%20s: %s\n",
510f675e35dSoster 			       device_config.spares[i].devname,
511f675e35dSoster 			       device_status(device_config.spares[i].status));
512f675e35dSoster 		}
513f675e35dSoster 	} else {
514f675e35dSoster 		printf("No spares.\n");
515f675e35dSoster 	}
5163a374be7Soster 	for(i=0; i < device_config.ndevs; i++) {
5173a374be7Soster 		if (device_config.devs[i].status == rf_ds_optimal) {
5183a374be7Soster 			get_component_label(fd, device_config.devs[i].devname);
5193a374be7Soster 		} else {
5203a374be7Soster 			printf("%s status is: %s.  Skipping label.\n",
5213a374be7Soster 			       device_config.devs[i].devname,
5223a374be7Soster 			       device_status(device_config.devs[i].status));
5233a374be7Soster 		}
5243a374be7Soster 	}
5253fa8f52bSoster 
5263a8aa0a4Smlelstv 	if (nspares > 0) {
5273a8aa0a4Smlelstv 		for(i=0; i < nspares; i++) {
528c4f772eeSoster 			if ((device_config.spares[i].status ==
529c4f772eeSoster 			     rf_ds_optimal) ||
530c4f772eeSoster 			    (device_config.spares[i].status ==
531c4f772eeSoster 			     rf_ds_used_spare)) {
532c4f772eeSoster 				get_component_label(fd,
533c4f772eeSoster 					    device_config.spares[i].devname);
534c4f772eeSoster 			} else {
535c4f772eeSoster 				printf("%s status is: %s.  Skipping label.\n",
536c4f772eeSoster 				       device_config.spares[i].devname,
537ee1e729eSkre 				       device_status(
538ee1e729eSkre 					   device_config.spares[i].status));
539c4f772eeSoster 			}
540c4f772eeSoster 		}
541c4f772eeSoster 	}
5423fa8f52bSoster 
543225f5a8bSoster 	do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean,
544225f5a8bSoster 		 "RAIDFRAME_CHECK_PARITY");
545225f5a8bSoster 	if (is_clean) {
546225f5a8bSoster 		printf("Parity status: clean\n");
547225f5a8bSoster 	} else {
548225f5a8bSoster 		printf("Parity status: DIRTY\n");
549225f5a8bSoster 	}
5503a374be7Soster 	check_status(fd,0);
55153d349a1Soster }
552f675e35dSoster 
55353d349a1Soster static void
554f1a1ad33Sjld rf_output_pmstat(int fd, int raidID)
555f1a1ad33Sjld {
556f1a1ad33Sjld 	char srs[7];
557858911baSplunky 	unsigned int i, j;
558858911baSplunky 	int dis, dr;
559f1a1ad33Sjld 	struct rf_pmstat st;
560f1a1ad33Sjld 
561db818c53Spooka 	if (prog_ioctl(fd, RAIDFRAME_PARITYMAP_STATUS, &st) == -1) {
5629abd7e49Sjld 		if (errno == EINVAL) {
5639abd7e49Sjld 			printf("raid%d: has no parity; parity map disabled\n",
5649abd7e49Sjld 				raidID);
5659abd7e49Sjld 			return;
5669abd7e49Sjld 		}
5679abd7e49Sjld 		err(1, "ioctl (%s) failed", "RAIDFRAME_PARITYMAP_STATUS");
5689abd7e49Sjld 	}
5699abd7e49Sjld 
570f1a1ad33Sjld 	if (st.enabled) {
571f1a1ad33Sjld 		if (0 > humanize_number(srs, 7, st.region_size * DEV_BSIZE,
572f1a1ad33Sjld 			"B", HN_AUTOSCALE, HN_NOSPACE))
573f1a1ad33Sjld 			strlcpy(srs, "???", 7);
574f1a1ad33Sjld 
575f1a1ad33Sjld 		printf("raid%d: parity map enabled with %u regions of %s\n",
576f1a1ad33Sjld 		    raidID, st.params.regions, srs);
5779bd6e266Sjld 		printf("raid%d: regions marked clean after %d intervals of"
578f1a1ad33Sjld 		    " %d.%03ds\n", raidID, st.params.cooldown,
579f1a1ad33Sjld 		    st.params.tickms / 1000, st.params.tickms % 1000);
580f1a1ad33Sjld 		printf("raid%d: write/sync/clean counters "
581f1a1ad33Sjld 		    "%"PRIu64"/%"PRIu64"/%"PRIu64"\n", raidID,
582f1a1ad33Sjld 		    st.ctrs.nwrite, st.ctrs.ncachesync, st.ctrs.nclearing);
583f1a1ad33Sjld 
584f1a1ad33Sjld 		dr = 0;
5858ccd0f67Sjld 		for (i = 0; i < st.params.regions; i++)
586f1a1ad33Sjld 			if (isset(st.dirty, i))
587f1a1ad33Sjld 				dr++;
588f1a1ad33Sjld 		printf("raid%d: %d dirty region%s\n", raidID, dr,
589f1a1ad33Sjld 		    dr == 1 ? "" : "s");
590f1a1ad33Sjld 
591f1a1ad33Sjld 		if (verbose > 0) {
592f1a1ad33Sjld 			for (i = 0; i < RF_PARITYMAP_NBYTE; i += 32) {
593f1a1ad33Sjld 				printf("    ");
594f1a1ad33Sjld 				for (j = i; j < RF_PARITYMAP_NBYTE
595f1a1ad33Sjld 					 && j < i + 32; j++)
596f1a1ad33Sjld 					printf("%x%x", st.dirty[j] & 15,
597f1a1ad33Sjld 					    (st.dirty[j] >> 4) & 15);
598f1a1ad33Sjld 				printf("\n");
599f1a1ad33Sjld 			}
600f1a1ad33Sjld 		}
601f1a1ad33Sjld 	} else {
602f1a1ad33Sjld 		printf("raid%d: parity map disabled\n", raidID);
603f1a1ad33Sjld 	}
604f1a1ad33Sjld 
605f1a1ad33Sjld 	do_ioctl(fd, RAIDFRAME_PARITYMAP_GET_DISABLE, &dis,
606f1a1ad33Sjld 	    "RAIDFRAME_PARITYMAP_GET_DISABLE");
607f1a1ad33Sjld 	printf("raid%d: parity map will %s %sabled on next configure\n",
608f1a1ad33Sjld 	    raidID, dis == st.enabled ? "be" : "remain", dis ? "dis" : "en");
609f1a1ad33Sjld }
610f1a1ad33Sjld 
611f1a1ad33Sjld static void
612f1a1ad33Sjld rf_pm_configure(int fd, int raidID, char *parityconf, int parityparams[])
613f1a1ad33Sjld {
614f1a1ad33Sjld 	int dis;
615f1a1ad33Sjld 	struct rf_pmparams params;
616f1a1ad33Sjld 
617f1a1ad33Sjld 	if (strcasecmp(parityconf, "yes") == 0)
618f1a1ad33Sjld 		dis = 0;
619f1a1ad33Sjld 	else if (strcasecmp(parityconf, "no") == 0)
620f1a1ad33Sjld 		dis = 1;
621f1a1ad33Sjld 	else if (strcasecmp(parityconf, "set") == 0) {
622f1a1ad33Sjld 		params.cooldown = parityparams[0];
623f1a1ad33Sjld 		params.tickms = parityparams[1];
624f1a1ad33Sjld 		params.regions = parityparams[2];
625f1a1ad33Sjld 
626f1a1ad33Sjld 		do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_PARAMS, &params,
627f1a1ad33Sjld 		    "RAIDFRAME_PARITYMAP_SET_PARAMS");
628f1a1ad33Sjld 
629f1a1ad33Sjld 		if (params.cooldown != 0 || params.tickms != 0) {
630f1a1ad33Sjld 			printf("raid%d: parity cleaned after", raidID);
631f1a1ad33Sjld 			if (params.cooldown != 0)
632f1a1ad33Sjld 				printf(" %d", params.cooldown);
633f1a1ad33Sjld 			printf(" intervals");
634f1a1ad33Sjld 			if (params.tickms != 0) {
635f1a1ad33Sjld 				printf(" of %d.%03ds", params.tickms / 1000,
636f1a1ad33Sjld 				    params.tickms % 1000);
637f1a1ad33Sjld 			}
638f1a1ad33Sjld 			printf("\n");
639f1a1ad33Sjld 		}
640f1a1ad33Sjld 		if (params.regions != 0)
641f1a1ad33Sjld 			printf("raid%d: will use %d regions on next"
642f1a1ad33Sjld 			    " configuration\n", raidID, params.regions);
643f1a1ad33Sjld 
644f1a1ad33Sjld 		return;
645f1a1ad33Sjld 		/* XXX the control flow here could be prettier. */
64613a59406Schristos 	} else
64713a59406Schristos 		err(1, "`%s' is not a valid parity map command", parityconf);
648f1a1ad33Sjld 
649f1a1ad33Sjld 	do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_DISABLE, &dis,
650f1a1ad33Sjld 	    "RAIDFRAME_PARITYMAP_SET_DISABLE");
651f1a1ad33Sjld 	printf("raid%d: parity map will be %sabled on next configure\n",
652f1a1ad33Sjld 	    raidID, dis ? "dis" : "en");
653f1a1ad33Sjld }
654f1a1ad33Sjld 
655ec5f69b6Smrg /* convert "component0" into "absent" */
6566c69384dSbad static const char *rf_output_devname(const char *name)
657ec5f69b6Smrg {
658ec5f69b6Smrg 
6596c69384dSbad 	if (strncmp(name, "component", 9) == 0)
660ec5f69b6Smrg 		return "absent";
6616c69384dSbad 	return name;
662ec5f69b6Smrg }
663f1a1ad33Sjld 
664f1a1ad33Sjld static void
665f0121f1fSxtraeme rf_output_configuration(int fd, const char *name)
666364e3039Slukem {
667364e3039Slukem 	RF_DeviceConfig_t device_config;
668364e3039Slukem 	void *cfg_ptr;
669dacdd9d9Smlelstv 	int i, nspares;
670364e3039Slukem 	RF_ComponentLabel_t component_label;
671364e3039Slukem 	void *label_ptr;
672364e3039Slukem 	int component_num;
673364e3039Slukem 	int num_cols;
674364e3039Slukem 
675364e3039Slukem 	cfg_ptr = &device_config;
676364e3039Slukem 
677364e3039Slukem 	printf("# raidctl config file for %s\n", name);
678364e3039Slukem 	printf("\n");
679364e3039Slukem 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
680364e3039Slukem 
681dacdd9d9Smlelstv 	nspares = MIN(device_config.nspares,
682dacdd9d9Smlelstv 	                __arraycount(device_config.spares));
683dacdd9d9Smlelstv 
684364e3039Slukem 	printf("START array\n");
6855a1ff55aSkre 	printf("# numCol numSpare\n");
6865a1ff55aSkre 	printf("%d %d\n", device_config.cols, device_config.nspares);
687364e3039Slukem 	printf("\n");
688364e3039Slukem 
689364e3039Slukem 	printf("START disks\n");
690364e3039Slukem 	for(i=0; i < device_config.ndevs; i++)
691ec5f69b6Smrg 		printf("%s\n",
692ec5f69b6Smrg 		    rf_output_devname(device_config.devs[i].devname));
693364e3039Slukem 	printf("\n");
694364e3039Slukem 
695dacdd9d9Smlelstv 	if (nspares > 0) {
696364e3039Slukem 		printf("START spare\n");
697dacdd9d9Smlelstv 		for(i=0; i < nspares; i++)
698364e3039Slukem 			printf("%s\n", device_config.spares[i].devname);
699364e3039Slukem 		printf("\n");
700364e3039Slukem 	}
701364e3039Slukem 
702364e3039Slukem 	for(i=0; i < device_config.ndevs; i++) {
703364e3039Slukem 		if (device_config.devs[i].status == rf_ds_optimal)
704364e3039Slukem 			break;
705364e3039Slukem 	}
706364e3039Slukem 	if (i == device_config.ndevs) {
707364e3039Slukem 		printf("# WARNING: no optimal components; using %s\n",
708364e3039Slukem 		    device_config.devs[0].devname);
709364e3039Slukem 		i = 0;
710364e3039Slukem 	}
711364e3039Slukem 	get_component_number(fd, device_config.devs[i].devname,
712364e3039Slukem 	    &component_num, &num_cols);
713364e3039Slukem 	memset(&component_label, 0, sizeof(RF_ComponentLabel_t));
714364e3039Slukem 	component_label.row = component_num / num_cols;
715364e3039Slukem 	component_label.column = component_num % num_cols;
716364e3039Slukem 	label_ptr = &component_label;
7176ebbd813Snakayama 	do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, label_ptr,
718364e3039Slukem 		  "RAIDFRAME_GET_COMPONENT_LABEL");
719364e3039Slukem 
720364e3039Slukem 	printf("START layout\n");
721364e3039Slukem 	printf(
722364e3039Slukem 	    "# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_%c\n",
723364e3039Slukem 	    (char) component_label.parityConfig);
724364e3039Slukem 	printf("%d %d %d %c\n",
725364e3039Slukem 	    component_label.sectPerSU, component_label.SUsPerPU,
726364e3039Slukem 	    component_label.SUsPerRU, (char) component_label.parityConfig);
727364e3039Slukem 	printf("\n");
728364e3039Slukem 
729364e3039Slukem 	printf("START queue\n");
730364e3039Slukem 	printf("fifo %d\n", device_config.maxqdepth);
731364e3039Slukem }
732364e3039Slukem 
733364e3039Slukem static void
734f0121f1fSxtraeme get_component_number(int fd, char *component_name, int *component_number,
735f0121f1fSxtraeme 		     int *num_columns)
73653d349a1Soster {
73753d349a1Soster 	RF_DeviceConfig_t device_config;
73853d349a1Soster 	void *cfg_ptr;
739dacdd9d9Smlelstv 	int i, nspares;
74053d349a1Soster 	int found;
74153d349a1Soster 
74253d349a1Soster 	*component_number = -1;
74353d349a1Soster 
74453d349a1Soster 	/* Assuming a full path spec... */
74553d349a1Soster 	cfg_ptr = &device_config;
74653d349a1Soster 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr,
74753d349a1Soster 		 "RAIDFRAME_GET_INFO");
74853d349a1Soster 
74953d349a1Soster 	*num_columns = device_config.cols;
75053d349a1Soster 
751dacdd9d9Smlelstv 	nspares = MIN(device_config.nspares,
752dacdd9d9Smlelstv 	                __arraycount(device_config.spares));
753dacdd9d9Smlelstv 
75453d349a1Soster 	found = 0;
75553d349a1Soster 	for(i=0; i < device_config.ndevs; i++) {
75653d349a1Soster 		if (strncmp(component_name, device_config.devs[i].devname,
75753d349a1Soster 			    PATH_MAX)==0) {
75853d349a1Soster 			found = 1;
75953d349a1Soster 			*component_number = i;
76053d349a1Soster 		}
76153d349a1Soster 	}
762c4f772eeSoster 	if (!found) { /* maybe it's a spare? */
763dacdd9d9Smlelstv 		for(i=0; i < nspares; i++) {
764c4f772eeSoster 			if (strncmp(component_name,
765c4f772eeSoster 				    device_config.spares[i].devname,
766c4f772eeSoster 				    PATH_MAX)==0) {
767c4f772eeSoster 				found = 1;
768c4f772eeSoster 				*component_number = i + device_config.ndevs;
7693fa8f52bSoster 				/* the way spares are done should
7703fa8f52bSoster 				   really change... */
7713fa8f52bSoster 				*num_columns = device_config.cols +
7723fa8f52bSoster 					device_config.nspares;
773c4f772eeSoster 			}
774c4f772eeSoster 		}
775c4f772eeSoster 	}
776c4f772eeSoster 
77713a59406Schristos 	if (!found)
77813a59406Schristos 		err(1,"%s is not a component of this device", component_name);
779f675e35dSoster }
780f675e35dSoster 
781f675e35dSoster static void
782f0121f1fSxtraeme rf_fail_disk(int fd, char *component_to_fail, int do_recon)
783f675e35dSoster {
784f675e35dSoster 	struct rf_recon_req recon_request;
785f675e35dSoster 	int component_num;
78653d349a1Soster 	int num_cols;
787f675e35dSoster 
78853d349a1Soster 	get_component_number(fd, component_to_fail, &component_num, &num_cols);
789f675e35dSoster 
79053d349a1Soster 	recon_request.col = component_num % num_cols;
791f675e35dSoster 	if (do_recon) {
792f675e35dSoster 		recon_request.flags = RF_FDFLAGS_RECON;
793f675e35dSoster 	} else {
794f675e35dSoster 		recon_request.flags = RF_FDFLAGS_NONE;
795f675e35dSoster 	}
796f675e35dSoster 	do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request,
797f675e35dSoster 		 "RAIDFRAME_FAIL_DISK");
798c714a07dSoster 	if (do_recon && verbose) {
799c714a07dSoster 		printf("Reconstruction status:\n");
800c714a07dSoster 		sleep(3); /* XXX give reconstruction a chance to start */
80164ad6c88Soster 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT);
802c714a07dSoster 	}
803f675e35dSoster }
804f675e35dSoster 
805f675e35dSoster static void
806f0121f1fSxtraeme get_component_label(int fd, char *component)
807ae9b468dSoster {
808ae9b468dSoster 	RF_ComponentLabel_t component_label;
809ae9b468dSoster 	void *label_ptr;
810ae9b468dSoster 	int component_num;
81153d349a1Soster 	int num_cols;
812ae9b468dSoster 
81353d349a1Soster 	get_component_number(fd, component, &component_num, &num_cols);
814ae9b468dSoster 
815ae9b468dSoster 	memset( &component_label, 0, sizeof(RF_ComponentLabel_t));
81653d349a1Soster 	component_label.row = component_num / num_cols;
81753d349a1Soster 	component_label.column = component_num % num_cols;
818ae9b468dSoster 
819ae9b468dSoster 	label_ptr = &component_label;
8206ebbd813Snakayama 	do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, label_ptr,
821ae9b468dSoster 		  "RAIDFRAME_GET_COMPONENT_LABEL");
822ae9b468dSoster 
823ae9b468dSoster 	printf("Component label for %s:\n",component);
8245aee30c0Soster 
8254e9651baSlukem 	printf("   Row: %d, Column: %d, Num Rows: %d, Num Columns: %d\n",
8265aee30c0Soster 	       component_label.row, component_label.column,
8275aee30c0Soster 	       component_label.num_rows, component_label.num_columns);
8281ca3e5d8Smrg 	printf("   Version: %d, Serial Number: %u, Mod Counter: %d\n",
8295aee30c0Soster 	       component_label.version, component_label.serial_number,
8305aee30c0Soster 	       component_label.mod_counter);
8314e9651baSlukem 	printf("   Clean: %s, Status: %d\n",
8325aee30c0Soster 	       component_label.clean ? "Yes" : "No",
8335aee30c0Soster 	       component_label.status );
8344e9651baSlukem 	printf("   sectPerSU: %d, SUsPerPU: %d, SUsPerRU: %d\n",
8355aee30c0Soster 	       component_label.sectPerSU, component_label.SUsPerPU,
8365aee30c0Soster 	       component_label.SUsPerRU);
837ec02ea41Senami 	printf("   Queue size: %d, blocksize: %d, numBlocks: %"PRIu64"\n",
8384e9651baSlukem 	       component_label.maxOutstanding, component_label.blockSize,
839ec02ea41Senami 	       rf_component_label_numblocks(&component_label));
8404e9651baSlukem 	printf("   RAID Level: %c\n", (char) component_label.parityConfig);
8415aee30c0Soster 	printf("   Autoconfig: %s\n",
8425aee30c0Soster 	       component_label.autoconfigure ? "Yes" : "No" );
843807e453cSoster 	printf("   Root partition: %s\n",
84452334fd8Schristos 	       rootpart[component_label.root_partition & 3]);
8455aee30c0Soster 	printf("   Last configured as: raid%d\n", component_label.last_unit );
846ae9b468dSoster }
847ae9b468dSoster 
848ae9b468dSoster static void
849f0121f1fSxtraeme set_component_label(int fd, char *component)
850ae9b468dSoster {
851ae9b468dSoster 	RF_ComponentLabel_t component_label;
852ae9b468dSoster 	int component_num;
85353d349a1Soster 	int num_cols;
854ae9b468dSoster 
85553d349a1Soster 	get_component_number(fd, component, &component_num, &num_cols);
856ae9b468dSoster 
85753d349a1Soster 	/* XXX This is currently here for testing, and future expandability */
858ae9b468dSoster 
859ae9b468dSoster 	component_label.version = 1;
860ae9b468dSoster 	component_label.serial_number = 123456;
861ae9b468dSoster 	component_label.mod_counter = 0;
86253d349a1Soster 	component_label.row = component_num / num_cols;
86353d349a1Soster 	component_label.column = component_num % num_cols;
864ae9b468dSoster 	component_label.num_rows = 0;
865ae9b468dSoster 	component_label.num_columns = 5;
866ae9b468dSoster 	component_label.clean = 0;
867ae9b468dSoster 	component_label.status = 1;
868ae9b468dSoster 
869ae9b468dSoster 	do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label,
870ae9b468dSoster 		  "RAIDFRAME_SET_COMPONENT_LABEL");
871ae9b468dSoster }
872ae9b468dSoster 
873ae9b468dSoster 
874ae9b468dSoster static void
875f0121f1fSxtraeme init_component_labels(int fd, int serial_number)
876ae9b468dSoster {
877ae9b468dSoster 	RF_ComponentLabel_t component_label;
878ae9b468dSoster 
879ae9b468dSoster 	component_label.version = 0;
880ae9b468dSoster 	component_label.serial_number = serial_number;
881ae9b468dSoster 	component_label.mod_counter = 0;
882ae9b468dSoster 	component_label.row = 0;
883ae9b468dSoster 	component_label.column = 0;
884ae9b468dSoster 	component_label.num_rows = 0;
885ae9b468dSoster 	component_label.num_columns = 0;
886ae9b468dSoster 	component_label.clean = 0;
887ae9b468dSoster 	component_label.status = 0;
888ae9b468dSoster 
889ae9b468dSoster 	do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label,
8906b6fd5e2Soster 		  "RAIDFRAME_INIT_LABELS");
891ae9b468dSoster }
892ae9b468dSoster 
893ae9b468dSoster static void
894f0121f1fSxtraeme set_autoconfig(int fd, int raidID, char *autoconf)
8955aee30c0Soster {
8965aee30c0Soster 	int auto_config;
8975aee30c0Soster 	int root_config;
8985aee30c0Soster 
8995aee30c0Soster 	auto_config = 0;
9005aee30c0Soster 	root_config = 0;
9015aee30c0Soster 
90252334fd8Schristos 	if (strncasecmp(autoconf, "root", 4) == 0 ||
90352334fd8Schristos 	    strncasecmp(autoconf, "hard", 4) == 0 ||
90406ac3946Ssborrill 	    strncasecmp(autoconf, "force", 5) == 0) {
9055aee30c0Soster 		root_config = 1;
90652334fd8Schristos 	} else if (strncasecmp(autoconf, "soft", 4) == 0) {
90752334fd8Schristos 		root_config = 2;
9085aee30c0Soster 	}
9095aee30c0Soster 
9105aee30c0Soster 	if ((strncasecmp(autoconf,"yes", 3) == 0) ||
91152334fd8Schristos 	    root_config > 0) {
9125aee30c0Soster 		auto_config = 1;
9135aee30c0Soster 	}
9145aee30c0Soster 
9155aee30c0Soster 	do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config,
9165aee30c0Soster 		 "RAIDFRAME_SET_AUTOCONFIG");
9175aee30c0Soster 
9185aee30c0Soster 	do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config,
9195aee30c0Soster 		 "RAIDFRAME_SET_ROOT");
9205aee30c0Soster 
92174ff9ea8Soster 	if (verbose) {
9225aee30c0Soster 		printf("raid%d: Autoconfigure: %s\n", raidID,
9235aee30c0Soster 		       auto_config ? "Yes" : "No");
92452334fd8Schristos 		if (auto_config == 1) {
92552334fd8Schristos 			printf("raid%d: Root: %s\n", raidID, rootpart[root_config]);
9265aee30c0Soster 		}
9275aee30c0Soster 	}
92874ff9ea8Soster }
9295aee30c0Soster 
9305aee30c0Soster static void
931f0121f1fSxtraeme add_hot_spare(int fd, char *component)
932ae9b468dSoster {
93353d349a1Soster 	RF_SingleComponent_t hot_spare;
934ae9b468dSoster 
93553d349a1Soster 	hot_spare.row = 0;
93653d349a1Soster 	hot_spare.column = 0;
93753d349a1Soster 	strncpy(hot_spare.component_name, component,
93853d349a1Soster 		sizeof(hot_spare.component_name));
939ae9b468dSoster 
940ae9b468dSoster 	do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare,
941ae9b468dSoster 		  "RAIDFRAME_ADD_HOT_SPARE");
94253d349a1Soster }
943ae9b468dSoster 
94453d349a1Soster static void
945a6071800Soster remove_component(int fd, char *component)
94653d349a1Soster {
947a6071800Soster 	RF_SingleComponent_t comp;
94853d349a1Soster 	int component_num;
94953d349a1Soster 	int num_cols;
95053d349a1Soster 
95153d349a1Soster 	get_component_number(fd, component, &component_num, &num_cols);
95253d349a1Soster 
953a6071800Soster 	comp.row = component_num / num_cols;
954a6071800Soster 	comp.column = component_num % num_cols;
95553d349a1Soster 
956a6071800Soster 	strncpy(comp.component_name, component,
957a6071800Soster 		sizeof(comp.component_name));
95853d349a1Soster 
959a6071800Soster 	do_ioctl( fd, RAIDFRAME_REMOVE_COMPONENT, &comp,
960a6071800Soster 		  "RAIDFRAME_REMOVE_COMPONENT");
96153d349a1Soster }
96253d349a1Soster 
96353d349a1Soster static void
964f0121f1fSxtraeme rebuild_in_place(int fd, char *component)
96553d349a1Soster {
96653d349a1Soster 	RF_SingleComponent_t comp;
96753d349a1Soster 	int component_num;
96853d349a1Soster 	int num_cols;
96953d349a1Soster 
97053d349a1Soster 	get_component_number(fd, component, &component_num, &num_cols);
97153d349a1Soster 
97253d349a1Soster 	comp.row = 0;
97353d349a1Soster 	comp.column = component_num;
97453d349a1Soster 	strncpy(comp.component_name, component, sizeof(comp.component_name));
97553d349a1Soster 
97653d349a1Soster 	do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp,
97753d349a1Soster 		  "RAIDFRAME_REBUILD_IN_PLACE");
978c714a07dSoster 
979c714a07dSoster 	if (verbose) {
980c714a07dSoster 		printf("Reconstruction status:\n");
981c714a07dSoster 		sleep(3); /* XXX give reconstruction a chance to start */
98264ad6c88Soster 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT);
983c714a07dSoster 	}
984c714a07dSoster 
985c714a07dSoster }
986c714a07dSoster 
987c714a07dSoster static void
988f0121f1fSxtraeme check_parity(int fd, int do_rewrite, char *dev_name)
989c714a07dSoster {
990c714a07dSoster 	int is_clean;
991c714a07dSoster 	int percent_done;
992c714a07dSoster 
993c714a07dSoster 	is_clean = 0;
994c714a07dSoster 	percent_done = 0;
995c714a07dSoster 	do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean,
996c714a07dSoster 		 "RAIDFRAME_CHECK_PARITY");
997c714a07dSoster 	if (is_clean) {
998c714a07dSoster 		printf("%s: Parity status: clean\n",dev_name);
999c714a07dSoster 	} else {
1000c714a07dSoster 		printf("%s: Parity status: DIRTY\n",dev_name);
1001c714a07dSoster 		if (do_rewrite) {
1002c714a07dSoster 			printf("%s: Initiating re-write of parity\n",
1003c714a07dSoster 			       dev_name);
1004c714a07dSoster 			do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
1005c714a07dSoster 				 "RAIDFRAME_REWRITEPARITY");
1006c714a07dSoster 			sleep(3); /* XXX give it time to
1007c714a07dSoster 				     get started. */
1008c714a07dSoster 			if (verbose) {
1009c714a07dSoster 				printf("Parity Re-write status:\n");
1010ee1e729eSkre 				do_meter(fd,
1011ee1e729eSkre 				    RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
1012c714a07dSoster 			} else {
1013c714a07dSoster 				do_ioctl(fd,
1014c714a07dSoster 					 RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
1015c714a07dSoster 					 &percent_done,
1016c714a07dSoster 					 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"
1017c714a07dSoster 					 );
1018c714a07dSoster 				while( percent_done < 100 ) {
10198b779951Soster 					sleep(3); /* wait a bit... */
1020ee1e729eSkre 					do_ioctl(fd,
1021ee1e729eSkre 					   RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
1022ee1e729eSkre 						 &percent_done,
1023ee1e729eSkre 				    "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
1024c714a07dSoster 				}
1025c714a07dSoster 
1026c714a07dSoster 			}
1027ee1e729eSkre 			printf("%s: Parity Re-write complete\n", dev_name);
1028c714a07dSoster 		} else {
1029c714a07dSoster 			/* parity is wrong, and is not being fixed.
1030c714a07dSoster 			   Exit w/ an error. */
1031c714a07dSoster 			exit(1);
1032c714a07dSoster 		}
1033c714a07dSoster 	}
1034c714a07dSoster }
1035c714a07dSoster 
1036c714a07dSoster 
1037c714a07dSoster static void
1038f0121f1fSxtraeme check_status(int fd, int meter)
1039c714a07dSoster {
1040c714a07dSoster 	int recon_percent_done = 0;
1041c714a07dSoster 	int parity_percent_done = 0;
1042c714a07dSoster 
1043c714a07dSoster 	do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done,
1044c714a07dSoster 		 "RAIDFRAME_CHECK_RECON_STATUS");
1045c714a07dSoster 	printf("Reconstruction is %d%% complete.\n", recon_percent_done);
1046c714a07dSoster 	do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
1047c714a07dSoster 		 &parity_percent_done,
1048c714a07dSoster 		 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
1049c714a07dSoster 	printf("Parity Re-write is %d%% complete.\n", parity_percent_done);
1050c714a07dSoster 
10513a374be7Soster 	if (meter) {
1052c714a07dSoster 		/* These 3 should be mutually exclusive at this point */
1053c714a07dSoster 		if (recon_percent_done < 100) {
1054c714a07dSoster 			printf("Reconstruction status:\n");
105564ad6c88Soster 			do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT);
1056c714a07dSoster 		} else if (parity_percent_done < 100) {
1057c714a07dSoster 			printf("Parity Re-write status:\n");
105864ad6c88Soster 			do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
1059c714a07dSoster 		}
1060c714a07dSoster 	}
10613a374be7Soster }
1062c714a07dSoster 
1063a53c712bSthorpej const char *tbits = "|/-\\";
1064c714a07dSoster 
1065c714a07dSoster static void
1066f0121f1fSxtraeme do_meter(int fd, u_long option)
1067c714a07dSoster {
1068c714a07dSoster 	int percent_done;
1069c10404e8Soster 	RF_uint64 start_value;
107064ad6c88Soster 	RF_ProgressInfo_t progressInfo;
107164ad6c88Soster 	void *pInfoPtr;
1072c714a07dSoster 	struct timeval start_time;
1073c714a07dSoster 	struct timeval current_time;
1074c714a07dSoster 	double elapsed;
1075c714a07dSoster 	int elapsed_sec;
1076c714a07dSoster 	int elapsed_usec;
10770ce56710Soster 	int simple_eta,last_eta;
1078c714a07dSoster 	double rate;
1079c10404e8Soster 	RF_uint64 amount;
1080c714a07dSoster 	int tbit_value;
1081c714a07dSoster 	char bar_buffer[1024];
1082c714a07dSoster 	char eta_buffer[1024];
1083c714a07dSoster 
108413a59406Schristos 	if (gettimeofday(&start_time,NULL) == -1)
108513a59406Schristos 		err(1, "gettimeofday failed!?!?");
108664ad6c88Soster 	memset(&progressInfo, 0, sizeof(RF_ProgressInfo_t));
108764ad6c88Soster 	pInfoPtr=&progressInfo;
108864ad6c88Soster 
1089c714a07dSoster 	percent_done = 0;
10906ebbd813Snakayama 	do_ioctl(fd, option, pInfoPtr, "");
1091c10404e8Soster 	start_value = progressInfo.completed;
1092c714a07dSoster 	current_time = start_time;
10939a1b8a3bSlukem 	simple_eta = 0;
10949a1b8a3bSlukem 	last_eta = 0;
1095c714a07dSoster 
1096c714a07dSoster 	tbit_value = 0;
109764ad6c88Soster 	while(progressInfo.completed < progressInfo.total) {
1098c714a07dSoster 
109964ad6c88Soster 		percent_done = (progressInfo.completed * 100) /
110064ad6c88Soster 			progressInfo.total;
1101c714a07dSoster 
1102c714a07dSoster 		get_bar(bar_buffer, percent_done, 40);
1103c714a07dSoster 
11040ce56710Soster 		elapsed_sec = current_time.tv_sec - start_time.tv_sec;
11050ce56710Soster 		elapsed_usec = current_time.tv_usec - start_time.tv_usec;
1106c714a07dSoster 		if (elapsed_usec < 0) {
1107c714a07dSoster 			elapsed_usec-=1000000;
1108c714a07dSoster 			elapsed_sec++;
1109c714a07dSoster 		}
1110c714a07dSoster 
1111c714a07dSoster 		elapsed = (double) elapsed_sec +
1112c714a07dSoster 			(double) elapsed_usec / 1000000.0;
1113c714a07dSoster 
11140ce56710Soster 		amount = progressInfo.completed - start_value;
111564ad6c88Soster 
1116c714a07dSoster 		if (amount <= 0) { /* we don't do negatives (yet?) */
1117c714a07dSoster 			amount = 0;
1118c714a07dSoster 		}
11190ce56710Soster 
11204d751100Soster 		if (elapsed == 0)
11214d751100Soster 			rate = 0.0;
11224d751100Soster 		else
1123c714a07dSoster 			rate = amount / elapsed;
1124c714a07dSoster 
1125c714a07dSoster 		if (rate > 0.0) {
112664ad6c88Soster 			simple_eta = (int) (((double)progressInfo.total -
112764ad6c88Soster 					     (double) progressInfo.completed)
112864ad6c88Soster 					    / rate);
1129c714a07dSoster 		} else {
1130c714a07dSoster 			simple_eta = -1;
1131c714a07dSoster 		}
113264ad6c88Soster 
1133c714a07dSoster 		if (simple_eta <=0) {
1134c714a07dSoster 			simple_eta = last_eta;
1135c714a07dSoster 		} else {
1136c714a07dSoster 			last_eta = simple_eta;
1137c714a07dSoster 		}
1138c714a07dSoster 
11397b743cfcSmrg 		get_time_string(eta_buffer, sizeof eta_buffer, simple_eta);
1140c714a07dSoster 
1141f42bf265Schristos 		fprintf(stdout,"\r%3d%% |%s| ETA: %s %c",
1142c714a07dSoster 			percent_done,bar_buffer,eta_buffer,tbits[tbit_value]);
1143c714a07dSoster 		fflush(stdout);
1144c714a07dSoster 
1145c714a07dSoster 		if (++tbit_value>3)
1146c714a07dSoster 			tbit_value = 0;
1147c714a07dSoster 
1148c714a07dSoster 		sleep(2);
1149c714a07dSoster 
115013a59406Schristos 		if (gettimeofday(&current_time,NULL) == -1)
115113a59406Schristos 			err(1, "gettimeofday failed!?!?");
1152c714a07dSoster 
11536ebbd813Snakayama 		do_ioctl( fd, option, pInfoPtr, "");
1154c714a07dSoster 
1155c714a07dSoster 
1156c714a07dSoster 	}
1157c714a07dSoster 	printf("\n");
1158c714a07dSoster }
1159c714a07dSoster /* 40 '*''s per line, then 40 ' ''s line. */
1160c714a07dSoster /* If you've got a screen wider than 160 characters, "tough" */
1161c714a07dSoster 
1162c714a07dSoster #define STAR_MIDPOINT 4*40
1163c714a07dSoster const char stars[] = "****************************************"
1164c714a07dSoster                      "****************************************"
1165c714a07dSoster                      "****************************************"
1166c714a07dSoster                      "****************************************"
1167c714a07dSoster                      "                                        "
1168c714a07dSoster                      "                                        "
1169c714a07dSoster                      "                                        "
1170c714a07dSoster                      "                                        "
1171c714a07dSoster                      "                                        ";
1172c714a07dSoster 
1173c714a07dSoster static void
1174f0121f1fSxtraeme get_bar(char *string, double percent, int max_strlen)
1175c714a07dSoster {
1176c714a07dSoster 	int offset;
1177c714a07dSoster 
1178c714a07dSoster 	if (max_strlen > STAR_MIDPOINT) {
1179c714a07dSoster 		max_strlen = STAR_MIDPOINT;
1180c714a07dSoster 	}
1181c714a07dSoster 	offset = STAR_MIDPOINT -
1182c714a07dSoster 		(int)((percent * max_strlen)/ 100);
1183c714a07dSoster 	if (offset < 0)
1184c714a07dSoster 		offset = 0;
11858da4f444Spooka 	snprintf(string,max_strlen,"%s",stars+offset);
1186c714a07dSoster }
1187c714a07dSoster 
1188c714a07dSoster static void
11897b743cfcSmrg get_time_string(char *string, size_t len, int simple_time)
1190c714a07dSoster {
1191c714a07dSoster 	int minutes, seconds, hours;
11927b743cfcSmrg 	char hours_buffer[8];
1193c714a07dSoster 	char minutes_buffer[5];
1194c714a07dSoster 	char seconds_buffer[5];
1195c714a07dSoster 
1196c714a07dSoster 	if (simple_time >= 0) {
1197c714a07dSoster 
11987b743cfcSmrg 		minutes = simple_time / 60;
11997b743cfcSmrg 		seconds = simple_time - 60*minutes;
1200c714a07dSoster 		hours = minutes / 60;
1201c714a07dSoster 		minutes = minutes - 60*hours;
12027b743cfcSmrg #if defined(__GNUC__)
12037b743cfcSmrg 		/*
12047b743cfcSmrg 		 * snprintf() truncation checker fails to detect that seconds
12057b743cfcSmrg 		 * and minutes will be 0-59 range.
12067b743cfcSmrg 		 */
12077b743cfcSmrg 		if (minutes < 0 || minutes > 60)
12087b743cfcSmrg 			minutes = 60;
12097b743cfcSmrg 		if (seconds < 0 || seconds > 60)
12107b743cfcSmrg 			seconds = 60;
12117b743cfcSmrg #endif
1212c714a07dSoster 
1213c714a07dSoster 		if (hours > 0) {
1214ee1e729eSkre 			snprintf(hours_buffer,sizeof hours_buffer,
1215ee1e729eSkre 			    "%02d:",hours);
1216c714a07dSoster 		} else {
12177b743cfcSmrg 			snprintf(hours_buffer,sizeof hours_buffer,"   ");
1218c714a07dSoster 		}
1219c714a07dSoster 
12207b743cfcSmrg 		snprintf(minutes_buffer,sizeof minutes_buffer,"%02d:",minutes);
12217b743cfcSmrg 		snprintf(seconds_buffer,sizeof seconds_buffer,"%02d",seconds);
12227b743cfcSmrg 		snprintf(string,len,"%s%s%s",
1223c714a07dSoster 			 hours_buffer, minutes_buffer, seconds_buffer);
1224c714a07dSoster 	} else {
12257b743cfcSmrg 		snprintf(string,len,"   --:--");
1226c714a07dSoster 	}
1227c714a07dSoster 
1228ae9b468dSoster }
1229ae9b468dSoster 
123074ff9ea8Soster /* Simplified RAID creation with a single command line... */
123174ff9ea8Soster static void
123274ff9ea8Soster rf_simple_create(int fd, int argc, char *argv[])
123374ff9ea8Soster {
123474ff9ea8Soster 	int i;
123574ff9ea8Soster 	int level;
123674ff9ea8Soster 	int num_components;
123774ff9ea8Soster 	char *components[RF_MAXCOL];
123874ff9ea8Soster 	void *generic;
123974ff9ea8Soster 	RF_Config_t cfg;
124074ff9ea8Soster 
124174ff9ea8Soster 	/*
124274ff9ea8Soster 	 * Note the extra level of redirection needed here, since
124374ff9ea8Soster 	 * what we really want to pass in is a pointer to the pointer to
124474ff9ea8Soster 	 * the configuration structure.
124574ff9ea8Soster 	 */
124674ff9ea8Soster 
124774ff9ea8Soster 
124874ff9ea8Soster 	if (strcmp(argv[0],"mirror")==0) {
124974ff9ea8Soster 		level = 1;
125074ff9ea8Soster 	} else
125174ff9ea8Soster 		level = atoi(argv[0]);
125274ff9ea8Soster 
125374ff9ea8Soster 	if (level != 0 && level != 1 && level !=5)
125474ff9ea8Soster 		usage();
125574ff9ea8Soster 
125674ff9ea8Soster 	/* remaining args must be components */
125774ff9ea8Soster 	num_components = 0;
125874ff9ea8Soster 	for (i=1 ; i<argc ; i++) {
125974ff9ea8Soster 		components[i-1] = argv[i];
126074ff9ea8Soster 		num_components++;
126174ff9ea8Soster 	}
126274ff9ea8Soster 
126374ff9ea8Soster 	/* Level 0 must have at least two components.
126474ff9ea8Soster 	   Level 1 must have exactly two components.
126574ff9ea8Soster 	   Level 5 must have at least three components. */
126674ff9ea8Soster 	if ((level == 0 && num_components < 2) ||
126774ff9ea8Soster 	    (level == 1 && num_components != 2) ||
126874ff9ea8Soster 	    (level == 5 && num_components < 3))
126974ff9ea8Soster 		usage();
127074ff9ea8Soster 
127174ff9ea8Soster 	/* build a config... */
127274ff9ea8Soster 
127374ff9ea8Soster 	memset(&cfg, 0, sizeof(cfg));
127474ff9ea8Soster 
127574ff9ea8Soster 	cfg.numCol = num_components;
127674ff9ea8Soster 	cfg.numSpare = 0;
127774ff9ea8Soster 
127874ff9ea8Soster 	for (i=0 ; i<num_components; i++) {
127974ff9ea8Soster 		strlcpy(cfg.devnames[0][i], components[i],
128074ff9ea8Soster 			sizeof(cfg.devnames[0][i]));
128174ff9ea8Soster 	}
128274ff9ea8Soster 
128374ff9ea8Soster 	/* pick some reasonable values for sectPerSU, etc. */
128474ff9ea8Soster 	if (level == 0) {
128574ff9ea8Soster 		if (num_components == 2) {
128674ff9ea8Soster 			/* 64 blocks (32K) per component - 64K data per stripe */
128774ff9ea8Soster 			cfg.sectPerSU = 64;
128874ff9ea8Soster 		} else if (num_components == 3 || num_components == 4) {
128974ff9ea8Soster 			/* 32 blocks (16K) per component - 64K data per strip for
129074ff9ea8Soster 			   the 4-component case. */
129174ff9ea8Soster 			cfg.sectPerSU = 32;
129274ff9ea8Soster 		} else {
129374ff9ea8Soster 			/* 16 blocks (8K) per component */
129474ff9ea8Soster 			cfg.sectPerSU = 16;
129574ff9ea8Soster 		}
129674ff9ea8Soster 	} else if (level == 1) {
1297a10c2cecSandvar 		/* 128 blocks (64K per component) - 64K per stripe */
129874ff9ea8Soster 		cfg.sectPerSU = 128;
129974ff9ea8Soster 	} else if (level == 5) {
130074ff9ea8Soster 		if (num_components == 3) {
130174ff9ea8Soster 			/* 64 blocks (32K) per disk - 64K data per stripe */
130274ff9ea8Soster 			cfg.sectPerSU = 64;
130374ff9ea8Soster 		} else if (num_components >= 4 && num_components < 9) {
130474ff9ea8Soster 			/* 4 components makes 3 data components.  No power of 2 is
130574ff9ea8Soster 			   evenly divisible by 3 so performance will be lousy
130674ff9ea8Soster 			   regardless of what number we choose here.  5 components is
130774ff9ea8Soster 			   what we are really hoping for here, as 5 components with 4
130874ff9ea8Soster 			   data components on RAID 5 means 32 blocks (16K) per data
130974ff9ea8Soster 			   component, or 64K per stripe */
131074ff9ea8Soster 			cfg.sectPerSU = 32;
131174ff9ea8Soster 		} else {
131274ff9ea8Soster 			/* 9 components here is optimal for 16 blocks (8K) per data
131374ff9ea8Soster 			   component */
131474ff9ea8Soster 			cfg.sectPerSU = 16;
131574ff9ea8Soster 		}
131674ff9ea8Soster 	} else
131774ff9ea8Soster 		usage();
131874ff9ea8Soster 
131974ff9ea8Soster 	cfg.SUsPerPU = 1;
132074ff9ea8Soster 	cfg.SUsPerRU = 1;
132174ff9ea8Soster 	cfg.parityConfig = '0' + level;
132274ff9ea8Soster 	strlcpy(cfg.diskQueueType, "fifo", sizeof(cfg.diskQueueType));
132374ff9ea8Soster 	cfg.maxOutstandingDiskReqs = 1;
132474ff9ea8Soster 	cfg.force = 1;
132574ff9ea8Soster 
132674ff9ea8Soster 	/* configure... */
132774ff9ea8Soster 
132874ff9ea8Soster 	generic = &cfg;
132974ff9ea8Soster 	do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE");
133074ff9ea8Soster 
133174ff9ea8Soster 	if (level == 1 || level == 5)
133274ff9ea8Soster 		do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
133374ff9ea8Soster 			 "RAIDFRAME_REWRITEPARITY");
133474ff9ea8Soster }
133574ff9ea8Soster 
133674ff9ea8Soster 
1337ae9b468dSoster static void
1338f0121f1fSxtraeme usage(void)
1339f675e35dSoster {
13408a986b2eScgd 	const char *progname = getprogname();
13418a986b2eScgd 
1342ee1e729eSkre 	fprintf(stderr,
134374ff9ea8Soster 		"usage: %s dev create [0 | 1 | mirror | 5] component component ...\n",
134474ff9ea8Soster 		progname);
134574ff9ea8Soster 	fprintf(stderr, "       %s [-v] -A [yes | no | softroot | hardroot] dev\n",
1346ee1e729eSkre 		progname);
1347704ad63cSwiz 	fprintf(stderr, "       %s [-v] -a component dev\n", progname);
13488a986b2eScgd 	fprintf(stderr, "       %s [-v] -B dev\n", progname);
13498a986b2eScgd 	fprintf(stderr, "       %s [-v] -C config_file dev\n", progname);
1350704ad63cSwiz 	fprintf(stderr, "       %s [-v] -c config_file dev\n", progname);
13518a986b2eScgd 	fprintf(stderr, "       %s [-v] -F component dev\n", progname);
1352704ad63cSwiz 	fprintf(stderr, "       %s [-v] -f component dev\n", progname);
1353364e3039Slukem 	fprintf(stderr, "       %s [-v] -G dev\n", progname);
1354704ad63cSwiz 	fprintf(stderr, "       %s [-v] -g component dev\n", progname);
13558a986b2eScgd 	fprintf(stderr, "       %s [-v] -I serial_number dev\n", progname);
1356704ad63cSwiz 	fprintf(stderr, "       %s [-v] -i dev\n", progname);
1357f1a1ad33Sjld 	fprintf(stderr, "       %s [-v] -M [yes | no | set params] dev\n",
1358f1a1ad33Sjld 	    progname);
1359704ad63cSwiz 	fprintf(stderr, "       %s [-v] -m dev\n", progname);
1360c1058540Soster 	fprintf(stderr, "       %s [-v] -P dev\n", progname);
1361704ad63cSwiz 	fprintf(stderr, "       %s [-v] -p dev\n", progname);
13628a986b2eScgd 	fprintf(stderr, "       %s [-v] -R component dev\n", progname);
1363704ad63cSwiz 	fprintf(stderr, "       %s [-v] -r component dev\n", progname);
13648a986b2eScgd 	fprintf(stderr, "       %s [-v] -S dev\n", progname);
1365704ad63cSwiz 	fprintf(stderr, "       %s [-v] -s dev\n", progname);
1366d73b978aSkre 	fprintf(stderr, "       %s [-v] -t config_file\n", progname);
1367704ad63cSwiz 	fprintf(stderr, "       %s [-v] -U unit dev\n", progname);
13688a986b2eScgd 	fprintf(stderr, "       %s [-v] -u dev\n", progname);
1369f675e35dSoster 	exit(1);
1370f675e35dSoster 	/* NOTREACHED */
1371f675e35dSoster }
137205c0668eSmanu 
137305c0668eSmanu static unsigned int
1374e304a25cSchristos xstrtouint(const char *str)
137505c0668eSmanu {
1376e304a25cSchristos 	int e;
1377e304a25cSchristos 	unsigned int num = (unsigned int)strtou(str, NULL, 10, 0, INT_MAX, &e);
1378e304a25cSchristos 	if (e)
1379e304a25cSchristos 		errc(EXIT_FAILURE, e, "Bad number `%s'", str);
1380e304a25cSchristos 	return num;
138105c0668eSmanu }
1382