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// Includes 39//----------------------------------------------------------------------------- 40 41#include "Probing.h" 42 43#include <stdio.h> 44#include <stdbool.h> 45#include <unistd.h> 46#include <CoreFoundation/CoreFoundation.h> 47#include <IOKit/IOKitLib.h> 48#include <IOKit/storage/IOStorageProtocolCharacteristics.h> 49#include <IOKit/scsi/SCSITask.h> 50 51 52//----------------------------------------------------------------------------- 53// Macros 54//----------------------------------------------------------------------------- 55 56#define DEBUG 0 57 58#define DEBUG_ASSERT_COMPONENT_NAME_STRING "Probing" 59 60#if DEBUG 61#define DEBUG_ASSERT_MESSAGE(componentNameString, \ 62 assertionString, \ 63 exceptionLabelString, \ 64 errorString, \ 65 fileName, \ 66 lineNumber, \ 67 errorCode) \ 68DebugAssert(componentNameString, \ 69 assertionString, \ 70 exceptionLabelString, \ 71 errorString, \ 72 fileName, \ 73 lineNumber, \ 74 errorCode) \ 75 76static void 77DebugAssert ( const char * componentNameString, 78 const char * assertionString, 79 const char * exceptionLabelString, 80 const char * errorString, 81 const char * fileName, 82 long lineNumber, 83 int errorCode ) 84{ 85 86 if ( ( assertionString != NULL ) && ( *assertionString != '\0' ) ) 87 printf ( "Assertion failed: %s: %s\n", componentNameString, assertionString ); 88 else 89 printf ( "Check failed: %s:\n", componentNameString ); 90 if ( exceptionLabelString != NULL ) 91 printf ( " %s\n", exceptionLabelString ); 92 if ( errorString != NULL ) 93 printf ( " %s\n", errorString ); 94 if ( fileName != NULL ) 95 printf ( " file: %s\n", fileName ); 96 if ( lineNumber != 0 ) 97 printf ( " line: %ld\n", lineNumber ); 98 if ( errorCode != 0 ) 99 printf ( " error: %d\n", errorCode ); 100 101} 102 103#endif /* DEBUG */ 104 105#include <AssertMacros.h> 106 107 108//----------------------------------------------------------------------------- 109// Constants 110//----------------------------------------------------------------------------- 111 112#define kIOSCSIParallelInterfaceControllerClassString "IOSCSIParallelInterfaceController" 113 114 115//----------------------------------------------------------------------------- 116// Prototypes 117//----------------------------------------------------------------------------- 118 119static IOReturn 120ReprobeTargetDevice ( io_service_t controller, SCSITargetIdentifier targetID ); 121 122 123//----------------------------------------------------------------------------- 124// ReprobeDomainTarget - Reprobes device at targetID on a SCSI Domain 125//----------------------------------------------------------------------------- 126 127 128IOReturn 129ReprobeDomainTarget ( UInt64 domainID, 130 SCSITargetIdentifier targetID ) 131{ 132 133 IOReturn result = kIOReturnSuccess; 134 io_service_t service = MACH_PORT_NULL; 135 io_iterator_t iterator = MACH_PORT_NULL; 136 boolean_t found = false; 137 138 // First, let's find all the SCSI Parallel Controllers. 139 result = IOServiceGetMatchingServices ( kIOMasterPortDefault, 140 IOServiceMatching ( kIOSCSIParallelInterfaceControllerClassString ), 141 &iterator ); 142 143 require ( ( result == kIOReturnSuccess ), ErrorExit ); 144 145 service = IOIteratorNext ( iterator ); 146 while ( service != MACH_PORT_NULL ) 147 { 148 149 // Have we found the one with the specified domainID yet? 150 if ( found == false ) 151 { 152 153 CFMutableDictionaryRef deviceDict = NULL; 154 CFDictionaryRef subDict = NULL; 155 156 // Get the properties for this node from the IORegistry 157 result = IORegistryEntryCreateCFProperties ( service, 158 &deviceDict, 159 kCFAllocatorDefault, 160 0 ); 161 162 // Get the protocol characteristics dictionary 163 subDict = ( CFDictionaryRef ) CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyProtocolCharacteristicsKey ) ); 164 if ( subDict != NULL ) 165 { 166 167 CFNumberRef deviceDomainIDRef = 0; 168 169 // Get the SCSI Domain Identifier value 170 deviceDomainIDRef = ( CFNumberRef ) CFDictionaryGetValue ( subDict, CFSTR ( kIOPropertySCSIDomainIdentifierKey ) ); 171 if ( deviceDomainIDRef != 0 ) 172 { 173 174 UInt64 deviceDomainID = 0; 175 176 // Get the value from the CFNumberRef. 177 if ( CFNumberGetValue ( deviceDomainIDRef, kCFNumberLongLongType, &deviceDomainID ) ) 178 { 179 180 // Does the domainID match? 181 if ( domainID == deviceDomainID ) 182 { 183 184 // Find the target device and reprobe it. 185 result = ReprobeTargetDevice ( service, targetID ); 186 found = true; 187 188 } 189 190 } 191 192 } 193 194 } 195 196 if ( deviceDict != NULL ) 197 CFRelease ( deviceDict ); 198 199 } 200 201 IOObjectRelease ( service ); 202 203 service = IOIteratorNext ( iterator ); 204 205 } 206 207 IOObjectRelease ( iterator ); 208 iterator = MACH_PORT_NULL; 209 210 if ( found == false ) 211 result = kIOReturnNoDevice; 212 213 214ErrorExit: 215 216 217 return result; 218 219} 220 221 222//----------------------------------------------------------------------------- 223// ReprobeTargetDevice - Actually performs the reprobe if it can find the 224// IOSCSIParallelInterfaceDevice at the targetID. 225//----------------------------------------------------------------------------- 226 227static IOReturn 228ReprobeTargetDevice ( io_service_t controller, SCSITargetIdentifier targetID ) 229{ 230 231 IOReturn result = kIOReturnSuccess; 232 io_iterator_t childIter = MACH_PORT_NULL; 233 io_service_t service = MACH_PORT_NULL; 234 boolean_t found = false; 235 236 // We find the children for the controller and iterate over them looking for the 237 // one which has a targetID which matches. 238 result = IORegistryEntryGetChildIterator ( controller, kIOServicePlane, &childIter ); 239 require ( ( result == kIOReturnSuccess ), ErrorExit ); 240 241 service = IOIteratorNext ( childIter ); 242 while ( service != MACH_PORT_NULL ) 243 { 244 245 // Did we find our device yet? If not, then try to find it. If we have already 246 // found it, we still need to call IOObjectRelease on the io_service_t 247 // or it will have an artificial retain count on it. 248 if ( found == false ) 249 { 250 251 CFMutableDictionaryRef deviceDict = NULL; 252 CFDictionaryRef subDict = NULL; 253 254 // Get the properties for this node from the IORegistry 255 result = IORegistryEntryCreateCFProperties ( service, 256 &deviceDict, 257 kCFAllocatorDefault, 258 0 ); 259 260 // Get the protocol characteristics dictionary 261 subDict = ( CFDictionaryRef ) CFDictionaryGetValue ( deviceDict, CFSTR ( kIOPropertyProtocolCharacteristicsKey ) ); 262 if ( subDict != NULL ) 263 { 264 265 CFNumberRef deviceTargetIDRef = 0; 266 267 // Get the targetID value 268 deviceTargetIDRef = ( CFNumberRef ) CFDictionaryGetValue ( subDict, CFSTR ( kIOPropertySCSITargetIdentifierKey ) ); 269 if ( deviceTargetIDRef != 0 ) 270 { 271 272 UInt64 deviceTargetID = 0; 273 274 // Get the value from the CFNumberRef. 275 if ( CFNumberGetValue ( deviceTargetIDRef, kCFNumberLongLongType, &deviceTargetID ) ) 276 { 277 278 // Does it match? 279 if ( targetID == deviceTargetID ) 280 { 281 282 // Reprobe the device. 283 result = IOServiceRequestProbe ( service, 0 ); 284 found = true; 285 286 } 287 288 } 289 290 } 291 292 } 293 294 if ( deviceDict != NULL ) 295 CFRelease ( deviceDict ); 296 297 } 298 299 IOObjectRelease ( service ); 300 301 service = IOIteratorNext ( childIter ); 302 303 } 304 305 IOObjectRelease ( childIter ); 306 childIter = MACH_PORT_NULL; 307 308 if ( found == false ) 309 result = kIOReturnNoDevice; 310 311 312ErrorExit: 313 314 315 return result; 316 317}