summaryrefslogtreecommitdiffstats
path: root/sys/dev/flash.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/flash.c')
-rw-r--r--sys/dev/flash.c1062
1 files changed, 0 insertions, 1062 deletions
diff --git a/sys/dev/flash.c b/sys/dev/flash.c
deleted file mode 100644
index e0069a5c130..00000000000
--- a/sys/dev/flash.c
+++ /dev/null
@@ -1,1062 +0,0 @@
-/* $OpenBSD: flash.c,v 1.32 2017/05/04 22:47:27 deraadt Exp $ */
-
-/*
- * Copyright (c) 2005 Uwe Stuehler <uwe@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/param.h>
-#include <sys/buf.h>
-#include <sys/conf.h>
-#include <sys/device.h>
-#include <sys/disk.h>
-#include <sys/disklabel.h>
-#include <sys/dkio.h>
-#include <sys/kernel.h>
-#include <sys/stat.h>
-#include <sys/systm.h>
-
-#include <dev/flashvar.h>
-
-#include <ufs/ffs/fs.h> /* XXX */
-
-/* Samsung command set */
-#define SAMSUNG_CMD_PTRLO 0x00
-#define SAMSUNG_CMD_PTRHI 0x01
-#define SAMSUNG_CMD_PTROOB 0x50
-#define SAMSUNG_CMD_READ 0x30
-#define SAMSUNG_CMD_SEQIN 0x80
-#define SAMSUNG_CMD_WRITE 0x10
-#define SAMSUNG_CMD_ERASE0 0x60
-#define SAMSUNG_CMD_ERASE1 0xd0
-#define SAMSUNG_CMD_STATUS 0x70
-#define STATUS_FAIL (1<<0)
-#define STATUS_READY (1<<6)
-#define STATUS_NWP (1<<7)
-#define SAMSUNG_CMD_READID 0x90
-#define SAMSUNG_CMD_RESET 0xff
-
-int flash_wait_ready(struct flash_softc *);
-int flash_wait_complete(struct flash_softc *);
-
-/* XXX: these should go elsewhere */
-cdev_decl(flash);
-bdev_decl(flash);
-
-#define flashlookup(unit) \
- (struct flash_softc *)device_lookup(&flash_cd, (unit))
-
-void flashminphys(struct buf *);
-void flashstart(struct flash_softc *);
-void _flashstart(struct flash_softc *, struct buf *);
-void flashdone(void *);
-
-int flashsafestrategy(struct flash_softc *, struct buf *);
-void flashgetdefaultlabel(dev_t, struct flash_softc *,
- struct disklabel *);
-int flashgetdisklabel(dev_t, struct flash_softc *, struct disklabel *, int);
-
-/*
- * Driver attachment glue
- */
-
-struct flashvendor {
- u_int8_t vendor;
- const char *name;
-};
-
-static const struct flashvendor flashvendors[] = {
- { FLASH_VENDOR_SAMSUNG, "Samsung" }
-};
-#define FLASH_NVENDORS (sizeof(flashvendors) / sizeof(flashvendors[0]))
-
-static const struct flashdev flashdevs[] = {
- { FLASH_DEVICE_SAMSUNG_K9F2808U0C, "K9F2808U0C 16Mx8 3.3V",
- 512, 16, 32, 32768 },
- { FLASH_DEVICE_SAMSUNG_K9F1G08U0A, "K9F1G08U0A 128Mx8 3.3V",
- 2048, 64, 64, 65536 },
-};
-#define FLASH_NDEVS (sizeof(flashdevs) / sizeof(flashdevs[0]))
-
-struct cfdriver flash_cd = {
- NULL, "flash", DV_DISK
-};
-
-void
-flashattach(struct flash_softc *sc, struct flash_ctl_tag *tag,
- void *cookie)
-{
- u_int8_t vendor, device;
- u_int16_t id;
- int i;
-
- sc->sc_tag = tag;
- sc->sc_cookie = cookie;
-
- if (sc->sc_maxwaitready <= 0)
- sc->sc_maxwaitready = 1000; /* 1ms */
- if (sc->sc_maxwaitcomplete <= 0)
- sc->sc_maxwaitcomplete = 200000; /* 200ms */
-
- flash_chip_enable(sc);
-
- /* Identify the flash device. */
- if (flash_chip_identify(sc, &vendor, &device) != 0) {
- printf(": identification failed\n");
- flash_chip_disable(sc);
- return;
- }
- id = (vendor << 8) | device;
-
- /* Look up device characteristics, abort if not recognized. */
- for (i = 0; i < FLASH_NVENDORS; i++) {
- if (flashvendors[i].vendor == vendor) {
- printf(": %s", flashvendors[i].name);
- break;
- }
- }
- if (i == FLASH_NVENDORS)
- printf(": vendor 0x%02x", vendor);
- for (i = 0; i < FLASH_NDEVS; i++) {
- if (flashdevs[i].id == id) {
- printf(" %s\n", flashdevs[i].longname);
- break;
- }
- }
- if (i == FLASH_NDEVS) {
- /* Need to add this device to flashdevs first. */
- printf(" device 0x%02x\n", device);
- flash_chip_disable(sc);
- return;
- }
- sc->sc_flashdev = &flashdevs[i];
-
- /* Check if the device really works or fail early. */
- if (flash_chip_reset(sc) != 0) {
- printf("%s: reset failed\n", sc->sc_dev.dv_xname);
- flash_chip_disable(sc);
- return;
- }
-
- flash_chip_disable(sc);
-
- /*
- * Initialize and attach the disk structure.
- */
- sc->sc_dk.dk_name = sc->sc_dev.dv_xname;
- bufq_init(&sc->sc_bufq, BUFQ_FIFO);
- disk_attach(&sc->sc_dev, &sc->sc_dk);
-
- /* XXX establish shutdown hook to finish any commands. */
-}
-
-int
-flashdetach(struct device *self, int flags)
-{
- struct flash_softc *sc = (struct flash_softc *)self;
-
- /* Detach disk. */
- disk_detach(&sc->sc_dk);
-
- /* XXX more resources need to be freed here. */
- return 0;
-}
-
-/*
- * Flash controller and chip functions
- */
-
-u_int8_t
-flash_reg8_read(struct flash_softc *sc, int reg)
-{
- return sc->sc_tag->reg8_read(sc->sc_cookie, reg);
-}
-
-void
-flash_reg8_read_page(struct flash_softc *sc, caddr_t data, caddr_t oob)
-{
- int i;
-
- for (i = 0; i < sc->sc_flashdev->pagesize; i++)
- data[i] = flash_reg8_read(sc, FLASH_REG_DATA);
-
- if (oob != NULL)
- for (i = 0; i < sc->sc_flashdev->oobsize; i++)
- oob[i] = flash_reg8_read(sc, FLASH_REG_DATA);
-}
-
-void
-flash_reg8_write(struct flash_softc *sc, int reg, u_int8_t value)
-{
- sc->sc_tag->reg8_write(sc->sc_cookie, reg, value);
-}
-
-void
-flash_reg8_write_page(struct flash_softc *sc, caddr_t data, caddr_t oob)
-{
- int i;
-
- for (i = 0; i < sc->sc_flashdev->pagesize; i++)
- flash_reg8_write(sc, FLASH_REG_DATA, data[i]);
-
- if (oob != NULL)
- for (i = 0; i < sc->sc_flashdev->oobsize; i++)
- flash_reg8_write(sc, FLASH_REG_DATA, oob[i]);
-}
-
-/*
- * Wait for the "Ready/Busy" signal to go high, indicating that the
- * device is ready to accept another command.
- */
-int
-flash_wait_ready(struct flash_softc *sc)
-{
- int timo = sc->sc_maxwaitready;
- u_int8_t ready;
-
- ready = flash_reg8_read(sc, FLASH_REG_READY);
- while (ready == 0 && timo-- > 0) {
- delay(1);
- ready = flash_reg8_read(sc, FLASH_REG_READY);
- }
- return (ready == 0 ? EIO : 0);
-}
-
-/*
- * Similar to flash_wait_ready() but looks at IO 6 and IO 0 signals
- * besides R/B to decide whether the last operation was successful.
- */
-int
-flash_wait_complete(struct flash_softc *sc)
-{
- int timo = sc->sc_maxwaitcomplete;
- u_int8_t status;
-
- (void)flash_wait_ready(sc);
-
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_STATUS);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
-
- status = flash_reg8_read(sc, FLASH_REG_DATA);
- while ((status & STATUS_READY) == 0 && timo-- > 0) {
- if (flash_reg8_read(sc, FLASH_REG_READY))
- break;
- delay(1);
- status = flash_reg8_read(sc, FLASH_REG_DATA);
- }
-
- status = flash_reg8_read(sc, FLASH_REG_DATA);
- return ((status & STATUS_FAIL) != 0 ? EIO : 0);
-}
-
-void
-flash_chip_enable(struct flash_softc *sc)
-{
- /* XXX aquire the lock. */
- flash_reg8_write(sc, FLASH_REG_CE, 1);
-}
-
-void
-flash_chip_disable(struct flash_softc *sc)
-{
- flash_reg8_write(sc, FLASH_REG_CE, 0);
- /* XXX release the lock. */
-}
-
-int
-flash_chip_reset(struct flash_softc *sc)
-{
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_RESET);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
-
- return flash_wait_ready(sc);
-}
-
-int
-flash_chip_identify(struct flash_softc *sc, u_int8_t *vendor,
- u_int8_t *device)
-{
- int error;
-
- (void)flash_wait_ready(sc);
-
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_READID);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
-
- error = flash_wait_ready(sc);
- if (error == 0) {
- *vendor = flash_reg8_read(sc, FLASH_REG_DATA);
- *device = flash_reg8_read(sc, FLASH_REG_DATA);
- }
- return error;
-}
-
-int
-flash_chip_erase_block(struct flash_softc *sc, long blkno)
-{
- long pageno = blkno * sc->sc_flashdev->blkpages;
- int error;
-
- (void)flash_wait_ready(sc);
-
- /* Disable write-protection. */
- flash_reg8_write(sc, FLASH_REG_WP, 0);
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_ERASE0);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_ERASE1);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- error = flash_wait_complete(sc);
-
- /* Re-enable write-protection. */
- flash_reg8_write(sc, FLASH_REG_WP, 1);
-
- return error;
-}
-
-int
-flash_chip_read_block(struct flash_softc *sc, long blkno, caddr_t data)
-{
- long pageno;
- long blkend;
- int error;
-
- pageno = blkno * sc->sc_flashdev->blkpages;
- blkend = pageno + sc->sc_flashdev->blkpages;
-
- while (pageno < blkend) {
- error = flash_chip_read_page(sc, pageno, data, NULL);
- if (error != 0)
- return error;
- data += sc->sc_flashdev->pagesize;
- pageno++;
- }
- return 0;
-}
-
-int
-flash_chip_read_page(struct flash_softc *sc, long pageno, caddr_t data,
- caddr_t oob)
-{
- int error;
-
- (void)flash_wait_ready(sc);
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTRLO);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_READ);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- if ((error = flash_wait_ready(sc)) != 0)
- return error;
-
- /* Support hardware ECC calculation. */
- if (sc->sc_tag->regx_read_page) {
- error = sc->sc_tag->regx_read_page(sc->sc_cookie, data,
- oob);
- if (error != 0)
- return error;
- } else
- flash_reg8_read_page(sc, data, oob);
-
- return 0;
-}
-
-int
-flash_chip_read_oob(struct flash_softc *sc, long pageno, caddr_t oob)
-{
- u_int8_t *p = (u_int8_t *)oob;
- int error;
- int i;
-
- (void)flash_wait_ready(sc);
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTROOB);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTRLO);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_COL, 0x08);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_READ);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- if ((error = flash_wait_ready(sc)) != 0)
- return error;
-
- for (i = 0; i < sc->sc_flashdev->oobsize; i++)
- p[i] = flash_reg8_read(sc, FLASH_REG_DATA);
-
- return 0;
-}
-
-int
-flash_chip_write_block(struct flash_softc *sc, long blkno, caddr_t data,
- caddr_t oob)
-{
- long pageno;
- long blkend;
- caddr_t p;
- int error;
-
- pageno = blkno * sc->sc_flashdev->blkpages;
- blkend = pageno + sc->sc_flashdev->blkpages;
-
- p = data;
- while (pageno < blkend) {
- error = flash_chip_write_page(sc, pageno, p, oob);
- if (error != 0)
- return error;
- p += sc->sc_flashdev->pagesize;
- pageno++;
- }
-
- /* Verify the newly written block. */
- return flash_chip_verify_block(sc, blkno, data, oob);
-}
-
-int
-flash_chip_write_page(struct flash_softc *sc, long pageno, caddr_t data,
- caddr_t oob)
-{
- int error;
-
- (void)flash_wait_ready(sc);
-
- /* Disable write-protection. */
- flash_reg8_write(sc, FLASH_REG_WP, 0);
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_PTRLO);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_SEQIN);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_COL, 0x00);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_ALE, 1);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno);
- flash_reg8_write(sc, FLASH_REG_ROW, pageno >> 8);
- flash_reg8_write(sc, FLASH_REG_ALE, 0);
- break;
- }
-
- /* Support hardware ECC calculation. */
- if (sc->sc_tag->regx_write_page) {
- error = sc->sc_tag->regx_write_page(sc->sc_cookie, data,
- oob);
- if (error != 0)
- return error;
- } else
- flash_reg8_write_page(sc, data, oob);
-
- switch (sc->sc_flashdev->id) {
- case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
- case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
- flash_reg8_write(sc, FLASH_REG_CLE, 1);
- flash_reg8_write(sc, FLASH_REG_CMD, SAMSUNG_CMD_WRITE);
- flash_reg8_write(sc, FLASH_REG_CLE, 0);
- break;
- }
-
- /*
- * Wait for the write operation to complete although this can
- * take up to 700 us for the K9F1G08U0A flash type.
- */
- error = flash_wait_complete(sc);
-
- /* Re-enable write-protection. */
- flash_reg8_write(sc, FLASH_REG_WP, 1);
-
- return error;
-}
-
-int
-flash_chip_verify_block(struct flash_softc *sc, long blkno, caddr_t data,
- caddr_t oob)
-{
- long pageno;
- long blkend;
- int error;
-
- pageno = blkno * sc->sc_flashdev->blkpages;
- blkend = pageno + sc->sc_flashdev->blkpages;
-
- while (pageno < blkend) {
- error = flash_chip_verify_page(sc, pageno, data, oob);
- if (error != 0) {
- printf("block %ld page %ld verify failed\n",
- blkno, pageno);
- return error;
- }
- data += sc->sc_flashdev->pagesize;
- pageno++;
- }
- return 0;
-}
-
-int
-flash_chip_verify_page(struct flash_softc *sc, long pageno, caddr_t data,
- caddr_t oob)
-{
- static u_char rbuf[FLASH_MAXPAGESIZE];
- static u_char roob[FLASH_MAXOOBSIZE];
- int error;
-
- error = flash_chip_read_page(sc, pageno, rbuf,
- oob == NULL ? NULL : roob);
- if (error != 0)
- return error;
-
- if (memcmp((const void *)&rbuf[0], (const void *)data,
- sc->sc_flashdev->pagesize) != 0)
- return EIO;
-
- if (oob != NULL && memcmp((const void *)&roob[0],
- (const void *)oob, sc->sc_flashdev->oobsize) != 0)
- return EIO;
-
- return 0;
-}
-
-/*
- * Block device functions
- */
-
-int
-flashopen(dev_t dev, int oflags, int devtype, struct proc *p)
-{
- struct flash_softc *sc;
- int error;
- int part;
-
- sc = flashlookup(flashunit(dev));
- if (sc == NULL)
- return ENXIO;
-
- if ((error = disk_lock(&sc->sc_dk)) != 0) {
- device_unref(&sc->sc_dev);
- return error;
- }
-
- /*
- * If no partition is open load the partition info if it is
- * not already valid. If partitions are already open, allow
- * opens only for the same kind of device.
- */
- if (sc->sc_dk.dk_openmask == 0) {
- if ((sc->sc_flags & FDK_LOADED) == 0 ||
- ((sc->sc_flags & FDK_SAFE) == 0) !=
- (flashsafe(dev) == 0)) {
- sc->sc_flags &= ~FDK_SAFE;
- sc->sc_flags |= FDK_LOADED;
- if (flashsafe(dev))
- sc->sc_flags |= FDK_SAFE;
- if ((error = flashgetdisklabel(dev, sc,
- sc->sc_dk.dk_label, 0)) != 0) {
- disk_unlock(&sc->sc_dk);
- device_unref(&sc->sc_dev);
- return error;
- }
- }
- } else if (((sc->sc_flags & FDK_SAFE) == 0) !=
- (flashsafe(dev) == 0)) {
- disk_unlock(&sc->sc_dk);
- device_unref(&sc->sc_dev);
- return EBUSY;
- }
-
- /* Check that the partition exists. */
- part = flashpart(dev);
- if (part != RAW_PART &&
- (part >= sc->sc_dk.dk_label->d_npartitions ||
- sc->sc_dk.dk_label->d_partitions[part].p_fstype == FS_UNUSED)) {
- disk_unlock(&sc->sc_dk);
- device_unref(&sc->sc_dev);
- return ENXIO;
- }
-
- /* Prevent our unit from being deconfigured while open. */
- switch (devtype) {
- case S_IFCHR:
- sc->sc_dk.dk_copenmask |= (1 << part);
- break;
- case S_IFBLK:
- sc->sc_dk.dk_bopenmask |= (1 << part);
- break;
- }
- sc->sc_dk.dk_openmask =
- sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
-
- disk_unlock(&sc->sc_dk);
- device_unref(&sc->sc_dev);
- return 0;
-}
-
-int
-flashclose(dev_t dev, int fflag, int devtype, struct proc *p)
-{
- struct flash_softc *sc;
- int part;
-
- sc = flashlookup(flashunit(dev));
- if (sc == NULL)
- return ENXIO;
-
- disk_lock_nointr(&sc->sc_dk);
-
- /* Close one open partition. */
- part = flashpart(dev);
- switch (devtype) {
- case S_IFCHR:
- sc->sc_dk.dk_copenmask &= ~(1 << part);
- break;
- case S_IFBLK:
- sc->sc_dk.dk_bopenmask &= ~(1 << part);
- break;
- }
- sc->sc_dk.dk_openmask =
- sc->sc_dk.dk_copenmask | sc->sc_dk.dk_bopenmask;
-
- if (sc->sc_dk.dk_openmask == 0) {
- /* XXX wait for I/O to complete? */
- }
-
- disk_unlock(&sc->sc_dk);
- device_unref(&sc->sc_dev);
- return 0;
-}
-
-/*
- * Queue the transfer of one or more flash pages.
- */
-void
-flashstrategy(struct buf *bp)
-{
- struct flash_softc *sc;
- int s;
-
- sc = flashlookup(flashunit(bp->b_dev));
- if (sc == NULL) {
- bp->b_error = ENXIO;
- goto bad;
- }
-
- /* If the device has been invalidated, error out. */
- if ((sc->sc_flags & FDK_LOADED) == 0) {
- bp->b_error = EIO;
- goto bad;
- }
-
- /* Translate logical block numbers to physical. */
- if (flashsafe(bp->b_dev) && flashsafestrategy(sc, bp) <= 0) {
- if (bp->b_flags & B_ERROR)
- bp->b_resid = bp->b_bcount;
- goto done;
- }
-
- /* Validate the request. */
- if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1)
- goto done;
-
- /* Queue the transfer. */
- bufq_queue(&sc->sc_bufq, bp);
-
- s = splbio();
- flashstart(sc);
- splx(s);
-
- device_unref(&sc->sc_dev);
- return;
-
- bad:
- bp->b_flags |= B_ERROR;
- bp->b_resid = bp->b_bcount;
- done:
- s = splbio();
- biodone(bp);
- splx(s);
- if (sc != NULL)
- device_unref(&sc->sc_dev);
-}
-
-int
-flashioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct proc *p)
-{
- struct flash_softc *sc;
- int error = 0;
-
- sc = flashlookup(flashunit(dev));
- if (sc == NULL)
- return ENXIO;
-
- if ((sc->sc_flags & FDK_LOADED) == 0) {
- device_unref(&sc->sc_dev);
- return EIO;
- }
-
- switch (cmd) {
- case DIOCGPDINFO:
- flashgetdisklabel(dev, sc, (struct disklabel *)data, 1);
- break;
-
- case DIOCGDINFO:
- *(struct disklabel *)data = *sc->sc_dk.dk_label;
- break;
-
- default:
- error = ENOTTY;
- break;
- }
-
- device_unref(&sc->sc_dev);
- return error;
-}
-
-int
-flashdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size)
-{
- printf("flashdump\n");
- return ENODEV;
-}
-
-daddr_t
-flashsize(dev_t dev)
-{
- printf("flashsize\n");
- return ENODEV;
-}
-
-void
-flashstart(struct flash_softc *sc)
-{
- struct buf *bp;
-
- while ((bp = bufq_dequeue(&sc->sc_bufq)) != NULL) {
- /* Transfer this buffer now. */
- _flashstart(sc, bp);
- }
-}
-
-void
-_flashstart(struct flash_softc *sc, struct buf *bp)
-{
- struct disklabel *lp;
- int part;
- daddr_t offset;
- long pgno;
-
- part = flashpart(bp->b_dev);
-
- lp = sc->sc_dk.dk_label;
- offset = DL_SECTOBLK(lp, DL_GETPOFFSET(&lp->d_partitions[part])) +
- bp->b_blkno;
- pgno = offset / (sc->sc_flashdev->pagesize / DEV_BSIZE);
-
- /*
- * If the requested page is exactly at the end of flash and it
- * is an "unsafe" device, return EOF, else error out.
- */
- if (!flashsafe(bp->b_dev) && pgno == sc->sc_flashdev->capacity) {
- bp->b_resid = bp->b_bcount;
- biodone(bp);
- return;
- } else if (pgno >= sc->sc_flashdev->capacity) {
- bp->b_error = EINVAL;
- bp->b_flags |= B_ERROR;
- biodone(bp);
- return;
- }
-
- sc->sc_bp = bp;
-
- /* Instrumentation. */
- disk_busy(&sc->sc_dk);
-
- /* XXX this should be done asynchronously. */
- flash_chip_enable(sc);
- if ((bp->b_flags & B_READ) != 0)
- bp->b_error = flash_chip_read_page(sc, pgno, bp->b_data,
- NULL);
- else
- bp->b_error = flash_chip_write_page(sc, pgno, bp->b_data,
- NULL);
- if (bp->b_error == 0)
- bp->b_resid = bp->b_bcount - sc->sc_flashdev->pagesize;
- flash_chip_disable(sc);
- flashdone(sc);
-}
-
-void
-flashdone(void *v)
-{
- struct flash_softc *sc = v;
- struct buf *bp = sc->sc_bp;
-
- /* Instrumentation. */
- disk_unbusy(&sc->sc_dk, bp->b_bcount - bp->b_resid,
- bp->b_blkno, (bp->b_flags & B_READ) != 0);
-
- if (bp->b_error != 0)
- bp->b_flags |= B_ERROR;
-
- biodone(bp);
- flashstart(sc);
-}
-
-void
-flashgetdefaultlabel(dev_t dev, struct flash_softc *sc,
- struct disklabel *lp)
-{
- size_t len;
-
- bzero(lp, sizeof(struct disklabel));
-
- lp->d_type = 0;
- strncpy(lp->d_typename, "NAND flash", sizeof(lp->d_typename));
-
- /* Use the product name up to the first space. */
- strncpy(lp->d_packname, sc->sc_flashdev->longname,
- sizeof(lp->d_packname));
- for (len = 0; len < sizeof(lp->d_packname); len++)
- if (lp->d_packname[len] == ' ') {
- lp->d_packname[len] = '\0';
- break;
- }
-
- /* Fake the disk geometry. */
- lp->d_ncylinders = 1;
- lp->d_ntracks = 16;
- lp->d_secsize = sc->sc_flashdev->pagesize;
- lp->d_nsectors = sc->sc_flashdev->capacity / lp->d_ntracks
- / lp->d_ncylinders;
- lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors;
- DL_SETDSIZE(lp, (u_int64_t)lp->d_ncylinders * lp->d_secpercyl);
-
- lp->d_version = 1;
-
- /* XXX these values assume ffs. */
- lp->d_bbsize = BBSIZE;
- lp->d_sbsize = SBSIZE;
-
- /* Wrap it up. */
- lp->d_magic = DISKMAGIC;
- lp->d_magic2 = DISKMAGIC;
- lp->d_checksum = dkcksum(lp);
-}
-
-int
-flashgetdisklabel(dev_t dev, struct flash_softc *sc,
- struct disklabel *lp, int spoofonly)
-{
- dev_t labeldev;
-
- flashgetdefaultlabel(dev, sc, lp);
-
- if (sc->sc_tag->default_disklabel != NULL)
- sc->sc_tag->default_disklabel(sc->sc_cookie, dev, lp);
-
- /* Call the generic disklabel extraction routine. */
- labeldev = flashlabeldev(dev);
- return readdisklabel(labeldev, flashstrategy, lp, spoofonly);
-}
-
-/*
- * Character device functions
- */
-
-void
-flashminphys(struct buf *bp)
-{
- struct flash_softc *sc;
-
- sc = flashlookup(flashunit(bp->b_dev));
-
- if (bp->b_bcount > sc->sc_flashdev->pagesize)
- bp->b_bcount = sc->sc_flashdev->pagesize;
-}
-
-int
-flashread(dev_t dev, struct uio *uio, int ioflag)
-{
- return physio(flashstrategy, dev, B_READ, flashminphys, uio);
-}
-
-int
-flashwrite(dev_t dev, struct uio *uio, int ioflag)
-{
- return physio(flashstrategy, dev, B_WRITE, flashminphys, uio);
-}
-
-/*
- * Physical access strategy "fixup" routines for transparent bad
- * blocks management, wear-leveling, etc.
- */
-
-/*
- * Call the machine-specific routine if there is any or use just a
- * default strategy for bad blocks management.
- */
-int
-flashsafestrategy(struct flash_softc *sc, struct buf *bp)
-{
- if (sc->sc_tag->safe_strategy) {
- return sc->sc_tag->safe_strategy(sc->sc_cookie, bp);
- }
-
- /* XXX no default bad blocks management strategy yet */
- return 1;
-}
-
-void dumppage(u_char *);
-void dumppage(u_char *buf)
-{
- int i;
- for (i = 0; i < 512; i++) {
- if ((i % 16) == 0)
- printf("%04x: ", i);
- if ((i % 16) == 8)
- printf(" ");
- printf(" %02x", buf[i]);
- if ((i % 16) == 15)
- printf("\n");
- }
- if ((i % 16) != 0)
- printf("\n");
-}