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