/*
* 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 "SCSIInitiator.h"
#import "SCSITargetProberKeys.h"
#import <IOKit/IOKitLib.h>
#import <IOKit/storage/IOStorageProtocolCharacteristics.h>
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// Constants
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
#define kSCSIInitiatorIdentifierString "SCSI Initiator Identifier"
#define kSocketNumberString "Socket Number"
#define kPCIKeyModel "model"
#define kPCIKeyVendorID "vendor-id"
#define kPCIKeyVersion "version"
#define kPCIKeyName "name"
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// Prototypes
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
static int
deviceComparator ( id obj1, id obj2, void * context );
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// Implementation
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
@implementation SCSIInitiator
- ( NSArray * ) devices { return devices; }
- ( void ) dealloc
{
[ self setInitiatorDevice: nil ];
[ self setDevices: nil ];
}
- ( void ) setInitiatorDevice: ( SCSIDevice * ) i
{
[ i retain ];
[ initiatorDevice release ];
initiatorDevice = i;
}
- ( void ) setDevices: ( NSMutableArray * ) d
{
[ d retain ];
[ devices release ];
devices = d;
}
- ( int ) initiatorID
{
return initiatorID;
}
- ( int ) domainID
{
return domainID;
}
- ( NSString * ) title
{
NSString * string = @"No Controllers Found";
if ( initiatorDevice != nil )
{
string = [ NSString stringWithFormat: @" }
return string;
}
- ( id ) init
{
self = [ super init ];
if ( self != nil )
{
[ self setDevices: [ [ [ NSMutableArray alloc ] init ] autorelease ] ];
[ self setInitiatorDevice: nil ];
}
return self;
}
- ( id ) initWithService: ( io_service_t ) service
{
self = [ super init ];
if ( self != nil )
{
[ self setDevices: [ [ [ NSMutableArray alloc ] init ] autorelease ] ];
[ self setInitiatorDevice: nil ];
[ self setInitiatorProperties: service ];
[ self setTargetProperties: service ];
}
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 add a target device to the devices array.
- ( void ) addTargetDevice: ( SCSIDevice * ) newDevice
{
int count = 0;
int index = 0;
SCSIDevice * device = nil;
count = [ devices count ];
// Broadcast to any listeners that we are updating the devices array.
[ self willChangeValueForKey: kDevicesKeyPath ];
for ( index = 0; index < count; index++ )
{
device = [ devices objectAtIndex: index ];
// Is this the correct device?
if ( [ [ device deviceIdentifier ] intValue ] == [ [ newDevice deviceIdentifier ] intValue ] )
{
// Yes, replace the device at this location with the updated one.
[ devices replaceObjectAtIndex: index withObject: newDevice ];
break;
}
}
// Broadcast to any listeners that we finished updating the devices array.
[ self didChangeValueForKey: kDevicesKeyPath ];
}
- ( void ) removeTargetDevice: ( int ) targetID
{
int count = 0;
int index = 0;
SCSIDevice * device = nil;
count = [ devices count ];
// Broadcast to any listeners that we are updating the devices array.
[ self willChangeValueForKey: kDevicesKeyPath ];
for ( index = 0; index < count; index++ )
{
// Is this the correct device?
device = [ devices objectAtIndex: index ];
if ( [ [ device deviceIdentifier ] intValue ] == targetID )
{
// Yes, force the information to get cleared since the
// target no longer exists.
[ device clearInformation ];
}
}
// Broadcast to any listeners that we finished updating the devices array.
[ self didChangeValueForKey: kDevicesKeyPath ];
}
// Called to set the properties up for the initiator.
- ( void ) setInitiatorProperties: ( io_service_t ) service
{
id value = nil;
// Create the device which represents the initiator.
initiatorDevice = [ [ SCSIDevice alloc ] init ];
// Set some initial defaults.
[ initiatorDevice setDevicePresent: YES ];
[ initiatorDevice setIsInitiator: YES ];
// Find the initiator identifier.
value = ( id ) IORegistryEntrySearchCFProperty ( service,
kIOServicePlane,
CFSTR ( kSCSIInitiatorIdentifierString ),
kCFAllocatorDefault,
0 );
initiatorID = [ value intValue ];
[ value release ];
// Find the SCSI Domain Identifier.
value = ( id ) IORegistryEntrySearchCFProperty ( service,
kIOServicePlane,
CFSTR ( kIOPropertyProtocolCharacteristicsKey ),
kCFAllocatorDefault,
0 );
domainID = [ [ value objectForKey: @kIOPropertySCSIDomainIdentifierKey ] intValue ];
// Set the physical interconnect.
[ initiatorDevice setPhysicalInterconnect: [ value objectForKey: @kIOPropertyPhysicalInterconnectTypeKey ] ];
[ value release ];
// Set the domainID and deviceID for the initiator device.
[ initiatorDevice setDomainIdentifier: [ NSNumber numberWithInt: domainID ] ];
[ initiatorDevice setDeviceIdentifier: [ NSNumber numberWithInt: initiatorID ] ];
// Cheesy hack to find out if this is Card Bus or PCI,
// need a better way to determine this in the future.
value = ( id ) IORegistryEntrySearchCFProperty ( service,
kIOServicePlane,
CFSTR ( kSocketNumberString ),
kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents );
if ( value == nil )
[ initiatorDevice setImage: [ NSImage imageNamed: kPCICardImageString ] ];
else
[ initiatorDevice setImage: [ NSImage imageNamed: kPCCardImageString ] ];
// The card doesn't have any features. Maybe we can add some later...
[ initiatorDevice setFeatures: nil ];
// Not all PCI/CardBus devices have these keys. Need to look at more
// cards and see if we can glean more information for things like Firmware Revision,
// FCode revision, etc. Maybe in the next release...
value = ( id ) IORegistryEntrySearchCFProperty ( service,
kIOServicePlane,
CFSTR ( kPCIKeyVersion ),
kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents );
[ initiatorDevice setRevision: [ NSString stringWithCString: value ? [ value bytes ] : "Unknown" ] ];
value = ( id ) IORegistryEntrySearchCFProperty ( service,
kIOServicePlane,
CFSTR ( kPCIKeyModel ),
kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents );
[ initiatorDevice setModel: [ NSString stringWithCString: value ? [ value bytes ] : "Unknown" ] ];
value = ( id ) IORegistryEntrySearchCFProperty ( service,
kIOServicePlane,
CFSTR ( kPCIKeyName ),
kCFAllocatorDefault,
kIORegistryIterateRecursively | kIORegistryIterateParents );
[ initiatorDevice setManufacturer: [ NSString stringWithCString: value ? [ value bytes ] : "Unknown" ] ];
// Add the initiator device to the list of devices.
[ devices addObject: initiatorDevice ];
}
// Called to set the properties up for the target devices.
- ( void ) setTargetProperties: ( io_service_t ) service
{
IOReturn result = kIOReturnSuccess;
io_iterator_t iterator = MACH_PORT_NULL;
SCSIDevice * device = nil;
// Get a child iterator.
result = IORegistryEntryGetChildIterator ( service,
kIOServicePlane,
&iterator );
if ( result == kIOReturnSuccess )
{
io_service_t child = MACH_PORT_NULL;
child = IOIteratorNext ( iterator );
while ( child != MACH_PORT_NULL )
{
// Create a SCSIDevice object to represent this device.
device = [ [ SCSIDevice alloc ] initWithService: child ];
// Add the device to the list.
[ devices addObject: device ];
// Proceed to the next...
IOObjectRelease ( child );
child = IOIteratorNext ( iterator );
}
IOObjectRelease ( iterator );
iterator = MACH_PORT_NULL;
}
// Sort the devices we found. The sorting function uses the
// targetID to sort. This is arbitrary, but works well in this
// case since we display stuff from lowest targetID to highest.
[ devices sortUsingFunction: deviceComparator context: nil ];
}
#if 0
#pragma mark -
#pragma mark Static Methods
#pragma mark -
#endif
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
// deviceComparator - Compares devices based on deviceIdentifier field
//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
int
deviceComparator ( id obj1, id obj2, void * context )
{
#pragma unused ( context )
int result = NSOrderedSame;
if ( [ [ obj1 deviceIdentifier ] intValue ] < [ [ obj2 deviceIdentifier ] intValue ] )
{
result = NSOrderedAscending;
}
else if ( [ [ obj1 deviceIdentifier ] intValue ] > [ [ obj2 deviceIdentifier ] intValue ] )
{
result = NSOrderedDescending;
}
return result;
}
@end