1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause OR GPL-2.0 3 * 4 * Copyright (c) 2004, 2005 Mellanox Technologies Ltd. All rights reserved. 5 * Copyright (c) 2004, 2005 Infinicon Corporation. All rights reserved. 6 * Copyright (c) 2004, 2005 Intel Corporation. All rights reserved. 7 * Copyright (c) 2004, 2005 Topspin Corporation. All rights reserved. 8 * Copyright (c) 2004-2007 Voltaire Corporation. All rights reserved. 9 * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved. 10 * Copyright (c) 2014 Intel Corporation. All rights reserved. 11 * 12 * This software is available to you under a choice of one of two 13 * licenses. You may choose to be licensed under the terms of the GNU 14 * General Public License (GPL) Version 2, available from the file 15 * COPYING in the main directory of this source tree, or the 16 * OpenIB.org BSD license below: 17 * 18 * Redistribution and use in source and binary forms, with or 19 * without modification, are permitted provided that the following 20 * conditions are met: 21 * 22 * - Redistributions of source code must retain the above 23 * copyright notice, this list of conditions and the following 24 * disclaimer. 25 * 26 * - Redistributions in binary form must reproduce the above 27 * copyright notice, this list of conditions and the following 28 * disclaimer in the documentation and/or other materials 29 * provided with the distribution. 30 * 31 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 32 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 33 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 34 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 35 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 36 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 37 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 38 * SOFTWARE. 39 */ 40 41 #include <sys/cdefs.h> 42 __FBSDID("$FreeBSD$"); 43 44 #include <rdma/ib_smi.h> 45 #include "smi.h" 46 #include "opa_smi.h" 47 48 static enum smi_action __smi_handle_dr_smp_send(bool is_switch, int port_num, 49 u8 *hop_ptr, u8 hop_cnt, 50 const u8 *initial_path, 51 const u8 *return_path, 52 u8 direction, 53 bool dr_dlid_is_permissive, 54 bool dr_slid_is_permissive) 55 { 56 /* See section 14.2.2.2, Vol 1 IB spec */ 57 /* C14-6 -- valid hop_cnt values are from 0 to 63 */ 58 if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) 59 return IB_SMI_DISCARD; 60 61 if (!direction) { 62 /* C14-9:1 */ 63 if (hop_cnt && *hop_ptr == 0) { 64 (*hop_ptr)++; 65 return (initial_path[*hop_ptr] == 66 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 67 } 68 69 /* C14-9:2 */ 70 if (*hop_ptr && *hop_ptr < hop_cnt) { 71 if (!is_switch) 72 return IB_SMI_DISCARD; 73 74 /* return_path set when received */ 75 (*hop_ptr)++; 76 return (initial_path[*hop_ptr] == 77 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 78 } 79 80 /* C14-9:3 -- We're at the end of the DR segment of path */ 81 if (*hop_ptr == hop_cnt) { 82 /* return_path set when received */ 83 (*hop_ptr)++; 84 return (is_switch || 85 dr_dlid_is_permissive ? 86 IB_SMI_HANDLE : IB_SMI_DISCARD); 87 } 88 89 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 90 /* C14-9:5 -- Fail unreasonable hop pointer */ 91 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 92 93 } else { 94 /* C14-13:1 */ 95 if (hop_cnt && *hop_ptr == hop_cnt + 1) { 96 (*hop_ptr)--; 97 return (return_path[*hop_ptr] == 98 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 99 } 100 101 /* C14-13:2 */ 102 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { 103 if (!is_switch) 104 return IB_SMI_DISCARD; 105 106 (*hop_ptr)--; 107 return (return_path[*hop_ptr] == 108 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 109 } 110 111 /* C14-13:3 -- at the end of the DR segment of path */ 112 if (*hop_ptr == 1) { 113 (*hop_ptr)--; 114 /* C14-13:3 -- SMPs destined for SM shouldn't be here */ 115 return (is_switch || 116 dr_slid_is_permissive ? 117 IB_SMI_HANDLE : IB_SMI_DISCARD); 118 } 119 120 /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ 121 if (*hop_ptr == 0) 122 return IB_SMI_HANDLE; 123 124 /* C14-13:5 -- Check for unreasonable hop pointer */ 125 return IB_SMI_DISCARD; 126 } 127 } 128 129 /* 130 * Fixup a directed route SMP for sending 131 * Return IB_SMI_DISCARD if the SMP should be discarded 132 */ 133 enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, 134 bool is_switch, int port_num) 135 { 136 return __smi_handle_dr_smp_send(is_switch, port_num, 137 &smp->hop_ptr, smp->hop_cnt, 138 smp->initial_path, 139 smp->return_path, 140 ib_get_smp_direction(smp), 141 smp->dr_dlid == IB_LID_PERMISSIVE, 142 smp->dr_slid == IB_LID_PERMISSIVE); 143 } 144 145 enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp, 146 bool is_switch, int port_num) 147 { 148 return __smi_handle_dr_smp_send(is_switch, port_num, 149 &smp->hop_ptr, smp->hop_cnt, 150 smp->route.dr.initial_path, 151 smp->route.dr.return_path, 152 opa_get_smp_direction(smp), 153 smp->route.dr.dr_dlid == 154 OPA_LID_PERMISSIVE, 155 smp->route.dr.dr_slid == 156 OPA_LID_PERMISSIVE); 157 } 158 159 static enum smi_action __smi_handle_dr_smp_recv(bool is_switch, int port_num, 160 int phys_port_cnt, 161 u8 *hop_ptr, u8 hop_cnt, 162 const u8 *initial_path, 163 u8 *return_path, 164 u8 direction, 165 bool dr_dlid_is_permissive, 166 bool dr_slid_is_permissive) 167 { 168 /* See section 14.2.2.2, Vol 1 IB spec */ 169 /* C14-6 -- valid hop_cnt values are from 0 to 63 */ 170 if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) 171 return IB_SMI_DISCARD; 172 173 if (!direction) { 174 /* C14-9:1 -- sender should have incremented hop_ptr */ 175 if (hop_cnt && *hop_ptr == 0) 176 return IB_SMI_DISCARD; 177 178 /* C14-9:2 -- intermediate hop */ 179 if (*hop_ptr && *hop_ptr < hop_cnt) { 180 if (!is_switch) 181 return IB_SMI_DISCARD; 182 183 return_path[*hop_ptr] = port_num; 184 /* hop_ptr updated when sending */ 185 return (initial_path[*hop_ptr+1] <= phys_port_cnt ? 186 IB_SMI_HANDLE : IB_SMI_DISCARD); 187 } 188 189 /* C14-9:3 -- We're at the end of the DR segment of path */ 190 if (*hop_ptr == hop_cnt) { 191 if (hop_cnt) 192 return_path[*hop_ptr] = port_num; 193 /* hop_ptr updated when sending */ 194 195 return (is_switch || 196 dr_dlid_is_permissive ? 197 IB_SMI_HANDLE : IB_SMI_DISCARD); 198 } 199 200 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 201 /* C14-9:5 -- fail unreasonable hop pointer */ 202 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 203 204 } else { 205 206 /* C14-13:1 */ 207 if (hop_cnt && *hop_ptr == hop_cnt + 1) { 208 (*hop_ptr)--; 209 return (return_path[*hop_ptr] == 210 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 211 } 212 213 /* C14-13:2 */ 214 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { 215 if (!is_switch) 216 return IB_SMI_DISCARD; 217 218 /* hop_ptr updated when sending */ 219 return (return_path[*hop_ptr-1] <= phys_port_cnt ? 220 IB_SMI_HANDLE : IB_SMI_DISCARD); 221 } 222 223 /* C14-13:3 -- We're at the end of the DR segment of path */ 224 if (*hop_ptr == 1) { 225 if (dr_slid_is_permissive) { 226 /* giving SMP to SM - update hop_ptr */ 227 (*hop_ptr)--; 228 return IB_SMI_HANDLE; 229 } 230 /* hop_ptr updated when sending */ 231 return (is_switch ? IB_SMI_HANDLE : IB_SMI_DISCARD); 232 } 233 234 /* C14-13:4 -- hop_ptr = 0 -> give to SM */ 235 /* C14-13:5 -- Check for unreasonable hop pointer */ 236 return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 237 } 238 } 239 240 /* 241 * Adjust information for a received SMP 242 * Return IB_SMI_DISCARD if the SMP should be dropped 243 */ 244 enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch, 245 int port_num, int phys_port_cnt) 246 { 247 return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, 248 &smp->hop_ptr, smp->hop_cnt, 249 smp->initial_path, 250 smp->return_path, 251 ib_get_smp_direction(smp), 252 smp->dr_dlid == IB_LID_PERMISSIVE, 253 smp->dr_slid == IB_LID_PERMISSIVE); 254 } 255 256 /* 257 * Adjust information for a received SMP 258 * Return IB_SMI_DISCARD if the SMP should be dropped 259 */ 260 enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch, 261 int port_num, int phys_port_cnt) 262 { 263 return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, 264 &smp->hop_ptr, smp->hop_cnt, 265 smp->route.dr.initial_path, 266 smp->route.dr.return_path, 267 opa_get_smp_direction(smp), 268 smp->route.dr.dr_dlid == 269 OPA_LID_PERMISSIVE, 270 smp->route.dr.dr_slid == 271 OPA_LID_PERMISSIVE); 272 } 273 274 static enum smi_forward_action __smi_check_forward_dr_smp(u8 hop_ptr, u8 hop_cnt, 275 u8 direction, 276 bool dr_dlid_is_permissive, 277 bool dr_slid_is_permissive) 278 { 279 if (!direction) { 280 /* C14-9:2 -- intermediate hop */ 281 if (hop_ptr && hop_ptr < hop_cnt) 282 return IB_SMI_FORWARD; 283 284 /* C14-9:3 -- at the end of the DR segment of path */ 285 if (hop_ptr == hop_cnt) 286 return (dr_dlid_is_permissive ? 287 IB_SMI_SEND : IB_SMI_LOCAL); 288 289 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 290 if (hop_ptr == hop_cnt + 1) 291 return IB_SMI_SEND; 292 } else { 293 /* C14-13:2 -- intermediate hop */ 294 if (2 <= hop_ptr && hop_ptr <= hop_cnt) 295 return IB_SMI_FORWARD; 296 297 /* C14-13:3 -- at the end of the DR segment of path */ 298 if (hop_ptr == 1) 299 return (!dr_slid_is_permissive ? 300 IB_SMI_SEND : IB_SMI_LOCAL); 301 } 302 return IB_SMI_LOCAL; 303 304 } 305 306 enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) 307 { 308 return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, 309 ib_get_smp_direction(smp), 310 smp->dr_dlid == IB_LID_PERMISSIVE, 311 smp->dr_slid == IB_LID_PERMISSIVE); 312 } 313 314 enum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp) 315 { 316 return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, 317 opa_get_smp_direction(smp), 318 smp->route.dr.dr_dlid == 319 OPA_LID_PERMISSIVE, 320 smp->route.dr.dr_slid == 321 OPA_LID_PERMISSIVE); 322 } 323 324 /* 325 * Return the forwarding port number from initial_path for outgoing SMP and 326 * from return_path for returning SMP 327 */ 328 int smi_get_fwd_port(struct ib_smp *smp) 329 { 330 return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] : 331 smp->return_path[smp->hop_ptr-1]); 332 } 333 334 /* 335 * Return the forwarding port number from initial_path for outgoing SMP and 336 * from return_path for returning SMP 337 */ 338 int opa_smi_get_fwd_port(struct opa_smp *smp) 339 { 340 return !opa_get_smp_direction(smp) ? smp->route.dr.initial_path[smp->hop_ptr+1] : 341 smp->route.dr.return_path[smp->hop_ptr-1]; 342 } 343