SCSIDevice.m   [plain text]


/*
 * Copyright (c) 2004-2007 Apple Inc. All rights reserved.
 *
 * IMPORTANT:  This Apple software is supplied to you by Apple Inc. ("Apple") in 
 * consideration of your agreement to the following terms, and your use, installation, 
 * modification or redistribution of this Apple software constitutes acceptance of these
 * terms.  If you do not agree with these terms, please do not use, install, modify or 
 * redistribute this Apple software.
 *
 * In consideration of your agreement to abide by the following terms, and subject to these 
 * terms, Apple grants you a personal, non exclusive license, under AppleÕs copyrights in this 
 * original Apple software (the ÒApple SoftwareÓ), to use, reproduce, modify and redistribute 
 * the Apple Software, with or without modifications, in source and/or binary forms; provided 
 * that if you redistribute the Apple Software in its entirety and without modifications, you 
 * must retain this notice and the following text and disclaimers in all such redistributions 
 * of the Apple Software.  Neither the name, trademarks, service marks or logos of Apple 
 * Computer, Inc. may be used to endorse or promote products derived from the Apple Software 
 * without specific prior written permission from Apple. Except as expressly stated in this 
 * notice, no other rights or licenses, express or implied, are granted by Apple herein, 
 * including but not limited to any patent rights that may be infringed by your derivative 
 * works or by other works in which the Apple Software may be incorporated.
 * 
 * The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO WARRANTIES, 
 * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF NON-
 * INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE 
 * SOFTWARE OR ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 
 *
 * IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR CONSEQUENTIAL 
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 
 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 
 * REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, HOWEVER CAUSED AND 
 * WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR 
 * OTHERWISE, EVEN IF APPLE HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
 

//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	Imports
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

#import <unistd.h>
#import "SCSIDevice.h"
#import "Probing.h"
#import "SCSITargetProberKeys.h"
#import <IOKit/IOKitLib.h>
#import <IOKit/IOKitKeys.h>
#import <IOKit/storage/IOStorageProtocolCharacteristics.h>
#import <IOKit/scsi/SCSICmds_INQUIRY_Definitions.h>


//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	Constants
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

#define kIOSCSITargetDeviceClassString					"IOSCSITargetDevice"

// "SCSI I_T Nexus Features" is only defined in
// IOSCSIParallelInterfaceController.h, but it isn't exported to user space (yet).
// Until it is, we have to create a string here and also copy the enums from the
// header as well.
// Remove this when the header is exported.

#define kSCSI_I_T_NexusFeaturesString					@"SCSI I_T Nexus Features"

enum
{
	kSCSIParallelFeature_WideDataTransfer 					= 0,
	kSCSIParallelFeature_SynchronousDataTransfer 			= 1,
	kSCSIParallelFeature_QuickArbitrationAndSelection 		= 2,
	kSCSIParallelFeature_DoubleTransitionDataTransfers 		= 3,
	kSCSIParallelFeature_InformationUnitTransfers 			= 4
};

enum
{
	kSCSIParallelFeature_WideDataTransferMask 				= (1 << kSCSIParallelFeature_WideDataTransfer),
	kSCSIParallelFeature_SynchronousDataTransferMask 		= (1 << kSCSIParallelFeature_SynchronousDataTransfer),
	kSCSIParallelFeature_QuickArbitrationAndSelectionMask 	= (1 << kSCSIParallelFeature_QuickArbitrationAndSelection),
	kSCSIParallelFeature_DoubleTransitionDataTransfersMask 	= (1 << kSCSIParallelFeature_DoubleTransitionDataTransfers),
	kSCSIParallelFeature_InformationUnitTransfersMask 		= (1 << kSCSIParallelFeature_InformationUnitTransfers)
};


//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
//	Implementation
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ

@implementation SCSIDevice

- ( NSString * ) physicalInterconnect { return physicalInterconnect; }
- ( NSString * ) manufacturer { return manufacturer; }
- ( NSString * ) model { return model; }
- ( NSString * ) revision { return revision; }
- ( NSString * ) peripheralDeviceType { return peripheralDeviceType; }
- ( NSNumber * ) domainIdentifier { return domainIdentifier; }
- ( NSNumber * ) deviceIdentifier { return deviceIdentifier; }
- ( NSArray * ) features { return features; }
- ( NSImage * ) image { return image; }
- ( BOOL ) devicePresent { return devicePresent; }
- ( BOOL ) isInitiator { return isInitiator; }


// Called to initialize the object with an io_service_t.

- ( id ) initWithService: ( io_service_t ) service
{
	
	CFTypeRef		property 	= NULL;
	id				value		= NULL;
	IOReturn		result		= kIOReturnSuccess;
	io_iterator_t	iterator	= MACH_PORT_NULL;

	self = [ super init ];
	
	if ( self != nil )
	{
		
		// Init to known state
		[ self clearInformation ];
		
		// Get the protocol characteristics key.
		property = IORegistryEntrySearchCFProperty ( service,
												   kIOServicePlane,
												   CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
												   kCFAllocatorDefault,
												   kIORegistryIterateRecursively );
		if ( property != NULL )
		{
			
			// Get the physical interconnect
			value = ( id ) CFDictionaryGetValue ( ( CFDictionaryRef ) property,
												  CFSTR ( kIOPropertyPhysicalInterconnectTypeKey ) );
			
			[ self setPhysicalInterconnect: ( NSString * ) value ];
			
			// Get the SCSI Domain ID
			value = ( id ) CFDictionaryGetValue ( ( CFDictionaryRef ) property,
												  CFSTR ( kIOPropertySCSIDomainIdentifierKey ) );
			
			[ self setDomainIdentifier: ( NSNumber * ) value ];
			
			// Get the SCSI Target ID
			value = ( id ) CFDictionaryGetValue ( ( CFDictionaryRef ) property,
												  CFSTR ( kIOPropertySCSITargetIdentifierKey ) );
			
			[ self setDeviceIdentifier: ( NSNumber * ) value ];
			
			CFRelease ( property );
			
		}
		
		// See if there is any more information we can fill in (i.e. is a target present?)		
		result = IORegistryEntryGetChildIterator ( service,
												   kIOServicePlane,
												   &iterator );
		if ( result == kIOReturnSuccess )
		{
			
			io_registry_entry_t		entry = MACH_PORT_NULL;
			
			entry = IOIteratorNext ( iterator );
			while ( entry != MACH_PORT_NULL )
			{
				
				// Is this an IOSCSITargetDevice?
				if ( IOObjectConformsTo ( entry, kIOSCSITargetDeviceClassString ) )
				{
					
					NSNumber *	number = nil;
					
					// We have a target device present at this location.
					// Get the information from it.
					[ self setDevicePresent: YES ];
					[ self setImage: [ NSImage imageNamed: kHardDiskImageString ] ];
					[ self setIsInitiator: NO ];
					
					// Get the PDT
					value = ( id ) IORegistryEntrySearchCFProperty (
									service,
									kIOServicePlane,
									CFSTR ( kIOPropertySCSIPeripheralDeviceType ),
									kCFAllocatorDefault,
									kIORegistryIterateRecursively );
					
					[ self setPeripheralDeviceType: [ NSString stringWithFormat: @"%02Xh", [ value intValue ] ] ];
					[ value release ];
					
					// Get the Vendor ID
					value = ( id ) IORegistryEntrySearchCFProperty (
									service,
									kIOServicePlane,
									CFSTR ( kIOPropertySCSIVendorIdentification ),
									kCFAllocatorDefault,
									kIORegistryIterateRecursively );
					
					[ self setManufacturer: value ];
					[ value release ];
					
					// Get the Product ID
					value = ( id ) IORegistryEntrySearchCFProperty (
									service,
									kIOServicePlane,
									CFSTR ( kIOPropertySCSIProductIdentification ),
									kCFAllocatorDefault,
									kIORegistryIterateRecursively );
					
					[ self setModel: value ];
					[ value release ];
					
					// Get the Product Revision Level
					value = ( id ) IORegistryEntrySearchCFProperty (
									service,
									kIOServicePlane,
									CFSTR ( kIOPropertySCSIProductRevisionLevel ),
									kCFAllocatorDefault,
									kIORegistryIterateRecursively );
					
					[ self setRevision: value ];
					[ value release ];
					
					// Get the I_T Nexus Features
					value = ( id ) IORegistryEntrySearchCFProperty (
									service,
									kIOServicePlane,
									CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
									kCFAllocatorDefault,
									kIORegistryIterateRecursively );
					
					number = [ ( NSDictionary * ) value objectForKey: kSCSI_I_T_NexusFeaturesString ];
					
					[ self setFeatures: [ self buildFeatureList: number ] ];
					[ value release ];
					
				}
				
				IOObjectRelease ( entry );
				entry = IOIteratorNext ( iterator );
				
			}
			
			IOObjectRelease ( iterator );
			
		}
	
	}
	
	return self;
	
}


// Called to get the SCSI Domain ID for the io_service_t.

+ ( int ) domainIDForService: ( io_service_t ) service
{
	
	int			domain	= 0;
	id			value	= nil;
	
	// Get the protocol characteristics key.
	value = ( id ) IORegistryEntrySearchCFProperty ( service,
													 kIOServicePlane,
													 CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
													 kCFAllocatorDefault,
													 0 );
	
	// Get the SCSI Domain ID.
	domain = [ [ value objectForKey: @kIOPropertySCSIDomainIdentifierKey ] intValue ];
	[ value release ];
	
	return domain;
	
}


// Called to get the SCSI Target ID for the io_service_t.

+ ( int ) targetIDForService: ( io_service_t ) service
{
	
	int			target	= 0;
	id			value	= nil;
	
	// Get the protocol characteristics key.
	value = ( id ) IORegistryEntrySearchCFProperty ( service,
													 kIOServicePlane,
													 CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
													 kCFAllocatorDefault,
													 0 );
	
	// Get the SCSI Target ID.
	target = [ [ value objectForKey: @kIOPropertySCSITargetIdentifierKey ] intValue ];
	[ value release ];
	
	return target;
	
}


// Builds a feature list out of the bitmask.

- ( NSArray * ) buildFeatureList: ( NSNumber * ) number
{
	
	NSMutableArray *	featureList = nil;
	NSString *			string		= nil;
	int					value		= 0;
	
	// Create an array to which we'll add string descriptions.
	featureList = [ [ [ NSMutableArray alloc ] init ] autorelease ];
	
	// Get the actual value as an int.
	value = [ number intValue ];
	
	// Does this device support Sync transfer?
	if ( value & kSCSIParallelFeature_SynchronousDataTransferMask )
	{
		
		// Yes, get localized string.
		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureSyncString
														   value: kSCSIParallelFeatureSyncString
														   table: nil ];
		// Add localized string to feature list.
		[ featureList addObject: string ];
		
	}
	
	// Does this device support Wide transfer?
	if ( value & kSCSIParallelFeature_WideDataTransferMask )
	{
		
		// Yes, get localized string.
		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureWideString
														   value: kSCSIParallelFeatureWideString
														   table: nil ];
		// Add localized string to feature list.
		[ featureList addObject: string ];
		
	}
	
	// Does this device support QAS?
	if ( value & kSCSIParallelFeature_QuickArbitrationAndSelectionMask )
	{
		
		// Yes, get localized string.
		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureQASString
														   value: kSCSIParallelFeatureQASString
														   table: nil ];
		// Add localized string to feature list.
		[ featureList addObject: string ];
		
	}
	
	// Does this device support DT?
	if ( value & kSCSIParallelFeature_DoubleTransitionDataTransfersMask )
	{
		
		// Yes, get localized string.
		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureDTString
														   value: kSCSIParallelFeatureDTString
														   table: nil ];
		// Add localized string to feature list.
		[ featureList addObject: string ];
		
	}
	
	// Does this device support IU?
	if ( value & kSCSIParallelFeature_InformationUnitTransfersMask )
	{
		
		// Yes, get localized string.
		string = [ [ NSBundle mainBundle ] localizedStringForKey: kSCSIParallelFeatureIUString
														   value: kSCSIParallelFeatureIUString
														   table: nil ];
		// Add localized string to feature list.
		[ featureList addObject: string ];
		
	}
	
	return featureList;
	
}


- ( NSString * ) title
{
	
	NSString *	string = @"No Device Present";
	
	if ( devicePresent == YES )
	{
		string = [ NSString stringWithFormat: @"%@ %@", manufacturer, model ];
	}
	
	return string;
	
}


- ( void ) clearInformation
{
	
	[ self setPhysicalInterconnect: nil ];
	[ self setManufacturer: nil ];
	[ self setModel: nil ];
	[ self setRevision: nil ];
	[ self setPeripheralDeviceType: nil ];
	[ self setDomainIdentifier: nil ];
	[ self setDeviceIdentifier: nil ];
	[ self setFeatures: nil ];
	[ self setIsInitiator: NO ];
	[ self setDevicePresent: NO ];
	[ self setImage: [ NSImage imageNamed: kNothingImageString ] ];
	
}


- ( void ) setIsInitiator: ( BOOL ) value
{
	
	isInitiator = value;
	if ( isInitiator )
	{
		[ self setPeripheralDeviceType: @"N/A" ];
	}
	
}


- ( void ) setDevicePresent: ( BOOL ) value
{
	devicePresent = value;
}


- ( void ) setPhysicalInterconnect: ( NSString * ) p
{
	
	[ p retain ];
	[ physicalInterconnect release ];
	physicalInterconnect = p;
	
}


- ( void ) setManufacturer: ( NSString * ) m
{
	
	[ m retain ];
	[ manufacturer release ];
	manufacturer = m;
	
}


- ( void ) setModel: ( NSString * ) m
{
	
	[ m retain ];
	[ model release ];
	model = m;
	
}


- ( void ) setRevision: ( NSString * ) r
{
	
	[ r retain ];
	[ revision release ];
	revision = r;
	
}


- ( void ) setPeripheralDeviceType: ( NSString * ) p
{
	
	[ p retain ];
	[ peripheralDeviceType release ];
	peripheralDeviceType = p;
	
}


- ( void ) setDomainIdentifier: ( NSNumber * ) i
{
	
	[ i retain ];
	[ domainIdentifier release ];
	domainIdentifier = i;
	
}


- ( void ) setDeviceIdentifier: ( NSNumber * ) i
{
	
	[ i retain ];
	[ deviceIdentifier release ];
	deviceIdentifier = i;
	
}


- ( void ) setFeatures: ( NSArray * ) f
{
	
	[ f retain ];
	[ features release ];
	features = f;
	
}

- ( void ) setImage: ( NSImage * ) i
{

	[ i retain ];
	[ image release ];
	image = i;
	
}


// Action method called by clicking on the "Reprobe" button

- ( IBAction ) reprobe: ( id ) sender
{

#pragma unused ( sender )
	
	IOReturn	result = kIOReturnSuccess;
	
	// Call the ReprobeDomainTarget method and pass the domainID
	// and targetID for this object since it is the one we are
	// reprobing.
	result = ReprobeDomainTarget ( [ domainIdentifier intValue ],
								   [ deviceIdentifier intValue ] );
	
}


@end