Home | History | Annotate | Line # | Download | only in flash
flash.c revision 1.2
      1 /*	$NetBSD: flash.c,v 1.2 2011/03/30 14:34:26 uebayasi 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.2 2011/03/30 14:34:26 uebayasi 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 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_addr_t offset;
    409 
    410 	unit = minor(dev);
    411 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    412 		return ENXIO;
    413 
    414 	err = 0;
    415 	switch (command) {
    416 	case FLASH_ERASE_BLOCK:
    417 		/**
    418 		 * Set up an erase instruction then call the registered
    419 		 * driver's erase operation.
    420 		 */
    421 		ep = data;
    422 
    423 		if (sc->sc_readonly) {
    424 			return EACCES;
    425 		}
    426 
    427 		ei.ei_addr = ep->ep_addr;
    428 		ei.ei_len = ep->ep_len;
    429 		ei.ei_callback = NULL;
    430 
    431 		err = flash_erase(sc->sc_dev, &ei);
    432 		if (err) {
    433 			return err;
    434 		}
    435 
    436 		break;
    437 	case FLASH_BLOCK_ISBAD:
    438 		/**
    439 		 * Set up an erase instruction then call the registered
    440 		 * driver's erase operation.
    441 		 */
    442 		bbp = data;
    443 
    444 		err = flash_block_isbad(sc->sc_dev, bbp->bbp_addr);
    445 		if (err == EIO) {
    446 			bbp->bbp_isbad = true;
    447 			err = 0;
    448 		} else if (err) {
    449 			return err;
    450 		} else {
    451 			bbp->bbp_isbad = false;
    452 		}
    453 
    454 		break;
    455 	case FLASH_BLOCK_MARKBAD:
    456 		bbp = data;
    457 
    458 		err = flash_block_markbad(sc->sc_dev, bbp->bbp_addr);
    459 
    460 		break;
    461 	case FLASH_DUMP:
    462 		dp = data;
    463 		offset = dp->dp_block * sc->flash_if->erasesize;
    464 		DPRINTF(("Reading from block: %jd len: %jd\n",
    465 			(intmax_t )dp->dp_block, (intmax_t )dp->dp_len));
    466 		err = flash_read(sc->sc_parent_dev, offset, dp->dp_len,
    467 		    &retlen, dp->dp_buf);
    468 		if (err)
    469 			return err;
    470 		if (retlen != dp->dp_len) {
    471 			dp->dp_len = -1;
    472 			dp->dp_buf = NULL;
    473 		}
    474 
    475 		break;
    476 	case FLASH_GET_INFO:
    477 		ip = data;
    478 
    479 		ip->ip_page_size = sc->flash_if->page_size;
    480 		ip->ip_erase_size = sc->flash_if->erasesize;
    481 		ip->ip_flash_type = sc->flash_if->type;
    482 		ip->ip_flash_size = sc->flash_if->size;
    483 		break;
    484 	default:
    485 		err = ENODEV;
    486 	}
    487 
    488 	return err;
    489 }
    490 
    491 int
    492 flashsize(dev_t dev)
    493 {
    494     return -1;
    495 }
    496 
    497 int
    498 flashdump(dev_t dev, daddr_t blkno, void *va, size_t size)
    499 {
    500     return EACCES;
    501 }
    502 
    503 bool
    504 flash_shutdown(device_t self, int how)
    505 {
    506 	struct flash_softc *sc = device_private(self);
    507 
    508 	if ((how & RB_NOSYNC) == 0 && !sc->sc_readonly)
    509 		flash_sync(self);
    510 
    511 	return true;
    512 }
    513 
    514 const struct flash_interface *
    515 flash_get_interface(dev_t dev)
    516 {
    517 	struct flash_softc *sc;
    518 	int unit;
    519 
    520 	unit = minor(dev);
    521 	if ((sc = device_lookup_private(&flash_cd, unit)) == NULL)
    522 		return NULL;
    523 
    524 	return sc->flash_if;
    525 }
    526 
    527 const struct flash_softc *
    528 flash_get_softc(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;
    537 }
    538 
    539 device_t
    540 flash_get_device(dev_t dev)
    541 {
    542 	struct flash_softc *sc;
    543 	int unit;
    544 
    545 	unit = minor(dev);
    546 	sc = device_lookup_private(&flash_cd, unit);
    547 
    548 	return sc->sc_dev;
    549 }
    550 
    551 static inline off_t
    552 flash_get_part_offset(struct flash_softc *fl, size_t poffset)
    553 {
    554 	return fl->flash_if->partition.part_offset + poffset;
    555 }
    556 
    557 int
    558 flash_erase(device_t self, struct flash_erase_instruction *ei)
    559 {
    560 	struct flash_softc *sc = device_private(self);
    561 	KASSERT(ei != NULL);
    562 	struct flash_erase_instruction e = *ei;
    563 
    564 	if (sc->sc_readonly)
    565 		return EACCES;
    566 
    567 	/* adjust for flash partition */
    568 	e.ei_addr += sc->flash_if->partition.part_offset;
    569 
    570 	/* bounds check for flash partition */
    571 	if (e.ei_addr + e.ei_len > sc->flash_if->partition.part_size +
    572 	    sc->flash_if->partition.part_offset)
    573 		return EINVAL;
    574 
    575 	return sc->flash_if->erase(device_parent(self), &e);
    576 }
    577 
    578 int
    579 flash_read(device_t self,
    580     off_t offset, size_t len, size_t *retlen, uint8_t *buf)
    581 {
    582 	struct flash_softc *sc = device_private(self);
    583 
    584 	offset += sc->flash_if->partition.part_offset;
    585 
    586 	if (offset + len > sc->flash_if->partition.part_size +
    587 	    sc->flash_if->partition.part_offset)
    588 		return EINVAL;
    589 
    590 	return sc->flash_if->read(device_parent(self),
    591 	    offset, len, retlen, buf);
    592 }
    593 
    594 int
    595 flash_write(device_t self,
    596     off_t offset, size_t len, size_t *retlen, const uint8_t *buf)
    597 {
    598 	struct flash_softc *sc = device_private(self);
    599 
    600 	if (sc->sc_readonly)
    601 		return EACCES;
    602 
    603 	offset += sc->flash_if->partition.part_offset;
    604 
    605 	if (offset + len > sc->flash_if->partition.part_size +
    606 	    sc->flash_if->partition.part_offset)
    607 		return EINVAL;
    608 
    609 	return sc->flash_if->write(device_parent(self),
    610 	    offset, len, retlen, buf);
    611 }
    612 
    613 int
    614 flash_block_markbad(device_t self, uint64_t offset)
    615 {
    616 	struct flash_softc *sc = device_private(self);
    617 
    618 	if (sc->sc_readonly)
    619 		return EACCES;
    620 
    621 	offset += sc->flash_if->partition.part_offset;
    622 
    623 	if (offset + sc->flash_if->erasesize >=
    624 	    sc->flash_if->partition.part_size +
    625 	    sc->flash_if->partition.part_offset)
    626 		return EINVAL;
    627 
    628 	return sc->flash_if->block_markbad(device_parent(self), offset);
    629 }
    630 
    631 int
    632 flash_block_isbad(device_t self, uint64_t offset)
    633 {
    634 	struct flash_softc *sc = device_private(self);
    635 
    636 	offset += sc->flash_if->partition.part_offset;
    637 
    638 	if (offset + sc->flash_if->erasesize >
    639 	    sc->flash_if->partition.part_size +
    640 	    sc->flash_if->partition.part_offset)
    641 		return EINVAL;
    642 
    643 	return sc->flash_if->block_isbad(device_parent(self), offset);
    644 }
    645 
    646 int
    647 flash_sync(device_t self)
    648 {
    649 	struct flash_softc *sc = device_private(self);
    650 
    651 	if (sc->sc_readonly)
    652 		return EACCES;
    653 
    654 	/* noop now TODO: implement */
    655 	return 0;
    656 }
    657 
    658 MODULE(MODULE_CLASS_DRIVER, flash, NULL);
    659 
    660 #ifdef _MODULE
    661 #include "ioconf.c"
    662 #endif
    663 
    664 static int
    665 flash_modcmd(modcmd_t cmd, void *opaque)
    666 {
    667 	int error = 0;
    668 #ifdef _MODULE
    669 	int bmaj = -1, cmaj = -1;
    670 #endif
    671 
    672 	switch (cmd) {
    673 	case MODULE_CMD_INIT:
    674 #ifdef _MODULE
    675 		error = config_init_component(cfdriver_ioconf_flash,
    676 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    677 		if (error)
    678 			return error;
    679 		error = devsw_attach("flash", &flash_bdevsw, &bmaj,
    680 		    &flash_cdevsw, &cmaj);
    681 		if (error)
    682 			config_fini_component(cfdriver_ioconf_flash,
    683 			    cfattach_ioconf_flash, cfdata_ioconf_flash);
    684 #endif
    685 		return error;
    686 	case MODULE_CMD_FINI:
    687 #ifdef _MODULE
    688 		devsw_detach(&flash_bdevsw, &flash_cdevsw);
    689 		error = config_fini_component(cfdriver_ioconf_flash,
    690 		    cfattach_ioconf_flash, cfdata_ioconf_flash);
    691 #endif
    692 		return error;
    693 	default:
    694 		return ENOTTY;
    695 	}
    696 }
    697