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