1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2014-2023 Broadcom 3 * All rights reserved. 4 */ 5 6 #include <rte_log.h> 7 #include <rte_malloc.h> 8 #include "bnxt_ulp_utils.h" 9 #include "tf_core.h" 10 #include "tfp.h" 11 #include "ulp_mapper.h" 12 #include "ulp_flow_db.h" 13 14 /* Retrieve the generic table initialization parameters for the tbl_idx */ 15 static const struct bnxt_ulp_generic_tbl_params* 16 ulp_mapper_gen_tbl_params_get(struct bnxt_ulp_context *ulp_ctx, 17 uint32_t tbl_idx) 18 { 19 struct bnxt_ulp_device_params *dparms; 20 const struct bnxt_ulp_generic_tbl_params *gen_tbl; 21 uint32_t dev_id; 22 23 if (tbl_idx >= BNXT_ULP_GEN_TBL_MAX_SZ) { 24 BNXT_DRV_DBG(ERR, "Gen table out of bounds %d\n", tbl_idx); 25 return NULL; 26 } 27 28 if (bnxt_ulp_cntxt_dev_id_get(ulp_ctx, &dev_id)) 29 return NULL; 30 31 dparms = bnxt_ulp_device_params_get(dev_id); 32 if (!dparms) { 33 BNXT_DRV_DBG(ERR, "Failed to get device parms\n"); 34 return NULL; 35 } 36 37 gen_tbl = &dparms->gen_tbl_params[tbl_idx]; 38 return gen_tbl; 39 } 40 41 /* 42 * Initialize the generic table list 43 * 44 * mapper_data [in] Pointer to the mapper data and the generic table is 45 * part of it 46 * 47 * returns 0 on success 48 */ 49 int32_t 50 ulp_mapper_generic_tbl_list_init(struct bnxt_ulp_context *ulp_ctx, 51 struct bnxt_ulp_mapper_data *mapper_data) 52 { 53 const struct bnxt_ulp_generic_tbl_params *tbl; 54 struct ulp_mapper_gen_tbl_list *entry; 55 struct ulp_hash_create_params cparams; 56 uint32_t idx, size, key_sz; 57 58 /* Allocate the generic tables. */ 59 for (idx = 0; idx < BNXT_ULP_GEN_TBL_MAX_SZ; idx++) { 60 tbl = ulp_mapper_gen_tbl_params_get(ulp_ctx, idx); 61 if (!tbl) { 62 BNXT_DRV_DBG(ERR, "Failed to get gen table parms %d\n", 63 idx); 64 return -EINVAL; 65 } 66 entry = &mapper_data->gen_tbl_list[idx]; 67 68 /* For simple list allocate memory for key storage*/ 69 if (tbl->gen_tbl_type == BNXT_ULP_GEN_TBL_TYPE_SIMPLE_LIST && 70 tbl->key_num_bytes) { 71 key_sz = tbl->key_num_bytes + 72 tbl->partial_key_num_bytes; 73 entry->container.byte_key_ex_size = tbl->key_num_bytes; 74 entry->container.byte_key_par_size = 75 tbl->partial_key_num_bytes; 76 } else { 77 key_sz = 0; 78 } 79 80 /* Allocate memory for result data and key data */ 81 if (tbl->result_num_entries != 0) { 82 /* assign the name */ 83 entry->gen_tbl_name = tbl->name; 84 entry->tbl_type = tbl->gen_tbl_type; 85 /* add 4 bytes for reference count */ 86 entry->mem_data_size = (tbl->result_num_entries + 1) * 87 (tbl->result_num_bytes + sizeof(uint32_t) + 88 key_sz); 89 90 /* allocate the big chunk of memory */ 91 entry->mem_data = rte_zmalloc("ulp mapper gen tbl", 92 entry->mem_data_size, 0); 93 if (!entry->mem_data) { 94 BNXT_DRV_DBG(ERR, 95 "%s:Failed to alloc gen table %d\n", 96 tbl->name, idx); 97 return -ENOMEM; 98 } 99 /* Populate the generic table container */ 100 entry->container.num_elem = tbl->result_num_entries; 101 entry->container.byte_data_size = tbl->result_num_bytes; 102 entry->container.ref_count = 103 (uint32_t *)entry->mem_data; 104 size = sizeof(uint32_t) * (tbl->result_num_entries + 1); 105 entry->container.byte_data = &entry->mem_data[size]; 106 entry->container.byte_order = tbl->result_byte_order; 107 } else { 108 BNXT_DRV_DBG(DEBUG, "%s: Unused Gen tbl entry is %d\n", 109 tbl->name, idx); 110 continue; 111 } 112 113 /* assign the memory for key data */ 114 if (tbl->gen_tbl_type == BNXT_ULP_GEN_TBL_TYPE_SIMPLE_LIST && 115 key_sz) { 116 size += tbl->result_num_bytes * 117 (tbl->result_num_entries + 1); 118 entry->container.byte_key = 119 &entry->mem_data[size]; 120 } 121 122 /* Initialize Hash list for hash based generic table */ 123 if (tbl->gen_tbl_type == BNXT_ULP_GEN_TBL_TYPE_HASH_LIST && 124 tbl->hash_tbl_entries) { 125 cparams.key_size = tbl->key_num_bytes; 126 cparams.num_buckets = tbl->num_buckets; 127 cparams.num_hash_tbl_entries = tbl->hash_tbl_entries; 128 cparams.num_key_entries = tbl->result_num_entries; 129 if (ulp_gen_hash_tbl_list_init(&cparams, 130 &entry->hash_tbl)) { 131 BNXT_DRV_DBG(ERR, 132 "%s: Failed to alloc hash tbl %d\n", 133 tbl->name, idx); 134 return -ENOMEM; 135 } 136 } 137 } 138 return 0; 139 } 140 141 /* 142 * Free the generic table list 143 * 144 * mapper_data [in] Pointer to the mapper data and the generic table is 145 * part of it 146 * 147 * returns 0 on success 148 */ 149 int32_t 150 ulp_mapper_generic_tbl_list_deinit(struct bnxt_ulp_mapper_data *mapper_data) 151 { 152 struct ulp_mapper_gen_tbl_list *tbl_list; 153 uint32_t idx; 154 155 /* iterate the generic table. */ 156 for (idx = 0; idx < BNXT_ULP_GEN_TBL_MAX_SZ; idx++) { 157 tbl_list = &mapper_data->gen_tbl_list[idx]; 158 if (tbl_list->mem_data) { 159 rte_free(tbl_list->mem_data); 160 tbl_list->mem_data = NULL; 161 tbl_list->container.byte_data = NULL; 162 tbl_list->container.byte_key = NULL; 163 tbl_list->container.ref_count = NULL; 164 } 165 if (tbl_list->hash_tbl) { 166 ulp_gen_hash_tbl_list_deinit(tbl_list->hash_tbl); 167 tbl_list->hash_tbl = NULL; 168 } 169 } 170 /* success */ 171 return 0; 172 } 173 174 /* 175 * Get the generic table list entry 176 * 177 * tbl_list [in] - Ptr to generic table 178 * key [in] - Key index to the table 179 * entry [out] - output will include the entry if found 180 * 181 * returns 0 on success. 182 */ 183 int32_t 184 ulp_mapper_gen_tbl_entry_get(struct ulp_mapper_gen_tbl_list *tbl_list, 185 uint32_t key, 186 struct ulp_mapper_gen_tbl_entry *entry) 187 { 188 /* populate the output and return the values */ 189 if (key > tbl_list->container.num_elem) { 190 BNXT_DRV_DBG(ERR, "%s: invalid key %x:%x\n", 191 tbl_list->gen_tbl_name, key, 192 tbl_list->container.num_elem); 193 return -EINVAL; 194 } 195 entry->ref_count = &tbl_list->container.ref_count[key]; 196 entry->byte_data_size = tbl_list->container.byte_data_size; 197 entry->byte_data = &tbl_list->container.byte_data[key * 198 entry->byte_data_size]; 199 entry->byte_order = tbl_list->container.byte_order; 200 if (tbl_list->tbl_type == BNXT_ULP_GEN_TBL_TYPE_SIMPLE_LIST) { 201 entry->byte_key_size = tbl_list->container.byte_key_ex_size + 202 tbl_list->container.byte_key_par_size; 203 entry->byte_key = &tbl_list->container.byte_key[key * 204 entry->byte_key_size]; 205 } else { 206 entry->byte_key = NULL; 207 entry->byte_key_size = 0; 208 } 209 return 0; 210 } 211 212 /* 213 * utility function to calculate the table idx 214 * 215 * res_sub_type [in] - Resource sub type 216 * dir [in] - Direction 217 * 218 * returns None 219 */ 220 int32_t 221 ulp_mapper_gen_tbl_idx_calculate(uint32_t res_sub_type, uint32_t dir) 222 { 223 int32_t tbl_idx; 224 225 /* Validate for direction */ 226 if (dir >= TF_DIR_MAX) { 227 BNXT_DRV_DBG(ERR, "invalid argument %x\n", dir); 228 return -EINVAL; 229 } 230 tbl_idx = (res_sub_type << 1) | (dir & 0x1); 231 if (tbl_idx >= BNXT_ULP_GEN_TBL_MAX_SZ) { 232 BNXT_DRV_DBG(ERR, "invalid table index %x\n", tbl_idx); 233 return -EINVAL; 234 } 235 return tbl_idx; 236 } 237 238 /* 239 * Set the data in the generic table entry, Data is in Big endian format 240 * 241 * entry [in] - generic table entry 242 * key [in] - pointer to the key to be used for setting the value. 243 * key_size [in] - The length of the key in bytess to be set 244 * data [in] - pointer to the data to be used for setting the value. 245 * data_size [in] - length of the data pointer in bytes. 246 * 247 * returns 0 on success 248 */ 249 int32_t 250 ulp_mapper_gen_tbl_entry_data_set(struct ulp_mapper_gen_tbl_list *tbl_list, 251 struct ulp_mapper_gen_tbl_entry *entry, 252 uint8_t *key, uint32_t key_size, 253 uint8_t *data, uint32_t data_size) 254 { 255 /* validate the null arguments */ 256 if (!entry || !key || !data) { 257 BNXT_DRV_DBG(ERR, "invalid argument\n"); 258 return -EINVAL; 259 } 260 261 /* check the size of the buffer for validation */ 262 if (data_size > entry->byte_data_size) { 263 BNXT_DRV_DBG(ERR, "invalid offset or length %x:%x\n", 264 data_size, entry->byte_data_size); 265 return -EINVAL; 266 } 267 memcpy(entry->byte_data, data, data_size); 268 if (tbl_list->tbl_type == BNXT_ULP_GEN_TBL_TYPE_SIMPLE_LIST) { 269 if (key_size > entry->byte_key_size) { 270 BNXT_DRV_DBG(ERR, "invalid offset or length %x:%x\n", 271 key_size, entry->byte_key_size); 272 return -EINVAL; 273 } 274 memcpy(entry->byte_key, key, key_size); 275 } 276 tbl_list->container.seq_cnt++; 277 return 0; 278 } 279 280 /* 281 * Get the data in the generic table entry, Data is in Big endian format 282 * 283 * entry [in] - generic table entry 284 * offset [in] - The offset in bits where the data has to get 285 * len [in] - The length of the data in bits to be get 286 * data [out] - pointer to the data to be used for setting the value. 287 * data_size [in] - The size of data in bytes 288 * 289 * returns 0 on success 290 */ 291 int32_t 292 ulp_mapper_gen_tbl_entry_data_get(struct ulp_mapper_gen_tbl_entry *entry, 293 uint32_t offset, uint32_t len, uint8_t *data, 294 uint32_t data_size) 295 { 296 /* validate the null arguments */ 297 if (!entry || !data) { 298 BNXT_DRV_DBG(ERR, "invalid argument\n"); 299 return -EINVAL; 300 } 301 302 /* check the size of the buffer for validation */ 303 if ((offset + len) > ULP_BYTE_2_BITS(entry->byte_data_size) || 304 len > ULP_BYTE_2_BITS(data_size)) { 305 BNXT_DRV_DBG(ERR, "invalid offset or length %x:%x:%x\n", 306 offset, len, entry->byte_data_size); 307 return -EINVAL; 308 } 309 if (entry->byte_order == BNXT_ULP_BYTE_ORDER_LE) 310 ulp_bs_pull_lsb(entry->byte_data, data, data_size, offset, len); 311 else 312 ulp_bs_pull_msb(entry->byte_data, data, offset, len); 313 314 return 0; 315 } 316 317 /* Free the generic table list entry 318 * 319 * ulp_ctx [in] - Pointer to the ulp context 320 * tbl_idx [in] - Index of the generic table 321 * ckey [in] - Key for the entry in the table 322 * 323 * returns 0 on success 324 */ 325 int32_t 326 ulp_mapper_gen_tbl_entry_free(struct bnxt_ulp_context *ulp_ctx, 327 uint32_t tbl_idx, uint32_t ckey) 328 { 329 struct ulp_flow_db_res_params res; 330 uint32_t fid = 0; /* not using for this case */ 331 332 res.direction = tbl_idx & 0x1; 333 res.resource_sub_type = tbl_idx >> 1; 334 res.resource_hndl = ckey; 335 336 return ulp_mapper_gen_tbl_res_free(ulp_ctx, fid, &res); 337 } 338 339 /* Free the generic table list resource 340 * 341 * ulp_ctx [in] - Pointer to the ulp context 342 * fid [in] - The fid the generic table is associated with 343 * res [in] - Pointer to flow db resource entry 344 * 345 * returns 0 on success 346 */ 347 int32_t 348 ulp_mapper_gen_tbl_res_free(struct bnxt_ulp_context *ulp_ctx, 349 uint32_t fid, 350 struct ulp_flow_db_res_params *res) 351 { 352 struct bnxt_ulp_mapper_data *mapper_data; 353 struct ulp_mapper_gen_tbl_list *gen_tbl_list; 354 struct ulp_mapper_gen_tbl_entry entry; 355 struct ulp_gen_hash_entry_params hash_entry; 356 int32_t tbl_idx; 357 uint32_t rid = 0; 358 uint32_t key_idx; 359 360 /* Extract the resource sub type and direction */ 361 tbl_idx = ulp_mapper_gen_tbl_idx_calculate(res->resource_sub_type, 362 res->direction); 363 if (tbl_idx < 0) { 364 BNXT_DRV_DBG(ERR, "invalid argument %x:%x\n", 365 res->resource_sub_type, res->direction); 366 return -EINVAL; 367 } 368 369 mapper_data = bnxt_ulp_cntxt_ptr2_mapper_data_get(ulp_ctx); 370 if (!mapper_data) { 371 BNXT_DRV_DBG(ERR, "invalid ulp context %x\n", tbl_idx); 372 return -EINVAL; 373 } 374 /* get the generic table */ 375 gen_tbl_list = &mapper_data->gen_tbl_list[tbl_idx]; 376 377 /* Get the generic table entry*/ 378 if (gen_tbl_list->hash_tbl) { 379 /* use the hash index to get the value */ 380 hash_entry.hash_index = (uint32_t)res->resource_hndl; 381 if (ulp_gen_hash_tbl_list_index_search(gen_tbl_list->hash_tbl, 382 &hash_entry)) { 383 BNXT_DRV_DBG(ERR, "Unable to find has entry %x:%x\n", 384 tbl_idx, hash_entry.hash_index); 385 return -EINVAL; 386 } 387 key_idx = hash_entry.key_idx; 388 389 } else { 390 key_idx = (uint32_t)res->resource_hndl; 391 } 392 if (ulp_mapper_gen_tbl_entry_get(gen_tbl_list, key_idx, &entry)) { 393 BNXT_DRV_DBG(ERR, "Gen tbl entry get failed %x:%" PRIX64 "\n", 394 tbl_idx, res->resource_hndl); 395 return -EINVAL; 396 } 397 398 /* Decrement the reference count */ 399 if (!ULP_GEN_TBL_REF_CNT(&entry)) { 400 BNXT_DRV_DBG(DEBUG, 401 "generic table entry already free %x:%" PRIX64 "\n", 402 tbl_idx, res->resource_hndl); 403 return 0; 404 } 405 ULP_GEN_TBL_REF_CNT_DEC(&entry); 406 407 /* retain the details since there are other users */ 408 if (ULP_GEN_TBL_REF_CNT(&entry)) 409 return 0; 410 411 /* Delete the generic table entry. First extract the rid */ 412 if (ulp_mapper_gen_tbl_entry_data_get(&entry, ULP_GEN_TBL_FID_OFFSET, 413 ULP_GEN_TBL_FID_SIZE_BITS, 414 (uint8_t *)&rid, 415 sizeof(rid))) { 416 BNXT_DRV_DBG(ERR, "Unable to get rid %x:%" PRIX64 "\n", 417 tbl_idx, res->resource_hndl); 418 return -EINVAL; 419 } 420 rid = tfp_be_to_cpu_32(rid); 421 /* no need to del if rid is 0 since there is no associated resource 422 * if rid from the entry is equal to the incoming fid, then we have a 423 * recursive delete, so don't follow the rid. 424 */ 425 if (rid && rid != fid) { 426 /* Destroy the flow associated with the shared flow id */ 427 if (ulp_mapper_flow_destroy(ulp_ctx, BNXT_ULP_FDB_TYPE_RID, 428 rid, NULL)) 429 BNXT_DRV_DBG(ERR, 430 "Error in deleting shared resource id %x\n", 431 rid); 432 } 433 434 /* Delete the entry from the hash table */ 435 if (gen_tbl_list->hash_tbl) 436 ulp_gen_hash_tbl_list_del(gen_tbl_list->hash_tbl, &hash_entry); 437 438 /* decrement the count */ 439 if (gen_tbl_list->tbl_type == BNXT_ULP_GEN_TBL_TYPE_SIMPLE_LIST && 440 gen_tbl_list->container.seq_cnt > 0) 441 gen_tbl_list->container.seq_cnt--; 442 443 /* clear the byte data of the generic table entry */ 444 memset(entry.byte_data, 0, entry.byte_data_size); 445 446 return 0; 447 } 448 449 /* 450 * Write the generic table list hash entry 451 * 452 * tbl_list [in] - pointer to the generic table list 453 * hash_entry [in] - Hash table entry 454 * gen_tbl_ent [out] - generic table entry 455 * 456 * returns 0 on success. 457 */ 458 int32_t 459 ulp_mapper_gen_tbl_hash_entry_add(struct ulp_mapper_gen_tbl_list *tbl_list, 460 struct ulp_gen_hash_entry_params *hash_entry, 461 struct ulp_mapper_gen_tbl_entry *gen_tbl_ent) 462 { 463 uint32_t key; 464 int32_t rc = 0; 465 466 switch (hash_entry->search_flag) { 467 case ULP_GEN_HASH_SEARCH_FOUND: 468 BNXT_DRV_DBG(ERR, "%s: gen hash entry already present\n", 469 tbl_list->gen_tbl_name); 470 return -EINVAL; 471 case ULP_GEN_HASH_SEARCH_FULL: 472 BNXT_DRV_DBG(ERR, "%s: gen hash table is full\n", 473 tbl_list->gen_tbl_name); 474 return -EINVAL; 475 case ULP_GEN_HASH_SEARCH_MISSED: 476 rc = ulp_gen_hash_tbl_list_add(tbl_list->hash_tbl, hash_entry); 477 if (rc) { 478 BNXT_DRV_DBG(ERR, "%s: gen hash table add failed\n", 479 tbl_list->gen_tbl_name); 480 return -EINVAL; 481 } 482 key = hash_entry->key_idx; 483 gen_tbl_ent->ref_count = &tbl_list->container.ref_count[key]; 484 gen_tbl_ent->byte_data_size = 485 tbl_list->container.byte_data_size; 486 gen_tbl_ent->byte_data = &tbl_list->container.byte_data[key * 487 gen_tbl_ent->byte_data_size]; 488 gen_tbl_ent->byte_order = tbl_list->container.byte_order; 489 break; 490 default: 491 BNXT_DRV_DBG(ERR, "%s: invalid search flag\n", 492 tbl_list->gen_tbl_name); 493 return -EINVAL; 494 } 495 496 return rc; 497 } 498 499 /* 500 * Perform add entry in the simple list 501 * 502 * tbl_list [in] - pointer to the generic table list 503 * key [in] - Key added as index 504 * data [in] - data added as result 505 * key_index [out] - index to the entry 506 * gen_tbl_ent [out] - write the output to the entry 507 * 508 * returns 0 on success. 509 */ 510 int32_t 511 ulp_gen_tbl_simple_list_add_entry(struct ulp_mapper_gen_tbl_list *tbl_list, 512 uint8_t *key, 513 uint8_t *data, 514 uint32_t *key_index, 515 struct ulp_mapper_gen_tbl_entry *ent) 516 { 517 struct ulp_mapper_gen_tbl_cont *cont; 518 uint32_t key_size, idx; 519 uint8_t *entry_key; 520 521 /* sequentially search for the matching key */ 522 cont = &tbl_list->container; 523 for (idx = 0; idx < cont->num_elem; idx++) { 524 ent->ref_count = &cont->ref_count[idx]; 525 if (ULP_GEN_TBL_REF_CNT(ent) == 0) { 526 /* add the entry */ 527 key_size = cont->byte_key_ex_size + 528 cont->byte_key_par_size; 529 entry_key = &cont->byte_key[idx * key_size]; 530 ent->byte_data_size = cont->byte_data_size; 531 ent->byte_data = &cont->byte_data[idx * 532 cont->byte_data_size]; 533 memcpy(entry_key, key, key_size); 534 memcpy(ent->byte_data, data, ent->byte_data_size); 535 ent->byte_order = cont->byte_order; 536 *key_index = idx; 537 cont->seq_cnt++; 538 return 0; 539 } 540 } 541 /* No more memory */ 542 return -ENOMEM; 543 } 544 545 /* perform the subset and superset. len should be 64bit multiple*/ 546 static enum ulp_gen_list_search_flag 547 ulp_gen_tbl_overlap_check(uint8_t *key1, uint8_t *key2, uint32_t len) 548 { 549 uint32_t sz = 0, superset = 0, subset = 0; 550 uint64_t src, dst; 551 552 while (sz < len) { 553 memcpy(&dst, key2, sizeof(dst)); 554 memcpy(&src, key1, sizeof(src)); 555 sz += sizeof(src); 556 if (dst == src) 557 continue; 558 else if (dst == (dst | src)) 559 superset = 1; 560 else if (src == (dst | src)) 561 subset = 1; 562 else 563 return ULP_GEN_LIST_SEARCH_MISSED; 564 } 565 if (superset && !subset) 566 return ULP_GEN_LIST_SEARCH_FOUND_SUPERSET; 567 if (!superset && subset) 568 return ULP_GEN_LIST_SEARCH_FOUND_SUBSET; 569 return ULP_GEN_LIST_SEARCH_FOUND; 570 } 571 572 uint32_t 573 ulp_gen_tbl_simple_list_search(struct ulp_mapper_gen_tbl_list *tbl_list, 574 uint8_t *match_key, 575 uint32_t *key_idx) 576 { 577 enum ulp_gen_list_search_flag rc = ULP_GEN_LIST_SEARCH_FULL; 578 uint32_t idx = 0, key_idx_set = 0, sz = 0, key_size = 0; 579 struct ulp_mapper_gen_tbl_entry ent = { 0 }; 580 struct ulp_mapper_gen_tbl_cont *cont = &tbl_list->container; 581 uint8_t *k1 = NULL, *k2, *entry_key; 582 uint32_t valid_ent = 0; 583 584 key_size = cont->byte_key_ex_size + cont->byte_key_par_size; 585 if (cont->byte_key_par_size) 586 k1 = match_key + cont->byte_key_ex_size; 587 588 /* sequentially search for the matching key */ 589 while (idx < cont->num_elem) { 590 ent.ref_count = &cont->ref_count[idx]; 591 entry_key = &cont->byte_key[idx * key_size]; 592 /* check ref count not zero and exact key matches */ 593 if (ULP_GEN_TBL_REF_CNT(&ent)) { 594 /* compare the exact match */ 595 if (!memcmp(match_key, entry_key, 596 cont->byte_key_ex_size)) { 597 /* Match the partial key*/ 598 if (cont->byte_key_par_size) { 599 k2 = entry_key + cont->byte_key_ex_size; 600 sz = cont->byte_key_par_size; 601 rc = ulp_gen_tbl_overlap_check(k1, k2, 602 sz); 603 if (rc != ULP_GEN_LIST_SEARCH_MISSED) { 604 *key_idx = idx; 605 return rc; 606 } 607 } else { 608 /* found the entry return */ 609 rc = ULP_GEN_LIST_SEARCH_FOUND; 610 *key_idx = idx; 611 return rc; 612 } 613 } 614 ++valid_ent; 615 } else { 616 /* empty slot */ 617 if (!key_idx_set) { 618 *key_idx = idx; 619 key_idx_set = 1; 620 rc = ULP_GEN_LIST_SEARCH_MISSED; 621 } 622 if (valid_ent >= cont->seq_cnt) 623 return rc; 624 } 625 idx++; 626 } 627 return rc; 628 } 629