Commit | Line | Data |
---|---|---|
26780d9e BG |
1 | /* |
2 | * linux/drivers/scsi/esas2r/esas2r_targdb.c | |
3 | * For use with ATTO ExpressSAS R6xx SAS/SATA RAID controllers | |
4 | * | |
5 | * Copyright (c) 2001-2013 ATTO Technology, Inc. | |
6 | * (mailto:linuxdrivers@attotech.com) | |
7 | * | |
8 | * This program is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU General Public License | |
10 | * as published by the Free Software Foundation; either version 2 | |
11 | * of the License, or (at your option) any later version. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * NO WARRANTY | |
19 | * THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR | |
20 | * CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT | |
21 | * LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT, | |
22 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is | |
23 | * solely responsible for determining the appropriateness of using and | |
24 | * distributing the Program and assumes all risks associated with its | |
25 | * exercise of rights under this Agreement, including but not limited to | |
26 | * the risks and costs of program errors, damage to or loss of data, | |
27 | * programs or equipment, and unavailability or interruption of operations. | |
28 | * | |
29 | * DISCLAIMER OF LIABILITY | |
30 | * NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY | |
31 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
32 | * DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND | |
33 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR | |
34 | * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE | |
35 | * USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED | |
36 | * HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES | |
37 | * | |
38 | * You should have received a copy of the GNU General Public License | |
39 | * along with this program; if not, write to the Free Software | |
40 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, | |
41 | * USA. | |
42 | */ | |
43 | ||
44 | #include "esas2r.h" | |
45 | ||
46 | void esas2r_targ_db_initialize(struct esas2r_adapter *a) | |
47 | { | |
48 | struct esas2r_target *t; | |
49 | ||
50 | for (t = a->targetdb; t < a->targetdb_end; t++) { | |
51 | memset(t, 0, sizeof(struct esas2r_target)); | |
52 | ||
53 | t->target_state = TS_NOT_PRESENT; | |
54 | t->buffered_target_state = TS_NOT_PRESENT; | |
55 | t->new_target_state = TS_INVALID; | |
56 | } | |
57 | } | |
58 | ||
59 | void esas2r_targ_db_remove_all(struct esas2r_adapter *a, bool notify) | |
60 | { | |
61 | struct esas2r_target *t; | |
62 | unsigned long flags; | |
63 | ||
64 | for (t = a->targetdb; t < a->targetdb_end; t++) { | |
65 | if (t->target_state != TS_PRESENT) | |
66 | continue; | |
67 | ||
68 | spin_lock_irqsave(&a->mem_lock, flags); | |
69 | esas2r_targ_db_remove(a, t); | |
70 | spin_unlock_irqrestore(&a->mem_lock, flags); | |
71 | ||
72 | if (notify) { | |
73 | esas2r_trace("remove id:%d", esas2r_targ_get_id(t, | |
74 | a)); | |
75 | esas2r_target_state_changed(a, esas2r_targ_get_id(t, | |
76 | a), | |
77 | TS_NOT_PRESENT); | |
78 | } | |
79 | } | |
80 | } | |
81 | ||
82 | void esas2r_targ_db_report_changes(struct esas2r_adapter *a) | |
83 | { | |
84 | struct esas2r_target *t; | |
85 | unsigned long flags; | |
86 | ||
87 | esas2r_trace_enter(); | |
88 | ||
9588d24e | 89 | if (test_bit(AF_DISC_PENDING, &a->flags)) { |
26780d9e BG |
90 | esas2r_trace_exit(); |
91 | return; | |
92 | } | |
93 | ||
94 | for (t = a->targetdb; t < a->targetdb_end; t++) { | |
95 | u8 state = TS_INVALID; | |
96 | ||
97 | spin_lock_irqsave(&a->mem_lock, flags); | |
98 | if (t->buffered_target_state != t->target_state) | |
99 | state = t->buffered_target_state = t->target_state; | |
100 | ||
101 | spin_unlock_irqrestore(&a->mem_lock, flags); | |
102 | if (state != TS_INVALID) { | |
103 | esas2r_trace("targ_db_report_changes:%d", | |
104 | esas2r_targ_get_id( | |
105 | t, | |
106 | a)); | |
107 | esas2r_trace("state:%d", state); | |
108 | ||
109 | esas2r_target_state_changed(a, | |
110 | esas2r_targ_get_id(t, | |
111 | a), | |
112 | state); | |
113 | } | |
114 | } | |
115 | ||
116 | esas2r_trace_exit(); | |
117 | } | |
118 | ||
119 | struct esas2r_target *esas2r_targ_db_add_raid(struct esas2r_adapter *a, | |
120 | struct esas2r_disc_context * | |
121 | dc) | |
122 | { | |
123 | struct esas2r_target *t; | |
124 | ||
125 | esas2r_trace_enter(); | |
126 | ||
127 | if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) { | |
128 | esas2r_bugon(); | |
129 | esas2r_trace_exit(); | |
130 | return NULL; | |
131 | } | |
132 | ||
133 | t = a->targetdb + dc->curr_virt_id; | |
134 | ||
135 | if (t->target_state == TS_PRESENT) { | |
136 | esas2r_trace_exit(); | |
137 | return NULL; | |
138 | } | |
139 | ||
140 | esas2r_hdebug("add RAID %s, T:%d", dc->raid_grp_name, | |
141 | esas2r_targ_get_id( | |
142 | t, | |
143 | a)); | |
144 | ||
145 | if (dc->interleave == 0 | |
146 | || dc->block_size == 0) { | |
147 | /* these are invalid values, don't create the target entry. */ | |
148 | ||
149 | esas2r_hdebug("invalid RAID group dimensions"); | |
150 | ||
151 | esas2r_trace_exit(); | |
152 | ||
153 | return NULL; | |
154 | } | |
155 | ||
156 | t->block_size = dc->block_size; | |
157 | t->inter_byte = dc->interleave; | |
158 | t->inter_block = dc->interleave / dc->block_size; | |
159 | t->virt_targ_id = dc->curr_virt_id; | |
160 | t->phys_targ_id = ESAS2R_TARG_ID_INV; | |
161 | ||
162 | t->flags &= ~TF_PASS_THRU; | |
163 | t->flags |= TF_USED; | |
164 | ||
165 | t->identifier_len = 0; | |
166 | ||
167 | t->target_state = TS_PRESENT; | |
168 | ||
169 | return t; | |
170 | } | |
171 | ||
172 | struct esas2r_target *esas2r_targ_db_add_pthru(struct esas2r_adapter *a, | |
173 | struct esas2r_disc_context *dc, | |
174 | u8 *ident, | |
175 | u8 ident_len) | |
176 | { | |
177 | struct esas2r_target *t; | |
178 | ||
179 | esas2r_trace_enter(); | |
180 | ||
181 | if (dc->curr_virt_id >= ESAS2R_MAX_TARGETS) { | |
182 | esas2r_bugon(); | |
183 | esas2r_trace_exit(); | |
184 | return NULL; | |
185 | } | |
186 | ||
187 | /* see if we found this device before. */ | |
188 | ||
189 | t = esas2r_targ_db_find_by_ident(a, ident, ident_len); | |
190 | ||
191 | if (t == NULL) { | |
192 | t = a->targetdb + dc->curr_virt_id; | |
193 | ||
194 | if (ident_len > sizeof(t->identifier) | |
195 | || t->target_state == TS_PRESENT) { | |
196 | esas2r_trace_exit(); | |
197 | return NULL; | |
198 | } | |
199 | } | |
200 | ||
201 | esas2r_hdebug("add PT; T:%d, V:%d, P:%d", esas2r_targ_get_id(t, a), | |
202 | dc->curr_virt_id, | |
203 | dc->curr_phys_id); | |
204 | ||
205 | t->block_size = 0; | |
206 | t->inter_byte = 0; | |
207 | t->inter_block = 0; | |
208 | t->virt_targ_id = dc->curr_virt_id; | |
209 | t->phys_targ_id = dc->curr_phys_id; | |
210 | t->identifier_len = ident_len; | |
211 | ||
212 | memcpy(t->identifier, ident, ident_len); | |
213 | ||
214 | t->flags |= TF_PASS_THRU | TF_USED; | |
215 | ||
216 | t->target_state = TS_PRESENT; | |
217 | ||
218 | return t; | |
219 | } | |
220 | ||
221 | void esas2r_targ_db_remove(struct esas2r_adapter *a, struct esas2r_target *t) | |
222 | { | |
223 | esas2r_trace_enter(); | |
224 | ||
225 | t->target_state = TS_NOT_PRESENT; | |
226 | ||
227 | esas2r_trace("remove id:%d", esas2r_targ_get_id(t, a)); | |
228 | ||
229 | esas2r_trace_exit(); | |
230 | } | |
231 | ||
232 | struct esas2r_target *esas2r_targ_db_find_by_sas_addr(struct esas2r_adapter *a, | |
233 | u64 *sas_addr) | |
234 | { | |
235 | struct esas2r_target *t; | |
236 | ||
237 | for (t = a->targetdb; t < a->targetdb_end; t++) | |
238 | if (t->sas_addr == *sas_addr) | |
239 | return t; | |
240 | ||
241 | return NULL; | |
242 | } | |
243 | ||
244 | struct esas2r_target *esas2r_targ_db_find_by_ident(struct esas2r_adapter *a, | |
245 | void *identifier, | |
246 | u8 ident_len) | |
247 | { | |
248 | struct esas2r_target *t; | |
249 | ||
250 | for (t = a->targetdb; t < a->targetdb_end; t++) { | |
251 | if (ident_len == t->identifier_len | |
252 | && memcmp(&t->identifier[0], identifier, | |
253 | ident_len) == 0) | |
254 | return t; | |
255 | } | |
256 | ||
257 | return NULL; | |
258 | } | |
259 | ||
260 | u16 esas2r_targ_db_find_next_present(struct esas2r_adapter *a, u16 target_id) | |
261 | { | |
262 | u16 id = target_id + 1; | |
263 | ||
264 | while (id < ESAS2R_MAX_TARGETS) { | |
265 | struct esas2r_target *t = a->targetdb + id; | |
266 | ||
267 | if (t->target_state == TS_PRESENT) | |
268 | break; | |
269 | ||
270 | id++; | |
271 | } | |
272 | ||
273 | return id; | |
274 | } | |
275 | ||
276 | struct esas2r_target *esas2r_targ_db_find_by_virt_id(struct esas2r_adapter *a, | |
277 | u16 virt_id) | |
278 | { | |
279 | struct esas2r_target *t; | |
280 | ||
281 | for (t = a->targetdb; t < a->targetdb_end; t++) { | |
282 | if (t->target_state != TS_PRESENT) | |
283 | continue; | |
284 | ||
285 | if (t->virt_targ_id == virt_id) | |
286 | return t; | |
287 | } | |
288 | ||
289 | return NULL; | |
290 | } | |
291 | ||
292 | u16 esas2r_targ_db_get_tgt_cnt(struct esas2r_adapter *a) | |
293 | { | |
294 | u16 devcnt = 0; | |
295 | struct esas2r_target *t; | |
296 | unsigned long flags; | |
297 | ||
298 | spin_lock_irqsave(&a->mem_lock, flags); | |
299 | for (t = a->targetdb; t < a->targetdb_end; t++) | |
300 | if (t->target_state == TS_PRESENT) | |
301 | devcnt++; | |
302 | ||
303 | spin_unlock_irqrestore(&a->mem_lock, flags); | |
304 | ||
305 | return devcnt; | |
306 | } |