1/*
2  File: AppleSCSIEmulatorAdapter.cpp
3
4  Contains:
5
6  Version: 1.0.0
7
8  Copyright: Copyright (c) 2007 by Apple Inc., All Rights Reserved.
9
10Disclaimer:IMPORTANT:  This Apple software is supplied to you by Apple Inc.
11("Apple") in consideration of your agreement to the following terms, and your use,
12installation, modification or redistribution of this Apple software constitutes acceptance
13of these terms.  If you do not agree with these terms, please do not use, install, modify or
14redistribute this Apple software.
15
16In consideration of your agreement to abide by the following terms, and subject
17to these terms, Apple grants you a personal, non-exclusive license, under Apple's
18copyrights in this original Apple software (the "Apple Software"), to use, reproduce,
19modify and redistribute the Apple Software, with or without modifications, in source and/or
20binary forms; provided that if you redistribute the Apple Software in its entirety
21and without modifications, you must retain this notice and the following text
22and disclaimers in all such redistributions of the Apple Software.  Neither the
23name, trademarks, service marks or logos of Apple Inc. may be used to
24endorse or promote products derived from the Apple Software without specific prior
25written permission from Apple.  Except as expressly stated in this notice, no
26other rights or licenses, express or implied, are granted by Apple herein,
27including but not limited to any patent rights that may be infringed by your derivative
28works or by other works in which the Apple Software may be incorporated.
29
30The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES,
31EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-INFRINGEMENT,
32MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE
33OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. IN NO EVENT SHALL APPLE
34BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
35NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
36OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
37REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED
38AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT
39LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40*/
41
42
43//-----------------------------------------------------------------------------
44//	Includes
45//-----------------------------------------------------------------------------
46
47#include <libkern/c++/OSArray.h>
48#include <libkern/c++/OSData.h>
49#include <libkern/c++/OSString.h>
50#include <IOKit/IOTypes.h>
51#include <IOKit/IOMessage.h>
52#include <IOKit/IOMemoryDescriptor.h>
53#include <IOKit/storage/IOStorageDeviceCharacteristics.h>
54#include <IOKit/storage/IOStorageProtocolCharacteristics.h>
55#include <IOKit/scsi/spi/IOSCSIParallelInterfaceController.h>
56
57#include "AppleSCSITargetEmulator.h"
58#include "AppleSCSIEmulatorAdapter.h"
59#include "AppleSCSIEmulatorEventSource.h"
60
61//-----------------------------------------------------------------------------
62//	Structures
63//-----------------------------------------------------------------------------
64
65typedef struct AdapterTargetStruct
66{
67	AppleSCSITargetEmulator *	emulator;
68} AdapterTargetStruct;
69
70
71//-----------------------------------------------------------------------------
72//	Macros
73//-----------------------------------------------------------------------------
74
75#define DEBUG 												1
76#define DEBUG_ASSERT_COMPONENT_NAME_STRING					"Adapter"
77
78#if DEBUG
79#define EMULATOR_ADAPTER_DEBUGGING_LEVEL					2
80#endif
81
82#include "DebugSupport.h"
83
84#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 1 )
85#define PANIC_NOW(x)		panic x
86#else
87#define PANIC_NOW(x)
88#endif
89
90#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 2 )
91#define ERROR_LOG(x)		IOLog x; IOSleep(1)
92#else
93#define ERROR_LOG(x)
94#endif
95
96#if ( EMULATOR_ADAPTER_DEBUGGING_LEVEL >= 3 )
97#define STATUS_LOG(x)		IOLog x; IOSleep(1)
98#else
99#define STATUS_LOG(x)
100#endif
101
102
103// Define superclass
104#define super IOSCSIParallelInterfaceController
105OSDefineMetaClassAndStructors ( AppleSCSIEmulatorAdapter, IOSCSIParallelInterfaceController );
106
107#define kMaxTargetID	256
108
109
110//-----------------------------------------------------------------------------
111//	ReportHBAConstraints
112//-----------------------------------------------------------------------------
113
114void
115AppleSCSIEmulatorAdapter::ReportHBAConstraints (
116	OSDictionary *		constraints )
117{
118
119	super::ReportHBAConstraints ( constraints );
120#if USE_LUN_BYTES
121	constraints->setObject ( kIOHierarchicalLogicalUnitSupportKey, kOSBooleanTrue );
122#endif
123
124}
125
126
127//-----------------------------------------------------------------------------
128//	ReportHBAHighestLogicalUnitNumber
129//-----------------------------------------------------------------------------
130
131SCSILogicalUnitNumber
132AppleSCSIEmulatorAdapter::ReportHBAHighestLogicalUnitNumber ( void )
133{
134
135	// Report the highest LUN number devices on this HBA are allowed to have.
136	// 0 is a valid response for HBAs that only allow a single LUN per device
137
138	SCSILogicalUnitNumber maxLUN = 0x3FFF;
139
140	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::ReportHBAHighestLogicalUnitNumber, maxLUN = %qd\n", maxLUN ) );
141
142	return maxLUN;
143
144}
145
146
147//-----------------------------------------------------------------------------
148//	DoesHBASupportSCSIParallelFeature
149//-----------------------------------------------------------------------------
150
151bool
152AppleSCSIEmulatorAdapter::DoesHBASupportSCSIParallelFeature ( SCSIParallelFeature theFeature )
153{
154	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::DoesHBASupportSCSIParallelFeature\n" ) );
155	return false;
156}
157
158
159//-----------------------------------------------------------------------------
160//	InitializeTargetForID
161//-----------------------------------------------------------------------------
162
163bool
164AppleSCSIEmulatorAdapter::InitializeTargetForID ( SCSITargetIdentifier targetID )
165{
166
167	UInt32						index			= 0;
168	UInt32						count			= 0;
169	AppleSCSITargetEmulator *	emulator		= NULL;
170	AdapterTargetStruct *		targetStruct	= NULL;
171	bool						found			= false;
172
173	// Link the emulator to the target.
174	count = fTargetEmulators->getCount ( );
175	for ( index = 0; index < count; index++ )
176	{
177
178		emulator = OSDynamicCast ( AppleSCSITargetEmulator, fTargetEmulators->getObject ( index ) );
179
180		if ( emulator->GetTargetID ( ) == targetID )
181		{
182
183			targetStruct = ( AdapterTargetStruct * ) GetHBATargetDataPointer ( targetID );
184			targetStruct->emulator = emulator;
185			found = true;
186
187		}
188
189	}
190
191	return found;
192
193}
194
195
196//-----------------------------------------------------------------------------
197//	AbortTaskRequest
198//-----------------------------------------------------------------------------
199
200SCSIServiceResponse
201AppleSCSIEmulatorAdapter::AbortTaskRequest (
202							SCSITargetIdentifier 		theT,
203							SCSILogicalUnitNumber		theL,
204							SCSITaggedTaskIdentifier	theQ )
205{
206	// Returning general failure for AbortTaskRequest as this isn't yet supported by our HBA
207
208	return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
209}
210
211
212//-----------------------------------------------------------------------------
213//	AbortTaskSetRequest
214//-----------------------------------------------------------------------------
215
216SCSIServiceResponse
217AppleSCSIEmulatorAdapter::AbortTaskSetRequest (
218							SCSITargetIdentifier 		theT,
219							SCSILogicalUnitNumber		theL )
220{
221	// Returning general failure for AbortTaskSetRequest as this isn't yet supported by our HBA
222
223	return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
224}
225
226
227//-----------------------------------------------------------------------------
228//	ClearACARequest
229//-----------------------------------------------------------------------------
230
231SCSIServiceResponse
232AppleSCSIEmulatorAdapter::ClearACARequest (
233							SCSITargetIdentifier 		theT,
234							SCSILogicalUnitNumber		theL )
235{
236	// Returning general failure for ClearACARequest as this isn't yet supported by our HBA
237
238	return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
239}
240
241
242//-----------------------------------------------------------------------------
243//	ClearTaskSetRequest
244//-----------------------------------------------------------------------------
245
246SCSIServiceResponse
247AppleSCSIEmulatorAdapter::ClearTaskSetRequest (
248							SCSITargetIdentifier 		theT,
249							SCSILogicalUnitNumber		theL )
250{
251	// Returning general failure for ClearTaskSetRequest as this isn't yet supported by our HBA
252
253	return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
254}
255
256
257//-----------------------------------------------------------------------------
258//	LogicalUnitResetRequest
259//-----------------------------------------------------------------------------
260
261SCSIServiceResponse
262AppleSCSIEmulatorAdapter::LogicalUnitResetRequest (
263							SCSITargetIdentifier 		theT,
264							SCSILogicalUnitNumber		theL )
265{
266	// Returning general failure for LogicalUnitResetRequest as this isn't yet supported by our HBA
267
268	return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
269}
270
271
272//-----------------------------------------------------------------------------
273//	TargetResetRequest
274//-----------------------------------------------------------------------------
275
276SCSIServiceResponse
277AppleSCSIEmulatorAdapter::TargetResetRequest (
278							SCSITargetIdentifier		theT )
279{
280	// Returning general failure for TargetResetRequest as this isn't yet supported by our HBA
281
282	return kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
283}
284
285
286//-----------------------------------------------------------------------------
287//	ReportInitiatorIdentifier
288//-----------------------------------------------------------------------------
289
290SCSIInitiatorIdentifier
291AppleSCSIEmulatorAdapter::ReportInitiatorIdentifier ( void )
292{
293
294	// What device ID does our HBA occupy on the bus?
295	SCSIInitiatorIdentifier ourIdentity = kInitiatorID;
296
297	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::ReportInitiatorIdentifier, ourIdentity = %qd\n", ourIdentity ) );
298
299	return ourIdentity;
300
301}
302
303
304//-----------------------------------------------------------------------------
305//	ReportHighestSupportedDeviceID
306//-----------------------------------------------------------------------------
307
308SCSIDeviceIdentifier
309AppleSCSIEmulatorAdapter::ReportHighestSupportedDeviceID ( void )
310{
311
312	// This HBA can handle how many attached devices?  The actual number can be lower
313	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::ReportHighestSupportedDeviceID, kMaxTargetID = %d\n", ( int ) kMaxTargetID ) );
314
315	return kMaxTargetID;
316
317}
318
319
320//-----------------------------------------------------------------------------
321//	ReportMaximumTaskCount
322//-----------------------------------------------------------------------------
323
324UInt32
325AppleSCSIEmulatorAdapter::ReportMaximumTaskCount ( void )
326{
327
328	// How many concurrent tasks does our HBA support?
329	// Given that this is the parallel tasking SCSI family, you'd
330	// expect this to be greater than 1, but single task HBAs are
331	// supported as well
332	UInt32 		maxTasks = 512;
333
334	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::ReportHighestSupportedDeviceID, maxTasks = %ld\n", maxTasks ) );
335
336	return maxTasks;
337
338}
339
340
341//-----------------------------------------------------------------------------
342//	ReportHBASpecificTaskDataSize
343//-----------------------------------------------------------------------------
344
345UInt32
346AppleSCSIEmulatorAdapter::ReportHBASpecificTaskDataSize ( void )
347{
348
349	UInt32	taskDataSize = 0;
350
351	// How much space do we need allocated internally for each task?
352	taskDataSize = sizeof ( SCSIEmulatorRequestBlock );
353	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::ReportHBASpecificTaskDataSize, taskDataSize = %ld\n", taskDataSize ) );
354
355	return taskDataSize;
356
357}
358
359
360//-----------------------------------------------------------------------------
361//	ReportHBASpecificDeviceDataSize
362//-----------------------------------------------------------------------------
363
364UInt32
365AppleSCSIEmulatorAdapter::ReportHBASpecificDeviceDataSize ( void )
366{
367
368	// How much space do we need allocated internally for each attached device?
369	UInt32 hbaDataSize = 0;
370
371	hbaDataSize = sizeof ( AdapterTargetStruct );
372	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::ReportHBASpecificDeviceDataSize, hbaDataSize = %ld\n", hbaDataSize ) );
373
374	return hbaDataSize;
375
376}
377
378
379//-----------------------------------------------------------------------------
380//	DoesHBAPerformDeviceManagement
381//-----------------------------------------------------------------------------
382
383bool
384AppleSCSIEmulatorAdapter::DoesHBAPerformDeviceManagement ( void )
385{
386
387	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::DoesHBAPerformDeviceManagement\n" ) );
388	return true;
389
390}
391
392
393//-----------------------------------------------------------------------------
394//	SetControllerProperties
395//-----------------------------------------------------------------------------
396
397void
398AppleSCSIEmulatorAdapter::SetControllerProperties ( void )
399{
400
401	OSString *	string	= NULL;
402	OSData *	data	= NULL;
403	UInt8		wwn[8];
404	UInt8		addressID[3];
405
406	string = OSString::withCString ( "Apple" );
407	if ( string != NULL )
408	{
409
410		SetHBAProperty ( kIOPropertyVendorNameKey, string );
411		string->release ( );
412		string = NULL;
413
414	}
415
416	string = OSString::withCString ( "SCSI HBA Emulator" );
417	if ( string != NULL )
418	{
419
420		SetHBAProperty ( kIOPropertyProductNameKey, string );
421		string->release ( );
422		string = NULL;
423
424	}
425
426	string = OSString::withCString ( "1.0" );
427	if ( string != NULL )
428	{
429
430		SetHBAProperty ( kIOPropertyProductRevisionLevelKey, string );
431		string->release ( );
432		string = NULL;
433
434	}
435
436	string = OSString::withCString ( "Port 0" );
437	if ( string != NULL )
438	{
439
440		SetHBAProperty ( kIOPropertyPortDescriptionKey, string );
441		string->release ( );
442		string = NULL;
443
444	}
445
446	string = OSString::withCString ( kIOPropertyPortSpeedAutomatic4GigabitKey );
447	if ( string != NULL )
448	{
449
450		SetHBAProperty ( kIOPropertyPortSpeedKey, string );
451		string->release ( );
452		string = NULL;
453
454	}
455
456	string = OSString::withCString ( kIOPropertyPortTopologyAutomaticNPortKey );
457	if ( string != NULL )
458	{
459
460		SetHBAProperty ( kIOPropertyPortTopologyKey, string );
461		string->release ( );
462		string = NULL;
463
464	}
465
466	wwn[0] = 0x10;
467	wwn[1] = 0x00;
468	wwn[2] = 0x00;
469	wwn[3] = 0x40;
470	wwn[4] = 0x50;
471	wwn[5] = 0x60;
472	wwn[6] = 0xBB;
473	wwn[7] = 0xA0;
474
475	data = OSData::withBytes ( wwn, sizeof ( wwn ) );
476	if ( data != NULL )
477	{
478
479		SetHBAProperty ( kIOPropertyFibreChannelPortWorldWideNameKey, data );
480		data->release ( );
481		data = NULL;
482
483	}
484
485	wwn[0] = 0x20;
486	wwn[1] = 0x00;
487	wwn[2] = 0x00;
488	wwn[3] = 0x40;
489	wwn[4] = 0x50;
490	wwn[5] = 0x60;
491	wwn[6] = 0xBB;
492	wwn[7] = 0xA0;
493
494	data = OSData::withBytes ( wwn, sizeof ( wwn ) );
495	if ( data != NULL )
496	{
497
498		SetHBAProperty ( kIOPropertyFibreChannelNodeWorldWideNameKey, data );
499		data->release ( );
500		data = NULL;
501
502	}
503
504	addressID[0] = 0;
505	addressID[1] = 0;
506	addressID[2] = 1;
507
508	data = OSData::withBytes ( addressID, sizeof ( addressID ) );
509	if ( data != NULL )
510	{
511
512		SetHBAProperty ( kIOPropertyFibreChannelAddressIdentifierKey, data );
513		data->release ( );
514		data = NULL;
515
516	}
517
518}
519
520
521//-----------------------------------------------------------------------------
522//	InitializeController
523//-----------------------------------------------------------------------------
524
525bool
526AppleSCSIEmulatorAdapter::InitializeController ( void )
527{
528
529	IOReturn	status 	= kIOReturnSuccess;
530
531	STATUS_LOG ( ( "+AppleSCSIEmulatorAdapter::InitializeController\n" ) );
532
533	SetControllerProperties ( );
534
535	// We don't have any real hardware to initialize in this example code since
536	// we are a virtual HBA. So, we allocate only one thing:
537	// An event source that we will use in lieu of an interrupt for our command
538	// completions.
539	fEventSource = AppleSCSIEmulatorEventSource::Create (
540		this,
541		OSMemberFunctionCast (
542			AppleSCSIEmulatorEventSource::Action,
543			this,
544			&AppleSCSIEmulatorAdapter::TaskComplete ) );
545
546	require_nonzero ( fEventSource, ErrorExit );
547
548	status = GetWorkLoop ( )->addEventSource ( fEventSource );
549	require_success ( status, ReleaseEventSource );
550
551	fTargetEmulators = OSArray::withCapacity ( 1 );
552	require_nonzero ( fTargetEmulators, RemoveEventSource );
553
554	STATUS_LOG ( ( "-AppleSCSIEmulatorAdapter::InitializeController\n" ) );
555
556	return true;
557
558
559RemoveEventSource:
560
561
562	GetWorkLoop ( )->removeEventSource ( fEventSource );
563
564
565ReleaseEventSource:
566
567
568	fEventSource->release ( );
569	fEventSource = NULL;
570
571
572ErrorExit:
573
574
575	STATUS_LOG ( ( "-AppleSCSIEmulatorAdapter::InitializeController failed\n" ) );
576	return false;
577
578}
579
580
581//-----------------------------------------------------------------------------
582//	TerminateController
583//-----------------------------------------------------------------------------
584
585void
586AppleSCSIEmulatorAdapter::TerminateController ( void )
587{
588
589	STATUS_LOG ( ( "+AppleSCSIEmulatorAdapter::TerminateController\n" ) );
590
591	if ( fEventSource != NULL )
592	{
593
594		if ( GetWorkLoop ( )->removeEventSource ( fEventSource ) != kIOReturnSuccess )
595		{
596			ERROR_LOG ( ( "TerminateController: failed to de-register eventsource?\n" ) );
597		}
598
599		fEventSource->release ( );
600		fEventSource = NULL;
601
602	}
603
604	if ( fTargetEmulators != NULL )
605	{
606
607		fTargetEmulators->release ( );
608		fTargetEmulators = NULL;
609
610	}
611
612	STATUS_LOG ( ( "-AppleSCSIEmulatorAdapter::TerminateController\n" ) );
613
614}
615
616
617//-----------------------------------------------------------------------------
618//	StartController
619//-----------------------------------------------------------------------------
620
621bool
622AppleSCSIEmulatorAdapter::StartController ( void )
623{
624
625	// Start providing HBA services.  Re-init anything needed and go
626	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::StartController\n" ) );
627
628	return true;
629
630}
631
632
633//-----------------------------------------------------------------------------
634//	StopController
635//-----------------------------------------------------------------------------
636
637void
638AppleSCSIEmulatorAdapter::StopController ( void )
639{
640
641	// We've been requested to stop providing HBA services.  Cleanup and shut down
642	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::StopController\n" ) );
643
644}
645
646
647//-----------------------------------------------------------------------------
648//	HandleInterruptRequest
649//-----------------------------------------------------------------------------
650
651void
652AppleSCSIEmulatorAdapter::HandleInterruptRequest ( void )
653{
654
655	// OK, odds are, your driver will want to do something here to get info from the HBA.
656	// Usually, this will be pulling task completion info, etc. and then calling TaskCompleted().
657	//
658	// this->TaskCompleted(task, transportSucceeded, scsiStatus, transferredDataLength, senseData, senseDataLength);
659	//
660
661	// Since this example operates without using a real primary interrupt, this will never get called
662	ERROR_LOG ( ( "HandleInterruptRequest: captured interrupt?" ) );
663
664}
665
666
667//-----------------------------------------------------------------------------
668//	CreateDeviceInterrupt
669//-----------------------------------------------------------------------------
670
671IOInterruptEventSource *
672AppleSCSIEmulatorAdapter::CreateDeviceInterrupt (
673											IOInterruptEventSource::Action			action,
674											IOFilterInterruptEventSource::Filter	filter,
675											IOService *								provider )
676{
677
678	STATUS_LOG ( ( "AppleSCSIEmulatorAdapter::CreateDeviceInterrupt\n" ) );
679	return NULL;
680
681}
682
683
684//-----------------------------------------------------------------------------
685//	ProcessParallelTask
686//-----------------------------------------------------------------------------
687
688SCSIServiceResponse
689AppleSCSIEmulatorAdapter::ProcessParallelTask ( SCSIParallelTaskIdentifier parallelRequest )
690{
691
692	SCSIServiceResponse 			ret 				= kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
693	UInt8							transferDir			= GetDataTransferDirection ( parallelRequest );
694	IOMemoryDescriptor *			transferMemDesc		= GetDataBuffer ( parallelRequest );
695	UInt8							cdbLength			= GetCommandDescriptorBlockSize ( parallelRequest );
696	SCSICommandDescriptorBlock  	cdbData				= { 0 };
697	SCSITaskStatus					scsiStatus			= kSCSITaskStatus_No_Status;
698	UInt64							dataLen				= 0;
699	SCSI_Sense_Data					senseDataBuffer		= { 0 };
700	UInt8							senseLength			= sizeof ( SCSI_Sense_Data );
701	AdapterTargetStruct *			targetStruct		= NULL;
702	SCSITargetIdentifier			targetID			= 0;
703	SCSILogicalUnitNumber			logicalUnitNumber	= 0;
704
705#if USE_LUN_BYTES
706	SCSILogicalUnitBytes			logicalUnitBytes	= {  0 };
707	GetLogicalUnitBytes ( parallelRequest, &logicalUnitBytes );
708#endif /* USE_LUN_BYTES */
709
710	targetID = GetTargetIdentifier ( parallelRequest );
711	targetStruct = ( AdapterTargetStruct * ) GetHBATargetDataPointer ( targetID );
712
713	GetCommandDescriptorBlock ( parallelRequest, &cdbData );
714
715	if ( transferMemDesc && ( transferDir != kSCSIDataTransfer_NoDataTransfer ) )
716	{
717		dataLen = GetRequestedDataTransferCount ( parallelRequest );
718	}
719
720#if USE_LUN_BYTES
721	targetStruct->emulator->SendCommand ( cdbData, cdbLength, transferMemDesc, &dataLen, logicalUnitBytes, &scsiStatus, &senseDataBuffer, &senseLength );
722#else
723	logicalUnitNumber = GetLogicalUnitNumber ( parallelRequest );
724	targetStruct->emulator->SendCommand ( cdbData, cdbLength, transferMemDesc, &dataLen, logicalUnitNumber, &scsiStatus, &senseDataBuffer, &senseLength );
725#endif
726
727	CompleteTaskOnWorkloopThread ( parallelRequest, true, scsiStatus, dataLen, &senseDataBuffer, senseLength );
728
729	ret = kSCSIServiceResponse_Request_In_Process;
730	return ret;
731
732}
733
734
735//-----------------------------------------------------------------------------
736//	CompleteTaskOnWorkloopThread
737//-----------------------------------------------------------------------------
738
739void
740AppleSCSIEmulatorAdapter::CompleteTaskOnWorkloopThread (
741	SCSIParallelTaskIdentifier		parallelRequest,
742	bool							transportSuccessful,
743	SCSITaskStatus					scsiStatus,
744	UInt64							actuallyTransferred,
745	SCSI_Sense_Data *				senseBuffer,
746	UInt8							senseLength )
747{
748
749	UInt8						transferDir				= GetDataTransferDirection ( parallelRequest );
750	UInt64						transferSizeMax			= GetRequestedDataTransferCount ( parallelRequest );
751	SCSIEmulatorRequestBlock *	srb						= ( SCSIEmulatorRequestBlock * ) GetHBADataPointer ( parallelRequest );
752
753	if ( transportSuccessful && ( scsiStatus != kSCSITaskStatus_TASK_SET_FULL ) )
754	{
755
756		// set the realized transfer counts
757		switch ( transferDir )
758		{
759
760			case kSCSIDataTransfer_FromTargetToInitiator:
761			{
762
763				if ( actuallyTransferred > transferSizeMax )
764				{
765					actuallyTransferred = transferSizeMax;
766				}
767
768				if ( !SetRealizedDataTransferCount ( parallelRequest, actuallyTransferred ) )
769				{
770					ERROR_LOG ( ( "CompleteTaskOnWorkloopThread: SetRealizedDataTransferCount (%llu bytes) returned FAIL", actuallyTransferred ) );
771				}
772				break;
773
774			}
775
776			case kSCSIDataTransfer_FromInitiatorToTarget:
777			{
778
779				if ( actuallyTransferred > transferSizeMax )
780				{
781					actuallyTransferred = transferSizeMax;
782				}
783
784				if ( !SetRealizedDataTransferCount ( parallelRequest, actuallyTransferred ) )
785				{
786					ERROR_LOG ( ( "CompleteTaskOnWorkloopThread: SetRealizedDataTransferCount (%llu bytes) returned FAIL", actuallyTransferred ) );
787				}
788				break;
789
790			}
791
792			case kSCSIDataTransfer_NoDataTransfer:
793			default:
794			{
795				break;
796			}
797
798		}
799
800	}
801
802	if ( !transportSuccessful )
803	{
804
805		ERROR_LOG ( ( "CompleteTaskOnWorkloopThread: Failed transport - task = %p, transferDir = %d, transferSize = %lld, scsiStatus = 0x%X", parallelRequest, transferDir, transferSizeMax, scsiStatus ) );
806		srb->fServiceResponse = kSCSIServiceResponse_SERVICE_DELIVERY_OR_TARGET_FAILURE;
807
808	}
809
810	else
811	{
812
813		srb->fServiceResponse = kSCSIServiceResponse_TASK_COMPLETE;
814
815		// handle sense data in common fashion and complete the task
816		if ( senseLength > 0 )
817		{
818
819			if ( !SetAutoSenseData ( parallelRequest, ( SCSI_Sense_Data * ) senseBuffer, senseLength ) )
820			{
821				ERROR_LOG ( ( "CompleteTaskOnWorkloopThread: Could not set sense data in parallel task" ) );
822			}
823
824		}
825
826	}
827
828	queue_init ( &srb->fQueueChain );
829	srb->fParallelRequest = parallelRequest;
830	srb->fTaskStatus = scsiStatus;
831	fEventSource->AddItemToQueue ( srb );
832
833}
834
835
836//-----------------------------------------------------------------------------
837//	TaskComplete
838//-----------------------------------------------------------------------------
839
840void
841AppleSCSIEmulatorAdapter::TaskComplete (
842							SCSIParallelTaskIdentifier parallelRequest )
843{
844
845	SCSIEmulatorRequestBlock *	srb = ( SCSIEmulatorRequestBlock * ) GetHBADataPointer ( parallelRequest );
846
847	if ( srb != NULL )
848	{
849		CompleteParallelTask ( parallelRequest, srb->fTaskStatus, srb->fServiceResponse );
850	}
851
852}
853
854
855//-----------------------------------------------------------------------------
856//	CreateLUN
857//-----------------------------------------------------------------------------
858
859IOReturn
860AppleSCSIEmulatorAdapter::CreateLUN (
861	EmulatorTargetParamsStruct * 	targetParameters,
862	task_t							task )
863{
864
865	IOReturn					status					= kIOReturnBadArgument;
866	bool						result					= false;
867	AppleSCSITargetEmulator *	target					= NULL;
868	AdapterTargetStruct *		targetStruct			= NULL;
869	IOMemoryDescriptor *		inquiryBuffer			= NULL;
870	IOMemoryDescriptor *		inquiryPage00Buffer		= NULL;
871	IOMemoryDescriptor *		inquiryPage80Buffer		= NULL;
872	IOMemoryDescriptor *		inquiryPage83Buffer		= NULL;
873
874	ERROR_LOG ( ( "AppleSCSIEmulatorAdapter::CreateTargetEmulator, targetID = %qd\n", targetParameters->targetID ) );
875
876	require ( ( targetParameters->targetID != kInitiatorID ), ErrorExit );
877
878	targetStruct = ( AdapterTargetStruct * ) GetHBATargetDataPointer ( targetParameters->targetID );
879
880	if ( targetStruct == NULL )
881	{
882
883		target = AppleSCSITargetEmulator::Create ( targetParameters->targetID );
884		require_nonzero_action ( target, ErrorExit, status = kIOReturnNoResources );
885
886	}
887
888	else
889	{
890
891		target = targetStruct->emulator;
892
893	}
894
895	ERROR_LOG ( ( "logicalUnit = %qd, capacity = %qd\n", targetParameters->lun.logicalUnit, targetParameters->lun.capacity ) );
896
897	ERROR_LOG ( ( "lun.inquiryData = %qx\n", targetParameters->lun.inquiryData ) );
898	ERROR_LOG ( ( "lun.inquiryPage00Data = %qx\n", targetParameters->lun.inquiryPage00Data ) );
899	ERROR_LOG ( ( "lun.inquiryPage80Data = %qx\n", targetParameters->lun.inquiryPage80Data ) );
900	ERROR_LOG ( ( "lun.inquiryPage83Data = %qx\n", targetParameters->lun.inquiryPage83Data ) );
901
902	ERROR_LOG ( ( "lun.inquiryDataLength = %d\n", targetParameters->lun.inquiryDataLength ) );
903	ERROR_LOG ( ( "lun.inquiryPage00DataLength = %d\n", targetParameters->lun.inquiryPage00DataLength ) );
904	ERROR_LOG ( ( "lun.inquiryPage80DataLength = %d\n", targetParameters->lun.inquiryPage80DataLength ) );
905	ERROR_LOG ( ( "lun.inquiryPage83DataLength = %d\n", targetParameters->lun.inquiryPage83DataLength ) );
906
907	inquiryBuffer = IOMemoryDescriptor::withAddressRange (
908		targetParameters->lun.inquiryData,
909		targetParameters->lun.inquiryDataLength,
910		0,
911		task );
912
913	inquiryPage00Buffer = IOMemoryDescriptor::withAddressRange (
914		targetParameters->lun.inquiryPage00Data,
915		targetParameters->lun.inquiryPage00DataLength,
916		0,
917		task );
918
919	inquiryPage80Buffer = IOMemoryDescriptor::withAddressRange (
920		targetParameters->lun.inquiryPage80Data,
921		targetParameters->lun.inquiryPage80DataLength,
922		0,
923		task );
924
925	inquiryPage83Buffer = IOMemoryDescriptor::withAddressRange (
926		targetParameters->lun.inquiryPage83Data,
927		targetParameters->lun.inquiryPage83DataLength,
928		0,
929		task );
930
931	if ( inquiryBuffer != NULL )
932	{
933		inquiryBuffer->prepare ( );
934	}
935
936	if ( inquiryPage00Buffer != NULL )
937	{
938		inquiryPage00Buffer->prepare ( );
939	}
940
941	if ( inquiryPage80Buffer != NULL )
942	{
943		inquiryPage80Buffer->prepare ( );
944	}
945
946	if ( inquiryPage83Buffer != NULL )
947	{
948		inquiryPage83Buffer->prepare ( );
949	}
950
951	result = target->AddLogicalUnit (
952		targetParameters->lun.logicalUnit,
953		targetParameters->lun.capacity,
954		inquiryBuffer,
955		inquiryPage00Buffer,
956		inquiryPage80Buffer,
957		inquiryPage83Buffer );
958
959	if ( inquiryBuffer != NULL )
960	{
961		inquiryBuffer->complete ( );
962		inquiryBuffer->release ( );
963	}
964
965	if ( inquiryPage00Buffer != NULL )
966	{
967		inquiryPage00Buffer->complete ( );
968		inquiryPage00Buffer->release ( );
969	}
970
971	if ( inquiryPage80Buffer != NULL )
972	{
973		inquiryPage80Buffer->complete ( );
974		inquiryPage80Buffer->release ( );
975	}
976
977	if ( inquiryPage83Buffer != NULL )
978	{
979		inquiryPage83Buffer->complete ( );
980		inquiryPage83Buffer->release ( );
981	}
982
983	// Did we just allocate this target?
984	if ( targetStruct == NULL )
985	{
986
987		OSDictionary *	dict = NULL;
988
989		// Yes. Make sure to add it to the list of target emulators.
990		fTargetEmulators->setObject ( target );
991
992		dict = OSDictionary::withCapacity ( 3 );
993		if ( dict != NULL )
994		{
995
996			OSData *	data		= NULL;
997			UInt8		nodeWWN[]	= { 0x60, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78 };
998			UInt8		portWWN[]	= { 0x50, 0x00, 0x00, 0x00, 0x12, 0x34, 0x56, 0x78 };
999
1000			nodeWWN[1] = ( targetParameters->targetID >> 16 ) & 0xFF;
1001			nodeWWN[2] = ( targetParameters->targetID >>  8 ) & 0xFF;
1002			nodeWWN[3] = ( targetParameters->targetID >>  0 ) & 0xFF;
1003
1004			data = OSData::withBytes ( nodeWWN, sizeof ( nodeWWN ) );
1005			if ( data != NULL )
1006			{
1007				dict->setObject ( kIOPropertyFibreChannelNodeWorldWideNameKey, data );
1008				data->release ( );
1009				data = NULL;
1010
1011			}
1012
1013			data = OSData::withBytes ( portWWN, sizeof ( portWWN ) );
1014			if ( data != NULL )
1015			{
1016				dict->setObject ( kIOPropertyFibreChannelPortWorldWideNameKey, data );
1017				data->release ( );
1018				data = NULL;
1019
1020			}
1021
1022		}
1023
1024		// Last thing to do is allocate the target device.
1025		result = CreateTargetForID ( targetParameters->targetID, dict );
1026
1027		target->release ( );
1028		target = NULL;
1029
1030		dict->release ( );
1031		dict = NULL;
1032
1033	}
1034
1035	if ( result == true )
1036		status = kIOReturnSuccess;
1037	else
1038		status = kIOReturnError;
1039
1040
1041ErrorExit:
1042
1043
1044	return status;
1045
1046}
1047
1048
1049//-----------------------------------------------------------------------------
1050//	DestroyLUN
1051//-----------------------------------------------------------------------------
1052
1053IOReturn
1054AppleSCSIEmulatorAdapter::DestroyLUN (
1055	SCSITargetIdentifier	targetID,
1056	SCSILogicalUnitNumber	logicalUnit )
1057{
1058
1059	AppleSCSITargetEmulator *	emulator		= NULL;
1060	AdapterTargetStruct *		targetStruct	= NULL;
1061
1062	ERROR_LOG ( ( "AppleSCSIEmulatorAdapter::DestroyLUN, targetID = %qd, logicalUnit = %qd\n", targetID, logicalUnit ) );
1063
1064	targetStruct = ( AdapterTargetStruct * ) GetHBATargetDataPointer ( targetID );
1065	require_nonzero ( targetStruct, ErrorExit );
1066
1067	emulator = targetStruct->emulator;
1068	emulator->RemoveLogicalUnit ( logicalUnit );
1069
1070	return kIOReturnSuccess;
1071
1072
1073ErrorExit:
1074
1075
1076	return kIOReturnError;
1077
1078}
1079
1080
1081//-----------------------------------------------------------------------------
1082//	DestroyTarget
1083//-----------------------------------------------------------------------------
1084
1085IOReturn
1086AppleSCSIEmulatorAdapter::DestroyTarget (
1087	SCSITargetIdentifier targetID )
1088{
1089
1090	int							index		= 0;
1091	int							count		= 0;
1092	AppleSCSITargetEmulator *	emulator	= NULL;
1093
1094	ERROR_LOG ( ( "AppleSCSIEmulatorAdapter::DestroyTarget, targetID = %qd\n", targetID ) );
1095
1096	DestroyTargetForID ( targetID );
1097
1098	// Release the emulator.
1099	count = fTargetEmulators->getCount ( );
1100	for ( index = 0; index < count; index++ )
1101	{
1102
1103		emulator = OSDynamicCast ( AppleSCSITargetEmulator, fTargetEmulators->getObject ( index ) );
1104
1105		if ( emulator->GetTargetID ( ) == targetID )
1106		{
1107
1108			fTargetEmulators->removeObject ( index );
1109			break;
1110
1111		}
1112
1113	}
1114
1115	return kIOReturnSuccess;
1116
1117
1118ErrorExit:
1119
1120
1121	return kIOReturnError;
1122
1123}
1124
1125
1126//-----------------------------------------------------------------------------
1127//	AppleSCSIEmulatorDebugAssert
1128//-----------------------------------------------------------------------------
1129
1130void
1131AppleSCSIEmulatorDebugAssert (
1132						const char * componentNameString,
1133						const char * assertionString,
1134						const char * exceptionLabelString,
1135						const char * errorString,
1136						const char * fileName,
1137						long lineNumber,
1138						int errorCode )
1139{
1140
1141	IOLog ( "%s Assert failed: %s ", componentNameString, assertionString );
1142
1143	if ( exceptionLabelString != NULL )
1144		IOLog ( "%s ", exceptionLabelString );
1145
1146	if ( errorString != NULL )
1147		IOLog ( "%s ", errorString );
1148
1149	if ( fileName != NULL )
1150		IOLog ( "file: %s ", fileName );
1151
1152	if ( lineNumber != 0 )
1153		IOLog ( "line: %ld ", lineNumber );
1154
1155	if ( ( long ) errorCode != 0 )
1156		IOLog ( "error: %ld ", ( long ) errorCode );
1157
1158	IOLog ( "\n" );
1159	IOSleep ( 1 );
1160
1161}
1162