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