1/* 2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 25//-------------------------------------------------------------------------------------------------- 26// Includes 27//-------------------------------------------------------------------------------------------------- 28 29 30// This class' header file 31#include "IOUSBMassStorageClass.h" 32#include "IOUSBMassStorageClassTimestamps.h" 33#include "Debugging.h" 34 35 36//-------------------------------------------------------------------------------------------------- 37// Macros 38//-------------------------------------------------------------------------------------------------- 39 40 41// Bulk Only State Machine States 42enum 43{ 44 45 kBulkOnlyCommandSent = 1, 46 kBulkOnlyCheckCBWBulkStall, 47 kBulkOnlyClearCBWBulkStall, 48 kBulkOnlyBulkIOComplete, 49 kBulkOnlyCheckBulkStall, 50 kBulkOnlyClearBulkStall, 51 kBulkOnlyCheckBulkStallPostCSW, 52 kBulkOnlyClearBulkStallPostCSW, 53 kBulkOnlyStatusReceived, 54 kBulkOnlyStatusReceived2ndTime, 55 kBulkOnlyResetCompleted, 56 kBulkOnlyClearBulkInCompleted, 57 kBulkOnlyClearBulkOutCompleted 58 59}; 60 61 62#pragma mark - 63#pragma mark Protocol Services Methods 64#pragma mark - 65 66 67//-------------------------------------------------------------------------------------------------- 68// AbortSCSICommandForBulkOnlyProtocol - The AbortSCSICommand helper method for Bulk Only protocol 69// devices. [PROTECTED] 70//-------------------------------------------------------------------------------------------------- 71 72IOReturn IOUSBMassStorageClass::AbortSCSICommandForBulkOnlyProtocol ( 73 SCSITaskIdentifier request ) 74{ 75 76 UNUSED ( request ); 77 78 return kIOReturnError; 79 80} 81 82 83//-------------------------------------------------------------------------------------------------- 84// SendSCSICommandForBulkOnlyProtocol - The SendSCSICommand helper method 85// for Bulk Only protocol devices. 86// [PROTECTED] 87//-------------------------------------------------------------------------------------------------- 88 89IOReturn IOUSBMassStorageClass::SendSCSICommandForBulkOnlyProtocol ( 90 SCSITaskIdentifier request ) 91{ 92 93 IOReturn status; 94 BulkOnlyRequestBlock * theBulkOnlyRB; 95 96 theBulkOnlyRB = GetBulkOnlyRequestBlock(); 97 98 // Clear out the CBW 99 bzero ( theBulkOnlyRB, sizeof ( BulkOnlyRequestBlock ) ); 100 101 // Save the SCSI Task 102 theBulkOnlyRB->request = request; 103 104 // Set up the IOUSBCompletion structure 105 theBulkOnlyRB->boCompletion.target = this; 106 theBulkOnlyRB->boCompletion.action = &this->BulkOnlyUSBCompletionAction; 107 theBulkOnlyRB->boCompletion.parameter = theBulkOnlyRB; 108 109 STATUS_LOG ( ( 6, "%s[%p]: SendSCSICommandForBulkOnlyProtocol send CBW", getName(), this ) ); 110 status = BulkOnlySendCBWPacket ( theBulkOnlyRB, kBulkOnlyCommandSent ); 111 STATUS_LOG ( ( 5, "%s[%p]: SendSCSICommandForBulkOnlyProtocol send CBW returned %x", getName(), this, status ) ); 112 113 return status; 114 115} 116 117 118#pragma mark - 119#pragma mark Bulk Only Protocol Specific Commands 120 121 122//-------------------------------------------------------------------------------------------------- 123// BulkDeviceResetDevice [PROTECTED] 124//-------------------------------------------------------------------------------------------------- 125 126IOReturn 127IOUSBMassStorageClass::BulkDeviceResetDevice ( 128 BulkOnlyRequestBlock * boRequestBlock, 129 UInt32 nextExecutionState ) 130{ 131 132 IOReturn status = kIOReturnDeviceError; 133 134 if ( fTerminating == true ) 135 { 136 137 // We have an invalid interface, the device has probably been removed. 138 // Nothing else to do except to report an error. 139 goto Exit; 140 141 } 142 143 // If bulk device reset is not an option, or if the previous command had also failed with a reset, 144 // then escalate to USB device reset. 145 if ( ( fUseUSBResetNotBOReset == true ) || ( fConsecutiveResetCount > 0 ) ) 146 { 147 148 STATUS_LOG ( ( 4, "%s[%p]: BulkDeviceResetDevice Escalating to DeviceReset", getName(), this, status ) ); 149 ResetDeviceNow ( false ); 150 status = kIOReturnSuccess; 151 goto Exit; 152 153 } 154 155 // Clear out the structure for the request 156 bzero ( &fUSBDeviceRequest, sizeof ( IOUSBDevRequest ) ); 157 158 // Build the USB command 159 fUSBDeviceRequest.bmRequestType = USBmakebmRequestType ( kUSBNone, kUSBClass, kUSBInterface ); 160 fUSBDeviceRequest.bRequest = 0xFF; 161 fUSBDeviceRequest.wValue = 0; 162 fUSBDeviceRequest.wIndex = GetInterfaceReference()->GetInterfaceNumber(); 163 fUSBDeviceRequest.wLength = 0; 164 fUSBDeviceRequest.pData = NULL; 165 166 // Set the next state to be executed 167 boRequestBlock->currentState = nextExecutionState; 168 169 // Send the command over the control endpoint 170 status = GetInterfaceReference()->DeviceRequest ( &fUSBDeviceRequest, &boRequestBlock->boCompletion ); 171 172Exit: 173 174 STATUS_LOG ( ( 4, "%s[%p]: BulkDeviceResetDevice returned %x", getName(), this, status ) ); 175 176 return status; 177 178} 179 180 181#pragma mark - 182#pragma mark SendSCSICommand Helper methods 183 184 185//-------------------------------------------------------------------------------------------------- 186// BulkOnlyUSBCompletionAction [PROTECTED] 187//-------------------------------------------------------------------------------------------------- 188 189void 190IOUSBMassStorageClass::BulkOnlyUSBCompletionAction ( 191 void * target, 192 void * parameter, 193 IOReturn status, 194 UInt32 bufferSizeRemaining) 195{ 196 197 IOUSBMassStorageClass * theMSC; 198 BulkOnlyRequestBlock * boRequestBlock; 199 200 theMSC = ( IOUSBMassStorageClass * ) target; 201 boRequestBlock = ( BulkOnlyRequestBlock * ) parameter; 202 theMSC->BulkOnlyExecuteCommandCompletion ( boRequestBlock, 203 status, 204 bufferSizeRemaining ); 205 206} 207 208 209//-------------------------------------------------------------------------------------------------- 210// BulkOnlySendCBWPacket - Prepare the Command Block Wrapper packet for Bulk Only Protocol 211// [PROTECTED] 212//-------------------------------------------------------------------------------------------------- 213 214IOReturn 215IOUSBMassStorageClass::BulkOnlySendCBWPacket ( 216 BulkOnlyRequestBlock * boRequestBlock, 217 UInt32 nextExecutionState ) 218{ 219 220 IOReturn status = kIOReturnError; 221 222 223 // Set our Bulk-Only phase descriptor. 224 require ( ( fBulkOnlyCBWMemoryDescriptor != NULL ), Exit ); 225 boRequestBlock->boPhaseDesc = fBulkOnlyCBWMemoryDescriptor; 226 227 boRequestBlock->boCBW.cbwSignature = kCommandBlockWrapperSignature; 228 boRequestBlock->boCBW.cbwTag = GetNextBulkOnlyCommandTag(); 229 boRequestBlock->boCBW.cbwTransferLength = HostToUSBLong( 230 GetRequestedDataTransferCount(boRequestBlock->request)); 231 if (GetDataTransferDirection(boRequestBlock->request) == 232 kSCSIDataTransfer_FromTargetToInitiator) 233 { 234 boRequestBlock->boCBW.cbwFlags = kCBWFlagsDataIn; 235 } 236 else if (GetDataTransferDirection(boRequestBlock->request) == 237 kSCSIDataTransfer_FromInitiatorToTarget) 238 { 239 boRequestBlock->boCBW.cbwFlags = kCBWFlagsDataOut; 240 } 241 else 242 { 243 boRequestBlock->boCBW.cbwFlags = 0; 244 } 245 246 // Set the LUN (not needed until LUN support is added). 247 boRequestBlock->boCBW.cbwLUN = GetLogicalUnitNumber( boRequestBlock->request ) & kCBWLUNMask; // Bits 0-3: LUN, 4-7: Reserved 248 boRequestBlock->boCBW.cbwCDBLength = GetCommandDescriptorBlockSize( boRequestBlock->request ); // Bits 0-4: CDB Length, 5-7: Reserved 249 GetCommandDescriptorBlock( boRequestBlock->request, &boRequestBlock->boCBW.cbwCDB ); 250 251 RecordUSBTimeStamp ( UMC_TRACE ( kBOCBWDescription ), 252 ( uintptr_t ) this, 253 ( uintptr_t ) boRequestBlock->request, 254 ( unsigned int ) boRequestBlock->boCBW.cbwLUN, 255 ( unsigned int ) boRequestBlock->boCBW.cbwTag ); 256 257 // Once timeouts are support, set the timeout value for the request 258 259 // Set the next state to be executed 260 boRequestBlock->currentState = nextExecutionState; 261 262 // Make sure our bulk out pipe is still valid before we try to use it. 263 require ( ( fBulkOutPipe != NULL ), Exit ); 264 265 // Send the CBW to the device 266 STATUS_LOG ( ( 6, "%s[%p]: BulkOnlySendCBWPacket sent", getName(), this ) ); 267 status = GetBulkOutPipe()->Write( boRequestBlock->boPhaseDesc, 268 GetTimeoutDuration( boRequestBlock->request ), // Use the client's timeout for both 269 GetTimeoutDuration( boRequestBlock->request ), 270 &boRequestBlock->boCompletion ); 271 STATUS_LOG ( ( 5, "%s[%p]: BulkOnlySendCBWPacket returned %x", getName(), this, status ) ); 272 273 RecordUSBTimeStamp ( UMC_TRACE ( kBOCBWBulkOutWriteResult ), ( uintptr_t ) this, status, 274 ( uintptr_t ) boRequestBlock->boCBW.cbwLUN, ( uintptr_t ) boRequestBlock->request ); 275 276 if ( status == kIOUSBPipeStalled ) 277 { 278 STATUS_LOG ( ( 5, "%s[%p]: BulkOnlySendCBWPacket could not be queued, returned", getName(), this ) ); 279 280 // The host is reporting a pipe stall. We'll need to address this if we ever wish to attempt a retry. 281 // We're relying on higher elements of the storage stack to initiate the retry. 282 boRequestBlock->currentState = kBulkOnlyCheckCBWBulkStall; 283 status = GetStatusEndpointStatus ( GetBulkOutPipe(), &boRequestBlock->boGetStatusBuffer, &boRequestBlock->boCompletion ); 284 285 } 286 287 288Exit: 289 290 return status; 291 292} 293 294 295//-------------------------------------------------------------------------------------------------- 296// BulkOnlyTransferData [PROTECTED] 297//-------------------------------------------------------------------------------------------------- 298 299IOReturn 300IOUSBMassStorageClass::BulkOnlyTransferData ( 301 BulkOnlyRequestBlock * boRequestBlock, 302 UInt32 nextExecutionState ) 303{ 304 305 IOReturn status = kIOReturnError; 306 307 // Set the next state to be executed 308 boRequestBlock->currentState = nextExecutionState; 309 310 // Start a bulk in or out transaction 311 if ( GetDataTransferDirection ( boRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 312 { 313#ifndef EMBEDDED 314 requireMaxBusStall ( 10000 ); 315 fRequiredMaxBusStall = 10000; 316#endif // EMBEDDED 317 status = GetBulkInPipe()->Read( 318 GetDataBuffer( boRequestBlock->request ), 319 GetTimeoutDuration( boRequestBlock->request ), // Use the client's timeout for both 320 GetTimeoutDuration( boRequestBlock->request ), 321 GetRequestedDataTransferCount( boRequestBlock->request ), 322 &boRequestBlock->boCompletion ); 323 324 } 325 else if ( GetDataTransferDirection(boRequestBlock->request) == kSCSIDataTransfer_FromInitiatorToTarget ) 326 { 327#ifndef EMBEDDED 328 requireMaxBusStall ( 10000 ); 329 fRequiredMaxBusStall = 10000; 330#endif // EMBEDDED 331 status = GetBulkOutPipe()->Write( 332 GetDataBuffer ( boRequestBlock->request ), 333 GetTimeoutDuration ( boRequestBlock->request ), // Use the client's timeout for both 334 GetTimeoutDuration ( boRequestBlock->request ), 335 GetRequestedDataTransferCount ( boRequestBlock->request ), 336 &boRequestBlock->boCompletion ); 337 } 338 339 STATUS_LOG ( ( 5, "%s[%p]: BulkOnlyTransferData returned %x", getName(), this, status ) ); 340 341 return status; 342 343} 344 345 346//-------------------------------------------------------------------------------------------------- 347// BulkOnlyReceiveCSWPacket - Prepare the Command Status Wrapper packet for Bulk Only Protocol. 348// [PROTECTED] 349//-------------------------------------------------------------------------------------------------- 350 351// 352IOReturn 353IOUSBMassStorageClass::BulkOnlyReceiveCSWPacket ( 354 BulkOnlyRequestBlock * boRequestBlock, 355 UInt32 nextExecutionState ) 356{ 357 358 IOReturn status = kIOReturnError; 359 360 // Set our Bulk-Only phase descriptor. 361 require ( ( fBulkOnlyCSWMemoryDescriptor != NULL ), Exit ); 362 boRequestBlock->boPhaseDesc = fBulkOnlyCSWMemoryDescriptor; 363 364 // Set the next state to be executed 365 boRequestBlock->currentState = nextExecutionState; 366 367 // Retrieve the CSW from the device 368 status = GetBulkInPipe()->Read ( boRequestBlock->boPhaseDesc, 369 GetTimeoutDuration( boRequestBlock->request ), // Use the client's timeout for both 370 GetTimeoutDuration( boRequestBlock->request ), 371 &boRequestBlock->boCompletion ); 372 373 STATUS_LOG ( ( 5, "%s[%p]: BulkOnlyReceiveCSWPacket returned %x", getName(), this, status ) ); 374 375 376Exit: 377 378 return status; 379 380} 381 382 383//-------------------------------------------------------------------------------------------------- 384// BulkOnlyExecuteCommandCompletion [PROTECTED] 385//-------------------------------------------------------------------------------------------------- 386 387void 388IOUSBMassStorageClass::BulkOnlyExecuteCommandCompletion ( 389 BulkOnlyRequestBlock * boRequestBlock, 390 IOReturn resultingStatus, 391 UInt32 bufferSizeRemaining) 392{ 393 394 IOReturn status = kIOReturnError; 395 bool commandInProgress = false; 396 bool abortCommand = false; 397 398 399 STATUS_LOG ( ( 4, "%s[%p]: BulkOnlyExecuteCommandCompletion Entered with boRequestBlock=%p currentState=%d resultingStatus=0x%x", getName(), this, boRequestBlock, boRequestBlock->currentState, resultingStatus ) ); 400 401#ifndef EMBEDDED 402 // Check to see if our expansion data is still valid. If we've already passed through free() it'll be NULL and 403 // access its members will cause us to kernel panic. This check exists to guard against callbacks received after 404 // driver termination. 405 if ( reserved == NULL ) 406 { 407 408 PANIC_NOW ( ( "IOUSBMassStorageClass::BulkOnlyExecuteCommandCompletion callback after driver has been freed" ) ); 409 return; 410 411 } 412 413 if ( fRequiredMaxBusStall != 0 ) 414 { 415 requireMaxBusStall ( 0 ); 416 fRequiredMaxBusStall = 0; 417 } 418#endif // EMBEDDED 419 420 if ( ( boRequestBlock->request == NULL ) || ( fBulkOnlyCommandStructInUse == false ) ) 421 { 422 // The request field is NULL, this appears to be a double callback, do nothing. 423 // OR the command was aborted earlier, do nothing. 424 STATUS_LOG ( ( 4, "%s[%p]: boRequestBlock->request is NULL, returned %x", getName(), this, resultingStatus ) ); 425 RecordUSBTimeStamp ( UMC_TRACE ( kBODoubleCompleteion ), ( uintptr_t ) this, NULL, NULL, NULL ); 426 return; 427 428 } 429 430 if ( ( GetInterfaceReference() == NULL ) || ( fTerminating == true ) ) 431 { 432 // Our interface has been closed, probably because of an 433 // unplug, return an error for the command since it can no 434 // longer be executed. 435 436 STATUS_LOG ( ( 4, "%s[%p]: Completion during termination", getName(), this ) ); 437 RecordUSBTimeStamp ( UMC_TRACE ( kBOCompletionDuringTermination ), ( uintptr_t ) this, NULL, NULL, NULL ); 438 439 goto Exit; 440 } 441 442 443 RecordUSBTimeStamp ( UMC_TRACE ( kBOCompletion ), ( uintptr_t ) this, resultingStatus, 444 ( uintptr_t ) boRequestBlock->currentState, ( uintptr_t ) boRequestBlock->request ); 445 446 if ( ( resultingStatus == kIOReturnNotResponding ) || ( resultingStatus == kIOReturnAborted ) ) 447 { 448 449 STATUS_LOG ( ( 5, "%s[%p]: BulkOnlyExecuteCommandCompletion previous command returned %x", getName(), this, resultingStatus ) ); 450 451 // The transfer failed mid-transfer or was aborted by the USB layer. Either way the device will 452 // be non-responsive until we reset it, or we discover it has been disconnected. 453 ResetDeviceNow ( false ); 454 commandInProgress = true; 455 456 goto Exit; 457 458 } 459 460 switch ( boRequestBlock->currentState ) 461 { 462 463 case kBulkOnlyCommandSent: 464 { 465 466 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyCommandSent returned %x cbwTag=0x%08x", getName(), this, resultingStatus, boRequestBlock->boCBW.cbwTag ) ); 467 468 if ( resultingStatus == kIOUSBPipeStalled ) 469 { 470 471 // The fUseUSBResetNotBOReset flag also implies that the device can't be set right with a Clear Pipe Stall. Reset time. 472 if ( fUseUSBResetNotBOReset ) 473 { 474 475 // By passing this to Finish device recovery we ensure that the driver is still active, 476 // and that the device is still connected to the Mac. 477 ResetDeviceNow ( false ); 478 status = kIOReturnSuccess; 479 480 } 481 else 482 { 483 484 // The host is reporting a pipe stall. We'll need to address this if we ever wish to attempt a retry. 485 // We're relying on higher elements of the storage stack to initate the retry. 486 boRequestBlock->currentState = kBulkOnlyCheckCBWBulkStall; 487 status = GetStatusEndpointStatus( GetBulkOutPipe(), &boRequestBlock->boGetStatusBuffer, &boRequestBlock->boCompletion ); 488 489 } 490 491 if ( status == kIOReturnSuccess ) 492 { 493 commandInProgress = true; 494 } 495 break; 496 497 } 498 499 if ( resultingStatus != kIOReturnSuccess ) 500 { 501 502 // An error occurred, probably a timeout error, 503 // and the command was not successfully sent to the device. 504 ResetDeviceNow ( false ); 505 status = kIOReturnSuccess; 506 507 if( status == kIOReturnSuccess ) 508 { 509 commandInProgress = true; 510 } 511 break; 512 513 } 514 515 // If there is to be no data transfer then we are done and can return to the caller. 516 if ( ( GetDataTransferDirection ( boRequestBlock->request ) == kSCSIDataTransfer_NoDataTransfer ) || 517 ( GetRequestedDataTransferCount ( boRequestBlock->request ) == 0 ) ) 518 { 519 520 // Bulk transfer is done, get the Command Status Wrapper from the device. 521 status = BulkOnlyReceiveCSWPacket ( boRequestBlock, kBulkOnlyStatusReceived ); 522 if ( status == kIOReturnSuccess ) 523 { 524 commandInProgress = true; 525 } 526 527 } 528 else 529 { 530 531 // Start a bulk in or out transaction. 532 status = BulkOnlyTransferData ( boRequestBlock, kBulkOnlyBulkIOComplete ); 533 if ( status == kIOReturnSuccess ) 534 { 535 commandInProgress = true; 536 } 537 538 } 539 540 } 541 break; 542 543 544 case kBulkOnlyCheckCBWBulkStall: 545 { 546 547 STATUS_LOG ( ( 5, "%s[%p]: IOUSBMassStorageClass::BulkOnlyExecuteCommandCompletion - kBulkOnlyCheckCBWBulkStall returned %x stalled=0x%x", getName(), this, resultingStatus, boRequestBlock->boGetStatusBuffer[0] ) ); 548 549 // Check to see if the endpoint was stalled 550 if ( ( boRequestBlock->boGetStatusBuffer[0] & 1 ) == 1 ) 551 { 552 553 STATUS_LOG ( ( 5, "%s[%p]: IOUSBMassStorageClass::BulkOnlyExecuteCommandCompletion - will try to clear endpoint", getName(), this ) ); 554 // The endpoint was stalled. Clear the stall so we'll be able to retry sending the CBW. 555 boRequestBlock->currentState = kBulkOnlyClearCBWBulkStall; 556 status = ClearFeatureEndpointStall ( GetBulkOutPipe(), &boRequestBlock->boCompletion ); 557 STATUS_LOG ( ( 5, "%s[%p]: IOUSBMassStorageClass::BulkOnlyExecuteCommandCompletion - ClearFeatureEndpointStall returned status = %x", getName(), this, status ) ); 558 if ( status == kIOReturnSuccess ) 559 { 560 commandInProgress = true; 561 } 562 563 } 564 else 565 { 566 567 STATUS_LOG ( ( 5, "%s[%p]: IOUSBMassStorageClass::BulkOnlyExecuteCommandCompletion - will reset", getName(), this ) ); 568 569 SetRealizedDataTransferCount ( boRequestBlock->request, 0 ); 570 571 // Since the pipe was not stalled, but the host thought it was we should reset the device. 572 status = BulkDeviceResetDevice( boRequestBlock, kBulkOnlyResetCompleted ); 573 574 if ( status == kIOReturnSuccess ) 575 { 576 commandInProgress = true; 577 } 578 579 } 580 581 } 582 break; 583 584 585 case kBulkOnlyClearCBWBulkStall: 586 { 587 588 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyClearCBWBulkStall returned %x", getName(), this, resultingStatus ) ); 589 590 // As we failed to successfully transmit the BO CBW we return an error up the stack so the command will be retried. 591 SetRealizedDataTransferCount ( boRequestBlock->request, 0 ); 592 status = kIOReturnError; 593 594 } 595 break; 596 597 598 case kBulkOnlyBulkIOComplete: 599 { 600 601 status = resultingStatus; // and status 602 603 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyBulkIOComplete returned %x", getName(), this, resultingStatus ) ); 604 605 if ( ( resultingStatus == kIOUSBPipeStalled ) || ( resultingStatus == kIOReturnSuccess ) ) 606 { 607 UInt64 realizedDataTransferCount = GetRequestedDataTransferCount ( boRequestBlock->request ) - bufferSizeRemaining; 608 609 // Save the number of bytes tranferred in the request 610 // Use the amount returned by USB to determine the amount of data transferred instead of 611 // the data residue field in the CSW since some devices will report the wrong value. 612 SetRealizedDataTransferCount ( boRequestBlock->request, realizedDataTransferCount ); 613 STATUS_LOG ( ( 5, "%s[%p]: bufferSizeRemaining=0x%x realizedDataTransferCount=0x%x", getName(), this, bufferSizeRemaining, realizedDataTransferCount ) ); 614 } 615 616 if ( resultingStatus == kIOReturnSuccess ) 617 { 618 // Bulk transfer is done, get the Command Status Wrapper from the device 619 status = BulkOnlyReceiveCSWPacket ( boRequestBlock, kBulkOnlyStatusReceived ); 620 if ( status == kIOReturnSuccess ) 621 { 622 commandInProgress = true; 623 } 624 625 } 626 else if ( resultingStatus == kIOReturnOverrun ) 627 { 628 629 // We set the data transfered to size of the request because the IOUSBFamily 630 // discards the excess for us. 631 632 SetRealizedDataTransferCount ( boRequestBlock->request, 633 GetRequestedDataTransferCount ( boRequestBlock->request ) ); 634 635 // Reset the device. We have to do a full device reset since a fair quantity of 636 // stellar USB devices don't properly handle a mid I/O Bulk-Only device reset. 637 ResetDeviceNow ( false ); 638 commandInProgress = true; 639 640 } 641 else 642 { 643 // Either an error occurred on transfer or we did not get all the data we requested. 644 // In either case, this transfer is complete, clean up and return an error to the client. 645 646 if ( ( resultingStatus == kIOReturnDeviceError ) 647 || ( resultingStatus == kIOUSBHighSpeedSplitError ) ) 648 { 649 // Was there a device error? The device could have been removed or lost power. 650 651 ResetDeviceNow ( false ); 652 status = kIOReturnSuccess; 653 if ( status == kIOReturnSuccess ) 654 { 655 commandInProgress = true; 656 } 657 658 } 659 else if ( resultingStatus == kIOUSBTransactionTimeout ) 660 { 661 662 // The device is so far gone that we couldn't even retry the CSW. Reset time. 663 status = BulkDeviceResetDevice( boRequestBlock, kBulkOnlyResetCompleted ); 664 665 if( status == kIOReturnSuccess ) 666 { 667 commandInProgress = true; 668 } 669 670 } 671 else 672 { 673 // Check if the bulk endpoint was stalled. 674 675 if ( GetDataTransferDirection ( boRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 676 { 677 fPotentiallyStalledPipe = GetBulkInPipe(); 678 } 679 else if ( GetDataTransferDirection ( boRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 680 { 681 fPotentiallyStalledPipe = GetBulkOutPipe(); 682 } 683 else 684 { 685 fPotentiallyStalledPipe = GetControlPipe(); 686 } 687 688 boRequestBlock->currentState = kBulkOnlyCheckBulkStall; 689 STATUS_LOG ( ( 5, "%s[%p]: Checking status for endpoint %d", getName(), this, fPotentiallyStalledPipe ? fPotentiallyStalledPipe->GetEndpointNumber() : -1 ) ); 690 status = GetStatusEndpointStatus ( fPotentiallyStalledPipe, &boRequestBlock->boGetStatusBuffer, &boRequestBlock->boCompletion ); 691 692 if ( status == kIOReturnSuccess ) 693 { 694 commandInProgress = true; 695 } 696 697 } 698 } 699 } 700 break; 701 702 703 case kBulkOnlyCheckBulkStall: 704 case kBulkOnlyCheckBulkStallPostCSW: 705 { 706 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyCheckBulkStall returned %x stalled %x for endpoint %d", getName(), this, resultingStatus, boRequestBlock->boGetStatusBuffer[0], fPotentiallyStalledPipe ? fPotentiallyStalledPipe->GetEndpointNumber() : -1 ) ); 707 708 // Check to see if the endpoint was stalled 709 if ( ( boRequestBlock->boGetStatusBuffer[0] & 1 ) == 1 ) 710 { 711 // Is this stall from the data or status phase? 712 if ( boRequestBlock->currentState == kBulkOnlyCheckBulkStall ) 713 { 714 boRequestBlock->currentState = kBulkOnlyClearBulkStall; 715 } 716 else 717 { 718 boRequestBlock->currentState = kBulkOnlyClearBulkStallPostCSW; 719 } 720 721 status = ClearFeatureEndpointStall ( fPotentiallyStalledPipe, &boRequestBlock->boCompletion ); 722 if ( status == kIOReturnSuccess ) 723 { 724 725 commandInProgress = true; 726 727 } 728 729 } 730 else 731 { 732 733 // If the endpoint was not stalled, resort to reset. 734 status = BulkDeviceResetDevice( boRequestBlock, kBulkOnlyResetCompleted ); 735 736 if ( status == kIOReturnSuccess ) 737 { 738 commandInProgress = true; 739 } 740 } 741 } 742 break; 743 744 case kBulkOnlyClearBulkStall: 745 case kBulkOnlyClearBulkStallPostCSW: 746 { 747 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyClearBulkStall returned %x", getName(), this, resultingStatus ) ); 748 749 // The pipe was stalled and an attempt to clear it was made 750 // Try to get the CSW. If the pipe was not successfully cleared, this will also 751 // set off a device reset sequence. 752 753 // If we already tried to get the CSW once, only try to get it once again. 754 755 if ( boRequestBlock->currentState == kBulkOnlyClearBulkStall ) 756 { 757 status = BulkOnlyReceiveCSWPacket( boRequestBlock, kBulkOnlyStatusReceived ); 758 } 759 else 760 { 761 status = BulkOnlyReceiveCSWPacket( boRequestBlock, kBulkOnlyStatusReceived2ndTime ); 762 } 763 764 if ( status == kIOReturnSuccess ) 765 { 766 commandInProgress = true; 767 } 768 769 } 770 break; 771 772 case kBulkOnlyStatusReceived: 773 { 774 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyStatusReceived returned %x cswTag=0x%08x", getName(), this, resultingStatus, boRequestBlock->boCSW.cswTag ) ); 775 776 // Bulk transfer is done, get the Command Status Wrapper from the device 777 if ( resultingStatus == kIOUSBPipeStalled) 778 { 779 780 // An error occurred trying to get the CSW, we should clear any stalls and try to get the CSW again. 781 boRequestBlock->currentState = kBulkOnlyCheckBulkStallPostCSW; 782 status = GetStatusEndpointStatus ( GetBulkInPipe(), &boRequestBlock->boGetStatusBuffer, &boRequestBlock->boCompletion ); 783 if ( status == kIOReturnSuccess ) 784 { 785 786 fPotentiallyStalledPipe = GetBulkInPipe(); 787 commandInProgress = true; 788 789 } 790 791 } 792 else if ( resultingStatus != kIOReturnSuccess) 793 { 794 // An error occurred trying to get the first CSW, we should check and clear the stall, 795 // and then try the CSW again 796 status = BulkOnlyReceiveCSWPacket ( boRequestBlock, kBulkOnlyStatusReceived2ndTime ); 797 if ( status != kIOReturnSuccess ) 798 { 799 800 // The device is so far gone that we couldn't even retry the CSW. Reset time. 801 status = BulkDeviceResetDevice( boRequestBlock, kBulkOnlyResetCompleted ); 802 803 } 804 805 if ( status == kIOReturnSuccess ) 806 { 807 commandInProgress = true; 808 } 809 810 } 811 else if ( ( boRequestBlock->boCSW.cswTag == boRequestBlock->boCBW.cbwTag ) || fKnownCSWTagMismatchIssues ) 812 { 813 // Since the CBW and CSW tags match, process 814 // the CSW to determine the appropriate response. 815 switch( boRequestBlock->boCSW.cswStatus ) 816 { 817 case kCSWCommandPassedError: 818 { 819 // The device reports no error on the command, and the realized data count was set after the bulk 820 // data transfer completion state. Return that the command was successfully completed. 821 status = kIOReturnSuccess; 822 823 } 824 break; 825 826 case kCSWCommandFailedError: 827 { 828 // The device reported an error for the command. 829 STATUS_LOG ( ( 4, "%s[%p]: kBulkOnlyStatusReceived kCSWCommandFailedError", getName(), this ) ); 830 status = kIOReturnError; 831 832 } 833 break; 834 835 case kCSWPhaseError: 836 { 837 // The device reported a phase error on the command, perform the 838 // bulk reset on the device. 839 STATUS_LOG ( ( 4, "%s[%p]: kBulkOnlyStatusReceived kCSWPhaseError", getName(), this ) ); 840 841 status = BulkDeviceResetDevice( boRequestBlock, kBulkOnlyResetCompleted ); 842 843 if( status == kIOReturnSuccess ) 844 { 845 commandInProgress = true; 846 } 847 848 } 849 break; 850 851 default: 852 { 853 854 STATUS_LOG ( ( 4, "%s[%p]: kBulkOnlyStatusReceived default", getName(), this ) ); 855 // We received an unkown status, report an error to the client. 856 status = kIOReturnError; 857 858 } 859 break; 860 } 861 } 862 else 863 { 864 865 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyStatusReceived tag mismatch", getName(), this ) ); 866 // The only way to get to this point is if the command completes successfully, 867 // but the CBW and CSW tags do not match. Report an error to the client. 868 status = kIOReturnError; 869 870 } 871 } 872 break; 873 874 case kBulkOnlyStatusReceived2ndTime: 875 { 876 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyStatusReceived2ndTime returned %x", getName(), this, resultingStatus ) ); 877 878 // Second try for the CSW is done, if an error occurred, reset device. 879 if ( resultingStatus != kIOReturnSuccess) 880 { 881 882 status = BulkDeviceResetDevice( boRequestBlock, kBulkOnlyResetCompleted ); 883 884 } 885 else 886 { 887 888 // Our second attempt to retrieve the CSW was successful. 889 // Re-enter the state machine to process the CSW packet. 890 boRequestBlock->currentState = kBulkOnlyStatusReceived; 891 BulkOnlyExecuteCommandCompletion( boRequestBlock, 892 resultingStatus, 893 bufferSizeRemaining ); 894 895 status = kIOReturnSuccess; 896 897 } 898 899 if( status == kIOReturnSuccess ) 900 { 901 commandInProgress = true; 902 } 903 904 } 905 break; 906 907 case kBulkOnlyResetCompleted: 908 { 909 910 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyResetCompleted returned %x", getName(), this, resultingStatus ) ); 911 912 if ( resultingStatus != kIOReturnSuccess) 913 { 914 915 // The Bulk-Only Reset failed. Try to recover the device. 916 ResetDeviceNow ( false ); 917 commandInProgress = true; 918 919 break; 920 } 921 922 boRequestBlock->currentState = kBulkOnlyClearBulkInCompleted; 923 status = ClearFeatureEndpointStall ( GetBulkInPipe(), &boRequestBlock->boCompletion ); 924 if ( status == kIOReturnSuccess ) 925 { 926 commandInProgress = true; 927 } 928 929 } 930 break; 931 932 case kBulkOnlyClearBulkInCompleted: 933 { 934 935 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyClearBulkInCompleted returned %x", getName(), this, resultingStatus ) ); 936 937 boRequestBlock->currentState = kBulkOnlyClearBulkOutCompleted; 938 status = ClearFeatureEndpointStall ( GetBulkOutPipe(), &boRequestBlock->boCompletion ); 939 if ( status == kIOReturnSuccess ) 940 { 941 commandInProgress = true; 942 } 943 944 } 945 break; 946 947 case kBulkOnlyClearBulkOutCompleted: 948 { 949 950 STATUS_LOG ( ( 5, "%s[%p]: kBulkOnlyClearBulkOutCompleted returned %x", getName(), this, resultingStatus ) ); 951 952 // This is the final cleanup step after a Bulk Device Reset sequence. We are hopefully functional again, 953 // and thus ready to fail the current I/O. We will do so using AbortCurrentSCSITask() 954 // so that the reset will be tabulated in case if the next I/O still fails and we need to escalate. 955 SetRealizedDataTransferCount ( boRequestBlock->request, 0 ); 956 abortCommand = true; 957 958 } 959 break; 960 961 default: 962 { 963 964 SetRealizedDataTransferCount ( boRequestBlock->request, 0 ); 965 status = kIOReturnError; 966 967 } 968 break; 969 970 } 971 972 973Exit: 974 975 if ( commandInProgress == false ) 976 { 977 978 if ( abortCommand == true ) 979 { 980 981 AbortCurrentSCSITask ( ); 982 983 } 984 else 985 { 986 987 SCSITaskIdentifier request = boRequestBlock->request; 988 989 ReleaseBulkOnlyRequestBlock ( boRequestBlock ); 990 CompleteSCSICommand ( request, status ); 991 992 } 993 994 } 995 STATUS_LOG ( ( 5, "%s[%p]: BulkOnlyExecuteCommandCompletion Returning with currentState=%d", getName(), this, boRequestBlock->currentState ) ); 996} 997