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