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