usb/disk: ctl write support

This commit is contained in:
ment 2011-05-08 01:36:37 +02:00
parent 28859a83f4
commit 24d7f981ec
2 changed files with 154 additions and 12 deletions

View file

@ -38,6 +38,129 @@ static Dirtab dirtab[] =
[Qdata] "data", 0640,
};
ulong ctlmode = 0664;
/*
* Partition management (adapted from disk/partfs)
*/
int
addpart(Umsc *lun, char *name, vlong start, vlong end)
{
Part *p;
if(start < 0 || start > end || end > lun->blocks){
werrstr("bad partition boundaries");
return -1;
}
if (strcmp(name, "ctl") == 0 || strcmp(name, "data") == 0) {
werrstr("partition name already in use");
return -1;
}
for (p = lun->part; p < lun->part + Maxparts && p->inuse; p++)
if (strcmp(p->name, name) == 0) {
werrstr("partition name already in use");
return -1;
}
if(p == lun->part + Maxparts){
werrstr("no free partition slots");
return -1;
}
p->inuse = 1;
free(p->name);
p->name = estrdup(name);
p->offset = start;
p->length = end - start;
p->mode = ctlmode;
p->vers++;
return 0;
}
int
delpart(Umsc *lun, char *s)
{
Part *p;
for (p = lun->part; p < lun->part + Maxparts; p++)
if(p->inuse && strcmp(p->name, s) == 0)
break;
if(p == lun->part + Maxparts){
werrstr("partition not found");
return -1;
}
p->inuse = 0;
free(p->name);
p->name = nil;
return 0;
}
/*
* 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, "%s lun %ld: ", fs->dev->dir, lun - &ums->lun[0]);
if(lun->flags & Finqok)
fmtprint(&fmt, "inquiry %s ", lun->inq);
if(lun->blocks > 0)
fmtprint(&fmt, "geometry %llud %ld", lun->blocks, lun->lbsize);
fmtprint(&fmt, "\n");
for (p = part; p < &part[Maxparts]; 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);
}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
*/
@ -461,8 +584,8 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
{
long n;
ulong path;
char buf[1024];
char *s, *e;
char buf[64];
char *s;
Umsc *lun;
Ums *ums;
Qid q;
@ -478,15 +601,9 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
count = usbdirread(fs, q, data, count, offset, dirgen, nil);
break;
case Qctl:
e = buf + sizeof(buf);
s = seprint(buf, e, "%s lun %ld: ", fs->dev->dir, lun - &ums->lun[0]);
if(lun->flags & Finqok)
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);
s = ctlstring(fs);
count = usbreadbuf(data, count, offset, s, strlen(s));
free(s);
break;
case Qraw:
if(lun->lbsize <= 0 && umscapacity(lun) < 0){
@ -548,6 +665,7 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
uvlong bno;
Ums *ums;
Umsc *lun;
char *s;
ums = fs->dev->aux;
lun = fs->aux;
@ -560,7 +678,13 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
count = -1;
break;
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;
case Qraw:
if(lun->lbsize <= 0 && umscapacity(lun) < 0){

View file

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