Home | History | Annotate | Line # | Download | only in flash
flash.c revision 1.12.18.2
      1 /*	$NetBSD: flash.c,v 1.12.18.2 2017/04/29 10:19:31 pgoyette Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2011 Department of Software Engineering,
      5  *		      University of Szeged, Hungary
      6  * Copyright (c) 2011 Adam Hoka <ahoka (at) NetBSD.org>
      7  * Copyright (c) 2010 David Tengeri <dtengeri (at) inf.u-szeged.hu>
      8  * All rights reserved.
      9  *
     10  * This code is derived from software contributed to The NetBSD Foundation
     11  * by the Department of Software Engineering, University of Szeged, Hungary
     12  *
     13  * Redistribution and use in source and binary forms, with or without
     14  * modification, are permitted provided that the following conditions
     15  * are met:
     16  * 1. Redistributions of source code must retain the above copyright
     17  *    notice, this list of conditions and the following disclaimer.
     18  * 2. Redistributions in binary form must reproduce the above copyright
     19  *    notice, this list of conditions and the following disclaimer in the
     20  *    documentation and/or other materials provided with the distribution.
     21  *
     22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     25  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     26  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     32  * SUCH DAMAGE.
     33  */
     34 
     35 /*-
     36  * Framework for storage devices based on Flash technology
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: flash.c,v 1.12.18.2 2017/04/29 10:19:31 pgoyette Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/types.h>
     44 #include <sys/proc.h>
     45 #include <sys/errno.h>
     46 #include <sys/ioctl.h>
     47 #include <sys/device.h>
     48 #include <sys/conf.h>
     49 #include <sys/kmem.h>
     50 #include <sys/uio.h>
     51 #include <sys/kernel.h>
     52 
     53 #include <sys/atomic.h>
     54 #include <sys/buf.h>
     55 #include <sys/bufq.h>
     56 #include <sys/disk.h>
     57 #include <sys/disklabel.h>
     58 #include <sys/malloc.h>
     59 #include <sys/reboot.h>
     60 
     61 #include <sys/flashio.h>
     62 #include "flash.h"
     63 
     64 #ifdef FLASH_DEBUG
     65 int flashdebug = FLASH_DEBUG;
     66 #endif
     67 
     68 extern struct cfdriver flash_cd;
     69 
     70 dev_type_open(flashopen);
     71 dev_type_close(flashclose);
     72 dev_type_read(flashread);
     73 dev_type_write(flashwrite);
     74 dev_type_ioctl(flashioctl);
     75 dev_type_strategy(flashstrategy);
     76 dev_type_dump(flashdump);
     77 
     78 int flash_print(void *aux, const char *pnp);
     79 
     80 bool flash_shutdown(device_t dev, int how);
     81 int flash_nsectors(struct buf *bp);
     82 int flash_sector(struct buf *bp);
     83 
     84 int flash_match(device_t parent, cfdata_t match, void *aux);
     85 void flash_attach(device_t parent, device_t self, void *aux);
     86 int flash_detach(device_t device, int flags);
     87 
     88 CFATTACH_DECL_NEW(flash, sizeof(struct flash_softc),
     89     flash_match, flash_attach, flash_detach, NULL);
     90 
     91 /**
     92  * Block device's operation
     93  */
     94 const struct bdevsw flash_bdevsw = {
     95 	DEVSW_MODULE_INIT
     96 	.d_open = flashopen,
     97 	.d_close = flashclose,
     98 	.d_strategy = flashstrategy,
     99 	.d_ioctl = flashioctl,
    100 	.d_dump = flashdump,
    101 	.d_psize = nosize,
    102 	.d_discard = nodiscard,	/* XXX this driver probably wants a discard */
    103 	.d_flag = D_DISK | D_MPSAFE
    104 };
    105 
    106 /**
    107  * Character device's operations
    108  */
    109 const struct cdevsw flash_cdevsw = {
    110 	DEVSW_MODULE_INIT
    111 	.d_open = flashopen,
    112 	.d_close = flashclose,
    113 	.d_read = flashread,
    114 	.d_write = flashwrite,
    115 	.d_ioctl = flashioctl,
    116 	.d_stop = nostop,
    117 	.d_tty = notty,
    118 	.d_poll = nopoll,
    119 	.d_mmap = nommap,
    120 	.d_kqfilter = nokqfilter,
    121 	.d_discard = nodiscard,
    122 	.d_flag = D_DISK | D_MPSAFE
    123 };
    124 
    125 /* ARGSUSED */
    126 int
    127 flash_match(device_t parent, cfdata_t match, void *aux)
    128 {
    129 	/* pseudo device, always attaches */
    130 	return 1;
    131 }
    132 
    133 /* ARGSUSED */
    134 void
    135 flash_attach(device_t parent, device_t self, void *aux)
    136 {
    137 	struct flash_softc * const sc = device_private(self);
    138 	struct flash_attach_args * const faa = aux;
    139 	char pbuf[2][sizeof("9999 KB")];
    140 
    141 	sc->sc_dev = self;
    142 	sc->sc_parent_dev = parent;
    143 	sc->flash_if = faa->flash_if;
    144 	sc->sc_partinfo = faa->partinfo;
    145 	sc->hw_softc = device_private(parent);
    146 
    147 	format_bytes(pbuf[0], sizeof(pbuf[0]), sc->sc_partinfo.part_size);
    148 	format_bytes(pbuf[1], sizeof(pbuf[1]), sc->flash_if->erasesize);
    149 
    150 	aprint_naive("\n");
    151 
    152 	switch (sc->flash_if->type) {
    153 	case FLASH_TYPE_NOR:
    154 		aprint_normal(": NOR flash partition size %s, offset %#jx",
    155 			pbuf[0], (uintmax_t )sc->sc_partinfo.part_offset);
    156 		break;
    157 
    158 	case FLASH_TYPE_NAND:
    159 		aprint_normal(": NAND flash partition size %s, offset %#jx",
    160 			pbuf[0], (uintmax_t )sc->sc_partinfo.part_offset);
    161 		break;
    162 
    163 	default:
    164 		aprint_normal(": %s unknown flash", pbuf[0]);
    165 	}
    166 
    167 	if (sc->sc_partinfo.part_flags & FLASH_PART_READONLY) {
    168 		sc->sc_readonly = true;
    169 		aprint_normal(", read only");
    170 	} else {
    171 		sc->sc_readonly = false;
    172 	}
    173 
    174 	aprint_normal("\n");
    175 
    176 	if (sc->sc_partinfo.part_size == 0) {
    177 		aprint_error_dev(self,
    178 		    "partition size must be larger than 0\n");
    179 		return;
    180 	}
    181 
    182 	switch (sc->flash_if->type) {
    183 	case FLASH_TYPE_NOR:
    184 		aprint_normal_dev(sc->sc_dev,
    185 		    "erase size %s bytes, write size %d bytes\n",
    186 		    pbuf[1], sc->flash_if->writesize);
    187 		break;
    188 
    189 	case FLASH_TYPE_NAND:
    190 	default:
    191 		aprint_normal_dev(sc->sc_dev,
    192 		    "erase size %s, page size %d bytes, write size %d bytes\n",
    193 		    pbuf[1], sc->flash_if->page_size,
    194 		    sc->flash_if->writesize);
    195 		break;
    196 	}
    197 
    198 	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, flash_shutdown))
    199 		aprint_error_dev(sc->sc_dev,
    200 		    "couldn't establish power handler\n");
    201 }
    202 
    203 int
    204 flash_detach(device_t device, int flags)
    205 {
    206 	struct flash_softc * const sc = device_private(device);
    207 
    208 	pmf_device_deregister(sc->sc_dev);
    209 
    210 	/* freeing flash_if is our responsibility */
    211 	kmem_free(sc->flash_if, sizeof(*sc->flash_if));
    212 
    213 	return 0;
    214 }
    215 
    216 int
    217 flash_print(void *aux, const char *pnp)
    218 {
    219 	struct flash_attach_args *arg;
    220 	const char *type;
    221 
    222 	if (pnp != NULL) {
    223 		arg = aux;
    224 		switch (arg->flash_if->type) {
    225 		case FLASH_TYPE_NOR:
    226 			type = "NOR";
    227 			break;
    228 		case FLASH_TYPE_NAND:
    229 			type = "NAND";
    230 			break;
    231 		default:
    232 			panic("flash_print: unknown type %d",
    233 			    arg->flash_if->type);
    234 		}
    235 		aprint_normal("%s flash at %s", type, pnp);
    236 	}
    237 	return UNCONF;
    238 }
    239 
    240 device_t
    241 flash_attach_mi(struct flash_interface * const flash_if, device_t device)
    242 {
    243 	struct flash_attach_args arg;
    244 
    245 #ifdef DIAGNOSTIC
    246 	if (flash_if == NULL) {
    247 		aprint_error("flash_attach_mi: NULL\n");
    248 		return 0;
    249 	}
    250 #endif
    251 	arg.flash_if = flash_if;
    252 
    253 	return config_found_ia(device, "flashbus", &arg, flash_print);
    254 }
    255 
    256 /**
    257  * flash_open - open the character device
    258  * Checks if there is a driver registered to the minor number of the open
    259  * request.
    260  */
    261 int
    262 flashopen(dev_t dev, int flags, int fmt, lwp_t *l)
    263 {
    264 	int unit = minor(dev);
    265 	struct flash_softc *sc;
    266 
    267 	FLDPRINTFN(1, ("flash: opening device unit %d\n", unit));
    268 
    269 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    270 		return ENXIO;
    271 
    272 	/* TODO return eperm if want to open for writing a read only dev */
    273 
    274 	/* reset buffer length */
    275 //	sc->sc_cache->fc_len = 0;
    276 
    277 	return 0;
    278 }
    279 
    280 /**
    281  * flash_close - close device
    282  * We don't have to release any resources, so just return 0.
    283  */
    284 int
    285 flashclose(dev_t dev, int flags, int fmt, lwp_t *l)
    286 {
    287 	int unit = minor(dev);
    288 	struct flash_softc *sc;
    289 	int err;
    290 
    291 	FLDPRINTFN(1, ("flash: closing flash device unit %d\n", unit));
    292 
    293 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    294 		return ENXIO;
    295 
    296 	if (!sc->sc_readonly) {
    297 		err = flash_sync(sc->sc_dev);
    298 		if (err)
    299 			return err;
    300 	}
    301 
    302 	return 0;
    303 }
    304 
    305 /**
    306  * flash_read - read from character device
    307  * This function uses the registered driver's read function to read the
    308  * requested length to * a buffer and then moves this buffer to userspace.
    309  */
    310 int
    311 flashread(dev_t dev, struct uio * const uio, int flag)
    312 {
    313 	return physio(flashstrategy, NULL, dev, B_READ, minphys, uio);
    314 }
    315 
    316 /**
    317  * flash_write - write to character device
    318  * This function moves the data into a buffer from userspace to kernel space,
    319  * then uses the registered driver's write function to write out the data to
    320  * the media.
    321  */
    322 int
    323 flashwrite(dev_t dev, struct uio * const uio, int flag)
    324 {
    325 	return physio(flashstrategy, NULL, dev, B_WRITE, minphys, uio);
    326 }
    327 
    328 void
    329 flashstrategy(struct buf * const bp)
    330 {
    331 	struct flash_softc *sc;
    332 	const struct flash_interface *flash_if;
    333 	const struct flash_partition *part;
    334 	int unit, device_blks;
    335 
    336 	unit = minor(bp->b_dev);
    337 	sc = device_lookup_private(&flash_cd, unit);
    338 	if (sc == NULL) {
    339 		bp->b_error = ENXIO;
    340 		goto done;
    341 	}
    342 
    343 	flash_if = sc->flash_if;
    344 	part = &sc->sc_partinfo;
    345 
    346 	/* divider */
    347 	KASSERT(flash_if->writesize != 0);
    348 
    349 	aprint_debug_dev(sc->sc_dev, "flash_strategy()\n");
    350 
    351 	if (!(bp->b_flags & B_READ) && sc->sc_readonly) {
    352 		bp->b_error = EACCES;
    353 		goto done;
    354 	}
    355 
    356 	/* check if length is not negative */
    357 	if (bp->b_blkno < 0) {
    358 		bp->b_error = EINVAL;
    359 		goto done;
    360 	}
    361 
    362 	/* zero lenght i/o */
    363 	if (bp->b_bcount == 0) {
    364 		goto done;
    365 	}
    366 
    367 	device_blks = sc->sc_partinfo.part_size / DEV_BSIZE;
    368 	KASSERT(part->part_offset % DEV_BSIZE == 0);
    369 	bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE);
    370 
    371 	if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) {
    372 		goto done;
    373 	}
    374 
    375 	bp->b_resid = bp->b_bcount;
    376 	flash_if->submit(sc->sc_parent_dev, bp);
    377 
    378 	return;
    379 done:
    380 	bp->b_resid = bp->b_bcount;
    381 	biodone(bp);
    382 }
    383 
    384 /*
    385  * Handle the ioctl for the device
    386  */
    387 int
    388 flashioctl(dev_t dev, u_long command, void * const data, int flags, lwp_t *l)
    389 {
    390 	struct flash_erase_params *ep;
    391 	struct flash_info_params *ip;
    392 	struct flash_dump_params *dp;
    393 	struct flash_badblock_params *bbp;
    394 	struct flash_erase_instruction ei;
    395 	struct flash_softc *sc;
    396 	int unit, err;
    397 	size_t retlen;
    398 	flash_off_t offset;
    399 	bool bad;
    400 
    401 	unit = minor(dev);
    402 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    403 		return ENXIO;
    404 
    405 	err = 0;
    406 	switch (command) {
    407 	case FLASH_ERASE_BLOCK:
    408 		/**
    409 		 * Set up an erase instruction then call the registered
    410 		 * driver's erase operation.
    411 		 */
    412 		ep = data;
    413 
    414 		if (sc->sc_readonly) {
    415 			return EACCES;
    416 		}
    417 
    418 		ei.ei_addr = ep->ep_addr;
    419 		ei.ei_len = ep->ep_len;
    420 		ei.ei_callback = NULL;
    421 
    422 		err = flash_erase(sc->sc_dev, &ei);
    423 		if (err) {
    424 			return err;
    425 		}
    426 
    427 		break;
    428 	case FLASH_BLOCK_ISBAD:
    429 		/**
    430 		 * Set up an erase instruction then call the registered
    431 		 * driver's erase operation.
    432 		 */
    433 		bbp = data;
    434 
    435 		err = flash_block_isbad(sc->sc_dev, bbp->bbp_addr, &bad);
    436 		if (err) {
    437 			return err;
    438 		}
    439 		bbp->bbp_isbad = bad;
    440 
    441 		break;
    442 	case FLASH_BLOCK_MARKBAD:
    443 		bbp = data;
    444 
    445 		err = flash_block_markbad(sc->sc_dev, bbp->bbp_addr);
    446 
    447 		break;
    448 	case FLASH_DUMP:
    449 		dp = data;
    450 		offset = dp->dp_block * sc->flash_if->erasesize;
    451 		FLDPRINTF(("Reading from block: %jd len: %jd\n",
    452 			(intmax_t )dp->dp_block, (intmax_t )dp->dp_len));
    453 		err = flash_read(sc->sc_parent_dev, offset, dp->dp_len,
    454 		    &retlen, dp->dp_buf);
    455 		if (err)
    456 			return err;
    457 		if (retlen != dp->dp_len) {
    458 			dp->dp_len = -1;
    459 			dp->dp_buf = NULL;
    460 		}
    461 
    462 		break;
    463 	case FLASH_GET_INFO:
    464 		ip = data;
    465 
    466 		ip->ip_page_size = sc->flash_if->page_size;
    467 		ip->ip_erase_size = sc->flash_if->erasesize;
    468 		ip->ip_flash_type = sc->flash_if->type;
    469 		ip->ip_flash_size = sc->sc_partinfo.part_size;
    470 		break;
    471 	default:
    472 		err = ENODEV;
    473 	}
    474 
    475 	return err;
    476 }
    477 
    478 int
    479 flashdump(dev_t dev, daddr_t blkno, void *va, size_t size)
    480 {
    481 	return EACCES;
    482 }
    483 
    484 bool
    485 flash_shutdown(device_t self, int how)
    486 {
    487 	struct flash_softc * const sc = device_private(self);
    488 
    489 	if ((how & RB_NOSYNC) == 0 && !sc->sc_readonly)
    490 		flash_sync(self);
    491 
    492 	return true;
    493 }
    494 
    495 const struct flash_interface *
    496 flash_get_interface(dev_t dev)
    497 {
    498 	struct flash_softc *sc;
    499 	int unit;
    500 
    501 	unit = minor(dev);
    502 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    503 		return NULL;
    504 
    505 	return sc->flash_if;
    506 }
    507 
    508 const struct flash_softc *
    509 flash_get_softc(dev_t dev)
    510 {
    511 	struct flash_softc *sc;
    512 	int unit;
    513 
    514 	unit = minor(dev);
    515 	sc = device_lookup_private(&flash_cd, unit);
    516 
    517 	return sc;
    518 }
    519 
    520 device_t
    521 flash_get_device(dev_t dev)
    522 {
    523 	struct flash_softc *sc;
    524 	int unit;
    525 
    526 	unit = minor(dev);
    527 	sc = device_lookup_private(&flash_cd, unit);
    528 
    529 	return sc->sc_dev;
    530 }
    531 
    532 flash_size_t
    533 flash_get_size(dev_t dev)
    534 {
    535 	const struct flash_softc *sc;
    536 
    537 	sc = flash_get_softc(dev);
    538 
    539 	return sc->sc_partinfo.part_size;
    540 }
    541 
    542 int
    543 flash_erase(device_t self, struct flash_erase_instruction * const ei)
    544 {
    545 	struct flash_softc * const sc = device_private(self);
    546 	KASSERT(ei != NULL);
    547 	struct flash_erase_instruction e = *ei;
    548 
    549 	if (sc->sc_readonly)
    550 		return EACCES;
    551 
    552 	/* adjust for flash partition */
    553 	e.ei_addr += sc->sc_partinfo.part_offset;
    554 
    555 	/* bounds check for flash partition */
    556 	if (e.ei_addr + e.ei_len > sc->sc_partinfo.part_size +
    557 	    sc->sc_partinfo.part_offset)
    558 		return EINVAL;
    559 
    560 	return sc->flash_if->erase(device_parent(self), &e);
    561 }
    562 
    563 int
    564 flash_read(device_t self, flash_off_t offset, size_t len, size_t * const retlen,
    565     uint8_t * const buf)
    566 {
    567 	struct flash_softc * const sc = device_private(self);
    568 
    569 	offset += sc->sc_partinfo.part_offset;
    570 
    571 	if (offset + len > sc->sc_partinfo.part_size +
    572 	    sc->sc_partinfo.part_offset)
    573 		return EINVAL;
    574 
    575 	return sc->flash_if->read(device_parent(self),
    576 	    offset, len, retlen, buf);
    577 }
    578 
    579 int
    580 flash_write(device_t self, flash_off_t offset, size_t len,
    581     size_t * const retlen, const uint8_t * const buf)
    582 {
    583 	struct flash_softc * const sc = device_private(self);
    584 
    585 	if (sc->sc_readonly)
    586 		return EACCES;
    587 
    588 	offset += sc->sc_partinfo.part_offset;
    589 
    590 	if (offset + len > sc->sc_partinfo.part_size +
    591 	    sc->sc_partinfo.part_offset)
    592 		return EINVAL;
    593 
    594 	return sc->flash_if->write(device_parent(self),
    595 	    offset, len, retlen, buf);
    596 }
    597 
    598 int
    599 flash_block_markbad(device_t self, flash_off_t offset)
    600 {
    601 	struct flash_softc * const sc = device_private(self);
    602 
    603 	if (sc->sc_readonly)
    604 		return EACCES;
    605 
    606 	offset += sc->sc_partinfo.part_offset;
    607 
    608 	if (offset + sc->flash_if->erasesize >=
    609 	    sc->sc_partinfo.part_size +
    610 	    sc->sc_partinfo.part_offset)
    611 		return EINVAL;
    612 
    613 	return sc->flash_if->block_markbad(device_parent(self), offset);
    614 }
    615 
    616 int
    617 flash_block_isbad(device_t self, flash_off_t offset, bool * const bad)
    618 {
    619 	struct flash_softc * const sc = device_private(self);
    620 
    621 	offset += sc->sc_partinfo.part_offset;
    622 
    623 	if (offset + sc->flash_if->erasesize >
    624 	    sc->sc_partinfo.part_size +
    625 	    sc->sc_partinfo.part_offset)
    626 		return EINVAL;
    627 
    628 	return sc->flash_if->block_isbad(device_parent(self), offset, bad);
    629 }
    630 
    631 int
    632 flash_sync(device_t self)
    633 {
    634 	struct flash_softc * const sc = device_private(self);
    635 
    636 	if (sc->sc_readonly)
    637 		return EACCES;
    638 
    639 	/* noop now TODO: implement */
    640 	return 0;
    641 }
    642 
    643 MODULE(MODULE_CLASS_DRIVER, flash, NULL);
    644 
    645 #ifdef _MODULE
    646 #include "ioconf.c"
    647 #endif
    648 
    649 static int
    650 flash_modcmd(modcmd_t cmd, void *opaque)
    651 {
    652 	int error = 0;
    653 #ifdef _MODULE
    654 	int bmaj = -1, cmaj = -1;
    655 #endif
    656 
    657 	switch (cmd) {
    658 	case MODULE_CMD_INIT:
    659 #ifdef _MODULE
    660 		error = config_init_component(cfdriver_ioconf_flash,
    661 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    662 		if (error)
    663 			return error;
    664 		error = devsw_attach("flash", &flash_bdevsw, &bmaj,
    665 		    &flash_cdevsw, &cmaj);
    666 		if (error)
    667 			config_fini_component(cfdriver_ioconf_flash,
    668 			    cfattach_ioconf_flash, cfdata_ioconf_flash);
    669 #endif
    670 		return error;
    671 	case MODULE_CMD_FINI:
    672 #ifdef _MODULE
    673 		devsw_detach(&flash_bdevsw, &flash_cdevsw);
    674 		error = config_fini_component(cfdriver_ioconf_flash,
    675 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    676 #endif
    677 		return error;
    678 	default:
    679 		return ENOTTY;
    680 	}
    681 }
    682