static int mmcsetpage10(Drive *drive, int page, void *v) { uint8_t cmd[10], *p, *pagedata; int len, n; /* allocate parameter list, copy in mode page, fill in header */ pagedata = v; assert(pagedata[0] == page); len = Mode10parmhdrlen + Modepaghdrlen + pagedata[1]; p = emalloc(len); memmove(p + Mode10parmhdrlen, pagedata, pagedata[1]); /* parameter list header */ p[0] = 0; p[1] = len - 2; /* set up CDB */ initcdb(cmd, sizeof cmd, ScmdMselect10); cmd[1] = 0x10; /* format not vendor-specific */ cmd[8] = len; n = scsi(&drive->scsi, cmd, sizeof(cmd), p, len, Swrite); free(p); if(n < len) return -1; return 0; }
/* * `read cd' only works for CDs; for everybody else, * we'll try plain `read (12)'. only use read cd if it's * a cd drive with a cd in it and we're not reading data * (e.g., reading audio). */ static int fillread12cdb(Drive *drive, uint8_t *cmd, int32_t nblock, uint32_t off, int bs) { if (drive->type == TypeCD && drive->mmctype == Mmccd && bs != BScdrom) { initcdb(cmd, 12, ScmdReadcd); cmd[6] = nblock>>16; cmd[7] = nblock>>8; cmd[8] = nblock>>0; cmd[9] = 0x10; switch(bs){ case BScdda: cmd[1] = 0x04; break; case BScdrom: cmd[1] = 0x08; break; case BScdxa: cmd[1] = 0x0C; break; default: werrstr("unknown bs %d", bs); return -1; } } else { /* e.g., TypeDA */
int mmcstatus(Drive *drive) { uchar cmd[12]; initcdb(cmd, sizeof cmd, ScmdCDstatus); /* mechanism status */ return scsi(drive, cmd, sizeof(cmd), nil, 0, Sread); }
static int start(Drive *drive, int code) { uchar cmd[6]; initcdb(cmd, sizeof cmd, ScmdStart); cmd[4] = code; return scsi(drive, cmd, sizeof(cmd), cmd, 0, Snone); }
static int start(Drive *drive, int code) { uint8_t cmd[6]; initcdb(cmd, sizeof cmd, ScmdStart); cmd[4] = code; return scsi(&drive->scsi, cmd, sizeof(cmd), cmd, 0, Snone); }
/* t is a track number on disc, i is an index into drive->track[] for result */ static int mmctrackinfo(Drive *drive, int t, int i) { int n, type, bs; uint32_t beg, size; uint8_t tmode; uint8_t cmd[10], resp[255]; Track *track; initcdb(cmd, sizeof cmd, ScmdRtrackinfo); cmd[1] = 1; /* address below is logical track # */ cmd[2] = t>>24; cmd[3] = t>>16; cmd[4] = t>>8; cmd[5] = t; cmd[7] = sizeof(resp)>>8; cmd[8] = sizeof(resp); n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < 28) { if(vflag) print("trackinfo %d fails n=%d: %r\n", t, n); return -1; } tmode = resp[5] & 0x0D; // dmode = resp[6] & 0x0F; gettypebs(tmode, t, i, &type, &bs); beg = bige(&resp[8]); size = bige(&resp[24]); track = &drive->track[i]; track->mtime = drive->changetime; track->beg = beg; track->end = beg + size; track->type = type; track->bs = bs; track->size = (int64_t)(size-2) * bs; /* -2: skip lead out */ if(resp[6] & (1<<6)) { /* blank? */ track->type = TypeBlank; drive->writeok = Yes; } if(vflag) print(" start %lu end %lu", beg, beg + size - 1); gettracknwa(drive, t, beg, resp); if (vflag) print("\n"); return 0; }
static int getdevtype(Drive *drive) { int n; uchar cmd[6], resp[Pagesz]; initcdb(cmd, sizeof cmd, ScmdInq); cmd[3] = sizeof resp >> 8; cmd[4] = sizeof resp; n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread); if (n < 8) return -1; return resp[0] & 037; }
static int getbdstruct(Drive *drive) { int n; uchar cmd[12], resp[4100]; initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */ cmd[1] = 1; /* media type: bd */ 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); /* * 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 * 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]); return -1; } drive->erasableset = drive->recordableset = 1; drive->mmctype = Mmcbd; return 0; }
/* this may fail for blank media */ static int mmcreadtoc(Drive *drive, int type, int track, void *data, int nbytes) { uint8_t cmd[10]; initcdb(cmd, sizeof cmd, ScmdRTOC); cmd[1] = type; /* msf bit & reserved */ cmd[2] = Tocfmttoc; cmd[6] = track; /* track/session */ cmd[7] = nbytes>>8; cmd[8] = nbytes; /* * printing iounit(drive->scsi.rawfd) here yields * iounit(3) = 0; # for local access * iounit(3) = 65512; # for remote access via /mnt/term */ return scsi(&drive->scsi, cmd, sizeof(cmd), data, nbytes, Sread); }
static int getdvdstruct(Drive *drive) { int n, cat; uchar cmd[12], resp[Pagesz]; initcdb(cmd, sizeof cmd, ScmdReadDVD); /* actually, read disc structure */ cmd[1] = 0; /* media type: dvd */ cmd[7] = 0; /* format code: physical format */ cmd[8] = sizeof resp >> 8; /* allocation length */ cmd[9] = sizeof resp; n = scsi(drive, cmd, sizeof(cmd), resp, sizeof resp, Sread); if (n < 7) 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) 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; /* * 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; 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->mmctype = (cat >= 8? Mmcdvdplus: Mmcdvdminus); return 0; }
static int getdiscinfo(Drive *drive, uint8_t resp[], int resplen) { int n; uint8_t cmd[10]; initcdb(cmd, sizeof cmd, ScmdRdiscinfo); cmd[7] = resplen>>8; cmd[8] = resplen; n = scsi(&drive->scsi, 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 -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? */ return n; }
static int mmcgetpage6(Drive *drive, int page, void *v) { uint8_t cmd[6], resp[512]; int n; initcdb(cmd, sizeof cmd, ScmdMsense6); cmd[2] = page; cmd[4] = 255; /* allocation length */ n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < Mode6parmhdrlen) return -1; n -= Mode6parmhdrlen + resp[3]; if(n < 0) return -1; if(n > Pagesz) n = Pagesz; memmove(v, &resp[Mode6parmhdrlen + resp[3]], n); return n; }
static int getconfcmd(Drive *drive, uint8_t *resp, int respsz) { int n; uint32_t datalen; uint8_t cmd[10]; initcdb(cmd, sizeof cmd, Scmdgetconf); cmd[3] = 0; /* start with profile list feature */ cmd[7] = respsz >> 8; cmd[8] = respsz; n = scsi(&drive->scsi, cmd, sizeof cmd, resp, respsz, 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; return datalen; }
static int mmcsetpage6(Drive *drive, int page, void *v) { uint8_t cmd[6], *p, *pagedata; int len, n; if (vflag) print("mmcsetpage6 called!\n"); pagedata = v; assert(pagedata[0] == page); len = Mode6parmhdrlen + Modepaghdrlen + pagedata[1]; p = emalloc(len); memmove(p + Mode6parmhdrlen, pagedata, pagedata[1]); initcdb(cmd, sizeof cmd, ScmdMselect6); cmd[1] = 0x10; /* format not vendor-specific */ cmd[4] = len; n = scsi(&drive->scsi, cmd, sizeof(cmd), p, len, Swrite); free(p); if(n < len) return -1; return 0; }
static int mmcgetpage10(Drive *drive, int page, void *v) { uint8_t cmd[10], resp[512]; int n, r; initcdb(cmd, sizeof cmd, ScmdMsense10); cmd[2] = page; cmd[8] = 255; /* allocation length: buffer size */ n = scsi(&drive->scsi, cmd, sizeof(cmd), resp, sizeof(resp), Sread); if(n < Mode10parmhdrlen) return -1; r = (resp[6]<<8) | resp[7]; /* block descriptor length */ n -= Mode10parmhdrlen + r; if(n < 0) return -1; if(n > Pagesz) n = Pagesz; memmove(v, &resp[Mode10parmhdrlen + r], n); return n; }
static int getbdstruct(Drive *drive) { int n; uint8_t cmd[12], resp[4+4096]; uint8_t *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] = (int8_t)sizeof resp; n = scsi(&drive->scsi, 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 (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. */ 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; } /* printed getbdstruct: di bytes 98 di units/layers 32 */ // fprint(2, "getbdstruct: di bytes %d di units/layers %d\n", di[6], di[3]); drive->mmctype = Mmcbd; return 0; }