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