geom_flashmap.c revision 235858
1163953Srrs/*-
2163953Srrs * Copyright (c) 2012 Semihalf
3163953Srrs * Copyright (c) 2009 Jakub Klama <jakub.klama@uj.edu.pl>
4163953Srrs * All rights reserved.
5163953Srrs *
6163953Srrs * Redistribution and use in source and binary forms, with or without
7163953Srrs * modification, are permitted provided that the following conditions
8163953Srrs * are met:
9163953Srrs * 1. Redistributions of source code must retain the above copyright
10163953Srrs *    notice, this list of conditions and the following disclaimer.
11163953Srrs * 2. Redistributions in binary form must reproduce the above copyright
12163953Srrs *    notice, this list of conditions and the following disclaimer in the
13163953Srrs *    documentation and/or other materials provided with the distribution.
14163953Srrs *
15163953Srrs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18163953Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25163953Srrs * SUCH DAMAGE.
26163953Srrs */
27163953Srrs
28163953Srrs#include <sys/cdefs.h>
29163953Srrs__FBSDID("$FreeBSD: head/sys/geom/geom_flashmap.c 235858 2012-05-23 20:51:21Z delphij $");
30163954Srrs
31163953Srrs#include <sys/param.h>
32163953Srrs#include <sys/endian.h>
33163953Srrs#include <sys/systm.h>
34163953Srrs#include <sys/kernel.h>
35163953Srrs#include <sys/fcntl.h>
36163953Srrs#include <sys/malloc.h>
37163953Srrs#include <sys/bio.h>
38163953Srrs#include <sys/bus.h>
39163953Srrs#include <sys/lock.h>
40163953Srrs#include <sys/mutex.h>
41163953Srrs#include <sys/slicer.h>
42163953Srrs
43163953Srrs#include <geom/geom.h>
44163953Srrs#include <geom/geom_slice.h>
45163953Srrs#include <geom/geom_disk.h>
46163953Srrs#include <dev/nand/nand_dev.h>
47163953Srrs
48163953Srrs#define FLASHMAP_CLASS_NAME "Flashmap"
49163953Srrs
50163953Srrsstruct g_flashmap_slice {
51163953Srrs	off_t		sl_start;
52163953Srrs	off_t		sl_end;
53163953Srrs	const char	*sl_name;
54163953Srrs
55163953Srrs	STAILQ_ENTRY(g_flashmap_slice) sl_link;
56163953Srrs};
57163953Srrs
58163953SrrsSTAILQ_HEAD(g_flashmap_head, g_flashmap_slice);
59163953Srrs
60163953Srrsstatic void g_flashmap_print(struct g_flashmap_slice *);
61163953Srrsstatic int g_flashmap_modify(struct g_geom *, const char *,
62163953Srrs    int, struct g_flashmap_head *);
63163953Srrsstatic int g_flashmap_start(struct bio *);
64163953Srrsstatic int g_flashmap_ioctl(struct g_provider *, u_long, void *,
65163953Srrs    int, struct thread *);
66163953Srrsstatic void g_flashmap_dumpconf(struct sbuf *, const char *,
67163953Srrs    struct g_geom *, struct g_consumer *, struct g_provider *);
68163953Srrsstatic struct g_geom *g_flashmap_taste(struct g_class *,
69163953Srrs    struct g_provider *, int);
70163953Srrsstatic void g_flashmap_config(struct gctl_req *, struct g_class *,
71163953Srrs    const char *);
72163953Srrsstatic int g_flashmap_load(device_t, struct g_flashmap_head *);
73163953Srrs
74163953SrrsMALLOC_DECLARE(M_FLASHMAP);
75163953SrrsMALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class");
76163953Srrs
77163953Srrsstatic void
78163953Srrsg_flashmap_print(struct g_flashmap_slice *slice)
79163953Srrs{
80163953Srrs
81163953Srrs	printf("%08jx-%08jx: %s (%juKB)\n", (uintmax_t)slice->sl_start,
82163953Srrs	    (uintmax_t)slice->sl_end, slice->sl_name,
83163953Srrs	    (uintmax_t)(slice->sl_end - slice->sl_start) / 1024);
84163953Srrs}
85163953Srrs
86163953Srrsstatic int
87163953Srrsg_flashmap_modify(struct g_geom *gp, const char *devname, int secsize,
88163953Srrs    struct g_flashmap_head *slices)
89163953Srrs{
90163953Srrs	struct g_flashmap_slice *slice;
91	int i, error;
92
93	g_topology_assert();
94
95	i = 0;
96	STAILQ_FOREACH(slice, slices, sl_link) {
97		if (bootverbose) {
98			printf("%s: slice ", devname);
99			g_flashmap_print(slice);
100		}
101
102		error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK,
103		    slice->sl_start,
104		    slice->sl_end - slice->sl_start + 1,
105		    secsize, "%ss.%s", gp->name, slice->sl_name);
106
107		if (error)
108			return (error);
109	}
110
111	i = 0;
112	STAILQ_FOREACH(slice, slices, sl_link) {
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
125static int
126g_flashmap_start(struct bio *bp)
127{
128
129	return (0);
130}
131
132static void
133g_flashmap_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
134    struct g_consumer *cp __unused, struct g_provider *pp)
135{
136	struct g_slicer *gsp;
137
138	gsp = gp->softc;
139	g_slice_dumpconf(sb, indent, gp, cp, pp);
140}
141
142static int
143g_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag,
144    struct thread *td)
145{
146	struct g_consumer *cp;
147	struct g_geom *gp;
148
149	if (cmd != NAND_IO_GET_CHIP_PARAM)
150		return (ENOIOCTL);
151
152	cp = LIST_FIRST(&pp->geom->consumer);
153	if (cp == NULL)
154		return (ENOIOCTL);
155	gp = cp->provider->geom;
156	if (gp->ioctl == NULL)
157		return (ENOIOCTL);
158
159	return (gp->ioctl(cp->provider, cmd, data, fflag, td));
160}
161
162
163static struct g_geom *
164g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags)
165{
166	struct g_geom *gp = NULL;
167	struct g_consumer *cp;
168	struct g_flashmap_head head;
169	struct g_flashmap_slice *slice, *slice_temp;
170	device_t dev;
171	int nslices, size;
172
173	g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name);
174	g_topology_assert();
175
176	if (flags == G_TF_NORMAL &&
177	    !strcmp(pp->geom->class->name, FLASHMAP_CLASS_NAME))
178		return (NULL);
179
180	gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, NULL, 0,
181	    g_flashmap_start);
182	if (gp == NULL)
183		return (NULL);
184
185	STAILQ_INIT(&head);
186
187	do {
188		size = sizeof(device_t);
189		if (g_io_getattr("NAND::device", cp, &size, &dev))
190			break;
191
192		nslices = g_flashmap_load(dev, &head);
193		if (nslices == 0)
194			break;
195
196		g_flashmap_modify(gp, cp->provider->name,
197		    cp->provider->sectorsize, &head);
198	} while (0);
199
200	g_access(cp, -1, 0, 0);
201
202	STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp) {
203		free(slice, M_FLASHMAP);
204	}
205
206	if (LIST_EMPTY(&gp->provider)) {
207		g_slice_spoiled(cp);
208		return (NULL);
209	}
210	return (gp);
211}
212
213static void
214g_flashmap_config(struct gctl_req *req, struct g_class *mp, const char *verb)
215{
216
217	gctl_error(req, "unknown config verb");
218}
219
220static int
221g_flashmap_load(device_t dev, struct g_flashmap_head *head)
222{
223	struct flash_slice *slices;
224	struct g_flashmap_slice *slice;
225	uint32_t i, buf_size;
226	int nslices = 0;
227
228	buf_size = sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM;
229	slices = malloc(buf_size, M_FLASHMAP, M_WAITOK | M_ZERO);
230	if (flash_fill_slices(dev, slices, &nslices) == 0) {
231		for (i = 0; i < nslices; i++) {
232			slice = malloc(sizeof(struct g_flashmap_slice),
233			    M_FLASHMAP, M_WAITOK);
234
235			slice->sl_name = slices[i].label;
236			slice->sl_start = slices[i].base;
237			slice->sl_end = slices[i].base + slices[i].size - 1;
238
239			STAILQ_INSERT_TAIL(head, slice, sl_link);
240		}
241	}
242
243	free(slices, M_FLASHMAP);
244	return (nslices);
245}
246
247static struct g_class g_flashmap_class = {
248	.name = FLASHMAP_CLASS_NAME,
249	.version = G_VERSION,
250	.taste = g_flashmap_taste,
251	.dumpconf = g_flashmap_dumpconf,
252	.ioctl = g_flashmap_ioctl,
253	.ctlreq = g_flashmap_config,
254};
255
256DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap);
257