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