summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorment <thement@ibawizard.net>2011-05-08 01:36:37 +0200
committerment <thement@ibawizard.net>2011-05-08 01:36:37 +0200
commit24d7f981ec545afb9e78152a717a550a4498edf7 (patch)
tree41d6e7f9a0a8c97e324a8d492afcda737ad1e107
parent28859a83f41b4c5231865cc556665f2060c70010 (diff)
usb/disk: ctl write support
-rw-r--r--sys/src/cmd/usb/disk/disk.c148
-rw-r--r--sys/src/cmd/usb/disk/ums.h18
2 files changed, 154 insertions, 12 deletions
diff --git a/sys/src/cmd/usb/disk/disk.c b/sys/src/cmd/usb/disk/disk.c
index 884df2d04..8eea67c2a 100644
--- a/sys/src/cmd/usb/disk/disk.c
+++ b/sys/src/cmd/usb/disk/disk.c
@@ -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){
diff --git a/sys/src/cmd/usb/disk/ums.h b/sys/src/cmd/usb/disk/ums.h
index d65f8897b..d1c8219dc 100644
--- a/sys/src/cmd/usb/disk/ums.h
+++ b/sys/src/cmd/usb/disk/ums.h
@@ -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;