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