g_raid3_ctl.c revision 139295
1133808Spjd/*- 2133808Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3133808Spjd * All rights reserved. 4133808Spjd * 5133808Spjd * Redistribution and use in source and binary forms, with or without 6133808Spjd * modification, are permitted provided that the following conditions 7133808Spjd * are met: 8133808Spjd * 1. Redistributions of source code must retain the above copyright 9133808Spjd * notice, this list of conditions and the following disclaimer. 10133808Spjd * 2. Redistributions in binary form must reproduce the above copyright 11133808Spjd * notice, this list of conditions and the following disclaimer in the 12133808Spjd * documentation and/or other materials provided with the distribution. 13133808Spjd * 14133808Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15133808Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16133808Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17133808Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18133808Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19133808Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20133808Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21133808Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22133808Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23133808Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24133808Spjd * SUCH DAMAGE. 25133808Spjd */ 26133808Spjd 27133808Spjd#include <sys/cdefs.h> 28133808Spjd__FBSDID("$FreeBSD: head/sys/geom/raid3/g_raid3_ctl.c 139295 2004-12-25 19:17:47Z pjd $"); 29133808Spjd 30133808Spjd#include <sys/param.h> 31133808Spjd#include <sys/systm.h> 32133808Spjd#include <sys/kernel.h> 33133808Spjd#include <sys/module.h> 34133808Spjd#include <sys/lock.h> 35133808Spjd#include <sys/mutex.h> 36133808Spjd#include <sys/bio.h> 37133808Spjd#include <sys/sysctl.h> 38133808Spjd#include <sys/malloc.h> 39133808Spjd#include <sys/bitstring.h> 40133808Spjd#include <vm/uma.h> 41133808Spjd#include <machine/atomic.h> 42133808Spjd#include <geom/geom.h> 43133808Spjd#include <sys/proc.h> 44133808Spjd#include <sys/kthread.h> 45133808Spjd#include <geom/raid3/g_raid3.h> 46133808Spjd 47133808Spjd 48133808Spjdstatic struct g_raid3_softc * 49133808Spjdg_raid3_find_device(struct g_class *mp, const char *name) 50133808Spjd{ 51133808Spjd struct g_raid3_softc *sc; 52133808Spjd struct g_geom *gp; 53133808Spjd 54133808Spjd g_topology_assert(); 55133808Spjd LIST_FOREACH(gp, &mp->geom, geom) { 56133808Spjd sc = gp->softc; 57133808Spjd if (sc == NULL) 58133808Spjd continue; 59133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_DESTROY) != 0) 60133808Spjd continue; 61133808Spjd if (strcmp(gp->name, name) == 0 || 62133808Spjd strcmp(sc->sc_name, name) == 0) { 63133808Spjd return (sc); 64133808Spjd } 65133808Spjd } 66133808Spjd return (NULL); 67133808Spjd} 68133808Spjd 69133808Spjdstatic struct g_raid3_disk * 70133808Spjdg_raid3_find_disk(struct g_raid3_softc *sc, const char *name) 71133808Spjd{ 72133808Spjd struct g_raid3_disk *disk; 73133808Spjd u_int n; 74133808Spjd 75133808Spjd g_topology_assert(); 76133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 77133808Spjd disk = &sc->sc_disks[n]; 78133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_NODISK) 79133808Spjd continue; 80133808Spjd if (disk->d_consumer == NULL) 81133808Spjd continue; 82133808Spjd if (disk->d_consumer->provider == NULL) 83133808Spjd continue; 84133808Spjd if (strcmp(disk->d_consumer->provider->name, name) == 0) 85133808Spjd return (disk); 86133808Spjd } 87133808Spjd return (NULL); 88133808Spjd} 89133808Spjd 90133808Spjdstatic void 91133808Spjdg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp) 92133808Spjd{ 93133808Spjd struct g_raid3_softc *sc; 94133808Spjd struct g_raid3_disk *disk; 95133808Spjd const char *name; 96134124Spjd int *nargs, do_sync = 0; 97134168Spjd int *autosync, *noautosync; 98134168Spjd int *round_robin, *noround_robin; 99134168Spjd int *verify, *noverify; 100133808Spjd u_int n; 101133808Spjd 102133808Spjd g_topology_assert(); 103133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 104133808Spjd if (*nargs != 1) { 105133808Spjd gctl_error(req, "Invalid number of arguments."); 106133808Spjd return; 107133808Spjd } 108133808Spjd name = gctl_get_asciiparam(req, "arg0"); 109133808Spjd sc = g_raid3_find_device(mp, name); 110133808Spjd if (sc == NULL) { 111133808Spjd gctl_error(req, "No such device: %s.", name); 112133808Spjd return; 113133808Spjd } 114133808Spjd if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) { 115133808Spjd gctl_error(req, "Not all disks connected."); 116133808Spjd return; 117133808Spjd } 118133808Spjd autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync)); 119133808Spjd if (autosync == NULL) { 120133808Spjd gctl_error(req, "No '%s' argument.", "autosync"); 121133808Spjd return; 122133808Spjd } 123133808Spjd noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync)); 124133808Spjd if (noautosync == NULL) { 125133808Spjd gctl_error(req, "No '%s' argument.", "noautosync"); 126133808Spjd return; 127133808Spjd } 128133808Spjd if (*autosync && *noautosync) { 129133808Spjd gctl_error(req, "'%s' and '%s' specified.", "autosync", 130133808Spjd "noautosync"); 131133808Spjd return; 132133808Spjd } 133134124Spjd round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin)); 134134124Spjd if (round_robin == NULL) { 135134124Spjd gctl_error(req, "No '%s' argument.", "round_robin"); 136134124Spjd return; 137134124Spjd } 138134124Spjd noround_robin = gctl_get_paraml(req, "noround_robin", 139134124Spjd sizeof(*noround_robin)); 140134124Spjd if (noround_robin == NULL) { 141134124Spjd gctl_error(req, "No '%s' argument.", "noround_robin"); 142134124Spjd return; 143134124Spjd } 144134124Spjd if (*round_robin && *noround_robin) { 145134124Spjd gctl_error(req, "'%s' and '%s' specified.", "round_robin", 146134124Spjd "noround_robin"); 147134124Spjd return; 148134124Spjd } 149134168Spjd verify = gctl_get_paraml(req, "verify", sizeof(*verify)); 150134168Spjd if (verify == NULL) { 151134168Spjd gctl_error(req, "No '%s' argument.", "verify"); 152134168Spjd return; 153134168Spjd } 154134168Spjd noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify)); 155134168Spjd if (noverify == NULL) { 156134168Spjd gctl_error(req, "No '%s' argument.", "noverify"); 157134168Spjd return; 158134168Spjd } 159134168Spjd if (*verify && *noverify) { 160134168Spjd gctl_error(req, "'%s' and '%s' specified.", "verify", 161134168Spjd "noverify"); 162134168Spjd return; 163134168Spjd } 164134168Spjd if (!*autosync && !*noautosync && !*round_robin && !*noround_robin && 165134168Spjd !*verify && !*noverify) { 166134124Spjd gctl_error(req, "Nothing has changed."); 167134124Spjd return; 168134124Spjd } 169133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) { 170133808Spjd if (*autosync) { 171133808Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 172133808Spjd do_sync = 1; 173133808Spjd } 174133808Spjd } else { 175133808Spjd if (*noautosync) 176133808Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC; 177133808Spjd } 178134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) { 179134168Spjd if (*noverify) 180134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY; 181134168Spjd } else { 182134168Spjd if (*verify) 183134168Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY; 184134168Spjd } 185134124Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 186134124Spjd if (*noround_robin) 187134124Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 188134124Spjd } else { 189134124Spjd if (*round_robin) 190134124Spjd sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 191134124Spjd } 192134168Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 && 193134168Spjd (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) { 194134168Spjd /* 195134168Spjd * VERIFY and ROUND-ROBIN options are mutally exclusive. 196134168Spjd */ 197134168Spjd sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN; 198134168Spjd } 199133808Spjd for (n = 0; n < sc->sc_ndisks; n++) { 200133808Spjd disk = &sc->sc_disks[n]; 201133808Spjd if (do_sync) { 202133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING) 203133808Spjd disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC; 204133808Spjd } 205133808Spjd g_raid3_update_metadata(disk); 206133808Spjd if (do_sync) { 207133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_STALE) { 208133808Spjd /* 209133808Spjd * XXX: This is probably possible that this 210133808Spjd * component will not be retasted. 211133808Spjd */ 212133808Spjd g_raid3_event_send(disk, 213133808Spjd G_RAID3_DISK_STATE_DISCONNECTED, 214133808Spjd G_RAID3_EVENT_DONTWAIT); 215133808Spjd } 216133808Spjd } 217133808Spjd } 218133808Spjd} 219133808Spjd 220133808Spjdstatic void 221133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp) 222133808Spjd{ 223133808Spjd struct g_raid3_softc *sc; 224133808Spjd struct g_raid3_disk *disk; 225133808Spjd const char *name; 226133808Spjd int *nargs; 227133808Spjd 228133808Spjd g_topology_assert(); 229133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 230133808Spjd if (nargs == NULL) { 231133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 232133808Spjd return; 233133808Spjd } 234133808Spjd if (*nargs != 2) { 235133808Spjd gctl_error(req, "Invalid number of arguments."); 236133808Spjd return; 237133808Spjd } 238133808Spjd name = gctl_get_asciiparam(req, "arg0"); 239133808Spjd if (name == NULL) { 240133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 241133808Spjd return; 242133808Spjd } 243133808Spjd sc = g_raid3_find_device(mp, name); 244133808Spjd if (sc == NULL) { 245133808Spjd gctl_error(req, "No such device: %s.", name); 246133808Spjd return; 247133808Spjd } 248133808Spjd name = gctl_get_asciiparam(req, "arg1"); 249133808Spjd if (name == NULL) { 250133808Spjd gctl_error(req, "No 'arg%u' argument.", 1); 251133808Spjd return; 252133808Spjd } 253133808Spjd disk = g_raid3_find_disk(sc, name); 254133808Spjd if (disk == NULL) { 255133808Spjd gctl_error(req, "No such provider: %s.", name); 256133808Spjd return; 257133808Spjd } 258133808Spjd if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE && 259133808Spjd g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) { 260133808Spjd gctl_error(req, "There is one stale disk already.", name); 261133808Spjd return; 262133808Spjd } 263133808Spjd /* 264133808Spjd * Do rebuild by resetting syncid and disconnecting disk. 265133808Spjd * It'll be retasted, connected to the device and synchronized. 266133808Spjd */ 267133808Spjd disk->d_sync.ds_syncid = 0; 268133808Spjd if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) 269133808Spjd disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC; 270133808Spjd g_raid3_update_metadata(disk); 271133808Spjd g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED, 272133808Spjd G_RAID3_EVENT_WAIT); 273133808Spjd} 274133808Spjd 275133808Spjdstatic void 276133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp) 277133808Spjd{ 278133808Spjd struct g_raid3_softc *sc; 279133808Spjd int *force, *nargs, error; 280133808Spjd const char *name; 281133808Spjd char param[16]; 282133808Spjd u_int i; 283133808Spjd 284133808Spjd g_topology_assert(); 285133808Spjd 286133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 287133808Spjd if (nargs == NULL) { 288133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 289133808Spjd return; 290133808Spjd } 291133808Spjd if (*nargs < 1) { 292133808Spjd gctl_error(req, "Missing device(s)."); 293133808Spjd return; 294133808Spjd } 295133808Spjd force = gctl_get_paraml(req, "force", sizeof(*force)); 296133808Spjd if (force == NULL) { 297133808Spjd gctl_error(req, "No '%s' argument.", "force"); 298133808Spjd return; 299133808Spjd } 300133808Spjd 301133808Spjd for (i = 0; i < (u_int)*nargs; i++) { 302133808Spjd snprintf(param, sizeof(param), "arg%u", i); 303133808Spjd name = gctl_get_asciiparam(req, param); 304133808Spjd if (name == NULL) { 305133808Spjd gctl_error(req, "No 'arg%u' argument.", i); 306133808Spjd return; 307133808Spjd } 308133808Spjd sc = g_raid3_find_device(mp, name); 309133808Spjd if (sc == NULL) { 310133808Spjd gctl_error(req, "No such device: %s.", name); 311133808Spjd return; 312133808Spjd } 313133808Spjd error = g_raid3_destroy(sc, *force); 314133808Spjd if (error != 0) { 315133808Spjd gctl_error(req, "Cannot destroy device %s (error=%d).", 316133808Spjd sc->sc_geom->name, error); 317133808Spjd return; 318133808Spjd } 319133808Spjd } 320133808Spjd} 321133808Spjd 322133808Spjdstatic void 323133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp) 324133808Spjd{ 325133808Spjd 326133808Spjd KASSERT(1 == 0, ("%s called while inserting %s.", __func__, 327133808Spjd cp->provider->name)); 328133808Spjd} 329133808Spjd 330133808Spjdstatic void 331133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp) 332133808Spjd{ 333133808Spjd struct g_raid3_metadata md; 334133808Spjd struct g_raid3_softc *sc; 335133808Spjd struct g_raid3_disk *disk; 336133808Spjd struct g_geom *gp; 337133808Spjd struct g_provider *pp; 338133808Spjd struct g_consumer *cp; 339133808Spjd const char *name; 340133808Spjd u_char *sector; 341134420Spjd off_t compsize; 342133808Spjd intmax_t *no; 343133808Spjd int *hardcode, *nargs, error; 344133808Spjd 345133808Spjd g_topology_assert(); 346133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 347133808Spjd if (nargs == NULL) { 348133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 349133808Spjd return; 350133808Spjd } 351133808Spjd if (*nargs != 2) { 352133808Spjd gctl_error(req, "Invalid number of arguments."); 353133808Spjd return; 354133808Spjd } 355133808Spjd name = gctl_get_asciiparam(req, "arg0"); 356133808Spjd if (name == NULL) { 357133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 358133808Spjd return; 359133808Spjd } 360133808Spjd sc = g_raid3_find_device(mp, name); 361133808Spjd if (sc == NULL) { 362133808Spjd gctl_error(req, "No such device: %s.", name); 363133808Spjd return; 364133808Spjd } 365133808Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 366133808Spjd if (no == NULL) { 367133808Spjd gctl_error(req, "No '%s' argument.", "no"); 368133808Spjd return; 369133808Spjd } 370133808Spjd if (*no >= sc->sc_ndisks) { 371133808Spjd gctl_error(req, "Invalid component number."); 372133808Spjd return; 373133808Spjd } 374133808Spjd hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode)); 375133808Spjd if (hardcode == NULL) { 376133808Spjd gctl_error(req, "No '%s' argument.", "hardcode"); 377133808Spjd return; 378133808Spjd } 379133808Spjd disk = &sc->sc_disks[*no]; 380133808Spjd if (disk->d_state != G_RAID3_DISK_STATE_NODISK) { 381133808Spjd gctl_error(req, "Component %u is already connected.", *no); 382133808Spjd return; 383133808Spjd } 384133808Spjd name = gctl_get_asciiparam(req, "arg1"); 385133808Spjd if (name == NULL) { 386133808Spjd gctl_error(req, "No 'arg%u' argument.", 1); 387133808Spjd return; 388133808Spjd } 389133808Spjd pp = g_provider_by_name(name); 390133808Spjd if (pp == NULL) { 391133808Spjd gctl_error(req, "Invalid provider."); 392133808Spjd return; 393133808Spjd } 394133808Spjd if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) { 395133808Spjd gctl_error(req, 396133808Spjd "Cannot insert provider %s, because of its sector size.", 397133808Spjd pp->name); 398133808Spjd return; 399133808Spjd } 400134420Spjd compsize = sc->sc_mediasize / (sc->sc_ndisks - 1); 401134420Spjd if (compsize > pp->mediasize - pp->sectorsize) { 402134420Spjd gctl_error(req, "Provider %s too small.", pp->name); 403134420Spjd return; 404134420Spjd } 405134420Spjd if (compsize < pp->mediasize - pp->sectorsize) { 406134420Spjd gctl_error(req, 407134420Spjd "warning: %s: only %jd bytes from %jd bytes used.", 408134420Spjd pp->name, (intmax_t)compsize, 409134420Spjd (intmax_t)(pp->mediasize - pp->sectorsize)); 410134420Spjd } 411133808Spjd gp = g_new_geomf(mp, "raid3:insert"); 412133808Spjd gp->orphan = g_raid3_ctl_insert_orphan; 413133808Spjd cp = g_new_consumer(gp); 414133808Spjd error = g_attach(cp, pp); 415133808Spjd if (error != 0) { 416133808Spjd gctl_error(req, "Cannot attach to %s.", pp->name); 417133808Spjd goto end; 418133808Spjd } 419133808Spjd error = g_access(cp, 0, 1, 1); 420133808Spjd if (error != 0) { 421133808Spjd gctl_error(req, "Cannot access %s.", pp->name); 422133808Spjd goto end; 423133808Spjd } 424133808Spjd g_raid3_fill_metadata(disk, &md); 425133808Spjd md.md_syncid = 0; 426133808Spjd md.md_dflags = 0; 427133808Spjd if (*hardcode) 428133808Spjd strlcpy(md.md_provider, pp->name, sizeof(md.md_provider)); 429133808Spjd else 430133808Spjd bzero(md.md_provider, sizeof(md.md_provider)); 431133808Spjd sector = g_malloc(pp->sectorsize, M_WAITOK); 432133808Spjd raid3_metadata_encode(&md, sector); 433133808Spjd g_topology_unlock(); 434133808Spjd error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector, 435133808Spjd pp->sectorsize); 436133808Spjd g_topology_lock(); 437133808Spjd g_free(sector); 438133808Spjd if (error != 0) 439133808Spjd gctl_error(req, "Cannot store metadata on %s.", pp->name); 440133808Spjdend: 441133808Spjd if (gp != NULL) { 442133808Spjd if (cp != NULL) { 443133808Spjd if (cp->acw > 0) 444133808Spjd g_access(cp, 0, -1, -1); 445133808Spjd if (cp->provider != NULL) 446133808Spjd g_detach(cp); 447133808Spjd g_destroy_consumer(cp); 448133808Spjd } 449133808Spjd g_destroy_geom(gp); 450133808Spjd } 451133808Spjd} 452133808Spjd 453133808Spjdstatic void 454133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp) 455133808Spjd{ 456133808Spjd struct g_raid3_softc *sc; 457133808Spjd struct g_raid3_disk *disk; 458133808Spjd const char *name; 459133808Spjd intmax_t *no; 460133808Spjd int *nargs; 461133808Spjd 462133808Spjd g_topology_assert(); 463133808Spjd nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs)); 464133808Spjd if (nargs == NULL) { 465133808Spjd gctl_error(req, "No '%s' argument.", "nargs"); 466133808Spjd return; 467133808Spjd } 468133808Spjd if (*nargs != 1) { 469133808Spjd gctl_error(req, "Invalid number of arguments."); 470133808Spjd return; 471133808Spjd } 472133808Spjd name = gctl_get_asciiparam(req, "arg0"); 473133808Spjd if (name == NULL) { 474133808Spjd gctl_error(req, "No 'arg%u' argument.", 0); 475133808Spjd return; 476133808Spjd } 477133808Spjd sc = g_raid3_find_device(mp, name); 478133808Spjd if (sc == NULL) { 479133808Spjd gctl_error(req, "No such device: %s.", name); 480133808Spjd return; 481133808Spjd } 482133808Spjd no = gctl_get_paraml(req, "number", sizeof(*no)); 483133808Spjd if (no == NULL) { 484133808Spjd gctl_error(req, "No '%s' argument.", "no"); 485133808Spjd return; 486133808Spjd } 487133808Spjd if (*no >= sc->sc_ndisks) { 488133808Spjd gctl_error(req, "Invalid component number."); 489133808Spjd return; 490133808Spjd } 491133808Spjd disk = &sc->sc_disks[*no]; 492133808Spjd switch (disk->d_state) { 493133808Spjd case G_RAID3_DISK_STATE_ACTIVE: 494133808Spjd /* 495133808Spjd * When replacing ACTIVE component, all the rest has to be also 496133808Spjd * ACTIVE. 497133808Spjd */ 498133808Spjd if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < 499133808Spjd sc->sc_ndisks) { 500133808Spjd gctl_error(req, "Cannot replace component number %u.", 501133808Spjd *no); 502133808Spjd return; 503133808Spjd } 504133808Spjd /* FALLTHROUGH */ 505133808Spjd case G_RAID3_DISK_STATE_STALE: 506133808Spjd case G_RAID3_DISK_STATE_SYNCHRONIZING: 507133808Spjd if (g_raid3_clear_metadata(disk) != 0) { 508133808Spjd gctl_error(req, "Cannot clear metadata on %s.", 509133808Spjd g_raid3_get_diskname(disk)); 510139295Spjd } else { 511139295Spjd g_raid3_event_send(disk, 512139295Spjd G_RAID3_DISK_STATE_DISCONNECTED, 513139295Spjd G_RAID3_EVENT_WAIT); 514133808Spjd } 515133808Spjd break; 516133808Spjd case G_RAID3_DISK_STATE_NODISK: 517133808Spjd break; 518133808Spjd default: 519133808Spjd gctl_error(req, "Cannot replace component number %u.", *no); 520133808Spjd return; 521133808Spjd } 522133808Spjd} 523133808Spjd 524133808Spjdvoid 525133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb) 526133808Spjd{ 527133808Spjd uint32_t *version; 528133808Spjd 529133808Spjd g_topology_assert(); 530133808Spjd 531133808Spjd version = gctl_get_paraml(req, "version", sizeof(*version)); 532133808Spjd if (version == NULL) { 533133808Spjd gctl_error(req, "No '%s' argument.", "version"); 534133808Spjd return; 535133808Spjd } 536133808Spjd if (*version != G_RAID3_VERSION) { 537133808Spjd gctl_error(req, "Userland and kernel parts are out of sync."); 538133808Spjd return; 539133808Spjd } 540133808Spjd 541133808Spjd if (strcmp(verb, "configure") == 0) 542133808Spjd g_raid3_ctl_configure(req, mp); 543133808Spjd else if (strcmp(verb, "insert") == 0) 544133808Spjd g_raid3_ctl_insert(req, mp); 545133808Spjd else if (strcmp(verb, "rebuild") == 0) 546133808Spjd g_raid3_ctl_rebuild(req, mp); 547133808Spjd else if (strcmp(verb, "remove") == 0) 548133808Spjd g_raid3_ctl_remove(req, mp); 549133808Spjd else if (strcmp(verb, "stop") == 0) 550133808Spjd g_raid3_ctl_stop(req, mp); 551133808Spjd else 552133808Spjd gctl_error(req, "Unknown verb."); 553133808Spjd} 554