1/*-
2 * Copyright (c) 2011 Alexander Motin <mav@FreeBSD.org>
3 * Copyright (c) 2006-2007 Matthew Jacob <mjacob@FreeBSD.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27/*
28 * Based upon work by Pawel Jakub Dawidek <pjd@FreeBSD.org> for all of the
29 * fine geom examples, and by Poul Henning Kamp <phk@FreeBSD.org> for GEOM
30 * itself, all of which is most gratefully acknowledged.
31 */
32
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD$");
35#include <sys/param.h>
36#include <sys/systm.h>
37#include <sys/kernel.h>
38#include <sys/module.h>
39#include <sys/lock.h>
40#include <sys/mutex.h>
41#include <sys/bio.h>
42#include <sys/sbuf.h>
43#include <sys/sysctl.h>
44#include <sys/kthread.h>
45#include <sys/malloc.h>
46#include <geom/geom.h>
47#include <geom/multipath/g_multipath.h>
48
49FEATURE(geom_multipath, "GEOM multipath support");
50
51SYSCTL_DECL(_kern_geom);
52static SYSCTL_NODE(_kern_geom, OID_AUTO, multipath, CTLFLAG_RW, 0,
53    "GEOM_MULTIPATH tunables");
54static u_int g_multipath_debug = 0;
55SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, debug, CTLFLAG_RW,
56    &g_multipath_debug, 0, "Debug level");
57static u_int g_multipath_exclusive = 1;
58SYSCTL_UINT(_kern_geom_multipath, OID_AUTO, exclusive, CTLFLAG_RW,
59    &g_multipath_exclusive, 0, "Exclusively open providers");
60
61static enum {
62	GKT_NIL,
63	GKT_RUN,
64	GKT_DIE
65} g_multipath_kt_state;
66static struct bio_queue_head gmtbq;
67static struct mtx gmtbq_mtx;
68
69static void g_multipath_orphan(struct g_consumer *);
70static void g_multipath_start(struct bio *);
71static void g_multipath_done(struct bio *);
72static void g_multipath_done_error(struct bio *);
73static void g_multipath_kt(void *);
74
75static int g_multipath_destroy(struct g_geom *);
76static int
77g_multipath_destroy_geom(struct gctl_req *, struct g_class *, struct g_geom *);
78
79static struct g_geom *g_multipath_find_geom(struct g_class *, const char *);
80static int g_multipath_rotate(struct g_geom *);
81
82static g_taste_t g_multipath_taste;
83static g_ctl_req_t g_multipath_config;
84static g_init_t g_multipath_init;
85static g_fini_t g_multipath_fini;
86static g_dumpconf_t g_multipath_dumpconf;
87
88struct g_class g_multipath_class = {
89	.name		= G_MULTIPATH_CLASS_NAME,
90	.version	= G_VERSION,
91	.ctlreq		= g_multipath_config,
92	.taste		= g_multipath_taste,
93	.destroy_geom	= g_multipath_destroy_geom,
94	.init		= g_multipath_init,
95	.fini		= g_multipath_fini
96};
97
98#define	MP_FAIL		0x00000001
99#define	MP_LOST		0x00000002
100#define	MP_NEW		0x00000004
101#define	MP_POSTED	0x00000008
102#define	MP_BAD		(MP_FAIL | MP_LOST | MP_NEW)
103#define MP_IDLE		0x00000010
104#define MP_IDLE_MASK	0xfffffff0
105
106static int
107g_multipath_good(struct g_geom *gp)
108{
109	struct g_consumer *cp;
110	int n = 0;
111
112	LIST_FOREACH(cp, &gp->consumer, consumer) {
113		if ((cp->index & MP_BAD) == 0)
114			n++;
115	}
116	return (n);
117}
118
119static void
120g_multipath_fault(struct g_consumer *cp, int cause)
121{
122	struct g_multipath_softc *sc;
123	struct g_consumer *lcp;
124	struct g_geom *gp;
125
126	gp = cp->geom;
127	sc = gp->softc;
128	cp->index |= cause;
129	if (g_multipath_good(gp) == 0 && sc->sc_ndisks > 0) {
130		LIST_FOREACH(lcp, &gp->consumer, consumer) {
131			if (lcp->provider == NULL ||
132			    (lcp->index & (MP_LOST | MP_NEW)))
133				continue;
134			if (sc->sc_ndisks > 1 && lcp == cp)
135				continue;
136			printf("GEOM_MULTIPATH: "
137			    "all paths in %s were marked FAIL, restore %s\n",
138			    sc->sc_name, lcp->provider->name);
139			lcp->index &= ~MP_FAIL;
140		}
141	}
142	if (cp != sc->sc_active)
143		return;
144	sc->sc_active = NULL;
145	LIST_FOREACH(lcp, &gp->consumer, consumer) {
146		if ((lcp->index & MP_BAD) == 0) {
147			sc->sc_active = lcp;
148			break;
149		}
150	}
151	if (sc->sc_active == NULL) {
152		printf("GEOM_MULTIPATH: out of providers for %s\n",
153		    sc->sc_name);
154	} else if (sc->sc_active_active != 1) {
155		printf("GEOM_MULTIPATH: %s is now active path in %s\n",
156		    sc->sc_active->provider->name, sc->sc_name);
157	}
158}
159
160static struct g_consumer *
161g_multipath_choose(struct g_geom *gp, struct bio *bp)
162{
163	struct g_multipath_softc *sc;
164	struct g_consumer *best, *cp;
165
166	sc = gp->softc;
167	if (sc->sc_active_active == 0 ||
168	    (sc->sc_active_active == 2 && bp->bio_cmd != BIO_READ))
169		return (sc->sc_active);
170	best = NULL;
171	LIST_FOREACH(cp, &gp->consumer, consumer) {
172		if (cp->index & MP_BAD)
173			continue;
174		cp->index += MP_IDLE;
175		if (best == NULL || cp->private < best->private ||
176		    (cp->private == best->private && cp->index > best->index))
177			best = cp;
178	}
179	if (best != NULL)
180		best->index &= ~MP_IDLE_MASK;
181	return (best);
182}
183
184static void
185g_mpd(void *arg, int flags __unused)
186{
187	struct g_geom *gp;
188	struct g_multipath_softc *sc;
189	struct g_consumer *cp;
190	int w;
191
192	g_topology_assert();
193	cp = arg;
194	gp = cp->geom;
195	if (cp->acr > 0 || cp->acw > 0 || cp->ace > 0) {
196		w = cp->acw;
197		g_access(cp, -cp->acr, -cp->acw, -cp->ace);
198		if (w > 0 && cp->provider != NULL &&
199		    (cp->provider->geom->flags & G_GEOM_WITHER) == 0) {
200			g_post_event(g_mpd, cp, M_WAITOK, NULL);
201			return;
202		}
203	}
204	sc = gp->softc;
205	mtx_lock(&sc->sc_mtx);
206	if (cp->provider) {
207		printf("GEOM_MULTIPATH: %s removed from %s\n",
208		    cp->provider->name, gp->name);
209		g_detach(cp);
210	}
211	g_destroy_consumer(cp);
212	mtx_unlock(&sc->sc_mtx);
213	if (LIST_EMPTY(&gp->consumer))
214		g_multipath_destroy(gp);
215}
216
217static void
218g_multipath_orphan(struct g_consumer *cp)
219{
220	struct g_multipath_softc *sc;
221	uintptr_t *cnt;
222
223	g_topology_assert();
224	printf("GEOM_MULTIPATH: %s in %s was disconnected\n",
225	    cp->provider->name, cp->geom->name);
226	sc = cp->geom->softc;
227	cnt = (uintptr_t *)&cp->private;
228	mtx_lock(&sc->sc_mtx);
229	sc->sc_ndisks--;
230	g_multipath_fault(cp, MP_LOST);
231	if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
232		cp->index |= MP_POSTED;
233		mtx_unlock(&sc->sc_mtx);
234		g_mpd(cp, 0);
235	} else
236		mtx_unlock(&sc->sc_mtx);
237}
238
239static void
240g_multipath_start(struct bio *bp)
241{
242	struct g_multipath_softc *sc;
243	struct g_geom *gp;
244	struct g_consumer *cp;
245	struct bio *cbp;
246	uintptr_t *cnt;
247
248	gp = bp->bio_to->geom;
249	sc = gp->softc;
250	KASSERT(sc != NULL, ("NULL sc"));
251	cbp = g_clone_bio(bp);
252	if (cbp == NULL) {
253		g_io_deliver(bp, ENOMEM);
254		return;
255	}
256	mtx_lock(&sc->sc_mtx);
257	cp = g_multipath_choose(gp, bp);
258	if (cp == NULL) {
259		mtx_unlock(&sc->sc_mtx);
260		g_destroy_bio(cbp);
261		g_io_deliver(bp, ENXIO);
262		return;
263	}
264	if ((uintptr_t)bp->bio_driver1 < sc->sc_ndisks)
265		bp->bio_driver1 = (void *)(uintptr_t)sc->sc_ndisks;
266	cnt = (uintptr_t *)&cp->private;
267	(*cnt)++;
268	mtx_unlock(&sc->sc_mtx);
269	cbp->bio_done = g_multipath_done;
270	g_io_request(cbp, cp);
271}
272
273static void
274g_multipath_done(struct bio *bp)
275{
276	struct g_multipath_softc *sc;
277	struct g_consumer *cp;
278	uintptr_t *cnt;
279
280	if (bp->bio_error == ENXIO || bp->bio_error == EIO) {
281		mtx_lock(&gmtbq_mtx);
282		bioq_insert_tail(&gmtbq, bp);
283		mtx_unlock(&gmtbq_mtx);
284		wakeup(&g_multipath_kt_state);
285	} else {
286		cp = bp->bio_from;
287		sc = cp->geom->softc;
288		cnt = (uintptr_t *)&cp->private;
289		mtx_lock(&sc->sc_mtx);
290		(*cnt)--;
291		if (*cnt == 0 && (cp->index & MP_LOST)) {
292			cp->index |= MP_POSTED;
293			mtx_unlock(&sc->sc_mtx);
294			g_post_event(g_mpd, cp, M_WAITOK, NULL);
295		} else
296			mtx_unlock(&sc->sc_mtx);
297		g_std_done(bp);
298	}
299}
300
301static void
302g_multipath_done_error(struct bio *bp)
303{
304	struct bio *pbp;
305	struct g_geom *gp;
306	struct g_multipath_softc *sc;
307	struct g_consumer *cp;
308	struct g_provider *pp;
309	uintptr_t *cnt;
310
311	/*
312	 * If we had a failure, we have to check first to see
313	 * whether the consumer it failed on was the currently
314	 * active consumer (i.e., this is the first in perhaps
315	 * a number of failures). If so, we then switch consumers
316	 * to the next available consumer.
317	 */
318
319	pbp = bp->bio_parent;
320	gp = pbp->bio_to->geom;
321	sc = gp->softc;
322	cp = bp->bio_from;
323	pp = cp->provider;
324	cnt = (uintptr_t *)&cp->private;
325
326	mtx_lock(&sc->sc_mtx);
327	if ((cp->index & MP_FAIL) == 0) {
328		printf("GEOM_MULTIPATH: Error %d, %s in %s marked FAIL\n",
329		    bp->bio_error, pp->name, sc->sc_name);
330		g_multipath_fault(cp, MP_FAIL);
331	}
332	(*cnt)--;
333	if (*cnt == 0 && (cp->index & (MP_LOST | MP_POSTED)) == MP_LOST) {
334		cp->index |= MP_POSTED;
335		mtx_unlock(&sc->sc_mtx);
336		g_post_event(g_mpd, cp, M_WAITOK, NULL);
337	} else
338		mtx_unlock(&sc->sc_mtx);
339
340	/*
341	 * If we can fruitfully restart the I/O, do so.
342	 */
343	if (pbp->bio_children < (uintptr_t)pbp->bio_driver1) {
344		pbp->bio_inbed++;
345		g_destroy_bio(bp);
346		g_multipath_start(pbp);
347	} else {
348		g_std_done(bp);
349	}
350}
351
352static void
353g_multipath_kt(void *arg)
354{
355
356	g_multipath_kt_state = GKT_RUN;
357	mtx_lock(&gmtbq_mtx);
358	while (g_multipath_kt_state == GKT_RUN) {
359		for (;;) {
360			struct bio *bp;
361
362			bp = bioq_takefirst(&gmtbq);
363			if (bp == NULL)
364				break;
365			mtx_unlock(&gmtbq_mtx);
366			g_multipath_done_error(bp);
367			mtx_lock(&gmtbq_mtx);
368		}
369		if (g_multipath_kt_state != GKT_RUN)
370			break;
371		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
372		    "gkt:wait", 0);
373	}
374	mtx_unlock(&gmtbq_mtx);
375	wakeup(&g_multipath_kt_state);
376	kproc_exit(0);
377}
378
379
380static int
381g_multipath_access(struct g_provider *pp, int dr, int dw, int de)
382{
383	struct g_geom *gp;
384	struct g_consumer *cp, *badcp = NULL;
385	struct g_multipath_softc *sc;
386	int error;
387
388	gp = pp->geom;
389
390	LIST_FOREACH(cp, &gp->consumer, consumer) {
391		error = g_access(cp, dr, dw, de);
392		if (error) {
393			badcp = cp;
394			goto fail;
395		}
396	}
397	sc = gp->softc;
398	sc->sc_opened += dr + dw + de;
399	if (sc->sc_stopping && sc->sc_opened == 0)
400		g_multipath_destroy(gp);
401	return (0);
402
403fail:
404	LIST_FOREACH(cp, &gp->consumer, consumer) {
405		if (cp == badcp)
406			break;
407		(void) g_access(cp, -dr, -dw, -de);
408	}
409	return (error);
410}
411
412static struct g_geom *
413g_multipath_create(struct g_class *mp, struct g_multipath_metadata *md)
414{
415	struct g_multipath_softc *sc;
416	struct g_geom *gp;
417	struct g_provider *pp;
418
419	g_topology_assert();
420
421	LIST_FOREACH(gp, &mp->geom, geom) {
422		sc = gp->softc;
423		if (sc == NULL || sc->sc_stopping)
424			continue;
425		if (strcmp(gp->name, md->md_name) == 0) {
426			printf("GEOM_MULTIPATH: name %s already exists\n",
427			    md->md_name);
428			return (NULL);
429		}
430	}
431
432	gp = g_new_geomf(mp, "%s", md->md_name);
433	sc = g_malloc(sizeof(*sc), M_WAITOK | M_ZERO);
434	mtx_init(&sc->sc_mtx, "multipath", NULL, MTX_DEF);
435	memcpy(sc->sc_uuid, md->md_uuid, sizeof (sc->sc_uuid));
436	memcpy(sc->sc_name, md->md_name, sizeof (sc->sc_name));
437	sc->sc_active_active = md->md_active_active;
438	gp->softc = sc;
439	gp->start = g_multipath_start;
440	gp->orphan = g_multipath_orphan;
441	gp->access = g_multipath_access;
442	gp->dumpconf = g_multipath_dumpconf;
443
444	pp = g_new_providerf(gp, "multipath/%s", md->md_name);
445	if (md->md_size != 0) {
446		pp->mediasize = md->md_size -
447		    ((md->md_uuid[0] != 0) ? md->md_sectorsize : 0);
448		pp->sectorsize = md->md_sectorsize;
449	}
450	sc->sc_pp = pp;
451	g_error_provider(pp, 0);
452	printf("GEOM_MULTIPATH: %s created\n", gp->name);
453	return (gp);
454}
455
456static int
457g_multipath_add_disk(struct g_geom *gp, struct g_provider *pp)
458{
459	struct g_multipath_softc *sc;
460	struct g_consumer *cp, *nxtcp;
461	int error, acr, acw, ace;
462
463	g_topology_assert();
464
465	sc = gp->softc;
466	KASSERT(sc, ("no softc"));
467
468	/*
469	 * Make sure that the passed provider isn't already attached
470	 */
471	LIST_FOREACH(cp, &gp->consumer, consumer) {
472		if (cp->provider == pp)
473			break;
474	}
475	if (cp) {
476		printf("GEOM_MULTIPATH: provider %s already attached to %s\n",
477		    pp->name, gp->name);
478		return (EEXIST);
479	}
480	nxtcp = LIST_FIRST(&gp->consumer);
481	cp = g_new_consumer(gp);
482	cp->private = NULL;
483	cp->index = MP_NEW;
484	error = g_attach(cp, pp);
485	if (error != 0) {
486		printf("GEOM_MULTIPATH: cannot attach %s to %s",
487		    pp->name, sc->sc_name);
488		g_destroy_consumer(cp);
489		return (error);
490	}
491
492	/*
493	 * Set access permissions on new consumer to match other consumers
494	 */
495	if (sc->sc_pp) {
496		acr = sc->sc_pp->acr;
497		acw = sc->sc_pp->acw;
498		ace = sc->sc_pp->ace;
499	} else
500		acr = acw = ace = 0;
501	if (g_multipath_exclusive) {
502		acr++;
503		acw++;
504		ace++;
505	}
506	error = g_access(cp, acr, acw, ace);
507	if (error) {
508		printf("GEOM_MULTIPATH: cannot set access in "
509		    "attaching %s to %s (%d)\n",
510		    pp->name, sc->sc_name, error);
511		g_detach(cp);
512		g_destroy_consumer(cp);
513		return (error);
514	}
515	if (sc->sc_pp != NULL && sc->sc_pp->mediasize == 0) {
516		sc->sc_pp->mediasize = pp->mediasize -
517		    ((sc->sc_uuid[0] != 0) ? pp->sectorsize : 0);
518		sc->sc_pp->sectorsize = pp->sectorsize;
519	}
520	if (sc->sc_pp != NULL &&
521	    sc->sc_pp->stripesize == 0 && sc->sc_pp->stripeoffset == 0) {
522		sc->sc_pp->stripesize = pp->stripesize;
523		sc->sc_pp->stripeoffset = pp->stripeoffset;
524	}
525	if (sc->sc_pp != NULL)
526		sc->sc_pp->flags |= pp->flags & G_PF_ACCEPT_UNMAPPED;
527	mtx_lock(&sc->sc_mtx);
528	cp->index = 0;
529	sc->sc_ndisks++;
530	mtx_unlock(&sc->sc_mtx);
531	printf("GEOM_MULTIPATH: %s added to %s\n",
532	    pp->name, sc->sc_name);
533	if (sc->sc_active == NULL) {
534		sc->sc_active = cp;
535		if (sc->sc_active_active != 1)
536			printf("GEOM_MULTIPATH: %s is now active path in %s\n",
537			    pp->name, sc->sc_name);
538	}
539	return (0);
540}
541
542static int
543g_multipath_destroy(struct g_geom *gp)
544{
545	struct g_multipath_softc *sc;
546	struct g_consumer *cp, *cp1;
547
548	g_topology_assert();
549	if (gp->softc == NULL)
550		return (ENXIO);
551	sc = gp->softc;
552	if (!sc->sc_stopping) {
553		printf("GEOM_MULTIPATH: destroying %s\n", gp->name);
554		sc->sc_stopping = 1;
555	}
556	if (sc->sc_opened != 0) {
557		if (sc->sc_pp != NULL) {
558			g_wither_provider(sc->sc_pp, ENXIO);
559			sc->sc_pp = NULL;
560		}
561		return (EINPROGRESS);
562	}
563	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
564		mtx_lock(&sc->sc_mtx);
565		if ((cp->index & MP_POSTED) == 0) {
566			cp->index |= MP_POSTED;
567			mtx_unlock(&sc->sc_mtx);
568			g_mpd(cp, 0);
569			if (cp1 == NULL)
570				return(0);	/* Recursion happened. */
571		} else
572			mtx_unlock(&sc->sc_mtx);
573	}
574	if (!LIST_EMPTY(&gp->consumer))
575		return (EINPROGRESS);
576	mtx_destroy(&sc->sc_mtx);
577	g_free(gp->softc);
578	gp->softc = NULL;
579	printf("GEOM_MULTIPATH: %s destroyed\n", gp->name);
580	g_wither_geom(gp, ENXIO);
581	return (0);
582}
583
584static int
585g_multipath_destroy_geom(struct gctl_req *req, struct g_class *mp,
586    struct g_geom *gp)
587{
588
589	return (g_multipath_destroy(gp));
590}
591
592static int
593g_multipath_rotate(struct g_geom *gp)
594{
595	struct g_consumer *lcp, *first_good_cp = NULL;
596	struct g_multipath_softc *sc = gp->softc;
597	int active_cp_seen = 0;
598
599	g_topology_assert();
600	if (sc == NULL)
601		return (ENXIO);
602	LIST_FOREACH(lcp, &gp->consumer, consumer) {
603		if ((lcp->index & MP_BAD) == 0) {
604			if (first_good_cp == NULL)
605				first_good_cp = lcp;
606			if (active_cp_seen)
607				break;
608		}
609		if (sc->sc_active == lcp)
610			active_cp_seen = 1;
611	}
612	if (lcp == NULL)
613		lcp = first_good_cp;
614	if (lcp && lcp != sc->sc_active) {
615		sc->sc_active = lcp;
616		if (sc->sc_active_active != 1)
617			printf("GEOM_MULTIPATH: %s is now active path in %s\n",
618			    lcp->provider->name, sc->sc_name);
619	}
620	return (0);
621}
622
623static void
624g_multipath_init(struct g_class *mp)
625{
626	bioq_init(&gmtbq);
627	mtx_init(&gmtbq_mtx, "gmtbq", NULL, MTX_DEF);
628	kproc_create(g_multipath_kt, mp, NULL, 0, 0, "g_mp_kt");
629}
630
631static void
632g_multipath_fini(struct g_class *mp)
633{
634	if (g_multipath_kt_state == GKT_RUN) {
635		mtx_lock(&gmtbq_mtx);
636		g_multipath_kt_state = GKT_DIE;
637		wakeup(&g_multipath_kt_state);
638		msleep(&g_multipath_kt_state, &gmtbq_mtx, PRIBIO,
639		    "gmp:fini", 0);
640		mtx_unlock(&gmtbq_mtx);
641	}
642}
643
644static int
645g_multipath_read_metadata(struct g_consumer *cp,
646    struct g_multipath_metadata *md)
647{
648	struct g_provider *pp;
649	u_char *buf;
650	int error;
651
652	g_topology_assert();
653	error = g_access(cp, 1, 0, 0);
654	if (error != 0)
655		return (error);
656	pp = cp->provider;
657	g_topology_unlock();
658	buf = g_read_data(cp, pp->mediasize - pp->sectorsize,
659	    pp->sectorsize, &error);
660	g_topology_lock();
661	g_access(cp, -1, 0, 0);
662	if (buf == NULL)
663		return (error);
664	multipath_metadata_decode(buf, md);
665	g_free(buf);
666	return (0);
667}
668
669static struct g_geom *
670g_multipath_taste(struct g_class *mp, struct g_provider *pp, int flags __unused)
671{
672	struct g_multipath_metadata md;
673	struct g_multipath_softc *sc;
674	struct g_consumer *cp;
675	struct g_geom *gp, *gp1;
676	int error, isnew;
677
678	g_topology_assert();
679
680	gp = g_new_geomf(mp, "multipath:taste");
681	gp->start = g_multipath_start;
682	gp->access = g_multipath_access;
683	gp->orphan = g_multipath_orphan;
684	cp = g_new_consumer(gp);
685	g_attach(cp, pp);
686	error = g_multipath_read_metadata(cp, &md);
687	g_detach(cp);
688	g_destroy_consumer(cp);
689	g_destroy_geom(gp);
690	if (error != 0)
691		return (NULL);
692	gp = NULL;
693
694	if (strcmp(md.md_magic, G_MULTIPATH_MAGIC) != 0) {
695		if (g_multipath_debug)
696			printf("%s is not MULTIPATH\n", pp->name);
697		return (NULL);
698	}
699	if (md.md_version != G_MULTIPATH_VERSION) {
700		printf("%s has version %d multipath id- this module is version "
701		    " %d: rejecting\n", pp->name, md.md_version,
702		    G_MULTIPATH_VERSION);
703		return (NULL);
704	}
705	if (md.md_size != 0 && md.md_size != pp->mediasize)
706		return (NULL);
707	if (md.md_sectorsize != 0 && md.md_sectorsize != pp->sectorsize)
708		return (NULL);
709	if (g_multipath_debug)
710		printf("MULTIPATH: %s/%s\n", md.md_name, md.md_uuid);
711
712	/*
713	 * Let's check if such a device already is present. We check against
714	 * uuid alone first because that's the true distinguishor. If that
715	 * passes, then we check for name conflicts. If there are conflicts,
716	 * modify the name.
717	 *
718	 * The whole purpose of this is to solve the problem that people don't
719	 * pick good unique names, but good unique names (like uuids) are a
720	 * pain to use. So, we allow people to build GEOMs with friendly names
721	 * and uuids, and modify the names in case there's a collision.
722	 */
723	sc = NULL;
724	LIST_FOREACH(gp, &mp->geom, geom) {
725		sc = gp->softc;
726		if (sc == NULL || sc->sc_stopping)
727			continue;
728		if (strncmp(md.md_uuid, sc->sc_uuid, sizeof(md.md_uuid)) == 0)
729			break;
730	}
731
732	LIST_FOREACH(gp1, &mp->geom, geom) {
733		if (gp1 == gp)
734			continue;
735		sc = gp1->softc;
736		if (sc == NULL || sc->sc_stopping)
737			continue;
738		if (strncmp(md.md_name, sc->sc_name, sizeof(md.md_name)) == 0)
739			break;
740	}
741
742	/*
743	 * If gp is NULL, we had no extant MULTIPATH geom with this uuid.
744	 *
745	 * If gp1 is *not* NULL, that means we have a MULTIPATH geom extant
746	 * with the same name (but a different UUID).
747	 *
748	 * If gp is NULL, then modify the name with a random number and
749  	 * complain, but allow the creation of the geom to continue.
750	 *
751	 * If gp is *not* NULL, just use the geom's name as we're attaching
752	 * this disk to the (previously generated) name.
753	 */
754
755	if (gp1) {
756		sc = gp1->softc;
757		if (gp == NULL) {
758			char buf[16];
759			u_long rand = random();
760
761			snprintf(buf, sizeof (buf), "%s-%lu", md.md_name, rand);
762			printf("GEOM_MULTIPATH: geom %s/%s exists already\n",
763			    sc->sc_name, sc->sc_uuid);
764			printf("GEOM_MULTIPATH: %s will be (temporarily) %s\n",
765			    md.md_uuid, buf);
766			strlcpy(md.md_name, buf, sizeof(md.md_name));
767		} else {
768			strlcpy(md.md_name, sc->sc_name, sizeof(md.md_name));
769		}
770	}
771
772	if (gp == NULL) {
773		gp = g_multipath_create(mp, &md);
774		if (gp == NULL) {
775			printf("GEOM_MULTIPATH: cannot create geom %s/%s\n",
776			    md.md_name, md.md_uuid);
777			return (NULL);
778		}
779		isnew = 1;
780	} else {
781		isnew = 0;
782	}
783
784	sc = gp->softc;
785	KASSERT(sc != NULL, ("sc is NULL"));
786	error = g_multipath_add_disk(gp, pp);
787	if (error != 0) {
788		if (isnew)
789			g_multipath_destroy(gp);
790		return (NULL);
791	}
792	return (gp);
793}
794
795static void
796g_multipath_ctl_add_name(struct gctl_req *req, struct g_class *mp,
797    const char *name)
798{
799	struct g_multipath_softc *sc;
800	struct g_geom *gp;
801	struct g_consumer *cp;
802	struct g_provider *pp;
803	const char *mpname;
804	static const char devpf[6] = "/dev/";
805
806	g_topology_assert();
807
808	mpname = gctl_get_asciiparam(req, "arg0");
809        if (mpname == NULL) {
810                gctl_error(req, "No 'arg0' argument");
811                return;
812        }
813	gp = g_multipath_find_geom(mp, mpname);
814	if (gp == NULL) {
815		gctl_error(req, "Device %s is invalid", mpname);
816		return;
817	}
818	sc = gp->softc;
819
820	if (strncmp(name, devpf, 5) == 0)
821		name += 5;
822	pp = g_provider_by_name(name);
823	if (pp == NULL) {
824		gctl_error(req, "Provider %s is invalid", name);
825		return;
826	}
827
828	/*
829	 * Check to make sure parameters match.
830	 */
831	LIST_FOREACH(cp, &gp->consumer, consumer) {
832		if (cp->provider == pp) {
833			gctl_error(req, "provider %s is already there",
834			    pp->name);
835			return;
836		}
837	}
838	if (sc->sc_pp != NULL && sc->sc_pp->mediasize != 0 &&
839	    sc->sc_pp->mediasize + (sc->sc_uuid[0] != 0 ? pp->sectorsize : 0)
840	     != pp->mediasize) {
841		gctl_error(req, "Providers size mismatch %jd != %jd",
842		    (intmax_t) sc->sc_pp->mediasize +
843			(sc->sc_uuid[0] != 0 ? pp->sectorsize : 0),
844		    (intmax_t) pp->mediasize);
845		return;
846	}
847	if (sc->sc_pp != NULL && sc->sc_pp->sectorsize != 0 &&
848	    sc->sc_pp->sectorsize != pp->sectorsize) {
849		gctl_error(req, "Providers sectorsize mismatch %u != %u",
850		    sc->sc_pp->sectorsize, pp->sectorsize);
851		return;
852	}
853
854	/*
855	 * Now add....
856	 */
857	(void) g_multipath_add_disk(gp, pp);
858}
859
860static void
861g_multipath_ctl_prefer(struct gctl_req *req, struct g_class *mp)
862{
863	struct g_geom *gp;
864	struct g_multipath_softc *sc;
865	struct g_consumer *cp;
866	const char *name, *mpname;
867	static const char devpf[6] = "/dev/";
868	int *nargs;
869
870	g_topology_assert();
871
872	mpname = gctl_get_asciiparam(req, "arg0");
873        if (mpname == NULL) {
874                gctl_error(req, "No 'arg0' argument");
875                return;
876        }
877	gp = g_multipath_find_geom(mp, mpname);
878	if (gp == NULL) {
879		gctl_error(req, "Device %s is invalid", mpname);
880		return;
881	}
882	sc = gp->softc;
883
884	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
885	if (nargs == NULL) {
886		gctl_error(req, "No 'nargs' argument");
887		return;
888	}
889	if (*nargs != 2) {
890		gctl_error(req, "missing device");
891		return;
892	}
893
894	name = gctl_get_asciiparam(req, "arg1");
895	if (name == NULL) {
896		gctl_error(req, "No 'arg1' argument");
897		return;
898	}
899	if (strncmp(name, devpf, 5) == 0) {
900		name += 5;
901	}
902
903	LIST_FOREACH(cp, &gp->consumer, consumer) {
904		if (cp->provider != NULL
905                      && strcmp(cp->provider->name, name) == 0)
906		    break;
907	}
908
909	if (cp == NULL) {
910		gctl_error(req, "Provider %s not found", name);
911		return;
912	}
913
914	mtx_lock(&sc->sc_mtx);
915
916	if (cp->index & MP_BAD) {
917		gctl_error(req, "Consumer %s is invalid", name);
918		mtx_unlock(&sc->sc_mtx);
919		return;
920	}
921
922	/* Here when the consumer is present and in good shape */
923
924	sc->sc_active = cp;
925	if (!sc->sc_active_active)
926	    printf("GEOM_MULTIPATH: %s now active path in %s\n",
927		sc->sc_active->provider->name, sc->sc_name);
928
929	mtx_unlock(&sc->sc_mtx);
930}
931
932static void
933g_multipath_ctl_add(struct gctl_req *req, struct g_class *mp)
934{
935	struct g_multipath_softc *sc;
936	struct g_geom *gp;
937	const char *mpname, *name;
938
939	mpname = gctl_get_asciiparam(req, "arg0");
940        if (mpname == NULL) {
941                gctl_error(req, "No 'arg0' argument");
942                return;
943        }
944	gp = g_multipath_find_geom(mp, mpname);
945	if (gp == NULL) {
946		gctl_error(req, "Device %s not found", mpname);
947		return;
948	}
949	sc = gp->softc;
950
951	name = gctl_get_asciiparam(req, "arg1");
952	if (name == NULL) {
953		gctl_error(req, "No 'arg1' argument");
954		return;
955	}
956	g_multipath_ctl_add_name(req, mp, name);
957}
958
959static void
960g_multipath_ctl_create(struct gctl_req *req, struct g_class *mp)
961{
962	struct g_multipath_metadata md;
963	struct g_multipath_softc *sc;
964	struct g_geom *gp;
965	const char *mpname, *name;
966	char param[16];
967	int *nargs, i, *val;
968
969	g_topology_assert();
970
971	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
972	if (*nargs < 2) {
973		gctl_error(req, "wrong number of arguments.");
974		return;
975	}
976
977	mpname = gctl_get_asciiparam(req, "arg0");
978        if (mpname == NULL) {
979                gctl_error(req, "No 'arg0' argument");
980                return;
981        }
982	gp = g_multipath_find_geom(mp, mpname);
983	if (gp != NULL) {
984		gctl_error(req, "Device %s already exist", mpname);
985		return;
986	}
987	sc = gp->softc;
988
989	memset(&md, 0, sizeof(md));
990	strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
991	md.md_version = G_MULTIPATH_VERSION;
992	strlcpy(md.md_name, mpname, sizeof(md.md_name));
993	md.md_size = 0;
994	md.md_sectorsize = 0;
995	md.md_uuid[0] = 0;
996	md.md_active_active = 0;
997	val = gctl_get_paraml(req, "active_active", sizeof(*val));
998	if (val != NULL && *val != 0)
999		md.md_active_active = 1;
1000	val = gctl_get_paraml(req, "active_read", sizeof(*val));
1001	if (val != NULL && *val != 0)
1002		md.md_active_active = 2;
1003	gp = g_multipath_create(mp, &md);
1004	if (gp == NULL) {
1005		gctl_error(req, "GEOM_MULTIPATH: cannot create geom %s/%s\n",
1006		    md.md_name, md.md_uuid);
1007		return;
1008	}
1009	sc = gp->softc;
1010
1011	for (i = 1; i < *nargs; i++) {
1012		snprintf(param, sizeof(param), "arg%d", i);
1013		name = gctl_get_asciiparam(req, param);
1014		g_multipath_ctl_add_name(req, mp, name);
1015	}
1016
1017	if (sc->sc_ndisks != (*nargs - 1))
1018		g_multipath_destroy(gp);
1019}
1020
1021static void
1022g_multipath_ctl_configure(struct gctl_req *req, struct g_class *mp)
1023{
1024	struct g_multipath_softc *sc;
1025	struct g_geom *gp;
1026	struct g_consumer *cp;
1027	struct g_provider *pp;
1028	struct g_multipath_metadata md;
1029	const char *name;
1030	int error, *val;
1031	void *buf;
1032
1033	g_topology_assert();
1034
1035	name = gctl_get_asciiparam(req, "arg0");
1036	if (name == NULL) {
1037		gctl_error(req, "No 'arg0' argument");
1038		return;
1039	}
1040	gp = g_multipath_find_geom(mp, name);
1041	if (gp == NULL) {
1042		gctl_error(req, "Device %s is invalid", name);
1043		return;
1044	}
1045	sc = gp->softc;
1046	val = gctl_get_paraml(req, "active_active", sizeof(*val));
1047	if (val != NULL && *val != 0)
1048		sc->sc_active_active = 1;
1049	val = gctl_get_paraml(req, "active_read", sizeof(*val));
1050	if (val != NULL && *val != 0)
1051		sc->sc_active_active = 2;
1052	val = gctl_get_paraml(req, "active_passive", sizeof(*val));
1053	if (val != NULL && *val != 0)
1054		sc->sc_active_active = 0;
1055	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
1056		cp = sc->sc_active;
1057		pp = cp->provider;
1058		error = g_access(cp, 1, 1, 1);
1059		if (error != 0) {
1060			gctl_error(req, "Can't open %s (%d)", pp->name, error);
1061			return;
1062		}
1063		g_topology_unlock();
1064		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1065		strlcpy(md.md_magic, G_MULTIPATH_MAGIC, sizeof(md.md_magic));
1066		memcpy(md.md_uuid, sc->sc_uuid, sizeof (sc->sc_uuid));
1067		strlcpy(md.md_name, name, sizeof(md.md_name));
1068		md.md_version = G_MULTIPATH_VERSION;
1069		md.md_size = pp->mediasize;
1070		md.md_sectorsize = pp->sectorsize;
1071		md.md_active_active = sc->sc_active_active;
1072		multipath_metadata_encode(&md, buf);
1073		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1074		    buf, pp->sectorsize);
1075		g_topology_lock();
1076		g_access(cp, -1, -1, -1);
1077		if (error != 0)
1078			gctl_error(req, "Can't update metadata on %s (%d)",
1079			    pp->name, error);
1080	}
1081}
1082
1083static void
1084g_multipath_ctl_fail(struct gctl_req *req, struct g_class *mp, int fail)
1085{
1086	struct g_multipath_softc *sc;
1087	struct g_geom *gp;
1088	struct g_consumer *cp;
1089	const char *mpname, *name;
1090	int found;
1091
1092	mpname = gctl_get_asciiparam(req, "arg0");
1093        if (mpname == NULL) {
1094                gctl_error(req, "No 'arg0' argument");
1095                return;
1096        }
1097	gp = g_multipath_find_geom(mp, mpname);
1098	if (gp == NULL) {
1099		gctl_error(req, "Device %s not found", mpname);
1100		return;
1101	}
1102	sc = gp->softc;
1103
1104	name = gctl_get_asciiparam(req, "arg1");
1105	if (name == NULL) {
1106		gctl_error(req, "No 'arg1' argument");
1107		return;
1108	}
1109
1110	found = 0;
1111	mtx_lock(&sc->sc_mtx);
1112	LIST_FOREACH(cp, &gp->consumer, consumer) {
1113		if (cp->provider != NULL &&
1114		    strcmp(cp->provider->name, name) == 0 &&
1115		    (cp->index & MP_LOST) == 0) {
1116			found = 1;
1117			if (!fail == !(cp->index & MP_FAIL))
1118				continue;
1119			printf("GEOM_MULTIPATH: %s in %s is marked %s.\n",
1120				name, sc->sc_name, fail ? "FAIL" : "OK");
1121			if (fail) {
1122				g_multipath_fault(cp, MP_FAIL);
1123			} else {
1124				cp->index &= ~MP_FAIL;
1125			}
1126		}
1127	}
1128	mtx_unlock(&sc->sc_mtx);
1129	if (found == 0)
1130		gctl_error(req, "Provider %s not found", name);
1131}
1132
1133static void
1134g_multipath_ctl_remove(struct gctl_req *req, struct g_class *mp)
1135{
1136	struct g_multipath_softc *sc;
1137	struct g_geom *gp;
1138	struct g_consumer *cp, *cp1;
1139	const char *mpname, *name;
1140	uintptr_t *cnt;
1141	int found;
1142
1143	mpname = gctl_get_asciiparam(req, "arg0");
1144        if (mpname == NULL) {
1145                gctl_error(req, "No 'arg0' argument");
1146                return;
1147        }
1148	gp = g_multipath_find_geom(mp, mpname);
1149	if (gp == NULL) {
1150		gctl_error(req, "Device %s not found", mpname);
1151		return;
1152	}
1153	sc = gp->softc;
1154
1155	name = gctl_get_asciiparam(req, "arg1");
1156	if (name == NULL) {
1157		gctl_error(req, "No 'arg1' argument");
1158		return;
1159	}
1160
1161	found = 0;
1162	mtx_lock(&sc->sc_mtx);
1163	LIST_FOREACH_SAFE(cp, &gp->consumer, consumer, cp1) {
1164		if (cp->provider != NULL &&
1165		    strcmp(cp->provider->name, name) == 0 &&
1166		    (cp->index & MP_LOST) == 0) {
1167			found = 1;
1168			printf("GEOM_MULTIPATH: removing %s from %s\n",
1169			    cp->provider->name, cp->geom->name);
1170			sc->sc_ndisks--;
1171			g_multipath_fault(cp, MP_LOST);
1172			cnt = (uintptr_t *)&cp->private;
1173			if (*cnt == 0 && (cp->index & MP_POSTED) == 0) {
1174				cp->index |= MP_POSTED;
1175				mtx_unlock(&sc->sc_mtx);
1176				g_mpd(cp, 0);
1177				if (cp1 == NULL)
1178					return;	/* Recursion happened. */
1179				mtx_lock(&sc->sc_mtx);
1180			}
1181		}
1182	}
1183	mtx_unlock(&sc->sc_mtx);
1184	if (found == 0)
1185		gctl_error(req, "Provider %s not found", name);
1186}
1187
1188static struct g_geom *
1189g_multipath_find_geom(struct g_class *mp, const char *name)
1190{
1191	struct g_geom *gp;
1192	struct g_multipath_softc *sc;
1193
1194	LIST_FOREACH(gp, &mp->geom, geom) {
1195		sc = gp->softc;
1196		if (sc == NULL || sc->sc_stopping)
1197			continue;
1198		if (strcmp(gp->name, name) == 0)
1199			return (gp);
1200	}
1201	return (NULL);
1202}
1203
1204static void
1205g_multipath_ctl_stop(struct gctl_req *req, struct g_class *mp)
1206{
1207	struct g_geom *gp;
1208	const char *name;
1209	int error;
1210
1211	g_topology_assert();
1212
1213	name = gctl_get_asciiparam(req, "arg0");
1214        if (name == NULL) {
1215                gctl_error(req, "No 'arg0' argument");
1216                return;
1217        }
1218	gp = g_multipath_find_geom(mp, name);
1219	if (gp == NULL) {
1220		gctl_error(req, "Device %s is invalid", name);
1221		return;
1222	}
1223	error = g_multipath_destroy(gp);
1224	if (error != 0 && error != EINPROGRESS)
1225		gctl_error(req, "failed to stop %s (err=%d)", name, error);
1226}
1227
1228static void
1229g_multipath_ctl_destroy(struct gctl_req *req, struct g_class *mp)
1230{
1231	struct g_geom *gp;
1232	struct g_multipath_softc *sc;
1233	struct g_consumer *cp;
1234	struct g_provider *pp;
1235	const char *name;
1236	uint8_t *buf;
1237	int error;
1238
1239	g_topology_assert();
1240
1241	name = gctl_get_asciiparam(req, "arg0");
1242        if (name == NULL) {
1243                gctl_error(req, "No 'arg0' argument");
1244                return;
1245        }
1246	gp = g_multipath_find_geom(mp, name);
1247	if (gp == NULL) {
1248		gctl_error(req, "Device %s is invalid", name);
1249		return;
1250	}
1251	sc = gp->softc;
1252
1253	if (sc->sc_uuid[0] != 0 && sc->sc_active != NULL) {
1254		cp = sc->sc_active;
1255		pp = cp->provider;
1256		error = g_access(cp, 1, 1, 1);
1257		if (error != 0) {
1258			gctl_error(req, "Can't open %s (%d)", pp->name, error);
1259			goto destroy;
1260		}
1261		g_topology_unlock();
1262		buf = g_malloc(pp->sectorsize, M_WAITOK | M_ZERO);
1263		error = g_write_data(cp, pp->mediasize - pp->sectorsize,
1264		    buf, pp->sectorsize);
1265		g_topology_lock();
1266		g_access(cp, -1, -1, -1);
1267		if (error != 0)
1268			gctl_error(req, "Can't erase metadata on %s (%d)",
1269			    pp->name, error);
1270	}
1271
1272destroy:
1273	error = g_multipath_destroy(gp);
1274	if (error != 0 && error != EINPROGRESS)
1275		gctl_error(req, "failed to destroy %s (err=%d)", name, error);
1276}
1277
1278static void
1279g_multipath_ctl_rotate(struct gctl_req *req, struct g_class *mp)
1280{
1281	struct g_geom *gp;
1282	const char *name;
1283	int error;
1284
1285	g_topology_assert();
1286
1287	name = gctl_get_asciiparam(req, "arg0");
1288        if (name == NULL) {
1289                gctl_error(req, "No 'arg0' argument");
1290                return;
1291        }
1292	gp = g_multipath_find_geom(mp, name);
1293	if (gp == NULL) {
1294		gctl_error(req, "Device %s is invalid", name);
1295		return;
1296	}
1297	error = g_multipath_rotate(gp);
1298	if (error != 0) {
1299		gctl_error(req, "failed to rotate %s (err=%d)", name, error);
1300	}
1301}
1302
1303static void
1304g_multipath_ctl_getactive(struct gctl_req *req, struct g_class *mp)
1305{
1306	struct sbuf *sb;
1307	struct g_geom *gp;
1308	struct g_multipath_softc *sc;
1309	struct g_consumer *cp;
1310	const char *name;
1311	int empty;
1312
1313	sb = sbuf_new_auto();
1314
1315	g_topology_assert();
1316	name = gctl_get_asciiparam(req, "arg0");
1317        if (name == NULL) {
1318                gctl_error(req, "No 'arg0' argument");
1319                return;
1320        }
1321	gp = g_multipath_find_geom(mp, name);
1322	if (gp == NULL) {
1323		gctl_error(req, "Device %s is invalid", name);
1324		return;
1325	}
1326	sc = gp->softc;
1327	if (sc->sc_active_active == 1) {
1328		empty = 1;
1329		LIST_FOREACH(cp, &gp->consumer, consumer) {
1330			if (cp->index & MP_BAD)
1331				continue;
1332			if (!empty)
1333				sbuf_cat(sb, " ");
1334			sbuf_cat(sb, cp->provider->name);
1335			empty = 0;
1336		}
1337		if (empty)
1338			sbuf_cat(sb, "none");
1339		sbuf_cat(sb, "\n");
1340	} else if (sc->sc_active && sc->sc_active->provider) {
1341		sbuf_printf(sb, "%s\n", sc->sc_active->provider->name);
1342	} else {
1343		sbuf_printf(sb, "none\n");
1344	}
1345	sbuf_finish(sb);
1346	gctl_set_param_err(req, "output", sbuf_data(sb), sbuf_len(sb) + 1);
1347	sbuf_delete(sb);
1348}
1349
1350static void
1351g_multipath_config(struct gctl_req *req, struct g_class *mp, const char *verb)
1352{
1353	uint32_t *version;
1354	g_topology_assert();
1355	version = gctl_get_paraml(req, "version", sizeof(*version));
1356	if (version == NULL) {
1357		gctl_error(req, "No 'version' argument");
1358	} else if (*version != G_MULTIPATH_VERSION) {
1359		gctl_error(req, "Userland and kernel parts are out of sync");
1360	} else if (strcmp(verb, "add") == 0) {
1361		g_multipath_ctl_add(req, mp);
1362	} else if (strcmp(verb, "prefer") == 0) {
1363		g_multipath_ctl_prefer(req, mp);
1364	} else if (strcmp(verb, "create") == 0) {
1365		g_multipath_ctl_create(req, mp);
1366	} else if (strcmp(verb, "configure") == 0) {
1367		g_multipath_ctl_configure(req, mp);
1368	} else if (strcmp(verb, "stop") == 0) {
1369		g_multipath_ctl_stop(req, mp);
1370	} else if (strcmp(verb, "destroy") == 0) {
1371		g_multipath_ctl_destroy(req, mp);
1372	} else if (strcmp(verb, "fail") == 0) {
1373		g_multipath_ctl_fail(req, mp, 1);
1374	} else if (strcmp(verb, "restore") == 0) {
1375		g_multipath_ctl_fail(req, mp, 0);
1376	} else if (strcmp(verb, "remove") == 0) {
1377		g_multipath_ctl_remove(req, mp);
1378	} else if (strcmp(verb, "rotate") == 0) {
1379		g_multipath_ctl_rotate(req, mp);
1380	} else if (strcmp(verb, "getactive") == 0) {
1381		g_multipath_ctl_getactive(req, mp);
1382	} else {
1383		gctl_error(req, "Unknown verb %s", verb);
1384	}
1385}
1386
1387static void
1388g_multipath_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
1389    struct g_consumer *cp, struct g_provider *pp)
1390{
1391	struct g_multipath_softc *sc;
1392	int good;
1393
1394	g_topology_assert();
1395
1396	sc = gp->softc;
1397	if (sc == NULL)
1398		return;
1399	if (cp != NULL) {
1400		sbuf_printf(sb, "%s<State>%s</State>\n", indent,
1401		    (cp->index & MP_NEW) ? "NEW" :
1402		    (cp->index & MP_LOST) ? "LOST" :
1403		    (cp->index & MP_FAIL) ? "FAIL" :
1404		    (sc->sc_active_active == 1 || sc->sc_active == cp) ?
1405		     "ACTIVE" :
1406		     sc->sc_active_active == 2 ? "READ" : "PASSIVE");
1407	} else {
1408		good = g_multipath_good(gp);
1409		sbuf_printf(sb, "%s<State>%s</State>\n", indent,
1410		    good == 0 ? "BROKEN" :
1411		    (good != sc->sc_ndisks || sc->sc_ndisks == 1) ?
1412		    "DEGRADED" : "OPTIMAL");
1413	}
1414	if (cp == NULL && pp == NULL) {
1415		sbuf_printf(sb, "%s<UUID>%s</UUID>\n", indent, sc->sc_uuid);
1416		sbuf_printf(sb, "%s<Mode>Active/%s</Mode>\n", indent,
1417		    sc->sc_active_active == 2 ? "Read" :
1418		    sc->sc_active_active == 1 ? "Active" : "Passive");
1419		sbuf_printf(sb, "%s<Type>%s</Type>\n", indent,
1420		    sc->sc_uuid[0] == 0 ? "MANUAL" : "AUTOMATIC");
1421	}
1422}
1423
1424DECLARE_GEOM_CLASS(g_multipath_class, g_multipath);
1425