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