xref: /netbsd-src/sbin/raidctl/raidctl.c (revision bada23909e740596d0a3785a73bd3583a9807fb8)
1 /*      $NetBSD: raidctl.c,v 1.6 1999/03/02 03:13:59 oster Exp $   */
2 /*-
3  * Copyright (c) 1996, 1997, 1998 The NetBSD Foundation, Inc.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to The NetBSD Foundation
7  * by Greg Oster
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *        This product includes software developed by the NetBSD
20  *        Foundation, Inc. and its contributors.
21  * 4. Neither the name of The NetBSD Foundation nor the names of its
22  *    contributors may be used to endorse or promote products derived
23  *    from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35  * POSSIBILITY OF SUCH DAMAGE.
36  */
37 
38 /*
39 
40    This program is a re-write of the original rf_ctrl program
41    distributed by CMU with RAIDframe 1.1.
42 
43    This program is the user-land interface to the RAIDframe kernel
44    driver in NetBSD.
45 
46  */
47 
48 #include <sys/param.h>
49 #include <sys/ioctl.h>
50 #include <sys/stat.h>
51 #include <util.h>
52 #include <stdio.h>
53 #include <fcntl.h>
54 #include <ctype.h>
55 #include <err.h>
56 #include <errno.h>
57 #include <sys/types.h>
58 #include <string.h>
59 #include <sys/disklabel.h>
60 #include <machine/disklabel.h>
61 #include <stdlib.h>
62 #include <unistd.h>
63 
64 #include "rf_raidframe.h"
65 
66 extern  char *__progname;
67 
68 int     main __P((int, char *[]));
69 static  void do_ioctl __P((int, unsigned long, void *, char *));
70 static  void rf_configure __P((int, char*, int));
71 static  char *device_status __P((RF_DiskStatus_t));
72 static  void rf_get_device_status __P((int));
73 static  void get_component_number __P((int, char *, int *, int *));
74 static  void rf_fail_disk __P((int, char *, int));
75 static  void usage __P((void));
76 static  void get_component_label __P((int, char *));
77 static  void set_component_label __P((int, char *));
78 static  void init_component_labels __P((int, int));
79 static  void add_hot_spare __P((int, char *));
80 static  void remove_hot_spare __P((int, char *));
81 static  void rebuild_in_place __P((int, char *));
82 
83 int
84 main(argc,argv)
85 	int argc;
86 	char *argv[];
87 {
88 	extern char *optarg;
89 	extern int optind;
90 	int ch;
91 	int num_options;
92 	unsigned long action;
93 	char config_filename[PATH_MAX];
94 	char dev_name[PATH_MAX];
95 	char name[PATH_MAX];
96 	char component[PATH_MAX];
97 	int do_recon;
98 	int raidID;
99 	int rawpart;
100 	int recon_percent_done;
101 	int serial_number;
102 	struct stat st;
103 	int fd;
104 	int force;
105 
106 	num_options = 0;
107 	action = 0;
108 	do_recon = 0;
109 	force = 0;
110 
111 	while ((ch = getopt(argc, argv, "a:Bc:C:f:F:g:iI:l:r:R:sSu")) != -1)
112 		switch(ch) {
113 		case 'a':
114 			action = RAIDFRAME_ADD_HOT_SPARE;
115 			strncpy(component, optarg, PATH_MAX);
116 			num_options++;
117 			break;
118 		case 'B':
119 			action = RAIDFRAME_COPYBACK;
120 			num_options++;
121 			break;
122 		case 'c':
123 			action = RAIDFRAME_CONFIGURE;
124 			strncpy(config_filename,optarg,PATH_MAX);
125 			force = 0;
126 			num_options++;
127 			break;
128 		case 'C':
129 			strncpy(config_filename,optarg,PATH_MAX);
130 			action = RAIDFRAME_CONFIGURE;
131 			force = 1;
132 			num_options++;
133 			break;
134 		case 'f':
135 			action = RAIDFRAME_FAIL_DISK;
136 			strncpy(component, optarg, PATH_MAX);
137 			do_recon = 0;
138 			num_options++;
139 			break;
140 		case 'F':
141 			action = RAIDFRAME_FAIL_DISK;
142 			strncpy(component, optarg, PATH_MAX);
143 			do_recon = 1;
144 			num_options++;
145 			break;
146 		case 'g':
147 			action = RAIDFRAME_GET_COMPONENT_LABEL;
148 			strncpy(component, optarg, PATH_MAX);
149 			num_options++;
150 			break;
151 		case 'i':
152 			action = RAIDFRAME_REWRITEPARITY;
153 			num_options++;
154 			break;
155 		case 'I':
156 			action = RAIDFRAME_INIT_LABELS;
157 			serial_number = atoi(optarg);
158 			num_options++;
159 			break;
160 		case 'l':
161 			action = RAIDFRAME_SET_COMPONENT_LABEL;
162 			strncpy(component, optarg, PATH_MAX);
163 			num_options++;
164 			break;
165 		case 'r':
166 			action = RAIDFRAME_REMOVE_HOT_SPARE;
167 			strncpy(component, optarg, PATH_MAX);
168 			num_options++;
169 			break;
170 		case 'R':
171 			strncpy(component,optarg,PATH_MAX);
172 			action = RAIDFRAME_REBUILD_IN_PLACE;
173 			num_options++;
174 			break;
175 		case 's':
176 			action = RAIDFRAME_GET_INFO;
177 			num_options++;
178 			break;
179 		case 'S':
180 			action = RAIDFRAME_CHECKRECON;
181 			num_options++;
182 			break;
183 		case 'u':
184 			action = RAIDFRAME_SHUTDOWN;
185 			num_options++;
186 			break;
187 		default:
188 			usage();
189 		}
190 	argc -= optind;
191 	argv += optind;
192 
193 	if ((num_options > 1) || (argc == NULL))
194 		usage();
195 
196 	strncpy(name,argv[0],PATH_MAX);
197 
198 	if ((name[0] == '/') || (name[0] == '.')) {
199 		/* they've (apparently) given a full path... */
200 		strncpy(dev_name, name, PATH_MAX);
201 	} else {
202 		if (isdigit(name[strlen(name)-1])) {
203 			rawpart = getrawpartition();
204 			snprintf(dev_name,PATH_MAX,"/dev/%s%c",name,
205 				 'a'+rawpart);
206 		} else {
207 			snprintf(dev_name,PATH_MAX,"/dev/%s",name);
208 		}
209 	}
210 
211 	if (stat(dev_name, &st) != 0) {
212 		fprintf(stderr,"%s: stat failure on: %s\n",
213 			__progname,dev_name);
214 		return (errno);
215 	}
216 	if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
217 		fprintf(stderr,"%s: invalid device: %s\n",
218 			__progname,dev_name);
219 		return (EINVAL);
220 	}
221 
222 	raidID = RF_DEV2RAIDID(st.st_rdev);
223 
224 	if ((fd = open( dev_name, O_RDWR, 0640)) < 0) {
225 		fprintf(stderr, "%s: unable to open device file: %s\n",
226 			__progname, dev_name);
227 		exit(1);
228 	}
229 
230 
231 	switch(action) {
232 	case RAIDFRAME_ADD_HOT_SPARE:
233 		add_hot_spare(fd,component);
234 		break;
235 	case RAIDFRAME_REMOVE_HOT_SPARE:
236 		remove_hot_spare(fd,component);
237 		break;
238 	case RAIDFRAME_CONFIGURE:
239 		rf_configure(fd, config_filename,force);
240 		break;
241 	case RAIDFRAME_COPYBACK:
242 		printf("Copyback.\n");
243 		do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK");
244 		break;
245 	case RAIDFRAME_FAIL_DISK:
246 		rf_fail_disk(fd,component,do_recon);
247 		break;
248 	case RAIDFRAME_SET_COMPONENT_LABEL:
249 		set_component_label(fd,component);
250 		break;
251 	case RAIDFRAME_GET_COMPONENT_LABEL:
252 		get_component_label(fd,component);
253 		break;
254 	case RAIDFRAME_INIT_LABELS:
255 		init_component_labels(fd,serial_number);
256 		break;
257 	case RAIDFRAME_REWRITEPARITY:
258 		printf("Initiating re-write of parity\n");
259 		do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
260 			 "RAIDFRAME_REWRITEPARITY");
261 		break;
262 	case RAIDFRAME_CHECKRECON:
263 		do_ioctl(fd, RAIDFRAME_CHECKRECON, &recon_percent_done,
264 			 "RAIDFRAME_CHECKRECON");
265 		printf("Reconstruction is %d%% complete.\n",
266 		       recon_percent_done);
267 		break;
268 	case RAIDFRAME_GET_INFO:
269 		rf_get_device_status(fd);
270 		break;
271 	case RAIDFRAME_REBUILD_IN_PLACE:
272 		rebuild_in_place(fd,component);
273 		break;
274 	case RAIDFRAME_SHUTDOWN:
275 		do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
276 		break;
277 	default:
278 		break;
279 	}
280 
281 	close(fd);
282 	exit(0);
283 }
284 
285 static void
286 do_ioctl(fd, command, arg, ioctl_name)
287 	int fd;
288 	unsigned long command;
289 	void *arg;
290 	char *ioctl_name;
291 {
292 	if (ioctl(fd, command, arg) < 0) {
293 		warn("ioctl (%s) failed", ioctl_name);
294 		exit(1);
295 	}
296 }
297 
298 
299 static void
300 rf_configure(fd,config_file,force)
301 	int fd;
302 	char *config_file;
303 	int force;
304 {
305 	void *generic;
306 	RF_Config_t cfg;
307 
308 	if (rf_MakeConfig( config_file, &cfg ) < 0) {
309 		fprintf(stderr,"%s: unable to create RAIDframe %s\n",
310 			__progname, "configuration structure\n");
311 		exit(1);
312 	}
313 
314 	cfg.force = force;
315 
316 	/*
317 
318 	   Note the extra level of redirection needed here, since
319 	   what we really want to pass in is a pointer to the pointer to
320 	   the configuration structure.
321 
322 	 */
323 
324 	generic = (void *) &cfg;
325 	do_ioctl(fd, RAIDFRAME_CONFIGURE, &generic, "RAIDFRAME_CONFIGURE");
326 }
327 
328 static char *
329 device_status(status)
330 	RF_DiskStatus_t status;
331 {
332 	static char status_string[256];
333 
334 	switch (status) {
335 	case rf_ds_optimal:
336 		strcpy(status_string,"optimal");
337 		break;
338 	case rf_ds_failed:
339 		strcpy(status_string,"failed");
340 		break;
341 	case rf_ds_reconstructing:
342 		strcpy(status_string,"reconstructing");
343 		break;
344 	case rf_ds_dist_spared:
345 		strcpy(status_string,"dist_spared");
346 		break;
347 	case rf_ds_spared:
348 		strcpy(status_string,"spared");
349 		break;
350 	case rf_ds_spare:
351 		strcpy(status_string,"spare");
352 		break;
353 	case rf_ds_used_spare:
354 		strcpy(status_string,"used_spare");
355 		break;
356 	default:
357 		strcpy(status_string,"UNKNOWN");
358 		break;
359 	}
360 	return(status_string);
361 }
362 
363 static void
364 rf_get_device_status(fd)
365 	int fd;
366 {
367 	RF_DeviceConfig_t device_config;
368 	void *cfg_ptr;
369 	int i;
370 
371 	cfg_ptr = &device_config;
372 
373 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
374 
375 	printf("Components:\n");
376 	for(i=0; i < device_config.ndevs; i++) {
377 		printf("%20s: %s\n", device_config.devs[i].devname,
378 		       device_status(device_config.devs[i].status));
379 	}
380 	if (device_config.nspares > 0) {
381 		printf("Spares:\n");
382 		for(i=0; i < device_config.nspares; i++) {
383 			printf("%20s: %s\n",
384 			       device_config.spares[i].devname,
385 			       device_status(device_config.spares[i].status));
386 		}
387 	} else {
388 		printf("No spares.\n");
389 	}
390 }
391 
392 static void
393 get_component_number(fd, component_name, component_number, num_columns)
394 	int fd;
395 	char *component_name;
396 	int *component_number;
397 	int *num_columns;
398 {
399 	RF_DeviceConfig_t device_config;
400 	void *cfg_ptr;
401 	int i;
402 	int found;
403 
404 	*component_number = -1;
405 
406 	/* Assuming a full path spec... */
407 	cfg_ptr = &device_config;
408 	do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr,
409 		 "RAIDFRAME_GET_INFO");
410 
411 	*num_columns = device_config.cols;
412 
413 	found = 0;
414 	for(i=0; i < device_config.ndevs; i++) {
415 		if (strncmp(component_name, device_config.devs[i].devname,
416 			    PATH_MAX)==0) {
417 			found = 1;
418 			*component_number = i;
419 		}
420 	}
421 	if (!found) {
422 		fprintf(stderr,"%s: %s is not a component %s", __progname,
423 			component_name, "of this device\n");
424 		exit(1);
425 	}
426 }
427 
428 static void
429 rf_fail_disk(fd, component_to_fail, do_recon)
430 	int fd;
431 	char *component_to_fail;
432 	int do_recon;
433 {
434 	struct rf_recon_req recon_request;
435 	int component_num;
436 	int num_cols;
437 
438 	get_component_number(fd, component_to_fail, &component_num, &num_cols);
439 
440 	recon_request.row = component_num / num_cols;
441 	recon_request.col = component_num % num_cols;
442 	if (do_recon) {
443 		recon_request.flags = RF_FDFLAGS_RECON;
444 	} else {
445 		recon_request.flags = RF_FDFLAGS_NONE;
446 	}
447 	do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request,
448 		 "RAIDFRAME_FAIL_DISK");
449 }
450 
451 static void
452 get_component_label(fd, component)
453 	int fd;
454 	char *component;
455 {
456 	RF_ComponentLabel_t component_label;
457 	void *label_ptr;
458 	int component_num;
459 	int num_cols;
460 
461 	get_component_number(fd, component, &component_num, &num_cols);
462 
463 	memset( &component_label, 0, sizeof(RF_ComponentLabel_t));
464 	component_label.row = component_num / num_cols;
465 	component_label.column = component_num % num_cols;
466 
467 	label_ptr = &component_label;
468 	do_ioctl( fd, RAIDFRAME_GET_COMPONENT_LABEL, &label_ptr,
469 		  "RAIDFRAME_GET_COMPONENT_LABEL");
470 
471 	printf("Component label for %s:\n",component);
472 	printf("Version: %d\n",component_label.version);
473 	printf("Serial Number: %d\n",component_label.serial_number);
474 	printf("Mod counter: %d\n",component_label.mod_counter);
475 	printf("Row: %d\n", component_label.row);
476 	printf("Column: %d\n", component_label.column);
477 	printf("Num Rows: %d\n", component_label.num_rows);
478 	printf("Num Columns: %d\n", component_label.num_columns);
479 	printf("Clean: %d\n", component_label.clean);
480 	printf("Status: %s\n", device_status(component_label.status));
481 }
482 
483 static void
484 set_component_label(fd, component)
485 	int fd;
486 	char *component;
487 {
488 	RF_ComponentLabel_t component_label;
489 	int component_num;
490 	int num_cols;
491 
492 	get_component_number(fd, component, &component_num, &num_cols);
493 
494 	/* XXX This is currently here for testing, and future expandability */
495 
496 	component_label.version = 1;
497 	component_label.serial_number = 123456;
498 	component_label.mod_counter = 0;
499 	component_label.row = component_num / num_cols;
500 	component_label.column = component_num % num_cols;
501 	component_label.num_rows = 0;
502 	component_label.num_columns = 5;
503 	component_label.clean = 0;
504 	component_label.status = 1;
505 
506 	do_ioctl( fd, RAIDFRAME_SET_COMPONENT_LABEL, &component_label,
507 		  "RAIDFRAME_SET_COMPONENT_LABEL");
508 }
509 
510 
511 static void
512 init_component_labels(fd, serial_number)
513 	int fd;
514 	int serial_number;
515 {
516 	RF_ComponentLabel_t component_label;
517 
518 	component_label.version = 0;
519 	component_label.serial_number = serial_number;
520 	component_label.mod_counter = 0;
521 	component_label.row = 0;
522 	component_label.column = 0;
523 	component_label.num_rows = 0;
524 	component_label.num_columns = 0;
525 	component_label.clean = 0;
526 	component_label.status = 0;
527 
528 	do_ioctl( fd, RAIDFRAME_INIT_LABELS, &component_label,
529 		  "RAIDFRAME_SET_COMPONENT_LABEL");
530 }
531 
532 static void
533 add_hot_spare(fd, component)
534 	int fd;
535 	char *component;
536 {
537 	RF_SingleComponent_t hot_spare;
538 
539 	hot_spare.row = 0;
540 	hot_spare.column = 0;
541 	strncpy(hot_spare.component_name, component,
542 		sizeof(hot_spare.component_name));
543 
544 	do_ioctl( fd, RAIDFRAME_ADD_HOT_SPARE, &hot_spare,
545 		  "RAIDFRAME_ADD_HOT_SPARE");
546 }
547 
548 static void
549 remove_hot_spare(fd, component)
550 	int fd;
551 	char *component;
552 {
553 	RF_SingleComponent_t hot_spare;
554 	int component_num;
555 	int num_cols;
556 
557 	get_component_number(fd, component, &component_num, &num_cols);
558 
559 	hot_spare.row = component_num / num_cols;
560 	hot_spare.column = component_num % num_cols;
561 
562 	strncpy(hot_spare.component_name, component,
563 		sizeof(hot_spare.component_name));
564 
565 	do_ioctl( fd, RAIDFRAME_REMOVE_HOT_SPARE, &hot_spare,
566 		  "RAIDFRAME_REMOVE_HOT_SPARE");
567 }
568 
569 static void
570 rebuild_in_place( fd, component )
571 	int fd;
572 	char *component;
573 {
574 	RF_SingleComponent_t comp;
575 	int component_num;
576 	int num_cols;
577 
578 	get_component_number(fd, component, &component_num, &num_cols);
579 
580 	comp.row = 0;
581 	comp.column = component_num;
582 	strncpy(comp.component_name, component, sizeof(comp.component_name));
583 
584 	do_ioctl( fd, RAIDFRAME_REBUILD_IN_PLACE, &comp,
585 		  "RAIDFRAME_REBUILD_IN_PLACE");
586 }
587 
588 
589 static void
590 usage()
591 {
592 	fprintf(stderr, "usage: %s -a component dev\n", __progname);
593 	fprintf(stderr, "       %s -B dev\n", __progname);
594 	fprintf(stderr, "       %s -c config_file dev\n", __progname);
595 	fprintf(stderr, "       %s -C config_file dev\n", __progname);
596 	fprintf(stderr, "       %s -f component dev\n", __progname);
597 	fprintf(stderr, "       %s -F component dev\n", __progname);
598 	fprintf(stderr, "       %s -g component dev\n", __progname);
599 	fprintf(stderr, "       %s -i dev\n", __progname);
600 	fprintf(stderr, "       %s -I serial_number dev\n", __progname);
601 	fprintf(stderr, "       %s -r component dev\n", __progname);
602 	fprintf(stderr, "       %s -R component dev\n", __progname);
603 	fprintf(stderr, "       %s -s dev\n", __progname);
604 	fprintf(stderr, "       %s -S dev\n", __progname);
605 	fprintf(stderr, "       %s -u dev\n", __progname);
606 #if 0
607 	fprintf(stderr, "usage: %s %s\n", __progname,
608 		"-a | -f | -F | -g | -r | -R component dev");
609 	fprintf(stderr, "       %s -B | -i | -s | -S -u dev\n", __progname);
610 	fprintf(stderr, "       %s -c | -C config_file dev\n", __progname);
611 	fprintf(stderr, "       %s -I serial_number dev\n", __progname);
612 #endif
613 	exit(1);
614 	/* NOTREACHED */
615 }
616