1/*
2 * Copyright (c) 1998-2009 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//-----------------------------------------------------------------------------
27//	Includes
28//-----------------------------------------------------------------------------
29
30// BSD includes
31#include <sys/sysctl.h>
32
33// FireWire includes
34#include <IOKit/firewire/IOConfigDirectory.h>
35#include <IOKit/firewire/IOFireWireDevice.h>
36#include <IOKit/IOKitKeys.h>
37#include <IOKit/IOTimeStamp.h>
38
39// FireWire Transport includes
40#include "IOFireWireSerialBusProtocolTransport.h"
41#include "IOFireWireSerialBusProtocolTransportTimestamps.h"
42
43
44//-----------------------------------------------------------------------------
45//	Macros
46//-----------------------------------------------------------------------------
47
48#define DEBUG 										0
49#define DEBUG_ASSERT_COMPONENT_NAME_STRING			"FireWire SBP2 Transport"
50
51#include "IOFireWireSerialBusProtocolTransportDebugging.h"
52
53#if DEBUG
54#define FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL		0
55#endif
56
57#if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 1 )
58#define PANIC_NOW(x)		panic x
59#else
60#define PANIC_NOW(x)
61#endif
62
63#if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 2 )
64#define ERROR_LOG(x)		IOLog x
65#else
66#define ERROR_LOG(x)
67#endif
68
69#if ( FIREWIRE_SBP_TRANSPORT_DEBUGGING_LEVEL >= 3 )
70#define DLOG(x)				IOLog x
71#else
72#define DLOG(x)
73#endif
74
75#define super IOSCSIProtocolServices
76OSDefineMetaClassAndStructors (	IOFireWireSerialBusProtocolTransport, IOSCSIProtocolServices )
77
78
79#define TRANSPORT_FAILURE_RETRIES			1
80
81
82//-----------------------------------------------------------------------------
83//	Structs
84//-----------------------------------------------------------------------------
85
86// SCSI Status Block as defined in Annex B of SBP-2. NB: This is a big-endian
87// representation of the status block, not a host memory representation.
88typedef struct FWSBP2SCSIStatusBlock
89{
90	UInt8		details;
91	UInt8		sbpStatus;
92	UInt16		orbOffsetHi;
93	UInt32		orbOffsetLo;
94	UInt8		status;
95	UInt8		senseKey;
96	UInt8		ASC;
97	UInt8		ASCQ;
98	UInt32		information;
99	UInt32		commandSpecificInformation;
100	UInt32		senseKeyDependent;
101} FWSBP2SCSIStatusBlock;
102
103
104enum
105{
106	kSBP2StatusBlock_Details_DeadBit			= 3,
107
108	kSBP2StatusBlock_Details_LenMask			= 0x7,
109	kSBP2StatusBlock_Details_DeadMask			= (1 << kSBP2StatusBlock_Details_DeadBit),
110	kSBP2StatusBlock_Details_RespMask			= 0x30,
111	kSBP2StatusBlock_Details_SrcMask			= 0xC0
112};
113
114
115enum
116{
117	kSBP2StatusBlock_Resp_REQUEST_COMPLETE		= 0,
118	kSBP2StatusBlock_Resp_TRANSPORT_FAILURE		= 1,
119	kSBP2StatusBlock_Resp_ILLEGAL_REQUEST		= 2,
120	kSBP2StatusBlock_Resp_VENDOR_DEPENDENT		= 3
121};
122
123
124enum
125{
126	kSBP2StatusBlock_SBPStatus_NoAdditionalInformation	= 0,
127	kSBP2StatusBlock_SBPStatus_RequestTypeUnsupported	= 1,
128	kSBP2StatusBlock_SBPStatus_SpeedUnsupported			= 2,
129	kSBP2StatusBlock_SBPStatus_PageSizeUnsupported		= 3,
130	kSBP2StatusBlock_SBPStatus_AccessDenied				= 4,
131	kSBP2StatusBlock_SBPStatus_LogicalUnitNotSupported	= 5,
132	kSBP2StatusBlock_SBPStatus_MaxPayloadTooSmall		= 6,
133	// 7 - reserved
134	kSBP2StatusBlock_SBPStatus_ResourcesUnavailable		= 8,
135	kSBP2StatusBlock_SBPStatus_FunctionRejected			= 9,
136	kSBP2StatusBlock_SBPStatus_LoginIDNotRecognized		= 10,
137	kSBP2StatusBlock_SBPStatus_DummyORBCompleted		= 11,
138	kSBP2StatusBlock_SBPStatus_RequestAborted			= 12,
139	kSBP2StatusBlock_SBPStatus_UnspecifiedError			= 0xFF
140};
141
142
143enum
144{
145
146	kFWSBP2SCSIStatusBlock_StatusBlockFormatCurrentError	= (0 << 6),
147	kFWSBP2SCSIStatusBlock_StatusBlockFormatDeferredError	= (1 << 6),
148	kFWSBP2SCSIStatusBlock_StatusBlockFormatMask			= 0xC0,
149	// reserved 2
150	// Vendor defined 3
151
152	kFWSBP2SCSIStatusBlock_StatusBlockStatusMask			= 0x3F
153};
154
155
156enum
157{
158	kFWSBP2SCSIStatusBlock_SenseKeyMask		= 0x0F,
159
160	kFWSBP2SCSIStatusBlock_ILI_Bit			= 4,
161	kFWSBP2SCSIStatusBlock_ILI_Mask			= (1 << kFWSBP2SCSIStatusBlock_ILI_Bit),
162
163	kFWSBP2SCSIStatusBlock_EOM_Bit			= 5,
164	kFWSBP2SCSIStatusBlock_EOM_Mask			= (1 << kFWSBP2SCSIStatusBlock_EOM_Bit),
165
166	kFWSBP2SCSIStatusBlock_FILEMARK_Bit		= 6,
167	kFWSBP2SCSIStatusBlock_FILEMARK_Mask	= (1 << kFWSBP2SCSIStatusBlock_FILEMARK_Bit),
168
169	kFWSBP2SCSIStatusBlock_VALID_Bit		= 7,
170	kFWSBP2SCSIStatusBlock_VALID_Mask		= (1 << kFWSBP2SCSIStatusBlock_VALID_Bit),
171
172	kFWSBP2SCSIStatusBlock_MEI_Mask			= kFWSBP2SCSIStatusBlock_ILI_Mask | kFWSBP2SCSIStatusBlock_EOM_Mask | kFWSBP2SCSIStatusBlock_FILEMARK_Mask
173
174};
175
176
177//-----------------------------------------------------------------------------
178//	Constants
179//-----------------------------------------------------------------------------
180
181#define kPreferredNameKey								"Preferred Name"
182#define kFireWireGUIDKey								"GUID"
183#define kFireWireVendorNameKey							"FireWire Vendor Name"
184#define kSBP2ReceiveBufferByteCountKey					"SBP2ReceiveBufferByteCount"
185#define kAlwaysSetAutoSenseData							"Always Set AutoSense Data"
186#define	kDontUsePTPacketLimitKey						"Do Not Use PT Packet Limit"
187#define kDefaultIOBlockCount							256
188#define kCRSModelInfo_ValidBitsMask						0x00FFFFFF
189#define kCRSModelInfo_TargetDiskMode					0x0054444D
190#define kIOFireWireMessageServiceIsRequestingClose		kIOFWMessageServiceIsRequestingClose
191#define kDefaultTimeOutValue							30000
192#define kCommandPoolOrbCount							1
193#define kFWSBP2DefaultPageTableEntriesCount				512
194#define kDoubleBufferCommandSizeCheckThreshold			512
195#define kLoginRetryCount								32
196#define kLoginDelayTime									1000000
197
198
199enum
200{
201	kFireWireSBP2CommandTransferDataToTarget 	= 0L,
202	kFireWireSBP2CommandTransferDataFromTarget 	= kFWSBP2CommandTransferDataFromTarget
203};
204
205
206//-----------------------------------------------------------------------------
207//	Class
208//-----------------------------------------------------------------------------
209
210class FWSBP2TransportGlobals
211{
212
213public:
214
215	// Constructor
216	FWSBP2TransportGlobals ( void );
217
218	// Destructor
219	virtual ~FWSBP2TransportGlobals ( void );
220
221};
222
223
224//-----------------------------------------------------------------------------
225//	Prototypes
226//-----------------------------------------------------------------------------
227
228static inline void
229RecordFireWireTimeStamp (
230	unsigned int code,
231	unsigned int a = 0, unsigned int b = 0,
232	unsigned int c = 0, unsigned int d = 0 );
233
234static int
235FirewireSBPTransportSysctl (
236	struct sysctl_oid * oidp,
237	void * 				arg1,
238	int					arg2,
239	struct sysctl_req * req );
240
241
242//-----------------------------------------------------------------------------
243//	Globals
244//-----------------------------------------------------------------------------
245
246static FWSBP2TransportGlobals 	gFWGlobals;
247UInt32							gSBP2DiskDebugFlags	= 0;
248
249SYSCTL_PROC ( _debug, OID_AUTO, FirewireSBPTransport, CTLFLAG_RW, 0, 0, FirewireSBPTransportSysctl, "FirewireSBPTransport", "FireWire SBP2 Transport debug interface" );
250
251
252//-----------------------------------------------------------------------------
253//	FirewireSBPTransportSysctl - Sysctl handler.					  [PRIVATE]
254//-----------------------------------------------------------------------------
255
256static int
257FirewireSBPTransportSysctl ( struct sysctl_oid * oidp, void * arg1, int arg2, struct sysctl_req * req )
258{
259
260	int				error = 0;
261	FWSysctlArgs	fwArgs;
262
263	DEBUG_UNUSED ( oidp );
264	DEBUG_UNUSED ( arg1 );
265	DEBUG_UNUSED ( arg2 );
266
267	DLOG ( ( "+FirewireSBPTransportSysctl: gSBP2DiskDebugFlags = 0x%08X\n", ( unsigned int ) gSBP2DiskDebugFlags ) );
268
269	error = SYSCTL_IN ( req, &fwArgs, sizeof ( fwArgs ) );
270	if ( ( error == 0 ) && ( fwArgs.type == kFWTypeDebug ) )
271	{
272
273		if ( fwArgs.operation == kFWOperationGetFlags )
274		{
275
276			fwArgs.debugFlags = gSBP2DiskDebugFlags;
277			error = SYSCTL_OUT ( req, &fwArgs, sizeof ( fwArgs ) );
278
279		}
280
281		else if ( fwArgs.operation == kFWOperationSetFlags )
282		{
283			gSBP2DiskDebugFlags = fwArgs.debugFlags;
284		}
285
286	}
287
288	DLOG ( ( "-FirewireSBPTransportSysctl: gSBP2DiskDebugFlags = 0x%08X\n", ( unsigned int ) gSBP2DiskDebugFlags ) );
289
290	return error;
291
292}
293
294
295//-----------------------------------------------------------------------------
296//	Default Constructor
297//-----------------------------------------------------------------------------
298
299FWSBP2TransportGlobals::FWSBP2TransportGlobals ( void )
300{
301
302	int		debugFlags;
303
304	DLOG ( ( "+FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
305
306	if ( PE_parse_boot_argn ( "sbp2disk", &debugFlags, sizeof ( debugFlags ) ) )
307	{
308
309		gSBP2DiskDebugFlags = debugFlags;
310
311	}
312
313	// Register our sysctl interface
314	sysctl_register_oid ( &sysctl__debug_FirewireSBPTransport );
315
316	DLOG ( ( "-FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
317
318}
319
320
321//-----------------------------------------------------------------------------
322//	Destructor
323//-----------------------------------------------------------------------------
324
325FWSBP2TransportGlobals::~FWSBP2TransportGlobals ( void )
326{
327
328	DLOG ( ( "+~FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
329
330	// Unregister our sysctl interface
331	sysctl_unregister_oid ( &sysctl__debug_FirewireSBPTransport );
332
333	DLOG ( ( "-~FWSBP2TransportGlobals::FWSBP2TransportGlobals\n" ) );
334
335}
336
337
338#if 0
339#pragma mark -
340#pragma mark Public Methods
341#pragma mark -
342#endif
343
344//-----------------------------------------------------------------------------
345// init - Called by IOKit to initialize us.							   [PUBLIC]
346//-----------------------------------------------------------------------------
347
348bool
349IOFireWireSerialBusProtocolTransport::init ( OSDictionary * propTable )
350{
351
352	fDeferRegisterService = true;
353	return super::init ( propTable );
354
355}
356
357
358//-----------------------------------------------------------------------------
359// start - Called by IOKit to start our services.					   [PUBLIC]
360//-----------------------------------------------------------------------------
361
362bool
363IOFireWireSerialBusProtocolTransport::start ( IOService * provider )
364{
365
366	IOReturn			status			= kIOReturnSuccess;
367	bool				returnValue		= false;
368	bool				openSucceeded	= false;
369	OSNumber *			number			= NULL;
370	OSDictionary *		dict			= NULL;
371
372	// See if there is a read time out duration passed in the property dictionary - if not
373	// set the default to 30 seconds.
374	number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) );
375	if ( number == NULL )
376	{
377
378		number = OSNumber::withNumber ( kDefaultTimeOutValue, 32 );
379		require ( number, exit );
380
381		setProperty ( kIOPropertyReadTimeOutDurationKey, number );
382		number->release ( );
383
384		number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyReadTimeOutDurationKey ) );
385
386	}
387
388	DLOG ( ( "%s: start read time out = %ld\n", getName ( ), number->unsigned32BitValue ( ) ) );
389
390	// See if there is a write time out duration passed in the property dictionary - if not
391	// set the default to 30 seconds.
392	number = OSDynamicCast ( OSNumber,  getProperty ( kIOPropertyWriteTimeOutDurationKey ) );
393	if ( number == NULL )
394	{
395
396		number = OSNumber::withNumber ( kDefaultTimeOutValue, 32 );
397		require ( number, exit );
398
399		setProperty ( kIOPropertyWriteTimeOutDurationKey, number );
400		number->release ( );
401
402		number = OSDynamicCast ( OSNumber, getProperty ( kIOPropertyWriteTimeOutDurationKey ) );
403
404	}
405
406	DLOG ( ( "%s: start read time out = %ld\n", getName ( ), number->unsigned32BitValue ( ) ) );
407
408	// Set the default maximum page table constraints for SBP2
409	// $$$ ( this should probably be moved down to SBP2 - ping Collin )
410
411	setProperty ( kIOMaximumSegmentCountReadKey, kFWSBP2DefaultPageTableEntriesCount, 32 );
412	setProperty ( kIOMaximumSegmentCountWriteKey, kFWSBP2DefaultPageTableEntriesCount, 32 );
413
414	setProperty ( kIOMaximumSegmentByteCountReadKey, kFWSBP2MaxPageClusterSize, 32 );
415	setProperty ( kIOMaximumSegmentByteCountWriteKey, kFWSBP2MaxPageClusterSize, 32 );
416
417	fSBPTarget = OSDynamicCast ( IOFireWireSBP2LUN, provider );
418	require ( fSBPTarget, exit );
419
420	// Add a retain here so we can keep IOFireWireSBP2LUN from doing garbage collection on us
421	// when we are in the middle of our finalize method.
422
423	fSBPTarget->retain ( );
424
425	openSucceeded = super::start ( provider );
426	require ( openSucceeded, exit );
427
428	openSucceeded = provider->open ( this );
429	require ( openSucceeded, exit );
430
431	fUnit = fSBPTarget->getFireWireUnit ( );
432	require ( fUnit, exit );
433
434	// Explicitly set the "enable retry on ack d" flag.
435	fUnit->setNodeFlags ( kIOFWEnableRetryOnAckD );
436
437	number = OSDynamicCast ( OSNumber, getProperty ( kFireWireGUIDKey, gIOServicePlane ) );
438	if ( number != NULL )
439	{
440
441		UInt64		GUID = 0;
442
443		GUID = number->unsigned64BitValue ( );
444
445		RecordFireWireTimeStamp (
446			FW_TRACE ( kGUID ),
447			( uintptr_t ) this,
448			( unsigned int ) ( ( GUID >> 32 ) & 0xFFFFFFFF ),
449			( unsigned int ) ( GUID & 0xFFFFFFFF ),
450			0 );
451
452	}
453
454	status = AllocateResources ( );
455	require_noerr ( status, exit );
456
457	// Get us on the workloop so we can sleep the start thread.
458	fCommandGate->runAction ( ConnectToDeviceStatic );
459
460	if ( reserved->fLoginState == kLogginSucceededState )
461	{
462		registerService ( );
463	}
464
465	DLOG ( ( "%s: start complete\n", getName ( ) ) );
466
467	returnValue = true;
468
469	// Copy some values to the Protocol Characteristics Dictionary.
470	dict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertyProtocolCharacteristicsKey ) );
471	if ( dict != NULL )
472	{
473
474		OSDictionary *		protocolDict 	= NULL;
475		OSString *			string			= NULL;
476
477		// Make a copy of the existing Protocol Characteristics Dictionary to Modify.
478		protocolDict = OSDictionary::withDictionary ( dict );
479		check ( protocolDict );
480
481		string = OSString::withCString ( kFireWireGUIDKey );
482		if ( string != NULL )
483		{
484
485			protocolDict->setObject ( string, getProperty ( kFireWireGUIDKey, gIOServicePlane ) );
486			string->release ( );
487			string = NULL;
488
489		}
490
491		string = OSString::withCString ( kPreferredNameKey );
492		if ( string != NULL )
493		{
494
495			protocolDict->setObject ( kPreferredNameKey, getProperty ( kFireWireVendorNameKey, gIOServicePlane ) );
496			string->release ( );
497			string = NULL;
498
499		}
500
501		// Replace the existing Protocol Characteristics Dictionary with our new one.
502		setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
503		protocolDict->release ( );
504		protocolDict = NULL;
505
506	}
507
508	// False by default.
509	reserved->fAutonomousSpinDownWorkAround = false;
510
511	if ( ( getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) != NULL )
512	{
513
514		OSDictionary *	characterDict	= NULL;
515
516
517		characterDict = OSDynamicCast ( OSDictionary, getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) );
518		if ( characterDict->getObject ( kIOPropertyAutonomousSpinDownKey ) != NULL )
519		{
520
521			reserved->fAutonomousSpinDownWorkAround = true;
522
523		}
524
525	}
526
527	if ( ( getProperty ( kDontUsePTPacketLimitKey ) ) != NULL )
528	{
529
530		IOFireWireSBP2Target *		target = NULL;
531
532		target = OSDynamicCast ( IOFireWireSBP2Target, fSBPTarget->getProvider( ) );
533
534		if ( target != NULL )
535		{
536			target->setTargetFlags ( kIOFWSBP2DontUsePTPacketLimit );
537		}
538
539	}
540
541	InitializePowerManagement ( provider );
542
543
544exit:
545
546
547	if ( returnValue == false )
548	{
549
550		DLOG ( ( "%s: start failed.  status = %x\n", getName ( ), status) );
551
552		// Call the cleanUp method to clean up any allocated resources.
553		cleanUp ( );
554
555	}
556
557	return returnValue;
558
559}
560
561
562//-----------------------------------------------------------------------------
563// cleanUp - This is misleadingly named due to binary compatibility burdens.
564//			 The cleanUp method actually just closes the SBP2LUN. fSBPTarget
565//			 is actually a SBP2LUN object.							   [PUBLIC]
566//-----------------------------------------------------------------------------
567
568void
569IOFireWireSerialBusProtocolTransport::cleanUp ( void )
570{
571
572	DLOG ( ( "%s: cleanUp called\n", getName ( ) ) );
573
574	if ( fSBPTarget != NULL )
575	{
576
577		// Close SBP2 if we have opened it.
578		if ( fSBPTarget->isOpen ( this ) )
579		{
580
581			OSNumber *	number = NULL;
582
583			number = OSDynamicCast ( OSNumber, getProperty ( kFireWireGUIDKey, gIOServicePlane ) );
584			if ( number != NULL )
585			{
586
587				UInt64		GUID = 0;
588
589				GUID = number->unsigned64BitValue ( );
590
591				RecordFireWireTimeStamp (
592					FW_TRACE ( kGUID ),
593					( uintptr_t ) this,
594					( unsigned int ) ( ( GUID >> 32 ) & 0xFFFFFFFF ),
595					( unsigned int ) ( GUID & 0xFFFFFFFF ),
596					1 );
597
598			}
599
600			fSBPTarget->close ( this );
601
602		}
603
604	}
605
606}
607
608
609//-----------------------------------------------------------------------------
610// finalize - Terminates all power management.						[PROTECTED]
611//-----------------------------------------------------------------------------
612
613bool
614IOFireWireSerialBusProtocolTransport::finalize ( IOOptionBits options )
615{
616
617	DeallocateResources ( );
618
619	// Release the retain we took to keep IOFireWireSBP2LUN from doing garbage collection on us
620	// when we are in the middle of DeallocateResources.
621	if ( fSBPTarget != NULL )
622	{
623
624		fSBPTarget->release ( );
625		fSBPTarget = NULL;
626
627	}
628
629	return super::finalize ( options );
630
631}
632
633
634//-----------------------------------------------------------------------------
635// free - Called to deallocate ExpansionData.						   [PUBLIC]
636//-----------------------------------------------------------------------------
637
638void
639IOFireWireSerialBusProtocolTransport::free ( void )
640{
641
642	if ( reserved != NULL )
643	{
644
645		if ( reserved->fCommandPool != NULL )
646		{
647
648			reserved->fCommandPool->release ( );
649			reserved->fCommandPool = NULL;
650
651		}
652
653		IOFree ( reserved, sizeof ( ExpansionData ) );
654		reserved = NULL;
655
656	}
657
658	super::free ( );
659
660}
661
662
663#if 0
664#pragma mark -
665#pragma mark Protected Methods
666#pragma mark -
667#endif
668
669
670//-----------------------------------------------------------------------------
671// CommandORBAccessor - Retrieves command orb.						[PROTECTED]
672//-----------------------------------------------------------------------------
673
674IOFireWireSBP2ORB *
675IOFireWireSerialBusProtocolTransport::CommandORBAccessor ( void )
676{
677	return fORB;
678}
679
680
681//-----------------------------------------------------------------------------
682// SBP2LoginAccessor - Retrieves login orb.							[PROTECTED]
683//-----------------------------------------------------------------------------
684
685IOFireWireSBP2Login *
686IOFireWireSerialBusProtocolTransport::SBP2LoginAccessor ( void )
687{
688	return fLogin;
689}
690
691
692//-----------------------------------------------------------------------------
693// message - Called by IOKit to deliver messages.					[PROTECTED]
694//-----------------------------------------------------------------------------
695
696IOReturn
697IOFireWireSerialBusProtocolTransport::message (
698	UInt32 			type,
699	IOService *		nub,
700	void * 			arg )
701{
702
703	IOFireWireSBP2ORB *		orb 		= NULL;
704	SBP2ClientOrbData *		clientData 	= NULL;
705	IOReturn				status		= kIOReturnSuccess;
706
707	switch ( type )
708	{
709
710		case kIOMessageServiceIsSuspended:
711		{
712
713			DLOG ( ( "%s: kIOMessageServiceIsSuspended\n", getName ( ) ) );
714
715			// Bus reset started - set flag to stop submitting orbs.
716			fLoggedIn = false;
717
718		}
719		break;
720
721		case kIOMessageServiceIsResumed:
722		{
723
724			DLOG ( ( "%s: kIOMessageServiceIsResumed\n", getName ( ) ) );
725
726			// Bus reset finished - if we have failed to log in previously, try again.
727			if ( fNeedLogin == true )
728			{
729
730				fNeedLogin = false;
731				fLoginRetryCount = 0;
732
733				// In case we are resumed after a terminate.
734				if ( fLogin != NULL )
735				{
736
737					login ( );
738
739				}
740
741			}
742
743		}
744		break;
745
746		case kIOMessageFWSBP2ReconnectComplete:
747		{
748
749			// As of this writing FireWireSBP2LUN will message all multi-LUN instances with this
750			// message. So qualify this message with our instance variable fLogin and ignore others.
751			if ( ( ( FWSBP2ReconnectParams * ) arg )->login == fLogin )
752			{
753
754				DLOG ( ( "%s: kIOMessageFWSBP2ReconnectComplete\n", getName ( ) ) );
755
756				fLoggedIn = true;
757
758				if ( fReconnectCount < kMaxReconnectCount)
759				{
760
761					DLOG ( ( "%s: resubmit orb \n", getName ( ) ) );
762					fReconnectCount++;
763					submitOrbFromQueue ( );
764
765				}
766
767				else
768				{
769
770					// Unable to recover from bus reset storm. We have exhausted the
771					// fReconnectCount - punt...
772
773					if ( fORB != NULL )
774					{
775
776						clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ( );
777						if ( clientData != NULL )
778						{
779
780							clientData->serviceResponse	= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
781							clientData->taskStatus		= kSCSITaskStatus_DeliveryFailure;
782							CompleteSCSITask ( fORB );
783
784						}
785
786					}
787
788				}
789
790			}
791
792		}
793		break;
794
795		case kIOMessageFWSBP2ReconnectFailed:
796		{
797
798			// As of this writing FireWireSBP2LUN will message all multi-LUN instances with this
799			// message. So qualify this message with our instance variable fLogin and ignore others.
800			if ( ( ( FWSBP2ReconnectParams * ) arg )->login == fLogin )
801			{
802
803				DLOG ( ( "%s: kIOMessageFWSBP2ReconnectFailed\n", getName ( ) ) );
804
805				// Try to reestablish log in.
806				fLoginRetryCount = 0;
807				login ( );
808
809			}
810
811		}
812		break;
813
814		case kIOFireWireMessageServiceIsRequestingClose:
815		{
816
817			DLOG ( ( "%s: kIOFireWireMessageServiceIsRequestingClose\n", getName ( ) ) );
818
819			// Tell our super to message it's clients that the device is gone.
820
821			SendNotification_DeviceRemoved ( );
822
823			// We need to drain the queued commands. See if there is an in flight orb (e.g. fORB)
824			// if not pull the first one out of the submit queue if there are any.
825
826			orb = fORB;
827
828			do
829			{
830
831				if ( orb != NULL )
832				{
833
834					clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
835					if ( clientData != NULL )
836					{
837
838						if ( clientData->scsiTask != NULL )
839						{
840
841							clientData->serviceResponse	= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
842							clientData->taskStatus		= kSCSITaskStatus_DeviceNotPresent;
843							CompleteSCSITask ( orb );
844
845						}
846
847					}
848
849				}
850
851			} while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand ( false ) ) );
852
853			cleanUp ( );
854
855		}
856		break;
857
858		case kIOMessageServiceIsTerminated:
859		{
860
861			DLOG ( ( "%s: kIOMessageServiceIsTerminated\n", getName ( ) ) );
862			// Let go of memory and what not.
863			cleanUp ( );
864
865		}
866		break;
867
868		default:
869		{
870
871			status = IOService::message ( type, nub, arg );
872
873		}
874		break;
875
876	}
877
878	return status;
879
880}
881
882
883//-----------------------------------------------------------------------------
884// SendSCSICommand - Converts a SCSITask to an ORB.					[PROTECTED]
885//-----------------------------------------------------------------------------
886
887bool
888IOFireWireSerialBusProtocolTransport::SendSCSICommand (
889	SCSITaskIdentifier 			request,
890	SCSIServiceResponse * 		serviceResponse,
891	SCSITaskStatus * 			taskStatus )
892{
893
894	SBP2ClientOrbData *				clientData 			= NULL;
895	IOFireWireSBP2ORB *				orb					= NULL;
896	SCSICommandDescriptorBlock		cdb 				= { 0 };
897	UInt8							commandLength		= 0;
898	UInt32							commandFlags		= 0;
899	UInt32							timeOut				= 0;
900	bool							commandProcessed	= false;
901
902	DLOG ( ( "%s: SendSCSICommand called\n", getName ( ) ) );
903
904	*serviceResponse		= kSCSIServiceResponse_Request_In_Process;
905	*taskStatus				= kSCSITaskStatus_No_Status;
906
907	if ( isInactive ( ) == true )
908	{
909
910		// Device is disconnected - we can not service command requests.
911		*serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
912		commandProcessed = true;
913		goto exit;
914
915	}
916
917	// Get an orb from our orb pool and do not block until we get one.
918	orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false );
919	require ( orb, exit );
920
921	GetCommandDescriptorBlock ( request, &cdb );
922
923	RecordFireWireTimeStamp (
924		FW_TRACE ( kSendSCSICommand1 ),
925		( uintptr_t ) this,
926		( uintptr_t ) request,
927		cdb[0] | ( cdb[1] << 8 ) | ( cdb[2] << 16 ) | ( cdb[3] << 24 ),
928		cdb[4] | ( cdb[5] << 8 ) | ( cdb[6] << 16 ) | ( cdb[7] << 24 ) );
929
930	RecordFireWireTimeStamp (
931		FW_TRACE ( kSendSCSICommand2 ),
932		( uintptr_t ) this,
933		( uintptr_t ) request,
934		cdb[ 8] | ( cdb[ 9] << 8 ) | ( cdb[10] << 16 ) | ( cdb[11] << 24 ),
935		cdb[12] | ( cdb[13] << 8 ) | ( cdb[14] << 16 ) | ( cdb[15] << 24 ) );
936
937	clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
938	require ( clientData, exit );
939
940	commandLength 	= GetCommandDescriptorBlockSize ( request );
941	commandFlags	= ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromTargetToInitiator ) ?
942															  kFireWireSBP2CommandTransferDataFromTarget :
943															  kFireWireSBP2CommandTransferDataToTarget;
944
945	orb->setCommandFlags (	commandFlags |
946							kFWSBP2CommandCompleteNotify |
947							kFWSBP2CommandImmediate |
948							kFWSBP2CommandNormalORB );
949
950	require ( ( SetCommandBuffers ( orb, request ) == kIOReturnSuccess ), exit );
951
952	orb->setCommandBlock ( cdb, commandLength );
953
954	// SBP-2 needs a non-zero timeout to fire completion routines if timeout is not expressed
955	// default to 0xFFFFFFFF.
956	timeOut = GetTimeoutDuration ( request );
957	if ( timeOut == 0 )
958	{
959		timeOut = 0xFFFFFFFF;
960	}
961
962	orb->setCommandTimeout ( timeOut );
963
964#if TRANSPORT_FAILURE_RETRIES
965	reserved->fLUNResetCount = 3;
966#endif
967
968	// Close the gate here to eliminate potenially rare double append of orb. If on a DP machine
969	// and a bus reset occurs the login thread can append the orb as well as here.
970	fCommandGate->runAction ( CriticalOrbSubmissionStatic, orb, request );
971	commandProcessed = true;
972
973
974exit:
975
976
977	DLOG ( ( "%s: SendSCSICommand exit, Service Response = %x\n", getName ( ), *serviceResponse ) );
978
979	return commandProcessed;
980
981}
982
983
984//-----------------------------------------------------------------------------
985// SetCommandBuffers - Sets the command buffers in the ORB.			[PROTECTED]
986//-----------------------------------------------------------------------------
987
988IOReturn
989IOFireWireSerialBusProtocolTransport::SetCommandBuffers (
990	IOFireWireSBP2ORB *		orb,
991	SCSITaskIdentifier		request )
992{
993
994	SBP2ClientOrbData *		clientData	= NULL;
995	IOReturn				status		= kIOReturnError;
996
997	clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
998	require ( clientData, Exit );
999
1000	clientData->quadletAlignedBuffer = NULL;
1001	if ( GetDataBuffer ( request ) != NULL )
1002	{
1003
1004		// Does this command require double buffering in order to ensure quadlet alignment?
1005		if ( ( GetDataBuffer ( request )->getLength ( ) < kDoubleBufferCommandSizeCheckThreshold ) &&
1006			 ( ( GetDataBuffer ( request )->getLength ( ) & 3 ) != 0 ) )
1007		{
1008
1009			// Create quadlet aligned IOBufferMemoryDescriptor, to be released in CompleteSCSITask().
1010			clientData->quadletAlignedBuffer = IOBufferMemoryDescriptor::withOptions (
1011				kIODirectionOutIn,
1012				GetDataBuffer ( request )->getLength ( ),
1013				4 );
1014
1015			require ( clientData->quadletAlignedBuffer, Exit );
1016
1017			// If necessary copy data from the non-aligned buffer to the aligned buffer.
1018			if ( GetDataTransferDirection ( request ) == kSCSIDataTransfer_FromInitiatorToTarget )
1019			{
1020
1021				GetDataBuffer ( request )->readBytes (	GetDataBufferOffset ( request ),
1022														clientData->quadletAlignedBuffer->getBytesNoCopy ( ),
1023														GetDataBuffer ( request )->getLength ( ) );
1024
1025			}
1026
1027			status = orb->setCommandBuffers (	clientData->quadletAlignedBuffer,
1028												GetDataBufferOffset ( request ),
1029												GetRequestedDataTransferCount ( request ) );
1030
1031			require_success ( status, Exit );
1032
1033		}
1034
1035	}
1036
1037	if ( clientData->quadletAlignedBuffer == NULL )
1038	{
1039
1040		status = orb->setCommandBuffers (	GetDataBuffer ( request ),
1041											GetDataBufferOffset ( request ),
1042											GetRequestedDataTransferCount ( request ) );
1043
1044	}
1045
1046
1047Exit:
1048
1049
1050	return status;
1051
1052}
1053
1054
1055//-----------------------------------------------------------------------------
1056// CompleteSCSITask - Completes a task.								[PROTECTED]
1057//-----------------------------------------------------------------------------
1058
1059void
1060IOFireWireSerialBusProtocolTransport::CompleteSCSITask ( IOFireWireSBP2ORB * orb )
1061{
1062
1063	SBP2ClientOrbData *	clientData = NULL;
1064
1065	DLOG ( ( "%s: CompleteSCSITask called\n", getName ( ) ) );
1066
1067	clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
1068	if ( clientData != NULL )
1069	{
1070
1071		if ( clientData->scsiTask != NULL )
1072		{
1073
1074			SCSITaskIdentifier		scsiTask			= NULL;
1075			SCSIServiceResponse		serviceResponse		= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
1076			SCSITaskStatus			taskStatus			= kSCSITaskStatus_No_Status;
1077			IOByteCount				bytesTransfered 	= 0;
1078
1079			//	/!\ WARNING - because SBP-2 can send status information at different
1080			//	stage of an orb's life ( or send none at all ) the caller of this routine
1081			//	has determined that the orb is indeed done. So we need to explicitly tell
1082			//	SBP-2 to let go of the buffer reference by calling releaseCommandBuffers.
1083			orb->releaseCommandBuffers ( );
1084
1085			if ( clientData->taskStatus == kSCSITaskStatus_GOOD )
1086			{
1087				bytesTransfered = GetRequestedDataTransferCount ( clientData->scsiTask );
1088			}
1089
1090			SetRealizedDataTransferCount ( clientData->scsiTask, bytesTransfered );
1091
1092			// Did we double buffer this command to ensure quadlet alignment?
1093			// If so, copy over memory if necessary.
1094			if ( clientData->quadletAlignedBuffer != NULL )
1095			{
1096
1097				if ( GetDataTransferDirection ( clientData->scsiTask ) == kSCSIDataTransfer_FromTargetToInitiator )
1098				{
1099
1100					GetDataBuffer ( clientData->scsiTask )->writeBytes (
1101						GetDataBufferOffset ( clientData->scsiTask ),
1102						clientData->quadletAlignedBuffer->getBytesNoCopy ( ),
1103						clientData->quadletAlignedBuffer->getLength ( ) );
1104
1105				}
1106
1107				clientData->quadletAlignedBuffer->release ( );
1108				clientData->quadletAlignedBuffer = NULL;
1109
1110			}
1111
1112			// Re-entrancy protection.
1113			scsiTask				= clientData->scsiTask;
1114			serviceResponse 		= clientData->serviceResponse;
1115			taskStatus				= clientData->taskStatus;
1116			clientData->scsiTask	= NULL;
1117			fORB					= NULL;
1118
1119			submitOrbFromQueue ( );
1120
1121			reserved->fCommandPool->returnCommand ( orb );
1122
1123			RecordFireWireTimeStamp (
1124				FW_TRACE ( kCompleteSCSICommand ),
1125				( uintptr_t ) this,
1126				( uintptr_t ) scsiTask,
1127				( serviceResponse << 8 ) | taskStatus );
1128
1129			CommandCompleted ( scsiTask, serviceResponse, taskStatus );
1130
1131		}
1132
1133	}
1134
1135}
1136
1137
1138//-----------------------------------------------------------------------------
1139// AbortSCSICommand - Aborts an outstanding I/O.					[PROTECTED]
1140//-----------------------------------------------------------------------------
1141
1142SCSIServiceResponse
1143IOFireWireSerialBusProtocolTransport::AbortSCSICommand ( SCSITaskIdentifier request )
1144{
1145
1146	SCSIServiceResponse		serviceResponse;
1147
1148	DEBUG_UNUSED ( request );
1149
1150	DLOG ( ( "%s: AbortSCSICommand called\n", getName ( ) ) );
1151
1152	serviceResponse = kSCSIServiceResponse_FUNCTION_REJECTED;
1153
1154	return serviceResponse;
1155
1156}
1157
1158
1159//-----------------------------------------------------------------------------
1160// IsProtocolServiceSupported -	Checks for protocol services supported by
1161// 								this device.						[PROTECTED]
1162//-----------------------------------------------------------------------------
1163
1164bool
1165IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported (
1166	SCSIProtocolFeature			feature,
1167	void *						serviceValue )
1168{
1169
1170	bool			isSupported		= false;
1171	OSDictionary * 	characterDict 	= NULL;
1172
1173	characterDict = OSDynamicCast ( OSDictionary, ( getProperty ( kIOPropertySCSIDeviceCharacteristicsKey ) ) );
1174
1175	DLOG ( ( "IOFireWireSerialBusProtocolTransport::IsProtocolServiceSupported called\n" ) );
1176
1177	switch ( feature )
1178	{
1179
1180		case kSCSIProtocolFeature_CPUInDiskMode:
1181		{
1182
1183			isSupported = IsDeviceCPUInDiskMode ( );
1184
1185		}
1186		break;
1187
1188		case kSCSIProtocolFeature_MaximumReadBlockTransferCount:
1189		{
1190
1191			OSNumber *		number = NULL;
1192
1193			// Start with our default value.
1194			* ( ( UInt32 * ) serviceValue ) = kDefaultIOBlockCount;
1195
1196			if ( characterDict != NULL )
1197			{
1198
1199				number = OSDynamicCast ( OSNumber, characterDict->getObject ( kIOMaximumByteCountReadKey ) );
1200				if ( number != NULL )
1201				{
1202					*( ( UInt32 * ) serviceValue ) = number->unsigned32BitValue ( );
1203				}
1204
1205			}
1206
1207			isSupported = true;
1208
1209		}
1210		break;
1211
1212		case kSCSIProtocolFeature_MaximumWriteBlockTransferCount:
1213		{
1214
1215			OSNumber *		number = NULL;
1216
1217			// Start with our default value.
1218			* ( ( UInt32 * ) serviceValue ) = kDefaultIOBlockCount;
1219
1220			if ( characterDict != NULL )
1221			{
1222
1223				number = OSDynamicCast ( OSNumber, characterDict->getObject ( kIOMaximumBlockCountWriteKey ) );
1224				if ( number != NULL )
1225				{
1226					*( ( UInt32 * ) serviceValue ) = number->unsigned32BitValue ( );
1227				}
1228
1229			}
1230
1231			isSupported = true;
1232
1233		}
1234		break;
1235
1236		case kSCSIProtocolFeature_MaximumReadTransferByteCount:
1237		{
1238
1239			OSNumber *		number = NULL;
1240
1241			// If the property SBP2ReceiveBufferByteCount exists we have a FireWire host
1242			// with the physical unit off and there is a software FIFO. ( i.e. Lynx )
1243			// We should tell clients to deblock on the SBP2ReceiveBufferByteCount.
1244			// bounds to avoid stalled I/O.
1245			number = OSDynamicCast (
1246				OSNumber,
1247				getProperty ( kSBP2ReceiveBufferByteCountKey, gIOServicePlane ) );
1248
1249			if ( number != NULL )
1250			{
1251
1252				* ( ( UInt64 * ) serviceValue ) = number->unsigned32BitValue ( );
1253				isSupported = true;
1254
1255			}
1256
1257		}
1258		break;
1259
1260		case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber:
1261		{
1262
1263			* ( ( UInt32 * ) serviceValue ) = kMaxFireWireLUN;
1264			isSupported = true;
1265
1266		}
1267		break;
1268
1269		case kSCSIProtocolFeature_ProtocolAlwaysReportsAutosenseData:
1270		{
1271
1272			isSupported = true;
1273
1274		}
1275		break;
1276
1277		case kSCSIProtocolFeature_ProtocolSpecificPowerControl:
1278		{
1279
1280			if ( reserved->fAutonomousSpinDownWorkAround == true )
1281			{
1282				isSupported = true;
1283			}
1284
1285		}
1286		break;
1287
1288		default:
1289		{
1290
1291			isSupported = false;
1292
1293		}
1294		break;
1295
1296	}
1297
1298	return isSupported;
1299
1300}
1301
1302
1303//-----------------------------------------------------------------------------
1304// HandleProtocolServiceFeature - Handles protocol service features.
1305//																	[PROTECTED]
1306//-----------------------------------------------------------------------------
1307
1308bool
1309IOFireWireSerialBusProtocolTransport::HandleProtocolServiceFeature (
1310	SCSIProtocolFeature		feature,
1311	void *					serviceValue )
1312{
1313
1314	bool		returnValue = false;
1315
1316	switch ( feature )
1317	{
1318
1319		case kSCSIProtocolFeature_ProtocolSpecificPowerControl:
1320		{
1321
1322			// This a workaround for devices which spin themselves up/down and can't
1323			// properly handle START_STOP commands from the host when the drive is
1324			// already in the requested state.
1325			if ( reserved->fAutonomousSpinDownWorkAround == true )
1326			{
1327
1328				// This essentially NOPs the spin up/down request.
1329				returnValue = true;
1330
1331			}
1332
1333		}
1334		break;
1335
1336		default:
1337		{
1338
1339			returnValue = false;
1340
1341		}
1342		break;
1343
1344	}
1345
1346	return returnValue;
1347
1348}
1349
1350
1351//-----------------------------------------------------------------------------
1352// IsDeviceCPUInDiskMode - 	Checks if device is a CPU in FireWire Target
1353//							Disk Mode.								[PROTECTED]
1354//-----------------------------------------------------------------------------
1355
1356bool
1357IOFireWireSerialBusProtocolTransport::IsDeviceCPUInDiskMode ( void )
1358{
1359
1360	UInt32						csrModelInfo 	= 0;;
1361	IOConfigDirectory *			directory		= NULL;
1362	IOFireWireDevice *			device			= NULL;
1363	IOReturn					status			= kIOReturnSuccess;
1364	bool						isCPUDiskMode	= false;
1365
1366
1367	DLOG ( ( "%s: IsDeviceCPUInDiskMode was called\n", getName ( ) ) );
1368
1369	device = OSDynamicCast ( IOFireWireDevice, fUnit->getProvider ( ) );
1370	require ( device, Exit );
1371
1372	status = device->getConfigDirectory ( directory );
1373	require_success ( status, Exit );
1374
1375	status = directory->getKeyValue ( kCSRModelInfoKey, csrModelInfo );
1376	require_success ( status, Exit );
1377
1378	if ( ( csrModelInfo & kCRSModelInfo_ValidBitsMask ) == kCRSModelInfo_TargetDiskMode )
1379	{
1380		isCPUDiskMode = true;
1381	}
1382
1383
1384Exit:
1385
1386
1387	DLOG ( ( "%s: CPU Disk Mode = %d\n", getName ( ), isCPUDiskMode ) );
1388
1389	return isCPUDiskMode;
1390
1391}
1392
1393
1394//-----------------------------------------------------------------------------
1395// StatusNotifyStatic - C->C++ glue method.							[PROTECTED]
1396//-----------------------------------------------------------------------------
1397
1398void
1399IOFireWireSerialBusProtocolTransport::StatusNotifyStatic (
1400	void *					refCon,
1401	FWSBP2NotifyParams *	params )
1402{
1403	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->StatusNotify ( params );
1404}
1405
1406
1407//-----------------------------------------------------------------------------
1408// StatusNotify - Status notify handler.							[PROTECTED]
1409//-----------------------------------------------------------------------------
1410
1411void
1412IOFireWireSerialBusProtocolTransport::StatusNotify ( FWSBP2NotifyParams * params )
1413{
1414
1415	IOFireWireSBP2ORB *		orb				= NULL;
1416	FWSBP2StatusBlock *		statusBlock		= NULL;
1417	SBP2ClientOrbData *		clientData		= NULL;
1418	SCSI_Sense_Data *		targetData		= NULL;
1419	UInt8			 		senseData[kSenseDefaultSize + 8] = { 0 };
1420
1421	targetData = ( SCSI_Sense_Data * ) &senseData [ 0 ];
1422
1423	if ( ( params->message != NULL ) && ( params->length != 0 ) )
1424	{
1425		statusBlock = ( FWSBP2StatusBlock * ) params->message;
1426	}
1427
1428	orb	= ( IOFireWireSBP2ORB * ) params->commandObject;
1429	if ( orb != NULL )
1430	{
1431		clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
1432	}
1433
1434	RecordFireWireTimeStamp (
1435		FW_TRACE ( kStatusNotify ),
1436		( uintptr_t ) this,
1437		( uintptr_t ) orb,
1438		params->notificationEvent );
1439
1440	switch ( params->notificationEvent )
1441	{
1442
1443		case kFWSBP2NormalCommandStatus:
1444		{
1445
1446			if ( clientData != NULL )
1447			{
1448
1449				// Read the status block details bits. See SBP-2 spec section 5.3.
1450				// Check the dead bit ( i.e. that the 'd' field == 1 ).
1451				if ( statusBlock->details & kSBP2StatusBlock_Details_DeadMask )
1452				{
1453
1454					SetValidAutoSenseData ( clientData, statusBlock, targetData );
1455
1456					// Wait for fetch agent to reset before calling CompleteSCSITask which will
1457					// be called in FetchAgentResetComplete.
1458					RecordFireWireTimeStamp (
1459						FW_TRACE ( kFetchAgentReset ),
1460						( uintptr_t ) this,
1461						( uintptr_t ) orb );
1462
1463					fLogin->submitFetchAgentReset ( );
1464
1465				}
1466
1467				else if ( ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) &&
1468						  ( statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_FunctionRejected ) )
1469				{
1470
1471					SetValidAutoSenseData ( clientData, statusBlock, targetData );
1472
1473					// Complete the SCSI request without a retry for devices that return a
1474					// SBP function rejected status but in actuality have successfully
1475					// processed the SCSI request with a CHECK condition
1476					// and have valid sense data.
1477					//
1478					// Certain Oxford 911 based devices seem to fall under this category
1479
1480					if ( clientData->taskStatus == kSCSITaskStatus_CHECK_CONDITION )
1481					{
1482
1483						CompleteSCSITask ( orb );
1484
1485					}
1486
1487					else
1488					{
1489
1490						clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
1491						clientData->taskStatus		= kSCSITaskStatus_DeviceNotResponding;
1492
1493						reserved->fLUNResetPathFlag = true;
1494						fLUNResetORB->submit ( );
1495
1496					}
1497
1498				}
1499
1500				else if ( ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) &&
1501						  ( ( statusBlock->details & kSBP2StatusBlock_Details_LenMask ) == 1 ) &&
1502						  ( statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_NoAdditionalInformation ) )
1503				{
1504
1505					clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE;
1506					clientData->taskStatus		= kSCSITaskStatus_GOOD;
1507
1508					CompleteSCSITask ( orb );
1509
1510					DLOG ( ( "%s: StatusNotify normal complete \n", getName ( ) ) );
1511
1512				}
1513
1514				else
1515				{
1516
1517					SetValidAutoSenseData ( clientData, statusBlock, targetData );
1518					CompleteSCSITask ( orb );
1519
1520					DLOG ( ( "%s: StatusNotify have sense data or an unexpected error? \n", getName ( ) ) );
1521
1522				}
1523
1524			}
1525
1526		}
1527		break;
1528
1529		case kFWSBP2NormalCommandTimeout:
1530		{
1531
1532			DLOG ( ( "%s: kFWSBP2NormalCommandTimeout \n", getName ( ) ) );
1533
1534			if ( clientData != NULL )
1535			{
1536
1537				if ( clientData->scsiTask != NULL )
1538				{
1539
1540					clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
1541					clientData->taskStatus		= kSCSITaskStatus_ProtocolTimeoutOccurred;
1542
1543				}
1544
1545			}
1546
1547			// Set flag so FetchAgentReset knows it is being called from a timeout path.
1548			// reserved->fLUNResetPathFlag = true;
1549
1550			RecordFireWireTimeStamp (
1551				FW_TRACE ( kLogicalUnitReset ),
1552				( uintptr_t ) this,
1553				( uintptr_t ) fLUNResetORB );
1554
1555			// We reset the LUN as good measure in case device is wedged. The LUN reset completion
1556			// handler will call the fetch agent to be reset. The FetchAgentReset completion handler
1557			// will call CompleteSCSITask() and complete the command with the approrpiate task status.
1558			fLUNResetORB->submit ( );
1559
1560		}
1561		break;
1562
1563		case kFWSBP2NormalCommandReset:
1564		{
1565
1566			DLOG ( ( "%s: kFWSBP2NormalCommandReset\n", getName ( ) ) );
1567
1568			// kFWSBP2NormalCommandReset - is a misleading definition. A pending command has
1569			// failed so we need notify the upper layers to complete failed command.
1570
1571			if ( clientData != NULL )
1572			{
1573
1574				if ( clientData->scsiTask != NULL )
1575				{
1576
1577					clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
1578					clientData->taskStatus		= kSCSITaskStatus_DeliveryFailure;
1579
1580					CompleteSCSITask ( orb );
1581
1582				}
1583
1584			}
1585
1586		}
1587		break;
1588
1589		default:
1590		{
1591			DLOG ( ( "%s: StatusNotify with unknown notificationEvent\n", getName ( ) ) );
1592		}
1593		break;
1594
1595	}
1596
1597}
1598
1599
1600//-----------------------------------------------------------------------------
1601//	SetValidAutoSenseData - Sets any valid sense data.				[PROTECTED]
1602//-----------------------------------------------------------------------------
1603
1604void
1605IOFireWireSerialBusProtocolTransport::SetValidAutoSenseData (
1606	SBP2ClientOrbData *			clientData,
1607	FWSBP2StatusBlock *			statusBlock,
1608	SCSI_Sense_Data *			targetData )
1609{
1610
1611	UInt8		quadletCount	= 0;
1612
1613	clientData->serviceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
1614	clientData->taskStatus		= kSCSITaskStatus_No_Status;
1615
1616	quadletCount = ( statusBlock->details & kSBP2StatusBlock_Details_LenMask ) - 1;
1617
1618	// See if we have any valid sense data.
1619	if ( ( statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE )
1620	{
1621
1622		clientData->serviceResponse = kSCSIServiceResponse_TASK_COMPLETE;
1623		clientData->taskStatus		= CoalesceSenseData ( statusBlock, quadletCount, targetData );
1624
1625	}
1626
1627	if ( ( clientData->taskStatus == kSCSITaskStatus_CHECK_CONDITION ) ||
1628		 ( reserved->fAlwaysSetSenseData ) )
1629	{
1630
1631		if ( clientData->scsiTask != NULL )
1632		{
1633			SetAutoSenseData ( clientData->scsiTask, targetData, kSenseDefaultSize + 8 );
1634		}
1635
1636	}
1637
1638	RecordFireWireTimeStamp (
1639		FW_TRACE ( kSCSICommandSenseData ),
1640		( uintptr_t ) this,
1641		( uintptr_t ) clientData->scsiTask,
1642		targetData->SENSE_KEY & kSENSE_KEY_Mask,
1643		( targetData->ADDITIONAL_SENSE_CODE << 8 ) | targetData->ADDITIONAL_SENSE_CODE_QUALIFIER );
1644
1645}
1646
1647
1648//-----------------------------------------------------------------------------
1649// CoalesceSenseData - Sets sense data in the data buffer.			[PROTECTED]
1650//-----------------------------------------------------------------------------
1651
1652SCSITaskStatus
1653IOFireWireSerialBusProtocolTransport::CoalesceSenseData (
1654	FWSBP2StatusBlock *		sourceData,
1655	UInt8					quadletCount,
1656	SCSI_Sense_Data *		targetData )
1657{
1658
1659	SCSITaskStatus				returnValue 		= kSCSITaskStatus_GOOD;
1660	UInt8 						statusBlockFormat 	= 0;
1661	FWSBP2SCSIStatusBlock *		scsiStatusBlock		= NULL;
1662
1663	scsiStatusBlock = ( FWSBP2SCSIStatusBlock * ) sourceData;
1664
1665	// Pull bits out of SBP-2 status block ( see SBP-2 Annex B section B.2 )
1666	// and copy them into sense data block ( see SPC-2 section 7.23.2 )
1667	if ( quadletCount > 0 )
1668	{
1669
1670		statusBlockFormat = scsiStatusBlock->status & kFWSBP2SCSIStatusBlock_StatusBlockFormatMask;
1671		returnValue = ( SCSITaskStatus ) ( scsiStatusBlock->status & kFWSBP2SCSIStatusBlock_StatusBlockStatusMask );
1672
1673		if ( statusBlockFormat == kFWSBP2SCSIStatusBlock_StatusBlockFormatCurrentError )
1674		{
1675			targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Current_Errors;
1676		}
1677
1678		else if ( statusBlockFormat == kFWSBP2SCSIStatusBlock_StatusBlockFormatDeferredError )
1679		{
1680			targetData->VALID_RESPONSE_CODE = kSENSE_RESPONSE_CODE_Deferred_Errors;
1681		}
1682
1683		if ( statusBlockFormat < 2 )
1684		{
1685
1686			targetData->VALID_RESPONSE_CODE |= ( scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_VALID_Mask );
1687			targetData->ADDITIONAL_SENSE_CODE = scsiStatusBlock->ASC;
1688			targetData->ADDITIONAL_SENSE_CODE_QUALIFIER = scsiStatusBlock->ASCQ;
1689			targetData->SENSE_KEY = scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_SenseKeyMask;
1690
1691			// Set the M, E, I bits: M->FileMark, E->EOM, I->ILI.
1692			targetData->SENSE_KEY |= ( scsiStatusBlock->senseKey & kFWSBP2SCSIStatusBlock_MEI_Mask ) << 1;
1693
1694			if ( quadletCount > 1 )
1695			{
1696
1697				scsiStatusBlock->information = OSSwapBigToHostInt32 ( scsiStatusBlock->information );
1698
1699				targetData->INFORMATION_1 = ( scsiStatusBlock->information >> 24 ) & 0xFF;
1700				targetData->INFORMATION_2 = ( scsiStatusBlock->information >> 16 ) & 0xFF;
1701				targetData->INFORMATION_3 = ( scsiStatusBlock->information >> 8 ) & 0xFF;
1702				targetData->INFORMATION_4 = scsiStatusBlock->information & 0xFF;
1703				targetData->ADDITIONAL_SENSE_LENGTH = 6;
1704
1705			}
1706
1707			if ( quadletCount > 2 )
1708			{
1709
1710				scsiStatusBlock->commandSpecificInformation = OSSwapBigToHostInt32 ( scsiStatusBlock->commandSpecificInformation );
1711
1712				targetData->COMMAND_SPECIFIC_INFORMATION_1 = ( scsiStatusBlock->commandSpecificInformation >> 24 ) & 0xFF;
1713				targetData->COMMAND_SPECIFIC_INFORMATION_2 = ( scsiStatusBlock->commandSpecificInformation >> 16 ) & 0xFF;
1714				targetData->COMMAND_SPECIFIC_INFORMATION_3 = ( scsiStatusBlock->commandSpecificInformation >> 8 ) & 0xFF;
1715				targetData->COMMAND_SPECIFIC_INFORMATION_4 = scsiStatusBlock->commandSpecificInformation & 0xFF;
1716				targetData->ADDITIONAL_SENSE_LENGTH = 6;
1717
1718			}
1719
1720			if ( quadletCount > 3 )
1721			{
1722
1723				UInt8	count = 0;
1724
1725				// Get bytes to copy and clip if greater than sizeof SCSI_Sense_Data.
1726				scsiStatusBlock->senseKeyDependent = OSSwapBigToHostInt32 ( scsiStatusBlock->senseKeyDependent );
1727
1728				count = ( quadletCount - 3 ) * sizeof ( UInt32 );
1729				if ( count > 4 )
1730					count = 4;
1731
1732				bcopy ( &scsiStatusBlock->senseKeyDependent,
1733						&targetData->FIELD_REPLACEABLE_UNIT_CODE,
1734						count );
1735
1736				targetData->ADDITIONAL_SENSE_LENGTH = count + 6;
1737
1738			}
1739
1740		}
1741
1742	}
1743
1744	return returnValue;
1745
1746}
1747
1748
1749//-----------------------------------------------------------------------------
1750//	LoginCompletionStatic - C->C++ glue method.						[PROTECTED]
1751//-----------------------------------------------------------------------------
1752
1753void
1754IOFireWireSerialBusProtocolTransport::LoginCompletionStatic (
1755	void *							refCon,
1756	FWSBP2LoginCompleteParams *		params )
1757{
1758	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LoginCompletion ( params );
1759}
1760
1761//-----------------------------------------------------------------------------
1762// LoginCompletion - Login completion handler.						[PROTECTED]
1763//-----------------------------------------------------------------------------
1764
1765void
1766IOFireWireSerialBusProtocolTransport::LoginCompletion (
1767	FWSBP2LoginCompleteParams * 	params )
1768{
1769
1770	DLOG ( ( "%s: LoginCompletion complete \n", getName ( ) ) );
1771
1772	// If login failed, retry if we haven't already exceeded max retry count.
1773	require_success ( params->status, Retry );
1774
1775	// We only have a valid SBP2 login params block if the login completed successfully.
1776	// Otherwise the block is NULL.
1777	require ( params->statusBlock, Retry );
1778
1779	RecordFireWireTimeStamp (
1780		FW_TRACE ( kLoginCompletion ),
1781		( uintptr_t ) this,
1782		params->status,
1783		params->statusBlock->details,
1784		params->statusBlock->sbpStatus );
1785
1786	if	( ( ( params->statusBlock->details & kSBP2StatusBlock_Details_RespMask ) == kSBP2StatusBlock_Resp_REQUEST_COMPLETE ) &&
1787		  ( params->statusBlock->sbpStatus == kSBP2StatusBlock_SBPStatus_NoAdditionalInformation ) )
1788	{
1789
1790		fLoginRetryCount	= 0;
1791		fLoggedIn			= true;
1792		fNeedLogin 			= false;
1793
1794		if ( reserved->fLoginState == kFirstTimeLoggingInState )
1795		{
1796
1797			reserved->fLoginState = kLogginSucceededState;
1798			fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
1799
1800		}
1801
1802		submitOrbFromQueue ( );
1803
1804		RecordFireWireTimeStamp ( FW_TRACE ( kLoginResumed ), ( uintptr_t ) this );
1805		loginResumed ( );
1806
1807		return;
1808
1809	}
1810
1811
1812Retry:
1813
1814	RecordFireWireTimeStamp (
1815		FW_TRACE ( kLoginCompletion ),
1816		( uintptr_t ) this,
1817		params->status, NULL, NULL );
1818
1819	if ( fLoginRetryCount < kMaxLoginRetryCount )
1820	{
1821
1822		IOReturn 	status = kIOReturnSuccess;
1823
1824		fLoginRetryCount++;
1825
1826		DLOG ( ( "%s: resubmitting Login\n", getName ( ) ) );
1827
1828		status = login ( );
1829		if ( status != kIOReturnSuccess )
1830		{
1831
1832			if ( reserved->fLoginState == kFirstTimeLoggingInState )
1833			{
1834
1835				reserved->fLoginState = kLogginFailedState;
1836
1837				// Wake up sleeping start thread.
1838				fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
1839
1840			}
1841
1842		}
1843
1844	}
1845
1846	else
1847	{
1848
1849		// Device can not be logged into after kMaxLoginRetryCount attemptes let's reset
1850		// the need login flag in case the device was unplugged during login.
1851
1852		fNeedLogin = true;
1853
1854		RecordFireWireTimeStamp (
1855			FW_TRACE ( kLoginLost ),
1856			( uintptr_t ) this,
1857			reserved->fLoginState );
1858
1859		loginLost ( );
1860
1861		if ( reserved->fLoginState == kFirstTimeLoggingInState )
1862		{
1863
1864			reserved->fLoginState = kLogginFailedState;
1865
1866			// Wake up sleeping start thread.
1867			fCommandGate->commandWakeup ( ( void * ) &reserved->fLoginState );
1868
1869		}
1870
1871	}
1872
1873}
1874
1875
1876//-----------------------------------------------------------------------------
1877// LogoutCompletionStatic - C->C++ glue.							[PROTECTED]
1878//-----------------------------------------------------------------------------
1879
1880void
1881IOFireWireSerialBusProtocolTransport::LogoutCompletionStatic (
1882	void *							refCon,
1883	FWSBP2LogoutCompleteParams *	params )
1884{
1885	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LogoutCompletion ( params );
1886}
1887
1888
1889//-----------------------------------------------------------------------------
1890// LogoutCompletion - Logout completion handler.					[PROTECTED]
1891//-----------------------------------------------------------------------------
1892
1893void
1894IOFireWireSerialBusProtocolTransport::LogoutCompletion (
1895	FWSBP2LogoutCompleteParams * 	params )
1896{
1897
1898	DEBUG_UNUSED ( params );
1899	DLOG ( ( "%s: LogoutCompletion complete \n", getName ( ) ) );
1900
1901}
1902
1903
1904//-----------------------------------------------------------------------------
1905// UnsolicitedStatusNotifyStatic - C->C++ glue.						[PROTECTED]
1906//-----------------------------------------------------------------------------
1907
1908void
1909IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotifyStatic (
1910	void * 					refCon,
1911	FWSBP2NotifyParams *	params )
1912{
1913	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->UnsolicitedStatusNotify ( params );
1914}
1915
1916
1917//-----------------------------------------------------------------------------
1918// UnsolicitedStatusNotify - Unsolicited status handler.			[PROTECTED]
1919//-----------------------------------------------------------------------------
1920
1921void
1922IOFireWireSerialBusProtocolTransport::UnsolicitedStatusNotify (
1923	FWSBP2NotifyParams * 		params )
1924{
1925
1926	DEBUG_UNUSED ( params );
1927
1928	DLOG ( ( "%s: UnsolicitedStatusNotify called\n", getName ( ) ) );
1929
1930	// Parse and handle unsolicited status.
1931	fLogin->enableUnsolicitedStatus ( );
1932
1933}
1934
1935
1936//-----------------------------------------------------------------------------
1937// FetchAgentResetCompleteStatic - C->C++ glue.						[PROTECTED]
1938//-----------------------------------------------------------------------------
1939
1940void
1941IOFireWireSerialBusProtocolTransport::FetchAgentResetCompleteStatic (
1942	void *		refCon,
1943	IOReturn	status )
1944{
1945	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->FetchAgentResetComplete ( status );
1946}
1947
1948
1949//-----------------------------------------------------------------------------
1950// FetchAgentResetComplete - Fetch agent reset handler.				[PROTECTED]
1951//-----------------------------------------------------------------------------
1952
1953void
1954IOFireWireSerialBusProtocolTransport::FetchAgentResetComplete ( IOReturn status )
1955{
1956
1957	SBP2ClientOrbData *		clientData = NULL;
1958
1959	DEBUG_UNUSED ( status );
1960
1961	DLOG ( ( "%s: FetchAgentResetComplete called\n", getName ( ) ) );
1962
1963	require ( fORB, exit );
1964
1965	// When orb chaining is implemented we will notify upper layer
1966	// to reconfigure device state and resubmitting commands
1967
1968	clientData = ( SBP2ClientOrbData * ) fORB->getRefCon ( );
1969	if ( clientData != NULL )
1970	{
1971
1972		if ( clientData->scsiTask != NULL )
1973		{
1974
1975			RecordFireWireTimeStamp (
1976				FW_TRACE ( kFetchAgentResetComplete ),
1977				( uintptr_t ) this,
1978				( uintptr_t ) fORB );
1979
1980		#if TRANSPORT_FAILURE_RETRIES
1981			if ( reserved->fLUNResetPathFlag && ( reserved->fLUNResetCount > 0 ) )
1982			{
1983
1984				reserved->fLUNResetCount--;
1985				submitOrbFromQueue ( );
1986
1987			}
1988
1989			else
1990		#endif
1991			{
1992				CompleteSCSITask ( fORB );
1993			}
1994
1995		}
1996
1997	}
1998
1999
2000exit:
2001
2002	reserved->fLUNResetPathFlag = false;
2003
2004}
2005
2006
2007//-----------------------------------------------------------------------------
2008// LunResetCompleteStatic - C->C++ glue.							[PROTECTED]
2009//-----------------------------------------------------------------------------
2010
2011void
2012IOFireWireSerialBusProtocolTransport::LunResetCompleteStatic (
2013	void *							refCon,
2014	IOReturn						status,
2015	IOFireWireSBP2ManagementORB *	orb )
2016{
2017	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->LunResetComplete ( status, orb );
2018}
2019
2020
2021//-----------------------------------------------------------------------------
2022// LunResetComplete - LUN reset completion handler.					[PROTECTED]
2023//-----------------------------------------------------------------------------
2024
2025void
2026IOFireWireSerialBusProtocolTransport::LunResetComplete (
2027	IOReturn						status,
2028	IOFireWireSBP2ManagementORB *	orb )
2029{
2030
2031	DEBUG_UNUSED ( status );
2032	DEBUG_UNUSED ( orb );
2033
2034	DLOG ( ( "%s: LunResetComplete called\n", getName ( ) ) );
2035
2036	RecordFireWireTimeStamp (
2037		FW_TRACE ( kLogicalUnitResetComplete ),
2038		( uintptr_t ) this,
2039		( uintptr_t ) orb,
2040		status );
2041
2042	RecordFireWireTimeStamp (
2043		FW_TRACE ( kFetchAgentReset ),
2044		( uintptr_t ) this,
2045		( uintptr_t ) orb );
2046
2047	fLogin->submitFetchAgentReset ( );
2048
2049}
2050
2051
2052//-----------------------------------------------------------------------------
2053// ConnectToDeviceStatic - C->C++ glue.								[PROTECTED]
2054//-----------------------------------------------------------------------------
2055
2056IOReturn
2057IOFireWireSerialBusProtocolTransport::ConnectToDeviceStatic (
2058	OSObject *	refCon,
2059	void *		val1,
2060	void *		val2,
2061	void *		val3,
2062	void *		val4 )
2063{
2064
2065	DEBUG_UNUSED ( val1 );
2066	DEBUG_UNUSED ( val2 );
2067	DEBUG_UNUSED ( val3 );
2068	DEBUG_UNUSED ( val4 );
2069
2070	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->ConnectToDevice ( );
2071
2072	return kIOReturnSuccess;
2073
2074}
2075
2076
2077//-----------------------------------------------------------------------------
2078//	ConnectToDevice - Connects to the device.						[PROTECTED]
2079//-----------------------------------------------------------------------------
2080
2081void
2082IOFireWireSerialBusProtocolTransport::ConnectToDevice ( void )
2083{
2084
2085	IOReturn	status = kIOReturnSuccess;
2086
2087	DLOG ( ( "%s: ConnectToDevice called\n", getName ( ) ) );
2088
2089	// Avoid double logins during login phase.
2090	fNeedLogin 			= false;
2091	fLoginRetryCount 	= 0;
2092
2093	status = login ( );
2094	if ( status == kIOReturnSuccess )
2095	{
2096
2097		// Sleep the start thread - we'll wake it up on login completion.
2098		fCommandGate->commandSleep ( ( void * ) &reserved->fLoginState, THREAD_UNINT );
2099
2100	}
2101
2102}
2103
2104
2105//-----------------------------------------------------------------------------
2106//	DisconnectFromDevice - Disconnects from device.					[PROTECTED]
2107//-----------------------------------------------------------------------------
2108
2109void
2110IOFireWireSerialBusProtocolTransport::DisconnectFromDevice ( void )
2111{
2112
2113	DLOG ( ( "%s: DisconnectFromDevice called\n", getName ( ) ) );
2114
2115	fLoggedIn = false;
2116
2117	// Avoid logins during a logout phase.
2118	fNeedLogin = false;
2119	fLogin->submitLogout ( );
2120
2121}
2122
2123
2124//-----------------------------------------------------------------------------
2125// CriticalOrbSubmissionStatic - C->C++ glue.						[PROTECTED]
2126//-----------------------------------------------------------------------------
2127
2128IOReturn
2129	IOFireWireSerialBusProtocolTransport::CriticalOrbSubmissionStatic (
2130		OSObject *	refCon,
2131		void *		val1,
2132		void *		val2,
2133		void *		val3,
2134		void *		val4 )
2135{
2136
2137	DEBUG_UNUSED ( val3 );
2138	DEBUG_UNUSED ( val4 );
2139
2140	( ( IOFireWireSerialBusProtocolTransport * ) refCon )->CriticalOrbSubmission (
2141		( IOFireWireSBP2ORB * ) val1, ( SCSITaskIdentifier  ) val2 );
2142
2143	return kIOReturnSuccess;
2144
2145}
2146
2147
2148//-----------------------------------------------------------------------------
2149//	CriticalOrbSubmission - add command to queue on workloop.		[PROTECTED]
2150//-----------------------------------------------------------------------------
2151
2152void
2153IOFireWireSerialBusProtocolTransport::CriticalOrbSubmission (
2154	IOFireWireSBP2ORB *		orb,
2155	SCSITaskIdentifier		request )
2156{
2157
2158	SBP2ClientOrbData *		clientData;
2159
2160	clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
2161	require ( clientData, exit );
2162
2163	clientData->scsiTask = request;
2164
2165	reserved->fSubmitQueue->returnCommand ( orb );
2166
2167	// Avoid double appending an active orb ( not this one ).
2168	if ( fORB == NULL )
2169	{
2170		submitOrbFromQueue ( );
2171	}
2172
2173
2174exit:
2175
2176
2177	return;
2178
2179}
2180
2181
2182//-----------------------------------------------------------------------------
2183// submitOrbFromQueue - submitORB on workloop.						[PROTECTED]
2184//-----------------------------------------------------------------------------
2185
2186OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 6 );
2187
2188void
2189IOFireWireSerialBusProtocolTransport::submitOrbFromQueue ( void )
2190{
2191
2192	DLOG ( ( "%s: submitOrbFromQueue called\n", getName ( ) ) );
2193
2194	// This check is necessary because we may be draining the queue on the requesting close path.
2195
2196	if ( fLoggedIn == true )
2197	{
2198
2199		if ( fORB == NULL )
2200		{
2201
2202			fORB = ( IOFireWireSBP2ORB * ) reserved->fSubmitQueue->getCommand ( false );
2203			fReconnectCount	= 0;
2204
2205		}
2206
2207		if ( fORB != NULL )
2208		{
2209
2210			RecordFireWireTimeStamp ( FW_TRACE ( kSubmitOrb ), ( uintptr_t ) this, ( uintptr_t ) fORB );
2211			fLogin->submitORB ( fORB );
2212
2213		}
2214
2215	}
2216
2217}
2218
2219
2220//-----------------------------------------------------------------------------
2221// AllocateResources - Allocates resources.							[PROTECTED]
2222//-----------------------------------------------------------------------------
2223
2224IOReturn
2225IOFireWireSerialBusProtocolTransport::AllocateResources ( void )
2226{
2227
2228	IOReturn 				status		= kIOReturnSuccess;
2229	IOWorkLoop * 			workLoop	= NULL;
2230
2231	DLOG ( ( "%s: AllocateResources called\n", getName ( ) ) );
2232
2233	fLogin = fSBPTarget->createLogin ( );
2234	require_action ( fLogin, exit,  status = kIOReturnNoMemory );
2235
2236	fLogin->setLoginFlags ( kFWSBP2ExclusiveLogin );
2237	fLogin->setLoginRetryCountAndDelayTime ( kLoginRetryCount, kLoginDelayTime );
2238	fLogin->setMaxPayloadSize ( kMaxFireWirePayload );
2239	fLogin->setStatusNotifyProc ( this, StatusNotifyStatic );
2240	fLogin->setUnsolicitedStatusNotifyProc ( this, UnsolicitedStatusNotifyStatic );
2241	fLogin->setLoginCompletion ( this, LoginCompletionStatic );
2242	fLogin->setLogoutCompletion ( this, LogoutCompletionStatic );
2243	fLogin->setFetchAgentResetCompletion ( this, FetchAgentResetCompleteStatic );
2244
2245	// Set BUSY_TIMEOUT register value see SBP-2 spec section 6.2
2246	// also see IEEE Std 1394-1995 section 8.3.2.3.5 ( no I am not kidding )
2247	fLogin->setBusyTimeoutRegisterValue ( kDefaultBusyTimeoutValue );
2248
2249	fLUNResetORB = fSBPTarget->createManagementORB ( this, LunResetCompleteStatic );
2250	require_action ( fLUNResetORB, exit, status = kIOReturnNoMemory );
2251
2252	fLUNResetORB->setCommandFunction ( kFWSBP2LogicalUnitReset );
2253	fLUNResetORB->setManageeCommand ( fLogin );
2254
2255	// Allocate expansion data.
2256	reserved = ( ExpansionData * ) IOMalloc ( sizeof ( ExpansionData ) );
2257	require_action ( reserved, exit, status = kIOReturnNoMemory );
2258	bzero ( reserved, sizeof ( ExpansionData ) );
2259
2260	reserved->fLoginState = kFirstTimeLoggingInState;
2261
2262	// Cache this as a member variable since we don't want to do this on every command.
2263	reserved->fAlwaysSetSenseData = getProperty ( kAlwaysSetAutoSenseData, gIOServicePlane ) ? true : false;
2264
2265	workLoop = getWorkLoop ( );
2266	require_action ( workLoop, exit, status = kIOReturnNoMemory );
2267
2268	reserved->fCommandPool = IOCommandPool::withWorkLoop ( workLoop );
2269	require_action ( reserved->fCommandPool, exit, status = kIOReturnNoMemory );
2270
2271	reserved->fSubmitQueue = IOCommandPool::withWorkLoop ( workLoop );
2272	require_action ( reserved->fSubmitQueue, exit, status = kIOReturnNoMemory );
2273
2274	for ( UInt32 i = 0; i < kCommandPoolOrbCount; ++i )
2275	{
2276
2277		IOFireWireSBP2ORB *		orb			= NULL;
2278		SBP2ClientOrbData *		clientData	= NULL;
2279
2280		orb = fLogin->createORB ( );
2281		require_action ( orb, exit, status = kIOReturnNoMemory );
2282
2283		clientData = ( SBP2ClientOrbData * ) IOMalloc ( sizeof ( SBP2ClientOrbData ) );
2284		require_action ( clientData, exit, status = kIOReturnNoMemory );
2285
2286		bzero ( clientData, sizeof ( SBP2ClientOrbData ) );
2287		clientData->orb	= orb;
2288		orb->setRefCon ( ( void * ) clientData );
2289
2290
2291		// Enqueue the command in the free list.
2292		reserved->fCommandPool->returnCommand ( orb );
2293
2294	}
2295
2296	status = kIOReturnSuccess;
2297
2298
2299exit:
2300
2301
2302	return status;
2303
2304}
2305
2306//-----------------------------------------------------------------------------
2307// DeallocateResources - Deallocates resources.						[PROTECTED]
2308//-----------------------------------------------------------------------------
2309
2310void
2311IOFireWireSerialBusProtocolTransport::DeallocateResources ( void )
2312{
2313
2314	IOFireWireSBP2ORB *		orb			= NULL;
2315	SBP2ClientOrbData *		clientData	= NULL;
2316
2317	DLOG ( ( "%s: DeallocateResources called\n", getName ( ) ) );
2318
2319	// /!\ WARNING - always release orb's before logins.
2320	if ( fLUNResetORB != NULL )
2321	{
2322
2323		fLUNResetORB->release ( );
2324		fLUNResetORB = NULL;
2325
2326	}
2327
2328	if ( reserved != NULL )
2329	{
2330
2331		// Drain the queue when requesting close so there are no in use commands when this is called.
2332		while ( ( orb = ( IOFireWireSBP2ORB * ) reserved->fCommandPool->getCommand ( false ) ) )
2333		{
2334
2335			clientData = ( SBP2ClientOrbData * ) orb->getRefCon ( );
2336			if ( clientData != NULL )
2337			{
2338
2339				IOFree ( clientData, sizeof ( SBP2ClientOrbData ) );
2340				clientData = NULL;
2341
2342			}
2343
2344			orb->release ( );
2345			orb = NULL;
2346
2347		}
2348
2349		reserved->fCommandPool->release ( );
2350		reserved->fCommandPool = NULL;
2351
2352		reserved->fSubmitQueue->release ( );
2353		reserved->fSubmitQueue = NULL;
2354
2355	}
2356
2357	if ( fLogin != NULL )
2358	{
2359
2360		fLogin->release ( );
2361		fLogin = NULL;
2362
2363	}
2364
2365}
2366
2367
2368//-----------------------------------------------------------------------------
2369//	login - login bottleneck to track retries.						[PROTECTED]
2370//-----------------------------------------------------------------------------
2371
2372OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 1 );
2373
2374IOReturn
2375IOFireWireSerialBusProtocolTransport::login ( void )
2376{
2377
2378	IOReturn	status = kIOReturnError;
2379
2380	DLOG ( ( "%s: submitting login.\n", getName ( ) ) );
2381
2382	fNeedLogin 	= false;
2383	fLoggedIn 	= false;
2384
2385	// If we enter this again and fLoginRetryCount is already
2386	// at kMaxLoginRetryCount - we should default status to an error.
2387	for ( ; fLoginRetryCount < kMaxLoginRetryCount; ++fLoginRetryCount )
2388	{
2389
2390		RecordFireWireTimeStamp (
2391			FW_TRACE ( kLoginRequest ),
2392			( uintptr_t ) this,
2393			reserved->fLoginState,
2394			fLoginRetryCount );
2395
2396		status = submitLogin ( );
2397		if ( status == kIOReturnSuccess )
2398		{
2399			break;
2400		}
2401
2402	}
2403
2404	if ( status != kIOReturnSuccess )
2405	{
2406
2407		fNeedLogin 	= true;
2408		fLoggedIn 	= false;
2409
2410		RecordFireWireTimeStamp (
2411			FW_TRACE ( kLoginLost ),
2412			( uintptr_t ) this,
2413			reserved->fLoginState );
2414
2415		loginLost ( );
2416
2417	}
2418
2419	return status;
2420
2421}
2422
2423
2424//-----------------------------------------------------------------------------
2425// submitLogin - submitLogin bottleneck for subclass.				[PROTECTED]
2426//-----------------------------------------------------------------------------
2427
2428OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 2 );
2429
2430IOReturn
2431IOFireWireSerialBusProtocolTransport::submitLogin ( void )
2432{
2433
2434	IOReturn	status = kIOReturnSuccess;
2435
2436	DLOG ( ( "%s: submitting login.\n", getName ( ) ) );
2437
2438	status = fLogin->submitLogin ( );
2439
2440	return status;
2441
2442}
2443
2444
2445//-----------------------------------------------------------------------------
2446// loginLost - login lost bottleneck for subclass.					[PROTECTED]
2447//-----------------------------------------------------------------------------
2448
2449OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 3 );
2450
2451void IOFireWireSerialBusProtocolTransport::loginLost ( void )
2452{
2453
2454	DLOG ( ( "%s: login lost.\n", getName ( ) ) );
2455	// Notification that the login is lost.
2456
2457}
2458
2459
2460//-----------------------------------------------------------------------------
2461// loginSuspended - login suspended bottleneck for subclass.		[PROTECTED]
2462//-----------------------------------------------------------------------------
2463
2464OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 4 );
2465
2466void
2467IOFireWireSerialBusProtocolTransport::loginSuspended ( void )
2468{
2469
2470	DLOG ( ( "%s: login suspended.\n", getName ( ) ) );
2471	// A successful reconnect orb is required.
2472
2473}
2474
2475
2476//-----------------------------------------------------------------------------
2477// loginResumed - login resumed bottleneck for subclass.			[PROTECTED]
2478//-----------------------------------------------------------------------------
2479
2480OSMetaClassDefineReservedUsed ( IOFireWireSerialBusProtocolTransport, 5 );
2481
2482void
2483IOFireWireSerialBusProtocolTransport::loginResumed ( void )
2484{
2485
2486	DLOG ( ( "%s: login resumed.\n", getName ( ) ) );
2487	// A reconnect orb has succeeded.
2488
2489}
2490
2491
2492#if 0
2493#pragma mark -
2494#pragma mark Static Debug Assertion Method
2495#pragma mark -
2496#endif
2497
2498
2499//-----------------------------------------------------------------------------
2500//	IOFireWireSerialBusProtocolTransportDebugAssert					   [STATIC]
2501//-----------------------------------------------------------------------------
2502
2503#if !DEBUG_ASSERT_PRODUCTION_CODE
2504
2505void
2506IOFireWireSerialBusProtocolTransportDebugAssert (
2507		const char * 	componentNameString,
2508		const char * 	assertionString,
2509		const char * 	exceptionLabelString,
2510		const char * 	errorString,
2511		const char * 	fileName,
2512		long 			lineNumber,
2513		int 			errorCode )
2514{
2515	IOLog ( "%s Assert failed: %s ", componentNameString, assertionString );
2516
2517	if ( exceptionLabelString != NULL ) { IOLog ( "%s ", exceptionLabelString ); }
2518
2519	if ( errorString != NULL ) { IOLog ( "%s ", errorString ); }
2520
2521	if ( fileName != NULL ) { IOLog ( "file: %s ", fileName ); }
2522
2523	if ( lineNumber != 0 ) { IOLog ( "line: %ld ", lineNumber ); }
2524
2525	if ( ( long ) errorCode != 0 ) { IOLog ( "error: %ld ( 0x%08lx )",
2526											 ( long ) errorCode,
2527											 ( long ) errorCode  ); }
2528
2529	IOLog ( "\n" );
2530}
2531
2532#endif
2533
2534
2535//-----------------------------------------------------------------------------
2536//	RecordFireWireTimeStamp											   [STATIC]
2537//-----------------------------------------------------------------------------
2538
2539static inline void
2540RecordFireWireTimeStamp (
2541	unsigned int code,
2542	unsigned int a, unsigned int b,
2543	unsigned int c, unsigned int d )
2544{
2545
2546	if ( gSBP2DiskDebugFlags & kSBP2DiskEnableTracePointsMask )
2547	{
2548		IOTimeStampConstant ( code, a, b, c, d );
2549	}
2550
2551}
2552
2553
2554#if 0
2555#pragma mark -
2556#pragma mark VTable Padding
2557#pragma mark -
2558#endif
2559
2560OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport,  7 );
2561OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport,  8 );
2562OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport,  9 );
2563OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 10 );
2564OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 11 );
2565OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 12 );
2566OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 13 );
2567OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 14 );
2568OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 15 );
2569OSMetaClassDefineReservedUnused ( IOFireWireSerialBusProtocolTransport, 16 );
2570