1 /* $OpenBSD: rf_layout.c,v 1.6 2002/12/16 07:01:04 tdeval Exp $ */
2 /* $NetBSD: rf_layout.c,v 1.6 2000/04/17 19:35:12 oster Exp $ */
3
4 /*
5 * Copyright (c) 1995 Carnegie-Mellon University.
6 * All rights reserved.
7 *
8 * Author: Mark Holland
9 *
10 * Permission to use, copy, modify and distribute this software and
11 * its documentation is hereby granted, provided that both the copyright
12 * notice and this permission notice appear in all copies of the
13 * software, derivative works or modified versions, and any portions
14 * thereof, and that both notices appear in supporting documentation.
15 *
16 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
17 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
18 * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
19 *
20 * Carnegie Mellon requests users of this software to return to
21 *
22 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
23 * School of Computer Science
24 * Carnegie Mellon University
25 * Pittsburgh PA 15213-3890
26 *
27 * any improvements or extensions that they make and grant Carnegie the
28 * rights to redistribute these changes.
29 */
30
31 /*
32 * rf_layout.c -- Driver code dealing with layout and mapping issues.
33 */
34
35 #include "rf_types.h"
36 #include "rf_archs.h"
37 #include "rf_raid.h"
38 #include "rf_configure.h"
39 #include "rf_dag.h"
40 #include "rf_desc.h"
41 #include "rf_decluster.h"
42 #include "rf_pq.h"
43 #include "rf_declusterPQ.h"
44 #include "rf_raid0.h"
45 #include "rf_raid1.h"
46 #include "rf_raid4.h"
47 #include "rf_raid5.h"
48 #include "rf_states.h"
49 #if RF_INCLUDE_RAID5_RS > 0
50 #include "rf_raid5_rotatedspare.h"
51 #endif /* RF_INCLUDE_RAID5_RS > 0 */
52 #if RF_INCLUDE_CHAINDECLUSTER > 0
53 #include "rf_chaindecluster.h"
54 #endif /* RF_INCLUDE_CHAINDECLUSTER > 0 */
55 #if RF_INCLUDE_INTERDECLUSTER > 0
56 #include "rf_interdecluster.h"
57 #endif /* RF_INCLUDE_INTERDECLUSTER > 0 */
58 #if RF_INCLUDE_PARITYLOGGING > 0
59 #include "rf_paritylogging.h"
60 #endif /* RF_INCLUDE_PARITYLOGGING > 0 */
61 #if RF_INCLUDE_EVENODD > 0
62 #include "rf_evenodd.h"
63 #endif /* RF_INCLUDE_EVENODD > 0 */
64 #include "rf_general.h"
65 #include "rf_driver.h"
66 #include "rf_parityscan.h"
67 #include "rf_reconbuffer.h"
68 #include "rf_reconutil.h"
69
70 /*****************************************************************************
71 *
72 * The layout switch defines all the layouts that are supported.
73 * Fields are: layout ID, init routine, shutdown routine, map sector,
74 * map parity, identify stripe, dag selection, map stripeid
75 * to parity stripe id (optional), num faults tolerated,
76 * special flags.
77 *
78 *****************************************************************************/
79
80 static RF_AccessState_t DefaultStates[] = {
81 rf_QuiesceState, rf_IncrAccessesCountState, rf_MapState,
82 rf_LockState, rf_CreateDAGState, rf_ExecuteDAGState,
83 rf_ProcessDAGState, rf_DecrAccessesCountState,
84 rf_CleanupState, rf_LastState
85 };
86
87 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && !defined(_KERNEL)
88 /*
89 * XXX Gross hack to shutup gcc -- It complains that DefaultStates is not
90 * used when compiling this in userland... I hate to burst it's bubble, but
91 * DefaultStates is used all over the place here in the initialization of
92 * lots of data structures. GO
93 */
94 RF_AccessState_t *NothingAtAll = DefaultStates;
95 #endif
96
97 #if (defined(__NetBSD__) || defined(__OpenBSD__)) && defined(_KERNEL)
98 /* XXX Remove static so GCC doesn't complain about these being unused ! */
99 int distSpareYes = 1;
100 int distSpareNo = 0;
101 #else
102 static int distSpareYes = 1;
103 static int distSpareNo = 0;
104 #endif
105
106 #ifdef _KERNEL
107 #define RF_NK2(a,b)
108 #else /* _KERNEL */
109 #define RF_NK2(a,b) a,b,
110 #endif /* !_KERNEL */
111
112 #if RF_UTILITY > 0
113 #define RF_NU(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p)
114 #else /* RF_UTILITY > 0 */
115 #define RF_NU(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p
116 #endif /* RF_UTILITY > 0 */
117
118 static RF_LayoutSW_t mapsw[] = {
119 /* Parity declustering. */
120 {'T', "Parity declustering",
121 RF_NK2(rf_MakeLayoutSpecificDeclustered, &distSpareNo)
122 RF_NU(
123 rf_ConfigureDeclustered,
124 rf_MapSectorDeclustered, rf_MapParityDeclustered, NULL,
125 rf_IdentifyStripeDeclustered,
126 rf_RaidFiveDagSelect,
127 rf_MapSIDToPSIDDeclustered,
128 rf_GetDefaultHeadSepLimitDeclustered,
129 rf_GetDefaultNumFloatingReconBuffersDeclustered,
130 NULL, NULL,
131 rf_SubmitReconBufferBasic,
132 rf_VerifyParityBasic,
133 1,
134 DefaultStates,
135 0)
136 },
137
138 /* Parity declustering with distributed sparing. */
139 {'D', "Distributed sparing parity declustering",
140 RF_NK2(rf_MakeLayoutSpecificDeclustered, &distSpareYes)
141 RF_NU(
142 rf_ConfigureDeclusteredDS,
143 rf_MapSectorDeclustered, rf_MapParityDeclustered, NULL,
144 rf_IdentifyStripeDeclustered,
145 rf_RaidFiveDagSelect,
146 rf_MapSIDToPSIDDeclustered,
147 rf_GetDefaultHeadSepLimitDeclustered,
148 rf_GetDefaultNumFloatingReconBuffersDeclustered,
149 rf_GetNumSpareRUsDeclustered, rf_InstallSpareTable,
150 rf_SubmitReconBufferBasic,
151 rf_VerifyParityBasic,
152 1,
153 DefaultStates,
154 RF_DISTRIBUTE_SPARE | RF_BD_DECLUSTERED)
155 },
156
157 #if RF_INCLUDE_DECL_PQ > 0
158 /* Declustered P+Q. */
159 {'Q', "Declustered P+Q",
160 RF_NK2(rf_MakeLayoutSpecificDeclustered, &distSpareNo)
161 RF_NU(
162 rf_ConfigureDeclusteredPQ,
163 rf_MapSectorDeclusteredPQ, rf_MapParityDeclusteredPQ,
164 rf_MapQDeclusteredPQ,
165 rf_IdentifyStripeDeclusteredPQ,
166 rf_PQDagSelect,
167 rf_MapSIDToPSIDDeclustered,
168 rf_GetDefaultHeadSepLimitDeclustered,
169 rf_GetDefaultNumFloatingReconBuffersPQ,
170 NULL, NULL,
171 NULL,
172 rf_VerifyParityBasic,
173 2,
174 DefaultStates,
175 0)
176 },
177 #endif /* RF_INCLUDE_DECL_PQ > 0 */
178
179 #if RF_INCLUDE_RAID5_RS > 0
180 /* RAID 5 with rotated sparing. */
181 {'R', "RAID Level 5 rotated sparing",
182 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
183 RF_NU(
184 rf_ConfigureRAID5_RS,
185 rf_MapSectorRAID5_RS, rf_MapParityRAID5_RS, NULL,
186 rf_IdentifyStripeRAID5_RS,
187 rf_RaidFiveDagSelect,
188 rf_MapSIDToPSIDRAID5_RS,
189 rf_GetDefaultHeadSepLimitRAID5,
190 rf_GetDefaultNumFloatingReconBuffersRAID5,
191 rf_GetNumSpareRUsRAID5_RS, NULL,
192 rf_SubmitReconBufferBasic,
193 rf_VerifyParityBasic,
194 1,
195 DefaultStates,
196 RF_DISTRIBUTE_SPARE)
197 },
198 #endif /* RF_INCLUDE_RAID5_RS > 0 */
199
200 #if RF_INCLUDE_CHAINDECLUSTER > 0
201 /* Chained Declustering. */
202 {'C', "Chained Declustering",
203 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
204 RF_NU(
205 rf_ConfigureChainDecluster,
206 rf_MapSectorChainDecluster, rf_MapParityChainDecluster,
207 NULL,
208 rf_IdentifyStripeChainDecluster,
209 rf_RAIDCDagSelect,
210 rf_MapSIDToPSIDChainDecluster,
211 NULL,
212 NULL,
213 rf_GetNumSpareRUsChainDecluster, NULL,
214 rf_SubmitReconBufferBasic,
215 rf_VerifyParityBasic,
216 1,
217 DefaultStates,
218 0)
219 },
220 #endif /* RF_INCLUDE_CHAINDECLUSTER > 0 */
221
222 #if RF_INCLUDE_INTERDECLUSTER > 0
223 /* Interleaved Declustering. */
224 {'I', "Interleaved Declustering",
225 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
226 RF_NU(
227 rf_ConfigureInterDecluster,
228 rf_MapSectorInterDecluster, rf_MapParityInterDecluster,
229 NULL,
230 rf_IdentifyStripeInterDecluster,
231 rf_RAIDIDagSelect,
232 rf_MapSIDToPSIDInterDecluster,
233 rf_GetDefaultHeadSepLimitInterDecluster,
234 rf_GetDefaultNumFloatingReconBuffersInterDecluster,
235 rf_GetNumSpareRUsInterDecluster, NULL,
236 rf_SubmitReconBufferBasic,
237 rf_VerifyParityBasic,
238 1,
239 DefaultStates,
240 RF_DISTRIBUTE_SPARE)
241 },
242 #endif /* RF_INCLUDE_INTERDECLUSTER > 0 */
243
244 #if RF_INCLUDE_RAID0 > 0
245 /* RAID level 0. */
246 {'0', "RAID Level 0",
247 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
248 RF_NU(
249 rf_ConfigureRAID0,
250 rf_MapSectorRAID0, rf_MapParityRAID0, NULL,
251 rf_IdentifyStripeRAID0,
252 rf_RAID0DagSelect,
253 rf_MapSIDToPSIDRAID0,
254 NULL,
255 NULL,
256 NULL, NULL,
257 NULL,
258 rf_VerifyParityRAID0,
259 0,
260 DefaultStates,
261 0)
262 },
263 #endif /* RF_INCLUDE_RAID0 > 0 */
264
265 #if RF_INCLUDE_RAID1 > 0
266 /* RAID level 1. */
267 {'1', "RAID Level 1",
268 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
269 RF_NU(
270 rf_ConfigureRAID1,
271 rf_MapSectorRAID1, rf_MapParityRAID1, NULL,
272 rf_IdentifyStripeRAID1,
273 rf_RAID1DagSelect,
274 rf_MapSIDToPSIDRAID1,
275 NULL,
276 NULL,
277 NULL, NULL,
278 rf_SubmitReconBufferRAID1,
279 rf_VerifyParityRAID1,
280 1,
281 DefaultStates,
282 0)
283 },
284 #endif /* RF_INCLUDE_RAID1 > 0 */
285
286 #if RF_INCLUDE_RAID4 > 0
287 /* RAID level 4. */
288 {'4', "RAID Level 4",
289 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
290 RF_NU(
291 rf_ConfigureRAID4,
292 rf_MapSectorRAID4, rf_MapParityRAID4, NULL,
293 rf_IdentifyStripeRAID4,
294 rf_RaidFiveDagSelect,
295 rf_MapSIDToPSIDRAID4,
296 rf_GetDefaultHeadSepLimitRAID4,
297 rf_GetDefaultNumFloatingReconBuffersRAID4,
298 NULL, NULL,
299 rf_SubmitReconBufferBasic,
300 rf_VerifyParityBasic,
301 1,
302 DefaultStates,
303 0)
304 },
305 #endif /* RF_INCLUDE_RAID4 > 0 */
306
307 #if RF_INCLUDE_RAID5 > 0
308 /* RAID level 5. */
309 {'5', "RAID Level 5",
310 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
311 RF_NU(
312 rf_ConfigureRAID5,
313 rf_MapSectorRAID5, rf_MapParityRAID5, NULL,
314 rf_IdentifyStripeRAID5,
315 rf_RaidFiveDagSelect,
316 rf_MapSIDToPSIDRAID5,
317 rf_GetDefaultHeadSepLimitRAID5,
318 rf_GetDefaultNumFloatingReconBuffersRAID5,
319 NULL, NULL,
320 rf_SubmitReconBufferBasic,
321 rf_VerifyParityBasic,
322 1,
323 DefaultStates,
324 0)
325 },
326 #endif /* RF_INCLUDE_RAID5 > 0 */
327
328 #if RF_INCLUDE_EVENODD > 0
329 /* Evenodd. */
330 {'E', "EvenOdd",
331 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
332 RF_NU(
333 rf_ConfigureEvenOdd,
334 rf_MapSectorRAID5, rf_MapParityEvenOdd, rf_MapEEvenOdd,
335 rf_IdentifyStripeEvenOdd,
336 rf_EODagSelect,
337 rf_MapSIDToPSIDRAID5,
338 NULL,
339 NULL,
340 NULL, NULL,
341 NULL, /* No reconstruction, yet. */
342 rf_VerifyParityEvenOdd,
343 2,
344 DefaultStates,
345 0)
346 },
347 #endif /* RF_INCLUDE_EVENODD > 0 */
348
349 #if RF_INCLUDE_EVENODD > 0
350 /* Declustered Evenodd. */
351 {'e', "Declustered EvenOdd",
352 RF_NK2(rf_MakeLayoutSpecificDeclustered, &distSpareNo)
353 RF_NU(
354 rf_ConfigureDeclusteredPQ,
355 rf_MapSectorDeclusteredPQ, rf_MapParityDeclusteredPQ,
356 rf_MapQDeclusteredPQ,
357 rf_IdentifyStripeDeclusteredPQ,
358 rf_EODagSelect,
359 rf_MapSIDToPSIDRAID5,
360 rf_GetDefaultHeadSepLimitDeclustered,
361 rf_GetDefaultNumFloatingReconBuffersPQ,
362 NULL, NULL,
363 NULL, /* No reconstruction, yet. */
364 rf_VerifyParityEvenOdd,
365 2,
366 DefaultStates,
367 0)
368 },
369 #endif /* RF_INCLUDE_EVENODD > 0 */
370
371 #if RF_INCLUDE_PARITYLOGGING > 0
372 /* Parity logging. */
373 {'L', "Parity logging",
374 RF_NK2(rf_MakeLayoutSpecificNULL, NULL)
375 RF_NU(
376 rf_ConfigureParityLogging,
377 rf_MapSectorParityLogging, rf_MapParityParityLogging, NULL,
378 rf_IdentifyStripeParityLogging,
379 rf_ParityLoggingDagSelect,
380 rf_MapSIDToPSIDParityLogging,
381 rf_GetDefaultHeadSepLimitParityLogging,
382 rf_GetDefaultNumFloatingReconBuffersParityLogging,
383 NULL, NULL,
384 rf_SubmitReconBufferBasic,
385 NULL,
386 1,
387 DefaultStates,
388 0)
389 },
390 #endif /* RF_INCLUDE_PARITYLOGGING > 0 */
391
392 /* End-of-list marker. */
393 {'\0', NULL,
394 RF_NK2(NULL, NULL)
395 RF_NU(
396 NULL,
397 NULL, NULL, NULL,
398 NULL,
399 NULL,
400 NULL,
401 NULL,
402 NULL,
403 NULL, NULL,
404 NULL,
405 NULL,
406 0,
407 NULL,
408 0)
409 }
410 };
411
412 RF_LayoutSW_t *
rf_GetLayout(RF_ParityConfig_t parityConfig)413 rf_GetLayout(RF_ParityConfig_t parityConfig)
414 {
415 RF_LayoutSW_t *p;
416
417 /* Look up the specific layout. */
418 for (p = &mapsw[0]; p->parityConfig; p++)
419 if (p->parityConfig == parityConfig)
420 break;
421 if (!p->parityConfig)
422 return (NULL);
423 RF_ASSERT(p->parityConfig == parityConfig);
424 return (p);
425 }
426
427 #if RF_UTILITY == 0
428 /*****************************************************************************
429 *
430 * ConfigureLayout
431 *
432 * Read the configuration file and set up the RAID layout parameters.
433 * After reading common params, invokes the layout-specific configuration
434 * routine to finish the configuration.
435 *
436 *****************************************************************************/
437 int
rf_ConfigureLayout(RF_ShutdownList_t ** listp,RF_Raid_t * raidPtr,RF_Config_t * cfgPtr)438 rf_ConfigureLayout(RF_ShutdownList_t **listp, RF_Raid_t *raidPtr,
439 RF_Config_t *cfgPtr)
440 {
441 RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
442 RF_ParityConfig_t parityConfig;
443 RF_LayoutSW_t *p;
444 int retval;
445
446 layoutPtr->sectorsPerStripeUnit = cfgPtr->sectPerSU;
447 layoutPtr->SUsPerPU = cfgPtr->SUsPerPU;
448 layoutPtr->SUsPerRU = cfgPtr->SUsPerRU;
449 parityConfig = cfgPtr->parityConfig;
450
451 if (layoutPtr->sectorsPerStripeUnit <= 0) {
452 RF_ERRORMSG2("raid%d: Invalid sectorsPerStripeUnit: %d.\n",
453 raidPtr->raidid, (int)layoutPtr->sectorsPerStripeUnit);
454 return (EINVAL);
455 }
456
457 layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk /
458 layoutPtr->sectorsPerStripeUnit;
459
460 p = rf_GetLayout(parityConfig);
461 if (p == NULL) {
462 RF_ERRORMSG1("Unknown parity configuration '%c'", parityConfig);
463 return (EINVAL);
464 }
465 RF_ASSERT(p->parityConfig == parityConfig);
466 layoutPtr->map = p;
467
468 /* Initialize the specific layout. */
469
470 retval = (p->Configure) (listp, raidPtr, cfgPtr);
471
472 if (retval)
473 return (retval);
474
475 layoutPtr->dataBytesPerStripe = layoutPtr->dataSectorsPerStripe <<
476 raidPtr->logBytesPerSector;
477 raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk *
478 layoutPtr->sectorsPerStripeUnit;
479
480 if (rf_forceNumFloatingReconBufs >= 0) {
481 raidPtr->numFloatingReconBufs = rf_forceNumFloatingReconBufs;
482 } else {
483 raidPtr->numFloatingReconBufs =
484 rf_GetDefaultNumFloatingReconBuffers(raidPtr);
485 }
486
487 if (rf_forceHeadSepLimit >= 0) {
488 raidPtr->headSepLimit = rf_forceHeadSepLimit;
489 } else {
490 raidPtr->headSepLimit = rf_GetDefaultHeadSepLimit(raidPtr);
491 }
492
493 #ifdef RAIDDEBUG
494 if (raidPtr->headSepLimit >= 0) {
495 printf("RAIDFRAME(%s): Using %ld floating recon bufs"
496 " with head sep limit %ld.\n", layoutPtr->map->configName,
497 (long) raidPtr->numFloatingReconBufs,
498 (long) raidPtr->headSepLimit);
499 } else {
500 printf("RAIDFRAME(%s): Using %ld floating recon bufs"
501 " with no head sep limit.\n", layoutPtr->map->configName,
502 (long) raidPtr->numFloatingReconBufs);
503 }
504 #endif /* RAIDDEBUG */
505
506 return (0);
507 }
508
509 /*
510 * Typically there is a 1-1 mapping between stripes and parity stripes.
511 * However, the declustering code supports packing multiple stripes into
512 * a single parity stripe, so as to increase the size of the reconstruction
513 * unit without affecting the size of the stripe unit. This routine finds
514 * the parity stripe identifier associated with a stripe ID. There is also
515 * a RaidAddressToParityStripeID macro in layout.h
516 */
517 RF_StripeNum_t
rf_MapStripeIDToParityStripeID(RF_RaidLayout_t * layoutPtr,RF_StripeNum_t stripeID,RF_ReconUnitNum_t * which_ru)518 rf_MapStripeIDToParityStripeID(RF_RaidLayout_t *layoutPtr,
519 RF_StripeNum_t stripeID, RF_ReconUnitNum_t *which_ru)
520 {
521 RF_StripeNum_t parityStripeID;
522
523 /* Quick exit in the common case of SUsPerPU == 1. */
524 if ((layoutPtr->SUsPerPU == 1) || !layoutPtr->map->MapSIDToPSID) {
525 *which_ru = 0;
526 return (stripeID);
527 } else {
528 (layoutPtr->map->MapSIDToPSID) (layoutPtr, stripeID,
529 &parityStripeID, which_ru);
530 }
531 return (parityStripeID);
532 }
533 #endif /* RF_UTILITY == 0 */
534