Annotation of src/usr.bin/cdio/mmc.c, Revision 1.6
1.6 ! mjc 1: /* $OpenBSD: mmc.c,v 1.5 2006/06/01 06:32:17 mjc Exp $ */
1.3 mjc 2: /*
3: * Copyright (c) 2006 Michael Coulter <mjc@openbsd.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
1.1 mjc 18: #include <sys/limits.h>
19: #include <sys/types.h>
20: #include <sys/scsiio.h>
21: #include <err.h>
1.2 mjc 22: #include <errno.h>
1.1 mjc 23: #include <fcntl.h>
24: #include <stdio.h>
25: #include <string.h>
26: #include <unistd.h>
27: #include "extern.h"
28:
1.2 mjc 29: extern int errno;
1.1 mjc 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;
52: if (! open_cd(cdname, 1))
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:
116: int
1.5 mjc 117: writetao(struct track_head *thp)
1.1 mjc 118: {
119: u_char modebuf[70];
1.5 mjc 120: struct track_info *tr;
121: int r;
1.1 mjc 122: u_char bdlen;
1.5 mjc 123:
1.1 mjc 124: if ((r = mode_sense_write(modebuf)) != SCCMD_OK) {
125: warnx("mode sense failed: %d", r);
126: return (r);
127: }
128: bdlen = modebuf[7];
129: modebuf[2+8+bdlen] |= 0x40; /* Buffer Underrun Free Enable */
130: modebuf[2+8+bdlen] |= 0x01; /* change write type to TAO */
131:
1.5 mjc 132: SLIST_FOREACH(tr, thp, track_list) {
133: switch(tr->type) {
134: case 'd':
1.1 mjc 135: modebuf[3+8+bdlen] = 0x04; /* track mode = data */
136: modebuf[4+8+bdlen] = 0x08; /* 2048 block track mode */
137: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 138: break;
139: case 'a':
1.1 mjc 140: modebuf[3+8+bdlen] = 0x00; /* track mode = audio */
141: modebuf[4+8+bdlen] = 0x00; /* 2352 block track mode */
142: modebuf[8+8+bdlen] = 0x00; /* turn off XA */
1.5 mjc 143: break;
144: default:
145: warn("impossible tracktype detected");
146: break;
1.1 mjc 147: }
148: while (unit_ready() != SCCMD_OK)
149: continue;
150: if ((r = mode_select_write(modebuf)) != SCCMD_OK) {
151: warnx("mode select failed: %d",r);
152: return (r);
153: }
1.5 mjc 154: writetrack(tr);
1.1 mjc 155: synchronize_cache();
156: }
157: fprintf(stderr,"\n");
158: close_session();
159: return (0);
160: }
161:
162: int
1.5 mjc 163: writetrack(struct track_info *tr)
1.1 mjc 164: {
165: u_char databuf[65536];
166: scsireq_t scr;
167: u_int end_lba, lba;
168: u_int tmp;
169: int r,rfd;
170: u_char nblk;
171:
1.5 mjc 172: nblk = 65535/tr->blklen;
1.1 mjc 173: bzero(&scr, sizeof(scr));
174: scr.timeout = 300000;
175: scr.cmd[0] = 0x2a;
176: scr.cmd[1] = 0x00;
177: scr.cmd[8] = nblk; /* Transfer length in blocks (LSB) */
178: scr.cmdlen = 10;
179: scr.databuf = (caddr_t)databuf;
1.5 mjc 180: scr.datalen = nblk * tr->blklen;
1.1 mjc 181: scr.senselen = SENSEBUFLEN;
182: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
183:
184: if (get_nwa(&lba) != SCCMD_OK) {
185: warnx("cannot get next writable address");
186: return (-1);
187: }
188: tmp = htobe32(lba); /* update lba in cdb */
189: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
190:
1.5 mjc 191: if (tr->sz / tr->blklen + 1 > UINT_MAX || tr->sz < tr->blklen) {
192: warnx("file %s has invalid size",tr->file);
1.1 mjc 193: return (-1);
194: }
1.5 mjc 195: if (tr->sz % tr->blklen) {
196: warnx("file %s is not multiple of block length %d", tr->file, tr->blklen);
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) {
217: warnx("ioctl returned bad status while attempting to write: %d", scr.retsts);
218: return (r);
219: }
220: lba += nblk;
221: fprintf(stderr,"\rLBA: 0x%06x/0x%06x",lba,end_lba);
222: tmp = htobe32(lba); /* update lba in cdb */
223: memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
224: }
225: nblk--;
226: }
227: close(rfd);
228: return (0);
229: }
230:
231: int
232: mode_sense_write(unsigned char buf[])
233: {
234: scsireq_t scr;
235: int r;
236:
237: bzero(&scr, sizeof(scr));
238: scr.timeout = 4000;
239: scr.senselen = SENSEBUFLEN;
240: scr.cmd[0] = 0x5a;
241: scr.cmd[1] = 0x00;
242: scr.cmd[2] = 0x05; /* Write parameters mode page */
243: scr.cmd[7] = 0x00;
244: scr.cmd[8] = 0x46; /* 16 for the header + size from pg. 89 mmc-r10a.pdf */
245: scr.cmdlen = 10;
246: scr.datalen= 0x46;
247: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
248: scr.databuf = (caddr_t)buf;
249:
250: r = ioctl(fd, SCIOCCOMMAND, &scr);
251: return (r == 0 ? scr.retsts : -1);
252: }
253:
254: int
255: mode_select_write(unsigned char buf[])
256: {
257: scsireq_t scr;
258: int r;
259:
260: bzero(&scr, sizeof(scr));
261: scr.timeout = 4000;
262: scr.senselen = SENSEBUFLEN;
263: scr.cmd[0] = 0x55;
264: scr.cmd[1] = 0x10; /* pages aren't vendor specific */
265: scr.cmd[2] = 0x00;
266: scr.cmd[7] = 0x00;
267: scr.cmd[8] = 2 + buf[1] + 256 * buf[0];
268: scr.cmdlen = 10;
269: scr.datalen = 2 + buf[1] + 256 * buf[0];
270: scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
271: scr.databuf = (caddr_t)buf;
272:
273: r = ioctl(fd, SCIOCCOMMAND, &scr);
1.6 ! mjc 274: return (r == 0 ? scr.retsts : -1);
! 275: }
! 276:
! 277: int
! 278: get_disc_size(off_t *availblk)
! 279: {
! 280: u_char databuf[28];
! 281: scsireq_t scr;
! 282: int r,tmp;
! 283:
! 284: bzero(&scr, sizeof(scr));
! 285: scr.timeout = 4000;
! 286: scr.senselen = SENSEBUFLEN;
! 287: scr.cmd[0] = 0x52; /* READ TRACK INFO */
! 288: scr.cmd[1] = 0x01;
! 289: scr.cmd[5] = 0x01; /* Track 01 */
! 290: scr.cmd[7] = 0x00;
! 291: scr.cmd[8] = 0x1c;
! 292: scr.cmdlen = 10;
! 293: scr.datalen= 0x1c;
! 294: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
! 295: scr.databuf = (caddr_t)databuf;
! 296:
! 297: r = ioctl(fd, SCIOCCOMMAND, &scr);
! 298: memcpy(&tmp, &databuf[16], sizeof(tmp));
! 299: *availblk = betoh32(tmp);
1.1 mjc 300: return (r == 0 ? scr.retsts : -1);
301: }
302:
303: int
304: get_nwa(int *nwa)
305: {
306: u_char databuf[28];
307: scsireq_t scr;
308: int r,tmp;
309:
310: bzero(&scr, sizeof(scr));
311: scr.timeout = 4000;
312: scr.senselen = SENSEBUFLEN;
313: scr.cmd[0] = 0x52; /* READ TRACK INFO */
314: scr.cmd[1] = 0x01;
315: scr.cmd[5] = 0xff; /* Invisible Track */
316: scr.cmd[7] = 0x00;
317: scr.cmd[8] = 0x1c;
318: scr.cmdlen = 10;
319: scr.datalen= 0x1c;
320: scr.flags = SCCMD_ESCAPE|SCCMD_READ;
321: scr.databuf = (caddr_t)databuf;
322:
323: r = ioctl(fd, SCIOCCOMMAND, &scr);
324: memcpy(&tmp, &databuf[12], sizeof(tmp));
325: *nwa = betoh32(tmp);
326: return (r == 0 ? scr.retsts : -1);
327: }