1/* 2 File: AppleSCSIPDT00Emulator.cpp 3 4 Contains: 5 6 Version: 1.0.0 7 8 Copyright: Copyright (c) 2007 by Apple Inc., All Rights Reserved. 9 10Disclaimer:IMPORTANT: This Apple software is supplied to you by Apple Inc. 11("Apple") in consideration of your agreement to the following terms, and your use, 12installation, modification or redistribution of this Apple software constitutes acceptance 13of these terms. If you do not agree with these terms, please do not use, install, modify or 14redistribute this Apple software. 15 16In consideration of your agreement to abide by the following terms, and subject 17to these terms, Apple grants you a personal, non-exclusive license, under Apple's 18copyrights in this original Apple software (the "Apple Software"), to use, reproduce, 19modify and redistribute the Apple Software, with or without modifications, in source and/or 20binary forms; provided that if you redistribute the Apple Software in its entirety 21and without modifications, you must retain this notice and the following text 22and disclaimers in all such redistributions of the Apple Software. Neither the 23name, trademarks, service marks or logos of Apple Inc. may be used to 24endorse or promote products derived from the Apple Software without specific prior 25written permission from Apple. Except as expressly stated in this notice, no 26other rights or licenses, express or implied, are granted by Apple herein, 27including but not limited to any patent rights that may be infringed by your derivative 28works or by other works in which the Apple Software may be incorporated. 29 30The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO WARRANTIES, 31EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, 32MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE 33OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE 34BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 35NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 36OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 37REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED 38AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT 39LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40*/ 41 42 43//----------------------------------------------------------------------------- 44// Includes 45//----------------------------------------------------------------------------- 46 47#include "AppleSCSIPDT00Emulator.h" 48 49#include <IOKit/IOMemoryDescriptor.h> 50 51#include <IOKit/scsi/SCSICommandOperationCodes.h> 52#include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h> 53#include <IOKit/scsi/SCSICmds_REPORT_LUNS_Definitions.h> 54#include <IOKit/scsi/SCSICmds_READ_CAPACITY_Definitions.h> 55 56 57//----------------------------------------------------------------------------- 58// Macros 59//----------------------------------------------------------------------------- 60 61#define DEBUG 1 62#define DEBUG_ASSERT_COMPONENT_NAME_STRING "PDT00Emulator" 63 64#if DEBUG 65#define EMULATOR_ADAPTER_DEBUGGING_LEVEL 4 66#endif 67 68#include "DebugSupport.h" 69 70#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 1 ) 71#define PANIC_NOW(x) panic x 72#else 73#define PANIC_NOW(x) 74#endif 75 76#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 2 ) 77#define ERROR_LOG(x) IOLog x; IOSleep(1) 78#else 79#define ERROR_LOG(x) 80#endif 81 82#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 3 ) 83#define STATUS_LOG(x) IOLog x; IOSleep(1) 84#else 85#define STATUS_LOG(x) 86#endif 87 88#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 4 ) 89#define COMMAND_LOG(x) IOLog x; IOSleep(1) 90#else 91#define COMMAND_LOG(x) 92#endif 93 94 95#define super AppleSCSILogicalUnitEmulator 96OSDefineMetaClassAndStructors ( AppleSCSIPDT00Emulator, AppleSCSILogicalUnitEmulator ); 97 98 99//----------------------------------------------------------------------------- 100// WithCapacity 101//----------------------------------------------------------------------------- 102 103AppleSCSIPDT00Emulator * 104AppleSCSIPDT00Emulator::WithCapacity ( UInt64 capacity ) 105{ 106 107 AppleSCSIPDT00Emulator * logicalUnit = NULL; 108 bool result = false; 109 110 STATUS_LOG ( ( "AppleSCSIPDT00Emulator::WithCapacity, capacity = %qd\n", capacity ) ); 111 112 logicalUnit = OSTypeAlloc ( AppleSCSIPDT00Emulator ); 113 require_nonzero ( logicalUnit, ErrorExit ); 114 115 result = logicalUnit->InitWithCapacity ( capacity ); 116 require ( result, ReleaseLogicalUnit ); 117 118 return logicalUnit; 119 120 121ReleaseLogicalUnit: 122 123 124 logicalUnit->release ( ); 125 126 127ErrorExit: 128 129 130 return NULL; 131 132} 133 134 135//----------------------------------------------------------------------------- 136// InitWithCapacity 137//----------------------------------------------------------------------------- 138 139bool 140AppleSCSIPDT00Emulator::InitWithCapacity ( UInt64 capacity ) 141{ 142 143 fMemoryBuffer = IOBufferMemoryDescriptor::inTaskWithOptions ( 144 kernel_task, 145 0, 146 capacity, 147 PAGE_SIZE ); 148 149 require_nonzero ( fMemoryBuffer, ErrorExit ); 150 151 fMemory = ( UInt8 * ) fMemoryBuffer->getBytesNoCopy ( ); 152 fBufferSize = capacity; 153 154 return true; 155 156 157ErrorExit: 158 159 160 return false; 161 162} 163 164 165//----------------------------------------------------------------------------- 166// SetDeviceBuffers 167//----------------------------------------------------------------------------- 168 169bool 170AppleSCSIPDT00Emulator::SetDeviceBuffers ( 171 IOMemoryDescriptor * inquiryBuffer, 172 IOMemoryDescriptor * inquiryPage00Buffer, 173 IOMemoryDescriptor * inquiryPage80Buffer, 174 IOMemoryDescriptor * inquiryPage83Buffer ) 175{ 176 177 require_nonzero ( inquiryBuffer, ErrorExit ); 178 require_nonzero ( inquiryPage00Buffer, ErrorExit ); 179 require_nonzero ( inquiryPage80Buffer, ErrorExit ); 180 require_nonzero ( inquiryPage83Buffer, ErrorExit ); 181 182 fInquiryDataSize = inquiryBuffer->getLength ( ); 183 fInquiryPage00DataSize = inquiryPage00Buffer->getLength ( ); 184 fInquiryPage80DataSize = inquiryPage80Buffer->getLength ( ); 185 fInquiryPage83DataSize = inquiryPage83Buffer->getLength ( ); 186 187 ERROR_LOG ( ( "fInquiryDataSize = %d\n", fInquiryDataSize ) ); 188 ERROR_LOG ( ( "fInquiryPage00DataSize = %d\n", fInquiryPage00DataSize ) ); 189 ERROR_LOG ( ( "fInquiryPage80DataSize = %d\n", fInquiryPage80DataSize ) ); 190 ERROR_LOG ( ( "fInquiryPage83DataSize = %d\n", fInquiryPage83DataSize ) ); 191 192 fInquiryData = ( UInt8 * ) IOMalloc ( fInquiryDataSize ); 193 require_nonzero ( fInquiryData, ErrorExit ); 194 195 fInquiryPage00Data = ( UInt8 * ) IOMalloc ( fInquiryPage00DataSize ); 196 require_nonzero ( fInquiryPage00Data, ErrorExit ); 197 198 fInquiryPage80Data = ( UInt8 * ) IOMalloc ( fInquiryPage80DataSize ); 199 require_nonzero ( fInquiryPage80Data, ErrorExit ); 200 201 fInquiryPage83Data = ( UInt8 * ) IOMalloc ( fInquiryPage83DataSize ); 202 require_nonzero ( fInquiryPage83Data, ErrorExit ); 203 204 inquiryBuffer->readBytes ( 0, fInquiryData, fInquiryDataSize ); 205 inquiryPage00Buffer->readBytes ( 0, fInquiryPage00Data, fInquiryPage00DataSize ); 206 inquiryPage80Buffer->readBytes ( 0, fInquiryPage80Data, fInquiryPage80DataSize ); 207 inquiryPage83Buffer->readBytes ( 0, fInquiryPage83Data, fInquiryPage83DataSize ); 208 209 return true; 210 211 212ErrorExit: 213 214 215 return false; 216 217} 218 219 220//----------------------------------------------------------------------------- 221// free 222//----------------------------------------------------------------------------- 223 224void 225AppleSCSIPDT00Emulator::free ( void ) 226{ 227 228 STATUS_LOG ( ( "AppleSCSIPDT00Emulator::free\n" ) ); 229 230 if ( fMemoryBuffer != NULL ) 231 { 232 233 fMemoryBuffer->release ( ); 234 fMemoryBuffer = NULL; 235 236 } 237 238 if ( fInquiryData != NULL ) 239 { 240 241 IOFree ( fInquiryData, fInquiryDataSize ); 242 fInquiryData = NULL; 243 244 } 245 246 if ( fInquiryPage00Data != NULL ) 247 { 248 249 IOFree ( fInquiryPage00Data, fInquiryPage00DataSize ); 250 fInquiryPage00Data = NULL; 251 252 } 253 254 if ( fInquiryPage80Data != NULL ) 255 { 256 257 IOFree ( fInquiryPage80Data, fInquiryPage80DataSize ); 258 fInquiryPage80Data = NULL; 259 260 } 261 262 if ( fInquiryPage83Data != NULL ) 263 { 264 265 IOFree ( fInquiryPage83Data, fInquiryPage83DataSize ); 266 fInquiryPage83Data = NULL; 267 268 } 269 270 super::free ( ); 271 272} 273 274 275//----------------------------------------------------------------------------- 276// SendCommand 277//----------------------------------------------------------------------------- 278 279int 280AppleSCSIPDT00Emulator::SendCommand ( 281 UInt8 * cdb, 282 UInt8 cbdLen, 283 IOMemoryDescriptor * dataDesc, 284 UInt64 * dataLen, 285 SCSITaskStatus * scsiStatus, 286 SCSI_Sense_Data * senseBuffer, 287 UInt8 * senseBufferLen ) 288{ 289 290 UInt32 lba; 291 UInt16 transferLength; 292 UInt32 byteOffset; 293 UInt32 numBytes; 294 295 STATUS_LOG ( ( "AppleSCSIPDT00Emulator::sendCommand, LUN = %qd\n", GetLogicalUnitNumber ( ) ) ); 296 297 switch ( cdb[0] ) 298 { 299 300 case kSCSICmd_TEST_UNIT_READY: 301 { 302 303 COMMAND_LOG ( ( "SCSI Command: TEST_UNIT_READY\n" ) ); 304 305 *scsiStatus = kSCSITaskStatus_GOOD; 306 *dataLen = 0; 307 break; 308 309 } 310 311 case kSCSICmd_INQUIRY: 312 { 313 314 COMMAND_LOG ( ( "SCSI Command: INQUIRY\n" ) ); 315 316 if ( cdb[1] == 1 ) 317 { 318 319 UInt8 * buffer; 320 UInt64 amount; 321 322 COMMAND_LOG ( ( "INQUIRY VPD requested\n" ) ); 323 324 // Asking for EVPD. Return EVPD data based on PAGE_CODE parameter. 325 if ( cdb[2] == kINQUIRY_Page00_PageCode ) 326 { 327 328 COMMAND_LOG ( ( "Page 00h requested\n" ) ); 329 330 buffer = ( UInt8 * ) fInquiryPage00Data; 331 amount = fInquiryPage00DataSize; 332 333 } 334 335 else if ( cdb[2] == kINQUIRY_Page80_PageCode ) 336 { 337 338 COMMAND_LOG ( ( "Page 80h requested\n" ) ); 339 340 buffer = ( UInt8 * ) fInquiryPage80Data; 341 amount = fInquiryPage80DataSize; 342 343 } 344 345 else if ( cdb[2] == kINQUIRY_Page83_PageCode ) 346 { 347 348 COMMAND_LOG ( ( "Page 83h requested\n" ) ); 349 350 buffer = ( UInt8 * ) fInquiryPage83Data; 351 amount = fInquiryPage83DataSize; 352 353 } 354 355 if ( buffer != NULL ) 356 { 357 358 COMMAND_LOG ( ( "Requested = %llu\n", *dataLen ) ); 359 COMMAND_LOG ( ( "Amount = %llu\n", amount ) ); 360 361 *dataLen = min ( amount, *dataLen ); 362 dataDesc->writeBytes ( 0, buffer, *dataLen ); 363 364 COMMAND_LOG ( ( "Realized = %llu\n", *dataLen ) ); 365 366 *scsiStatus = kSCSITaskStatus_GOOD; 367 368 } 369 370 else 371 { 372 373 *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; 374 375 if ( senseBuffer != NULL ) 376 { 377 378 UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); 379 380 bzero ( senseBuffer, *senseBufferLen ); 381 bcopy ( &gInvalidCDBFieldSenseData, senseBuffer, amount ); 382 383 *senseBufferLen = amount; 384 385 } 386 387 } 388 389 } 390 391 else if ( ( cdb[1] == 2 ) || ( cdb[2] != 0 ) || ( cdb[3] != 0 ) ) 392 { 393 394 COMMAND_LOG ( ( "Illegal request\n" ) ); 395 396 // Don't support CMDDT bit, or PAGE_CODE without EVPD set. 397 *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; 398 399 if ( senseBuffer != NULL ) 400 { 401 402 UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); 403 404 bzero ( senseBuffer, *senseBufferLen ); 405 bcopy ( &gInvalidCDBFieldSenseData, senseBuffer, amount ); 406 407 *senseBufferLen = amount; 408 409 } 410 411 } 412 413 else 414 { 415 416 COMMAND_LOG ( ( "Standard INQUIRY\n" ) ); 417 418 *dataLen = min ( fInquiryDataSize, *dataLen ); 419 dataDesc->writeBytes ( 0, fInquiryData, *dataLen ); 420 421 *scsiStatus = kSCSITaskStatus_GOOD; 422 423 } 424 425 } 426 break; 427 428 case kSCSICmd_READ_CAPACITY: 429 { 430 431 SCSI_Capacity_Data data; 432 UInt32 lastBlock; 433 434 COMMAND_LOG ( ( "SCSI Command: READ_CAPACITY\n" ) ); 435 436 lastBlock = ( fBufferSize / kBlockSize ) - 1; 437 data.RETURNED_LOGICAL_BLOCK_ADDRESS = OSSwapHostToBigInt32 ( lastBlock ); 438 data.BLOCK_LENGTH_IN_BYTES = OSSwapHostToBigInt32 ( kBlockSize ); 439 440 *dataLen = min ( sizeof ( data ), *dataLen ); 441 442 dataDesc->writeBytes ( 0, &data, *dataLen ); 443 444 *scsiStatus = kSCSITaskStatus_GOOD; 445 446 } 447 break; 448 449 case kSCSICmd_WRITE_10: 450 { 451 452 lba = OSReadBigInt32 ( cdb, 2 ); 453 transferLength = OSReadBigInt16 ( cdb, 7 ); 454 455 byteOffset = lba * kBlockSize; 456 numBytes = transferLength * kBlockSize; 457 458 COMMAND_LOG ( ( "SCSI Command: WRITE_10 - %d (0x%X) bytes at 0x%X (ptr = %p)\n", numBytes, numBytes, byteOffset, &fMemory[byteOffset] ) ); 459 460 dataDesc->readBytes ( 0, &fMemory[byteOffset], numBytes ); 461 462 *scsiStatus = kSCSITaskStatus_GOOD; 463 464 } 465 break; 466 467 case kSCSICmd_READ_10: 468 { 469 470 lba = OSReadBigInt32 ( cdb, 2 ); 471 transferLength = OSReadBigInt16 ( cdb, 7 ); 472 473 byteOffset = lba * kBlockSize; 474 numBytes = transferLength * kBlockSize; 475 476 COMMAND_LOG ( ( "SCSI Command: READ_10 - %qd (0x%qX) bytes at 0x%X (ptr = %p)\n", *dataLen, *dataLen, byteOffset, &fMemory[byteOffset] ) ); 477 478 dataDesc->writeBytes ( 0, &fMemory[byteOffset], *dataLen ); 479 480 *scsiStatus = kSCSITaskStatus_GOOD; 481 482 } 483 break; 484 485 case kSCSICmd_START_STOP_UNIT: 486 { 487 488 COMMAND_LOG ( ( "SCSI Command: START_STOP_UNIT\n" ) ); 489 490 // For now just set the status to success. 491 *scsiStatus = kSCSITaskStatus_GOOD; 492 493 } 494 break; 495 496 case kSCSICmd_PREVENT_ALLOW_MEDIUM_REMOVAL: 497 { 498 499 COMMAND_LOG ( ( "SCSI Command: PREVENT_ALLOW_MEDIUM_REMOVAL - prevent = 0x%02X\n", cdb[4] & 0x03 ) ); 500 501 // We're not a changeable medium... safe to ignore for now 502 *scsiStatus = kSCSITaskStatus_GOOD; 503 *senseBufferLen = 0; 504 505 } 506 break; 507 508 case kSCSICmd_REQUEST_SENSE: 509 { 510 511 COMMAND_LOG ( ( "SCSI Command: REQUEST_SENSE (desc = %s, allocation length = %d bytes) - returning CHECK CONDITION with INVALID COMMAND\n", (cdb[1] & 0x01) ? "TRUE" : "FALSE", cdb[4] ) ); 512 513 *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; 514 *dataLen = 0; 515 516 if ( senseBuffer != NULL ) 517 { 518 519 UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); 520 521 bzero ( senseBuffer, *senseBufferLen ); 522 bcopy ( &gInvalidCommandSenseData, senseBuffer, amount ); 523 524 *senseBufferLen = amount; 525 526 } 527 528 } 529 break; 530 531 532 case kSCSICmd_MODE_SENSE_6: 533 { 534 535 SPCModeParameterHeader6 header; 536 537 COMMAND_LOG ( ( "SCSI Command: MODE_SENSE_6\n" ) ); 538 539 // We don't support any mode pages, but we support the mode parameter header. 540 // Just return the header. 541 *senseBufferLen = 0; 542 543 COMMAND_LOG ( ( "*dataLen = %llu, sizeof(header) = %lu\n", *dataLen, sizeof ( header ) ) ); 544 COMMAND_LOG ( ( "pageCode = 0x%02x\n", cdb[2] & 0x3FFFF ) ); 545 546 *dataLen = min ( sizeof ( header ), *dataLen ); 547 548 header.MODE_DATA_LENGTH = sizeof ( header ) - sizeof ( header.MODE_DATA_LENGTH ); 549 header.MEDIUM_TYPE = 0; // Must be 0h by SBC spec. 550 header.DEVICE_SPECIFIC_PARAMETER = 0; // Not write protected. Doesn't support DPOFUA. 551 header.BLOCK_DESCRIPTOR_LENGTH = 0; // No block descriptors. 552 553 COMMAND_LOG ( ( "header.MODE_DATA_LENGTH = %d, *dataLen = %llu\n", header.MODE_DATA_LENGTH, *dataLen ) ); 554 555 dataDesc->writeBytes ( 0, &header, *dataLen ); 556 557 *scsiStatus = kSCSITaskStatus_GOOD; 558 559 } 560 break; 561 562 case kSCSICmd_MODE_SENSE_10: 563 { 564 565 SPCModeParameterHeader10 header; 566 567 COMMAND_LOG ( ( "SCSI Command: MODE_SENSE_10\n" ) ); 568 569 // We don't support any mode pages, but we support the mode parameter header. 570 // Just return the header. 571 *senseBufferLen = 0; 572 573 COMMAND_LOG ( ( "*dataLen = %llu, sizeof(header) = %lu\n", *dataLen, sizeof ( header ) ) ); 574 COMMAND_LOG ( ( "pageCode = 0x%02x\n", cdb[2] & 0x3FFFF ) ); 575 576 *dataLen = min ( sizeof ( header ), *dataLen ); 577 578 header.MODE_DATA_LENGTH = sizeof ( header ) - sizeof ( header.MODE_DATA_LENGTH ); 579 header.MEDIUM_TYPE = 0; // Must be 0h by SBC spec. 580 header.DEVICE_SPECIFIC_PARAMETER = 0; // Not write protected. Doesn't support DPOFUA. 581 header.BLOCK_DESCRIPTOR_LENGTH = 0; // No block descriptors. 582 583 COMMAND_LOG ( ( "header.MODE_DATA_LENGTH = %d, *dataLen = %llu\n", header.MODE_DATA_LENGTH, *dataLen ) ); 584 585 dataDesc->writeBytes ( 0, &header, *dataLen ); 586 587 *scsiStatus = kSCSITaskStatus_GOOD; 588 589 } 590 break; 591 592 default: 593 { 594 595 COMMAND_LOG ( ( "SCSI Command: Unknown: 0x%X\n", cdb[0] ) ); 596 597 *scsiStatus = kSCSITaskStatus_CHECK_CONDITION; 598 599 if ( senseBuffer != NULL ) 600 { 601 602 UInt8 amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) ); 603 604 bzero ( senseBuffer, *senseBufferLen ); 605 bcopy ( &gInvalidCommandSenseData, senseBuffer, amount ); 606 607 *senseBufferLen = amount; 608 609 } 610 611 } 612 break; 613 614 } 615 616 return 1; 617 618}