xref: /freebsd/sys/geom/geom_flashmap.c (revision 4ffd4dfe1729706a172acf245e49896d1b99b7b4)
1*4ffd4dfeSGrzegorz Bernacki /*-
2*4ffd4dfeSGrzegorz Bernacki  * Copyright (c) 2012 Semihalf
3*4ffd4dfeSGrzegorz Bernacki  * Copyright (c) 2009 Jakub Klama <jakub.klama@uj.edu.pl>
4*4ffd4dfeSGrzegorz Bernacki  * All rights reserved.
5*4ffd4dfeSGrzegorz Bernacki  *
6*4ffd4dfeSGrzegorz Bernacki  * Redistribution and use in source and binary forms, with or without
7*4ffd4dfeSGrzegorz Bernacki  * modification, are permitted provided that the following conditions
8*4ffd4dfeSGrzegorz Bernacki  * are met:
9*4ffd4dfeSGrzegorz Bernacki  * 1. Redistributions of source code must retain the above copyright
10*4ffd4dfeSGrzegorz Bernacki  *    notice, this list of conditions and the following disclaimer.
11*4ffd4dfeSGrzegorz Bernacki  * 2. Redistributions in binary form must reproduce the above copyright
12*4ffd4dfeSGrzegorz Bernacki  *    notice, this list of conditions and the following disclaimer in the
13*4ffd4dfeSGrzegorz Bernacki  *    documentation and/or other materials provided with the distribution.
14*4ffd4dfeSGrzegorz Bernacki  *
15*4ffd4dfeSGrzegorz Bernacki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16*4ffd4dfeSGrzegorz Bernacki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17*4ffd4dfeSGrzegorz Bernacki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18*4ffd4dfeSGrzegorz Bernacki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19*4ffd4dfeSGrzegorz Bernacki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20*4ffd4dfeSGrzegorz Bernacki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21*4ffd4dfeSGrzegorz Bernacki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22*4ffd4dfeSGrzegorz Bernacki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23*4ffd4dfeSGrzegorz Bernacki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24*4ffd4dfeSGrzegorz Bernacki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25*4ffd4dfeSGrzegorz Bernacki  * SUCH DAMAGE.
26*4ffd4dfeSGrzegorz Bernacki  */
27*4ffd4dfeSGrzegorz Bernacki 
28*4ffd4dfeSGrzegorz Bernacki #include <sys/cdefs.h>
29*4ffd4dfeSGrzegorz Bernacki __FBSDID("$FreeBSD$");
30*4ffd4dfeSGrzegorz Bernacki 
31*4ffd4dfeSGrzegorz Bernacki #include <sys/param.h>
32*4ffd4dfeSGrzegorz Bernacki #include <sys/endian.h>
33*4ffd4dfeSGrzegorz Bernacki #include <sys/systm.h>
34*4ffd4dfeSGrzegorz Bernacki #include <sys/kernel.h>
35*4ffd4dfeSGrzegorz Bernacki #include <sys/fcntl.h>
36*4ffd4dfeSGrzegorz Bernacki #include <sys/malloc.h>
37*4ffd4dfeSGrzegorz Bernacki #include <sys/bio.h>
38*4ffd4dfeSGrzegorz Bernacki #include <sys/bus.h>
39*4ffd4dfeSGrzegorz Bernacki #include <sys/lock.h>
40*4ffd4dfeSGrzegorz Bernacki #include <sys/mutex.h>
41*4ffd4dfeSGrzegorz Bernacki #include <sys/slicer.h>
42*4ffd4dfeSGrzegorz Bernacki 
43*4ffd4dfeSGrzegorz Bernacki #include <geom/geom.h>
44*4ffd4dfeSGrzegorz Bernacki #include <geom/geom_slice.h>
45*4ffd4dfeSGrzegorz Bernacki #include <geom/geom_disk.h>
46*4ffd4dfeSGrzegorz Bernacki #include <dev/nand/nand_dev.h>
47*4ffd4dfeSGrzegorz Bernacki 
48*4ffd4dfeSGrzegorz Bernacki #define FLASHMAP_CLASS_NAME "Flashmap"
49*4ffd4dfeSGrzegorz Bernacki 
50*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_slice {
51*4ffd4dfeSGrzegorz Bernacki 	off_t		sl_start;
52*4ffd4dfeSGrzegorz Bernacki 	off_t		sl_end;
53*4ffd4dfeSGrzegorz Bernacki 	const char	*sl_name;
54*4ffd4dfeSGrzegorz Bernacki 
55*4ffd4dfeSGrzegorz Bernacki 	STAILQ_ENTRY(g_flashmap_slice) sl_link;
56*4ffd4dfeSGrzegorz Bernacki };
57*4ffd4dfeSGrzegorz Bernacki 
58*4ffd4dfeSGrzegorz Bernacki STAILQ_HEAD(g_flashmap_head, g_flashmap_slice);
59*4ffd4dfeSGrzegorz Bernacki 
60*4ffd4dfeSGrzegorz Bernacki static void g_flashmap_print(struct g_flashmap_slice *);
61*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_modify(struct g_geom *, const char *,
62*4ffd4dfeSGrzegorz Bernacki     int, struct g_flashmap_head *);
63*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_start(struct bio *);
64*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_ioctl(struct g_provider *, u_long, void *,
65*4ffd4dfeSGrzegorz Bernacki     int, struct thread *);
66*4ffd4dfeSGrzegorz Bernacki static void g_flashmap_dumpconf(struct sbuf *, const char *,
67*4ffd4dfeSGrzegorz Bernacki     struct g_geom *, struct g_consumer *, struct g_provider *);
68*4ffd4dfeSGrzegorz Bernacki static struct g_geom *g_flashmap_taste(struct g_class *,
69*4ffd4dfeSGrzegorz Bernacki     struct g_provider *, int);
70*4ffd4dfeSGrzegorz Bernacki static void g_flashmap_config(struct gctl_req *, struct g_class *,
71*4ffd4dfeSGrzegorz Bernacki     const char *);
72*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_load(device_t, struct g_flashmap_head *);
73*4ffd4dfeSGrzegorz Bernacki 
74*4ffd4dfeSGrzegorz Bernacki MALLOC_DECLARE(M_FLASHMAP);
75*4ffd4dfeSGrzegorz Bernacki MALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class");
76*4ffd4dfeSGrzegorz Bernacki 
77*4ffd4dfeSGrzegorz Bernacki static void
78*4ffd4dfeSGrzegorz Bernacki g_flashmap_print(struct g_flashmap_slice *slice)
79*4ffd4dfeSGrzegorz Bernacki {
80*4ffd4dfeSGrzegorz Bernacki 
81*4ffd4dfeSGrzegorz Bernacki 	printf("%08llx-%08llx: %s (%lluKB)\n", slice->sl_start, slice->sl_end,
82*4ffd4dfeSGrzegorz Bernacki 	    slice->sl_name, (slice->sl_end - slice->sl_start) / 1024);
83*4ffd4dfeSGrzegorz Bernacki }
84*4ffd4dfeSGrzegorz Bernacki 
85*4ffd4dfeSGrzegorz Bernacki static int
86*4ffd4dfeSGrzegorz Bernacki g_flashmap_modify(struct g_geom *gp, const char *devname, int secsize,
87*4ffd4dfeSGrzegorz Bernacki     struct g_flashmap_head *slices)
88*4ffd4dfeSGrzegorz Bernacki {
89*4ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_slice *slice;
90*4ffd4dfeSGrzegorz Bernacki 	int i, error;
91*4ffd4dfeSGrzegorz Bernacki 
92*4ffd4dfeSGrzegorz Bernacki 	g_topology_assert();
93*4ffd4dfeSGrzegorz Bernacki 
94*4ffd4dfeSGrzegorz Bernacki 	i = 0;
95*4ffd4dfeSGrzegorz Bernacki 	STAILQ_FOREACH(slice, slices, sl_link) {
96*4ffd4dfeSGrzegorz Bernacki 		if (bootverbose) {
97*4ffd4dfeSGrzegorz Bernacki 			printf("%s: slice ", devname);
98*4ffd4dfeSGrzegorz Bernacki 			g_flashmap_print(slice);
99*4ffd4dfeSGrzegorz Bernacki 		}
100*4ffd4dfeSGrzegorz Bernacki 
101*4ffd4dfeSGrzegorz Bernacki 		error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK,
102*4ffd4dfeSGrzegorz Bernacki 		    slice->sl_start,
103*4ffd4dfeSGrzegorz Bernacki 		    slice->sl_end - slice->sl_start + 1,
104*4ffd4dfeSGrzegorz Bernacki 		    secsize, "%ss.%s", gp->name, slice->sl_name);
105*4ffd4dfeSGrzegorz Bernacki 
106*4ffd4dfeSGrzegorz Bernacki 		if (error)
107*4ffd4dfeSGrzegorz Bernacki 			return (error);
108*4ffd4dfeSGrzegorz Bernacki 	}
109*4ffd4dfeSGrzegorz Bernacki 
110*4ffd4dfeSGrzegorz Bernacki 	i = 0;
111*4ffd4dfeSGrzegorz Bernacki 	STAILQ_FOREACH(slice, slices, sl_link) {
112*4ffd4dfeSGrzegorz Bernacki 		error = g_slice_config(gp, i++, G_SLICE_CONFIG_SET,
113*4ffd4dfeSGrzegorz Bernacki 		    slice->sl_start,
114*4ffd4dfeSGrzegorz Bernacki 		    slice->sl_end - slice->sl_start + 1,
115*4ffd4dfeSGrzegorz Bernacki 		    secsize, "%ss.%s", gp->name, slice->sl_name);
116*4ffd4dfeSGrzegorz Bernacki 
117*4ffd4dfeSGrzegorz Bernacki 		if (error)
118*4ffd4dfeSGrzegorz Bernacki 			return (error);
119*4ffd4dfeSGrzegorz Bernacki 	}
120*4ffd4dfeSGrzegorz Bernacki 
121*4ffd4dfeSGrzegorz Bernacki 	return (0);
122*4ffd4dfeSGrzegorz Bernacki }
123*4ffd4dfeSGrzegorz Bernacki 
124*4ffd4dfeSGrzegorz Bernacki static int
125*4ffd4dfeSGrzegorz Bernacki g_flashmap_start(struct bio *bp)
126*4ffd4dfeSGrzegorz Bernacki {
127*4ffd4dfeSGrzegorz Bernacki 
128*4ffd4dfeSGrzegorz Bernacki 	return (0);
129*4ffd4dfeSGrzegorz Bernacki }
130*4ffd4dfeSGrzegorz Bernacki 
131*4ffd4dfeSGrzegorz Bernacki static void
132*4ffd4dfeSGrzegorz Bernacki g_flashmap_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
133*4ffd4dfeSGrzegorz Bernacki     struct g_consumer *cp __unused, struct g_provider *pp)
134*4ffd4dfeSGrzegorz Bernacki {
135*4ffd4dfeSGrzegorz Bernacki 	struct g_slicer *gsp;
136*4ffd4dfeSGrzegorz Bernacki 
137*4ffd4dfeSGrzegorz Bernacki 	gsp = gp->softc;
138*4ffd4dfeSGrzegorz Bernacki 	g_slice_dumpconf(sb, indent, gp, cp, pp);
139*4ffd4dfeSGrzegorz Bernacki }
140*4ffd4dfeSGrzegorz Bernacki 
141*4ffd4dfeSGrzegorz Bernacki static int
142*4ffd4dfeSGrzegorz Bernacki g_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag,
143*4ffd4dfeSGrzegorz Bernacki     struct thread *td)
144*4ffd4dfeSGrzegorz Bernacki {
145*4ffd4dfeSGrzegorz Bernacki 	struct g_consumer *cp;
146*4ffd4dfeSGrzegorz Bernacki 	struct g_geom *gp;
147*4ffd4dfeSGrzegorz Bernacki 
148*4ffd4dfeSGrzegorz Bernacki 	if (cmd != NAND_IO_GET_CHIP_PARAM)
149*4ffd4dfeSGrzegorz Bernacki 		return (ENOIOCTL);
150*4ffd4dfeSGrzegorz Bernacki 
151*4ffd4dfeSGrzegorz Bernacki 	cp = LIST_FIRST(&pp->geom->consumer);
152*4ffd4dfeSGrzegorz Bernacki 	if (cp == NULL)
153*4ffd4dfeSGrzegorz Bernacki 		return (ENOIOCTL);
154*4ffd4dfeSGrzegorz Bernacki 	gp = cp->provider->geom;
155*4ffd4dfeSGrzegorz Bernacki 	if (gp->ioctl == NULL)
156*4ffd4dfeSGrzegorz Bernacki 		return (ENOIOCTL);
157*4ffd4dfeSGrzegorz Bernacki 
158*4ffd4dfeSGrzegorz Bernacki 	return (gp->ioctl(cp->provider, cmd, data, fflag, td));
159*4ffd4dfeSGrzegorz Bernacki }
160*4ffd4dfeSGrzegorz Bernacki 
161*4ffd4dfeSGrzegorz Bernacki 
162*4ffd4dfeSGrzegorz Bernacki static struct g_geom *
163*4ffd4dfeSGrzegorz Bernacki g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags)
164*4ffd4dfeSGrzegorz Bernacki {
165*4ffd4dfeSGrzegorz Bernacki 	struct g_geom *gp = NULL;
166*4ffd4dfeSGrzegorz Bernacki 	struct g_consumer *cp;
167*4ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_head head;
168*4ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_slice *slice, *slice_temp;
169*4ffd4dfeSGrzegorz Bernacki 	device_t dev;
170*4ffd4dfeSGrzegorz Bernacki 	int nslices, size;
171*4ffd4dfeSGrzegorz Bernacki 
172*4ffd4dfeSGrzegorz Bernacki 	g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name);
173*4ffd4dfeSGrzegorz Bernacki 	g_topology_assert();
174*4ffd4dfeSGrzegorz Bernacki 
175*4ffd4dfeSGrzegorz Bernacki 	if (flags == G_TF_NORMAL &&
176*4ffd4dfeSGrzegorz Bernacki 	    !strcmp(pp->geom->class->name, FLASHMAP_CLASS_NAME))
177*4ffd4dfeSGrzegorz Bernacki 		return (NULL);
178*4ffd4dfeSGrzegorz Bernacki 
179*4ffd4dfeSGrzegorz Bernacki 	gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, NULL, 0,
180*4ffd4dfeSGrzegorz Bernacki 	    g_flashmap_start);
181*4ffd4dfeSGrzegorz Bernacki 	if (gp == NULL)
182*4ffd4dfeSGrzegorz Bernacki 		return (NULL);
183*4ffd4dfeSGrzegorz Bernacki 
184*4ffd4dfeSGrzegorz Bernacki 	STAILQ_INIT(&head);
185*4ffd4dfeSGrzegorz Bernacki 
186*4ffd4dfeSGrzegorz Bernacki 	do {
187*4ffd4dfeSGrzegorz Bernacki 		size = sizeof(device_t);
188*4ffd4dfeSGrzegorz Bernacki 		if (g_io_getattr("NAND::device", cp, &size, &dev))
189*4ffd4dfeSGrzegorz Bernacki 			break;
190*4ffd4dfeSGrzegorz Bernacki 
191*4ffd4dfeSGrzegorz Bernacki 		nslices = g_flashmap_load(dev, &head);
192*4ffd4dfeSGrzegorz Bernacki 		if (nslices == 0)
193*4ffd4dfeSGrzegorz Bernacki 			break;
194*4ffd4dfeSGrzegorz Bernacki 
195*4ffd4dfeSGrzegorz Bernacki 		g_flashmap_modify(gp, cp->provider->name,
196*4ffd4dfeSGrzegorz Bernacki 		    cp->provider->sectorsize, &head);
197*4ffd4dfeSGrzegorz Bernacki 	} while (0);
198*4ffd4dfeSGrzegorz Bernacki 
199*4ffd4dfeSGrzegorz Bernacki 	g_access(cp, -1, 0, 0);
200*4ffd4dfeSGrzegorz Bernacki 
201*4ffd4dfeSGrzegorz Bernacki 	STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp) {
202*4ffd4dfeSGrzegorz Bernacki 		free(slice, M_FLASHMAP);
203*4ffd4dfeSGrzegorz Bernacki 	}
204*4ffd4dfeSGrzegorz Bernacki 
205*4ffd4dfeSGrzegorz Bernacki 	if (LIST_EMPTY(&gp->provider)) {
206*4ffd4dfeSGrzegorz Bernacki 		g_slice_spoiled(cp);
207*4ffd4dfeSGrzegorz Bernacki 		return (NULL);
208*4ffd4dfeSGrzegorz Bernacki 	}
209*4ffd4dfeSGrzegorz Bernacki 	return (gp);
210*4ffd4dfeSGrzegorz Bernacki }
211*4ffd4dfeSGrzegorz Bernacki 
212*4ffd4dfeSGrzegorz Bernacki static void
213*4ffd4dfeSGrzegorz Bernacki g_flashmap_config(struct gctl_req *req, struct g_class *mp, const char *verb)
214*4ffd4dfeSGrzegorz Bernacki {
215*4ffd4dfeSGrzegorz Bernacki 
216*4ffd4dfeSGrzegorz Bernacki 	gctl_error(req, "unknown config verb");
217*4ffd4dfeSGrzegorz Bernacki }
218*4ffd4dfeSGrzegorz Bernacki 
219*4ffd4dfeSGrzegorz Bernacki static int
220*4ffd4dfeSGrzegorz Bernacki g_flashmap_load(device_t dev, struct g_flashmap_head *head)
221*4ffd4dfeSGrzegorz Bernacki {
222*4ffd4dfeSGrzegorz Bernacki 	struct flash_slice *slices;
223*4ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_slice *slice;
224*4ffd4dfeSGrzegorz Bernacki 	uint32_t i, buf_size;
225*4ffd4dfeSGrzegorz Bernacki 	int nslices = 0;
226*4ffd4dfeSGrzegorz Bernacki 
227*4ffd4dfeSGrzegorz Bernacki 	buf_size = sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM;
228*4ffd4dfeSGrzegorz Bernacki 	slices = malloc(buf_size, M_FLASHMAP, M_WAITOK | M_ZERO);
229*4ffd4dfeSGrzegorz Bernacki 	if (flash_fill_slices(dev, slices, &nslices) == 0) {
230*4ffd4dfeSGrzegorz Bernacki 		for (i = 0; i < nslices; i++) {
231*4ffd4dfeSGrzegorz Bernacki 			slice = malloc(sizeof(struct g_flashmap_slice),
232*4ffd4dfeSGrzegorz Bernacki 			    M_FLASHMAP, M_WAITOK);
233*4ffd4dfeSGrzegorz Bernacki 
234*4ffd4dfeSGrzegorz Bernacki 			slice->sl_name = slices[i].label;
235*4ffd4dfeSGrzegorz Bernacki 			slice->sl_start = slices[i].base;
236*4ffd4dfeSGrzegorz Bernacki 			slice->sl_end = slices[i].base + slices[i].size - 1;
237*4ffd4dfeSGrzegorz Bernacki 
238*4ffd4dfeSGrzegorz Bernacki 			STAILQ_INSERT_TAIL(head, slice, sl_link);
239*4ffd4dfeSGrzegorz Bernacki 		}
240*4ffd4dfeSGrzegorz Bernacki 	}
241*4ffd4dfeSGrzegorz Bernacki 
242*4ffd4dfeSGrzegorz Bernacki 	free(slices, M_FLASHMAP);
243*4ffd4dfeSGrzegorz Bernacki 	return (nslices);
244*4ffd4dfeSGrzegorz Bernacki }
245*4ffd4dfeSGrzegorz Bernacki 
246*4ffd4dfeSGrzegorz Bernacki static struct g_class g_flashmap_class = {
247*4ffd4dfeSGrzegorz Bernacki 	.name = FLASHMAP_CLASS_NAME,
248*4ffd4dfeSGrzegorz Bernacki 	.version = G_VERSION,
249*4ffd4dfeSGrzegorz Bernacki 	.taste = g_flashmap_taste,
250*4ffd4dfeSGrzegorz Bernacki 	.dumpconf = g_flashmap_dumpconf,
251*4ffd4dfeSGrzegorz Bernacki 	.ioctl = g_flashmap_ioctl,
252*4ffd4dfeSGrzegorz Bernacki 	.ctlreq = g_flashmap_config,
253*4ffd4dfeSGrzegorz Bernacki };
254*4ffd4dfeSGrzegorz Bernacki 
255*4ffd4dfeSGrzegorz Bernacki DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap);
256