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