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