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