|
|
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: ! 16: #include <fd.h> ! 17: #if NFD > 0 ! 18: /* ! 19: * Floppy disk driver. ! 20: * ! 21: * Supports: ! 22: * 1 controller and 2 drives. ! 23: * Media change and automatic media detection. ! 24: * Arbitrarily sized read/write requests. ! 25: * Misaligned requests ! 26: * DMA above 16 Meg ! 27: * ! 28: * TODO: ! 29: * 1) Real probe routines for controller and drives. ! 30: * 2) Support for multiple controllers. The driver does ! 31: * not assume a single controller since all functions ! 32: * take the controller and/or device structure as an ! 33: * argument, however the probe routines limit the ! 34: * number of controllers and drives to 1 and 2 respectively. ! 35: * 3) V_VERIFY ioctl. ! 36: * 4) User defined diskette parameters. ! 37: * 5) Detect Intel 82077 or compatible and use its FIFO mode. ! 38: * ! 39: * Shantanu Goel ([email protected]) ! 40: */ ! 41: #include <sys/types.h> ! 42: #include <sys/ioctl.h> ! 43: #include "vm_param.h" ! 44: #include <kern/time_out.h> ! 45: #include <vm/pmap.h> ! 46: #include <device/param.h> ! 47: #include <device/buf.h> ! 48: #include <device/errno.h> ! 49: #include <chips/busses.h> ! 50: #include <i386/machspl.h> ! 51: #include <i386/pio.h> ! 52: #include <i386at/cram.h> ! 53: #include <i386at/disk.h> ! 54: #include <i386at/nfdreg.h> ! 55: ! 56: /* ! 57: * Number of drives supported by an FDC. ! 58: * The controller is actually capable of ! 59: * supporting 4 drives, however, most (all?) ! 60: * board implementations only support 2. ! 61: */ ! 62: #define NDRIVES_PER_FDC 2 ! 63: #define NFDC ((NFD + NDRIVES_PER_FDC - 1) / NDRIVES_PER_FDC) ! 64: ! 65: #define fdunit(dev) (((int)(dev) >> 6) & 3) ! 66: #define fdmedia(dev) ((int)(dev) & 3) ! 67: ! 68: #define b_cylin b_resid ! 69: #define B_FORMAT B_MD1 ! 70: ! 71: #define SECSIZE 512 ! 72: ! 73: #define DMABSIZE (18*1024) /* size of DMA bounce buffer */ ! 74: ! 75: #define OP_TIMEOUT 5 /* time to wait (secs) for an ! 76: operation before giving up */ ! 77: #define MOTOR_TIMEOUT 5 /* time to wait (secs) before turning ! 78: off an idle drive motor */ ! 79: #define MAX_RETRIES 48 /* number of times to try ! 80: an I/O operation */ ! 81: ! 82: #define SRTHUT 0xdf /* step rate/head unload time */ ! 83: #define HLTND 0x02 /* head load time/dma mode */ ! 84: ! 85: /* ! 86: * DMA controller. ! 87: * ! 88: * XXX: There should be a generic <i386/dma.h> file. ! 89: */ ! 90: ! 91: /* ! 92: * Ports ! 93: */ ! 94: #define DMA2_PAGE 0x81 /* channel 2, page register */ ! 95: #define DMA2_ADDR 0x04 /* channel 2, addr register */ ! 96: #define DMA2_COUNT 0x05 /* channel 2, count register */ ! 97: #define DMA_STATUS 0x08 /* status register */ ! 98: #define DMA_COMMAND 0x08 /* command register */ ! 99: #define DMA_WREQ 0x09 /* request register */ ! 100: #define DMA_SINGLEMSK 0x0a /* single mask register */ ! 101: #define DMA_MODE 0x0b /* mode register */ ! 102: #define DMA_FLIPFLOP 0x0c /* pointer flip/flop */ ! 103: #define DMA_TEMP 0x0d /* temporary register */ ! 104: #define DMA_MASTERCLR 0x0d /* master clear */ ! 105: #define DMA_CLRMASK 0x0e /* clear mask register */ ! 106: #define DMA_ALLMASK 0x0f /* all mask register */ ! 107: ! 108: /* ! 109: * Commands ! 110: */ ! 111: #define DMA_WRITE 0x46 /* write on channel 2 */ ! 112: #define DMA_READ 0x4a /* read on channel 2 */ ! 113: ! 114: /* ! 115: * Autoconfiguration stuff. ! 116: */ ! 117: struct bus_ctlr *fdminfo[NFDC]; ! 118: struct bus_device *fddinfo[NFD]; ! 119: int fdstd[] = { 0 }; ! 120: int fdprobe(), fdslave(), fdintr(); ! 121: void fdattach(); ! 122: struct bus_driver fddriver = { ! 123: fdprobe, fdslave, fdattach, 0, fdstd, "fd", fddinfo, "fdc", fdminfo ! 124: }; ! 125: ! 126: /* ! 127: * Per-controller state. ! 128: */ ! 129: struct fdcsoftc { ! 130: int sc_flags; ! 131: #define FDF_WANT 0x01 /* someone needs direct controller access */ ! 132: #define FDF_RESET 0x02 /* controller needs reset */ ! 133: #define FDF_LIMIT 0x04 /* limit transfer to a single sector */ ! 134: #define FDF_BOUNCE 0x08 /* using bounce buffer */ ! 135: int sc_state; /* transfer fsm */ ! 136: caddr_t sc_addr; /* buffer address */ ! 137: int sc_resid; /* amount left to transfer */ ! 138: int sc_amt; /* amount currently being transferred */ ! 139: int sc_op; /* operation being performed */ ! 140: int sc_mode; /* DMA mode */ ! 141: int sc_sn; /* sector number */ ! 142: int sc_tn; /* track number */ ! 143: int sc_cn; /* cylinder number */ ! 144: int sc_recalerr; /* # recalibration errors */ ! 145: int sc_seekerr; /* # seek errors */ ! 146: int sc_ioerr; /* # i/o errors */ ! 147: int sc_dor; /* copy of digital output register */ ! 148: int sc_rate; /* copy of transfer rate register */ ! 149: int sc_wticks; /* watchdog */ ! 150: u_int sc_buf; /* buffer for transfers > 16 Meg */ ! 151: u_char sc_cmd[9]; /* command buffer */ ! 152: u_char sc_results[7]; /* operation results */ ! 153: } fdcsoftc[NFDC]; ! 154: ! 155: #define sc_st0 sc_results[0] ! 156: #define sc_st3 sc_results[0] ! 157: #define sc_st1 sc_results[1] ! 158: #define sc_pcn sc_results[1] ! 159: #define sc_st2 sc_results[2] ! 160: #define sc_c sc_results[3] ! 161: #define sc_h sc_results[4] ! 162: #define sc_r sc_results[5] ! 163: #define sc_n sc_results[6] ! 164: ! 165: /* ! 166: * Transfer states. ! 167: */ ! 168: #define IDLE 0 /* controller is idle */ ! 169: #define RESET 1 /* reset controller */ ! 170: #define RESETDONE 2 /* reset completion interrupt */ ! 171: #define RECAL 3 /* recalibrate drive */ ! 172: #define RECALDONE 4 /* recalibration complete interrupt */ ! 173: #define SEEK 5 /* perform seek on drive */ ! 174: #define SEEKDONE 6 /* seek completion interrupt */ ! 175: #define TRANSFER 7 /* perform transfer on drive */ ! 176: #define TRANSFERDONE 8 /* transfer completion interrupt */ ! 177: ! 178: /* ! 179: * Per-drive state. ! 180: */ ! 181: struct fdsoftc { ! 182: int sc_flags; ! 183: #define FDF_RECAL 0x02 /* drive needs recalibration */ ! 184: #define FDF_SEEK 0x04 /* force seek during auto-detection */ ! 185: #define FDF_AUTO 0x08 /* performing auto-density */ ! 186: #define FDF_AUTOFORCE 0x10 /* force auto-density */ ! 187: #define FDF_INIT 0x20 /* drive is being initialized */ ! 188: int sc_type; /* drive type */ ! 189: struct fddk *sc_dk; /* diskette type */ ! 190: int sc_cyl; /* current head position */ ! 191: int sc_mticks; /* motor timeout */ ! 192: } fdsoftc[NFD]; ! 193: ! 194: struct buf fdtab[NFDC]; /* controller queues */ ! 195: struct buf fdutab[NFD]; /* drive queues */ ! 196: ! 197: /* ! 198: * Floppy drive type names. ! 199: */ ! 200: char *fdnames[] = { "360K", "1.2 Meg", "720K", "1.44 Meg" }; ! 201: #define NTYPES (sizeof(fdnames) / sizeof(fdnames[0])) ! 202: ! 203: /* ! 204: * Floppy diskette parameters. ! 205: */ ! 206: struct fddk { ! 207: int dk_nspu; /* sectors/unit */ ! 208: int dk_nspc; /* sectors/cylinder */ ! 209: int dk_ncyl; /* cylinders/unit */ ! 210: int dk_nspt; /* sectors/track */ ! 211: int dk_step; /* !=0 means double track steps */ ! 212: int dk_gap; /* read/write gap length */ ! 213: int dk_fgap; /* format gap length */ ! 214: int dk_rate; /* transfer rate */ ! 215: int dk_drives; /* bit mask of drives that accept diskette */ ! 216: char *dk_name; /* type name */ ! 217: } fddk[] = { ! 218: /* ! 219: * NOTE: largest density for each drive type must be first so ! 220: * fdauto() tries it before any lower ones. ! 221: */ ! 222: { 2880, 36, 80, 18, 0, 0x1b, 0x6c, 0x00, 0x08, "1.44 Meg" }, ! 223: { 2400, 30, 80, 15, 0, 0x1b, 0x54, 0x00, 0x02, "1.2 Meg" }, ! 224: { 1440, 18, 80, 9, 0, 0x2a, 0x50, 0x02, 0x0c, "720K" }, ! 225: { 720, 18, 40, 9, 1, 0x23, 0x50, 0x01, 0x02, "360K" }, ! 226: { 720, 18, 40, 9, 0, 0x2a, 0x50, 0x02, 0x01, "360K PC" } ! 227: }; ! 228: #define NDKTYPES (sizeof(fddk) / sizeof(fddk[0])) ! 229: ! 230: /* ! 231: * For compatibility with old driver. ! 232: * This array is indexed by the old floppy type codes ! 233: * and points to the corresponding entry for that ! 234: * type in fddk[] above. ! 235: */ ! 236: struct fddk *fdcompat[NDKTYPES]; ! 237: ! 238: int fdwstart = 0; ! 239: int fdstrategy(), fdformat(); ! 240: char *fderrmsg(); ! 241: void fdwatch(), fdminphys(), fdspinup(), wakeup(); ! 242: ! 243: #define FDDEBUG ! 244: #ifdef FDDEBUG ! 245: int fddebug = 0; ! 246: #define DEBUGF(n, stmt) { if (fddebug >= (n)) stmt; } ! 247: #else ! 248: #define DEBUGF(n, stmt) ! 249: #endif ! 250: ! 251: /* ! 252: * Probe for a controller. ! 253: */ ! 254: int ! 255: fdprobe(xxx, um) ! 256: int xxx; ! 257: struct bus_ctlr *um; ! 258: { ! 259: struct fdcsoftc *fdc; ! 260: ! 261: if (um->unit >= NFDC) { ! 262: printf("fdc%d: not configured\n", um->unit); ! 263: return (0); ! 264: } ! 265: if (um->unit > 0) /* XXX: only 1 controller */ ! 266: return (0); ! 267: ! 268: /* ! 269: * XXX: need real probe ! 270: */ ! 271: take_ctlr_irq(um); ! 272: printf("%s%d: port 0x%x, spl %d, pic %d.\n", ! 273: um->name, um->unit, um->address, um->sysdep, um->sysdep1); ! 274: ! 275: /* ! 276: * Set up compatibility array. ! 277: */ ! 278: fdcompat[0] = &fddk[2]; ! 279: fdcompat[1] = &fddk[0]; ! 280: fdcompat[2] = &fddk[3]; ! 281: fdcompat[3] = &fddk[1]; ! 282: ! 283: fdc = &fdcsoftc[um->unit]; ! 284: fdc->sc_rate = -1; ! 285: if (!fdc->sc_buf) { ! 286: fdc->sc_buf = alloc_dma_mem(DMABSIZE, 64*1024); ! 287: if (fdc->sc_buf == 0) ! 288: panic("fd: alloc_dma_mem() failed"); ! 289: } ! 290: fdc->sc_dor = DOR_RSTCLR | DOR_IENABLE; ! 291: outb(FD_DOR(um->address), fdc->sc_dor); ! 292: return (1); ! 293: } ! 294: ! 295: /* ! 296: * Probe for a drive. ! 297: */ ! 298: int ! 299: fdslave(ui) ! 300: struct bus_device *ui; ! 301: { ! 302: struct fdsoftc *sc; ! 303: ! 304: if (ui->unit >= NFD) { ! 305: printf("fd%d: not configured\n", ui->unit); ! 306: return (0); ! 307: } ! 308: if (ui->unit > 1) /* XXX: only 2 drives */ ! 309: return (0); ! 310: ! 311: /* ! 312: * Find out from CMOS if drive exists. ! 313: */ ! 314: sc = &fdsoftc[ui->unit]; ! 315: outb(CMOS_ADDR, 0x10); ! 316: sc->sc_type = inb(CMOS_DATA); ! 317: if (ui->unit == 0) ! 318: sc->sc_type >>= 4; ! 319: sc->sc_type &= 0x0f; ! 320: return (sc->sc_type); ! 321: } ! 322: ! 323: /* ! 324: * Attach a drive to the system. ! 325: */ ! 326: void ! 327: fdattach(ui) ! 328: struct bus_device *ui; ! 329: { ! 330: struct fdsoftc *sc; ! 331: ! 332: sc = &fdsoftc[ui->unit]; ! 333: if (--sc->sc_type >= NTYPES) { ! 334: printf(": unknown drive type %d", sc->sc_type); ! 335: ui->alive = 0; ! 336: return; ! 337: } ! 338: printf(": %s", fdnames[sc->sc_type]); ! 339: sc->sc_flags = FDF_RECAL | FDF_SEEK | FDF_AUTOFORCE; ! 340: } ! 341: ! 342: int ! 343: fdopen(dev, mode) ! 344: dev_t dev; ! 345: int mode; ! 346: { ! 347: int unit = fdunit(dev), error; ! 348: struct bus_device *ui; ! 349: struct fdsoftc *sc; ! 350: ! 351: if (unit >= NFD || (ui = fddinfo[unit]) == 0 || ui->alive == 0) ! 352: return (ENXIO); ! 353: ! 354: /* ! 355: * Start watchdog. ! 356: */ ! 357: if (!fdwstart) { ! 358: fdwstart++; ! 359: timeout(fdwatch, 0, hz); ! 360: } ! 361: /* ! 362: * Do media detection if drive is being opened for the ! 363: * first time or diskette has been changed since the last open. ! 364: */ ! 365: sc = &fdsoftc[unit]; ! 366: if ((sc->sc_flags & FDF_AUTOFORCE) || fddskchg(ui)) { ! 367: if (error = fdauto(dev)) ! 368: return (error); ! 369: sc->sc_flags &= ~FDF_AUTOFORCE; ! 370: } ! 371: return (0); ! 372: } ! 373: ! 374: int ! 375: fdclose(dev) ! 376: dev_t dev; ! 377: { ! 378: int s, unit = fdunit(dev); ! 379: struct fdsoftc *sc = &fdsoftc[unit]; ! 380: ! 381: /* ! 382: * Wait for pending operations to complete. ! 383: */ ! 384: s = splbio(); ! 385: while (fdutab[unit].b_active) { ! 386: sc->sc_flags |= FDF_WANT; ! 387: assert_wait((event_t)sc, FALSE); ! 388: thread_block((void (*)())0); ! 389: } ! 390: splx(s); ! 391: return (0); ! 392: } ! 393: ! 394: int ! 395: fdread(dev, ior) ! 396: dev_t dev; ! 397: io_req_t ior; ! 398: { ! 399: return (block_io(fdstrategy, fdminphys, ior)); ! 400: } ! 401: ! 402: int ! 403: fdwrite(dev, ior) ! 404: dev_t dev; ! 405: io_req_t ior; ! 406: { ! 407: return (block_io(fdstrategy, fdminphys, ior)); ! 408: } ! 409: ! 410: int ! 411: fdgetstat(dev, flavor, status, status_count) ! 412: dev_t dev; ! 413: dev_flavor_t flavor; ! 414: dev_status_t status; ! 415: mach_msg_type_number_t *status_count; ! 416: { ! 417: switch (flavor) { ! 418: ! 419: case DEV_GET_SIZE: ! 420: { ! 421: int *info; ! 422: io_return_t error; ! 423: struct disk_parms dp; ! 424: ! 425: if (error = fdgetparms(dev, &dp)) ! 426: return (error); ! 427: info = (int *)status; ! 428: info[DEV_GET_SIZE_DEVICE_SIZE] = dp.dp_pnumsec * SECSIZE; ! 429: info[DEV_GET_SIZE_RECORD_SIZE] = SECSIZE; ! 430: *status_count = DEV_GET_SIZE_COUNT; ! 431: return (D_SUCCESS); ! 432: } ! 433: case V_GETPARMS: ! 434: if (*status_count < (sizeof(struct disk_parms) / sizeof(int))) ! 435: return (D_INVALID_OPERATION); ! 436: *status_count = sizeof(struct disk_parms) / sizeof(int); ! 437: return (fdgetparms(dev, (struct disk_parms *)status)); ! 438: ! 439: default: ! 440: return (D_INVALID_OPERATION); ! 441: } ! 442: } ! 443: ! 444: int ! 445: fdsetstat(dev, flavor, status, status_count) ! 446: dev_t dev; ! 447: dev_flavor_t flavor; ! 448: dev_status_t status; ! 449: mach_msg_type_number_t status_count; ! 450: { ! 451: switch (flavor) { ! 452: ! 453: case V_SETPARMS: ! 454: return (fdsetparms(dev, *(int *)status)); ! 455: ! 456: case V_FORMAT: ! 457: return (fdformat(dev, (union io_arg *)status)); ! 458: ! 459: case V_VERIFY: ! 460: /* ! 461: * XXX: needs to be implemented ! 462: */ ! 463: return (D_SUCCESS); ! 464: ! 465: default: ! 466: return (D_INVALID_OPERATION); ! 467: } ! 468: } ! 469: ! 470: int ! 471: fddevinfo(dev, flavor, info) ! 472: dev_t dev; ! 473: int flavor; ! 474: char *info; ! 475: { ! 476: switch (flavor) { ! 477: ! 478: case D_INFO_BLOCK_SIZE: ! 479: *(int *)info = SECSIZE; ! 480: return (D_SUCCESS); ! 481: ! 482: default: ! 483: return (D_INVALID_OPERATION); ! 484: } ! 485: } ! 486: ! 487: /* ! 488: * Allow arbitrary transfers. Standard minphys restricts ! 489: * transfers to a maximum of 256K preventing us from reading ! 490: * an entire diskette in a single system call. ! 491: */ ! 492: void ! 493: fdminphys(ior) ! 494: io_req_t ior; ! 495: { ! 496: } ! 497: ! 498: /* ! 499: * Return current media parameters. ! 500: */ ! 501: int ! 502: fdgetparms(dev, dp) ! 503: dev_t dev; ! 504: struct disk_parms *dp; ! 505: { ! 506: struct fddk *dk = fdsoftc[fdunit(dev)].sc_dk; ! 507: ! 508: dp->dp_type = DPT_FLOPPY; ! 509: dp->dp_heads = 2; ! 510: dp->dp_sectors = dk->dk_nspt; ! 511: dp->dp_pstartsec = 0; ! 512: dp->dp_cyls = dk->dk_ncyl; ! 513: dp->dp_pnumsec = dk->dk_nspu; ! 514: return (0); ! 515: } ! 516: ! 517: /* ! 518: * Set media parameters. ! 519: */ ! 520: int ! 521: fdsetparms(dev, type) ! 522: dev_t dev; ! 523: int type; ! 524: { ! 525: struct fdsoftc *sc; ! 526: struct fddk *dk; ! 527: ! 528: if (type < 0 || type >= NDKTYPES) ! 529: return (EINVAL); ! 530: dk = fdcompat[type]; ! 531: sc = &fdsoftc[fdunit(dev)]; ! 532: if ((dk->dk_drives & (1 << sc->sc_type)) == 0) ! 533: return (EINVAL); ! 534: sc->sc_dk = dk; ! 535: return (D_SUCCESS); ! 536: } ! 537: ! 538: /* ! 539: * Format a floppy. ! 540: */ ! 541: int ! 542: fdformat(dev, arg) ! 543: dev_t dev; ! 544: union io_arg *arg; ! 545: { ! 546: int i, j, sect, error = 0; ! 547: unsigned track, num_trks; ! 548: struct buf *bp; ! 549: struct fddk *dk; ! 550: struct format_info *fmt; ! 551: ! 552: dk = fdsoftc[fdunit(dev)].sc_dk; ! 553: num_trks = arg->ia_fmt.num_trks; ! 554: track = arg->ia_fmt.start_trk; ! 555: if (num_trks == 0 || track + num_trks > (dk->dk_ncyl << 1) ! 556: || arg->ia_fmt.intlv >= dk->dk_nspt) ! 557: return (EINVAL); ! 558: ! 559: bp = (struct buf *)geteblk(SECSIZE); ! 560: bp->b_dev = dev; ! 561: bp->b_bcount = dk->dk_nspt * sizeof(struct format_info); ! 562: bp->b_blkno = track * dk->dk_nspt; ! 563: ! 564: while (num_trks-- > 0) { ! 565: /* ! 566: * Set up format information. ! 567: */ ! 568: fmt = (struct format_info *)bp->b_un.b_addr; ! 569: for (i = 0; i < dk->dk_nspt; i++) ! 570: fmt[i].sector = 0; ! 571: for (i = 0, j = 0, sect = 1; i < dk->dk_nspt; i++) { ! 572: fmt[j].cyl = track >> 1; ! 573: fmt[j].head = track & 1; ! 574: fmt[j].sector = sect++; ! 575: fmt[j].secsize = 2; ! 576: if ((j += arg->ia_fmt.intlv) < dk->dk_nspt) ! 577: continue; ! 578: for (j -= dk->dk_nspt; j < dk->dk_nspt; j++) ! 579: if (fmt[j].sector == 0) ! 580: break; ! 581: } ! 582: bp->b_flags = B_FORMAT; ! 583: fdstrategy(bp); ! 584: biowait(bp); ! 585: if (bp->b_flags & B_ERROR) { ! 586: error = bp->b_error; ! 587: break; ! 588: } ! 589: bp->b_blkno += dk->dk_nspt; ! 590: track++; ! 591: } ! 592: bp->b_flags &= ~B_FORMAT; ! 593: brelse(bp); ! 594: return (error); ! 595: } ! 596: ! 597: /* ! 598: * Strategy routine. ! 599: * Enqueue a request on drive queue. ! 600: */ ! 601: int ! 602: fdstrategy(bp) ! 603: struct buf *bp; ! 604: { ! 605: int unit = fdunit(bp->b_dev), s; ! 606: int bn, sz, maxsz; ! 607: struct buf *dp; ! 608: struct bus_device *ui = fddinfo[unit]; ! 609: struct fddk *dk = fdsoftc[unit].sc_dk; ! 610: ! 611: bn = bp->b_blkno; ! 612: sz = (bp->b_bcount + SECSIZE - 1) / SECSIZE; ! 613: maxsz = dk->dk_nspu; ! 614: if (bn < 0 || bn + sz > maxsz) { ! 615: if (bn == maxsz) { ! 616: bp->b_resid = bp->b_bcount; ! 617: goto done; ! 618: } ! 619: sz = maxsz - bn; ! 620: if (sz <= 0) { ! 621: bp->b_error = EINVAL; ! 622: bp->b_flags |= B_ERROR; ! 623: goto done; ! 624: } ! 625: bp->b_bcount = sz * SECSIZE; ! 626: } ! 627: bp->b_cylin = bn / dk->dk_nspc; ! 628: dp = &fdutab[unit]; ! 629: s = splbio(); ! 630: disksort(dp, bp); ! 631: if (!dp->b_active) { ! 632: fdustart(ui); ! 633: if (!fdtab[ui->mi->unit].b_active) ! 634: fdstart(ui->mi); ! 635: } ! 636: splx(s); ! 637: return; ! 638: done: ! 639: biodone(bp); ! 640: return; ! 641: } ! 642: ! 643: /* ! 644: * Unit start routine. ! 645: * Move request from drive to controller queue. ! 646: */ ! 647: int ! 648: fdustart(ui) ! 649: struct bus_device *ui; ! 650: { ! 651: struct buf *bp; ! 652: struct buf *dp; ! 653: ! 654: bp = &fdutab[ui->unit]; ! 655: if (bp->b_actf == 0) ! 656: return; ! 657: dp = &fdtab[ui->mi->unit]; ! 658: if (dp->b_actf == 0) ! 659: dp->b_actf = bp; ! 660: else ! 661: dp->b_actl->b_forw = bp; ! 662: bp->b_forw = 0; ! 663: dp->b_actl = bp; ! 664: bp->b_active++; ! 665: } ! 666: ! 667: /* ! 668: * Start output on controller. ! 669: */ ! 670: int ! 671: fdstart(um) ! 672: struct bus_ctlr *um; ! 673: { ! 674: struct buf *bp; ! 675: struct buf *dp; ! 676: struct fdsoftc *sc; ! 677: struct fdcsoftc *fdc; ! 678: struct bus_device *ui; ! 679: struct fddk *dk; ! 680: ! 681: /* ! 682: * Pull a request from the controller queue. ! 683: */ ! 684: dp = &fdtab[um->unit]; ! 685: if ((bp = dp->b_actf) == 0) ! 686: return; ! 687: bp = bp->b_actf; ! 688: ! 689: fdc = &fdcsoftc[um->unit]; ! 690: ui = fddinfo[fdunit(bp->b_dev)]; ! 691: sc = &fdsoftc[ui->unit]; ! 692: dk = sc->sc_dk; ! 693: ! 694: /* ! 695: * Mark controller busy. ! 696: */ ! 697: dp->b_active++; ! 698: ! 699: /* ! 700: * Figure out where this request is going. ! 701: */ ! 702: fdc->sc_cn = bp->b_cylin; ! 703: fdc->sc_sn = bp->b_blkno % dk->dk_nspc; ! 704: fdc->sc_tn = fdc->sc_sn / dk->dk_nspt; ! 705: fdc->sc_sn %= dk->dk_nspt; ! 706: ! 707: /* ! 708: * Set up for multi-sector transfer. ! 709: */ ! 710: fdc->sc_op = ((bp->b_flags & B_FORMAT) ? CMD_FORMAT ! 711: : ((bp->b_flags & B_READ) ? CMD_READ : CMD_WRITE)); ! 712: fdc->sc_mode = (bp->b_flags & B_READ) ? DMA_WRITE : DMA_READ; ! 713: fdc->sc_addr = bp->b_un.b_addr; ! 714: fdc->sc_resid = bp->b_bcount; ! 715: fdc->sc_wticks = 0; ! 716: fdc->sc_recalerr = 0; ! 717: fdc->sc_seekerr = 0; ! 718: fdc->sc_ioerr = 0; ! 719: ! 720: /* ! 721: * Set initial transfer state. ! 722: */ ! 723: if (fdc->sc_flags & FDF_RESET) ! 724: fdc->sc_state = RESET; ! 725: else if (sc->sc_flags & FDF_RECAL) ! 726: fdc->sc_state = RECAL; ! 727: else if (sc->sc_cyl != fdc->sc_cn) ! 728: fdc->sc_state = SEEK; ! 729: else ! 730: fdc->sc_state = TRANSFER; ! 731: ! 732: /* ! 733: * Set transfer rate. ! 734: */ ! 735: if (fdc->sc_rate != dk->dk_rate) { ! 736: fdc->sc_rate = dk->dk_rate; ! 737: outb(FD_RATE(um->address), fdc->sc_rate); ! 738: } ! 739: /* ! 740: * Turn on drive motor. ! 741: * Don't start I/O if drive is spinning up. ! 742: */ ! 743: if (fdmotoron(ui)) { ! 744: timeout(fdspinup, (void *)um, hz / 2); ! 745: return; ! 746: } ! 747: /* ! 748: * Call transfer state routine to do the actual I/O. ! 749: */ ! 750: fdstate(um); ! 751: } ! 752: ! 753: /* ! 754: * Interrupt routine. ! 755: */ ! 756: int ! 757: fdintr(ctlr) ! 758: int ctlr; ! 759: { ! 760: int timedout; ! 761: u_char results[7]; ! 762: struct buf *bp; ! 763: struct bus_device *ui; ! 764: struct fdsoftc *sc; ! 765: struct buf *dp = &fdtab[ctlr]; ! 766: struct fdcsoftc *fdc = &fdcsoftc[ctlr]; ! 767: struct bus_ctlr *um = fdminfo[ctlr]; ! 768: ! 769: if (!dp->b_active) { ! 770: printf("fdc%d: stray interrupt\n", ctlr); ! 771: return; ! 772: } ! 773: timedout = fdc->sc_wticks >= OP_TIMEOUT; ! 774: fdc->sc_wticks = 0; ! 775: bp = dp->b_actf->b_actf; ! 776: ui = fddinfo[fdunit(bp->b_dev)]; ! 777: sc = &fdsoftc[ui->unit]; ! 778: ! 779: /* ! 780: * Operation timed out, terminate request. ! 781: */ ! 782: if (timedout) { ! 783: fderror("timed out", ui); ! 784: fdmotoroff(ui); ! 785: sc->sc_flags |= FDF_RECAL; ! 786: bp->b_flags |= B_ERROR; ! 787: bp->b_error = ENXIO; ! 788: fddone(ui, bp); ! 789: return; ! 790: } ! 791: /* ! 792: * Read results from FDC. ! 793: * For transfer completion they can be read immediately. ! 794: * For anything else, we must issue a Sense Interrupt ! 795: * Status Command. We keep issuing this command till ! 796: * FDC returns invalid command status. The Controller Busy ! 797: * bit in the status register indicates completion of a ! 798: * read/write/format operation. ! 799: */ ! 800: if (inb(FD_STATUS(um->address)) & ST_CB) { ! 801: if (!fdresults(um, fdc->sc_results)) ! 802: return; ! 803: } else { ! 804: while (1) { ! 805: fdc->sc_cmd[0] = CMD_SENSEI; ! 806: if (!fdcmd(um, 1)) { ! 807: DEBUGF(2, printf(2, "fd%d: SENSEI failed\n")); ! 808: return; ! 809: } ! 810: if (!fdresults(um, results)) ! 811: return; ! 812: if ((results[0] & ST0_IC) == 0x80) ! 813: break; ! 814: if ((results[0] & ST0_US) == ui->slave) { ! 815: fdc->sc_results[0] = results[0]; ! 816: fdc->sc_results[1] = results[1]; ! 817: } ! 818: } ! 819: } ! 820: /* ! 821: * Let transfer state routine handle the rest. ! 822: */ ! 823: fdstate(um); ! 824: } ! 825: ! 826: /* ! 827: * Transfer finite state machine driver. ! 828: */ ! 829: int ! 830: fdstate(um) ! 831: struct bus_ctlr *um; ! 832: { ! 833: int unit, max, pa, s; ! 834: struct buf *bp; ! 835: struct fdsoftc *sc; ! 836: struct bus_device *ui; ! 837: struct fddk *dk; ! 838: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 839: ! 840: bp = fdtab[um->unit].b_actf->b_actf; ! 841: ui = fddinfo[fdunit(bp->b_dev)]; ! 842: sc = &fdsoftc[ui->unit]; ! 843: dk = sc->sc_dk; ! 844: ! 845: while (1) switch (fdc->sc_state) { ! 846: ! 847: case RESET: ! 848: /* ! 849: * Reset the controller. ! 850: */ ! 851: fdreset(um); ! 852: return; ! 853: ! 854: case RESETDONE: ! 855: /* ! 856: * Reset complete. ! 857: * Mark all drives as needing recalibration ! 858: * and issue specify command. ! 859: */ ! 860: for (unit = 0; unit < NFD; unit++) ! 861: if (fddinfo[unit] && fddinfo[unit]->alive ! 862: && fddinfo[unit]->mi == um) ! 863: fdsoftc[unit].sc_flags |= FDF_RECAL; ! 864: fdc->sc_cmd[0] = CMD_SPECIFY; ! 865: fdc->sc_cmd[1] = SRTHUT; ! 866: fdc->sc_cmd[2] = HLTND; ! 867: if (!fdcmd(um, 3)) ! 868: return; ! 869: fdc->sc_flags &= ~FDF_RESET; ! 870: fdc->sc_state = RECAL; ! 871: break; ! 872: ! 873: case RECAL: ! 874: /* ! 875: * Recalibrate drive. ! 876: */ ! 877: fdc->sc_state = RECALDONE; ! 878: fdc->sc_cmd[0] = CMD_RECAL; ! 879: fdc->sc_cmd[1] = ui->slave; ! 880: fdcmd(um, 2); ! 881: return; ! 882: ! 883: case RECALDONE: ! 884: /* ! 885: * Recalibration complete. ! 886: */ ! 887: if ((fdc->sc_st0 & ST0_IC) || (fdc->sc_st0 & ST0_EC)) { ! 888: if (++fdc->sc_recalerr == 2) { ! 889: fderror("recalibrate failed", ui); ! 890: goto bad; ! 891: } ! 892: fdc->sc_state = RESET; ! 893: break; ! 894: } ! 895: sc->sc_flags &= ~FDF_RECAL; ! 896: fdc->sc_recalerr = 0; ! 897: sc->sc_cyl = -1; ! 898: fdc->sc_state = SEEK; ! 899: break; ! 900: ! 901: case SEEK: ! 902: /* ! 903: * Perform seek operation. ! 904: */ ! 905: fdc->sc_state = SEEKDONE; ! 906: fdc->sc_cmd[0] = CMD_SEEK; ! 907: fdc->sc_cmd[1] = (fdc->sc_tn << 2) | ui->slave; ! 908: fdc->sc_cmd[2] = fdc->sc_cn; ! 909: if (dk->dk_step) ! 910: fdc->sc_cmd[2] <<= 1; ! 911: fdcmd(um, 3); ! 912: return; ! 913: ! 914: case SEEKDONE: ! 915: /* ! 916: * Seek complete. ! 917: */ ! 918: if (dk->dk_step) ! 919: fdc->sc_pcn >>= 1; ! 920: if ((fdc->sc_st0 & ST0_IC) || (fdc->sc_st0 & ST0_SE) == 0 ! 921: || fdc->sc_pcn != fdc->sc_cn) { ! 922: if (++fdc->sc_seekerr == 2) { ! 923: fderror("seek failed", ui); ! 924: goto bad; ! 925: } ! 926: fdc->sc_state = RESET; ! 927: break; ! 928: } ! 929: fdc->sc_seekerr = 0; ! 930: sc->sc_cyl = fdc->sc_pcn; ! 931: fdc->sc_state = TRANSFER; ! 932: break; ! 933: ! 934: case TRANSFER: ! 935: /* ! 936: * Perform I/O transfer. ! 937: */ ! 938: fdc->sc_flags &= ~FDF_BOUNCE; ! 939: pa = pmap_extract(kernel_pmap, fdc->sc_addr); ! 940: if (fdc->sc_op == CMD_FORMAT) { ! 941: max = sizeof(struct format_info) * dk->dk_nspt; ! 942: } else if (fdc->sc_flags & FDF_LIMIT) { ! 943: fdc->sc_flags &= ~FDF_LIMIT; ! 944: max = SECSIZE; ! 945: } else { ! 946: max = (dk->dk_nspc - dk->dk_nspt * fdc->sc_tn ! 947: - fdc->sc_sn) * SECSIZE; ! 948: } ! 949: if (max > fdc->sc_resid) ! 950: max = fdc->sc_resid; ! 951: if (pa >= 16*1024*1024) { ! 952: fdc->sc_flags |= FDF_BOUNCE; ! 953: pa = fdc->sc_buf; ! 954: if (max < DMABSIZE) ! 955: fdc->sc_amt = max; ! 956: else ! 957: fdc->sc_amt = DMABSIZE; ! 958: } else { ! 959: int prevpa, curpa, omax; ! 960: vm_offset_t va; ! 961: ! 962: omax = max; ! 963: if (max > 65536 - (pa & 0xffff)) ! 964: max = 65536 - (pa & 0xffff); ! 965: fdc->sc_amt = I386_PGBYTES - (pa & (I386_PGBYTES - 1)); ! 966: va = (vm_offset_t)fdc->sc_addr + fdc->sc_amt; ! 967: prevpa = pa & ~(I386_PGBYTES - 1); ! 968: while (fdc->sc_amt < max) { ! 969: curpa = pmap_extract(kernel_pmap, va); ! 970: if (curpa >= 16*1024*1024 ! 971: || curpa != prevpa + I386_PGBYTES) ! 972: break; ! 973: fdc->sc_amt += I386_PGBYTES; ! 974: va += I386_PGBYTES; ! 975: prevpa = curpa; ! 976: } ! 977: if (fdc->sc_amt > max) ! 978: fdc->sc_amt = max; ! 979: if (fdc->sc_op == CMD_FORMAT) { ! 980: if (fdc->sc_amt != omax) { ! 981: fdc->sc_flags |= FDF_BOUNCE; ! 982: pa = fdc->sc_buf; ! 983: fdc->sc_amt = omax; ! 984: } ! 985: } else if (fdc->sc_amt != fdc->sc_resid) { ! 986: if (fdc->sc_amt < SECSIZE) { ! 987: fdc->sc_flags |= FDF_BOUNCE; ! 988: pa = fdc->sc_buf; ! 989: if (omax > DMABSIZE) ! 990: fdc->sc_amt = DMABSIZE; ! 991: else ! 992: fdc->sc_amt = omax; ! 993: } else ! 994: fdc->sc_amt &= ~(SECSIZE - 1); ! 995: } ! 996: } ! 997: ! 998: DEBUGF(2, printf("fd%d: TRANSFER: amt %d cn %d tn %d sn %d\n", ! 999: ui->unit, fdc->sc_amt, fdc->sc_cn, ! 1000: fdc->sc_tn, fdc->sc_sn + 1)); ! 1001: ! 1002: if ((fdc->sc_flags & FDF_BOUNCE) && fdc->sc_op != CMD_READ) { ! 1003: fdc->sc_flags &= ~FDF_BOUNCE; ! 1004: bcopy(fdc->sc_addr, (caddr_t)phystokv(fdc->sc_buf), ! 1005: fdc->sc_amt); ! 1006: } ! 1007: /* ! 1008: * Set up DMA. ! 1009: */ ! 1010: s = sploff(); ! 1011: outb(DMA_SINGLEMSK, 0x04 | 0x02); ! 1012: outb(DMA_FLIPFLOP, 0); ! 1013: outb(DMA_MODE, fdc->sc_mode); ! 1014: outb(DMA2_ADDR, pa); ! 1015: outb(DMA2_ADDR, pa >> 8); ! 1016: outb(DMA2_PAGE, pa >> 16); ! 1017: outb(DMA2_COUNT, fdc->sc_amt - 1); ! 1018: outb(DMA2_COUNT, (fdc->sc_amt - 1) >> 8); ! 1019: outb(DMA_SINGLEMSK, 0x02); ! 1020: splon(s); ! 1021: ! 1022: /* ! 1023: * Issue command to FDC. ! 1024: */ ! 1025: fdc->sc_state = TRANSFERDONE; ! 1026: fdc->sc_cmd[0] = fdc->sc_op; ! 1027: fdc->sc_cmd[1] = (fdc->sc_tn << 2) | ui->slave; ! 1028: if (fdc->sc_op == CMD_FORMAT) { ! 1029: fdc->sc_cmd[2] = 0x02; ! 1030: fdc->sc_cmd[3] = dk->dk_nspt; ! 1031: fdc->sc_cmd[4] = dk->dk_fgap; ! 1032: fdc->sc_cmd[5] = 0xda; ! 1033: fdcmd(um, 6); ! 1034: } else { ! 1035: fdc->sc_cmd[2] = fdc->sc_cn; ! 1036: fdc->sc_cmd[3] = fdc->sc_tn; ! 1037: fdc->sc_cmd[4] = fdc->sc_sn + 1; ! 1038: fdc->sc_cmd[5] = 0x02; ! 1039: fdc->sc_cmd[6] = dk->dk_nspt; ! 1040: fdc->sc_cmd[7] = dk->dk_gap; ! 1041: fdc->sc_cmd[8] = 0xff; ! 1042: fdcmd(um, 9); ! 1043: } ! 1044: return; ! 1045: ! 1046: case TRANSFERDONE: ! 1047: /* ! 1048: * Transfer complete. ! 1049: */ ! 1050: if (fdc->sc_st0 & ST0_IC) { ! 1051: fdc->sc_ioerr++; ! 1052: if (sc->sc_flags & FDF_AUTO) { ! 1053: /* ! 1054: * Give up on second try if ! 1055: * media detection is in progress. ! 1056: */ ! 1057: if (fdc->sc_ioerr == 2) ! 1058: goto bad; ! 1059: fdc->sc_state = RECAL; ! 1060: break; ! 1061: } ! 1062: if (fdc->sc_ioerr == MAX_RETRIES) { ! 1063: fderror(fderrmsg(ui), ui); ! 1064: goto bad; ! 1065: } ! 1066: /* ! 1067: * Give up immediately on write-protected diskettes. ! 1068: */ ! 1069: if (fdc->sc_st1 & ST1_NW) { ! 1070: fderror("write-protected diskette", ui); ! 1071: goto bad; ! 1072: } ! 1073: /* ! 1074: * Limit transfer to a single sector. ! 1075: */ ! 1076: fdc->sc_flags |= FDF_LIMIT; ! 1077: /* ! 1078: * Every fourth attempt recalibrate the drive. ! 1079: * Every eight attempt reset the controller. ! 1080: * Also, every eighth attempt inform user ! 1081: * about the error. ! 1082: */ ! 1083: if (fdc->sc_ioerr & 3) ! 1084: fdc->sc_state = TRANSFER; ! 1085: else if (fdc->sc_ioerr & 7) ! 1086: fdc->sc_state = RECAL; ! 1087: else { ! 1088: fdc->sc_state = RESET; ! 1089: fderror(fderrmsg(ui), ui); ! 1090: } ! 1091: break; ! 1092: } ! 1093: /* ! 1094: * Transfer completed successfully. ! 1095: * Advance counters/pointers, and if more ! 1096: * is left, initiate I/O. ! 1097: */ ! 1098: if (fdc->sc_flags & FDF_BOUNCE) { ! 1099: fdc->sc_flags &= ~FDF_BOUNCE; ! 1100: bcopy((caddr_t)phystokv(fdc->sc_buf), fdc->sc_addr, ! 1101: fdc->sc_amt); ! 1102: } ! 1103: if ((fdc->sc_resid -= fdc->sc_amt) == 0) { ! 1104: bp->b_resid = 0; ! 1105: fddone(ui, bp); ! 1106: return; ! 1107: } ! 1108: fdc->sc_state = TRANSFER; ! 1109: fdc->sc_ioerr = 0; ! 1110: fdc->sc_addr += fdc->sc_amt; ! 1111: if (fdc->sc_op == CMD_FORMAT) { ! 1112: fdc->sc_sn = 0; ! 1113: if (fdc->sc_tn == 1) { ! 1114: fdc->sc_tn = 0; ! 1115: fdc->sc_cn++; ! 1116: fdc->sc_state = SEEK; ! 1117: } else ! 1118: fdc->sc_tn = 1; ! 1119: } else { ! 1120: fdc->sc_sn += fdc->sc_amt / SECSIZE; ! 1121: while (fdc->sc_sn >= dk->dk_nspt) { ! 1122: fdc->sc_sn -= dk->dk_nspt; ! 1123: if (fdc->sc_tn == 1) { ! 1124: fdc->sc_tn = 0; ! 1125: fdc->sc_cn++; ! 1126: fdc->sc_state = SEEK; ! 1127: } else ! 1128: fdc->sc_tn = 1; ! 1129: } ! 1130: } ! 1131: break; ! 1132: ! 1133: default: ! 1134: printf("fd%d: invalid state\n", ui->unit); ! 1135: panic("fdstate"); ! 1136: /*NOTREACHED*/ ! 1137: } ! 1138: bad: ! 1139: bp->b_flags |= B_ERROR; ! 1140: bp->b_error = EIO; ! 1141: sc->sc_flags |= FDF_RECAL; ! 1142: fddone(ui, bp); ! 1143: } ! 1144: ! 1145: /* ! 1146: * Terminate current request and start ! 1147: * any others that are queued. ! 1148: */ ! 1149: int ! 1150: fddone(ui, bp) ! 1151: struct bus_device *ui; ! 1152: struct buf *bp; ! 1153: { ! 1154: struct bus_ctlr *um = ui->mi; ! 1155: struct fdsoftc *sc = &fdsoftc[ui->unit]; ! 1156: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 1157: struct buf *dp = &fdtab[um->unit]; ! 1158: ! 1159: DEBUGF(1, printf("fd%d: fddone()\n", ui->unit)); ! 1160: ! 1161: /* ! 1162: * Remove this request from queue. ! 1163: */ ! 1164: if (bp) { ! 1165: fdutab[ui->unit].b_actf = bp->b_actf; ! 1166: biodone(bp); ! 1167: bp = &fdutab[ui->unit]; ! 1168: dp->b_actf = bp->b_forw; ! 1169: } else ! 1170: bp = &fdutab[ui->unit]; ! 1171: ! 1172: /* ! 1173: * Mark controller and drive idle. ! 1174: */ ! 1175: dp->b_active = 0; ! 1176: bp->b_active = 0; ! 1177: fdc->sc_state = IDLE; ! 1178: sc->sc_mticks = 0; ! 1179: fdc->sc_flags &= ~(FDF_LIMIT|FDF_BOUNCE); ! 1180: ! 1181: /* ! 1182: * Start up other requests. ! 1183: */ ! 1184: fdustart(ui); ! 1185: fdstart(um); ! 1186: ! 1187: /* ! 1188: * Wakeup anyone waiting for drive or controller. ! 1189: */ ! 1190: if (sc->sc_flags & FDF_WANT) { ! 1191: sc->sc_flags &= ~FDF_WANT; ! 1192: wakeup((void *)sc); ! 1193: } ! 1194: if (fdc->sc_flags & FDF_WANT) { ! 1195: fdc->sc_flags &= ~FDF_WANT; ! 1196: wakeup((void *)fdc); ! 1197: } ! 1198: } ! 1199: ! 1200: /* ! 1201: * Check if diskette change has occured since the last open. ! 1202: */ ! 1203: int ! 1204: fddskchg(ui) ! 1205: struct bus_device *ui; ! 1206: { ! 1207: int s, dir; ! 1208: struct fdsoftc *sc = &fdsoftc[ui->unit]; ! 1209: struct bus_ctlr *um = ui->mi; ! 1210: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 1211: ! 1212: /* ! 1213: * Get access to controller. ! 1214: */ ! 1215: s = splbio(); ! 1216: while (fdtab[um->unit].b_active) { ! 1217: fdc->sc_flags |= FDF_WANT; ! 1218: assert_wait((event_t)fdc, FALSE); ! 1219: thread_block((void (*)())0); ! 1220: } ! 1221: fdtab[um->unit].b_active = 1; ! 1222: fdutab[ui->unit].b_active = 1; ! 1223: ! 1224: /* ! 1225: * Turn on drive motor and read digital input register. ! 1226: */ ! 1227: if (fdmotoron(ui)) { ! 1228: timeout(wakeup, (void *)fdc, hz / 2); ! 1229: assert_wait((event_t)fdc, FALSE); ! 1230: thread_block((void (*)())0); ! 1231: } ! 1232: dir = inb(FD_DIR(um->address)); ! 1233: fddone(ui, NULL); ! 1234: splx(s); ! 1235: ! 1236: if (dir & DIR_DSKCHG) { ! 1237: printf("fd%d: diskette change detected\n", ui->unit); ! 1238: sc->sc_flags |= FDF_SEEK; ! 1239: return (1); ! 1240: } ! 1241: return (0); ! 1242: } ! 1243: ! 1244: /* ! 1245: * Do media detection. ! 1246: */ ! 1247: int ! 1248: fdauto(dev) ! 1249: dev_t dev; ! 1250: { ! 1251: int i, error = 0; ! 1252: struct buf *bp; ! 1253: struct bus_device *ui = fddinfo[fdunit(dev)]; ! 1254: struct fdsoftc *sc = &fdsoftc[ui->unit]; ! 1255: struct fddk *dk, *def = 0; ! 1256: ! 1257: sc->sc_flags |= FDF_AUTO; ! 1258: bp = (struct buf *)geteblk(SECSIZE); ! 1259: for (i = 0, dk = fddk; i < NDKTYPES; i++, dk++) { ! 1260: if ((dk->dk_drives & (1 << sc->sc_type)) == 0) ! 1261: continue; ! 1262: if (def == 0) ! 1263: def = dk; ! 1264: sc->sc_dk = dk; ! 1265: bp->b_flags = B_READ; ! 1266: bp->b_dev = dev; ! 1267: bp->b_bcount = SECSIZE; ! 1268: if (sc->sc_flags & FDF_SEEK) { ! 1269: sc->sc_flags &= ~FDF_SEEK; ! 1270: bp->b_blkno = 100; ! 1271: } else ! 1272: bp->b_blkno = 0; ! 1273: fdstrategy(bp); ! 1274: biowait(bp); ! 1275: if ((bp->b_flags & B_ERROR) == 0 || bp->b_error == ENXIO) ! 1276: break; ! 1277: } ! 1278: if (i == NDKTYPES) { ! 1279: printf("fd%d: couldn't detect type, using %s\n", ! 1280: ui->unit, def->dk_name); ! 1281: sc->sc_dk = def; ! 1282: } else if ((bp->b_flags & B_ERROR) == 0) ! 1283: printf("fd%d: detected %s\n", ui->unit, sc->sc_dk->dk_name); ! 1284: else ! 1285: error = ENXIO; ! 1286: sc->sc_flags &= ~FDF_AUTO; ! 1287: brelse(bp); ! 1288: return (error); ! 1289: } ! 1290: ! 1291: /* ! 1292: * Turn on drive motor and select drive. ! 1293: */ ! 1294: int ! 1295: fdmotoron(ui) ! 1296: struct bus_device *ui; ! 1297: { ! 1298: int bit; ! 1299: struct bus_ctlr *um = ui->mi; ! 1300: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 1301: ! 1302: bit = 1 << (ui->slave + 4); ! 1303: if ((fdc->sc_dor & bit) == 0) { ! 1304: fdc->sc_dor &= ~3; ! 1305: fdc->sc_dor |= bit | ui->slave; ! 1306: outb(FD_DOR(um->address), fdc->sc_dor); ! 1307: return (1); ! 1308: } ! 1309: if ((fdc->sc_dor & 3) != ui->slave) { ! 1310: fdc->sc_dor &= ~3; ! 1311: fdc->sc_dor |= ui->slave; ! 1312: outb(FD_DOR(um->address), fdc->sc_dor); ! 1313: } ! 1314: return (0); ! 1315: } ! 1316: ! 1317: /* ! 1318: * Turn off drive motor. ! 1319: */ ! 1320: int ! 1321: fdmotoroff(ui) ! 1322: struct bus_device *ui; ! 1323: { ! 1324: struct bus_ctlr *um = ui->mi; ! 1325: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 1326: ! 1327: fdc->sc_dor &= ~(1 << (ui->slave + 4)); ! 1328: outb(FD_DOR(um->address), fdc->sc_dor); ! 1329: } ! 1330: ! 1331: /* ! 1332: * This routine is invoked via timeout() by fdstart() ! 1333: * to call fdstate() at splbio. ! 1334: */ ! 1335: void ! 1336: fdspinup(um) ! 1337: struct bus_ctlr *um; ! 1338: { ! 1339: int s; ! 1340: ! 1341: s = splbio(); ! 1342: fdstate(um); ! 1343: splx(s); ! 1344: } ! 1345: ! 1346: /* ! 1347: * Watchdog routine. ! 1348: * Check for hung operations. ! 1349: * Turn off motor of idle drives. ! 1350: */ ! 1351: void ! 1352: fdwatch() ! 1353: { ! 1354: int unit, s; ! 1355: struct bus_device *ui; ! 1356: ! 1357: timeout(fdwatch, 0, hz); ! 1358: s = splbio(); ! 1359: for (unit = 0; unit < NFDC; unit++) ! 1360: if (fdtab[unit].b_active ! 1361: && ++fdcsoftc[unit].sc_wticks == OP_TIMEOUT) ! 1362: fdintr(unit); ! 1363: for (unit = 0; unit < NFD; unit++) { ! 1364: if ((ui = fddinfo[unit]) == 0 || ui->alive == 0) ! 1365: continue; ! 1366: if (fdutab[unit].b_active == 0 ! 1367: && (fdcsoftc[ui->mi->unit].sc_dor & (1 << (ui->slave + 4))) ! 1368: && ++fdsoftc[unit].sc_mticks == MOTOR_TIMEOUT) ! 1369: fdmotoroff(ui); ! 1370: } ! 1371: splx(s); ! 1372: } ! 1373: ! 1374: /* ! 1375: * Print an error message. ! 1376: */ ! 1377: int ! 1378: fderror(msg, ui) ! 1379: char *msg; ! 1380: struct bus_device *ui; ! 1381: { ! 1382: struct fdcsoftc *fdc = &fdcsoftc[ui->mi->unit]; ! 1383: ! 1384: printf("fd%d: %s, %sing cn %d tn %d sn %d\n", ui->unit, msg, ! 1385: (fdc->sc_op == CMD_READ ? "read" ! 1386: : (fdc->sc_op == CMD_WRITE ? "writ" : "formatt")), ! 1387: fdc->sc_cn, fdc->sc_tn, fdc->sc_sn + 1); ! 1388: } ! 1389: ! 1390: /* ! 1391: * Return an error message for an I/O error. ! 1392: */ ! 1393: char * ! 1394: fderrmsg(ui) ! 1395: struct bus_device *ui; ! 1396: { ! 1397: struct fdcsoftc *fdc = &fdcsoftc[ui->mi->unit]; ! 1398: ! 1399: if (fdc->sc_st1 & ST1_EC) ! 1400: return ("invalid sector"); ! 1401: if (fdc->sc_st1 & ST1_DE) ! 1402: return ("CRC error"); ! 1403: if (fdc->sc_st1 & ST1_OR) ! 1404: return ("DMA overrun"); ! 1405: if (fdc->sc_st1 & ST1_ND) ! 1406: return ("sector not found"); ! 1407: if (fdc->sc_st1 & ST1_NW) ! 1408: return ("write-protected diskette"); ! 1409: if (fdc->sc_st1 & ST1_MA) ! 1410: return ("missing address mark"); ! 1411: return ("hard error"); ! 1412: } ! 1413: ! 1414: /* ! 1415: * Output a command to FDC. ! 1416: */ ! 1417: int ! 1418: fdcmd(um, n) ! 1419: struct bus_ctlr *um; ! 1420: int n; ! 1421: { ! 1422: int i, j; ! 1423: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 1424: ! 1425: for (i = j = 0; i < 200; i++) { ! 1426: if ((inb(FD_STATUS(um->address)) & (ST_RQM|ST_DIO)) != ST_RQM) ! 1427: continue; ! 1428: outb(FD_DATA(um->address), fdc->sc_cmd[j++]); ! 1429: if (--n == 0) ! 1430: return (1); ! 1431: } ! 1432: /* ! 1433: * Controller is not responding, reset it. ! 1434: */ ! 1435: DEBUGF(1, printf("fdc%d: fdcmd() failed\n", um->unit)); ! 1436: fdreset(um); ! 1437: return (0); ! 1438: } ! 1439: ! 1440: /* ! 1441: * Read results from FDC. ! 1442: */ ! 1443: int ! 1444: fdresults(um, rp) ! 1445: struct bus_ctlr *um; ! 1446: u_char *rp; ! 1447: { ! 1448: int i, j, status; ! 1449: ! 1450: for (i = j = 0; i < 200; i++) { ! 1451: status = inb(FD_STATUS(um->address)); ! 1452: if ((status & ST_RQM) == 0) ! 1453: continue; ! 1454: if ((status & ST_DIO) == 0) ! 1455: return (j); ! 1456: if (j == 7) ! 1457: break; ! 1458: *rp++ = inb(FD_DATA(um->address)); ! 1459: j++; ! 1460: } ! 1461: /* ! 1462: * Controller is not responding, reset it. ! 1463: */ ! 1464: DEBUGF(1, printf("fdc%d: fdresults() failed\n", um->unit)); ! 1465: fdreset(um); ! 1466: return (0); ! 1467: } ! 1468: ! 1469: /* ! 1470: * Reset controller. ! 1471: */ ! 1472: int ! 1473: fdreset(um) ! 1474: struct bus_ctlr *um; ! 1475: { ! 1476: struct fdcsoftc *fdc = &fdcsoftc[um->unit]; ! 1477: ! 1478: outb(FD_DOR(um->address), fdc->sc_dor & ~(DOR_RSTCLR|DOR_IENABLE)); ! 1479: fdc->sc_state = RESETDONE; ! 1480: fdc->sc_flags |= FDF_RESET; ! 1481: outb(FD_DOR(um->address), fdc->sc_dor); ! 1482: } ! 1483: ! 1484: #endif /* NFD > 0 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.