Annotation of XNU/iokit/Families/IOStorage/IODrive.cpp, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1998-2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: 
                     23: #include <IOKit/assert.h>
                     24: #include <IOKit/IOLib.h>
                     25: #include <IOKit/IOMemoryDescriptor.h>
                     26: #include <IOKit/storage/IODrive.h>
                     27: 
                     28: #define super IOStorage
                     29: OSDefineMetaClass(IODrive, IOStorage)
                     30: OSDefineAbstractStructors(IODrive, IOStorage)
                     31: 
                     32: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     33: 
                     34: const UInt32 kPollerInterval = 1000;                           // (ms, 1 second)
                     35: 
                     36: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     37: 
                     38: bool IODrive::init(OSDictionary * properties = 0)
                     39: {
                     40:     //
                     41:     // Initialize this object's minimal state.
                     42:     //
                     43: 
                     44:     if (super::init(properties) == false)  return false;
                     45: 
                     46:     _deblockerLockForRMWs   = IOLockAlloc();
                     47:     _openClients            = OSSet::withCapacity(2);
                     48: 
                     49:     for (unsigned index = 0; index < kStatisticsCount; index++)
                     50:         _statistics[index] = OSNumber::withNumber(0ULL, 64);
                     51: 
                     52:     if (_deblockerLockForRMWs == 0 || _openClients == 0)  return false;
                     53: 
                     54:     for (unsigned index = 0; index < kStatisticsCount; index++)
                     55:         if (_statistics[index] == 0)  return false;
                     56: 
                     57:     IOLockInit(_deblockerLockForRMWs);
                     58: 
                     59:     //
                     60:     // Create the standard drive registry properties.
                     61:     //
                     62: 
                     63:     OSDictionary * statistics = OSDictionary::withCapacity(kStatisticsCount);
                     64: 
                     65:     if (statistics == 0)  return false;
                     66: 
                     67:     statistics->setObject( kIODriveStatisticsBytesRead,
                     68:                            _statistics[kStatisticsBytesRead] );
                     69:     statistics->setObject( kIODriveStatisticsBytesWritten,
                     70:                            _statistics[kStatisticsBytesWritten] );
                     71:     statistics->setObject( kIODriveStatisticsReadErrors,
                     72:                            _statistics[kStatisticsReadErrors] );
                     73:     statistics->setObject( kIODriveStatisticsWriteErrors,
                     74:                            _statistics[kStatisticsWriteErrors] );
                     75:     statistics->setObject( kIODriveStatisticsLatentReadTime,
                     76:                            _statistics[kStatisticsLatentReadTime] );
                     77:     statistics->setObject( kIODriveStatisticsLatentWriteTime,
                     78:                            _statistics[kStatisticsLatentWriteTime] );
                     79:     statistics->setObject( kIODriveStatisticsReads,
                     80:                            _statistics[kStatisticsReads] );
                     81:     statistics->setObject( kIODriveStatisticsWrites,
                     82:                            _statistics[kStatisticsWrites] );
                     83:     statistics->setObject( kIODriveStatisticsReadRetries,
                     84:                            _statistics[kStatisticsReadRetries] );
                     85:     statistics->setObject( kIODriveStatisticsWriteRetries,
                     86:                            _statistics[kStatisticsWriteRetries] );
                     87:     statistics->setObject( kIODriveStatisticsTotalReadTime,
                     88:                            _statistics[kStatisticsTotalReadTime] );
                     89:     statistics->setObject( kIODriveStatisticsTotalWriteTime,
                     90:                            _statistics[kStatisticsTotalWriteTime] );
                     91:     
                     92:     setProperty(kIODriveStatistics, statistics);
                     93: 
                     94:     return true;
                     95: }
                     96: 
                     97: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                     98: 
                     99: bool IODrive::start(IOService * provider)
                    100: {
                    101:     //
                    102:     // This method is called once we have been attached to the provider object.
                    103:     //
                    104: 
                    105:     // Instruct our subclass to prepare the drive for operation.
                    106: 
                    107:     if (handleStart(provider) == false)  return false;
                    108: 
                    109:     // Initiate the poller mechanism if it is required.
                    110: 
                    111:     if (isMediaEjectable() && isMediaPollRequired() && !isMediaPollExpensive())
                    112:     {
                    113:         lockForArbitration();        // (disable opens/closes; a recursive lock)
                    114: 
                    115:         if (!isOpen() && !isInactive())
                    116:             schedulePoller();        // (schedule the poller, increments retain)
                    117: 
                    118:         unlockForArbitration();       // (enable opens/closes; a recursive lock)
                    119:     }
                    120: 
                    121:     // Register this object so it can be found via notification requests. It is
                    122:     // not being registered to have I/O Kit attempt to have drivers match on it,
                    123:     // which is the reason most other services are registered -- that's not the
                    124:     // intention of this registerService call.
                    125: 
                    126:     registerService();
                    127: 
                    128:     return true;
                    129: }
                    130: 
                    131: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    132: 
                    133: void IODrive::stop(IOService * provider)
                    134: {
                    135:     //
                    136:     // This method is called before we are detached from the provider object.
                    137:     //
                    138: 
                    139:     // Halt the poller mechanism if it is required.
                    140:         
                    141:     if (isMediaEjectable() && isMediaPollRequired() && !isMediaPollExpensive())
                    142:         unschedulePoller();                           // (unschedule the poller)
                    143: 
                    144:     // Instruct our subclass to stop the drive.
                    145: 
                    146:     handleStop(provider);
                    147: 
                    148:     super::stop(provider);
                    149: }
                    150: 
                    151: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    152: 
                    153: void IODrive::free()
                    154: {
                    155:     //
                    156:     // Free all of this object's outstanding resources.
                    157:     //
                    158: 
                    159:     if (_deblockerLockForRMWs)  IOLockFree(_deblockerLockForRMWs);
                    160:     if (_openClients)  _openClients->release();
                    161: 
                    162:     for (unsigned index = 0; index < kStatisticsCount; index++)
                    163:         if (_statistics[index])  _statistics[index]->release();
                    164: 
                    165:     super::free();
                    166: }
                    167: 
                    168: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    169: 
                    170: bool IODrive::handleOpen(IOService *  client,
                    171:                          IOOptionBits options,
                    172:                          void *       argument)
                    173: {
                    174:     //
                    175:     // The handleOpen method grants or denies permission to access this object
                    176:     // to an interested client.  The argument is an IOStorageAccess value that
                    177:     // specifies the level of access desired -- reader or reader-writer.
                    178:     //
                    179:     // This method can be invoked to upgrade or downgrade the access level for
                    180:     // an existing client as well.  The previous access level will prevail for
                    181:     // upgrades that fail, of course.   A downgrade should never fail.  If the
                    182:     // new access level should be the same as the old for a given client, this
                    183:     // method will do nothing and return success.  In all cases, one, singular
                    184:     // close-per-client is expected for all opens-per-client received.
                    185:     //
                    186:     // We are guaranteed that no other opens or closes will be processed until
                    187:     // we make our decision, change our state, and return from this method.
                    188:     //
                    189: 
                    190:     IOStorageAccess access = (IOStorageAccess) (int) argument;
                    191: 
                    192:     assert(client);
                    193:     assert(access != kAccessNone);
                    194: 
                    195:     // Handle the first open on removable media in a special case.
                    196: 
                    197:     if (isMediaEjectable() && _openClients->getCount() == 0)
                    198:     {
                    199:         // Halt the poller if it is active and this is the drive's first open.
                    200: 
                    201:         if (isMediaPollRequired() && !isMediaPollExpensive())
                    202:             unschedulePoller();                       // (unschedule the poller)
                    203: 
                    204:         // Lock down the media while we have opens on this drive object.  The
                    205:         // arbitration lock is held during the operation -- however we assume
                    206:         // the extra length of time will not be an issue for now.
                    207: 
                    208:         if (lockMedia(true) != kIOReturnSuccess)
                    209:             IOLog("%s: Unable to lock down removable media.\n", getName());
                    210:     }
                    211: 
                    212:     // Process the open.
                    213: 
                    214:     _openClients->setObject(client);          // (works for up/downgrade case)
                    215: 
                    216:     return true;
                    217: }
                    218: 
                    219: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    220: 
                    221: bool IODrive::handleIsOpen(const IOService * client) const
                    222: {
                    223:     //
                    224:     // The handleIsOpen method determines whether the specified client, or any
                    225:     // client if none is specificed, presently has an open on this object.
                    226:     //
                    227:     // We are guaranteed that no other opens or closes will be processed until
                    228:     // we return from this method.
                    229:     //
                    230: 
                    231:     if (client)
                    232:         return _openClients->containsObject(client);
                    233:     else
                    234:         return (_openClients->getCount() != 0);
                    235: }
                    236: 
                    237: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    238: 
                    239: void IODrive::handleClose(IOService * client, IOOptionBits options)
                    240: {
                    241:     //
                    242:     // The handleClose method drops the incoming client's access to this object.
                    243:     //
                    244:     // We are guaranteed that no other opens or closes will be processed until
                    245:     // we change our state and return from this method.
                    246:     //
                    247: 
                    248:     assert(client);
                    249: 
                    250:     // Process the close.
                    251: 
                    252:     _openClients->removeObject(client);
                    253: 
                    254:     // Handle the last close on removable media in a special case.
                    255: 
                    256:     if (isMediaEjectable() && _openClients->getCount() == 0)
                    257:     {
                    258:         // Unlock the media in the drive.   The arbitration lock is held during
                    259:         // the operation -- however we assume the extra length of time will not
                    260:         // be an issue for now.
                    261: 
                    262:         if (lockMedia(false) != kIOReturnSuccess)
                    263:             IOLog("%s: Unable to unlock removable media.\n", getName());
                    264: 
                    265:         // Reactivate the poller.
                    266: 
                    267:         if (isMediaPollRequired() && !isMediaPollExpensive() && !isInactive())
                    268:             schedulePoller();        // (schedule the poller, increments retain)
                    269:     }
                    270: }
                    271: 
                    272: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    273: 
                    274: void IODrive::read(IOService *          /* client */,
                    275:                    UInt64               byteStart,
                    276:                    IOMemoryDescriptor * buffer,
                    277:                    IOStorageCompletion  completion)
                    278: {
                    279:     //
                    280:     // Read data from the storage object at the specified byte offset into the
                    281:     // specified buffer, asynchronously.   When the read completes, the caller
                    282:     // will be notified via the specified completion action.
                    283:     //
                    284:     // The buffer will be retained for the duration of the read.
                    285:     //
                    286:     // Note that the read passes through several other methods before being
                    287:     // passed to executeRequest.  The first is deblockRequest, which aligns
                    288:     // the request with the media's block boundaries; the second is prepare-
                    289:     // Request which prepares the memory involved in the transfer (involves
                    290:     // wiring, virtual-to-physical mapping, and breakup of the memory range
                    291:     // based on the controller's and/or drive's constraints).
                    292:     //
                    293: 
                    294:     UInt64 mediaBlockSize = getMediaBlockSize();
                    295: 
                    296:     // State our assumptions.
                    297: 
                    298:     assert(buffer->getDirection() == kIODirectionIn);
                    299: 
                    300:     // If the request is aligned with the media's block boundaries, we can
                    301:     // short-circuit the deblocker and call prepareRequest directly.
                    302: 
                    303:     if ( (byteStart           % mediaBlockSize) == 0 &&
                    304:          (buffer->getLength() % mediaBlockSize) == 0 )
                    305:     {
                    306:         prepareRequest(byteStart, buffer, completion);
                    307:         return;
                    308:     }
                    309: 
                    310:     deblockRequest(byteStart, buffer, completion);
                    311: }
                    312: 
                    313: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    314: 
                    315: void IODrive::write(IOService *          /* client */,
                    316:                     UInt64               byteStart,
                    317:                     IOMemoryDescriptor * buffer,
                    318:                     IOStorageCompletion  completion)
                    319: {
                    320:     //
                    321:     // Write data into the storage object at the specified byte offset from the
                    322:     // specified buffer, asynchronously.   When the write completes, the caller
                    323:     // will be notified via the specified completion action.
                    324:     //
                    325:     // The buffer will be retained for the duration of the write.
                    326:     //
                    327:     // Note that the write passes through several other methods before being
                    328:     // passed to executeRequest.  The first is deblockRequest, which aligns
                    329:     // the request with the media's block boundaries; the second is prepare-
                    330:     // Request which prepares the memory involved in the transfer (involves
                    331:     // wiring, virtual-to-physical mapping, and breakup of the memory range
                    332:     // based on the controller's and/or drive's constraints).
                    333:     //
                    334: 
                    335:     UInt64 mediaBlockSize = getMediaBlockSize();
                    336: 
                    337:     // State our assumptions.
                    338: 
                    339:     assert(buffer->getDirection() == kIODirectionOut);
                    340: 
                    341:     // If the request is aligned with the media's block boundaries, we can
                    342:     // short-circuit the deblocker and call prepareRequest directly.
                    343: 
                    344:     if ( (byteStart           % mediaBlockSize) == 0 &&
                    345:          (buffer->getLength() % mediaBlockSize) == 0 )
                    346:     {
                    347:         prepareRequest(byteStart, buffer, completion);
                    348:         return;
                    349:     }
                    350: 
                    351:     deblockRequest(byteStart, buffer, completion);
                    352: }
                    353: 
                    354: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    355: 
                    356: void IODrive::addToBytesTransferred(UInt64 bytesTransferred,
                    357:                                     UInt64 totalTime,                    // (ns)
                    358:                                     UInt64 latentTime,                   // (ns)
                    359:                                     bool   isWrite)
                    360: {
                    361:     //
                    362:     // Update the total number of bytes transferred, the total transfer time,
                    363:     // and the total latency time for this drive -- used for statistics.
                    364:     //
                    365: 
                    366:     if (isWrite)
                    367:     {
                    368:         _statistics[kStatisticsWrites]->addValue(1);
                    369:         _statistics[kStatisticsBytesWritten]->addValue(bytesTransferred);
                    370:         _statistics[kStatisticsTotalWriteTime]->addValue(totalTime);
                    371:         _statistics[kStatisticsLatentWriteTime]->addValue(latentTime);
                    372:         if (bytesTransferred <= getMediaBlockSize())
                    373:             _statistics[kStatisticsSingleBlockWrites]->addValue(1);
                    374:     }
                    375:     else
                    376:     {
                    377:         _statistics[kStatisticsReads]->addValue(1);
                    378:         _statistics[kStatisticsBytesRead]->addValue(bytesTransferred);
                    379:         _statistics[kStatisticsTotalReadTime]->addValue(totalTime);
                    380:         _statistics[kStatisticsLatentReadTime]->addValue(latentTime);
                    381:         if (bytesTransferred <= getMediaBlockSize())
                    382:             _statistics[kStatisticsSingleBlockReads]->addValue(1);
                    383:     }
                    384: }
                    385: 
                    386: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    387: 
                    388: void IODrive::incrementRetries(bool isWrite)
                    389: {
                    390:     //
                    391:     // Update the total retry count -- used for statistics.
                    392:     //
                    393: 
                    394:     if (isWrite)
                    395:         _statistics[kStatisticsWriteRetries]->addValue(1);
                    396:     else
                    397:         _statistics[kStatisticsReadRetries]->addValue(1);
                    398: }
                    399: 
                    400: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    401: 
                    402: void IODrive::incrementErrors(bool isWrite)
                    403: {
                    404:     //
                    405:     // Update the total error count -- used for statistics.
                    406:     //
                    407: 
                    408:     if (isWrite)
                    409:         _statistics[kStatisticsWriteErrors]->addValue(1);
                    410:     else
                    411:         _statistics[kStatisticsReadErrors]->addValue(1);
                    412: }
                    413: 
                    414: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    415: 
                    416: UInt32 IODrive::getStatistics(UInt64 * statistics,
                    417:                               UInt32   statisticsMaxCount) const
                    418: {
                    419:     //
                    420:     // Ask the drive to report its operating statistics.  The statistics are
                    421:     // described by the IODrive::Statistics indices.  This routine fills the
                    422:     // caller's buffer, up to the maximum count specified if the real number
                    423:     // of statistics would overflow the buffer.   The return value indicates
                    424:     // the actual number of statistics copied to the buffer.
                    425:     //
                    426:     // If the statistics buffer is not supplied or if the maximum count is
                    427:     // zero, the routine returns the proposed count of statistics instead.
                    428:     //
                    429: 
                    430:     if (statistics == 0)
                    431:         return kStatisticsCount;
                    432: 
                    433:     UInt32 statisticsCount = min(kStatisticsCount, statisticsMaxCount);
                    434: 
                    435:     for (unsigned index = 0; index < statisticsCount; index++)
                    436:         statistics[index] = _statistics[index]->unsigned64BitValue();
                    437: 
                    438:     return statisticsCount;
                    439: }
                    440: 
                    441: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    442: 
                    443: UInt64 IODrive::getStatistic(Statistics statistic) const
                    444: {
                    445:     //
                    446:     // Ask the drive to report one of its operating statistics.
                    447:     //
                    448: 
                    449:     if ((UInt32) statistic >= kStatisticsCount)  return 0;
                    450: 
                    451:     return _statistics[statistic]->unsigned64BitValue();
                    452: }
                    453: 
                    454: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    455: 
                    456: void IODrive::prepareRequest(UInt64               byteStart,
                    457:                              IOMemoryDescriptor * buffer,
                    458:                              IOStorageCompletion  completion)
                    459: {
                    460:     //
                    461:     // The prepareRequest method prepares the memory involved in the transfer.
                    462:     // The memory will be wired down, physically mapped, and broken up based
                    463:     // on the controller's and drive's constraints.
                    464:     //
                    465:     // This method is part of a sequence of methods that are called for each
                    466:     // read or write request.  The first is deblockRequest, which aligns the
                    467:     // request at the media's block boundaries; the second is prepareRequest,
                    468:     // which prepares the buffer involved in the transfer;  and the third is 
                    469:     // executeRequest, which implements the actual transfer from the drive.
                    470:     //
                    471: 
                    472:     executeRequest(byteStart, buffer, completion);
                    473:     return;
                    474: }
                    475: 
                    476: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    477: 
                    478: void IODrive::schedulePoller()
                    479: {
                    480:     //
                    481:     // Schedule the poller mechanism.
                    482:     //
                    483:     // This method assumes that the arbitration lock is held.
                    484:     //
                    485: 
                    486:     AbsoluteTime deadline;
                    487: 
                    488:     retain();
                    489: 
                    490:     clock_interval_to_deadline(kPollerInterval, kMillisecondScale, &deadline);
                    491:     thread_call_func_delayed(poller, this, deadline);
                    492: }
                    493: 
                    494: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    495: 
                    496: void IODrive::unschedulePoller()
                    497: {
                    498:     //
                    499:     // Unschedule the poller mechanism.
                    500:     //
                    501:     // This method assumes that the arbitration lock is held.
                    502:     //
                    503: 
                    504:     if (thread_call_func_cancel(poller, this, true))  release();
                    505: }
                    506: 
                    507: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    508: 
                    509: void IODrive::poller(void * target, void *)
                    510: {
                    511:     //
                    512:     // This method is the timeout handler for the poller mechanism.  It polls
                    513:     // for media and reschedules another timeout if the drive is still closed.
                    514:     //
                    515: 
                    516:     IODrive * drive = (IODrive *) target;
                    517: 
                    518:     drive->pollMedia();
                    519: 
                    520:     drive->lockForArbitration();     // (disable opens/closes; a recursive lock)
                    521: 
                    522:     if (!drive->isOpen() && !drive->isInactive())
                    523:         drive->schedulePoller();     // (schedule the poller, increments retain)
                    524: 
                    525:     drive->unlockForArbitration();    // (enable opens/closes; a recursive lock)
                    526: 
                    527:     drive->release();             // (drop the retain associated with this poll)
                    528: }
                    529: 
                    530: // -----------------------------------------------------------------------------
                    531: // Deblocker Implementation
                    532: 
                    533: IODrive::DeblockerContext * IODrive::deblockerContextAllocate()
                    534: {
                    535:     //
                    536:     // Allocate a deblocker context structure.  It comes preinitialized with
                    537:     // a block-sized scratch buffer and an associated memory descriptor, but
                    538:     // is otherwise uninitialized.
                    539:     //
                    540:     // A future implementation may recycle deblocker context structures here
                    541:     // as an optimization.
                    542:     //
                    543: 
                    544:     DeblockerContext * deblockerContext = IONew(DeblockerContext, 1);
                    545:     UInt64             mediaBlockSize   = getMediaBlockSize();
                    546: 
                    547:     if (deblockerContext)
                    548:     {
                    549:         deblockerContext->blockBufferPtr = IONew(UInt8, mediaBlockSize);
                    550: 
                    551:         if (deblockerContext->blockBufferPtr)
                    552:         {
                    553:             deblockerContext->blockBuffer = IOMemoryDescriptor::withAddress(
                    554:                        /* address       */ deblockerContext->blockBufferPtr,
                    555:                        /* withLength    */ (vm_size_t) mediaBlockSize,
                    556:                        /* withDirection */ kIODirectionNone );
                    557: 
                    558:             if (deblockerContext->blockBuffer)  return deblockerContext;
                    559: 
                    560:             IODelete(deblockerContext->blockBufferPtr, UInt8, mediaBlockSize);
                    561:         }
                    562:         IODelete(deblockerContext, DeblockerContext, 1);
                    563:     }
                    564: 
                    565:     return 0; // (failure)
                    566: }
                    567: 
                    568: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    569: 
                    570: void IODrive::deblockerContextFree(IODrive::DeblockerContext * deblockerContext)
                    571: {
                    572:     //
                    573:     // Deallocate a deblocker context structure.  The block-sized scratch
                    574:     // buffer and memory descriptor is automatically deallocated as well.
                    575:     //
                    576: 
                    577:     assert(deblockerContext->blockBuffer && deblockerContext->blockBufferPtr);
                    578: 
                    579:     if (deblockerContext->middleBuffer)
                    580:         deblockerContext->middleBuffer->release();
                    581: 
                    582:     deblockerContext->blockBuffer->release();
                    583:     IODelete(deblockerContext->blockBufferPtr, UInt8, getMediaBlockSize());
                    584:     IODelete(deblockerContext, DeblockerContext, 1);
                    585: }
                    586: 
                    587: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    588: 
                    589: void IODrive::deblockRequest(UInt64               byteStart,
                    590:                              IOMemoryDescriptor * buffer,
                    591:                              IOStorageCompletion  completion)
                    592: {
                    593:     //
                    594:     // The deblockRequest method checks to see if the incoming request rests
                    595:     // on the media's block boundaries, and if not, deblocks it.  Deblocking
                    596:     // involves breaking up the request into sub-requests that rest on block
                    597:     // boundaries, and performing the appropriate unaligned byte copies from
                    598:     // the scratch buffer into into the client's request buffer.
                    599:     //
                    600:     // This method is part of a sequence of methods that are called for each
                    601:     // read or write request.  The first is deblockRequest, which aligns the
                    602:     // request at the media's block boundaries; the second is prepareRequest,
                    603:     // which prepares the memory involved in the transfer;  and the third is 
                    604:     // executeRequest, which implements the actual transfer from the drive.
                    605:     //
                    606:     // The current implementation of deblockRequest is asynchronous.
                    607:     //
                    608:     // A diagram and description of the key players:
                    609:     //    ____ _______________ ______   ______ _______________ ____
                    610:     // ...    |               |      ...      |               |    ...
                    611:     //    ____|_______________|______   ______|_______________|____
                    612:     //              ^                                 ^
                    613:     //        |\___/|\_______/|\_____________/|\_____/|
                    614:     //        |  |  |    |    |       |       |   |   |
                    615:     //        |  |  |    |    |       |       |   |   |_  byteStart + byteCount
                    616:     //        |  |  |    |    |       |       |   |_ _ _  bytesFinal
                    617:     //        |  |  |    |    |       |       |_ _ _ _ _  BLOCK BOUNDARY
                    618:     //        |  |  |    |    |       |
                    619:     //        |  |  |    |    |       |_ _ _ _ _ _ _ _ _  bytesMiddle
                    620:     //        |  |  |    |    |_ _ _ _ _ _ _ _ _ _ _ _ _  BLOCK BOUNDARY
                    621:     //        |  |  |    |
                    622:     //        |  |  |    |__ _ _ _ _ _ _ _ _ _ _ _ _ _ _  bytesStart
                    623:     //        |  |  |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  byteStart
                    624:     //        |  |__ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  offsetStart
                    625:     //        |_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _  BLOCK BOUNDARY
                    626:     // 
                    627:     // byteStart   = the start of transfer, absolute position on media
                    628:     // offsetStart = unaligned offset into the first block, zero if aligned
                    629:     // bytesStart  = unaligned bytecount for the first block, zero if aligned
                    630:     // bytesMiddle = aligned byte count for the middle blocks, zero if none
                    631:     // bytesFinal  = unaligned byte count for the last block, zero if aligned
                    632:     //
                    633: 
                    634:     UInt64             byteCount = buffer->getLength();
                    635:     DeblockerContext * context   = deblockerContextAllocate();
                    636:     bool               isWrite   = (buffer->getDirection() == kIODirectionOut);
                    637:     UInt64             mediaBlockSize = getMediaBlockSize();
                    638: 
                    639:     if (context == 0)
                    640:     {
                    641:         complete(completion, kIOReturnNoMemory);
                    642:         return;
                    643:     }
                    644: 
                    645:     //
                    646:     // This implementation of the deblocker permits only one read-modify-write
                    647:     // at any given time.  Note that other write requests can, and do, proceed
                    648:     // simultaneously so long as they do not require the deblocker -- refer to
                    649:     // the read() and the write() routines for the decision logic.
                    650:     //
                    651: 
                    652:     if (isWrite)  IOTakeLock(_deblockerLockForRMWs);
                    653: 
                    654:     //
                    655:     // We split up our calculation logic into two distinct cases:
                    656:     //  (a) all one block transfers with an unaligned end;
                    657:     //  (b) all one block transfers with an aligned end and > 2 block transfers
                    658:     //
                    659: 
                    660:     context->offsetStart = byteStart % mediaBlockSize;
                    661: 
                    662:     if (context->offsetStart + byteCount < mediaBlockSize) // (not '<=')
                    663:     {
                    664:        context->bytesStart = byteCount;
                    665:        context->bytesFinal = 0;
                    666:        context->bytesMiddle = 0;
                    667:     }
                    668:     else // (case b)
                    669:     {
                    670:        context->bytesStart  = (context->offsetStart) ? 
                    671:                               (mediaBlockSize - context->offsetStart) : 0;
                    672:        context->bytesFinal  = (context->offsetStart + byteCount) %
                    673:                               mediaBlockSize;
                    674:        context->bytesMiddle = byteCount - context->bytesStart -
                    675:                               context->bytesFinal;
                    676:     }
                    677: 
                    678:     assert(context->bytesMiddle % mediaBlockSize == 0);
                    679: 
                    680:     //
                    681:     // We set the deblock phase to "begin" and pass control to an internal
                    682:     // completion routine, which implements the deblocking state machine.
                    683:     //
                    684: 
                    685:     context->phase            = (isWrite) ? kPhaseBeginRMW : kPhaseBegin;
                    686:     context->bytesTransferred = 0;
                    687: 
                    688:     context->originalRequest.byteStart  = byteStart;
                    689:     context->originalRequest.buffer     = buffer;
                    690:     context->originalRequest.buffer->retain();   // (retain the original buffer)
                    691:     context->originalRequest.completion = completion;
                    692: 
                    693:     if (context->bytesMiddle)                               // (very bad things)
                    694:     {
                    695:         context->middleBuffer = IOMemoryDescriptor::withSubRange(
                    696:           /* descriptor    */ context->originalRequest.buffer,
                    697:           /* withOffset    */ context->bytesStart,
                    698:           /* withLength    */ context->bytesMiddle,
                    699:           /* withDirection */ context->originalRequest.buffer->getDirection() );
                    700:         assert(context->middleBuffer);
                    701:     }
                    702:     else
                    703:     {
                    704:         context->middleBuffer = 0;
                    705:     }
                    706: 
                    707:     context->subrequest.buffer               = 0;
                    708:     context->subrequest.byteStart            = 0;
                    709:     context->subrequest.completion.target    = this;
                    710:     context->subrequest.completion.action    = deblockerCompletion;
                    711:     context->subrequest.completion.parameter = context;
                    712: 
                    713:     deblockerCompletion(this, context, kIOReturnSuccess, 0);
                    714:     return;
                    715: }
                    716: 
                    717: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                    718: 
                    719: void IODrive::deblockerCompletion(void *   target,
                    720:                                   void *   parameter,
                    721:                                   IOReturn status,
                    722:                                   UInt64   actualByteCount)
                    723: {
                    724:     //
                    725:     // This is the completion routine for the aligned deblocker subrequests.
                    726:     // It performs work on the just-completed phase, if any, transitions to
                    727:     // the next phase, then builds and issues a transfer for the next phase.
                    728:     //
                    729:     //
                    730:     // For write storage requests, the state machine proceeds as follows:
                    731:     //
                    732:     // kPhaseBeginRMW --> { kPhaseStartRM --> kPhaseStartW } -->
                    733:     // { kPhaseMiddleW } --> { kPhaseFinalRM --> kPhaseFinalW } --> kPhaseDone
                    734:     //
                    735:     // For read storage requests, the state machine proceeds as follows:
                    736:     //
                    737:     // kPhaseBegin --> { kPhaseStart } --> { kPhaseMiddle } --> { kPhaseFinal }
                    738:     // --> kPhaseDone
                    739:     //
                    740:     // { } denotes skippable states
                    741:     //
                    742: 
                    743:     DeblockerContext * context        = (DeblockerContext *) parameter;
                    744:     IODirection        direction      = kIODirectionIn;
                    745:     IODrive *          drive          = (IODrive *) target;
                    746:     UInt64             mediaBlockSize = drive->getMediaBlockSize();
                    747: 
                    748:     //
                    749:     // Complete the work necessary for the just-completed transfer, if any.
                    750:     // Note that we go out of our way to squeeze every good byte through to
                    751:     // the disk, even if the transfer failed half way through.
                    752:     //
                    753:     // A note for future developers: be mindful that we haven't checked the
                    754:     // returned actual byte count and status yet. 
                    755:     //
                    756: 
                    757:     switch (context->phase)
                    758:     {
                    759:         case kPhaseStart: // - - - - - - - - - - - - - - - - - - - - - - - - - -
                    760:         {
                    761:             UInt64 bytesToCopy;
                    762: 
                    763:             // Ensure a sufficient amount of the block was read.
                    764: 
                    765:             if (actualByteCount > context->offsetStart)
                    766:             {
                    767:                 // Copy the slice of data to be read from the scratch buffer,
                    768:                 // or the subset thereof if the actual transfer came up short.
                    769: 
                    770:                 bytesToCopy = min(context->bytesStart,
                    771:                                   actualByteCount - context->offsetStart);
                    772: 
                    773:                 bytesToCopy = context->originalRequest.buffer->writeBytes(
                    774:                                 context->bytesTransferred,
                    775:                                 context->blockBufferPtr + context->offsetStart,
                    776:                                 (UInt32)bytesToCopy);
                    777: 
                    778:                 // Bring the total number of bytes transferred up to date.
                    779: 
                    780:                 context->bytesTransferred += bytesToCopy;
                    781: 
                    782:                 // If the actual transfer came up short (due to writeBytes),
                    783:                 // set an error status.
                    784: 
                    785:                 if (bytesToCopy < context->bytesStart &&
                    786:                     status == kIOReturnSuccess)
                    787:                 {
                    788:                     status = kIOReturnNoSpace; // (writeBytes failure)
                    789:                 }
                    790:             }
                    791:         } break;
                    792: 
                    793:         case kPhaseMiddle:  // - - - - - - - - - - - - - - - - - - - - - - - - -
                    794:         {
                    795:             // Bring the total number of bytes transferred up to date.
                    796: 
                    797:             context->bytesTransferred += actualByteCount;
                    798:         } break;
                    799: 
                    800:         case kPhaseFinal: // - - - - - - - - - - - - - - - - - - - - - - - - - -
                    801:         {
                    802:             UInt64 bytesToCopy = min(context->bytesFinal, actualByteCount);
                    803: 
                    804:             // Ensure at least some amount of the block was read.
                    805: 
                    806:             if (bytesToCopy)
                    807:             {
                    808:                 // Copy the slice of data to be read from the scratch buffer,
                    809:                 // or the subset thereof if the actual transfer came up short.
                    810: 
                    811:                 bytesToCopy = context->originalRequest.buffer->writeBytes(
                    812:                             context->bytesTransferred,
                    813:                             context->blockBufferPtr,
                    814:                             (UInt32)bytesToCopy);
                    815: 
                    816:                 // Bring the total number of bytes transferred up to date.
                    817: 
                    818:                 context->bytesTransferred += bytesToCopy;
                    819: 
                    820:                 // If the actual transfer came up short (due to writeBytes),
                    821:                 // set an error status.
                    822: 
                    823:                 if (bytesToCopy < context->bytesFinal &&
                    824:                     status == kIOReturnSuccess)
                    825:                 {
                    826:                     status = kIOReturnNoSpace; // (writeBytes failure)
                    827:                 }
                    828:             }
                    829:         } break;
                    830: 
                    831:         case kPhaseStartRM: // - - - - - - - - - - - - - - - - - - - - - - - - -
                    832:         {
                    833:             // Ensure the entire block was read into the scratch buffer.
                    834: 
                    835:             if (actualByteCount == mediaBlockSize)
                    836:             {
                    837:                 // Copy the slice of data to be written into the scratch buffer.
                    838: 
                    839:                 if (context->originalRequest.buffer->readBytes(
                    840:                     context->bytesTransferred,
                    841:                     context->blockBufferPtr + context->offsetStart,
                    842:                     (UInt32)context->bytesStart) != (UInt32)context->bytesStart)
                    843:                 {
                    844:                     status = kIOReturnInternalError; // (readBytes failure)
                    845:                 }
                    846:             }
                    847:         } break;
                    848:         
                    849:         case kPhaseStartW:  // - - - - - - - - - - - - - - - - - - - - - - - - -
                    850:         {
                    851:             // Ensure the entire block was written and bring total number of
                    852:             // bytes transferred up to date.
                    853: 
                    854:             if (actualByteCount == mediaBlockSize)
                    855:             {
                    856:                 // Bring the total number of bytes transferred up to date.
                    857:                 context->bytesTransferred += context->bytesStart;
                    858:             }
                    859:         } break;
                    860: 
                    861:         case kPhaseMiddleW: // - - - - - - - - - - - - - - - - - - - - - - - - -
                    862:         {
                    863:             // Bring the total number of bytes transferred up to date.
                    864:             context->bytesTransferred += actualByteCount;
                    865:         } break;
                    866: 
                    867:         case kPhaseFinalRM: // - - - - - - - - - - - - - - - - - - - - - - - - -
                    868:         {
                    869:             // Ensure the entire block was read into the scratch buffer.
                    870: 
                    871:             if (actualByteCount == mediaBlockSize)
                    872:             {
                    873:                 // Copy the slice of data to be written into the scratch buffer.
                    874: 
                    875:                 if (context->originalRequest.buffer->readBytes(
                    876:                     context->bytesTransferred,
                    877:                     context->blockBufferPtr,
                    878:                     (UInt32)context->bytesFinal) != (UInt32)context->bytesFinal)
                    879:                 {
                    880:                     status = kIOReturnInternalError; // (readBytes failure)
                    881:                 }
                    882:             }
                    883:         } break;
                    884: 
                    885:         case kPhaseFinalW:  // - - - - - - - - - - - - - - - - - - - - - - - - -
                    886:         {
                    887:             // Ensure the entire block was written and bring total number of
                    888:             // bytes transferred up to date.
                    889: 
                    890:             if (actualByteCount == mediaBlockSize)
                    891:             {
                    892:                 // Bring the total number of bytes transferred up to date.
                    893:                 context->bytesTransferred += context->bytesFinal;
                    894:             }
                    895:         } break;
                    896: 
                    897:         default:
                    898:         {
                    899:             // Nothing to do.
                    900:         } break;
                    901:     }
                    902: 
                    903:     //
                    904:     // Fail the original transfer if an error was detected.
                    905:     //
                    906: 
                    907:     if (context->phase != kPhaseBegin && context->phase != kPhaseBeginRMW)
                    908:     {
                    909:         assert( status          != kIOReturnSuccess                        ||
                    910:                 actualByteCount == context->subrequest.buffer->getLength() );
                    911: 
                    912:         if ( status          != kIOReturnSuccess                        || 
                    913:              actualByteCount != context->subrequest.buffer->getLength() )
                    914:         {
                    915:             // Unlock the RMW-lock, to allow the next RMW to proceed.
                    916:             if (context->originalRequest.buffer->getDirection() ==
                    917:                                                                 kIODirectionOut)
                    918:                 IOUnlock(drive->_deblockerLockForRMWs);
                    919: 
                    920:             // Release the retain we placed on the request buffer.
                    921:             context->originalRequest.buffer->release();
                    922: 
                    923:             // Complete the request.
                    924:             drive->complete(context->originalRequest.completion,
                    925:                             status,
                    926:                             context->bytesTransferred);
                    927: 
                    928:             // Release the deblocker context structure.
                    929:             drive->deblockerContextFree(context);
                    930:             return;
                    931:         }
                    932:     }
                    933: 
                    934:     //
                    935:     // Transistion to the next phase of the unaligned transfer.
                    936:     //
                    937: 
                    938:     switch (context->phase)
                    939:     {
                    940:         case kPhaseBegin:
                    941:             if (context->bytesStart)  { context->phase = kPhaseStart;  break; }
                    942:         case kPhaseStart:
                    943:             if (context->bytesMiddle) { context->phase = kPhaseMiddle; break; }
                    944:         case kPhaseMiddle:
                    945:             if (context->bytesFinal)  { context->phase = kPhaseFinal;  break; }
                    946:         case kPhaseFinal:
                    947:             context->phase = kPhaseDone;
                    948:             break;
                    949: 
                    950:         case kPhaseBeginRMW:
                    951:             if (context->bytesStart)  { context->phase = kPhaseStartRM; break; }
                    952:         case kPhaseStartW:
                    953:             if (context->bytesMiddle)
                    954:             {
                    955:                 context->phase = kPhaseMiddleW;
                    956:                 direction = kIODirectionOut;
                    957:                 break;
                    958:             }
                    959:         case kPhaseMiddleW:
                    960:             if (context->bytesFinal)  { context->phase = kPhaseFinalRM; break; }
                    961:         case kPhaseFinalW:
                    962:             context->phase = kPhaseDone;
                    963:             break;
                    964: 
                    965:         case kPhaseStartRM:
                    966:             context->phase = kPhaseStartW;
                    967:             direction = kIODirectionOut;
                    968:             break;
                    969:         case kPhaseFinalRM:
                    970:             context->phase = kPhaseFinalW;
                    971:             direction = kIODirectionOut;
                    972:             break;
                    973: 
                    974:         default:
                    975:             assert(0);
                    976:             break;
                    977:     }
                    978: 
                    979:     //
                    980:     // Build and execute the transfer for the new phase.
                    981:     //
                    982: 
                    983:     switch (context->phase)
                    984:     {
                    985:         case kPhaseStart: // - - - - - - - - - - - - - - - - - - - - - - - - - -
                    986:         case kPhaseStartRM:
                    987:         case kPhaseStartW:
                    988:             context->subrequest.byteStart = context->originalRequest.byteStart -
                    989:                                             context->offsetStart;
                    990:             context->subrequest.buffer    = context->blockBuffer;
                    991: 
                    992:             context->subrequest.buffer->initWithAddress(
                    993:                                     /* address       */ context->blockBufferPtr,
                    994:                                     /* withLength    */ mediaBlockSize,
                    995:                                     /* withDirection */ direction );
                    996:             break;
                    997: 
                    998:         case kPhaseMiddle:  // - - - - - - - - - - - - - - - - - - - - - - - - -
                    999:         case kPhaseMiddleW:
                   1000:             context->subrequest.byteStart = context->originalRequest.byteStart +
                   1001:                                             context->bytesStart;
                   1002:             context->subrequest.buffer    = context->middleBuffer;
                   1003: 
                   1004:             assert(context->middleBuffer);                           // (to fix)
                   1005:             break;
                   1006: 
                   1007:         case kPhaseFinal: // - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1008:         case kPhaseFinalRM:
                   1009:         case kPhaseFinalW:
                   1010:             context->subrequest.byteStart = context->originalRequest.byteStart +
                   1011:                                             context->bytesStart +
                   1012:                                             context->bytesMiddle;
                   1013:             context->subrequest.buffer    = context->blockBuffer;
                   1014: 
                   1015:             context->subrequest.buffer->initWithAddress(
                   1016:                                     /* address       */ context->blockBufferPtr,
                   1017:                                     /* withLength    */ mediaBlockSize,
                   1018:                                     /* withDirection */ direction );
                   1019:             break;
                   1020: 
                   1021:         case kPhaseDone:  // - - - - - - - - - - - - - - - - - - - - - - - - - -
                   1022: 
                   1023:             // Unlock the RMW-lock, to allow the next RMW to proceed.
                   1024:             if (context->originalRequest.buffer->getDirection() ==
                   1025:                                                                 kIODirectionOut)
                   1026:                 IOUnlock(drive->_deblockerLockForRMWs);
                   1027: 
                   1028:             // Release the retain we placed on the request buffer.
                   1029:             context->originalRequest.buffer->release();
                   1030: 
                   1031:             // Complete the request.
                   1032:             drive->complete(context->originalRequest.completion,
                   1033:                             kIOReturnSuccess,
                   1034:                             context->bytesTransferred);
                   1035: 
                   1036:             // Release the deblocker context structure.
                   1037:             drive->deblockerContextFree(context);
                   1038:             return;
                   1039: 
                   1040:         default:
                   1041:             assert(0);
                   1042:             break;
                   1043:     }
                   1044: 
                   1045:     // (presuming completion.target/action/parameter are unchanged)
                   1046: 
                   1047:     drive->prepareRequest(context->subrequest.byteStart,
                   1048:                           context->subrequest.buffer,
                   1049:                           context->subrequest.completion);
                   1050:     return;
                   1051: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.