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