M pc/devfloppy.c => pc/devfloppy.c +56 -24
@@ 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)
*/
M pc/devvga.c => pc/devvga.c +2 -0
@@ 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; port<offset+n; port++) {
outb(port, *cp++);
}
M pc/kbd.c => pc/kbd.c +1 -1
@@ 188,7 188,7 @@ mousecmd(int cmd)
c = inb(Data);
} while(c == 0xFE || c == 0);
if(c != 0xFA){
- print("mouse returns %2.2ux to the %2.2ux command\n", c, cmd);
+ kprint("mouse returns %2.2ux to the %2.2ux command\n", c, cmd);
return -1;
}
return 0;
M port/chan.c => port/chan.c +7 -5
@@ 42,7 42,7 @@ chandevreset(void)
{
int i;
- for(i=0; i<strlen(devchar); i++)
+ for(i=0; i<devchar[i]; i++)
(*devtab[i].reset)();
}
@@ 51,7 51,7 @@ chandevinit(void)
{
int i;
- for(i=0; i<strlen(devchar); i++)
+ for(i=0; i<devchar[i]; i++)
(*devtab[i].init)();
}
@@ 429,6 429,7 @@ namec(char *name, int amode, int omode, ulong perm)
{
Chan *c, *nc, *cc;
int t;
+ Rune r;
int mntok, isdot;
char *p;
char *elem;
@@ 463,12 464,13 @@ namec(char *name, int amode, int omode, ulong perm)
else
if(name[0] == '#') {
mntok = 0;
- if(name[1]=='M')
+ name++;
+ name += chartorune(&r, name);
+ if(r == 'M')
error(Enonexist);
- t = devno(name[1], 1);
+ t = devno(r, 1);
if(t == -1)
error(Ebadsharp);
- name += 2;
if(*name == '/'){
name = skipslash(name);
elem[0]=0;
M port/dev.c => port/dev.c +16 -9
@@ 12,15 12,22 @@ extern ulong kerndate;
int
devno(int c, int user)
{
- char *s;
+ Rune *s;
+ int i;
- s = strchr(devchar, c);
- if(s==0 || c==0){
- if(user)
- return -1;
- panic("devno %c 0x%ux", c, c);
+ s = devchar;
+ i = 0;
+ while(*s){
+ if(c == *s)
+ return i;
+ i++;
+ s++;
}
- return s - devchar;
+
+ if(user)
+ return -1;
+ panic("devno %C 0x%ux", c, c);
+ return 0;
}
void
@@ 68,7 75,7 @@ Chan *
devclone(Chan *c, Chan *nc)
{
if(c->flag & 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:
M port/devmnt.c => port/devmnt.c +1 -2
@@ 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;
}
M port/net.c => port/net.c +1 -1
@@ 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;
M port/portdat.h => port/portdat.h +1 -1
@@ 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[];
M power/fns.h => power/fns.h +1 -0
@@ 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*);
M power/scsi.c => power/scsi.c +113 -66
@@ 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
M power/trap.c => power/trap.c +1 -3
@@ 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);
}