shithub: riscv

Download patch

ref: 24d7f981ec545afb9e78152a717a550a4498edf7
parent: 28859a83f41b4c5231865cc556665f2060c70010
author: ment <[email protected]>
date: Sat May 7 21:36:37 EDT 2011

usb/disk: ctl write support

--- a/sys/src/cmd/usb/disk/disk.c
+++ b/sys/src/cmd/usb/disk/disk.c
@@ -38,7 +38,130 @@
 	[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
  */
 int exabyte, force6bytecmds;
@@ -461,8 +584,8 @@
 {
 	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 @@
 		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 @@
 	uvlong bno;
 	Ums *ums;
 	Umsc *lun;
+	char *s;
 
 	ums = fs->dev->aux;
 	lun = fs->aux;
@@ -560,7 +678,13 @@
 		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){
--- a/sys/src/cmd/usb/disk/ums.h
+++ b/sys/src/cmd/usb/disk/ums.h
@@ -7,6 +7,7 @@
 typedef struct Ums Ums;
 typedef struct Cbw Cbw;			/* command block wrapper */
 typedef struct Csw Csw;			/* command status wrapper */
+typedef struct Part Part;
 
 enum
 {
@@ -42,6 +43,8 @@
 	CswOk		= 0,
 	CswFailed	= 1,
 	CswPhaseErr	= 2,
+	
+	Maxparts		= 8,
 };
 
 /*
@@ -48,6 +51,18 @@
  * 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;
@@ -58,6 +73,9 @@
 	char	*bufp;
 	long	off;		/* offset within a block */
 	long	nb;		/* byte count */
+
+	/* partitions */
+	Part part[Maxparts];
 
 	uchar 	rawcmd[10];
 	uchar	phase;