bioctl.c revision 1.14 1 1.14 joerg /* $NetBSD: bioctl.c,v 1.14 2011/05/25 15:34:19 joerg Exp $ */
2 1.7 xtraeme /* $OpenBSD: bioctl.c,v 1.52 2007/03/20 15:26:06 jmc Exp $ */
3 1.1 bouyer
4 1.1 bouyer /*
5 1.7 xtraeme * Copyright (c) 2007, 2008 Juan Romero Pardines
6 1.1 bouyer * Copyright (c) 2004, 2005 Marco Peereboom
7 1.1 bouyer * All rights reserved.
8 1.1 bouyer *
9 1.1 bouyer * Redistribution and use in source and binary forms, with or without
10 1.1 bouyer * modification, are permitted provided that the following conditions
11 1.1 bouyer * are met:
12 1.1 bouyer * 1. Redistributions of source code must retain the above copyright
13 1.1 bouyer * notice, this list of conditions and the following disclaimer.
14 1.1 bouyer * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 bouyer * notice, this list of conditions and the following disclaimer in the
16 1.1 bouyer * documentation and/or other materials provided with the distribution.
17 1.1 bouyer *
18 1.1 bouyer * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
19 1.1 bouyer * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 1.1 bouyer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 1.1 bouyer * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR
22 1.1 bouyer * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 1.1 bouyer * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24 1.1 bouyer * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25 1.1 bouyer * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26 1.1 bouyer * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27 1.1 bouyer * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 1.1 bouyer * SUCH DAMAGE.
29 1.1 bouyer *
30 1.1 bouyer */
31 1.1 bouyer #include <sys/cdefs.h>
32 1.1 bouyer
33 1.1 bouyer #ifndef lint
34 1.14 joerg __RCSID("$NetBSD: bioctl.c,v 1.14 2011/05/25 15:34:19 joerg Exp $");
35 1.1 bouyer #endif
36 1.1 bouyer
37 1.7 xtraeme #include <sys/types.h>
38 1.1 bouyer #include <sys/ioctl.h>
39 1.1 bouyer #include <sys/param.h>
40 1.1 bouyer #include <sys/queue.h>
41 1.1 bouyer #include <dev/biovar.h>
42 1.1 bouyer
43 1.1 bouyer #include <errno.h>
44 1.1 bouyer #include <err.h>
45 1.1 bouyer #include <fcntl.h>
46 1.1 bouyer #include <util.h>
47 1.7 xtraeme #include <stdbool.h>
48 1.1 bouyer #include <stdio.h>
49 1.1 bouyer #include <stdlib.h>
50 1.1 bouyer #include <string.h>
51 1.1 bouyer #include <unistd.h>
52 1.1 bouyer #include <ctype.h>
53 1.1 bouyer #include <util.h>
54 1.1 bouyer #include "strtonum.h"
55 1.1 bouyer
56 1.7 xtraeme struct command {
57 1.7 xtraeme const char *cmd_name;
58 1.7 xtraeme const char *arg_names;
59 1.7 xtraeme void (*cmd_func)(int, int, char **);
60 1.7 xtraeme };
61 1.7 xtraeme
62 1.7 xtraeme struct biotmp {
63 1.7 xtraeme struct bioc_inq *bi;
64 1.7 xtraeme struct bioc_vol *bv;
65 1.7 xtraeme char volname[64];
66 1.7 xtraeme int fd;
67 1.7 xtraeme int volid;
68 1.7 xtraeme int diskid;
69 1.7 xtraeme bool format;
70 1.7 xtraeme bool show_disknovol;
71 1.7 xtraeme };
72 1.7 xtraeme
73 1.1 bouyer struct locator {
74 1.1 bouyer int channel;
75 1.1 bouyer int target;
76 1.1 bouyer int lun;
77 1.1 bouyer };
78 1.1 bouyer
79 1.7 xtraeme static void usage(void);
80 1.7 xtraeme static void bio_alarm(int, int, char **);
81 1.7 xtraeme static void bio_show_common(int, int, char **);
82 1.7 xtraeme static int bio_show_volumes(struct biotmp *);
83 1.7 xtraeme static void bio_show_disks(struct biotmp *);
84 1.7 xtraeme static void bio_setblink(int, int, char **);
85 1.7 xtraeme static void bio_blink(int, char *, int, int);
86 1.7 xtraeme static void bio_setstate_hotspare(int, int, char **);
87 1.7 xtraeme static void bio_setstate_passthru(int, int, char **);
88 1.7 xtraeme static void bio_setstate_common(int, char *, struct bioc_setstate *,
89 1.7 xtraeme struct locator *);
90 1.7 xtraeme static void bio_setstate_consistency(int, int, char **);
91 1.7 xtraeme static void bio_volops_create(int, int, char **);
92 1.7 xtraeme #ifdef notyet
93 1.7 xtraeme static void bio_volops_modify(int, int, char **);
94 1.7 xtraeme #endif
95 1.7 xtraeme static void bio_volops_remove(int, int, char **);
96 1.7 xtraeme
97 1.2 xtraeme static const char *str2locator(const char *, struct locator *);
98 1.1 bouyer
99 1.7 xtraeme static struct bio_locate bl;
100 1.7 xtraeme static struct command commands[] = {
101 1.7 xtraeme {
102 1.7 xtraeme "show",
103 1.7 xtraeme "[disks] | [volumes]",
104 1.7 xtraeme bio_show_common },
105 1.7 xtraeme {
106 1.7 xtraeme "alarm",
107 1.7 xtraeme "[enable] | [disable] | [silence] | [test]",
108 1.7 xtraeme bio_alarm },
109 1.7 xtraeme {
110 1.7 xtraeme "blink",
111 1.11 xtraeme "start [channel:target[.lun]] | stop [channel:target[.lun]]",
112 1.7 xtraeme bio_setblink },
113 1.7 xtraeme {
114 1.7 xtraeme "hotspare",
115 1.11 xtraeme "add channel:target.lun | remove channel:target.lun",
116 1.7 xtraeme bio_setstate_hotspare },
117 1.7 xtraeme {
118 1.7 xtraeme "passthru",
119 1.11 xtraeme "add DISKID channel:target.lun | remove channel:target.lun",
120 1.7 xtraeme bio_setstate_passthru },
121 1.7 xtraeme {
122 1.7 xtraeme "check",
123 1.11 xtraeme "start VOLID | stop VOLID",
124 1.7 xtraeme bio_setstate_consistency },
125 1.7 xtraeme {
126 1.7 xtraeme "create",
127 1.7 xtraeme "volume VOLID DISKIDs [SIZE] STRIPE RAID_LEVEL channel:target.lun",
128 1.7 xtraeme bio_volops_create },
129 1.7 xtraeme #ifdef notyet
130 1.7 xtraeme {
131 1.7 xtraeme "modify",
132 1.7 xtraeme "volume VOLID STRIPE RAID_LEVEL channel:target.lun",
133 1.7 xtraeme bio_volops_modify },
134 1.7 xtraeme #endif
135 1.7 xtraeme {
136 1.7 xtraeme "remove",
137 1.7 xtraeme "volume VOLID channel:target.lun",
138 1.7 xtraeme bio_volops_remove },
139 1.2 xtraeme
140 1.7 xtraeme { NULL, NULL, NULL }
141 1.7 xtraeme };
142 1.1 bouyer
143 1.1 bouyer int
144 1.7 xtraeme main(int argc, char **argv)
145 1.1 bouyer {
146 1.7 xtraeme char *dvname;
147 1.7 xtraeme const char *cmdname;
148 1.7 xtraeme int fd = 0, i;
149 1.1 bouyer
150 1.7 xtraeme /* Must have at least: device command */
151 1.7 xtraeme if (argc < 3)
152 1.1 bouyer usage();
153 1.1 bouyer
154 1.7 xtraeme /* Skip program name, get and skip device name and command */
155 1.2 xtraeme setprogname(*argv);
156 1.7 xtraeme dvname = argv[1];
157 1.7 xtraeme cmdname = argv[2];
158 1.7 xtraeme argv += 3;
159 1.7 xtraeme argc -= 3;
160 1.7 xtraeme
161 1.7 xtraeme /* Look up and call the command */
162 1.7 xtraeme for (i = 0; commands[i].cmd_name != NULL; i++)
163 1.7 xtraeme if (strcmp(cmdname, commands[i].cmd_name) == 0)
164 1.7 xtraeme break;
165 1.7 xtraeme if (commands[i].cmd_name == NULL)
166 1.7 xtraeme errx(EXIT_FAILURE, "unknown command: %s", cmdname);
167 1.7 xtraeme
168 1.7 xtraeme /* Locate the device by issuing the BIOCLOCATE ioctl */
169 1.7 xtraeme fd = open("/dev/bio", O_RDWR);
170 1.7 xtraeme if (fd == -1)
171 1.7 xtraeme err(EXIT_FAILURE, "Can't open /dev/bio");
172 1.7 xtraeme
173 1.7 xtraeme bl.bl_name = dvname;
174 1.7 xtraeme if (ioctl(fd, BIOCLOCATE, &bl) == -1)
175 1.7 xtraeme errx(EXIT_FAILURE, "Can't locate %s device via /dev/bio",
176 1.7 xtraeme bl.bl_name);
177 1.2 xtraeme
178 1.7 xtraeme /* and execute the command */
179 1.7 xtraeme (*commands[i].cmd_func)(fd, argc, argv);
180 1.1 bouyer
181 1.7 xtraeme (void)close(fd);
182 1.2 xtraeme exit(EXIT_SUCCESS);
183 1.1 bouyer }
184 1.1 bouyer
185 1.2 xtraeme static void
186 1.1 bouyer usage(void)
187 1.1 bouyer {
188 1.7 xtraeme int i;
189 1.7 xtraeme
190 1.7 xtraeme (void)fprintf(stderr, "usage: %s device command [arg [...]]\n",
191 1.7 xtraeme getprogname());
192 1.7 xtraeme
193 1.7 xtraeme (void)fprintf(stderr, "Available commands:\n");
194 1.7 xtraeme for (i = 0; commands[i].cmd_name != NULL; i++)
195 1.7 xtraeme (void)fprintf(stderr, " %s %s\n", commands[i].cmd_name,
196 1.7 xtraeme commands[i].arg_names);
197 1.7 xtraeme
198 1.2 xtraeme exit(EXIT_FAILURE);
199 1.2 xtraeme /* NOTREACHED */
200 1.1 bouyer }
201 1.1 bouyer
202 1.2 xtraeme static const char *
203 1.1 bouyer str2locator(const char *string, struct locator *location)
204 1.1 bouyer {
205 1.7 xtraeme const char *errstr;
206 1.7 xtraeme char parse[80], *targ, *lun;
207 1.1 bouyer
208 1.1 bouyer strlcpy(parse, string, sizeof parse);
209 1.1 bouyer targ = strchr(parse, ':');
210 1.1 bouyer if (targ == NULL)
211 1.7 xtraeme return "target not specified";
212 1.7 xtraeme
213 1.1 bouyer *targ++ = '\0';
214 1.1 bouyer lun = strchr(targ, '.');
215 1.1 bouyer if (lun != NULL) {
216 1.1 bouyer *lun++ = '\0';
217 1.1 bouyer location->lun = strtonum(lun, 0, 256, &errstr);
218 1.1 bouyer if (errstr)
219 1.2 xtraeme return errstr;
220 1.1 bouyer } else
221 1.1 bouyer location->lun = 0;
222 1.1 bouyer
223 1.1 bouyer location->target = strtonum(targ, 0, 256, &errstr);
224 1.1 bouyer if (errstr)
225 1.2 xtraeme return errstr;
226 1.1 bouyer location->channel = strtonum(parse, 0, 256, &errstr);
227 1.1 bouyer if (errstr)
228 1.2 xtraeme return errstr;
229 1.2 xtraeme return NULL;
230 1.1 bouyer }
231 1.1 bouyer
232 1.7 xtraeme /*
233 1.7 xtraeme * Shows info about available RAID volumes.
234 1.7 xtraeme */
235 1.7 xtraeme static int
236 1.7 xtraeme bio_show_volumes(struct biotmp *bt)
237 1.7 xtraeme {
238 1.7 xtraeme struct bioc_vol bv;
239 1.10 xtraeme const char *status, *rtypestr, *stripestr;
240 1.7 xtraeme char size[64], percent[16], seconds[20];
241 1.7 xtraeme char rtype[16], stripe[16], tmp[32];
242 1.7 xtraeme
243 1.10 xtraeme rtypestr = stripestr = NULL;
244 1.10 xtraeme
245 1.7 xtraeme memset(&bv, 0, sizeof(bv));
246 1.7 xtraeme bv.bv_cookie = bl.bl_cookie;
247 1.7 xtraeme bv.bv_volid = bt->volid;
248 1.7 xtraeme bv.bv_percent = -1;
249 1.7 xtraeme bv.bv_seconds = -1;
250 1.7 xtraeme
251 1.7 xtraeme if (ioctl(bt->fd, BIOCVOL, &bv) == -1)
252 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOL");
253 1.7 xtraeme
254 1.7 xtraeme percent[0] = '\0';
255 1.7 xtraeme seconds[0] = '\0';
256 1.7 xtraeme if (bv.bv_percent != -1)
257 1.7 xtraeme snprintf(percent, sizeof(percent),
258 1.7 xtraeme " %3.2f%% done", bv.bv_percent / 10.0);
259 1.7 xtraeme if (bv.bv_seconds)
260 1.7 xtraeme snprintf(seconds, sizeof(seconds),
261 1.7 xtraeme " %u seconds", bv.bv_seconds);
262 1.7 xtraeme
263 1.7 xtraeme switch (bv.bv_status) {
264 1.7 xtraeme case BIOC_SVONLINE:
265 1.7 xtraeme status = BIOC_SVONLINE_S;
266 1.7 xtraeme break;
267 1.7 xtraeme case BIOC_SVOFFLINE:
268 1.7 xtraeme status = BIOC_SVOFFLINE_S;
269 1.7 xtraeme break;
270 1.7 xtraeme case BIOC_SVDEGRADED:
271 1.7 xtraeme status = BIOC_SVDEGRADED_S;
272 1.7 xtraeme break;
273 1.7 xtraeme case BIOC_SVBUILDING:
274 1.7 xtraeme status = BIOC_SVBUILDING_S;
275 1.7 xtraeme break;
276 1.7 xtraeme case BIOC_SVREBUILD:
277 1.7 xtraeme status = BIOC_SVREBUILD_S;
278 1.7 xtraeme break;
279 1.7 xtraeme case BIOC_SVMIGRATING:
280 1.7 xtraeme status = BIOC_SVMIGRATING_S;
281 1.7 xtraeme break;
282 1.7 xtraeme case BIOC_SVSCRUB:
283 1.7 xtraeme status = BIOC_SVSCRUB_S;
284 1.7 xtraeme break;
285 1.7 xtraeme case BIOC_SVCHECKING:
286 1.7 xtraeme status = BIOC_SVCHECKING_S;
287 1.7 xtraeme break;
288 1.7 xtraeme case BIOC_SVINVALID:
289 1.7 xtraeme default:
290 1.7 xtraeme status = BIOC_SVINVALID_S;
291 1.7 xtraeme break;
292 1.7 xtraeme }
293 1.7 xtraeme
294 1.7 xtraeme snprintf(bt->volname, sizeof(bt->volname), "%u", bv.bv_volid);
295 1.7 xtraeme if (bv.bv_vendor)
296 1.7 xtraeme snprintf(tmp, sizeof(tmp), "%s %s", bv.bv_dev, bv.bv_vendor);
297 1.7 xtraeme else
298 1.7 xtraeme snprintf(tmp, sizeof(tmp), "%s", bv.bv_dev);
299 1.7 xtraeme
300 1.7 xtraeme switch (bv.bv_level) {
301 1.7 xtraeme case BIOC_SVOL_HOTSPARE:
302 1.10 xtraeme rtypestr = "Hot spare";
303 1.10 xtraeme stripestr = "N/A";
304 1.7 xtraeme break;
305 1.7 xtraeme case BIOC_SVOL_PASSTHRU:
306 1.10 xtraeme rtypestr = "Pass through";
307 1.10 xtraeme stripestr = "N/A";
308 1.10 xtraeme break;
309 1.10 xtraeme case BIOC_SVOL_RAID01:
310 1.10 xtraeme rtypestr = "RAID 0+1";
311 1.10 xtraeme break;
312 1.10 xtraeme case BIOC_SVOL_RAID10:
313 1.10 xtraeme rtypestr = "RAID 1+0";
314 1.7 xtraeme break;
315 1.7 xtraeme default:
316 1.7 xtraeme snprintf(rtype, sizeof(rtype), "RAID %u", bv.bv_level);
317 1.9 xtraeme if (bv.bv_level == 1 || bv.bv_stripe_size == 0)
318 1.10 xtraeme stripestr = "N/A";
319 1.7 xtraeme break;
320 1.7 xtraeme }
321 1.7 xtraeme
322 1.10 xtraeme if (rtypestr)
323 1.14 joerg strlcpy(rtype, rtypestr, sizeof(rtype));
324 1.10 xtraeme if (stripestr)
325 1.14 joerg strlcpy(stripe, stripestr, sizeof(stripe));
326 1.10 xtraeme else
327 1.10 xtraeme snprintf(stripe, sizeof(stripe), "%uK", bv.bv_stripe_size);
328 1.10 xtraeme
329 1.7 xtraeme humanize_number(size, 5, (int64_t)bv.bv_size, "", HN_AUTOSCALE,
330 1.7 xtraeme HN_B | HN_NOSPACE | HN_DECIMAL);
331 1.7 xtraeme
332 1.9 xtraeme printf("%6s %-12s %4s %20s %8s %6s %s%s\n",
333 1.7 xtraeme bt->volname, status, size, tmp,
334 1.7 xtraeme rtype, stripe, percent, seconds);
335 1.7 xtraeme
336 1.7 xtraeme bt->bv = &bv;
337 1.7 xtraeme
338 1.7 xtraeme return bv.bv_nodisk;
339 1.7 xtraeme }
340 1.7 xtraeme
341 1.7 xtraeme /*
342 1.7 xtraeme * Shows info about physical disks.
343 1.7 xtraeme */
344 1.2 xtraeme static void
345 1.7 xtraeme bio_show_disks(struct biotmp *bt)
346 1.1 bouyer {
347 1.7 xtraeme struct bioc_disk bd;
348 1.7 xtraeme const char *status;
349 1.7 xtraeme char size[64], serial[32], scsiname[16];
350 1.7 xtraeme
351 1.7 xtraeme memset(&bd, 0, sizeof(bd));
352 1.7 xtraeme bd.bd_cookie = bl.bl_cookie;
353 1.7 xtraeme bd.bd_diskid = bt->diskid;
354 1.7 xtraeme bd.bd_volid = bt->volid;
355 1.7 xtraeme
356 1.7 xtraeme if (bt->show_disknovol) {
357 1.7 xtraeme if (ioctl(bt->fd, BIOCDISK_NOVOL, &bd) == -1)
358 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK_NOVOL");
359 1.7 xtraeme if (!bd.bd_disknovol)
360 1.7 xtraeme return;
361 1.7 xtraeme } else {
362 1.7 xtraeme if (ioctl(bt->fd, BIOCDISK, &bd) == -1)
363 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK");
364 1.7 xtraeme }
365 1.7 xtraeme
366 1.7 xtraeme switch (bd.bd_status) {
367 1.7 xtraeme case BIOC_SDONLINE:
368 1.7 xtraeme status = BIOC_SDONLINE_S;
369 1.7 xtraeme break;
370 1.7 xtraeme case BIOC_SDOFFLINE:
371 1.7 xtraeme status = BIOC_SDOFFLINE_S;
372 1.7 xtraeme break;
373 1.7 xtraeme case BIOC_SDFAILED:
374 1.7 xtraeme status = BIOC_SDFAILED_S;
375 1.7 xtraeme break;
376 1.7 xtraeme case BIOC_SDREBUILD:
377 1.7 xtraeme status = BIOC_SDREBUILD_S;
378 1.7 xtraeme break;
379 1.7 xtraeme case BIOC_SDHOTSPARE:
380 1.7 xtraeme status = BIOC_SDHOTSPARE_S;
381 1.7 xtraeme break;
382 1.7 xtraeme case BIOC_SDUNUSED:
383 1.7 xtraeme status = BIOC_SDUNUSED_S;
384 1.7 xtraeme break;
385 1.7 xtraeme case BIOC_SDSCRUB:
386 1.7 xtraeme status = BIOC_SDSCRUB_S;
387 1.7 xtraeme break;
388 1.7 xtraeme case BIOC_SDPASSTHRU:
389 1.7 xtraeme status = BIOC_SDPASSTHRU_S;
390 1.7 xtraeme break;
391 1.7 xtraeme case BIOC_SDINVALID:
392 1.7 xtraeme default:
393 1.7 xtraeme status = BIOC_SDINVALID_S;
394 1.7 xtraeme break;
395 1.7 xtraeme }
396 1.7 xtraeme
397 1.7 xtraeme if (bt->format)
398 1.7 xtraeme snprintf(bt->volname, sizeof(bt->volname),
399 1.7 xtraeme "%u:%u", bt->bv->bv_volid, bd.bd_diskid);
400 1.7 xtraeme
401 1.7 xtraeme humanize_number(size, 5, bd.bd_size, "", HN_AUTOSCALE,
402 1.7 xtraeme HN_B | HN_NOSPACE | HN_DECIMAL);
403 1.7 xtraeme
404 1.7 xtraeme if (bd.bd_procdev[0])
405 1.7 xtraeme snprintf(scsiname, sizeof(scsiname), "%u:%u.%u %s",
406 1.7 xtraeme bd.bd_channel, bd.bd_target, bd.bd_lun,
407 1.7 xtraeme bd.bd_procdev);
408 1.7 xtraeme else
409 1.7 xtraeme snprintf(scsiname, sizeof(scsiname), "%u:%u.%u noencl",
410 1.7 xtraeme bd.bd_channel, bd.bd_target, bd.bd_lun);
411 1.7 xtraeme
412 1.7 xtraeme if (bd.bd_serial[0])
413 1.7 xtraeme strlcpy(serial, bd.bd_serial, sizeof(serial));
414 1.7 xtraeme else
415 1.7 xtraeme strlcpy(serial, "unknown serial", sizeof(serial));
416 1.7 xtraeme
417 1.7 xtraeme if (bt->format)
418 1.7 xtraeme printf("%6s %-12s %4s %20s <%s>\n",
419 1.7 xtraeme bt->volname, status, size, scsiname,
420 1.7 xtraeme bd.bd_vendor);
421 1.7 xtraeme else
422 1.7 xtraeme printf("%5d [%-28s] %-12s %-6s %12s\n",
423 1.7 xtraeme bt->diskid, bd.bd_vendor, status, size, scsiname);
424 1.1 bouyer
425 1.7 xtraeme }
426 1.7 xtraeme
427 1.7 xtraeme /*
428 1.7 xtraeme * Shows info about volumes/disks.
429 1.7 xtraeme */
430 1.7 xtraeme static void
431 1.7 xtraeme bio_show_common(int fd, int argc, char **argv)
432 1.7 xtraeme {
433 1.7 xtraeme struct biotmp *biot;
434 1.7 xtraeme struct bioc_inq bi;
435 1.7 xtraeme int i, d, ndisks;
436 1.7 xtraeme bool show_all, show_disks;
437 1.7 xtraeme bool show_vols, show_caps;
438 1.1 bouyer
439 1.7 xtraeme show_all = show_disks = show_vols = show_caps = false;
440 1.1 bouyer
441 1.7 xtraeme if (argc > 1)
442 1.7 xtraeme usage();
443 1.1 bouyer
444 1.7 xtraeme if (argv[0]) {
445 1.7 xtraeme if (strcmp(argv[0], "disks") == 0)
446 1.7 xtraeme show_disks = true;
447 1.7 xtraeme else if (strcmp(argv[0], "volumes") == 0)
448 1.7 xtraeme show_vols = true;
449 1.7 xtraeme else
450 1.7 xtraeme usage();
451 1.7 xtraeme } else
452 1.7 xtraeme show_all = true;
453 1.1 bouyer
454 1.7 xtraeme memset(&bi, 0, sizeof(bi));
455 1.7 xtraeme bi.bi_cookie = bl.bl_cookie;
456 1.1 bouyer
457 1.7 xtraeme if (ioctl(fd, BIOCINQ, &bi) == -1)
458 1.7 xtraeme err(EXIT_FAILURE, "BIOCINQ");
459 1.1 bouyer
460 1.7 xtraeme /*
461 1.7 xtraeme * If there are volumes there's no point to continue.
462 1.7 xtraeme */
463 1.7 xtraeme if (show_all || show_vols) {
464 1.7 xtraeme if (!bi.bi_novol) {
465 1.7 xtraeme warnx("no volumes available");
466 1.7 xtraeme return;
467 1.1 bouyer }
468 1.7 xtraeme }
469 1.1 bouyer
470 1.7 xtraeme biot = calloc(1, sizeof(*biot));
471 1.7 xtraeme if (!biot)
472 1.7 xtraeme err(EXIT_FAILURE, "biotemp calloc");
473 1.7 xtraeme
474 1.7 xtraeme biot->fd = fd;
475 1.7 xtraeme biot->bi = &bi;
476 1.7 xtraeme /*
477 1.7 xtraeme * Go to the disks section if that was specified.
478 1.7 xtraeme */
479 1.7 xtraeme if (show_disks)
480 1.7 xtraeme goto disks;
481 1.7 xtraeme
482 1.7 xtraeme /*
483 1.7 xtraeme * Common code to show only info about volumes and disks
484 1.7 xtraeme * associated to them.
485 1.7 xtraeme */
486 1.9 xtraeme printf("%6s %-12s %4s %20s %8s %6s\n",
487 1.7 xtraeme "Volume", "Status", "Size", "Device/Label",
488 1.9 xtraeme "Level", "Stripe");
489 1.7 xtraeme printf("=============================================="
490 1.9 xtraeme "===============\n");
491 1.1 bouyer
492 1.7 xtraeme for (i = 0; i < bi.bi_novol; i++) {
493 1.7 xtraeme biot->format = true;
494 1.7 xtraeme biot->volid = i;
495 1.7 xtraeme ndisks = bio_show_volumes(biot);
496 1.7 xtraeme if (show_vols)
497 1.7 xtraeme continue;
498 1.7 xtraeme
499 1.7 xtraeme for (d = 0; d < ndisks; d++) {
500 1.7 xtraeme biot->diskid = d;
501 1.7 xtraeme bio_show_disks(biot);
502 1.1 bouyer }
503 1.1 bouyer
504 1.7 xtraeme }
505 1.7 xtraeme goto out;
506 1.1 bouyer
507 1.7 xtraeme disks:
508 1.7 xtraeme /*
509 1.7 xtraeme * show info about all disks connected to the raid controller,
510 1.7 xtraeme * even if they aren't associated with a volume or raid set.
511 1.7 xtraeme */
512 1.7 xtraeme if (show_disks) {
513 1.7 xtraeme printf("%5s %-30s %-12s %-6s %12s\n",
514 1.7 xtraeme "Disk", "Model/Serial", "Status", "Size", "Location");
515 1.7 xtraeme printf("==============================================="
516 1.7 xtraeme "======================\n");
517 1.7 xtraeme for (d = 0; d < bi.bi_nodisk; d++) {
518 1.7 xtraeme biot->show_disknovol = true;
519 1.7 xtraeme biot->diskid = d;
520 1.7 xtraeme bio_show_disks(biot);
521 1.1 bouyer }
522 1.1 bouyer }
523 1.7 xtraeme out:
524 1.7 xtraeme free(biot);
525 1.1 bouyer }
526 1.1 bouyer
527 1.7 xtraeme /*
528 1.7 xtraeme * To handle the alarm feature.
529 1.7 xtraeme */
530 1.2 xtraeme static void
531 1.7 xtraeme bio_alarm(int fd, int argc, char **argv)
532 1.1 bouyer {
533 1.7 xtraeme struct bioc_alarm ba;
534 1.7 xtraeme bool show = false;
535 1.1 bouyer
536 1.7 xtraeme memset(&ba, 0, sizeof(ba));
537 1.1 bouyer ba.ba_cookie = bl.bl_cookie;
538 1.1 bouyer
539 1.7 xtraeme if (argc > 1)
540 1.7 xtraeme usage();
541 1.7 xtraeme
542 1.7 xtraeme if (argc == 0) {
543 1.7 xtraeme /* show alarm status */
544 1.7 xtraeme ba.ba_opcode = BIOC_GASTATUS;
545 1.7 xtraeme show = true;
546 1.7 xtraeme } else if (strcmp(argv[0], "silence") == 0) {
547 1.7 xtraeme /* silence alarm */
548 1.1 bouyer ba.ba_opcode = BIOC_SASILENCE;
549 1.7 xtraeme } else if (strcmp(argv[0], "enable") == 0) {
550 1.7 xtraeme /* enable alarm */
551 1.7 xtraeme ba.ba_opcode = BIOC_SAENABLE;
552 1.7 xtraeme } else if (strcmp(argv[0], "disable") == 0) {
553 1.7 xtraeme /* disable alarm */
554 1.7 xtraeme ba.ba_opcode = BIOC_SADISABLE;
555 1.7 xtraeme } else if (strcmp(argv[0], "test") == 0) {
556 1.7 xtraeme /* test alarm */
557 1.7 xtraeme ba.ba_opcode = BIOC_SATEST;
558 1.7 xtraeme } else
559 1.7 xtraeme usage();
560 1.7 xtraeme
561 1.7 xtraeme if (ioctl(fd, BIOCALARM, &ba) == -1)
562 1.7 xtraeme err(EXIT_FAILURE, "BIOCALARM");
563 1.7 xtraeme
564 1.7 xtraeme if (show)
565 1.7 xtraeme printf("alarm is currently %s\n",
566 1.7 xtraeme ba.ba_status ? "enabled" : "disabled");
567 1.7 xtraeme }
568 1.7 xtraeme
569 1.7 xtraeme /*
570 1.7 xtraeme * To add/remove a hotspare disk.
571 1.7 xtraeme */
572 1.7 xtraeme static void
573 1.7 xtraeme bio_setstate_hotspare(int fd, int argc, char **argv)
574 1.7 xtraeme {
575 1.7 xtraeme struct bioc_setstate bs;
576 1.7 xtraeme struct locator location;
577 1.7 xtraeme
578 1.7 xtraeme memset(&bs, 0, sizeof(bs));
579 1.7 xtraeme
580 1.7 xtraeme if (argc != 2)
581 1.7 xtraeme usage();
582 1.7 xtraeme
583 1.7 xtraeme if (strcmp(argv[0], "add") == 0)
584 1.7 xtraeme bs.bs_status = BIOC_SSHOTSPARE;
585 1.7 xtraeme else if (strcmp(argv[0], "remove") == 0)
586 1.7 xtraeme bs.bs_status = BIOC_SSDELHOTSPARE;
587 1.7 xtraeme else
588 1.7 xtraeme usage();
589 1.7 xtraeme
590 1.7 xtraeme bio_setstate_common(fd, argv[1], &bs, &location);
591 1.7 xtraeme }
592 1.7 xtraeme
593 1.7 xtraeme /*
594 1.7 xtraeme * To add/remove a pass through disk.
595 1.7 xtraeme */
596 1.7 xtraeme static void
597 1.7 xtraeme bio_setstate_passthru(int fd, int argc, char **argv)
598 1.7 xtraeme {
599 1.7 xtraeme struct bioc_setstate bs;
600 1.7 xtraeme struct locator location;
601 1.7 xtraeme char *endptr;
602 1.7 xtraeme bool rem = false;
603 1.7 xtraeme
604 1.13 ahoka if (argc < 2 || argc > 3)
605 1.7 xtraeme usage();
606 1.7 xtraeme
607 1.7 xtraeme memset(&bs, 0, sizeof(bs));
608 1.7 xtraeme
609 1.7 xtraeme if (strcmp(argv[0], "add") == 0) {
610 1.7 xtraeme if (argv[1] == NULL || argv[2] == NULL)
611 1.7 xtraeme usage();
612 1.7 xtraeme
613 1.7 xtraeme bs.bs_status = BIOC_SSPASSTHRU;
614 1.7 xtraeme } else if (strcmp(argv[0], "remove") == 0) {
615 1.7 xtraeme if (argv[1] == NULL)
616 1.7 xtraeme usage();
617 1.7 xtraeme
618 1.7 xtraeme bs.bs_status = BIOC_SSDELPASSTHRU;
619 1.7 xtraeme rem = true;
620 1.7 xtraeme } else
621 1.7 xtraeme usage();
622 1.7 xtraeme
623 1.7 xtraeme if (rem)
624 1.7 xtraeme bio_setstate_common(fd, argv[1], &bs, &location);
625 1.7 xtraeme else {
626 1.7 xtraeme bs.bs_other_id = (unsigned int)strtoul(argv[1], &endptr, 10);
627 1.7 xtraeme if (*endptr != '\0')
628 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value");
629 1.7 xtraeme
630 1.7 xtraeme bio_setstate_common(fd, argv[2], &bs, &location);
631 1.7 xtraeme }
632 1.7 xtraeme }
633 1.7 xtraeme
634 1.7 xtraeme /*
635 1.7 xtraeme * To start/stop a consistency check in a RAID volume.
636 1.7 xtraeme */
637 1.7 xtraeme static void
638 1.7 xtraeme bio_setstate_consistency(int fd, int argc, char **argv)
639 1.7 xtraeme {
640 1.7 xtraeme struct bioc_setstate bs;
641 1.7 xtraeme char *endptr;
642 1.7 xtraeme
643 1.13 ahoka if (argc != 2)
644 1.7 xtraeme usage();
645 1.7 xtraeme
646 1.8 xtraeme memset(&bs, 0, sizeof(bs));
647 1.8 xtraeme
648 1.7 xtraeme if (strcmp(argv[0], "start") == 0)
649 1.7 xtraeme bs.bs_status = BIOC_SSCHECKSTART_VOL;
650 1.7 xtraeme else if (strcmp(argv[0], "stop") == 0)
651 1.7 xtraeme bs.bs_status = BIOC_SSCHECKSTOP_VOL;
652 1.7 xtraeme else
653 1.7 xtraeme usage();
654 1.7 xtraeme
655 1.8 xtraeme bs.bs_volid = (unsigned int)strtoul(argv[1], &endptr, 10);
656 1.7 xtraeme if (*endptr != '\0')
657 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value");
658 1.7 xtraeme
659 1.7 xtraeme bio_setstate_common(fd, NULL, &bs, NULL);
660 1.7 xtraeme }
661 1.7 xtraeme
662 1.7 xtraeme static void
663 1.7 xtraeme bio_setstate_common(int fd, char *arg, struct bioc_setstate *bs,
664 1.7 xtraeme struct locator *location)
665 1.7 xtraeme {
666 1.7 xtraeme const char *errstr;
667 1.7 xtraeme
668 1.7 xtraeme if (!arg || !location)
669 1.7 xtraeme goto send;
670 1.7 xtraeme
671 1.7 xtraeme errstr = str2locator(arg, location);
672 1.7 xtraeme if (errstr)
673 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", arg, errstr);
674 1.7 xtraeme
675 1.7 xtraeme bs->bs_channel = location->channel;
676 1.7 xtraeme bs->bs_target = location->target;
677 1.7 xtraeme bs->bs_lun = location->lun;
678 1.7 xtraeme
679 1.7 xtraeme send:
680 1.7 xtraeme bs->bs_cookie = bl.bl_cookie;
681 1.7 xtraeme
682 1.7 xtraeme if (ioctl(fd, BIOCSETSTATE, bs) == -1)
683 1.7 xtraeme err(EXIT_FAILURE, "BIOCSETSTATE");
684 1.7 xtraeme }
685 1.7 xtraeme
686 1.7 xtraeme /*
687 1.7 xtraeme * To create a RAID volume.
688 1.7 xtraeme */
689 1.7 xtraeme static void
690 1.7 xtraeme bio_volops_create(int fd, int argc, char **argv)
691 1.7 xtraeme {
692 1.7 xtraeme struct bioc_volops bc;
693 1.7 xtraeme struct bioc_inq bi;
694 1.7 xtraeme struct bioc_disk bd;
695 1.7 xtraeme struct locator location;
696 1.10 xtraeme uint64_t total_size = 0, disksize = 0;
697 1.7 xtraeme int64_t volsize = 0;
698 1.7 xtraeme const char *errstr;
699 1.10 xtraeme char *endptr, *stripe, levelstr[32];
700 1.7 xtraeme char *scsiname, *raid_level, size[64];
701 1.7 xtraeme int disk_first = 0, disk_end = 0;
702 1.7 xtraeme int i, nfreedisks = 0;
703 1.7 xtraeme int user_disks = 0;
704 1.7 xtraeme
705 1.7 xtraeme if (argc < 6 || argc > 7)
706 1.7 xtraeme usage();
707 1.7 xtraeme
708 1.7 xtraeme if (strcmp(argv[0], "volume") != 0)
709 1.7 xtraeme usage();
710 1.7 xtraeme
711 1.7 xtraeme /*
712 1.7 xtraeme * No size requested, use max size depending on RAID level.
713 1.7 xtraeme */
714 1.7 xtraeme if (argc == 6) {
715 1.7 xtraeme stripe = argv[3];
716 1.7 xtraeme raid_level = argv[4];
717 1.7 xtraeme scsiname = argv[5];
718 1.7 xtraeme } else {
719 1.7 xtraeme stripe = argv[4];
720 1.7 xtraeme raid_level = argv[5];
721 1.7 xtraeme scsiname = argv[6];
722 1.7 xtraeme }
723 1.7 xtraeme
724 1.7 xtraeme memset(&bd, 0, sizeof(bd));
725 1.7 xtraeme memset(&bc, 0, sizeof(bc));
726 1.7 xtraeme memset(&bi, 0, sizeof(bi));
727 1.7 xtraeme
728 1.7 xtraeme bc.bc_cookie = bd.bd_cookie = bi.bi_cookie = bl.bl_cookie;
729 1.7 xtraeme bc.bc_opcode = BIOC_VCREATE_VOLUME;
730 1.7 xtraeme
731 1.7 xtraeme bc.bc_volid = (unsigned int)strtoul(argv[1], &endptr, 10);
732 1.7 xtraeme if (*endptr != '\0')
733 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value");
734 1.7 xtraeme
735 1.7 xtraeme if (argc == 7)
736 1.12 lukem if (dehumanize_number(argv[3], &volsize) == -1
737 1.12 lukem || volsize < 0)
738 1.7 xtraeme errx(EXIT_FAILURE, "Invalid SIZE value");
739 1.7 xtraeme
740 1.7 xtraeme bc.bc_stripe = (unsigned int)strtoul(stripe, &endptr, 10);
741 1.7 xtraeme if (*endptr != '\0')
742 1.7 xtraeme errx(EXIT_FAILURE, "Invalid STRIPE size value");
743 1.7 xtraeme
744 1.7 xtraeme bc.bc_level = (unsigned int)strtoul(raid_level, &endptr, 10);
745 1.7 xtraeme if (*endptr != '\0')
746 1.7 xtraeme errx(EXIT_FAILURE, "Invalid RAID_LEVEL value");
747 1.7 xtraeme
748 1.7 xtraeme errstr = str2locator(scsiname, &location);
749 1.7 xtraeme if (errstr)
750 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", scsiname, errstr);
751 1.7 xtraeme
752 1.7 xtraeme /*
753 1.7 xtraeme * Parse the device list that will be used for the volume,
754 1.7 xtraeme * by using a bit field for the disks.
755 1.7 xtraeme */
756 1.7 xtraeme if ((isdigit((unsigned char)argv[2][0]) == 0) || argv[2][1] != '-' ||
757 1.7 xtraeme (isdigit((unsigned char)argv[2][2]) == 0))
758 1.7 xtraeme errx(EXIT_FAILURE, "Invalid DISKIDs value");
759 1.7 xtraeme
760 1.7 xtraeme disk_first = atoi(&argv[2][0]);
761 1.7 xtraeme disk_end = atoi(&argv[2][2]);
762 1.7 xtraeme
763 1.7 xtraeme for (i = disk_first; i < disk_end + 1; i++) {
764 1.7 xtraeme bc.bc_devmask |= (1 << i);
765 1.7 xtraeme user_disks++;
766 1.7 xtraeme }
767 1.7 xtraeme
768 1.7 xtraeme /*
769 1.7 xtraeme * Find out how many disks are free and how much size we
770 1.7 xtraeme * have available for the new volume.
771 1.7 xtraeme */
772 1.7 xtraeme if (ioctl(fd, BIOCINQ, &bi) == -1)
773 1.7 xtraeme err(EXIT_FAILURE, "BIOCINQ");
774 1.7 xtraeme
775 1.7 xtraeme for (i = 0; i < bi.bi_nodisk; i++) {
776 1.7 xtraeme bd.bd_diskid = i;
777 1.7 xtraeme if (ioctl(fd, BIOCDISK_NOVOL, &bd) == -1)
778 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK_NOVOL");
779 1.7 xtraeme
780 1.7 xtraeme if (bd.bd_status == BIOC_SDUNUSED) {
781 1.7 xtraeme if (i == 0)
782 1.10 xtraeme disksize = bd.bd_size;
783 1.7 xtraeme
784 1.10 xtraeme total_size += bd.bd_size;
785 1.7 xtraeme nfreedisks++;
786 1.7 xtraeme }
787 1.7 xtraeme }
788 1.7 xtraeme
789 1.10 xtraeme if (user_disks > nfreedisks)
790 1.10 xtraeme errx(EXIT_FAILURE, "specified disks number is higher than "
791 1.10 xtraeme "available free disks");
792 1.10 xtraeme
793 1.7 xtraeme /*
794 1.7 xtraeme * Basic checks to be sure we don't do something stupid.
795 1.7 xtraeme */
796 1.7 xtraeme if (nfreedisks == 0)
797 1.7 xtraeme errx(EXIT_FAILURE, "No free disks available");
798 1.7 xtraeme
799 1.7 xtraeme switch (bc.bc_level) {
800 1.7 xtraeme case 0: /* RAID 0 requires at least one disk */
801 1.7 xtraeme if (argc == 7) {
802 1.12 lukem if ((uint64_t)volsize > (disksize * user_disks))
803 1.7 xtraeme errx(EXIT_FAILURE, "volume size specified "
804 1.7 xtraeme "is larger than available on free disks");
805 1.7 xtraeme bc.bc_size = (uint64_t)volsize;
806 1.7 xtraeme } else
807 1.10 xtraeme bc.bc_size = disksize * user_disks;
808 1.1 bouyer
809 1.1 bouyer break;
810 1.10 xtraeme case 1: /* RAID 1 requires two disks and size is total / 2 */
811 1.7 xtraeme if (nfreedisks < 2 || user_disks < 2)
812 1.7 xtraeme errx(EXIT_FAILURE, "2 disks are required at least for "
813 1.7 xtraeme "this RAID level");
814 1.7 xtraeme
815 1.10 xtraeme /* RAID 1+0 requires three disks at least */
816 1.10 xtraeme if (nfreedisks > 2 && user_disks > 2)
817 1.10 xtraeme bc.bc_level = BIOC_SVOL_RAID10;
818 1.10 xtraeme
819 1.7 xtraeme if (argc == 7) {
820 1.12 lukem if ((uint64_t)volsize > ((disksize * user_disks) / 2))
821 1.7 xtraeme errx(EXIT_FAILURE, "volume size specified "
822 1.7 xtraeme "is larger than available on free disks");
823 1.7 xtraeme bc.bc_size = (uint64_t)volsize;
824 1.7 xtraeme } else
825 1.10 xtraeme bc.bc_size = ((disksize * user_disks) / 2);
826 1.1 bouyer
827 1.1 bouyer break;
828 1.10 xtraeme case 3: /* RAID 3/5 requires three disks and size is total - 1 disk */
829 1.7 xtraeme case 5:
830 1.7 xtraeme if (nfreedisks < 3 || user_disks < 3)
831 1.7 xtraeme errx(EXIT_FAILURE, "3 disks are required at least for "
832 1.7 xtraeme "this RAID level");
833 1.7 xtraeme
834 1.7 xtraeme if (argc == 7) {
835 1.12 lukem if ((uint64_t)volsize > (disksize * (user_disks - 1)))
836 1.7 xtraeme errx(EXIT_FAILURE, "volume size specified "
837 1.7 xtraeme "is larger than available on free disks");
838 1.7 xtraeme bc.bc_size = (uint64_t)volsize;
839 1.7 xtraeme } else
840 1.10 xtraeme bc.bc_size = (disksize * (user_disks - 1));
841 1.1 bouyer
842 1.1 bouyer break;
843 1.7 xtraeme case 6: /* RAID 6 requires four disks and size is total - 2 disks */
844 1.7 xtraeme if (nfreedisks < 4 || user_disks < 4)
845 1.7 xtraeme errx(EXIT_FAILURE, "4 disks are required at least for "
846 1.7 xtraeme "this RAID level");
847 1.7 xtraeme
848 1.7 xtraeme if (argc == 7) {
849 1.12 lukem if ((uint64_t)volsize >
850 1.10 xtraeme ((disksize * user_disks) - (disksize * 2)))
851 1.7 xtraeme err(EXIT_FAILURE, "volume size specified "
852 1.7 xtraeme "is larger than available on free disks");
853 1.7 xtraeme bc.bc_size = (uint64_t)volsize;
854 1.7 xtraeme } else
855 1.10 xtraeme bc.bc_size =
856 1.10 xtraeme (((disksize * user_disks) - (disksize * 2)));
857 1.1 bouyer
858 1.1 bouyer break;
859 1.1 bouyer default:
860 1.7 xtraeme errx(EXIT_FAILURE, "Unsupported RAID level");
861 1.1 bouyer }
862 1.1 bouyer
863 1.7 xtraeme bc.bc_channel = location.channel;
864 1.7 xtraeme bc.bc_target = location.target;
865 1.7 xtraeme bc.bc_lun = location.lun;
866 1.7 xtraeme
867 1.7 xtraeme if (ioctl(fd, BIOCVOLOPS, &bc) == -1)
868 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOLOPS");
869 1.7 xtraeme
870 1.7 xtraeme humanize_number(size, 5, bc.bc_size, "", HN_AUTOSCALE,
871 1.7 xtraeme HN_B | HN_NOSPACE | HN_DECIMAL);
872 1.7 xtraeme
873 1.10 xtraeme if (bc.bc_level == BIOC_SVOL_RAID10)
874 1.10 xtraeme snprintf(levelstr, sizeof(levelstr), "1+0");
875 1.10 xtraeme else
876 1.10 xtraeme snprintf(levelstr, sizeof(levelstr), "%u", bc.bc_level);
877 1.10 xtraeme
878 1.10 xtraeme printf("Created volume %u size: %s stripe: %uK level: %s "
879 1.7 xtraeme "SCSI location: %u:%u.%u\n", bc.bc_volid, size, bc.bc_stripe,
880 1.10 xtraeme levelstr, bc.bc_channel, bc.bc_target, bc.bc_lun);
881 1.7 xtraeme }
882 1.1 bouyer
883 1.7 xtraeme #ifdef notyet
884 1.7 xtraeme /*
885 1.7 xtraeme * To modify a RAID volume.
886 1.7 xtraeme */
887 1.7 xtraeme static void
888 1.7 xtraeme bio_volops_modify(int fd, int argc, char **argv)
889 1.7 xtraeme {
890 1.7 xtraeme /* XTRAEME: TODO */
891 1.1 bouyer }
892 1.7 xtraeme #endif
893 1.1 bouyer
894 1.7 xtraeme /*
895 1.7 xtraeme * To remove a RAID volume.
896 1.7 xtraeme */
897 1.2 xtraeme static void
898 1.7 xtraeme bio_volops_remove(int fd, int argc, char **argv)
899 1.1 bouyer {
900 1.7 xtraeme struct bioc_volops bc;
901 1.1 bouyer struct locator location;
902 1.1 bouyer const char *errstr;
903 1.7 xtraeme char *endptr;
904 1.1 bouyer
905 1.7 xtraeme if (argc != 3 || strcmp(argv[0], "volume") != 0)
906 1.7 xtraeme usage();
907 1.7 xtraeme
908 1.7 xtraeme memset(&bc, 0, sizeof(bc));
909 1.7 xtraeme bc.bc_cookie = bl.bl_cookie;
910 1.7 xtraeme bc.bc_opcode = BIOC_VREMOVE_VOLUME;
911 1.7 xtraeme
912 1.7 xtraeme bc.bc_volid = (unsigned int)strtoul(argv[1], &endptr, 10);
913 1.7 xtraeme if (*endptr != '\0')
914 1.7 xtraeme errx(EXIT_FAILURE, "Invalid Volume ID value");
915 1.7 xtraeme
916 1.7 xtraeme errstr = str2locator(argv[2], &location);
917 1.1 bouyer if (errstr)
918 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", argv[2], errstr);
919 1.7 xtraeme
920 1.7 xtraeme bc.bc_channel = location.channel;
921 1.7 xtraeme bc.bc_target = location.target;
922 1.7 xtraeme bc.bc_lun = location.lun;
923 1.1 bouyer
924 1.7 xtraeme if (ioctl(fd, BIOCVOLOPS, &bc) == -1)
925 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOLOPS");
926 1.1 bouyer
927 1.7 xtraeme printf("Removed volume %u at SCSI location %u:%u.%u\n",
928 1.7 xtraeme bc.bc_volid, bc.bc_channel, bc.bc_target, bc.bc_lun);
929 1.1 bouyer }
930 1.1 bouyer
931 1.7 xtraeme /*
932 1.7 xtraeme * To blink/unblink a disk in enclosures.
933 1.7 xtraeme */
934 1.2 xtraeme static void
935 1.7 xtraeme bio_setblink(int fd, int argc, char **argv)
936 1.1 bouyer {
937 1.1 bouyer struct locator location;
938 1.1 bouyer struct bioc_inq bi;
939 1.1 bouyer struct bioc_vol bv;
940 1.1 bouyer struct bioc_disk bd;
941 1.1 bouyer struct bioc_blink bb;
942 1.1 bouyer const char *errstr;
943 1.7 xtraeme int v, d, rv, blink = 0;
944 1.7 xtraeme
945 1.7 xtraeme if (argc != 2)
946 1.7 xtraeme usage();
947 1.1 bouyer
948 1.7 xtraeme if (strcmp(argv[0], "start") == 0)
949 1.7 xtraeme blink = BIOC_SBBLINK;
950 1.7 xtraeme else if (strcmp(argv[0], "stop") == 0)
951 1.7 xtraeme blink = BIOC_SBUNBLINK;
952 1.7 xtraeme else
953 1.7 xtraeme usage();
954 1.7 xtraeme
955 1.7 xtraeme errstr = str2locator(argv[1], &location);
956 1.1 bouyer if (errstr)
957 1.7 xtraeme errx(EXIT_FAILURE, "Target %s: %s", argv[1], errstr);
958 1.1 bouyer
959 1.1 bouyer /* try setting blink on the device directly */
960 1.1 bouyer memset(&bb, 0, sizeof(bb));
961 1.1 bouyer bb.bb_cookie = bl.bl_cookie;
962 1.1 bouyer bb.bb_status = blink;
963 1.1 bouyer bb.bb_target = location.target;
964 1.1 bouyer bb.bb_channel = location.channel;
965 1.2 xtraeme rv = ioctl(fd, BIOCBLINK, &bb);
966 1.1 bouyer if (rv == 0)
967 1.1 bouyer return;
968 1.1 bouyer
969 1.1 bouyer /* if the blink didnt work, try to find something that will */
970 1.1 bouyer memset(&bi, 0, sizeof(bi));
971 1.1 bouyer bi.bi_cookie = bl.bl_cookie;
972 1.2 xtraeme rv = ioctl(fd, BIOCINQ, &bi);
973 1.7 xtraeme if (rv == -1)
974 1.7 xtraeme err(EXIT_FAILURE, "BIOCINQ");
975 1.1 bouyer
976 1.1 bouyer for (v = 0; v < bi.bi_novol; v++) {
977 1.1 bouyer memset(&bv, 0, sizeof(bv));
978 1.1 bouyer bv.bv_cookie = bl.bl_cookie;
979 1.1 bouyer bv.bv_volid = v;
980 1.2 xtraeme rv = ioctl(fd, BIOCVOL, &bv);
981 1.4 xtraeme if (rv == -1)
982 1.7 xtraeme err(EXIT_FAILURE, "BIOCVOL");
983 1.1 bouyer
984 1.1 bouyer for (d = 0; d < bv.bv_nodisk; d++) {
985 1.1 bouyer memset(&bd, 0, sizeof(bd));
986 1.1 bouyer bd.bd_cookie = bl.bl_cookie;
987 1.1 bouyer bd.bd_volid = v;
988 1.1 bouyer bd.bd_diskid = d;
989 1.1 bouyer
990 1.2 xtraeme rv = ioctl(fd, BIOCDISK, &bd);
991 1.4 xtraeme if (rv == -1)
992 1.7 xtraeme err(EXIT_FAILURE, "BIOCDISK");
993 1.1 bouyer
994 1.1 bouyer if (bd.bd_channel == location.channel &&
995 1.1 bouyer bd.bd_target == location.target &&
996 1.1 bouyer bd.bd_lun == location.lun) {
997 1.1 bouyer if (bd.bd_procdev[0] != '\0') {
998 1.2 xtraeme bio_blink(fd, bd.bd_procdev,
999 1.1 bouyer location.target, blink);
1000 1.1 bouyer } else
1001 1.7 xtraeme warnx("Disk %s is not in an enclosure",
1002 1.7 xtraeme argv[1]);
1003 1.1 bouyer return;
1004 1.1 bouyer }
1005 1.1 bouyer }
1006 1.1 bouyer }
1007 1.1 bouyer
1008 1.7 xtraeme warnx("Disk %s does not exist", argv[1]);
1009 1.1 bouyer }
1010 1.1 bouyer
1011 1.2 xtraeme static void
1012 1.2 xtraeme bio_blink(int fd, char *enclosure, int target, int blinktype)
1013 1.1 bouyer {
1014 1.1 bouyer struct bio_locate bio;
1015 1.1 bouyer struct bioc_blink blink;
1016 1.1 bouyer
1017 1.1 bouyer bio.bl_name = enclosure;
1018 1.7 xtraeme if (ioctl(fd, BIOCLOCATE, &bio) == -1)
1019 1.4 xtraeme errx(EXIT_FAILURE,
1020 1.7 xtraeme "Can't locate %s device via /dev/bio", enclosure);
1021 1.1 bouyer
1022 1.1 bouyer memset(&blink, 0, sizeof(blink));
1023 1.1 bouyer blink.bb_cookie = bio.bl_cookie;
1024 1.1 bouyer blink.bb_status = blinktype;
1025 1.1 bouyer blink.bb_target = target;
1026 1.1 bouyer
1027 1.7 xtraeme if (ioctl(fd, BIOCBLINK, &blink) == -1)
1028 1.7 xtraeme err(EXIT_FAILURE, "BIOCBLINK");
1029 1.1 bouyer }
1030