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