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/IODeviceTreeSupport.h>
26#include <IOKit/IOKitKeys.h>
27#include <IOKit/IOLib.h>
28#include <IOKit/IOMapper.h>
29#include <IOKit/IOMemoryDescriptor.h>
30#include <IOKit/IOSubMemoryDescriptor.h>
31#include <IOKit/pwr_mgt/RootDomain.h>
32#include <IOKit/storage/IOBlockStorageDevice.h>
33#include <IOKit/storage/IOBlockStorageDriver.h>
34#include <IOKit/storage/IOMedia.h>
35#include <kern/energy_perf.h>
36#include <kern/thread_call.h>
37///w:start
38#if TARGET_OS_EMBEDDED
39#include <sys/disk.h>
40#endif /* TARGET_OS_EMBEDDED */
41///w:stop
42
43#define super IOStorage
44OSDefineMetaClassAndStructors(IOBlockStorageDriver, IOStorage)
45
46#ifdef __LP64__
47#define original request
48#else /* !__LP64__ */
49#define isMediaRemovable() _removable
50#endif /* !__LP64__ */
51
52#ifndef __LP64__
53#define kIOBlockStorageDriverAttributesUnsupported ( ( IOStorage::ExpansionData * ) 2 )
54
55extern IOStorageAttributes gIOStorageAttributesUnsupported;
56
57extern "C" void _ZN20IOBlockStorageDriver14prepareRequestEyP18IOMemoryDescriptor19IOStorageCompletion( IOBlockStorageDriver *, UInt64, IOMemoryDescriptor *, IOStorageCompletion );
58
59#define prepareRequestAttributes( driver ) ( OSMemberFunctionCast( void *, driver, ( void ( IOBlockStorageDriver::* )( UInt64, IOMemoryDescriptor *, IOStorageCompletion ) ) &IOBlockStorageDriver::prepareRequest ) == _ZN20IOBlockStorageDriver14prepareRequestEyP18IOMemoryDescriptor19IOStorageCompletion )
60#endif /* !__LP64__ */
61
62static char * strclean(char * s)
63{
64    //
65    // strclean() trims any spaces at either end of the string, strips any
66    // control characters within the string, and collapses any sequence of
67    // spaces within the string into a single space.
68    //
69
70    int sourceIndex = 0, targetIndex = 0, targetLength = 0;
71
72    for ( ; s[sourceIndex] > '\0' && s[sourceIndex] <= ' '; sourceIndex++ );
73
74    for ( ; s[sourceIndex]; sourceIndex++ )
75    {
76        if ( s[sourceIndex] < '\0' || s[sourceIndex] >= ' ' )
77        {
78            if ( s[sourceIndex] != ' ' )
79            {
80                if ( targetLength < targetIndex )
81                {
82                    targetIndex = targetLength + 1;
83                }
84
85                targetLength = targetIndex + 1;
86            }
87
88            s[targetIndex++] = s[sourceIndex];
89        }
90    }
91
92    s[targetLength] = '\0';
93
94    return s;
95}
96
97IOBlockStorageDevice * IOBlockStorageDriver::getProvider() const
98{
99    //
100    // Obtain this object's provider.  We override the superclass's method to
101    // return a more specific subclass of IOService -- IOBlockStorageDevice.
102    // This method serves simply as a convenience to subclass developers.
103    //
104
105    return (IOBlockStorageDevice *) IOService::getProvider();
106}
107
108bool IOBlockStorageDriver::init(OSDictionary * properties)
109{
110    //
111    // Initialize this object's minimal state.
112    //
113
114#ifndef __LP64__
115    if (prepareRequestAttributes(this) == false)
116        IOStorage::_expansionData = kIOBlockStorageDriverAttributesUnsupported;
117#endif /* !__LP64__ */
118
119    // Ask our superclass' opinion.
120
121    if (super::init(properties) == false)  return false;
122
123    // Initialize our state.
124
125    _expansionData = IONew(ExpansionData, 1);
126    if (_expansionData == 0)  return false;
127///w:start
128#if TARGET_OS_EMBEDDED
129    _expansionData->reserved0000     = 0;
130#endif /* TARGET_OS_EMBEDDED */
131///w:stop
132
133    initMediaState();
134
135    _ejectable                       = false;
136    _removable                       = false;
137
138    _mediaBlockSize                  = 0;
139    _maxBlockNumber                  = 0;
140    _writeProtected                  = false;
141
142    _maxReadBlockTransfer            = 0;
143    _maxWriteBlockTransfer           = 0;
144    _maxReadByteTransfer             = 0;
145    _maxWriteByteTransfer            = 0;
146    _maxReadSegmentTransfer          = 0;
147    _maxWriteSegmentTransfer         = 0;
148    _maxReadSegmentByteTransfer      = 0;
149    _maxWriteSegmentByteTransfer     = 0;
150    _minSegmentAlignmentByteTransfer = 4;
151    _maxSegmentWidthByteTransfer     = 0;
152
153    _contexts                        = NULL;
154    _contextsLock                    = IOSimpleLockAlloc();
155    _contextsCount                   = 0;
156    _contextsMaxCount                = 32;
157
158    if (_contextsLock == 0)
159        return false;
160
161    _deblockRequestWriteLock         = IOLockAlloc();
162    _deblockRequestWriteLockCount    = 0;
163    _openAssertions                  = 0;
164    _openClients                     = OSSet::withCapacity(2);
165    _powerEventNotifier              = 0;
166
167    for (unsigned index = 0; index < kStatisticsCount; index++)
168        _statistics[index] = OSNumber::withNumber(0ULL, 64);
169
170    if (_deblockRequestWriteLock == 0 || _openClients == 0)
171        return false;
172
173    for (unsigned index = 0; index < kStatisticsCount; index++)
174        if (_statistics[index] == 0)  return false;
175
176    // Create our registry properties.
177
178    OSDictionary * statistics = OSDictionary::withCapacity(kStatisticsCount);
179
180    if (statistics == 0)  return false;
181
182    statistics->setObject( kIOBlockStorageDriverStatisticsBytesReadKey,
183                           _statistics[kStatisticsBytesRead] );
184    statistics->setObject( kIOBlockStorageDriverStatisticsBytesWrittenKey,
185                           _statistics[kStatisticsBytesWritten] );
186    statistics->setObject( kIOBlockStorageDriverStatisticsReadErrorsKey,
187                           _statistics[kStatisticsReadErrors] );
188    statistics->setObject( kIOBlockStorageDriverStatisticsWriteErrorsKey,
189                           _statistics[kStatisticsWriteErrors] );
190    statistics->setObject( kIOBlockStorageDriverStatisticsLatentReadTimeKey,
191                           _statistics[kStatisticsLatentReadTime] );
192    statistics->setObject( kIOBlockStorageDriverStatisticsLatentWriteTimeKey,
193                           _statistics[kStatisticsLatentWriteTime] );
194    statistics->setObject( kIOBlockStorageDriverStatisticsReadsKey,
195                           _statistics[kStatisticsReads] );
196    statistics->setObject( kIOBlockStorageDriverStatisticsWritesKey,
197                           _statistics[kStatisticsWrites] );
198    statistics->setObject( kIOBlockStorageDriverStatisticsReadRetriesKey,
199                           _statistics[kStatisticsReadRetries] );
200    statistics->setObject( kIOBlockStorageDriverStatisticsWriteRetriesKey,
201                           _statistics[kStatisticsWriteRetries] );
202    statistics->setObject( kIOBlockStorageDriverStatisticsTotalReadTimeKey,
203                           _statistics[kStatisticsTotalReadTime] );
204    statistics->setObject( kIOBlockStorageDriverStatisticsTotalWriteTimeKey,
205                           _statistics[kStatisticsTotalWriteTime] );
206
207    setProperty(kIOBlockStorageDriverStatisticsKey, statistics);
208
209    statistics->release();
210
211    return true;
212}
213
214bool IOBlockStorageDriver::start(IOService * provider)
215{
216    //
217    // This method is called once we have been attached to the provider object.
218    //
219
220    bool success;
221
222    // Open the block storage device.
223
224    success = open(this);
225
226    if (success)
227    {
228        // Prepare the block storage driver for operation.
229
230        success = handleStart(provider);
231
232        // Close the block storage device.
233
234        close(this);
235    }
236
237    if (success)
238    {
239        // Register this object so it can be found via notification requests. It is
240        // not being registered to have I/O Kit attempt to have drivers match on it,
241        // which is the reason most other services are registered -- that's not the
242        // intention of this registerService call.
243
244        registerService();
245    }
246
247    return success;
248}
249
250bool IOBlockStorageDriver::didTerminate(IOService *  provider,
251                                        IOOptionBits options,
252                                        bool *       defer)
253{
254    // Try to teardown.
255
256    decommissionMedia(false);
257
258    return super::didTerminate(provider, options, defer);
259}
260
261bool IOBlockStorageDriver::yield(IOService *  provider,
262                                 IOOptionBits options,
263                                 void *       argument)
264{
265    return false;
266}
267
268void IOBlockStorageDriver::free()
269{
270    //
271    // Free all of this object's outstanding resources.
272    //
273
274    while (_contexts)
275    {
276        Context * context = _contexts;
277
278        _contexts = context->next;
279        _contextsCount--;
280
281        IODelete(context, Context, 1);
282    }
283
284    if (_contextsLock)  IOSimpleLockFree(_contextsLock);
285
286    if (_deblockRequestWriteLock)  IOLockFree(_deblockRequestWriteLock);
287    if (_openClients)  _openClients->release();
288
289    for (unsigned index = 0; index < kStatisticsCount; index++)
290        if (_statistics[index])  _statistics[index]->release();
291
292    if (_expansionData)  IODelete(_expansionData, ExpansionData, 1);
293
294    super::free();
295}
296
297bool IOBlockStorageDriver::handleOpen(IOService *  client,
298                                      IOOptionBits options,
299                                      void *       argument)
300{
301    //
302    // The handleOpen method grants or denies permission to access this object
303    // to an interested client.  The argument is an IOStorageAccess value that
304    // specifies the level of access desired -- reader or reader-writer.
305    //
306    // This method can be invoked to upgrade or downgrade the access level for
307    // an existing client as well.  The previous access level will prevail for
308    // upgrades that fail, of course.   A downgrade should never fail.  If the
309    // new access level should be the same as the old for a given client, this
310    // method will do nothing and return success.  In all cases, one, singular
311    // close-per-client is expected for all opens-per-client received.
312    //
313    // This method assumes that the arbitration lock is held.
314    //
315
316    assert(client);
317
318    // Ensure there is media in the block storage device.
319
320    if (client != this)
321    {
322        if (_mediaObject == NULL)
323        {
324            return false;
325        }
326    }
327
328    // Handle the first open in a special case.
329
330    if (_openClients->getCount() == 0)
331    {
332        // Open the block storage device.
333
334        if (getProvider()->open(this) == false)
335        {
336            return false;
337        }
338    }
339
340    // Process the open.
341
342    if (client != this)
343    {
344        _openClients->setObject(client);
345    }
346    else
347    {
348        if (_openAssertions == 0)
349        {
350            _openClients->setObject(client);
351        }
352
353        _openAssertions++;
354    }
355
356    return true;
357}
358
359bool IOBlockStorageDriver::handleIsOpen(const IOService * client) const
360{
361    //
362    // The handleIsOpen method determines whether the specified client, or any
363    // client if none is specificed, presently has an open on this object.
364    //
365    // This method assumes that the arbitration lock is held.
366    //
367
368    if (client)
369    {
370        return _openClients->containsObject(client);
371    }
372    else
373    {
374        return _openClients->getCount() ? true : false;
375    }
376}
377
378void IOBlockStorageDriver::handleClose(IOService * client, IOOptionBits options)
379{
380    //
381    // The handleClose method drops the incoming client's access to this object.
382    //
383    // This method assumes that the arbitration lock is held.
384    //
385
386    assert(client);
387
388    // Process the close.
389
390    if (client != this)
391    {
392        _openClients->removeObject(client);
393    }
394    else
395    {
396        _openAssertions--;
397
398        if (_openAssertions == 0)
399        {
400            _openClients->removeObject(client);
401        }
402    }
403
404    // Handle the last close in a special case.
405
406    if (_openClients->getCount() == 0)
407    {
408        if (_mediaObject)
409        {
410            if (_mediaObject->isInactive())
411            {
412                message(kIOMessageServiceIsRequestingClose, getProvider(), 0);
413            }
414        }
415
416        // Close the block storage device.
417
418        getProvider()->close(this);
419    }
420}
421
422void IOBlockStorageDriver::read(IOService *           client,
423                                UInt64                byteStart,
424                                IOMemoryDescriptor *  buffer,
425                                IOStorageAttributes * attributes,
426                                IOStorageCompletion * completion)
427{
428    //
429    // The read method is the receiving end for all read requests from the
430    // storage framework, ie. via the media object created by this driver.
431    //
432    // This method initiates a sequence of methods (stages) for each read/write
433    // request.  The first is prepareRequest, which allocates and prepares some
434    // context for the transfer; the second is deblockRequest, which aligns the
435    // transfer at the media's block boundaries; third is breakUpRequest, which
436    // breaks up the transfer into multiple sub-transfers when certain hardware
437    // constraints are exceeded; fourth is executeRequest, which implements the
438    // actual transfer from the block storage device.
439    //
440
441    // State our assumptions.
442
443    assert( buffer->getDirection( ) == kIODirectionIn );
444
445    // Prepare the transfer.
446
447#ifndef __LP64__
448    if ( IOStorage::_expansionData )
449    {
450        if ( attributes == &gIOStorageAttributesUnsupported )
451        {
452            attributes = NULL;
453
454            if ( IOStorage::_expansionData == kIOBlockStorageDriverAttributesUnsupported )
455            {
456                prepareRequest( byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } );
457
458                return;
459            }
460        }
461        else
462        {
463            if ( attributes && attributes->options )
464            {
465                complete( completion, kIOReturnUnsupported );
466            }
467            else
468            {
469                if ( IOStorage::_expansionData == kIOBlockStorageDriverAttributesUnsupported )
470                {
471                    prepareRequest( byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } );
472                }
473                else
474                {
475                    read( client, byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } );
476                }
477            }
478
479            return;
480        }
481    }
482#endif /* !__LP64__ */
483
484    prepareRequest( byteStart, buffer, attributes, completion );
485}
486
487void IOBlockStorageDriver::write(IOService *           client,
488                                 UInt64                byteStart,
489                                 IOMemoryDescriptor *  buffer,
490                                 IOStorageAttributes * attributes,
491                                 IOStorageCompletion * completion)
492{
493    //
494    // The write method is the receiving end for all write requests from the
495    // storage framework, ie. via the media object created by this driver.
496    //
497    // This method initiates a sequence of methods (stages) for each read/write
498    // request.  The first is prepareRequest, which allocates and prepares some
499    // context for the transfer; the second is deblockRequest, which aligns the
500    // transfer at the media's block boundaries; third is breakUpRequest, which
501    // breaks up the transfer into multiple sub-transfers when certain hardware
502    // constraints are exceeded; fourth is executeRequest, which implements the
503    // actual transfer from the block storage device.
504    //
505
506    // State our assumptions.
507
508    assert( buffer->getDirection( ) == kIODirectionOut );
509
510    // Prepare the transfer.
511
512#ifndef __LP64__
513    if ( IOStorage::_expansionData )
514    {
515        if ( attributes == &gIOStorageAttributesUnsupported )
516        {
517            attributes = NULL;
518
519            if ( IOStorage::_expansionData == kIOBlockStorageDriverAttributesUnsupported )
520            {
521                prepareRequest( byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } );
522
523                return;
524            }
525        }
526        else
527        {
528            if ( attributes && attributes->options )
529            {
530                complete( completion, kIOReturnUnsupported );
531            }
532            else
533            {
534                if ( IOStorage::_expansionData == kIOBlockStorageDriverAttributesUnsupported )
535                {
536                    prepareRequest( byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } );
537                }
538                else
539                {
540                    write( client, byteStart, buffer, completion ? *completion : ( IOStorageCompletion ) { 0 } );
541                }
542            }
543
544            return;
545        }
546    }
547#endif /* !__LP64__ */
548
549    prepareRequest( byteStart, buffer, attributes, completion );
550}
551
552void IOBlockStorageDriver::addToBytesTransferred(UInt64 bytesTransferred,
553                                                 UInt64 totalTime,       // (ns)
554                                                 UInt64 latentTime,      // (ns)
555                                                 bool   isWrite)
556{
557    //
558    // Update the total number of bytes transferred, the total transfer time,
559    // and the total latency time -- used for statistics.
560    //
561
562    if (isWrite)
563    {
564        _statistics[kStatisticsWrites]->addValue(1);
565        _statistics[kStatisticsBytesWritten]->addValue(bytesTransferred);
566        _statistics[kStatisticsTotalWriteTime]->addValue(totalTime);
567        _statistics[kStatisticsLatentWriteTime]->addValue(latentTime);
568    }
569    else
570    {
571        _statistics[kStatisticsReads]->addValue(1);
572        _statistics[kStatisticsBytesRead]->addValue(bytesTransferred);
573        _statistics[kStatisticsTotalReadTime]->addValue(totalTime);
574        _statistics[kStatisticsLatentReadTime]->addValue(latentTime);
575    }
576}
577
578void IOBlockStorageDriver::incrementRetries(bool isWrite)
579{
580    //
581    // Update the total retry count -- used for statistics.
582    //
583
584    if (isWrite)
585        _statistics[kStatisticsWriteRetries]->addValue(1);
586    else
587        _statistics[kStatisticsReadRetries]->addValue(1);
588}
589
590void IOBlockStorageDriver::incrementErrors(bool isWrite)
591{
592    //
593    // Update the total error count -- used for statistics.
594    //
595
596    if (isWrite)
597        _statistics[kStatisticsWriteErrors]->addValue(1);
598    else
599        _statistics[kStatisticsReadErrors]->addValue(1);
600}
601
602UInt32 IOBlockStorageDriver::getStatistics(UInt64 * statistics,
603                                           UInt32   statisticsMaxCount) const
604{
605    //
606    // Ask the driver to report its operating statistics.
607    //
608    // The statistics are each indexed by IOBlockStorageDriver::Statistics
609    // indices.  This routine fills the caller's buffer, up to the maximum
610    // count specified if the real number of statistics would overflow the
611    // buffer.  The return value indicates the actual number of statistics
612    // copied to the buffer.
613    //
614    // If the statistics buffer is not supplied or if the maximum count is
615    // zero, the routine returns the proposed count of statistics instead.
616    //
617
618    if (statistics == 0)
619        return kStatisticsCount;
620
621    UInt32 statisticsCount = min(kStatisticsCount, statisticsMaxCount);
622
623    for (unsigned index = 0; index < statisticsCount; index++)
624        statistics[index] = _statistics[index]->unsigned64BitValue();
625
626    return statisticsCount;
627}
628
629UInt64 IOBlockStorageDriver::getStatistic(Statistics statistic) const
630{
631    //
632    // Ask the driver to report one of its operating statistics.
633    //
634
635    if ((UInt32) statistic >= kStatisticsCount)  return 0;
636
637    return _statistics[statistic]->unsigned64BitValue();
638}
639
640IOBlockStorageDriver::Context * IOBlockStorageDriver::allocateContext()
641{
642    //
643    // Allocate a context structure for a read/write operation.
644    //
645
646    Context * context;
647
648    IOSimpleLockLock(_contextsLock);
649
650    context = _contexts;
651
652    if (context)
653    {
654        _contexts = context->next;
655        _contextsCount--;
656    }
657
658    IOSimpleLockUnlock(_contextsLock);
659
660    if (context == 0)
661    {
662        context = IONew(Context, 1);
663    }
664
665    if (context)
666    {
667        bzero(context, sizeof(Context));
668    }
669
670    return context;
671}
672
673void IOBlockStorageDriver::deleteContext(
674                                        IOBlockStorageDriver::Context * context)
675{
676    //
677    // Delete a context structure from a read/write operation.
678    //
679
680    IOSimpleLockLock(_contextsLock);
681
682    if (_contextsCount < _contextsMaxCount)
683    {
684        context->next = _contexts;
685
686        _contexts = context;
687        _contextsCount++;
688
689        context = 0;
690    }
691
692    IOSimpleLockUnlock(_contextsLock);
693
694    if (context)
695    {
696        IODelete(context, Context, 1);
697    }
698}
699
700#ifndef __LP64__
701void IOBlockStorageDriver::prepareRequest(UInt64               byteStart,
702                                          IOMemoryDescriptor * buffer,
703                                          IOStorageCompletion  completion)
704{
705    //
706    // The prepareRequest method allocates and prepares state for the transfer.
707    //
708    // This method is part of a sequence of methods invoked for each read/write
709    // request.  The first is prepareRequest, which allocates and prepares some
710    // context for the transfer; the second is deblockRequest, which aligns the
711    // transfer at the media's block boundaries; third is breakUpRequest, which
712    // breaks up the transfer into multiple sub-transfers when certain hardware
713    // constraints are exceeded; fourth is executeRequest, which implements the
714    // actual transfer from the block storage device.
715    //
716
717    prepareRequest( byteStart, buffer, NULL, &completion );
718}
719#endif /* !__LP64__ */
720
721void IOBlockStorageDriver::prepareRequestCompletion(void *   target,
722                                                    void *   parameter,
723                                                    IOReturn status,
724                                                    UInt64   actualByteCount)
725{
726    //
727    // This is the completion routine for the prepared request.  It updates
728    // the driver's statistics, performs some clean up work, then calls the
729    // original request's completion routine.
730    //
731
732    Context *              context = (Context              *) parameter;
733    IOBlockStorageDriver * driver  = (IOBlockStorageDriver *) target;
734    bool                   isWrite;
735    AbsoluteTime           time;
736    UInt64                 timeInNanoseconds;
737
738    isWrite = (context->original.buffer->getDirection() == kIODirectionOut);
739
740    // Update the error state, on a short transfer.
741
742    if (actualByteCount < context->original.buffer->getLength())
743    {
744        if (status == kIOReturnSuccess)
745        {
746            status = kIOReturnUnderrun;
747        }
748    }
749
750    // Update the total number of bytes transferred and the total transfer time.
751
752    clock_get_uptime(&time);
753    SUB_ABSOLUTETIME(&time, &context->timeStart);
754    absolutetime_to_nanoseconds(time, &timeInNanoseconds);
755
756    driver->addToBytesTransferred(actualByteCount, timeInNanoseconds, 0, isWrite);
757
758    // Update the total error count.
759
760    if (status != kIOReturnSuccess)
761    {
762        driver->incrementErrors(isWrite);
763    }
764
765    // Complete the transfer request.
766
767    IOStorage::complete(&context->original.completion, status, actualByteCount);
768
769    // Release our resources.
770
771    context->original.buffer->release();
772
773    driver->deleteContext(context);
774}
775
776void IOBlockStorageDriver::schedulePoller()
777{
778
779}
780
781void IOBlockStorageDriver::unschedulePoller()
782{
783
784}
785
786IOReturn IOBlockStorageDriver::message(UInt32      type,
787                                       IOService * provider,
788                                       void *      argument)
789{
790    //
791    // Generic entry point for calls from the provider.  A return value of
792    // kIOReturnSuccess indicates that the message was received, and where
793    // applicable, that it was successful.
794    //
795
796    switch (type)
797    {
798        case kIOMessageMediaParametersHaveChanged:
799        {
800            IOReturn status;
801            if (open(this)) {
802                status = recordMediaParameters();
803                if (status == kIOReturnSuccess) {
804                    UInt64 nbytes;
805                    IOMedia *m;
806                    if (_maxBlockNumber) {
807                        nbytes = _mediaBlockSize * (_maxBlockNumber + 1);
808                    } else {
809                        nbytes = 0;
810                    }
811                    m = instantiateMediaObject(0,nbytes,_mediaBlockSize,NULL);
812                    if (m) {
813                        lockForArbitration();
814                        if (_mediaObject) {
815                            _mediaObject->init( m->getBase(),
816                                                m->getSize(),
817                                                m->getPreferredBlockSize(),
818                                                m->getAttributes(),
819                                                m->isWhole(),
820                                                m->isWritable(),
821                                                m->getContentHint() );
822                            _mediaObject->messageClients(kIOMessageServicePropertyChange);
823                        } else {
824                            status = kIOReturnNoMedia;
825                        }
826                        unlockForArbitration();
827                        m->release();
828                    } else {
829                        status = kIOReturnBadArgument;
830                    }
831                }
832                close(this);
833            } else {
834                status = kIOReturnNotAttached;
835            }
836            return status;
837        }
838        case kIOMessageMediaStateHasChanged:
839        {
840            IOReturn status;
841            if (open(this)) {
842                status = mediaStateHasChanged((uintptr_t) argument);
843                close(this);
844            } else {
845                status = kIOReturnNotAttached;
846            }
847            return status;
848        }
849        case kIOMessageServiceIsRequestingClose:
850        {
851            IOReturn status;
852            status = decommissionMedia(false);
853            return status;
854        }
855        default:
856        {
857            return super::message(type, provider, argument);
858        }
859    }
860}
861
862/* Accept a new piece of media, doing whatever's necessary to make it
863 * show up properly to the system. The arbitration lock is assumed to
864 * be held during the call.
865 */
866IOReturn
867IOBlockStorageDriver::acceptNewMedia(void)
868{
869    IOReturn result;
870    bool ok;
871    UInt64 nbytes;
872    char name[128];
873    bool nameSep;
874    IOMedia *m;
875
876    if (_maxBlockNumber) {
877        nbytes = _mediaBlockSize * (_maxBlockNumber + 1);
878    } else {
879        nbytes = 0;
880    }
881
882    /* Instantiate a media object and attach it to ourselves. */
883
884    name[0] = 0;
885    nameSep = false;
886    if (getProvider()->getVendorString()) {
887        strlcat(name, getProvider()->getVendorString(), sizeof(name) - strlen(name));
888        nameSep = true;
889    }
890    if (getProvider()->getProductString()) {
891        if (nameSep == true)  strlcat(name, " ", sizeof(name) - strlen(name));
892        strlcat(name, getProvider()->getProductString(), sizeof(name) - strlen(name));
893        nameSep = true;
894    }
895    if (nameSep == true)  strlcat(name, " ", sizeof(name) - strlen(name));
896    strlcat(name, "Media", sizeof(name) - strlen(name));
897    strclean(name);
898
899    m = instantiateMediaObject(0,nbytes,_mediaBlockSize,name);
900    result = (m) ? kIOReturnSuccess : kIOReturnBadArgument;
901
902    if (result == kIOReturnSuccess) {
903        if (getProperty(kIOMediaIconKey, gIOServicePlane)) {
904            m->removeProperty(kIOMediaIconKey);
905        }
906        ok = m->attach(this);	/* attach media object above us */
907        if (ok) {
908            IOService *parent = this;
909            OSNumber *unit = NULL;
910            OSNumber *unitLUN = NULL;
911            OSString *unitName = NULL;
912
913            /* Wire the media object to the device tree. */
914
915            while ((parent = parent->getProvider())) {
916                if (!unit) {
917                    unit = OSDynamicCast(OSNumber, parent->getProperty("IOUnit"));
918                }
919                if (!unitLUN) {
920                    unitLUN = OSDynamicCast(OSNumber, parent->getProperty("IOUnitLUN"));
921                }
922                if (!unitName) {
923                    unitName = OSDynamicCast(OSString, parent->getProperty("IOUnitName"));
924                }
925                if (parent->inPlane(gIODTPlane)) {
926                    IORegistryEntry *child;
927                    IORegistryIterator *children;
928                    if (!unit || !parent->getProvider()) {
929                        break;
930                    }
931
932                    children = IORegistryIterator::iterateOver(parent, gIODTPlane);
933                    if (!children) {
934                        break;
935                    }
936                    while ((child = children->getNextObject())) {
937                        if (!OSDynamicCast(IOMedia, child)) {
938                            child->detachAll(gIODTPlane);
939                        }
940                    }
941                    children->release();
942
943                    if (m->attachToParent(parent, gIODTPlane)) {
944                        char location[ 32 ];
945                        if (unitLUN && unitLUN->unsigned32BitValue()) {
946                            snprintf(location, sizeof(location), "%x,%x:0", unit->unsigned32BitValue(), unitLUN->unsigned32BitValue());
947                        } else {
948                            snprintf(location, sizeof(location), "%x:0", unit->unsigned32BitValue());
949                        }
950                        m->setLocation(location, gIODTPlane);
951                        m->setName(unitName ? unitName->getCStringNoCopy() : "", gIODTPlane);
952                    }
953                    break;
954                }
955            }
956
957            lockForArbitration();
958            _mediaObject = m;
959            _mediaObject->retain();
960            unlockForArbitration();
961
962            m->registerService(kIOServiceAsynchronous);		/* enable matching */
963        } else {
964            result = kIOReturnNoMemory;	/* give up now */
965        }
966        m->release();
967    }
968
969    return(result);
970}
971
972IOReturn
973IOBlockStorageDriver::checkForMedia(void)
974{
975    IOReturn result;
976    bool currentState;
977    bool changed;
978
979    result = getProvider()->reportMediaState(&currentState,&changed);
980    if (result != kIOReturnSuccess) {		/* the poll operation failed */
981        IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from reportMediaState\n",
982              getName(),stringFromReturn(result));
983    } else {
984        changed = _mediaObject ? !currentState : currentState;
985        if (changed) {	/* the poll succeeded, media state has changed */
986            result = mediaStateHasChanged(currentState ? kIOMediaStateOnline
987                                                       : kIOMediaStateOffline);
988        }
989    }
990
991    return(result);
992}
993
994IOReturn
995IOBlockStorageDriver::mediaStateHasChanged(IOMediaState state)
996{
997    IOReturn result;
998
999    /* The media has changed state. See if it's just inserted or removed. */
1000
1001    if (state == kIOMediaStateOnline) {		/* media is now present */
1002
1003        if (_mediaObject) {
1004            return(kIOReturnBadArgument);
1005        }
1006
1007        initMediaState();        /* clear all knowledge of the media */
1008
1009        /* Allow a subclass to decide whether we accept the media. Such a
1010         * decision might be based on things like password-protection, etc.
1011         */
1012
1013        if (validateNewMedia() == false) {	/* we're told to reject it */
1014            rejectMedia();			/* so let subclass do whatever it wants */
1015            return(kIOReturnSuccess);		/* pretend nothing happened */
1016        }
1017
1018        result = recordMediaParameters();	/* learn about media */
1019        if (result != kIOReturnSuccess) {	/* couldn't record params */
1020	    IOLog("%s[IOBlockStorageDriver]::mediaStateHasChanged: err '%s' from recordMediaParameters\n",
1021			getName(),stringFromReturn(result));
1022            return(result);
1023        }
1024
1025        /* Now we do what's necessary to make the new media
1026         * show up properly in the system.
1027         */
1028
1029        result = acceptNewMedia();
1030        if (result != kIOReturnSuccess) {
1031	    IOLog("%s[IOBlockStorageDriver]::mediaStateHasChanged; err '%s' from acceptNewMedia\n",
1032            getName(),stringFromReturn(result));
1033        }
1034
1035        return(result);		/* all done, new media is ready */
1036
1037    } else {				/* media is now absent */
1038
1039        result = decommissionMedia(true);	/* force a teardown */
1040        if (result != kIOReturnSuccess && result != kIOReturnNoMedia) {
1041	    IOLog("%s[IOBlockStorageDriver]::mediaStateHasChanged; err '%s' from decommissionNewMedia\n",
1042			getName(),stringFromReturn(result));
1043            return(result);
1044        }
1045
1046        return(kIOReturnSuccess);		/* all done; media is gone */
1047    }
1048}
1049
1050UInt64
1051IOBlockStorageDriver::constrainByteCount(UInt64 /* requestedCount */ ,bool isWrite)
1052{
1053    if (isWrite) {
1054        return(_maxWriteByteTransfer);
1055    } else {
1056        return(_maxReadByteTransfer);
1057    }
1058}
1059
1060/* Decommission a piece of media that has become unavailable either due to
1061 * ejection or some outside force (e.g. the Giant Hand of the User).
1062 * (I prefer the term "decommission" rather than "abandon." The former implies
1063 * a well-determined procedure, whereas the latter implies leaving the media
1064 * in an orphaned state.)
1065 */
1066/* Tear down the stack above the specified object. Usually these objects will
1067 * be of type IOMedia, but they could be any IOService.
1068 */
1069IOReturn
1070IOBlockStorageDriver::decommissionMedia(bool forcible)
1071{
1072    IOMedia *m = NULL;
1073    IOReturn result;
1074
1075    lockForArbitration();
1076
1077    if (_mediaObject) {
1078        /* If this is a forcible decommission (i.e. media is gone), we
1079         * forget about the media.
1080         */
1081        if (forcible || !_openClients->containsObject(_mediaObject)) {
1082            m = _mediaObject;
1083            _mediaObject = 0;
1084
1085            result = kIOReturnSuccess;
1086        } else {
1087            result = kIOReturnBusy;
1088        }
1089    } else {
1090        result = kIOReturnNoMedia;
1091    }
1092
1093    unlockForArbitration();
1094
1095    if (m) {
1096        IORegistryEntry * parent;
1097
1098        /* Unwire the media object from the device tree. */
1099
1100        if ( (parent = m->getParentEntry(gIODTPlane)) ) {
1101            m->detachFromParent(parent, gIODTPlane);
1102        }
1103
1104        if (!m->isInactive()) {
1105            m->terminate();
1106        }
1107
1108        m->release();
1109    }
1110
1111    return(result);
1112}
1113
1114IOReturn
1115IOBlockStorageDriver::ejectMedia(void)
1116{
1117    IOReturn result;
1118
1119    if (_ejectable)
1120    {
1121        result = decommissionMedia(false);	/* try to teardown */
1122    }
1123    else
1124    {
1125        lockForArbitration();
1126
1127        if (_mediaObject) {
1128            if (!_openClients->containsObject(_mediaObject)) {
1129                result = kIOReturnSuccess;
1130            } else {
1131                result = kIOReturnBusy;
1132            }
1133        } else {
1134            result = kIOReturnNoMedia;
1135        }
1136
1137        unlockForArbitration();
1138    }
1139
1140    if (result == kIOReturnSuccess) {	/* eject */
1141        if (!_writeProtected) {
1142            (void)getProvider()->doSynchronizeCache();
1143        }
1144
1145        (void)getProvider()->doEjectMedia();	/* ignore any error */
1146    }
1147
1148    return(result);
1149}
1150
1151void
1152IOBlockStorageDriver::executeRequest(UInt64                          byteStart,
1153                                     IOMemoryDescriptor *            buffer,
1154#ifdef __LP64__
1155                                     IOStorageAttributes *           attributes,
1156                                     IOStorageCompletion *           completion,
1157#else /* !__LP64__ */
1158                                     IOStorageCompletion             completion,
1159#endif /* !__LP64__ */
1160                                     IOBlockStorageDriver::Context * context)
1161{
1162    UInt32 flags = 0;
1163    UInt64 block;
1164    UInt64 nblks;
1165    IOReturn result;
1166
1167    if (!_mediaObject) {		/* no media? you lose */
1168        complete(completion,kIOReturnNoMedia,0);
1169        return;
1170    }
1171
1172    /* We know that we are never called with a request too large,
1173     * nor one that is misaligned with a block.
1174     */
1175    assert((byteStart           % context->block.size) == 0);
1176    assert((buffer->getLength() % context->block.size) == 0);
1177
1178    block = byteStart           / context->block.size;
1179    nblks = buffer->getLength() / context->block.size;
1180
1181    /* Now the protocol-specific provider implements the actual
1182     * start of the data transfer: */
1183
1184#ifdef __LP64__
1185    if (attributes) {
1186        if (attributes->priority > kIOStoragePriorityDefault) {
1187            flags |= IO_PRIORITY_LOW;
1188        }
1189    }
1190#else /* !__LP64__ */
1191    if (context->request.attributes.priority > kIOStoragePriorityDefault) {
1192        flags |= IO_PRIORITY_LOW;
1193    }
1194#endif /* !__LP64__ */
1195
1196    if (_solidState) {
1197        flags |= IO_MEDIUM_SOLID_STATE;
1198    }
1199
1200    if (buffer->getDirection() == kIODirectionIn) {
1201        io_rate_update(flags, 1, 0, buffer->getLength(), 0);
1202    } else {
1203        io_rate_update(flags, 0, 1, 0, buffer->getLength());
1204    }
1205
1206#if TARGET_OS_EMBEDDED
1207    // This is where we adjust the offset for this access to the nand layer.
1208    // We already maintain this buffer's file offset in attributes.fileOffset
1209#ifdef __LP64__
1210    if (!attributes) {
1211        attributes = &context->request.attributes;
1212    }
1213    attributes->adjustedOffset = ((SInt64)byteStart - (SInt64)context->original.byteStart);
1214#else /* !__LP64__ */
1215    context->request.attributes.adjustedOffset = ((SInt64)byteStart - (SInt64)context->original.byteStart);
1216#endif /* !__LP64__ */
1217#endif /* TARGET_OS_EMBEDDED */
1218#ifdef __LP64__
1219    result = getProvider()->doAsyncReadWrite(buffer,block,nblks,attributes,completion);
1220#else /* !__LP64__ */
1221    result = getProvider()->doAsyncReadWrite(buffer,block,nblks,&context->request.attributes,&completion);
1222#endif /* !__LP64__ */
1223
1224    if (result != kIOReturnSuccess) {		/* it failed to start */
1225        if (result != kIOReturnNotPermitted) {		/* expected error from content protection */
1226            IOLog("%s[IOBlockStorageDriver]; executeRequest: request failed to start!\n",getName());
1227        }
1228        complete(completion,result);
1229        return;
1230    }
1231}
1232
1233IOReturn
1234IOBlockStorageDriver::formatMedia(UInt64 byteCapacity)
1235{
1236    IOReturn result;
1237
1238    result = decommissionMedia(false);	/* try to teardown */
1239
1240    if (result == kIOReturnSuccess) {	/* format */
1241        result = getProvider()->doFormatMedia(byteCapacity);
1242
1243        if (result == kIOReturnSuccess) {
1244            result = mediaStateHasChanged(kIOMediaStateOnline);
1245        } else {
1246            (void)mediaStateHasChanged(kIOMediaStateOnline);
1247        }
1248    }
1249
1250    return(result);
1251}
1252
1253const char *
1254IOBlockStorageDriver::getDeviceTypeName(void)
1255{
1256    return(kIOBlockStorageDeviceTypeGeneric);
1257}
1258
1259UInt32
1260IOBlockStorageDriver::getFormatCapacities(UInt64 * capacities,
1261                                            UInt32   capacitiesMaxCount) const
1262{
1263    return(getProvider()->doGetFormatCapacities(capacities,capacitiesMaxCount));
1264}
1265
1266UInt64
1267IOBlockStorageDriver::getMediaBlockSize() const
1268{
1269    return(_mediaBlockSize);
1270}
1271
1272IOMediaState
1273IOBlockStorageDriver::getMediaState() const
1274{
1275    if (_mediaObject) {
1276        return(kIOMediaStateOnline);
1277    } else {
1278        return(kIOMediaStateOffline);
1279    }
1280}
1281
1282IOReturn
1283IOBlockStorageDriver::handlePowerEvent(void *target,void *refCon,
1284                                       UInt32 messageType,IOService *provider,
1285                                       void *messageArgument,vm_size_t argSize)
1286{
1287    IOBlockStorageDriver *driver = (IOBlockStorageDriver *)target;
1288    IOReturn result;
1289
1290    switch (messageType) {
1291        case kIOMessageSystemWillPowerOff:
1292        case kIOMessageSystemWillRestart:
1293            if (driver->open(driver)) {
1294                if (driver->_mediaObject) {
1295                    if (!driver->_writeProtected) {
1296                        driver->getProvider()->doSynchronizeCache();
1297                    }
1298                    if (!driver->_removable && (messageType == kIOMessageSystemWillPowerOff)) {
1299                        driver->getProvider()->doEjectMedia();
1300                    }
1301                }
1302                driver->close(driver);
1303            }
1304            result = kIOReturnSuccess;
1305            break;
1306
1307        default:
1308            result = kIOReturnUnsupported;
1309            break;
1310    }
1311
1312    return(result);
1313}
1314
1315bool
1316IOBlockStorageDriver::handleStart(IOService * provider)
1317{
1318    OSObject *object;
1319    OSNumber *number;
1320    IOReturn result;
1321
1322    /* The protocol-specific provider determines whether the media is removable. */
1323
1324    result = getProvider()->reportRemovability(&_removable);
1325    if (result != kIOReturnSuccess) {
1326	IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportRemovability\n",
1327			getName(),stringFromReturn(result));
1328        return(false);
1329    }
1330
1331    if (_removable) {
1332
1333        /* The protocol-specific provider determines whether the media is ejectable
1334         * under software control.
1335         */
1336        result = getProvider()->reportEjectability(&_ejectable);
1337        if (result != kIOReturnSuccess) {
1338	    IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportEjectability\n",
1339			getName(),stringFromReturn(result));
1340            return(false);
1341        }
1342
1343    } else {		/* fixed disk: not ejectable */
1344        OSDictionary *dictionary = OSDynamicCast(OSDictionary, getProvider()->getProperty(kIOPropertyDeviceCharacteristicsKey));
1345
1346        if (dictionary) {
1347            OSString *string = OSDynamicCast(OSString, dictionary->getObject(kIOPropertyMediumTypeKey));
1348
1349            if (string) {
1350                if (string->isEqualTo(kIOPropertyMediumTypeSolidStateKey)) {
1351                    _solidState = true;
1352                }
1353            }
1354        }
1355
1356        _ejectable = false;
1357    }
1358
1359    /* Obtain the constraint values for reads and writes. */
1360
1361    object = copyProperty(kIOMaximumBlockCountReadKey, gIOServicePlane);
1362    if (object) {
1363
1364        number = OSDynamicCast(OSNumber, object);
1365        if (number) {
1366            _maxReadBlockTransfer = number->unsigned64BitValue();
1367        }
1368
1369        object->release();
1370    }
1371#ifndef __LP64__
1372    if (object == 0) {
1373        UInt64 maxReadTransfer;
1374
1375        result = getProvider()->reportMaxReadTransfer(512, &maxReadTransfer);
1376        if (result == kIOReturnSuccess) {
1377            _maxReadBlockTransfer = maxReadTransfer / 512;
1378        }
1379
1380        getProvider()->setProperty(kIOMaximumBlockCountReadKey, _maxReadBlockTransfer, 64);
1381    }
1382#endif /* !__LP64__ */
1383
1384    object = copyProperty(kIOMaximumBlockCountWriteKey, gIOServicePlane);
1385    if (object) {
1386
1387        number = OSDynamicCast(OSNumber, object);
1388        if (number) {
1389            _maxWriteBlockTransfer = number->unsigned64BitValue();
1390        }
1391
1392        object->release();
1393    }
1394#ifndef __LP64__
1395    if (object == 0) {
1396        UInt64 maxWriteTransfer;
1397
1398        result = getProvider()->reportMaxWriteTransfer(512, &maxWriteTransfer);
1399        if (result == kIOReturnSuccess) {
1400            _maxWriteBlockTransfer = maxWriteTransfer / 512;
1401        }
1402
1403        getProvider()->setProperty(kIOMaximumBlockCountWriteKey, _maxWriteBlockTransfer, 64);
1404    }
1405#endif /* !__LP64__ */
1406
1407    object = copyProperty(kIOMaximumByteCountReadKey, gIOServicePlane);
1408    if (object) {
1409
1410        number = OSDynamicCast(OSNumber, object);
1411        if (number) {
1412            _maxReadByteTransfer = number->unsigned64BitValue();
1413        }
1414
1415        object->release();
1416    }
1417
1418    object = copyProperty(kIOMaximumByteCountWriteKey, gIOServicePlane);
1419    if (object) {
1420
1421        number = OSDynamicCast(OSNumber, object);
1422        if (number) {
1423            _maxWriteByteTransfer = number->unsigned64BitValue();
1424        }
1425
1426        object->release();
1427    }
1428
1429    object = copyProperty(kIOMaximumSegmentCountReadKey, gIOServicePlane);
1430    if (object) {
1431
1432        number = OSDynamicCast(OSNumber, object);
1433        if (number) {
1434            _maxReadSegmentTransfer = number->unsigned64BitValue();
1435        }
1436
1437        object->release();
1438    }
1439
1440    object = copyProperty(kIOMaximumSegmentCountWriteKey, gIOServicePlane);
1441    if (object) {
1442
1443        number = OSDynamicCast(OSNumber, object);
1444        if (number) {
1445            _maxWriteSegmentTransfer = number->unsigned64BitValue();
1446        }
1447
1448        object->release();
1449    }
1450
1451    object = copyProperty(kIOMaximumSegmentByteCountReadKey, gIOServicePlane);
1452    if (object) {
1453
1454        number = OSDynamicCast(OSNumber, object);
1455        if (number) {
1456            _maxReadSegmentByteTransfer = number->unsigned64BitValue();
1457        }
1458
1459        object->release();
1460    }
1461
1462    object = copyProperty(kIOMaximumSegmentByteCountWriteKey, gIOServicePlane);
1463    if (object) {
1464
1465        number = OSDynamicCast(OSNumber, object);
1466        if (number) {
1467            _maxWriteSegmentByteTransfer = number->unsigned64BitValue();
1468        }
1469
1470        object->release();
1471    }
1472
1473    object = copyProperty(kIOMinimumSegmentAlignmentByteCountKey, gIOServicePlane);
1474    if (object) {
1475
1476        number = OSDynamicCast(OSNumber, object);
1477        if (number) {
1478            _minSegmentAlignmentByteTransfer = number->unsigned64BitValue();
1479        }
1480
1481        object->release();
1482    } else {
1483        getProvider()->setProperty(kIOMinimumSegmentAlignmentByteCountKey, _minSegmentAlignmentByteTransfer, 64);
1484    }
1485
1486    object = copyProperty(kIOMaximumSegmentAddressableBitCountKey, gIOServicePlane);
1487    if (object) {
1488
1489        number = OSDynamicCast(OSNumber, object);
1490        if (number) {
1491            if (number->unsigned64BitValue()) {
1492                if (number->unsigned64BitValue() < 64) {
1493                    _maxSegmentWidthByteTransfer = 1ULL << number->unsigned64BitValue();
1494                }
1495            }
1496        }
1497
1498        object->release();
1499    }
1500
1501    object = copyProperty(kIOCommandPoolSizeKey, gIOServicePlane);
1502    if (object) {
1503
1504        number = OSDynamicCast(OSNumber, object);
1505        if (number) {
1506            _contextsMaxCount = number->unsigned32BitValue();
1507        }
1508
1509        object->release();
1510    }
1511///w:start
1512#if TARGET_OS_EMBEDDED
1513    if (getProperty(kIOMaximumPriorityCountKey, gIOServicePlane)) {
1514        _expansionData->reserved0000 = 1;
1515    }
1516#endif /* TARGET_OS_EMBEDDED */
1517///w:stop
1518
1519    /* Check for the device being ready with media inserted: */
1520
1521    result = checkForMedia();
1522
1523    /* The poll should never fail for nonremovable media: */
1524
1525    if (result != kIOReturnSuccess && !_removable) {
1526	IOLog("%s[IOBlockStorageDriver]::handleStart: err '%s' from checkForMedia\n",
1527			getName(),stringFromReturn(result));
1528        return(false);
1529    }
1530
1531    /* Set up the power event handler for restarts and shutdowns: */
1532
1533    _powerEventNotifier = registerPrioritySleepWakeInterest(handlePowerEvent,this);
1534    if (_powerEventNotifier) {
1535        retain();
1536    }
1537
1538    return(true);
1539}
1540
1541bool
1542IOBlockStorageDriver::handleYield(IOService *  provider,
1543                                  IOOptionBits options,
1544                                  void *       argument)
1545{
1546    return false;
1547}
1548
1549void
1550IOBlockStorageDriver::initMediaState(void)
1551{
1552    _mediaType = 0;
1553}
1554
1555IOMedia *
1556IOBlockStorageDriver::instantiateDesiredMediaObject(void)
1557{
1558    return(new IOMedia);
1559}
1560
1561IOMedia *
1562IOBlockStorageDriver::instantiateMediaObject(UInt64 base,UInt64 byteSize,
1563                                        UInt32 blockSize,char *mediaName)
1564{
1565    IOMediaAttributeMask attributes = 0;
1566    IOMedia *m;
1567    bool result;
1568
1569    m = instantiateDesiredMediaObject();
1570    if (m == NULL) {
1571        return(NULL);
1572    }
1573
1574    attributes |= _ejectable ? kIOMediaAttributeEjectableMask : 0;
1575    attributes |= _removable ? kIOMediaAttributeRemovableMask : 0;
1576
1577    result = m->init(   base,			/* base byte offset */
1578                        byteSize,		/* byte size */
1579                        blockSize,		/* preferred block size */
1580                        attributes,		/* attributes */
1581                        true,			/* TRUE if whole physical media */
1582                        !_writeProtected,	/* TRUE if writable */
1583        		"");			/* content hint */
1584
1585    if (result) {
1586        const char *picture = "External.icns";
1587
1588        if (_removable) {
1589            picture = "Removable.icns";
1590        } else {
1591            OSDictionary *dictionary = OSDynamicCast(OSDictionary, getProvider()->getProperty(kIOPropertyProtocolCharacteristicsKey));
1592
1593            if (dictionary) {
1594                OSString *string = OSDynamicCast(OSString, dictionary->getObject(kIOPropertyPhysicalInterconnectLocationKey));
1595
1596                if (string) {
1597                    if (string->isEqualTo(kIOPropertyExternalKey)) {
1598                        picture = "External.icns";
1599                    } else {
1600                        picture = "Internal.icns";
1601                    }
1602                }
1603            }
1604        }
1605
1606        if (picture) {
1607            OSDictionary *dictionary = OSDictionary::withCapacity(2);
1608            OSString *identifier = OSString::withCString("com.apple.iokit.IOStorageFamily");
1609            OSString *resourceFile = OSString::withCString(picture);
1610
1611            if (dictionary && identifier && resourceFile) {
1612                dictionary->setObject("CFBundleIdentifier", identifier);
1613                dictionary->setObject("IOBundleResourceFile", resourceFile);
1614            }
1615
1616            m->setProperty(kIOMediaIconKey, dictionary);
1617
1618            if (resourceFile) {
1619                resourceFile->release();
1620            }
1621            if (identifier) {
1622                identifier->release();
1623            }
1624            if (dictionary) {
1625                dictionary->release();
1626            }
1627        }
1628
1629        if (mediaName) {
1630            m->setName(mediaName);
1631        }
1632
1633        return(m);
1634
1635    } else {					/* some init error */
1636        m->release();
1637        return(NULL);		/* beats me...call it this error */
1638    }
1639}
1640
1641bool
1642IOBlockStorageDriver::isMediaEjectable(void) const
1643{
1644    return(_ejectable);
1645}
1646
1647#ifdef __LP64__
1648bool
1649IOBlockStorageDriver::isMediaRemovable(void) const
1650{
1651    return(_removable);
1652}
1653#endif /* __LP64__ */
1654
1655bool
1656IOBlockStorageDriver::isMediaPollExpensive(void) const
1657{
1658    return(false);
1659}
1660
1661bool
1662IOBlockStorageDriver::isMediaPollRequired(void) const
1663{
1664    return(false);
1665}
1666
1667bool
1668IOBlockStorageDriver::isMediaWritable(void) const
1669{
1670    return(!_writeProtected);
1671}
1672
1673IOReturn
1674IOBlockStorageDriver::lockMedia(bool locked)
1675{
1676    return(kIOReturnUnsupported);
1677}
1678
1679IOReturn
1680IOBlockStorageDriver::pollMedia(void)
1681{
1682    return(kIOReturnUnsupported);
1683}
1684
1685IOReturn
1686IOBlockStorageDriver::recordMediaParameters(void)
1687{
1688    IOReturn result;
1689
1690    /* Determine the device's block size and max block number.
1691     * What should an unformatted device report? All zeroes.
1692     */
1693
1694    result = getProvider()->reportBlockSize(&_mediaBlockSize);
1695    if (result != kIOReturnSuccess) {
1696        goto err;
1697    }
1698
1699    result = getProvider()->reportMaxValidBlock(&_maxBlockNumber);
1700    if (result != kIOReturnSuccess) {
1701        goto err;
1702    }
1703
1704    /* Is the media write-protected? */
1705
1706    result = getProvider()->reportWriteProtection(&_writeProtected);
1707    if (result != kIOReturnSuccess) {
1708        goto err;
1709    }
1710
1711    return(kIOReturnSuccess);		/* everything was successful */
1712
1713    /* If we fall thru to here, we had some kind of error. Set everything to
1714     * a reasonable state since we haven't got any real information.
1715     */
1716
1717err:
1718    return(result);
1719}
1720
1721void
1722IOBlockStorageDriver::rejectMedia(void)
1723{
1724    (void)getProvider()->doEjectMedia();	/* eject it, ignoring any error */
1725}
1726
1727void
1728IOBlockStorageDriver::stop(IOService * provider)
1729{
1730    if (_powerEventNotifier) {
1731        _powerEventNotifier->remove();
1732        _powerEventNotifier = NULL;
1733        release();
1734    }
1735    super::stop(provider);
1736}
1737
1738IOReturn
1739IOBlockStorageDriver::synchronizeCache(IOService *client)
1740{
1741    return(getProvider()->doSynchronizeCache());
1742}
1743
1744IOReturn
1745IOBlockStorageDriver::unmap(IOService *       client,
1746                            IOStorageExtent * extents,
1747                            UInt32            extentsCount,
1748                            UInt32            options)
1749{
1750    UInt32                       extentsIndex;
1751    IOBlockStorageDeviceExtent * extentsOut;
1752    UInt32                       extentsOutCount;
1753
1754    assert( sizeof( IOStorageExtent ) == sizeof( IOBlockStorageDeviceExtent ) );
1755
1756    if ( options )
1757    {
1758        return kIOReturnBadArgument;
1759    }
1760
1761    extentsOut      = ( IOBlockStorageDeviceExtent * ) extents;
1762    extentsOutCount = 0;
1763
1764    for ( extentsIndex = 0; extentsIndex < extentsCount; extentsIndex++ )
1765    {
1766        UInt64 blockStart;
1767        UInt64 blockCount;
1768
1769        blockStart = ( extents[ extentsIndex ].byteStart + _mediaBlockSize - 1 ) / _mediaBlockSize;
1770        blockCount = ( extents[ extentsIndex ].byteStart + extents[ extentsIndex ].byteCount ) / _mediaBlockSize;
1771
1772        if ( blockCount > blockStart )
1773        {
1774            blockCount = blockCount - blockStart;
1775
1776            extentsOut[ extentsOutCount ].blockStart = blockStart;
1777            extentsOut[ extentsOutCount ].blockCount = blockCount;
1778
1779            extentsOutCount++;
1780        }
1781    }
1782
1783    if ( extentsOutCount )
1784    {
1785        return getProvider( )->doUnmap( extentsOut, extentsOutCount, options );
1786    }
1787    else
1788    {
1789        return kIOReturnSuccess;
1790    }
1791}
1792
1793bool IOBlockStorageDriver::lockPhysicalExtents(IOService * client)
1794{
1795    //
1796    // Lock the contents of the storage object against relocation temporarily,
1797    // for the purpose of getting physical extents.
1798    //
1799
1800    return(true);
1801}
1802
1803IOStorage * IOBlockStorageDriver::copyPhysicalExtent(IOService * client,
1804                                                     UInt64 *    byteStart,
1805                                                     UInt64 *    byteCount)
1806{
1807    //
1808    // Convert the specified byte offset into a physical byte offset, relative
1809    // to a physical storage object.  This call should only be made within the
1810    // context of lockPhysicalExtents().
1811    //
1812
1813    IOMedia *m;
1814
1815    lockForArbitration();
1816    m = _mediaObject;
1817    if (m) {
1818        m->retain();
1819    }
1820    unlockForArbitration();
1821
1822    return(m);
1823}
1824
1825void IOBlockStorageDriver::unlockPhysicalExtents(IOService * client)
1826{
1827    //
1828    // Unlock the contents of the storage object for relocation again.  This
1829    // call must balance a successful call to lockPhysicalExtents().
1830    //
1831
1832    return;
1833}
1834
1835IOReturn
1836IOBlockStorageDriver::setPriority(IOService *       client,
1837                                  IOStorageExtent * extents,
1838                                  UInt32            extentsCount,
1839                                  IOStoragePriority priority)
1840{
1841    UInt32                       extentsIndex;
1842    IOBlockStorageDeviceExtent * extentsOut;
1843
1844    assert( sizeof( IOStorageExtent ) == sizeof( IOBlockStorageDeviceExtent ) );
1845
1846    extentsOut = ( IOBlockStorageDeviceExtent * ) extents;
1847
1848    for ( extentsIndex = 0; extentsIndex < extentsCount; extentsIndex++ )
1849    {
1850        UInt64 blockStart;
1851        UInt64 blockCount;
1852
1853        blockStart = extents[ extentsIndex ].byteStart / _mediaBlockSize;
1854        blockCount = extents[ extentsIndex ].byteCount / _mediaBlockSize;
1855
1856        extentsOut[ extentsIndex ].blockStart = blockStart;
1857        extentsOut[ extentsIndex ].blockCount = blockCount;
1858    }
1859
1860///w:start
1861#if TARGET_OS_EMBEDDED
1862    if ( _expansionData->reserved0000 )
1863    {
1864        priority = DK_PRIORITY_TO_TIER( priority );
1865    }
1866#endif /* TARGET_OS_EMBEDDED */
1867///w:stop
1868    return getProvider( )->doSetPriority( extentsOut, extentsCount, priority );
1869}
1870
1871bool
1872IOBlockStorageDriver::validateNewMedia(void)
1873{
1874    return(true);
1875}
1876
1877// -----------------------------------------------------------------------------
1878// Deblocker Implementation
1879
1880#include <IOKit/IOBufferMemoryDescriptor.h>
1881
1882class IODeblocker : public IOMemoryDescriptor
1883{
1884    OSDeclareDefaultStructors(IODeblocker);
1885
1886protected:
1887
1888    UInt64                     _blockSize;
1889
1890    struct
1891    {
1892        IOMemoryDescriptor * buffer;
1893        UInt32               offset;
1894        UInt32               length;
1895    }                          _chunks[3];
1896    UInt32                     _chunksCount;
1897
1898    IOBufferMemoryDescriptor * _excessBuffer;
1899    UInt64                     _excessCountFinal;
1900    UInt64                     _excessCountStart;
1901
1902    IOMemoryDescriptor *       _requestBuffer;
1903    IOStorageAttributes        _requestAttributes;
1904    IOStorageCompletion        _requestCompletion;
1905    void *                     _requestContext;
1906    UInt64                     _requestCount;
1907    bool                       _requestIsOneBlock;
1908    UInt64                     _requestStart;
1909
1910    UInt64                     _byteStart;
1911
1912    thread_call_t              _threadCallback;
1913
1914    enum
1915    {
1916        kStageInit,
1917        kStagePrepareExcessStart,
1918        kStagePrepareExcessFinal,
1919        kStageLast,
1920        kStageDone
1921    } _stage;
1922
1923    virtual void free();
1924
1925public:
1926
1927    static IODeblocker * withBlockSize(
1928                                  UInt64                blockSize,
1929                                  UInt64                withRequestStart,
1930                                  IOMemoryDescriptor *  withRequestBuffer,
1931                                  IOStorageAttributes * withRequestAttributes,
1932                                  IOStorageCompletion * withRequestCompletion,
1933                                  void *                withRequestContext );
1934
1935    virtual bool initWithBlockSize(
1936                                  UInt64                blockSize,
1937                                  UInt64                withRequestStart,
1938                                  IOMemoryDescriptor *  withRequestBuffer,
1939                                  IOStorageAttributes * withRequestAttributes,
1940                                  IOStorageCompletion * withRequestCompletion,
1941                                  void *                withRequestContext );
1942
1943    virtual addr64_t getPhysicalSegment( IOByteCount   offset,
1944                                         IOByteCount * length,
1945                                         IOOptionBits  options = 0 );
1946
1947    virtual IOReturn prepare(IODirection forDirection = kIODirectionNone);
1948
1949    virtual IOReturn complete(IODirection forDirection = kIODirectionNone);
1950
1951    virtual bool getNextStage();
1952
1953    virtual IOStorageAttributes * getRequestAttributes();
1954
1955    virtual IOStorageCompletion * getRequestCompletion(UInt64 * actualByteCount);
1956
1957    virtual IOMemoryDescriptor * getRequestBuffer();
1958
1959    virtual void * getRequestContext();
1960
1961    virtual UInt64 getByteStart();
1962
1963    virtual thread_call_t getThreadCallback();
1964
1965    virtual bool setThreadCallback(thread_call_func_t callback);
1966};
1967
1968#undef  super
1969#define super IOMemoryDescriptor
1970OSDefineMetaClassAndStructors(IODeblocker, IOMemoryDescriptor)
1971
1972IODeblocker * IODeblocker::withBlockSize(
1973                                  UInt64                blockSize,
1974                                  UInt64                withRequestStart,
1975                                  IOMemoryDescriptor *  withRequestBuffer,
1976                                  IOStorageAttributes * withRequestAttributes,
1977                                  IOStorageCompletion * withRequestCompletion,
1978                                  void *                withRequestContext )
1979{
1980    //
1981    // Create a new IODeblocker.
1982    //
1983
1984    IODeblocker * me = new IODeblocker;
1985
1986    if ( me && me->initWithBlockSize(
1987                /* blockSize               */ blockSize,
1988                /* withRequestStart        */ withRequestStart,
1989                /* withRequestBuffer       */ withRequestBuffer,
1990                /* withRequestAttributes   */ withRequestAttributes,
1991                /* withRequestCompletion   */ withRequestCompletion,
1992                /* withRequestContext      */ withRequestContext ) == false )
1993    {
1994	    me->release();
1995	    me = 0;
1996    }
1997
1998    return me;
1999}
2000
2001bool IODeblocker::initWithBlockSize(
2002                                  UInt64                blockSize,
2003                                  UInt64                withRequestStart,
2004                                  IOMemoryDescriptor *  withRequestBuffer,
2005                                  IOStorageAttributes * withRequestAttributes,
2006                                  IOStorageCompletion * withRequestCompletion,
2007                                  void *                withRequestContext )
2008{
2009    //
2010    // Initialize an IODeblocker.
2011    //
2012    // _excessCountStart = byte count from media boundary to start of request
2013    // _excessCountFinal = byte count from end of request to a media boundary
2014    //
2015
2016    UInt32 excessBufferSize = 0;
2017
2018    // Ask our superclass' opinion.
2019
2020    if ( super::init() == false )  return false;
2021
2022    // Initialize our minimal state.
2023
2024    _blockSize         = blockSize;
2025    _chunksCount       = 0;
2026    _flags             = kIODirectionNone;
2027    _length            = 0;
2028
2029    _requestBuffer     = withRequestBuffer;
2030    _requestBuffer->retain();
2031
2032    if (withRequestAttributes)  _requestAttributes = *withRequestAttributes;
2033    if (withRequestCompletion)  _requestCompletion = *withRequestCompletion;
2034
2035    _requestContext    = withRequestContext;
2036    _requestCount      = withRequestBuffer->getLength();
2037    _requestStart      = withRequestStart;
2038
2039    _excessCountStart  = (withRequestStart                ) % blockSize;
2040    _excessCountFinal  = (withRequestStart + _requestCount) % blockSize;
2041    if ( _excessCountFinal )  _excessCountFinal = blockSize - _excessCountFinal;
2042
2043    _requestIsOneBlock = (_excessCountStart + _requestCount <= blockSize);
2044
2045    // Determine the necessary size for our scratch buffer.
2046
2047    switch ( _requestBuffer->getDirection() )
2048    {
2049        case kIODirectionIn:                                           // (read)
2050        {
2051            excessBufferSize = max(_excessCountStart, _excessCountFinal);
2052        } break;
2053
2054        case kIODirectionOut:                                         // (write)
2055        {
2056            if ( _excessCountStart )  excessBufferSize += blockSize;
2057            if ( _excessCountFinal )  excessBufferSize += blockSize;
2058
2059            // If there is excess both ends of the original request, but both
2060            // ends reside within the same media block, then we could shorten
2061            // our buffer size to just one block.
2062
2063            if ( _excessCountStart && _excessCountFinal && _requestIsOneBlock )
2064            {
2065                excessBufferSize -= blockSize;
2066            }
2067        } break;
2068
2069        default:
2070        {
2071            assert(0);
2072        } break;
2073    }
2074
2075    // Allocate our scratch buffer.
2076
2077    if ( excessBufferSize )
2078    {
2079        _excessBuffer = IOBufferMemoryDescriptor::withCapacity(
2080                                         /* capacity      */ excessBufferSize,
2081                                         /* withDirection */ kIODirectionNone );
2082        if ( _excessBuffer == 0 )  return false;
2083    }
2084
2085    return true;
2086}
2087
2088void IODeblocker::free()
2089{
2090    //
2091    // Free all of this object's outstanding resources.
2092    //
2093
2094    if ( _requestBuffer )  _requestBuffer->release();
2095    if ( _excessBuffer )  _excessBuffer->release();
2096    if ( _threadCallback )  thread_call_free(_threadCallback);
2097
2098    super::free();
2099}
2100
2101IOReturn IODeblocker::prepare(IODirection forDirection)
2102{
2103    //
2104    // Prepare the memory for an I/O transfer.
2105    //
2106    // This involves paging in the memory and wiring it down for the duration
2107    // of the transfer.  The complete() method finishes the processing of the
2108    // memory after the I/O transfer finishes.
2109    //
2110
2111    unsigned index;
2112    IOReturn status = kIOReturnInternalError;
2113    IOReturn statusUndo;
2114
2115    if ( forDirection == kIODirectionNone )
2116    {
2117        forDirection = (IODirection) (_flags & kIOMemoryDirectionMask);
2118    }
2119
2120    for ( index = 0; index < _chunksCount; index++ )
2121    {
2122        status = _chunks[index].buffer->prepare(forDirection);
2123        if ( status != kIOReturnSuccess )  break;
2124    }
2125
2126    if ( status != kIOReturnSuccess )
2127    {
2128        for ( unsigned indexUndo = 0; indexUndo <= index; indexUndo++ )
2129        {
2130            statusUndo = _chunks[index].buffer->complete(forDirection);
2131            assert(statusUndo == kIOReturnSuccess);
2132        }
2133    }
2134
2135    return status;
2136}
2137
2138IOReturn IODeblocker::complete(IODirection forDirection)
2139{
2140    //
2141    // Complete processing of the memory after an I/O transfer finishes.
2142    //
2143    // This method shouldn't be called unless a prepare() was previously issued;
2144    // the prepare() and complete() must occur in pairs, before and after an I/O
2145    // transfer.
2146    //
2147
2148    IOReturn status;
2149    IOReturn statusFinal = kIOReturnSuccess;
2150
2151    if ( forDirection == kIODirectionNone )
2152    {
2153        forDirection = (IODirection) (_flags & kIOMemoryDirectionMask);
2154    }
2155
2156    for ( unsigned index = 0; index < _chunksCount; index++ )
2157    {
2158        status = _chunks[index].buffer->complete(forDirection);
2159        if ( status != kIOReturnSuccess )  statusFinal = status;
2160        assert(status == kIOReturnSuccess);
2161    }
2162
2163    return statusFinal;
2164}
2165
2166addr64_t IODeblocker::getPhysicalSegment( IOByteCount   offset,
2167                                          IOByteCount * length,
2168                                          IOOptionBits  options )
2169{
2170    //
2171    // This method returns the physical address of the byte at the given offset
2172    // into the memory,  and optionally the length of the physically contiguous
2173    // segment from that offset.
2174    //
2175
2176    assert(offset <= _length);
2177
2178    for ( unsigned index = 0; index < _chunksCount; index++ )
2179    {
2180        if ( offset < _chunks[index].length )
2181        {
2182            addr64_t address;
2183            address = _chunks[index].buffer->getPhysicalSegment(
2184                                    /* offset  */ offset + _chunks[index].offset,
2185                                    /* length  */ length,
2186                                    /* options */ options );
2187            if ( length )  *length = min(*length, _chunks[index].length);
2188            return address;
2189        }
2190        offset -= _chunks[index].length;
2191    }
2192
2193    if ( length )  *length = 0;
2194
2195    return 0;
2196}
2197
2198bool IODeblocker::getNextStage()
2199{
2200    //
2201    // Obtain the next stage of the transfer.   The transfer buffer will be the
2202    // deblocker object itself and the byte start will be returned in getByteStart().
2203    //
2204    // This method must not be called if the current stage failed with an error
2205    // or a short byte count, but instead getRequestCompletion() must be called
2206    // to adjust the status and actual byte count (with respect to the original
2207    // request) and return the original request's completion routine.  The same
2208    // call to getRequestCompletion() should also be done if the getNextStage()
2209    // method returns false.
2210    //
2211
2212    _chunksCount = 0;
2213    _flags       = (_flags & ~kIOMemoryDirectionMask) | kIODirectionNone;
2214    _length      = 0;
2215
2216    switch ( _requestBuffer->getDirection() )
2217    {
2218        case kIODirectionIn:                                           // (read)
2219        {
2220            switch ( _stage )
2221            {
2222                case kStageInit:
2223                {
2224                    _stage     = kStageLast;
2225                    _excessBuffer->setDirection(kIODirectionIn);
2226                    _flags     = (_flags & ~kIOMemoryDirectionMask) | kIODirectionIn;
2227                    _byteStart = _requestStart - _excessCountStart;
2228
2229                    if ( _excessCountStart )
2230                    {
2231                        _chunks[_chunksCount].buffer = _excessBuffer;
2232                        _chunks[_chunksCount].offset = 0;
2233                        _chunks[_chunksCount].length = _excessCountStart;
2234                        _chunksCount++;
2235                    }
2236
2237                    _chunks[_chunksCount].buffer = _requestBuffer;
2238                    _chunks[_chunksCount].offset = 0;
2239                    _chunks[_chunksCount].length = _requestBuffer->getLength();
2240                    _chunksCount++;
2241
2242                    if ( _excessCountFinal )
2243                    {
2244                        _chunks[_chunksCount].buffer = _excessBuffer;
2245                        _chunks[_chunksCount].offset = 0;
2246                        _chunks[_chunksCount].length = _excessCountFinal;
2247                        _chunksCount++;
2248                    }
2249                } break;
2250
2251                case kStageLast:
2252                {
2253                    _stage = kStageDone;
2254                } break;
2255
2256                default:
2257                {
2258                    assert(0);
2259                } break;
2260            } // (switch)
2261        } break;
2262
2263        case kIODirectionOut:                                         // (write)
2264        {
2265            switch ( _stage )
2266            {
2267                case kStageInit:
2268                {
2269                    if ( _excessCountStart )
2270                    {
2271                        _stage = kStagePrepareExcessStart;
2272                        _excessBuffer->setDirection(kIODirectionIn);
2273                        _flags     = (_flags & ~kIOMemoryDirectionMask) | kIODirectionIn;
2274                        _byteStart = _requestStart - _excessCountStart;
2275
2276                        _chunks[_chunksCount].buffer = _excessBuffer;
2277                        _chunks[_chunksCount].offset = 0;
2278                        _chunks[_chunksCount].length = _blockSize;
2279                        _chunksCount++;
2280                        break;
2281                    }
2282                } // (fall thru)
2283
2284                case kStagePrepareExcessStart:
2285                {
2286                    if ( _excessCountFinal )
2287                    {
2288                        // We do not issue this stage if the original transfer
2289                        // resides within one media block, and we already read
2290                        // that block into our buffer in the previous stage.
2291
2292                        if ( !_excessCountStart || !_requestIsOneBlock )
2293                        {
2294                            _stage = kStagePrepareExcessFinal;
2295                            _excessBuffer->setDirection(kIODirectionIn);
2296                            _flags     = (_flags & ~kIOMemoryDirectionMask) | kIODirectionIn;
2297                            _byteStart = _requestStart + _requestCount +
2298                                         _excessCountFinal - _blockSize;
2299
2300                            _chunks[_chunksCount].buffer = _excessBuffer;
2301                            _chunks[_chunksCount].offset = (_requestIsOneBlock)
2302                                                           ? 0
2303                                                           : (_excessCountStart)
2304                                                             ? _blockSize
2305                                                             : 0;
2306                            _chunks[_chunksCount].length = _blockSize;
2307                            _chunksCount++;
2308                            break;
2309                        }
2310                    }
2311                } // (fall thru)
2312
2313                case kStagePrepareExcessFinal:
2314                {
2315                    _stage     = kStageLast;
2316                    _excessBuffer->setDirection(kIODirectionOut);
2317                    _flags     = (_flags & ~kIOMemoryDirectionMask) | kIODirectionOut;
2318                    _byteStart = _requestStart - _excessCountStart;
2319
2320                    if ( _excessCountStart )
2321                    {
2322                        _chunks[_chunksCount].buffer = _excessBuffer;
2323                        _chunks[_chunksCount].offset = 0;
2324                        _chunks[_chunksCount].length = _excessCountStart;
2325                        _chunksCount++;
2326                    }
2327
2328                    _chunks[_chunksCount].buffer = _requestBuffer;
2329                    _chunks[_chunksCount].offset = 0;
2330                    _chunks[_chunksCount].length = _requestBuffer->getLength();
2331                    _chunksCount++;
2332
2333                    if ( _excessCountFinal )
2334                    {
2335                        _chunks[_chunksCount].buffer = _excessBuffer;
2336                        _chunks[_chunksCount].offset = (_requestIsOneBlock)
2337                                                       ? 0
2338                                                       : (_excessCountStart)
2339                                                         ? _blockSize
2340                                                         : 0;
2341                        _chunks[_chunksCount].offset += ( _blockSize -
2342                                                          _excessCountFinal );
2343                        _chunks[_chunksCount].length = _excessCountFinal;
2344                        _chunksCount++;
2345                    }
2346                } break;
2347
2348                case kStageLast:
2349                {
2350                    _stage = kStageDone;
2351                } break;
2352
2353                default:
2354                {
2355                    assert(0);
2356                } break;
2357            } // (switch)
2358        } break;
2359
2360        default:
2361        {
2362            assert(0);
2363        } break;
2364    } // (switch)
2365
2366    // Determine whether we have an abort or completion condition.
2367
2368    if ( _chunksCount == 0 )  return false;
2369
2370    // Compute the total length of the descriptor over all chunks.
2371
2372    for ( unsigned index = 0; index < _chunksCount; index++ )
2373    {
2374        _length += _chunks[index].length;
2375    }
2376
2377    return true;
2378}
2379
2380IOStorageAttributes * IODeblocker::getRequestAttributes()
2381{
2382    //
2383    // Obtain the attributes for the original request.
2384    //
2385
2386    return &_requestAttributes;
2387}
2388
2389IOStorageCompletion * IODeblocker::getRequestCompletion(UInt64 * actualByteCount)
2390{
2391    //
2392    // Obtain the completion information for the original request, taking
2393    // into account the actual byte count of the current stage.
2394    //
2395
2396    switch ( _stage )
2397    {
2398        case kStageInit:                                       // (inital stage)
2399        {
2400            *actualByteCount = 0;
2401        } break;
2402
2403        case kStagePrepareExcessStart:              // (write preparation stage)
2404        case kStagePrepareExcessFinal:
2405        {
2406            *actualByteCount = 0;
2407        } break;
2408
2409        case kStageLast:                                         // (last stage)
2410        case kStageDone:
2411        {
2412            if ( *actualByteCount > _excessCountStart )
2413                *actualByteCount -= _excessCountStart;
2414            else
2415                *actualByteCount = 0;
2416
2417            if ( *actualByteCount > _requestBuffer->getLength() )
2418                *actualByteCount = _requestBuffer->getLength();
2419        } break;
2420
2421        default:
2422        {
2423            assert(0);
2424        } break;
2425    }
2426
2427    return &_requestCompletion;
2428}
2429
2430IOMemoryDescriptor * IODeblocker::getRequestBuffer()
2431{
2432    //
2433    // Obtain the buffer for the original request.
2434    //
2435
2436    return _requestBuffer;
2437}
2438
2439void * IODeblocker::getRequestContext()
2440{
2441    //
2442    // Obtain the context for the original request.
2443    //
2444
2445    return _requestContext;
2446}
2447
2448UInt64 IODeblocker::getByteStart()
2449{
2450    //
2451    // Obtain the byte start for the current stage.
2452    //
2453
2454    return _byteStart;
2455}
2456
2457thread_call_t IODeblocker::getThreadCallback()
2458{
2459    //
2460    // Obtain the thread callback.
2461    //
2462
2463    return _threadCallback;
2464}
2465
2466bool IODeblocker::setThreadCallback(thread_call_func_t callback)
2467{
2468    //
2469    // Allocate a thread callback.
2470    //
2471
2472    _threadCallback = thread_call_allocate(callback, this);
2473
2474    return _threadCallback ? true : false;
2475}
2476
2477void IOBlockStorageDriver::deblockRequest(
2478                                     UInt64                          byteStart,
2479                                     IOMemoryDescriptor *            buffer,
2480#ifdef __LP64__
2481                                     IOStorageAttributes *           attributes,
2482                                     IOStorageCompletion *           completion,
2483#else /* !__LP64__ */
2484                                     IOStorageCompletion             completion,
2485#endif /* !__LP64__ */
2486                                     IOBlockStorageDriver::Context * context )
2487{
2488    //
2489    // The deblockRequest method checks to see if the incoming request rests
2490    // on the media's block boundaries, and if not, deblocks it.  Deblocking
2491    // involves rounding out the request to the nearest block boundaries and
2492    // transferring the excess bytes into a scratch buffer.
2493    //
2494    // This method is part of a sequence of methods invoked for each read/write
2495    // request.  The first is prepareRequest, which allocates and prepares some
2496    // context for the transfer; the second is deblockRequest, which aligns the
2497    // transfer at the media's block boundaries; third is breakUpRequest, which
2498    // breaks up the transfer into multiple sub-transfers when certain hardware
2499    // constraints are exceeded; fourth is executeRequest, which implements the
2500    // actual transfer from the block storage device.
2501    //
2502    // The current implementation of deblockRequest is asynchronous.
2503    //
2504
2505    IODeblocker * deblocker;
2506
2507    // If the request is aligned with the media's block boundaries, we
2508    // do short-circuit the deblocker and call breakUpRequest directly.
2509
2510    if ( (byteStart           % context->block.size) == 0 &&
2511         (buffer->getLength() % context->block.size) == 0 )
2512    {
2513#ifdef __LP64__
2514        breakUpRequest(byteStart, buffer, attributes, completion, context);
2515#else /* !__LP64__ */
2516        breakUpRequest(byteStart, buffer, completion, context);
2517#endif /* !__LP64__ */
2518        return;
2519    }
2520
2521    // Build a deblocker object.
2522
2523    deblocker = IODeblocker::withBlockSize(
2524                                /* blockSize             */ context->block.size,
2525                                /* withRequestStart      */ byteStart,
2526                                /* withRequestBuffer     */ buffer,
2527#ifdef __LP64__
2528                                /* withRequestAttributes */ attributes,
2529                                /* withRequestCompletion */ completion,
2530#else /* !__LP64__ */
2531                                /* withRequestAttributes */ NULL,
2532                                /* withRequestCompletion */ &completion,
2533#endif /* !__LP64__ */
2534                                /* withRequestContext    */ context );
2535
2536    if ( deblocker == 0 )
2537    {
2538        complete(completion, kIOReturnNoMemory);
2539        return;
2540    }
2541
2542    // This implementation of the deblocker permits only one read-modify-write
2543    // at any given time.  Note that other write requests can, and do, proceed
2544    // simultaneously so long as they do not require the deblocker.
2545
2546    if ( buffer->getDirection() == kIODirectionOut )
2547    {
2548        IOLockLock(_deblockRequestWriteLock);
2549
2550        _deblockRequestWriteLockCount++;
2551
2552        if ( _deblockRequestWriteLockCount > 1 )
2553        {
2554            while ( IOLockSleep( /* lock          */ _deblockRequestWriteLock,
2555                                 /* event         */ _deblockRequestWriteLock,
2556                                 /* interruptible */ THREAD_UNINT ) );
2557        }
2558
2559        IOLockUnlock(_deblockRequestWriteLock);
2560    }
2561
2562    // Execute the transfer (for the next stage).
2563
2564    deblockRequestCompletion(this, deblocker, kIOReturnSuccess, 0);
2565}
2566
2567void IOBlockStorageDriver::deblockRequestCompletion( void *   target,
2568                                                     void *   parameter,
2569                                                     IOReturn status,
2570                                                     UInt64   actualByteCount )
2571{
2572    //
2573    // This is the completion routine for the aligned deblocker subrequests.
2574    // It verifies the success of the just-completed stage,  transitions to
2575    // the next stage, then builds and issues a transfer for the next stage.
2576    //
2577
2578    thread_call_t          callback;
2579    IODeblocker *          deblocker = (IODeblocker          *) parameter;
2580    IOBlockStorageDriver * driver    = (IOBlockStorageDriver *) target;
2581
2582    // Allocate a thread callback.
2583
2584    callback = deblocker->getThreadCallback();
2585
2586#if !TARGET_OS_EMBEDDED
2587    if ( callback == 0 )
2588    {
2589        if ( deblocker->setThreadCallback(deblockRequestExecute) == false )
2590        {
2591            status = kIOReturnNoMemory;
2592        }
2593    }
2594#endif /* !TARGET_OS_EMBEDDED */
2595
2596    // Determine whether an error occurred or whether there are no more stages.
2597
2598    if ( actualByteCount            < deblocker->getLength() ||
2599         status                    != kIOReturnSuccess       ||
2600         deblocker->getNextStage() == false                  )
2601    {
2602        IOStorageCompletion * completion;
2603
2604        // Unlock the write-lock in order to allow the next write to proceed.
2605
2606        if ( deblocker->getRequestBuffer()->getDirection() == kIODirectionOut )
2607        {
2608            IOLockLock(driver->_deblockRequestWriteLock);
2609
2610            driver->_deblockRequestWriteLockCount--;
2611
2612            if ( driver->_deblockRequestWriteLockCount > 0 )
2613            {
2614                IOLockWakeup( /* lock  */ driver->_deblockRequestWriteLock,
2615                              /* event */ driver->_deblockRequestWriteLock,
2616                              /* one   */ true );
2617            }
2618
2619            IOLockUnlock(driver->_deblockRequestWriteLock);
2620        }
2621
2622        // Obtain the completion information for the original request, taking
2623        // into account the actual byte count of the current stage.
2624
2625        completion = deblocker->getRequestCompletion(&actualByteCount);
2626
2627        // Complete the original request.
2628
2629        IOStorage::complete(completion, status, actualByteCount);
2630
2631        // Release our resources.
2632
2633        deblocker->release();
2634    }
2635    else
2636    {
2637        // Execute the transfer (for the next stage).
2638
2639        if ( callback )
2640        {
2641            thread_call_enter1(callback, driver);
2642        }
2643        else
2644        {
2645            deblockRequestExecute(deblocker, driver);
2646        }
2647    }
2648}
2649
2650void IOBlockStorageDriver::deblockRequestExecute(void * parameter, void * target)
2651{
2652    //
2653    // Execute the transfer (for the next stage).
2654    //
2655
2656    IOStorageAttributes *  attributes;
2657    UInt64                 byteStart;
2658    IOStorageCompletion    completion;
2659    Context *              context;
2660    IODeblocker *          deblocker = (IODeblocker          *) parameter;
2661    IOBlockStorageDriver * driver    = (IOBlockStorageDriver *) target;
2662
2663    attributes = deblocker->getRequestAttributes();
2664
2665    byteStart = deblocker->getByteStart();
2666
2667    completion.target    = driver;
2668    completion.action    = deblockRequestCompletion;
2669    completion.parameter = deblocker;
2670
2671    context = (Context *) deblocker->getRequestContext();
2672
2673#ifdef __LP64__
2674    driver->breakUpRequest(byteStart, deblocker, attributes, &completion, context);
2675#else /* !__LP64__ */
2676    driver->breakUpRequest(byteStart, deblocker, completion, context);
2677#endif /* !__LP64__ */
2678}
2679
2680// -----------------------------------------------------------------------------
2681// Breaker Implementation
2682
2683class IOBreaker : public IOSubMemoryDescriptor
2684{
2685    OSDeclareDefaultStructors(IOBreaker);
2686
2687protected:
2688
2689    UInt64                     _breakSize;
2690
2691    UInt64                     _maximumBlockCount;
2692    UInt64                     _maximumByteCount;
2693    UInt64                     _maximumSegmentCount;
2694    UInt64                     _maximumSegmentByteCount;
2695    UInt64                     _minimumSegmentAlignmentByteCount;
2696    UInt64                     _maximumSegmentWidthByteCount;
2697
2698    UInt64                     _requestBlockSize;
2699    IOMemoryDescriptor *       _requestBuffer;
2700    IOStorageAttributes        _requestAttributes;
2701    IOStorageCompletion        _requestCompletion;
2702    void *                     _requestContext;
2703    UInt64                     _requestCount;
2704    UInt64                     _requestStart;
2705
2706    UInt64                     _byteStart;
2707
2708    thread_call_t              _threadCallback;
2709
2710    virtual void free();
2711
2712public:
2713
2714    static UInt64 getBreakSize(
2715                              UInt64               withMaximumBlockCount,
2716                              UInt64               withMaximumByteCount,
2717                              UInt64               withMaximumSegmentCount,
2718                              UInt64               withMaximumSegmentByteCount,
2719                              UInt64               withMinimumSegmentAlignmentByteCount,
2720                              UInt64               withMaximumSegmentWidthByteCount,
2721                              UInt64               withRequestBlockSize,
2722                              IOMemoryDescriptor * withRequestBuffer,
2723                              UInt64               withRequestBufferOffset );
2724
2725    static IOBreaker * withBreakSize(
2726                              UInt64                breakSize,
2727                              UInt64                withMaximumBlockCount,
2728                              UInt64                withMaximumByteCount,
2729                              UInt64                withMaximumSegmentCount,
2730                              UInt64                withMaximumSegmentByteCount,
2731                              UInt64                withMinimumSegmentAlignmentByteCount,
2732                              UInt64                withMaximumSegmentWidthByteCount,
2733                              UInt64                withRequestBlockSize,
2734                              UInt64                withRequestStart,
2735                              IOMemoryDescriptor *  withRequestBuffer,
2736                              IOStorageAttributes * withRequestAttributes,
2737                              IOStorageCompletion * withRequestCompletion,
2738                              void *                withRequestContext );
2739
2740    virtual bool initWithBreakSize(
2741                              UInt64                breakSize,
2742                              UInt64                withMaximumBlockCount,
2743                              UInt64                withMaximumByteCount,
2744                              UInt64                withMaximumSegmentCount,
2745                              UInt64                withMaximumSegmentByteCount,
2746                              UInt64                withMinimumSegmentAlignmentByteCount,
2747                              UInt64                withMaximumSegmentWidthByteCount,
2748                              UInt64                withRequestBlockSize,
2749                              UInt64                withRequestStart,
2750                              IOMemoryDescriptor *  withRequestBuffer,
2751                              IOStorageAttributes * withRequestAttributes,
2752                              IOStorageCompletion * withRequestCompletion,
2753                              void *                withRequestContext );
2754
2755    virtual bool getNextStage();
2756
2757    virtual IOStorageAttributes * getRequestAttributes();
2758
2759    virtual IOStorageCompletion * getRequestCompletion(UInt64 * actualByteCount);
2760
2761    virtual IOMemoryDescriptor * getRequestBuffer();
2762
2763    virtual void * getRequestContext();
2764
2765    virtual UInt64 getByteStart();
2766
2767    virtual thread_call_t getThreadCallback();
2768
2769    virtual bool setThreadCallback(thread_call_func_t callback);
2770};
2771
2772#undef  super
2773#define super IOSubMemoryDescriptor
2774OSDefineMetaClassAndStructors(IOBreaker, IOSubMemoryDescriptor)
2775
2776UInt64 IOBreaker::getBreakSize(
2777                              UInt64               withMaximumBlockCount,
2778                              UInt64               withMaximumByteCount,
2779                              UInt64               withMaximumSegmentCount,
2780                              UInt64               withMaximumSegmentByteCount,
2781                              UInt64               withMinimumSegmentAlignmentByteCount,
2782                              UInt64               withMaximumSegmentWidthByteCount,
2783                              UInt64               withRequestBlockSize,
2784                              IOMemoryDescriptor * withRequestBuffer,
2785                              UInt64               withRequestBufferOffset )
2786{
2787    //
2788    // Determine where the next break point is given our constraints.
2789    //
2790
2791    UInt64               breakSize    = 0;
2792    IOMemoryDescriptor * buffer       = withRequestBuffer;
2793    IOByteCount          bufferLength = withRequestBuffer->getLength();
2794    IOByteCount          bufferOffset = withRequestBufferOffset;
2795    addr64_t             chunk        = 0;
2796    UInt32               chunkSize    = 0;
2797    addr64_t             segment      = 0;
2798    UInt32               segmentCount = 0;
2799    IOByteCount          segmentSize  = 0;
2800
2801    // Prepare segment alignment mask.
2802
2803    if ( withMinimumSegmentAlignmentByteCount )
2804    {
2805        withMinimumSegmentAlignmentByteCount--;
2806    }
2807
2808    // Constrain block count.
2809
2810    if ( withMaximumBlockCount )
2811    {
2812        UInt64 blockCountInBytes;
2813
2814        blockCountInBytes = withMaximumBlockCount * withRequestBlockSize;
2815
2816        if ( withMaximumByteCount )
2817        {
2818            withMaximumByteCount = min(blockCountInBytes, withMaximumByteCount);
2819        }
2820        else
2821        {
2822            withMaximumByteCount = blockCountInBytes;
2823        }
2824    }
2825
2826    // Scan the buffer's segments.
2827
2828    while ( segment || bufferOffset < bufferLength )
2829    {
2830        // Obtain a new segment.
2831
2832        if ( segment == 0 )
2833        {
2834            segment = buffer->getPhysicalSegment(bufferOffset, &segmentSize, 0);
2835
2836            assert(segment);
2837            assert(segmentSize);
2838
2839            bufferOffset += segmentSize;
2840        }
2841
2842        // Fold in a segment.
2843
2844        if ( chunk == 0 )
2845        {
2846            breakSize  += segmentSize;
2847
2848            chunk       = segment;
2849            chunkSize   = segmentSize;
2850
2851            segment     = 0;
2852            segmentSize = 0;
2853
2854            segmentCount++;
2855        }
2856        else if ( chunk + chunkSize == segment )
2857        {
2858            breakSize  += segmentSize;
2859            chunkSize  += segmentSize;
2860
2861            segment     = 0;
2862            segmentSize = 0;
2863        }
2864
2865        // Trim a complete segment.
2866
2867        if ( segment == 0 )
2868        {
2869            // Constrain segment byte count.
2870
2871            if ( withMaximumSegmentByteCount )
2872            {
2873                if ( chunkSize > withMaximumSegmentByteCount )
2874                {
2875                    segmentSize = chunkSize - withMaximumSegmentByteCount;
2876                }
2877            }
2878
2879            // Constrain segment alignment byte count.
2880
2881            if ( withMinimumSegmentAlignmentByteCount )
2882            {
2883                if ( ( chunk & withMinimumSegmentAlignmentByteCount ) || ( chunkSize & withMinimumSegmentAlignmentByteCount ) )
2884                {
2885                    if ( chunkSize > PAGE_SIZE )
2886                    {
2887                        segmentSize = max(chunkSize - PAGE_SIZE, segmentSize);
2888                    }
2889                }
2890            }
2891
2892            // Constrain segment width byte count.
2893
2894            if ( withMaximumSegmentWidthByteCount )
2895            {
2896                if ( chunk >= withMaximumSegmentWidthByteCount )
2897                {
2898                    if ( chunkSize > PAGE_SIZE )
2899                    {
2900                        segmentSize = max(chunkSize - PAGE_SIZE, segmentSize);
2901                    }
2902                }
2903                else if ( chunk + chunkSize > withMaximumSegmentWidthByteCount )
2904                {
2905                    segmentSize = max(chunk + chunkSize - withMaximumSegmentWidthByteCount, segmentSize);
2906                }
2907            }
2908
2909            if ( segmentSize )
2910            {
2911                segment     = chunk + chunkSize - segmentSize;
2912
2913                breakSize  -= segmentSize;
2914                chunkSize  -= segmentSize;
2915            }
2916
2917            // Constrain byte count.
2918
2919            if ( withMaximumByteCount )
2920            {
2921                if ( breakSize >= withMaximumByteCount )
2922                {
2923                    breakSize = withMaximumByteCount;
2924                    break;
2925                }
2926            }
2927        }
2928
2929        // Commit a complete segment.
2930
2931        if ( segment )
2932        {
2933            // Constrain segment count.
2934
2935            if ( withMaximumSegmentCount )
2936            {
2937                if ( segmentCount == withMaximumSegmentCount )
2938                {
2939                    break;
2940                }
2941            }
2942
2943            chunk     = 0;
2944            chunkSize = 0;
2945        }
2946    }
2947
2948    breakSize = IOTrunc(breakSize, withRequestBlockSize);
2949
2950    return breakSize;
2951}
2952
2953IOBreaker * IOBreaker::withBreakSize(
2954                              UInt64                breakSize,
2955                              UInt64                withMaximumBlockCount,
2956                              UInt64                withMaximumByteCount,
2957                              UInt64                withMaximumSegmentCount,
2958                              UInt64                withMaximumSegmentByteCount,
2959                              UInt64                withMinimumSegmentAlignmentByteCount,
2960                              UInt64                withMaximumSegmentWidthByteCount,
2961                              UInt64                withRequestBlockSize,
2962                              UInt64                withRequestStart,
2963                              IOMemoryDescriptor *  withRequestBuffer,
2964                              IOStorageAttributes * withRequestAttributes,
2965                              IOStorageCompletion * withRequestCompletion,
2966                              void *                withRequestContext )
2967{
2968    //
2969    // Create a new IOBreaker.
2970    //
2971
2972    IOBreaker * me = new IOBreaker;
2973
2974    if ( me && me->initWithBreakSize(
2975              /* breakSize                            */ breakSize,
2976              /* withMaximumBlockCount                */ withMaximumBlockCount,
2977              /* withMaximumByteCount                 */ withMaximumByteCount,
2978              /* withMaximumSegmentCount              */ withMaximumSegmentCount,
2979              /* withMaximumSegmentByteCount          */ withMaximumSegmentByteCount,
2980              /* withMinimumSegmentAlignmentByteCount */ withMinimumSegmentAlignmentByteCount,
2981              /* withMaximumSegmentWidthByteCount     */ withMaximumSegmentWidthByteCount,
2982              /* withRequestBlockSize                 */ withRequestBlockSize,
2983              /* withRequestStart                     */ withRequestStart,
2984              /* withRequestBuffer                    */ withRequestBuffer,
2985              /* withRequestAttributes                */ withRequestAttributes,
2986              /* withRequestCompletion                */ withRequestCompletion,
2987              /* withRequestContext                   */ withRequestContext ) == false )
2988    {
2989	    me->release();
2990	    me = 0;
2991    }
2992
2993    return me;
2994}
2995
2996bool IOBreaker::initWithBreakSize(
2997                              UInt64                breakSize,
2998                              UInt64                withMaximumBlockCount,
2999                              UInt64                withMaximumByteCount,
3000                              UInt64                withMaximumSegmentCount,
3001                              UInt64                withMaximumSegmentByteCount,
3002                              UInt64                withMinimumSegmentAlignmentByteCount,
3003                              UInt64                withMaximumSegmentWidthByteCount,
3004                              UInt64                withRequestBlockSize,
3005                              UInt64                withRequestStart,
3006                              IOMemoryDescriptor *  withRequestBuffer,
3007                              IOStorageAttributes * withRequestAttributes,
3008                              IOStorageCompletion * withRequestCompletion,
3009                              void *                withRequestContext )
3010{
3011    //
3012    // Initialize an IOBreaker.
3013    //
3014
3015    // Ask our superclass' opinion.
3016
3017    if ( super::initSubRange(
3018              /* parent        */ withRequestBuffer,
3019              /* withOffset    */ 0,
3020              /* withLength    */ withRequestBuffer->getLength(),
3021              /* withDirection */ withRequestBuffer->getDirection() ) == false )
3022    {
3023        return false;
3024    }
3025
3026    // Initialize our minimal state.
3027
3028    _breakSize                        = breakSize;
3029    _length                           = 0;
3030
3031    _maximumBlockCount                = withMaximumBlockCount;
3032    _maximumByteCount                 = withMaximumByteCount;
3033    _maximumSegmentCount              = withMaximumSegmentCount;
3034    _maximumSegmentByteCount          = withMaximumSegmentByteCount;
3035    _minimumSegmentAlignmentByteCount = withMinimumSegmentAlignmentByteCount;
3036    _maximumSegmentWidthByteCount     = withMaximumSegmentWidthByteCount;
3037
3038    _requestBlockSize                 = withRequestBlockSize;
3039    _requestBuffer                    = withRequestBuffer;
3040    _requestBuffer->retain();
3041
3042    if (withRequestAttributes)  _requestAttributes = *withRequestAttributes;
3043    if (withRequestCompletion)  _requestCompletion = *withRequestCompletion;
3044
3045    _requestContext                   = withRequestContext;
3046    _requestCount                     = withRequestBuffer->getLength();
3047    _requestStart                     = withRequestStart;
3048
3049    return true;
3050}
3051
3052void IOBreaker::free()
3053{
3054    //
3055    // Free all of this object's outstanding resources.
3056    //
3057
3058    if ( _requestBuffer )  _requestBuffer->release();
3059    if ( _threadCallback )  thread_call_free(_threadCallback);
3060
3061    super::free();
3062}
3063
3064bool IOBreaker::getNextStage()
3065{
3066    //
3067    // Obtain the next stage of the transfer.   The transfer buffer will be the
3068    // breaker object itself and the byte start will be returned in getByteStart().
3069    //
3070    // This method must not be called if the current stage failed with an error
3071    // or a short byte count, but instead getRequestCompletion() must be called
3072    // to adjust the status and actual byte count (with respect to the original
3073    // request) and return the original request's completion routine.  The same
3074    // call to getRequestCompletion() should also be done if the getNextStage()
3075    // method returns false.
3076    //
3077
3078    if ( _start + _length < _requestCount )
3079    {
3080        _start += _length;
3081        _length = min(_breakSize, _requestCount - _start);
3082
3083        _breakSize = getBreakSize(
3084              /* withMaximumBlockCount                */ _maximumBlockCount,
3085              /* withMaximumByteCount                 */ _maximumByteCount,
3086              /* withMaximumSegmentCount              */ _maximumSegmentCount,
3087              /* withMaximumSegmentByteCount          */ _maximumSegmentByteCount,
3088              /* withMinimumSegmentAlignmentByteCount */ _minimumSegmentAlignmentByteCount,
3089              /* withMaximumSegmentWidthByteCount     */ _maximumSegmentWidthByteCount,
3090              /* withRequestBlockSize                 */ _requestBlockSize,
3091              /* withRequestBuffer                    */ _requestBuffer,
3092              /* withRequestBufferOffset              */ _start + _length );
3093    }
3094    else
3095    {
3096        return false;
3097    }
3098
3099    _byteStart = _requestStart + _start;
3100
3101    return true;
3102}
3103
3104IOStorageAttributes * IOBreaker::getRequestAttributes()
3105{
3106    //
3107    // Obtain the attributes for the original request.
3108    //
3109
3110    return &_requestAttributes;
3111}
3112
3113IOStorageCompletion * IOBreaker::getRequestCompletion(UInt64 * actualByteCount)
3114{
3115    //
3116    // Obtain the completion information for the original request, taking
3117    // into account the actual byte count of the current stage.
3118    //
3119
3120    *actualByteCount += _start;
3121
3122    return &_requestCompletion;
3123}
3124
3125IOMemoryDescriptor * IOBreaker::getRequestBuffer()
3126{
3127    //
3128    // Obtain the buffer for the original request.
3129    //
3130
3131    return _requestBuffer;
3132}
3133
3134void * IOBreaker::getRequestContext()
3135{
3136    //
3137    // Obtain the context for the original request.
3138    //
3139
3140    return _requestContext;
3141}
3142
3143UInt64 IOBreaker::getByteStart()
3144{
3145    //
3146    // Obtain the byte start for the current stage.
3147    //
3148
3149    return _byteStart;
3150}
3151
3152thread_call_t IOBreaker::getThreadCallback()
3153{
3154    //
3155    // Obtain the thread callback.
3156    //
3157
3158    return _threadCallback;
3159}
3160
3161bool IOBreaker::setThreadCallback(thread_call_func_t callback)
3162{
3163    //
3164    // Allocate a thread callback.
3165    //
3166
3167    _threadCallback = thread_call_allocate(callback, this);
3168
3169    return _threadCallback ? true : false;
3170}
3171
3172void IOBlockStorageDriver::breakUpRequest(
3173                                     UInt64                          byteStart,
3174                                     IOMemoryDescriptor *            buffer,
3175#ifdef __LP64__
3176                                     IOStorageAttributes *           attributes,
3177                                     IOStorageCompletion *           completion,
3178#else /* !__LP64__ */
3179                                     IOStorageCompletion             completion,
3180#endif /* !__LP64__ */
3181                                     IOBlockStorageDriver::Context * context )
3182{
3183    //
3184    // The breakUpRequest method checks to see if the incoming request exceeds
3185    // our transfer constraints, and if so, breaks up the request into smaller
3186    // sub-requests.
3187    //
3188    // This method is part of a sequence of methods invoked for each read/write
3189    // request.  The first is prepareRequest, which allocates and prepares some
3190    // context for the transfer; the second is deblockRequest, which aligns the
3191    // transfer at the media's block boundaries; third is breakUpRequest, which
3192    // breaks up the transfer into multiple sub-transfers when certain hardware
3193    // constraints are exceeded; fourth is executeRequest, which implements the
3194    // actual transfer from the block storage device.
3195    //
3196    // The current implementation of breakUpRequest is asynchronous.
3197    //
3198
3199    IOBreaker * breaker;
3200    UInt64      breakSize;
3201
3202    // State our assumptions.
3203
3204    assert((byteStart           % context->block.size) == 0);
3205    assert((buffer->getLength() % context->block.size) == 0);
3206
3207    // Determine the transfer constraint, based on direction.
3208
3209    if ( buffer->getDirection() == kIODirectionIn )
3210    {
3211        breakSize = IOBreaker::getBreakSize(
3212              /* withMaximumBlockCount                */ _maxReadBlockTransfer,
3213              /* withMaximumByteCount                 */ _maxReadByteTransfer,
3214              /* withMaximumSegmentCount              */ _maxReadSegmentTransfer,
3215              /* withMaximumSegmentByteCount          */ _maxReadSegmentByteTransfer,
3216              /* withMinimumSegmentAlignmentByteCount */ _minSegmentAlignmentByteTransfer,
3217              /* withMaximumSegmentWidthByteCount     */ _maxSegmentWidthByteTransfer,
3218              /* withRequestBlockSize                 */ context->block.size,
3219              /* withRequestBuffer                    */ buffer,
3220              /* withRequestBufferOffset              */ 0 );
3221    }
3222    else
3223    {
3224        breakSize = IOBreaker::getBreakSize(
3225              /* withMaximumBlockCount                */ _maxWriteBlockTransfer,
3226              /* withMaximumByteCount                 */ _maxWriteByteTransfer,
3227              /* withMaximumSegmentCount              */ _maxWriteSegmentTransfer,
3228              /* withMaximumSegmentByteCount          */ _maxWriteSegmentByteTransfer,
3229              /* withMinimumSegmentAlignmentByteCount */ _minSegmentAlignmentByteTransfer,
3230              /* withMaximumSegmentWidthByteCount     */ _maxSegmentWidthByteTransfer,
3231              /* withRequestBlockSize                 */ context->block.size,
3232              /* withRequestBuffer                    */ buffer,
3233              /* withRequestBufferOffset              */ 0 );
3234    }
3235
3236    if ( breakSize == 0 )
3237    {
3238        complete(completion, kIOReturnDMAError);
3239        return;
3240    }
3241
3242    // If the request doesn't exceed our transfer constaints, we do
3243    // short-circuit the break-up and call executeRequest directly.
3244
3245    if ( buffer->getLength() <= breakSize )
3246    {
3247#ifdef __LP64__
3248        executeRequest(byteStart, buffer, attributes, completion, context);
3249#else /* !__LP64__ */
3250        executeRequest(byteStart, buffer, completion, context);
3251#endif /* !__LP64__ */
3252        return;
3253    }
3254
3255    // Build a breaker object.
3256
3257    if ( buffer->getDirection() == kIODirectionIn )
3258    {
3259        breaker = IOBreaker::withBreakSize(
3260              /* breakSize                            */ breakSize,
3261              /* withMaximumBlockCount                */ _maxReadBlockTransfer,
3262              /* withMaximumByteCount                 */ _maxReadByteTransfer,
3263              /* withMaximumSegmentCount              */ _maxReadSegmentTransfer,
3264              /* withMaximumSegmentByteCount          */ _maxReadSegmentByteTransfer,
3265              /* withMinimumSegmentAlignmentByteCount */ _minSegmentAlignmentByteTransfer,
3266              /* withMaximumSegmentWidthByteCount     */ _maxSegmentWidthByteTransfer,
3267              /* withRequestBlockSize                 */ context->block.size,
3268              /* withRequestStart                     */ byteStart,
3269              /* withRequestBuffer                    */ buffer,
3270#ifdef __LP64__
3271              /* withRequestAttributes                */ attributes,
3272              /* withRequestCompletion                */ completion,
3273#else /* !__LP64__ */
3274              /* withRequestAttributes                */ NULL,
3275              /* withRequestCompletion                */ &completion,
3276#endif /* !__LP64__ */
3277              /* withRequestContext                   */ context );
3278    }
3279    else
3280    {
3281        breaker = IOBreaker::withBreakSize(
3282              /* breakSize                            */ breakSize,
3283              /* withMaximumBlockCount                */ _maxWriteBlockTransfer,
3284              /* withMaximumByteCount                 */ _maxWriteByteTransfer,
3285              /* withMaximumSegmentCount              */ _maxWriteSegmentTransfer,
3286              /* withMaximumSegmentByteCount          */ _maxWriteSegmentByteTransfer,
3287              /* withMinimumSegmentAlignmentByteCount */ _minSegmentAlignmentByteTransfer,
3288              /* withMaximumSegmentWidthByteCount     */ _maxSegmentWidthByteTransfer,
3289              /* withRequestBlockSize                 */ context->block.size,
3290              /* withRequestStart                     */ byteStart,
3291              /* withRequestBuffer                    */ buffer,
3292#ifdef __LP64__
3293              /* withRequestAttributes                */ attributes,
3294              /* withRequestCompletion                */ completion,
3295#else /* !__LP64__ */
3296              /* withRequestAttributes                */ NULL,
3297              /* withRequestCompletion                */ &completion,
3298#endif /* !__LP64__ */
3299              /* withRequestContext                   */ context );
3300    }
3301
3302    if ( breaker == 0 )
3303    {
3304        complete(completion, kIOReturnNoMemory);
3305        return;
3306    }
3307
3308    // Execute the transfer (for the next stage).
3309
3310    breakUpRequestCompletion(this, breaker, kIOReturnSuccess, 0);
3311}
3312
3313void IOBlockStorageDriver::breakUpRequestCompletion( void *   target,
3314                                                     void *   parameter,
3315                                                     IOReturn status,
3316                                                     UInt64   actualByteCount )
3317{
3318    //
3319    // This is the completion routine for the broken-up breaker subrequests.
3320    // It verifies the success of the just-completed stage,  transitions to
3321    // the next stage, then builds and issues a transfer for the next stage.
3322    //
3323
3324    IOBreaker *            breaker = (IOBreaker            *) parameter;
3325    thread_call_t          callback;
3326    IOBlockStorageDriver * driver  = (IOBlockStorageDriver *) target;
3327
3328    // Allocate a thread callback.
3329
3330    callback = breaker->getThreadCallback();
3331
3332#if !TARGET_OS_EMBEDDED
3333    if ( callback == 0 )
3334    {
3335        if ( breaker->setThreadCallback(breakUpRequestExecute) == false )
3336        {
3337            status = kIOReturnNoMemory;
3338        }
3339    }
3340#endif /* !TARGET_OS_EMBEDDED */
3341
3342    // Determine whether an error occurred or whether there are no more stages.
3343
3344    if ( actualByteCount          < breaker->getLength() ||
3345         status                  != kIOReturnSuccess     ||
3346         breaker->getNextStage() == false                )
3347    {
3348        IOStorageCompletion * completion;
3349
3350        // Obtain the completion information for the original request, taking
3351        // into account the actual byte count of the current stage.
3352
3353        completion = breaker->getRequestCompletion(&actualByteCount);
3354
3355        // Complete the original request.
3356
3357        IOStorage::complete(completion, status, actualByteCount);
3358
3359        // Release our resources.
3360
3361        breaker->release();
3362    }
3363    else
3364    {
3365        // Execute the transfer (for the next stage).
3366
3367        if ( callback )
3368        {
3369            thread_call_enter1(callback, driver);
3370        }
3371        else
3372        {
3373            breakUpRequestExecute(breaker, driver);
3374        }
3375    }
3376}
3377
3378void IOBlockStorageDriver::breakUpRequestExecute(void * parameter, void * target)
3379{
3380    //
3381    // Execute the transfer (for the next stage).
3382    //
3383
3384    IOStorageAttributes *  attributes;
3385    IOBreaker *            breaker = (IOBreaker            *) parameter;
3386    UInt64                 byteStart;
3387    IOStorageCompletion    completion;
3388    Context *              context;
3389    IOBlockStorageDriver * driver  = (IOBlockStorageDriver *) target;
3390
3391    attributes = breaker->getRequestAttributes();
3392
3393    byteStart = breaker->getByteStart();
3394
3395    completion.target    = driver;
3396    completion.action    = breakUpRequestCompletion;
3397    completion.parameter = breaker;
3398
3399    context = (Context *) breaker->getRequestContext();
3400
3401#ifdef __LP64__
3402    driver->executeRequest(byteStart, breaker, attributes, &completion, context);
3403#else /* !__LP64__ */
3404    driver->executeRequest(byteStart, breaker, completion, context);
3405#endif /* !__LP64__ */
3406}
3407
3408void IOBlockStorageDriver::prepareRequest(UInt64                byteStart,
3409                                          IOMemoryDescriptor *  buffer,
3410                                          IOStorageAttributes * attributes,
3411                                          IOStorageCompletion * completion)
3412{
3413    //
3414    // The prepareRequest method allocates and prepares state for the transfer.
3415    //
3416    // This method is part of a sequence of methods invoked for each read/write
3417    // request.  The first is prepareRequest, which allocates and prepares some
3418    // context for the transfer; the second is deblockRequest, which aligns the
3419    // transfer at the media's block boundaries; third is breakUpRequest, which
3420    // breaks up the transfer into multiple sub-transfers when certain hardware
3421    // constraints are exceeded; fourth is executeRequest, which implements the
3422    // actual transfer from the block storage device.
3423    //
3424
3425    IOStorageCompletion completionOut;
3426    Context *           context;
3427
3428    // Determine whether the attributes are valid.
3429
3430    if (attributes)
3431    {
3432        if ((attributes->options & kIOStorageOptionReserved))
3433        {
3434            complete(completion, kIOReturnBadArgument);
3435            return;
3436        }
3437
3438        if (attributes->reserved0024)
3439        {
3440            complete(completion, kIOReturnBadArgument);
3441            return;
3442        }
3443
3444#ifdef __LP64__
3445        if (attributes->reserved0032 || attributes->reserved0064 || attributes->reserved0128)
3446        {
3447            complete(completion, kIOReturnBadArgument);
3448            return;
3449        }
3450#else /* !__LP64__ */
3451#if !TARGET_OS_EMBEDDED
3452        if (attributes->reserved0064)
3453        {
3454            complete(completion, kIOReturnBadArgument);
3455            return;
3456        }
3457#endif /* !TARGET_OS_EMBEDDED */
3458#endif /* !__LP64__ */
3459    }
3460
3461    // Allocate a context structure to hold some of our state.
3462
3463    context = allocateContext();
3464
3465    if (context == 0)
3466    {
3467        complete(completion, kIOReturnNoMemory);
3468        return;
3469    }
3470
3471    // Fill in the context structure with some of our state.
3472
3473    context->block.size = getMediaBlockSize();
3474    context->block.type = kBlockTypeStandard;
3475
3476    context->original.byteStart = byteStart;
3477    context->original.buffer    = buffer;
3478    context->original.buffer->retain();
3479
3480    if (attributes)  context->request.attributes = *attributes;
3481    if (completion)  context->original.completion = *completion;
3482
3483    clock_get_uptime(&context->timeStart);
3484
3485    completionOut.target    = this;
3486    completionOut.action    = prepareRequestCompletion;
3487    completionOut.parameter = context;
3488
3489    // Deblock the transfer.
3490
3491#ifdef __LP64__
3492    deblockRequest(byteStart, buffer, attributes, &completionOut, context);
3493#else /* !__LP64__ */
3494    deblockRequest(byteStart, buffer, completionOut, context);
3495#endif /* !__LP64__ */
3496}
3497
3498IOReturn
3499IOBlockStorageDriver::requestIdle(void)
3500{
3501    return(getProvider()->requestIdle());
3502}
3503
3504#ifdef __LP64__
3505OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  0);
3506OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  1);
3507OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  2);
3508#else /* !__LP64__ */
3509OSMetaClassDefineReservedUsed(IOBlockStorageDriver,  0);
3510OSMetaClassDefineReservedUsed(IOBlockStorageDriver,  1);
3511OSMetaClassDefineReservedUsed(IOBlockStorageDriver,  2);
3512#endif /* !__LP64__ */
3513OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  3);
3514OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  4);
3515OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  5);
3516OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  6);
3517OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  7);
3518OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  8);
3519OSMetaClassDefineReservedUnused(IOBlockStorageDriver,  9);
3520OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 10);
3521OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 11);
3522OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 12);
3523OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 13);
3524OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 14);
3525OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 15);
3526OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 16);
3527OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 17);
3528OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 18);
3529OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 19);
3530OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 20);
3531OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 21);
3532OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 22);
3533OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 23);
3534OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 24);
3535OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 25);
3536OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 26);
3537OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 27);
3538OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 28);
3539OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 29);
3540OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 30);
3541OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 31);
3542
3543#ifndef __LP64__
3544extern "C" void _ZN20IOBlockStorageDriver4readEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOBlockStorageDriver * driver, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion )
3545{
3546    driver->read( client, byteStart, buffer, NULL, &completion );
3547}
3548
3549extern "C" void _ZN20IOBlockStorageDriver5writeEP9IOServiceyP18IOMemoryDescriptor19IOStorageCompletion( IOBlockStorageDriver * driver, IOService * client, UInt64 byteStart, IOMemoryDescriptor * buffer, IOStorageCompletion completion )
3550{
3551    driver->write( client, byteStart, buffer, NULL, &completion );
3552}
3553#endif /* !__LP64__ */
3554