Home | History | Annotate | Line # | Download | only in raidframe
rf_declusterPQ.c revision 1.2
      1 /*	$NetBSD: rf_declusterPQ.c,v 1.2 1999/01/26 02:33:55 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 #include "rf_types.h"
     39 #include "rf_raid.h"
     40 #include "rf_configure.h"
     41 #include "rf_decluster.h"
     42 #include "rf_declusterPQ.h"
     43 #include "rf_debugMem.h"
     44 #include "rf_utils.h"
     45 #include "rf_alloclist.h"
     46 #include "rf_general.h"
     47 
     48 /* configuration code */
     49 
     50 int rf_ConfigureDeclusteredPQ(
     51   RF_ShutdownList_t  **listp,
     52   RF_Raid_t           *raidPtr,
     53   RF_Config_t         *cfgPtr)
     54 {
     55     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
     56     int b, v, k, r, lambda;				/* block design params */
     57     int i, j, l;
     58     int *first_avail_slot;
     59     int  complete_FT_count, SUID;
     60     RF_DeclusteredConfigInfo_t *info;
     61     int numCompleteFullTablesPerDisk;
     62     int PUsPerDisk, spareRegionDepthInPUs, numCompleteSpareRegionsPerDisk = 0, extraPUsPerDisk;
     63     int totSparePUsPerDisk;
     64     int diskOffsetOfLastFullTableInSUs, SpareSpaceInSUs;
     65     char *cfgBuf = (char *) (cfgPtr->layoutSpecific);
     66 
     67     cfgBuf += RF_SPAREMAP_NAME_LEN;
     68 
     69     b        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
     70     v        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
     71     k        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
     72     r        = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
     73     lambda   = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
     74     raidPtr->noRotate = *( (int *) cfgBuf);   cfgBuf += sizeof(int);
     75 
     76     if (k <= 2) {
     77       printf("RAIDFRAME: k=%d, minimum value 2\n", k);
     78       return(EINVAL);
     79     }
     80 
     81     /* 1. create layout specific structure */
     82     RF_MallocAndAdd(info, sizeof(RF_DeclusteredConfigInfo_t), (RF_DeclusteredConfigInfo_t *), raidPtr->cleanupList);
     83     if (info == NULL)
     84       return(ENOMEM);
     85     layoutPtr->layoutSpecificInfo = (void *) info;
     86 
     87     /* the sparemaps are generated assuming that parity is rotated, so we issue
     88      * a warning if both distributed sparing and no-rotate are on at the same time
     89      */
     90     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE) && raidPtr->noRotate) {
     91 	RF_ERRORMSG("Warning:  distributed sparing specified without parity rotation.\n");
     92     }
     93 
     94     if (raidPtr->numCol != v) {
     95         RF_ERRORMSG2("RAID: config error: table element count (%d) not equal to no. of cols (%d)\n", v, raidPtr->numCol);
     96         return(EINVAL);
     97     }
     98 
     99     /* 3.  set up the values used in devRaidMap */
    100     info->BlocksPerTable = b;
    101     info->NumParityReps = info->groupSize = k;
    102     info->PUsPerBlock = k-2;  /* PQ */
    103     info->SUsPerTable = b * info->PUsPerBlock * layoutPtr->SUsPerPU;/* b blks, k-1 SUs each */
    104     info->SUsPerFullTable = k * info->SUsPerTable;	/* rot k times */
    105     info->SUsPerBlock = info->PUsPerBlock * layoutPtr->SUsPerPU;
    106     info->TableDepthInPUs = (b*k) / v;
    107     info->FullTableDepthInPUs = info->TableDepthInPUs * k;		/* k repetitions */
    108 
    109     /* used only in distributed sparing case */
    110     info->FullTablesPerSpareRegion = (v-1) / rf_gcd(r, v-1);		/* (v-1)/gcd fulltables */
    111     info->TablesPerSpareRegion = k * info->FullTablesPerSpareRegion;
    112     info->SpareSpaceDepthPerRegionInSUs = (r * info->TablesPerSpareRegion / (v-1)) * layoutPtr->SUsPerPU;
    113 
    114     /* check to make sure the block design is sufficiently small */
    115     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    116         if (info->FullTableDepthInPUs * layoutPtr->SUsPerPU + info->SpareSpaceDepthPerRegionInSUs > layoutPtr->stripeUnitsPerDisk) {
    117 	    RF_ERRORMSG3("RAID: config error: Full Table depth (%d) + Spare Space (%d) larger than disk size (%d) (BD too big)\n",
    118 			 (int)info->FullTableDepthInPUs,
    119 			 (int)info->SpareSpaceDepthPerRegionInSUs,
    120 			 (int)layoutPtr->stripeUnitsPerDisk);
    121 	    return(EINVAL);
    122 	}
    123     } else {
    124 	if (info->TableDepthInPUs * layoutPtr->SUsPerPU > layoutPtr->stripeUnitsPerDisk) {
    125 	    RF_ERRORMSG2("RAID: config error: Table depth (%d) larger than disk size (%d) (BD too big)\n",
    126 			 (int)(info->TableDepthInPUs * layoutPtr->SUsPerPU),
    127 			 (int)layoutPtr->stripeUnitsPerDisk);
    128 	    return(EINVAL);
    129 	}
    130     }
    131 
    132 
    133     /* compute the size of each disk, and the number of tables in the last fulltable (which
    134      * need not be complete)
    135      */
    136     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    137 
    138 	PUsPerDisk = layoutPtr->stripeUnitsPerDisk / layoutPtr->SUsPerPU;
    139 	spareRegionDepthInPUs = (info->TablesPerSpareRegion * info->TableDepthInPUs +
    140 				 (info->TablesPerSpareRegion * info->TableDepthInPUs) / (v-1));
    141 	info->SpareRegionDepthInSUs = spareRegionDepthInPUs * layoutPtr->SUsPerPU;
    142 
    143 	numCompleteSpareRegionsPerDisk = PUsPerDisk / spareRegionDepthInPUs;
    144 	info->NumCompleteSRs = numCompleteSpareRegionsPerDisk;
    145 	extraPUsPerDisk = PUsPerDisk % spareRegionDepthInPUs;
    146 
    147 	/* assume conservatively that we need the full amount of spare space in one region in order
    148 	 * to provide spares for the partial spare region at the end of the array.  We set "i" to
    149 	 * the number of tables in the partial spare region.  This may actually include some fulltables.
    150 	 */
    151 	extraPUsPerDisk -= (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
    152 	if (extraPUsPerDisk <= 0) i = 0;
    153 	else i = extraPUsPerDisk/info->TableDepthInPUs;
    154 
    155 	complete_FT_count = raidPtr->numRow * (numCompleteSpareRegionsPerDisk * (info->TablesPerSpareRegion/k) + i/k);
    156         info->FullTableLimitSUID = complete_FT_count * info->SUsPerFullTable;
    157 	info->ExtraTablesPerDisk = i % k;
    158 
    159 	/* note that in the last spare region, the spare space is complete even though data/parity space is not */
    160 	totSparePUsPerDisk = (numCompleteSpareRegionsPerDisk+1) * (info->SpareSpaceDepthPerRegionInSUs / layoutPtr->SUsPerPU);
    161 	info->TotSparePUsPerDisk = totSparePUsPerDisk;
    162 
    163 	layoutPtr->stripeUnitsPerDisk =
    164 	    ((complete_FT_count/raidPtr->numRow) * info->FullTableDepthInPUs +	 	/* data & parity space */
    165 	     info->ExtraTablesPerDisk * info->TableDepthInPUs +
    166 	     totSparePUsPerDisk								/* spare space */
    167 	    ) * layoutPtr->SUsPerPU;
    168 	layoutPtr->dataStripeUnitsPerDisk =
    169 	    (complete_FT_count * info->FullTableDepthInPUs + info->ExtraTablesPerDisk * info->TableDepthInPUs)
    170 	    * layoutPtr->SUsPerPU * (k-1) / k;
    171 
    172     } else {
    173         /* non-dist spare case:  force each disk to contain an integral number of tables */
    174         layoutPtr->stripeUnitsPerDisk /= (info->TableDepthInPUs * layoutPtr->SUsPerPU);
    175         layoutPtr->stripeUnitsPerDisk *= (info->TableDepthInPUs * layoutPtr->SUsPerPU);
    176 
    177 	/* compute the number of tables in the last fulltable, which need not be complete */
    178         complete_FT_count =
    179             ((layoutPtr->stripeUnitsPerDisk/layoutPtr->SUsPerPU) / info->FullTableDepthInPUs) * raidPtr->numRow;
    180 
    181         info->FullTableLimitSUID = complete_FT_count * info->SUsPerFullTable;
    182         info->ExtraTablesPerDisk =
    183 		((layoutPtr->stripeUnitsPerDisk/layoutPtr->SUsPerPU) / info->TableDepthInPUs) % k;
    184     }
    185 
    186     raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
    187 
    188     /* find the disk offset of the stripe unit where the last fulltable starts */
    189     numCompleteFullTablesPerDisk = complete_FT_count / raidPtr->numRow;
    190     diskOffsetOfLastFullTableInSUs = numCompleteFullTablesPerDisk * info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    191     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    192         SpareSpaceInSUs  = numCompleteSpareRegionsPerDisk * info->SpareSpaceDepthPerRegionInSUs;
    193         diskOffsetOfLastFullTableInSUs += SpareSpaceInSUs;
    194         info->DiskOffsetOfLastSpareSpaceChunkInSUs =
    195 	    diskOffsetOfLastFullTableInSUs + info->ExtraTablesPerDisk * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    196     }
    197     info->DiskOffsetOfLastFullTableInSUs = diskOffsetOfLastFullTableInSUs;
    198     info->numCompleteFullTablesPerDisk = numCompleteFullTablesPerDisk;
    199 
    200     /* 4.  create and initialize the lookup tables */
    201     info->LayoutTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
    202     if (info->LayoutTable == NULL)
    203       return(ENOMEM);
    204     info->OffsetTable = rf_make_2d_array(b, k, raidPtr->cleanupList);
    205     if (info->OffsetTable == NULL)
    206       return(ENOMEM);
    207     info->BlockTable  =	rf_make_2d_array(info->TableDepthInPUs*layoutPtr->SUsPerPU, raidPtr->numCol, raidPtr->cleanupList);
    208     if (info->BlockTable == NULL)
    209       return(ENOMEM);
    210 
    211     first_avail_slot  = (int *) rf_make_1d_array(v, NULL);
    212     if (first_avail_slot == NULL)
    213       return(ENOMEM);
    214 
    215     for (i=0; i<b; i++)
    216       for (j=0; j<k; j++)
    217         info->LayoutTable[i][j] = *cfgBuf++;
    218 
    219     /* initialize offset table */
    220     for (i=0; i<b; i++) for (j=0; j<k; j++) {
    221         info->OffsetTable[i][j] = first_avail_slot[ info->LayoutTable[i][j] ];
    222         first_avail_slot[ info->LayoutTable[i][j] ]++;
    223     }
    224 
    225     /* initialize block table */
    226     for (SUID=l=0; l<layoutPtr->SUsPerPU; l++) {
    227         for (i=0; i<b; i++) {
    228             for (j=0; j<k; j++) {
    229                 info->BlockTable[ (info->OffsetTable[i][j] * layoutPtr->SUsPerPU) + l ]
    230 		                [ info->LayoutTable[i][j] ] = SUID;
    231             }
    232             SUID++;
    233         }
    234     }
    235 
    236     rf_free_1d_array(first_avail_slot, v);
    237 
    238     /* 5.  set up the remaining redundant-but-useful parameters */
    239 
    240     raidPtr->totalSectors = (k*complete_FT_count + raidPtr->numRow*info->ExtraTablesPerDisk) *
    241     			  info->SUsPerTable * layoutPtr->sectorsPerStripeUnit;
    242     layoutPtr->numStripe = (raidPtr->totalSectors / layoutPtr->sectorsPerStripeUnit) / (k-2);
    243 
    244     /* strange evaluation order below to try and minimize overflow problems */
    245 
    246     layoutPtr->dataSectorsPerStripe = (k-2) * layoutPtr->sectorsPerStripeUnit;
    247     layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
    248     layoutPtr->numDataCol = k-2;
    249     layoutPtr->numParityCol = 2;
    250 
    251     return(0);
    252 }
    253 
    254 int rf_GetDefaultNumFloatingReconBuffersPQ(RF_Raid_t *raidPtr)
    255 {
    256   int def_decl;
    257 
    258   def_decl = rf_GetDefaultNumFloatingReconBuffersDeclustered(raidPtr);
    259   return(RF_MAX(3 * raidPtr->numCol, def_decl));
    260 }
    261 
    262 void rf_MapSectorDeclusteredPQ(
    263   RF_Raid_t         *raidPtr,
    264   RF_RaidAddr_t      raidSector,
    265   RF_RowCol_t       *row,
    266   RF_RowCol_t       *col,
    267   RF_SectorNum_t    *diskSector,
    268   int                remap)
    269 {
    270     RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    271     RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    272     RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    273     RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    274     RF_StripeNum_t BlockID, BlockOffset, RepIndex;
    275     RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    276     RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    277     RF_StripeNum_t base_suid = 0, outSU, SpareRegion=0, SpareSpace=0;
    278 
    279     rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    280 
    281     FullTableID     = SUID / sus_per_fulltable;		/* fulltable ID within array (across rows) */
    282     *row            = FullTableID % raidPtr->numRow;
    283     FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    284     if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    285 	SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    286         SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    287     }
    288     FullTableOffset = SUID % sus_per_fulltable;
    289     TableID         = FullTableOffset / info->SUsPerTable;
    290     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    291     BlockID         = TableOffset / info->PUsPerBlock;
    292     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    293     BlockID        %= info->BlocksPerTable;
    294     RF_ASSERT(BlockOffset < info->groupSize-2 );
    295     /*
    296        TableIDs go from 0 .. GroupSize-1 inclusive.
    297        PUsPerBlock is k-2.
    298        We want the tableIDs to rotate from the
    299        right, so use GroupSize
    300        */
    301     RepIndex        = info->groupSize - 1 - TableID;
    302     RF_ASSERT(RepIndex >= 0);
    303     if (!raidPtr->noRotate)
    304       {
    305 	if (TableID==0)
    306 	    BlockOffset++; /* P on last drive, Q on first */
    307 	else
    308 	  BlockOffset    += ((BlockOffset >= RepIndex) ? 2 : 0); /* skip over PQ */
    309 	RF_ASSERT(BlockOffset < info->groupSize);
    310 	*col            = info->LayoutTable[BlockID][BlockOffset];
    311       }
    312 
    313     /* remap to distributed spare space if indicated */
    314     if (remap) {
    315 	rf_remap_to_spare_space(layoutPtr, info, *row, FullTableID, TableID, BlockID, (base_suid) ? 1 : 0, SpareRegion, col, &outSU);
    316     } else {
    317 
    318         outSU	    = base_suid;
    319         outSU      += FullTableID * fulltable_depth;  				        /* offs to strt of FT */
    320         outSU	   += SpareSpace;						        /* skip rsvd spare space */
    321         outSU      += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;   	        /* offs to strt of tble */
    322         outSU      += info->OffsetTable[BlockID][BlockOffset] * layoutPtr->SUsPerPU;	/* offs to the PU */
    323     }
    324     outSU          += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);	        /* offs to the SU within a PU */
    325 
    326     /* convert SUs to sectors, and, if not aligned to SU boundary, add in offset to sector */
    327     *diskSector     = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    328 }
    329 
    330 
    331 void rf_MapParityDeclusteredPQ(
    332   RF_Raid_t       *raidPtr,
    333   RF_RaidAddr_t    raidSector,
    334   RF_RowCol_t     *row,
    335   RF_RowCol_t     *col,
    336   RF_SectorNum_t  *diskSector,
    337   int              remap)
    338 {
    339   RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    340   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    341   RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    342   RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    343   RF_StripeNum_t BlockID, BlockOffset, RepIndex;
    344   RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    345   RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    346   RF_StripeNum_t base_suid = 0, outSU, SpareRegion, SpareSpace=0;
    347 
    348   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    349 
    350   /* compute row & (possibly) spare space exactly as before */
    351   FullTableID     = SUID / sus_per_fulltable;
    352   *row            = FullTableID % raidPtr->numRow;
    353   FullTableID    /= raidPtr->numRow;			/* convert to fulltable ID on this disk */
    354   if ((raidPtr->Layout.map->flags & RF_DISTRIBUTE_SPARE)) {
    355     SpareRegion = FullTableID / info->FullTablesPerSpareRegion;
    356     SpareSpace  = SpareRegion * info->SpareSpaceDepthPerRegionInSUs;
    357   }
    358 
    359   /* compute BlockID and RepIndex exactly as before */
    360   FullTableOffset = SUID % sus_per_fulltable;
    361   TableID         = FullTableOffset / info->SUsPerTable;
    362     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    363     BlockID         = TableOffset / info->PUsPerBlock;
    364     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    365     BlockID        %= info->BlocksPerTable;
    366 
    367   /* the parity block is in the position indicated by RepIndex */
    368   RepIndex        = (raidPtr->noRotate) ? info->PUsPerBlock : info->groupSize - 1 - TableID;
    369   *col	    = info->LayoutTable[BlockID][RepIndex];
    370 
    371   if (remap)
    372     RF_PANIC();
    373 
    374   /* compute sector as before, except use RepIndex instead of BlockOffset */
    375   outSU        = base_suid;
    376   outSU       += FullTableID * fulltable_depth;
    377   outSU	+= SpareSpace;						/* skip rsvd spare space */
    378   outSU       += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    379   outSU       += info->OffsetTable[BlockID][RepIndex] * layoutPtr->SUsPerPU;
    380   outSU       += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
    381 
    382   *diskSector  = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    383 }
    384 
    385 void rf_MapQDeclusteredPQ(
    386   RF_Raid_t       *raidPtr,
    387   RF_RaidAddr_t    raidSector,
    388   RF_RowCol_t     *row,
    389   RF_RowCol_t     *col,
    390   RF_SectorNum_t  *diskSector,
    391   int              remap)
    392 {
    393   RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
    394   RF_DeclusteredConfigInfo_t *info = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    395   RF_StripeNum_t SUID = raidSector / layoutPtr->sectorsPerStripeUnit;
    396   RF_StripeNum_t FullTableID, FullTableOffset, TableID, TableOffset;
    397   RF_StripeNum_t BlockID, BlockOffset, RepIndex, RepIndexQ;
    398   RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    399   RF_StripeCount_t fulltable_depth  = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    400   RF_StripeNum_t base_suid = 0, outSU, SpareRegion, SpareSpace=0;
    401 
    402   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    403 
    404   /* compute row & (possibly) spare space exactly as before */
    405   FullTableID     = SUID / sus_per_fulltable;
    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 
    413   /* compute BlockID and RepIndex exactly as before */
    414   FullTableOffset = SUID % sus_per_fulltable;
    415   TableID         = FullTableOffset / info->SUsPerTable;
    416     TableOffset     = FullTableOffset - TableID * info->SUsPerTable;
    417     BlockID         = TableOffset / info->PUsPerBlock;
    418     BlockOffset     = TableOffset - BlockID * info->PUsPerBlock;
    419     BlockID        %= info->BlocksPerTable;
    420 
    421   /* the q block is in the position indicated by RepIndex */
    422   RepIndex        = (raidPtr->noRotate) ? info->PUsPerBlock : info->groupSize - 1 - TableID;
    423   RepIndexQ = ((RepIndex == (info->groupSize-1)) ? 0 : RepIndex+1);
    424   *col = info->LayoutTable[BlockID][RepIndexQ];
    425 
    426   if (remap)
    427     RF_PANIC();
    428 
    429   /* compute sector as before, except use RepIndex instead of BlockOffset */
    430   outSU        = base_suid;
    431   outSU       += FullTableID * fulltable_depth;
    432   outSU	+= SpareSpace;						/* skip rsvd spare space */
    433   outSU       += TableID * info->TableDepthInPUs * layoutPtr->SUsPerPU;
    434   outSU       += TableOffset / (info->BlocksPerTable * info->PUsPerBlock);
    435 
    436   outSU       += info->OffsetTable[BlockID][RepIndexQ] * layoutPtr->SUsPerPU;
    437   *diskSector = outSU*layoutPtr->sectorsPerStripeUnit + (raidSector % layoutPtr->sectorsPerStripeUnit);
    438 }
    439 
    440 /* returns an array of ints identifying the disks that comprise the stripe containing the indicated address.
    441  * the caller must _never_ attempt to modify this array.
    442  */
    443 void rf_IdentifyStripeDeclusteredPQ(
    444   RF_Raid_t        *raidPtr,
    445   RF_RaidAddr_t     addr,
    446   RF_RowCol_t     **diskids,
    447   RF_RowCol_t      *outRow)
    448 {
    449   RF_RaidLayout_t *layoutPtr           = &(raidPtr->Layout);
    450   RF_DeclusteredConfigInfo_t *info     = (RF_DeclusteredConfigInfo_t *) layoutPtr->layoutSpecificInfo;
    451   RF_StripeCount_t sus_per_fulltable = info->SUsPerFullTable;
    452   RF_StripeCount_t fulltable_depth   = info->FullTableDepthInPUs * layoutPtr->SUsPerPU;
    453   RF_StripeNum_t base_suid         = 0;
    454   RF_StripeNum_t SUID              = rf_RaidAddressToStripeUnitID(layoutPtr, addr);
    455   RF_StripeNum_t stripeID, FullTableID;
    456   int tableOffset;
    457 
    458   rf_decluster_adjust_params(layoutPtr, &SUID, &sus_per_fulltable, &fulltable_depth, &base_suid);
    459   FullTableID     = SUID / sus_per_fulltable;		/* fulltable ID within array (across rows) */
    460   *outRow         = FullTableID % raidPtr->numRow;
    461   stripeID = rf_StripeUnitIDToStripeID(layoutPtr, SUID);                     /* find stripe offset into array */
    462   tableOffset = (stripeID % info->BlocksPerTable);                        /* find offset into block design table */
    463   *diskids = info->LayoutTable[tableOffset];
    464 }
    465