raidctl.c revision 1.3 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 <unistd.h>
61
62 #include "rf_raidframe.h"
63
64 extern char *__progname;
65
66 int main __P((int, char *[]));
67 static void do_ioctl __P((int, unsigned long, void *, char *));
68 static void rf_configure __P((int, char*));
69 static char *device_status __P((RF_DiskStatus_t));
70 static void rf_get_device_status __P((int));
71 static void rf_fail_disk __P((int, char *, int));
72 static void usage __P((void));
73
74 int
75 main(argc,argv)
76 int argc;
77 char *argv[];
78 {
79 extern char *optarg;
80 extern int optind;
81 int ch;
82 int num_options;
83 unsigned long action;
84 char config_filename[PATH_MAX];
85 char dev_name[PATH_MAX];
86 char name[PATH_MAX];
87 char component_to_fail[PATH_MAX];
88 int do_recon;
89 int raidID;
90 int rawpart;
91 int recon_percent_done;
92 struct stat st;
93 int fd;
94
95 num_options = 0;
96 action = 0;
97 do_recon = 0;
98
99 while ((ch = getopt(argc, argv, "c:Cf:F:rRsu")) != -1)
100 switch(ch) {
101 case 'c':
102 strncpy(config_filename,optarg,PATH_MAX);
103 action = RAIDFRAME_CONFIGURE;
104 num_options++;
105 break;
106 case 'C':
107 action = RAIDFRAME_COPYBACK;
108 num_options++;
109 break;
110 case 'f':
111 action = RAIDFRAME_FAIL_DISK;
112 do_recon = 0;
113 strncpy(component_to_fail, optarg, PATH_MAX);
114 num_options++;
115 break;
116 case 'F':
117 action = RAIDFRAME_FAIL_DISK;
118 do_recon = 1;
119 strncpy(component_to_fail, optarg, PATH_MAX);
120 num_options++;
121 break;
122 case 'r':
123 action = RAIDFRAME_REWRITEPARITY;
124 num_options++;
125 break;
126 case 'R':
127 action = RAIDFRAME_CHECKRECON;
128 num_options++;
129 break;
130 case 's':
131 action = RAIDFRAME_GET_INFO;
132 num_options++;
133 break;
134 case 'u':
135 action = RAIDFRAME_SHUTDOWN;
136 num_options++;
137 break;
138 default:
139 usage();
140 }
141 argc -= optind;
142 argv += optind;
143
144 if ((num_options > 1) || (argc == NULL))
145 usage();
146
147 strncpy(name,argv[0],PATH_MAX);
148
149 if ((name[0] == '/') || (name[0] == '.')) {
150 /* they've (apparently) given a full path... */
151 strncpy(dev_name, name, PATH_MAX);
152 } else {
153 if (isdigit(name[strlen(name)-1])) {
154 rawpart = getrawpartition();
155 snprintf(dev_name,PATH_MAX,"/dev/%s%c",name,
156 'a'+rawpart);
157 } else {
158 snprintf(dev_name,PATH_MAX,"/dev/%s",name);
159 }
160 }
161
162 if (stat(dev_name, &st) != 0) {
163 fprintf(stderr,"%s: stat failure on: %s\n",
164 __progname,dev_name);
165 return (errno);
166 }
167 if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
168 fprintf(stderr,"%s: invalid device: %s\n",
169 __progname,dev_name);
170 return (EINVAL);
171 }
172
173 raidID = RF_DEV2RAIDID(st.st_rdev);
174
175 if ((fd = open( dev_name, O_RDWR, 0640)) < 0) {
176 fprintf(stderr, "%s: unable to open device file: %s\n",
177 __progname, dev_name);
178 exit(1);
179 }
180
181
182 switch(action) {
183 case RAIDFRAME_CONFIGURE:
184 rf_configure(fd, config_filename);
185 break;
186 case RAIDFRAME_COPYBACK:
187 printf("Copyback.\n");
188 do_ioctl(fd, RAIDFRAME_COPYBACK, NULL, "RAIDFRAME_COPYBACK");
189 break;
190 case RAIDFRAME_FAIL_DISK:
191 rf_fail_disk(fd,component_to_fail,do_recon);
192 break;
193 case RAIDFRAME_REWRITEPARITY:
194 printf("Initiating re-write of parity\n");
195 do_ioctl(fd, RAIDFRAME_REWRITEPARITY, NULL,
196 "RAIDFRAME_REWRITEPARITY");
197 break;
198 case RAIDFRAME_CHECKRECON:
199 do_ioctl(fd, RAIDFRAME_CHECKRECON, &recon_percent_done,
200 "RAIDFRAME_CHECKRECON");
201 printf("Reconstruction is %d%% complete.\n",
202 recon_percent_done);
203 break;
204 case RAIDFRAME_GET_INFO:
205 rf_get_device_status(fd);
206 break;
207 case RAIDFRAME_SHUTDOWN:
208 do_ioctl(fd, RAIDFRAME_SHUTDOWN, NULL, "RAIDFRAME_SHUTDOWN");
209 break;
210 default:
211 break;
212 }
213
214 close(fd);
215 exit(0);
216 }
217
218 static void
219 do_ioctl(fd, command, arg, ioctl_name)
220 int fd;
221 unsigned long command;
222 void *arg;
223 char *ioctl_name;
224 {
225 if (ioctl(fd, command, arg) < 0) {
226 warn("ioctl (%s) failed", ioctl_name);
227 exit(1);
228 }
229 }
230
231
232 static void
233 rf_configure(fd,config_file)
234 int fd;
235 char *config_file;
236 {
237 void *generic;
238 RF_Config_t cfg;
239
240 if (rf_MakeConfig( config_file, &cfg ) < 0) {
241 fprintf(stderr,"%s: unable to create RAIDframe %s\n",
242 __progname, "configuration structure\n");
243 exit(1);
244 }
245
246 /*
247
248 Note the extra level of redirection needed here, since
249 what we really want to pass in is a pointer to the pointer to
250 the configuration structure.
251
252 */
253
254 generic = (void *) &cfg;
255 do_ioctl(fd,RAIDFRAME_CONFIGURE,&generic,"RAIDFRAME_CONFIGURE");
256 #if 0
257 if (ioctl(fd, RAIDFRAME_CONFIGURE, &generic) < 0) {
258 warn("ioctl (RAIDFRAME_CONFIGURE): failed\n");
259 exit(1);
260 }
261 #endif
262 }
263
264 static char *
265 device_status(status)
266 RF_DiskStatus_t status;
267 {
268 static char status_string[256];
269
270 switch (status) {
271 case rf_ds_optimal:
272 strcpy(status_string,"optimal");
273 break;
274 case rf_ds_failed:
275 strcpy(status_string,"failed");
276 break;
277 case rf_ds_reconstructing:
278 strcpy(status_string,"reconstructing");
279 break;
280 case rf_ds_dist_spared:
281 strcpy(status_string,"dist_spared");
282 break;
283 case rf_ds_spared:
284 strcpy(status_string,"spared");
285 break;
286 case rf_ds_spare:
287 strcpy(status_string,"spare");
288 break;
289 case rf_ds_used_spare:
290 strcpy(status_string,"used_spare");
291 break;
292 default:
293 strcpy(status_string,"UNKNOWN");
294 break;
295 }
296 return(status_string);
297 }
298
299 static void
300 rf_get_device_status(fd)
301 int fd;
302 {
303 RF_DeviceConfig_t device_config;
304 void *cfg_ptr;
305 int i;
306
307 cfg_ptr = &device_config;
308
309 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr, "RAIDFRAME_GET_INFO");
310
311 printf("Components:\n");
312 for(i=0; i < device_config.ndevs; i++) {
313 printf("%20s: %s\n", device_config.devs[i].devname,
314 device_status(device_config.devs[i].status));
315 }
316 if (device_config.nspares > 0) {
317 printf("Spares:\n");
318 for(i=0; i < device_config.nspares; i++) {
319 printf("%20s [%d][%d]: %s\n",
320 device_config.spares[i].devname,
321 device_config.spares[i].spareRow,
322 device_config.spares[i].spareCol,
323 device_status(device_config.spares[i].status));
324 }
325 } else {
326 printf("No spares.\n");
327 }
328
329 }
330
331 static void
332 rf_fail_disk(fd, component_to_fail, do_recon)
333 int fd;
334 char *component_to_fail;
335 int do_recon;
336 {
337 struct rf_recon_req recon_request;
338 RF_DeviceConfig_t device_config;
339 void *cfg_ptr;
340 int i;
341 int found;
342 int component_num;
343
344 component_num = -1;
345
346 /* Assuming a full path spec... */
347 cfg_ptr = &device_config;
348 do_ioctl(fd, RAIDFRAME_GET_INFO, &cfg_ptr,
349 "RAIDFRAME_GET_INFO");
350 found = 0;
351 for(i=0; i < device_config.ndevs; i++) {
352 if (strncmp(component_to_fail,
353 device_config.devs[i].devname,
354 PATH_MAX)==0) {
355 found = 1;
356 component_num = i;
357 }
358 }
359 if (!found) {
360 fprintf(stderr,"%s: %s is not a component %s",
361 __progname, component_to_fail,
362 "of this device\n");
363 exit(1);
364 }
365
366 recon_request.row = component_num / device_config.cols;
367 recon_request.col = component_num % device_config.cols;
368 if (do_recon) {
369 recon_request.flags = RF_FDFLAGS_RECON;
370 } else {
371 recon_request.flags = RF_FDFLAGS_NONE;
372 }
373 do_ioctl(fd, RAIDFRAME_FAIL_DISK, &recon_request,
374 "RAIDFRAME_FAIL_DISK");
375
376 }
377
378 static void
379 usage()
380 {
381 fprintf(stderr, "usage: %s -c config_file dev\n", __progname);
382 fprintf(stderr, " %s -C dev\n", __progname);
383 fprintf(stderr, " %s -f component dev\n", __progname);
384 fprintf(stderr, " %s -F component dev\n", __progname);
385 fprintf(stderr, " %s -r dev\n", __progname);
386 fprintf(stderr, " %s -R dev\n", __progname);
387 fprintf(stderr, " %s -s dev\n", __progname);
388 fprintf(stderr, " %s -u dev\n", __progname);
389 exit(1);
390 /* NOTREACHED */
391 }
392