mfi_config.c revision 253244
1180750Sdes/*-
2180750Sdes * Copyright (c) 2008, 2009 Yahoo!, Inc.
3180750Sdes * All rights reserved.
4180750Sdes *
5180750Sdes * Redistribution and use in source and binary forms, with or without
6180750Sdes * modification, are permitted provided that the following conditions
7180750Sdes * are met:
8180750Sdes * 1. Redistributions of source code must retain the above copyright
9180750Sdes *    notice, this list of conditions and the following disclaimer.
10180750Sdes * 2. Redistributions in binary form must reproduce the above copyright
11180750Sdes *    notice, this list of conditions and the following disclaimer in the
12180750Sdes *    documentation and/or other materials provided with the distribution.
13180750Sdes * 3. The names of the authors may not be used to endorse or promote
14180750Sdes *    products derived from this software without specific prior written
15180750Sdes *    permission.
16180750Sdes *
17180750Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18180750Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19180750Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20180750Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21180750Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22180750Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23180750Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24180750Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25180750Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26180750Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27180750Sdes * SUCH DAMAGE.
28180750Sdes *
29180750Sdes * $FreeBSD: stable/9/usr.sbin/mfiutil/mfi_config.c 253244 2013-07-12 02:26:15Z sbruno $
30180750Sdes */
31180750Sdes
32180750Sdes#include <sys/param.h>
33180750Sdes#ifdef DEBUG
34180750Sdes#include <sys/sysctl.h>
35180750Sdes#endif
36180750Sdes#include <err.h>
37180750Sdes#include <errno.h>
38180750Sdes#include <fcntl.h>
39180750Sdes#include <libutil.h>
40180750Sdes#include <stdint.h>
41180750Sdes#include <stdio.h>
42180750Sdes#include <stdlib.h>
43180750Sdes#include <string.h>
44180750Sdes#include <unistd.h>
45180750Sdes#include "mfiutil.h"
46180750Sdes
47180750Sdesstatic int	add_spare(int ac, char **av);
48180750Sdesstatic int	remove_spare(int ac, char **av);
49180750Sdes
50180750Sdesstatic long
51180750Sdesdehumanize(const char *value)
52180750Sdes{
53180750Sdes        char    *vtp;
54180750Sdes        long    iv;
55180750Sdes
56180750Sdes        if (value == NULL)
57180750Sdes                return (0);
58180750Sdes        iv = strtoq(value, &vtp, 0);
59180750Sdes        if (vtp == value || (vtp[0] != '\0' && vtp[1] != '\0')) {
60180750Sdes                return (0);
61180750Sdes        }
62180750Sdes        switch (vtp[0]) {
63180750Sdes        case 't': case 'T':
64180750Sdes                iv *= 1024;
65180750Sdes        case 'g': case 'G':
66180750Sdes                iv *= 1024;
67180750Sdes        case 'm': case 'M':
68180750Sdes                iv *= 1024;
69180750Sdes        case 'k': case 'K':
70180750Sdes                iv *= 1024;
71180750Sdes        case '\0':
72180750Sdes                break;
73180750Sdes        default:
74180750Sdes                return (0);
75180750Sdes        }
76180750Sdes        return (iv);
77180750Sdes}
78180750Sdes
79180750Sdesint
80180750Sdesmfi_config_read(int fd, struct mfi_config_data **configp)
81180750Sdes{
82180750Sdes	return mfi_config_read_opcode(fd, MFI_DCMD_CFG_READ, configp, NULL, 0);
83180750Sdes}
84180750Sdes
85180750Sdesint
86180750Sdesmfi_config_read_opcode(int fd, uint32_t opcode, struct mfi_config_data **configp,
87180750Sdes	uint8_t *mbox, size_t mboxlen)
88180750Sdes{
89180750Sdes	struct mfi_config_data *config;
90180750Sdes	uint32_t config_size;
91180750Sdes	int error;
92180750Sdes
93180750Sdes	/*
94180750Sdes	 * Keep fetching the config in a loop until we have a large enough
95180750Sdes	 * buffer to hold the entire configuration.
96180750Sdes	 */
97180750Sdes	config = NULL;
98180750Sdes	config_size = 1024;
99180750Sdesfetch:
100180750Sdes	config = reallocf(config, config_size);
101180750Sdes	if (config == NULL)
102180750Sdes		return (-1);
103180750Sdes	if (mfi_dcmd_command(fd, opcode, config,
104180750Sdes	    config_size, mbox, mboxlen, NULL) < 0) {
105180750Sdes		error = errno;
106180750Sdes		free(config);
107180750Sdes		errno = error;
108180750Sdes		return (-1);
109180750Sdes	}
110180750Sdes
111180750Sdes	if (config->size > config_size) {
112180750Sdes		config_size = config->size;
113180750Sdes		goto fetch;
114180750Sdes	}
115180750Sdes
116180750Sdes	*configp = config;
117180750Sdes	return (0);
118180750Sdes}
119180750Sdes
120180750Sdesstatic struct mfi_array *
121180750Sdesmfi_config_lookup_array(struct mfi_config_data *config, uint16_t array_ref)
122180750Sdes{
123180750Sdes	struct mfi_array *ar;
124180750Sdes	char *p;
125180750Sdes	int i;
126180750Sdes
127180750Sdes	p = (char *)config->array;
128180750Sdes	for (i = 0; i < config->array_count; i++) {
129180750Sdes		ar = (struct mfi_array *)p;
130180750Sdes		if (ar->array_ref == array_ref)
131180750Sdes			return (ar);
132180750Sdes		p += config->array_size;
133180750Sdes	}
134180750Sdes
135180750Sdes	return (NULL);
136180750Sdes}
137180750Sdes
138180750Sdesstatic struct mfi_ld_config *
139180750Sdesmfi_config_lookup_volume(struct mfi_config_data *config, uint8_t target_id)
140180750Sdes{
141180750Sdes	struct mfi_ld_config *ld;
142180750Sdes	char *p;
143180750Sdes	int i;
144180750Sdes
145180750Sdes	p = (char *)config->array + config->array_count * config->array_size;
146180750Sdes	for (i = 0; i < config->log_drv_count; i++) {
147180750Sdes		ld = (struct mfi_ld_config *)p;
148180750Sdes		if (ld->properties.ld.v.target_id == target_id)
149180750Sdes			return (ld);
150180750Sdes		p += config->log_drv_size;
151180750Sdes	}
152180750Sdes
153180750Sdes	return (NULL);
154180750Sdes}
155180750Sdes
156180750Sdesstatic int
157180750Sdesclear_config(int ac __unused, char **av __unused)
158180750Sdes{
159180750Sdes	struct mfi_ld_list list;
160180750Sdes	int ch, error, fd;
161180750Sdes	u_int i;
162180750Sdes
163180750Sdes	fd = mfi_open(mfi_unit, O_RDWR);
164180750Sdes	if (fd < 0) {
165180750Sdes		error = errno;
166180750Sdes		warn("mfi_open");
167180750Sdes		return (error);
168180750Sdes	}
169180750Sdes
170180750Sdes	if (!mfi_reconfig_supported()) {
171180750Sdes		warnx("The current mfi(4) driver does not support "
172180750Sdes		    "configuration changes.");
173180750Sdes		close(fd);
174180750Sdes		return (EOPNOTSUPP);
175180750Sdes	}
176180750Sdes
177180750Sdes	if (mfi_ld_get_list(fd, &list, NULL) < 0) {
178180750Sdes		error = errno;
179180750Sdes		warn("Failed to get volume list");
180180750Sdes		close(fd);
181180750Sdes		return (error);
182180750Sdes	}
183180750Sdes
184180750Sdes	for (i = 0; i < list.ld_count; i++) {
185180750Sdes		if (mfi_volume_busy(fd, list.ld_list[i].ld.v.target_id)) {
186180750Sdes			warnx("Volume %s is busy and cannot be deleted",
187180750Sdes			    mfi_volume_name(fd, list.ld_list[i].ld.v.target_id));
188180750Sdes			close(fd);
189180750Sdes			return (EBUSY);
190180750Sdes		}
191180750Sdes	}
192180750Sdes
193180750Sdes	printf(
194180750Sdes	    "Are you sure you wish to clear the configuration on mfi%u? [y/N] ",
195180750Sdes	    mfi_unit);
196180750Sdes	ch = getchar();
197180750Sdes	if (ch != 'y' && ch != 'Y') {
198180750Sdes		printf("\nAborting\n");
199180750Sdes		close(fd);
200180750Sdes		return (0);
201180750Sdes	}
202180750Sdes
203180750Sdes	if (mfi_dcmd_command(fd, MFI_DCMD_CFG_CLEAR, NULL, 0, NULL, 0, NULL) < 0) {
204180750Sdes		error = errno;
205180750Sdes		warn("Failed to clear configuration");
206180750Sdes		close(fd);
207180750Sdes		return (error);
208180750Sdes	}
209180750Sdes
210180750Sdes	printf("mfi%d: Configuration cleared\n", mfi_unit);
211180750Sdes	close(fd);
212180750Sdes
213180750Sdes	return (0);
214180750Sdes}
215180750SdesMFI_COMMAND(top, clear, clear_config);
216180750Sdes
217180750Sdes#define MAX_DRIVES_PER_ARRAY MFI_MAX_ROW_SIZE
218180750Sdes#define MFI_ARRAY_SIZE sizeof(struct mfi_array)
219180750Sdes
220180750Sdes#define	RT_RAID0	0
221180750Sdes#define	RT_RAID1	1
222180750Sdes#define	RT_RAID5	2
223180750Sdes#define	RT_RAID6	3
224180750Sdes#define	RT_JBOD		4
225180750Sdes#define	RT_CONCAT	5
226180750Sdes#define	RT_RAID10	6
227180750Sdes#define	RT_RAID50	7
228180750Sdes#define	RT_RAID60	8
229180750Sdes
230180750Sdesstatic int
231180750Sdescompare_int(const void *one, const void *two)
232180750Sdes{
233180750Sdes	int first, second;
234180750Sdes
235180750Sdes	first = *(const int *)one;
236180750Sdes	second = *(const int *)two;
237180750Sdes
238180750Sdes	return (first - second);
239180750Sdes}
240180750Sdes
241180750Sdesstatic struct raid_type_entry {
242180750Sdes	const char *name;
243180750Sdes	int	raid_type;
244180750Sdes} raid_type_table[] = {
245180750Sdes	{ "raid0",	RT_RAID0 },
246180750Sdes	{ "raid-0",	RT_RAID0 },
247180750Sdes	{ "raid1",	RT_RAID1 },
248180750Sdes	{ "raid-1",	RT_RAID1 },
249180750Sdes	{ "mirror",	RT_RAID1 },
250180750Sdes	{ "raid5",	RT_RAID5 },
251180750Sdes	{ "raid-5",	RT_RAID5 },
252180750Sdes	{ "raid6",	RT_RAID6 },
253180750Sdes	{ "raid-6",	RT_RAID6 },
254180750Sdes	{ "jbod",	RT_JBOD },
255180750Sdes	{ "concat",	RT_CONCAT },
256180750Sdes	{ "raid10",	RT_RAID10 },
257180750Sdes	{ "raid1+0",	RT_RAID10 },
258180750Sdes	{ "raid-10",	RT_RAID10 },
259180750Sdes	{ "raid-1+0",	RT_RAID10 },
260180750Sdes	{ "raid50",	RT_RAID50 },
261180750Sdes	{ "raid5+0",	RT_RAID50 },
262180750Sdes	{ "raid-50",	RT_RAID50 },
263180750Sdes	{ "raid-5+0",	RT_RAID50 },
264180750Sdes	{ "raid60",	RT_RAID60 },
265180750Sdes	{ "raid6+0",	RT_RAID60 },
266180750Sdes	{ "raid-60",	RT_RAID60 },
267180750Sdes	{ "raid-6+0",	RT_RAID60 },
268180750Sdes	{ NULL,		0 },
269180750Sdes};
270180750Sdes
271180750Sdesstruct config_id_state {
272180750Sdes	int	array_count;
273180750Sdes	int	log_drv_count;
274180750Sdes	int	*arrays;
275180750Sdes	int	*volumes;
276180750Sdes	uint16_t array_ref;
277180750Sdes	uint8_t	target_id;
278180750Sdes};
279180750Sdes
280180750Sdesstruct array_info {
281180750Sdes	int	drive_count;
282180750Sdes	struct mfi_pd_info *drives;
283180750Sdes	struct mfi_array *array;
284180750Sdes};
285180750Sdes
286180750Sdes/* Parse a comma-separated list of drives for an array. */
287180750Sdesstatic int
288180750Sdesparse_array(int fd, int raid_type, char *array_str, struct array_info *info)
289180750Sdes{
290180750Sdes	struct mfi_pd_info *pinfo;
291180750Sdes	uint16_t device_id;
292180750Sdes	char *cp;
293180750Sdes	u_int count;
294180750Sdes	int error;
295180750Sdes
296180750Sdes	cp = array_str;
297180750Sdes	for (count = 0; cp != NULL; count++) {
298180750Sdes		cp = strchr(cp, ',');
299180750Sdes		if (cp != NULL) {
300180750Sdes			cp++;
301180750Sdes			if (*cp == ',') {
302180750Sdes				warnx("Invalid drive list '%s'", array_str);
303180750Sdes				return (EINVAL);
304180750Sdes			}
305180750Sdes		}
306180750Sdes	}
307180750Sdes
308180750Sdes	/* Validate the number of drives for this array. */
309180750Sdes	if (count >= MAX_DRIVES_PER_ARRAY) {
310180750Sdes		warnx("Too many drives for a single array: max is %d",
311180750Sdes		    MAX_DRIVES_PER_ARRAY);
312180750Sdes		return (EINVAL);
313180750Sdes	}
314180750Sdes	switch (raid_type) {
315180750Sdes	case RT_RAID1:
316180750Sdes	case RT_RAID10:
317180750Sdes		if (count % 2 != 0) {
318180750Sdes			warnx("RAID1 and RAID10 require an even number of "
319180750Sdes			    "drives in each array");
320180750Sdes			return (EINVAL);
321180750Sdes		}
322180750Sdes		break;
323180750Sdes	case RT_RAID5:
324180750Sdes	case RT_RAID50:
325180750Sdes		if (count < 3) {
326180750Sdes			warnx("RAID5 and RAID50 require at least 3 drives in "
327180750Sdes			    "each array");
328180750Sdes			return (EINVAL);
329180750Sdes		}
330180750Sdes		break;
331180750Sdes	case RT_RAID6:
332180750Sdes	case RT_RAID60:
333180750Sdes		if (count < 4) {
334180750Sdes			warnx("RAID6 and RAID60 require at least 4 drives in "
335180750Sdes			    "each array");
336180750Sdes			return (EINVAL);
337180750Sdes		}
338180750Sdes		break;
339180750Sdes	}
340180750Sdes
341180750Sdes	/* Validate each drive. */
342180750Sdes	info->drives = calloc(count, sizeof(struct mfi_pd_info));
343180750Sdes	if (info->drives == NULL) {
344180750Sdes		warnx("malloc failed");
345180750Sdes		return (ENOMEM);
346180750Sdes	}
347180750Sdes	info->drive_count = count;
348180750Sdes	for (pinfo = info->drives; (cp = strsep(&array_str, ",")) != NULL;
349180750Sdes	     pinfo++) {
350180750Sdes		error = mfi_lookup_drive(fd, cp, &device_id);
351180750Sdes		if (error) {
352180750Sdes			free(info->drives);
353180750Sdes			info->drives = NULL;
354180750Sdes			return (error);
355180750Sdes		}
356180750Sdes
357180750Sdes		if (mfi_pd_get_info(fd, device_id, pinfo, NULL) < 0) {
358180750Sdes			error = errno;
359180750Sdes			warn("Failed to fetch drive info for drive %s", cp);
360180750Sdes			free(info->drives);
361180750Sdes			info->drives = NULL;
362180750Sdes			return (error);
363180750Sdes		}
364180750Sdes
365180750Sdes		if (pinfo->fw_state != MFI_PD_STATE_UNCONFIGURED_GOOD) {
366180750Sdes			warnx("Drive %u is not available", device_id);
367180750Sdes			free(info->drives);
368180750Sdes			info->drives = NULL;
369180750Sdes			return (EINVAL);
370180750Sdes		}
371180750Sdes
372180750Sdes		if (pinfo->state.ddf.v.pd_type.is_foreign) {
373180750Sdes			warnx("Drive %u is foreign", device_id);
374180750Sdes			free(info->drives);
375180750Sdes			info->drives = NULL;
376180750Sdes			return (EINVAL);
377180750Sdes		}
378180750Sdes	}
379180750Sdes
380180750Sdes	return (0);
381180750Sdes}
382180750Sdes
383180750Sdes/*
384180750Sdes * Find the next free array ref assuming that 'array_ref' is the last
385180750Sdes * one used.  'array_ref' should be 0xffff for the initial test.
386180750Sdes */
387180750Sdesstatic uint16_t
388180750Sdesfind_next_array(struct config_id_state *state)
389180750Sdes{
390180750Sdes	int i;
391180750Sdes
392180750Sdes	/* Assume the current one is used. */
393180750Sdes	state->array_ref++;
394180750Sdes
395180750Sdes	/* Find the next free one. */
396180750Sdes	for (i = 0; i < state->array_count; i++)
397180750Sdes		if (state->arrays[i] == state->array_ref)
398180750Sdes			state->array_ref++;
399180750Sdes	return (state->array_ref);
400180750Sdes}
401180750Sdes
402180750Sdes/*
403180750Sdes * Find the next free volume ID assuming that 'target_id' is the last
404180750Sdes * one used.  'target_id' should be 0xff for the initial test.
405180750Sdes */
406180750Sdesstatic uint8_t
407180750Sdesfind_next_volume(struct config_id_state *state)
408180750Sdes{
409180750Sdes	int i;
410180750Sdes
411180750Sdes	/* Assume the current one is used. */
412180750Sdes	state->target_id++;
413180750Sdes
414180750Sdes	/* Find the next free one. */
415180750Sdes	for (i = 0; i < state->log_drv_count; i++)
416180750Sdes		if (state->volumes[i] == state->target_id)
417180750Sdes			state->target_id++;
418180750Sdes	return (state->target_id);
419180750Sdes}
420180750Sdes
421180750Sdes/* Populate an array with drives. */
422static void
423build_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 */
450static void
451build_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
544static int
545create_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
827error:
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}
841MFI_COMMAND(top, create, create_volume);
842
843static int
844delete_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}
918MFI_COMMAND(top, delete, delete_volume);
919
920static int
921add_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
1041error:
1042	free(spare);
1043	free(config);
1044	close(fd);
1045
1046	return (error);
1047}
1048MFI_COMMAND(top, add, add_spare);
1049
1050static int
1051remove_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}
1103MFI_COMMAND(top, remove, remove_spare);
1104
1105/* Display raw data about a config. */
1106void
1107dump_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
1201static int
1202debug_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}
1234MFI_COMMAND(top, debug, debug_config);
1235
1236static int
1237dump(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}
1286MFI_COMMAND(top, dump, dump);
1287#endif
1288