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