rf_evenodd_dagfuncs.c revision 1.17
1142262Sru/*	$NetBSD: rf_evenodd_dagfuncs.c,v 1.17 2006/08/28 02:58:16 christos Exp $	*/
2142262Sru/*
3161526Sru * Copyright (c) 1995 Carnegie-Mellon University.
4142262Sru * All rights reserved.
5142410Scognet *
6178633Sgonzo * Author: ChangMing Wu
7178633Sgonzo *
8142262Sru * Permission to use, copy, modify and distribute this software and
9142262Sru * its documentation is hereby granted, provided that both the copyright
10209868Snwhitehorn * notice and this permission notice appear in all copies of the
11142410Scognet * software, derivative works or modified versions, and any portions
12178633Sgonzo * thereof, and that both notices appear in supporting documentation.
13178633Sgonzo *
14142262Sru * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
15142262Sru * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
16 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 *
18 * Carnegie Mellon requests users of this software to return to
19 *
20 *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21 *  School of Computer Science
22 *  Carnegie Mellon University
23 *  Pittsburgh PA 15213-3890
24 *
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
27 */
28
29/*
30 * Code for RAID-EVENODD  architecture.
31 */
32
33#include <sys/cdefs.h>
34__KERNEL_RCSID(0, "$NetBSD: rf_evenodd_dagfuncs.c,v 1.17 2006/08/28 02:58:16 christos Exp $");
35
36#include "rf_archs.h"
37#include "opt_raid_diagnostic.h"
38
39#if RF_INCLUDE_EVENODD > 0
40
41#include <dev/raidframe/raidframevar.h>
42
43#include "rf_raid.h"
44#include "rf_dag.h"
45#include "rf_dagffrd.h"
46#include "rf_dagffwr.h"
47#include "rf_dagdegrd.h"
48#include "rf_dagdegwr.h"
49#include "rf_dagutils.h"
50#include "rf_dagfuncs.h"
51#include "rf_etimer.h"
52#include "rf_general.h"
53#include "rf_parityscan.h"
54#include "rf_evenodd.h"
55#include "rf_evenodd_dagfuncs.h"
56
57/* These redundant functions are for small write */
58RF_RedFuncs_t rf_EOSmallWritePFuncs = {rf_RegularXorFunc, "Regular Old-New P", rf_SimpleXorFunc, "Simple Old-New P"};
59RF_RedFuncs_t rf_EOSmallWriteEFuncs = {rf_RegularONEFunc, "Regular Old-New E", rf_SimpleONEFunc, "Regular Old-New E"};
60/* These redundant functions are for degraded read */
61RF_RedFuncs_t rf_eoPRecoveryFuncs = {rf_RecoveryXorFunc, "Recovery Xr", rf_RecoveryXorFunc, "Recovery Xr"};
62RF_RedFuncs_t rf_eoERecoveryFuncs = {rf_RecoveryEFunc, "Recovery E Func", rf_RecoveryEFunc, "Recovery E Func"};
63/**********************************************************************************************
64 *   the following encoding node functions is used in  EO_000_CreateLargeWriteDAG
65 **********************************************************************************************/
66int
67rf_RegularPEFunc(node)
68	RF_DagNode_t *node;
69{
70	rf_RegularESubroutine(node, node->results[1]);
71	rf_RegularXorFunc(node);/* does the wakeup here! */
72#if 1
73	return (0);		/* XXX This was missing... GO */
74#endif
75}
76
77
78/************************************************************************************************
79 *  For EO_001_CreateSmallWriteDAG, there are (i)RegularONEFunc() and (ii)SimpleONEFunc() to
80 *  be used. The previous case is when write access at least sectors of full stripe unit.
81 *  The later function is used when the write access two stripe units but with total sectors
82 *  less than sectors per SU. In this case, the access of parity and 'E' are shown as disconnected
83 *  areas in their stripe unit and  parity write and 'E' write are both devided into two distinct
84 *  writes( totally four). This simple old-new write and regular old-new write happen as in RAID-5
85 ************************************************************************************************/
86
87/* Algorithm:
88     1. Store the difference of old data and new data in the Rod buffer.
89     2. then encode this buffer into the buffer which already have old 'E' information inside it,
90	the result can be shown to be the new 'E' information.
91     3. xor the Wnd buffer into the difference buffer to recover the  original old data.
92   Here we have another alternative: to allocate a temporary buffer for storing the difference of
93   old data and new data, then encode temp buf into old 'E' buf to form new 'E', but this approach
94   take the same speed as the previous, and need more memory.
95*/
96int
97rf_RegularONEFunc(node)
98	RF_DagNode_t *node;
99{
100	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
101	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout;
102	int     EpdaIndex = (node->numParams - 1) / 2 - 1;	/* the parameter of node
103								 * where you can find
104								 * e-pda */
105	int     i, k, retcode = 0;
106	int     suoffset, length;
107	RF_RowCol_t scol;
108	char   *srcbuf, *destbuf;
109	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
110	RF_Etimer_t timer;
111	RF_PhysDiskAddr_t *pda;
112#ifdef RAID_DIAGNOSTIC
113	RF_PhysDiskAddr_t *EPDA =
114	    (RF_PhysDiskAddr_t *) node->params[EpdaIndex].p;
115	int     ESUOffset = rf_StripeUnitOffset(layoutPtr, EPDA->startSector);
116#endif /* RAID_DIAGNOSTIC */
117
118	RF_ASSERT(EPDA->type == RF_PDA_TYPE_Q);
119	RF_ASSERT(ESUOffset == 0);
120
121	RF_ETIMER_START(timer);
122
123	/* Xor the Wnd buffer into Rod buffer, the difference of old data and
124	 * new data is stored in Rod buffer */
125	for (k = 0; k < EpdaIndex; k += 2) {
126		length = rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *) node->params[k].p)->numSector);
127		retcode = rf_bxor(node->params[k + EpdaIndex + 3].p, node->params[k + 1].p, length);
128	}
129	/* Start to encoding the buffer storing the difference of old data and
130	 * new data into 'E' buffer  */
131	for (i = 0; i < EpdaIndex; i += 2)
132		if (node->params[i + 1].p != node->results[0]) {	/* results[0] is buf ptr
133									 * of E */
134			pda = (RF_PhysDiskAddr_t *) node->params[i].p;
135			srcbuf = (char *) node->params[i + 1].p;
136			scol = rf_EUCol(layoutPtr, pda->raidAddress);
137			suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
138			destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr, suoffset);
139			rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector);
140		}
141	/* Recover the original old data to be used by parity encoding
142	 * function in XorNode */
143	for (k = 0; k < EpdaIndex; k += 2) {
144		length = rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *) node->params[k].p)->numSector);
145		retcode = rf_bxor(node->params[k + EpdaIndex + 3].p, node->params[k + 1].p, length);
146	}
147	RF_ETIMER_STOP(timer);
148	RF_ETIMER_EVAL(timer);
149	tracerec->q_us += RF_ETIMER_VAL_US(timer);
150	rf_GenericWakeupFunc(node, 0);
151#if 1
152	return (0);		/* XXX this was missing.. GO */
153#endif
154}
155
156int
157rf_SimpleONEFunc(node)
158	RF_DagNode_t *node;
159{
160	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
161	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout;
162	RF_PhysDiskAddr_t *pda = (RF_PhysDiskAddr_t *) node->params[0].p;
163	int     retcode = 0;
164	char   *srcbuf, *destbuf;
165	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
166	int     length;
167	RF_RowCol_t scol;
168	RF_Etimer_t timer;
169
170	RF_ASSERT(((RF_PhysDiskAddr_t *) node->params[2].p)->type == RF_PDA_TYPE_Q);
171	if (node->dagHdr->status == rf_enable) {
172		RF_ETIMER_START(timer);
173		length = rf_RaidAddressToByte(raidPtr, ((RF_PhysDiskAddr_t *) node->params[4].p)->numSector);	/* this is a pda of
174														 * writeDataNodes */
175		/* bxor to buffer of readDataNodes */
176		retcode = rf_bxor(node->params[5].p, node->params[1].p, length);
177		/* find out the corresponding colume in encoding matrix for
178		 * write colume to be encoded into redundant disk 'E' */
179		scol = rf_EUCol(layoutPtr, pda->raidAddress);
180		srcbuf = node->params[1].p;
181		destbuf = node->params[3].p;
182		/* Start encoding process */
183		rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector);
184		rf_bxor(node->params[5].p, node->params[1].p, length);
185		RF_ETIMER_STOP(timer);
186		RF_ETIMER_EVAL(timer);
187		tracerec->q_us += RF_ETIMER_VAL_US(timer);
188
189	}
190	return (rf_GenericWakeupFunc(node, retcode));	/* call wake func
191							 * explicitly since no
192							 * I/O in this node */
193}
194
195
196/****** called by rf_RegularPEFunc(node) and rf_RegularEFunc(node) in f.f. large write  ********/
197void
198rf_RegularESubroutine(node, ebuf)
199	RF_DagNode_t *node;
200	char   *ebuf;
201{
202	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
203	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout;
204	RF_PhysDiskAddr_t *pda;
205	int     i, suoffset;
206	RF_RowCol_t scol;
207	char   *srcbuf, *destbuf;
208	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
209	RF_Etimer_t timer;
210
211	RF_ETIMER_START(timer);
212	for (i = 0; i < node->numParams - 2; i += 2) {
213		RF_ASSERT(node->params[i + 1].p != ebuf);
214		pda = (RF_PhysDiskAddr_t *) node->params[i].p;
215		suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
216		scol = rf_EUCol(layoutPtr, pda->raidAddress);
217		srcbuf = (char *) node->params[i + 1].p;
218		destbuf = ebuf + rf_RaidAddressToByte(raidPtr, suoffset);
219		rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector);
220	}
221	RF_ETIMER_STOP(timer);
222	RF_ETIMER_EVAL(timer);
223	tracerec->xor_us += RF_ETIMER_VAL_US(timer);
224}
225
226
227/*******************************************************************************************
228 *			 Used in  EO_001_CreateLargeWriteDAG
229 ******************************************************************************************/
230int
231rf_RegularEFunc(node)
232	RF_DagNode_t *node;
233{
234	rf_RegularESubroutine(node, node->results[0]);
235	rf_GenericWakeupFunc(node, 0);
236#if 1
237	return (0);		/* XXX this was missing?.. GO */
238#endif
239}
240/*******************************************************************************************
241 * This degraded function allow only two case:
242 *  1. when write access the full failed stripe unit, then the access can be more than
243 *     one tripe units.
244 *  2. when write access only part of the failed SU, we assume accesses of more than
245 *     one stripe unit is not allowed so that the write can be dealt with like a
246 *     large write.
247 *  The following function is based on these assumptions. So except in the second case,
248 *  it looks the same as a large write encodeing function. But this is not exactly the
249 *  normal way for doing a degraded write, since raidframe have to break cases of access
250 *  other than the above two into smaller accesses. We may have to change
251 *  DegrESubroutin in the future.
252 *******************************************************************************************/
253void
254rf_DegrESubroutine(node, ebuf)
255	RF_DagNode_t *node;
256	char   *ebuf;
257{
258	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
259	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout;
260	RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *) node->params[node->numParams - 2].p;
261	RF_PhysDiskAddr_t *pda;
262	int     i, suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr, failedPDA->startSector);
263	RF_RowCol_t scol;
264	char   *srcbuf, *destbuf;
265	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
266	RF_Etimer_t timer;
267
268	RF_ETIMER_START(timer);
269	for (i = 0; i < node->numParams - 2; i += 2) {
270		RF_ASSERT(node->params[i + 1].p != ebuf);
271		pda = (RF_PhysDiskAddr_t *) node->params[i].p;
272		suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
273		scol = rf_EUCol(layoutPtr, pda->raidAddress);
274		srcbuf = (char *) node->params[i + 1].p;
275		destbuf = ebuf + rf_RaidAddressToByte(raidPtr, suoffset - failedSUOffset);
276		rf_e_encToBuf(raidPtr, scol, srcbuf, RF_EO_MATRIX_DIM - 2, destbuf, pda->numSector);
277	}
278
279	RF_ETIMER_STOP(timer);
280	RF_ETIMER_EVAL(timer);
281	tracerec->q_us += RF_ETIMER_VAL_US(timer);
282}
283
284
285/**************************************************************************************
286 * This function is used in case where one data disk failed and both redundant disks
287 * alive. It is used in the EO_100_CreateWriteDAG. Note: if there is another disk
288 * failed in the stripe but not accessed at this time, then we should, instead, use
289 * the rf_EOWriteDoubleRecoveryFunc().
290 **************************************************************************************/
291int
292rf_Degraded_100_EOFunc(node)
293	RF_DagNode_t *node;
294{
295	rf_DegrESubroutine(node, node->results[1]);
296	rf_RecoveryXorFunc(node);	/* does the wakeup here! */
297#if 1
298	return (0);		/* XXX this was missing... SHould these be
299				 * void functions??? GO */
300#endif
301}
302/**************************************************************************************
303 * This function is to encode one sector in one of the data disks to the E disk.
304 * However, in evenodd this function can also be used as decoding function to recover
305 * data from dead disk in the case of parity failure and a single data failure.
306 **************************************************************************************/
307void
308rf_e_EncOneSect(
309    RF_RowCol_t srcLogicCol,
310    char *srcSecbuf,
311    RF_RowCol_t destLogicCol,
312    char *destSecbuf,
313    int bytesPerSector)
314{
315	int     S_index;	/* index of the EU in the src col which need
316				 * be Xored into all EUs in a dest sector */
317	int     numRowInEncMatix = (RF_EO_MATRIX_DIM) - 1;
318	RF_RowCol_t j, indexInDest,	/* row index of an encoding unit in
319					 * the destination colume of encoding
320					 * matrix */
321	        indexInSrc;	/* row index of an encoding unit in the source
322				 * colume used for recovery */
323	int     bytesPerEU = bytesPerSector / numRowInEncMatix;
324
325#if RF_EO_MATRIX_DIM > 17
326	int     shortsPerEU = bytesPerEU / sizeof(short);
327	short  *destShortBuf, *srcShortBuf1, *srcShortBuf2;
328	short temp1;
329#elif RF_EO_MATRIX_DIM == 17
330	int     longsPerEU = bytesPerEU / sizeof(long);
331	long   *destLongBuf, *srcLongBuf1, *srcLongBuf2;
332	long temp1;
333#endif
334
335#if RF_EO_MATRIX_DIM > 17
336	RF_ASSERT(sizeof(short) == 2 || sizeof(short) == 1);
337	RF_ASSERT(bytesPerEU % sizeof(short) == 0);
338#elif RF_EO_MATRIX_DIM == 17
339	RF_ASSERT(sizeof(long) == 8 || sizeof(long) == 4);
340	RF_ASSERT(bytesPerEU % sizeof(long) == 0);
341#endif
342
343	S_index = rf_EO_Mod((RF_EO_MATRIX_DIM - 1 + destLogicCol - srcLogicCol), RF_EO_MATRIX_DIM);
344#if RF_EO_MATRIX_DIM > 17
345	srcShortBuf1 = (short *) (srcSecbuf + S_index * bytesPerEU);
346#elif RF_EO_MATRIX_DIM == 17
347	srcLongBuf1 = (long *) (srcSecbuf + S_index * bytesPerEU);
348#endif
349
350	for (indexInDest = 0; indexInDest < numRowInEncMatix; indexInDest++) {
351		indexInSrc = rf_EO_Mod((indexInDest + destLogicCol - srcLogicCol), RF_EO_MATRIX_DIM);
352
353#if RF_EO_MATRIX_DIM > 17
354		destShortBuf = (short *) (destSecbuf + indexInDest * bytesPerEU);
355		srcShortBuf2 = (short *) (srcSecbuf + indexInSrc * bytesPerEU);
356		for (j = 0; j < shortsPerEU; j++) {
357			temp1 = destShortBuf[j] ^ srcShortBuf1[j];
358			/* note: S_index won't be at the end row for any src
359			 * col! */
360			if (indexInSrc != RF_EO_MATRIX_DIM - 1)
361				destShortBuf[j] = (srcShortBuf2[j]) ^ temp1;
362			/* if indexInSrc is at the end row, ie.
363			 * RF_EO_MATRIX_DIM -1, then all elements are zero! */
364			else
365				destShortBuf[j] = temp1;
366		}
367
368#elif RF_EO_MATRIX_DIM == 17
369		destLongBuf = (long *) (destSecbuf + indexInDest * bytesPerEU);
370		srcLongBuf2 = (long *) (srcSecbuf + indexInSrc * bytesPerEU);
371		for (j = 0; j < longsPerEU; j++) {
372			temp1 = destLongBuf[j] ^ srcLongBuf1[j];
373			if (indexInSrc != RF_EO_MATRIX_DIM - 1)
374				destLongBuf[j] = (srcLongBuf2[j]) ^ temp1;
375			else
376				destLongBuf[j] = temp1;
377		}
378#endif
379	}
380}
381
382void
383rf_e_encToBuf(
384    RF_Raid_t * raidPtr,
385    RF_RowCol_t srcLogicCol,
386    char *srcbuf,
387    RF_RowCol_t destLogicCol,
388    char *destbuf,
389    int numSector)
390{
391	int     i, bytesPerSector = rf_RaidAddressToByte(raidPtr, 1);
392
393	for (i = 0; i < numSector; i++) {
394		rf_e_EncOneSect(srcLogicCol, srcbuf, destLogicCol, destbuf, bytesPerSector);
395		srcbuf += bytesPerSector;
396		destbuf += bytesPerSector;
397	}
398}
399/**************************************************************************************
400 * when parity die and one data die, We use second redundant information, 'E',
401 * to recover the data in dead disk. This function is used in the recovery node of
402 * for EO_110_CreateReadDAG
403 **************************************************************************************/
404int
405rf_RecoveryEFunc(node)
406	RF_DagNode_t *node;
407{
408	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
409	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout;
410	RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *) node->params[node->numParams - 2].p;
411	RF_RowCol_t scol,	/* source logical column */
412	        fcol = rf_EUCol(layoutPtr, failedPDA->raidAddress);	/* logical column of
413									 * failed SU */
414	int     i;
415	RF_PhysDiskAddr_t *pda;
416	int     suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr, failedPDA->startSector);
417	char   *srcbuf, *destbuf;
418	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
419	RF_Etimer_t timer;
420
421	memset((char *) node->results[0], 0,
422	    rf_RaidAddressToByte(raidPtr, failedPDA->numSector));
423	if (node->dagHdr->status == rf_enable) {
424		RF_ETIMER_START(timer);
425		for (i = 0; i < node->numParams - 2; i += 2)
426			if (node->params[i + 1].p != node->results[0]) {
427				pda = (RF_PhysDiskAddr_t *) node->params[i].p;
428				if (i == node->numParams - 4)
429					scol = RF_EO_MATRIX_DIM - 2;	/* the colume of
430									 * redundant E */
431				else
432					scol = rf_EUCol(layoutPtr, pda->raidAddress);
433				srcbuf = (char *) node->params[i + 1].p;
434				suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
435				destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr, suoffset - failedSUOffset);
436				rf_e_encToBuf(raidPtr, scol, srcbuf, fcol, destbuf, pda->numSector);
437			}
438		RF_ETIMER_STOP(timer);
439		RF_ETIMER_EVAL(timer);
440		tracerec->xor_us += RF_ETIMER_VAL_US(timer);
441	}
442	return (rf_GenericWakeupFunc(node, 0));	/* node execute successfully */
443}
444/**************************************************************************************
445 * This function is used in the case where one data and the parity have filed.
446 * (in EO_110_CreateWriteDAG )
447 **************************************************************************************/
448int
449rf_EO_DegradedWriteEFunc(RF_DagNode_t * node)
450{
451	rf_DegrESubroutine(node, node->results[0]);
452	rf_GenericWakeupFunc(node, 0);
453#if 1
454	return (0);		/* XXX Yet another one!! GO */
455#endif
456}
457
458
459
460/**************************************************************************************
461 *  		THE FUNCTION IS FOR DOUBLE DEGRADED READ AND WRITE CASES
462 **************************************************************************************/
463
464void
465rf_doubleEOdecode(
466    RF_Raid_t * raidPtr,
467    char **rrdbuf,
468    char **dest,
469    RF_RowCol_t * fcol,
470    char *pbuf,
471    char *ebuf)
472{
473	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout);
474	int     i, j, k, f1, f2, row;
475	int     rrdrow, erow, count = 0;
476	int     bytesPerSector = rf_RaidAddressToByte(raidPtr, 1);
477	int     numRowInEncMatix = (RF_EO_MATRIX_DIM) - 1;
478#if 0
479	int     pcol = (RF_EO_MATRIX_DIM) - 1;
480#endif
481	int     ecol = (RF_EO_MATRIX_DIM) - 2;
482	int     bytesPerEU = bytesPerSector / numRowInEncMatix;
483	int     numDataCol = layoutPtr->numDataCol;
484#if RF_EO_MATRIX_DIM > 17
485	int     shortsPerEU = bytesPerEU / sizeof(short);
486	short  *rrdbuf_current, *pbuf_current, *ebuf_current;
487	short  *dest_smaller, *dest_smaller_current, *dest_larger, *dest_larger_current;
488	short *temp;
489	short  *P;
490
491	RF_ASSERT(bytesPerEU % sizeof(short) == 0);
492	RF_Malloc(P, bytesPerEU, (short *));
493	RF_Malloc(temp, bytesPerEU, (short *));
494#elif RF_EO_MATRIX_DIM == 17
495	int     longsPerEU = bytesPerEU / sizeof(long);
496	long   *rrdbuf_current, *pbuf_current, *ebuf_current;
497	long   *dest_smaller, *dest_smaller_current, *dest_larger, *dest_larger_current;
498	long *temp;
499	long   *P;
500
501	RF_ASSERT(bytesPerEU % sizeof(long) == 0);
502	RF_Malloc(P, bytesPerEU, (long *));
503	RF_Malloc(temp, bytesPerEU, (long *));
504#endif
505	RF_ASSERT(*((long *) dest[0]) == 0);
506	RF_ASSERT(*((long *) dest[1]) == 0);
507	memset((char *) P, 0, bytesPerEU);
508	memset((char *) temp, 0, bytesPerEU);
509	RF_ASSERT(*P == 0);
510	/* calculate the 'P' parameter, which, not parity, is the Xor of all
511	 * elements in the last two column, ie. 'E' and 'parity' colume, see
512	 * the Ref. paper by Blaum, et al 1993  */
513	for (i = 0; i < numRowInEncMatix; i++)
514		for (k = 0; k < longsPerEU; k++) {
515#if RF_EO_MATRIX_DIM > 17
516			ebuf_current = ((short *) ebuf) + i * shortsPerEU + k;
517			pbuf_current = ((short *) pbuf) + i * shortsPerEU + k;
518#elif RF_EO_MATRIX_DIM == 17
519			ebuf_current = ((long *) ebuf) + i * longsPerEU + k;
520			pbuf_current = ((long *) pbuf) + i * longsPerEU + k;
521#endif
522			P[k] ^= *ebuf_current;
523			P[k] ^= *pbuf_current;
524		}
525	RF_ASSERT(fcol[0] != fcol[1]);
526	if (fcol[0] < fcol[1]) {
527#if RF_EO_MATRIX_DIM > 17
528		dest_smaller = (short *) (dest[0]);
529		dest_larger = (short *) (dest[1]);
530#elif RF_EO_MATRIX_DIM == 17
531		dest_smaller = (long *) (dest[0]);
532		dest_larger = (long *) (dest[1]);
533#endif
534		f1 = fcol[0];
535		f2 = fcol[1];
536	} else {
537#if RF_EO_MATRIX_DIM > 17
538		dest_smaller = (short *) (dest[1]);
539		dest_larger = (short *) (dest[0]);
540#elif RF_EO_MATRIX_DIM == 17
541		dest_smaller = (long *) (dest[1]);
542		dest_larger = (long *) (dest[0]);
543#endif
544		f1 = fcol[1];
545		f2 = fcol[0];
546	}
547	row = (RF_EO_MATRIX_DIM) - 1;
548	while ((row = rf_EO_Mod((row + f1 - f2), RF_EO_MATRIX_DIM)) != ((RF_EO_MATRIX_DIM) - 1)) {
549#if RF_EO_MATRIX_DIM > 17
550		dest_larger_current = dest_larger + row * shortsPerEU;
551		dest_smaller_current = dest_smaller + row * shortsPerEU;
552#elif RF_EO_MATRIX_DIM == 17
553		dest_larger_current = dest_larger + row * longsPerEU;
554		dest_smaller_current = dest_smaller + row * longsPerEU;
555#endif
556		/**    Do the diagonal recovery. Initially, temp[k] = (failed 1),
557		       which is the failed data in the colume which has smaller col index. **/
558		/* step 1:  ^(SUM of nonfailed in-diagonal A(rrdrow,0..m-3))         */
559		for (j = 0; j < numDataCol; j++) {
560			if (j == f1 || j == f2)
561				continue;
562			rrdrow = rf_EO_Mod((row + f2 - j), RF_EO_MATRIX_DIM);
563			if (rrdrow != (RF_EO_MATRIX_DIM) - 1) {
564#if RF_EO_MATRIX_DIM > 17
565				rrdbuf_current = (short *) (rrdbuf[j]) + rrdrow * shortsPerEU;
566				for (k = 0; k < shortsPerEU; k++)
567					temp[k] ^= *(rrdbuf_current + k);
568#elif RF_EO_MATRIX_DIM == 17
569				rrdbuf_current = (long *) (rrdbuf[j]) + rrdrow * longsPerEU;
570				for (k = 0; k < longsPerEU; k++)
571					temp[k] ^= *(rrdbuf_current + k);
572#endif
573			}
574		}
575		/* step 2:  ^E(erow,m-2), If erow is at the buttom row, don't
576		 * Xor into it  E(erow,m-2) = (principle diagonal) ^ (failed
577		 * 1) ^ (failed 2) ^ ( SUM of nonfailed in-diagonal
578		 * A(rrdrow,0..m-3) ) After this step, temp[k] = (principle
579		 * diagonal) ^ (failed 2)       */
580
581		erow = rf_EO_Mod((row + f2 - ecol), (RF_EO_MATRIX_DIM));
582		if (erow != (RF_EO_MATRIX_DIM) - 1) {
583#if RF_EO_MATRIX_DIM > 17
584			ebuf_current = (short *) ebuf + shortsPerEU * erow;
585			for (k = 0; k < shortsPerEU; k++)
586				temp[k] ^= *(ebuf_current + k);
587#elif RF_EO_MATRIX_DIM == 17
588			ebuf_current = (long *) ebuf + longsPerEU * erow;
589			for (k = 0; k < longsPerEU; k++)
590				temp[k] ^= *(ebuf_current + k);
591#endif
592		}
593		/* step 3: ^P to obtain the failed data (failed 2).  P can be
594		 * proved to be actually  (principle diagonal)  After this
595		 * step, temp[k] = (failed 2), the failed data to be recovered */
596#if RF_EO_MATRIX_DIM > 17
597		for (k = 0; k < shortsPerEU; k++)
598			temp[k] ^= P[k];
599		/* Put the data to the destination buffer                              */
600		for (k = 0; k < shortsPerEU; k++)
601			dest_larger_current[k] = temp[k];
602#elif RF_EO_MATRIX_DIM == 17
603		for (k = 0; k < longsPerEU; k++)
604			temp[k] ^= P[k];
605		/* Put the data to the destination buffer                              */
606		for (k = 0; k < longsPerEU; k++)
607			dest_larger_current[k] = temp[k];
608#endif
609
610		/**          THE FOLLOWING DO THE HORIZONTAL XOR                **/
611		/* step 1:  ^(SUM of A(row,0..m-3)), ie. all nonfailed data
612		 * columes    */
613		for (j = 0; j < numDataCol; j++) {
614			if (j == f1 || j == f2)
615				continue;
616#if RF_EO_MATRIX_DIM > 17
617			rrdbuf_current = (short *) (rrdbuf[j]) + row * shortsPerEU;
618			for (k = 0; k < shortsPerEU; k++)
619				temp[k] ^= *(rrdbuf_current + k);
620#elif RF_EO_MATRIX_DIM == 17
621			rrdbuf_current = (long *) (rrdbuf[j]) + row * longsPerEU;
622			for (k = 0; k < longsPerEU; k++)
623				temp[k] ^= *(rrdbuf_current + k);
624#endif
625		}
626		/* step 2: ^A(row,m-1) */
627		/* step 3: Put the data to the destination buffer                             	 */
628#if RF_EO_MATRIX_DIM > 17
629		pbuf_current = (short *) pbuf + shortsPerEU * row;
630		for (k = 0; k < shortsPerEU; k++)
631			temp[k] ^= *(pbuf_current + k);
632		for (k = 0; k < shortsPerEU; k++)
633			dest_smaller_current[k] = temp[k];
634#elif RF_EO_MATRIX_DIM == 17
635		pbuf_current = (long *) pbuf + longsPerEU * row;
636		for (k = 0; k < longsPerEU; k++)
637			temp[k] ^= *(pbuf_current + k);
638		for (k = 0; k < longsPerEU; k++)
639			dest_smaller_current[k] = temp[k];
640#endif
641		count++;
642	}
643	/* Check if all Encoding Unit in the data buffer have been decoded,
644	 * according EvenOdd theory, if "RF_EO_MATRIX_DIM" is a prime number,
645	 * this algorithm will covered all buffer 				 */
646	RF_ASSERT(count == numRowInEncMatix);
647	RF_Free((char *) P, bytesPerEU);
648	RF_Free((char *) temp, bytesPerEU);
649}
650
651
652/***************************************************************************************
653* 	This function is called by double degragded read
654* 	EO_200_CreateReadDAG
655*
656***************************************************************************************/
657int
658rf_EvenOddDoubleRecoveryFunc(node)
659	RF_DagNode_t *node;
660{
661	int     ndataParam = 0;
662	int     np = node->numParams;
663	RF_AccessStripeMap_t *asmap = (RF_AccessStripeMap_t *) node->params[np - 1].p;
664	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 2].p;
665	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout);
666	int     i, prm, sector, nresults = node->numResults;
667	RF_SectorCount_t secPerSU = layoutPtr->sectorsPerStripeUnit;
668	unsigned sosAddr;
669	int     two = 0, mallc_one = 0, mallc_two = 0;	/* flags to indicate if
670							 * memory is allocated */
671	int     bytesPerSector = rf_RaidAddressToByte(raidPtr, 1);
672	RF_PhysDiskAddr_t *ppda, *ppda2, *epda, *epda2, *pda, *pda0, *pda1,
673	        npda;
674	RF_RowCol_t fcol[2], fsuoff[2], fsuend[2], numDataCol = layoutPtr->numDataCol;
675	char  **buf, *ebuf, *pbuf, *dest[2];
676	long   *suoff = NULL, *suend = NULL, *prmToCol = NULL,
677	    psuoff = 0, esuoff = 0;
678	RF_SectorNum_t startSector, endSector;
679	RF_Etimer_t timer;
680	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
681
682	RF_ETIMER_START(timer);
683
684	/* Find out the number of parameters which are pdas for data
685	 * information */
686	for (i = 0; i <= np; i++)
687		if (((RF_PhysDiskAddr_t *) node->params[i].p)->type != RF_PDA_TYPE_DATA) {
688			ndataParam = i;
689			break;
690		}
691	RF_Malloc(buf, numDataCol * sizeof(char *), (char **));
692	if (ndataParam != 0) {
693		RF_Malloc(suoff, ndataParam * sizeof(long), (long *));
694		RF_Malloc(suend, ndataParam * sizeof(long), (long *));
695		RF_Malloc(prmToCol, ndataParam * sizeof(long), (long *));
696	}
697	if (asmap->failedPDAs[1] &&
698	    (asmap->failedPDAs[1]->numSector + asmap->failedPDAs[0]->numSector < secPerSU)) {
699		RF_ASSERT(0);	/* currently, no support for this situation */
700		ppda = node->params[np - 6].p;
701		ppda2 = node->params[np - 5].p;
702		RF_ASSERT(ppda2->type == RF_PDA_TYPE_PARITY);
703		epda = node->params[np - 4].p;
704		epda2 = node->params[np - 3].p;
705		RF_ASSERT(epda2->type == RF_PDA_TYPE_Q);
706		two = 1;
707	} else {
708		ppda = node->params[np - 4].p;
709		epda = node->params[np - 3].p;
710		psuoff = rf_StripeUnitOffset(layoutPtr, ppda->startSector);
711		esuoff = rf_StripeUnitOffset(layoutPtr, epda->startSector);
712		RF_ASSERT(psuoff == esuoff);
713	}
714	/*
715            the followings have three goals:
716            1. determine the startSector to begin decoding and endSector to end decoding.
717            2. determine the colume numbers of the two failed disks.
718            3. determine the offset and end offset of the access within each failed stripe unit.
719         */
720	if (nresults == 1) {
721		/* find the startSector to begin decoding */
722		pda = node->results[0];
723		memset(pda->bufPtr, 0, bytesPerSector * pda->numSector);
724		fsuoff[0] = rf_StripeUnitOffset(layoutPtr, pda->startSector);
725		fsuend[0] = fsuoff[0] + pda->numSector;
726		fsuoff[1] = 0;
727		fsuend[1] = 0;
728		startSector = fsuoff[0];
729		endSector = fsuend[0];
730
731		/* find out the column of failed disk being accessed */
732		fcol[0] = rf_EUCol(layoutPtr, pda->raidAddress);
733
734		/* find out the other failed colume not accessed */
735		sosAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, asmap->raidAddress);
736		for (i = 0; i < numDataCol; i++) {
737			npda.raidAddress = sosAddr + (i * secPerSU);
738			(raidPtr->Layout.map->MapSector) (raidPtr, npda.raidAddress, &(npda.col), &(npda.startSector), 0);
739			/* skip over dead disks */
740			if (RF_DEAD_DISK(raidPtr->Disks[npda.col].status))
741				if (i != fcol[0])
742					break;
743		}
744		RF_ASSERT(i < numDataCol);
745		fcol[1] = i;
746	} else {
747		RF_ASSERT(nresults == 2);
748		pda0 = node->results[0];
749		memset(pda0->bufPtr, 0, bytesPerSector * pda0->numSector);
750		pda1 = node->results[1];
751		memset(pda1->bufPtr, 0, bytesPerSector * pda1->numSector);
752		/* determine the failed colume numbers of the two failed
753		 * disks. */
754		fcol[0] = rf_EUCol(layoutPtr, pda0->raidAddress);
755		fcol[1] = rf_EUCol(layoutPtr, pda1->raidAddress);
756		/* determine the offset and end offset of the access within
757		 * each failed stripe unit. */
758		fsuoff[0] = rf_StripeUnitOffset(layoutPtr, pda0->startSector);
759		fsuend[0] = fsuoff[0] + pda0->numSector;
760		fsuoff[1] = rf_StripeUnitOffset(layoutPtr, pda1->startSector);
761		fsuend[1] = fsuoff[1] + pda1->numSector;
762		/* determine the startSector to begin decoding */
763		startSector = RF_MIN(pda0->startSector, pda1->startSector);
764		/* determine the endSector to end decoding */
765		endSector = RF_MAX(fsuend[0], fsuend[1]);
766	}
767	/*
768	      assign the beginning sector and the end sector for each parameter
769	      find out the corresponding colume # for each parameter
770        */
771	for (prm = 0; prm < ndataParam; prm++) {
772		pda = node->params[prm].p;
773		suoff[prm] = rf_StripeUnitOffset(layoutPtr, pda->startSector);
774		suend[prm] = suoff[prm] + pda->numSector;
775		prmToCol[prm] = rf_EUCol(layoutPtr, pda->raidAddress);
776	}
777	/* 'sector' is the sector for the current decoding algorithm. For each
778	 * sector in the failed SU, find out the corresponding parameters that
779	 * cover the current sector and that are needed for decoding of this
780	 * sector in failed SU. 2.  Find out if sector is in the shadow of any
781	 * accessed failed SU. If not, malloc a temporary space of a sector in
782	 * size. */
783	for (sector = startSector; sector < endSector; sector++) {
784		if (nresults == 2)
785			if (!(fsuoff[0] <= sector && sector < fsuend[0]) && !(fsuoff[1] <= sector && sector < fsuend[1]))
786				continue;
787		for (prm = 0; prm < ndataParam; prm++)
788			if (suoff[prm] <= sector && sector < suend[prm])
789				buf[(prmToCol[prm])] = ((RF_PhysDiskAddr_t *) node->params[prm].p)->bufPtr +
790				    rf_RaidAddressToByte(raidPtr, sector - suoff[prm]);
791		/* find out if sector is in the shadow of any accessed failed
792		 * SU. If yes, assign dest[0], dest[1] to point at suitable
793		 * position of the buffer corresponding to failed SUs. if no,
794		 * malloc a temporary space of a sector in size for
795		 * destination of decoding. */
796		RF_ASSERT(nresults == 1 || nresults == 2);
797		if (nresults == 1) {
798			dest[0] = ((RF_PhysDiskAddr_t *) node->results[0])->bufPtr + rf_RaidAddressToByte(raidPtr, sector - fsuoff[0]);
799			/* Always malloc temp buffer to dest[1]  */
800			RF_Malloc(dest[1], bytesPerSector, (char *));
801			memset(dest[1], 0, bytesPerSector);
802			mallc_two = 1;
803		} else {
804			if (fsuoff[0] <= sector && sector < fsuend[0])
805				dest[0] = ((RF_PhysDiskAddr_t *) node->results[0])->bufPtr + rf_RaidAddressToByte(raidPtr, sector - fsuoff[0]);
806			else {
807				RF_Malloc(dest[0], bytesPerSector, (char *));
808				memset(dest[0], 0, bytesPerSector);
809				mallc_one = 1;
810			}
811			if (fsuoff[1] <= sector && sector < fsuend[1])
812				dest[1] = ((RF_PhysDiskAddr_t *) node->results[1])->bufPtr + rf_RaidAddressToByte(raidPtr, sector - fsuoff[1]);
813			else {
814				RF_Malloc(dest[1], bytesPerSector, (char *));
815				memset(dest[1], 0, bytesPerSector);
816				mallc_two = 1;
817			}
818			RF_ASSERT(mallc_one == 0 || mallc_two == 0);
819		}
820		pbuf = ppda->bufPtr + rf_RaidAddressToByte(raidPtr, sector - psuoff);
821		ebuf = epda->bufPtr + rf_RaidAddressToByte(raidPtr, sector - esuoff);
822		/*
823	         * After finish finding all needed sectors, call doubleEOdecode function for decoding
824	         * one sector to destination.
825	         */
826		rf_doubleEOdecode(raidPtr, buf, dest, fcol, pbuf, ebuf);
827		/* free all allocated memory, and mark flag to indicate no
828		 * memory is being allocated */
829		if (mallc_one == 1)
830			RF_Free(dest[0], bytesPerSector);
831		if (mallc_two == 1)
832			RF_Free(dest[1], bytesPerSector);
833		mallc_one = mallc_two = 0;
834	}
835	RF_Free(buf, numDataCol * sizeof(char *));
836	if (ndataParam != 0) {
837		RF_Free(suoff, ndataParam * sizeof(long));
838		RF_Free(suend, ndataParam * sizeof(long));
839		RF_Free(prmToCol, ndataParam * sizeof(long));
840	}
841	RF_ETIMER_STOP(timer);
842	RF_ETIMER_EVAL(timer);
843	if (tracerec) {
844		tracerec->q_us += RF_ETIMER_VAL_US(timer);
845	}
846	rf_GenericWakeupFunc(node, 0);
847#if 1
848	return (0);		/* XXX is this even close!!?!?!!? GO */
849#endif
850}
851
852
853/* currently, only access of one of the two failed SU is allowed in this function.
854 * also, asmap->numStripeUnitsAccessed is limited to be one, the RaidFrame will break large access into
855 * many accesses of single stripe unit.
856 */
857
858int
859rf_EOWriteDoubleRecoveryFunc(node)
860	RF_DagNode_t *node;
861{
862	int     np = node->numParams;
863	RF_AccessStripeMap_t *asmap = (RF_AccessStripeMap_t *) node->params[np - 1].p;
864	RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 2].p;
865	RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & (raidPtr->Layout);
866	RF_SectorNum_t sector;
867	RF_RowCol_t col, scol;
868	int     prm, i, j;
869	RF_SectorCount_t secPerSU = layoutPtr->sectorsPerStripeUnit;
870	unsigned sosAddr;
871	unsigned bytesPerSector = rf_RaidAddressToByte(raidPtr, 1);
872	RF_int64 numbytes;
873	RF_SectorNum_t startSector, endSector;
874	RF_PhysDiskAddr_t *ppda, *epda, *pda, *fpda, npda;
875	RF_RowCol_t fcol[2], numDataCol = layoutPtr->numDataCol;
876	char  **buf;		/* buf[0], buf[1], buf[2], ...etc. point to
877				 * buffer storing data read from col0, col1,
878				 * col2 */
879	char   *ebuf, *pbuf, *dest[2], *olddata[2];
880	RF_Etimer_t timer;
881	RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
882
883	RF_ASSERT(asmap->numDataFailed == 1);	/* currently only support this
884						 * case, the other failed SU
885						 * is not being accessed */
886	RF_ETIMER_START(timer);
887	RF_Malloc(buf, numDataCol * sizeof(char *), (char **));
888
889	ppda = node->results[0];/* Instead of being buffers, node->results[0]
890				 * and [1] are Ppda and Epda  */
891	epda = node->results[1];
892	fpda = asmap->failedPDAs[0];
893
894	/* First, recovery the failed old SU using EvenOdd double decoding      */
895	/* determine the startSector and endSector for decoding */
896	startSector = rf_StripeUnitOffset(layoutPtr, fpda->startSector);
897	endSector = startSector + fpda->numSector;
898	/* Assign buf[col] pointers to point to each non-failed colume  and
899	 * initialize the pbuf and ebuf to point at the beginning of each
900	 * source buffers and destination buffers */
901	for (prm = 0; prm < numDataCol - 2; prm++) {
902		pda = (RF_PhysDiskAddr_t *) node->params[prm].p;
903		col = rf_EUCol(layoutPtr, pda->raidAddress);
904		buf[col] = pda->bufPtr;
905	}
906	/* pbuf and ebuf:  they will change values as double recovery decoding
907	 * goes on */
908	pbuf = ppda->bufPtr;
909	ebuf = epda->bufPtr;
910	/* find out the logical colume numbers in the encoding matrix of the
911	 * two failed columes */
912	fcol[0] = rf_EUCol(layoutPtr, fpda->raidAddress);
913
914	/* find out the other failed colume not accessed this time */
915	sosAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, asmap->raidAddress);
916	for (i = 0; i < numDataCol; i++) {
917		npda.raidAddress = sosAddr + (i * secPerSU);
918		(raidPtr->Layout.map->MapSector) (raidPtr, npda.raidAddress, &(npda.col), &(npda.startSector), 0);
919		/* skip over dead disks */
920		if (RF_DEAD_DISK(raidPtr->Disks[npda.col].status))
921			if (i != fcol[0])
922				break;
923	}
924	RF_ASSERT(i < numDataCol);
925	fcol[1] = i;
926	/* assign temporary space to put recovered failed SU */
927	numbytes = fpda->numSector * bytesPerSector;
928	RF_Malloc(olddata[0], numbytes, (char *));
929	RF_Malloc(olddata[1], numbytes, (char *));
930	dest[0] = olddata[0];
931	dest[1] = olddata[1];
932	memset(olddata[0], 0, numbytes);
933	memset(olddata[1], 0, numbytes);
934	/* Begin the recovery decoding, initially buf[j],  ebuf, pbuf, dest[j]
935	 * have already pointed at the beginning of each source buffers and
936	 * destination buffers */
937	for (sector = startSector, i = 0; sector < endSector; sector++, i++) {
938		rf_doubleEOdecode(raidPtr, buf, dest, fcol, pbuf, ebuf);
939		for (j = 0; j < numDataCol; j++)
940			if ((j != fcol[0]) && (j != fcol[1]))
941				buf[j] += bytesPerSector;
942		dest[0] += bytesPerSector;
943		dest[1] += bytesPerSector;
944		ebuf += bytesPerSector;
945		pbuf += bytesPerSector;
946	}
947	/* after recovery, the buffer pointed by olddata[0] is the old failed
948	 * data. With new writing data and this old data, use small write to
949	 * calculate the new redundant informations */
950	/* node->params[ 0, ... PDAPerDisk * (numDataCol - 2)-1 ] are Pdas of
951	 * Rrd; params[ PDAPerDisk*(numDataCol - 2), ... PDAPerDisk*numDataCol
952	 * -1 ] are Pdas of Rp, ( Rp2 ), Re, ( Re2 ) ; params[
953	 * PDAPerDisk*numDataCol, ... PDAPerDisk*numDataCol
954	 * +asmap->numStripeUnitsAccessed -asmap->numDataFailed-1] are Pdas of
955	 * wudNodes; For current implementation, we assume the simplest case:
956	 * asmap->numStripeUnitsAccessed == 1 and asmap->numDataFailed == 1
957	 * ie. PDAPerDisk = 1 then node->params[numDataCol] must be the new
958	 * data to be writen to the failed disk. We first bxor the new data
959	 * into the old recovered data, then do the same things as small
960	 * write. */
961
962	rf_bxor(((RF_PhysDiskAddr_t *) node->params[numDataCol].p)->bufPtr, olddata[0], numbytes);
963	/* do new 'E' calculation  */
964	/* find out the corresponding colume in encoding matrix for write
965	 * colume to be encoded into redundant disk 'E' */
966	scol = rf_EUCol(layoutPtr, fpda->raidAddress);
967	/* olddata[0] now is source buffer pointer; epda->bufPtr is the dest
968	 * buffer pointer               */
969	rf_e_encToBuf(raidPtr, scol, olddata[0], RF_EO_MATRIX_DIM - 2, epda->bufPtr, fpda->numSector);
970
971	/* do new 'P' calculation  */
972	rf_bxor(olddata[0], ppda->bufPtr, numbytes);
973	/* Free the allocated buffer  */
974	RF_Free(olddata[0], numbytes);
975	RF_Free(olddata[1], numbytes);
976	RF_Free(buf, numDataCol * sizeof(char *));
977
978	RF_ETIMER_STOP(timer);
979	RF_ETIMER_EVAL(timer);
980	if (tracerec) {
981		tracerec->q_us += RF_ETIMER_VAL_US(timer);
982	}
983	rf_GenericWakeupFunc(node, 0);
984	return (0);
985}
986#endif				/* RF_INCLUDE_EVENODD > 0 */
987