Annotation of lucent/sys/src/9/pc/devata.c, revision 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.