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