diff --git a/sys/src/cmd/cdfs/dat.h b/sys/src/cmd/cdfs/dat.h index 8408ecccf..2dca92b24 100644 --- a/sys/src/cmd/cdfs/dat.h +++ b/sys/src/cmd/cdfs/dat.h @@ -30,6 +30,17 @@ enum { 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 @@ enum { }; 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 @@ struct Drive 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 */ diff --git a/sys/src/cmd/cdfs/fns.h b/sys/src/cmd/cdfs/fns.h index ef4f6742b..5227bc034 100644 --- a/sys/src/cmd/cdfs/fns.h +++ b/sys/src/cmd/cdfs/fns.h @@ -4,6 +4,7 @@ void bterm(Buf*); 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*); diff --git a/sys/src/cmd/cdfs/main.c b/sys/src/cmd/cdfs/main.c index cf3a3ed28..7ef34f371 100644 --- a/sys/src/cmd/cdfs/main.c +++ b/sys/src/cmd/cdfs/main.c @@ -192,7 +192,7 @@ fsremove(Req *r) 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 @@ fsremove(Req *r) } /* 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 @@ disctype(Drive *drive) } 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 @@ fillstat(ulong qid, Dir *d) break; case Qwa: - if(drive->writeok == 0 || + if(drive->writeok == No || drive->mmctype != Mmcnone && drive->mmctype != Mmccd) return 0; @@ -281,7 +281,7 @@ fillstat(ulong qid, Dir *d) break; case Qwd: - if(drive->writeok == 0) + if(drive->writeok == No) return 0; d->name = "wd"; d->qid.type = QTDIR; @@ -340,6 +340,7 @@ static void readctl(Req *r) { int i, isaudio; + ulong nwa; char *p, *e, *ty; char s[1024]; Msf *m; @@ -375,9 +376,14 @@ readctl(Req *r) 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 @@ main(int argc, char **argv) if(dev == nil || mtpt == nil || argc > 0) usage(); + werrstr(""); if((s = openscsi(dev)) == nil) sysfatal("openscsi '%s': %r", dev); if((drive = mmcprobe(s)) == nil) diff --git a/sys/src/cmd/cdfs/mmc.c b/sys/src/cmd/cdfs/mmc.c index c2ee6caf2..4fbec235e 100644 --- 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 @@ struct Mmcaux { int pagecmdsz; /* disc characteristics */ - ulong mmcnwa; + long mmcnwa; /* next writable address (block #) */ int nropen; int nwopen; vlong ntotby; @@ -60,6 +62,8 @@ static char *dvdtype[] = { "type-15-unknown", }; +static int getinvistrack(Drive *drive); + static ulong bige(void *p) { @@ -110,16 +114,6 @@ initcdb(uchar *cdb, int len, int cmd) 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 @@ mmcgetpage10(Drive *drive, int page, void *v) 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 @@ mmcgetpage10(Drive *drive, int page, void *v) 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 @@ mmcgetpage6(Drive *drive, int page, void *v) 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 @@ mmcsetpage10(Drive *drive, int page, void *v) 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 @@ mmcsetpage6(Drive *drive, int page, void *v) 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 @@ mmcprobe(Scsi *scsi) 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,14 +465,14 @@ static int mmctrackinfo(Drive *drive, int t, int i) { int n, type, bs; + long newnwa; ulong beg, size; uchar tmode; uchar cmd[10], resp[255]; 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 @@ mmctrackinfo(Drive *drive, int t, int i) 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 @@ mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes) { 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 @@ mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes) 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,18 +597,104 @@ static int 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; } @@ -648,11 +710,11 @@ getdvdstruct(Drive *drive) 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 */ @@ -660,65 +722,115 @@ getdvdstruct(Drive *drive) 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, * 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') - 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; - break; - case 'R': /* Recordable */ - drive->recordable = 1; - break; - case 'W': /* reWritable */ - drive->erasable = 1; - break; - default: - fprint(2, "%s: unknown bd type BD%c\n", argv0, resp[4+8+2]); + 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; di format %d\n", + di[2]); + + drive->erasable = drive->recordable = No; + switch (body[2]) { + case 'O': /* read-Only */ + break; + case 'R': /* Recordable */ + drive->recordable = Yes; + break; + case 'W': /* reWritable */ + drive->erasable = Yes; + break; + default: + 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 @@ mmcgettoc(Drive *drive) 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 @@ mmcgettoc(Drive *drive) } /* - * 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 @@ mmcgettoc(Drive *drive) */ 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 @@ mmcgettoc(Drive *drive) 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 @@ mmcgettoc(Drive *drive) } } + /* 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 @@ mmcsetbs(Drive *drive, int bs) 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 @@ mmcread(Buf *buf, void *v, long nblock, ulong off) * 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 @@ mmcread(Buf *buf, void *v, long nblock, ulong off) 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 @@ format(Drive *drive) 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,20 +1267,20 @@ format(Drive *drive) 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; } 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 @@ mmcxwrite(Otrack *o, void *v, long nblk) 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,13 +1360,14 @@ getinvistrack(Drive *drive) if(vflag) print("getinvistrack: track #%d session #%d\n", resp[2], resp[3]); + drive->invistrack = resp[2]; return resp[2]; } static Otrack* mmccreate(Drive *drive, int type) { - int bs, invis; + int bs; Mmcaux *aux; Track *t; Otrack *o; @@ -1271,15 +1391,11 @@ mmccreate(Drive *drive, int type) 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,20 +1403,20 @@ mmccreate(Drive *drive, int type) 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; } /* 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 @@ mmcxclose(Drive *drive, int clf, int trackno) { 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 @@ mmcxclose(Drive *drive, int clf, int trackno) void mmcsynccache(Drive *drive) { - int invis; uchar cmd[10]; Mmcaux *aux; @@ -1364,7 +1478,7 @@ mmcsynccache(Drive *drive) 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 @@ mmcsynccache(Drive *drive) 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 @@ mmcfixate(Drive *drive) 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 @@ mmcfixate(Drive *drive) * 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 @@ mmcblank(Drive *drive, int quick) 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 @@ mmcsetspeed(Drive *drive, int r, int w) 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;