xref: /netbsd-src/sys/dev/raidframe/rf_evenodd.c (revision 3b01aba77a7a698587faaae455bbfe740923c1f5)
1 /*	$NetBSD: rf_evenodd.c,v 1.5 2001/07/18 06:45:33 thorpej Exp $	*/
2 /*
3  * Copyright (c) 1995 Carnegie-Mellon University.
4  * All rights reserved.
5  *
6  * Author: Chang-Ming 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  *
31  * rf_evenodd.c -- implements EVENODD array architecture
32  *
33  ****************************************************************************************/
34 
35 #include "rf_archs.h"
36 
37 #if RF_INCLUDE_EVENODD > 0
38 
39 #include "rf_types.h"
40 #include "rf_raid.h"
41 #include "rf_dag.h"
42 #include "rf_dagffrd.h"
43 #include "rf_dagffwr.h"
44 #include "rf_dagdegrd.h"
45 #include "rf_dagdegwr.h"
46 #include "rf_dagutils.h"
47 #include "rf_dagfuncs.h"
48 #include "rf_etimer.h"
49 #include "rf_general.h"
50 #include "rf_evenodd.h"
51 #include "rf_configure.h"
52 #include "rf_parityscan.h"
53 #include "rf_utils.h"
54 #include "rf_map.h"
55 #include "rf_pq.h"
56 #include "rf_mcpair.h"
57 #include "rf_evenodd.h"
58 #include "rf_evenodd_dagfuncs.h"
59 #include "rf_evenodd_dags.h"
60 #include "rf_engine.h"
61 
62 typedef struct RF_EvenOddConfigInfo_s {
63 	RF_RowCol_t **stripeIdentifier;	/* filled in at config time & used by
64 					 * IdentifyStripe */
65 }       RF_EvenOddConfigInfo_t;
66 
67 int
68 rf_ConfigureEvenOdd(listp, raidPtr, cfgPtr)
69 	RF_ShutdownList_t **listp;
70 	RF_Raid_t *raidPtr;
71 	RF_Config_t *cfgPtr;
72 {
73 	RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
74 	RF_EvenOddConfigInfo_t *info;
75 	RF_RowCol_t i, j, startdisk;
76 
77 	RF_MallocAndAdd(info, sizeof(RF_EvenOddConfigInfo_t), (RF_EvenOddConfigInfo_t *), raidPtr->cleanupList);
78 	layoutPtr->layoutSpecificInfo = (void *) info;
79 
80 	RF_ASSERT(raidPtr->numRow == 1);
81 
82 	info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, raidPtr->numCol, raidPtr->cleanupList);
83 	startdisk = 0;
84 	for (i = 0; i < raidPtr->numCol; i++) {
85 		for (j = 0; j < raidPtr->numCol; j++) {
86 			info->stripeIdentifier[i][j] = (startdisk + j) % raidPtr->numCol;
87 		}
88 		if ((startdisk -= 2) < 0)
89 			startdisk += raidPtr->numCol;
90 	}
91 
92 	/* fill in the remaining layout parameters */
93 	layoutPtr->numStripe = layoutPtr->stripeUnitsPerDisk;
94 	layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
95 	layoutPtr->numDataCol = raidPtr->numCol - 2;	/* ORIG:
96 							 * layoutPtr->numDataCol
97 							 * = raidPtr->numCol-1;  */
98 #if RF_EO_MATRIX_DIM > 17
99 	if (raidPtr->numCol <= 17) {
100 		printf("Number of stripe units in a parity stripe is smaller than 17. Please\n");
101 		printf("define the macro RF_EO_MATRIX_DIM in file rf_evenodd_dagfuncs.h to \n");
102 		printf("be 17 to increase performance. \n");
103 		return (EINVAL);
104 	}
105 #elif RF_EO_MATRIX_DIM == 17
106 	if (raidPtr->numCol > 17) {
107 		printf("Number of stripe units in a parity stripe is bigger than 17. Please\n");
108 		printf("define the macro RF_EO_MATRIX_DIM in file rf_evenodd_dagfuncs.h to \n");
109 		printf("be 257 for encoding and decoding functions to work. \n");
110 		return (EINVAL);
111 	}
112 #endif
113 	layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
114 	layoutPtr->numParityCol = 2;
115 	layoutPtr->dataStripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk;
116 	raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
117 
118 	raidPtr->totalSectors = layoutPtr->stripeUnitsPerDisk * layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
119 
120 	return (0);
121 }
122 
123 int
124 rf_GetDefaultNumFloatingReconBuffersEvenOdd(RF_Raid_t * raidPtr)
125 {
126 	return (20);
127 }
128 
129 RF_HeadSepLimit_t
130 rf_GetDefaultHeadSepLimitEvenOdd(RF_Raid_t * raidPtr)
131 {
132 	return (10);
133 }
134 
135 void
136 rf_IdentifyStripeEvenOdd(
137     RF_Raid_t * raidPtr,
138     RF_RaidAddr_t addr,
139     RF_RowCol_t ** diskids,
140     RF_RowCol_t * outRow)
141 {
142 	RF_StripeNum_t stripeID = rf_RaidAddressToStripeID(&raidPtr->Layout, addr);
143 	RF_EvenOddConfigInfo_t *info = (RF_EvenOddConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
144 
145 	*outRow = 0;
146 	*diskids = info->stripeIdentifier[stripeID % raidPtr->numCol];
147 }
148 /* The layout of stripe unit on the disks are:      c0 c1 c2 c3 c4
149 
150  						     0  1  2  E  P
151 						     5  E  P  3  4
152 						     P  6  7  8  E
153 	 					    10 11  E  P  9
154 						     E  P 12 13 14
155 						     ....
156 
157   We use the MapSectorRAID5 to map data information because the routine can be shown to map exactly
158   the layout of data stripe unit as shown above although we have 2 redundant information now.
159   But for E and P, we use rf_MapEEvenOdd and rf_MapParityEvenOdd which are different method from raid-5.
160 */
161 
162 
163 void
164 rf_MapParityEvenOdd(
165     RF_Raid_t * raidPtr,
166     RF_RaidAddr_t raidSector,
167     RF_RowCol_t * row,
168     RF_RowCol_t * col,
169     RF_SectorNum_t * diskSector,
170     int remap)
171 {
172 	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
173 	RF_StripeNum_t endSUIDofthisStrip = (SUID / raidPtr->Layout.numDataCol + 1) * raidPtr->Layout.numDataCol - 1;
174 
175 	*row = 0;
176 	*col = (endSUIDofthisStrip + 2) % raidPtr->numCol;
177 	*diskSector = (SUID / (raidPtr->Layout.numDataCol)) * raidPtr->Layout.sectorsPerStripeUnit +
178 	    (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
179 }
180 
181 void
182 rf_MapEEvenOdd(
183     RF_Raid_t * raidPtr,
184     RF_RaidAddr_t raidSector,
185     RF_RowCol_t * row,
186     RF_RowCol_t * col,
187     RF_SectorNum_t * diskSector,
188     int remap)
189 {
190 	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
191 	RF_StripeNum_t endSUIDofthisStrip = (SUID / raidPtr->Layout.numDataCol + 1) * raidPtr->Layout.numDataCol - 1;
192 
193 	*row = 0;
194 	*col = (endSUIDofthisStrip + 1) % raidPtr->numCol;
195 	*diskSector = (SUID / (raidPtr->Layout.numDataCol)) * raidPtr->Layout.sectorsPerStripeUnit +
196 	    (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
197 }
198 
199 void
200 rf_EODagSelect(
201     RF_Raid_t * raidPtr,
202     RF_IoType_t type,
203     RF_AccessStripeMap_t * asmap,
204     RF_VoidFuncPtr * createFunc)
205 {
206 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
207 	unsigned ndfail = asmap->numDataFailed;
208 	unsigned npfail = asmap->numParityFailed + asmap->numQFailed;
209 	unsigned ntfail = npfail + ndfail;
210 
211 	RF_ASSERT(RF_IO_IS_R_OR_W(type));
212 	if (ntfail > 2) {
213 		RF_ERRORMSG("more than two disks failed in a single group!  Aborting I/O operation.\n");
214 		 /* *infoFunc = */ *createFunc = NULL;
215 		return;
216 	}
217 	/* ok, we can do this I/O */
218 	if (type == RF_IO_TYPE_READ) {
219 		switch (ndfail) {
220 		case 0:
221 			/* fault free read */
222 			*createFunc = (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG;	/* same as raid 5 */
223 			break;
224 		case 1:
225 			/* lost a single data unit */
226 			/* two cases: (1) parity is not lost. do a normal raid
227 			 * 5 reconstruct read. (2) parity is lost. do a
228 			 * reconstruct read using "e". */
229 			if (ntfail == 2) {	/* also lost redundancy */
230 				if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY)
231 					*createFunc = (RF_VoidFuncPtr) rf_EO_110_CreateReadDAG;
232 				else
233 					*createFunc = (RF_VoidFuncPtr) rf_EO_101_CreateReadDAG;
234 			} else {
235 				/* P and E are ok. But is there a failure in
236 				 * some unaccessed data unit? */
237 				if (rf_NumFailedDataUnitsInStripe(raidPtr, asmap) == 2)
238 					*createFunc = (RF_VoidFuncPtr) rf_EO_200_CreateReadDAG;
239 				else
240 					*createFunc = (RF_VoidFuncPtr) rf_EO_100_CreateReadDAG;
241 			}
242 			break;
243 		case 2:
244 			/* *createFunc = rf_EO_200_CreateReadDAG; */
245 			*createFunc = NULL;
246 			break;
247 		}
248 		return;
249 	}
250 	/* a write */
251 	switch (ntfail) {
252 	case 0:		/* fault free */
253 		if (rf_suppressLocksAndLargeWrites ||
254 		    (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) && (layoutPtr->numDataCol != 1)) ||
255 			(asmap->parityInfo->next != NULL) || (asmap->qInfo->next != NULL) || rf_CheckStripeForFailures(raidPtr, asmap))) {
256 
257 			*createFunc = (RF_VoidFuncPtr) rf_EOCreateSmallWriteDAG;
258 		} else {
259 			*createFunc = (RF_VoidFuncPtr) rf_EOCreateLargeWriteDAG;
260 		}
261 		break;
262 
263 	case 1:		/* single disk fault */
264 		if (npfail == 1) {
265 			RF_ASSERT((asmap->failedPDAs[0]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q));
266 			if (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q) {	/* q died, treat like
267 										 * normal mode raid5
268 										 * write. */
269 				if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1))
270 				    || (asmap->parityInfo->next != NULL) || rf_NumFailedDataUnitsInStripe(raidPtr, asmap))
271 					*createFunc = (RF_VoidFuncPtr) rf_EO_001_CreateSmallWriteDAG;
272 				else
273 					*createFunc = (RF_VoidFuncPtr) rf_EO_001_CreateLargeWriteDAG;
274 			} else {/* parity died, small write only updating Q */
275 				if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1))
276 				    || (asmap->qInfo->next != NULL) || rf_NumFailedDataUnitsInStripe(raidPtr, asmap))
277 					*createFunc = (RF_VoidFuncPtr) rf_EO_010_CreateSmallWriteDAG;
278 				else
279 					*createFunc = (RF_VoidFuncPtr) rf_EO_010_CreateLargeWriteDAG;
280 			}
281 		} else {	/* data missing. Do a P reconstruct write if
282 				 * only a single data unit is lost in the
283 				 * stripe, otherwise a reconstruct write which
284 				 * employnig both P and E units. */
285 			if (rf_NumFailedDataUnitsInStripe(raidPtr, asmap) == 2) {
286 				if (asmap->numStripeUnitsAccessed == 1)
287 					*createFunc = (RF_VoidFuncPtr) rf_EO_200_CreateWriteDAG;
288 				else
289 					*createFunc = NULL;	/* No direct support for
290 								 * this case now, like
291 								 * that in Raid-5  */
292 			} else {
293 				if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
294 					*createFunc = NULL;	/* No direct support for
295 								 * this case now, like
296 								 * that in Raid-5  */
297 				else
298 					*createFunc = (RF_VoidFuncPtr) rf_EO_100_CreateWriteDAG;
299 			}
300 		}
301 		break;
302 
303 	case 2:		/* two disk faults */
304 		switch (npfail) {
305 		case 2:	/* both p and q dead */
306 			*createFunc = (RF_VoidFuncPtr) rf_EO_011_CreateWriteDAG;
307 			break;
308 		case 1:	/* either p or q and dead data */
309 			RF_ASSERT(asmap->failedPDAs[0]->type == RF_PDA_TYPE_DATA);
310 			RF_ASSERT((asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q));
311 			if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q) {
312 				if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
313 					*createFunc = NULL;	/* In both PQ and
314 								 * EvenOdd, no direct
315 								 * support for this case
316 								 * now, like that in
317 								 * Raid-5  */
318 				else
319 					*createFunc = (RF_VoidFuncPtr) rf_EO_101_CreateWriteDAG;
320 			} else {
321 				if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
322 					*createFunc = NULL;	/* No direct support for
323 								 * this case, like that
324 								 * in Raid-5  */
325 				else
326 					*createFunc = (RF_VoidFuncPtr) rf_EO_110_CreateWriteDAG;
327 			}
328 			break;
329 		case 0:	/* double data loss */
330 			/* if(asmap->failedPDAs[0]->numSector +
331 			 * asmap->failedPDAs[1]->numSector == 2 *
332 			 * layoutPtr->sectorsPerStripeUnit ) createFunc =
333 			 * rf_EOCreateLargeWriteDAG; else    							 */
334 			*createFunc = NULL;	/* currently, in Evenodd, No
335 						 * support for simultaneous
336 						 * access of both failed SUs */
337 			break;
338 		}
339 		break;
340 
341 	default:		/* more than 2 disk faults */
342 		*createFunc = NULL;
343 		RF_PANIC();
344 	}
345 	return;
346 }
347 
348 
349 int
350 rf_VerifyParityEvenOdd(raidPtr, raidAddr, parityPDA, correct_it, flags)
351 	RF_Raid_t *raidPtr;
352 	RF_RaidAddr_t raidAddr;
353 	RF_PhysDiskAddr_t *parityPDA;
354 	int     correct_it;
355 	RF_RaidAccessFlags_t flags;
356 {
357 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
358 	RF_RaidAddr_t startAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, raidAddr);
359 	RF_SectorCount_t numsector = parityPDA->numSector;
360 	int     numbytes = rf_RaidAddressToByte(raidPtr, numsector);
361 	int     bytesPerStripe = numbytes * layoutPtr->numDataCol;
362 	RF_DagHeader_t *rd_dag_h, *wr_dag_h;	/* read, write dag */
363 	RF_DagNode_t *blockNode, *unblockNode, *wrBlock, *wrUnblock;
364 	RF_AccessStripeMapHeader_t *asm_h;
365 	RF_AccessStripeMap_t *asmap;
366 	RF_AllocListElem_t *alloclist;
367 	RF_PhysDiskAddr_t *pda;
368 	char   *pbuf, *buf, *end_p, *p;
369 	char   *redundantbuf2;
370 	int     redundantTwoErr = 0, redundantOneErr = 0;
371 	int     parity_cant_correct = RF_FALSE, red2_cant_correct = RF_FALSE,
372 	        parity_corrected = RF_FALSE, red2_corrected = RF_FALSE;
373 	int     i, retcode;
374 	RF_ReconUnitNum_t which_ru;
375 	RF_StripeNum_t psID = rf_RaidAddressToParityStripeID(layoutPtr, raidAddr, &which_ru);
376 	int     stripeWidth = layoutPtr->numDataCol + layoutPtr->numParityCol;
377 	RF_AccTraceEntry_t tracerec;
378 	RF_MCPair_t *mcpair;
379 
380 	retcode = RF_PARITY_OKAY;
381 
382 	mcpair = rf_AllocMCPair();
383 	rf_MakeAllocList(alloclist);
384 	RF_MallocAndAdd(buf, numbytes * (layoutPtr->numDataCol + layoutPtr->numParityCol), (char *), alloclist);
385 	RF_CallocAndAdd(pbuf, 1, numbytes, (char *), alloclist);	/* use calloc to make
386 									 * sure buffer is zeroed */
387 	end_p = buf + bytesPerStripe;
388 	RF_CallocAndAdd(redundantbuf2, 1, numbytes, (char *), alloclist);	/* use calloc to make
389 										 * sure buffer is zeroed */
390 
391 	rd_dag_h = rf_MakeSimpleDAG(raidPtr, stripeWidth, numbytes, buf, rf_DiskReadFunc, rf_DiskReadUndoFunc,
392 	    "Rod", alloclist, flags, RF_IO_NORMAL_PRIORITY);
393 	blockNode = rd_dag_h->succedents[0];
394 	unblockNode = blockNode->succedents[0]->succedents[0];
395 
396 	/* map the stripe and fill in the PDAs in the dag */
397 	asm_h = rf_MapAccess(raidPtr, startAddr, layoutPtr->dataSectorsPerStripe, buf, RF_DONT_REMAP);
398 	asmap = asm_h->stripeMap;
399 
400 	for (pda = asmap->physInfo, i = 0; i < layoutPtr->numDataCol; i++, pda = pda->next) {
401 		RF_ASSERT(pda);
402 		rf_RangeRestrictPDA(raidPtr, parityPDA, pda, 0, 1);
403 		RF_ASSERT(pda->numSector != 0);
404 		if (rf_TryToRedirectPDA(raidPtr, pda, 0))
405 			goto out;	/* no way to verify parity if disk is
406 					 * dead.  return w/ good status */
407 		blockNode->succedents[i]->params[0].p = pda;
408 		blockNode->succedents[i]->params[2].v = psID;
409 		blockNode->succedents[i]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
410 	}
411 
412 	RF_ASSERT(!asmap->parityInfo->next);
413 	rf_RangeRestrictPDA(raidPtr, parityPDA, asmap->parityInfo, 0, 1);
414 	RF_ASSERT(asmap->parityInfo->numSector != 0);
415 	if (rf_TryToRedirectPDA(raidPtr, asmap->parityInfo, 1))
416 		goto out;
417 	blockNode->succedents[layoutPtr->numDataCol]->params[0].p = asmap->parityInfo;
418 
419 	RF_ASSERT(!asmap->qInfo->next);
420 	rf_RangeRestrictPDA(raidPtr, parityPDA, asmap->qInfo, 0, 1);
421 	RF_ASSERT(asmap->qInfo->numSector != 0);
422 	if (rf_TryToRedirectPDA(raidPtr, asmap->qInfo, 1))
423 		goto out;
424 	/* if disk is dead, b/c no reconstruction is implemented right now,
425 	 * the function "rf_TryToRedirectPDA" always return one, which cause
426 	 * go to out and return w/ good status   */
427 	blockNode->succedents[layoutPtr->numDataCol + 1]->params[0].p = asmap->qInfo;
428 
429 	/* fire off the DAG */
430 	memset((char *) &tracerec, 0, sizeof(tracerec));
431 	rd_dag_h->tracerec = &tracerec;
432 
433 	if (rf_verifyParityDebug) {
434 		printf("Parity verify read dag:\n");
435 		rf_PrintDAGList(rd_dag_h);
436 	}
437 	RF_LOCK_MUTEX(mcpair->mutex);
438 	mcpair->flag = 0;
439 	rf_DispatchDAG(rd_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc,
440 	    (void *) mcpair);
441 	while (!mcpair->flag)
442 		RF_WAIT_COND(mcpair->cond, mcpair->mutex);
443 	RF_UNLOCK_MUTEX(mcpair->mutex);
444 	if (rd_dag_h->status != rf_enable) {
445 		RF_ERRORMSG("Unable to verify parity:  can't read the stripe\n");
446 		retcode = RF_PARITY_COULD_NOT_VERIFY;
447 		goto out;
448 	}
449 	for (p = buf, i = 0; p < end_p; p += numbytes, i++) {
450 		rf_e_encToBuf(raidPtr, i, p, RF_EO_MATRIX_DIM - 2, redundantbuf2, numsector);
451 		/* the corresponding columes in EvenOdd encoding Matrix for
452 		 * these p pointers which point to the databuffer in a full
453 		 * stripe are sequentially from 0 to layoutPtr->numDataCol-1 */
454 		rf_bxor(p, pbuf, numbytes, NULL);
455 	}
456 	RF_ASSERT(i == layoutPtr->numDataCol);
457 
458 	for (i = 0; i < numbytes; i++) {
459 		if (pbuf[i] != buf[bytesPerStripe + i]) {
460 			if (!correct_it) {
461 				RF_ERRORMSG3("Parity verify error: byte %d of parity is 0x%x should be 0x%x\n",
462 				    i, (u_char) buf[bytesPerStripe + i], (u_char) pbuf[i]);
463 			}
464 		}
465 		redundantOneErr = 1;
466 		break;
467 	}
468 
469 	for (i = 0; i < numbytes; i++) {
470 		if (redundantbuf2[i] != buf[bytesPerStripe + numbytes + i]) {
471 			if (!correct_it) {
472 				RF_ERRORMSG3("Parity verify error: byte %d of second redundant information is 0x%x should be 0x%x\n",
473 				    i, (u_char) buf[bytesPerStripe + numbytes + i], (u_char) redundantbuf2[i]);
474 			}
475 			redundantTwoErr = 1;
476 			break;
477 		}
478 	}
479 	if (redundantOneErr || redundantTwoErr)
480 		retcode = RF_PARITY_BAD;
481 
482 	/* correct the first redundant disk, ie parity if it is error    */
483 	if (redundantOneErr && correct_it) {
484 		wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, pbuf, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
485 		    "Wnp", alloclist, flags, RF_IO_NORMAL_PRIORITY);
486 		wrBlock = wr_dag_h->succedents[0];
487 		wrUnblock = wrBlock->succedents[0]->succedents[0];
488 		wrBlock->succedents[0]->params[0].p = asmap->parityInfo;
489 		wrBlock->succedents[0]->params[2].v = psID;
490 		wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
491 		memset((char *) &tracerec, 0, sizeof(tracerec));
492 		wr_dag_h->tracerec = &tracerec;
493 		if (rf_verifyParityDebug) {
494 			printf("Parity verify write dag:\n");
495 			rf_PrintDAGList(wr_dag_h);
496 		}
497 		RF_LOCK_MUTEX(mcpair->mutex);
498 		mcpair->flag = 0;
499 		rf_DispatchDAG(wr_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc,
500 		    (void *) mcpair);
501 		while (!mcpair->flag)
502 			RF_WAIT_COND(mcpair->cond, mcpair->mutex);
503 		RF_UNLOCK_MUTEX(mcpair->mutex);
504 		if (wr_dag_h->status != rf_enable) {
505 			RF_ERRORMSG("Unable to correct parity in VerifyParity:  can't write the stripe\n");
506 			parity_cant_correct = RF_TRUE;
507 		} else {
508 			parity_corrected = RF_TRUE;
509 		}
510 		rf_FreeDAG(wr_dag_h);
511 	}
512 	if (redundantTwoErr && correct_it) {
513 		wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, redundantbuf2, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
514 		    "Wnred2", alloclist, flags, RF_IO_NORMAL_PRIORITY);
515 		wrBlock = wr_dag_h->succedents[0];
516 		wrUnblock = wrBlock->succedents[0]->succedents[0];
517 		wrBlock->succedents[0]->params[0].p = asmap->qInfo;
518 		wrBlock->succedents[0]->params[2].v = psID;
519 		wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
520 		memset((char *) &tracerec, 0, sizeof(tracerec));
521 		wr_dag_h->tracerec = &tracerec;
522 		if (rf_verifyParityDebug) {
523 			printf("Dag of write new second redundant information in parity verify :\n");
524 			rf_PrintDAGList(wr_dag_h);
525 		}
526 		RF_LOCK_MUTEX(mcpair->mutex);
527 		mcpair->flag = 0;
528 		rf_DispatchDAG(wr_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc,
529 		    (void *) mcpair);
530 		while (!mcpair->flag)
531 			RF_WAIT_COND(mcpair->cond, mcpair->mutex);
532 		RF_UNLOCK_MUTEX(mcpair->mutex);
533 		if (wr_dag_h->status != rf_enable) {
534 			RF_ERRORMSG("Unable to correct second redundant information in VerifyParity:  can't write the stripe\n");
535 			red2_cant_correct = RF_TRUE;
536 		} else {
537 			red2_corrected = RF_TRUE;
538 		}
539 		rf_FreeDAG(wr_dag_h);
540 	}
541 	if ((redundantOneErr && parity_cant_correct) ||
542 	    (redundantTwoErr && red2_cant_correct))
543 		retcode = RF_PARITY_COULD_NOT_CORRECT;
544 	if ((retcode = RF_PARITY_BAD) && parity_corrected && red2_corrected)
545 		retcode = RF_PARITY_CORRECTED;
546 
547 
548 out:
549 	rf_FreeAccessStripeMap(asm_h);
550 	rf_FreeAllocList(alloclist);
551 	rf_FreeDAG(rd_dag_h);
552 	rf_FreeMCPair(mcpair);
553 	return (retcode);
554 }
555 #endif				/* RF_INCLUDE_EVENODD > 0 */
556