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
25#define super AppleRAIDSet
26OSDefineMetaClassAndStructors(AppleRAIDConcatSet, AppleRAIDSet);
27
28AppleRAIDSet * AppleRAIDConcatSet::createRAIDSet(AppleRAIDMember * firstMember)
29{
30    AppleRAIDConcatSet *raidSet = new AppleRAIDConcatSet;
31
32    IOLog1("AppleRAIDConcatSet::createRAIDSet(%p) called, new set = %p  *********\n", firstMember, raidSet);
33
34    while (raidSet){
35
36	if (!raidSet->init()) break;
37	if (!raidSet->initWithHeader(firstMember->getHeader(), true)) break;
38	if (raidSet->resizeSet(raidSet->getMemberCount())) return raidSet;
39
40	break;
41    }
42
43    if (raidSet) raidSet->release();
44
45    return 0;
46}
47
48
49bool AppleRAIDConcatSet::init()
50{
51    IOLog1("AppleRAIDConcatSet::init() called\n");
52
53    if (super::init() == false) return false;
54
55    arMemberBlockCounts = 0;
56    arExpectingLiveAdd = 0;
57
58    setProperty(kAppleRAIDLevelNameKey, kAppleRAIDLevelNameConcat);
59
60    arAllocateRequestMethod = OSMemberFunctionCast(IOCommandGate::Action, this, &AppleRAIDSet::allocateRAIDRequest);
61
62    return true;
63}
64
65void AppleRAIDConcatSet::free(void)
66{
67    if (arMemberBlockCounts) IODelete(arMemberBlockCounts, UInt64, arMemberCount);
68
69    super::free();
70}
71
72//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
73//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
74//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
75
76bool AppleRAIDConcatSet::addSpare(AppleRAIDMember * member)
77{
78    if (super::addSpare(member) == false) return false;
79
80    member->changeMemberState(kAppleRAIDMemberStateBroken);
81
82    return true;
83}
84
85bool AppleRAIDConcatSet::addMember(AppleRAIDMember * member)
86{
87    if (super::addMember(member) == false) return false;
88
89    OSNumber * number = OSDynamicCast(OSNumber, member->getHeaderProperty(kAppleRAIDChunkCountKey));
90    if (!number) return false;
91    UInt64 memberBlockCount = number->unsigned64BitValue();
92
93    UInt32 memberIndex = member->getMemberIndex();
94    arMemberBlockCounts[memberIndex] = memberBlockCount;
95
96    // total up the block count as we go
97    arSetBlockCount += memberBlockCount;
98    arSetMediaSize = arSetBlockCount * arSetBlockSize;
99
100    return true;
101}
102
103bool AppleRAIDConcatSet::removeMember(AppleRAIDMember * member, IOOptionBits options)
104{
105    UInt32 memberIndex = member->getMemberIndex();
106    UInt64 memberBlockCount = arMemberBlockCounts[memberIndex];
107
108    IOLog1("AppleRAIDConcatSet::removeMember(%p) called for index %d block count %lld\n",
109	   member, (int)memberIndex, memberBlockCount);
110
111    // remove this member's blocks from the total block count
112    arSetBlockCount -= memberBlockCount;
113    arSetMediaSize = arSetBlockCount * arSetBlockSize;
114    arMemberBlockCounts[memberIndex] = 0;
115
116    return super::removeMember(member, options);
117}
118
119#ifndef MIN
120#define MIN(a,b) (((a)<(b))?(a):(b))
121#endif
122
123bool AppleRAIDConcatSet::resizeSet(UInt32 newMemberCount)
124{
125    UInt32 oldMemberCount = arMemberCount;
126    UInt64 *oldBlockCounts = arMemberBlockCounts;
127
128    arMemberBlockCounts = IONew(UInt64, newMemberCount);
129    bzero(arMemberBlockCounts, sizeof(UInt64) * newMemberCount);
130
131    if (oldBlockCounts) {
132	bcopy(oldBlockCounts, arMemberBlockCounts, sizeof(UInt64) * MIN(newMemberCount, oldMemberCount));
133	IODelete(oldBlockCounts, sizeof(UInt64), oldMemberCount);
134    }
135
136    if (super::resizeSet(newMemberCount) == false) return false;
137
138    if (oldMemberCount && arMemberCount > oldMemberCount) arExpectingLiveAdd += arMemberCount - oldMemberCount;
139
140    return true;
141}
142
143bool AppleRAIDConcatSet::startSet(void)
144{
145    if (super::startSet() == false) return false;
146
147    // the set remains paused when a new member is added
148    if (arExpectingLiveAdd) {
149	arExpectingLiveAdd--;
150	if (arExpectingLiveAdd == 0) unpauseSet();
151    }
152
153    return true;
154}
155
156bool AppleRAIDConcatSet::publishSet(void)
157{
158    if (arExpectingLiveAdd) {
159	IOLog1("AppleRAIDConcat::publishSet() publish ignored.\n");
160	return false;
161    }
162
163    return super::publishSet();
164}
165
166void AppleRAIDConcatSet::unpauseSet()
167{
168    if (arExpectingLiveAdd) {
169	IOLog1("AppleRAIDConcat::unpauseSet() unpause ignored.\n");
170	return;
171    }
172
173    super::unpauseSet();
174}
175
176UInt64 AppleRAIDConcatSet::getMemberSize(UInt32 memberIndex) const
177{
178    assert(arMemberBlockCounts);
179    assert(memberIndex < arMemberCount);
180
181    return arMemberBlockCounts[memberIndex] * arSetBlockSize;;
182}
183
184AppleRAIDMemoryDescriptor * AppleRAIDConcatSet::allocateMemoryDescriptor(AppleRAIDStorageRequest *storageRequest, UInt32 memberIndex)
185{
186    return AppleRAIDConcatMemoryDescriptor::withStorageRequest(storageRequest, memberIndex);
187}
188
189
190// AppleRAIDConcatMemoryDescriptor
191// AppleRAIDConcatMemoryDescriptor
192// AppleRAIDConcatMemoryDescriptor
193
194
195#undef super
196#define super AppleRAIDMemoryDescriptor
197OSDefineMetaClassAndStructors(AppleRAIDConcatMemoryDescriptor, AppleRAIDMemoryDescriptor);
198
199AppleRAIDMemoryDescriptor *
200AppleRAIDConcatMemoryDescriptor::withStorageRequest(AppleRAIDStorageRequest *storageRequest, UInt32 memberIndex)
201{
202    AppleRAIDMemoryDescriptor *memoryDescriptor = new AppleRAIDConcatMemoryDescriptor;
203
204    if (memoryDescriptor != 0) {
205        if (!memoryDescriptor->initWithStorageRequest(storageRequest, memberIndex)) {
206            memoryDescriptor->release();
207            memoryDescriptor = 0;
208        }
209    }
210
211    return memoryDescriptor;
212}
213
214bool AppleRAIDConcatMemoryDescriptor::initWithStorageRequest(AppleRAIDStorageRequest *storageRequest, UInt32 memberIndex)
215{
216    if (!super::initWithStorageRequest(storageRequest, memberIndex)) return false;
217
218    AppleRAIDConcatSet * set = (AppleRAIDConcatSet *)mdStorageRequest->srRAIDSet;
219
220    mdMemberStart = 0;
221    mdMemberEnd = set->getMemberSize(0) - 1;
222
223    for (UInt32 index = 1; index <= memberIndex; index++) {
224
225	mdMemberStart += set->getMemberSize(index - 1);
226	mdMemberEnd += set->getMemberSize(index);
227    }
228
229    return true;
230}
231
232bool AppleRAIDConcatMemoryDescriptor::configureForMemoryDescriptor(IOMemoryDescriptor *memoryDescriptor, UInt64 byteStart, UInt32 activeIndex)
233{
234    UInt32 byteCount = memoryDescriptor->getLength();
235    UInt64 byteEnd = byteStart + byteCount - 1;
236
237    IOLogRW("concat start=%llu end=%llu bytestart=%llu byteCount=%u\n", mdMemberStart, mdMemberEnd, byteStart, (uint32_t)byteCount);
238
239    assert(mdMemberIndex == activeIndex);
240
241    if ((byteEnd < mdMemberStart) || (byteStart > mdMemberEnd)) return false;
242
243    if (byteStart < mdMemberStart) {
244        mdMemberByteStart = 0;
245        mdMemberOffset = mdMemberStart - byteStart;
246        byteCount -= mdMemberOffset;
247    } else {
248        mdMemberByteStart = byteStart - mdMemberStart;
249        mdMemberOffset = 0;
250    }
251
252    if (byteEnd > mdMemberEnd) {
253        byteCount -= byteEnd - mdMemberEnd;
254    }
255
256    _length = byteCount;
257
258    mdMemoryDescriptor = memoryDescriptor;
259
260    _flags = (_flags & ~kIOMemoryDirectionMask) | memoryDescriptor->getDirection();
261
262    IOLogRW("concat mdbytestart=%llu _length=0x%x\n", byteStart, (uint32_t)_length);
263
264    return true;
265}
266
267addr64_t AppleRAIDConcatMemoryDescriptor::getPhysicalSegment(IOByteCount offset, IOByteCount *length, IOOptionBits options)
268{
269    IOByteCount		setOffset = offset + mdMemberOffset;
270    addr64_t		physAddress;
271
272    physAddress = mdMemoryDescriptor->getPhysicalSegment(setOffset, length, options);
273
274    return physAddress;
275}
276