1 /* $NetBSD: rf_interdecluster.c,v 1.13 2006/10/12 01:31:51 christos Exp $ */
3 * Copyright (c) 1995 Carnegie-Mellon University.
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.
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.
18 * Carnegie Mellon requests users of this software to return to
20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
21 * School of Computer Science
22 * Carnegie Mellon University
23 * Pittsburgh PA 15213-3890
25 * any improvements or extensions that they make and grant Carnegie the
26 * rights to redistribute these changes.
29 /************************************************************
31 * rf_interdecluster.c -- implements interleaved declustering
33 ************************************************************/
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: rf_interdecluster.c,v 1.13 2006/10/12 01:31:51 christos Exp $");
40 #if RF_INCLUDE_INTERDECLUSTER > 0
42 #include <dev/raidframe/raidframevar.h>
45 #include "rf_interdecluster.h"
47 #include "rf_dagutils.h"
48 #include "rf_dagfuncs.h"
49 #include "rf_general.h"
51 #include "rf_dagffrd.h"
52 #include "rf_dagdegrd.h"
53 #include "rf_dagffwr.h"
54 #include "rf_dagdegwr.h"
56 typedef struct RF_InterdeclusterConfigInfo_s
{
57 RF_RowCol_t
**stripeIdentifier
; /* filled in at config time and used
58 * by IdentifyStripe */
59 RF_StripeCount_t numSparingRegions
;
60 RF_StripeCount_t stripeUnitsPerSparingRegion
;
61 RF_SectorNum_t mirrorStripeOffset
;
62 } RF_InterdeclusterConfigInfo_t
;
65 rf_ConfigureInterDecluster(
66 RF_ShutdownList_t
** listp
,
70 RF_RaidLayout_t
*layoutPtr
= &raidPtr
->Layout
;
71 RF_StripeCount_t num_used_stripeUnitsPerDisk
;
72 RF_InterdeclusterConfigInfo_t
*info
;
73 RF_RowCol_t i
, tmp
, SUs_per_region
;
75 /* create an Interleaved Declustering configuration structure */
76 RF_MallocAndAdd(info
, sizeof(RF_InterdeclusterConfigInfo_t
), (RF_InterdeclusterConfigInfo_t
*),
77 raidPtr
->cleanupList
);
80 layoutPtr
->layoutSpecificInfo
= (void *) info
;
82 /* fill in the config structure. */
83 SUs_per_region
= raidPtr
->numCol
* (raidPtr
->numCol
- 1);
84 info
->stripeIdentifier
= rf_make_2d_array(SUs_per_region
, 2, raidPtr
->cleanupList
);
85 if (info
->stripeIdentifier
== NULL
)
87 for (i
= 0; i
< SUs_per_region
; i
++) {
88 info
->stripeIdentifier
[i
][0] = i
/ (raidPtr
->numCol
- 1);
89 tmp
= i
/ raidPtr
->numCol
;
90 info
->stripeIdentifier
[i
][1] = (i
+ 1 + tmp
) % raidPtr
->numCol
;
93 /* fill in the remaining layout parameters */
95 /* total number of stripes should a multiple of 2*numCol: Each sparing
96 * region consists of 2*numCol stripes: n-1 primary copy, n-1
97 * secondary copy and 2 for spare .. */
98 num_used_stripeUnitsPerDisk
= layoutPtr
->stripeUnitsPerDisk
- (layoutPtr
->stripeUnitsPerDisk
%
99 (2 * raidPtr
->numCol
));
100 info
->numSparingRegions
= num_used_stripeUnitsPerDisk
/ (2 * raidPtr
->numCol
);
101 /* this is in fact the number of stripe units (that are primary data
102 * copies) in the sparing region */
103 info
->stripeUnitsPerSparingRegion
= raidPtr
->numCol
* (raidPtr
->numCol
- 1);
104 info
->mirrorStripeOffset
= info
->numSparingRegions
* (raidPtr
->numCol
+ 1);
105 layoutPtr
->numStripe
= info
->numSparingRegions
* info
->stripeUnitsPerSparingRegion
;
106 layoutPtr
->numDataCol
= 1;
107 layoutPtr
->dataSectorsPerStripe
= layoutPtr
->numDataCol
* layoutPtr
->sectorsPerStripeUnit
;
108 layoutPtr
->numParityCol
= 1;
110 layoutPtr
->dataStripeUnitsPerDisk
= num_used_stripeUnitsPerDisk
;
112 raidPtr
->sectorsPerDisk
=
113 num_used_stripeUnitsPerDisk
* layoutPtr
->sectorsPerStripeUnit
;
115 raidPtr
->totalSectors
=
116 (layoutPtr
->numStripe
) * layoutPtr
->sectorsPerStripeUnit
;
118 layoutPtr
->stripeUnitsPerDisk
= raidPtr
->sectorsPerDisk
/ layoutPtr
->sectorsPerStripeUnit
;
124 rf_GetDefaultNumFloatingReconBuffersInterDecluster(RF_Raid_t
* raidPtr
)
130 rf_GetDefaultHeadSepLimitInterDecluster(RF_Raid_t
* raidPtr
)
132 return (raidPtr
->sectorsPerDisk
);
136 rf_GetNumSpareRUsInterDecluster(
139 RF_InterdeclusterConfigInfo_t
*info
= (RF_InterdeclusterConfigInfo_t
*) raidPtr
->Layout
.layoutSpecificInfo
;
141 return (2 * ((RF_ReconUnitCount_t
) info
->numSparingRegions
));
142 /* the layout uses two stripe units per disk as spare within each
145 /* Maps to the primary copy of the data, i.e. the first mirror pair */
147 rf_MapSectorInterDecluster(
149 RF_RaidAddr_t raidSector
,
151 RF_SectorNum_t
* diskSector
,
154 RF_InterdeclusterConfigInfo_t
*info
= (RF_InterdeclusterConfigInfo_t
*) raidPtr
->Layout
.layoutSpecificInfo
;
155 RF_StripeNum_t SUID
= raidSector
/ raidPtr
->Layout
.sectorsPerStripeUnit
;
156 RF_StripeNum_t su_offset_into_disk
, mirror_su_offset_into_disk
;
157 RF_StripeNum_t sparing_region_id
, index_within_region
;
158 int col_before_remap
;
160 sparing_region_id
= SUID
/ info
->stripeUnitsPerSparingRegion
;
161 index_within_region
= SUID
% info
->stripeUnitsPerSparingRegion
;
162 su_offset_into_disk
= index_within_region
% (raidPtr
->numCol
- 1);
163 mirror_su_offset_into_disk
= index_within_region
/ raidPtr
->numCol
;
164 col_before_remap
= index_within_region
/ (raidPtr
->numCol
- 1);
167 *col
= col_before_remap
;
168 *diskSector
= (su_offset_into_disk
+ ((raidPtr
->numCol
- 1) * sparing_region_id
)) *
169 raidPtr
->Layout
.sectorsPerStripeUnit
;
170 *diskSector
+= (raidSector
% raidPtr
->Layout
.sectorsPerStripeUnit
);
172 /* remap sector to spare space... */
173 *diskSector
= sparing_region_id
* (raidPtr
->numCol
+ 1) * raidPtr
->Layout
.sectorsPerStripeUnit
;
174 *diskSector
+= (raidPtr
->numCol
- 1) * raidPtr
->Layout
.sectorsPerStripeUnit
;
175 *diskSector
+= (raidSector
% raidPtr
->Layout
.sectorsPerStripeUnit
);
176 *col
= (index_within_region
+ 1 + mirror_su_offset_into_disk
) % raidPtr
->numCol
;
177 *col
= (*col
+ 1) % raidPtr
->numCol
;
178 if (*col
== col_before_remap
)
179 *col
= (*col
+ 1) % raidPtr
->numCol
;
182 /* Maps to the second copy of the mirror pair. */
184 rf_MapParityInterDecluster(
186 RF_RaidAddr_t raidSector
,
188 RF_SectorNum_t
* diskSector
,
191 RF_InterdeclusterConfigInfo_t
*info
= (RF_InterdeclusterConfigInfo_t
*) raidPtr
->Layout
.layoutSpecificInfo
;
192 RF_StripeNum_t sparing_region_id
, index_within_region
, mirror_su_offset_into_disk
;
193 RF_StripeNum_t SUID
= raidSector
/ raidPtr
->Layout
.sectorsPerStripeUnit
;
194 int col_before_remap
;
196 sparing_region_id
= SUID
/ info
->stripeUnitsPerSparingRegion
;
197 index_within_region
= SUID
% info
->stripeUnitsPerSparingRegion
;
198 mirror_su_offset_into_disk
= index_within_region
/ raidPtr
->numCol
;
199 col_before_remap
= (index_within_region
+ 1 + mirror_su_offset_into_disk
) % raidPtr
->numCol
;
202 *col
= col_before_remap
;
203 *diskSector
= info
->mirrorStripeOffset
* raidPtr
->Layout
.sectorsPerStripeUnit
;
204 *diskSector
+= sparing_region_id
* (raidPtr
->numCol
- 1) * raidPtr
->Layout
.sectorsPerStripeUnit
;
205 *diskSector
+= mirror_su_offset_into_disk
* raidPtr
->Layout
.sectorsPerStripeUnit
;
206 *diskSector
+= (raidSector
% raidPtr
->Layout
.sectorsPerStripeUnit
);
208 /* remap parity to spare space ... */
209 *diskSector
= sparing_region_id
* (raidPtr
->numCol
+ 1) * raidPtr
->Layout
.sectorsPerStripeUnit
;
210 *diskSector
+= (raidPtr
->numCol
) * raidPtr
->Layout
.sectorsPerStripeUnit
;
211 *diskSector
+= (raidSector
% raidPtr
->Layout
.sectorsPerStripeUnit
);
212 *col
= index_within_region
/ (raidPtr
->numCol
- 1);
213 *col
= (*col
+ 1) % raidPtr
->numCol
;
214 if (*col
== col_before_remap
)
215 *col
= (*col
+ 1) % raidPtr
->numCol
;
220 rf_IdentifyStripeInterDecluster(
223 RF_RowCol_t
** diskids
)
225 RF_InterdeclusterConfigInfo_t
*info
= (RF_InterdeclusterConfigInfo_t
*) raidPtr
->Layout
.layoutSpecificInfo
;
228 SUID
= addr
/ raidPtr
->Layout
.sectorsPerStripeUnit
;
229 SUID
= SUID
% info
->stripeUnitsPerSparingRegion
;
231 *diskids
= info
->stripeIdentifier
[SUID
];
235 rf_MapSIDToPSIDInterDecluster(
236 RF_RaidLayout_t
* layoutPtr
,
237 RF_StripeNum_t stripeID
,
238 RF_StripeNum_t
* psID
,
239 RF_ReconUnitNum_t
* which_ru
)
244 /******************************************************************************
245 * select a graph to perform a single-stripe access
247 * Parameters: raidPtr - description of the physical array
248 * type - type of operation (read or write) requested
249 * asmap - logical & physical addresses for this access
250 * createFunc - name of function to use to create the graph
251 *****************************************************************************/
257 RF_AccessStripeMap_t
* asmap
,
258 RF_VoidFuncPtr
* createFunc
)
260 RF_ASSERT(RF_IO_IS_R_OR_W(type
));
262 if (asmap
->numDataFailed
+ asmap
->numParityFailed
> 1) {
263 RF_ERRORMSG("Multiple disks failed in a single group! Aborting I/O operation.\n");
267 *createFunc
= (type
== RF_IO_TYPE_READ
) ? (RF_VoidFuncPtr
) rf_CreateFaultFreeReadDAG
: (RF_VoidFuncPtr
) rf_CreateRaidOneWriteDAG
;
268 if (type
== RF_IO_TYPE_READ
) {
269 if (asmap
->numDataFailed
== 0)
270 *createFunc
= (RF_VoidFuncPtr
) rf_CreateMirrorPartitionReadDAG
;
272 *createFunc
= (RF_VoidFuncPtr
) rf_CreateRaidOneDegradedReadDAG
;
274 *createFunc
= (RF_VoidFuncPtr
) rf_CreateRaidOneWriteDAG
;
276 #endif /* RF_INCLUDE_INTERDECLUSTER > 0 */