Home | History | Annotate | Line # | Download | only in raidframe
rf_declusterPQ.c revision 1.1
      1 /*	$NetBSD: rf_declusterPQ.c,v 1.1 1998/11/13 04:20:28 oster Exp $	*/
      2 /*
      3  * Copyright (c) 1995 Carnegie-Mellon University.
      4  * All rights reserved.
      5  *
      6  * Authors: Daniel Stodolsky, Mark Holland, Jim Zelenka
      7  *
      8  * Permission to use, copy, modify and distribute this software and
      9  * its documentation is hereby granted, provided that both the copyright
     10  * notice and this permission notice appear in all copies of the
     11  * software, derivative works or modified versions, and any portions
     12  * thereof, and that both notices appear in supporting documentation.
     13  *
     14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
     15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
     16  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
     17  *
     18  * Carnegie Mellon requests users of this software to return to
     19  *
     20  *  Software Distribution Coordinator  or  Software.Distribution (at) CS.CMU.EDU
     21  *  School of Computer Science
     22  *  Carnegie Mellon University
     23  *  Pittsburgh PA 15213-3890
     24  *
     25  * any improvements or extensions that they make and grant Carnegie the
     26  * rights to redistribute these changes.
     27  */
     28 
     29 /*--------------------------------------------------
     30  * rf_declusterPQ.c
     31  *
     32  * mapping code for declustered P & Q or declustered EvenOdd
     33  * much code borrowed from rf_decluster.c
     34  *
     35  *--------------------------------------------------*/
     36 
     37 /*
     38  * $Header: /tank/opengrok/rsync2/NetBSD/src/sys/dev/raidframe/rf_declusterPQ.c,v 1.1 1998/11/13 04:20:28 oster Exp $
     39  *
     40  * Log: rf_declusterPQ.c,v
     41  * Revision 1.34  1996/08/21 19:47:14  jimz
     42  * fix bogus return values from config
     43  *
     44  * Revision 1.33  1996/08/21  15:09:16  jimz
     45  * cleanup debugging spoo
     46  *
     47  * Revision 1.32  1996/08/21  04:13:36  jimz
     48  * debug with EvenOdd
     49  *
     50  * Revision 1.31  1996/08/20  22:41:54  jimz
     51  * 2 parity disks, not 1
     52  *
     53  * Revision 1.30  1996/07/31  16:56:18  jimz
     54  * dataBytesPerStripe, sectorsPerDisk init arch-indep.
     55  *
     56  * Revision 1.29  1996/07/18  22:57:14  jimz
     57  * port simulator to AIX
     58  *
     59  * Revision 1.28  1996/07/13  00:00:59  jimz
     60  * sanitized generalized reconstruction architecture
     61  * cleaned up head sep, rbuf problems
     62  *
     63  * Revision 1.27  1996/06/11  08:45:12  jimz
     64  * improved error-checking on array configuration
     65  *
     66  * Revision 1.26  1996/06/10  11:55:47  jimz
     67  * Straightened out some per-array/not-per-array distinctions, fixed
     68  * a couple bugs related to confusion. Added shutdown lists. Removed
     69  * layout shutdown function (now subsumed by shutdown lists).
     70  *
     71  * Revision 1.25  1996/06/07  21:33:04  jimz
     72  * begin using consistent types for sector numbers,
     73  * stripe numbers, row+col numbers, recon unit numbers
     74  *
     75  * Revision 1.24  1996/06/02  17:31:48  jimz
     76  * Moved a lot of global stuff into array structure, where it belongs.
     77  * Fixed up paritylogging, pss modules in this manner. Some general
     78  * code cleanup. Removed lots of dead code, some dead files.
     79  *
     80  * Revision 1.23  1996/05/30  23:22:16  jimz
     81  * bugfixes of serialization, timing problems
     82  * more cleanup
     83  *
     84  * Revision 1.22  1996/05/27  18:56:37  jimz
     85  * more code cleanup
     86  * better typing
     87  * compiles in all 3 environments
     88  *
     89  * Revision 1.21  1996/05/24  22:17:04  jimz
     90  * continue code + namespace cleanup
     91  * typed a bunch of flags
     92  *
     93  * Revision 1.20  1996/05/24  01:59:45  jimz
     94  * another checkpoint in code cleanup for release
     95  * time to sync kernel tree
     96  *
     97  * Revision 1.19  1996/05/23  00:33:23  jimz
     98  * code cleanup: move all debug decls to rf_options.c, all extern
     99  * debug decls to rf_options.h, all debug vars preceded by rf_
    100  *
    101  * Revision 1.18  1996/05/18  19:51:34  jimz
    102  * major code cleanup- fix syntax, make some types consistent,
    103  * add prototypes, clean out dead code, et cetera
    104  *
    105  * Revision 1.17  1996/05/17  00:52:56  jimz
    106  * RepIndex was not being initialized before the computation of
    107  * RepIndexQ in MapQDeclusteredPQ(). I copied the initialization
    108  * from MapParityDeclusteredPQ(). Hope that was right.
    109  *
    110  * Revision 1.16  1995/12/12  18:10:06  jimz
    111  * MIN -> RF_MIN, MAX -> RF_MAX, ASSERT -> RF_ASSERT
    112  * fix 80-column brain damage in comments
    113  *
    114  * Revision 1.15  1995/12/01  15:57:46  root
    115  * added copyright info
    116  *
    117  * Revision 1.14  1995/11/17  19:00:13  wvcii
    118  * added prototyping to MapParity
    119  * created MapQ
    120  *
    121  * Revision 1.13  1995/10/05  22:20:48  jimz
    122  * free_1d_array() takes two args; provide them both
    123  *
    124  * Revision 1.12  1995/09/06  19:26:33  wvcii
    125  * offset cfgBuf by sparemap length (ConfigureDeclusteredPQ)
    126  *
    127  * Revision 1.11  95/06/23  13:41:11  robby
    128  * updeated to prototypes in rf_layout.h
    129  *
    130  * Revision 1.10  1995/05/02  22:46:53  holland
    131  * minor code cleanups.
    132  *
    133  * Revision 1.9  1995/03/15  20:45:23  holland
    134  * distr sparing changes.
    135  *
    136  * Revision 1.8  1995/03/01  20:25:48  holland
    137  * kernelization changes
    138  *
    139  * Revision 1.7  1995/02/17  19:39:56  holland
    140  * added size param to all calls to Free().
    141  * this is ignored at user level, but necessary in the kernel.
    142  *
    143  * Revision 1.6  1995/02/10  17:34:10  holland
    144  * kernelization changes
    145  *
    146  * Revision 1.5  1995/02/03  22:31:36  holland
    147  * many changes related to kernelization
    148  *
    149  * Revision 1.4  1995/02/01  15:13:05  holland
    150  * moved #include of general.h out of raid.h and into each file
    151  *
    152  * Revision 1.3  1995/02/01  14:25:19  holland
    153  * began changes for kernelization:
    154  *      changed all instances of mutex_t and cond_t to DECLARE macros
    155  *      converted configuration code to use config structure
    156  *
    157  * Revision 1.2  1994/11/28  22:13:56  danner
    158  * corrected some mapping bugs.
    159  *
    160  */
    161 
    162 #include "rf_types.h"
    163 #include "rf_raid.h"
    164 #include "rf_configure.h"
    165 #include "rf_decluster.h"
    166 #include "rf_declusterPQ.h"
    167 #include "rf_debugMem.h"
    168 #include "rf_utils.h"
    169 #include "rf_alloclist.h"
    170 #include "rf_general.h"
    171 
    172 /* configuration code */
    173 
    174 int rf_ConfigureDeclusteredPQ(
    175   RF_ShutdownList_t  **listp,
    176   RF_Raid_t           *raidPtr,
    177   RF_Config_t         *cfgPtr)
    178 {
    179     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    180     int b, v, k, r, lambda;				/* block design params */
    181     int i, j, l;
    182     int *first_avail_slot;
    183     int  complete_FT_count, SUID;
    184     RF_DeclusteredConfigInfo_t *info;
    185     int numCompleteFullTablesPerDisk;
    186     int PUsPerDisk, spareRegionDepthInPUs, numCompleteSpareRegionsPerDisk = 0, extraPUsPerDisk;
    187     int totSparePUsPerDisk;
    188     int diskOffsetOfLastFullTableInSUs, SpareSpaceInSUs;
    189     char *cfgBuf = (char *) (cfgPtr->layoutSpecific);
    190 
    191     cfgBuf += RF_SPAREMAP_NAME_LEN;
    192 
    193     b        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    194     v        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    195     k        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    196     r        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    197     lambda   = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    198     raidPtr->noRotate = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
    199 
    200     if (k <= 2) {
    201       printf("RAIDFRAME: k=%d, minimum value 2\n", k);
    202       return(EINVAL);
    203     }
    204 
    205     /* 1. create layout specific structure */
    206     RF_MallocAndAdd(info, sizeof(RF_DeclusteredConfigInfo_t), (RF_DeclusteredConfigInfo_t *), raidPtr->cleanupList);
    207     if (info == NULL)
    208       return(ENOMEM);
    209     layoutPtr->layoutSpecificInfo = (void *) info;
    210 
    211     /* the sparemaps are generated assuming that parity is rotated, so we issue
    212      * a warning if both distributed sparing and no-rotate are on at the same time
    213      */
    214     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) && raidPtr->noRotate) {
    215 	RF_ERRORMSG("Warning:  distributed sparing specified without parity rotation.\n");
    216     }
    217 
    218     if (raidPtr->numCol != v) {
    219         RF_ERRORMSG2("RAID: config error: table element count (%d) not equal to no. of cols (%d)\n", v, raidPtr->numCol);
    220         return(EINVAL);
    221     }
    222 
    223     /* 3.  set up the values used in devRaidMap */
    224     info->BlocksPerTable = b;
    225     info->NumParityReps = info->groupSize = k;
    226     info->PUsPerBlock = k-2;  /* PQ */
    227     info->SUsPerTable = b * info->PUsPerBlock * layoutPtr->SUsPerPU;/* b blks, k-1 SUs each */
    228     info->SUsPerFullTable = k * info->SUsPerTable;	/* rot k times */
    229     info->SUsPerBlock = info->PUsPerBlock * layoutPtr->SUsPerPU;
    230     info->TableDepthInPUs = (b*k) / v;
    231     info->FullTableDepthInPUs = info->TableDepthInPUs * k;		/* k repetitions */
    232 
    233     /* used only in distributed sparing case */
    234     info->FullTablesPerSpareRegion = (v-1) / rf_gcd(r, v-1);		/* (v-1)/gcd fulltables */
    235     info->TablesPerSpareRegion = k * info->FullTablesPerSpareRegion;
    236     info->SpareSpaceDepthPerRegionInSUs = (r * info->TablesPerSpareRegion / (v-1)) * layoutPtr->SUsPerPU;
    237 
    238     /* check to make sure the block design is sufficiently small */
    239     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    240         if (info->FullTableDepthInPUs * layoutPtr->SUsPerPU + info->SpareSpaceDepthPerRegionInSUs > layoutPtr->stripeUnitsPerDisk) {
    241 	    RF_ERRORMSG3("RAID: config error: Full Table depth (%d) + Spare Space (%d) larger than disk size (%d) (BD too big)\n",
    242 			 (int)info->FullTableDepthInPUs,
    243 			 (int)info->SpareSpaceDepthPerRegionInSUs,
    244 			 (int)layoutPtr->stripeUnitsPerDisk);
    245 	    return(EINVAL);
    246 	}
    247     } else {
    248 	if (info->TableDepthInPUs * layoutPtr->SUsPerPU > layoutPtr->stripeUnitsPerDisk) {
    249 	    RF_ERRORMSG2("RAID: config error: Table depth (%d) larger than disk size (%d) (BD too big)\n",
    250 			 (int)(info->TableDepthInPUs * layoutPtr->SUsPerPU),
    251 			 (int)layoutPtr->stripeUnitsPerDisk);
    252 	    return(EINVAL);
    253 	}
    254     }
    255 
    256 
    257     /* compute the size of each disk, and the number of tables in the last fulltable (which
    258      * need not be complete)
    259      */
    260     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    261 
    262 	PUsPerDisk = layoutPtr->stripeUnitsPerDisk / layoutPtr->SUsPerPU;
    263 	spareRegionDepthInPUs = (info->TablesPerSpareRegion * info->TableDepthInPUs +
    264 				 (info->TablesPerSpareRegion * info->TableDepthInPUs) / (v-1));
    265 	info->SpareRegionDepthInSUs = spareRegionDepthInPUs * layoutPtr->SUsPerPU;
    266 
    267 	numCompleteSpareRegionsPerDisk = PUsPerDisk / spareRegionDepthInPUs;
    268 	info->NumCompleteSRs = numCompleteSpareRegionsPerDisk;
    269 	extraPUsPerDisk = PUsPerDisk % spareRegionDepthInPUs;
    270 
    271 	/* assume conservatively that we need the full amount of spare space in one region in order
    272 	 * to provide spares for the partial spare region at the end of the array.  We set "i" to
    273 	 * the number of tables in the partial spare region.  This may actually include some fulltables.
    274 	 */
    275 	extraPUsPerDisk -= (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
    276 	if (extraPUsPerDisk <= 0) i = 0;
    277 	else i = extraPUsPerDisk/info->TableDepthInPUs;
    278 
    279 	complete_FT_count = raidPtr->numRow * (numCompleteSpareRegionsPerDisk * (info->TablesPerSpareRegion/k) + i/k);
    280         info->FullTableLimitSUID = complete_FT_count * info->SUsPerFullTable;
    281 	info->ExtraTablesPerDisk = i % k;
    282 
    283 	/* note that in the last spare region, the spare space is complete even though data/parity space is not */
    284 	totSparePUsPerDisk = (numCompleteSpareRegionsPerDisk+1) * (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
    285 	info->TotSparePUsPerDisk = totSparePUsPerDisk;
    286 
    287 	layoutPtr->stripeUnitsPerDisk =
    288 	    ((complete_FT_count/raidPtr->numRow) * info->FullTableDepthInPUs +	 	/* data & parity space */
    289 	     info->ExtraTablesPerDisk * info->TableDepthInPUs +
    290 	     totSparePUsPerDisk								/* spare space */
    291 	    ) * layoutPtr->SUsPerPU;
    292 	layoutPtr->dataStripeUnitsPerDisk =
    293 	    (complete_FT_count * info->FullTableDepthInPUs + info->ExtraTablesPerDisk * info->TableDepthInPUs)
    294 	    * layoutPtr->SUsPerPU * (k-1) / k;
    295 
    296     } else {
    297         /* non-dist spare case:  force each disk to contain an integral number of tables */
    298         layoutPtr->stripeUnitsPerDisk /= (info->TableDepthInPUs * layoutPtr->SUsPerPU);
    299         layoutPtr->stripeUnitsPerDisk *= (info->TableDepthInPUs * layoutPtr->SUsPerPU);
    300 
    301 	/* compute the number of tables in the last fulltable, which need not be complete */
    302         complete_FT_count =
    303             ((layoutPtr->stripeUnitsPerDisk/layoutPtr->SUsPerPU) / info->FullTableDepthInPUs) * raidPtr->numRow;
    304 
    305         info->FullTableLimitSUID = complete_FT_count * info->SUsPerFullTable;
    306         info->ExtraTablesPerDisk =
    307 		((layoutPtr->stripeUnitsPerDisk/layoutPtr->SUsPerPU) / info->TableDepthInPUs) % k;
    308     }
    309 
    310     raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
    311 
    312     /* find the disk offset of the stripe unit where the last fulltable starts */
    313     numCompleteFullTablesPerDisk = complete_FT_count / raidPtr->numRow;
    314     diskOffsetOfLastFullTableInSUs = numCompleteFullTablesPerDisk * info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    315     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    316         SpareSpaceInSUs  = numCompleteSpareRegionsPerDisk * info->SpareSpaceDepthPerRegionInSUs;
    317         diskOffsetOfLastFullTableInSUs += SpareSpaceInSUs;
    318         info->DiskOffsetOfLastSpareSpaceChunkInSUs =
    319 	    diskOffsetOfLastFullTableInSUs + info->ExtraTablesPerDisk * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    320     }
    321     info->DiskOffsetOfLastFullTableInSUs = diskOffsetOfLastFullTableInSUs;
    322     info->numCompleteFullTablesPerDisk = numCompleteFullTablesPerDisk;
    323 
    324     /* 4.  create and initialize the lookup tables */
    325     info->LayoutTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
    326     if (info->LayoutTable == NULL)
    327       return(ENOMEM);
    328     info->OffsetTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
    329     if (info->OffsetTable == NULL)
    330       return(ENOMEM);
    331     info->BlockTable  =	rf_make_2d_array(info->TableDepthInPUs*layoutPtr->SUsPerPU, raidPtr->numCol, raidPtr->cleanupList);
    332     if (info->BlockTable == NULL)
    333       return(ENOMEM);
    334 
    335     first_avail_slot  = (int *) rf_make_1d_array(v, NULL);
    336     if (first_avail_slot == NULL)
    337       return(ENOMEM);
    338 
    339     for (i=0; i<b; i++)
    340       for (j=0; j<k; j++)
    341         info->LayoutTable[i][j] = *cfgBuf++;
    342 
    343     /* initialize offset table */
    344     for (i=0; i<b; i++) for (j=0; j<k; j++) {
    345         info->OffsetTable[i][j] = first_avail_slot[ info->LayoutTable[i][j] ];
    346         first_avail_slot[ info->LayoutTable[i][j] ]++;
    347     }
    348 
    349     /* initialize block table */
    350     for (SUID=l=0; l<layoutPtr->SUsPerPU; l++) {
    351         for (i=0; i<b; i++) {
    352             for (j=0; j<k; j++) {
    353                 info->BlockTable[ (info->OffsetTable[i][j] * layoutPtr->SUsPerPU) + l ]
    354 		                [ info->LayoutTable[i][j] ] = SUID;
    355             }
    356             SUID++;
    357         }
    358     }
    359 
    360     rf_free_1d_array(first_avail_slot, v);
    361 
    362     /* 5.  set up the remaining redundant-but-useful parameters */
    363 
    364     raidPtr->totalSectors = (k*complete_FT_count + raidPtr->numRow*info->ExtraTablesPerDisk) *
    365     			  info->SUsPerTable * layoutPtr->sectorsPerStripeUnit;
    366     layoutPtr->numStripe = (raidPtr->totalSectors / layoutPtr->sectorsPerStripeUnit) / (k-2);
    367 
    368     /* strange evaluation order below to try and minimize overflow problems */
    369 
    370     layoutPtr->dataSectorsPerStripe = (k-2) * layoutPtr->sectorsPerStripeUnit;
    371     layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
    372     layoutPtr->numDataCol = k-2;
    373     layoutPtr->numParityCol = 2;
    374 
    375     return(0);
    376 }
    377 
    378 int rf_GetDefaultNumFloatingReconBuffersPQ(RF_Raid_t *raidPtr)
    379 {
    380   int def_decl;
    381 
    382   def_decl = rf_GetDefaultNumFloatingReconBuffersDeclustered(raidPtr);
    383   return(RF_MAX(3 * raidPtr->numCol, def_decl));
    384 }
    385 
    386 void rf_MapSectorDeclusteredPQ(
    387   RF_Raid_t         *raidPtr,
    388   RF_RaidAddr_t      raidSector,
    389   RF_RowCol_t       *row,
    390   RF_RowCol_t       *col,
    391   RF_SectorNum_t    *diskSector,
    392   int                remap)
    393 {
    394     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    395     RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    396     RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    397     RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    398     RF_StripeNum_t BlockID, BlockOffset, RepIndex;
    399     RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    400     RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    401     RF_StripeNum_t base_suid = 0, outSU, SpareRegion=0, SpareSpace=0;
    402 
    403     rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    404 
    405     FullTableID     = SUID / sus_per_fulltable;		/* fulltable ID within array (across rows) */
    406     *row            = FullTableID % raidPtr->numRow;
    407     FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    408     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    409 	SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    410         SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    411     }
    412     FullTableOffset = SUID % sus_per_fulltable;
    413     TableID         = FullTableOffset / info->SUsPerTable;
    414     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    415     BlockID         = TableOffset / info->PUsPerBlock;
    416     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    417     BlockID        %= info->BlocksPerTable;
    418     RF_ASSERT(BlockOffset < info->groupSize-2 );
    419     /*
    420        TableIDs go from 0 .. GroupSize-1 inclusive.
    421        PUsPerBlock is k-2.
    422        We want the tableIDs to rotate from the
    423        right, so use GroupSize
    424        */
    425     RepIndex        = info->groupSize - 1 - TableID;
    426     RF_ASSERT(RepIndex >= 0);
    427     if (!raidPtr->noRotate)
    428       {
    429 	if (TableID==0)
    430 	    BlockOffset++; /* P on last drive, Q on first */
    431 	else
    432 	  BlockOffset    += ((BlockOffset >= RepIndex) ? 2 : 0); /* skip over PQ */
    433 	RF_ASSERT(BlockOffset < info->groupSize);
    434 	*col            = info->LayoutTable[BlockID][BlockOffset];
    435       }
    436 
    437     /* remap to distributed spare space if indicated */
    438     if (remap) {
    439 	rf_remap_to_spare_space(layoutPtr, info, *row, FullTableID, TableID, BlockID, (base_suid) ? 1 : 0, SpareRegion, col, &outSU);
    440     } else {
    441 
    442         outSU	    = base_suid;
    443         outSU      += FullTableID * fulltable_depth;  				        /* offs to strt of FT */
    444         outSU	   += SpareSpace;						        /* skip rsvd spare space */
    445         outSU      += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;   	        /* offs to strt of tble */
    446         outSU      += info->OffsetTable[BlockID][BlockOffset] * layoutPtr->SUsPerPU;	/* offs to the PU */
    447     }
    448     outSU          += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);	        /* offs to the SU within a PU */
    449 
    450     /* convert SUs to sectors, and, if not aligned to SU boundary, add in offset to sector */
    451     *diskSector     = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    452 }
    453 
    454 
    455 void rf_MapParityDeclusteredPQ(
    456   RF_Raid_t       *raidPtr,
    457   RF_RaidAddr_t    raidSector,
    458   RF_RowCol_t     *row,
    459   RF_RowCol_t     *col,
    460   RF_SectorNum_t  *diskSector,
    461   int              remap)
    462 {
    463   RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    464   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    465   RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    466   RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    467   RF_StripeNum_t BlockID, BlockOffset, RepIndex;
    468   RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    469   RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    470   RF_StripeNum_t base_suid = 0, outSU, SpareRegion, SpareSpace=0;
    471 
    472   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    473 
    474   /* compute row & (possibly) spare space exactly as before */
    475   FullTableID     = SUID / sus_per_fulltable;
    476   *row            = FullTableID % raidPtr->numRow;
    477   FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    478   if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    479     SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    480     SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    481   }
    482 
    483   /* compute BlockID and RepIndex exactly as before */
    484   FullTableOffset = SUID % sus_per_fulltable;
    485   TableID         = FullTableOffset / info->SUsPerTable;
    486     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    487     BlockID         = TableOffset / info->PUsPerBlock;
    488     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    489     BlockID        %= info->BlocksPerTable;
    490 
    491   /* the parity block is in the position indicated by RepIndex */
    492   RepIndex        = (raidPtr->noRotate) ? info->PUsPerBlock : info->groupSize - 1 - TableID;
    493   *col	    = info->LayoutTable[BlockID][RepIndex];
    494 
    495   if (remap)
    496     RF_PANIC();
    497 
    498   /* compute sector as before, except use RepIndex instead of BlockOffset */
    499   outSU        = base_suid;
    500   outSU       += FullTableID * fulltable_depth;
    501   outSU	+= SpareSpace;						/* skip rsvd spare space */
    502   outSU       += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    503   outSU       += info->OffsetTable[BlockID][RepIndex] * layoutPtr->SUsPerPU;
    504   outSU       += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
    505 
    506   *diskSector  = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    507 }
    508 
    509 void rf_MapQDeclusteredPQ(
    510   RF_Raid_t       *raidPtr,
    511   RF_RaidAddr_t    raidSector,
    512   RF_RowCol_t     *row,
    513   RF_RowCol_t     *col,
    514   RF_SectorNum_t  *diskSector,
    515   int              remap)
    516 {
    517   RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    518   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    519   RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    520   RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    521   RF_StripeNum_t BlockID, BlockOffset, RepIndex, RepIndexQ;
    522   RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    523   RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    524   RF_StripeNum_t base_suid = 0, outSU, SpareRegion, SpareSpace=0;
    525 
    526   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    527 
    528   /* compute row & (possibly) spare space exactly as before */
    529   FullTableID     = SUID / sus_per_fulltable;
    530   *row            = FullTableID % raidPtr->numRow;
    531   FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    532   if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    533     SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    534     SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    535   }
    536 
    537   /* compute BlockID and RepIndex exactly as before */
    538   FullTableOffset = SUID % sus_per_fulltable;
    539   TableID         = FullTableOffset / info->SUsPerTable;
    540     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    541     BlockID         = TableOffset / info->PUsPerBlock;
    542     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    543     BlockID        %= info->BlocksPerTable;
    544 
    545   /* the q block is in the position indicated by RepIndex */
    546   RepIndex        = (raidPtr->noRotate) ? info->PUsPerBlock : info->groupSize - 1 - TableID;
    547   RepIndexQ = ((RepIndex == (info->groupSize-1)) ? 0 : RepIndex+1);
    548   *col = info->LayoutTable[BlockID][RepIndexQ];
    549 
    550   if (remap)
    551     RF_PANIC();
    552 
    553   /* compute sector as before, except use RepIndex instead of BlockOffset */
    554   outSU        = base_suid;
    555   outSU       += FullTableID * fulltable_depth;
    556   outSU	+= SpareSpace;						/* skip rsvd spare space */
    557   outSU       += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    558   outSU       += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
    559 
    560   outSU       += info->OffsetTable[BlockID][RepIndexQ] * layoutPtr->SUsPerPU;
    561   *diskSector = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    562 }
    563 
    564 /* returns an array of ints identifying the disks that comprise the stripe containing the indicated address.
    565  * the caller must _never_ attempt to modify this array.
    566  */
    567 void rf_IdentifyStripeDeclusteredPQ(
    568   RF_Raid_t        *raidPtr,
    569   RF_RaidAddr_t     addr,
    570   RF_RowCol_t     **diskids,
    571   RF_RowCol_t      *outRow)
    572 {
    573   RF_RaidLayout_t *layoutPtr           = &(raidPtr->Layout);
    574   RF_DeclusteredConfigInfo_t *info     = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    575   RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    576   RF_StripeCount_t fulltable_depth   = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    577   RF_StripeNum_t base_suid         = 0;
    578   RF_StripeNum_t SUID              = rf_RaidAddressToStripeUnitID(layoutPtr, addr);
    579   RF_StripeNum_t stripeID, FullTableID;
    580   int tableOffset;
    581 
    582   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    583   FullTableID     = SUID / sus_per_fulltable;		/* fulltable ID within array (across rows) */
    584   *outRow         = FullTableID % raidPtr->numRow;
    585   stripeID = rf_StripeUnitIDToStripeID(layoutPtr, SUID);                     /* find stripe offset into array */
    586   tableOffset = (stripeID % info->BlocksPerTable);                        /* find offset into block design table */
    587   *diskids = info->LayoutTable[tableOffset];
    588 }
    589