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