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