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