raidctl.c revision 1.45 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, ¶ms,
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, ©back_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(¤t_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