|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "io.h" ! 7: #include "../port/error.h" ! 8: ! 9: /* Intel 82077A (8272A compatible) floppy controller */ ! 10: ! 11: typedef struct Drive Drive; ! 12: typedef struct Controller Controller; ! 13: typedef struct Type Type; ! 14: typedef struct Device Device; ! 15: ! 16: /* registers on the 82077 */ ! 17: struct Device ! 18: { ! 19: uchar sra; /* (R/O) status register A */ ! 20: uchar srb; /* (R/O) status register B */ ! 21: uchar dor; /* (R/W) digital output register */ ! 22: uchar rsvd3; /* reserved */ ! 23: uchar msr; /* (R/O) main status register */ ! 24: #define dsr msr ! 25: uchar fifo; /* (R/W) data FIFO */ ! 26: uchar rsvd6; /* reserved */ ! 27: uchar dir; /* (R/O) digital input register */ ! 28: #define ccr dir ! 29: uchar flpctl; /* (W/O) control (not in 82077) */ ! 30: }; ! 31: ! 32: /* bits in the registers */ ! 33: enum ! 34: { ! 35: /* status register A */ ! 36: Fintpend= 0x80, /* interrupt pending */ ! 37: ! 38: /* digital output register */ ! 39: Fintena= 0x8, /* enable floppy interrupt */ ! 40: Fena= 0x4, /* 0 == reset controller */ ! 41: ! 42: /* main status register */ ! 43: Fready= 0x80, /* ready to be touched */ ! 44: Ffrom= 0x40, /* data from controller */ ! 45: Fbusy= 0x10, /* operation not over */ ! 46: ! 47: /* data register */ ! 48: Frecal= 0x07, /* recalibrate cmd */ ! 49: Fseek= 0x0f, /* seek cmd */ ! 50: Fsense= 0x08, /* sense cmd */ ! 51: Fread= 0x66, /* read cmd */ ! 52: Freadid= 0x4a, /* read track id */ ! 53: Fspec= 0x03, /* set hold times */ ! 54: Fwrite= 0x45, /* write cmd */ ! 55: Fmulti= 0x80, /* or'd with Fread or Fwrite for multi-head */ ! 56: Fdumpreg= 0x0e, /* dump internal registers */ ! 57: ! 58: /* disk changed register */ ! 59: Fchange= 0x80, /* disk has changed */ ! 60: ! 61: /* floppy control register (not part of 82077) */ ! 62: Eject_disc = 0x80, /* Eject the floppy */ ! 63: Sel_82077 = 0x40, /* Scsi/82077 select */ ! 64: Drv_id = 0x04, /* Drive present flag */ ! 65: Mid = 0x03, /* Media id bits */ ! 66: ! 67: /* status 0 byte */ ! 68: Drivemask= 3<<0, ! 69: Seekend= 1<<5, ! 70: Codemask= (3<<6)|(3<<3), ! 71: ! 72: /* file types */ ! 73: Qdir= 0, ! 74: Qdata= (1<<2), ! 75: Qctl= (2<<2), ! 76: Qmask= (3<<2), ! 77: }; ! 78: ! 79: /* ! 80: * floppy types ! 81: */ ! 82: struct Type ! 83: { ! 84: char *name; ! 85: int bytes; /* bytes/sector */ ! 86: int sectors; /* sectors/track */ ! 87: int heads; /* number of heads */ ! 88: int steps; /* steps per cylinder */ ! 89: int tracks; /* tracks/disk */ ! 90: int gpl; /* intersector gap length for read/write */ ! 91: int fgpl; /* intersector gap length for format */ ! 92: ! 93: /* ! 94: * these depend on previous entries and are set filled in ! 95: * by floppyinit ! 96: */ ! 97: int bcode; /* coded version of bytes for the controller */ ! 98: long cap; /* drive capacity in bytes */ ! 99: long tsize; /* track size in bytes */ ! 100: }; ! 101: Type floppytype[] = ! 102: { ! 103: { "MF2HD", 512, 18, 2, 1, 80, 0x1B, 0x54, }, ! 104: { "MF1DD", 512, 9, 2, 1, 80, 0x1B, 0x54, }, ! 105: { "MF4HD", 1024, 18, 2, 1, 80, 0x1B, 0x54, }, ! 106: { "F2HD", 512, 15, 2, 1, 80, 0x2A, 0x50, }, ! 107: { "F2DD", 512, 8, 2, 2, 40, 0x2A, 0x50, }, ! 108: { "F1DD", 512, 8, 1, 2, 40, 0x2A, 0x50, }, ! 109: }; ! 110: #define NTYPES (sizeof(floppytype)/sizeof(Type)) ! 111: ! 112: /* ! 113: * bytes per sector encoding for the controller. ! 114: * - index for b2c is is (bytes per sector/128). ! 115: * - index for c2b is code from b2c ! 116: */ ! 117: static int b2c[] = ! 118: { ! 119: [1] 0, ! 120: [2] 1, ! 121: [4] 2, ! 122: [8] 3, ! 123: }; ! 124: static int c2b[] = ! 125: { ! 126: 128, ! 127: 256, ! 128: 512, ! 129: 1024, ! 130: }; ! 131: ! 132: /* ! 133: * a floppy drive ! 134: */ ! 135: struct Drive ! 136: { ! 137: Type *t; ! 138: int dev; ! 139: ! 140: ulong lasttouched; /* time last touched */ ! 141: int cyl; /* current cylinder */ ! 142: int confused; /* needs to be recalibrated */ ! 143: int vers; ! 144: ! 145: int tcyl; /* target cylinder */ ! 146: int thead; /* target head */ ! 147: int tsec; /* target sector */ ! 148: long len; /* size of xfer */ ! 149: ! 150: uchar *virtual; /* track cache */ ! 151: uchar *physical; /* ... */ ! 152: int ccyl; ! 153: int chead; ! 154: ! 155: Rendez r; /* waiting here for motor to spin up */ ! 156: }; ! 157: ! 158: /* ! 159: * controller for 4 floppys ! 160: */ ! 161: struct Controller ! 162: { ! 163: QLock; /* exclusive access to the contoller */ ! 164: ! 165: Drive *d; /* the floppy drives */ ! 166: uchar cmd[14]; /* command */ ! 167: int ncmd; /* # command bytes */ ! 168: uchar stat[14]; /* command status */ ! 169: int nstat; /* # status bytes */ ! 170: int confused; /* controler needs to be reset */ ! 171: Rendez r; /* wait here for command termination */ ! 172: int motor; /* bit mask of spinning disks */ ! 173: ! 174: uchar *virtual; /* kernel buffer for DMA (output) */ ! 175: uchar *physical; /* ... */ ! 176: ! 177: Rendez kr; /* for motor watcher */ ! 178: }; ! 179: ! 180: Controller fl; ! 181: ! 182: #define MOTORBIT(i) (1<<((i)+4)) ! 183: ! 184: /* ! 185: * predeclared ! 186: */ ! 187: static int floppycmd(void); ! 188: static void floppyeject(Drive*); ! 189: static void floppykproc(void*); ! 190: static void floppyon(Drive*); ! 191: static void floppyoff(Drive*); ! 192: static void floppypos(Drive*,long); ! 193: static int floppyrecal(Drive*); ! 194: static int floppyresult(void); ! 195: static void floppyrevive(void); ! 196: static long floppyseek(Drive*, long); ! 197: static int floppysense(void); ! 198: static void floppywait(void); ! 199: static long floppyxfer(Drive*, int, void*, long, long); ! 200: static long floppythrice(Drive*, int, void*, long, long); ! 201: static int cmddone(void*); ! 202: ! 203: Dirtab floppydir[]={ ! 204: "fd0disk", {Qdata + 0}, 0, 0666, ! 205: "fd0ctl", {Qctl + 0}, 0, 0666, ! 206: "fd1disk", {Qdata + 1}, 0, 0666, ! 207: "fd1ctl", {Qctl + 1}, 0, 0666, ! 208: "fd2disk", {Qdata + 2}, 0, 0666, ! 209: "fd2ctl", {Qctl + 2}, 0, 0666, ! 210: "fd3disk", {Qdata + 3}, 0, 0666, ! 211: "fd3ctl", {Qctl + 3}, 0, 0666, ! 212: }; ! 213: #define NFDIR 2 /* directory entries/drive */ ! 214: ! 215: /* ! 216: * grab DMA from SCSI ! 217: */ ! 218: #define GETDMA\ ! 219: {\ ! 220: qlock(&dmalock);\ ! 221: dmaowner = Ofloppy;\ ! 222: ((Device*)(FDCTLRL))->flpctl = Sel_82077;\ ! 223: if(waserror()){\ ! 224: ((Device*)(FDCTLRL))->flpctl = 0;\ ! 225: qunlock(&dmalock);\ ! 226: nexterror();\ ! 227: }\ ! 228: } ! 229: ! 230: /* ! 231: * let SCSI have DMA ! 232: */ ! 233: #define PUTDMA\ ! 234: {\ ! 235: ((Device*)(FDCTLRL))->flpctl = 0;\ ! 236: dmaowner = Oscsi;\ ! 237: qunlock(&dmalock);\ ! 238: poperror();\ ! 239: } ! 240: ! 241: void ! 242: nextfloppyreset(void) ! 243: { ! 244: Device *devp = (Device*)(FDCTLRL); ! 245: Drive *dp; ! 246: Type *t; ! 247: ulong p; ! 248: long l; ! 249: ! 250: /* ! 251: * init dependent parameters ! 252: */ ! 253: for(t = floppytype; t < &floppytype[NTYPES]; t++){ ! 254: t->cap = t->bytes * t->heads * t->sectors * t->tracks; ! 255: t->bcode = b2c[t->bytes/128]; ! 256: t->tsize = t->bytes * t->sectors; ! 257: } ! 258: ! 259: /* ! 260: * allocate the drive storage ! 261: */ ! 262: fl.d = xalloc(conf.nfloppy*sizeof(Drive)); ! 263: ! 264: /* ! 265: * allocate a page for dma ! 266: */ ! 267: p = (ulong)xspanalloc(BY2PG, BY2PG, 0); ! 268: fl.virtual = (uchar *)kmappa(p); ! 269: fl.physical = (uchar*)p; ! 270: ! 271: /* ! 272: * reset the chip, leave it off ! 273: */ ! 274: fl.motor = 0; ! 275: devp->flpctl = Sel_82077; ! 276: devp->dor = 0; ! 277: devp->flpctl = 0; ! 278: ! 279: /* ! 280: * init drives ! 281: */ ! 282: for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){ ! 283: dp->dev = dp - fl.d; ! 284: dp->t = &floppytype[0]; /* default type */ ! 285: floppydir[NFDIR*dp->dev].length = dp->t->cap; ! 286: dp->cyl = -1; /* because we don't know */ ! 287: p = (ulong)xspanalloc(dp->t->tsize, BY2PG, 0); ! 288: dp->virtual = (uchar *)kmappa(p); ! 289: for(l = BY2PG; l < dp->t->tsize; l += BY2PG) ! 290: kmappa(p+l); ! 291: dp->physical = (uchar*)p; ! 292: dp->ccyl = -1; ! 293: dp->vers = 1; ! 294: } ! 295: ! 296: /* ! 297: * first operation will recalibrate ! 298: */ ! 299: fl.confused = 1; ! 300: } ! 301: ! 302: void ! 303: nextfloppyinit(void) ! 304: { ! 305: } ! 306: ! 307: Chan* ! 308: nextfloppyattach(char *spec) ! 309: { ! 310: static int kstarted; ! 311: ! 312: if(kstarted == 0){ ! 313: /* ! 314: * watchdog to turn off the motors ! 315: */ ! 316: kstarted = 1; ! 317: kproc("floppy", floppykproc, 0); ! 318: } ! 319: return devattach('f', spec); ! 320: } ! 321: ! 322: Chan* ! 323: nextfloppyclone(Chan *c, Chan *nc) ! 324: { ! 325: return devclone(c, nc); ! 326: } ! 327: ! 328: int ! 329: nextfloppywalk(Chan *c, char *name) ! 330: { ! 331: return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen); ! 332: } ! 333: ! 334: void ! 335: nextfloppystat(Chan *c, char *dp) ! 336: { ! 337: devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen); ! 338: } ! 339: ! 340: Chan* ! 341: nextfloppyopen(Chan *c, int omode) ! 342: { ! 343: return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen); ! 344: } ! 345: ! 346: void ! 347: nextfloppycreate(Chan *c, char *name, int omode, ulong perm) ! 348: { ! 349: USED(c, name, omode, perm); ! 350: error(Eperm); ! 351: } ! 352: ! 353: void ! 354: nextfloppyclose(Chan *c) ! 355: { ! 356: USED(c); ! 357: } ! 358: ! 359: void ! 360: nextfloppyremove(Chan *c) ! 361: { ! 362: USED(c); ! 363: error(Eperm); ! 364: } ! 365: ! 366: void ! 367: nextfloppywstat(Chan *c, char *dp) ! 368: { ! 369: USED(c, dp); ! 370: error(Eperm); ! 371: } ! 372: ! 373: static void ! 374: islegal(Chan *c, long n, Drive *dp) ! 375: { ! 376: if(c->offset % dp->t->bytes) ! 377: error(Ebadarg); ! 378: if(n % dp->t->bytes) ! 379: error(Ebadarg); ! 380: if(c->qid.vers!=0 && c->qid.vers!=dp->vers){ ! 381: c->qid.vers = dp->vers; ! 382: error(Eio); ! 383: } else ! 384: c->qid.vers = dp->vers; ! 385: } ! 386: ! 387: static void ! 388: changed(Chan *c, Drive *dp) ! 389: { ! 390: ulong old; ! 391: ! 392: old = c->qid.vers; ! 393: c->qid.vers = dp->vers; ! 394: if(old && old!=dp->vers) ! 395: error(Eio); ! 396: } ! 397: ! 398: long ! 399: nextfloppyread(Chan *c, void *a, long n) ! 400: { ! 401: Drive *dp; ! 402: long rv, i; ! 403: int nn, sec, head, cyl; ! 404: long len; ! 405: uchar *aa; ! 406: ! 407: if(c->qid.path == CHDIR) ! 408: return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen); ! 409: ! 410: rv = 0; ! 411: dp = &fl.d[c->qid.path & ~Qmask]; ! 412: ! 413: switch ((int)(c->qid.path & Qmask)) { ! 414: case Qdata: ! 415: islegal(c, n, dp); ! 416: aa = a; ! 417: nn = dp->t->tsize; ! 418: ! 419: qlock(&fl); ! 420: if(waserror()){ ! 421: qunlock(&fl); ! 422: fl.confused = 1; ! 423: CLRCTL(Cpu_dma); ! 424: nexterror(); ! 425: } ! 426: GETDMA; ! 427: floppyon(dp); ! 428: changed(c, dp); ! 429: for(rv = 0; rv < n; rv += len){ ! 430: /* ! 431: * truncate xfer at track boundary ! 432: */ ! 433: dp->len = n - rv; ! 434: floppypos(dp, c->offset+rv); ! 435: cyl = dp->tcyl; ! 436: head = dp->thead; ! 437: len = dp->len; ! 438: sec = dp->tsec; ! 439: ! 440: /* ! 441: * read the track ! 442: */ ! 443: if(dp->ccyl!=cyl || dp->chead!=head){ ! 444: dp->ccyl = -1; ! 445: i = floppythrice(dp, Fread,0,(cyl*dp->t->heads+head)*nn,nn); ! 446: if(i != nn){ ! 447: if(i == 0) ! 448: break; ! 449: error(Eio); ! 450: } ! 451: dp->ccyl = cyl; ! 452: dp->chead = head; ! 453: } ! 454: memmove(aa+rv, dp->virtual + (sec-1)*dp->t->bytes, len); ! 455: } ! 456: PUTDMA; ! 457: qunlock(&fl); ! 458: poperror(); ! 459: break; ! 460: case Qctl: ! 461: break; ! 462: default: ! 463: panic("floppyread: bad qid"); ! 464: } ! 465: ! 466: return rv; ! 467: } ! 468: ! 469: #define SNCMP(a, b) strncmp(a, b, sizeof(b)-1) ! 470: long ! 471: nextfloppywrite(Chan *c, void *a, long n) ! 472: { ! 473: Drive *dp; ! 474: long rv, i; ! 475: char *aa = a; ! 476: ! 477: rv = 0; ! 478: dp = &fl.d[c->qid.path & ~Qmask]; ! 479: ! 480: switch ((int)(c->qid.path & Qmask)) { ! 481: case Qdata: ! 482: islegal(c, n, dp); ! 483: qlock(&fl); ! 484: if(waserror()){ ! 485: qunlock(&fl); ! 486: fl.confused = 1; ! 487: CLRCTL(Cpu_dma); ! 488: nexterror(); ! 489: } ! 490: GETDMA; ! 491: floppyon(dp); ! 492: changed(c, dp); ! 493: for(rv = 0; rv < n; rv += i){ ! 494: floppypos(dp, c->offset+rv); ! 495: if(dp->tcyl == dp->ccyl) ! 496: dp->ccyl = -1; ! 497: i = floppythrice(dp, Fwrite, aa+rv, c->offset+rv, ! 498: n-rv); ! 499: if(i <= 0) ! 500: break; ! 501: } ! 502: PUTDMA; ! 503: qunlock(&fl); ! 504: poperror(); ! 505: break; ! 506: case Qctl: ! 507: if(SNCMP(aa, "eject") == 0){ ! 508: qlock(&fl); ! 509: GETDMA; ! 510: floppyeject(dp); ! 511: PUTDMA; ! 512: qunlock(&fl); ! 513: } else if(SNCMP(aa, "reset") == 0){ ! 514: qlock(&fl); ! 515: GETDMA; ! 516: floppyon(dp); ! 517: PUTDMA; ! 518: qunlock(&fl); ! 519: } ! 520: break; ! 521: default: ! 522: panic("floppywrite: bad qid"); ! 523: } ! 524: ! 525: return rv; ! 526: } ! 527: ! 528: static void ! 529: floppykproc(void *a) ! 530: { ! 531: Drive *dp; ! 532: ! 533: USED(a); ! 534: ! 535: while(waserror()) ! 536: ; ! 537: for(;;){ ! 538: for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){ ! 539: if((fl.motor&MOTORBIT(dp->dev)) ! 540: && TK2SEC(m->ticks - dp->lasttouched) > 5 ! 541: && canqlock(&fl)){ ! 542: GETDMA; ! 543: if(TK2SEC(m->ticks - dp->lasttouched) > 5) ! 544: floppyoff(dp); ! 545: qunlock(&fl); ! 546: PUTDMA; ! 547: } ! 548: } ! 549: tsleep(&fl.kr, return0, 0, 5*1000); ! 550: } ! 551: } ! 552: ! 553: /* ! 554: * start a floppy drive's motor. ! 555: */ ! 556: static void ! 557: floppyon(Drive *dp) ! 558: { ! 559: Device *devp = (Device*)(FDCTLRL); ! 560: int alreadyon; ! 561: int tries; ! 562: ! 563: for(tries = 0; tries < 4; tries++){ ! 564: if(fl.confused) ! 565: floppyrevive(); ! 566: ! 567: /* start motor and select drive */ ! 568: alreadyon = fl.motor & MOTORBIT(dp->dev); ! 569: fl.motor |= MOTORBIT(dp->dev); ! 570: devp->dor = fl.motor | Fintena | Fena | dp->dev; ! 571: if(!alreadyon) ! 572: tsleep(&dp->r, return0, 0, 750); ! 573: ! 574: /* get drive to a known cylinder */ ! 575: if(dp->confused) ! 576: if(floppyrecal(dp) >= 0) ! 577: break; ! 578: else ! 579: break; ! 580: } ! 581: dp->lasttouched = m->ticks; ! 582: } ! 583: ! 584: /* ! 585: * stop the floppy if it hasn't been used in 5 seconds ! 586: */ ! 587: static void ! 588: floppyoff(Drive *dp) ! 589: { ! 590: Device *devp = (Device*)(FDCTLRL); ! 591: ! 592: fl.motor &= ~MOTORBIT(dp->dev); ! 593: devp->dor = fl.motor | Fintena | Fena | dp->dev; ! 594: } ! 595: ! 596: /* ! 597: * eject disk ! 598: */ ! 599: static void ! 600: floppyeject(Drive *dp) ! 601: { ! 602: Device *devp = (Device*)(FDCTLRL); ! 603: ! 604: dp->vers++; ! 605: floppyon(dp); ! 606: delay(1); ! 607: devp->flpctl = Eject_disc|Sel_82077; ! 608: delay(1); ! 609: devp->flpctl = Sel_82077; ! 610: delay(1); ! 611: floppyoff(dp); ! 612: } ! 613: ! 614: /* ! 615: * send a command to the floppy ! 616: */ ! 617: static int ! 618: floppycmd(void) ! 619: { ! 620: Device *devp = (Device*)(FDCTLRL); ! 621: int i; ! 622: int tries; ! 623: ! 624: for(i = 0; i < fl.ncmd; i++){ ! 625: for(tries = 0; ; tries++){ ! 626: if(tries > 1000){ ! 627: print("cmd %ux can't be sent (%d %ux)\n", fl.cmd[0], i, devp->msr); ! 628: fl.confused = 1; ! 629: return -1; ! 630: } ! 631: if((devp->msr&(Ffrom|Fready)) == Fready) ! 632: break; ! 633: } ! 634: devp->fifo = fl.cmd[i]; ! 635: } ! 636: return 0; ! 637: } ! 638: ! 639: /* ! 640: * get a command result from the floppy ! 641: * ! 642: * when the controller goes ready waiting for a command ! 643: * (instead of sending results), we're done ! 644: * ! 645: */ ! 646: static int ! 647: floppyresult(void) ! 648: { ! 649: Device *devp = (Device*)(FDCTLRL); ! 650: int i, s; ! 651: int tries; ! 652: ! 653: for(i = 0; i < sizeof(fl.stat); i++){ ! 654: for(tries = 0; ; tries++){ ! 655: if(tries > 1000){ ! 656: fl.confused = 1; ! 657: return -1; ! 658: } ! 659: s = devp->msr&(Ffrom|Fready); ! 660: if(s == Fready){ ! 661: fl.nstat = i; ! 662: return i; ! 663: } ! 664: if(s == (Ffrom|Fready)) ! 665: break; ! 666: } ! 667: fl.stat[i] = devp->fifo; ! 668: } ! 669: fl.nstat = i; ! 670: return i; ! 671: } ! 672: ! 673: /* ! 674: * calculate physical address of a logical byte offset into the disk ! 675: * ! 676: * truncate dp->length if it crosses a track boundary ! 677: */ ! 678: static void ! 679: floppypos(Drive *dp, long off) ! 680: { ! 681: int lsec; ! 682: int ltrack; ! 683: int end; ! 684: ! 685: lsec = off/dp->t->bytes; ! 686: ltrack = lsec/dp->t->sectors; ! 687: dp->tcyl = ltrack/dp->t->heads; ! 688: dp->tsec = (lsec % dp->t->sectors) + 1; ! 689: dp->thead = (lsec/dp->t->sectors) % dp->t->heads; ! 690: ! 691: /* ! 692: * can't read across track boundaries. ! 693: * if so, decrement the bytes to be read. ! 694: */ ! 695: end = (ltrack+1)*dp->t->sectors*dp->t->bytes; ! 696: if(off+dp->len > end) ! 697: dp->len = end - off; ! 698: } ! 699: ! 700: /* ! 701: * get the interrupt cause from the floppy. ! 702: */ ! 703: static int ! 704: floppysense(void) ! 705: { ! 706: fl.ncmd = 0; ! 707: fl.cmd[fl.ncmd++] = Fsense; ! 708: if(floppycmd() < 0) ! 709: return -1; ! 710: if(floppyresult() < 2){ ! 711: print("can't read sense response\n"); ! 712: fl.confused = 1; ! 713: return -1; ! 714: } ! 715: return 0; ! 716: } ! 717: ! 718: static int ! 719: cmddone(void *a) ! 720: { ! 721: USED(a); ! 722: return fl.ncmd == 0; ! 723: } ! 724: ! 725: /* ! 726: * wait for a floppy interrupt ! 727: */ ! 728: static void ! 729: floppywait(void) ! 730: { ! 731: tsleep(&fl.r, cmddone, 0, 2000); ! 732: } ! 733: ! 734: /* ! 735: * we've lost the floppy position, go to cylinder 0. ! 736: */ ! 737: static int ! 738: floppyrecal(Drive *dp) ! 739: { ! 740: Device *devp = (Device*)(FDCTLRL); ! 741: int type; ! 742: ! 743: dp->ccyl = -1; ! 744: ! 745: type = devp->flpctl & Mid; ! 746: switch(type){ ! 747: case 0: ! 748: print("no diskette %d\n", dp->dev); ! 749: return -1; ! 750: case 1: ! 751: devp->dsr = 3; ! 752: devp->ccr = 3; ! 753: dp->t = &floppytype[2]; ! 754: return -1; ! 755: case 2: ! 756: dp->t = &floppytype[0]; ! 757: break; ! 758: case 3: ! 759: devp->dsr = 0; ! 760: devp->ccr = 0; ! 761: dp->t = &floppytype[1]; ! 762: break; ! 763: } ! 764: ! 765: fl.ncmd = 0; ! 766: fl.cmd[fl.ncmd++] = Frecal; ! 767: fl.cmd[fl.ncmd++] = dp->dev; ! 768: if(floppycmd() < 0) ! 769: return -1; ! 770: floppywait(); ! 771: if(fl.nstat < 2){ ! 772: fl.confused = 1; ! 773: return -1; ! 774: } ! 775: if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ ! 776: dp->confused = 1; ! 777: return -1; ! 778: } ! 779: dp->cyl = fl.stat[1]/dp->t->steps; ! 780: if(dp->cyl != 0){ ! 781: print("recalibrate went to wrong cylinder %d\n", dp->cyl); ! 782: dp->confused = 1; ! 783: return -1; ! 784: } ! 785: ! 786: dp->confused = 0; ! 787: return 0; ! 788: } ! 789: ! 790: /* ! 791: * if the controller or a specific drive is in a confused state, ! 792: * reset it and get back to a kown state ! 793: */ ! 794: void ! 795: floppyrevive(void) ! 796: { ! 797: Device *devp = (Device*)(FDCTLRL); ! 798: Drive *dp; ! 799: ! 800: /* ! 801: * reset the controller if it's confused ! 802: */ ! 803: if(fl.confused){ ! 804: /* reset controller and turn all motors off */ ! 805: splhi(); ! 806: fl.cmd[0] = 0; ! 807: devp->dor = 0; ! 808: delay(1); ! 809: devp->dor = Fintena|Fena; ! 810: spllo(); ! 811: for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++) ! 812: dp->confused = 1; ! 813: fl.motor = 0; ! 814: floppywait(); ! 815: fl.confused = 0; ! 816: devp->dsr = 0; ! 817: devp->ccr = 0; ! 818: } ! 819: } ! 820: ! 821: /* ! 822: * seek to the target cylinder ! 823: * ! 824: * interrupt, no results ! 825: */ ! 826: static long ! 827: floppyseek(Drive *dp, long off) ! 828: { ! 829: floppypos(dp, off); ! 830: if(dp->cyl == dp->tcyl) ! 831: return dp->cyl; ! 832: ! 833: /* print("seeking tcyl %d, thead %d\n", dp->tcyl, dp->thead); /**/ ! 834: fl.ncmd = 0; ! 835: fl.cmd[fl.ncmd++] = Fseek; ! 836: fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; ! 837: fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; ! 838: if(floppycmd() < 0){ ! 839: print("seek cmd failed\n"); ! 840: return -1; ! 841: } ! 842: floppywait(); ! 843: if(fl.nstat < 2){ ! 844: fl.confused = 1; ! 845: return -1; ! 846: } ! 847: if((fl.stat[0] & (Codemask|Seekend)) != Seekend){ ! 848: print("seek failed\n"); ! 849: dp->confused = 1; ! 850: return -1; ! 851: } ! 852: ! 853: dp->cyl = dp->tcyl; ! 854: return dp->cyl; ! 855: } ! 856: ! 857: /* ! 858: * since floppies are so flakey, try 3 times before giving up ! 859: */ ! 860: static long ! 861: floppythrice(Drive *dp, int cmd, void *a, long off, long n) ! 862: { ! 863: int tries; ! 864: long rv; ! 865: ! 866: for(tries = 0; ; tries++){ ! 867: if(waserror()){ ! 868: if(strcmp(u->error, Eintr)==0 || tries > 3) ! 869: nexterror(); ! 870: } else { ! 871: rv = floppyxfer(dp, cmd, a, off, n); ! 872: poperror(); ! 873: return rv; ! 874: } ! 875: } ! 876: } ! 877: ! 878: static long ! 879: floppyxfer(Drive *dp, int cmd, void *a, long off, long n) ! 880: { ! 881: Device *devp = (Device*)(FDCTLRL); ! 882: SCSIdma *dma = (SCSIdma *)SCSIDMA; ! 883: long offset; ! 884: ulong up; ! 885: ! 886: if(off >= dp->t->cap) ! 887: return 0; ! 888: if(off + n > dp->t->cap) ! 889: n = dp->t->cap - off; ! 890: ! 891: /* ! 892: * calculate new position and seek to it (dp->len may be trimmed) ! 893: */ ! 894: dp->len = n; ! 895: if(floppyseek(dp, off) < 0) ! 896: error(Eio); ! 897: ! 898: /*print("tcyl %d, thead %d, tsec %d, addr %lux, buf %lux, n %d\n", ! 899: dp->tcyl, dp->thead, dp->tsec, a, fl.physical, dp->len);/**/ ! 900: ! 901: /* ! 902: * turn off any previous dma, set up new one ! 903: */ ! 904: dma->csr = Dinit | Dcreset; ! 905: if(cmd == Fread){ ! 906: up = (ulong)dp->physical; ! 907: } else { ! 908: memmove(fl.virtual, a, dp->len); ! 909: up = (ulong)fl.physical; ! 910: } ! 911: dma->base = up; ! 912: if(cmd == Fread){ ! 913: dma->limit = up + dp->len; ! 914: SETCTL(Dmadir); ! 915: dma->csr = Dseten | Dsetread | Dinit; ! 916: } else { ! 917: dma->limit = up + dp->len + 16; ! 918: CLRCTL(Dmadir); ! 919: dma->csr = Dseten | Dinit; ! 920: } ! 921: ! 922: /* ! 923: * start operation ! 924: */ ! 925: /* cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);/**/ ! 926: fl.ncmd = 0; ! 927: fl.cmd[fl.ncmd++] = cmd; ! 928: fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; ! 929: fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps; ! 930: fl.cmd[fl.ncmd++] = dp->thead; ! 931: fl.cmd[fl.ncmd++] = dp->tsec; ! 932: fl.cmd[fl.ncmd++] = dp->t->bcode; ! 933: fl.cmd[fl.ncmd++] = dp->tsec + dp->len/dp->t->bytes - 1; ! 934: fl.cmd[fl.ncmd++] = dp->t->gpl; ! 935: fl.cmd[fl.ncmd++] = 0xFF; ! 936: splhi(); ! 937: if(floppycmd() < 0){ ! 938: spllo(); ! 939: print("xfer cmd failed\n"); ! 940: error(Eio); ! 941: } ! 942: ! 943: /* ! 944: * give bus to DMA, floppyintr() will read result ! 945: */ ! 946: SETCTL(Cpu_dma); ! 947: spllo(); ! 948: floppywait(); ! 949: ! 950: /* ! 951: * check for errors ! 952: */ ! 953: if(fl.nstat < 7){ ! 954: print("xfer result failed %lux\n", devp->msr); ! 955: fl.confused = 1; ! 956: error(Eio); ! 957: } ! 958: if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){ ! 959: if(fl.stat[1] != 0x80){ ! 960: print("xfer failed %lux %lux %lux\n", fl.stat[0], ! 961: fl.stat[1], fl.stat[2]); ! 962: print("offset %lud len %d\n", off, dp->len); ! 963: dp->confused = 1; ! 964: error(Eio); ! 965: } else ! 966: fl.stat[5]++; ! 967: } ! 968: ! 969: /* ! 970: * check for correct cylinder ! 971: */ ! 972: offset = (fl.stat[3]/dp->t->steps) * dp->t->heads + fl.stat[4]; ! 973: offset = offset*dp->t->sectors + fl.stat[5] - 1; ! 974: offset = offset * c2b[fl.stat[6]]; ! 975: if(offset != off+dp->len){ ! 976: print("new offset %d instead of %d\n", offset, off+dp->len); ! 977: dp->confused = 1; ! 978: error(Eio); ! 979: } ! 980: ! 981: dp->lasttouched = m->ticks; ! 982: return dp->len; ! 983: } ! 984: ! 985: void ! 986: floppyintr(void) ! 987: { ! 988: SCSIdma *dma = (SCSIdma *)SCSIDMA; ! 989: Device *devp = (Device*)(FDCTLRL); ! 990: ! 991: switch(fl.cmd[0]&~Fmulti){ ! 992: case Fread: ! 993: case Fwrite: ! 994: if(dma->base != dma->limit) ! 995: crankfifo(dma->limit - dma->base); ! 996: CLRCTL(Cpu_dma); ! 997: floppyresult(); ! 998: break; ! 999: case Freadid: ! 1000: floppyresult(); ! 1001: break; ! 1002: case Fseek: ! 1003: case Frecal: ! 1004: default: ! 1005: if(dmaowner != Ofloppy) ! 1006: devp->flpctl = Sel_82077; ! 1007: floppysense(); /* to clear interrupt */ ! 1008: if(dmaowner != Ofloppy) ! 1009: devp->flpctl = 0; ! 1010: break; ! 1011: } ! 1012: fl.ncmd = 0; ! 1013: wakeup(&fl.r); ! 1014: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.