diff options
Diffstat (limited to 'drivers/scsi/isci/remote_node_table.c')
-rw-r--r-- | drivers/scsi/isci/remote_node_table.c | 600 |
1 files changed, 600 insertions, 0 deletions
diff --git a/drivers/scsi/isci/remote_node_table.c b/drivers/scsi/isci/remote_node_table.c new file mode 100644 index 000000000000..8886146d9db2 --- /dev/null +++ b/drivers/scsi/isci/remote_node_table.c | |||
@@ -0,0 +1,600 @@ | |||
1 | /* | ||
2 | * This file is provided under a dual BSD/GPLv2 license. When using or | ||
3 | * redistributing this file, you may do so under either license. | ||
4 | * | ||
5 | * GPL LICENSE SUMMARY | ||
6 | * | ||
7 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of version 2 of the GNU General Public License as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, but | ||
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
16 | * General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. | ||
21 | * The full GNU General Public License is included in this distribution | ||
22 | * in the file called LICENSE.GPL. | ||
23 | * | ||
24 | * BSD LICENSE | ||
25 | * | ||
26 | * Copyright(c) 2008 - 2011 Intel Corporation. All rights reserved. | ||
27 | * All rights reserved. | ||
28 | * | ||
29 | * Redistribution and use in source and binary forms, with or without | ||
30 | * modification, are permitted provided that the following conditions | ||
31 | * are met: | ||
32 | * | ||
33 | * * Redistributions of source code must retain the above copyright | ||
34 | * notice, this list of conditions and the following disclaimer. | ||
35 | * * Redistributions in binary form must reproduce the above copyright | ||
36 | * notice, this list of conditions and the following disclaimer in | ||
37 | * the documentation and/or other materials provided with the | ||
38 | * distribution. | ||
39 | * * Neither the name of Intel Corporation nor the names of its | ||
40 | * contributors may be used to endorse or promote products derived | ||
41 | * from this software without specific prior written permission. | ||
42 | * | ||
43 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | ||
44 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | ||
45 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | ||
46 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | ||
47 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
48 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | ||
49 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
50 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
51 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
52 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
53 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
54 | */ | ||
55 | |||
56 | /** | ||
57 | * This file contains the implementation of the SCIC_SDS_REMOTE_NODE_TABLE | ||
58 | * public, protected, and private methods. | ||
59 | * | ||
60 | * | ||
61 | */ | ||
62 | #include "sci_util.h" | ||
63 | #include "sci_environment.h" | ||
64 | #include "remote_node_table.h" | ||
65 | #include "remote_node_context.h" | ||
66 | |||
67 | /** | ||
68 | * | ||
69 | * @remote_node_table: This is the remote node index table from which the | ||
70 | * selection will be made. | ||
71 | * @group_table_index: This is the index to the group table from which to | ||
72 | * search for an available selection. | ||
73 | * | ||
74 | * This routine will find the bit position in absolute bit terms of the next 32 | ||
75 | * + bit position. If there are available bits in the first u32 then it is | ||
76 | * just bit position. u32 This is the absolute bit position for an available | ||
77 | * group. | ||
78 | */ | ||
79 | static u32 scic_sds_remote_node_table_get_group_index( | ||
80 | struct scic_remote_node_table *remote_node_table, | ||
81 | u32 group_table_index) | ||
82 | { | ||
83 | u32 dword_index; | ||
84 | u32 *group_table; | ||
85 | u32 bit_index; | ||
86 | |||
87 | group_table = remote_node_table->remote_node_groups[group_table_index]; | ||
88 | |||
89 | for (dword_index = 0; dword_index < remote_node_table->group_array_size; dword_index++) { | ||
90 | if (group_table[dword_index] != 0) { | ||
91 | for (bit_index = 0; bit_index < 32; bit_index++) { | ||
92 | if ((group_table[dword_index] & (1 << bit_index)) != 0) { | ||
93 | return (dword_index * 32) + bit_index; | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | return SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX; | ||
100 | } | ||
101 | |||
102 | /** | ||
103 | * | ||
104 | * @out]: remote_node_table This the remote node table in which to clear the | ||
105 | * selector. | ||
106 | * @set_index: This is the remote node selector in which the change will be | ||
107 | * made. | ||
108 | * @group_index: This is the bit index in the table to be modified. | ||
109 | * | ||
110 | * This method will clear the group index entry in the specified group index | ||
111 | * table. none | ||
112 | */ | ||
113 | static void scic_sds_remote_node_table_clear_group_index( | ||
114 | struct scic_remote_node_table *remote_node_table, | ||
115 | u32 group_table_index, | ||
116 | u32 group_index) | ||
117 | { | ||
118 | u32 dword_index; | ||
119 | u32 bit_index; | ||
120 | u32 *group_table; | ||
121 | |||
122 | BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT); | ||
123 | BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32)); | ||
124 | |||
125 | dword_index = group_index / 32; | ||
126 | bit_index = group_index % 32; | ||
127 | group_table = remote_node_table->remote_node_groups[group_table_index]; | ||
128 | |||
129 | group_table[dword_index] = group_table[dword_index] & ~(1 << bit_index); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * | ||
134 | * @out]: remote_node_table This the remote node table in which to set the | ||
135 | * selector. | ||
136 | * @group_table_index: This is the remote node selector in which the change | ||
137 | * will be made. | ||
138 | * @group_index: This is the bit position in the table to be modified. | ||
139 | * | ||
140 | * This method will set the group index bit entry in the specified gropu index | ||
141 | * table. none | ||
142 | */ | ||
143 | static void scic_sds_remote_node_table_set_group_index( | ||
144 | struct scic_remote_node_table *remote_node_table, | ||
145 | u32 group_table_index, | ||
146 | u32 group_index) | ||
147 | { | ||
148 | u32 dword_index; | ||
149 | u32 bit_index; | ||
150 | u32 *group_table; | ||
151 | |||
152 | BUG_ON(group_table_index >= SCU_STP_REMOTE_NODE_COUNT); | ||
153 | BUG_ON(group_index >= (u32)(remote_node_table->group_array_size * 32)); | ||
154 | |||
155 | dword_index = group_index / 32; | ||
156 | bit_index = group_index % 32; | ||
157 | group_table = remote_node_table->remote_node_groups[group_table_index]; | ||
158 | |||
159 | group_table[dword_index] = group_table[dword_index] | (1 << bit_index); | ||
160 | } | ||
161 | |||
162 | /** | ||
163 | * | ||
164 | * @out]: remote_node_table This is the remote node table in which to modify | ||
165 | * the remote node availability. | ||
166 | * @remote_node_index: This is the remote node index that is being returned to | ||
167 | * the table. | ||
168 | * | ||
169 | * This method will set the remote to available in the remote node allocation | ||
170 | * table. none | ||
171 | */ | ||
172 | static void scic_sds_remote_node_table_set_node_index( | ||
173 | struct scic_remote_node_table *remote_node_table, | ||
174 | u32 remote_node_index) | ||
175 | { | ||
176 | u32 dword_location; | ||
177 | u32 dword_remainder; | ||
178 | u32 slot_normalized; | ||
179 | u32 slot_position; | ||
180 | |||
181 | BUG_ON( | ||
182 | (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) | ||
183 | <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT) | ||
184 | ); | ||
185 | |||
186 | dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD; | ||
187 | dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD; | ||
188 | slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32); | ||
189 | slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT; | ||
190 | |||
191 | remote_node_table->available_remote_nodes[dword_location] |= | ||
192 | 1 << (slot_normalized + slot_position); | ||
193 | } | ||
194 | |||
195 | /** | ||
196 | * | ||
197 | * @out]: remote_node_table This is the remote node table from which to clear | ||
198 | * the available remote node bit. | ||
199 | * @remote_node_index: This is the remote node index which is to be cleared | ||
200 | * from the table. | ||
201 | * | ||
202 | * This method clears the remote node index from the table of available remote | ||
203 | * nodes. none | ||
204 | */ | ||
205 | static void scic_sds_remote_node_table_clear_node_index( | ||
206 | struct scic_remote_node_table *remote_node_table, | ||
207 | u32 remote_node_index) | ||
208 | { | ||
209 | u32 dword_location; | ||
210 | u32 dword_remainder; | ||
211 | u32 slot_position; | ||
212 | u32 slot_normalized; | ||
213 | |||
214 | BUG_ON( | ||
215 | (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) | ||
216 | <= (remote_node_index / SCU_STP_REMOTE_NODE_COUNT) | ||
217 | ); | ||
218 | |||
219 | dword_location = remote_node_index / SCIC_SDS_REMOTE_NODES_PER_DWORD; | ||
220 | dword_remainder = remote_node_index % SCIC_SDS_REMOTE_NODES_PER_DWORD; | ||
221 | slot_normalized = (dword_remainder / SCU_STP_REMOTE_NODE_COUNT) * sizeof(u32); | ||
222 | slot_position = remote_node_index % SCU_STP_REMOTE_NODE_COUNT; | ||
223 | |||
224 | remote_node_table->available_remote_nodes[dword_location] &= | ||
225 | ~(1 << (slot_normalized + slot_position)); | ||
226 | } | ||
227 | |||
228 | /** | ||
229 | * | ||
230 | * @out]: remote_node_table The remote node table from which the slot will be | ||
231 | * cleared. | ||
232 | * @group_index: The index for the slot that is to be cleared. | ||
233 | * | ||
234 | * This method clears the entire table slot at the specified slot index. none | ||
235 | */ | ||
236 | static void scic_sds_remote_node_table_clear_group( | ||
237 | struct scic_remote_node_table *remote_node_table, | ||
238 | u32 group_index) | ||
239 | { | ||
240 | u32 dword_location; | ||
241 | u32 dword_remainder; | ||
242 | u32 dword_value; | ||
243 | |||
244 | BUG_ON( | ||
245 | (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) | ||
246 | <= (group_index / SCU_STP_REMOTE_NODE_COUNT) | ||
247 | ); | ||
248 | |||
249 | dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; | ||
250 | dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; | ||
251 | |||
252 | dword_value = remote_node_table->available_remote_nodes[dword_location]; | ||
253 | dword_value &= ~(SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4)); | ||
254 | remote_node_table->available_remote_nodes[dword_location] = dword_value; | ||
255 | } | ||
256 | |||
257 | /** | ||
258 | * | ||
259 | * @remote_node_table: | ||
260 | * | ||
261 | * THis method sets an entire remote node group in the remote node table. | ||
262 | */ | ||
263 | static void scic_sds_remote_node_table_set_group( | ||
264 | struct scic_remote_node_table *remote_node_table, | ||
265 | u32 group_index) | ||
266 | { | ||
267 | u32 dword_location; | ||
268 | u32 dword_remainder; | ||
269 | u32 dword_value; | ||
270 | |||
271 | BUG_ON( | ||
272 | (remote_node_table->available_nodes_array_size * SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD) | ||
273 | <= (group_index / SCU_STP_REMOTE_NODE_COUNT) | ||
274 | ); | ||
275 | |||
276 | dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; | ||
277 | dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; | ||
278 | |||
279 | dword_value = remote_node_table->available_remote_nodes[dword_location]; | ||
280 | dword_value |= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4)); | ||
281 | remote_node_table->available_remote_nodes[dword_location] = dword_value; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * | ||
286 | * @remote_node_table: This is the remote node table that for which the group | ||
287 | * value is to be returned. | ||
288 | * @group_index: This is the group index to use to find the group value. | ||
289 | * | ||
290 | * This method will return the group value for the specified group index. The | ||
291 | * bit values at the specified remote node group index. | ||
292 | */ | ||
293 | static u8 scic_sds_remote_node_table_get_group_value( | ||
294 | struct scic_remote_node_table *remote_node_table, | ||
295 | u32 group_index) | ||
296 | { | ||
297 | u32 dword_location; | ||
298 | u32 dword_remainder; | ||
299 | u32 dword_value; | ||
300 | |||
301 | dword_location = group_index / SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; | ||
302 | dword_remainder = group_index % SCIC_SDS_REMOTE_NODE_SETS_PER_DWORD; | ||
303 | |||
304 | dword_value = remote_node_table->available_remote_nodes[dword_location]; | ||
305 | dword_value &= (SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE << (dword_remainder * 4)); | ||
306 | dword_value = dword_value >> (dword_remainder * 4); | ||
307 | |||
308 | return (u8)dword_value; | ||
309 | } | ||
310 | |||
311 | /** | ||
312 | * | ||
313 | * @out]: remote_node_table The remote that which is to be initialized. | ||
314 | * @remote_node_entries: The number of entries to put in the table. | ||
315 | * | ||
316 | * This method will initialize the remote node table for use. none | ||
317 | */ | ||
318 | void scic_sds_remote_node_table_initialize( | ||
319 | struct scic_remote_node_table *remote_node_table, | ||
320 | u32 remote_node_entries) | ||
321 | { | ||
322 | u32 index; | ||
323 | |||
324 | /* | ||
325 | * Initialize the raw data we could improve the speed by only initializing | ||
326 | * those entries that we are actually going to be used */ | ||
327 | memset( | ||
328 | remote_node_table->available_remote_nodes, | ||
329 | 0x00, | ||
330 | sizeof(remote_node_table->available_remote_nodes) | ||
331 | ); | ||
332 | |||
333 | memset( | ||
334 | remote_node_table->remote_node_groups, | ||
335 | 0x00, | ||
336 | sizeof(remote_node_table->remote_node_groups) | ||
337 | ); | ||
338 | |||
339 | /* Initialize the available remote node sets */ | ||
340 | remote_node_table->available_nodes_array_size = (u16) | ||
341 | (remote_node_entries / SCIC_SDS_REMOTE_NODES_PER_DWORD) | ||
342 | + ((remote_node_entries % SCIC_SDS_REMOTE_NODES_PER_DWORD) != 0); | ||
343 | |||
344 | |||
345 | /* Initialize each full DWORD to a FULL SET of remote nodes */ | ||
346 | for (index = 0; index < remote_node_entries; index++) { | ||
347 | scic_sds_remote_node_table_set_node_index(remote_node_table, index); | ||
348 | } | ||
349 | |||
350 | remote_node_table->group_array_size = (u16) | ||
351 | (remote_node_entries / (SCU_STP_REMOTE_NODE_COUNT * 32)) | ||
352 | + ((remote_node_entries % (SCU_STP_REMOTE_NODE_COUNT * 32)) != 0); | ||
353 | |||
354 | for (index = 0; index < (remote_node_entries / SCU_STP_REMOTE_NODE_COUNT); index++) { | ||
355 | /* | ||
356 | * These are all guaranteed to be full slot values so fill them in the | ||
357 | * available sets of 3 remote nodes */ | ||
358 | scic_sds_remote_node_table_set_group_index(remote_node_table, 2, index); | ||
359 | } | ||
360 | |||
361 | /* Now fill in any remainders that we may find */ | ||
362 | if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 2) { | ||
363 | scic_sds_remote_node_table_set_group_index(remote_node_table, 1, index); | ||
364 | } else if ((remote_node_entries % SCU_STP_REMOTE_NODE_COUNT) == 1) { | ||
365 | scic_sds_remote_node_table_set_group_index(remote_node_table, 0, index); | ||
366 | } | ||
367 | } | ||
368 | |||
369 | /** | ||
370 | * | ||
371 | * @out]: remote_node_table The remote node table from which to allocate a | ||
372 | * remote node. | ||
373 | * @table_index: The group index that is to be used for the search. | ||
374 | * | ||
375 | * This method will allocate a single RNi from the remote node table. The | ||
376 | * table index will determine from which remote node group table to search. | ||
377 | * This search may fail and another group node table can be specified. The | ||
378 | * function is designed to allow a serach of the available single remote node | ||
379 | * group up to the triple remote node group. If an entry is found in the | ||
380 | * specified table the remote node is removed and the remote node groups are | ||
381 | * updated. The RNi value or an invalid remote node context if an RNi can not | ||
382 | * be found. | ||
383 | */ | ||
384 | static u16 scic_sds_remote_node_table_allocate_single_remote_node( | ||
385 | struct scic_remote_node_table *remote_node_table, | ||
386 | u32 group_table_index) | ||
387 | { | ||
388 | u8 index; | ||
389 | u8 group_value; | ||
390 | u32 group_index; | ||
391 | u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; | ||
392 | |||
393 | group_index = scic_sds_remote_node_table_get_group_index( | ||
394 | remote_node_table, group_table_index); | ||
395 | |||
396 | /* We could not find an available slot in the table selector 0 */ | ||
397 | if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) { | ||
398 | group_value = scic_sds_remote_node_table_get_group_value( | ||
399 | remote_node_table, group_index); | ||
400 | |||
401 | for (index = 0; index < SCU_STP_REMOTE_NODE_COUNT; index++) { | ||
402 | if (((1 << index) & group_value) != 0) { | ||
403 | /* We have selected a bit now clear it */ | ||
404 | remote_node_index = (u16)(group_index * SCU_STP_REMOTE_NODE_COUNT | ||
405 | + index); | ||
406 | |||
407 | scic_sds_remote_node_table_clear_group_index( | ||
408 | remote_node_table, group_table_index, group_index | ||
409 | ); | ||
410 | |||
411 | scic_sds_remote_node_table_clear_node_index( | ||
412 | remote_node_table, remote_node_index | ||
413 | ); | ||
414 | |||
415 | if (group_table_index > 0) { | ||
416 | scic_sds_remote_node_table_set_group_index( | ||
417 | remote_node_table, group_table_index - 1, group_index | ||
418 | ); | ||
419 | } | ||
420 | |||
421 | break; | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | |||
426 | return remote_node_index; | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * | ||
431 | * @remote_node_table: This is the remote node table from which to allocate the | ||
432 | * remote node entries. | ||
433 | * @group_table_index: THis is the group table index which must equal two (2) | ||
434 | * for this operation. | ||
435 | * | ||
436 | * This method will allocate three consecutive remote node context entries. If | ||
437 | * there are no remaining triple entries the function will return a failure. | ||
438 | * The remote node index that represents three consecutive remote node entries | ||
439 | * or an invalid remote node context if none can be found. | ||
440 | */ | ||
441 | static u16 scic_sds_remote_node_table_allocate_triple_remote_node( | ||
442 | struct scic_remote_node_table *remote_node_table, | ||
443 | u32 group_table_index) | ||
444 | { | ||
445 | u32 group_index; | ||
446 | u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; | ||
447 | |||
448 | group_index = scic_sds_remote_node_table_get_group_index( | ||
449 | remote_node_table, group_table_index); | ||
450 | |||
451 | if (group_index != SCIC_SDS_REMOTE_NODE_TABLE_INVALID_INDEX) { | ||
452 | remote_node_index = (u16)group_index * SCU_STP_REMOTE_NODE_COUNT; | ||
453 | |||
454 | scic_sds_remote_node_table_clear_group_index( | ||
455 | remote_node_table, group_table_index, group_index | ||
456 | ); | ||
457 | |||
458 | scic_sds_remote_node_table_clear_group( | ||
459 | remote_node_table, group_index | ||
460 | ); | ||
461 | } | ||
462 | |||
463 | return remote_node_index; | ||
464 | } | ||
465 | |||
466 | /** | ||
467 | * | ||
468 | * @remote_node_table: This is the remote node table from which the remote node | ||
469 | * allocation is to take place. | ||
470 | * @remote_node_count: This is ther remote node count which is one of | ||
471 | * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3). | ||
472 | * | ||
473 | * This method will allocate a remote node that mataches the remote node count | ||
474 | * specified by the caller. Valid values for remote node count is | ||
475 | * SCU_SSP_REMOTE_NODE_COUNT(1) or SCU_STP_REMOTE_NODE_COUNT(3). u16 This is | ||
476 | * the remote node index that is returned or an invalid remote node context. | ||
477 | */ | ||
478 | u16 scic_sds_remote_node_table_allocate_remote_node( | ||
479 | struct scic_remote_node_table *remote_node_table, | ||
480 | u32 remote_node_count) | ||
481 | { | ||
482 | u16 remote_node_index = SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX; | ||
483 | |||
484 | if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) { | ||
485 | remote_node_index = | ||
486 | scic_sds_remote_node_table_allocate_single_remote_node( | ||
487 | remote_node_table, 0); | ||
488 | |||
489 | if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { | ||
490 | remote_node_index = | ||
491 | scic_sds_remote_node_table_allocate_single_remote_node( | ||
492 | remote_node_table, 1); | ||
493 | } | ||
494 | |||
495 | if (remote_node_index == SCIC_SDS_REMOTE_NODE_CONTEXT_INVALID_INDEX) { | ||
496 | remote_node_index = | ||
497 | scic_sds_remote_node_table_allocate_single_remote_node( | ||
498 | remote_node_table, 2); | ||
499 | } | ||
500 | } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) { | ||
501 | remote_node_index = | ||
502 | scic_sds_remote_node_table_allocate_triple_remote_node( | ||
503 | remote_node_table, 2); | ||
504 | } | ||
505 | |||
506 | return remote_node_index; | ||
507 | } | ||
508 | |||
509 | /** | ||
510 | * | ||
511 | * @remote_node_table: | ||
512 | * | ||
513 | * This method will free a single remote node index back to the remote node | ||
514 | * table. This routine will update the remote node groups | ||
515 | */ | ||
516 | static void scic_sds_remote_node_table_release_single_remote_node( | ||
517 | struct scic_remote_node_table *remote_node_table, | ||
518 | u16 remote_node_index) | ||
519 | { | ||
520 | u32 group_index; | ||
521 | u8 group_value; | ||
522 | |||
523 | group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT; | ||
524 | |||
525 | group_value = scic_sds_remote_node_table_get_group_value(remote_node_table, group_index); | ||
526 | |||
527 | /* | ||
528 | * Assert that we are not trying to add an entry to a slot that is already | ||
529 | * full. */ | ||
530 | BUG_ON(group_value == SCIC_SDS_REMOTE_NODE_TABLE_FULL_SLOT_VALUE); | ||
531 | |||
532 | if (group_value == 0x00) { | ||
533 | /* | ||
534 | * There are no entries in this slot so it must be added to the single | ||
535 | * slot table. */ | ||
536 | scic_sds_remote_node_table_set_group_index(remote_node_table, 0, group_index); | ||
537 | } else if ((group_value & (group_value - 1)) == 0) { | ||
538 | /* | ||
539 | * There is only one entry in this slot so it must be moved from the | ||
540 | * single slot table to the dual slot table */ | ||
541 | scic_sds_remote_node_table_clear_group_index(remote_node_table, 0, group_index); | ||
542 | scic_sds_remote_node_table_set_group_index(remote_node_table, 1, group_index); | ||
543 | } else { | ||
544 | /* | ||
545 | * There are two entries in the slot so it must be moved from the dual | ||
546 | * slot table to the tripple slot table. */ | ||
547 | scic_sds_remote_node_table_clear_group_index(remote_node_table, 1, group_index); | ||
548 | scic_sds_remote_node_table_set_group_index(remote_node_table, 2, group_index); | ||
549 | } | ||
550 | |||
551 | scic_sds_remote_node_table_set_node_index(remote_node_table, remote_node_index); | ||
552 | } | ||
553 | |||
554 | /** | ||
555 | * | ||
556 | * @remote_node_table: This is the remote node table to which the remote node | ||
557 | * index is to be freed. | ||
558 | * | ||
559 | * This method will release a group of three consecutive remote nodes back to | ||
560 | * the free remote nodes. | ||
561 | */ | ||
562 | static void scic_sds_remote_node_table_release_triple_remote_node( | ||
563 | struct scic_remote_node_table *remote_node_table, | ||
564 | u16 remote_node_index) | ||
565 | { | ||
566 | u32 group_index; | ||
567 | |||
568 | group_index = remote_node_index / SCU_STP_REMOTE_NODE_COUNT; | ||
569 | |||
570 | scic_sds_remote_node_table_set_group_index( | ||
571 | remote_node_table, 2, group_index | ||
572 | ); | ||
573 | |||
574 | scic_sds_remote_node_table_set_group(remote_node_table, group_index); | ||
575 | } | ||
576 | |||
577 | /** | ||
578 | * | ||
579 | * @remote_node_table: The remote node table to which the remote node index is | ||
580 | * to be freed. | ||
581 | * @remote_node_count: This is the count of consecutive remote nodes that are | ||
582 | * to be freed. | ||
583 | * | ||
584 | * This method will release the remote node index back into the remote node | ||
585 | * table free pool. | ||
586 | */ | ||
587 | void scic_sds_remote_node_table_release_remote_node_index( | ||
588 | struct scic_remote_node_table *remote_node_table, | ||
589 | u32 remote_node_count, | ||
590 | u16 remote_node_index) | ||
591 | { | ||
592 | if (remote_node_count == SCU_SSP_REMOTE_NODE_COUNT) { | ||
593 | scic_sds_remote_node_table_release_single_remote_node( | ||
594 | remote_node_table, remote_node_index); | ||
595 | } else if (remote_node_count == SCU_STP_REMOTE_NODE_COUNT) { | ||
596 | scic_sds_remote_node_table_release_triple_remote_node( | ||
597 | remote_node_table, remote_node_index); | ||
598 | } | ||
599 | } | ||
600 | |||