From a3fea5bbc7fdb6094887af032dda0266effedea2 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 17 Dec 1992 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1992-12-17 --- pc/devfloppy.c | 80 +++++++++++++++------- pc/devvga.c | 2 + pc/kbd.c | 2 +- port/chan.c | 12 ++-- port/dev.c | 25 ++++--- port/devmnt.c | 3 +- port/net.c | 2 +- port/portdat.h | 2 +- power/fns.h | 1 + power/scsi.c | 179 +++++++++++++++++++++++++++++++------------------ power/trap.c | 4 +- 11 files changed, 200 insertions(+), 112 deletions(-) diff --git a/pc/devfloppy.c b/pc/devfloppy.c index 6937f0c138f6b0a912d5150ec97a84807561a6a0..d0b96073f60fdaf332e1ce64f8c12a29042cf3e1 100644 --- a/pc/devfloppy.c +++ b/pc/devfloppy.c @@ -13,12 +13,16 @@ typedef struct Drive Drive; typedef struct Controller Controller; typedef struct Type Type; -#define DPRINT if(floppydebug)print +#define DPRINT if(floppydebug)kprint int floppydebug; /* bits in the registers */ enum { + /* status registers a & b */ + Psra= 0x3f0, + Psrb= 0x3f1, + /* digital output register */ Pdor= 0x3f2, Fintena= 0x8, /* enable floppy interrupt */ @@ -212,6 +216,13 @@ Dirtab floppydir[]={ }; #define NFDIR 2 /* directory entries/drive */ +static void +fldump(void) +{ + DPRINT("sra %ux srb %ux dor %ux msr %ux dir %ux\n", inb(Psra), inb(Psrb), + inb(Pdor), inb(Pmsr), inb(Pdir)); +} + /* * set floppy drive to its default type */ @@ -380,7 +391,7 @@ islegal(ulong offset, long n, Drive *dp) * * if the read fails, cycle through the possible floppy * density till one works or we've cycled through all - * possibilities. + * possibilities for this drive. */ static void changed(Chan *c, Drive *dp) @@ -392,7 +403,8 @@ changed(Chan *c, Drive *dp) * if floppy has changed or first time through */ if((inb(Pdir)&Fchange) || dp->vers == 0){ -DPRINT("changed: msr %ux dir %ux\n", inb(Pmsr), inb(Pdir)); + DPRINT("changed\n"); + fldump(); dp->vers++; setdef(dp); start = dp->t; @@ -408,9 +420,10 @@ DPRINT("changed: msr %ux dir %ux\n", inb(Pmsr), inb(Pdir)); } floppydir[NFDIR*dp->dev].length = dp->t->cap; floppyon(dp); + DPRINT("changed: trying %s\n", dp->t->name); + fldump(); if(dp->t == start) nexterror(); - DPRINT("changed: trying %s\n", dp->t->name); } floppyxfer(dp, Fread, dp->cache, 0, dp->t->tsize); poperror(); @@ -594,9 +607,14 @@ floppyon(Drive *dp) alreadyon = fl.motor & MOTORBIT(dp->dev); fl.motor |= MOTORBIT(dp->dev); outb(Pdor, fl.motor | Fintena | Fena | dp->dev); - if(!alreadyon) + if(!alreadyon){ + /* wait for drive to spin up */ tsleep(&dp->r, return0, 0, 750); + /* clear any pending interrupts */ + floppysense(); + } + /* set transfer rate */ if(fl.rate != dp->t->rate){ fl.rate = dp->t->rate; @@ -646,10 +664,12 @@ floppycmd(void) fl.nstat = 0; for(i = 0; i < fl.ncmd; i++){ for(tries = 0; ; tries++){ - if(tries > 10000){ - DPRINT("cmd %ux can't be sent (%d %ux)\n", - fl.cmd[0], i, inb(Pmsr)); - fl.confused = 1; + if(tries > 1000){ + DPRINT("cmd %ux can't be sent (%d)\n", fl.cmd[0], i); + fldump(); + + /* empty fifo, might have been a bad command */ + floppyresult(); return -1; } if((inb(Pmsr)&(Ffrom|Fready)) == Fready) @@ -673,24 +693,28 @@ floppyresult(void) int i, s; int tries; + /* get the result of the operation */ for(i = 0; i < sizeof(fl.stat); i++){ + /* wait for status byte */ for(tries = 0; ; tries++){ if(tries > 1000){ + DPRINT("floppyresult: %d stats\n", i); + fldump(); fl.confused = 1; return -1; } s = inb(Pmsr)&(Ffrom|Fready); if(s == Fready){ fl.nstat = i; - return i; + return fl.nstat; } if(s == (Ffrom|Fready)) break; } fl.stat[i] = inb(Pdata); } - fl.nstat = i; - return i; + fl.nstat = sizeof(fl.stat); + return fl.nstat; } /* @@ -732,6 +756,7 @@ floppysense(void) return -1; if(floppyresult() < 2){ DPRINT("can't read sense response\n"); + fldump(); fl.confused = 1; return -1; } @@ -746,12 +771,15 @@ cmddone(void *a) } /* - * wait for a floppy interrupt + * Wait for a floppy interrupt. If none occurs in 5 seconds, we + * may have missed one. This only happens on some portables which + * do power management behind our backs. Call the interrupt + * routine to try to clear any conditions. */ static void floppywait(void) { - tsleep(&fl.r, cmddone, 0, 2000); + tsleep(&fl.r, cmddone, 0, 5000); if(!cmddone(0)) floppyintr(0); } @@ -765,7 +793,6 @@ floppyrecal(Drive *dp) dp->ccyl = -1; dp->cyl = -1; -DPRINT("floppyrecal: msr %ux dir %ux\n", inb(Pmsr), inb(Pdir)); fl.ncmd = 0; fl.cmd[fl.ncmd++] = Frecal; fl.cmd[fl.ncmd++] = dp->dev; @@ -807,22 +834,31 @@ floppyrevive(void) * reset the controller if it's confused */ if(fl.confused){ -DPRINT("floppyrevive: msr %ux dir %ux\n", inb(Pmsr), inb(Pdir)); + DPRINT("floppyrevive in\n"); + fldump(); + /* reset controller and turn all motors off */ splhi(); + fl.ncmd = 1; fl.cmd[0] = 0; outb(Pdor, 0); delay(1); outb(Pdor, Fintena|Fena); spllo(); - for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++) - dp->confused = 1; fl.motor = 0; - floppywait(); fl.confused = 0; + floppywait(); + + /* mark all drives in an unknown state */ + for(dp = fl.d; dp < &fl.d[conf.nfloppy]; dp++) + dp->confused = 1; + + /* set rate to a known value */ outb(Pdsr, 0); fl.rate = 0; -DPRINT("floppyrevive: msr %ux dir %ux\n", inb(Pmsr), inb(Pdir)); + + DPRINT("floppyrevive out\n"); + fldump(); } } @@ -839,7 +875,6 @@ floppyseek(Drive *dp, long off) return dp->tcyl; dp->cyl = -1; - DPRINT("seek: tcyl %d, thead %d\n", dp->tcyl, dp->thead); fl.ncmd = 0; fl.cmd[fl.ncmd++] = Fseek; fl.cmd[fl.ncmd++] = (dp->thead<<2) | dp->dev; @@ -891,9 +926,6 @@ floppyxfer(Drive *dp, int cmd, void *a, long off, long n) error(Eio); } - DPRINT("floppyxfer: tcyl %d, thead %d, tsec %d, addr %lux, n %d\n", - dp->tcyl, dp->thead, dp->tsec, a, dp->len); - /* * set up the dma (dp->len may be trimmed) */ diff --git a/pc/devvga.c b/pc/devvga.c index cba7dc4d699b8d836a333e1c3edc1495e6324851..059a207b5510731942ec1fc853dae46847e0070d 100644 --- a/pc/devvga.c +++ b/pc/devvga.c @@ -297,8 +297,10 @@ vgawrite(Chan *c, void *buf, long n, ulong offset) return n; case Qvgaport: cp = buf; + /* if (offset + n >= 0x8000 || offset < 0x300) error(Ebadarg); + */ for (port=offset; portflag & COPEN) - panic("clone of open file type %c\n", devchar[c->type]); + panic("clone of open file type %C\n", devchar[c->type]); if(nc == 0) nc = newchan(); nc->type = c->type; @@ -130,7 +137,7 @@ devstat(Chan *c, char *db, Dirtab *tab, int ntab, Devgen *gen) convD2M(&dir, db); return; } - print("%s %s: devstat %c %lux\n", u->p->text, u->p->user, + print("%s %s: devstat %C %lux\n", u->p->text, u->p->user, devchar[c->type], c->qid.path); error(Enonexist); case 0: diff --git a/port/devmnt.c b/port/devmnt.c index 06a0f17ef0c40e6bc1eb061aa453775bf7ed4231..ea623731cac7810781b454c0b721bebf50acb0de 100644 --- a/port/devmnt.c +++ b/port/devmnt.c @@ -773,8 +773,7 @@ mntchk(Chan *c) void mntdirfix(uchar *dirbuf, Chan *c) { - dirbuf[DIRLEN-4] = devchar[c->type]; - dirbuf[DIRLEN-3] = 0; + *(ushort*)&dirbuf[DIRLEN-4] = devchar[c->type]; dirbuf[DIRLEN-2] = c->dev; dirbuf[DIRLEN-1] = c->dev>>8; } diff --git a/port/net.c b/port/net.c index 8c18d00de96accb071cac870b1b2bd8d53c23c04..91f677c17b265fb4f5b6450b0f0f337db1139eab 100644 --- a/port/net.c +++ b/port/net.c @@ -151,7 +151,7 @@ netstat(Chan *c, char *db, Network *np) convD2M(&dir, db); return; } - print("netstat %c %lux\n", devchar[c->type], c->qid.path); + print("netstat %C %lux\n", devchar[c->type], c->qid.path); error(Enonexist); case 0: break; diff --git a/port/portdat.h b/port/portdat.h index 5eb5e1fcd8539300b70b24ebf18d1916db6ed9f8..0e7d93676d6026874e4d4e66d68c268c8bf39abc 100644 --- a/port/portdat.h +++ b/port/portdat.h @@ -733,7 +733,7 @@ enum extern Conf conf; extern char* conffile; extern int cpuserver; -extern char* devchar; +extern Rune* devchar; extern Dev devtab[]; extern char eve[]; extern uchar initcode[]; diff --git a/power/fns.h b/power/fns.h index 34d0b354548a3dfc13ae382cac55fb6b187f5aac..4057e329e8334432e28f7c03900d32b6bf51ad7d 100644 --- a/power/fns.h +++ b/power/fns.h @@ -58,6 +58,7 @@ void puttlbx(int, ulong, ulong); int readlog(ulong, char*, ulong); void restfpregs(FPsave*, ulong); #define screenputs syslog +void scsiintr(int); void setvmevec(int, void (*)(int)); void sinit(void); uchar* smap(int, uchar*); diff --git a/power/scsi.c b/power/scsi.c index 287f13ecc296ca53cfa5d9baedd7044995c2b229..93b0e30a0abc9d94a0f063fb22fac94083c82899 100644 --- a/power/scsi.c +++ b/power/scsi.c @@ -34,6 +34,7 @@ enum Rdata = 0x19, /* data register */ Raux = 0x1F, /* auxiliary status register */ Dbr = 0x01, /* data buffer ready */ + Cip = 0x10, /* command in progress */ Intrpend = 0x80, /* interrupt pending */ Creset = 0x00, /* reset */ @@ -60,6 +61,7 @@ typedef struct Target Target; struct Target { QLock; + Lock regs; Rendez; ulong flags; uchar sync; @@ -115,6 +117,15 @@ static Target target[NCtlr][NTarget]; static void dmamap(Target*); +static void +issue(Target *ctlr, uchar cmd) +{ + while(*ctlr->addr & Cip) + ; + *ctlr->addr = Rcmd; + *ctlr->data = cmd; +} + /* * Set up and start a data transfer. This maybe * a continuation. @@ -165,8 +176,7 @@ start(Target *tp) /* * Select and transfer. */ - *dev->addr = Rcmd; - *dev->data = tp->transfer; + issue(dev, tp->transfer); } /* @@ -200,8 +210,7 @@ arbitrate(Target *dev) *dev->data = 0x00; /* cmdphase */ *dev->addr = Rdestid; *dev->data = tp->target; - *dev->addr = Rcmd; - *dev->data = CselectATN; + issue(dev, CselectATN); } static int @@ -241,12 +250,13 @@ scsiio(int nbus, Scsi *p, int rw) tp->dmalen = p->data.lim - p->data.base; tp->dmatx = 0; tp->status = 0x6002; + tp->lun = p->lun; tp->clen = p->cmd.lim - p->cmd.base; memmove(tp->cdb, p->cmd.base, tp->clen); s = splhi(); - qlock(ctlr); + lock(&ctlr->regs); /* * Link the target onto the end of the @@ -264,7 +274,7 @@ scsiio(int nbus, Scsi *p, int rw) arbitrate(ctlr); } - qunlock(ctlr); + unlock(&ctlr->regs); splx(s); /* @@ -335,7 +345,7 @@ complete(Target *ctlr) * one up. */ tp->flags &= Fidentified; - *tp->dmafls = 1; + *tp->dmafls = 0; wakeup(tp); @@ -362,11 +372,10 @@ disconnect(Target *ctlr) tp->flags |= Fdisconnected; ctlr->active = tp->active; - if(ctlr->active){ + if(ctlr->active) arbitrate(ctlr); - return; - } - ctlr->flags &= ~Fbusy; + else + ctlr->flags &= ~Fbusy; } /* @@ -404,9 +413,11 @@ identify(Target *tp, uchar status) switch(status){ case 0x11: /* select complete */ - delay(7); - *dev->addr = Rcmd; - *dev->data = Catn; + /* + * This is what WD calls an 'extended interrupt', + * the next interrupt (0x8E) is already in the + * pipe, we don't have to do anything. + */ break; case 0x8E: /* service required - MSGOUT */ @@ -421,8 +432,7 @@ identify(Target *tp, uchar status) *dev->data = 0x00; *dev->data = 0x00; *dev->data = sizeof(msgout); - *dev->addr = Rcmd; - *dev->data = Ctinfo; + issue(dev, Ctinfo); msgout[0] = Midentify|tp->lun; *dev->addr = Rdata; n = 0; @@ -463,8 +473,7 @@ identify(Target *tp, uchar status) *dev->data = 0x00; *dev->data = 0x00; *dev->data = 5; - *dev->addr = Rcmd; - *dev->data = Ctinfo; + issue(dev, Ctinfo); *dev->addr = Rdata; for(i = sizeof(msgin)-1, n = 0; n < i; n++){ while((*dev->addr & Dbr) == 0){ @@ -489,8 +498,24 @@ identify(Target *tp, uchar status) break; case 0x4E: - *dev->addr = Rcmd; - *dev->data = Csbt|Ctinfo; + /* + * The target went to message-out phase, so send + * it a NOP to keep it happy. + * There seems to be no reason for this delay, other than + * that we just end up busy without an interrupt if it + * isn't there. + * I wish I understood this. + */ + delay(10); + *dev->addr = Rstatus; + n = *dev->data; + USED(n); + + *dev->addr = Rtchi; + *dev->data = 0x00; + *dev->data = 0x00; + *dev->data = 1; + issue(dev, Ctinfo); *dev->addr = Rdata; while((*dev->addr & Dbr) == 0){ if(*dev->addr & Intrpend) @@ -499,10 +524,8 @@ identify(Target *tp, uchar status) *dev->data = Mnop; break; - case 0x20: /* transfer info paused */ - delay(7); - *dev->addr = Rcmd; - *dev->data = Cnack; + case 0x20: /* transfer info paused */ + issue(dev, Cnack); break; case 0x1A: @@ -527,7 +550,7 @@ saveptr(Target *tp) Target *dev; ulong count, tx; - *tp->dmafls = 1; + *tp->dmafls = 0; dev = tp->ctlr; /* @@ -539,6 +562,11 @@ saveptr(Target *tp) count += (*dev->data & 0xFF)<<8; count += (*dev->data & 0xFF); + *dev->addr = Rtchi; + *dev->data = 0; + *dev->data = 0; + *dev->data = 0; + tx = tp->dmalen - count; tp->dmaaddr += tx; tp->dmalen = count; @@ -557,28 +585,38 @@ scsistatus(Target *ctlr) return status; } -void -scsiintr(int ctlrno) +static void +scsiprocessint(int ctlrno, Target *ctlr) { - uchar status, x, phase; - Target *ctlr, *tp; + Target *tp; + uchar aux, status, sid, phase, x; - ctlr = &target[ctlrno][CtlrID]; tp = ctlr->active; - if(*ctlr->addr & 0x20) - print("busy\n"); + while(*ctlr->addr & 0x20) /* Wait for busy to clear */ + ; + + aux = *ctlr->addr; + if((aux&0x80) == 0) { + print("scsi%d: bogus int #%2.2lux\n", ctlrno, *ctlr->addr); + return; + } + if(aux & 0x02) + print("scsi%d: parity error (ignored)\n", ctlrno); + if(aux & 0x10) + print("scsi%d: cip #%2.2lux\n", ctlrno, aux); *ctlr->addr = Rcmdphase; phase = *ctlr->data; - + *ctlr->addr = Rsrcid; + sid = *ctlr->data; *ctlr->addr = Rstatus; status = *ctlr->data; - switch(status){ - case 0x00: /* reset interrupt */ - return; + if((aux&0x40) && status != 0x81) + print("lci but not reconnect #%2.2lux\n", status); + switch(status) { case 0x42: /* timeout */ tp->flags &= ~Fretry; scsistatus(ctlr); /* Must read lun register */ @@ -586,12 +624,6 @@ scsiintr(int ctlrno) return; case 0x16: /* select-and-transfer complete */ - /* - * The target status comes back in the Rlun - * register. Returned status is combined - * with the final command phase, which - * should be 0x60. - */ saveptr(tp); tp->status = scsistatus(ctlr); /* target status */ complete(ctlr); @@ -599,8 +631,7 @@ scsiintr(int ctlrno) case 0x21: /* save data pointers */ saveptr(tp); - *ctlr->addr = Rcmd; - *ctlr->data = tp->transfer; + issue(ctlr, tp->transfer); return; case 0x4B: /* unexpected status phase */ @@ -610,17 +641,12 @@ scsiintr(int ctlrno) *ctlr->data = 0x41; /* resume no data */ else *ctlr->data = 0x46; /* collect status */ - *ctlr->addr = Rtchi; - *ctlr->data = 0; - *ctlr->data = 0; - *ctlr->data = 0; - *ctlr->addr = Rcmd; - *ctlr->data = tp->transfer; + issue(ctlr, tp->transfer); return; - case 0x85: /* disconnect */ + case 0x85: /* disconnect */ if(tp->flags & Fidentifying){ - tp->cmdphase = 0x00; /* complete retry */ + tp->cmdphase = 0x00; /* complete retry */ complete(ctlr); return; } @@ -628,31 +654,52 @@ scsiintr(int ctlrno) return; case 0x81: - *ctlr->addr = Rsrcid; - x = *ctlr->data; - if(x & Siv){ /* source ID valid */ - reselect(ctlr, x & 0x07); - ctlr->active->cmdphase = 0x44; /* reselected by target */ - start(ctlr->active); - return; + *ctlr->addr = Rdata; + x = *ctlr->data; /* the identify message */ + USED(x); + if((sid & Siv) == 0) { /* source ID valid */ + print("scsi%d: invalid src id\n", ctlrno); + break; } - break; + reselect(ctlr, sid & 0x07); + ctlr->active->cmdphase = 0x45; /* reselected by target */ + start(ctlr->active); + return; default: + if(tp == 0) { + print("scsi%d: bogus sr #%2.2lux phase #%2.2lux\n", + ctlrno, status, phase); + return; + } if((tp->flags & Fidentifying) && identify(tp, status) == 0) return; break; } - delay(1000); - print("scsi intr status #%.2ux\n", status); - print("scsi aux status #%.2ux\n", *ctlr->addr & 0xFF); + print("scsi%d:\n", ctlrno); + if(tp) print("unit %d cmd #%2.2lux flags #%4.4lux phase #%2.2lux\n", + tp->target, tp->cdb[0], tp->flags, tp->cmdphase); + print("scsi status #%.2ux phase #%2.2lux\n", status, phase); + print("aux status #%2.2ux was #%2.2lux\n", *ctlr->addr, aux); for(*ctlr->addr = 0x00, x = 0x00; x < 0x19; x++){ if((x & 0x07) == 0x07) - print("#%.2ux: #%.2ux\n", x, *ctlr->data & 0xFF); + print("#%.2ux: #%2.2ux\n", x, *ctlr->data); else - print("#%.2ux: #%.2ux ", x, *ctlr->data & 0xFF); + print("#%.2ux: #%2.2ux ", x, *ctlr->data); } - panic("scsiintr\n"); + panic("\nscsiintr"); +} + +void +scsiintr(int ctlrno) +{ + Target *ctlr; + + ctlr = &target[ctlrno][CtlrID]; + + lock(&ctlr->regs); + scsiprocessint(ctlrno, ctlr); + unlock(&ctlr->regs); } void diff --git a/power/trap.c b/power/trap.c index 208452e7cb136b705afa28b7a2bb8e07bebe786f..6e01ced2fbcbf8f8db245bd6900732c8ba81929b 100644 --- a/power/trap.c +++ b/power/trap.c @@ -172,7 +172,7 @@ intr(Ureg *ur) int i, any; ulong cause; static int bogies; - uchar pend, npend, xxx; + uchar pend, xxx; m->intr++; cause = ur->cause&(INTR5|INTR4|INTR3|INTR2|INTR1); @@ -209,7 +209,6 @@ intr(Ureg *ur) * 3. read pending interrupts */ pend = SBCCREG->fintpending; - npend = pend; /* * 4. clear pending register @@ -227,7 +226,6 @@ intr(Ureg *ur) xxx = SBCCREG->fintpending; if(xxx){ print("new pend %ux\n", xxx); - npend = pend |= xxx; i = SBCCREG->flevel; USED(i); }