Home | History | Annotate | Download | only in cdrw
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <sys/types.h>
     29 #include <stdlib.h>
     30 #include <stdio.h>
     31 #include <string.h>
     32 
     33 #include "transport.h"
     34 #include "mmc.h"
     35 #include "util.h"
     36 #include "main.h"
     37 
     38 int
     39 test_unit_ready(int fd)
     40 {
     41 	struct uscsi_cmd *scmd;
     42 
     43 	scmd = get_uscsi_cmd();
     44 	scmd->uscsi_flags = USCSI_SILENT;
     45 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
     46 	/* give length of cdb structure */
     47 	scmd->uscsi_cdblen = 6;
     48 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
     49 		return (0);
     50 	return (1);
     51 }
     52 
     53 int
     54 inquiry(int fd, uchar_t *inq)
     55 {
     56 	struct uscsi_cmd *scmd;
     57 
     58 	scmd = get_uscsi_cmd();
     59 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
     60 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
     61 	scmd->uscsi_cdb[0] = INQUIRY_CMD;
     62 	scmd->uscsi_cdb[4] = INQUIRY_DATA_LENGTH;
     63 	scmd->uscsi_cdblen = 6;
     64 	scmd->uscsi_bufaddr = (char *)inq;
     65 	scmd->uscsi_buflen = INQUIRY_DATA_LENGTH;
     66 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
     67 		return (0);
     68 	return (1);
     69 }
     70 
     71 int
     72 read_capacity(int fd, uchar_t *capbuf)
     73 {
     74 	struct uscsi_cmd *scmd;
     75 
     76 	scmd = get_uscsi_cmd();
     77 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
     78 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
     79 	scmd->uscsi_cdb[0] = READ_CAP_CMD;
     80 	scmd->uscsi_cdblen = 10;
     81 	scmd->uscsi_bufaddr = (char *)capbuf;
     82 	scmd->uscsi_buflen = 8;
     83 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
     84 		return (0);
     85 	return (1);
     86 }
     87 
     88 int
     89 mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
     90 {
     91 	struct uscsi_cmd *scmd;
     92 
     93 	scmd = get_uscsi_cmd();
     94 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
     95 	scmd->uscsi_buflen = page_len;
     96 	scmd->uscsi_bufaddr = (char *)buffer;
     97 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
     98 	scmd->uscsi_cdblen = 0xa;
     99 	scmd->uscsi_cdb[0] = MODE_SENSE_10_CMD;
    100 	if (dbd) {
    101 		/* don't return any block descriptors */
    102 		scmd->uscsi_cdb[1] = 0x8;
    103 	}
    104 	/* the page code we want */
    105 	scmd->uscsi_cdb[2] = pc;
    106 	/* allocation length */
    107 	scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
    108 	scmd->uscsi_cdb[8] = page_len & 0xff;
    109 
    110 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    111 		return (0);
    112 	return (1);
    113 }
    114 
    115 int
    116 mode_select(int fd, int page_len, uchar_t *buffer)
    117 {
    118 	struct uscsi_cmd *scmd;
    119 
    120 	scmd = get_uscsi_cmd();
    121 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
    122 	scmd->uscsi_buflen = page_len;
    123 	scmd->uscsi_bufaddr = (char *)buffer;
    124 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    125 	scmd->uscsi_cdblen = 0xa;
    126 
    127 	/* mode select (10) command */
    128 	scmd->uscsi_cdb[0] = MODE_SELECT_10_CMD;
    129 	scmd->uscsi_cdb[1] = 0x10;
    130 
    131 	/* parameter list length */
    132 	scmd->uscsi_cdb[7] = (page_len >> 8) & 0xff;
    133 	scmd->uscsi_cdb[8] = page_len & 0xff;
    134 
    135 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    136 		return (0);
    137 	return (1);
    138 }
    139 
    140 int
    141 read_track_info(int fd, int trackno, uchar_t *ti)
    142 {
    143 	struct uscsi_cmd *scmd;
    144 
    145 	scmd = get_uscsi_cmd();
    146 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    147 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    148 	scmd->uscsi_cdb[0] = READ_TRACK_CMD;
    149 
    150 	/* tell device we are giving it a track number */
    151 	scmd->uscsi_cdb[1] = 1;
    152 
    153 	/* track number to read */
    154 	if (trackno == -1)
    155 		if (device_type == CD_RW) {
    156 			((uchar_t *)scmd->uscsi_cdb)[5] = 0xff;
    157 		} else {
    158 			/* only 1 track is allowed on DVD media */
    159 			scmd->uscsi_cdb[1] = 0;
    160 			((uchar_t *)scmd->uscsi_cdb)[5] = 0;
    161 		}
    162 	else
    163 		scmd->uscsi_cdb[5] = (uchar_t)trackno;
    164 
    165 	scmd->uscsi_cdb[8] = TRACK_INFO_SIZE;
    166 	scmd->uscsi_cdblen = 10;
    167 	scmd->uscsi_bufaddr = (char *)ti;
    168 	scmd->uscsi_buflen = TRACK_INFO_SIZE;
    169 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    170 		return (0);
    171 	return (1);
    172 }
    173 
    174 int
    175 read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf)
    176 {
    177 	struct uscsi_cmd *scmd;
    178 
    179 	scmd = get_uscsi_cmd();
    180 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    181 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    182 	scmd->uscsi_cdb[0] = READ_TOC_CMD;
    183 	scmd->uscsi_cdb[2] = format & 0xf;
    184 	scmd->uscsi_cdb[6] = trackno;
    185 	scmd->uscsi_cdb[8] = buflen & 0xff;
    186 	scmd->uscsi_cdb[7] = (buflen >> 8) & 0xff;
    187 	scmd->uscsi_cdblen = 10;
    188 	scmd->uscsi_bufaddr = (char *)buf;
    189 	scmd->uscsi_buflen = buflen;
    190 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    191 		return (0);
    192 
    193 	/* Fix for old SONY drives */
    194 	if ((format == 0) && (buflen == 4) && (buf[0] == 0) && (buf[1] == 2)) {
    195 		uint16_t toc_size;
    196 
    197 		toc_size = (((uint16_t)(buf[3] + 1)) * 8) + 2;
    198 		load_scsi16(buf, toc_size);
    199 	}
    200 	return (1);
    201 }
    202 
    203 int
    204 read_header(int fd, uint32_t lba, uchar_t *buf)
    205 {
    206 	struct uscsi_cmd *scmd;
    207 
    208 	scmd = get_uscsi_cmd();
    209 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    210 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    211 	scmd->uscsi_cdb[0] = READ_HDR_CMD;
    212 
    213 	/* Logical block address */
    214 	load_scsi32(&scmd->uscsi_cdb[2], lba);
    215 
    216 	/* allocation length */
    217 	scmd->uscsi_cdb[8] = 8;
    218 	scmd->uscsi_cdblen = 10;
    219 	scmd->uscsi_bufaddr = (char *)buf;
    220 	scmd->uscsi_buflen = 8;
    221 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    222 		return (0);
    223 	return (1);
    224 }
    225 
    226 int
    227 read_disc_info(int fd, uchar_t *di)
    228 {
    229 	struct uscsi_cmd *scmd;
    230 
    231 	scmd = get_uscsi_cmd();
    232 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    233 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    234 	scmd->uscsi_cdb[0] = READ_INFO_CMD;
    235 	scmd->uscsi_cdb[8] = DISC_INFO_BLOCK_SIZE;
    236 	scmd->uscsi_cdblen = 10;
    237 	scmd->uscsi_bufaddr = (char *)di;
    238 	scmd->uscsi_buflen = DISC_INFO_BLOCK_SIZE;
    239 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    240 		return (0);
    241 	return (1);
    242 }
    243 
    244 /* Get information about the Logical Unit's capabilities */
    245 int
    246 get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf)
    247 {
    248 	struct uscsi_cmd *scmd;
    249 
    250 	scmd = get_uscsi_cmd();
    251 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    252 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    253 
    254 	/* Set OPERATION CODE in CDB */
    255 	scmd->uscsi_cdb[0] = GET_CONFIG_CMD;
    256 
    257 	/*
    258 	 * Set RT field in CDB, currently need at most one
    259 	 * Feature Descriptor
    260 	 */
    261 	scmd->uscsi_cdb[1] = 0x2;
    262 
    263 	/* Set Starting Feature Number in CDB */
    264 	scmd->uscsi_cdb[2] = (feature >> 8) & 0xff;
    265 	scmd->uscsi_cdb[3] = feature & 0xff;
    266 
    267 	/* Set Allocation Length in CDB */
    268 	scmd->uscsi_cdb[7] = (bufsize >> 8) & 0xff;
    269 	scmd->uscsi_cdb[8] = bufsize & 0xff;
    270 
    271 	scmd->uscsi_cdblen = 10;
    272 	scmd->uscsi_bufaddr = (char *)buf;
    273 	scmd->uscsi_buflen = bufsize;
    274 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    275 		return (0);
    276 	return (1);
    277 }
    278 
    279 int
    280 read10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
    281 	uint32_t bufsize)
    282 {
    283 	struct uscsi_cmd *scmd;
    284 
    285 	scmd = get_uscsi_cmd();
    286 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    287 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    288 	scmd->uscsi_cdb[0] = READ_10_CMD;
    289 	load_scsi32(&scmd->uscsi_cdb[2], start_blk);
    290 	scmd->uscsi_cdb[8] = nblk & 0xff;
    291 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
    292 	scmd->uscsi_cdblen = 10;
    293 	scmd->uscsi_bufaddr = (char *)buf;
    294 	scmd->uscsi_buflen = bufsize;
    295 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    296 		return (0);
    297 	return (1);
    298 }
    299 
    300 int
    301 write10(int fd, uint32_t start_blk, uint16_t nblk, uchar_t *buf,
    302 	uint32_t bufsize)
    303 {
    304 	struct uscsi_cmd *scmd;
    305 
    306 	scmd = get_uscsi_cmd();
    307 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
    308 	/*
    309 	 * Some DVD drives take longer to write than
    310 	 * the standard time, since they tend to generate
    311 	 * the media TOC on the fly when the cache is full
    312 	 */
    313 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT * 3;
    314 	scmd->uscsi_cdb[0] = WRITE_10_CMD;
    315 	load_scsi32(&scmd->uscsi_cdb[2], start_blk);
    316 	scmd->uscsi_cdb[8] = nblk & 0xff;
    317 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
    318 	scmd->uscsi_cdblen = 10;
    319 	scmd->uscsi_bufaddr = (char *)buf;
    320 	scmd->uscsi_buflen = bufsize;
    321 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    322 		return (0);
    323 	return (1);
    324 }
    325 
    326 int
    327 close_track(int fd, int trackno, int close_session, int immediate)
    328 {
    329 	struct uscsi_cmd *scmd;
    330 
    331 	scmd = get_uscsi_cmd();
    332 	scmd->uscsi_flags = USCSI_SILENT;
    333 	scmd->uscsi_cdb[0] = CLOSE_TRACK_CMD;
    334 	if (immediate) {
    335 		scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    336 		scmd->uscsi_cdb[1] = 1;
    337 	} else {
    338 		scmd->uscsi_timeout = 240;
    339 	}
    340 	if ((close_session) || (device_type == DVD_PLUS) ||
    341 	    (device_type == DVD_PLUS_W)) {
    342 		/* close the session */
    343 		scmd->uscsi_cdb[2] = 2;
    344 
    345 	} else {
    346 		/* Close the track but leave session open */
    347 		scmd->uscsi_cdb[2] = 1;
    348 		scmd->uscsi_cdb[5] = trackno & 0xff;
    349 	}
    350 
    351 	/*
    352 	 * DVD+R media are already formatted, we are using
    353 	 * a special case to notify that drive to close
    354 	 * track/session and null-fill the remaining space.
    355 	 */
    356 	if (device_type == DVD_PLUS) {
    357 		scmd->uscsi_cdb[5] = 1; /* only 1 track */
    358 
    359 		if (close_session) {
    360 			scmd->uscsi_cdb[2] = 6; /* session */
    361 		} else {
    362 			scmd->uscsi_cdb[2] = 1; /* track */
    363 		}
    364 	}
    365 
    366 	scmd->uscsi_cdblen = 10;
    367 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    368 		return (0);
    369 	return (1);
    370 }
    371 
    372 int
    373 blank_disc(int fd, int type, int immediate)
    374 {
    375 	struct uscsi_cmd *scmd;
    376 
    377 	scmd = get_uscsi_cmd();
    378 	scmd->uscsi_flags = USCSI_SILENT;
    379 
    380 	if (immediate) {
    381 		scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    382 		scmd->uscsi_cdb[1] = 0x10;
    383 	} else {
    384 		scmd->uscsi_timeout = 0x12c0;
    385 	}
    386 	((uchar_t *)scmd->uscsi_cdb)[0] = BLANK_CMD;
    387 
    388 	/* tell it to blank the last session or all of the disk */
    389 	scmd->uscsi_cdb[1] |= type & 0x07;
    390 	scmd->uscsi_cdblen = 12;
    391 
    392 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    393 		return (0);
    394 	return (1);
    395 }
    396 
    397 int
    398 read_cd(int fd, uint32_t start_blk, uint16_t nblk, uchar_t sector_type,
    399 	uchar_t *buf, uint32_t bufsize)
    400 {
    401 	struct uscsi_cmd *scmd;
    402 
    403 	scmd = get_uscsi_cmd();
    404 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    405 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    406 	((uchar_t *)scmd->uscsi_cdb)[0] = READ_CD_CMD;
    407 	scmd->uscsi_cdb[1] = (sector_type & 0x7) << 2;
    408 	scmd->uscsi_cdb[5] = start_blk & 0xff;
    409 	scmd->uscsi_cdb[4] = (start_blk >> 8) & 0xff;
    410 	scmd->uscsi_cdb[3] = (start_blk >> 16) & 0xff;
    411 	scmd->uscsi_cdb[2] = (start_blk >> 24) & 0xff;
    412 	scmd->uscsi_cdb[8] = nblk & 0xff;
    413 	scmd->uscsi_cdb[7] = (nblk >> 8) & 0xff;
    414 	scmd->uscsi_cdb[9] = 0x10;
    415 	scmd->uscsi_cdblen = 12;
    416 	scmd->uscsi_bufaddr = (char *)buf;
    417 	scmd->uscsi_buflen = bufsize;
    418 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    419 		return (0);
    420 	return (1);
    421 }
    422 
    423 int
    424 load_unload(int fd, int load)
    425 {
    426 	struct uscsi_cmd *scmd;
    427 
    428 	scmd = get_uscsi_cmd();
    429 	scmd->uscsi_flags = USCSI_SILENT;
    430 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    431 	scmd->uscsi_cdb[0] = START_STOP_CMD;
    432 	if (load == 0) {
    433 		/* unload medium */
    434 		scmd->uscsi_cdb[4] = 2;
    435 	} else {
    436 		/* load medium */
    437 		scmd->uscsi_cdb[4] = 3;
    438 	}
    439 	scmd->uscsi_cdblen = 6;
    440 
    441 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    442 		return (0);
    443 	return (1);
    444 }
    445 
    446 int
    447 prevent_allow_mr(int fd, int op)
    448 {
    449 	struct uscsi_cmd *scmd;
    450 
    451 	scmd = get_uscsi_cmd();
    452 	scmd->uscsi_flags = USCSI_SILENT;
    453 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    454 	scmd->uscsi_cdb[0] = PREVENT_ALLOW_CMD;
    455 	if (!op) {	/* prevent */
    456 		scmd->uscsi_cdb[4] = 1;
    457 	}
    458 	scmd->uscsi_cdblen = 6;
    459 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    460 		return (0);
    461 	return (1);
    462 }
    463 
    464 int
    465 set_cd_speed(int fd, uint16_t read_speed, uint16_t write_speed)
    466 {
    467 	struct uscsi_cmd *scmd;
    468 
    469 	scmd = get_uscsi_cmd();
    470 	scmd->uscsi_flags = USCSI_SILENT;
    471 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    472 	scmd->uscsi_cdblen = 0xc;
    473 	((uchar_t *)scmd->uscsi_cdb)[0] = SET_CD_SPEED;
    474 	scmd->uscsi_cdb[2] = (read_speed >> 8) & 0xff;
    475 	scmd->uscsi_cdb[3] = read_speed & 0xff;
    476 	scmd->uscsi_cdb[4] = (write_speed >> 8) & 0xff;
    477 	scmd->uscsi_cdb[5] = write_speed & 0xff;
    478 
    479 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    480 		return (0);
    481 	return (1);
    482 }
    483 
    484 int
    485 get_performance(int fd, int get_write_performance, uchar_t *perf)
    486 {
    487 	struct uscsi_cmd *scmd;
    488 
    489 	scmd = get_uscsi_cmd();
    490 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    491 	scmd->uscsi_buflen = GET_PERF_DATA_LEN;
    492 	scmd->uscsi_bufaddr = (char *)perf;
    493 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    494 	scmd->uscsi_cdblen = 0xc;
    495 	((uchar_t *)scmd->uscsi_cdb)[0] = GET_PERFORMANCE_CMD;
    496 	scmd->uscsi_cdb[1] = 0x10;
    497 	if (get_write_performance)
    498 		scmd->uscsi_cdb[1] |= 4;
    499 	scmd->uscsi_cdb[9] = 2;
    500 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    501 		return (0);
    502 	return (1);
    503 }
    504 
    505 int
    506 set_streaming(int fd, uchar_t *buf)
    507 {
    508 	struct uscsi_cmd *scmd;
    509 
    510 	scmd = get_uscsi_cmd();
    511 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
    512 	scmd->uscsi_buflen = SET_STREAM_DATA_LEN;
    513 	scmd->uscsi_bufaddr = (char *)buf;
    514 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    515 	scmd->uscsi_cdblen = 0xc;
    516 	((uchar_t *)scmd->uscsi_cdb)[0] = STREAM_CMD;
    517 	scmd->uscsi_cdb[10] = SET_STREAM_DATA_LEN;
    518 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    519 		return (0);
    520 	return (1);
    521 }
    522 
    523 int
    524 rezero_unit(int fd)
    525 {
    526 	struct uscsi_cmd *scmd;
    527 
    528 	scmd = get_uscsi_cmd();
    529 	scmd->uscsi_flags = USCSI_SILENT;
    530 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    531 	scmd->uscsi_cdblen = 0x6;
    532 	scmd->uscsi_cdb[0] = REZERO_UNIT_CMD;
    533 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    534 		return (0);
    535 	return (1);
    536 }
    537 
    538 int
    539 start_stop(int fd, int start)
    540 {
    541 	struct uscsi_cmd *scmd;
    542 
    543 	scmd = get_uscsi_cmd();
    544 	scmd->uscsi_flags = USCSI_SILENT;
    545 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    546 	scmd->uscsi_cdblen = 0x6;
    547 	scmd->uscsi_cdb[0] = START_STOP_CMD;
    548 	if (start) {
    549 		scmd->uscsi_cdb[4] = 1;
    550 	}
    551 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    552 		return (0);
    553 	return (1);
    554 }
    555 
    556 int
    557 flush_cache(int fd)
    558 {
    559 	struct uscsi_cmd *scmd;
    560 
    561 	scmd = get_uscsi_cmd();
    562 	scmd->uscsi_flags = USCSI_SILENT;
    563 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    564 	scmd->uscsi_cdblen = 10;
    565 	scmd->uscsi_cdb[0] = SYNC_CACHE_CMD;
    566 	if (device_type != CD_RW) {
    567 		scmd->uscsi_cdb[1] = 0x2; /* Immediate */
    568 	}
    569 
    570 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    571 		return (0);
    572 	return (1);
    573 }
    574 
    575 /*
    576  * used for DVD- to reserve the size we want to write.
    577  * This is used by the drive to generate a TOC.
    578  */
    579 int
    580 set_reservation(int fd, ulong_t size)
    581 {
    582 	struct uscsi_cmd *scmd;
    583 
    584 	scmd = get_uscsi_cmd();
    585 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    586 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    587 	scmd->uscsi_cdb[0] = SET_RESERVATION_CMD;
    588 	scmd->uscsi_cdblen = 10;
    589 	scmd->uscsi_cdb[5] = (uchar_t)(size >> 24);
    590 	scmd->uscsi_cdb[6] = (uchar_t)(size >> 16);
    591 	scmd->uscsi_cdb[7] = (uchar_t)(size >> 8);
    592 	scmd->uscsi_cdb[8] = (uchar_t)size;
    593 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    594 		return (0);
    595 	return (1);
    596 }
    597 
    598 /*
    599  * Used for DVD+RW media to prepare the disk to write.
    600  * It will also be used for packet mode writing when
    601  * it becomes supported.
    602  */
    603 int
    604 format_media(int fd)
    605 {
    606 	struct uscsi_cmd *scmd;
    607 	uchar_t buf[20];
    608 
    609 	(void) memset(buf, 0, 20);
    610 	scmd = get_uscsi_cmd();
    611 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    612 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    613 
    614 	scmd->uscsi_cdblen = 12;
    615 	scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
    616 	scmd->uscsi_cdb[8] = 0x14; /* buffer length */
    617 	scmd->uscsi_buflen = 20;
    618 	scmd->uscsi_bufaddr = (char *)buf;
    619 
    620 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    621 		return (0);
    622 
    623 	/* RE-use cap structure */
    624 
    625 	scmd->uscsi_flags = USCSI_WRITE|USCSI_SILENT;
    626 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    627 	scmd->uscsi_cdblen = 6;
    628 	scmd->uscsi_cdb[0] = FORMAT_UNIT_CMD;
    629 	/* full format */
    630 	scmd->uscsi_cdb[1] = 0x11;
    631 	scmd->uscsi_buflen = 12;
    632 	buf[1] = 0x82; /* immediate and FOV */
    633 	buf[3] = 8;	/* descriptor length */
    634 	buf[8] = 0x98;	/* type = 26 DVD+RW format */
    635 	buf[10] = 0;
    636 
    637 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    638 		return (0);
    639 	return (1);
    640 }
    641 
    642 
    643 /*
    644  * Prefered method of reading the media size. This is
    645  * the only supported method on several newer drives.
    646  */
    647 uint32_t
    648 read_format_capacity(int fd, uint_t *bsize)
    649 {
    650 	struct uscsi_cmd *scmd;
    651 	uint32_t filesize;
    652 	char buf[20];
    653 
    654 	scmd = get_uscsi_cmd();
    655 	scmd->uscsi_flags = USCSI_READ|USCSI_SILENT;
    656 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    657 	scmd->uscsi_cdblen = 12;
    658 	scmd->uscsi_cdb[0] = READ_FORMAT_CAP_CMD;
    659 	scmd->uscsi_cdb[8] = 0x14;
    660 	scmd->uscsi_buflen = 20;
    661 	scmd->uscsi_bufaddr = buf;
    662 
    663 	if ((uscsi_error = uscsi(fd, scmd)) < 0)
    664 		return (0);
    665 
    666 	filesize =  (uint32_t)(((uchar_t)buf[4] << 24) +
    667 	    ((uchar_t)buf[5] << 16) + ((uchar_t)buf[6] << 8) + (uchar_t)buf[7]);
    668 
    669 	*bsize = (uint16_t)(((uchar_t)buf[10] << 8) + (uchar_t)buf[11]);
    670 
    671 	return (filesize);
    672 }
    673 
    674 /*
    675  * Used to reset the device. Since, sd(7D) requires a
    676  * command to be issued when resetting a device we will
    677  * issue an innocuous command. The command chosen for this
    678  * purpose is the TEST UNIT READY (TUR) command. We also do
    679  * not care about the sucess of the TUR so we will not return
    680  * a value.
    681  */
    682 void
    683 reset_dev(int fd)
    684 {
    685 	struct uscsi_cmd *scmd;
    686 
    687 	/*
    688 	 * Since a TUR has SCSI operation code of 0, we
    689 	 * can make use of the fact that get_uscsi_cmd()
    690 	 * initializes a CDB to all zeros to generate
    691 	 * the TUR command.
    692 	 */
    693 	scmd = get_uscsi_cmd();
    694 
    695 	/* Tell sd(7D) to do a silent reset of the device. */
    696 	scmd->uscsi_flags = USCSI_SILENT | USCSI_RESET;
    697 
    698 	scmd->uscsi_timeout = DEFAULT_SCSI_TIMEOUT;
    699 	scmd->uscsi_cdblen = 6;
    700 
    701 	/* Issue the TUR command. */
    702 	uscsi_error = uscsi(fd, scmd);
    703 }
    704 
    705 
    706 /*
    707  * Function:    ftr_supported
    708  *
    709  * Description: Check to see if a device supports a Feature
    710  *
    711  * Arguments:   fd      - file descriptor
    712  *              feature - the MMC Feature for which we'd like to know
    713  *                        if there's support
    714  *
    715  * Return Code: 1       - Feature is supported
    716  *		0	- Feature is not supported
    717  *
    718  */
    719 int
    720 ftr_supported(int fd, uint16_t feature)
    721 {
    722 	size_t response_len;
    723 	uchar_t *bufp;
    724 	int ret;
    725 
    726 	response_len = MMC_FTR_HDR_LEN + MMC_FTR_DSCRPTR_BASE_LEN;
    727 	bufp = (uchar_t *)my_zalloc(response_len);
    728 
    729 	/*
    730 	 * If a Feature is supported, a device will return a Feature Descriptor
    731 	 * for that Feature, and its Current Bit will be set.
    732 	 */
    733 	if (get_configuration(fd, feature, response_len, bufp) == 1) {
    734 		/*
    735 		 * To check that a Feature Descriptor was returned, we
    736 		 * check to see if the Data Length field of the Feature
    737 		 * Header holds a value greater than four.  To check if
    738 		 * the Current Bit is set, we check bit 1 of byte 10.
    739 		 */
    740 		if (read_scsi32(bufp) > 4 && bufp[10] & 1)
    741 			ret = 1;
    742 		else
    743 			ret = 0;
    744 	} else {
    745 		/* get_configuration failed */
    746 		ret = 0;
    747 	}
    748 	free(bufp);
    749 	return (ret);
    750 }
    751 
    752 /*
    753  * Function:    print_profile_name
    754  *
    755  * Description: Prints a list of the Profiles the device supports
    756  *
    757  * Parameters:  num     - hexadecimal representation of Profile
    758  *              current - 1 if the Profile is Current, otherwise 0
    759  *		abbr	- 1 if printing abbreviated name, otherwise 0
    760  */
    761 void
    762 print_profile_name(uint16_t num, uchar_t current, uchar_t abbr)
    763 {
    764 	if (abbr != 1)
    765 		(void) printf(" 0x%04x: ", num);
    766 
    767 	switch (num) {
    768 	case 0x0000:
    769 		(void) printf("No Current Profile");
    770 		break;
    771 	case 0x0001:
    772 		(void) printf("Non-Removable Disk");
    773 		break;
    774 	case 0x0002:
    775 		(void) printf("Removable Disk");
    776 		break;
    777 	case 0x0003:
    778 		(void) printf("Magneto-Optical Erasable");
    779 		break;
    780 	case 0x0004:
    781 		(void) printf("Optical Write Once");
    782 		break;
    783 	case 0x0005:
    784 		(void) printf("AS-MO");
    785 		break;
    786 	case 0x0008:
    787 		(void) printf("CD-ROM");
    788 		break;
    789 	case 0x0009:
    790 		(void) printf("CD-R");
    791 		break;
    792 	case 0x000A:
    793 		(void) printf("CD-RW");
    794 		break;
    795 	case 0x0010:
    796 		(void) printf("DVD-ROM");
    797 		break;
    798 	case 0x0011:
    799 		(void) printf("DVD-R");
    800 		if (abbr != 1)
    801 			(void) printf(" Sequential Recording");
    802 		break;
    803 	case 0x0012:
    804 		(void) printf("DVD-RAM");
    805 		break;
    806 	case 0x0013:
    807 		(void) printf("DVD-RW");
    808 		if (abbr != 1)
    809 			(void) printf(" Restricted Overwrite");
    810 		break;
    811 	case 0x0014:
    812 		(void) printf("DVD-RW");
    813 		if (abbr != 1)
    814 			(void) printf(" Sequential Recording");
    815 		break;
    816 	case 0x0015:
    817 		(void) printf("DVD-R");
    818 		if (abbr != 1)
    819 			(void) printf(" Dual Layer Sequential Recording");
    820 		else
    821 			(void) printf(" DL");
    822 		break;
    823 	case 0x0016:
    824 		(void) printf("DVD-R");
    825 		if (abbr != 1)
    826 			(void) printf(" Dual Layer Jump Recording");
    827 		else
    828 			(void) printf(" DL");
    829 		break;
    830 	case 0x0017:
    831 		(void) printf("DVD-RW");
    832 		if (abbr != 1)
    833 			(void) printf(" Dual Layer");
    834 		else
    835 			(void) printf(" DL");
    836 		break;
    837 	case 0x001A:
    838 		(void) printf("DVD+RW");
    839 		break;
    840 	case 0x001B:
    841 		(void) printf("DVD+R");
    842 		break;
    843 	case 0x0020:
    844 		(void) printf("DDCD-ROM");
    845 		break;
    846 	case 0x0021:
    847 		(void) printf("DDCD-R");
    848 		break;
    849 	case 0x0022:
    850 		(void) printf("DDCD-RW");
    851 		break;
    852 	case 0x002A:
    853 		(void) printf("DVD+RW");
    854 		if (abbr != 1)
    855 			(void) printf(" Dual Layer");
    856 		else
    857 			(void) printf(" DL");
    858 		break;
    859 	case 0x002B:
    860 		(void) printf("DVD+R");
    861 		if (abbr != 1)
    862 			(void) printf(" Dual Layer");
    863 		else
    864 			(void) printf(" DL");
    865 		break;
    866 	case 0x0040:
    867 		(void) printf("BD-ROM");
    868 		break;
    869 	case 0x0041:
    870 		(void) printf("BD-R Sequential Recording (SRM) Profile");
    871 		break;
    872 	case 0x0042:
    873 		(void) printf("BD-R Random Recording (RRM) Profile");
    874 		break;
    875 	case 0x0043:
    876 		(void) printf("BD-RE");
    877 		break;
    878 	case 0xFFFF:
    879 		(void) printf("Nonstandard Profile");
    880 		break;
    881 	default:
    882 		break;
    883 	}
    884 	if (current == 1)
    885 		(void) printf(" (Current Profile)");
    886 	(void) printf("\n");
    887 }
    888 
    889 /*
    890  * Function: print_profile_list
    891  *
    892  * Description: Print a list of Profiles supported by the Logical Unit.
    893  *
    894  * Parameters:	fd 	- file descriptor for device whose list of
    895  *			  profiles we wish to print
    896  */
    897 void
    898 print_profile_list(int fd)
    899 {
    900 	size_t i;
    901 	size_t buflen;
    902 	uint16_t current;
    903 	uint16_t other;
    904 	uchar_t *bufp = (uchar_t *)my_zalloc(MMC_FTR_HDR_LEN);
    905 
    906 	/*
    907 	 * First get_configuration call is used to determine amount of memory
    908 	 * needed to hold all the Profiles.  The first four bytes of bufp
    909 	 * concatenated tell us the number of bytes of memory we need but do
    910 	 * not take themselves into account.  Therefore, add four, and
    911 	 * allocate that number of bytes.
    912 	 */
    913 	if (get_configuration(fd, MMC_FTR_PRFL_LIST, MMC_FTR_HDR_LEN,
    914 	    bufp)) {
    915 		buflen = read_scsi32(bufp) + 4;
    916 		free(bufp);
    917 		bufp = (uchar_t *)my_zalloc(buflen);
    918 
    919 		/*
    920 		 * Now get all the Profiles
    921 		 */
    922 		if (get_configuration(fd, MMC_FTR_PRFL_LIST, buflen, bufp)) {
    923 			(void) printf("\nProfile List\n");
    924 			(void) printf("---------------------------------\n");
    925 
    926 			/*
    927 			 * Find out the Logical Unit's Current Profile
    928 			 */
    929 			current = read_scsi16(&bufp[6]);
    930 
    931 			/*
    932 			 * Print out the Profile List and indicate which
    933 			 * Profile is Current
    934 			 */
    935 			for (i = MMC_FTR_HDR_LEN + MMC_FTR_DSCRPTR_BASE_LEN;
    936 			    i < buflen; i += MMC_PRFL_DSCRPTR_LEN) {
    937 				other = read_scsi16(&bufp[i]);
    938 				if (other == current)
    939 					print_profile_name(other, 1, 0);
    940 				else
    941 					print_profile_name(other, 0, 0);
    942 			}
    943 			(void) printf("\n");
    944 		}
    945 	}
    946 	free(bufp);
    947 }
    948