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