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