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