2 * Copyright (c) 2008, 2009 Yahoo!, Inc.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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
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
29 * $FreeBSD: src/usr.sbin/mfiutil/mfi_config.c,v 1.8 2011/11/29 08:16:14 delphij Exp $
32 #include <sys/param.h>
34 #include <sys/sysctl.h>
46 static int add_spare(int ac
, char **av
);
47 static int remove_spare(int ac
, char **av
);
50 mfi_config_read(int fd
, struct mfi_config_data
**configp
)
52 return mfi_config_read_opcode(fd
, MFI_DCMD_CFG_READ
, configp
, NULL
, 0);
56 mfi_config_read_opcode(int fd
, uint32_t opcode
,
57 struct mfi_config_data
**configp
, uint8_t *mbox
, size_t mboxlen
)
59 struct mfi_config_data
*config
;
64 * Keep fetching the config in a loop until we have a large enough
65 * buffer to hold the entire configuration.
70 config
= reallocf(config
, config_size
);
73 if (mfi_dcmd_command(fd
, opcode
, config
,
74 config_size
, mbox
, mboxlen
, NULL
) < 0) {
81 if (config
->size
> config_size
) {
82 config_size
= config
->size
;
90 static struct mfi_array
*
91 mfi_config_lookup_array(struct mfi_config_data
*config
, uint16_t array_ref
)
97 p
= (char *)config
->array
;
98 for (i
= 0; i
< config
->array_count
; i
++) {
99 ar
= (struct mfi_array
*)p
;
100 if (ar
->array_ref
== array_ref
)
102 p
+= config
->array_size
;
108 static struct mfi_ld_config
*
109 mfi_config_lookup_volume(struct mfi_config_data
*config
, uint8_t target_id
)
111 struct mfi_ld_config
*ld
;
115 p
= (char *)config
->array
+ config
->array_count
* config
->array_size
;
116 for (i
= 0; i
< config
->log_drv_count
; i
++) {
117 ld
= (struct mfi_ld_config
*)p
;
118 if (ld
->properties
.ld
.v
.target_id
== target_id
)
120 p
+= config
->log_drv_size
;
127 clear_config(__unused
int ac
, __unused
char **av
)
129 struct mfi_ld_list list
;
133 fd
= mfi_open(mfi_unit
);
140 if (!mfi_reconfig_supported()) {
141 warnx("The current mfi(4) driver does not support "
142 "configuration changes.");
147 if (mfi_ld_get_list(fd
, &list
, NULL
) < 0) {
149 warn("Failed to get volume list");
154 for (i
= 0; i
< list
.ld_count
; i
++) {
155 if (mfi_volume_busy(fd
, list
.ld_list
[i
].ld
.v
.target_id
)) {
156 warnx("Volume %s is busy and cannot be deleted",
157 mfi_volume_name(fd
, list
.ld_list
[i
].ld
.v
.target_id
));
164 "Are you sure you wish to clear the configuration on mfi%u? [y/N] ",
167 if (ch
!= 'y' && ch
!= 'Y') {
168 printf("\nAborting\n");
173 if (mfi_dcmd_command(fd
, MFI_DCMD_CFG_CLEAR
, NULL
, 0, NULL
, 0, NULL
) < 0) {
175 warn("Failed to clear configuration");
180 printf("mfi%d: Configuration cleared\n", mfi_unit
);
185 MFI_COMMAND(top
, clear
, clear_config
);
187 #define MFI_ARRAY_SIZE 288
188 #define MAX_DRIVES_PER_ARRAY \
189 ((MFI_ARRAY_SIZE - sizeof(struct mfi_array)) / 8)
202 compare_int(const void *one
, const void *two
)
206 first
= *(const int *)one
;
207 second
= *(const int *)two
;
209 return (first
- second
);
212 static struct raid_type_entry
{
215 } raid_type_table
[] = {
216 { "raid0", RT_RAID0
},
217 { "raid-0", RT_RAID0
},
218 { "raid1", RT_RAID1
},
219 { "raid-1", RT_RAID1
},
220 { "mirror", RT_RAID1
},
221 { "raid5", RT_RAID5
},
222 { "raid-5", RT_RAID5
},
223 { "raid6", RT_RAID6
},
224 { "raid-6", RT_RAID6
},
226 { "concat", RT_CONCAT
},
227 { "raid10", RT_RAID10
},
228 { "raid1+0", RT_RAID10
},
229 { "raid-10", RT_RAID10
},
230 { "raid-1+0", RT_RAID10
},
231 { "raid50", RT_RAID50
},
232 { "raid5+0", RT_RAID50
},
233 { "raid-50", RT_RAID50
},
234 { "raid-5+0", RT_RAID50
},
235 { "raid60", RT_RAID60
},
236 { "raid6+0", RT_RAID60
},
237 { "raid-60", RT_RAID60
},
238 { "raid-6+0", RT_RAID60
},
242 struct config_id_state
{
253 struct mfi_pd_info
*drives
;
254 struct mfi_array
*array
;
257 /* Parse a comma-separated list of drives for an array. */
259 parse_array(int fd
, int raid_type
, char *array_str
, struct array_info
*info
)
261 struct mfi_pd_info
*pinfo
;
268 for (count
= 0; cp
!= NULL
; count
++) {
269 cp
= strchr(cp
, ',');
273 warnx("Invalid drive list '%s'", array_str
);
279 /* Validate the number of drives for this array. */
280 if (count
>= MAX_DRIVES_PER_ARRAY
) {
281 warnx("Too many drives for a single array: max is %zu",
282 MAX_DRIVES_PER_ARRAY
);
288 if (count
% 2 != 0) {
289 warnx("RAID1 and RAID10 require an even number of "
290 "drives in each array");
297 warnx("RAID5 and RAID50 require at least 3 drives in "
305 warnx("RAID6 and RAID60 require at least 4 drives in "
312 /* Validate each drive. */
313 info
->drives
= calloc(count
, sizeof(struct mfi_pd_info
));
314 if (info
->drives
== NULL
) {
315 warnx("malloc failed");
318 info
->drive_count
= count
;
319 for (pinfo
= info
->drives
; (cp
= strsep(&array_str
, ",")) != NULL
;
321 error
= mfi_lookup_drive(fd
, cp
, &device_id
);
328 if (mfi_pd_get_info(fd
, device_id
, pinfo
, NULL
) < 0) {
330 warn("Failed to fetch drive info for drive %s", cp
);
336 if (pinfo
->fw_state
!= MFI_PD_STATE_UNCONFIGURED_GOOD
) {
337 warnx("Drive %u is not available", device_id
);
343 if (pinfo
->state
.ddf
.v
.pd_type
.is_foreign
) {
344 warnx("Drive %u is foreign", device_id
);
355 * Find the next free array ref assuming that 'array_ref' is the last
356 * one used. 'array_ref' should be 0xffff for the initial test.
359 find_next_array(struct config_id_state
*state
)
363 /* Assume the current one is used. */
366 /* Find the next free one. */
367 for (i
= 0; i
< state
->array_count
; i
++)
368 if (state
->arrays
[i
] == state
->array_ref
)
370 return (state
->array_ref
);
374 * Find the next free volume ID assuming that 'target_id' is the last
375 * one used. 'target_id' should be 0xff for the initial test.
378 find_next_volume(struct config_id_state
*state
)
382 /* Assume the current one is used. */
385 /* Find the next free one. */
386 for (i
= 0; i
< state
->log_drv_count
; i
++)
387 if (state
->volumes
[i
] == state
->target_id
)
389 return (state
->target_id
);
392 /* Populate an array with drives. */
394 build_array(__unused
int fd
, char *arrayp
, struct array_info
*array_info
,
395 struct config_id_state
*state
, int verbose
)
397 struct mfi_array
*ar
= (struct mfi_array
*)arrayp
;
400 ar
->size
= array_info
->drives
[0].coerced_size
;
401 ar
->num_drives
= array_info
->drive_count
;
402 ar
->array_ref
= find_next_array(state
);
403 for (i
= 0; i
< array_info
->drive_count
; i
++) {
405 printf("Adding drive %s to array %u\n",
407 array_info
->drives
[i
].ref
.v
.device_id
,
408 MFI_DNAME_DEVICE_ID
|MFI_DNAME_HONOR_OPTS
),
410 if (ar
->size
> array_info
->drives
[i
].coerced_size
)
411 ar
->size
= array_info
->drives
[i
].coerced_size
;
412 ar
->pd
[i
].ref
= array_info
->drives
[i
].ref
;
413 ar
->pd
[i
].fw_state
= MFI_PD_STATE_ONLINE
;
415 array_info
->array
= ar
;
419 * Create a volume that spans one or more arrays.
422 build_volume(char *volumep
, int narrays
, struct array_info
*arrays
,
423 int raid_type
, long stripe_size
, struct config_id_state
*state
, int verbose
)
425 struct mfi_ld_config
*ld
= (struct mfi_ld_config
*)volumep
;
426 struct mfi_array
*ar
;
430 ld
->properties
.ld
.v
.target_id
= find_next_volume(state
);
431 ld
->properties
.ld
.v
.seq
= 0;
432 ld
->properties
.default_cache_policy
= MR_LD_CACHE_ALLOW_WRITE_CACHE
|
433 MR_LD_CACHE_WRITE_BACK
;
434 ld
->properties
.access_policy
= MFI_LD_ACCESS_RW
;
435 ld
->properties
.disk_cache_policy
= MR_PD_CACHE_UNCHANGED
;
436 ld
->properties
.current_cache_policy
= MR_LD_CACHE_ALLOW_WRITE_CACHE
|
437 MR_LD_CACHE_WRITE_BACK
;
438 ld
->properties
.no_bgi
= 0;
444 ld
->params
.primary_raid_level
= DDF_RAID0
;
445 ld
->params
.raid_level_qualifier
= 0;
446 ld
->params
.secondary_raid_level
= 0;
449 ld
->params
.primary_raid_level
= DDF_RAID1
;
450 ld
->params
.raid_level_qualifier
= 0;
451 ld
->params
.secondary_raid_level
= 0;
454 ld
->params
.primary_raid_level
= DDF_RAID5
;
455 ld
->params
.raid_level_qualifier
= 3;
456 ld
->params
.secondary_raid_level
= 0;
459 ld
->params
.primary_raid_level
= DDF_RAID6
;
460 ld
->params
.raid_level_qualifier
= 3;
461 ld
->params
.secondary_raid_level
= 0;
464 ld
->params
.primary_raid_level
= DDF_CONCAT
;
465 ld
->params
.raid_level_qualifier
= 0;
466 ld
->params
.secondary_raid_level
= 0;
469 ld
->params
.primary_raid_level
= DDF_RAID1
;
470 ld
->params
.raid_level_qualifier
= 0;
471 ld
->params
.secondary_raid_level
= 3; /* XXX? */
475 * XXX: This appears to work though the card's BIOS
476 * complains that the configuration is foreign. The
477 * BIOS setup does not allow for creation of RAID-50
478 * or RAID-60 arrays. The only nested array
479 * configuration it allows for is RAID-10.
481 ld
->params
.primary_raid_level
= DDF_RAID5
;
482 ld
->params
.raid_level_qualifier
= 3;
483 ld
->params
.secondary_raid_level
= 3; /* XXX? */
486 ld
->params
.primary_raid_level
= DDF_RAID6
;
487 ld
->params
.raid_level_qualifier
= 3;
488 ld
->params
.secondary_raid_level
= 3; /* XXX? */
493 * Stripe size is encoded as (2 ^ N) * 512 = stripe_size. Use
494 * ffs() to simulate log2(stripe_size).
496 ld
->params
.stripe_size
= ffs(stripe_size
) - 1 - 9;
497 ld
->params
.num_drives
= arrays
[0].array
->num_drives
;
498 ld
->params
.span_depth
= narrays
;
499 ld
->params
.state
= MFI_LD_STATE_OPTIMAL
;
500 ld
->params
.init_state
= MFI_LD_PARAMS_INIT_NO
;
501 ld
->params
.is_consistent
= 0;
504 for (i
= 0; i
< narrays
; i
++) {
505 ar
= arrays
[i
].array
;
507 printf("Adding array %u to volume %u\n", ar
->array_ref
,
508 ld
->properties
.ld
.v
.target_id
);
509 ld
->span
[i
].start_block
= 0;
510 ld
->span
[i
].num_blocks
= ar
->size
;
511 ld
->span
[i
].array_ref
= ar
->array_ref
;
516 create_volume(int ac
, char **av
)
518 struct mfi_config_data
*config
;
519 struct mfi_array
*ar
;
520 struct mfi_ld_config
*ld
;
521 struct config_id_state state
;
523 char *p
, *cfg_arrays
, *cfg_volumes
;
524 int error
, fd
, i
, raid_type
;
525 int narrays
, nvolumes
, arrays_per_volume
;
526 struct array_info
*arrays
;
534 * Backwards compat. Map 'create volume' to 'create' and
535 * 'create spare' to 'add'.
538 if (strcmp(av
[1], "volume") == 0) {
541 } else if (strcmp(av
[1], "spare") == 0) {
544 return (add_spare(ac
, av
));
549 warnx("create volume: volume type required");
553 bzero(&state
, sizeof(state
));
559 fd
= mfi_open(mfi_unit
);
566 if (!mfi_reconfig_supported()) {
567 warnx("The current mfi(4) driver does not support "
568 "configuration changes.");
573 /* Lookup the RAID type first. */
575 for (i
= 0; raid_type_table
[i
].name
!= NULL
; i
++)
576 if (strcasecmp(raid_type_table
[i
].name
, av
[1]) == 0) {
577 raid_type
= raid_type_table
[i
].raid_type
;
581 if (raid_type
== -1) {
582 warnx("Unknown or unsupported volume type %s", av
[1]);
587 /* Parse any options. */
593 stripe_size
= 64 * 1024;
595 while ((ch
= getopt(ac
, av
, "ds:v")) != -1) {
603 error
= dehumanize_number(optarg
, &stripe_size
);
605 warnx("Illegal stripe size");
608 if ((stripe_size
< 512) || (!powerof2(stripe_size
))) {
609 warnx("Illegal stripe size, using 64K");
610 stripe_size
= 64 * 1024;
625 /* Parse all the arrays. */
628 warnx("At least one drive list is required");
639 warnx("Only one drive list can be specified");
648 warnx("RAID10, RAID50, and RAID60 require at least "
653 if (narrays
> MFI_MAX_SPAN_DEPTH
) {
654 warnx("Volume spans more than %d arrays",
661 arrays
= calloc(narrays
, sizeof(*arrays
));
662 if (arrays
== NULL
) {
663 warnx("malloc failed");
667 for (i
= 0; i
< narrays
; i
++) {
668 error
= parse_array(fd
, raid_type
, av
[i
], &arrays
[i
]);
677 for (i
= 1; i
< narrays
; i
++) {
678 if (arrays
[i
].drive_count
!= arrays
[0].drive_count
) {
679 warnx("All arrays must contain the same "
689 * Fetch the current config and build sorted lists of existing
690 * array and volume identifiers.
692 if (mfi_config_read(fd
, &config
) < 0) {
694 warn("Failed to read configuration");
697 p
= (char *)config
->array
;
698 state
.array_ref
= 0xffff;
699 state
.target_id
= 0xff;
700 state
.array_count
= config
->array_count
;
701 if (config
->array_count
> 0) {
702 state
.arrays
= calloc(config
->array_count
, sizeof(int));
703 if (state
.arrays
== NULL
) {
704 warnx("malloc failed");
708 for (i
= 0; i
< config
->array_count
; i
++) {
709 ar
= (struct mfi_array
*)p
;
710 state
.arrays
[i
] = ar
->array_ref
;
711 p
+= config
->array_size
;
713 qsort(state
.arrays
, config
->array_count
, sizeof(int),
717 state
.log_drv_count
= config
->log_drv_count
;
718 if (config
->log_drv_count
) {
719 state
.volumes
= calloc(config
->log_drv_count
, sizeof(int));
720 if (state
.volumes
== NULL
) {
721 warnx("malloc failed");
725 for (i
= 0; i
< config
->log_drv_count
; i
++) {
726 ld
= (struct mfi_ld_config
*)p
;
727 state
.volumes
[i
] = ld
->properties
.ld
.v
.target_id
;
728 p
+= config
->log_drv_size
;
730 qsort(state
.volumes
, config
->log_drv_count
, sizeof(int),
733 state
.volumes
= NULL
;
736 /* Determine the size of the configuration we will build. */
744 /* Each volume spans a single array. */
750 /* A single volume spans multiple arrays. */
758 config_size
= sizeof(struct mfi_config_data
) +
759 sizeof(struct mfi_ld_config
) * nvolumes
+ MFI_ARRAY_SIZE
* narrays
;
760 config
= calloc(1, config_size
);
761 if (config
== NULL
) {
762 warnx("malloc failed");
766 config
->size
= config_size
;
767 config
->array_count
= narrays
;
768 config
->array_size
= MFI_ARRAY_SIZE
; /* XXX: Firmware hardcode */
769 config
->log_drv_count
= nvolumes
;
770 config
->log_drv_size
= sizeof(struct mfi_ld_config
);
771 config
->spares_count
= 0;
772 config
->spares_size
= 40; /* XXX: Firmware hardcode */
773 cfg_arrays
= (char *)config
->array
;
774 cfg_volumes
= cfg_arrays
+ config
->array_size
* narrays
;
776 /* Build the arrays. */
777 for (i
= 0; i
< narrays
; i
++) {
778 build_array(fd
, cfg_arrays
, &arrays
[i
], &state
, verbose
);
779 cfg_arrays
+= config
->array_size
;
782 /* Now build the volume(s). */
783 arrays_per_volume
= narrays
/ nvolumes
;
784 for (i
= 0; i
< nvolumes
; i
++) {
785 build_volume(cfg_volumes
, arrays_per_volume
,
786 &arrays
[i
* arrays_per_volume
], raid_type
, stripe_size
,
788 cfg_volumes
+= config
->log_drv_size
;
793 dump_config(fd
, config
, NULL
);
796 /* Send the new config to the controller. */
797 if (mfi_dcmd_command(fd
, MFI_DCMD_CFG_ADD
, config
, config_size
,
798 NULL
, 0, NULL
) < 0) {
800 warn("Failed to add volume");
809 if (arrays
!= NULL
) {
810 for (i
= 0; i
< narrays
; i
++)
811 free(arrays
[i
].drives
);
818 MFI_COMMAND(top
, create
, create_volume
);
821 delete_volume(int ac
, char **av
)
823 struct mfi_ld_info info
;
825 uint8_t target_id
, mbox
[4];
828 * Backwards compat. Map 'delete volume' to 'delete' and
829 * 'delete spare' to 'remove'.
832 if (strcmp(av
[1], "volume") == 0) {
835 } else if (strcmp(av
[1], "spare") == 0) {
838 return (remove_spare(ac
, av
));
843 warnx("delete volume: volume required");
847 fd
= mfi_open(mfi_unit
);
854 if (!mfi_reconfig_supported()) {
855 warnx("The current mfi(4) driver does not support "
856 "configuration changes.");
861 if (mfi_lookup_volume(fd
, av
[1], &target_id
) < 0) {
863 warn("Invalid volume %s", av
[1]);
868 if (mfi_ld_get_info(fd
, target_id
, &info
, NULL
) < 0) {
870 warn("Failed to get info for volume %d", target_id
);
875 if (mfi_volume_busy(fd
, target_id
)) {
876 warnx("Volume %s is busy and cannot be deleted",
877 mfi_volume_name(fd
, target_id
));
882 mbox_store_ldref(mbox
, &info
.ld_config
.properties
.ld
);
883 if (mfi_dcmd_command(fd
, MFI_DCMD_LD_DELETE
, NULL
, 0, mbox
,
884 sizeof(mbox
), NULL
) < 0) {
886 warn("Failed to delete volume");
895 MFI_COMMAND(top
, delete, delete_volume
);
898 add_spare(int ac
, char **av
)
900 struct mfi_pd_info info
;
901 struct mfi_config_data
*config
;
902 struct mfi_array
*ar
;
903 struct mfi_ld_config
*ld
;
904 struct mfi_spare
*spare
;
911 warnx("add spare: drive required");
915 fd
= mfi_open(mfi_unit
);
924 error
= mfi_lookup_drive(fd
, av
[1], &device_id
);
928 if (mfi_pd_get_info(fd
, device_id
, &info
, NULL
) < 0) {
930 warn("Failed to fetch drive info");
934 if (info
.fw_state
!= MFI_PD_STATE_UNCONFIGURED_GOOD
) {
935 warnx("Drive %u is not available", device_id
);
941 if (mfi_lookup_volume(fd
, av
[2], &target_id
) < 0) {
943 warn("Invalid volume %s", av
[2]);
948 if (mfi_config_read(fd
, &config
) < 0) {
950 warn("Failed to read configuration");
954 spare
= malloc(sizeof(struct mfi_spare
) + sizeof(uint16_t) *
955 config
->array_count
);
957 warnx("malloc failed");
961 bzero(spare
, sizeof(struct mfi_spare
));
962 spare
->ref
= info
.ref
;
965 /* Global spare backs all arrays. */
966 p
= (char *)config
->array
;
967 for (i
= 0; i
< config
->array_count
; i
++) {
968 ar
= (struct mfi_array
*)p
;
969 if (ar
->size
> info
.coerced_size
) {
970 warnx("Spare isn't large enough for array %u",
975 p
+= config
->array_size
;
977 spare
->array_count
= 0;
980 * Dedicated spares only back the arrays for a
983 ld
= mfi_config_lookup_volume(config
, target_id
);
985 warnx("Did not find volume %d", target_id
);
990 spare
->spare_type
|= MFI_SPARE_DEDICATED
;
991 spare
->array_count
= ld
->params
.span_depth
;
992 for (i
= 0; i
< ld
->params
.span_depth
; i
++) {
993 ar
= mfi_config_lookup_array(config
,
994 ld
->span
[i
].array_ref
);
996 warnx("Missing array; inconsistent config?");
1000 if (ar
->size
> info
.coerced_size
) {
1001 warnx("Spare isn't large enough for array %u",
1006 spare
->array_ref
[i
] = ar
->array_ref
;
1010 if (mfi_dcmd_command(fd
, MFI_DCMD_CFG_MAKE_SPARE
, spare
,
1011 sizeof(struct mfi_spare
) + sizeof(uint16_t) * spare
->array_count
,
1012 NULL
, 0, NULL
) < 0) {
1014 warn("Failed to assign spare");
1025 MFI_COMMAND(top
, add
, add_spare
);
1028 remove_spare(int ac
, char **av
)
1030 struct mfi_pd_info info
;
1036 warnx("remove spare: drive required");
1040 fd
= mfi_open(mfi_unit
);
1047 error
= mfi_lookup_drive(fd
, av
[1], &device_id
);
1053 /* Get the info for this drive. */
1054 if (mfi_pd_get_info(fd
, device_id
, &info
, NULL
) < 0) {
1056 warn("Failed to fetch info for drive %u", device_id
);
1061 if (info
.fw_state
!= MFI_PD_STATE_HOT_SPARE
) {
1062 warnx("Drive %u is not a hot spare", device_id
);
1067 mbox_store_pdref(mbox
, &info
.ref
);
1068 if (mfi_dcmd_command(fd
, MFI_DCMD_CFG_REMOVE_SPARE
, NULL
, 0, mbox
,
1069 sizeof(mbox
), NULL
) < 0) {
1071 warn("Failed to delete spare");
1080 MFI_COMMAND(top
, remove
, remove_spare
);
1082 /* Display raw data about a config. */
1084 dump_config(int fd
, struct mfi_config_data
*config
, const char *msg_prefix
)
1086 struct mfi_array
*ar
;
1087 struct mfi_ld_config
*ld
;
1088 struct mfi_spare
*sp
;
1089 struct mfi_pd_info pinfo
;
1094 if (NULL
== msg_prefix
)
1095 msg_prefix
= "Configuration (Debug)";
1098 "mfi%d %s: %d arrays, %d volumes, %d spares\n", mfi_unit
,
1099 msg_prefix
, config
->array_count
, config
->log_drv_count
,
1100 config
->spares_count
);
1101 printf(" array size: %u\n", config
->array_size
);
1102 printf(" volume size: %u\n", config
->log_drv_size
);
1103 printf(" spare size: %u\n", config
->spares_size
);
1104 p
= (char *)config
->array
;
1106 for (i
= 0; i
< config
->array_count
; i
++) {
1107 ar
= (struct mfi_array
*)p
;
1108 printf(" array %u of %u drives:\n", ar
->array_ref
,
1110 printf(" size = %ju\n", (uintmax_t)ar
->size
);
1111 for (j
= 0; j
< ar
->num_drives
; j
++) {
1112 device_id
= ar
->pd
[j
].ref
.v
.device_id
;
1113 if (device_id
== 0xffff)
1114 printf(" drive MISSING\n");
1116 printf(" drive %u %s\n", device_id
,
1117 mfi_pdstate(ar
->pd
[j
].fw_state
));
1118 if (mfi_pd_get_info(fd
, device_id
, &pinfo
,
1120 printf(" raw size: %ju\n",
1121 (uintmax_t)pinfo
.raw_size
);
1122 printf(" non-coerced size: %ju\n",
1123 (uintmax_t)pinfo
.non_coerced_size
);
1124 printf(" coerced size: %ju\n",
1125 (uintmax_t)pinfo
.coerced_size
);
1129 p
+= config
->array_size
;
1132 for (i
= 0; i
< config
->log_drv_count
; i
++) {
1133 ld
= (struct mfi_ld_config
*)p
;
1134 printf(" volume %s ",
1135 mfi_volume_name(fd
, ld
->properties
.ld
.v
.target_id
));
1137 mfi_raid_level(ld
->params
.primary_raid_level
,
1138 ld
->params
.secondary_raid_level
),
1139 mfi_ldstate(ld
->params
.state
));
1140 if (ld
->properties
.name
[0] != '\0')
1141 printf(" <%s>", ld
->properties
.name
);
1143 printf(" primary raid level: %u\n",
1144 ld
->params
.primary_raid_level
);
1145 printf(" raid level qualifier: %u\n",
1146 ld
->params
.raid_level_qualifier
);
1147 printf(" secondary raid level: %u\n",
1148 ld
->params
.secondary_raid_level
);
1149 printf(" stripe size: %u\n", ld
->params
.stripe_size
);
1150 printf(" num drives: %u\n", ld
->params
.num_drives
);
1151 printf(" init state: %u\n", ld
->params
.init_state
);
1152 printf(" consistent: %u\n", ld
->params
.is_consistent
);
1153 printf(" no bgi: %u\n", ld
->properties
.no_bgi
);
1154 printf(" spans:\n");
1155 for (j
= 0; j
< ld
->params
.span_depth
; j
++) {
1156 printf(" array %u @ ", ld
->span
[j
].array_ref
);
1157 printf("%ju : %ju\n",
1158 (uintmax_t)ld
->span
[j
].start_block
,
1159 (uintmax_t)ld
->span
[j
].num_blocks
);
1161 p
+= config
->log_drv_size
;
1164 for (i
= 0; i
< config
->spares_count
; i
++) {
1165 sp
= (struct mfi_spare
*)p
;
1166 printf(" %s spare %u ",
1167 sp
->spare_type
& MFI_SPARE_DEDICATED
? "dedicated" :
1168 "global", sp
->ref
.v
.device_id
);
1169 printf("%s", mfi_pdstate(MFI_PD_STATE_HOT_SPARE
));
1170 printf(" backs:\n");
1171 for (j
= 0; j
< sp
->array_count
; j
++)
1172 printf(" array %u\n", sp
->array_ref
[j
]);
1173 p
+= config
->spares_size
;
1179 debug_config(int ac
, char **av
)
1181 struct mfi_config_data
*config
;
1185 warnx("debug: extra arguments");
1189 fd
= mfi_open(mfi_unit
);
1196 /* Get the config from the controller. */
1197 if (mfi_config_read(fd
, &config
) < 0) {
1199 warn("Failed to get config");
1204 /* Dump out the configuration. */
1205 dump_config(fd
, config
, NULL
);
1211 MFI_COMMAND(top
, debug
, debug_config
);
1214 dump(int ac
, char **av
)
1216 struct mfi_config_data
*config
;
1222 warnx("dump: extra arguments");
1226 fd
= mfi_open(mfi_unit
);
1233 /* Get the stashed copy of the last dcmd from the driver. */
1234 snprintf(buf
, sizeof(buf
), "hw.mfi%d.debug_command", mfi_unit
);
1235 if (sysctlbyname(buf
, NULL
, &len
, NULL
, 0) < 0) {
1237 warn("Failed to read debug command");
1238 if (error
== ENOENT
)
1244 config
= malloc(len
);
1245 if (config
== NULL
) {
1246 warnx("malloc failed");
1250 if (sysctlbyname(buf
, config
, &len
, NULL
, 0) < 0) {
1252 warn("Failed to read debug command");
1257 dump_config(fd
, config
, NULL
);
1263 MFI_COMMAND(top
, dump
, dump
);