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