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 /* 23a2b4fdf6Srameshc * 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 <stdio.h> 337c478bd9Sstevel@tonic-gate #include <sys/dkio.h> 347c478bd9Sstevel@tonic-gate #include <unistd.h> 357c478bd9Sstevel@tonic-gate #include <errno.h> 367c478bd9Sstevel@tonic-gate #include <libintl.h> 377c478bd9Sstevel@tonic-gate #include <sys/time.h> 387c478bd9Sstevel@tonic-gate 397c478bd9Sstevel@tonic-gate #include "mmc.h" 407c478bd9Sstevel@tonic-gate #include "util.h" 417c478bd9Sstevel@tonic-gate #include "misc_scsi.h" 427c478bd9Sstevel@tonic-gate #include "transport.h" 437c478bd9Sstevel@tonic-gate #include "main.h" 447c478bd9Sstevel@tonic-gate #include "toshiba.h" 457c478bd9Sstevel@tonic-gate #include "msgs.h" 46*98584592Sarutz #include "device.h" 477c478bd9Sstevel@tonic-gate 487c478bd9Sstevel@tonic-gate uint32_t 497c478bd9Sstevel@tonic-gate read_scsi32(void *addr) 507c478bd9Sstevel@tonic-gate { 517c478bd9Sstevel@tonic-gate uchar_t *ad = (uchar_t *)addr; 527c478bd9Sstevel@tonic-gate uint32_t ret; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate ret = ((((uint32_t)ad[0]) << 24) | (((uint32_t)ad[1]) << 16) | 557c478bd9Sstevel@tonic-gate (((uint32_t)ad[2]) << 8) | ad[3]); 567c478bd9Sstevel@tonic-gate return (ret); 577c478bd9Sstevel@tonic-gate } 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate uint16_t 607c478bd9Sstevel@tonic-gate read_scsi16(void *addr) 617c478bd9Sstevel@tonic-gate { 627c478bd9Sstevel@tonic-gate uchar_t *ad = (uchar_t *)addr; 637c478bd9Sstevel@tonic-gate uint16_t ret; 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate ret = ((((uint16_t)ad[0]) << 8) | ad[1]); 667c478bd9Sstevel@tonic-gate return (ret); 677c478bd9Sstevel@tonic-gate } 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate void 707c478bd9Sstevel@tonic-gate load_scsi32(void *addr, uint32_t v) 717c478bd9Sstevel@tonic-gate { 727c478bd9Sstevel@tonic-gate uchar_t *ad = (uchar_t *)addr; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate ad[0] = (uchar_t)(v >> 24); 757c478bd9Sstevel@tonic-gate ad[1] = (uchar_t)(v >> 16); 767c478bd9Sstevel@tonic-gate ad[2] = (uchar_t)(v >> 8); 777c478bd9Sstevel@tonic-gate ad[3] = (uchar_t)v; 787c478bd9Sstevel@tonic-gate } 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate void 817c478bd9Sstevel@tonic-gate load_scsi16(void *addr, uint16_t v) 827c478bd9Sstevel@tonic-gate { 837c478bd9Sstevel@tonic-gate uchar_t *ad = (uchar_t *)addr; 847c478bd9Sstevel@tonic-gate ad[0] = (uchar_t)(v >> 8); 857c478bd9Sstevel@tonic-gate ad[1] = (uchar_t)v; 867c478bd9Sstevel@tonic-gate } 877c478bd9Sstevel@tonic-gate /* 887c478bd9Sstevel@tonic-gate * will get the mode page only i.e. will strip off the header. 897c478bd9Sstevel@tonic-gate */ 907c478bd9Sstevel@tonic-gate int 917c478bd9Sstevel@tonic-gate get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer) 927c478bd9Sstevel@tonic-gate { 937c478bd9Sstevel@tonic-gate int ret; 947c478bd9Sstevel@tonic-gate uchar_t byte2, *buf; 957c478bd9Sstevel@tonic-gate uint_t header_len, page_len, copy_cnt; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f)); 987c478bd9Sstevel@tonic-gate buf = (uchar_t *)my_zalloc(256); 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate /* Ask 254 bytes only to make our IDE driver happy */ 1017c478bd9Sstevel@tonic-gate ret = mode_sense(fd, byte2, 1, 254, buf); 1027c478bd9Sstevel@tonic-gate if (ret == 0) { 1037c478bd9Sstevel@tonic-gate free(buf); 1047c478bd9Sstevel@tonic-gate return (0); 1057c478bd9Sstevel@tonic-gate } 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate header_len = 8 + read_scsi16(&buf[6]); 1087c478bd9Sstevel@tonic-gate page_len = buf[header_len + 1] + 2; 1097c478bd9Sstevel@tonic-gate 1107c478bd9Sstevel@tonic-gate copy_cnt = (page_len > buf_len) ? buf_len : page_len; 1117c478bd9Sstevel@tonic-gate (void) memcpy(buffer, &buf[header_len], copy_cnt); 1127c478bd9Sstevel@tonic-gate free(buf); 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate return (1); 1157c478bd9Sstevel@tonic-gate } 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * will take care of adding mode header and any extra bytes at the end. 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate int 1217c478bd9Sstevel@tonic-gate set_mode_page(int fd, uchar_t *buffer) 1227c478bd9Sstevel@tonic-gate { 1237c478bd9Sstevel@tonic-gate int ret; 1247c478bd9Sstevel@tonic-gate uchar_t *buf; 1257c478bd9Sstevel@tonic-gate uint_t total, p_len; 1267c478bd9Sstevel@tonic-gate 1277c478bd9Sstevel@tonic-gate p_len = buffer[1] + 2; 1287c478bd9Sstevel@tonic-gate total = p_len + 8; 1297c478bd9Sstevel@tonic-gate buf = (uchar_t *)my_zalloc(total); 1307c478bd9Sstevel@tonic-gate 1317c478bd9Sstevel@tonic-gate (void) memcpy(&buf[8], buffer, p_len); 1327c478bd9Sstevel@tonic-gate if (debug) { 1337c478bd9Sstevel@tonic-gate int i; 1347c478bd9Sstevel@tonic-gate 1357c478bd9Sstevel@tonic-gate (void) printf("MODE: ["); 1367c478bd9Sstevel@tonic-gate for (i = 0; i < p_len; i++) { 1377c478bd9Sstevel@tonic-gate (void) printf("0x%02x ", (uchar_t)buffer[i]); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate (void) printf("]\n"); 1417c478bd9Sstevel@tonic-gate } 1427c478bd9Sstevel@tonic-gate ret = mode_select(fd, total, buf); 1437c478bd9Sstevel@tonic-gate free(buf); 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate return (ret); 1467c478bd9Sstevel@tonic-gate } 1477c478bd9Sstevel@tonic-gate 1487c478bd9Sstevel@tonic-gate /* 1497c478bd9Sstevel@tonic-gate * Builds track information database for track trackno. If trackno is 1507c478bd9Sstevel@tonic-gate * -1, builds the database for next blank track. 1517c478bd9Sstevel@tonic-gate */ 1527c478bd9Sstevel@tonic-gate int 1537c478bd9Sstevel@tonic-gate build_track_info(cd_device *dev, int trackno, struct track_info *t_info) 1547c478bd9Sstevel@tonic-gate { 1557c478bd9Sstevel@tonic-gate uchar_t *ti; 1567c478bd9Sstevel@tonic-gate uchar_t toc[20]; /* 2 entries + 4 byte header */ 1577c478bd9Sstevel@tonic-gate int ret; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate (void) memset(t_info, 0, sizeof (*t_info)); 1607c478bd9Sstevel@tonic-gate /* 1st try READ TRACK INFORMATION */ 1617c478bd9Sstevel@tonic-gate ti = (uchar_t *)my_zalloc(TRACK_INFO_SIZE); 1627c478bd9Sstevel@tonic-gate t_info->ti_track_no = trackno; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* Gererate faked information for writing to DVD */ 1657c478bd9Sstevel@tonic-gate if (device_type != CD_RW) { 1667c478bd9Sstevel@tonic-gate uint_t bsize; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate t_info->ti_flags = 0x3000; 1697c478bd9Sstevel@tonic-gate t_info->ti_track_no = 1; 1707c478bd9Sstevel@tonic-gate t_info->ti_session_no = 1; 1717c478bd9Sstevel@tonic-gate t_info->ti_track_mode = 0x4; 1727c478bd9Sstevel@tonic-gate t_info->ti_data_mode = 1; 1737c478bd9Sstevel@tonic-gate t_info->ti_start_address = 0; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* only 1 track on DVD make it max size */ 1767c478bd9Sstevel@tonic-gate t_info->ti_track_size = read_format_capacity(target->d_fd, 1777c478bd9Sstevel@tonic-gate &bsize); 1787c478bd9Sstevel@tonic-gate if (t_info->ti_track_size < MAX_CD_BLKS) { 1797c478bd9Sstevel@tonic-gate t_info->ti_track_size = MAX_DVD_BLKS; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate t_info->ti_nwa = 0; 1837c478bd9Sstevel@tonic-gate t_info->ti_lra = 0; 1847c478bd9Sstevel@tonic-gate t_info->ti_packet_size = 0x10; 1857c478bd9Sstevel@tonic-gate t_info->ti_free_blocks = 0; 1867c478bd9Sstevel@tonic-gate } 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate if (read_track_info(dev->d_fd, trackno, ti)) { 1897c478bd9Sstevel@tonic-gate 1907c478bd9Sstevel@tonic-gate if (debug) 1917c478bd9Sstevel@tonic-gate (void) printf("using read_track_info for TOC \n"); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate t_info->ti_track_no = ti[2]; 1947c478bd9Sstevel@tonic-gate t_info->ti_session_no = ti[3]; 1957c478bd9Sstevel@tonic-gate t_info->ti_flags = (ti[6] >> 4) & 0xf; 1967c478bd9Sstevel@tonic-gate t_info->ti_flags |= (uint32_t)(ti[5] & 0xf0); 1977c478bd9Sstevel@tonic-gate t_info->ti_flags |= (uint32_t)(ti[7]) << 8; 1987c478bd9Sstevel@tonic-gate t_info->ti_flags |= TI_SESSION_NO_VALID | TI_FREE_BLOCKS_VALID; 1997c478bd9Sstevel@tonic-gate t_info->ti_track_mode = ti[5] & 0xf; 2007c478bd9Sstevel@tonic-gate if ((ti[6] & 0xf) == 0xf) 2017c478bd9Sstevel@tonic-gate t_info->ti_data_mode = 0xff; 2027c478bd9Sstevel@tonic-gate else 2037c478bd9Sstevel@tonic-gate t_info->ti_data_mode = ti[6] & 0xf; 2047c478bd9Sstevel@tonic-gate t_info->ti_start_address = read_scsi32(&ti[8]); 2057c478bd9Sstevel@tonic-gate t_info->ti_nwa = read_scsi32(&ti[12]); 2067c478bd9Sstevel@tonic-gate t_info->ti_free_blocks = read_scsi32(&ti[16]); 2077c478bd9Sstevel@tonic-gate t_info->ti_packet_size = read_scsi32(&ti[20]); 2087c478bd9Sstevel@tonic-gate t_info->ti_track_size = read_scsi32(&ti[24]); 2097c478bd9Sstevel@tonic-gate t_info->ti_lra = read_scsi32(&ti[28]); 2107c478bd9Sstevel@tonic-gate free(ti); 2117c478bd9Sstevel@tonic-gate return (1); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate /* READ TRACK INFORMATION not supported, try other options */ 2147c478bd9Sstevel@tonic-gate free(ti); 2157c478bd9Sstevel@tonic-gate /* 2167c478bd9Sstevel@tonic-gate * We can get info for next blank track if READ TRACK INFO is not 2177c478bd9Sstevel@tonic-gate * supported. 2187c478bd9Sstevel@tonic-gate */ 2197c478bd9Sstevel@tonic-gate if (trackno == -1) 2207c478bd9Sstevel@tonic-gate return (0); 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate if (debug) 2237c478bd9Sstevel@tonic-gate (void) printf("using READ_TOC for TOC\n"); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* Try Read TOC */ 2267c478bd9Sstevel@tonic-gate if (!read_toc(dev->d_fd, 0, trackno, 20, toc)) { 2277c478bd9Sstevel@tonic-gate return (0); 2287c478bd9Sstevel@tonic-gate } 2297c478bd9Sstevel@tonic-gate t_info->ti_start_address = read_scsi32(&toc[8]); 2307c478bd9Sstevel@tonic-gate t_info->ti_track_mode = toc[5] & 0xf; 2317c478bd9Sstevel@tonic-gate t_info->ti_track_size = read_scsi32(&toc[16]) - read_scsi32(&toc[8]); 2327c478bd9Sstevel@tonic-gate t_info->ti_data_mode = get_data_mode(dev->d_fd, read_scsi32(&toc[8])); 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate /* Numbers for audio tracks are always in 2K chunks */ 2357c478bd9Sstevel@tonic-gate if ((dev->d_blksize == 512) && ((t_info->ti_track_mode & 4) == 0)) { 2367c478bd9Sstevel@tonic-gate t_info->ti_start_address /= 4; 2377c478bd9Sstevel@tonic-gate t_info->ti_track_size /= 4; 2387c478bd9Sstevel@tonic-gate } 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate /* Now find out the session thing */ 2417c478bd9Sstevel@tonic-gate ret = read_toc(dev->d_fd, 1, trackno, 12, toc); 2427c478bd9Sstevel@tonic-gate 2437c478bd9Sstevel@tonic-gate /* 2447c478bd9Sstevel@tonic-gate * Make sure that the call succeeds and returns the requested 2457c478bd9Sstevel@tonic-gate * TOC size correctly. 2467c478bd9Sstevel@tonic-gate */ 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate if ((ret == 0) || (toc[1] != 0x0a)) { 2497c478bd9Sstevel@tonic-gate 2507c478bd9Sstevel@tonic-gate /* For ATAPI drives or old Toshiba drives */ 2517c478bd9Sstevel@tonic-gate ret = read_toc_as_per_8020(dev->d_fd, 1, trackno, 12, toc); 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate /* If this goes through well TOC length will always be 0x0a */ 2547c478bd9Sstevel@tonic-gate if (ret && (toc[1] == 0x0a)) { 2557c478bd9Sstevel@tonic-gate if (trackno >= toc[6]) { 2567c478bd9Sstevel@tonic-gate t_info->ti_session_no = toc[3]; 2577c478bd9Sstevel@tonic-gate t_info->ti_flags |= TI_SESSION_NO_VALID; 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate /* 2607c478bd9Sstevel@tonic-gate * This might be the last track of this session. If so, 2617c478bd9Sstevel@tonic-gate * exclude the leadout and next lead in. 2627c478bd9Sstevel@tonic-gate */ 2637c478bd9Sstevel@tonic-gate if (trackno == (toc[6] - 1)) { 2647c478bd9Sstevel@tonic-gate /* 2657c478bd9Sstevel@tonic-gate * 1.5 Min leadout + 1 min. leadin + 2 sec. pre-gap. 2667c478bd9Sstevel@tonic-gate * For 2nd+ leadout it will be 0.5 min. But currently 2677c478bd9Sstevel@tonic-gate * there is no direct way. And it will not happen 2687c478bd9Sstevel@tonic-gate * for any normal case. 2697c478bd9Sstevel@tonic-gate * 2707c478bd9Sstevel@tonic-gate * 75 frames/sec, 60 sec/min, so leadin gap is 2717c478bd9Sstevel@tonic-gate * ((1.5 +1)*60 + 2)*75 = 11400 frames (blocks) 2727c478bd9Sstevel@tonic-gate */ 2737c478bd9Sstevel@tonic-gate t_info->ti_track_size -= 11400; 2747c478bd9Sstevel@tonic-gate } 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate return (1); 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate uchar_t 2807c478bd9Sstevel@tonic-gate get_data_mode(int fd, uint32_t lba) 2817c478bd9Sstevel@tonic-gate { 2827c478bd9Sstevel@tonic-gate int ret; 2837c478bd9Sstevel@tonic-gate uchar_t *buf; 2847c478bd9Sstevel@tonic-gate uchar_t mode; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate buf = (uchar_t *)my_zalloc(8); 2877c478bd9Sstevel@tonic-gate ret = read_header(fd, lba, buf); 2887c478bd9Sstevel@tonic-gate if (ret == 0) 2897c478bd9Sstevel@tonic-gate mode = 0xff; 2907c478bd9Sstevel@tonic-gate else 2917c478bd9Sstevel@tonic-gate mode = buf[0]; 2927c478bd9Sstevel@tonic-gate free(buf); 2937c478bd9Sstevel@tonic-gate return (mode); 2947c478bd9Sstevel@tonic-gate } 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Set page code 5 for TAO mode. 2987c478bd9Sstevel@tonic-gate */ 2997c478bd9Sstevel@tonic-gate int 3007c478bd9Sstevel@tonic-gate prepare_for_write(cd_device *dev, int track_mode, int test_write, 3017c478bd9Sstevel@tonic-gate int keep_disc_open) 3027c478bd9Sstevel@tonic-gate { 3037c478bd9Sstevel@tonic-gate uchar_t *buf; 3047c478bd9Sstevel@tonic-gate int no_err; 3057c478bd9Sstevel@tonic-gate int reset_device; 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if ((write_mode == DAO_MODE) && keep_disc_open) { 3087c478bd9Sstevel@tonic-gate (void) printf(gettext( 3097c478bd9Sstevel@tonic-gate "Multi-session is not supported on DVD media\n")); 3107c478bd9Sstevel@tonic-gate exit(1); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if ((write_mode == DAO_MODE) && debug) { 3147c478bd9Sstevel@tonic-gate (void) printf("Preparing to write in DAO\n"); 3157c478bd9Sstevel@tonic-gate } 3167c478bd9Sstevel@tonic-gate 3177c478bd9Sstevel@tonic-gate (void) start_stop(dev->d_fd, 1); 3187c478bd9Sstevel@tonic-gate /* Some drives do not support this command but still do it */ 3197c478bd9Sstevel@tonic-gate (void) rezero_unit(dev->d_fd); 3207c478bd9Sstevel@tonic-gate 3217c478bd9Sstevel@tonic-gate buf = (uchar_t *)my_zalloc(64); 3227c478bd9Sstevel@tonic-gate 3237c478bd9Sstevel@tonic-gate no_err = get_mode_page(dev->d_fd, 5, 0, 64, buf); 3247c478bd9Sstevel@tonic-gate if (no_err) 3257c478bd9Sstevel@tonic-gate no_err = ((buf[1] + 2) > 64) ? 0 : 1; 3267c478bd9Sstevel@tonic-gate /* 3277c478bd9Sstevel@tonic-gate * If the device is already in simulation mode and again a 3287c478bd9Sstevel@tonic-gate * simulation is requested, then set the device in non-simulation 3297c478bd9Sstevel@tonic-gate * 1st and then take it to simulation mode. This will flush any 3307c478bd9Sstevel@tonic-gate * previous fake state in the drive. 3317c478bd9Sstevel@tonic-gate */ 3327c478bd9Sstevel@tonic-gate if (no_err && test_write && (buf[2] & 0x10)) { 3337c478bd9Sstevel@tonic-gate reset_device = 1; 3347c478bd9Sstevel@tonic-gate } else { 3357c478bd9Sstevel@tonic-gate reset_device = 0; 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate if (no_err != 0) { 3387c478bd9Sstevel@tonic-gate buf[0] &= 0x3f; 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate /* set TAO or DAO writing mode */ 3417c478bd9Sstevel@tonic-gate buf[2] = (write_mode == TAO_MODE)?1:2; 3427c478bd9Sstevel@tonic-gate 3437c478bd9Sstevel@tonic-gate /* set simulation flag */ 3447c478bd9Sstevel@tonic-gate if (test_write && (!reset_device)) { 3457c478bd9Sstevel@tonic-gate buf[2] |= 0x10; 3467c478bd9Sstevel@tonic-gate } else { 3477c478bd9Sstevel@tonic-gate buf[2] &= ~0x10; 3487c478bd9Sstevel@tonic-gate } 3497c478bd9Sstevel@tonic-gate 3507c478bd9Sstevel@tonic-gate /* Turn on HW buffer underrun protection (BUFE) */ 3517c478bd9Sstevel@tonic-gate if (!test_write) { 3527c478bd9Sstevel@tonic-gate buf[2] |= 0x40; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate 3557c478bd9Sstevel@tonic-gate /* set track mode type */ 3567c478bd9Sstevel@tonic-gate if (device_type == CD_RW) { 3577c478bd9Sstevel@tonic-gate buf[3] = track_mode & 0x0f; /* ctrl nibble */ 3587c478bd9Sstevel@tonic-gate } else { 3597c478bd9Sstevel@tonic-gate buf[3] = 5; /* always 5 for DVD */ 3607c478bd9Sstevel@tonic-gate } 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate if (keep_disc_open) { 3637c478bd9Sstevel@tonic-gate buf[3] |= 0xc0; /* Allow more sessions */ 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate /* Select track type (audio or data) */ 3677c478bd9Sstevel@tonic-gate if (track_mode == TRACK_MODE_DATA) { 3687c478bd9Sstevel@tonic-gate buf[4] = 8; /* 2048 byte sector */ 3697c478bd9Sstevel@tonic-gate } else { 3707c478bd9Sstevel@tonic-gate buf[4] = 0; /* 2352 byte sector */ 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate buf[7] = buf[8] = 0; 3737c478bd9Sstevel@tonic-gate 3747c478bd9Sstevel@tonic-gate /* Need to clear these fields for setting into DAO */ 3757c478bd9Sstevel@tonic-gate if (write_mode == DAO_MODE) 3767c478bd9Sstevel@tonic-gate buf[5] = buf[15] = 0; 3777c478bd9Sstevel@tonic-gate 3787c478bd9Sstevel@tonic-gate /* print out mode for detailed log */ 3797c478bd9Sstevel@tonic-gate if (debug && verbose) { 3807c478bd9Sstevel@tonic-gate int i; 3817c478bd9Sstevel@tonic-gate 3827c478bd9Sstevel@tonic-gate (void) printf("setting = [ "); 3837c478bd9Sstevel@tonic-gate for (i = 0; i < 15; i++) 3847c478bd9Sstevel@tonic-gate (void) printf("0x%x ", buf[i]); 3857c478bd9Sstevel@tonic-gate (void) printf("]\n"); 3867c478bd9Sstevel@tonic-gate } 3877c478bd9Sstevel@tonic-gate 3887c478bd9Sstevel@tonic-gate no_err = set_mode_page(dev->d_fd, buf); 3897c478bd9Sstevel@tonic-gate 3907c478bd9Sstevel@tonic-gate if (no_err && reset_device) { 3917c478bd9Sstevel@tonic-gate /* Turn the test write bit back on */ 3927c478bd9Sstevel@tonic-gate buf[2] |= 0x10; 3937c478bd9Sstevel@tonic-gate no_err = set_mode_page(dev->d_fd, buf); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * Since BUFE is the only optional flag we are 3987c478bd9Sstevel@tonic-gate * setting we will try to turn it off if the command 3997c478bd9Sstevel@tonic-gate * fails. 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate if (!no_err) { 4027c478bd9Sstevel@tonic-gate /* 4037c478bd9Sstevel@tonic-gate * Some old drives may not support HW 4047c478bd9Sstevel@tonic-gate * buffer underrun protection, try again 4057c478bd9Sstevel@tonic-gate * after turning it off. 4067c478bd9Sstevel@tonic-gate */ 4077c478bd9Sstevel@tonic-gate if (debug) 4087c478bd9Sstevel@tonic-gate (void) printf("Turning off BUFE\n"); 4097c478bd9Sstevel@tonic-gate buf[2] &= ~0x40; 4107c478bd9Sstevel@tonic-gate no_err = set_mode_page(dev->d_fd, buf); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate } 4137c478bd9Sstevel@tonic-gate 4147c478bd9Sstevel@tonic-gate free(buf); 4157c478bd9Sstevel@tonic-gate return (no_err); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Close session. This will write TOC. 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate int 4227c478bd9Sstevel@tonic-gate finalize(cd_device *dev) 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate uchar_t *di; 4257c478bd9Sstevel@tonic-gate int count, ret, err; 4267c478bd9Sstevel@tonic-gate int immediate; 4277c478bd9Sstevel@tonic-gate int finalize_max; 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate /* 4307c478bd9Sstevel@tonic-gate * For ATAPI devices we will use the immediate mode and will 4317c478bd9Sstevel@tonic-gate * poll the command for completion so that this command may 4327c478bd9Sstevel@tonic-gate * not hog the channel. But for SCSI, we will use the treditional 4337c478bd9Sstevel@tonic-gate * way of issuing the command with a large enough timeout. This 4347c478bd9Sstevel@tonic-gate * is done because immediate mode was designed for ATAPI and some 4357c478bd9Sstevel@tonic-gate * SCSI RW drives might not be even tested with it. 4367c478bd9Sstevel@tonic-gate */ 4377c478bd9Sstevel@tonic-gate if ((dev->d_inq[2] & 7) != 0) { 4387c478bd9Sstevel@tonic-gate /* SCSI device */ 4397c478bd9Sstevel@tonic-gate immediate = 0; 4407c478bd9Sstevel@tonic-gate } else { 4417c478bd9Sstevel@tonic-gate /* non-SCSI (e.g ATAPI) device */ 4427c478bd9Sstevel@tonic-gate immediate = 1; 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate /* We need to close track before close session */ 4467c478bd9Sstevel@tonic-gate if (device_type == DVD_PLUS) { 4477c478bd9Sstevel@tonic-gate if (!close_track(dev->d_fd, 0, 0, immediate)) 4487c478bd9Sstevel@tonic-gate return (0); 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate if (!close_track(dev->d_fd, 0, 1, immediate)) { 4527c478bd9Sstevel@tonic-gate /* 4537c478bd9Sstevel@tonic-gate * For DVD-RW close track is not well defined 4547c478bd9Sstevel@tonic-gate * some drives dont like it, others want us 4557c478bd9Sstevel@tonic-gate * to close track before closing the session. 4567c478bd9Sstevel@tonic-gate * NOTE that for MMC specification it is not mandatory 4577c478bd9Sstevel@tonic-gate * to support close track. 4587c478bd9Sstevel@tonic-gate */ 4597c478bd9Sstevel@tonic-gate if (device_type == DVD_MINUS) { 4607c478bd9Sstevel@tonic-gate if (!close_track(dev->d_fd, 1, 0, immediate)) { 4617c478bd9Sstevel@tonic-gate return (0); 4627c478bd9Sstevel@tonic-gate } else { 4637c478bd9Sstevel@tonic-gate /* command is already done */ 4647c478bd9Sstevel@tonic-gate if (!immediate) 4657c478bd9Sstevel@tonic-gate return (1); 4667c478bd9Sstevel@tonic-gate } 4677c478bd9Sstevel@tonic-gate } else { 4687c478bd9Sstevel@tonic-gate return (0); 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate } else { 4717c478bd9Sstevel@tonic-gate if (!immediate) 4727c478bd9Sstevel@tonic-gate return (1); 4737c478bd9Sstevel@tonic-gate } 4747c478bd9Sstevel@tonic-gate if (immediate) { 4757c478bd9Sstevel@tonic-gate (void) sleep(10); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); 4787c478bd9Sstevel@tonic-gate err = 0; 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate if (device_type == CD_RW) { 4817c478bd9Sstevel@tonic-gate /* Finalization should not take more than 6 minutes */ 4827c478bd9Sstevel@tonic-gate finalize_max = FINALIZE_TIMEOUT; 4837c478bd9Sstevel@tonic-gate } else { 4847c478bd9Sstevel@tonic-gate /* some DVD-RW drives take longer than 6 minutes */ 4857c478bd9Sstevel@tonic-gate finalize_max = FINALIZE_TIMEOUT*2; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate for (count = 0; count < finalize_max; count++) { 4897c478bd9Sstevel@tonic-gate ret = read_disc_info(dev->d_fd, di); 4907c478bd9Sstevel@tonic-gate if (ret != 0) 4917c478bd9Sstevel@tonic-gate break; 4927c478bd9Sstevel@tonic-gate if (uscsi_status != 2) 4937c478bd9Sstevel@tonic-gate err = 1; 4947c478bd9Sstevel@tonic-gate if (SENSE_KEY(rqbuf) == 2) { 4957c478bd9Sstevel@tonic-gate /* not ready but not becoming ready */ 4967c478bd9Sstevel@tonic-gate if (ASC(rqbuf) != 4) 4977c478bd9Sstevel@tonic-gate err = 1; 4987c478bd9Sstevel@tonic-gate } else if (SENSE_KEY(rqbuf) == 5) { 4997c478bd9Sstevel@tonic-gate /* illegal mode for this track */ 5007c478bd9Sstevel@tonic-gate if (ASC(rqbuf) != 0x64) 5017c478bd9Sstevel@tonic-gate err = 1; 5027c478bd9Sstevel@tonic-gate } else { 5037c478bd9Sstevel@tonic-gate err = 1; 5047c478bd9Sstevel@tonic-gate } 5057c478bd9Sstevel@tonic-gate if (err == 1) { 5067c478bd9Sstevel@tonic-gate if (debug) { 5077c478bd9Sstevel@tonic-gate (void) printf("Finalization failed\n"); 5087c478bd9Sstevel@tonic-gate (void) printf("%x %x %x %x\n", 5097c478bd9Sstevel@tonic-gate uscsi_status, SENSE_KEY(rqbuf), 5107c478bd9Sstevel@tonic-gate ASC(rqbuf), ASCQ(rqbuf)); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate free(di); 5137c478bd9Sstevel@tonic-gate return (0); 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate if (uscsi_status == 2) { 5167c478bd9Sstevel@tonic-gate int i; 5177c478bd9Sstevel@tonic-gate /* illegal field in command packet */ 5187c478bd9Sstevel@tonic-gate if (ASC(rqbuf) == 0x24) { 5197c478bd9Sstevel@tonic-gate /* print it out! */ 5207c478bd9Sstevel@tonic-gate (void) printf("\n"); 5217c478bd9Sstevel@tonic-gate for (i = 0; i < 18; i++) 5227c478bd9Sstevel@tonic-gate (void) printf("%x ", 5237c478bd9Sstevel@tonic-gate (unsigned)(rqbuf[i])); 5247c478bd9Sstevel@tonic-gate (void) printf("\n"); 5257c478bd9Sstevel@tonic-gate } 5267c478bd9Sstevel@tonic-gate } 5277c478bd9Sstevel@tonic-gate (void) sleep(5); 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate free(di); 5307c478bd9Sstevel@tonic-gate } 5317c478bd9Sstevel@tonic-gate return (ret); 5327c478bd9Sstevel@tonic-gate } 5337c478bd9Sstevel@tonic-gate 5347c478bd9Sstevel@tonic-gate /* 5357c478bd9Sstevel@tonic-gate * Find out media capacity. 5367c478bd9Sstevel@tonic-gate */ 5377c478bd9Sstevel@tonic-gate int 5387c478bd9Sstevel@tonic-gate get_last_possible_lba(cd_device *dev) 5397c478bd9Sstevel@tonic-gate { 5407c478bd9Sstevel@tonic-gate uchar_t *di; 5417c478bd9Sstevel@tonic-gate int cap; 5427c478bd9Sstevel@tonic-gate 5437c478bd9Sstevel@tonic-gate di = (uchar_t *)my_zalloc(DISC_INFO_BLOCK_SIZE); 5447c478bd9Sstevel@tonic-gate if (!read_disc_info(dev->d_fd, di)) { 5457c478bd9Sstevel@tonic-gate free(di); 5467c478bd9Sstevel@tonic-gate return (0); 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate if ((di[21] != 0) && (di[21] != 0xff)) { 5497c478bd9Sstevel@tonic-gate cap = ((di[21] * 60) + di[22]) * 75; 5507c478bd9Sstevel@tonic-gate } else { 5517c478bd9Sstevel@tonic-gate cap = 0; 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate 5547c478bd9Sstevel@tonic-gate free(di); 5557c478bd9Sstevel@tonic-gate return (cap); 5567c478bd9Sstevel@tonic-gate } 5577c478bd9Sstevel@tonic-gate 5587c478bd9Sstevel@tonic-gate int 5597c478bd9Sstevel@tonic-gate read_audio_through_read_cd(cd_device *dev, uint_t start_lba, uint_t nblks, 5607c478bd9Sstevel@tonic-gate uchar_t *buf) 5617c478bd9Sstevel@tonic-gate { 5627c478bd9Sstevel@tonic-gate int retry; 5637c478bd9Sstevel@tonic-gate int ret; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate for (retry = 0; retry < 3; retry++) { 5667c478bd9Sstevel@tonic-gate ret = read_cd(dev->d_fd, (uint32_t)start_lba, (uint16_t)nblks, 5677c478bd9Sstevel@tonic-gate 1, buf, (uint32_t)(nblks * 2352)); 5687c478bd9Sstevel@tonic-gate if (ret) 5697c478bd9Sstevel@tonic-gate break; 5707c478bd9Sstevel@tonic-gate } 5717c478bd9Sstevel@tonic-gate return (ret); 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate 5747c478bd9Sstevel@tonic-gate int 5757c478bd9Sstevel@tonic-gate eject_media(cd_device *dev) 5767c478bd9Sstevel@tonic-gate { 5777c478bd9Sstevel@tonic-gate if (vol_running) { 5787c478bd9Sstevel@tonic-gate /* If there is a media, try using DKIOCEJECT 1st */ 5797c478bd9Sstevel@tonic-gate if (check_device(dev, CHECK_NO_MEDIA) == 0) { 5807c478bd9Sstevel@tonic-gate if (ioctl(dev->d_fd, DKIOCEJECT, 0) == 0) { 5817c478bd9Sstevel@tonic-gate return (1); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate } 5857c478bd9Sstevel@tonic-gate if (load_unload(dev->d_fd, 0) == 0) { 5867c478bd9Sstevel@tonic-gate /* if eject fails */ 5877c478bd9Sstevel@tonic-gate if ((uscsi_status == 2) && (ASC(rqbuf) == 0x53)) { 5887c478bd9Sstevel@tonic-gate /* 5897c478bd9Sstevel@tonic-gate * check that eject is not blocked on the device 5907c478bd9Sstevel@tonic-gate */ 5917c478bd9Sstevel@tonic-gate if (!prevent_allow_mr(dev->d_fd, 1)) 5927c478bd9Sstevel@tonic-gate return (0); 5937c478bd9Sstevel@tonic-gate return (load_unload(dev->d_fd, 0)); 5947c478bd9Sstevel@tonic-gate } 5957c478bd9Sstevel@tonic-gate return (0); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate return (1); 5987c478bd9Sstevel@tonic-gate } 5997c478bd9Sstevel@tonic-gate 6007c478bd9Sstevel@tonic-gate /* 601*98584592Sarutz * Get current Read or Write Speed from Mode Page 0x2a. 602*98584592Sarutz * 603*98584592Sarutz * Use the size of the Page to determine which Multimedia Command 604*98584592Sarutz * set (MMC) is present. Based on the MMC version, get the 605*98584592Sarutz * specified Read/Write Speed. 606*98584592Sarutz * 607*98584592Sarutz * Note that some MMC versions do not necessarily support a 608*98584592Sarutz * (current) Read or Write Speed. As a result, this function 609*98584592Sarutz * _can_ return a value of zero. 610*98584592Sarutz * 611*98584592Sarutz * The newer standards (reserve and) mark the field(s) as Obsolete, 612*98584592Sarutz * yet many vendors populate the Obsolete fields with valid values 613*98584592Sarutz * (assumedly for backward compatibility). This is important, as 614*98584592Sarutz * a command like GET PERFORMANCE cannot return _the_ speed; it can 615*98584592Sarutz * only return a Logical-Block-Address-dependent (LBA) speed. Such 616*98584592Sarutz * values can vary widely between the innermost and outermost Track. 617*98584592Sarutz * Mode Page 0x2a is the best solution identifying "the current 618*98584592Sarutz * (nominal) speed". 6197c478bd9Sstevel@tonic-gate */ 6207c478bd9Sstevel@tonic-gate static uint16_t 621*98584592Sarutz cd_speed_get(cd_device *dev, int cmd) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate uchar_t *mp2a; 624*98584592Sarutz uint16_t rate = 0; 625*98584592Sarutz int offset; 626*98584592Sarutz uint_t buflen = 254; 6277c478bd9Sstevel@tonic-gate 628*98584592Sarutz /* 629*98584592Sarutz * Allocate a buffer acceptably larger than any nominal 630*98584592Sarutz * Page for Page Code 0x2A. 631*98584592Sarutz */ 632*98584592Sarutz mp2a = (uchar_t *)my_zalloc(buflen); 633*98584592Sarutz if (get_mode_page(dev->d_fd, 0x2A, 0, buflen, mp2a) == 0) 634*98584592Sarutz goto end; 635*98584592Sarutz 636*98584592Sarutz /* Determine MMC version based on 'Page Length' field */ 637*98584592Sarutz switch (mp2a[1]) { 638*98584592Sarutz case 0x14: /* MMC-1 */ 639*98584592Sarutz if (debug) 640*98584592Sarutz (void) printf("Mode Page 2A: MMC-1\n"); 641*98584592Sarutz 642*98584592Sarutz offset = (cmd == GET_READ_SPEED) ? 14 : 20; 643*98584592Sarutz rate = read_scsi16(&mp2a[offset]); 644*98584592Sarutz break; 645*98584592Sarutz 646*98584592Sarutz 647*98584592Sarutz case 0x18: /* MMC-2 */ 648*98584592Sarutz if (debug) 649*98584592Sarutz (void) printf("Mode Page 2A: MMC-2;" 650*98584592Sarutz " Read and Write Speeds are " 651*98584592Sarutz "obsolete\n"); 652*98584592Sarutz 653*98584592Sarutz /* see if "Obsolete" values are valid: */ 654*98584592Sarutz offset = (cmd == GET_READ_SPEED) ? 14 : 20; 655*98584592Sarutz rate = read_scsi16(&mp2a[offset]); 656*98584592Sarutz break; 657*98584592Sarutz 658*98584592Sarutz default: /* MMC-3 or newer */ 659*98584592Sarutz if (debug) 660*98584592Sarutz (void) printf("Mode Page 2A: MMC-3 or" 661*98584592Sarutz " newer; Read Speed is obsolete.\n"); 662*98584592Sarutz 6637c478bd9Sstevel@tonic-gate if (cmd == GET_READ_SPEED) { 664*98584592Sarutz /* this is Obsolete, but try it */ 665*98584592Sarutz offset = 14; 666*98584592Sarutz rate = read_scsi16(&mp2a[offset]); 6677c478bd9Sstevel@tonic-gate } else { 668*98584592Sarutz /* Write Speed is not obsolete */ 669*98584592Sarutz offset = 28; 670*98584592Sarutz rate = read_scsi16(&mp2a[offset]); 671*98584592Sarutz 672*98584592Sarutz if (rate == 0) { 673*98584592Sarutz /* 674*98584592Sarutz * then try an Obsolete field 675*98584592Sarutz * (but this shouldn't happen!) 676*98584592Sarutz */ 677*98584592Sarutz offset = 20; 678*98584592Sarutz rate = read_scsi16(&mp2a[offset]); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate } 681*98584592Sarutz break; 682*98584592Sarutz } 683*98584592Sarutz end: 6847c478bd9Sstevel@tonic-gate free(mp2a); 685*98584592Sarutz 686*98584592Sarutz if (debug) 687*98584592Sarutz (void) printf("cd_speed_get: %s Speed is " 688*98584592Sarutz "%uX\n", (cmd == GET_READ_SPEED) ? 689*98584592Sarutz "Read" : "Write", cdrw_bandwidth_to_x(rate)); 6907c478bd9Sstevel@tonic-gate return (rate); 6917c478bd9Sstevel@tonic-gate } 6927c478bd9Sstevel@tonic-gate 6937c478bd9Sstevel@tonic-gate /* 6947c478bd9Sstevel@tonic-gate * CD speed related functions (ioctl style) for drives which do not support 6957c478bd9Sstevel@tonic-gate * real time streaming. 696*98584592Sarutz * 697*98584592Sarutz * For the SET operations, the SET CD SPEED command needs 698*98584592Sarutz * both the Read Speed and the Write Speed. Eg, if 699*98584592Sarutz * we're trying to set the Write Speed (SET_WRITE_SPEED), 700*98584592Sarutz * then we first need to obtain the current Read Speed. 701*98584592Sarutz * That speed is specified along with the chosen_speed (the 702*98584592Sarutz * Write Speed in this case) in the SET CD SPEED command. 7037c478bd9Sstevel@tonic-gate */ 7047c478bd9Sstevel@tonic-gate int 7057c478bd9Sstevel@tonic-gate cd_speed_ctrl(cd_device *dev, int cmd, int speed) 7067c478bd9Sstevel@tonic-gate { 7077c478bd9Sstevel@tonic-gate uint16_t rate; 7087c478bd9Sstevel@tonic-gate 709*98584592Sarutz switch (cmd) { 710*98584592Sarutz case GET_READ_SPEED: 711*98584592Sarutz rate = cd_speed_get(dev, GET_READ_SPEED); 712*98584592Sarutz return (cdrw_bandwidth_to_x(rate)); 713*98584592Sarutz 714*98584592Sarutz case GET_WRITE_SPEED: 715*98584592Sarutz rate = cd_speed_get(dev, GET_WRITE_SPEED); 716*98584592Sarutz return (cdrw_bandwidth_to_x(rate)); 717*98584592Sarutz 718*98584592Sarutz case SET_READ_SPEED: 719*98584592Sarutz rate = cd_speed_get(dev, GET_WRITE_SPEED); 720*98584592Sarutz return (set_cd_speed(dev->d_fd, 721*98584592Sarutz cdrw_x_to_bandwidth(speed), rate)); 722*98584592Sarutz break; 723*98584592Sarutz 724*98584592Sarutz case SET_WRITE_SPEED: 725*98584592Sarutz rate = cd_speed_get(dev, GET_READ_SPEED); 7267c478bd9Sstevel@tonic-gate return (set_cd_speed(dev->d_fd, rate, 727*98584592Sarutz cdrw_x_to_bandwidth(speed))); 728*98584592Sarutz break; 729*98584592Sarutz 730*98584592Sarutz default: 7317c478bd9Sstevel@tonic-gate return (0); 7327c478bd9Sstevel@tonic-gate } 733*98584592Sarutz } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* 736*98584592Sarutz * Manage sending of SET STREAMING command using the specified 737*98584592Sarutz * read_speed and write_speed. 738*98584592Sarutz * 739*98584592Sarutz * This function allocates and initializes a Performance 740*98584592Sarutz * Descriptor, which is sent as part of the SET STREAMING 741*98584592Sarutz * command. The descriptor is deallocated before function 742*98584592Sarutz * exit. 743*98584592Sarutz */ 744*98584592Sarutz static int 745*98584592Sarutz do_set_streaming(cd_device *dev, uint_t read_speed, 746*98584592Sarutz uint_t write_speed) 747*98584592Sarutz { 748*98584592Sarutz int ret; 749*98584592Sarutz uchar_t *str; 750*98584592Sarutz 751*98584592Sarutz /* Allocate and initialize the Performance Descriptor */ 752*98584592Sarutz str = (uchar_t *)my_zalloc(SET_STREAM_DATA_LEN); 753*98584592Sarutz 754*98584592Sarutz /* Read Time (in milliseconds) */ 755*98584592Sarutz load_scsi32(&str[16], 1000); 756*98584592Sarutz /* Write Time (in milliseconds) */ 757*98584592Sarutz load_scsi32(&str[24], 1000); 758*98584592Sarutz 759*98584592Sarutz /* Read Speed */ 760*98584592Sarutz load_scsi32(&str[12], (uint32_t)read_speed); 761*98584592Sarutz /* Write Speed */ 762*98584592Sarutz load_scsi32(&str[20], (uint32_t)write_speed); 763*98584592Sarutz 764*98584592Sarutz /* issue SET STREAMING command */ 765*98584592Sarutz ret = set_streaming(dev->d_fd, str); 766*98584592Sarutz free(str); 767*98584592Sarutz 768*98584592Sarutz return (ret); 769*98584592Sarutz } 770*98584592Sarutz 771*98584592Sarutz /* 772*98584592Sarutz * cd speed related functions for drives which support 773*98584592Sarutz * Real-Time Streaming Feature. 774*98584592Sarutz * 775*98584592Sarutz * For the SET operations, the SET STREAMING command needs 776*98584592Sarutz * both the Read Speed and the Write Speed. Eg, if 777*98584592Sarutz * we're trying to set the Write Speed (SET_WRITE_SPEED), 778*98584592Sarutz * then we first need to obtain the current Read Speed. 779*98584592Sarutz * That speed is specified along with the chosen_speed (the 780*98584592Sarutz * Write Speed in this case) in the SET STREAMING command. 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate int 7837c478bd9Sstevel@tonic-gate rt_streaming_ctrl(cd_device *dev, int cmd, int speed) 7847c478bd9Sstevel@tonic-gate { 785*98584592Sarutz int ret = 0; 786*98584592Sarutz uint_t rate; 7877c478bd9Sstevel@tonic-gate 788*98584592Sarutz switch (cmd) { 789*98584592Sarutz case GET_WRITE_SPEED: 790*98584592Sarutz rate = cd_speed_get(dev, GET_WRITE_SPEED); 791*98584592Sarutz ret = (int)cdrw_bandwidth_to_x(rate); 792*98584592Sarutz break; 793*98584592Sarutz 794*98584592Sarutz case GET_READ_SPEED: 795*98584592Sarutz rate = cd_speed_get(dev, GET_READ_SPEED); 796*98584592Sarutz ret = (int)cdrw_bandwidth_to_x(rate); 797*98584592Sarutz break; 798*98584592Sarutz 799*98584592Sarutz case SET_READ_SPEED: { 800*98584592Sarutz uint_t write_speed = cd_speed_get(dev, GET_WRITE_SPEED); 801*98584592Sarutz 802*98584592Sarutz /* set Read Speed using SET STREAMING */ 803*98584592Sarutz ret = do_set_streaming(dev, 804*98584592Sarutz cdrw_x_to_bandwidth(speed), write_speed); 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate /* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */ 8077c478bd9Sstevel@tonic-gate if (ret == 0) { 8087c478bd9Sstevel@tonic-gate if (debug) 8097c478bd9Sstevel@tonic-gate (void) printf(" real time speed control" 8107c478bd9Sstevel@tonic-gate " failed, using CD speed control\n"); 8117c478bd9Sstevel@tonic-gate 8127c478bd9Sstevel@tonic-gate dev->d_speed_ctrl = cd_speed_ctrl; 8137c478bd9Sstevel@tonic-gate ret = dev->d_speed_ctrl(dev, cmd, speed); 8147c478bd9Sstevel@tonic-gate } 815*98584592Sarutz break; 816*98584592Sarutz } 8177c478bd9Sstevel@tonic-gate 818*98584592Sarutz case SET_WRITE_SPEED: { 819*98584592Sarutz uint_t read_speed = cd_speed_get(dev, GET_READ_SPEED); 820*98584592Sarutz 821*98584592Sarutz /* set Write Speed using SET STREAMING */ 822*98584592Sarutz ret = do_set_streaming(dev, read_speed, 823*98584592Sarutz cdrw_x_to_bandwidth(speed)); 824*98584592Sarutz 825*98584592Sarutz /* If rt_speed_ctrl fails for any reason use cd_speed_ctrl */ 826*98584592Sarutz if (ret == 0) { 827*98584592Sarutz if (debug) 828*98584592Sarutz (void) printf(" real time speed control" 829*98584592Sarutz " failed, using CD speed control\n"); 830*98584592Sarutz 831*98584592Sarutz dev->d_speed_ctrl = cd_speed_ctrl; 832*98584592Sarutz ret = dev->d_speed_ctrl(dev, cmd, speed); 833*98584592Sarutz } 834*98584592Sarutz break; 835*98584592Sarutz } 836*98584592Sarutz 837*98584592Sarutz default: 838*98584592Sarutz break; 839*98584592Sarutz } 840*98584592Sarutz 8417c478bd9Sstevel@tonic-gate return (ret); 8427c478bd9Sstevel@tonic-gate } 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate /* 8457c478bd9Sstevel@tonic-gate * Initialize device for track-at-once mode of writing. All of the data will 8467c478bd9Sstevel@tonic-gate * need to be written to the track without interruption. 8477c478bd9Sstevel@tonic-gate * This initialized TAO by setting page code 5 and speed. 8487c478bd9Sstevel@tonic-gate */ 8497c478bd9Sstevel@tonic-gate void 8507c478bd9Sstevel@tonic-gate write_init(int mode) 8517c478bd9Sstevel@tonic-gate { 8527c478bd9Sstevel@tonic-gate (void) printf(gettext("Initializing device")); 8537c478bd9Sstevel@tonic-gate if (simulation) 8547c478bd9Sstevel@tonic-gate (void) printf(gettext("(Simulation mode)")); 8557c478bd9Sstevel@tonic-gate print_n_flush("..."); 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate get_media_type(target->d_fd); 8587c478bd9Sstevel@tonic-gate 8597c478bd9Sstevel@tonic-gate /* DVD- requires DAO mode */ 8607c478bd9Sstevel@tonic-gate if (device_type == DVD_MINUS) { 8617c478bd9Sstevel@tonic-gate write_mode = DAO_MODE; 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /* For debug, print out device config information */ 8657c478bd9Sstevel@tonic-gate if (debug) { 8667c478bd9Sstevel@tonic-gate int i; 8677c478bd9Sstevel@tonic-gate uchar_t cap[80]; 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate if (get_configuration(target->d_fd, 0, 80, cap)) 8707c478bd9Sstevel@tonic-gate (void) printf("Drive profile = "); 8717c478bd9Sstevel@tonic-gate for (i = 10; i < 70; i += 8) 8727c478bd9Sstevel@tonic-gate (void) printf(" 0x%x", cap[i]); 8737c478bd9Sstevel@tonic-gate (void) printf("\n"); 8747c478bd9Sstevel@tonic-gate } 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate /* DVD+ and DVD- have no support for AUDIO, bail out */ 8777c478bd9Sstevel@tonic-gate if ((mode == TRACK_MODE_AUDIO) && (device_type != CD_RW)) { 8787c478bd9Sstevel@tonic-gate err_msg(gettext("Audio mode is only supported for CD media\n")); 8797c478bd9Sstevel@tonic-gate exit(1); 8807c478bd9Sstevel@tonic-gate } 881a2b4fdf6Srameshc if (simulation && 882a2b4fdf6Srameshc check_device(target, CHECK_MEDIA_IS_NOT_BLANK) && 883a2b4fdf6Srameshc !check_device(target, CHECK_MEDIA_IS_NOT_ERASABLE) && 884a2b4fdf6Srameshc device_type != DVD_PLUS_W) { 885a2b4fdf6Srameshc /* 886a2b4fdf6Srameshc * If we were in simulation mode, and media wasn't blank, 887a2b4fdf6Srameshc * but medium was erasable, then cdrw goes to erase the 888a2b4fdf6Srameshc * contents of the media after the simulation writing in order 889a2b4fdf6Srameshc * to cleanup the ghost TOC (see write_fini() calls blank()). 890a2b4fdf6Srameshc * This is bad because it removes existing data if media was 891a2b4fdf6Srameshc * multi-session. Therefore, we no longer allow simulation 892a2b4fdf6Srameshc * writing if such condition is met. we don't blank the DVD+RW 893a2b4fdf6Srameshc * media, so DVD+RWs are fine. 894a2b4fdf6Srameshc */ 895a2b4fdf6Srameshc err_msg(gettext( 896a2b4fdf6Srameshc "Cannot perform simulation for non-blank media\n")); 897a2b4fdf6Srameshc exit(1); 898a2b4fdf6Srameshc } 8997c478bd9Sstevel@tonic-gate 9007c478bd9Sstevel@tonic-gate if (!prepare_for_write(target, mode, simulation, keep_disc_open)) { 9017c478bd9Sstevel@tonic-gate /* l10n_NOTE : 'failed' as in Initializing device...failed */ 9027c478bd9Sstevel@tonic-gate (void) printf(gettext("failed.\n")); 9037c478bd9Sstevel@tonic-gate err_msg(gettext("Cannot initialize device for write\n")); 9047c478bd9Sstevel@tonic-gate exit(1); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate /* l10n_NOTE : 'done' as in "Initializing device...done" */ 9077c478bd9Sstevel@tonic-gate (void) printf(gettext("done.\n")); 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate /* if speed change option was used (-p) then try to set the speed */ 9107c478bd9Sstevel@tonic-gate if (requested_speed != 0) { 9117c478bd9Sstevel@tonic-gate if (verbose) 9127c478bd9Sstevel@tonic-gate (void) printf(gettext("Trying to set speed to %dX.\n"), 9137c478bd9Sstevel@tonic-gate requested_speed); 9147c478bd9Sstevel@tonic-gate if (target->d_speed_ctrl(target, SET_WRITE_SPEED, 9157c478bd9Sstevel@tonic-gate requested_speed) == 0) { 9167c478bd9Sstevel@tonic-gate err_msg(gettext("Unable to set speed.\n")); 9177c478bd9Sstevel@tonic-gate exit(1); 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate if (verbose) { 9207c478bd9Sstevel@tonic-gate int speed; 9217c478bd9Sstevel@tonic-gate speed = target->d_speed_ctrl(target, 9227c478bd9Sstevel@tonic-gate GET_WRITE_SPEED, 0); 9237c478bd9Sstevel@tonic-gate if (speed == requested_speed) { 9247c478bd9Sstevel@tonic-gate (void) printf(gettext("Speed set to %dX.\n"), 9257c478bd9Sstevel@tonic-gate speed); 926*98584592Sarutz } else if (speed == 0) { 927*98584592Sarutz (void) printf(gettext("Could not obtain " 928*98584592Sarutz "current Write Speed.\n")); 9297c478bd9Sstevel@tonic-gate } else { 9307c478bd9Sstevel@tonic-gate (void) printf( 9317c478bd9Sstevel@tonic-gate gettext("Speed set to closest approximation " 9327c478bd9Sstevel@tonic-gate "of %dX allowed by device (%dX).\n"), 9337c478bd9Sstevel@tonic-gate requested_speed, speed); 9347c478bd9Sstevel@tonic-gate } 9357c478bd9Sstevel@tonic-gate } 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate void 9407c478bd9Sstevel@tonic-gate write_fini(void) 9417c478bd9Sstevel@tonic-gate { 9427c478bd9Sstevel@tonic-gate print_n_flush(gettext("Finalizing (Can take several minutes)...")); 9437c478bd9Sstevel@tonic-gate /* Some drives don't like this while in test write mode */ 9447c478bd9Sstevel@tonic-gate if (!simulation) { 9457c478bd9Sstevel@tonic-gate if (!finalize(target)) { 9467c478bd9Sstevel@tonic-gate /* 9477c478bd9Sstevel@tonic-gate * It is possible that the drive is busy writing the 9487c478bd9Sstevel@tonic-gate * buffered portion. So do not get upset yet. 9497c478bd9Sstevel@tonic-gate */ 9507c478bd9Sstevel@tonic-gate (void) sleep(10); 9517c478bd9Sstevel@tonic-gate if (!finalize(target)) { 9527c478bd9Sstevel@tonic-gate if (debug) { 9537c478bd9Sstevel@tonic-gate (void) printf("status %x, %x/%x/%x\n", 9547c478bd9Sstevel@tonic-gate uscsi_status, SENSE_KEY(rqbuf), 9557c478bd9Sstevel@tonic-gate ASC(rqbuf), ASCQ(rqbuf)); 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if ((device_type == DVD_MINUS) && 9597c478bd9Sstevel@tonic-gate (SENSE_KEY(rqbuf) == 5)) { 9607c478bd9Sstevel@tonic-gate 9617c478bd9Sstevel@tonic-gate if (verbose) { 9627c478bd9Sstevel@tonic-gate (void) printf( 9637c478bd9Sstevel@tonic-gate "skipping finalizing\n"); 9647c478bd9Sstevel@tonic-gate } 9657c478bd9Sstevel@tonic-gate } else { 9667c478bd9Sstevel@tonic-gate 9677c478bd9Sstevel@tonic-gate /* l10n_NOTE : 'failed' as in finishing up...failed */ 9687c478bd9Sstevel@tonic-gate (void) printf(gettext("failed.\n")); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate err_msg(gettext( 9717c478bd9Sstevel@tonic-gate "Could not finalize the disc.\n")); 9727c478bd9Sstevel@tonic-gate exit(1); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate } 9787c478bd9Sstevel@tonic-gate if (vol_running) { 9797c478bd9Sstevel@tonic-gate (void) eject_media(target); 9807c478bd9Sstevel@tonic-gate } 9817c478bd9Sstevel@tonic-gate } else if (check_device(target, CHECK_MEDIA_IS_NOT_BLANK)) { 9827c478bd9Sstevel@tonic-gate /* 9837c478bd9Sstevel@tonic-gate * Some drives such as the pioneer A04 will retain a 9847c478bd9Sstevel@tonic-gate * ghost TOC after a simulation write is done. The 9857c478bd9Sstevel@tonic-gate * media will actually be blank, but the drive will 9867c478bd9Sstevel@tonic-gate * report a TOC. There is currently no other way to 9877c478bd9Sstevel@tonic-gate * re-initialize the media other than ejecting or 9887c478bd9Sstevel@tonic-gate * to ask the drive to clear the leadout. The laser 9897c478bd9Sstevel@tonic-gate * is currently off so nothing is written to the 9907c478bd9Sstevel@tonic-gate * media (on a good behaving drive). 9917c478bd9Sstevel@tonic-gate * NOTE that a device reset does not work to make 9927c478bd9Sstevel@tonic-gate * the drive re-initialize the media. 9937c478bd9Sstevel@tonic-gate */ 9947c478bd9Sstevel@tonic-gate 995a2b4fdf6Srameshc blanking_type = "clear_ghost"; 9967c478bd9Sstevel@tonic-gate blank(); 9977c478bd9Sstevel@tonic-gate 9987c478bd9Sstevel@tonic-gate } 9997c478bd9Sstevel@tonic-gate /* l10n_NOTE : 'done' as in "Finishing up...done" */ 10007c478bd9Sstevel@tonic-gate (void) printf(gettext("done.\n")); 10017c478bd9Sstevel@tonic-gate } 1002