1 | /* $NetBSD: rf_pqdeg.c,v 1.9 2005/12/11 12:23:37 christos Exp $ */ |
2 | /* |
3 | * Copyright (c) 1995 Carnegie-Mellon University. |
4 | * All rights reserved. |
5 | * |
6 | * Author: Daniel Stodolsky |
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 | #include <sys/cdefs.h> |
30 | __KERNEL_RCSID(0, "$NetBSD: rf_pqdeg.c,v 1.9 2005/12/11 12:23:37 christos Exp $" ); |
31 | |
32 | #include "rf_archs.h" |
33 | |
34 | #if (RF_INCLUDE_DECL_PQ > 0) || (RF_INCLUDE_RAID6 > 0) |
35 | |
36 | #include <dev/raidframe/raidframevar.h> |
37 | |
38 | #include "rf_raid.h" |
39 | #include "rf_dag.h" |
40 | #include "rf_dagutils.h" |
41 | #include "rf_dagfuncs.h" |
42 | #include "rf_dagffrd.h" |
43 | #include "rf_dagffwr.h" |
44 | #include "rf_dagdegrd.h" |
45 | #include "rf_dagdegwr.h" |
46 | #include "rf_etimer.h" |
47 | #include "rf_pqdeg.h" |
48 | #include "rf_general.h" |
49 | #include "rf_pqdegdags.h" |
50 | #include "rf_pq.h" |
51 | |
52 | /* |
53 | Degraded mode dag functions for P+Q calculations. |
54 | |
55 | The following nomenclature is used. |
56 | |
57 | PQ_<D><P><Q>_Create{Large,Small}<Write|Read>DAG |
58 | |
59 | where <D><P><Q> are single digits representing the number of failed |
60 | data units <D> (0,1,2), parity units <P> (0,1), and Q units <Q>, effecting |
61 | the I/O. The reads have only PQ_<D><P><Q>_CreateReadDAG variants, while |
62 | the single fault writes have both large and small write versions. (Single fault |
63 | PQ is equivalent to normal mode raid 5 in many aspects. |
64 | |
65 | Some versions degenerate into the same case, and are grouped together below. |
66 | */ |
67 | |
68 | /* Reads, single failure |
69 | |
70 | we have parity, so we can do a raid 5 |
71 | reconstruct read. |
72 | */ |
73 | |
74 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_100_CreateReadDAG) |
75 | { |
76 | rf_CreateDegradedReadDAG(raidPtr, asmap, dag_h, bp, flags, allocList, &rf_pRecoveryFuncs); |
77 | } |
78 | /* Reads double failure */ |
79 | |
80 | /* |
81 | Q is lost, but not parity |
82 | so we can a raid 5 reconstruct read. |
83 | */ |
84 | |
85 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_101_CreateReadDAG) |
86 | { |
87 | rf_CreateDegradedReadDAG(raidPtr, asmap, dag_h, bp, flags, allocList, &rf_pRecoveryFuncs); |
88 | } |
89 | /* |
90 | parity is lost, so we need to |
91 | do a reconstruct read and recompute |
92 | the data with Q. |
93 | */ |
94 | |
95 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_110_CreateReadDAG) |
96 | { |
97 | RF_PhysDiskAddr_t *temp; |
98 | /* swap P and Q pointers to fake out the DegradedReadDAG code */ |
99 | temp = asmap->parityInfo; |
100 | asmap->parityInfo = asmap->qInfo; |
101 | asmap->qInfo = temp; |
102 | rf_CreateDegradedReadDAG(raidPtr, asmap, dag_h, bp, flags, allocList, &rf_qRecoveryFuncs); |
103 | } |
104 | /* |
105 | Two data units are dead in this stripe, so we will need read |
106 | both P and Q to reconstruct the data. Note that only |
107 | one data unit we are reading may actually be missing. |
108 | */ |
109 | RF_CREATE_DAG_FUNC_DECL(rf_CreateDoubleDegradedReadDAG); |
110 | RF_CREATE_DAG_FUNC_DECL(rf_CreateDoubleDegradedReadDAG) |
111 | { |
112 | rf_PQ_DoubleDegRead(raidPtr, asmap, dag_h, bp, flags, allocList); |
113 | } |
114 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_200_CreateReadDAG); |
115 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_200_CreateReadDAG) |
116 | { |
117 | rf_CreateDoubleDegradedReadDAG(raidPtr, asmap, dag_h, bp, flags, allocList); |
118 | } |
119 | /* Writes, single failure */ |
120 | |
121 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_100_CreateWriteDAG); |
122 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_100_CreateWriteDAG) |
123 | { |
124 | if (asmap->numStripeUnitsAccessed != 1 && |
125 | asmap->failedPDAs[0]->numSector != |
126 | raidPtr->Layout.sectorsPerStripeUnit) |
127 | RF_PANIC(); |
128 | rf_CommonCreateSimpleDegradedWriteDAG(raidPtr, asmap, dag_h, bp, |
129 | flags, allocList, 2, |
130 | (int (*) (RF_DagNode_t *)) rf_Degraded_100_PQFunc, |
131 | RF_FALSE); |
132 | } |
133 | /* Dead P - act like a RAID 5 small write with parity = Q */ |
134 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_010_CreateSmallWriteDAG) |
135 | { |
136 | RF_PhysDiskAddr_t *temp; |
137 | /* swap P and Q pointers to fake out the DegradedReadDAG code */ |
138 | temp = asmap->parityInfo; |
139 | asmap->parityInfo = asmap->qInfo; |
140 | asmap->qInfo = temp; |
141 | rf_CommonCreateSmallWriteDAG(raidPtr, asmap, dag_h, bp, flags, |
142 | allocList, &rf_qFuncs, NULL); |
143 | } |
144 | /* Dead Q - act like a RAID 5 small write */ |
145 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_001_CreateSmallWriteDAG) |
146 | { |
147 | rf_CommonCreateSmallWriteDAG(raidPtr, asmap, dag_h, bp, flags, |
148 | allocList, &rf_pFuncs, NULL); |
149 | } |
150 | /* Dead P - act like a RAID 5 large write but for Q */ |
151 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_010_CreateLargeWriteDAG) |
152 | { |
153 | RF_PhysDiskAddr_t *temp; |
154 | /* swap P and Q pointers to fake out the code */ |
155 | temp = asmap->parityInfo; |
156 | asmap->parityInfo = asmap->qInfo; |
157 | asmap->qInfo = temp; |
158 | rf_CommonCreateLargeWriteDAG(raidPtr, asmap, dag_h, bp, flags, |
159 | allocList, 1, rf_RegularQFunc, RF_FALSE); |
160 | } |
161 | /* Dead Q - act like a RAID 5 large write */ |
162 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_001_CreateLargeWriteDAG) |
163 | { |
164 | rf_CommonCreateLargeWriteDAG(raidPtr, asmap, dag_h, bp, flags, |
165 | allocList, 1, rf_RegularPFunc, RF_FALSE); |
166 | } |
167 | |
168 | |
169 | /* |
170 | * writes, double failure |
171 | */ |
172 | |
173 | /* |
174 | * Lost P & Q - do a nonredundant write |
175 | */ |
176 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_011_CreateWriteDAG) |
177 | { |
178 | rf_CreateNonRedundantWriteDAG(raidPtr, asmap, dag_h, bp, flags, allocList, |
179 | RF_IO_TYPE_WRITE); |
180 | } |
181 | /* |
182 | In the two cases below, |
183 | A nasty case arises when the write a (strict) portion of a failed stripe unit |
184 | and parts of another su. For now, we do not support this. |
185 | */ |
186 | |
187 | /* |
188 | Lost Data and P - do a Q write. |
189 | */ |
190 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_110_CreateWriteDAG) |
191 | { |
192 | RF_PhysDiskAddr_t *temp; |
193 | |
194 | if (asmap->numStripeUnitsAccessed != 1 && |
195 | asmap->failedPDAs[0]->numSector != raidPtr->Layout.sectorsPerStripeUnit) { |
196 | RF_PANIC(); |
197 | } |
198 | /* swap P and Q to fake out parity code */ |
199 | temp = asmap->parityInfo; |
200 | asmap->parityInfo = asmap->qInfo; |
201 | asmap->qInfo = temp; |
202 | rf_CommonCreateSimpleDegradedWriteDAG(raidPtr, asmap, dag_h, bp, flags, |
203 | allocList, 1, |
204 | (int (*) (RF_DagNode_t *)) rf_PQ_DegradedWriteQFunc, |
205 | RF_FALSE); |
206 | /* is the regular Q func the right one to call? */ |
207 | } |
208 | /* |
209 | Lost Data and Q - do degraded mode P write |
210 | */ |
211 | RF_CREATE_DAG_FUNC_DECL(rf_PQ_101_CreateWriteDAG) |
212 | { |
213 | if (asmap->numStripeUnitsAccessed != 1 && |
214 | asmap->failedPDAs[0]->numSector != raidPtr->Layout.sectorsPerStripeUnit) |
215 | RF_PANIC(); |
216 | rf_CommonCreateSimpleDegradedWriteDAG(raidPtr, asmap, dag_h, bp, flags, |
217 | allocList, 1, rf_RecoveryXorFunc, RF_FALSE); |
218 | } |
219 | #endif /* (RF_INCLUDE_DECL_PQ > 0) || |
220 | * (RF_INCLUDE_RAID6 > 0) */ |
221 | |