1*4ffd4dfeSGrzegorz Bernacki /*- 2*4ffd4dfeSGrzegorz Bernacki * Copyright (c) 2012 Semihalf 3*4ffd4dfeSGrzegorz Bernacki * Copyright (c) 2009 Jakub Klama <jakub.klama@uj.edu.pl> 4*4ffd4dfeSGrzegorz Bernacki * All rights reserved. 5*4ffd4dfeSGrzegorz Bernacki * 6*4ffd4dfeSGrzegorz Bernacki * Redistribution and use in source and binary forms, with or without 7*4ffd4dfeSGrzegorz Bernacki * modification, are permitted provided that the following conditions 8*4ffd4dfeSGrzegorz Bernacki * are met: 9*4ffd4dfeSGrzegorz Bernacki * 1. Redistributions of source code must retain the above copyright 10*4ffd4dfeSGrzegorz Bernacki * notice, this list of conditions and the following disclaimer. 11*4ffd4dfeSGrzegorz Bernacki * 2. Redistributions in binary form must reproduce the above copyright 12*4ffd4dfeSGrzegorz Bernacki * notice, this list of conditions and the following disclaimer in the 13*4ffd4dfeSGrzegorz Bernacki * documentation and/or other materials provided with the distribution. 14*4ffd4dfeSGrzegorz Bernacki * 15*4ffd4dfeSGrzegorz Bernacki * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16*4ffd4dfeSGrzegorz Bernacki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17*4ffd4dfeSGrzegorz Bernacki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18*4ffd4dfeSGrzegorz Bernacki * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19*4ffd4dfeSGrzegorz Bernacki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20*4ffd4dfeSGrzegorz Bernacki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21*4ffd4dfeSGrzegorz Bernacki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22*4ffd4dfeSGrzegorz Bernacki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23*4ffd4dfeSGrzegorz Bernacki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24*4ffd4dfeSGrzegorz Bernacki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25*4ffd4dfeSGrzegorz Bernacki * SUCH DAMAGE. 26*4ffd4dfeSGrzegorz Bernacki */ 27*4ffd4dfeSGrzegorz Bernacki 28*4ffd4dfeSGrzegorz Bernacki #include <sys/cdefs.h> 29*4ffd4dfeSGrzegorz Bernacki __FBSDID("$FreeBSD$"); 30*4ffd4dfeSGrzegorz Bernacki 31*4ffd4dfeSGrzegorz Bernacki #include <sys/param.h> 32*4ffd4dfeSGrzegorz Bernacki #include <sys/endian.h> 33*4ffd4dfeSGrzegorz Bernacki #include <sys/systm.h> 34*4ffd4dfeSGrzegorz Bernacki #include <sys/kernel.h> 35*4ffd4dfeSGrzegorz Bernacki #include <sys/fcntl.h> 36*4ffd4dfeSGrzegorz Bernacki #include <sys/malloc.h> 37*4ffd4dfeSGrzegorz Bernacki #include <sys/bio.h> 38*4ffd4dfeSGrzegorz Bernacki #include <sys/bus.h> 39*4ffd4dfeSGrzegorz Bernacki #include <sys/lock.h> 40*4ffd4dfeSGrzegorz Bernacki #include <sys/mutex.h> 41*4ffd4dfeSGrzegorz Bernacki #include <sys/slicer.h> 42*4ffd4dfeSGrzegorz Bernacki 43*4ffd4dfeSGrzegorz Bernacki #include <geom/geom.h> 44*4ffd4dfeSGrzegorz Bernacki #include <geom/geom_slice.h> 45*4ffd4dfeSGrzegorz Bernacki #include <geom/geom_disk.h> 46*4ffd4dfeSGrzegorz Bernacki #include <dev/nand/nand_dev.h> 47*4ffd4dfeSGrzegorz Bernacki 48*4ffd4dfeSGrzegorz Bernacki #define FLASHMAP_CLASS_NAME "Flashmap" 49*4ffd4dfeSGrzegorz Bernacki 50*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_slice { 51*4ffd4dfeSGrzegorz Bernacki off_t sl_start; 52*4ffd4dfeSGrzegorz Bernacki off_t sl_end; 53*4ffd4dfeSGrzegorz Bernacki const char *sl_name; 54*4ffd4dfeSGrzegorz Bernacki 55*4ffd4dfeSGrzegorz Bernacki STAILQ_ENTRY(g_flashmap_slice) sl_link; 56*4ffd4dfeSGrzegorz Bernacki }; 57*4ffd4dfeSGrzegorz Bernacki 58*4ffd4dfeSGrzegorz Bernacki STAILQ_HEAD(g_flashmap_head, g_flashmap_slice); 59*4ffd4dfeSGrzegorz Bernacki 60*4ffd4dfeSGrzegorz Bernacki static void g_flashmap_print(struct g_flashmap_slice *); 61*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_modify(struct g_geom *, const char *, 62*4ffd4dfeSGrzegorz Bernacki int, struct g_flashmap_head *); 63*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_start(struct bio *); 64*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_ioctl(struct g_provider *, u_long, void *, 65*4ffd4dfeSGrzegorz Bernacki int, struct thread *); 66*4ffd4dfeSGrzegorz Bernacki static void g_flashmap_dumpconf(struct sbuf *, const char *, 67*4ffd4dfeSGrzegorz Bernacki struct g_geom *, struct g_consumer *, struct g_provider *); 68*4ffd4dfeSGrzegorz Bernacki static struct g_geom *g_flashmap_taste(struct g_class *, 69*4ffd4dfeSGrzegorz Bernacki struct g_provider *, int); 70*4ffd4dfeSGrzegorz Bernacki static void g_flashmap_config(struct gctl_req *, struct g_class *, 71*4ffd4dfeSGrzegorz Bernacki const char *); 72*4ffd4dfeSGrzegorz Bernacki static int g_flashmap_load(device_t, struct g_flashmap_head *); 73*4ffd4dfeSGrzegorz Bernacki 74*4ffd4dfeSGrzegorz Bernacki MALLOC_DECLARE(M_FLASHMAP); 75*4ffd4dfeSGrzegorz Bernacki MALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class"); 76*4ffd4dfeSGrzegorz Bernacki 77*4ffd4dfeSGrzegorz Bernacki static void 78*4ffd4dfeSGrzegorz Bernacki g_flashmap_print(struct g_flashmap_slice *slice) 79*4ffd4dfeSGrzegorz Bernacki { 80*4ffd4dfeSGrzegorz Bernacki 81*4ffd4dfeSGrzegorz Bernacki printf("%08llx-%08llx: %s (%lluKB)\n", slice->sl_start, slice->sl_end, 82*4ffd4dfeSGrzegorz Bernacki slice->sl_name, (slice->sl_end - slice->sl_start) / 1024); 83*4ffd4dfeSGrzegorz Bernacki } 84*4ffd4dfeSGrzegorz Bernacki 85*4ffd4dfeSGrzegorz Bernacki static int 86*4ffd4dfeSGrzegorz Bernacki g_flashmap_modify(struct g_geom *gp, const char *devname, int secsize, 87*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_head *slices) 88*4ffd4dfeSGrzegorz Bernacki { 89*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_slice *slice; 90*4ffd4dfeSGrzegorz Bernacki int i, error; 91*4ffd4dfeSGrzegorz Bernacki 92*4ffd4dfeSGrzegorz Bernacki g_topology_assert(); 93*4ffd4dfeSGrzegorz Bernacki 94*4ffd4dfeSGrzegorz Bernacki i = 0; 95*4ffd4dfeSGrzegorz Bernacki STAILQ_FOREACH(slice, slices, sl_link) { 96*4ffd4dfeSGrzegorz Bernacki if (bootverbose) { 97*4ffd4dfeSGrzegorz Bernacki printf("%s: slice ", devname); 98*4ffd4dfeSGrzegorz Bernacki g_flashmap_print(slice); 99*4ffd4dfeSGrzegorz Bernacki } 100*4ffd4dfeSGrzegorz Bernacki 101*4ffd4dfeSGrzegorz Bernacki error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK, 102*4ffd4dfeSGrzegorz Bernacki slice->sl_start, 103*4ffd4dfeSGrzegorz Bernacki slice->sl_end - slice->sl_start + 1, 104*4ffd4dfeSGrzegorz Bernacki secsize, "%ss.%s", gp->name, slice->sl_name); 105*4ffd4dfeSGrzegorz Bernacki 106*4ffd4dfeSGrzegorz Bernacki if (error) 107*4ffd4dfeSGrzegorz Bernacki return (error); 108*4ffd4dfeSGrzegorz Bernacki } 109*4ffd4dfeSGrzegorz Bernacki 110*4ffd4dfeSGrzegorz Bernacki i = 0; 111*4ffd4dfeSGrzegorz Bernacki STAILQ_FOREACH(slice, slices, sl_link) { 112*4ffd4dfeSGrzegorz Bernacki error = g_slice_config(gp, i++, G_SLICE_CONFIG_SET, 113*4ffd4dfeSGrzegorz Bernacki slice->sl_start, 114*4ffd4dfeSGrzegorz Bernacki slice->sl_end - slice->sl_start + 1, 115*4ffd4dfeSGrzegorz Bernacki secsize, "%ss.%s", gp->name, slice->sl_name); 116*4ffd4dfeSGrzegorz Bernacki 117*4ffd4dfeSGrzegorz Bernacki if (error) 118*4ffd4dfeSGrzegorz Bernacki return (error); 119*4ffd4dfeSGrzegorz Bernacki } 120*4ffd4dfeSGrzegorz Bernacki 121*4ffd4dfeSGrzegorz Bernacki return (0); 122*4ffd4dfeSGrzegorz Bernacki } 123*4ffd4dfeSGrzegorz Bernacki 124*4ffd4dfeSGrzegorz Bernacki static int 125*4ffd4dfeSGrzegorz Bernacki g_flashmap_start(struct bio *bp) 126*4ffd4dfeSGrzegorz Bernacki { 127*4ffd4dfeSGrzegorz Bernacki 128*4ffd4dfeSGrzegorz Bernacki return (0); 129*4ffd4dfeSGrzegorz Bernacki } 130*4ffd4dfeSGrzegorz Bernacki 131*4ffd4dfeSGrzegorz Bernacki static void 132*4ffd4dfeSGrzegorz Bernacki g_flashmap_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, 133*4ffd4dfeSGrzegorz Bernacki struct g_consumer *cp __unused, struct g_provider *pp) 134*4ffd4dfeSGrzegorz Bernacki { 135*4ffd4dfeSGrzegorz Bernacki struct g_slicer *gsp; 136*4ffd4dfeSGrzegorz Bernacki 137*4ffd4dfeSGrzegorz Bernacki gsp = gp->softc; 138*4ffd4dfeSGrzegorz Bernacki g_slice_dumpconf(sb, indent, gp, cp, pp); 139*4ffd4dfeSGrzegorz Bernacki } 140*4ffd4dfeSGrzegorz Bernacki 141*4ffd4dfeSGrzegorz Bernacki static int 142*4ffd4dfeSGrzegorz Bernacki g_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, 143*4ffd4dfeSGrzegorz Bernacki struct thread *td) 144*4ffd4dfeSGrzegorz Bernacki { 145*4ffd4dfeSGrzegorz Bernacki struct g_consumer *cp; 146*4ffd4dfeSGrzegorz Bernacki struct g_geom *gp; 147*4ffd4dfeSGrzegorz Bernacki 148*4ffd4dfeSGrzegorz Bernacki if (cmd != NAND_IO_GET_CHIP_PARAM) 149*4ffd4dfeSGrzegorz Bernacki return (ENOIOCTL); 150*4ffd4dfeSGrzegorz Bernacki 151*4ffd4dfeSGrzegorz Bernacki cp = LIST_FIRST(&pp->geom->consumer); 152*4ffd4dfeSGrzegorz Bernacki if (cp == NULL) 153*4ffd4dfeSGrzegorz Bernacki return (ENOIOCTL); 154*4ffd4dfeSGrzegorz Bernacki gp = cp->provider->geom; 155*4ffd4dfeSGrzegorz Bernacki if (gp->ioctl == NULL) 156*4ffd4dfeSGrzegorz Bernacki return (ENOIOCTL); 157*4ffd4dfeSGrzegorz Bernacki 158*4ffd4dfeSGrzegorz Bernacki return (gp->ioctl(cp->provider, cmd, data, fflag, td)); 159*4ffd4dfeSGrzegorz Bernacki } 160*4ffd4dfeSGrzegorz Bernacki 161*4ffd4dfeSGrzegorz Bernacki 162*4ffd4dfeSGrzegorz Bernacki static struct g_geom * 163*4ffd4dfeSGrzegorz Bernacki g_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags) 164*4ffd4dfeSGrzegorz Bernacki { 165*4ffd4dfeSGrzegorz Bernacki struct g_geom *gp = NULL; 166*4ffd4dfeSGrzegorz Bernacki struct g_consumer *cp; 167*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_head head; 168*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_slice *slice, *slice_temp; 169*4ffd4dfeSGrzegorz Bernacki device_t dev; 170*4ffd4dfeSGrzegorz Bernacki int nslices, size; 171*4ffd4dfeSGrzegorz Bernacki 172*4ffd4dfeSGrzegorz Bernacki g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name); 173*4ffd4dfeSGrzegorz Bernacki g_topology_assert(); 174*4ffd4dfeSGrzegorz Bernacki 175*4ffd4dfeSGrzegorz Bernacki if (flags == G_TF_NORMAL && 176*4ffd4dfeSGrzegorz Bernacki !strcmp(pp->geom->class->name, FLASHMAP_CLASS_NAME)) 177*4ffd4dfeSGrzegorz Bernacki return (NULL); 178*4ffd4dfeSGrzegorz Bernacki 179*4ffd4dfeSGrzegorz Bernacki gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, NULL, 0, 180*4ffd4dfeSGrzegorz Bernacki g_flashmap_start); 181*4ffd4dfeSGrzegorz Bernacki if (gp == NULL) 182*4ffd4dfeSGrzegorz Bernacki return (NULL); 183*4ffd4dfeSGrzegorz Bernacki 184*4ffd4dfeSGrzegorz Bernacki STAILQ_INIT(&head); 185*4ffd4dfeSGrzegorz Bernacki 186*4ffd4dfeSGrzegorz Bernacki do { 187*4ffd4dfeSGrzegorz Bernacki size = sizeof(device_t); 188*4ffd4dfeSGrzegorz Bernacki if (g_io_getattr("NAND::device", cp, &size, &dev)) 189*4ffd4dfeSGrzegorz Bernacki break; 190*4ffd4dfeSGrzegorz Bernacki 191*4ffd4dfeSGrzegorz Bernacki nslices = g_flashmap_load(dev, &head); 192*4ffd4dfeSGrzegorz Bernacki if (nslices == 0) 193*4ffd4dfeSGrzegorz Bernacki break; 194*4ffd4dfeSGrzegorz Bernacki 195*4ffd4dfeSGrzegorz Bernacki g_flashmap_modify(gp, cp->provider->name, 196*4ffd4dfeSGrzegorz Bernacki cp->provider->sectorsize, &head); 197*4ffd4dfeSGrzegorz Bernacki } while (0); 198*4ffd4dfeSGrzegorz Bernacki 199*4ffd4dfeSGrzegorz Bernacki g_access(cp, -1, 0, 0); 200*4ffd4dfeSGrzegorz Bernacki 201*4ffd4dfeSGrzegorz Bernacki STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp) { 202*4ffd4dfeSGrzegorz Bernacki free(slice, M_FLASHMAP); 203*4ffd4dfeSGrzegorz Bernacki } 204*4ffd4dfeSGrzegorz Bernacki 205*4ffd4dfeSGrzegorz Bernacki if (LIST_EMPTY(&gp->provider)) { 206*4ffd4dfeSGrzegorz Bernacki g_slice_spoiled(cp); 207*4ffd4dfeSGrzegorz Bernacki return (NULL); 208*4ffd4dfeSGrzegorz Bernacki } 209*4ffd4dfeSGrzegorz Bernacki return (gp); 210*4ffd4dfeSGrzegorz Bernacki } 211*4ffd4dfeSGrzegorz Bernacki 212*4ffd4dfeSGrzegorz Bernacki static void 213*4ffd4dfeSGrzegorz Bernacki g_flashmap_config(struct gctl_req *req, struct g_class *mp, const char *verb) 214*4ffd4dfeSGrzegorz Bernacki { 215*4ffd4dfeSGrzegorz Bernacki 216*4ffd4dfeSGrzegorz Bernacki gctl_error(req, "unknown config verb"); 217*4ffd4dfeSGrzegorz Bernacki } 218*4ffd4dfeSGrzegorz Bernacki 219*4ffd4dfeSGrzegorz Bernacki static int 220*4ffd4dfeSGrzegorz Bernacki g_flashmap_load(device_t dev, struct g_flashmap_head *head) 221*4ffd4dfeSGrzegorz Bernacki { 222*4ffd4dfeSGrzegorz Bernacki struct flash_slice *slices; 223*4ffd4dfeSGrzegorz Bernacki struct g_flashmap_slice *slice; 224*4ffd4dfeSGrzegorz Bernacki uint32_t i, buf_size; 225*4ffd4dfeSGrzegorz Bernacki int nslices = 0; 226*4ffd4dfeSGrzegorz Bernacki 227*4ffd4dfeSGrzegorz Bernacki buf_size = sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM; 228*4ffd4dfeSGrzegorz Bernacki slices = malloc(buf_size, M_FLASHMAP, M_WAITOK | M_ZERO); 229*4ffd4dfeSGrzegorz Bernacki if (flash_fill_slices(dev, slices, &nslices) == 0) { 230*4ffd4dfeSGrzegorz Bernacki for (i = 0; i < nslices; i++) { 231*4ffd4dfeSGrzegorz Bernacki slice = malloc(sizeof(struct g_flashmap_slice), 232*4ffd4dfeSGrzegorz Bernacki M_FLASHMAP, M_WAITOK); 233*4ffd4dfeSGrzegorz Bernacki 234*4ffd4dfeSGrzegorz Bernacki slice->sl_name = slices[i].label; 235*4ffd4dfeSGrzegorz Bernacki slice->sl_start = slices[i].base; 236*4ffd4dfeSGrzegorz Bernacki slice->sl_end = slices[i].base + slices[i].size - 1; 237*4ffd4dfeSGrzegorz Bernacki 238*4ffd4dfeSGrzegorz Bernacki STAILQ_INSERT_TAIL(head, slice, sl_link); 239*4ffd4dfeSGrzegorz Bernacki } 240*4ffd4dfeSGrzegorz Bernacki } 241*4ffd4dfeSGrzegorz Bernacki 242*4ffd4dfeSGrzegorz Bernacki free(slices, M_FLASHMAP); 243*4ffd4dfeSGrzegorz Bernacki return (nslices); 244*4ffd4dfeSGrzegorz Bernacki } 245*4ffd4dfeSGrzegorz Bernacki 246*4ffd4dfeSGrzegorz Bernacki static struct g_class g_flashmap_class = { 247*4ffd4dfeSGrzegorz Bernacki .name = FLASHMAP_CLASS_NAME, 248*4ffd4dfeSGrzegorz Bernacki .version = G_VERSION, 249*4ffd4dfeSGrzegorz Bernacki .taste = g_flashmap_taste, 250*4ffd4dfeSGrzegorz Bernacki .dumpconf = g_flashmap_dumpconf, 251*4ffd4dfeSGrzegorz Bernacki .ioctl = g_flashmap_ioctl, 252*4ffd4dfeSGrzegorz Bernacki .ctlreq = g_flashmap_config, 253*4ffd4dfeSGrzegorz Bernacki }; 254*4ffd4dfeSGrzegorz Bernacki 255*4ffd4dfeSGrzegorz Bernacki DECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap); 256