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 * |
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 |
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 |
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 | |