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 #include <rdma/ib_smi.h> 43 #include "smi.h" 44 #include "opa_smi.h" 45 46 static enum smi_action __smi_handle_dr_smp_send(bool is_switch, int port_num, 47 u8 *hop_ptr, u8 hop_cnt, 48 const u8 *initial_path, 49 const u8 *return_path, 50 u8 direction, 51 bool dr_dlid_is_permissive, 52 bool dr_slid_is_permissive) 53 { 54 /* See section 14.2.2.2, Vol 1 IB spec */ 55 /* C14-6 -- valid hop_cnt values are from 0 to 63 */ 56 if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) 57 return IB_SMI_DISCARD; 58 59 if (!direction) { 60 /* C14-9:1 */ 61 if (hop_cnt && *hop_ptr == 0) { 62 (*hop_ptr)++; 63 return (initial_path[*hop_ptr] == 64 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 65 } 66 67 /* C14-9:2 */ 68 if (*hop_ptr && *hop_ptr < hop_cnt) { 69 if (!is_switch) 70 return IB_SMI_DISCARD; 71 72 /* return_path set when received */ 73 (*hop_ptr)++; 74 return (initial_path[*hop_ptr] == 75 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 76 } 77 78 /* C14-9:3 -- We're at the end of the DR segment of path */ 79 if (*hop_ptr == hop_cnt) { 80 /* return_path set when received */ 81 (*hop_ptr)++; 82 return (is_switch || 83 dr_dlid_is_permissive ? 84 IB_SMI_HANDLE : IB_SMI_DISCARD); 85 } 86 87 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 88 /* C14-9:5 -- Fail unreasonable hop pointer */ 89 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 90 91 } else { 92 /* C14-13:1 */ 93 if (hop_cnt && *hop_ptr == hop_cnt + 1) { 94 (*hop_ptr)--; 95 return (return_path[*hop_ptr] == 96 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 97 } 98 99 /* C14-13:2 */ 100 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { 101 if (!is_switch) 102 return IB_SMI_DISCARD; 103 104 (*hop_ptr)--; 105 return (return_path[*hop_ptr] == 106 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 107 } 108 109 /* C14-13:3 -- at the end of the DR segment of path */ 110 if (*hop_ptr == 1) { 111 (*hop_ptr)--; 112 /* C14-13:3 -- SMPs destined for SM shouldn't be here */ 113 return (is_switch || 114 dr_slid_is_permissive ? 115 IB_SMI_HANDLE : IB_SMI_DISCARD); 116 } 117 118 /* C14-13:4 -- hop_ptr = 0 -> should have gone to SM */ 119 if (*hop_ptr == 0) 120 return IB_SMI_HANDLE; 121 122 /* C14-13:5 -- Check for unreasonable hop pointer */ 123 return IB_SMI_DISCARD; 124 } 125 } 126 127 /* 128 * Fixup a directed route SMP for sending 129 * Return IB_SMI_DISCARD if the SMP should be discarded 130 */ 131 enum smi_action smi_handle_dr_smp_send(struct ib_smp *smp, 132 bool is_switch, int port_num) 133 { 134 return __smi_handle_dr_smp_send(is_switch, port_num, 135 &smp->hop_ptr, smp->hop_cnt, 136 smp->initial_path, 137 smp->return_path, 138 ib_get_smp_direction(smp), 139 smp->dr_dlid == IB_LID_PERMISSIVE, 140 smp->dr_slid == IB_LID_PERMISSIVE); 141 } 142 143 enum smi_action opa_smi_handle_dr_smp_send(struct opa_smp *smp, 144 bool is_switch, int port_num) 145 { 146 return __smi_handle_dr_smp_send(is_switch, port_num, 147 &smp->hop_ptr, smp->hop_cnt, 148 smp->route.dr.initial_path, 149 smp->route.dr.return_path, 150 opa_get_smp_direction(smp), 151 smp->route.dr.dr_dlid == 152 OPA_LID_PERMISSIVE, 153 smp->route.dr.dr_slid == 154 OPA_LID_PERMISSIVE); 155 } 156 157 static enum smi_action __smi_handle_dr_smp_recv(bool is_switch, int port_num, 158 int phys_port_cnt, 159 u8 *hop_ptr, u8 hop_cnt, 160 const u8 *initial_path, 161 u8 *return_path, 162 u8 direction, 163 bool dr_dlid_is_permissive, 164 bool dr_slid_is_permissive) 165 { 166 /* See section 14.2.2.2, Vol 1 IB spec */ 167 /* C14-6 -- valid hop_cnt values are from 0 to 63 */ 168 if (hop_cnt >= IB_SMP_MAX_PATH_HOPS) 169 return IB_SMI_DISCARD; 170 171 if (!direction) { 172 /* C14-9:1 -- sender should have incremented hop_ptr */ 173 if (hop_cnt && *hop_ptr == 0) 174 return IB_SMI_DISCARD; 175 176 /* C14-9:2 -- intermediate hop */ 177 if (*hop_ptr && *hop_ptr < hop_cnt) { 178 if (!is_switch) 179 return IB_SMI_DISCARD; 180 181 return_path[*hop_ptr] = port_num; 182 /* hop_ptr updated when sending */ 183 return (initial_path[*hop_ptr+1] <= phys_port_cnt ? 184 IB_SMI_HANDLE : IB_SMI_DISCARD); 185 } 186 187 /* C14-9:3 -- We're at the end of the DR segment of path */ 188 if (*hop_ptr == hop_cnt) { 189 if (hop_cnt) 190 return_path[*hop_ptr] = port_num; 191 /* hop_ptr updated when sending */ 192 193 return (is_switch || 194 dr_dlid_is_permissive ? 195 IB_SMI_HANDLE : IB_SMI_DISCARD); 196 } 197 198 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 199 /* C14-9:5 -- fail unreasonable hop pointer */ 200 return (*hop_ptr == hop_cnt + 1 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 201 202 } else { 203 204 /* C14-13:1 */ 205 if (hop_cnt && *hop_ptr == hop_cnt + 1) { 206 (*hop_ptr)--; 207 return (return_path[*hop_ptr] == 208 port_num ? IB_SMI_HANDLE : IB_SMI_DISCARD); 209 } 210 211 /* C14-13:2 */ 212 if (2 <= *hop_ptr && *hop_ptr <= hop_cnt) { 213 if (!is_switch) 214 return IB_SMI_DISCARD; 215 216 /* hop_ptr updated when sending */ 217 return (return_path[*hop_ptr-1] <= phys_port_cnt ? 218 IB_SMI_HANDLE : IB_SMI_DISCARD); 219 } 220 221 /* C14-13:3 -- We're at the end of the DR segment of path */ 222 if (*hop_ptr == 1) { 223 if (dr_slid_is_permissive) { 224 /* giving SMP to SM - update hop_ptr */ 225 (*hop_ptr)--; 226 return IB_SMI_HANDLE; 227 } 228 /* hop_ptr updated when sending */ 229 return (is_switch ? IB_SMI_HANDLE : IB_SMI_DISCARD); 230 } 231 232 /* C14-13:4 -- hop_ptr = 0 -> give to SM */ 233 /* C14-13:5 -- Check for unreasonable hop pointer */ 234 return (*hop_ptr == 0 ? IB_SMI_HANDLE : IB_SMI_DISCARD); 235 } 236 } 237 238 /* 239 * Adjust information for a received SMP 240 * Return IB_SMI_DISCARD if the SMP should be dropped 241 */ 242 enum smi_action smi_handle_dr_smp_recv(struct ib_smp *smp, bool is_switch, 243 int port_num, int phys_port_cnt) 244 { 245 return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, 246 &smp->hop_ptr, smp->hop_cnt, 247 smp->initial_path, 248 smp->return_path, 249 ib_get_smp_direction(smp), 250 smp->dr_dlid == IB_LID_PERMISSIVE, 251 smp->dr_slid == IB_LID_PERMISSIVE); 252 } 253 254 /* 255 * Adjust information for a received SMP 256 * Return IB_SMI_DISCARD if the SMP should be dropped 257 */ 258 enum smi_action opa_smi_handle_dr_smp_recv(struct opa_smp *smp, bool is_switch, 259 int port_num, int phys_port_cnt) 260 { 261 return __smi_handle_dr_smp_recv(is_switch, port_num, phys_port_cnt, 262 &smp->hop_ptr, smp->hop_cnt, 263 smp->route.dr.initial_path, 264 smp->route.dr.return_path, 265 opa_get_smp_direction(smp), 266 smp->route.dr.dr_dlid == 267 OPA_LID_PERMISSIVE, 268 smp->route.dr.dr_slid == 269 OPA_LID_PERMISSIVE); 270 } 271 272 static enum smi_forward_action __smi_check_forward_dr_smp(u8 hop_ptr, u8 hop_cnt, 273 u8 direction, 274 bool dr_dlid_is_permissive, 275 bool dr_slid_is_permissive) 276 { 277 if (!direction) { 278 /* C14-9:2 -- intermediate hop */ 279 if (hop_ptr && hop_ptr < hop_cnt) 280 return IB_SMI_FORWARD; 281 282 /* C14-9:3 -- at the end of the DR segment of path */ 283 if (hop_ptr == hop_cnt) 284 return (dr_dlid_is_permissive ? 285 IB_SMI_SEND : IB_SMI_LOCAL); 286 287 /* C14-9:4 -- hop_ptr = hop_cnt + 1 -> give to SMA/SM */ 288 if (hop_ptr == hop_cnt + 1) 289 return IB_SMI_SEND; 290 } else { 291 /* C14-13:2 -- intermediate hop */ 292 if (2 <= hop_ptr && hop_ptr <= hop_cnt) 293 return IB_SMI_FORWARD; 294 295 /* C14-13:3 -- at the end of the DR segment of path */ 296 if (hop_ptr == 1) 297 return (!dr_slid_is_permissive ? 298 IB_SMI_SEND : IB_SMI_LOCAL); 299 } 300 return IB_SMI_LOCAL; 301 302 } 303 304 enum smi_forward_action smi_check_forward_dr_smp(struct ib_smp *smp) 305 { 306 return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, 307 ib_get_smp_direction(smp), 308 smp->dr_dlid == IB_LID_PERMISSIVE, 309 smp->dr_slid == IB_LID_PERMISSIVE); 310 } 311 312 enum smi_forward_action opa_smi_check_forward_dr_smp(struct opa_smp *smp) 313 { 314 return __smi_check_forward_dr_smp(smp->hop_ptr, smp->hop_cnt, 315 opa_get_smp_direction(smp), 316 smp->route.dr.dr_dlid == 317 OPA_LID_PERMISSIVE, 318 smp->route.dr.dr_slid == 319 OPA_LID_PERMISSIVE); 320 } 321 322 /* 323 * Return the forwarding port number from initial_path for outgoing SMP and 324 * from return_path for returning SMP 325 */ 326 int smi_get_fwd_port(struct ib_smp *smp) 327 { 328 return (!ib_get_smp_direction(smp) ? smp->initial_path[smp->hop_ptr+1] : 329 smp->return_path[smp->hop_ptr-1]); 330 } 331 332 /* 333 * Return the forwarding port number from initial_path for outgoing SMP and 334 * from return_path for returning SMP 335 */ 336 int opa_smi_get_fwd_port(struct opa_smp *smp) 337 { 338 return !opa_get_smp_direction(smp) ? smp->route.dr.initial_path[smp->hop_ptr+1] : 339 smp->route.dr.return_path[smp->hop_ptr-1]; 340 } 341