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