Annotation of src/usr.bin/cdio/mmc.c, Revision 1.7
1.7 ! deraadt 1: /* $OpenBSD: mmc.c,v 1.6 2006/06/01 07:12:18 mjc Exp $ */
! 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>
22: #include <err.h>
1.2 mjc 23: #include <errno.h>
1.1 mjc 24: #include <fcntl.h>
25: #include <stdio.h>
26: #include <string.h>
27: #include <unistd.h>
28: #include "extern.h"
29:
30: extern int fd;
1.2 mjc 31: extern char *cdname;
1.1 mjc 32:
33: int
34: blank(void)
35: {
36: scsireq_t scr;
37: int r;
38:
39: bzero(&scr, sizeof(scr));
40: scr.cmd[0] = 0xa1;
41: scr.cmd[1] = 0x01;
42: scr.cmdlen = 12;
43: scr.datalen = 0;
44: scr.timeout = 120000;
45: scr.flags = SCCMD_ESCAPE;
46: scr.senselen = SENSEBUFLEN;
47:
1.2 mjc 48: r = ioctl(fd, SCIOCCOMMAND, &scr);
49: if (r == -1 && errno == EPERM) {
50: close(fd);
51: fd = -1;
1.7 ! deraadt 52: if (!open_cd(cdname, 1))
1.2 mjc 53: return (-1);
54: }
1.1 mjc 55: r = ioctl(fd, SCIOCCOMMAND, &scr);
56: return (r == 0 ? scr.retsts : -1);
57: }
58:
59: int
60: unit_ready(void)
61: {
62: scsireq_t scr;
63: int r;
64:
65: bzero(&scr, sizeof(scr));
66: scr.cmd[0] = 0x00;
67: scr.cmdlen = 6;
68: scr.datalen = 0;
69: scr.timeout = 120000;
70: scr.flags = SCCMD_ESCAPE;
71: scr.senselen = SENSEBUFLEN;
72:
73: r = ioctl(fd, SCIOCCOMMAND, &scr);
74: return (r == 0 ? scr.retsts : -1);
75: }
76:
77: int
78: synchronize_cache(void)
79: {
80: scsireq_t scr;
81: int r;
82:
83: bzero(&scr, sizeof(scr));
84: scr.cmd[0] = 0x35;
85: scr.cmdlen = 10;
86: scr.datalen = 0;
87: scr.timeout = 120000;
88: scr.flags = SCCMD_ESCAPE;
89: scr.senselen = SENSEBUFLEN;
90:
91: r = ioctl(fd, SCIOCCOMMAND, &scr);
92: return (r == 0 ? scr.retsts : -1);
93: }
94:
95: int
96: close_session(void)
97: {
98: scsireq_t scr;
99: int r;
100:
101: bzero(&scr, sizeof(scr));
102: scr.cmd[0] = 0x5b;
103: scr.cmd[2] = 0x02; /* close session */
104: scr.cmd[5] = 0x00; /* track number */
105: scr.cmdlen = 10;
106: scr.datalen = 0;
107: scr.timeout = 120000;
108: scr.flags = SCCMD_ESCAPE;
109: scr.senselen = SENSEBUFLEN;
110:
111: r = ioctl(fd, SCIOCCOMMAND, &scr);
112: return (r == 0 ? scr.retsts : -1);
113: }
114:
115: int
1.5 mjc 116: writetao(struct track_head *thp)
1.1 mjc 117: {
118: u_char modebuf[70];
1.5 mjc 119: struct track_info *tr;
1.7 ! deraadt 120: u_char bdlen;
1.5 mjc 121: int r;
122:
1.1 mjc 123: if ((r = mode_sense_write(modebuf)) != SCCMD_OK) {
124: warnx("mode sense failed: %d", r);
125: return (r);
126: }
127: bdlen = modebuf[7];
128: modebuf[2+8+bdlen] |= 0x40; /* Buffer Underrun Free Enable */
129: modebuf[2+8+bdlen] |= 0x01; /* change write type to TAO */
130:
1.5 mjc 131: SLIST_FOREACH(tr, thp, track_list) {
1.7 ! deraadt 132: switch (tr->type) {
1.5 mjc 133: case 'd':
1.1 mjc 134: modebuf[3+8+bdlen] = 0x04; /* track mode = data */
135: modebuf[4+8+bdlen] = 0x08; /* 2048 block track mode */
136: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 137: break;
138: case 'a':
1.1 mjc 139: modebuf[3+8+bdlen] = 0x00; /* track mode = audio */
140: modebuf[4+8+bdlen] = 0x00; /* 2352 block track mode */
141: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 142: break;
143: default:
144: warn("impossible tracktype detected");
145: break;
1.1 mjc 146: }
147: while (unit_ready() != SCCMD_OK)
148: continue;
149: if ((r = mode_select_write(modebuf)) != SCCMD_OK) {
150: warnx("mode select failed: %d",r);
151: return (r);
152: }
1.5 mjc 153: writetrack(tr);
1.1 mjc 154: synchronize_cache();
155: }
156: fprintf(stderr,"\n");
157: close_session();
158: return (0);
159: }
160:
161: int
1.5 mjc 162: writetrack(struct track_info *tr)
1.1 mjc 163: {
164: u_char databuf[65536];
165: scsireq_t scr;
166: u_int end_lba, lba;
167: u_int tmp;
168: int r,rfd;
169: u_char nblk;
170:
1.5 mjc 171: nblk = 65535/tr->blklen;
1.1 mjc 172: bzero(&scr, sizeof(scr));
173: scr.timeout = 300000;
174: scr.cmd[0] = 0x2a;
175: scr.cmd[1] = 0x00;
176: scr.cmd[8] = nblk; /* Transfer length in blocks (LSB) */
177: scr.cmdlen = 10;
178: scr.databuf = (caddr_t)databuf;
1.5 mjc 179: scr.datalen = nblk * tr->blklen;
1.1 mjc 180: scr.senselen = SENSEBUFLEN;
181: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
182:
183: if (get_nwa(&lba) != SCCMD_OK) {
184: warnx("cannot get next writable address");
185: return (-1);
186: }
187: tmp = htobe32(lba); /* update lba in cdb */
188: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
189:
1.5 mjc 190: if (tr->sz / tr->blklen + 1 > UINT_MAX || tr->sz < tr->blklen) {
191: warnx("file %s has invalid size",tr->file);
1.1 mjc 192: return (-1);
193: }
1.5 mjc 194: if (tr->sz % tr->blklen) {
1.7 ! deraadt 195: warnx("file %s is not multiple of block length %d",
! 196: tr->file, tr->blklen);
1.5 mjc 197: end_lba = tr->sz / tr->blklen + lba + 1;
1.1 mjc 198: } else {
1.5 mjc 199: end_lba = tr->sz / tr->blklen + lba;
1.1 mjc 200: }
1.5 mjc 201: rfd = open(tr->file, O_RDONLY, 0640);
202: if (tr->type == 'a') {
1.1 mjc 203: if (lseek(rfd, WAVHDRLEN, SEEK_SET) == -1)
204: err(1, "seek failed");
205: }
206: while ((lba < end_lba) && (nblk != 0)) {
207: while (lba + nblk <= end_lba) {
1.5 mjc 208: read(rfd, databuf, nblk * tr->blklen);
1.1 mjc 209: scr.cmd[8] = nblk;
1.5 mjc 210: scr.datalen = nblk * tr->blklen;
1.1 mjc 211: r = ioctl(fd, SCIOCCOMMAND, &scr);
212: if (r != 0) {
213: warn("ioctl failed while attempting to write");
214: return (-1);
215: }
216: if (scr.retsts != SCCMD_OK) {
1.7 ! deraadt 217: warnx("ioctl returned bad status while "
! 218: "attempting to write: %d",
! 219: scr.retsts);
1.1 mjc 220: return (r);
221: }
222: lba += nblk;
223: fprintf(stderr,"\rLBA: 0x%06x/0x%06x",lba,end_lba);
224: tmp = htobe32(lba); /* update lba in cdb */
225: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
226: }
227: nblk--;
228: }
229: close(rfd);
230: return (0);
231: }
232:
233: int
234: mode_sense_write(unsigned char buf[])
235: {
236: scsireq_t scr;
237: int r;
238:
239: bzero(&scr, sizeof(scr));
240: scr.timeout = 4000;
241: scr.senselen = SENSEBUFLEN;
242: scr.cmd[0] = 0x5a;
243: scr.cmd[1] = 0x00;
244: scr.cmd[2] = 0x05; /* Write parameters mode page */
245: scr.cmd[7] = 0x00;
246: scr.cmd[8] = 0x46; /* 16 for the header + size from pg. 89 mmc-r10a.pdf */
247: scr.cmdlen = 10;
1.7 ! deraadt 248: scr.datalen= 0x46;
1.1 mjc 249: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
250: scr.databuf = (caddr_t)buf;
251:
252: r = ioctl(fd, SCIOCCOMMAND, &scr);
253: return (r == 0 ? scr.retsts : -1);
254: }
255:
256: int
257: mode_select_write(unsigned char buf[])
258: {
259: scsireq_t scr;
260: int r;
261:
262: bzero(&scr, sizeof(scr));
263: scr.timeout = 4000;
264: scr.senselen = SENSEBUFLEN;
265: scr.cmd[0] = 0x55;
266: scr.cmd[1] = 0x10; /* pages aren't vendor specific */
267: scr.cmd[2] = 0x00;
268: scr.cmd[7] = 0x00;
269: scr.cmd[8] = 2 + buf[1] + 256 * buf[0];
270: scr.cmdlen = 10;
271: scr.datalen = 2 + buf[1] + 256 * buf[0];
272: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
273: scr.databuf = (caddr_t)buf;
274:
275: r = ioctl(fd, SCIOCCOMMAND, &scr);
1.6 mjc 276: return (r == 0 ? scr.retsts : -1);
277: }
278:
279: int
280: get_disc_size(off_t *availblk)
281: {
282: u_char databuf[28];
283: scsireq_t scr;
284: int r,tmp;
285:
286: bzero(&scr, sizeof(scr));
287: scr.timeout = 4000;
288: scr.senselen = SENSEBUFLEN;
289: scr.cmd[0] = 0x52; /* READ TRACK INFO */
290: scr.cmd[1] = 0x01;
291: scr.cmd[5] = 0x01; /* Track 01 */
292: scr.cmd[7] = 0x00;
293: scr.cmd[8] = 0x1c;
294: scr.cmdlen = 10;
1.7 ! deraadt 295: scr.datalen= 0x1c;
1.6 mjc 296: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
297: scr.databuf = (caddr_t)databuf;
298:
299: r = ioctl(fd, SCIOCCOMMAND, &scr);
300: memcpy(&tmp, &databuf[16], sizeof(tmp));
301: *availblk = betoh32(tmp);
1.1 mjc 302: return (r == 0 ? scr.retsts : -1);
303: }
304:
305: int
306: get_nwa(int *nwa)
307: {
308: u_char databuf[28];
309: scsireq_t scr;
310: int r,tmp;
311:
312: bzero(&scr, sizeof(scr));
313: scr.timeout = 4000;
314: scr.senselen = SENSEBUFLEN;
315: scr.cmd[0] = 0x52; /* READ TRACK INFO */
316: scr.cmd[1] = 0x01;
317: scr.cmd[5] = 0xff; /* Invisible Track */
318: scr.cmd[7] = 0x00;
319: scr.cmd[8] = 0x1c;
320: scr.cmdlen = 10;
1.7 ! deraadt 321: scr.datalen= 0x1c;
1.1 mjc 322: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
323: scr.databuf = (caddr_t)databuf;
324:
325: r = ioctl(fd, SCIOCCOMMAND, &scr);
326: memcpy(&tmp, &databuf[12], sizeof(tmp));
327: *nwa = betoh32(tmp);
328: return (r == 0 ? scr.retsts : -1);
329: }