Home | History | Annotate | Line # | Download | only in raidframe
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