Home | History | Annotate | Line # | Download | only in flash
flash.c revision 1.1.4.3
      1 /*	$NetBSD: flash.c,v 1.1.4.3 2011/04/21 01:41:46 rmind 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.1.4.3 2011/04/21 01:41:46 rmind 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 	printf("freeing flash_if...");
    220 	kmem_free(sc->flash_if, sizeof(*sc->flash_if));
    221 	printf("done!\n");
    222 
    223 	return 0;
    224 }
    225 
    226 int
    227 flash_print(void *aux, const char *pnp)
    228 {
    229 	struct flash_attach_args *arg;
    230 	const char *type;
    231 
    232 	if (pnp != NULL) {
    233 		arg = aux;
    234 		switch (arg->flash_if->type) {
    235 		case FLASH_TYPE_NOR:
    236 			type = "NOR";
    237 			break;
    238 		case FLASH_TYPE_NAND:
    239 			type = "NAND";
    240 			break;
    241 		default:
    242 			panic("flash_print: unknown type %d",
    243 			    arg->flash_if->type);
    244 		}
    245 		aprint_normal("%s flash at %s", type, pnp);
    246 	}
    247 	return UNCONF;
    248 }
    249 
    250 device_t
    251 flash_attach_mi(struct flash_interface *flash_if, device_t device)
    252 {
    253 	struct flash_attach_args arg;
    254 
    255 #ifdef DIAGNOSTIC
    256 	if (flash_if == NULL) {
    257 		aprint_error("flash_attach_mi: NULL\n");
    258 		return 0;
    259 	}
    260 #endif
    261 	arg.flash_if = flash_if;
    262 
    263 	return config_found_ia(device, "flashbus", &arg, flash_print);
    264 }
    265 
    266 /**
    267  * flash_open - open the character device
    268  * Checks if there is a driver registered to the minor number of the open
    269  * request.
    270  */
    271 int
    272 flashopen(dev_t dev, int flags, int fmt, struct lwp *l)
    273 {
    274 	int unit = minor(dev);
    275 	struct flash_softc *sc;
    276 
    277 	DPRINTFN(1, ("flash: opening device unit %d\n", unit));
    278 
    279 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    280 		return ENXIO;
    281 
    282 	/* TODO return eperm if want to open for writing a read only dev */
    283 
    284 	/* reset buffer length */
    285 //	sc->sc_cache->fc_len = 0;
    286 
    287 	return 0;
    288 }
    289 
    290 /**
    291  * flash_close - close device
    292  * We don't have to release any resources, so just return 0.
    293  */
    294 int
    295 flashclose(dev_t dev, int flags, int fmt, struct lwp *l)
    296 {
    297 	int unit = minor(dev);
    298 	struct flash_softc *sc;
    299 	int err;
    300 
    301 	DPRINTFN(1, ("flash: closing flash device unit %d\n", unit));
    302 
    303 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    304 		return ENXIO;
    305 
    306 	if (!sc->sc_readonly) {
    307 		err = flash_sync(sc->sc_dev);
    308 		if (err)
    309 			return err;
    310 	}
    311 
    312 	return 0;
    313 }
    314 
    315 /**
    316  * flash_read - read from character device
    317  * This function uses the registered driver's read function to read the requested length to
    318  * a buffer and then moves this buffer to userspace.
    319  */
    320 int
    321 flashread(dev_t dev, struct uio *uio, int flag)
    322 {
    323 	return physio(flashstrategy, NULL, dev, B_READ, minphys, uio);
    324 }
    325 
    326 /**
    327  * flash_write - write to character device
    328  * This function moves the data into a buffer from userspace to kernel space,
    329  * then uses the registered driver's write function to write out the data to
    330  * the media.
    331  */
    332 int
    333 flashwrite(dev_t dev, struct uio *uio, int flag)
    334 {
    335 	return physio(flashstrategy, NULL, dev, B_WRITE, minphys, uio);
    336 }
    337 
    338 void
    339 flashstrategy(struct buf *bp)
    340 {
    341 	struct flash_softc *sc;
    342 	const struct flash_interface *flash_if;
    343 	const struct flash_partition *part;
    344 	int unit, device_blks;
    345 
    346 	unit = minor(bp->b_dev);
    347 	sc = device_lookup_private(&flash_cd, unit);
    348 	if (sc == NULL) {
    349 		bp->b_error = ENXIO;
    350 		goto done;
    351 	}
    352 
    353 	flash_if = sc->flash_if;
    354 	part = &flash_if->partition;
    355 
    356 	/* divider */
    357 	KASSERT(flash_if->writesize != 0);
    358 
    359 	aprint_debug_dev(sc->sc_dev, "flash_strategy()\n");
    360 
    361 	if (!(bp->b_flags & B_READ) && sc->sc_readonly) {
    362 		bp->b_error = EACCES;
    363 		goto done;
    364 	}
    365 
    366 	/* check if length is not negative */
    367 	if (bp->b_blkno < 0) {
    368 		bp->b_error = EINVAL;
    369 		goto done;
    370 	}
    371 
    372 	/* zero lenght i/o */
    373 	if (bp->b_bcount == 0) {
    374 		goto done;
    375 	}
    376 
    377 	device_blks = sc->flash_if->size / DEV_BSIZE;
    378 	KASSERT(part->part_offset % DEV_BSIZE == 0);
    379 	bp->b_rawblkno = bp->b_blkno + (part->part_offset / DEV_BSIZE);
    380 
    381 	if (bounds_check_with_mediasize(bp, DEV_BSIZE, device_blks) <= 0) {
    382 		goto done;
    383 	}
    384 
    385 	bp->b_resid = bp->b_bcount;
    386 	flash_if->submit(sc->sc_parent_dev, bp);
    387 
    388 	return;
    389 done:
    390 	bp->b_resid = bp->b_bcount;
    391 	biodone(bp);
    392 }
    393 
    394 /*
    395  * Handle the ioctl for the device
    396  */
    397 int
    398 flashioctl(dev_t dev, u_long command, void *data, int flags, struct lwp *l)
    399 {
    400 	struct flash_erase_params *ep;
    401 	struct flash_info_params *ip;
    402 	struct flash_dump_params *dp;
    403 	struct flash_badblock_params *bbp;
    404 	struct flash_erase_instruction ei;
    405 	struct flash_softc *sc;
    406 	int unit, err;
    407 	size_t retlen;
    408 	flash_off_t offset;
    409 	bool bad;
    410 
    411 	unit = minor(dev);
    412 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    413 		return ENXIO;
    414 
    415 	err = 0;
    416 	switch (command) {
    417 	case FLASH_ERASE_BLOCK:
    418 		/**
    419 		 * Set up an erase instruction then call the registered
    420 		 * driver's erase operation.
    421 		 */
    422 		ep = data;
    423 
    424 		if (sc->sc_readonly) {
    425 			return EACCES;
    426 		}
    427 
    428 		ei.ei_addr = ep->ep_addr;
    429 		ei.ei_len = ep->ep_len;
    430 		ei.ei_callback = NULL;
    431 
    432 		err = flash_erase(sc->sc_dev, &ei);
    433 		if (err) {
    434 			return err;
    435 		}
    436 
    437 		break;
    438 	case FLASH_BLOCK_ISBAD:
    439 		/**
    440 		 * Set up an erase instruction then call the registered
    441 		 * driver's erase operation.
    442 		 */
    443 		bbp = data;
    444 
    445 		err = flash_block_isbad(sc->sc_dev, bbp->bbp_addr, &bad);
    446 		if (err) {
    447 			return err;
    448 		}
    449 		bbp->bbp_isbad = bad;
    450 
    451 		break;
    452 	case FLASH_BLOCK_MARKBAD:
    453 		bbp = data;
    454 
    455 		err = flash_block_markbad(sc->sc_dev, bbp->bbp_addr);
    456 
    457 		break;
    458 	case FLASH_DUMP:
    459 		dp = data;
    460 		offset = dp->dp_block * sc->flash_if->erasesize;
    461 		DPRINTF(("Reading from block: %jd len: %jd\n",
    462 			(intmax_t )dp->dp_block, (intmax_t )dp->dp_len));
    463 		err = flash_read(sc->sc_parent_dev, offset, dp->dp_len,
    464 		    &retlen, dp->dp_buf);
    465 		if (err)
    466 			return err;
    467 		if (retlen != dp->dp_len) {
    468 			dp->dp_len = -1;
    469 			dp->dp_buf = NULL;
    470 		}
    471 
    472 		break;
    473 	case FLASH_GET_INFO:
    474 		ip = data;
    475 
    476 		ip->ip_page_size = sc->flash_if->page_size;
    477 		ip->ip_erase_size = sc->flash_if->erasesize;
    478 		ip->ip_flash_type = sc->flash_if->type;
    479 		ip->ip_flash_size = sc->flash_if->size;
    480 		break;
    481 	default:
    482 		err = ENODEV;
    483 	}
    484 
    485 	return err;
    486 }
    487 
    488 int
    489 flashsize(dev_t dev)
    490 {
    491     return -1;
    492 }
    493 
    494 int
    495 flashdump(dev_t dev, daddr_t blkno, void *va, size_t size)
    496 {
    497     return EACCES;
    498 }
    499 
    500 bool
    501 flash_shutdown(device_t self, int how)
    502 {
    503 	struct flash_softc *sc = device_private(self);
    504 
    505 	if ((how & RB_NOSYNC) == 0 && !sc->sc_readonly)
    506 		flash_sync(self);
    507 
    508 	return true;
    509 }
    510 
    511 const struct flash_interface *
    512 flash_get_interface(dev_t dev)
    513 {
    514 	struct flash_softc *sc;
    515 	int unit;
    516 
    517 	unit = minor(dev);
    518 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    519 		return NULL;
    520 
    521 	return sc->flash_if;
    522 }
    523 
    524 const struct flash_softc *
    525 flash_get_softc(dev_t dev)
    526 {
    527 	struct flash_softc *sc;
    528 	int unit;
    529 
    530 	unit = minor(dev);
    531 	sc = device_lookup_private(&flash_cd, unit);
    532 
    533 	return sc;
    534 }
    535 
    536 device_t
    537 flash_get_device(dev_t dev)
    538 {
    539 	struct flash_softc *sc;
    540 	int unit;
    541 
    542 	unit = minor(dev);
    543 	sc = device_lookup_private(&flash_cd, unit);
    544 
    545 	return sc->sc_dev;
    546 }
    547 
    548 static inline flash_off_t
    549 flash_get_part_offset(struct flash_softc *fl, size_t poffset)
    550 {
    551 	return fl->flash_if->partition.part_offset + poffset;
    552 }
    553 
    554 int
    555 flash_erase(device_t self, struct flash_erase_instruction *ei)
    556 {
    557 	struct flash_softc *sc = device_private(self);
    558 	KASSERT(ei != NULL);
    559 	struct flash_erase_instruction e = *ei;
    560 
    561 	if (sc->sc_readonly)
    562 		return EACCES;
    563 
    564 	/* adjust for flash partition */
    565 	e.ei_addr += sc->flash_if->partition.part_offset;
    566 
    567 	/* bounds check for flash partition */
    568 	if (e.ei_addr + e.ei_len > sc->flash_if->partition.part_size +
    569 	    sc->flash_if->partition.part_offset)
    570 		return EINVAL;
    571 
    572 	return sc->flash_if->erase(device_parent(self), &e);
    573 }
    574 
    575 int
    576 flash_read(device_t self,
    577     flash_off_t offset, size_t len, size_t *retlen, uint8_t *buf)
    578 {
    579 	struct flash_softc *sc = device_private(self);
    580 
    581 	offset += sc->flash_if->partition.part_offset;
    582 
    583 	if (offset + len > sc->flash_if->partition.part_size +
    584 	    sc->flash_if->partition.part_offset)
    585 		return EINVAL;
    586 
    587 	return sc->flash_if->read(device_parent(self),
    588 	    offset, len, retlen, buf);
    589 }
    590 
    591 int
    592 flash_write(device_t self,
    593     flash_off_t offset, size_t len, size_t *retlen, const uint8_t *buf)
    594 {
    595 	struct flash_softc *sc = device_private(self);
    596 
    597 	if (sc->sc_readonly)
    598 		return EACCES;
    599 
    600 	offset += sc->flash_if->partition.part_offset;
    601 
    602 	if (offset + len > sc->flash_if->partition.part_size +
    603 	    sc->flash_if->partition.part_offset)
    604 		return EINVAL;
    605 
    606 	return sc->flash_if->write(device_parent(self),
    607 	    offset, len, retlen, buf);
    608 }
    609 
    610 int
    611 flash_block_markbad(device_t self, flash_off_t offset)
    612 {
    613 	struct flash_softc *sc = device_private(self);
    614 
    615 	if (sc->sc_readonly)
    616 		return EACCES;
    617 
    618 	offset += sc->flash_if->partition.part_offset;
    619 
    620 	if (offset + sc->flash_if->erasesize >=
    621 	    sc->flash_if->partition.part_size +
    622 	    sc->flash_if->partition.part_offset)
    623 		return EINVAL;
    624 
    625 	return sc->flash_if->block_markbad(device_parent(self), offset);
    626 }
    627 
    628 int
    629 flash_block_isbad(device_t self, flash_off_t offset, bool *bad)
    630 {
    631 	struct flash_softc *sc = device_private(self);
    632 
    633 	offset += sc->flash_if->partition.part_offset;
    634 
    635 	if (offset + sc->flash_if->erasesize >
    636 	    sc->flash_if->partition.part_size +
    637 	    sc->flash_if->partition.part_offset)
    638 		return EINVAL;
    639 
    640 	return sc->flash_if->block_isbad(device_parent(self), offset, bad);
    641 }
    642 
    643 int
    644 flash_sync(device_t self)
    645 {
    646 	struct flash_softc *sc = device_private(self);
    647 
    648 	if (sc->sc_readonly)
    649 		return EACCES;
    650 
    651 	/* noop now TODO: implement */
    652 	return 0;
    653 }
    654 
    655 MODULE(MODULE_CLASS_DRIVER, flash, NULL);
    656 
    657 #ifdef _MODULE
    658 #include "ioconf.c"
    659 #endif
    660 
    661 static int
    662 flash_modcmd(modcmd_t cmd, void *opaque)
    663 {
    664 	int error = 0;
    665 #ifdef _MODULE
    666 	int bmaj = -1, cmaj = -1;
    667 #endif
    668 
    669 	switch (cmd) {
    670 	case MODULE_CMD_INIT:
    671 #ifdef _MODULE
    672 		error = config_init_component(cfdriver_ioconf_flash,
    673 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    674 		if (error)
    675 			return error;
    676 		error = devsw_attach("flash", &flash_bdevsw, &bmaj,
    677 		    &flash_cdevsw, &cmaj);
    678 		if (error)
    679 			config_fini_component(cfdriver_ioconf_flash,
    680 			    cfattach_ioconf_flash, cfdata_ioconf_flash);
    681 #endif
    682 		return error;
    683 	case MODULE_CMD_FINI:
    684 #ifdef _MODULE
    685 		devsw_detach(&flash_bdevsw, &flash_cdevsw);
    686 		error = config_fini_component(cfdriver_ioconf_flash,
    687 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    688 #endif
    689 		return error;
    690 	default:
    691 		return ENOTTY;
    692 	}
    693 }
    694