xref: /titanic_41/usr/src/cmd/cdrw/blank.c (revision a2b4fdf6f9770a7725bfd41e7b3a92253e26645c)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*a2b4fdf6Srameshc  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <libintl.h>
337c478bd9Sstevel@tonic-gate #include <unistd.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "msgs.h"
367c478bd9Sstevel@tonic-gate #include "mmc.h"
377c478bd9Sstevel@tonic-gate #include "util.h"
387c478bd9Sstevel@tonic-gate #include "transport.h"
397c478bd9Sstevel@tonic-gate #include "main.h"
407c478bd9Sstevel@tonic-gate #include "misc_scsi.h"
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate /*
437c478bd9Sstevel@tonic-gate  * This is called recursively once, if an ALL blank succeeds but the
447c478bd9Sstevel@tonic-gate  * media is not blank we call blank() again to perform a fast blank.
457c478bd9Sstevel@tonic-gate  * This is a workaround for some drives such as older Toshiba DVD-RW
467c478bd9Sstevel@tonic-gate  * which has this problem with ALL blanking.
477c478bd9Sstevel@tonic-gate  */
487c478bd9Sstevel@tonic-gate void
blank(void)497c478bd9Sstevel@tonic-gate blank(void)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	int type, invalid;
527c478bd9Sstevel@tonic-gate 	int count, ret;
537c478bd9Sstevel@tonic-gate 	uchar_t *di, *buf;
547c478bd9Sstevel@tonic-gate 	int immediate, err;
557c478bd9Sstevel@tonic-gate 	int silent_pass = 0;
56*a2b4fdf6Srameshc 	/*
57*a2b4fdf6Srameshc 	 * silent_pass is set to 1 whenever we do not want to print
58*a2b4fdf6Srameshc 	 * information messages. This is the case where blank() function
59*a2b4fdf6Srameshc 	 * is called within the blank() function or the blank() function
60*a2b4fdf6Srameshc 	 * is called from other functions within cdrw to blank the media
61*a2b4fdf6Srameshc 	 * as part of other operations (clearing ghost TOC, closing the media
62*a2b4fdf6Srameshc 	 * after a write operation, etc). In all those cases we need not print
63*a2b4fdf6Srameshc 	 * or duplicate information messages. We should also return from the
64*a2b4fdf6Srameshc 	 * blank() function to the calling function in those cases.
65*a2b4fdf6Srameshc 	 */
66*a2b4fdf6Srameshc 	int ignore_error = 0;
67*a2b4fdf6Srameshc 	/*
68*a2b4fdf6Srameshc 	 * ignore_error is set to 1 whenever we do not want to report any
69*a2b4fdf6Srameshc 	 * error messages to the user and make things transparent to the
70*a2b4fdf6Srameshc 	 * user (For eg: Clearing ghost TOC during write simulation).
71*a2b4fdf6Srameshc 	 */
72*a2b4fdf6Srameshc 
737c478bd9Sstevel@tonic-gate 	invalid = 0;
747c478bd9Sstevel@tonic-gate 	err = 0;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate 	(void) check_device(target, CHECK_TYPE_NOT_CDROM | CHECK_NO_MEDIA |
777c478bd9Sstevel@tonic-gate 	    EXIT_IF_CHECK_FAILED);
787c478bd9Sstevel@tonic-gate 	(void) check_device(target, CHECK_DEVICE_NOT_READY |
797c478bd9Sstevel@tonic-gate 	    CHECK_DEVICE_NOT_WRITABLE | EXIT_IF_CHECK_FAILED);
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate 	if (blanking_type == NULL) {
827c478bd9Sstevel@tonic-gate 		invalid = 1;
837c478bd9Sstevel@tonic-gate 	}
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	get_media_type(target->d_fd);
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate 	if (strcmp(blanking_type, "all") == 0) {
887c478bd9Sstevel@tonic-gate 		/* erase the whole disk */
897c478bd9Sstevel@tonic-gate 		type = ALL;
907c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "session") == 0) {
917c478bd9Sstevel@tonic-gate 		/* only erase the last session */
927c478bd9Sstevel@tonic-gate 		type = SESSION;
937c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "fast") == 0) {
947c478bd9Sstevel@tonic-gate 		/* quick blank the TOC on the media */
957c478bd9Sstevel@tonic-gate 		type = FAST;
967c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "leadout") == 0) {
977c478bd9Sstevel@tonic-gate 		/* erase the track tail to unclose the media */
987c478bd9Sstevel@tonic-gate 		type = LEADOUT;
997c478bd9Sstevel@tonic-gate 		silent_pass = 1;
1007c478bd9Sstevel@tonic-gate 	} else if (strcmp(blanking_type, "clear") == 0) {
1017c478bd9Sstevel@tonic-gate 		/*
1027c478bd9Sstevel@tonic-gate 		 * used for drives where "all" blanking fails,
1037c478bd9Sstevel@tonic-gate 		 * if it fails we follow up with a quick erase of TOC.
1047c478bd9Sstevel@tonic-gate 		 * This is only called from within this function to do
1057c478bd9Sstevel@tonic-gate 		 * a second blanking pass.
1067c478bd9Sstevel@tonic-gate 		 */
1077c478bd9Sstevel@tonic-gate 		type = CLEAR;
1087c478bd9Sstevel@tonic-gate 		silent_pass = 1;
109*a2b4fdf6Srameshc 	} else if (strcmp(blanking_type, "clear_ghost") == 0) {
110*a2b4fdf6Srameshc 		/*
111*a2b4fdf6Srameshc 		 * used for drives in simulation mode to blank ghost
112*a2b4fdf6Srameshc 		 * TOC after simulation write is complete.
113*a2b4fdf6Srameshc 		 */
114*a2b4fdf6Srameshc 		type = CLEAR;
115*a2b4fdf6Srameshc 		silent_pass = 1;
116*a2b4fdf6Srameshc 		ignore_error = 1;
1177c478bd9Sstevel@tonic-gate 	} else {
1187c478bd9Sstevel@tonic-gate 		/* invalid blank type was passed on the command line */
1197c478bd9Sstevel@tonic-gate 		invalid = 1;
1207c478bd9Sstevel@tonic-gate 	}
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate 	if (invalid) {
1237c478bd9Sstevel@tonic-gate 		err_msg(gettext("Invalid blanking type specified\n"));
1247c478bd9Sstevel@tonic-gate 		exit(1);
1257c478bd9Sstevel@tonic-gate 	}
126*a2b4fdf6Srameshc 
127*a2b4fdf6Srameshc 	/*
128*a2b4fdf6Srameshc 	 * many DVD+RW drives do not allow blanking the media, it is also
129*a2b4fdf6Srameshc 	 * not included in the spec, we would just reformat the media prior
130*a2b4fdf6Srameshc 	 * to writing. This is not the equivelent to blanking as the media
131*a2b4fdf6Srameshc 	 * contains a TOC when formatted.
132*a2b4fdf6Srameshc 	 */
133*a2b4fdf6Srameshc 	if (device_type == DVD_PLUS_W) {
134*a2b4fdf6Srameshc 		if (ignore_error)
135*a2b4fdf6Srameshc 			return;
136*a2b4fdf6Srameshc 		err_msg(gettext("Blanking cannot be done on DVD+RW media\n"));
137*a2b4fdf6Srameshc 		exit(1);
138*a2b4fdf6Srameshc 	}
139*a2b4fdf6Srameshc 
1407c478bd9Sstevel@tonic-gate 	if ((target->d_inq[2] & 7) != 0) {
1417c478bd9Sstevel@tonic-gate 		/* SCSI device */
1427c478bd9Sstevel@tonic-gate 		immediate = 0;
1437c478bd9Sstevel@tonic-gate 	} else {
1447c478bd9Sstevel@tonic-gate 		/* non-SCSI (e.g ATAPI) device */
1457c478bd9Sstevel@tonic-gate 		immediate = 1;
1467c478bd9Sstevel@tonic-gate 	}
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 	/* we are doing a second pass. We don't want to re-print messsages */
1497c478bd9Sstevel@tonic-gate 	if (!silent_pass)
1507c478bd9Sstevel@tonic-gate 		print_n_flush(gettext("Initializing device..."));
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/* Make sure that test write is off */
1537c478bd9Sstevel@tonic-gate 	buf = (uchar_t *)my_zalloc(64);
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	/* get mode page for test writing if it fails we cannot turn it off */
1567c478bd9Sstevel@tonic-gate 	if (!get_mode_page(target->d_fd, 5, 0, 64, buf)) {
157*a2b4fdf6Srameshc 		if (ignore_error)
158*a2b4fdf6Srameshc 			return;
1597c478bd9Sstevel@tonic-gate 		err_msg(gettext("Device not supported\n"));
1607c478bd9Sstevel@tonic-gate 		exit(1);
1617c478bd9Sstevel@tonic-gate 	}
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 	buf[2] &= 0xef;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* turn laser on */
1667c478bd9Sstevel@tonic-gate 	if (!set_mode_page(target->d_fd, buf)) {
167*a2b4fdf6Srameshc 		if (ignore_error)
168*a2b4fdf6Srameshc 			return;
1697c478bd9Sstevel@tonic-gate 		err_msg(gettext("Unable to configure device\n"));
1707c478bd9Sstevel@tonic-gate 		exit(1);
1717c478bd9Sstevel@tonic-gate 	}
1727c478bd9Sstevel@tonic-gate 	free(buf);
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* we are doing a second pass. We don't want to re-print messsages */
1757c478bd9Sstevel@tonic-gate 	if (!silent_pass) {
1767c478bd9Sstevel@tonic-gate 		/* l10n_NOTE : 'done' as in "Initializing device...done"  */
1777c478bd9Sstevel@tonic-gate 		(void) printf(gettext("done.\n"));
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 		print_n_flush(gettext(
1807c478bd9Sstevel@tonic-gate 		    "Blanking the media (Can take several minutes)..."));
1817c478bd9Sstevel@tonic-gate 	}
1827c478bd9Sstevel@tonic-gate 	if (!blank_disc(target->d_fd, type, immediate)) {
183*a2b4fdf6Srameshc 		if (ignore_error)
184*a2b4fdf6Srameshc 			return;
1857c478bd9Sstevel@tonic-gate 		err_msg(gettext("Blank command failed\n"));
1867c478bd9Sstevel@tonic-gate 		if (debug)
1877c478bd9Sstevel@tonic-gate 			(void) printf("%x %x %x %x\n", uscsi_status,
1887c478bd9Sstevel@tonic-gate 			    SENSE_KEY(rqbuf), ASC(rqbuf), ASCQ(rqbuf));
1897c478bd9Sstevel@tonic-gate 		goto blank_failed;
1907c478bd9Sstevel@tonic-gate 	}
1917c478bd9Sstevel@tonic-gate 	/* Allow the blanking to start */
1927c478bd9Sstevel@tonic-gate 	(void) sleep(10);
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	/*
1957c478bd9Sstevel@tonic-gate 	 * set ATAPI devices to immediately return from the command and poll
1967c478bd9Sstevel@tonic-gate 	 * so that we don't hog the channel.
1977c478bd9Sstevel@tonic-gate 	 */
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	if (immediate) {
2007c478bd9Sstevel@tonic-gate 		di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE);
2017c478bd9Sstevel@tonic-gate 		/* Blanking should not take more than 75 minutes */
2027c478bd9Sstevel@tonic-gate 		for (count = 0; count < (16*60); count++) {
2037c478bd9Sstevel@tonic-gate 			ret = read_disc_info(target->d_fd, di);
2047c478bd9Sstevel@tonic-gate 			if (ret != 0)
2057c478bd9Sstevel@tonic-gate 				break;
2067c478bd9Sstevel@tonic-gate 			if (uscsi_status != 2)
2077c478bd9Sstevel@tonic-gate 				err = 1;
2087c478bd9Sstevel@tonic-gate 			/* not ready but not becoming ready */
2097c478bd9Sstevel@tonic-gate 			if (SENSE_KEY(rqbuf) == 2) {
2107c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) != 4)
2117c478bd9Sstevel@tonic-gate 					err = 1;
2127c478bd9Sstevel@tonic-gate 			/* illegal mode for this track */
2137c478bd9Sstevel@tonic-gate 			} else if (SENSE_KEY(rqbuf) == 5) {
2147c478bd9Sstevel@tonic-gate 				if (ASC(rqbuf) != 0x64)
2157c478bd9Sstevel@tonic-gate 					err = 1;
2167c478bd9Sstevel@tonic-gate 			} else {
2177c478bd9Sstevel@tonic-gate 				err = 1;
2187c478bd9Sstevel@tonic-gate 			}
2197c478bd9Sstevel@tonic-gate 			if (err == 1) {
220*a2b4fdf6Srameshc 				if (ignore_error)
221*a2b4fdf6Srameshc 					break;
2227c478bd9Sstevel@tonic-gate 				err_msg(gettext("Blanking operation failed\n"));
2237c478bd9Sstevel@tonic-gate 				if (debug) {
2247c478bd9Sstevel@tonic-gate 					(void) printf("%x %x %x %x\n",
2257c478bd9Sstevel@tonic-gate 					    uscsi_status, SENSE_KEY(rqbuf),
2267c478bd9Sstevel@tonic-gate 					    ASC(rqbuf), ASCQ(rqbuf));
2277c478bd9Sstevel@tonic-gate 				}
2287c478bd9Sstevel@tonic-gate 				free(di);
2297c478bd9Sstevel@tonic-gate 				goto blank_failed;
2307c478bd9Sstevel@tonic-gate 			}
2317c478bd9Sstevel@tonic-gate 			(void) sleep(5);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 		free(di);
2347c478bd9Sstevel@tonic-gate 		if (count == (16*60)) {
235*a2b4fdf6Srameshc 			if (!silent_pass) {
236*a2b4fdf6Srameshc 				(void) printf(gettext(
237*a2b4fdf6Srameshc 				    "Blank command timed out.\n"));
238*a2b4fdf6Srameshc 			}
2397c478bd9Sstevel@tonic-gate 			goto blank_failed;
2407c478bd9Sstevel@tonic-gate 		}
2417c478bd9Sstevel@tonic-gate 	}
2427c478bd9Sstevel@tonic-gate 	/* we are doing a second pass. We don't want to re-print messsages */
2437c478bd9Sstevel@tonic-gate 	if (!silent_pass) {
2447c478bd9Sstevel@tonic-gate 		/* l10n_NOTE : 'done' as in "Erasing track 1...done"  */
2457c478bd9Sstevel@tonic-gate 		(void) printf(gettext("done.\n"));
2467c478bd9Sstevel@tonic-gate 	}
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 	/*
2497c478bd9Sstevel@tonic-gate 	 * some cruft left from all blanking, this has been seen on some
2507c478bd9Sstevel@tonic-gate 	 * newer drives including Toshiba SD-6112 DVD-RW and Sony 510A.
2517c478bd9Sstevel@tonic-gate 	 * we will do a second pass with a recursive call to blank the
2527c478bd9Sstevel@tonic-gate 	 * lead-in.
2537c478bd9Sstevel@tonic-gate 	 */
2547c478bd9Sstevel@tonic-gate 	if (type == ALL) {
255*a2b4fdf6Srameshc 		if (check_device(target,  CHECK_MEDIA_IS_NOT_BLANK)) {
2567c478bd9Sstevel@tonic-gate 			blanking_type = "clear";
2577c478bd9Sstevel@tonic-gate 			blank();
258*a2b4fdf6Srameshc 			if (silent_pass)
259*a2b4fdf6Srameshc 				return;
2607c478bd9Sstevel@tonic-gate 			exit(0);
2617c478bd9Sstevel@tonic-gate 		}
2627c478bd9Sstevel@tonic-gate 	}
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * We erased part of the leadout for the media to unclose
2667c478bd9Sstevel@tonic-gate 	 * the disk, we still need to generate an appendable leadout
2677c478bd9Sstevel@tonic-gate 	 * so that the next track can be written. so do not eject or exit.
2687c478bd9Sstevel@tonic-gate 	 */
2697c478bd9Sstevel@tonic-gate 	if (silent_pass)
2707c478bd9Sstevel@tonic-gate 		return;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if (vol_running)
2737c478bd9Sstevel@tonic-gate 		(void) eject_media(target);
2747c478bd9Sstevel@tonic-gate 	exit(0);
2757c478bd9Sstevel@tonic-gate blank_failed:
2767c478bd9Sstevel@tonic-gate 	if ((type != ALL) && !silent_pass) {
2777c478bd9Sstevel@tonic-gate 		(void) printf("Try using blanking type 'all'\n");
2787c478bd9Sstevel@tonic-gate 	}
279*a2b4fdf6Srameshc 	if (silent_pass)
280*a2b4fdf6Srameshc 		return;
2817c478bd9Sstevel@tonic-gate 	if (vol_running)
2827c478bd9Sstevel@tonic-gate 		(void) eject_media(target);
2837c478bd9Sstevel@tonic-gate 	exit(1);
2847c478bd9Sstevel@tonic-gate }
285