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}