1 /*- 2 * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to The NetBSD Foundation 6 * by Greg Oster 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the NetBSD 19 * Foundation, Inc. and its contributors. 20 * 4. Neither the name of The NetBSD Foundation nor the names of its 21 * contributors may be used to endorse or promote products derived 22 * from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 /* 38 39 This program is a re-write of the original rf_ctrl program 40 distributed by CMU with RAIDframe 1.1. 41 42 This program is the user-land interface to the RAIDframe kernel 43 driver in NetBSD. 44 45 */ 46 47 #include <sys/param.h> 48 #include <sys/ioctl.h> 49 #include <sys/stat.h> 50 #include <util.h> 51 #include <stdio.h> 52 #include <fcntl.h> 53 #include <ctype.h> 54 #include <err.h> 55 #include <errno.h> 56 #include <sys/types.h> 57 #include <string.h> 58 #include <sys/disklabel.h> 59 #include <machine/disklabel.h> 60 #include "rf_raidframe.h" 61 62 extern char *__progname; 63 64 int main __P((int, char *[])); 65 static void do_ioctl __P((int, unsigned long, void *, char *)); 66 static void rf_configure __P((int, char*)); 67 static char *device_status __P((RF_DiskStatus_t)); 68 static void rf_get_device_status __P((int)); 69 static void rf_fail_disk __P((int, char *, int)); 70 static void usage __P((void)); 71 72 int 73 main(argc,argv) 74 int argc; 75 char *argv[]; 76 { 77 extern char *optarg; 78 extern int optind; 79 int ch; 80 int num_options; 81 unsigned long action; 82 char config_filename[PATH_MAX]; 83 char dev_name[PATH_MAX]; 84 char name[PATH_MAX]; 85 char component_to_fail[PATH_MAX]; 86 int do_recon; 87 int raidID; 88 int rawpart; 89 int recon_percent_done; 90 struct stat st; 91 int fd; 92 93 num_options = 0; 94 action = 0; 95 do_recon = 0; 96 97 while ((ch = getopt(argc, argv, "c:Cf:F:rRsu")) != -1) 98 switch(ch) { 99 case 'c': 100 strncpy(config_filename,optarg,PATH_MAX); 101 action = RAIDFRAME_CONFIGURE; 102 num_options++; 103 break; 104 case 'C': 105 action = RAIDFRAME_COPYBACK; 106 num_options++; 107 break; 108 case 'f': 109 action = RAIDFRAME_FAIL_DISK; 110 do_recon = 0; 111 strncpy(component_to_fail, optarg, PATH_MAX); 112 num_options++; 113 break; 114 case 'F': 115 action = RAIDFRAME_FAIL_DISK; 116 do_recon = 1; 117 strncpy(component_to_fail, optarg, PATH_MAX); 118 num_options++; 119 break; 120 case 'r': 121 action = RAIDFRAME_REWRITEPARITY; 122 num_options++; 123 break; 124 case 'R': 125 action = RAIDFRAME_CHECKRECON; 126 num_options++; 127 break; 128 case 's': 129 action = RAIDFRAME_GET_INFO; 130 num_options++; 131 break; 132 case 'u': 133 action = RAIDFRAME_SHUTDOWN; 134 num_options++; 135 break; 136 default: 137 usage(); 138 } 139 argc -= optind; 140 argv += optind; 141 142 if ((num_options > 1) || (argc == NULL)) 143 usage(); 144 145 strncpy(name,argv[0],PATH_MAX); 146 147 if ((name[0] == '/') || (name[0] == '.')) { 148 /* they've (apparently) given a full path... */ 149 strncpy(dev_name, name, PATH_MAX); 150 } else { 151 if (isdigit(name[strlen(name)-1])) { 152 rawpart = getrawpartition(); 153 snprintf(dev_name,PATH_MAX,"/dev/%s%c",name, 154 'a'+rawpart); 155 } else { 156 snprintf(dev_name,PATH_MAX,"/dev/%s",name); 157 } 158 } 159 160 if (stat(dev_name, &st) != 0) { 161 fprintf(stderr,"%s: stat failure on: %s\n", 162 __progname,dev_name); 163 return (errno); 164 } 165 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) { 166 fprintf(stderr,"%s: invalid device: %s\n", 167 __progname,dev_name); 168 return (EINVAL); 169 } 170 171 raidID = RF_DEV2RAIDID(st.st_rdev); 172 173 if ((fd = open( dev_name, O_RDWR, 0640)) < 0) { 174 fprintf(stderr, "%s: unable to open device file: %s\n", 175 __progname, dev_name); 176 exit(1); 177 } 178 179 180 switch(action) { 181 case RAIDFRAME_CONFIGURE: 182 rf_configure(fd, config_filename); 183 break; 184 case RAIDFRAME_COPYBACK: 185 printf("Copyback.\n"); 186 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK"); 187 break; 188 case RAIDFRAME_FAIL_DISK: 189 rf_fail_disk(fd,component_to_fail,do_recon); 190 break; 191 case RAIDFRAME_REWRITEPARITY: 192 printf("Initiating re-write of parity\n"); 193 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL, 194 "RAIDFRAME_REWRITEPARITY"); 195 break; 196 case RAIDFRAME_CHECKRECON: 197 do_ioctl(fd, RAIDFRAME_CHECKRECON, &recon_percent_done, 198 "RAIDFRAME_CHECKRECON"); 199 printf("Reconstruction is %d%% complete.\n", 200 recon_percent_done); 201 break; 202 case RAIDFRAME_GET_INFO: 203 rf_get_device_status(fd); 204 break; 205 case RAIDFRAME_SHUTDOWN: 206 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN"); 207 break; 208 default: 209 break; 210 } 211 212 close(fd); 213 exit(0); 214 } 215 216 static void 217 do_ioctl(fd, command, arg, ioctl_name) 218 int fd; 219 unsigned long command; 220 void *arg; 221 char *ioctl_name; 222 { 223 if (ioctl(fd, command, arg) < 0) { 224 warn("ioctl (%s) failed", ioctl_name); 225 exit(1); 226 } 227 } 228 229 230 static void 231 rf_configure(fd,config_file) 232 int fd; 233 char *config_file; 234 { 235 void *generic; 236 RF_Config_t cfg; 237 238 if (rf_MakeConfig( config_file, &cfg ) < 0) { 239 fprintf(stderr,"%s: unable to create RAIDframe %s\n", 240 __progname, "configuration structure\n"); 241 exit(1); 242 } 243 244 /* 245 246 Note the extra level of redirection needed here, since 247 what we really want to pass in is a pointer to the pointer to 248 the configuration structure. 249 250 */ 251 252 generic = (void *) &cfg; 253 do_ioctl(fd,RAIDFRAME_CONFIGURE,&generic,"RAIDFRAME_CONFIGURE"); 254 #if 0 255 if (ioctl(fd, RAIDFRAME_CONFIGURE, &generic) < 0) { 256 warn("ioctl (RAIDFRAME_CONFIGURE): failed\n"); 257 exit(1); 258 } 259 #endif 260 } 261 262 static char * 263 device_status(status) 264 RF_DiskStatus_t status; 265 { 266 static char status_string[256]; 267 268 switch (status) { 269 case rf_ds_optimal: 270 strcpy(status_string,"optimal"); 271 break; 272 case rf_ds_failed: 273 strcpy(status_string,"failed"); 274 break; 275 case rf_ds_reconstructing: 276 strcpy(status_string,"reconstructing"); 277 break; 278 case rf_ds_dist_spared: 279 strcpy(status_string,"dist_spared"); 280 break; 281 case rf_ds_spared: 282 strcpy(status_string,"spared"); 283 break; 284 case rf_ds_spare: 285 strcpy(status_string,"spare"); 286 break; 287 case rf_ds_used_spare: 288 strcpy(status_string,"used_spare"); 289 break; 290 default: 291 strcpy(status_string,"UNKNOWN"); 292 break; 293 } 294 return(status_string); 295 } 296 297 static void 298 rf_get_device_status(fd) 299 int fd; 300 { 301 RF_DeviceConfig_t device_config; 302 void *cfg_ptr; 303 int i; 304 305 cfg_ptr = &device_config; 306 307 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO"); 308 309 printf("Components:\n"); 310 for(i=0; i < device_config.ndevs; i++) { 311 printf("%20s: %s\n", device_config.devs[i].devname, 312 device_status(device_config.devs[i].status)); 313 } 314 if (device_config.nspares > 0) { 315 printf("Spares:\n"); 316 for(i=0; i < device_config.nspares; i++) { 317 printf("%20s [%d][%d]: %s\n", 318 device_config.spares[i].devname, 319 device_config.spares[i].spareRow, 320 device_config.spares[i].spareCol, 321 device_status(device_config.spares[i].status)); 322 } 323 } else { 324 printf("No spares.\n"); 325 } 326 327 } 328 329 static void 330 rf_fail_disk(fd, component_to_fail, do_recon) 331 int fd; 332 char *component_to_fail; 333 int do_recon; 334 { 335 struct rf_recon_req recon_request; 336 RF_DeviceConfig_t device_config; 337 void *cfg_ptr; 338 int i; 339 int found; 340 int component_num; 341 342 component_num = -1; 343 344 /* Assuming a full path spec... */ 345 cfg_ptr = &device_config; 346 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, 347 "RAIDFRAME_GET_INFO"); 348 found = 0; 349 for(i=0; i < device_config.ndevs; i++) { 350 if (strncmp(component_to_fail, 351 device_config.devs[i].devname, 352 PATH_MAX)==0) { 353 found = 1; 354 component_num = i; 355 } 356 } 357 if (!found) { 358 fprintf(stderr,"%s: %s is not a component %s", 359 __progname, component_to_fail, 360 "of this device\n"); 361 exit(1); 362 } 363 364 recon_request.row = component_num / device_config.cols; 365 recon_request.col = component_num % device_config.cols; 366 if (do_recon) { 367 recon_request.flags = RF_FDFLAGS_RECON; 368 } else { 369 recon_request.flags = RF_FDFLAGS_NONE; 370 } 371 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request, 372 "RAIDFRAME_FAIL_DISK"); 373 374 } 375 376 static void 377 usage() 378 { 379 fprintf(stderr, "usage: %s -c config_file dev\n", __progname); 380 fprintf(stderr, " %s -C dev\n", __progname); 381 fprintf(stderr, " %s -f component dev\n", __progname); 382 fprintf(stderr, " %s -F component dev\n", __progname); 383 fprintf(stderr, " %s -r dev\n", __progname); 384 fprintf(stderr, " %s -R dev\n", __progname); 385 fprintf(stderr, " %s -s dev\n", __progname); 386 fprintf(stderr, " %s -u dev\n", __progname); 387 exit(1); 388 /* NOTREACHED */ 389 } 390