Annotation of lucent/sys/src/9/pc/devata.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.