]> git.saurik.com Git - apple/xnu.git/blame - iokit/Families/IOStorage/IOBlockStorageDriver.cpp
xnu-124.7.tar.gz
[apple/xnu.git] / iokit / Families / IOStorage / IOBlockStorageDriver.cpp
CommitLineData
1c79356b
A
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/IOBlockStorageDevice.h>
27#include <IOKit/storage/IOBlockStorageDriver.h>
28#include <IOKit/storage/IOMedia.h>
29
30#define super IOStorage
31OSDefineMetaClassAndStructors(IOBlockStorageDriver, IOStorage)
32
33// Hack for Cheetah to prevent sleep if there's disk activity.
34static IOService * gIORootPowerDomain = NULL;
35
36// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
37
38const UInt32 kPollerInterval = 1000; // (ms, 1 second)
39
40// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
41
42IOBlockStorageDevice * IOBlockStorageDriver::getProvider() const
43{
44 //
45 // Obtain this object's provider. We override the superclass's method to
46 // return a more specific subclass of IOService -- IOBlockStorageDevice.
47 // This method serves simply as a convenience to subclass developers.
48 //
49
50 return (IOBlockStorageDevice *) IOService::getProvider();
51}
52
53// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54
55bool IOBlockStorageDriver::init(OSDictionary * properties = 0)
56{
57 //
58 // Initialize this object's minimal state.
59 //
60
61 if (super::init(properties) == false) return false;
62
63 initMediaState();
64
65 _ejectable = false;
66 _lockable = false;
67 _pollIsExpensive = false;
68 _pollIsRequired = false;
69 _removable = false;
70
71 _mediaBlockSize = 0;
72 _maxBlockNumber = 0;
73 _maxReadByteTransfer = 0;
74 _maxWriteByteTransfer = 0;
75
76 _mediaStateLock = IOLockAlloc();
77
78 if (_mediaStateLock == 0)
79 return false;
80
81 _deblockRequestWriteLock = IOLockAlloc();
82 _openClients = OSSet::withCapacity(2);
83 _pollerCall = thread_call_allocate(poller, this);
84
85 for (unsigned index = 0; index < kStatisticsCount; index++)
86 _statistics[index] = OSNumber::withNumber(0ULL, 64);
87
88 if (_deblockRequestWriteLock == 0 || _openClients == 0 || _pollerCall == 0)
89 return false;
90
91 for (unsigned index = 0; index < kStatisticsCount; index++)
92 if (_statistics[index] == 0) return false;
93
94 //
95 // Create the standard block storage driver registry properties.
96 //
97
98 OSDictionary * statistics = OSDictionary::withCapacity(kStatisticsCount);
99
100 if (statistics == 0) return false;
101
102 statistics->setObject( kIOBlockStorageDriverStatisticsBytesReadKey,
103 _statistics[kStatisticsBytesRead] );
104 statistics->setObject( kIOBlockStorageDriverStatisticsBytesWrittenKey,
105 _statistics[kStatisticsBytesWritten] );
106 statistics->setObject( kIOBlockStorageDriverStatisticsReadErrorsKey,
107 _statistics[kStatisticsReadErrors] );
108 statistics->setObject( kIOBlockStorageDriverStatisticsWriteErrorsKey,
109 _statistics[kStatisticsWriteErrors] );
110 statistics->setObject( kIOBlockStorageDriverStatisticsLatentReadTimeKey,
111 _statistics[kStatisticsLatentReadTime] );
112 statistics->setObject( kIOBlockStorageDriverStatisticsLatentWriteTimeKey,
113 _statistics[kStatisticsLatentWriteTime] );
114 statistics->setObject( kIOBlockStorageDriverStatisticsReadsKey,
115 _statistics[kStatisticsReads] );
116 statistics->setObject( kIOBlockStorageDriverStatisticsWritesKey,
117 _statistics[kStatisticsWrites] );
118 statistics->setObject( kIOBlockStorageDriverStatisticsReadRetriesKey,
119 _statistics[kStatisticsReadRetries] );
120 statistics->setObject( kIOBlockStorageDriverStatisticsWriteRetriesKey,
121 _statistics[kStatisticsWriteRetries] );
122 statistics->setObject( kIOBlockStorageDriverStatisticsTotalReadTimeKey,
123 _statistics[kStatisticsTotalReadTime] );
124 statistics->setObject( kIOBlockStorageDriverStatisticsTotalWriteTimeKey,
125 _statistics[kStatisticsTotalWriteTime] );
126
127 setProperty(kIOBlockStorageDriverStatisticsKey, statistics);
128
129 // Hack for Cheetah to prevent sleep if there's disk activity.
130 if (!gIORootPowerDomain) {
131 // No danger of race here as we're ultimately just setting
132 // the gIORootPowerDomain variable.
133
134 do {
135 IOService * root = NULL;
136 OSIterator * iterator = NULL;
137 OSDictionary * pmDict = NULL;
138
139 root = IOService::getServiceRoot();
140 if (!root) break;
141
142 pmDict = root->serviceMatching("IOPMrootDomain");
143 if (!pmDict) break;
144
145 iterator = root->getMatchingServices(pmDict);
146 pmDict->release();
147 if (!iterator) break;
148
149 if (iterator) {
150 gIORootPowerDomain = OSDynamicCast(IOService, iterator->getNextObject());
151 iterator->release();
152 }
153 } while (false);
154 }
155
156 return true;
157}
158
159// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
160
161bool IOBlockStorageDriver::start(IOService * provider)
162{
163 //
164 // This method is called once we have been attached to the provider object.
165 //
166
167 // Open the block storage device.
168
169 if (provider->open(this) == false) return false;
170
171 // Prepare the block storage driver for operation.
172
173 if (handleStart(provider) == false)
174 {
175 provider->close(this);
176 return false;
177 }
178
179 // Initiate the poller mechanism if it is required.
180
181 if (isMediaEjectable() && isMediaPollRequired() && !isMediaPollExpensive())
182 {
183 lockForArbitration(); // (disable opens/closes; a recursive lock)
184
185 if (!isOpen() && !isInactive())
186 schedulePoller(); // (schedule the poller, increments retain)
187
188 unlockForArbitration(); // (enable opens/closes; a recursive lock)
189 }
190
191 // Register this object so it can be found via notification requests. It is
192 // not being registered to have I/O Kit attempt to have drivers match on it,
193 // which is the reason most other services are registered -- that's not the
194 // intention of this registerService call.
195
196 registerService();
197
198 return true;
199}
200
201// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
202
203bool IOBlockStorageDriver::yield(IOService * provider,
204 IOOptionBits options,
205 void * argument)
206{
207 //
208 // This method is called as a result of the kIOMessageServiceIsTerminated
209 // or kIOMessageServiceIsRequestingClose provider messages. The argument
210 // is passed in as-is from the message. The kIOServiceRequired option is
211 // set for the kIOMessageServiceIsTerminated message to indicate that the
212 // yield must succeed.
213 //
214
215 bool success = false;
216
217 lockForArbitration();
218
219 // Yield the block storage device.
220
221 success = handleYield(provider, options, argument);
222
223 if (success)
224 {
225 // Close the block storage device.
226
227 provider->close(this);
228 }
229
230 unlockForArbitration();
231
232 return success;
233}
234
235// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
236
237void IOBlockStorageDriver::free()
238{
239 //
240 // Free all of this object's outstanding resources.
241 //
242
243 if (_mediaStateLock) IOLockFree(_mediaStateLock);
244
245 if (_deblockRequestWriteLock) IOLockFree(_deblockRequestWriteLock);
246 if (_openClients) _openClients->release();
247 if (_pollerCall) thread_call_free(_pollerCall);
248
249 for (unsigned index = 0; index < kStatisticsCount; index++)
250 if (_statistics[index]) _statistics[index]->release();
251
252 super::free();
253}
254
255// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
256
257bool IOBlockStorageDriver::handleOpen(IOService * client,
258 IOOptionBits options,
259 void * argument)
260{
261 //
262 // The handleOpen method grants or denies permission to access this object
263 // to an interested client. The argument is an IOStorageAccess value that
264 // specifies the level of access desired -- reader or reader-writer.
265 //
266 // This method can be invoked to upgrade or downgrade the access level for
267 // an existing client as well. The previous access level will prevail for
268 // upgrades that fail, of course. A downgrade should never fail. If the
269 // new access level should be the same as the old for a given client, this
270 // method will do nothing and return success. In all cases, one, singular
271 // close-per-client is expected for all opens-per-client received.
272 //
273 // This method assumes that the arbitration lock is held.
274 //
275
276 assert(client);
277
278 // Ensure there is media in the block storage device.
279
280 if (getMediaState() == kIOMediaStateOffline) return false;
281
282 // Handle the first open on removable media in a special case.
283
284 if (isMediaEjectable() && _openClients->getCount() == 0)
285 {
286 // Halt the poller if it is active and this is the first open.
287
288 if (isMediaPollRequired() && !isMediaPollExpensive())
289 unschedulePoller(); // (unschedule the poller)
290
291 // Lock down the media while we have opens on this driver object.
292
293 if (lockMedia(true) != kIOReturnSuccess)
294 IOLog("%s: Unable to lock down removable media.\n", getName());
295 }
296
297 // Process the open.
298
299 _openClients->setObject(client); // (works for up/downgrade case)
300
301 return true;
302}
303
304// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
305
306bool IOBlockStorageDriver::handleIsOpen(const IOService * client) const
307{
308 //
309 // The handleIsOpen method determines whether the specified client, or any
310 // client if none is specificed, presently has an open on this object.
311 //
312 // This method assumes that the arbitration lock is held.
313 //
314
315 if (client)
316 return _openClients->containsObject(client);
317 else
318 return (_openClients->getCount() != 0);
319}
320
321// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
322
323void IOBlockStorageDriver::handleClose(IOService * client, IOOptionBits options)
324{
325 //
326 // The handleClose method drops the incoming client's access to this object.
327 //
328 // This method assumes that the arbitration lock is held.
329 //
330
331 assert(client);
332
333 // Process the close.
334
335 _openClients->removeObject(client);
336
337 // Handle the last close in a special case.
338
339 if (!isInactive() && _openClients->getCount() == 0)
340 {
341 if (isMediaWritable())
342 {
343 if (getMediaState() == kIOMediaStateOnline)
344 {
345 // Synchronize the cache on writeable media.
346
347 if (synchronizeCache(this) != kIOReturnSuccess)
348 IOLog("%s: Unable to flush cache on media.\n", getName());
349 }
350 }
351
352 if (isMediaEjectable())
353 {
354 // Unlock the removable media.
355
356 if (getMediaState() == kIOMediaStateOnline)
357 {
358 if (lockMedia(false) != kIOReturnSuccess)
359 IOLog("%s: Unable to unlock removable media.\n", getName());
360 }
361
362 // Reactivate the poller.
363
364 if (isMediaPollRequired() && !isMediaPollExpensive())
365 schedulePoller(); // (schedule the poller, increments retain)
366 }
367 }
368}
369
370// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
371
372void IOBlockStorageDriver::read(IOService * /* client */,
373 UInt64 byteStart,
374 IOMemoryDescriptor * buffer,
375 IOStorageCompletion completion)
376{
377 //
378 // The read method is the receiving end for all read requests from the
379 // storage framework, ie. via the media object created by this driver.
380 //
381 // This method kicks off a sequence of three methods for each read or write
382 // request. The first is prepareRequest, which allocates and prepares some
383 // context for the transfer; the second is deblockRequest, which aligns the
384 // transfer at the media block boundaries; and the third is executeRequest,
385 // which implements the actual transfer from the block storage device.
386 //
387
388 // State our assumptions.
389
390 assert(buffer->getDirection() == kIODirectionIn);
391
392 // Prepare the transfer.
393
394 prepareRequest(byteStart, buffer, completion);
395}
396
397// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
398
399void IOBlockStorageDriver::write(IOService * /* client */,
400 UInt64 byteStart,
401 IOMemoryDescriptor * buffer,
402 IOStorageCompletion completion)
403{
404 //
405 // The write method is the receiving end for all write requests from the
406 // storage framework, ie. via the media object created by this driver.
407 //
408 // This method kicks off a sequence of three methods for each read or write
409 // request. The first is prepareRequest, which allocates and prepares some
410 // context for the transfer; the second is deblockRequest, which aligns the
411 // transfer at the media block boundaries; and the third is executeRequest,
412 // which implements the actual transfer from the block storage driver.
413 //
414
415 // State our assumptions.
416
417 assert(buffer->getDirection() == kIODirectionOut);
418
419 // Prepare the transfer.
420
421 prepareRequest(byteStart, buffer, completion);
422}
423
424// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
425
426void IOBlockStorageDriver::addToBytesTransferred(UInt64 bytesTransferred,
427 UInt64 totalTime, // (ns)
428 UInt64 latentTime, // (ns)
429 bool isWrite)
430{
431 //
432 // Update the total number of bytes transferred, the total transfer time,
433 // and the total latency time -- used for statistics.
434 //
435
436 if (isWrite)
437 {
438 _statistics[kStatisticsWrites]->addValue(1);
439 _statistics[kStatisticsBytesWritten]->addValue(bytesTransferred);
440 _statistics[kStatisticsTotalWriteTime]->addValue(totalTime);
441 _statistics[kStatisticsLatentWriteTime]->addValue(latentTime);
442 if (bytesTransferred <= getMediaBlockSize())
443 _statistics[kStatisticsSingleBlockWrites]->addValue(1);
444 }
445 else
446 {
447 _statistics[kStatisticsReads]->addValue(1);
448 _statistics[kStatisticsBytesRead]->addValue(bytesTransferred);
449 _statistics[kStatisticsTotalReadTime]->addValue(totalTime);
450 _statistics[kStatisticsLatentReadTime]->addValue(latentTime);
451 }
452}
453
454// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
455
456void IOBlockStorageDriver::incrementRetries(bool isWrite)
457{
458 //
459 // Update the total retry count -- used for statistics.
460 //
461
462 if (isWrite)
463 _statistics[kStatisticsWriteRetries]->addValue(1);
464 else
465 _statistics[kStatisticsReadRetries]->addValue(1);
466}
467
468// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
469
470void IOBlockStorageDriver::incrementErrors(bool isWrite)
471{
472 //
473 // Update the total error count -- used for statistics.
474 //
475
476 if (isWrite)
477 _statistics[kStatisticsWriteErrors]->addValue(1);
478 else
479 _statistics[kStatisticsReadErrors]->addValue(1);
480}
481
482// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
483
484UInt32 IOBlockStorageDriver::getStatistics(UInt64 * statistics,
485 UInt32 statisticsMaxCount) const
486{
487 //
488 // Ask the driver to report its operating statistics.
489 //
490 // The statistics are each indexed by IOBlockStorageDriver::Statistics
491 // indices. This routine fills the caller's buffer, up to the maximum
492 // count specified if the real number of statistics would overflow the
493 // buffer. The return value indicates the actual number of statistics
494 // copied to the buffer.
495 //
496 // If the statistics buffer is not supplied or if the maximum count is
497 // zero, the routine returns the proposed count of statistics instead.
498 //
499
500 if (statistics == 0)
501 return kStatisticsCount;
502
503 UInt32 statisticsCount = min(kStatisticsCount, statisticsMaxCount);
504
505 for (unsigned index = 0; index < statisticsCount; index++)
506 statistics[index] = _statistics[index]->unsigned64BitValue();
507
508 return statisticsCount;
509}
510
511// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
512
513UInt64 IOBlockStorageDriver::getStatistic(Statistics statistic) const
514{
515 //
516 // Ask the driver to report one of its operating statistics.
517 //
518
519 if ((UInt32) statistic >= kStatisticsCount) return 0;
520
521 return _statistics[statistic]->unsigned64BitValue();
522}
523
524// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
525
526IOBlockStorageDriver::Context * IOBlockStorageDriver::allocateContext()
527{
528 //
529 // Allocate a context structure for a read/write operation.
530 //
531
532 Context * context = IONew(Context, 1);
533
534 if (context)
535 {
536 bzero(context, sizeof(Context));
537 }
538
539 return context;
540}
541
542// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
543
544void IOBlockStorageDriver::deleteContext(
545 IOBlockStorageDriver::Context * context)
546{
547 //
548 // Delete a context structure from a read/write operation.
549 //
550
551 IODelete(context, Context, 1);
552}
553
554// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
555
556void IOBlockStorageDriver::prepareRequest(UInt64 byteStart,
557 IOMemoryDescriptor * buffer,
558 IOStorageCompletion completion)
559{
560 //
561 // The prepareRequest method allocates and prepares state for the transfer.
562 //
563 // This method is part of a sequence of methods invoked for each read/write
564 // request. The first is prepareRequest, which allocates and prepares some
565 // context for the transfer; the second is deblockRequest, which aligns the
566 // transfer at the media block boundaries; and the third is executeRequest,
567 // which implements the actual transfer from the block storage device.
568 //
569
570 Context * context;
571 IOReturn status;
572
573 // Allocate a context structure to hold some of our state.
574
575 context = allocateContext();
576
577 if (context == 0)
578 {
579 complete(completion, kIOReturnNoMemory);
580 return;
581 }
582
583 // Prepare the transfer buffer.
584
585 status = buffer->prepare();
586
587 if (status != kIOReturnSuccess)
588 {
589 deleteContext(context);
590 complete(completion, status);
591 return;
592 }
593
594 // Fill in the context structure with some of our state.
595
596 context->block.size = getMediaBlockSize();
597 context->block.type = kBlockTypeStandard;
598
599 context->original.byteStart = byteStart;
600 context->original.buffer = buffer;
601 context->original.buffer->retain();
602 context->original.completion = completion;
603
604 completion.target = this;
605 completion.action = prepareRequestCompletion;
606 completion.parameter = context;
607
608 // Deblock the transfer.
609
610 deblockRequest(byteStart, buffer, completion, context);
611}
612
613// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
614
615void IOBlockStorageDriver::prepareRequestCompletion(void * target,
616 void * parameter,
617 IOReturn status,
618 UInt64 actualByteCount)
619{
620 //
621 // This is the completion routine for the prepared request. It updates
622 // the driver's statistics, performs some clean up work, then calls the
623 // original request's completion routine.
624 //
625
626 Context * context = (Context *) parameter;
627 IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
628 bool isWrite;
629
630 isWrite = (context->original.buffer->getDirection() == kIODirectionOut);
631
632 // State our assumptions.
633
634 assert(status != kIOReturnSuccess ||
635 context->original.buffer->getLength() == actualByteCount);
636
637 // Update the total number of bytes transferred.
638
639 driver->addToBytesTransferred(actualByteCount, 0, 0, isWrite);
640
641 // Update the total error count.
642
643 if (status != kIOReturnSuccess)
644 {
645 driver->incrementErrors(isWrite);
646 }
647
648 // Complete the transfer buffer.
649
650 context->original.buffer->complete();
651
652 // Complete the transfer request.
653
654 IOStorage::complete(context->original.completion, status, actualByteCount);
655
656 // Release our resources.
657
658 context->original.buffer->release();
659
660 driver->deleteContext(context);
661}
662
663// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
664
665void IOBlockStorageDriver::schedulePoller()
666{
667 //
668 // Schedule the poller mechanism.
669 //
670 // This method assumes that the arbitration lock is held.
671 //
672
673 AbsoluteTime deadline;
674
675 retain();
676
677 clock_interval_to_deadline(kPollerInterval, kMillisecondScale, &deadline);
678 thread_call_enter_delayed(_pollerCall, deadline);
679}
680
681// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
682
683void IOBlockStorageDriver::unschedulePoller()
684{
685 //
686 // Unschedule the poller mechanism.
687 //
688 // This method assumes that the arbitration lock is held.
689 //
690
691 if (thread_call_cancel(_pollerCall)) release();
692}
693
694// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
695
696void IOBlockStorageDriver::poller(void * target, void *)
697{
698 //
699 // This method is the timeout handler for the poller mechanism. It polls
700 // for media and reschedules another timeout if there are still no opens.
701 //
702
703 IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
704
705 driver->pollMedia();
706
707 driver->lockForArbitration(); // (disable opens/closes; a recursive lock)
708
709 if (!driver->isOpen() && !driver->isInactive())
710 driver->schedulePoller(); // (schedule the poller, increments retain)
711
712 driver->unlockForArbitration(); // (enable opens/closes; a recursive lock)
713
714 driver->release(); // (drop the retain associated with this poll)
715}
716
717
718// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
719
720IOReturn IOBlockStorageDriver::message(UInt32 type,
721 IOService * provider,
722 void * argument)
723{
724 //
725 // Generic entry point for calls from the provider. A return value of
726 // kIOReturnSuccess indicates that the message was received, and where
727 // applicable, that it was successful.
728 //
729
730 switch (type)
731 {
732 case kIOMessageMediaStateHasChanged:
733 {
734 IOReturn status;
735 IOLockLock(_mediaStateLock);
736 status = mediaStateHasChanged((IOMediaState) argument);
737 IOLockUnlock(_mediaStateLock);
738 return status;
739 }
740 case kIOMessageServiceIsRequestingClose:
741 {
742 bool success;
743 success = yield(provider, 0, argument);
744 return success ? kIOReturnSuccess : kIOReturnBusy;
745 }
746 case kIOMessageServiceIsTerminated:
747 {
748 bool success;
749 success = yield(provider, kIOServiceRequired, argument);
750 return success ? kIOReturnSuccess : kIOReturnError;
751 }
752 default:
753 {
754 return super::message(type, provider, argument);
755 }
756 }
757}
758
759// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
760
761/* Accept a new piece of media, doing whatever's necessary to make it
762 * show up properly to the system. The arbitration lock is assumed to
763 * be held during the call.
764 */
765IOReturn
766IOBlockStorageDriver::acceptNewMedia(void)
767{
768 IOReturn result;
769 bool ok;
770 UInt64 nbytes;
771 char name[128];
772 bool nameSep;
773
774 /* Since the kernel printf doesn't handle 64-bit integers, we
775 * simply make an assumption that the block count and size
776 * will be 32-bit values max.
777 */
778
779#ifdef moreDebug
780 IOLog("%s[IOBlockStorageDriver]::%s media: %ld blocks, %ld bytes each, write-%s.\n",
781 getName(),
782 getDeviceTypeName(),
783 (UInt32)_maxBlockNumber + 1,(UInt32)getMediaBlockSize(),
784 (_writeProtected ? "protected" : "enabled"));
785#endif
786
787 if (_maxBlockNumber) {
788 nbytes = _mediaBlockSize * (_maxBlockNumber + 1);
789 } else {
790 nbytes = 0;
791 }
792
793 /* Instantiate a media object and attach it to ourselves. */
794
795 name[0] = 0;
796 nameSep = false;
797 if (getProvider()->getVendorString()) {
798 strcat(name, getProvider()->getVendorString());
799 nameSep = true;
800 }
801 if (getProvider()->getProductString()) {
802 if (nameSep == true) strcat(name, " ");
803 strcat(name, getProvider()->getProductString());
804 nameSep = true;
805 }
806 if (nameSep == true) strcat(name, " ");
807 strcat(name, "Media");
808
809 _mediaObject = instantiateMediaObject(0,nbytes,_mediaBlockSize,name);
810 result = (_mediaObject) ? kIOReturnSuccess : kIOReturnBadArgument;
811
812 if (result == kIOReturnSuccess) {
813 ok = _mediaObject->attach(this); /* attach media object above us */
814 if (ok) {
815 _mediaPresent = true;
816 _mediaObject->registerService(); /* enable matching */
817 } else {
818 _mediaObject->release();
819 _mediaObject = 0;
820 return(kIOReturnNoMemory); /* give up now */
821 }
822 }
823
824 return(result);
825}
826
827IOReturn
828IOBlockStorageDriver::checkForMedia(void)
829{
830 IOReturn result;
831 bool currentState;
832 bool changed;
833
834 IOLockLock(_mediaStateLock);
835
836 result = getProvider()->reportMediaState(&currentState,&changed);
837 if (result != kIOReturnSuccess) { /* the poll operation failed */
838 IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from reportMediaState\n",
839 getName(),stringFromReturn(result));
840 } else if (changed) { /* the poll succeeded, media state has changed */
841 result = mediaStateHasChanged(currentState ? kIOMediaStateOnline
842 : kIOMediaStateOffline);
843 }
844
845 IOLockUnlock(_mediaStateLock);
846 return(result);
847}
848
849IOReturn
850IOBlockStorageDriver::mediaStateHasChanged(IOMediaState state)
851{
852 IOReturn result;
853
854 /* The media has changed state. See if it's just inserted or removed. */
855
856 if (state == kIOMediaStateOnline) { /* media is now present */
857
858 /* Allow a subclass to decide whether we accept the media. Such a
859 * decision might be based on things like password-protection, etc.
860 */
861
862 if (validateNewMedia() == false) { /* we're told to reject it */
863 rejectMedia(); /* so let subclass do whatever it wants */
864 return(kIOReturnSuccess); /* pretend nothing happened */
865 }
866
867 result = recordMediaParameters(); /* learn about media */
868 if (result != kIOReturnSuccess) { /* couldn't record params */
869 initMediaState(); /* deny existence of new media */
870 IOLog("%s[IOBlockStorageDriver]::checkForMedia: err '%s' from recordMediaParameters\n",
871 getName(),stringFromReturn(result));
872 return(result);
873 }
874
875 /* Now we do what's necessary to make the new media
876 * show up properly in the system.
877 */
878
879 lockForArbitration();
880 result = acceptNewMedia();
881
882 if (result != kIOReturnSuccess) {
883 initMediaState(); /* deny existence of new media */
884 IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from acceptNewMedia\n",
885 getName(),stringFromReturn(result));
886 }
887
888 unlockForArbitration();
889 return(result); /* all done, new media is ready */
890
891 } else { /* media is now absent */
892
893 lockForArbitration();
894 result = decommissionMedia(true); /* force a teardown */
895 unlockForArbitration();
896
897 if (result != kIOReturnSuccess && result != kIOReturnNoMedia) {
898 IOLog("%s[IOBlockStorageDriver]::checkForMedia; err '%s' from decommissionNewMedia\n",
899 getName(),stringFromReturn(result));
900 return(result);
901 }
902
903 return(kIOReturnSuccess); /* all done; media is gone */
904 }
905}
906
907UInt64
908IOBlockStorageDriver::constrainByteCount(UInt64 /* requestedCount */ ,bool isWrite)
909{
910 if (isWrite) {
911 return(_maxWriteByteTransfer);
912 } else {
913 return(_maxReadByteTransfer);
914 }
915}
916
917/* Decommission a piece of media that has become unavailable either due to
918 * ejection or some outside force (e.g. the Giant Hand of the User).
919 * (I prefer the term "decommission" rather than "abandon." The former implies
920 * a well-determined procedure, whereas the latter implies leaving the media
921 * in an orphaned state.)
922 */
923/* Tear down the stack above the specified object. Usually these objects will
924 * be of type IOMedia, but they could be any IOService. The arbitration lock is
925 * assumed to be held during the call.
926 */
927IOReturn
928IOBlockStorageDriver::decommissionMedia(bool forcible)
929{
930 IOReturn result;
931
932 if (_mediaObject) {
933 /* If this is a forcible decommission (i.e. media is gone), we don't
934 * care whether the teardown worked; we forget about the media.
935 */
936 if (_mediaObject->terminate(forcible ? kIOServiceRequired : 0) || forcible) {
937 _mediaObject->release();
938 _mediaObject = 0;
939
940 initMediaState(); /* clear all knowledge of the media */
941 result = kIOReturnSuccess;
942
943 } else {
944 result = kIOReturnBusy;
945 }
946 } else {
947 result = kIOReturnNoMedia;
948 }
949
950 return(result);
951}
952
953IOReturn
954IOBlockStorageDriver::ejectMedia(void)
955{
956 IOReturn result;
957
958 if (_removable) {
959
960 IOLockLock(_mediaStateLock);
961
962 lockForArbitration();
963 result = decommissionMedia(false); /* try to teardown */
964 unlockForArbitration();
965
966 if (result == kIOReturnSuccess) { /* eject */
967 if (lockMedia(false) != kIOReturnSuccess)
968 IOLog("%s: Unable to unlock removable media.\n", getName());
969
970 (void)getProvider()->doEjectMedia(); /* ignore any error */
971 }
972
973 IOLockUnlock(_mediaStateLock);
974
975 return(result);
976
977 } else {
978 return(kIOReturnUnsupported);
979 }
980}
981
982void
983IOBlockStorageDriver::executeRequest(UInt64 byteStart,
984 IOMemoryDescriptor * buffer,
985 IOStorageCompletion completion,
986 IOBlockStorageDriver::Context * context)
987{
988 UInt32 block;
989 UInt32 nblks;
990 IOReturn result;
991
992 if (!_mediaPresent) { /* no media? you lose */
993 complete(completion, kIOReturnNoMedia,0);
994 return;
995 }
996
997 /* We know that we are never called with a request too large,
998 * nor one that is misaligned with a block.
999 */
1000 assert((byteStart % _mediaBlockSize) == 0);
1001 assert((buffer->getLength() % _mediaBlockSize) == 0);
1002
1003 block = byteStart / _mediaBlockSize;
1004 nblks = buffer->getLength() / _mediaBlockSize;
1005
1006/* Now the protocol-specific provider implements the actual
1007 * start of the data transfer: */
1008
1009 // Tickle the root power domain to reset the sleep countdown.
1010 if (gIORootPowerDomain) {
1011 gIORootPowerDomain->activityTickle(kIOPMSubclassPolicy);
1012 }
1013
1014 result = getProvider()->doAsyncReadWrite(buffer,block,nblks,completion);
1015
1016 if (result != kIOReturnSuccess) { /* it failed to start */
1017 IOLog("%s[IOBlockStorageDriver]; executeRequest: request failed to start!\n",getName());
1018 complete(completion,result);
1019 return;
1020 }
1021}
1022
1023IOReturn
1024IOBlockStorageDriver::formatMedia(UInt64 byteCapacity)
1025{
1026 if (!_mediaPresent) {
1027 return(kIOReturnNoMedia);
1028 }
1029
1030 return(getProvider()->doFormatMedia(byteCapacity));
1031}
1032
1033const char *
1034IOBlockStorageDriver::getDeviceTypeName(void)
1035{
1036 return(kIOBlockStorageDeviceTypeGeneric);
1037}
1038
1039UInt32
1040IOBlockStorageDriver::getFormatCapacities(UInt64 * capacities,
1041 UInt32 capacitiesMaxCount) const
1042{
1043 return(getProvider()->doGetFormatCapacities(capacities,capacitiesMaxCount));
1044}
1045
1046UInt64
1047IOBlockStorageDriver::getMediaBlockSize() const
1048{
1049 return(_mediaBlockSize);
1050}
1051
1052IOMediaState
1053IOBlockStorageDriver::getMediaState() const
1054{
1055 if (_mediaPresent) {
1056 return(kIOMediaStateOnline);
1057 } else {
1058 return(kIOMediaStateOffline);
1059 }
1060}
1061
1062bool
1063IOBlockStorageDriver::handleStart(IOService * provider)
1064{
1065 IOReturn result;
1066
1067 /* Print device name/type information on the console: */
1068
1069 /*The protocol-specific provider determines whether the media is removable. */
1070
1071 result = getProvider()->reportRemovability(&_removable);
1072 if (result != kIOReturnSuccess) {
1073 IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportRemovability\n",
1074 getName(),stringFromReturn(result));
1075 return(false);
1076 }
1077
1078 if (_removable) {
1079
1080 /* The protocol-specific provider determines whether we must poll to detect
1081 * media insertion. Nonremovable devices never need polling.
1082 */
1083
1084 result = getProvider()->reportPollRequirements(&_pollIsRequired,&_pollIsExpensive);
1085
1086 if (result != kIOReturnSuccess) {
1087 IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportPollRequirements\n",
1088 getName(),stringFromReturn(result));
1089 return(false);
1090 }
1091
1092 /* The protocol-specific provider determines whether the media is ejectable
1093 * under software control.
1094 */
1095 result = getProvider()->reportEjectability(&_ejectable);
1096 if (result != kIOReturnSuccess) {
1097 IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportEjectability\n",
1098 getName(),stringFromReturn(result));
1099 return(false);
1100 }
1101
1102 /* The protocol-specific provider determines whether the media is lockable
1103 * under software control.
1104 */
1105 result = getProvider()->reportLockability(&_lockable);
1106 if (result != kIOReturnSuccess) {
1107 IOLog("%s[IOBlockStorageDriver]::handleStart; err '%s' from reportLockability\n",
1108 getName(),stringFromReturn(result));
1109 return(false);
1110 }
1111
1112 } else { /* fixed disk: not ejectable, not lockable */
1113 _ejectable = false;
1114 _lockable = false;
1115 _pollIsRequired = true; /* polling detects device disappearance */
1116 }
1117
1118 /* Check for the device being ready with media inserted: */
1119
1120 result = checkForMedia();
1121
1122 /* The poll should never fail for nonremovable media: */
1123
1124 if (result != kIOReturnSuccess && !_removable) {
1125 IOLog("%s[IOBlockStorageDriver]::handleStart: err '%s' from checkForMedia\n",
1126 getName(),stringFromReturn(result));
1127 return(false);
1128 }
1129
1130 return(true);
1131}
1132
1133/* The driver has been instructed to yield. The arbitration lock is assumed to
1134 * be held during the call.
1135 */
1136bool
1137IOBlockStorageDriver::handleYield(IOService * provider,
1138 IOOptionBits options,
1139 void * argument)
1140{
1141 // Determine whether we can yield (for non-required yield requests).
1142
1143 if ( (options & kIOServiceRequired) == 0 && isOpen() != false )
1144 {
1145 return false;
1146 }
1147
1148 // Halt the poller mechanism.
1149
1150 if ( isMediaEjectable() != false &&
1151 isMediaPollRequired() != false &&
1152 isMediaPollExpensive() == false )
1153 {
1154 unschedulePoller(); // (unschedule the poller)
1155 }
1156
1157 // Force a teardown.
1158
1159 decommissionMedia(true);
1160
1161 return true;
1162}
1163
1164void
1165IOBlockStorageDriver::initMediaState(void)
1166{
1167 _mediaPresent = false;
1168 _writeProtected = false;
1169}
1170
1171IOMedia *
1172IOBlockStorageDriver::instantiateDesiredMediaObject(void)
1173{
1174 return(new IOMedia);
1175}
1176
1177IOMedia *
1178IOBlockStorageDriver::instantiateMediaObject(UInt64 base,UInt64 byteSize,
1179 UInt32 blockSize,char *mediaName)
1180{
1181 IOMedia *m;
1182 bool result;
1183
1184 m = instantiateDesiredMediaObject();
1185 if (m == NULL) {
1186 return(NULL);
1187 }
1188
1189 result = m->init( base, /* base byte offset */
1190 byteSize, /* byte size */
1191 blockSize, /* preferred block size */
1192 _ejectable, /* TRUE if ejectable */
1193 true, /* TRUE if whole physical media */
1194 !_writeProtected, /* TRUE if writable */
1195 ""); /* content hint */
1196
1197 if (result) {
1198 m->setName(mediaName);
1199 return(m);
1200
1201 } else { /* some init error */
1202 m->release();
1203 return(NULL); /* beats me...call it this error */
1204 }
1205}
1206
1207bool
1208IOBlockStorageDriver::isMediaEjectable(void) const
1209{
1210 return(_ejectable);
1211}
1212
1213bool
1214IOBlockStorageDriver::isMediaPollExpensive(void) const
1215{
1216 return(_pollIsExpensive);
1217}
1218
1219bool
1220IOBlockStorageDriver::isMediaPollRequired(void) const
1221{
1222 return(_pollIsRequired);
1223}
1224
1225bool
1226IOBlockStorageDriver::isMediaWritable(void) const
1227{
1228 return(!_writeProtected);
1229}
1230
1231IOReturn
1232IOBlockStorageDriver::lockMedia(bool locked)
1233{
1234 if (_lockable) {
1235 return(getProvider()->doLockUnlockMedia(locked));
1236 } else {
1237 return(kIOReturnUnsupported);
1238 }
1239}
1240
1241IOReturn
1242IOBlockStorageDriver::pollMedia(void)
1243{
1244 if (!_pollIsRequired) { /* shouldn't poll; it's an error */
1245
1246 return(kIOReturnUnsupported);
1247
1248 } else { /* poll is required...do it */
1249
1250 return(checkForMedia());
1251
1252 }
1253}
1254
1255IOReturn
1256IOBlockStorageDriver::recordMediaParameters(void)
1257{
1258 IOReturn result;
1259
1260 /* Determine the device's block size and max block number.
1261 * What should an unformatted device report? All zeroes, or an error?
1262 */
1263
1264 result = getProvider()->reportBlockSize(&_mediaBlockSize);
1265 if (result != kIOReturnSuccess) {
1266 goto err;
1267 }
1268
1269 result = getProvider()->reportMaxValidBlock(&_maxBlockNumber);
1270 if (result != kIOReturnSuccess) {
1271 goto err;
1272 }
1273
1274 /* Calculate the maximum allowed byte transfers for reads and writes. */
1275
1276 result = getProvider()->reportMaxReadTransfer(_mediaBlockSize,&_maxReadByteTransfer);
1277 if (result != kIOReturnSuccess) {
1278 goto err;
1279 }
1280
1281 result = getProvider()->reportMaxWriteTransfer(_mediaBlockSize,&_maxWriteByteTransfer);
1282 if (result != kIOReturnSuccess) {
1283 goto err;
1284 }
1285
1286 /* Is the media write-protected? */
1287
1288 result = getProvider()->reportWriteProtection(&_writeProtected);
1289 if (result != kIOReturnSuccess) {
1290 goto err;
1291 }
1292
1293 return(kIOReturnSuccess); /* everything was successful */
1294
1295 /* If we fall thru to here, we had some kind of error. Set everything to
1296 * a reasonable state since we haven't got any real information.
1297 */
1298
1299err:
1300 _mediaPresent = false;
1301 _writeProtected = true;
1302
1303 return(result);
1304}
1305
1306void
1307IOBlockStorageDriver::rejectMedia(void)
1308{
1309 (void)getProvider()->doEjectMedia(); /* eject it, ignoring any error */
1310 initMediaState(); /* deny existence of new media */
1311}
1312
1313IOReturn
1314IOBlockStorageDriver::synchronizeCache(IOService *client)
1315{
1316 return(getProvider()->doSynchronizeCache());
1317}
1318
1319bool
1320IOBlockStorageDriver::validateNewMedia(void)
1321{
1322 return(true);
1323}
1324
1325// -----------------------------------------------------------------------------
1326// Deblocker Implementation
1327
1328#include <IOKit/IOBufferMemoryDescriptor.h>
1329
1330class IODeblocker : public IOMemoryDescriptor
1331{
1332 OSDeclareDefaultStructors(IODeblocker);
1333
1334protected:
1335
1336 UInt64 _blockSize;
1337
1338 struct
1339 {
1340 IOMemoryDescriptor * buffer;
1341 UInt32 offset;
1342 UInt32 length;
1343 } _chunks[3];
1344 UInt32 _chunksCount;
1345
1346 IOBufferMemoryDescriptor * _excessBuffer;
1347 UInt64 _excessCountFinal;
1348 UInt64 _excessCountStart;
1349
1350 IOMemoryDescriptor * _requestBuffer;
1351 IOStorageCompletion _requestCompletion;
1352 void * _requestContext;
1353 UInt64 _requestCount;
1354 bool _requestIsOneBlock;
1355 UInt64 _requestStart;
1356
1357 enum
1358 {
1359 kStageInit,
1360 kStagePrepareExcessStart,
1361 kStagePrepareExcessFinal,
1362 kStageLast,
1363 kStageDone
1364 } _stage;
1365
1366 virtual void free();
1367
1368 virtual bool initWithAddress( void * address, /* not supported */
1369 IOByteCount withLength,
1370 IODirection withDirection );
1371
1372 virtual bool initWithAddress( vm_address_t address, /* not supported */
1373 IOByteCount withLength,
1374 IODirection withDirection,
1375 task_t withTask );
1376
1377 virtual bool initWithPhysicalAddress(
1378 IOPhysicalAddress address, /* not supported */
1379 IOByteCount withLength,
1380 IODirection withDirection );
1381
1382 virtual bool initWithPhysicalRanges(
1383 IOPhysicalRange * ranges, /* not supproted */
1384 UInt32 withCount,
1385 IODirection withDirection,
1386 bool asReference = false );
1387
1388 virtual bool initWithRanges( IOVirtualRange * ranges, /* not supported */
1389 UInt32 withCount,
1390 IODirection withDirection,
1391 task_t withTask,
1392 bool asReference = false );
1393
1394 virtual void * getVirtualSegment( IOByteCount offset, /* not supported */
1395 IOByteCount * length );
1396
1397 IOMemoryDescriptor::withAddress; /* not supported */
1398 IOMemoryDescriptor::withPhysicalAddress; /* not supported */
1399 IOMemoryDescriptor::withPhysicalRanges; /* not supported */
1400 IOMemoryDescriptor::withRanges; /* not supported */
1401 IOMemoryDescriptor::withSubRange; /* not supported */
1402
1403public:
1404
1405 static IODeblocker * withBlockSize(
1406 UInt64 blockSize,
1407 UInt64 withRequestStart,
1408 IOMemoryDescriptor * withRequestBuffer,
1409 IOStorageCompletion withRequestCompletion,
1410 void * withRequestContext );
1411
1412 virtual bool initWithBlockSize(
1413 UInt64 blockSize,
1414 UInt64 withRequestStart,
1415 IOMemoryDescriptor * withRequestBuffer,
1416 IOStorageCompletion withRequestCompletion,
1417 void * withRequestContext );
1418
1419 virtual IOPhysicalAddress getPhysicalSegment( IOByteCount offset,
1420 IOByteCount * length );
1421
1422 virtual IOReturn prepare(IODirection forDirection = kIODirectionNone);
1423
1424 virtual IOReturn complete(IODirection forDirection = kIODirectionNone);
1425
1426 virtual IOByteCount readBytes( IOByteCount offset,
1427 void * bytes,
1428 IOByteCount withLength );
1429
1430 virtual IOByteCount writeBytes( IOByteCount offset,
1431 const void * bytes,
1432 IOByteCount withLength );
1433
1434 virtual bool getNextStage(UInt64 * byteStart);
1435
1436 virtual void getRequestCompletion( IOStorageCompletion * completion,
1437 IOReturn * status,
1438 UInt64 * actualByteCount );
1439
1440 virtual IOMemoryDescriptor * getRequestBuffer();
1441
1442 virtual void * getRequestContext();
1443};
1444
1445// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1446
1447#undef super
1448#define super IOMemoryDescriptor
1449OSDefineMetaClassAndStructors(IODeblocker, IOMemoryDescriptor)
1450
1451// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1452
1453bool IODeblocker::initWithAddress( void * /* address */ ,
1454 IOByteCount /* withLength */ ,
1455 IODirection /* withDirection */ )
1456{
1457 return false;
1458}
1459
1460// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1461
1462bool IODeblocker::initWithAddress( vm_address_t /* address */ ,
1463 IOByteCount /* withLength */ ,
1464 IODirection /* withDirection */ ,
1465 task_t /* withTask */ )
1466{
1467 return false;
1468}
1469
1470// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1471
1472bool IODeblocker::initWithPhysicalAddress(
1473 IOPhysicalAddress /* address */ ,
1474 IOByteCount /* withLength */ ,
1475 IODirection /* withDirection */ )
1476{
1477 return false;
1478}
1479
1480
1481// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1482
1483bool IODeblocker::initWithPhysicalRanges(
1484 IOPhysicalRange * /* ranges */ ,
1485 UInt32 /* withCount */ ,
1486 IODirection /* withDirection */ ,
1487 bool /* asReference */ )
1488{
1489 return false;
1490}
1491
1492// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1493
1494bool IODeblocker::initWithRanges( IOVirtualRange * /* ranges */ ,
1495 UInt32 /* withCount */ ,
1496 IODirection /* withDirection */ ,
1497 task_t /* withTask */ ,
1498 bool /* asReference */ )
1499{
1500 return false;
1501}
1502
1503// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1504
1505IODeblocker * IODeblocker::withBlockSize(
1506 UInt64 blockSize,
1507 UInt64 withRequestStart,
1508 IOMemoryDescriptor * withRequestBuffer,
1509 IOStorageCompletion withRequestCompletion,
1510 void * withRequestContext )
1511{
1512 //
1513 // Create a new IODeblocker.
1514 //
1515
1516 IODeblocker * me = new IODeblocker;
1517
1518 if ( me && me->initWithBlockSize(
1519 /* blockSize */ blockSize,
1520 /* withRequestStart */ withRequestStart,
1521 /* withRequestBuffer */ withRequestBuffer,
1522 /* withRequestCompletion */ withRequestCompletion,
1523 /* withRequestContext */ withRequestContext ) == false )
1524 {
1525 me->release();
1526 me = 0;
1527 }
1528
1529 return me;
1530}
1531
1532// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1533
1534bool IODeblocker::initWithBlockSize(
1535 UInt64 blockSize,
1536 UInt64 withRequestStart,
1537 IOMemoryDescriptor * withRequestBuffer,
1538 IOStorageCompletion withRequestCompletion,
1539 void * withRequestContext )
1540{
1541 //
1542 // Initialize an IODeblocker.
1543 //
1544 // _excessCountStart = byte count from media boundary to start of request
1545 // _excessCountFinal = byte count from end of request to a media boundary
1546 //
1547
1548 UInt32 excessBufferSize = 0;
1549
1550 // Ask our superclass' opinion.
1551
1552 if ( super::init() == false ) return false;
1553
1554 // Initialize our minimal state.
1555
1556 _blockSize = blockSize;
1557 _chunksCount = 0;
1558 _direction = kIODirectionNone;
1559 _length = 0;
1560
1561 _requestBuffer = withRequestBuffer;
1562 _requestBuffer->retain();
1563 _requestCompletion = withRequestCompletion;
1564 _requestContext = withRequestContext;
1565 _requestCount = withRequestBuffer->getLength();
1566 _requestStart = withRequestStart;
1567
1568 _excessCountStart = (withRequestStart ) % blockSize;
1569 _excessCountFinal = (withRequestStart + _requestCount) % blockSize;
1570 if ( _excessCountFinal ) _excessCountFinal = blockSize - _excessCountFinal;
1571
1572 _requestIsOneBlock = (_excessCountStart + _requestCount <= blockSize);
1573
1574 // Determine the necessary size for our scratch buffer.
1575
1576 switch ( _requestBuffer->getDirection() )
1577 {
1578 case kIODirectionIn: // (read)
1579 {
1580 excessBufferSize = max(_excessCountStart, _excessCountFinal);
1581 } break;
1582
1583 case kIODirectionOut: // (write)
1584 {
1585 if ( _excessCountStart ) excessBufferSize += blockSize;
1586 if ( _excessCountFinal ) excessBufferSize += blockSize;
1587
1588 // If there is excess both ends of the original request, but both
1589 // ends reside within the same media block, then we could shorten
1590 // our buffer size to just one block.
1591
1592 if ( _excessCountStart && _excessCountFinal && _requestIsOneBlock )
1593 {
1594 excessBufferSize -= blockSize;
1595 }
1596 } break;
1597
1598 default:
1599 {
1600 assert(0);
1601 } break;
1602 }
1603
1604 // Allocate our scratch buffer.
1605
1606 if ( excessBufferSize )
1607 {
1608 _excessBuffer = IOBufferMemoryDescriptor::withCapacity(
1609 /* capacity */ excessBufferSize,
1610 /* withDirection */ kIODirectionNone );
1611 if ( _excessBuffer == 0 ) return false;
1612 }
1613
1614 return true;
1615}
1616
1617// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1618
1619void IODeblocker::free()
1620{
1621 //
1622 // Free all of this object's outstanding resources.
1623 //
1624
1625 if ( _requestBuffer ) _requestBuffer->release();
1626 if ( _excessBuffer ) _excessBuffer->release();
1627
1628 super::free();
1629}
1630
1631// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1632
1633IOReturn IODeblocker::prepare(IODirection forDirection)
1634{
1635 //
1636 // Prepare the memory for an I/O transfer.
1637 //
1638 // This involves paging in the memory and wiring it down for the duration
1639 // of the transfer. The complete() method finishes the processing of the
1640 // memory after the I/O transfer finishes.
1641 //
1642
1643 unsigned index;
1644 IOReturn status = kIOReturnInternalError;
1645 IOReturn statusUndo;
1646
1647 if ( forDirection == kIODirectionNone )
1648 {
1649 forDirection = _direction;
1650 }
1651
1652 for ( index = 0; index < _chunksCount; index++ )
1653 {
1654 status = _chunks[index].buffer->prepare(forDirection);
1655 if ( status != kIOReturnSuccess ) break;
1656 }
1657
1658 if ( status != kIOReturnSuccess )
1659 {
1660 for ( unsigned indexUndo = 0; indexUndo <= index; indexUndo++ )
1661 {
1662 statusUndo = _chunks[index].buffer->complete(forDirection);
1663 assert(statusUndo == kIOReturnSuccess);
1664 }
1665 }
1666
1667 return status;
1668}
1669
1670// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1671
1672IOReturn IODeblocker::complete(IODirection forDirection)
1673{
1674 //
1675 // Complete processing of the memory after an I/O transfer finishes.
1676 //
1677 // This method shouldn't be called unless a prepare() was previously issued;
1678 // the prepare() and complete() must occur in pairs, before and after an I/O
1679 // transfer.
1680 //
1681
1682 IOReturn status;
1683 IOReturn statusFinal = kIOReturnSuccess;
1684
1685 if ( forDirection == kIODirectionNone )
1686 {
1687 forDirection = _direction;
1688 }
1689
1690 for ( unsigned index = 0; index < _chunksCount; index++ )
1691 {
1692 status = _chunks[index].buffer->complete(forDirection);
1693 if ( status != kIOReturnSuccess ) statusFinal = status;
1694 assert(status == kIOReturnSuccess);
1695 }
1696
1697 return statusFinal;
1698}
1699
1700// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1701
1702IOPhysicalAddress IODeblocker::getPhysicalSegment( IOByteCount offset,
1703 IOByteCount * length )
1704{
1705 //
1706 // This method returns the physical address of the byte at the given offset
1707 // into the memory, and optionally the length of the physically contiguous
1708 // segment from that offset.
1709 //
1710
1711 assert(offset <= _length);
1712
1713 for ( unsigned index = 0; index < _chunksCount; index++ )
1714 {
1715 if ( offset < _chunks[index].length )
1716 {
1717 IOPhysicalAddress address;
1718 address = _chunks[index].buffer->getPhysicalSegment(
1719 /* offset */ offset + _chunks[index].offset,
1720 /* length */ length );
1721 if ( length ) *length = min(*length, _chunks[index].length);
1722 return address;
1723 }
1724 offset -= _chunks[index].length;
1725 }
1726
1727 if ( length ) *length = 0;
1728
1729 return 0;
1730}
1731
1732// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1733
1734void * IODeblocker::getVirtualSegment( IOByteCount /* offset */ ,
1735 IOByteCount * /* length */ )
1736{
1737 return 0;
1738}
1739
1740// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1741
1742IOByteCount IODeblocker::readBytes( IOByteCount offset,
1743 void * bytes,
1744 IOByteCount withLength )
1745{
1746 //
1747 // Copies data from the memory descriptor's buffer at the given offset, to
1748 // the specified buffer. Returns the number of bytes copied.
1749 //
1750
1751 IOByteCount bytesCopied = 0;
1752 unsigned index;
1753
1754 for ( index = 0; index < _chunksCount; index++ )
1755 {
1756 if ( offset < _chunks[index].length ) break;
1757 offset -= _chunks[index].length;
1758 }
1759
1760 for ( ; index < _chunksCount && withLength; index++)
1761 {
e7c99d92 1762 IOByteCount copy = min(_chunks[index].length - offset, withLength);
1c79356b
A
1763 IOByteCount copied = _chunks[index].buffer->readBytes(
1764 /* offset */ offset + _chunks[index].offset,
1765 /* bytes */ bytes,
1766 /* length */ copy );
1767
1768 bytesCopied += copied;
1769 if ( copied != copy ) break;
1770
1771 bytes = ((UInt8 *) bytes) + copied;
1772 withLength -= copied;
1773 offset = 0;
1774 }
1775
1776 return bytesCopied;
1777}
1778
1779// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1780
1781IOByteCount IODeblocker::writeBytes( IOByteCount offset,
1782 const void * bytes,
1783 IOByteCount withLength )
1784{
1785 //
1786 // Copies data to the memory descriptor's buffer at the given offset, from
1787 // the specified buffer. Returns the number of bytes copied.
1788 //
1789
1790 IOByteCount bytesCopied = 0;
1791 unsigned index;
1792
1793 for ( index = 0; index < _chunksCount; index++ )
1794 {
1795 if ( offset < _chunks[index].length ) break;
1796 offset -= _chunks[index].length;
1797 }
1798
1799 for ( ; index < _chunksCount && withLength; index++)
1800 {
e7c99d92 1801 IOByteCount copy = min(_chunks[index].length - offset, withLength);
1c79356b
A
1802 IOByteCount copied = _chunks[index].buffer->writeBytes(
1803 /* offset */ offset + _chunks[index].offset,
1804 /* bytes */ bytes,
1805 /* length */ copy );
1806
1807 bytesCopied += copied;
1808 if ( copied != copy ) break;
1809
1810 bytes = ((UInt8 *) bytes) + copied;
1811 withLength -= copied;
1812 offset = 0;
1813 }
1814
1815 return bytesCopied;
1816}
1817
1818// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1819
1820bool IODeblocker::getNextStage(UInt64 * byteStart)
1821{
1822 //
1823 // Obtain the next stage of the transfer. The transfer buffer will be the
1824 // deblocker object itself and the byte start will be returned in byteStart.
1825 //
1826 // This method must not be called if the current stage failed with an error
1827 // or a short byte count, but instead getRequestCompletion() must be called
1828 // to adjust the status and actual byte count (with respect to the original
1829 // request) and return the original request's completion routine. The same
1830 // call to getRequestCompletion() should also be done if the getNextStage()
1831 // method returns false.
1832 //
1833
1834 _chunksCount = 0;
1835 _direction = kIODirectionNone;
1836 _length = 0;
1837
1838 switch ( _requestBuffer->getDirection() )
1839 {
1840 case kIODirectionIn: // (read)
1841 {
1842 switch ( _stage )
1843 {
1844 case kStageInit:
1845 {
1846 _stage = kStageLast;
1847 _excessBuffer->setDirection(kIODirectionIn);
1848 _direction = kIODirectionIn;
1849 *byteStart = _requestStart - _excessCountStart;
1850
1851 if ( _excessCountStart )
1852 {
1853 _chunks[_chunksCount].buffer = _excessBuffer;
1854 _chunks[_chunksCount].offset = 0;
1855 _chunks[_chunksCount].length = _excessCountStart;
1856 _chunksCount++;
1857 }
1858
1859 _chunks[_chunksCount].buffer = _requestBuffer;
1860 _chunks[_chunksCount].offset = 0;
1861 _chunks[_chunksCount].length = _requestBuffer->getLength();
1862 _chunksCount++;
1863
1864 if ( _excessCountFinal )
1865 {
1866 _chunks[_chunksCount].buffer = _excessBuffer;
1867 _chunks[_chunksCount].offset = 0;
1868 _chunks[_chunksCount].length = _excessCountFinal;
1869 _chunksCount++;
1870 }
1871 } break;
1872
1873 case kStageLast:
1874 {
1875 _stage = kStageDone;
1876 } break;
1877
1878 default:
1879 {
1880 assert(0);
1881 } break;
1882 } // (switch)
1883 } break;
1884
1885 case kIODirectionOut: // (write)
1886 {
1887 switch ( _stage )
1888 {
1889 case kStageInit:
1890 {
1891 if ( _excessCountStart )
1892 {
1893 _stage = kStagePrepareExcessStart;
1894 _excessBuffer->setDirection(kIODirectionIn);
1895 _direction = kIODirectionIn;
1896 *byteStart = _requestStart - _excessCountStart;
1897
1898 _chunks[_chunksCount].buffer = _excessBuffer;
1899 _chunks[_chunksCount].offset = 0;
1900 _chunks[_chunksCount].length = _blockSize;
1901 _chunksCount++;
1902 break;
1903 }
1904 } // (fall thru)
1905
1906 case kStagePrepareExcessStart:
1907 {
1908 if ( _excessCountFinal )
1909 {
1910 // We do not issue this stage if the original transfer
1911 // resides within one media block, and we already read
1912 // that block into our buffer in the previous stage.
1913
1914 if ( !_excessCountStart || !_requestIsOneBlock )
1915 {
1916 _stage = kStagePrepareExcessFinal;
1917 _excessBuffer->setDirection(kIODirectionIn);
1918 _direction = kIODirectionIn;
1919 *byteStart = _requestStart + _requestCount +
1920 _excessCountFinal - _blockSize;
1921
1922 _chunks[_chunksCount].buffer = _excessBuffer;
1923 _chunks[_chunksCount].offset = (_requestIsOneBlock)
1924 ? 0
1925 : (_excessCountStart)
1926 ? _blockSize
1927 : 0;
1928 _chunks[_chunksCount].length = _blockSize;
1929 _chunksCount++;
1930 break;
1931 }
1932 }
1933 } // (fall thru)
1934
1935 case kStagePrepareExcessFinal:
1936 {
1937 _stage = kStageLast;
1938 _excessBuffer->setDirection(kIODirectionOut);
1939 _direction = kIODirectionOut;
1940 *byteStart = _requestStart - _excessCountStart;
1941
1942 if ( _excessCountStart )
1943 {
1944 _chunks[_chunksCount].buffer = _excessBuffer;
1945 _chunks[_chunksCount].offset = 0;
1946 _chunks[_chunksCount].length = _excessCountStart;
1947 _chunksCount++;
1948 }
1949
1950 _chunks[_chunksCount].buffer = _requestBuffer;
1951 _chunks[_chunksCount].offset = 0;
1952 _chunks[_chunksCount].length = _requestBuffer->getLength();
1953 _chunksCount++;
1954
1955 if ( _excessCountFinal )
1956 {
1957 _chunks[_chunksCount].buffer = _excessBuffer;
1958 _chunks[_chunksCount].offset = (_requestIsOneBlock)
1959 ? 0
1960 : (_excessCountStart)
1961 ? _blockSize
1962 : 0;
1963 _chunks[_chunksCount].offset += ( _blockSize -
1964 _excessCountFinal );
1965 _chunks[_chunksCount].length = _excessCountFinal;
1966 _chunksCount++;
1967 }
1968 } break;
1969
1970 case kStageLast:
1971 {
1972 _stage = kStageDone;
1973 } break;
1974
1975 default:
1976 {
1977 assert(0);
1978 } break;
1979 } // (switch)
1980 } break;
1981
1982 default:
1983 {
1984 assert(0);
1985 } break;
1986 } // (switch)
1987
1988 // Determine whether we have an abort or completion condition.
1989
1990 if ( _chunksCount == 0 ) return false;
1991
1992 // Compute the total length of the descriptor over all chunks.
1993
1994 for ( unsigned index = 0; index < _chunksCount; index++ )
1995 {
1996 _length += _chunks[index].length;
1997 }
1998
1999 return true;
2000}
2001
2002// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2003
2004void IODeblocker::getRequestCompletion( IOStorageCompletion * completion,
2005 IOReturn * status,
2006 UInt64 * actualByteCount )
2007{
2008 //
2009 // Obtain the completion information for the original request, taking
2010 // into account the status and actual byte count of the current stage.
2011 //
2012
2013 *completion = _requestCompletion;
2014
2015 switch ( _stage )
2016 {
2017 case kStageInit: // (inital stage)
2018 {
2019 *status = kIOReturnInternalError;
2020 *actualByteCount = 0;
2021 } break;
2022
2023 case kStagePrepareExcessStart: // (write preparation stage)
2024 case kStagePrepareExcessFinal:
2025 {
2026 *actualByteCount = 0;
2027 } break;
2028
2029 case kStageLast: // (last stage)
2030 case kStageDone:
2031 {
2032 if ( *actualByteCount > _excessCountStart )
2033 *actualByteCount -= _excessCountStart;
2034 else
2035 *actualByteCount = 0;
2036
2037 if ( *actualByteCount > _requestBuffer->getLength() )
2038 *actualByteCount = _requestBuffer->getLength();
2039 } break;
2040
2041 default:
2042 {
2043 assert(0);
2044 } break;
2045 }
2046}
2047
2048// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2049
2050IOMemoryDescriptor * IODeblocker::getRequestBuffer()
2051{
2052 //
2053 // Obtain the buffer for the original request.
2054 //
2055
2056 return _requestBuffer;
2057}
2058
2059// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2060
2061void * IODeblocker::getRequestContext()
2062{
2063 //
2064 // Obtain the context for the original request.
2065 //
2066
2067 return _requestContext;
2068}
2069
2070// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2071
2072void IOBlockStorageDriver::deblockRequest(
2073 UInt64 byteStart,
2074 IOMemoryDescriptor * buffer,
2075 IOStorageCompletion completion,
2076 IOBlockStorageDriver::Context * context )
2077{
2078 //
2079 // The deblockRequest method checks to see if the incoming request rests
2080 // on the media's block boundaries, and if not, deblocks it. Deblocking
2081 // involves rounding out the request to the nearest block boundaries and
2082 // transferring the excess bytes into a scratch buffer.
2083 //
2084 // This method is part of a sequence of methods invoked for each read/write
2085 // request. The first is prepareRequest, which allocates and prepares some
2086 // context for the transfer; the second is deblockRequest, which aligns the
2087 // transfer at the media block boundaries; and the third is executeRequest,
2088 // which implements the actual transfer from the block storage device.
2089 //
2090 // The current implementation of deblockRequest is asynchronous.
2091 //
2092
2093 IODeblocker * deblocker;
2094
2095 // If the request is aligned with the media's block boundaries, we
2096 // do short-circuit the deblocker and call executeRequest directly.
2097
2098 if ( (byteStart % context->block.size) == 0 &&
2099 (buffer->getLength() % context->block.size) == 0 )
2100 {
2101 executeRequest(byteStart, buffer, completion, context);
2102 return;
2103 }
2104
2105 // Build a deblocker object.
2106
2107 deblocker = IODeblocker::withBlockSize(
2108 /* blockSize */ context->block.size,
2109 /* withRequestStart */ byteStart,
2110 /* withRequestBuffer */ buffer,
2111 /* withRequestCompletion */ completion,
2112 /* withRequestContext */ context );
2113
2114 if ( deblocker == 0 )
2115 {
2116 complete(completion, kIOReturnNoMemory);
2117 return;
2118 }
2119
2120 // This implementation of the deblocker permits only one read-modify-write
2121 // at any given time. Note that other write requests can, and do, proceed
2122 // simultaneously so long as they do not require the deblocker -- refer to
2123 // the read() and the write() routines for the short-cut logic.
2124 //
2125 // Note that the original buffer during a read-modify-write operation must
2126 // be prepared on the client's thread, that is, right now, or else it will
2127 // happen on the controller's thread after the read stage(s) complete, and
2128 // this is bad (causes deadlock if that controller was the swap device).
2129
2130 if ( buffer->getDirection() == kIODirectionOut )
2131 {
2132 if ( buffer->prepare() != kIOReturnSuccess )
2133 {
2134 deblocker->release();
2135 complete(completion, kIOReturnNoMemory);
2136 return;
2137 }
2138
2139 IOLockLock(_deblockRequestWriteLock);
2140 }
2141
2142 // Execute the transfer (for the next stage).
2143
2144 deblockRequestCompletion(this, deblocker, kIOReturnSuccess, 0);
2145
2146 return;
2147}
2148
2149// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2150
2151void IOBlockStorageDriver::deblockRequestCompletion( void * target,
2152 void * parameter,
2153 IOReturn status,
2154 UInt64 actualByteCount )
2155{
2156 //
2157 // This is the completion routine for the aligned deblocker subrequests.
2158 // It verifies the success of the just-completed stage, transitions to
2159 // the next stage, then builds and issues a transfer for the next stage.
2160 //
2161
2162 UInt64 byteStart;
2163 IOStorageCompletion completion;
2164 Context * context;
2165 IODeblocker * deblocker = (IODeblocker *) parameter;
2166 IOBlockStorageDriver * driver = (IOBlockStorageDriver *) target;
2167
2168 // Determine whether an error occurred or whether there are no more stages.
2169
2170 if ( actualByteCount < deblocker->getLength() ||
2171 status != kIOReturnSuccess ||
2172 deblocker->getNextStage(&byteStart) == false )
2173 {
2174 // Unlock the write-lock in order to allow the next write to proceed.
2175
2176 if ( deblocker->getRequestBuffer()->getDirection() == kIODirectionOut )
2177 {
2178 IOLockUnlock(driver->_deblockRequestWriteLock);
2179
2180 deblocker->getRequestBuffer()->complete();
2181 }
2182
2183 // Obtain the completion information for the original request, taking
2184 // into account the status and actual byte count of the current stage.
2185
2186 deblocker->getRequestCompletion(&completion, &status, &actualByteCount);
2187
2188 // Complete the original request.
2189
2190 IOStorage::complete(completion, status, actualByteCount);
2191
2192 // Release our resources.
2193
2194 deblocker->release();
2195
2196 return;
2197 }
2198
2199 // Execute the transfer (for the next stage).
2200
2201 completion.target = driver;
2202 completion.action = deblockRequestCompletion;
2203 completion.parameter = deblocker;
2204
2205 context = (Context *) deblocker->getRequestContext();
2206
2207 driver->executeRequest(byteStart, deblocker, completion, context);
2208
2209 return;
2210}
2211
2212// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2213
2214OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 0);
2215
2216// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2217
2218OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 1);
2219
2220// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2221
2222OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 2);
2223
2224// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2225
2226OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 3);
2227
2228// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2229
2230OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 4);
2231
2232// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2233
2234OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 5);
2235
2236// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2237
2238OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 6);
2239
2240// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2241
2242OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 7);
2243
2244// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2245
2246OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 8);
2247
2248// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2249
2250OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 9);
2251
2252// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2253
2254OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 10);
2255
2256// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2257
2258OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 11);
2259
2260// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2261
2262OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 12);
2263
2264// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2265
2266OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 13);
2267
2268// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2269
2270OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 14);
2271
2272// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2273
2274OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 15);
2275
2276// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2277
2278OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 16);
2279
2280// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2281
2282OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 17);
2283
2284// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2285
2286OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 18);
2287
2288// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2289
2290OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 19);
2291
2292// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2293
2294OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 20);
2295
2296// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2297
2298OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 21);
2299
2300// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2301
2302OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 22);
2303
2304// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2305
2306OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 23);
2307
2308// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2309
2310OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 24);
2311
2312// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2313
2314OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 25);
2315
2316// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2317
2318OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 26);
2319
2320// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2321
2322OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 27);
2323
2324// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2325
2326OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 28);
2327
2328// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2329
2330OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 29);
2331
2332// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2333
2334OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 30);
2335
2336// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2337
2338OSMetaClassDefineReservedUnused(IOBlockStorageDriver, 31);