1/*
2 * Copyright (c) 1998-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//-------------------------------------------------------------------------------------------------
26//	Includes
27//-------------------------------------------------------------------------------------------------
28
29#include <IOKit/IOLib.h>
30#include <IOKit/IOKitKeys.h>
31#include <IOKit/storage/IOBlockStorageDriver.h>
32#include "IOUFIStorageServices.h"
33
34
35//-------------------------------------------------------------------------------------------------
36//	Macros
37//-------------------------------------------------------------------------------------------------
38
39#if ( USB_MASS_STORAGE_DEBUG == 1 )
40#define PANIC_NOW(x)		panic x
41// Override the debug level for USBLog to make sure our logs make it out and then import
42// the logging header.
43#define DEBUG_LEVEL			1
44#include <IOKit/usb/IOUSBLog.h>
45#define STATUS_LOG(x)		USBLog x
46#else
47#define PANIC_NOW(x)
48#define STATUS_LOG(x)
49#endif
50
51// The command should be tried 5 times.  The original attempt
52// plus 4 retries.
53#define kNumberRetries              4
54
55// Default I/O size values.
56enum
57{
58    kMaximumBlockCountRead      = 128,
59    kMaximumBlockCountWrite     = 128,
60    kMaximumByteCountRead       = 65536,
61    kMaximumByteCountWrite      = 65536
62};
63
64// Structure for the asynch client data
65struct BlockServicesClientData
66{
67
68	// The object that owns the copy of this structure.
69	IOUFIStorageServices *		owner;
70
71	// The request parameters provided by the client.
72	IOStorageCompletion			completionData;
73	IOMemoryDescriptor * 		clientBuffer;
74	UInt32 						clientStartingBlock;
75	UInt32 						clientRequestedBlockCount;
76	UInt32 						clientRequestedBlockSize;
77
78	// The internally needed parameters.
79	UInt32						retriesLeft;
80
81};
82
83typedef struct BlockServicesClientData	BlockServicesClientData;
84
85#define super IOBlockStorageDevice
86OSDefineMetaClassAndStructors ( IOUFIStorageServices, IOBlockStorageDevice );
87
88
89//-------------------------------------------------------------------------------------------------
90//	  attach - attach to provider.														[PROTECTED]
91//-------------------------------------------------------------------------------------------------
92
93bool
94IOUFIStorageServices::attach ( IOService * provider )
95{
96
97    OSDictionary * 				scsiCharacterDict 	= NULL;
98
99
100	STATUS_LOG ( ( 6, "%s[%p]:: attach called", getName(), this ) );
101
102	if ( !super::attach ( provider ) )
103	{
104		return false;
105	}
106
107	fProvider = OSDynamicCast ( IOUSBMassStorageUFIDevice, provider );
108	if ( fProvider == NULL )
109	{
110
111		STATUS_LOG ( ( 1, "%s[%p]:: attach; wrong provider type!", getName(), this ) );
112		return false;
113
114	}
115
116	setProperty ( kIOPropertyProtocolCharacteristicsKey, fProvider->GetProtocolCharacteristicsDictionary ( ) );
117	setProperty ( kIOPropertyDeviceCharacteristicsKey, fProvider->GetDeviceCharacteristicsDictionary ( ) );
118
119    // Check for a SCSI Device Characteristics dictionary, if not present, set default values.
120    scsiCharacterDict = OSDynamicCast ( OSDictionary, fProvider->getProperty( kIOPropertySCSIDeviceCharacteristicsKey ) );
121    if ( scsiCharacterDict == NULL )
122    {
123
124        setProperty ( kIOMaximumBlockCountReadKey, kMaximumBlockCountRead );
125        setProperty ( kIOMaximumBlockCountWriteKey, kMaximumBlockCountWrite );
126        setProperty ( kIOMaximumByteCountReadKey, kMaximumByteCountRead );
127        setProperty ( kIOMaximumByteCountWriteKey, kMaximumByteCountWrite );
128
129    }
130    else
131    {
132
133        OSNumber    *	number			= NULL;
134        UInt32          maxBlockCount   = 0;
135        UInt64          maxByteCount    = 0;
136
137
138        // Set a max block read count, favor SCSI Characteristics property if present.
139        maxBlockCount = kMaximumBlockCountRead;
140        number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumBlockCountReadKey ) );
141        if ( number != NULL )
142        {
143
144            maxBlockCount = number->unsigned32BitValue ( );
145            if ( maxBlockCount == 0 )
146            {
147                maxBlockCount = kMaximumBlockCountRead;
148            }
149
150        }
151
152        setProperty ( kIOMaximumBlockCountReadKey, maxBlockCount );
153
154        // Set a max block write count, favor SCSI Characteristics property if present.
155        maxBlockCount = kMaximumBlockCountWrite;
156        number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumBlockCountWriteKey ) );
157        if ( number != NULL )
158        {
159
160            maxBlockCount = number->unsigned32BitValue ( );
161            if ( maxBlockCount == 0 )
162            {
163                maxBlockCount = kMaximumBlockCountWrite;
164            }
165
166        }
167
168        setProperty ( kIOMaximumBlockCountWriteKey, maxBlockCount );
169
170        // Set a max byte read count, favor SCSI Characteristics property if present.
171        maxByteCount = kMaximumByteCountRead;
172        number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumByteCountReadKey ) );
173        if ( number != NULL )
174        {
175
176            maxByteCount = number->unsigned32BitValue ( );
177            if ( maxByteCount == 0 )
178            {
179                maxByteCount = kMaximumByteCountRead;
180            }
181
182        }
183
184        setProperty ( kIOMaximumByteCountReadKey, maxByteCount );
185
186        // Set a max byte write count, favor SCSI Characteristics property if present.
187        maxByteCount = kMaximumByteCountWrite;
188        number = OSDynamicCast ( OSNumber, scsiCharacterDict->getObject ( kIOMaximumByteCountWriteKey ) );
189        if ( number != NULL )
190        {
191
192            maxByteCount = number->unsigned32BitValue ( );
193            if ( maxByteCount == 0 )
194            {
195                maxByteCount = kMaximumByteCountWrite;
196            }
197
198        }
199
200        setProperty ( kIOMaximumByteCountWriteKey, maxByteCount );
201
202    }
203
204	fMediaChanged			= false;
205	fMediaPresent			= false;
206
207	STATUS_LOG ( ( 6, "%s[%p]:: attach exiting", getName(), this ) );
208
209	return true;
210
211}
212
213
214//-------------------------------------------------------------------------------------------------
215//	  detach - detach from provider.													[PROTECTED]
216//-------------------------------------------------------------------------------------------------
217
218void
219IOUFIStorageServices::detach( IOService * provider )
220{
221
222	STATUS_LOG ( ( 6, "%s[%p]: detach called", getName(), this ) );
223
224	super::detach( provider );
225
226	STATUS_LOG ( ( 6, "%s[%p]: detach exiting", getName(), this ) );
227
228}
229
230
231//-------------------------------------------------------------------------------------------------
232//	  message - handles messages.									   					   [PUBLIC]
233//-------------------------------------------------------------------------------------------------
234
235IOReturn
236IOUFIStorageServices::message( 	UInt32 			type,
237								IOService *		nub,
238								void *			arg )
239{
240
241	IOReturn 	status = kIOReturnSuccess;
242
243
244	STATUS_LOG ( ( 6, "%s[%p]::message called", getName(), this ) );
245
246	switch ( type )
247	{
248
249		case kIOMessageMediaStateHasChanged:
250		{
251
252			STATUS_LOG ( ( 5, "%s[%p]:: type = kIOMessageMediaStateHasChanged, nub = %p", getName(), this, nub ) );
253
254			fMediaChanged	= true;
255			fMediaPresent	= true;
256			status = messageClients ( type, arg, sizeof ( IOMediaState ) );
257			STATUS_LOG ( ( 5, "%s[%p]:: status = %ld", getName(), this, ( UInt32 ) status ) );
258
259		}
260		break;
261
262		default:
263		{
264			status = super::message ( type, nub, arg );
265		}
266		break;
267
268	}
269
270	return status;
271
272}
273
274
275//-------------------------------------------------------------------------------------------------
276//	  AsyncReadWriteComplete - Completion routine for I/O	  					   [STATIC][PRIVATE]
277//-------------------------------------------------------------------------------------------------
278
279void
280IOUFIStorageServices::AsyncReadWriteComplete (	void * 			clientData,
281												IOReturn		status,
282												UInt64 			actualByteCount )
283{
284
285	IOUFIStorageServices *		owner;
286	BlockServicesClientData * 	servicesData;
287	IOStorageCompletion			returnData;
288	bool						commandComplete = true;
289
290
291	// Save the IOCompletion information so that it may be returned
292	// to the client.
293	servicesData 	= ( BlockServicesClientData * ) clientData;
294	returnData 		= servicesData->completionData;
295	owner 			= servicesData->owner;
296
297	STATUS_LOG ( ( 5, "%s[%p]:: AsyncReadWriteComplete; command status %x", owner->getName(), owner, status ) );
298	// Check to see if an error occurred that on which the request should be retried.
299	if ( ( ( status != kIOReturnNotAttached ) && ( status != kIOReturnOffline ) &&
300		( status != kIOReturnSuccess ) ) && ( servicesData->retriesLeft > 0 ) )
301	{
302
303		IOReturn 	requestStatus;
304
305		STATUS_LOG ( (5, "%s[%p]:: AsyncReadWriteComplete; retry command", owner->getName(), owner ) );
306		// An error occurred, but it is one on which the command should be retried.  Decrement
307		// the retry counter and try again.
308		servicesData->retriesLeft--;
309		requestStatus = owner->fProvider->AsyncReadWrite (
310										servicesData->clientBuffer,
311										servicesData->clientStartingBlock,
312										servicesData->clientRequestedBlockCount,
313										servicesData->clientRequestedBlockSize,
314										clientData );
315		if ( requestStatus != kIOReturnSuccess )
316		{
317			commandComplete = true;
318		}
319		else
320		{
321			commandComplete = false;
322		}
323
324	}
325
326	if ( commandComplete == true )
327	{
328
329		IOFree ( clientData, sizeof ( BlockServicesClientData ) );
330
331		// Release the retains for this command.
332		owner->fProvider->release();
333		owner->release();
334
335		IOStorage::complete ( &returnData, status, actualByteCount );
336
337	}
338}
339
340
341// Deprecated !!!
342//--------------------------------------------------------------------------------------------------
343//	doAsyncReadWrite                                                                        [PUBLIC]
344//--------------------------------------------------------------------------------------------------
345
346IOReturn
347IOUFIStorageServices::doAsyncReadWrite (	IOMemoryDescriptor *	buffer,
348											UInt32					block,
349											UInt32					nblks,
350											IOStorageCompletion		completion )
351{
352
353	UNUSED ( buffer );
354    UNUSED ( block );
355    UNUSED ( nblks );
356    UNUSED ( completion );
357
358
359	return kIOReturnUnsupported;
360
361}
362
363
364//--------------------------------------------------------------------------------------------------
365//	doAsyncReadWrite                                                                        [PUBLIC]
366//--------------------------------------------------------------------------------------------------
367
368
369IOReturn
370IOUFIStorageServices::doAsyncReadWrite (    IOMemoryDescriptor *    buffer,
371                                            UInt64                  block,
372                                            UInt64                  nblks,
373                                            IOStorageAttributes *   attributes,
374                                            IOStorageCompletion *   completion )
375{
376	BlockServicesClientData	*	clientData;
377	IODirection					direction;
378	IOReturn					requestStatus;
379	UInt32						requestBlockSize;
380
381
382    UNUSED ( attributes );
383
384	// Return errors for incoming I/O if we have been terminated.
385	if ( isInactive() != false )
386	{
387		return kIOReturnNotAttached;
388	}
389
390	direction = buffer->getDirection();
391	if ( ( direction != kIODirectionIn ) && ( direction != kIODirectionOut ) )
392	{
393		// This is neither a read nor write request (since this is a read/write method,
394		// what kind of request is it?) return an error to the client.
395		return kIOReturnBadArgument;
396	}
397
398	clientData = ( BlockServicesClientData * ) IOMalloc ( sizeof( BlockServicesClientData ) );
399	if ( clientData == NULL )
400	{
401		STATUS_LOG ( ( 1, "%s[%p]:: doAsyncReadWrite; clientData malloc failed!", getName(), this ) );
402		return kIOReturnNoResources;
403	}
404
405	// Make sure we don't go away while the command is being executed.
406	retain();
407	fProvider->retain();
408
409	requestBlockSize = fProvider->ReportMediumBlockSize();
410
411	STATUS_LOG ( ( 5, "%s[%p]:: doAsyncReadWrite; save completion data!", getName(), this ) );
412
413	// Set the owner of this request.
414	clientData->owner = this;
415
416	// Save the client's request parameters.
417	clientData->completionData 				= *completion;
418	clientData->clientBuffer 				= buffer;
419	clientData->clientStartingBlock 		= block;
420	clientData->clientRequestedBlockCount 	= nblks;
421	clientData->clientRequestedBlockSize 	= requestBlockSize;
422
423	// Set the retry limit to the maximum
424	clientData->retriesLeft = kNumberRetries;
425
426	requestStatus = fProvider->AsyncReadWrite ( buffer, block, nblks, ( UInt64 ) requestBlockSize, ( void * ) clientData );
427	if ( requestStatus != kIOReturnSuccess )
428	{
429		if ( clientData != NULL )
430		{
431			IOFree ( clientData, sizeof ( BlockServicesClientData ) );
432		}
433	}
434
435	return requestStatus;
436}
437
438
439//-------------------------------------------------------------------------------------------------
440//	  doSyncReadWrite																		[PUBLIC]
441//-------------------------------------------------------------------------------------------------
442
443IOReturn
444IOUFIStorageServices::doSyncReadWrite (		IOMemoryDescriptor * 	buffer,
445											UInt32 					block,
446											UInt32 					nblks )
447{
448
449	IOReturn	result;
450
451	// Return errors for incoming I/O if we have been terminated
452	if ( isInactive() != false )
453	{
454		return kIOReturnNotAttached;
455	}
456
457	// Make sure we don't go away while the command in being executed.
458	retain();
459	fProvider->retain();
460
461	// Execute the command
462	result = fProvider->SyncReadWrite( buffer, block, nblks, fProvider->ReportMediumBlockSize() );
463
464	// Release the retains for this command.
465	fProvider->release();
466	release();
467
468	return result;
469
470}
471
472
473//--------------------------------------------------------------------------------------------------
474//	  doEjectMedia																			[PUBLIC]
475//--------------------------------------------------------------------------------------------------
476
477IOReturn
478IOUFIStorageServices::doEjectMedia ( void )
479{
480
481	IOReturn	result;
482
483
484	fMediaPresent = false;
485
486	// Return errors for incoming activity if we have been terminated
487	if ( isInactive() != false )
488	{
489		return kIOReturnNotAttached;
490	}
491
492	// Make sure we don't go away while the command in being executed.
493	retain();
494	fProvider->retain();
495
496	// Execute the command
497	result = fProvider->EjectTheMedium();
498
499	// Release the retains for this command.
500	fProvider->release();
501	release();
502
503	return result;
504
505}
506
507
508//--------------------------------------------------------------------------------------------------
509//	  doFormatMedia																			[PUBLIC]
510//--------------------------------------------------------------------------------------------------
511
512IOReturn
513IOUFIStorageServices::doFormatMedia ( UInt64 byteCapacity )
514{
515
516	IOReturn result;
517
518
519	// Return errors for incoming activity if we have been terminated
520	if ( isInactive() != false )
521	{
522		return kIOReturnNotAttached;
523	}
524
525	// Make sure we don't go away while the command in being executed.
526	retain();
527	fProvider->retain();
528
529	// Execute the command
530	result = fProvider->FormatMedium( byteCapacity / ( fProvider->ReportMediumBlockSize() ),
531									   fProvider->ReportMediumBlockSize() );
532
533	// Release the retains for this command.
534	fProvider->release();
535	release();
536
537	return result;
538
539}
540
541
542//--------------------------------------------------------------------------------------------------
543//	  doGetFormatCapacities																	[PUBLIC]
544//--------------------------------------------------------------------------------------------------
545
546UInt32
547IOUFIStorageServices::doGetFormatCapacities (	UInt64 * capacities,
548												UInt32   capacitiesMaxCount ) const
549{
550
551	IOReturn result;
552
553	// Return errors for incoming activity if we have been terminated
554	if ( isInactive() != false )
555	{
556		return kIOReturnNotAttached;
557	}
558
559	// Make sure we don't go away while the command in being executed.
560	retain();
561	fProvider->retain();
562
563	// Execute the command
564	result = fProvider->GetFormatCapacities ( capacities, capacitiesMaxCount );
565
566	// Release the retains for this command.
567	fProvider->release();
568	release();
569
570	return result;
571
572}
573
574
575//--------------------------------------------------------------------------------------------------
576//	  doSynchronizeCache																	[PUBLIC]
577//--------------------------------------------------------------------------------------------------
578
579IOReturn
580IOUFIStorageServices::doSynchronizeCache ( void )
581{
582
583	// Return errors for incoming activity if we have been terminated
584	if ( isInactive() != false )
585	{
586		return kIOReturnNotAttached;
587	}
588
589	return kIOReturnSuccess;
590
591}
592
593
594//--------------------------------------------------------------------------------------------------
595//	  getVendorString																		[PUBLIC]
596//--------------------------------------------------------------------------------------------------
597
598char *
599IOUFIStorageServices::getVendorString ( void )
600{
601	return fProvider->GetVendorString ( );
602}
603
604
605//--------------------------------------------------------------------------------------------------
606//	  getProductString																		[PUBLIC]
607//--------------------------------------------------------------------------------------------------
608
609char *
610IOUFIStorageServices::getProductString ( void )
611{
612	return fProvider->GetProductString ( );
613}
614
615
616//--------------------------------------------------------------------------------------------------
617//	  getRevisionString																		[PUBLIC]
618//--------------------------------------------------------------------------------------------------
619
620char *
621IOUFIStorageServices::getRevisionString ( void )
622{
623	return fProvider->GetRevisionString ( );
624}
625
626
627//--------------------------------------------------------------------------------------------------
628//	  getAdditionalDeviceInfoString															[PUBLIC]
629//--------------------------------------------------------------------------------------------------
630
631char *
632IOUFIStorageServices::getAdditionalDeviceInfoString ( void )
633{
634
635	STATUS_LOG ( (6, "%s::%s called", getName ( ), __FUNCTION__ ) );
636	return ( ( char * ) "No Additional Device Info" );
637
638}
639
640
641//--------------------------------------------------------------------------------------------------
642//	  reportBlockSize																		[PUBLIC]
643//--------------------------------------------------------------------------------------------------
644
645IOReturn
646IOUFIStorageServices::reportBlockSize ( UInt64 * blockSize )
647{
648
649	*blockSize = fProvider->ReportMediumBlockSize ( );
650	return kIOReturnSuccess;
651
652}
653
654
655//--------------------------------------------------------------------------------------------------
656//	  reportEjectability																	[PUBLIC]
657//--------------------------------------------------------------------------------------------------
658
659IOReturn
660IOUFIStorageServices::reportEjectability ( bool * isEjectable )
661{
662
663	*isEjectable = true;
664	return kIOReturnSuccess;
665
666}
667
668
669//--------------------------------------------------------------------------------------------------
670//	  reportMaxValidBlock																	[PUBLIC]
671//--------------------------------------------------------------------------------------------------
672
673IOReturn
674IOUFIStorageServices::reportMaxValidBlock ( UInt64 * maxBlock )
675{
676
677	*maxBlock = ( fProvider->ReportMediumTotalBlockCount ( ) - 1 );
678	return kIOReturnSuccess;
679
680}
681
682
683//--------------------------------------------------------------------------------------------------
684//	  reportMediaState																		[PUBLIC]
685//--------------------------------------------------------------------------------------------------
686
687IOReturn
688IOUFIStorageServices::reportMediaState ( 	bool * mediaPresent,
689											bool * changed )
690{
691
692    STATUS_LOG ( ( 6, "%s[%p]::reportMediaState.", getName(), this ) );
693
694	*mediaPresent 	= fMediaPresent;
695	*changed 		= fMediaChanged;
696
697	if ( fMediaChanged )
698	{
699		fMediaChanged = !fMediaChanged;
700	}
701
702	return kIOReturnSuccess;
703
704}
705
706
707//--------------------------------------------------------------------------------------------------
708//	  reportRemovability																	[PUBLIC]
709//--------------------------------------------------------------------------------------------------
710
711IOReturn
712IOUFIStorageServices::reportRemovability ( bool * isRemovable )
713{
714
715	*isRemovable = true;
716	return kIOReturnSuccess;
717
718}
719
720
721//--------------------------------------------------------------------------------------------------
722//	  reportWriteProtection																	[PUBLIC]
723//--------------------------------------------------------------------------------------------------
724
725IOReturn
726IOUFIStorageServices::reportWriteProtection ( bool * isWriteProtected )
727{
728
729	*isWriteProtected = fProvider->ReportMediumWriteProtection();
730	return kIOReturnSuccess;
731
732}
733
734
735//--------------------------------------------------------------------------------------------------
736//	getWriteCacheState                                                                      [PUBLIC]
737//--------------------------------------------------------------------------------------------------
738
739IOReturn
740IOUFIStorageServices::getWriteCacheState ( bool * enabled )
741{
742
743    UNUSED ( enabled );
744
745    return ( kIOReturnUnsupported );
746
747}
748
749
750//--------------------------------------------------------------------------------------------------
751//	setWriteCacheState                                                                      [PUBLIC]
752//--------------------------------------------------------------------------------------------------
753
754IOReturn
755IOUFIStorageServices::setWriteCacheState ( bool enabled )
756{
757
758    UNUSED ( enabled );
759
760    return ( kIOReturnUnsupported );
761
762}
763
764
765// Space reserved for future expansion.
766OSMetaClassDefineReservedUnused( IOUFIStorageServices, 1 );
767OSMetaClassDefineReservedUnused( IOUFIStorageServices, 2 );
768OSMetaClassDefineReservedUnused( IOUFIStorageServices, 3 );
769OSMetaClassDefineReservedUnused( IOUFIStorageServices, 4 );
770OSMetaClassDefineReservedUnused( IOUFIStorageServices, 5 );
771OSMetaClassDefineReservedUnused( IOUFIStorageServices, 6 );
772OSMetaClassDefineReservedUnused( IOUFIStorageServices, 7 );
773OSMetaClassDefineReservedUnused( IOUFIStorageServices, 8 );
774
775//--------------------------------------------------------------------------------------------------
776//							End				Of				File
777//--------------------------------------------------------------------------------------------------
778