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