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 2005 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