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