Annotation of lucent/sys/src/9/port/f002551, revision 1.1.1.1

1.1       root        1: #include       "u.h"
                      2: #include       "../port/lib.h"
                      3: #include       "mem.h"
                      4: #include       "dat.h"
                      5: #include       "fns.h"
                      6: #include       "io.h"
                      7: #include       "../port/error.h"
                      8: #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.