xref: /freebsd/sys/geom/raid3/g_raid3_ctl.c (revision f5a2f7feac56d7bdf1936f6b2e4788888f157b11)
12d1661a5SPawel Jakub Dawidek /*-
22d1661a5SPawel Jakub Dawidek  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
32d1661a5SPawel Jakub Dawidek  * All rights reserved.
42d1661a5SPawel Jakub Dawidek  *
52d1661a5SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
62d1661a5SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
72d1661a5SPawel Jakub Dawidek  * are met:
82d1661a5SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
92d1661a5SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
102d1661a5SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
112d1661a5SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
122d1661a5SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
132d1661a5SPawel Jakub Dawidek  *
142d1661a5SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
152d1661a5SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
162d1661a5SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
172d1661a5SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
182d1661a5SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
192d1661a5SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
202d1661a5SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
212d1661a5SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
222d1661a5SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
232d1661a5SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
242d1661a5SPawel Jakub Dawidek  * SUCH DAMAGE.
252d1661a5SPawel Jakub Dawidek  */
262d1661a5SPawel Jakub Dawidek 
272d1661a5SPawel Jakub Dawidek #include <sys/cdefs.h>
282d1661a5SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
292d1661a5SPawel Jakub Dawidek 
302d1661a5SPawel Jakub Dawidek #include <sys/param.h>
312d1661a5SPawel Jakub Dawidek #include <sys/systm.h>
322d1661a5SPawel Jakub Dawidek #include <sys/kernel.h>
332d1661a5SPawel Jakub Dawidek #include <sys/module.h>
342d1661a5SPawel Jakub Dawidek #include <sys/lock.h>
352d1661a5SPawel Jakub Dawidek #include <sys/mutex.h>
362d1661a5SPawel Jakub Dawidek #include <sys/bio.h>
372d1661a5SPawel Jakub Dawidek #include <sys/sysctl.h>
382d1661a5SPawel Jakub Dawidek #include <sys/malloc.h>
392d1661a5SPawel Jakub Dawidek #include <sys/bitstring.h>
402d1661a5SPawel Jakub Dawidek #include <vm/uma.h>
412d1661a5SPawel Jakub Dawidek #include <machine/atomic.h>
422d1661a5SPawel Jakub Dawidek #include <geom/geom.h>
432d1661a5SPawel Jakub Dawidek #include <sys/proc.h>
442d1661a5SPawel Jakub Dawidek #include <sys/kthread.h>
452d1661a5SPawel Jakub Dawidek #include <geom/raid3/g_raid3.h>
462d1661a5SPawel Jakub Dawidek 
472d1661a5SPawel Jakub Dawidek 
482d1661a5SPawel Jakub Dawidek static struct g_raid3_softc *
492d1661a5SPawel Jakub Dawidek g_raid3_find_device(struct g_class *mp, const char *name)
502d1661a5SPawel Jakub Dawidek {
512d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
522d1661a5SPawel Jakub Dawidek 	struct g_geom *gp;
532d1661a5SPawel Jakub Dawidek 
542d1661a5SPawel Jakub Dawidek 	g_topology_assert();
552d1661a5SPawel Jakub Dawidek 	LIST_FOREACH(gp, &mp->geom, geom) {
562d1661a5SPawel Jakub Dawidek 		sc = gp->softc;
572d1661a5SPawel Jakub Dawidek 		if (sc == NULL)
582d1661a5SPawel Jakub Dawidek 			continue;
592d1661a5SPawel Jakub Dawidek 		if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0)
602d1661a5SPawel Jakub Dawidek 			continue;
612d1661a5SPawel Jakub Dawidek 		if (strcmp(gp->name, name) == 0 ||
622d1661a5SPawel Jakub Dawidek 		    strcmp(sc->sc_name, name) == 0) {
632d1661a5SPawel Jakub Dawidek 			return (sc);
642d1661a5SPawel Jakub Dawidek 		}
652d1661a5SPawel Jakub Dawidek 	}
662d1661a5SPawel Jakub Dawidek 	return (NULL);
672d1661a5SPawel Jakub Dawidek }
682d1661a5SPawel Jakub Dawidek 
692d1661a5SPawel Jakub Dawidek static struct g_raid3_disk *
702d1661a5SPawel Jakub Dawidek g_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
712d1661a5SPawel Jakub Dawidek {
722d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
732d1661a5SPawel Jakub Dawidek 	u_int n;
742d1661a5SPawel Jakub Dawidek 
752d1661a5SPawel Jakub Dawidek 	g_topology_assert();
762d1661a5SPawel Jakub Dawidek 	for (n = 0; n < sc->sc_ndisks; n++) {
772d1661a5SPawel Jakub Dawidek 		disk = &sc->sc_disks[n];
782d1661a5SPawel Jakub Dawidek 		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
792d1661a5SPawel Jakub Dawidek 			continue;
802d1661a5SPawel Jakub Dawidek 		if (disk->d_consumer == NULL)
812d1661a5SPawel Jakub Dawidek 			continue;
822d1661a5SPawel Jakub Dawidek 		if (disk->d_consumer->provider == NULL)
832d1661a5SPawel Jakub Dawidek 			continue;
842d1661a5SPawel Jakub Dawidek 		if (strcmp(disk->d_consumer->provider->name, name) == 0)
852d1661a5SPawel Jakub Dawidek 			return (disk);
862d1661a5SPawel Jakub Dawidek 	}
872d1661a5SPawel Jakub Dawidek 	return (NULL);
882d1661a5SPawel Jakub Dawidek }
892d1661a5SPawel Jakub Dawidek 
902d1661a5SPawel Jakub Dawidek static void
912d1661a5SPawel Jakub Dawidek g_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
922d1661a5SPawel Jakub Dawidek {
932d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
942d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
952d1661a5SPawel Jakub Dawidek 	const char *name;
96f5a2f7feSPawel Jakub Dawidek 	int *nargs, do_sync = 0;
97f5a2f7feSPawel Jakub Dawidek 	int *autosync, *noautosync, *round_robin, *noround_robin;
982d1661a5SPawel Jakub Dawidek 	u_int n;
992d1661a5SPawel Jakub Dawidek 
1002d1661a5SPawel Jakub Dawidek 	g_topology_assert();
1012d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1022d1661a5SPawel Jakub Dawidek 	if (*nargs != 1) {
1032d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
1042d1661a5SPawel Jakub Dawidek 		return;
1052d1661a5SPawel Jakub Dawidek 	}
1062d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
1072d1661a5SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
1082d1661a5SPawel Jakub Dawidek 	if (sc == NULL) {
1092d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
1102d1661a5SPawel Jakub Dawidek 		return;
1112d1661a5SPawel Jakub Dawidek 	}
1122d1661a5SPawel Jakub Dawidek 	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
1132d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Not all disks connected.");
1142d1661a5SPawel Jakub Dawidek 		return;
1152d1661a5SPawel Jakub Dawidek 	}
1162d1661a5SPawel Jakub Dawidek 	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
1172d1661a5SPawel Jakub Dawidek 	if (autosync == NULL) {
1182d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "autosync");
1192d1661a5SPawel Jakub Dawidek 		return;
1202d1661a5SPawel Jakub Dawidek 	}
1212d1661a5SPawel Jakub Dawidek 	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
1222d1661a5SPawel Jakub Dawidek 	if (noautosync == NULL) {
1232d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "noautosync");
1242d1661a5SPawel Jakub Dawidek 		return;
1252d1661a5SPawel Jakub Dawidek 	}
1262d1661a5SPawel Jakub Dawidek 	if (*autosync && *noautosync) {
1272d1661a5SPawel Jakub Dawidek 		gctl_error(req, "'%s' and '%s' specified.", "autosync",
1282d1661a5SPawel Jakub Dawidek 		    "noautosync");
1292d1661a5SPawel Jakub Dawidek 		return;
1302d1661a5SPawel Jakub Dawidek 	}
131f5a2f7feSPawel Jakub Dawidek 	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
132f5a2f7feSPawel Jakub Dawidek 	if (round_robin == NULL) {
133f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "round_robin");
134f5a2f7feSPawel Jakub Dawidek 		return;
135f5a2f7feSPawel Jakub Dawidek 	}
136f5a2f7feSPawel Jakub Dawidek 	noround_robin = gctl_get_paraml(req, "noround_robin",
137f5a2f7feSPawel Jakub Dawidek 	    sizeof(*noround_robin));
138f5a2f7feSPawel Jakub Dawidek 	if (noround_robin == NULL) {
139f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "noround_robin");
140f5a2f7feSPawel Jakub Dawidek 		return;
141f5a2f7feSPawel Jakub Dawidek 	}
142f5a2f7feSPawel Jakub Dawidek 	if (*round_robin && *noround_robin) {
143f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
144f5a2f7feSPawel Jakub Dawidek 		    "noround_robin");
145f5a2f7feSPawel Jakub Dawidek 		return;
146f5a2f7feSPawel Jakub Dawidek 	}
147f5a2f7feSPawel Jakub Dawidek 	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin) {
148f5a2f7feSPawel Jakub Dawidek 		gctl_error(req, "Nothing has changed.");
149f5a2f7feSPawel Jakub Dawidek 		return;
150f5a2f7feSPawel Jakub Dawidek 	}
1512d1661a5SPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
1522d1661a5SPawel Jakub Dawidek 		if (*autosync) {
1532d1661a5SPawel Jakub Dawidek 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
1542d1661a5SPawel Jakub Dawidek 			do_sync = 1;
1552d1661a5SPawel Jakub Dawidek 		}
1562d1661a5SPawel Jakub Dawidek 	} else {
1572d1661a5SPawel Jakub Dawidek 		if (*noautosync)
1582d1661a5SPawel Jakub Dawidek 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
1592d1661a5SPawel Jakub Dawidek 	}
160f5a2f7feSPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
161f5a2f7feSPawel Jakub Dawidek 		if (*noround_robin)
162f5a2f7feSPawel Jakub Dawidek 			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
163f5a2f7feSPawel Jakub Dawidek 	} else {
164f5a2f7feSPawel Jakub Dawidek 		if (*round_robin)
165f5a2f7feSPawel Jakub Dawidek 			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
166f5a2f7feSPawel Jakub Dawidek 	}
1672d1661a5SPawel Jakub Dawidek 	for (n = 0; n < sc->sc_ndisks; n++) {
1682d1661a5SPawel Jakub Dawidek 		disk = &sc->sc_disks[n];
1692d1661a5SPawel Jakub Dawidek 		if (do_sync) {
1702d1661a5SPawel Jakub Dawidek 			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
1712d1661a5SPawel Jakub Dawidek 				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
1722d1661a5SPawel Jakub Dawidek 		}
1732d1661a5SPawel Jakub Dawidek 		g_raid3_update_metadata(disk);
1742d1661a5SPawel Jakub Dawidek 		if (do_sync) {
1752d1661a5SPawel Jakub Dawidek 			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
1762d1661a5SPawel Jakub Dawidek 				/*
1772d1661a5SPawel Jakub Dawidek 				 * XXX: This is probably possible that this
1782d1661a5SPawel Jakub Dawidek 				 *      component will not be retasted.
1792d1661a5SPawel Jakub Dawidek 				 */
1802d1661a5SPawel Jakub Dawidek 				g_raid3_event_send(disk,
1812d1661a5SPawel Jakub Dawidek 				    G_RAID3_DISK_STATE_DISCONNECTED,
1822d1661a5SPawel Jakub Dawidek 				    G_RAID3_EVENT_DONTWAIT);
1832d1661a5SPawel Jakub Dawidek 			}
1842d1661a5SPawel Jakub Dawidek 		}
1852d1661a5SPawel Jakub Dawidek 	}
1862d1661a5SPawel Jakub Dawidek }
1872d1661a5SPawel Jakub Dawidek 
1882d1661a5SPawel Jakub Dawidek static void
1892d1661a5SPawel Jakub Dawidek g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
1902d1661a5SPawel Jakub Dawidek {
1912d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
1922d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
1932d1661a5SPawel Jakub Dawidek 	const char *name;
1942d1661a5SPawel Jakub Dawidek 	int *nargs;
1952d1661a5SPawel Jakub Dawidek 
1962d1661a5SPawel Jakub Dawidek 	g_topology_assert();
1972d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
1982d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
1992d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
2002d1661a5SPawel Jakub Dawidek 		return;
2012d1661a5SPawel Jakub Dawidek 	}
2022d1661a5SPawel Jakub Dawidek 	if (*nargs != 2) {
2032d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
2042d1661a5SPawel Jakub Dawidek 		return;
2052d1661a5SPawel Jakub Dawidek 	}
2062d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
2072d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
2082d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
2092d1661a5SPawel Jakub Dawidek 		return;
2102d1661a5SPawel Jakub Dawidek 	}
2112d1661a5SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
2122d1661a5SPawel Jakub Dawidek 	if (sc == NULL) {
2132d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
2142d1661a5SPawel Jakub Dawidek 		return;
2152d1661a5SPawel Jakub Dawidek 	}
2162d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg1");
2172d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
2182d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 1);
2192d1661a5SPawel Jakub Dawidek 		return;
2202d1661a5SPawel Jakub Dawidek 	}
2212d1661a5SPawel Jakub Dawidek 	disk = g_raid3_find_disk(sc, name);
2222d1661a5SPawel Jakub Dawidek 	if (disk == NULL) {
2232d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such provider: %s.", name);
2242d1661a5SPawel Jakub Dawidek 		return;
2252d1661a5SPawel Jakub Dawidek 	}
2262d1661a5SPawel Jakub Dawidek 	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
2272d1661a5SPawel Jakub Dawidek 	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
2282d1661a5SPawel Jakub Dawidek 		gctl_error(req, "There is one stale disk already.", name);
2292d1661a5SPawel Jakub Dawidek 		return;
2302d1661a5SPawel Jakub Dawidek 	}
2312d1661a5SPawel Jakub Dawidek 	/*
2322d1661a5SPawel Jakub Dawidek 	 * Do rebuild by resetting syncid and disconnecting disk.
2332d1661a5SPawel Jakub Dawidek 	 * It'll be retasted, connected to the device and synchronized.
2342d1661a5SPawel Jakub Dawidek 	 */
2352d1661a5SPawel Jakub Dawidek 	disk->d_sync.ds_syncid = 0;
2362d1661a5SPawel Jakub Dawidek 	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
2372d1661a5SPawel Jakub Dawidek 		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
2382d1661a5SPawel Jakub Dawidek 	g_raid3_update_metadata(disk);
2392d1661a5SPawel Jakub Dawidek 	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
2402d1661a5SPawel Jakub Dawidek 	    G_RAID3_EVENT_WAIT);
2412d1661a5SPawel Jakub Dawidek }
2422d1661a5SPawel Jakub Dawidek 
2432d1661a5SPawel Jakub Dawidek static void
2442d1661a5SPawel Jakub Dawidek g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
2452d1661a5SPawel Jakub Dawidek {
2462d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
2472d1661a5SPawel Jakub Dawidek 	int *force, *nargs, error;
2482d1661a5SPawel Jakub Dawidek 	const char *name;
2492d1661a5SPawel Jakub Dawidek 	char param[16];
2502d1661a5SPawel Jakub Dawidek 	u_int i;
2512d1661a5SPawel Jakub Dawidek 
2522d1661a5SPawel Jakub Dawidek 	g_topology_assert();
2532d1661a5SPawel Jakub Dawidek 
2542d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
2552d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
2562d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
2572d1661a5SPawel Jakub Dawidek 		return;
2582d1661a5SPawel Jakub Dawidek 	}
2592d1661a5SPawel Jakub Dawidek 	if (*nargs < 1) {
2602d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Missing device(s).");
2612d1661a5SPawel Jakub Dawidek 		return;
2622d1661a5SPawel Jakub Dawidek 	}
2632d1661a5SPawel Jakub Dawidek 	force = gctl_get_paraml(req, "force", sizeof(*force));
2642d1661a5SPawel Jakub Dawidek 	if (force == NULL) {
2652d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "force");
2662d1661a5SPawel Jakub Dawidek 		return;
2672d1661a5SPawel Jakub Dawidek 	}
2682d1661a5SPawel Jakub Dawidek 
2692d1661a5SPawel Jakub Dawidek 	for (i = 0; i < (u_int)*nargs; i++) {
2702d1661a5SPawel Jakub Dawidek 		snprintf(param, sizeof(param), "arg%u", i);
2712d1661a5SPawel Jakub Dawidek 		name = gctl_get_asciiparam(req, param);
2722d1661a5SPawel Jakub Dawidek 		if (name == NULL) {
2732d1661a5SPawel Jakub Dawidek 			gctl_error(req, "No 'arg%u' argument.", i);
2742d1661a5SPawel Jakub Dawidek 			return;
2752d1661a5SPawel Jakub Dawidek 		}
2762d1661a5SPawel Jakub Dawidek 		sc = g_raid3_find_device(mp, name);
2772d1661a5SPawel Jakub Dawidek 		if (sc == NULL) {
2782d1661a5SPawel Jakub Dawidek 			gctl_error(req, "No such device: %s.", name);
2792d1661a5SPawel Jakub Dawidek 			return;
2802d1661a5SPawel Jakub Dawidek 		}
2812d1661a5SPawel Jakub Dawidek 		error = g_raid3_destroy(sc, *force);
2822d1661a5SPawel Jakub Dawidek 		if (error != 0) {
2832d1661a5SPawel Jakub Dawidek 			gctl_error(req, "Cannot destroy device %s (error=%d).",
2842d1661a5SPawel Jakub Dawidek 			    sc->sc_geom->name, error);
2852d1661a5SPawel Jakub Dawidek 			return;
2862d1661a5SPawel Jakub Dawidek 		}
2872d1661a5SPawel Jakub Dawidek 	}
2882d1661a5SPawel Jakub Dawidek }
2892d1661a5SPawel Jakub Dawidek 
2902d1661a5SPawel Jakub Dawidek static void
2912d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert_orphan(struct g_consumer *cp)
2922d1661a5SPawel Jakub Dawidek {
2932d1661a5SPawel Jakub Dawidek 
2942d1661a5SPawel Jakub Dawidek 	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
2952d1661a5SPawel Jakub Dawidek 	    cp->provider->name));
2962d1661a5SPawel Jakub Dawidek }
2972d1661a5SPawel Jakub Dawidek 
2982d1661a5SPawel Jakub Dawidek static void
2992d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
3002d1661a5SPawel Jakub Dawidek {
3012d1661a5SPawel Jakub Dawidek 	struct g_raid3_metadata md;
3022d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
3032d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
3042d1661a5SPawel Jakub Dawidek 	struct g_geom *gp;
3052d1661a5SPawel Jakub Dawidek 	struct g_provider *pp;
3062d1661a5SPawel Jakub Dawidek 	struct g_consumer *cp;
3072d1661a5SPawel Jakub Dawidek 	const char *name;
3082d1661a5SPawel Jakub Dawidek 	u_char *sector;
3092d1661a5SPawel Jakub Dawidek 	intmax_t *no;
3102d1661a5SPawel Jakub Dawidek 	int *hardcode, *nargs, error;
3112d1661a5SPawel Jakub Dawidek 
3122d1661a5SPawel Jakub Dawidek 	g_topology_assert();
3132d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
3142d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
3152d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
3162d1661a5SPawel Jakub Dawidek 		return;
3172d1661a5SPawel Jakub Dawidek 	}
3182d1661a5SPawel Jakub Dawidek 	if (*nargs != 2) {
3192d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
3202d1661a5SPawel Jakub Dawidek 		return;
3212d1661a5SPawel Jakub Dawidek 	}
3222d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
3232d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
3242d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
3252d1661a5SPawel Jakub Dawidek 		return;
3262d1661a5SPawel Jakub Dawidek 	}
3272d1661a5SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
3282d1661a5SPawel Jakub Dawidek 	if (sc == NULL) {
3292d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
3302d1661a5SPawel Jakub Dawidek 		return;
3312d1661a5SPawel Jakub Dawidek 	}
3322d1661a5SPawel Jakub Dawidek 	no = gctl_get_paraml(req, "number", sizeof(*no));
3332d1661a5SPawel Jakub Dawidek 	if (no == NULL) {
3342d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "no");
3352d1661a5SPawel Jakub Dawidek 		return;
3362d1661a5SPawel Jakub Dawidek 	}
3372d1661a5SPawel Jakub Dawidek 	if (*no >= sc->sc_ndisks) {
3382d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid component number.");
3392d1661a5SPawel Jakub Dawidek 		return;
3402d1661a5SPawel Jakub Dawidek 	}
3412d1661a5SPawel Jakub Dawidek 	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
3422d1661a5SPawel Jakub Dawidek 	if (hardcode == NULL) {
3432d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "hardcode");
3442d1661a5SPawel Jakub Dawidek 		return;
3452d1661a5SPawel Jakub Dawidek 	}
3462d1661a5SPawel Jakub Dawidek 	disk = &sc->sc_disks[*no];
3472d1661a5SPawel Jakub Dawidek 	if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
3482d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Component %u is already connected.", *no);
3492d1661a5SPawel Jakub Dawidek 		return;
3502d1661a5SPawel Jakub Dawidek 	}
3512d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg1");
3522d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
3532d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 1);
3542d1661a5SPawel Jakub Dawidek 		return;
3552d1661a5SPawel Jakub Dawidek 	}
3562d1661a5SPawel Jakub Dawidek 	pp = g_provider_by_name(name);
3572d1661a5SPawel Jakub Dawidek 	if (pp == NULL) {
3582d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid provider.");
3592d1661a5SPawel Jakub Dawidek 		return;
3602d1661a5SPawel Jakub Dawidek 	}
3612d1661a5SPawel Jakub Dawidek 	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
3622d1661a5SPawel Jakub Dawidek 		gctl_error(req,
3632d1661a5SPawel Jakub Dawidek 		    "Cannot insert provider %s, because of its sector size.",
3642d1661a5SPawel Jakub Dawidek 		    pp->name);
3652d1661a5SPawel Jakub Dawidek 		return;
3662d1661a5SPawel Jakub Dawidek 	}
3672d1661a5SPawel Jakub Dawidek 	gp = g_new_geomf(mp, "raid3:insert");
3682d1661a5SPawel Jakub Dawidek 	gp->orphan = g_raid3_ctl_insert_orphan;
3692d1661a5SPawel Jakub Dawidek 	cp = g_new_consumer(gp);
3702d1661a5SPawel Jakub Dawidek 	error = g_attach(cp, pp);
3712d1661a5SPawel Jakub Dawidek 	if (error != 0) {
3722d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Cannot attach to %s.", pp->name);
3732d1661a5SPawel Jakub Dawidek 		goto end;
3742d1661a5SPawel Jakub Dawidek 	}
3752d1661a5SPawel Jakub Dawidek 	error = g_access(cp, 0, 1, 1);
3762d1661a5SPawel Jakub Dawidek 	if (error != 0) {
3772d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Cannot access %s.", pp->name);
3782d1661a5SPawel Jakub Dawidek 		goto end;
3792d1661a5SPawel Jakub Dawidek 	}
3802d1661a5SPawel Jakub Dawidek 	g_raid3_fill_metadata(disk, &md);
3812d1661a5SPawel Jakub Dawidek 	md.md_syncid = 0;
3822d1661a5SPawel Jakub Dawidek         md.md_dflags = 0;
3832d1661a5SPawel Jakub Dawidek 	if (*hardcode)
3842d1661a5SPawel Jakub Dawidek                 strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
3852d1661a5SPawel Jakub Dawidek         else
3862d1661a5SPawel Jakub Dawidek                 bzero(md.md_provider, sizeof(md.md_provider));
3872d1661a5SPawel Jakub Dawidek 	sector = g_malloc(pp->sectorsize, M_WAITOK);
3882d1661a5SPawel Jakub Dawidek 	raid3_metadata_encode(&md, sector);
3892d1661a5SPawel Jakub Dawidek 	g_topology_unlock();
3902d1661a5SPawel Jakub Dawidek 	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
3912d1661a5SPawel Jakub Dawidek 	    pp->sectorsize);
3922d1661a5SPawel Jakub Dawidek 	g_topology_lock();
3932d1661a5SPawel Jakub Dawidek 	g_free(sector);
3942d1661a5SPawel Jakub Dawidek 	if (error != 0)
3952d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Cannot store metadata on %s.", pp->name);
3962d1661a5SPawel Jakub Dawidek end:
3972d1661a5SPawel Jakub Dawidek 	if (gp != NULL) {
3982d1661a5SPawel Jakub Dawidek 		if (cp != NULL) {
3992d1661a5SPawel Jakub Dawidek 			if (cp->acw > 0)
4002d1661a5SPawel Jakub Dawidek 				g_access(cp, 0, -1, -1);
4012d1661a5SPawel Jakub Dawidek 			if (cp->provider != NULL)
4022d1661a5SPawel Jakub Dawidek 				g_detach(cp);
4032d1661a5SPawel Jakub Dawidek 			g_destroy_consumer(cp);
4042d1661a5SPawel Jakub Dawidek 		}
4052d1661a5SPawel Jakub Dawidek 		g_destroy_geom(gp);
4062d1661a5SPawel Jakub Dawidek 	}
4072d1661a5SPawel Jakub Dawidek }
4082d1661a5SPawel Jakub Dawidek 
4092d1661a5SPawel Jakub Dawidek static void
4102d1661a5SPawel Jakub Dawidek g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
4112d1661a5SPawel Jakub Dawidek {
4122d1661a5SPawel Jakub Dawidek 	struct g_raid3_softc *sc;
4132d1661a5SPawel Jakub Dawidek 	struct g_raid3_disk *disk;
4142d1661a5SPawel Jakub Dawidek 	const char *name;
4152d1661a5SPawel Jakub Dawidek 	intmax_t *no;
4162d1661a5SPawel Jakub Dawidek 	int *nargs;
4172d1661a5SPawel Jakub Dawidek 
4182d1661a5SPawel Jakub Dawidek 	g_topology_assert();
4192d1661a5SPawel Jakub Dawidek 	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
4202d1661a5SPawel Jakub Dawidek 	if (nargs == NULL) {
4212d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "nargs");
4222d1661a5SPawel Jakub Dawidek 		return;
4232d1661a5SPawel Jakub Dawidek 	}
4242d1661a5SPawel Jakub Dawidek 	if (*nargs != 1) {
4252d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid number of arguments.");
4262d1661a5SPawel Jakub Dawidek 		return;
4272d1661a5SPawel Jakub Dawidek 	}
4282d1661a5SPawel Jakub Dawidek 	name = gctl_get_asciiparam(req, "arg0");
4292d1661a5SPawel Jakub Dawidek 	if (name == NULL) {
4302d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No 'arg%u' argument.", 0);
4312d1661a5SPawel Jakub Dawidek 		return;
4322d1661a5SPawel Jakub Dawidek 	}
4332d1661a5SPawel Jakub Dawidek 	sc = g_raid3_find_device(mp, name);
4342d1661a5SPawel Jakub Dawidek 	if (sc == NULL) {
4352d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No such device: %s.", name);
4362d1661a5SPawel Jakub Dawidek 		return;
4372d1661a5SPawel Jakub Dawidek 	}
4382d1661a5SPawel Jakub Dawidek 	no = gctl_get_paraml(req, "number", sizeof(*no));
4392d1661a5SPawel Jakub Dawidek 	if (no == NULL) {
4402d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "no");
4412d1661a5SPawel Jakub Dawidek 		return;
4422d1661a5SPawel Jakub Dawidek 	}
4432d1661a5SPawel Jakub Dawidek 	if (*no >= sc->sc_ndisks) {
4442d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Invalid component number.");
4452d1661a5SPawel Jakub Dawidek 		return;
4462d1661a5SPawel Jakub Dawidek 	}
4472d1661a5SPawel Jakub Dawidek 	disk = &sc->sc_disks[*no];
4482d1661a5SPawel Jakub Dawidek 	switch (disk->d_state) {
4492d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_ACTIVE:
4502d1661a5SPawel Jakub Dawidek 		/*
4512d1661a5SPawel Jakub Dawidek 		 * When replacing ACTIVE component, all the rest has to be also
4522d1661a5SPawel Jakub Dawidek 		 * ACTIVE.
4532d1661a5SPawel Jakub Dawidek 		 */
4542d1661a5SPawel Jakub Dawidek 		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
4552d1661a5SPawel Jakub Dawidek 		    sc->sc_ndisks) {
4562d1661a5SPawel Jakub Dawidek 			gctl_error(req, "Cannot replace component number %u.",
4572d1661a5SPawel Jakub Dawidek 			    *no);
4582d1661a5SPawel Jakub Dawidek 			return;
4592d1661a5SPawel Jakub Dawidek 		}
4602d1661a5SPawel Jakub Dawidek 		/* FALLTHROUGH */
4612d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_STALE:
4622d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_SYNCHRONIZING:
4632d1661a5SPawel Jakub Dawidek 		if (g_raid3_clear_metadata(disk) != 0) {
4642d1661a5SPawel Jakub Dawidek 			gctl_error(req, "Cannot clear metadata on %s.",
4652d1661a5SPawel Jakub Dawidek 			    g_raid3_get_diskname(disk));
4662d1661a5SPawel Jakub Dawidek 			sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY;
4672d1661a5SPawel Jakub Dawidek 		}
4682d1661a5SPawel Jakub Dawidek 		g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
4692d1661a5SPawel Jakub Dawidek 		    G_RAID3_EVENT_WAIT);
4702d1661a5SPawel Jakub Dawidek 		break;
4712d1661a5SPawel Jakub Dawidek 	case G_RAID3_DISK_STATE_NODISK:
4722d1661a5SPawel Jakub Dawidek 		break;
4732d1661a5SPawel Jakub Dawidek 	default:
4742d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Cannot replace component number %u.", *no);
4752d1661a5SPawel Jakub Dawidek 		return;
4762d1661a5SPawel Jakub Dawidek 	}
4772d1661a5SPawel Jakub Dawidek }
4782d1661a5SPawel Jakub Dawidek 
4792d1661a5SPawel Jakub Dawidek void
4802d1661a5SPawel Jakub Dawidek g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
4812d1661a5SPawel Jakub Dawidek {
4822d1661a5SPawel Jakub Dawidek 	uint32_t *version;
4832d1661a5SPawel Jakub Dawidek 
4842d1661a5SPawel Jakub Dawidek 	g_topology_assert();
4852d1661a5SPawel Jakub Dawidek 
4862d1661a5SPawel Jakub Dawidek 	version = gctl_get_paraml(req, "version", sizeof(*version));
4872d1661a5SPawel Jakub Dawidek 	if (version == NULL) {
4882d1661a5SPawel Jakub Dawidek 		gctl_error(req, "No '%s' argument.", "version");
4892d1661a5SPawel Jakub Dawidek 		return;
4902d1661a5SPawel Jakub Dawidek 	}
4912d1661a5SPawel Jakub Dawidek 	if (*version != G_RAID3_VERSION) {
4922d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Userland and kernel parts are out of sync.");
4932d1661a5SPawel Jakub Dawidek 		return;
4942d1661a5SPawel Jakub Dawidek 	}
4952d1661a5SPawel Jakub Dawidek 
4962d1661a5SPawel Jakub Dawidek 	if (strcmp(verb, "configure") == 0)
4972d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_configure(req, mp);
4982d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "insert") == 0)
4992d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_insert(req, mp);
5002d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "rebuild") == 0)
5012d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_rebuild(req, mp);
5022d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "remove") == 0)
5032d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_remove(req, mp);
5042d1661a5SPawel Jakub Dawidek 	else if (strcmp(verb, "stop") == 0)
5052d1661a5SPawel Jakub Dawidek 		g_raid3_ctl_stop(req, mp);
5062d1661a5SPawel Jakub Dawidek 	else
5072d1661a5SPawel Jakub Dawidek 		gctl_error(req, "Unknown verb.");
5082d1661a5SPawel Jakub Dawidek }
509