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: stable/10/sys/geom/geom_flashmap.c 320168 2017-06-20 19:59:57Z marius $"); 30235778Sgber 31235778Sgber#include <sys/param.h> 32235778Sgber#include <sys/systm.h> 33235778Sgber#include <sys/kernel.h> 34235778Sgber#include <sys/malloc.h> 35235778Sgber#include <sys/lock.h> 36235778Sgber#include <sys/mutex.h> 37320168Smarius#include <sys/proc.h> 38235778Sgber#include <sys/slicer.h> 39235778Sgber 40235778Sgber#include <geom/geom.h> 41235778Sgber#include <geom/geom_slice.h> 42235778Sgber#include <geom/geom_disk.h> 43318159Smarius 44235778Sgber#include <dev/nand/nand_dev.h> 45235778Sgber 46318159Smarius#define FLASHMAP_CLASS_NAME "Flashmap" 47235778Sgber 48235778Sgberstruct g_flashmap_slice { 49235778Sgber off_t sl_start; 50235778Sgber off_t sl_end; 51235778Sgber const char *sl_name; 52235778Sgber 53235778Sgber STAILQ_ENTRY(g_flashmap_slice) sl_link; 54235778Sgber}; 55235778Sgber 56235778SgberSTAILQ_HEAD(g_flashmap_head, g_flashmap_slice); 57235778Sgber 58318159Smariusstatic struct { 59318159Smarius const char *type; 60318159Smarius flash_slicer_t slicer; 61318159Smarius} g_flashmap_slicers[] = { 62318159Smarius { "NAND::device", NULL }, 63318159Smarius { "CFI::device", NULL }, 64318159Smarius { "SPI::device", NULL }, 65318159Smarius { "MMC::device", NULL } 66318159Smarius}; 67235778Sgber 68318159Smariusstatic g_ioctl_t g_flashmap_ioctl; 69318159Smariusstatic g_taste_t g_flashmap_taste; 70318159Smarius 71318159Smariusstatic int g_flashmap_load(device_t dev, struct g_provider *pp, 72318159Smarius flash_slicer_t slicer, struct g_flashmap_head *head); 73318159Smariusstatic int g_flashmap_modify(struct g_geom *gp, const char *devname, 74318159Smarius int secsize, struct g_flashmap_head *slices); 75318159Smariusstatic void g_flashmap_print(struct g_flashmap_slice *slice); 76318159Smarius 77235778SgberMALLOC_DECLARE(M_FLASHMAP); 78235778SgberMALLOC_DEFINE(M_FLASHMAP, "geom_flashmap", "GEOM flash memory slicer class"); 79235778Sgber 80235778Sgberstatic void 81235778Sgberg_flashmap_print(struct g_flashmap_slice *slice) 82235778Sgber{ 83235778Sgber 84235858Sdelphij printf("%08jx-%08jx: %s (%juKB)\n", (uintmax_t)slice->sl_start, 85235858Sdelphij (uintmax_t)slice->sl_end, slice->sl_name, 86235858Sdelphij (uintmax_t)(slice->sl_end - slice->sl_start) / 1024); 87235778Sgber} 88235778Sgber 89235778Sgberstatic int 90235778Sgberg_flashmap_modify(struct g_geom *gp, const char *devname, int secsize, 91235778Sgber struct g_flashmap_head *slices) 92235778Sgber{ 93235778Sgber struct g_flashmap_slice *slice; 94235778Sgber int i, error; 95235778Sgber 96235778Sgber g_topology_assert(); 97235778Sgber 98235778Sgber i = 0; 99235778Sgber STAILQ_FOREACH(slice, slices, sl_link) { 100235778Sgber if (bootverbose) { 101235778Sgber printf("%s: slice ", devname); 102235778Sgber g_flashmap_print(slice); 103235778Sgber } 104235778Sgber 105235778Sgber error = g_slice_config(gp, i++, G_SLICE_CONFIG_CHECK, 106235778Sgber slice->sl_start, 107235778Sgber slice->sl_end - slice->sl_start + 1, 108318159Smarius secsize, FLASH_SLICES_FMT, gp->name, slice->sl_name); 109235778Sgber 110235778Sgber if (error) 111235778Sgber return (error); 112235778Sgber } 113235778Sgber 114235778Sgber i = 0; 115235778Sgber STAILQ_FOREACH(slice, slices, sl_link) { 116235778Sgber error = g_slice_config(gp, i++, G_SLICE_CONFIG_SET, 117235778Sgber slice->sl_start, 118235778Sgber slice->sl_end - slice->sl_start + 1, 119235778Sgber secsize, "%ss.%s", gp->name, slice->sl_name); 120235778Sgber 121235778Sgber if (error) 122235778Sgber return (error); 123235778Sgber } 124235778Sgber 125235778Sgber return (0); 126235778Sgber} 127235778Sgber 128235778Sgberstatic int 129235778Sgberg_flashmap_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, 130235778Sgber struct thread *td) 131235778Sgber{ 132235778Sgber struct g_consumer *cp; 133235778Sgber struct g_geom *gp; 134235778Sgber 135235778Sgber if (cmd != NAND_IO_GET_CHIP_PARAM) 136235778Sgber return (ENOIOCTL); 137235778Sgber 138235778Sgber cp = LIST_FIRST(&pp->geom->consumer); 139235778Sgber if (cp == NULL) 140235778Sgber return (ENOIOCTL); 141235778Sgber gp = cp->provider->geom; 142235778Sgber if (gp->ioctl == NULL) 143235778Sgber return (ENOIOCTL); 144235778Sgber 145235778Sgber return (gp->ioctl(cp->provider, cmd, data, fflag, td)); 146235778Sgber} 147235778Sgber 148235778Sgberstatic struct g_geom * 149235778Sgberg_flashmap_taste(struct g_class *mp, struct g_provider *pp, int flags) 150235778Sgber{ 151318159Smarius struct g_geom *gp; 152235778Sgber struct g_consumer *cp; 153235778Sgber struct g_flashmap_head head; 154235778Sgber struct g_flashmap_slice *slice, *slice_temp; 155318159Smarius flash_slicer_t slicer; 156235778Sgber device_t dev; 157318159Smarius int i, size; 158235778Sgber 159235778Sgber g_trace(G_T_TOPOLOGY, "flashmap_taste(%s,%s)", mp->name, pp->name); 160235778Sgber g_topology_assert(); 161235778Sgber 162235778Sgber if (flags == G_TF_NORMAL && 163249556Sbrooks strcmp(pp->geom->class->name, G_DISK_CLASS_NAME) != 0) 164235778Sgber return (NULL); 165235778Sgber 166318159Smarius gp = g_slice_new(mp, FLASH_SLICES_MAX_NUM, pp, &cp, NULL, 0, NULL); 167235778Sgber if (gp == NULL) 168235778Sgber return (NULL); 169235778Sgber 170235778Sgber STAILQ_INIT(&head); 171235778Sgber 172235778Sgber do { 173318159Smarius slicer = NULL; 174318159Smarius for (i = 0; i < nitems(g_flashmap_slicers); i++) { 175251117Sbrooks size = sizeof(device_t); 176318159Smarius if (g_io_getattr(g_flashmap_slicers[i].type, cp, 177318159Smarius &size, &dev) == 0) { 178318159Smarius slicer = g_flashmap_slicers[i].slicer; 179251117Sbrooks break; 180318159Smarius } 181251117Sbrooks } 182318159Smarius if (slicer == NULL) 183318159Smarius break; 184235778Sgber 185318159Smarius if (g_flashmap_load(dev, pp, slicer, &head) == 0) 186235778Sgber break; 187235778Sgber 188235778Sgber g_flashmap_modify(gp, cp->provider->name, 189235778Sgber cp->provider->sectorsize, &head); 190235778Sgber } while (0); 191235778Sgber 192235778Sgber g_access(cp, -1, 0, 0); 193235778Sgber 194318159Smarius STAILQ_FOREACH_SAFE(slice, &head, sl_link, slice_temp) 195235778Sgber free(slice, M_FLASHMAP); 196235778Sgber 197235778Sgber if (LIST_EMPTY(&gp->provider)) { 198235778Sgber g_slice_spoiled(cp); 199235778Sgber return (NULL); 200235778Sgber } 201235778Sgber return (gp); 202235778Sgber} 203235778Sgber 204235778Sgberstatic int 205318159Smariusg_flashmap_load(device_t dev, struct g_provider *pp, flash_slicer_t slicer, 206318159Smarius struct g_flashmap_head *head) 207235778Sgber{ 208235778Sgber struct flash_slice *slices; 209235778Sgber struct g_flashmap_slice *slice; 210318159Smarius int i, nslices = 0; 211235778Sgber 212318159Smarius slices = malloc(sizeof(struct flash_slice) * FLASH_SLICES_MAX_NUM, 213318159Smarius M_FLASHMAP, M_WAITOK | M_ZERO); 214318159Smarius if (slicer(dev, pp->name, slices, &nslices) == 0) { 215235778Sgber for (i = 0; i < nslices; i++) { 216235778Sgber slice = malloc(sizeof(struct g_flashmap_slice), 217235778Sgber M_FLASHMAP, M_WAITOK); 218235778Sgber 219235778Sgber slice->sl_name = slices[i].label; 220235778Sgber slice->sl_start = slices[i].base; 221235778Sgber slice->sl_end = slices[i].base + slices[i].size - 1; 222235778Sgber 223235778Sgber STAILQ_INSERT_TAIL(head, slice, sl_link); 224235778Sgber } 225235778Sgber } 226235778Sgber 227235778Sgber free(slices, M_FLASHMAP); 228235778Sgber return (nslices); 229235778Sgber} 230235778Sgber 231318159Smariusvoid flash_register_slicer(flash_slicer_t slicer, u_int type, bool force) 232318159Smarius{ 233318159Smarius 234320168Smarius DROP_GIANT(); 235318159Smarius g_topology_lock(); 236318159Smarius if (g_flashmap_slicers[type].slicer == NULL || force == TRUE) 237318159Smarius g_flashmap_slicers[type].slicer = slicer; 238318159Smarius g_topology_unlock(); 239320168Smarius PICKUP_GIANT(); 240318159Smarius} 241318159Smarius 242235778Sgberstatic struct g_class g_flashmap_class = { 243235778Sgber .name = FLASHMAP_CLASS_NAME, 244235778Sgber .version = G_VERSION, 245235778Sgber .taste = g_flashmap_taste, 246235778Sgber .ioctl = g_flashmap_ioctl, 247235778Sgber}; 248235778Sgber 249235778SgberDECLARE_GEOM_CLASS(g_flashmap_class, g_flashmap); 250318159SmariusMODULE_VERSION(g_flashmap, 0); 251