Annotation of lucent/sys/src/9/port/f002551, 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: #include       "devtab.h"
        !             9: 
        !            10: /* Intel 82077A (8272A compatible) floppy controller */
        !            11: 
        !            12: /* This module expects the following functions to be defined
        !            13:  * elsewhere: 
        !            14:  * 
        !            15:  * inb()
        !            16:  * outb()
        !            17:  * floppyexec()
        !            18:  * floppyeject() 
        !            19:  * floppysetup0()
        !            20:  * floppysetup1()
        !            21:  * dmasetup()
        !            22:  * dmaend()
        !            23:  * 
        !            24:  * On DMA systems, floppyexec() should be an empty function; 
        !            25:  * on non-DMA systems, dmaend() should be an empty function; 
        !            26:  * dmasetup() may enforce maximum transfer sizes. 
        !            27:  */
        !            28: 
        !            29: enum {
        !            30:        /* file types */
        !            31:        Qdir=           0, 
        !            32:        Qdata=          (1<<2),
        !            33:        Qctl=           (2<<2),
        !            34:        Qmask=          (3<<2),
        !            35: 
        !            36:        DMAchan=        2,      /* floppy dma channel */
        !            37: };
        !            38: 
        !            39: #define DPRINT if(floppydebug)kprint
        !            40: int floppydebug;
        !            41: 
        !            42: /*
        !            43:  *  types of drive (from PC equipment byte)
        !            44:  */
        !            45: enum
        !            46: {
        !            47:        Tnone=          0,
        !            48:        T360kb=         1,
        !            49:        T1200kb=        2,
        !            50:        T720kb=         3,
        !            51:        T1440kb=        4,
        !            52: };
        !            53: 
        !            54: FType floppytype[] =
        !            55: {
        !            56:  { "3½HD",    T1440kb, 512, 18, 2, 1, 80, 0x1B, 0x54, 0, },
        !            57:  { "3½DD",    T1440kb, 512,  9, 2, 1, 80, 0x1B, 0x54, 2, },
        !            58:  { "3½DD",    T720kb,  512,  9, 2, 1, 80, 0x1B, 0x54, 2, },
        !            59:  { "5¼HD",    T1200kb, 512, 15, 2, 1, 80, 0x2A, 0x50, 0, },
        !            60:  { "5¼DD",    T1200kb, 512,  9, 2, 2, 40, 0x2A, 0x50, 1, },
        !            61:  { "ATT3B1",   T1200kb, 512,  8, 2, 2, 48, 0x2A, 0x50, 1, },
        !            62:  { "5¼DD",    T360kb,  512,  9, 2, 1, 40, 0x2A, 0x50, 2, },
        !            63: };
        !            64: #define NTYPES (sizeof(floppytype)/sizeof(FType))
        !            65: 
        !            66: /*
        !            67:  *  bytes per sector encoding for the controller.
        !            68:  *  - index for b2c is is (bytes per sector/128).
        !            69:  *  - index for c2b is code from b2c
        !            70:  */
        !            71: static int b2c[] =
        !            72: {
        !            73: [1]    0,
        !            74: [2]    1,
        !            75: [4]    2,
        !            76: [8]    3,
        !            77: };
        !            78: static int c2b[] =
        !            79: {
        !            80:        128,
        !            81:        256,
        !            82:        512,
        !            83:        1024,
        !            84: };
        !            85: 
        !            86: FController    fl;
        !            87: 
        !            88: #define MOTORBIT(i)    (1<<((i)+4))
        !            89: 
        !            90: /*
        !            91:  *  predeclared
        !            92:  */
        !            93: static void    floppykproc(void*);
        !            94: static void    floppypos(FDrive*,long);
        !            95: static int     floppyrecal(FDrive*);
        !            96: static void    floppyrevive(void);
        !            97: static long    floppyseek(FDrive*, long);
        !            98: static int     floppysense(void);
        !            99: static void    floppywait(void);
        !           100: static long    floppyxfer(FDrive*, int, void*, long, long);
        !           101: static void    floppyformat(FDrive*, char*);
        !           102: static int     cmddone(void*);
        !           103: void Xdelay(int);
        !           104: 
        !           105: Dirtab floppydir[]={
        !           106:        "fd0disk",              {Qdata + 0},    0,      0666,
        !           107:        "fd0ctl",               {Qctl + 0},     0,      0666,
        !           108:        "fd1disk",              {Qdata + 1},    0,      0666,
        !           109:        "fd1ctl",               {Qctl + 1},     0,      0666,
        !           110:        "fd2disk",              {Qdata + 2},    0,      0666,
        !           111:        "fd2ctl",               {Qctl + 2},     0,      0666,
        !           112:        "fd3disk",              {Qdata + 3},    0,      0666,
        !           113:        "fd3ctl",               {Qctl + 3},     0,      0666,
        !           114: };
        !           115: #define NFDIR  2       /* directory entries/drive */
        !           116: 
        !           117: static void
        !           118: fldump(void)
        !           119: {
        !           120:        DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb),
        !           121:                inb(Pdor), inb(Pmsr), inb(Pdir));
        !           122: }
        !           123: 
        !           124: /*
        !           125:  *  set floppy drive to its default type
        !           126:  */
        !           127: void
        !           128: floppysetdef(FDrive *dp)
        !           129: {
        !           130:        FType *t;
        !           131: 
        !           132:        for(t = floppytype; t < &floppytype[NTYPES]; t++)
        !           133:                if(dp->dt == t->dt){
        !           134:                        dp->t = t;
        !           135:                        floppydir[NFDIR*dp->dev].length = dp->t->cap;
        !           136:                        break;
        !           137:                }
        !           138: }
        !           139: 
        !           140: void
        !           141: floppyreset(void)
        !           142: {
        !           143:        FDrive *dp;
        !           144:        FType *t;
        !           145:        ulong maxtsize;
        !           146:        
        !           147:        floppysetup0(&fl);
        !           148: 
        !           149:        /*
        !           150:         *  init dependent parameters
        !           151:         */
        !           152:        maxtsize = 0;
        !           153:        for(t = floppytype; t < &floppytype[NTYPES]; t++){
        !           154:                t->cap = t->bytes * t->heads * t->sectors * t->tracks;
        !           155:                t->bcode = b2c[t->bytes/128];
        !           156:                t->tsize = t->bytes * t->sectors;
        !           157:                if(maxtsize < t->tsize)
        !           158:                        maxtsize = t->tsize;
        !           159:        }
        !           160: 
        !           161:        /*
        !           162:         *  allocate the drive storage
        !           163:         */
        !           164:        fl.d = xalloc(conf.nfloppy*sizeof(FDrive));
        !           165:        fl.selected = fl.d;
        !           166: 
        !           167:        /*
        !           168:         *  stop the motors
        !           169:         */
        !           170:        fl.motor = 0;
        !           171:        delay(10);
        !           172:        outb(Pdor, fl.motor | Fintena | Fena);
        !           173:        delay(10);
        !           174: 
        !           175:        /*
        !           176:         *  init drives
        !           177:         */
        !           178:        for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){
        !           179:                dp->dev = dp - fl.d;
        !           180:                dp->dt = T1440kb;
        !           181:                floppysetdef(dp);
        !           182:                dp->cyl = -1;                   /* because we don't know */
        !           183:                dp->cache = (uchar*)xspanalloc(maxtsize, BY2PG, 64*1024);
        !           184:                dp->ccyl = -1;
        !           185:                dp->vers = 1;
        !           186:        }
        !           187: 
        !           188:        /*
        !           189:         *  first operation will recalibrate
        !           190:         */
        !           191:        fl.confused = 1;
        !           192: 
        !           193:        floppysetup1(&fl);
        !           194: }
        !           195: 
        !           196: void
        !           197: floppyinit(void)
        !           198: {
        !           199: }
        !           200: 
        !           201: Chan*
        !           202: floppyattach(char *spec)
        !           203: {
        !           204:        static int kstarted;
        !           205: 
        !           206:        if(kstarted == 0){
        !           207:                /*
        !           208:                 *  watchdog to turn off the motors
        !           209:                 */
        !           210:                kstarted = 1;
        !           211:                kproc("floppy", floppykproc, 0);
        !           212:        }
        !           213:        return devattach('f', spec);
        !           214: }
        !           215: 
        !           216: Chan*
        !           217: floppyclone(Chan *c, Chan *nc)
        !           218: {
        !           219:        return devclone(c, nc);
        !           220: }
        !           221: 
        !           222: int
        !           223: floppywalk(Chan *c, char *name)
        !           224: {
        !           225:        return devwalk(c, name, floppydir, conf.nfloppy*NFDIR, devgen);
        !           226: }
        !           227: 
        !           228: void
        !           229: floppystat(Chan *c, char *dp)
        !           230: {
        !           231:        devstat(c, dp, floppydir, conf.nfloppy*NFDIR, devgen);
        !           232: }
        !           233: 
        !           234: Chan*
        !           235: floppyopen(Chan *c, int omode)
        !           236: {
        !           237:        return devopen(c, omode, floppydir, conf.nfloppy*NFDIR, devgen);
        !           238: }
        !           239: 
        !           240: void
        !           241: floppycreate(Chan *c, char *name, int omode, ulong perm)
        !           242: {
        !           243:        USED(c, name, omode, perm);
        !           244:        error(Eperm);
        !           245: }
        !           246: 
        !           247: void
        !           248: floppyclose(Chan *c)
        !           249: {
        !           250:        USED(c);
        !           251: }
        !           252: 
        !           253: void
        !           254: floppyremove(Chan *c)
        !           255: {
        !           256:        USED(c);
        !           257:        error(Eperm);
        !           258: }
        !           259: 
        !           260: void
        !           261: floppywstat(Chan *c, char *dp)
        !           262: {
        !           263:        USED(c, dp);
        !           264:        error(Eperm);
        !           265: }
        !           266: 
        !           267: static void
        !           268: islegal(ulong offset, long n, FDrive *dp)
        !           269: {
        !           270:        if(offset % dp->t->bytes)
        !           271:                error(Ebadarg);
        !           272:        if(n % dp->t->bytes)
        !           273:                error(Ebadarg);
        !           274: }
        !           275: 
        !           276: /*
        !           277:  *  check if the floppy has been replaced under foot.  cause
        !           278:  *  an error if it has.
        !           279:  *
        !           280:  *  a seek and a read clears the condition.  this was determined
        !           281:  *  experimentally, there has to be a better way.
        !           282:  *
        !           283:  *  if the read fails, cycle through the possible floppy
        !           284:  *  density till one works or we've cycled through all
        !           285:  *  possibilities for this drive.
        !           286:  */
        !           287: static void
        !           288: changed(Chan *c, FDrive *dp)
        !           289: {
        !           290:        ulong old;
        !           291:        FType *start;
        !           292: 
        !           293:        /*
        !           294:         *  if floppy has changed or first time through
        !           295:         */
        !           296:        if((inb(Pdir)&Fchange) || dp->vers == 0){
        !           297:                DPRINT("changed\n");
        !           298:                fldump();
        !           299:                dp->vers++;
        !           300:                floppysetdef(dp);
        !           301:                start = dp->t;
        !           302:                dp->confused = 1;       /* make floppyon recal */
        !           303:                floppyon(dp);
        !           304:                floppyseek(dp, dp->t->heads*dp->t->tsize);
        !           305:                while(waserror()){
        !           306:                        while(++dp->t){
        !           307:                                if(dp->t == &floppytype[NTYPES])
        !           308:                                        dp->t = floppytype;
        !           309:                                if(dp->dt == dp->t->dt)
        !           310:                                        break;
        !           311:                        }
        !           312:                        floppydir[NFDIR*dp->dev].length = dp->t->cap;
        !           313:                        floppyon(dp);
        !           314:                        DPRINT("changed: trying %s\n", dp->t->name);
        !           315:                        fldump();
        !           316:                        if(dp->t == start)
        !           317:                                nexterror();
        !           318:                }
        !           319:                floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize);
        !           320:                poperror();
        !           321:        }
        !           322: 
        !           323:        old = c->qid.vers;
        !           324:        c->qid.vers = dp->vers;
        !           325:        if(old && old != dp->vers)
        !           326:                error(Eio);
        !           327: }
        !           328: 
        !           329: static int
        !           330: readtrack(FDrive *dp, int cyl, int head)
        !           331: {
        !           332:        int i, nn, sofar;
        !           333:        ulong pos;
        !           334: 
        !           335:        nn = dp->t->tsize;
        !           336:        if(dp->ccyl==cyl && dp->chead==head)
        !           337:                return nn;
        !           338:        pos = (cyl*dp->t->heads+head) * nn;
        !           339:        for(sofar = 0; sofar < nn; sofar += i){
        !           340:                dp->ccyl = -1;
        !           341:                i = floppyxfer(dp, Fread, dp->cache + sofar, pos + sofar, nn - sofar);
        !           342:                if(i <= 0)
        !           343:                        return -1;
        !           344:        }
        !           345:        dp->ccyl = cyl;
        !           346:        dp->chead = head;
        !           347:        return nn;
        !           348: }
        !           349: 
        !           350: long
        !           351: floppyread(Chan *c, void *a, long n, ulong offset)
        !           352: {
        !           353:        FDrive *dp;
        !           354:        long rv;
        !           355:        int sec, head, cyl;
        !           356:        long len;
        !           357:        uchar *aa;
        !           358: 
        !           359:        if(c->qid.path == CHDIR)
        !           360:                return devdirread(c, a, n, floppydir, conf.nfloppy*NFDIR, devgen);
        !           361: 
        !           362:        rv = 0;
        !           363:        dp = &fl.d[c->qid.path & ~Qmask];
        !           364:        switch ((int)(c->qid.path & Qmask)) {
        !           365:        case Qdata:
        !           366:                islegal(offset, n, dp);
        !           367:                aa = a;
        !           368: 
        !           369:                qlock(&fl);
        !           370:                if(waserror()){
        !           371:                        qunlock(&fl);
        !           372:                        nexterror();
        !           373:                }
        !           374:                floppyon(dp);
        !           375:                changed(c, dp);
        !           376:                for(rv = 0; rv < n; rv += len){
        !           377:                        /*
        !           378:                         *  all xfers come out of the track cache
        !           379:                         */
        !           380:                        dp->len = n - rv;
        !           381:                        floppypos(dp, offset+rv);
        !           382:                        cyl = dp->tcyl;
        !           383:                        head = dp->thead;
        !           384:                        len = dp->len;
        !           385:                        sec = dp->tsec;
        !           386:                        if(readtrack(dp, cyl, head) < 0)
        !           387:                                break;
        !           388:                        memmove(aa+rv, dp->cache + (sec-1)*dp->t->bytes, len);
        !           389:                }
        !           390:                qunlock(&fl);
        !           391:                poperror();
        !           392: 
        !           393:                break;
        !           394:        case Qctl:
        !           395:                return readstr(offset, a, n, dp->t->name);
        !           396:        default:
        !           397:                panic("floppyread: bad qid");
        !           398:        }
        !           399: 
        !           400:        return rv;
        !           401: }
        !           402: 
        !           403: #define SNCMP(a, b) strncmp(a, b, sizeof(b)-1)
        !           404: long
        !           405: floppywrite(Chan *c, void *a, long n, ulong offset)
        !           406: {
        !           407:        FDrive *dp;
        !           408:        long rv, i;
        !           409:        char *aa = a;
        !           410:        char ctlmsg[64];
        !           411: 
        !           412:        rv = 0;
        !           413:        dp = &fl.d[c->qid.path & ~Qmask];
        !           414:        switch ((int)(c->qid.path & Qmask)) {
        !           415:        case Qdata:
        !           416:                islegal(offset, n, dp);
        !           417:                qlock(&fl);
        !           418:                if(waserror()){
        !           419:                        qunlock(&fl);
        !           420:                        nexterror();
        !           421:                }
        !           422:                floppyon(dp);
        !           423:                changed(c, dp);
        !           424:                for(rv = 0; rv < n; rv += i){
        !           425:                        floppypos(dp, offset+rv);
        !           426:                        if(dp->tcyl == dp->ccyl)
        !           427:                                dp->ccyl = -1;
        !           428:                        i = floppyxfer(dp, Fwrite, aa+rv, offset+rv, n-rv);
        !           429:                        if(i < 0)
        !           430:                                break;
        !           431:                        if(i == 0)
        !           432:                                error(Eio);
        !           433:                }
        !           434:                qunlock(&fl);
        !           435:                poperror();
        !           436:                break;
        !           437:        case Qctl:
        !           438:                rv = n;
        !           439:                qlock(&fl);
        !           440:                if(waserror()){
        !           441:                        qunlock(&fl);
        !           442:                        nexterror();
        !           443:                }
        !           444:                if(n >= sizeof(ctlmsg))
        !           445:                        n = sizeof(ctlmsg) - 1;
        !           446:                memmove(ctlmsg, aa, n);
        !           447:                ctlmsg[n] = 0;
        !           448:                if(SNCMP(ctlmsg, "eject") == 0){
        !           449:                        floppyeject(dp);
        !           450:                } else if(SNCMP(ctlmsg, "reset") == 0){
        !           451:                        fl.confused = 1;
        !           452:                        floppyon(dp);
        !           453:                } else if(SNCMP(ctlmsg, "format") == 0){
        !           454:                        floppyformat(dp, ctlmsg);
        !           455:                } else if(SNCMP(ctlmsg, "debug") == 0){
        !           456:                        floppydebug = 1;
        !           457:                } else
        !           458:                        error(Ebadctl);
        !           459:                poperror();
        !           460:                qunlock(&fl);
        !           461:                break;
        !           462:        default:
        !           463:                panic("floppywrite: bad qid");
        !           464:        }
        !           465: 
        !           466:        return rv;
        !           467: }
        !           468: 
        !           469: static void
        !           470: floppykproc(void *a)
        !           471: {
        !           472:        FDrive *dp;
        !           473: 
        !           474:        USED(a);
        !           475:        while(waserror())
        !           476:                ;
        !           477:        for(;;){
        !           478:                for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++){
        !           479:                        if((fl.motor&MOTORBIT(dp->dev))
        !           480:                        && TK2SEC(m->ticks - dp->lasttouched) > 5
        !           481:                        && canqlock(&fl)){
        !           482:                                if(TK2SEC(m->ticks - dp->lasttouched) > 5)
        !           483:                                        floppyoff(dp);
        !           484:                                qunlock(&fl);
        !           485:                        }
        !           486:                }
        !           487:                tsleep(&fl.kr, return0, 0, 1000);
        !           488:        }
        !           489: }
        !           490: 
        !           491: /*
        !           492:  *  start a floppy drive's motor.
        !           493:  */
        !           494: void
        !           495: floppyon(FDrive *dp)
        !           496: {
        !           497:        int alreadyon;
        !           498:        int tries;
        !           499: 
        !           500:        if(fl.confused)
        !           501:                floppyrevive();
        !           502: 
        !           503:        /* start motor and select drive */
        !           504:        alreadyon = fl.motor & MOTORBIT(dp->dev);
        !           505:        fl.motor |= MOTORBIT(dp->dev);
        !           506:        outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
        !           507:        if(!alreadyon){
        !           508:                /* wait for drive to spin up */
        !           509:                tsleep(&dp->r, return0, 0, 750);
        !           510: 
        !           511:                /* clear any pending interrupts */
        !           512:                floppysense();
        !           513:        }
        !           514: 
        !           515:        /* set transfer rate */
        !           516:        if(fl.rate != dp->t->rate){
        !           517:                fl.rate = dp->t->rate;
        !           518:                outb(Pdsr, fl.rate);
        !           519:        }
        !           520: 
        !           521:        /* get drive to a known cylinder */
        !           522:        if(dp->confused)
        !           523:                for(tries = 0; tries < 4; tries++)
        !           524:                        if(floppyrecal(dp) >= 0)
        !           525:                                break;
        !           526:        dp->lasttouched = m->ticks;
        !           527:        fl.selected = dp;
        !           528: }
        !           529: 
        !           530: /*
        !           531:  *  stop the floppy if it hasn't been used in 5 seconds
        !           532:  */
        !           533: void
        !           534: floppyoff(FDrive *dp)
        !           535: {
        !           536:        fl.motor &= ~MOTORBIT(dp->dev);
        !           537:        outb(Pdor, fl.motor | Fintena | Fena | dp->dev);
        !           538:        fl.selected = dp;
        !           539: }
        !           540: 
        !           541: /*
        !           542:  *  send a command to the floppy
        !           543:  */
        !           544: int
        !           545: floppycmd(void)
        !           546: {
        !           547:        int i;
        !           548:        int tries;
        !           549: 
        !           550:        fl.nstat = 0;
        !           551:        for(i = 0; i < fl.ncmd; i++){
        !           552:                for(tries = 0; ; tries++){
        !           553:                        if(tries > 1000){
        !           554:                                DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i);
        !           555:                                fldump();
        !           556: 
        !           557:                                /* empty fifo, might have been a bad command */
        !           558:                                floppyresult();
        !           559:                                return -1;
        !           560:                        }
        !           561:                        if((inb(Pmsr)&(Ffrom|Fready)) == Fready)
        !           562:                                break;
        !           563:                }
        !           564:                outb(Pfdata, fl.cmd[i]);
        !           565:        }
        !           566:        return 0;
        !           567: }
        !           568: 
        !           569: /*
        !           570:  *  get a command result from the floppy
        !           571:  *
        !           572:  *  when the controller goes ready waiting for a command
        !           573:  *  (instead of sending results), we're done
        !           574:  * 
        !           575:  */
        !           576: int
        !           577: floppyresult(void)
        !           578: {
        !           579:        int i, s;
        !           580:        int tries;
        !           581: 
        !           582:        /* get the result of the operation */
        !           583:        for(i = 0; i < sizeof(fl.stat); i++){
        !           584:                /* wait for status byte */
        !           585:                for(tries = 0; ; tries++){
        !           586:                        if(tries > 1000){
        !           587:                                DPRINT("floppyresult: %d stats\n", i);
        !           588:                                fldump();
        !           589:                                fl.confused = 1;
        !           590:                                return -1;
        !           591:                        }
        !           592:                        s = inb(Pmsr)&(Ffrom|Fready);
        !           593:                        if(s == Fready){
        !           594:                                fl.nstat = i;
        !           595:                                return fl.nstat;
        !           596:                        }
        !           597:                        if(s == (Ffrom|Fready))
        !           598:                                break;
        !           599:                }
        !           600:                fl.stat[i] = inb(Pfdata);
        !           601:        }
        !           602:        fl.nstat = sizeof(fl.stat);
        !           603:        return fl.nstat;
        !           604: }
        !           605: 
        !           606: /*
        !           607:  *  calculate physical address of a logical byte offset into the disk
        !           608:  *
        !           609:  *  truncate dp->length if it crosses a track boundary
        !           610:  */
        !           611: static void
        !           612: floppypos(FDrive *dp, long off)
        !           613: {
        !           614:        int lsec;
        !           615:        int ltrack;
        !           616:        int end;
        !           617: 
        !           618:        lsec = off/dp->t->bytes;
        !           619:        ltrack = lsec/dp->t->sectors;
        !           620:        dp->tcyl = ltrack/dp->t->heads;
        !           621:        dp->tsec = (lsec % dp->t->sectors) + 1;
        !           622:        dp->thead = (lsec/dp->t->sectors) % dp->t->heads;
        !           623: 
        !           624:        /*
        !           625:         *  can't read across track boundaries.
        !           626:         *  if so, decrement the bytes to be read.
        !           627:         */
        !           628:        end = (ltrack+1)*dp->t->sectors*dp->t->bytes;
        !           629:        if(off+dp->len > end)
        !           630:                dp->len = end - off;
        !           631: }
        !           632: 
        !           633: /*
        !           634:  *  get the interrupt cause from the floppy.
        !           635:  */
        !           636: static int
        !           637: floppysense(void)
        !           638: {
        !           639:        fl.ncmd = 0;
        !           640:        fl.cmd[fl.ncmd++] = Fsense;
        !           641:        if(floppycmd() < 0)
        !           642:                return -1;
        !           643:        if(floppyresult() < 2){
        !           644:                DPRINT("can't read sense response\n");
        !           645:                fldump();
        !           646:                fl.confused = 1;
        !           647:                return -1;
        !           648:        }
        !           649:        return 0;
        !           650: }
        !           651: 
        !           652: static int
        !           653: cmddone(void *a)
        !           654: {
        !           655:        USED(a);
        !           656:        return fl.ncmd == 0;
        !           657: }
        !           658: 
        !           659: /*
        !           660:  *  Wait for a floppy interrupt.  If none occurs in 5 seconds, we
        !           661:  *  may have missed one.  This only happens on some portables which
        !           662:  *  do power management behind our backs.  Call the interrupt
        !           663:  *  routine to try to clear any conditions.
        !           664:  */
        !           665: static void
        !           666: floppywait(void)
        !           667: {
        !           668:        tsleep(&fl.r, cmddone, 0, 5000);
        !           669:        if(!cmddone(0)){
        !           670:                floppyintr(0);
        !           671:                fl.confused = 1;
        !           672:        }
        !           673: }
        !           674: 
        !           675: /*
        !           676:  *  we've lost the floppy position, go to cylinder 0.
        !           677:  */
        !           678: static int
        !           679: floppyrecal(FDrive *dp)
        !           680: {
        !           681:        dp->ccyl = -1;
        !           682:        dp->cyl = -1;
        !           683: 
        !           684:        fl.ncmd = 0;
        !           685:        fl.cmd[fl.ncmd++] = Frecal;
        !           686:        fl.cmd[fl.ncmd++] = dp->dev;
        !           687:        if(floppycmd() < 0)
        !           688:                return -1;
        !           689:        floppywait();
        !           690:        if(fl.nstat < 2){
        !           691:                DPRINT("recalibrate: confused %ux\n", inb(Pmsr));
        !           692:                fl.confused = 1;
        !           693:                return -1;
        !           694:        }
        !           695:        if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
        !           696:                DPRINT("recalibrate: failed\n");
        !           697:                dp->confused = 1;
        !           698:                return -1;
        !           699:        }
        !           700:        dp->cyl = fl.stat[1];
        !           701:        if(dp->cyl != 0){
        !           702:                DPRINT("recalibrate: wrong cylinder %d\n", dp->cyl);
        !           703:                dp->cyl = -1;
        !           704:                dp->confused = 1;
        !           705:                return -1;
        !           706:        }
        !           707: 
        !           708:        dp->confused = 0;
        !           709:        return 0;
        !           710: }
        !           711: 
        !           712: /*
        !           713:  *  if the controller or a specific drive is in a confused state,
        !           714:  *  reset it and get back to a kown state
        !           715:  */
        !           716: void
        !           717: floppyrevive(void)
        !           718: {
        !           719:        FDrive *dp;
        !           720: 
        !           721:        /*
        !           722:         *  reset the controller if it's confused
        !           723:         */
        !           724:        if(fl.confused){
        !           725:                DPRINT("floppyrevive in\n");
        !           726:                fldump();
        !           727: 
        !           728:                /* reset controller and turn all motors off */
        !           729:                splhi();
        !           730:                fl.ncmd = 1;
        !           731:                fl.cmd[0] = 0;
        !           732:                outb(Pdor, 0);
        !           733:                delay(10);
        !           734:                outb(Pdor, Fintena|Fena);
        !           735:                delay(10);
        !           736:                spllo();
        !           737:                fl.motor = 0;
        !           738:                fl.confused = 0;
        !           739:                floppywait();
        !           740: 
        !           741:                /* mark all drives in an unknown state */
        !           742:                for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++)
        !           743:                        dp->confused = 1;
        !           744: 
        !           745:                /* set rate to a known value */
        !           746:                outb(Pdsr, 0);
        !           747:                fl.rate = 0;
        !           748: 
        !           749:                DPRINT("floppyrevive out\n");
        !           750:                fldump();
        !           751:        }
        !           752: }
        !           753: 
        !           754: /*
        !           755:  *  seek to the target cylinder
        !           756:  *
        !           757:  *     interrupt, no results
        !           758:  */
        !           759: static long
        !           760: floppyseek(FDrive *dp, long off)
        !           761: {
        !           762:        floppypos(dp, off);
        !           763:        if(dp->cyl == dp->tcyl)
        !           764:                return dp->tcyl;
        !           765:        dp->cyl = -1;
        !           766: 
        !           767:        fl.ncmd = 0;
        !           768:        fl.cmd[fl.ncmd++] = Fseek;
        !           769:        fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
        !           770:        fl.cmd[fl.ncmd++] = dp->tcyl * dp->t->steps;
        !           771:        if(floppycmd() < 0)
        !           772:                return -1;
        !           773:        floppywait();
        !           774:        if(fl.nstat < 2){
        !           775:                DPRINT("seek: confused\n");
        !           776:                fl.confused = 1;
        !           777:                return -1;
        !           778:        }
        !           779:        if((fl.stat[0] & (Codemask|Seekend)) != Seekend){
        !           780:                DPRINT("seek: failed\n");
        !           781:                dp->confused = 1;
        !           782:                return -1;
        !           783:        }
        !           784: 
        !           785:        dp->cyl = dp->tcyl;
        !           786:        return dp->tcyl;
        !           787: }
        !           788: 
        !           789: /*
        !           790:  *  read or write to floppy.  try up to three times.
        !           791:  */
        !           792: static long
        !           793: floppyxfer(FDrive *dp, int cmd, void *a, long off, long n)
        !           794: {
        !           795:        long offset;
        !           796:        int tries;
        !           797: 
        !           798:        if(off >= dp->t->cap)
        !           799:                return 0;
        !           800:        if(off + n > dp->t->cap)
        !           801:                n = dp->t->cap - off;
        !           802: 
        !           803:        /* retry on error 3 times */
        !           804:        tries = 0;
        !           805:        while(waserror()){
        !           806:                if(tries++ >= 3)
        !           807:                        nexterror();
        !           808:                DPRINT("floppyxfer: retrying\n");
        !           809:                floppyon(dp);
        !           810:        }
        !           811: 
        !           812:        dp->len = n;
        !           813:        if(floppyseek(dp, off) < 0){
        !           814:                DPRINT("xfer: seek failed\n");
        !           815:                dp->confused = 1;
        !           816:                error(Eio);
        !           817:        }
        !           818: 
        !           819:        /*
        !           820:         *  set up the dma (dp->len may be trimmed)
        !           821:         */
        !           822:        if(waserror()){
        !           823:                dmaend(DMAchan);
        !           824:                nexterror();
        !           825:        }
        !           826:        dp->len = dmasetup(DMAchan, a, dp->len, cmd==Fread);
        !           827: 
        !           828:        /*
        !           829:         *  start operation
        !           830:         */
        !           831:        cmd = cmd | (dp->t->heads > 1 ? Fmulti : 0);
        !           832:        fl.ncmd = 0;
        !           833:        fl.cmd[fl.ncmd++] = cmd;
        !           834:        fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev;
        !           835:        fl.cmd[fl.ncmd++] = dp->tcyl;
        !           836:        fl.cmd[fl.ncmd++] = dp->thead;
        !           837:        fl.cmd[fl.ncmd++] = dp->tsec;
        !           838:        fl.cmd[fl.ncmd++] = dp->t->bcode;
        !           839:        fl.cmd[fl.ncmd++] = dp->t->sectors;
        !           840:        fl.cmd[fl.ncmd++] = dp->t->gpl;
        !           841:        fl.cmd[fl.ncmd++] = 0xFF;
        !           842:        if(floppycmd() < 0)
        !           843:                error(Eio);
        !           844: 
        !           845:        /* Poll ready bits and transfer data */
        !           846:        floppyexec((char*)a, dp->len, (cmd & ~Fmulti)==Fread);
        !           847: 
        !           848:        /*
        !           849:         *  give bus to DMA, floppyintr() will read result
        !           850:         */
        !           851:        floppywait();
        !           852:        dmaend(DMAchan);
        !           853:        poperror();
        !           854: 
        !           855:        /*
        !           856:         *  check for errors
        !           857:         */
        !           858:        if(fl.nstat < 7){
        !           859:                DPRINT("xfer: confused\n");
        !           860:                fl.confused = 1;
        !           861:                error(Eio);
        !           862:        }
        !           863:        if((fl.stat[0] & Codemask)!=0 || fl.stat[1] || fl.stat[2]){
        !           864:                DPRINT("xfer: failed %lux %lux %lux\n", fl.stat[0],
        !           865:                        fl.stat[1], fl.stat[2]);
        !           866:                DPRINT("offset %lud len %d\n", off, dp->len);
        !           867:                dp->confused = 1;
        !           868:                error(Eio);
        !           869:        }
        !           870: 
        !           871:        /*
        !           872:         *  check for correct cylinder
        !           873:         */
        !           874:        offset = fl.stat[3] * dp->t->heads + fl.stat[4];
        !           875:        offset = offset*dp->t->sectors + fl.stat[5] - 1;
        !           876:        offset = offset * c2b[fl.stat[6]];
        !           877:        if(offset != off+dp->len){
        !           878:                DPRINT("xfer: ends on wrong cyl\n");
        !           879:                dp->confused = 1;
        !           880:                error(Eio);
        !           881:        }
        !           882:        poperror();
        !           883: 
        !           884:        dp->lasttouched = m->ticks;
        !           885:        return dp->len;
        !           886: }
        !           887: 
        !           888: /*
        !           889:  *  format a track
        !           890:  */
        !           891: static void
        !           892: floppyformat(FDrive *dp, char *params)
        !           893: {
        !           894:        int cyl, h, sec;
        !           895:        ulong track;
        !           896:        uchar *buf, *bp;
        !           897:        FType *t;
        !           898:        char *f[3];
        !           899: 
        !           900:        /*
        !           901:         *  set the type
        !           902:         */
        !           903:        if(getfields(params, f, 3, " ") > 1){
        !           904:                for(t = floppytype; t < &floppytype[NTYPES]; t++){
        !           905:                        if(strcmp(f[1], t->name)==0 && t->dt==dp->dt){
        !           906:                                dp->t = t;
        !           907:                                floppydir[NFDIR*dp->dev].length = dp->t->cap;
        !           908:                                break;
        !           909:                        }
        !           910:                }
        !           911:                if(t >= &floppytype[NTYPES])
        !           912:                        error(Ebadarg);
        !           913:        } else {
        !           914:                floppysetdef(dp);
        !           915:                t = dp->t;
        !           916:        }
        !           917: 
        !           918:        /*
        !           919:         *  buffer for per track info
        !           920:         */
        !           921:        buf = smalloc(t->sectors*4);
        !           922:        if(waserror()){
        !           923:                free(buf);
        !           924:                nexterror();
        !           925:        }
        !           926: 
        !           927:        /* force a recalibrate to cylinder 0 */
        !           928:        dp->confused = 1;
        !           929:        if(!waserror()){
        !           930:                floppyon(dp);
        !           931:                poperror();
        !           932:        }
        !           933: 
        !           934:        /*
        !           935:         *  format a track at time
        !           936:         */
        !           937:        for(track = 0; track < t->tracks*t->heads; track++){
        !           938:                cyl = track/t->heads;
        !           939:                h = track % t->heads;
        !           940: 
        !           941:                /*
        !           942:                 *  seek to track, ignore errors
        !           943:                 */
        !           944:                floppyseek(dp, track*t->tsize);
        !           945:                dp->cyl = cyl;
        !           946:                dp->confused = 0;
        !           947: 
        !           948:                /*
        !           949:                 *  set up the dma (dp->len may be trimmed)
        !           950:                 */
        !           951:                bp = buf;
        !           952:                for(sec = 1; sec <= t->sectors; sec++){
        !           953:                        *bp++ = cyl;
        !           954:                        *bp++ = h;
        !           955:                        *bp++ = sec;
        !           956:                        *bp++ = t->bcode;
        !           957:                }
        !           958:                if(waserror()){
        !           959:                        dmaend(DMAchan);
        !           960:                        nexterror();
        !           961:                }
        !           962:                dmasetup(DMAchan, buf, bp-buf, 0);
        !           963: 
        !           964:                /*
        !           965:                 *  start operation
        !           966:                 */
        !           967:                fl.ncmd = 0;
        !           968:                fl.cmd[fl.ncmd++] = Fformat;
        !           969:                fl.cmd[fl.ncmd++] = (h<<2) | dp->dev;
        !           970:                fl.cmd[fl.ncmd++] = t->bcode;
        !           971:                fl.cmd[fl.ncmd++] = t->sectors;
        !           972:                fl.cmd[fl.ncmd++] = t->fgpl;
        !           973:                fl.cmd[fl.ncmd++] = 0x5a;
        !           974:                if(floppycmd() < 0)
        !           975:                        error(Eio);
        !           976: 
        !           977:                /* Poll ready bits and transfer data */
        !           978:                floppyexec((char *)buf, bp-buf, 0);
        !           979: 
        !           980:                /*
        !           981:                 *  give bus to DMA, floppyintr() will read result
        !           982:                 */
        !           983:                floppywait();
        !           984:                dmaend(DMAchan);
        !           985:                poperror();
        !           986: 
        !           987:                /*
        !           988:                 *  check for errors
        !           989:                 */
        !           990:                if(fl.nstat < 7){
        !           991:                        DPRINT("format: confused\n");
        !           992:                        fl.confused = 1;
        !           993:                        error(Eio);
        !           994:                }
        !           995:                if((fl.stat[0]&Codemask)!=0 || fl.stat[1]|| fl.stat[2]){
        !           996:                        DPRINT("format: failed %lux %lux %lux\n",
        !           997:                                fl.stat[0], fl.stat[1], fl.stat[2]);
        !           998:                        dp->confused = 1;
        !           999:                        error(Eio);
        !          1000:                }
        !          1001:        }
        !          1002:        free(buf);
        !          1003:        dp->confused = 1;
        !          1004:        poperror();
        !          1005: }
        !          1006: 
        !          1007: void
        !          1008: floppyintr(Ureg *ur)
        !          1009: {
        !          1010:        USED(ur);
        !          1011:        switch(fl.cmd[0]&~Fmulti){
        !          1012:        case Fread:
        !          1013:        case Fwrite:
        !          1014:        case Fformat:
        !          1015:        case Fdumpreg: 
        !          1016:                floppyresult();
        !          1017:                break;
        !          1018:        case Fseek:
        !          1019:        case Frecal:
        !          1020:        default:
        !          1021:                floppysense();  /* to clear interrupt */
        !          1022:                break;
        !          1023:        }
        !          1024:        fl.ncmd = 0;
        !          1025:        wakeup(&fl.r);
        !          1026: }

unix.superglobalmegacorp.com

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