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