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