1/* 2 * Copyright (c) 1998-2013 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#ifdef __LP64__ 223 IOStorageAttributes * attributes, 224#endif /* __LP64__ */ 225 UInt64 * actualByteCount) 226{ 227 // 228 // Read data from the storage object at the specified byte offset into the 229 // specified buffer, synchronously. When the read completes, this method 230 // will return to the caller. The actual byte count field is optional. 231 // 232 233 IOStorageCompletion completion; 234 IOStorageSyncer syncer; 235 236 // Fill in the completion information for this request. 237 238 completion.target = &syncer; 239 completion.action = storageCompletion; 240 completion.parameter = actualByteCount; 241 242 // Issue the asynchronous read. 243 244#ifdef __LP64__ 245 read(client, byteStart, buffer, attributes, &completion); 246#else /* !__LP64__ */ 247 read(client, byteStart, buffer, NULL, &completion); 248#endif /* !__LP64__ */ 249 250 // Wait for the read to complete. 251 252 return syncer.wait(); 253} 254 255IOReturn IOStorage::write(IOService * client, 256 UInt64 byteStart, 257 IOMemoryDescriptor * buffer, 258#ifdef __LP64__ 259 IOStorageAttributes * attributes, 260#endif /* __LP64__ */ 261 UInt64 * actualByteCount) 262{ 263 // 264 // Write data into the storage object at the specified byte offset from the 265 // specified buffer, synchronously. When the write completes, this method 266 // will return to the caller. The actual byte count field is optional. 267 // 268 269 IOStorageCompletion completion; 270 IOStorageSyncer syncer; 271 272 // Fill in the completion information for this request. 273 274 completion.target = &syncer; 275 completion.action = storageCompletion; 276 completion.parameter = actualByteCount; 277 278 // Issue the asynchronous write. 279 280#ifdef __LP64__ 281 write(client, byteStart, buffer, attributes, &completion); 282#else /* !__LP64__ */ 283 write(client, byteStart, buffer, NULL, &completion); 284#endif /* !__LP64__ */ 285 286 // Wait for the write to complete. 287 288 return syncer.wait(); 289} 290 291#ifndef __LP64__ 292void IOStorage::read(IOService * client, 293 UInt64 byteStart, 294 IOMemoryDescriptor * buffer, 295 IOStorageCompletion completion) 296{ 297 // 298 // Read data from the storage object at the specified byte offset into the 299 // specified buffer, asynchronously. When the read completes, the caller 300 // will be notified via the specified completion action. 301 // 302 // The buffer will be retained for the duration of the read. 303 // 304 305 if ( IOStorage::_expansionData == kIOStorageAttributesUnsupported ) 306 { 307 read( client, byteStart, buffer, &gIOStorageAttributesUnsupported, &completion ); 308 } 309 else 310 { 311 read( client, byteStart, buffer, NULL, &completion ); 312 } 313} 314 315void IOStorage::write(IOService * client, 316 UInt64 byteStart, 317 IOMemoryDescriptor * buffer, 318 IOStorageCompletion completion) 319{ 320 // 321 // Write data into the storage object at the specified byte offset from the 322 // specified buffer, asynchronously. When the write completes, the caller 323 // will be notified via the specified completion action. 324 // 325 // The buffer will be retained for the duration of the write. 326 // 327 328 if ( IOStorage::_expansionData == kIOStorageAttributesUnsupported ) 329 { 330 write( client, byteStart, buffer, &gIOStorageAttributesUnsupported, &completion ); 331 } 332 else 333 { 334 write( client, byteStart, buffer, NULL, &completion ); 335 } 336} 337 338void IOStorage::read(IOService * client, 339 UInt64 byteStart, 340 IOMemoryDescriptor * buffer, 341 IOStorageAttributes * attributes, 342 IOStorageCompletion * completion) 343{ 344 // 345 // Read data from the storage object at the specified byte offset into the 346 // specified buffer, asynchronously. When the read completes, the caller 347 // will be notified via the specified completion action. 348 // 349 // The buffer will be retained for the duration of the read. 350 // 351 352 if ( attributes && attributes->options ) 353 { 354 complete( completion, kIOReturnUnsupported ); 355 } 356 else 357 { 358 read( client, byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } ); 359 } 360} 361 362void IOStorage::write(IOService * client, 363 UInt64 byteStart, 364 IOMemoryDescriptor * buffer, 365 IOStorageAttributes * attributes, 366 IOStorageCompletion * completion) 367{ 368 // 369 // Write data into the storage object at the specified byte offset from the 370 // specified buffer, asynchronously. When the write completes, the caller 371 // will be notified via the specified completion action. 372 // 373 // The buffer will be retained for the duration of the write. 374 // 375 376 if ( attributes && attributes->options ) 377 { 378 complete( completion, kIOReturnUnsupported ); 379 } 380 else 381 { 382 write( client, byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } ); 383 } 384} 385#endif /* !__LP64__ */ 386 387IOReturn IOStorage::discard(IOService * client, 388 UInt64 byteStart, 389 UInt64 byteCount) 390{ 391 // 392 // Delete unused data from the storage object at the specified byte offset, 393 // synchronously. 394 // 395 396 return kIOReturnUnsupported; 397} 398 399IOReturn IOStorage::unmap(IOService * client, 400 IOStorageExtent * extents, 401 UInt32 extentsCount, 402 UInt32 options) 403{ 404 // 405 // Delete unused data from the storage object at the specified byte offsets, 406 // synchronously. 407 // 408 409 return kIOReturnUnsupported; 410} 411 412bool IOStorage::lockPhysicalExtents(IOService * client) 413{ 414 // 415 // Lock the contents of the storage object against relocation temporarily, 416 // for the purpose of getting physical extents. 417 // 418 419 return false; 420} 421 422IOStorage * IOStorage::copyPhysicalExtent(IOService * client, 423 UInt64 * byteStart, 424 UInt64 * byteCount) 425{ 426 // 427 // Convert the specified byte offset into a physical byte offset, relative 428 // to a physical storage object. This call should only be made within the 429 // context of lockPhysicalExtents(). 430 // 431 432 return NULL; 433} 434 435void IOStorage::unlockPhysicalExtents(IOService * client) 436{ 437 // 438 // Unlock the contents of the storage object for relocation again. This 439 // call must balance a successful call to lockPhysicalExtents(). 440 // 441 442 return; 443} 444 445OSMetaClassDefineReservedUsed(IOStorage, 0); 446OSMetaClassDefineReservedUsed(IOStorage, 1); 447OSMetaClassDefineReservedUsed(IOStorage, 2); 448OSMetaClassDefineReservedUsed(IOStorage, 3); 449#ifdef __LP64__ 450OSMetaClassDefineReservedUnused(IOStorage, 4); 451OSMetaClassDefineReservedUnused(IOStorage, 5); 452OSMetaClassDefineReservedUnused(IOStorage, 6); 453#else /* !__LP64__ */ 454OSMetaClassDefineReservedUsed(IOStorage, 4); 455OSMetaClassDefineReservedUsed(IOStorage, 5); 456OSMetaClassDefineReservedUsed(IOStorage, 6); 457#endif /* !__LP64__ */ 458OSMetaClassDefineReservedUnused(IOStorage, 7); 459OSMetaClassDefineReservedUnused(IOStorage, 8); 460OSMetaClassDefineReservedUnused(IOStorage, 9); 461OSMetaClassDefineReservedUnused(IOStorage, 10); 462OSMetaClassDefineReservedUnused(IOStorage, 11); 463OSMetaClassDefineReservedUnused(IOStorage, 12); 464OSMetaClassDefineReservedUnused(IOStorage, 13); 465OSMetaClassDefineReservedUnused(IOStorage, 14); 466OSMetaClassDefineReservedUnused(IOStorage, 15); 467