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