|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1994 Shantanu Goel ! 3: * All Rights Reserved. ! 4: * ! 5: * Permission to use, copy, modify and distribute this software and its ! 6: * documentation is hereby granted, provided that both the copyright ! 7: * notice and this permission notice appear in all copies of the ! 8: * software, derivative works or modified versions, and any portions ! 9: * thereof, and that both notices appear in supporting documentation. ! 10: * ! 11: * THE AUTHOR ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 12: * CONDITION. THE AUTHOR DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 13: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 14: * ! 15: * MODIFIED BY KEVIN T. VAN MAREN, University of Utah, CSL ! 16: * Copyright (c) 1996, University of Utah, CSL ! 17: * ! 18: * Uses a 'unified' partition code with the SCSI driver. ! 19: * Reading/Writing disklabels through the kernel is NOT recommended. ! 20: * (The preferred method is through the raw device (wd0), with no ! 21: * open partitions). setdisklabel() should work for the in-core ! 22: * fudged disklabel, but will not change the partitioning. The driver ! 23: * *never* sees the disklabel on the disk. ! 24: * ! 25: */ ! 26: ! 27: ! 28: #include <hd.h> ! 29: #if NHD > 0 && !defined(LINUX_DEV) ! 30: /* ! 31: * Hard disk driver. ! 32: * ! 33: * Supports: ! 34: * 1 controller and 2 drives. ! 35: * Arbitrarily sized read/write requests. ! 36: * Misaligned requests. ! 37: * Multiple sector transfer mode (not tested extensively). ! 38: * ! 39: * TODO: ! 40: * 1) Real probe routines for controller and drives. ! 41: * 2) Support for multiple controllers. The driver does ! 42: * not assume a single controller since all functions ! 43: * take the controller and/or device structure as an ! 44: * argument, however the probe routines limit the ! 45: * number of controllers and drives to 1 and 2 respectively. ! 46: * ! 47: * Shantanu Goel ([email protected]) ! 48: */ ! 49: #include <sys/types.h> ! 50: #include <sys/ioctl.h> ! 51: #include "vm_param.h" ! 52: #include <kern/time_out.h> ! 53: #include <vm/vm_kern.h> ! 54: #include <vm/pmap.h> ! 55: #include <device/param.h> ! 56: #include <device/buf.h> ! 57: #include <device/errno.h> ! 58: #include <device/device_types.h> ! 59: #include <device/disk_status.h> ! 60: #include <chips/busses.h> ! 61: #include <i386/machspl.h> ! 62: #include <i386/pio.h> ! 63: #include <i386at/cram.h> ! 64: #include <i386at/disk.h> ! 65: #include <i386at/nhdreg.h> ! 66: ! 67: #include <scsi/rz_labels.h> ! 68: ! 69: ! 70: /* this is for the partition code */ ! 71: typedef struct ide_driver_info { ! 72: dev_t dev; ! 73: /* struct buf *bp; */ ! 74: int sectorsize; ! 75: } ide_driver_info; ! 76: ! 77: #define MAX_IDE_PARTS 32 /* max partitions per drive */ ! 78: static char *drive_name[4]={"wd0: ","wd1: ","xxx ","yyy "}; ! 79: ! 80: /* ! 81: * XXX: This will have to be fixed for controllers that ! 82: * can support upto 4 drives. ! 83: */ ! 84: #define NDRIVES_PER_HDC 2 ! 85: #define NHDC ((NHD + NDRIVES_PER_HDC - 1) / NDRIVES_PER_HDC) ! 86: ! 87: #define b_cylin b_resid ! 88: ! 89: #define B_ABS B_MD1 ! 90: #define B_IDENTIFY (B_MD1 << 1) ! 91: ! 92: /* shift right SLICE_BITS + PARTITION_BITS. Note: 2^10 = 1024 sub-parts */ ! 93: #define hdunit(dev) (((dev) >> 10) & 3) ! 94: #define hdpart(dev) ((dev) & 0x3ff) ! 95: ! 96: #define MAX_RETRIES 12 /* maximum number of retries */ ! 97: #define OP_TIMEOUT 7 /* time to wait (secs) for an operation */ ! 98: ! 99: /* ! 100: * Autoconfiguration stuff. ! 101: */ ! 102: struct bus_ctlr *hdminfo[NHDC]; ! 103: struct bus_device *hddinfo[NHD]; ! 104: int hdstd[] = { 0 }; ! 105: int hdprobe(), hdslave(), hdstrategy(); ! 106: void hdattach(); ! 107: struct bus_driver hddriver = { ! 108: hdprobe, hdslave, hdattach, 0, hdstd, "hd", hddinfo, "hdc", hdminfo, 0 ! 109: }; ! 110: ! 111: /* ! 112: * BIOS geometry. ! 113: */ ! 114: struct hdbios { ! 115: int bg_ncyl; /* cylinders/unit */ ! 116: int bg_ntrk; /* tracks/cylinder */ ! 117: int bg_precomp; /* write precomp cylinder */ ! 118: int bg_nsect; /* sectors/track */ ! 119: } hdbios[NHD]; ! 120: ! 121: /* ! 122: * Controller state. ! 123: */ ! 124: struct hdcsoftc { ! 125: int sc_state; /* transfer fsm */ ! 126: caddr_t sc_addr; /* buffer address */ ! 127: int sc_resid; /* amount left to transfer */ ! 128: int sc_amt; /* amount currently being transferred */ ! 129: int sc_cnt; /* amount transferred per interrupt */ ! 130: int sc_sn; /* sector number */ ! 131: int sc_tn; /* track number */ ! 132: int sc_cn; /* cylinder number */ ! 133: int sc_recalerr; /* # recalibration errors */ ! 134: int sc_ioerr; /* # i/o errors */ ! 135: int sc_wticks; /* watchdog */ ! 136: caddr_t sc_buf; /* buffer for unaligned requests */ ! 137: } hdcsoftc[NHDC]; ! 138: ! 139: /* ! 140: * Transfer states. ! 141: */ ! 142: #define IDLE 0 /* controller is idle */ ! 143: #define SETPARAM 1 /* set disk parameters */ ! 144: #define SETPARAMDONE 2 /* set parameters done */ ! 145: #define RESTORE 3 /* recalibrate drive */ ! 146: #define RESTOREDONE 4 /* recalibrate done */ ! 147: #define TRANSFER 5 /* perform I/O transfer */ ! 148: #define TRANSFERDONE 6 /* transfer done */ ! 149: #define IDENTIFY 7 /* get drive info */ ! 150: #define IDENTIFYDONE 8 /* get drive info done */ ! 151: #define SETMULTI 9 /* set multiple mode count */ ! 152: #define SETMULTIDONE 10 /* set multiple mode count done */ ! 153: ! 154: /* ! 155: * Drive state. ! 156: */ ! 157: struct hdsoftc { ! 158: int sc_flags; ! 159: #define HDF_SETPARAM 0x001 /* set drive parameters before I/O operation */ ! 160: #define HDF_RESTORE 0x002 /* drive needs recalibration */ ! 161: #define HDF_WANT 0x004 /* some one is waiting for drive */ ! 162: #define HDF_UNALIGNED 0x008 /* request is not a multiple of sector size */ ! 163: #define HDF_SETMULTI 0x010 /* set multiple count before I/O operation */ ! 164: #define HDF_MULTIDONE 0x020 /* multicnt field is valid */ ! 165: #define HDF_IDENTDONE 0x040 /* identify command done */ ! 166: #define HDF_LBA 0x080 /* use LBA mode */ ! 167: int sc_multicnt; /* current multiple count */ ! 168: int sc_abssn; /* absolute sector number (for {RD,WR}ABS) */ ! 169: int sc_abscnt; /* absolute sector count */ ! 170: int sc_openpart; /* bit mask of open partitions */ ! 171: struct hdident sc_id; /* info returned by identify */ ! 172: } hdsoftc[NHD]; ! 173: ! 174: struct buf hdtab[NHDC]; /* controller queues */ ! 175: struct buf hdutab[NHD]; /* drive queues */ ! 176: struct disklabel hdlabel[NHD]; /* disklabels -- incorrect info! */ ! 177: struct diskpart array[NHD*MAX_IDE_PARTS]; /* partition info */ ! 178: ! 179: /* ! 180: * To enable multiple mode, ! 181: * set this, recompile, and reboot the machine. ! 182: */ ! 183: int hdenmulti = 0; ! 184: ! 185: char *hderrchk(); ! 186: struct buf *geteblk(); ! 187: int hdwstart = 0; ! 188: void hdwatch(); ! 189: ! 190: /* ! 191: * Probe for a controller. ! 192: */ ! 193: int ! 194: hdprobe(xxx, um) ! 195: int xxx; ! 196: struct bus_ctlr *um; ! 197: { ! 198: struct hdcsoftc *hdc; ! 199: ! 200: if (um->unit >= NHDC) { ! 201: printf("hdc%d: not configured\n", um->unit); ! 202: return (0); ! 203: } ! 204: if (um->unit > 0) { /* XXX: only 1 controller */ ! 205: ! 206: printf("nhd:probe for 2+ controllers -- not implemented\n"); ! 207: return (0); ! 208: } ! 209: ! 210: /* ! 211: * XXX: need real probe ! 212: */ ! 213: hdc = &hdcsoftc[um->unit]; ! 214: if (!hdc->sc_buf) ! 215: kmem_alloc(kernel_map, ! 216: (vm_offset_t *)&hdc->sc_buf, I386_PGBYTES); ! 217: take_ctlr_irq(um); ! 218: return (1); ! 219: } ! 220: ! 221: /* ! 222: * Probe for a drive. ! 223: */ ! 224: int ! 225: hdslave(ui) ! 226: struct bus_device *ui; ! 227: { ! 228: int type; ! 229: ! 230: if (ui->unit >= NHD) { ! 231: printf("hd%d: not configured\n", ui->unit); ! 232: return (0); ! 233: } ! 234: if (ui->unit > 1) /* XXX: only 2 drives */ ! 235: return (0); ! 236: ! 237: /* ! 238: * Find out if drive exists by reading CMOS. ! 239: */ ! 240: outb(CMOS_ADDR, 0x12); ! 241: type = inb(CMOS_DATA); ! 242: if (ui->unit == 0) ! 243: type >>= 4; ! 244: type &= 0x0f; ! 245: return (type); ! 246: } ! 247: ! 248: /* ! 249: * Attach a drive to the system. ! 250: */ ! 251: void ! 252: hdattach(ui) ! 253: struct bus_device *ui; ! 254: { ! 255: char *tbl; ! 256: unsigned n; ! 257: /* struct hdsoftc *sc = &hdsoftc[ui->unit]; */ ! 258: struct disklabel *lp = &hdlabel[ui->unit]; ! 259: struct hdbios *bg = &hdbios[ui->unit]; ! 260: ! 261: /* ! 262: * Set up a temporary disklabel from BIOS parameters. ! 263: * The actual partition table will be read during open. ! 264: */ ! 265: n = *(unsigned *)phystokv(ui->address); ! 266: tbl = (unsigned char *)phystokv((n & 0xffff) + ((n >> 12) & 0xffff0)); ! 267: bg->bg_ncyl = *(unsigned short *)tbl; ! 268: bg->bg_ntrk = *(unsigned char *)(tbl + 2); ! 269: bg->bg_precomp = *(unsigned short *)(tbl + 5); ! 270: bg->bg_nsect = *(unsigned char *)(tbl + 14); ! 271: fudge_bsd_label(lp, DTYPE_ESDI, bg->bg_ncyl*bg->bg_ntrk*bg->bg_nsect, ! 272: bg->bg_ntrk, bg->bg_nsect, SECSIZE, 3); ! 273: ! 274: /* FORCE sector size to 512... */ ! 275: ! 276: printf(": ntrak(heads) %d, ncyl %d, nsec %d, size %u MB", ! 277: lp->d_ntracks, lp->d_ncylinders, lp->d_nsectors, ! 278: lp->d_secperunit * lp->d_secsize / (1024*1024)); ! 279: } ! 280: ! 281: int ! 282: hdopen(dev, mode) ! 283: dev_t dev; ! 284: int mode; ! 285: { ! 286: int unit = hdunit(dev), part = hdpart(dev) /*, error */; ! 287: struct bus_device *ui; ! 288: struct hdsoftc *sc; ! 289: struct diskpart *label; ! 290: ! 291: if (unit >= NHD || (ui = hddinfo[unit]) == 0 || ui->alive == 0) ! 292: return (ENXIO); ! 293: if (!hdwstart) { ! 294: hdwstart++; ! 295: timeout(hdwatch, 0, hz); ! 296: } ! 297: sc = &hdsoftc[unit]; ! 298: /* should this be changed so only gets called once, even if all ! 299: partitions are closed and re-opened? */ ! 300: if (sc->sc_openpart == 0) { ! 301: hdinit(dev); ! 302: if (sc->sc_flags & HDF_LBA) ! 303: printf("hd%d: Using LBA mode\n", ui->unit); ! 304: } ! 305: ! 306: /* Note: should set a bit in the label structure to ensure that ! 307: aliasing prevents multiple instances to be opened. */ ! 308: #if 0 ! 309: if (part >= MAXPARTITIONS || lp->d_partitions[part].p_size == 0) ! 310: return (ENXIO); ! 311: #endif 0 ! 312: ! 313: label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(dev)); ! 314: if (!label) ! 315: return (ENXIO); ! 316: ! 317: ! 318: sc->sc_openpart |= 1 << part; ! 319: return (0); ! 320: } ! 321: ! 322: int ! 323: hdclose(dev) ! 324: dev_t dev; ! 325: { ! 326: int unit = hdunit(dev), s; ! 327: struct hdsoftc *sc = &hdsoftc[unit]; ! 328: ! 329: sc->sc_openpart &= ~(1 << hdpart(dev)); ! 330: if (sc->sc_openpart == 0) { ! 331: s = splbio(); ! 332: while (hdutab[unit].b_active) { ! 333: sc->sc_flags |= HDF_WANT; ! 334: assert_wait((event_t)sc, FALSE); ! 335: thread_block((void (*)())0); ! 336: } ! 337: splx(s); ! 338: } ! 339: return (0); ! 340: } ! 341: ! 342: int ! 343: hdread(dev, ior) ! 344: dev_t dev; ! 345: io_req_t ior; ! 346: { ! 347: return (block_io(hdstrategy, minphys, ior)); ! 348: } ! 349: ! 350: int ! 351: hdwrite(dev, ior) ! 352: dev_t dev; ! 353: io_req_t ior; ! 354: { ! 355: return (block_io(hdstrategy, minphys, ior)); ! 356: } ! 357: ! 358: int ! 359: hdgetstat(dev, flavor, data, count) ! 360: dev_t dev; ! 361: dev_flavor_t flavor; ! 362: dev_status_t data; ! 363: mach_msg_type_number_t *count; ! 364: { ! 365: int unit = hdunit(dev), part = hdpart(dev); ! 366: struct hdsoftc *sc = &hdsoftc[unit]; ! 367: struct disklabel *lp = &hdlabel[unit]; ! 368: struct buf *bp; ! 369: struct diskpart *label; ! 370: ! 371: label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(dev)); ! 372: switch (flavor) { ! 373: ! 374: case DEV_GET_SIZE: ! 375: if (label) { ! 376: data[DEV_GET_SIZE_DEVICE_SIZE] = (label->size * lp->d_secsize); ! 377: data[DEV_GET_SIZE_RECORD_SIZE] = lp->d_secsize; ! 378: *count = DEV_GET_SIZE_COUNT; ! 379: } else { /* Kevin: added checking here */ ! 380: data[DEV_GET_SIZE_DEVICE_SIZE] = 0; ! 381: data[DEV_GET_SIZE_RECORD_SIZE] = 0; ! 382: *count = 0; ! 383: } ! 384: break; ! 385: ! 386: case DIOCGDINFO: ! 387: case DIOCGDINFO - (0x10 << 16): ! 388: dkgetlabel(lp, flavor, data, count); ! 389: break; ! 390: ! 391: case V_GETPARMS: ! 392: { ! 393: struct disk_parms *dp; ! 394: struct hdbios *bg = &hdbios[unit]; ! 395: ! 396: if (*count < (sizeof(struct disk_parms) / sizeof(int))) ! 397: return (D_INVALID_OPERATION); ! 398: dp = (struct disk_parms *)data; ! 399: dp->dp_type = DPT_WINI; ! 400: dp->dp_heads = lp->d_ntracks; ! 401: dp->dp_cyls = lp->d_ncylinders; ! 402: dp->dp_sectors = lp->d_nsectors; ! 403: dp->dp_dosheads = bg->bg_ntrk; ! 404: dp->dp_doscyls = bg->bg_ncyl; ! 405: dp->dp_dossectors = bg->bg_nsect; ! 406: dp->dp_secsiz = lp->d_secsize; ! 407: dp->dp_ptag = 0; ! 408: dp->dp_pflag = 0; ! 409: if (label) { ! 410: dp->dp_pstartsec = label->start; ! 411: dp->dp_pnumsec = label->size; ! 412: } else { /* added by Kevin */ ! 413: dp->dp_pstartsec = -1; ! 414: dp->dp_pnumsec = -1; ! 415: } ! 416: ! 417: *count = sizeof(struct disk_parms) / sizeof(int); ! 418: break; ! 419: } ! 420: case V_RDABS: ! 421: if (*count < lp->d_secsize / sizeof(int)) { ! 422: printf("hd%d: RDABS, bad size %d\n", unit, *count); ! 423: return (EINVAL); ! 424: } ! 425: bp = geteblk(lp->d_secsize); ! 426: bp->b_flags = B_READ | B_ABS; ! 427: bp->b_blkno = sc->sc_abssn; ! 428: bp->b_dev = dev; ! 429: bp->b_bcount = lp->d_secsize; ! 430: hdstrategy(bp); ! 431: biowait(bp); ! 432: if (bp->b_flags & B_ERROR) { ! 433: printf("hd%d: RDABS failed\n", unit); ! 434: brelse(bp); ! 435: return (EIO); ! 436: } ! 437: bcopy(bp->b_un.b_addr, (caddr_t)data, lp->d_secsize); ! 438: brelse(bp); ! 439: *count = lp->d_secsize / sizeof(int); ! 440: break; ! 441: ! 442: case V_VERIFY: ! 443: { ! 444: int i, amt, n, error = 0; ! 445: ! 446: bp = geteblk(I386_PGBYTES); ! 447: bp->b_blkno = sc->sc_abssn; ! 448: bp->b_dev = dev; ! 449: amt = sc->sc_abscnt; ! 450: n = I386_PGBYTES / lp->d_secsize; ! 451: while (amt > 0) { ! 452: i = (amt > n) ? n : amt; ! 453: bp->b_bcount = i * lp->d_secsize; ! 454: bp->b_flags = B_READ | B_ABS; ! 455: hdstrategy(bp); ! 456: biowait(bp); ! 457: if (bp->b_flags & B_ERROR) { ! 458: error = BAD_BLK; ! 459: break; ! 460: } ! 461: amt -= bp->b_bcount; ! 462: bp->b_blkno += i; ! 463: } ! 464: brelse(bp); ! 465: data[0] = error; ! 466: *count = 1; ! 467: break; ! 468: } ! 469: default: ! 470: return (D_INVALID_OPERATION); ! 471: } ! 472: return (0); ! 473: } ! 474: ! 475: int ! 476: hdsetstat(dev, flavor, data, count) ! 477: dev_t dev; ! 478: dev_flavor_t flavor; ! 479: dev_status_t data; ! 480: mach_msg_type_number_t count; ! 481: { ! 482: int unit = hdunit(dev); /* , part = hdpart(dev); */ ! 483: int error = 0 /*, s */; ! 484: struct hdsoftc *sc = &hdsoftc[unit]; ! 485: struct disklabel *lp = &hdlabel[unit]; ! 486: struct buf *bp; ! 487: ! 488: switch (flavor) { ! 489: ! 490: case DIOCWLABEL: ! 491: case DIOCWLABEL - (0x10 << 16): ! 492: break; ! 493: ! 494: case DIOCSDINFO: ! 495: case DIOCSDINFO - (0x10 << 16): ! 496: if (count != (sizeof(struct disklabel) / sizeof(int))) ! 497: return (D_INVALID_SIZE); ! 498: error = setdisklabel(lp, (struct disklabel *)data); ! 499: if (error == 0 && (sc->sc_flags & HDF_LBA) == 0) ! 500: sc->sc_flags |= HDF_SETPARAM; ! 501: break; ! 502: ! 503: case DIOCWDINFO: ! 504: case DIOCWDINFO - (0x10 << 16): ! 505: if (count != (sizeof(struct disklabel) / sizeof(int))) ! 506: return (D_INVALID_SIZE); ! 507: error = setdisklabel(lp, (struct disklabel *)data); ! 508: if (error == 0) { ! 509: if ((sc->sc_flags & HDF_LBA) == 0) ! 510: sc->sc_flags |= HDF_SETPARAM; ! 511: error = hdwritelabel(dev); ! 512: } ! 513: break; ! 514: ! 515: case V_REMOUNT: ! 516: hdinit(dev); ! 517: break; ! 518: ! 519: case V_ABS: ! 520: if (count != 1 && count != 2) ! 521: return (D_INVALID_OPERATION); ! 522: sc->sc_abssn = *(int *)data; ! 523: if (sc->sc_abssn < 0 || sc->sc_abssn >= lp->d_secperunit) ! 524: return (D_INVALID_OPERATION); ! 525: if (count == 2) ! 526: sc->sc_abscnt = *((int *)data + 1); ! 527: else ! 528: sc->sc_abscnt = 1; ! 529: if (sc->sc_abscnt <= 0 ! 530: || sc->sc_abssn + sc->sc_abscnt > lp->d_secperunit) ! 531: return (D_INVALID_OPERATION); ! 532: break; ! 533: ! 534: case V_WRABS: ! 535: if (count < (lp->d_secsize / sizeof(int))) { ! 536: printf("hd%d: WRABS, bad size %d\n", unit, count); ! 537: return (D_INVALID_OPERATION); ! 538: } ! 539: bp = geteblk(lp->d_secsize); ! 540: bcopy((caddr_t)data, bp->b_un.b_addr, lp->d_secsize); ! 541: bp->b_flags = B_WRITE | B_ABS; ! 542: bp->b_blkno = sc->sc_abssn; ! 543: bp->b_bcount = lp->d_secsize; ! 544: bp->b_dev = dev; ! 545: hdstrategy(bp); ! 546: biowait(bp); ! 547: if (bp->b_flags & B_ERROR) { ! 548: printf("hd%d: WRABS failed\n", unit); ! 549: error = EIO; ! 550: } ! 551: brelse(bp); ! 552: break; ! 553: ! 554: default: ! 555: return (D_INVALID_OPERATION); ! 556: } ! 557: return (error); ! 558: } ! 559: ! 560: int ! 561: hddevinfo(dev, flavor, info) ! 562: dev_t dev; ! 563: int flavor; ! 564: char *info; ! 565: { ! 566: switch (flavor) { ! 567: ! 568: case D_INFO_BLOCK_SIZE: ! 569: *((int *)info) = SECSIZE; /* #defined to 512 */ ! 570: break; ! 571: ! 572: default: ! 573: return (D_INVALID_OPERATION); ! 574: } ! 575: return (0); ! 576: } ! 577: ! 578: ! 579: ! 580: ! 581: /* Kevin T. Van Maren: Added this low-level routine for the unified ! 582: partition code. A pointer to this routine is passed, along with param* */ ! 583: int ! 584: ide_read_fun(struct ide_driver_info *param, int sectornum, char *buff) ! 585: { ! 586: struct buf *bp; ! 587: ! 588: bp = geteblk(param->sectorsize); ! 589: bp->b_flags = B_READ | B_ABS; ! 590: ! 591: bp->b_bcount = param->sectorsize; ! 592: bp->b_blkno = sectornum; ! 593: ! 594: /* WARNING: DEPENDS ON NUMBER OF BITS FOR PARTITIONS */ ! 595: bp->b_dev = param->dev & ~0x3ff; ! 596: hdstrategy(bp); ! 597: biowait(bp); ! 598: if ((bp->b_flags & B_ERROR) == 0) ! 599: bcopy((char *)bp->b_un.b_addr, buff, param->sectorsize); ! 600: else { ! 601: printf("ERROR!\n"); ! 602: return(B_ERROR); ! 603: } ! 604: ! 605: brelse(bp); ! 606: return(0); ! 607: } ! 608: ! 609: ! 610: ! 611: /* ! 612: * Initialize drive. ! 613: */ ! 614: int ! 615: hdinit(dev) ! 616: dev_t dev; ! 617: { ! 618: int unit = hdunit(dev); ! 619: struct hdsoftc *sc = &hdsoftc[unit]; ! 620: struct disklabel *lp = &hdlabel[unit], *dlp; ! 621: struct buf *bp = 0; ! 622: int numpart; ! 623: ! 624: struct ide_driver_info ide_param = { dev, /* bp, */ lp->d_secsize }; ! 625: int ret; ! 626: ! 627: /* ! 628: * Issue identify command. ! 629: */ ! 630: if ((sc->sc_flags & HDF_IDENTDONE) == 0) { ! 631: sc->sc_flags |= HDF_IDENTDONE; ! 632: bp = geteblk(lp->d_secsize); ! 633: /* sector size #defined to 512 */ ! 634: bp->b_flags = B_IDENTIFY; ! 635: bp->b_dev = dev; ! 636: hdstrategy(bp); ! 637: biowait(bp); ! 638: if ((bp->b_flags & B_ERROR) == 0) { ! 639: bcopy((char *)bp->b_un.b_addr, ! 640: (char *)&sc->sc_id, sizeof(struct hdident)); ! 641: ! 642: /* ! 643: * Check if drive supports LBA mode. ! 644: */ ! 645: if (sc->sc_id.id_capability & 2) ! 646: sc->sc_flags |= HDF_LBA; ! 647: } ! 648: } ! 649: ! 650: /* ! 651: * Check if drive supports multiple read/write mode. ! 652: */ ! 653: hdmulti(dev); ! 654: ! 655: /* Note: label was fudged during attach! */ ! 656: ! 657: /* ensure the 'raw disk' can be accessed reliably */ ! 658: array[MAX_IDE_PARTS*unit].start=0; ! 659: array[MAX_IDE_PARTS*unit].size=lp->d_secperunit; /* fill in root for MY reads */ ! 660: #if 0 ! 661: array[MAX_IDE_PARTS*unit].subs=0; ! 662: array[MAX_IDE_PARTS*unit].nsubs=0; ! 663: array[MAX_IDE_PARTS*unit].type=0; ! 664: array[MAX_IDE_PARTS*unit].fsys=0; ! 665: #endif 0 ! 666: ! 667: numpart=get_only_partition(&ide_param, (*ide_read_fun), ! 668: &array[MAX_IDE_PARTS*unit],MAX_IDE_PARTS,lp->d_secperunit, ! 669: drive_name[unit]); ! 670: ! 671: printf("%s %d partitions found\n",drive_name[unit],numpart); ! 672: ! 673: if ((sc->sc_flags & HDF_LBA) == 0) ! 674: sc->sc_flags |= HDF_SETPARAM; ! 675: ! 676: brelse(bp); ! 677: return(ret); ! 678: } ! 679: ! 680: ! 681: ! 682: ! 683: /* ! 684: * Check if drive supports multiple read/write mode. ! 685: */ ! 686: int ! 687: hdmulti(dev) ! 688: dev_t dev; ! 689: { ! 690: int unit = hdunit(dev); ! 691: struct hdsoftc *sc = &hdsoftc[unit]; ! 692: struct buf *bp; ! 693: struct hdident *id; ! 694: ! 695: if (sc->sc_flags & HDF_MULTIDONE) ! 696: return(0); ! 697: ! 698: sc->sc_flags |= HDF_MULTIDONE; ! 699: ! 700: if (hdenmulti == 0) ! 701: return(0); ! 702: ! 703: /* ! 704: * Get drive information by issuing IDENTIFY command. ! 705: */ ! 706: bp = geteblk(DEV_BSIZE); ! 707: bp->b_flags = B_IDENTIFY; ! 708: bp->b_dev = dev; ! 709: hdstrategy(bp); ! 710: biowait(bp); ! 711: id = (struct hdident *)bp->b_un.b_addr; ! 712: ! 713: /* ! 714: * If controller does not recognise IDENTIFY command, ! 715: * or does not support multiple mode, clear count. ! 716: */ ! 717: if ((bp->b_flags & B_ERROR) || !id->id_multisize) ! 718: sc->sc_multicnt = 0; ! 719: else { ! 720: sc->sc_multicnt = id->id_multisize; ! 721: printf("hd%d: max multiple size %u", unit, sc->sc_multicnt); ! 722: /* ! 723: * Use 4096 since it is the minimum block size in FFS. ! 724: */ ! 725: if (sc->sc_multicnt > 4096 / 512) ! 726: sc->sc_multicnt = 4096 / 512; ! 727: printf(", using %u\n", sc->sc_multicnt); ! 728: sc->sc_flags |= HDF_SETMULTI; ! 729: } ! 730: brelse(bp); ! 731: } ! 732: ! 733: /* ! 734: * Write label to disk. ! 735: */ ! 736: int ! 737: hdwritelabel(dev) ! 738: dev_t dev; ! 739: { ! 740: int unit = hdunit(dev), error = 0; ! 741: long labelsect; ! 742: struct buf *bp; ! 743: struct disklabel *lp = &hdlabel[unit]; ! 744: ! 745: printf("hdwritelabel: no longer implemented\n"); ! 746: ! 747: #if 0 ! 748: bp = geteblk(lp->d_secsize); ! 749: bp->b_flags = B_READ | B_ABS; ! 750: bp->b_blkno = LBLLOC + lp->d_partitions[PART_DISK].p_offset; ! 751: bp->b_bcount = lp->d_secsize; ! 752: bp->b_dev = dev; ! 753: hdstrategy(bp); ! 754: biowait(bp); ! 755: if (bp->b_flags & B_ERROR) { ! 756: printf("hd%d: hdwritelabel(), error reading disklabel\n",unit); ! 757: error = EIO; ! 758: goto out; ! 759: } ! 760: *(struct disklabel *)bp->b_un.b_addr = *lp; /* copy disk label */ ! 761: bp->b_flags = B_WRITE | B_ABS; ! 762: hdstrategy(bp); ! 763: biowait(bp); ! 764: if (bp->b_flags & B_ERROR) { ! 765: printf("hd%d: hdwritelabel(), error writing disklabel\n",unit); ! 766: error = EIO; ! 767: } ! 768: out: ! 769: brelse(bp); ! 770: #endif 0 ! 771: ! 772: return (error); ! 773: } ! 774: ! 775: /* ! 776: * Strategy routine. ! 777: * Enqueue request on drive. ! 778: */ ! 779: int ! 780: hdstrategy(bp) ! 781: struct buf *bp; ! 782: { ! 783: int unit = hdunit(bp->b_dev), part = hdpart(bp->b_dev), s; ! 784: long bn, sz, maxsz; ! 785: struct buf *dp; ! 786: struct hdsoftc *sc = &hdsoftc[unit]; ! 787: struct bus_device *ui = hddinfo[unit]; ! 788: struct disklabel *lp = &hdlabel[unit]; ! 789: struct diskpart *label; ! 790: ! 791: if (bp->b_flags & B_IDENTIFY) { ! 792: bp->b_cylin = 0; ! 793: goto q; ! 794: } ! 795: bn = bp->b_blkno; ! 796: if (bp->b_flags & B_ABS) ! 797: goto q1; ! 798: sz = (bp->b_bcount + lp->d_secsize - 1) / lp->d_secsize; ! 799: label=lookup_part(&array[MAX_IDE_PARTS*unit], hdpart(bp->b_dev)); ! 800: if (label) { ! 801: maxsz = label->size; ! 802: } else { ! 803: bp->b_flags |= B_ERROR; ! 804: bp->b_error = EINVAL; ! 805: goto done; ! 806: } ! 807: ! 808: if (bn < 0 || bn + sz > maxsz) { ! 809: if (bn == maxsz) { ! 810: bp->b_resid = bp->b_bcount; ! 811: goto done; ! 812: } ! 813: sz = maxsz - bn; ! 814: if (sz <= 0) { ! 815: bp->b_flags |= B_ERROR; ! 816: bp->b_error = EINVAL; ! 817: goto done; ! 818: } ! 819: bp->b_bcount = sz * lp->d_secsize; ! 820: } ! 821: bn += lp->d_partitions[part].p_offset; ! 822: bn += label->start; ! 823: ! 824: q1: ! 825: bp->b_cylin = (sc->sc_flags & HDF_LBA) ? bn : bn / lp->d_secpercyl; ! 826: q: ! 827: dp = &hdutab[unit]; ! 828: s = splbio(); ! 829: disksort(dp, bp); ! 830: if (!dp->b_active) { ! 831: hdustart(ui); ! 832: if (!hdtab[ui->mi->unit].b_active) ! 833: hdstart(ui->mi); ! 834: } ! 835: splx(s); ! 836: return(0); ! 837: done: ! 838: biodone(bp); ! 839: return(0); ! 840: } ! 841: ! 842: /* ! 843: * Unit start routine. ! 844: * Move request from drive to controller queue. ! 845: */ ! 846: int ! 847: hdustart(ui) ! 848: struct bus_device *ui; ! 849: { ! 850: struct buf *bp; ! 851: struct buf *dp; ! 852: ! 853: bp = &hdutab[ui->unit]; ! 854: if (bp->b_actf == 0) ! 855: return(0); ! 856: dp = &hdtab[ui->mi->unit]; ! 857: if (dp->b_actf == 0) ! 858: dp->b_actf = bp; ! 859: else ! 860: dp->b_actl->b_forw = bp; ! 861: bp->b_forw = 0; ! 862: dp->b_actl = bp; ! 863: bp->b_active++; ! 864: } ! 865: ! 866: /* ! 867: * Start output on controller. ! 868: */ ! 869: int ! 870: hdstart(um) ! 871: struct bus_ctlr *um; ! 872: { ! 873: long bn; ! 874: struct buf *bp; ! 875: struct buf *dp; ! 876: struct hdsoftc *sc; ! 877: struct hdcsoftc *hdc; ! 878: struct bus_device *ui; ! 879: struct disklabel *lp; ! 880: struct diskpart *label; ! 881: ! 882: /* ! 883: * Pull a request from the controller queue. ! 884: */ ! 885: dp = &hdtab[um->unit]; ! 886: if ((bp = dp->b_actf) == 0) ! 887: return(0); ! 888: bp = bp->b_actf; ! 889: ! 890: hdc = &hdcsoftc[um->unit]; ! 891: ui = hddinfo[hdunit(bp->b_dev)]; ! 892: sc = &hdsoftc[ui->unit]; ! 893: lp = &hdlabel[ui->unit]; ! 894: ! 895: label = lookup_part(&array[MAX_IDE_PARTS*hdunit(bp->b_dev)], hdpart(bp->b_dev)); ! 896: ! 897: /* ! 898: * Mark controller busy. ! 899: */ ! 900: dp->b_active++; ! 901: ! 902: if (bp->b_flags & B_IDENTIFY) { ! 903: hdc->sc_state = IDENTIFY; ! 904: goto doit; ! 905: } ! 906: ! 907: /* ! 908: * Figure out where this request is going. ! 909: */ ! 910: if (sc->sc_flags & HDF_LBA) ! 911: hdc->sc_cn = bp->b_cylin; ! 912: else { ! 913: bn = bp->b_blkno; ! 914: if ((bp->b_flags & B_ABS) == 0) { ! 915: bn += label->start; /* partition must be valid */ ! 916: } ! 917: hdc->sc_cn = bp->b_cylin; ! 918: hdc->sc_sn = bn % lp->d_secpercyl; ! 919: hdc->sc_tn = hdc->sc_sn / lp->d_nsectors; ! 920: hdc->sc_sn %= lp->d_nsectors; ! 921: } ! 922: ! 923: /* ! 924: * Set up for multi-sector transfer. ! 925: */ ! 926: hdc->sc_addr = bp->b_un.b_addr; ! 927: hdc->sc_resid = bp->b_bcount; ! 928: hdc->sc_wticks = 0; ! 929: hdc->sc_recalerr = 0; ! 930: hdc->sc_ioerr = 0; ! 931: ! 932: /* ! 933: * Set initial transfer state. ! 934: */ ! 935: if (sc->sc_flags & HDF_SETPARAM) ! 936: hdc->sc_state = SETPARAM; ! 937: else if (sc->sc_flags & HDF_RESTORE) ! 938: hdc->sc_state = RESTORE; ! 939: else if (sc->sc_flags & HDF_SETMULTI) ! 940: hdc->sc_state = SETMULTI; ! 941: else ! 942: hdc->sc_state = TRANSFER; ! 943: ! 944: doit: ! 945: /* ! 946: * Call transfer state routine to do the actual I/O. ! 947: */ ! 948: hdstate(um); ! 949: } ! 950: ! 951: /* ! 952: * Interrupt routine. ! 953: */ ! 954: int ! 955: hdintr(ctlr) ! 956: int ctlr; ! 957: { ! 958: int timedout; ! 959: struct bus_ctlr *um = hdminfo[ctlr]; ! 960: struct bus_device *ui; ! 961: struct buf *bp; ! 962: struct buf *dp = &hdtab[ctlr]; ! 963: struct hdcsoftc *hdc = &hdcsoftc[ctlr]; ! 964: ! 965: if (!dp->b_active) { ! 966: (void) inb(HD_STATUS(um->address)); ! 967: printf("hdc%d: stray interrupt\n", ctlr); ! 968: return(0); ! 969: } ! 970: timedout = hdc->sc_wticks >= OP_TIMEOUT; ! 971: hdc->sc_wticks = 0; ! 972: ! 973: /* ! 974: * Operation timed out, terminate request. ! 975: */ ! 976: if (timedout) { ! 977: bp = dp->b_actf->b_actf; ! 978: ui = hddinfo[hdunit(bp->b_dev)]; ! 979: hderror("timed out", ui); ! 980: hdsoftc[ui->unit].sc_flags |= HDF_RESTORE; ! 981: bp->b_flags |= B_ERROR; ! 982: bp->b_error = EIO; ! 983: hddone(ui, bp); ! 984: return(0); ! 985: } ! 986: ! 987: /* ! 988: * Let transfer state routine handle the rest. ! 989: */ ! 990: hdstate(um); ! 991: } ! 992: ! 993: /* ! 994: * Transfer finite state machine driver. ! 995: */ ! 996: int ! 997: hdstate(um) ! 998: struct bus_ctlr *um; ! 999: { ! 1000: char *msg; ! 1001: int op; ! 1002: struct buf *bp; ! 1003: struct hdsoftc *sc; ! 1004: struct bus_device *ui; ! 1005: struct disklabel *lp; ! 1006: struct hdcsoftc *hdc = &hdcsoftc[um->unit]; ! 1007: struct hdbios *bg; ! 1008: ! 1009: bp = hdtab[um->unit].b_actf->b_actf; ! 1010: ui = hddinfo[hdunit(bp->b_dev)]; ! 1011: lp = &hdlabel[ui->unit]; ! 1012: sc = &hdsoftc[ui->unit]; ! 1013: bg = &hdbios[ui->unit]; ! 1014: ! 1015: /* ! 1016: * Ensure controller is not busy. ! 1017: */ ! 1018: if (!hdwait(um)) ! 1019: goto ctlr_err; ! 1020: ! 1021: while (1) switch (hdc->sc_state) { ! 1022: ! 1023: case SETPARAM: ! 1024: /* ! 1025: * Set drive parameters. ! 1026: */ ! 1027: outb(HD_DRVHD(um->address), ! 1028: 0xa0 | (ui->slave << 4) | (lp->d_ntracks - 1)); ! 1029: outb(HD_SECTCNT(um->address), lp->d_nsectors); ! 1030: outb(HD_CMD(um->address), CMD_SETPARAM); ! 1031: hdc->sc_state = SETPARAMDONE; ! 1032: return(0); ! 1033: ! 1034: case SETPARAMDONE: ! 1035: /* ! 1036: * Set parameters complete. ! 1037: */ ! 1038: if (msg = hderrchk(um)) ! 1039: goto bad; ! 1040: sc->sc_flags &= ~HDF_SETPARAM; ! 1041: hdc->sc_state = RESTORE; ! 1042: break; ! 1043: ! 1044: case RESTORE: ! 1045: /* ! 1046: * Recalibrate drive. ! 1047: */ ! 1048: outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4)); ! 1049: outb(HD_CMD(um->address), CMD_RESTORE); ! 1050: hdc->sc_state = RESTOREDONE; ! 1051: return(0); ! 1052: ! 1053: case RESTOREDONE: ! 1054: /* ! 1055: * Recalibration complete. ! 1056: */ ! 1057: if (msg = hderrchk(um)) { ! 1058: if (++hdc->sc_recalerr == 2) ! 1059: goto bad; ! 1060: hdc->sc_state = RESTORE; ! 1061: break; ! 1062: } ! 1063: sc->sc_flags &= ~HDF_RESTORE; ! 1064: hdc->sc_recalerr = 0; ! 1065: if (sc->sc_flags & HDF_SETMULTI) ! 1066: hdc->sc_state = SETMULTI; ! 1067: else ! 1068: hdc->sc_state = TRANSFER; ! 1069: break; ! 1070: ! 1071: case TRANSFER: ! 1072: /* ! 1073: * Perform I/O transfer. ! 1074: */ ! 1075: sc->sc_flags &= ~HDF_UNALIGNED; ! 1076: hdc->sc_state = TRANSFERDONE; ! 1077: hdc->sc_amt = hdc->sc_resid / lp->d_secsize; ! 1078: if (hdc->sc_amt == 0) { ! 1079: sc->sc_flags |= HDF_UNALIGNED; ! 1080: hdc->sc_amt = 1; ! 1081: } else if (hdc->sc_amt > 256) ! 1082: hdc->sc_amt = 256; ! 1083: if (sc->sc_multicnt > 1 && hdc->sc_amt >= sc->sc_multicnt) { ! 1084: hdc->sc_cnt = sc->sc_multicnt; ! 1085: hdc->sc_amt -= hdc->sc_amt % hdc->sc_cnt; ! 1086: if (bp->b_flags & B_READ) ! 1087: op = CMD_READMULTI; ! 1088: else ! 1089: op = CMD_WRITEMULTI; ! 1090: } else { ! 1091: hdc->sc_cnt = 1; ! 1092: if (bp->b_flags & B_READ) ! 1093: op = CMD_READ; ! 1094: else ! 1095: op = CMD_WRITE; ! 1096: } ! 1097: if (sc->sc_flags & HDF_LBA) { ! 1098: outb(HD_DRVHD(um->address), ! 1099: (0xe0 | (ui->slave << 4) ! 1100: | ((hdc->sc_cn >> 24) & 0x0f))); ! 1101: outb(HD_SECT(um->address), hdc->sc_cn); ! 1102: outb(HD_CYLLO(um->address), hdc->sc_cn >> 8); ! 1103: outb(HD_CYLHI(um->address), hdc->sc_cn >> 16); ! 1104: } else { ! 1105: outb(HD_DRVHD(um->address), ! 1106: 0xa0 | (ui->slave << 4) | hdc->sc_tn); ! 1107: outb(HD_SECT(um->address), hdc->sc_sn + 1); ! 1108: outb(HD_CYLLO(um->address), hdc->sc_cn); ! 1109: outb(HD_CYLHI(um->address), hdc->sc_cn >> 8); ! 1110: } ! 1111: outb(HD_SECTCNT(um->address), hdc->sc_amt & 0xff); ! 1112: outb(HD_PRECOMP(um->address), bg->bg_precomp / 4); ! 1113: outb(HD_CMD(um->address), op); ! 1114: if ((bp->b_flags & B_READ) == 0) { ! 1115: int i; ! 1116: caddr_t buf; ! 1117: ! 1118: if (sc->sc_flags & HDF_UNALIGNED) { ! 1119: buf = hdc->sc_buf; ! 1120: bcopy(hdc->sc_addr, buf, hdc->sc_resid); ! 1121: bzero(buf + hdc->sc_resid, ! 1122: lp->d_secsize - hdc->sc_resid); ! 1123: } else ! 1124: buf = hdc->sc_addr; ! 1125: for (i = 0; i < 1000000; i++) ! 1126: if (inb(HD_STATUS(um->address)) & ST_DREQ) { ! 1127: loutw(HD_DATA(um->address), buf, ! 1128: hdc->sc_cnt * lp->d_secsize / 2); ! 1129: return(0); ! 1130: } ! 1131: goto ctlr_err; ! 1132: } ! 1133: return(0); ! 1134: ! 1135: case TRANSFERDONE: ! 1136: /* ! 1137: * Transfer complete. ! 1138: */ ! 1139: if (msg = hderrchk(um)) { ! 1140: if (++hdc->sc_ioerr == MAX_RETRIES) ! 1141: goto bad; ! 1142: /* ! 1143: * Every fourth attempt print a message ! 1144: * and recalibrate the drive. ! 1145: */ ! 1146: if (hdc->sc_ioerr & 3) ! 1147: hdc->sc_state = TRANSFER; ! 1148: else { ! 1149: hderror(msg, ui); ! 1150: hdc->sc_state = RESTORE; ! 1151: } ! 1152: break; ! 1153: } ! 1154: if (bp->b_flags & B_READ) { ! 1155: if (sc->sc_flags & HDF_UNALIGNED) { ! 1156: linw(HD_DATA(um->address), hdc->sc_buf, ! 1157: lp->d_secsize / 2); ! 1158: bcopy(hdc->sc_buf, hdc->sc_addr, ! 1159: hdc->sc_resid); ! 1160: } else ! 1161: linw(HD_DATA(um->address), hdc->sc_addr, ! 1162: hdc->sc_cnt * lp->d_secsize / 2); ! 1163: } ! 1164: hdc->sc_resid -= hdc->sc_cnt * lp->d_secsize; ! 1165: if (hdc->sc_resid <= 0) { ! 1166: bp->b_resid = 0; ! 1167: hddone(ui, bp); ! 1168: return(0); ! 1169: } ! 1170: if (sc->sc_flags & HDF_LBA) ! 1171: hdc->sc_cn += hdc->sc_cnt; ! 1172: else { ! 1173: hdc->sc_sn += hdc->sc_cnt; ! 1174: while (hdc->sc_sn >= lp->d_nsectors) { ! 1175: hdc->sc_sn -= lp->d_nsectors; ! 1176: if (++hdc->sc_tn == lp->d_ntracks) { ! 1177: hdc->sc_tn = 0; ! 1178: hdc->sc_cn++; ! 1179: } ! 1180: } ! 1181: } ! 1182: hdc->sc_ioerr = 0; ! 1183: hdc->sc_addr += hdc->sc_cnt * lp->d_secsize; ! 1184: hdc->sc_amt -= hdc->sc_cnt; ! 1185: if (hdc->sc_amt == 0) { ! 1186: hdc->sc_state = TRANSFER; ! 1187: break; ! 1188: } ! 1189: if ((bp->b_flags & B_READ) == 0) { ! 1190: int i; ! 1191: ! 1192: for (i = 0; i < 1000000; i++) ! 1193: if (inb(HD_STATUS(um->address)) & ST_DREQ) { ! 1194: loutw(HD_DATA(um->address), ! 1195: hdc->sc_addr, ! 1196: hdc->sc_cnt * lp->d_secsize / 2); ! 1197: return(0); ! 1198: } ! 1199: goto ctlr_err; ! 1200: } ! 1201: return(0); ! 1202: ! 1203: case IDENTIFY: ! 1204: /* ! 1205: * Get drive info. ! 1206: */ ! 1207: hdc->sc_state = IDENTIFYDONE; ! 1208: outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4)); ! 1209: outb(HD_CMD(um->address), CMD_IDENTIFY); ! 1210: return(0); ! 1211: ! 1212: case IDENTIFYDONE: ! 1213: /* ! 1214: * Get drive info complete. ! 1215: */ ! 1216: if (msg = hderrchk(um)) ! 1217: goto bad; ! 1218: linw(HD_DATA(um->address), (u_short *)bp->b_un.b_addr, 256); ! 1219: hddone(ui, bp); ! 1220: return(0); ! 1221: ! 1222: case SETMULTI: ! 1223: /* ! 1224: * Set multiple mode count. ! 1225: */ ! 1226: hdc->sc_state = SETMULTIDONE; ! 1227: outb(HD_DRVHD(um->address), 0xa0 | (ui->slave << 4)); ! 1228: outb(HD_SECTCNT(um->address), sc->sc_multicnt); ! 1229: outb(HD_CMD(um->address), CMD_SETMULTI); ! 1230: return(0); ! 1231: ! 1232: case SETMULTIDONE: ! 1233: /* ! 1234: * Set multiple mode count complete. ! 1235: */ ! 1236: sc->sc_flags &= ~HDF_SETMULTI; ! 1237: if (msg = hderrchk(um)) { ! 1238: sc->sc_multicnt = 0; ! 1239: goto bad; ! 1240: } ! 1241: hdc->sc_state = TRANSFER; ! 1242: break; ! 1243: ! 1244: default: ! 1245: printf("hd%d: invalid state\n", ui->unit); ! 1246: panic("hdstate"); ! 1247: /*NOTREACHED*/ ! 1248: } ! 1249: ! 1250: ctlr_err: ! 1251: msg = "controller error"; ! 1252: ! 1253: bad: ! 1254: hderror(msg, ui); ! 1255: bp->b_flags |= B_ERROR; ! 1256: bp->b_error = EIO; ! 1257: sc->sc_flags |= HDF_RESTORE; ! 1258: hddone(ui, bp); ! 1259: } ! 1260: ! 1261: /* ! 1262: * Terminate current request and start ! 1263: * any others that are queued. ! 1264: */ ! 1265: int ! 1266: hddone(ui, bp) ! 1267: struct bus_device *ui; ! 1268: struct buf *bp; ! 1269: { ! 1270: struct bus_ctlr *um = ui->mi; ! 1271: struct hdsoftc *sc = &hdsoftc[ui->unit]; ! 1272: struct hdcsoftc *hdc = &hdcsoftc[um->unit]; ! 1273: struct buf *dp = &hdtab[um->unit]; ! 1274: ! 1275: sc->sc_flags &= ~HDF_UNALIGNED; ! 1276: ! 1277: /* ! 1278: * Remove this request from queue. ! 1279: */ ! 1280: hdutab[ui->unit].b_actf = bp->b_actf; ! 1281: biodone(bp); ! 1282: bp = &hdutab[ui->unit]; ! 1283: dp->b_actf = bp->b_forw; ! 1284: ! 1285: /* ! 1286: * Mark controller and drive idle. ! 1287: */ ! 1288: dp->b_active = 0; ! 1289: bp->b_active = 0; ! 1290: hdc->sc_state = IDLE; ! 1291: ! 1292: /* ! 1293: * Start up other requests. ! 1294: */ ! 1295: hdustart(ui); ! 1296: hdstart(um); ! 1297: ! 1298: /* ! 1299: * Wakeup anyone waiting for drive. ! 1300: */ ! 1301: if (sc->sc_flags & HDF_WANT) { ! 1302: sc->sc_flags &= ~HDF_WANT; ! 1303: wakeup((caddr_t)sc); ! 1304: } ! 1305: } ! 1306: ! 1307: /* ! 1308: * Wait for controller to be idle. ! 1309: */ ! 1310: int ! 1311: hdwait(um) ! 1312: struct bus_ctlr *um; ! 1313: { ! 1314: int i, status; ! 1315: ! 1316: for (i = 0; i < 1000000; i++) { ! 1317: status = inb(HD_STATUS(um->address)); ! 1318: if ((status & ST_BUSY) == 0 && (status & ST_READY)) ! 1319: return (status); ! 1320: } ! 1321: return (0); ! 1322: } ! 1323: ! 1324: /* ! 1325: * Check for errors on completion of an operation. ! 1326: */ ! 1327: char * ! 1328: hderrchk(um) ! 1329: struct bus_ctlr *um; ! 1330: { ! 1331: int status; ! 1332: ! 1333: status = inb(HD_STATUS(um->address)); ! 1334: if (status & ST_WRTFLT) ! 1335: return ("write fault"); ! 1336: if (status & ST_ERROR) { ! 1337: status = inb(HD_ERROR(um->address)); ! 1338: if (status & ERR_DAM) ! 1339: return ("data address mark not found"); ! 1340: if (status & ERR_TR0) ! 1341: return ("track 0 not found"); ! 1342: if (status & ERR_ID) ! 1343: return ("sector not found"); ! 1344: if (status & ERR_ECC) ! 1345: return ("uncorrectable ECC error"); ! 1346: if (status & ERR_BADBLK) ! 1347: return ("bad block detected"); ! 1348: if (status & ERR_ABORT) ! 1349: return ("command aborted"); ! 1350: return ("hard error"); ! 1351: } ! 1352: return (NULL); ! 1353: } ! 1354: ! 1355: /* ! 1356: * Print an error message. ! 1357: */ ! 1358: hderror(msg, ui) ! 1359: char *msg; ! 1360: struct bus_device *ui; ! 1361: { ! 1362: char *op; ! 1363: int prn_sn = 0; ! 1364: struct hdcsoftc *hdc = &hdcsoftc[ui->mi->unit]; ! 1365: ! 1366: switch (hdc->sc_state) { ! 1367: ! 1368: case SETPARAM: ! 1369: case SETPARAMDONE: ! 1370: op = "SETPARAM: "; ! 1371: break; ! 1372: ! 1373: case RESTORE: ! 1374: case RESTOREDONE: ! 1375: op = "RESTORE: "; ! 1376: break; ! 1377: ! 1378: case TRANSFER: ! 1379: case TRANSFERDONE: ! 1380: if (hdutab[ui->unit].b_actf->b_flags & B_READ) ! 1381: op = "READ: "; ! 1382: else ! 1383: op = "WRITE: "; ! 1384: prn_sn = 1; ! 1385: break; ! 1386: ! 1387: case IDENTIFY: ! 1388: case IDENTIFYDONE: ! 1389: op = "IDENTIFY: "; ! 1390: break; ! 1391: ! 1392: case SETMULTI: ! 1393: case SETMULTIDONE: ! 1394: op = "SETMULTI: "; ! 1395: break; ! 1396: ! 1397: default: ! 1398: op = ""; ! 1399: break; ! 1400: } ! 1401: printf("hd%d: %s%s", ui->unit, op, msg); ! 1402: if (prn_sn) { ! 1403: if (hdsoftc[ui->unit].sc_flags & HDF_LBA) ! 1404: printf(", bn %d", hdc->sc_cn); ! 1405: else ! 1406: printf(", cn %d tn %d sn %d", ! 1407: hdc->sc_cn, hdc->sc_tn, hdc->sc_sn + 1); ! 1408: } ! 1409: printf("\n"); ! 1410: } ! 1411: ! 1412: /* ! 1413: * Watchdog routine. ! 1414: * Check for any hung operations. ! 1415: */ ! 1416: void ! 1417: hdwatch() ! 1418: { ! 1419: int unit, s; ! 1420: ! 1421: timeout(hdwatch, 0, hz); ! 1422: s = splbio(); ! 1423: for (unit = 0; unit < NHDC; unit++) ! 1424: if (hdtab[unit].b_active ! 1425: && ++hdcsoftc[unit].sc_wticks >= OP_TIMEOUT) ! 1426: hdintr(unit); ! 1427: splx(s); ! 1428: } ! 1429: ! 1430: #endif /* NHD > 0 && !LINUX_DEV */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.