rf_pq.c revision 1.16 1 1.16 dsl /* $NetBSD: rf_pq.c,v 1.16 2009/03/14 15:36:20 dsl 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.16 dsl __KERNEL_RCSID(0, "$NetBSD: rf_pq.c,v 1.16 2009/03/14 15:36:20 dsl 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.14 perry int
60 1.16 dsl rf_RegularONPFunc(RF_DagNode_t *node)
61 1.1 oster {
62 1.3 oster return (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.14 perry int
69 1.16 dsl rf_SimpleONPFunc(RF_DagNode_t *node)
70 1.1 oster {
71 1.3 oster return (rf_SimpleXorFunc(node));
72 1.1 oster }
73 1.1 oster
74 1.14 perry int
75 1.16 dsl rf_RecoveryPFunc(RF_DagNode_t *node)
76 1.1 oster {
77 1.3 oster return (rf_RecoveryXorFunc(node));
78 1.1 oster }
79 1.1 oster
80 1.14 perry int
81 1.16 dsl rf_RegularPFunc(RF_DagNode_t *node)
82 1.1 oster {
83 1.3 oster return (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.14 perry int
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.3 oster return (0);
283 1.1 oster }
284 1.1 oster /*
285 1.1 oster See the SimpleXORFunc for the difference between a simple and regular func.
286 1.3 oster These Q functions should be used for
287 1.3 oster
288 1.3 oster new q = Q(data,old data,old q)
289 1.1 oster
290 1.3 oster style updates and not for
291 1.1 oster
292 1.1 oster q = ( new data, new data, .... )
293 1.1 oster
294 1.1 oster computations.
295 1.1 oster
296 1.1 oster The simple q takes 2(2d+1)+1 params, where d is the number
297 1.1 oster of stripes written. The order of params is
298 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
299 1.1 oster [2d] old q pda_0, old q buffer
300 1.1 oster [2d_2] new data pda_0, new data buffer_0, ... new data pda_d, new data buffer_d
301 1.1 oster raidPtr
302 1.1 oster */
303 1.1 oster
304 1.14 perry int
305 1.16 dsl rf_SimpleONQFunc(RF_DagNode_t *node)
306 1.3 oster {
307 1.3 oster int np = node->numParams;
308 1.3 oster int d;
309 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p;
310 1.3 oster int i;
311 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
312 1.3 oster RF_Etimer_t timer;
313 1.3 oster char *qbuf;
314 1.3 oster char *obuf, *nbuf;
315 1.3 oster RF_PhysDiskAddr_t *old, *new;
316 1.3 oster unsigned long coeff;
317 1.3 oster
318 1.3 oster RF_ETIMER_START(timer);
319 1.3 oster
320 1.3 oster d = (np - 3) / 4;
321 1.3 oster RF_ASSERT(4 * d + 3 == np);
322 1.3 oster qbuf = (char *) node->params[2 * d + 1].p; /* q buffer */
323 1.3 oster for (i = 0; i < d; i++) {
324 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p;
325 1.3 oster obuf = (char *) node->params[2 * i + 1].p;
326 1.3 oster new = (RF_PhysDiskAddr_t *) node->params[2 * (d + 1 + i)].p;
327 1.3 oster nbuf = (char *) node->params[2 * (d + 1 + i) + 1].p;
328 1.3 oster RF_ASSERT(new->numSector == old->numSector);
329 1.3 oster RF_ASSERT(new->raidAddress == old->raidAddress);
330 1.3 oster /* the stripe unit within the stripe tells us the coefficient
331 1.3 oster * to use for the multiply. */
332 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), new->raidAddress);
333 1.3 oster /* compute the data unit offset within the column, then add
334 1.3 oster * one */
335 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol);
336 1.3 oster QDelta(qbuf, obuf, nbuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff);
337 1.3 oster }
338 1.3 oster
339 1.3 oster RF_ETIMER_STOP(timer);
340 1.3 oster RF_ETIMER_EVAL(timer);
341 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer);
342 1.3 oster rf_GenericWakeupFunc(node, 0); /* call wake func explicitly since no
343 1.3 oster * I/O in this node */
344 1.3 oster return (0);
345 1.1 oster }
346 1.1 oster RF_CREATE_DAG_FUNC_DECL(rf_PQCreateSmallWriteDAG)
347 1.1 oster {
348 1.3 oster rf_CommonCreateSmallWriteDAG(raidPtr, asmap, dag_h, bp, flags, allocList, &rf_pFuncs, &rf_qFuncs);
349 1.1 oster }
350 1.1 oster
351 1.5 oster static void RegularQSubr(RF_DagNode_t *node, char *qbuf);
352 1.5 oster
353 1.14 perry static void
354 1.16 dsl RegularQSubr(RF_DagNode_t *node, char *qbuf)
355 1.3 oster {
356 1.3 oster int np = node->numParams;
357 1.3 oster int d;
358 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p;
359 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit;
360 1.3 oster int i;
361 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
362 1.3 oster RF_Etimer_t timer;
363 1.3 oster char *obuf, *qpbuf;
364 1.3 oster RF_PhysDiskAddr_t *old;
365 1.3 oster unsigned long coeff;
366 1.3 oster
367 1.3 oster RF_ETIMER_START(timer);
368 1.3 oster
369 1.3 oster d = (np - 1) / 2;
370 1.3 oster RF_ASSERT(2 * d + 1 == np);
371 1.3 oster for (i = 0; i < d; i++) {
372 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p;
373 1.3 oster obuf = (char *) node->params[2 * i + 1].p;
374 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), old->raidAddress);
375 1.3 oster /* compute the data unit offset within the column, then add
376 1.3 oster * one */
377 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol);
378 1.3 oster /* the input buffers may not all be aligned with the start of
379 1.3 oster * the stripe. so shift by their sector offset within the
380 1.3 oster * stripe unit */
381 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, old->startSector % secPerSU);
382 1.3 oster rf_IncQ((unsigned long *) qpbuf, (unsigned long *) obuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff);
383 1.3 oster }
384 1.3 oster
385 1.3 oster RF_ETIMER_STOP(timer);
386 1.3 oster RF_ETIMER_EVAL(timer);
387 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer);
388 1.1 oster }
389 1.1 oster /*
390 1.1 oster used in degraded writes.
391 1.1 oster */
392 1.1 oster
393 1.5 oster static void DegrQSubr(RF_DagNode_t *node);
394 1.5 oster
395 1.14 perry static void
396 1.16 dsl DegrQSubr(RF_DagNode_t *node)
397 1.3 oster {
398 1.3 oster int np = node->numParams;
399 1.3 oster int d;
400 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p;
401 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit;
402 1.3 oster int i;
403 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
404 1.3 oster RF_Etimer_t timer;
405 1.3 oster char *qbuf = node->results[1];
406 1.3 oster char *obuf, *qpbuf;
407 1.3 oster RF_PhysDiskAddr_t *old;
408 1.3 oster unsigned long coeff;
409 1.3 oster unsigned fail_start;
410 1.3 oster int j;
411 1.3 oster
412 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[np - 2].p;
413 1.3 oster fail_start = old->startSector % secPerSU;
414 1.3 oster
415 1.3 oster RF_ETIMER_START(timer);
416 1.3 oster
417 1.3 oster d = (np - 2) / 2;
418 1.3 oster RF_ASSERT(2 * d + 2 == np);
419 1.3 oster for (i = 0; i < d; i++) {
420 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p;
421 1.3 oster obuf = (char *) node->params[2 * i + 1].p;
422 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), old->raidAddress);
423 1.3 oster /* compute the data unit offset within the column, then add
424 1.3 oster * one */
425 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol);
426 1.3 oster /* the input buffers may not all be aligned with the start of
427 1.3 oster * the stripe. so shift by their sector offset within the
428 1.3 oster * stripe unit */
429 1.3 oster j = old->startSector % secPerSU;
430 1.3 oster RF_ASSERT(j >= fail_start);
431 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, j - fail_start);
432 1.3 oster rf_IncQ((unsigned long *) qpbuf, (unsigned long *) obuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff);
433 1.3 oster }
434 1.3 oster
435 1.3 oster RF_ETIMER_STOP(timer);
436 1.3 oster RF_ETIMER_EVAL(timer);
437 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer);
438 1.1 oster }
439 1.1 oster /*
440 1.1 oster Called by large write code to compute the new parity and the new q.
441 1.3 oster
442 1.1 oster structure of the params:
443 1.1 oster
444 1.1 oster pda_0, buffer_0, pda_1 , buffer_1, ... , pda_d, buffer_d ( d = numDataCol
445 1.3 oster raidPtr
446 1.1 oster
447 1.1 oster for a total of 2d+1 arguments.
448 1.1 oster The result buffers results[0], results[1] are the buffers for the p and q,
449 1.1 oster respectively.
450 1.1 oster
451 1.1 oster We compute Q first, then compute P. The P calculation may try to reuse
452 1.1 oster one of the input buffers for its output, so if we computed P first, we would
453 1.1 oster corrupt the input for the q calculation.
454 1.1 oster */
455 1.1 oster
456 1.14 perry int
457 1.16 dsl rf_RegularPQFunc(RF_DagNode_t *node)
458 1.3 oster {
459 1.3 oster RegularQSubr(node, node->results[1]);
460 1.3 oster return (rf_RegularXorFunc(node)); /* does the wakeup */
461 1.3 oster }
462 1.3 oster
463 1.14 perry int
464 1.16 dsl rf_RegularQFunc(RF_DagNode_t *node)
465 1.3 oster {
466 1.3 oster /* Almost ... adjust Qsubr args */
467 1.3 oster RegularQSubr(node, node->results[0]);
468 1.3 oster rf_GenericWakeupFunc(node, 0); /* call wake func explicitly since no
469 1.3 oster * I/O in this node */
470 1.3 oster return (0);
471 1.1 oster }
472 1.1 oster /*
473 1.1 oster Called by singly degraded write code to compute the new parity and the new q.
474 1.3 oster
475 1.1 oster structure of the params:
476 1.1 oster
477 1.3 oster pda_0, buffer_0, pda_1 , buffer_1, ... , pda_d, buffer_d
478 1.3 oster failedPDA raidPtr
479 1.1 oster
480 1.1 oster for a total of 2d+2 arguments.
481 1.1 oster The result buffers results[0], results[1] are the buffers for the parity and q,
482 1.1 oster respectively.
483 1.1 oster
484 1.1 oster We compute Q first, then compute parity. The parity calculation may try to reuse
485 1.1 oster one of the input buffers for its output, so if we computed parity first, we would
486 1.1 oster corrupt the input for the q calculation.
487 1.1 oster
488 1.1 oster We treat this identically to the regularPQ case, ignoring the failedPDA extra argument.
489 1.1 oster */
490 1.1 oster
491 1.14 perry void
492 1.16 dsl rf_Degraded_100_PQFunc(RF_DagNode_t *node)
493 1.3 oster {
494 1.3 oster int np = node->numParams;
495 1.3 oster
496 1.3 oster RF_ASSERT(np >= 2);
497 1.3 oster DegrQSubr(node);
498 1.3 oster rf_RecoveryXorFunc(node);
499 1.1 oster }
500 1.1 oster
501 1.1 oster
502 1.1 oster /*
503 1.1 oster The two below are used when reading a stripe with a single lost data unit.
504 1.1 oster The parameters are
505 1.1 oster
506 1.1 oster pda_0, buffer_0, .... pda_n, buffer_n, P pda, P buffer, failedPDA, raidPtr
507 1.1 oster
508 1.1 oster and results[0] contains the data buffer. Which is originally zero-filled.
509 1.3 oster
510 1.1 oster */
511 1.1 oster
512 1.1 oster /* this Q func is used by the degraded-mode dag functions to recover lost data.
513 1.1 oster * the second-to-last parameter is the PDA for the failed portion of the access.
514 1.1 oster * the code here looks at this PDA and assumes that the xor target buffer is
515 1.1 oster * equal in size to the number of sectors in the failed PDA. It then uses
516 1.1 oster * the other PDAs in the parameter list to determine where within the target
517 1.1 oster * buffer the corresponding data should be xored.
518 1.1 oster *
519 1.3 oster * Recall the basic equation is
520 1.3 oster *
521 1.1 oster * Q = ( data_1 + 2 * data_2 ... + k * data_k ) mod 256
522 1.1 oster *
523 1.1 oster * so to recover data_j we need
524 1.1 oster *
525 1.1 oster * J data_j = (Q - data_1 - 2 data_2 ....- k* data_k) mod 256
526 1.1 oster *
527 1.1 oster * So the coefficient for each buffer is (255 - data_col), and j should be initialized by
528 1.1 oster * copying Q into it. Then we need to do a table lookup to convert to solve
529 1.1 oster * data_j /= J
530 1.3 oster *
531 1.3 oster *
532 1.1 oster */
533 1.14 perry int
534 1.16 dsl rf_RecoveryQFunc(RF_DagNode_t *node)
535 1.3 oster {
536 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
537 1.3 oster RF_RaidLayout_t *layoutPtr = (RF_RaidLayout_t *) & raidPtr->Layout;
538 1.3 oster RF_PhysDiskAddr_t *failedPDA = (RF_PhysDiskAddr_t *) node->params[node->numParams - 2].p;
539 1.3 oster int i;
540 1.3 oster RF_PhysDiskAddr_t *pda;
541 1.3 oster RF_RaidAddr_t suoffset, failedSUOffset = rf_StripeUnitOffset(layoutPtr, failedPDA->startSector);
542 1.3 oster char *srcbuf, *destbuf;
543 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
544 1.3 oster RF_Etimer_t timer;
545 1.3 oster unsigned long coeff;
546 1.3 oster
547 1.3 oster RF_ETIMER_START(timer);
548 1.3 oster /* start by copying Q into the buffer */
549 1.12 wiz memcpy(node->results[0], node->params[node->numParams - 3].p,
550 1.3 oster rf_RaidAddressToByte(raidPtr, failedPDA->numSector));
551 1.3 oster for (i = 0; i < node->numParams - 4; i += 2) {
552 1.3 oster RF_ASSERT(node->params[i + 1].p != node->results[0]);
553 1.3 oster pda = (RF_PhysDiskAddr_t *) node->params[i].p;
554 1.3 oster srcbuf = (char *) node->params[i + 1].p;
555 1.3 oster suoffset = rf_StripeUnitOffset(layoutPtr, pda->startSector);
556 1.3 oster destbuf = ((char *) node->results[0]) + rf_RaidAddressToByte(raidPtr, suoffset - failedSUOffset);
557 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), pda->raidAddress);
558 1.3 oster /* compute the data unit offset within the column */
559 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol);
560 1.3 oster rf_IncQ((unsigned long *) destbuf, (unsigned long *) srcbuf, rf_RaidAddressToByte(raidPtr, pda->numSector), coeff);
561 1.3 oster }
562 1.3 oster /* Do the nasty inversion now */
563 1.3 oster coeff = (rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), failedPDA->startSector) % raidPtr->Layout.numDataCol);
564 1.3 oster rf_InvertQ(node->results[0], node->results[0], rf_RaidAddressToByte(raidPtr, pda->numSector), coeff);
565 1.3 oster RF_ETIMER_STOP(timer);
566 1.3 oster RF_ETIMER_EVAL(timer);
567 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer);
568 1.3 oster rf_GenericWakeupFunc(node, 0);
569 1.3 oster return (0);
570 1.3 oster }
571 1.3 oster
572 1.14 perry int
573 1.16 dsl rf_RecoveryPQFunc(RF_DagNode_t *node)
574 1.1 oster {
575 1.6 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[node->numParams - 1].p;
576 1.6 oster printf("raid%d: Recovery from PQ not implemented.\n",raidPtr->raidid);
577 1.3 oster return (1);
578 1.1 oster }
579 1.1 oster /*
580 1.3 oster Degraded write Q subroutine.
581 1.1 oster Used when P is dead.
582 1.3 oster Large-write style Q computation.
583 1.1 oster Parameters
584 1.1 oster
585 1.1 oster (pda,buf),(pda,buf),.....,(failedPDA,bufPtr),failedPDA,raidPtr.
586 1.1 oster
587 1.1 oster We ignore failedPDA.
588 1.1 oster
589 1.1 oster This is a "simple style" recovery func.
590 1.1 oster */
591 1.1 oster
592 1.14 perry void
593 1.16 dsl rf_PQ_DegradedWriteQFunc(RF_DagNode_t *node)
594 1.3 oster {
595 1.3 oster int np = node->numParams;
596 1.3 oster int d;
597 1.3 oster RF_Raid_t *raidPtr = (RF_Raid_t *) node->params[np - 1].p;
598 1.3 oster unsigned secPerSU = raidPtr->Layout.sectorsPerStripeUnit;
599 1.3 oster int i;
600 1.3 oster RF_AccTraceEntry_t *tracerec = node->dagHdr->tracerec;
601 1.3 oster RF_Etimer_t timer;
602 1.3 oster char *qbuf = node->results[0];
603 1.3 oster char *obuf, *qpbuf;
604 1.3 oster RF_PhysDiskAddr_t *old;
605 1.3 oster unsigned long coeff;
606 1.3 oster int fail_start, j;
607 1.3 oster
608 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[np - 2].p;
609 1.3 oster fail_start = old->startSector % secPerSU;
610 1.3 oster
611 1.3 oster RF_ETIMER_START(timer);
612 1.3 oster
613 1.3 oster d = (np - 2) / 2;
614 1.3 oster RF_ASSERT(2 * d + 2 == np);
615 1.3 oster
616 1.3 oster for (i = 0; i < d; i++) {
617 1.3 oster old = (RF_PhysDiskAddr_t *) node->params[2 * i].p;
618 1.3 oster obuf = (char *) node->params[2 * i + 1].p;
619 1.3 oster coeff = rf_RaidAddressToStripeUnitID(&(raidPtr->Layout), old->raidAddress);
620 1.3 oster /* compute the data unit offset within the column, then add
621 1.3 oster * one */
622 1.3 oster coeff = (coeff % raidPtr->Layout.numDataCol);
623 1.3 oster j = old->startSector % secPerSU;
624 1.3 oster RF_ASSERT(j >= fail_start);
625 1.3 oster qpbuf = qbuf + rf_RaidAddressToByte(raidPtr, j - fail_start);
626 1.3 oster rf_IncQ((unsigned long *) qpbuf, (unsigned long *) obuf, rf_RaidAddressToByte(raidPtr, old->numSector), coeff);
627 1.3 oster }
628 1.3 oster
629 1.3 oster RF_ETIMER_STOP(timer);
630 1.3 oster RF_ETIMER_EVAL(timer);
631 1.3 oster tracerec->q_us += RF_ETIMER_VAL_US(timer);
632 1.3 oster rf_GenericWakeupFunc(node, 0);
633 1.1 oster }
634 1.1 oster
635 1.1 oster
636 1.1 oster
637 1.1 oster
638 1.1 oster /* Q computations */
639 1.1 oster
640 1.1 oster /*
641 1.1 oster coeff - colummn;
642 1.1 oster
643 1.1 oster compute dest ^= qfor[28-coeff][rn[coeff+1] a]
644 1.1 oster
645 1.1 oster on 5-bit basis;
646 1.1 oster length in bytes;
647 1.1 oster */
648 1.1 oster
649 1.14 perry void
650 1.16 dsl rf_IncQ(unsigned long *dest, unsigned long *buf, unsigned length, unsigned coeff)
651 1.3 oster {
652 1.3 oster unsigned long a, d, new;
653 1.3 oster unsigned long a1, a2;
654 1.3 oster unsigned int *q = &(rf_qfor[28 - coeff][0]);
655 1.3 oster unsigned r = rf_rn[coeff + 1];
656 1.1 oster
657 1.1 oster #define EXTRACT(a,i) ((a >> (5L*i)) & 0x1f)
658 1.1 oster #define INSERT(a,i) (a << (5L*i))
659 1.1 oster
660 1.3 oster length /= 8;
661 1.3 oster /* 13 5 bit quants in a 64 bit word */
662 1.3 oster while (length) {
663 1.3 oster a = *buf++;
664 1.3 oster d = *dest;
665 1.3 oster a1 = EXTRACT(a, 0) ^ r;
666 1.3 oster a2 = EXTRACT(a, 1) ^ r;
667 1.3 oster new = INSERT(a2, 1) | a1;
668 1.3 oster a1 = EXTRACT(a, 2) ^ r;
669 1.3 oster a2 = EXTRACT(a, 3) ^ r;
670 1.3 oster a1 = q[a1];
671 1.3 oster a2 = q[a2];
672 1.3 oster new = new | INSERT(a1, 2) | INSERT(a2, 3);
673 1.3 oster a1 = EXTRACT(a, 4) ^ r;
674 1.3 oster a2 = EXTRACT(a, 5) ^ r;
675 1.3 oster a1 = q[a1];
676 1.3 oster a2 = q[a2];
677 1.3 oster new = new | INSERT(a1, 4) | INSERT(a2, 5);
678 1.3 oster a1 = EXTRACT(a, 5) ^ r;
679 1.3 oster a2 = EXTRACT(a, 6) ^ r;
680 1.3 oster a1 = q[a1];
681 1.3 oster a2 = q[a2];
682 1.3 oster new = new | INSERT(a1, 5) | INSERT(a2, 6);
683 1.1 oster #if RF_LONGSHIFT > 2
684 1.3 oster a1 = EXTRACT(a, 7) ^ r;
685 1.3 oster a2 = EXTRACT(a, 8) ^ r;
686 1.3 oster a1 = q[a1];
687 1.3 oster a2 = q[a2];
688 1.3 oster new = new | INSERT(a1, 7) | INSERT(a2, 8);
689 1.3 oster a1 = EXTRACT(a, 9) ^ r;
690 1.3 oster a2 = EXTRACT(a, 10) ^ r;
691 1.3 oster a1 = q[a1];
692 1.3 oster a2 = q[a2];
693 1.3 oster new = new | INSERT(a1, 9) | INSERT(a2, 10);
694 1.3 oster a1 = EXTRACT(a, 11) ^ r;
695 1.3 oster a2 = EXTRACT(a, 12) ^ r;
696 1.3 oster a1 = q[a1];
697 1.3 oster a2 = q[a2];
698 1.3 oster new = new | INSERT(a1, 11) | INSERT(a2, 12);
699 1.3 oster #endif /* RF_LONGSHIFT > 2 */
700 1.3 oster d ^= new;
701 1.3 oster *dest++ = d;
702 1.3 oster length--;
703 1.3 oster }
704 1.1 oster }
705 1.3 oster /*
706 1.3 oster compute
707 1.1 oster
708 1.1 oster dest ^= rf_qfor[28-coeff][rf_rn[coeff+1] (old^new) ]
709 1.1 oster
710 1.1 oster on a five bit basis.
711 1.1 oster optimization: compute old ^ new on 64 bit basis.
712 1.1 oster
713 1.1 oster length in bytes.
714 1.1 oster */
715 1.1 oster
716 1.14 perry static void
717 1.3 oster QDelta(
718 1.3 oster char *dest,
719 1.3 oster char *obuf,
720 1.3 oster char *nbuf,
721 1.3 oster unsigned length,
722 1.3 oster unsigned char coeff)
723 1.3 oster {
724 1.3 oster unsigned long a, d, new;
725 1.3 oster unsigned long a1, a2;
726 1.3 oster unsigned int *q = &(rf_qfor[28 - coeff][0]);
727 1.5 oster unsigned int r = rf_rn[coeff + 1];
728 1.5 oster
729 1.5 oster r = a1 = a2 = new = d = a = 0; /* XXX for now... */
730 1.5 oster q = NULL; /* XXX for now */
731 1.1 oster
732 1.2 oster #ifdef _KERNEL
733 1.3 oster /* PQ in kernel currently not supported because the encoding/decoding
734 1.3 oster * table is not present */
735 1.9 thorpej memset(dest, 0, length);
736 1.3 oster #else /* KERNEL */
737 1.3 oster /* this code probably doesn't work and should be rewritten -wvcii */
738 1.3 oster /* 13 5 bit quants in a 64 bit word */
739 1.3 oster length /= 8;
740 1.3 oster while (length) {
741 1.3 oster a = *obuf++; /* XXX need to reorg to avoid cache conflicts */
742 1.3 oster a ^= *nbuf++;
743 1.3 oster d = *dest;
744 1.3 oster a1 = EXTRACT(a, 0) ^ r;
745 1.3 oster a2 = EXTRACT(a, 1) ^ r;
746 1.3 oster a1 = q[a1];
747 1.3 oster a2 = q[a2];
748 1.3 oster new = INSERT(a2, 1) | a1;
749 1.3 oster a1 = EXTRACT(a, 2) ^ r;
750 1.3 oster a2 = EXTRACT(a, 3) ^ r;
751 1.3 oster a1 = q[a1];
752 1.3 oster a2 = q[a2];
753 1.3 oster new = new | INSERT(a1, 2) | INSERT(a2, 3);
754 1.3 oster a1 = EXTRACT(a, 4) ^ r;
755 1.3 oster a2 = EXTRACT(a, 5) ^ r;
756 1.3 oster a1 = q[a1];
757 1.3 oster a2 = q[a2];
758 1.3 oster new = new | INSERT(a1, 4) | INSERT(a2, 5);
759 1.3 oster a1 = EXTRACT(a, 5) ^ r;
760 1.3 oster a2 = EXTRACT(a, 6) ^ r;
761 1.3 oster a1 = q[a1];
762 1.3 oster a2 = q[a2];
763 1.3 oster new = new | INSERT(a1, 5) | INSERT(a2, 6);
764 1.1 oster #if RF_LONGSHIFT > 2
765 1.3 oster a1 = EXTRACT(a, 7) ^ r;
766 1.3 oster a2 = EXTRACT(a, 8) ^ r;
767 1.3 oster a1 = q[a1];
768 1.3 oster a2 = q[a2];
769 1.3 oster new = new | INSERT(a1, 7) | INSERT(a2, 8);
770 1.3 oster a1 = EXTRACT(a, 9) ^ r;
771 1.3 oster a2 = EXTRACT(a, 10) ^ r;
772 1.3 oster a1 = q[a1];
773 1.3 oster a2 = q[a2];
774 1.3 oster new = new | INSERT(a1, 9) | INSERT(a2, 10);
775 1.3 oster a1 = EXTRACT(a, 11) ^ r;
776 1.3 oster a2 = EXTRACT(a, 12) ^ r;
777 1.3 oster a1 = q[a1];
778 1.3 oster a2 = q[a2];
779 1.3 oster new = new | INSERT(a1, 11) | INSERT(a2, 12);
780 1.3 oster #endif /* RF_LONGSHIFT > 2 */
781 1.3 oster d ^= new;
782 1.3 oster *dest++ = d;
783 1.3 oster length--;
784 1.3 oster }
785 1.3 oster #endif /* _KERNEL */
786 1.1 oster }
787 1.1 oster /*
788 1.1 oster recover columns a and b from the given p and q into
789 1.1 oster bufs abuf and bbuf. All bufs are word aligned.
790 1.1 oster Length is in bytes.
791 1.1 oster */
792 1.3 oster
793 1.1 oster
794 1.1 oster /*
795 1.1 oster * XXX
796 1.1 oster *
797 1.1 oster * Everything about this seems wrong.
798 1.1 oster */
799 1.14 perry void
800 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)
801 1.3 oster {
802 1.3 oster unsigned long p, q, a, a0, a1;
803 1.3 oster int col = (29 * coeff_a) + coeff_b;
804 1.3 oster unsigned char *q0 = &(rf_qinv[col][0]);
805 1.3 oster
806 1.3 oster length /= 8;
807 1.3 oster while (length) {
808 1.3 oster p = *pbuf++;
809 1.3 oster q = *qbuf++;
810 1.3 oster a0 = EXTRACT(p, 0);
811 1.3 oster a1 = EXTRACT(q, 0);
812 1.3 oster a = q0[a0 << 5 | a1];
813 1.1 oster #define MF(i) \
814 1.1 oster a0 = EXTRACT(p,i); \
815 1.1 oster a1 = EXTRACT(q,i); \
816 1.1 oster a = a | INSERT(q0[a0<<5 | a1],i)
817 1.1 oster
818 1.3 oster MF(1);
819 1.3 oster MF(2);
820 1.3 oster MF(3);
821 1.3 oster MF(4);
822 1.3 oster MF(5);
823 1.3 oster MF(6);
824 1.1 oster #if 0
825 1.3 oster MF(7);
826 1.3 oster MF(8);
827 1.3 oster MF(9);
828 1.3 oster MF(10);
829 1.3 oster MF(11);
830 1.3 oster MF(12);
831 1.3 oster #endif /* 0 */
832 1.3 oster *abuf++ = a;
833 1.3 oster *bbuf++ = a ^ p;
834 1.3 oster length--;
835 1.3 oster }
836 1.1 oster }
837 1.3 oster /*
838 1.1 oster Lost parity and a data column. Recover that data column.
839 1.1 oster Assume col coeff is lost. Let q the contents of Q after
840 1.1 oster all surviving data columns have been q-xored out of it.
841 1.1 oster Then we have the equation
842 1.1 oster
843 1.1 oster q[28-coeff][a_i ^ r_i+1] = q
844 1.1 oster
845 1.3 oster but q is cyclic with period 31.
846 1.1 oster So q[3+coeff][q[28-coeff][a_i ^ r_{i+1}]] =
847 1.1 oster q[31][a_i ^ r_{i+1}] = a_i ^ r_{i+1} .
848 1.1 oster
849 1.1 oster so a_i = r_{coeff+1} ^ q[3+coeff][q]
850 1.1 oster
851 1.1 oster The routine is passed q buffer and the buffer
852 1.1 oster the data is to be recoverd into. They can be the same.
853 1.1 oster */
854 1.1 oster
855 1.1 oster
856 1.3 oster
857 1.14 perry static void
858 1.3 oster rf_InvertQ(
859 1.3 oster unsigned long *qbuf,
860 1.3 oster unsigned long *abuf,
861 1.3 oster unsigned length,
862 1.3 oster unsigned coeff)
863 1.3 oster {
864 1.3 oster unsigned long a, new;
865 1.3 oster unsigned long a1, a2;
866 1.3 oster unsigned int *q = &(rf_qfor[3 + coeff][0]);
867 1.3 oster unsigned r = rf_rn[coeff + 1];
868 1.3 oster
869 1.3 oster /* 13 5 bit quants in a 64 bit word */
870 1.3 oster length /= 8;
871 1.3 oster while (length) {
872 1.3 oster a = *qbuf++;
873 1.3 oster a1 = EXTRACT(a, 0);
874 1.3 oster a2 = EXTRACT(a, 1);
875 1.3 oster a1 = r ^ q[a1];
876 1.3 oster a2 = r ^ q[a2];
877 1.3 oster new = INSERT(a2, 1) | a1;
878 1.1 oster #define M(i,j) \
879 1.1 oster a1 = EXTRACT(a,i); \
880 1.1 oster a2 = EXTRACT(a,j); \
881 1.1 oster a1 = r ^ q[a1]; \
882 1.1 oster a2 = r ^ q[a2]; \
883 1.1 oster new = new | INSERT(a1,i) | INSERT(a2,j)
884 1.1 oster
885 1.3 oster M(2, 3);
886 1.3 oster M(4, 5);
887 1.3 oster M(5, 6);
888 1.1 oster #if RF_LONGSHIFT > 2
889 1.3 oster M(7, 8);
890 1.3 oster M(9, 10);
891 1.3 oster M(11, 12);
892 1.3 oster #endif /* RF_LONGSHIFT > 2 */
893 1.3 oster *abuf++ = new;
894 1.3 oster length--;
895 1.3 oster }
896 1.1 oster }
897 1.3 oster #endif /* (RF_INCLUDE_DECL_PQ > 0) ||
898 1.3 oster * (RF_INCLUDE_RAID6 > 0) */
899