1219820Sjeff/* 2219820Sjeff * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. 3219820Sjeff * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 4219820Sjeff * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 5219820Sjeff * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 6219820Sjeff * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. 7219820Sjeff * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 8219820Sjeff * 9219820Sjeff * This software is available to you under a choice of one of two 10219820Sjeff * licenses. You may choose to be licensed under the terms of the GNU 11219820Sjeff * General Public License (GPL) Version 2, available from the file 12219820Sjeff * COPYING in the main directory of this source tree, or the 13219820Sjeff * OpenIB.org BSD license below: 14219820Sjeff * 15219820Sjeff * Redistribution and use in source and binary forms, with or 16219820Sjeff * without modification, are permitted provided that the following 17219820Sjeff * conditions are met: 18219820Sjeff * 19219820Sjeff * - Redistributions of source code must retain the above 20219820Sjeff * copyright notice, this list of conditions and the following 21219820Sjeff * disclaimer. 22219820Sjeff * 23219820Sjeff * - Redistributions in binary form must reproduce the above 24219820Sjeff * copyright notice, this list of conditions and the following 25219820Sjeff * disclaimer in the documentation and/or other materials 26219820Sjeff * provided with the distribution. 27219820Sjeff * 28219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 31219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 32219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 33219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35219820Sjeff * SOFTWARE. 36219820Sjeff * 37219820Sjeff */ 38219820Sjeff 39219820Sjeff#include <rdma/ib_smi.h> 40219820Sjeff#include "smi.h" 41219820Sjeff 42219820Sjeff/* 43219820Sjeff * Fixup a directed route SMP for sending 44219820Sjeff * Return 0 if the SMP should be discarded 45219820Sjeff */ 46219820Sjeffenum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, 47219820Sjeff u8 node_type, int port_num) 48219820Sjeff{ 49219820Sjeff u8 hop_ptr, hop_cnt; 50219820Sjeff 51219820Sjeff hop_ptr = smp->hop_ptr; 52219820Sjeff hop_cnt = smp->hop_cnt; 53219820Sjeff 54219820Sjeff /* See section 14.2.2.2, Vol 1 IB spec */ 55219820Sjeff if (!ib_get_smp_direction(smp)) { 56219820Sjeff /* C14-9:1 */ 57219820Sjeff if (hop_cnt && hop_ptr == 0) { 58219820Sjeff smp->hop_ptr++; 59219820Sjeff return (smp->initial_path[smp->hop_ptr] == 60219820Sjeff port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 61219820Sjeff } 62219820Sjeff 63219820Sjeff /* C14-9:2 */ 64219820Sjeff if (hop_ptr && hop_ptr < hop_cnt) { 65219820Sjeff if (node_type != RDMA_NODE_IB_SWITCH) 66219820Sjeff return IB_SMI_DISCARD; 67219820Sjeff 68219820Sjeff /* smp->return_path set when received */ 69219820Sjeff smp->hop_ptr++; 70219820Sjeff return (smp->initial_path[smp->hop_ptr] == 71219820Sjeff port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 72219820Sjeff } 73219820Sjeff 74219820Sjeff /* C14-9:3 -- We're at the end of the DR segment of path */ 75219820Sjeff if (hop_ptr == hop_cnt) { 76219820Sjeff /* smp->return_path set when received */ 77219820Sjeff smp->hop_ptr++; 78219820Sjeff return (node_type == RDMA_NODE_IB_SWITCH || 79219820Sjeff smp->dr_dlid == IB_LID_PERMISSIVE ? 80219820Sjeff IB_SMI_HANDLE : IB_SMI_DISCARD); 81219820Sjeff } 82219820Sjeff 83219820Sjeff /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 84219820Sjeff /* C14-9:5 -- Fail unreasonable hop pointer */ 85219820Sjeff return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 86219820Sjeff 87219820Sjeff } else { 88219820Sjeff /* C14-13:1 */ 89219820Sjeff if (hop_cnt && hop_ptr == hop_cnt + 1) { 90219820Sjeff smp->hop_ptr--; 91219820Sjeff return (smp->return_path[smp->hop_ptr] == 92219820Sjeff port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 93219820Sjeff } 94219820Sjeff 95219820Sjeff /* C14-13:2 */ 96219820Sjeff if (2 <= hop_ptr && hop_ptr <= hop_cnt) { 97219820Sjeff if (node_type != RDMA_NODE_IB_SWITCH) 98219820Sjeff return IB_SMI_DISCARD; 99219820Sjeff 100219820Sjeff smp->hop_ptr--; 101219820Sjeff return (smp->return_path[smp->hop_ptr] == 102219820Sjeff port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 103219820Sjeff } 104219820Sjeff 105219820Sjeff /* C14-13:3 -- at the end of the DR segment of path */ 106219820Sjeff if (hop_ptr == 1) { 107219820Sjeff smp->hop_ptr--; 108219820Sjeff /* C14-13:3 -- SMPs destined for SM shouldn't be here */ 109219820Sjeff return (node_type == RDMA_NODE_IB_SWITCH || 110219820Sjeff smp->dr_slid == IB_LID_PERMISSIVE ? 111219820Sjeff IB_SMI_HANDLE : IB_SMI_DISCARD); 112219820Sjeff } 113219820Sjeff 114219820Sjeff /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ 115219820Sjeff if (hop_ptr == 0) 116219820Sjeff return IB_SMI_HANDLE; 117219820Sjeff 118219820Sjeff /* C14-13:5 -- Check for unreasonable hop pointer */ 119219820Sjeff return IB_SMI_DISCARD; 120219820Sjeff } 121219820Sjeff} 122219820Sjeff 123219820Sjeff/* 124219820Sjeff * Adjust information for a received SMP 125219820Sjeff * Return 0 if the SMP should be dropped 126219820Sjeff */ 127219820Sjeffenum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, u8 node_type, 128219820Sjeff int port_num, int phys_port_cnt) 129219820Sjeff{ 130219820Sjeff u8 hop_ptr, hop_cnt; 131219820Sjeff 132219820Sjeff hop_ptr = smp->hop_ptr; 133219820Sjeff hop_cnt = smp->hop_cnt; 134219820Sjeff 135219820Sjeff /* See section 14.2.2.2, Vol 1 IB spec */ 136219820Sjeff if (!ib_get_smp_direction(smp)) { 137219820Sjeff /* C14-9:1 -- sender should have incremented hop_ptr */ 138219820Sjeff if (hop_cnt && hop_ptr == 0) 139219820Sjeff return IB_SMI_DISCARD; 140219820Sjeff 141219820Sjeff /* C14-9:2 -- intermediate hop */ 142219820Sjeff if (hop_ptr && hop_ptr < hop_cnt) { 143219820Sjeff if (node_type != RDMA_NODE_IB_SWITCH) 144219820Sjeff return IB_SMI_DISCARD; 145219820Sjeff 146219820Sjeff smp->return_path[hop_ptr] = port_num; 147219820Sjeff /* smp->hop_ptr updated when sending */ 148219820Sjeff return (smp->initial_path[hop_ptr+1] <= phys_port_cnt ? 149219820Sjeff IB_SMI_HANDLE : IB_SMI_DISCARD); 150219820Sjeff } 151219820Sjeff 152219820Sjeff /* C14-9:3 -- We're at the end of the DR segment of path */ 153219820Sjeff if (hop_ptr == hop_cnt) { 154219820Sjeff if (hop_cnt) 155219820Sjeff smp->return_path[hop_ptr] = port_num; 156219820Sjeff /* smp->hop_ptr updated when sending */ 157219820Sjeff 158219820Sjeff return (node_type == RDMA_NODE_IB_SWITCH || 159219820Sjeff smp->dr_dlid == IB_LID_PERMISSIVE ? 160219820Sjeff IB_SMI_HANDLE : IB_SMI_DISCARD); 161219820Sjeff } 162219820Sjeff 163219820Sjeff /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 164219820Sjeff /* C14-9:5 -- fail unreasonable hop pointer */ 165219820Sjeff return (hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 166219820Sjeff 167219820Sjeff } else { 168219820Sjeff 169219820Sjeff /* C14-13:1 */ 170219820Sjeff if (hop_cnt && hop_ptr == hop_cnt + 1) { 171219820Sjeff smp->hop_ptr--; 172219820Sjeff return (smp->return_path[smp->hop_ptr] == 173219820Sjeff port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 174219820Sjeff } 175219820Sjeff 176219820Sjeff /* C14-13:2 */ 177219820Sjeff if (2 <= hop_ptr && hop_ptr <= hop_cnt) { 178219820Sjeff if (node_type != RDMA_NODE_IB_SWITCH) 179219820Sjeff return IB_SMI_DISCARD; 180219820Sjeff 181219820Sjeff /* smp->hop_ptr updated when sending */ 182219820Sjeff return (smp->return_path[hop_ptr-1] <= phys_port_cnt ? 183219820Sjeff IB_SMI_HANDLE : IB_SMI_DISCARD); 184219820Sjeff } 185219820Sjeff 186219820Sjeff /* C14-13:3 -- We're at the end of the DR segment of path */ 187219820Sjeff if (hop_ptr == 1) { 188219820Sjeff if (smp->dr_slid == IB_LID_PERMISSIVE) { 189219820Sjeff /* giving SMP to SM - update hop_ptr */ 190219820Sjeff smp->hop_ptr--; 191219820Sjeff return IB_SMI_HANDLE; 192219820Sjeff } 193219820Sjeff /* smp->hop_ptr updated when sending */ 194219820Sjeff return (node_type == RDMA_NODE_IB_SWITCH ? 195219820Sjeff IB_SMI_HANDLE : IB_SMI_DISCARD); 196219820Sjeff } 197219820Sjeff 198219820Sjeff /* C14-13:4 -- hop_ptr = 0 -> give to SM */ 199219820Sjeff /* C14-13:5 -- Check for unreasonable hop pointer */ 200219820Sjeff return (hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 201219820Sjeff } 202219820Sjeff} 203219820Sjeff 204219820Sjeffenum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) 205219820Sjeff{ 206219820Sjeff u8 hop_ptr, hop_cnt; 207219820Sjeff 208219820Sjeff hop_ptr = smp->hop_ptr; 209219820Sjeff hop_cnt = smp->hop_cnt; 210219820Sjeff 211219820Sjeff if (!ib_get_smp_direction(smp)) { 212219820Sjeff /* C14-9:2 -- intermediate hop */ 213219820Sjeff if (hop_ptr && hop_ptr < hop_cnt) 214219820Sjeff return IB_SMI_FORWARD; 215219820Sjeff 216219820Sjeff /* C14-9:3 -- at the end of the DR segment of path */ 217219820Sjeff if (hop_ptr == hop_cnt) 218219820Sjeff return (smp->dr_dlid == IB_LID_PERMISSIVE ? 219219820Sjeff IB_SMI_SEND : IB_SMI_LOCAL); 220219820Sjeff 221219820Sjeff /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 222219820Sjeff if (hop_ptr == hop_cnt + 1) 223219820Sjeff return IB_SMI_SEND; 224219820Sjeff } else { 225219820Sjeff /* C14-13:2 -- intermediate hop */ 226219820Sjeff if (2 <= hop_ptr && hop_ptr <= hop_cnt) 227219820Sjeff return IB_SMI_FORWARD; 228219820Sjeff 229219820Sjeff /* C14-13:3 -- at the end of the DR segment of path */ 230219820Sjeff if (hop_ptr == 1) 231219820Sjeff return (smp->dr_slid != IB_LID_PERMISSIVE ? 232219820Sjeff IB_SMI_SEND : IB_SMI_LOCAL); 233219820Sjeff } 234219820Sjeff return IB_SMI_LOCAL; 235219820Sjeff} 236219820Sjeff 237219820Sjeff/* 238219820Sjeff * Return the forwarding port number from initial_path for outgoing SMP and 239219820Sjeff * from return_path for returning SMP 240219820Sjeff */ 241219820Sjeffint smi_get_fwd_port(struct ib_smp *smp) 242219820Sjeff{ 243219820Sjeff return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] : 244219820Sjeff smp->return_path[smp->hop_ptr-1]); 245219820Sjeff} 246