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