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