xref: /netbsd-src/sys/dev/raidframe/rf_chaindecluster.c (revision 001c68bd94f75ce9270b69227c4199fbf34ee396)
1 /*	$NetBSD: rf_chaindecluster.c,v 1.9 2002/09/23 02:40:08 oster Exp $	*/
2 /*
3  * Copyright (c) 1995 Carnegie-Mellon University.
4  * All rights reserved.
5  *
6  * Author: Khalil Amiri
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 /******************************************************************************
30  *
31  * rf_chaindecluster.c -- implements chained declustering
32  *
33  *****************************************************************************/
34 
35 #include <sys/cdefs.h>
36 __KERNEL_RCSID(0, "$NetBSD: rf_chaindecluster.c,v 1.9 2002/09/23 02:40:08 oster Exp $");
37 
38 #include "rf_archs.h"
39 
40 #if (RF_INCLUDE_CHAINDECLUSTER > 0)
41 
42 #include <dev/raidframe/raidframevar.h>
43 
44 #include "rf_raid.h"
45 #include "rf_chaindecluster.h"
46 #include "rf_dag.h"
47 #include "rf_dagutils.h"
48 #include "rf_dagffrd.h"
49 #include "rf_dagffwr.h"
50 #include "rf_dagdegrd.h"
51 #include "rf_dagfuncs.h"
52 #include "rf_general.h"
53 #include "rf_utils.h"
54 
55 typedef struct RF_ChaindeclusterConfigInfo_s {
56 	RF_RowCol_t **stripeIdentifier;	/* filled in at config time and used
57 					 * by IdentifyStripe */
58 	RF_StripeCount_t numSparingRegions;
59 	RF_StripeCount_t stripeUnitsPerSparingRegion;
60 	RF_SectorNum_t mirrorStripeOffset;
61 }       RF_ChaindeclusterConfigInfo_t;
62 
63 int
64 rf_ConfigureChainDecluster(
65     RF_ShutdownList_t ** listp,
66     RF_Raid_t * raidPtr,
67     RF_Config_t * cfgPtr)
68 {
69 	RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
70 	RF_StripeCount_t num_used_stripeUnitsPerDisk;
71 	RF_ChaindeclusterConfigInfo_t *info;
72 	RF_RowCol_t i;
73 
74 	/* create a Chained Declustering configuration structure */
75 	RF_MallocAndAdd(info, sizeof(RF_ChaindeclusterConfigInfo_t), (RF_ChaindeclusterConfigInfo_t *), raidPtr->cleanupList);
76 	if (info == NULL)
77 		return (ENOMEM);
78 	layoutPtr->layoutSpecificInfo = (void *) info;
79 
80 	/* fill in the config structure.  */
81 	info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, 2, raidPtr->cleanupList);
82 	if (info->stripeIdentifier == NULL)
83 		return (ENOMEM);
84 	for (i = 0; i < raidPtr->numCol; i++) {
85 		info->stripeIdentifier[i][0] = i % raidPtr->numCol;
86 		info->stripeIdentifier[i][1] = (i + 1) % raidPtr->numCol;
87 	}
88 
89 	RF_ASSERT(raidPtr->numRow == 1);
90 
91 	/* fill in the remaining layout parameters */
92 	num_used_stripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk - (layoutPtr->stripeUnitsPerDisk %
93 	    (2 * raidPtr->numCol - 2));
94 	info->numSparingRegions = num_used_stripeUnitsPerDisk / (2 * raidPtr->numCol - 2);
95 	info->stripeUnitsPerSparingRegion = raidPtr->numCol * (raidPtr->numCol - 1);
96 	info->mirrorStripeOffset = info->numSparingRegions * (raidPtr->numCol - 1);
97 	layoutPtr->numStripe = info->numSparingRegions * info->stripeUnitsPerSparingRegion;
98 	layoutPtr->numDataCol = 1;
99 	layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
100 	layoutPtr->numParityCol = 1;
101 
102 	layoutPtr->dataStripeUnitsPerDisk = num_used_stripeUnitsPerDisk;
103 
104 	raidPtr->sectorsPerDisk =
105 	    num_used_stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
106 
107 	raidPtr->totalSectors =
108 	    (layoutPtr->numStripe) * layoutPtr->sectorsPerStripeUnit;
109 
110 	layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk / layoutPtr->sectorsPerStripeUnit;
111 
112 	return (0);
113 }
114 
115 RF_ReconUnitCount_t
116 rf_GetNumSpareRUsChainDecluster(raidPtr)
117 	RF_Raid_t *raidPtr;
118 {
119 	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
120 
121 	/*
122          * The layout uses two stripe units per disk as spare within each
123          * sparing region.
124          */
125 	return (2 * info->numSparingRegions);
126 }
127 
128 
129 /* Maps to the primary copy of the data, i.e. the first mirror pair */
130 void
131 rf_MapSectorChainDecluster(
132     RF_Raid_t * raidPtr,
133     RF_RaidAddr_t raidSector,
134     RF_RowCol_t * row,
135     RF_RowCol_t * col,
136     RF_SectorNum_t * diskSector,
137     int remap)
138 {
139 	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
140 	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
141 	RF_SectorNum_t index_within_region, index_within_disk;
142 	RF_StripeNum_t sparing_region_id;
143 	int     col_before_remap;
144 
145 	*row = 0;
146 	sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
147 	index_within_region = SUID % info->stripeUnitsPerSparingRegion;
148 	index_within_disk = index_within_region / raidPtr->numCol;
149 	col_before_remap = SUID % raidPtr->numCol;
150 
151 	if (!remap) {
152 		*col = col_before_remap;
153 		*diskSector = (index_within_disk + ((raidPtr->numCol - 1) * sparing_region_id)) *
154 		    raidPtr->Layout.sectorsPerStripeUnit;
155 		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
156 	} else {
157 		/* remap sector to spare space... */
158 		*diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
159 		*diskSector += (raidPtr->numCol - 1) * raidPtr->Layout.sectorsPerStripeUnit;
160 		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
161 		index_within_disk = index_within_region / raidPtr->numCol;
162 		if (index_within_disk < col_before_remap)
163 			*col = index_within_disk;
164 		else
165 			if (index_within_disk == raidPtr->numCol - 2) {
166 				*col = (col_before_remap + raidPtr->numCol - 1) % raidPtr->numCol;
167 				*diskSector += raidPtr->Layout.sectorsPerStripeUnit;
168 			} else
169 				*col = (index_within_disk + 2) % raidPtr->numCol;
170 	}
171 
172 }
173 
174 
175 
176 /* Maps to the second copy of the mirror pair, which is chain declustered. The second copy is contained
177    in the next disk (mod numCol) after the disk containing the primary copy.
178    The offset into the disk is one-half disk down */
179 void
180 rf_MapParityChainDecluster(
181     RF_Raid_t * raidPtr,
182     RF_RaidAddr_t raidSector,
183     RF_RowCol_t * row,
184     RF_RowCol_t * col,
185     RF_SectorNum_t * diskSector,
186     int remap)
187 {
188 	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
189 	RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
190 	RF_SectorNum_t index_within_region, index_within_disk;
191 	RF_StripeNum_t sparing_region_id;
192 	int     col_before_remap;
193 
194 	*row = 0;
195 	if (!remap) {
196 		*col = SUID % raidPtr->numCol;
197 		*col = (*col + 1) % raidPtr->numCol;
198 		*diskSector = info->mirrorStripeOffset * raidPtr->Layout.sectorsPerStripeUnit;
199 		*diskSector += (SUID / raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
200 		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
201 	} else {
202 		/* remap parity to spare space ... */
203 		sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
204 		index_within_region = SUID % info->stripeUnitsPerSparingRegion;
205 		index_within_disk = index_within_region / raidPtr->numCol;
206 		*diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
207 		*diskSector += (raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
208 		*diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
209 		col_before_remap = SUID % raidPtr->numCol;
210 		if (index_within_disk < col_before_remap)
211 			*col = index_within_disk;
212 		else
213 			if (index_within_disk == raidPtr->numCol - 2) {
214 				*col = (col_before_remap + 2) % raidPtr->numCol;
215 				*diskSector -= raidPtr->Layout.sectorsPerStripeUnit;
216 			} else
217 				*col = (index_within_disk + 2) % raidPtr->numCol;
218 	}
219 
220 }
221 
222 void
223 rf_IdentifyStripeChainDecluster(
224     RF_Raid_t * raidPtr,
225     RF_RaidAddr_t addr,
226     RF_RowCol_t ** diskids,
227     RF_RowCol_t * outRow)
228 {
229 	RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
230 	RF_StripeNum_t SUID;
231 	RF_RowCol_t col;
232 
233 	SUID = addr / raidPtr->Layout.sectorsPerStripeUnit;
234 	col = SUID % raidPtr->numCol;
235 	*outRow = 0;
236 	*diskids = info->stripeIdentifier[col];
237 }
238 
239 void
240 rf_MapSIDToPSIDChainDecluster(
241     RF_RaidLayout_t * layoutPtr,
242     RF_StripeNum_t stripeID,
243     RF_StripeNum_t * psID,
244     RF_ReconUnitNum_t * which_ru)
245 {
246 	*which_ru = 0;
247 	*psID = stripeID;
248 }
249 /******************************************************************************
250  * select a graph to perform a single-stripe access
251  *
252  * Parameters:  raidPtr    - description of the physical array
253  *              type       - type of operation (read or write) requested
254  *              asmap      - logical & physical addresses for this access
255  *              createFunc - function to use to create the graph (return value)
256  *****************************************************************************/
257 
258 void
259 rf_RAIDCDagSelect(
260     RF_Raid_t * raidPtr,
261     RF_IoType_t type,
262     RF_AccessStripeMap_t * asmap,
263     RF_VoidFuncPtr * createFunc)
264 #if 0
265 	void    (**createFunc) (RF_Raid_t *, RF_AccessStripeMap_t *,
266             RF_DagHeader_t *, void *, RF_RaidAccessFlags_t,
267             RF_AllocListElem_t *)
268 #endif
269 {
270 	RF_ASSERT(RF_IO_IS_R_OR_W(type));
271 	RF_ASSERT(raidPtr->numRow == 1);
272 
273 	if (asmap->numDataFailed + asmap->numParityFailed > 1) {
274 		RF_ERRORMSG("Multiple disks failed in a single group!  Aborting I/O operation.\n");
275 		*createFunc = NULL;
276 		return;
277 	}
278 	*createFunc = (type == RF_IO_TYPE_READ) ? (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG : (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
279 
280 	if (type == RF_IO_TYPE_READ) {
281 		if ((raidPtr->status[0] == rf_rs_degraded) || (raidPtr->status[0] == rf_rs_reconstructing))
282 			*createFunc = (RF_VoidFuncPtr) rf_CreateRaidCDegradedReadDAG;	/* array status is
283 											 * degraded, implement
284 											 * workload shifting */
285 		else
286 			*createFunc = (RF_VoidFuncPtr) rf_CreateMirrorPartitionReadDAG;	/* array status not
287 											 * degraded, so use
288 											 * mirror partition dag */
289 	} else
290 		*createFunc = (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
291 }
292 #endif /* (RF_INCLUDE_CHAINDECLUSTER > 0) */
293