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