xref: /titanic_53/usr/src/cmd/cdrw/misc_scsi.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <string.h>
32*7c478bd9Sstevel@tonic-gate #include <stdio.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/dkio.h>
34*7c478bd9Sstevel@tonic-gate #include <unistd.h>
35*7c478bd9Sstevel@tonic-gate #include <errno.h>
36*7c478bd9Sstevel@tonic-gate #include <libintl.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/time.h>
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate #include "mmc.h"
40*7c478bd9Sstevel@tonic-gate #include "util.h"
41*7c478bd9Sstevel@tonic-gate #include "misc_scsi.h"
42*7c478bd9Sstevel@tonic-gate #include "transport.h"
43*7c478bd9Sstevel@tonic-gate #include "main.h"
44*7c478bd9Sstevel@tonic-gate #include "toshiba.h"
45*7c478bd9Sstevel@tonic-gate #include "msgs.h"
46*7c478bd9Sstevel@tonic-gate 
47*7c478bd9Sstevel@tonic-gate uint32_t
48*7c478bd9Sstevel@tonic-gate read_scsi32(void *addr)
49*7c478bd9Sstevel@tonic-gate {
50*7c478bd9Sstevel@tonic-gate 	uchar_t *ad = (uchar_t *)addr;
51*7c478bd9Sstevel@tonic-gate 	uint32_t ret;
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate 	ret = ((((uint32_t)ad[0]) << 24) | (((uint32_t)ad[1]) << 16) |
54*7c478bd9Sstevel@tonic-gate 	    (((uint32_t)ad[2]) << 8) | ad[3]);
55*7c478bd9Sstevel@tonic-gate 	return (ret);
56*7c478bd9Sstevel@tonic-gate }
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate uint16_t
59*7c478bd9Sstevel@tonic-gate read_scsi16(void *addr)
60*7c478bd9Sstevel@tonic-gate {
61*7c478bd9Sstevel@tonic-gate 	uchar_t *ad = (uchar_t *)addr;
62*7c478bd9Sstevel@tonic-gate 	uint16_t ret;
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	ret = ((((uint16_t)ad[0]) << 8) | ad[1]);
65*7c478bd9Sstevel@tonic-gate 	return (ret);
66*7c478bd9Sstevel@tonic-gate }
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate void
69*7c478bd9Sstevel@tonic-gate load_scsi32(void *addr, uint32_t v)
70*7c478bd9Sstevel@tonic-gate {
71*7c478bd9Sstevel@tonic-gate 	uchar_t *ad = (uchar_t *)addr;
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 	ad[0] = (uchar_t)(v >> 24);
74*7c478bd9Sstevel@tonic-gate 	ad[1] = (uchar_t)(v >> 16);
75*7c478bd9Sstevel@tonic-gate 	ad[2] = (uchar_t)(v >> 8);
76*7c478bd9Sstevel@tonic-gate 	ad[3] = (uchar_t)v;
77*7c478bd9Sstevel@tonic-gate }
78*7c478bd9Sstevel@tonic-gate 
79*7c478bd9Sstevel@tonic-gate void
80*7c478bd9Sstevel@tonic-gate load_scsi16(void *addr, uint16_t v)
81*7c478bd9Sstevel@tonic-gate {
82*7c478bd9Sstevel@tonic-gate 	uchar_t *ad = (uchar_t *)addr;
83*7c478bd9Sstevel@tonic-gate 	ad[0] = (uchar_t)(v >> 8);
84*7c478bd9Sstevel@tonic-gate 	ad[1] = (uchar_t)v;
85*7c478bd9Sstevel@tonic-gate }
86*7c478bd9Sstevel@tonic-gate /*
87*7c478bd9Sstevel@tonic-gate  * will get the mode page only i.e. will strip off the header.
88*7c478bd9Sstevel@tonic-gate  */
89*7c478bd9Sstevel@tonic-gate int
90*7c478bd9Sstevel@tonic-gate get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer)
91*7c478bd9Sstevel@tonic-gate {
92*7c478bd9Sstevel@tonic-gate 	int ret;
93*7c478bd9Sstevel@tonic-gate 	uchar_t byte2, *buf;
94*7c478bd9Sstevel@tonic-gate 	uint_t header_len, page_len, copy_cnt;
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate 	byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
97*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)my_zalloc(256);
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/* Ask 254 bytes only to make our IDE driver happy */
100*7c478bd9Sstevel@tonic-gate 	ret = mode_sense(fd, byte2, 1, 254, buf);
101*7c478bd9Sstevel@tonic-gate 	if (ret == 0) {
102*7c478bd9Sstevel@tonic-gate 		free(buf);
103*7c478bd9Sstevel@tonic-gate 		return (0);
104*7c478bd9Sstevel@tonic-gate 	}
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate 	header_len = 8 + read_scsi16(&buf[6]);
107*7c478bd9Sstevel@tonic-gate 	page_len = buf[header_len + 1] + 2;
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate 	copy_cnt = (page_len > buf_len) ? buf_len : page_len;
110*7c478bd9Sstevel@tonic-gate 	(void) memcpy(buffer, &buf[header_len], copy_cnt);
111*7c478bd9Sstevel@tonic-gate 	free(buf);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	return (1);
114*7c478bd9Sstevel@tonic-gate }
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate /*
117*7c478bd9Sstevel@tonic-gate  * will take care of adding mode header and any extra bytes at the end.
118*7c478bd9Sstevel@tonic-gate  */
119*7c478bd9Sstevel@tonic-gate int
120*7c478bd9Sstevel@tonic-gate set_mode_page(int fd, uchar_t *buffer)
121*7c478bd9Sstevel@tonic-gate {
122*7c478bd9Sstevel@tonic-gate 	int ret;
123*7c478bd9Sstevel@tonic-gate 	uchar_t *buf;
124*7c478bd9Sstevel@tonic-gate 	uint_t total, p_len;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	p_len = buffer[1] + 2;
127*7c478bd9Sstevel@tonic-gate 	total = p_len + 8;
128*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)my_zalloc(total);
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&buf[8], buffer, p_len);
131*7c478bd9Sstevel@tonic-gate 	if (debug) {
132*7c478bd9Sstevel@tonic-gate 		int i;
133*7c478bd9Sstevel@tonic-gate 
134*7c478bd9Sstevel@tonic-gate 		(void) printf("MODE: [");
135*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < p_len; i++) {
136*7c478bd9Sstevel@tonic-gate 			(void) printf("0x%02x ", (uchar_t)buffer[i]);
137*7c478bd9Sstevel@tonic-gate 		}
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate 		(void) printf("]\n");
140*7c478bd9Sstevel@tonic-gate 	}
141*7c478bd9Sstevel@tonic-gate 	ret = mode_select(fd, total, buf);
142*7c478bd9Sstevel@tonic-gate 	free(buf);
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 	return (ret);
145*7c478bd9Sstevel@tonic-gate }
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate /*
148*7c478bd9Sstevel@tonic-gate  * Builds track information database for track trackno. If trackno is
149*7c478bd9Sstevel@tonic-gate  * -1, builds the database for next blank track.
150*7c478bd9Sstevel@tonic-gate  */
151*7c478bd9Sstevel@tonic-gate int
152*7c478bd9Sstevel@tonic-gate build_track_info(cd_device *dev, int trackno, struct track_info *t_info)
153*7c478bd9Sstevel@tonic-gate {
154*7c478bd9Sstevel@tonic-gate 	uchar_t *ti;
155*7c478bd9Sstevel@tonic-gate 	uchar_t toc[20];		/* 2 entries + 4 byte header */
156*7c478bd9Sstevel@tonic-gate 	int ret;
157*7c478bd9Sstevel@tonic-gate 
158*7c478bd9Sstevel@tonic-gate 	(void) memset(t_info, 0, sizeof (*t_info));
159*7c478bd9Sstevel@tonic-gate 	/* 1st try READ TRACK INFORMATION */
160*7c478bd9Sstevel@tonic-gate 	ti = (uchar_t *)my_zalloc(TRACK_INFO_SIZE);
161*7c478bd9Sstevel@tonic-gate 	t_info->ti_track_no = trackno;
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 	/* Gererate faked information for writing to DVD */
164*7c478bd9Sstevel@tonic-gate 	if (device_type != CD_RW) {
165*7c478bd9Sstevel@tonic-gate 		uint_t bsize;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 		t_info->ti_flags = 0x3000;
168*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_no = 1;
169*7c478bd9Sstevel@tonic-gate 		t_info->ti_session_no = 1;
170*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_mode = 0x4;
171*7c478bd9Sstevel@tonic-gate 		t_info->ti_data_mode = 1;
172*7c478bd9Sstevel@tonic-gate 		t_info->ti_start_address = 0;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 		/* only 1 track on DVD make it max size */
175*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_size = read_format_capacity(target->d_fd,
176*7c478bd9Sstevel@tonic-gate 		    &bsize);
177*7c478bd9Sstevel@tonic-gate 		if (t_info->ti_track_size < MAX_CD_BLKS) {
178*7c478bd9Sstevel@tonic-gate 			t_info->ti_track_size = MAX_DVD_BLKS;
179*7c478bd9Sstevel@tonic-gate 		}
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate 		t_info->ti_nwa = 0;
182*7c478bd9Sstevel@tonic-gate 		t_info->ti_lra = 0;
183*7c478bd9Sstevel@tonic-gate 		t_info->ti_packet_size = 0x10;
184*7c478bd9Sstevel@tonic-gate 		t_info->ti_free_blocks = 0;
185*7c478bd9Sstevel@tonic-gate 	}
186*7c478bd9Sstevel@tonic-gate 
187*7c478bd9Sstevel@tonic-gate 	if (read_track_info(dev->d_fd, trackno, ti)) {
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate 		if (debug)
190*7c478bd9Sstevel@tonic-gate 			(void) printf("using read_track_info for TOC \n");
191*7c478bd9Sstevel@tonic-gate 
192*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_no = ti[2];
193*7c478bd9Sstevel@tonic-gate 		t_info->ti_session_no = ti[3];
194*7c478bd9Sstevel@tonic-gate 		t_info->ti_flags = (ti[6] >> 4) & 0xf;
195*7c478bd9Sstevel@tonic-gate 		t_info->ti_flags |= (uint32_t)(ti[5] & 0xf0);
196*7c478bd9Sstevel@tonic-gate 		t_info->ti_flags |= (uint32_t)(ti[7]) << 8;
197*7c478bd9Sstevel@tonic-gate 		t_info->ti_flags |= TI_SESSION_NO_VALID | TI_FREE_BLOCKS_VALID;
198*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_mode = ti[5] & 0xf;
199*7c478bd9Sstevel@tonic-gate 		if ((ti[6] & 0xf) == 0xf)
200*7c478bd9Sstevel@tonic-gate 			t_info->ti_data_mode = 0xff;
201*7c478bd9Sstevel@tonic-gate 		else
202*7c478bd9Sstevel@tonic-gate 			t_info->ti_data_mode = ti[6] & 0xf;
203*7c478bd9Sstevel@tonic-gate 		t_info->ti_start_address = read_scsi32(&ti[8]);
204*7c478bd9Sstevel@tonic-gate 		t_info->ti_nwa = read_scsi32(&ti[12]);
205*7c478bd9Sstevel@tonic-gate 		t_info->ti_free_blocks = read_scsi32(&ti[16]);
206*7c478bd9Sstevel@tonic-gate 		t_info->ti_packet_size = read_scsi32(&ti[20]);
207*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_size = read_scsi32(&ti[24]);
208*7c478bd9Sstevel@tonic-gate 		t_info->ti_lra = read_scsi32(&ti[28]);
209*7c478bd9Sstevel@tonic-gate 		free(ti);
210*7c478bd9Sstevel@tonic-gate 		return (1);
211*7c478bd9Sstevel@tonic-gate 	}
212*7c478bd9Sstevel@tonic-gate 	/* READ TRACK INFORMATION not supported, try other options */
213*7c478bd9Sstevel@tonic-gate 	free(ti);
214*7c478bd9Sstevel@tonic-gate 	/*
215*7c478bd9Sstevel@tonic-gate 	 * We can get info for next blank track if READ TRACK INFO is not
216*7c478bd9Sstevel@tonic-gate 	 * supported.
217*7c478bd9Sstevel@tonic-gate 	 */
218*7c478bd9Sstevel@tonic-gate 	if (trackno == -1)
219*7c478bd9Sstevel@tonic-gate 		return (0);
220*7c478bd9Sstevel@tonic-gate 
221*7c478bd9Sstevel@tonic-gate 	if (debug)
222*7c478bd9Sstevel@tonic-gate 		(void) printf("using READ_TOC for TOC\n");
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/* Try Read TOC */
225*7c478bd9Sstevel@tonic-gate 	if (!read_toc(dev->d_fd, 0, trackno, 20, toc)) {
226*7c478bd9Sstevel@tonic-gate 		return (0);
227*7c478bd9Sstevel@tonic-gate 	}
228*7c478bd9Sstevel@tonic-gate 	t_info->ti_start_address = read_scsi32(&toc[8]);
229*7c478bd9Sstevel@tonic-gate 	t_info->ti_track_mode = toc[5] & 0xf;
230*7c478bd9Sstevel@tonic-gate 	t_info->ti_track_size = read_scsi32(&toc[16]) - read_scsi32(&toc[8]);
231*7c478bd9Sstevel@tonic-gate 	t_info->ti_data_mode = get_data_mode(dev->d_fd, read_scsi32(&toc[8]));
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	/* Numbers for audio tracks are always in 2K chunks */
234*7c478bd9Sstevel@tonic-gate 	if ((dev->d_blksize == 512) && ((t_info->ti_track_mode & 4) == 0)) {
235*7c478bd9Sstevel@tonic-gate 		t_info->ti_start_address /= 4;
236*7c478bd9Sstevel@tonic-gate 		t_info->ti_track_size /= 4;
237*7c478bd9Sstevel@tonic-gate 	}
238*7c478bd9Sstevel@tonic-gate 
239*7c478bd9Sstevel@tonic-gate 	/* Now find out the session thing */
240*7c478bd9Sstevel@tonic-gate 	ret = read_toc(dev->d_fd, 1, trackno, 12, toc);
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	/*
243*7c478bd9Sstevel@tonic-gate 	 * Make sure that the call succeeds and returns the requested
244*7c478bd9Sstevel@tonic-gate 	 * TOC size correctly.
245*7c478bd9Sstevel@tonic-gate 	 */
246*7c478bd9Sstevel@tonic-gate 
247*7c478bd9Sstevel@tonic-gate 	if ((ret == 0) || (toc[1] != 0x0a)) {
248*7c478bd9Sstevel@tonic-gate 
249*7c478bd9Sstevel@tonic-gate 		/* For ATAPI drives or old Toshiba drives */
250*7c478bd9Sstevel@tonic-gate 		ret = read_toc_as_per_8020(dev->d_fd, 1, trackno, 12, toc);
251*7c478bd9Sstevel@tonic-gate 	}
252*7c478bd9Sstevel@tonic-gate 	/* If this goes through well TOC length will always be 0x0a */
253*7c478bd9Sstevel@tonic-gate 	if (ret && (toc[1] == 0x0a)) {
254*7c478bd9Sstevel@tonic-gate 		if (trackno >= toc[6]) {
255*7c478bd9Sstevel@tonic-gate 			t_info->ti_session_no = toc[3];
256*7c478bd9Sstevel@tonic-gate 			t_info->ti_flags |= TI_SESSION_NO_VALID;
257*7c478bd9Sstevel@tonic-gate 		}
258*7c478bd9Sstevel@tonic-gate 		/*
259*7c478bd9Sstevel@tonic-gate 		 * This might be the last track of this session. If so,
260*7c478bd9Sstevel@tonic-gate 		 * exclude the leadout and next lead in.
261*7c478bd9Sstevel@tonic-gate 		 */
262*7c478bd9Sstevel@tonic-gate 		if (trackno == (toc[6] - 1)) {
263*7c478bd9Sstevel@tonic-gate 			/*
264*7c478bd9Sstevel@tonic-gate 			 * 1.5 Min leadout + 1 min. leadin + 2 sec. pre-gap.
265*7c478bd9Sstevel@tonic-gate 			 * For 2nd+ leadout it will be 0.5 min. But currently
266*7c478bd9Sstevel@tonic-gate 			 * there is no direct way. And it will not happen
267*7c478bd9Sstevel@tonic-gate 			 * for any normal case.
268*7c478bd9Sstevel@tonic-gate 			 *
269*7c478bd9Sstevel@tonic-gate 			 * 75 frames/sec, 60 sec/min, so leadin gap is
270*7c478bd9Sstevel@tonic-gate 			 * ((1.5 +1)*60 + 2)*75 = 11400 frames (blocks)
271*7c478bd9Sstevel@tonic-gate 			 */
272*7c478bd9Sstevel@tonic-gate 			t_info->ti_track_size -= 11400;
273*7c478bd9Sstevel@tonic-gate 		}
274*7c478bd9Sstevel@tonic-gate 	}
275*7c478bd9Sstevel@tonic-gate 	return (1);
276*7c478bd9Sstevel@tonic-gate }
277*7c478bd9Sstevel@tonic-gate 
278*7c478bd9Sstevel@tonic-gate uchar_t
279*7c478bd9Sstevel@tonic-gate get_data_mode(int fd, uint32_t lba)
280*7c478bd9Sstevel@tonic-gate {
281*7c478bd9Sstevel@tonic-gate 	int ret;
282*7c478bd9Sstevel@tonic-gate 	uchar_t *buf;
283*7c478bd9Sstevel@tonic-gate 	uchar_t mode;
284*7c478bd9Sstevel@tonic-gate 
285*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)my_zalloc(8);
286*7c478bd9Sstevel@tonic-gate 	ret = read_header(fd, lba, buf);
287*7c478bd9Sstevel@tonic-gate 	if (ret == 0)
288*7c478bd9Sstevel@tonic-gate 		mode = 0xff;
289*7c478bd9Sstevel@tonic-gate 	else
290*7c478bd9Sstevel@tonic-gate 		mode = buf[0];
291*7c478bd9Sstevel@tonic-gate 	free(buf);
292*7c478bd9Sstevel@tonic-gate 	return (mode);
293*7c478bd9Sstevel@tonic-gate }
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate /*
296*7c478bd9Sstevel@tonic-gate  * Set page code 5 for TAO mode.
297*7c478bd9Sstevel@tonic-gate  */
298*7c478bd9Sstevel@tonic-gate int
299*7c478bd9Sstevel@tonic-gate prepare_for_write(cd_device *dev, int track_mode, int test_write,
300*7c478bd9Sstevel@tonic-gate     int keep_disc_open)
301*7c478bd9Sstevel@tonic-gate {
302*7c478bd9Sstevel@tonic-gate 	uchar_t *buf;
303*7c478bd9Sstevel@tonic-gate 	int no_err;
304*7c478bd9Sstevel@tonic-gate 	int reset_device;
305*7c478bd9Sstevel@tonic-gate 
306*7c478bd9Sstevel@tonic-gate 	if ((write_mode == DAO_MODE) && keep_disc_open) {
307*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext(
308*7c478bd9Sstevel@tonic-gate 		    "Multi-session is not supported on DVD media\n"));
309*7c478bd9Sstevel@tonic-gate 		exit(1);
310*7c478bd9Sstevel@tonic-gate 	}
311*7c478bd9Sstevel@tonic-gate 
312*7c478bd9Sstevel@tonic-gate 	if ((write_mode == DAO_MODE) && debug) {
313*7c478bd9Sstevel@tonic-gate 		(void) printf("Preparing to write in DAO\n");
314*7c478bd9Sstevel@tonic-gate 	}
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	(void) start_stop(dev->d_fd, 1);
317*7c478bd9Sstevel@tonic-gate 	/* Some drives do not support this command but still do it */
318*7c478bd9Sstevel@tonic-gate 	(void) rezero_unit(dev->d_fd);
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)my_zalloc(64);
321*7c478bd9Sstevel@tonic-gate 
322*7c478bd9Sstevel@tonic-gate 	no_err = get_mode_page(dev->d_fd, 5, 0, 64, buf);
323*7c478bd9Sstevel@tonic-gate 	if (no_err)
324*7c478bd9Sstevel@tonic-gate 		no_err = ((buf[1] + 2) > 64) ? 0 : 1;
325*7c478bd9Sstevel@tonic-gate 	/*
326*7c478bd9Sstevel@tonic-gate 	 * If the device is already in simulation mode and again a
327*7c478bd9Sstevel@tonic-gate 	 * simulation is requested, then set the device in non-simulation
328*7c478bd9Sstevel@tonic-gate 	 * 1st and then take it to simulation mode. This will flush any
329*7c478bd9Sstevel@tonic-gate 	 * previous fake state in the drive.
330*7c478bd9Sstevel@tonic-gate 	 */
331*7c478bd9Sstevel@tonic-gate 	if (no_err && test_write && (buf[2] & 0x10)) {
332*7c478bd9Sstevel@tonic-gate 		reset_device = 1;
333*7c478bd9Sstevel@tonic-gate 	} else {
334*7c478bd9Sstevel@tonic-gate 		reset_device = 0;
335*7c478bd9Sstevel@tonic-gate 	}
336*7c478bd9Sstevel@tonic-gate 	if (no_err != 0) {
337*7c478bd9Sstevel@tonic-gate 		buf[0] &= 0x3f;
338*7c478bd9Sstevel@tonic-gate 
339*7c478bd9Sstevel@tonic-gate 		/* set TAO or DAO writing mode */
340*7c478bd9Sstevel@tonic-gate 		buf[2] = (write_mode == TAO_MODE)?1:2;
341*7c478bd9Sstevel@tonic-gate 
342*7c478bd9Sstevel@tonic-gate 		/* set simulation flag */
343*7c478bd9Sstevel@tonic-gate 		if (test_write && (!reset_device)) {
344*7c478bd9Sstevel@tonic-gate 			buf[2] |= 0x10;
345*7c478bd9Sstevel@tonic-gate 		} else {
346*7c478bd9Sstevel@tonic-gate 			buf[2] &= ~0x10;
347*7c478bd9Sstevel@tonic-gate 		}
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 		/* Turn on HW buffer underrun protection (BUFE) */
350*7c478bd9Sstevel@tonic-gate 		if (!test_write) {
351*7c478bd9Sstevel@tonic-gate 			buf[2] |= 0x40;
352*7c478bd9Sstevel@tonic-gate 		}
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 		/* set track mode type */
355*7c478bd9Sstevel@tonic-gate 		if (device_type == CD_RW) {
356*7c478bd9Sstevel@tonic-gate 			buf[3] = track_mode & 0x0f;	/* ctrl nibble */
357*7c478bd9Sstevel@tonic-gate 		} else {
358*7c478bd9Sstevel@tonic-gate 			buf[3] = 5;	/* always 5 for DVD */
359*7c478bd9Sstevel@tonic-gate 		}
360*7c478bd9Sstevel@tonic-gate 
361*7c478bd9Sstevel@tonic-gate 		if (keep_disc_open) {
362*7c478bd9Sstevel@tonic-gate 			buf[3] |= 0xc0;		/* Allow more sessions */
363*7c478bd9Sstevel@tonic-gate 		}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 		/* Select track type (audio or data) */
366*7c478bd9Sstevel@tonic-gate 		if (track_mode == TRACK_MODE_DATA) {
367*7c478bd9Sstevel@tonic-gate 			buf[4] = 8;		/* 2048 byte sector */
368*7c478bd9Sstevel@tonic-gate 		} else {
369*7c478bd9Sstevel@tonic-gate 			buf[4] = 0;		/* 2352 byte sector */
370*7c478bd9Sstevel@tonic-gate 		}
371*7c478bd9Sstevel@tonic-gate 		buf[7] = buf[8] = 0;
372*7c478bd9Sstevel@tonic-gate 
373*7c478bd9Sstevel@tonic-gate 		/* Need to clear these fields for setting into DAO */
374*7c478bd9Sstevel@tonic-gate 		if (write_mode == DAO_MODE)
375*7c478bd9Sstevel@tonic-gate 			buf[5] = buf[15] = 0;
376*7c478bd9Sstevel@tonic-gate 
377*7c478bd9Sstevel@tonic-gate 		/* print out mode for detailed log */
378*7c478bd9Sstevel@tonic-gate 		if (debug && verbose) {
379*7c478bd9Sstevel@tonic-gate 			int i;
380*7c478bd9Sstevel@tonic-gate 
381*7c478bd9Sstevel@tonic-gate 			(void) printf("setting = [ ");
382*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < 15; i++)
383*7c478bd9Sstevel@tonic-gate 				(void) printf("0x%x ", buf[i]);
384*7c478bd9Sstevel@tonic-gate 			(void) printf("]\n");
385*7c478bd9Sstevel@tonic-gate 		}
386*7c478bd9Sstevel@tonic-gate 
387*7c478bd9Sstevel@tonic-gate 		no_err = set_mode_page(dev->d_fd, buf);
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 		if (no_err && reset_device) {
390*7c478bd9Sstevel@tonic-gate 			/* Turn the test write bit back on */
391*7c478bd9Sstevel@tonic-gate 			buf[2] |= 0x10;
392*7c478bd9Sstevel@tonic-gate 			no_err = set_mode_page(dev->d_fd, buf);
393*7c478bd9Sstevel@tonic-gate 		}
394*7c478bd9Sstevel@tonic-gate 
395*7c478bd9Sstevel@tonic-gate 		/*
396*7c478bd9Sstevel@tonic-gate 		 * Since BUFE is the only optional flag we are
397*7c478bd9Sstevel@tonic-gate 		 * setting we will try to turn it off if the command
398*7c478bd9Sstevel@tonic-gate 		 * fails.
399*7c478bd9Sstevel@tonic-gate 		 */
400*7c478bd9Sstevel@tonic-gate 		if (!no_err) {
401*7c478bd9Sstevel@tonic-gate 			/*
402*7c478bd9Sstevel@tonic-gate 			 * Some old drives may not support HW
403*7c478bd9Sstevel@tonic-gate 			 * buffer underrun protection, try again
404*7c478bd9Sstevel@tonic-gate 			 * after turning it off.
405*7c478bd9Sstevel@tonic-gate 			 */
406*7c478bd9Sstevel@tonic-gate 			if (debug)
407*7c478bd9Sstevel@tonic-gate 				(void) printf("Turning off BUFE\n");
408*7c478bd9Sstevel@tonic-gate 			buf[2] &= ~0x40;
409*7c478bd9Sstevel@tonic-gate 			no_err = set_mode_page(dev->d_fd, buf);
410*7c478bd9Sstevel@tonic-gate 		}
411*7c478bd9Sstevel@tonic-gate 	}
412*7c478bd9Sstevel@tonic-gate 
413*7c478bd9Sstevel@tonic-gate 	free(buf);
414*7c478bd9Sstevel@tonic-gate 	return (no_err);
415*7c478bd9Sstevel@tonic-gate }
416*7c478bd9Sstevel@tonic-gate 
417*7c478bd9Sstevel@tonic-gate /*
418*7c478bd9Sstevel@tonic-gate  * Close session. This will write TOC.
419*7c478bd9Sstevel@tonic-gate  */
420*7c478bd9Sstevel@tonic-gate int
421*7c478bd9Sstevel@tonic-gate finalize(cd_device *dev)
422*7c478bd9Sstevel@tonic-gate {
423*7c478bd9Sstevel@tonic-gate 	uchar_t *di;
424*7c478bd9Sstevel@tonic-gate 	int count, ret, err;
425*7c478bd9Sstevel@tonic-gate 	int immediate;
426*7c478bd9Sstevel@tonic-gate 	int finalize_max;
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate 	/*
429*7c478bd9Sstevel@tonic-gate 	 * For ATAPI devices we will use the immediate mode and will
430*7c478bd9Sstevel@tonic-gate 	 * poll the command for completion so that this command may
431*7c478bd9Sstevel@tonic-gate 	 * not hog the channel. But for SCSI, we will use the treditional
432*7c478bd9Sstevel@tonic-gate 	 * way of issuing the command with a large enough timeout. This
433*7c478bd9Sstevel@tonic-gate 	 * is done because immediate mode was designed for ATAPI and some
434*7c478bd9Sstevel@tonic-gate 	 * SCSI RW drives might not be even tested with it.
435*7c478bd9Sstevel@tonic-gate 	 */
436*7c478bd9Sstevel@tonic-gate 	if ((dev->d_inq[2] & 7) != 0) {
437*7c478bd9Sstevel@tonic-gate 		/* SCSI device */
438*7c478bd9Sstevel@tonic-gate 		immediate = 0;
439*7c478bd9Sstevel@tonic-gate 	} else {
440*7c478bd9Sstevel@tonic-gate 		/* non-SCSI (e.g ATAPI) device */
441*7c478bd9Sstevel@tonic-gate 		immediate = 1;
442*7c478bd9Sstevel@tonic-gate 	}
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	/* We need to close track before close session */
445*7c478bd9Sstevel@tonic-gate 	if (device_type == DVD_PLUS) {
446*7c478bd9Sstevel@tonic-gate 		if (!close_track(dev->d_fd, 0, 0, immediate))
447*7c478bd9Sstevel@tonic-gate 			return (0);
448*7c478bd9Sstevel@tonic-gate 	}
449*7c478bd9Sstevel@tonic-gate 
450*7c478bd9Sstevel@tonic-gate 	if (!close_track(dev->d_fd, 0, 1, immediate)) {
451*7c478bd9Sstevel@tonic-gate 		/*
452*7c478bd9Sstevel@tonic-gate 		 * For DVD-RW close track is not well defined
453*7c478bd9Sstevel@tonic-gate 		 * some drives dont like it, others want us
454*7c478bd9Sstevel@tonic-gate 		 * to close track before closing the session.
455*7c478bd9Sstevel@tonic-gate 		 * NOTE that for MMC specification it is not mandatory
456*7c478bd9Sstevel@tonic-gate 		 * to support close track.
457*7c478bd9Sstevel@tonic-gate 		 */
458*7c478bd9Sstevel@tonic-gate 		if (device_type == DVD_MINUS) {
459*7c478bd9Sstevel@tonic-gate 			if (!close_track(dev->d_fd, 1, 0, immediate)) {
460*7c478bd9Sstevel@tonic-gate 				return (0);
461*7c478bd9Sstevel@tonic-gate 			} else {
462*7c478bd9Sstevel@tonic-gate 				/* command is already done */
463*7c478bd9Sstevel@tonic-gate 				if (!immediate)
464*7c478bd9Sstevel@tonic-gate 					return (1);
465*7c478bd9Sstevel@tonic-gate 			}
466*7c478bd9Sstevel@tonic-gate 		} else {
467*7c478bd9Sstevel@tonic-gate 			return (0);
468*7c478bd9Sstevel@tonic-gate 		}
469*7c478bd9Sstevel@tonic-gate 	} else {
470*7c478bd9Sstevel@tonic-gate 		if (!immediate)
471*7c478bd9Sstevel@tonic-gate 			return (1);
472*7c478bd9Sstevel@tonic-gate 	}
473*7c478bd9Sstevel@tonic-gate 	if (immediate) {
474*7c478bd9Sstevel@tonic-gate 		(void) sleep(10);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 		di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
477*7c478bd9Sstevel@tonic-gate 		err = 0;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 		if (device_type == CD_RW) {
480*7c478bd9Sstevel@tonic-gate 			/* Finalization should not take more than 6 minutes */
481*7c478bd9Sstevel@tonic-gate 			finalize_max = FINALIZE_TIMEOUT;
482*7c478bd9Sstevel@tonic-gate 		} else {
483*7c478bd9Sstevel@tonic-gate 			/* some DVD-RW drives take longer than 6 minutes */
484*7c478bd9Sstevel@tonic-gate 			finalize_max = FINALIZE_TIMEOUT*2;
485*7c478bd9Sstevel@tonic-gate 		}
486*7c478bd9Sstevel@tonic-gate 
487*7c478bd9Sstevel@tonic-gate 		for (count = 0; count < finalize_max; count++) {
488*7c478bd9Sstevel@tonic-gate 			ret = read_disc_info(dev->d_fd, di);
489*7c478bd9Sstevel@tonic-gate 			if (ret != 0)
490*7c478bd9Sstevel@tonic-gate 				break;
491*7c478bd9Sstevel@tonic-gate 			if (uscsi_status != 2)
492*7c478bd9Sstevel@tonic-gate 				err = 1;
493*7c478bd9Sstevel@tonic-gate 			if (SENSE_KEY(rqbuf) == 2) {
494*7c478bd9Sstevel@tonic-gate 				/* not ready but not becoming ready */
495*7c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) != 4)
496*7c478bd9Sstevel@tonic-gate 					err = 1;
497*7c478bd9Sstevel@tonic-gate 			} else if (SENSE_KEY(rqbuf) == 5) {
498*7c478bd9Sstevel@tonic-gate 				/* illegal mode for this track */
499*7c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) != 0x64)
500*7c478bd9Sstevel@tonic-gate 					err = 1;
501*7c478bd9Sstevel@tonic-gate 			} else {
502*7c478bd9Sstevel@tonic-gate 				err = 1;
503*7c478bd9Sstevel@tonic-gate 			}
504*7c478bd9Sstevel@tonic-gate 			if (err == 1) {
505*7c478bd9Sstevel@tonic-gate 				if (debug) {
506*7c478bd9Sstevel@tonic-gate 					(void) printf("Finalization failed\n");
507*7c478bd9Sstevel@tonic-gate 					(void) printf("%x %x %x %x\n",
508*7c478bd9Sstevel@tonic-gate 					    uscsi_status, SENSE_KEY(rqbuf),
509*7c478bd9Sstevel@tonic-gate 					    ASC(rqbuf), ASCQ(rqbuf));
510*7c478bd9Sstevel@tonic-gate 				}
511*7c478bd9Sstevel@tonic-gate 				free(di);
512*7c478bd9Sstevel@tonic-gate 				return (0);
513*7c478bd9Sstevel@tonic-gate 			}
514*7c478bd9Sstevel@tonic-gate 			if (uscsi_status == 2) {
515*7c478bd9Sstevel@tonic-gate 				int i;
516*7c478bd9Sstevel@tonic-gate 				/* illegal field in command packet */
517*7c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) == 0x24) {
518*7c478bd9Sstevel@tonic-gate 					/* print it out! */
519*7c478bd9Sstevel@tonic-gate 					(void) printf("\n");
520*7c478bd9Sstevel@tonic-gate 					for (i = 0; i < 18; i++)
521*7c478bd9Sstevel@tonic-gate 						(void) printf("%x ",
522*7c478bd9Sstevel@tonic-gate 						    (unsigned)(rqbuf[i]));
523*7c478bd9Sstevel@tonic-gate 					(void) printf("\n");
524*7c478bd9Sstevel@tonic-gate 				}
525*7c478bd9Sstevel@tonic-gate 			}
526*7c478bd9Sstevel@tonic-gate 			(void) sleep(5);
527*7c478bd9Sstevel@tonic-gate 		}
528*7c478bd9Sstevel@tonic-gate 		free(di);
529*7c478bd9Sstevel@tonic-gate 	}
530*7c478bd9Sstevel@tonic-gate 	return (ret);
531*7c478bd9Sstevel@tonic-gate }
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate /*
534*7c478bd9Sstevel@tonic-gate  * Find out media capacity.
535*7c478bd9Sstevel@tonic-gate  */
536*7c478bd9Sstevel@tonic-gate int
537*7c478bd9Sstevel@tonic-gate get_last_possible_lba(cd_device *dev)
538*7c478bd9Sstevel@tonic-gate {
539*7c478bd9Sstevel@tonic-gate 	uchar_t *di;
540*7c478bd9Sstevel@tonic-gate 	int cap;
541*7c478bd9Sstevel@tonic-gate 
542*7c478bd9Sstevel@tonic-gate 	di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
543*7c478bd9Sstevel@tonic-gate 	if (!read_disc_info(dev->d_fd, di)) {
544*7c478bd9Sstevel@tonic-gate 		free(di);
545*7c478bd9Sstevel@tonic-gate 		return (0);
546*7c478bd9Sstevel@tonic-gate 	}
547*7c478bd9Sstevel@tonic-gate 	if ((di[21] != 0) && (di[21] != 0xff)) {
548*7c478bd9Sstevel@tonic-gate 		cap = ((di[21] * 60) + di[22]) * 75;
549*7c478bd9Sstevel@tonic-gate 	} else {
550*7c478bd9Sstevel@tonic-gate 		cap = 0;
551*7c478bd9Sstevel@tonic-gate 	}
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate 	free(di);
554*7c478bd9Sstevel@tonic-gate 	return (cap);
555*7c478bd9Sstevel@tonic-gate }
556*7c478bd9Sstevel@tonic-gate 
557*7c478bd9Sstevel@tonic-gate int
558*7c478bd9Sstevel@tonic-gate read_audio_through_read_cd(cd_device *dev, uint_t start_lba, uint_t nblks,
559*7c478bd9Sstevel@tonic-gate     uchar_t *buf)
560*7c478bd9Sstevel@tonic-gate {
561*7c478bd9Sstevel@tonic-gate 	int retry;
562*7c478bd9Sstevel@tonic-gate 	int ret;
563*7c478bd9Sstevel@tonic-gate 
564*7c478bd9Sstevel@tonic-gate 	for (retry = 0; retry < 3; retry++) {
565*7c478bd9Sstevel@tonic-gate 		ret = read_cd(dev->d_fd, (uint32_t)start_lba, (uint16_t)nblks,
566*7c478bd9Sstevel@tonic-gate 		    1, buf, (uint32_t)(nblks * 2352));
567*7c478bd9Sstevel@tonic-gate 		if (ret)
568*7c478bd9Sstevel@tonic-gate 			break;
569*7c478bd9Sstevel@tonic-gate 	}
570*7c478bd9Sstevel@tonic-gate 	return (ret);
571*7c478bd9Sstevel@tonic-gate }
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate int
574*7c478bd9Sstevel@tonic-gate eject_media(cd_device *dev)
575*7c478bd9Sstevel@tonic-gate {
576*7c478bd9Sstevel@tonic-gate 	if (vol_running) {
577*7c478bd9Sstevel@tonic-gate 		/* If there is a media, try using DKIOCEJECT 1st */
578*7c478bd9Sstevel@tonic-gate 		if (check_device(dev, CHECK_NO_MEDIA) == 0) {
579*7c478bd9Sstevel@tonic-gate 			if (ioctl(dev->d_fd, DKIOCEJECT, 0) == 0) {
580*7c478bd9Sstevel@tonic-gate 				return (1);
581*7c478bd9Sstevel@tonic-gate 			}
582*7c478bd9Sstevel@tonic-gate 		}
583*7c478bd9Sstevel@tonic-gate 	}
584*7c478bd9Sstevel@tonic-gate 	if (load_unload(dev->d_fd, 0) == 0) {
585*7c478bd9Sstevel@tonic-gate 		/* if eject fails */
586*7c478bd9Sstevel@tonic-gate 		if ((uscsi_status == 2) && (ASC(rqbuf) == 0x53)) {
587*7c478bd9Sstevel@tonic-gate 			/*
588*7c478bd9Sstevel@tonic-gate 			 * check that eject is not blocked on the device
589*7c478bd9Sstevel@tonic-gate 			 */
590*7c478bd9Sstevel@tonic-gate 			if (!prevent_allow_mr(dev->d_fd, 1))
591*7c478bd9Sstevel@tonic-gate 				return (0);
592*7c478bd9Sstevel@tonic-gate 			return (load_unload(dev->d_fd, 0));
593*7c478bd9Sstevel@tonic-gate 		}
594*7c478bd9Sstevel@tonic-gate 		return (0);
595*7c478bd9Sstevel@tonic-gate 	}
596*7c478bd9Sstevel@tonic-gate 	return (1);
597*7c478bd9Sstevel@tonic-gate }
598*7c478bd9Sstevel@tonic-gate 
599*7c478bd9Sstevel@tonic-gate /*
600*7c478bd9Sstevel@tonic-gate  * Get CD speed from Page code 2A. since GET PERFORMANCE is not supported
601*7c478bd9Sstevel@tonic-gate  * (which is already checked before) this mode page *will* have the speed.
602*7c478bd9Sstevel@tonic-gate  */
603*7c478bd9Sstevel@tonic-gate static uint16_t
604*7c478bd9Sstevel@tonic-gate i_cd_speed_read(cd_device *dev, int cmd)
605*7c478bd9Sstevel@tonic-gate {
606*7c478bd9Sstevel@tonic-gate 	uchar_t *mp2a;
607*7c478bd9Sstevel@tonic-gate 	uint16_t rate;
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 	mp2a = (uchar_t *)my_zalloc(PAGE_CODE_2A_SIZE);
610*7c478bd9Sstevel@tonic-gate 	if (get_mode_page(dev->d_fd, 0x2A, 0, PAGE_CODE_2A_SIZE,
611*7c478bd9Sstevel@tonic-gate 	    mp2a) == 0) {
612*7c478bd9Sstevel@tonic-gate 		rate = 0;
613*7c478bd9Sstevel@tonic-gate 	} else {
614*7c478bd9Sstevel@tonic-gate 		if (cmd == GET_READ_SPEED) {
615*7c478bd9Sstevel@tonic-gate 			rate = ((uint16_t)mp2a[14] << 8) | mp2a[15];
616*7c478bd9Sstevel@tonic-gate 		} else {
617*7c478bd9Sstevel@tonic-gate 			rate = ((uint16_t)mp2a[20] << 8) | mp2a[21];
618*7c478bd9Sstevel@tonic-gate 		}
619*7c478bd9Sstevel@tonic-gate 	}
620*7c478bd9Sstevel@tonic-gate 	free(mp2a);
621*7c478bd9Sstevel@tonic-gate 	return (rate);
622*7c478bd9Sstevel@tonic-gate }
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate /*
625*7c478bd9Sstevel@tonic-gate  * CD speed related functions (ioctl style) for drives which do not support
626*7c478bd9Sstevel@tonic-gate  * real time streaming.
627*7c478bd9Sstevel@tonic-gate  */
628*7c478bd9Sstevel@tonic-gate int
629*7c478bd9Sstevel@tonic-gate cd_speed_ctrl(cd_device *dev, int cmd, int speed)
630*7c478bd9Sstevel@tonic-gate {
631*7c478bd9Sstevel@tonic-gate 	uint16_t rate;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	if ((cmd == GET_READ_SPEED) || (cmd == GET_WRITE_SPEED))
634*7c478bd9Sstevel@tonic-gate 		return (XFER_RATE_TO_SPEED(i_cd_speed_read(dev, cmd)));
635*7c478bd9Sstevel@tonic-gate 	if (cmd == SET_READ_SPEED) {
636*7c478bd9Sstevel@tonic-gate 		rate = i_cd_speed_read(dev, GET_WRITE_SPEED);
637*7c478bd9Sstevel@tonic-gate 		return (set_cd_speed(dev->d_fd, SPEED_TO_XFER_RATE(speed),
638*7c478bd9Sstevel@tonic-gate 		    rate));
639*7c478bd9Sstevel@tonic-gate 	}
640*7c478bd9Sstevel@tonic-gate 	if (cmd == SET_WRITE_SPEED) {
641*7c478bd9Sstevel@tonic-gate 		rate = i_cd_speed_read(dev, GET_READ_SPEED);
642*7c478bd9Sstevel@tonic-gate 		return (set_cd_speed(dev->d_fd, rate,
643*7c478bd9Sstevel@tonic-gate 		    SPEED_TO_XFER_RATE(speed)));
644*7c478bd9Sstevel@tonic-gate 	}
645*7c478bd9Sstevel@tonic-gate 	return (0);
646*7c478bd9Sstevel@tonic-gate }
647*7c478bd9Sstevel@tonic-gate 
648*7c478bd9Sstevel@tonic-gate /*
649*7c478bd9Sstevel@tonic-gate  * cd speed related functions for drives which support RT-streaming
650*7c478bd9Sstevel@tonic-gate  */
651*7c478bd9Sstevel@tonic-gate int
652*7c478bd9Sstevel@tonic-gate rt_streaming_ctrl(cd_device *dev, int cmd, int speed)
653*7c478bd9Sstevel@tonic-gate {
654*7c478bd9Sstevel@tonic-gate 	uchar_t *perf, *str;
655*7c478bd9Sstevel@tonic-gate 	int write_perf;
656*7c478bd9Sstevel@tonic-gate 	int ret;
657*7c478bd9Sstevel@tonic-gate 	uint16_t perf_got;
658*7c478bd9Sstevel@tonic-gate 
659*7c478bd9Sstevel@tonic-gate 	write_perf = 0;
660*7c478bd9Sstevel@tonic-gate 	if ((cmd == GET_WRITE_SPEED) || (cmd == SET_READ_SPEED))
661*7c478bd9Sstevel@tonic-gate 		write_perf = 1;
662*7c478bd9Sstevel@tonic-gate 	perf = (uchar_t *)my_zalloc(GET_PERF_DATA_LEN);
663*7c478bd9Sstevel@tonic-gate 	if (!get_performance(dev->d_fd, write_perf, perf)) {
664*7c478bd9Sstevel@tonic-gate 		ret = 0;
665*7c478bd9Sstevel@tonic-gate 		goto end_rsc;
666*7c478bd9Sstevel@tonic-gate 	}
667*7c478bd9Sstevel@tonic-gate 	perf_got = (uint16_t)read_scsi32(&perf[20]);
668*7c478bd9Sstevel@tonic-gate 	if ((cmd == GET_READ_SPEED) || (cmd == GET_WRITE_SPEED)) {
669*7c478bd9Sstevel@tonic-gate 		ret = XFER_RATE_TO_SPEED(perf_got);
670*7c478bd9Sstevel@tonic-gate 		goto end_rsc;
671*7c478bd9Sstevel@tonic-gate 	}
672*7c478bd9Sstevel@tonic-gate 	str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN);
673*7c478bd9Sstevel@tonic-gate 	(void) memcpy(&str[8], &perf[16], 4);
674*7c478bd9Sstevel@tonic-gate 	load_scsi32(&str[16], 1000);
675*7c478bd9Sstevel@tonic-gate 	load_scsi32(&str[24], 1000);
676*7c478bd9Sstevel@tonic-gate 	if (cmd == SET_WRITE_SPEED) {
677*7c478bd9Sstevel@tonic-gate 		load_scsi32(&str[12], (uint32_t)perf_got);
678*7c478bd9Sstevel@tonic-gate 		load_scsi32(&str[20], (uint32_t)SPEED_TO_XFER_RATE(speed));
679*7c478bd9Sstevel@tonic-gate 	} else {
680*7c478bd9Sstevel@tonic-gate 		load_scsi32(&str[20], (uint32_t)perf_got);
681*7c478bd9Sstevel@tonic-gate 		load_scsi32(&str[12], (uint32_t)SPEED_TO_XFER_RATE(speed));
682*7c478bd9Sstevel@tonic-gate 	}
683*7c478bd9Sstevel@tonic-gate 	ret = set_streaming(dev->d_fd, str);
684*7c478bd9Sstevel@tonic-gate 	free(str);
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	/* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */
687*7c478bd9Sstevel@tonic-gate 	if (ret == 0) {
688*7c478bd9Sstevel@tonic-gate 		if (debug)
689*7c478bd9Sstevel@tonic-gate 			(void) printf(" real time speed control"
690*7c478bd9Sstevel@tonic-gate 			    " failed, using CD speed control\n");
691*7c478bd9Sstevel@tonic-gate 
692*7c478bd9Sstevel@tonic-gate 		dev->d_speed_ctrl = cd_speed_ctrl;
693*7c478bd9Sstevel@tonic-gate 		ret = dev->d_speed_ctrl(dev, cmd, speed);
694*7c478bd9Sstevel@tonic-gate 	}
695*7c478bd9Sstevel@tonic-gate 
696*7c478bd9Sstevel@tonic-gate end_rsc:
697*7c478bd9Sstevel@tonic-gate 	free(perf);
698*7c478bd9Sstevel@tonic-gate 	return (ret);
699*7c478bd9Sstevel@tonic-gate }
700*7c478bd9Sstevel@tonic-gate 
701*7c478bd9Sstevel@tonic-gate /*
702*7c478bd9Sstevel@tonic-gate  * Initialize device for track-at-once mode of writing. All of the data will
703*7c478bd9Sstevel@tonic-gate  * need to be written to the track without interruption.
704*7c478bd9Sstevel@tonic-gate  * This initialized TAO by setting page code 5 and speed.
705*7c478bd9Sstevel@tonic-gate  */
706*7c478bd9Sstevel@tonic-gate void
707*7c478bd9Sstevel@tonic-gate write_init(int mode)
708*7c478bd9Sstevel@tonic-gate {
709*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("Initializing device"));
710*7c478bd9Sstevel@tonic-gate 	if (simulation)
711*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("(Simulation mode)"));
712*7c478bd9Sstevel@tonic-gate 	print_n_flush("...");
713*7c478bd9Sstevel@tonic-gate 
714*7c478bd9Sstevel@tonic-gate 	get_media_type(target->d_fd);
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	/* DVD- requires DAO mode */
717*7c478bd9Sstevel@tonic-gate 	if (device_type == DVD_MINUS) {
718*7c478bd9Sstevel@tonic-gate 		write_mode = DAO_MODE;
719*7c478bd9Sstevel@tonic-gate 	}
720*7c478bd9Sstevel@tonic-gate 
721*7c478bd9Sstevel@tonic-gate 	/* For debug, print out device config information */
722*7c478bd9Sstevel@tonic-gate 	if (debug) {
723*7c478bd9Sstevel@tonic-gate 		int i;
724*7c478bd9Sstevel@tonic-gate 		uchar_t cap[80];
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate 		if (get_configuration(target->d_fd, 0, 80, cap))
727*7c478bd9Sstevel@tonic-gate 			(void) printf("Drive profile = ");
728*7c478bd9Sstevel@tonic-gate 			for (i = 10; i < 70; i += 8)
729*7c478bd9Sstevel@tonic-gate 				(void) printf(" 0x%x", cap[i]);
730*7c478bd9Sstevel@tonic-gate 			(void) printf("\n");
731*7c478bd9Sstevel@tonic-gate 	}
732*7c478bd9Sstevel@tonic-gate 
733*7c478bd9Sstevel@tonic-gate 	/* DVD+ and DVD- have no support for AUDIO, bail out */
734*7c478bd9Sstevel@tonic-gate 	if ((mode == TRACK_MODE_AUDIO) && (device_type != CD_RW)) {
735*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Audio mode is only supported for CD media\n"));
736*7c478bd9Sstevel@tonic-gate 		exit(1);
737*7c478bd9Sstevel@tonic-gate 	}
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate 	if (!prepare_for_write(target, mode, simulation, keep_disc_open)) {
740*7c478bd9Sstevel@tonic-gate 		/* l10n_NOTE : 'failed' as in Initializing device...failed  */
741*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("failed.\n"));
742*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Cannot initialize device for write\n"));
743*7c478bd9Sstevel@tonic-gate 		exit(1);
744*7c478bd9Sstevel@tonic-gate 	}
745*7c478bd9Sstevel@tonic-gate 	/* l10n_NOTE : 'done' as in "Initializing device...done"  */
746*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("done.\n"));
747*7c478bd9Sstevel@tonic-gate 
748*7c478bd9Sstevel@tonic-gate 	/* if speed change option was used (-p) then try to set the speed */
749*7c478bd9Sstevel@tonic-gate 	if (requested_speed != 0) {
750*7c478bd9Sstevel@tonic-gate 		if (verbose)
751*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Trying to set speed to %dX.\n"),
752*7c478bd9Sstevel@tonic-gate 			    requested_speed);
753*7c478bd9Sstevel@tonic-gate 		if (target->d_speed_ctrl(target, SET_WRITE_SPEED,
754*7c478bd9Sstevel@tonic-gate 		    requested_speed) == 0) {
755*7c478bd9Sstevel@tonic-gate 			err_msg(gettext("Unable to set speed.\n"));
756*7c478bd9Sstevel@tonic-gate 			exit(1);
757*7c478bd9Sstevel@tonic-gate 		}
758*7c478bd9Sstevel@tonic-gate 		if (verbose) {
759*7c478bd9Sstevel@tonic-gate 			int speed;
760*7c478bd9Sstevel@tonic-gate 			speed = target->d_speed_ctrl(target,
761*7c478bd9Sstevel@tonic-gate 			    GET_WRITE_SPEED, 0);
762*7c478bd9Sstevel@tonic-gate 			if (speed == requested_speed) {
763*7c478bd9Sstevel@tonic-gate 				(void) printf(gettext("Speed set to %dX.\n"),
764*7c478bd9Sstevel@tonic-gate 				    speed);
765*7c478bd9Sstevel@tonic-gate 			} else {
766*7c478bd9Sstevel@tonic-gate 				(void) printf(
767*7c478bd9Sstevel@tonic-gate 				gettext("Speed set to closest approximation "
768*7c478bd9Sstevel@tonic-gate 				    "of %dX allowed by device (%dX).\n"),
769*7c478bd9Sstevel@tonic-gate 				    requested_speed, speed);
770*7c478bd9Sstevel@tonic-gate 			}
771*7c478bd9Sstevel@tonic-gate 		}
772*7c478bd9Sstevel@tonic-gate 	}
773*7c478bd9Sstevel@tonic-gate }
774*7c478bd9Sstevel@tonic-gate 
775*7c478bd9Sstevel@tonic-gate void
776*7c478bd9Sstevel@tonic-gate write_fini(void)
777*7c478bd9Sstevel@tonic-gate {
778*7c478bd9Sstevel@tonic-gate 	print_n_flush(gettext("Finalizing (Can take several minutes)..."));
779*7c478bd9Sstevel@tonic-gate 	/* Some drives don't like this while in test write mode */
780*7c478bd9Sstevel@tonic-gate 	if (!simulation) {
781*7c478bd9Sstevel@tonic-gate 		if (!finalize(target)) {
782*7c478bd9Sstevel@tonic-gate 			/*
783*7c478bd9Sstevel@tonic-gate 			 * It is possible that the drive is busy writing the
784*7c478bd9Sstevel@tonic-gate 			 * buffered portion. So do not get upset yet.
785*7c478bd9Sstevel@tonic-gate 			 */
786*7c478bd9Sstevel@tonic-gate 			(void) sleep(10);
787*7c478bd9Sstevel@tonic-gate 			if (!finalize(target)) {
788*7c478bd9Sstevel@tonic-gate 				if (debug) {
789*7c478bd9Sstevel@tonic-gate 					(void) printf("status %x, %x/%x/%x\n",
790*7c478bd9Sstevel@tonic-gate 					    uscsi_status, SENSE_KEY(rqbuf),
791*7c478bd9Sstevel@tonic-gate 					    ASC(rqbuf), ASCQ(rqbuf));
792*7c478bd9Sstevel@tonic-gate 				}
793*7c478bd9Sstevel@tonic-gate 
794*7c478bd9Sstevel@tonic-gate 				if ((device_type == DVD_MINUS) &&
795*7c478bd9Sstevel@tonic-gate 				    (SENSE_KEY(rqbuf) == 5)) {
796*7c478bd9Sstevel@tonic-gate 
797*7c478bd9Sstevel@tonic-gate 					if (verbose) {
798*7c478bd9Sstevel@tonic-gate 						(void) printf(
799*7c478bd9Sstevel@tonic-gate 						    "skipping finalizing\n");
800*7c478bd9Sstevel@tonic-gate 					}
801*7c478bd9Sstevel@tonic-gate 				} else {
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate 			/* l10n_NOTE : 'failed' as in finishing up...failed  */
804*7c478bd9Sstevel@tonic-gate 					(void) printf(gettext("failed.\n"));
805*7c478bd9Sstevel@tonic-gate 
806*7c478bd9Sstevel@tonic-gate 					err_msg(gettext(
807*7c478bd9Sstevel@tonic-gate 					    "Could not finalize the disc.\n"));
808*7c478bd9Sstevel@tonic-gate 					exit(1);
809*7c478bd9Sstevel@tonic-gate 				}
810*7c478bd9Sstevel@tonic-gate 
811*7c478bd9Sstevel@tonic-gate 
812*7c478bd9Sstevel@tonic-gate 			}
813*7c478bd9Sstevel@tonic-gate 		}
814*7c478bd9Sstevel@tonic-gate 		if (vol_running) {
815*7c478bd9Sstevel@tonic-gate 			(void) eject_media(target);
816*7c478bd9Sstevel@tonic-gate 		}
817*7c478bd9Sstevel@tonic-gate 	} else if (check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) {
818*7c478bd9Sstevel@tonic-gate 		/*
819*7c478bd9Sstevel@tonic-gate 		 * Some drives such as the pioneer A04 will retain a
820*7c478bd9Sstevel@tonic-gate 		 * ghost TOC after a simulation write is done. The
821*7c478bd9Sstevel@tonic-gate 		 * media will actually be blank, but the drive will
822*7c478bd9Sstevel@tonic-gate 		 * report a TOC. There is currently no other way to
823*7c478bd9Sstevel@tonic-gate 		 * re-initialize the media other than ejecting or
824*7c478bd9Sstevel@tonic-gate 		 * to ask the drive to clear the leadout. The laser
825*7c478bd9Sstevel@tonic-gate 		 * is currently off so nothing is written to the
826*7c478bd9Sstevel@tonic-gate 		 * media (on a good behaving drive).
827*7c478bd9Sstevel@tonic-gate 		 * NOTE that a device reset does not work to make
828*7c478bd9Sstevel@tonic-gate 		 * the drive re-initialize the media.
829*7c478bd9Sstevel@tonic-gate 		 */
830*7c478bd9Sstevel@tonic-gate 
831*7c478bd9Sstevel@tonic-gate 		if (!vol_running) {
832*7c478bd9Sstevel@tonic-gate 			blanking_type = "clear";
833*7c478bd9Sstevel@tonic-gate 			blank();
834*7c478bd9Sstevel@tonic-gate 		}
835*7c478bd9Sstevel@tonic-gate 
836*7c478bd9Sstevel@tonic-gate 	}
837*7c478bd9Sstevel@tonic-gate 	/* l10n_NOTE : 'done' as in "Finishing up...done"  */
838*7c478bd9Sstevel@tonic-gate 	(void) printf(gettext("done.\n"));
839*7c478bd9Sstevel@tonic-gate }
840