shithub: riscv

Download patch

ref: 9b5b68a3022a6503aab296986fec1b463f9e6b1e
parent: c7ad44a0489ab779e410b58c0c504b9d8a99aa9c
author: cinap_lenrek <[email protected]>
date: Wed Aug 1 17:34:14 EDT 2012

cdfs: pull updates from sources

--- a/sys/src/cmd/cdfs/dat.h
+++ b/sys/src/cmd/cdfs/dat.h
@@ -30,6 +30,17 @@
 	TypeDisk,
 	TypeBlank,
 
+	/* disc writability classes */
+	Readonly	= 0,		/* -ROM */
+	Write1,				/* -R: write once only */
+	Erasewrite,			/* -R[WE]: erase then write */
+	Ram,				/* -RAM: read & write unrestricted */
+
+	/* tri-state flags */
+	Unset		= -1,
+	No,
+	Yes,
+
 	/* offsets in Pagcapmechsts mode page; see MMC-3 §5.5.10 */
 	Capread		= 2,
 	Capwrite	= 3,
@@ -129,11 +140,12 @@
 };
 
 typedef struct Buf Buf;
-typedef struct Drive Drive;
-typedef struct Track Track;
-typedef struct Otrack Otrack;
 typedef struct Dev Dev;
+typedef struct Drive Drive;
 typedef struct Msf Msf;		/* minute, second, frame */
+typedef struct Otrack Otrack;
+typedef struct Track Track;
+typedef schar Tristate;
 
 struct Msf {
 	int	m;
@@ -196,23 +208,24 @@
 	QLock;
 	Scsi;
 
-	int	type;			/* scsi peripheral device type */
+	int	type;			/* scsi peripheral device type: Type?? */
 
 	/* disc characteristics */
-	int	mmctype;
-	char	*dvdtype;
+	int	mmctype;		/* cd, dvd, or bd */
+	char	*dvdtype;		/* name of dvd flavour */
 	int	firsttrack;
+	int	invistrack;
 	int	ntrack;
 	int	nchange;		/* compare with the members in Scsi */
 	ulong	changetime;		/* " */
 	int	nameok;
-	int	writeok;
-	int	blank;			/* (not used for anything yet) */
-	int	blankset;
-	int	recordable;		/* writable by burning? */
-	int	recordableset;
-	int	erasable;		/* rewritable? */
-	int	erasableset;
+	int	writeok;		/* writable disc? */
+	/*
+	 * we could combine these attributes into a single variable except
+	 * that we discover them separately sometimes.
+	 */
+	Tristate recordable;		/* writable by burning? */
+	Tristate erasable;		/* writable after erasing? */
 
 	Track	track[Ntrack];
 	ulong	cap;			/* drive capabilities */
--- a/sys/src/cmd/cdfs/fns.h
+++ b/sys/src/cmd/cdfs/fns.h
@@ -4,6 +4,7 @@
 long	bufread(Otrack*, void*, long, vlong);
 long	bufwrite(Otrack*, void*, long);
 long	bwrite(Buf*, void*, long);
+char*	disctype(Drive *drive);
 void	*emalloc(ulong);
 char*	geterrstr(void);
 Drive*	mmcprobe(Scsi*);
--- a/sys/src/cmd/cdfs/main.c
+++ b/sys/src/cmd/cdfs/main.c
@@ -192,7 +192,7 @@
 	case Qwd:
 		if(drive->fixate(drive) < 0)
 			respond(r, geterrstr());
-// let us see if it can figure this out:	drive->writeok = 0;	
+// let us see if it can figure this out:	drive->writeok = No;	
 		else
 			respond(r, nil);
 		checktoc(drive);
@@ -204,7 +204,7 @@
 }
 
 /* result is one word, so it can be used as a uid in Dir structs */
-static char *
+char *
 disctype(Drive *drive)
 {
 	char *type, *rw;
@@ -229,9 +229,9 @@
 	}
 	rw = "";
 	if (drive->mmctype != Mmcnone && drive->dvdtype == nil)
-		if (drive->erasable)
+		if (drive->erasable == Yes)
 			rw = drive->mmctype == Mmcbd? "re": "rw";
-		else if (drive->recordable)
+		else if (drive->recordable == Yes)
 			rw = "r";
 		else
 			rw = "rom";
@@ -271,7 +271,7 @@
 		break;
 
 	case Qwa:
-		if(drive->writeok == 0 ||
+		if(drive->writeok == No ||
 		    drive->mmctype != Mmcnone &&
 		    drive->mmctype != Mmccd)
 			return 0;
@@ -281,7 +281,7 @@
 		break;
 
 	case Qwd:
-		if(drive->writeok == 0)
+		if(drive->writeok == No)
 			return 0;
 		d->name = "wd";
 		d->qid.type = QTDIR;
@@ -340,6 +340,7 @@
 readctl(Req *r)
 {
 	int i, isaudio;
+	ulong nwa;
 	char *p, *e, *ty;
 	char s[1024];
 	Msf *m;
@@ -375,9 +376,14 @@
 		ty = disctype(drive);
 		p = seprint(p, e, "%s", ty);
 		free(ty);
-		if (drive->mmctype != Mmcnone)
-			p = seprint(p, e, " next writable sector %lud",
-				getnwa(drive));
+		if (drive->mmctype != Mmcnone) {
+			nwa = getnwa(drive);
+			p = seprint(p, e, " next writable sector ");
+			if (nwa == ~0ul)
+				p = seprint(p, e, "none; disc full");
+			else
+				p = seprint(p, e, "%lud", nwa);
+		}
 		seprint(p, e, "\n");
 	}
 	readstr(r, s);
@@ -718,6 +724,7 @@
 	if(dev == nil || mtpt == nil || argc > 0)
 		usage();
 
+	werrstr("");
 	if((s = openscsi(dev)) == nil)
 		sysfatal("openscsi '%s': %r", dev);
 	if((drive = mmcprobe(s)) == nil)
--- a/sys/src/cmd/cdfs/mmc.c
+++ b/sys/src/cmd/cdfs/mmc.c
@@ -14,6 +14,8 @@
 
 enum
 {
+	Desperate	= 0,	/* non-zero grubs around in inquiry string */
+
 	Pagesz		= 255,
 
 	Pagwrparams	= 5,	/* (cd|dvd)-r(w) device write parameters */
@@ -33,7 +35,7 @@
 	int	pagecmdsz;
 
 	/* disc characteristics */
-	ulong	mmcnwa;
+	long	mmcnwa;			/* next writable address (block #) */
 	int	nropen;
 	int	nwopen;
 	vlong	ntotby;
@@ -60,6 +62,8 @@
 	"type-15-unknown",
 };
 
+static int getinvistrack(Drive *drive);
+
 static ulong
 bige(void *p)
 {
@@ -110,16 +114,6 @@
 	cdb[0] = cmd;
 }
 
-//static uchar *
-//newcdb(int len, int cmd)
-//{
-//	uchar *cdb;
-//
-//	cdb = emalloc(len);
-//	cdb[0] = cmd;
-//	return cdb;
-//}
-
 /*
  * SCSI CDBs (cmd arrays) are 6, 10, 12, 16 or 32 bytes long.
  * The mode sense/select commands implicitly refer to
@@ -162,14 +156,9 @@
 	uchar cmd[10], resp[512];
 	int n, r;
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdMsense10;
+	initcdb(cmd, sizeof cmd, ScmdMsense10);
 	cmd[2] = page;
 	cmd[8] = 255;			/* allocation length: buffer size */
-
-//	print("get: sending cmd\n");
-//	hexdump(cmd, 10);
-
 	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof(resp), Sread);
 	if(n < Mode10parmhdrlen)
 		return -1;
@@ -183,12 +172,6 @@
 		n = Pagesz;
 
 	memmove(v, &resp[Mode10parmhdrlen + r], n);
-
-//	print("get: got cmd\n");
-//	hexdump(cmd, 10);
-//	print("page\n");
-//	hexdump(v, n);
-
 	return n;
 }
 
@@ -198,8 +181,7 @@
 	uchar cmd[6], resp[512];
 	int n;
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdMsense6;
+	initcdb(cmd, sizeof cmd, ScmdMsense6);
 	cmd[2] = page;
 	cmd[4] = 255;			/* allocation length */
 
@@ -234,8 +216,7 @@
 	p[1] = len - 2;
 
 	/* set up CDB */
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdMselect10;
+	initcdb(cmd, sizeof cmd, ScmdMselect10);
 	cmd[1] = 0x10;			/* format not vendor-specific */
 	cmd[8] = len;
 
@@ -271,8 +252,7 @@
 	p = emalloc(len);
 	memmove(p + Mode6parmhdrlen, pagedata, pagedata[1]);
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdMselect6;
+	initcdb(cmd, sizeof cmd, ScmdMselect6);
 	cmd[1] = 0x10;			/* format not vendor-specific */
 	cmd[4] = len;
 
@@ -388,11 +368,16 @@
 
 	if (vflag)
 		print("mmcprobe: inquiry: %s\n", scsi->inquire);
+
 	drive = emalloc(sizeof(Drive));
 	drive->Scsi = *scsi;
 	drive->Dev = mmcdev;
+	drive->invistrack = -1;
+	getinvistrack(drive);
+
 	aux = emalloc(sizeof(Mmcaux));
 	drive->aux = aux;
+
 	scsiready(drive);
 	drive->type = getdevtype(drive);
 	if (drive->type != TypeCD) {
@@ -480,6 +465,7 @@
 mmctrackinfo(Drive *drive, int t, int i)
 {
 	int n, type, bs;
+	long newnwa;
 	ulong beg, size;
 	uchar tmode;
 	uchar cmd[10], resp[255];
@@ -486,8 +472,7 @@
 	Mmcaux *aux;
 
 	aux = drive->aux;
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdRtrackinfo;
+	initcdb(cmd, sizeof cmd, ScmdRtrackinfo);
 	cmd[1] = 1;			/* address below is logical track # */
 	cmd[2] = t>>24;
 	cmd[3] = t>>16;
@@ -545,20 +530,32 @@
 
 	if(resp[6] & (1<<6)) {			/* blank? */
 		drive->track[i].type = TypeBlank;
-		drive->writeok = 1;
+		drive->writeok = Yes;
 	}
 
+	/*
+	 * figure out the first writable block, if we can
+	 */
 	if(vflag)
 		print(" start %lud end %lud", beg, beg + size - 1);
-	/* resp[6] & (1<<7) of zero: invisible track */
-	/* t == getinvistrack(): invisible track */
-	if(t == Invistrack || resp[7] & 1) {	/* invis or nwa valid? */
-		aux->mmcnwa = bige(&resp[12]);
-		if ((long)aux->mmcnwa < 0)	/* implausible? */
-			aux->mmcnwa = 0;
-		if (vflag)
-			print(" nwa %lud", aux->mmcnwa);
+	if(resp[7] & 1) {			/* nwa valid? */
+		newnwa = bige(&resp[12]);
+		if (newnwa >= 0)
+			if (aux->mmcnwa < 0)
+				aux->mmcnwa = newnwa;
+			else if (aux->mmcnwa != newnwa)
+				fprint(2, "nwa is %ld but invis track starts blk %ld\n",
+					newnwa, aux->mmcnwa);
 	}
+	/* resp[6] & (1<<7) of zero: invisible track */
+	if(t == Invistrack || t == drive->invistrack)
+		if (aux->mmcnwa < 0)
+			aux->mmcnwa = beg;
+		else if (aux->mmcnwa != beg)
+			fprint(2, "invis track starts blk %ld but nwa is %ld\n",
+				beg, aux->mmcnwa);
+	if (vflag && aux->mmcnwa >= 0)
+		print(" nwa %lud", aux->mmcnwa);
 	if (vflag)
 		print("\n");
 	return 0;
@@ -570,8 +567,7 @@
 {
 	uchar cmd[10];
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdRTOC;
+	initcdb(cmd, sizeof cmd, ScmdRTOC);
 	cmd[1] = type;				/* msf bit & reserved */
 	cmd[2] = Tocfmttoc;
 	cmd[6] = track;				/* track/session */
@@ -586,26 +582,6 @@
 	return scsi(drive, cmd, sizeof(cmd), data, nbytes, Sread);
 }
 
-static int
-mmcreaddiscinfo(Drive *drive, void *data, int nbytes)
-{
-	uchar cmd[10];
-	int n;
-
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdRdiscinfo;
-	cmd[7] = nbytes>>8;
-	cmd[8] = nbytes;
-	n = scsi(drive, cmd, sizeof(cmd), data, nbytes, Sread);
-	if(n < 24) {
-		if(n >= 0)
-			werrstr("rdiscinfo returns %d", n);
-		return -1;
-	}
-
-	return n;
-}
-
 static Msf
 rdmsf(uchar *p)
 {
@@ -621,22 +597,108 @@
 getdiscinfo(Drive *drive, uchar resp[], int resplen)
 {
 	int n;
+	uchar cmd[10];
 
-	n = mmcreaddiscinfo(drive, resp, resplen);
-	if(n < 3) {
-		if (vflag)
+	initcdb(cmd, sizeof cmd, ScmdRdiscinfo);
+	cmd[7] = resplen>>8;
+	cmd[8] = resplen;
+	n = scsi(drive, cmd, sizeof(cmd), resp, resplen, Sread);
+	if(n < 24) {
+		if(n >= 0)
+			werrstr("rdiscinfo returns %d", n);
+		else if (vflag)
 			fprint(2, "read disc info failed\n");
-		return n;
+		return -1;
 	}
 	if (vflag)
 		fprint(2, "read disc info succeeded\n");
 	assert((resp[2] & 0340) == 0);			/* data type 0 */
 	drive->erasable = ((resp[2] & 0x10) != 0);	/* -RW? */
-	drive->erasableset = 1;
 	return n;
 }
 
 static int
+getconf(Drive *drive)
+{
+	int n;
+	ushort prof;
+	ulong datalen;
+	uchar cmd[10];
+	uchar resp[2*1024];	/* 64k-8 ok, 2k often enough, 400 typical */
+
+	initcdb(cmd, sizeof cmd, Scmdgetconf);
+	cmd[3] = 1;			/* start with core feature */
+	cmd[7] = sizeof resp >> 8;
+	cmd[8] = sizeof resp;
+	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
+	if (n < 0) {
+		if(vflag)
+			fprint(2, "get config cmd failed\n");
+		return -1;
+	}
+	if (n < 4)
+		return -1;
+	datalen = GETBELONG(resp+0);
+	if (datalen < 8)
+		return -1;
+	/*
+	 * features start with an 8-byte header:
+	 * ulong datalen, ushort reserved, ushort current profile.
+	 * profile codes (table 92) are: 0 reserved, 1-7 legacy, 8-0xf cd,
+	 * 0x10-0x1f 0x2a-0x2b dvd*, 0x40-0x4f bd, 0x50-0x5f hd dvd,
+	 * 0xffff whacko.
+	 *
+	 * this is followed by multiple feature descriptors:
+	 * ushort code, uchar bits, uchar addnl_len, addnl_len bytes.
+	 */
+	prof = resp[6]<<8 | resp[7];
+	if(prof == 0 || prof == 0xffff)	/* none or whacko? */
+		return n;
+	if(drive->mmctype != Mmcnone)
+		return n;
+	switch (prof >> 4) {
+	case 0:
+		drive->mmctype = Mmccd;
+		break;
+	case 1:
+		if (prof == 0x1a || prof == 0x1b)
+			drive->mmctype = Mmcdvdplus;
+		else
+			drive->mmctype = Mmcdvdminus;
+		break;
+	case 2:
+		drive->mmctype = Mmcdvdplus;	/* dual layer */
+		break;
+	case 4:
+		drive->mmctype = Mmcbd;
+		/*
+		 * further decode prof to set writability flags.
+		 * mostly for Pioneer BDR-206M.  there may be unnecessary
+		 * future profiles for dual, triple and quad layer;
+		 * let's hope not.
+		 */
+		switch (prof) {
+		case 0x40:
+			drive->erasable = drive->recordable = No;
+		case 0x41:
+		case 0x42:
+			drive->erasable = No;
+			drive->recordable = Yes;
+			break;
+		case 0x43:
+			drive->erasable = Yes;
+			drive->recordable = No;
+			break;
+		}
+		break;
+	case 5:
+		drive->mmctype = Mmcdvdminus;	/* hd dvd, obs. */
+		break;
+	}
+	return n;
+}
+
+static int
 getdvdstruct(Drive *drive)
 {
 	int n, cat;
@@ -648,12 +710,12 @@
 	cmd[8] = sizeof resp >> 8;	/* allocation length */
 	cmd[9] = sizeof resp;
 	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
-	if (n < 7)
+	if (n < 7) {
+		if(vflag)
+			fprint(2, "read disc structure (dvd) cmd failed\n");
 		return -1;
+	}
 
-//	print("dvd structure:\n");
-//	hexdump(resp, n);
-
 	/* resp[0..1] is resp length */
 	cat = (resp[4] & 0xf0) >> 4;	/* disk category, MMC-6 §6.22.3.2.1 */
 	if (vflag)
@@ -660,7 +722,7 @@
 		fprint(2, "dvd type is %s\n", dvdtype[cat]);
 	drive->dvdtype = dvdtype[cat];
 	/* write parameters mode page may suffice to compute writeok for dvd */
-	drive->erasable = drive->recordable = 0;
+	drive->erasable = drive->recordable = No;
 	/*
 	 * the layer-type field is a *bit array*,
 	 * though an enumeration of types would make more sense,
@@ -667,58 +729,108 @@
 	 * since the types are exclusive, not orthogonal.
 	 */
 	if (resp[6] & (1<<2))			/* rewritable? */
-		drive->erasable = 1;
+		drive->erasable = Yes;
 	else if (resp[6] & (1<<1))		/* recordable once? */
-		drive->recordable = 1;
-	else {					/* factory-pressed disk */
-		drive->blank = 0;
-		drive->blankset = 1;
-	}
-	drive->erasableset = drive->recordableset = 1;
+		drive->recordable = Yes;
+	/* else it's a factory-pressed disk */
 	drive->mmctype = (cat >= 8? Mmcdvdplus: Mmcdvdminus);
 	return 0;
 }
 
+/*
+ * ugly hack to divine device type from inquiry string as last resort.
+ * mostly for Pioneer BDR-206M.
+ */
 static int
+bdguess(Drive *drive)
+{
+	if (drive->mmctype == Mmcnone) {
+		if (strstr(drive->Scsi.inquire, "BD") == nil)
+			return -1;
+		if (vflag)
+			fprint(2, "drive probably a BD (from inquiry string)\n");
+		drive->mmctype = Mmcbd;
+	} else if (drive->mmctype == Mmcbd) {
+		if (drive->erasable != Unset && drive->recordable != Unset)
+			return 0;
+	} else
+		return -1;
+
+	drive->recordable = drive->writeok = No;
+	if (strstr(drive->Scsi.inquire, "RW") != nil) {
+		if (vflag)
+			fprint(2, "drive probably a burner (from inquiry string)\n");
+		drive->recordable = drive->writeok = Yes;
+		if (drive->erasable == Unset) {	/* set by getdiscinfo perhaps */
+			drive->erasable = No;	/* no way to tell, alas */
+			if (vflag)
+				fprint(2, "\tassuming -r not -rw\n");
+		}
+	} else {
+		if (drive->erasable == Unset)
+			drive->erasable = No;
+	}
+	if (drive->erasable == Yes)
+		drive->recordable = No;		/* mutually exclusive */
+	return 0;
+}
+
+static int
 getbdstruct(Drive *drive)
 {
 	int n;
-	uchar cmd[12], resp[4100];
+	uchar cmd[12], resp[4+4096];
+	uchar *di, *body;
 
 	initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */
 	cmd[1] = 1;			/* media type: bd */
+	/* cmd[6] is layer #, 0 is first */
 	cmd[7] = 0;			/* format code: disc info */
 	cmd[8] = sizeof resp >> 8;	/* allocation length */
 	cmd[9] = sizeof resp;
 	n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread);
+	if(n < 0) {
+		if(vflag)
+			fprint(2, "read disc structure (bd) cmd failed\n");
+		return -1;
+	}
+
 	/*
-	 * resp[0..1] is resp length.
-	 * resp[4+8..4+8+2] is bd type (disc type identifier):
-	 * BDO|BDW|BDR, MMC-6 §6.22.3.3.1.  The above command should
+	 * resp[0..1] is resp length (4100); 2 & 3 are reserved.
+	 * there may be multiple disc info structs of 112 bytes each.
+	 * disc info (di) starts at 4.  di[0..7] are header, followed by body.
+	 * body[0..2] is bd type (disc type identifier):
+	 * BDO|BDW|BDR, MMC-6 §6.22.3.3.1.  The above scsi command should
 	 * fail on DVD drives, but some seem to ignore media type
 	 * and return successfully, so verify that it's a BD drive.
 	 */
-	if (n < 4+8+3 || resp[4+8] != 'B' || resp[4+8+1] != 'D')
+	di = resp + 4;
+	body = di + 8;
+	n -= 4 + 8;
+	if (n < 3 || di[0] != 'D' || di[1] != 'I' ||
+	    body[0] != 'B' || body[1] != 'D') {
+		if(vflag)
+			fprint(2, "it's not a bd\n");
 		return -1;
+	}
 	if (vflag)
-		fprint(2, "read disc structure (bd) succeeded\n");
-	drive->erasable = drive->recordable = 0;
-	switch (resp[4+8+2]) {
-	case 'O':
-		drive->blank = 0;
-		drive->blankset = 1;
+		fprint(2, "read disc structure (bd) succeeded; di format %d\n",
+			di[2]);
+
+	drive->erasable = drive->recordable = No;
+	switch (body[2]) {
+	case 'O':				/* read-Only */
 		break;
 	case 'R':				/* Recordable */
-		drive->recordable = 1;
+		drive->recordable = Yes;
 		break;
 	case 'W':				/* reWritable */
-		drive->erasable = 1;
+		drive->erasable = Yes;
 		break;
 	default:
-		fprint(2, "%s: unknown bd type BD%c\n", argv0, resp[4+8+2]);
+		fprint(2, "%s: unknown bd type BD%c\n", argv0, body[2]);
 		return -1;
 	}
-	drive->erasableset = drive->recordableset = 1;
 	drive->mmctype = Mmcbd;
 	return 0;
 }
@@ -809,10 +921,11 @@
 	drive->nameok = 0;
 	drive->nchange = drive->Scsi.nchange;
 	drive->changetime = drive->Scsi.changetime;
-	drive->writeok = drive->erasable = drive->recordable = drive->blank = 0;
-	drive->erasableset = drive->recordableset = drive->blankset = 0;
+	drive->writeok = No;
+	drive->erasable = drive->recordable = Unset;
+	getinvistrack(drive);
 	aux = drive->aux;
-	aux->mmcnwa = 0;
+	aux->mmcnwa = -1;
 	aux->nropen = aux->nwopen = 0;
 	aux->ntotby = aux->ntotbk = 0;
 
@@ -822,7 +935,7 @@
 	}
 
 	/*
-	 * TODO: set read ahead, MMC-6 §6.37, seems to control caching.
+	 * should set read ahead, MMC-6 §6.37, seems to control caching.
 	 */
 
 	/*
@@ -830,8 +943,8 @@
 	 */
 	if((n = mmcreadtoc(drive, Msfbit, 0, resp, sizeof(resp))) < 4) {
 		/*
-		 * on a blank disc in a cd-rw, use readdiscinfo
-		 * to find the track info.
+		 * it could be a blank disc.  in case it's a blank disc in a
+		 * cd-rw drive, use readdiscinfo to try to find the track info.
 		 */
 		if(getdiscinfo(drive, resp, sizeof(resp)) < 7)
 			return -1;
@@ -841,9 +954,8 @@
 		first = resp[3];
 		last = resp[6];
 		if(vflag)
-			print("blank disc %d %d\n", first, last);
-		/* the assumption of blankness may be unwarranted */
-		drive->writeok = drive->blank = drive->blankset = 1;
+			print("tracks %d-%d\n", first, last);
+		drive->writeok = Yes;
 	} else {
 		first = resp[2];
 		last = resp[3];
@@ -858,26 +970,28 @@
 		}
 	}
 
+	/* deduce disc type */
 	drive->mmctype = Mmcnone;
 	drive->dvdtype = nil;
 	getdvdstruct(drive);
+	getconf(drive);
 	getbdstruct(drive);
+	if (Desperate)
+		bdguess(drive);
 	if (drive->mmctype == Mmcnone)
 		drive->mmctype = Mmccd;		/* by default */
-	if (drive->recordable || drive->erasable)
-		drive->writeok = 1;
+	if (drive->recordable == Yes || drive->erasable == Yes)
+		drive->writeok = Yes;
 
 	if (vflag) {
 		fprint(2, "writeok %d", drive->writeok);
-		/* drive->blank is never used and hard to figure out */
-//		if (drive->blankset)
-//			fprint(2, " blank %d", drive->blank);
-		if (drive->recordableset)
+		if (drive->recordable != Unset)
 			fprint(2, " recordable %d", drive->recordable);
-		if (drive->erasableset)
+		if (drive->erasable != Unset)
 			fprint(2, " erasable %d", drive->erasable);
 		fprint(2, "\n");
-		print("first %d last %d\n", first, last);
+		fprint(2, "first %d last %d\n", first, last);
+		fprint(2, "it's a %s disc.\n\n", disctype(drive)); /* leak */
 	}
 
 	if(first == 0 && last == 0)
@@ -954,7 +1068,7 @@
 		switch(bs){
 		case BScdda:
 			/* 2 audio channels without pre-emphasis */
-			settrkmode(p, Tmcdda);	/* TODO: should be Tm2audio? */
+			settrkmode(p, Tmcdda);	/* should be Tm2audio? */
 			p[Wpdatblktype] = Dbraw;
 			break;
 		case BScdrom:
@@ -1023,9 +1137,8 @@
 	 * a cd drive with a cd in it and we're not reading data
 	 * (e.g., reading audio).
 	 */
-	memset(cmd, 0, sizeof(cmd));
 	if (drive->type == TypeCD && drive->mmctype == Mmccd && bs != BScdrom) {
-		cmd[0] = ScmdReadcd;
+		initcdb(cmd, sizeof cmd, ScmdReadcd);
 		cmd[2] = off>>24;
 		cmd[3] = off>>16;
 		cmd[4] = off>>8;
@@ -1049,7 +1162,7 @@
 			return -1;
 		}
 	} else {			/* e.g., TypeDA */
-		cmd[0] = ScmdRead12;
+		initcdb(cmd, sizeof cmd, ScmdRead12);
 		cmd[2] = off>>24;
 		cmd[3] = off>>16;
 		cmd[4] = off>>8;
@@ -1111,7 +1224,7 @@
 	uchar *fmtdesc;
 	uchar cmd[6], parms[4+8];
 
-	if (drive->recordable && drive->mmctype != Mmcbd) {
+	if (drive->recordable == Yes && drive->mmctype != Mmcbd) {
 		werrstr("don't format write-once cd or dvd media");
 		return -1;
 	}
@@ -1154,12 +1267,13 @@
 static long
 mmcxwrite(Otrack *o, void *v, long nblk)
 {
+	int r;
 	uchar cmd[10];
 	Mmcaux *aux;
 
 	assert(o->omode == OWRITE);
 	aux = o->drive->aux;
-	if (aux->mmcnwa == 0 && scsiready(o->drive) < 0) {
+	if (aux->mmcnwa == -1 && scsiready(o->drive) < 0) {
 		werrstr("device not ready to write");
 		return -1;
 	}
@@ -1166,8 +1280,7 @@
 	aux->ntotby += nblk*o->track->bs;
 	aux->ntotbk += nblk;
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdExtwrite;		/* write (10) */
+	initcdb(cmd, sizeof cmd, ScmdExtwrite);	/* write (10) */
 	cmd[2] = aux->mmcnwa>>24;
 	cmd[3] = aux->mmcnwa>>16;
 	cmd[4] = aux->mmcnwa>>8;
@@ -1177,8 +1290,14 @@
 	if(vflag)
 		print("%lld ns: write %ld at 0x%lux\n",
 			nsec(), nblk, aux->mmcnwa);
+	r = scsi(o->drive, cmd, sizeof(cmd), v, nblk*o->track->bs, Swrite);
+	if (r < 0)
+		fprint(2, "%s: write error at blk offset %,ld = "
+			"offset %,lld / bs %ld: %r\n",
+			argv0, aux->mmcnwa, (vlong)aux->mmcnwa * o->track->bs,
+			o->track->bs);
 	aux->mmcnwa += nblk;
-	return scsi(o->drive, cmd, sizeof(cmd), v, nblk*o->track->bs, Swrite);
+	return r;
 }
 
 static long
@@ -1241,6 +1360,7 @@
 	if(vflag)
 		print("getinvistrack: track #%d session #%d\n",
 			resp[2], resp[3]);
+	drive->invistrack = resp[2];
 	return resp[2];
 }
 
@@ -1247,7 +1367,7 @@
 static Otrack*
 mmccreate(Drive *drive, int type)
 {
-	int bs, invis;
+	int bs;
 	Mmcaux *aux;
 	Track *t;
 	Otrack *o;
@@ -1271,15 +1391,11 @@
 		return nil;
 	}
 
-	invis = getinvistrack(drive);
-	if (invis < 0)
-		invis = Invistrack;
-
 	/* comment out the returns for now; it should be no big deal - geoff */
-	if(mmctrackinfo(drive, invis, Maxtrack)) {
+	if(mmctrackinfo(drive, drive->invistrack, Maxtrack)) {
 		if (vflag)
 			fprint(2, "mmccreate: mmctrackinfo for invis track %d"
-				" failed: %r\n", invis);
+				" failed: %r\n", drive->invistrack);
 		werrstr("disc not writable");
 //		return nil;
 	}
@@ -1287,10 +1403,10 @@
 		werrstr("cannot set bs mode");
 //		return nil;
 	}
-	if(mmctrackinfo(drive, invis, Maxtrack)) {
+	if(mmctrackinfo(drive, drive->invistrack, Maxtrack)) {
 		if (vflag)
 			fprint(2, "mmccreate: mmctrackinfo for invis track %d"
-				" (2) failed: %r\n", invis);
+				" (2) failed: %r\n", drive->invistrack);
 		werrstr("disc not writable 2");
 //		return nil;
 	}
@@ -1297,10 +1413,10 @@
 
 	/* special hack for dvd-r: reserve the invisible track */
 	if (drive->mmctype == Mmcdvdminus && drive->writeok &&
-	    drive->recordable && reserve(drive, invis) < 0) {
+	    drive->recordable == Yes && reserve(drive, drive->invistrack) < 0) {
 		if (vflag)
 			fprint(2, "mmcreate: reserving track %d for dvd-r "
-				"failed: %r\n", invis);
+				"failed: %r\n", drive->invistrack);
 		return nil;
 	}
 
@@ -1339,8 +1455,7 @@
 {
 	uchar cmd[10];
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdClosetracksess;
+	initcdb(cmd, sizeof cmd, ScmdClosetracksess);
 	/* cmd[1] & 1 is the immediate bit */
 	cmd[2] = clf;				/* close function */
 	if(clf == Closetrack)
@@ -1352,7 +1467,6 @@
 void
 mmcsynccache(Drive *drive)
 {
-	int invis;
 	uchar cmd[10];
 	Mmcaux *aux;
 
@@ -1364,7 +1478,7 @@
 	if (vflag) {
 		fprint(2, "syncing cache");
 		if (drive->mmctype == Mmcdvdminus && drive->writeok &&
-		    drive->recordable)
+		    drive->recordable == Yes)
 			fprint(2, "; dvd-r burning rest of track reservation, "
 				"will be slow");
 		fprint(2, "\n");
@@ -1376,21 +1490,19 @@
 			aux->ntotby, aux->ntotbk, aux->mmcnwa);
 	}
 
-	invis = getinvistrack(drive);
-	if (invis < 0)
-		invis = Invistrack;
 	/*
 	 * rsc: seems not to work on some drives.
 	 * so ignore return code & don't issue on dvd+rw.
 	 */
-	if(drive->mmctype != Mmcdvdplus || !drive->erasable) {
+	if(drive->mmctype != Mmcdvdplus || drive->erasable == No) {
 		if (vflag)
 			fprint(2, "closing invisible track %d (not dvd+rw)...\n",
-				invis);
- 		mmcxclose(drive, Closetrack, invis);
+				drive->invistrack);
+ 		mmcxclose(drive, Closetrack, drive->invistrack);
 		if (vflag)
 			fprint(2, "... done.\n");
 	}
+	getinvistrack(drive);		/* track # has probably changed */
 }
 
 /*
@@ -1445,7 +1557,7 @@
 	setonesess(drive);
 
 	/* skip explicit close session on bd-r */
-	if (drive->mmctype != Mmcbd || drive->erasable) {
+	if (drive->mmctype != Mmcbd || drive->erasable == Yes) {
 		if (vflag)
 			fprint(2, "closing session and maybe finalizing...\n");
 		r = mmcxclose(drive, Closesessfinal, 0);
@@ -1459,7 +1571,7 @@
 	 * Closedvdrbdfinal closes & finalizes dvd+r and bd-r.
 	 */
 	if ((drive->mmctype == Mmcdvdplus || drive->mmctype == Mmcbd) &&
-	    !drive->erasable) {
+	    drive->erasable == No) {
 		if (vflag)
 			fprint(2, "finalizing dvd+r or bd-r... "
 				"(won't print `done').\n");
@@ -1475,8 +1587,7 @@
 
 	drive->nchange = -1;		/* force reread toc */
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdBlank;		/* blank cd-rw media */
+	initcdb(cmd, sizeof cmd, ScmdBlank);	/* blank cd-rw media */
 	/* immediate bit is 0x10 */
 	/* cmd[1] = 0 means blank the whole disc; = 1 just the header */
 	cmd[1] = quick ? 0x01 : 0x00;
@@ -1519,8 +1630,7 @@
 	char *rv;
 	uchar cmd[12];
 
-	memset(cmd, 0, sizeof(cmd));
-	cmd[0] = ScmdSetcdspeed;
+	initcdb(cmd, sizeof cmd, ScmdSetcdspeed);
 	cmd[2] = r>>8;
 	cmd[3] = r;
 	cmd[4] = w>>8;