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