|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.