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