rf_dagfuncs.c revision 1.2 1 1.2 oster /* $NetBSD: rf_dagfuncs.c,v 1.2 1999/01/26 02:33:53 oster Exp $ */
2 1.1 oster /*
3 1.1 oster * Copyright (c) 1995 Carnegie-Mellon University.
4 1.1 oster * All rights reserved.
5 1.1 oster *
6 1.1 oster * Author: Mark Holland, William V. Courtright II
7 1.1 oster *
8 1.1 oster * Permission to use, copy, modify and distribute this software and
9 1.1 oster * its documentation is hereby granted, provided that both the copyright
10 1.1 oster * notice and this permission notice appear in all copies of the
11 1.1 oster * software, derivative works or modified versions, and any portions
12 1.1 oster * thereof, and that both notices appear in supporting documentation.
13 1.1 oster *
14 1.1 oster * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15 1.1 oster * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
16 1.1 oster * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 1.1 oster *
18 1.1 oster * Carnegie Mellon requests users of this software to return to
19 1.1 oster *
20 1.1 oster * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU
21 1.1 oster * School of Computer Science
22 1.1 oster * Carnegie Mellon University
23 1.1 oster * Pittsburgh PA 15213-3890
24 1.1 oster *
25 1.1 oster * any improvements or extensions that they make and grant Carnegie the
26 1.1 oster * rights to redistribute these changes.
27 1.1 oster */
28 1.1 oster
29 1.1 oster /*
30 1.1 oster * dagfuncs.c -- DAG node execution routines
31 1.1 oster *
32 1.1 oster * Rules:
33 1.1 oster * 1. Every DAG execution function must eventually cause node->status to
34 1.1 oster * get set to "good" or "bad", and "FinishNode" to be called. In the
35 1.1 oster * case of nodes that complete immediately (xor, NullNodeFunc, etc),
36 1.1 oster * the node execution function can do these two things directly. In
37 1.1 oster * the case of nodes that have to wait for some event (a disk read to
38 1.1 oster * complete, a lock to be released, etc) to occur before they can
39 1.1 oster * complete, this is typically achieved by having whatever module
40 1.1 oster * is doing the operation call GenericWakeupFunc upon completion.
41 1.1 oster * 2. DAG execution functions should check the status in the DAG header
42 1.1 oster * and NOP out their operations if the status is not "enable". However,
43 1.1 oster * execution functions that release resources must be sure to release
44 1.1 oster * them even when they NOP out the function that would use them.
45 1.1 oster * Functions that acquire resources should go ahead and acquire them
46 1.1 oster * even when they NOP, so that a downstream release node will not have
47 1.1 oster * to check to find out whether or not the acquire was suppressed.
48 1.1 oster */
49 1.1 oster
50 1.1 oster #include <sys/ioctl.h>
51 1.1 oster #include <sys/param.h>
52 1.1 oster
53 1.1 oster #include "rf_archs.h"
54 1.1 oster #include "rf_raid.h"
55 1.1 oster #include "rf_dag.h"
56 1.1 oster #include "rf_layout.h"
57 1.1 oster #include "rf_etimer.h"
58 1.1 oster #include "rf_acctrace.h"
59 1.1 oster #include "rf_diskqueue.h"
60 1.1 oster #include "rf_dagfuncs.h"
61 1.1 oster #include "rf_general.h"
62 1.1 oster #include "rf_engine.h"
63 1.1 oster #include "rf_dagutils.h"
64 1.1 oster
65 1.1 oster #include "rf_kintf.h"
66 1.1 oster
67 1.1 oster #if RF_INCLUDE_PARITYLOGGING > 0
68 1.1 oster #include "rf_paritylog.h"
69 1.1 oster #endif /* RF_INCLUDE_PARITYLOGGING > 0 */
70 1.1 oster
71 1.1 oster int (*rf_DiskReadFunc)(RF_DagNode_t *);
72 1.1 oster int (*rf_DiskWriteFunc)(RF_DagNode_t *);
73 1.1 oster int (*rf_DiskReadUndoFunc)(RF_DagNode_t *);
74 1.1 oster int (*rf_DiskWriteUndoFunc)(RF_DagNode_t *);
75 1.1 oster int (*rf_DiskUnlockFunc)(RF_DagNode_t *);
76 1.1 oster int (*rf_DiskUnlockUndoFunc)(RF_DagNode_t *);
77 1.1 oster int (*rf_RegularXorUndoFunc)(RF_DagNode_t *);
78 1.1 oster int (*rf_SimpleXorUndoFunc)(RF_DagNode_t *);
79 1.1 oster int (*rf_RecoveryXorUndoFunc)(RF_DagNode_t *);
80 1.1 oster
81 1.1 oster /*****************************************************************************************
82 1.1 oster * main (only) configuration routine for this module
83 1.1 oster ****************************************************************************************/
84 1.1 oster int rf_ConfigureDAGFuncs(listp)
85 1.1 oster RF_ShutdownList_t **listp;
86 1.1 oster {
87 1.1 oster RF_ASSERT( ((sizeof(long)==8) && RF_LONGSHIFT==3) || ((sizeof(long)==4) && RF_LONGSHIFT==2) );
88 1.1 oster rf_DiskReadFunc = rf_DiskReadFuncForThreads;
89 1.1 oster rf_DiskReadUndoFunc = rf_DiskUndoFunc;
90 1.1 oster rf_DiskWriteFunc = rf_DiskWriteFuncForThreads;
91 1.1 oster rf_DiskWriteUndoFunc = rf_DiskUndoFunc;
92 1.1 oster rf_DiskUnlockFunc = rf_DiskUnlockFuncForThreads;
93 1.1 oster rf_DiskUnlockUndoFunc = rf_NullNodeUndoFunc;
94 1.1 oster rf_RegularXorUndoFunc = rf_NullNodeUndoFunc;
95 1.1 oster rf_SimpleXorUndoFunc = rf_NullNodeUndoFunc;
96 1.1 oster rf_RecoveryXorUndoFunc = rf_NullNodeUndoFunc;
97 1.1 oster return(0);
98 1.1 oster }
99 1.1 oster
100 1.1 oster
101 1.1 oster
102 1.1 oster /*****************************************************************************************
103 1.1 oster * the execution function associated with a terminate node
104 1.1 oster ****************************************************************************************/
105 1.1 oster int rf_TerminateFunc(node)
106 1.1 oster RF_DagNode_t *node;
107 1.1 oster {
108 1.1 oster RF_ASSERT(node->dagHdr->numCommits == node->dagHdr->numCommitNodes);
109 1.1 oster node->status = rf_good;
110 1.1 oster return(rf_FinishNode(node, RF_THREAD_CONTEXT));
111 1.1 oster }
112 1.1 oster
113 1.1 oster int rf_TerminateUndoFunc(node)
114 1.1 oster RF_DagNode_t *node;
115 1.1 oster {
116 1.1 oster return(0);
117 1.1 oster }
118 1.1 oster
119 1.1 oster
120 1.1 oster /*****************************************************************************************
121 1.1 oster * execution functions associated with a mirror node
122 1.1 oster *
123 1.1 oster * parameters:
124 1.1 oster *
125 1.1 oster * 0 - physical disk addres of data
126 1.1 oster * 1 - buffer for holding read data
127 1.1 oster * 2 - parity stripe ID
128 1.1 oster * 3 - flags
129 1.1 oster * 4 - physical disk address of mirror (parity)
130 1.1 oster *
131 1.1 oster ****************************************************************************************/
132 1.1 oster
133 1.1 oster int rf_DiskReadMirrorIdleFunc(node)
134 1.1 oster RF_DagNode_t *node;
135 1.1 oster {
136 1.1 oster /* select the mirror copy with the shortest queue and fill in node parameters
137 1.1 oster with physical disk address */
138 1.1 oster
139 1.1 oster rf_SelectMirrorDiskIdle(node);
140 1.1 oster return(rf_DiskReadFunc(node));
141 1.1 oster }
142 1.1 oster
143 1.1 oster int rf_DiskReadMirrorPartitionFunc(node)
144 1.1 oster RF_DagNode_t *node;
145 1.1 oster {
146 1.1 oster /* select the mirror copy with the shortest queue and fill in node parameters
147 1.1 oster with physical disk address */
148 1.1 oster
149 1.1 oster rf_SelectMirrorDiskPartition(node);
150 1.1 oster return(rf_DiskReadFunc(node));
151 1.1 oster }
152 1.1 oster
153 1.1 oster int rf_DiskReadMirrorUndoFunc(node)
154 1.1 oster RF_DagNode_t *node;
155 1.1 oster {
156 1.1 oster return(0);
157 1.1 oster }
158 1.1 oster
159 1.1 oster
160 1.1 oster
161 1.1 oster #if RF_INCLUDE_PARITYLOGGING > 0
162 1.1 oster /*****************************************************************************************
163 1.1 oster * the execution function associated with a parity log update node
164 1.1 oster ****************************************************************************************/
165 1.1 oster int rf_ParityLogUpdateFunc(node)
166 1.1 oster RF_DagNode_t *node;
167 1.1 oster {
168 1.1 oster RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *) node->params[0].p;
169 1.1 oster caddr_t buf = (caddr_t) node->params[1].p;
170 1.1 oster RF_ParityLogData_t *logData;
171 1.1 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
172 1.1 oster RF_Etimer_t timer;
173 1.1 oster
174 1.1 oster if (node->dagHdr->status == rf_enable)
175 1.1 oster {
176 1.1 oster RF_ETIMER_START(timer);
177 1.1 oster logData = rf_CreateParityLogData(RF_UPDATE, pda, buf,
178 1.1 oster (RF_Raid_t *) (node->dagHdr->raidPtr),
179 1.1 oster node->wakeFunc, (void *) node,
180 1.1 oster node->dagHdr->tracerec, timer);
181 1.1 oster if (logData)
182 1.1 oster rf_ParityLogAppend(logData, RF_FALSE, NULL, RF_FALSE);
183 1.1 oster else
184 1.1 oster {
185 1.1 oster RF_ETIMER_STOP(timer); RF_ETIMER_EVAL(timer); tracerec->plog_us += RF_ETIMER_VAL_US(timer);
186 1.1 oster (node->wakeFunc)(node, ENOMEM);
187 1.1 oster }
188 1.1 oster }
189 1.1 oster return(0);
190 1.1 oster }
191 1.1 oster
192 1.1 oster
193 1.1 oster /*****************************************************************************************
194 1.1 oster * the execution function associated with a parity log overwrite node
195 1.1 oster ****************************************************************************************/
196 1.1 oster int rf_ParityLogOverwriteFunc(node)
197 1.1 oster RF_DagNode_t *node;
198 1.1 oster {
199 1.1 oster RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *) node->params[0].p;
200 1.1 oster caddr_t buf = (caddr_t) node->params[1].p;
201 1.1 oster RF_ParityLogData_t *logData;
202 1.1 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
203 1.1 oster RF_Etimer_t timer;
204 1.1 oster
205 1.1 oster if (node->dagHdr->status == rf_enable)
206 1.1 oster {
207 1.1 oster RF_ETIMER_START(timer);
208 1.1 oster logData = rf_CreateParityLogData(RF_OVERWRITE, pda, buf, (RF_Raid_t *) (node->dagHdr->raidPtr),
209 1.1 oster node->wakeFunc, (void *) node, node->dagHdr->tracerec, timer);
210 1.1 oster if (logData)
211 1.1 oster rf_ParityLogAppend(logData, RF_FALSE, NULL, RF_FALSE);
212 1.1 oster else
213 1.1 oster {
214 1.1 oster RF_ETIMER_STOP(timer); RF_ETIMER_EVAL(timer); tracerec->plog_us += RF_ETIMER_VAL_US(timer);
215 1.1 oster (node->wakeFunc)(node, ENOMEM);
216 1.1 oster }
217 1.1 oster }
218 1.1 oster return(0);
219 1.1 oster }
220 1.1 oster
221 1.1 oster #else /* RF_INCLUDE_PARITYLOGGING > 0 */
222 1.1 oster
223 1.1 oster int rf_ParityLogUpdateFunc(node)
224 1.1 oster RF_DagNode_t *node;
225 1.1 oster {
226 1.1 oster return(0);
227 1.1 oster }
228 1.1 oster int rf_ParityLogOverwriteFunc(node)
229 1.1 oster RF_DagNode_t *node;
230 1.1 oster {
231 1.1 oster return(0);
232 1.1 oster }
233 1.1 oster
234 1.1 oster #endif /* RF_INCLUDE_PARITYLOGGING > 0 */
235 1.1 oster
236 1.1 oster int rf_ParityLogUpdateUndoFunc(node)
237 1.1 oster RF_DagNode_t *node;
238 1.1 oster {
239 1.1 oster return(0);
240 1.1 oster }
241 1.1 oster
242 1.1 oster int rf_ParityLogOverwriteUndoFunc(node)
243 1.1 oster RF_DagNode_t *node;
244 1.1 oster {
245 1.1 oster return(0);
246 1.1 oster }
247 1.1 oster
248 1.1 oster /*****************************************************************************************
249 1.1 oster * the execution function associated with a NOP node
250 1.1 oster ****************************************************************************************/
251 1.1 oster int rf_NullNodeFunc(node)
252 1.1 oster RF_DagNode_t *node;
253 1.1 oster {
254 1.1 oster node->status = rf_good;
255 1.1 oster return(rf_FinishNode(node, RF_THREAD_CONTEXT));
256 1.1 oster }
257 1.1 oster
258 1.1 oster int rf_NullNodeUndoFunc(node)
259 1.1 oster RF_DagNode_t *node;
260 1.1 oster {
261 1.1 oster node->status = rf_undone;
262 1.1 oster return(rf_FinishNode(node, RF_THREAD_CONTEXT));
263 1.1 oster }
264 1.1 oster
265 1.1 oster
266 1.1 oster /*****************************************************************************************
267 1.1 oster * the execution function associated with a disk-read node
268 1.1 oster ****************************************************************************************/
269 1.1 oster int rf_DiskReadFuncForThreads(node)
270 1.1 oster RF_DagNode_t *node;
271 1.1 oster {
272 1.1 oster RF_DiskQueueData_t *req;
273 1.1 oster RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *)node->params[0].p;
274 1.1 oster caddr_t buf = (caddr_t)node->params[1].p;
275 1.1 oster RF_StripeNum_t parityStripeID = (RF_StripeNum_t)node->params[2].v;
276 1.1 oster unsigned priority = RF_EXTRACT_PRIORITY(node->params[3].v);
277 1.1 oster unsigned lock = RF_EXTRACT_LOCK_FLAG(node->params[3].v);
278 1.1 oster unsigned unlock = RF_EXTRACT_UNLOCK_FLAG(node->params[3].v);
279 1.1 oster unsigned which_ru = RF_EXTRACT_RU(node->params[3].v);
280 1.1 oster RF_DiskQueueDataFlags_t flags = 0;
281 1.1 oster RF_IoType_t iotype = (node->dagHdr->status == rf_enable) ? RF_IO_TYPE_READ : RF_IO_TYPE_NOP;
282 1.1 oster RF_DiskQueue_t **dqs = ((RF_Raid_t *) (node->dagHdr->raidPtr))->Queues;
283 1.1 oster void *b_proc = NULL;
284 1.1 oster #if RF_BACKWARD > 0
285 1.1 oster caddr_t undoBuf;
286 1.1 oster #endif
287 1.1 oster
288 1.1 oster if (node->dagHdr->bp) b_proc = (void *) ((struct buf *) node->dagHdr->bp)->b_proc;
289 1.1 oster
290 1.1 oster RF_ASSERT( !(lock && unlock) );
291 1.1 oster flags |= (lock) ? RF_LOCK_DISK_QUEUE : 0;
292 1.1 oster flags |= (unlock) ? RF_UNLOCK_DISK_QUEUE : 0;
293 1.1 oster #if RF_BACKWARD > 0
294 1.1 oster /* allocate and zero the undo buffer.
295 1.1 oster * this is equivalent to copying the original buffer's contents to the undo buffer
296 1.1 oster * prior to performing the disk read.
297 1.1 oster * XXX hardcoded 512 bytes per sector!
298 1.1 oster */
299 1.1 oster if (node->dagHdr->allocList == NULL)
300 1.1 oster rf_MakeAllocList(node->dagHdr->allocList);
301 1.1 oster RF_CallocAndAdd(undoBuf, 1, 512 * pda->numSector, (caddr_t), node->dagHdr->allocList);
302 1.1 oster #endif /* RF_BACKWARD > 0 */
303 1.1 oster req = rf_CreateDiskQueueData(iotype, pda->startSector, pda->numSector,
304 1.1 oster buf, parityStripeID, which_ru,
305 1.1 oster (int (*)(void *,int)) node->wakeFunc,
306 1.1 oster node, NULL, node->dagHdr->tracerec,
307 1.1 oster (void *)(node->dagHdr->raidPtr), flags, b_proc);
308 1.1 oster if (!req) {
309 1.1 oster (node->wakeFunc)(node, ENOMEM);
310 1.1 oster } else {
311 1.1 oster node->dagFuncData = (void *) req;
312 1.1 oster rf_DiskIOEnqueue( &(dqs[pda->row][pda->col]), req, priority );
313 1.1 oster }
314 1.1 oster return(0);
315 1.1 oster }
316 1.1 oster
317 1.1 oster
318 1.1 oster /*****************************************************************************************
319 1.1 oster * the execution function associated with a disk-write node
320 1.1 oster ****************************************************************************************/
321 1.1 oster int rf_DiskWriteFuncForThreads(node)
322 1.1 oster RF_DagNode_t *node;
323 1.1 oster {
324 1.1 oster RF_DiskQueueData_t *req;
325 1.1 oster RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *)node->params[0].p;
326 1.1 oster caddr_t buf = (caddr_t)node->params[1].p;
327 1.1 oster RF_StripeNum_t parityStripeID = (RF_StripeNum_t)node->params[2].v;
328 1.1 oster unsigned priority = RF_EXTRACT_PRIORITY(node->params[3].v);
329 1.1 oster unsigned lock = RF_EXTRACT_LOCK_FLAG(node->params[3].v);
330 1.1 oster unsigned unlock = RF_EXTRACT_UNLOCK_FLAG(node->params[3].v);
331 1.1 oster unsigned which_ru = RF_EXTRACT_RU(node->params[3].v);
332 1.1 oster RF_DiskQueueDataFlags_t flags = 0;
333 1.1 oster RF_IoType_t iotype = (node->dagHdr->status == rf_enable) ? RF_IO_TYPE_WRITE : RF_IO_TYPE_NOP;
334 1.1 oster RF_DiskQueue_t **dqs = ((RF_Raid_t *) (node->dagHdr->raidPtr))->Queues;
335 1.1 oster void *b_proc = NULL;
336 1.1 oster #if RF_BACKWARD > 0
337 1.1 oster caddr_t undoBuf;
338 1.1 oster #endif
339 1.1 oster
340 1.1 oster if (node->dagHdr->bp) b_proc = (void *) ((struct buf *) node->dagHdr->bp)->b_proc;
341 1.1 oster
342 1.1 oster #if RF_BACKWARD > 0
343 1.1 oster /* This area is used only for backward error recovery experiments
344 1.1 oster * First, schedule allocate a buffer and schedule a pre-read of the disk
345 1.1 oster * After the pre-read, proceed with the normal disk write
346 1.1 oster */
347 1.1 oster if (node->status == rf_bwd2) {
348 1.1 oster /* just finished undo logging, now perform real function */
349 1.1 oster node->status = rf_fired;
350 1.1 oster RF_ASSERT( !(lock && unlock) );
351 1.1 oster flags |= (lock) ? RF_LOCK_DISK_QUEUE : 0;
352 1.1 oster flags |= (unlock) ? RF_UNLOCK_DISK_QUEUE : 0;
353 1.1 oster req = rf_CreateDiskQueueData(iotype,
354 1.1 oster pda->startSector, pda->numSector, buf, parityStripeID, which_ru,
355 1.1 oster node->wakeFunc, (void *) node, NULL, node->dagHdr->tracerec,
356 1.1 oster (void *) (node->dagHdr->raidPtr), flags, b_proc);
357 1.1 oster
358 1.1 oster if (!req) {
359 1.1 oster (node->wakeFunc)(node, ENOMEM);
360 1.1 oster } else {
361 1.1 oster node->dagFuncData = (void *) req;
362 1.1 oster rf_DiskIOEnqueue( &(dqs[pda->row][pda->col]), req, priority );
363 1.1 oster }
364 1.1 oster }
365 1.1 oster
366 1.1 oster else {
367 1.1 oster /* node status should be rf_fired */
368 1.1 oster /* schedule a disk pre-read */
369 1.1 oster node->status = rf_bwd1;
370 1.1 oster RF_ASSERT( !(lock && unlock) );
371 1.1 oster flags |= (lock) ? RF_LOCK_DISK_QUEUE : 0;
372 1.1 oster flags |= (unlock) ? RF_UNLOCK_DISK_QUEUE : 0;
373 1.1 oster if (node->dagHdr->allocList == NULL)
374 1.1 oster rf_MakeAllocList(node->dagHdr->allocList);
375 1.1 oster RF_CallocAndAdd(undoBuf, 1, 512 * pda->numSector, (caddr_t), node->dagHdr->allocList);
376 1.1 oster req = rf_CreateDiskQueueData(RF_IO_TYPE_READ,
377 1.1 oster pda->startSector, pda->numSector, undoBuf, parityStripeID, which_ru,
378 1.1 oster node->wakeFunc, (void *) node, NULL, node->dagHdr->tracerec,
379 1.1 oster (void *) (node->dagHdr->raidPtr), flags, b_proc);
380 1.1 oster
381 1.1 oster if (!req) {
382 1.1 oster (node->wakeFunc)(node, ENOMEM);
383 1.1 oster } else {
384 1.1 oster node->dagFuncData = (void *) req;
385 1.1 oster rf_DiskIOEnqueue( &(dqs[pda->row][pda->col]), req, priority );
386 1.1 oster }
387 1.1 oster }
388 1.1 oster return(0);
389 1.1 oster #endif /* RF_BACKWARD > 0 */
390 1.1 oster
391 1.1 oster /* normal processing (rollaway or forward recovery) begins here */
392 1.1 oster RF_ASSERT( !(lock && unlock) );
393 1.1 oster flags |= (lock) ? RF_LOCK_DISK_QUEUE : 0;
394 1.1 oster flags |= (unlock) ? RF_UNLOCK_DISK_QUEUE : 0;
395 1.1 oster req = rf_CreateDiskQueueData(iotype, pda->startSector, pda->numSector,
396 1.1 oster buf, parityStripeID, which_ru,
397 1.1 oster (int (*)(void *,int)) node->wakeFunc,
398 1.1 oster (void *) node, NULL,
399 1.1 oster node->dagHdr->tracerec,
400 1.1 oster (void *) (node->dagHdr->raidPtr),
401 1.1 oster flags, b_proc);
402 1.1 oster
403 1.1 oster if (!req) {
404 1.1 oster (node->wakeFunc)(node, ENOMEM);
405 1.1 oster } else {
406 1.1 oster node->dagFuncData = (void *) req;
407 1.1 oster rf_DiskIOEnqueue( &(dqs[pda->row][pda->col]), req, priority );
408 1.1 oster }
409 1.1 oster
410 1.1 oster return(0);
411 1.1 oster }
412 1.1 oster
413 1.1 oster /*****************************************************************************************
414 1.1 oster * the undo function for disk nodes
415 1.1 oster * Note: this is not a proper undo of a write node, only locks are released.
416 1.1 oster * old data is not restored to disk!
417 1.1 oster ****************************************************************************************/
418 1.1 oster int rf_DiskUndoFunc(node)
419 1.1 oster RF_DagNode_t *node;
420 1.1 oster {
421 1.1 oster RF_DiskQueueData_t *req;
422 1.1 oster RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *)node->params[0].p;
423 1.1 oster RF_DiskQueue_t **dqs = ((RF_Raid_t *) (node->dagHdr->raidPtr))->Queues;
424 1.1 oster
425 1.1 oster req = rf_CreateDiskQueueData(RF_IO_TYPE_NOP,
426 1.1 oster 0L, 0, NULL, 0L, 0,
427 1.1 oster (int (*)(void *,int)) node->wakeFunc,
428 1.1 oster (void *) node,
429 1.1 oster NULL, node->dagHdr->tracerec,
430 1.1 oster (void *) (node->dagHdr->raidPtr),
431 1.1 oster RF_UNLOCK_DISK_QUEUE, NULL);
432 1.1 oster if (!req)
433 1.1 oster (node->wakeFunc)(node, ENOMEM);
434 1.1 oster else {
435 1.1 oster node->dagFuncData = (void *) req;
436 1.1 oster rf_DiskIOEnqueue( &(dqs[pda->row][pda->col]), req, RF_IO_NORMAL_PRIORITY );
437 1.1 oster }
438 1.1 oster
439 1.1 oster return(0);
440 1.1 oster }
441 1.1 oster
442 1.1 oster /*****************************************************************************************
443 1.1 oster * the execution function associated with an "unlock disk queue" node
444 1.1 oster ****************************************************************************************/
445 1.1 oster int rf_DiskUnlockFuncForThreads(node)
446 1.1 oster RF_DagNode_t *node;
447 1.1 oster {
448 1.1 oster RF_DiskQueueData_t *req;
449 1.1 oster RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *)node->params[0].p;
450 1.1 oster RF_DiskQueue_t **dqs = ((RF_Raid_t *) (node->dagHdr->raidPtr))->Queues;
451 1.1 oster
452 1.1 oster req = rf_CreateDiskQueueData(RF_IO_TYPE_NOP,
453 1.1 oster 0L, 0, NULL, 0L, 0,
454 1.1 oster (int (*)(void *,int)) node->wakeFunc,
455 1.1 oster (void *) node,
456 1.1 oster NULL, node->dagHdr->tracerec,
457 1.1 oster (void *) (node->dagHdr->raidPtr),
458 1.1 oster RF_UNLOCK_DISK_QUEUE, NULL);
459 1.1 oster if (!req)
460 1.1 oster (node->wakeFunc)(node, ENOMEM);
461 1.1 oster else {
462 1.1 oster node->dagFuncData = (void *) req;
463 1.1 oster rf_DiskIOEnqueue( &(dqs[pda->row][pda->col]), req, RF_IO_NORMAL_PRIORITY );
464 1.1 oster }
465 1.1 oster
466 1.1 oster return(0);
467 1.1 oster }
468 1.1 oster
469 1.1 oster /*****************************************************************************************
470 1.1 oster * Callback routine for DiskRead and DiskWrite nodes. When the disk op completes,
471 1.1 oster * the routine is called to set the node status and inform the execution engine that
472 1.1 oster * the node has fired.
473 1.1 oster ****************************************************************************************/
474 1.1 oster int rf_GenericWakeupFunc(node, status)
475 1.1 oster RF_DagNode_t *node;
476 1.1 oster int status;
477 1.1 oster {
478 1.1 oster switch (node->status) {
479 1.1 oster case rf_bwd1 :
480 1.1 oster node->status = rf_bwd2;
481 1.1 oster if (node->dagFuncData)
482 1.1 oster rf_FreeDiskQueueData((RF_DiskQueueData_t *) node->dagFuncData);
483 1.1 oster return(rf_DiskWriteFuncForThreads(node));
484 1.1 oster break;
485 1.1 oster case rf_fired :
486 1.1 oster if (status) node->status = rf_bad;
487 1.1 oster else node->status = rf_good;
488 1.1 oster break;
489 1.1 oster case rf_recover :
490 1.1 oster /* probably should never reach this case */
491 1.1 oster if (status) node->status = rf_panic;
492 1.1 oster else node->status = rf_undone;
493 1.1 oster break;
494 1.1 oster default :
495 1.1 oster RF_PANIC();
496 1.1 oster break;
497 1.1 oster }
498 1.1 oster if (node->dagFuncData)
499 1.1 oster rf_FreeDiskQueueData((RF_DiskQueueData_t *) node->dagFuncData);
500 1.1 oster return(rf_FinishNode(node, RF_INTR_CONTEXT));
501 1.1 oster }
502 1.1 oster
503 1.1 oster
504 1.1 oster /*****************************************************************************************
505 1.1 oster * there are three distinct types of xor nodes
506 1.1 oster * A "regular xor" is used in the fault-free case where the access spans a complete
507 1.1 oster * stripe unit. It assumes that the result buffer is one full stripe unit in size,
508 1.1 oster * and uses the stripe-unit-offset values that it computes from the PDAs to determine
509 1.1 oster * where within the stripe unit to XOR each argument buffer.
510 1.1 oster *
511 1.1 oster * A "simple xor" is used in the fault-free case where the access touches only a portion
512 1.1 oster * of one (or two, in some cases) stripe unit(s). It assumes that all the argument
513 1.1 oster * buffers are of the same size and have the same stripe unit offset.
514 1.1 oster *
515 1.1 oster * A "recovery xor" is used in the degraded-mode case. It's similar to the regular
516 1.1 oster * xor function except that it takes the failed PDA as an additional parameter, and
517 1.1 oster * uses it to determine what portions of the argument buffers need to be xor'd into
518 1.1 oster * the result buffer, and where in the result buffer they should go.
519 1.1 oster ****************************************************************************************/
520 1.1 oster
521 1.1 oster /* xor the params together and store the result in the result field.
522 1.1 oster * assume the result field points to a buffer that is the size of one SU,
523 1.1 oster * and use the pda params to determine where within the buffer to XOR
524 1.1 oster * the input buffers.
525 1.1 oster */
526 1.1 oster int rf_RegularXorFunc(node)
527 1.1 oster RF_DagNode_t *node;
528 1.1 oster {
529 1.1 oster RF_Raid_t *raidPtr = (RF_Raid_t *)node->params[node->numParams-1].p;
530 1.1 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
531 1.1 oster RF_Etimer_t timer;
532 1.1 oster int i, retcode;
533 1.1 oster #if RF_BACKWARD > 0
534 1.1 oster RF_PhysDiskAddr_t *pda;
535 1.1 oster caddr_t undoBuf;
536 1.1 oster #endif
537 1.1 oster
538 1.1 oster retcode = 0;
539 1.1 oster if (node->dagHdr->status == rf_enable) {
540 1.1 oster /* don't do the XOR if the input is the same as the output */
541 1.1 oster RF_ETIMER_START(timer);
542 1.1 oster for (i=0; i<node->numParams-1; i+=2) if (node->params[i+1].p != node->results[0]) {
543 1.1 oster #if RF_BACKWARD > 0
544 1.1 oster /* This section mimics undo logging for backward error recovery experiments b
545 1.1 oster * allocating and initializing a buffer
546 1.1 oster * XXX 512 byte sector size is hard coded!
547 1.1 oster */
548 1.1 oster pda = node->params[i].p;
549 1.1 oster if (node->dagHdr->allocList == NULL)
550 1.1 oster rf_MakeAllocList(node->dagHdr->allocList);
551 1.1 oster RF_CallocAndAdd(undoBuf, 1, 512 * pda->numSector, (caddr_t), node->dagHdr->allocList);
552 1.1 oster #endif /* RF_BACKWARD > 0 */
553 1.1 oster retcode = rf_XorIntoBuffer(raidPtr, (RF_PhysDiskAddr_t *) node->params[i].p,
554 1.1 oster (char *)node->params[i+1].p, (char *) node->results[0], node->dagHdr->bp);
555 1.1 oster }
556 1.1 oster RF_ETIMER_STOP(timer); RF_ETIMER_EVAL(timer); tracerec->xor_us += RF_ETIMER_VAL_US(timer);
557 1.1 oster }
558 1.1 oster return(rf_GenericWakeupFunc(node, retcode)); /* call wake func explicitly since no I/O in this node */
559 1.1 oster }
560 1.1 oster
561 1.1 oster /* xor the inputs into the result buffer, ignoring placement issues */
562 1.1 oster int rf_SimpleXorFunc(node)
563 1.1 oster RF_DagNode_t *node;
564 1.1 oster {
565 1.1 oster RF_Raid_t *raidPtr = (RF_Raid_t *)node->params[node->numParams-1].p;
566 1.1 oster int i, retcode = 0;
567 1.1 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
568 1.1 oster RF_Etimer_t timer;
569 1.1 oster #if RF_BACKWARD > 0
570 1.1 oster RF_PhysDiskAddr_t *pda;
571 1.1 oster caddr_t undoBuf;
572 1.1 oster #endif
573 1.1 oster
574 1.1 oster if (node->dagHdr->status == rf_enable) {
575 1.1 oster RF_ETIMER_START(timer);
576 1.1 oster /* don't do the XOR if the input is the same as the output */
577 1.1 oster for (i=0; i<node->numParams-1; i+=2) if (node->params[i+1].p != node->results[0]) {
578 1.1 oster #if RF_BACKWARD > 0
579 1.1 oster /* This section mimics undo logging for backward error recovery experiments b
580 1.1 oster * allocating and initializing a buffer
581 1.1 oster * XXX 512 byte sector size is hard coded!
582 1.1 oster */
583 1.1 oster pda = node->params[i].p;
584 1.1 oster if (node->dagHdr->allocList == NULL)
585 1.1 oster rf_MakeAllocList(node->dagHdr->allocList);
586 1.1 oster RF_CallocAndAdd(undoBuf, 1, 512 * pda->numSector, (caddr_t), node->dagHdr->allocList);
587 1.1 oster #endif /* RF_BACKWARD > 0 */
588 1.1 oster retcode = rf_bxor((char *)node->params[i+1].p, (char *) node->results[0],
589 1.1 oster rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *)node->params[i].p)->numSector),
590 1.1 oster (struct buf *) node->dagHdr->bp);
591 1.1 oster }
592 1.1 oster RF_ETIMER_STOP(timer); RF_ETIMER_EVAL(timer); tracerec->xor_us += RF_ETIMER_VAL_US(timer);
593 1.1 oster }
594 1.1 oster
595 1.1 oster return(rf_GenericWakeupFunc(node, retcode)); /* call wake func explicitly since no I/O in this node */
596 1.1 oster }
597 1.1 oster
598 1.1 oster /* this xor is used by the degraded-mode dag functions to recover lost data.
599 1.1 oster * the second-to-last parameter is the PDA for the failed portion of the access.
600 1.1 oster * the code here looks at this PDA and assumes that the xor target buffer is
601 1.1 oster * equal in size to the number of sectors in the failed PDA. It then uses
602 1.1 oster * the other PDAs in the parameter list to determine where within the target
603 1.1 oster * buffer the corresponding data should be xored.
604 1.1 oster */
605 1.1 oster int rf_RecoveryXorFunc(node)
606 1.1 oster RF_DagNode_t *node;
607 1.1 oster {
608 1.1 oster RF_Raid_t *raidPtr = (RF_Raid_t *)node->params[node->numParams-1].p;
609 1.1 oster RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) &raidPtr->Layout;
610 1.1 oster RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *)node->params[node->numParams-2].p;
611 1.1 oster int i, retcode = 0;
612 1.1 oster RF_PhysDiskAddr_t *pda;
613 1.1 oster int suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr,failedPDA->startSector);
614 1.1 oster char *srcbuf, *destbuf;
615 1.1 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
616 1.1 oster RF_Etimer_t timer;
617 1.1 oster #if RF_BACKWARD > 0
618 1.1 oster caddr_t undoBuf;
619 1.1 oster #endif
620 1.1 oster
621 1.1 oster if (node->dagHdr->status == rf_enable) {
622 1.1 oster RF_ETIMER_START(timer);
623 1.1 oster for (i=0; i<node->numParams-2; i+=2) if (node->params[i+1].p != node->results[0]) {
624 1.1 oster pda = (RF_PhysDiskAddr_t *)node->params[i].p;
625 1.1 oster #if RF_BACKWARD > 0
626 1.1 oster /* This section mimics undo logging for backward error recovery experiments b
627 1.1 oster * allocating and initializing a buffer
628 1.1 oster * XXX 512 byte sector size is hard coded!
629 1.1 oster */
630 1.1 oster if (node->dagHdr->allocList == NULL)
631 1.1 oster rf_MakeAllocList(node->dagHdr->allocList);
632 1.1 oster RF_CallocAndAdd(undoBuf, 1, 512 * pda->numSector, (caddr_t), node->dagHdr->allocList);
633 1.1 oster #endif /* RF_BACKWARD > 0 */
634 1.1 oster srcbuf = (char *)node->params[i+1].p;
635 1.1 oster suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
636 1.1 oster destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr,suoffset-failedSUOffset);
637 1.1 oster retcode = rf_bxor(srcbuf, destbuf, rf_RaidAddressToByte(raidPtr, pda->numSector), node->dagHdr->bp);
638 1.1 oster }
639 1.1 oster RF_ETIMER_STOP(timer); RF_ETIMER_EVAL(timer); tracerec->xor_us += RF_ETIMER_VAL_US(timer);
640 1.1 oster }
641 1.1 oster return (rf_GenericWakeupFunc(node, retcode));
642 1.1 oster }
643 1.1 oster
644 1.1 oster /*****************************************************************************************
645 1.1 oster * The next three functions are utilities used by the above xor-execution functions.
646 1.1 oster ****************************************************************************************/
647 1.1 oster
648 1.1 oster
649 1.1 oster /*
650 1.1 oster * this is just a glorified buffer xor. targbuf points to a buffer that is one full stripe unit
651 1.1 oster * in size. srcbuf points to a buffer that may be less than 1 SU, but never more. When the
652 1.1 oster * access described by pda is one SU in size (which by implication means it's SU-aligned),
653 1.1 oster * all that happens is (targbuf) <- (srcbuf ^ targbuf). When the access is less than one
654 1.1 oster * SU in size the XOR occurs on only the portion of targbuf identified in the pda.
655 1.1 oster */
656 1.1 oster
657 1.1 oster int rf_XorIntoBuffer(raidPtr, pda, srcbuf, targbuf, bp)
658 1.1 oster RF_Raid_t *raidPtr;
659 1.1 oster RF_PhysDiskAddr_t *pda;
660 1.1 oster char *srcbuf;
661 1.1 oster char *targbuf;
662 1.1 oster void *bp;
663 1.1 oster {
664 1.1 oster char *targptr;
665 1.1 oster int sectPerSU = raidPtr->Layout.sectorsPerStripeUnit;
666 1.1 oster int SUOffset = pda->startSector % sectPerSU;
667 1.1 oster int length, retcode = 0;
668 1.1 oster
669 1.1 oster RF_ASSERT(pda->numSector <= sectPerSU);
670 1.1 oster
671 1.1 oster targptr = targbuf + rf_RaidAddressToByte(raidPtr, SUOffset);
672 1.1 oster length = rf_RaidAddressToByte(raidPtr, pda->numSector);
673 1.1 oster retcode = rf_bxor(srcbuf, targptr, length, bp);
674 1.1 oster return(retcode);
675 1.1 oster }
676 1.1 oster
677 1.1 oster /* it really should be the case that the buffer pointers (returned by malloc)
678 1.1 oster * are aligned to the natural word size of the machine, so this is the only
679 1.1 oster * case we optimize for. The length should always be a multiple of the sector
680 1.1 oster * size, so there should be no problem with leftover bytes at the end.
681 1.1 oster */
682 1.1 oster int rf_bxor(src, dest, len, bp)
683 1.1 oster char *src;
684 1.1 oster char *dest;
685 1.1 oster int len;
686 1.1 oster void *bp;
687 1.1 oster {
688 1.1 oster unsigned mask = sizeof(long) -1, retcode = 0;
689 1.1 oster
690 1.1 oster if ( !(((unsigned long) src) & mask) && !(((unsigned long) dest) & mask) && !(len&mask) ) {
691 1.1 oster retcode = rf_longword_bxor((unsigned long *) src, (unsigned long *) dest, len>>RF_LONGSHIFT, bp);
692 1.1 oster } else {
693 1.1 oster RF_ASSERT(0);
694 1.1 oster }
695 1.1 oster return(retcode);
696 1.1 oster }
697 1.1 oster
698 1.1 oster /* map a user buffer into kernel space, if necessary */
699 1.1 oster #define REMAP_VA(_bp,x,y) (y) = (x)
700 1.1 oster
701 1.1 oster /* When XORing in kernel mode, we need to map each user page to kernel space before we can access it.
702 1.1 oster * We don't want to assume anything about which input buffers are in kernel/user
703 1.1 oster * space, nor about their alignment, so in each loop we compute the maximum number
704 1.1 oster * of bytes that we can xor without crossing any page boundaries, and do only this many
705 1.1 oster * bytes before the next remap.
706 1.1 oster */
707 1.1 oster int rf_longword_bxor(src, dest, len, bp)
708 1.1 oster register unsigned long *src;
709 1.1 oster register unsigned long *dest;
710 1.1 oster int len; /* longwords */
711 1.1 oster void *bp;
712 1.1 oster {
713 1.1 oster register unsigned long *end = src+len;
714 1.1 oster register unsigned long d0, d1, d2, d3, s0, s1, s2, s3; /* temps */
715 1.1 oster register unsigned long *pg_src, *pg_dest; /* per-page source/dest pointers */
716 1.1 oster int longs_this_time; /* # longwords to xor in the current iteration */
717 1.1 oster
718 1.1 oster REMAP_VA(bp, src, pg_src);
719 1.1 oster REMAP_VA(bp, dest, pg_dest);
720 1.1 oster if (!pg_src || !pg_dest) return(EFAULT);
721 1.1 oster
722 1.1 oster while (len >= 4 ) {
723 1.1 oster longs_this_time = RF_MIN(len, RF_MIN(RF_BLIP(pg_src), RF_BLIP(pg_dest)) >> RF_LONGSHIFT); /* note len in longwords */
724 1.1 oster src += longs_this_time; dest+= longs_this_time; len -= longs_this_time;
725 1.1 oster while (longs_this_time >= 4) {
726 1.1 oster d0 = pg_dest[0];
727 1.1 oster d1 = pg_dest[1];
728 1.1 oster d2 = pg_dest[2];
729 1.1 oster d3 = pg_dest[3];
730 1.1 oster s0 = pg_src[0];
731 1.1 oster s1 = pg_src[1];
732 1.1 oster s2 = pg_src[2];
733 1.1 oster s3 = pg_src[3];
734 1.1 oster pg_dest[0] = d0 ^ s0;
735 1.1 oster pg_dest[1] = d1 ^ s1;
736 1.1 oster pg_dest[2] = d2 ^ s2;
737 1.1 oster pg_dest[3] = d3 ^ s3;
738 1.1 oster pg_src += 4;
739 1.1 oster pg_dest += 4;
740 1.1 oster longs_this_time -= 4;
741 1.1 oster }
742 1.1 oster while (longs_this_time > 0) { /* cannot cross any page boundaries here */
743 1.1 oster *pg_dest++ ^= *pg_src++;
744 1.1 oster longs_this_time--;
745 1.1 oster }
746 1.1 oster
747 1.1 oster /* either we're done, or we've reached a page boundary on one (or possibly both) of the pointers */
748 1.1 oster if (len) {
749 1.1 oster if (RF_PAGE_ALIGNED(src)) REMAP_VA(bp, src, pg_src);
750 1.1 oster if (RF_PAGE_ALIGNED(dest)) REMAP_VA(bp, dest, pg_dest);
751 1.1 oster if (!pg_src || !pg_dest) return(EFAULT);
752 1.1 oster }
753 1.1 oster }
754 1.1 oster while (src < end) {
755 1.1 oster *pg_dest++ ^= *pg_src++;
756 1.1 oster src++; dest++; len--;
757 1.1 oster if (RF_PAGE_ALIGNED(src)) REMAP_VA(bp, src, pg_src);
758 1.1 oster if (RF_PAGE_ALIGNED(dest)) REMAP_VA(bp, dest, pg_dest);
759 1.1 oster }
760 1.1 oster RF_ASSERT(len == 0);
761 1.1 oster return(0);
762 1.1 oster }
763 1.1 oster
764 1.1 oster
765 1.1 oster /*
766 1.1 oster dst = a ^ b ^ c;
767 1.1 oster a may equal dst
768 1.1 oster see comment above longword_bxor
769 1.1 oster */
770 1.1 oster int rf_longword_bxor3(dst,a,b,c,len, bp)
771 1.1 oster register unsigned long *dst;
772 1.1 oster register unsigned long *a;
773 1.1 oster register unsigned long *b;
774 1.1 oster register unsigned long *c;
775 1.1 oster int len; /* length in longwords */
776 1.1 oster void *bp;
777 1.1 oster {
778 1.1 oster unsigned long a0,a1,a2,a3, b0,b1,b2,b3;
779 1.1 oster register unsigned long *pg_a, *pg_b, *pg_c, *pg_dst; /* per-page source/dest pointers */
780 1.1 oster int longs_this_time; /* # longs to xor in the current iteration */
781 1.1 oster char dst_is_a = 0;
782 1.1 oster
783 1.1 oster REMAP_VA(bp, a, pg_a);
784 1.1 oster REMAP_VA(bp, b, pg_b);
785 1.1 oster REMAP_VA(bp, c, pg_c);
786 1.1 oster if (a == dst) {pg_dst = pg_a; dst_is_a = 1;} else { REMAP_VA(bp, dst, pg_dst); }
787 1.1 oster
788 1.1 oster /* align dest to cache line. Can't cross a pg boundary on dst here. */
789 1.1 oster while ((((unsigned long) pg_dst) & 0x1f)) {
790 1.1 oster *pg_dst++ = *pg_a++ ^ *pg_b++ ^ *pg_c++;
791 1.1 oster dst++; a++; b++; c++;
792 1.1 oster if (RF_PAGE_ALIGNED(a)) {REMAP_VA(bp, a, pg_a); if (!pg_a) return(EFAULT);}
793 1.1 oster if (RF_PAGE_ALIGNED(b)) {REMAP_VA(bp, a, pg_b); if (!pg_b) return(EFAULT);}
794 1.1 oster if (RF_PAGE_ALIGNED(c)) {REMAP_VA(bp, a, pg_c); if (!pg_c) return(EFAULT);}
795 1.1 oster len--;
796 1.1 oster }
797 1.1 oster
798 1.1 oster while (len > 4 ) {
799 1.1 oster longs_this_time = RF_MIN(len, RF_MIN(RF_BLIP(a), RF_MIN(RF_BLIP(b), RF_MIN(RF_BLIP(c), RF_BLIP(dst)))) >> RF_LONGSHIFT);
800 1.1 oster a+= longs_this_time; b+= longs_this_time; c+= longs_this_time; dst+=longs_this_time; len-=longs_this_time;
801 1.1 oster while (longs_this_time >= 4) {
802 1.1 oster a0 = pg_a[0]; longs_this_time -= 4;
803 1.1 oster
804 1.1 oster a1 = pg_a[1];
805 1.1 oster a2 = pg_a[2];
806 1.1 oster
807 1.1 oster a3 = pg_a[3]; pg_a += 4;
808 1.1 oster
809 1.1 oster b0 = pg_b[0];
810 1.1 oster b1 = pg_b[1];
811 1.1 oster
812 1.1 oster b2 = pg_b[2];
813 1.1 oster b3 = pg_b[3];
814 1.1 oster /* start dual issue */
815 1.1 oster a0 ^= b0; b0 = pg_c[0];
816 1.1 oster
817 1.1 oster pg_b += 4; a1 ^= b1;
818 1.1 oster
819 1.1 oster a2 ^= b2; a3 ^= b3;
820 1.1 oster
821 1.1 oster b1 = pg_c[1]; a0 ^= b0;
822 1.1 oster
823 1.1 oster b2 = pg_c[2]; a1 ^= b1;
824 1.1 oster
825 1.1 oster b3 = pg_c[3]; a2 ^= b2;
826 1.1 oster
827 1.1 oster pg_dst[0] = a0; a3 ^= b3;
828 1.1 oster pg_dst[1] = a1; pg_c += 4;
829 1.1 oster pg_dst[2] = a2;
830 1.1 oster pg_dst[3] = a3; pg_dst += 4;
831 1.1 oster }
832 1.1 oster while (longs_this_time > 0) { /* cannot cross any page boundaries here */
833 1.1 oster *pg_dst++ = *pg_a++ ^ *pg_b++ ^ *pg_c++;
834 1.1 oster longs_this_time--;
835 1.1 oster }
836 1.1 oster
837 1.1 oster if (len) {
838 1.1 oster if (RF_PAGE_ALIGNED(a)) {REMAP_VA(bp, a, pg_a); if (!pg_a) return(EFAULT); if (dst_is_a) pg_dst = pg_a;}
839 1.1 oster if (RF_PAGE_ALIGNED(b)) {REMAP_VA(bp, b, pg_b); if (!pg_b) return(EFAULT);}
840 1.1 oster if (RF_PAGE_ALIGNED(c)) {REMAP_VA(bp, c, pg_c); if (!pg_c) return(EFAULT);}
841 1.1 oster if (!dst_is_a) if (RF_PAGE_ALIGNED(dst)) {REMAP_VA(bp, dst, pg_dst); if (!pg_dst) return(EFAULT);}
842 1.1 oster }
843 1.1 oster }
844 1.1 oster while (len) {
845 1.1 oster *pg_dst++ = *pg_a++ ^ *pg_b++ ^ *pg_c++;
846 1.1 oster dst++; a++; b++; c++;
847 1.1 oster if (RF_PAGE_ALIGNED(a)) {REMAP_VA(bp, a, pg_a); if (!pg_a) return(EFAULT); if (dst_is_a) pg_dst = pg_a;}
848 1.1 oster if (RF_PAGE_ALIGNED(b)) {REMAP_VA(bp, b, pg_b); if (!pg_b) return(EFAULT);}
849 1.1 oster if (RF_PAGE_ALIGNED(c)) {REMAP_VA(bp, c, pg_c); if (!pg_c) return(EFAULT);}
850 1.1 oster if (!dst_is_a) if (RF_PAGE_ALIGNED(dst)) {REMAP_VA(bp, dst, pg_dst); if (!pg_dst) return(EFAULT);}
851 1.1 oster len--;
852 1.1 oster }
853 1.1 oster return(0);
854 1.1 oster }
855 1.1 oster
856 1.1 oster int rf_bxor3(dst,a,b,c,len, bp)
857 1.1 oster register unsigned char *dst;
858 1.1 oster register unsigned char *a;
859 1.1 oster register unsigned char *b;
860 1.1 oster register unsigned char *c;
861 1.1 oster unsigned long len;
862 1.1 oster void *bp;
863 1.1 oster {
864 1.1 oster RF_ASSERT(((RF_UL(dst)|RF_UL(a)|RF_UL(b)|RF_UL(c)|len) & 0x7) == 0);
865 1.1 oster
866 1.1 oster return(rf_longword_bxor3((unsigned long *)dst, (unsigned long *)a,
867 1.1 oster (unsigned long *)b, (unsigned long *)c, len>>RF_LONGSHIFT, bp));
868 1.1 oster }
869