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