Annotation of src/usr.bin/cdio/mmc.c, Revision 1.16
1.16 ! mjc 1: /* $OpenBSD: mmc.c,v 1.15 2006/08/26 03:48:50 deraadt 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.1 mjc 35:
36: int
37: blank(void)
38: {
1.8 mjc 39: struct scsi_blank *scb;
1.1 mjc 40: scsireq_t scr;
41: int r;
42:
43: bzero(&scr, sizeof(scr));
1.8 mjc 44: scb = (struct scsi_blank *)scr.cmd;
45: scb->opcode = BLANK;
46: scb->byte2 |= BLANK_MINIMAL;
47: scr.cmdlen = sizeof(*scb);
1.1 mjc 48: scr.datalen = 0;
49: scr.timeout = 120000;
50: scr.flags = SCCMD_ESCAPE;
51: scr.senselen = SENSEBUFLEN;
52:
1.2 mjc 53: r = ioctl(fd, SCIOCCOMMAND, &scr);
54: if (r == -1 && errno == EPERM) {
55: close(fd);
56: fd = -1;
1.7 deraadt 57: if (!open_cd(cdname, 1))
1.2 mjc 58: return (-1);
59: }
1.1 mjc 60: r = ioctl(fd, SCIOCCOMMAND, &scr);
61: return (r == 0 ? scr.retsts : -1);
62: }
63:
64: int
65: unit_ready(void)
66: {
1.8 mjc 67: struct scsi_test_unit_ready *scb;
1.1 mjc 68: scsireq_t scr;
69: int r;
70:
71: bzero(&scr, sizeof(scr));
1.8 mjc 72: scb = (struct scsi_test_unit_ready *)scr.cmd;
73: scb->opcode = TEST_UNIT_READY;
74: scr.cmdlen = sizeof(*scb);
1.1 mjc 75: scr.datalen = 0;
76: scr.timeout = 120000;
77: scr.flags = SCCMD_ESCAPE;
78: scr.senselen = SENSEBUFLEN;
79:
80: r = ioctl(fd, SCIOCCOMMAND, &scr);
81: return (r == 0 ? scr.retsts : -1);
82: }
83:
84: int
85: synchronize_cache(void)
86: {
1.8 mjc 87: struct scsi_synchronize_cache *scb;
1.1 mjc 88: scsireq_t scr;
89: int r;
90:
91: bzero(&scr, sizeof(scr));
1.8 mjc 92: scb = (struct scsi_synchronize_cache *)scr.cmd;
93: scb->opcode = SYNCHRONIZE_CACHE;
94: scr.cmdlen = sizeof(*scb);
1.1 mjc 95: scr.datalen = 0;
96: scr.timeout = 120000;
97: scr.flags = SCCMD_ESCAPE;
98: scr.senselen = SENSEBUFLEN;
99:
100: r = ioctl(fd, SCIOCCOMMAND, &scr);
101: return (r == 0 ? scr.retsts : -1);
102: }
103:
104: int
105: close_session(void)
106: {
1.8 mjc 107: struct scsi_close_track *scb;
1.1 mjc 108: scsireq_t scr;
109: int r;
110:
111: bzero(&scr, sizeof(scr));
1.8 mjc 112: scb = (struct scsi_close_track *)scr.cmd;
113: scb->opcode = CLOSE_TRACK;
114: scb->closefunc = CT_CLOSE_SESS;
115: scr.cmdlen = sizeof(*scb);
1.1 mjc 116: scr.datalen = 0;
117: scr.timeout = 120000;
118: scr.flags = SCCMD_ESCAPE;
119: scr.senselen = SENSEBUFLEN;
120:
121: r = ioctl(fd, SCIOCCOMMAND, &scr);
122: return (r == 0 ? scr.retsts : -1);
123: }
124:
125: int
1.5 mjc 126: writetao(struct track_head *thp)
1.1 mjc 127: {
1.15 deraadt 128: u_char modebuf[70], bdlen;
1.5 mjc 129: struct track_info *tr;
1.15 deraadt 130: int r, track = 0;
1.5 mjc 131:
1.1 mjc 132: if ((r = mode_sense_write(modebuf)) != SCCMD_OK) {
133: warnx("mode sense failed: %d", r);
134: return (r);
135: }
136: bdlen = modebuf[7];
137: modebuf[2+8+bdlen] |= 0x40; /* Buffer Underrun Free Enable */
138: modebuf[2+8+bdlen] |= 0x01; /* change write type to TAO */
139:
1.5 mjc 140: SLIST_FOREACH(tr, thp, track_list) {
1.15 deraadt 141: track++;
1.7 deraadt 142: switch (tr->type) {
1.5 mjc 143: case 'd':
1.1 mjc 144: modebuf[3+8+bdlen] = 0x04; /* track mode = data */
145: modebuf[4+8+bdlen] = 0x08; /* 2048 block track mode */
146: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 147: break;
148: case 'a':
1.1 mjc 149: modebuf[3+8+bdlen] = 0x00; /* track mode = audio */
150: modebuf[4+8+bdlen] = 0x00; /* 2352 block track mode */
151: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 152: break;
153: default:
154: warn("impossible tracktype detected");
155: break;
1.1 mjc 156: }
157: while (unit_ready() != SCCMD_OK)
158: continue;
159: if ((r = mode_select_write(modebuf)) != SCCMD_OK) {
1.15 deraadt 160: warnx("mode select failed: %d", r);
1.1 mjc 161: return (r);
162: }
1.15 deraadt 163: writetrack(tr, track);
1.1 mjc 164: synchronize_cache();
165: }
1.15 deraadt 166: fprintf(stderr, "Closing session.\n");
1.1 mjc 167: close_session();
168: return (0);
169: }
170:
171: int
1.15 deraadt 172: writetrack(struct track_info *tr, int track)
1.1 mjc 173: {
1.15 deraadt 174: struct timeval tv, otv, atv;
175: u_char databuf[65536], nblk;
176: u_int end_lba, lba, tmp;
1.1 mjc 177: scsireq_t scr;
1.11 mjc 178: int r;
1.1 mjc 179:
1.5 mjc 180: nblk = 65535/tr->blklen;
1.1 mjc 181: bzero(&scr, sizeof(scr));
182: scr.timeout = 300000;
1.9 mjc 183: scr.cmd[0] = WRITE_BIG;
1.1 mjc 184: scr.cmd[1] = 0x00;
185: scr.cmd[8] = nblk; /* Transfer length in blocks (LSB) */
186: scr.cmdlen = 10;
187: scr.databuf = (caddr_t)databuf;
1.5 mjc 188: scr.datalen = nblk * tr->blklen;
1.1 mjc 189: scr.senselen = SENSEBUFLEN;
190: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
191:
1.15 deraadt 192: timerclear(&otv);
193: atv.tv_sec = 1;
194: atv.tv_usec = 0;
195:
1.1 mjc 196: if (get_nwa(&lba) != SCCMD_OK) {
197: warnx("cannot get next writable address");
198: return (-1);
199: }
200: tmp = htobe32(lba); /* update lba in cdb */
201: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
202:
1.5 mjc 203: if (tr->sz / tr->blklen + 1 > UINT_MAX || tr->sz < tr->blklen) {
1.15 deraadt 204: warnx("file %s has invalid size", tr->file);
1.1 mjc 205: return (-1);
206: }
1.5 mjc 207: if (tr->sz % tr->blklen) {
1.7 deraadt 208: warnx("file %s is not multiple of block length %d",
209: tr->file, tr->blklen);
1.5 mjc 210: end_lba = tr->sz / tr->blklen + lba + 1;
1.1 mjc 211: } else {
1.5 mjc 212: end_lba = tr->sz / tr->blklen + lba;
1.1 mjc 213: }
1.5 mjc 214: if (tr->type == 'a') {
1.11 mjc 215: if (lseek(tr->fd, WAVHDRLEN, SEEK_SET) == -1)
216: err(1, "seek failed for file %s", tr->file);
1.1 mjc 217: }
1.13 deraadt 218: while (lba < end_lba && nblk != 0) {
1.1 mjc 219: while (lba + nblk <= end_lba) {
1.11 mjc 220: read(tr->fd, databuf, nblk * tr->blklen);
1.1 mjc 221: scr.cmd[8] = nblk;
1.5 mjc 222: scr.datalen = nblk * tr->blklen;
1.12 mjc 223: again:
1.1 mjc 224: r = ioctl(fd, SCIOCCOMMAND, &scr);
225: if (r != 0) {
1.15 deraadt 226: printf("%60s\r", "");
1.1 mjc 227: warn("ioctl failed while attempting to write");
228: return (-1);
1.12 mjc 229: }
230: if (scr.retsts == SCCMD_SENSE && scr.sense[2] == 0x2) {
231: usleep(1000);
232: goto again;
1.1 mjc 233: }
234: if (scr.retsts != SCCMD_OK) {
1.15 deraadt 235: printf("%60s\r", "");
1.7 deraadt 236: warnx("ioctl returned bad status while "
237: "attempting to write: %d",
238: scr.retsts);
1.1 mjc 239: return (r);
240: }
241: lba += nblk;
1.15 deraadt 242:
243: gettimeofday(&tv, NULL);
244: if (lba == end_lba || timercmp(&tv, &otv, >)) {
245: fprintf(stderr,
246: "track %02d '%c' %08u/%08u %3d%%\r",
247: track, tr->type,
248: lba, end_lba, 100 * lba / end_lba);
249: timeradd(&tv, &atv, &otv);
250: }
1.1 mjc 251: tmp = htobe32(lba); /* update lba in cdb */
252: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
253: }
254: nblk--;
255: }
1.13 deraadt 256: printf("\n");
1.11 mjc 257: close(tr->fd);
1.1 mjc 258: return (0);
259: }
260:
261: int
262: mode_sense_write(unsigned char buf[])
263: {
1.8 mjc 264: struct scsi_mode_sense_big *scb;
1.1 mjc 265: scsireq_t scr;
266: int r;
267:
268: bzero(&scr, sizeof(scr));
1.8 mjc 269: scb = (struct scsi_mode_sense_big *)scr.cmd;
270: scb->opcode = MODE_SENSE_BIG;
271: /* XXX: need to set disable block descriptors and check SCSI drive */
272: scb->page = WRITE_PARAM_PAGE;
273: scb->length[1] = 0x46; /* 16 for the header + size from pg. 89 mmc-r10a.pdf */
274: scr.cmdlen = sizeof(*scb);
1.1 mjc 275: scr.timeout = 4000;
276: scr.senselen = SENSEBUFLEN;
1.7 deraadt 277: scr.datalen= 0x46;
1.1 mjc 278: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
279: scr.databuf = (caddr_t)buf;
280:
281: r = ioctl(fd, SCIOCCOMMAND, &scr);
282: return (r == 0 ? scr.retsts : -1);
283: }
284:
285: int
286: mode_select_write(unsigned char buf[])
287: {
1.8 mjc 288: struct scsi_mode_select_big *scb;
1.1 mjc 289: scsireq_t scr;
290: int r;
291:
292: bzero(&scr, sizeof(scr));
1.8 mjc 293: scb = (struct scsi_mode_select_big *)scr.cmd;
294: scb->opcode = MODE_SELECT_BIG;
1.10 deraadt 295:
296: /*
297: * INF-8020 says bit 4 in byte 2 is '1'
298: * INF-8090 refers to it as 'PF(1)' then doesn't
299: * describe it.
300: */
1.8 mjc 301: scb->byte2 = 0x10;
302: scb->length[1] = 2 + buf[1] + 256 * buf[0];
1.1 mjc 303: scr.timeout = 4000;
304: scr.senselen = SENSEBUFLEN;
1.8 mjc 305: scr.cmdlen = sizeof(*scb);
1.1 mjc 306: scr.datalen = 2 + buf[1] + 256 * buf[0];
307: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
308: scr.databuf = (caddr_t)buf;
309:
310: r = ioctl(fd, SCIOCCOMMAND, &scr);
1.6 mjc 311: return (r == 0 ? scr.retsts : -1);
312: }
313:
314: int
315: get_disc_size(off_t *availblk)
316: {
317: u_char databuf[28];
1.8 mjc 318: struct scsi_read_track_info *scb;
1.6 mjc 319: scsireq_t scr;
1.15 deraadt 320: int r, tmp;
1.6 mjc 321:
322: bzero(&scr, sizeof(scr));
1.8 mjc 323: scb = (struct scsi_read_track_info *)scr.cmd;
1.6 mjc 324: scr.timeout = 4000;
325: scr.senselen = SENSEBUFLEN;
1.8 mjc 326: scb->opcode = READ_TRACK_INFO;
327: scb->addrtype = RTI_TRACK;
1.16 ! mjc 328: scb->addr[3] = 1;
! 329: scb->data_len[1] = 0x1c;
1.8 mjc 330: scr.cmdlen = sizeof(*scb);
1.7 deraadt 331: scr.datalen= 0x1c;
1.6 mjc 332: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
333: scr.databuf = (caddr_t)databuf;
334:
335: r = ioctl(fd, SCIOCCOMMAND, &scr);
336: memcpy(&tmp, &databuf[16], sizeof(tmp));
337: *availblk = betoh32(tmp);
1.1 mjc 338: return (r == 0 ? scr.retsts : -1);
339: }
340:
341: int
342: get_nwa(int *nwa)
343: {
344: u_char databuf[28];
345: scsireq_t scr;
1.15 deraadt 346: int r, tmp;
1.1 mjc 347:
348: bzero(&scr, sizeof(scr));
349: scr.timeout = 4000;
350: scr.senselen = SENSEBUFLEN;
351: scr.cmd[0] = 0x52; /* READ TRACK INFO */
352: scr.cmd[1] = 0x01;
353: scr.cmd[5] = 0xff; /* Invisible Track */
354: scr.cmd[7] = 0x00;
355: scr.cmd[8] = 0x1c;
356: scr.cmdlen = 10;
1.7 deraadt 357: scr.datalen= 0x1c;
1.1 mjc 358: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
359: scr.databuf = (caddr_t)databuf;
360:
361: r = ioctl(fd, SCIOCCOMMAND, &scr);
362: memcpy(&tmp, &databuf[12], sizeof(tmp));
363: *nwa = betoh32(tmp);
364: return (r == 0 ? scr.retsts : -1);
365: }