From owner-svn-src-head@FreeBSD.ORG Mon Mar 9 23:16:02 2009 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id BB95F106564A; Mon, 9 Mar 2009 23:16:02 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id A89E48FC12; Mon, 9 Mar 2009 23:16:02 +0000 (UTC) (envelope-from sam@FreeBSD.org) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id n29NG2Y2040165; Mon, 9 Mar 2009 23:16:02 GMT (envelope-from sam@svn.freebsd.org) Received: (from sam@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id n29NG2wI040160; Mon, 9 Mar 2009 23:16:02 GMT (envelope-from sam@svn.freebsd.org) Message-Id: <200903092316.n29NG2wI040160@svn.freebsd.org> From: Sam Leffler Date: Mon, 9 Mar 2009 23:16:02 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r189606 - in head/sys: conf dev/cfi X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 09 Mar 2009 23:16:03 -0000 Author: sam Date: Mon Mar 9 23:16:02 2009 New Revision: 189606 URL: http://svn.freebsd.org/changeset/base/189606 Log: Add cfid, a disk interface to CFI flash devices; this enables construction of flash-based filesystems. Note this is not interlocked against the raw CFI device. Added: head/sys/dev/cfi/cfi_disk.c (contents, props changed) Modified: head/sys/conf/files head/sys/dev/cfi/cfi_core.c head/sys/dev/cfi/cfi_dev.c head/sys/dev/cfi/cfi_var.h Modified: head/sys/conf/files ============================================================================== --- head/sys/conf/files Mon Mar 9 23:10:19 2009 (r189605) +++ head/sys/conf/files Mon Mar 9 23:16:02 2009 (r189606) @@ -702,6 +702,7 @@ dev/cardbus/cardbus_cis.c optional cardb dev/cardbus/cardbus_device.c optional cardbus dev/cfi/cfi_core.c optional cfi dev/cfi/cfi_dev.c optional cfi +dev/cfi/cfi_disk.c optional cfid dev/ciss/ciss.c optional ciss dev/cm/smc90cx6.c optional cm dev/cmx/cmx.c optional cmx Modified: head/sys/dev/cfi/cfi_core.c ============================================================================== --- head/sys/dev/cfi/cfi_core.c Mon Mar 9 23:10:19 2009 (r189605) +++ head/sys/dev/cfi/cfi_core.c Mon Mar 9 23:16:02 2009 (r189606) @@ -51,6 +51,7 @@ extern struct cdevsw cfi_cdevsw; char cfi_driver_name[] = "cfi"; devclass_t cfi_devclass; +devclass_t cfi_diskclass; uint32_t cfi_read(struct cfi_softc *sc, u_int ofs) @@ -284,6 +285,10 @@ cfi_attach(device_t dev) "%s%u", cfi_driver_name, u); sc->sc_nod->si_drv1 = sc; + device_add_child(dev, "cfid", + devclass_find_free_unit(cfi_diskclass, 0)); + bus_generic_attach(dev); + return (0); } Modified: head/sys/dev/cfi/cfi_dev.c ============================================================================== --- head/sys/dev/cfi/cfi_dev.c Mon Mar 9 23:10:19 2009 (r189605) +++ head/sys/dev/cfi/cfi_dev.c Mon Mar 9 23:16:02 2009 (r189606) @@ -74,7 +74,7 @@ struct cdevsw cfi_cdevsw = { * or the process stops writing. At that time we write the whole * sector to flash (see cfi_block_finish). */ -static int +int cfi_block_start(struct cfi_softc *sc, u_int ofs) { union { @@ -124,7 +124,7 @@ cfi_block_start(struct cfi_softc *sc, u_ * Finish updating the current block/sector by writing the compound * set of changes to the flash. */ -static int +int cfi_block_finish(struct cfi_softc *sc) { int error; Added: head/sys/dev/cfi/cfi_disk.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/sys/dev/cfi/cfi_disk.c Mon Mar 9 23:16:02 2009 (r189606) @@ -0,0 +1,319 @@ +/*- + * Copyright (c) 2009 Sam Leffler, Errno Consulting + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +struct cfi_disk_softc { + struct cfi_softc *parent; + struct disk *disk; + int flags; +#define CFI_DISK_OPEN 0x0001 + struct bio_queue_head bioq; /* bio queue */ + struct mtx qlock; /* bioq lock */ + struct taskqueue *tq; /* private task queue for i/o request */ + struct task iotask; /* i/o processing */ +}; + +#define CFI_DISK_SECSIZE 512 +#define CFI_DISK_MAXIOSIZE 65536 + +static int cfi_disk_detach(device_t); +static int cfi_disk_open(struct disk *); +static int cfi_disk_close(struct disk *); +static void cfi_io_proc(void *, int); +static void cfi_disk_strategy(struct bio *); +static int cfi_disk_ioctl(struct disk *, u_long, void *, int, struct thread *); + +static int +cfi_disk_probe(device_t dev) +{ + return 0; +} + +static int +cfi_disk_attach(device_t dev) +{ + struct cfi_disk_softc *sc = device_get_softc(dev); + + sc->parent = device_get_softc(device_get_parent(dev)); + /* validate interface width; assumed by other code */ + if (sc->parent->sc_width != 1 && + sc->parent->sc_width != 2 && + sc->parent->sc_width != 4) + return EINVAL; + + sc->disk = disk_alloc(); + if (sc->disk == NULL) + return ENOMEM; + sc->disk->d_name = "cfid"; + sc->disk->d_unit = device_get_unit(dev); + sc->disk->d_open = cfi_disk_open; + sc->disk->d_close = cfi_disk_close; + sc->disk->d_strategy = cfi_disk_strategy; + sc->disk->d_ioctl = cfi_disk_ioctl; + sc->disk->d_dump = NULL; /* NB: no dumps */ + sc->disk->d_sectorsize = CFI_DISK_SECSIZE; + sc->disk->d_mediasize = sc->parent->sc_size; + sc->disk->d_maxsize = CFI_DISK_MAXIOSIZE; + /* NB: use stripesize to hold the erase/region size */ + if (sc->parent->sc_regions) + sc->disk->d_stripesize = sc->parent->sc_region->r_blksz; + else + sc->disk->d_stripesize = sc->disk->d_mediasize; + sc->disk->d_drv1 = sc; + disk_create(sc->disk, DISK_VERSION); + + mtx_init(&sc->qlock, "CFID I/O lock", NULL, MTX_DEF); + bioq_init(&sc->bioq); + + sc->tq = taskqueue_create("cfid_taskq", M_NOWAIT, + taskqueue_thread_enqueue, &sc->tq); + taskqueue_start_threads(&sc->tq, 1, PI_DISK, "cfid taskq"); + + TASK_INIT(&sc->iotask, 0, cfi_io_proc, sc); + + return 0; +} + +static int +cfi_disk_detach(device_t dev) +{ + struct cfi_disk_softc *sc = device_get_softc(dev); + + if (sc->flags & CFI_DISK_OPEN) + return EBUSY; + taskqueue_free(sc->tq); + /* XXX drain bioq */ + disk_destroy(sc->disk); + mtx_destroy(&sc->qlock); + return 0; +} + +static int +cfi_disk_open(struct disk *dp) +{ + struct cfi_disk_softc *sc = dp->d_drv1; + + /* XXX no interlock with /dev/cfi */ + sc->flags |= CFI_DISK_OPEN; + return 0; +} + +static int +cfi_disk_close(struct disk *dp) +{ + struct cfi_disk_softc *sc = dp->d_drv1; + + sc->flags &= ~CFI_DISK_OPEN; + return 0; +} + +static void +cfi_disk_read(struct cfi_softc *sc, struct bio *bp) +{ + long resid; + + KASSERT(sc->sc_width == 1 || sc->sc_width == 2 || sc->sc_width == 4, + ("sc_width %d", sc->sc_width)); + + if (sc->sc_writing) { + bp->bio_error = cfi_block_finish(sc); + if (bp->bio_error) { + bp->bio_flags |= BIO_ERROR; + goto done; + } + } + if (bp->bio_offset > sc->sc_size) { + bp->bio_flags |= BIO_ERROR; + bp->bio_error = EIO; + goto done; + } + resid = bp->bio_bcount; + if (sc->sc_width == 1) { + uint8_t *dp = (uint8_t *)bp->bio_data; + while (resid > 0 && bp->bio_offset < sc->sc_size) { + *dp++ = cfi_read(sc, bp->bio_offset); + bp->bio_offset += 1, resid -= 1; + } + } else if (sc->sc_width == 2) { + uint16_t *dp = (uint16_t *)bp->bio_data; + while (resid > 0 && bp->bio_offset < sc->sc_size) { + *dp++ = cfi_read(sc, bp->bio_offset); + bp->bio_offset += 2, resid -= 2; + } + } else { + uint32_t *dp = (uint32_t *)bp->bio_data; + while (resid > 0 && bp->bio_offset < sc->sc_size) { + *dp++ = cfi_read(sc, bp->bio_offset); + bp->bio_offset += 4, resid -= 4; + } + } + bp->bio_resid = resid; +done: + biodone(bp); +} + +static void +cfi_disk_write(struct cfi_softc *sc, struct bio *bp) +{ + long resid; + u_int top; + + KASSERT(sc->sc_width == 1 || sc->sc_width == 2 || sc->sc_width == 4, + ("sc_width %d", sc->sc_width)); + + if (bp->bio_offset > sc->sc_size) { + bp->bio_flags |= BIO_ERROR; + bp->bio_error = EIO; + goto done; + } + resid = bp->bio_bcount; + while (resid > 0) { + /* + * Finish the current block if we're about to write + * to a different block. + */ + if (sc->sc_writing) { + top = sc->sc_wrofs + sc->sc_wrbufsz; + if (bp->bio_offset < sc->sc_wrofs || + bp->bio_offset >= top) + cfi_block_finish(sc); + } + + /* Start writing to a (new) block if applicable. */ + if (!sc->sc_writing) { + bp->bio_error = cfi_block_start(sc, bp->bio_offset); + if (bp->bio_error) { + bp->bio_flags |= BIO_ERROR; + goto done; + } + } + + top = sc->sc_wrofs + sc->sc_wrbufsz; + bcopy(bp->bio_data, + sc->sc_wrbuf + bp->bio_offset - sc->sc_wrofs, + MIN(top - bp->bio_offset, resid)); + resid -= MIN(top - bp->bio_offset, resid); + } + bp->bio_resid = resid; +done: + biodone(bp); +} + +static void +cfi_io_proc(void *arg, int pending) +{ + struct cfi_disk_softc *sc = arg; + struct cfi_softc *cfi = sc->parent; + struct bio *bp; + + for (;;) { + mtx_lock(&sc->qlock); + bp = bioq_takefirst(&sc->bioq); + mtx_unlock(&sc->qlock); + if (bp == NULL) + break; + + switch (bp->bio_cmd) { + case BIO_READ: + cfi_disk_read(cfi, bp); + break; + case BIO_WRITE: + cfi_disk_write(cfi, bp); + break; + } + } +} + +static void +cfi_disk_strategy(struct bio *bp) +{ + struct cfi_disk_softc *sc = bp->bio_disk->d_drv1; + + if (sc == NULL) + goto invalid; + if (bp->bio_bcount == 0) { + bp->bio_resid = bp->bio_bcount; + biodone(bp); + return; + } + switch (bp->bio_cmd) { + case BIO_READ: + case BIO_WRITE: + mtx_lock(&sc->qlock); + /* no value in sorting requests? */ + bioq_insert_tail(&sc->bioq, bp); + mtx_unlock(&sc->qlock); + taskqueue_enqueue(sc->tq, &sc->iotask); + return; + } + /* fall thru... */ +invalid: + bp->bio_flags |= BIO_ERROR; + bp->bio_error = EINVAL; + biodone(bp); +} + +static int +cfi_disk_ioctl(struct disk *dp, u_long cmd, void *data, int fflag, + struct thread *td) +{ + return EINVAL; +} + +static device_method_t cfi_disk_methods[] = { + DEVMETHOD(device_probe, cfi_disk_probe), + DEVMETHOD(device_attach, cfi_disk_attach), + DEVMETHOD(device_detach, cfi_disk_detach), + + { 0, 0 } +}; +static driver_t cfi_disk_driver = { + "cfid", + cfi_disk_methods, + sizeof(struct cfi_disk_softc), +}; +DRIVER_MODULE(cfid, cfi, cfi_disk_driver, cfi_diskclass, 0, NULL); Modified: head/sys/dev/cfi/cfi_var.h ============================================================================== --- head/sys/dev/cfi/cfi_var.h Mon Mar 9 23:10:19 2009 (r189605) +++ head/sys/dev/cfi/cfi_var.h Mon Mar 9 23:16:02 2009 (r189606) @@ -65,6 +65,7 @@ struct cfi_softc { extern char cfi_driver_name[]; extern devclass_t cfi_devclass; +extern devclass_t cfi_diskclass; int cfi_probe(device_t); int cfi_attach(device_t); @@ -73,6 +74,8 @@ int cfi_detach(device_t); uint32_t cfi_read(struct cfi_softc *, u_int); uint8_t cfi_read_qry(struct cfi_softc *, u_int); int cfi_write_block(struct cfi_softc *); +int cfi_block_start(struct cfi_softc *, u_int); +int cfi_block_finish(struct cfi_softc *); #ifdef CFI_SUPPORT_STRATAFLASH int cfi_intel_get_factory_pr(struct cfi_softc *sc, uint64_t *);