[BACK]Return to zaurus_flash.c CVS log [TXT][DIR] Up to [local] / sys / arch / zaurus / dev

Annotation of sys/arch/zaurus/dev/zaurus_flash.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: zaurus_flash.c,v 1.4 2007/06/20 18:15:46 deraadt Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005 Uwe Stuehler <uwe@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: /*
        !            20:  * Samsung NAND flash controlled by some unspecified CPLD device.
        !            21:  */
        !            22:
        !            23: #include <sys/param.h>
        !            24: #include <sys/buf.h>
        !            25: #include <sys/device.h>
        !            26: #include <sys/disk.h>
        !            27: #include <sys/disklabel.h>
        !            28: #include <sys/kernel.h>
        !            29: #include <sys/malloc.h>
        !            30: #include <sys/systm.h>
        !            31:
        !            32: #include <dev/flashvar.h>
        !            33: #include <dev/rndvar.h>
        !            34:
        !            35: #include <machine/zaurus_var.h>
        !            36:
        !            37: #include <arch/arm/xscale/pxa2x0var.h>
        !            38:
        !            39: #define DEBUG
        !            40: #ifdef DEBUG
        !            41: #define DPRINTF(x) printf x
        !            42: #else
        !            43: #define DPRINTF(x)
        !            44: #endif
        !            45:
        !            46: /* CPLD register definitions */
        !            47: #define CPLD_REG_ECCLPLB       0x00
        !            48: #define CPLD_REG_ECCLPUB       0x04
        !            49: #define CPLD_REG_ECCCP         0x08
        !            50: #define CPLD_REG_ECCCNTR       0x0c
        !            51: #define CPLD_REG_ECCCLRR       0x10
        !            52: #define CPLD_REG_FLASHIO       0x14
        !            53: #define CPLD_REG_FLASHCTL      0x18
        !            54: #define  FLASHCTL_NCE0         (1<<0)
        !            55: #define  FLASHCTL_CLE          (1<<1)
        !            56: #define  FLASHCTL_ALE          (1<<2)
        !            57: #define  FLASHCTL_NWP          (1<<3)
        !            58: #define  FLASHCTL_NCE1         (1<<4)
        !            59: #define  FLASHCTL_RYBY         (1<<5)
        !            60: #define  FLASHCTL_NCE          (FLASHCTL_NCE0|FLASHCTL_NCE1)
        !            61:
        !            62: /* CPLD register accesses */
        !            63: #define CPLD_READ(sc, r)                                               \
        !            64:        bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (r))
        !            65: #define CPLD_WRITE(sc, r, v)                                           \
        !            66:        bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (r), (v))
        !            67: #define CPLD_SET(sc, r, v)                                             \
        !            68:        CPLD_WRITE((sc), (r), CPLD_READ((sc), (r)) | (v))
        !            69: #define CPLD_CLR(sc, r, v)                                             \
        !            70:        CPLD_WRITE((sc), (r), CPLD_READ((sc), (r)) & ~(v))
        !            71: #define CPLD_SETORCLR(sc, r, m, v)                                     \
        !            72:        ((v) ? CPLD_SET((sc), (r), (m)) : CPLD_CLR((sc), (r), (m)))
        !            73:
        !            74: /* Offsets into OOB data. */
        !            75: #define OOB_JFFS2_ECC0         0
        !            76: #define OOB_JFFS2_ECC1         1
        !            77: #define OOB_JFFS2_ECC2         2
        !            78: #define OOB_JFFS2_ECC3         3
        !            79: #define OOB_JFFS2_ECC4         6
        !            80: #define OOB_JFFS2_ECC5         7
        !            81: #define OOB_LOGADDR_0_LO       8
        !            82: #define OOB_LOGADDR_0_HI       9
        !            83: #define OOB_LOGADDR_1_LO       10
        !            84: #define OOB_LOGADDR_1_HI       11
        !            85: #define OOB_LOGADDR_2_LO       12
        !            86: #define OOB_LOGADDR_2_HI       13
        !            87:
        !            88: /*
        !            89:  * Structure for managing logical blocks in a partition; allocated on
        !            90:  * first use of each partition on a "safe" flash device.
        !            91:  */
        !            92: struct zflash_safe {
        !            93:        dev_t                    sp_dev;
        !            94:        u_long                   sp_pblks;      /* physical block count */
        !            95:        u_long                   sp_lblks;      /* logical block count */
        !            96:        u_int16_t               *sp_phyuse;     /* physical block usage */
        !            97:        u_int                   *sp_logmap;     /* logical to physical */
        !            98:        u_int                    sp_pnext;      /* next physical block */
        !            99: };
        !           100:
        !           101: struct zflash_softc {
        !           102:        struct flash_softc       sc_flash;
        !           103:        bus_space_tag_t          sc_iot;
        !           104:        bus_space_handle_t       sc_ioh;
        !           105:        int                      sc_ioobbadblk;
        !           106:        int                      sc_ioobpostbadblk;
        !           107:        struct zflash_safe      *sc_safe[MAXPARTITIONS];
        !           108: };
        !           109:
        !           110: int     zflashmatch(struct device *, void *, void *);
        !           111: void    zflashattach(struct device *, struct device *, void *);
        !           112: int     zflashdetach(struct device *, int);
        !           113:
        !           114: u_int8_t zflash_reg8_read(void *, int);
        !           115: int     zflash_regx_read_page(void *, caddr_t, caddr_t);
        !           116: void    zflash_reg8_write(void *, int, u_int8_t);
        !           117: int     zflash_regx_write_page(void *, caddr_t, caddr_t);
        !           118: void    zflash_default_disklabel(void *, dev_t, struct disklabel *);
        !           119: int     zflash_safe_strategy(void *, struct buf *);
        !           120:
        !           121: int     zflash_safe_start(struct zflash_softc *, dev_t);
        !           122: void    zflash_safe_stop(struct zflash_softc *, dev_t);
        !           123:
        !           124: struct cfattach flash_pxaip_ca = {
        !           125:        sizeof(struct zflash_softc), zflashmatch, zflashattach,
        !           126:        zflashdetach, flashactivate
        !           127: };
        !           128:
        !           129: struct flash_ctl_tag zflash_ctl_tag = {
        !           130:        zflash_reg8_read,
        !           131:        zflash_regx_read_page,
        !           132:        zflash_reg8_write,
        !           133:        zflash_regx_write_page,
        !           134:        zflash_default_disklabel,
        !           135:        zflash_safe_strategy
        !           136: };
        !           137:
        !           138: int
        !           139: zflashmatch(struct device *parent, void *match, void *aux)
        !           140: {
        !           141:        /* XXX call flashprobe(), yet to be implemented */
        !           142:        return ZAURUS_ISC3000;
        !           143: }
        !           144:
        !           145: void
        !           146: zflashattach(struct device *parent, struct device *self, void *aux)
        !           147: {
        !           148:        struct zflash_softc *sc = (struct zflash_softc *)self;
        !           149:        struct pxaip_attach_args *pxa = aux;
        !           150:        bus_addr_t addr = pxa->pxa_addr;
        !           151:        bus_size_t size = pxa->pxa_size;
        !           152:
        !           153:        sc->sc_iot = pxa->pxa_iot;
        !           154:
        !           155:        if ((int)addr == -1 || (int)size == 0) {
        !           156:                addr = 0x0c000000;
        !           157:                size = 0x00001000;
        !           158:        }
        !           159:
        !           160:        if (bus_space_map(sc->sc_iot, addr, size, 0, &sc->sc_ioh) != 0) {
        !           161:                printf(": failed to map controller\n");
        !           162:                return;
        !           163:        }
        !           164:
        !           165:        /* Disable and write-protect the chip. */
        !           166:        CPLD_WRITE(sc, CPLD_REG_FLASHCTL, FLASHCTL_NCE);
        !           167:
        !           168:        flashattach(&sc->sc_flash, &zflash_ctl_tag, sc);
        !           169:
        !           170:        switch (sc->sc_flash.sc_flashdev->id) {
        !           171:        case FLASH_DEVICE_SAMSUNG_K9F2808U0C: /* C3000 */
        !           172:                sc->sc_ioobpostbadblk = 4;
        !           173:                sc->sc_ioobbadblk = 5;
        !           174:                break;
        !           175:        case FLASH_DEVICE_SAMSUNG_K9F1G08U0A: /* C3100 */
        !           176:                sc->sc_ioobpostbadblk = 4;
        !           177:                sc->sc_ioobbadblk = 0;
        !           178:                break;
        !           179:        }
        !           180: }
        !           181:
        !           182: int
        !           183: zflashdetach(struct device *self, int flags)
        !           184: {
        !           185:        struct zflash_softc *sc = (struct zflash_softc *)self;
        !           186:        int part;
        !           187:
        !           188:        for (part = 0; part < MAXPARTITIONS; part++)
        !           189:                zflash_safe_stop(sc, part);
        !           190:
        !           191:        return (flashdetach(self, flags));
        !           192: }
        !           193:
        !           194: u_int8_t
        !           195: zflash_reg8_read(void *arg, int reg)
        !           196: {
        !           197:        struct zflash_softc *sc = arg;
        !           198:        u_int8_t value;
        !           199:
        !           200:        switch (reg) {
        !           201:        case FLASH_REG_DATA:
        !           202:                value = CPLD_READ(sc, CPLD_REG_FLASHIO);
        !           203:                break;
        !           204:        case FLASH_REG_READY:
        !           205:                value = (CPLD_READ(sc, CPLD_REG_FLASHCTL) &
        !           206:                    FLASHCTL_RYBY) != 0;
        !           207:                break;
        !           208:        default:
        !           209: #ifdef DIAGNOSTIC
        !           210:                printf("%s: read from pseudo-register %02x\n",
        !           211:                    sc->sc_flash.sc_dev.dv_xname, reg);
        !           212: #endif
        !           213:                value = 0;
        !           214:                break;
        !           215:        }
        !           216:        return value;
        !           217: }
        !           218:
        !           219: void
        !           220: zflash_reg8_write(void *arg, int reg, u_int8_t value)
        !           221: {
        !           222:        struct zflash_softc *sc = arg;
        !           223:
        !           224:        switch (reg) {
        !           225:        case FLASH_REG_DATA:
        !           226:        case FLASH_REG_COL:
        !           227:        case FLASH_REG_ROW:
        !           228:        case FLASH_REG_CMD:
        !           229:                CPLD_WRITE(sc, CPLD_REG_FLASHIO, value);
        !           230:                break;
        !           231:        case FLASH_REG_ALE:
        !           232:                CPLD_SETORCLR(sc, CPLD_REG_FLASHCTL, FLASHCTL_ALE, value);
        !           233:                break;
        !           234:        case FLASH_REG_CLE:
        !           235:                CPLD_SETORCLR(sc, CPLD_REG_FLASHCTL, FLASHCTL_CLE, value);
        !           236:                break;
        !           237:        case FLASH_REG_CE:
        !           238:                CPLD_SETORCLR(sc, CPLD_REG_FLASHCTL, FLASHCTL_NCE, !value);
        !           239:                break;
        !           240:        case FLASH_REG_WP:
        !           241:                CPLD_SETORCLR(sc, CPLD_REG_FLASHCTL, FLASHCTL_NWP, !value);
        !           242:                break;
        !           243: #ifdef DIAGNOSTIC
        !           244:        default:
        !           245:                printf("%s: write to pseudo-register %02x\n",
        !           246:                    sc->sc_flash.sc_dev.dv_xname, reg);
        !           247: #endif
        !           248:        }
        !           249: }
        !           250:
        !           251: int
        !           252: zflash_regx_read_page(void *arg, caddr_t data, caddr_t oob)
        !           253: {
        !           254:        struct zflash_softc *sc = arg;
        !           255:
        !           256:        if (oob == NULL || sc->sc_flash.sc_flashdev->pagesize != 512) {
        !           257:                flash_reg8_read_page(&sc->sc_flash, data, oob);
        !           258:                return 0;
        !           259:        }
        !           260:
        !           261:        flash_reg8_read_page(&sc->sc_flash, data, oob);
        !           262:
        !           263:        oob[OOB_JFFS2_ECC0] = 0xff;
        !           264:        oob[OOB_JFFS2_ECC1] = 0xff;
        !           265:        oob[OOB_JFFS2_ECC2] = 0xff;
        !           266:        oob[OOB_JFFS2_ECC3] = 0xff;
        !           267:        oob[OOB_JFFS2_ECC4] = 0xff;
        !           268:        oob[OOB_JFFS2_ECC5] = 0xff;
        !           269:        return 0;
        !           270: }
        !           271:
        !           272: int
        !           273: zflash_regx_write_page(void *arg, caddr_t data, caddr_t oob)
        !           274: {
        !           275:        struct zflash_softc *sc = arg;
        !           276:        int i;
        !           277:
        !           278:        if (oob == NULL || sc->sc_flash.sc_flashdev->pagesize != 512) {
        !           279:                flash_reg8_write_page(&sc->sc_flash, data, oob);
        !           280:                return 0;
        !           281:        }
        !           282:
        !           283:        if (oob[OOB_JFFS2_ECC0] != 0xff || oob[OOB_JFFS2_ECC1] != 0xff ||
        !           284:            oob[OOB_JFFS2_ECC2] != 0xff || oob[OOB_JFFS2_ECC3] != 0xff ||
        !           285:            oob[OOB_JFFS2_ECC4] != 0xff || oob[OOB_JFFS2_ECC5] != 0xff) {
        !           286: #ifdef DIAGNOSTIC
        !           287:                printf("%s: non-FF ECC bytes in OOB data\n",
        !           288:                    sc->sc_flash.sc_dev.dv_xname);
        !           289: #endif
        !           290:                return EINVAL;
        !           291:        }
        !           292:
        !           293:        CPLD_WRITE(sc, CPLD_REG_ECCCLRR, 0x00);
        !           294:        for (i = 0; i < sc->sc_flash.sc_flashdev->pagesize / 2; i++)
        !           295:                flash_reg8_write(&sc->sc_flash, FLASH_REG_DATA, data[i]);
        !           296:
        !           297:        oob[OOB_JFFS2_ECC0] = ~CPLD_READ(sc, CPLD_REG_ECCLPUB);
        !           298:        oob[OOB_JFFS2_ECC1] = ~CPLD_READ(sc, CPLD_REG_ECCLPLB);
        !           299:        oob[OOB_JFFS2_ECC2] = (~CPLD_READ(sc, CPLD_REG_ECCCP) << 2) | 0x03;
        !           300:
        !           301:        if (CPLD_READ(sc, CPLD_REG_ECCCNTR) != 0) {
        !           302:                printf("%s: ECC failed\n", sc->sc_flash.sc_dev.dv_xname);
        !           303:                oob[OOB_JFFS2_ECC0] = 0xff;
        !           304:                oob[OOB_JFFS2_ECC1] = 0xff;
        !           305:                oob[OOB_JFFS2_ECC2] = 0xff;
        !           306:                return EIO;
        !           307:        }
        !           308:
        !           309:        CPLD_WRITE(sc, CPLD_REG_ECCCLRR, 0x00);
        !           310:        for (; i < sc->sc_flash.sc_flashdev->pagesize; i++)
        !           311:                flash_reg8_write(&sc->sc_flash, FLASH_REG_DATA, data[i]);
        !           312:
        !           313:        oob[OOB_JFFS2_ECC3] = ~CPLD_READ(sc, CPLD_REG_ECCLPUB);
        !           314:        oob[OOB_JFFS2_ECC4] = ~CPLD_READ(sc, CPLD_REG_ECCLPLB);
        !           315:        oob[OOB_JFFS2_ECC5] = (~CPLD_READ(sc, CPLD_REG_ECCCP) << 2) | 0x03;
        !           316:
        !           317:        if (CPLD_READ(sc, CPLD_REG_ECCCNTR) != 0) {
        !           318:                printf("%s: ECC failed\n", sc->sc_flash.sc_dev.dv_xname);
        !           319:                oob[OOB_JFFS2_ECC0] = 0xff;
        !           320:                oob[OOB_JFFS2_ECC1] = 0xff;
        !           321:                oob[OOB_JFFS2_ECC2] = 0xff;
        !           322:                oob[OOB_JFFS2_ECC3] = 0xff;
        !           323:                oob[OOB_JFFS2_ECC4] = 0xff;
        !           324:                oob[OOB_JFFS2_ECC5] = 0xff;
        !           325:                return EIO;
        !           326:        }
        !           327:
        !           328:        for (i = 0; i < sc->sc_flash.sc_flashdev->oobsize; i++)
        !           329:                flash_reg8_write(&sc->sc_flash, FLASH_REG_DATA, oob[i]);
        !           330:
        !           331:        oob[OOB_JFFS2_ECC0] = 0xff;
        !           332:        oob[OOB_JFFS2_ECC1] = 0xff;
        !           333:        oob[OOB_JFFS2_ECC2] = 0xff;
        !           334:        oob[OOB_JFFS2_ECC3] = 0xff;
        !           335:        oob[OOB_JFFS2_ECC4] = 0xff;
        !           336:        oob[OOB_JFFS2_ECC5] = 0xff;
        !           337:        return 0;
        !           338: }
        !           339:
        !           340: /*
        !           341:  * A default disklabel with only one RAW_PART spanning the whole
        !           342:  * device is passed to us. We add the partitions besides RAW_PART.
        !           343:  */
        !           344: void
        !           345: zflash_default_disklabel(void *arg, dev_t dev, struct disklabel *lp)
        !           346: {
        !           347:        struct zflash_softc *sc = arg;
        !           348:        long bsize = sc->sc_flash.sc_flashdev->pagesize;
        !           349:
        !           350:        switch (sc->sc_flash.sc_flashdev->id) {
        !           351:        case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
        !           352:                DL_SETPSIZE(&lp->d_partitions[8], 7*1024*1024 / bsize);
        !           353:                DL_SETPSIZE(&lp->d_partitions[9], 5*1024*1024 / bsize);
        !           354:                DL_SETPSIZE(&lp->d_partitions[10], 4*1024*1024 / bsize);
        !           355:                break;
        !           356:        case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
        !           357:                DL_SETPSIZE(&lp->d_partitions[8], 7*1024*1024 / bsize);
        !           358:                DL_SETPSIZE(&lp->d_partitions[9], 32*1024*1024 / bsize);
        !           359:                DL_SETPSIZE(&lp->d_partitions[10], 89*1024*1024 / bsize);
        !           360:                break;
        !           361:        default:
        !           362:                return;
        !           363:        }
        !           364:
        !           365:        /* The "smf" partition uses logical addressing. */
        !           366:        DL_SETPOFFSET(&lp->d_partitions[8], 0);
        !           367:        lp->d_partitions[8].p_fstype = FS_OTHER;
        !           368:
        !           369:        /* The "root" partition uses physical addressing. */
        !           370:        DL_SETPSIZE(&lp->d_partitions[9], DL_GETPSIZE(&lp->d_partitions[8]));
        !           371:        lp->d_partitions[9].p_fstype = FS_OTHER;
        !           372:
        !           373:        /* The "home" partition uses physical addressing. */
        !           374:        DL_SETPOFFSET(&lp->d_partitions[10],
        !           375:            DL_GETPOFFSET(&lp->d_partitions[9]) + DL_GETPSIZE(&lp->d_partitions[9]));
        !           376:        lp->d_partitions[10].p_fstype = FS_OTHER;
        !           377:        lp->d_npartitions = 11;
        !           378:
        !           379:        lp->d_version = 1;
        !           380:        /* Re-calculate the checksum. */
        !           381:        lp->d_checksum = dkcksum(lp);
        !           382: }
        !           383:
        !           384: /*
        !           385:  * Sharp's access strategy for bad blocks management and wear-leveling.
        !           386:  */
        !           387:
        !           388: #define PHYUSE_STATUS(v)       ((v) & 0x00ff)
        !           389: #define  P_BADBLOCK            0x0000
        !           390: #define  P_POSTBADBLOCK                0x00f0
        !           391: #define  P_NORMALBLOCK         0x00ff
        !           392: #define PHYUSE_WRITTEN(v)      ((v) & 0xff00)
        !           393: #define  P_DUST                        0x0000
        !           394: #define  P_LOGICAL             0x0100
        !           395: #define  P_JFFS2               0x0300
        !           396:
        !           397: void     zflash_write_strategy(struct zflash_softc *, struct buf *,
        !           398:     struct zflash_safe *, u_int, u_int);
        !           399: u_int    zflash_safe_next_block(struct zflash_safe *);
        !           400:
        !           401: u_char   zflash_oob_status_decode(u_char);
        !           402: u_int16_t zflash_oob_status(struct zflash_softc *, u_char *);
        !           403: u_int    zflash_oob_logno(struct zflash_softc *, u_char *);
        !           404: void     zflash_oob_set_status(struct zflash_softc *, u_char *, u_int16_t);
        !           405: void     zflash_oob_set_logno(struct zflash_softc *, u_char *, u_int);
        !           406:
        !           407: int
        !           408: zflash_safe_strategy(void *arg, struct buf *bp)
        !           409: {
        !           410:        struct zflash_softc *sc = arg;
        !           411:        struct zflash_safe *sp;
        !           412:        u_int logno;
        !           413:        u_int blkofs;
        !           414:        u_int blkno;
        !           415:        int error;
        !           416:        int part;
        !           417:        int i;
        !           418:
        !           419:        /* Initialize logical blocks management on the fly. */
        !           420:        /* XXX toss everything when the disklabel has changed. */
        !           421:        if ((error = zflash_safe_start(sc, bp->b_dev)) != 0) {
        !           422:                bp->b_error = error;
        !           423:                bp->b_flags |= B_ERROR;
        !           424:                return 0;
        !           425:        }
        !           426:
        !           427:        part = flashpart(bp->b_dev);
        !           428:        sp = sc->sc_safe[part];
        !           429:
        !           430:        logno = bp->b_blkno / (sc->sc_flash.sc_flashdev->blkpages *
        !           431:            sc->sc_flash.sc_flashdev->pagesize / DEV_BSIZE);
        !           432:        blkofs = bp->b_blkno % (sc->sc_flash.sc_flashdev->blkpages *
        !           433:            sc->sc_flash.sc_flashdev->pagesize / DEV_BSIZE);
        !           434:
        !           435:        /* If exactly at end of logical flash, return EOF, else error. */
        !           436:        if (logno == sp->sp_lblks && blkofs == 0) {
        !           437:                bp->b_resid = bp->b_bcount;
        !           438:                return 0;
        !           439:        } else if (logno >= sp->sp_lblks) {
        !           440:                bp->b_error = EINVAL;
        !           441:                bp->b_flags |= B_ERROR;
        !           442:                return 0;
        !           443:        }
        !           444:
        !           445:        /* Writing is more complicated, so handle it separately. */
        !           446:        if ((bp->b_flags & B_READ) == 0) {
        !           447:                flash_chip_enable(&sc->sc_flash);
        !           448:                zflash_write_strategy(sc, bp, sp, logno, blkofs);
        !           449:                flash_chip_disable(&sc->sc_flash);
        !           450:                return 0;
        !           451:        }
        !           452:
        !           453:        /* Get the physical flash block number for this logical one. */
        !           454:        blkno = sp->sp_logmap[logno];
        !           455:
        !           456:        /* Unused logical blocks read as all 0xff. */
        !           457:        if ((bp->b_flags & B_READ) != 0 && blkno == UINT_MAX) {
        !           458:                for (i = 0; i < sc->sc_flash.sc_flashdev->pagesize; i++)
        !           459:                        ((u_char *)bp->b_data)[i] = 0xff;
        !           460:                bp->b_resid = bp->b_bcount -
        !           461:                    sc->sc_flash.sc_flashdev->pagesize;
        !           462:                return 0;
        !           463:        }
        !           464:
        !           465:        /* Update the block number in the buffer with the physical one. */
        !           466:        bp->b_blkno = blkno * (sc->sc_flash.sc_flashdev->blkpages *
        !           467:            sc->sc_flash.sc_flashdev->pagesize / DEV_BSIZE) + blkofs;
        !           468:
        !           469:        /* Process the modified transfer buffer normally. */
        !           470:        return 1;
        !           471: }
        !           472:
        !           473: void
        !           474: zflash_write_strategy(struct zflash_softc *sc, struct buf *bp,
        !           475:     struct zflash_safe *sp, u_int logno, u_int logofs)
        !           476: {
        !           477:        size_t  bufsize;
        !           478:        u_char *buf = NULL;
        !           479:        size_t  oobsize;
        !           480:        u_char *oob = NULL;
        !           481:        u_int   oblkno;
        !           482:        u_int   nblkno;
        !           483:        int     error;
        !           484:
        !           485:        /* Not efficient, but we always transfer one page for now. */
        !           486:        if (bp->b_bcount < sc->sc_flash.sc_flashdev->pagesize) {
        !           487:                bp->b_error = EINVAL;
        !           488:                goto bad;
        !           489:        }
        !           490:
        !           491:        /* Allocate a temporary buffer for one flash block. */
        !           492:        bufsize = sc->sc_flash.sc_flashdev->blkpages *
        !           493:            sc->sc_flash.sc_flashdev->pagesize;
        !           494:        buf = (u_char *)malloc(bufsize, M_DEVBUF, M_NOWAIT);
        !           495:        if (buf == NULL) {
        !           496:                bp->b_error = ENOMEM;
        !           497:                goto bad;
        !           498:        }
        !           499:
        !           500:        /* Allocate a temporary buffer for one spare area. */
        !           501:        oobsize = sc->sc_flash.sc_flashdev->oobsize;
        !           502:        oob = (u_char *)malloc(oobsize, M_DEVBUF, M_NOWAIT);
        !           503:        if (oob == NULL) {
        !           504:                bp->b_error = ENOMEM;
        !           505:                goto bad;
        !           506:        }
        !           507:
        !           508:        /* Read the old logical block into the temporary buffer. */
        !           509:        oblkno = sp->sp_logmap[logno];
        !           510:        if (oblkno != UINT_MAX) {
        !           511:                error = flash_chip_read_block(&sc->sc_flash, oblkno, buf);
        !           512:                if (error != 0) {
        !           513:                        bp->b_error = error;
        !           514:                        goto bad;
        !           515:                }
        !           516:        } else
        !           517:                /* Unused logical blocks read as all 0xff. */
        !           518:                memset(buf, 0xff, bufsize);
        !           519:
        !           520:        /* Transfer the page into the logical block buffer. */
        !           521:        bcopy(bp->b_data, buf + logofs * sc->sc_flash.sc_flashdev->pagesize,
        !           522:            sc->sc_flash.sc_flashdev->pagesize);
        !           523:
        !           524:        /* Generate OOB data for the spare area of this logical block. */
        !           525:        memset(oob, 0xff, oobsize);
        !           526:        zflash_oob_set_status(sc, oob, P_NORMALBLOCK);
        !           527:        zflash_oob_set_logno(sc, oob, logno);
        !           528:
        !           529:        while (1) {
        !           530:                /* Search for a free physical block. */
        !           531:                nblkno = zflash_safe_next_block(sp);
        !           532:                if (nblkno == UINT_MAX) {
        !           533:                        printf("%s: no spare block, giving up on logical"
        !           534:                            " block %u\n", sc->sc_flash.sc_dev.dv_xname,
        !           535:                            logno);
        !           536:                        bp->b_error = ENOSPC;
        !           537:                        goto bad;
        !           538:                }
        !           539:
        !           540: #if 0
        !           541:                DPRINTF(("%s: moving logical block %u from physical %u to %u\n",
        !           542:                    sc->sc_flash.sc_dev.dv_xname, logno, oblkno, nblkno));
        !           543: #endif
        !           544:
        !           545:                /* Erase the free physical block. */
        !           546:                if (flash_chip_erase_block(&sc->sc_flash, nblkno) != 0) {
        !           547:                        printf("%s: can't erase block %u, retrying\n",
        !           548:                            sc->sc_flash.sc_dev.dv_xname, nblkno);
        !           549:                        sp->sp_phyuse[nblkno] = P_POSTBADBLOCK | P_DUST;
        !           550:                        continue;
        !           551:                }
        !           552:
        !           553:                /* Write the logical block to the free physical block. */
        !           554:                if (flash_chip_write_block(&sc->sc_flash, nblkno, buf, oob)) {
        !           555:                        printf("%s: can't write block %u, retrying\n",
        !           556:                            sc->sc_flash.sc_dev.dv_xname, nblkno);
        !           557:                        goto trynext;
        !           558:                }
        !           559:
        !           560:                /* Yeah, we re-wrote that logical block! */
        !           561:                break;
        !           562:        trynext:
        !           563:                sp->sp_phyuse[nblkno] = P_POSTBADBLOCK | P_DUST;
        !           564:                (void)flash_chip_erase_block(&sc->sc_flash, nblkno);
        !           565:        }
        !           566:
        !           567:        /* Map the new physical block. */
        !           568:        sp->sp_logmap[logno] = nblkno;
        !           569:        sp->sp_phyuse[nblkno] = PHYUSE_STATUS(sp->sp_phyuse[nblkno])
        !           570:            | P_LOGICAL;
        !           571:
        !           572:        /* Erase the old physical block. */
        !           573:        if (oblkno != UINT_MAX) {
        !           574:                sp->sp_phyuse[oblkno] = PHYUSE_STATUS(sp->sp_phyuse[oblkno])
        !           575:                    | P_DUST;
        !           576:                error = flash_chip_erase_block(&sc->sc_flash, oblkno);
        !           577:                if (error != 0) {
        !           578:                        printf("%s: can't erase old block %u\n",
        !           579:                            sc->sc_flash.sc_dev.dv_xname, oblkno);
        !           580:                        bp->b_error = error;
        !           581:                        goto bad;
        !           582:                }
        !           583:        }
        !           584:
        !           585:        bp->b_resid = bp->b_bcount - sc->sc_flash.sc_flashdev->pagesize;
        !           586:        free(oob, M_DEVBUF);
        !           587:        free(buf, M_DEVBUF);
        !           588:        return;
        !           589: bad:
        !           590:        bp->b_flags |= B_ERROR;
        !           591:        if (oob != NULL)
        !           592:                free(oob, M_DEVBUF);
        !           593:        if (buf != NULL)
        !           594:                free(buf, M_DEVBUF);
        !           595: }
        !           596:
        !           597: int
        !           598: zflash_safe_start(struct zflash_softc *sc, dev_t dev)
        !           599: {
        !           600:        u_char oob[FLASH_MAXOOBSIZE];
        !           601:        struct disklabel *lp = sc->sc_flash.sc_dk.dk_label;
        !           602:        struct zflash_safe *sp;
        !           603:        u_int16_t *phyuse;
        !           604:        u_int *logmap;
        !           605:        u_int blksect;
        !           606:        u_int blkno;
        !           607:        u_int logno;
        !           608:        u_int unusable;
        !           609:        int part;
        !           610:
        !           611:        part = flashpart(dev);
        !           612:        if (sc->sc_safe[part] != NULL)
        !           613:                return 0;
        !           614:
        !           615:        /* We can only handle so much OOB data here. */
        !           616:        if (sc->sc_flash.sc_flashdev->oobsize > FLASH_MAXOOBSIZE)
        !           617:                return EIO;
        !           618:
        !           619:        /* Safe partitions must start on a flash block boundary. */
        !           620:        blksect = (sc->sc_flash.sc_flashdev->blkpages *
        !           621:            sc->sc_flash.sc_flashdev->pagesize) / lp->d_secsize;
        !           622:        if (DL_GETPOFFSET(&lp->d_partitions[part]) % blksect)
        !           623:                return EIO;
        !           624:
        !           625:        MALLOC(sp, struct zflash_safe *, sizeof(struct zflash_safe),
        !           626:            M_DEVBUF, M_NOWAIT);
        !           627:        if (sp == NULL)
        !           628:                return ENOMEM;
        !           629:
        !           630:        bzero(sp, sizeof(struct zflash_safe));
        !           631:        sp->sp_dev = dev;
        !           632:
        !           633:        sp->sp_pblks = DL_GETPSIZE(&lp->d_partitions[part]) / blksect;
        !           634:        sp->sp_lblks = sp->sp_pblks;
        !           635:
        !           636:        /* Try to reserve a number of spare physical blocks. */
        !           637:        switch (sc->sc_flash.sc_flashdev->id) {
        !           638:        case FLASH_DEVICE_SAMSUNG_K9F2808U0C:
        !           639:                sp->sp_lblks -= 24; /* C3000 */
        !           640:                break;
        !           641:        case FLASH_DEVICE_SAMSUNG_K9F1G08U0A:
        !           642:                sp->sp_lblks -= 4;  /* C3100 */
        !           643:                break;
        !           644:        }
        !           645:
        !           646:        DPRINTF(("pblks %u lblks %u\n", sp->sp_pblks, sp->sp_lblks));
        !           647:
        !           648:        /* Next physical block to use; randomize for wear-leveling. */
        !           649:        sp->sp_pnext = arc4random() % sp->sp_pblks;
        !           650:
        !           651:        /* Allocate physical block usage map. */
        !           652:        phyuse = (u_int16_t *)malloc(sp->sp_pblks * sizeof(u_int16_t),
        !           653:            M_DEVBUF, M_NOWAIT);
        !           654:        if (phyuse == NULL) {
        !           655:                FREE(sp, M_DEVBUF);
        !           656:                return ENOMEM;
        !           657:        }
        !           658:        sp->sp_phyuse = phyuse;
        !           659:
        !           660:        /* Allocate logical to physical block map. */
        !           661:        logmap = (u_int *)malloc(sp->sp_lblks * sizeof(u_int),
        !           662:            M_DEVBUF, M_NOWAIT);
        !           663:        if (logmap == NULL) {
        !           664:                FREE(phyuse, M_DEVBUF);
        !           665:                FREE(sp, M_DEVBUF);
        !           666:                return ENOMEM;
        !           667:        }
        !           668:        sp->sp_logmap = logmap;
        !           669:
        !           670:        /* Initialize the physical and logical block maps. */
        !           671:        for (blkno = 0; blkno < sp->sp_pblks; blkno++)
        !           672:                phyuse[blkno] = P_BADBLOCK | P_DUST;
        !           673:        for (blkno = 0; blkno < sp->sp_lblks; blkno++)
        !           674:                logmap[blkno] = UINT_MAX;
        !           675:
        !           676:        /* Update physical block usage map with real data. */
        !           677:        unusable = 0;
        !           678:        flash_chip_enable(&sc->sc_flash);
        !           679:        for (blkno = 0; blkno < sp->sp_pblks; blkno++) {
        !           680:                long pageno;
        !           681:
        !           682:                pageno = blkno * sc->sc_flash.sc_flashdev->blkpages;
        !           683:                if (flash_chip_read_oob(&sc->sc_flash, pageno, oob) != 0) {
        !           684:                        DPRINTF(("blkno %u: can't read oob data\n", blkno));
        !           685:                        phyuse[blkno] = P_POSTBADBLOCK | P_DUST;
        !           686:                        unusable++;
        !           687:                        continue;
        !           688:                }
        !           689:
        !           690:                phyuse[blkno] = zflash_oob_status(sc, oob);
        !           691:                if (PHYUSE_STATUS(phyuse[blkno]) != P_NORMALBLOCK) {
        !           692:                        DPRINTF(("blkno %u: badblock status %x\n", blkno,
        !           693:                            PHYUSE_STATUS(phyuse[blkno])));
        !           694:                        phyuse[blkno] |= P_DUST;
        !           695:                        unusable++;
        !           696:                        continue;
        !           697:                }
        !           698:
        !           699:                logno = zflash_oob_logno(sc, oob);
        !           700:                if (logno == UINT_MAX) {
        !           701:                        DPRINTF(("blkno %u: can't read logno\n", blkno));
        !           702:                        phyuse[blkno] |= P_JFFS2;
        !           703:                        unusable++;
        !           704:                        continue;
        !           705:                }
        !           706:
        !           707:                if (logno == USHRT_MAX) {
        !           708:                        phyuse[blkno] |= P_DUST;
        !           709:                        /* Block is usable and available. */
        !           710:                        continue;
        !           711:                }
        !           712:
        !           713:                if (logno >= sp->sp_lblks) {
        !           714:                        DPRINTF(("blkno %u: logno %u too big\n", blkno,
        !           715:                            logno));
        !           716:                        phyuse[blkno] |= P_JFFS2;
        !           717:                        unusable++;
        !           718:                        continue;
        !           719:                }
        !           720:
        !           721:                if (logmap[logno] == UINT_MAX) {
        !           722:                        phyuse[blkno] |= P_LOGICAL;
        !           723:                        logmap[logno] = blkno;
        !           724:                } else {
        !           725:                        /* Duplicate logical block! */
        !           726:                        DPRINTF(("blkno %u: duplicate logno %u\n", blkno,
        !           727:                            logno));
        !           728:                        phyuse[blkno] |= P_DUST;
        !           729:                }
        !           730:        }
        !           731:        flash_chip_disable(&sc->sc_flash);
        !           732:
        !           733:        if (unusable > 0)
        !           734:                printf("%s: %u unusable blocks\n",
        !           735:                    sc->sc_flash.sc_dev.dv_xname, unusable);
        !           736:
        !           737:        sc->sc_safe[part] = sp;
        !           738:        return 0;
        !           739: }
        !           740:
        !           741: void
        !           742: zflash_safe_stop(struct zflash_softc *sc, dev_t dev)
        !           743: {
        !           744:        struct zflash_safe *sp;
        !           745:        int part;
        !           746:
        !           747:        part = flashpart(dev);
        !           748:        if (sc->sc_safe[part] == NULL)
        !           749:                return;
        !           750:
        !           751:        sp = sc->sc_safe[part];
        !           752:        free(sp->sp_phyuse, M_DEVBUF);
        !           753:        free(sp->sp_logmap, M_DEVBUF);
        !           754:        FREE(sp, M_DEVBUF);
        !           755:        sc->sc_safe[part] = NULL;
        !           756: }
        !           757:
        !           758: u_int
        !           759: zflash_safe_next_block(struct zflash_safe *sp)
        !           760: {
        !           761:        u_int blkno;
        !           762:
        !           763:        for (blkno = sp->sp_pnext; blkno < sp->sp_pblks; blkno++)
        !           764:                if (sp->sp_phyuse[blkno] == (P_NORMALBLOCK|P_DUST)) {
        !           765:                        sp->sp_pnext = blkno + 1;
        !           766:                        return blkno;
        !           767:                }
        !           768:
        !           769:        for (blkno = 0; blkno < sp->sp_pnext; blkno++)
        !           770:                if (sp->sp_phyuse[blkno] == (P_NORMALBLOCK|P_DUST)) {
        !           771:                        sp->sp_pnext = blkno + 1;
        !           772:                        return blkno;
        !           773:                }
        !           774:
        !           775:        return UINT_MAX;
        !           776: }
        !           777:
        !           778: /*
        !           779:  * Correct single bit errors in the block's status byte.
        !           780:  */
        !           781: u_char
        !           782: zflash_oob_status_decode(u_char status)
        !           783: {
        !           784:        u_char bit;
        !           785:        int count;
        !           786:
        !           787:        /* Speed-up. */
        !           788:        if (status == 0xff)
        !           789:                return 0xff;
        !           790:
        !           791:        /* Count the number of bits set in the byte. */
        !           792:        for (count = 0, bit = 0x01; bit != 0x00; bit <<= 1)
        !           793:                if ((status & bit) != 0)
        !           794:                        count++;
        !           795:
        !           796:        return (count > 6) ? 0xff : 0x00;
        !           797: }
        !           798:
        !           799: /*
        !           800:  * Decode the block's status byte into a value for the phyuse map.
        !           801:  */
        !           802: u_int16_t
        !           803: zflash_oob_status(struct zflash_softc *sc, u_char *oob)
        !           804: {
        !           805:        u_char status;
        !           806:
        !           807:        status = zflash_oob_status_decode(oob[sc->sc_ioobbadblk]);
        !           808:        if (status != 0xff)
        !           809:                return P_BADBLOCK;
        !           810:
        !           811:        status = zflash_oob_status_decode(oob[sc->sc_ioobpostbadblk]);
        !           812:        if (status != 0xff)
        !           813:                return P_POSTBADBLOCK;
        !           814:
        !           815:        return P_NORMALBLOCK;
        !           816: }
        !           817:
        !           818: /*
        !           819:  * Extract the 16-bit logical block number corresponding to a physical
        !           820:  * block from the physical block's OOB data.
        !           821:  */
        !           822: u_int
        !           823: zflash_oob_logno(struct zflash_softc *sc, u_char *oob)
        !           824: {
        !           825:        int idx_lo, idx_hi;
        !           826:        u_int16_t word;
        !           827:        u_int16_t bit;
        !           828:        int parity;
        !           829:
        !           830:        /* Find a matching pair of high and low bytes. */
        !           831:        if (oob[OOB_LOGADDR_0_LO] == oob[OOB_LOGADDR_1_LO] &&
        !           832:            oob[OOB_LOGADDR_0_HI] == oob[OOB_LOGADDR_1_HI]) {
        !           833:                idx_lo = OOB_LOGADDR_0_LO;
        !           834:                idx_hi = OOB_LOGADDR_0_HI;
        !           835:        } else if (oob[OOB_LOGADDR_1_LO] == oob[OOB_LOGADDR_2_LO] &&
        !           836:            oob[OOB_LOGADDR_1_HI] == oob[OOB_LOGADDR_2_HI]) {
        !           837:                idx_lo = OOB_LOGADDR_1_LO;
        !           838:                idx_hi = OOB_LOGADDR_1_HI;
        !           839:        } else if (oob[OOB_LOGADDR_2_LO] == oob[OOB_LOGADDR_0_LO] &&
        !           840:            oob[OOB_LOGADDR_2_HI] == oob[OOB_LOGADDR_0_HI]) {
        !           841:                idx_lo = OOB_LOGADDR_2_LO;
        !           842:                idx_hi = OOB_LOGADDR_2_HI;
        !           843:        } else
        !           844:                /* Block's OOB data may be invalid. */
        !           845:                return UINT_MAX;
        !           846:
        !           847:        word = ((u_int16_t)oob[idx_lo] << 0) |
        !           848:            ((u_int16_t)oob[idx_hi] << 8);
        !           849:
        !           850:        /* Check for parity error in the logical block number. */
        !           851:        for (parity = 0, bit = 0x0001; bit != 0x0000; bit <<= 1)
        !           852:                if ((word & bit) != 0)
        !           853:                        parity++;
        !           854:        if ((parity & 1) != 0)
        !           855:                return UINT_MAX;
        !           856:
        !           857:        /* No logical block number assigned to this block? */
        !           858:        if (word == USHRT_MAX)
        !           859:                return word;
        !           860:
        !           861:        /* Return the validated logical block number. */
        !           862:        return (word & 0x07fe) >> 1;
        !           863: }
        !           864:
        !           865: void
        !           866: zflash_oob_set_status(struct zflash_softc *sc, u_char *oob, u_int16_t phyuse)
        !           867: {
        !           868:        switch (PHYUSE_STATUS(phyuse)) {
        !           869:        case P_NORMALBLOCK:
        !           870:                oob[sc->sc_ioobbadblk] = 0xff;
        !           871:                oob[sc->sc_ioobpostbadblk] = 0xff;
        !           872:                break;
        !           873:        case P_BADBLOCK:
        !           874:                oob[sc->sc_ioobbadblk] = 0x00;
        !           875:                oob[sc->sc_ioobpostbadblk] = 0x00;
        !           876:                break;
        !           877:        case P_POSTBADBLOCK:
        !           878:                oob[sc->sc_ioobbadblk] = 0xff;
        !           879:                oob[sc->sc_ioobpostbadblk] = 0x00;
        !           880:                break;
        !           881:        }
        !           882: }
        !           883:
        !           884: void
        !           885: zflash_oob_set_logno(struct zflash_softc *sc, u_char *oob, u_int logno)
        !           886: {
        !           887:        u_int16_t word;
        !           888:        u_int16_t bit;
        !           889:        u_char lo;
        !           890:        u_char hi;
        !           891:        int parity;
        !           892:
        !           893:        /* Why do we set the most significant bit? */
        !           894:        word = ((logno & 0x03ff) << 1) | 0x1000;
        !           895:
        !           896:        /* Calculate the parity. */
        !           897:        for (bit = 0x0001; bit != 0x0000; bit <<= 1)
        !           898:                if ((word & bit) != 0)
        !           899:                        parity++;
        !           900:        if ((parity & 1) != 0)
        !           901:                word |= 0x0001;
        !           902:
        !           903:        lo = word & 0x00ff;
        !           904:        hi = (word & 0xff00) >> 8;
        !           905:
        !           906:        oob[OOB_LOGADDR_0_LO] = lo;
        !           907:        oob[OOB_LOGADDR_0_HI] = hi;
        !           908:        oob[OOB_LOGADDR_1_LO] = lo;
        !           909:        oob[OOB_LOGADDR_1_HI] = hi;
        !           910:        oob[OOB_LOGADDR_2_LO] = lo;
        !           911:        oob[OOB_LOGADDR_2_HI] = hi;
        !           912: }

CVSweb