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; 97dba915cfSPawel Jakub Dawidek int *autosync, *noautosync; 98dba915cfSPawel Jakub Dawidek int *round_robin, *noround_robin; 99dba915cfSPawel Jakub Dawidek int *verify, *noverify; 1002d1661a5SPawel Jakub Dawidek u_int n; 1012d1661a5SPawel Jakub Dawidek 1022d1661a5SPawel Jakub Dawidek g_topology_assert(); 1032d1661a5SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 1042d1661a5SPawel Jakub Dawidek if (*nargs != 1) { 1052d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 1062d1661a5SPawel Jakub Dawidek return; 1072d1661a5SPawel Jakub Dawidek } 1082d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 1092d1661a5SPawel Jakub Dawidek sc = g_raid3_find_device(mp, name); 1102d1661a5SPawel Jakub Dawidek if (sc == NULL) { 1112d1661a5SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name); 1122d1661a5SPawel Jakub Dawidek return; 1132d1661a5SPawel Jakub Dawidek } 1142d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 1152d1661a5SPawel Jakub Dawidek gctl_error(req, "Not all disks connected."); 1162d1661a5SPawel Jakub Dawidek return; 1172d1661a5SPawel Jakub Dawidek } 1182d1661a5SPawel Jakub Dawidek autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 1192d1661a5SPawel Jakub Dawidek if (autosync == NULL) { 1202d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "autosync"); 1212d1661a5SPawel Jakub Dawidek return; 1222d1661a5SPawel Jakub Dawidek } 1232d1661a5SPawel Jakub Dawidek noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 1242d1661a5SPawel Jakub Dawidek if (noautosync == NULL) { 1252d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "noautosync"); 1262d1661a5SPawel Jakub Dawidek return; 1272d1661a5SPawel Jakub Dawidek } 1282d1661a5SPawel Jakub Dawidek if (*autosync && *noautosync) { 1292d1661a5SPawel Jakub Dawidek gctl_error(req, "'%s' and '%s' specified.", "autosync", 1302d1661a5SPawel Jakub Dawidek "noautosync"); 1312d1661a5SPawel Jakub Dawidek return; 1322d1661a5SPawel Jakub Dawidek } 133f5a2f7feSPawel Jakub Dawidek round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 134f5a2f7feSPawel Jakub Dawidek if (round_robin == NULL) { 135f5a2f7feSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "round_robin"); 136f5a2f7feSPawel Jakub Dawidek return; 137f5a2f7feSPawel Jakub Dawidek } 138f5a2f7feSPawel Jakub Dawidek noround_robin = gctl_get_paraml(req, "noround_robin", 139f5a2f7feSPawel Jakub Dawidek sizeof(*noround_robin)); 140f5a2f7feSPawel Jakub Dawidek if (noround_robin == NULL) { 141f5a2f7feSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "noround_robin"); 142f5a2f7feSPawel Jakub Dawidek return; 143f5a2f7feSPawel Jakub Dawidek } 144f5a2f7feSPawel Jakub Dawidek if (*round_robin && *noround_robin) { 145f5a2f7feSPawel Jakub Dawidek gctl_error(req, "'%s' and '%s' specified.", "round_robin", 146f5a2f7feSPawel Jakub Dawidek "noround_robin"); 147f5a2f7feSPawel Jakub Dawidek return; 148f5a2f7feSPawel Jakub Dawidek } 149dba915cfSPawel Jakub Dawidek verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 150dba915cfSPawel Jakub Dawidek if (verify == NULL) { 151dba915cfSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "verify"); 152dba915cfSPawel Jakub Dawidek return; 153dba915cfSPawel Jakub Dawidek } 154dba915cfSPawel Jakub Dawidek noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 155dba915cfSPawel Jakub Dawidek if (noverify == NULL) { 156dba915cfSPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "noverify"); 157dba915cfSPawel Jakub Dawidek return; 158dba915cfSPawel Jakub Dawidek } 159dba915cfSPawel Jakub Dawidek if (*verify && *noverify) { 160dba915cfSPawel Jakub Dawidek gctl_error(req, "'%s' and '%s' specified.", "verify", 161dba915cfSPawel Jakub Dawidek "noverify"); 162dba915cfSPawel Jakub Dawidek return; 163dba915cfSPawel Jakub Dawidek } 164dba915cfSPawel Jakub Dawidek if (!*autosync && !*noautosync && !*round_robin && !*noround_robin && 165dba915cfSPawel Jakub Dawidek !*verify && !*noverify) { 166f5a2f7feSPawel Jakub Dawidek gctl_error(req, "Nothing has changed."); 167f5a2f7feSPawel Jakub Dawidek return; 168f5a2f7feSPawel Jakub Dawidek } 1692d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 1702d1661a5SPawel Jakub Dawidek if (*autosync) { 1712d1661a5SPawel Jakub Dawidek sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 1722d1661a5SPawel Jakub Dawidek do_sync = 1; 1732d1661a5SPawel Jakub Dawidek } 1742d1661a5SPawel Jakub Dawidek } else { 1752d1661a5SPawel Jakub Dawidek if (*noautosync) 1762d1661a5SPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 1772d1661a5SPawel Jakub Dawidek } 178dba915cfSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 179dba915cfSPawel Jakub Dawidek if (*noverify) 180dba915cfSPawel Jakub Dawidek sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 181dba915cfSPawel Jakub Dawidek } else { 182dba915cfSPawel Jakub Dawidek if (*verify) 183dba915cfSPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 184dba915cfSPawel Jakub Dawidek } 185f5a2f7feSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 186f5a2f7feSPawel Jakub Dawidek if (*noround_robin) 187f5a2f7feSPawel Jakub Dawidek sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 188f5a2f7feSPawel Jakub Dawidek } else { 189f5a2f7feSPawel Jakub Dawidek if (*round_robin) 190f5a2f7feSPawel Jakub Dawidek sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 191f5a2f7feSPawel Jakub Dawidek } 192dba915cfSPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 193dba915cfSPawel Jakub Dawidek (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 194dba915cfSPawel Jakub Dawidek /* 195dba915cfSPawel Jakub Dawidek * VERIFY and ROUND-ROBIN options are mutally exclusive. 196dba915cfSPawel Jakub Dawidek */ 197dba915cfSPawel Jakub Dawidek sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 198dba915cfSPawel Jakub Dawidek } 1992d1661a5SPawel Jakub Dawidek for (n = 0; n < sc->sc_ndisks; n++) { 2002d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[n]; 2012d1661a5SPawel Jakub Dawidek if (do_sync) { 2022d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 2032d1661a5SPawel Jakub Dawidek disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 2042d1661a5SPawel Jakub Dawidek } 2052d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 2062d1661a5SPawel Jakub Dawidek if (do_sync) { 2072d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 2082d1661a5SPawel Jakub Dawidek /* 2092d1661a5SPawel Jakub Dawidek * XXX: This is probably possible that this 2102d1661a5SPawel Jakub Dawidek * component will not be retasted. 2112d1661a5SPawel Jakub Dawidek */ 2122d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, 2132d1661a5SPawel Jakub Dawidek G_RAID3_DISK_STATE_DISCONNECTED, 2142d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_DONTWAIT); 2152d1661a5SPawel Jakub Dawidek } 2162d1661a5SPawel Jakub Dawidek } 2172d1661a5SPawel Jakub Dawidek } 2182d1661a5SPawel Jakub Dawidek } 2192d1661a5SPawel Jakub Dawidek 2202d1661a5SPawel Jakub Dawidek static void 2212d1661a5SPawel Jakub Dawidek g_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 2222d1661a5SPawel Jakub Dawidek { 2232d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2242d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 2252d1661a5SPawel Jakub Dawidek const char *name; 2262d1661a5SPawel Jakub Dawidek int *nargs; 2272d1661a5SPawel Jakub Dawidek 2282d1661a5SPawel Jakub Dawidek g_topology_assert(); 2292d1661a5SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 2302d1661a5SPawel Jakub Dawidek if (nargs == NULL) { 2312d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 2322d1661a5SPawel Jakub Dawidek return; 2332d1661a5SPawel Jakub Dawidek } 2342d1661a5SPawel Jakub Dawidek if (*nargs != 2) { 2352d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 2362d1661a5SPawel Jakub Dawidek return; 2372d1661a5SPawel Jakub Dawidek } 2382d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 2392d1661a5SPawel Jakub Dawidek if (name == NULL) { 2402d1661a5SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 2412d1661a5SPawel Jakub Dawidek return; 2422d1661a5SPawel Jakub Dawidek } 2432d1661a5SPawel Jakub Dawidek sc = g_raid3_find_device(mp, name); 2442d1661a5SPawel Jakub Dawidek if (sc == NULL) { 2452d1661a5SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name); 2462d1661a5SPawel Jakub Dawidek return; 2472d1661a5SPawel Jakub Dawidek } 2482d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg1"); 2492d1661a5SPawel Jakub Dawidek if (name == NULL) { 2502d1661a5SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 1); 2512d1661a5SPawel Jakub Dawidek return; 2522d1661a5SPawel Jakub Dawidek } 2532d1661a5SPawel Jakub Dawidek disk = g_raid3_find_disk(sc, name); 2542d1661a5SPawel Jakub Dawidek if (disk == NULL) { 2552d1661a5SPawel Jakub Dawidek gctl_error(req, "No such provider: %s.", name); 2562d1661a5SPawel Jakub Dawidek return; 2572d1661a5SPawel Jakub Dawidek } 2582d1661a5SPawel Jakub Dawidek if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 2592d1661a5SPawel Jakub Dawidek g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 2602d1661a5SPawel Jakub Dawidek gctl_error(req, "There is one stale disk already.", name); 2612d1661a5SPawel Jakub Dawidek return; 2622d1661a5SPawel Jakub Dawidek } 2632d1661a5SPawel Jakub Dawidek /* 2642d1661a5SPawel Jakub Dawidek * Do rebuild by resetting syncid and disconnecting disk. 2652d1661a5SPawel Jakub Dawidek * It'll be retasted, connected to the device and synchronized. 2662d1661a5SPawel Jakub Dawidek */ 2672d1661a5SPawel Jakub Dawidek disk->d_sync.ds_syncid = 0; 2682d1661a5SPawel Jakub Dawidek if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 2692d1661a5SPawel Jakub Dawidek disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 2702d1661a5SPawel Jakub Dawidek g_raid3_update_metadata(disk); 2712d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 2722d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_WAIT); 2732d1661a5SPawel Jakub Dawidek } 2742d1661a5SPawel Jakub Dawidek 2752d1661a5SPawel Jakub Dawidek static void 2762d1661a5SPawel Jakub Dawidek g_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 2772d1661a5SPawel Jakub Dawidek { 2782d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 2792d1661a5SPawel Jakub Dawidek int *force, *nargs, error; 2802d1661a5SPawel Jakub Dawidek const char *name; 2812d1661a5SPawel Jakub Dawidek char param[16]; 2822d1661a5SPawel Jakub Dawidek u_int i; 2832d1661a5SPawel Jakub Dawidek 2842d1661a5SPawel Jakub Dawidek g_topology_assert(); 2852d1661a5SPawel Jakub Dawidek 2862d1661a5SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 2872d1661a5SPawel Jakub Dawidek if (nargs == NULL) { 2882d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 2892d1661a5SPawel Jakub Dawidek return; 2902d1661a5SPawel Jakub Dawidek } 2912d1661a5SPawel Jakub Dawidek if (*nargs < 1) { 2922d1661a5SPawel Jakub Dawidek gctl_error(req, "Missing device(s)."); 2932d1661a5SPawel Jakub Dawidek return; 2942d1661a5SPawel Jakub Dawidek } 2952d1661a5SPawel Jakub Dawidek force = gctl_get_paraml(req, "force", sizeof(*force)); 2962d1661a5SPawel Jakub Dawidek if (force == NULL) { 2972d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "force"); 2982d1661a5SPawel Jakub Dawidek return; 2992d1661a5SPawel Jakub Dawidek } 3002d1661a5SPawel Jakub Dawidek 3012d1661a5SPawel Jakub Dawidek for (i = 0; i < (u_int)*nargs; i++) { 3022d1661a5SPawel Jakub Dawidek snprintf(param, sizeof(param), "arg%u", i); 3032d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, param); 3042d1661a5SPawel Jakub Dawidek if (name == NULL) { 3052d1661a5SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", i); 3062d1661a5SPawel Jakub Dawidek return; 3072d1661a5SPawel Jakub Dawidek } 3082d1661a5SPawel Jakub Dawidek sc = g_raid3_find_device(mp, name); 3092d1661a5SPawel Jakub Dawidek if (sc == NULL) { 3102d1661a5SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name); 3112d1661a5SPawel Jakub Dawidek return; 3122d1661a5SPawel Jakub Dawidek } 3132d1661a5SPawel Jakub Dawidek error = g_raid3_destroy(sc, *force); 3142d1661a5SPawel Jakub Dawidek if (error != 0) { 3152d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot destroy device %s (error=%d).", 3162d1661a5SPawel Jakub Dawidek sc->sc_geom->name, error); 3172d1661a5SPawel Jakub Dawidek return; 3182d1661a5SPawel Jakub Dawidek } 3192d1661a5SPawel Jakub Dawidek } 3202d1661a5SPawel Jakub Dawidek } 3212d1661a5SPawel Jakub Dawidek 3222d1661a5SPawel Jakub Dawidek static void 3232d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert_orphan(struct g_consumer *cp) 3242d1661a5SPawel Jakub Dawidek { 3252d1661a5SPawel Jakub Dawidek 3262d1661a5SPawel Jakub Dawidek KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 3272d1661a5SPawel Jakub Dawidek cp->provider->name)); 3282d1661a5SPawel Jakub Dawidek } 3292d1661a5SPawel Jakub Dawidek 3302d1661a5SPawel Jakub Dawidek static void 3312d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 3322d1661a5SPawel Jakub Dawidek { 3332d1661a5SPawel Jakub Dawidek struct g_raid3_metadata md; 3342d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 3352d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 3362d1661a5SPawel Jakub Dawidek struct g_geom *gp; 3372d1661a5SPawel Jakub Dawidek struct g_provider *pp; 3382d1661a5SPawel Jakub Dawidek struct g_consumer *cp; 3392d1661a5SPawel Jakub Dawidek const char *name; 3402d1661a5SPawel Jakub Dawidek u_char *sector; 3412d1661a5SPawel Jakub Dawidek intmax_t *no; 3422d1661a5SPawel Jakub Dawidek int *hardcode, *nargs, error; 3432d1661a5SPawel Jakub Dawidek 3442d1661a5SPawel Jakub Dawidek g_topology_assert(); 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 != 2) { 3512d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 3522d1661a5SPawel Jakub Dawidek return; 3532d1661a5SPawel Jakub Dawidek } 3542d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 3552d1661a5SPawel Jakub Dawidek if (name == NULL) { 3562d1661a5SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 3572d1661a5SPawel Jakub Dawidek return; 3582d1661a5SPawel Jakub Dawidek } 3592d1661a5SPawel Jakub Dawidek sc = g_raid3_find_device(mp, name); 3602d1661a5SPawel Jakub Dawidek if (sc == NULL) { 3612d1661a5SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name); 3622d1661a5SPawel Jakub Dawidek return; 3632d1661a5SPawel Jakub Dawidek } 3642d1661a5SPawel Jakub Dawidek no = gctl_get_paraml(req, "number", sizeof(*no)); 3652d1661a5SPawel Jakub Dawidek if (no == NULL) { 3662d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "no"); 3672d1661a5SPawel Jakub Dawidek return; 3682d1661a5SPawel Jakub Dawidek } 3692d1661a5SPawel Jakub Dawidek if (*no >= sc->sc_ndisks) { 3702d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid component number."); 3712d1661a5SPawel Jakub Dawidek return; 3722d1661a5SPawel Jakub Dawidek } 3732d1661a5SPawel Jakub Dawidek hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 3742d1661a5SPawel Jakub Dawidek if (hardcode == NULL) { 3752d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "hardcode"); 3762d1661a5SPawel Jakub Dawidek return; 3772d1661a5SPawel Jakub Dawidek } 3782d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[*no]; 3792d1661a5SPawel Jakub Dawidek if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 3802d1661a5SPawel Jakub Dawidek gctl_error(req, "Component %u is already connected.", *no); 3812d1661a5SPawel Jakub Dawidek return; 3822d1661a5SPawel Jakub Dawidek } 3832d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg1"); 3842d1661a5SPawel Jakub Dawidek if (name == NULL) { 3852d1661a5SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 1); 3862d1661a5SPawel Jakub Dawidek return; 3872d1661a5SPawel Jakub Dawidek } 3882d1661a5SPawel Jakub Dawidek pp = g_provider_by_name(name); 3892d1661a5SPawel Jakub Dawidek if (pp == NULL) { 3902d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid provider."); 3912d1661a5SPawel Jakub Dawidek return; 3922d1661a5SPawel Jakub Dawidek } 3932d1661a5SPawel Jakub Dawidek if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 3942d1661a5SPawel Jakub Dawidek gctl_error(req, 3952d1661a5SPawel Jakub Dawidek "Cannot insert provider %s, because of its sector size.", 3962d1661a5SPawel Jakub Dawidek pp->name); 3972d1661a5SPawel Jakub Dawidek return; 3982d1661a5SPawel Jakub Dawidek } 3992d1661a5SPawel Jakub Dawidek gp = g_new_geomf(mp, "raid3:insert"); 4002d1661a5SPawel Jakub Dawidek gp->orphan = g_raid3_ctl_insert_orphan; 4012d1661a5SPawel Jakub Dawidek cp = g_new_consumer(gp); 4022d1661a5SPawel Jakub Dawidek error = g_attach(cp, pp); 4032d1661a5SPawel Jakub Dawidek if (error != 0) { 4042d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot attach to %s.", pp->name); 4052d1661a5SPawel Jakub Dawidek goto end; 4062d1661a5SPawel Jakub Dawidek } 4072d1661a5SPawel Jakub Dawidek error = g_access(cp, 0, 1, 1); 4082d1661a5SPawel Jakub Dawidek if (error != 0) { 4092d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot access %s.", pp->name); 4102d1661a5SPawel Jakub Dawidek goto end; 4112d1661a5SPawel Jakub Dawidek } 4122d1661a5SPawel Jakub Dawidek g_raid3_fill_metadata(disk, &md); 4132d1661a5SPawel Jakub Dawidek md.md_syncid = 0; 4142d1661a5SPawel Jakub Dawidek md.md_dflags = 0; 4152d1661a5SPawel Jakub Dawidek if (*hardcode) 4162d1661a5SPawel Jakub Dawidek strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 4172d1661a5SPawel Jakub Dawidek else 4182d1661a5SPawel Jakub Dawidek bzero(md.md_provider, sizeof(md.md_provider)); 4192d1661a5SPawel Jakub Dawidek sector = g_malloc(pp->sectorsize, M_WAITOK); 4202d1661a5SPawel Jakub Dawidek raid3_metadata_encode(&md, sector); 4212d1661a5SPawel Jakub Dawidek g_topology_unlock(); 4222d1661a5SPawel Jakub Dawidek error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 4232d1661a5SPawel Jakub Dawidek pp->sectorsize); 4242d1661a5SPawel Jakub Dawidek g_topology_lock(); 4252d1661a5SPawel Jakub Dawidek g_free(sector); 4262d1661a5SPawel Jakub Dawidek if (error != 0) 4272d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot store metadata on %s.", pp->name); 4282d1661a5SPawel Jakub Dawidek end: 4292d1661a5SPawel Jakub Dawidek if (gp != NULL) { 4302d1661a5SPawel Jakub Dawidek if (cp != NULL) { 4312d1661a5SPawel Jakub Dawidek if (cp->acw > 0) 4322d1661a5SPawel Jakub Dawidek g_access(cp, 0, -1, -1); 4332d1661a5SPawel Jakub Dawidek if (cp->provider != NULL) 4342d1661a5SPawel Jakub Dawidek g_detach(cp); 4352d1661a5SPawel Jakub Dawidek g_destroy_consumer(cp); 4362d1661a5SPawel Jakub Dawidek } 4372d1661a5SPawel Jakub Dawidek g_destroy_geom(gp); 4382d1661a5SPawel Jakub Dawidek } 4392d1661a5SPawel Jakub Dawidek } 4402d1661a5SPawel Jakub Dawidek 4412d1661a5SPawel Jakub Dawidek static void 4422d1661a5SPawel Jakub Dawidek g_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 4432d1661a5SPawel Jakub Dawidek { 4442d1661a5SPawel Jakub Dawidek struct g_raid3_softc *sc; 4452d1661a5SPawel Jakub Dawidek struct g_raid3_disk *disk; 4462d1661a5SPawel Jakub Dawidek const char *name; 4472d1661a5SPawel Jakub Dawidek intmax_t *no; 4482d1661a5SPawel Jakub Dawidek int *nargs; 4492d1661a5SPawel Jakub Dawidek 4502d1661a5SPawel Jakub Dawidek g_topology_assert(); 4512d1661a5SPawel Jakub Dawidek nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 4522d1661a5SPawel Jakub Dawidek if (nargs == NULL) { 4532d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "nargs"); 4542d1661a5SPawel Jakub Dawidek return; 4552d1661a5SPawel Jakub Dawidek } 4562d1661a5SPawel Jakub Dawidek if (*nargs != 1) { 4572d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid number of arguments."); 4582d1661a5SPawel Jakub Dawidek return; 4592d1661a5SPawel Jakub Dawidek } 4602d1661a5SPawel Jakub Dawidek name = gctl_get_asciiparam(req, "arg0"); 4612d1661a5SPawel Jakub Dawidek if (name == NULL) { 4622d1661a5SPawel Jakub Dawidek gctl_error(req, "No 'arg%u' argument.", 0); 4632d1661a5SPawel Jakub Dawidek return; 4642d1661a5SPawel Jakub Dawidek } 4652d1661a5SPawel Jakub Dawidek sc = g_raid3_find_device(mp, name); 4662d1661a5SPawel Jakub Dawidek if (sc == NULL) { 4672d1661a5SPawel Jakub Dawidek gctl_error(req, "No such device: %s.", name); 4682d1661a5SPawel Jakub Dawidek return; 4692d1661a5SPawel Jakub Dawidek } 4702d1661a5SPawel Jakub Dawidek no = gctl_get_paraml(req, "number", sizeof(*no)); 4712d1661a5SPawel Jakub Dawidek if (no == NULL) { 4722d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "no"); 4732d1661a5SPawel Jakub Dawidek return; 4742d1661a5SPawel Jakub Dawidek } 4752d1661a5SPawel Jakub Dawidek if (*no >= sc->sc_ndisks) { 4762d1661a5SPawel Jakub Dawidek gctl_error(req, "Invalid component number."); 4772d1661a5SPawel Jakub Dawidek return; 4782d1661a5SPawel Jakub Dawidek } 4792d1661a5SPawel Jakub Dawidek disk = &sc->sc_disks[*no]; 4802d1661a5SPawel Jakub Dawidek switch (disk->d_state) { 4812d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_ACTIVE: 4822d1661a5SPawel Jakub Dawidek /* 4832d1661a5SPawel Jakub Dawidek * When replacing ACTIVE component, all the rest has to be also 4842d1661a5SPawel Jakub Dawidek * ACTIVE. 4852d1661a5SPawel Jakub Dawidek */ 4862d1661a5SPawel Jakub Dawidek if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 4872d1661a5SPawel Jakub Dawidek sc->sc_ndisks) { 4882d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot replace component number %u.", 4892d1661a5SPawel Jakub Dawidek *no); 4902d1661a5SPawel Jakub Dawidek return; 4912d1661a5SPawel Jakub Dawidek } 4922d1661a5SPawel Jakub Dawidek /* FALLTHROUGH */ 4932d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_STALE: 4942d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_SYNCHRONIZING: 4952d1661a5SPawel Jakub Dawidek if (g_raid3_clear_metadata(disk) != 0) { 4962d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot clear metadata on %s.", 4972d1661a5SPawel Jakub Dawidek g_raid3_get_diskname(disk)); 4982d1661a5SPawel Jakub Dawidek sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY; 4992d1661a5SPawel Jakub Dawidek } 5002d1661a5SPawel Jakub Dawidek g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 5012d1661a5SPawel Jakub Dawidek G_RAID3_EVENT_WAIT); 5022d1661a5SPawel Jakub Dawidek break; 5032d1661a5SPawel Jakub Dawidek case G_RAID3_DISK_STATE_NODISK: 5042d1661a5SPawel Jakub Dawidek break; 5052d1661a5SPawel Jakub Dawidek default: 5062d1661a5SPawel Jakub Dawidek gctl_error(req, "Cannot replace component number %u.", *no); 5072d1661a5SPawel Jakub Dawidek return; 5082d1661a5SPawel Jakub Dawidek } 5092d1661a5SPawel Jakub Dawidek } 5102d1661a5SPawel Jakub Dawidek 5112d1661a5SPawel Jakub Dawidek void 5122d1661a5SPawel Jakub Dawidek g_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 5132d1661a5SPawel Jakub Dawidek { 5142d1661a5SPawel Jakub Dawidek uint32_t *version; 5152d1661a5SPawel Jakub Dawidek 5162d1661a5SPawel Jakub Dawidek g_topology_assert(); 5172d1661a5SPawel Jakub Dawidek 5182d1661a5SPawel Jakub Dawidek version = gctl_get_paraml(req, "version", sizeof(*version)); 5192d1661a5SPawel Jakub Dawidek if (version == NULL) { 5202d1661a5SPawel Jakub Dawidek gctl_error(req, "No '%s' argument.", "version"); 5212d1661a5SPawel Jakub Dawidek return; 5222d1661a5SPawel Jakub Dawidek } 5232d1661a5SPawel Jakub Dawidek if (*version != G_RAID3_VERSION) { 5242d1661a5SPawel Jakub Dawidek gctl_error(req, "Userland and kernel parts are out of sync."); 5252d1661a5SPawel Jakub Dawidek return; 5262d1661a5SPawel Jakub Dawidek } 5272d1661a5SPawel Jakub Dawidek 5282d1661a5SPawel Jakub Dawidek if (strcmp(verb, "configure") == 0) 5292d1661a5SPawel Jakub Dawidek g_raid3_ctl_configure(req, mp); 5302d1661a5SPawel Jakub Dawidek else if (strcmp(verb, "insert") == 0) 5312d1661a5SPawel Jakub Dawidek g_raid3_ctl_insert(req, mp); 5322d1661a5SPawel Jakub Dawidek else if (strcmp(verb, "rebuild") == 0) 5332d1661a5SPawel Jakub Dawidek g_raid3_ctl_rebuild(req, mp); 5342d1661a5SPawel Jakub Dawidek else if (strcmp(verb, "remove") == 0) 5352d1661a5SPawel Jakub Dawidek g_raid3_ctl_remove(req, mp); 5362d1661a5SPawel Jakub Dawidek else if (strcmp(verb, "stop") == 0) 5372d1661a5SPawel Jakub Dawidek g_raid3_ctl_stop(req, mp); 5382d1661a5SPawel Jakub Dawidek else 5392d1661a5SPawel Jakub Dawidek gctl_error(req, "Unknown verb."); 5402d1661a5SPawel Jakub Dawidek } 541