]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ofed/opensm/opensm/osm_sa_path_record.c
Merge libcxxrt master f96846efbfd508f66d91fcbbef5dd808947c7f6d.
[FreeBSD/FreeBSD.git] / contrib / ofed / opensm / opensm / osm_sa_path_record.c
1 /*
2  * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
3  * Copyright (c) 2002-2011 Mellanox Technologies LTD. All rights reserved.
4  * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5  * Copyright (c) 2008 Xsigo Systems Inc. All rights reserved.
6  * Copyright (c) 2009 HNR Consulting. All rights reserved.
7  * Copyright (c) 2010 Sun Microsystems, Inc. All rights reserved.
8  * Copyright (c) 2009-2011 ZIH, TU Dresden, Federal Republic of Germany. All rights reserved.
9  * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved.
10  *
11  * This software is available to you under a choice of one of two
12  * licenses.  You may choose to be licensed under the terms of the GNU
13  * General Public License (GPL) Version 2, available from the file
14  * COPYING in the main directory of this source tree, or the
15  * OpenIB.org BSD license below:
16  *
17  *     Redistribution and use in source and binary forms, with or
18  *     without modification, are permitted provided that the following
19  *     conditions are met:
20  *
21  *      - Redistributions of source code must retain the above
22  *        copyright notice, this list of conditions and the following
23  *        disclaimer.
24  *
25  *      - Redistributions in binary form must reproduce the above
26  *        copyright notice, this list of conditions and the following
27  *        disclaimer in the documentation and/or other materials
28  *        provided with the distribution.
29  *
30  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
31  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
32  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
33  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
34  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
35  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
36  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
37  * SOFTWARE.
38  *
39  */
40
41 /*
42  * Abstract:
43  *    Implementation of osm_pr_rcv_t.
44  * This object represents the PathRecord Receiver object.
45  * This object is part of the opensm family of objects.
46  */
47
48 #if HAVE_CONFIG_H
49 #  include <config.h>
50 #endif                          /* HAVE_CONFIG_H */
51
52 #include <string.h>
53 #include <arpa/inet.h>
54 #include <sys/socket.h>
55 #include <iba/ib_types.h>
56 #include <complib/cl_qmap.h>
57 #include <complib/cl_passivelock.h>
58 #include <complib/cl_debug.h>
59 #include <complib/cl_qlist.h>
60 #include <opensm/osm_file_ids.h>
61 #define FILE_ID OSM_FILE_SA_PATH_RECORD_C
62 #include <vendor/osm_vendor_api.h>
63 #include <opensm/osm_base.h>
64 #include <opensm/osm_port.h>
65 #include <opensm/osm_node.h>
66 #include <opensm/osm_switch.h>
67 #include <opensm/osm_helper.h>
68 #include <opensm/osm_pkey.h>
69 #include <opensm/osm_multicast.h>
70 #include <opensm/osm_partition.h>
71 #include <opensm/osm_opensm.h>
72 #include <opensm/osm_qos_policy.h>
73 #include <opensm/osm_sa.h>
74 #include <opensm/osm_router.h>
75 #include <opensm/osm_prefix_route.h>
76 #include <opensm/osm_ucast_lash.h>
77
78 #define SA_PR_RESP_SIZE SA_ITEM_RESP_SIZE(path_rec)
79
80 #define MAX_HOPS 64
81
82 static inline boolean_t sa_path_rec_is_tavor_port(IN const osm_port_t * p_port)
83 {
84         osm_node_t const *p_node;
85         ib_net32_t vend_id;
86
87         p_node = p_port->p_node;
88         vend_id = ib_node_info_get_vendor_id(&p_node->node_info);
89
90         return ((p_node->node_info.device_id == CL_HTON16(23108)) &&
91                 ((vend_id == CL_HTON32(OSM_VENDOR_ID_MELLANOX)) ||
92                  (vend_id == CL_HTON32(OSM_VENDOR_ID_TOPSPIN)) ||
93                  (vend_id == CL_HTON32(OSM_VENDOR_ID_SILVERSTORM)) ||
94                  (vend_id == CL_HTON32(OSM_VENDOR_ID_VOLTAIRE))));
95 }
96
97 static boolean_t
98 sa_path_rec_apply_tavor_mtu_limit(IN const ib_path_rec_t * p_pr,
99                                   IN const osm_port_t * p_src_port,
100                                   IN const osm_port_t * p_dest_port,
101                                   IN const ib_net64_t comp_mask)
102 {
103         uint8_t required_mtu;
104
105         /* only if at least one of the ports is a Tavor device */
106         if (!sa_path_rec_is_tavor_port(p_src_port) &&
107             !sa_path_rec_is_tavor_port(p_dest_port))
108                 return FALSE;
109
110         /*
111            we can apply the patch if either:
112            1. No MTU required
113            2. Required MTU <
114            3. Required MTU = 1K or 512 or 256
115            4. Required MTU > 256 or 512
116          */
117         required_mtu = ib_path_rec_mtu(p_pr);
118         if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
119             (comp_mask & IB_PR_COMPMASK_MTU)) {
120                 switch (ib_path_rec_mtu_sel(p_pr)) {
121                 case 0: /* must be greater than */
122                 case 2: /* exact match */
123                         if (IB_MTU_LEN_1024 < required_mtu)
124                                 return FALSE;
125                         break;
126
127                 case 1: /* must be less than */
128                         /* can't be disqualified by this one */
129                         break;
130
131                 case 3: /* largest available */
132                         /* the ULP intentionally requested */
133                         /* the largest MTU possible */
134                         return FALSE;
135
136                 default:
137                         /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
138                         CL_ASSERT(FALSE);
139                         break;
140                 }
141         }
142
143         return TRUE;
144 }
145
146 static ib_api_status_t pr_rcv_get_path_parms(IN osm_sa_t * sa,
147                                              IN const ib_path_rec_t * p_pr,
148                                              IN const osm_alias_guid_t * p_src_alias_guid,
149                                              IN const uint16_t src_lid_ho,
150                                              IN const osm_alias_guid_t * p_dest_alias_guid,
151                                              IN const uint16_t dest_lid_ho,
152                                              IN const ib_net64_t comp_mask,
153                                              OUT osm_path_parms_t * p_parms)
154 {
155         const osm_node_t *p_node;
156         const osm_physp_t *p_physp, *p_physp0;
157         const osm_physp_t *p_src_physp;
158         const osm_physp_t *p_dest_physp;
159         const osm_prtn_t *p_prtn = NULL;
160         osm_opensm_t *p_osm;
161         struct osm_routing_engine *p_re;
162         const ib_port_info_t *p_pi, *p_pi0;
163         ib_api_status_t status = IB_SUCCESS;
164         ib_net16_t pkey;
165         uint8_t mtu;
166         uint8_t rate, p0_extended_rate, dest_rate;
167         uint8_t pkt_life;
168         uint8_t required_mtu;
169         uint8_t required_rate;
170         uint8_t required_pkt_life;
171         uint8_t sl;
172         uint8_t in_port_num;
173         ib_net16_t dest_lid;
174         uint8_t i;
175         ib_slvl_table_t *p_slvl_tbl = NULL;
176         osm_qos_level_t *p_qos_level = NULL;
177         uint16_t valid_sl_mask = 0xffff;
178         int hops = 0;
179         int extended, p0_extended;
180
181         OSM_LOG_ENTER(sa->p_log);
182
183         dest_lid = cl_hton16(dest_lid_ho);
184
185         p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
186         p_physp = p_src_alias_guid->p_base_port->p_physp;
187         p_src_physp = p_physp;
188         p_pi = &p_physp->port_info;
189         p_osm = sa->p_subn->p_osm;
190         p_re = p_osm->routing_engine_used;
191
192         mtu = ib_port_info_get_mtu_cap(p_pi);
193         extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
194         rate = ib_port_info_compute_rate(p_pi, extended);
195
196         /*
197            Mellanox Tavor device performance is better using 1K MTU.
198            If required MTU and MTU selector are such that 1K is OK
199            and at least one end of the path is Tavor we override the
200            port MTU with 1K.
201          */
202         if (sa->p_subn->opt.enable_quirks &&
203             sa_path_rec_apply_tavor_mtu_limit(p_pr,
204                                               p_src_alias_guid->p_base_port,
205                                               p_dest_alias_guid->p_base_port,
206                                               comp_mask))
207                 if (mtu > IB_MTU_LEN_1024) {
208                         mtu = IB_MTU_LEN_1024;
209                         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
210                                 "Optimized Path MTU to 1K for Mellanox Tavor device\n");
211                 }
212
213         /*
214            Walk the subnet object from source to destination,
215            tracking the most restrictive rate and mtu values along the way...
216
217            If source port node is a switch, then p_physp should
218            point to the port that routes the destination lid
219          */
220
221         p_node = osm_physp_get_node_ptr(p_physp);
222
223         if (p_node->sw) {
224                 /*
225                  * Source node is a switch.
226                  * Make sure that p_physp points to the out port of the
227                  * switch that routes to the destination lid (dest_lid_ho)
228                  */
229                 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
230                 if (p_physp == 0) {
231                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F02: "
232                                 "Cannot find routing from LID %u to LID %u on "
233                                 "switch %s (GUID: 0x%016" PRIx64 ")\n",
234                                 src_lid_ho, dest_lid_ho, p_node->print_desc,
235                                 cl_ntoh64(osm_node_get_node_guid(p_node)));
236                         status = IB_NOT_FOUND;
237                         goto Exit;
238                 }
239         }
240
241         if (sa->p_subn->opt.qos) {
242                 /*
243                  * Whether this node is switch or CA, the IN port for
244                  * the sl2vl table is 0, because this is a source node.
245                  */
246                 p_slvl_tbl = osm_physp_get_slvl_tbl(p_physp, 0);
247
248                 /* update valid SLs that still exist on this route */
249                 for (i = 0; i < IB_MAX_NUM_VLS; i++) {
250                         if (valid_sl_mask & (1 << i) &&
251                             ib_slvl_table_get(p_slvl_tbl, i) == IB_DROP_VL)
252                                 valid_sl_mask &= ~(1 << i);
253                 }
254                 if (!valid_sl_mask) {
255                         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
256                                 "All the SLs lead to VL15 on this path\n");
257                         status = IB_NOT_FOUND;
258                         goto Exit;
259                 }
260         }
261
262         /*
263          * Same as above
264          */
265         p_node = osm_physp_get_node_ptr(p_dest_physp);
266
267         if (p_node->sw) {
268                 /*
269                  * if destination is switch, we want p_dest_physp to point to port 0
270                  */
271                 p_dest_physp =
272                     osm_switch_get_route_by_lid(p_node->sw, dest_lid);
273
274                 if (p_dest_physp == 0) {
275                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F03: "
276                                 "Can't find routing from LID %u to LID %u on "
277                                 "switch %s (GUID: 0x%016" PRIx64 ")\n",
278                                 src_lid_ho, dest_lid_ho, p_node->print_desc,
279                                 cl_ntoh64(osm_node_get_node_guid(p_node)));
280                         status = IB_NOT_FOUND;
281                         goto Exit;
282                 }
283
284         }
285
286         /*
287          * Now go through the path step by step
288          */
289
290         while (p_physp != p_dest_physp) {
291
292                 int tmp_pnum = p_physp->port_num;
293                 p_node = osm_physp_get_node_ptr(p_physp);
294                 p_physp = osm_physp_get_remote(p_physp);
295
296                 if (p_physp == 0) {
297                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F05: "
298                                 "Can't find remote phys port of %s (GUID: "
299                                 "0x%016"PRIx64") port %d "
300                                 "while routing from LID %u to LID %u\n",
301                                 p_node->print_desc,
302                                 cl_ntoh64(osm_node_get_node_guid(p_node)),
303                                 tmp_pnum, src_lid_ho, dest_lid_ho);
304                         status = IB_ERROR;
305                         goto Exit;
306                 }
307
308                 in_port_num = osm_physp_get_port_num(p_physp);
309
310                 /*
311                    This is point to point case (no switch in between)
312                  */
313                 if (p_physp == p_dest_physp)
314                         break;
315
316                 p_node = osm_physp_get_node_ptr(p_physp);
317
318                 if (!p_node->sw) {
319                         /*
320                            There is some sort of problem in the subnet object!
321                            If this isn't a switch, we should have reached
322                            the destination by now!
323                          */
324                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F06: "
325                                 "Internal error, bad path while routing "
326                                 "%s (GUID: 0x%016"PRIx64") port %d to "
327                                 "%s (GUID: 0x%016"PRIx64") port %d; "
328                                 "ended at %s port %d\n",
329                                 p_src_alias_guid->p_base_port->p_node->print_desc,
330                                 cl_ntoh64(p_src_alias_guid->p_base_port->p_node->node_info.node_guid),
331                                 p_src_alias_guid->p_base_port->p_physp->port_num,
332                                 p_dest_alias_guid->p_base_port->p_node->print_desc,
333                                 cl_ntoh64(p_dest_alias_guid->p_base_port->p_node->node_info.node_guid),
334                                 p_dest_alias_guid->p_base_port->p_physp->port_num,
335                                 p_node->print_desc,
336                                 p_physp->port_num);
337                         status = IB_ERROR;
338                         goto Exit;
339                 }
340
341                 /*
342                    Check parameters for the ingress port in this switch.
343                  */
344                 p_pi = &p_physp->port_info;
345
346                 if (mtu > ib_port_info_get_mtu_cap(p_pi))
347                         mtu = ib_port_info_get_mtu_cap(p_pi);
348
349                 p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
350                 p_pi0 = &p_physp0->port_info;
351                 p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
352                 p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
353                 if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
354                         rate = p0_extended_rate;
355
356                 /*
357                    Continue with the egress port on this switch.
358                  */
359                 p_physp = osm_switch_get_route_by_lid(p_node->sw, dest_lid);
360                 if (p_physp == 0) {
361                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F07: "
362                                 "Dead end path on switch "
363                                 "%s (GUID: 0x%016"PRIx64") to LID %u\n",
364                                 p_node->print_desc,
365                                 cl_ntoh64(osm_node_get_node_guid(p_node)),
366                                 dest_lid_ho);
367                         status = IB_ERROR;
368                         goto Exit;
369                 }
370
371                 p_pi = &p_physp->port_info;
372
373                 if (mtu > ib_port_info_get_mtu_cap(p_pi))
374                         mtu = ib_port_info_get_mtu_cap(p_pi);
375
376                 p_physp0 = osm_node_get_physp_ptr((osm_node_t *)p_node, 0);
377                 p_pi0 = &p_physp0->port_info;
378                 p0_extended = p_pi0->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
379                 p0_extended_rate = ib_port_info_compute_rate(p_pi, p0_extended);
380                 if (ib_path_compare_rates(rate, p0_extended_rate) > 0)
381                         rate = p0_extended_rate;
382
383                 if (sa->p_subn->opt.qos) {
384                         /*
385                          * Check SL2VL table of the switch and update valid SLs
386                          */
387                         p_slvl_tbl =
388                             osm_physp_get_slvl_tbl(p_physp, in_port_num);
389                         for (i = 0; i < IB_MAX_NUM_VLS; i++) {
390                                 if (valid_sl_mask & (1 << i) &&
391                                     ib_slvl_table_get(p_slvl_tbl,
392                                                       i) == IB_DROP_VL)
393                                         valid_sl_mask &= ~(1 << i);
394                         }
395                         if (!valid_sl_mask) {
396                                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "All the SLs "
397                                         "lead to VL15 on this path\n");
398                                 status = IB_NOT_FOUND;
399                                 goto Exit;
400                         }
401                 }
402
403                 /* update number of hops traversed */
404                 hops++;
405                 if (hops > MAX_HOPS) {
406                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F25: "
407                                 "Path from GUID 0x%016" PRIx64 " (%s port %d) "
408                                 "to lid %u GUID 0x%016" PRIx64 " (%s port %d) "
409                                 "needs more than %d hops, max %d hops allowed\n",
410                                 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
411                                 p_src_physp->p_node->print_desc,
412                                 p_src_physp->port_num,
413                                 dest_lid_ho,
414                                 cl_ntoh64(osm_physp_get_port_guid
415                                           (p_dest_physp)),
416                                 p_dest_physp->p_node->print_desc,
417                                 p_dest_physp->port_num,
418                                 hops,
419                                 MAX_HOPS);
420                         status = IB_NOT_FOUND;
421                         goto Exit;
422                 }
423         }
424
425         /*
426            p_physp now points to the destination
427          */
428         p_pi = &p_physp->port_info;
429
430         if (mtu > ib_port_info_get_mtu_cap(p_pi))
431                 mtu = ib_port_info_get_mtu_cap(p_pi);
432
433         extended = p_pi->capability_mask & IB_PORT_CAP_HAS_EXT_SPEEDS;
434         dest_rate = ib_port_info_compute_rate(p_pi, extended);
435         if (ib_path_compare_rates(rate, dest_rate) > 0)
436                 rate = dest_rate;
437
438         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
439                 "Path min MTU = %u, min rate = %u\n", mtu, rate);
440
441         /*
442          * Get QoS Level object according to the path request
443          * and adjust path parameters according to QoS settings
444          */
445         if (sa->p_subn->opt.qos &&
446             sa->p_subn->p_qos_policy &&
447             (p_qos_level =
448              osm_qos_policy_get_qos_level_by_pr(sa->p_subn->p_qos_policy,
449                                                 p_pr, p_src_physp, p_dest_physp,
450                                                 comp_mask))) {
451                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
452                         "PathRecord request matches QoS Level '%s' (%s)\n",
453                         p_qos_level->name, p_qos_level->use ?
454                         p_qos_level->use : "no description");
455
456                 if (p_qos_level->mtu_limit_set
457                     && (mtu > p_qos_level->mtu_limit))
458                         mtu = p_qos_level->mtu_limit;
459
460                 if (p_qos_level->rate_limit_set
461                     && (ib_path_compare_rates(rate, p_qos_level->rate_limit) > 0))
462                         rate = p_qos_level->rate_limit;
463
464                 if (p_qos_level->sl_set) {
465                         sl = p_qos_level->sl;
466                         if (!(valid_sl_mask & (1 << sl))) {
467                                 status = IB_NOT_FOUND;
468                                 goto Exit;
469                         }
470                 }
471         }
472
473         /*
474          * Set packet lifetime.
475          * According to spec definition IBA 1.2 Table 205
476          * PacketLifeTime description, for loopback paths,
477          * packetLifeTime shall be zero.
478          */
479         if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
480                 pkt_life = 0;
481         else if (p_qos_level && p_qos_level->pkt_life_set)
482                 pkt_life = p_qos_level->pkt_life;
483         else
484                 pkt_life = sa->p_subn->opt.subnet_timeout;
485
486         /*
487            Determine if these values meet the user criteria
488            and adjust appropriately
489          */
490
491         /* we silently ignore cases where only the MTU selector is defined */
492         if ((comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
493             (comp_mask & IB_PR_COMPMASK_MTU)) {
494                 required_mtu = ib_path_rec_mtu(p_pr);
495                 switch (ib_path_rec_mtu_sel(p_pr)) {
496                 case 0: /* must be greater than */
497                         if (mtu <= required_mtu)
498                                 status = IB_NOT_FOUND;
499                         break;
500
501                 case 1: /* must be less than */
502                         if (mtu >= required_mtu) {
503                                 /* adjust to use the highest mtu
504                                    lower than the required one */
505                                 if (required_mtu > 1)
506                                         mtu = required_mtu - 1;
507                                 else
508                                         status = IB_NOT_FOUND;
509                         }
510                         break;
511
512                 case 2: /* exact match */
513                         if (mtu < required_mtu)
514                                 status = IB_NOT_FOUND;
515                         else
516                                 mtu = required_mtu;
517                         break;
518
519                 case 3: /* largest available */
520                         /* can't be disqualified by this one */
521                         break;
522
523                 default:
524                         /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
525                         CL_ASSERT(FALSE);
526                         status = IB_ERROR;
527                         break;
528                 }
529         }
530         if (status != IB_SUCCESS)
531                 goto Exit;
532
533         /* we silently ignore cases where only the Rate selector is defined */
534         if ((comp_mask & IB_PR_COMPMASK_RATESELEC) &&
535             (comp_mask & IB_PR_COMPMASK_RATE)) {
536                 required_rate = ib_path_rec_rate(p_pr);
537                 switch (ib_path_rec_rate_sel(p_pr)) {
538                 case 0: /* must be greater than */
539                         if (ib_path_compare_rates(rate, required_rate) <= 0)
540                                 status = IB_NOT_FOUND;
541                         break;
542
543                 case 1: /* must be less than */
544                         if (ib_path_compare_rates(rate, required_rate) >= 0) {
545                                 /* adjust the rate to use the highest rate
546                                    lower than the required one */
547                                 rate = ib_path_rate_get_prev(required_rate);
548                                 if (!rate)
549                                         status = IB_NOT_FOUND;
550                         }
551                         break;
552
553                 case 2: /* exact match */
554                         if (ib_path_compare_rates(rate, required_rate))
555                                 status = IB_NOT_FOUND;
556                         else
557                                 rate = required_rate;
558                         break;
559
560                 case 3: /* largest available */
561                         /* can't be disqualified by this one */
562                         break;
563
564                 default:
565                         /* if we're here, there's a bug in ib_path_rec_mtu_sel() */
566                         CL_ASSERT(FALSE);
567                         status = IB_ERROR;
568                         break;
569                 }
570         }
571         if (status != IB_SUCCESS)
572                 goto Exit;
573
574         /* we silently ignore cases where only the PktLife selector is defined */
575         if ((comp_mask & IB_PR_COMPMASK_PKTLIFETIMESELEC) &&
576             (comp_mask & IB_PR_COMPMASK_PKTLIFETIME)) {
577                 required_pkt_life = ib_path_rec_pkt_life(p_pr);
578                 switch (ib_path_rec_pkt_life_sel(p_pr)) {
579                 case 0: /* must be greater than */
580                         if (pkt_life <= required_pkt_life)
581                                 status = IB_NOT_FOUND;
582                         break;
583
584                 case 1: /* must be less than */
585                         if (pkt_life >= required_pkt_life) {
586                                 /* adjust the lifetime to use the highest possible
587                                    lower than the required one */
588                                 if (required_pkt_life > 1)
589                                         pkt_life = required_pkt_life - 1;
590                                 else
591                                         status = IB_NOT_FOUND;
592                         }
593                         break;
594
595                 case 2: /* exact match */
596                         if (pkt_life < required_pkt_life)
597                                 status = IB_NOT_FOUND;
598                         else
599                                 pkt_life = required_pkt_life;
600                         break;
601
602                 case 3: /* smallest available */
603                         /* can't be disqualified by this one */
604                         break;
605
606                 default:
607                         /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
608                         CL_ASSERT(FALSE);
609                         status = IB_ERROR;
610                         break;
611                 }
612         }
613
614         if (status != IB_SUCCESS)
615                 goto Exit;
616
617         /*
618          * set Pkey for this path record request
619          */
620
621         if ((comp_mask & IB_PR_COMPMASK_RAWTRAFFIC) &&
622             (cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31)))
623                 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
624                                                   sa->p_subn->opt.allow_both_pkeys);
625
626         else if (comp_mask & IB_PR_COMPMASK_PKEY) {
627                 /*
628                  * PR request has a specific pkey:
629                  * Check that source and destination share this pkey.
630                  * If QoS level has pkeys, check that this pkey exists
631                  * in the QoS level pkeys.
632                  * PR returned pkey is the requested pkey.
633                  */
634                 pkey = p_pr->pkey;
635                 if (!osm_physp_share_this_pkey(p_src_physp, p_dest_physp, pkey,
636                                                sa->p_subn->opt.allow_both_pkeys)) {
637                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1A: "
638                                 "Ports 0x%016" PRIx64 " (%s port %d) and "
639                                 "0x%016" PRIx64 " (%s port %d) "
640                                 "do not share specified PKey 0x%04x\n",
641                                 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
642                                 p_src_physp->p_node->print_desc,
643                                 p_src_physp->port_num,
644                                 cl_ntoh64(osm_physp_get_port_guid
645                                           (p_dest_physp)),
646                                 p_dest_physp->p_node->print_desc,
647                                 p_dest_physp->port_num,
648                                 cl_ntoh16(pkey));
649                         status = IB_NOT_FOUND;
650                         goto Exit;
651                 }
652                 if (p_qos_level && p_qos_level->pkey_range_len &&
653                     !osm_qos_level_has_pkey(p_qos_level, pkey)) {
654                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1D: "
655                                 "QoS level \"%s\" doesn't define specified PKey 0x%04x "
656                                 "for ports 0x%016" PRIx64 " (%s port %d) and "
657                                 "0x%016"PRIx64" (%s port %d)\n",
658                                 p_qos_level->name,
659                                 cl_ntoh16(pkey),
660                                 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
661                                 p_src_physp->p_node->print_desc,
662                                 p_src_alias_guid->p_base_port->p_physp->port_num,
663                                 cl_ntoh64(osm_physp_get_port_guid
664                                           (p_dest_physp)),
665                                 p_dest_physp->p_node->print_desc,
666                                 p_dest_alias_guid->p_base_port->p_physp->port_num);
667                         status = IB_NOT_FOUND;
668                         goto Exit;
669                 }
670
671         } else if (p_qos_level && p_qos_level->pkey_range_len) {
672                 /*
673                  * PR request doesn't have a specific pkey, but QoS level
674                  * has pkeys - get shared pkey from QoS level pkeys
675                  */
676                 pkey = osm_qos_level_get_shared_pkey(p_qos_level,
677                                                      p_src_physp, p_dest_physp,
678                                                      sa->p_subn->opt.allow_both_pkeys);
679                 if (!pkey) {
680                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1E: "
681                                 "Ports 0x%016" PRIx64 " (%s) and "
682                                 "0x%016" PRIx64 " (%s) do not share "
683                                 "PKeys defined by QoS level \"%s\"\n",
684                                 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
685                                 p_src_physp->p_node->print_desc,
686                                 cl_ntoh64(osm_physp_get_port_guid
687                                           (p_dest_physp)),
688                                 p_dest_physp->p_node->print_desc,
689                                 p_qos_level->name);
690                         status = IB_NOT_FOUND;
691                         goto Exit;
692                 }
693         } else {
694                 /*
695                  * Neither PR request nor QoS level have pkey.
696                  * Just get any shared pkey.
697                  */
698                 pkey = osm_physp_find_common_pkey(p_src_physp, p_dest_physp,
699                                                   sa->p_subn->opt.allow_both_pkeys);
700                 if (!pkey) {
701                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1B: "
702                                 "Ports src 0x%016"PRIx64" (%s port %d) and "
703                                 "dst 0x%016"PRIx64" (%s port %d) do not have "
704                                 "any shared PKeys\n",
705                                 cl_ntoh64(osm_physp_get_port_guid(p_src_physp)),
706                                 p_src_physp->p_node->print_desc,
707                                 p_src_physp->port_num,
708                                 cl_ntoh64(osm_physp_get_port_guid
709                                           (p_dest_physp)),
710                                 p_dest_physp->p_node->print_desc,
711                                 p_dest_physp->port_num);
712                         status = IB_NOT_FOUND;
713                         goto Exit;
714                 }
715         }
716
717         if (pkey) {
718                 p_prtn =
719                     (osm_prtn_t *) cl_qmap_get(&sa->p_subn->prtn_pkey_tbl,
720                                                pkey & cl_hton16((uint16_t) ~
721                                                                 0x8000));
722                 if (p_prtn ==
723                     (osm_prtn_t *) cl_qmap_end(&sa->p_subn->prtn_pkey_tbl))
724                         p_prtn = NULL;
725         }
726
727         /*
728          * Set PathRecord SL
729          */
730
731         if (comp_mask & IB_PR_COMPMASK_SL) {
732                 /*
733                  * Specific SL was requested
734                  */
735                 sl = ib_path_rec_sl(p_pr);
736
737                 if (p_qos_level && p_qos_level->sl_set
738                     && (p_qos_level->sl != sl)) {
739                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1F: "
740                                 "QoS constraints: required PathRecord SL (%u) "
741                                 "doesn't match QoS policy \"%s\" SL (%u) "
742                                 "[%s port %d <-> %s port %d]\n", sl,
743                                 p_qos_level->name,
744                                 p_qos_level->sl,
745                                 p_src_alias_guid->p_base_port->p_node->print_desc,
746                                 p_src_alias_guid->p_base_port->p_physp->port_num,
747                                 p_dest_alias_guid->p_base_port->p_node->print_desc,
748                                 p_dest_alias_guid->p_base_port->p_physp->port_num);
749                         status = IB_NOT_FOUND;
750                         goto Exit;
751                 }
752
753         } else if (p_qos_level && p_qos_level->sl_set) {
754                 /*
755                  * No specific SL was requested, but there is an SL in
756                  * QoS level.
757                  */
758                 sl = p_qos_level->sl;
759
760                 if (pkey && p_prtn && p_prtn->sl != p_qos_level->sl)
761                         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
762                                 "QoS level SL (%u) overrides partition SL (%u)\n",
763                                 p_qos_level->sl, p_prtn->sl);
764
765         } else if (pkey) {
766                 /*
767                  * No specific SL in request or in QoS level - use partition SL
768                  */
769                 if (!p_prtn) {
770                         sl = OSM_DEFAULT_SL;
771                         /* this may be possible when pkey tables are created somehow in
772                            previous runs or things are going wrong here */
773                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F1C: "
774                                 "No partition found for PKey 0x%04x - "
775                                 "using default SL %d "
776                                 "[%s port %d <-> %s port %d]\n",
777                                 cl_ntoh16(pkey), sl,
778                                 p_src_alias_guid->p_base_port->p_node->print_desc,
779                                 p_src_alias_guid->p_base_port->p_physp->port_num,
780                                 p_dest_alias_guid->p_base_port->p_node->print_desc,
781                                 p_dest_alias_guid->p_base_port->p_physp->port_num);
782                 } else
783                         sl = p_prtn->sl;
784         } else if (sa->p_subn->opt.qos) {
785                 if (valid_sl_mask & (1 << OSM_DEFAULT_SL))
786                         sl = OSM_DEFAULT_SL;
787                 else {
788                         for (i = 0; i < IB_MAX_NUM_VLS; i++)
789                                 if (valid_sl_mask & (1 << i))
790                                         break;
791                         sl = i;
792                 }
793         } else
794                 sl = OSM_DEFAULT_SL;
795
796         if (sa->p_subn->opt.qos && !(valid_sl_mask & (1 << sl))) {
797                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F24: "
798                         "Selected SL (%u) leads to VL15 "
799                         "[%s port %d <-> %s port %d]\n",
800                         sl,
801                         p_src_alias_guid->p_base_port->p_node->print_desc,
802                         p_src_alias_guid->p_base_port->p_physp->port_num,
803                         p_dest_alias_guid->p_base_port->p_node->print_desc,
804                         p_dest_alias_guid->p_base_port->p_physp->port_num);
805                 status = IB_NOT_FOUND;
806                 goto Exit;
807         }
808
809         /*
810          * If the routing engine wants to have a say in path SL selection,
811          * send the currently computed SL value as a hint and let the routing
812          * engine override it.
813          */
814         if (p_re && p_re->path_sl) {
815                 uint8_t pr_sl;
816                 pr_sl = sl;
817
818                 sl = p_re->path_sl(p_re->context, sl,
819                                    cl_hton16(src_lid_ho), cl_hton16(dest_lid_ho));
820
821                 if ((comp_mask & IB_PR_COMPMASK_SL) && (sl != pr_sl)) {
822                         OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F2A: "
823                                 "Requested SL (%u) doesn't match SL calculated"
824                                 "by routing engine (%u) "
825                                 "[%s port %d <-> %s port %d]\n",
826                                 pr_sl,
827                                 sl,
828                                 p_src_alias_guid->p_base_port->p_node->print_desc,
829                                 p_src_alias_guid->p_base_port->p_physp->port_num,
830                                 p_dest_alias_guid->p_base_port->p_node->print_desc,
831                                 p_dest_alias_guid->p_base_port->p_physp->port_num);
832                         status = IB_NOT_FOUND;
833                         goto Exit;
834                 }
835         }
836         /* reset pkey when raw traffic */
837         if (comp_mask & IB_PR_COMPMASK_RAWTRAFFIC &&
838             cl_ntoh32(p_pr->hop_flow_raw) & (1 << 31))
839                 pkey = 0;
840
841         p_parms->mtu = mtu;
842         p_parms->rate = rate;
843         p_parms->pkt_life = pkt_life;
844         p_parms->pkey = pkey;
845         p_parms->sl = sl;
846
847         OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Path params: mtu = %u, rate = %u,"
848                 " packet lifetime = %u, pkey = 0x%04X, sl = %u\n",
849                 mtu, rate, pkt_life, cl_ntoh16(pkey), sl);
850 Exit:
851         OSM_LOG_EXIT(sa->p_log);
852         return status;
853 }
854
855 ib_api_status_t osm_get_path_params(IN osm_sa_t * sa,
856                                     IN const osm_port_t * p_src_port,
857                                     IN const uint16_t slid_ho,
858                                     IN const osm_port_t * p_dest_port,
859                                     IN const uint16_t dlid_ho,
860                                     OUT osm_path_parms_t * p_parms)
861 {
862         osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
863         ib_path_rec_t pr;
864
865         if (!p_src_port || !slid_ho || !p_dest_port || !dlid_ho)
866                 return IB_INVALID_PARAMETER;
867
868         memset(&pr, 0, sizeof(ib_path_rec_t));
869
870         p_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
871                                                       osm_port_get_guid(p_src_port));
872         p_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
873                                                        osm_port_get_guid(p_dest_port));
874         return pr_rcv_get_path_parms(sa, &pr,
875                                      p_src_alias_guid, slid_ho,
876                                      p_dest_alias_guid, dlid_ho, 0, p_parms);
877 }
878
879 static void pr_rcv_build_pr(IN osm_sa_t * sa,
880                             IN const osm_alias_guid_t * p_src_alias_guid,
881                             IN const osm_alias_guid_t * p_dest_alias_guid,
882                             IN const ib_gid_t * p_sgid,
883                             IN const ib_gid_t * p_dgid,
884                             IN const uint16_t src_lid_ho,
885                             IN const uint16_t dest_lid_ho,
886                             IN const uint8_t preference,
887                             IN const osm_path_parms_t * p_parms,
888                             OUT ib_path_rec_t * p_pr)
889 {
890         const osm_physp_t *p_src_physp, *p_dest_physp;
891
892         OSM_LOG_ENTER(sa->p_log);
893
894         if (p_dgid)
895                 p_pr->dgid = *p_dgid;
896         else {
897                 p_dest_physp = p_dest_alias_guid->p_base_port->p_physp;
898
899                 p_pr->dgid.unicast.prefix =
900                     osm_physp_get_subnet_prefix(p_dest_physp);
901                 p_pr->dgid.unicast.interface_id = p_dest_alias_guid->alias_guid;
902         }
903         if (p_sgid)
904                 p_pr->sgid = *p_sgid;
905         else {
906                 p_src_physp = p_src_alias_guid->p_base_port->p_physp;
907
908                 p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix(p_src_physp);
909                 p_pr->sgid.unicast.interface_id = p_src_alias_guid->alias_guid;
910         }
911
912         p_pr->dlid = cl_hton16(dest_lid_ho);
913         p_pr->slid = cl_hton16(src_lid_ho);
914
915         p_pr->hop_flow_raw &= cl_hton32(1 << 31);
916
917         /* Only set HopLimit if going through a router */
918         if (p_dgid)
919                 p_pr->hop_flow_raw |= cl_hton32(IB_HOPLIMIT_MAX);
920
921         p_pr->pkey = p_parms->pkey;
922         ib_path_rec_set_sl(p_pr, p_parms->sl);
923         ib_path_rec_set_qos_class(p_pr, 0);
924         p_pr->mtu = (uint8_t) (p_parms->mtu | 0x80);
925         p_pr->rate = (uint8_t) (p_parms->rate | 0x80);
926
927         /* According to 1.2 spec definition Table 205 PacketLifeTime description,
928            for loopback paths, packetLifeTime shall be zero. */
929         if (p_src_alias_guid->p_base_port == p_dest_alias_guid->p_base_port)
930                 p_pr->pkt_life = 0x80;  /* loopback */
931         else
932                 p_pr->pkt_life = (uint8_t) (p_parms->pkt_life | 0x80);
933
934         p_pr->preference = preference;
935
936         /* always return num_path = 0 so this is only the reversible component */
937         if (p_parms->reversible)
938                 p_pr->num_path = 0x80;
939
940         OSM_LOG_EXIT(sa->p_log);
941 }
942
943 static osm_sa_item_t *pr_rcv_get_lid_pair_path(IN osm_sa_t * sa,
944                                                IN const ib_path_rec_t * p_pr,
945                                                IN const osm_alias_guid_t * p_src_alias_guid,
946                                                IN const osm_alias_guid_t * p_dest_alias_guid,
947                                                IN const ib_gid_t * p_sgid,
948                                                IN const ib_gid_t * p_dgid,
949                                                IN const uint16_t src_lid_ho,
950                                                IN const uint16_t dest_lid_ho,
951                                                IN const ib_net64_t comp_mask,
952                                                IN const uint8_t preference)
953 {
954         osm_path_parms_t path_parms;
955         osm_path_parms_t rev_path_parms;
956         osm_sa_item_t *p_pr_item;
957         ib_api_status_t status, rev_path_status;
958
959         OSM_LOG_ENTER(sa->p_log);
960
961         OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Src LID %u, Dest LID %u\n",
962                 src_lid_ho, dest_lid_ho);
963
964         p_pr_item = malloc(SA_PR_RESP_SIZE);
965         if (p_pr_item == NULL) {
966                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F01: "
967                         "Unable to allocate path record\n");
968                 goto Exit;
969         }
970         memset(p_pr_item, 0, SA_PR_RESP_SIZE);
971
972         status = pr_rcv_get_path_parms(sa, p_pr, p_src_alias_guid, src_lid_ho,
973                                        p_dest_alias_guid, dest_lid_ho,
974                                        comp_mask, &path_parms);
975
976         if (status != IB_SUCCESS) {
977                 free(p_pr_item);
978                 p_pr_item = NULL;
979                 goto Exit;
980         }
981
982         /* now try the reversible path */
983         rev_path_status = pr_rcv_get_path_parms(sa, p_pr, p_dest_alias_guid,
984                                                 dest_lid_ho, p_src_alias_guid,
985                                                 src_lid_ho, comp_mask,
986                                                 &rev_path_parms);
987
988         path_parms.reversible = (rev_path_status == IB_SUCCESS);
989
990         /* did we get a Reversible Path compmask ? */
991         /*
992            NOTE that if the reversible component = 0, it is a don't care
993            rather than requiring non-reversible paths ...
994            see Vol1 Ver1.2 p900 l16
995          */
996         if ((comp_mask & IB_PR_COMPMASK_REVERSIBLE) &&
997             !path_parms.reversible && (p_pr->num_path & 0x80)) {
998                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
999                         "Requested reversible path but failed to get one\n");
1000                 free(p_pr_item);
1001                 p_pr_item = NULL;
1002                 goto Exit;
1003         }
1004
1005         pr_rcv_build_pr(sa, p_src_alias_guid, p_dest_alias_guid, p_sgid, p_dgid,
1006                         src_lid_ho, dest_lid_ho, preference, &path_parms,
1007                         &p_pr_item->resp.path_rec);
1008
1009 Exit:
1010         OSM_LOG_EXIT(sa->p_log);
1011         return p_pr_item;
1012 }
1013
1014 static void pr_rcv_get_port_pair_paths(IN osm_sa_t * sa,
1015                                        IN const ib_sa_mad_t *sa_mad,
1016                                        IN const osm_port_t * p_req_port,
1017                                        IN const osm_alias_guid_t * p_src_alias_guid,
1018                                        IN const osm_alias_guid_t * p_dest_alias_guid,
1019                                        IN const ib_gid_t * p_sgid,
1020                                        IN const ib_gid_t * p_dgid,
1021                                        IN cl_qlist_t * p_list)
1022 {
1023         const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1024         ib_net64_t comp_mask = sa_mad->comp_mask;
1025         osm_sa_item_t *p_pr_item;
1026         uint16_t src_lid_min_ho;
1027         uint16_t src_lid_max_ho;
1028         uint16_t dest_lid_min_ho;
1029         uint16_t dest_lid_max_ho;
1030         uint16_t src_lid_ho;
1031         uint16_t dest_lid_ho;
1032         uint32_t path_num;
1033         uint8_t preference;
1034         unsigned iterations, src_offset, dest_offset;
1035
1036         OSM_LOG_ENTER(sa->p_log);
1037
1038         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1039                 "Src port 0x%016" PRIx64 ", Dst port 0x%016" PRIx64 "\n",
1040                 cl_ntoh64(p_src_alias_guid->alias_guid),
1041                 cl_ntoh64(p_dest_alias_guid->alias_guid));
1042
1043         /* Check that the req_port, src_port and dest_port all share a
1044            pkey. The check is done on the default physical port of the ports. */
1045         if (osm_port_share_pkey(sa->p_log, p_req_port,
1046                                 p_src_alias_guid->p_base_port,
1047                                 sa->p_subn->opt.allow_both_pkeys) == FALSE
1048             || osm_port_share_pkey(sa->p_log, p_req_port,
1049                                    p_dest_alias_guid->p_base_port,
1050                                    sa->p_subn->opt.allow_both_pkeys) == FALSE
1051             || osm_port_share_pkey(sa->p_log, p_src_alias_guid->p_base_port,
1052                                    p_dest_alias_guid->p_base_port,
1053                                    sa->p_subn->opt.allow_both_pkeys) == FALSE)
1054                 /* One of the pairs doesn't share a pkey so the path is disqualified. */
1055                 goto Exit;
1056
1057         /*
1058            We shouldn't be here if the paths are disqualified in some way...
1059            Thus, we assume every possible connection is valid.
1060
1061            We desire to return high-quality paths first.
1062            In OpenSM, higher quality means least overlap with other paths.
1063            This is acheived in practice by returning paths with
1064            different LID value on each end, which means these
1065            paths are more redundant that paths with the same LID repeated
1066            on one side.  For example, in OpenSM the paths between two
1067            endpoints with LMC = 1 might be as follows:
1068
1069            Port A, LID 1 <-> Port B, LID 3
1070            Port A, LID 1 <-> Port B, LID 4
1071            Port A, LID 2 <-> Port B, LID 3
1072            Port A, LID 2 <-> Port B, LID 4
1073
1074            The OpenSM unicast routing algorithms attempt to disperse each path
1075            to as varied a physical path as is reasonable.  1<->3 and 1<->4 have
1076            more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
1077
1078            OpenSM ranks paths in three preference groups:
1079
1080            Preference Value    Description
1081            ----------------    -------------------------------------------
1082            0             Redundant in both directions with other
1083            pref value = 0 paths
1084
1085            1             Redundant in one direction with other
1086            pref value = 0 and pref value = 1 paths
1087
1088            2             Not redundant in either direction with
1089            other paths
1090
1091            3-FF          Unused
1092
1093            SA clients don't need to know these details, only that the lower
1094            preference paths are preferred, as stated in the spec.  The paths
1095            may not actually be physically redundant depending on the topology
1096            of the subnet, but the point of LMC > 0 is to offer redundancy,
1097            so it is assumed that the subnet is physically appropriate for the
1098            specified LMC value.  A more advanced implementation would inspect for
1099            physical redundancy, but I'm not going to bother with that now.
1100          */
1101
1102         /*
1103            Refine our search if the client specified end-point LIDs
1104          */
1105         if (comp_mask & IB_PR_COMPMASK_DLID)
1106                 dest_lid_max_ho = dest_lid_min_ho = cl_ntoh16(p_pr->dlid);
1107         else
1108                 osm_port_get_lid_range_ho(p_dest_alias_guid->p_base_port,
1109                                           &dest_lid_min_ho, &dest_lid_max_ho);
1110
1111         if (comp_mask & IB_PR_COMPMASK_SLID)
1112                 src_lid_max_ho = src_lid_min_ho = cl_ntoh16(p_pr->slid);
1113         else
1114                 osm_port_get_lid_range_ho(p_src_alias_guid->p_base_port,
1115                                           &src_lid_min_ho, &src_lid_max_ho);
1116
1117         if (src_lid_min_ho == 0) {
1118                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1119                         "Obtained source LID of 0. No such LID possible "
1120                         "(%s port %d)\n",
1121                         p_src_alias_guid->p_base_port->p_node->print_desc,
1122                         p_src_alias_guid->p_base_port->p_physp->port_num);
1123                 goto Exit;
1124         }
1125
1126         if (dest_lid_min_ho == 0) {
1127                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1128                         "Obtained destination LID of 0. No such LID possible "
1129                         "(%s port %d)\n",
1130                         p_dest_alias_guid->p_base_port->p_node->print_desc,
1131                         p_dest_alias_guid->p_base_port->p_physp->port_num);
1132                 goto Exit;
1133         }
1134
1135         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1136                 "Src LIDs [%u-%u], Dest LIDs [%u-%u]\n",
1137                 src_lid_min_ho, src_lid_max_ho,
1138                 dest_lid_min_ho, dest_lid_max_ho);
1139
1140         src_lid_ho = src_lid_min_ho;
1141         dest_lid_ho = dest_lid_min_ho;
1142
1143         /*
1144            Preferred paths come first in OpenSM
1145          */
1146         preference = 0;
1147         path_num = 0;
1148
1149         /* If SubnAdmGet, assume NumbPaths 1 (1.2 erratum) */
1150         if (sa_mad->method == IB_MAD_METHOD_GET)
1151                 iterations = 1;
1152         else if (comp_mask & IB_PR_COMPMASK_NUMBPATH)
1153                 iterations = ib_path_rec_num_path(p_pr);
1154         else
1155                 iterations = (unsigned) (-1);
1156
1157         while (path_num < iterations) {
1158                 /*
1159                    These paths are "fully redundant"
1160                  */
1161
1162                 p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
1163                                                      p_dest_alias_guid,
1164                                                      p_sgid, p_dgid,
1165                                                      src_lid_ho, dest_lid_ho,
1166                                                      comp_mask, preference);
1167
1168                 if (p_pr_item) {
1169                         cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1170                         ++path_num;
1171                 }
1172
1173                 if (++src_lid_ho > src_lid_max_ho)
1174                         break;
1175
1176                 if (++dest_lid_ho > dest_lid_max_ho)
1177                         break;
1178         }
1179
1180         /*
1181            Check if we've accumulated all the paths that the user cares to see
1182          */
1183         if (path_num == iterations)
1184                 goto Exit;
1185
1186         /*
1187            Don't bother reporting preference 1 paths for now.
1188            It's more trouble than it's worth and can only occur
1189            if ports have different LMC values, which isn't supported
1190            by OpenSM right now anyway.
1191          */
1192         preference = 2;
1193         src_lid_ho = src_lid_min_ho;
1194         dest_lid_ho = dest_lid_min_ho;
1195         src_offset = 0;
1196         dest_offset = 0;
1197
1198         /*
1199            Iterate over the remaining paths
1200          */
1201         while (path_num < iterations) {
1202                 dest_offset++;
1203                 dest_lid_ho++;
1204
1205                 if (dest_lid_ho > dest_lid_max_ho) {
1206                         src_offset++;
1207                         src_lid_ho++;
1208
1209                         if (src_lid_ho > src_lid_max_ho)
1210                                 break;  /* done */
1211
1212                         dest_offset = 0;
1213                         dest_lid_ho = dest_lid_min_ho;
1214                 }
1215
1216                 /*
1217                    These paths are "fully non-redundant" with paths already
1218                    identified above and consequently not of much value.
1219
1220                    Don't return paths we already identified above, as indicated
1221                    by the offset values being equal.
1222                  */
1223                 if (src_offset == dest_offset)
1224                         continue;       /* already reported */
1225
1226                 p_pr_item = pr_rcv_get_lid_pair_path(sa, p_pr, p_src_alias_guid,
1227                                                      p_dest_alias_guid, p_sgid,
1228                                                      p_dgid, src_lid_ho,
1229                                                      dest_lid_ho, comp_mask,
1230                                                      preference);
1231
1232                 if (p_pr_item) {
1233                         cl_qlist_insert_tail(p_list, &p_pr_item->list_item);
1234                         ++path_num;
1235                 }
1236         }
1237
1238 Exit:
1239         OSM_LOG_EXIT(sa->p_log);
1240 }
1241
1242 /* Find the router port that is configured to handle this prefix, if any */
1243 static ib_net64_t find_router(const osm_sa_t *sa, ib_net64_t prefix)
1244 {
1245         osm_prefix_route_t *route = NULL;
1246         osm_router_t *rtr;
1247         cl_qlist_t *l = &sa->p_subn->prefix_routes_list;
1248         cl_list_item_t *i;
1249
1250         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "Non local DGID subnet prefix "
1251                 "0x%016" PRIx64 "\n", cl_ntoh64(prefix));
1252
1253         for (i = cl_qlist_head(l); i != cl_qlist_end(l); i = cl_qlist_next(i)) {
1254                 osm_prefix_route_t *r = (osm_prefix_route_t *)i;
1255                 if (!r->prefix || r->prefix == prefix) {
1256                         route = r;
1257                         break;
1258                 }
1259         }
1260         if (!route)
1261                 return 0;
1262
1263         if (route->guid == 0) /* first router */
1264                 rtr = (osm_router_t *) cl_qmap_head(&sa->p_subn->rtr_guid_tbl);
1265         else
1266                 rtr = (osm_router_t *) cl_qmap_get(&sa->p_subn->rtr_guid_tbl,
1267                                                    route->guid);
1268
1269         if (rtr == (osm_router_t *) cl_qmap_end(&sa->p_subn->rtr_guid_tbl))
1270                 return 0;
1271
1272         return osm_port_get_guid(osm_router_get_port_ptr(rtr));
1273 }
1274
1275 ib_net16_t osm_pr_get_end_points(IN osm_sa_t * sa,
1276                                  IN const ib_sa_mad_t *sa_mad,
1277                                  OUT const osm_alias_guid_t ** pp_src_alias_guid,
1278                                  OUT const osm_alias_guid_t ** pp_dest_alias_guid,
1279                                  OUT const osm_port_t ** pp_src_port,
1280                                  OUT const osm_port_t ** pp_dest_port,
1281                                  OUT const ib_gid_t ** pp_sgid,
1282                                  OUT const ib_gid_t ** pp_dgid)
1283 {
1284         const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1285         ib_net64_t comp_mask = sa_mad->comp_mask;
1286         ib_net64_t dest_guid;
1287         ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
1288
1289         OSM_LOG_ENTER(sa->p_log);
1290
1291         /*
1292            Determine what fields are valid and then get a pointer
1293            to the source and destination port objects, if possible.
1294          */
1295
1296         /*
1297            Check a few easy disqualifying cases up front before getting
1298            into the endpoints.
1299          */
1300
1301         *pp_src_alias_guid = NULL;
1302         *pp_src_port = NULL;
1303         if (comp_mask & IB_PR_COMPMASK_SGID) {
1304                 if (!ib_gid_is_link_local(&p_pr->sgid)) {
1305                         if (ib_gid_get_subnet_prefix(&p_pr->sgid) !=
1306                             sa->p_subn->opt.subnet_prefix) {
1307                                 /*
1308                                    This 'error' is the client's fault (bad gid)
1309                                    so don't enter it as an error in our own log.
1310                                    Return an error response to the client.
1311                                  */
1312                                 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1313                                         "Non local SGID subnet prefix 0x%016"
1314                                         PRIx64 "\n",
1315                                         cl_ntoh64(p_pr->sgid.unicast.prefix));
1316                                 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1317                                 goto Exit;
1318                         }
1319                 }
1320
1321                 *pp_src_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
1322                                                                 p_pr->sgid.unicast.interface_id);
1323                 if (!*pp_src_alias_guid) {
1324                         /*
1325                            This 'error' is the client's fault (bad gid) so
1326                            don't enter it as an error in our own log.
1327                            Return an error response to the client.
1328                          */
1329                         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1330                                 "No source port with GUID 0x%016" PRIx64 "\n",
1331                                 cl_ntoh64(p_pr->sgid.unicast.interface_id));
1332                         sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1333                         goto Exit;
1334                 }
1335                 if (pp_sgid)
1336                         *pp_sgid = &p_pr->sgid;
1337         }
1338
1339         if (comp_mask & IB_PR_COMPMASK_SLID) {
1340                 *pp_src_port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
1341                 if (!*pp_src_port) {
1342                         /*
1343                            This 'error' is the client's fault (bad lid) so
1344                            don't enter it as an error in our own log.
1345                            Return an error response to the client.
1346                          */
1347                         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No source port "
1348                                 "with LID %u\n", cl_ntoh16(p_pr->slid));
1349                         sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1350                         goto Exit;
1351                 }
1352         }
1353
1354         *pp_dest_alias_guid = NULL;
1355         *pp_dest_port = NULL;
1356         if (comp_mask & IB_PR_COMPMASK_DGID) {
1357                 if (!ib_gid_is_link_local(&p_pr->dgid) &&
1358                     !ib_gid_is_multicast(&p_pr->dgid) &&
1359                     ib_gid_get_subnet_prefix(&p_pr->dgid) !=
1360                     sa->p_subn->opt.subnet_prefix) {
1361                         dest_guid = find_router(sa, p_pr->dgid.unicast.prefix);
1362                         if (!dest_guid) {
1363                                 char gid_str[INET6_ADDRSTRLEN];
1364                                 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1365                                         "Off subnet DGID %s, but router not "
1366                                         "found\n",
1367                                         inet_ntop(AF_INET6, p_pr->dgid.raw,
1368                                                   gid_str, sizeof(gid_str)));
1369                                 sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1370                                 goto Exit;
1371                         }
1372                         if (pp_dgid)
1373                                 *pp_dgid = &p_pr->dgid;
1374                 } else
1375                         dest_guid = p_pr->dgid.unicast.interface_id;
1376
1377                 *pp_dest_alias_guid = osm_get_alias_guid_by_guid(sa->p_subn,
1378                                                                  dest_guid);
1379                 if (!*pp_dest_alias_guid) {
1380                         /*
1381                            This 'error' is the client's fault (bad gid) so
1382                            don't enter it as an error in our own log.
1383                            Return an error response to the client.
1384                          */
1385                         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1386                                 "No dest port with GUID 0x%016" PRIx64 "\n",
1387                                 cl_ntoh64(dest_guid));
1388                         sa_status = IB_SA_MAD_STATUS_INVALID_GID;
1389                         goto Exit;
1390                 }
1391         }
1392
1393         if (comp_mask & IB_PR_COMPMASK_DLID) {
1394                 *pp_dest_port = osm_get_port_by_lid(sa->p_subn, p_pr->dlid);
1395                 if (!*pp_dest_port) {
1396                         /*
1397                            This 'error' is the client's fault (bad lid)
1398                            so don't enter it as an error in our own log.
1399                            Return an error response to the client.
1400                          */
1401                         OSM_LOG(sa->p_log, OSM_LOG_VERBOSE, "No dest port "
1402                                 "with LID %u\n", cl_ntoh16(p_pr->dlid));
1403                         sa_status = IB_SA_MAD_STATUS_NO_RECORDS;
1404                         goto Exit;
1405                 }
1406         }
1407
1408 Exit:
1409         OSM_LOG_EXIT(sa->p_log);
1410         return sa_status;
1411 }
1412
1413 static void pr_rcv_process_world(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1414                                  IN const osm_port_t * requester_port,
1415                                  IN const ib_gid_t * p_sgid,
1416                                  IN const ib_gid_t * p_dgid,
1417                                  IN cl_qlist_t * p_list)
1418 {
1419         const cl_qmap_t *p_tbl;
1420         const osm_alias_guid_t *p_dest_alias_guid, *p_src_alias_guid;
1421
1422         OSM_LOG_ENTER(sa->p_log);
1423
1424         /*
1425            Iterate the entire port space over itself.
1426            A path record from a port to itself is legit, so no
1427            need for a special case there.
1428
1429            We compute both A -> B and B -> A, since we don't have
1430            any check to determine the reversability of the paths.
1431          */
1432         p_tbl = &sa->p_subn->alias_port_guid_tbl;
1433
1434         p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1435         while (p_dest_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1436                 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1437                 while (p_src_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1438                         pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1439                                                    p_src_alias_guid,
1440                                                    p_dest_alias_guid,
1441                                                    p_sgid, p_dgid, p_list);
1442                         if (sa_mad->method == IB_MAD_METHOD_GET &&
1443                             cl_qlist_count(p_list) > 0)
1444                                 goto Exit;
1445
1446                         p_src_alias_guid =
1447                             (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1448                 }
1449
1450                 p_dest_alias_guid =
1451                     (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1452         }
1453
1454 Exit:
1455         OSM_LOG_EXIT(sa->p_log);
1456 }
1457
1458 void osm_pr_process_half(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1459                                 IN const osm_port_t * requester_port,
1460                                 IN const osm_alias_guid_t * p_src_alias_guid,
1461                                 IN const osm_alias_guid_t * p_dest_alias_guid,
1462                                 IN const ib_gid_t * p_sgid,
1463                                 IN const ib_gid_t * p_dgid,
1464                                 IN cl_qlist_t * p_list)
1465 {
1466         const cl_qmap_t *p_tbl;
1467         const osm_alias_guid_t *p_alias_guid;
1468
1469         OSM_LOG_ENTER(sa->p_log);
1470
1471         /*
1472            Iterate over every port, looking for matches...
1473            A path record from a port to itself is legit, so no
1474            need to special case that one.
1475          */
1476         p_tbl = &sa->p_subn->alias_port_guid_tbl;
1477
1478         if (p_src_alias_guid) {
1479                 /*
1480                    The src port if fixed, so iterate over destination ports.
1481                  */
1482                 p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1483                 while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1484                         pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1485                                                    p_src_alias_guid,
1486                                                    p_alias_guid,
1487                                                    p_sgid, p_dgid, p_list);
1488                         if (sa_mad->method == IB_MAD_METHOD_GET &&
1489                             cl_qlist_count(p_list) > 0)
1490                                 break;
1491                         p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1492                 }
1493         } else {
1494                 /*
1495                    The dest port if fixed, so iterate over source ports.
1496                  */
1497                 p_alias_guid = (osm_alias_guid_t *) cl_qmap_head(p_tbl);
1498                 while (p_alias_guid != (osm_alias_guid_t *) cl_qmap_end(p_tbl)) {
1499                         pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port,
1500                                                    p_alias_guid,
1501                                                    p_dest_alias_guid, p_sgid,
1502                                                    p_dgid, p_list);
1503                         if (sa_mad->method == IB_MAD_METHOD_GET &&
1504                             cl_qlist_count(p_list) > 0)
1505                                 break;
1506                         p_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_alias_guid->map_item);
1507                 }
1508         }
1509
1510         OSM_LOG_EXIT(sa->p_log);
1511 }
1512
1513 void osm_pr_process_pair(IN osm_sa_t * sa, IN const ib_sa_mad_t * sa_mad,
1514                                 IN const osm_port_t * requester_port,
1515                                 IN const osm_alias_guid_t * p_src_alias_guid,
1516                                 IN const osm_alias_guid_t * p_dest_alias_guid,
1517                                 IN const ib_gid_t * p_sgid,
1518                                 IN const ib_gid_t * p_dgid,
1519                                 IN cl_qlist_t * p_list)
1520 {
1521         OSM_LOG_ENTER(sa->p_log);
1522
1523         pr_rcv_get_port_pair_paths(sa, sa_mad, requester_port, p_src_alias_guid,
1524                                    p_dest_alias_guid, p_sgid, p_dgid, p_list);
1525
1526         OSM_LOG_EXIT(sa->p_log);
1527 }
1528
1529 static ib_api_status_t pr_match_mgrp_attributes(IN osm_sa_t * sa,
1530                                                 IN const ib_sa_mad_t * sa_mad,
1531                                                 IN const osm_mgrp_t * p_mgrp)
1532 {
1533         const ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(sa_mad);
1534         ib_net64_t comp_mask = sa_mad->comp_mask;
1535         const osm_port_t *port;
1536         ib_api_status_t status = IB_ERROR;
1537         uint32_t flow_label;
1538         uint8_t sl, hop_limit;
1539
1540         OSM_LOG_ENTER(sa->p_log);
1541
1542         /* check that MLID of the MC group matches the PathRecord DLID */
1543         if ((comp_mask & IB_PR_COMPMASK_DLID) && p_mgrp->mlid != p_pr->dlid) {
1544                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1545                         "DLID 0x%x is not MLID 0x%x for MC group\n",
1546                          cl_ntoh16(p_pr->dlid), cl_ntoh16(p_mgrp->mlid));
1547                 goto Exit;
1548         }
1549
1550         /* If SGID and/or SLID specified, should validate as member of MC group */
1551         if (comp_mask & IB_PR_COMPMASK_SGID) {
1552                 if (!osm_mgrp_get_mcm_alias_guid(p_mgrp,
1553                                                  p_pr->sgid.unicast.interface_id)) {
1554                         char gid_str[INET6_ADDRSTRLEN];
1555                         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1556                                 "SGID %s is not a member of MC group\n",
1557                                 inet_ntop(AF_INET6, p_pr->sgid.raw,
1558                                           gid_str, sizeof gid_str));
1559                         goto Exit;
1560                 }
1561         }
1562
1563         if (comp_mask & IB_PR_COMPMASK_SLID) {
1564                 port = osm_get_port_by_lid(sa->p_subn, p_pr->slid);
1565                 if (!port || !osm_mgrp_get_mcm_port(p_mgrp, port->guid)) {
1566                         OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1567                                 "Either no port with SLID %u found or "
1568                                 "SLID not a member of MC group\n",
1569                                 cl_ntoh16(p_pr->slid));
1570                         goto Exit;
1571                 }
1572         }
1573
1574         /* Also, MTU, rate, packet lifetime, and raw traffic requested are not currently checked */
1575         if ((comp_mask & IB_PR_COMPMASK_PKEY) &&
1576             p_pr->pkey != p_mgrp->mcmember_rec.pkey) {
1577                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1578                         "Pkey 0x%x doesn't match MC group Pkey 0x%x\n",
1579                         cl_ntoh16(p_pr->pkey),
1580                         cl_ntoh16(p_mgrp->mcmember_rec.pkey));
1581                 goto Exit;
1582         }
1583
1584         ib_member_get_sl_flow_hop(p_mgrp->mcmember_rec.sl_flow_hop,
1585                                   &sl, &flow_label, &hop_limit);
1586
1587         if ((comp_mask & IB_PR_COMPMASK_SL) && ib_path_rec_sl(p_pr) != sl) {
1588                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1589                         "SL %d doesn't match MC group SL %d\n",
1590                         ib_path_rec_sl(p_pr), sl);
1591                 goto Exit;
1592         }
1593
1594         /* If SubnAdmGet, assume NumbPaths of 1 (1.2 erratum) */
1595         if ((comp_mask & IB_PR_COMPMASK_NUMBPATH) &&
1596             sa_mad->method != IB_MAD_METHOD_GET &&
1597             ib_path_rec_num_path(p_pr) == 0) {
1598                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1599                         "Number of paths requested is 0\n");
1600                 goto Exit;
1601         }
1602
1603         if ((comp_mask & IB_PR_COMPMASK_FLOWLABEL) &&
1604             ib_path_rec_flow_lbl(p_pr) != flow_label) {
1605                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1606                         "Flow label 0x%x doesn't match MC group "
1607                         " flow label 0x%x\n",
1608                         ib_path_rec_flow_lbl(p_pr), flow_label);
1609                 goto Exit;
1610         }
1611
1612         if ((comp_mask & IB_PR_COMPMASK_HOPLIMIT) &&
1613             ib_path_rec_hop_limit(p_pr) != hop_limit) {
1614                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1615                         "Hop limit %u doesn't match MC group hop limit %u\n",
1616                         ib_path_rec_hop_limit(p_pr), hop_limit);
1617                 goto Exit;
1618         }
1619
1620
1621         if ((comp_mask & IB_PR_COMPMASK_TCLASS) &&
1622             p_pr->tclass != p_mgrp->mcmember_rec.tclass) {
1623                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1624                         "TClass 0x%02x doesn't match MC group TClass 0x%02x\n",
1625                         p_pr->tclass, p_mgrp->mcmember_rec.tclass);
1626                 goto Exit;
1627         }
1628
1629         status = IB_SUCCESS;
1630
1631 Exit:
1632         OSM_LOG_EXIT(sa->p_log);
1633         return status;
1634 }
1635
1636 static void pr_process_multicast(osm_sa_t * sa, const ib_sa_mad_t *sa_mad,
1637                                  cl_qlist_t *list)
1638 {
1639         ib_path_rec_t *pr = ib_sa_mad_get_payload_ptr(sa_mad);
1640         osm_mgrp_t *mgrp;
1641         ib_api_status_t status;
1642         osm_sa_item_t *pr_item;
1643         uint32_t flow_label;
1644         uint8_t sl, hop_limit;
1645
1646         OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Multicast destination requested\n");
1647
1648         mgrp = osm_get_mgrp_by_mgid(sa->p_subn, &pr->dgid);
1649         if (!mgrp) {
1650                 char gid_str[INET6_ADDRSTRLEN];
1651                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F09: "
1652                         "No MC group found for PathRecord destination GID %s\n",
1653                         inet_ntop(AF_INET6, pr->dgid.raw, gid_str,
1654                                   sizeof gid_str));
1655                 return;
1656         }
1657
1658         /* Make sure the rest of the PathRecord matches the MC group attributes */
1659         status = pr_match_mgrp_attributes(sa, sa_mad, mgrp);
1660         if (status != IB_SUCCESS) {
1661                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F19: "
1662                         "MC group attributes don't match PathRecord request\n");
1663                 return;
1664         }
1665
1666         pr_item = malloc(SA_PR_RESP_SIZE);
1667         if (pr_item == NULL) {
1668                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F18: "
1669                         "Unable to allocate path record for MC group\n");
1670                 return;
1671         }
1672         memset(pr_item, 0, sizeof(cl_list_item_t));
1673
1674         /* Copy PathRecord request into response */
1675         pr_item->resp.path_rec = *pr;
1676
1677         /* Now, use the MC info to cruft up the PathRecord response */
1678         pr_item->resp.path_rec.dgid = mgrp->mcmember_rec.mgid;
1679         pr_item->resp.path_rec.dlid = mgrp->mcmember_rec.mlid;
1680         pr_item->resp.path_rec.tclass = mgrp->mcmember_rec.tclass;
1681         pr_item->resp.path_rec.num_path = 1;
1682         pr_item->resp.path_rec.pkey = mgrp->mcmember_rec.pkey;
1683
1684         /* MTU, rate, and packet lifetime should be exactly */
1685         pr_item->resp.path_rec.mtu = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.mtu;
1686         pr_item->resp.path_rec.rate = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.rate;
1687         pr_item->resp.path_rec.pkt_life = (IB_PATH_SELECTOR_EXACTLY << 6) | mgrp->mcmember_rec.pkt_life;
1688
1689         /* SL, Hop Limit, and Flow Label */
1690         ib_member_get_sl_flow_hop(mgrp->mcmember_rec.sl_flow_hop,
1691                                   &sl, &flow_label, &hop_limit);
1692         ib_path_rec_set_sl(&pr_item->resp.path_rec, sl);
1693         ib_path_rec_set_qos_class(&pr_item->resp.path_rec, 0);
1694
1695         /* HopLimit is not yet set in non link local MC groups */
1696         /* If it were, this would not be needed */
1697         if (ib_mgid_get_scope(&mgrp->mcmember_rec.mgid) !=
1698             IB_MC_SCOPE_LINK_LOCAL)
1699                 hop_limit = IB_HOPLIMIT_MAX;
1700
1701         pr_item->resp.path_rec.hop_flow_raw =
1702             cl_hton32(hop_limit) | (flow_label << 8);
1703
1704         cl_qlist_insert_tail(list, &pr_item->list_item);
1705 }
1706
1707 void osm_pr_rcv_process(IN void *context, IN void *data)
1708 {
1709         osm_sa_t *sa = context;
1710         osm_madw_t *p_madw = data;
1711         const ib_sa_mad_t *p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
1712         ib_path_rec_t *p_pr = ib_sa_mad_get_payload_ptr(p_sa_mad);
1713         cl_qlist_t pr_list;
1714         const ib_gid_t *p_sgid = NULL, *p_dgid = NULL;
1715         const osm_alias_guid_t *p_src_alias_guid, *p_dest_alias_guid;
1716         const osm_port_t *p_src_port, *p_dest_port;
1717         osm_port_t *requester_port;
1718         uint8_t rate, mtu;
1719
1720         OSM_LOG_ENTER(sa->p_log);
1721
1722         CL_ASSERT(p_madw);
1723
1724         CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_PATH_RECORD);
1725
1726         /* we only support SubnAdmGet and SubnAdmGetTable methods */
1727         if (p_sa_mad->method != IB_MAD_METHOD_GET &&
1728             p_sa_mad->method != IB_MAD_METHOD_GETTABLE) {
1729                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F17: "
1730                         "Unsupported Method (%s) for PathRecord request\n",
1731                         ib_get_sa_method_str(p_sa_mad->method));
1732                 osm_sa_send_error(sa, p_madw, IB_MAD_STATUS_UNSUP_METHOD_ATTR);
1733                 goto Exit;
1734         }
1735
1736         /* Validate rate if supplied */
1737         if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_RATESELEC) &&
1738             (p_sa_mad->comp_mask & IB_PR_COMPMASK_RATE)) {
1739                 rate = ib_path_rec_rate(p_pr);
1740                 if (!ib_rate_is_valid(rate)) {
1741                         osm_sa_send_error(sa, p_madw,
1742                                           IB_SA_MAD_STATUS_REQ_INVALID);
1743                         goto Exit;
1744                 }
1745         }
1746         /* Validate MTU if supplied */
1747         if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_MTUSELEC) &&
1748             (p_sa_mad->comp_mask & IB_PR_COMPMASK_MTU)) {
1749                 mtu = ib_path_rec_mtu(p_pr);
1750                 if (!ib_mtu_is_valid(mtu)) {
1751                         osm_sa_send_error(sa, p_madw,
1752                                           IB_SA_MAD_STATUS_REQ_INVALID);
1753                         goto Exit;
1754                 }
1755         }
1756
1757         /* Make sure either none or both ServiceID parameters are supplied */
1758         if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) != 0 &&
1759             (p_sa_mad->comp_mask & IB_PR_COMPMASK_SERVICEID) !=
1760              IB_PR_COMPMASK_SERVICEID) {
1761                 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_INSUF_COMPS);
1762                 goto Exit;
1763         }
1764
1765         cl_qlist_init(&pr_list);
1766
1767         /*
1768            Most SA functions (including this one) are read-only on the
1769            subnet object, so we grab the lock non-exclusively.
1770          */
1771         cl_plock_acquire(sa->p_lock);
1772
1773         /* update the requester physical port */
1774         requester_port = osm_get_port_by_mad_addr(sa->p_log, sa->p_subn,
1775                                                   osm_madw_get_mad_addr_ptr
1776                                                   (p_madw));
1777         if (requester_port == NULL) {
1778                 cl_plock_release(sa->p_lock);
1779                 OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1F16: "
1780                         "Cannot find requester physical port\n");
1781                 goto Exit;
1782         }
1783
1784         if (OSM_LOG_IS_ACTIVE_V2(sa->p_log, OSM_LOG_DEBUG)) {
1785                 OSM_LOG(sa->p_log, OSM_LOG_DEBUG,
1786                         "Requester port GUID 0x%" PRIx64 "\n",
1787                         cl_ntoh64(osm_port_get_guid(requester_port)));
1788                 osm_dump_path_record_v2(sa->p_log, p_pr, FILE_ID, OSM_LOG_DEBUG);
1789         }
1790
1791         /* Handle multicast destinations separately */
1792         if ((p_sa_mad->comp_mask & IB_PR_COMPMASK_DGID) &&
1793             ib_gid_is_multicast(&p_pr->dgid)) {
1794                 pr_process_multicast(sa, p_sa_mad, &pr_list);
1795                 goto Unlock;
1796         }
1797
1798         OSM_LOG(sa->p_log, OSM_LOG_DEBUG, "Unicast destination requested\n");
1799
1800         if (osm_pr_get_end_points(sa, p_sa_mad,
1801                                   &p_src_alias_guid, &p_dest_alias_guid,
1802                                   &p_src_port, &p_dest_port,
1803                                   &p_sgid, &p_dgid) != IB_SA_MAD_STATUS_SUCCESS)
1804                 goto Unlock;
1805
1806         if (p_src_alias_guid && p_src_port &&
1807             p_src_alias_guid->p_base_port != p_src_port) {
1808                 cl_plock_release(sa->p_lock);
1809                 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1810                         "Requester port GUID 0x%" PRIx64 ": Port for SGUID "
1811                         "0x%" PRIx64 " not same as port for SLID %u\n",
1812                         cl_ntoh64(osm_port_get_guid(requester_port)),
1813                         cl_ntoh64(p_pr->sgid.unicast.interface_id),
1814                         cl_ntoh16(p_pr->slid));
1815                 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1816                 goto Exit;
1817         }
1818
1819         if (p_dest_alias_guid && p_dest_port &&
1820             p_dest_alias_guid->p_base_port != p_dest_port) {
1821                 cl_plock_release(sa->p_lock);
1822                 OSM_LOG(sa->p_log, OSM_LOG_VERBOSE,
1823                         "Requester port GUID 0x%" PRIx64 ": Port for DGUID "
1824                         "0x%" PRIx64 " not same as port for DLID %u\n",
1825                         cl_ntoh64(osm_port_get_guid(requester_port)),
1826                         cl_ntoh64(p_pr->dgid.unicast.interface_id),
1827                         cl_ntoh16(p_pr->dlid));
1828                 osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
1829                 goto Exit;
1830         }
1831
1832         /*
1833            What happens next depends on the type of endpoint information
1834            that was specified....
1835          */
1836         if (p_src_alias_guid) {
1837                 if (p_dest_alias_guid)
1838                         osm_pr_process_pair(sa, p_sa_mad, requester_port,
1839                                             p_src_alias_guid, p_dest_alias_guid,
1840                                             p_sgid, p_dgid, &pr_list);
1841                 else if (!p_dest_port)
1842                         osm_pr_process_half(sa, p_sa_mad, requester_port,
1843                                             p_src_alias_guid, NULL, p_sgid,
1844                                             p_dgid, &pr_list);
1845                 else {
1846                         /* Get all alias GUIDs for the dest port */
1847                         p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1848                         while (p_dest_alias_guid !=
1849                                (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1850                                 if (osm_get_port_by_alias_guid(sa->p_subn, p_dest_alias_guid->alias_guid) ==
1851                                     p_dest_port)
1852                                         osm_pr_process_pair(sa, p_sa_mad,
1853                                                             requester_port,
1854                                                             p_src_alias_guid,
1855                                                             p_dest_alias_guid,
1856                                                             p_sgid, p_dgid,
1857                                                             &pr_list);
1858                                 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1859                                     cl_qlist_count(&pr_list) > 0)
1860                                         break;
1861
1862                                 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1863                         }
1864                 }
1865         } else {
1866                 if (p_dest_alias_guid && !p_src_port)
1867                         osm_pr_process_half(sa, p_sa_mad, requester_port,
1868                                             NULL, p_dest_alias_guid, p_sgid,
1869                                             p_dgid, &pr_list);
1870                 else if (!p_src_port && !p_dest_port)
1871                         /*
1872                            Katie, bar the door!
1873                          */
1874                         pr_rcv_process_world(sa, p_sa_mad, requester_port,
1875                                              p_sgid, p_dgid, &pr_list);
1876                 else if (p_dest_alias_guid && p_src_port) {
1877                         /* Get all alias GUIDs for the src port */
1878                         p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1879                         while (p_src_alias_guid !=
1880                                (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1881                                 if (osm_get_port_by_alias_guid(sa->p_subn,
1882                                                                p_src_alias_guid->alias_guid) ==
1883                                     p_src_port)
1884                                         osm_pr_process_pair(sa, p_sa_mad,
1885                                                             requester_port,
1886                                                             p_src_alias_guid,
1887                                                             p_dest_alias_guid,
1888                                                             p_sgid, p_dgid,
1889                                                             &pr_list);
1890                                 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1891                                     cl_qlist_count(&pr_list) > 0)
1892                                         break;
1893                                 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1894                         }
1895                 } else if (p_src_port && !p_dest_port) {
1896                         /* Get all alias GUIDs for the src port */
1897                         p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1898                         while (p_src_alias_guid !=
1899                                (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1900                                 if (osm_get_port_by_alias_guid(sa->p_subn,
1901                                                                p_src_alias_guid->alias_guid) ==
1902                                     p_src_port)
1903                                         osm_pr_process_half(sa, p_sa_mad,
1904                                                             requester_port,
1905                                                             p_src_alias_guid,
1906                                                             NULL, p_sgid,
1907                                                             p_dgid, &pr_list);
1908                                 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1909                         }
1910                 } else if (p_dest_port && !p_src_port) {
1911                         /* Get all alias GUIDs for the dest port */
1912                         p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1913                         while (p_dest_alias_guid !=
1914                                (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1915                                 if (osm_get_port_by_alias_guid(sa->p_subn,
1916                                                                p_dest_alias_guid->alias_guid) ==
1917                                     p_dest_port)
1918                                         osm_pr_process_half(sa, p_sa_mad,
1919                                                             requester_port,
1920                                                             NULL,
1921                                                             p_dest_alias_guid,
1922                                                             p_sgid, p_dgid,
1923                                                             &pr_list);
1924                                 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1925                         }
1926                 } else {
1927                         /* Get all alias GUIDs for the src port */
1928                         p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1929                         while (p_src_alias_guid !=
1930                                (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1931                                 if (osm_get_port_by_alias_guid(sa->p_subn,
1932                                                                p_src_alias_guid->alias_guid) ==
1933                                     p_src_port) {
1934                                         /* Get all alias GUIDs for the dest port */
1935                                         p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_head(&sa->p_subn->alias_port_guid_tbl);
1936                                         while (p_dest_alias_guid !=
1937                                                (osm_alias_guid_t *) cl_qmap_end(&sa->p_subn->alias_port_guid_tbl)) {
1938                                                 if (osm_get_port_by_alias_guid(sa->p_subn,
1939                                                                                p_dest_alias_guid->alias_guid) ==
1940                                                     p_dest_port)
1941                                                 osm_pr_process_pair(sa,
1942                                                                     p_sa_mad,
1943                                                                     requester_port,
1944                                                                     p_src_alias_guid,
1945                                                                     p_dest_alias_guid,
1946                                                                     p_sgid,
1947                                                                     p_dgid,
1948                                                                     &pr_list);
1949                                                 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1950                                                     cl_qlist_count(&pr_list) > 0)
1951                                                         break;
1952                                                 p_dest_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_dest_alias_guid->map_item);
1953                                         }
1954                                 }
1955                                 if (p_sa_mad->method == IB_MAD_METHOD_GET &&
1956                                     cl_qlist_count(&pr_list) > 0)
1957                                         break;
1958                                 p_src_alias_guid = (osm_alias_guid_t *) cl_qmap_next(&p_src_alias_guid->map_item);
1959                         }
1960                 }
1961         }
1962
1963 Unlock:
1964         cl_plock_release(sa->p_lock);
1965
1966         /* Now, (finally) respond to the PathRecord request */
1967         osm_sa_respond(sa, p_madw, sizeof(ib_path_rec_t), &pr_list);
1968
1969 Exit:
1970         OSM_LOG_EXIT(sa->p_log);
1971 }