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