xref: /netbsd-src/sbin/raidctl/raidctl.c (revision 7f21db1c0118155e0dd40b75182e30c589d9f63e)
1 /*      $NetBSD: raidctl.c,v 1.45 2010/01/27 18:34:02 christos Exp $   */
2 
3 /*-
4  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Greg Oster
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * This program is a re-write of the original rf_ctrl program
34  * distributed by CMU with RAIDframe 1.1.
35  *
36  * This program is the user-land interface to the RAIDframe kernel
37  * driver in NetBSD.
38  */
39 #include <sys/cdefs.h>
40 
41 #ifndef lint
42 __RCSID("$NetBSD: raidctl.c,v 1.45 2010/01/27 18:34:02 christos Exp $");
43 #endif
44 
45 
46 #include <sys/param.h>
47 #include <sys/ioctl.h>
48 #include <sys/stat.h>
49 #include <sys/disklabel.h>
50 
51 #include <ctype.h>
52 #include <err.h>
53 #include <errno.h>
54 #include <fcntl.h>
55 #include <stdio.h>
56 #include <stdlib.h>
57 #include <string.h>
58 #include <unistd.h>
59 #include <util.h>
60 
61 #include <rump/rump.h>
62 #include <rump/rump_syscalls.h>
63 
64 #include <dev/raidframe/raidframevar.h>
65 #include <dev/raidframe/raidframeio.h>
66 #include "rf_configure.h"
67 
68 void	do_ioctl(int, u_long, void *, const char *);
69 static  void rf_configure(int, char*, int);
70 static  const char *device_status(RF_DiskStatus_t);
71 static  void rf_get_device_status(int);
72 static	void rf_output_configuration(int, const char *);
73 static  void get_component_number(int, char *, int *, int *);
74 static  void rf_fail_disk(int, char *, int);
75 static  void usage(void);
76 static  void get_component_label(int, char *);
77 static  void set_component_label(int, char *);
78 static  void init_component_labels(int, int);
79 static  void set_autoconfig(int, int, char *);
80 static  void add_hot_spare(int, char *);
81 static  void remove_hot_spare(int, char *);
82 static  void rebuild_in_place(int, char *);
83 static  void check_status(int,int);
84 static  void check_parity(int,int, char *);
85 static  void do_meter(int, u_long);
86 static  void get_bar(char *, double, int);
87 static  void get_time_string(char *, int);
88 static  void rf_output_pmstat(int, int);
89 static  void rf_pm_configure(int, int, char *, int[]);
90 
91 int verbose;
92 
93 int
94 main(int argc,char *argv[])
95 {
96 	int ch, i;
97 	int num_options;
98 	unsigned long action;
99 	char config_filename[PATH_MAX];
100 	char dev_name[PATH_MAX];
101 	char name[PATH_MAX];
102 	char component[PATH_MAX];
103 	char autoconf[10];
104 	char *parityconf = NULL;
105 	int parityparams[3];
106 	int do_output;
107 	int do_recon;
108 	int do_rewrite;
109 	int is_clean;
110 	int raidID;
111 	int serial_number;
112 	struct stat st;
113 	int fd;
114 	int force;
115 	int openmode;
116 
117 	num_options = 0;
118 	action = 0;
119 	do_output = 0;
120 	do_recon = 0;
121 	do_rewrite = 0;
122 	is_clean = 0;
123 	serial_number = 0;
124 	force = 0;
125 	openmode = O_RDWR;	/* default to read/write */
126 
127 #ifdef RUMP_ACTION
128 	rump_init();
129 #endif
130 
131 	while ((ch = getopt(argc, argv, "a:A:Bc:C:f:F:g:GiI:l:mM:r:R:sSpPuv"))
132 	       != -1)
133 		switch(ch) {
134 		case 'a':
135 			action = RAIDFRAME_ADD_HOT_SPARE;
136 			strlcpy(component, optarg, sizeof(component));
137 			num_options++;
138 			break;
139 		case 'A':
140 			action = RAIDFRAME_SET_AUTOCONFIG;
141 			strlcpy(autoconf, optarg, sizeof(autoconf));
142 			num_options++;
143 			break;
144 		case 'B':
145 			action = RAIDFRAME_COPYBACK;
146 			num_options++;
147 			break;
148 		case 'c':
149 			action = RAIDFRAME_CONFIGURE;
150 			strlcpy(config_filename, optarg,
151 			    sizeof(config_filename));
152 			force = 0;
153 			num_options++;
154 			break;
155 		case 'C':
156 			strlcpy(config_filename, optarg,
157 			    sizeof(config_filename));
158 			action = RAIDFRAME_CONFIGURE;
159 			force = 1;
160 			num_options++;
161 			break;
162 		case 'f':
163 			action = RAIDFRAME_FAIL_DISK;
164 			strlcpy(component, optarg, sizeof(component));
165 			do_recon = 0;
166 			num_options++;
167 			break;
168 		case 'F':
169 			action = RAIDFRAME_FAIL_DISK;
170 			strlcpy(component, optarg, sizeof(component));
171 			do_recon = 1;
172 			num_options++;
173 			break;
174 		case 'g':
175 			action = RAIDFRAME_GET_COMPONENT_LABEL;
176 			strlcpy(component, optarg, sizeof(component));
177 			openmode = O_RDONLY;
178 			num_options++;
179 			break;
180 		case 'G':
181 			action = RAIDFRAME_GET_INFO;
182 			openmode = O_RDONLY;
183 			do_output = 1;
184 			num_options++;
185 			break;
186 		case 'i':
187 			action = RAIDFRAME_REWRITEPARITY;
188 			num_options++;
189 			break;
190 		case 'I':
191 			action = RAIDFRAME_INIT_LABELS;
192 			serial_number = atoi(optarg);
193 			num_options++;
194 			break;
195 		case 'm':
196 			action = RAIDFRAME_PARITYMAP_STATUS;
197 			openmode = O_RDONLY;
198 			num_options++;
199 			break;
200 		case 'M':
201 			action = RAIDFRAME_PARITYMAP_SET_DISABLE;
202 			parityconf = strdup(optarg);
203 			num_options++;
204 			/* XXXjld: should rf_pm_configure do the atoi()s? */
205 			i = 0;
206 			while (i < 3 && optind < argc &&
207 			    isdigit((int)argv[optind][0]))
208 				parityparams[i++] = atoi(argv[optind++]);
209 			while (i < 3)
210 				parityparams[i++] = 0;
211 			break;
212 		case 'l':
213 			action = RAIDFRAME_SET_COMPONENT_LABEL;
214 			strlcpy(component, optarg, sizeof(component));
215 			num_options++;
216 			break;
217 		case 'r':
218 			action = RAIDFRAME_REMOVE_HOT_SPARE;
219 			strlcpy(component, optarg, sizeof(component));
220 			num_options++;
221 			break;
222 		case 'R':
223 			strlcpy(component, optarg, sizeof(component));
224 			action = RAIDFRAME_REBUILD_IN_PLACE;
225 			num_options++;
226 			break;
227 		case 's':
228 			action = RAIDFRAME_GET_INFO;
229 			openmode = O_RDONLY;
230 			num_options++;
231 			break;
232 		case 'S':
233 			action = RAIDFRAME_CHECK_RECON_STATUS_EXT;
234 			openmode = O_RDONLY;
235 			num_options++;
236 			break;
237 		case 'p':
238 			action = RAIDFRAME_CHECK_PARITY;
239 			openmode = O_RDONLY;
240 			num_options++;
241 			break;
242 		case 'P':
243 			action = RAIDFRAME_CHECK_PARITY;
244 			do_rewrite = 1;
245 			num_options++;
246 			break;
247 		case 'u':
248 			action = RAIDFRAME_SHUTDOWN;
249 			num_options++;
250 			break;
251 		case 'v':
252 			verbose = 1;
253 			/* Don't bump num_options, as '-v' is not
254 			   an option like the others */
255 			/* num_options++; */
256 			break;
257 		default:
258 			usage();
259 		}
260 	argc -= optind;
261 	argv += optind;
262 
263 	if ((num_options > 1) || (argc == 0))
264 		usage();
265 
266 	strlcpy(name, argv[0], sizeof(name));
267 #ifdef RUMP_ACTION
268 	fd = opendisk1(name, openmode, dev_name, sizeof(dev_name), 0,
269 	    rump_sys_open);
270 #else
271 	fd = opendisk(name, openmode, dev_name, sizeof(dev_name), 0);
272 #endif
273 	if (fd == -1)
274 		err(1, "Unable to open device file: %s", name);
275 	if (fstat(fd, &st) == -1)
276 		err(1, "stat failure on: %s", dev_name);
277 	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
278 		err(1, "invalid device: %s", dev_name);
279 
280 	raidID = DISKUNIT(st.st_rdev);
281 
282 	switch(action) {
283 	case RAIDFRAME_ADD_HOT_SPARE:
284 		add_hot_spare(fd, component);
285 		break;
286 	case RAIDFRAME_REMOVE_HOT_SPARE:
287 		remove_hot_spare(fd, component);
288 		break;
289 	case RAIDFRAME_CONFIGURE:
290 		rf_configure(fd, config_filename, force);
291 		break;
292 	case RAIDFRAME_SET_AUTOCONFIG:
293 		set_autoconfig(fd, raidID, autoconf);
294 		break;
295 	case RAIDFRAME_COPYBACK:
296 		printf("Copyback.\n");
297 		do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK");
298 		if (verbose) {
299 			sleep(3); /* XXX give the copyback a chance to start */
300 			printf("Copyback status:\n");
301 			do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT);
302 		}
303 		break;
304 	case RAIDFRAME_FAIL_DISK:
305 		rf_fail_disk(fd, component, do_recon);
306 		break;
307 	case RAIDFRAME_SET_COMPONENT_LABEL:
308 		set_component_label(fd, component);
309 		break;
310 	case RAIDFRAME_GET_COMPONENT_LABEL:
311 		get_component_label(fd, component);
312 		break;
313 	case RAIDFRAME_INIT_LABELS:
314 		init_component_labels(fd, serial_number);
315 		break;
316 	case RAIDFRAME_REWRITEPARITY:
317 		printf("Initiating re-write of parity\n");
318 		do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
319 			 "RAIDFRAME_REWRITEPARITY");
320 		if (verbose) {
321 			sleep(3); /* XXX give it time to get started */
322 			printf("Parity Re-write status:\n");
323 			do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
324 		}
325 		break;
326 	case RAIDFRAME_CHECK_RECON_STATUS_EXT:
327 		check_status(fd,1);
328 		break;
329 	case RAIDFRAME_GET_INFO:
330 		if (do_output)
331 			rf_output_configuration(fd, dev_name);
332 		else
333 			rf_get_device_status(fd);
334 		break;
335 	case RAIDFRAME_PARITYMAP_STATUS:
336 		rf_output_pmstat(fd, raidID);
337 		break;
338 	case RAIDFRAME_PARITYMAP_SET_DISABLE:
339 		rf_pm_configure(fd, raidID, parityconf, parityparams);
340 		break;
341 	case RAIDFRAME_REBUILD_IN_PLACE:
342 		rebuild_in_place(fd, component);
343 		break;
344 	case RAIDFRAME_CHECK_PARITY:
345 		check_parity(fd, do_rewrite, dev_name);
346 		break;
347 	case RAIDFRAME_SHUTDOWN:
348 		do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
349 		break;
350 	default:
351 		break;
352 	}
353 
354 	close(fd);
355 	exit(0);
356 }
357 
358 void
359 do_ioctl(int fd, unsigned long command, void *arg, const char *ioctl_name)
360 {
361 	if (ioctl(fd, command, arg) == -1)
362 		err(1, "ioctl (%s) failed", ioctl_name);
363 }
364 
365 
366 static void
367 rf_configure(int fd, char *config_file, int force)
368 {
369 	void *generic;
370 	RF_Config_t cfg;
371 
372 	if (rf_MakeConfig( config_file, &cfg ) != 0)
373 		err(1, "Unable to create RAIDframe configuration structure");
374 
375 	cfg.force = force;
376 
377 	/*
378 	 * Note the extra level of redirection needed here, since
379 	 * what we really want to pass in is a pointer to the pointer to
380 	 * the configuration structure.
381 	 */
382 
383 	generic = &cfg;
384 	do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE");
385 }
386 
387 static const char *
388 device_status(RF_DiskStatus_t status)
389 {
390 
391 	switch (status) {
392 	case rf_ds_optimal:
393 		return ("optimal");
394 		break;
395 	case rf_ds_failed:
396 		return ("failed");
397 		break;
398 	case rf_ds_reconstructing:
399 		return ("reconstructing");
400 		break;
401 	case rf_ds_dist_spared:
402 		return ("dist_spared");
403 		break;
404 	case rf_ds_spared:
405 		return ("spared");
406 		break;
407 	case rf_ds_spare:
408 		return ("spare");
409 		break;
410 	case rf_ds_used_spare:
411 		return ("used_spare");
412 		break;
413 	default:
414 		return ("UNKNOWN");
415 	}
416 	/* NOTREACHED */
417 }
418 
419 static void
420 rf_get_device_status(int fd)
421 {
422 	RF_DeviceConfig_t device_config;
423 	void *cfg_ptr;
424 	int is_clean;
425 	int i;
426 
427 	cfg_ptr = &device_config;
428 
429 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
430 
431 	printf("Components:\n");
432 	for(i=0; i < device_config.ndevs; i++) {
433 		printf("%20s: %s\n", device_config.devs[i].devname,
434 		       device_status(device_config.devs[i].status));
435 	}
436 	if (device_config.nspares > 0) {
437 		printf("Spares:\n");
438 		for(i=0; i < device_config.nspares; i++) {
439 			printf("%20s: %s\n",
440 			       device_config.spares[i].devname,
441 			       device_status(device_config.spares[i].status));
442 		}
443 	} else {
444 		printf("No spares.\n");
445 	}
446 	for(i=0; i < device_config.ndevs; i++) {
447 		if (device_config.devs[i].status == rf_ds_optimal) {
448 			get_component_label(fd, device_config.devs[i].devname);
449 		} else {
450 			printf("%s status is: %s.  Skipping label.\n",
451 			       device_config.devs[i].devname,
452 			       device_status(device_config.devs[i].status));
453 		}
454 	}
455 
456 	if (device_config.nspares > 0) {
457 		for(i=0; i < device_config.nspares; i++) {
458 			if ((device_config.spares[i].status ==
459 			     rf_ds_optimal) ||
460 			    (device_config.spares[i].status ==
461 			     rf_ds_used_spare)) {
462 				get_component_label(fd,
463 					    device_config.spares[i].devname);
464 			} else {
465 				printf("%s status is: %s.  Skipping label.\n",
466 				       device_config.spares[i].devname,
467 				       device_status(device_config.spares[i].status));
468 			}
469 		}
470 	}
471 
472 	do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean,
473 		 "RAIDFRAME_CHECK_PARITY");
474 	if (is_clean) {
475 		printf("Parity status: clean\n");
476 	} else {
477 		printf("Parity status: DIRTY\n");
478 	}
479 	check_status(fd,0);
480 }
481 
482 static void
483 rf_output_pmstat(int fd, int raidID)
484 {
485 	char srs[7];
486 	int i, j, dr;
487 	int dis;
488 	struct rf_pmstat st;
489 
490 	do_ioctl(fd, RAIDFRAME_PARITYMAP_STATUS, &st,
491 	    "RAIDFRAME_PARITYMAP_STATUS");
492 	if (st.enabled) {
493 		if (0 > humanize_number(srs, 7, st.region_size * DEV_BSIZE,
494 			"B", HN_AUTOSCALE, HN_NOSPACE))
495 			strlcpy(srs, "???", 7);
496 
497 		printf("raid%d: parity map enabled with %u regions of %s\n",
498 		    raidID, st.params.regions, srs);
499 		printf("raid%d: regions marked clean after %d intervals of"
500 		    " %d.%03ds\n", raidID, st.params.cooldown,
501 		    st.params.tickms / 1000, st.params.tickms % 1000);
502 		printf("raid%d: write/sync/clean counters "
503 		    "%"PRIu64"/%"PRIu64"/%"PRIu64"\n", raidID,
504 		    st.ctrs.nwrite, st.ctrs.ncachesync, st.ctrs.nclearing);
505 
506 		dr = 0;
507 		for (i = 0; i < RF_PARITYMAP_NREG; i++)
508 			if (isset(st.dirty, i))
509 				dr++;
510 		printf("raid%d: %d dirty region%s\n", raidID, dr,
511 		    dr == 1 ? "" : "s");
512 
513 		if (verbose > 0) {
514 			for (i = 0; i < RF_PARITYMAP_NBYTE; i += 32) {
515 				printf("    ");
516 				for (j = i; j < RF_PARITYMAP_NBYTE
517 					 && j < i + 32; j++)
518 					printf("%x%x", st.dirty[j] & 15,
519 					    (st.dirty[j] >> 4) & 15);
520 				printf("\n");
521 			}
522 		}
523 	} else {
524 		printf("raid%d: parity map disabled\n", raidID);
525 	}
526 
527 	do_ioctl(fd, RAIDFRAME_PARITYMAP_GET_DISABLE, &dis,
528 	    "RAIDFRAME_PARITYMAP_GET_DISABLE");
529 	printf("raid%d: parity map will %s %sabled on next configure\n",
530 	    raidID, dis == st.enabled ? "be" : "remain", dis ? "dis" : "en");
531 }
532 
533 static void
534 rf_pm_configure(int fd, int raidID, char *parityconf, int parityparams[])
535 {
536 	int dis;
537 	struct rf_pmparams params;
538 
539 	if (strcasecmp(parityconf, "yes") == 0)
540 		dis = 0;
541 	else if (strcasecmp(parityconf, "no") == 0)
542 		dis = 1;
543 	else if (strcasecmp(parityconf, "set") == 0) {
544 		params.cooldown = parityparams[0];
545 		params.tickms = parityparams[1];
546 		params.regions = parityparams[2];
547 
548 		do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_PARAMS, &params,
549 		    "RAIDFRAME_PARITYMAP_SET_PARAMS");
550 
551 		if (params.cooldown != 0 || params.tickms != 0) {
552 			printf("raid%d: parity cleaned after", raidID);
553 			if (params.cooldown != 0)
554 				printf(" %d", params.cooldown);
555 			printf(" intervals");
556 			if (params.tickms != 0) {
557 				printf(" of %d.%03ds", params.tickms / 1000,
558 				    params.tickms % 1000);
559 			}
560 			printf("\n");
561 		}
562 		if (params.regions != 0)
563 			printf("raid%d: will use %d regions on next"
564 			    " configuration\n", raidID, params.regions);
565 
566 		return;
567 		/* XXX the control flow here could be prettier. */
568 	} else
569 		err(1, "`%s' is not a valid parity map command", parityconf);
570 
571 	do_ioctl(fd, RAIDFRAME_PARITYMAP_SET_DISABLE, &dis,
572 	    "RAIDFRAME_PARITYMAP_SET_DISABLE");
573 	printf("raid%d: parity map will be %sabled on next configure\n",
574 	    raidID, dis ? "dis" : "en");
575 }
576 
577 
578 static void
579 rf_output_configuration(int fd, const char *name)
580 {
581 	RF_DeviceConfig_t device_config;
582 	void *cfg_ptr;
583 	int i;
584 	RF_ComponentLabel_t component_label;
585 	void *label_ptr;
586 	int component_num;
587 	int num_cols;
588 
589 	cfg_ptr = &device_config;
590 
591 	printf("# raidctl config file for %s\n", name);
592 	printf("\n");
593 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
594 
595 	printf("START array\n");
596 	printf("# numRow numCol numSpare\n");
597 	printf("%d %d %d\n", device_config.rows, device_config.cols,
598 	    device_config.nspares);
599 	printf("\n");
600 
601 	printf("START disks\n");
602 	for(i=0; i < device_config.ndevs; i++)
603 		printf("%s\n", device_config.devs[i].devname);
604 	printf("\n");
605 
606 	if (device_config.nspares > 0) {
607 		printf("START spare\n");
608 		for(i=0; i < device_config.nspares; i++)
609 			printf("%s\n", device_config.spares[i].devname);
610 		printf("\n");
611 	}
612 
613 	for(i=0; i < device_config.ndevs; i++) {
614 		if (device_config.devs[i].status == rf_ds_optimal)
615 			break;
616 	}
617 	if (i == device_config.ndevs) {
618 		printf("# WARNING: no optimal components; using %s\n",
619 		    device_config.devs[0].devname);
620 		i = 0;
621 	}
622 	get_component_number(fd, device_config.devs[i].devname,
623 	    &component_num, &num_cols);
624 	memset(&component_label, 0, sizeof(RF_ComponentLabel_t));
625 	component_label.row = component_num / num_cols;
626 	component_label.column = component_num % num_cols;
627 	label_ptr = &component_label;
628 	do_ioctl(fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr,
629 		  "RAIDFRAME_GET_COMPONENT_LABEL");
630 
631 	printf("START layout\n");
632 	printf(
633 	    "# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_%c\n",
634 	    (char) component_label.parityConfig);
635 	printf("%d %d %d %c\n",
636 	    component_label.sectPerSU, component_label.SUsPerPU,
637 	    component_label.SUsPerRU, (char) component_label.parityConfig);
638 	printf("\n");
639 
640 	printf("START queue\n");
641 	printf("fifo %d\n", device_config.maxqdepth);
642 }
643 
644 static void
645 get_component_number(int fd, char *component_name, int *component_number,
646 		     int *num_columns)
647 {
648 	RF_DeviceConfig_t device_config;
649 	void *cfg_ptr;
650 	int i;
651 	int found;
652 
653 	*component_number = -1;
654 
655 	/* Assuming a full path spec... */
656 	cfg_ptr = &device_config;
657 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr,
658 		 "RAIDFRAME_GET_INFO");
659 
660 	*num_columns = device_config.cols;
661 
662 	found = 0;
663 	for(i=0; i < device_config.ndevs; i++) {
664 		if (strncmp(component_name, device_config.devs[i].devname,
665 			    PATH_MAX)==0) {
666 			found = 1;
667 			*component_number = i;
668 		}
669 	}
670 	if (!found) { /* maybe it's a spare? */
671 		for(i=0; i < device_config.nspares; i++) {
672 			if (strncmp(component_name,
673 				    device_config.spares[i].devname,
674 				    PATH_MAX)==0) {
675 				found = 1;
676 				*component_number = i + device_config.ndevs;
677 				/* the way spares are done should
678 				   really change... */
679 				*num_columns = device_config.cols +
680 					device_config.nspares;
681 			}
682 		}
683 	}
684 
685 	if (!found)
686 		err(1,"%s is not a component of this device", component_name);
687 }
688 
689 static void
690 rf_fail_disk(int fd, char *component_to_fail, int do_recon)
691 {
692 	struct rf_recon_req recon_request;
693 	int component_num;
694 	int num_cols;
695 
696 	get_component_number(fd, component_to_fail, &component_num, &num_cols);
697 
698 	recon_request.row = component_num / num_cols;
699 	recon_request.col = component_num % num_cols;
700 	if (do_recon) {
701 		recon_request.flags = RF_FDFLAGS_RECON;
702 	} else {
703 		recon_request.flags = RF_FDFLAGS_NONE;
704 	}
705 	do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request,
706 		 "RAIDFRAME_FAIL_DISK");
707 	if (do_recon && verbose) {
708 		printf("Reconstruction status:\n");
709 		sleep(3); /* XXX give reconstruction a chance to start */
710 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT);
711 	}
712 }
713 
714 static void
715 get_component_label(int fd, char *component)
716 {
717 	RF_ComponentLabel_t component_label;
718 	void *label_ptr;
719 	int component_num;
720 	int num_cols;
721 
722 	get_component_number(fd, component, &component_num, &num_cols);
723 
724 	memset( &component_label, 0, sizeof(RF_ComponentLabel_t));
725 	component_label.row = component_num / num_cols;
726 	component_label.column = component_num % num_cols;
727 
728 	label_ptr = &component_label;
729 	do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr,
730 		  "RAIDFRAME_GET_COMPONENT_LABEL");
731 
732 	printf("Component label for %s:\n",component);
733 
734 	printf("   Row: %d, Column: %d, Num Rows: %d, Num Columns: %d\n",
735 	       component_label.row, component_label.column,
736 	       component_label.num_rows, component_label.num_columns);
737 	printf("   Version: %d, Serial Number: %d, Mod Counter: %d\n",
738 	       component_label.version, component_label.serial_number,
739 	       component_label.mod_counter);
740 	printf("   Clean: %s, Status: %d\n",
741 	       component_label.clean ? "Yes" : "No",
742 	       component_label.status );
743 	printf("   sectPerSU: %d, SUsPerPU: %d, SUsPerRU: %d\n",
744 	       component_label.sectPerSU, component_label.SUsPerPU,
745 	       component_label.SUsPerRU);
746 	printf("   Queue size: %d, blocksize: %d, numBlocks: %u\n",
747 	       component_label.maxOutstanding, component_label.blockSize,
748 	       component_label.numBlocks);
749 	printf("   RAID Level: %c\n", (char) component_label.parityConfig);
750 	printf("   Autoconfig: %s\n",
751 	       component_label.autoconfigure ? "Yes" : "No" );
752 	printf("   Root partition: %s\n",
753 	       component_label.root_partition ? "Yes" : "No" );
754 	printf("   Last configured as: raid%d\n", component_label.last_unit );
755 }
756 
757 static void
758 set_component_label(int fd, char *component)
759 {
760 	RF_ComponentLabel_t component_label;
761 	int component_num;
762 	int num_cols;
763 
764 	get_component_number(fd, component, &component_num, &num_cols);
765 
766 	/* XXX This is currently here for testing, and future expandability */
767 
768 	component_label.version = 1;
769 	component_label.serial_number = 123456;
770 	component_label.mod_counter = 0;
771 	component_label.row = component_num / num_cols;
772 	component_label.column = component_num % num_cols;
773 	component_label.num_rows = 0;
774 	component_label.num_columns = 5;
775 	component_label.clean = 0;
776 	component_label.status = 1;
777 
778 	do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label,
779 		  "RAIDFRAME_SET_COMPONENT_LABEL");
780 }
781 
782 
783 static void
784 init_component_labels(int fd, int serial_number)
785 {
786 	RF_ComponentLabel_t component_label;
787 
788 	component_label.version = 0;
789 	component_label.serial_number = serial_number;
790 	component_label.mod_counter = 0;
791 	component_label.row = 0;
792 	component_label.column = 0;
793 	component_label.num_rows = 0;
794 	component_label.num_columns = 0;
795 	component_label.clean = 0;
796 	component_label.status = 0;
797 
798 	do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label,
799 		  "RAIDFRAME_SET_COMPONENT_LABEL");
800 }
801 
802 static void
803 set_autoconfig(int fd, int raidID, char *autoconf)
804 {
805 	int auto_config;
806 	int root_config;
807 
808 	auto_config = 0;
809 	root_config = 0;
810 
811 	if (strncasecmp(autoconf,"root", 4) == 0) {
812 		root_config = 1;
813 	}
814 
815 	if ((strncasecmp(autoconf,"yes", 3) == 0) ||
816 	    root_config == 1) {
817 		auto_config = 1;
818 	}
819 
820 	do_ioctl(fd, RAIDFRAME_SET_AUTOCONFIG, &auto_config,
821 		 "RAIDFRAME_SET_AUTOCONFIG");
822 
823 	do_ioctl(fd, RAIDFRAME_SET_ROOT, &root_config,
824 		 "RAIDFRAME_SET_ROOT");
825 
826 	printf("raid%d: Autoconfigure: %s\n", raidID,
827 	       auto_config ? "Yes" : "No");
828 
829 	if (root_config == 1) {
830 		printf("raid%d: Root: %s\n", raidID,
831 		       auto_config ? "Yes" : "No");
832 	}
833 }
834 
835 static void
836 add_hot_spare(int fd, char *component)
837 {
838 	RF_SingleComponent_t hot_spare;
839 
840 	hot_spare.row = 0;
841 	hot_spare.column = 0;
842 	strncpy(hot_spare.component_name, component,
843 		sizeof(hot_spare.component_name));
844 
845 	do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare,
846 		  "RAIDFRAME_ADD_HOT_SPARE");
847 }
848 
849 static void
850 remove_hot_spare(int fd, char *component)
851 {
852 	RF_SingleComponent_t hot_spare;
853 	int component_num;
854 	int num_cols;
855 
856 	get_component_number(fd, component, &component_num, &num_cols);
857 
858 	hot_spare.row = component_num / num_cols;
859 	hot_spare.column = component_num % num_cols;
860 
861 	strncpy(hot_spare.component_name, component,
862 		sizeof(hot_spare.component_name));
863 
864 	do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare,
865 		  "RAIDFRAME_REMOVE_HOT_SPARE");
866 }
867 
868 static void
869 rebuild_in_place(int fd, char *component)
870 {
871 	RF_SingleComponent_t comp;
872 	int component_num;
873 	int num_cols;
874 
875 	get_component_number(fd, component, &component_num, &num_cols);
876 
877 	comp.row = 0;
878 	comp.column = component_num;
879 	strncpy(comp.component_name, component, sizeof(comp.component_name));
880 
881 	do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp,
882 		  "RAIDFRAME_REBUILD_IN_PLACE");
883 
884 	if (verbose) {
885 		printf("Reconstruction status:\n");
886 		sleep(3); /* XXX give reconstruction a chance to start */
887 		do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT);
888 	}
889 
890 }
891 
892 static void
893 check_parity(int fd, int do_rewrite, char *dev_name)
894 {
895 	int is_clean;
896 	int percent_done;
897 
898 	is_clean = 0;
899 	percent_done = 0;
900 	do_ioctl(fd, RAIDFRAME_CHECK_PARITY, &is_clean,
901 		 "RAIDFRAME_CHECK_PARITY");
902 	if (is_clean) {
903 		printf("%s: Parity status: clean\n",dev_name);
904 	} else {
905 		printf("%s: Parity status: DIRTY\n",dev_name);
906 		if (do_rewrite) {
907 			printf("%s: Initiating re-write of parity\n",
908 			       dev_name);
909 			do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
910 				 "RAIDFRAME_REWRITEPARITY");
911 			sleep(3); /* XXX give it time to
912 				     get started. */
913 			if (verbose) {
914 				printf("Parity Re-write status:\n");
915 				do_meter(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
916 			} else {
917 				do_ioctl(fd,
918 					 RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
919 					 &percent_done,
920 					 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS"
921 					 );
922 				while( percent_done < 100 ) {
923 					sleep(3); /* wait a bit... */
924 					do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
925 						 &percent_done, "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
926 				}
927 
928 			}
929 			       printf("%s: Parity Re-write complete\n",
930 				      dev_name);
931 		} else {
932 			/* parity is wrong, and is not being fixed.
933 			   Exit w/ an error. */
934 			exit(1);
935 		}
936 	}
937 }
938 
939 
940 static void
941 check_status(int fd, int meter)
942 {
943 	int recon_percent_done = 0;
944 	int parity_percent_done = 0;
945 	int copyback_percent_done = 0;
946 
947 	do_ioctl(fd, RAIDFRAME_CHECK_RECON_STATUS, &recon_percent_done,
948 		 "RAIDFRAME_CHECK_RECON_STATUS");
949 	printf("Reconstruction is %d%% complete.\n", recon_percent_done);
950 	do_ioctl(fd, RAIDFRAME_CHECK_PARITYREWRITE_STATUS,
951 		 &parity_percent_done,
952 		 "RAIDFRAME_CHECK_PARITYREWRITE_STATUS");
953 	printf("Parity Re-write is %d%% complete.\n", parity_percent_done);
954 	do_ioctl(fd, RAIDFRAME_CHECK_COPYBACK_STATUS, &copyback_percent_done,
955 		 "RAIDFRAME_CHECK_COPYBACK_STATUS");
956 	printf("Copyback is %d%% complete.\n", copyback_percent_done);
957 
958 	if (meter) {
959 		/* These 3 should be mutually exclusive at this point */
960 		if (recon_percent_done < 100) {
961 			printf("Reconstruction status:\n");
962 			do_meter(fd,RAIDFRAME_CHECK_RECON_STATUS_EXT);
963 		} else if (parity_percent_done < 100) {
964 			printf("Parity Re-write status:\n");
965 			do_meter(fd,RAIDFRAME_CHECK_PARITYREWRITE_STATUS_EXT);
966 		} else if (copyback_percent_done < 100) {
967 			printf("Copyback status:\n");
968 			do_meter(fd,RAIDFRAME_CHECK_COPYBACK_STATUS_EXT);
969 		}
970 	}
971 }
972 
973 const char *tbits = "|/-\\";
974 
975 static void
976 do_meter(int fd, u_long option)
977 {
978 	int percent_done;
979 	RF_uint64 start_value;
980 	RF_ProgressInfo_t progressInfo;
981 	void *pInfoPtr;
982 	struct timeval start_time;
983 	struct timeval current_time;
984 	double elapsed;
985 	int elapsed_sec;
986 	int elapsed_usec;
987 	int simple_eta,last_eta;
988 	double rate;
989 	RF_uint64 amount;
990 	int tbit_value;
991 	char buffer[1024];
992 	char bar_buffer[1024];
993 	char eta_buffer[1024];
994 
995 	if (gettimeofday(&start_time,NULL) == -1)
996 		err(1, "gettimeofday failed!?!?");
997 	memset(&progressInfo, 0, sizeof(RF_ProgressInfo_t));
998 	pInfoPtr=&progressInfo;
999 
1000 	percent_done = 0;
1001 	do_ioctl(fd, option, &pInfoPtr, "");
1002 	start_value = progressInfo.completed;
1003 	current_time = start_time;
1004 	simple_eta = 0;
1005 	last_eta = 0;
1006 
1007 	tbit_value = 0;
1008 	while(progressInfo.completed < progressInfo.total) {
1009 
1010 		percent_done = (progressInfo.completed * 100) /
1011 			progressInfo.total;
1012 
1013 		get_bar(bar_buffer, percent_done, 40);
1014 
1015 		elapsed_sec = current_time.tv_sec - start_time.tv_sec;
1016 		elapsed_usec = current_time.tv_usec - start_time.tv_usec;
1017 		if (elapsed_usec < 0) {
1018 			elapsed_usec-=1000000;
1019 			elapsed_sec++;
1020 		}
1021 
1022 		elapsed = (double) elapsed_sec +
1023 			(double) elapsed_usec / 1000000.0;
1024 
1025 		amount = progressInfo.completed - start_value;
1026 
1027 		if (amount <= 0) { /* we don't do negatives (yet?) */
1028 			amount = 0;
1029 		}
1030 
1031 		if (elapsed == 0)
1032 			rate = 0.0;
1033 		else
1034 			rate = amount / elapsed;
1035 
1036 		if (rate > 0.0) {
1037 			simple_eta = (int) (((double)progressInfo.total -
1038 					     (double) progressInfo.completed)
1039 					    / rate);
1040 		} else {
1041 			simple_eta = -1;
1042 		}
1043 
1044 		if (simple_eta <=0) {
1045 			simple_eta = last_eta;
1046 		} else {
1047 			last_eta = simple_eta;
1048 		}
1049 
1050 		get_time_string(eta_buffer, simple_eta);
1051 
1052 		snprintf(buffer,1024,"\r%3d%% |%s| ETA: %s %c",
1053 			 percent_done,bar_buffer,eta_buffer,tbits[tbit_value]);
1054 
1055 		write(fileno(stdout),buffer,strlen(buffer));
1056 		fflush(stdout);
1057 
1058 		if (++tbit_value>3)
1059 			tbit_value = 0;
1060 
1061 		sleep(2);
1062 
1063 		if (gettimeofday(&current_time,NULL) == -1)
1064 			err(1, "gettimeofday failed!?!?");
1065 
1066 		do_ioctl( fd, option, &pInfoPtr, "");
1067 
1068 
1069 	}
1070 	printf("\n");
1071 }
1072 /* 40 '*''s per line, then 40 ' ''s line. */
1073 /* If you've got a screen wider than 160 characters, "tough" */
1074 
1075 #define STAR_MIDPOINT 4*40
1076 const char stars[] = "****************************************"
1077                      "****************************************"
1078                      "****************************************"
1079                      "****************************************"
1080                      "                                        "
1081                      "                                        "
1082                      "                                        "
1083                      "                                        "
1084                      "                                        ";
1085 
1086 static void
1087 get_bar(char *string, double percent, int max_strlen)
1088 {
1089 	int offset;
1090 
1091 	if (max_strlen > STAR_MIDPOINT) {
1092 		max_strlen = STAR_MIDPOINT;
1093 	}
1094 	offset = STAR_MIDPOINT -
1095 		(int)((percent * max_strlen)/ 100);
1096 	if (offset < 0)
1097 		offset = 0;
1098 	snprintf(string,max_strlen,"%s",&stars[offset]);
1099 }
1100 
1101 static void
1102 get_time_string(char *string, int simple_time)
1103 {
1104 	int minutes, seconds, hours;
1105 	char hours_buffer[5];
1106 	char minutes_buffer[5];
1107 	char seconds_buffer[5];
1108 
1109 	if (simple_time >= 0) {
1110 
1111 		minutes = (int) simple_time / 60;
1112 		seconds = ((int)simple_time - 60*minutes);
1113 		hours = minutes / 60;
1114 		minutes = minutes - 60*hours;
1115 
1116 		if (hours > 0) {
1117 			snprintf(hours_buffer,5,"%02d:",hours);
1118 		} else {
1119 			snprintf(hours_buffer,5,"   ");
1120 		}
1121 
1122 		snprintf(minutes_buffer,5,"%02d:",minutes);
1123 		snprintf(seconds_buffer,5,"%02d",seconds);
1124 		snprintf(string,1024,"%s%s%s",
1125 			 hours_buffer, minutes_buffer, seconds_buffer);
1126 	} else {
1127 		snprintf(string,1024,"   --:--");
1128 	}
1129 
1130 }
1131 
1132 static void
1133 usage(void)
1134 {
1135 	const char *progname = getprogname();
1136 
1137 	fprintf(stderr, "usage: %s [-v] -a component dev\n", progname);
1138 	fprintf(stderr, "       %s [-v] -A [yes | no | root] dev\n", progname);
1139 	fprintf(stderr, "       %s [-v] -B dev\n", progname);
1140 	fprintf(stderr, "       %s [-v] -c config_file dev\n", progname);
1141 	fprintf(stderr, "       %s [-v] -C config_file dev\n", progname);
1142 	fprintf(stderr, "       %s [-v] -f component dev\n", progname);
1143 	fprintf(stderr, "       %s [-v] -F component dev\n", progname);
1144 	fprintf(stderr, "       %s [-v] -g component dev\n", progname);
1145 	fprintf(stderr, "       %s [-v] -G dev\n", progname);
1146 	fprintf(stderr, "       %s [-v] -i dev\n", progname);
1147 	fprintf(stderr, "       %s [-v] -I serial_number dev\n", progname);
1148 	fprintf(stderr, "       %s [-v] -m dev\n", progname);
1149 	fprintf(stderr, "       %s [-v] -M [yes | no | set params] dev\n",
1150 	    progname);
1151 	fprintf(stderr, "       %s [-v] -p dev\n", progname);
1152 	fprintf(stderr, "       %s [-v] -P dev\n", progname);
1153 	fprintf(stderr, "       %s [-v] -r component dev\n", progname);
1154 	fprintf(stderr, "       %s [-v] -R component dev\n", progname);
1155 	fprintf(stderr, "       %s [-v] -s dev\n", progname);
1156 	fprintf(stderr, "       %s [-v] -S dev\n", progname);
1157 	fprintf(stderr, "       %s [-v] -u dev\n", progname);
1158 	exit(1);
1159 	/* NOTREACHED */
1160 }
1161