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