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