1 /*        $NetBSD: rf_chaindecluster.c,v 1.16 2019/02/09 03:33:59 christos 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.16 2019/02/09 03:33:59 christos 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
rf_ConfigureChainDecluster(RF_ShutdownList_t ** listp,RF_Raid_t * raidPtr,RF_Config_t * cfgPtr)64 rf_ConfigureChainDecluster(RF_ShutdownList_t **listp,
65     RF_Raid_t *raidPtr, RF_Config_t *cfgPtr)
66 {
67           RF_RaidLayout_t *layoutPtr = &raidPtr->Layout;
68           RF_StripeCount_t num_used_stripeUnitsPerDisk;
69           RF_ChaindeclusterConfigInfo_t *info;
70           RF_RowCol_t i;
71 
72           /* create a Chained Declustering configuration structure */
73           info = RF_MallocAndAdd(sizeof(*info), raidPtr->cleanupList);
74           if (info == NULL)
75                     return (ENOMEM);
76           layoutPtr->layoutSpecificInfo = (void *) info;
77 
78           /* fill in the config structure.  */
79           info->stripeIdentifier = rf_make_2d_array(raidPtr->numCol, 2, raidPtr->cleanupList);
80           if (info->stripeIdentifier == NULL)
81                     return (ENOMEM);
82           for (i = 0; i < raidPtr->numCol; i++) {
83                     info->stripeIdentifier[i][0] = i % raidPtr->numCol;
84                     info->stripeIdentifier[i][1] = (i + 1) % raidPtr->numCol;
85           }
86 
87           /* fill in the remaining layout parameters */
88           num_used_stripeUnitsPerDisk = layoutPtr->stripeUnitsPerDisk - (layoutPtr->stripeUnitsPerDisk %
89               (2 * raidPtr->numCol - 2));
90           info->numSparingRegions = num_used_stripeUnitsPerDisk / (2 * raidPtr->numCol - 2);
91           info->stripeUnitsPerSparingRegion = raidPtr->numCol * (raidPtr->numCol - 1);
92           info->mirrorStripeOffset = info->numSparingRegions * (raidPtr->numCol - 1);
93           layoutPtr->numStripe = info->numSparingRegions * info->stripeUnitsPerSparingRegion;
94           layoutPtr->numDataCol = 1;
95           layoutPtr->dataSectorsPerStripe = layoutPtr->numDataCol * layoutPtr->sectorsPerStripeUnit;
96           layoutPtr->numParityCol = 1;
97 
98           layoutPtr->dataStripeUnitsPerDisk = num_used_stripeUnitsPerDisk;
99 
100           raidPtr->sectorsPerDisk =
101               num_used_stripeUnitsPerDisk * layoutPtr->sectorsPerStripeUnit;
102 
103           raidPtr->totalSectors =
104               (layoutPtr->numStripe) * layoutPtr->sectorsPerStripeUnit;
105 
106           layoutPtr->stripeUnitsPerDisk = raidPtr->sectorsPerDisk / layoutPtr->sectorsPerStripeUnit;
107 
108           return (0);
109 }
110 
111 RF_ReconUnitCount_t
rf_GetNumSpareRUsChainDecluster(RF_Raid_t * raidPtr)112 rf_GetNumSpareRUsChainDecluster(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
rf_MapSectorChainDecluster(RF_Raid_t * raidPtr,RF_RaidAddr_t raidSector,RF_RowCol_t * col,RF_SectorNum_t * diskSector,int remap)126 rf_MapSectorChainDecluster(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
127                                  RF_RowCol_t *col, RF_SectorNum_t *diskSector,
128                                  int remap)
129 {
130           RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
131           RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
132           RF_SectorNum_t index_within_region, index_within_disk;
133           RF_StripeNum_t sparing_region_id;
134           int     col_before_remap;
135 
136           sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
137           index_within_region = SUID % info->stripeUnitsPerSparingRegion;
138           index_within_disk = index_within_region / raidPtr->numCol;
139           col_before_remap = SUID % raidPtr->numCol;
140 
141           if (!remap) {
142                     *col = col_before_remap;
143                     *diskSector = (index_within_disk + ((raidPtr->numCol - 1) * sparing_region_id)) *
144                         raidPtr->Layout.sectorsPerStripeUnit;
145                     *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
146           } else {
147                     /* remap sector to spare space... */
148                     *diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
149                     *diskSector += (raidPtr->numCol - 1) * raidPtr->Layout.sectorsPerStripeUnit;
150                     *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
151                     index_within_disk = index_within_region / raidPtr->numCol;
152                     if (index_within_disk < col_before_remap)
153                               *col = index_within_disk;
154                     else
155                               if (index_within_disk == raidPtr->numCol - 2) {
156                                         *col = (col_before_remap + raidPtr->numCol - 1) % raidPtr->numCol;
157                                         *diskSector += raidPtr->Layout.sectorsPerStripeUnit;
158                               } else
159                                         *col = (index_within_disk + 2) % raidPtr->numCol;
160           }
161 
162 }
163 
164 
165 
166 /* Maps to the second copy of the mirror pair, which is chain declustered. The second copy is contained
167    in the next disk (mod numCol) after the disk containing the primary copy.
168    The offset into the disk is one-half disk down */
169 void
rf_MapParityChainDecluster(RF_Raid_t * raidPtr,RF_RaidAddr_t raidSector,RF_RowCol_t * col,RF_SectorNum_t * diskSector,int remap)170 rf_MapParityChainDecluster(RF_Raid_t *raidPtr, RF_RaidAddr_t raidSector,
171                                  RF_RowCol_t *col, RF_SectorNum_t *diskSector,
172                                  int remap)
173 {
174           RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
175           RF_StripeNum_t SUID = raidSector / raidPtr->Layout.sectorsPerStripeUnit;
176           RF_SectorNum_t index_within_region, index_within_disk;
177           RF_StripeNum_t sparing_region_id;
178           int     col_before_remap;
179 
180           if (!remap) {
181                     *col = SUID % raidPtr->numCol;
182                     *col = (*col + 1) % raidPtr->numCol;
183                     *diskSector = info->mirrorStripeOffset * raidPtr->Layout.sectorsPerStripeUnit;
184                     *diskSector += (SUID / raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
185                     *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
186           } else {
187                     /* remap parity to spare space ... */
188                     sparing_region_id = SUID / info->stripeUnitsPerSparingRegion;
189                     index_within_region = SUID % info->stripeUnitsPerSparingRegion;
190                     index_within_disk = index_within_region / raidPtr->numCol;
191                     *diskSector = sparing_region_id * (raidPtr->numCol + 1) * raidPtr->Layout.sectorsPerStripeUnit;
192                     *diskSector += (raidPtr->numCol) * raidPtr->Layout.sectorsPerStripeUnit;
193                     *diskSector += (raidSector % raidPtr->Layout.sectorsPerStripeUnit);
194                     col_before_remap = SUID % raidPtr->numCol;
195                     if (index_within_disk < col_before_remap)
196                               *col = index_within_disk;
197                     else
198                               if (index_within_disk == raidPtr->numCol - 2) {
199                                         *col = (col_before_remap + 2) % raidPtr->numCol;
200                                         *diskSector -= raidPtr->Layout.sectorsPerStripeUnit;
201                               } else
202                                         *col = (index_within_disk + 2) % raidPtr->numCol;
203           }
204 
205 }
206 
207 void
rf_IdentifyStripeChainDecluster(RF_Raid_t * raidPtr,RF_RaidAddr_t addr,RF_RowCol_t ** diskids)208 rf_IdentifyStripeChainDecluster(RF_Raid_t *raidPtr, RF_RaidAddr_t addr,
209                                         RF_RowCol_t **diskids)
210 {
211           RF_ChaindeclusterConfigInfo_t *info = (RF_ChaindeclusterConfigInfo_t *) raidPtr->Layout.layoutSpecificInfo;
212           RF_StripeNum_t SUID;
213           RF_RowCol_t col;
214 
215           SUID = addr / raidPtr->Layout.sectorsPerStripeUnit;
216           col = SUID % raidPtr->numCol;
217           *diskids = info->stripeIdentifier[col];
218 }
219 
220 void
rf_MapSIDToPSIDChainDecluster(RF_RaidLayout_t * layoutPtr,RF_StripeNum_t stripeID,RF_StripeNum_t * psID,RF_ReconUnitNum_t * which_ru)221 rf_MapSIDToPSIDChainDecluster(RF_RaidLayout_t *layoutPtr,
222                                     RF_StripeNum_t stripeID,
223                                     RF_StripeNum_t *psID,
224                                     RF_ReconUnitNum_t *which_ru)
225 {
226           *which_ru = 0;
227           *psID = stripeID;
228 }
229 /******************************************************************************
230  * select a graph to perform a single-stripe access
231  *
232  * Parameters:  raidPtr    - description of the physical array
233  *              type       - type of operation (read or write) requested
234  *              asmap      - logical & physical addresses for this access
235  *              createFunc - function to use to create the graph (return value)
236  *****************************************************************************/
237 
238 void
rf_RAIDCDagSelect(RF_Raid_t * raidPtr,RF_IoType_t type,RF_AccessStripeMap_t * asmap,RF_VoidFuncPtr * createFunc)239 rf_RAIDCDagSelect(RF_Raid_t *raidPtr, RF_IoType_t type,
240                       RF_AccessStripeMap_t *asmap, RF_VoidFuncPtr *createFunc)
241 #if 0
242           void    (**createFunc) (RF_Raid_t *, RF_AccessStripeMap_t *,
243             RF_DagHeader_t *, void *, RF_RaidAccessFlags_t,
244             RF_AllocListElem_t *)
245 #endif
246 {
247           RF_ASSERT(RF_IO_IS_R_OR_W(type));
248 
249           if (asmap->numDataFailed + asmap->numParityFailed > 1) {
250                     RF_ERRORMSG("Multiple disks failed in a single group!  Aborting I/O operation.\n");
251                     *createFunc = NULL;
252                     return;
253           }
254           *createFunc = (type == RF_IO_TYPE_READ) ? (RF_VoidFuncPtr) rf_CreateFaultFreeReadDAG : (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
255 
256           if (type == RF_IO_TYPE_READ) {
257                     if ((raidPtr->status == rf_rs_degraded) || (raidPtr->status == rf_rs_reconstructing))
258                               *createFunc = (RF_VoidFuncPtr) rf_CreateRaidCDegradedReadDAG;         /* array status is
259                                                                                                                * degraded, implement
260                                                                                                                * workload shifting */
261                     else
262                               *createFunc = (RF_VoidFuncPtr) rf_CreateMirrorPartitionReadDAG;       /* array status not
263                                                                                                                * degraded, so use
264                                                                                                                * mirror partition dag */
265           } else
266                     *createFunc = (RF_VoidFuncPtr) rf_CreateRaidOneWriteDAG;
267 }
268 #endif /* (RF_INCLUDE_CHAINDECLUSTER > 0) */
269