g_raid3_ctl.c revision 156878
1133808Spjd/*-
2156878Spjd * Copyright (c) 2004-2006 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.
13155174Spjd *
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 156878 2006-03-19 12:55:51Z 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
54156612Spjd	g_topology_lock();
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) {
63156612Spjd			g_topology_unlock();
64156612Spjd			sx_xlock(&sc->sc_lock);
65133808Spjd			return (sc);
66133808Spjd		}
67133808Spjd	}
68156612Spjd	g_topology_unlock();
69133808Spjd	return (NULL);
70133808Spjd}
71133808Spjd
72133808Spjdstatic struct g_raid3_disk *
73133808Spjdg_raid3_find_disk(struct g_raid3_softc *sc, const char *name)
74133808Spjd{
75133808Spjd	struct g_raid3_disk *disk;
76133808Spjd	u_int n;
77133808Spjd
78156612Spjd	sx_assert(&sc->sc_lock, SX_XLOCKED);
79133808Spjd	for (n = 0; n < sc->sc_ndisks; n++) {
80133808Spjd		disk = &sc->sc_disks[n];
81133808Spjd		if (disk->d_state == G_RAID3_DISK_STATE_NODISK)
82133808Spjd			continue;
83133808Spjd		if (disk->d_consumer == NULL)
84133808Spjd			continue;
85133808Spjd		if (disk->d_consumer->provider == NULL)
86133808Spjd			continue;
87133808Spjd		if (strcmp(disk->d_consumer->provider->name, name) == 0)
88133808Spjd			return (disk);
89133808Spjd	}
90133808Spjd	return (NULL);
91133808Spjd}
92133808Spjd
93133808Spjdstatic void
94133808Spjdg_raid3_ctl_configure(struct gctl_req *req, struct g_class *mp)
95133808Spjd{
96133808Spjd	struct g_raid3_softc *sc;
97133808Spjd	struct g_raid3_disk *disk;
98133808Spjd	const char *name;
99134124Spjd	int *nargs, do_sync = 0;
100134168Spjd	int *autosync, *noautosync;
101134168Spjd	int *round_robin, *noround_robin;
102134168Spjd	int *verify, *noverify;
103133808Spjd	u_int n;
104133808Spjd
105133808Spjd	g_topology_assert();
106133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
107144142Spjd	if (nargs == NULL) {
108144142Spjd		gctl_error(req, "No '%s' argument.", "nargs");
109144142Spjd		return;
110144142Spjd	}
111133808Spjd	if (*nargs != 1) {
112133808Spjd		gctl_error(req, "Invalid number of arguments.");
113133808Spjd		return;
114133808Spjd	}
115133808Spjd	autosync = gctl_get_paraml(req, "autosync", sizeof(*autosync));
116133808Spjd	if (autosync == NULL) {
117133808Spjd		gctl_error(req, "No '%s' argument.", "autosync");
118133808Spjd		return;
119133808Spjd	}
120133808Spjd	noautosync = gctl_get_paraml(req, "noautosync", sizeof(*noautosync));
121133808Spjd	if (noautosync == NULL) {
122133808Spjd		gctl_error(req, "No '%s' argument.", "noautosync");
123133808Spjd		return;
124133808Spjd	}
125133808Spjd	if (*autosync && *noautosync) {
126133808Spjd		gctl_error(req, "'%s' and '%s' specified.", "autosync",
127133808Spjd		    "noautosync");
128133808Spjd		return;
129133808Spjd	}
130134124Spjd	round_robin = gctl_get_paraml(req, "round_robin", sizeof(*round_robin));
131134124Spjd	if (round_robin == NULL) {
132134124Spjd		gctl_error(req, "No '%s' argument.", "round_robin");
133134124Spjd		return;
134134124Spjd	}
135134124Spjd	noround_robin = gctl_get_paraml(req, "noround_robin",
136134124Spjd	    sizeof(*noround_robin));
137134124Spjd	if (noround_robin == NULL) {
138134124Spjd		gctl_error(req, "No '%s' argument.", "noround_robin");
139134124Spjd		return;
140134124Spjd	}
141134124Spjd	if (*round_robin && *noround_robin) {
142134124Spjd		gctl_error(req, "'%s' and '%s' specified.", "round_robin",
143134124Spjd		    "noround_robin");
144134124Spjd		return;
145134124Spjd	}
146134168Spjd	verify = gctl_get_paraml(req, "verify", sizeof(*verify));
147134168Spjd	if (verify == NULL) {
148134168Spjd		gctl_error(req, "No '%s' argument.", "verify");
149134168Spjd		return;
150134168Spjd	}
151134168Spjd	noverify = gctl_get_paraml(req, "noverify", sizeof(*noverify));
152134168Spjd	if (noverify == NULL) {
153134168Spjd		gctl_error(req, "No '%s' argument.", "noverify");
154134168Spjd		return;
155134168Spjd	}
156134168Spjd	if (*verify && *noverify) {
157134168Spjd		gctl_error(req, "'%s' and '%s' specified.", "verify",
158134168Spjd		    "noverify");
159134168Spjd		return;
160134168Spjd	}
161134168Spjd	if (!*autosync && !*noautosync && !*round_robin && !*noround_robin &&
162134168Spjd	    !*verify && !*noverify) {
163134124Spjd		gctl_error(req, "Nothing has changed.");
164134124Spjd		return;
165134124Spjd	}
166156612Spjd	name = gctl_get_asciiparam(req, "arg0");
167156612Spjd	if (name == NULL) {
168156612Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
169156612Spjd		return;
170156612Spjd	}
171156612Spjd	sc = g_raid3_find_device(mp, name);
172156612Spjd	if (sc == NULL) {
173156612Spjd		gctl_error(req, "No such device: %s.", name);
174156612Spjd		return;
175156612Spjd	}
176156612Spjd	if (g_raid3_ndisks(sc, -1) < sc->sc_ndisks) {
177156612Spjd		gctl_error(req, "Not all disks connected.");
178156612Spjd		sx_xunlock(&sc->sc_lock);
179156612Spjd		return;
180156612Spjd	}
181133808Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0) {
182133808Spjd		if (*autosync) {
183133808Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
184133808Spjd			do_sync = 1;
185133808Spjd		}
186133808Spjd	} else {
187133808Spjd		if (*noautosync)
188133808Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_NOAUTOSYNC;
189133808Spjd	}
190134168Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0) {
191134168Spjd		if (*noverify)
192134168Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_VERIFY;
193134168Spjd	} else {
194134168Spjd		if (*verify)
195134168Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_VERIFY;
196134168Spjd	}
197134124Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
198134124Spjd		if (*noround_robin)
199134124Spjd			sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
200134124Spjd	} else {
201134124Spjd		if (*round_robin)
202134124Spjd			sc->sc_flags |= G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
203134124Spjd	}
204134168Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_VERIFY) != 0 &&
205134168Spjd	    (sc->sc_flags & G_RAID3_DEVICE_FLAG_ROUND_ROBIN) != 0) {
206134168Spjd		/*
207134168Spjd		 * VERIFY and ROUND-ROBIN options are mutally exclusive.
208134168Spjd		 */
209134168Spjd		sc->sc_flags &= ~G_RAID3_DEVICE_FLAG_ROUND_ROBIN;
210134168Spjd	}
211133808Spjd	for (n = 0; n < sc->sc_ndisks; n++) {
212133808Spjd		disk = &sc->sc_disks[n];
213133808Spjd		if (do_sync) {
214133808Spjd			if (disk->d_state == G_RAID3_DISK_STATE_SYNCHRONIZING)
215133808Spjd				disk->d_flags &= ~G_RAID3_DISK_FLAG_FORCE_SYNC;
216133808Spjd		}
217133808Spjd		g_raid3_update_metadata(disk);
218133808Spjd		if (do_sync) {
219133808Spjd			if (disk->d_state == G_RAID3_DISK_STATE_STALE) {
220133808Spjd				/*
221133808Spjd				 * XXX: This is probably possible that this
222133808Spjd				 *      component will not be retasted.
223133808Spjd				 */
224133808Spjd				g_raid3_event_send(disk,
225133808Spjd				    G_RAID3_DISK_STATE_DISCONNECTED,
226133808Spjd				    G_RAID3_EVENT_DONTWAIT);
227133808Spjd			}
228133808Spjd		}
229133808Spjd	}
230156612Spjd	sx_xunlock(&sc->sc_lock);
231133808Spjd}
232133808Spjd
233133808Spjdstatic void
234133808Spjdg_raid3_ctl_rebuild(struct gctl_req *req, struct g_class *mp)
235133808Spjd{
236139671Spjd	struct g_raid3_metadata md;
237133808Spjd	struct g_raid3_softc *sc;
238133808Spjd	struct g_raid3_disk *disk;
239139671Spjd	struct g_provider *pp;
240133808Spjd	const char *name;
241139671Spjd	int error, *nargs;
242133808Spjd
243133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
244133808Spjd	if (nargs == NULL) {
245133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
246133808Spjd		return;
247133808Spjd	}
248133808Spjd	if (*nargs != 2) {
249133808Spjd		gctl_error(req, "Invalid number of arguments.");
250133808Spjd		return;
251133808Spjd	}
252133808Spjd	name = gctl_get_asciiparam(req, "arg0");
253133808Spjd	if (name == NULL) {
254133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
255133808Spjd		return;
256133808Spjd	}
257133808Spjd	sc = g_raid3_find_device(mp, name);
258133808Spjd	if (sc == NULL) {
259133808Spjd		gctl_error(req, "No such device: %s.", name);
260133808Spjd		return;
261133808Spjd	}
262133808Spjd	name = gctl_get_asciiparam(req, "arg1");
263133808Spjd	if (name == NULL) {
264133808Spjd		gctl_error(req, "No 'arg%u' argument.", 1);
265156612Spjd		sx_xunlock(&sc->sc_lock);
266133808Spjd		return;
267133808Spjd	}
268133808Spjd	disk = g_raid3_find_disk(sc, name);
269133808Spjd	if (disk == NULL) {
270133808Spjd		gctl_error(req, "No such provider: %s.", name);
271156612Spjd		sx_xunlock(&sc->sc_lock);
272133808Spjd		return;
273133808Spjd	}
274133808Spjd	if (disk->d_state == G_RAID3_DISK_STATE_ACTIVE &&
275133808Spjd	    g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) < sc->sc_ndisks) {
276133808Spjd		gctl_error(req, "There is one stale disk already.", name);
277156612Spjd		sx_xunlock(&sc->sc_lock);
278133808Spjd		return;
279133808Spjd	}
280133808Spjd	/*
281133808Spjd	 * Do rebuild by resetting syncid and disconnecting disk.
282133808Spjd	 * It'll be retasted, connected to the device and synchronized.
283133808Spjd	 */
284133808Spjd	disk->d_sync.ds_syncid = 0;
285133808Spjd	if ((sc->sc_flags & G_RAID3_DEVICE_FLAG_NOAUTOSYNC) != 0)
286133808Spjd		disk->d_flags |= G_RAID3_DISK_FLAG_FORCE_SYNC;
287133808Spjd	g_raid3_update_metadata(disk);
288139671Spjd	pp = disk->d_consumer->provider;
289156612Spjd	g_topology_lock();
290139671Spjd	error = g_raid3_read_metadata(disk->d_consumer, &md);
291156612Spjd	g_topology_unlock();
292133808Spjd	g_raid3_event_send(disk, G_RAID3_DISK_STATE_DISCONNECTED,
293133808Spjd	    G_RAID3_EVENT_WAIT);
294139671Spjd	if (error != 0) {
295139671Spjd		gctl_error(req, "Cannot read metadata from %s.", pp->name);
296156612Spjd		sx_xunlock(&sc->sc_lock);
297139671Spjd		return;
298139671Spjd	}
299139671Spjd	error = g_raid3_add_disk(sc, pp, &md);
300156612Spjd	if (error != 0)
301139671Spjd		gctl_error(req, "Cannot reconnect component %s.", pp->name);
302156612Spjd	sx_xunlock(&sc->sc_lock);
303133808Spjd}
304133808Spjd
305133808Spjdstatic void
306133808Spjdg_raid3_ctl_stop(struct gctl_req *req, struct g_class *mp)
307133808Spjd{
308133808Spjd	struct g_raid3_softc *sc;
309133808Spjd	int *force, *nargs, error;
310133808Spjd	const char *name;
311133808Spjd	char param[16];
312133808Spjd	u_int i;
313133808Spjd
314133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
315133808Spjd	if (nargs == NULL) {
316133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
317133808Spjd		return;
318133808Spjd	}
319133808Spjd	if (*nargs < 1) {
320133808Spjd		gctl_error(req, "Missing device(s).");
321133808Spjd		return;
322133808Spjd	}
323133808Spjd	force = gctl_get_paraml(req, "force", sizeof(*force));
324133808Spjd	if (force == NULL) {
325133808Spjd		gctl_error(req, "No '%s' argument.", "force");
326133808Spjd		return;
327133808Spjd	}
328133808Spjd
329133808Spjd	for (i = 0; i < (u_int)*nargs; i++) {
330133808Spjd		snprintf(param, sizeof(param), "arg%u", i);
331133808Spjd		name = gctl_get_asciiparam(req, param);
332133808Spjd		if (name == NULL) {
333133808Spjd			gctl_error(req, "No 'arg%u' argument.", i);
334133808Spjd			return;
335133808Spjd		}
336133808Spjd		sc = g_raid3_find_device(mp, name);
337133808Spjd		if (sc == NULL) {
338133808Spjd			gctl_error(req, "No such device: %s.", name);
339133808Spjd			return;
340133808Spjd		}
341133808Spjd		error = g_raid3_destroy(sc, *force);
342133808Spjd		if (error != 0) {
343133808Spjd			gctl_error(req, "Cannot destroy device %s (error=%d).",
344133808Spjd			    sc->sc_geom->name, error);
345156612Spjd			sx_xunlock(&sc->sc_lock);
346133808Spjd			return;
347133808Spjd		}
348156612Spjd		/* No need to unlock, because lock is already dead. */
349133808Spjd	}
350133808Spjd}
351133808Spjd
352133808Spjdstatic void
353133808Spjdg_raid3_ctl_insert_orphan(struct g_consumer *cp)
354133808Spjd{
355133808Spjd
356133808Spjd	KASSERT(1 == 0, ("%s called while inserting %s.", __func__,
357133808Spjd	    cp->provider->name));
358133808Spjd}
359133808Spjd
360133808Spjdstatic void
361133808Spjdg_raid3_ctl_insert(struct gctl_req *req, struct g_class *mp)
362133808Spjd{
363133808Spjd	struct g_raid3_metadata md;
364133808Spjd	struct g_raid3_softc *sc;
365133808Spjd	struct g_raid3_disk *disk;
366133808Spjd	struct g_geom *gp;
367133808Spjd	struct g_provider *pp;
368133808Spjd	struct g_consumer *cp;
369133808Spjd	const char *name;
370133808Spjd	u_char *sector;
371134420Spjd	off_t compsize;
372133808Spjd	intmax_t *no;
373133808Spjd	int *hardcode, *nargs, error;
374133808Spjd
375133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
376133808Spjd	if (nargs == NULL) {
377133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
378133808Spjd		return;
379133808Spjd	}
380133808Spjd	if (*nargs != 2) {
381133808Spjd		gctl_error(req, "Invalid number of arguments.");
382133808Spjd		return;
383133808Spjd	}
384156612Spjd	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
385156612Spjd	if (hardcode == NULL) {
386156612Spjd		gctl_error(req, "No '%s' argument.", "hardcode");
387133808Spjd		return;
388133808Spjd	}
389156612Spjd	name = gctl_get_asciiparam(req, "arg1");
390156612Spjd	if (name == NULL) {
391156612Spjd		gctl_error(req, "No 'arg%u' argument.", 1);
392133808Spjd		return;
393133808Spjd	}
394133808Spjd	no = gctl_get_paraml(req, "number", sizeof(*no));
395133808Spjd	if (no == NULL) {
396133808Spjd		gctl_error(req, "No '%s' argument.", "no");
397133808Spjd		return;
398133808Spjd	}
399156612Spjd	g_topology_lock();
400156612Spjd	pp = g_provider_by_name(name);
401156612Spjd	if (pp == NULL) {
402156612Spjd		g_topology_unlock();
403156612Spjd		gctl_error(req, "Invalid provider.");
404156612Spjd		return;
405156612Spjd	}
406156612Spjd	gp = g_new_geomf(mp, "raid3:insert");
407156612Spjd	gp->orphan = g_raid3_ctl_insert_orphan;
408156612Spjd	cp = g_new_consumer(gp);
409156612Spjd	error = g_attach(cp, pp);
410156612Spjd	if (error != 0) {
411156612Spjd		g_topology_unlock();
412156612Spjd		gctl_error(req, "Cannot attach to %s.", pp->name);
413156612Spjd		goto end;
414156612Spjd	}
415156612Spjd	error = g_access(cp, 0, 1, 1);
416156612Spjd	if (error != 0) {
417156612Spjd		g_topology_unlock();
418156612Spjd		gctl_error(req, "Cannot access %s.", pp->name);
419156612Spjd		goto end;
420156612Spjd	}
421156612Spjd	g_topology_unlock();
422156612Spjd	name = gctl_get_asciiparam(req, "arg0");
423156612Spjd	if (name == NULL) {
424156612Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
425156612Spjd		goto end;
426156612Spjd	}
427156612Spjd	sc = g_raid3_find_device(mp, name);
428156612Spjd	if (sc == NULL) {
429156612Spjd		gctl_error(req, "No such device: %s.", name);
430156612Spjd		goto end;
431156612Spjd	}
432133808Spjd	if (*no >= sc->sc_ndisks) {
433156612Spjd		sx_xunlock(&sc->sc_lock);
434133808Spjd		gctl_error(req, "Invalid component number.");
435156612Spjd		goto end;
436133808Spjd	}
437133808Spjd	disk = &sc->sc_disks[*no];
438133808Spjd	if (disk->d_state != G_RAID3_DISK_STATE_NODISK) {
439156612Spjd		sx_xunlock(&sc->sc_lock);
440133808Spjd		gctl_error(req, "Component %u is already connected.", *no);
441156612Spjd		goto end;
442133808Spjd	}
443133808Spjd	if (((sc->sc_sectorsize / (sc->sc_ndisks - 1)) % pp->sectorsize) != 0) {
444156612Spjd		sx_xunlock(&sc->sc_lock);
445133808Spjd		gctl_error(req,
446133808Spjd		    "Cannot insert provider %s, because of its sector size.",
447133808Spjd		    pp->name);
448156612Spjd		goto end;
449133808Spjd	}
450134420Spjd	compsize = sc->sc_mediasize / (sc->sc_ndisks - 1);
451134420Spjd	if (compsize > pp->mediasize - pp->sectorsize) {
452156612Spjd		sx_xunlock(&sc->sc_lock);
453134420Spjd		gctl_error(req, "Provider %s too small.", pp->name);
454156612Spjd		goto end;
455134420Spjd	}
456134420Spjd	if (compsize < pp->mediasize - pp->sectorsize) {
457134420Spjd		gctl_error(req,
458134420Spjd		    "warning: %s: only %jd bytes from %jd bytes used.",
459134420Spjd		    pp->name, (intmax_t)compsize,
460134420Spjd		    (intmax_t)(pp->mediasize - pp->sectorsize));
461134420Spjd	}
462133808Spjd	g_raid3_fill_metadata(disk, &md);
463156612Spjd	sx_xunlock(&sc->sc_lock);
464133808Spjd	md.md_syncid = 0;
465133808Spjd        md.md_dflags = 0;
466133808Spjd	if (*hardcode)
467133808Spjd                strlcpy(md.md_provider, pp->name, sizeof(md.md_provider));
468133808Spjd        else
469133808Spjd                bzero(md.md_provider, sizeof(md.md_provider));
470156527Spjd	md.md_provsize = pp->mediasize;
471133808Spjd	sector = g_malloc(pp->sectorsize, M_WAITOK);
472133808Spjd	raid3_metadata_encode(&md, sector);
473133808Spjd	error = g_write_data(cp, pp->mediasize - pp->sectorsize, sector,
474133808Spjd	    pp->sectorsize);
475133808Spjd	g_free(sector);
476133808Spjd	if (error != 0)
477133808Spjd		gctl_error(req, "Cannot store metadata on %s.", pp->name);
478133808Spjdend:
479156612Spjd	g_topology_lock();
480146118Spjd	if (cp->acw > 0)
481146118Spjd		g_access(cp, 0, -1, -1);
482146118Spjd	if (cp->provider != NULL)
483146118Spjd		g_detach(cp);
484146118Spjd	g_destroy_consumer(cp);
485146117Spjd	g_destroy_geom(gp);
486156612Spjd	g_topology_unlock();
487133808Spjd}
488133808Spjd
489133808Spjdstatic void
490133808Spjdg_raid3_ctl_remove(struct gctl_req *req, struct g_class *mp)
491133808Spjd{
492133808Spjd	struct g_raid3_softc *sc;
493133808Spjd	struct g_raid3_disk *disk;
494133808Spjd	const char *name;
495133808Spjd	intmax_t *no;
496133808Spjd	int *nargs;
497133808Spjd
498133808Spjd	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
499133808Spjd	if (nargs == NULL) {
500133808Spjd		gctl_error(req, "No '%s' argument.", "nargs");
501133808Spjd		return;
502133808Spjd	}
503133808Spjd	if (*nargs != 1) {
504133808Spjd		gctl_error(req, "Invalid number of arguments.");
505133808Spjd		return;
506133808Spjd	}
507156612Spjd	no = gctl_get_paraml(req, "number", sizeof(*no));
508156612Spjd	if (no == NULL) {
509156612Spjd		gctl_error(req, "No '%s' argument.", "no");
510156612Spjd		return;
511156612Spjd	}
512133808Spjd	name = gctl_get_asciiparam(req, "arg0");
513133808Spjd	if (name == NULL) {
514133808Spjd		gctl_error(req, "No 'arg%u' argument.", 0);
515133808Spjd		return;
516133808Spjd	}
517133808Spjd	sc = g_raid3_find_device(mp, name);
518133808Spjd	if (sc == NULL) {
519133808Spjd		gctl_error(req, "No such device: %s.", name);
520133808Spjd		return;
521133808Spjd	}
522133808Spjd	if (*no >= sc->sc_ndisks) {
523156612Spjd		sx_xunlock(&sc->sc_lock);
524133808Spjd		gctl_error(req, "Invalid component number.");
525133808Spjd		return;
526133808Spjd	}
527133808Spjd	disk = &sc->sc_disks[*no];
528133808Spjd	switch (disk->d_state) {
529133808Spjd	case G_RAID3_DISK_STATE_ACTIVE:
530133808Spjd		/*
531133808Spjd		 * When replacing ACTIVE component, all the rest has to be also
532133808Spjd		 * ACTIVE.
533133808Spjd		 */
534133808Spjd		if (g_raid3_ndisks(sc, G_RAID3_DISK_STATE_ACTIVE) <
535133808Spjd		    sc->sc_ndisks) {
536133808Spjd			gctl_error(req, "Cannot replace component number %u.",
537133808Spjd			    *no);
538156612Spjd			break;
539133808Spjd		}
540133808Spjd		/* FALLTHROUGH */
541133808Spjd	case G_RAID3_DISK_STATE_STALE:
542133808Spjd	case G_RAID3_DISK_STATE_SYNCHRONIZING:
543133808Spjd		if (g_raid3_clear_metadata(disk) != 0) {
544133808Spjd			gctl_error(req, "Cannot clear metadata on %s.",
545133808Spjd			    g_raid3_get_diskname(disk));
546139295Spjd		} else {
547139295Spjd			g_raid3_event_send(disk,
548139295Spjd			    G_RAID3_DISK_STATE_DISCONNECTED,
549156612Spjd			    G_RAID3_EVENT_DONTWAIT);
550133808Spjd		}
551133808Spjd		break;
552133808Spjd	case G_RAID3_DISK_STATE_NODISK:
553133808Spjd		break;
554133808Spjd	default:
555133808Spjd		gctl_error(req, "Cannot replace component number %u.", *no);
556156612Spjd		break;
557133808Spjd	}
558156612Spjd	sx_xunlock(&sc->sc_lock);
559133808Spjd}
560133808Spjd
561133808Spjdvoid
562133808Spjdg_raid3_config(struct gctl_req *req, struct g_class *mp, const char *verb)
563133808Spjd{
564133808Spjd	uint32_t *version;
565133808Spjd
566133808Spjd	g_topology_assert();
567133808Spjd
568133808Spjd	version = gctl_get_paraml(req, "version", sizeof(*version));
569133808Spjd	if (version == NULL) {
570133808Spjd		gctl_error(req, "No '%s' argument.", "version");
571133808Spjd		return;
572133808Spjd	}
573133808Spjd	if (*version != G_RAID3_VERSION) {
574133808Spjd		gctl_error(req, "Userland and kernel parts are out of sync.");
575133808Spjd		return;
576133808Spjd	}
577133808Spjd
578156612Spjd	g_topology_unlock();
579133808Spjd	if (strcmp(verb, "configure") == 0)
580133808Spjd		g_raid3_ctl_configure(req, mp);
581133808Spjd	else if (strcmp(verb, "insert") == 0)
582133808Spjd		g_raid3_ctl_insert(req, mp);
583133808Spjd	else if (strcmp(verb, "rebuild") == 0)
584133808Spjd		g_raid3_ctl_rebuild(req, mp);
585133808Spjd	else if (strcmp(verb, "remove") == 0)
586133808Spjd		g_raid3_ctl_remove(req, mp);
587133808Spjd	else if (strcmp(verb, "stop") == 0)
588133808Spjd		g_raid3_ctl_stop(req, mp);
589133808Spjd	else
590133808Spjd		gctl_error(req, "Unknown verb.");
591156612Spjd	g_topology_lock();
592133808Spjd}
593