Annotation of src/usr.bin/cdio/mmc.c, Revision 1.20
1.20 ! av 1: /* $OpenBSD: mmc.c,v 1.19 2008/06/06 10:16:52 av Exp $ */
1.7 deraadt 2:
1.3 mjc 3: /*
4: * Copyright (c) 2006 Michael Coulter <mjc@openbsd.org>
5: *
6: * Permission to use, copy, modify, and distribute this software for any
7: * purpose with or without fee is hereby granted, provided that the above
8: * copyright notice and this permission notice appear in all copies.
9: *
10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17: */
18:
1.1 mjc 19: #include <sys/limits.h>
20: #include <sys/types.h>
21: #include <sys/scsiio.h>
1.8 mjc 22: #include <scsi/cd.h>
23: #include <scsi/scsi_all.h>
24: #include <scsi/scsi_disk.h>
1.1 mjc 25: #include <err.h>
1.2 mjc 26: #include <errno.h>
1.1 mjc 27: #include <fcntl.h>
28: #include <stdio.h>
29: #include <string.h>
30: #include <unistd.h>
31: #include "extern.h"
32:
33: extern int fd;
1.2 mjc 34: extern char *cdname;
1.20 ! av 35:
! 36: #define SCSI_GET_CONFIGURATION 0x46
! 37:
! 38: #define MMC_FEATURE_CD_TAO 0x2d
! 39: #define MMC_FEATURE_CDRW_WRITE 0x37
! 40:
! 41: int
! 42: get_media_capabilities(int *cap)
! 43: {
! 44: scsireq_t scr;
! 45: char buf[4096];
! 46: int error;
! 47: u_int32_t i, dsz;
! 48: u_int16_t feature;
! 49:
! 50: *cap = 0;
! 51: memset(buf, 0, sizeof(buf));
! 52: memset(&scr, 0, sizeof(scr));
! 53:
! 54: scr.cmd[0] = SCSI_GET_CONFIGURATION;
! 55: scr.cmd[1] = 1; /* enumerate only "current" features */
! 56: *(u_int16_t *)(scr.cmd + 7) = betoh16(sizeof(buf));
! 57:
! 58: scr.flags = SCCMD_ESCAPE | SCCMD_READ;
! 59: scr.databuf = buf;
! 60: scr.datalen = sizeof(buf);
! 61: scr.cmdlen = 10;
! 62: scr.timeout = 120000;
! 63: scr.senselen = SENSEBUFLEN;
! 64:
! 65: error = ioctl(fd, SCIOCCOMMAND, &scr);
! 66: if (error == -1 || scr.retsts != 0)
! 67: return (-1);
! 68: if (scr.datalen_used < 8)
! 69: return (-1); /* can't get header */
! 70:
! 71: dsz = betoh32(*(u_int32_t *)buf);
! 72: if (dsz > scr.datalen_used - 4)
! 73: dsz = scr.datalen_used - 4;
! 74:
! 75: dsz += 4; /* total size of bufer for all features */
! 76: i = 8;
! 77: while (i <= dsz - 4) {
! 78: if (dsz - i < 4 + buf[i + 3])
! 79: break; /* partial feature descriptor */
! 80: feature = betoh16(*(u_int16_t *)(buf + i));
! 81:
! 82: if (feature == MMC_FEATURE_CD_TAO)
! 83: *cap |= MEDIACAP_TAO;
! 84: else if (feature == MMC_FEATURE_CDRW_WRITE)
! 85: *cap |= MEDIACAP_CDRW_WRITE;
! 86:
! 87: i += 4 + buf[i + 3];
! 88: }
! 89:
! 90: return (0);
! 91: }
1.1 mjc 92:
93: int
94: blank(void)
95: {
1.8 mjc 96: struct scsi_blank *scb;
1.1 mjc 97: scsireq_t scr;
98: int r;
99:
100: bzero(&scr, sizeof(scr));
1.8 mjc 101: scb = (struct scsi_blank *)scr.cmd;
102: scb->opcode = BLANK;
103: scb->byte2 |= BLANK_MINIMAL;
104: scr.cmdlen = sizeof(*scb);
1.1 mjc 105: scr.datalen = 0;
106: scr.timeout = 120000;
107: scr.flags = SCCMD_ESCAPE;
108: scr.senselen = SENSEBUFLEN;
109:
1.2 mjc 110: r = ioctl(fd, SCIOCCOMMAND, &scr);
1.1 mjc 111: return (r == 0 ? scr.retsts : -1);
112: }
113:
114: int
115: unit_ready(void)
116: {
1.8 mjc 117: struct scsi_test_unit_ready *scb;
1.1 mjc 118: scsireq_t scr;
119: int r;
120:
121: bzero(&scr, sizeof(scr));
1.8 mjc 122: scb = (struct scsi_test_unit_ready *)scr.cmd;
123: scb->opcode = TEST_UNIT_READY;
124: scr.cmdlen = sizeof(*scb);
1.1 mjc 125: scr.datalen = 0;
126: scr.timeout = 120000;
127: scr.flags = SCCMD_ESCAPE;
128: scr.senselen = SENSEBUFLEN;
129:
130: r = ioctl(fd, SCIOCCOMMAND, &scr);
131: return (r == 0 ? scr.retsts : -1);
132: }
133:
134: int
135: synchronize_cache(void)
136: {
1.8 mjc 137: struct scsi_synchronize_cache *scb;
1.1 mjc 138: scsireq_t scr;
139: int r;
140:
141: bzero(&scr, sizeof(scr));
1.8 mjc 142: scb = (struct scsi_synchronize_cache *)scr.cmd;
143: scb->opcode = SYNCHRONIZE_CACHE;
144: scr.cmdlen = sizeof(*scb);
1.1 mjc 145: scr.datalen = 0;
146: scr.timeout = 120000;
147: scr.flags = SCCMD_ESCAPE;
148: scr.senselen = SENSEBUFLEN;
149:
150: r = ioctl(fd, SCIOCCOMMAND, &scr);
151: return (r == 0 ? scr.retsts : -1);
152: }
153:
154: int
155: close_session(void)
156: {
1.8 mjc 157: struct scsi_close_track *scb;
1.1 mjc 158: scsireq_t scr;
159: int r;
160:
161: bzero(&scr, sizeof(scr));
1.8 mjc 162: scb = (struct scsi_close_track *)scr.cmd;
163: scb->opcode = CLOSE_TRACK;
164: scb->closefunc = CT_CLOSE_SESS;
165: scr.cmdlen = sizeof(*scb);
1.1 mjc 166: scr.datalen = 0;
167: scr.timeout = 120000;
168: scr.flags = SCCMD_ESCAPE;
169: scr.senselen = SENSEBUFLEN;
170:
171: r = ioctl(fd, SCIOCCOMMAND, &scr);
172: return (r == 0 ? scr.retsts : -1);
173: }
174:
175: int
1.5 mjc 176: writetao(struct track_head *thp)
1.1 mjc 177: {
1.15 deraadt 178: u_char modebuf[70], bdlen;
1.5 mjc 179: struct track_info *tr;
1.15 deraadt 180: int r, track = 0;
1.5 mjc 181:
1.1 mjc 182: if ((r = mode_sense_write(modebuf)) != SCCMD_OK) {
183: warnx("mode sense failed: %d", r);
184: return (r);
185: }
186: bdlen = modebuf[7];
187: modebuf[2+8+bdlen] |= 0x40; /* Buffer Underrun Free Enable */
188: modebuf[2+8+bdlen] |= 0x01; /* change write type to TAO */
189:
1.5 mjc 190: SLIST_FOREACH(tr, thp, track_list) {
1.15 deraadt 191: track++;
1.7 deraadt 192: switch (tr->type) {
1.5 mjc 193: case 'd':
1.1 mjc 194: modebuf[3+8+bdlen] = 0x04; /* track mode = data */
195: modebuf[4+8+bdlen] = 0x08; /* 2048 block track mode */
196: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 197: break;
198: case 'a':
1.1 mjc 199: modebuf[3+8+bdlen] = 0x00; /* track mode = audio */
200: modebuf[4+8+bdlen] = 0x00; /* 2352 block track mode */
201: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 202: break;
203: default:
204: warn("impossible tracktype detected");
205: break;
1.1 mjc 206: }
207: while (unit_ready() != SCCMD_OK)
208: continue;
209: if ((r = mode_select_write(modebuf)) != SCCMD_OK) {
1.15 deraadt 210: warnx("mode select failed: %d", r);
1.1 mjc 211: return (r);
212: }
1.15 deraadt 213: writetrack(tr, track);
1.1 mjc 214: synchronize_cache();
215: }
1.15 deraadt 216: fprintf(stderr, "Closing session.\n");
1.1 mjc 217: close_session();
218: return (0);
219: }
220:
221: int
1.15 deraadt 222: writetrack(struct track_info *tr, int track)
1.1 mjc 223: {
1.15 deraadt 224: struct timeval tv, otv, atv;
225: u_char databuf[65536], nblk;
226: u_int end_lba, lba, tmp;
1.1 mjc 227: scsireq_t scr;
1.11 mjc 228: int r;
1.1 mjc 229:
1.5 mjc 230: nblk = 65535/tr->blklen;
1.1 mjc 231: bzero(&scr, sizeof(scr));
232: scr.timeout = 300000;
1.9 mjc 233: scr.cmd[0] = WRITE_BIG;
1.1 mjc 234: scr.cmd[1] = 0x00;
235: scr.cmd[8] = nblk; /* Transfer length in blocks (LSB) */
236: scr.cmdlen = 10;
237: scr.databuf = (caddr_t)databuf;
1.5 mjc 238: scr.datalen = nblk * tr->blklen;
1.1 mjc 239: scr.senselen = SENSEBUFLEN;
240: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
241:
1.15 deraadt 242: timerclear(&otv);
243: atv.tv_sec = 1;
244: atv.tv_usec = 0;
245:
1.1 mjc 246: if (get_nwa(&lba) != SCCMD_OK) {
247: warnx("cannot get next writable address");
248: return (-1);
249: }
250: tmp = htobe32(lba); /* update lba in cdb */
251: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
252:
1.5 mjc 253: if (tr->sz / tr->blklen + 1 > UINT_MAX || tr->sz < tr->blklen) {
1.15 deraadt 254: warnx("file %s has invalid size", tr->file);
1.1 mjc 255: return (-1);
256: }
1.5 mjc 257: if (tr->sz % tr->blklen) {
1.7 deraadt 258: warnx("file %s is not multiple of block length %d",
259: tr->file, tr->blklen);
1.5 mjc 260: end_lba = tr->sz / tr->blklen + lba + 1;
1.1 mjc 261: } else {
1.5 mjc 262: end_lba = tr->sz / tr->blklen + lba;
1.1 mjc 263: }
1.5 mjc 264: if (tr->type == 'a') {
1.11 mjc 265: if (lseek(tr->fd, WAVHDRLEN, SEEK_SET) == -1)
266: err(1, "seek failed for file %s", tr->file);
1.1 mjc 267: }
1.13 deraadt 268: while (lba < end_lba && nblk != 0) {
1.1 mjc 269: while (lba + nblk <= end_lba) {
1.11 mjc 270: read(tr->fd, databuf, nblk * tr->blklen);
1.1 mjc 271: scr.cmd[8] = nblk;
1.5 mjc 272: scr.datalen = nblk * tr->blklen;
1.12 mjc 273: again:
1.1 mjc 274: r = ioctl(fd, SCIOCCOMMAND, &scr);
275: if (r != 0) {
1.17 deraadt 276: printf("\r%60s", "");
1.1 mjc 277: warn("ioctl failed while attempting to write");
278: return (-1);
1.12 mjc 279: }
280: if (scr.retsts == SCCMD_SENSE && scr.sense[2] == 0x2) {
281: usleep(1000);
282: goto again;
1.1 mjc 283: }
284: if (scr.retsts != SCCMD_OK) {
1.17 deraadt 285: printf("\r%60s", "");
1.7 deraadt 286: warnx("ioctl returned bad status while "
287: "attempting to write: %d",
288: scr.retsts);
1.1 mjc 289: return (r);
290: }
291: lba += nblk;
1.15 deraadt 292:
293: gettimeofday(&tv, NULL);
294: if (lba == end_lba || timercmp(&tv, &otv, >)) {
295: fprintf(stderr,
1.17 deraadt 296: "\rtrack %02d '%c' %08u/%08u %3d%%",
1.15 deraadt 297: track, tr->type,
298: lba, end_lba, 100 * lba / end_lba);
299: timeradd(&tv, &atv, &otv);
300: }
1.1 mjc 301: tmp = htobe32(lba); /* update lba in cdb */
302: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
303: }
304: nblk--;
305: }
1.13 deraadt 306: printf("\n");
1.11 mjc 307: close(tr->fd);
1.1 mjc 308: return (0);
309: }
310:
311: int
312: mode_sense_write(unsigned char buf[])
313: {
1.8 mjc 314: struct scsi_mode_sense_big *scb;
1.1 mjc 315: scsireq_t scr;
316: int r;
317:
318: bzero(&scr, sizeof(scr));
1.8 mjc 319: scb = (struct scsi_mode_sense_big *)scr.cmd;
320: scb->opcode = MODE_SENSE_BIG;
321: /* XXX: need to set disable block descriptors and check SCSI drive */
322: scb->page = WRITE_PARAM_PAGE;
323: scb->length[1] = 0x46; /* 16 for the header + size from pg. 89 mmc-r10a.pdf */
324: scr.cmdlen = sizeof(*scb);
1.1 mjc 325: scr.timeout = 4000;
326: scr.senselen = SENSEBUFLEN;
1.7 deraadt 327: scr.datalen= 0x46;
1.1 mjc 328: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
329: scr.databuf = (caddr_t)buf;
330:
331: r = ioctl(fd, SCIOCCOMMAND, &scr);
332: return (r == 0 ? scr.retsts : -1);
333: }
334:
335: int
336: mode_select_write(unsigned char buf[])
337: {
1.8 mjc 338: struct scsi_mode_select_big *scb;
1.1 mjc 339: scsireq_t scr;
340: int r;
341:
342: bzero(&scr, sizeof(scr));
1.8 mjc 343: scb = (struct scsi_mode_select_big *)scr.cmd;
344: scb->opcode = MODE_SELECT_BIG;
1.10 deraadt 345:
346: /*
347: * INF-8020 says bit 4 in byte 2 is '1'
348: * INF-8090 refers to it as 'PF(1)' then doesn't
349: * describe it.
350: */
1.8 mjc 351: scb->byte2 = 0x10;
352: scb->length[1] = 2 + buf[1] + 256 * buf[0];
1.1 mjc 353: scr.timeout = 4000;
354: scr.senselen = SENSEBUFLEN;
1.8 mjc 355: scr.cmdlen = sizeof(*scb);
1.1 mjc 356: scr.datalen = 2 + buf[1] + 256 * buf[0];
357: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
358: scr.databuf = (caddr_t)buf;
359:
360: r = ioctl(fd, SCIOCCOMMAND, &scr);
1.6 mjc 361: return (r == 0 ? scr.retsts : -1);
362: }
363:
364: int
365: get_disc_size(off_t *availblk)
366: {
367: u_char databuf[28];
1.8 mjc 368: struct scsi_read_track_info *scb;
1.6 mjc 369: scsireq_t scr;
1.15 deraadt 370: int r, tmp;
1.6 mjc 371:
372: bzero(&scr, sizeof(scr));
1.8 mjc 373: scb = (struct scsi_read_track_info *)scr.cmd;
1.6 mjc 374: scr.timeout = 4000;
375: scr.senselen = SENSEBUFLEN;
1.8 mjc 376: scb->opcode = READ_TRACK_INFO;
377: scb->addrtype = RTI_TRACK;
1.16 mjc 378: scb->addr[3] = 1;
379: scb->data_len[1] = 0x1c;
1.8 mjc 380: scr.cmdlen = sizeof(*scb);
1.7 deraadt 381: scr.datalen= 0x1c;
1.6 mjc 382: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
383: scr.databuf = (caddr_t)databuf;
384:
385: r = ioctl(fd, SCIOCCOMMAND, &scr);
386: memcpy(&tmp, &databuf[16], sizeof(tmp));
387: *availblk = betoh32(tmp);
1.1 mjc 388: return (r == 0 ? scr.retsts : -1);
389: }
390:
391: int
392: get_nwa(int *nwa)
393: {
394: u_char databuf[28];
395: scsireq_t scr;
1.15 deraadt 396: int r, tmp;
1.1 mjc 397:
398: bzero(&scr, sizeof(scr));
399: scr.timeout = 4000;
400: scr.senselen = SENSEBUFLEN;
401: scr.cmd[0] = 0x52; /* READ TRACK INFO */
402: scr.cmd[1] = 0x01;
403: scr.cmd[5] = 0xff; /* Invisible Track */
404: scr.cmd[7] = 0x00;
405: scr.cmd[8] = 0x1c;
406: scr.cmdlen = 10;
1.7 deraadt 407: scr.datalen= 0x1c;
1.1 mjc 408: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
409: scr.databuf = (caddr_t)databuf;
410:
411: r = ioctl(fd, SCIOCCOMMAND, &scr);
412: memcpy(&tmp, &databuf[12], sizeof(tmp));
413: *nwa = betoh32(tmp);
414: return (r == 0 ? scr.retsts : -1);
415: }