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#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