162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 562306a36Sopenharmony_ci * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 662306a36Sopenharmony_ci * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. 762306a36Sopenharmony_ci * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 862306a36Sopenharmony_ci * Copyright (c) 2014 Intel Corporation. All rights reserved. 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * This software is available to you under a choice of one of two 1162306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 1262306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 1362306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1462306a36Sopenharmony_ci * OpenIB.org BSD license below: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1762306a36Sopenharmony_ci * without modification, are permitted provided that the following 1862306a36Sopenharmony_ci * conditions are met: 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions of source code must retain the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer. 2362306a36Sopenharmony_ci * 2462306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2662306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2762306a36Sopenharmony_ci * provided with the distribution. 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 3062306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 3162306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 3262306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 3362306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3462306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3562306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3662306a36Sopenharmony_ci * SOFTWARE. 3762306a36Sopenharmony_ci * 3862306a36Sopenharmony_ci */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci#include <rdma/ib_smi.h> 4162306a36Sopenharmony_ci#include "smi.h" 4262306a36Sopenharmony_ci#include "opa_smi.h" 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_cistatic enum smi_action __smi_handle_dr_smp_send(bool is_switch, u32 port_num, 4562306a36Sopenharmony_ci u8 *hop_ptr, u8 hop_cnt, 4662306a36Sopenharmony_ci const u8 *initial_path, 4762306a36Sopenharmony_ci const u8 *return_path, 4862306a36Sopenharmony_ci u8 direction, 4962306a36Sopenharmony_ci bool dr_dlid_is_permissive, 5062306a36Sopenharmony_ci bool dr_slid_is_permissive) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci /* See section 14.2.2.2, Vol 1 IB spec */ 5362306a36Sopenharmony_ci /* C14-6 -- valid hop_cnt values are from 0 to 63 */ 5462306a36Sopenharmony_ci if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) 5562306a36Sopenharmony_ci return IB_SMI_DISCARD; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (!direction) { 5862306a36Sopenharmony_ci /* C14-9:1 */ 5962306a36Sopenharmony_ci if (hop_cnt && *hop_ptr == 0) { 6062306a36Sopenharmony_ci (*hop_ptr)++; 6162306a36Sopenharmony_ci return (initial_path[*hop_ptr] == 6262306a36Sopenharmony_ci port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 6362306a36Sopenharmony_ci } 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* C14-9:2 */ 6662306a36Sopenharmony_ci if (*hop_ptr && *hop_ptr < hop_cnt) { 6762306a36Sopenharmony_ci if (!is_switch) 6862306a36Sopenharmony_ci return IB_SMI_DISCARD; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* return_path set when received */ 7162306a36Sopenharmony_ci (*hop_ptr)++; 7262306a36Sopenharmony_ci return (initial_path[*hop_ptr] == 7362306a36Sopenharmony_ci port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci /* C14-9:3 -- We're at the end of the DR segment of path */ 7762306a36Sopenharmony_ci if (*hop_ptr == hop_cnt) { 7862306a36Sopenharmony_ci /* return_path set when received */ 7962306a36Sopenharmony_ci (*hop_ptr)++; 8062306a36Sopenharmony_ci return (is_switch || 8162306a36Sopenharmony_ci dr_dlid_is_permissive ? 8262306a36Sopenharmony_ci IB_SMI_HANDLE : IB_SMI_DISCARD); 8362306a36Sopenharmony_ci } 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 8662306a36Sopenharmony_ci /* C14-9:5 -- Fail unreasonable hop pointer */ 8762306a36Sopenharmony_ci return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci } else { 9062306a36Sopenharmony_ci /* C14-13:1 */ 9162306a36Sopenharmony_ci if (hop_cnt && *hop_ptr == hop_cnt + 1) { 9262306a36Sopenharmony_ci (*hop_ptr)--; 9362306a36Sopenharmony_ci return (return_path[*hop_ptr] == 9462306a36Sopenharmony_ci port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 9562306a36Sopenharmony_ci } 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* C14-13:2 */ 9862306a36Sopenharmony_ci if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { 9962306a36Sopenharmony_ci if (!is_switch) 10062306a36Sopenharmony_ci return IB_SMI_DISCARD; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci (*hop_ptr)--; 10362306a36Sopenharmony_ci return (return_path[*hop_ptr] == 10462306a36Sopenharmony_ci port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* C14-13:3 -- at the end of the DR segment of path */ 10862306a36Sopenharmony_ci if (*hop_ptr == 1) { 10962306a36Sopenharmony_ci (*hop_ptr)--; 11062306a36Sopenharmony_ci /* C14-13:3 -- SMPs destined for SM shouldn't be here */ 11162306a36Sopenharmony_ci return (is_switch || 11262306a36Sopenharmony_ci dr_slid_is_permissive ? 11362306a36Sopenharmony_ci IB_SMI_HANDLE : IB_SMI_DISCARD); 11462306a36Sopenharmony_ci } 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ 11762306a36Sopenharmony_ci if (*hop_ptr == 0) 11862306a36Sopenharmony_ci return IB_SMI_HANDLE; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* C14-13:5 -- Check for unreasonable hop pointer */ 12162306a36Sopenharmony_ci return IB_SMI_DISCARD; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci/* 12662306a36Sopenharmony_ci * Fixup a directed route SMP for sending 12762306a36Sopenharmony_ci * Return IB_SMI_DISCARD if the SMP should be discarded 12862306a36Sopenharmony_ci */ 12962306a36Sopenharmony_cienum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, 13062306a36Sopenharmony_ci bool is_switch, u32 port_num) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci return __smi_handle_dr_smp_send(is_switch, port_num, 13362306a36Sopenharmony_ci &smp->hop_ptr, smp->hop_cnt, 13462306a36Sopenharmony_ci smp->initial_path, 13562306a36Sopenharmony_ci smp->return_path, 13662306a36Sopenharmony_ci ib_get_smp_direction(smp), 13762306a36Sopenharmony_ci smp->dr_dlid == IB_LID_PERMISSIVE, 13862306a36Sopenharmony_ci smp->dr_slid == IB_LID_PERMISSIVE); 13962306a36Sopenharmony_ci} 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_cienum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp, 14262306a36Sopenharmony_ci bool is_switch, u32 port_num) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci return __smi_handle_dr_smp_send(is_switch, port_num, 14562306a36Sopenharmony_ci &smp->hop_ptr, smp->hop_cnt, 14662306a36Sopenharmony_ci smp->route.dr.initial_path, 14762306a36Sopenharmony_ci smp->route.dr.return_path, 14862306a36Sopenharmony_ci opa_get_smp_direction(smp), 14962306a36Sopenharmony_ci smp->route.dr.dr_dlid == 15062306a36Sopenharmony_ci OPA_LID_PERMISSIVE, 15162306a36Sopenharmony_ci smp->route.dr.dr_slid == 15262306a36Sopenharmony_ci OPA_LID_PERMISSIVE); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cistatic enum smi_action __smi_handle_dr_smp_recv(bool is_switch, u32 port_num, 15662306a36Sopenharmony_ci int phys_port_cnt, 15762306a36Sopenharmony_ci u8 *hop_ptr, u8 hop_cnt, 15862306a36Sopenharmony_ci const u8 *initial_path, 15962306a36Sopenharmony_ci u8 *return_path, 16062306a36Sopenharmony_ci u8 direction, 16162306a36Sopenharmony_ci bool dr_dlid_is_permissive, 16262306a36Sopenharmony_ci bool dr_slid_is_permissive) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci /* See section 14.2.2.2, Vol 1 IB spec */ 16562306a36Sopenharmony_ci /* C14-6 -- valid hop_cnt values are from 0 to 63 */ 16662306a36Sopenharmony_ci if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) 16762306a36Sopenharmony_ci return IB_SMI_DISCARD; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (!direction) { 17062306a36Sopenharmony_ci /* C14-9:1 -- sender should have incremented hop_ptr */ 17162306a36Sopenharmony_ci if (hop_cnt && *hop_ptr == 0) 17262306a36Sopenharmony_ci return IB_SMI_DISCARD; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci /* C14-9:2 -- intermediate hop */ 17562306a36Sopenharmony_ci if (*hop_ptr && *hop_ptr < hop_cnt) { 17662306a36Sopenharmony_ci if (!is_switch) 17762306a36Sopenharmony_ci return IB_SMI_DISCARD; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci return_path[*hop_ptr] = port_num; 18062306a36Sopenharmony_ci /* hop_ptr updated when sending */ 18162306a36Sopenharmony_ci return (initial_path[*hop_ptr+1] <= phys_port_cnt ? 18262306a36Sopenharmony_ci IB_SMI_HANDLE : IB_SMI_DISCARD); 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci /* C14-9:3 -- We're at the end of the DR segment of path */ 18662306a36Sopenharmony_ci if (*hop_ptr == hop_cnt) { 18762306a36Sopenharmony_ci if (hop_cnt) 18862306a36Sopenharmony_ci return_path[*hop_ptr] = port_num; 18962306a36Sopenharmony_ci /* hop_ptr updated when sending */ 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci return (is_switch || 19262306a36Sopenharmony_ci dr_dlid_is_permissive ? 19362306a36Sopenharmony_ci IB_SMI_HANDLE : IB_SMI_DISCARD); 19462306a36Sopenharmony_ci } 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_ci /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 19762306a36Sopenharmony_ci /* C14-9:5 -- fail unreasonable hop pointer */ 19862306a36Sopenharmony_ci return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci } else { 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci /* C14-13:1 */ 20362306a36Sopenharmony_ci if (hop_cnt && *hop_ptr == hop_cnt + 1) { 20462306a36Sopenharmony_ci (*hop_ptr)--; 20562306a36Sopenharmony_ci return (return_path[*hop_ptr] == 20662306a36Sopenharmony_ci port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci /* C14-13:2 */ 21062306a36Sopenharmony_ci if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { 21162306a36Sopenharmony_ci if (!is_switch) 21262306a36Sopenharmony_ci return IB_SMI_DISCARD; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci /* hop_ptr updated when sending */ 21562306a36Sopenharmony_ci return (return_path[*hop_ptr-1] <= phys_port_cnt ? 21662306a36Sopenharmony_ci IB_SMI_HANDLE : IB_SMI_DISCARD); 21762306a36Sopenharmony_ci } 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci /* C14-13:3 -- We're at the end of the DR segment of path */ 22062306a36Sopenharmony_ci if (*hop_ptr == 1) { 22162306a36Sopenharmony_ci if (dr_slid_is_permissive) { 22262306a36Sopenharmony_ci /* giving SMP to SM - update hop_ptr */ 22362306a36Sopenharmony_ci (*hop_ptr)--; 22462306a36Sopenharmony_ci return IB_SMI_HANDLE; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci /* hop_ptr updated when sending */ 22762306a36Sopenharmony_ci return (is_switch ? IB_SMI_HANDLE : IB_SMI_DISCARD); 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* C14-13:4 -- hop_ptr = 0 -> give to SM */ 23162306a36Sopenharmony_ci /* C14-13:5 -- Check for unreasonable hop pointer */ 23262306a36Sopenharmony_ci return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci/* 23762306a36Sopenharmony_ci * Adjust information for a received SMP 23862306a36Sopenharmony_ci * Return IB_SMI_DISCARD if the SMP should be dropped 23962306a36Sopenharmony_ci */ 24062306a36Sopenharmony_cienum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch, 24162306a36Sopenharmony_ci u32 port_num, int phys_port_cnt) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, 24462306a36Sopenharmony_ci &smp->hop_ptr, smp->hop_cnt, 24562306a36Sopenharmony_ci smp->initial_path, 24662306a36Sopenharmony_ci smp->return_path, 24762306a36Sopenharmony_ci ib_get_smp_direction(smp), 24862306a36Sopenharmony_ci smp->dr_dlid == IB_LID_PERMISSIVE, 24962306a36Sopenharmony_ci smp->dr_slid == IB_LID_PERMISSIVE); 25062306a36Sopenharmony_ci} 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci/* 25362306a36Sopenharmony_ci * Adjust information for a received SMP 25462306a36Sopenharmony_ci * Return IB_SMI_DISCARD if the SMP should be dropped 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_cienum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch, 25762306a36Sopenharmony_ci u32 port_num, int phys_port_cnt) 25862306a36Sopenharmony_ci{ 25962306a36Sopenharmony_ci return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, 26062306a36Sopenharmony_ci &smp->hop_ptr, smp->hop_cnt, 26162306a36Sopenharmony_ci smp->route.dr.initial_path, 26262306a36Sopenharmony_ci smp->route.dr.return_path, 26362306a36Sopenharmony_ci opa_get_smp_direction(smp), 26462306a36Sopenharmony_ci smp->route.dr.dr_dlid == 26562306a36Sopenharmony_ci OPA_LID_PERMISSIVE, 26662306a36Sopenharmony_ci smp->route.dr.dr_slid == 26762306a36Sopenharmony_ci OPA_LID_PERMISSIVE); 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic enum smi_forward_action __smi_check_forward_dr_smp(u8 hop_ptr, u8 hop_cnt, 27162306a36Sopenharmony_ci u8 direction, 27262306a36Sopenharmony_ci bool dr_dlid_is_permissive, 27362306a36Sopenharmony_ci bool dr_slid_is_permissive) 27462306a36Sopenharmony_ci{ 27562306a36Sopenharmony_ci if (!direction) { 27662306a36Sopenharmony_ci /* C14-9:2 -- intermediate hop */ 27762306a36Sopenharmony_ci if (hop_ptr && hop_ptr < hop_cnt) 27862306a36Sopenharmony_ci return IB_SMI_FORWARD; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* C14-9:3 -- at the end of the DR segment of path */ 28162306a36Sopenharmony_ci if (hop_ptr == hop_cnt) 28262306a36Sopenharmony_ci return (dr_dlid_is_permissive ? 28362306a36Sopenharmony_ci IB_SMI_SEND : IB_SMI_LOCAL); 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 28662306a36Sopenharmony_ci if (hop_ptr == hop_cnt + 1) 28762306a36Sopenharmony_ci return IB_SMI_SEND; 28862306a36Sopenharmony_ci } else { 28962306a36Sopenharmony_ci /* C14-13:2 -- intermediate hop */ 29062306a36Sopenharmony_ci if (2 <= hop_ptr && hop_ptr <= hop_cnt) 29162306a36Sopenharmony_ci return IB_SMI_FORWARD; 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci /* C14-13:3 -- at the end of the DR segment of path */ 29462306a36Sopenharmony_ci if (hop_ptr == 1) 29562306a36Sopenharmony_ci return (!dr_slid_is_permissive ? 29662306a36Sopenharmony_ci IB_SMI_SEND : IB_SMI_LOCAL); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci return IB_SMI_LOCAL; 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_ci} 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_cienum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) 30362306a36Sopenharmony_ci{ 30462306a36Sopenharmony_ci return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, 30562306a36Sopenharmony_ci ib_get_smp_direction(smp), 30662306a36Sopenharmony_ci smp->dr_dlid == IB_LID_PERMISSIVE, 30762306a36Sopenharmony_ci smp->dr_slid == IB_LID_PERMISSIVE); 30862306a36Sopenharmony_ci} 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_cienum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp) 31162306a36Sopenharmony_ci{ 31262306a36Sopenharmony_ci return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, 31362306a36Sopenharmony_ci opa_get_smp_direction(smp), 31462306a36Sopenharmony_ci smp->route.dr.dr_dlid == 31562306a36Sopenharmony_ci OPA_LID_PERMISSIVE, 31662306a36Sopenharmony_ci smp->route.dr.dr_slid == 31762306a36Sopenharmony_ci OPA_LID_PERMISSIVE); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci/* 32162306a36Sopenharmony_ci * Return the forwarding port number from initial_path for outgoing SMP and 32262306a36Sopenharmony_ci * from return_path for returning SMP 32362306a36Sopenharmony_ci */ 32462306a36Sopenharmony_ciint smi_get_fwd_port(struct ib_smp *smp) 32562306a36Sopenharmony_ci{ 32662306a36Sopenharmony_ci return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] : 32762306a36Sopenharmony_ci smp->return_path[smp->hop_ptr-1]); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/* 33162306a36Sopenharmony_ci * Return the forwarding port number from initial_path for outgoing SMP and 33262306a36Sopenharmony_ci * from return_path for returning SMP 33362306a36Sopenharmony_ci */ 33462306a36Sopenharmony_ciint opa_smi_get_fwd_port(struct opa_smp *smp) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci return !opa_get_smp_direction(smp) ? smp->route.dr.initial_path[smp->hop_ptr+1] : 33762306a36Sopenharmony_ci smp->route.dr.return_path[smp->hop_ptr-1]; 33862306a36Sopenharmony_ci} 339