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