xref: /freebsd/sys/geom/raid3/g_raid3_ctl.c (revision 8510f61acdf83ef524e694b9b0eebeb7ad834162)
12d1661a5SPawel Jakub Dawidek /*-
23728855aSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
33728855aSPedro F. Giffuni  *
49bfdf598SPawel Jakub Dawidek  * Copyright (c) 2004-2006 Pawel Jakub Dawidek <pjd@FreeBSD.org>
52d1661a5SPawel Jakub Dawidek  * All rights reserved.
62d1661a5SPawel Jakub Dawidek  *
72d1661a5SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
82d1661a5SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
92d1661a5SPawel Jakub Dawidek  * are met:
102d1661a5SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
112d1661a5SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
122d1661a5SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
132d1661a5SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
142d1661a5SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
152d1661a5SPawel Jakub Dawidek  *
162d1661a5SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
172d1661a5SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
182d1661a5SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
192d1661a5SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
202d1661a5SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
212d1661a5SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
222d1661a5SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
232d1661a5SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
242d1661a5SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
252d1661a5SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
262d1661a5SPawel Jakub Dawidek  * SUCH DAMAGE.
272d1661a5SPawel Jakub Dawidek  */
282d1661a5SPawel Jakub Dawidek 
292d1661a5SPawel Jakub Dawidek #include <sys/cdefs.h>
302d1661a5SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
312d1661a5SPawel Jakub Dawidek 
322d1661a5SPawel Jakub Dawidek #include <sys/param.h>
332d1661a5SPawel Jakub Dawidek #include <sys/systm.h>
342d1661a5SPawel Jakub Dawidek #include <sys/kernel.h>
352d1661a5SPawel Jakub Dawidek #include <sys/module.h>
362d1661a5SPawel Jakub Dawidek #include <sys/lock.h>
372d1661a5SPawel Jakub Dawidek #include <sys/mutex.h>
382d1661a5SPawel Jakub Dawidek #include <sys/bio.h>
392d1661a5SPawel Jakub Dawidek #include <sys/sysctl.h>
402d1661a5SPawel Jakub Dawidek #include <sys/malloc.h>
412d1661a5SPawel Jakub Dawidek #include <sys/bitstring.h>
422d1661a5SPawel Jakub Dawidek #include <vm/uma.h>
432d1661a5SPawel Jakub Dawidek #include <machine/atomic.h>
442d1661a5SPawel Jakub Dawidek #include <geom/geom.h>
452d1661a5SPawel Jakub Dawidek #include <sys/proc.h>
462d1661a5SPawel Jakub Dawidek #include <sys/kthread.h>
472d1661a5SPawel Jakub Dawidek #include <geom/raid3/g_raid3.h>
482d1661a5SPawel Jakub Dawidek 
492d1661a5SPawel Jakub Dawidek 
502d1661a5SPawel Jakub Dawidek static struct g_raid3_softc *
512d1661a5SPawel Jakub Dawidek g_raid3_find_device(struct g_class *mp, const char *name)
522d1661a5SPawel Jakub Dawidek {
532d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
542d1661a5SPawel Jakub Dawidek 	struct g_geom *gp;
552d1661a5SPawel Jakub Dawidek 
563650be51SPawel Jakub Dawidek 	g_topology_lock();
572d1661a5SPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
582d1661a5SPawel Jakub Dawidek 		sc = gp->softc;
592d1661a5SPawel Jakub Dawidek 		if (sc == NULL)
602d1661a5SPawel Jakub Dawidek 			continue;
612d1661a5SPawel Jakub Dawidek 		if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0)
622d1661a5SPawel Jakub Dawidek 			continue;
632d1661a5SPawel Jakub Dawidek 		if (strcmp(gp->name, name) == 0 ||
642d1661a5SPawel Jakub Dawidek 		    strcmp(sc->sc_name, name) == 0) {
653650be51SPawel Jakub Dawidek 			g_topology_unlock();
663650be51SPawel Jakub Dawidek 			sx_xlock(&sc->sc_lock);
672d1661a5SPawel Jakub Dawidek 			return (sc);
682d1661a5SPawel Jakub Dawidek 		}
692d1661a5SPawel Jakub Dawidek 	}
703650be51SPawel Jakub Dawidek 	g_topology_unlock();
712d1661a5SPawel Jakub Dawidek 	return (NULL);
722d1661a5SPawel Jakub Dawidek }
732d1661a5SPawel Jakub Dawidek 
742d1661a5SPawel Jakub Dawidek static struct g_raid3_disk *
752d1661a5SPawel Jakub Dawidek g_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
762d1661a5SPawel Jakub Dawidek {
772d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
782d1661a5SPawel Jakub Dawidek 	u_int n;
792d1661a5SPawel Jakub Dawidek 
803650be51SPawel Jakub Dawidek 	sx_assert(&sc->sc_lock, SX_XLOCKED);
81*8510f61aSXin LI 	if (strncmp(name, _PATH_DEV, 5) == 0)
8286ed3c25SPawel Jakub Dawidek 		name += 5;
832d1661a5SPawel Jakub Dawidek 	for (n = 0; n < sc->sc_ndisks; n++) {
842d1661a5SPawel Jakub Dawidek 		disk = &sc->sc_disks[n];
852d1661a5SPawel Jakub Dawidek 		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
862d1661a5SPawel Jakub Dawidek 			continue;
872d1661a5SPawel Jakub Dawidek 		if (disk->d_consumer == NULL)
882d1661a5SPawel Jakub Dawidek 			continue;
892d1661a5SPawel Jakub Dawidek 		if (disk->d_consumer->provider == NULL)
902d1661a5SPawel Jakub Dawidek 			continue;
912d1661a5SPawel Jakub Dawidek 		if (strcmp(disk->d_consumer->provider->name, name) == 0)
922d1661a5SPawel Jakub Dawidek 			return (disk);
932d1661a5SPawel Jakub Dawidek 	}
942d1661a5SPawel Jakub Dawidek 	return (NULL);
952d1661a5SPawel Jakub Dawidek }
962d1661a5SPawel Jakub Dawidek 
972d1661a5SPawel Jakub Dawidek static void
982d1661a5SPawel Jakub Dawidek g_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
992d1661a5SPawel Jakub Dawidek {
1002d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
1012d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
1022d1661a5SPawel Jakub Dawidek 	const char *name;
103501250baSPawel Jakub Dawidek 	int *nargs, do_sync = 0, dirty = 1;
104dba915cfSPawel Jakub Dawidek 	int *autosync, *noautosync;
105501250baSPawel Jakub Dawidek 	int *failsync, *nofailsync;
106dba915cfSPawel Jakub Dawidek 	int *round_robin, *noround_robin;
107dba915cfSPawel Jakub Dawidek 	int *verify, *noverify;
1082d1661a5SPawel Jakub Dawidek 	u_int n;
1092d1661a5SPawel Jakub Dawidek 
1102d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
111cc6aa917SPawel Jakub Dawidek 	if (nargs == NULL) {
112cc6aa917SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
113cc6aa917SPawel Jakub Dawidek 		return;
114cc6aa917SPawel Jakub Dawidek 	}
1152d1661a5SPawel Jakub Dawidek 	if (*nargs != 1) {
1162d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
1172d1661a5SPawel Jakub Dawidek 		return;
1182d1661a5SPawel Jakub Dawidek 	}
1192d1661a5SPawel Jakub Dawidek 	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
1202d1661a5SPawel Jakub Dawidek 	if (autosync == NULL) {
1212d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "autosync");
1222d1661a5SPawel Jakub Dawidek 		return;
1232d1661a5SPawel Jakub Dawidek 	}
1242d1661a5SPawel Jakub Dawidek 	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
1252d1661a5SPawel Jakub Dawidek 	if (noautosync == NULL) {
1262d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "noautosync");
1272d1661a5SPawel Jakub Dawidek 		return;
1282d1661a5SPawel Jakub Dawidek 	}
1292d1661a5SPawel Jakub Dawidek 	if (*autosync && *noautosync) {
1302d1661a5SPawel Jakub Dawidek 		gctl_error(req, "'%s' and '%s' specified.", "autosync",
1312d1661a5SPawel Jakub Dawidek 		    "noautosync");
1322d1661a5SPawel Jakub Dawidek 		return;
1332d1661a5SPawel Jakub Dawidek 	}
134501250baSPawel Jakub Dawidek 	failsync = gctl_get_paraml(req, "failsync", sizeof(*failsync));
135501250baSPawel Jakub Dawidek 	if (failsync == NULL) {
136501250baSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "failsync");
137501250baSPawel Jakub Dawidek 		return;
138501250baSPawel Jakub Dawidek 	}
139501250baSPawel Jakub Dawidek 	nofailsync = gctl_get_paraml(req, "nofailsync", sizeof(*nofailsync));
140501250baSPawel Jakub Dawidek 	if (nofailsync == NULL) {
141501250baSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nofailsync");
142501250baSPawel Jakub Dawidek 		return;
143501250baSPawel Jakub Dawidek 	}
144501250baSPawel Jakub Dawidek 	if (*failsync && *nofailsync) {
145501250baSPawel Jakub Dawidek 		gctl_error(req, "'%s' and '%s' specified.", "failsync",
146501250baSPawel Jakub Dawidek 		    "nofailsync");
147501250baSPawel Jakub Dawidek 		return;
148501250baSPawel Jakub Dawidek 	}
149f5a2f7feSPawel Jakub Dawidek 	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
150f5a2f7feSPawel Jakub Dawidek 	if (round_robin == NULL) {
151f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "round_robin");
152f5a2f7feSPawel Jakub Dawidek 		return;
153f5a2f7feSPawel Jakub Dawidek 	}
154f5a2f7feSPawel Jakub Dawidek 	noround_robin = gctl_get_paraml(req, "noround_robin",
155f5a2f7feSPawel Jakub Dawidek 	    sizeof(*noround_robin));
156f5a2f7feSPawel Jakub Dawidek 	if (noround_robin == NULL) {
157f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "noround_robin");
158f5a2f7feSPawel Jakub Dawidek 		return;
159f5a2f7feSPawel Jakub Dawidek 	}
160f5a2f7feSPawel Jakub Dawidek 	if (*round_robin && *noround_robin) {
161f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
162f5a2f7feSPawel Jakub Dawidek 		    "noround_robin");
163f5a2f7feSPawel Jakub Dawidek 		return;
164f5a2f7feSPawel Jakub Dawidek 	}
165dba915cfSPawel Jakub Dawidek 	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
166dba915cfSPawel Jakub Dawidek 	if (verify == NULL) {
167dba915cfSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "verify");
168dba915cfSPawel Jakub Dawidek 		return;
169dba915cfSPawel Jakub Dawidek 	}
170dba915cfSPawel Jakub Dawidek 	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
171dba915cfSPawel Jakub Dawidek 	if (noverify == NULL) {
172dba915cfSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "noverify");
173dba915cfSPawel Jakub Dawidek 		return;
174dba915cfSPawel Jakub Dawidek 	}
175dba915cfSPawel Jakub Dawidek 	if (*verify && *noverify) {
176dba915cfSPawel Jakub Dawidek 		gctl_error(req, "'%s' and '%s' specified.", "verify",
177dba915cfSPawel Jakub Dawidek 		    "noverify");
178dba915cfSPawel Jakub Dawidek 		return;
179dba915cfSPawel Jakub Dawidek 	}
180501250baSPawel Jakub Dawidek 	if (!*autosync && !*noautosync && !*failsync && !*nofailsync &&
181501250baSPawel Jakub Dawidek 	    !*round_robin && !*noround_robin && !*verify && !*noverify) {
182f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "Nothing has changed.");
183f5a2f7feSPawel Jakub Dawidek 		return;
184f5a2f7feSPawel Jakub Dawidek 	}
1853650be51SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
1863650be51SPawel Jakub Dawidek 	if (name == NULL) {
1873650be51SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
1883650be51SPawel Jakub Dawidek 		return;
1893650be51SPawel Jakub Dawidek 	}
1903650be51SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
1913650be51SPawel Jakub Dawidek 	if (sc == NULL) {
1923650be51SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
1933650be51SPawel Jakub Dawidek 		return;
1943650be51SPawel Jakub Dawidek 	}
1953650be51SPawel Jakub Dawidek 	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
1963650be51SPawel Jakub Dawidek 		gctl_error(req, "Not all disks connected.");
1973650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
1983650be51SPawel Jakub Dawidek 		return;
1993650be51SPawel Jakub Dawidek 	}
2002d1661a5SPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
2012d1661a5SPawel Jakub Dawidek 		if (*autosync) {
2022d1661a5SPawel Jakub Dawidek 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
2032d1661a5SPawel Jakub Dawidek 			do_sync = 1;
2042d1661a5SPawel Jakub Dawidek 		}
2052d1661a5SPawel Jakub Dawidek 	} else {
2062d1661a5SPawel Jakub Dawidek 		if (*noautosync)
2072d1661a5SPawel Jakub Dawidek 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
2082d1661a5SPawel Jakub Dawidek 	}
209501250baSPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOFAILSYNC) != 0) {
210501250baSPawel Jakub Dawidek 		if (*failsync)
211501250baSPawel Jakub Dawidek 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOFAILSYNC;
212501250baSPawel Jakub Dawidek 	} else {
213501250baSPawel Jakub Dawidek 		if (*nofailsync) {
214501250baSPawel Jakub Dawidek 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOFAILSYNC;
215501250baSPawel Jakub Dawidek 			dirty = 0;
216501250baSPawel Jakub Dawidek 		}
217501250baSPawel Jakub Dawidek 	}
218dba915cfSPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
219dba915cfSPawel Jakub Dawidek 		if (*noverify)
220dba915cfSPawel Jakub Dawidek 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
221dba915cfSPawel Jakub Dawidek 	} else {
222dba915cfSPawel Jakub Dawidek 		if (*verify)
223dba915cfSPawel Jakub Dawidek 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
224dba915cfSPawel Jakub Dawidek 	}
225f5a2f7feSPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
226f5a2f7feSPawel Jakub Dawidek 		if (*noround_robin)
227f5a2f7feSPawel Jakub Dawidek 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
228f5a2f7feSPawel Jakub Dawidek 	} else {
229f5a2f7feSPawel Jakub Dawidek 		if (*round_robin)
230f5a2f7feSPawel Jakub Dawidek 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
231f5a2f7feSPawel Jakub Dawidek 	}
232dba915cfSPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
233dba915cfSPawel Jakub Dawidek 	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
234dba915cfSPawel Jakub Dawidek 		/*
235dba915cfSPawel Jakub Dawidek 		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
236dba915cfSPawel Jakub Dawidek 		 */
237dba915cfSPawel Jakub Dawidek 		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
238dba915cfSPawel Jakub Dawidek 	}
2392d1661a5SPawel Jakub Dawidek 	for (n = 0; n < sc->sc_ndisks; n++) {
2402d1661a5SPawel Jakub Dawidek 		disk = &sc->sc_disks[n];
2412d1661a5SPawel Jakub Dawidek 		if (do_sync) {
2422d1661a5SPawel Jakub Dawidek 			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
2432d1661a5SPawel Jakub Dawidek 				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
2442d1661a5SPawel Jakub Dawidek 		}
245501250baSPawel Jakub Dawidek 		if (!dirty)
246501250baSPawel Jakub Dawidek 			disk->d_flags &= ~G_RAID3_DISK_FLAG_DIRTY;
2472d1661a5SPawel Jakub Dawidek 		g_raid3_update_metadata(disk);
2482d1661a5SPawel Jakub Dawidek 		if (do_sync) {
2492d1661a5SPawel Jakub Dawidek 			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
2502d1661a5SPawel Jakub Dawidek 				/*
2512d1661a5SPawel Jakub Dawidek 				 * XXX: This is probably possible that this
2522d1661a5SPawel Jakub Dawidek 				 *      component will not be retasted.
2532d1661a5SPawel Jakub Dawidek 				 */
2542d1661a5SPawel Jakub Dawidek 				g_raid3_event_send(disk,
2552d1661a5SPawel Jakub Dawidek 				    G_RAID3_DISK_STATE_DISCONNECTED,
2562d1661a5SPawel Jakub Dawidek 				    G_RAID3_EVENT_DONTWAIT);
2572d1661a5SPawel Jakub Dawidek 			}
2582d1661a5SPawel Jakub Dawidek 		}
2592d1661a5SPawel Jakub Dawidek 	}
2603650be51SPawel Jakub Dawidek 	sx_xunlock(&sc->sc_lock);
2612d1661a5SPawel Jakub Dawidek }
2622d1661a5SPawel Jakub Dawidek 
2632d1661a5SPawel Jakub Dawidek static void
2642d1661a5SPawel Jakub Dawidek g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
2652d1661a5SPawel Jakub Dawidek {
266ea973705SPawel Jakub Dawidek 	struct g_raid3_metadata md;
2672d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
2682d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
269ea973705SPawel Jakub Dawidek 	struct g_provider *pp;
2702d1661a5SPawel Jakub Dawidek 	const char *name;
271ea973705SPawel Jakub Dawidek 	int error, *nargs;
2722d1661a5SPawel Jakub Dawidek 
2732d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
2742d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
2752d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
2762d1661a5SPawel Jakub Dawidek 		return;
2772d1661a5SPawel Jakub Dawidek 	}
2782d1661a5SPawel Jakub Dawidek 	if (*nargs != 2) {
2792d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
2802d1661a5SPawel Jakub Dawidek 		return;
2812d1661a5SPawel Jakub Dawidek 	}
2822d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
2832d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
2842d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
2852d1661a5SPawel Jakub Dawidek 		return;
2862d1661a5SPawel Jakub Dawidek 	}
2872d1661a5SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
2882d1661a5SPawel Jakub Dawidek 	if (sc == NULL) {
2892d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
2902d1661a5SPawel Jakub Dawidek 		return;
2912d1661a5SPawel Jakub Dawidek 	}
2922d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg1");
2932d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
2942d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 1);
2953650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
2962d1661a5SPawel Jakub Dawidek 		return;
2972d1661a5SPawel Jakub Dawidek 	}
2982d1661a5SPawel Jakub Dawidek 	disk = g_raid3_find_disk(sc, name);
2992d1661a5SPawel Jakub Dawidek 	if (disk == NULL) {
3002d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such provider: %s.", name);
3013650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
3022d1661a5SPawel Jakub Dawidek 		return;
3032d1661a5SPawel Jakub Dawidek 	}
3042d1661a5SPawel Jakub Dawidek 	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
3052d1661a5SPawel Jakub Dawidek 	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
3065a20446dSPawel Jakub Dawidek 		gctl_error(req, "There is one stale disk already.");
3073650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
3082d1661a5SPawel Jakub Dawidek 		return;
3092d1661a5SPawel Jakub Dawidek 	}
3102d1661a5SPawel Jakub Dawidek 	/*
3112d1661a5SPawel Jakub Dawidek 	 * Do rebuild by resetting syncid and disconnecting disk.
3122d1661a5SPawel Jakub Dawidek 	 * It'll be retasted, connected to the device and synchronized.
3132d1661a5SPawel Jakub Dawidek 	 */
3142d1661a5SPawel Jakub Dawidek 	disk->d_sync.ds_syncid = 0;
3152d1661a5SPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
3162d1661a5SPawel Jakub Dawidek 		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
3172d1661a5SPawel Jakub Dawidek 	g_raid3_update_metadata(disk);
318ea973705SPawel Jakub Dawidek 	pp = disk->d_consumer->provider;
3193650be51SPawel Jakub Dawidek 	g_topology_lock();
320ea973705SPawel Jakub Dawidek 	error = g_raid3_read_metadata(disk->d_consumer, &md);
3213650be51SPawel Jakub Dawidek 	g_topology_unlock();
3222d1661a5SPawel Jakub Dawidek 	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
3232d1661a5SPawel Jakub Dawidek 	    G_RAID3_EVENT_WAIT);
324ea973705SPawel Jakub Dawidek 	if (error != 0) {
325ea973705SPawel Jakub Dawidek 		gctl_error(req, "Cannot read metadata from %s.", pp->name);
3263650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
327ea973705SPawel Jakub Dawidek 		return;
328ea973705SPawel Jakub Dawidek 	}
329ea973705SPawel Jakub Dawidek 	error = g_raid3_add_disk(sc, pp, &md);
3303650be51SPawel Jakub Dawidek 	if (error != 0)
331ea973705SPawel Jakub Dawidek 		gctl_error(req, "Cannot reconnect component %s.", pp->name);
3323650be51SPawel Jakub Dawidek 	sx_xunlock(&sc->sc_lock);
3332d1661a5SPawel Jakub Dawidek }
3342d1661a5SPawel Jakub Dawidek 
3352d1661a5SPawel Jakub Dawidek static void
3362d1661a5SPawel Jakub Dawidek g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
3372d1661a5SPawel Jakub Dawidek {
3382d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
3392d1661a5SPawel Jakub Dawidek 	int *force, *nargs, error;
3402d1661a5SPawel Jakub Dawidek 	const char *name;
3412d1661a5SPawel Jakub Dawidek 	char param[16];
3422d1661a5SPawel Jakub Dawidek 	u_int i;
343712fe9bdSPawel Jakub Dawidek 	int how;
3442d1661a5SPawel Jakub Dawidek 
3452d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
3462d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
3472d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
3482d1661a5SPawel Jakub Dawidek 		return;
3492d1661a5SPawel Jakub Dawidek 	}
3502d1661a5SPawel Jakub Dawidek 	if (*nargs < 1) {
3512d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
3522d1661a5SPawel Jakub Dawidek 		return;
3532d1661a5SPawel Jakub Dawidek 	}
3542d1661a5SPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
3552d1661a5SPawel Jakub Dawidek 	if (force == NULL) {
3562d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
3572d1661a5SPawel Jakub Dawidek 		return;
3582d1661a5SPawel Jakub Dawidek 	}
359712fe9bdSPawel Jakub Dawidek 	if (*force)
360712fe9bdSPawel Jakub Dawidek 		how = G_RAID3_DESTROY_HARD;
361712fe9bdSPawel Jakub Dawidek 	else
362712fe9bdSPawel Jakub Dawidek 		how = G_RAID3_DESTROY_SOFT;
3632d1661a5SPawel Jakub Dawidek 
3642d1661a5SPawel Jakub Dawidek 	for (i = 0; i < (u_int)*nargs; i++) {
3652d1661a5SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%u", i);
3662d1661a5SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, param);
3672d1661a5SPawel Jakub Dawidek 		if (name == NULL) {
3682d1661a5SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%u' argument.", i);
3692d1661a5SPawel Jakub Dawidek 			return;
3702d1661a5SPawel Jakub Dawidek 		}
3712d1661a5SPawel Jakub Dawidek 		sc = g_raid3_find_device(mp, name);
3722d1661a5SPawel Jakub Dawidek 		if (sc == NULL) {
3732d1661a5SPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", name);
3742d1661a5SPawel Jakub Dawidek 			return;
3752d1661a5SPawel Jakub Dawidek 		}
376712fe9bdSPawel Jakub Dawidek 		g_cancel_event(sc);
377712fe9bdSPawel Jakub Dawidek 		error = g_raid3_destroy(sc, how);
3782d1661a5SPawel Jakub Dawidek 		if (error != 0) {
3792d1661a5SPawel Jakub Dawidek 			gctl_error(req, "Cannot destroy device %s (error=%d).",
3802d1661a5SPawel Jakub Dawidek 			    sc->sc_geom->name, error);
3813650be51SPawel Jakub Dawidek 			sx_xunlock(&sc->sc_lock);
3822d1661a5SPawel Jakub Dawidek 			return;
3832d1661a5SPawel Jakub Dawidek 		}
3843650be51SPawel Jakub Dawidek 		/* No need to unlock, because lock is already dead. */
3852d1661a5SPawel Jakub Dawidek 	}
3862d1661a5SPawel Jakub Dawidek }
3872d1661a5SPawel Jakub Dawidek 
3882d1661a5SPawel Jakub Dawidek static void
3892d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert_orphan(struct g_consumer *cp)
3902d1661a5SPawel Jakub Dawidek {
3912d1661a5SPawel Jakub Dawidek 
3922d1661a5SPawel Jakub Dawidek 	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
3932d1661a5SPawel Jakub Dawidek 	    cp->provider->name));
3942d1661a5SPawel Jakub Dawidek }
3952d1661a5SPawel Jakub Dawidek 
3962d1661a5SPawel Jakub Dawidek static void
3972d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
3982d1661a5SPawel Jakub Dawidek {
3992d1661a5SPawel Jakub Dawidek 	struct g_raid3_metadata md;
4002d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
4012d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
4022d1661a5SPawel Jakub Dawidek 	struct g_geom *gp;
4032d1661a5SPawel Jakub Dawidek 	struct g_provider *pp;
4042d1661a5SPawel Jakub Dawidek 	struct g_consumer *cp;
4052d1661a5SPawel Jakub Dawidek 	const char *name;
4062d1661a5SPawel Jakub Dawidek 	u_char *sector;
40708249e9eSPawel Jakub Dawidek 	off_t compsize;
4082d1661a5SPawel Jakub Dawidek 	intmax_t *no;
4092c6a2737SAlexander Motin 	int *hardcode, *nargs, error, autono;
4102d1661a5SPawel Jakub Dawidek 
4112d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
4122d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
4132d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
4142d1661a5SPawel Jakub Dawidek 		return;
4152d1661a5SPawel Jakub Dawidek 	}
4162d1661a5SPawel Jakub Dawidek 	if (*nargs != 2) {
4172d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
4182d1661a5SPawel Jakub Dawidek 		return;
4192d1661a5SPawel Jakub Dawidek 	}
4202d1661a5SPawel Jakub Dawidek 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
4212d1661a5SPawel Jakub Dawidek 	if (hardcode == NULL) {
4222d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "hardcode");
4232d1661a5SPawel Jakub Dawidek 		return;
4242d1661a5SPawel Jakub Dawidek 	}
4252d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg1");
4262d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
4272d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 1);
4282d1661a5SPawel Jakub Dawidek 		return;
4292d1661a5SPawel Jakub Dawidek 	}
4302c6a2737SAlexander Motin 	if (gctl_get_param(req, "number", NULL) != NULL)
4313650be51SPawel Jakub Dawidek 		no = gctl_get_paraml(req, "number", sizeof(*no));
4322c6a2737SAlexander Motin 	else
4332c6a2737SAlexander Motin 		no = NULL;
434*8510f61aSXin LI 	if (strncmp(name, _PATH_DEV, 5) == 0)
43586ed3c25SPawel Jakub Dawidek 		name += 5;
4363650be51SPawel Jakub Dawidek 	g_topology_lock();
4372d1661a5SPawel Jakub Dawidek 	pp = g_provider_by_name(name);
4382d1661a5SPawel Jakub Dawidek 	if (pp == NULL) {
4393650be51SPawel Jakub Dawidek 		g_topology_unlock();
4402d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid provider.");
4412d1661a5SPawel Jakub Dawidek 		return;
4422d1661a5SPawel Jakub Dawidek 	}
4433650be51SPawel Jakub Dawidek 	gp = g_new_geomf(mp, "raid3:insert");
4443650be51SPawel Jakub Dawidek 	gp->orphan = g_raid3_ctl_insert_orphan;
4453650be51SPawel Jakub Dawidek 	cp = g_new_consumer(gp);
4463650be51SPawel Jakub Dawidek 	error = g_attach(cp, pp);
4473650be51SPawel Jakub Dawidek 	if (error != 0) {
4483650be51SPawel Jakub Dawidek 		g_topology_unlock();
4493650be51SPawel Jakub Dawidek 		gctl_error(req, "Cannot attach to %s.", pp->name);
4503650be51SPawel Jakub Dawidek 		goto end;
4513650be51SPawel Jakub Dawidek 	}
4523650be51SPawel Jakub Dawidek 	error = g_access(cp, 0, 1, 1);
4533650be51SPawel Jakub Dawidek 	if (error != 0) {
4543650be51SPawel Jakub Dawidek 		g_topology_unlock();
4553650be51SPawel Jakub Dawidek 		gctl_error(req, "Cannot access %s.", pp->name);
4563650be51SPawel Jakub Dawidek 		goto end;
4573650be51SPawel Jakub Dawidek 	}
4583650be51SPawel Jakub Dawidek 	g_topology_unlock();
4593650be51SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
4603650be51SPawel Jakub Dawidek 	if (name == NULL) {
4613650be51SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
4623650be51SPawel Jakub Dawidek 		goto end;
4633650be51SPawel Jakub Dawidek 	}
4643650be51SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
4653650be51SPawel Jakub Dawidek 	if (sc == NULL) {
4663650be51SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
4673650be51SPawel Jakub Dawidek 		goto end;
4683650be51SPawel Jakub Dawidek 	}
4692c6a2737SAlexander Motin 	if (no != NULL) {
4702c6a2737SAlexander Motin 		if (*no < 0 || *no >= sc->sc_ndisks) {
4713650be51SPawel Jakub Dawidek 			sx_xunlock(&sc->sc_lock);
4723650be51SPawel Jakub Dawidek 			gctl_error(req, "Invalid component number.");
4733650be51SPawel Jakub Dawidek 			goto end;
4743650be51SPawel Jakub Dawidek 		}
4753650be51SPawel Jakub Dawidek 		disk = &sc->sc_disks[*no];
4763650be51SPawel Jakub Dawidek 		if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
4773650be51SPawel Jakub Dawidek 			sx_xunlock(&sc->sc_lock);
4782c6a2737SAlexander Motin 			gctl_error(req, "Component %jd is already connected.",
4792c6a2737SAlexander Motin 			    *no);
4803650be51SPawel Jakub Dawidek 			goto end;
4813650be51SPawel Jakub Dawidek 		}
4822c6a2737SAlexander Motin 	} else {
4832c6a2737SAlexander Motin 		disk = NULL;
4842c6a2737SAlexander Motin 		for (autono = 0; autono < sc->sc_ndisks && disk == NULL; autono++)
4852c6a2737SAlexander Motin 			if (sc->sc_disks[autono].d_state ==
4862c6a2737SAlexander Motin 			    G_RAID3_DISK_STATE_NODISK)
4872c6a2737SAlexander Motin 				disk = &sc->sc_disks[autono];
4882c6a2737SAlexander Motin 		if (disk == NULL) {
4892c6a2737SAlexander Motin 			sx_xunlock(&sc->sc_lock);
4902c6a2737SAlexander Motin 			gctl_error(req, "No disconnected components.");
4912c6a2737SAlexander Motin 			goto end;
4922c6a2737SAlexander Motin 		}
4932c6a2737SAlexander Motin 	}
4942d1661a5SPawel Jakub Dawidek 	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
4953650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
4962d1661a5SPawel Jakub Dawidek 		gctl_error(req,
4972d1661a5SPawel Jakub Dawidek 		    "Cannot insert provider %s, because of its sector size.",
4982d1661a5SPawel Jakub Dawidek 		    pp->name);
4993650be51SPawel Jakub Dawidek 		goto end;
5002d1661a5SPawel Jakub Dawidek 	}
50108249e9eSPawel Jakub Dawidek 	compsize = sc->sc_mediasize / (sc->sc_ndisks - 1);
50208249e9eSPawel Jakub Dawidek 	if (compsize > pp->mediasize - pp->sectorsize) {
5033650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
50408249e9eSPawel Jakub Dawidek 		gctl_error(req, "Provider %s too small.", pp->name);
5053650be51SPawel Jakub Dawidek 		goto end;
50608249e9eSPawel Jakub Dawidek 	}
50708249e9eSPawel Jakub Dawidek 	if (compsize < pp->mediasize - pp->sectorsize) {
50808249e9eSPawel Jakub Dawidek 		gctl_error(req,
50908249e9eSPawel Jakub Dawidek 		    "warning: %s: only %jd bytes from %jd bytes used.",
51008249e9eSPawel Jakub Dawidek 		    pp->name, (intmax_t)compsize,
51108249e9eSPawel Jakub Dawidek 		    (intmax_t)(pp->mediasize - pp->sectorsize));
51208249e9eSPawel Jakub Dawidek 	}
5132d1661a5SPawel Jakub Dawidek 	g_raid3_fill_metadata(disk, &md);
5143650be51SPawel Jakub Dawidek 	sx_xunlock(&sc->sc_lock);
5152d1661a5SPawel Jakub Dawidek 	md.md_syncid = 0;
5162d1661a5SPawel Jakub Dawidek 	md.md_dflags = 0;
5172d1661a5SPawel Jakub Dawidek 	if (*hardcode)
5182d1661a5SPawel Jakub Dawidek 		strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
5192d1661a5SPawel Jakub Dawidek 	else
5202d1661a5SPawel Jakub Dawidek 		bzero(md.md_provider, sizeof(md.md_provider));
5219d793bddSPawel Jakub Dawidek 	md.md_provsize = pp->mediasize;
5222d1661a5SPawel Jakub Dawidek 	sector = g_malloc(pp->sectorsize, M_WAITOK);
5232d1661a5SPawel Jakub Dawidek 	raid3_metadata_encode(&md, sector);
5242d1661a5SPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
5252d1661a5SPawel Jakub Dawidek 	    pp->sectorsize);
5262d1661a5SPawel Jakub Dawidek 	g_free(sector);
5272d1661a5SPawel Jakub Dawidek 	if (error != 0)
5282d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s.", pp->name);
5292d1661a5SPawel Jakub Dawidek end:
5303650be51SPawel Jakub Dawidek 	g_topology_lock();
5312d1661a5SPawel Jakub Dawidek 	if (cp->acw > 0)
5322d1661a5SPawel Jakub Dawidek 		g_access(cp, 0, -1, -1);
5332d1661a5SPawel Jakub Dawidek 	if (cp->provider != NULL)
5342d1661a5SPawel Jakub Dawidek 		g_detach(cp);
5352d1661a5SPawel Jakub Dawidek 	g_destroy_consumer(cp);
5362d1661a5SPawel Jakub Dawidek 	g_destroy_geom(gp);
5373650be51SPawel Jakub Dawidek 	g_topology_unlock();
5382d1661a5SPawel Jakub Dawidek }
5392d1661a5SPawel Jakub Dawidek 
5402d1661a5SPawel Jakub Dawidek static void
5412d1661a5SPawel Jakub Dawidek g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
5422d1661a5SPawel Jakub Dawidek {
5432d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
5442d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
5452d1661a5SPawel Jakub Dawidek 	const char *name;
5462d1661a5SPawel Jakub Dawidek 	intmax_t *no;
5472d1661a5SPawel Jakub Dawidek 	int *nargs;
5482d1661a5SPawel Jakub Dawidek 
5492d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
5502d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
5512d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
5522d1661a5SPawel Jakub Dawidek 		return;
5532d1661a5SPawel Jakub Dawidek 	}
5542d1661a5SPawel Jakub Dawidek 	if (*nargs != 1) {
5552d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
5562d1661a5SPawel Jakub Dawidek 		return;
5572d1661a5SPawel Jakub Dawidek 	}
5583650be51SPawel Jakub Dawidek 	no = gctl_get_paraml(req, "number", sizeof(*no));
5593650be51SPawel Jakub Dawidek 	if (no == NULL) {
5603650be51SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "no");
5613650be51SPawel Jakub Dawidek 		return;
5623650be51SPawel Jakub Dawidek 	}
5632d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
5642d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
5652d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
5662d1661a5SPawel Jakub Dawidek 		return;
5672d1661a5SPawel Jakub Dawidek 	}
5682d1661a5SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
5692d1661a5SPawel Jakub Dawidek 	if (sc == NULL) {
5702d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
5712d1661a5SPawel Jakub Dawidek 		return;
5722d1661a5SPawel Jakub Dawidek 	}
5732d1661a5SPawel Jakub Dawidek 	if (*no >= sc->sc_ndisks) {
5743650be51SPawel Jakub Dawidek 		sx_xunlock(&sc->sc_lock);
5752d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid component number.");
5762d1661a5SPawel Jakub Dawidek 		return;
5772d1661a5SPawel Jakub Dawidek 	}
5782d1661a5SPawel Jakub Dawidek 	disk = &sc->sc_disks[*no];
5792d1661a5SPawel Jakub Dawidek 	switch (disk->d_state) {
5802d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_ACTIVE:
5812d1661a5SPawel Jakub Dawidek 		/*
5822d1661a5SPawel Jakub Dawidek 		 * When replacing ACTIVE component, all the rest has to be also
5832d1661a5SPawel Jakub Dawidek 		 * ACTIVE.
5842d1661a5SPawel Jakub Dawidek 		 */
5852d1661a5SPawel Jakub Dawidek 		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
5862d1661a5SPawel Jakub Dawidek 		    sc->sc_ndisks) {
5875a20446dSPawel Jakub Dawidek 			gctl_error(req, "Cannot replace component number %jd.",
5882d1661a5SPawel Jakub Dawidek 			    *no);
5893650be51SPawel Jakub Dawidek 			break;
5902d1661a5SPawel Jakub Dawidek 		}
5912d1661a5SPawel Jakub Dawidek 		/* FALLTHROUGH */
5922d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_STALE:
5932d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_SYNCHRONIZING:
5942d1661a5SPawel Jakub Dawidek 		if (g_raid3_clear_metadata(disk) != 0) {
5952d1661a5SPawel Jakub Dawidek 			gctl_error(req, "Cannot clear metadata on %s.",
5962d1661a5SPawel Jakub Dawidek 			    g_raid3_get_diskname(disk));
597a245a548SPawel Jakub Dawidek 		} else {
598a245a548SPawel Jakub Dawidek 			g_raid3_event_send(disk,
599a245a548SPawel Jakub Dawidek 			    G_RAID3_DISK_STATE_DISCONNECTED,
6003650be51SPawel Jakub Dawidek 			    G_RAID3_EVENT_DONTWAIT);
601a245a548SPawel Jakub Dawidek 		}
6022d1661a5SPawel Jakub Dawidek 		break;
6032d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_NODISK:
6042d1661a5SPawel Jakub Dawidek 		break;
6052d1661a5SPawel Jakub Dawidek 	default:
6065a20446dSPawel Jakub Dawidek 		gctl_error(req, "Cannot replace component number %jd.", *no);
6073650be51SPawel Jakub Dawidek 		break;
6082d1661a5SPawel Jakub Dawidek 	}
6093650be51SPawel Jakub Dawidek 	sx_xunlock(&sc->sc_lock);
6102d1661a5SPawel Jakub Dawidek }
6112d1661a5SPawel Jakub Dawidek 
6122d1661a5SPawel Jakub Dawidek void
6132d1661a5SPawel Jakub Dawidek g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
6142d1661a5SPawel Jakub Dawidek {
6152d1661a5SPawel Jakub Dawidek 	uint32_t *version;
6162d1661a5SPawel Jakub Dawidek 
6172d1661a5SPawel Jakub Dawidek 	g_topology_assert();
6182d1661a5SPawel Jakub Dawidek 
6192d1661a5SPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
6202d1661a5SPawel Jakub Dawidek 	if (version == NULL) {
6212d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
6222d1661a5SPawel Jakub Dawidek 		return;
6232d1661a5SPawel Jakub Dawidek 	}
6242d1661a5SPawel Jakub Dawidek 	if (*version != G_RAID3_VERSION) {
6252d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
6262d1661a5SPawel Jakub Dawidek 		return;
6272d1661a5SPawel Jakub Dawidek 	}
6282d1661a5SPawel Jakub Dawidek 
6293650be51SPawel Jakub Dawidek 	g_topology_unlock();
6302d1661a5SPawel Jakub Dawidek 	if (strcmp(verb, "configure") == 0)
6312d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_configure(req, mp);
6322d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "insert") == 0)
6332d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_insert(req, mp);
6342d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "rebuild") == 0)
6352d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_rebuild(req, mp);
6362d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "remove") == 0)
6372d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_remove(req, mp);
6382d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "stop") == 0)
6392d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_stop(req, mp);
6402d1661a5SPawel Jakub Dawidek 	else
6412d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
6423650be51SPawel Jakub Dawidek 	g_topology_lock();
6432d1661a5SPawel Jakub Dawidek }
644