nand_geom.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (C) 2009-2012 Semihalf 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/11/sys/dev/nand/nand_geom.c 330897 2018-03-14 03:19:51Z eadler $"); 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/conf.h> 35#include <sys/bus.h> 36#include <sys/malloc.h> 37#include <sys/uio.h> 38#include <sys/bio.h> 39#include <geom/geom.h> 40#include <geom/geom_disk.h> 41 42#include <dev/nand/nand.h> 43#include <dev/nand/nandbus.h> 44#include <dev/nand/nand_dev.h> 45#include "nand_if.h" 46#include "nandbus_if.h" 47 48#define BIO_NAND_STD ((void *)1) 49#define BIO_NAND_RAW ((void *)2) 50 51static disk_ioctl_t nand_ioctl; 52static disk_getattr_t nand_getattr; 53static disk_strategy_t nand_strategy; 54static disk_strategy_t nand_strategy_raw; 55 56static int 57nand_read(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) 58{ 59 60 nand_debug(NDBG_GEOM, "Read from chip %d [%p] at %d", chip->num, chip, 61 offset); 62 63 return (nand_read_pages(chip, offset, buf, len)); 64} 65 66static int 67nand_write(struct nand_chip *chip, uint32_t offset, void* buf, uint32_t len) 68{ 69 70 nand_debug(NDBG_GEOM, "Write to chip %d [%p] at %d", chip->num, chip, 71 offset); 72 73 return (nand_prog_pages(chip, offset, buf, len)); 74} 75 76static int 77nand_read_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) 78{ 79 nand_debug(NDBG_GEOM, "Raw read from chip %d [%p] at %d", chip->num, 80 chip, offset); 81 82 return (nand_read_pages_raw(chip, offset, buf, len)); 83} 84 85static int 86nand_write_raw(struct nand_chip *chip, uint32_t offset, void *buf, uint32_t len) 87{ 88 89 nand_debug(NDBG_GEOM, "Raw write to chip %d [%p] at %d", chip->num, 90 chip, offset); 91 92 return (nand_prog_pages_raw(chip, offset, buf, len)); 93} 94 95static void 96nand_strategy(struct bio *bp) 97{ 98 struct nand_chip *chip; 99 100 chip = (struct nand_chip *)bp->bio_disk->d_drv1; 101 102 bp->bio_driver1 = BIO_NAND_STD; 103 104 nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", 105 bp->bio_cmd == BIO_READ ? "READ" : 106 (bp->bio_cmd == BIO_WRITE ? "WRITE" : 107 (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), 108 chip->num, chip); 109 110 mtx_lock(&chip->qlock); 111 bioq_insert_tail(&chip->bioq, bp); 112 mtx_unlock(&chip->qlock); 113 taskqueue_enqueue(chip->tq, &chip->iotask); 114} 115 116static void 117nand_strategy_raw(struct bio *bp) 118{ 119 struct nand_chip *chip; 120 121 chip = (struct nand_chip *)bp->bio_disk->d_drv1; 122 123 /* Inform taskqueue that it's a raw access */ 124 bp->bio_driver1 = BIO_NAND_RAW; 125 126 nand_debug(NDBG_GEOM, "Strategy %s on chip %d [%p]", 127 bp->bio_cmd == BIO_READ ? "READ" : 128 (bp->bio_cmd == BIO_WRITE ? "WRITE" : 129 (bp->bio_cmd == BIO_DELETE ? "DELETE" : "UNKNOWN")), 130 chip->num, chip); 131 132 mtx_lock(&chip->qlock); 133 bioq_insert_tail(&chip->bioq, bp); 134 mtx_unlock(&chip->qlock); 135 taskqueue_enqueue(chip->tq, &chip->iotask); 136} 137 138static int 139nand_oob_access(struct nand_chip *chip, uint32_t page, uint32_t offset, 140 uint32_t len, uint8_t *data, uint8_t write) 141{ 142 struct chip_geom *cg; 143 int ret = 0; 144 145 cg = &chip->chip_geom; 146 147 if (!write) 148 ret = nand_read_oob(chip, page, data, cg->oob_size); 149 else 150 ret = nand_prog_oob(chip, page, data, cg->oob_size); 151 152 return (ret); 153} 154 155static int 156nand_getattr(struct bio *bp) 157{ 158 struct nand_chip *chip; 159 struct chip_geom *cg; 160 device_t dev; 161 int val; 162 163 if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL) 164 return (ENXIO); 165 166 chip = (struct nand_chip *)bp->bio_disk->d_drv1; 167 cg = &(chip->chip_geom); 168 169 dev = device_get_parent(chip->dev); 170 dev = device_get_parent(dev); 171 172 if (strcmp(bp->bio_attribute, "NAND::device") == 0) { 173 if (bp->bio_length != sizeof(dev)) 174 return (EFAULT); 175 bcopy(&dev, bp->bio_data, sizeof(dev)); 176 } else { 177 if (strcmp(bp->bio_attribute, "NAND::oobsize") == 0) 178 val = cg->oob_size; 179 else if (strcmp(bp->bio_attribute, "NAND::pagesize") == 0) 180 val = cg->page_size; 181 else if (strcmp(bp->bio_attribute, "NAND::blocksize") == 0) 182 val = cg->block_size; 183 else 184 return (-1); 185 if (bp->bio_length != sizeof(val)) 186 return (EFAULT); 187 bcopy(&val, bp->bio_data, sizeof(val)); 188 } 189 bp->bio_completed = bp->bio_length; 190 return (0); 191} 192 193static int 194nand_ioctl(struct disk *ndisk, u_long cmd, void *data, int fflag, 195 struct thread *td) 196{ 197 struct nand_chip *chip; 198 struct chip_geom *cg; 199 struct nand_oob_rw *oob_rw = NULL; 200 struct nand_raw_rw *raw_rw = NULL; 201 device_t nandbus; 202 size_t bufsize = 0, len = 0; 203 size_t raw_size; 204 off_t off; 205 uint8_t *buf = NULL; 206 int ret = 0; 207 uint8_t status; 208 209 chip = (struct nand_chip *)ndisk->d_drv1; 210 cg = &chip->chip_geom; 211 nandbus = device_get_parent(chip->dev); 212 213 if ((cmd == NAND_IO_RAW_READ) || (cmd == NAND_IO_RAW_PROG)) { 214 raw_rw = (struct nand_raw_rw *)data; 215 raw_size = cg->pgs_per_blk * (cg->page_size + cg->oob_size); 216 217 /* Check if len is not bigger than chip size */ 218 if (raw_rw->len > raw_size) 219 return (EFBIG); 220 221 /* 222 * Do not ask for too much memory, in case of large transfers 223 * read/write in 16-pages chunks 224 */ 225 bufsize = 16 * (cg->page_size + cg->oob_size); 226 if (raw_rw->len < bufsize) 227 bufsize = raw_rw->len; 228 229 buf = malloc(bufsize, M_NAND, M_WAITOK); 230 len = raw_rw->len; 231 off = 0; 232 } 233 234 switch (cmd) { 235 case NAND_IO_ERASE: 236 ret = nand_erase_blocks(chip, ((off_t *)data)[0], 237 ((off_t *)data)[1]); 238 break; 239 240 case NAND_IO_OOB_READ: 241 oob_rw = (struct nand_oob_rw *)data; 242 ret = nand_oob_access(chip, oob_rw->page, 0, 243 oob_rw->len, oob_rw->data, 0); 244 break; 245 246 case NAND_IO_OOB_PROG: 247 oob_rw = (struct nand_oob_rw *)data; 248 ret = nand_oob_access(chip, oob_rw->page, 0, 249 oob_rw->len, oob_rw->data, 1); 250 break; 251 252 case NAND_IO_GET_STATUS: 253 NANDBUS_LOCK(nandbus); 254 ret = NANDBUS_GET_STATUS(nandbus, &status); 255 if (ret == 0) 256 *(uint8_t *)data = status; 257 NANDBUS_UNLOCK(nandbus); 258 break; 259 260 case NAND_IO_RAW_PROG: 261 while (len > 0) { 262 if (len < bufsize) 263 bufsize = len; 264 265 ret = copyin(raw_rw->data + off, buf, bufsize); 266 if (ret) 267 break; 268 ret = nand_prog_pages_raw(chip, raw_rw->off + off, buf, 269 bufsize); 270 if (ret) 271 break; 272 len -= bufsize; 273 off += bufsize; 274 } 275 break; 276 277 case NAND_IO_RAW_READ: 278 while (len > 0) { 279 if (len < bufsize) 280 bufsize = len; 281 282 ret = nand_read_pages_raw(chip, raw_rw->off + off, buf, 283 bufsize); 284 if (ret) 285 break; 286 287 ret = copyout(buf, raw_rw->data + off, bufsize); 288 if (ret) 289 break; 290 len -= bufsize; 291 off += bufsize; 292 } 293 break; 294 295 case NAND_IO_GET_CHIP_PARAM: 296 nand_get_chip_param(chip, (struct chip_param_io *)data); 297 break; 298 299 default: 300 printf("Unknown nand_ioctl request \n"); 301 ret = EIO; 302 } 303 304 if (buf) 305 free(buf, M_NAND); 306 307 return (ret); 308} 309 310static void 311nand_io_proc(void *arg, int pending) 312{ 313 struct nand_chip *chip = arg; 314 struct bio *bp; 315 int err = 0; 316 317 for (;;) { 318 mtx_lock(&chip->qlock); 319 bp = bioq_takefirst(&chip->bioq); 320 mtx_unlock(&chip->qlock); 321 if (bp == NULL) 322 break; 323 324 if (bp->bio_driver1 == BIO_NAND_STD) { 325 if (bp->bio_cmd == BIO_READ) { 326 err = nand_read(chip, 327 bp->bio_offset & 0xffffffff, 328 bp->bio_data, bp->bio_bcount); 329 } else if (bp->bio_cmd == BIO_WRITE) { 330 err = nand_write(chip, 331 bp->bio_offset & 0xffffffff, 332 bp->bio_data, bp->bio_bcount); 333 } 334 } else if (bp->bio_driver1 == BIO_NAND_RAW) { 335 if (bp->bio_cmd == BIO_READ) { 336 err = nand_read_raw(chip, 337 bp->bio_offset & 0xffffffff, 338 bp->bio_data, bp->bio_bcount); 339 } else if (bp->bio_cmd == BIO_WRITE) { 340 err = nand_write_raw(chip, 341 bp->bio_offset & 0xffffffff, 342 bp->bio_data, bp->bio_bcount); 343 } 344 } else 345 panic("Unknown access type in bio->bio_driver1\n"); 346 347 if (bp->bio_cmd == BIO_DELETE) { 348 nand_debug(NDBG_GEOM, "Delete on chip%d offset %lld " 349 "length %ld\n", chip->num, bp->bio_offset, 350 bp->bio_bcount); 351 err = nand_erase_blocks(chip, 352 bp->bio_offset & 0xffffffff, 353 bp->bio_bcount); 354 } 355 356 if (err == 0 || err == ECC_CORRECTABLE) 357 bp->bio_resid = 0; 358 else { 359 nand_debug(NDBG_GEOM,"nand_[read|write|erase_blocks] " 360 "error: %d\n", err); 361 362 bp->bio_error = EIO; 363 bp->bio_flags |= BIO_ERROR; 364 bp->bio_resid = bp->bio_bcount; 365 } 366 biodone(bp); 367 } 368} 369 370int 371create_geom_disk(struct nand_chip *chip) 372{ 373 struct disk *ndisk, *rdisk; 374 375 /* Create the disk device */ 376 ndisk = disk_alloc(); 377 ndisk->d_strategy = nand_strategy; 378 ndisk->d_ioctl = nand_ioctl; 379 ndisk->d_getattr = nand_getattr; 380 ndisk->d_name = "gnand"; 381 ndisk->d_drv1 = chip; 382 ndisk->d_maxsize = chip->chip_geom.block_size; 383 ndisk->d_sectorsize = chip->chip_geom.page_size; 384 ndisk->d_mediasize = chip->chip_geom.chip_size; 385 ndisk->d_unit = chip->num + 386 10 * device_get_unit(device_get_parent(chip->dev)); 387 388 /* 389 * When using BBT, make two last blocks of device unavailable 390 * to user (because those are used to store BBT table). 391 */ 392 if (chip->bbt != NULL) 393 ndisk->d_mediasize -= (2 * chip->chip_geom.block_size); 394 395 ndisk->d_flags = DISKFLAG_CANDELETE; 396 397 snprintf(ndisk->d_ident, sizeof(ndisk->d_ident), 398 "nand: Man:0x%02x Dev:0x%02x", chip->id.man_id, chip->id.dev_id); 399 ndisk->d_rotation_rate = DISK_RR_NON_ROTATING; 400 401 disk_create(ndisk, DISK_VERSION); 402 403 /* Create the RAW disk device */ 404 rdisk = disk_alloc(); 405 rdisk->d_strategy = nand_strategy_raw; 406 rdisk->d_ioctl = nand_ioctl; 407 rdisk->d_getattr = nand_getattr; 408 rdisk->d_name = "gnand.raw"; 409 rdisk->d_drv1 = chip; 410 rdisk->d_maxsize = chip->chip_geom.block_size; 411 rdisk->d_sectorsize = chip->chip_geom.page_size; 412 rdisk->d_mediasize = chip->chip_geom.chip_size; 413 rdisk->d_unit = chip->num + 414 10 * device_get_unit(device_get_parent(chip->dev)); 415 416 rdisk->d_flags = DISKFLAG_CANDELETE; 417 418 snprintf(rdisk->d_ident, sizeof(rdisk->d_ident), 419 "nand_raw: Man:0x%02x Dev:0x%02x", chip->id.man_id, 420 chip->id.dev_id); 421 rdisk->d_rotation_rate = DISK_RR_NON_ROTATING; 422 423 disk_create(rdisk, DISK_VERSION); 424 425 chip->ndisk = ndisk; 426 chip->rdisk = rdisk; 427 428 mtx_init(&chip->qlock, "NAND I/O lock", NULL, MTX_DEF); 429 bioq_init(&chip->bioq); 430 431 TASK_INIT(&chip->iotask, 0, nand_io_proc, chip); 432 chip->tq = taskqueue_create("nand_taskq", M_WAITOK, 433 taskqueue_thread_enqueue, &chip->tq); 434 taskqueue_start_threads(&chip->tq, 1, PI_DISK, "nand taskq"); 435 436 if (bootverbose) 437 device_printf(chip->dev, "Created gnand%d for chip [0x%0x, " 438 "0x%0x]\n", ndisk->d_unit, chip->id.man_id, 439 chip->id.dev_id); 440 441 return (0); 442} 443 444void 445destroy_geom_disk(struct nand_chip *chip) 446{ 447 struct bio *bp; 448 449 taskqueue_free(chip->tq); 450 disk_destroy(chip->ndisk); 451 disk_destroy(chip->rdisk); 452 453 mtx_lock(&chip->qlock); 454 for (;;) { 455 bp = bioq_takefirst(&chip->bioq); 456 if (bp == NULL) 457 break; 458 bp->bio_error = EIO; 459 bp->bio_flags |= BIO_ERROR; 460 bp->bio_resid = bp->bio_bcount; 461 462 biodone(bp); 463 } 464 mtx_unlock(&chip->qlock); 465 466 mtx_destroy(&chip->qlock); 467} 468