geom_flashmap.c revision 235778
1231200Smm/*-
2232153Smm * Copyright (c) 2012 Semihalf
3231200Smm * Copyright (c) 2009 Jakub Klama <jakub.klama@uj.edu.pl>
4231200Smm * All rights reserved.
5231200Smm *
6231200Smm * Redistribution and use in source and binary forms, with or without
7231200Smm * modification, are permitted provided that the following conditions
8231200Smm * are met:
9231200Smm * 1. Redistributions of source code must retain the above copyright
10231200Smm *    notice, this list of conditions and the following disclaimer.
11231200Smm * 2. Redistributions in binary form must reproduce the above copyright
12231200Smm *    notice, this list of conditions and the following disclaimer in the
13231200Smm *    documentation and/or other materials provided with the distribution.
14231200Smm *
15231200Smm * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16231200Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17231200Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18231200Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19231200Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20231200Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21231200Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22231200Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23231200Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24231200Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25231200Smm * SUCH DAMAGE.
26231200Smm */
27231200Smm
28231200Smm#include <sys/cdefs.h>
29231200Smm__FBSDID("$FreeBSD: head/sys/geom/geom_flashmap.c 235778 2012-05-22 08:33:14Z gber $");
30231200Smm
31231200Smm#include <sys/param.h>
32231200Smm#include <sys/endian.h>
33231200Smm#include <sys/systm.h>
34231200Smm#include <sys/kernel.h>
35231200Smm#include <sys/fcntl.h>
36231200Smm#include <sys/malloc.h>
37231200Smm#include <sys/bio.h>
38231200Smm#include <sys/bus.h>
39231200Smm#include <sys/lock.h>
40231200Smm#include <sys/mutex.h>
41231200Smm#include <sys/slicer.h>
42231200Smm
43231200Smm#include <geom/geom.h>
44231200Smm#include <geom/geom_slice.h>
45231200Smm#include <geom/geom_disk.h>
46231200Smm#include <dev/nand/nand_dev.h>
47231200Smm
48231200Smm#define FLASHMAP_CLASS_NAME "Flashmap"
49231200Smm
50231200Smmstruct g_flashmap_slice {
51231200Smm	off_t		sl_start;
52231200Smm	off_t		sl_end;
53231200Smm	const char	*sl_name;
54231200Smm
55231200Smm	STAILQ_ENTRY(g_flashmap_slice) sl_link;
56231200Smm};
57231200Smm
58231200SmmSTAILQ_HEAD(g_flashmap_head, g_flashmap_slice);
59231200Smm
60231200Smmstatic void g_flashmap_print(struct g_flashmap_slice *);
61231200Smmstatic int g_flashmap_modify(struct g_geom *, const char *,
62231200Smm    int, struct g_flashmap_head *);
63231200Smmstatic int g_flashmap_start(struct bio *);
64231200Smmstatic int g_flashmap_ioctl(struct g_provider *, u_long, void *,
65231200Smm    int, struct thread *);
66231200Smmstatic void g_flashmap_dumpconf(struct sbuf *, const char *,
67231200Smm    struct g_geom *, struct g_consumer *, struct g_provider *);
68231200Smmstatic struct g_geom *g_flashmap_taste(struct g_class *,
69231200Smm    struct g_provider *, int);
70231200Smmstatic void g_flashmap_config(struct gctl_req *, struct g_class *,
71231200Smm    const char *);
72231200Smmstatic int g_flashmap_load(device_t, struct g_flashmap_head *);
73231200Smm
74231200SmmMALLOC_DECLARE(M_FLASHMAP);
75231200SmmMALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class");
76231200Smm
77231200Smmstatic void
78231200Smmg_flashmap_print(struct g_flashmap_slice *slice)
79231200Smm{
80231200Smm
81231200Smm	printf("%08llx-%08llx: %s (%lluKB)\n", slice->sl_start, slice->sl_end,
82231200Smm	    slice->sl_name, (slice->sl_end - slice->sl_start) / 1024);
83231200Smm}
84231200Smm
85231200Smmstatic int
86231200Smmg_flashmap_modify(struct g_geom *gp, const char *devname, int secsize,
87231200Smm    struct g_flashmap_head *slices)
88231200Smm{
89231200Smm	struct g_flashmap_slice *slice;
90231200Smm	int i, error;
91231200Smm
92231200Smm	g_topology_assert();
93231200Smm
94231200Smm	i = 0;
95231200Smm	STAILQ_FOREACH(slice, slices, sl_link) {
96231200Smm		if (bootverbose) {
97231200Smm			printf("%s: slice ", devname);
98231200Smm			g_flashmap_print(slice);
99231200Smm		}
100232153Smm
101232153Smm		error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK,
102231200Smm		    slice->sl_start,
103231200Smm		    slice->sl_end - slice->sl_start + 1,
104231200Smm		    secsize, "%ss.%s", gp->name, slice->sl_name);
105231200Smm
106231200Smm		if (error)
107231200Smm			return (error);
108231200Smm	}
109231200Smm
110231200Smm	i = 0;
111231200Smm	STAILQ_FOREACH(slice, slices, sl_link) {
112231200Smm		error = g_slice_config(gp, i++, G_SLICE_CONFIG_SET,
113231200Smm		    slice->sl_start,
114231200Smm		    slice->sl_end - slice->sl_start + 1,
115231200Smm		    secsize, "%ss.%s", gp->name, slice->sl_name);
116231200Smm
117231200Smm		if (error)
118231200Smm			return (error);
119231200Smm	}
120231200Smm
121231200Smm	return (0);
122231200Smm}
123231200Smm
124231200Smmstatic int
125231200Smmg_flashmap_start(struct bio *bp)
126231200Smm{
127231200Smm
128231200Smm	return (0);
129231200Smm}
130231200Smm
131231200Smmstatic void
132231200Smmg_flashmap_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
133231200Smm    struct g_consumer *cp __unused, struct g_provider *pp)
134231200Smm{
135231200Smm	struct g_slicer *gsp;
136231200Smm
137231200Smm	gsp = gp->softc;
138231200Smm	g_slice_dumpconf(sb, indent, gp, cp, pp);
139231200Smm}
140231200Smm
141231200Smmstatic int
142231200Smmg_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag,
143231200Smm    struct thread *td)
144231200Smm{
145231200Smm	struct g_consumer *cp;
146231200Smm	struct g_geom *gp;
147231200Smm
148231200Smm	if (cmd != NAND_IO_GET_CHIP_PARAM)
149231200Smm		return (ENOIOCTL);
150231200Smm
151231200Smm	cp = LIST_FIRST(&pp->geom->consumer);
152231200Smm	if (cp == NULL)
153231200Smm		return (ENOIOCTL);
154231200Smm	gp = cp->provider->geom;
155231200Smm	if (gp->ioctl == NULL)
156231200Smm		return (ENOIOCTL);
157231200Smm
158231200Smm	return (gp->ioctl(cp->provider, cmd, data, fflag, td));
159231200Smm}
160231200Smm
161231200Smm
162231200Smmstatic struct g_geom *
163231200Smmg_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags)
164231200Smm{
165231200Smm	struct g_geom *gp = NULL;
166231200Smm	struct g_consumer *cp;
167231200Smm	struct g_flashmap_head head;
168231200Smm	struct g_flashmap_slice *slice, *slice_temp;
169231200Smm	device_t dev;
170231200Smm	int nslices, size;
171231200Smm
172231200Smm	g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name);
173231200Smm	g_topology_assert();
174231200Smm
175231200Smm	if (flags == G_TF_NORMAL &&
176231200Smm	    !strcmp(pp->geom->class->name, FLASHMAP_CLASS_NAME))
177231200Smm		return (NULL);
178231200Smm
179231200Smm	gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, NULL, 0,
180231200Smm	    g_flashmap_start);
181231200Smm	if (gp == NULL)
182231200Smm		return (NULL);
183231200Smm
184231200Smm	STAILQ_INIT(&head);
185231200Smm
186231200Smm	do {
187231200Smm		size = sizeof(device_t);
188231200Smm		if (g_io_getattr("NAND::device", cp, &size, &dev))
189231200Smm			break;
190231200Smm
191231200Smm		nslices = g_flashmap_load(dev, &head);
192231200Smm		if (nslices == 0)
193231200Smm			break;
194231200Smm
195231200Smm		g_flashmap_modify(gp, cp->provider->name,
196231200Smm		    cp->provider->sectorsize, &head);
197231200Smm	} while (0);
198231200Smm
199231200Smm	g_access(cp, -1, 0, 0);
200231200Smm
201231200Smm	STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp) {
202231200Smm		free(slice, M_FLASHMAP);
203231200Smm	}
204231200Smm
205231200Smm	if (LIST_EMPTY(&gp->provider)) {
206231200Smm		g_slice_spoiled(cp);
207231200Smm		return (NULL);
208231200Smm	}
209231200Smm	return (gp);
210231200Smm}
211231200Smm
212231200Smmstatic void
213231200Smmg_flashmap_config(struct gctl_req *req, struct g_class *mp, const char *verb)
214231200Smm{
215231200Smm
216231200Smm	gctl_error(req, "unknown config verb");
217231200Smm}
218231200Smm
219231200Smmstatic int
220231200Smmg_flashmap_load(device_t dev, struct g_flashmap_head *head)
221231200Smm{
222231200Smm	struct flash_slice *slices;
223231200Smm	struct g_flashmap_slice *slice;
224231200Smm	uint32_t i, buf_size;
225231200Smm	int nslices = 0;
226231200Smm
227231200Smm	buf_size = sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM;
228231200Smm	slices = malloc(buf_size, M_FLASHMAP, M_WAITOK | M_ZERO);
229231200Smm	if (flash_fill_slices(dev, slices, &nslices) == 0) {
230231200Smm		for (i = 0; i < nslices; i++) {
231231200Smm			slice = malloc(sizeof(struct g_flashmap_slice),
232231200Smm			    M_FLASHMAP, M_WAITOK);
233231200Smm
234231200Smm			slice->sl_name = slices[i].label;
235231200Smm			slice->sl_start = slices[i].base;
236231200Smm			slice->sl_end = slices[i].base + slices[i].size - 1;
237231200Smm
238231200Smm			STAILQ_INSERT_TAIL(head, slice, sl_link);
239231200Smm		}
240231200Smm	}
241231200Smm
242231200Smm	free(slices, M_FLASHMAP);
243231200Smm	return (nslices);
244231200Smm}
245231200Smm
246231200Smmstatic struct g_class g_flashmap_class = {
247231200Smm	.name = FLASHMAP_CLASS_NAME,
248231200Smm	.version = G_VERSION,
249231200Smm	.taste = g_flashmap_taste,
250231200Smm	.dumpconf = g_flashmap_dumpconf,
251231200Smm	.ioctl = g_flashmap_ioctl,
252231200Smm	.ctlreq = g_flashmap_config,
253231200Smm};
254231200Smm
255231200SmmDECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap);
256231200Smm