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