xref: /freebsd/sys/geom/geom_flashmap.c (revision 4d846d260e2b9a3d4d0a701462568268cbfe7a5b)
14ffd4dfeSGrzegorz Bernacki /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
33728855aSPedro F. Giffuni  *
44ffd4dfeSGrzegorz Bernacki  * Copyright (c) 2012 Semihalf
54ffd4dfeSGrzegorz Bernacki  * Copyright (c) 2009 Jakub Klama <jakub.klama@uj.edu.pl>
64ffd4dfeSGrzegorz Bernacki  * All rights reserved.
74ffd4dfeSGrzegorz Bernacki  *
84ffd4dfeSGrzegorz Bernacki  * Redistribution and use in source and binary forms, with or without
94ffd4dfeSGrzegorz Bernacki  * modification, are permitted provided that the following conditions
104ffd4dfeSGrzegorz Bernacki  * are met:
114ffd4dfeSGrzegorz Bernacki  * 1. Redistributions of source code must retain the above copyright
124ffd4dfeSGrzegorz Bernacki  *    notice, this list of conditions and the following disclaimer.
134ffd4dfeSGrzegorz Bernacki  * 2. Redistributions in binary form must reproduce the above copyright
144ffd4dfeSGrzegorz Bernacki  *    notice, this list of conditions and the following disclaimer in the
154ffd4dfeSGrzegorz Bernacki  *    documentation and/or other materials provided with the distribution.
164ffd4dfeSGrzegorz Bernacki  *
174ffd4dfeSGrzegorz Bernacki  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
184ffd4dfeSGrzegorz Bernacki  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
194ffd4dfeSGrzegorz Bernacki  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
204ffd4dfeSGrzegorz Bernacki  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
214ffd4dfeSGrzegorz Bernacki  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
224ffd4dfeSGrzegorz Bernacki  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
234ffd4dfeSGrzegorz Bernacki  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
244ffd4dfeSGrzegorz Bernacki  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
254ffd4dfeSGrzegorz Bernacki  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
264ffd4dfeSGrzegorz Bernacki  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
274ffd4dfeSGrzegorz Bernacki  * SUCH DAMAGE.
284ffd4dfeSGrzegorz Bernacki  */
294ffd4dfeSGrzegorz Bernacki 
304ffd4dfeSGrzegorz Bernacki #include <sys/cdefs.h>
314ffd4dfeSGrzegorz Bernacki __FBSDID("$FreeBSD$");
324ffd4dfeSGrzegorz Bernacki 
334ffd4dfeSGrzegorz Bernacki #include <sys/param.h>
344ffd4dfeSGrzegorz Bernacki #include <sys/systm.h>
354ffd4dfeSGrzegorz Bernacki #include <sys/kernel.h>
364ffd4dfeSGrzegorz Bernacki #include <sys/malloc.h>
374ffd4dfeSGrzegorz Bernacki #include <sys/lock.h>
384ffd4dfeSGrzegorz Bernacki #include <sys/mutex.h>
394ffd4dfeSGrzegorz Bernacki #include <sys/slicer.h>
404ffd4dfeSGrzegorz Bernacki 
414ffd4dfeSGrzegorz Bernacki #include <geom/geom.h>
424ffd4dfeSGrzegorz Bernacki #include <geom/geom_disk.h>
4391a3f358SIan Lepore #include <geom/geom_flashmap.h>
4491a3f358SIan Lepore #include <geom/geom_slice.h>
454874af73SMarius Strobl 
464ffd4dfeSGrzegorz Bernacki struct g_flashmap_slice {
474ffd4dfeSGrzegorz Bernacki 	off_t		sl_start;
484ffd4dfeSGrzegorz Bernacki 	off_t		sl_end;
494ffd4dfeSGrzegorz Bernacki 	const char	*sl_name;
504ffd4dfeSGrzegorz Bernacki 
514ffd4dfeSGrzegorz Bernacki 	STAILQ_ENTRY(g_flashmap_slice) sl_link;
524ffd4dfeSGrzegorz Bernacki };
534ffd4dfeSGrzegorz Bernacki 
544ffd4dfeSGrzegorz Bernacki STAILQ_HEAD(g_flashmap_head, g_flashmap_slice);
554ffd4dfeSGrzegorz Bernacki 
564874af73SMarius Strobl static struct {
574874af73SMarius Strobl 	const char	*type;
584874af73SMarius Strobl 	flash_slicer_t	slicer;
594874af73SMarius Strobl } g_flashmap_slicers[] = {
604874af73SMarius Strobl 	{ "NAND::device",	NULL },
614874af73SMarius Strobl 	{ "CFI::device",	NULL },
624874af73SMarius Strobl 	{ "SPI::device",	NULL },
634874af73SMarius Strobl 	{ "MMC::device",	NULL }
644874af73SMarius Strobl };
654874af73SMarius Strobl 
664874af73SMarius Strobl static g_taste_t g_flashmap_taste;
674874af73SMarius Strobl 
684874af73SMarius Strobl static int g_flashmap_load(device_t dev, struct g_provider *pp,
694874af73SMarius Strobl     flash_slicer_t slicer, struct g_flashmap_head *head);
7091a3f358SIan Lepore static int g_flashmap_modify(struct g_flashmap *gfp, struct g_geom *gp,
7191a3f358SIan Lepore     const char *devname, int secsize, struct g_flashmap_head *slices);
724874af73SMarius Strobl static void g_flashmap_print(struct g_flashmap_slice *slice);
734ffd4dfeSGrzegorz Bernacki 
744ffd4dfeSGrzegorz Bernacki MALLOC_DECLARE(M_FLASHMAP);
754ffd4dfeSGrzegorz Bernacki MALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class");
764ffd4dfeSGrzegorz Bernacki 
774ffd4dfeSGrzegorz Bernacki static void
784ffd4dfeSGrzegorz Bernacki g_flashmap_print(struct g_flashmap_slice *slice)
794ffd4dfeSGrzegorz Bernacki {
804ffd4dfeSGrzegorz Bernacki 
818287ee1bSXin LI 	printf("%08jx-%08jx: %s (%juKB)\n", (uintmax_t)slice->sl_start,
828287ee1bSXin LI 	    (uintmax_t)slice->sl_end, slice->sl_name,
838287ee1bSXin LI 	    (uintmax_t)(slice->sl_end - slice->sl_start) / 1024);
844ffd4dfeSGrzegorz Bernacki }
854ffd4dfeSGrzegorz Bernacki 
864ffd4dfeSGrzegorz Bernacki static int
8791a3f358SIan Lepore g_flashmap_modify(struct g_flashmap *gfp, struct g_geom *gp,
8891a3f358SIan Lepore     const char *devname, int secsize, struct g_flashmap_head *slices)
894ffd4dfeSGrzegorz Bernacki {
904ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_slice *slice;
914ffd4dfeSGrzegorz Bernacki 	int i, error;
924ffd4dfeSGrzegorz Bernacki 
934ffd4dfeSGrzegorz Bernacki 	g_topology_assert();
944ffd4dfeSGrzegorz Bernacki 
954ffd4dfeSGrzegorz Bernacki 	i = 0;
964ffd4dfeSGrzegorz Bernacki 	STAILQ_FOREACH(slice, slices, sl_link) {
974ffd4dfeSGrzegorz Bernacki 		if (bootverbose) {
984ffd4dfeSGrzegorz Bernacki 			printf("%s: slice ", devname);
994ffd4dfeSGrzegorz Bernacki 			g_flashmap_print(slice);
1004ffd4dfeSGrzegorz Bernacki 		}
1014ffd4dfeSGrzegorz Bernacki 
1024ffd4dfeSGrzegorz Bernacki 		error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK,
1034ffd4dfeSGrzegorz Bernacki 		    slice->sl_start,
1044ffd4dfeSGrzegorz Bernacki 		    slice->sl_end - slice->sl_start + 1,
1054874af73SMarius Strobl 		    secsize, FLASH_SLICES_FMT, gp->name, slice->sl_name);
1064ffd4dfeSGrzegorz Bernacki 
1074ffd4dfeSGrzegorz Bernacki 		if (error)
1084ffd4dfeSGrzegorz Bernacki 			return (error);
1094ffd4dfeSGrzegorz Bernacki 	}
1104ffd4dfeSGrzegorz Bernacki 
1114ffd4dfeSGrzegorz Bernacki 	i = 0;
1124ffd4dfeSGrzegorz Bernacki 	STAILQ_FOREACH(slice, slices, sl_link) {
11391a3f358SIan Lepore 		free(__DECONST(void *, gfp->labels[i]), M_FLASHMAP);
11491a3f358SIan Lepore 		gfp->labels[i] = strdup(slice->sl_name, M_FLASHMAP);
1154ffd4dfeSGrzegorz Bernacki 		error = g_slice_config(gp, i++, G_SLICE_CONFIG_SET,
1164ffd4dfeSGrzegorz Bernacki 		    slice->sl_start,
1174ffd4dfeSGrzegorz Bernacki 		    slice->sl_end - slice->sl_start + 1,
1184ffd4dfeSGrzegorz Bernacki 		    secsize, "%ss.%s", gp->name, slice->sl_name);
1194ffd4dfeSGrzegorz Bernacki 
1204ffd4dfeSGrzegorz Bernacki 		if (error)
1214ffd4dfeSGrzegorz Bernacki 			return (error);
1224ffd4dfeSGrzegorz Bernacki 	}
1234ffd4dfeSGrzegorz Bernacki 
1244ffd4dfeSGrzegorz Bernacki 	return (0);
1254ffd4dfeSGrzegorz Bernacki }
1264ffd4dfeSGrzegorz Bernacki 
1274ffd4dfeSGrzegorz Bernacki static struct g_geom *
1284ffd4dfeSGrzegorz Bernacki g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags)
1294ffd4dfeSGrzegorz Bernacki {
1304874af73SMarius Strobl 	struct g_geom *gp;
1314ffd4dfeSGrzegorz Bernacki 	struct g_consumer *cp;
1324ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_head head;
1334ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_slice *slice, *slice_temp;
13491a3f358SIan Lepore 	struct g_flashmap *gfp;
1354874af73SMarius Strobl 	flash_slicer_t slicer;
1364ffd4dfeSGrzegorz Bernacki 	device_t dev;
1374874af73SMarius Strobl 	int i, size;
1384ffd4dfeSGrzegorz Bernacki 
1394ffd4dfeSGrzegorz Bernacki 	g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name);
1404ffd4dfeSGrzegorz Bernacki 	g_topology_assert();
1414ffd4dfeSGrzegorz Bernacki 
1424ffd4dfeSGrzegorz Bernacki 	if (flags == G_TF_NORMAL &&
143b7b63db7SBrooks Davis 	    strcmp(pp->geom->class->name, G_DISK_CLASS_NAME) != 0)
1444ffd4dfeSGrzegorz Bernacki 		return (NULL);
1454ffd4dfeSGrzegorz Bernacki 
14691a3f358SIan Lepore 	gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, (void**)&gfp,
14791a3f358SIan Lepore 	    sizeof(struct g_flashmap), NULL);
1484ffd4dfeSGrzegorz Bernacki 	if (gp == NULL)
1494ffd4dfeSGrzegorz Bernacki 		return (NULL);
1504ffd4dfeSGrzegorz Bernacki 
1514ffd4dfeSGrzegorz Bernacki 	STAILQ_INIT(&head);
1524ffd4dfeSGrzegorz Bernacki 
1534ffd4dfeSGrzegorz Bernacki 	do {
1544874af73SMarius Strobl 		slicer = NULL;
1554874af73SMarius Strobl 		for (i = 0; i < nitems(g_flashmap_slicers); i++) {
1564ffd4dfeSGrzegorz Bernacki 			size = sizeof(device_t);
1574874af73SMarius Strobl 			if (g_io_getattr(g_flashmap_slicers[i].type, cp,
1584874af73SMarius Strobl 			    &size, &dev) == 0) {
1594874af73SMarius Strobl 				slicer = g_flashmap_slicers[i].slicer;
1604ffd4dfeSGrzegorz Bernacki 				break;
161444e7801SBrooks Davis 			}
16261789a9aSAdrian Chadd 		}
1634874af73SMarius Strobl 		if (slicer == NULL)
1644874af73SMarius Strobl 			break;
1654ffd4dfeSGrzegorz Bernacki 
1664874af73SMarius Strobl 		if (g_flashmap_load(dev, pp, slicer, &head) == 0)
1674ffd4dfeSGrzegorz Bernacki 			break;
1684ffd4dfeSGrzegorz Bernacki 
16991a3f358SIan Lepore 		g_flashmap_modify(gfp, gp, cp->provider->name,
1704ffd4dfeSGrzegorz Bernacki 		    cp->provider->sectorsize, &head);
1714ffd4dfeSGrzegorz Bernacki 	} while (0);
1724ffd4dfeSGrzegorz Bernacki 
1734ffd4dfeSGrzegorz Bernacki 	g_access(cp, -1, 0, 0);
1744ffd4dfeSGrzegorz Bernacki 
1754874af73SMarius Strobl 	STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp)
1764ffd4dfeSGrzegorz Bernacki 		free(slice, M_FLASHMAP);
1774ffd4dfeSGrzegorz Bernacki 
1784ffd4dfeSGrzegorz Bernacki 	if (LIST_EMPTY(&gp->provider)) {
1794ffd4dfeSGrzegorz Bernacki 		g_slice_spoiled(cp);
1804ffd4dfeSGrzegorz Bernacki 		return (NULL);
1814ffd4dfeSGrzegorz Bernacki 	}
1824ffd4dfeSGrzegorz Bernacki 	return (gp);
1834ffd4dfeSGrzegorz Bernacki }
1844ffd4dfeSGrzegorz Bernacki 
1854ffd4dfeSGrzegorz Bernacki static int
1864874af73SMarius Strobl g_flashmap_load(device_t dev, struct g_provider *pp, flash_slicer_t slicer,
1874874af73SMarius Strobl     struct g_flashmap_head *head)
1884ffd4dfeSGrzegorz Bernacki {
1894ffd4dfeSGrzegorz Bernacki 	struct flash_slice *slices;
1904ffd4dfeSGrzegorz Bernacki 	struct g_flashmap_slice *slice;
1914874af73SMarius Strobl 	int i, nslices = 0;
1924ffd4dfeSGrzegorz Bernacki 
1934874af73SMarius Strobl 	slices = malloc(sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM,
1944874af73SMarius Strobl 	    M_FLASHMAP, M_WAITOK | M_ZERO);
1954874af73SMarius Strobl 	if (slicer(dev, pp->name, slices, &nslices) == 0) {
1964ffd4dfeSGrzegorz Bernacki 		for (i = 0; i < nslices; i++) {
1974ffd4dfeSGrzegorz Bernacki 			slice = malloc(sizeof(struct g_flashmap_slice),
1984ffd4dfeSGrzegorz Bernacki 			    M_FLASHMAP, M_WAITOK);
1994ffd4dfeSGrzegorz Bernacki 
2004ffd4dfeSGrzegorz Bernacki 			slice->sl_name = slices[i].label;
2014ffd4dfeSGrzegorz Bernacki 			slice->sl_start = slices[i].base;
2024ffd4dfeSGrzegorz Bernacki 			slice->sl_end = slices[i].base + slices[i].size - 1;
2034ffd4dfeSGrzegorz Bernacki 
2044ffd4dfeSGrzegorz Bernacki 			STAILQ_INSERT_TAIL(head, slice, sl_link);
2054ffd4dfeSGrzegorz Bernacki 		}
2064ffd4dfeSGrzegorz Bernacki 	}
2074ffd4dfeSGrzegorz Bernacki 
2084ffd4dfeSGrzegorz Bernacki 	free(slices, M_FLASHMAP);
2094ffd4dfeSGrzegorz Bernacki 	return (nslices);
2104ffd4dfeSGrzegorz Bernacki }
2114ffd4dfeSGrzegorz Bernacki 
2124874af73SMarius Strobl void flash_register_slicer(flash_slicer_t slicer, u_int type, bool force)
2136aabc119SJustin Hibbits {
2146aabc119SJustin Hibbits 
2154874af73SMarius Strobl 	g_topology_lock();
2164874af73SMarius Strobl 	if (g_flashmap_slicers[type].slicer == NULL || force == TRUE)
2174874af73SMarius Strobl 		g_flashmap_slicers[type].slicer = slicer;
2184874af73SMarius Strobl 	g_topology_unlock();
2196aabc119SJustin Hibbits }
2206aabc119SJustin Hibbits 
2214ffd4dfeSGrzegorz Bernacki static struct g_class g_flashmap_class = {
2224ffd4dfeSGrzegorz Bernacki 	.name = FLASHMAP_CLASS_NAME,
2234ffd4dfeSGrzegorz Bernacki 	.version = G_VERSION,
2244ffd4dfeSGrzegorz Bernacki 	.taste = g_flashmap_taste,
2254ffd4dfeSGrzegorz Bernacki };
2264ffd4dfeSGrzegorz Bernacki 
2274ffd4dfeSGrzegorz Bernacki DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap);
2284874af73SMarius Strobl MODULE_VERSION(g_flashmap, 0);
229