| 1 | /* $NetBSD: rf_evenodd.c,v 1.21 2014/03/23 09:30:59 christos 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.21 2014/03/23 09:30:59 christos 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 | RF_MallocAndAdd(info, sizeof(RF_EvenOddConfigInfo_t), (RF_EvenOddConfigInfo_t *), 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 | * employnig 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(); |
| 360 | rf_MakeAllocList(alloclist); |
| 361 | RF_MallocAndAdd(buf, numbytes * (layoutPtr->numDataCol + layoutPtr->numParityCol), (char *), alloclist); |
| 362 | RF_MallocAndAdd(pbuf, numbytes, (char *), alloclist); |
| 363 | end_p = buf + bytesPerStripe; |
| 364 | RF_MallocAndAdd(redundantbuf2, numbytes, (char *), alloclist); |
| 365 | |
| 366 | rd_dag_h = rf_MakeSimpleDAG(raidPtr, stripeWidth, numbytes, buf, rf_DiskReadFunc, rf_DiskReadUndoFunc, |
| 367 | "Rod" , alloclist, flags, RF_IO_NORMAL_PRIORITY); |
| 368 | blockNode = rd_dag_h->succedents[0]; |
| 369 | |
| 370 | /* map the stripe and fill in the PDAs in the dag */ |
| 371 | asm_h = rf_MapAccess(raidPtr, startAddr, layoutPtr->dataSectorsPerStripe, buf, RF_DONT_REMAP); |
| 372 | asmap = asm_h->stripeMap; |
| 373 | |
| 374 | for (pda = asmap->physInfo, i = 0; i < layoutPtr->numDataCol; i++, pda = pda->next) { |
| 375 | RF_ASSERT(pda); |
| 376 | rf_RangeRestrictPDA(raidPtr, parityPDA, pda, 0, 1); |
| 377 | RF_ASSERT(pda->numSector != 0); |
| 378 | if (rf_TryToRedirectPDA(raidPtr, pda, 0)) |
| 379 | goto out; /* no way to verify parity if disk is |
| 380 | * dead. return w/ good status */ |
| 381 | blockNode->succedents[i]->params[0].p = pda; |
| 382 | blockNode->succedents[i]->params[2].v = psID; |
| 383 | blockNode->succedents[i]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru); |
| 384 | } |
| 385 | |
| 386 | RF_ASSERT(!asmap->parityInfo->next); |
| 387 | rf_RangeRestrictPDA(raidPtr, parityPDA, asmap->parityInfo, 0, 1); |
| 388 | RF_ASSERT(asmap->parityInfo->numSector != 0); |
| 389 | if (rf_TryToRedirectPDA(raidPtr, asmap->parityInfo, 1)) |
| 390 | goto out; |
| 391 | blockNode->succedents[layoutPtr->numDataCol]->params[0].p = asmap->parityInfo; |
| 392 | |
| 393 | RF_ASSERT(!asmap->qInfo->next); |
| 394 | rf_RangeRestrictPDA(raidPtr, parityPDA, asmap->qInfo, 0, 1); |
| 395 | RF_ASSERT(asmap->qInfo->numSector != 0); |
| 396 | if (rf_TryToRedirectPDA(raidPtr, asmap->qInfo, 1)) |
| 397 | goto out; |
| 398 | /* if disk is dead, b/c no reconstruction is implemented right now, |
| 399 | * the function "rf_TryToRedirectPDA" always return one, which cause |
| 400 | * go to out and return w/ good status */ |
| 401 | blockNode->succedents[layoutPtr->numDataCol + 1]->params[0].p = asmap->qInfo; |
| 402 | |
| 403 | /* fire off the DAG */ |
| 404 | memset((char *) &tracerec, 0, sizeof(tracerec)); |
| 405 | rd_dag_h->tracerec = &tracerec; |
| 406 | |
| 407 | #if RF_DEBUG_VALIDATE_DAG |
| 408 | if (rf_verifyParityDebug) { |
| 409 | printf("Parity verify read dag:\n" ); |
| 410 | rf_PrintDAGList(rd_dag_h); |
| 411 | } |
| 412 | #endif |
| 413 | RF_LOCK_MCPAIR(mcpair); |
| 414 | mcpair->flag = 0; |
| 415 | rf_DispatchDAG(rd_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc, |
| 416 | (void *) mcpair); |
| 417 | while (!mcpair->flag) |
| 418 | RF_WAIT_MCPAIR(mcpair); |
| 419 | RF_UNLOCK_MCPAIR(mcpair); |
| 420 | if (rd_dag_h->status != rf_enable) { |
| 421 | RF_ERRORMSG("Unable to verify parity: can't read the stripe\n" ); |
| 422 | retcode = RF_PARITY_COULD_NOT_VERIFY; |
| 423 | goto out; |
| 424 | } |
| 425 | for (p = buf, i = 0; p < end_p; p += numbytes, i++) { |
| 426 | rf_e_encToBuf(raidPtr, i, p, RF_EO_MATRIX_DIM - 2, redundantbuf2, numsector); |
| 427 | /* the corresponding columes in EvenOdd encoding Matrix for |
| 428 | * these p pointers which point to the databuffer in a full |
| 429 | * stripe are sequentially from 0 to layoutPtr->numDataCol-1 */ |
| 430 | rf_bxor(p, pbuf, numbytes); |
| 431 | } |
| 432 | RF_ASSERT(i == layoutPtr->numDataCol); |
| 433 | |
| 434 | for (i = 0; i < numbytes; i++) { |
| 435 | if (pbuf[i] != buf[bytesPerStripe + i]) { |
| 436 | if (!correct_it) { |
| 437 | RF_ERRORMSG3("Parity verify error: byte %d of parity is 0x%x should be 0x%x\n" , |
| 438 | i, (u_char) buf[bytesPerStripe + i], (u_char) pbuf[i]); |
| 439 | } |
| 440 | } |
| 441 | redundantOneErr = 1; |
| 442 | break; |
| 443 | } |
| 444 | |
| 445 | for (i = 0; i < numbytes; i++) { |
| 446 | if (redundantbuf2[i] != buf[bytesPerStripe + numbytes + i]) { |
| 447 | if (!correct_it) { |
| 448 | RF_ERRORMSG3("Parity verify error: byte %d of second redundant information is 0x%x should be 0x%x\n" , |
| 449 | i, (u_char) buf[bytesPerStripe + numbytes + i], (u_char) redundantbuf2[i]); |
| 450 | } |
| 451 | redundantTwoErr = 1; |
| 452 | break; |
| 453 | } |
| 454 | } |
| 455 | if (redundantOneErr || redundantTwoErr) |
| 456 | retcode = RF_PARITY_BAD; |
| 457 | |
| 458 | /* correct the first redundant disk, ie parity if it is error */ |
| 459 | if (redundantOneErr && correct_it) { |
| 460 | wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, pbuf, rf_DiskWriteFunc, rf_DiskWriteUndoFunc, |
| 461 | "Wnp" , alloclist, flags, RF_IO_NORMAL_PRIORITY); |
| 462 | wrBlock = wr_dag_h->succedents[0]; |
| 463 | wrBlock->succedents[0]->params[0].p = asmap->parityInfo; |
| 464 | wrBlock->succedents[0]->params[2].v = psID; |
| 465 | wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru); |
| 466 | memset((char *) &tracerec, 0, sizeof(tracerec)); |
| 467 | wr_dag_h->tracerec = &tracerec; |
| 468 | #if RF_DEBUG_VALIDATE_DAG |
| 469 | if (rf_verifyParityDebug) { |
| 470 | printf("Parity verify write dag:\n" ); |
| 471 | rf_PrintDAGList(wr_dag_h); |
| 472 | } |
| 473 | #endif |
| 474 | RF_LOCK_MCPAIR(mcpair); |
| 475 | mcpair->flag = 0; |
| 476 | rf_DispatchDAG(wr_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc, |
| 477 | (void *) mcpair); |
| 478 | while (!mcpair->flag) |
| 479 | RF_WAIT_MCPAIR(mcpair); |
| 480 | RF_UNLOCK_MCPAIR(mcpair); |
| 481 | if (wr_dag_h->status != rf_enable) { |
| 482 | RF_ERRORMSG("Unable to correct parity in VerifyParity: can't write the stripe\n" ); |
| 483 | parity_cant_correct = RF_TRUE; |
| 484 | } else { |
| 485 | parity_corrected = RF_TRUE; |
| 486 | } |
| 487 | rf_FreeDAG(wr_dag_h); |
| 488 | } |
| 489 | if (redundantTwoErr && correct_it) { |
| 490 | wr_dag_h = rf_MakeSimpleDAG(raidPtr, 1, numbytes, redundantbuf2, rf_DiskWriteFunc, rf_DiskWriteUndoFunc, |
| 491 | "Wnred2" , alloclist, flags, RF_IO_NORMAL_PRIORITY); |
| 492 | wrBlock = wr_dag_h->succedents[0]; |
| 493 | wrBlock->succedents[0]->params[0].p = asmap->qInfo; |
| 494 | wrBlock->succedents[0]->params[2].v = psID; |
| 495 | wrBlock->succedents[0]->params[3].v = RF_CREATE_PARAM3(RF_IO_NORMAL_PRIORITY, which_ru); |
| 496 | memset((char *) &tracerec, 0, sizeof(tracerec)); |
| 497 | wr_dag_h->tracerec = &tracerec; |
| 498 | #if RF_DEBUG_VALIDATE_DAG |
| 499 | if (rf_verifyParityDebug) { |
| 500 | printf("Dag of write new second redundant information in parity verify :\n" ); |
| 501 | rf_PrintDAGList(wr_dag_h); |
| 502 | } |
| 503 | #endif |
| 504 | RF_LOCK_MCPAIR(mcpair); |
| 505 | mcpair->flag = 0; |
| 506 | rf_DispatchDAG(wr_dag_h, (void (*) (void *)) rf_MCPairWakeupFunc, |
| 507 | (void *) mcpair); |
| 508 | while (!mcpair->flag) |
| 509 | RF_WAIT_MCPAIR(mcpair); |
| 510 | RF_UNLOCK_MCPAIR(mcpair); |
| 511 | if (wr_dag_h->status != rf_enable) { |
| 512 | RF_ERRORMSG("Unable to correct second redundant information in VerifyParity: can't write the stripe\n" ); |
| 513 | red2_cant_correct = RF_TRUE; |
| 514 | } else { |
| 515 | red2_corrected = RF_TRUE; |
| 516 | } |
| 517 | rf_FreeDAG(wr_dag_h); |
| 518 | } |
| 519 | if ((redundantOneErr && parity_cant_correct) || |
| 520 | (redundantTwoErr && red2_cant_correct)) |
| 521 | retcode = RF_PARITY_COULD_NOT_CORRECT; |
| 522 | if ((retcode = RF_PARITY_BAD) && parity_corrected && red2_corrected) |
| 523 | retcode = RF_PARITY_CORRECTED; |
| 524 | |
| 525 | |
| 526 | out: |
| 527 | rf_FreeAccessStripeMap(asm_h); |
| 528 | rf_FreeAllocList(alloclist); |
| 529 | rf_FreeDAG(rd_dag_h); |
| 530 | rf_FreeMCPair(mcpair); |
| 531 | return (retcode); |
| 532 | } |
| 533 | #endif /* RF_INCLUDE_EVENODD > 0 */ |
| 534 | |