1/*
2  File: AppleSCSITargetEmulator.h
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 "AppleSCSITargetEmulator.h"
48#include "AppleSCSILogicalUnitEmulator.h"
49#include "AppleSCSIPDT00Emulator.h"
50#include "AppleSCSIPDT03Emulator.h"
51
52#include <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h>
53#include <IOKit/scsi/SCSICmds_REQUEST_SENSE_Defs.h>
54#include <IOKit/scsi/SCSICmds_REPORT_LUNS_Definitions.h>
55#include <IOKit/scsi/SCSICommandOperationCodes.h>
56#include <IOKit/IOLocks.h>
57
58
59//-----------------------------------------------------------------------------
60//	Macros
61//-----------------------------------------------------------------------------
62
63#define DEBUG 												1
64#define DEBUG_ASSERT_COMPONENT_NAME_STRING					"TargetEmulator"
65
66#if DEBUG
67#define TARGET_EMULATOR_DEBUGGING_LEVEL						4
68#endif
69
70#include "DebugSupport.h"
71
72#if ( TARGET_EMULATOR_DEBUGGING_LEVEL >= 1 )
73#define PANIC_NOW(x)		panic x
74#else
75#define PANIC_NOW(x)
76#endif
77
78#if ( TARGET_EMULATOR_DEBUGGING_LEVEL >= 2 )
79#define ERROR_LOG(x)		IOLog x; IOSleep(1)
80#else
81#define ERROR_LOG(x)
82#endif
83
84#if ( TARGET_EMULATOR_DEBUGGING_LEVEL >= 3 )
85#define STATUS_LOG(x)		IOLog x; IOSleep(1)
86#else
87#define STATUS_LOG(x)
88#endif
89
90#if ( TARGET_EMULATOR_DEBUGGING_LEVEL >= 4 )
91#define COMMAND_LOG(x)		IOLog x; IOSleep(1)
92#else
93#define COMMAND_LOG(x)
94#endif
95
96
97#define super OSObject
98OSDefineMetaClassAndStructors ( AppleSCSITargetEmulator, OSObject );
99
100
101//-----------------------------------------------------------------------------
102//	Prototypes
103//-----------------------------------------------------------------------------
104
105static SInt32
106CompareLUNs (
107	const OSMetaClassBase * obj1,
108	const OSMetaClassBase * obj2,
109	void * ref );
110
111
112//-----------------------------------------------------------------------------
113//	Globals
114//-----------------------------------------------------------------------------
115
116SCSICmd_INQUIRY_StandardData gInquiryData =
117{
118	kINQUIRY_PERIPHERAL_QUALIFIER_NotSupported | kINQUIRY_PERIPHERAL_TYPE_UnknownOrNoDeviceType,	// PERIPHERAL_DEVICE_TYPE
119	0,	// RMB;
120	5,	// VERSION
121	2,	// RESPONSE_DATA_FORMAT
122	sizeof ( SCSICmd_INQUIRY_StandardData ) - 5,	// ADDITIONAL_LENGTH
123	0,	// SCCSReserved
124	0,	// flags1
125	0,	// flags2
126	"APPLE  ",
127	"SCSI Emulator  ",
128	"1.0",
129};
130
131SCSI_Sense_Data
132AppleSCSITargetEmulator::sBadLUNSenseData =
133{
134	/* VALID_RESPONSE_CODE */				0x80 | kSENSE_RESPONSE_CODE_Current_Errors,
135	/* SEGMENT_NUMBER */					0x00, // Obsolete
136	/* SENSE_KEY */							kSENSE_KEY_ILLEGAL_REQUEST,
137	/* INFORMATION_1 */						0x00,
138	/* INFORMATION_2 */						0x00,
139	/* INFORMATION_3 */						0x00,
140	/* INFORMATION_4 */						0x00,
141	/* ADDITIONAL_SENSE_LENGTH */			0x00,
142	/* COMMAND_SPECIFIC_INFORMATION_1 */	0x00,
143	/* COMMAND_SPECIFIC_INFORMATION_2 */	0x00,
144	/* COMMAND_SPECIFIC_INFORMATION_3 */	0x00,
145	/* COMMAND_SPECIFIC_INFORMATION_4 */	0x00,
146	/* ADDITIONAL_SENSE_CODE */				0x25, // LOGICAL UNIT NOT SUPPORTED
147	/* ADDITIONAL_SENSE_CODE_QUALIFIER */	0x00,
148	/* FIELD_REPLACEABLE_UNIT_CODE */		0x00,
149	/* SKSV_SENSE_KEY_SPECIFIC_MSB */		0x00,
150	/* SENSE_KEY_SPECIFIC_MID */			0x00,
151	/* SENSE_KEY_SPECIFIC_LSB */			0x00
152};
153
154SCSI_Sense_Data
155AppleSCSITargetEmulator::sLUNInventoryChangedData =
156{
157	/* VALID_RESPONSE_CODE */				0x80 | kSENSE_RESPONSE_CODE_Current_Errors,
158	/* SEGMENT_NUMBER */					0x00, // Obsolete
159	/* SENSE_KEY */							kSENSE_KEY_UNIT_ATTENTION,
160	/* INFORMATION_1 */						0x00,
161	/* INFORMATION_2 */						0x00,
162	/* INFORMATION_3 */						0x00,
163	/* INFORMATION_4 */						0x00,
164	/* ADDITIONAL_SENSE_LENGTH */			0x00,
165	/* COMMAND_SPECIFIC_INFORMATION_1 */	0x00,
166	/* COMMAND_SPECIFIC_INFORMATION_2 */	0x00,
167	/* COMMAND_SPECIFIC_INFORMATION_3 */	0x00,
168	/* COMMAND_SPECIFIC_INFORMATION_4 */	0x00,
169	/* ADDITIONAL_SENSE_CODE */				0x3F, // LOGICAL UNIT NOT SUPPORTED
170	/* ADDITIONAL_SENSE_CODE_QUALIFIER */	0x0E,
171	/* FIELD_REPLACEABLE_UNIT_CODE */		0x00,
172	/* SKSV_SENSE_KEY_SPECIFIC_MSB */		0x00,
173	/* SENSE_KEY_SPECIFIC_MID */			0x00,
174	/* SENSE_KEY_SPECIFIC_LSB */			0x00
175};
176
177
178//-----------------------------------------------------------------------------
179//	Create
180//-----------------------------------------------------------------------------
181
182AppleSCSITargetEmulator *
183AppleSCSITargetEmulator::Create (
184	SCSITargetIdentifier 		targetID )
185{
186
187	AppleSCSITargetEmulator *	emulator 	= NULL;
188	bool						result		= false;
189
190	STATUS_LOG ( ( "AppleSCSITargetEmulator::Create, targetID = %qd\n", targetID ) );
191
192	emulator = OSTypeAlloc ( AppleSCSITargetEmulator );
193	require_nonzero ( emulator, ErrorExit );
194
195	result = emulator->Init ( targetID );
196	require ( result, ReleaseEmulator );
197
198	return emulator;
199
200
201ReleaseEmulator:
202
203
204	emulator->release ( );
205
206
207ErrorExit:
208
209
210	return NULL;
211
212}
213
214
215//-----------------------------------------------------------------------------
216//	Init
217//-----------------------------------------------------------------------------
218
219bool
220AppleSCSITargetEmulator::Init (
221	SCSITargetIdentifier 		targetID )
222{
223
224	bool						result		= false;
225	AppleSCSIPDT03Emulator *	emulator	= NULL;
226
227	STATUS_LOG ( ( "AppleSCSITargetEmulator::Init, targetID = %qd\n", targetID ) );
228
229	result = super::init ( );
230	require ( result, ErrorExit );
231
232	fTargetID = targetID;
233
234	fLock = IOLockAlloc ( );
235	require_nonzero ( fLock, ErrorExit );
236
237	fLUNs = OSOrderedSet::withCapacity ( 16, CompareLUNs );
238	require_nonzero ( fLUNs, ReleaseLock );
239
240	// Allocate LUN0 (PDT 03h device).
241	emulator = OSTypeAlloc ( AppleSCSIPDT03Emulator );
242	require_nonzero ( emulator, ReleaseSet );
243
244	emulator->SetLogicalUnitNumber ( 0 );
245	fLUNs->setObject ( emulator );
246	emulator->release ( );
247
248	fLUNDataAvailable		= kREPORT_LUNS_HeaderSize + sizeof ( SCSICmd_REPORT_LUNS_LUN_ENTRY );
249	fLUNReportBufferSize	= PAGE_SIZE;
250
251	// Start with a page of memory. Grow as required later.
252	fLUNReportBuffer = ( SCSICmd_REPORT_LUNS_Header * ) IOMalloc ( fLUNReportBufferSize );
253	require_nonzero ( fLUNReportBuffer, ReleaseSet );
254
255	bzero ( fLUNReportBuffer, fLUNReportBufferSize );
256
257	fLUNReportBuffer->LUN_LIST_LENGTH = OSSwapHostToBigInt32 ( sizeof ( SCSICmd_REPORT_LUNS_LUN_ENTRY ) );
258	fLUNReportBuffer->LUN[0].FIRST_LEVEL_ADDRESSING = OSSwapHostToBigInt16 ( 0 );
259
260	return true;
261
262
263ReleaseSet:
264
265
266	fLUNs->release ( );
267	fLUNs = NULL;
268
269
270ReleaseLock:
271
272
273	IOLockFree ( fLock );
274	fLock = NULL;
275
276
277ErrorExit:
278
279
280	return false;
281
282}
283
284
285//-----------------------------------------------------------------------------
286//	free
287//-----------------------------------------------------------------------------
288
289void
290AppleSCSITargetEmulator::free ( void )
291{
292
293	STATUS_LOG ( ( "AppleSCSITargetEmulator::free\n" ) );
294
295	if ( fLUNs != NULL )
296	{
297
298		fLUNs->release ( );
299		fLUNs = NULL;
300
301	}
302
303	if ( fLUNReportBuffer != NULL )
304	{
305
306		IOFree ( fLUNReportBuffer, fLUNReportBufferSize );
307		fLUNReportBuffer = NULL;
308		fLUNReportBufferSize = 0;
309
310	}
311
312	IOLockFree ( fLock );
313	fLock = NULL;
314
315	super::free ( );
316
317}
318
319
320//-----------------------------------------------------------------------------
321//	AddLogicalUnit
322//-----------------------------------------------------------------------------
323
324bool
325AppleSCSITargetEmulator::AddLogicalUnit (
326	SCSILogicalUnitNumber	logicalUnit,
327	UInt64					capacity,
328	IOMemoryDescriptor * 	inquiryBuffer,
329	IOMemoryDescriptor * 	inquiryPage00Buffer,
330	IOMemoryDescriptor * 	inquiryPage80Buffer,
331	IOMemoryDescriptor * 	inquiryPage83Buffer )
332{
333
334	AppleSCSIPDT00Emulator *		emulator	= NULL;
335	bool							result		= false;
336	bool							needsWakeup = false;
337	UInt32							bufferSize	= 0;
338
339	STATUS_LOG ( ( "+AppleSCSITargetEmulator::AddLogicalUnit, logicalUnit = %qd, capacity = %qd\n", logicalUnit, capacity ) );
340
341	require ( ( logicalUnit < 16384 ), ErrorExit );
342	require ( ( logicalUnit > 0 ), ErrorExit );
343
344	emulator = AppleSCSIPDT00Emulator::WithCapacity ( capacity );
345	require_nonzero ( emulator, ErrorExit );
346
347	emulator->SetLogicalUnitNumber ( logicalUnit );
348
349	result = emulator->SetDeviceBuffers ( inquiryBuffer, inquiryPage00Buffer, inquiryPage80Buffer, inquiryPage83Buffer );
350	require ( result, ReleaseEmulator );
351
352	IOLockLock ( fLock );
353
354	if ( fState & kTargetStateChangeActiveMask )
355	{
356
357		fState |= kTargetStateChangeActiveWaitMask;
358		IOLockSleep ( fLock, &fState, THREAD_UNINT );
359
360	}
361
362	if ( ( fLUNReportBufferSize - fLUNDataAvailable ) < sizeof ( SCSICmd_REPORT_LUNS_LUN_ENTRY ) )
363	{
364
365		void *	buffer = NULL;
366
367		// Double the buffer size.
368		bufferSize = fLUNReportBufferSize << 1;
369
370		// Mark that we're changing state. Anyone who grabs the lock after we
371		// drop it will be forced to sleep and wait until this state change is done.
372		fState |= kTargetStateChangeActiveMask;
373
374		// Drop the lock since IOMalloc might block.
375		IOLockUnlock ( fLock );
376
377		// Allocate the new buffer.
378		buffer = IOMalloc ( bufferSize );
379
380		// Reacquire the lock.
381		IOLockLock ( fLock );
382
383		fState &= ~kTargetStateChangeActiveMask;
384
385		if ( buffer != NULL )
386		{
387
388			// Free the old buffer.
389			IOFree ( fLUNReportBuffer, fLUNReportBufferSize );
390
391			// Set the new buffer.
392			fLUNReportBuffer 		= ( SCSICmd_REPORT_LUNS_Header * ) buffer;
393			fLUNReportBufferSize 	= bufferSize;
394
395		}
396
397		else
398		{
399
400			if ( fState & kTargetStateChangeActiveWaitMask )
401			{
402				needsWakeup = true;
403			}
404
405			IOLockUnlock ( fLock );
406
407			if ( needsWakeup == true )
408			{
409				IOLockWakeup ( fLock, &fState, false );
410			}
411
412			goto ReleaseEmulator;
413
414		}
415
416	}
417
418	// Add this LUN emulator to the set.
419	fLUNs->setObject ( emulator );
420
421	// Rebuild the list.
422	RebuildListOfLUNs ( );
423
424	if ( fState & kTargetStateChangeActiveWaitMask )
425	{
426		needsWakeup = true;
427	}
428
429	IOLockUnlock ( fLock );
430
431	if ( needsWakeup == true )
432	{
433		IOLockWakeup ( fLock, &fState, false );
434	}
435
436	emulator->release ( );
437
438	STATUS_LOG ( ( "-AppleSCSITargetEmulator::AddLogicalUnit\n" ) );
439
440	return result;
441
442
443ReleaseEmulator:
444
445
446	emulator->release ( );
447	emulator = NULL;
448
449
450ErrorExit:
451
452
453	STATUS_LOG ( ( "-AppleSCSITargetEmulator::AddLogicalUnit failed!!!\n" ) );
454
455	return false;
456
457}
458
459
460//-----------------------------------------------------------------------------
461//	RemoveLogicalUnit
462//-----------------------------------------------------------------------------
463
464void
465AppleSCSITargetEmulator::RemoveLogicalUnit (
466	SCSILogicalUnitNumber		logicalUnitNumber )
467{
468
469	AppleSCSILogicalUnitEmulator *	LUN		= NULL;
470	int								index	= 0;
471	int								count	= 0;
472
473	STATUS_LOG ( ( "AppleSCSITargetEmulator::RemoveLogicalUnit, logicalUnitNumber = %qd\n", logicalUnitNumber ) );
474
475	IOLockLock ( fLock );
476
477	count = fLUNs->getCount ( );
478
479	STATUS_LOG ( ( "count = %d\n", count ) );
480
481	for ( index = 0; index < count; index++ )
482	{
483
484		LUN = ( AppleSCSILogicalUnitEmulator * ) fLUNs->getObject ( index );
485
486		STATUS_LOG ( ( "LUN->GetLogicalUnitNumber ( ) = %qd\n", LUN->GetLogicalUnitNumber ( ) ) );
487
488		if ( LUN->GetLogicalUnitNumber ( ) == logicalUnitNumber )
489		{
490
491			fLUNs->removeObject ( LUN );
492			break;
493
494		}
495
496	}
497
498	// Rebuild the list.
499	RebuildListOfLUNs ( );
500
501	IOLockUnlock ( fLock );
502
503}
504
505
506//-----------------------------------------------------------------------------
507//	RebuildListOfLUNs
508//-----------------------------------------------------------------------------
509// MUST BE CALLED WITH fLock HELD.
510
511void
512AppleSCSITargetEmulator::RebuildListOfLUNs ( void )
513{
514
515	UInt32	index		= 0;
516	UInt32	count 		= 0;
517	UInt32	bufferSize 	= 0;
518
519	STATUS_LOG ( ( "AppleSCSITargetEmulator::RebuildListOfLUNs\n" ) );
520
521	// Get the count of emulators (including this new one).
522	count = fLUNs->getCount ( );
523
524	// Set the bufferSize.
525	bufferSize = count * sizeof ( SCSICmd_REPORT_LUNS_LUN_ENTRY );
526
527	// Zero the buffer.
528	bzero ( fLUNReportBuffer, fLUNReportBufferSize );
529
530	// Repopulate the buffer with correct LUN data.
531	fLUNReportBuffer->LUN_LIST_LENGTH = OSSwapHostToBigInt32 ( bufferSize );
532
533#if USE_LUN_BYTES
534
535	// Repopulate the buffer with correct LUN inventory.
536	for ( index = 0; index < count; index++ )
537	{
538
539		SCSILogicalUnitBytes			logicalUnitBytes	= { 0 };
540		AppleSCSILogicalUnitEmulator *	LUN					= NULL;
541
542		LUN = ( AppleSCSILogicalUnitEmulator * ) fLUNs->getObject ( index );
543		LUN->GetLogicalUnitBytes ( &logicalUnitBytes );
544
545		bcopy ( logicalUnitBytes, &fLUNReportBuffer->LUN[index], sizeof ( SCSILogicalUnitBytes ) );
546
547		STATUS_LOG ( ( "logicalUnitBytes = 0x%02x 0x%02x, Data = 0x%04x\n",
548						logicalUnitBytes[0], logicalUnitBytes[1],
549						fLUNReportBuffer->LUN[index].FIRST_LEVEL_ADDRESSING ) );
550
551	}
552
553#else
554
555	// Repopulate the buffer with correct LUN inventory.
556	for ( index = 0; index < count; index++ )
557	{
558
559		SCSILogicalUnitNumber			logicalUnit	= 0;
560		AppleSCSILogicalUnitEmulator *	LUN			= NULL;
561
562		LUN = ( AppleSCSILogicalUnitEmulator * ) fLUNs->getObject ( index );
563		logicalUnit = LUN->GetLogicalUnitNumber ( );
564
565		fLUNReportBuffer->LUN[index].FIRST_LEVEL_ADDRESSING = OSSwapHostToBigInt16 ( logicalUnit );
566
567	}
568
569#endif	/* USE_LUN_BYTES */
570
571	fLUNDataAvailable = bufferSize + kREPORT_LUNS_HeaderSize;
572
573	fLUNInventoryChanged = true;
574
575}
576
577
578#if USE_LUN_BYTES
579
580//-----------------------------------------------------------------------------
581//	SendCommand
582//-----------------------------------------------------------------------------
583
584int
585AppleSCSITargetEmulator::SendCommand (
586	UInt8 *					cdb,
587	UInt8 					cdbLen,
588	IOMemoryDescriptor *	dataDesc,
589	UInt64 *				dataLen,
590	SCSILogicalUnitBytes	logicalUnitBytes,
591	SCSITaskStatus *		scsiStatus,
592	SCSI_Sense_Data *		senseBuffer,
593	UInt8 *					senseBufferLen )
594{
595
596	int		result				= 0;
597	bool	processedCommand	= false;
598
599	IOLockLock ( fLock );
600
601	if ( fLUNInventoryChanged == true )
602	{
603
604		ERROR_LOG ( ( "Generating UNIT_ATTENTION for LUN inventory change\n" ) );
605		fLUNInventoryChanged = false;
606
607		*scsiStatus = kSCSITaskStatus_CHECK_CONDITION;
608		if ( senseBuffer != NULL )
609		{
610
611			UInt8	amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) );
612
613			bzero ( senseBuffer, *senseBufferLen );
614			bcopy ( &sLUNInventoryChangedData, senseBuffer, amount );
615
616			*senseBufferLen = amount;
617
618		}
619
620		processedCommand = true;
621
622	}
623
624	IOLockUnlock ( fLock );
625
626	if ( processedCommand == false )
627	{
628
629		if ( cdb[0] == kSCSICmd_REPORT_LUNS )
630		{
631
632			COMMAND_LOG ( ( "REPORT_LUNS requested = %qd\n", *dataLen ) );
633
634			if ( fLUNReportBuffer != NULL )
635			{
636
637				*dataLen = min ( fLUNDataAvailable, *dataLen );
638				dataDesc->writeBytes ( 0, fLUNReportBuffer, *dataLen );
639
640				COMMAND_LOG ( ( "REPORT_LUNS realized = %qd\n", *dataLen ) );
641
642				*scsiStatus = kSCSITaskStatus_GOOD;
643
644			}
645
646			processedCommand = true;
647
648		}
649
650		else
651		{
652
653			UInt32								index		= 0;
654			UInt32								count		= 0;
655			AppleSCSILogicalUnitEmulator *		LUN			= NULL;
656
657			IOLockLock ( fLock );
658
659			count = fLUNs->getCount ( );
660
661			// Dispatch to the proper LUN.
662			for ( index = 0; index < count; index++ )
663			{
664
665				SCSILogicalUnitBytes	tempBytes = { 0 };
666
667				LUN = ( AppleSCSILogicalUnitEmulator * ) fLUNs->getObject ( index );
668				LUN->GetLogicalUnitBytes ( &tempBytes );
669				if ( !bcmp ( tempBytes, logicalUnitBytes, sizeof ( SCSILogicalUnitBytes ) ) )
670				{
671
672					IOLockUnlock ( fLock );
673
674					result = LUN->SendCommand ( cdb, cdbLen, dataDesc, dataLen, scsiStatus, senseBuffer, senseBufferLen );
675					processedCommand = true;
676					break;
677
678				}
679
680			}
681
682			if ( processedCommand == false )
683			{
684				IOLockUnlock ( fLock );
685			}
686
687		}
688
689	}
690
691	if ( processedCommand == false )
692	{
693
694		ERROR_LOG ( ( "No LUN found LUN = 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n",
695			logicalUnitBytes[0], logicalUnitBytes[1], logicalUnitBytes[2], logicalUnitBytes[3],
696			logicalUnitBytes[4], logicalUnitBytes[5], logicalUnitBytes[6], logicalUnitBytes[7] ) );
697
698		if ( cdb[0] == kSCSICmd_INQUIRY )
699		{
700
701			ERROR_LOG ( ( "Special case INQUIRY to unknown LUN\n" ) );
702
703			if ( *dataLen > cdb[4] )
704				*dataLen = cdb[4];
705
706			if ( *dataLen > 0 )
707			{
708
709				if ( *dataLen > sizeof ( gInquiryData ) )
710				{
711					*dataLen = sizeof ( gInquiryData );
712				}
713
714				dataDesc->writeBytes ( 0, &gInquiryData, *dataLen );
715
716			}
717
718			*scsiStatus = kSCSITaskStatus_GOOD;
719
720			result = 0;
721
722		}
723
724		else
725		{
726
727			ERROR_LOG ( ( "Something other than INQUIRY to unknown LUN, report error\n" ) );
728
729			*scsiStatus = kSCSITaskStatus_CHECK_CONDITION;
730			if ( senseBuffer != NULL )
731			{
732
733				UInt8	amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) );
734
735				bzero ( senseBuffer, *senseBufferLen );
736				bcopy ( &sBadLUNSenseData, senseBuffer, amount );
737
738				*senseBufferLen = amount;
739
740			}
741
742			result = 0;
743
744		}
745
746	}
747
748	return result;
749
750}
751
752
753#else
754
755
756//-----------------------------------------------------------------------------
757//	SendCommand
758//-----------------------------------------------------------------------------
759
760int
761AppleSCSITargetEmulator::SendCommand (
762	UInt8 *					cdb,
763	UInt8 					cdbLen,
764	IOMemoryDescriptor *	dataDesc,
765	UInt64 *				dataLen,
766	SCSILogicalUnitNumber	logicalUnit,
767	SCSITaskStatus *		scsiStatus,
768	SCSI_Sense_Data *		senseBuffer,
769	UInt8 *					senseBufferLen )
770{
771
772	int		result				= 0;
773	bool	processedCommand	= false;
774
775	IOLockLock ( fLock );
776
777	if ( fLUNInventoryChanged == true )
778	{
779
780		ERROR_LOG ( ( "Generating UNIT_ATTENTION for LUN inventory change\n" ) );
781		fLUNInventoryChanged = false;
782
783		*scsiStatus = kSCSITaskStatus_CHECK_CONDITION;
784		if ( senseBuffer != NULL )
785		{
786
787			UInt8	amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) );
788
789			bzero ( senseBuffer, *senseBufferLen );
790			bcopy ( &sLUNInventoryChangedData, senseBuffer, amount );
791
792			*senseBufferLen = amount;
793
794		}
795
796		processedCommand = true;
797
798	}
799
800	IOLockUnlock ( fLock );
801
802	if ( processedCommand == false )
803	{
804
805		if ( cdb[0] == kSCSICmd_REPORT_LUNS )
806		{
807
808			COMMAND_LOG ( ( "REPORT_LUNS requested = %qd\n", *dataLen ) );
809
810			if ( fLUNReportBuffer != NULL )
811			{
812
813				*dataLen = min ( fLUNDataAvailable, *dataLen );
814				dataDesc->writeBytes ( 0, fLUNReportBuffer, *dataLen );
815
816				COMMAND_LOG ( ( "REPORT_LUNS realized = %qd\n", *dataLen ) );
817
818				*scsiStatus = kSCSITaskStatus_GOOD;
819
820			}
821
822			processedCommand = true;
823
824		}
825
826		else
827		{
828
829			UInt32								index		= 0;
830			UInt32								count		= 0;
831			AppleSCSILogicalUnitEmulator *		LUN			= NULL;
832
833			IOLockLock ( fLock );
834
835			count = fLUNs->getCount ( );
836
837			// Dispatch to the proper LUN.
838			for ( index = 0; index < count; index++ )
839			{
840
841				LUN = ( AppleSCSILogicalUnitEmulator * ) fLUNs->getObject ( index );
842
843				if ( logicalUnit == LUN->GetLogicalUnitNumber ( ) )
844				{
845
846					IOLockUnlock ( fLock );
847
848					result = LUN->SendCommand ( cdb, cdbLen, dataDesc, dataLen, scsiStatus, senseBuffer, senseBufferLen );
849					processedCommand = true;
850					break;
851
852				}
853
854			}
855
856			if ( processedCommand == false )
857			{
858				IOLockUnlock ( fLock );
859			}
860
861		}
862
863	}
864
865	if ( processedCommand == false )
866	{
867
868		ERROR_LOG ( ( "No LUN found LUN = %qd\n", logicalUnit ) );
869
870		if ( cdb[0] == kSCSICmd_INQUIRY )
871		{
872
873			ERROR_LOG ( ( "Special case INQUIRY to unknown LUN\n" ) );
874
875			if ( *dataLen > cdb[4] )
876				*dataLen = cdb[4];
877
878			if ( *dataLen > 0 )
879			{
880
881				if ( *dataLen > sizeof ( gInquiryData ) )
882				{
883					*dataLen = sizeof ( gInquiryData );
884				}
885
886				dataDesc->writeBytes ( 0, &gInquiryData, *dataLen );
887
888			}
889
890			*scsiStatus = kSCSITaskStatus_GOOD;
891
892			result = 0;
893
894		}
895
896		else
897		{
898
899			ERROR_LOG ( ( "Something other than INQUIRY to unknown LUN, report error\n" ) );
900
901			*scsiStatus = kSCSITaskStatus_CHECK_CONDITION;
902			if ( senseBuffer != NULL )
903			{
904
905				UInt8	amount = min ( *senseBufferLen, sizeof ( SCSI_Sense_Data ) );
906
907				bzero ( senseBuffer, *senseBufferLen );
908				bcopy ( &sBadLUNSenseData, senseBuffer, amount );
909
910				*senseBufferLen = amount;
911
912			}
913
914			result = 0;
915
916		}
917
918	}
919
920	return result;
921
922}
923
924
925#endif /* USE_LUN_BYTES */
926
927
928//-----------------------------------------------------------------------------
929//	CompareLUNs
930//-----------------------------------------------------------------------------
931
932static SInt32
933CompareLUNs (
934	const OSMetaClassBase * obj1,
935	const OSMetaClassBase * obj2,
936	void * ref )
937{
938
939	AppleSCSILogicalUnitEmulator *	lun1 = ( AppleSCSILogicalUnitEmulator * ) obj1;
940	AppleSCSILogicalUnitEmulator *	lun2 = ( AppleSCSILogicalUnitEmulator * ) obj2;
941
942#if USE_LUN_BYTES
943
944	SCSILogicalUnitBytes	temp1Bytes = { 0 };
945	SCSILogicalUnitBytes	temp2Bytes = { 0 };
946
947	lun1->GetLogicalUnitBytes ( &temp1Bytes );
948	lun2->GetLogicalUnitBytes ( &temp2Bytes );
949
950	// Returns a comparison result of the object, a negative value if obj1 > obj2,
951	// 0 if obj1 == obj2, and a positive value if obj1 < obj2
952	return bcmp ( temp2Bytes, temp1Bytes, sizeof ( SCSILogicalUnitBytes ) );
953
954#else
955
956	return ( lun1->GetLogicalUnitNumber ( ) - lun2->GetLogicalUnitNumber ( ) );
957
958#endif	/* USE_LUN_BYTES */
959
960}
961