1/* $OpenBSD: octcf.c,v 1.36 2024/05/20 23:13:33 jsg Exp $ */ 2/* $NetBSD: wd.c,v 1.193 1999/02/28 17:15:27 explorer Exp $ */ 3 4/* 5 * Copyright (c) 1998, 2001 Manuel Bouyer. 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/*- 29 * Copyright (c) 1998 The NetBSD Foundation, Inc. 30 * All rights reserved. 31 * 32 * This code is derived from software contributed to The NetBSD Foundation 33 * by Charles M. Hannum and by Onno van der Linden. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 45 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 46 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 47 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 48 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 49 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 50 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 51 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 52 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 53 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 54 * POSSIBILITY OF SUCH DAMAGE. 55 */ 56 57#include <sys/param.h> 58#include <sys/systm.h> 59#include <sys/kernel.h> 60#include <sys/conf.h> 61#include <sys/fcntl.h> 62#include <sys/stat.h> 63#include <sys/ioctl.h> 64#include <sys/mutex.h> 65#include <sys/buf.h> 66#include <sys/uio.h> 67#include <sys/malloc.h> 68#include <sys/device.h> 69#include <sys/disklabel.h> 70#include <sys/disk.h> 71#include <sys/syslog.h> 72#include <sys/proc.h> 73#include <sys/vnode.h> 74#include <sys/dkio.h> 75 76#include <machine/intr.h> 77#include <machine/bus.h> 78 79#include <dev/ata/atareg.h> 80#include <dev/ata/atavar.h> 81#include <dev/ic/wdcreg.h> 82#include <dev/ic/wdcvar.h> 83 84#include <octeon/dev/iobusvar.h> 85#include <machine/octeonreg.h> 86#include <machine/octeonvar.h> 87 88#define OCTCF_REG_SIZE 8 89#define ATAPARAMS_SIZE 512 90#define SECTOR_SIZE 512 91#define OCTCFDELAY 100 /* 100 microseconds */ 92#define NR_TRIES 1000 93 94#define DEBUG_XFERS 0x02 95#define DEBUG_FUNCS 0x08 96#define DEBUG_PROBE 0x10 97 98#ifdef OCTCFDEBUG 99int octcfdebug_mask = 0xff; 100#define OCTCFDEBUG_PRINT(args, level) do { \ 101 if ((octcfdebug_mask & (level)) != 0) \ 102 printf args; \ 103} while (0) 104#else 105#define OCTCFDEBUG_PRINT(args, level) 106#endif 107 108struct octcf_softc { 109 /* General disk infos */ 110 struct device sc_dev; 111 struct disk sc_dk; 112 struct bufq sc_bufq; 113 struct buf *sc_bp; 114 struct ataparams sc_params;/* drive characteristics found */ 115 int sc_flags; 116#define OCTCFF_LOADED 0x10 /* parameters loaded */ 117 u_int64_t sc_capacity; 118 bus_space_tag_t sc_iot; 119 bus_space_handle_t sc_ioh; 120}; 121 122int octcfprobe(struct device *, void *, void *); 123void octcfattach(struct device *, struct device *, void *); 124int octcfdetach(struct device *, int); 125int octcfactivate(struct device *, int); 126 127const struct cfattach octcf_ca = { 128 sizeof(struct octcf_softc), octcfprobe, octcfattach, 129 octcfdetach, octcfactivate 130}; 131 132struct cfdriver octcf_cd = { 133 NULL, "octcf", DV_DISK 134}; 135 136void octcfgetdefaultlabel(struct octcf_softc *, struct disklabel *); 137int octcfgetdisklabel(dev_t dev, struct octcf_softc *, struct disklabel *, int); 138void octcfstrategy(struct buf *); 139void octcfstart(void *); 140void _octcfstart(struct octcf_softc*, struct buf *); 141void octcfdone(void *); 142 143cdev_decl(octcf); 144bdev_decl(octcf); 145 146#define octcflookup(unit) (struct octcf_softc *)disk_lookup(&octcf_cd, (unit)) 147 148int octcf_write_sectors(struct octcf_softc *, uint32_t, uint32_t, void *); 149int octcf_read_sectors(struct octcf_softc *, uint32_t, uint32_t, void *); 150int octcf_wait_busy(struct octcf_softc *); 151void octcf_command(struct octcf_softc *, uint32_t, uint8_t); 152int octcf_get_params(struct octcf_softc *, struct ataparams *); 153 154#define OCTCF_REG_READ(wd, reg) \ 155 bus_space_read_2(wd->sc_iot, wd->sc_ioh, reg & 0x6) 156#define OCTCF_REG_WRITE(wd, reg, val) \ 157 bus_space_write_2(wd->sc_iot, wd->sc_ioh, reg & 0x6, val) 158 159int 160octcfprobe(struct device *parent, void *match, void *aux) 161{ 162 if (octeon_boot_info->cf_common_addr == 0) { 163 OCTCFDEBUG_PRINT(("%s: No cf bus found\n", __func__), DEBUG_FUNCS | DEBUG_PROBE); 164 return 0; 165 } 166 167 return 1; 168} 169 170void 171octcfattach(struct device *parent, struct device *self, void *aux) 172{ 173 struct octcf_softc *wd = (void *)self; 174 struct iobus_attach_args *aa = aux; 175 int i, blank; 176 char buf[41], c, *p, *q; 177 uint8_t status; 178 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS | DEBUG_PROBE); 179 180 wd->sc_iot = aa->aa_bust; 181 182 if (bus_space_map(wd->sc_iot, aa->aa_addr, 183 OCTCF_REG_SIZE, BUS_SPACE_MAP_KSEG0, &wd->sc_ioh)) { 184 printf(": couldn't map registers\n"); 185 return; 186 } 187 188 for (i = 0; i < 8; i++) { 189 uint64_t cfg = 190 *(uint64_t *)PHYS_TO_XKPHYS( 191 OCTEON_MIO_BOOT_BASE + MIO_BOOT_REG_CFG(i), CCA_NC); 192 193 if ((cfg & BOOT_CFG_BASE_MASK) == 194 (OCTEON_CF_BASE >> BOOT_CFG_BASE_SHIFT)) { 195 if ((cfg & BOOT_CFG_WIDTH_MASK) == 0) 196 printf(": doesn't support 8bit cards\n"); 197 break; 198 } 199 } 200 201 /* Check if CF is inserted */ 202 i = 0; 203 while ( (status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) { 204 if ((i++) == NR_TRIES ) { 205 printf(": card not present\n"); 206 return; 207 } 208 DELAY(OCTCFDELAY); 209 } 210 211 /* read our drive info */ 212 if (octcf_get_params(wd, &wd->sc_params) != 0) { 213 printf(": IDENTIFY failed\n"); 214 return; 215 } 216 217 for (blank = 0, p = wd->sc_params.atap_model, q = buf, i = 0; 218 i < sizeof(wd->sc_params.atap_model); i++) { 219 c = *p++; 220 if (c == '\0') 221 break; 222 if (c != ' ') { 223 if (blank) { 224 *q++ = ' '; 225 blank = 0; 226 } 227 *q++ = c; 228 } else 229 blank = 1; 230 } 231 *q++ = '\0'; 232 233 printf(": <%s>\n", buf); 234 printf("%s: %d-sector PIO,", 235 wd->sc_dev.dv_xname, wd->sc_params.atap_multi & 0xff); 236 237 wd->sc_capacity = 238 wd->sc_params.atap_cylinders * 239 wd->sc_params.atap_heads * 240 wd->sc_params.atap_sectors; 241 printf(" CHS, %lluMB, %d cyl, %d head, %d sec, %llu sectors\n", 242 wd->sc_capacity / (1048576 / DEV_BSIZE), 243 wd->sc_params.atap_cylinders, 244 wd->sc_params.atap_heads, 245 wd->sc_params.atap_sectors, 246 wd->sc_capacity); 247 248 OCTCFDEBUG_PRINT( 249 ("%s: atap_dmatiming_mimi=%d, atap_dmatiming_recom=%d\n", 250 self->dv_xname, wd->sc_params.atap_dmatiming_mimi, 251 wd->sc_params.atap_dmatiming_recom), DEBUG_PROBE); 252 253 /* 254 * Initialize disk structures. 255 */ 256 wd->sc_dk.dk_name = wd->sc_dev.dv_xname; 257 bufq_init(&wd->sc_bufq, BUFQ_DEFAULT); 258 259 /* Attach disk. */ 260 disk_attach(&wd->sc_dev, &wd->sc_dk); 261} 262 263int 264octcfactivate(struct device *self, int act) 265{ 266 return 0; 267} 268 269int 270octcfdetach(struct device *self, int flags) 271{ 272 struct octcf_softc *sc = (struct octcf_softc *)self; 273 274 bufq_drain(&sc->sc_bufq); 275 276 disk_gone(octcfopen, self->dv_unit); 277 278 /* Detach disk. */ 279 bufq_destroy(&sc->sc_bufq); 280 disk_detach(&sc->sc_dk); 281 282 return (0); 283} 284 285/* 286 * Read/write routine for a buffer. Validates the arguments and schedules the 287 * transfer. Does not wait for the transfer to complete. 288 */ 289void 290octcfstrategy(struct buf *bp) 291{ 292 struct octcf_softc *wd; 293 int s; 294 295 wd = octcflookup(DISKUNIT(bp->b_dev)); 296 if (wd == NULL) { 297 bp->b_error = ENXIO; 298 goto bad; 299 } 300 301 OCTCFDEBUG_PRINT(("%s (%s)\n", __func__, wd->sc_dev.dv_xname), 302 DEBUG_XFERS); 303 304 /* If device invalidated (e.g. media change, door open), error. */ 305 if ((wd->sc_flags & OCTCFF_LOADED) == 0) { 306 bp->b_error = EIO; 307 goto bad; 308 } 309 310 /* Validate the request. */ 311 if (bounds_check_with_label(bp, wd->sc_dk.dk_label) == -1) 312 goto done; 313 314 /* Check that the number of sectors can fit in a byte. */ 315 if ((bp->b_bcount / wd->sc_dk.dk_label->d_secsize) >= (1 << NBBY)) { 316 bp->b_error = EINVAL; 317 goto bad; 318 } 319 320 /* Queue transfer on drive, activate drive and controller if idle. */ 321 bufq_queue(&wd->sc_bufq, bp); 322 s = splbio(); 323 octcfstart(wd); 324 splx(s); 325 device_unref(&wd->sc_dev); 326 return; 327 328 bad: 329 bp->b_flags |= B_ERROR; 330 bp->b_resid = bp->b_bcount; 331 done: 332 s = splbio(); 333 biodone(bp); 334 splx(s); 335 if (wd != NULL) 336 device_unref(&wd->sc_dev); 337} 338 339/* 340 * Queue a drive for I/O. 341 */ 342void 343octcfstart(void *arg) 344{ 345 struct octcf_softc *wd = arg; 346 struct buf *bp; 347 348 OCTCFDEBUG_PRINT(("%s %s\n", __func__, wd->sc_dev.dv_xname), 349 DEBUG_XFERS); 350 while ((bp = bufq_dequeue(&wd->sc_bufq)) != NULL) { 351 /* Transfer this buffer now. */ 352 _octcfstart(wd, bp); 353 } 354} 355 356void 357_octcfstart(struct octcf_softc *wd, struct buf *bp) 358{ 359 struct disklabel *lp; 360 u_int64_t secno; 361 u_int64_t nsecs; 362 363 lp = wd->sc_dk.dk_label; 364 secno = DL_BLKTOSEC(lp, bp->b_blkno) + 365 DL_GETPOFFSET(&lp->d_partitions[DISKPART(bp->b_dev)]); 366 nsecs = howmany(bp->b_bcount, lp->d_secsize); 367 wd->sc_bp = bp; 368 369 /* Instrumentation. */ 370 disk_busy(&wd->sc_dk); 371 372 if (bp->b_flags & B_READ) 373 bp->b_error = octcf_read_sectors(wd, nsecs, secno, bp->b_data); 374 else 375 bp->b_error = octcf_write_sectors(wd, nsecs, secno, bp->b_data); 376 377 octcfdone(wd); 378} 379 380void 381octcfdone(void *arg) 382{ 383 struct octcf_softc *wd = arg; 384 struct buf *bp = wd->sc_bp; 385 386 if (bp->b_error == 0) 387 bp->b_resid = 0; 388 else 389 bp->b_flags |= B_ERROR; 390 391 disk_unbusy(&wd->sc_dk, (bp->b_bcount - bp->b_resid), 392 bp->b_blkno, (bp->b_flags & B_READ)); 393 biodone(bp); 394} 395 396int 397octcfread(dev_t dev, struct uio *uio, int flags) 398{ 399 400 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS); 401 return (physio(octcfstrategy, dev, B_READ, minphys, uio)); 402} 403 404int 405octcfwrite(dev_t dev, struct uio *uio, int flags) 406{ 407 408 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_XFERS); 409 return (physio(octcfstrategy, dev, B_WRITE, minphys, uio)); 410} 411 412int 413octcfopen(dev_t dev, int flag, int fmt, struct proc *p) 414{ 415 struct octcf_softc *wd; 416 int unit, part; 417 int error; 418 419 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 420 421 unit = DISKUNIT(dev); 422 wd = octcflookup(unit); 423 if (wd == NULL) 424 return ENXIO; 425 426 /* 427 * If this is the first open of this device, add a reference 428 * to the adapter. 429 */ 430 if ((error = disk_lock(&wd->sc_dk)) != 0) 431 goto bad4; 432 433 if (wd->sc_dk.dk_openmask != 0) { 434 /* 435 * If any partition is open, but the disk has been invalidated, 436 * disallow further opens. 437 */ 438 if ((wd->sc_flags & OCTCFF_LOADED) == 0) { 439 error = EIO; 440 goto bad3; 441 } 442 } else { 443 if ((wd->sc_flags & OCTCFF_LOADED) == 0) { 444 wd->sc_flags |= OCTCFF_LOADED; 445 446 /* Load the physical device parameters. */ 447 octcf_get_params(wd, &wd->sc_params); 448 449 /* Load the partition info if not already loaded. */ 450 if (octcfgetdisklabel(dev, wd, 451 wd->sc_dk.dk_label, 0) == EIO) { 452 error = EIO; 453 goto bad; 454 } 455 } 456 } 457 458 part = DISKPART(dev); 459 460 if ((error = disk_openpart(&wd->sc_dk, part, fmt, 1)) != 0) 461 goto bad; 462 463 disk_unlock(&wd->sc_dk); 464 device_unref(&wd->sc_dev); 465 return 0; 466 467bad: 468 if (wd->sc_dk.dk_openmask == 0) { 469 } 470 471bad3: 472 disk_unlock(&wd->sc_dk); 473bad4: 474 device_unref(&wd->sc_dev); 475 return error; 476} 477 478int 479octcfclose(dev_t dev, int flag, int fmt, struct proc *p) 480{ 481 struct octcf_softc *wd; 482 int part = DISKPART(dev); 483 484 wd = octcflookup(DISKUNIT(dev)); 485 if (wd == NULL) 486 return ENXIO; 487 488 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 489 490 disk_lock_nointr(&wd->sc_dk); 491 492 disk_closepart(&wd->sc_dk, part, fmt); 493 494 disk_unlock(&wd->sc_dk); 495 496 device_unref(&wd->sc_dev); 497 return (0); 498} 499 500void 501octcfgetdefaultlabel(struct octcf_softc *wd, struct disklabel *lp) 502{ 503 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 504 bzero(lp, sizeof(struct disklabel)); 505 506 lp->d_secsize = DEV_BSIZE; 507 DL_SETDSIZE(lp, wd->sc_capacity); 508 lp->d_ntracks = wd->sc_params.atap_heads; 509 lp->d_nsectors = wd->sc_params.atap_sectors; 510 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 511 lp->d_ncylinders = DL_GETDSIZE(lp) / lp->d_secpercyl; 512 lp->d_type = DTYPE_ESDI; 513 strncpy(lp->d_typename, "ESDI/IDE disk", sizeof lp->d_typename); 514 515 /* XXX - user viscopy() like sd.c */ 516 strncpy(lp->d_packname, wd->sc_params.atap_model, sizeof lp->d_packname); 517 lp->d_version = 1; 518 519 lp->d_magic = DISKMAGIC; 520 lp->d_magic2 = DISKMAGIC; 521 lp->d_checksum = dkcksum(lp); 522} 523 524/* 525 * Fabricate a default disk label, and try to read the correct one. 526 */ 527int 528octcfgetdisklabel(dev_t dev, struct octcf_softc *wd, struct disklabel *lp, 529 int spoofonly) 530{ 531 int error; 532 533 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 534 535 octcfgetdefaultlabel(wd, lp); 536 error = readdisklabel(DISKLABELDEV(dev), octcfstrategy, lp, 537 spoofonly); 538 return (error); 539} 540 541int 542octcfioctl(dev_t dev, u_long xfer, caddr_t addr, int flag, struct proc *p) 543{ 544 struct octcf_softc *wd; 545 struct disklabel *lp; 546 int error = 0; 547 548 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 549 550 wd = octcflookup(DISKUNIT(dev)); 551 if (wd == NULL) 552 return ENXIO; 553 554 if ((wd->sc_flags & OCTCFF_LOADED) == 0) { 555 error = EIO; 556 goto exit; 557 } 558 559 switch (xfer) { 560 case DIOCRLDINFO: 561 lp = malloc(sizeof(*lp), M_TEMP, M_WAITOK); 562 octcfgetdisklabel(dev, wd, lp, 0); 563 bcopy(lp, wd->sc_dk.dk_label, sizeof(*lp)); 564 free(lp, M_TEMP, sizeof(*lp)); 565 goto exit; 566 567 case DIOCGPDINFO: 568 octcfgetdisklabel(dev, wd, (struct disklabel *)addr, 1); 569 goto exit; 570 571 case DIOCGDINFO: 572 *(struct disklabel *)addr = *(wd->sc_dk.dk_label); 573 goto exit; 574 575 case DIOCGPART: 576 ((struct partinfo *)addr)->disklab = wd->sc_dk.dk_label; 577 ((struct partinfo *)addr)->part = 578 &wd->sc_dk.dk_label->d_partitions[DISKPART(dev)]; 579 goto exit; 580 581 case DIOCWDINFO: 582 case DIOCSDINFO: 583 if ((flag & FWRITE) == 0) { 584 error = EBADF; 585 goto exit; 586 } 587 588 if ((error = disk_lock(&wd->sc_dk)) != 0) 589 goto exit; 590 591 error = setdisklabel(wd->sc_dk.dk_label, 592 (struct disklabel *)addr, wd->sc_dk.dk_openmask); 593 if (error == 0) { 594 if (xfer == DIOCWDINFO) 595 error = writedisklabel(DISKLABELDEV(dev), 596 octcfstrategy, wd->sc_dk.dk_label); 597 } 598 599 disk_unlock(&wd->sc_dk); 600 goto exit; 601 602 default: 603 error = ENOTTY; 604 goto exit; 605 } 606 607#ifdef DIAGNOSTIC 608 panic("octcfioctl: impossible"); 609#endif 610 611 exit: 612 device_unref(&wd->sc_dev); 613 return (error); 614} 615 616#ifdef B_FORMAT 617int 618wdformat(struct buf *bp) 619{ 620 bp->b_flags |= B_FORMAT; 621 return octcfstrategy(bp); 622} 623#endif 624 625daddr_t 626octcfsize(dev_t dev) 627{ 628 struct octcf_softc *wd; 629 struct disklabel *lp; 630 int part, omask; 631 daddr_t size; 632 633 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 634 635 wd = octcflookup(DISKUNIT(dev)); 636 if (wd == NULL) 637 return (-1); 638 639 part = DISKPART(dev); 640 omask = wd->sc_dk.dk_openmask & (1 << part); 641 642 if (omask == 0 && octcfopen(dev, 0, S_IFBLK, NULL) != 0) { 643 size = -1; 644 goto exit; 645 } 646 647 lp = wd->sc_dk.dk_label; 648 size = DL_SECTOBLK(lp, DL_GETPSIZE(&lp->d_partitions[part])); 649 if (omask == 0 && octcfclose(dev, 0, S_IFBLK, NULL) != 0) 650 size = -1; 651 652 exit: 653 device_unref(&wd->sc_dev); 654 return (size); 655} 656 657/* 658 * Dump core after a system crash. 659 */ 660int 661octcfdump(dev_t dev, daddr_t blkno, caddr_t va, size_t size) 662{ 663 return ENXIO; 664} 665 666int 667octcf_read_sectors(struct octcf_softc *wd, uint32_t nr_sectors, 668 uint32_t start_sector, void *buf) 669{ 670 uint32_t count; 671 uint16_t *ptr = (uint16_t*)buf; 672 int error; 673 uint8_t status; 674 675 while (nr_sectors--) { 676 while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) 677 DELAY(OCTCFDELAY); 678 octcf_command(wd, start_sector++, WDCC_READ); 679 error = octcf_wait_busy(wd); 680 if (error != 0) 681 return (error); 682 683 volatile uint16_t dummy; 684 for (count = 0; count < SECTOR_SIZE; count+=2) { 685 uint16_t temp; 686 temp = OCTCF_REG_READ(wd, 0x0); 687 *ptr++ = swap16(temp); 688 if ((count & 0xf) == 0) 689 dummy = OCTCF_REG_READ(wd, wdr_status); 690 } 691 } 692 return (0); 693} 694 695int 696octcf_write_sectors(struct octcf_softc *wd, uint32_t nr_sectors, 697 uint32_t start_sector, void *buf) 698{ 699 uint32_t count; 700 uint16_t *ptr = (uint16_t*)buf; 701 int error; 702 uint8_t status; 703 704 while (nr_sectors--) { 705 while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) 706 DELAY(OCTCFDELAY); 707 octcf_command(wd, start_sector++, WDCC_WRITE); 708 if((error = octcf_wait_busy(wd))) 709 return (error); 710 711 volatile uint16_t dummy; 712 for (count = 0; count < SECTOR_SIZE; count+=2) { 713 uint16_t temp = *ptr++; 714 OCTCF_REG_WRITE(wd, 0x0, swap16(temp)); 715 if ((count & 0xf) == 0) 716 dummy = OCTCF_REG_READ(wd, wdr_status); 717 } 718 } 719 return (0); 720} 721 722void 723octcf_command(struct octcf_softc *wd, uint32_t lba, uint8_t cmd) 724{ 725 OCTCF_REG_WRITE(wd, wdr_seccnt, 1 | ((lba & 0xff) << 8)); 726 OCTCF_REG_WRITE(wd, wdr_cyl_lo, 727 ((lba >> 8) & 0xff) | (((lba >> 16) & 0xff) << 8)); 728 OCTCF_REG_WRITE(wd, wdr_sdh, 729 (((lba >> 24) & 0xff) | 0xe0) | (cmd << 8)); 730} 731 732int 733octcf_wait_busy(struct octcf_softc *wd) 734{ 735 uint8_t status; 736 737 status = OCTCF_REG_READ(wd, wdr_status)>>8; 738 while ((status & WDCS_BSY) == WDCS_BSY) { 739 if ((status & WDCS_DWF) != 0) 740 return (EIO); 741 DELAY(OCTCFDELAY); 742 status = (uint8_t)(OCTCF_REG_READ(wd, wdr_status)>>8); 743 } 744 745 if ((status & WDCS_DRQ) == 0) 746 return (ENXIO); 747 748 return (0); 749} 750 751/* Get the disk's parameters */ 752int 753octcf_get_params(struct octcf_softc *wd, struct ataparams *params) 754{ 755 char *tb; 756 int i; 757 u_int16_t *p; 758 int count; 759 uint8_t status; 760 int error; 761 762 OCTCFDEBUG_PRINT(("%s\n", __func__), DEBUG_FUNCS); 763 764 tb = malloc(ATAPARAMS_SIZE, M_DEVBUF, M_NOWAIT | M_ZERO); 765 if (tb == NULL) 766 return CMD_AGAIN; 767 768 while ((status = (OCTCF_REG_READ(wd, wdr_status)>>8)) & WDCS_BSY) 769 DELAY(OCTCFDELAY); 770 771 OCTCF_REG_WRITE(wd, wdr_seccnt, 0); 772 OCTCF_REG_WRITE(wd, wdr_cyl_lo, 0); 773 OCTCF_REG_WRITE(wd, wdr_sdh, 0 | (WDCC_IDENTIFY<<8)); 774 775 error = octcf_wait_busy(wd); 776 if (error == 0) { 777 for (count = 0; count < SECTOR_SIZE; count+=2) { 778 uint16_t temp; 779 temp = OCTCF_REG_READ(wd, 0x0); 780 781 /* endianness will be swapped below */ 782 tb[count] = (temp & 0xff); 783 tb[count+1] = (temp & 0xff00)>>8; 784 } 785 } 786 787 if (error != 0) { 788 printf("%s: identify failed: %d\n", __func__, error); 789 free(tb, M_DEVBUF, ATAPARAMS_SIZE); 790 return CMD_ERR; 791 } else { 792 /* 793 * All the fields in the params structure are 16-bit 794 * integers except for the ID strings which are char 795 * strings. The 16-bit integers are currently in 796 * memory in little-endian, regardless of architecture. 797 * So, they need to be swapped on big-endian architectures 798 * before they are accessed through the ataparams structure. 799 * 800 * The swaps below avoid touching the char strings. 801 */ 802 swap16_multi((u_int16_t *)tb, 10); 803 swap16_multi((u_int16_t *)tb + 20, 3); 804 swap16_multi((u_int16_t *)tb + 47, ATAPARAMS_SIZE / 2 - 47); 805 806 /* Read in parameter block. */ 807 bcopy(tb, params, sizeof(struct ataparams)); 808 809 /* 810 * Shuffle string byte order. 811 * ATAPI Mitsumi and NEC drives don't need this. 812 */ 813 if ((params->atap_config & WDC_CFG_ATAPI_MASK) == 814 WDC_CFG_ATAPI && 815 ((params->atap_model[0] == 'N' && 816 params->atap_model[1] == 'E') || 817 (params->atap_model[0] == 'F' && 818 params->atap_model[1] == 'X'))) { 819 free(tb, M_DEVBUF, ATAPARAMS_SIZE); 820 return CMD_OK; 821 } 822 for (i = 0; i < sizeof(params->atap_model); i += 2) { 823 p = (u_short *)(params->atap_model + i); 824 *p = swap16(*p); 825 } 826 for (i = 0; i < sizeof(params->atap_serial); i += 2) { 827 p = (u_short *)(params->atap_serial + i); 828 *p = swap16(*p); 829 } 830 for (i = 0; i < sizeof(params->atap_revision); i += 2) { 831 p = (u_short *)(params->atap_revision + i); 832 *p = swap16(*p); 833 } 834 835 free(tb, M_DEVBUF, ATAPARAMS_SIZE); 836 return CMD_OK; 837 } 838} 839