1 /* 2 * Copyright 2004-2010, Haiku, Inc. All rights reserved. 3 * Copyright 2002-2003, Thomas Kurschel. All rights reserved. 4 * 5 * Distributed under the terms of the MIT License. 6 */ 7 8 9 /*! Peripheral driver to handle CD-ROM drives. To be more 10 precisely, it supports CD-ROM and WORM drives (well - 11 I've never _seen_ a WORM driver). 12 13 Much work is done by scsi_periph and block_io. 14 */ 15 16 17 #include "scsi_cd.h" 18 19 #include <stdlib.h> 20 #include <string.h> 21 22 #include <algorithm> 23 24 #include <io_requests.h> 25 #include <vm/vm_page.h> 26 27 #include "IOCache.h" 28 #include "IOSchedulerSimple.h" 29 30 31 #define TRACE_CD_DISK 32 #ifdef TRACE_CD_DISK 33 # define TRACE(x...) dprintf("scsi_cd: " x) 34 #else 35 # define TRACE(x...) ; 36 #endif 37 38 39 static const uint8 kCDIcon[] = { 40 0x6e, 0x63, 0x69, 0x66, 0x05, 0x05, 0x00, 0x02, 0x03, 0x06, 0x05, 0xb8, 41 0x12, 0xa5, 0xbe, 0x03, 0xe1, 0x3d, 0xe7, 0x84, 0xb8, 0x02, 0x10, 0x49, 42 0xf7, 0x9f, 0x49, 0xed, 0xd8, 0x00, 0xf1, 0xf1, 0xf1, 0x36, 0xd9, 0xdd, 43 0xf4, 0x8a, 0x99, 0x96, 0xb9, 0xb4, 0xb8, 0xbe, 0xdb, 0xff, 0xf4, 0xf4, 44 0xf4, 0x04, 0xeb, 0xd0, 0x02, 0x00, 0x06, 0x02, 0x3c, 0x92, 0xc0, 0x38, 45 0x8f, 0x5f, 0xb8, 0x54, 0x50, 0x3c, 0x57, 0x63, 0x48, 0xd8, 0xdf, 0x48, 46 0x89, 0x5b, 0x00, 0x41, 0x37, 0xa9, 0xff, 0xb9, 0xb9, 0xb9, 0x04, 0x01, 47 0x7e, 0x04, 0x02, 0x04, 0x3f, 0x2c, 0x4e, 0x2c, 0x30, 0x2c, 0x22, 0x40, 48 0x22, 0x34, 0x22, 0x4c, 0x3f, 0x54, 0x30, 0x54, 0x4e, 0x54, 0x5c, 0x40, 49 0x5c, 0x4c, 0x5c, 0x34, 0x02, 0x04, 0x3f, 0x3a, 0x43, 0x3a, 0x3b, 0x3a, 50 0x39, 0x3e, 0x39, 0x3c, 0x39, 0x40, 0x3f, 0x42, 0x3b, 0x42, 0x43, 0x42, 51 0x45, 0x3e, 0x45, 0x40, 0x45, 0x3c, 0x02, 0x04, 0x4b, 0x3e, 0x4b, 0x3a, 52 0x4b, 0x42, 0x3f, 0x46, 0x47, 0x46, 0x37, 0x46, 0x33, 0x3e, 0x33, 0x42, 53 0x33, 0x3a, 0x3f, 0xbb, 0xf7, 0x37, 0xbb, 0xf7, 0x47, 0xbb, 0xf7, 0x02, 54 0x04, 0x40, 0x2a, 0x54, 0x2a, 0x50, 0x2c, 0x5c, 0x40, 0x5c, 0x34, 0x5c, 55 0x4c, 0x40, 0x56, 0x50, 0x54, 0x54, 0x56, 0x60, 0x40, 0x60, 0x4c, 0x60, 56 0x34, 0x06, 0x0a, 0x04, 0x01, 0x03, 0x00, 0x0a, 0x00, 0x02, 0x00, 0x01, 57 0x18, 0x15, 0xff, 0x01, 0x17, 0x84, 0x00, 0x04, 0x0a, 0x00, 0x02, 0x00, 58 0x01, 0x18, 0x00, 0x15, 0x01, 0x17, 0x86, 0x00, 0x04, 0x0a, 0x01, 0x02, 59 0x00, 0x02, 0x00, 0x0a, 0x02, 0x02, 0x02, 0x01, 0x00, 0x0a, 0x03, 0x01, 60 0x02, 0x10, 0x01, 0x17, 0x82, 0x00, 0x04 61 }; 62 63 64 static scsi_periph_interface *sSCSIPeripheral; 65 static device_manager_info *sDeviceManager; 66 67 68 #define SCSI_CD_STD_TIMEOUT 10 69 70 71 static status_t 72 update_capacity(cd_driver_info *info) 73 { 74 TRACE("update_capacity()\n"); 75 76 scsi_ccb *ccb = info->scsi->alloc_ccb(info->scsi_device); 77 if (ccb == NULL) 78 return B_NO_MEMORY; 79 80 status_t status = sSCSIPeripheral->check_capacity( 81 info->scsi_periph_device, ccb); 82 83 info->scsi->free_ccb(ccb); 84 85 return status; 86 } 87 88 89 /*! Iteratively correct the reported capacity by trying to read from the device 90 close to its end. 91 */ 92 static uint64 93 test_capacity(cd_driver_info *info) 94 { 95 static const size_t kMaxEntries = 4; 96 const uint32 blockSize = info->block_size; 97 const size_t kBufferSize = blockSize * 4; 98 99 TRACE("test_capacity: read with buffer size %" B_PRIuSIZE ", block size %" 100 B_PRIu32", capacity %llu\n", kBufferSize, blockSize, 101 info->original_capacity); 102 103 info->capacity = info->original_capacity; 104 105 size_t numBlocks = B_PAGE_SIZE / blockSize; 106 uint64 offset = info->original_capacity; 107 if (offset <= numBlocks) 108 return B_OK; 109 110 offset -= numBlocks; 111 112 scsi_ccb *request = info->scsi->alloc_ccb(info->scsi_device); 113 if (request == NULL) 114 return B_NO_MEMORY; 115 116 // Allocate buffer 117 118 physical_entry entries[4]; 119 size_t numEntries = 0; 120 121 vm_page_reservation reservation; 122 vm_page_reserve_pages(&reservation, 123 (kBufferSize - 1 + B_PAGE_SIZE) / B_PAGE_SIZE, VM_PRIORITY_SYSTEM); 124 125 for (size_t left = kBufferSize; numEntries < kMaxEntries && left > 0; 126 numEntries++) { 127 size_t bytes = std::min(left, (size_t)B_PAGE_SIZE); 128 129 vm_page* page = vm_page_allocate_page(&reservation, 130 PAGE_STATE_WIRED | VM_PAGE_ALLOC_BUSY); 131 132 entries[numEntries].address = page->physical_page_number * B_PAGE_SIZE; 133 entries[numEntries].size = bytes;; 134 135 left -= bytes; 136 } 137 138 vm_page_unreserve_pages(&reservation); 139 140 // Read close to the end of the device to find out its real end 141 142 // Only try 1 second before the end (= 75 blocks) 143 while (offset > info->original_capacity - 75) { 144 size_t bytesTransferred; 145 status_t status = sSCSIPeripheral->read_write(info->scsi_periph_device, 146 request, offset, numBlocks, entries, numEntries, false, 147 &bytesTransferred); 148 149 TRACE("test_capacity: read from offset %llu: %s\n", offset, 150 strerror(status)); 151 152 if (status == B_OK || (request->sense[0] & 0x7f) != 0x70) 153 break; 154 155 switch (request->sense[2]) { 156 case SCSIS_KEY_MEDIUM_ERROR: 157 case SCSIS_KEY_ILLEGAL_REQUEST: 158 case SCSIS_KEY_VOLUME_OVERFLOW: 159 { 160 // find out the problematic sector 161 uint32 errorBlock = (request->sense[3] << 24U) 162 | (request->sense[4] << 16U) | (request->sense[5] << 8U) 163 | request->sense[6]; 164 if (errorBlock >= offset) 165 info->capacity = errorBlock; 166 break; 167 } 168 169 default: 170 break; 171 } 172 173 if (numBlocks > offset) 174 break; 175 176 offset -= numBlocks; 177 } 178 179 info->scsi->free_ccb(request); 180 181 for (size_t i = 0; i < numEntries; i++) { 182 vm_page_set_state(vm_lookup_page(entries[i].address / B_PAGE_SIZE), 183 PAGE_STATE_FREE); 184 } 185 186 if (info->capacity != info->original_capacity) { 187 dprintf("scsi_cd: adjusted capacity from %llu to %llu blocks.\n", 188 info->original_capacity, info->capacity); 189 } 190 191 return B_OK; 192 } 193 194 195 static status_t 196 get_geometry(cd_handle *handle, device_geometry *geometry) 197 { 198 cd_driver_info *info = handle->info; 199 200 status_t status = update_capacity(info); 201 202 // it seems that Be expects B_GET_GEOMETRY to always succeed unless 203 // the medium has been changed; e.g. if we report B_DEV_NO_MEDIA, the 204 // info is ignored by the CDPlayer and CDBurner 205 if (status == B_DEV_MEDIA_CHANGED) 206 return B_DEV_MEDIA_CHANGED; 207 208 geometry->bytes_per_sector = info->block_size; 209 geometry->sectors_per_track = 1; 210 geometry->cylinder_count = info->capacity; 211 geometry->head_count = 1; 212 geometry->device_type = info->device_type; 213 geometry->removable = info->removable; 214 215 // TBD: for all but CD-ROMs, read mode sense - medium type 216 // (bit 7 of block device specific parameter for Optical Memory Block Device) 217 // (same for Direct-Access Block Devices) 218 // (same for write-once block devices) 219 // (same for optical memory block devices) 220 geometry->read_only = true; 221 geometry->write_once = info->device_type == scsi_dev_WORM; 222 223 TRACE("scsi_disk: get_geometry(): %ld, %ld, %ld, %ld, %d, %d, %d, %d\n", 224 geometry->bytes_per_sector, geometry->sectors_per_track, 225 geometry->cylinder_count, geometry->head_count, geometry->device_type, 226 geometry->removable, geometry->read_only, geometry->write_once); 227 228 return B_OK; 229 } 230 231 232 static status_t 233 get_toc(cd_driver_info *info, scsi_toc *toc) 234 { 235 scsi_ccb *ccb; 236 status_t res; 237 scsi_cmd_read_toc *cmd; 238 size_t dataLength; 239 scsi_toc_general *shortResponse = (scsi_toc_general *)toc->toc_data; 240 241 TRACE("get_toc()\n"); 242 243 ccb = info->scsi->alloc_ccb(info->scsi_device); 244 if (ccb == NULL) 245 return B_NO_MEMORY; 246 247 // first read number of tracks only 248 ccb->flags = SCSI_DIR_IN; 249 250 cmd = (scsi_cmd_read_toc *)ccb->cdb; 251 252 memset(cmd, 0, sizeof(*cmd)); 253 cmd->opcode = SCSI_OP_READ_TOC; 254 cmd->time = 1; 255 cmd->format = SCSI_TOC_FORMAT_TOC; 256 cmd->track = 1; 257 cmd->allocation_length = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_toc_general)); 258 259 ccb->cdb_length = sizeof(*cmd); 260 261 ccb->sort = -1; 262 ccb->timeout = SCSI_CD_STD_TIMEOUT; 263 264 ccb->data = toc->toc_data; 265 ccb->sg_list = NULL; 266 ccb->data_length = sizeof(toc->toc_data); 267 268 res = sSCSIPeripheral->safe_exec(info->scsi_periph_device, ccb); 269 if (res != B_OK) 270 goto err; 271 272 // then read all track infos 273 // (little hint: number of tracks is last - first + 1; 274 // but scsi_toc_toc has already one track, so we get 275 // last - first extra tracks; finally, we want the lead-out as 276 // well, so we add an extra track) 277 dataLength = (shortResponse->last - shortResponse->first + 1) 278 * sizeof(scsi_toc_track) + sizeof(scsi_toc_toc); 279 dataLength = min_c(dataLength, sizeof(toc->toc_data)); 280 281 TRACE(" tracks: %d - %d, data length %d\n", shortResponse->first, 282 shortResponse->last, (int)dataLength); 283 284 cmd->allocation_length = B_HOST_TO_BENDIAN_INT16(dataLength); 285 286 res = sSCSIPeripheral->safe_exec(info->scsi_periph_device, ccb); 287 288 err: 289 info->scsi->free_ccb(ccb); 290 291 return res; 292 } 293 294 295 static status_t 296 load_eject(cd_driver_info *info, bool load) 297 { 298 TRACE("load_eject()\n"); 299 300 scsi_ccb *ccb = info->scsi->alloc_ccb(info->scsi_device); 301 if (ccb == NULL) 302 return B_NO_MEMORY; 303 304 err_res result = sSCSIPeripheral->send_start_stop( 305 info->scsi_periph_device, ccb, load, true); 306 307 info->scsi->free_ccb(ccb); 308 309 return result.error_code; 310 } 311 312 313 static status_t 314 get_position(cd_driver_info *info, scsi_position *position) 315 { 316 scsi_cmd_read_subchannel cmd; 317 318 TRACE("get_position()\n"); 319 320 memset(&cmd, 0, sizeof(cmd)); 321 cmd.opcode = SCSI_OP_READ_SUB_CHANNEL; 322 cmd.time = 1; 323 cmd.subq = 1; 324 cmd.parameter_list = scsi_sub_channel_parameter_list_cd_pos; 325 cmd.track = 0; 326 cmd.allocation_length = B_HOST_TO_BENDIAN_INT16(sizeof(scsi_position)); 327 328 return sSCSIPeripheral->simple_exec(info->scsi_periph_device, 329 &cmd, sizeof(cmd), position, sizeof(*position), SCSI_DIR_IN); 330 } 331 332 333 static status_t 334 get_set_volume(cd_driver_info *info, scsi_volume *volume, bool set) 335 { 336 scsi_cmd_mode_sense_6 cmd; 337 scsi_mode_param_header_6 header; 338 size_t len; 339 void *buffer; 340 scsi_modepage_audio *page; 341 status_t res; 342 343 TRACE("get_set_volume()\n"); 344 345 // determine size of block descriptor 346 memset(&cmd, 0, sizeof(cmd)); 347 cmd.opcode = SCSI_OP_MODE_SENSE_6; 348 cmd.page_code = SCSI_MODEPAGE_AUDIO; 349 cmd.page_control = SCSI_MODE_SENSE_PC_CURRENT; 350 cmd.allocation_length = sizeof(header); 351 352 memset(&header, -2, sizeof(header)); 353 354 res = sSCSIPeripheral->simple_exec(info->scsi_periph_device, &cmd, 355 sizeof(cmd), &header, sizeof(header), SCSI_DIR_IN); 356 if (res != B_OK) 357 return res; 358 359 TRACE(" block_desc_len=%d", header.block_desc_length); 360 #if 0 361 // ToDo: why this?? 362 return B_ERROR; 363 #endif 364 365 // retrieve param header, block descriptor and actual codepage 366 len = sizeof(header) + header.block_desc_length 367 + sizeof(scsi_modepage_audio); 368 369 buffer = malloc(len); 370 if (buffer == NULL) 371 return B_NO_MEMORY; 372 373 memset(buffer, -1, sizeof(buffer)); 374 375 cmd.allocation_length = len; 376 377 res = sSCSIPeripheral->simple_exec(info->scsi_periph_device, &cmd, 378 sizeof(cmd), buffer, len, SCSI_DIR_IN); 379 if (res != B_OK) { 380 free(buffer); 381 return res; 382 } 383 384 TRACE(" mode_data_len=%d, block_desc_len=%d", 385 ((scsi_mode_param_header_6 *)buffer)->mode_data_length, 386 ((scsi_mode_param_header_6 *)buffer)->block_desc_length); 387 388 // find control page and retrieve values 389 page = (scsi_modepage_audio *)((char *)buffer + sizeof(header) 390 + header.block_desc_length); 391 392 TRACE(" page=%p, codepage=%d", page, page->header.page_code); 393 394 if (!set) { 395 volume->port0_channel = page->ports[0].channel; 396 volume->port0_volume = page->ports[0].volume; 397 volume->port1_channel = page->ports[1].channel; 398 volume->port1_volume = page->ports[1].volume; 399 volume->port2_channel = page->ports[2].channel; 400 volume->port2_volume = page->ports[2].volume; 401 volume->port3_channel = page->ports[3].channel; 402 volume->port3_volume = page->ports[3].volume; 403 404 #if 0 405 SHOW_FLOW(3, "1: %d - %d", volume->port0_channel, volume->port0_volume); 406 SHOW_FLOW(3, "2: %d - %d", volume->port1_channel, volume->port1_volume); 407 SHOW_FLOW(3, "3: %d - %d", volume->port2_channel, volume->port2_volume); 408 SHOW_FLOW(3, "4: %d - %d", volume->port3_channel, volume->port3_volume); 409 #endif 410 res = B_OK; 411 } else { 412 scsi_cmd_mode_select_6 cmd; 413 414 if (volume->flags & 0x01) 415 page->ports[0].channel = volume->port0_channel; 416 if (volume->flags & 0x02) 417 page->ports[0].volume = volume->port0_volume; 418 if (volume->flags & 0x04) 419 page->ports[1].channel = volume->port1_channel; 420 if (volume->flags & 0x08) 421 page->ports[1].volume = volume->port1_volume; 422 if (volume->flags & 0x10) 423 page->ports[2].channel = volume->port2_channel; 424 if (volume->flags & 0x20) 425 page->ports[2].volume = volume->port2_volume; 426 if (volume->flags & 0x40) 427 page->ports[3].channel = volume->port3_channel; 428 if (volume->flags & 0x80) 429 page->ports[3].volume = volume->port3_volume; 430 431 memset(&cmd, 0, sizeof(cmd)); 432 cmd.opcode = SCSI_OP_MODE_SELECT_6; 433 cmd.pf = 1; 434 cmd.param_list_length = sizeof(header) + header.block_desc_length 435 + sizeof(*page); 436 437 res = sSCSIPeripheral->simple_exec(info->scsi_periph_device, 438 &cmd, sizeof(cmd), buffer, len, SCSI_DIR_OUT); 439 } 440 441 free(buffer); 442 return res; 443 } 444 445 446 /*! Play audio cd; time is in MSF */ 447 static status_t 448 play_msf(cd_driver_info *info, const scsi_play_position *position) 449 { 450 scsi_cmd_play_msf cmd; 451 452 TRACE("play_msf(): %d:%d:%d-%d:%d:%d\n", position->start_m, 453 position->start_s, position->start_f, position->end_m, position->end_s, 454 position->end_f); 455 456 memset(&cmd, 0, sizeof(cmd)); 457 458 cmd.opcode = SCSI_OP_PLAY_MSF; 459 cmd.start_minute = position->start_m; 460 cmd.start_second = position->start_s; 461 cmd.start_frame = position->start_f; 462 cmd.end_minute = position->end_m; 463 cmd.end_second = position->end_s; 464 cmd.end_frame = position->end_f; 465 466 return sSCSIPeripheral->simple_exec(info->scsi_periph_device, 467 &cmd, sizeof(cmd), NULL, 0, SCSI_DIR_NONE); 468 } 469 470 471 /*! Play audio cd; time is in track/index */ 472 static status_t 473 play_track_index(cd_driver_info *info, const scsi_play_track *buf) 474 { 475 scsi_toc generic_toc; 476 scsi_toc_toc *toc; 477 status_t res; 478 int start_track, end_track; 479 scsi_play_position position; 480 481 TRACE("play_track_index(): %d-%d\n", buf->start_track, buf->end_track); 482 483 // the corresponding command PLAY AUDIO TRACK/INDEX is deprecated, 484 // so we have to simulate it by converting track to time via TOC 485 res = get_toc(info, &generic_toc); 486 if (res != B_OK) 487 return res; 488 489 toc = (scsi_toc_toc *)&generic_toc.toc_data[0]; 490 491 start_track = buf->start_track; 492 end_track = buf->end_track; 493 494 if (start_track > toc->last_track) 495 return B_BAD_INDEX; 496 497 if (end_track > toc->last_track) 498 end_track = toc->last_track + 1; 499 500 if (end_track < toc->last_track + 1) 501 ++end_track; 502 503 start_track -= toc->first_track; 504 end_track -= toc->first_track; 505 506 if (start_track < 0 || end_track < 0) 507 return B_BAD_INDEX; 508 509 position.start_m = toc->tracks[start_track].start.time.minute; 510 position.start_s = toc->tracks[start_track].start.time.second; 511 position.start_f = toc->tracks[start_track].start.time.frame; 512 513 position.end_m = toc->tracks[end_track].start.time.minute; 514 position.end_s = toc->tracks[end_track].start.time.second; 515 position.end_f = toc->tracks[end_track].start.time.frame; 516 517 return play_msf(info, &position); 518 } 519 520 521 static status_t 522 stop_audio(cd_driver_info *info) 523 { 524 scsi_cmd_stop_play cmd; 525 526 TRACE("stop_audio()\n"); 527 528 memset( &cmd, 0, sizeof( cmd )); 529 cmd.opcode = SCSI_OP_STOP_PLAY; 530 531 return sSCSIPeripheral->simple_exec(info->scsi_periph_device, 532 &cmd, sizeof(cmd), NULL, 0, SCSI_DIR_NONE); 533 } 534 535 536 static status_t 537 pause_resume(cd_driver_info *info, bool resume) 538 { 539 scsi_cmd_pause_resume cmd; 540 541 TRACE("pause_resume()\n"); 542 543 memset(&cmd, 0, sizeof(cmd)); 544 cmd.opcode = SCSI_OP_PAUSE_RESUME; 545 cmd.resume = resume; 546 547 return sSCSIPeripheral->simple_exec(info->scsi_periph_device, 548 &cmd, sizeof(cmd), NULL, 0, SCSI_DIR_NONE); 549 } 550 551 552 static status_t 553 scan(cd_driver_info *info, const scsi_scan *buf) 554 { 555 scsi_cmd_scan cmd; 556 scsi_position curPos; 557 scsi_cd_current_position *cdPos; 558 559 TRACE("scan(direction =% d)\n", buf->direction); 560 561 status_t res = get_position(info, &curPos); 562 if (res != B_OK) 563 return res; 564 565 cdPos = (scsi_cd_current_position *)((char *)&curPos 566 + sizeof(scsi_subchannel_data_header)); 567 568 if (buf->direction == 0) { 569 scsi_play_position playPos; 570 571 // to stop scan, we issue play command with "open end" 572 playPos.start_m = cdPos->absolute_address.time.minute; 573 playPos.start_s = cdPos->absolute_address.time.second; 574 playPos.start_f = cdPos->absolute_address.time.frame; 575 playPos.end_m = 99; 576 playPos.end_s = 59; 577 playPos.end_f = 24; 578 579 return play_msf(info, &playPos); 580 } 581 582 memset(&cmd, 0, sizeof(cmd)); 583 584 cmd.opcode = SCSI_OP_SCAN; 585 cmd.direct = buf->direction < 0; 586 cmd.start.time = cdPos->absolute_address.time; 587 cmd.type = scsi_scan_msf; 588 589 /* 590 tmp = (uint8 *)&cmd; 591 dprintf("%d %d %d %d %d %d %d %d %d %d %d %d\n", 592 tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], 593 tmp[6], tmp[7], tmp[8], tmp[9], tmp[10], tmp[11]); 594 */ 595 596 return sSCSIPeripheral->simple_exec(info->scsi_periph_device, 597 &cmd, sizeof(cmd), NULL, 0, SCSI_DIR_NONE); 598 } 599 600 601 static status_t 602 read_cd(cd_driver_info *info, const scsi_read_cd *readCD) 603 { 604 scsi_cmd_read_cd *cmd; 605 uint32 lba, length; 606 scsi_ccb *ccb; 607 status_t res; 608 609 // we use safe_exec instead of simple_exec as we want to set 610 // the sorting order manually (only makes much sense if you grab 611 // multiple tracks at once, but we are prepared) 612 ccb = info->scsi->alloc_ccb(info->scsi_device); 613 614 if (ccb == NULL) 615 return B_NO_MEMORY; 616 617 cmd = (scsi_cmd_read_cd *)ccb->cdb; 618 memset(cmd, 0, sizeof(*cmd)); 619 cmd->opcode = SCSI_OP_READ_CD; 620 cmd->sector_type = 1; 621 622 // skip first two seconds, they are lead-in 623 lba = (readCD->start_m * 60 + readCD->start_s) * 75 + readCD->start_f 624 - 2 * 75; 625 length = (readCD->length_m * 60 + readCD->length_s) * 75 + readCD->length_f; 626 627 cmd->lba = B_HOST_TO_BENDIAN_INT32(lba); 628 cmd->high_length = (length >> 16) & 0xff; 629 cmd->mid_length = (length >> 8) & 0xff; 630 cmd->low_length = length & 0xff; 631 632 cmd->error_field = scsi_read_cd_error_none; 633 cmd->edc_ecc = 0; 634 cmd->user_data = 1; 635 cmd->header_code = scsi_read_cd_header_none; 636 cmd->sync = 0; 637 cmd->sub_channel_selection = scsi_read_cd_sub_channel_none; 638 639 ccb->cdb_length = sizeof(*cmd); 640 641 ccb->flags = SCSI_DIR_IN | SCSI_DIS_DISCONNECT; 642 ccb->sort = lba; 643 // are 10 seconds enough for timeout? 644 ccb->timeout = 10; 645 646 // TODO: we pass a user buffer here! 647 ccb->data = (uint8 *)readCD->buffer; 648 ccb->sg_list = NULL; 649 ccb->data_length = readCD->buffer_length; 650 651 res = sSCSIPeripheral->safe_exec(info->scsi_periph_device, ccb); 652 653 info->scsi->free_ccb(ccb); 654 655 return res; 656 } 657 658 659 static int 660 log2(uint32 x) 661 { 662 int y; 663 664 for (y = 31; y >= 0; --y) { 665 if (x == (1UL << y)) 666 break; 667 } 668 669 return y; 670 } 671 672 673 static status_t 674 do_io(void* cookie, IOOperation* operation) 675 { 676 cd_driver_info* info = (cd_driver_info*)cookie; 677 678 // TODO: this can go away as soon as we pushed the IOOperation to the upper 679 // layers - we can then set scsi_periph::io() as callback for the scheduler 680 size_t bytesTransferred; 681 status_t status = sSCSIPeripheral->io(info->scsi_periph_device, operation, 682 &bytesTransferred); 683 684 info->io_scheduler->OperationCompleted(operation, status, bytesTransferred); 685 return status; 686 } 687 688 689 // #pragma mark - device module API 690 691 692 static status_t 693 cd_init_device(void* _info, void** _cookie) 694 { 695 cd_driver_info* info = (cd_driver_info*)_info; 696 697 // and get (initial) capacity 698 status_t status = update_capacity(info); 699 if (status != B_OK) 700 return status; 701 702 *_cookie = info; 703 return B_OK; 704 } 705 706 707 static void 708 cd_uninit_device(void* _cookie) 709 { 710 cd_driver_info* info = (cd_driver_info*)_cookie; 711 712 delete info->io_scheduler; 713 delete info->dma_resource; 714 } 715 716 717 static status_t 718 cd_open(void* _info, const char* path, int openMode, void** _cookie) 719 { 720 cd_driver_info* info = (cd_driver_info*)_info; 721 722 cd_handle* handle = (cd_handle*)malloc(sizeof(cd_handle)); 723 if (handle == NULL) 724 return B_NO_MEMORY; 725 726 handle->info = info; 727 728 status_t status = sSCSIPeripheral->handle_open(info->scsi_periph_device, 729 (periph_handle_cookie)handle, &handle->scsi_periph_handle); 730 if (status < B_OK) { 731 free(handle); 732 return status; 733 } 734 735 *_cookie = handle; 736 return B_OK; 737 } 738 739 740 static status_t 741 cd_close(void* cookie) 742 { 743 cd_handle* handle = (cd_handle*)cookie; 744 TRACE("close()\n"); 745 746 sSCSIPeripheral->handle_close(handle->scsi_periph_handle); 747 return B_OK; 748 } 749 750 751 static status_t 752 cd_free(void* cookie) 753 { 754 cd_handle* handle = (cd_handle*)cookie; 755 TRACE("free()\n"); 756 757 sSCSIPeripheral->handle_free(handle->scsi_periph_handle); 758 free(handle); 759 return B_OK; 760 } 761 762 763 static status_t 764 cd_read(void* cookie, off_t pos, void* buffer, size_t* _length) 765 { 766 cd_handle* handle = (cd_handle*)cookie; 767 size_t length = *_length; 768 769 if (handle->info->capacity == 0) 770 return B_DEV_NO_MEDIA; 771 772 IORequest request; 773 status_t status = request.Init(pos, (addr_t)buffer, length, false, 0); 774 if (status != B_OK) 775 return status; 776 777 status = handle->info->io_scheduler->ScheduleRequest(&request); 778 if (status != B_OK) 779 return status; 780 781 status = request.Wait(0, 0); 782 if (status == B_OK) 783 *_length = length; 784 else 785 dprintf("cd_read(): request.Wait() returned: %s\n", strerror(status)); 786 787 return status; 788 } 789 790 791 static status_t 792 cd_write(void* cookie, off_t pos, const void* buffer, size_t* _length) 793 { 794 cd_handle* handle = (cd_handle*)cookie; 795 size_t length = *_length; 796 797 if (handle->info->capacity == 0) 798 return B_DEV_NO_MEDIA; 799 800 IORequest request; 801 status_t status = request.Init(pos, (addr_t)buffer, length, true, 0); 802 if (status != B_OK) 803 return status; 804 805 status = handle->info->io_scheduler->ScheduleRequest(&request); 806 if (status != B_OK) 807 return status; 808 809 status = request.Wait(0, 0); 810 if (status == B_OK) 811 *_length = length; 812 else 813 dprintf("cd_write(): request.Wait() returned: %s\n", strerror(status)); 814 815 return status; 816 } 817 818 819 static status_t 820 cd_io(void* cookie, io_request* request) 821 { 822 cd_handle* handle = (cd_handle*)cookie; 823 824 if (handle->info->capacity == 0) { 825 notify_io_request(request, B_DEV_NO_MEDIA); 826 return B_DEV_NO_MEDIA; 827 } 828 829 return handle->info->io_scheduler->ScheduleRequest(request); 830 } 831 832 833 static status_t 834 cd_ioctl(void* cookie, uint32 op, void* buffer, size_t length) 835 { 836 cd_handle* handle = (cd_handle*)cookie; 837 cd_driver_info *info = handle->info; 838 839 TRACE("ioctl(op = %lu)\n", op); 840 841 switch (op) { 842 case B_GET_DEVICE_SIZE: 843 { 844 status_t status = update_capacity(info); 845 if (status != B_OK) 846 return status; 847 848 size_t size = info->capacity * info->block_size; 849 return user_memcpy(buffer, &size, sizeof(size_t)); 850 } 851 852 case B_GET_GEOMETRY: 853 { 854 if (buffer == NULL /*|| length != sizeof(device_geometry)*/) 855 return B_BAD_VALUE; 856 857 device_geometry geometry; 858 status_t status = get_geometry(handle, &geometry); 859 if (status != B_OK) 860 return status; 861 862 return user_memcpy(buffer, &geometry, sizeof(device_geometry)); 863 } 864 865 case B_GET_ICON_NAME: 866 return user_strlcpy((char*)buffer, "devices/drive-optical", 867 B_FILE_NAME_LENGTH); 868 869 case B_GET_VECTOR_ICON: 870 { 871 device_icon iconData; 872 if (length != sizeof(device_icon)) 873 return B_BAD_VALUE; 874 if (user_memcpy(&iconData, buffer, sizeof(device_icon)) != B_OK) 875 return B_BAD_ADDRESS; 876 877 if (iconData.icon_size >= (int32)sizeof(kCDIcon)) { 878 if (user_memcpy(iconData.icon_data, kCDIcon, 879 sizeof(kCDIcon)) != B_OK) 880 return B_BAD_ADDRESS; 881 } 882 883 iconData.icon_size = sizeof(kCDIcon); 884 return user_memcpy(buffer, &iconData, sizeof(device_icon)); 885 } 886 887 case B_SCSI_GET_TOC: 888 // TODO: we pass a user buffer here! 889 return get_toc(info, (scsi_toc *)buffer); 890 891 case B_EJECT_DEVICE: 892 case B_SCSI_EJECT: 893 return load_eject(info, false); 894 895 case B_LOAD_MEDIA: 896 return load_eject(info, true); 897 898 case B_SCSI_GET_POSITION: 899 { 900 if (buffer == NULL) 901 return B_BAD_VALUE; 902 903 scsi_position position; 904 status_t status = get_position(info, &position); 905 if (status != B_OK) 906 return status; 907 908 return user_memcpy(buffer, &position, sizeof(scsi_position)); 909 } 910 911 case B_SCSI_GET_VOLUME: 912 // TODO: we pass a user buffer here! 913 return get_set_volume(info, (scsi_volume *)buffer, false); 914 case B_SCSI_SET_VOLUME: 915 // TODO: we pass a user buffer here! 916 return get_set_volume(info, (scsi_volume *)buffer, true); 917 918 case B_SCSI_PLAY_TRACK: 919 { 920 scsi_play_track track; 921 if (user_memcpy(&track, buffer, sizeof(scsi_play_track)) != B_OK) 922 return B_BAD_ADDRESS; 923 924 return play_track_index(info, &track); 925 } 926 case B_SCSI_PLAY_POSITION: 927 { 928 scsi_play_position position; 929 if (user_memcpy(&position, buffer, sizeof(scsi_play_position)) 930 != B_OK) 931 return B_BAD_ADDRESS; 932 933 return play_msf(info, &position); 934 } 935 936 case B_SCSI_STOP_AUDIO: 937 return stop_audio(info); 938 case B_SCSI_PAUSE_AUDIO: 939 return pause_resume(info, false); 940 case B_SCSI_RESUME_AUDIO: 941 return pause_resume(info, true); 942 943 case B_SCSI_SCAN: 944 { 945 scsi_scan scanBuffer; 946 if (user_memcpy(&scanBuffer, buffer, sizeof(scsi_scan)) != B_OK) 947 return B_BAD_ADDRESS; 948 949 return scan(info, &scanBuffer); 950 } 951 case B_SCSI_READ_CD: 952 // TODO: we pass a user buffer here! 953 return read_cd(info, (scsi_read_cd *)buffer); 954 955 default: 956 return sSCSIPeripheral->ioctl(handle->scsi_periph_handle, op, 957 buffer, length); 958 } 959 } 960 961 962 // #pragma mark - scsi_periph callbacks 963 964 965 static void 966 cd_set_capacity(cd_driver_info* info, uint64 capacity, uint32 blockSize) 967 { 968 TRACE("cd_set_capacity(info = %p, capacity = %Ld, blockSize = %ld)\n", 969 info, capacity, blockSize); 970 971 // get log2, if possible 972 uint32 blockShift = log2(blockSize); 973 974 if ((1UL << blockShift) != blockSize) 975 blockShift = 0; 976 977 if (info->block_size != blockSize) { 978 if (capacity == 0) { 979 // there is obviously no medium in the drive, don't try to update 980 // the DMA resource 981 return; 982 } 983 984 if (info->block_size != 0) { 985 dprintf("old %ld, new %ld\n", info->block_size, blockSize); 986 panic("updating DMAResource not yet implemented..."); 987 } 988 989 // TODO: we need to replace the DMAResource in our IOScheduler 990 status_t status = info->dma_resource->Init(info->node, blockSize, 1024, 991 32); 992 if (status != B_OK) 993 panic("initializing DMAResource failed: %s", strerror(status)); 994 995 // Allocate the I/O scheduler. If there seems to be sufficient memory 996 // we use an IOCache, since that adds caching at the lowest I/O layer 997 // and thus dramatically reduces I/O operations and seeks. The 998 // disadvantage is that it increases free memory (physical pages) 999 // fragmentation, which makes large contiguous allocations more likely 1000 // to fail. 1001 size_t freeMemory = vm_page_num_free_pages(); 1002 if (freeMemory > 180 * 1024 * 1024 / B_PAGE_SIZE) { 1003 info->io_scheduler = new(std::nothrow) IOCache(info->dma_resource, 1004 1024 * 1024); 1005 } else { 1006 dprintf("scsi_cd: Using IOSchedulerSimple instead of IOCache to " 1007 "avoid memory allocation issues.\n"); 1008 info->io_scheduler = new(std::nothrow) IOSchedulerSimple( 1009 info->dma_resource); 1010 } 1011 1012 if (info->io_scheduler == NULL) 1013 panic("allocating IOScheduler failed."); 1014 1015 // TODO: use whole device name here 1016 status = info->io_scheduler->Init("scsi"); 1017 if (status != B_OK) 1018 panic("initializing IOScheduler failed: %s", strerror(status)); 1019 1020 info->io_scheduler->SetCallback(do_io, info); 1021 info->block_size = blockSize; 1022 } 1023 1024 if (info->original_capacity != capacity && info->io_scheduler != NULL) { 1025 info->original_capacity = capacity; 1026 1027 // For CDs, it's obviously relatively normal that they report a larger 1028 // capacity than it can actually address. Therefore we'll manually 1029 // correct the value here. 1030 test_capacity(info); 1031 1032 info->io_scheduler->SetDeviceCapacity(info->capacity * blockSize); 1033 } 1034 } 1035 1036 1037 static void 1038 cd_media_changed(cd_driver_info* info, scsi_ccb* request) 1039 { 1040 // do a capacity check 1041 // TODO: is this a good idea (e.g. if this is an empty CD)? 1042 info->original_capacity = 0; 1043 info->capacity = 0; 1044 sSCSIPeripheral->check_capacity(info->scsi_periph_device, request); 1045 1046 if (info->io_scheduler != NULL) 1047 info->io_scheduler->MediaChanged(); 1048 } 1049 1050 1051 scsi_periph_callbacks callbacks = { 1052 (void (*)(periph_device_cookie, uint64, uint32))cd_set_capacity, 1053 (void (*)(periph_device_cookie, scsi_ccb *))cd_media_changed 1054 }; 1055 1056 1057 // #pragma mark - driver module API 1058 1059 1060 static float 1061 cd_supports_device(device_node* parent) 1062 { 1063 const char* bus; 1064 uint8 deviceType; 1065 1066 // make sure parent is really the SCSI bus manager 1067 if (sDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 1068 return -1; 1069 1070 if (strcmp(bus, "scsi")) 1071 return 0.0; 1072 1073 // check whether it's really a CD-ROM or WORM 1074 if (sDeviceManager->get_attr_uint8(parent, SCSI_DEVICE_TYPE_ITEM, 1075 &deviceType, true) != B_OK 1076 || (deviceType != scsi_dev_CDROM && deviceType != scsi_dev_WORM)) 1077 return 0.0; 1078 1079 return 0.6; 1080 } 1081 1082 1083 /*! Called whenever a new device was added to system; 1084 if we really support it, we create a new node that gets 1085 server by the block_io module 1086 */ 1087 static status_t 1088 cd_register_device(device_node* node) 1089 { 1090 const scsi_res_inquiry* deviceInquiry = NULL; 1091 size_t inquiryLength; 1092 uint32 maxBlocks; 1093 1094 // get inquiry data 1095 if (sDeviceManager->get_attr_raw(node, SCSI_DEVICE_INQUIRY_ITEM, 1096 (const void**)&deviceInquiry, &inquiryLength, true) != B_OK 1097 || inquiryLength < sizeof(deviceInquiry)) 1098 return B_ERROR; 1099 1100 // get block limit of underlying hardware to lower it (if necessary) 1101 if (sDeviceManager->get_attr_uint32(node, B_DMA_MAX_TRANSFER_BLOCKS, 1102 &maxBlocks, true) != B_OK) 1103 maxBlocks = INT_MAX; 1104 1105 // using 10 byte commands, at most 0xffff blocks can be transmitted at once 1106 // (sadly, we cannot update this value later on if only 6 byte commands 1107 // are supported, but the block_io module can live with that) 1108 maxBlocks = min_c(maxBlocks, 0xffff); 1109 1110 // ready to register 1111 device_attr attrs[] = { 1112 {"removable", B_UINT8_TYPE, {ui8: deviceInquiry->removable_medium}}, 1113 {B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, {ui32: maxBlocks}}, 1114 { NULL } 1115 }; 1116 1117 return sDeviceManager->register_node(node, SCSI_CD_DRIVER_MODULE_NAME, 1118 attrs, NULL, NULL); 1119 } 1120 1121 1122 static status_t 1123 cd_init_driver(device_node* node, void** _cookie) 1124 { 1125 TRACE("cd_init_driver"); 1126 1127 uint8 removable; 1128 status_t status = sDeviceManager->get_attr_uint8(node, "removable", 1129 &removable, false); 1130 if (status != B_OK) 1131 return status; 1132 1133 cd_driver_info* info = (cd_driver_info*)malloc(sizeof(cd_driver_info)); 1134 if (info == NULL) 1135 return B_NO_MEMORY; 1136 1137 memset(info, 0, sizeof(cd_driver_info)); 1138 1139 info->dma_resource = new(std::nothrow) DMAResource; 1140 if (info->dma_resource == NULL) { 1141 free(info); 1142 return B_NO_MEMORY; 1143 } 1144 1145 info->node = node; 1146 info->removable = removable; 1147 1148 // set capacity to zero, so it get checked on first opened handle 1149 info->original_capacity = 0; 1150 info->capacity = 0; 1151 info->block_size = 0; 1152 1153 sDeviceManager->get_attr_uint8(node, SCSI_DEVICE_TYPE_ITEM, 1154 &info->device_type, true); 1155 1156 device_node *parent = sDeviceManager->get_parent_node(node); 1157 sDeviceManager->get_driver(parent, (driver_module_info**)&info->scsi, 1158 (void**)&info->scsi_device); 1159 sDeviceManager->put_node(parent); 1160 1161 status = sSCSIPeripheral->register_device((periph_device_cookie)info, 1162 &callbacks, info->scsi_device, info->scsi, info->node, 1163 info->removable, 10, &info->scsi_periph_device); 1164 if (status != B_OK) { 1165 free(info); 1166 return status; 1167 } 1168 1169 *_cookie = info; 1170 return B_OK; 1171 } 1172 1173 1174 static void 1175 cd_uninit_driver(void* _cookie) 1176 { 1177 cd_driver_info* info = (cd_driver_info*)_cookie; 1178 1179 sSCSIPeripheral->unregister_device(info->scsi_periph_device); 1180 free(info); 1181 } 1182 1183 1184 static status_t 1185 cd_register_child_devices(void* _cookie) 1186 { 1187 cd_driver_info* info = (cd_driver_info*)_cookie; 1188 1189 char* name = sSCSIPeripheral->compose_device_name(info->node, "disk/scsi"); 1190 if (name == NULL) 1191 return B_ERROR; 1192 1193 status_t status = sDeviceManager->publish_device(info->node, name, 1194 SCSI_CD_DEVICE_MODULE_NAME); 1195 1196 free(name); 1197 return status; 1198 } 1199 1200 1201 module_dependency module_dependencies[] = { 1202 {SCSI_PERIPH_MODULE_NAME, (module_info**)&sSCSIPeripheral}, 1203 {B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&sDeviceManager}, 1204 {} 1205 }; 1206 1207 struct device_module_info sSCSICDDevice = { 1208 { 1209 SCSI_CD_DEVICE_MODULE_NAME, 1210 0, 1211 NULL 1212 }, 1213 1214 cd_init_device, 1215 cd_uninit_device, 1216 NULL, // remove, 1217 1218 cd_open, 1219 cd_close, 1220 cd_free, 1221 cd_read, 1222 cd_write, 1223 cd_io, 1224 cd_ioctl, 1225 1226 NULL, // select 1227 NULL, // deselect 1228 }; 1229 1230 struct driver_module_info sSCSICDDriver = { 1231 { 1232 SCSI_CD_DRIVER_MODULE_NAME, 1233 0, 1234 NULL 1235 }, 1236 1237 cd_supports_device, 1238 cd_register_device, 1239 cd_init_driver, 1240 cd_uninit_driver, 1241 cd_register_child_devices, 1242 NULL, // rescan 1243 NULL, // removed 1244 }; 1245 1246 module_info* modules[] = { 1247 (module_info*)&sSCSICDDriver, 1248 (module_info*)&sSCSICDDevice, 1249 NULL 1250 }; 1251