1/* 2 * Copyright (c) 1998-2014 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#include "IOUSBMassStorageClass.h" 30#include "IOUSBMassStorageClassTimestamps.h" 31#include "Debugging.h" 32 33 34//-------------------------------------------------------------------------------------------------- 35// Macros 36//-------------------------------------------------------------------------------------------------- 37 38 39// CBI State Machine States 40enum 41{ 42 kCBIExecuteCommand = 1, // Begin execution of user command 43 kCBIExecuteCommandCompletion, // Complete the user command 44 kCBIBulkIOComplete, // Complete the bulk I/O 45 kCBIReadInterruptComplete, 46 kCBIGetStatusControlEndpointComplete, 47 kCBIClearControlEndpointComplete, 48 kCBIGetStatusBulkEndpointComplete, 49 kCBIClearBulkEndpointComplete 50}; 51 52#pragma mark - 53#pragma mark Protocol Services Methods 54 55 56//-------------------------------------------------------------------------------------------------- 57// AbortSCSICommandForCBIProtocol - The AbortSCSICommand helper method for 58// CBI and CB protocol devices. [PROTECTED] 59//-------------------------------------------------------------------------------------------------- 60 61IOReturn 62IOUSBMassStorageClass::AbortSCSICommandForCBIProtocol ( 63 SCSITaskIdentifier abortTask ) 64{ 65 66 UNUSED( abortTask ); 67 68 return kIOReturnError; 69 70} 71 72 73//-------------------------------------------------------------------------------------------------- 74// SendSCSICommandForCBIProtocol - The SendSCSICommand helper method for CBI and CB protocol 75// devices. [PROTECTED] 76//-------------------------------------------------------------------------------------------------- 77 78IOReturn 79IOUSBMassStorageClass::SendSCSICommandForCBIProtocol ( SCSITaskIdentifier request ) 80{ 81 82 IOReturn status; 83 CBIRequestBlock * theCBIRequestBlock; 84 85 86 if ( fTerminating == true ) 87 { 88 // We have an invalid interface, the device has probably been removed. 89 // Nothing else to do except to report an error. 90 return kIOReturnDeviceError; 91 92 } 93 94 theCBIRequestBlock = GetCBIRequestBlock(); 95 96 bzero ( theCBIRequestBlock, sizeof ( CBIRequestBlock ) ); 97 98 // After having bzero'd the struct we need reset the cbiPhaseDesc to fCBIMemoryDescriptor. 99 fCBICommandRequestBlock.cbiPhaseDesc = fCBIMemoryDescriptor; 100 101 // Get a local copy of the callers cdb 102 GetCommandDescriptorBlock ( request, &theCBIRequestBlock->cbiCDB ); 103 104 // Save the SCSI Task 105 theCBIRequestBlock->request = request; 106 107 // Set up the IOUSBCompletion structure 108 theCBIRequestBlock->cbiCompletion.target = this; 109 theCBIRequestBlock->cbiCompletion.action = &this->CBIProtocolUSBCompletionAction; 110 theCBIRequestBlock->cbiCompletion.parameter = theCBIRequestBlock; 111 112 theCBIRequestBlock->currentState = kCBIExecuteCommand; 113 114 // Build the USB command 115 theCBIRequestBlock->cbiDevRequest.bmRequestType = USBmakebmRequestType ( kUSBOut, kUSBClass, kUSBInterface ); 116 theCBIRequestBlock->cbiDevRequest.bRequest = 0; 117 theCBIRequestBlock->cbiDevRequest.wValue = 0; 118 theCBIRequestBlock->cbiDevRequest.wIndex = GetInterfaceReference()->GetInterfaceNumber(); 119 theCBIRequestBlock->cbiDevRequest.wLength = 12; //kCommandMaxCDBSize 120 theCBIRequestBlock->cbiDevRequest.pData = &theCBIRequestBlock->cbiCDB; 121 122 // Send the command over the control endpoint 123 status = GetInterfaceReference()->GetDevice()->DeviceRequest ( 124 &theCBIRequestBlock->cbiDevRequest, 125 GetTimeoutDuration( theCBIRequestBlock->request ), // Use the client's timeout 126 GetTimeoutDuration( theCBIRequestBlock->request ), // Use the client's timeout 127 &theCBIRequestBlock->cbiCompletion ); 128 STATUS_LOG ( ( 5, "%s[%p]: SendSCSICommandForCBIProtocol DeviceRequest returned %x", getName(), this, status ) ); 129 130 return status; 131 132} 133 134#pragma mark - 135#pragma mark SendSCSICommand Helper methods 136 137 138//-------------------------------------------------------------------------------------------------- 139// CBIProtocolUSBCompletionAction [PROTECTED] 140//-------------------------------------------------------------------------------------------------- 141 142void 143IOUSBMassStorageClass::CBIProtocolUSBCompletionAction ( 144 void * target, 145 void * parameter, 146 IOReturn status, 147 UInt32 bufferSizeRemaining) 148{ 149 150 IOUSBMassStorageClass * theMSC; 151 CBIRequestBlock * cbiRequestBlock; 152 153 154 theMSC = ( IOUSBMassStorageClass * ) target; 155 cbiRequestBlock = ( CBIRequestBlock * ) parameter; 156 theMSC->CBIProtocolCommandCompletion ( cbiRequestBlock, 157 status, 158 bufferSizeRemaining ); 159 160} 161 162 163//-------------------------------------------------------------------------------------------------- 164// CBIProtocolTransferData [PROTECTED] 165//-------------------------------------------------------------------------------------------------- 166 167IOReturn 168IOUSBMassStorageClass::CBIProtocolTransferData ( 169 CBIRequestBlock * cbiRequestBlock, 170 UInt32 nextExecutionState ) 171{ 172 173 IOReturn status = kIOReturnError; 174 175 176 // Set the next state to be executed 177 cbiRequestBlock->currentState = nextExecutionState; 178 179 // Start a bulk in or out transaction 180 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 181 { 182 183 status = GetBulkInPipe()->Read ( 184 GetDataBuffer ( cbiRequestBlock->request ), 185 GetTimeoutDuration ( cbiRequestBlock->request ), // Use the client's timeout for both 186 GetTimeoutDuration ( cbiRequestBlock->request ), 187 GetRequestedDataTransferCount ( cbiRequestBlock->request ), 188 &cbiRequestBlock->cbiCompletion ); 189 190 } 191 else if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 192 { 193 194 status = GetBulkOutPipe()->Write ( 195 GetDataBuffer ( cbiRequestBlock->request ), 196 GetTimeoutDuration ( cbiRequestBlock->request ), // Use the client's timeout for both 197 GetTimeoutDuration ( cbiRequestBlock->request ), 198 GetRequestedDataTransferCount ( cbiRequestBlock->request ), 199 &cbiRequestBlock->cbiCompletion ); 200 201 } 202 203 STATUS_LOG ( ( 5, "%s[%p]: CBIProtocolTransferData returned %x", getName(), this, status ) ); 204 return status; 205 206} 207 208 209//-------------------------------------------------------------------------------------------------- 210// CBIProtocolReadInterrupt [PROTECTED] 211//-------------------------------------------------------------------------------------------------- 212 213IOReturn 214IOUSBMassStorageClass::CBIProtocolReadInterrupt ( 215 CBIRequestBlock * cbiRequestBlock, 216 UInt32 nextExecutionState ) 217{ 218 219 IOReturn status = kIOReturnError; 220 221 222 // Ensure we still have a valid IOMemoryDescriptor. 223 require ( ( cbiRequestBlock->cbiPhaseDesc != NULL ), Exit ); 224 225 // Set the next state to be executed 226 cbiRequestBlock->currentState = nextExecutionState; 227 228 // Start a read from the interrupt pipe 229 status = GetInterruptPipe()->Read ( cbiRequestBlock->cbiPhaseDesc, &cbiRequestBlock->cbiCompletion); 230 STATUS_LOG ( ( 5, "%s[%p]: CBIProtocolReadInterrupt returned %x", getName(), this, status ) ); 231 232 233Exit: 234 235 return status; 236 237} 238 239 240//-------------------------------------------------------------------------------------------------- 241// CBIGetStatusEndpointStatus [PROTECTED] 242//-------------------------------------------------------------------------------------------------- 243 244IOReturn 245IOUSBMassStorageClass::CBIGetStatusEndpointStatus( 246 IOUSBPipe * targetPipe, 247 CBIRequestBlock * cbiRequestBlock, 248 UInt32 nextExecutionState ) 249{ 250 251 IOReturn status; 252 253 254 if( targetPipe == NULL ) 255 { 256 // We need to check if the pipe is NULL 257 status = kIOReturnError; 258 goto ErrorExit; 259 } 260 261 // Set the next state to be executed 262 cbiRequestBlock->currentState = nextExecutionState; 263 264 // Call the default GetStatusEndpointStatus method 265 status = GetStatusEndpointStatus ( targetPipe, &cbiRequestBlock->cbiGetStatusBuffer, &cbiRequestBlock->cbiCompletion ); 266 STATUS_LOG ( ( 5, "%s[%p]: CBIGetStatusEndpointStatus returned %x", getName(), this, status ) ); 267 268 269ErrorExit: 270 271 return status; 272 273} 274 275 276//-------------------------------------------------------------------------------------------------- 277// CBIClearFeatureEndpointStall [PROTECTED] 278//-------------------------------------------------------------------------------------------------- 279 280IOReturn 281IOUSBMassStorageClass::CBIClearFeatureEndpointStall( 282 IOUSBPipe * targetPipe, 283 CBIRequestBlock * cbiRequestBlock, 284 UInt32 nextExecutionState ) 285{ 286 287 IOReturn status; 288 289 290 if( targetPipe == NULL ) 291 { 292 // We need to check if the pipe is NULL (ie if we are being terminated). 293 status = kIOReturnError; 294 goto ErrorExit; 295 } 296 297 // Set the next state to be executed 298 cbiRequestBlock->currentState = nextExecutionState; 299 300 // Call the default ClearFeatureEndpointStall method 301 status = ClearFeatureEndpointStall ( targetPipe, &cbiRequestBlock->cbiCompletion ); 302 STATUS_LOG ( ( 5, "%s[%p]: CBIClearFeatureEndpointStall returned %x", getName(), this, status ) ); 303 304 305ErrorExit: 306 307 return status; 308 309} 310 311 312//-------------------------------------------------------------------------------------------------- 313// CBIProtocolCommandCompletion [PROTECTED] 314//-------------------------------------------------------------------------------------------------- 315 316void 317IOUSBMassStorageClass::CBIProtocolCommandCompletion( 318 CBIRequestBlock * cbiRequestBlock, 319 IOReturn resultingStatus, 320 UInt32 bufferSizeRemaining ) 321{ 322 323 IOReturn status = kIOReturnError; 324 bool commandInProgress = false; 325 326 327 // Check to see if our expansion data is still valid. If we've already passed through free() it'll be NULL and 328 // access its members will cause us to kernel panic. This check exists to guard against callbacks received after 329 // driver termination. 330#ifndef EMBEDDED 331 if ( reserved == NULL ) 332 { 333 334 PANIC_NOW ( ( "IOUSBMassStorageClass::CBIProtocolCommandCompletion callback after driver has been freed" ) ); 335 return; 336 337 } 338#endif // EMBEDDED 339 340 if ( ( cbiRequestBlock->request == NULL ) || ( fCBICommandStructInUse == false ) ) 341 { 342 // The request field is NULL, this appears to be a double callback, do nothing. 343 // OR the command was aborted earlier, do nothing. 344 STATUS_LOG(( 4, "%s[%p]: cbiRequestBlock->request is NULL, returned %x", getName(), this, resultingStatus )); 345 return; 346 347 } 348 349 if ( ( GetInterfaceReference() == NULL ) || ( fTerminating == true ) ) 350 { 351 // Our interface has been closed, probably because of an 352 // unplug, return an error for the command since there it 353 // can no longer be executed. 354 355 STATUS_LOG ( ( 4, "%s[%p]: Completion during termination", getName(), this ) ); 356 goto Exit; 357 358 } 359 360 361 if ( ( resultingStatus == kIOReturnNotResponding ) || ( resultingStatus == kIOReturnAborted ) ) 362 { 363 364 STATUS_LOG(( 5, "%s[%p]: CBIProtocolCommandCompletion previous command returned %x", getName(), this, resultingStatus )); 365 366 // The transfer failed mid-transfer or was aborted by the USB layer. Either way the device will 367 // be non-responsive until we reset it, or we discover it has been disconnected. 368 ResetDeviceNow ( false ); 369 commandInProgress = true; 370 goto Exit; 371 372 } 373 374 RecordUSBTimeStamp ( UMC_TRACE ( kCBICompletion ), ( uintptr_t ) this, resultingStatus, 375 ( unsigned int ) cbiRequestBlock->currentState, ( uintptr_t ) cbiRequestBlock->request ); 376 377 switch ( cbiRequestBlock->currentState ) 378 { 379 380 case kCBIExecuteCommand: // Device request completion 381 { 382 383 STATUS_LOG(( 5, "%s[%p]: kCBIExecuteCommand status %x", getName(), this, resultingStatus )); 384 385#if defined (__i386__) || defined (__x86_64__) 386 // For UHCI. 387 // First check to see if an error occurred on sending the command to the device. 388 if ( resultingStatus == kIOUSBPipeStalled ) 389 { 390 391 status = CBIClearFeatureEndpointStall ( GetControlPipe(), cbiRequestBlock, kCBIClearBulkEndpointComplete ); 392 if ( status == kIOReturnSuccess ) 393 { 394 commandInProgress = true; 395 } 396 397 break; 398 } 399#endif 400 401 // First check to see if an error occurred on the command out 402 if ( resultingStatus != kIOReturnSuccess ) 403 { 404 405 status = CBIGetStatusEndpointStatus ( GetControlPipe(), cbiRequestBlock, kCBIGetStatusControlEndpointComplete ); 406 if ( status == kIOReturnSuccess ) 407 { 408 commandInProgress = true; 409 } 410 411 STATUS_LOG ( ( 4, "%s[%p]: kCBIExecuteCommand GetStatusEndpointStatus status %x", getName(), this, status ) ); 412 413 } 414 else 415 { 416 // If there is to be no data transfer then we are done and can return to the caller 417 // We will only get to here if no Error occurred. 418 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_NoDataTransfer ) 419 { 420 421 status = kIOReturnSuccess; 422 STATUS_LOG ( ( 5, "%s[%p]: kCBIExecuteCommand no data to transfer status %x", getName(), this, status ) ); 423 break; 424 425 } 426 427 status = CBIProtocolTransferData ( cbiRequestBlock, kCBIBulkIOComplete ); 428 if ( status == kIOReturnSuccess ) 429 { 430 commandInProgress = true; 431 } 432 433 STATUS_LOG ( ( 5, "%s[%p]: kCBIExecuteCommand CBIProtocolTransferData status %x", getName(), this, status ) ); 434 435 } 436 437 } 438 break; 439 440 case kCBIBulkIOComplete: 441 { 442 443 STATUS_LOG ( ( 5, "%s[%p]: kCBIBulkIOComplete status %x", getName(), this, resultingStatus ) ); 444 if ( resultingStatus == kIOReturnOverrun ) 445 { 446 // If we got more data than expected, act like we got exactly the amount 447 // requested. 448 resultingStatus = kIOReturnSuccess; 449 SetRealizedDataTransferCount ( cbiRequestBlock->request, GetRequestedDataTransferCount( cbiRequestBlock->request ) ); 450 451 // Clear the halt status on the host side for the pipe in use. 452 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 453 { 454 GetBulkInPipe()->Reset(); 455 } 456 else if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 457 { 458 GetBulkOutPipe()->Reset(); 459 } 460 461 } 462 else 463 { 464 SetRealizedDataTransferCount ( cbiRequestBlock->request, GetRequestedDataTransferCount( cbiRequestBlock->request ) - bufferSizeRemaining ); 465 } 466 467#if defined (__i386__) || defined (__x86_64__) 468 // For UHCI. 469 if ( resultingStatus == kIOUSBPipeStalled ) 470 { 471 472 IOUSBPipe * thePipe = NULL; 473 474 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 475 { 476 thePipe = GetBulkInPipe(); 477 } 478 else if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 479 { 480 thePipe = GetBulkOutPipe(); 481 } 482 483 if ( thePipe != NULL ) 484 { 485 486 status = CBIClearFeatureEndpointStall ( thePipe, cbiRequestBlock, kCBIClearBulkEndpointComplete ); 487 if ( status == kIOReturnSuccess ) 488 { 489 commandInProgress = true; 490 491 } 492 break; 493 494 } 495 496 } 497#endif 498 499 if ( resultingStatus != kIOReturnSuccess ) 500 { 501 // Check if the bulk endpoint was stalled 502 IOUSBPipe * thePipe = NULL; 503 504 if ( GetDataTransferDirection( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 505 { 506 thePipe = GetBulkInPipe(); 507 } 508 else if ( GetDataTransferDirection( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 509 { 510 thePipe = GetBulkOutPipe(); 511 } 512 else 513 { 514 thePipe = GetControlPipe(); 515 } 516 517 status = CBIGetStatusEndpointStatus ( thePipe, cbiRequestBlock, kCBIGetStatusBulkEndpointComplete ); 518 if ( status == kIOReturnSuccess ) 519 { 520 commandInProgress = true; 521 } 522 523 STATUS_LOG ( ( 5, "%s[%p]: kCBIBulkIOComplete GetStatusEndpointStatus status %x", getName(), this, status ) ); 524 525 } 526 else 527 { 528 529 if ( ( GetInterruptPipe() != NULL ) && ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 530 && ( ( GetInterfaceSubclass() == kUSBStorageSFF8070iSubclass ) || ( GetInterfaceSubclass() == kUSBStorageUFISubclass ) ) ) 531 { 532 // We have an interrupt pipe, and device uses it to determine a command is done 533 status = CBIProtocolReadInterrupt ( cbiRequestBlock, kCBIReadInterruptComplete ); 534 if ( status == kIOReturnSuccess ) 535 { 536 commandInProgress = true; 537 } 538 539 STATUS_LOG(( 5, "%s[%p]: kCBIBulkIOComplete CBIProtocolReadInterrupt status %x", getName(), this, status )); 540 541 } 542 else 543 { 544 status = kIOReturnSuccess; 545 } 546 547 } 548 549 } 550 break; 551 552 case kCBIReadInterruptComplete: 553 { 554 STATUS_LOG(( 5, "%s[%p]: kCBIReadInterruptComplete status %x", getName(), this, resultingStatus )); 555 556 // What should the status really be, should probably process and return 557 // a relevent error. 558 if ( ( resultingStatus == kIOReturnSuccess ) && ( ( GetInterfaceSubclass() == kUSBStorageSFF8070iSubclass ) || ( GetInterfaceSubclass() == kUSBStorageUFISubclass ) ) ) 559 { 560 if ( GetInterfaceSubclass() == kUSBStorageUFISubclass ) 561 { 562 // Decide what error to return based on the Interrupt data 563 if ( ( cbiRequestBlock->cbiGetStatusBuffer[0] == 0x00 ) && ( cbiRequestBlock->cbiGetStatusBuffer[1] == 0x00 ) ) 564 { 565 status = kIOReturnSuccess; 566 } 567 else 568 { 569 status = kIOReturnError; 570 } 571 572 } 573 else // This is probably a kUSBStorageSFF8070iSubclass device but in the future may include others as well 574 { 575 // As per the USB Mass Storage Class CBI Transport Specification 3.4.3.1.1 Common Interrupt Data Block 576 if ( ( cbiRequestBlock->cbiGetStatusBuffer[0] == 0x00 ) && 577 ( ( cbiRequestBlock->cbiGetStatusBuffer[1] & 0x3 ) != 0 ) ) 578 { 579 status = kIOReturnError; 580 } 581 else 582 { 583 status = kIOReturnSuccess; 584 } 585 586 } 587 } 588 else 589 { 590 // The Class doesn't know how to interpret the data 591 // return an error and mark interrupt data as invalid 592 status = kIOReturnError; 593 594 } 595 596 STATUS_LOG ( ( 5, "%s[%p]: kCBIReadInterruptComplete ending status %x", getName(), this, status ) ); 597 } 598 break; 599 600 case kCBIGetStatusControlEndpointComplete: 601 { 602 STATUS_LOG ( ( 5, "%s[%p]: kCBIGetStatusControlEndpointComplete status %x", getName(), this, resultingStatus ) ); 603 604 if ( resultingStatus == kIOReturnSuccess ) 605 { 606 607 if ( ( cbiRequestBlock->cbiGetStatusBuffer[0] & 1 ) == 1 ) 608 { 609 // This endpoint was stalled, go ahead and clear it 610 status = CBIClearFeatureEndpointStall ( GetControlPipe(), cbiRequestBlock, kCBIClearControlEndpointComplete ); 611 if ( status == kIOReturnSuccess ) 612 { 613 commandInProgress = true; 614 } 615 616 STATUS_LOG ( ( 5, "%s[%p]: kCBIGetStatusControlEndpointComplete CBIClearFeatureEndpointStall status %x", getName(), this, status ) ); 617 618 } 619 else 620 { 621 622 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_NoDataTransfer ) 623 { 624 625 SetRealizedDataTransferCount ( cbiRequestBlock->request, 0 ); 626 status = kIOReturnError; 627 628 } 629 else 630 { 631 // Check if the bulk endpoint was stalled 632 IOUSBPipe * thePipe = NULL; 633 634 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 635 { 636 thePipe = GetBulkInPipe(); 637 } 638 else if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 639 { 640 thePipe = GetBulkOutPipe(); 641 } 642 else 643 { 644 thePipe = GetControlPipe(); 645 } 646 647 status = CBIGetStatusEndpointStatus ( GetControlPipe(), cbiRequestBlock, kCBIGetStatusBulkEndpointComplete ); 648 if ( status == kIOReturnSuccess ) 649 { 650 commandInProgress = true; 651 } 652 653 STATUS_LOG ( ( 5, "%s[%p]: kCBIGetStatusControlEndpointComplete CBIGetStatusEndpointStatus status %x", getName(), this, status ) ); 654 655 } 656 } 657 } 658 else 659 { 660 // An error occurred to GET_STATUS ( shouldn't happen!!) reset the endpoint anyway 661 status = CBIClearFeatureEndpointStall ( GetControlPipe(), cbiRequestBlock, kCBIClearControlEndpointComplete ); 662 if ( status == kIOReturnSuccess ) 663 { 664 commandInProgress = true; 665 } 666 667 STATUS_LOG(( 5, "%s[%p]: kCBIGetStatusControlEndpointComplete CBIClearFeatureEndpointStall status %x", getName(), this, status )); 668 669 } 670 } 671 break; 672 673 case kCBIClearControlEndpointComplete: 674 { 675 STATUS_LOG ( ( 5, "%s[%p]: kCBIClearControlEndpointComplete status %x", getName(), this, resultingStatus ) ); 676 677 if (resultingStatus == kIOReturnSuccess) 678 { 679 680 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_NoDataTransfer ) 681 { 682 683 SetRealizedDataTransferCount ( cbiRequestBlock->request, 0 ); 684 status = kIOReturnError; 685 686 } 687 else 688 { 689 // Check if the bulk endpoint was stalled 690 IOUSBPipe * thePipe = NULL; 691 692 if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 693 { 694 thePipe = GetBulkInPipe(); 695 } 696 else if ( GetDataTransferDirection ( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 697 { 698 thePipe = GetBulkOutPipe(); 699 } 700 else 701 { 702 thePipe = GetControlPipe(); 703 } 704 705 status = CBIGetStatusEndpointStatus ( thePipe, cbiRequestBlock, kCBIGetStatusBulkEndpointComplete ); 706 if ( status == kIOReturnSuccess ) 707 { 708 commandInProgress = true; 709 } 710 711 STATUS_LOG ( ( 5, "%s[%p]: kCBIClearControlEndpointComplete CBIGetStatusEndpointStatus status %x", getName(), this, status ) ); 712 713 } 714 715 } 716 else 717 { 718 status = resultingStatus; 719 } 720 721 } 722 break; 723 724 case kCBIGetStatusBulkEndpointComplete: 725 { 726 STATUS_LOG ( ( 5, "%s[%p]: kCBIGetStatusBulkEndpointComplete status %x", getName(), this, resultingStatus ) ); 727 728 if ( resultingStatus == kIOReturnSuccess ) 729 { 730 731 if ( ( cbiRequestBlock->cbiGetStatusBuffer[0] & 1 ) == 1 ) 732 { 733 734 IOUSBPipe * thePipe = NULL; 735 736 if ( GetDataTransferDirection( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 737 { 738 thePipe = GetBulkInPipe(); 739 } 740 else if ( GetDataTransferDirection( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 741 { 742 thePipe = GetBulkOutPipe(); 743 } 744 else 745 { 746 thePipe = GetControlPipe(); 747 } 748 749 status = CBIClearFeatureEndpointStall ( thePipe, cbiRequestBlock, kCBIClearBulkEndpointComplete ); 750 if ( status == kIOReturnSuccess ) 751 { 752 commandInProgress = true; 753 } 754 755 STATUS_LOG(( 5, "%s[%p]: kCBIGetStatusBulkEndpointComplete CBIClearFeatureEndpointStall status %x", getName(), this, status )); 756 757 } 758 else 759 { 760 761 SetRealizedDataTransferCount( cbiRequestBlock->request, 0 ); 762 status = kIOReturnError; 763 764 } 765 766 } 767 else 768 { 769 770 IOUSBPipe * thePipe = NULL; 771 772 if ( GetDataTransferDirection( cbiRequestBlock->request ) == kSCSIDataTransfer_FromTargetToInitiator ) 773 { 774 thePipe = GetBulkInPipe(); 775 } 776 else if ( GetDataTransferDirection( cbiRequestBlock->request ) == kSCSIDataTransfer_FromInitiatorToTarget ) 777 { 778 thePipe = GetBulkOutPipe(); 779 } 780 else 781 { 782 thePipe = GetControlPipe(); 783 } 784 785 status = CBIClearFeatureEndpointStall ( thePipe, cbiRequestBlock, kCBIClearBulkEndpointComplete ); 786 if ( status == kIOReturnSuccess ) 787 { 788 commandInProgress = true; 789 } 790 791 STATUS_LOG(( 5, "%s[%p]: kCBIGetStatusBulkEndpointComplete CBIClearFeatureEndpointStall status %x", getName(), this, status )); 792 793 } 794 } 795 break; 796 797 case kCBIClearBulkEndpointComplete: 798 { 799 800 STATUS_LOG ( ( 5, "%s[%p]: kCBIClearBulkEndpointComplete status %x", getName(), this, resultingStatus ) ); 801 802 SetRealizedDataTransferCount ( cbiRequestBlock->request, 0 ); 803 status = kIOReturnError; 804 805 } 806 break; 807 808 default: 809 { 810 811 STATUS_LOG ( ( 5, "%s[%p]: default case status %x", getName(), this, resultingStatus ) ); 812 813 SetRealizedDataTransferCount ( cbiRequestBlock->request, 0 ); 814 status = kIOReturnError; 815 816 } 817 break; 818 819 } 820 821 822Exit: 823 824 825 // If the command has been completed ( no longer pending ), call the clients completion routine. 826 if ( commandInProgress == false ) 827 { 828 829 SCSITaskIdentifier request = cbiRequestBlock->request; 830 831 ReleaseCBIRequestBlock ( cbiRequestBlock ); 832 CompleteSCSICommand ( request, status ); 833 834 } 835} 836 837