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 "pcmcia.h" 10 11 #define DPRINT if(0)print 12 13 typedef struct Drive Drive; 14 typedef struct Ident Ident; 15 typedef struct Controller Controller; 16 typedef struct Partition Partition; 17 typedef struct Repl Repl; 18 19 enum 20 { 21 /* ports */ 22 Pbase= 0x1F0, 23 Pdata= 0, /* data port (16 bits) */ 24 Perror= 1, /* error port (read) */ 25 Pprecomp= 1, /* buffer mode port (write) */ 26 Pcount= 2, /* sector count port */ 27 Psector= 3, /* sector number port */ 28 Pcyllsb= 4, /* least significant byte cylinder # */ 29 Pcylmsb= 5, /* most significant byte cylinder # */ 30 Pdh= 6, /* drive/head port */ 31 Pstatus= 7, /* status port (read) */ 32 Sbusy= (1<<7), 33 Sready= (1<<6), 34 Sdrq= (1<<3), 35 Serr= (1<<0), 36 Pcmd= 7, /* cmd port (write) */ 37 38 /* commands */ 39 Crecal= 0x10, 40 Cread= 0x20, 41 Cwrite= 0x30, 42 Cident= 0xEC, 43 Cident2= 0xFF, /* pseudo command for post Cident interrupt */ 44 Csetbuf= 0xEF, 45 Cinitparam= 0x91, 46 47 /* conner specific commands */ 48 Cstandby= 0xE2, 49 Cidle= 0xE1, 50 Cpowerdown= 0xE3, 51 52 /* disk states */ 53 Sspinning, 54 Sstandby, 55 Sidle, 56 Spowerdown, 57 58 /* something we have to or into the drive/head reg */ 59 DHmagic= 0xA0, 60 61 /* file types */ 62 Qdir= 0, 63 64 Maxxfer= BY2PG, /* maximum transfer size/cmd */ 65 Npart= 8+2, /* 8 sub partitions, disk, and partition */ 66 Nrepl= 64, /* maximum replacement blocks */ 67 }; 68 #define PART(x) ((x)&0xF) 69 #define DRIVE(x) (((x)>>4)&0x7) 70 #define MKQID(d,p) (((d)<<4) | (p)) 71 72 struct Partition 73 { 74 ulong start; 75 ulong end; 76 char name[NAMELEN+1]; 77 }; 78 79 struct Repl 80 { 81 Partition *p; 82 int nrepl; 83 ulong blk[Nrepl]; 84 }; 85 86 #define PARTMAGIC "plan9 partitions" 87 #define REPLMAGIC "block replacements" 88 89 /* 90 * an ata drive 91 */ 92 struct Drive 93 { 94 QLock; 95 96 Controller *cp; 97 int drive; 98 int confused; /* needs to be recalibrated (or worse) */ 99 int online; 100 int npart; /* number of real partitions */ 101 Partition p[Npart]; 102 Repl repl; 103 ulong usetime; 104 int state; 105 char vol[NAMELEN]; 106 107 ulong cap; /* total bytes */ 108 int bytes; /* bytes/sector */ 109 int sectors; /* sectors/track */ 110 int heads; /* heads/cyl */ 111 long cyl; /* cylinders/drive */ 112 113 char lba; /* true if drive has logical block addressing */ 114 char multi; /* non-zero if drive does multiple block xfers */ 115 }; 116 117 /* 118 * a controller for 2 drives 119 */ 120 struct Controller 121 { 122 QLock; /* exclusive access to the controller */ 123 ISAConf; /* interface to pcmspecial */ 124 125 Lock reglock; /* exclusive access to the registers */ 126 127 int confused; /* needs to be recalibrated (or worse) */ 128 ulong pbase; /* base port (copied from ISAConf) */ 129 130 /* 131 * current operation 132 */ 133 int cmd; /* current command */ 134 int lastcmd; /* debugging info */ 135 Rendez r; /* wait here for command termination */ 136 char *buf; /* xfer buffer */ 137 int nsecs; /* length of transfer (sectors) */ 138 int sofar; /* sectors transferred so far */ 139 int status; 140 int error; 141 Drive *dp; /* drive being accessed */ 142 }; 143 144 Controller *atac; 145 Drive *ata; 146 static char* ataerr; 147 static int nhard; 148 static int spindowntime; 149 150 static void ataintr(Ureg*, void*); 151 static long ataxfer(Drive*, Partition*, int, long, long, char*); 152 static void ataident(Drive*); 153 static void atasetbuf(Drive*, int); 154 static void ataparams(Drive*); 155 static void atapart(Drive*); 156 static int ataprobe(Drive*, int, int, int); 157 158 static int 159 atagen(Chan *c, Dirtab*, int, int s, Dir *dirp) 160 { 161 Qid qid; 162 int drive; 163 Drive *dp; 164 Partition *pp; 165 ulong l; 166 167 qid.vers = 0; 168 drive = s/Npart; 169 s = s % Npart; 170 if(drive >= nhard) 171 return -1; 172 dp = &ata[drive]; 173 174 if(dp->online == 0 || s >= dp->npart) 175 return 0; 176 177 pp = &dp->p[s]; 178 sprint(up->genbuf, "%s%s", dp->vol, pp->name); 179 qid.path = MKQID(drive, s); 180 l = (pp->end - pp->start) * dp->bytes; 181 devdir(c, qid, up->genbuf, l, eve, 0660, dirp); 182 return 1; 183 } 184 185 static void 186 atainit(void) 187 { 188 Drive *dp; 189 Controller *cp; 190 uchar equip; 191 int pcmslot; 192 193 if (atac) 194 return; /* already done */ 195 196 equip = 0x10; /* hard coded */ 197 198 print("ata init\n"); 199 cp = malloc(sizeof(*cp)); 200 if (!cp) 201 error(Enomem); 202 203 cp->port = Pbase; 204 cp->irq = 14; 205 206 if((pcmslot = pcmspecial("SunDisk", cp)) < 0) { 207 print("No ATA card\n"); 208 free(cp); 209 ataerr = Enoifc; 210 return; 211 } 212 ata = malloc(2 * sizeof(*ata)); 213 if(ata == nil) { 214 pcmspecialclose(pcmslot); 215 free(cp); 216 error(Enomem); 217 } 218 219 atac = cp; 220 cp->buf = 0; 221 cp->lastcmd = cp->cmd; 222 cp->cmd = 0; 223 cp->pbase = cp->port; 224 pcmintrenable(pcmslot, ataintr, cp); 225 226 dp = ata; 227 if(equip & 0xf0){ 228 dp->drive = 0; 229 dp->online = 0; 230 dp->cp = cp; 231 dp++; 232 } 233 if((equip & 0x0f)){ 234 dp->drive = 1; 235 dp->online = 0; 236 dp->cp = cp; 237 dp++; 238 } 239 nhard = dp - ata; 240 241 spindowntime = 1; 242 } 243 244 245 /* 246 * Get the characteristics of each drive. Mark unresponsive ones 247 * off line. 248 */ 249 static Chan* 250 ataattach(char *spec) 251 { 252 Drive *dp; 253 254 atainit(); 255 if (!ata) 256 error(ataerr ? ataerr : Enoifc); 257 for(dp = ata; dp < &ata[nhard]; dp++){ 258 if(waserror()){ 259 dp->online = 0; 260 qunlock(dp); 261 continue; 262 } 263 qlock(dp); 264 if(!dp->online){ 265 /* 266 * Make sure ataclock() doesn't 267 * interfere. 268 */ 269 dp->usetime = m->ticks; 270 ataparams(dp); 271 dp->online = 1; 272 atasetbuf(dp, 1); 273 } 274 275 /* 276 * read Plan 9 partition table 277 */ 278 atapart(dp); 279 qunlock(dp); 280 poperror(); 281 } 282 return devattach('H', spec); 283 } 284 285 static int 286 atawalk(Chan *c, char *name) 287 { 288 return devwalk(c, name, 0, 0, atagen); 289 } 290 291 static void 292 atastat(Chan *c, char *dp) 293 { 294 devstat(c, dp, 0, 0, atagen); 295 } 296 297 static Chan* 298 ataopen(Chan *c, int omode) 299 { 300 return devopen(c, omode, 0, 0, atagen); 301 } 302 303 static void 304 ataclose(Chan *c) 305 { 306 Drive *d; 307 Partition *p; 308 309 if(c->mode != OWRITE && c->mode != ORDWR) 310 return; 311 312 d = &ata[DRIVE(c->qid.path)]; 313 p = &d->p[PART(c->qid.path)]; 314 if(strcmp(p->name, "partition") != 0) 315 return; 316 317 if(waserror()){ 318 qunlock(d); 319 nexterror(); 320 } 321 qlock(d); 322 atapart(d); 323 qunlock(d); 324 poperror(); 325 } 326 327 static long 328 ataread(Chan *c, void *a, long n, vlong offset) 329 { 330 Drive *dp; 331 long rv, i; 332 int skip; 333 uchar *aa = a; 334 Partition *pp; 335 char *buf; 336 337 if(c->qid.path == CHDIR) 338 return devdirread(c, a, n, 0, 0, atagen); 339 340 buf = smalloc(Maxxfer); 341 if(waserror()){ 342 free(buf); 343 nexterror(); 344 } 345 346 dp = &ata[DRIVE(c->qid.path)]; 347 pp = &dp->p[PART(c->qid.path)]; 348 349 skip = offset % dp->bytes; 350 for(rv = 0; rv < n; rv += i){ 351 i = ataxfer(dp, pp, Cread, offset+rv-skip, n-rv+skip, buf); 352 if(i == 0) 353 break; 354 i -= skip; 355 if(i > n - rv) 356 i = n - rv; 357 memmove(aa+rv, buf + skip, i); 358 skip = 0; 359 } 360 361 free(buf); 362 poperror(); 363 364 return rv; 365 } 366 367 static long 368 atawrite(Chan *c, void *a, long n, vlong offset) 369 { 370 Drive *dp; 371 long rv, i, partial; 372 uchar *aa = a; 373 Partition *pp; 374 char *buf; 375 376 if(c->qid.path == CHDIR) 377 error(Eisdir); 378 379 dp = &ata[DRIVE(c->qid.path)]; 380 pp = &dp->p[PART(c->qid.path)]; 381 buf = smalloc(Maxxfer); 382 if(waserror()){ 383 free(buf); 384 nexterror(); 385 } 386 387 /* 388 * if not starting on a sector boundary, 389 * read in the first sector before writing 390 * it out. 391 */ 392 partial = offset % dp->bytes; 393 if(partial){ 394 ataxfer(dp, pp, Cread, offset-partial, dp->bytes, buf); 395 if(partial+n > dp->bytes) 396 rv = dp->bytes - partial; 397 else 398 rv = n; 399 memmove(buf+partial, aa, rv); 400 ataxfer(dp, pp, Cwrite, offset-partial, dp->bytes, buf); 401 } else 402 rv = 0; 403 404 /* 405 * write out the full sectors 406 */ 407 partial = (n - rv) % dp->bytes; 408 n -= partial; 409 for(; rv < n; rv += i){ 410 i = n - rv; 411 if(i > Maxxfer) 412 i = Maxxfer; 413 memmove(buf, aa+rv, i); 414 i = ataxfer(dp, pp, Cwrite, offset+rv, i, buf); 415 if(i == 0) 416 break; 417 } 418 419 /* 420 * if not ending on a sector boundary, 421 * read in the last sector before writing 422 * it out. 423 */ 424 if(partial){ 425 ataxfer(dp, pp, Cread, offset+rv, dp->bytes, buf); 426 memmove(buf, aa+rv, partial); 427 ataxfer(dp, pp, Cwrite, offset+rv, dp->bytes, buf); 428 rv += partial; 429 } 430 431 free(buf); 432 poperror(); 433 434 return rv; 435 } 436 437 /* 438 * did an interrupt happen? 439 */ 440 static int 441 cmddone(void *a) 442 { 443 Controller *cp = a; 444 445 return cp->cmd == 0; 446 } 447 448 /* 449 * Wait for the controller to be ready to accept a command. 450 * This is protected from intereference by ataclock() by 451 * setting dp->usetime before it is called. 452 */ 453 static void 454 cmdreadywait(Drive *dp) 455 { 456 long start; 457 int period; 458 Controller *cp = dp->cp; 459 460 /* give it 2 seconds to spin down and up */ 461 if(dp->state == Sspinning) 462 period = 10; 463 else 464 period = 2000; 465 466 start = m->ticks; 467 while((inb(cp->pbase+Pstatus) & (Sready|Sbusy)) != Sready) 468 if(TK2MS(m->ticks - start) > period){ 469 DPRINT("cmdreadywait failed\n"); 470 error(Eio); 471 } 472 } 473 474 static void 475 atarepl(Drive *dp, long bblk) 476 { 477 int i; 478 479 if(dp->repl.p == 0) 480 return; 481 for(i = 0; i < dp->repl.nrepl; i++){ 482 if(dp->repl.blk[i] == bblk) 483 DPRINT("found bblk %ld at offset %ld\n", bblk, i); 484 } 485 } 486 487 static void 488 atasleep(Controller *cp, int ms) 489 { 490 tsleep(&cp->r, cmddone, cp, ms); 491 if(cp->cmd && cp->cmd != Cident2){ 492 DPRINT("ata: cmd 0x%uX timeout, status=%lux\n", 493 cp->cmd, inb(cp->pbase+Pstatus)); 494 error("ata drive timeout"); 495 } 496 } 497 498 /* 499 * transfer a number of sectors. ataintr will perform all the iterative 500 * parts. 501 */ 502 static long 503 ataxfer(Drive *dp, Partition *pp, int cmd, long start, long len, char *buf) 504 { 505 Controller *cp; 506 long lblk; 507 int cyl, sec, head; 508 int loop, stat; 509 510 if(dp->online == 0) 511 error(Eio); 512 513 /* 514 * cut transfer size down to disk buffer size 515 */ 516 start = start / dp->bytes; 517 if(len > Maxxfer) 518 len = Maxxfer; 519 len = (len + dp->bytes - 1) / dp->bytes; 520 if(len == 0) 521 return 0; 522 523 /* 524 * calculate physical address 525 */ 526 lblk = start + pp->start; 527 if(lblk >= pp->end) 528 return 0; 529 if(lblk+len > pp->end) 530 len = pp->end - lblk; 531 if(dp->lba){ 532 sec = lblk & 0xff; 533 cyl = (lblk>>8) & 0xffff; 534 head = (lblk>>24) & 0xf; 535 } else { 536 cyl = lblk/(dp->sectors*dp->heads); 537 sec = (lblk % dp->sectors) + 1; 538 head = ((lblk/dp->sectors) % dp->heads); 539 } 540 541 DPRINT("<%s %d>", (cmd == Cwrite) ? "W" : "R", lblk); 542 cp = dp->cp; 543 qlock(cp); 544 if(waserror()){ 545 cp->buf = 0; 546 qunlock(cp); 547 nexterror(); 548 } 549 550 /* 551 * Make sure hardclock() doesn't 552 * interfere. 553 */ 554 dp->usetime = m->ticks; 555 cmdreadywait(dp); 556 557 ilock(&cp->reglock); 558 cp->sofar = 0; 559 cp->buf = buf; 560 cp->nsecs = len; 561 cp->cmd = cmd; 562 cp->dp = dp; 563 cp->status = 0; 564 565 outb(cp->pbase+Pcount, cp->nsecs); 566 outb(cp->pbase+Psector, sec); 567 outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | (dp->lba<<6) | head); 568 outb(cp->pbase+Pcyllsb, cyl); 569 outb(cp->pbase+Pcylmsb, cyl>>8); 570 outb(cp->pbase+Pcmd, cmd); 571 572 if(cmd == Cwrite){ 573 loop = 0; 574 microdelay(1); 575 while((stat = inb(cp->pbase+Pstatus) & (Serr|Sdrq)) == 0) 576 if(++loop > 10000) 577 panic("ataxfer"); 578 outss(cp->pbase+Pdata, cp->buf, dp->bytes/2); 579 } else 580 stat = 0; 581 iunlock(&cp->reglock); 582 583 if(stat & Serr) 584 error(Eio); 585 586 /* 587 * wait for command to complete. if we get a note, 588 * remember it but keep waiting to let the disk finish 589 * the current command. 590 */ 591 loop = 0; 592 while(waserror()){ 593 DPRINT("interrupted ataxfer\n"); 594 if(loop++ > 10){ 595 print("ata disk error\n"); 596 nexterror(); 597 } 598 } 599 atasleep(cp, 3000); 600 dp->state = Sspinning; 601 dp->usetime = m->ticks; 602 poperror(); 603 if(loop) 604 nexterror(); 605 606 if(cp->status & Serr){ 607 DPRINT("hd%d err: lblk %ld status %lux, err %lux\n", 608 dp-ata, lblk, cp->status, cp->error); 609 DPRINT("\tcyl %d, sec %d, head %d\n", cyl, sec, head); 610 DPRINT("\tnsecs %d, sofar %d\n", cp->nsecs, cp->sofar); 611 atarepl(dp, lblk+cp->sofar); 612 error(Eio); 613 } 614 cp->buf = 0; 615 len = cp->sofar*dp->bytes; 616 qunlock(cp); 617 poperror(); 618 619 return len; 620 } 621 622 /* 623 * set read ahead mode 624 */ 625 static void 626 atasetbuf(Drive *dp, int on) 627 { 628 Controller *cp = dp->cp; 629 630 qlock(cp); 631 if(waserror()){ 632 qunlock(cp); 633 nexterror(); 634 } 635 636 cmdreadywait(dp); 637 638 ilock(&cp->reglock); 639 cp->cmd = Csetbuf; 640 outb(cp->pbase+Pprecomp, on ? 0xAA : 0x55); /* read look ahead */ 641 outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); 642 outb(cp->pbase+Pcmd, Csetbuf); 643 iunlock(&cp->reglock); 644 645 atasleep(cp, 5000); 646 647 /* if(cp->status & Serr) 648 DPRINT("hd%d setbuf err: status %lux, err %lux\n", 649 dp-ata, cp->status, cp->error);/**/ 650 651 poperror(); 652 qunlock(cp); 653 } 654 655 /* 656 * ident sector from drive. this is from ANSI X3.221-1994 657 */ 658 struct Ident 659 { 660 ushort config; /* general configuration info */ 661 ushort cyls; /* # of cylinders (default) */ 662 ushort reserved0; 663 ushort heads; /* # of heads (default) */ 664 ushort b2t; /* unformatted bytes/track */ 665 ushort b2s; /* unformated bytes/sector */ 666 ushort s2t; /* sectors/track (default) */ 667 ushort reserved1[3]; 668 /* 10 */ 669 ushort serial[10]; /* serial number */ 670 ushort type; /* buffer type */ 671 ushort bsize; /* buffer size/512 */ 672 ushort ecc; /* ecc bytes returned by read long */ 673 ushort firm[4]; /* firmware revision */ 674 ushort model[20]; /* model number */ 675 /* 47 */ 676 ushort s2i; /* number of sectors/interrupt */ 677 ushort dwtf; /* double word transfer flag */ 678 ushort capabilities; 679 ushort reserved2; 680 ushort piomode; 681 ushort dmamode; 682 ushort cvalid; /* (cvald&1) if next 4 words are valid */ 683 ushort ccyls; /* current # cylinders */ 684 ushort cheads; /* current # heads */ 685 ushort cs2t; /* current sectors/track */ 686 ushort ccap[2]; /* current capacity in sectors */ 687 ushort cs2i; /* current number of sectors/interrupt */ 688 /* 60 */ 689 ushort lbasecs[2]; /* # LBA user addressable sectors */ 690 ushort dmasingle; 691 ushort dmadouble; 692 /* 64 */ 693 ushort reserved3[64]; 694 ushort vendor[32]; /* vendor specific */ 695 ushort reserved4[96]; 696 }; 697 698 /* 699 * get parameters from the drive 700 */ 701 static void 702 ataident(Drive *dp) 703 { 704 Controller *cp; 705 char *buf; 706 Ident *ip; 707 char id[21]; 708 709 cp = dp->cp; 710 buf = smalloc(Maxxfer); 711 qlock(cp); 712 if(waserror()){ 713 cp->buf = 0; 714 qunlock(cp); 715 free(buf); 716 nexterror(); 717 } 718 719 cmdreadywait(dp); 720 721 ilock(&cp->reglock); 722 cp->nsecs = 1; 723 cp->sofar = 0; 724 cp->cmd = Cident; 725 cp->dp = dp; 726 cp->buf = buf; 727 outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4)); 728 outb(cp->pbase+Pcmd, Cident); 729 iunlock(&cp->reglock); 730 731 atasleep(cp, 5000); 732 if(cp->status & Serr){ 733 DPRINT("bad disk ident status\n"); 734 error(Eio); 735 } 736 ip = (Ident*)buf; 737 738 /* 739 * this function appears to respond with an extra interrupt after 740 * the ident information is read, except on the safari. The following 741 * delay gives this extra interrupt a chance to happen while we are quiet. 742 * Otherwise, the interrupt may come during a subsequent read or write, 743 * causing a panic and much confusion. 744 */ 745 if (cp->cmd == Cident2) 746 tsleep(&cp->r, return0, 0, 10); 747 748 memmove(id, ip->model, sizeof(id)-1); 749 id[sizeof(id)-1] = 0; 750 751 if(ip->capabilities & (1<<9)){ 752 dp->lba = 1; 753 dp->sectors = (ip->lbasecs[0]) | (ip->lbasecs[1]<<16); 754 dp->cap = dp->bytes * dp->sectors; 755 /*print("\nata%d model %s with %d lba sectors\n", dp->drive, id, dp->sectors);/**/ 756 } else { 757 dp->lba = 0; 758 759 /* use default (unformatted) settings */ 760 dp->cyl = ip->cyls; 761 dp->heads = ip->heads; 762 dp->sectors = ip->s2t; 763 /*print("\nata%d model %s with default %d cyl %d head %d sec\n", dp->drive, 764 id, dp->cyl, dp->heads, dp->sectors);/**/ 765 766 if(ip->cvalid&(1<<0)){ 767 /* use current settings */ 768 dp->cyl = ip->ccyls; 769 dp->heads = ip->cheads; 770 dp->sectors = ip->cs2t; 771 /*print("\tchanged to %d cyl %d head %d sec\n", dp->cyl, dp->heads, dp->sectors);/**/ 772 } 773 dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; 774 } 775 cp->lastcmd = cp->cmd; 776 cp->cmd = 0; 777 cp->buf = 0; 778 free(buf); 779 poperror(); 780 qunlock(cp); 781 } 782 783 /* 784 * probe the given sector to see if it exists 785 */ 786 static int 787 ataprobe(Drive *dp, int cyl, int sec, int head) 788 { 789 Controller *cp; 790 char *buf; 791 int rv; 792 793 cp = dp->cp; 794 buf = smalloc(Maxxfer); 795 qlock(cp); 796 if(waserror()){ 797 free(buf); 798 qunlock(cp); 799 nexterror(); 800 } 801 802 cmdreadywait(dp); 803 804 ilock(&cp->reglock); 805 cp->cmd = Cread; 806 cp->dp = dp; 807 cp->status = 0; 808 cp->nsecs = 1; 809 cp->sofar = 0; 810 811 outb(cp->pbase+Pcount, 1); 812 outb(cp->pbase+Psector, sec+1); 813 outb(cp->pbase+Pdh, DHmagic | head | (dp->lba<<6) | (dp->drive<<4)); 814 outb(cp->pbase+Pcyllsb, cyl); 815 outb(cp->pbase+Pcylmsb, cyl>>8); 816 outb(cp->pbase+Pcmd, Cread); 817 iunlock(&cp->reglock); 818 819 atasleep(cp, 5000); 820 821 if(cp->status & Serr) 822 rv = -1; 823 else 824 rv = 0; 825 826 cp->buf = 0; 827 free(buf); 828 poperror(); 829 qunlock(cp); 830 return rv; 831 } 832 833 /* 834 * figure out the drive parameters 835 */ 836 static void 837 ataparams(Drive *dp) 838 { 839 int i, hi, lo; 840 841 /* 842 * first try the easy way, ask the drive and make sure it 843 * isn't lying. 844 */ 845 dp->bytes = 512; 846 ataident(dp); 847 if(dp->lba){ 848 i = dp->sectors - 1; 849 if(ataprobe(dp, (i>>8)&0xffff, (i&0xff)-1, (i>>24)&0xf) == 0) 850 return; 851 } else { 852 if(ataprobe(dp, dp->cyl-1, dp->sectors-1, dp->heads-1) == 0) 853 return; 854 } 855 856 /* 857 * the drive lied, determine parameters by seeing which ones 858 * work to read sectors. 859 */ 860 dp->lba = 0; 861 for(i = 0; i < 32; i++) 862 if(ataprobe(dp, 0, 0, i) < 0) 863 break; 864 dp->heads = i; 865 for(i = 0; i < 128; i++) 866 if(ataprobe(dp, 0, i, 0) < 0) 867 break; 868 dp->sectors = i; 869 for(i = 512; ; i += 512) 870 if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) 871 break; 872 lo = i - 512; 873 hi = i; 874 for(; hi-lo > 1;){ 875 i = lo + (hi - lo)/2; 876 if(ataprobe(dp, i, dp->sectors-1, dp->heads-1) < 0) 877 hi = i; 878 else 879 lo = i; 880 } 881 dp->cyl = lo + 1; 882 dp->cap = dp->bytes * dp->cyl * dp->heads * dp->sectors; 883 } 884 885 /* 886 * Read block replacement table. 887 * The table is just ascii block numbers. 888 */ 889 static void 890 atareplinit(Drive *dp) 891 { 892 char *line[Nrepl+1]; 893 char *field[1]; 894 ulong n; 895 int i; 896 char *buf; 897 898 /* 899 * check the partition is big enough 900 */ 901 if(dp->repl.p->end - dp->repl.p->start < Nrepl+1){ 902 dp->repl.p = 0; 903 return; 904 } 905 906 buf = smalloc(Maxxfer); 907 if(waserror()){ 908 free(buf); 909 nexterror(); 910 } 911 912 /* 913 * read replacement table from disk, null terminate 914 */ 915 ataxfer(dp, dp->repl.p, Cread, 0, dp->bytes, buf); 916 buf[dp->bytes-1] = 0; 917 918 /* 919 * parse replacement table. 920 */ 921 n = getfields(buf, line, Nrepl+1, 1, "\n"); 922 if(strncmp(line[0], REPLMAGIC, sizeof(REPLMAGIC)-1)){ 923 dp->repl.p = 0; 924 } else { 925 for(dp->repl.nrepl = 0, i = 1; i < n; i++, dp->repl.nrepl++){ 926 if(getfields(line[i], field, 1, 1, " ") != 1) 927 break; 928 dp->repl.blk[dp->repl.nrepl] = strtoul(field[0], 0, 0); 929 if(dp->repl.blk[dp->repl.nrepl] <= 0) 930 break; 931 } 932 } 933 free(buf); 934 poperror(); 935 } 936 937 /* 938 * read partition table. The partition table is just ascii strings. 939 */ 940 static void 941 atapart(Drive *dp) 942 { 943 Partition *pp; 944 char *line[Npart+1]; 945 char *field[3]; 946 ulong n; 947 int i; 948 char *buf; 949 950 sprint(dp->vol, "hd%d", dp - ata); 951 952 /* 953 * we always have a partition for the whole disk 954 * and one for the partition table 955 */ 956 pp = &dp->p[0]; 957 strcpy(pp->name, "disk"); 958 pp->start = 0; 959 pp->end = dp->cap / dp->bytes; 960 pp++; 961 strcpy(pp->name, "partition"); 962 pp->start = dp->p[0].end - 1; 963 pp->end = dp->p[0].end; 964 pp++; 965 dp->npart = 2; 966 967 /* 968 * initialise the bad-block replacement info 969 */ 970 dp->repl.p = 0; 971 972 buf = smalloc(Maxxfer); 973 if(waserror()){ 974 free(buf); 975 nexterror(); 976 } 977 978 /* 979 * read last sector from disk, null terminate. This used 980 * to be the sector we used for the partition tables. 981 * However, this sector is special on some PC's so we've 982 * started to use the second last sector as the partition 983 * table instead. To avoid reconfiguring all our old systems 984 * we first look to see if there is a valid partition 985 * table in the last sector. If so, we use it. Otherwise 986 * we switch to the second last. 987 */ 988 ataxfer(dp, dp->p+1, Cread, 0, dp->bytes, buf); 989 buf[dp->bytes-1] = 0; 990 n = getfields(buf, line, Npart+1, 1, "\n"); 991 if(n == 0 || strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1)){ 992 dp->p[0].end--; 993 dp->p[1].start--; 994 dp->p[1].end--; 995 ataxfer(dp, dp->p+1, Cread, 0, dp->bytes, buf); 996 buf[dp->bytes-1] = 0; 997 n = getfields(buf, line, Npart+1, 1, "\n"); 998 } 999 1000 /* 1001 * parse partition table. 1002 */ 1003 if(n > 0 && strncmp(line[0], PARTMAGIC, sizeof(PARTMAGIC)-1) == 0){ 1004 for(i = 1; i < n; i++){ 1005 switch(getfields(line[i], field, 3, 1, " ")) { 1006 case 2: 1007 if(strcmp(field[0], "unit") == 0) 1008 strncpy(dp->vol, field[1], NAMELEN); 1009 break; 1010 case 3: 1011 strncpy(pp->name, field[0], NAMELEN); 1012 if(strncmp(pp->name, "repl", NAMELEN) == 0) 1013 dp->repl.p = pp; 1014 pp->start = strtoul(field[1], 0, 0); 1015 pp->end = strtoul(field[2], 0, 0); 1016 if(pp->start > pp->end || pp->end > dp->p[0].end) 1017 break; 1018 dp->npart++; 1019 pp++; 1020 } 1021 } 1022 } 1023 free(buf); 1024 poperror(); 1025 1026 if(dp->repl.p) 1027 atareplinit(dp); 1028 } 1029 1030 enum 1031 { 1032 Maxloop= 10000, 1033 }; 1034 1035 /* 1036 * we get an interrupt for every sector transferred 1037 */ 1038 static void 1039 ataintr(Ureg*, void *arg) 1040 { 1041 Controller *cp; 1042 Drive *dp; 1043 long loop; 1044 char *addr; 1045 1046 cp = arg; 1047 dp = cp->dp; 1048 1049 ilock(&cp->reglock); 1050 1051 loop = 0; 1052 while((cp->status = inb(cp->pbase+Pstatus)) & Sbusy){ 1053 if(++loop > Maxloop) { 1054 DPRINT("cmd=%lux status=%lux\n", 1055 cp->cmd, inb(cp->pbase+Pstatus)); 1056 panic("ataintr: wait busy"); 1057 } 1058 } 1059 1060 switch(cp->cmd){ 1061 case Cwrite: 1062 if(cp->status & Serr){ 1063 cp->lastcmd = cp->cmd; 1064 cp->cmd = 0; 1065 cp->error = inb(cp->pbase+Perror); 1066 wakeup(&cp->r); 1067 break; 1068 } 1069 cp->sofar++; 1070 if(cp->sofar < cp->nsecs){ 1071 loop = 0; 1072 while(((cp->status = inb(cp->pbase+Pstatus)) & Sdrq) == 0) 1073 if(++loop > Maxloop) { 1074 DPRINT("cmd=%lux status=%lux\n", 1075 cp->cmd, inb(cp->pbase+Pstatus)); 1076 panic("ataintr: write"); 1077 } 1078 addr = cp->buf; 1079 if(addr){ 1080 addr += cp->sofar*dp->bytes; 1081 outss(cp->pbase+Pdata, addr, dp->bytes/2); 1082 } 1083 } else{ 1084 cp->lastcmd = cp->cmd; 1085 cp->cmd = 0; 1086 wakeup(&cp->r); 1087 } 1088 break; 1089 case Cread: 1090 case Cident: 1091 loop = 0; 1092 while((cp->status & (Serr|Sdrq)) == 0){ 1093 if(++loop > Maxloop) { 1094 DPRINT("cmd=%lux status=%lux\n", 1095 cp->cmd, inb(cp->pbase+Pstatus)); 1096 panic("ataintr: read/ident"); 1097 } 1098 cp->status = inb(cp->pbase+Pstatus); 1099 } 1100 if(cp->status & Serr){ 1101 cp->lastcmd = cp->cmd; 1102 cp->cmd = 0; 1103 cp->error = inb(cp->pbase+Perror); 1104 wakeup(&cp->r); 1105 break; 1106 } 1107 addr = cp->buf; 1108 if(addr){ 1109 addr += cp->sofar*dp->bytes; 1110 inss(cp->pbase+Pdata, addr, dp->bytes/2); 1111 } 1112 cp->sofar++; 1113 if(cp->sofar > cp->nsecs) 1114 print("ataintr %d %d\n", cp->sofar, cp->nsecs); 1115 if(cp->sofar >= cp->nsecs){ 1116 cp->lastcmd = cp->cmd; 1117 if (cp->cmd == Cread) 1118 cp->cmd = 0; 1119 else 1120 cp->cmd = Cident2; 1121 wakeup(&cp->r); 1122 } 1123 break; 1124 case Cinitparam: 1125 case Csetbuf: 1126 case Cidle: 1127 case Cstandby: 1128 case Cpowerdown: 1129 cp->lastcmd = cp->cmd; 1130 cp->cmd = 0; 1131 wakeup(&cp->r); 1132 break; 1133 case Cident2: 1134 cp->lastcmd = cp->cmd; 1135 cp->cmd = 0; 1136 break; 1137 default: 1138 print("weird disk interrupt, cmd=%.2ux, lastcmd= %.2ux status=%.2ux\n", 1139 cp->cmd, cp->lastcmd, cp->status); 1140 break; 1141 } 1142 1143 iunlock(&cp->reglock); 1144 } 1145 1146 void 1147 hardclock(void) 1148 { 1149 int drive; 1150 Drive *dp; 1151 Controller *cp; 1152 int diff; 1153 1154 if(spindowntime <= 0) 1155 return; 1156 1157 for(drive = 0; drive < nhard; drive++){ 1158 dp = &ata[drive]; 1159 cp = dp->cp; 1160 1161 diff = TK2SEC(m->ticks - dp->usetime); 1162 if((dp->state == Sspinning) && (diff >= spindowntime)){ 1163 ilock(&cp->reglock); 1164 cp->cmd = Cstandby; 1165 outb(cp->pbase+Pcount, 0); 1166 outb(cp->pbase+Pdh, DHmagic | (dp->drive<<4) | 0); 1167 outb(cp->pbase+Pcmd, cp->cmd); 1168 iunlock(&cp->reglock); 1169 dp->state = Sstandby; 1170 } 1171 } 1172 } 1173 1174 Dev atadevtab = { 1175 'H', 1176 "ata", 1177 1178 devreset, 1179 atainit, 1180 ataattach, 1181 devdetach, 1182 devclone, 1183 atawalk, 1184 atastat, 1185 ataopen, 1186 devcreate, 1187 ataclose, 1188 ataread, 1189 devbread, 1190 atawrite, 1191 devbwrite, 1192 devremove, 1193 devwstat, 1194 }; 1195