1/* 2 * Copyright (c) 1998-2014 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#include <IOKit/assert.h> 25#include <IOKit/IOLib.h> 26#include <IOKit/storage/IOStorage.h> 27 28#define super IOService 29OSDefineMetaClassAndAbstractStructors(IOStorage, IOService) 30 31#ifndef __LP64__ 32#define kIOStorageAttributesUnsupported ( ( IOStorage::ExpansionData * ) 1 ) 33 34IOStorageAttributes gIOStorageAttributesUnsupported = { kIOStorageOptionReserved }; 35 36extern "C" void _ZN9IOStorage4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOStorage *, IOService *, UInt64, IOMemoryDescriptor *, IOStorageCompletion ); 37extern "C" void _ZN9IOStorage5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOStorage *, IOService *, UInt64, IOMemoryDescriptor *, IOStorageCompletion ); 38extern "C" void _ZN9IOStorage4readEP9IOServiceyP18IOMemoryDescriptorP19IOStorageAttributesP19IOStorageCompletion( IOStorage *, IOService *, UInt64, IOMemoryDescriptor *, IOStorageAttributes *, IOStorageCompletion * ); 39extern "C" void _ZN9IOStorage5writeEP9IOServiceyP18IOMemoryDescriptorP19IOStorageAttributesP19IOStorageCompletion( IOStorage *, IOService *, UInt64, IOMemoryDescriptor *, IOStorageAttributes *, IOStorageCompletion * ); 40 41#define storageAttributes( storage ) ( ( OSMemberFunctionCast( void *, storage, ( void ( IOStorage::* )( IOService *, UInt64, IOMemoryDescriptor *, IOStorageCompletion ) ) &IOStorage::read ) == _ZN9IOStorage4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion ) && \ 42 ( OSMemberFunctionCast( void *, storage, ( void ( IOStorage::* )( IOService *, UInt64, IOMemoryDescriptor *, IOStorageCompletion ) ) &IOStorage::write ) == _ZN9IOStorage5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion ) && \ 43 ( OSMemberFunctionCast( void *, storage, ( void ( IOStorage::* )( IOService *, UInt64, IOMemoryDescriptor *, IOStorageAttributes *, IOStorageCompletion * ) ) &IOStorage::read ) != _ZN9IOStorage4readEP9IOServiceyP18IOMemoryDescriptorP19IOStorageAttributesP19IOStorageCompletion ) && \ 44 ( OSMemberFunctionCast( void *, storage, ( void ( IOStorage::* )( IOService *, UInt64, IOMemoryDescriptor *, IOStorageAttributes *, IOStorageCompletion * ) ) &IOStorage::write ) != _ZN9IOStorage5writeEP9IOServiceyP18IOMemoryDescriptorP19IOStorageAttributesP19IOStorageCompletion ) ) 45#endif /* !__LP64__ */ 46 47class IOStorageSyncerLock 48{ 49protected: 50 51 IOLock * _lock; 52 53public: 54 55 inline IOStorageSyncerLock( ) 56 { 57 _lock = IOLockAlloc( ); 58 } 59 60 inline ~IOStorageSyncerLock( ) 61 { 62 if ( _lock ) IOLockFree( _lock ); 63 } 64 65 inline void lock( ) 66 { 67 IOLockLock( _lock ); 68 } 69 70 inline void unlock( ) 71 { 72 IOLockUnlock( _lock ); 73 } 74 75 inline void sleep( void * event ) 76 { 77 IOLockSleep( _lock, event, THREAD_UNINT ); 78 } 79 80 inline void wakeup( void * event ) 81 { 82 IOLockWakeup( _lock, event, false ); 83 } 84}; 85 86static IOStorageSyncerLock gIOStorageSyncerLock; 87 88class IOStorageSyncer 89{ 90protected: 91 92 IOReturn _status; 93 bool _wakeup; 94 95public: 96 97 IOStorageSyncer( ) 98 { 99 _wakeup = false; 100 } 101 102 IOReturn wait( ) 103 { 104 gIOStorageSyncerLock.lock( ); 105 106 while ( _wakeup == false ) 107 { 108 gIOStorageSyncerLock.sleep( this ); 109 } 110 111 gIOStorageSyncerLock.unlock( ); 112 113 return _status; 114 } 115 116 void signal( IOReturn status ) 117 { 118 _status = status; 119 120 gIOStorageSyncerLock.lock( ); 121 122 _wakeup = true; 123 124 gIOStorageSyncerLock.wakeup( this ); 125 126 gIOStorageSyncerLock.unlock( ); 127 } 128}; 129 130static void storageCompletion(void * target, 131 void * parameter, 132 IOReturn status, 133 UInt64 actualByteCount) 134{ 135 // 136 // Internal completion routine for synchronous versions of read and write. 137 // 138 139 if (parameter) *((UInt64 *)parameter) = actualByteCount; 140 ((IOStorageSyncer *)target)->signal(status); 141} 142 143#ifndef __LP64__ 144bool IOStorage::init(OSDictionary * properties) 145{ 146 // 147 // Initialize this object's minimal state. 148 // 149 150 if ( super::init( properties ) == false ) 151 { 152 return false; 153 } 154 155 if ( storageAttributes( this ) == false ) 156 { 157 IOStorage::_expansionData = kIOStorageAttributesUnsupported; 158 } 159 160 if ( IOStorage::_expansionData ) 161 { 162 OSDictionary * features; 163 164 features = OSDictionary::withCapacity( 1 ); 165 166 if ( features ) 167 { 168 setProperty( kIOStorageFeaturesKey, features ); 169 170 features->release( ); 171 } 172 } 173 174 return true; 175} 176 177void IOStorage::complete(IOStorageCompletion completion, 178 IOReturn status, 179 UInt64 actualByteCount) 180{ 181 // 182 // Invokes the specified completion action of the read/write request. If 183 // the completion action is unspecified, no action is taken. This method 184 // serves simply as a convenience to storage subclass developers. 185 // 186 187 complete( &completion, status, actualByteCount ); 188} 189#endif /* !__LP64__ */ 190 191void IOStorage::complete(IOStorageCompletion * completion, 192 IOReturn status, 193 UInt64 actualByteCount) 194{ 195 // 196 // Invokes the specified completion action of the read/write request. If 197 // the completion action is unspecified, no action is taken. This method 198 // serves simply as a convenience to storage subclass developers. 199 // 200 201 if ( completion && completion->action ) 202 { 203 ( completion->action )( completion->target, completion->parameter, status, actualByteCount ); 204 } 205} 206 207bool IOStorage::open(IOService * client, 208 IOOptionBits options, 209 IOStorageAccess access) 210{ 211 // 212 // Ask the storage object for permission to access its contents; the method 213 // is equivalent to IOService::open(), but with the correct parameter types. 214 // 215 216 return super::open(client, options, (void *) (uintptr_t) access); 217} 218 219IOReturn IOStorage::read(IOService * client, 220 UInt64 byteStart, 221 IOMemoryDescriptor * buffer, 222 IOStorageAttributes * attributes, 223 UInt64 * actualByteCount) 224{ 225 // 226 // Read data from the storage object at the specified byte offset into the 227 // specified buffer, synchronously. When the read completes, this method 228 // will return to the caller. The actual byte count field is optional. 229 // 230 231 IOStorageCompletion completion; 232 IOStorageSyncer syncer; 233 234 // Fill in the completion information for this request. 235 236 completion.target = &syncer; 237 completion.action = storageCompletion; 238 completion.parameter = actualByteCount; 239 240 // Issue the asynchronous read. 241 242 read(client, byteStart, buffer, attributes, &completion); 243 244 // Wait for the read to complete. 245 246 return syncer.wait(); 247} 248 249IOReturn IOStorage::write(IOService * client, 250 UInt64 byteStart, 251 IOMemoryDescriptor * buffer, 252 IOStorageAttributes * attributes, 253 UInt64 * actualByteCount) 254{ 255 // 256 // Write data into the storage object at the specified byte offset from the 257 // specified buffer, synchronously. When the write completes, this method 258 // will return to the caller. The actual byte count field is optional. 259 // 260 261 IOStorageCompletion completion; 262 IOStorageSyncer syncer; 263 264 // Fill in the completion information for this request. 265 266 completion.target = &syncer; 267 completion.action = storageCompletion; 268 completion.parameter = actualByteCount; 269 270 // Issue the asynchronous write. 271 272 write(client, byteStart, buffer, attributes, &completion); 273 274 // Wait for the write to complete. 275 276 return syncer.wait(); 277} 278 279#ifndef __LP64__ 280void IOStorage::read(IOService * client, 281 UInt64 byteStart, 282 IOMemoryDescriptor * buffer, 283 IOStorageCompletion completion) 284{ 285 // 286 // Read data from the storage object at the specified byte offset into the 287 // specified buffer, asynchronously. When the read completes, the caller 288 // will be notified via the specified completion action. 289 // 290 // The buffer will be retained for the duration of the read. 291 // 292 293 if ( IOStorage::_expansionData == kIOStorageAttributesUnsupported ) 294 { 295 read( client, byteStart, buffer, &gIOStorageAttributesUnsupported, &completion ); 296 } 297 else 298 { 299 read( client, byteStart, buffer, NULL, &completion ); 300 } 301} 302 303void IOStorage::write(IOService * client, 304 UInt64 byteStart, 305 IOMemoryDescriptor * buffer, 306 IOStorageCompletion completion) 307{ 308 // 309 // Write data into the storage object at the specified byte offset from the 310 // specified buffer, asynchronously. When the write completes, the caller 311 // will be notified via the specified completion action. 312 // 313 // The buffer will be retained for the duration of the write. 314 // 315 316 if ( IOStorage::_expansionData == kIOStorageAttributesUnsupported ) 317 { 318 write( client, byteStart, buffer, &gIOStorageAttributesUnsupported, &completion ); 319 } 320 else 321 { 322 write( client, byteStart, buffer, NULL, &completion ); 323 } 324} 325 326void IOStorage::read(IOService * client, 327 UInt64 byteStart, 328 IOMemoryDescriptor * buffer, 329 IOStorageAttributes * attributes, 330 IOStorageCompletion * completion) 331{ 332 // 333 // Read data from the storage object at the specified byte offset into the 334 // specified buffer, asynchronously. When the read completes, the caller 335 // will be notified via the specified completion action. 336 // 337 // The buffer will be retained for the duration of the read. 338 // 339 340 if ( attributes && attributes->options ) 341 { 342 complete( completion, kIOReturnUnsupported ); 343 } 344 else 345 { 346 read( client, byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } ); 347 } 348} 349 350void IOStorage::write(IOService * client, 351 UInt64 byteStart, 352 IOMemoryDescriptor * buffer, 353 IOStorageAttributes * attributes, 354 IOStorageCompletion * completion) 355{ 356 // 357 // Write data into the storage object at the specified byte offset from the 358 // specified buffer, asynchronously. When the write completes, the caller 359 // will be notified via the specified completion action. 360 // 361 // The buffer will be retained for the duration of the write. 362 // 363 364 if ( attributes && attributes->options ) 365 { 366 complete( completion, kIOReturnUnsupported ); 367 } 368 else 369 { 370 write( client, byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } ); 371 } 372} 373#endif /* !__LP64__ */ 374 375IOReturn IOStorage::discard(IOService * client, 376 UInt64 byteStart, 377 UInt64 byteCount) 378{ 379 // 380 // Delete unused data from the storage object at the specified byte offset, 381 // synchronously. 382 // 383 384 return kIOReturnUnsupported; 385} 386 387IOReturn IOStorage::unmap(IOService * client, 388 IOStorageExtent * extents, 389 UInt32 extentsCount, 390 UInt32 options) 391{ 392 // 393 // Delete unused data from the storage object at the specified byte offsets, 394 // synchronously. 395 // 396 397 return kIOReturnUnsupported; 398} 399 400bool IOStorage::lockPhysicalExtents(IOService * client) 401{ 402 // 403 // Lock the contents of the storage object against relocation temporarily, 404 // for the purpose of getting physical extents. 405 // 406 407 return false; 408} 409 410IOStorage * IOStorage::copyPhysicalExtent(IOService * client, 411 UInt64 * byteStart, 412 UInt64 * byteCount) 413{ 414 // 415 // Convert the specified byte offset into a physical byte offset, relative 416 // to a physical storage object. This call should only be made within the 417 // context of lockPhysicalExtents(). 418 // 419 420 return NULL; 421} 422 423void IOStorage::unlockPhysicalExtents(IOService * client) 424{ 425 // 426 // Unlock the contents of the storage object for relocation again. This 427 // call must balance a successful call to lockPhysicalExtents(). 428 // 429 430 return; 431} 432 433IOReturn IOStorage::setPriority(IOService * client, 434 IOStorageExtent * extents, 435 UInt32 extentsCount, 436 IOStoragePriority priority) 437 438{ 439 // 440 // Reprioritize read or write requests at the specified byte offsets. 441 // 442 443 return kIOReturnUnsupported; 444} 445 446OSMetaClassDefineReservedUsed(IOStorage, 0); 447OSMetaClassDefineReservedUsed(IOStorage, 1); 448OSMetaClassDefineReservedUsed(IOStorage, 2); 449OSMetaClassDefineReservedUsed(IOStorage, 3); 450OSMetaClassDefineReservedUsed(IOStorage, 4); 451#ifdef __LP64__ 452OSMetaClassDefineReservedUnused(IOStorage, 5); 453OSMetaClassDefineReservedUnused(IOStorage, 6); 454OSMetaClassDefineReservedUnused(IOStorage, 7); 455#else /* !__LP64__ */ 456OSMetaClassDefineReservedUsed(IOStorage, 5); 457OSMetaClassDefineReservedUsed(IOStorage, 6); 458OSMetaClassDefineReservedUsed(IOStorage, 7); 459#endif /* !__LP64__ */ 460OSMetaClassDefineReservedUnused(IOStorage, 8); 461OSMetaClassDefineReservedUnused(IOStorage, 9); 462OSMetaClassDefineReservedUnused(IOStorage, 10); 463OSMetaClassDefineReservedUnused(IOStorage, 11); 464OSMetaClassDefineReservedUnused(IOStorage, 12); 465OSMetaClassDefineReservedUnused(IOStorage, 13); 466OSMetaClassDefineReservedUnused(IOStorage, 14); 467OSMetaClassDefineReservedUnused(IOStorage, 15); 468