1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. The names of the authors may not be used to endorse or promote
16 * products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 */
31
32 #include <sys/param.h>
33 #ifdef DEBUG
34 #include <sys/sysctl.h>
35 #endif
36 #include <ctype.h>
37 #include <err.h>
38 #include <errno.h>
39 #include <fcntl.h>
40 #include <libutil.h>
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include "mfiutil.h"
47
48 static int add_spare(int ac, char **av);
49 static int remove_spare(int ac, char **av);
50
51 static long
dehumanize(const char * value)52 dehumanize(const char *value)
53 {
54 char *vtp;
55 long iv;
56
57 if (value == NULL)
58 return (0);
59 iv = strtoq(value, &vtp, 0);
60 if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
61 return (0);
62 }
63 switch (vtp[0]) {
64 case 't': case 'T':
65 iv *= 1024;
66 case 'g': case 'G':
67 iv *= 1024;
68 case 'm': case 'M':
69 iv *= 1024;
70 case 'k': case 'K':
71 iv *= 1024;
72 case '\0':
73 break;
74 default:
75 return (0);
76 }
77 return (iv);
78 }
79
80 int
mfi_config_read(int fd,struct mfi_config_data ** configp)81 mfi_config_read(int fd, struct mfi_config_data **configp)
82 {
83 return mfi_config_read_opcode(fd, MFI_DCMD_CFG_READ, configp, NULL, 0);
84 }
85
86 int
mfi_config_read_opcode(int fd,uint32_t opcode,struct mfi_config_data ** configp,uint8_t * mbox,size_t mboxlen)87 mfi_config_read_opcode(int fd, uint32_t opcode, struct mfi_config_data **configp,
88 uint8_t *mbox, size_t mboxlen)
89 {
90 struct mfi_config_data *config;
91 uint32_t config_size;
92 int error;
93
94 /*
95 * Keep fetching the config in a loop until we have a large enough
96 * buffer to hold the entire configuration.
97 */
98 config = NULL;
99 config_size = 1024;
100 fetch:
101 config = reallocf(config, config_size);
102 if (config == NULL)
103 return (-1);
104 if (mfi_dcmd_command(fd, opcode, config,
105 config_size, mbox, mboxlen, NULL) < 0) {
106 error = errno;
107 free(config);
108 errno = error;
109 return (-1);
110 }
111
112 if (config->size > config_size) {
113 config_size = config->size;
114 goto fetch;
115 }
116
117 *configp = config;
118 return (0);
119 }
120
121 static struct mfi_array *
mfi_config_lookup_array(struct mfi_config_data * config,uint16_t array_ref)122 mfi_config_lookup_array(struct mfi_config_data *config, uint16_t array_ref)
123 {
124 struct mfi_array *ar;
125 char *p;
126 int i;
127
128 p = (char *)config->array;
129 for (i = 0; i < config->array_count; i++) {
130 ar = (struct mfi_array *)p;
131 if (ar->array_ref == array_ref)
132 return (ar);
133 p += config->array_size;
134 }
135
136 return (NULL);
137 }
138
139 static struct mfi_ld_config *
mfi_config_lookup_volume(struct mfi_config_data * config,uint8_t target_id)140 mfi_config_lookup_volume(struct mfi_config_data *config, uint8_t target_id)
141 {
142 struct mfi_ld_config *ld;
143 char *p;
144 int i;
145
146 p = (char *)config->array + config->array_count * config->array_size;
147 for (i = 0; i < config->log_drv_count; i++) {
148 ld = (struct mfi_ld_config *)p;
149 if (ld->properties.ld.v.target_id == target_id)
150 return (ld);
151 p += config->log_drv_size;
152 }
153
154 return (NULL);
155 }
156
157 static int
clear_config(int ac __unused,char ** av __unused)158 clear_config(int ac __unused, char **av __unused)
159 {
160 struct mfi_ld_list list;
161 int ch, error, fd;
162 u_int i;
163
164 fd = mfi_open(mfi_device, O_RDWR);
165 if (fd < 0) {
166 error = errno;
167 warn("mfi_open");
168 return (error);
169 }
170
171 if (!mfi_reconfig_supported(mfi_device)) {
172 warnx("The current %s driver does not support "
173 "configuration changes.", mfi_device);
174 close(fd);
175 return (EOPNOTSUPP);
176 }
177
178 if (mfi_ld_get_list(fd, &list, NULL) < 0) {
179 error = errno;
180 warn("Failed to get volume list");
181 close(fd);
182 return (error);
183 }
184
185 for (i = 0; i < list.ld_count; i++) {
186 if (mfi_volume_busy(fd, list.ld_list[i].ld.v.target_id)) {
187 warnx("Volume %s is busy and cannot be deleted",
188 mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
189 close(fd);
190 return (EBUSY);
191 }
192 }
193
194 printf(
195 "Are you sure you wish to clear the configuration on %s? [y/N] ",
196 mfi_device);
197 ch = getchar();
198 if (ch != 'y' && ch != 'Y') {
199 printf("\nAborting\n");
200 close(fd);
201 return (0);
202 }
203
204 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_CLEAR, NULL, 0, NULL, 0, NULL) < 0) {
205 error = errno;
206 warn("Failed to clear configuration");
207 close(fd);
208 return (error);
209 }
210
211 printf("%s: Configuration cleared\n", mfi_device);
212 close(fd);
213
214 return (0);
215 }
216 MFI_COMMAND(top, clear, clear_config);
217
218 #define MAX_DRIVES_PER_ARRAY MFI_MAX_ROW_SIZE
219 #define MFI_ARRAY_SIZE sizeof(struct mfi_array)
220
221 #define RT_RAID0 0
222 #define RT_RAID1 1
223 #define RT_RAID5 2
224 #define RT_RAID6 3
225 #define RT_JBOD 4
226 #define RT_CONCAT 5
227 #define RT_RAID10 6
228 #define RT_RAID50 7
229 #define RT_RAID60 8
230
231 static int
compare_int(const void * one,const void * two)232 compare_int(const void *one, const void *two)
233 {
234 int first, second;
235
236 first = *(const int *)one;
237 second = *(const int *)two;
238
239 return (first - second);
240 }
241
242 static struct raid_type_entry {
243 const char *name;
244 int raid_type;
245 } raid_type_table[] = {
246 { "raid0", RT_RAID0 },
247 { "raid-0", RT_RAID0 },
248 { "raid1", RT_RAID1 },
249 { "raid-1", RT_RAID1 },
250 { "mirror", RT_RAID1 },
251 { "raid5", RT_RAID5 },
252 { "raid-5", RT_RAID5 },
253 { "raid6", RT_RAID6 },
254 { "raid-6", RT_RAID6 },
255 { "jbod", RT_JBOD },
256 { "concat", RT_CONCAT },
257 { "raid10", RT_RAID10 },
258 { "raid1+0", RT_RAID10 },
259 { "raid-10", RT_RAID10 },
260 { "raid-1+0", RT_RAID10 },
261 { "raid50", RT_RAID50 },
262 { "raid5+0", RT_RAID50 },
263 { "raid-50", RT_RAID50 },
264 { "raid-5+0", RT_RAID50 },
265 { "raid60", RT_RAID60 },
266 { "raid6+0", RT_RAID60 },
267 { "raid-60", RT_RAID60 },
268 { "raid-6+0", RT_RAID60 },
269 { NULL, 0 },
270 };
271
272 struct config_id_state {
273 int array_count;
274 int log_drv_count;
275 int *arrays;
276 int *volumes;
277 uint16_t array_ref;
278 uint8_t target_id;
279 };
280
281 struct array_info {
282 int drive_count;
283 struct mfi_pd_info *drives;
284 struct mfi_array *array;
285 };
286
287 /* Parse a comma-separated list of drives for an array. */
288 static int
parse_array(int fd,int raid_type,char * array_str,struct array_info * info)289 parse_array(int fd, int raid_type, char *array_str, struct array_info *info)
290 {
291 struct mfi_pd_info *pinfo;
292 uint16_t device_id;
293 char *cp;
294 u_int count;
295 int error;
296
297 cp = array_str;
298 for (count = 0; cp != NULL; count++) {
299 cp = strchr(cp, ',');
300 if (cp != NULL) {
301 cp++;
302 if (*cp == ',') {
303 warnx("Invalid drive list '%s'", array_str);
304 return (EINVAL);
305 }
306 }
307 }
308
309 /* Validate the number of drives for this array. */
310 if (count >= MAX_DRIVES_PER_ARRAY) {
311 warnx("Too many drives for a single array: max is %d",
312 MAX_DRIVES_PER_ARRAY);
313 return (EINVAL);
314 }
315 switch (raid_type) {
316 case RT_RAID1:
317 case RT_RAID10:
318 if (count % 2 != 0) {
319 warnx("RAID1 and RAID10 require an even number of "
320 "drives in each array");
321 return (EINVAL);
322 }
323 break;
324 case RT_RAID5:
325 case RT_RAID50:
326 if (count < 3) {
327 warnx("RAID5 and RAID50 require at least 3 drives in "
328 "each array");
329 return (EINVAL);
330 }
331 break;
332 case RT_RAID6:
333 case RT_RAID60:
334 if (count < 4) {
335 warnx("RAID6 and RAID60 require at least 4 drives in "
336 "each array");
337 return (EINVAL);
338 }
339 break;
340 }
341
342 /* Validate each drive. */
343 info->drives = calloc(count, sizeof(struct mfi_pd_info));
344 if (info->drives == NULL) {
345 warnx("malloc failed");
346 return (ENOMEM);
347 }
348 info->drive_count = count;
349 for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL;
350 pinfo++) {
351 error = mfi_lookup_drive(fd, cp, &device_id);
352 if (error) {
353 free(info->drives);
354 info->drives = NULL;
355 return (error);
356 }
357
358 if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) {
359 error = errno;
360 warn("Failed to fetch drive info for drive %s", cp);
361 free(info->drives);
362 info->drives = NULL;
363 return (error);
364 }
365
366 if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
367 warnx("Drive %u is not available", device_id);
368 free(info->drives);
369 info->drives = NULL;
370 return (EINVAL);
371 }
372
373 if (pinfo->state.ddf.v.pd_type.is_foreign) {
374 warnx("Drive %u is foreign", device_id);
375 free(info->drives);
376 info->drives = NULL;
377 return (EINVAL);
378 }
379 }
380
381 return (0);
382 }
383
384 /*
385 * Find the next free array ref assuming that 'array_ref' is the last
386 * one used. 'array_ref' should be 0xffff for the initial test.
387 */
388 static uint16_t
find_next_array(struct config_id_state * state)389 find_next_array(struct config_id_state *state)
390 {
391 int i;
392
393 /* Assume the current one is used. */
394 state->array_ref++;
395
396 /* Find the next free one. */
397 for (i = 0; i < state->array_count; i++)
398 if (state->arrays[i] == state->array_ref)
399 state->array_ref++;
400 return (state->array_ref);
401 }
402
403 /*
404 * Find the next free volume ID assuming that 'target_id' is the last
405 * one used. 'target_id' should be 0xff for the initial test.
406 */
407 static uint8_t
find_next_volume(struct config_id_state * state)408 find_next_volume(struct config_id_state *state)
409 {
410 int i;
411
412 /* Assume the current one is used. */
413 state->target_id++;
414
415 /* Find the next free one. */
416 for (i = 0; i < state->log_drv_count; i++)
417 if (state->volumes[i] == state->target_id)
418 state->target_id++;
419 return (state->target_id);
420 }
421
422 /* Populate an array with drives. */
423 static void
build_array(int fd __unused,char * arrayp,struct array_info * array_info,struct config_id_state * state,int verbose)424 build_array(int fd __unused, char *arrayp, struct array_info *array_info,
425 struct config_id_state *state, int verbose)
426 {
427 struct mfi_array *ar = (struct mfi_array *)arrayp;
428 int i;
429
430 ar->size = array_info->drives[0].coerced_size;
431 ar->num_drives = array_info->drive_count;
432 ar->array_ref = find_next_array(state);
433 for (i = 0; i < array_info->drive_count; i++) {
434 if (verbose)
435 printf("Adding drive %s to array %u\n",
436 mfi_drive_name(NULL,
437 array_info->drives[i].ref.v.device_id,
438 MFI_DNAME_DEVICE_ID|MFI_DNAME_HONOR_OPTS),
439 ar->array_ref);
440 if (ar->size > array_info->drives[i].coerced_size)
441 ar->size = array_info->drives[i].coerced_size;
442 ar->pd[i].ref = array_info->drives[i].ref;
443 ar->pd[i].fw_state = MFI_PD_STATE_ONLINE;
444 }
445 array_info->array = ar;
446 }
447
448 /*
449 * Create a volume that spans one or more arrays.
450 */
451 static void
build_volume(char * volumep,int narrays,struct array_info * arrays,int raid_type,long stripe_size,struct config_id_state * state,int verbose)452 build_volume(char *volumep, int narrays, struct array_info *arrays,
453 int raid_type, long stripe_size, struct config_id_state *state, int verbose)
454 {
455 struct mfi_ld_config *ld = (struct mfi_ld_config *)volumep;
456 struct mfi_array *ar;
457 int i;
458
459 /* properties */
460 ld->properties.ld.v.target_id = find_next_volume(state);
461 ld->properties.ld.v.seq = 0;
462 ld->properties.default_cache_policy = MR_LD_CACHE_ALLOW_WRITE_CACHE |
463 MR_LD_CACHE_WRITE_BACK;
464 ld->properties.access_policy = MFI_LD_ACCESS_RW;
465 ld->properties.disk_cache_policy = MR_PD_CACHE_UNCHANGED;
466 ld->properties.current_cache_policy = MR_LD_CACHE_ALLOW_WRITE_CACHE |
467 MR_LD_CACHE_WRITE_BACK;
468 ld->properties.no_bgi = 0;
469
470 /* params */
471 switch (raid_type) {
472 case RT_RAID0:
473 case RT_JBOD:
474 ld->params.primary_raid_level = DDF_RAID0;
475 ld->params.raid_level_qualifier = 0;
476 ld->params.secondary_raid_level = 0;
477 break;
478 case RT_RAID1:
479 ld->params.primary_raid_level = DDF_RAID1;
480 ld->params.raid_level_qualifier = 0;
481 ld->params.secondary_raid_level = 0;
482 break;
483 case RT_RAID5:
484 ld->params.primary_raid_level = DDF_RAID5;
485 ld->params.raid_level_qualifier = 3;
486 ld->params.secondary_raid_level = 0;
487 break;
488 case RT_RAID6:
489 ld->params.primary_raid_level = DDF_RAID6;
490 ld->params.raid_level_qualifier = 3;
491 ld->params.secondary_raid_level = 0;
492 break;
493 case RT_CONCAT:
494 ld->params.primary_raid_level = DDF_CONCAT;
495 ld->params.raid_level_qualifier = 0;
496 ld->params.secondary_raid_level = 0;
497 break;
498 case RT_RAID10:
499 ld->params.primary_raid_level = DDF_RAID1;
500 ld->params.raid_level_qualifier = 0;
501 ld->params.secondary_raid_level = 3; /* XXX? */
502 break;
503 case RT_RAID50:
504 /*
505 * XXX: This appears to work though the card's BIOS
506 * complains that the configuration is foreign. The
507 * BIOS setup does not allow for creation of RAID-50
508 * or RAID-60 arrays. The only nested array
509 * configuration it allows for is RAID-10.
510 */
511 ld->params.primary_raid_level = DDF_RAID5;
512 ld->params.raid_level_qualifier = 3;
513 ld->params.secondary_raid_level = 3; /* XXX? */
514 break;
515 case RT_RAID60:
516 ld->params.primary_raid_level = DDF_RAID6;
517 ld->params.raid_level_qualifier = 3;
518 ld->params.secondary_raid_level = 3; /* XXX? */
519 break;
520 }
521
522 /*
523 * Stripe size is encoded as (2 ^ N) * 512 = stripe_size. Use
524 * ffs() to simulate log2(stripe_size).
525 */
526 ld->params.stripe_size = ffs(stripe_size) - 1 - 9;
527 ld->params.num_drives = arrays[0].array->num_drives;
528 ld->params.span_depth = narrays;
529 ld->params.state = MFI_LD_STATE_OPTIMAL;
530 ld->params.init_state = MFI_LD_PARAMS_INIT_NO;
531 ld->params.is_consistent = 0;
532
533 /* spans */
534 for (i = 0; i < narrays; i++) {
535 ar = arrays[i].array;
536 if (verbose)
537 printf("Adding array %u to volume %u\n", ar->array_ref,
538 ld->properties.ld.v.target_id);
539 ld->span[i].start_block = 0;
540 ld->span[i].num_blocks = ar->size;
541 ld->span[i].array_ref = ar->array_ref;
542 }
543 }
544
545 static int
create_volume(int ac,char ** av)546 create_volume(int ac, char **av)
547 {
548 struct mfi_config_data *config;
549 struct mfi_array *ar;
550 struct mfi_ld_config *ld;
551 struct config_id_state state;
552 size_t config_size;
553 char *p, *cfg_arrays, *cfg_volumes;
554 int error, fd, i, raid_type;
555 int narrays, nvolumes, arrays_per_volume;
556 struct array_info *arrays;
557 long stripe_size;
558 #ifdef DEBUG
559 int dump;
560 #endif
561 int ch, verbose;
562
563 /*
564 * Backwards compat. Map 'create volume' to 'create' and
565 * 'create spare' to 'add'.
566 */
567 if (ac > 1) {
568 if (strcmp(av[1], "volume") == 0) {
569 av++;
570 ac--;
571 } else if (strcmp(av[1], "spare") == 0) {
572 av++;
573 ac--;
574 return (add_spare(ac, av));
575 }
576 }
577
578 if (ac < 2) {
579 warnx("create volume: volume type required");
580 return (EINVAL);
581 }
582
583 bzero(&state, sizeof(state));
584 config = NULL;
585 arrays = NULL;
586 narrays = 0;
587 error = 0;
588
589 fd = mfi_open(mfi_device, O_RDWR);
590 if (fd < 0) {
591 error = errno;
592 warn("mfi_open");
593 return (error);
594 }
595
596 if (!mfi_reconfig_supported(mfi_device)) {
597 warnx("The current %s(4) driver does not support "
598 "configuration changes.", mfi_device);
599 error = EOPNOTSUPP;
600 goto error;
601 }
602
603 /* Lookup the RAID type first. */
604 raid_type = -1;
605 for (i = 0; raid_type_table[i].name != NULL; i++)
606 if (strcasecmp(raid_type_table[i].name, av[1]) == 0) {
607 raid_type = raid_type_table[i].raid_type;
608 break;
609 }
610
611 if (raid_type == -1) {
612 warnx("Unknown or unsupported volume type %s", av[1]);
613 error = EINVAL;
614 goto error;
615 }
616
617 /* Parse any options. */
618 optind = 2;
619 #ifdef DEBUG
620 dump = 0;
621 #endif
622 verbose = 0;
623 stripe_size = 64 * 1024;
624
625 while ((ch = getopt(ac, av, "ds:v")) != -1) {
626 switch (ch) {
627 #ifdef DEBUG
628 case 'd':
629 dump = 1;
630 break;
631 #endif
632 case 's':
633 stripe_size = dehumanize(optarg);
634 if ((stripe_size < 512) || (!powerof2(stripe_size)))
635 stripe_size = 64 * 1024;
636 break;
637 case 'v':
638 verbose = 1;
639 break;
640 case '?':
641 default:
642 error = EINVAL;
643 goto error;
644 }
645 }
646 ac -= optind;
647 av += optind;
648
649 /* Parse all the arrays. */
650 narrays = ac;
651 if (narrays == 0) {
652 warnx("At least one drive list is required");
653 error = EINVAL;
654 goto error;
655 }
656 switch (raid_type) {
657 case RT_RAID0:
658 case RT_RAID1:
659 case RT_RAID5:
660 case RT_RAID6:
661 case RT_CONCAT:
662 if (narrays != 1) {
663 warnx("Only one drive list can be specified");
664 error = EINVAL;
665 goto error;
666 }
667 break;
668 case RT_RAID10:
669 case RT_RAID50:
670 case RT_RAID60:
671 if (narrays < 1) {
672 warnx("RAID10, RAID50, and RAID60 require at least "
673 "two drive lists");
674 error = EINVAL;
675 goto error;
676 }
677 if (narrays > MFI_MAX_SPAN_DEPTH) {
678 warnx("Volume spans more than %d arrays",
679 MFI_MAX_SPAN_DEPTH);
680 error = EINVAL;
681 goto error;
682 }
683 break;
684 }
685 arrays = calloc(narrays, sizeof(*arrays));
686 if (arrays == NULL) {
687 warnx("malloc failed");
688 error = ENOMEM;
689 goto error;
690 }
691 for (i = 0; i < narrays; i++) {
692 error = parse_array(fd, raid_type, av[i], &arrays[i]);
693 if (error)
694 goto error;
695 }
696
697 switch (raid_type) {
698 case RT_RAID10:
699 case RT_RAID50:
700 case RT_RAID60:
701 for (i = 1; i < narrays; i++) {
702 if (arrays[i].drive_count != arrays[0].drive_count) {
703 warnx("All arrays must contain the same "
704 "number of drives");
705 error = EINVAL;
706 goto error;
707 }
708 }
709 break;
710 }
711
712 /*
713 * Fetch the current config and build sorted lists of existing
714 * array and volume identifiers.
715 */
716 if (mfi_config_read(fd, &config) < 0) {
717 error = errno;
718 warn("Failed to read configuration");
719 goto error;
720 }
721 p = (char *)config->array;
722 state.array_ref = 0xffff;
723 state.target_id = 0xff;
724 state.array_count = config->array_count;
725 if (config->array_count > 0) {
726 state.arrays = calloc(config->array_count, sizeof(int));
727 if (state.arrays == NULL) {
728 warnx("malloc failed");
729 error = ENOMEM;
730 goto error;
731 }
732 for (i = 0; i < config->array_count; i++) {
733 ar = (struct mfi_array *)p;
734 state.arrays[i] = ar->array_ref;
735 p += config->array_size;
736 }
737 qsort(state.arrays, config->array_count, sizeof(int),
738 compare_int);
739 } else
740 state.arrays = NULL;
741 state.log_drv_count = config->log_drv_count;
742 if (config->log_drv_count) {
743 state.volumes = calloc(config->log_drv_count, sizeof(int));
744 if (state.volumes == NULL) {
745 warnx("malloc failed");
746 error = ENOMEM;
747 goto error;
748 }
749 for (i = 0; i < config->log_drv_count; i++) {
750 ld = (struct mfi_ld_config *)p;
751 state.volumes[i] = ld->properties.ld.v.target_id;
752 p += config->log_drv_size;
753 }
754 qsort(state.volumes, config->log_drv_count, sizeof(int),
755 compare_int);
756 } else
757 state.volumes = NULL;
758 free(config);
759
760 /* Determine the size of the configuration we will build. */
761 switch (raid_type) {
762 case RT_RAID0:
763 case RT_RAID1:
764 case RT_RAID5:
765 case RT_RAID6:
766 case RT_CONCAT:
767 case RT_JBOD:
768 /* Each volume spans a single array. */
769 nvolumes = narrays;
770 break;
771 case RT_RAID10:
772 case RT_RAID50:
773 case RT_RAID60:
774 /* A single volume spans multiple arrays. */
775 nvolumes = 1;
776 break;
777 default:
778 /* Pacify gcc. */
779 abort();
780 }
781
782 config_size = sizeof(struct mfi_config_data) +
783 sizeof(struct mfi_ld_config) * nvolumes + MFI_ARRAY_SIZE * narrays;
784 config = calloc(1, config_size);
785 if (config == NULL) {
786 warnx("malloc failed");
787 error = ENOMEM;
788 goto error;
789 }
790 config->size = config_size;
791 config->array_count = narrays;
792 config->array_size = MFI_ARRAY_SIZE; /* XXX: Firmware hardcode */
793 config->log_drv_count = nvolumes;
794 config->log_drv_size = sizeof(struct mfi_ld_config);
795 config->spares_count = 0;
796 config->spares_size = 40; /* XXX: Firmware hardcode */
797 cfg_arrays = (char *)config->array;
798 cfg_volumes = cfg_arrays + config->array_size * narrays;
799
800 /* Build the arrays. */
801 for (i = 0; i < narrays; i++) {
802 build_array(fd, cfg_arrays, &arrays[i], &state, verbose);
803 cfg_arrays += config->array_size;
804 }
805
806 /* Now build the volume(s). */
807 arrays_per_volume = narrays / nvolumes;
808 for (i = 0; i < nvolumes; i++) {
809 build_volume(cfg_volumes, arrays_per_volume,
810 &arrays[i * arrays_per_volume], raid_type, stripe_size,
811 &state, verbose);
812 cfg_volumes += config->log_drv_size;
813 }
814
815 #ifdef DEBUG
816 if (dump)
817 dump_config(fd, config, NULL);
818 #endif
819
820 /* Send the new config to the controller. */
821 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_ADD, config, config_size,
822 NULL, 0, NULL) < 0) {
823 error = errno;
824 warn("Failed to add volume");
825 /* FALLTHROUGH */
826 }
827
828 error:
829 /* Clean up. */
830 free(config);
831 free(state.volumes);
832 free(state.arrays);
833 if (arrays != NULL) {
834 for (i = 0; i < narrays; i++)
835 free(arrays[i].drives);
836 free(arrays);
837 }
838 close(fd);
839
840 return (error);
841 }
842 MFI_COMMAND(top, create, create_volume);
843
844 static int
delete_volume(int ac,char ** av)845 delete_volume(int ac, char **av)
846 {
847 struct mfi_ld_info info;
848 int error, fd;
849 uint8_t target_id, mbox[4];
850
851 /*
852 * Backwards compat. Map 'delete volume' to 'delete' and
853 * 'delete spare' to 'remove'.
854 */
855 if (ac > 1) {
856 if (strcmp(av[1], "volume") == 0) {
857 av++;
858 ac--;
859 } else if (strcmp(av[1], "spare") == 0) {
860 av++;
861 ac--;
862 return (remove_spare(ac, av));
863 }
864 }
865
866 if (ac != 2) {
867 warnx("delete volume: volume required");
868 return (EINVAL);
869 }
870
871 fd = mfi_open(mfi_device, O_RDWR);
872 if (fd < 0) {
873 error = errno;
874 warn("mfi_open");
875 return (error);
876 }
877
878 if (!mfi_reconfig_supported(mfi_device)) {
879 warnx("The current %s(4) driver does not support "
880 "configuration changes.", mfi_device);
881 close(fd);
882 return (EOPNOTSUPP);
883 }
884
885 if (mfi_lookup_volume(fd, av[1], &target_id) < 0) {
886 error = errno;
887 warn("Invalid volume %s", av[1]);
888 close(fd);
889 return (error);
890 }
891
892 if (mfi_ld_get_info(fd, target_id, &info, NULL) < 0) {
893 error = errno;
894 warn("Failed to get info for volume %d", target_id);
895 close(fd);
896 return (error);
897 }
898
899 if (mfi_volume_busy(fd, target_id)) {
900 warnx("Volume %s is busy and cannot be deleted",
901 mfi_volume_name(fd, target_id));
902 close(fd);
903 return (EBUSY);
904 }
905
906 mbox_store_ldref(mbox, &info.ld_config.properties.ld);
907 if (mfi_dcmd_command(fd, MFI_DCMD_LD_DELETE, NULL, 0, mbox,
908 sizeof(mbox), NULL) < 0) {
909 error = errno;
910 warn("Failed to delete volume");
911 close(fd);
912 return (error);
913 }
914
915 close(fd);
916
917 return (0);
918 }
919 MFI_COMMAND(top, delete, delete_volume);
920
921 static int
add_spare(int ac,char ** av)922 add_spare(int ac, char **av)
923 {
924 struct mfi_pd_info info;
925 struct mfi_config_data *config;
926 struct mfi_array *ar;
927 struct mfi_ld_config *ld;
928 struct mfi_spare *spare;
929 uint16_t device_id;
930 uint8_t target_id;
931 char *p;
932 int error, fd, i;
933
934 if (ac < 2) {
935 warnx("add spare: drive required");
936 return (EINVAL);
937 }
938
939 fd = mfi_open(mfi_device, O_RDWR);
940 if (fd < 0) {
941 error = errno;
942 warn("mfi_open");
943 return (error);
944 }
945
946 config = NULL;
947 spare = NULL;
948 error = mfi_lookup_drive(fd, av[1], &device_id);
949 if (error)
950 goto error;
951
952 if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
953 error = errno;
954 warn("Failed to fetch drive info");
955 goto error;
956 }
957
958 if (info.fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
959 warnx("Drive %u is not available", device_id);
960 error = EINVAL;
961 goto error;
962 }
963
964 if (ac > 2) {
965 if (mfi_lookup_volume(fd, av[2], &target_id) < 0) {
966 error = errno;
967 warn("Invalid volume %s", av[2]);
968 goto error;
969 }
970 }
971
972 if (mfi_config_read(fd, &config) < 0) {
973 error = errno;
974 warn("Failed to read configuration");
975 goto error;
976 }
977
978 spare = malloc(sizeof(struct mfi_spare) + sizeof(uint16_t) *
979 config->array_count);
980 if (spare == NULL) {
981 warnx("malloc failed");
982 error = ENOMEM;
983 goto error;
984 }
985 bzero(spare, sizeof(struct mfi_spare));
986 spare->ref = info.ref;
987
988 if (ac == 2) {
989 /* Global spare backs all arrays. */
990 p = (char *)config->array;
991 for (i = 0; i < config->array_count; i++) {
992 ar = (struct mfi_array *)p;
993 if (ar->size > info.coerced_size) {
994 warnx("Spare isn't large enough for array %u",
995 ar->array_ref);
996 error = EINVAL;
997 goto error;
998 }
999 p += config->array_size;
1000 }
1001 spare->array_count = 0;
1002 } else {
1003 /*
1004 * Dedicated spares only back the arrays for a
1005 * specific volume.
1006 */
1007 ld = mfi_config_lookup_volume(config, target_id);
1008 if (ld == NULL) {
1009 warnx("Did not find volume %d", target_id);
1010 error = EINVAL;
1011 goto error;
1012 }
1013
1014 spare->spare_type |= MFI_SPARE_DEDICATED;
1015 spare->array_count = ld->params.span_depth;
1016 for (i = 0; i < ld->params.span_depth; i++) {
1017 ar = mfi_config_lookup_array(config,
1018 ld->span[i].array_ref);
1019 if (ar == NULL) {
1020 warnx("Missing array; inconsistent config?");
1021 error = ENXIO;
1022 goto error;
1023 }
1024 if (ar->size > info.coerced_size) {
1025 warnx("Spare isn't large enough for array %u",
1026 ar->array_ref);
1027 error = EINVAL;
1028 goto error;
1029 }
1030 spare->array_ref[i] = ar->array_ref;
1031 }
1032 }
1033
1034 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_MAKE_SPARE, spare,
1035 sizeof(struct mfi_spare) + sizeof(uint16_t) * spare->array_count,
1036 NULL, 0, NULL) < 0) {
1037 error = errno;
1038 warn("Failed to assign spare");
1039 /* FALLTHROUGH. */
1040 }
1041
1042 error:
1043 free(spare);
1044 free(config);
1045 close(fd);
1046
1047 return (error);
1048 }
1049 MFI_COMMAND(top, add, add_spare);
1050
1051 static int
remove_spare(int ac,char ** av)1052 remove_spare(int ac, char **av)
1053 {
1054 struct mfi_pd_info info;
1055 int error, fd;
1056 uint16_t device_id;
1057 uint8_t mbox[4];
1058
1059 if (ac != 2) {
1060 warnx("remove spare: drive required");
1061 return (EINVAL);
1062 }
1063
1064 fd = mfi_open(mfi_device, O_RDWR);
1065 if (fd < 0) {
1066 error = errno;
1067 warn("mfi_open");
1068 return (error);
1069 }
1070
1071 error = mfi_lookup_drive(fd, av[1], &device_id);
1072 if (error) {
1073 close(fd);
1074 return (error);
1075 }
1076
1077 /* Get the info for this drive. */
1078 if (mfi_pd_get_info(fd, device_id, &info, NULL) < 0) {
1079 error = errno;
1080 warn("Failed to fetch info for drive %u", device_id);
1081 close(fd);
1082 return (error);
1083 }
1084
1085 if (info.fw_state != MFI_PD_STATE_HOT_SPARE) {
1086 warnx("Drive %u is not a hot spare", device_id);
1087 close(fd);
1088 return (EINVAL);
1089 }
1090
1091 mbox_store_pdref(mbox, &info.ref);
1092 if (mfi_dcmd_command(fd, MFI_DCMD_CFG_REMOVE_SPARE, NULL, 0, mbox,
1093 sizeof(mbox), NULL) < 0) {
1094 error = errno;
1095 warn("Failed to delete spare");
1096 close(fd);
1097 return (error);
1098 }
1099
1100 close(fd);
1101
1102 return (0);
1103 }
1104 MFI_COMMAND(top, remove, remove_spare);
1105
1106 /* Display raw data about a config. */
1107 void
dump_config(int fd,struct mfi_config_data * config,const char * msg_prefix)1108 dump_config(int fd, struct mfi_config_data *config, const char *msg_prefix)
1109 {
1110 struct mfi_array *ar;
1111 struct mfi_ld_config *ld;
1112 struct mfi_spare *sp;
1113 struct mfi_pd_info pinfo;
1114 uint16_t device_id;
1115 char *p;
1116 int i, j;
1117
1118 if (NULL == msg_prefix)
1119 msg_prefix = "Configuration (Debug)";
1120
1121 printf(
1122 "%s %s: %d arrays, %d volumes, %d spares\n", mfi_device,
1123 msg_prefix, config->array_count, config->log_drv_count,
1124 config->spares_count);
1125 printf(" array size: %u\n", config->array_size);
1126 printf(" volume size: %u\n", config->log_drv_size);
1127 printf(" spare size: %u\n", config->spares_size);
1128 p = (char *)config->array;
1129
1130 for (i = 0; i < config->array_count; i++) {
1131 ar = (struct mfi_array *)p;
1132 printf(" array %u of %u drives:\n", ar->array_ref,
1133 ar->num_drives);
1134 printf(" size = %ju\n", (uintmax_t)ar->size);
1135 for (j = 0; j < ar->num_drives; j++) {
1136 device_id = ar->pd[j].ref.v.device_id;
1137 if (device_id == 0xffff)
1138 printf(" drive MISSING\n");
1139 else {
1140 printf(" drive %u %s\n", device_id,
1141 mfi_pdstate(ar->pd[j].fw_state));
1142 if (mfi_pd_get_info(fd, device_id, &pinfo,
1143 NULL) >= 0) {
1144 printf(" raw size: %ju\n",
1145 (uintmax_t)pinfo.raw_size);
1146 printf(" non-coerced size: %ju\n",
1147 (uintmax_t)pinfo.non_coerced_size);
1148 printf(" coerced size: %ju\n",
1149 (uintmax_t)pinfo.coerced_size);
1150 }
1151 }
1152 }
1153 p += config->array_size;
1154 }
1155
1156 for (i = 0; i < config->log_drv_count; i++) {
1157 ld = (struct mfi_ld_config *)p;
1158 printf(" volume %s ",
1159 mfi_volume_name(fd, ld->properties.ld.v.target_id));
1160 printf("%s %s",
1161 mfi_raid_level(ld->params.primary_raid_level,
1162 ld->params.secondary_raid_level),
1163 mfi_ldstate(ld->params.state));
1164 if (ld->properties.name[0] != '\0')
1165 printf(" <%s>", ld->properties.name);
1166 printf("\n");
1167 printf(" primary raid level: %u\n",
1168 ld->params.primary_raid_level);
1169 printf(" raid level qualifier: %u\n",
1170 ld->params.raid_level_qualifier);
1171 printf(" secondary raid level: %u\n",
1172 ld->params.secondary_raid_level);
1173 printf(" stripe size: %u\n", ld->params.stripe_size);
1174 printf(" num drives: %u\n", ld->params.num_drives);
1175 printf(" init state: %u\n", ld->params.init_state);
1176 printf(" consistent: %u\n", ld->params.is_consistent);
1177 printf(" no bgi: %u\n", ld->properties.no_bgi);
1178 printf(" spans:\n");
1179 for (j = 0; j < ld->params.span_depth; j++) {
1180 printf(" array %u @ ", ld->span[j].array_ref);
1181 printf("%ju : %ju\n",
1182 (uintmax_t)ld->span[j].start_block,
1183 (uintmax_t)ld->span[j].num_blocks);
1184 }
1185 p += config->log_drv_size;
1186 }
1187
1188 for (i = 0; i < config->spares_count; i++) {
1189 sp = (struct mfi_spare *)p;
1190 printf(" %s spare %u ",
1191 sp->spare_type & MFI_SPARE_DEDICATED ? "dedicated" :
1192 "global", sp->ref.v.device_id);
1193 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE));
1194 printf(" backs:\n");
1195 for (j = 0; j < sp->array_count; j++)
1196 printf(" array %u\n", sp->array_ref[j]);
1197 p += config->spares_size;
1198 }
1199 }
1200
1201 #ifdef DEBUG
1202 static int
debug_config(int ac,char ** av)1203 debug_config(int ac, char **av)
1204 {
1205 struct mfi_config_data *config;
1206 int error, fd;
1207
1208 if (ac != 1) {
1209 warnx("debug: extra arguments");
1210 return (EINVAL);
1211 }
1212
1213 fd = mfi_open(mfi_device, O_RDWR);
1214 if (fd < 0) {
1215 error = errno;
1216 warn("mfi_open");
1217 return (error);
1218 }
1219
1220 /* Get the config from the controller. */
1221 if (mfi_config_read(fd, &config) < 0) {
1222 error = errno;
1223 warn("Failed to get config");
1224 close(fd);
1225 return (error);
1226 }
1227
1228 /* Dump out the configuration. */
1229 dump_config(fd, config, NULL);
1230 free(config);
1231 close(fd);
1232
1233 return (0);
1234 }
1235 MFI_COMMAND(top, debug, debug_config);
1236
1237 static int
dump(int ac,char ** av)1238 dump(int ac, char **av)
1239 {
1240 struct mfi_config_data *config;
1241 char buf[64];
1242 size_t len;
1243 int error, fd;
1244
1245 if (ac != 1) {
1246 warnx("dump: extra arguments");
1247 return (EINVAL);
1248 }
1249
1250 fd = mfi_open(mfi_device, O_RDWR);
1251 if (fd < 0) {
1252 error = errno;
1253 warn("mfi_open");
1254 return (error);
1255 }
1256
1257 /* Get the stashed copy of the last dcmd from the driver. */
1258 snprintf(buf, sizeof(buf), "dev.mfi.%d.debug_command", mfi_unit);
1259 if (sysctlbyname(buf, NULL, &len, NULL, 0) < 0) {
1260 error = errno;
1261 warn("Failed to read debug command");
1262 if (error == ENOENT)
1263 error = EOPNOTSUPP;
1264 close(fd);
1265 return (error);
1266 }
1267
1268 config = malloc(len);
1269 if (config == NULL) {
1270 warnx("malloc failed");
1271 close(fd);
1272 return (ENOMEM);
1273 }
1274 if (sysctlbyname(buf, config, &len, NULL, 0) < 0) {
1275 error = errno;
1276 warn("Failed to read debug command");
1277 free(config);
1278 close(fd);
1279 return (error);
1280 }
1281 dump_config(fd, config, NULL);
1282 free(config);
1283 close(fd);
1284
1285 return (0);
1286 }
1287 MFI_COMMAND(top, dump, dump);
1288 #endif
1289