1 1.18 oster /* $NetBSD: rf_pq.c,v 1.18 2023/10/15 18:15:20 oster Exp $ */ 2 1.1 oster /* 3 1.1 oster * Copyright (c) 1995 Carnegie-Mellon University. 4 1.1 oster * All rights reserved. 5 1.1 oster * 6 1.1 oster * Author: Daniel Stodolsky 7 1.1 oster * 8 1.1 oster * Permission to use, copy, modify and distribute this software and 9 1.1 oster * its documentation is hereby granted, provided that both the copyright 10 1.1 oster * notice and this permission notice appear in all copies of the 11 1.1 oster * software, derivative works or modified versions, and any portions 12 1.1 oster * thereof, and that both notices appear in supporting documentation. 13 1.1 oster * 14 1.1 oster * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 1.1 oster * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 16 1.1 oster * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 1.1 oster * 18 1.1 oster * Carnegie Mellon requests users of this software to return to 19 1.1 oster * 20 1.1 oster * Software Distribution Coordinator or Software.Distribution (at) CS.CMU.EDU 21 1.1 oster * School of Computer Science 22 1.1 oster * Carnegie Mellon University 23 1.1 oster * Pittsburgh PA 15213-3890 24 1.1 oster * 25 1.1 oster * any improvements or extensions that they make and grant Carnegie the 26 1.1 oster * rights to redistribute these changes. 27 1.1 oster */ 28 1.1 oster 29 1.1 oster /* 30 1.1 oster * Code for RAID level 6 (P + Q) disk array architecture. 31 1.1 oster */ 32 1.11 lukem 33 1.11 lukem #include <sys/cdefs.h> 34 1.18 oster __KERNEL_RCSID(0, "$NetBSD: rf_pq.c,v 1.18 2023/10/15 18:15:20 oster Exp $"); 35 1.1 oster 36 1.1 oster #include "rf_archs.h" 37 1.8 oster 38 1.8 oster #if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0) || (RF_INCLUDE_EVENODD > 0) 39 1.8 oster 40 1.10 oster #include <dev/raidframe/raidframevar.h> 41 1.10 oster 42 1.1 oster #include "rf_raid.h" 43 1.1 oster #include "rf_dag.h" 44 1.1 oster #include "rf_dagffrd.h" 45 1.1 oster #include "rf_dagffwr.h" 46 1.1 oster #include "rf_dagdegrd.h" 47 1.1 oster #include "rf_dagdegwr.h" 48 1.1 oster #include "rf_dagutils.h" 49 1.1 oster #include "rf_dagfuncs.h" 50 1.1 oster #include "rf_etimer.h" 51 1.1 oster #include "rf_pqdeg.h" 52 1.1 oster #include "rf_general.h" 53 1.1 oster #include "rf_map.h" 54 1.1 oster #include "rf_pq.h" 55 1.1 oster 56 1.3 oster RF_RedFuncs_t rf_pFuncs = {rf_RegularONPFunc, "Regular Old-New P", rf_SimpleONPFunc, "Simple Old-New P"}; 57 1.3 oster RF_RedFuncs_t rf_pRecoveryFuncs = {rf_RecoveryPFunc, "Recovery P Func", rf_RecoveryPFunc, "Recovery P Func"}; 58 1.1 oster 59 1.17 christos void 60 1.16 dsl rf_RegularONPFunc(RF_DagNode_t *node) 61 1.1 oster { 62 1.17 christos rf_RegularXorFunc(node); 63 1.1 oster } 64 1.1 oster /* 65 1.3 oster same as simpleONQ func, but the coefficient is always 1 66 1.1 oster */ 67 1.1 oster 68 1.17 christos void 69 1.16 dsl rf_SimpleONPFunc(RF_DagNode_t *node) 70 1.1 oster { 71 1.17 christos rf_SimpleXorFunc(node); 72 1.1 oster } 73 1.1 oster 74 1.17 christos void 75 1.16 dsl rf_RecoveryPFunc(RF_DagNode_t *node) 76 1.1 oster { 77 1.17 christos rf_RecoveryXorFunc(node); 78 1.1 oster } 79 1.1 oster 80 1.17 christos void 81 1.16 dsl rf_RegularPFunc(RF_DagNode_t *node) 82 1.1 oster { 83 1.17 christos rf_RegularXorFunc(node); 84 1.1 oster } 85 1.8 oster #endif /* (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0) || (RF_INCLUDE_EVENODD > 0) */ 86 1.1 oster #if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0) 87 1.1 oster 88 1.14 perry static void 89 1.3 oster QDelta(char *dest, char *obuf, char *nbuf, unsigned length, 90 1.3 oster unsigned char coeff); 91 1.14 perry static void 92 1.3 oster rf_InvertQ(unsigned long *qbuf, unsigned long *abuf, 93 1.3 oster unsigned length, unsigned coeff); 94 1.3 oster 95 1.3 oster RF_RedFuncs_t rf_qFuncs = {rf_RegularONQFunc, "Regular Old-New Q", rf_SimpleONQFunc, "Simple Old-New Q"}; 96 1.3 oster RF_RedFuncs_t rf_qRecoveryFuncs = {rf_RecoveryQFunc, "Recovery Q Func", rf_RecoveryQFunc, "Recovery Q Func"}; 97 1.3 oster RF_RedFuncs_t rf_pqRecoveryFuncs = {rf_RecoveryPQFunc, "Recovery PQ Func", rf_RecoveryPQFunc, "Recovery PQ Func"}; 98 1.3 oster 99 1.14 perry void 100 1.3 oster rf_PQDagSelect( 101 1.3 oster RF_Raid_t * raidPtr, 102 1.3 oster RF_IoType_t type, 103 1.3 oster RF_AccessStripeMap_t * asmap, 104 1.3 oster RF_VoidFuncPtr * createFunc) 105 1.3 oster { 106 1.3 oster RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout); 107 1.3 oster unsigned ndfail = asmap->numDataFailed; 108 1.3 oster unsigned npfail = asmap->numParityFailed; 109 1.3 oster unsigned ntfail = npfail + ndfail; 110 1.3 oster 111 1.3 oster RF_ASSERT(RF_IO_IS_R_OR_W(type)); 112 1.3 oster if (ntfail > 2) { 113 1.3 oster RF_ERRORMSG("more than two disks failed in a single group! Aborting I/O operation.\n"); 114 1.13 oster *createFunc = NULL; 115 1.3 oster return; 116 1.3 oster } 117 1.3 oster /* ok, we can do this I/O */ 118 1.3 oster if (type == RF_IO_TYPE_READ) { 119 1.3 oster switch (ndfail) { 120 1.3 oster case 0: 121 1.3 oster /* fault free read */ 122 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG; /* same as raid 5 */ 123 1.3 oster break; 124 1.3 oster case 1: 125 1.3 oster /* lost a single data unit */ 126 1.3 oster /* two cases: (1) parity is not lost. do a normal raid 127 1.3 oster * 5 reconstruct read. (2) parity is lost. do a 128 1.3 oster * reconstruct read using "q". */ 129 1.3 oster if (ntfail == 2) { /* also lost redundancy */ 130 1.3 oster if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY) 131 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_110_CreateReadDAG; 132 1.3 oster else 133 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_101_CreateReadDAG; 134 1.3 oster } else { 135 1.3 oster /* P and Q are ok. But is there a failure in 136 1.3 oster * some unaccessed data unit? */ 137 1.3 oster if (rf_NumFailedDataUnitsInStripe(raidPtr, asmap) == 2) 138 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_200_CreateReadDAG; 139 1.3 oster else 140 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_100_CreateReadDAG; 141 1.3 oster } 142 1.3 oster break; 143 1.3 oster case 2: 144 1.3 oster /* lost two data units */ 145 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_200_CreateReadDAG; 146 1.3 oster break; 147 1.3 oster } 148 1.3 oster return; 149 1.3 oster } 150 1.3 oster /* a write */ 151 1.3 oster switch (ntfail) { 152 1.3 oster case 0: /* fault free */ 153 1.3 oster if (rf_suppressLocksAndLargeWrites || 154 1.3 oster (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) && (layoutPtr->numDataCol != 1)) || 155 1.3 oster (asmap->parityInfo->next != NULL) || (asmap->qInfo->next != NULL) || rf_CheckStripeForFailures(raidPtr, asmap))) { 156 1.3 oster 157 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQCreateSmallWriteDAG; 158 1.3 oster } else { 159 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQCreateLargeWriteDAG; 160 1.3 oster } 161 1.3 oster break; 162 1.3 oster 163 1.3 oster case 1: /* single disk fault */ 164 1.3 oster if (npfail == 1) { 165 1.3 oster RF_ASSERT((asmap->failedPDAs[0]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q)); 166 1.3 oster if (asmap->failedPDAs[0]->type == RF_PDA_TYPE_Q) { /* q died, treat like 167 1.3 oster * normal mode raid5 168 1.3 oster * write. */ 169 1.3 oster if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1)) 170 1.3 oster || rf_NumFailedDataUnitsInStripe(raidPtr, asmap)) 171 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_001_CreateSmallWriteDAG; 172 1.3 oster else 173 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_001_CreateLargeWriteDAG; 174 1.3 oster } else {/* parity died, small write only updating Q */ 175 1.3 oster if (((asmap->numStripeUnitsAccessed <= (layoutPtr->numDataCol / 2)) || (asmap->numStripeUnitsAccessed == 1)) 176 1.3 oster || rf_NumFailedDataUnitsInStripe(raidPtr, asmap)) 177 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_010_CreateSmallWriteDAG; 178 1.3 oster else 179 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_010_CreateLargeWriteDAG; 180 1.3 oster } 181 1.3 oster } else { /* data missing. Do a P reconstruct write if 182 1.3 oster * only a single data unit is lost in the 183 1.3 oster * stripe, otherwise a PQ reconstruct write. */ 184 1.3 oster if (rf_NumFailedDataUnitsInStripe(raidPtr, asmap) == 2) 185 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_200_CreateWriteDAG; 186 1.3 oster else 187 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_100_CreateWriteDAG; 188 1.3 oster } 189 1.3 oster break; 190 1.3 oster 191 1.3 oster case 2: /* two disk faults */ 192 1.3 oster switch (npfail) { 193 1.3 oster case 2: /* both p and q dead */ 194 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_011_CreateWriteDAG; 195 1.3 oster break; 196 1.3 oster case 1: /* either p or q and dead data */ 197 1.3 oster RF_ASSERT(asmap->failedPDAs[0]->type == RF_PDA_TYPE_DATA); 198 1.3 oster RF_ASSERT((asmap->failedPDAs[1]->type == RF_PDA_TYPE_PARITY) || (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q)); 199 1.3 oster if (asmap->failedPDAs[1]->type == RF_PDA_TYPE_Q) 200 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_101_CreateWriteDAG; 201 1.3 oster else 202 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_110_CreateWriteDAG; 203 1.3 oster break; 204 1.3 oster case 0: /* double data loss */ 205 1.5 oster *createFunc = (RF_VoidFuncPtr) rf_PQ_200_CreateWriteDAG; 206 1.3 oster break; 207 1.3 oster } 208 1.3 oster break; 209 1.3 oster 210 1.3 oster default: /* more than 2 disk faults */ 211 1.3 oster *createFunc = NULL; 212 1.3 oster RF_PANIC(); 213 1.3 oster } 214 1.3 oster return; 215 1.3 oster } 216 1.3 oster /* 217 1.3 oster Used as a stop gap info function 218 1.3 oster */ 219 1.5 oster #if 0 220 1.14 perry static void 221 1.16 dsl PQOne(RF_Raid_t *raidPtr, int *nSucc, int *nAnte, RF_AccessStripeMap_t *asmap) 222 1.1 oster { 223 1.3 oster *nSucc = *nAnte = 1; 224 1.1 oster } 225 1.1 oster 226 1.14 perry static void 227 1.16 dsl PQOneTwo(RF_Raid_t *raidPtr, int *nSucc, int *nAnte, RF_AccessStripeMap_t *asmap) 228 1.3 oster { 229 1.3 oster *nSucc = 1; 230 1.3 oster *nAnte = 2; 231 1.3 oster } 232 1.5 oster #endif 233 1.5 oster 234 1.1 oster RF_CREATE_DAG_FUNC_DECL(rf_PQCreateLargeWriteDAG) 235 1.1 oster { 236 1.3 oster rf_CommonCreateLargeWriteDAG(raidPtr, asmap, dag_h, bp, flags, allocList, 2, 237 1.3 oster rf_RegularPQFunc, RF_FALSE); 238 1.1 oster } 239 1.1 oster 240 1.18 oster void 241 1.16 dsl rf_RegularONQFunc(RF_DagNode_t *node) 242 1.3 oster { 243 1.3 oster int np = node->numParams; 244 1.3 oster int d; 245 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p; 246 1.3 oster int i; 247 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 248 1.3 oster RF_Etimer_t timer; 249 1.3 oster char *qbuf, *qpbuf; 250 1.3 oster char *obuf, *nbuf; 251 1.3 oster RF_PhysDiskAddr_t *old, *new; 252 1.3 oster unsigned long coeff; 253 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit; 254 1.3 oster 255 1.3 oster RF_ETIMER_START(timer); 256 1.3 oster 257 1.3 oster d = (np - 3) / 4; 258 1.3 oster RF_ASSERT(4 * d + 3 == np); 259 1.3 oster qbuf = (char *) node->params[2 * d + 1].p; /* q buffer */ 260 1.3 oster for (i = 0; i < d; i++) { 261 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p; 262 1.3 oster obuf = (char *) node->params[2 * i + 1].p; 263 1.3 oster new = (RF_PhysDiskAddr_t *) node->params[2 * (d + 1 + i)].p; 264 1.3 oster nbuf = (char *) node->params[2 * (d + 1 + i) + 1].p; 265 1.3 oster RF_ASSERT(new->numSector == old->numSector); 266 1.3 oster RF_ASSERT(new->raidAddress == old->raidAddress); 267 1.3 oster /* the stripe unit within the stripe tells us the coefficient 268 1.3 oster * to use for the multiply. */ 269 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), new->raidAddress); 270 1.3 oster /* compute the data unit offset within the column, then add 271 1.3 oster * one */ 272 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol); 273 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, old->startSector % secPerSU); 274 1.3 oster QDelta(qpbuf, obuf, nbuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff); 275 1.3 oster } 276 1.3 oster 277 1.3 oster RF_ETIMER_STOP(timer); 278 1.3 oster RF_ETIMER_EVAL(timer); 279 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer); 280 1.3 oster rf_GenericWakeupFunc(node, 0); /* call wake func explicitly since no 281 1.3 oster * I/O in this node */ 282 1.1 oster } 283 1.1 oster /* 284 1.1 oster See the SimpleXORFunc for the difference between a simple and regular func. 285 1.3 oster These Q functions should be used for 286 1.3 oster 287 1.3 oster new q = Q(data,old data,old q) 288 1.1 oster 289 1.3 oster style updates and not for 290 1.1 oster 291 1.1 oster q = ( new data, new data, .... ) 292 1.1 oster 293 1.1 oster computations. 294 1.1 oster 295 1.1 oster The simple q takes 2(2d+1)+1 params, where d is the number 296 1.1 oster of stripes written. The order of params is 297 1.1 oster old data pda_0, old data buffer_0, old data pda_1, old data buffer_1, ... old data pda_d, old data buffer_d 298 1.1 oster [2d] old q pda_0, old q buffer 299 1.1 oster [2d_2] new data pda_0, new data buffer_0, ... new data pda_d, new data buffer_d 300 1.1 oster raidPtr 301 1.1 oster */ 302 1.1 oster 303 1.18 oster void 304 1.16 dsl rf_SimpleONQFunc(RF_DagNode_t *node) 305 1.3 oster { 306 1.3 oster int np = node->numParams; 307 1.3 oster int d; 308 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p; 309 1.3 oster int i; 310 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 311 1.3 oster RF_Etimer_t timer; 312 1.3 oster char *qbuf; 313 1.3 oster char *obuf, *nbuf; 314 1.3 oster RF_PhysDiskAddr_t *old, *new; 315 1.3 oster unsigned long coeff; 316 1.3 oster 317 1.3 oster RF_ETIMER_START(timer); 318 1.3 oster 319 1.3 oster d = (np - 3) / 4; 320 1.3 oster RF_ASSERT(4 * d + 3 == np); 321 1.3 oster qbuf = (char *) node->params[2 * d + 1].p; /* q buffer */ 322 1.3 oster for (i = 0; i < d; i++) { 323 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p; 324 1.3 oster obuf = (char *) node->params[2 * i + 1].p; 325 1.3 oster new = (RF_PhysDiskAddr_t *) node->params[2 * (d + 1 + i)].p; 326 1.3 oster nbuf = (char *) node->params[2 * (d + 1 + i) + 1].p; 327 1.3 oster RF_ASSERT(new->numSector == old->numSector); 328 1.3 oster RF_ASSERT(new->raidAddress == old->raidAddress); 329 1.3 oster /* the stripe unit within the stripe tells us the coefficient 330 1.3 oster * to use for the multiply. */ 331 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), new->raidAddress); 332 1.3 oster /* compute the data unit offset within the column, then add 333 1.3 oster * one */ 334 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol); 335 1.3 oster QDelta(qbuf, obuf, nbuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff); 336 1.3 oster } 337 1.3 oster 338 1.3 oster RF_ETIMER_STOP(timer); 339 1.3 oster RF_ETIMER_EVAL(timer); 340 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer); 341 1.3 oster rf_GenericWakeupFunc(node, 0); /* call wake func explicitly since no 342 1.3 oster * I/O in this node */ 343 1.1 oster } 344 1.1 oster RF_CREATE_DAG_FUNC_DECL(rf_PQCreateSmallWriteDAG) 345 1.1 oster { 346 1.3 oster rf_CommonCreateSmallWriteDAG(raidPtr, asmap, dag_h, bp, flags, allocList, &rf_pFuncs, &rf_qFuncs); 347 1.1 oster } 348 1.1 oster 349 1.5 oster static void RegularQSubr(RF_DagNode_t *node, char *qbuf); 350 1.5 oster 351 1.14 perry static void 352 1.16 dsl RegularQSubr(RF_DagNode_t *node, char *qbuf) 353 1.3 oster { 354 1.3 oster int np = node->numParams; 355 1.3 oster int d; 356 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p; 357 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit; 358 1.3 oster int i; 359 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 360 1.3 oster RF_Etimer_t timer; 361 1.3 oster char *obuf, *qpbuf; 362 1.3 oster RF_PhysDiskAddr_t *old; 363 1.3 oster unsigned long coeff; 364 1.3 oster 365 1.3 oster RF_ETIMER_START(timer); 366 1.3 oster 367 1.3 oster d = (np - 1) / 2; 368 1.3 oster RF_ASSERT(2 * d + 1 == np); 369 1.3 oster for (i = 0; i < d; i++) { 370 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p; 371 1.3 oster obuf = (char *) node->params[2 * i + 1].p; 372 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), old->raidAddress); 373 1.3 oster /* compute the data unit offset within the column, then add 374 1.3 oster * one */ 375 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol); 376 1.3 oster /* the input buffers may not all be aligned with the start of 377 1.3 oster * the stripe. so shift by their sector offset within the 378 1.3 oster * stripe unit */ 379 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, old->startSector % secPerSU); 380 1.3 oster rf_IncQ((unsigned long *) qpbuf, (unsigned long *) obuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff); 381 1.3 oster } 382 1.3 oster 383 1.3 oster RF_ETIMER_STOP(timer); 384 1.3 oster RF_ETIMER_EVAL(timer); 385 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer); 386 1.1 oster } 387 1.1 oster /* 388 1.1 oster used in degraded writes. 389 1.1 oster */ 390 1.1 oster 391 1.5 oster static void DegrQSubr(RF_DagNode_t *node); 392 1.5 oster 393 1.14 perry static void 394 1.16 dsl DegrQSubr(RF_DagNode_t *node) 395 1.3 oster { 396 1.3 oster int np = node->numParams; 397 1.3 oster int d; 398 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p; 399 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit; 400 1.3 oster int i; 401 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 402 1.3 oster RF_Etimer_t timer; 403 1.3 oster char *qbuf = node->results[1]; 404 1.3 oster char *obuf, *qpbuf; 405 1.3 oster RF_PhysDiskAddr_t *old; 406 1.3 oster unsigned long coeff; 407 1.3 oster unsigned fail_start; 408 1.3 oster int j; 409 1.3 oster 410 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[np - 2].p; 411 1.3 oster fail_start = old->startSector % secPerSU; 412 1.3 oster 413 1.3 oster RF_ETIMER_START(timer); 414 1.3 oster 415 1.3 oster d = (np - 2) / 2; 416 1.3 oster RF_ASSERT(2 * d + 2 == np); 417 1.3 oster for (i = 0; i < d; i++) { 418 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p; 419 1.3 oster obuf = (char *) node->params[2 * i + 1].p; 420 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), old->raidAddress); 421 1.3 oster /* compute the data unit offset within the column, then add 422 1.3 oster * one */ 423 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol); 424 1.3 oster /* the input buffers may not all be aligned with the start of 425 1.3 oster * the stripe. so shift by their sector offset within the 426 1.3 oster * stripe unit */ 427 1.3 oster j = old->startSector % secPerSU; 428 1.3 oster RF_ASSERT(j >= fail_start); 429 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, j - fail_start); 430 1.3 oster rf_IncQ((unsigned long *) qpbuf, (unsigned long *) obuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff); 431 1.3 oster } 432 1.3 oster 433 1.3 oster RF_ETIMER_STOP(timer); 434 1.3 oster RF_ETIMER_EVAL(timer); 435 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer); 436 1.1 oster } 437 1.1 oster /* 438 1.1 oster Called by large write code to compute the new parity and the new q. 439 1.3 oster 440 1.1 oster structure of the params: 441 1.1 oster 442 1.1 oster pda_0, buffer_0, pda_1 , buffer_1, ... , pda_d, buffer_d ( d = numDataCol 443 1.3 oster raidPtr 444 1.1 oster 445 1.1 oster for a total of 2d+1 arguments. 446 1.1 oster The result buffers results[0], results[1] are the buffers for the p and q, 447 1.1 oster respectively. 448 1.1 oster 449 1.1 oster We compute Q first, then compute P. The P calculation may try to reuse 450 1.1 oster one of the input buffers for its output, so if we computed P first, we would 451 1.1 oster corrupt the input for the q calculation. 452 1.1 oster */ 453 1.1 oster 454 1.18 oster void 455 1.16 dsl rf_RegularPQFunc(RF_DagNode_t *node) 456 1.3 oster { 457 1.3 oster RegularQSubr(node, node->results[1]); 458 1.18 oster rf_RegularXorFunc(node); /* does the wakeup */ 459 1.3 oster } 460 1.3 oster 461 1.18 oster void 462 1.16 dsl rf_RegularQFunc(RF_DagNode_t *node) 463 1.3 oster { 464 1.3 oster /* Almost ... adjust Qsubr args */ 465 1.3 oster RegularQSubr(node, node->results[0]); 466 1.3 oster rf_GenericWakeupFunc(node, 0); /* call wake func explicitly since no 467 1.3 oster * I/O in this node */ 468 1.1 oster } 469 1.1 oster /* 470 1.1 oster Called by singly degraded write code to compute the new parity and the new q. 471 1.3 oster 472 1.1 oster structure of the params: 473 1.1 oster 474 1.3 oster pda_0, buffer_0, pda_1 , buffer_1, ... , pda_d, buffer_d 475 1.3 oster failedPDA raidPtr 476 1.1 oster 477 1.1 oster for a total of 2d+2 arguments. 478 1.1 oster The result buffers results[0], results[1] are the buffers for the parity and q, 479 1.1 oster respectively. 480 1.1 oster 481 1.1 oster We compute Q first, then compute parity. The parity calculation may try to reuse 482 1.1 oster one of the input buffers for its output, so if we computed parity first, we would 483 1.1 oster corrupt the input for the q calculation. 484 1.1 oster 485 1.1 oster We treat this identically to the regularPQ case, ignoring the failedPDA extra argument. 486 1.1 oster */ 487 1.1 oster 488 1.14 perry void 489 1.16 dsl rf_Degraded_100_PQFunc(RF_DagNode_t *node) 490 1.3 oster { 491 1.3 oster int np = node->numParams; 492 1.3 oster 493 1.3 oster RF_ASSERT(np >= 2); 494 1.3 oster DegrQSubr(node); 495 1.3 oster rf_RecoveryXorFunc(node); 496 1.1 oster } 497 1.1 oster 498 1.1 oster 499 1.1 oster /* 500 1.1 oster The two below are used when reading a stripe with a single lost data unit. 501 1.1 oster The parameters are 502 1.1 oster 503 1.1 oster pda_0, buffer_0, .... pda_n, buffer_n, P pda, P buffer, failedPDA, raidPtr 504 1.1 oster 505 1.1 oster and results[0] contains the data buffer. Which is originally zero-filled. 506 1.3 oster 507 1.1 oster */ 508 1.1 oster 509 1.1 oster /* this Q func is used by the degraded-mode dag functions to recover lost data. 510 1.1 oster * the second-to-last parameter is the PDA for the failed portion of the access. 511 1.1 oster * the code here looks at this PDA and assumes that the xor target buffer is 512 1.1 oster * equal in size to the number of sectors in the failed PDA. It then uses 513 1.1 oster * the other PDAs in the parameter list to determine where within the target 514 1.1 oster * buffer the corresponding data should be xored. 515 1.1 oster * 516 1.3 oster * Recall the basic equation is 517 1.3 oster * 518 1.1 oster * Q = ( data_1 + 2 * data_2 ... + k * data_k ) mod 256 519 1.1 oster * 520 1.1 oster * so to recover data_j we need 521 1.1 oster * 522 1.1 oster * J data_j = (Q - data_1 - 2 data_2 ....- k* data_k) mod 256 523 1.1 oster * 524 1.1 oster * So the coefficient for each buffer is (255 - data_col), and j should be initialized by 525 1.1 oster * copying Q into it. Then we need to do a table lookup to convert to solve 526 1.1 oster * data_j /= J 527 1.3 oster * 528 1.3 oster * 529 1.1 oster */ 530 1.18 oster void 531 1.16 dsl rf_RecoveryQFunc(RF_DagNode_t *node) 532 1.3 oster { 533 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 534 1.3 oster RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout; 535 1.3 oster RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *) node->params[node->numParams - 2].p; 536 1.3 oster int i; 537 1.18 oster RF_PhysDiskAddr_t *pda = NULL; 538 1.3 oster RF_RaidAddr_t suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr, failedPDA->startSector); 539 1.3 oster char *srcbuf, *destbuf; 540 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 541 1.3 oster RF_Etimer_t timer; 542 1.3 oster unsigned long coeff; 543 1.3 oster 544 1.3 oster RF_ETIMER_START(timer); 545 1.3 oster /* start by copying Q into the buffer */ 546 1.12 wiz memcpy(node->results[0], node->params[node->numParams - 3].p, 547 1.3 oster rf_RaidAddressToByte(raidPtr, failedPDA->numSector)); 548 1.3 oster for (i = 0; i < node->numParams - 4; i += 2) { 549 1.3 oster RF_ASSERT(node->params[i + 1].p != node->results[0]); 550 1.3 oster pda = (RF_PhysDiskAddr_t *) node->params[i].p; 551 1.3 oster srcbuf = (char *) node->params[i + 1].p; 552 1.3 oster suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector); 553 1.3 oster destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr, suoffset - failedSUOffset); 554 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), pda->raidAddress); 555 1.3 oster /* compute the data unit offset within the column */ 556 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol); 557 1.3 oster rf_IncQ((unsigned long *) destbuf, (unsigned long *) srcbuf, rf_RaidAddressToByte(raidPtr, pda->numSector), coeff); 558 1.3 oster } 559 1.3 oster /* Do the nasty inversion now */ 560 1.3 oster coeff = (rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), failedPDA->startSector) % raidPtr->Layout.numDataCol); 561 1.3 oster rf_InvertQ(node->results[0], node->results[0], rf_RaidAddressToByte(raidPtr, pda->numSector), coeff); 562 1.3 oster RF_ETIMER_STOP(timer); 563 1.3 oster RF_ETIMER_EVAL(timer); 564 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer); 565 1.3 oster rf_GenericWakeupFunc(node, 0); 566 1.3 oster } 567 1.3 oster 568 1.18 oster void 569 1.16 dsl rf_RecoveryPQFunc(RF_DagNode_t *node) 570 1.1 oster { 571 1.6 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p; 572 1.6 oster printf("raid%d: Recovery from PQ not implemented.\n",raidPtr->raidid); 573 1.18 oster /* XXX: Was: */ 574 1.18 oster /* return (1); */ 575 1.1 oster } 576 1.1 oster /* 577 1.3 oster Degraded write Q subroutine. 578 1.1 oster Used when P is dead. 579 1.3 oster Large-write style Q computation. 580 1.1 oster Parameters 581 1.1 oster 582 1.1 oster (pda,buf),(pda,buf),.....,(failedPDA,bufPtr),failedPDA,raidPtr. 583 1.1 oster 584 1.1 oster We ignore failedPDA. 585 1.1 oster 586 1.1 oster This is a "simple style" recovery func. 587 1.1 oster */ 588 1.1 oster 589 1.14 perry void 590 1.16 dsl rf_PQ_DegradedWriteQFunc(RF_DagNode_t *node) 591 1.3 oster { 592 1.3 oster int np = node->numParams; 593 1.3 oster int d; 594 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p; 595 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit; 596 1.3 oster int i; 597 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec; 598 1.3 oster RF_Etimer_t timer; 599 1.3 oster char *qbuf = node->results[0]; 600 1.3 oster char *obuf, *qpbuf; 601 1.3 oster RF_PhysDiskAddr_t *old; 602 1.3 oster unsigned long coeff; 603 1.3 oster int fail_start, j; 604 1.3 oster 605 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[np - 2].p; 606 1.3 oster fail_start = old->startSector % secPerSU; 607 1.3 oster 608 1.3 oster RF_ETIMER_START(timer); 609 1.3 oster 610 1.3 oster d = (np - 2) / 2; 611 1.3 oster RF_ASSERT(2 * d + 2 == np); 612 1.3 oster 613 1.3 oster for (i = 0; i < d; i++) { 614 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p; 615 1.3 oster obuf = (char *) node->params[2 * i + 1].p; 616 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), old->raidAddress); 617 1.3 oster /* compute the data unit offset within the column, then add 618 1.3 oster * one */ 619 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol); 620 1.3 oster j = old->startSector % secPerSU; 621 1.3 oster RF_ASSERT(j >= fail_start); 622 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, j - fail_start); 623 1.3 oster rf_IncQ((unsigned long *) qpbuf, (unsigned long *) obuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff); 624 1.3 oster } 625 1.3 oster 626 1.3 oster RF_ETIMER_STOP(timer); 627 1.3 oster RF_ETIMER_EVAL(timer); 628 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer); 629 1.3 oster rf_GenericWakeupFunc(node, 0); 630 1.1 oster } 631 1.1 oster 632 1.1 oster 633 1.1 oster 634 1.1 oster 635 1.1 oster /* Q computations */ 636 1.1 oster 637 1.1 oster /* 638 1.1 oster coeff - colummn; 639 1.1 oster 640 1.1 oster compute dest ^= qfor[28-coeff][rn[coeff+1] a] 641 1.1 oster 642 1.1 oster on 5-bit basis; 643 1.1 oster length in bytes; 644 1.1 oster */ 645 1.1 oster 646 1.14 perry void 647 1.16 dsl rf_IncQ(unsigned long *dest, unsigned long *buf, unsigned length, unsigned coeff) 648 1.3 oster { 649 1.3 oster unsigned long a, d, new; 650 1.3 oster unsigned long a1, a2; 651 1.3 oster unsigned int *q = &(rf_qfor[28 - coeff][0]); 652 1.3 oster unsigned r = rf_rn[coeff + 1]; 653 1.1 oster 654 1.1 oster #define EXTRACT(a,i) ((a >> (5L*i)) & 0x1f) 655 1.1 oster #define INSERT(a,i) (a << (5L*i)) 656 1.1 oster 657 1.3 oster length /= 8; 658 1.3 oster /* 13 5 bit quants in a 64 bit word */ 659 1.3 oster while (length) { 660 1.3 oster a = *buf++; 661 1.3 oster d = *dest; 662 1.3 oster a1 = EXTRACT(a, 0) ^ r; 663 1.3 oster a2 = EXTRACT(a, 1) ^ r; 664 1.3 oster new = INSERT(a2, 1) | a1; 665 1.3 oster a1 = EXTRACT(a, 2) ^ r; 666 1.3 oster a2 = EXTRACT(a, 3) ^ r; 667 1.3 oster a1 = q[a1]; 668 1.3 oster a2 = q[a2]; 669 1.3 oster new = new | INSERT(a1, 2) | INSERT(a2, 3); 670 1.3 oster a1 = EXTRACT(a, 4) ^ r; 671 1.3 oster a2 = EXTRACT(a, 5) ^ r; 672 1.3 oster a1 = q[a1]; 673 1.3 oster a2 = q[a2]; 674 1.3 oster new = new | INSERT(a1, 4) | INSERT(a2, 5); 675 1.3 oster a1 = EXTRACT(a, 5) ^ r; 676 1.3 oster a2 = EXTRACT(a, 6) ^ r; 677 1.3 oster a1 = q[a1]; 678 1.3 oster a2 = q[a2]; 679 1.3 oster new = new | INSERT(a1, 5) | INSERT(a2, 6); 680 1.1 oster #if RF_LONGSHIFT > 2 681 1.3 oster a1 = EXTRACT(a, 7) ^ r; 682 1.3 oster a2 = EXTRACT(a, 8) ^ r; 683 1.3 oster a1 = q[a1]; 684 1.3 oster a2 = q[a2]; 685 1.3 oster new = new | INSERT(a1, 7) | INSERT(a2, 8); 686 1.3 oster a1 = EXTRACT(a, 9) ^ r; 687 1.3 oster a2 = EXTRACT(a, 10) ^ r; 688 1.3 oster a1 = q[a1]; 689 1.3 oster a2 = q[a2]; 690 1.3 oster new = new | INSERT(a1, 9) | INSERT(a2, 10); 691 1.3 oster a1 = EXTRACT(a, 11) ^ r; 692 1.3 oster a2 = EXTRACT(a, 12) ^ r; 693 1.3 oster a1 = q[a1]; 694 1.3 oster a2 = q[a2]; 695 1.3 oster new = new | INSERT(a1, 11) | INSERT(a2, 12); 696 1.3 oster #endif /* RF_LONGSHIFT > 2 */ 697 1.3 oster d ^= new; 698 1.3 oster *dest++ = d; 699 1.3 oster length--; 700 1.3 oster } 701 1.1 oster } 702 1.3 oster /* 703 1.3 oster compute 704 1.1 oster 705 1.1 oster dest ^= rf_qfor[28-coeff][rf_rn[coeff+1] (old^new) ] 706 1.1 oster 707 1.1 oster on a five bit basis. 708 1.1 oster optimization: compute old ^ new on 64 bit basis. 709 1.1 oster 710 1.1 oster length in bytes. 711 1.1 oster */ 712 1.1 oster 713 1.14 perry static void 714 1.3 oster QDelta( 715 1.3 oster char *dest, 716 1.3 oster char *obuf, 717 1.3 oster char *nbuf, 718 1.3 oster unsigned length, 719 1.3 oster unsigned char coeff) 720 1.3 oster { 721 1.18 oster #ifndef _KERNEL 722 1.3 oster unsigned long a, d, new; 723 1.3 oster unsigned long a1, a2; 724 1.3 oster unsigned int *q = &(rf_qfor[28 - coeff][0]); 725 1.5 oster unsigned int r = rf_rn[coeff + 1]; 726 1.5 oster 727 1.5 oster r = a1 = a2 = new = d = a = 0; /* XXX for now... */ 728 1.5 oster q = NULL; /* XXX for now */ 729 1.18 oster #endif 730 1.2 oster #ifdef _KERNEL 731 1.3 oster /* PQ in kernel currently not supported because the encoding/decoding 732 1.3 oster * table is not present */ 733 1.9 thorpej memset(dest, 0, length); 734 1.3 oster #else /* KERNEL */ 735 1.3 oster /* this code probably doesn't work and should be rewritten -wvcii */ 736 1.3 oster /* 13 5 bit quants in a 64 bit word */ 737 1.3 oster length /= 8; 738 1.3 oster while (length) { 739 1.3 oster a = *obuf++; /* XXX need to reorg to avoid cache conflicts */ 740 1.3 oster a ^= *nbuf++; 741 1.3 oster d = *dest; 742 1.3 oster a1 = EXTRACT(a, 0) ^ r; 743 1.3 oster a2 = EXTRACT(a, 1) ^ r; 744 1.3 oster a1 = q[a1]; 745 1.3 oster a2 = q[a2]; 746 1.3 oster new = INSERT(a2, 1) | a1; 747 1.3 oster a1 = EXTRACT(a, 2) ^ r; 748 1.3 oster a2 = EXTRACT(a, 3) ^ r; 749 1.3 oster a1 = q[a1]; 750 1.3 oster a2 = q[a2]; 751 1.3 oster new = new | INSERT(a1, 2) | INSERT(a2, 3); 752 1.3 oster a1 = EXTRACT(a, 4) ^ r; 753 1.3 oster a2 = EXTRACT(a, 5) ^ r; 754 1.3 oster a1 = q[a1]; 755 1.3 oster a2 = q[a2]; 756 1.3 oster new = new | INSERT(a1, 4) | INSERT(a2, 5); 757 1.3 oster a1 = EXTRACT(a, 5) ^ r; 758 1.3 oster a2 = EXTRACT(a, 6) ^ r; 759 1.3 oster a1 = q[a1]; 760 1.3 oster a2 = q[a2]; 761 1.3 oster new = new | INSERT(a1, 5) | INSERT(a2, 6); 762 1.1 oster #if RF_LONGSHIFT > 2 763 1.3 oster a1 = EXTRACT(a, 7) ^ r; 764 1.3 oster a2 = EXTRACT(a, 8) ^ r; 765 1.3 oster a1 = q[a1]; 766 1.3 oster a2 = q[a2]; 767 1.3 oster new = new | INSERT(a1, 7) | INSERT(a2, 8); 768 1.3 oster a1 = EXTRACT(a, 9) ^ r; 769 1.3 oster a2 = EXTRACT(a, 10) ^ r; 770 1.3 oster a1 = q[a1]; 771 1.3 oster a2 = q[a2]; 772 1.3 oster new = new | INSERT(a1, 9) | INSERT(a2, 10); 773 1.3 oster a1 = EXTRACT(a, 11) ^ r; 774 1.3 oster a2 = EXTRACT(a, 12) ^ r; 775 1.3 oster a1 = q[a1]; 776 1.3 oster a2 = q[a2]; 777 1.3 oster new = new | INSERT(a1, 11) | INSERT(a2, 12); 778 1.3 oster #endif /* RF_LONGSHIFT > 2 */ 779 1.3 oster d ^= new; 780 1.3 oster *dest++ = d; 781 1.3 oster length--; 782 1.3 oster } 783 1.3 oster #endif /* _KERNEL */ 784 1.1 oster } 785 1.1 oster /* 786 1.1 oster recover columns a and b from the given p and q into 787 1.1 oster bufs abuf and bbuf. All bufs are word aligned. 788 1.1 oster Length is in bytes. 789 1.1 oster */ 790 1.3 oster 791 1.1 oster 792 1.1 oster /* 793 1.1 oster * XXX 794 1.1 oster * 795 1.1 oster * Everything about this seems wrong. 796 1.1 oster */ 797 1.14 perry void 798 1.16 dsl rf_PQ_recover(unsigned long *pbuf, unsigned long *qbuf, unsigned long *abuf, unsigned long *bbuf, unsigned length, unsigned coeff_a, unsigned coeff_b) 799 1.3 oster { 800 1.3 oster unsigned long p, q, a, a0, a1; 801 1.3 oster int col = (29 * coeff_a) + coeff_b; 802 1.3 oster unsigned char *q0 = &(rf_qinv[col][0]); 803 1.3 oster 804 1.3 oster length /= 8; 805 1.3 oster while (length) { 806 1.3 oster p = *pbuf++; 807 1.3 oster q = *qbuf++; 808 1.3 oster a0 = EXTRACT(p, 0); 809 1.3 oster a1 = EXTRACT(q, 0); 810 1.3 oster a = q0[a0 << 5 | a1]; 811 1.1 oster #define MF(i) \ 812 1.1 oster a0 = EXTRACT(p,i); \ 813 1.1 oster a1 = EXTRACT(q,i); \ 814 1.1 oster a = a | INSERT(q0[a0<<5 | a1],i) 815 1.1 oster 816 1.3 oster MF(1); 817 1.3 oster MF(2); 818 1.3 oster MF(3); 819 1.3 oster MF(4); 820 1.3 oster MF(5); 821 1.3 oster MF(6); 822 1.1 oster #if 0 823 1.3 oster MF(7); 824 1.3 oster MF(8); 825 1.3 oster MF(9); 826 1.3 oster MF(10); 827 1.3 oster MF(11); 828 1.3 oster MF(12); 829 1.3 oster #endif /* 0 */ 830 1.3 oster *abuf++ = a; 831 1.3 oster *bbuf++ = a ^ p; 832 1.3 oster length--; 833 1.3 oster } 834 1.1 oster } 835 1.3 oster /* 836 1.1 oster Lost parity and a data column. Recover that data column. 837 1.1 oster Assume col coeff is lost. Let q the contents of Q after 838 1.1 oster all surviving data columns have been q-xored out of it. 839 1.1 oster Then we have the equation 840 1.1 oster 841 1.1 oster q[28-coeff][a_i ^ r_i+1] = q 842 1.1 oster 843 1.3 oster but q is cyclic with period 31. 844 1.1 oster So q[3+coeff][q[28-coeff][a_i ^ r_{i+1}]] = 845 1.1 oster q[31][a_i ^ r_{i+1}] = a_i ^ r_{i+1} . 846 1.1 oster 847 1.1 oster so a_i = r_{coeff+1} ^ q[3+coeff][q] 848 1.1 oster 849 1.1 oster The routine is passed q buffer and the buffer 850 1.1 oster the data is to be recoverd into. They can be the same. 851 1.1 oster */ 852 1.1 oster 853 1.1 oster 854 1.3 oster 855 1.14 perry static void 856 1.3 oster rf_InvertQ( 857 1.3 oster unsigned long *qbuf, 858 1.3 oster unsigned long *abuf, 859 1.3 oster unsigned length, 860 1.3 oster unsigned coeff) 861 1.3 oster { 862 1.3 oster unsigned long a, new; 863 1.3 oster unsigned long a1, a2; 864 1.3 oster unsigned int *q = &(rf_qfor[3 + coeff][0]); 865 1.3 oster unsigned r = rf_rn[coeff + 1]; 866 1.3 oster 867 1.3 oster /* 13 5 bit quants in a 64 bit word */ 868 1.3 oster length /= 8; 869 1.3 oster while (length) { 870 1.3 oster a = *qbuf++; 871 1.3 oster a1 = EXTRACT(a, 0); 872 1.3 oster a2 = EXTRACT(a, 1); 873 1.3 oster a1 = r ^ q[a1]; 874 1.3 oster a2 = r ^ q[a2]; 875 1.3 oster new = INSERT(a2, 1) | a1; 876 1.1 oster #define M(i,j) \ 877 1.1 oster a1 = EXTRACT(a,i); \ 878 1.1 oster a2 = EXTRACT(a,j); \ 879 1.1 oster a1 = r ^ q[a1]; \ 880 1.1 oster a2 = r ^ q[a2]; \ 881 1.1 oster new = new | INSERT(a1,i) | INSERT(a2,j) 882 1.1 oster 883 1.3 oster M(2, 3); 884 1.3 oster M(4, 5); 885 1.3 oster M(5, 6); 886 1.1 oster #if RF_LONGSHIFT > 2 887 1.3 oster M(7, 8); 888 1.3 oster M(9, 10); 889 1.3 oster M(11, 12); 890 1.3 oster #endif /* RF_LONGSHIFT > 2 */ 891 1.3 oster *abuf++ = new; 892 1.3 oster length--; 893 1.3 oster } 894 1.1 oster } 895 1.3 oster #endif /* (RF_INCLUDE_DECL_PQ > 0) || 896 1.3 oster * (RF_INCLUDE_RAID6 > 0) */ 897