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
49static int	add_spare(int ac, char **av);
50static int	remove_spare(int ac, char **av);
51
52static long
53dehumanize(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
81int
82mfi_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
87int
88mfi_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;
101fetch:
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
122static struct mfi_array *
123mfi_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
140static struct mfi_ld_config *
141mfi_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
158static int
159clear_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}
217MFI_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
232static int
233compare_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
243static 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
273struct 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
282struct 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. */
289static int
290parse_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 */
389static uint16_t
390find_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 */
408static uint8_t
409find_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. */
424static void
425build_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 */
452static void
453build_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
546static int
547create_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
829error:
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}
843MFI_COMMAND(top, create, create_volume);
844
845static int
846delete_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}
920MFI_COMMAND(top, delete, delete_volume);
921
922static int
923add_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
1043error:
1044	free(spare);
1045	free(config);
1046	close(fd);
1047
1048	return (error);
1049}
1050MFI_COMMAND(top, add, add_spare);
1051
1052static int
1053remove_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}
1105MFI_COMMAND(top, remove, remove_spare);
1106
1107/* Display raw data about a config. */
1108void
1109dump_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
1203static int
1204debug_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}
1236MFI_COMMAND(top, debug, debug_config);
1237
1238static int
1239dump(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}
1288MFI_COMMAND(top, dump, dump);
1289#endif
1290