1 /* $OpenBSD: amdcf.c,v 1.9 2022/10/23 19:33:39 krw Exp $ */ 2 3 /* 4 * Copyright (c) 2007, Juniper Networks, Inc. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the author nor the names of any co-contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 2009 Sam Leffler, Errno Consulting 34 * All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 45 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 46 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 47 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 48 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 49 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 50 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 51 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 52 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 53 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 54 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57 /* 58 * Copyright (c) 2015 Paul Irofti. 59 * 60 * Permission to use, copy, modify, and distribute this software for any 61 * purpose with or without fee is hereby granted, provided that the above 62 * copyright notice and this permission notice appear in all copies. 63 * 64 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 65 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 66 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 67 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 68 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 69 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 70 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 71 */ 72 73 74 #include <sys/param.h> 75 #include <sys/systm.h> 76 #include <sys/kernel.h> 77 #include <sys/conf.h> 78 #include <sys/fcntl.h> 79 #include <sys/stat.h> 80 #include <sys/ioctl.h> 81 #include <sys/mutex.h> 82 #include <sys/buf.h> 83 #include <sys/uio.h> 84 #include <sys/malloc.h> 85 #include <sys/device.h> 86 #include <sys/disklabel.h> 87 #include <sys/disk.h> 88 #include <sys/syslog.h> 89 #include <sys/proc.h> 90 #include <sys/vnode.h> 91 #include <sys/dkio.h> 92 93 #include <machine/intr.h> 94 #include <machine/bus.h> 95 #include <machine/autoconf.h> 96 97 #include <octeon/dev/iobusvar.h> 98 #include <machine/octeonreg.h> 99 #include <machine/octeonvar.h> 100 101 102 #define CFI_QRY_CMD_ADDR 0x55 103 #define CFI_QRY_CMD_DATA 0x98 104 105 #define CFI_QRY_TTO_WRITE 0x1f 106 #define CFI_QRY_TTO_ERASE 0x21 107 #define CFI_QRY_MTO_WRITE 0x23 108 #define CFI_QRY_MTO_ERASE 0x25 109 110 #define CFI_QRY_SIZE 0x27 111 #define CFI_QRY_NREGIONS 0x2c 112 #define CFI_QRY_REGION0 0x31 113 #define CFI_QRY_REGION(x) (CFI_QRY_REGION0 + (x) * 4) 114 115 #define CFI_BCS_READ_ARRAY 0xff 116 117 #define CFI_DISK_SECSIZE 512 118 #define CFI_DISK_MAXIOSIZE 65536 119 120 #define AMDCF_MAP_SIZE 0x02000000 121 122 #define CFI_AMD_BLOCK_ERASE 0x30 123 #define CFI_AMD_UNLOCK 0xaa 124 #define CFI_AMD_UNLOCK_ACK 0x55 125 #define CFI_AMD_PROGRAM 0xa0 126 #define CFI_AMD_RESET 0xf0 127 128 #define AMD_ADDR_START 0x555 129 #define AMD_ADDR_ACK 0x2aa 130 131 #define BOOTLOADER_ADDR 0xa0000 132 133 struct cfi_region { 134 u_int r_blocks; 135 u_int r_blksz; 136 }; 137 138 struct amdcf_softc { 139 /* General disk infos */ 140 struct device sc_dev; 141 struct disk sc_dk; 142 struct bufq sc_bufq; 143 struct buf *sc_bp; 144 145 int sc_flags; 146 #define AMDCF_LOADED 0x10 147 148 struct iobus_attach_args *sc_io; 149 bus_space_tag_t sc_iot; 150 bus_space_handle_t sc_ioh; 151 152 size_t sc_size; /* Disk size in bytes */ 153 u_int sc_regions; /* Erase regions. */ 154 struct cfi_region *sc_region; /* Array of region info. */ 155 156 u_int sc_width; 157 u_int sc_shift; 158 u_int sc_mask; 159 160 u_int sc_erase_timeout; 161 u_int sc_erase_max_timeout; 162 u_int sc_write_timeout; 163 u_int sc_write_max_timeout; 164 u_int sc_rstcmd; 165 166 u_char *sc_wrbuf; 167 u_int sc_wrbufsz; 168 u_int sc_wrofs; 169 u_int sc_writing; 170 }; 171 172 int amdcf_match(struct device *, void *, void *); 173 void amdcf_attach(struct device *, struct device *, void *); 174 int amdcf_detach(struct device *, int); 175 176 const struct cfattach amdcf_ca = { 177 sizeof(struct amdcf_softc), amdcf_match, amdcf_attach, amdcf_detach 178 }; 179 180 struct cfdriver amdcf_cd = { 181 NULL, "amdcf", DV_DISK 182 }; 183 184 cdev_decl(amdcf); 185 bdev_decl(amdcf); 186 187 #define amdcflookup(unit) (struct amdcf_softc *)disk_lookup(&amdcf_cd, (unit)) 188 int amdcfgetdisklabel(dev_t, struct amdcf_softc *, struct disklabel *, int); 189 190 void amdcfstart(void *); 191 void _amdcfstart(struct amdcf_softc *, struct buf *); 192 void amdcfdone(void *); 193 194 void amdcf_disk_read(struct amdcf_softc *, struct buf *, off_t); 195 void amdcf_disk_write(struct amdcf_softc *, struct buf *, off_t); 196 197 int cfi_block_start(struct amdcf_softc *, u_int); 198 int cfi_write_block(struct amdcf_softc *); 199 int cfi_erase_block(struct amdcf_softc *, u_int); 200 int cfi_block_finish(struct amdcf_softc *); 201 202 void cfi_array_write(struct amdcf_softc *sc, u_int, u_int, u_int); 203 void cfi_amd_write(struct amdcf_softc *, u_int, u_int, u_int); 204 205 uint8_t cfi_read_qry(struct amdcf_softc *, uint64_t); 206 uint8_t cfi_read(struct amdcf_softc *, bus_size_t, bus_size_t); 207 void cfi_write(struct amdcf_softc *, bus_size_t, bus_size_t, uint8_t); 208 int cfi_wait_ready(struct amdcf_softc *, u_int, u_int, u_int); 209 int cfi_make_cmd(uint8_t, u_int); 210 211 int 212 amdcf_match(struct device *parent, void *match, void *aux) 213 { 214 struct mainbus_attach_args *maa = aux; 215 struct cfdata *cf = match; 216 217 if (strcmp(maa->maa_name, cf->cf_driver->cd_name) != 0) 218 return 0; 219 220 /* Only for DSR machines */ 221 if (octeon_board != BOARD_DLINK_DSR_500) 222 return 0; 223 224 return 1; 225 } 226 227 void 228 amdcf_attach(struct device *parent, struct device *self, void *aux) 229 { 230 struct amdcf_softc *sc = (void *)self; 231 u_int blksz, blocks, r; 232 233 sc->sc_io = aux; 234 sc->sc_iot = sc->sc_io->aa_bust; 235 236 if (bus_space_map(sc->sc_iot, OCTEON_AMDCF_BASE, AMDCF_MAP_SIZE, 0, 237 &sc->sc_ioh)) { 238 printf(": can't map registers"); 239 } 240 241 /* should be detected in the generic driver */ 242 sc->sc_width = 1; 243 sc->sc_shift = 2; 244 sc->sc_mask = 0x000000ff; 245 sc->sc_rstcmd = CFI_AMD_RESET; 246 247 /* Initialize the Query Database from the CF */ 248 cfi_array_write(sc, 0, 0, sc->sc_rstcmd); 249 cfi_write(sc, 0, CFI_QRY_CMD_ADDR, CFI_QRY_CMD_DATA); 250 251 /* Get time-out values for erase and write. */ 252 sc->sc_write_timeout = 1 << cfi_read(sc, 0, CFI_QRY_TTO_WRITE); 253 sc->sc_erase_timeout = 1 << cfi_read(sc, 0, CFI_QRY_TTO_ERASE); 254 sc->sc_write_max_timeout = 1 << cfi_read(sc, 0, CFI_QRY_MTO_WRITE); 255 sc->sc_erase_max_timeout = 1 << cfi_read(sc, 0, CFI_QRY_MTO_ERASE); 256 257 /* Get the device size. */ 258 sc->sc_size = 1U << cfi_read(sc, 0, CFI_QRY_SIZE); 259 printf(": AMD/Fujitsu %zu bytes\n", sc->sc_size); 260 261 /* Get erase regions. */ 262 sc->sc_regions = cfi_read(sc, 0, CFI_QRY_NREGIONS); 263 sc->sc_region = malloc(sc->sc_regions * 264 sizeof(struct cfi_region), M_TEMP, M_WAITOK | M_ZERO); 265 266 for (r = 0; r < sc->sc_regions; r++) { 267 blocks = cfi_read(sc, 0, CFI_QRY_REGION(r)) | 268 (cfi_read(sc, 0, CFI_QRY_REGION(r) + 1) << 8); 269 sc->sc_region[r].r_blocks = blocks + 1; 270 271 blksz = cfi_read(sc, 0, CFI_QRY_REGION(r) + 2) | 272 (cfi_read(sc, 0, CFI_QRY_REGION(r) + 3) << 8); 273 sc->sc_region[r].r_blksz = (blksz == 0) ? 128 : 274 blksz * 256; 275 } 276 277 /* Reset the device to the default state */ 278 cfi_array_write(sc, 0, 0, sc->sc_rstcmd); 279 280 /* 281 * Initialize disk structures. 282 */ 283 sc->sc_dk.dk_name = sc->sc_dev.dv_xname; 284 bufq_init(&sc->sc_bufq, BUFQ_DEFAULT); 285 286 /* Attach disk. */ 287 disk_attach(&sc->sc_dev, &sc->sc_dk); 288 289 } 290 291 int 292 amdcf_detach(struct device *self, int flags) 293 { 294 struct amdcf_softc *sc = (struct amdcf_softc *)self; 295 296 bufq_drain(&sc->sc_bufq); 297 298 disk_gone(amdcfopen, self->dv_unit); 299 300 /* Detach disk. */ 301 bufq_destroy(&sc->sc_bufq); 302 disk_detach(&sc->sc_dk); 303 304 return 0; 305 } 306 307 308 int 309 amdcfopen(dev_t dev, int flag, int fmt, struct proc *p) 310 { 311 struct amdcf_softc *sc; 312 int unit, part; 313 int error; 314 315 unit = DISKUNIT(dev); 316 sc = amdcflookup(unit); 317 if (sc == NULL) 318 return ENXIO; 319 320 /* 321 * If this is the first open of this device, add a reference 322 * to the adapter. 323 */ 324 if ((error = disk_lock(&sc->sc_dk)) != 0) 325 goto out1; 326 327 if (sc->sc_dk.dk_openmask != 0) { 328 /* 329 * If any partition is open, but the disk has been invalidated, 330 * disallow further opens. 331 */ 332 if ((sc->sc_flags & AMDCF_LOADED) == 0) { 333 error = EIO; 334 goto out; 335 } 336 } else { 337 if ((sc->sc_flags & AMDCF_LOADED) == 0) { 338 sc->sc_flags |= AMDCF_LOADED; 339 340 /* Load the partition info if not already loaded. */ 341 if (amdcfgetdisklabel(dev, sc, 342 sc->sc_dk.dk_label, 0) == EIO) { 343 error = EIO; 344 goto out; 345 } 346 } 347 } 348 349 part = DISKPART(dev); 350 351 if ((error = disk_openpart(&sc->sc_dk, part, fmt, 1)) != 0) 352 goto out; 353 354 disk_unlock(&sc->sc_dk); 355 device_unref(&sc->sc_dev); 356 return 0; 357 358 out: 359 disk_unlock(&sc->sc_dk); 360 out1: 361 device_unref(&sc->sc_dev); 362 return error; 363 } 364 365 /* 366 * Load the label information on the named device 367 */ 368 int 369 amdcfgetdisklabel(dev_t dev, struct amdcf_softc *sc, struct disklabel *lp, 370 int spoofonly) 371 { 372 memset(lp, 0, sizeof(struct disklabel)); 373 374 lp->d_secsize = DEV_BSIZE; 375 lp->d_nsectors = 1; /* bogus */ 376 lp->d_ntracks = 1; /* bogus */ 377 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 378 lp->d_ncylinders = sc->sc_size / lp->d_secpercyl; 379 380 strlcpy(lp->d_typename, "amdcf device", sizeof(lp->d_typename)); 381 lp->d_type = DTYPE_SCSI; /* bogus type, can be anything */ 382 strlcpy(lp->d_packname, "CFI Disk", sizeof(lp->d_packname)); 383 DL_SETDSIZE(lp, sc->sc_size / DEV_BSIZE); 384 lp->d_version = 1; 385 386 lp->d_magic = DISKMAGIC; 387 lp->d_magic2 = DISKMAGIC; 388 lp->d_checksum = dkcksum(lp); 389 390 /* Call the generic disklabel extraction routine */ 391 return readdisklabel(DISKLABELDEV(dev), amdcfstrategy, lp, spoofonly); 392 } 393 394 int 395 amdcfclose(dev_t dev, int flag, int fmt, struct proc *p) 396 { 397 struct amdcf_softc *sc; 398 int part = DISKPART(dev); 399 400 sc = amdcflookup(DISKUNIT(dev)); 401 if (sc == NULL) 402 return ENXIO; 403 404 disk_lock_nointr(&sc->sc_dk); 405 406 disk_closepart(&sc->sc_dk, part, fmt); 407 408 disk_unlock(&sc->sc_dk); 409 410 device_unref(&sc->sc_dev); 411 return 0; 412 } 413 414 int 415 amdcfread(dev_t dev, struct uio *uio, int flags) 416 { 417 return (physio(amdcfstrategy, dev, B_READ, minphys, uio)); 418 } 419 420 int 421 amdcfwrite(dev_t dev, struct uio *uio, int flags) 422 { 423 #ifdef AMDCF_DISK_WRITE_ENABLE 424 return (physio(amdcfstrategy, dev, B_WRITE, minphys, uio)); 425 #else 426 return 0; 427 #endif 428 } 429 430 void 431 amdcfstrategy(struct buf *bp) 432 { 433 struct amdcf_softc *sc; 434 int s; 435 436 sc = amdcflookup(DISKUNIT(bp->b_dev)); 437 if (sc == NULL) { 438 bp->b_error = ENXIO; 439 goto bad; 440 } 441 /* If device invalidated (e.g. media change, door open), error. */ 442 if ((sc->sc_flags & AMDCF_LOADED) == 0) { 443 bp->b_error = EIO; 444 goto bad; 445 } 446 447 /* Validate the request. */ 448 if (bounds_check_with_label(bp, sc->sc_dk.dk_label) == -1) 449 goto done; 450 451 /* Check that the number of sectors can fit in a byte. */ 452 if ((bp->b_bcount / sc->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) { 453 bp->b_error = EINVAL; 454 goto bad; 455 } 456 457 /* Queue transfer on drive, activate drive and controller if idle. */ 458 bufq_queue(&sc->sc_bufq, bp); 459 s = splbio(); 460 amdcfstart(sc); 461 splx(s); 462 device_unref(&sc->sc_dev); 463 return; 464 465 bad: 466 bp->b_flags |= B_ERROR; 467 bp->b_resid = bp->b_bcount; 468 done: 469 s = splbio(); 470 biodone(bp); 471 splx(s); 472 if (sc != NULL) 473 device_unref(&sc->sc_dev); 474 } 475 476 int 477 amdcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p) 478 { 479 struct amdcf_softc *sc; 480 struct disklabel *lp; 481 int error = 0; 482 483 sc = amdcflookup(DISKUNIT(dev)); 484 if (sc == NULL) 485 return ENXIO; 486 487 if ((sc->sc_flags & AMDCF_LOADED) == 0) { 488 error = EIO; 489 goto exit; 490 } 491 492 switch (xfer) { 493 case DIOCRLDINFO: 494 lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); 495 amdcfgetdisklabel(dev, sc, lp, 0); 496 bcopy(lp, sc->sc_dk.dk_label, sizeof(*lp)); 497 free(lp, M_TEMP, sizeof(*lp)); 498 goto exit; 499 500 case DIOCGPDINFO: 501 amdcfgetdisklabel(dev, sc, (struct disklabel *)addr, 1); 502 goto exit; 503 504 case DIOCGDINFO: 505 *(struct disklabel *)addr = *(sc->sc_dk.dk_label); 506 goto exit; 507 508 case DIOCGPART: 509 ((struct partinfo *)addr)->disklab = sc->sc_dk.dk_label; 510 ((struct partinfo *)addr)->part = 511 &sc->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 512 goto exit; 513 514 case DIOCWDINFO: 515 case DIOCSDINFO: 516 if ((flag & FWRITE) == 0) { 517 error = EBADF; 518 goto exit; 519 } 520 521 if ((error = disk_lock(&sc->sc_dk)) != 0) 522 goto exit; 523 524 error = setdisklabel(sc->sc_dk.dk_label, 525 (struct disklabel *)addr, sc->sc_dk.dk_openmask); 526 if (error == 0) { 527 if (xfer == DIOCWDINFO) 528 error = writedisklabel(DISKLABELDEV(dev), 529 amdcfstrategy, sc->sc_dk.dk_label); 530 } 531 532 disk_unlock(&sc->sc_dk); 533 goto exit; 534 535 default: 536 error = ENOTTY; 537 goto exit; 538 } 539 540 #ifdef DIAGNOSTIC 541 panic("amdcfioctl: impossible"); 542 #endif 543 544 exit: 545 device_unref(&sc->sc_dev); 546 return error; 547 } 548 549 /* 550 * Dump core after a system crash. 551 */ 552 int 553 amdcfdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 554 { 555 return ENXIO; 556 } 557 558 daddr_t 559 amdcfsize(dev_t dev) 560 { 561 struct amdcf_softc *sc; 562 struct disklabel *lp; 563 int part, omask; 564 daddr_t size; 565 566 sc = amdcflookup(DISKUNIT(dev)); 567 if (sc == NULL) 568 return (-1); 569 570 part = DISKPART(dev); 571 omask = sc->sc_dk.dk_openmask & (1 << part); 572 573 if (omask == 0 && amdcfopen(dev, 0, S_IFBLK, NULL) != 0) { 574 size = -1; 575 goto exit; 576 } 577 578 lp = sc->sc_dk.dk_label; 579 size = DL_SECTOBLK(lp, DL_GETPSIZE(&lp->d_partitions[part])); 580 if (omask == 0 && amdcfclose(dev, 0, S_IFBLK, NULL) != 0) 581 size = -1; 582 583 exit: 584 device_unref(&sc->sc_dev); 585 return size; 586 } 587 588 589 /* 590 * Queue a drive for I/O. 591 */ 592 void 593 amdcfstart(void *arg) 594 { 595 struct amdcf_softc *sc = arg; 596 struct buf *bp; 597 598 while ((bp = bufq_dequeue(&sc->sc_bufq)) != NULL) { 599 /* Transfer this buffer now. */ 600 _amdcfstart(sc, bp); 601 } 602 } 603 604 void 605 _amdcfstart(struct amdcf_softc *sc, struct buf *bp) 606 { 607 off_t off; 608 struct partition *p; 609 610 sc->sc_bp = bp; 611 612 /* Fetch buffer's read/write offset */ 613 p = &sc->sc_dk.dk_label->d_partitions[DISKPART(bp->b_dev)]; 614 off = DL_GETPOFFSET(p) * sc->sc_dk.dk_label->d_secsize + 615 (u_int64_t)bp->b_blkno * DEV_BSIZE; 616 if (off > sc->sc_size) { 617 bp->b_flags |= B_ERROR; 618 bp->b_error = EIO; 619 return; 620 } 621 622 /* Instrumentation. */ 623 disk_busy(&sc->sc_dk); 624 625 if (bp->b_flags & B_READ) 626 amdcf_disk_read(sc, bp, off); 627 #ifdef AMDCF_DISK_WRITE_ENABLE 628 else 629 amdcf_disk_write(sc, bp, off); 630 #endif 631 632 amdcfdone(sc); 633 } 634 635 void 636 amdcfdone(void *arg) 637 { 638 struct amdcf_softc *sc = arg; 639 struct buf *bp = sc->sc_bp; 640 641 if (bp->b_error == 0) 642 bp->b_resid = 0; 643 else 644 bp->b_flags |= B_ERROR; 645 646 disk_unbusy(&sc->sc_dk, (bp->b_bcount - bp->b_resid), 647 bp->b_blkno, (bp->b_flags & B_READ)); 648 biodone(bp); 649 } 650 651 void 652 amdcf_disk_read(struct amdcf_softc *sc, struct buf *bp, off_t off) 653 { 654 long resid; 655 656 if (sc->sc_writing) { 657 bp->b_error = cfi_block_finish(sc); 658 if (bp->b_error) { 659 bp->b_flags |= B_ERROR; 660 return; 661 } 662 } 663 664 resid = bp->b_bcount; 665 uint8_t *dp = (uint8_t *)bp->b_data; 666 while (resid > 0 && off < sc->sc_size) { 667 *dp++ = cfi_read(sc, off, 0); 668 off += 1, resid -= 1; 669 } 670 bp->b_resid = resid; 671 } 672 673 void 674 amdcf_disk_write(struct amdcf_softc *sc, struct buf *bp, off_t off) 675 { 676 long resid; 677 u_int top; 678 679 resid = bp->b_bcount; 680 while (resid > 0) { 681 /* 682 * Finish the current block if we're about to write 683 * to a different block. 684 */ 685 if (sc->sc_writing) { 686 top = sc->sc_wrofs + sc->sc_wrbufsz; 687 if (off < sc->sc_wrofs || off >= top) 688 cfi_block_finish(sc); 689 } 690 691 /* Start writing to a (new) block if applicable. */ 692 if (!sc->sc_writing) { 693 bp->b_error = cfi_block_start(sc, off); 694 if (bp->b_error) { 695 bp->b_flags |= B_ERROR; 696 return; 697 } 698 } 699 700 top = sc->sc_wrofs + sc->sc_wrbufsz; 701 bcopy(bp->b_data, 702 sc->sc_wrbuf + off - sc->sc_wrofs, 703 MIN(top - off, resid)); 704 resid -= MIN(top - off, resid); 705 } 706 bp->b_resid = resid; 707 } 708 709 /* 710 * Begin writing into a new block/sector. We read the sector into 711 * memory and keep updating that, until we move into another sector 712 * or the process stops writing. At that time we write the whole 713 * sector to flash (see cfi_block_finish). 714 */ 715 int 716 cfi_block_start(struct amdcf_softc *sc, u_int ofs) 717 { 718 u_int rofs, rsz; 719 int r; 720 uint8_t *ptr; 721 722 rofs = 0; 723 for (r = 0; r < sc->sc_regions; r++) { 724 rsz = sc->sc_region[r].r_blocks * sc->sc_region[r].r_blksz; 725 if (ofs < rofs + rsz) 726 break; 727 rofs += rsz; 728 } 729 if (r == sc->sc_regions) 730 return (EFAULT); 731 732 sc->sc_wrbufsz = sc->sc_region[r].r_blksz; 733 sc->sc_wrbuf = malloc(sc->sc_wrbufsz, M_TEMP, M_WAITOK); 734 sc->sc_wrofs = ofs - (ofs - rofs) % sc->sc_wrbufsz; 735 736 ptr = sc->sc_wrbuf; 737 /* Read the block from flash for byte-serving. */ 738 for (r = 0; r < sc->sc_wrbufsz; r++) 739 *(ptr)++ = cfi_read(sc, sc->sc_wrofs + r, 0); 740 741 sc->sc_writing = 1; 742 return (0); 743 } 744 745 /* 746 * Finish updating the current block/sector by writing the compound 747 * set of changes to the flash. 748 */ 749 int 750 cfi_block_finish(struct amdcf_softc *sc) 751 { 752 int error; 753 754 error = cfi_write_block(sc); 755 free(sc->sc_wrbuf, M_TEMP, sc->sc_wrbufsz); 756 sc->sc_wrbuf = NULL; 757 sc->sc_wrbufsz = 0; 758 sc->sc_wrofs = 0; 759 sc->sc_writing = 0; 760 return (error); 761 } 762 763 int 764 cfi_write_block(struct amdcf_softc *sc) 765 { 766 uint8_t *ptr; 767 int error, i, s; 768 769 if (sc->sc_wrofs > sc->sc_size) 770 panic("CFI: write offset (%x) bigger " 771 "than cfi array size (%zu)\n", 772 sc->sc_wrofs, sc->sc_size); 773 774 if ((sc->sc_wrofs < BOOTLOADER_ADDR) || 775 ((sc->sc_wrofs + sc->sc_wrbufsz) < BOOTLOADER_ADDR)) 776 return EOPNOTSUPP; 777 778 error = cfi_erase_block(sc, sc->sc_wrofs); 779 if (error) 780 goto out; 781 782 /* Write the block. */ 783 ptr = sc->sc_wrbuf; 784 785 for (i = 0; i < sc->sc_wrbufsz; i += sc->sc_width) { 786 787 /* 788 * Make sure the command to start a write and the 789 * actual write happens back-to-back without any 790 * excessive delays. 791 */ 792 s = splbio(); 793 794 cfi_amd_write(sc, sc->sc_wrofs, AMD_ADDR_START, 795 CFI_AMD_PROGRAM); 796 /* Raw data do not use cfi_array_write */ 797 cfi_write(sc, sc->sc_wrofs + i, 0, *(ptr)++); 798 799 splx(s); 800 801 error = cfi_wait_ready(sc, sc->sc_wrofs + i, 802 sc->sc_write_timeout, sc->sc_write_max_timeout); 803 if (error) 804 goto out; 805 } 806 807 out: 808 cfi_array_write(sc, sc->sc_wrofs, 0, sc->sc_rstcmd); 809 return error; 810 } 811 812 int 813 cfi_erase_block(struct amdcf_softc *sc, u_int offset) 814 { 815 int error = 0; 816 817 if (offset > sc->sc_size) 818 panic("CFI: erase offset (%x) bigger " 819 "than cfi array size (%zu)\n", 820 sc->sc_wrofs, sc->sc_size); 821 822 /* Erase the block. */ 823 cfi_amd_write(sc, offset, 0, CFI_AMD_BLOCK_ERASE); 824 825 error = cfi_wait_ready(sc, offset, sc->sc_erase_timeout, 826 sc->sc_erase_max_timeout); 827 828 return error; 829 } 830 831 832 833 int 834 cfi_wait_ready(struct amdcf_softc *sc, u_int ofs, u_int timeout, u_int count) 835 { 836 int done, error; 837 u_int st0 = 0, st = 0; 838 839 done = 0; 840 error = 0; 841 842 if (!timeout) 843 timeout = 100; /* Default to 100 uS */ 844 if (!count) 845 count = 100; /* Max timeout is 10 mS */ 846 847 while (!done && !error && count) { 848 DELAY(timeout); 849 850 count--; 851 852 /* 853 * read sc->sc_width bytes, and check for toggle bit. 854 */ 855 st0 = cfi_read(sc, ofs, 0); 856 st = cfi_read(sc, ofs, 0); 857 done = ((st & cfi_make_cmd(0x40, sc->sc_mask)) == 858 (st0 & cfi_make_cmd(0x40, sc->sc_mask))) ? 1 : 0; 859 860 break; 861 } 862 if (!done && !error) 863 error = ETIMEDOUT; 864 if (error) 865 printf("\nerror=%d (st 0x%x st0 0x%x) at offset=%x\n", 866 error, st, st0, ofs); 867 return error; 868 } 869 870 /* 871 * cfi_array_write 872 * fill "bus width" word with value of var data by array mask sc->sc_mask 873 */ 874 void 875 cfi_array_write(struct amdcf_softc *sc, u_int ofs, u_int addr, u_int data) 876 { 877 data &= 0xff; 878 cfi_write(sc, ofs, addr, cfi_make_cmd(data, sc->sc_mask)); 879 } 880 881 void 882 cfi_amd_write(struct amdcf_softc *sc, u_int ofs, u_int addr, u_int data) 883 { 884 cfi_array_write(sc, ofs, AMD_ADDR_START, CFI_AMD_UNLOCK); 885 cfi_array_write(sc, ofs, AMD_ADDR_ACK, CFI_AMD_UNLOCK_ACK); 886 cfi_array_write(sc, ofs, addr, data); 887 } 888 889 890 891 /* 892 * The following routines assume width=1 and shift=2 as that is 893 * the case on the Octeon DSR machines. 894 * If this assumption fails a new detection routine should be written 895 * and called during attach. 896 */ 897 uint8_t 898 cfi_read(struct amdcf_softc *sc, bus_size_t base, bus_size_t offset) 899 { 900 return bus_space_read_1(sc->sc_iot, sc->sc_ioh, 901 base | (offset * sc->sc_shift)); 902 } 903 904 void 905 cfi_write(struct amdcf_softc *sc, bus_size_t base, bus_size_t offset, 906 uint8_t val) 907 { 908 bus_space_write_1(sc->sc_iot, sc->sc_ioh, 909 base | (offset * sc->sc_shift), val); 910 } 911 912 int 913 cfi_make_cmd(uint8_t cmd, u_int mask) 914 { 915 int i; 916 u_int data = 0; 917 918 for (i = 0; i < sizeof(int); i ++) { 919 if (mask & (0xff << (i*8))) 920 data |= cmd << (i*8); 921 } 922 923 return data; 924 } 925