M mpc/random.c => mpc/random.c +2 -2
@@ 81,7 81,7 @@ randomclock(void)
wakeup(&rb.consumer);
}
-static void
+void
randominit(void)
{
addclock0link(randomclock);
@@ 93,7 93,7 @@ randominit(void)
/*
* consume random bytes from a circular buffer
*/
-static ulong
+ulong
randomread(void *xp, ulong n)
{
uchar *e, *p;
M mpc/trap.c => mpc/trap.c +1 -0
@@ 656,6 656,7 @@ syscall(Ureg* ureg)
}
if(up->nerrlab){
print("bad errstack [%d]: %d extra\n", scallnr, up->nerrlab);
+ print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
for(i = 0; i < NERR; i++)
print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
panic("error stack");
M pc/pci.c => pc/pci.c +4 -1
@@ 61,6 61,7 @@ enum
static Lock pcicfglock;
static Lock pcicfginitlock;
static int pcicfgmode = -1;
+static int pcimaxbno = 255;
static int pcimaxdno;
static Pcidev* pciroot;
static Pcidev* pcilist;
@@ 534,11 535,13 @@ pcicfginit(void)
fmtinstall('T', tbdfconv);
+ if(p = getconf("*pcimaxbno"))
+ pcimaxbno = strtoul(p, 0, 0);
if(p = getconf("*pcimaxdno"))
pcimaxdno = strtoul(p, 0, 0);
list = &pciroot;
- for(bno = 0; bno < 256; bno++) {
+ for(bno = 0; bno <= pcimaxbno; bno++) {
bno = pciscan(bno, list);
while(*list)
list = &(*list)->link;
M pc/sdata.c => pc/sdata.c +1 -1
@@ 1758,7 1758,7 @@ atarctl(SDunit* unit, char* p, int l)
n += snprint(p+n, l-n, " rwm %ud rwmctl %ud",
drive->rwm, drive->rwmctl);
n += snprint(p+n, l-n, "\n");
- if(!unit->changed && unit->sectors){
+ if(unit->sectors){
n += snprint(p+n, l-n, "geometry %ld %ld",
unit->sectors, unit->secsize);
if(drive->pkt == 0)
M pc/sdscsi.c => pc/sdscsi.c +14 -5
@@ 217,6 217,14 @@ scsionline(SDunit* unit)
*/
unit->sectors++;
unit->secsize = (p[4]<<24)|(p[5]<<16)|(p[6]<<8)|p[7];
+
+ /*
+ * Some ATAPI CD readers lie about the block size.
+ * Since we don't read audio via this interface
+ * it's okay to always fudge this.
+ */
+ if((unit->inquiry[0] & 0x1F) == 0x05 && unit->secsize == 2352)
+ unit->secsize = 2048;
ok = 1;
break;
case 1:
@@ 230,7 238,10 @@ scsionline(SDunit* unit)
free(p);
free(r);
- return ok;
+ if(ok)
+ return ok+retries;
+ else
+ return 0;
}
int
@@ 331,15 342,13 @@ again:
case 0x06: /* check condition */
/*
* Check for a removeable media change.
- * If so, mark it and zap the geometry info
+ * If so, mark it by zapping the geometry info
* to force an online request.
*/
if(r->sense[12] != 0x28 || r->sense[13] != 0)
break;
- if(unit->inquiry[1] & 0x80){
- unit->changed = 1;
+ if(unit->inquiry[1] & 0x80)
unit->sectors = 0;
- }
break;
case 0x02: /* not ready */
/*
A port/devloopback.c => port/devloopback.c +582 -0
@@ 0,0 1,582 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "../port/error.h"
+
+#include "netif.h"
+
+typedef struct Link Link;
+typedef struct Loop Loop;
+
+struct Link
+{
+ Lock;
+
+ int ref;
+
+ int nodrop; /* disable dropping on iq overflow */
+ int soverflows; /* packets dropped because iq overflowed */
+ int drops; /* packets deliberately dropped */
+
+ long delay0; /* fastticks of delay in the link */
+ long delayn; /* fastticks of delay per byte */
+
+ Block *tq; /* transmission queue */
+ Block *tqtail;
+ vlong tout; /* time the last packet in tq is really out */
+ vlong tin; /* time the head packet in tq enters the remote side */
+
+ Queue *oq; /* output queue from other side & packets in the link */
+ Queue *iq;
+};
+
+struct Loop
+{
+ QLock;
+ int ref;
+ int minmtu; /* smallest block transmittable */
+ Loop *next;
+ ulong path;
+ long limit; /* queue buffering limit */
+ Link link[2];
+};
+
+static struct
+{
+ Lock;
+ ulong path;
+} loopbackalloc;
+
+enum
+{
+ Qdir,
+ Qctl,
+ Qstatus,
+ Qstats,
+ Qdata0,
+ Qdata1,
+
+ TMSIZE = 8,
+
+ NLOOPBACKS = 1,
+ LOOPBACKSIZE = 32*1024, /*ZZZ change to settable; size of queues */
+};
+
+Dirtab loopbackdir[] =
+{
+ "ctl", {Qctl}, 0, 0222,
+ "status", {Qstatus}, 0, 0222,
+ "stats", {Qstats}, 0, 0444,
+ "data", {Qdata0}, 0, 0666,
+ "data1", {Qdata1}, 0, 0666,
+};
+
+static Loop loopbacks[NLOOPBACKS];
+
+static void looper(Loop *lb);
+static long loopoput(Loop *lb, Link *link, Block *bp);
+static void ptime(uchar *p, vlong t);
+static vlong gtime(uchar *p);
+static void closelink(Link *link, int dofree);
+static vlong pushlink(Link *link, vlong now);
+static void freelb(Loop *lb);
+
+static void
+loopbackinit(void)
+{
+ int i;
+
+ for(i = 0; i < NLOOPBACKS; i++)
+ loopbacks[i].path = i;
+}
+
+static Chan*
+loopbackattach(char *spec)
+{
+ Loop *lb;
+ Queue *q;
+ Chan *c;
+ int chan;
+
+ c = devattach('X', spec);
+ lb = &loopbacks[0];
+
+ qlock(lb);
+ if(waserror()){
+ qunlock(lb);
+ nexterror();
+ }
+
+ lb->ref++;
+ if(lb->ref == 1){
+ lb->limit = LOOPBACKSIZE;
+ for(chan = 0; chan < 2; chan++){
+ q = qopen(lb->limit, 0, 0, 0);
+ lb->link[chan].iq = q;
+ if(q == nil){
+ freelb(lb);
+ exhausted("memory");
+ }
+ q = qopen(lb->limit, 0, 0, 0);
+ lb->link[chan].oq = q;
+ if(q == nil){
+ freelb(lb);
+ exhausted("memory");
+ }
+ lb->link[chan].nodrop = 1;
+ }
+ }
+ poperror();
+ qunlock(lb);
+
+ c->qid = (Qid){CHDIR|NETQID(2*lb->path, Qdir), 0};
+ c->aux = lb;
+ c->dev = 0;
+ return c;
+}
+
+static Chan*
+loopbackclone(Chan *c, Chan *nc)
+{
+ Loop *lb;
+ int chan;
+
+ lb = c->aux;
+ nc = devclone(c, nc);
+ qlock(lb);
+ lb->ref++;
+ if(c->flag & COPEN){
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ lb->link[chan].ref++;
+ break;
+ }
+ }
+ qunlock(lb);
+ return nc;
+}
+
+static int
+loopbackgen(Chan *c, Dirtab *tab, int ntab, int i, Dir *dp)
+{
+ Loop *lb;
+ int id, len, chan;
+
+ if(i == DEVDOTDOT){
+ devdir(c, c->qid, "#X", 0, eve, CHDIR|0555, dp);
+ return 1;
+ }
+
+ id = NETID(c->qid.path);
+ if(i > 1)
+ id++;
+ if(tab==nil || i>=ntab)
+ return -1;
+ tab += i;
+ lb = c->aux;
+ switch(chan = tab->qid.path){
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ len = qlen(lb->link[chan].iq);
+ break;
+ default:
+ len = tab->length;
+ break;
+ }
+ devdir(c, (Qid){NETQID(id, tab->qid.path),0}, tab->name, len, eve, tab->perm, dp);
+ return 1;
+}
+
+
+static int
+loopbackwalk(Chan *c, char *name)
+{
+ return devwalk(c, name, loopbackdir, nelem(loopbackdir), loopbackgen);
+}
+
+static void
+loopbackstat(Chan *c, char *db)
+{
+ Loop *lb;
+ Dir dir;
+ int chan;
+
+ lb = c->aux;
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdir:
+ devdir(c, c->qid, ".", nelem(loopbackdir)*DIRLEN, eve, CHDIR|0555, &dir);
+ break;
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ devdir(c, c->qid, "data", qlen(lb->link[chan].iq), eve, 0660, &dir);
+ break;
+ default:
+ panic("loopbackstat");
+ }
+ convD2M(&dir, db);
+}
+
+/*
+ * if the stream doesn't exist, create it
+ */
+static Chan*
+loopbackopen(Chan *c, int omode)
+{
+ Loop *lb;
+ int chan;
+
+ if(c->qid.path & CHDIR){
+ if(omode != OREAD)
+ error(Ebadarg);
+ c->mode = omode;
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+ }
+
+ lb = c->aux;
+ qlock(lb);
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ lb->link[chan].ref++;
+ break;
+ }
+ qunlock(lb);
+
+ c->mode = openmode(omode);
+ c->flag |= COPEN;
+ c->offset = 0;
+ return c;
+}
+
+static void
+loopbackclose(Chan *c)
+{
+ Loop *lb;
+ int ref, chan;
+
+ lb = c->aux;
+
+ qlock(lb);
+ if(c->flag & COPEN){
+ /*
+ * closing either side hangs up the stream
+ */
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ if(--lb->link[chan].ref == 0){
+ qhangup(lb->link[chan ^ 1].oq, nil);
+ looper(lb);
+ }
+ break;
+ }
+ }
+
+
+ /*
+ * if both sides are closed, they are reusable
+ */
+ if(lb->link[0].ref == 0 && lb->link[1].ref == 0){
+ for(chan = 0; chan < 2; chan++){
+ closelink(&lb->link[chan], 0);
+ qreopen(lb->link[chan].iq);
+ qreopen(lb->link[chan].oq);
+ }
+ }
+ ref = --lb->ref;
+ if(ref == 0)
+ freelb(lb);
+ qunlock(lb);
+}
+
+static void
+freelb(Loop *lb)
+{
+ int chan;
+
+ for(chan = 0; chan < 2; chan++)
+ closelink(&lb->link[chan], 1);
+}
+
+/*
+ * called with the Loop qlocked,
+ * so only pushlink can mess with the queues
+ */
+static void
+closelink(Link *link, int dofree)
+{
+ Queue *iq, *oq;
+ Block *bp;
+
+ ilock(link);
+ iq = link->iq;
+ oq = link->oq;
+ bp = link->tq;
+ link->tq = nil;
+ link->tqtail = nil;
+ link->tout = 0;
+ link->tin = 0;
+ iunlock(link);
+ if(iq != nil){
+ qclose(iq);
+ if(dofree){
+ ilock(link);
+ free(iq);
+ link->iq = nil;
+ iunlock(link);
+ }
+ }
+ if(oq != nil){
+ qclose(oq);
+ if(dofree){
+ ilock(link);
+ free(oq);
+ link->oq = nil;
+ iunlock(link);
+ }
+ }
+ freeblist(bp);
+}
+
+static long
+loopbackread(Chan *c, void *va, long n, vlong)
+{
+ Loop *lb;
+ int chan;
+
+ lb = c->aux;
+//ZZZ ctl message to set q limit -- qsetlimit(q, limit)
+//ZZZ ctl message to set blocking/dropping qnoblock(q, dropit)
+//ZZZ ctl message for delays
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdir:
+ return devdirread(c, va, n, loopbackdir, nelem(loopbackdir), loopbackgen);
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ return qread(lb->link[chan].iq, va, n);
+ default:
+ panic("loopbackread");
+ }
+ return -1; /* not reached */
+}
+
+static Block*
+loopbackbread(Chan *c, long n, ulong offset)
+{
+ Loop *lb;
+ int chan;
+
+ lb = c->aux;
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ return qbread(lb->link[chan].iq, n);
+ }
+
+ return devbread(c, n, offset);
+}
+
+static long
+loopbackbwrite(Chan *c, Block *bp, ulong off)
+{
+ Loop *lb;
+ int chan;
+
+ lb = c->aux;
+ switch(chan = NETTYPE(c->qid.path)){
+ case Qdata0:
+ case Qdata1:
+ chan -= Qdata0;
+ return loopoput(lb, &lb->link[chan ^ 1], bp);
+ default:
+ return devbwrite(c, bp, off);
+ }
+}
+
+static long
+loopbackwrite(Chan *c, void *va, long n, vlong off)
+{
+ Block *bp;
+
+ if(!islo())
+ print("loopbackwrite hi %lux\n", getcallerpc(&c));
+
+ switch(NETTYPE(c->qid.path)){
+ case Qdata0:
+ case Qdata1:
+ bp = allocb(n);
+ if(waserror()){
+ freeb(bp);
+ nexterror();
+ }
+ memmove(bp->wp, va, n);
+ poperror();
+ bp->wp += n;
+ return loopbackbwrite(c, bp, off);
+ case Qctl:
+ default:
+ panic("loopbackwrite");
+ }
+
+ return n;
+}
+
+static long
+loopoput(Loop *lb, Link *link, Block *bp)
+{
+ long n;
+
+ n = BLEN(bp);
+
+ /* make it a single block with space for the loopback header */
+ bp = padblock(bp, TMSIZE);
+ if(bp->next)
+ bp = concatblock(bp);
+ if(BLEN(bp) < lb->minmtu)
+ bp = adjustblock(bp, lb->minmtu);
+
+ qbwrite(link->oq, bp);
+ looper(lb);
+ return n;
+}
+
+/*
+ * move blocks between queues if they are ready.
+ * schedule an interrupt for the next interesting time
+ */
+static void
+looper(Loop *lb)
+{
+ vlong t, tt;
+
+ tt = fastticks(nil);
+again:;
+ t = pushlink(&lb->link[0], tt);
+ tt = pushlink(&lb->link[1], tt);
+ if(t > tt && tt)
+ t = tt;
+ if(t){
+ tt = fastticks(nil);
+ if(tt <= t)
+ goto again;
+ //schedule an intr at tt-t fastticks
+ }
+}
+
+static vlong
+pushlink(Link *link, vlong now)
+{
+ Block *bp;
+ vlong t;
+
+ /*
+ * put another block in the link queue
+ */
+ ilock(link);
+ if(link->iq == nil || link->oq == nil){
+ iunlock(link);
+ return 0;
+ }
+ t = link->tout;
+ if(!t || t < now){
+ bp = qget(link->oq);
+ if(bp != nil){
+ if(!t)
+ t = now;
+ link->tout = t + BLEN(bp) * link->delayn;
+ ptime(bp->rp, t + link->delay0);
+//ZZZ drop or introduce errors here
+ if(link->tq == nil)
+ link->tq = bp;
+ else
+ link->tqtail->next = bp;
+ link->tqtail = bp;
+ }else
+ link->tout = 0;
+ }
+
+ /*
+ * put more blocks into the receive queue
+ */
+ t = 0;
+ while(bp = link->tq){
+ t = gtime(bp->rp);
+ if(t > now)
+ break;
+ bp->rp += TMSIZE;
+ link->tq = bp->next;
+ bp->next = nil;
+ if(link->nodrop)
+ qpassnolim(link->iq, bp);
+ else if(qpass(link->iq, bp) < 0)
+ link->soverflows++;
+ t = 0;
+ }
+ if(bp == nil && qisclosed(link->oq) && !qcanread(link->oq) && !qisclosed(link->iq))
+ qhangup(link->iq, nil);
+ link->tin = t;
+ if(!t || t < link->tout)
+ t = link->tout;
+ iunlock(link);
+ return t;
+}
+
+static void
+ptime(uchar *p, vlong t)
+{
+ ulong tt;
+
+ tt = t >> 32;
+ p[0] = tt >> 24;
+ p[1] = tt >> 16;
+ p[2] = tt >> 8;
+ p[3] = tt;
+ tt = t;
+ p[4] = tt >> 24;
+ p[5] = tt >> 16;
+ p[6] = tt >> 8;
+ p[7] = tt;
+}
+
+static vlong
+gtime(uchar *p)
+{
+ ulong t1, t2;
+
+ t1 = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
+ t2 = (p[4] << 24) | (p[5] << 16) | (p[6] << 8) | p[7];
+ return ((vlong)t1 << 32) | t2;
+}
+
+Dev loopbackdevtab = {
+ 'X',
+ "loopback",
+
+ devreset,
+ loopbackinit,
+ loopbackattach,
+ loopbackclone,
+ loopbackwalk,
+ loopbackstat,
+ loopbackopen,
+ devcreate,
+ loopbackclose,
+ loopbackread,
+ loopbackbread,
+ loopbackwrite,
+ loopbackbwrite,
+ devremove,
+ devwstat,
+};
M port/devsd.c => port/devsd.c +50 -56
@@ 78,7 78,9 @@ sdaddpart(SDunit* unit, char* name, ulong start, ulong end)
/*
* Check there is a free slot and size and extent are valid.
*/
- if(partno == -1 || start > end || end > unit->sectors)
+ if(partno == -1)
+ error(Ebadctl);
+ if(start > end || end > unit->sectors)
error(Eio);
pp = &unit->part[partno];
pp->start = start;
@@ 87,7 89,6 @@ sdaddpart(SDunit* unit, char* name, ulong start, ulong end)
strncpy(pp->user, eve, NAMELEN);
pp->perm = 0640;
pp->valid = 1;
- unit->npart++;
}
static void
@@ 99,8 100,6 @@ sddelpart(SDunit* unit, char* name)
/*
* Look for the partition to delete.
* Can't delete if someone still has it open.
- * If it's the last valid partition zap the
- * whole table.
*/
pp = unit->part;
for(i = 0; i < SDnpart; i++){
@@ 112,29 111,24 @@ sddelpart(SDunit* unit, char* name)
error(Ebadctl);
if(strncmp(up->user, pp->user, NAMELEN) && !iseve())
error(Eperm);
- if(pp->nopen)
- error(Einuse);
pp->valid = 0;
-
- unit->npart--;
- if(unit->npart == 0){
- free(unit->part);
- unit->part = nil;
- }
+ pp->vers++;
}
static int
sdinitpart(SDunit* unit)
{
- int nf;
+ int i, nf;
ulong start, end;
char *f[4], *p, *q, buf[10];
+ unit->vers++;
unit->sectors = unit->secsize = 0;
- unit->npart = 0;
if(unit->part){
- free(unit->part);
- unit->part = nil;
+ for(i = 0; i < SDnpart; i++){
+ unit->part[i].valid = 0;
+ unit->part[i].vers++;
+ }
}
if(unit->inquiry[0] & 0xC0)
@@ 322,22 316,20 @@ sd2gen(Chan* c, int i, Dir* dp)
SDpart *pp;
SDunit *unit;
+ unit = sdunit[UNIT(c->qid)];
switch(i){
case Qctl:
- q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qctl), c->qid.vers};
+ q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qctl), unit->vers};
devdir(c, q, "ctl", 0, eve, 0640, dp);
return 1;
case Qraw:
- q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qraw), c->qid.vers};
+ q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qraw), unit->vers};
devdir(c, q, "raw", 0, eve, CHEXCL|0600, dp);
return 1;
case Qpart:
- unit = sdunit[UNIT(c->qid)];
- if(unit->changed)
- break;
pp = &unit->part[PART(c->qid)];
l = (pp->end - pp->start) * (vlong)unit->secsize;
- q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qpart), c->qid.vers};
+ q = (Qid){QID(UNIT(c->qid), PART(c->qid), Qpart), unit->vers+pp->vers};
if(pp->user[0] == '\0')
strncpy(pp->user, eve, NAMELEN);
devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
@@ 392,8 384,16 @@ sdgen(Chan* c, Dirtab*, int, int s, Dir* dp)
}
unit = sdunit[UNIT(c->qid)];
qlock(&unit->ctl);
- if(!unit->changed && unit->sectors == 0)
+
+ /*
+ * Check for media change.
+ * If one has already been detected, sectors will be zero.
+ * If there is one waiting to be detected, online will return > 1.
+ * Online is a bit of a large hammer but does the job.
+ */
+ if(unit->sectors == 0 || (unit->dev->ifc->online && unit->dev->ifc->online(unit) > 1))
sdinitpart(unit);
+
i = s+Qunitbase;
if(i < Qpart){
r = sd2gen(c, i, dp);
@@ 401,17 401,17 @@ sdgen(Chan* c, Dirtab*, int, int s, Dir* dp)
return r;
}
i -= Qpart;
- if(unit->npart == 0 || i >= SDnpart){
+ if(unit->part == nil || i >= SDnpart){
qunlock(&unit->ctl);
break;
}
pp = &unit->part[i];
- if(unit->changed || !pp->valid){
+ if(!pp->valid){
qunlock(&unit->ctl);
return 0;
}
l = (pp->end - pp->start) * (vlong)unit->secsize;
- q = (Qid){QID(UNIT(c->qid), i, Qpart), c->qid.vers};
+ q = (Qid){QID(UNIT(c->qid), i, Qpart), unit->vers+pp->vers};
if(pp->user[0] == '\0')
strncpy(pp->user, eve, NAMELEN);
devdir(c, q, pp->name, l, pp->user, pp->perm, dp);
@@ 493,8 493,13 @@ sdopen(Chan* c, int omode)
switch(TYPE(c->qid)){
default:
break;
+ case Qctl:
+ unit = sdunit[UNIT(c->qid)];
+ c->qid.vers = unit->vers;
+ break;
case Qraw:
unit = sdunit[UNIT(c->qid)];
+ c->qid.vers = unit->vers;
if(!canlock(&unit->rawinuse)){
c->flag &= ~COPEN;
error(Einuse);
@@ 509,11 514,8 @@ sdopen(Chan* c, int omode)
c->flag &= ~COPEN;
nexterror();
}
- if(unit->changed)
- error(Eio);
pp = &unit->part[PART(c->qid)];
- pp->nopen++;
- unit->nopen++;
+ c->qid.vers = unit->vers+pp->vers;
qunlock(&unit->ctl);
poperror();
break;
@@ 524,7 526,6 @@ sdopen(Chan* c, int omode)
static void
sdclose(Chan* c)
{
- SDpart *pp;
SDunit *unit;
if(c->qid.path & CHDIR)
@@ 539,28 540,13 @@ sdclose(Chan* c)
unit = sdunit[UNIT(c->qid)];
unlock(&unit->rawinuse);
break;
- case Qpart:
- unit = sdunit[UNIT(c->qid)];
- qlock(&unit->ctl);
- if(waserror()){
- qunlock(&unit->ctl);
- c->flag &= ~COPEN;
- nexterror();
- }
- pp = &unit->part[PART(c->qid)];
- pp->nopen--;
- unit->nopen--;
- if(unit->nopen == 0)
- unit->changed = 0;
- qunlock(&unit->ctl);
- poperror();
- break;
}
}
static long
sdbio(Chan* c, int write, char* a, long len, vlong off)
{
+ int nchange;
long l;
uchar *b;
SDpart *pp;
@@ 569,12 555,21 @@ sdbio(Chan* c, int write, char* a, long len, vlong off)
unit = sdunit[UNIT(c->qid)];
+ nchange = 0;
qlock(&unit->ctl);
- if(waserror()){
+ while(waserror()){
+ /* notification of media change; go around again */
+ if(strcmp(up->error, Eio) == 0 && unit->sectors == 0 && nchange++ == 0){
+ sdinitpart(unit);
+ continue;
+ }
+
+ /* other errors; give up */
qunlock(&unit->ctl);
nexterror();
}
- if(unit->changed)
+ pp = &unit->part[PART(c->qid)];
+ if(unit->vers+pp->vers != c->qid.vers)
error(Eio);
/*
@@ 588,7 583,6 @@ sdbio(Chan* c, int write, char* a, long len, vlong off)
* (sectors, secsize) can't change once the drive has
* been brought online.
*/
- pp = &unit->part[PART(c->qid)];
bno = (off/unit->secsize) + pp->start;
nb = ((off+len+unit->secsize-1)/unit->secsize) + pp->start - bno;
max = SDmaxio/unit->secsize;
@@ 728,7 722,9 @@ sdread(Chan *c, void *a, long n, vlong off)
*/
if(unit->dev->ifc->rctl)
l += unit->dev->ifc->rctl(unit, p+l, READSTR-l);
- if(!unit->changed && unit->sectors){
+ if(unit->sectors == 0)
+ sdinitpart(unit);
+ if(unit->sectors){
if(unit->dev->ifc->rctl == nil)
l += snprint(p+l, READSTR-l,
"geometry %ld %ld\n",
@@ 789,13 785,13 @@ sdwrite(Chan *c, void *a, long n, vlong off)
free(cb);
nexterror();
}
- if(unit->changed)
+ if(unit->vers != c->qid.vers)
error(Eio);
if(cb->nf < 1)
error(Ebadctl);
if(strcmp(cb->f[0], "part") == 0){
- if(cb->nf != 4 || unit->npart >= SDnpart)
+ if(cb->nf != 4)
error(Ebadctl);
if(unit->sectors == 0 && !sdinitpart(unit))
error(Eio);
@@ 874,10 870,8 @@ sdwstat(Chan* c, char* dp)
nexterror();
}
- if(unit->changed)
- error(Enonexist);
pp = &unit->part[PART(c->qid)];
- if(!pp->valid)
+ if(unit->vers+pp->vers != c->qid.vers)
error(Enonexist);
if(strncmp(up->user, pp->user, NAMELEN) && !iseve())
error(Eperm);
M port/devsdp.c => port/devsdp.c +0 -1
@@ 528,7 528,6 @@ sdpclose(Chan* ch)
}
}
qunlock(c);
- poperror();
break;
}
}
M port/sd.h => port/sd.h +3 -5
@@ 14,7 14,7 @@ typedef struct SDpart {
char user[NAMELEN];
ulong perm;
int valid;
- int nopen; /* of this partition */
+ ulong vers;
} SDpart;
typedef struct SDunit {
@@ 27,10 27,8 @@ typedef struct SDunit {
QLock ctl;
ulong sectors;
ulong secsize;
- SDpart* part;
- int npart; /* of valid partitions */
- int nopen; /* of partitions on this unit */
- int changed;
+ SDpart* part; /* either nil or points at array of size SDnpart */
+ ulong vers;
Lock rawinuse; /* really just a test-and-set */
int state;