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