1 /*	$NetBSD: rf_layout.c,v 1.20 2008/05/04 20:57:23 oster Exp $	*/
2 /*
3  * Copyright (c) 1995 Carnegie-Mellon University.
4  * All rights reserved.
5  *
6  * Author: Mark Holland
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@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 /* rf_layout.c -- driver code dealing with layout and mapping issues
30  */
31 
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: rf_layout.c,v 1.20 2008/05/04 20:57:23 oster Exp $");
34 
35 #include <dev/raidframe/raidframevar.h>
36 
37 #include "rf_archs.h"
38 #include "rf_raid.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
74  *    sector, map parity, identify stripe, dag selection, map stripeid
75  *    to parity stripe id (optional), num faults tolerated, special
76  *    flags.
77  *
78  ***********************************************************************/
79 
80 static const RF_AccessState_t DefaultStates[] = {
81 					   rf_QuiesceState,
82 					   rf_IncrAccessesCountState,
83 					   rf_MapState,
84 					   rf_LockState,
85 					   rf_CreateDAGState,
86 					   rf_ExecuteDAGState,
87 					   rf_ProcessDAGState,
88 					   rf_CleanupState,
89 					   rf_DecrAccessesCountState,
90 					   rf_LastState};
91 
92 #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
93 
94 /* Note that if you add any new RAID types to this list, that you must
95    also update the mapsw[] table in the raidctl sources */
96 
97 static const RF_LayoutSW_t mapsw[] = {
98 #if RF_INCLUDE_PARITY_DECLUSTERING > 0
99 	/* parity declustering */
100 	{'T', "Parity declustering",
101 		RF_NU(
102 		    rf_ConfigureDeclustered,
103 		    rf_MapSectorDeclustered, rf_MapParityDeclustered, NULL,
104 		    rf_IdentifyStripeDeclustered,
105 		    rf_RaidFiveDagSelect,
106 		    rf_MapSIDToPSIDDeclustered,
107 		    rf_GetDefaultHeadSepLimitDeclustered,
108 		    rf_GetDefaultNumFloatingReconBuffersDeclustered,
109 		    NULL, NULL,
110 		    rf_SubmitReconBufferBasic,
111 		    rf_VerifyParityBasic,
112 		    1,
113 		    DefaultStates,
114 		    0)
115 	},
116 #endif
117 
118 #if RF_INCLUDE_PARITY_DECLUSTERING_DS > 0
119 	/* parity declustering with distributed sparing */
120 	{'D', "Distributed sparing parity declustering",
121 		RF_NU(
122 		    rf_ConfigureDeclusteredDS,
123 		    rf_MapSectorDeclustered, rf_MapParityDeclustered, NULL,
124 		    rf_IdentifyStripeDeclustered,
125 		    rf_RaidFiveDagSelect,
126 		    rf_MapSIDToPSIDDeclustered,
127 		    rf_GetDefaultHeadSepLimitDeclustered,
128 		    rf_GetDefaultNumFloatingReconBuffersDeclustered,
129 		    rf_GetNumSpareRUsDeclustered, rf_InstallSpareTable,
130 		    rf_SubmitReconBufferBasic,
131 		    rf_VerifyParityBasic,
132 		    1,
133 		    DefaultStates,
134 		    RF_DISTRIBUTE_SPARE | RF_BD_DECLUSTERED)
135 	},
136 #endif
137 
138 #if RF_INCLUDE_DECL_PQ > 0
139 	/* declustered P+Q */
140 	{'Q', "Declustered P+Q",
141 		RF_NU(
142 		    rf_ConfigureDeclusteredPQ,
143 		    rf_MapSectorDeclusteredPQ, rf_MapParityDeclusteredPQ, rf_MapQDeclusteredPQ,
144 		    rf_IdentifyStripeDeclusteredPQ,
145 		    rf_PQDagSelect,
146 		    rf_MapSIDToPSIDDeclustered,
147 		    rf_GetDefaultHeadSepLimitDeclustered,
148 		    rf_GetDefaultNumFloatingReconBuffersPQ,
149 		    NULL, NULL,
150 		    NULL,
151 		    rf_VerifyParityBasic,
152 		    2,
153 		    DefaultStates,
154 		    0)
155 	},
156 #endif				/* RF_INCLUDE_DECL_PQ > 0 */
157 
158 #if RF_INCLUDE_RAID5_RS > 0
159 	/* RAID 5 with rotated sparing */
160 	{'R', "RAID Level 5 rotated sparing",
161 		RF_NU(
162 		    rf_ConfigureRAID5_RS,
163 		    rf_MapSectorRAID5_RS, rf_MapParityRAID5_RS, NULL,
164 		    rf_IdentifyStripeRAID5_RS,
165 		    rf_RaidFiveDagSelect,
166 		    rf_MapSIDToPSIDRAID5_RS,
167 		    rf_GetDefaultHeadSepLimitRAID5,
168 		    rf_GetDefaultNumFloatingReconBuffersRAID5,
169 		    rf_GetNumSpareRUsRAID5_RS, NULL,
170 		    rf_SubmitReconBufferBasic,
171 		    rf_VerifyParityBasic,
172 		    1,
173 		    DefaultStates,
174 		    RF_DISTRIBUTE_SPARE)
175 	},
176 #endif				/* RF_INCLUDE_RAID5_RS > 0 */
177 
178 #if RF_INCLUDE_CHAINDECLUSTER > 0
179 	/* Chained Declustering */
180 	{'C', "Chained Declustering",
181 		RF_NU(
182 		    rf_ConfigureChainDecluster,
183 		    rf_MapSectorChainDecluster, rf_MapParityChainDecluster, NULL,
184 		    rf_IdentifyStripeChainDecluster,
185 		    rf_RAIDCDagSelect,
186 		    rf_MapSIDToPSIDChainDecluster,
187 		    NULL,
188 		    NULL,
189 		    rf_GetNumSpareRUsChainDecluster, NULL,
190 		    rf_SubmitReconBufferBasic,
191 		    rf_VerifyParityBasic,
192 		    1,
193 		    DefaultStates,
194 		    0)
195 	},
196 #endif				/* RF_INCLUDE_CHAINDECLUSTER > 0 */
197 
198 #if RF_INCLUDE_INTERDECLUSTER > 0
199 	/* Interleaved Declustering */
200 	{'I', "Interleaved Declustering",
201 		RF_NU(
202 		    rf_ConfigureInterDecluster,
203 		    rf_MapSectorInterDecluster, rf_MapParityInterDecluster, NULL,
204 		    rf_IdentifyStripeInterDecluster,
205 		    rf_RAIDIDagSelect,
206 		    rf_MapSIDToPSIDInterDecluster,
207 		    rf_GetDefaultHeadSepLimitInterDecluster,
208 		    rf_GetDefaultNumFloatingReconBuffersInterDecluster,
209 		    rf_GetNumSpareRUsInterDecluster, NULL,
210 		    rf_SubmitReconBufferBasic,
211 		    rf_VerifyParityBasic,
212 		    1,
213 		    DefaultStates,
214 		    RF_DISTRIBUTE_SPARE)
215 	},
216 #endif				/* RF_INCLUDE_INTERDECLUSTER > 0 */
217 
218 #if RF_INCLUDE_RAID0 > 0
219 	/* RAID level 0 */
220 	{'0', "RAID Level 0",
221 		RF_NU(
222 		    rf_ConfigureRAID0,
223 		    rf_MapSectorRAID0, rf_MapParityRAID0, NULL,
224 		    rf_IdentifyStripeRAID0,
225 		    rf_RAID0DagSelect,
226 		    rf_MapSIDToPSIDRAID0,
227 		    NULL,
228 		    NULL,
229 		    NULL, NULL,
230 		    NULL,
231 		    rf_VerifyParityRAID0,
232 		    0,
233 		    DefaultStates,
234 		    0)
235 	},
236 #endif				/* RF_INCLUDE_RAID0 > 0 */
237 
238 #if RF_INCLUDE_RAID1 > 0
239 	/* RAID level 1 */
240 	{'1', "RAID Level 1",
241 		RF_NU(
242 		    rf_ConfigureRAID1,
243 		    rf_MapSectorRAID1, rf_MapParityRAID1, NULL,
244 		    rf_IdentifyStripeRAID1,
245 		    rf_RAID1DagSelect,
246 		    rf_MapSIDToPSIDRAID1,
247 		    rf_GetDefaultHeadSepLimitRAID1,
248 		    NULL,
249 		    NULL, NULL,
250 		    rf_SubmitReconBufferRAID1,
251 		    rf_VerifyParityRAID1,
252 		    1,
253 		    DefaultStates,
254 		    0)
255 	},
256 #endif				/* RF_INCLUDE_RAID1 > 0 */
257 
258 #if RF_INCLUDE_RAID4 > 0
259 	/* RAID level 4 */
260 	{'4', "RAID Level 4",
261 		RF_NU(
262 		    rf_ConfigureRAID4,
263 		    rf_MapSectorRAID4, rf_MapParityRAID4, NULL,
264 		    rf_IdentifyStripeRAID4,
265 		    rf_RaidFiveDagSelect,
266 		    rf_MapSIDToPSIDRAID4,
267 		    rf_GetDefaultHeadSepLimitRAID4,
268 		    rf_GetDefaultNumFloatingReconBuffersRAID4,
269 		    NULL, NULL,
270 		    rf_SubmitReconBufferBasic,
271 		    rf_VerifyParityBasic,
272 		    1,
273 		    DefaultStates,
274 		    0)
275 	},
276 #endif				/* RF_INCLUDE_RAID4 > 0 */
277 
278 #if RF_INCLUDE_RAID5 > 0
279 	/* RAID level 5 */
280 	{'5', "RAID Level 5",
281 		RF_NU(
282 		    rf_ConfigureRAID5,
283 		    rf_MapSectorRAID5, rf_MapParityRAID5, NULL,
284 		    rf_IdentifyStripeRAID5,
285 		    rf_RaidFiveDagSelect,
286 		    rf_MapSIDToPSIDRAID5,
287 		    rf_GetDefaultHeadSepLimitRAID5,
288 		    rf_GetDefaultNumFloatingReconBuffersRAID5,
289 		    NULL, NULL,
290 		    rf_SubmitReconBufferBasic,
291 		    rf_VerifyParityBasic,
292 		    1,
293 		    DefaultStates,
294 		    0)
295 	},
296 #endif				/* RF_INCLUDE_RAID5 > 0 */
297 
298 #if RF_INCLUDE_EVENODD > 0
299 	/* Evenodd */
300 	{'E', "EvenOdd",
301 		RF_NU(
302 		    rf_ConfigureEvenOdd,
303 		    rf_MapSectorRAID5, rf_MapParityEvenOdd, rf_MapEEvenOdd,
304 		    rf_IdentifyStripeEvenOdd,
305 		    rf_EODagSelect,
306 		    rf_MapSIDToPSIDRAID5,
307 		    NULL,
308 		    NULL,
309 		    NULL, NULL,
310 		    NULL,	/* no reconstruction, yet */
311 		    rf_VerifyParityEvenOdd,
312 		    2,
313 		    DefaultStates,
314 		    0)
315 	},
316 #endif				/* RF_INCLUDE_EVENODD > 0 */
317 
318 #if RF_INCLUDE_EVENODD > 0
319 	/* Declustered Evenodd */
320 	{'e', "Declustered EvenOdd",
321 		RF_NU(
322 		    rf_ConfigureDeclusteredPQ,
323 		    rf_MapSectorDeclusteredPQ, rf_MapParityDeclusteredPQ, rf_MapQDeclusteredPQ,
324 		    rf_IdentifyStripeDeclusteredPQ,
325 		    rf_EODagSelect,
326 		    rf_MapSIDToPSIDRAID5,
327 		    rf_GetDefaultHeadSepLimitDeclustered,
328 		    rf_GetDefaultNumFloatingReconBuffersPQ,
329 		    NULL, NULL,
330 		    NULL,	/* no reconstruction, yet */
331 		    rf_VerifyParityEvenOdd,
332 		    2,
333 		    DefaultStates,
334 		    0)
335 	},
336 #endif				/* RF_INCLUDE_EVENODD > 0 */
337 
338 #if RF_INCLUDE_PARITYLOGGING > 0
339 	/* parity logging */
340 	{'L', "Parity logging",
341 		RF_NU(
342 		    rf_ConfigureParityLogging,
343 		    rf_MapSectorParityLogging, rf_MapParityParityLogging, NULL,
344 		    rf_IdentifyStripeParityLogging,
345 		    rf_ParityLoggingDagSelect,
346 		    rf_MapSIDToPSIDParityLogging,
347 		    rf_GetDefaultHeadSepLimitParityLogging,
348 		    rf_GetDefaultNumFloatingReconBuffersParityLogging,
349 		    NULL, NULL,
350 		    rf_SubmitReconBufferBasic,
351 		    NULL,
352 		    1,
353 		    DefaultStates,
354 		    0)
355 	},
356 #endif				/* RF_INCLUDE_PARITYLOGGING > 0 */
357 
358 	/* end-of-list marker */
359 	{'\0', NULL,
360 		RF_NU(
361 		    NULL,
362 		    NULL, NULL, NULL,
363 		    NULL,
364 		    NULL,
365 		    NULL,
366 		    NULL,
367 		    NULL,
368 		    NULL, NULL,
369 		    NULL,
370 		    NULL,
371 		    0,
372 		    NULL,
373 		    0)
374 	}
375 };
376 
377 const RF_LayoutSW_t *
rf_GetLayout(RF_ParityConfig_t parityConfig)378 rf_GetLayout(RF_ParityConfig_t parityConfig)
379 {
380 	const RF_LayoutSW_t *p;
381 
382 	/* look up the specific layout */
383 	for (p = &mapsw[0]; p->parityConfig; p++)
384 		if (p->parityConfig == parityConfig)
385 			break;
386 	if (!p->parityConfig)
387 		return (NULL);
388 	RF_ASSERT(p->parityConfig == parityConfig);
389 	return (p);
390 }
391 
392 /*****************************************************************************
393  *
394  * ConfigureLayout --
395  *
396  * read the configuration file and set up the RAID layout parameters.
397  * After reading common params, invokes the layout-specific
398  * configuration routine to finish the configuration.
399  *
400  ****************************************************************************/
401 int
rf_ConfigureLayout(RF_ShutdownList_t ** listp,RF_Raid_t * raidPtr,RF_Config_t * cfgPtr)402 rf_ConfigureLayout(RF_ShutdownList_t **listp, RF_Raid_t *raidPtr,
403 		   RF_Config_t *cfgPtr)
404 {
405 	RF_RaidLayout_t *layoutPtr = &(raidPtr->Layout);
406 	RF_ParityConfig_t parityConfig;
407 	const RF_LayoutSW_t *p;
408 	int     retval;
409 
410 	layoutPtr->sectorsPerStripeUnit = cfgPtr->sectPerSU;
411 	layoutPtr->SUsPerPU = cfgPtr->SUsPerPU;
412 	layoutPtr->SUsPerRU = cfgPtr->SUsPerRU;
413 	parityConfig = cfgPtr->parityConfig;
414 
415 	if (layoutPtr->sectorsPerStripeUnit <= 0) {
416 		RF_ERRORMSG2("raid%d: Invalid sectorsPerStripeUnit: %d\n",
417 			     raidPtr->raidid,
418 			     (int)layoutPtr->sectorsPerStripeUnit);
419 		return (EINVAL);
420 	}
421 
422 	if (layoutPtr->SUsPerPU <= 0) {
423 		RF_ERRORMSG2("raid%d: Invalid StripeUnitsPerParityUnit: %d\n",
424 			     raidPtr->raidid,
425 			     (int)layoutPtr->SUsPerPU);
426 		return (EINVAL);
427 	}
428 
429 	if (layoutPtr->SUsPerRU <= 0) {
430 		RF_ERRORMSG2("raid%d: Invalid StripeUnitsPerReconstructUnit: %d\n",
431 			     raidPtr->raidid,
432 			     (int)layoutPtr->SUsPerRU);
433 		return (EINVAL);
434 	}
435 
436 	layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk / layoutPtr->sectorsPerStripeUnit;
437 
438 	p = rf_GetLayout(parityConfig);
439 	if (p == NULL) {
440 		RF_ERRORMSG1("Unknown parity configuration '%c'", parityConfig);
441 		return (EINVAL);
442 	}
443 	RF_ASSERT(p->parityConfig == parityConfig);
444 	layoutPtr->map = p;
445 
446 	/* initialize the specific layout */
447 
448 	retval = (p->Configure) (listp, raidPtr, cfgPtr);
449 
450 	if (retval)
451 		return (retval);
452 
453 	raidPtr->sectorsPerDisk = layoutPtr->stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
454 
455 	if (rf_forceNumFloatingReconBufs >= 0) {
456 		raidPtr->numFloatingReconBufs = rf_forceNumFloatingReconBufs;
457 	} else {
458 		raidPtr->numFloatingReconBufs = rf_GetDefaultNumFloatingReconBuffers(raidPtr);
459 	}
460 
461 	if (rf_forceHeadSepLimit >= 0) {
462 		raidPtr->headSepLimit = rf_forceHeadSepLimit;
463 	} else {
464 		raidPtr->headSepLimit = rf_GetDefaultHeadSepLimit(raidPtr);
465 	}
466 	return (0);
467 }
468 /* typically there is a 1-1 mapping between stripes and parity stripes.
469  * however, the declustering code supports packing multiple stripes into
470  * a single parity stripe, so as to increase the size of the reconstruction
471  * unit without affecting the size of the stripe unit.  This routine finds
472  * the parity stripe identifier associated with a stripe ID.  There is also
473  * a RaidAddressToParityStripeID macro in layout.h
474  */
475 RF_StripeNum_t
rf_MapStripeIDToParityStripeID(RF_RaidLayout_t * layoutPtr,RF_StripeNum_t stripeID,RF_ReconUnitNum_t * which_ru)476 rf_MapStripeIDToParityStripeID(RF_RaidLayout_t *layoutPtr,
477 			       RF_StripeNum_t stripeID,
478 			       RF_ReconUnitNum_t *which_ru)
479 {
480 	RF_StripeNum_t parityStripeID;
481 
482 	/* quick exit in the common case of SUsPerPU==1 */
483 	if ((layoutPtr->SUsPerPU == 1) || !layoutPtr->map->MapSIDToPSID) {
484 		*which_ru = 0;
485 		return (stripeID);
486 	} else {
487 		(layoutPtr->map->MapSIDToPSID) (layoutPtr, stripeID, &parityStripeID, which_ru);
488 	}
489 	return (parityStripeID);
490 }
491