Home | History | Annotate | Line # | Download | only in raidframe
      1 /*	$NetBSD: rf_evenodd.c,v 1.24 2025/06/27 21:36:22 andvar 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 (at) 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.24 2025/06/27 21:36:22 andvar 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_dagfuncs.h"
     61 #include "rf_evenodd_dags.h"
     62 #include "rf_engine.h"
     63 
     64 typedef struct RF_EvenOddConfigInfo_s {
     65 	RF_RowCol_t **stripeIdentifier;	/* filled in at config time & used by
     66 					 * IdentifyStripe */
     67 }       RF_EvenOddConfigInfo_t;
     68 
     69 int
     70 rf_ConfigureEvenOdd(RF_ShutdownList_t **listp, 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 	info = RF_MallocAndAdd(sizeof(*info), raidPtr->cleanupList);
     78 	layoutPtr->layoutSpecificInfo = (void *) info;
     79 
     80 	info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, raidPtr->numCol, raidPtr->cleanupList);
     81 	startdisk = 0;
     82 	for (i = 0; i < raidPtr->numCol; i++) {
     83 		for (j = 0; j < raidPtr->numCol; j++) {
     84 			info->stripeIdentifier[i][j] = (startdisk + j) % raidPtr->numCol;
     85 		}
     86 		if ((startdisk -= 2) < 0)
     87 			startdisk += raidPtr->numCol;
     88 	}
     89 
     90 	/* fill in the remaining layout parameters */
     91 	layoutPtr->numStripe = layoutPtr->stripeUnitsPerDisk;
     92 	layoutPtr->numDataCol = raidPtr->numCol - 2;	/* ORIG:
     93 							 * layoutPtr->numDataCol
     94 							 * = raidPtr->numCol-1;  */
     95 #if RF_EO_MATRIX_DIM > 17
     96 	if (raidPtr->numCol <= 17) {
     97 		printf("Number of stripe units in a parity stripe is smaller than 17. Please\n");
     98 		printf("define the macro RF_EO_MATRIX_DIM in file rf_evenodd_dagfuncs.h to \n");
     99 		printf("be 17 to increase performance. \n");
    100 		return (EINVAL);
    101 	}
    102 #elif RF_EO_MATRIX_DIM == 17
    103 	if (raidPtr->numCol > 17) {
    104 		printf("Number of stripe units in a parity stripe is bigger than 17. Please\n");
    105 		printf("define the macro RF_EO_MATRIX_DIM in file rf_evenodd_dagfuncs.h to \n");
    106 		printf("be 257 for encoding and decoding functions to work. \n");
    107 		return (EINVAL);
    108 	}
    109 #endif
    110 	layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
    111 	layoutPtr->numParityCol = 2;
    112 	layoutPtr->dataStripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk;
    113 	raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
    114 
    115 	raidPtr->totalSectors = layoutPtr->stripeUnitsPerDisk * layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
    116 
    117 	return (0);
    118 }
    119 
    120 int
    121 rf_GetDefaultNumFloatingReconBuffersEvenOdd(RF_Raid_t *raidPtr)
    122 {
    123 	return (20);
    124 }
    125 
    126 RF_HeadSepLimit_t
    127 rf_GetDefaultHeadSepLimitEvenOdd(RF_Raid_t *raidPtr)
    128 {
    129 	return (10);
    130 }
    131 
    132 void
    133 rf_IdentifyStripeEvenOdd(RF_Raid_t *raidPtr, RF_RaidAddr_t addr,
    134 			 RF_RowCol_t **diskids)
    135 {
    136 	RF_StripeNum_t stripeID = rf_RaidAddressToStripeID(&raidPtr->Layout, addr);
    137 	RF_EvenOddConfigInfo_t *info = (RF_EvenOddConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
    138 
    139 	*diskids = info->stripeIdentifier[stripeID % raidPtr->numCol];
    140 }
    141 /* The layout of stripe unit on the disks are:      c0 c1 c2 c3 c4
    142 
    143  						     0  1  2  E  P
    144 						     5  E  P  3  4
    145 						     P  6  7  8  E
    146 	 					    10 11  E  P  9
    147 						     E  P 12 13 14
    148 						     ....
    149 
    150   We use the MapSectorRAID5 to map data information because the routine can be shown to map exactly
    151   the layout of data stripe unit as shown above although we have 2 redundant information now.
    152   But for E and P, we use rf_MapEEvenOdd and rf_MapParityEvenOdd which are different method from raid-5.
    153 */
    154 
    155 
    156 void
    157 rf_MapParityEvenOdd(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
    158 		    RF_RowCol_t *col,
    159 		    RF_SectorNum_t *diskSector, int remap)
    160 {
    161 	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
    162 	RF_StripeNum_t endSUIDofthisStrip = (SUID / raidPtr->Layout.numDataCol + 1) * raidPtr->Layout.numDataCol - 1;
    163 
    164 	*col = (endSUIDofthisStrip + 2) % raidPtr->numCol;
    165 	*diskSector = (SUID / (raidPtr->Layout.numDataCol)) * raidPtr->Layout.sectorsPerStripeUnit +
    166 	    (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
    167 }
    168 
    169 void
    170 rf_MapEEvenOdd(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
    171 	       RF_RowCol_t *col, 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 	*col = (endSUIDofthisStrip + 1) % raidPtr->numCol;
    178 	*diskSector = (SUID / (raidPtr->Layout.numDataCol)) * raidPtr->Layout.sectorsPerStripeUnit +
    179 	    (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
    180 }
    181 
    182 void
    183 rf_EODagSelect(RF_Raid_t *raidPtr, RF_IoType_t type,
    184 	       RF_AccessStripeMap_t *asmap, RF_VoidFuncPtr *createFunc)
    185 {
    186 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    187 	unsigned ndfail = asmap->numDataFailed;
    188 	unsigned npfail = asmap->numParityFailed + asmap->numQFailed;
    189 	unsigned ntfail = npfail + ndfail;
    190 
    191 	RF_ASSERT(RF_IO_IS_R_OR_W(type));
    192 	if (ntfail > 2) {
    193 		RF_ERRORMSG("more than two disks failed in a single group!  Aborting I/O operation.\n");
    194 		*createFunc = NULL;
    195 		return;
    196 	}
    197 	/* ok, we can do this I/O */
    198 	if (type == RF_IO_TYPE_READ) {
    199 		switch (ndfail) {
    200 		case 0:
    201 			/* fault free read */
    202 			*createFunc = (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG;	/* same as raid 5 */
    203 			break;
    204 		case 1:
    205 			/* lost a single data unit */
    206 			/* two cases: (1) parity is not lost. do a normal raid
    207 			 * 5 reconstruct read. (2) parity is lost. do a
    208 			 * reconstruct read using "e". */
    209 			if (ntfail == 2) {	/* also lost redundancy */
    210 				if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY)
    211 					*createFunc = (RF_VoidFuncPtr) rf_EO_110_CreateReadDAG;
    212 				else
    213 					*createFunc = (RF_VoidFuncPtr) rf_EO_101_CreateReadDAG;
    214 			} else {
    215 				/* P and E are ok. But is there a failure in
    216 				 * some unaccessed data unit? */
    217 				if (rf_NumFailedDataUnitsInStripe(raidPtr, asmap) == 2)
    218 					*createFunc = (RF_VoidFuncPtr) rf_EO_200_CreateReadDAG;
    219 				else
    220 					*createFunc = (RF_VoidFuncPtr) rf_EO_100_CreateReadDAG;
    221 			}
    222 			break;
    223 		case 2:
    224 			/* *createFunc = rf_EO_200_CreateReadDAG; */
    225 			*createFunc = NULL;
    226 			break;
    227 		}
    228 		return;
    229 	}
    230 	/* a write */
    231 	switch (ntfail) {
    232 	case 0:		/* fault free */
    233 		if (rf_suppressLocksAndLargeWrites ||
    234 		    (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) && (layoutPtr->numDataCol != 1)) ||
    235 			(asmap->parityInfo->next != NULL) || (asmap->qInfo->next != NULL) || rf_CheckStripeForFailures(raidPtr, asmap))) {
    236 
    237 			*createFunc = (RF_VoidFuncPtr) rf_EOCreateSmallWriteDAG;
    238 		} else {
    239 			*createFunc = (RF_VoidFuncPtr) rf_EOCreateLargeWriteDAG;
    240 		}
    241 		break;
    242 
    243 	case 1:		/* single disk fault */
    244 		if (npfail == 1) {
    245 			RF_ASSERT((asmap->failedPDAs[0]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q));
    246 			if (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q) {	/* q died, treat like
    247 										 * normal mode raid5
    248 										 * write. */
    249 				if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1))
    250 				    || (asmap->parityInfo->next != NULL) || rf_NumFailedDataUnitsInStripe(raidPtr, asmap))
    251 					*createFunc = (RF_VoidFuncPtr) rf_EO_001_CreateSmallWriteDAG;
    252 				else
    253 					*createFunc = (RF_VoidFuncPtr) rf_EO_001_CreateLargeWriteDAG;
    254 			} else {/* parity died, small write only updating Q */
    255 				if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1))
    256 				    || (asmap->qInfo->next != NULL) || rf_NumFailedDataUnitsInStripe(raidPtr, asmap))
    257 					*createFunc = (RF_VoidFuncPtr) rf_EO_010_CreateSmallWriteDAG;
    258 				else
    259 					*createFunc = (RF_VoidFuncPtr) rf_EO_010_CreateLargeWriteDAG;
    260 			}
    261 		} else {	/* data missing. Do a P reconstruct write if
    262 				 * only a single data unit is lost in the
    263 				 * stripe, otherwise a reconstruct write which
    264 				 * employing both P and E units. */
    265 			if (rf_NumFailedDataUnitsInStripe(raidPtr, asmap) == 2) {
    266 				if (asmap->numStripeUnitsAccessed == 1)
    267 					*createFunc = (RF_VoidFuncPtr) rf_EO_200_CreateWriteDAG;
    268 				else
    269 					*createFunc = NULL;	/* No direct support for
    270 								 * this case now, like
    271 								 * that in Raid-5  */
    272 			} else {
    273 				if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
    274 					*createFunc = NULL;	/* No direct support for
    275 								 * this case now, like
    276 								 * that in Raid-5  */
    277 				else
    278 					*createFunc = (RF_VoidFuncPtr) rf_EO_100_CreateWriteDAG;
    279 			}
    280 		}
    281 		break;
    282 
    283 	case 2:		/* two disk faults */
    284 		switch (npfail) {
    285 		case 2:	/* both p and q dead */
    286 			*createFunc = (RF_VoidFuncPtr) rf_EO_011_CreateWriteDAG;
    287 			break;
    288 		case 1:	/* either p or q and dead data */
    289 			RF_ASSERT(asmap->failedPDAs[0]->type == RF_PDA_TYPE_DATA);
    290 			RF_ASSERT((asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q));
    291 			if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q) {
    292 				if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
    293 					*createFunc = NULL;	/* In both PQ and
    294 								 * EvenOdd, no direct
    295 								 * support for this case
    296 								 * now, like that in
    297 								 * Raid-5  */
    298 				else
    299 					*createFunc = (RF_VoidFuncPtr) rf_EO_101_CreateWriteDAG;
    300 			} else {
    301 				if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
    302 					*createFunc = NULL;	/* No direct support for
    303 								 * this case, like that
    304 								 * in Raid-5  */
    305 				else
    306 					*createFunc = (RF_VoidFuncPtr) rf_EO_110_CreateWriteDAG;
    307 			}
    308 			break;
    309 		case 0:	/* double data loss */
    310 			/* if(asmap->failedPDAs[0]->numSector +
    311 			 * asmap->failedPDAs[1]->numSector == 2 *
    312 			 * layoutPtr->sectorsPerStripeUnit ) createFunc =
    313 			 * rf_EOCreateLargeWriteDAG; else    							 */
    314 			*createFunc = NULL;	/* currently, in Evenodd, No
    315 						 * support for simultaneous
    316 						 * access of both failed SUs */
    317 			break;
    318 		}
    319 		break;
    320 
    321 	default:		/* more than 2 disk faults */
    322 		*createFunc = NULL;
    323 		RF_PANIC();
    324 	}
    325 	return;
    326 }
    327 
    328 
    329 int
    330 rf_VerifyParityEvenOdd(RF_Raid_t *raidPtr, RF_RaidAddr_t raidAddr,
    331 		       RF_PhysDiskAddr_t *parityPDA, int correct_it,
    332 		       RF_RaidAccessFlags_t flags)
    333 {
    334 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    335 	RF_RaidAddr_t startAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, raidAddr);
    336 	RF_SectorCount_t numsector = parityPDA->numSector;
    337 	int     numbytes = rf_RaidAddressToByte(raidPtr, numsector);
    338 	int     bytesPerStripe = numbytes * layoutPtr->numDataCol;
    339 	RF_DagHeader_t *rd_dag_h, *wr_dag_h;	/* read, write dag */
    340 	RF_DagNode_t *blockNode, *wrBlock;
    341 	RF_AccessStripeMapHeader_t *asm_h;
    342 	RF_AccessStripeMap_t *asmap;
    343 	RF_AllocListElem_t *alloclist;
    344 	RF_PhysDiskAddr_t *pda;
    345 	char   *pbuf, *buf, *end_p, *p;
    346 	char   *redundantbuf2;
    347 	int     redundantTwoErr = 0, redundantOneErr = 0;
    348 	int     parity_cant_correct = RF_FALSE, red2_cant_correct = RF_FALSE,
    349 	        parity_corrected = RF_FALSE, red2_corrected = RF_FALSE;
    350 	int     i, retcode;
    351 	RF_ReconUnitNum_t which_ru;
    352 	RF_StripeNum_t psID = rf_RaidAddressToParityStripeID(layoutPtr, raidAddr, &which_ru);
    353 	int     stripeWidth = layoutPtr->numDataCol + layoutPtr->numParityCol;
    354 	RF_AccTraceEntry_t tracerec;
    355 	RF_MCPair_t *mcpair;
    356 
    357 	retcode = RF_PARITY_OKAY;
    358 
    359 	mcpair = rf_AllocMCPair(raidPtr);
    360 	rf_MakeAllocList(alloclist);
    361 	buf = RF_MallocAndAdd(
    362 	    numbytes * (layoutPtr->numDataCol + layoutPtr->numParityCol),
    363 	    alloclist);
    364 	pbuf = RF_MallocAndAdd(numbytes, alloclist);
    365 	end_p = buf + bytesPerStripe;
    366 	redundantbuf2 = RF_MallocAndAdd(numbytes, alloclist);
    367 
    368 	rd_dag_h = rf_MakeSimpleDAG(raidPtr, stripeWidth, numbytes, buf, rf_DiskReadFunc, rf_DiskReadUndoFunc,
    369 	    "Rod", alloclist, flags, RF_IO_NORMAL_PRIORITY);
    370 	blockNode = rd_dag_h->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(&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_MCPAIR(mcpair);
    416 	mcpair->flag = 0;
    417 	rf_DispatchDAG(rd_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc,
    418 	    (void *) mcpair);
    419 	while (!mcpair->flag)
    420 		RF_WAIT_MCPAIR(mcpair);
    421 	RF_UNLOCK_MCPAIR(mcpair);
    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 		wrBlock->succedents[0]->params[0].p = asmap->parityInfo;
    466 		wrBlock->succedents[0]->params[2].v = psID;
    467 		wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
    468 		memset(&tracerec, 0, sizeof(tracerec));
    469 		wr_dag_h->tracerec = &tracerec;
    470 #if RF_DEBUG_VALIDATE_DAG
    471 		if (rf_verifyParityDebug) {
    472 			printf("Parity verify write dag:\n");
    473 			rf_PrintDAGList(wr_dag_h);
    474 		}
    475 #endif
    476 		RF_LOCK_MCPAIR(mcpair);
    477 		mcpair->flag = 0;
    478 		rf_DispatchDAG(wr_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc,
    479 		    (void *) mcpair);
    480 		while (!mcpair->flag)
    481 			RF_WAIT_MCPAIR(mcpair);
    482 		RF_UNLOCK_MCPAIR(mcpair);
    483 		if (wr_dag_h->status != rf_enable) {
    484 			RF_ERRORMSG("Unable to correct parity in VerifyParity:  can't write the stripe\n");
    485 			parity_cant_correct = RF_TRUE;
    486 		} else {
    487 			parity_corrected = RF_TRUE;
    488 		}
    489 		rf_FreeDAG(wr_dag_h);
    490 	}
    491 	if (redundantTwoErr && correct_it) {
    492 		wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, redundantbuf2, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
    493 		    "Wnred2", alloclist, flags, RF_IO_NORMAL_PRIORITY);
    494 		wrBlock = wr_dag_h->succedents[0];
    495 		wrBlock->succedents[0]->params[0].p = asmap->qInfo;
    496 		wrBlock->succedents[0]->params[2].v = psID;
    497 		wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru);
    498 		memset(&tracerec, 0, sizeof(tracerec));
    499 		wr_dag_h->tracerec = &tracerec;
    500 #if RF_DEBUG_VALIDATE_DAG
    501 		if (rf_verifyParityDebug) {
    502 			printf("Dag of write new second redundant information in parity verify :\n");
    503 			rf_PrintDAGList(wr_dag_h);
    504 		}
    505 #endif
    506 		RF_LOCK_MCPAIR(mcpair);
    507 		mcpair->flag = 0;
    508 		rf_DispatchDAG(wr_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc,
    509 		    (void *) mcpair);
    510 		while (!mcpair->flag)
    511 			RF_WAIT_MCPAIR(mcpair);
    512 		RF_UNLOCK_MCPAIR(mcpair);
    513 		if (wr_dag_h->status != rf_enable) {
    514 			RF_ERRORMSG("Unable to correct second redundant information in VerifyParity:  can't write the stripe\n");
    515 			red2_cant_correct = RF_TRUE;
    516 		} else {
    517 			red2_corrected = RF_TRUE;
    518 		}
    519 		rf_FreeDAG(wr_dag_h);
    520 	}
    521 	if ((redundantOneErr && parity_cant_correct) ||
    522 	    (redundantTwoErr && red2_cant_correct))
    523 		retcode = RF_PARITY_COULD_NOT_CORRECT;
    524 	if ((retcode = RF_PARITY_BAD) && parity_corrected && red2_corrected)
    525 		retcode = RF_PARITY_CORRECTED;
    526 
    527 
    528 out:
    529 	rf_FreeAccessStripeMap(raidPtr, asm_h);
    530 	rf_FreeAllocList(alloclist);
    531 	rf_FreeDAG(rd_dag_h);
    532 	rf_FreeMCPair(raidPtr, mcpair);
    533 	return (retcode);
    534 }
    535 #endif				/* RF_INCLUDE_EVENODD > 0 */
    536