Home | History | Annotate | Line # | Download | only in flash
flash.c revision 1.4.4.2
      1 /*	$NetBSD: flash.c,v 1.4.4.2 2011/06/06 09:07:48 jruoho 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.4.4.2 2011/06/06 09:07:48 jruoho 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 #define FLASH_DEBUG 1
     65 #ifdef FLASH_DEBUG
     66 #define DPRINTF(x)	if (flashdebug) printf x
     67 #define DPRINTFN(n,x)	if (flashdebug>(n)) printf x
     68 int	flashdebug = FLASH_DEBUG;
     69 #else
     70 #define DPRINTF(x)
     71 #define DPRINTFN(n,x)
     72 #endif
     73 
     74 extern struct cfdriver flash_cd;
     75 
     76 dev_type_open(flashopen);
     77 dev_type_close(flashclose);
     78 dev_type_read(flashread);
     79 dev_type_write(flashwrite);
     80 dev_type_ioctl(flashioctl);
     81 dev_type_strategy(flashstrategy);
     82 dev_type_dump(flashdump);
     83 dev_type_size(flashsize);
     84 
     85 int flash_print(void *aux, const char *pnp);
     86 
     87 bool flash_shutdown(device_t dev, int how);
     88 int flash_nsectors(struct buf *bp);
     89 int flash_sector(struct buf *bp);
     90 
     91 static inline flash_off_t flash_get_part_offset(struct flash_softc *fl,
     92     size_t poffset);
     93 
     94 int flash_match(device_t parent, cfdata_t match, void *aux);
     95 void flash_attach(device_t parent, device_t self, void *aux);
     96 int flash_detach(device_t device, int flags);
     97 
     98 CFATTACH_DECL_NEW(flash, sizeof(struct flash_softc),
     99     flash_match, flash_attach, flash_detach, NULL);
    100 
    101 /**
    102  * Block device's operation
    103  */
    104 const struct bdevsw flash_bdevsw = {
    105 	.d_open = flashopen,
    106 	.d_close = flashclose,
    107 	.d_strategy = flashstrategy,
    108 	.d_ioctl = flashioctl,
    109 	.d_dump = flashdump,
    110 	.d_psize = flashsize,
    111 	.d_flag = D_DISK | D_MPSAFE
    112 };
    113 
    114 /**
    115  * Character device's operations
    116  */
    117 const struct cdevsw flash_cdevsw = {
    118 	.d_open = flashopen,
    119 	.d_close = flashclose,
    120 	.d_read = flashread,
    121 	.d_write = flashwrite,
    122 	.d_ioctl = flashioctl,
    123 	.d_stop = nostop,
    124 	.d_tty = notty,
    125 	.d_poll = nopoll,
    126 	.d_mmap = nommap,
    127 	.d_kqfilter = nokqfilter,
    128 	.d_flag = D_DISK | D_MPSAFE
    129 };
    130 
    131 /* ARGSUSED */
    132 int
    133 flash_match(device_t parent, cfdata_t match, void *aux)
    134 {
    135 	/* pseudo device, always attaches */
    136 	return 1;
    137 }
    138 
    139 /* ARGSUSED */
    140 void
    141 flash_attach(device_t parent, device_t self, void *aux)
    142 {
    143 	struct flash_softc *sc = device_private(self);
    144 	struct flash_attach_args *faa = aux;
    145 	char pbuf[2][sizeof("9999 KB")];
    146 
    147 	sc->sc_dev = self;
    148 	sc->sc_parent_dev = parent;
    149 	sc->flash_if = faa->flash_if;
    150 	sc->hw_softc = device_private(parent);
    151 
    152 	format_bytes(pbuf[0], sizeof(pbuf[0]), sc->flash_if->size);
    153 	format_bytes(pbuf[1], sizeof(pbuf[1]), sc->flash_if->erasesize);
    154 
    155 	aprint_naive("\n");
    156 
    157 	switch (sc->flash_if->type) {
    158 	case FLASH_TYPE_NOR:
    159 		aprint_normal(": %s NOR flash\n", pbuf[0]);
    160 		break;
    161 
    162 	case FLASH_TYPE_NAND:
    163 		aprint_normal(": %s NAND flash\n", pbuf[0]);
    164 		break;
    165 
    166 	default:
    167 		aprint_normal(": %s unknown flash\n", pbuf[0]);
    168 	}
    169 
    170 	aprint_normal_dev(sc->sc_dev,
    171 	    "size: 0x%jx, offset: 0x%jx",
    172 	    (uintmax_t )sc->flash_if->partition.part_size,
    173 	    (uintmax_t )sc->flash_if->partition.part_offset);
    174 
    175 	if (sc->flash_if->partition.part_flags & FLASH_PART_READONLY) {
    176 		sc->sc_readonly = true;
    177 		aprint_normal(", read only");
    178 	} else {
    179 		sc->sc_readonly = false;
    180 	}
    181 
    182 	aprint_normal("\n");
    183 
    184 	if (sc->flash_if->partition.part_size == 0) {
    185 		aprint_error_dev(self,
    186 		    "partition size must be larger than 0\n");
    187 		return;
    188 	}
    189 
    190 	switch (sc->flash_if->type) {
    191 	case FLASH_TYPE_NOR:
    192 		aprint_normal_dev(sc->sc_dev,
    193 		    "erase size %s bytes, write size %d bytes\n",
    194 		    pbuf[1], sc->flash_if->writesize);
    195 		break;
    196 
    197 	case FLASH_TYPE_NAND:
    198 	default:
    199 		aprint_normal_dev(sc->sc_dev,
    200 		    "erase size %s, page size %d bytes, write size %d bytes\n",
    201 		    pbuf[1], sc->flash_if->page_size,
    202 		    sc->flash_if->writesize);
    203 		break;
    204 	}
    205 
    206 	if (!pmf_device_register1(sc->sc_dev, NULL, NULL, flash_shutdown))
    207 		aprint_error_dev(sc->sc_dev,
    208 		    "couldn't establish power handler\n");
    209 }
    210 
    211 int
    212 flash_detach(device_t device, int flags)
    213 {
    214 	struct flash_softc *sc = device_private(device);
    215 
    216 	pmf_device_deregister(sc->sc_dev);
    217 
    218 	/* freeing flash_if is our responsibility */
    219 	kmem_free(sc->flash_if, sizeof(*sc->flash_if));
    220 
    221 	return 0;
    222 }
    223 
    224 int
    225 flash_print(void *aux, const char *pnp)
    226 {
    227 	struct flash_attach_args *arg;
    228 	const char *type;
    229 
    230 	if (pnp != NULL) {
    231 		arg = aux;
    232 		switch (arg->flash_if->type) {
    233 		case FLASH_TYPE_NOR:
    234 			type = "NOR";
    235 			break;
    236 		case FLASH_TYPE_NAND:
    237 			type = "NAND";
    238 			break;
    239 		default:
    240 			panic("flash_print: unknown type %d",
    241 			    arg->flash_if->type);
    242 		}
    243 		aprint_normal("%s flash at %s", type, pnp);
    244 	}
    245 	return UNCONF;
    246 }
    247 
    248 device_t
    249 flash_attach_mi(struct flash_interface *flash_if, device_t device)
    250 {
    251 	struct flash_attach_args arg;
    252 
    253 #ifdef DIAGNOSTIC
    254 	if (flash_if == NULL) {
    255 		aprint_error("flash_attach_mi: NULL\n");
    256 		return 0;
    257 	}
    258 #endif
    259 	arg.flash_if = flash_if;
    260 
    261 	return config_found_ia(device, "flashbus", &arg, flash_print);
    262 }
    263 
    264 /**
    265  * flash_open - open the character device
    266  * Checks if there is a driver registered to the minor number of the open
    267  * request.
    268  */
    269 int
    270 flashopen(dev_t dev, int flags, int fmt, struct lwp *l)
    271 {
    272 	int unit = minor(dev);
    273 	struct flash_softc *sc;
    274 
    275 	DPRINTFN(1, ("flash: opening device unit %d\n", unit));
    276 
    277 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    278 		return ENXIO;
    279 
    280 	/* TODO return eperm if want to open for writing a read only dev */
    281 
    282 	/* reset buffer length */
    283 //	sc->sc_cache->fc_len = 0;
    284 
    285 	return 0;
    286 }
    287 
    288 /**
    289  * flash_close - close device
    290  * We don't have to release any resources, so just return 0.
    291  */
    292 int
    293 flashclose(dev_t dev, int flags, int fmt, struct lwp *l)
    294 {
    295 	int unit = minor(dev);
    296 	struct flash_softc *sc;
    297 	int err;
    298 
    299 	DPRINTFN(1, ("flash: closing flash device unit %d\n", unit));
    300 
    301 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    302 		return ENXIO;
    303 
    304 	if (!sc->sc_readonly) {
    305 		err = flash_sync(sc->sc_dev);
    306 		if (err)
    307 			return err;
    308 	}
    309 
    310 	return 0;
    311 }
    312 
    313 /**
    314  * flash_read - read from character device
    315  * This function uses the registered driver's read function to read the requested length to
    316  * a buffer and then moves this buffer to userspace.
    317  */
    318 int
    319 flashread(dev_t dev, struct uio *uio, int flag)
    320 {
    321 	return physio(flashstrategy, NULL, dev, B_READ, minphys, uio);
    322 }
    323 
    324 /**
    325  * flash_write - write to character device
    326  * This function moves the data into a buffer from userspace to kernel space,
    327  * then uses the registered driver's write function to write out the data to
    328  * the media.
    329  */
    330 int
    331 flashwrite(dev_t dev, struct uio *uio, int flag)
    332 {
    333 	return physio(flashstrategy, NULL, dev, B_WRITE, minphys, uio);
    334 }
    335 
    336 void
    337 flashstrategy(struct buf *bp)
    338 {
    339 	struct flash_softc *sc;
    340 	const struct flash_interface *flash_if;
    341 	const struct flash_partition *part;
    342 	int unit, device_blks;
    343 
    344 	unit = minor(bp->b_dev);
    345 	sc = device_lookup_private(&flash_cd, unit);
    346 	if (sc == NULL) {
    347 		bp->b_error = ENXIO;
    348 		goto done;
    349 	}
    350 
    351 	flash_if = sc->flash_if;
    352 	part = &flash_if->partition;
    353 
    354 	/* divider */
    355 	KASSERT(flash_if->writesize != 0);
    356 
    357 	aprint_debug_dev(sc->sc_dev, "flash_strategy()\n");
    358 
    359 	if (!(bp->b_flags & B_READ) && sc->sc_readonly) {
    360 		bp->b_error = EACCES;
    361 		goto done;
    362 	}
    363 
    364 	/* check if length is not negative */
    365 	if (bp->b_blkno < 0) {
    366 		bp->b_error = EINVAL;
    367 		goto done;
    368 	}
    369 
    370 	/* zero lenght i/o */
    371 	if (bp->b_bcount == 0) {
    372 		goto done;
    373 	}
    374 
    375 	device_blks = sc->flash_if->size / DEV_BSIZE;
    376 	KASSERT(part->part_offset % DEV_BSIZE == 0);
    377 	bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE);
    378 
    379 	if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) {
    380 		goto done;
    381 	}
    382 
    383 	bp->b_resid = bp->b_bcount;
    384 	flash_if->submit(sc->sc_parent_dev, bp);
    385 
    386 	return;
    387 done:
    388 	bp->b_resid = bp->b_bcount;
    389 	biodone(bp);
    390 }
    391 
    392 /*
    393  * Handle the ioctl for the device
    394  */
    395 int
    396 flashioctl(dev_t dev, u_long command, void *data, int flags, struct lwp *l)
    397 {
    398 	struct flash_erase_params *ep;
    399 	struct flash_info_params *ip;
    400 	struct flash_dump_params *dp;
    401 	struct flash_badblock_params *bbp;
    402 	struct flash_erase_instruction ei;
    403 	struct flash_softc *sc;
    404 	int unit, err;
    405 	size_t retlen;
    406 	flash_off_t offset;
    407 	bool bad;
    408 
    409 	unit = minor(dev);
    410 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    411 		return ENXIO;
    412 
    413 	err = 0;
    414 	switch (command) {
    415 	case FLASH_ERASE_BLOCK:
    416 		/**
    417 		 * Set up an erase instruction then call the registered
    418 		 * driver's erase operation.
    419 		 */
    420 		ep = data;
    421 
    422 		if (sc->sc_readonly) {
    423 			return EACCES;
    424 		}
    425 
    426 		ei.ei_addr = ep->ep_addr;
    427 		ei.ei_len = ep->ep_len;
    428 		ei.ei_callback = NULL;
    429 
    430 		err = flash_erase(sc->sc_dev, &ei);
    431 		if (err) {
    432 			return err;
    433 		}
    434 
    435 		break;
    436 	case FLASH_BLOCK_ISBAD:
    437 		/**
    438 		 * Set up an erase instruction then call the registered
    439 		 * driver's erase operation.
    440 		 */
    441 		bbp = data;
    442 
    443 		err = flash_block_isbad(sc->sc_dev, bbp->bbp_addr, &bad);
    444 		if (err) {
    445 			return err;
    446 		}
    447 		bbp->bbp_isbad = bad;
    448 
    449 		break;
    450 	case FLASH_BLOCK_MARKBAD:
    451 		bbp = data;
    452 
    453 		err = flash_block_markbad(sc->sc_dev, bbp->bbp_addr);
    454 
    455 		break;
    456 	case FLASH_DUMP:
    457 		dp = data;
    458 		offset = dp->dp_block * sc->flash_if->erasesize;
    459 		DPRINTF(("Reading from block: %jd len: %jd\n",
    460 			(intmax_t )dp->dp_block, (intmax_t )dp->dp_len));
    461 		err = flash_read(sc->sc_parent_dev, offset, dp->dp_len,
    462 		    &retlen, dp->dp_buf);
    463 		if (err)
    464 			return err;
    465 		if (retlen != dp->dp_len) {
    466 			dp->dp_len = -1;
    467 			dp->dp_buf = NULL;
    468 		}
    469 
    470 		break;
    471 	case FLASH_GET_INFO:
    472 		ip = data;
    473 
    474 		ip->ip_page_size = sc->flash_if->page_size;
    475 		ip->ip_erase_size = sc->flash_if->erasesize;
    476 		ip->ip_flash_type = sc->flash_if->type;
    477 		ip->ip_flash_size = sc->flash_if->size;
    478 		break;
    479 	default:
    480 		err = ENODEV;
    481 	}
    482 
    483 	return err;
    484 }
    485 
    486 int
    487 flashsize(dev_t dev)
    488 {
    489     return -1;
    490 }
    491 
    492 int
    493 flashdump(dev_t dev, daddr_t blkno, void *va, size_t size)
    494 {
    495     return EACCES;
    496 }
    497 
    498 bool
    499 flash_shutdown(device_t self, int how)
    500 {
    501 	struct flash_softc *sc = device_private(self);
    502 
    503 	if ((how & RB_NOSYNC) == 0 && !sc->sc_readonly)
    504 		flash_sync(self);
    505 
    506 	return true;
    507 }
    508 
    509 const struct flash_interface *
    510 flash_get_interface(dev_t dev)
    511 {
    512 	struct flash_softc *sc;
    513 	int unit;
    514 
    515 	unit = minor(dev);
    516 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    517 		return NULL;
    518 
    519 	return sc->flash_if;
    520 }
    521 
    522 const struct flash_softc *
    523 flash_get_softc(dev_t dev)
    524 {
    525 	struct flash_softc *sc;
    526 	int unit;
    527 
    528 	unit = minor(dev);
    529 	sc = device_lookup_private(&flash_cd, unit);
    530 
    531 	return sc;
    532 }
    533 
    534 device_t
    535 flash_get_device(dev_t dev)
    536 {
    537 	struct flash_softc *sc;
    538 	int unit;
    539 
    540 	unit = minor(dev);
    541 	sc = device_lookup_private(&flash_cd, unit);
    542 
    543 	return sc->sc_dev;
    544 }
    545 
    546 static inline flash_off_t
    547 flash_get_part_offset(struct flash_softc *fl, size_t poffset)
    548 {
    549 	return fl->flash_if->partition.part_offset + poffset;
    550 }
    551 
    552 int
    553 flash_erase(device_t self, struct flash_erase_instruction *ei)
    554 {
    555 	struct flash_softc *sc = device_private(self);
    556 	KASSERT(ei != NULL);
    557 	struct flash_erase_instruction e = *ei;
    558 
    559 	if (sc->sc_readonly)
    560 		return EACCES;
    561 
    562 	/* adjust for flash partition */
    563 	e.ei_addr += sc->flash_if->partition.part_offset;
    564 
    565 	/* bounds check for flash partition */
    566 	if (e.ei_addr + e.ei_len > sc->flash_if->partition.part_size +
    567 	    sc->flash_if->partition.part_offset)
    568 		return EINVAL;
    569 
    570 	return sc->flash_if->erase(device_parent(self), &e);
    571 }
    572 
    573 int
    574 flash_read(device_t self,
    575     flash_off_t offset, size_t len, size_t *retlen, uint8_t *buf)
    576 {
    577 	struct flash_softc *sc = device_private(self);
    578 
    579 	offset += sc->flash_if->partition.part_offset;
    580 
    581 	if (offset + len > sc->flash_if->partition.part_size +
    582 	    sc->flash_if->partition.part_offset)
    583 		return EINVAL;
    584 
    585 	return sc->flash_if->read(device_parent(self),
    586 	    offset, len, retlen, buf);
    587 }
    588 
    589 int
    590 flash_write(device_t self,
    591     flash_off_t offset, size_t len, size_t *retlen, const uint8_t *buf)
    592 {
    593 	struct flash_softc *sc = device_private(self);
    594 
    595 	if (sc->sc_readonly)
    596 		return EACCES;
    597 
    598 	offset += sc->flash_if->partition.part_offset;
    599 
    600 	if (offset + len > sc->flash_if->partition.part_size +
    601 	    sc->flash_if->partition.part_offset)
    602 		return EINVAL;
    603 
    604 	return sc->flash_if->write(device_parent(self),
    605 	    offset, len, retlen, buf);
    606 }
    607 
    608 int
    609 flash_block_markbad(device_t self, flash_off_t offset)
    610 {
    611 	struct flash_softc *sc = device_private(self);
    612 
    613 	if (sc->sc_readonly)
    614 		return EACCES;
    615 
    616 	offset += sc->flash_if->partition.part_offset;
    617 
    618 	if (offset + sc->flash_if->erasesize >=
    619 	    sc->flash_if->partition.part_size +
    620 	    sc->flash_if->partition.part_offset)
    621 		return EINVAL;
    622 
    623 	return sc->flash_if->block_markbad(device_parent(self), offset);
    624 }
    625 
    626 int
    627 flash_block_isbad(device_t self, flash_off_t offset, bool *bad)
    628 {
    629 	struct flash_softc *sc = device_private(self);
    630 
    631 	offset += sc->flash_if->partition.part_offset;
    632 
    633 	if (offset + sc->flash_if->erasesize >
    634 	    sc->flash_if->partition.part_size +
    635 	    sc->flash_if->partition.part_offset)
    636 		return EINVAL;
    637 
    638 	return sc->flash_if->block_isbad(device_parent(self), offset, bad);
    639 }
    640 
    641 int
    642 flash_sync(device_t self)
    643 {
    644 	struct flash_softc *sc = device_private(self);
    645 
    646 	if (sc->sc_readonly)
    647 		return EACCES;
    648 
    649 	/* noop now TODO: implement */
    650 	return 0;
    651 }
    652 
    653 MODULE(MODULE_CLASS_DRIVER, flash, NULL);
    654 
    655 #ifdef _MODULE
    656 #include "ioconf.c"
    657 #endif
    658 
    659 static int
    660 flash_modcmd(modcmd_t cmd, void *opaque)
    661 {
    662 	int error = 0;
    663 #ifdef _MODULE
    664 	int bmaj = -1, cmaj = -1;
    665 #endif
    666 
    667 	switch (cmd) {
    668 	case MODULE_CMD_INIT:
    669 #ifdef _MODULE
    670 		error = config_init_component(cfdriver_ioconf_flash,
    671 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    672 		if (error)
    673 			return error;
    674 		error = devsw_attach("flash", &flash_bdevsw, &bmaj,
    675 		    &flash_cdevsw, &cmaj);
    676 		if (error)
    677 			config_fini_component(cfdriver_ioconf_flash,
    678 			    cfattach_ioconf_flash, cfdata_ioconf_flash);
    679 #endif
    680 		return error;
    681 	case MODULE_CMD_FINI:
    682 #ifdef _MODULE
    683 		devsw_detach(&flash_bdevsw, &flash_cdevsw);
    684 		error = config_fini_component(cfdriver_ioconf_flash,
    685 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    686 #endif
    687 		return error;
    688 	default:
    689 		return ENOTTY;
    690 	}
    691 }
    692