1/*
2 * Copyright (c) 2002-2008 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// Libkern includes
30#include <libkern/c++/OSData.h>
31#include <libkern/c++/OSDictionary.h>
32
33// General IOKit includes
34#include <IOKit/IOBufferMemoryDescriptor.h>
35#include <IOKit/IOMessage.h>
36#include <IOKit/IODeviceTreeSupport.h>
37
38// IOKit storage includes
39#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
40#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
41
42// SCSI Architecture Model Family includes
43#include <IOKit/scsi/SCSICommandOperationCodes.h>
44#include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h>
45
46// SCSI Parallel Family includes
47#include "IOSCSIParallelInterfaceDevice.h"
48
49
50//-----------------------------------------------------------------------------
51//	Macros
52//-----------------------------------------------------------------------------
53
54#define DEBUG 												0
55#define DEBUG_ASSERT_COMPONENT_NAME_STRING					"SPI Device"
56
57#if DEBUG
58#define SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL				0
59#endif
60
61#include "IOSCSIParallelFamilyDebugging.h"
62
63#if ( SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL >= 1 )
64#define PANIC_NOW(x)           panic x
65#else
66#define PANIC_NOW(x)
67#endif
68
69#if ( SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL >= 2 )
70#define ERROR_LOG(x)           IOLog x
71#else
72#define ERROR_LOG(x)
73#endif
74
75#if ( SCSI_PARALLEL_DEVICE_DEBUGGING_LEVEL >= 3 )
76#define STATUS_LOG(x)          IOLog x
77#else
78#define STATUS_LOG(x)
79#endif
80
81
82#define super IOSCSIProtocolServices
83OSDefineMetaClassAndStructors ( IOSCSIParallelInterfaceDevice, IOSCSIProtocolServices );
84
85
86//-----------------------------------------------------------------------------
87//	Constants
88//-----------------------------------------------------------------------------
89
90#define kIOPropertyIOUnitKey		"IOUnit"
91#define kIODeviceLocationKey		"io-device-location"
92
93#define kMaxTaskRetryCount			3
94
95enum
96{
97	kWorldWideNameDataSize 		= 8,
98	kAddressIdentifierDataSize 	= 3,
99	kALPADataSize				= 1,
100	kSASAddressDataSize			= 8,
101	kSCSIPortIdentifierDataSize = 8
102};
103
104// Used by power manager to figure out what states we support
105// The default implementation supports two basic states: ON and OFF
106// ON state means the device can be used on this transport layer
107// OFF means the device cannot receive any I/O on this transport layer
108static IOPMPowerState sPowerStates[kSCSIProtocolLayerNumDefaultStates] =
109{
110	{ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
111	{ 1, (IOPMDeviceUsable | IOPMMaxPerformance), IOPMPowerOn, IOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0 }
112};
113
114
115#if 0
116#pragma mark -
117#pragma mark IOKit Member Routines
118#pragma mark -
119#endif
120
121
122//-----------------------------------------------------------------------------
123//	SetInitialTargetProperties										   [PUBLIC]
124//-----------------------------------------------------------------------------
125
126bool
127IOSCSIParallelInterfaceDevice::SetInitialTargetProperties (
128										OSDictionary * properties )
129{
130
131	OSDictionary *	protocolDict	= NULL;
132	OSObject *		value			= NULL;
133	bool			result			= false;
134
135	protocolDict = OSDictionary::withCapacity ( properties->getCount ( ) );
136	require_nonzero ( protocolDict, INIT_FAILURE );
137
138	setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
139	protocolDict->release ( );
140	protocolDict = NULL;
141
142	// Set the properties from the dictionary
143	value = properties->getObject ( kIOPropertyFibreChannelNodeWorldWideNameKey );
144	SetTargetProperty ( kIOPropertyFibreChannelNodeWorldWideNameKey, value );
145
146	value = properties->getObject ( kIOPropertyFibreChannelPortWorldWideNameKey );
147	SetTargetProperty ( kIOPropertyFibreChannelPortWorldWideNameKey, value );
148
149	value = properties->getObject ( kIOPropertyFibreChannelAddressIdentifierKey );
150	SetTargetProperty ( kIOPropertyFibreChannelAddressIdentifierKey, value );
151
152	value = properties->getObject ( kIOPropertyFibreChannelALPAKey );
153	SetTargetProperty ( kIOPropertyFibreChannelALPAKey, value );
154
155	value = properties->getObject ( kIOPropertySASAddressKey );
156	SetTargetProperty ( kIOPropertySASAddressKey, value );
157
158	value = properties->getObject ( kIOPropertyRetryCountKey );
159	SetTargetProperty ( kIOPropertyRetryCountKey, value );
160
161	result = true;
162
163
164INIT_FAILURE:
165
166
167	return result;
168
169}
170
171
172//-----------------------------------------------------------------------------
173//	start															   [PUBLIC]
174//-----------------------------------------------------------------------------
175
176bool
177IOSCSIParallelInterfaceDevice::start ( IOService * provider )
178{
179
180	OSDictionary *	protocolDict	= NULL;
181	OSDictionary *	copyDict		= NULL;
182	bool			result			= false;
183	char			unit[10];
184
185	// Save access to the controller object so that Tasks can be sent
186	// for execution.
187	fController = OSDynamicCast ( IOSCSIParallelInterfaceController, provider );
188	require_nonzero ( fController, PROVIDER_CAST_FAILURE );
189
190	// Retain the controller.
191	fController->retain ( );
192
193	// Execute the inherited start
194	result = super::start ( provider );
195	require ( result, PROVIDER_START_FAILURE );
196
197	// Open the controller, the provider.
198	result = fController->open ( this );
199	require ( result, CONTROLLER_OPEN_FAILURE );
200
201	result = fController->InitializeTargetForID ( fTargetIdentifier );
202	require ( result, CONTROLLER_INIT_FAILURE );
203
204	// Check if controller supports Multipathing
205	fMultiPathSupport = fController->DoesHBASupportMultiPathing ( );
206
207	// Setup power management for this object.
208	InitializePowerManagement ( provider );
209
210	copyDict = OSDynamicCast ( OSDictionary, copyProperty ( kIOPropertyProtocolCharacteristicsKey ) );
211	if ( copyDict != NULL )
212	{
213
214		protocolDict = ( OSDictionary * ) copyDict->copyCollection ( );
215		copyDict->release ( );
216		copyDict = NULL;
217
218	}
219
220	if ( protocolDict != NULL )
221	{
222
223		OSNumber *	targetID = NULL;
224
225		// Create an OSNumber object with the SCSI Target Identifier
226		targetID = OSNumber::withNumber ( fTargetIdentifier, 64 );
227		if ( targetID != NULL )
228		{
229
230			protocolDict->setObject ( kIOPropertySCSITargetIdentifierKey, targetID );
231
232			// Set the Unit number used to build the device tree path
233			setProperty ( kIOPropertyIOUnitKey, targetID );
234
235			targetID->release ( );
236
237		}
238
239		setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
240		protocolDict->release ( );
241		protocolDict = NULL;
242
243	}
244
245	// Set the location to allow booting
246    snprintf ( unit, 10, "%x", ( int ) fTargetIdentifier );
247    setLocation ( unit );
248
249	// The device and this driver have been succesfully configured
250	// and are ready to provide their services, call CreateSCSITargetDevice().
251	CreateSCSITargetDevice ( );
252
253	return true;
254
255
256CONTROLLER_INIT_FAILURE:
257CONTROLLER_OPEN_FAILURE:
258PROVIDER_START_FAILURE:
259PROVIDER_CAST_FAILURE:
260
261
262	return false;
263
264}
265
266
267//-----------------------------------------------------------------------------
268//	stop															   [PUBLIC]
269//-----------------------------------------------------------------------------
270
271void
272IOSCSIParallelInterfaceDevice::stop ( IOService * provider )
273{
274	super::stop ( provider );
275}
276
277
278//-----------------------------------------------------------------------------
279//	finalize													       [PUBLIC]
280//-----------------------------------------------------------------------------
281
282bool
283IOSCSIParallelInterfaceDevice::finalize ( IOOptionBits options )
284{
285
286	if ( ( fController != NULL ) && ( fController->isOpen ( this ) == true ) )
287	{
288
289		fController->close ( this );
290
291	}
292
293	return super::finalize ( options );
294
295}
296
297
298//-----------------------------------------------------------------------------
299//	free															   [PUBLIC]
300//-----------------------------------------------------------------------------
301
302void
303IOSCSIParallelInterfaceDevice::free ( void )
304{
305
306	// Release the HBA specific data
307	if ( fHBAData != NULL )
308	{
309
310		IOFree ( fHBAData, fHBADataSize );
311		fHBAData		= NULL;
312		fHBADataSize	= 0;
313
314	}
315
316	// Release the lock for the Task Queue.
317	if ( fQueueLock != NULL )
318	{
319
320		// Free the SCSI Task queue access lock.
321		IOSimpleLockFree ( fQueueLock );
322		fQueueLock = NULL;
323
324	}
325
326	if ( fController != NULL )
327	{
328
329		fController->release ( );
330		fController = NULL;
331
332	}
333
334	super::free ( );
335
336}
337
338
339//-----------------------------------------------------------------------------
340//	message															   [PUBLIC]
341//-----------------------------------------------------------------------------
342
343IOReturn
344IOSCSIParallelInterfaceDevice::message (
345							UInt32 						type,
346							IOService * 				provider,
347							void * 						argument )
348{
349
350	IOReturn	result = kIOReturnSuccess;
351
352	switch ( type )
353	{
354
355		case kSCSIControllerNotificationBusReset:
356		{
357
358			// Bus reset occurred, disavow all negotiation settings
359			// and force renegotiation
360			for ( int index = 0; index < kSCSIParallelFeature_TotalFeatureCount; index++ )
361			{
362
363				// Set each one to false.
364				fFeatureIsNegotiated[index] = false;
365
366			}
367
368			// Message the SAM drivers to verify their device's state
369			SendNotification_VerifyDeviceState ( );
370
371		}
372		break;
373
374		case kSCSIPort_NotificationStatusChange:
375		{
376
377			// Port status is changing, let target device object know
378			// about it.
379			messageClients ( kSCSIPort_NotificationStatusChange, argument );
380
381		}
382
383		default:
384		{
385			result = super::message ( type, provider, argument );
386		}
387		break;
388
389	}
390
391	return result;
392
393}
394
395
396//-----------------------------------------------------------------------------
397//	requestProbe													   [PUBLIC]
398//-----------------------------------------------------------------------------
399
400IOReturn
401IOSCSIParallelInterfaceDevice::requestProbe ( IOOptionBits options )
402{
403
404	// See if this device already has any opens on it.
405	if ( isOpen ( ) == false )
406	{
407
408		// The device and this driver have been succesfully configured
409		// and are ready to provide their services, call CreateSCSITargetDevice().
410		CreateSCSITargetDevice ( );
411
412		return kIOReturnSuccess;
413
414	}
415
416	else
417	{
418		return kIOReturnNotPermitted;
419	}
420
421}
422
423//-----------------------------------------------------------------------------
424// InitializePowerManagement - 	Register the driver with our policy-maker
425//								(also in the same class).			[PROTECTED]
426//-----------------------------------------------------------------------------
427
428void
429IOSCSIParallelInterfaceDevice::InitializePowerManagement ( IOService * provider )
430{
431
432	PMinit ( );
433
434	temporaryPowerClampOn ( );
435
436	provider->joinPMtree ( this );
437
438	// Call makeUsable here to tell the power manager to put us in our
439	// highest power state when we call registerPowerDriver().
440	makeUsable ( );
441
442	fPowerManagementInitialized = true;
443
444	fCurrentPowerState = kSCSIProtocolLayerPowerStateOn;
445
446	// Register this piece with power management as the "policy maker"
447	// i.e. the thing that controls power management for the protocol layer
448	registerPowerDriver ( this, sPowerStates, kSCSIProtocolLayerNumDefaultStates );
449
450	// make sure we default to on state
451	changePowerStateTo ( kSCSIProtocolLayerPowerStateOn );
452
453	fCurrentPowerState = kSCSIProtocolLayerPowerStateOn;
454	fProposedPowerState = kSCSIProtocolLayerPowerStateOn;
455
456}
457
458#if 0
459#pragma mark -
460#pragma mark Device Object Management Member routines
461#pragma mark -
462#endif
463
464
465//-----------------------------------------------------------------------------
466//	CreateTarget	- 	Creates an IOSCSIParallelInterfaceDevice for the
467//						specified target ID.				   [STATIC][PUBLIC]
468//-----------------------------------------------------------------------------
469
470IOSCSIParallelInterfaceDevice *
471IOSCSIParallelInterfaceDevice::CreateTarget (
472							SCSITargetIdentifier 		targetID,
473							UInt32 						sizeOfHBAData,
474							IORegistryEntry *			entry )
475{
476
477	IOSCSIParallelInterfaceDevice * newDevice	= NULL;
478	bool							result		= false;
479
480	newDevice = OSTypeAlloc ( IOSCSIParallelInterfaceDevice );
481	require_nonzero ( newDevice, DEVICE_CREATION_FAILURE );
482
483	result = newDevice->InitTarget ( targetID, sizeOfHBAData, entry );
484	require ( result, RELEASE_DEVICE );
485
486	return newDevice;
487
488
489RELEASE_DEVICE:
490
491
492	require_nonzero_quiet ( newDevice, DEVICE_CREATION_FAILURE );
493	newDevice->release ( );
494	newDevice = NULL;
495
496
497DEVICE_CREATION_FAILURE:
498
499
500	return NULL;
501
502}
503
504
505//-----------------------------------------------------------------------------
506//	InitTarget -Initializes a target device.						[PROTECTED]
507//-----------------------------------------------------------------------------
508
509bool
510IOSCSIParallelInterfaceDevice::InitTarget (
511							SCSITargetIdentifier 		targetID,
512							UInt32 						sizeOfHBAData,
513							IORegistryEntry *			entry )
514{
515
516	bool	result	= false;
517
518	result = super::init ( 0 );
519	require ( result, ERROR_EXIT );
520
521	queue_init ( &fOutstandingTaskList );
522	queue_init ( &fResendTaskList );
523
524	// Allocate the lock for the Task Queue
525	fQueueLock = IOSimpleLockAlloc ( );
526	require_nonzero ( fQueueLock, ERROR_EXIT );
527
528	if ( entry != NULL )
529	{
530
531		OSObject *	value = NULL;
532
533		lockForArbitration ( );
534		result = attachToParent ( entry, gIODTPlane );
535		unlockForArbitration ( );
536
537		require ( result, ATTACH_TO_PARENT_FAILURE );
538
539		value = entry->copyProperty ( kIODeviceLocationKey );
540		if ( value != NULL )
541		{
542			setProperty ( kIODeviceLocationKey, value );
543		}
544
545	}
546
547	// Set all of the fields to their defaults
548	fHBADataSize		= sizeOfHBAData;
549	fTargetIdentifier	= targetID;
550
551	fAllowResends = true;
552
553	// Set Multipath support to 'true' by default.
554	// The HBA driver will be queried and this will be
555	// updated.
556	fMultiPathSupport = true;
557
558	if ( sizeOfHBAData != 0 )
559	{
560
561		// Allocate the HBA specific data for the device object
562		fHBAData = IOMalloc ( sizeOfHBAData );
563		require_nonzero ( fHBAData, HBA_DATA_ALLOC_FAILURE );
564		bzero ( fHBAData, sizeOfHBAData );
565
566	}
567
568	return true;
569
570
571HBA_DATA_ALLOC_FAILURE:
572ATTACH_TO_PARENT_FAILURE:
573
574
575	require_nonzero_quiet ( fQueueLock, ERROR_EXIT );
576	IOSimpleLockFree ( fQueueLock );
577	fQueueLock = NULL;
578
579
580ERROR_EXIT:
581
582
583	return false;
584
585}
586
587
588//-----------------------------------------------------------------------------
589//	DestroyTarget	- 	Destroys an IOSCSIParallelInterfaceDevice.	   [PUBLIC]
590//-----------------------------------------------------------------------------
591
592void
593IOSCSIParallelInterfaceDevice::DestroyTarget ( void )
594{
595
596	IORegistryEntry *		parent = NULL;
597
598	SendNotification_DeviceRemoved ( );
599
600	// Get rid of the io-device-location property first.
601	removeProperty ( kIODeviceLocationKey );
602
603	// Remove anything from the "resend queue".
604	IOSimpleLockLock ( fQueueLock );
605
606	fAllowResends = false;
607
608	IOSimpleLockUnlock ( fQueueLock );
609
610	// Remove this entry from the IODeviceTree plane.
611	lockForArbitration ( );
612
613	parent = getParentEntry ( gIODTPlane );
614
615	if ( parent != NULL )
616	{
617		detachFromParent ( parent, gIODTPlane );
618	}
619
620	unlockForArbitration ( );
621
622}
623
624
625//-----------------------------------------------------------------------------
626//	GetPreviousDeviceInList - Retrieves previous device in linked list.
627//																	   [PUBLIC]
628//-----------------------------------------------------------------------------
629
630IOSCSIParallelInterfaceDevice *
631IOSCSIParallelInterfaceDevice::GetPreviousDeviceInList ( void )
632{
633	return fPreviousParallelDevice;
634}
635
636
637//-----------------------------------------------------------------------------
638//	SetPreviousDeviceInList - Sets previous device in linked list.	   [PUBLIC]
639//-----------------------------------------------------------------------------
640
641void
642IOSCSIParallelInterfaceDevice::SetPreviousDeviceInList (
643							IOSCSIParallelInterfaceDevice * newPrev )
644{
645	fPreviousParallelDevice = newPrev;
646}
647
648
649//-----------------------------------------------------------------------------
650//	GetNextDeviceInList - Retrieves next device in linked list.		   [PUBLIC]
651//-----------------------------------------------------------------------------
652
653IOSCSIParallelInterfaceDevice *
654IOSCSIParallelInterfaceDevice::GetNextDeviceInList ( void )
655{
656	return fNextParallelDevice;
657}
658
659
660//-----------------------------------------------------------------------------
661//	SetNextDeviceInList - Sets next device in linked list.			   [PUBLIC]
662//-----------------------------------------------------------------------------
663
664void
665IOSCSIParallelInterfaceDevice::SetNextDeviceInList (
666							IOSCSIParallelInterfaceDevice * 	newNext )
667{
668	fNextParallelDevice = newNext;
669}
670
671
672//-----------------------------------------------------------------------------
673//	DetermineParallelFeatures - 	Determines parallel protocol features based
674//									on INQUIRY data.				  [PRIVATE]
675//-----------------------------------------------------------------------------
676
677void
678IOSCSIParallelInterfaceDevice::DetermineParallelFeatures ( UInt8 * inqData )
679{
680
681	OSDictionary *	dict			= NULL;
682	OSDictionary *	copyDict		= NULL;
683	OSNumber *		features		= NULL;
684	UInt64			deviceFeatures	= 0;
685	UInt64			ITNexusFeatures	= 0;
686	bool			supported		= false;
687	UInt8			inqSCSIVersion	= 0;
688	UInt8			inqDataLength	= 0;
689
690	inqSCSIVersion = ( ( SCSICmd_INQUIRY_StandardData * ) inqData )->VERSION & kINQUIRY_ANSI_VERSION_Mask;
691	inqDataLength = ( ( SCSICmd_INQUIRY_StandardData * ) inqData )->ADDITIONAL_LENGTH + 5;
692
693	// Verify that the device is SCSI-2 compliant and the INQUIRY data is large
694	// enough to contain the SCSI-2 feature flags
695	if ( ( inqSCSIVersion >= kINQUIRY_ANSI_VERSION_SCSI_2_Compliant ) &&
696		 ( inqDataLength > kINQUIRY_Byte7_Offset ) )
697	{
698
699		if ( inqData[kINQUIRY_Byte7_Offset] & kINQUIRY_Byte7_SYNC_Mask )
700		{
701
702			deviceFeatures |= (1 << kSCSIParallelFeature_SynchronousDataTransfer);
703			supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_SynchronousDataTransfer );
704			if ( supported == true )
705			{
706
707				fITNexusSupportsFeature[kSCSIParallelFeature_SynchronousDataTransfer] = true;
708				ITNexusFeatures |= (1 << kSCSIParallelFeature_SynchronousDataTransfer);
709
710			}
711
712		}
713
714		if ( inqData[kINQUIRY_Byte7_Offset] & kINQUIRY_Byte7_WBUS16_Mask )
715		{
716
717			deviceFeatures |= (1 << kSCSIParallelFeature_WideDataTransfer);
718			supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_WideDataTransfer );
719			if ( supported == true )
720			{
721
722				fITNexusSupportsFeature[kSCSIParallelFeature_WideDataTransfer] = true;
723				ITNexusFeatures |= (1 << kSCSIParallelFeature_WideDataTransfer);
724
725			}
726
727		}
728
729	}
730
731	// Verify that the device is SPC compliant and the INQUIRY data is large
732	// enough to contain the SPI-3 feature flags
733	if ( ( inqSCSIVersion >= kINQUIRY_ANSI_VERSION_SCSI_SPC_Compliant ) &&
734		 ( inqDataLength > kINQUIRY_Byte56_Offset ) )
735	{
736
737		if ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_IUS_Mask )
738		{
739
740			deviceFeatures |= (1 << kSCSIParallelFeature_InformationUnitTransfers);
741			supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_InformationUnitTransfers );
742			if ( supported == true )
743			{
744
745				fITNexusSupportsFeature[kSCSIParallelFeature_InformationUnitTransfers] = true;
746				ITNexusFeatures |= (1 << kSCSIParallelFeature_InformationUnitTransfers);
747
748			}
749
750		}
751
752		if ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_QAS_Mask )
753		{
754
755			deviceFeatures |= (1 << kSCSIParallelFeature_QuickArbitrationAndSelection);
756			supported = DoesHBASupportSCSIParallelFeature( kSCSIParallelFeature_QuickArbitrationAndSelection );
757			if ( supported == true )
758			{
759
760				fITNexusSupportsFeature[kSCSIParallelFeature_QuickArbitrationAndSelection] = true;
761				ITNexusFeatures |= (1 << kSCSIParallelFeature_QuickArbitrationAndSelection);
762
763			}
764
765		}
766
767		if ( ( ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_CLOCKING_Mask ) == kINQUIRY_Byte56_CLOCKING_ONLY_DT ) ||
768			 ( ( inqData[kINQUIRY_Byte56_Offset] & kINQUIRY_Byte56_CLOCKING_Mask ) == kINQUIRY_Byte56_CLOCKING_ST_AND_DT ) )
769		{
770
771			deviceFeatures |= (1 << kSCSIParallelFeature_DoubleTransitionDataTransfers);
772			supported = DoesHBASupportSCSIParallelFeature ( kSCSIParallelFeature_DoubleTransitionDataTransfers );
773			if ( supported == true )
774			{
775
776				fITNexusSupportsFeature[kSCSIParallelFeature_DoubleTransitionDataTransfers] = true;
777				ITNexusFeatures |= (1 << kSCSIParallelFeature_DoubleTransitionDataTransfers);
778
779			}
780
781		}
782
783	}
784
785	copyDict = ( OSDictionary * ) copyProperty ( kIOPropertyProtocolCharacteristicsKey );
786	if ( copyDict != NULL )
787	{
788
789		dict = ( OSDictionary * ) copyDict->copyCollection ( );
790		copyDict->release ( );
791
792	}
793
794	if ( dict != NULL )
795	{
796
797		features = OSNumber::withNumber ( deviceFeatures, 64 );
798		if ( features != NULL )
799		{
800
801			dict->setObject ( kIOPropertySCSIDeviceFeaturesKey, features );
802			features->release ( );
803			features = NULL;
804
805		}
806
807		features = OSNumber::withNumber ( ITNexusFeatures, 64 );
808		if ( features != NULL )
809		{
810
811			dict->setObject ( kIOPropertySCSI_I_T_NexusFeaturesKey, features );
812			features->release ( );
813			features = NULL;
814
815		}
816
817		setProperty ( kIOPropertyProtocolCharacteristicsKey, dict );
818		dict->release ( );
819		dict = NULL;
820
821	}
822
823}
824
825
826//-----------------------------------------------------------------------------
827//	GetTargetIdentifier - Retrieves the SCSITargetIdentifier for this device.
828//																	   [PUBLIC]
829//-----------------------------------------------------------------------------
830
831SCSITargetIdentifier
832IOSCSIParallelInterfaceDevice::GetTargetIdentifier ( void )
833{
834	return fTargetIdentifier;
835}
836
837
838//-----------------------------------------------------------------------------
839//	GetHBADataPointer - Retrieves the pointer to the HBA Data for this device.
840//																	   [PUBLIC]
841//-----------------------------------------------------------------------------
842
843void *
844IOSCSIParallelInterfaceDevice::GetHBADataPointer ( void )
845{
846	return fHBAData;
847}
848
849
850//-----------------------------------------------------------------------------
851//	GetHBADataSize - Retrieves the HBA Data size for this device.	   [PUBLIC]
852//-----------------------------------------------------------------------------
853
854UInt32
855IOSCSIParallelInterfaceDevice::GetHBADataSize ( void )
856{
857	return fHBADataSize;
858}
859
860
861//-----------------------------------------------------------------------------
862//	IsFeatureNegotiationNecessary - 	Checks if a feature negotiation is
863//										necessary.					   [PUBLIC]
864//-----------------------------------------------------------------------------
865
866bool
867IOSCSIParallelInterfaceDevice::IsFeatureNegotiationNecessary (
868							SCSIParallelFeature			feature )
869{
870	// Verify that the requested feature is one that is known to
871	// the device object.
872	if ( feature >= kSCSIParallelFeature_TotalFeatureCount )
873	{
874		return false;
875	}
876
877	return ( fITNexusSupportsFeature[feature] &&
878			 ( fFeatureIsNegotiated[feature] == false ) );
879
880}
881
882
883//-----------------------------------------------------------------------------
884//	FindTaskForAddress - 	Find the outstanding task for the Task Address of
885//							this Target and the specified Lun and Tag.
886//																	   [PUBLIC]
887//-----------------------------------------------------------------------------
888
889SCSIParallelTaskIdentifier
890IOSCSIParallelInterfaceDevice::FindTaskForAddress (
891							SCSILogicalUnitNumber		theL,
892							SCSITaggedTaskIdentifier	theQ )
893{
894
895	SCSIParallelTask *	task 	= NULL;
896	bool				found	= false;
897
898	// Grab the queue lock.
899	IOSimpleLockLock ( fQueueLock );
900
901	// Iterate over all the commands in the list, looking for one that matches.
902	queue_iterate ( &fOutstandingTaskList, task, SCSIParallelTask *, fCommandChain )
903	{
904
905		// Does this one match?
906		if ( ( GetLogicalUnitNumber ( task ) == theL ) && ( GetTaggedTaskIdentifier ( task ) == theQ ) )
907		{
908
909			// Yes, stop searching.
910			found = true;
911			break;
912
913		}
914
915	}
916
917	IOSimpleLockUnlock ( fQueueLock );
918
919	if ( found == false )
920	{
921		task = NULL;
922	}
923
924	return task;
925
926}
927
928
929//-----------------------------------------------------------------------------
930//	FindTaskForControllerIdentifier - Find the outstanding task for the
931//										identifier. 				   [PUBLIC]
932//-----------------------------------------------------------------------------
933
934SCSIParallelTaskIdentifier
935IOSCSIParallelInterfaceDevice::FindTaskForControllerIdentifier (
936							UInt64						theIdentifier )
937{
938
939
940	SCSIParallelTask *	task 	= NULL;
941	bool				found	= false;
942
943	// Grab the queue lock.
944	IOSimpleLockLock ( fQueueLock );
945
946	// Iterate over all the commands in the list, looking for one that matches.
947	queue_iterate ( &fOutstandingTaskList, task, SCSIParallelTask *, fCommandChain )
948	{
949
950		// Check if the request is to return the first element on the queue.
951		if ( theIdentifier == kSCSIParallelTaskControllerIDQueueHead )
952		{
953
954			// The request is for the first element on the queue, this will
955			// break the first time through the while loop.
956			found = true;
957			break;
958
959		}
960
961		// Does this one match?
962		if ( GetControllerTaskIdentifier ( task ) == theIdentifier )
963		{
964
965			// Yes, stop searching.
966			found = true;
967			break;
968
969		}
970
971	}
972
973	IOSimpleLockUnlock ( fQueueLock );
974
975	if ( found == false )
976	{
977		task = NULL;
978	}
979
980	return task;
981
982}
983
984
985//-----------------------------------------------------------------------------
986//	SetTargetProperty - Sets a target property. 					   [PUBLIC]
987//-----------------------------------------------------------------------------
988
989bool
990IOSCSIParallelInterfaceDevice::SetTargetProperty (
991									const char * 		key,
992									OSObject *			value )
993{
994
995	bool			result			= false;
996	OSDictionary *	protocolDict	= NULL;
997	OSDictionary *	copyDict		= NULL;
998
999	require_nonzero ( key, ErrorExit );
1000	require_nonzero ( value, ErrorExit );
1001
1002	copyDict = OSDynamicCast ( OSDictionary, copyProperty ( kIOPropertyProtocolCharacteristicsKey ) );
1003	require_nonzero ( copyDict, ErrorExit );
1004
1005	protocolDict = ( OSDictionary * ) copyDict->copyCollection ( );
1006	copyDict->release ( );
1007
1008	require_nonzero ( protocolDict, ErrorExit );
1009
1010	if ( strcmp ( key, kIOPropertyFibreChannelPortWorldWideNameKey ) == 0 )
1011	{
1012
1013		OSData * data = OSDynamicCast ( OSData, value );
1014
1015		require_nonzero ( data, ErrorExit );
1016		require ( ( data->getLength ( ) == kWorldWideNameDataSize ), ErrorExit );
1017		result = protocolDict->setObject ( key, value );
1018		result = protocolDict->setObject ( kIOPropertySCSIPortIdentifierKey, value );
1019
1020	}
1021
1022	else if ( strcmp ( key, kIOPropertyFibreChannelNodeWorldWideNameKey ) == 0 )
1023	{
1024
1025		OSData *	data		= OSDynamicCast ( OSData, value );
1026		char		name[27]	= { 0 };
1027
1028		require_nonzero ( data, ErrorExit );
1029		require ( ( data->getLength ( ) == kWorldWideNameDataSize ), ErrorExit );
1030		result = protocolDict->setObject ( key, value );
1031
1032		snprintf ( name, sizeof ( name ), "FC Target %016qX", OSSwapHostToBigInt64 ( *( UInt64 * ) data->getBytesNoCopy ( ) ) );
1033		setName ( name, gIOServicePlane );
1034
1035	}
1036
1037	else if ( strcmp ( key, kIOPropertyFibreChannelAddressIdentifierKey ) == 0 )
1038	{
1039
1040		OSData * data = OSDynamicCast ( OSData, value );
1041
1042		require_nonzero ( data, ErrorExit );
1043		require ( ( data->getLength ( ) == kAddressIdentifierDataSize ), ErrorExit );
1044		result = protocolDict->setObject ( key, value );
1045
1046	}
1047
1048	else if ( strcmp ( key, kIOPropertyFibreChannelALPAKey ) == 0 )
1049	{
1050
1051		OSData * data = OSDynamicCast ( OSData, value );
1052
1053		require_nonzero ( data, ErrorExit );
1054		require ( ( data->getLength ( ) == kALPADataSize ), ErrorExit );
1055		result = protocolDict->setObject ( key, value );
1056
1057	}
1058
1059	else if ( strcmp ( key, kIOPropertySASAddressKey ) == 0 )
1060	{
1061
1062		OSData *	data		= OSDynamicCast ( OSData, value );
1063		char		name[28]	= { 0 };
1064
1065		require_nonzero ( data, ErrorExit );
1066		require ( ( data->getLength ( ) == kSASAddressDataSize ), ErrorExit );
1067		result = protocolDict->setObject ( key, value );
1068		result = protocolDict->setObject ( kIOPropertySCSIPortIdentifierKey, value );
1069
1070		snprintf ( name, sizeof ( name ), "SAS Target %016qX", OSSwapHostToBigInt64 ( *( UInt64 * ) data->getBytesNoCopy ( ) ) );
1071		setName ( name, gIOServicePlane );
1072
1073	}
1074
1075	else if ( strcmp ( key, kIOPropertyRetryCountKey ) == 0 )
1076	{
1077
1078		result = protocolDict->setObject ( key, value );
1079
1080	}
1081
1082	setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
1083	protocolDict->release ( );
1084	protocolDict = NULL;
1085
1086
1087ErrorExit:
1088
1089
1090	return result;
1091
1092}
1093
1094
1095//-----------------------------------------------------------------------------
1096//	RemoveTargetProperty - Removes a property for this object. 		   [PUBLIC]
1097//-----------------------------------------------------------------------------
1098
1099void
1100IOSCSIParallelInterfaceDevice::RemoveTargetProperty ( const char * key )
1101{
1102
1103	OSDictionary *	protocolDict	= NULL;
1104	OSDictionary *	copyDict		= NULL;
1105
1106	require_nonzero ( key, ErrorExit );
1107
1108	copyDict = OSDynamicCast ( OSDictionary, copyProperty ( kIOPropertyProtocolCharacteristicsKey ) );
1109	require_nonzero ( copyDict, ErrorExit );
1110
1111	protocolDict = ( OSDictionary * ) copyDict->copyCollection ( );
1112	copyDict->release ( );
1113
1114	require_nonzero ( protocolDict, ErrorExit );
1115
1116	if ( protocolDict->getObject ( key ) != NULL )
1117	{
1118
1119		protocolDict->removeObject ( key );
1120
1121	}
1122
1123	setProperty ( kIOPropertyProtocolCharacteristicsKey, protocolDict );
1124	protocolDict->release ( );
1125	protocolDict = NULL;
1126
1127
1128ErrorExit:
1129
1130
1131	return;
1132
1133}
1134
1135
1136#if 0
1137#pragma mark -
1138#pragma mark SCSI Protocol Services Member Routines
1139#pragma mark -
1140#endif
1141
1142
1143//-----------------------------------------------------------------------------
1144//	SendSCSICommand - Sends a command to the controller.			   [PUBLIC]
1145//-----------------------------------------------------------------------------
1146
1147bool
1148IOSCSIParallelInterfaceDevice::SendSCSICommand (
1149							SCSITaskIdentifier			request,
1150							SCSIServiceResponse * 		serviceResponse,
1151							SCSITaskStatus *			taskStatus )
1152{
1153
1154	SCSIParallelTaskIdentifier		parallelTask	= NULL;
1155	IOMemoryDescriptor *			buffer			= NULL;
1156	IOReturn						status			= kIOReturnBadArgument;
1157	IOWorkLoop *					workLoop		= NULL;
1158	bool							block			= true;
1159
1160	// Set the defaults to an error state.
1161	*taskStatus			= kSCSITaskStatus_No_Status;
1162	*serviceResponse	= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
1163
1164	if ( isInactive ( ) == true )
1165	{
1166
1167		return false;
1168
1169	}
1170
1171	// Check if there is an SCSIParallelTask available to allow the request
1172	// to be sent to the device. If we don't block on the client thread, we
1173	// risk the chance of never being able to send an I/O to the controller for
1174	// this device.
1175	//
1176	// But, we can't block the ISR either. Depending on what thread we're on,
1177	// we have to make the right decision here.
1178	workLoop = getWorkLoop ( );
1179	if ( workLoop != NULL )
1180	{
1181
1182		if ( workLoop->onThread ( ) )
1183		{
1184			block = false;
1185		}
1186
1187	}
1188
1189	parallelTask = GetSCSIParallelTask ( block );
1190	if ( parallelTask == NULL )
1191	{
1192
1193		// A SCSI Parallel Task could not be obtained, report
1194		// that the task was not executed and wait for a task to complete.
1195		return false;
1196
1197	}
1198
1199	SetTargetIdentifier ( parallelTask, fTargetIdentifier );
1200	SetDevice ( parallelTask, this );
1201
1202	// Do the 2-way association, so that we can reference the SCSITask from
1203	// SCSIParallelTask and vice-versa.
1204	SetSCSITaskIdentifier ( parallelTask, request );
1205	SetProtocolLayerReference ( request, parallelTask );
1206
1207	// Set the Parallel SCSI transfer features.
1208	for ( UInt32 index = 0; index < kSCSIParallelFeature_TotalFeatureCount; index++ )
1209	{
1210
1211		// Set each one to false.
1212		if ( IsFeatureNegotiationNecessary ( ( SCSIParallelFeature ) index ) == true )
1213		{
1214
1215			SetSCSIParallelFeatureNegotiation (
1216								parallelTask,
1217								( SCSIParallelFeature ) index,
1218								kSCSIParallelFeature_AttemptNegotiation );
1219
1220		}
1221
1222	}
1223
1224	// Add the task to the outstanding task list.
1225	AddToOutstandingTaskList ( parallelTask );
1226
1227	// Set the buffer for IODMACommand.
1228	buffer = GetDataBuffer ( parallelTask );
1229	if ( buffer != NULL )
1230	{
1231
1232		status = SetDMABuffer ( parallelTask, buffer );
1233		if ( status != kIOReturnSuccess )
1234		{
1235
1236			ERROR_LOG ( ( "SetDMABuffer failed, status = 0x%08x\n", status ) );
1237
1238			RemoveFromOutstandingTaskList ( parallelTask );
1239
1240			// Release the SCSI Parallel Task object
1241			FreeSCSIParallelTask ( parallelTask );
1242
1243			CommandCompleted ( request, *serviceResponse, *taskStatus );
1244
1245			return true;
1246
1247		}
1248
1249	}
1250
1251	*serviceResponse = ExecuteParallelTask ( parallelTask );
1252	if ( *serviceResponse != kSCSIServiceResponse_Request_In_Process )
1253	{
1254
1255		// The task has already completed
1256		RemoveFromOutstandingTaskList ( parallelTask );
1257
1258		// Release the SCSI Parallel Task object
1259		FreeSCSIParallelTask ( parallelTask );
1260
1261		// Since we are completing the command IOSCSIProtocolServices
1262		// should not process the command any more
1263		*serviceResponse = kSCSIServiceResponse_Request_In_Process;
1264
1265		if ( isInactive ( ) == true )
1266		{
1267
1268			*taskStatus = kSCSITaskStatus_DeviceNotPresent;
1269
1270		}
1271
1272		CommandCompleted ( request, kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE, *taskStatus );
1273
1274	}
1275
1276	return true;
1277
1278}
1279
1280
1281//-----------------------------------------------------------------------------
1282//	CompleteSCSITask - Completes a command from the controller.		   [PUBLIC]
1283//-----------------------------------------------------------------------------
1284
1285void
1286IOSCSIParallelInterfaceDevice::CompleteSCSITask (
1287							SCSIParallelTaskIdentifier 	completedTask,
1288							SCSIServiceResponse 		serviceResponse,
1289							SCSITaskStatus 				completionStatus )
1290{
1291
1292	SCSITaskIdentifier	clientRequest	= NULL;
1293	SCSIParallelTask *	task			= ( SCSIParallelTask * ) completedTask;
1294	UInt8				retryCount		= task->fTaskRetryCount;
1295
1296	if ( completedTask == NULL )
1297	{
1298
1299		// The driver was asked to complete an invalid task,
1300		// there is nothing it can do so just return.
1301		return;
1302
1303	}
1304
1305	// Check if the device rejected the task because its queue is full.
1306	if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
1307		 ( completionStatus == kSCSITaskStatus_TASK_SET_FULL ) &&
1308		 ( fAllowResends == true ) &&
1309		 ( retryCount < kMaxTaskRetryCount ) )
1310	{
1311
1312		// The task was not executed because the device reported
1313		// a TASK_SET_FULL, place it on the resend queue and wait for
1314		// a task to complete with a status other than TASK_SET_FULL.
1315		AddToResendTaskList ( completedTask );
1316
1317		// Done for now.
1318		return;
1319
1320	}
1321
1322	// Make sure that the task is removed from the outstanding task list
1323	// so that the driver no longer sees this task as outstanding.
1324	RemoveFromOutstandingTaskList ( completedTask );
1325
1326	// Retrieve the original SCSI Task.
1327	clientRequest = GetSCSITaskIdentifier ( completedTask );
1328	if ( clientRequest == NULL )
1329	{
1330		panic ( "IOSCSIParallelInterfaceDevice::CompleteSCSITask: clientRequest is NULL, completedTask = %p\n", completedTask );
1331	}
1332
1333	// Set the appropriate fields in the SCSI Task.
1334	IOSCSIProtocolServices::SetRealizedDataTransferCount ( clientRequest, GetRealizedDataTransferCount ( completedTask ) );
1335
1336	// Store any negotiations that were done.
1337	for ( UInt32 index = 0; index < kSCSIParallelFeature_TotalFeatureCount; index++ )
1338	{
1339
1340		// Set each one to false.
1341		if ( IsFeatureNegotiationNecessary ( ( SCSIParallelFeature ) index ) == true )
1342		{
1343
1344			if ( GetSCSIParallelFeatureNegotiationResult ( completedTask, ( SCSIParallelFeature ) index ) ==
1345				kSCSIParallelFeature_NegotitiationSuccess )
1346			{
1347				fFeatureIsNegotiated[index] = true;
1348			}
1349
1350		}
1351
1352	}
1353
1354	// Release the SCSI Parallel Task object.
1355	FreeSCSIParallelTask ( completedTask );
1356
1357	IOSimpleLockLock ( fQueueLock );
1358
1359	// If there are requests on the resend queue, send them first.
1360	// Currently only the element at the head of the queue will be sent.
1361	// If the desire is to allow all elements to be sent, the break
1362	// statement can be removed.
1363	while ( !queue_empty ( &fResendTaskList ) )
1364	{
1365
1366		SCSIParallelTaskIdentifier 	parallelTask;
1367		SCSIParallelTask *		task = NULL;
1368
1369		parallelTask = ( SCSIParallelTaskIdentifier ) queue_first ( &fResendTaskList );
1370
1371		task = ( SCSIParallelTask * ) parallelTask ;
1372
1373		queue_remove ( &fResendTaskList, task, SCSIParallelTask *, fResendTaskChain );
1374
1375		IOSimpleLockUnlock ( fQueueLock );
1376
1377
1378		if ( ExecuteParallelTask ( parallelTask ) != kSCSIServiceResponse_Request_In_Process )
1379		{
1380
1381			SCSITaskIdentifier		nextRequest	= NULL;
1382
1383			// The task has already completed
1384			RemoveFromOutstandingTaskList ( parallelTask );
1385
1386			nextRequest = GetSCSITaskIdentifier ( parallelTask );
1387
1388			// Release the SCSI Parallel Task object
1389			FreeSCSIParallelTask ( parallelTask );
1390
1391			CommandCompleted ( nextRequest, kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE, kSCSITaskStatus_No_Status );
1392
1393
1394			IOSimpleLockLock ( fQueueLock );
1395
1396			// Since this command has already completed, start the next
1397			// one on the queue.
1398			continue;
1399
1400		}
1401
1402		else
1403		{
1404
1405			IOSimpleLockLock ( fQueueLock );
1406
1407			// A command was successfully sent, wait for it to complete
1408			// before sending the next one.
1409			break;
1410
1411		}
1412
1413	}
1414
1415	IOSimpleLockUnlock ( fQueueLock );
1416
1417	// If the IO completed with TASK_SET_FULL but has exhausted its max retries,
1418	// complete it with taskStatus BUSY. The upper layer will retry it again.
1419	if ( ( serviceResponse == kSCSIServiceResponse_TASK_COMPLETE ) &&
1420		 ( completionStatus == kSCSITaskStatus_TASK_SET_FULL ) &&
1421		 ( retryCount >= kMaxTaskRetryCount ) )
1422	{
1423
1424		CommandCompleted ( clientRequest, kSCSIServiceResponse_TASK_COMPLETE, kSCSITaskStatus_BUSY );
1425
1426	}
1427
1428	else
1429	{
1430
1431		// Inform the client that the task has been executed.
1432		CommandCompleted ( clientRequest, serviceResponse, completionStatus );
1433
1434	}
1435
1436}
1437
1438
1439#if 0
1440#pragma mark -
1441#pragma mark SCSI Protocol Service Feature routines
1442#pragma mark -
1443#endif
1444
1445
1446//-----------------------------------------------------------------------------
1447//	IsProtocolServiceSupported - 	Called by SCSI Application Layer to determine
1448//									if the protocol layer driver supports a
1449//									SCSIProtocolFeature.	   		   [PUBLIC]
1450//-----------------------------------------------------------------------------
1451
1452bool
1453IOSCSIParallelInterfaceDevice::IsProtocolServiceSupported (
1454							SCSIProtocolFeature 		feature,
1455							void * 						value )
1456{
1457
1458	bool	isSupported = false;
1459
1460	require ( ( isInactive ( ) == false ), ErrorExit );
1461	require_nonzero ( fController, ErrorExit );
1462
1463	switch ( feature )
1464	{
1465
1466		case kSCSIProtocolFeature_GetMaximumLogicalUnitNumber:
1467		{
1468
1469			isSupported = true;
1470			*( UInt32 * ) value = fController->ReportHBAHighestLogicalUnitNumber ( );
1471
1472		}
1473		break;
1474
1475		case kSCSIProtocolFeature_SubmitDefaultInquiryData:
1476		{
1477			isSupported = true;
1478		}
1479		break;
1480
1481		case kSCSIProtocolFeature_ProtocolAlwaysReportsAutosenseData:
1482		{
1483			isSupported = fController->DoesHBAPerformAutoSense ( );
1484		}
1485		break;
1486
1487		case kSCSIProtocolFeature_HierarchicalLogicalUnits:
1488		{
1489
1490			OSBoolean *     obj = NULL;
1491
1492			obj = OSDynamicCast ( OSBoolean, fController->getProperty ( kIOHierarchicalLogicalUnitSupportKey ) );
1493
1494			if ( ( obj != NULL ) && ( obj->isTrue ( ) ) )
1495			{
1496				isSupported = true;
1497			}
1498
1499		}
1500		break;
1501
1502		case kSCSIProtocolFeature_MultiPathing:
1503		{
1504			isSupported = fMultiPathSupport;
1505		}
1506		break;
1507
1508		default:
1509		{
1510			// Since isSupported is set to false by default, there is
1511			// nothing that needs to be done for the default case.
1512		}
1513		break;
1514
1515	}
1516
1517
1518ErrorExit:
1519
1520
1521	return isSupported;
1522
1523}
1524
1525
1526//-----------------------------------------------------------------------------
1527//	HandleProtocolServiceFeature - Called by SCSI Application Layer to handle
1528//									 a SCSIProtocolFeature.	   		   [PUBLIC]
1529//-----------------------------------------------------------------------------
1530bool
1531IOSCSIParallelInterfaceDevice::HandleProtocolServiceFeature (
1532							SCSIProtocolFeature 		feature,
1533							void * 						serviceValue )
1534{
1535
1536	bool	wasHandled = false;
1537
1538	switch ( feature )
1539	{
1540
1541		case kSCSIProtocolFeature_SubmitDefaultInquiryData:
1542		{
1543
1544			DetermineParallelFeatures ( ( UInt8 * ) serviceValue );
1545			wasHandled = true;
1546
1547			// Put us in the IORegistry so we can be found by utilities like
1548			// System Profiler easily.
1549			registerService ( );
1550
1551		}
1552		break;
1553
1554		default:
1555		{
1556			break;
1557		}
1558
1559	}
1560
1561	return wasHandled;
1562
1563}
1564
1565
1566#if 0
1567#pragma mark -
1568#pragma mark SCSI Task Management Functions
1569#pragma mark -
1570#endif
1571
1572
1573//-----------------------------------------------------------------------------
1574//	AbortSCSICommand - Not used.	   		   			     [OBSOLETE][PUBLIC]
1575//-----------------------------------------------------------------------------
1576
1577SCSIServiceResponse
1578IOSCSIParallelInterfaceDevice::AbortSCSICommand (
1579							SCSITaskIdentifier 			request )
1580{
1581	return kSCSIServiceResponse_FUNCTION_REJECTED;
1582}
1583
1584
1585//-----------------------------------------------------------------------------
1586//	HandleAbortTask - Calls controller to perform abort task.		[PROTECTED]
1587//-----------------------------------------------------------------------------
1588
1589SCSIServiceResponse
1590IOSCSIParallelInterfaceDevice::HandleAbortTask (
1591							UInt8 						theLogicalUnit,
1592							SCSITaggedTaskIdentifier 	theTag )
1593{
1594	return fController->AbortTaskRequest ( fTargetIdentifier, theLogicalUnit, theTag );
1595}
1596
1597
1598//-----------------------------------------------------------------------------
1599//	HandleAbortTaskSet - Calls controller to perform abort task set.
1600//																	[PROTECTED]
1601//-----------------------------------------------------------------------------
1602
1603SCSIServiceResponse
1604IOSCSIParallelInterfaceDevice::HandleAbortTaskSet (
1605							UInt8 						theLogicalUnit )
1606{
1607	return fController->AbortTaskSetRequest ( fTargetIdentifier, theLogicalUnit );
1608}
1609
1610
1611//-----------------------------------------------------------------------------
1612//	HandleClearACA - Calls controller to perform Clear ACA.			[PROTECTED]
1613//-----------------------------------------------------------------------------
1614
1615SCSIServiceResponse
1616IOSCSIParallelInterfaceDevice::HandleClearACA (
1617							UInt8						theLogicalUnit )
1618{
1619	return fController->ClearACARequest ( fTargetIdentifier, theLogicalUnit );
1620}
1621
1622
1623//-----------------------------------------------------------------------------
1624//	HandleClearTaskSet - Calls controller to perform clear task set.
1625//																	[PROTECTED]
1626//-----------------------------------------------------------------------------
1627
1628SCSIServiceResponse
1629IOSCSIParallelInterfaceDevice::HandleClearTaskSet (
1630							UInt8						theLogicalUnit )
1631{
1632	return fController->ClearTaskSetRequest ( fTargetIdentifier, theLogicalUnit );
1633}
1634
1635
1636//-----------------------------------------------------------------------------
1637//	HandleLogicalUnitReset - Calls controller to perform LUN reset.	[PROTECTED]
1638//-----------------------------------------------------------------------------
1639
1640SCSIServiceResponse
1641IOSCSIParallelInterfaceDevice::HandleLogicalUnitReset (
1642							UInt8 						theLogicalUnit )
1643{
1644	return fController->LogicalUnitResetRequest ( fTargetIdentifier, theLogicalUnit );
1645}
1646
1647
1648//-----------------------------------------------------------------------------
1649//	HandleTargetReset - Calls controller to perform Target reset.	[PROTECTED]
1650//-----------------------------------------------------------------------------
1651
1652SCSIServiceResponse
1653IOSCSIParallelInterfaceDevice::HandleTargetReset ( void )
1654{
1655	return fController->TargetResetRequest ( fTargetIdentifier );
1656}
1657
1658
1659#if 0
1660#pragma mark -
1661#pragma mark Controller Object Accessors
1662#pragma mark -
1663#endif
1664
1665
1666//-----------------------------------------------------------------------------
1667//	ExecuteParallelTask - Called to issue a task to the controller.	[PROTECTED]
1668//-----------------------------------------------------------------------------
1669
1670SCSIServiceResponse
1671IOSCSIParallelInterfaceDevice::ExecuteParallelTask (
1672							SCSIParallelTaskIdentifier	parallelRequest )
1673{
1674	return fController->ExecuteParallelTask ( parallelRequest );
1675}
1676
1677
1678//-----------------------------------------------------------------------------
1679//	GetSCSIParallelTask - Gets a SCSIParallelTaskIdentifier from the
1680//							controller's command pool.				[PROTECTED]
1681//-----------------------------------------------------------------------------
1682
1683SCSIParallelTaskIdentifier
1684IOSCSIParallelInterfaceDevice::GetSCSIParallelTask ( bool blockForCommand )
1685{
1686	return fController->GetSCSIParallelTask ( blockForCommand );
1687}
1688
1689
1690//-----------------------------------------------------------------------------
1691//	FreeSCSIParallelTask - Returns a SCSIParallelTaskIdentifier to the
1692//							 controller's command pool.				[PROTECTED]
1693//-----------------------------------------------------------------------------
1694
1695void
1696IOSCSIParallelInterfaceDevice::FreeSCSIParallelTask (
1697							SCSIParallelTaskIdentifier	returnTask )
1698{
1699	return fController->FreeSCSIParallelTask ( returnTask );
1700}
1701
1702
1703//-----------------------------------------------------------------------------
1704//	DoesHBASupportSCSIParallelFeature - 	Queries the controller if a
1705//											specific SCSIParallelFeature is
1706//											supported.				[PROTECTED]
1707//-----------------------------------------------------------------------------
1708
1709bool
1710IOSCSIParallelInterfaceDevice::DoesHBASupportSCSIParallelFeature (
1711							SCSIParallelFeature			theFeature )
1712{
1713	return fController->DoesHBASupportSCSIParallelFeature ( theFeature );
1714}
1715
1716
1717#if 0
1718#pragma mark -
1719#pragma mark SCSI Parallel Task Object Accessors
1720#pragma mark -
1721#endif
1722
1723
1724//-----------------------------------------------------------------------------
1725//	AddToOutstandingTaskList - Adds a task to the outstanding task list.
1726//																	[PROTECTED]
1727//-----------------------------------------------------------------------------
1728
1729bool
1730IOSCSIParallelInterfaceDevice::AddToOutstandingTaskList (
1731							SCSIParallelTaskIdentifier	parallelTask )
1732{
1733
1734	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
1735
1736	if ( task == NULL )
1737	{
1738		return false;
1739	}
1740
1741	IOSimpleLockLock ( fQueueLock );
1742
1743	queue_enter ( &fOutstandingTaskList, task, SCSIParallelTask *, fCommandChain );
1744
1745	IOSimpleLockUnlock ( fQueueLock );
1746
1747	return true;
1748
1749}
1750
1751
1752//-----------------------------------------------------------------------------
1753//	RemoveFromOutstandingTaskList - 	Removes a task from the outstanding
1754//										task list.					[PROTECTED]
1755//-----------------------------------------------------------------------------
1756
1757void
1758IOSCSIParallelInterfaceDevice::RemoveFromOutstandingTaskList (
1759							SCSIParallelTaskIdentifier 	parallelTask )
1760{
1761
1762	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
1763
1764	require_nonzero ( ( task->fCommandChain.next ), Exit );
1765	require_nonzero ( ( task->fCommandChain.prev ), Exit );
1766
1767	IOSimpleLockLock ( fQueueLock );
1768
1769	require ( ( queue_empty ( &fOutstandingTaskList ) == false ), ExitLocked );
1770
1771	queue_remove ( &fOutstandingTaskList, task, SCSIParallelTask *, fCommandChain );
1772
1773
1774ExitLocked:
1775
1776
1777	IOSimpleLockUnlock ( fQueueLock );
1778
1779
1780Exit:
1781
1782
1783	return;
1784
1785}
1786
1787
1788//-----------------------------------------------------------------------------
1789//	AddToResendTaskList - Adds a task to the resend (TASK_SET_FULL) task list.
1790//																	[PROTECTED]
1791//-----------------------------------------------------------------------------
1792
1793bool
1794IOSCSIParallelInterfaceDevice::AddToResendTaskList (
1795							SCSIParallelTaskIdentifier	parallelTask )
1796{
1797
1798	SCSIParallelTask *	task	= ( SCSIParallelTask * ) parallelTask;
1799	thread_t			thread	= THREAD_NULL;
1800
1801	if ( task == NULL )
1802	{
1803		return false;
1804	}
1805
1806	IOSimpleLockLock ( fQueueLock );
1807
1808	task->fTaskRetryCount++;
1809
1810	queue_enter ( &fResendTaskList, task, SCSIParallelTask *, fResendTaskChain );
1811
1812	// Some targets return TASK SET FULL even if they have no other pending
1813	// IOs from the I-T nexus. In this case we don't want that IO to sit
1814	// in a limbo on the fResendTaskList. So we start a thread that will drive
1815	// the list.
1816	if ( fResendThreadScheduled == false )
1817	{
1818
1819		fResendThreadScheduled = true;
1820
1821		IOSimpleLockUnlock ( fQueueLock );
1822
1823		retain ( );
1824
1825		kernel_thread_start (
1826			OSMemberFunctionCast (
1827				thread_continue_t,
1828				this,
1829				&IOSCSIParallelInterfaceDevice::SendFromResendTaskList ),
1830			this,
1831			&thread );
1832
1833	}
1834
1835	else
1836	{
1837		IOSimpleLockUnlock ( fQueueLock );
1838	}
1839
1840	return true;
1841
1842}
1843
1844
1845//-----------------------------------------------------------------------------
1846//	SendFromResendTaskList - Drives the Resend Task List.
1847//																	[PROTECTED]
1848//-----------------------------------------------------------------------------
1849
1850void
1851IOSCSIParallelInterfaceDevice::SendFromResendTaskList ( void )
1852{
1853
1854	thread_t					thread			= THREAD_NULL;
1855	SCSIParallelTaskIdentifier 	parallelTask	= NULL;
1856	SCSIParallelTask *			task			= NULL;
1857
1858	// Sleep for 10 seconds before driving the queue
1859	// only if we are not terminating.
1860	if ( fAllowResends == true )
1861	{
1862
1863		// Wait 10 seconds before driving the list.
1864		IOSleep ( 10000 );
1865
1866	}
1867
1868
1869	IOSimpleLockLock ( fQueueLock );
1870
1871	// If there are requests on the resend queue, send them first.
1872	// Currently only the element at the head of the queue will be sent.
1873	// If the desire is to allow all elements to be sent, the break
1874	// statement can be removed.
1875
1876	while ( !queue_empty ( &fResendTaskList ) )
1877	{
1878
1879		parallelTask = ( SCSIParallelTaskIdentifier ) queue_first ( &fResendTaskList );
1880
1881		task = ( SCSIParallelTask * ) parallelTask;
1882
1883		queue_remove ( &fResendTaskList, task, SCSIParallelTask *, fResendTaskChain );
1884
1885		IOSimpleLockUnlock ( fQueueLock );
1886
1887		// If Device is not destroyed, send command to device, else
1888		// complete the command with error.
1889		if ( fAllowResends == true )
1890		{
1891
1892			if ( ExecuteParallelTask ( parallelTask ) == kSCSIServiceResponse_Request_In_Process )
1893			{
1894
1895				IOSimpleLockLock ( fQueueLock );
1896
1897				// A command was successfully sent.
1898				// The next IO in the Resend task list will be driven when
1899				// this completes.
1900				break;
1901
1902			}
1903
1904		}
1905
1906		SCSITaskIdentifier		nextRequest	= NULL;
1907
1908		// The task has already completed
1909		RemoveFromOutstandingTaskList ( parallelTask );
1910
1911		nextRequest = GetSCSITaskIdentifier ( parallelTask );
1912
1913		// Release the SCSI Parallel Task object
1914		FreeSCSIParallelTask ( parallelTask );
1915
1916		// Return taskStatus BUSY so that upper layer will retry the IO.
1917		CommandCompleted ( nextRequest, kSCSIServiceResponse_TASK_COMPLETE, kSCSITaskStatus_BUSY );
1918
1919		IOSimpleLockLock ( fQueueLock );
1920
1921		// Since this command has already completed, start the next
1922		// one on the queue.
1923		continue;
1924
1925	}
1926
1927	fResendThreadScheduled = false;
1928
1929	IOSimpleLockUnlock ( fQueueLock );
1930
1931	// Release our retain held while starting thread.
1932	release ( );
1933
1934	// Terminate the thread.
1935	thread = current_thread ( );
1936	thread_deallocate ( thread );
1937	thread_terminate ( thread );
1938
1939}
1940
1941
1942//-----------------------------------------------------------------------------
1943//	RemoveFromOutstandingTaskList - 	Removes a task from the resend task
1944//										(TASK_SET_FULL) list.		[PROTECTED]
1945//-----------------------------------------------------------------------------
1946
1947void
1948IOSCSIParallelInterfaceDevice::RemoveFromResendTaskList (
1949							SCSIParallelTaskIdentifier 	parallelTask )
1950{
1951
1952	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
1953
1954	require_nonzero ( ( task->fResendTaskChain.next ), Exit );
1955	require_nonzero ( ( task->fResendTaskChain.prev ), Exit );
1956
1957	IOSimpleLockLock ( fQueueLock );
1958
1959	require ( ( queue_empty ( &fResendTaskList ) == false ), ExitLocked );
1960
1961	queue_remove ( &fResendTaskList, task, SCSIParallelTask *, fResendTaskChain );
1962
1963
1964ExitLocked:
1965
1966
1967	IOSimpleLockUnlock ( fQueueLock );
1968
1969
1970Exit:
1971
1972
1973	return;
1974
1975}
1976
1977
1978//-----------------------------------------------------------------------------
1979//	SetSCSITaskIdentifier - 	Sets the SCSITaskIdentifier in the
1980//								parallelTask.						[PROTECTED]
1981//-----------------------------------------------------------------------------
1982
1983bool
1984IOSCSIParallelInterfaceDevice::SetSCSITaskIdentifier (
1985							SCSIParallelTaskIdentifier 	parallelTask,
1986							SCSITaskIdentifier 			scsiRequest )
1987{
1988
1989	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
1990
1991	if ( task == NULL )
1992	{
1993		return false;
1994	}
1995
1996	return task->SetSCSITaskIdentifier ( scsiRequest );
1997
1998}
1999
2000
2001//-----------------------------------------------------------------------------
2002//	GetSCSITaskIdentifier - 	Retrieves the SCSITaskIdentifier from the
2003//								parallelTask.						[PROTECTED]
2004//-----------------------------------------------------------------------------
2005
2006SCSITaskIdentifier
2007IOSCSIParallelInterfaceDevice::GetSCSITaskIdentifier (
2008							SCSIParallelTaskIdentifier 	parallelTask )
2009{
2010
2011	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2012
2013	if ( task == NULL )
2014	{
2015		return NULL;
2016	}
2017
2018	return task->GetSCSITaskIdentifier ( );
2019
2020}
2021
2022
2023//-----------------------------------------------------------------------------
2024//	SetDevice - Sets the device in the parallelTask.				[PROTECTED]
2025//-----------------------------------------------------------------------------
2026
2027bool
2028IOSCSIParallelInterfaceDevice::SetDevice (
2029							SCSIParallelTaskIdentifier			parallelTask,
2030							IOSCSIParallelInterfaceDevice * 	device )
2031{
2032
2033	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2034
2035	if ( task == NULL )
2036	{
2037		return false;
2038	}
2039
2040	return task->SetDevice ( device );
2041
2042}
2043
2044
2045//-----------------------------------------------------------------------------
2046//	SetTargetIdentifier - 	Sets the SCSITargetIdentifier in the
2047//								parallelTask.						[PROTECTED]
2048//-----------------------------------------------------------------------------
2049
2050bool
2051IOSCSIParallelInterfaceDevice::SetTargetIdentifier (
2052							SCSIParallelTaskIdentifier 	parallelTask,
2053							SCSITargetIdentifier 		theTargetID )
2054{
2055
2056	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2057
2058	if ( task == NULL )
2059	{
2060		return false;
2061	}
2062
2063	return task->SetTargetIdentifier ( theTargetID );
2064
2065}
2066
2067
2068//-----------------------------------------------------------------------------
2069//	GetTargetIdentifier - 	Retrieves the SCSITargetIdentifier from the
2070//								parallelTask.						[PROTECTED]
2071//-----------------------------------------------------------------------------
2072
2073SCSITargetIdentifier
2074IOSCSIParallelInterfaceDevice::GetTargetIdentifier (
2075							SCSIParallelTaskIdentifier 	parallelTask )
2076{
2077
2078	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2079
2080	if ( task == NULL )
2081	{
2082		return NULL;
2083	}
2084
2085	return task->GetTargetIdentifier ( );
2086
2087}
2088
2089
2090//-----------------------------------------------------------------------------
2091//	SetDMABuffer - Sets the DMA buffer in the task.					[PROTECTED]
2092//-----------------------------------------------------------------------------
2093
2094IOReturn
2095IOSCSIParallelInterfaceDevice::SetDMABuffer (
2096							SCSIParallelTaskIdentifier 	parallelTask,
2097							IOMemoryDescriptor *		buffer )
2098{
2099
2100	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2101
2102	if ( task == NULL )
2103	{
2104		return NULL;
2105	}
2106
2107	return task->SetBuffer ( buffer );
2108
2109}
2110
2111
2112// ---- Methods for Accessing data in the client's SCSI Task Object ----
2113// Method to retrieve the LUN that identifies the Logical Unit whose Task
2114// Set to which this task is to be added.
2115// --> Currently this only supports Level 1 Addressing, complete
2116// Hierachal LUN addressing will need to be added to the SCSI Task object
2117// and the Peripheral Device Type objects which will represent Logical Units.
2118// Since that will be completed before this is released, this method will be
2119// changed at that time.
2120
2121//-----------------------------------------------------------------------------
2122//	GetLogicalUnitNumber - 	Retrieves the SCSILogicalUnitNumber from the
2123//							parallelTask.							[PROTECTED]
2124//-----------------------------------------------------------------------------
2125
2126SCSILogicalUnitNumber
2127IOSCSIParallelInterfaceDevice::GetLogicalUnitNumber (
2128							SCSIParallelTaskIdentifier 	parallelTask )
2129{
2130
2131	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2132
2133	if ( task == NULL )
2134	{
2135		return 0;
2136	}
2137
2138	return task->GetLogicalUnitNumber ( );
2139
2140}
2141
2142
2143//-----------------------------------------------------------------------------
2144//	GetTaggedTaskIdentifier - 	Retrieves the SCSITaggedTaskIdentifier from the
2145//								parallelTask.						[PROTECTED]
2146//-----------------------------------------------------------------------------
2147
2148SCSITaggedTaskIdentifier
2149IOSCSIParallelInterfaceDevice::GetTaggedTaskIdentifier (
2150							SCSIParallelTaskIdentifier		parallelTask )
2151{
2152
2153	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2154
2155	if ( task == NULL )
2156	{
2157		return kSCSIUntaggedTaskIdentifier;
2158	}
2159
2160	return task->GetTaggedTaskIdentifier ( );
2161
2162}
2163
2164
2165//-----------------------------------------------------------------------------
2166//	GetTaskAttribute - 	Retrieves the SCSITaskAttribute from the parallelTask.
2167//																	[PROTECTED]
2168//-----------------------------------------------------------------------------
2169
2170SCSITaskAttribute
2171IOSCSIParallelInterfaceDevice::GetTaskAttribute (
2172							SCSIParallelTaskIdentifier 		parallelTask )
2173{
2174
2175	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2176
2177	if ( task == NULL )
2178	{
2179		return kSCSITask_SIMPLE;
2180	}
2181
2182	return task->GetTaskAttribute ( );
2183
2184}
2185
2186
2187//-----------------------------------------------------------------------------
2188//	GetCommandDescriptorBlockSize - 	Retrieves the CDB size from the
2189//										parallelTask.				[PROTECTED]
2190//-----------------------------------------------------------------------------
2191
2192UInt8
2193IOSCSIParallelInterfaceDevice::GetCommandDescriptorBlockSize (
2194							SCSIParallelTaskIdentifier 	parallelTask )
2195{
2196
2197	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2198
2199	if ( task == NULL )
2200	{
2201		return 0;
2202	}
2203
2204	return task->GetCommandDescriptorBlockSize ( );
2205
2206}
2207
2208
2209//-----------------------------------------------------------------------------
2210//	GetCommandDescriptorBlockSize - 	Retrieves the CDB from the parallelTask.
2211//																	[PROTECTED]
2212//-----------------------------------------------------------------------------
2213
2214bool
2215IOSCSIParallelInterfaceDevice::GetCommandDescriptorBlock (
2216							SCSIParallelTaskIdentifier 		parallelTask,
2217							SCSICommandDescriptorBlock *	cdbData )
2218{
2219
2220	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2221
2222	if ( task == NULL )
2223	{
2224		return false;
2225	}
2226
2227	return task->GetCommandDescriptorBlock ( cdbData );
2228
2229}
2230
2231
2232//-----------------------------------------------------------------------------
2233//	GetDataTransferDirection - 	Retrieves the data transfer direction from
2234//								the parallelTask.					[PROTECTED]
2235//-----------------------------------------------------------------------------
2236
2237UInt8
2238IOSCSIParallelInterfaceDevice::GetDataTransferDirection (
2239							SCSIParallelTaskIdentifier 	parallelTask )
2240{
2241
2242	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2243
2244	if ( task == NULL )
2245	{
2246		return kSCSIDataTransfer_NoDataTransfer;
2247	}
2248
2249	return task->GetDataTransferDirection ( );
2250
2251}
2252
2253
2254//-----------------------------------------------------------------------------
2255//	GetRequestedDataTransferCount -	Retrieves the requested data transfer
2256//									count from the parallelTask.	[PROTECTED]
2257//-----------------------------------------------------------------------------
2258
2259UInt64
2260IOSCSIParallelInterfaceDevice::GetRequestedDataTransferCount (
2261							SCSIParallelTaskIdentifier 	parallelTask )
2262{
2263
2264	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2265
2266	if ( task == NULL )
2267	{
2268		return 0;
2269	}
2270
2271	return task->GetRequestedDataTransferCount ( );
2272
2273}
2274
2275
2276//-----------------------------------------------------------------------------
2277//	GetRequestedDataTransferCount - Retrieves the realized data transfer
2278//									count from the parallelTask.	[PROTECTED]
2279//-----------------------------------------------------------------------------
2280
2281UInt64
2282IOSCSIParallelInterfaceDevice::GetRealizedDataTransferCount (
2283							SCSIParallelTaskIdentifier 		parallelTask )
2284{
2285
2286	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2287
2288	if ( task == NULL )
2289	{
2290		return 0;
2291	}
2292
2293	return task->GetRealizedDataTransferCount ( );
2294
2295}
2296
2297
2298//-----------------------------------------------------------------------------
2299//	GetRequestedDataTransferCount - Sets the realized data transfer
2300//									count in the parallelTask.		[PROTECTED]
2301//-----------------------------------------------------------------------------
2302
2303bool
2304IOSCSIParallelInterfaceDevice::SetRealizedDataTransferCount (
2305							SCSIParallelTaskIdentifier 	parallelTask,
2306							UInt64 						realizedTransferCountInBytes )
2307{
2308
2309	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2310
2311	if ( task == NULL )
2312	{
2313		return false;
2314	}
2315
2316	return task->SetRealizedDataTransferCount ( realizedTransferCountInBytes );
2317
2318}
2319
2320
2321//-----------------------------------------------------------------------------
2322//	GetRequestedDataTransferCount - Increments the realized data transfer
2323//									  count in the parallelTask.	[PROTECTED]
2324//-----------------------------------------------------------------------------
2325
2326void
2327IOSCSIParallelInterfaceDevice::IncrementRealizedDataTransferCount (
2328							SCSIParallelTaskIdentifier 	parallelTask,
2329							UInt64 						realizedTransferCountInBytes )
2330{
2331
2332	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2333
2334	if ( task == NULL )
2335	{
2336		return;
2337	}
2338
2339	return task->IncrementRealizedDataTransferCount ( realizedTransferCountInBytes );
2340
2341}
2342
2343
2344//-----------------------------------------------------------------------------
2345//	GetRequestedDataTransferCount - Retrieves the data buffer in the
2346//									  parallelTask.					[PROTECTED]
2347//-----------------------------------------------------------------------------
2348
2349IOMemoryDescriptor *
2350IOSCSIParallelInterfaceDevice::GetDataBuffer (
2351							SCSIParallelTaskIdentifier 	parallelTask )
2352{
2353
2354	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2355
2356	if ( task == NULL )
2357	{
2358		return NULL;
2359	}
2360
2361	return task->GetDataBuffer ( );
2362
2363}
2364
2365
2366//-----------------------------------------------------------------------------
2367//	GetDataBufferOffset - Retrieves the data buffer offset in the parallelTask.
2368//																	[PROTECTED]
2369//-----------------------------------------------------------------------------
2370
2371UInt64
2372IOSCSIParallelInterfaceDevice::GetDataBufferOffset (
2373							SCSIParallelTaskIdentifier 	parallelTask )
2374{
2375
2376	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2377
2378	if ( task == NULL )
2379	{
2380		return 0;
2381	}
2382
2383	return task->GetDataBufferOffset ( );
2384
2385}
2386
2387
2388//-----------------------------------------------------------------------------
2389//	GetTimeoutDuration - Retrieves the timeout duration in the parallelTask.
2390//																	[PROTECTED]
2391//-----------------------------------------------------------------------------
2392
2393UInt32
2394IOSCSIParallelInterfaceDevice::GetTimeoutDuration (
2395							SCSIParallelTaskIdentifier 	parallelTask )
2396{
2397
2398	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2399
2400	if ( task == NULL )
2401	{
2402		return 0;
2403	}
2404
2405	return task->GetTimeoutDuration ( );
2406
2407}
2408
2409//-----------------------------------------------------------------------------
2410//	SetSCSIParallelFeatureNegotiation - 	Sets a feature negotiation request
2411//											in the specified task.
2412//																	[PROTECTED]
2413//-----------------------------------------------------------------------------
2414
2415void
2416IOSCSIParallelInterfaceDevice::SetSCSIParallelFeatureNegotiation (
2417							SCSIParallelTaskIdentifier 		parallelTask,
2418							SCSIParallelFeature 			requestedFeature,
2419							SCSIParallelFeatureRequest 		newRequest )
2420{
2421
2422	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2423
2424	if ( task == NULL )
2425	{
2426		return;
2427	}
2428
2429	return task->SetSCSIParallelFeatureNegotiation ( requestedFeature, newRequest );
2430
2431}
2432
2433
2434//-----------------------------------------------------------------------------
2435//	GetSCSIParallelFeatureNegotiation - 	Gets a feature negotiation request
2436//											in the specified task.
2437//																	[PROTECTED]
2438//-----------------------------------------------------------------------------
2439
2440SCSIParallelFeatureRequest
2441IOSCSIParallelInterfaceDevice::GetSCSIParallelFeatureNegotiation (
2442							SCSIParallelTaskIdentifier 		parallelTask,
2443							SCSIParallelFeature 			requestedFeature )
2444{
2445
2446	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2447
2448	if ( task == NULL )
2449	{
2450		return kSCSIParallelFeature_NoNegotiation;
2451	}
2452
2453	return task->GetSCSIParallelFeatureNegotiation ( requestedFeature );
2454
2455}
2456
2457
2458//-----------------------------------------------------------------------------
2459//	GetSCSIParallelFeatureNegotiationResult - 	Gets a feature negotiation
2460//												result in the specified task.
2461//																	[PROTECTED]
2462//-----------------------------------------------------------------------------
2463
2464SCSIParallelFeatureResult
2465IOSCSIParallelInterfaceDevice::GetSCSIParallelFeatureNegotiationResult (
2466							SCSIParallelTaskIdentifier 		parallelTask,
2467							SCSIParallelFeature 			requestedFeature )
2468{
2469
2470	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2471
2472	if ( task == NULL )
2473	{
2474		return kSCSIParallelFeature_NegotitiationUnchanged;
2475	}
2476
2477	return task->GetSCSIParallelFeatureNegotiationResult ( requestedFeature );
2478
2479}
2480
2481
2482//-----------------------------------------------------------------------------
2483//	GetControllerTaskIdentifier - Gets the identifier associated with the
2484//								  task.							[PROTECTED]
2485//-----------------------------------------------------------------------------
2486
2487UInt64
2488IOSCSIParallelInterfaceDevice::GetControllerTaskIdentifier (
2489							SCSIParallelTaskIdentifier 		parallelTask )
2490{
2491
2492	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2493
2494	if ( task == NULL )
2495	{
2496		return 0;
2497	}
2498
2499	return task->GetControllerTaskIdentifier ( );
2500
2501}
2502
2503
2504//-----------------------------------------------------------------------------
2505//	GetHBADataSize - Gets the size of HBA Data associated with a command.
2506//																	[PROTECTED]
2507//-----------------------------------------------------------------------------
2508
2509UInt32
2510IOSCSIParallelInterfaceDevice::GetHBADataSize (
2511							SCSIParallelTaskIdentifier 	parallelTask )
2512{
2513
2514	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2515
2516	if ( task == NULL )
2517	{
2518		return 0;
2519	}
2520
2521	return task->GetHBADataSize ( );
2522
2523}
2524
2525
2526//-----------------------------------------------------------------------------
2527//	GetHBADataPointer - Gets the HBA Data pointer associated with a command.
2528//																	[PROTECTED]
2529//-----------------------------------------------------------------------------
2530
2531void *
2532IOSCSIParallelInterfaceDevice::GetHBADataPointer (
2533							SCSIParallelTaskIdentifier 	parallelTask )
2534{
2535
2536	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2537
2538	if ( task == NULL )
2539	{
2540		return NULL;
2541	}
2542
2543	return task->GetHBADataPointer ( );
2544
2545}
2546
2547
2548//-----------------------------------------------------------------------------
2549//	GetHBADataDescriptor - Gets the HBA memory descriptor associated with
2550//							 a command.								[PROTECTED]
2551//-----------------------------------------------------------------------------
2552
2553IOMemoryDescriptor *
2554IOSCSIParallelInterfaceDevice::GetHBADataDescriptor (
2555							SCSIParallelTaskIdentifier 	parallelTask )
2556{
2557
2558	SCSIParallelTask *	task = ( SCSIParallelTask * ) parallelTask;
2559
2560	if ( task == NULL )
2561	{
2562		return NULL;
2563	}
2564
2565	return task->GetHBADataDescriptor ( );
2566
2567}
2568