This commit is contained in:
ment 2011-05-08 21:55:24 +02:00
commit 2330fdb537
4 changed files with 256 additions and 64 deletions

View file

@ -235,7 +235,7 @@ dirgen(int off, Dir *d, void*)
for(p = tab; p < tab + nelem(tab); p++, n++){ for(p = tab; p < tab + nelem(tab); p++, n++){
if(!p->inuse) if(!p->inuse)
continue; continue;
if(n == off){ if(off-- == 0){
d->name = estrdup9p(p->name); d->name = estrdup9p(p->name);
d->length = p->length*sectsize; d->length = p->length*sectsize;
d->mode = p->mode; d->mode = p->mode;

View file

@ -20,7 +20,8 @@ enum
Qctl, Qctl,
Qraw, Qraw,
Qdata, Qdata,
Qmax, Qpart,
Qmax = Maxparts,
}; };
typedef struct Dirtab Dirtab; typedef struct Dirtab Dirtab;
@ -30,13 +31,156 @@ struct Dirtab
int mode; int mode;
}; };
static Dirtab dirtab[] = ulong ctlmode = 0664;
/*
* Partition management (adapted from disk/partfs)
*/
Part *
lookpart(Umsc *lun, char *name)
{ {
[Qdir] "/", DMDIR|0555, Part *part, *p;
[Qctl] "ctl", 0664, /* nothing secret here */
[Qraw] "raw", 0640, part = lun->part;
[Qdata] "data", 0640, for(p=part; p < &part[Qmax]; p++){
}; if(p->inuse && strcmp(p->name, name) == 0)
return p;
}
return nil;
}
Part *
freepart(Umsc *lun)
{
Part *part, *p;
part = lun->part;
for(p=part; p < &part[Qmax]; p++){
if(!p->inuse)
return p;
}
return nil;
}
int
addpart(Umsc *lun, char *name, vlong start, vlong end, ulong mode)
{
Part *p;
if(start < 0 || start > end || end > lun->blocks){
werrstr("bad partition boundaries");
return -1;
}
if(lookpart(lun, name) != nil) {
werrstr("partition name already in use");
return -1;
}
p = freepart(lun);
if(p == nil){
werrstr("no free partition slots");
return -1;
}
p->inuse = 1;
free(p->name);
p->id = p - lun->part;
p->name = estrdup(name);
p->offset = start;
p->length = end - start;
p->mode = mode;
return 0;
}
int
delpart(Umsc *lun, char *s)
{
Part *p;
p = lookpart(lun, s);
if(p == nil || p->id <= Qdata){
werrstr("partition not found");
return -1;
}
p->inuse = 0;
free(p->name);
p->name = nil;
p->vers++;
return 0;
}
void
makeparts(Umsc *lun)
{
addpart(lun, "/", 0, 0, DMDIR | 0555);
addpart(lun, "ctl", 0, 0, 0664);
addpart(lun, "raw", 0, 0, 0640);
addpart(lun, "data", 0, lun->blocks, 0640);
}
/*
* ctl parsing & formatting (adapted from partfs)
*/
static char*
ctlstring(Usbfs *fs)
{
Part *p, *part;
Fmt fmt;
Umsc *lun;
Ums *ums;
ums = fs->dev->aux;
lun = fs->aux;
part = &lun->part[0];
fmtstrinit(&fmt);
fmtprint(&fmt, "dev %s\n", fs->dev->dir);
fmtprint(&fmt, "lun %ld\n", lun - &ums->lun[0]);
if(lun->flags & Finqok)
fmtprint(&fmt, "inquiry %s\n", lun->inq);
if(lun->blocks > 0)
fmtprint(&fmt, "geometry %llud %ld\n", lun->blocks, lun->lbsize);
for (p = &part[Qdata+1]; p < &part[Qmax]; p++)
if (p->inuse)
fmtprint(&fmt, "part %s %lld %lld\n",
p->name, p->offset, p->length);
return fmtstrflush(&fmt);
}
static int
ctlparse(Usbfs *fs, char *msg)
{
vlong start, end;
char *argv[16];
int argc;
Umsc *lun;
lun = fs->aux;
argc = tokenize(msg, argv, nelem(argv));
if(argc < 1){
werrstr("empty control message");
return -1;
}
if(strcmp(argv[0], "part") == 0){
if(argc != 4){
werrstr("part takes 3 args");
return -1;
}
start = strtoll(argv[2], 0, 0);
end = strtoll(argv[3], 0, 0);
return addpart(lun, argv[1], start, end, 0640);
}else if(strcmp(argv[0], "delpart") == 0){
if(argc != 2){
werrstr("delpart takes 1 arg");
return -1;
}
return delpart(lun, argv[1]);
}
werrstr("unknown ctl");
return -1;
}
/* /*
* These are used by scuzz scsireq * These are used by scuzz scsireq
@ -152,6 +296,7 @@ umscapacity(Umsc *lun)
} }
lun->blocks++; /* SRcapacity returns LBA of last block */ lun->blocks++; /* SRcapacity returns LBA of last block */
lun->capacity = (vlong)lun->blocks * lun->lbsize; lun->capacity = (vlong)lun->blocks * lun->lbsize;
lun->part[Qdata].length = lun->blocks;
if(diskdebug) if(diskdebug)
fprint(2, "disk: logical block size %lud, # blocks %llud\n", fprint(2, "disk: logical block size %lud, # blocks %llud\n",
lun->lbsize, lun->blocks); lun->lbsize, lun->blocks);
@ -329,59 +474,65 @@ Fail:
static int static int
dwalk(Usbfs *fs, Fid *fid, char *name) dwalk(Usbfs *fs, Fid *fid, char *name)
{ {
int i; Umsc *lun;
Qid qid; Part *p;
qid = fid->qid; lun = fs->aux;
if((qid.type & QTDIR) == 0){
if((fid->qid.type & QTDIR) == 0){
werrstr("walk in non-directory"); werrstr("walk in non-directory");
return -1; return -1;
} }
if(strcmp(name, "..") == 0) if(strcmp(name, "..") == 0)
return 0; return 0;
for(i = 1; i < nelem(dirtab); i++) p = lookpart(lun, name);
if(strcmp(name, dirtab[i].name) == 0){ if(p == nil){
qid.path = i | fs->qid; werrstr(Enotfound);
qid.vers = 0; return -1;
qid.type = dirtab[i].mode >> 24; }
fid->qid = qid; fid->qid.path = p->id | fs->qid;
return 0; fid->qid.vers = p->vers;
} fid->qid.type = p->mode >> 24;
werrstr(Enotfound); return 0;
return -1;
} }
static int
dstat(Usbfs *fs, Qid qid, Dir *d);
static void static void
dostat(Usbfs *fs, int path, Dir *d) dostat(Usbfs *fs, int path, Dir *d)
{ {
Dirtab *t;
Umsc *lun; Umsc *lun;
Part *p;
t = &dirtab[path];
d->qid.path = path;
d->qid.type = t->mode >> 24;
d->mode = t->mode;
d->name = t->name;
lun = fs->aux; lun = fs->aux;
if(path == Qdata) p = &lun->part[path];
d->length = lun->capacity; d->qid.path = path;
else d->qid.vers = p->vers;
d->length = 0; d->qid.type =p->mode >> 24;
d->mode = p->mode;
d->length = (vlong) p->length * lun->lbsize;
strecpy(d->name, d->name + Namesz - 1, p->name);
} }
static int static int
dirgen(Usbfs *fs, Qid, int i, Dir *d, void*) dirgen(Usbfs *fs, Qid, int n, Dir *d, void*)
{ {
i++; /* skip dir */ Umsc *lun;
if(i >= Qmax) int i;
return -1;
else{ lun = fs->aux;
dostat(fs, i, d); for(i = Qctl; i < Qmax; i++){
d->qid.path |= fs->qid; if(lun->part[i].inuse == 0)
return 0; continue;
if(n-- == 0)
break;
} }
if(i == Qmax)
return -1;
dostat(fs, i, d);
d->qid.path |= fs->qid;
return 0;
} }
static int static int
@ -417,7 +568,7 @@ dopen(Usbfs *fs, Fid *fid, int)
* since we don't need general division nor its cost. * since we don't need general division nor its cost.
*/ */
static int static int
setup(Umsc *lun, char *data, int count, vlong offset) setup(Umsc *lun, Part *p, char *data, int count, vlong offset)
{ {
long nb, lbsize, lbshift, lbmask; long nb, lbsize, lbshift, lbmask;
uvlong bno; uvlong bno;
@ -432,13 +583,14 @@ setup(Umsc *lun, char *data, int count, vlong offset)
bno = offset >> lbshift; /* offset / lbsize */ bno = offset >> lbshift; /* offset / lbsize */
nb = ((offset + count + lbsize - 1) >> lbshift) - bno; nb = ((offset + count + lbsize - 1) >> lbshift) - bno;
bno += p->offset; /* start of partition */
if(bno + nb > lun->blocks) /* past end of device? */ if(bno + nb > p->length) /* past end of partition? */
nb = lun->blocks - bno; nb = p->length - bno;
if(nb * lbsize > Maxiosize) if(nb * lbsize > Maxiosize)
nb = Maxiosize / lbsize; nb = Maxiosize / lbsize;
lun->nb = nb; lun->nb = nb;
if(bno >= lun->blocks || nb == 0) if(bno >= p->length || nb == 0)
return 0; return 0;
lun->offset = bno; lun->offset = bno;
@ -461,8 +613,9 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
{ {
long n; long n;
ulong path; ulong path;
char buf[1024]; char buf[64];
char *s, *e; char *s;
Part *p;
Umsc *lun; Umsc *lun;
Ums *ums; Ums *ums;
Qid q; Qid q;
@ -478,15 +631,9 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
count = usbdirread(fs, q, data, count, offset, dirgen, nil); count = usbdirread(fs, q, data, count, offset, dirgen, nil);
break; break;
case Qctl: case Qctl:
e = buf + sizeof(buf); s = ctlstring(fs);
s = seprint(buf, e, "%s lun %ld: ", fs->dev->dir, lun - &ums->lun[0]); count = usbreadbuf(data, count, offset, s, strlen(s));
if(lun->flags & Finqok) free(s);
s = seprint(s, e, "inquiry %s ", lun->inq);
if(lun->blocks > 0)
s = seprint(s, e, "geometry %llud %ld",
lun->blocks, lun->lbsize);
s = seprint(s, e, "\n");
count = usbreadbuf(data, count, offset, buf, s - buf);
break; break;
case Qraw: case Qraw:
if(lun->lbsize <= 0 && umscapacity(lun) < 0){ if(lun->lbsize <= 0 && umscapacity(lun) < 0){
@ -515,7 +662,14 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
} }
break; break;
case Qdata: case Qdata:
count = setup(lun, data, count, offset); default:
p = &lun->part[path];
if(!p->inuse){
count = -1;
werrstr(Eperm);
break;
}
count = setup(lun, p, data, count, offset);
if (count <= 0) if (count <= 0)
break; break;
n = SRread(lun, lun->bufp, lun->nb * lun->lbsize); n = SRread(lun, lun->bufp, lun->nb * lun->lbsize);
@ -547,7 +701,9 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
ulong path; ulong path;
uvlong bno; uvlong bno;
Ums *ums; Ums *ums;
Part *p;
Umsc *lun; Umsc *lun;
char *s;
ums = fs->dev->aux; ums = fs->dev->aux;
lun = fs->aux; lun = fs->aux;
@ -555,12 +711,18 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
qlock(ums); qlock(ums);
switch(path){ switch(path){
default: case Qdir:
werrstr(Eperm);
count = -1; count = -1;
werrstr(Eperm);
break; break;
case Qctl: case Qctl:
dprint(2, "usb/disk: ctl ignored\n"); s = emallocz(count+1, 1);
memmove(s, data, count);
if(s[count-1] == '\n')
s[count-1] = 0;
if(ctlparse(fs, s) == -1)
count = -1;
free(s);
break; break;
case Qraw: case Qraw:
if(lun->lbsize <= 0 && umscapacity(lun) < 0){ if(lun->lbsize <= 0 && umscapacity(lun) < 0){
@ -597,8 +759,15 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
} }
break; break;
case Qdata: case Qdata:
default:
p = &lun->part[path];
if(!p->inuse){
count = -1;
werrstr(Eperm);
break;
}
len = ocount = count; len = ocount = count;
count = setup(lun, data, count, offset); count = setup(lun, p, data, count, offset);
if (count <= 0) if (count <= 0)
break; break;
bno = lun->offset; bno = lun->offset;
@ -788,6 +957,7 @@ diskmain(Dev *dev, int argc, char **argv)
lun->fs.dev = dev; lun->fs.dev = dev;
incref(dev); incref(dev);
lun->fs.aux = lun; lun->fs.aux = lun;
makeparts(lun);
usbfsadd(&lun->fs); usbfsadd(&lun->fs);
} }
return 0; return 0;

View file

@ -7,6 +7,7 @@ typedef struct Umsc Umsc;
typedef struct Ums Ums; typedef struct Ums Ums;
typedef struct Cbw Cbw; /* command block wrapper */ typedef struct Cbw Cbw; /* command block wrapper */
typedef struct Csw Csw; /* command status wrapper */ typedef struct Csw Csw; /* command status wrapper */
typedef struct Part Part;
enum enum
{ {
@ -42,12 +43,27 @@ enum
CswOk = 0, CswOk = 0,
CswFailed = 1, CswFailed = 1,
CswPhaseErr = 2, CswPhaseErr = 2,
Maxparts = 16,
}; };
/* /*
* corresponds to a lun. * corresponds to a lun.
* these are ~600+Maxiosize bytes each; ScsiReq is not tiny. * these are ~600+Maxiosize bytes each; ScsiReq is not tiny.
*/ */
struct Part
{
int id;
int inuse;
int vers;
ulong mode;
char *name;
vlong offset; /* in lbsize units */
vlong length; /* in lbsize units */
};
struct Umsc struct Umsc
{ {
ScsiReq; ScsiReq;
@ -59,6 +75,9 @@ struct Umsc
long off; /* offset within a block */ long off; /* offset within a block */
long nb; /* byte count */ long nb; /* byte count */
/* partitions */
Part part[Maxparts];
uchar rawcmd[10]; uchar rawcmd[10];
uchar phase; uchar phase;
char *inq; char *inq;

View file

@ -183,6 +183,8 @@ fswalk(Usbfs*, Fid *fid, char *name)
int rc; int rc;
Dev *dev; Dev *dev;
Dir d; Dir d;
char dname[Namesz];
int (*xfswalk)(Usbfs *fs, Fid *f, char *name); int (*xfswalk)(Usbfs *fs, Fid *f, char *name);
q = fid->qid; q = fid->qid;
@ -218,6 +220,7 @@ fswalk(Usbfs*, Fid *fid, char *name)
for(i = 0; i < nfs; i++) for(i = 0; i < nfs; i++)
if(fs[i] != nil && strcmp(name, fs[i]->name) == 0){ if(fs[i] != nil && strcmp(name, fs[i]->name) == 0){
q.path = mkqid(i, Qdir); q.path = mkqid(i, Qdir);
d.name = dname;
fs[i]->stat(fs[i], q, &d); /* may be a file */ fs[i]->stat(fs[i], q, &d); /* may be a file */
fid->qid = d.qid; fid->qid = d.qid;
qunlock(&fslck); qunlock(&fslck);