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