1235778Sgber/*-
2235778Sgber * Copyright (c) 2012 Semihalf
3235778Sgber * Copyright (c) 2009 Jakub Klama <jakub.klama@uj.edu.pl>
4235778Sgber * All rights reserved.
5235778Sgber *
6235778Sgber * Redistribution and use in source and binary forms, with or without
7235778Sgber * modification, are permitted provided that the following conditions
8235778Sgber * are met:
9235778Sgber * 1. Redistributions of source code must retain the above copyright
10235778Sgber *    notice, this list of conditions and the following disclaimer.
11235778Sgber * 2. Redistributions in binary form must reproduce the above copyright
12235778Sgber *    notice, this list of conditions and the following disclaimer in the
13235778Sgber *    documentation and/or other materials provided with the distribution.
14235778Sgber *
15235778Sgber * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16235778Sgber * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17235778Sgber * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18235778Sgber * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19235778Sgber * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20235778Sgber * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21235778Sgber * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22235778Sgber * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23235778Sgber * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24235778Sgber * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25235778Sgber * SUCH DAMAGE.
26235778Sgber */
27235778Sgber
28235778Sgber#include <sys/cdefs.h>
29235778Sgber__FBSDID("$FreeBSD: releng/10.3/sys/geom/geom_flashmap.c 251117 2013-05-30 01:19:02Z brooks $");
30235778Sgber
31235778Sgber#include <sys/param.h>
32235778Sgber#include <sys/endian.h>
33235778Sgber#include <sys/systm.h>
34235778Sgber#include <sys/kernel.h>
35235778Sgber#include <sys/fcntl.h>
36235778Sgber#include <sys/malloc.h>
37235778Sgber#include <sys/bio.h>
38235778Sgber#include <sys/bus.h>
39235778Sgber#include <sys/lock.h>
40235778Sgber#include <sys/mutex.h>
41235778Sgber#include <sys/slicer.h>
42235778Sgber
43235778Sgber#include <geom/geom.h>
44235778Sgber#include <geom/geom_slice.h>
45235778Sgber#include <geom/geom_disk.h>
46235778Sgber#include <dev/nand/nand_dev.h>
47235778Sgber
48235778Sgber#define FLASHMAP_CLASS_NAME "Flashmap"
49235778Sgber
50235778Sgberstruct g_flashmap_slice {
51235778Sgber	off_t		sl_start;
52235778Sgber	off_t		sl_end;
53235778Sgber	const char	*sl_name;
54235778Sgber
55235778Sgber	STAILQ_ENTRY(g_flashmap_slice) sl_link;
56235778Sgber};
57235778Sgber
58235778SgberSTAILQ_HEAD(g_flashmap_head, g_flashmap_slice);
59235778Sgber
60235778Sgberstatic void g_flashmap_print(struct g_flashmap_slice *);
61235778Sgberstatic int g_flashmap_modify(struct g_geom *, const char *,
62235778Sgber    int, struct g_flashmap_head *);
63235778Sgberstatic int g_flashmap_start(struct bio *);
64235778Sgberstatic int g_flashmap_ioctl(struct g_provider *, u_long, void *,
65235778Sgber    int, struct thread *);
66235778Sgberstatic void g_flashmap_dumpconf(struct sbuf *, const char *,
67235778Sgber    struct g_geom *, struct g_consumer *, struct g_provider *);
68235778Sgberstatic struct g_geom *g_flashmap_taste(struct g_class *,
69235778Sgber    struct g_provider *, int);
70235778Sgberstatic void g_flashmap_config(struct gctl_req *, struct g_class *,
71235778Sgber    const char *);
72235778Sgberstatic int g_flashmap_load(device_t, struct g_flashmap_head *);
73235778Sgber
74235778SgberMALLOC_DECLARE(M_FLASHMAP);
75235778SgberMALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class");
76235778Sgber
77235778Sgberstatic void
78235778Sgberg_flashmap_print(struct g_flashmap_slice *slice)
79235778Sgber{
80235778Sgber
81235858Sdelphij	printf("%08jx-%08jx: %s (%juKB)\n", (uintmax_t)slice->sl_start,
82235858Sdelphij	    (uintmax_t)slice->sl_end, slice->sl_name,
83235858Sdelphij	    (uintmax_t)(slice->sl_end - slice->sl_start) / 1024);
84235778Sgber}
85235778Sgber
86235778Sgberstatic int
87235778Sgberg_flashmap_modify(struct g_geom *gp, const char *devname, int secsize,
88235778Sgber    struct g_flashmap_head *slices)
89235778Sgber{
90235778Sgber	struct g_flashmap_slice *slice;
91235778Sgber	int i, error;
92235778Sgber
93235778Sgber	g_topology_assert();
94235778Sgber
95235778Sgber	i = 0;
96235778Sgber	STAILQ_FOREACH(slice, slices, sl_link) {
97235778Sgber		if (bootverbose) {
98235778Sgber			printf("%s: slice ", devname);
99235778Sgber			g_flashmap_print(slice);
100235778Sgber		}
101235778Sgber
102235778Sgber		error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK,
103235778Sgber		    slice->sl_start,
104235778Sgber		    slice->sl_end - slice->sl_start + 1,
105235778Sgber		    secsize, "%ss.%s", gp->name, slice->sl_name);
106235778Sgber
107235778Sgber		if (error)
108235778Sgber			return (error);
109235778Sgber	}
110235778Sgber
111235778Sgber	i = 0;
112235778Sgber	STAILQ_FOREACH(slice, slices, sl_link) {
113235778Sgber		error = g_slice_config(gp, i++, G_SLICE_CONFIG_SET,
114235778Sgber		    slice->sl_start,
115235778Sgber		    slice->sl_end - slice->sl_start + 1,
116235778Sgber		    secsize, "%ss.%s", gp->name, slice->sl_name);
117235778Sgber
118235778Sgber		if (error)
119235778Sgber			return (error);
120235778Sgber	}
121235778Sgber
122235778Sgber	return (0);
123235778Sgber}
124235778Sgber
125235778Sgberstatic int
126235778Sgberg_flashmap_start(struct bio *bp)
127235778Sgber{
128235778Sgber
129235778Sgber	return (0);
130235778Sgber}
131235778Sgber
132235778Sgberstatic void
133235778Sgberg_flashmap_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp,
134235778Sgber    struct g_consumer *cp __unused, struct g_provider *pp)
135235778Sgber{
136235778Sgber	struct g_slicer *gsp;
137235778Sgber
138235778Sgber	gsp = gp->softc;
139235778Sgber	g_slice_dumpconf(sb, indent, gp, cp, pp);
140235778Sgber}
141235778Sgber
142235778Sgberstatic int
143235778Sgberg_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag,
144235778Sgber    struct thread *td)
145235778Sgber{
146235778Sgber	struct g_consumer *cp;
147235778Sgber	struct g_geom *gp;
148235778Sgber
149235778Sgber	if (cmd != NAND_IO_GET_CHIP_PARAM)
150235778Sgber		return (ENOIOCTL);
151235778Sgber
152235778Sgber	cp = LIST_FIRST(&pp->geom->consumer);
153235778Sgber	if (cp == NULL)
154235778Sgber		return (ENOIOCTL);
155235778Sgber	gp = cp->provider->geom;
156235778Sgber	if (gp->ioctl == NULL)
157235778Sgber		return (ENOIOCTL);
158235778Sgber
159235778Sgber	return (gp->ioctl(cp->provider, cmd, data, fflag, td));
160235778Sgber}
161235778Sgber
162235778Sgber
163235778Sgberstatic struct g_geom *
164235778Sgberg_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags)
165235778Sgber{
166235778Sgber	struct g_geom *gp = NULL;
167235778Sgber	struct g_consumer *cp;
168235778Sgber	struct g_flashmap_head head;
169235778Sgber	struct g_flashmap_slice *slice, *slice_temp;
170235778Sgber	device_t dev;
171235778Sgber	int nslices, size;
172235778Sgber
173235778Sgber	g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name);
174235778Sgber	g_topology_assert();
175235778Sgber
176235778Sgber	if (flags == G_TF_NORMAL &&
177249556Sbrooks	    strcmp(pp->geom->class->name, G_DISK_CLASS_NAME) != 0)
178235778Sgber		return (NULL);
179235778Sgber
180235778Sgber	gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, NULL, 0,
181235778Sgber	    g_flashmap_start);
182235778Sgber	if (gp == NULL)
183235778Sgber		return (NULL);
184235778Sgber
185235778Sgber	STAILQ_INIT(&head);
186235778Sgber
187235778Sgber	do {
188235778Sgber		size = sizeof(device_t);
189251117Sbrooks		if (g_io_getattr("NAND::device", cp, &size, &dev)) {
190251117Sbrooks			size = sizeof(device_t);
191251117Sbrooks			if (g_io_getattr("CFI::device", cp, &size, &dev))
192251117Sbrooks				break;
193251117Sbrooks		}
194235778Sgber
195235778Sgber		nslices = g_flashmap_load(dev, &head);
196235778Sgber		if (nslices == 0)
197235778Sgber			break;
198235778Sgber
199235778Sgber		g_flashmap_modify(gp, cp->provider->name,
200235778Sgber		    cp->provider->sectorsize, &head);
201235778Sgber	} while (0);
202235778Sgber
203235778Sgber	g_access(cp, -1, 0, 0);
204235778Sgber
205235778Sgber	STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp) {
206235778Sgber		free(slice, M_FLASHMAP);
207235778Sgber	}
208235778Sgber
209235778Sgber	if (LIST_EMPTY(&gp->provider)) {
210235778Sgber		g_slice_spoiled(cp);
211235778Sgber		return (NULL);
212235778Sgber	}
213235778Sgber	return (gp);
214235778Sgber}
215235778Sgber
216235778Sgberstatic void
217235778Sgberg_flashmap_config(struct gctl_req *req, struct g_class *mp, const char *verb)
218235778Sgber{
219235778Sgber
220235778Sgber	gctl_error(req, "unknown config verb");
221235778Sgber}
222235778Sgber
223235778Sgberstatic int
224235778Sgberg_flashmap_load(device_t dev, struct g_flashmap_head *head)
225235778Sgber{
226235778Sgber	struct flash_slice *slices;
227235778Sgber	struct g_flashmap_slice *slice;
228235778Sgber	uint32_t i, buf_size;
229235778Sgber	int nslices = 0;
230235778Sgber
231235778Sgber	buf_size = sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM;
232235778Sgber	slices = malloc(buf_size, M_FLASHMAP, M_WAITOK | M_ZERO);
233235778Sgber	if (flash_fill_slices(dev, slices, &nslices) == 0) {
234235778Sgber		for (i = 0; i < nslices; i++) {
235235778Sgber			slice = malloc(sizeof(struct g_flashmap_slice),
236235778Sgber			    M_FLASHMAP, M_WAITOK);
237235778Sgber
238235778Sgber			slice->sl_name = slices[i].label;
239235778Sgber			slice->sl_start = slices[i].base;
240235778Sgber			slice->sl_end = slices[i].base + slices[i].size - 1;
241235778Sgber
242235778Sgber			STAILQ_INSERT_TAIL(head, slice, sl_link);
243235778Sgber		}
244235778Sgber	}
245235778Sgber
246235778Sgber	free(slices, M_FLASHMAP);
247235778Sgber	return (nslices);
248235778Sgber}
249235778Sgber
250235778Sgberstatic struct g_class g_flashmap_class = {
251235778Sgber	.name = FLASHMAP_CLASS_NAME,
252235778Sgber	.version = G_VERSION,
253235778Sgber	.taste = g_flashmap_taste,
254235778Sgber	.dumpconf = g_flashmap_dumpconf,
255235778Sgber	.ioctl = g_flashmap_ioctl,
256235778Sgber	.ctlreq = g_flashmap_config,
257235778Sgber};
258235778Sgber
259235778SgberDECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap);
260