1/*
2 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
3 *
4 * IMPORTANT:  This Apple software is supplied to you by Apple Inc. ("Apple") in
5 * consideration of your agreement to the following terms, and your use, installation,
6 * modification or redistribution of this Apple software constitutes acceptance of these
7 * terms.  If you do not agree with these terms, please do not use, install, modify or
8 * redistribute this Apple software.
9 *
10 * In consideration of your agreement to abide by the following terms, and subject to these
11 * terms, Apple grants you a personal, non exclusive license, under Apple�s copyrights in this
12 * original Apple software (the �Apple Software�), to use, reproduce, modify and redistribute
13 * the Apple Software, with or without modifications, in source and/or binary forms; provided
14 * that if you redistribute the Apple Software in its entirety and without modifications, you
15 * must retain this notice and the following text and disclaimers in all such redistributions
16 * of the Apple Software.  Neither the name, trademarks, service marks or logos of Apple
17 * Computer, Inc. may be used to endorse or promote products derived from the Apple Software
18 * without specific prior written permission from Apple. Except as expressly stated in this
19 * notice, no other rights or licenses, express or implied, are granted by Apple herein,
20 * including but not limited to any patent rights that may be infringed by your derivative
21 * works or by other works in which the Apple Software may be incorporated.
22 *
23 * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES,
24 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-
25 * INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE
26 * SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS.
27 *
28 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
30 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE,
31 * REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND
32 * WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
33 * OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36
37//�����������������������������������������������������������������������������
38//	Imports
39//�����������������������������������������������������������������������������
40
41#import <unistd.h>
42#import "SCSIDevice.h"
43#import "Probing.h"
44#import "SCSITargetProberKeys.h"
45#import <IOKit/IOKitLib.h>
46#import <IOKit/IOKitKeys.h>
47#import <IOKit/storage/IOStorageProtocolCharacteristics.h>
48#import <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h>
49
50
51//�����������������������������������������������������������������������������
52//	Constants
53//�����������������������������������������������������������������������������
54
55#define kIOSCSITargetDeviceClassString					"IOSCSITargetDevice"
56
57// "SCSI I_T Nexus Features" is only defined in
58// IOSCSIParallelInterfaceController.h, but it isn't exported to user space (yet).
59// Until it is, we have to create a string here and also copy the enums from the
60// header as well.
61// Remove this when the header is exported.
62
63#define kSCSI_I_T_NexusFeaturesString					@"SCSI I_T Nexus Features"
64
65enum
66{
67	kSCSIParallelFeature_WideDataTransfer 					= 0,
68	kSCSIParallelFeature_SynchronousDataTransfer 			= 1,
69	kSCSIParallelFeature_QuickArbitrationAndSelection 		= 2,
70	kSCSIParallelFeature_DoubleTransitionDataTransfers 		= 3,
71	kSCSIParallelFeature_InformationUnitTransfers 			= 4
72};
73
74enum
75{
76	kSCSIParallelFeature_WideDataTransferMask 				= (1 << kSCSIParallelFeature_WideDataTransfer),
77	kSCSIParallelFeature_SynchronousDataTransferMask 		= (1 << kSCSIParallelFeature_SynchronousDataTransfer),
78	kSCSIParallelFeature_QuickArbitrationAndSelectionMask 	= (1 << kSCSIParallelFeature_QuickArbitrationAndSelection),
79	kSCSIParallelFeature_DoubleTransitionDataTransfersMask 	= (1 << kSCSIParallelFeature_DoubleTransitionDataTransfers),
80	kSCSIParallelFeature_InformationUnitTransfersMask 		= (1 << kSCSIParallelFeature_InformationUnitTransfers)
81};
82
83
84//�����������������������������������������������������������������������������
85//	Implementation
86//�����������������������������������������������������������������������������
87
88@implementation SCSIDevice
89
90- ( NSString * ) physicalInterconnect { return physicalInterconnect; }
91- ( NSString * ) manufacturer { return manufacturer; }
92- ( NSString * ) model { return model; }
93- ( NSString * ) revision { return revision; }
94- ( NSString * ) peripheralDeviceType { return peripheralDeviceType; }
95- ( NSNumber * ) domainIdentifier { return domainIdentifier; }
96- ( NSNumber * ) deviceIdentifier { return deviceIdentifier; }
97- ( NSArray * ) features { return features; }
98- ( NSImage * ) image { return image; }
99- ( BOOL ) devicePresent { return devicePresent; }
100- ( BOOL ) isInitiator { return isInitiator; }
101
102
103// Called to initialize the object with an io_service_t.
104
105- ( id ) initWithService: ( io_service_t ) service
106{
107
108	CFTypeRef		property 	= NULL;
109	id				value		= NULL;
110	IOReturn		result		= kIOReturnSuccess;
111	io_iterator_t	iterator	= MACH_PORT_NULL;
112
113	self = [ super init ];
114
115	if ( self != nil )
116	{
117
118		// Init to known state
119		[ self clearInformation ];
120
121		// Get the protocol characteristics key.
122		property = IORegistryEntrySearchCFProperty ( service,
123												   kIOServicePlane,
124												   CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
125												   kCFAllocatorDefault,
126												   kIORegistryIterateRecursively );
127		if ( property != NULL )
128		{
129
130			// Get the physical interconnect
131			value = ( id ) CFDictionaryGetValue ( ( CFDictionaryRef ) property,
132												  CFSTR ( kIOPropertyPhysicalInterconnectTypeKey ) );
133
134			[ self setPhysicalInterconnect: ( NSString * ) value ];
135
136			// Get the SCSI Domain ID
137			value = ( id ) CFDictionaryGetValue ( ( CFDictionaryRef ) property,
138												  CFSTR ( kIOPropertySCSIDomainIdentifierKey ) );
139
140			[ self setDomainIdentifier: ( NSNumber * ) value ];
141
142			// Get the SCSI Target ID
143			value = ( id ) CFDictionaryGetValue ( ( CFDictionaryRef ) property,
144												  CFSTR ( kIOPropertySCSITargetIdentifierKey ) );
145
146			[ self setDeviceIdentifier: ( NSNumber * ) value ];
147
148			CFRelease ( property );
149
150		}
151
152		// See if there is any more information we can fill in (i.e. is a target present?)
153		result = IORegistryEntryGetChildIterator ( service,
154												   kIOServicePlane,
155												   &iterator );
156		if ( result == kIOReturnSuccess )
157		{
158
159			io_registry_entry_t		entry = MACH_PORT_NULL;
160
161			entry = IOIteratorNext ( iterator );
162			while ( entry != MACH_PORT_NULL )
163			{
164
165				// Is this an IOSCSITargetDevice?
166				if ( IOObjectConformsTo ( entry, kIOSCSITargetDeviceClassString ) )
167				{
168
169					NSNumber *	number = nil;
170
171					// We have a target device present at this location.
172					// Get the information from it.
173					[ self setDevicePresent: YES ];
174					[ self setImage: [ NSImage imageNamed: kHardDiskImageString ] ];
175					[ self setIsInitiator: NO ];
176
177					// Get the PDT
178					value = ( id ) IORegistryEntrySearchCFProperty (
179									service,
180									kIOServicePlane,
181									CFSTR ( kIOPropertySCSIPeripheralDeviceType ),
182									kCFAllocatorDefault,
183									kIORegistryIterateRecursively );
184
185					[ self setPeripheralDeviceType: [ NSString stringWithFormat: @"%02Xh", [ value intValue ] ] ];
186					[ value release ];
187
188					// Get the Vendor ID
189					value = ( id ) IORegistryEntrySearchCFProperty (
190									service,
191									kIOServicePlane,
192									CFSTR ( kIOPropertySCSIVendorIdentification ),
193									kCFAllocatorDefault,
194									kIORegistryIterateRecursively );
195
196					[ self setManufacturer: value ];
197					[ value release ];
198
199					// Get the Product ID
200					value = ( id ) IORegistryEntrySearchCFProperty (
201									service,
202									kIOServicePlane,
203									CFSTR ( kIOPropertySCSIProductIdentification ),
204									kCFAllocatorDefault,
205									kIORegistryIterateRecursively );
206
207					[ self setModel: value ];
208					[ value release ];
209
210					// Get the Product Revision Level
211					value = ( id ) IORegistryEntrySearchCFProperty (
212									service,
213									kIOServicePlane,
214									CFSTR ( kIOPropertySCSIProductRevisionLevel ),
215									kCFAllocatorDefault,
216									kIORegistryIterateRecursively );
217
218					[ self setRevision: value ];
219					[ value release ];
220
221					// Get the I_T Nexus Features
222					value = ( id ) IORegistryEntrySearchCFProperty (
223									service,
224									kIOServicePlane,
225									CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
226									kCFAllocatorDefault,
227									kIORegistryIterateRecursively );
228
229					number = [ ( NSDictionary * ) value objectForKey: kSCSI_I_T_NexusFeaturesString ];
230
231					[ self setFeatures: [ self buildFeatureList: number ] ];
232					[ value release ];
233
234				}
235
236				IOObjectRelease ( entry );
237				entry = IOIteratorNext ( iterator );
238
239			}
240
241			IOObjectRelease ( iterator );
242
243		}
244
245	}
246
247	return self;
248
249}
250
251
252// Called to get the SCSI Domain ID for the io_service_t.
253
254+ ( int ) domainIDForService: ( io_service_t ) service
255{
256
257	int			domain	= 0;
258	id			value	= nil;
259
260	// Get the protocol characteristics key.
261	value = ( id ) IORegistryEntrySearchCFProperty ( service,
262													 kIOServicePlane,
263													 CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
264													 kCFAllocatorDefault,
265													 0 );
266
267	// Get the SCSI Domain ID.
268	domain = [ [ value objectForKey: @kIOPropertySCSIDomainIdentifierKey ] intValue ];
269	[ value release ];
270
271	return domain;
272
273}
274
275
276// Called to get the SCSI Target ID for the io_service_t.
277
278+ ( int ) targetIDForService: ( io_service_t ) service
279{
280
281	int			target	= 0;
282	id			value	= nil;
283
284	// Get the protocol characteristics key.
285	value = ( id ) IORegistryEntrySearchCFProperty ( service,
286													 kIOServicePlane,
287													 CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
288													 kCFAllocatorDefault,
289													 0 );
290
291	// Get the SCSI Target ID.
292	target = [ [ value objectForKey: @kIOPropertySCSITargetIdentifierKey ] intValue ];
293	[ value release ];
294
295	return target;
296
297}
298
299
300// Builds a feature list out of the bitmask.
301
302- ( NSArray * ) buildFeatureList: ( NSNumber * ) number
303{
304
305	NSMutableArray *	featureList = nil;
306	NSString *			string		= nil;
307	int					value		= 0;
308
309	// Create an array to which we'll add string descriptions.
310	featureList = [ [ [ NSMutableArray alloc ] init ] autorelease ];
311
312	// Get the actual value as an int.
313	value = [ number intValue ];
314
315	// Does this device support Sync transfer?
316	if ( value & kSCSIParallelFeature_SynchronousDataTransferMask )
317	{
318
319		// Yes, get localized string.
320		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureSyncString
321														   value: kSCSIParallelFeatureSyncString
322														   table: nil ];
323		// Add localized string to feature list.
324		[ featureList addObject: string ];
325
326	}
327
328	// Does this device support Wide transfer?
329	if ( value & kSCSIParallelFeature_WideDataTransferMask )
330	{
331
332		// Yes, get localized string.
333		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureWideString
334														   value: kSCSIParallelFeatureWideString
335														   table: nil ];
336		// Add localized string to feature list.
337		[ featureList addObject: string ];
338
339	}
340
341	// Does this device support QAS?
342	if ( value & kSCSIParallelFeature_QuickArbitrationAndSelectionMask )
343	{
344
345		// Yes, get localized string.
346		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureQASString
347														   value: kSCSIParallelFeatureQASString
348														   table: nil ];
349		// Add localized string to feature list.
350		[ featureList addObject: string ];
351
352	}
353
354	// Does this device support DT?
355	if ( value & kSCSIParallelFeature_DoubleTransitionDataTransfersMask )
356	{
357
358		// Yes, get localized string.
359		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureDTString
360														   value: kSCSIParallelFeatureDTString
361														   table: nil ];
362		// Add localized string to feature list.
363		[ featureList addObject: string ];
364
365	}
366
367	// Does this device support IU?
368	if ( value & kSCSIParallelFeature_InformationUnitTransfersMask )
369	{
370
371		// Yes, get localized string.
372		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureIUString
373														   value: kSCSIParallelFeatureIUString
374														   table: nil ];
375		// Add localized string to feature list.
376		[ featureList addObject: string ];
377
378	}
379
380	return featureList;
381
382}
383
384
385- ( NSString * ) title
386{
387
388	NSString *	string = @"No Device Present";
389
390	if ( devicePresent == YES )
391	{
392		string = [ NSString stringWithFormat: @"%@ %@", manufacturer, model ];
393	}
394
395	return string;
396
397}
398
399
400- ( void ) clearInformation
401{
402
403	[ self setPhysicalInterconnect: nil ];
404	[ self setManufacturer: nil ];
405	[ self setModel: nil ];
406	[ self setRevision: nil ];
407	[ self setPeripheralDeviceType: nil ];
408	[ self setDomainIdentifier: nil ];
409	[ self setDeviceIdentifier: nil ];
410	[ self setFeatures: nil ];
411	[ self setIsInitiator: NO ];
412	[ self setDevicePresent: NO ];
413	[ self setImage: [ NSImage imageNamed: kNothingImageString ] ];
414
415}
416
417
418- ( void ) setIsInitiator: ( BOOL ) value
419{
420
421	isInitiator = value;
422	if ( isInitiator )
423	{
424		[ self setPeripheralDeviceType: @"N/A" ];
425	}
426
427}
428
429
430- ( void ) setDevicePresent: ( BOOL ) value
431{
432	devicePresent = value;
433}
434
435
436- ( void ) setPhysicalInterconnect: ( NSString * ) p
437{
438
439	[ p retain ];
440	[ physicalInterconnect release ];
441	physicalInterconnect = p;
442
443}
444
445
446- ( void ) setManufacturer: ( NSString * ) m
447{
448
449	[ m retain ];
450	[ manufacturer release ];
451	manufacturer = m;
452
453}
454
455
456- ( void ) setModel: ( NSString * ) m
457{
458
459	[ m retain ];
460	[ model release ];
461	model = m;
462
463}
464
465
466- ( void ) setRevision: ( NSString * ) r
467{
468
469	[ r retain ];
470	[ revision release ];
471	revision = r;
472
473}
474
475
476- ( void ) setPeripheralDeviceType: ( NSString * ) p
477{
478
479	[ p retain ];
480	[ peripheralDeviceType release ];
481	peripheralDeviceType = p;
482
483}
484
485
486- ( void ) setDomainIdentifier: ( NSNumber * ) i
487{
488
489	[ i retain ];
490	[ domainIdentifier release ];
491	domainIdentifier = i;
492
493}
494
495
496- ( void ) setDeviceIdentifier: ( NSNumber * ) i
497{
498
499	[ i retain ];
500	[ deviceIdentifier release ];
501	deviceIdentifier = i;
502
503}
504
505
506- ( void ) setFeatures: ( NSArray * ) f
507{
508
509	[ f retain ];
510	[ features release ];
511	features = f;
512
513}
514
515- ( void ) setImage: ( NSImage * ) i
516{
517
518	[ i retain ];
519	[ image release ];
520	image = i;
521
522}
523
524
525// Action method called by clicking on the "Reprobe" button
526
527- ( IBAction ) reprobe: ( id ) sender
528{
529
530#pragma unused ( sender )
531
532	IOReturn	result = kIOReturnSuccess;
533
534	// Call the ReprobeDomainTarget method and pass the domainID
535	// and targetID for this object since it is the one we are
536	// reprobing.
537	result = ReprobeDomainTarget ( [ domainIdentifier intValue ],
538								   [ deviceIdentifier intValue ] );
539
540}
541
542
543@end