g_raid3_ctl.c revision 134124
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 134124 2004-08-21 18:11:46Z 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;
97134124Spjd	int *autosync, *noautosync, *round_robin, *noround_robin;
98133808Spjd	u_int n;
99133808Spjd
100133808Spjd	g_topology_assert();
101133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
102133808Spjd	if (*nargs != 1) {
103133808Spjd		gctl_error(req, "Invalid number of arguments.");
104133808Spjd		return;
105133808Spjd	}
106133808Spjd	name = gctl_get_asciiparam(req, "arg0");
107133808Spjd	sc = g_raid3_find_device(mp, name);
108133808Spjd	if (sc == NULL) {
109133808Spjd		gctl_error(req, "No such device: %s.", name);
110133808Spjd		return;
111133808Spjd	}
112133808Spjd	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
113133808Spjd		gctl_error(req, "Not all disks connected.");
114133808Spjd		return;
115133808Spjd	}
116133808Spjd	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
117133808Spjd	if (autosync == NULL) {
118133808Spjd		gctl_error(req, "No '%s' argument.", "autosync");
119133808Spjd		return;
120133808Spjd	}
121133808Spjd	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
122133808Spjd	if (noautosync == NULL) {
123133808Spjd		gctl_error(req, "No '%s' argument.", "noautosync");
124133808Spjd		return;
125133808Spjd	}
126133808Spjd	if (*autosync && *noautosync) {
127133808Spjd		gctl_error(req, "'%s' and '%s' specified.", "autosync",
128133808Spjd		    "noautosync");
129133808Spjd		return;
130133808Spjd	}
131134124Spjd	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
132134124Spjd	if (round_robin == NULL) {
133134124Spjd		gctl_error(req, "No '%s' argument.", "round_robin");
134134124Spjd		return;
135134124Spjd	}
136134124Spjd	noround_robin = gctl_get_paraml(req, "noround_robin",
137134124Spjd	    sizeof(*noround_robin));
138134124Spjd	if (noround_robin == NULL) {
139134124Spjd		gctl_error(req, "No '%s' argument.", "noround_robin");
140134124Spjd		return;
141134124Spjd	}
142134124Spjd	if (*round_robin && *noround_robin) {
143134124Spjd		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
144134124Spjd		    "noround_robin");
145134124Spjd		return;
146134124Spjd	}
147134124Spjd	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin) {
148134124Spjd		gctl_error(req, "Nothing has changed.");
149134124Spjd		return;
150134124Spjd	}
151133808Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
152133808Spjd		if (*autosync) {
153133808Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
154133808Spjd			do_sync = 1;
155133808Spjd		}
156133808Spjd	} else {
157133808Spjd		if (*noautosync)
158133808Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
159133808Spjd	}
160134124Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
161134124Spjd		if (*noround_robin)
162134124Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
163134124Spjd	} else {
164134124Spjd		if (*round_robin)
165134124Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
166134124Spjd	}
167133808Spjd	for (n = 0; n < sc->sc_ndisks; n++) {
168133808Spjd		disk = &sc->sc_disks[n];
169133808Spjd		if (do_sync) {
170133808Spjd			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
171133808Spjd				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
172133808Spjd		}
173133808Spjd		g_raid3_update_metadata(disk);
174133808Spjd		if (do_sync) {
175133808Spjd			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
176133808Spjd				/*
177133808Spjd				 * XXX: This is probably possible that this
178133808Spjd				 *      component will not be retasted.
179133808Spjd				 */
180133808Spjd				g_raid3_event_send(disk,
181133808Spjd				    G_RAID3_DISK_STATE_DISCONNECTED,
182133808Spjd				    G_RAID3_EVENT_DONTWAIT);
183133808Spjd			}
184133808Spjd		}
185133808Spjd	}
186133808Spjd}
187133808Spjd
188133808Spjdstatic void
189133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
190133808Spjd{
191133808Spjd	struct g_raid3_softc *sc;
192133808Spjd	struct g_raid3_disk *disk;
193133808Spjd	const char *name;
194133808Spjd	int *nargs;
195133808Spjd
196133808Spjd	g_topology_assert();
197133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
198133808Spjd	if (nargs == NULL) {
199133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
200133808Spjd		return;
201133808Spjd	}
202133808Spjd	if (*nargs != 2) {
203133808Spjd		gctl_error(req, "Invalid number of arguments.");
204133808Spjd		return;
205133808Spjd	}
206133808Spjd	name = gctl_get_asciiparam(req, "arg0");
207133808Spjd	if (name == NULL) {
208133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
209133808Spjd		return;
210133808Spjd	}
211133808Spjd	sc = g_raid3_find_device(mp, name);
212133808Spjd	if (sc == NULL) {
213133808Spjd		gctl_error(req, "No such device: %s.", name);
214133808Spjd		return;
215133808Spjd	}
216133808Spjd	name = gctl_get_asciiparam(req, "arg1");
217133808Spjd	if (name == NULL) {
218133808Spjd		gctl_error(req, "No 'arg%u' argument.", 1);
219133808Spjd		return;
220133808Spjd	}
221133808Spjd	disk = g_raid3_find_disk(sc, name);
222133808Spjd	if (disk == NULL) {
223133808Spjd		gctl_error(req, "No such provider: %s.", name);
224133808Spjd		return;
225133808Spjd	}
226133808Spjd	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
227133808Spjd	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
228133808Spjd		gctl_error(req, "There is one stale disk already.", name);
229133808Spjd		return;
230133808Spjd	}
231133808Spjd	/*
232133808Spjd	 * Do rebuild by resetting syncid and disconnecting disk.
233133808Spjd	 * It'll be retasted, connected to the device and synchronized.
234133808Spjd	 */
235133808Spjd	disk->d_sync.ds_syncid = 0;
236133808Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
237133808Spjd		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
238133808Spjd	g_raid3_update_metadata(disk);
239133808Spjd	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
240133808Spjd	    G_RAID3_EVENT_WAIT);
241133808Spjd}
242133808Spjd
243133808Spjdstatic void
244133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
245133808Spjd{
246133808Spjd	struct g_raid3_softc *sc;
247133808Spjd	int *force, *nargs, error;
248133808Spjd	const char *name;
249133808Spjd	char param[16];
250133808Spjd	u_int i;
251133808Spjd
252133808Spjd	g_topology_assert();
253133808Spjd
254133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
255133808Spjd	if (nargs == NULL) {
256133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
257133808Spjd		return;
258133808Spjd	}
259133808Spjd	if (*nargs < 1) {
260133808Spjd		gctl_error(req, "Missing device(s).");
261133808Spjd		return;
262133808Spjd	}
263133808Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
264133808Spjd	if (force == NULL) {
265133808Spjd		gctl_error(req, "No '%s' argument.", "force");
266133808Spjd		return;
267133808Spjd	}
268133808Spjd
269133808Spjd	for (i = 0; i < (u_int)*nargs; i++) {
270133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
271133808Spjd		name = gctl_get_asciiparam(req, param);
272133808Spjd		if (name == NULL) {
273133808Spjd			gctl_error(req, "No 'arg%u' argument.", i);
274133808Spjd			return;
275133808Spjd		}
276133808Spjd		sc = g_raid3_find_device(mp, name);
277133808Spjd		if (sc == NULL) {
278133808Spjd			gctl_error(req, "No such device: %s.", name);
279133808Spjd			return;
280133808Spjd		}
281133808Spjd		error = g_raid3_destroy(sc, *force);
282133808Spjd		if (error != 0) {
283133808Spjd			gctl_error(req, "Cannot destroy device %s (error=%d).",
284133808Spjd			    sc->sc_geom->name, error);
285133808Spjd			return;
286133808Spjd		}
287133808Spjd	}
288133808Spjd}
289133808Spjd
290133808Spjdstatic void
291133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp)
292133808Spjd{
293133808Spjd
294133808Spjd	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
295133808Spjd	    cp->provider->name));
296133808Spjd}
297133808Spjd
298133808Spjdstatic void
299133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
300133808Spjd{
301133808Spjd	struct g_raid3_metadata md;
302133808Spjd	struct g_raid3_softc *sc;
303133808Spjd	struct g_raid3_disk *disk;
304133808Spjd	struct g_geom *gp;
305133808Spjd	struct g_provider *pp;
306133808Spjd	struct g_consumer *cp;
307133808Spjd	const char *name;
308133808Spjd	u_char *sector;
309133808Spjd	intmax_t *no;
310133808Spjd	int *hardcode, *nargs, error;
311133808Spjd
312133808Spjd	g_topology_assert();
313133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
314133808Spjd	if (nargs == NULL) {
315133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
316133808Spjd		return;
317133808Spjd	}
318133808Spjd	if (*nargs != 2) {
319133808Spjd		gctl_error(req, "Invalid number of arguments.");
320133808Spjd		return;
321133808Spjd	}
322133808Spjd	name = gctl_get_asciiparam(req, "arg0");
323133808Spjd	if (name == NULL) {
324133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
325133808Spjd		return;
326133808Spjd	}
327133808Spjd	sc = g_raid3_find_device(mp, name);
328133808Spjd	if (sc == NULL) {
329133808Spjd		gctl_error(req, "No such device: %s.", name);
330133808Spjd		return;
331133808Spjd	}
332133808Spjd	no = gctl_get_paraml(req, "number", sizeof(*no));
333133808Spjd	if (no == NULL) {
334133808Spjd		gctl_error(req, "No '%s' argument.", "no");
335133808Spjd		return;
336133808Spjd	}
337133808Spjd	if (*no >= sc->sc_ndisks) {
338133808Spjd		gctl_error(req, "Invalid component number.");
339133808Spjd		return;
340133808Spjd	}
341133808Spjd	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
342133808Spjd	if (hardcode == NULL) {
343133808Spjd		gctl_error(req, "No '%s' argument.", "hardcode");
344133808Spjd		return;
345133808Spjd	}
346133808Spjd	disk = &sc->sc_disks[*no];
347133808Spjd	if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
348133808Spjd		gctl_error(req, "Component %u is already connected.", *no);
349133808Spjd		return;
350133808Spjd	}
351133808Spjd	name = gctl_get_asciiparam(req, "arg1");
352133808Spjd	if (name == NULL) {
353133808Spjd		gctl_error(req, "No 'arg%u' argument.", 1);
354133808Spjd		return;
355133808Spjd	}
356133808Spjd	pp = g_provider_by_name(name);
357133808Spjd	if (pp == NULL) {
358133808Spjd		gctl_error(req, "Invalid provider.");
359133808Spjd		return;
360133808Spjd	}
361133808Spjd	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
362133808Spjd		gctl_error(req,
363133808Spjd		    "Cannot insert provider %s, because of its sector size.",
364133808Spjd		    pp->name);
365133808Spjd		return;
366133808Spjd	}
367133808Spjd	gp = g_new_geomf(mp, "raid3:insert");
368133808Spjd	gp->orphan = g_raid3_ctl_insert_orphan;
369133808Spjd	cp = g_new_consumer(gp);
370133808Spjd	error = g_attach(cp, pp);
371133808Spjd	if (error != 0) {
372133808Spjd		gctl_error(req, "Cannot attach to %s.", pp->name);
373133808Spjd		goto end;
374133808Spjd	}
375133808Spjd	error = g_access(cp, 0, 1, 1);
376133808Spjd	if (error != 0) {
377133808Spjd		gctl_error(req, "Cannot access %s.", pp->name);
378133808Spjd		goto end;
379133808Spjd	}
380133808Spjd	g_raid3_fill_metadata(disk, &md);
381133808Spjd	md.md_syncid = 0;
382133808Spjd        md.md_dflags = 0;
383133808Spjd	if (*hardcode)
384133808Spjd                strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
385133808Spjd        else
386133808Spjd                bzero(md.md_provider, sizeof(md.md_provider));
387133808Spjd	sector = g_malloc(pp->sectorsize, M_WAITOK);
388133808Spjd	raid3_metadata_encode(&md, sector);
389133808Spjd	g_topology_unlock();
390133808Spjd	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
391133808Spjd	    pp->sectorsize);
392133808Spjd	g_topology_lock();
393133808Spjd	g_free(sector);
394133808Spjd	if (error != 0)
395133808Spjd		gctl_error(req, "Cannot store metadata on %s.", pp->name);
396133808Spjdend:
397133808Spjd	if (gp != NULL) {
398133808Spjd		if (cp != NULL) {
399133808Spjd			if (cp->acw > 0)
400133808Spjd				g_access(cp, 0, -1, -1);
401133808Spjd			if (cp->provider != NULL)
402133808Spjd				g_detach(cp);
403133808Spjd			g_destroy_consumer(cp);
404133808Spjd		}
405133808Spjd		g_destroy_geom(gp);
406133808Spjd	}
407133808Spjd}
408133808Spjd
409133808Spjdstatic void
410133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
411133808Spjd{
412133808Spjd	struct g_raid3_softc *sc;
413133808Spjd	struct g_raid3_disk *disk;
414133808Spjd	const char *name;
415133808Spjd	intmax_t *no;
416133808Spjd	int *nargs;
417133808Spjd
418133808Spjd	g_topology_assert();
419133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
420133808Spjd	if (nargs == NULL) {
421133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
422133808Spjd		return;
423133808Spjd	}
424133808Spjd	if (*nargs != 1) {
425133808Spjd		gctl_error(req, "Invalid number of arguments.");
426133808Spjd		return;
427133808Spjd	}
428133808Spjd	name = gctl_get_asciiparam(req, "arg0");
429133808Spjd	if (name == NULL) {
430133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
431133808Spjd		return;
432133808Spjd	}
433133808Spjd	sc = g_raid3_find_device(mp, name);
434133808Spjd	if (sc == NULL) {
435133808Spjd		gctl_error(req, "No such device: %s.", name);
436133808Spjd		return;
437133808Spjd	}
438133808Spjd	no = gctl_get_paraml(req, "number", sizeof(*no));
439133808Spjd	if (no == NULL) {
440133808Spjd		gctl_error(req, "No '%s' argument.", "no");
441133808Spjd		return;
442133808Spjd	}
443133808Spjd	if (*no >= sc->sc_ndisks) {
444133808Spjd		gctl_error(req, "Invalid component number.");
445133808Spjd		return;
446133808Spjd	}
447133808Spjd	disk = &sc->sc_disks[*no];
448133808Spjd	switch (disk->d_state) {
449133808Spjd	case G_RAID3_DISK_STATE_ACTIVE:
450133808Spjd		/*
451133808Spjd		 * When replacing ACTIVE component, all the rest has to be also
452133808Spjd		 * ACTIVE.
453133808Spjd		 */
454133808Spjd		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
455133808Spjd		    sc->sc_ndisks) {
456133808Spjd			gctl_error(req, "Cannot replace component number %u.",
457133808Spjd			    *no);
458133808Spjd			return;
459133808Spjd		}
460133808Spjd		/* FALLTHROUGH */
461133808Spjd	case G_RAID3_DISK_STATE_STALE:
462133808Spjd	case G_RAID3_DISK_STATE_SYNCHRONIZING:
463133808Spjd		if (g_raid3_clear_metadata(disk) != 0) {
464133808Spjd			gctl_error(req, "Cannot clear metadata on %s.",
465133808Spjd			    g_raid3_get_diskname(disk));
466133808Spjd			sc->sc_bump_syncid = G_RAID3_BUMP_IMMEDIATELY;
467133808Spjd		}
468133808Spjd		g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
469133808Spjd		    G_RAID3_EVENT_WAIT);
470133808Spjd		break;
471133808Spjd	case G_RAID3_DISK_STATE_NODISK:
472133808Spjd		break;
473133808Spjd	default:
474133808Spjd		gctl_error(req, "Cannot replace component number %u.", *no);
475133808Spjd		return;
476133808Spjd	}
477133808Spjd}
478133808Spjd
479133808Spjdvoid
480133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
481133808Spjd{
482133808Spjd	uint32_t *version;
483133808Spjd
484133808Spjd	g_topology_assert();
485133808Spjd
486133808Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
487133808Spjd	if (version == NULL) {
488133808Spjd		gctl_error(req, "No '%s' argument.", "version");
489133808Spjd		return;
490133808Spjd	}
491133808Spjd	if (*version != G_RAID3_VERSION) {
492133808Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
493133808Spjd		return;
494133808Spjd	}
495133808Spjd
496133808Spjd	if (strcmp(verb, "configure") == 0)
497133808Spjd		g_raid3_ctl_configure(req, mp);
498133808Spjd	else if (strcmp(verb, "insert") == 0)
499133808Spjd		g_raid3_ctl_insert(req, mp);
500133808Spjd	else if (strcmp(verb, "rebuild") == 0)
501133808Spjd		g_raid3_ctl_rebuild(req, mp);
502133808Spjd	else if (strcmp(verb, "remove") == 0)
503133808Spjd		g_raid3_ctl_remove(req, mp);
504133808Spjd	else if (strcmp(verb, "stop") == 0)
505133808Spjd		g_raid3_ctl_stop(req, mp);
506133808Spjd	else
507133808Spjd		gctl_error(req, "Unknown verb.");
508133808Spjd}
509