xref: /titanic_50/usr/src/cmd/cdrw/blank.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 <libintl.h>
33*7c478bd9Sstevel@tonic-gate #include <unistd.h>
34*7c478bd9Sstevel@tonic-gate 
35*7c478bd9Sstevel@tonic-gate #include "msgs.h"
36*7c478bd9Sstevel@tonic-gate #include "mmc.h"
37*7c478bd9Sstevel@tonic-gate #include "util.h"
38*7c478bd9Sstevel@tonic-gate #include "transport.h"
39*7c478bd9Sstevel@tonic-gate #include "main.h"
40*7c478bd9Sstevel@tonic-gate #include "misc_scsi.h"
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate /*
43*7c478bd9Sstevel@tonic-gate  * This is called recursively once, if an ALL blank succeeds but the
44*7c478bd9Sstevel@tonic-gate  * media is not blank we call blank() again to perform a fast blank.
45*7c478bd9Sstevel@tonic-gate  * This is a workaround for some drives such as older Toshiba DVD-RW
46*7c478bd9Sstevel@tonic-gate  * which has this problem with ALL blanking.
47*7c478bd9Sstevel@tonic-gate  */
48*7c478bd9Sstevel@tonic-gate void
49*7c478bd9Sstevel@tonic-gate blank(void)
50*7c478bd9Sstevel@tonic-gate {
51*7c478bd9Sstevel@tonic-gate 	int type, invalid;
52*7c478bd9Sstevel@tonic-gate 	int count, ret;
53*7c478bd9Sstevel@tonic-gate 	uchar_t *di, *buf;
54*7c478bd9Sstevel@tonic-gate 	int immediate, err;
55*7c478bd9Sstevel@tonic-gate 	int silent_pass = 0;
56*7c478bd9Sstevel@tonic-gate 	invalid = 0;
57*7c478bd9Sstevel@tonic-gate 	err = 0;
58*7c478bd9Sstevel@tonic-gate 
59*7c478bd9Sstevel@tonic-gate 	(void) check_device(target, CHECK_TYPE_NOT_CDROM | CHECK_NO_MEDIA |
60*7c478bd9Sstevel@tonic-gate 	    EXIT_IF_CHECK_FAILED);
61*7c478bd9Sstevel@tonic-gate 	(void) check_device(target, CHECK_DEVICE_NOT_READY |
62*7c478bd9Sstevel@tonic-gate 	    CHECK_DEVICE_NOT_WRITABLE | EXIT_IF_CHECK_FAILED);
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate 	if (blanking_type == NULL) {
65*7c478bd9Sstevel@tonic-gate 		invalid = 1;
66*7c478bd9Sstevel@tonic-gate 	}
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate 	get_media_type(target->d_fd);
69*7c478bd9Sstevel@tonic-gate 
70*7c478bd9Sstevel@tonic-gate 	/*
71*7c478bd9Sstevel@tonic-gate 	 * many DVD+RW drives do not allow blanking the media, it is also
72*7c478bd9Sstevel@tonic-gate 	 * not included in the spec, we would just reformat the media prior
73*7c478bd9Sstevel@tonic-gate 	 * to writing. This is not the equivelent to blanking as the media
74*7c478bd9Sstevel@tonic-gate 	 * contains a TOC when formatted.
75*7c478bd9Sstevel@tonic-gate 	 */
76*7c478bd9Sstevel@tonic-gate 	if (device_type == DVD_PLUS_W) {
77*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Blanking cannot be done on DVD+RW media\n"));
78*7c478bd9Sstevel@tonic-gate 		exit(1);
79*7c478bd9Sstevel@tonic-gate 	}
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate 	if (strcmp(blanking_type, "all") == 0) {
82*7c478bd9Sstevel@tonic-gate 		/* erase the whole disk */
83*7c478bd9Sstevel@tonic-gate 		type = ALL;
84*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "session") == 0) {
85*7c478bd9Sstevel@tonic-gate 		/* only erase the last session */
86*7c478bd9Sstevel@tonic-gate 		type = SESSION;
87*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "fast") == 0) {
88*7c478bd9Sstevel@tonic-gate 		/* quick blank the TOC on the media */
89*7c478bd9Sstevel@tonic-gate 		type = FAST;
90*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "leadout") == 0) {
91*7c478bd9Sstevel@tonic-gate 		/* erase the track tail to unclose the media */
92*7c478bd9Sstevel@tonic-gate 		type = LEADOUT;
93*7c478bd9Sstevel@tonic-gate 		silent_pass = 1;
94*7c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "clear") == 0) {
95*7c478bd9Sstevel@tonic-gate 		/*
96*7c478bd9Sstevel@tonic-gate 		 * used for drives where "all" blanking fails,
97*7c478bd9Sstevel@tonic-gate 		 * if it fails we follow up with a quick erase of TOC.
98*7c478bd9Sstevel@tonic-gate 		 * This is only called from within this function to do
99*7c478bd9Sstevel@tonic-gate 		 * a second blanking pass.
100*7c478bd9Sstevel@tonic-gate 		 */
101*7c478bd9Sstevel@tonic-gate 		type = CLEAR;
102*7c478bd9Sstevel@tonic-gate 		silent_pass = 1;
103*7c478bd9Sstevel@tonic-gate 	} else {
104*7c478bd9Sstevel@tonic-gate 		/* invalid blank type was passed on the command line */
105*7c478bd9Sstevel@tonic-gate 		invalid = 1;
106*7c478bd9Sstevel@tonic-gate 	}
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 	if (invalid) {
109*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Invalid blanking type specified\n"));
110*7c478bd9Sstevel@tonic-gate 		exit(1);
111*7c478bd9Sstevel@tonic-gate 	}
112*7c478bd9Sstevel@tonic-gate 	if ((target->d_inq[2] & 7) != 0) {
113*7c478bd9Sstevel@tonic-gate 		/* SCSI device */
114*7c478bd9Sstevel@tonic-gate 		immediate = 0;
115*7c478bd9Sstevel@tonic-gate 	} else {
116*7c478bd9Sstevel@tonic-gate 		/* non-SCSI (e.g ATAPI) device */
117*7c478bd9Sstevel@tonic-gate 		immediate = 1;
118*7c478bd9Sstevel@tonic-gate 	}
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 	/* we are doing a second pass. We don't want to re-print messsages */
121*7c478bd9Sstevel@tonic-gate 	if (!silent_pass)
122*7c478bd9Sstevel@tonic-gate 		print_n_flush(gettext("Initializing device..."));
123*7c478bd9Sstevel@tonic-gate 
124*7c478bd9Sstevel@tonic-gate 	/* Make sure that test write is off */
125*7c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)my_zalloc(64);
126*7c478bd9Sstevel@tonic-gate 
127*7c478bd9Sstevel@tonic-gate 	/* get mode page for test writing if it fails we cannot turn it off */
128*7c478bd9Sstevel@tonic-gate 	if (!get_mode_page(target->d_fd, 5, 0, 64, buf)) {
129*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Device not supported\n"));
130*7c478bd9Sstevel@tonic-gate 		exit(1);
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	buf[2] &= 0xef;
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate 	/* turn laser on */
136*7c478bd9Sstevel@tonic-gate 	if (!set_mode_page(target->d_fd, buf)) {
137*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Unable to configure device\n"));
138*7c478bd9Sstevel@tonic-gate 		exit(1);
139*7c478bd9Sstevel@tonic-gate 	}
140*7c478bd9Sstevel@tonic-gate 	free(buf);
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	/* we are doing a second pass. We don't want to re-print messsages */
143*7c478bd9Sstevel@tonic-gate 	if (!silent_pass) {
144*7c478bd9Sstevel@tonic-gate 		/* l10n_NOTE : 'done' as in "Initializing device...done"  */
145*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("done.\n"));
146*7c478bd9Sstevel@tonic-gate 
147*7c478bd9Sstevel@tonic-gate 		print_n_flush(gettext(
148*7c478bd9Sstevel@tonic-gate 		    "Blanking the media (Can take several minutes)..."));
149*7c478bd9Sstevel@tonic-gate 	}
150*7c478bd9Sstevel@tonic-gate 	if (!blank_disc(target->d_fd, type, immediate)) {
151*7c478bd9Sstevel@tonic-gate 		err_msg(gettext("Blank command failed\n"));
152*7c478bd9Sstevel@tonic-gate 		if (debug)
153*7c478bd9Sstevel@tonic-gate 			(void) printf("%x %x %x %x\n", uscsi_status,
154*7c478bd9Sstevel@tonic-gate 			    SENSE_KEY(rqbuf), ASC(rqbuf), ASCQ(rqbuf));
155*7c478bd9Sstevel@tonic-gate 		goto blank_failed;
156*7c478bd9Sstevel@tonic-gate 	}
157*7c478bd9Sstevel@tonic-gate 	/* Allow the blanking to start */
158*7c478bd9Sstevel@tonic-gate 	(void) sleep(10);
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	/*
161*7c478bd9Sstevel@tonic-gate 	 * set ATAPI devices to immediately return from the command and poll
162*7c478bd9Sstevel@tonic-gate 	 * so that we don't hog the channel.
163*7c478bd9Sstevel@tonic-gate 	 */
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	if (immediate) {
166*7c478bd9Sstevel@tonic-gate 		di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
167*7c478bd9Sstevel@tonic-gate 		/* Blanking should not take more than 75 minutes */
168*7c478bd9Sstevel@tonic-gate 		for (count = 0; count < (16*60); count++) {
169*7c478bd9Sstevel@tonic-gate 			ret = read_disc_info(target->d_fd, di);
170*7c478bd9Sstevel@tonic-gate 			if (ret != 0)
171*7c478bd9Sstevel@tonic-gate 				break;
172*7c478bd9Sstevel@tonic-gate 			if (uscsi_status != 2)
173*7c478bd9Sstevel@tonic-gate 				err = 1;
174*7c478bd9Sstevel@tonic-gate 			/* not ready but not becoming ready */
175*7c478bd9Sstevel@tonic-gate 			if (SENSE_KEY(rqbuf) == 2) {
176*7c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) != 4)
177*7c478bd9Sstevel@tonic-gate 					err = 1;
178*7c478bd9Sstevel@tonic-gate 			/* illegal mode for this track */
179*7c478bd9Sstevel@tonic-gate 			} else if (SENSE_KEY(rqbuf) == 5) {
180*7c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) != 0x64)
181*7c478bd9Sstevel@tonic-gate 					err = 1;
182*7c478bd9Sstevel@tonic-gate 			} else {
183*7c478bd9Sstevel@tonic-gate 				err = 1;
184*7c478bd9Sstevel@tonic-gate 			}
185*7c478bd9Sstevel@tonic-gate 			if (err == 1) {
186*7c478bd9Sstevel@tonic-gate 				err_msg(gettext("Blanking operation failed\n"));
187*7c478bd9Sstevel@tonic-gate 				if (debug) {
188*7c478bd9Sstevel@tonic-gate 					(void) printf("%x %x %x %x\n",
189*7c478bd9Sstevel@tonic-gate 					    uscsi_status, SENSE_KEY(rqbuf),
190*7c478bd9Sstevel@tonic-gate 					    ASC(rqbuf), ASCQ(rqbuf));
191*7c478bd9Sstevel@tonic-gate 				}
192*7c478bd9Sstevel@tonic-gate 				free(di);
193*7c478bd9Sstevel@tonic-gate 				goto blank_failed;
194*7c478bd9Sstevel@tonic-gate 			}
195*7c478bd9Sstevel@tonic-gate 			(void) sleep(5);
196*7c478bd9Sstevel@tonic-gate 		}
197*7c478bd9Sstevel@tonic-gate 		free(di);
198*7c478bd9Sstevel@tonic-gate 		if (count == (16*60)) {
199*7c478bd9Sstevel@tonic-gate 			(void) printf(gettext("Blank command timed out.\n"));
200*7c478bd9Sstevel@tonic-gate 			goto blank_failed;
201*7c478bd9Sstevel@tonic-gate 		}
202*7c478bd9Sstevel@tonic-gate 	}
203*7c478bd9Sstevel@tonic-gate 	/* we are doing a second pass. We don't want to re-print messsages */
204*7c478bd9Sstevel@tonic-gate 	if (!silent_pass) {
205*7c478bd9Sstevel@tonic-gate 		/* l10n_NOTE : 'done' as in "Erasing track 1...done"  */
206*7c478bd9Sstevel@tonic-gate 		(void) printf(gettext("done.\n"));
207*7c478bd9Sstevel@tonic-gate 	}
208*7c478bd9Sstevel@tonic-gate 
209*7c478bd9Sstevel@tonic-gate 	/*
210*7c478bd9Sstevel@tonic-gate 	 * some cruft left from all blanking, this has been seen on some
211*7c478bd9Sstevel@tonic-gate 	 * newer drives including Toshiba SD-6112 DVD-RW and Sony 510A.
212*7c478bd9Sstevel@tonic-gate 	 * we will do a second pass with a recursive call to blank the
213*7c478bd9Sstevel@tonic-gate 	 * lead-in.
214*7c478bd9Sstevel@tonic-gate 	 */
215*7c478bd9Sstevel@tonic-gate 	if (type == ALL) {
216*7c478bd9Sstevel@tonic-gate 		if ((check_device(target,  CHECK_MEDIA_IS_NOT_BLANK)) &&
217*7c478bd9Sstevel@tonic-gate 		    (!vol_running)) {
218*7c478bd9Sstevel@tonic-gate 			blanking_type = "clear";
219*7c478bd9Sstevel@tonic-gate 			blank();
220*7c478bd9Sstevel@tonic-gate 			exit(0);
221*7c478bd9Sstevel@tonic-gate 		}
222*7c478bd9Sstevel@tonic-gate 	}
223*7c478bd9Sstevel@tonic-gate 
224*7c478bd9Sstevel@tonic-gate 	/*
225*7c478bd9Sstevel@tonic-gate 	 * We erased part of the leadout for the media to unclose
226*7c478bd9Sstevel@tonic-gate 	 * the disk, we still need to generate an appendable leadout
227*7c478bd9Sstevel@tonic-gate 	 * so that the next track can be written. so do not eject or exit.
228*7c478bd9Sstevel@tonic-gate 	 */
229*7c478bd9Sstevel@tonic-gate 	if (silent_pass)
230*7c478bd9Sstevel@tonic-gate 		return;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	if (vol_running)
233*7c478bd9Sstevel@tonic-gate 		(void) eject_media(target);
234*7c478bd9Sstevel@tonic-gate 	exit(0);
235*7c478bd9Sstevel@tonic-gate blank_failed:
236*7c478bd9Sstevel@tonic-gate 	if ((type != ALL) && !silent_pass) {
237*7c478bd9Sstevel@tonic-gate 		(void) printf("Try using blanking type 'all'\n");
238*7c478bd9Sstevel@tonic-gate 	}
239*7c478bd9Sstevel@tonic-gate 	if (vol_running)
240*7c478bd9Sstevel@tonic-gate 		(void) eject_media(target);
241*7c478bd9Sstevel@tonic-gate 	exit(1);
242*7c478bd9Sstevel@tonic-gate }
243