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