usb/disk: ctl write support
This commit is contained in:
parent
28859a83f4
commit
24d7f981ec
2 changed files with 154 additions and 12 deletions
|
@ -38,6 +38,129 @@ static Dirtab dirtab[] =
|
||||||
[Qdata] "data", 0640,
|
[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
|
* These are used by scuzz scsireq
|
||||||
*/
|
*/
|
||||||
|
@ -461,8 +584,8 @@ 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;
|
||||||
Umsc *lun;
|
Umsc *lun;
|
||||||
Ums *ums;
|
Ums *ums;
|
||||||
Qid q;
|
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);
|
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){
|
||||||
|
@ -548,6 +665,7 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
|
||||||
uvlong bno;
|
uvlong bno;
|
||||||
Ums *ums;
|
Ums *ums;
|
||||||
Umsc *lun;
|
Umsc *lun;
|
||||||
|
char *s;
|
||||||
|
|
||||||
ums = fs->dev->aux;
|
ums = fs->dev->aux;
|
||||||
lun = fs->aux;
|
lun = fs->aux;
|
||||||
|
@ -560,7 +678,13 @@ dwrite(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
|
||||||
count = -1;
|
count = -1;
|
||||||
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){
|
||||||
|
|
|
@ -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,26 @@ enum
|
||||||
CswOk = 0,
|
CswOk = 0,
|
||||||
CswFailed = 1,
|
CswFailed = 1,
|
||||||
CswPhaseErr = 2,
|
CswPhaseErr = 2,
|
||||||
|
|
||||||
|
Maxparts = 8,
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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 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 +74,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;
|
||||||
|
|
Loading…
Reference in a new issue