rf_chaindecluster.c revision 1.2
1/*	$NetBSD: rf_chaindecluster.c,v 1.2 1999/01/26 02:33:50 oster Exp $	*/
2/*
3 * Copyright (c) 1995 Carnegie-Mellon University.
4 * All rights reserved.
5 *
6 * Author: Khalil Amiri
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@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 *
31 * rf_chaindecluster.c -- implements chained declustering
32 *
33 *****************************************************************************/
34
35#include "rf_archs.h"
36#include "rf_types.h"
37#include "rf_raid.h"
38#include "rf_chaindecluster.h"
39#include "rf_dag.h"
40#include "rf_dagutils.h"
41#include "rf_dagffrd.h"
42#include "rf_dagffwr.h"
43#include "rf_dagdegrd.h"
44#include "rf_dagfuncs.h"
45#include "rf_threadid.h"
46#include "rf_general.h"
47#include "rf_utils.h"
48
49typedef struct RF_ChaindeclusterConfigInfo_s {
50  RF_RowCol_t       **stripeIdentifier;   /* filled in at config time
51                                           * and used by IdentifyStripe */
52  RF_StripeCount_t    numSparingRegions;
53  RF_StripeCount_t    stripeUnitsPerSparingRegion;
54  RF_SectorNum_t      mirrorStripeOffset;
55} RF_ChaindeclusterConfigInfo_t;
56
57int rf_ConfigureChainDecluster(
58  RF_ShutdownList_t  **listp,
59  RF_Raid_t           *raidPtr,
60  RF_Config_t         *cfgPtr)
61{
62  RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
63  RF_StripeCount_t num_used_stripeUnitsPerDisk;
64  RF_ChaindeclusterConfigInfo_t *info;
65  RF_RowCol_t i;
66
67  /* create a Chained Declustering configuration structure */
68  RF_MallocAndAdd(info, sizeof(RF_ChaindeclusterConfigInfo_t), (RF_ChaindeclusterConfigInfo_t *), raidPtr->cleanupList);
69  if (info == NULL)
70    return(ENOMEM);
71  layoutPtr->layoutSpecificInfo = (void *) info;
72
73  /*  fill in the config structure.  */
74  info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, 2 , raidPtr->cleanupList);
75  if (info->stripeIdentifier == NULL)
76    return(ENOMEM);
77  for (i=0; i< raidPtr->numCol; i++) {
78      info->stripeIdentifier[i][0] = i % raidPtr->numCol;
79      info->stripeIdentifier[i][1] = (i+1) % raidPtr->numCol;
80    }
81
82  RF_ASSERT(raidPtr->numRow == 1);
83
84  /* fill in the remaining layout parameters */
85  num_used_stripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk - (layoutPtr->stripeUnitsPerDisk %
86        (2*raidPtr->numCol-2) );
87  info->numSparingRegions = num_used_stripeUnitsPerDisk / (2*raidPtr->numCol-2);
88  info->stripeUnitsPerSparingRegion = raidPtr->numCol * (raidPtr->numCol - 1);
89  info->mirrorStripeOffset = info->numSparingRegions * (raidPtr->numCol-1);
90  layoutPtr->numStripe = info->numSparingRegions * info->stripeUnitsPerSparingRegion;
91  layoutPtr->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
92  layoutPtr->numDataCol = 1;
93  layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
94  layoutPtr->numParityCol = 1;
95
96 layoutPtr->dataStripeUnitsPerDisk = num_used_stripeUnitsPerDisk;
97
98 raidPtr->sectorsPerDisk =
99     num_used_stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
100
101  raidPtr->totalSectors =
102     (layoutPtr->numStripe) * layoutPtr->sectorsPerStripeUnit;
103
104  layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk / layoutPtr->sectorsPerStripeUnit;
105
106  return(0);
107}
108
109RF_ReconUnitCount_t rf_GetNumSpareRUsChainDecluster(raidPtr)
110  RF_Raid_t  *raidPtr;
111{
112  RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
113
114  /*
115   * The layout uses two stripe units per disk as spare within each
116   * sparing region.
117   */
118  return (2*info->numSparingRegions);
119}
120
121
122/* Maps to the primary copy of the data, i.e. the first mirror pair */
123void rf_MapSectorChainDecluster(
124  RF_Raid_t         *raidPtr,
125  RF_RaidAddr_t      raidSector,
126  RF_RowCol_t       *row,
127  RF_RowCol_t       *col,
128  RF_SectorNum_t    *diskSector,
129  int                remap)
130{
131 RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
132 RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
133 RF_SectorNum_t index_within_region, index_within_disk;
134 RF_StripeNum_t sparing_region_id;
135 int col_before_remap;
136
137 *row = 0;
138 sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
139 index_within_region = SUID % info->stripeUnitsPerSparingRegion;
140 index_within_disk = index_within_region / raidPtr->numCol;
141 col_before_remap = SUID % raidPtr->numCol;
142
143 if (!remap) {
144        *col = col_before_remap;
145        *diskSector = ( index_within_disk + ( (raidPtr->numCol-1) * sparing_region_id) ) *
146                        raidPtr->Layout.sectorsPerStripeUnit;
147        *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
148      }
149 else {
150       /* remap sector to spare space...*/
151      *diskSector = sparing_region_id * (raidPtr->numCol+1) * raidPtr->Layout.sectorsPerStripeUnit;
152      *diskSector += (raidPtr->numCol-1) * raidPtr->Layout.sectorsPerStripeUnit;
153      *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
154      index_within_disk = index_within_region / raidPtr->numCol;
155      if (index_within_disk < col_before_remap )
156        *col = index_within_disk;
157      else if (index_within_disk  == raidPtr->numCol-2 ) {
158        *col = (col_before_remap+raidPtr->numCol-1) % raidPtr->numCol;
159        *diskSector += raidPtr->Layout.sectorsPerStripeUnit;
160        }
161      else
162        *col = (index_within_disk + 2) % raidPtr->numCol;
163   }
164
165}
166
167
168
169/* Maps to the second copy of the mirror pair, which is chain declustered. The second copy is contained
170   in the next disk (mod numCol) after the disk containing the primary copy.
171   The offset into the disk is one-half disk down */
172void rf_MapParityChainDecluster(
173  RF_Raid_t       *raidPtr,
174  RF_RaidAddr_t    raidSector,
175  RF_RowCol_t     *row,
176  RF_RowCol_t     *col,
177  RF_SectorNum_t  *diskSector,
178  int              remap)
179{
180  RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
181  RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
182  RF_SectorNum_t index_within_region, index_within_disk;
183  RF_StripeNum_t sparing_region_id;
184  int col_before_remap;
185
186  *row = 0;
187  if (!remap) {
188        *col = SUID % raidPtr->numCol;
189        *col = (*col + 1) % raidPtr->numCol;
190        *diskSector =  info->mirrorStripeOffset * raidPtr->Layout.sectorsPerStripeUnit;
191        *diskSector += ( SUID / raidPtr->numCol ) * raidPtr->Layout.sectorsPerStripeUnit;
192        *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
193       }
194  else {
195        /* remap parity to spare space ... */
196        sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
197        index_within_region = SUID % info->stripeUnitsPerSparingRegion;
198        index_within_disk = index_within_region / raidPtr->numCol;
199        *diskSector =  sparing_region_id * (raidPtr->numCol+1) * raidPtr->Layout.sectorsPerStripeUnit;
200        *diskSector += (raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
201        *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
202        col_before_remap = SUID % raidPtr->numCol;
203        if (index_within_disk < col_before_remap)
204                *col = index_within_disk;
205        else if (index_within_disk  == raidPtr->numCol-2 ) {
206                *col = (col_before_remap+2) % raidPtr->numCol;
207                *diskSector -= raidPtr->Layout.sectorsPerStripeUnit;
208                }
209        else
210                *col = (index_within_disk + 2) % raidPtr->numCol;
211  }
212
213}
214
215void rf_IdentifyStripeChainDecluster(
216  RF_Raid_t        *raidPtr,
217  RF_RaidAddr_t     addr,
218  RF_RowCol_t     **diskids,
219  RF_RowCol_t      *outRow)
220{
221  RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
222  RF_StripeNum_t SUID;
223  RF_RowCol_t col;
224
225  SUID = addr / raidPtr->Layout.sectorsPerStripeUnit;
226  col = SUID  % raidPtr->numCol;
227  *outRow = 0;
228  *diskids = info->stripeIdentifier[ col ];
229}
230
231void rf_MapSIDToPSIDChainDecluster(
232  RF_RaidLayout_t    *layoutPtr,
233  RF_StripeNum_t      stripeID,
234  RF_StripeNum_t     *psID,
235  RF_ReconUnitNum_t  *which_ru)
236{
237  *which_ru = 0;
238  *psID = stripeID;
239}
240
241/******************************************************************************
242 * select a graph to perform a single-stripe access
243 *
244 * Parameters:  raidPtr    - description of the physical array
245 *              type       - type of operation (read or write) requested
246 *              asmap      - logical & physical addresses for this access
247 *              createFunc - function to use to create the graph (return value)
248 *****************************************************************************/
249
250void rf_RAIDCDagSelect(
251  RF_Raid_t             *raidPtr,
252  RF_IoType_t            type,
253  RF_AccessStripeMap_t  *asmap,
254  RF_VoidFuncPtr *createFunc)
255#if 0
256  void (**createFunc)(RF_Raid_t *, RF_AccessStripeMap_t *,
257		     RF_DagHeader_t *, void *, RF_RaidAccessFlags_t,
258		     RF_AllocListElem_t *))
259#endif
260{
261  RF_ASSERT(RF_IO_IS_R_OR_W(type));
262  RF_ASSERT(raidPtr->numRow == 1);
263
264  if (asmap->numDataFailed + asmap->numParityFailed > 1) {
265    RF_ERRORMSG("Multiple disks failed in a single group!  Aborting I/O operation.\n");
266    *createFunc = NULL;
267    return;
268  }
269
270  *createFunc = (type == RF_IO_TYPE_READ) ? (RF_VoidFuncPtr)rf_CreateFaultFreeReadDAG :(RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
271
272  if (type == RF_IO_TYPE_READ) {
273    if ( ( raidPtr->status[0] == rf_rs_degraded ) || (  raidPtr->status[0] == rf_rs_reconstructing) )
274      *createFunc = (RF_VoidFuncPtr)rf_CreateRaidCDegradedReadDAG;  /* array status is degraded, implement workload shifting */
275    else
276      *createFunc = (RF_VoidFuncPtr)rf_CreateMirrorPartitionReadDAG; /* array status not degraded, so use mirror partition dag */
277  }
278  else
279    *createFunc = (RF_VoidFuncPtr)rf_CreateRaidOneWriteDAG;
280}
281