NetBSD/sys/dev/raidframe/rf_evenodd.c

556 lines
20 KiB
C

/* $NetBSD: rf_evenodd.c,v 1.1 1998/11/13 04:20:29 oster Exp $ */
/*
* Copyright (c) 1995 Carnegie-Mellon University.
* All rights reserved.
*
* Author: Chang-Ming Wu
*
* Permission to use, copy, modify and distribute this software and
* its documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
* FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie the
* rights to redistribute these changes.
*/
/*****************************************************************************************
*
* rf_evenodd.c -- implements EVENODD array architecture
*
****************************************************************************************/
#include "rf_archs.h"
#if RF_INCLUDE_EVENODD > 0
#include "rf_types.h"
#include "rf_raid.h"
#include "rf_dag.h"
#include "rf_dagffrd.h"
#include "rf_dagffwr.h"
#include "rf_dagdegrd.h"
#include "rf_dagdegwr.h"
#include "rf_dagutils.h"
#include "rf_dagfuncs.h"
#include "rf_threadid.h"
#include "rf_etimer.h"
#include "rf_general.h"
#include "rf_evenodd.h"
#include "rf_configure.h"
#include "rf_parityscan.h"
#include "rf_utils.h"
#include "rf_map.h"
#include "rf_pq.h"
#include "rf_mcpair.h"
#include "rf_sys.h"
#include "rf_evenodd.h"
#include "rf_evenodd_dagfuncs.h"
#include "rf_evenodd_dags.h"
#include "rf_engine.h"
typedef struct RF_EvenOddConfigInfo_s {
RF_RowCol_t **stripeIdentifier; /* filled in at config time & used by IdentifyStripe */
} RF_EvenOddConfigInfo_t;
int rf_ConfigureEvenOdd(listp, raidPtr, cfgPtr)
RF_ShutdownList_t **listp;
RF_Raid_t *raidPtr;
RF_Config_t *cfgPtr;
{
RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
RF_EvenOddConfigInfo_t *info;
RF_RowCol_t i, j, startdisk;
RF_MallocAndAdd(info, sizeof(RF_EvenOddConfigInfo_t), (RF_EvenOddConfigInfo_t *), raidPtr->cleanupList);
layoutPtr->layoutSpecificInfo = (void *) info;
RF_ASSERT(raidPtr->numRow == 1);
info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, raidPtr->numCol, raidPtr->cleanupList);
startdisk = 0;
for (i=0; i<raidPtr->numCol; i++) {
for (j=0; j<raidPtr->numCol; j++) {
info->stripeIdentifier[i][j] = (startdisk + j) % raidPtr->numCol;
}
if ((startdisk -= 2) < 0) startdisk += raidPtr->numCol;
}
/* fill in the remaining layout parameters */
layoutPtr->numStripe = layoutPtr->stripeUnitsPerDisk;
layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
layoutPtr->numDataCol = raidPtr->numCol-2; /* ORIG: layoutPtr->numDataCol = raidPtr->numCol-1; */
#if RF_EO_MATRIX_DIM > 17
if (raidPtr->numCol <= 17){
printf("Number of stripe units in a parity stripe is smaller than 17. Please\n");
printf("define the macro RF_EO_MATRIX_DIM in file rf_evenodd_dagfuncs.h to \n");
printf("be 17 to increase performance. \n");
return(EINVAL);
}
#elif RF_EO_MATRIX_DIM == 17
if (raidPtr->numCol > 17) {
printf("Number of stripe units in a parity stripe is bigger than 17. Please\n");
printf("define the macro RF_EO_MATRIX_DIM in file rf_evenodd_dagfuncs.h to \n");
printf("be 257 for encoding and decoding functions to work. \n");
return(EINVAL);
}
#endif
layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
layoutPtr->numParityCol = 2;
layoutPtr->dataStripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk;
raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
raidPtr->totalSectors = layoutPtr->stripeUnitsPerDisk * layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
return(0);
}
int rf_GetDefaultNumFloatingReconBuffersEvenOdd(RF_Raid_t *raidPtr)
{
return(20);
}
RF_HeadSepLimit_t rf_GetDefaultHeadSepLimitEvenOdd(RF_Raid_t *raidPtr)
{
return(10);
}
void rf_IdentifyStripeEvenOdd(
RF_Raid_t *raidPtr,
RF_RaidAddr_t addr,
RF_RowCol_t **diskids,
RF_RowCol_t *outRow)
{
RF_StripeNum_t stripeID = rf_RaidAddressToStripeID(&raidPtr->Layout, addr);
RF_EvenOddConfigInfo_t *info = (RF_EvenOddConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
*outRow = 0;
*diskids = info->stripeIdentifier[ stripeID % raidPtr->numCol ];
}
/* The layout of stripe unit on the disks are: c0 c1 c2 c3 c4
0 1 2 E P
5 E P 3 4
P 6 7 8 E
10 11 E P 9
E P 12 13 14
....
We use the MapSectorRAID5 to map data information because the routine can be shown to map exactly
the layout of data stripe unit as shown above although we have 2 redundant information now.
But for E and P, we use rf_MapEEvenOdd and rf_MapParityEvenOdd which are different method from raid-5.
*/
void rf_MapParityEvenOdd(
RF_Raid_t *raidPtr,
RF_RaidAddr_t raidSector,
RF_RowCol_t *row,
RF_RowCol_t *col,
RF_SectorNum_t *diskSector,
int remap)
{
RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
RF_StripeNum_t endSUIDofthisStrip = (SUID/raidPtr->Layout.numDataCol + 1)*raidPtr->Layout.numDataCol - 1;
*row = 0;
*col = ( endSUIDofthisStrip + 2)%raidPtr->numCol;
*diskSector = (SUID / (raidPtr->Layout.numDataCol)) * raidPtr->Layout.sectorsPerStripeUnit +
(raidSector % raidPtr->Layout.sectorsPerStripeUnit);
}
void rf_MapEEvenOdd(
RF_Raid_t *raidPtr,
RF_RaidAddr_t raidSector,
RF_RowCol_t *row,
RF_RowCol_t *col,
RF_SectorNum_t *diskSector,
int remap)
{
RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
RF_StripeNum_t endSUIDofthisStrip = (SUID/raidPtr->Layout.numDataCol + 1)*raidPtr->Layout.numDataCol - 1;
*row = 0;
*col = ( endSUIDofthisStrip + 1)%raidPtr->numCol;
*diskSector = (SUID / (raidPtr->Layout.numDataCol)) * raidPtr->Layout.sectorsPerStripeUnit +
(raidSector % raidPtr->Layout.sectorsPerStripeUnit);
}
void rf_EODagSelect(
RF_Raid_t *raidPtr,
RF_IoType_t type,
RF_AccessStripeMap_t *asmap,
RF_VoidFuncPtr *createFunc)
{
RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
unsigned ndfail = asmap->numDataFailed;
unsigned npfail = asmap->numParityFailed +asmap->numQFailed;
unsigned ntfail = npfail + ndfail;
RF_ASSERT(RF_IO_IS_R_OR_W(type));
if (ntfail > 2)
{
RF_ERRORMSG("more than two disks failed in a single group! Aborting I/O operation.\n");
/* *infoFunc = */ *createFunc = NULL;
return;
}
/* ok, we can do this I/O */
if (type == RF_IO_TYPE_READ)
{
switch (ndfail)
{
case 0:
/* fault free read */
*createFunc = (RF_VoidFuncPtr)rf_CreateFaultFreeReadDAG; /* same as raid 5 */
break;
case 1:
/* lost a single data unit */
/* two cases:
(1) parity is not lost.
do a normal raid 5 reconstruct read.
(2) parity is lost.
do a reconstruct read using "e".
*/
if (ntfail == 2) /* also lost redundancy */
{
if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY)
*createFunc = (RF_VoidFuncPtr)rf_EO_110_CreateReadDAG;
else
*createFunc = (RF_VoidFuncPtr)rf_EO_101_CreateReadDAG;
}
else
{
/* P and E are ok. But is there a failure
in some unaccessed data unit?
*/
if (rf_NumFailedDataUnitsInStripe(raidPtr,asmap)==2)
*createFunc = (RF_VoidFuncPtr)rf_EO_200_CreateReadDAG;
else
*createFunc = (RF_VoidFuncPtr)rf_EO_100_CreateReadDAG;
}
break;
case 2:
/* *createFunc = rf_EO_200_CreateReadDAG; */
*createFunc = NULL;
break;
}
return;
}
/* a write */
switch (ntfail)
{
case 0: /* fault free */
if (rf_suppressLocksAndLargeWrites ||
(((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) && (layoutPtr->numDataCol != 1)) ||
(asmap->parityInfo->next != NULL) || (asmap->qInfo->next != NULL) || rf_CheckStripeForFailures(raidPtr, asmap))) {
*createFunc = (RF_VoidFuncPtr)rf_EOCreateSmallWriteDAG;
}
else {
*createFunc = (RF_VoidFuncPtr)rf_EOCreateLargeWriteDAG;
}
break;
case 1: /* single disk fault */
if (npfail==1)
{
RF_ASSERT ((asmap->failedPDAs[0]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q));
if (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q)
{ /* q died, treat like normal mode raid5 write.*/
if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1))
|| (asmap->parityInfo->next!=NULL) || rf_NumFailedDataUnitsInStripe(raidPtr,asmap))
*createFunc = (RF_VoidFuncPtr)rf_EO_001_CreateSmallWriteDAG;
else
*createFunc = (RF_VoidFuncPtr)rf_EO_001_CreateLargeWriteDAG;
}
else
{ /* parity died, small write only updating Q */
if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1))
|| (asmap->qInfo->next!=NULL) || rf_NumFailedDataUnitsInStripe(raidPtr,asmap))
*createFunc = (RF_VoidFuncPtr)rf_EO_010_CreateSmallWriteDAG;
else
*createFunc = (RF_VoidFuncPtr)rf_EO_010_CreateLargeWriteDAG;
}
}
else
{ /* data missing.
Do a P reconstruct write if only a single data unit
is lost in the stripe, otherwise a reconstruct
write which employnig both P and E units. */
if (rf_NumFailedDataUnitsInStripe(raidPtr,asmap)==2)
{
if (asmap->numStripeUnitsAccessed == 1)
*createFunc = (RF_VoidFuncPtr)rf_EO_200_CreateWriteDAG;
else
*createFunc = NULL; /* No direct support for this case now, like that in Raid-5 */
}
else
{
if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
*createFunc = NULL; /* No direct support for this case now, like that in Raid-5 */
else *createFunc = (RF_VoidFuncPtr)rf_EO_100_CreateWriteDAG;
}
}
break;
case 2: /* two disk faults */
switch (npfail)
{
case 2: /* both p and q dead */
*createFunc = (RF_VoidFuncPtr)rf_EO_011_CreateWriteDAG;
break;
case 1: /* either p or q and dead data */
RF_ASSERT(asmap->failedPDAs[0]->type == RF_PDA_TYPE_DATA);
RF_ASSERT ((asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q));
if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q)
{
if(asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
*createFunc = NULL; /* In both PQ and EvenOdd, no direct support for this case now, like that in Raid-5 */
else
*createFunc = (RF_VoidFuncPtr)rf_EO_101_CreateWriteDAG;
}
else
{
if (asmap->numStripeUnitsAccessed != 1 && asmap->failedPDAs[0]->numSector != layoutPtr->sectorsPerStripeUnit)
*createFunc = NULL; /* No direct support for this case, like that in Raid-5 */
else
*createFunc = (RF_VoidFuncPtr)rf_EO_110_CreateWriteDAG;
}
break;
case 0: /* double data loss */
/* if(asmap->failedPDAs[0]->numSector + asmap->failedPDAs[1]->numSector == 2 * layoutPtr->sectorsPerStripeUnit )
*createFunc = rf_EOCreateLargeWriteDAG;
else */
*createFunc = NULL; /* currently, in Evenodd, No support for simultaneous access of both failed SUs */
break;
}
break;
default: /* more than 2 disk faults */
*createFunc = NULL;
RF_PANIC();
}
return;
}
int rf_VerifyParityEvenOdd(raidPtr, raidAddr, parityPDA, correct_it, flags)
RF_Raid_t *raidPtr;
RF_RaidAddr_t raidAddr;
RF_PhysDiskAddr_t *parityPDA;
int correct_it;
RF_RaidAccessFlags_t flags;
{
RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
RF_RaidAddr_t startAddr = rf_RaidAddressOfPrevStripeBoundary(layoutPtr, raidAddr);
RF_SectorCount_t numsector = parityPDA->numSector;
int numbytes = rf_RaidAddressToByte(raidPtr, numsector);
int bytesPerStripe = numbytes * layoutPtr->numDataCol;
RF_DagHeader_t *rd_dag_h, *wr_dag_h; /* read, write dag */
RF_DagNode_t *blockNode, *unblockNode, *wrBlock, *wrUnblock;
RF_AccessStripeMapHeader_t *asm_h;
RF_AccessStripeMap_t *asmap;
RF_AllocListElem_t *alloclist;
RF_PhysDiskAddr_t *pda;
char *pbuf, *buf, *end_p, *p;
char *redundantbuf2;
int redundantTwoErr = 0, redundantOneErr = 0;
int parity_cant_correct = RF_FALSE, red2_cant_correct = RF_FALSE, parity_corrected = RF_FALSE, red2_corrected = RF_FALSE;
int i, retcode;
RF_ReconUnitNum_t which_ru;
RF_StripeNum_t psID = rf_RaidAddressToParityStripeID(layoutPtr, raidAddr, &which_ru);
int stripeWidth = layoutPtr->numDataCol + layoutPtr->numParityCol;
RF_AccTraceEntry_t tracerec;
RF_MCPair_t *mcpair;
retcode = RF_PARITY_OKAY;
mcpair = rf_AllocMCPair();
rf_MakeAllocList(alloclist);
RF_MallocAndAdd(buf, numbytes * (layoutPtr->numDataCol + layoutPtr->numParityCol), (char *), alloclist);
RF_CallocAndAdd(pbuf, 1, numbytes, (char *), alloclist); /* use calloc to make sure buffer is zeroed */
end_p = buf + bytesPerStripe;
RF_CallocAndAdd(redundantbuf2, 1, numbytes, (char *), alloclist); /* use calloc to make sure buffer is zeroed */
rd_dag_h = rf_MakeSimpleDAG(raidPtr, stripeWidth, numbytes, buf, rf_DiskReadFunc, rf_DiskReadUndoFunc,
"Rod", alloclist, flags, RF_IO_NORMAL_PRIORITY);
blockNode = rd_dag_h->succedents[0];
unblockNode = blockNode->succedents[0]->succedents[0];
/* map the stripe and fill in the PDAs in the dag */
asm_h = rf_MapAccess(raidPtr, startAddr, layoutPtr->dataSectorsPerStripe, buf, RF_DONT_REMAP);
asmap = asm_h->stripeMap;
for (pda=asmap->physInfo,i=0; i<layoutPtr->numDataCol; i++,pda=pda->next) {
RF_ASSERT(pda);
rf_RangeRestrictPDA(raidPtr, parityPDA, pda, 0, 1);
RF_ASSERT(pda->numSector != 0);
if (rf_TryToRedirectPDA(raidPtr, pda, 0)) goto out; /* no way to verify parity if disk is dead. return w/ good status */
blockNode->succedents[i]->params[0].p = pda;
blockNode->succedents[i]->params[2].v = psID;
blockNode->succedents[i]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
}
RF_ASSERT(!asmap->parityInfo->next);
rf_RangeRestrictPDA(raidPtr, parityPDA, asmap->parityInfo, 0, 1);
RF_ASSERT(asmap->parityInfo->numSector != 0);
if (rf_TryToRedirectPDA(raidPtr, asmap->parityInfo, 1))
goto out;
blockNode->succedents[ layoutPtr->numDataCol ]->params[0].p = asmap->parityInfo;
RF_ASSERT(!asmap->qInfo->next);
rf_RangeRestrictPDA(raidPtr, parityPDA, asmap->qInfo, 0, 1);
RF_ASSERT(asmap->qInfo->numSector != 0);
if (rf_TryToRedirectPDA(raidPtr, asmap->qInfo, 1)) goto out;
/*
* if disk is dead, b/c no reconstruction is implemented right now,
* the function "rf_TryToRedirectPDA" always return one, which cause
* go to out and return w/ good status
*/
blockNode->succedents[ layoutPtr->numDataCol +1 ]->params[0].p = asmap->qInfo;
/* fire off the DAG */
bzero((char *)&tracerec,sizeof(tracerec));
rd_dag_h->tracerec = &tracerec;
if (rf_verifyParityDebug) {
printf("Parity verify read dag:\n");
rf_PrintDAGList(rd_dag_h);
}
RF_LOCK_MUTEX(mcpair->mutex);
mcpair->flag = 0;
rf_DispatchDAG(rd_dag_h, (void (*)(void *))rf_MCPairWakeupFunc,
(void *) mcpair);
while (!mcpair->flag) RF_WAIT_COND(mcpair->cond, mcpair->mutex);
RF_UNLOCK_MUTEX(mcpair->mutex);
if (rd_dag_h->status != rf_enable) {
RF_ERRORMSG("Unable to verify parity: can't read the stripe\n");
retcode = RF_PARITY_COULD_NOT_VERIFY;
goto out;
}
for (p=buf, i=0; p<end_p; p+=numbytes, i++) {
rf_e_encToBuf(raidPtr, i, p, RF_EO_MATRIX_DIM - 2, redundantbuf2, numsector);
/*
* the corresponding columes in EvenOdd encoding Matrix for these p pointers which point
* to the databuffer in a full stripe are sequentially from 0 to layoutPtr->numDataCol-1
*/
rf_bxor(p, pbuf, numbytes, NULL);
}
RF_ASSERT(i==layoutPtr->numDataCol);
for (i=0; i<numbytes; i++) {
if (pbuf[i] != buf[bytesPerStripe+i]) {
if (!correct_it) {
RF_ERRORMSG3("Parity verify error: byte %d of parity is 0x%x should be 0x%x\n",
i,(u_char) buf[bytesPerStripe+i],(u_char) pbuf[i]);
}
}
redundantOneErr = 1;
break;
}
for (i=0; i<numbytes; i++) {
if (redundantbuf2[i] != buf[bytesPerStripe+numbytes+i]) {
if (!correct_it) {
RF_ERRORMSG3("Parity verify error: byte %d of second redundant information is 0x%x should be 0x%x\n",
i,(u_char) buf[bytesPerStripe+numbytes+i],(u_char) redundantbuf2[i]);
}
redundantTwoErr = 1;
break;
}
}
if (redundantOneErr || redundantTwoErr )
retcode = RF_PARITY_BAD;
/* correct the first redundant disk, ie parity if it is error */
if (redundantOneErr && correct_it) {
wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, pbuf, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
"Wnp", alloclist, flags, RF_IO_NORMAL_PRIORITY);
wrBlock = wr_dag_h->succedents[0]; wrUnblock = wrBlock->succedents[0]->succedents[0];
wrBlock->succedents[0]->params[0].p = asmap->parityInfo;
wrBlock->succedents[0]->params[2].v = psID;
wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
bzero((char *)&tracerec,sizeof(tracerec));
wr_dag_h->tracerec = &tracerec;
if (rf_verifyParityDebug) {
printf("Parity verify write dag:\n");
rf_PrintDAGList(wr_dag_h);
}
RF_LOCK_MUTEX(mcpair->mutex);
mcpair->flag = 0;
rf_DispatchDAG(wr_dag_h, (void (*)(void *))rf_MCPairWakeupFunc,
(void *) mcpair);
while (!mcpair->flag)
RF_WAIT_COND(mcpair->cond, mcpair->mutex);
RF_UNLOCK_MUTEX(mcpair->mutex);
if (wr_dag_h->status != rf_enable) {
RF_ERRORMSG("Unable to correct parity in VerifyParity: can't write the stripe\n");
parity_cant_correct = RF_TRUE;
} else {
parity_corrected = RF_TRUE;
}
rf_FreeDAG(wr_dag_h);
}
if (redundantTwoErr && correct_it) {
wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, redundantbuf2, rf_DiskWriteFunc, rf_DiskWriteUndoFunc,
"Wnred2", alloclist, flags, RF_IO_NORMAL_PRIORITY);
wrBlock = wr_dag_h->succedents[0]; wrUnblock = wrBlock->succedents[0]->succedents[0];
wrBlock->succedents[0]->params[0].p = asmap->qInfo;
wrBlock->succedents[0]->params[2].v = psID;
wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, 0, 0, which_ru);
bzero((char *)&tracerec,sizeof(tracerec));
wr_dag_h->tracerec = &tracerec;
if (rf_verifyParityDebug) {
printf("Dag of write new second redundant information in parity verify :\n");
rf_PrintDAGList(wr_dag_h);
}
RF_LOCK_MUTEX(mcpair->mutex);
mcpair->flag = 0;
rf_DispatchDAG(wr_dag_h, (void (*)(void *))rf_MCPairWakeupFunc,
(void *) mcpair);
while (!mcpair->flag)
RF_WAIT_COND(mcpair->cond, mcpair->mutex);
RF_UNLOCK_MUTEX(mcpair->mutex);
if (wr_dag_h->status != rf_enable) {
RF_ERRORMSG("Unable to correct second redundant information in VerifyParity: can't write the stripe\n");
red2_cant_correct = RF_TRUE;
} else {
red2_corrected = RF_TRUE;
}
rf_FreeDAG(wr_dag_h);
}
if ( (redundantOneErr && parity_cant_correct) ||
(redundantTwoErr && red2_cant_correct ))
retcode = RF_PARITY_COULD_NOT_CORRECT;
if ( (retcode = RF_PARITY_BAD) && parity_corrected && red2_corrected )
retcode = RF_PARITY_CORRECTED;
out:
rf_FreeAccessStripeMap(asm_h);
rf_FreeAllocList(alloclist);
rf_FreeDAG(rd_dag_h);
rf_FreeMCPair(mcpair);
return(retcode);
}
#endif /* RF_INCLUDE_EVENODD > 0 */