rf_chaindecluster.c revision 1.6.2.2 1 /* $NetBSD: rf_chaindecluster.c,v 1.6.2.2 2001/11/14 19:15:46 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.2 2001/11/14 19:15:46 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->bytesPerStripeUnit = layoutPtr->sectorsPerStripeUnit << raidPtr->logBytesPerSector;
99 layoutPtr->numDataCol = 1;
100 layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
101 layoutPtr->numParityCol = 1;
102
103 layoutPtr->dataStripeUnitsPerDisk = num_used_stripeUnitsPerDisk;
104
105 raidPtr->sectorsPerDisk =
106 num_used_stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
107
108 raidPtr->totalSectors =
109 (layoutPtr->numStripe) * layoutPtr->sectorsPerStripeUnit;
110
111 layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk / layoutPtr->sectorsPerStripeUnit;
112
113 return (0);
114 }
115
116 RF_ReconUnitCount_t
117 rf_GetNumSpareRUsChainDecluster(raidPtr)
118 RF_Raid_t *raidPtr;
119 {
120 RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
121
122 /*
123 * The layout uses two stripe units per disk as spare within each
124 * sparing region.
125 */
126 return (2 * info->numSparingRegions);
127 }
128
129
130 /* Maps to the primary copy of the data, i.e. the first mirror pair */
131 void
132 rf_MapSectorChainDecluster(
133 RF_Raid_t * raidPtr,
134 RF_RaidAddr_t raidSector,
135 RF_RowCol_t * row,
136 RF_RowCol_t * col,
137 RF_SectorNum_t * diskSector,
138 int remap)
139 {
140 RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
141 RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
142 RF_SectorNum_t index_within_region, index_within_disk;
143 RF_StripeNum_t sparing_region_id;
144 int col_before_remap;
145
146 *row = 0;
147 sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
148 index_within_region = SUID % info->stripeUnitsPerSparingRegion;
149 index_within_disk = index_within_region / raidPtr->numCol;
150 col_before_remap = SUID % raidPtr->numCol;
151
152 if (!remap) {
153 *col = col_before_remap;
154 *diskSector = (index_within_disk + ((raidPtr->numCol - 1) * sparing_region_id)) *
155 raidPtr->Layout.sectorsPerStripeUnit;
156 *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
157 } else {
158 /* remap sector to spare space... */
159 *diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
160 *diskSector += (raidPtr->numCol - 1) * raidPtr->Layout.sectorsPerStripeUnit;
161 *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
162 index_within_disk = index_within_region / raidPtr->numCol;
163 if (index_within_disk < col_before_remap)
164 *col = index_within_disk;
165 else
166 if (index_within_disk == raidPtr->numCol - 2) {
167 *col = (col_before_remap + raidPtr->numCol - 1) % raidPtr->numCol;
168 *diskSector += raidPtr->Layout.sectorsPerStripeUnit;
169 } else
170 *col = (index_within_disk + 2) % raidPtr->numCol;
171 }
172
173 }
174
175
176
177 /* Maps to the second copy of the mirror pair, which is chain declustered. The second copy is contained
178 in the next disk (mod numCol) after the disk containing the primary copy.
179 The offset into the disk is one-half disk down */
180 void
181 rf_MapParityChainDecluster(
182 RF_Raid_t * raidPtr,
183 RF_RaidAddr_t raidSector,
184 RF_RowCol_t * row,
185 RF_RowCol_t * col,
186 RF_SectorNum_t * diskSector,
187 int remap)
188 {
189 RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
190 RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
191 RF_SectorNum_t index_within_region, index_within_disk;
192 RF_StripeNum_t sparing_region_id;
193 int col_before_remap;
194
195 *row = 0;
196 if (!remap) {
197 *col = SUID % raidPtr->numCol;
198 *col = (*col + 1) % raidPtr->numCol;
199 *diskSector = info->mirrorStripeOffset * raidPtr->Layout.sectorsPerStripeUnit;
200 *diskSector += (SUID / raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
201 *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
202 } else {
203 /* remap parity to spare space ... */
204 sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
205 index_within_region = SUID % info->stripeUnitsPerSparingRegion;
206 index_within_disk = index_within_region / raidPtr->numCol;
207 *diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
208 *diskSector += (raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
209 *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
210 col_before_remap = SUID % raidPtr->numCol;
211 if (index_within_disk < col_before_remap)
212 *col = index_within_disk;
213 else
214 if (index_within_disk == raidPtr->numCol - 2) {
215 *col = (col_before_remap + 2) % raidPtr->numCol;
216 *diskSector -= raidPtr->Layout.sectorsPerStripeUnit;
217 } else
218 *col = (index_within_disk + 2) % raidPtr->numCol;
219 }
220
221 }
222
223 void
224 rf_IdentifyStripeChainDecluster(
225 RF_Raid_t * raidPtr,
226 RF_RaidAddr_t addr,
227 RF_RowCol_t ** diskids,
228 RF_RowCol_t * outRow)
229 {
230 RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
231 RF_StripeNum_t SUID;
232 RF_RowCol_t col;
233
234 SUID = addr / raidPtr->Layout.sectorsPerStripeUnit;
235 col = SUID % raidPtr->numCol;
236 *outRow = 0;
237 *diskids = info->stripeIdentifier[col];
238 }
239
240 void
241 rf_MapSIDToPSIDChainDecluster(
242 RF_RaidLayout_t * layoutPtr,
243 RF_StripeNum_t stripeID,
244 RF_StripeNum_t * psID,
245 RF_ReconUnitNum_t * which_ru)
246 {
247 *which_ru = 0;
248 *psID = stripeID;
249 }
250 /******************************************************************************
251 * select a graph to perform a single-stripe access
252 *
253 * Parameters: raidPtr - description of the physical array
254 * type - type of operation (read or write) requested
255 * asmap - logical & physical addresses for this access
256 * createFunc - function to use to create the graph (return value)
257 *****************************************************************************/
258
259 void
260 rf_RAIDCDagSelect(
261 RF_Raid_t * raidPtr,
262 RF_IoType_t type,
263 RF_AccessStripeMap_t * asmap,
264 RF_VoidFuncPtr * createFunc)
265 #if 0
266 void (**createFunc) (RF_Raid_t *, RF_AccessStripeMap_t *,
267 RF_DagHeader_t *, void *, RF_RaidAccessFlags_t,
268 RF_AllocListElem_t *)
269 #endif
270 {
271 RF_ASSERT(RF_IO_IS_R_OR_W(type));
272 RF_ASSERT(raidPtr->numRow == 1);
273
274 if (asmap->numDataFailed + asmap->numParityFailed > 1) {
275 RF_ERRORMSG("Multiple disks failed in a single group! Aborting I/O operation.\n");
276 *createFunc = NULL;
277 return;
278 }
279 *createFunc = (type == RF_IO_TYPE_READ) ? (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG : (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
280
281 if (type == RF_IO_TYPE_READ) {
282 if ((raidPtr->status[0] == rf_rs_degraded) || (raidPtr->status[0] == rf_rs_reconstructing))
283 *createFunc = (RF_VoidFuncPtr) rf_CreateRaidCDegradedReadDAG; /* array status is
284 * degraded, implement
285 * workload shifting */
286 else
287 *createFunc = (RF_VoidFuncPtr) rf_CreateMirrorPartitionReadDAG; /* array status not
288 * degraded, so use
289 * mirror partition dag */
290 } else
291 *createFunc = (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
292 }
293 #endif /* (RF_INCLUDE_CHAINDECLUSTER > 0) */
294