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