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 IOCommand
26OSDefineMetaClassAndStructors(AppleRAIDStorageRequest, IOCommand);
27
28void AppleRAIDStorageRequest::free(void)
29{
30    UInt32	index;
31
32    if (srRequestStatus != 0) IODelete(srRequestStatus, IOReturn, srRequestsAllocated);
33    if (srRequestByteCounts != 0) IODelete(srRequestByteCounts, UInt64, srRequestsAllocated);
34    if (srActiveMembers != 0) IODelete(srActiveMembers, AppleRAIDMember *, srMemberCount);
35
36    if (srMemoryDescriptors != 0) {
37
38        for (index = 0; index < srRequestsAllocated; index++) {
39            if (srMemoryDescriptors[index]) {
40		srMemoryDescriptors[index]->release();
41	    }
42	}
43
44	IODelete(srMemoryDescriptors, AppleRAIDMemoryDescriptor *, srRequestsAllocated);
45
46	srMemoryDescriptors = 0;
47    }
48
49    super::free();
50}
51
52AppleRAIDStorageRequest *AppleRAIDStorageRequest::withAppleRAIDSet(AppleRAIDSet *set)
53{
54    AppleRAIDStorageRequest *storageRequest = new AppleRAIDStorageRequest;
55
56    if (storageRequest != 0) {
57        if (!storageRequest->initWithAppleRAIDSet(set)) {
58            storageRequest->release();
59            storageRequest = 0;
60        }
61    }
62
63    return storageRequest;
64}
65
66
67bool AppleRAIDStorageRequest::initWithAppleRAIDSet(AppleRAIDSet *set)
68{
69    UInt32	index;
70
71    if (!super::init()) return false;
72
73    // anything that can change, must go thru this
74    srRAIDSet = set;
75
76    // these can not change
77    srEventSource	= set->arSetEventSource;
78    srSetBlockSize   	= set->arMaxReadRequestFactor ? (set->arSetBlockSize * set->arMaxReadRequestFactor) : set->arSetBlockSize;
79    srMemberCount	= set->getMemberCount();
80    srRequestCount	= set->getMaxRequestCount();
81    srRequestsAllocated = set->getMaxRequestCount();
82    srMemberBaseOffset	= set->getBase();
83
84    srRequestStatus = IONew(IOReturn, srRequestsAllocated);
85    if (srRequestStatus == 0) return false;
86
87    srRequestByteCounts = IONew(UInt64, srRequestsAllocated);
88    if (srRequestByteCounts == 0) return false;
89
90    srActiveMembers = IONew(AppleRAIDMember *, srMemberCount);
91    if (srActiveMembers == 0) return false;
92
93    srMemoryDescriptors = IONew(AppleRAIDMemoryDescriptor *, srRequestsAllocated);
94    if (srMemoryDescriptors == 0) return false;
95
96    for (index = 0; index < srRequestsAllocated; index++) {
97	srMemoryDescriptors[index] = set->allocateMemoryDescriptor(this, index);
98	if (!srMemoryDescriptors[index]) return false;
99    }
100
101    return true;
102}
103
104
105void AppleRAIDStorageRequest::extractRequest(IOService **client, UInt64 *byteStart,
106					     IOMemoryDescriptor **buffer, IOStorageCompletion *completion)
107{
108    // copy out what we need to restart this i/o
109
110    *client			= srClient;
111    *byteStart			= srByteStart;
112    *buffer	 		= srMemoryDescriptor;
113    *completion 		= srClientsCompletion;
114}
115
116void AppleRAIDStorageRequest::read(IOService *client, UInt64 byteStart, IOMemoryDescriptor *buffer,
117				   IOStorageAttributes * attributes, IOStorageCompletion * completion)
118{
119    UInt32			index, virtIndex;
120    AppleRAIDMember		*member;
121    bool			isOnline;
122    AppleRAIDMemoryDescriptor	*memoryDescriptor;
123    IOStorageCompletion		internalCompletion;
124
125    srClient			= client;
126    srClientsCompletion 	= *completion;
127    srCompletedCount		= 0;
128    srMemoryDescriptor 		= buffer;
129    srMemoryDescriptorDirection	= buffer->getDirection();
130    srByteCount 		= buffer->getLength();
131    srByteStart			= byteStart;
132
133    srRequestCount		= srRAIDSet->getMaxRequestCount();
134    srActiveCount		= srRAIDSet->getActiveCount();
135    srRAIDSet->activeReadMembers(srActiveMembers, srByteStart, srByteCount);
136
137    // XXX this is hideously inefficent, it adds a context switch per i/o request
138    // XXX replace event source code with a direct runAction call?
139    internalCompletion.target    = srEventSource;
140    internalCompletion.action    = srEventSource->getStorageCompletionAction();
141
142    for (virtIndex = 0; virtIndex < srMemberCount; virtIndex++) {
143
144	member = srActiveMembers[virtIndex];
145	isOnline = (uintptr_t)(member) >= 0x1000;
146	index = isOnline ? member->getMemberIndex() : (uintptr_t)member;
147	memoryDescriptor = srMemoryDescriptors[index];
148
149	if (isOnline && memoryDescriptor->configureForMemoryDescriptor(buffer, byteStart, virtIndex)) {
150	    internalCompletion.parameter = memoryDescriptor;
151	    member->read(srRAIDSet, srMemberBaseOffset + memoryDescriptor->mdMemberByteStart,
152			 memoryDescriptor, attributes, &internalCompletion);
153	} else {
154	    // XXX this is lame, just have completion code check active count instead of the member count
155	    // XXX instead of this we could just set the byte count and status here
156	    // this would speed up any io request that does not hit all disks in the set
157	    // would need to handle the case of all the members being DOA?
158	    // there is also a race if we switch the count on the fly
159	    srEventSource->completeRequest(memoryDescriptor, kIOReturnSuccess, 0);
160	}
161    }
162}
163
164void AppleRAIDStorageRequest::write(IOService *client, UInt64 byteStart, IOMemoryDescriptor *buffer,
165				    IOStorageAttributes * attributes, IOStorageCompletion * completion)
166{
167    UInt32			index, virtIndex;
168    AppleRAIDMember		*member;
169    bool			isOnline;
170    AppleRAIDMemoryDescriptor	*memoryDescriptor;
171    IOStorageCompletion		internalCompletion;
172
173    srClient			= client;
174    srClientsCompletion 	= *completion;
175    srCompletedCount		= 0;
176    srMemoryDescriptor 		= buffer;
177    srMemoryDescriptorDirection	= buffer->getDirection();
178    srByteCount 		= buffer->getLength();
179    srByteStart			= byteStart;
180
181    srRequestCount		= srRAIDSet->getMaxRequestCount();
182    srActiveCount		= srRAIDSet->getActiveCount();
183    srRAIDSet->activeWriteMembers(srActiveMembers, srByteStart, srByteCount);
184
185    internalCompletion.target    = srEventSource;
186    internalCompletion.action    = srEventSource->getStorageCompletionAction();
187
188    for (virtIndex = 0; virtIndex < srMemberCount; virtIndex++) {
189
190	member = srActiveMembers[virtIndex];
191	isOnline = (uintptr_t)(member) >= 0x1000;
192	index = isOnline ? member->getMemberIndex() : (uintptr_t)member;
193	memoryDescriptor = srMemoryDescriptors[index];
194
195	if (isOnline && memoryDescriptor->configureForMemoryDescriptor(buffer, byteStart, virtIndex)) {
196            internalCompletion.parameter = memoryDescriptor;
197            member->write(srRAIDSet, srMemberBaseOffset + memoryDescriptor->mdMemberByteStart,
198			  memoryDescriptor, attributes, &internalCompletion);
199        } else {
200            srEventSource->completeRequest(memoryDescriptor, kIOReturnSuccess, 0);
201        }
202    }
203}
204