1/*
2 * Copyright (c) 2001-2007 Apple 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 "AppleRAID.h"
24#include <IOKit/IOPolledInterface.h>
25#include "sys/param.h"  // MAXBSIZE
26
27#define super AppleRAIDMember
28OSDefineMetaClassAndAbstractStructors(AppleRAIDSet, AppleRAIDMember);
29
30void AppleRAIDSet::free(void)
31{
32    if (arOpenReaders)		arOpenReaders->release();
33
34    if (arMembers)		IODelete(arMembers, AppleRAIDMember *, arLastAllocCount);
35    if (arSpareMembers)		arSpareMembers->release();
36
37//    UInt32 count = 0;    // XXXXXXXXXXXXXXX  LVM
38    if (arStorageRequestPool) {
39        while (1) {
40	    AppleRAIDStorageRequest * storageRequest;
41	    storageRequest = (AppleRAIDStorageRequest *)arStorageRequestPool->getCommand(false);
42            if (storageRequest == 0) break;
43//	    count++;  // XXXXXXXXXXXXXXX
44            storageRequest->release();
45        }
46        arStorageRequestPool->release();
47	arStorageRequestPool = 0;
48    }
49//    IOLog1("ARSFree: freed %lu SR's, pending %lu  XXXXXXXXXXXXXXX\n", count, arStorageRequestsPending);
50
51    if (arSetCommandGate != 0) {
52        arSetWorkLoop->removeEventSource(arSetCommandGate);
53        arSetCommandGate->release();
54        arSetCommandGate = 0;
55    }
56    if (arSetEventSource != 0) {
57        arSetWorkLoop->removeEventSource(arSetEventSource);
58        arSetEventSource->release();
59        arSetEventSource = 0;
60    }
61    if (arSetWorkLoop != 0) arSetWorkLoop->release();
62    arSetWorkLoop = 0;
63
64    if (arRecoveryThreadCall) thread_call_free(arRecoveryThreadCall);
65    arRecoveryThreadCall = 0;
66
67    super::free();
68}
69
70// once only init
71bool AppleRAIDSet::init()
72{
73    if (super::init() == false) return false;
74
75    arSetState = kAppleRAIDSetStateInitializing;
76    setProperty(kAppleRAIDStatusKey, kAppleRAIDStatusOffline);
77    // this will disable the writing of hibernation data on RAID volumes
78    setProperty(kIOPolledInterfaceSupportKey, kOSBooleanFalse);
79
80    arMemberCount	= 0;
81    arLastAllocCount	= 0;
82    arSequenceNumber	= 0;
83    arMedia		= NULL;
84    arOpenLevel		= kIOStorageAccessNone;
85    arOpenReaders	= OSSet::withCapacity(10);
86    arOpenReaderWriters	= OSSet::withCapacity(10);
87
88    arSetCompleteTimeout = kARSetCompleteTimeoutNone;
89    arSetBlockCount	= 0;
90    arSetMediaSize	= 0;
91    arMaxReadRequestFactor = 0;
92    arPrimaryMetaDataUsed = 0;
93    arPrimaryMetaDataMax = 0;
94
95    arMembers		= 0;
96    arSpareMembers	= OSSet::withCapacity(10);
97
98    arSetIsSyncingCount	= 0;
99
100    if (!arSpareMembers || !arOpenReaders) return false;
101
102    // Get the WorkLoop.
103    if (getWorkLoop() != 0) {
104	arSetCommandGate = IOCommandGate::commandGate(this);
105	if (arSetCommandGate != 0) {
106	    getWorkLoop()->addEventSource(arSetCommandGate);
107	}
108
109	AppleRAIDEventSource::Action completeRequestMethod = OSMemberFunctionCast(AppleRAIDEventSource::Action, this, &AppleRAIDSet::completeRAIDRequest);
110	arSetEventSource = AppleRAIDEventSource::withAppleRAIDSet(this, completeRequestMethod);
111	if (arSetEventSource != 0) {
112	    getWorkLoop()->addEventSource(arSetEventSource);
113	}
114    }
115
116    thread_call_func_t recoverMethod = OSMemberFunctionCast(thread_call_func_t, this, &AppleRAIDSet::recover);
117    arRecoveryThreadCall = thread_call_allocate(recoverMethod, (thread_call_param_t)this);
118    if (arRecoveryThreadCall == 0) return false;
119
120    arAllocateRequestMethod = (IOCommandGate::Action)0xdeadbeef;
121
122    return true;
123}
124
125bool AppleRAIDSet::initWithHeader(OSDictionary * header, bool firstTime)
126{
127    if (!header) return false;
128
129    OSString * string;
130    string = OSDynamicCast(OSString, header->getObject(kAppleRAIDSetNameKey));
131    if (string) setProperty(kAppleRAIDSetNameKey, string);
132
133    string = OSDynamicCast(OSString, header->getObject(kAppleRAIDSetUUIDKey));
134    if (string) {
135	setProperty(kAppleRAIDMemberUUIDKey, string);	// the real uuid for this set
136	setProperty(kAppleRAIDSetUUIDKey, string);	// is overridden in addMember if stacked
137    } else {
138	if (firstTime) return false;
139    }
140    // this is only in v2 headers, the spare list is built on the fly
141    OSArray * members = OSDynamicCast(OSArray, header->getObject(kAppleRAIDMembersKey));
142    if (members) setProperty(kAppleRAIDMembersKey, members);
143
144    OSNumber * number;
145    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDHeaderVersionKey));
146    if (number) {
147	arHeaderVersion = number->unsigned32BitValue();
148    } else {
149	if (firstTime) return false;
150    }
151
152    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDSequenceNumberKey));
153    if (number) {
154	arSequenceNumber = number->unsigned32BitValue();
155    } else {
156	if (firstTime) return false;
157    }
158
159    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDChunkSizeKey));
160    if (number) {
161	arSetBlockSize = number->unsigned64BitValue();
162    } else {
163	if (firstTime) return false;
164    }
165
166    // not really in v2 header
167    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDMemberCountKey));
168    if (number) {
169	arMemberCount = number->unsigned32BitValue();
170    } else {
171	if (firstTime) return false;
172    }
173
174    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDBaseOffsetKey));
175    if (number) {
176	arBaseOffset = number->unsigned64BitValue();
177    } else {
178	if (firstTime) return false;
179    }
180
181    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDNativeBlockSizeKey));
182    if (number) {
183	arNativeBlockSize = number->unsigned64BitValue();
184    } else {
185	if (firstTime) return false;
186    }
187
188    number = OSDynamicCast(OSNumber, header->getObject(kAppleRAIDPrimaryMetaDataUsedKey));
189    if (number) {
190	arPrimaryMetaDataUsed = number->unsigned64BitValue();
191    }
192
193    // don't care if these fail
194    setProperty(kAppleRAIDSetContentHintKey, header->getObject(kAppleRAIDSetContentHintKey));
195    setProperty(kAppleRAIDCanAddMembersKey, header->getObject(kAppleRAIDCanAddMembersKey));
196    setProperty(kAppleRAIDCanAddSparesKey, header->getObject(kAppleRAIDCanAddSparesKey));
197    setProperty(kAppleRAIDRemovalAllowedKey, header->getObject(kAppleRAIDRemovalAllowedKey));
198    setProperty(kAppleRAIDSizesCanVaryKey, header->getObject(kAppleRAIDSizesCanVaryKey));
199
200    return true;
201}
202
203//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
204//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
205//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
206
207bool AppleRAIDSet::addSpare(AppleRAIDMember * member)
208{
209    IOLog1("AppleRAIDSet::addSpare(%p) entered, spare count was %u.\n", member, (uint32_t)getSpareCount());
210
211    assert(gAppleRAIDGlobals.islocked());
212
213    if (!this->attach(member)) {
214	IOLog1("AppleRAIDSet::addSpare(%p) this->attach(%p) failed\n", this, member);
215	member->changeMemberState(kAppleRAIDMemberStateBroken);
216	return false;
217    }
218
219    arSpareMembers->setObject(member);
220
221    return true;
222}
223
224bool AppleRAIDSet::addMember(AppleRAIDMember * member)
225{
226    IOLog1("AppleRAIDSet::addMember(%p) called\n", member);
227
228    assert(gAppleRAIDGlobals.islocked());
229
230    if (member->isBroken()) return false;
231
232    // deal with spare members separately
233    if (member->isSpare()) return false;
234
235    // new members should be closed ...
236    if (member->getMemberState() != kAppleRAIDMemberStateClosed) {
237	IOLog1("AppleRAIDSet::addMember(%p) member is not closed.\n", member);
238	member->changeMemberState(kAppleRAIDMemberStateBroken);
239	return false;
240    }
241
242    // check the current state of the raid set, can we accept another member?
243    if (arActiveCount >= arMemberCount) {
244	IOLog("AppleRAIDSet::addMember() too many members, active = %u, count = %u, member = %s\n",
245	      (uint32_t)arActiveCount, (uint32_t)arMemberCount, member->getUUIDString());
246	member->changeMemberState(kAppleRAIDMemberStateSpare);
247        return false;
248    }
249
250    // double check, can the set take more members?
251    // degraded sets should reject new members unless paused
252    if (getSetState() >= kAppleRAIDSetStateOnline && !arSetIsPaused) {
253	IOLog("AppleRAIDSet::addMember() set already started, ignoring new member %s\n", member->getUUIDString());
254	member->changeMemberState(kAppleRAIDMemberStateSpare);
255        return false;
256    }
257
258    OSNumber * number;
259    number = OSDynamicCast(OSNumber, member->getHeaderProperty(kAppleRAIDHeaderVersionKey));
260    if (!number) return false;
261    UInt32 memberHeaderVersion = number->unsigned32BitValue();
262
263    // double check that this member is a part of the set, only for v2 headers
264    OSArray * memberUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey));
265    if (memberUUIDs) {
266	const OSString * uuid = member->getUUID();
267	if (!uuid) return false;
268	bool foundit = false;
269	for (UInt32 i = 0; i < arMemberCount; i++) {
270
271	    if (uuid->isEqualTo(memberUUIDs->getObject(i))) {
272		foundit = arMembers[i] == 0;
273	    }
274	    if (foundit) break;
275	}
276	if (!foundit) return false;
277    }
278
279    // no mix and match header versions
280    if (memberHeaderVersion != arHeaderVersion) {
281	IOLog("AppleRAIDSet::addMember() header version mismatch for member %s\n",
282	      member->getUUIDString());
283	// just punt, this is fatal and requires user interaction
284	// it is possible to get here during a failed set upgrade
285	changeSetState(kAppleRAIDSetStateFailed);
286	member->changeMemberState(kAppleRAIDMemberStateBroken);
287	return false;
288    }
289
290    number = OSDynamicCast(OSNumber, member->getHeaderProperty(kAppleRAIDSequenceNumberKey));
291    if (!number) return false;
292    UInt32 memberSequenceNumber = number->unsigned32BitValue();
293    UInt32 memberIndex = member->getMemberIndex();
294
295    // Don't use members that have sequence numbers older than the raid set.
296    if (memberSequenceNumber < arSequenceNumber) {
297	IOLog("AppleRAIDSet::addMember() detected expired sequenceNumber (%u) for member %s\n",
298	      (uint32_t)memberSequenceNumber, member->getUUIDString());
299	member->changeMemberState(kAppleRAIDMemberStateSpare);
300        return false;
301    }
302
303    // If this new member is newer than the others then remove the old ones.
304    if (memberSequenceNumber > arSequenceNumber) {
305        for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
306	    if (arMembers[cnt] != 0) {
307
308		OSNumber * number = OSDynamicCast(OSNumber, arMembers[cnt]->getHeaderProperty(kAppleRAIDSequenceNumberKey));
309		if (number) {
310		    IOLog("AppleRAIDSet::addMember() detected expired sequenceNumber (%u) for member %s\n",
311			  number->unsigned32BitValue(), arMembers[cnt]->getUUIDString());
312		}
313		AppleRAIDMember * expiredMember = arMembers[cnt];
314		removeMember(arMembers[cnt], 0);
315		expiredMember->changeMemberState(kAppleRAIDMemberStateSpare);
316		addSpare(expiredMember);
317            }
318	}
319
320	// we may have removed everything
321	if (arActiveCount == 0) {
322	    arSetState = kAppleRAIDSetStateInitializing;
323	    setProperty(kAppleRAIDStatusKey, kAppleRAIDStatusOffline);
324	    initWithHeader(member->getHeader(), true);
325	}
326
327	// Update the raid set's sequence number.
328	arSequenceNumber = memberSequenceNumber;
329
330	// reset the block count
331	arSetBlockCount = 0;
332
333	// calculate the max size for the primary data, the primary data is always the
334	// same size but may be at different offsets depending on the type of raid set
335	assert(arPrimaryMetaDataMax ? (arPrimaryMetaDataMax == member->getPrimaryMaxSize()) : 1);
336	arPrimaryMetaDataMax = member->getPrimaryMaxSize();
337    }
338
339    // Make sure this is the only member in this slot.
340    if (arMembers[memberIndex] != 0) {
341	IOLog("AppleRAIDSet::addMember() detected the same member index (%u) twice?\n", (uint32_t)memberIndex);
342	// take the entire set set offline, this is fatal
343	changeSetState(kAppleRAIDSetStateFailed);
344	member->changeMemberState(kAppleRAIDMemberStateBroken);
345        return false;
346    }
347
348    //
349    // at this point we should have a valid member
350    //
351
352    // Save the AppleRAIDMember in the raid set.
353    arMembers[memberIndex] = member;
354
355    if (!this->attach(member)) {
356	IOLog1("AppleRAIDSet::addMember(%p) this->attach(%p) failed\n", this, member);
357	member->changeMemberState(kAppleRAIDMemberStateBroken);
358	return false;
359    }
360
361    // Count this member as started.
362    arActiveCount++;
363
364    IOLog1("AppleRAIDSet::addMember(%p) was successful.\n", member);
365
366    return true;
367}
368
369// this also removes spares
370
371bool AppleRAIDSet::removeMember(AppleRAIDMember * member, IOOptionBits options)
372{
373    IOLog1("AppleRAIDSet::removeMember(%p) called\n", member);
374
375    assert(gAppleRAIDGlobals.islocked());
376
377    bool shouldBeClosed = member->changeMemberState(kAppleRAIDMemberStateClosing);
378
379    // spares are not open
380    if (shouldBeClosed) member->close(this, options);
381
382    member->changeMemberState(kAppleRAIDMemberStateClosed);
383
384    UInt32 memberIndex = member->getMemberIndex();
385
386    if (arMembers[memberIndex] == member) {
387	arMembers[memberIndex] = 0;
388	arActiveCount--;
389    }
390
391    arSpareMembers->removeObject(member);
392
393    this->detach(member);
394
395    return true;
396}
397
398
399bool AppleRAIDSet::upgradeMember(AppleRAIDMember *member)
400{
401    IOLog1("AppleRAIDSet::upgradeMember(%p) entered.\n", this);
402
403    // this is running in the workloop (when called from rebuildComplete)
404
405    // the set is paused
406    assert(arSetIsPaused);
407
408    // update member & spare uuid lists in raid headers, only for v2 headers
409    OSArray * memberUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey));
410    OSArray * spareUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDSparesKey));
411    for (UInt32 i = 0; i < arMemberCount; i++) {
412	if (arMembers[i]) {
413	    arMembers[i]->setHeaderProperty(kAppleRAIDMembersKey, memberUUIDs);
414	    arMembers[i]->setHeaderProperty(kAppleRAIDSparesKey, spareUUIDs);
415	}
416    }
417
418    // fix up the member
419    member->setHeaderProperty(kAppleRAIDMemberTypeKey, kAppleRAIDMembersKey);
420    member->setHeaderProperty(kAppleRAIDSequenceNumberKey, arSequenceNumber, 32);
421    member->setHeaderProperty(kAppleRAIDMembersKey, memberUUIDs);
422    member->setHeaderProperty(kAppleRAIDSparesKey, spareUUIDs);
423
424    // add member into the raid set (special cased for paused sets)
425    if (!addMember(member)) return false;
426
427    // force it open (if needed)
428    if (arOpenReaderWriters->getCount() || arOpenReaders->getCount()) {
429	IOStorageAccess level = arOpenReaderWriters->getCount() ? kIOStorageAccessReaderWriter : kIOStorageAccessReader;
430	IOLog1("AppleRAIDSet::upgradeMember(%p) opening for read%s.\n", this, arOpenReaderWriters->getCount() ? "/write" : " only");
431	if (!member->open(this, 0, level)) {
432	    IOLog("AppleRAIDSet::upgradeMember(%p) open failed.\n", this);
433	    return false;
434	}
435    }
436
437    return true;
438}
439
440//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
441//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
442//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
443
444
445bool AppleRAIDSet::resizeSet(UInt32 newMemberCount)
446{
447    AppleRAIDMember	**oldMembers = 0;
448
449    IOLog1("AppleRAIDSet::resizeSet(%p) entered. alloc = %d old = %d new = %d\n",
450	   this, (int)arLastAllocCount, (int)arMemberCount, (int)newMemberCount);
451
452    UInt32 oldMemberCount = arMemberCount;
453
454    // if downsizing, just hold on to the extra space
455    if (arLastAllocCount && (arLastAllocCount >= newMemberCount)) {
456	arMemberCount = newMemberCount;
457	// zero out the deleted stuff;
458	for (UInt32 i = newMemberCount; i < arLastAllocCount; i++) {
459	    arMembers[i] = NULL;
460	}
461	return true;
462    }
463
464    // back up the old member info if we need to increase the set size
465    if (arLastAllocCount) {
466	oldMembers = arMembers;
467    }
468
469    arMembers = IONew(AppleRAIDMember *, newMemberCount);
470    if (!arMembers) return false;
471
472    // Clear the new arrays.
473    bzero(arMembers, sizeof(AppleRAIDMember *) * newMemberCount);
474
475    // copy the old into the new, if needed
476    if (arLastAllocCount) {
477	bcopy(oldMembers, arMembers, sizeof(AppleRAIDMember *) * oldMemberCount);
478	IODelete(oldMembers, AppleRAIDMember *, arLastAllocCount);
479    }
480
481    arLastAllocCount = newMemberCount;
482    arMemberCount = newMemberCount;
483
484    IOLog1("AppleRAIDSet::resizeSet(%p) successful\n", this);
485
486    return true;
487}
488
489
490UInt32 AppleRAIDSet::nextSetState(void)
491{
492    if (isSetComplete()) {
493	return kAppleRAIDSetStateOnline;
494    }
495
496    if (arActiveCount == 0 && getSpareCount() == 0) {
497	IOLog1("AppleRAIDSet::nextSetState: %p is empty, setting state to terminating.\n", this);
498	return kAppleRAIDSetStateTerminating;
499    }
500
501    if (getSetState() != kAppleRAIDSetStateInitializing) {
502	IOLog1("AppleRAIDSet::nextSetState: set \"%s\" failed to come online.\n", getSetNameString());
503    }
504
505    return kAppleRAIDSetStateInitializing;
506}
507
508
509UInt64 AppleRAIDSet::getSmallestMaxByteCount(void)
510{
511    UInt64 minimum = MAXBSIZE;  // currently 1MB
512    UInt64 newMinimum;
513
514    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
515	AppleRAIDMember * target = arMembers[cnt];
516	if (target) {
517
518	    newMinimum = 0;
519
520	    OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(kIOMaximumByteCountReadKey, gIOServicePlane));
521            if (number) {
522		newMinimum = number->unsigned64BitValue();
523		if (newMinimum) minimum = min(minimum, newMinimum);
524	    }
525
526	    if (!newMinimum) {
527		OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(kIOMaximumBlockCountReadKey, gIOServicePlane));
528		if (number) {
529		    newMinimum = number->unsigned64BitValue() * 512;
530		    if (newMinimum) minimum = min(minimum, newMinimum);
531		}
532	    }
533	}
534    }
535
536    return minimum;
537}
538
539void AppleRAIDSet::setSmallest64BitMemberPropertyFor(const char * key, UInt32 multiplier)
540{
541    UInt64 minimum = UINT64_MAX;
542
543    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
544	AppleRAIDMember * target = arMembers[cnt];
545	if (target) {
546	    OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(key, gIOServicePlane));
547            if (number) {
548		UInt64 newMinimum = number->unsigned64BitValue();
549		if (newMinimum) minimum = min(minimum, newMinimum);
550	    }
551	}
552    }
553
554    if (minimum < UINT64_MAX) {
555	setProperty(key, minimum * multiplier, 64);
556    } else {
557	removeProperty(key);
558    }
559}
560
561
562void AppleRAIDSet::setLargest64BitMemberPropertyFor(const char * key, UInt32 multiplier)
563{
564    UInt64 maximum = 0;
565
566    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
567	AppleRAIDMember * target = arMembers[cnt];
568	if (target) {
569	    OSNumber * number = OSDynamicCast(OSNumber, target->getProperty(key, gIOServicePlane));
570            if (number) {
571		UInt64 newMaximum = number->unsigned64BitValue();
572		if (newMaximum) maximum = max(maximum, newMaximum);
573	    }
574	}
575    }
576
577    if (maximum > 0) {
578	setProperty(key, maximum * multiplier, 64);
579    } else {
580	removeProperty(key);
581    }
582}
583
584
585bool AppleRAIDSet::startSet(void)
586{
587    IOLog1("AppleRAIDSet::startSet %p called with %u of %u members (%u spares).\n",
588	   this, (uint32_t)arActiveCount, (uint32_t)arMemberCount, (uint32_t)getSpareCount());
589
590    // if terminating, stay that way
591    if (getSetState() <= kAppleRAIDSetStateTerminating) {
592	IOLog1("AppleRAIDSet::startSet: the set \"%s\" is terminating or broken (%d).\n", getSetNameString(), (int)getSetState());
593	return false;
594    }
595
596    // update set status
597    UInt32 nextState = nextSetState();
598    changeSetState(nextState);
599    if (nextState < kAppleRAIDSetStateOnline) {
600	IOLog1("AppleRAIDSet::startSet %p was unsuccessful.\n", this);
601	return false;
602    }
603
604    // clean out the old storage requests and their memory descriptors
605
606    if (arStorageRequestPool && arSetIsPaused) {
607	assert(arStorageRequestsPending == 0);
608        while (1) {
609	    AppleRAIDStorageRequest * storageRequest;
610	    storageRequest = (AppleRAIDStorageRequest *)arStorageRequestPool->getCommand(false);
611            if (storageRequest == 0) break;
612            storageRequest->release();
613        }
614        arStorageRequestPool->release();
615	arStorageRequestPool = 0;
616    }
617
618    // Create and populate the storage request pool.
619
620    if (!arStorageRequestPool) {
621
622	// XXX fix this? looks like the code always calls getCommand with false
623	// XXX while already inside the workloop, just use fCommandChain directly ?
624
625	arStorageRequestPool = IOCommandPool::withWorkLoop(getWorkLoop());
626	if (arStorageRequestPool == 0) return kIOReturnNoMemory;
627	for (UInt32 cnt = 0; cnt < kAppleRAIDStorageRequestCount; cnt++) {
628
629	    AppleRAIDStorageRequest * storageRequest;
630	    if (OSDynamicCast(AppleLVMGroup, this)) {
631		storageRequest = AppleLVMStorageRequest::withAppleRAIDSet(this);
632	    } else {
633		storageRequest = AppleRAIDStorageRequest::withAppleRAIDSet(this);
634	    }
635	    if (storageRequest == 0) break;
636	    arStorageRequestPool->returnCommand(storageRequest);
637	}
638    }
639
640    // (re)calculate ejectable and writeable, ...
641
642    arIsWritable = true;
643    arIsEjectable = true;
644    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
645
646	// if any members are not ejectable/writable turn off the entire set
647
648	if (arMembers[cnt] && (arMembers[cnt]->getMemberState() >= kAppleRAIDMemberStateClosed)) {
649	    if (!arMembers[cnt]->isEjectable()) arIsEjectable = false;
650	    if (!arMembers[cnt]->isWritable())  arIsWritable  = false;
651	}
652    }
653
654    setSmallest64BitMemberPropertyFor(kIOMaximumBlockCountReadKey, 1);
655    setSmallest64BitMemberPropertyFor(kIOMaximumBlockCountWriteKey, 1);
656    setSmallest64BitMemberPropertyFor(kIOMaximumByteCountReadKey, 1);
657    setSmallest64BitMemberPropertyFor(kIOMaximumByteCountWriteKey, 1);
658
659    setSmallest64BitMemberPropertyFor(kIOMaximumSegmentCountReadKey, 1);
660    setSmallest64BitMemberPropertyFor(kIOMaximumSegmentCountWriteKey, 1);
661    setSmallest64BitMemberPropertyFor(kIOMaximumSegmentByteCountReadKey, 1);		// don't scale this
662    setSmallest64BitMemberPropertyFor(kIOMaximumSegmentByteCountWriteKey, 1);		// don't scale this
663
664    setLargest64BitMemberPropertyFor(kIOMinimumSegmentAlignmentByteCountKey, 1);	// don't scale this
665    setSmallest64BitMemberPropertyFor(kIOMaximumSegmentAddressableBitCountKey, 1);	// don't scale this
666
667    IOLog1("AppleRAIDSet::startSet %p was successful.\n", this);
668    return true;
669}
670
671
672bool AppleRAIDSet::publishSet(void)
673{
674    IOLog1("AppleRAIDSet::publishSet called %p\n", this);
675
676    // are we (still) connected to the io registry?
677    if (arActiveCount == 0 && getSpareCount() == 0) {
678	IOLog1("AppleRAIDSet::publishSet: the set %p is empty, aborting.\n", this);
679	return false;
680    }
681
682    if (getSetState() < kAppleRAIDSetStateOnline || isRAIDMember()) {
683	IOLog1("AppleRAIDSet::publishSet: skipping offline or stacked raid set.\n");
684	unpublishSet();
685	return true;
686    }
687
688    // logical volume groups do not export a media object
689    const char * contentHint = 0;
690    OSString * theHint = OSDynamicCast(OSString, getProperty(kAppleRAIDSetContentHintKey));
691    if (theHint) {
692	if (theHint->isEqualTo(kAppleRAIDNoMediaExport)) {
693	    IOLog1("AppleRAIDSet::publishSet: shortcircuiting publish for no media set.\n");
694	    return true;
695	}
696	contentHint = theHint->getCStringNoCopy();
697    }
698
699    // Create the member object for the raid set.
700    bool firstTime = false;
701    if (arMedia) {
702	arMedia->retain();
703    } else {
704	arMedia = new IOMedia;
705	firstTime = true;
706    }
707
708    if (arMedia) {
709
710	IOMediaAttributeMask attributes = arIsEjectable ? (kIOMediaAttributeEjectableMask | kIOMediaAttributeRemovableMask) : 0;
711        if (arMedia->init(/* base               */ 0,
712			  /* size               */ arSetMediaSize,
713			  /* preferredBlockSize */ arNativeBlockSize,
714			  /* attributes         */ attributes,
715			  /* isWhole            */ true,
716			  /* isWritable         */ arIsWritable,
717			  /* contentHint        */ contentHint)) {
718
719	    arMedia->setName(getSetNameString());
720
721	    // Set a location value (partition number) for this partition.
722	    char location[12];
723	    snprintf(location, sizeof(location), "%d", 0);
724	    arMedia->setLocation(location);
725
726	    OSArray * bootArray = OSArray::withCapacity(arMemberCount);
727	    if (bootArray) {
728		// if any of the devices are not in the device tree
729		// just return an empty array
730		(void)addBootDeviceInfo(bootArray);
731		arMedia->setProperty(kIOBootDeviceKey, bootArray);
732		bootArray->release();
733	    }
734
735	    arMedia->setProperty(kIOMediaUUIDKey, (OSObject *)getUUID());
736	    arMedia->setProperty(kAppleRAIDIsRAIDKey, kOSBooleanTrue);
737	    if (getSetState() < kAppleRAIDSetStateOnline || isRAIDMember()) {
738		arMedia->setProperty("autodiskmount", kOSBooleanFalse);
739	    } else {
740		arMedia->removeProperty("autodiskmount");
741	    }
742
743	    if (firstTime) {
744		arMedia->attach(this);
745		arMedia->registerService();
746	    }  else {
747                arMedia->messageClients(kIOMessageServicePropertyChange);
748	    }
749	}
750    } else {
751	IOLog("AppleRAIDSet::publishSet(void): failed for set \"%s\" (%s)\n", getSetNameString(), getUUIDString());
752    }
753
754    if (arMedia) arMedia->release();
755
756    IOLog1("AppleRAIDSet::publishSet: was %ssuccessful.\n", arMedia ? "" : "un");
757    return arMedia != NULL;
758}
759
760
761bool AppleRAIDSet::unpublishSet(void)
762{
763    bool success = true;
764
765    IOLog1("AppleRAIDSet::unpublishSet(%p) entered, arMedia = %p\n", this, arMedia);
766
767    if (arMedia) {
768	success = arMedia->terminate(kIOServiceRequired | kIOServiceSynchronous);
769	arMedia = 0;
770    }
771
772    return success;
773}
774
775bool AppleRAIDSet::destroySet(void)
776{
777    IOLog1("AppleRAIDSet::destroySet(%p) entered.\n", this);
778
779    assert(gAppleRAIDGlobals.islocked());
780
781    if (isRAIDMember()) {
782	IOLog("AppleRAIDSet::destroySet() failed, an attempt was made to destroy subordinate set\n");
783	return false;
784    }
785
786    // zero headers on members
787    for (UInt32 i = 0; i < arMemberCount; i++) {
788	if (arMembers[i]) {
789	    (void)arMembers[i]->zeroRAIDHeader();
790	    if (arMembers[i]->getMemberState() == kAppleRAIDMemberStateRebuilding) {
791		arMembers[i]->changeMemberState(kAppleRAIDMemberStateSpare, true);
792		while (arMembers[i]->getMemberState() == kAppleRAIDMemberStateSpare) {
793		    IOSleep(50);
794		}
795		// drag member back to spare list, keeping it attached, ** active count doesn't change **
796		AppleRAIDMember * member = arMembers[i];
797		arMembers[i] = 0;
798		arSpareMembers->setObject(member);
799	    }
800	}
801    }
802
803    // zero headers on spares
804    OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers);
805    if (!iter) return false;
806    while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) {
807	(void)spare->zeroRAIDHeader();
808    }
809    iter->release();
810
811    // this keeps us from bumping sequence numbers on the way down
812    changeSetState(kAppleRAIDSetStateTerminating);
813
814    // remove the members from the set
815    for (UInt32 i = 0; i < arMemberCount; i++) {
816	if (arMembers[i]) {
817	    if (arMembers[i]->isRAIDSet()) {
818		arController->oldMember(arMembers[i]);
819	    } else {
820		arMembers[i]->stop(NULL);
821	    }
822	}
823    }
824
825    // remove the spares from the set
826    // make a copy since this changes the spare list
827    OSSet * copy = OSSet::withSet(arSpareMembers, arSpareMembers->getCount());
828    if (!copy) return false;
829    while (AppleRAIDMember * spare = (AppleRAIDMember *)copy->getAnyObject()) {
830	copy->removeObject(spare);
831	if (spare->isRAIDSet()) {
832	    arController->oldMember(spare);
833	} else {
834	    spare->stop(NULL);
835	}
836    }
837    copy->release();
838
839    IOLog1("AppleRAIDSet::destroySet(%p) was successful.\n", this);
840
841    return true;
842}
843
844
845bool AppleRAIDSet::reconfigureSet(OSDictionary * updateInfo)
846{
847    bool updateHeader = false;
848    UInt32 newMemberCount = arMemberCount;
849
850    IOLog1("AppleRAIDSet::reconfigureSet(%p) entered.\n", this);
851
852    OSString * deleted = OSString::withCString(kAppleRAIDDeletedUUID);
853    if (!deleted) return false;
854
855    OSArray * oldMemberList = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey));
856    OSArray * newMemberList = OSDynamicCast(OSArray, updateInfo->getObject(kAppleRAIDMembersKey));
857
858    if (oldMemberList && newMemberList) {
859
860	IOLog1("AppleRAIDSet::reconfigureSet(%p) updating member list.\n", this);
861
862	assert(arMemberCount == oldMemberList->getCount());
863
864	// look for kAppleRAIDDeletedUUID
865	for (UInt32 i = 0; i < newMemberCount; i++) {
866
867	    OSString * uuid = OSDynamicCast(OSString, newMemberList->getObject(i));
868
869	    if (uuid && (uuid->isEqualTo(deleted))) {
870
871		if (arMembers[i]) {
872		    arMembers[i]->zeroRAIDHeader();
873		    if (arMembers[i]->getMemberState() == kAppleRAIDMemberStateRebuilding) {
874			// hack, this will cause the rebuild to abort
875			arMembers[i]->changeMemberState(kAppleRAIDMemberStateSpare, true);
876			while (arMembers[i]->getMemberState() == kAppleRAIDMemberStateSpare) {
877			    arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::unpauseSet));
878			    IOSleep(50);
879			    arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::pauseSet), (void *)false);
880			}
881			// drag member back to spare list, keeping it attached, ** active count doesn't change **
882			AppleRAIDMember * member = arMembers[i];
883			arMembers[i] = 0;
884			arSpareMembers->setObject(member);
885			if (member->isRAIDSet()) {
886			    arController->oldMember(member);
887			} else {
888			    member->stop(NULL);
889			}
890		    } else {
891			if (arMembers[i]->isRAIDSet()) {
892			    arController->oldMember(arMembers[i]);
893			} else {
894			    arMembers[i]->stop(NULL);
895			}
896		    }
897		} else {
898		    // if the member is broken it might be in the spare list
899		    OSString * olduuid = OSDynamicCast(OSString, oldMemberList->getObject(i));
900		    OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers);
901		    if (!iter) return false;
902
903		    while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) {
904			if (spare->getUUID()->isEqualTo(olduuid)) {
905			    spare->zeroRAIDHeader();
906			    if (spare->isRAIDSet()) {
907				arController->oldMember(spare);
908			    } else {
909				spare->stop(NULL);
910			    }
911			    break;
912			}
913		    }
914		    iter->release();
915		}
916
917		// slide everything in one to fill the deleted spot
918		newMemberCount--;
919		newMemberList->removeObject(i);
920		for (UInt32 j = i; j < newMemberCount; j++) {
921		    arMembers[j] = arMembers[j + 1];
922		    if (arMembers[j]) arMembers[j]->setMemberIndex(j);
923		}
924
925		break;	// XXX this can only delete one member, the interface allows for more
926	    }
927	}
928
929	// this catches new member adds, resizeSet() fixes arMemberCount below
930	newMemberCount = newMemberList->getCount();
931
932	setProperty(kAppleRAIDMembersKey, newMemberList);
933	updateInfo->removeObject(kAppleRAIDMembersKey);
934	updateHeader = true;
935    }
936
937    OSArray * oldSpareList = OSDynamicCast(OSArray, getProperty(kAppleRAIDSparesKey));
938    OSArray * newSpareList = OSDynamicCast(OSArray, updateInfo->getObject(kAppleRAIDSparesKey));
939    if (oldSpareList && newSpareList) {
940
941	IOLog1("AppleRAIDSet::reconfigureSet(%p) updating spare list.\n", this);
942
943	// look for kAppleRAIDDeletedUUID in new list
944	UInt32 spareCount = newSpareList->getCount();
945	for (UInt32 i = 0; i < spareCount; i++) {
946
947	    OSString * uuid = OSDynamicCast(OSString, newSpareList->getObject(i));
948	    if (!uuid || !uuid->isEqualTo(deleted)) continue;
949
950	    // remove "deleted uuid" from the new list
951	    newSpareList->removeObject(i);
952
953	    // get the old uuid based on the position of the deleted uuid marker
954	    OSString * olduuid = OSDynamicCast(OSString, oldSpareList->getObject(i));
955	    if (!olduuid) return false;
956
957	    // Find && nuke the old spare
958	    OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers);
959	    if (!iter) return false;
960
961	    while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) {
962		if (spare->getUUID()->isEqualTo(olduuid)) {
963		    spare->zeroRAIDHeader();
964		    if (spare->isRAIDSet()) {
965			arController->oldMember(spare);
966		    } else {
967			spare->stop(NULL);
968		    }
969		    break;
970		}
971	    }
972	    iter->release();
973
974	    break;	// XXX this can only delete one spare, the interface allows for more
975	}
976	setProperty(kAppleRAIDSparesKey, newSpareList);
977	updateInfo->removeObject(kAppleRAIDSparesKey);
978	updateHeader = true;
979    }
980    deleted->release();
981
982    // pull out the remaining stuff
983    if (updateInfo->getCount()) {
984	initWithHeader(updateInfo, false);
985	updateHeader = true;
986    }
987
988    // newMemberCount will be zero when deleting last member
989    if (newMemberCount != arMemberCount) {
990
991	resizeSet(newMemberCount);
992
993	// update the shadow member count
994	OSNumber * number = OSNumber::withNumber(newMemberCount, 32);
995	if (number) {
996	    updateInfo->setObject(kAppleRAIDMemberCountKey, number);
997	    number->release();
998	}
999    }
1000
1001    if (updateHeader) {
1002
1003	changeSetState(kAppleRAIDSetStateInitializing);
1004
1005	OSArray * memberUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey));
1006	OSArray * spareUUIDs = OSDynamicCast(OSArray, getProperty(kAppleRAIDSparesKey));
1007	for (UInt32 i = 0; i < arMemberCount; i++) {
1008	    if (arMembers[i]) {
1009
1010		// merge new properties into each member
1011		arMembers[i]->updateRAIDHeader(updateInfo);
1012
1013		// update member & spare uuid lists in raid headers, only for v2 headers
1014		arMembers[i]->setHeaderProperty(kAppleRAIDMembersKey, memberUUIDs);
1015		arMembers[i]->setHeaderProperty(kAppleRAIDSparesKey, spareUUIDs);
1016	    }
1017	}
1018    }
1019
1020    return true;
1021}
1022
1023
1024//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1025//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1026//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1027
1028UInt32 AppleRAIDSet::getSequenceNumber()
1029{
1030    return arSequenceNumber;
1031}
1032
1033void AppleRAIDSet::bumpSequenceNumber(void)
1034{
1035    UInt32 cnt;
1036
1037    assert(gAppleRAIDGlobals.islocked());
1038
1039    arSequenceNumber++;
1040
1041    IOLog1("AppleRAIDSet::bumpSequenceNumber(%p) bumping to %u\n", this, (uint32_t)arSequenceNumber);
1042
1043    for (cnt = 0; cnt < arMemberCount; cnt++) {
1044
1045	if (arMembers[cnt]) {
1046	    arMembers[cnt]->setHeaderProperty(kAppleRAIDSequenceNumberKey, arSequenceNumber, 32);
1047	}
1048    }
1049}
1050
1051IOReturn AppleRAIDSet::writeRAIDHeader(void)
1052{
1053    UInt32 cnt;
1054    IOReturn rc = kIOReturnSuccess, rc2;
1055
1056    IOLog1("AppleRAIDSet::writeRAIDHeader(%p) entered.\n", this);
1057
1058    assert(gAppleRAIDGlobals.islocked());
1059
1060    if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) {
1061	IOLog1("AppleRAIDSet::writeRAIDHeader(%p) ignoring request, the set is empty or broken/terminating.\n", this);
1062	return rc;
1063    }
1064
1065    // opening the set changes it's state
1066    UInt32 formerSetState = getSetState();
1067
1068    // we need to be opened for write
1069    bool openedForWrite = arOpenReaderWriters->getCount() != 0;
1070    bool openedForRead  = arOpenReaders->getCount() != 0;
1071    if (!openedForWrite) {
1072	IOLog1("AppleRAIDSet::writeRAIDHeader(%p): opening set for writing.\n", this);
1073	if (!open(this, 0, kIOStorageAccessReaderWriter)) return kIOReturnIOError;
1074    }
1075
1076    for (cnt = 0; cnt < arMemberCount; cnt++) {
1077
1078	if (!arMembers[cnt] || (arMembers[cnt]->getMemberState() < kAppleRAIDMemberStateOpen)) continue;
1079
1080	if (arMembers[cnt]->isRAIDSet() && (rc2 = arMembers[cnt]->AppleRAIDMember::writeRAIDHeader()) != kIOReturnSuccess) {
1081	    IOLog("AppleRAIDSet::writeRAIDHeader() update failed on a set level on set \"%s\" (%s) member %s, rc = %x\n",
1082		  getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), rc2);
1083	    rc = rc2;
1084	    // keep going ...
1085	}
1086
1087	if ((rc2 = arMembers[cnt]->writeRAIDHeader()) != kIOReturnSuccess) {
1088	    IOLog("AppleRAIDSet::writeRAIDHeader() update failed at member level on set \"%s\" (%s) member %s, rc = %x\n",
1089		  getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), rc2);
1090	    rc = rc2;
1091	    // keep going ...
1092	}
1093    }
1094
1095    if (!openedForWrite) {
1096	if (!openedForRead) {
1097	    IOLog1("AppleRAIDSet::writeRAIDHeader(%p): closing set.\n", this);
1098	    close(this, 0);
1099	} else {
1100	    IOLog1("AppleRAIDSet::writeRAIDHeader(%p): downgrading set to read only.\n", this);
1101	    if (!open(this, 0, kIOStorageAccessReader)) {	// downgrades should "always" work
1102		IOLog1("AppleRAIDSet::writeRAIDHeader(%p): downgrade back to RO failed.\n", this);
1103		changeSetState(kAppleRAIDSetStateFailed);
1104		return kIOReturnError;
1105	    }
1106	}
1107	changeSetState(formerSetState);
1108    }
1109    IOLog1("AppleRAIDSet::writeRAIDHeader(%p) exiting with 0x%x.\n", this, rc);
1110
1111    return rc;
1112}
1113
1114//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1115//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1116//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1117
1118
1119
1120IOBufferMemoryDescriptor * AppleRAIDSet::readPrimaryMetaData(AppleRAIDMember * member)
1121{
1122    if (!member) return NULL;
1123    return member->readPrimaryMetaData();
1124}
1125
1126IOReturn AppleRAIDSet::writePrimaryMetaData(IOBufferMemoryDescriptor * primaryBuffer)
1127{
1128    UInt32 cnt;
1129    IOReturn rc = kIOReturnSuccess, rc2;
1130
1131    IOLog1("AppleRAIDSet::writePrimaryMetaData(%p) entered.\n", this);
1132
1133    // XXX assert(gAppleRAIDGlobals.islocked());
1134
1135    if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) {
1136	IOLog1("AppleRAIDSet::writePrimaryMetaData(%p) ignoring request, the set is empty or broken/terminating.\n", this);
1137	return rc;
1138    }
1139
1140    // opening the set changes it's state
1141    UInt32 formerSetState = getSetState();
1142
1143    // we need to be opened for write
1144    bool openedForWrite = arOpenReaderWriters->getCount() != 0;
1145    bool openedForRead  = arOpenReaders->getCount() != 0;
1146    if (!openedForWrite) {
1147	IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): opening set for writing.\n", this);
1148	if (!open(this, 0, kIOStorageAccessReaderWriter)) return kIOReturnIOError;
1149    }
1150
1151    for (cnt = 0; cnt < arMemberCount; cnt++) {
1152
1153	if (!arMembers[cnt] || (arMembers[cnt]->getMemberState() < kAppleRAIDMemberStateOpen)) continue;
1154
1155	if ((rc2 = arMembers[cnt]->writePrimaryMetaData(primaryBuffer)) != kIOReturnSuccess) {
1156	    IOLog("AppleRAIDSet::writePrimaryMetaData() update failed on set \"%s\" (%s) member %s, rc = %x\n",
1157		  getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), rc2);
1158	    rc = rc2;
1159	    // keep going ...
1160	}
1161    }
1162
1163    if (!openedForWrite) {
1164	if (!openedForRead) {
1165	    IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): closing set.\n", this);
1166	    close(this, 0);
1167	} else {
1168	    IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): downgrading set to read only.\n", this);
1169	    if (!open(this, 0, kIOStorageAccessReader)) {	// downgrades should "always" work
1170		IOLog1("AppleRAIDSet::writePrimaryMetaData(%p): downgrade back to RO failed.\n", this);
1171		changeSetState(kAppleRAIDSetStateFailed);
1172		return kIOReturnError;
1173	    }
1174	}
1175	changeSetState(formerSetState);
1176    }
1177    IOLog1("AppleRAIDSet::writePrimaryMetaData(%p) exiting with 0x%x.\n", this, rc);
1178
1179    return rc;
1180}
1181
1182
1183// read into a buffer using member offsets
1184
1185bool AppleRAIDSet::readIntoBuffer(AppleRAIDMember * member, IOBufferMemoryDescriptor * buffer, UInt64 offset)
1186{
1187    assert(buffer);
1188    assert(member);
1189
1190    // Open the whole set
1191    bool openedForRead = isOpen();
1192    if (!openedForRead) {
1193	if (!getTarget()->open(this, 0, kIOStorageAccessReader)) return false;
1194    }
1195
1196    // Read into the buffer
1197    buffer->setDirection(kIODirectionIn);
1198    IOReturn rc = member->getTarget()->read(this, offset, buffer);
1199
1200    // Close the set
1201    if (!openedForRead) {
1202	getTarget()->close(this, 0);
1203    }
1204
1205    return rc == kIOReturnSuccess;
1206}
1207
1208// write from a buffer using member offsets
1209
1210IOReturn AppleRAIDSet::writeFromBuffer(AppleRAIDMember * member, IOBufferMemoryDescriptor * buffer, UInt64 offset)
1211{
1212    IOReturn rc = kIOReturnSuccess;
1213
1214    IOLog1("AppleRAIDSet::writeFromBuffer(%p) entered.\n", this);
1215
1216//    assert(gAppleRAIDGlobals.islocked());
1217
1218    if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) {
1219	IOLog1("AppleRAIDSet::writeFromBuffer(%p) ignoring request, the set is empty or broken/terminating.\n", this);
1220	return rc;
1221    }
1222
1223    // opening the set changes it's state
1224    UInt32 formerSetState = getSetState();
1225
1226    // we need to be opened for write
1227    bool openedForWrite = arOpenReaderWriters->getCount() != 0;
1228    bool openedForRead  = arOpenReaders->getCount() != 0;
1229    if (!openedForWrite) {
1230	IOLog1("AppleRAIDSet::writeFromBuffer(%p): opening set for writing.\n", this);
1231	if (!open(this, 0, kIOStorageAccessReaderWriter)) return kIOReturnIOError;
1232    }
1233
1234    buffer->setDirection(kIODirectionOut);
1235    rc = member->getTarget()->write(this, offset, buffer);
1236
1237    if (!openedForWrite) {
1238	if (!openedForRead) {
1239	    IOLog1("AppleRAIDSet::writeFromBuffer(%p): closing set.\n", this);
1240	    close(this, 0);
1241	} else {
1242	    IOLog1("AppleRAIDSet::writeFromBuffer(%p): downgrading set to read only.\n", this);
1243	    if (!open(this, 0, kIOStorageAccessReader)) {	// downgrades should "always" work
1244		IOLog1("AppleRAIDSet::writeFromBuffer(%p): downgrade back to RO failed.\n", this);
1245		changeSetState(kAppleRAIDSetStateFailed);
1246		return kIOReturnError;
1247	    }
1248	}
1249	changeSetState(formerSetState);
1250    }
1251    IOLog1("AppleRAIDSet::writeFromBuffer(%p) exiting with 0x%x.\n", this, rc);
1252
1253    return rc;
1254}
1255
1256
1257//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1258//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1259//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1260
1261
1262const OSString * AppleRAIDSet::getSetName(void)
1263{
1264    return OSDynamicCast(OSString, getProperty(kAppleRAIDSetNameKey));
1265}
1266
1267const OSString * AppleRAIDSet::getUUID(void)
1268{
1269    return OSDynamicCast(OSString, getProperty(kAppleRAIDMemberUUIDKey));
1270}
1271
1272const OSString * AppleRAIDSet::getSetUUID(void)
1273{
1274    return OSDynamicCast(OSString, getProperty(kAppleRAIDSetUUIDKey));
1275}
1276
1277const OSString * AppleRAIDSet::getDiskName(void)
1278{
1279    return arMedia ? OSDynamicCast(OSString, arMedia->getProperty(kIOBSDNameKey)) : NULL;
1280}
1281
1282//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1283//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1284//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1285
1286IOStorage * AppleRAIDSet::getTarget(void) const
1287{
1288    return (IOStorage *)this;
1289}
1290
1291bool AppleRAIDSet::isRAIDSet(void)
1292{
1293    return true;
1294}
1295
1296bool AppleRAIDSet::isSetComplete(void)
1297{
1298    return arActiveCount == arMemberCount;
1299}
1300
1301bool AppleRAIDSet::bumpOnError(void)
1302{
1303    return false;
1304}
1305
1306UInt64 AppleRAIDSet::getSize() const
1307{
1308    return arSetMediaSize;
1309}
1310
1311IOWorkLoop * AppleRAIDSet::getWorkLoop(void)
1312{
1313    // Create a WorkLoop if it has not already been done.
1314    if (arSetWorkLoop == 0) {
1315        arSetWorkLoop = IOWorkLoop::workLoop();
1316    }
1317
1318    return arSetWorkLoop;
1319}
1320
1321bool AppleRAIDSet::changeSetState(UInt32 newState)
1322{
1323    bool	swapState = false;
1324    const char	*newStatus = "bogus";
1325
1326#ifdef DEBUG
1327    const char	*oldStatus = "not set";
1328    OSString    *oldStatusString = OSDynamicCast(OSString, getProperty(kAppleRAIDStatusKey));
1329    if (oldStatusString) oldStatus = oldStatusString->getCStringNoCopy();
1330#endif
1331
1332    // short cut
1333    if (arSetState == newState) return true;
1334
1335    switch (newState) {
1336
1337    case kAppleRAIDSetStateFailed:		// 0
1338	swapState = true;
1339	newStatus = kAppleRAIDStatusFailed;
1340	break;
1341
1342    case kAppleRAIDSetStateTerminating:		// 1
1343	swapState = arSetState > kAppleRAIDSetStateFailed;
1344	newStatus = kAppleRAIDStatusOffline;
1345	break;
1346
1347    case kAppleRAIDSetStateInitializing:	// 2
1348	swapState = arSetState > kAppleRAIDSetStateTerminating;
1349	newStatus = kAppleRAIDStatusOffline;
1350	break;
1351
1352    case kAppleRAIDSetStateOnline:		// 3
1353	swapState = arSetState >= kAppleRAIDSetStateInitializing;
1354	newStatus = kAppleRAIDStatusOnline;
1355	break;
1356
1357    case kAppleRAIDSetStateDegraded:		// 4
1358	swapState = arSetState >= kAppleRAIDSetStateInitializing;
1359	newStatus = kAppleRAIDStatusDegraded;
1360	break;
1361
1362    default:
1363	IOLog("AppleRAIDSet::changeSetState() this \"%s\" (%s), bogus state %u?\n",
1364	      getSetNameString(), getUUIDString(), (uint32_t)newState);
1365    }
1366
1367    if (swapState) {
1368	IOLog1("AppleRAIDSet::changeSetState(%p) from %u (%s) to %u (%s).\n",
1369	       this, (uint32_t)arSetState, oldStatus, (uint32_t)newState, newStatus);
1370
1371	if (isRAIDMember()) {
1372	    if ((newState >= kAppleRAIDSetStateOnline) && (newState > arSetState)) {
1373		if (getMemberState() >= kAppleRAIDMemberStateClosing) {
1374		    changeMemberState(kAppleRAIDMemberStateOpen);
1375		} else {
1376		    changeMemberState(kAppleRAIDMemberStateClosed);
1377		}
1378	    }
1379	    if ((newState < kAppleRAIDSetStateOnline) && (newState < arSetState)) {
1380		changeMemberState(kAppleRAIDMemberStateClosing);
1381	    }
1382	}
1383
1384	arSetState = newState;
1385	setProperty(kAppleRAIDStatusKey, newStatus);
1386	messageClients(kAppleRAIDMessageSetChanged);
1387
1388    } else {
1389	IOLog1("AppleRAIDSet::changeSetState(%p) FAILED from %u (%s) to %u (%s).\n",
1390	       this, (uint32_t)arSetState, oldStatus, (uint32_t)newState, newStatus);
1391    }
1392
1393    return swapState;
1394}
1395
1396//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1397//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1398//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1399
1400bool
1401AppleRAIDSet::addBootDeviceInfo(OSArray * bootArray)
1402{
1403    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
1404	if (arMembers[cnt] != NULL) {
1405	    if ((arMembers[cnt]->getMemberState() >= kAppleRAIDMemberStateClosed) &&
1406	        (arMembers[cnt]->getMemberState() != kAppleRAIDMemberStateRebuilding)) {
1407
1408		if (!arMembers[cnt]->addBootDeviceInfo(bootArray)) {
1409		    // if any of the devices are not in the device tree
1410		    // just return an empty array
1411		    bootArray->flushCollection();
1412		    return false;
1413		}
1414	    }
1415	}
1416    }
1417
1418    return true;
1419}
1420
1421
1422OSDictionary * AppleRAIDSet::getSetProperties(void)
1423{
1424    OSNumber * tmpNumber;
1425
1426    OSDictionary * props = OSDictionary::withCapacity(32);
1427    if (!props) return NULL;
1428
1429    props->setObject(kAppleRAIDSetNameKey, getSetName());
1430    props->setObject(kAppleRAIDSetUUIDKey, getUUID());
1431    props->setObject(kAppleRAIDLevelNameKey, getProperty(kAppleRAIDLevelNameKey));
1432
1433    tmpNumber = OSNumber::withNumber(arHeaderVersion, 32);
1434    if (tmpNumber) {
1435	props->setObject(kAppleRAIDHeaderVersionKey, tmpNumber);
1436	tmpNumber->release();
1437    }
1438
1439    tmpNumber = OSNumber::withNumber(arSequenceNumber, 32);
1440    if (tmpNumber) {
1441	props->setObject(kAppleRAIDSequenceNumberKey, tmpNumber);
1442	tmpNumber->release();
1443    }
1444
1445    tmpNumber = OSNumber::withNumber(arSetBlockSize, 64);
1446    if (tmpNumber) {
1447	props->setObject(kAppleRAIDChunkSizeKey, tmpNumber);
1448	tmpNumber->release();
1449    }
1450
1451    tmpNumber = OSNumber::withNumber(arSetBlockCount, 64);
1452    if (tmpNumber) {
1453	props->setObject(kAppleRAIDChunkCountKey, tmpNumber);
1454	tmpNumber->release();
1455    }
1456
1457    if (arPrimaryMetaDataUsed) {
1458	tmpNumber = OSNumber::withNumber(arPrimaryMetaDataUsed, 64);
1459	if (tmpNumber){
1460	    props->setObject(kAppleRAIDPrimaryMetaDataUsedKey, tmpNumber);
1461	    tmpNumber->release();
1462	}
1463    }
1464    props->setObject(kAppleRAIDSetContentHintKey, getProperty(kAppleRAIDSetContentHintKey));
1465
1466    props->setObject(kAppleRAIDCanAddMembersKey, getProperty(kAppleRAIDCanAddMembersKey));
1467    props->setObject(kAppleRAIDCanAddSparesKey, getProperty(kAppleRAIDCanAddSparesKey));
1468    props->setObject(kAppleRAIDRemovalAllowedKey, getProperty(kAppleRAIDRemovalAllowedKey));
1469    props->setObject(kAppleRAIDSizesCanVaryKey, getProperty(kAppleRAIDSizesCanVaryKey));
1470
1471    // not from header
1472
1473    props->setObject(kAppleRAIDStatusKey, getProperty(kAppleRAIDStatusKey));
1474    props->setObject(kIOBSDNameKey, getDiskName());
1475
1476    // set up the members array, only v2 headers contain a list of the members
1477    OSArray * members = OSDynamicCast(OSArray, getProperty(kAppleRAIDMembersKey));
1478    if (members) {
1479
1480	props->setObject(kAppleRAIDMembersKey, members);
1481
1482    } else {
1483
1484	members = OSArray::withCapacity(arMemberCount);
1485	if (members) {
1486	    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
1487		if (arMembers[cnt] != 0) {
1488		    const OSString * uuid = arMembers[cnt]->getUUID();
1489		    if (uuid) members->setObject(uuid);
1490		} else {
1491		    OSString * uuid = OSString::withCString(kAppleRAIDMissingUUID);
1492		    if (uuid) {
1493			members->setObject(uuid);
1494			uuid->release();
1495		    }
1496		}
1497	    }
1498	    props->setObject(kAppleRAIDMembersKey, members);
1499	    members->release();
1500	}
1501    }
1502
1503    // we don't worry about losing spares from this spare uuid list,
1504    // if they ever come online again they will be returned to the list
1505    OSArray * spares = OSArray::withCapacity(arMemberCount);
1506    OSCollectionIterator * iter = OSCollectionIterator::withCollection(arSpareMembers);
1507    if (spares && iter) {
1508	while (AppleRAIDMember * spare = (AppleRAIDMember *)iter->getNextObject()) {
1509
1510	    const OSString * uuid = spare->getUUID();
1511	    assert(uuid);
1512	    if (!uuid) continue;
1513
1514	    // skip spares that are in the member list
1515	    OSArray * members = (OSArray *)props->getObject(kAppleRAIDMembersKey);
1516	    UInt32 memberCount = members ? members->getCount() : 0;
1517	    bool foundIt = false;
1518	    for (UInt32 cnt2 = 0; cnt2 < memberCount; cnt2++) {
1519		foundIt = members->getObject(cnt2)->isEqualTo(uuid);
1520		if (foundIt) break;
1521	    }
1522	    if (foundIt) continue;
1523
1524	    // finally, add it to the spare list
1525	    spares->setObject(uuid);
1526	}
1527	props->setObject(kAppleRAIDSparesKey, spares);
1528	setProperty(kAppleRAIDSparesKey, spares);   // lazy update
1529	spares->release();
1530	iter->release();
1531    }
1532
1533    return props;
1534}
1535
1536
1537//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1538//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1539//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1540
1541// This code was lifted from IOPartitionScheme.cpp
1542//
1543// It has few major additions:
1544// 1) Instead of opening or closing one device it handles all the members in a set
1545// 2) Only logical volume groups allow more that one open for writing.
1546// 3) Rebuilding members are left writable even if the set is only open for read.
1547// 4) Opens are only allowed for sets that are online or degraded and at the top level.
1548
1549bool AppleRAIDSet::handleOpen(IOService *  client,
1550			      IOOptionBits options,
1551			      void *       argument)
1552{
1553    //
1554    // The handleOpen method grants or denies permission to access this object
1555    // to an interested client.  The argument is an IOStorageAccess value that
1556    // specifies the level of access desired -- reader or reader-writer.
1557    //
1558    // This method can be invoked to upgrade or downgrade the access level for
1559    // an existing client as well.  The previous access level will prevail for
1560    // upgrades that fail, of course.   A downgrade should never fail.  If the
1561    // new access level should be the same as the old for a given client, this
1562    // method will do nothing and return success.  In all cases, one, singular
1563    // close-per-client is expected for all opens-per-client received.
1564    //
1565    // This implementation replaces the IOService definition of handleOpen().
1566    //
1567    // We are guaranteed that no other opens or closes will be processed until
1568    // we make our decision, change our state, and return from this method.
1569    //
1570
1571    IOStorageAccess access = (IOStorageAccess) (uintptr_t) argument;
1572    IOStorageAccess level;
1573
1574    IOLogOC("AppleRAIDSet::handleOpen(%p) called, client %p, access %u, state %u, client is a set = %s, raid member = %s.\n",
1575			this, client, (uint32_t)access, (uint32_t)arSetState, OSDynamicCast(AppleRAIDSet, client) ? "y" : "n", isRAIDMember() ? "y" : "n");
1576
1577    assert(client);
1578    assert( access == kIOStorageAccessReader       ||
1579            access == kIOStorageAccessReaderWriter );
1580
1581    access &= kIOStorageAccessReaderWriter;   // just in case
1582
1583    // only allow "external" opens after we have published that we are online
1584    if (!OSDynamicCast(AppleRAIDSet, client) && getSetState() < kAppleRAIDSetStateOnline) {
1585	IOLogOC("AppleRAIDSet::handleOpen(%p) open refused (set is not online (published)).\n", this);
1586	return false;
1587    }
1588    // only allow the set that we are a member of to open us if we are stacked.
1589    // however, until we open and read the header, "is member" will be false
1590    if (!OSDynamicCast(AppleRAIDSet, client) && isRAIDMember()) {
1591	IOLogOC("AppleRAIDSet::handleOpen(%p) open refused (set is stacked).\n", this);
1592	return false;
1593    }
1594    assert(arSetState >= kAppleRAIDSetStateOnline);
1595
1596    unsigned writers = arOpenReaderWriters->getCount();
1597
1598#ifdef XXX
1599    if (writers >= arOpenReaderWriterMax)
1600    {
1601	IOLogOC("AppleRAIDSet::handleOpen(%p) client %p access %lu arOpenReaderWriter already set %p\n",
1602		this, client, access, arOpenReaderWriter);
1603	return false;
1604    }
1605#endif
1606
1607    if (arOpenReaderWriters->containsObject(client)) writers--;
1608    if (access == kIOStorageAccessReaderWriter)      writers++;
1609
1610    level = (writers) ? kIOStorageAccessReaderWriter : kIOStorageAccessReader;
1611
1612    //
1613    // Determine whether the levels below us accept this open or not (we avoid
1614    // the open if the required access is the access we already hold).
1615    //
1616
1617    if (arOpenLevel != level)
1618    {
1619	bool success = false;
1620
1621//XXX	level = (level | kIOStorageAccessSharedLock);     breaks stacked raid sets, see assert above
1622
1623	for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
1624	    if (arMembers[cnt] != 0) {
1625
1626		IOLogOC("AppleRAIDSet::handleOpen(%p) opening %p member=%u access=%u level=%u\n",
1627			this, arMembers[cnt], (uint32_t)cnt, (uint32_t)access, (uint32_t)level);
1628
1629		if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue;
1630
1631		success = arMembers[cnt]->open(this, options, level);
1632
1633		if (!success) {
1634		    IOLog("AppleRAIDSet::handleOpen(%p) client %p member %s failed to open for set \"%s\" (%s).\n",
1635			  this, client, arMembers[cnt]->getUUIDString(), getSetNameString(), getUUIDString());
1636		    IOLogOC("AppleRAIDSet::handleOpen() open failed on member %u of %u (active = %u), state = %u isOpen = %s",
1637			  (uint32_t)cnt, (uint32_t)arMemberCount, (uint32_t)arActiveCount, (uint32_t)arSetState, arMembers[cnt]->isOpen(NULL) ? "t" : "f");
1638
1639		    // XXX this is wrong, we might need to just downgrade instead
1640
1641		    // clean up any successfully opened members
1642		    for (UInt32 cnt2 = 0; cnt2 < cnt; cnt2++) {
1643			if (arMembers[cnt2] != 0) {
1644			    if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue;
1645			    arMembers[cnt2]->close(this, 0);
1646			}
1647		    }
1648
1649		    return false;
1650		}
1651	    }
1652	}
1653
1654	level = (level & kIOStorageAccessReaderWriter);
1655    }
1656
1657    //
1658    // Process the open.
1659    //
1660
1661    if (access == kIOStorageAccessReader)
1662    {
1663        arOpenReaders->setObject(client);
1664
1665        arOpenReaderWriters->removeObject(client);           // (for a downgrade)
1666    }
1667    else // (access == kIOStorageAccessReaderWriter)
1668    {
1669        arOpenReaderWriters->setObject(client);
1670
1671        arOpenReaders->removeObject(client);                  // (for an upgrade)
1672    }
1673
1674    arOpenLevel = level;
1675
1676    changeMemberState(kAppleRAIDMemberStateOpen);	// for stacked raid sets
1677
1678    IOLogOC("AppleRAIDSet::handleOpen(%p) successful, client %p, access %u, state %u\n", this, client, (uint32_t)access, (uint32_t)arSetState);
1679
1680    return true;
1681}
1682
1683bool AppleRAIDSet::handleIsOpen(const IOService * client) const
1684{
1685    if (client == 0)  return (arOpenLevel != kIOStorageAccessNone);
1686
1687    bool open = arOpenReaderWriters->containsObject(client) || arOpenReaders->containsObject(client);
1688
1689    IOLogOC("AppleRAIDSet::handleIsOpen(%p) client %p is %s\n", this, client, open ? "true" : "false");
1690
1691    return open;
1692}
1693
1694
1695void AppleRAIDSet::handleClose(IOService * client, IOOptionBits options)
1696{
1697    IOLogOC("AppleRAIDSet::handleClose(%p) called, client %p current state %u\n", this, client, (uint32_t)arSetState);
1698
1699    //
1700    // The handleClose method closes the client's access to this object.
1701    //
1702    // This implementation replaces the IOService definition of handleClose().
1703    //
1704    // We are guaranteed that no other opens or closes will be processed until
1705    // we change our state and return from this method.
1706    //
1707
1708    assert(client);
1709
1710    //
1711    // Process the close.
1712    //
1713
1714    if (arOpenReaderWriters->containsObject(client))  // (is it a reader-writer?)
1715    {
1716        arOpenReaderWriters->removeObject(client);
1717    }
1718    else if (arOpenReaders->containsObject(client))  // (is the client a reader?)
1719    {
1720        arOpenReaders->removeObject(client);
1721    }
1722    else                                      // (is the client is an imposter?)
1723    {
1724        assert(0);
1725        return;
1726    }
1727
1728
1729    //
1730    // Reevaluate the open we have on the level below us.  If no opens remain,
1731    // we close, or if no reader-writer remains, but readers do, we downgrade.
1732    //
1733
1734    IOStorageAccess level;
1735
1736    if (arOpenReaderWriters->getCount())  level = kIOStorageAccessReaderWriter;
1737    else if (arOpenReaders->getCount())   level = kIOStorageAccessReader;
1738    else                                  level = kIOStorageAccessNone;
1739
1740    if (level == kIOStorageAccessNone) {
1741	changeMemberState(kAppleRAIDMemberStateClosing); // for stacked raid sets
1742    }
1743
1744    if (arOpenLevel != level)			// (has open level changed?)
1745    {
1746        assert(level != kIOStorageAccessReaderWriter);
1747
1748	if (level == kIOStorageAccessNone)	// (is a close in order?)
1749	{
1750	    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
1751		if (arMembers[cnt] != 0) {
1752		    if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue;
1753		    arMembers[cnt]->close(this, options);
1754		}
1755	    }
1756
1757	} else {				// (is a downgrade in order?)
1758
1759//XXX	    level = (level | kIOStorageAccessSharedLock);
1760
1761	    bool success;
1762	    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
1763		if (arMembers[cnt] != 0) {
1764		    if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateRebuilding) continue;
1765		    success = arMembers[cnt]->open(this, 0, level);
1766		    assert(success);		// (should never fail, unless avoided deadlock)
1767		}
1768	    }
1769
1770	    level = (level & kIOStorageAccessReaderWriter);  // clear the shared bit
1771	}
1772
1773	arOpenLevel = level;
1774    }
1775
1776    if (level == kIOStorageAccessNone) {
1777	changeMemberState(kAppleRAIDMemberStateClosed);		// for stacked raid sets
1778    }
1779}
1780
1781//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1782//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1783//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
1784
1785void AppleRAIDSet::read(IOService *client, UInt64 byteStart,
1786			IOMemoryDescriptor *buffer, IOStorageAttributes * attributes, IOStorageCompletion * completion)
1787{
1788    AppleRAIDStorageRequest * storageRequest;
1789
1790    IOLogRW("AppleRAIDSet::read(%p, %llu, 0x%x) this %p, state %u\n", client, byteStart, buffer ? (uint32_t)buffer->getLength() : 0, this, (uint32_t)arSetState);
1791
1792    arSetCommandGate->runAction(arAllocateRequestMethod, &storageRequest);
1793
1794    if (storageRequest != 0) {
1795        buffer->retain();
1796        storageRequest->read(client, byteStart, buffer, attributes, completion);
1797    } else {
1798	IOLogRW("AppleRAIDSet::read(%p, 0x%llx) could not allocate a storage request\n", client, byteStart);
1799        IOStorage::complete(completion, kIOReturnNoMedia, 0);
1800    }
1801}
1802
1803void AppleRAIDSet::write(IOService *client, UInt64 byteStart,
1804			 IOMemoryDescriptor *buffer, IOStorageAttributes * attributes, IOStorageCompletion * completion)
1805{
1806    AppleRAIDStorageRequest * storageRequest;
1807
1808    IOLogRW("AppleRAIDSet::write(%p, %llu, 0x%x) this %p, state %u\n", client, byteStart, buffer ? (uint32_t)buffer->getLength() : 0, this, (uint32_t)arSetState);
1809
1810    arSetCommandGate->runAction(arAllocateRequestMethod, &storageRequest);
1811
1812    if (storageRequest != 0) {
1813        buffer->retain();
1814        storageRequest->write(client, byteStart, buffer, attributes, completion);
1815    } else {
1816	IOLogRW("AppleRAIDSet::write(%p, 0x%llx) could not allocate a storage request\n", client, byteStart);
1817        IOStorage::complete(completion, kIOReturnNoMedia, 0);
1818    }
1819}
1820
1821void AppleRAIDSet::activeReadMembers(AppleRAIDMember ** activeMembers, UInt64 byteStart, UInt32 byteCount)
1822{
1823    // XXX the default code should be able to cache this, maybe in the storage request?
1824
1825    for (UInt32 index = 0; index < arMemberCount; index++) {
1826	AppleRAIDMember * member = arMembers[index];
1827	if (member && member->getMemberState() >= kAppleRAIDMemberStateClosing) {
1828	    activeMembers[index] = arMembers[index];
1829	} else {
1830	    activeMembers[index] = (AppleRAIDMember *)index;
1831	}
1832    }
1833}
1834
1835void AppleRAIDSet::activeWriteMembers(AppleRAIDMember ** activeMembers, UInt64 byteStart, UInt32 byteCount)
1836{
1837    // XXX the default code should be able to cache this, maybe in the storage request?
1838
1839    for (UInt32 index = 0; index < arMemberCount; index++) {
1840	AppleRAIDMember * member = arMembers[index];
1841	if (member && member->getMemberState() >= kAppleRAIDMemberStateClosing) {
1842	    activeMembers[index] = arMembers[index];
1843	} else {
1844	    activeMembers[index] = (AppleRAIDMember *)index;
1845	}
1846    }
1847}
1848
1849// the top set (master) needs to go through the workloop
1850// members or members are then already called in that workloop
1851// member sets can just call through, the syncing count is already bumped
1852
1853IOReturn AppleRAIDSet::synchronizeCache(IOService *client)
1854{
1855    if (OSDynamicCast(AppleRAIDSet, client)) return synchronizeCacheGated(client);
1856
1857    IOCommandGate::Action syncCacheMethod = OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::synchronizeCacheGated);
1858    return arSetCommandGate->runAction(syncCacheMethod, (void *)client);
1859}
1860
1861IOReturn AppleRAIDSet::synchronizeCacheGated(IOService *client)
1862{
1863    AppleRAIDSet * masterSet = OSDynamicCast(AppleRAIDSet, client);
1864
1865    if (masterSet == NULL) {
1866	while (arSetIsSyncingCount > 0) {
1867	    IOLog1("AppleRAIDSet::requestSynchronizeCache(%p) stalled count=%d \n", client, (int32_t)arSetIsSyncingCount);
1868	    arSetCommandGate->commandSleep(&arSetIsSyncingCount, THREAD_UNINT);
1869	}
1870	arSetIsSyncingCount++;  // prevents multiple drops to zero
1871    }
1872
1873    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
1874
1875	if (!arMembers[cnt] || (arMembers[cnt]->getMemberState() < kAppleRAIDMemberStateRebuilding)) continue;
1876
1877	arMembers[cnt]->synchronizeCache(masterSet ? masterSet : this);
1878    }
1879
1880    // wait for members to complete
1881    if (masterSet == NULL) {
1882	while (arSetIsSyncingCount > 1) {
1883	    arSetCommandGate->commandSleep(&arSetIsSyncingCount, THREAD_UNINT);
1884	}
1885
1886	// we are done, wake up any other blocked requests
1887	arSetIsSyncingCount--;
1888	assert(arSetIsSyncingCount == 0);
1889	arSetCommandGate->commandWakeup(&arSetIsSyncingCount, /* oneThread */ false);
1890    }
1891
1892    return 0;
1893}
1894
1895void AppleRAIDSet::synchronizeStarted(void)
1896{
1897    arSetIsSyncingCount++;
1898}
1899
1900void AppleRAIDSet::synchronizeCompleted(void)
1901{
1902    arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::synchronizeCompletedGated));
1903}
1904
1905void AppleRAIDSet::synchronizeCompletedGated(void)
1906{
1907    arSetIsSyncingCount--;
1908    if (arSetIsSyncingCount <= 1) {
1909	assert(arSetIsSyncingCount == 1);
1910	arSetCommandGate->commandWakeup(&arSetIsSyncingCount, /* oneThread */ false);
1911    }
1912}
1913
1914bool AppleRAIDSet::pauseSet(bool whenIdle)
1915{
1916    // this is running in the workloop
1917    if (whenIdle) {
1918	if (arStorageRequestsPending != 0) return false;
1919	if (arSetWasBlockedByPause) {
1920	    arSetWasBlockedByPause = false;
1921	    return false;
1922	}
1923    }
1924
1925    // *** ALWAYS CALL SLEEPS IN THE SAME ORDER ***
1926
1927    // only one pause at a time
1928    while (arSetIsPaused) {
1929	arSetWasBlockedByPause = true;
1930	arSetCommandGate->commandSleep(&arSetIsPaused, THREAD_UNINT);
1931    }
1932
1933    arSetIsPaused++;
1934
1935    // wait for any currently pending i/o to drain.
1936    while (arStorageRequestsPending != 0) {
1937        arSetCommandGate->commandSleep(&arStorageRequestPool, THREAD_UNINT);
1938    }
1939
1940    return true;
1941}
1942
1943void AppleRAIDSet::unpauseSet()
1944{
1945    // this is running in the workloop
1946
1947    assert(arSetIsPaused);
1948
1949    arSetIsPaused--;
1950    if (arSetIsPaused == 0) {
1951	arSetCommandGate->commandWakeup(&arSetIsPaused, /* oneThread */ false);
1952    }
1953}
1954
1955IOReturn AppleRAIDSet::allocateRAIDRequest(AppleRAIDStorageRequest **storageRequest)
1956{
1957    while (1) {
1958	if ((arActiveCount == 0) || getSetState() <= kAppleRAIDSetStateTerminating) {
1959	    *storageRequest = 0;
1960	    return kIOReturnNoMedia;
1961	}
1962
1963	// *** ALWAYS CALL SLEEPS IN THE SAME ORDER ***
1964
1965        if (arSetIsPaused) {
1966	    arSetWasBlockedByPause = true;
1967            arSetCommandGate->commandSleep(&arSetIsPaused, THREAD_UNINT);
1968            continue;
1969        }
1970
1971        *storageRequest = (AppleRAIDStorageRequest *)arStorageRequestPool->getCommand(false);
1972        if (*storageRequest == 0) {
1973            arSetCommandGate->commandSleep(&arStorageRequestPool, THREAD_UNINT);
1974            continue;
1975        }
1976
1977        break;
1978    }
1979
1980    arStorageRequestsPending++;
1981
1982    return kIOReturnSuccess;
1983}
1984
1985void AppleRAIDSet::returnRAIDRequest(AppleRAIDStorageRequest *storageRequest)
1986{
1987    arStorageRequestsPending--;
1988    arStorageRequestPool->returnCommand(storageRequest);
1989    arSetCommandGate->commandWakeup(&arStorageRequestPool, /* oneThread */ false);
1990}
1991
1992void AppleRAIDSet::completeRAIDRequest(AppleRAIDStorageRequest *storageRequest)
1993{
1994    UInt32		cnt;
1995    UInt64              byteCount;
1996    IOReturn            status;
1997    bool		isWrite;
1998
1999    // this is running in the workloop, via a AppleRAIDEvent
2000
2001    isWrite = (storageRequest->srMemoryDescriptorDirection == kIODirectionOut);
2002    byteCount = 0;
2003    status = kIOReturnSuccess;
2004
2005    // Collect the status and byte count for each member.
2006    for (cnt = 0; cnt < arMemberCount; cnt++) {
2007
2008	// Ignore missing members.
2009	if (arMembers[cnt] == 0) continue;
2010
2011	// Ignore offline members
2012	if (arMembers[cnt]->getMemberState() != kAppleRAIDMemberStateOpen) {
2013	    IOLogRW("AppleRAIDSet::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p, member state %u\n",
2014		    (uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt],
2015		    byteCount, arMembers[cnt], (uint32_t)arMembers[cnt]->getMemberState());
2016
2017	    if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateClosing) {
2018		status = kIOReturnOffline;
2019	    }
2020
2021	    continue;
2022	}
2023
2024        // Return any status errors.
2025        if (storageRequest->srRequestStatus[cnt] != kIOReturnSuccess) {
2026            status = storageRequest->srRequestStatus[cnt];
2027	    IOLog("AppleRAID::completeRAIDRequest - error 0x%x detected for set \"%s\" (%s), member %s, set byte offset = %llu.\n",
2028		  status, getSetNameString(), getUUIDString(), arMembers[cnt]->getUUIDString(), storageRequest->srByteStart);
2029
2030	    continue;
2031	}
2032
2033	// once the status goes bad, stop counting bytes transfered
2034	if (status == kIOReturnSuccess) {
2035	    byteCount += storageRequest->srRequestByteCounts[cnt];
2036	}
2037
2038	IOLogRW("AppleRAIDSet::completeRAIDRequest - [%u] tbc 0x%llx, sbc 0x%llx bc 0x%llx, member %p\n",
2039		(uint32_t)cnt, storageRequest->srByteCount, storageRequest->srRequestByteCounts[cnt],
2040		byteCount, arMembers[cnt]);
2041    }
2042
2043    // Return an underrun error if the byte count is not complete.
2044    // This can happen if one or more members reported a smaller than expected byte count.
2045    if ((status == kIOReturnSuccess) && (byteCount != storageRequest->srByteCount)) {
2046	IOLog("AppleRAID::completeRAIDRequest - underrun detected, expected = 0x%llx, actual = 0x%llx, set = \"%s\" (%s)\n",
2047	      storageRequest->srByteCount, byteCount, getSetNameString(), getUUIDString());
2048        status = kIOReturnUnderrun;
2049        byteCount = 0;
2050    }
2051
2052    storageRequest->srMemoryDescriptor->release();
2053    returnRAIDRequest(storageRequest);
2054
2055    // Call the clients completion routine, bad status is also returned here.
2056    IOStorage::complete(&storageRequest->srClientsCompletion, status, byteCount);
2057
2058    // remove any failing members from the set
2059    if (status != kIOReturnSuccess) recoverStart();
2060}
2061
2062void AppleRAIDSet::recoverStart()
2063{
2064    IOLog1("AppleRAID::recoverStart entered\n");
2065
2066    arSetIsPaused++;
2067    retain();  // the set also holds a controller ref
2068
2069    bool bumped = thread_call_enter(arRecoveryThreadCall);
2070
2071    if (bumped) {
2072	arSetIsPaused--;
2073	release();
2074    }
2075}
2076
2077void AppleRAIDSet::recoverWait()
2078{
2079    // this is on a separate thread
2080    // running on the workloop
2081
2082    assert(arSetIsPaused);
2083
2084    IOLog1("AppleRAID::recover %u requests are pending.\n", (uint32_t)arStorageRequestsPending);
2085    while (arStorageRequestsPending != 0) {
2086        arSetCommandGate->commandSleep(&arStorageRequestPool, THREAD_UNINT);
2087    }
2088}
2089
2090bool AppleRAIDSet::recover()
2091{
2092    // this is on a separate thread
2093    // the set is paused.
2094
2095    // still here?
2096    if (arController->findSet(getUUID()) != this) return false;
2097
2098    // wait for outstanding i/o
2099    arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::recoverWait));
2100
2101    IOLog1("AppleRAID::recover wait for requests complete.\n");
2102
2103    // at this point, the set should be paused and not allowing any new i/o
2104    // and there should be no active i/o outstanding other than the failed i/o
2105
2106    // thread_call_enter() allows multiple threads to run at once
2107    // the first one that gets out of sleep will then do most of the work
2108    IOSleep(100);
2109
2110    // remove any bad members from the set and reconfigure memory descriptors
2111
2112    gAppleRAIDGlobals.lock();
2113
2114    assert(arSetIsPaused);
2115
2116    UInt32 oldActiveCount = arActiveCount;
2117    OSSet * brokenMembers= OSSet::withCapacity(10);
2118
2119    for (UInt32 cnt = 0; cnt < arMemberCount; cnt++) {
2120
2121	if (arMembers[cnt] == 0) continue;
2122
2123	if (arMembers[cnt]->getMemberState() == kAppleRAIDMemberStateClosing) {
2124
2125	    IOLog("AppleRAID::recover() member %s from set \"%s\" (%s) has been marked offline.\n",
2126		  arMembers[cnt]->getUUIDString(), getSetNameString(), getUUIDString());
2127
2128	    // manually move bad member to the spare list
2129	    // leaving it attached and then close them last
2130
2131	    AppleRAIDMember * brokenMember = arMembers[cnt];
2132
2133	    arMembers[cnt] = 0;
2134	    arActiveCount--;
2135
2136	    brokenMembers->setObject(brokenMember);
2137	    arSpareMembers->setObject(brokenMember);
2138
2139	    brokenMember->changeMemberState(kAppleRAIDMemberStateBroken);
2140	}
2141    }
2142
2143    if (oldActiveCount != arActiveCount) {
2144
2145	// reconfigure the set with the remaining active members
2146	arController->restartSet(this, bumpOnError());
2147
2148	// close the new spares
2149	while (brokenMembers->getCount()) {
2150
2151	    AppleRAIDMember * brokenMember = (AppleRAIDMember *)brokenMembers->getAnyObject();
2152	    brokenMember->close(this, 0);
2153	    brokenMembers->removeObject(brokenMember);
2154	}
2155    }
2156
2157    brokenMembers->release();
2158
2159    bool stillAlive = arActiveCount > 0;
2160
2161    gAppleRAIDGlobals.unlock();
2162
2163    arSetCommandGate->runAction(OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::unpauseSet));
2164
2165    release();  // from recoverStart
2166
2167    IOLog1("AppleRAID::recover finished\n");
2168    return stillAlive;
2169}
2170