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