[openib-general] [RFC] [PATCH] OpenSM: Add support for SA MultiPathRecord
Hal Rosenstock
halr at voltaire.com
Fri May 5 10:52:15 PDT 2006
OpenSM: Add support for SA MultiPathRecord
Add the optional support for SA MultiPathRecord. This is an initial
implementation. Note that this capability is not enabled in the build
just yet.
Signed-off-by: Hal Rosenstock <halr at voltaire.com>
Index: osm/include/opensm/osm_sa_multipath_record.h
===================================================================
--- osm/include/opensm/osm_sa_multipath_record.h (revision 0)
+++ osm/include/opensm/osm_sa_multipath_record.h (revision 0)
@@ -0,0 +1,275 @@
+/*
+ * Copyright (c) 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+
+/*
+ * Abstract:
+ * Declaration of osm_mpr_rcv_t.
+ * This object represents the MultiPathRecord Receiver object.
+ * attribute from a node.
+ * This object is part of the OpenSM family of objects.
+ *
+ * Environment:
+ * Linux User Mode
+ *
+ */
+
+#ifndef _OSM_MPR_RCV_H_
+#define _OSM_MPR_RCV_H_
+
+#include <complib/cl_passivelock.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_qlockpool.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_sa_response.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_state_mgr.h>
+
+#ifdef __cplusplus
+# define BEGIN_C_DECLS extern "C" {
+# define END_C_DECLS }
+#else /* !__cplusplus */
+# define BEGIN_C_DECLS
+# define END_C_DECLS
+#endif /* __cplusplus */
+
+BEGIN_C_DECLS
+
+/****h* OpenSM/MultiPath Record Receiver
+* NAME
+* MultiPath Record Receiver
+*
+* DESCRIPTION
+* The MultiPath Record Receiver object encapsulates the information
+* needed to receive the PathRecord request from a node.
+*
+* The MultiPath Record Receiver object is thread safe.
+*
+* This object should be treated as opaque and should be
+* manipulated only through the provided functions.
+*
+* AUTHOR
+* Hal Rosenstock, Voltaire
+*
+*********/
+
+/****s* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_t
+* NAME
+* osm_mpr_rcv_t
+*
+* DESCRIPTION
+* MultiPath Record Receiver structure.
+*
+* This object should be treated as opaque and should
+* be manipulated only through the provided functions.
+*
+* SYNOPSIS
+*/
+typedef struct _osm_mpr_rcv
+{
+ osm_subn_t *p_subn;
+ osm_sa_resp_t *p_resp;
+ osm_mad_pool_t *p_mad_pool;
+ osm_log_t *p_log;
+ cl_plock_t *p_lock;
+ cl_qlock_pool_t pr_pool;
+} osm_mpr_rcv_t;
+/*
+* FIELDS
+* p_subn
+* Pointer to the Subnet object for this subnet.
+*
+* p_gen_req_ctrl
+* Pointer to the generic request controller.
+*
+* p_log
+* Pointer to the log object.
+*
+* p_lock
+* Pointer to the serializing lock.
+*
+* pr_pool
+* Pool of multipath record objects used to generate query responses.
+*
+* SEE ALSO
+* MultiPath Record Receiver object
+*********/
+
+/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_construct
+* NAME
+* osm_mpr_rcv_construct
+*
+* DESCRIPTION
+* This function constructs a MultiPath Record Receiver object.
+*
+* SYNOPSIS
+*/
+void
+osm_mpr_rcv_construct(
+ IN osm_mpr_rcv_t* const p_rcv );
+/*
+* PARAMETERS
+* p_rcv
+* [in] Pointer to a MultiPath Record Receiver object to construct.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* NOTES
+* Allows calling osm_mpr_rcv_init, osm_mpr_rcv_destroy
+*
+* Calling osm_mpr_rcv_construct is a prerequisite to calling any other
+* method except osm_mpr_rcv_init.
+*
+* SEE ALSO
+* MultiPath Record Receiver object, osm_mpr_rcv_init, osm_mpr_rcv_destroy
+*********/
+
+/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_destroy
+* NAME
+* osm_mpr_rcv_destroy
+*
+* DESCRIPTION
+* The osm_mpr_rcv_destroy function destroys the object, releasing
+* all resources.
+*
+* SYNOPSIS
+*/
+void
+osm_mpr_rcv_destroy(
+ IN osm_mpr_rcv_t* const p_rcv );
+/*
+* PARAMETERS
+* p_rcv
+* [in] Pointer to the object to destroy.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* NOTES
+* Performs any necessary cleanup of the specified
+* MultiPath Record Receiver object.
+* Further operations should not be attempted on the destroyed object.
+* This function should only be called after a call to
+* osm_mpr_rcv_construct or osm_mpr_rcv_init.
+*
+* SEE ALSO
+* MultiPath Record Receiver object, osm_mpr_rcv_construct,
+* osm_mpr_rcv_init
+*********/
+
+/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_init
+* NAME
+* osm_mpr_rcv_init
+*
+* DESCRIPTION
+* The osm_mpr_rcv_init function initializes a
+* MultiPath Record Receiver object for use.
+*
+* SYNOPSIS
+*/
+ib_api_status_t
+osm_mpr_rcv_init(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN osm_sa_resp_t* const p_resp,
+ IN osm_mad_pool_t* const p_mad_pool,
+ IN osm_subn_t* const p_subn,
+ IN osm_log_t* const p_log,
+ IN cl_plock_t* const p_lock );
+/*
+* PARAMETERS
+* p_rcv
+* [in] Pointer to an osm_mpr_rcv_t object to initialize.
+*
+* p_subn
+* [in] Pointer to the Subnet object for this subnet.
+*
+* p_log
+* [in] Pointer to the log object.
+*
+* p_lock
+* [in] Pointer to the OpenSM serializing lock.
+*
+* RETURN VALUES
+* IB_SUCCESS if the MultiPath Record Receiver object was initialized
+* successfully.
+*
+* NOTES
+* Allows calling other MultiPath Record Receiver methods.
+*
+* SEE ALSO
+* MultiPath Record Receiver object, osm_mpr_rcv_construct,
+* osm_mpr_rcv_destroy
+*********/
+
+/****f* OpenSM: MultiPath Record Receiver/osm_mpr_rcv_process
+* NAME
+* osm_mpr_rcv_process
+*
+* DESCRIPTION
+* Process the MultiPathRecord request.
+*
+* SYNOPSIS
+*/
+void
+osm_mpr_rcv_process(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN osm_madw_t* const p_madw );
+/*
+* PARAMETERS
+* p_rcv
+* [in] Pointer to an osm_mpr_rcv_t object.
+*
+* p_madw
+* [in] Pointer to the MAD Wrapper containing the MAD
+* that contains the node's MultiPathRecord attribute.
+*
+* RETURN VALUES
+* IB_SUCCESS if the MultiPathRecord processing was successful.
+*
+* NOTES
+* This function processes a MultiPathRecord attribute.
+*
+* SEE ALSO
+* MultiPath Record Receiver, Node Info Response Controller
+*********/
+
+END_C_DECLS
+
+#endif /* _OSM_MPR_RCV_H_ */
Property changes on: osm/include/opensm/osm_sa_multipath_record.h
___________________________________________________________________
Name: svn:keywords
+ Id
Index: osm/include/opensm/osm_helper.h
===================================================================
--- osm/include/opensm/osm_helper.h (revision 6920)
+++ osm/include/opensm/osm_helper.h (working copy)
@@ -217,6 +217,12 @@ osm_dump_path_record(
IN const osm_log_level_t log_level );
void
+osm_dump_multipath_record(
+ IN osm_log_t* const p_log,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_log_level_t log_level );
+
+void
osm_dump_node_record(
IN osm_log_t* const p_log,
IN const ib_node_record_t* const p_nr,
Index: osm/include/opensm/osm_sa.h
===================================================================
--- osm/include/opensm/osm_sa.h (revision 6920)
+++ osm/include/opensm/osm_sa.h (working copy)
@@ -67,6 +67,7 @@
#include <opensm/osm_sa_guidinfo_record_ctrl.h>
#include <opensm/osm_sa_link_record_ctrl.h>
#include <opensm/osm_sa_path_record_ctrl.h>
+#include <opensm/osm_sa_multipath_record_ctrl.h>
#include <opensm/osm_sa_sminfo_record_ctrl.h>
#include <opensm/osm_sa_mad_ctrl.h>
#include <opensm/osm_sa_mcmember_record_ctrl.h>
@@ -167,7 +168,11 @@ typedef struct _osm_sa
osm_mcmr_rcv_ctrl_t mcmr_rcv_ctlr;
osm_sr_rcv_t sr_rcv;
osm_sr_rcv_ctrl_t sr_rcv_ctrl;
-
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ osm_mpr_rcv_t mpr_rcv;
+ osm_mpr_rcv_ctrl_t mpr_rcv_ctrl;
+#endif
+
/* InformInfo Receiver */
osm_infr_rcv_t infr_rcv;
osm_infr_rcv_ctrl_t infr_rcv_ctrl;
Index: osm/include/opensm/osm_msgdef.h
===================================================================
--- osm/include/opensm/osm_msgdef.h (revision 6920)
+++ osm/include/opensm/osm_msgdef.h (working copy)
@@ -192,6 +192,9 @@ enum
OSM_MSG_MAD_VL_ARB,
OSM_MSG_MAD_SLVL,
OSM_MSG_MAD_GUIDINFO_RECORD,
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ OSM_MSG_MAD_MULTIPATH_RECORD,
+#endif
OSM_MSG_MAX
};
Index: osm/include/opensm/osm_sa_multipath_record_ctrl.h
===================================================================
--- osm/include/opensm/osm_sa_multipath_record_ctrl.h (revision 0)
+++ osm/include/opensm/osm_sa_multipath_record_ctrl.h (revision 0)
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+
+/*
+ * Abstract:
+ * Declaration of osm_mpr_rcv_ctrl_t.
+ * This object represents a controller that receives the IBA
+ * MultiPathRecord attribute from a node.
+ * This object is part of the OpenSM family of objects.
+ *
+ * Environment:
+ * Linux User Mode
+ *
+ */
+
+
+#ifndef _OSM_MPRCTRL_H_
+#define _OSM_MPRCTRL_H_
+
+
+#include <complib/cl_dispatcher.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_sa_multipath_record.h>
+
+#ifdef __cplusplus
+# define BEGIN_C_DECLS extern "C" {
+# define END_C_DECLS }
+#else /* !__cplusplus */
+# define BEGIN_C_DECLS
+# define END_C_DECLS
+#endif /* __cplusplus */
+
+BEGIN_C_DECLS
+
+/****h* OpenSM/MultiPath Record Receive Controller
+* NAME
+* MultiPath Record Receive Controller
+*
+* DESCRIPTION
+* The MultiPath Record Receive Controller object encapsulates
+* the information needed to receive the MultiPathRecord attribute from a node.
+*
+* The MultiPath record Receive Controller object is thread safe.
+*
+* This object should be treated as opaque and should be
+* manipulated only through the provided functions.
+*
+* AUTHOR
+* Hal Rosenstock, Voltaire
+*
+*********/
+/****s* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_t
+* NAME
+* osm_mpr_rcv_ctrl_t
+*
+* DESCRIPTION
+* MultiPath Record Receive Controller structure.
+*
+* This object should be treated as opaque and should
+* be manipulated only through the provided functions.
+*
+* SYNOPSIS
+*/
+typedef struct _osm_mpr_rcv_ctrl
+{
+ osm_mpr_rcv_t *p_rcv;
+ osm_log_t *p_log;
+ cl_dispatcher_t *p_disp;
+ cl_disp_reg_handle_t h_disp;
+
+} osm_mpr_rcv_ctrl_t;
+/*
+* FIELDS
+* p_rcv
+* Pointer to the MultiPath Record Receiver object.
+*
+* p_log
+* Pointer to the log object.
+*
+* p_disp
+* Pointer to the Dispatcher.
+*
+* h_disp
+* Handle returned from dispatcher registration.
+*
+* SEE ALSO
+* MultiPath Record Receive Controller object
+* MultiPath Record Receiver object
+*********/
+
+/****f* OpenSM: MultiPath Record Receive Controller/osm_pr_rcv_ctrl_construct
+* NAME
+* osm_mpr_rcv_ctrl_construct
+*
+* DESCRIPTION
+* This function constructs a MultiPath Record Receive Controller object.
+*
+* SYNOPSIS
+*/
+void osm_mpr_rcv_ctrl_construct(
+ IN osm_mpr_rcv_ctrl_t* const p_ctrl );
+/*
+* PARAMETERS
+* p_ctrl
+* [in] Pointer to a MultiPath Record Receive Controller
+* object to construct.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* NOTES
+* Allows calling osm_mpr_rcv_ctrl_init, osm_mpr_rcv_ctrl_destroy,
+* and osm_mpr_rcv_ctrl_is_inited.
+*
+* Calling osm_mpr_rcv_ctrl_construct is a prerequisite to calling any
+* other method except osm_mpr_rcv_ctrl_init.
+*
+* SEE ALSO
+* MultiPath Record Receive Controller object, osm_mpr_rcv_ctrl_init,
+* osm_mpr_rcv_ctrl_destroy, osm_mpr_rcv_ctrl_is_inited
+*********/
+
+/****f* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_destroy
+* NAME
+* osm_mpr_rcv_ctrl_destroy
+*
+* DESCRIPTION
+* The osm_mpr_rcv_ctrl_destroy function destroys the object, releasing
+* all resources.
+*
+* SYNOPSIS
+*/
+void osm_mpr_rcv_ctrl_destroy(
+ IN osm_mpr_rcv_ctrl_t* const p_ctrl );
+/*
+* PARAMETERS
+* p_ctrl
+* [in] Pointer to the object to destroy.
+*
+* RETURN VALUE
+* This function does not return a value.
+*
+* NOTES
+* Performs any necessary cleanup of the specified
+* MultiPath Record Receive Controller object.
+* Further operations should not be attempted on the destroyed object.
+* This function should only be called after a call to
+* osm_mpr_rcv_ctrl_construct or osm_mpr_rcv_ctrl_init.
+*
+* SEE ALSO
+* MultiPath Record Receive Controller object, osm_mpr_rcv_ctrl_construct,
+* osm_mpr_rcv_ctrl_init
+*********/
+
+/****f* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_init
+* NAME
+* osm_mpr_rcv_ctrl_init
+*
+* DESCRIPTION
+* The osm_mpr_rcv_ctrl_init function initializes a
+* MultiPath Record Receive Controller object for use.
+*
+* SYNOPSIS
+*/
+ib_api_status_t osm_mpr_rcv_ctrl_init(
+ IN osm_mpr_rcv_ctrl_t* const p_ctrl,
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN osm_log_t* const p_log,
+ IN cl_dispatcher_t* const p_disp );
+/*
+* PARAMETERS
+* p_ctrl
+* [in] Pointer to an osm_mpr_rcv_ctrl_t object to initialize.
+*
+* p_rcv
+* [in] Pointer to an osm_mpr_t object.
+*
+* p_log
+* [in] Pointer to the log object.
+*
+* p_disp
+* [in] Pointer to the OpenSM central Dispatcher.
+*
+* RETURN VALUES
+* CL_SUCCESS if the MultiPath Record Receive Controller object was
+* initialized successfully.
+*
+* NOTES
+* Allows calling other MultiPath Record Receive Controller methods.
+*
+* SEE ALSO
+* MultiPath Record Receive Controller object, osm_pr_rcv_ctrl_construct,
+* osm_mpr_rcv_ctrl_destroy, osm_mpr_rcv_ctrl_is_inited
+*********/
+
+/****f* OpenSM: MultiPath Record Receive Controller/osm_mpr_rcv_ctrl_is_inited
+* NAME
+* osm_mpr_rcv_ctrl_is_inited
+*
+* DESCRIPTION
+* Indicates if the object has been initialized with osm_mpr_rcv_ctrl_init.
+*
+* SYNOPSIS
+*/
+boolean_t osm_mpr_rcv_ctrl_is_inited(
+ IN const osm_mpr_rcv_ctrl_t* const p_ctrl );
+/*
+* PARAMETERS
+* p_ctrl
+* [in] Pointer to an osm_mpr_rcv_ctrl_t object.
+*
+* RETURN VALUES
+* TRUE if the object was initialized successfully,
+* FALSE otherwise.
+*
+* NOTES
+* The osm_mpr_rcv_ctrl_construct or osm_mpr_rcv_ctrl_init must be
+* called before using this function.
+*
+* SEE ALSO
+* MultiPath Record Receive Controller object, osm_mpr_rcv_ctrl_construct,
+* osm_mpr_rcv_ctrl_init
+*********/
+
+END_C_DECLS
+
+#endif /* _OSM_MPRCTRL_H_ */
Property changes on: osm/include/opensm/osm_sa_multipath_record_ctrl.h
___________________________________________________________________
Name: svn:keywords
+ Id
Index: osm/include/Makefile.am
===================================================================
--- osm/include/Makefile.am (revision 6920)
+++ osm/include/Makefile.am (working copy)
@@ -8,6 +8,7 @@ EXTRA_DIST = \
$(srcdir)/opensm/osm_version.h \
$(srcdir)/opensm/osm_sa_portinfo_record_ctrl.h \
$(srcdir)/opensm/osm_sa_guidinfo_record_ctrl.h \
+ $(srcdir)/opensm/osm_sa_multipath_record_ctrl.h \
$(srcdir)/opensm/osm_sa_path_record.h \
$(srcdir)/opensm/osm_lid_mgr.h \
$(srcdir)/opensm/osm_vl_arb_rcv.h \
@@ -37,6 +38,7 @@ EXTRA_DIST = \
$(srcdir)/opensm/osm_helper.h \
$(srcdir)/opensm/osm_sa_portinfo_record.h \
$(srcdir)/opensm/osm_sa_guidinfo_record.h \
+ $(srcdir)/opensm/osm_sa_multipath_record.h \
$(srcdir)/opensm/osm_sa_service_record.h \
$(srcdir)/opensm/osm_sa_response.h \
$(srcdir)/opensm/osm_node.h \
Index: osm/include/iba/ib_types.h
===================================================================
--- osm/include/iba/ib_types.h (revision 6920)
+++ osm/include/iba/ib_types.h (working copy)
@@ -1615,6 +1615,17 @@ ib_class_is_rmpp(
* SOURCE
*/
#define IB_PATH_REC_SELECTOR_MASK 0xC0
+/****d* IBA Base: Constants/IB_MULTIPATH_REC_SELECTOR_MASK
+* NAME
+* IB_MULTIPATH_REC_SELECTOR_MASK
+*
+* DESCRIPTION
+* Mask for the selector field for multipath record MTU, rate,
+* and packet lifetime.
+*
+* SOURCE
+*/
+#define IB_MULTIPATH_REC_SELECTOR_MASK 0xC0
/**********/
/****d* IBA Base: Constants/IB_PATH_REC_BASE_MASK
* NAME
@@ -1628,6 +1639,18 @@ ib_class_is_rmpp(
*/
#define IB_PATH_REC_BASE_MASK 0x3F
/**********/
+/****d* IBA Base: Constants/IB_MULTIPATH_REC_BASE_MASK
+* NAME
+* IB_MULTIPATH_REC_BASE_MASK
+*
+* DESCRIPTION
+* Mask for the base value field for multipath record MTU, rate,
+* and packet lifetime.
+*
+* SOURCE
+*/
+#define IB_MULTIPATH_REC_BASE_MASK 0x3F
+/**********/
/****h* IBA Base/Type Definitions
* NAME
@@ -2401,6 +2424,72 @@ typedef struct _ib_path_rec
#define IB_GIR_COMPMASK_GID6 (CL_HTON64(((uint64_t)1)<<10))
#define IB_GIR_COMPMASK_GID7 (CL_HTON64(((uint64_t)1)<<11))
+/* MultiPath Record Component Masks */
+#define IB_MPR_COMPMASK_RAWTRAFFIC (CL_HTON64(((uint64_t)1)<<0))
+#define IB_MPR_COMPMASK_RESV0 (CL_HTON64(((uint64_t)1)<<1))
+#define IB_MPR_COMPMASK_FLOWLABEL (CL_HTON64(((uint64_t)1)<<2))
+#define IB_MPR_COMPMASK_HOPLIMIT (CL_HTON64(((uint64_t)1)<<3))
+#define IB_MPR_COMPMASK_TCLASS (CL_HTON64(((uint64_t)1)<<4))
+#define IB_MPR_COMPMASK_REVERSIBLE (CL_HTON64(((uint64_t)1)<<5))
+#define IB_MPR_COMPMASK_NUMBPATH (CL_HTON64(((uint64_t)1)<<6))
+#define IB_MPR_COMPMASK_PKEY (CL_HTON64(((uint64_t)1)<<7))
+#define IB_MPR_COMPMASK_RESV1 (CL_HTON64(((uint64_t)1)<<8))
+#define IB_MPR_COMPMASK_SL (CL_HTON64(((uint64_t)1)<<9))
+#define IB_MPR_COMPMASK_MTUSELEC (CL_HTON64(((uint64_t)1)<<10))
+#define IB_MPR_COMPMASK_MTU (CL_HTON64(((uint64_t)1)<<11))
+#define IB_MPR_COMPMASK_RATESELEC (CL_HTON64(((uint64_t)1)<<12))
+#define IB_MPR_COMPMASK_RATE (CL_HTON64(((uint64_t)1)<<13))
+#define IB_MPR_COMPMASK_PKTLIFETIMESELEC (CL_HTON64(((uint64_t)1)<<14))
+#define IB_MPR_COMPMASK_PKTLIFETIME (CL_HTON64(((uint64_t)1)<<15))
+#define IB_MPR_COMPMASK_RESV2 (CL_HTON64(((uint64_t)1)<<16))
+#define IB_MPR_COMPMASK_INDEPSELEC (CL_HTON64(((uint64_t)1)<<17))
+#define IB_MPR_COMPMASK_RESV3 (CL_HTON64(((uint64_t)1)<<18))
+#define IB_MPR_COMPMASK_SGIDCOUNT (CL_HTON64(((uint64_t)1)<<19))
+#define IB_MPR_COMPMASK_DGIDCOUNT (CL_HTON64(((uint64_t)1)<<20))
+#define IB_MPR_COMPMASK_RESV4 (CL_HTON64(((uint64_t)1)<<21))
+#define IB_MPR_COMPMASK_SDGID1 (CL_HTON64(((uint64_t)1)<<22))
+#define IB_MPR_COMPMASK_SDGID2 (CL_HTON64(((uint64_t)1)<<23))
+#define IB_MPR_COMPMASK_SDGID3 (CL_HTON64(((uint64_t)1)<<24))
+#define IB_MPR_COMPMASK_SDGID4 (CL_HTON64(((uint64_t)1)<<25))
+#define IB_MPR_COMPMASK_SDGID5 (CL_HTON64(((uint64_t)1)<<26))
+#define IB_MPR_COMPMASK_SDGID6 (CL_HTON64(((uint64_t)1)<<27))
+#define IB_MPR_COMPMASK_SDGID7 (CL_HTON64(((uint64_t)1)<<28))
+#define IB_MPR_COMPMASK_SDGID8 (CL_HTON64(((uint64_t)1)<<29))
+#define IB_MPR_COMPMASK_SDGID9 (CL_HTON64(((uint64_t)1)<<30))
+#define IB_MPR_COMPMASK_SDGID10 (CL_HTON64(((uint64_t)1)<<31))
+#define IB_MPR_COMPMASK_SDGID11 (CL_HTON64(((uint64_t)1)<<32))
+#define IB_MPR_COMPMASK_SDGID12 (CL_HTON64(((uint64_t)1)<<33))
+#define IB_MPR_COMPMASK_SDGID13 (CL_HTON64(((uint64_t)1)<<34))
+#define IB_MPR_COMPMASK_SDGID14 (CL_HTON64(((uint64_t)1)<<35))
+#define IB_MPR_COMPMASK_SDGID15 (CL_HTON64(((uint64_t)1)<<36))
+#define IB_MPR_COMPMASK_SDGID16 (CL_HTON64(((uint64_t)1)<<37))
+#define IB_MPR_COMPMASK_SDGID17 (CL_HTON64(((uint64_t)1)<<38))
+#define IB_MPR_COMPMASK_SDGID18 (CL_HTON64(((uint64_t)1)<<39))
+#define IB_MPR_COMPMASK_SDGID19 (CL_HTON64(((uint64_t)1)<<40))
+#define IB_MPR_COMPMASK_SDGID20 (CL_HTON64(((uint64_t)1)<<41))
+#define IB_MPR_COMPMASK_SDGID21 (CL_HTON64(((uint64_t)1)<<42))
+#define IB_MPR_COMPMASK_SDGID22 (CL_HTON64(((uint64_t)1)<<43))
+#define IB_MPR_COMPMASK_SDGID23 (CL_HTON64(((uint64_t)1)<<44))
+#define IB_MPR_COMPMASK_SDGID24 (CL_HTON64(((uint64_t)1)<<45))
+#define IB_MPR_COMPMASK_SDGID25 (CL_HTON64(((uint64_t)1)<<46))
+#define IB_MPR_COMPMASK_SDGID26 (CL_HTON64(((uint64_t)1)<<47))
+#define IB_MPR_COMPMASK_SDGID27 (CL_HTON64(((uint64_t)1)<<48))
+#define IB_MPR_COMPMASK_SDGID28 (CL_HTON64(((uint64_t)1)<<49))
+#define IB_MPR_COMPMASK_SDGID29 (CL_HTON64(((uint64_t)1)<<50))
+#define IB_MPR_COMPMASK_SDGID30 (CL_HTON64(((uint64_t)1)<<51))
+#define IB_MPR_COMPMASK_SDGID31 (CL_HTON64(((uint64_t)1)<<52))
+#define IB_MPR_COMPMASK_SDGID32 (CL_HTON64(((uint64_t)1)<<53))
+#define IB_MPR_COMPMASK_SDGID33 (CL_HTON64(((uint64_t)1)<<54))
+#define IB_MPR_COMPMASK_SDGID34 (CL_HTON64(((uint64_t)1)<<55))
+#define IB_MPR_COMPMASK_SDGID35 (CL_HTON64(((uint64_t)1)<<56))
+#define IB_MPR_COMPMASK_SDGID36 (CL_HTON64(((uint64_t)1)<<57))
+#define IB_MPR_COMPMASK_SDGID37 (CL_HTON64(((uint64_t)1)<<58))
+#define IB_MPR_COMPMASK_SDGID38 (CL_HTON64(((uint64_t)1)<<59))
+#define IB_MPR_COMPMASK_SDGID39 (CL_HTON64(((uint64_t)1)<<60))
+#define IB_MPR_COMPMASK_SDGID40 (CL_HTON64(((uint64_t)1)<<61))
+#define IB_MPR_COMPMASK_SDGID41 (CL_HTON64(((uint64_t)1)<<62))
+#define IB_MPR_COMPMASK_SDGID42 (CL_HTON64(((uint64_t)1)<<63))
+
/****f* IBA Base: Types/ib_path_rec_init_local
* NAME
* ib_path_rec_init_local
@@ -5508,6 +5597,316 @@ typedef struct _ib_guidinfo_record
} PACK_SUFFIX ib_guidinfo_record_t;
#include <complib/cl_packoff.h>
+#define IB_MULTIPATH_MAX_GIDS 11 /* Support max that can fit into first MAD (for now) */
+
+#include <complib/cl_packon.h>
+typedef struct _ib_multipath_rec_t
+{
+ ib_net32_t hop_flow_raw;
+ uint8_t tclass;
+ uint8_t num_path;
+ ib_net16_t pkey;
+ uint8_t resv0;
+ uint8_t sl;
+ uint8_t mtu;
+ uint8_t rate;
+ uint8_t pkt_life;
+ uint8_t resv1;
+ uint8_t independence; /* formerly resv2 */
+ uint8_t sgid_count;
+ uint8_t dgid_count;
+ uint8_t resv3[7];
+ ib_gid_t gids[IB_MULTIPATH_MAX_GIDS];
+} PACK_SUFFIX ib_multipath_rec_t;
+#include <complib/cl_packoff.h>
+/*
+* FIELDS
+* hop_flow_raw
+* Global routing parameters: hop count, flow label and raw bit.
+*
+* tclass
+* Another global routing parameter.
+*
+* num_path
+* Reversible path - 1 bit to say if path is reversible.
+* num_path [6:0] In queries, maximum number of paths to return.
+* In responses, undefined.
+*
+* pkey
+* Partition key (P_Key) to use on this path.
+*
+* sl
+* Service level to use on this path.
+*
+* mtu
+* MTU and MTU selector fields to use on this path
+* rate
+* Rate and rate selector fields to use on this path.
+*
+* pkt_life
+* Packet lifetime
+*
+* preference
+* Indicates the relative merit of this path versus other path
+* records returned from the SA. Lower numbers are better.
+*
+* SEE ALSO
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_num_path
+* NAME
+* ib_multipath_rec_num_path
+*
+* DESCRIPTION
+* Get max number of paths to return.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_num_path(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( p_rec->num_path &0x7F );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* Maximum number of paths to return for each unique SGID_DGID combination.
+*
+* NOTES
+*
+* SEE ALSO
+* ib_multipath_rec_t
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_sl
+* NAME
+* ib_multipath_rec_sl
+*
+* DESCRIPTION
+* Get multipath service level.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_sl(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( (uint8_t)((cl_ntoh16( p_rec->sl )) & 0xF) );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* SL.
+*
+* NOTES
+*
+* SEE ALSO
+* ib_multipath_rec_t
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_mtu
+* NAME
+* ib_multipath_rec_mtu
+*
+* DESCRIPTION
+* Get encoded path MTU.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_mtu(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( (uint8_t)(p_rec->mtu & IB_MULTIPATH_REC_BASE_MASK) );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* Encoded path MTU.
+* 1: 256
+* 2: 512
+* 3: 1024
+* 4: 2048
+* 5: 4096
+* others: reserved
+*
+* NOTES
+*
+* SEE ALSO
+* ib_multipath_rec_t
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_mtu_sel
+* NAME
+* ib_multipath_rec_mtu_sel
+*
+* DESCRIPTION
+* Get encoded multipath MTU selector.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_mtu_sel(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( (uint8_t)((p_rec->mtu & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6) );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* Encoded path MTU selector value (for queries).
+* 0: greater than MTU specified
+* 1: less than MTU specified
+* 2: exactly the MTU specified
+* 3: largest MTU available
+*
+* NOTES
+*
+* SEE ALSO
+* ib_multipath_rec_t
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_rate
+* NAME
+* ib_multipath_rec_rate
+*
+* DESCRIPTION
+* Get encoded multipath rate.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_rate(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( (uint8_t)(p_rec->rate & IB_MULTIPATH_REC_BASE_MASK) );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* Encoded multipath rate.
+* 2: 2.5 Gb/sec.
+* 3: 10 Gb/sec.
+* 4: 30 Gb/sec.
+* others: reserved
+*
+* NOTES
+*
+* SEE ALSO
+* ib_multipath_rec_t
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_rate_sel
+* NAME
+* ib_multipath_rec_rate_sel
+*
+* DESCRIPTION
+* Get encoded multipath rate selector.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_rate_sel(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( (uint8_t)((p_rec->rate & IB_MULTIPATH_REC_SELECTOR_MASK) >> 6) );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* Encoded path rate selector value (for queries).
+* 0: greater than rate specified
+* 1: less than rate specified
+* 2: exactly the rate specified
+* 3: largest rate available
+*
+* NOTES
+*
+* SEE ALSO
+* ib_multipath_rec_t
+*********/
+
+/****f* IBA Base: Types/ib_multipath_rec_pkt_life
+* NAME
+* ib_multipath_rec_pkt_life
+*
+* DESCRIPTION
+* Get encoded multipath pkt_life.
+*
+* SYNOPSIS
+*/
+static inline uint8_t
+ib_multipath_rec_pkt_life(
+ IN const ib_multipath_rec_t* const p_rec )
+{
+ return( (uint8_t)(p_rec->pkt_life & IB_MULTIPATH_REC_BASE_MASK) );
+}
+/*
+* PARAMETERS
+* p_rec
+* [in] Pointer to the multipath record object.
+*
+* RETURN VALUES
+* Encoded multipath pkt_life = 4.096 ode must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+
+/*
+ * Abstract:
+ * Implementation of osm_mpr_rcv_t.
+ * This object represents the MultiPath Record Receiver object.
+ * This object is part of the opensm family of objects.
+ *
+ * Environment:
+ * Linux User Mode
+ *
+ */
+
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <iba/ib_types.h>
+#include <complib/cl_memory.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_sa_multipath_record.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <vendor/osm_vendor.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_helper.h>
+
+#define OSM_MPR_RCV_POOL_MIN_SIZE 64
+#define OSM_MPR_RCV_POOL_GROW_SIZE 64
+
+#define OSM_SA_MPR_MAX_NUM_PATH 127
+
+typedef struct _osm_mpr_item
+{
+ cl_pool_item_t pool_item;
+ const osm_port_t *p_src_port;
+ const osm_port_t *p_dest_port;
+ int hops;
+ ib_path_rec_t path_rec;
+} osm_mpr_item_t;
+
+typedef struct _osm_path_parms
+{
+ ib_net16_t pkey;
+ uint8_t mtu;
+ uint8_t rate;
+ uint8_t sl;
+ uint8_t pkt_life;
+ boolean_t reversible;
+ int hops;
+} osm_path_parms_t;
+
+
+/**********************************************************************
+ **********************************************************************/
+void
+osm_mpr_rcv_construct(
+ IN osm_mpr_rcv_t* const p_rcv )
+{
+ cl_memclr( p_rcv, sizeof(*p_rcv) );
+ cl_qlock_pool_construct( &p_rcv->pr_pool );
+}
+
+/**********************************************************************
+ **********************************************************************/
+void
+osm_mpr_rcv_destroy(
+ IN osm_mpr_rcv_t* const p_rcv )
+{
+ OSM_LOG_ENTER( p_rcv->p_log, osm_mpr_rcv_destroy );
+ cl_qlock_pool_destroy( &p_rcv->pr_pool );
+ OSM_LOG_EXIT( p_rcv->p_log );
+}
+
+/**********************************************************************
+ **********************************************************************/
+ib_api_status_t
+osm_mpr_rcv_init(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN osm_sa_resp_t* const p_resp,
+ IN osm_mad_pool_t* const p_mad_pool,
+ IN osm_subn_t* const p_subn,
+ IN osm_log_t* const p_log,
+ IN cl_plock_t* const p_lock )
+{
+ ib_api_status_t status;
+
+ OSM_LOG_ENTER( p_log, osm_mpr_rcv_init );
+
+ osm_mpr_rcv_construct( p_rcv );
+
+ p_rcv->p_log = p_log;
+ p_rcv->p_subn = p_subn;
+ p_rcv->p_lock = p_lock;
+ p_rcv->p_resp = p_resp;
+ p_rcv->p_mad_pool = p_mad_pool;
+
+ status = cl_qlock_pool_init( &p_rcv->pr_pool,
+ OSM_MPR_RCV_POOL_MIN_SIZE,
+ 0,
+ OSM_MPR_RCV_POOL_GROW_SIZE,
+ sizeof(osm_mpr_item_t),
+ NULL, NULL, NULL );
+
+ OSM_LOG_EXIT( p_rcv->p_log );
+ return( status );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static ib_api_status_t
+__osm_mpr_rcv_get_path_parms(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_port_t* const p_src_port,
+ IN const osm_port_t* const p_dest_port,
+ IN const uint16_t dest_lid_ho,
+ IN const ib_net64_t comp_mask,
+ OUT osm_path_parms_t* const p_parms )
+{
+ ib_net64_t node_guid;
+ const osm_node_t* p_node;
+ const osm_physp_t* p_physp;
+ const osm_physp_t* p_dest_physp;
+ const osm_switch_t* p_sw;
+ const ib_port_info_t* p_pi;
+ const cl_qmap_t* p_sw_tbl;
+ ib_slvl_table_t* p_slvl_tbl;
+ ib_api_status_t status = IB_SUCCESS;
+ uint8_t mtu;
+ uint8_t rate;
+ uint8_t pkt_life;
+ uint8_t required_mtu;
+ uint8_t required_rate;
+ uint16_t required_pkey;
+ uint8_t required_sl;
+ uint8_t required_pkt_life;
+ ib_net16_t dest_lid;
+ int hops = 0;
+ int in_port_num = 0;
+ uint8_t vl;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_path_parms );
+
+ dest_lid = cl_hton16( dest_lid_ho );
+
+ p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );
+ p_physp = osm_port_get_default_phys_ptr( p_src_port );
+ p_pi = osm_physp_get_port_info_ptr( p_physp );
+ p_sw_tbl = &p_rcv->p_subn->sw_guid_tbl;
+
+ mtu = ib_port_info_get_neighbor_mtu( p_pi );
+ rate = ib_port_info_compute_rate( p_pi );
+
+ if ( comp_mask & IB_MPR_COMPMASK_SL )
+ required_sl = ib_multipath_rec_sl( p_mpr );
+ else
+ required_sl = OSM_DEFAULT_SL;
+
+ if ( comp_mask & IB_MPR_COMPMASK_PKEY ) {
+ required_pkey = p_mpr->pkey;
+ if ( !osm_physp_has_pkey( p_rcv->p_log, required_pkey, p_physp ) ||
+ !osm_physp_has_pkey( p_rcv->p_log, required_pkey, p_dest_physp ) ) {
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
+ "__osm_mpr_rcv_get_path_parms: "
+ "path not found for PKEY = 0x%x\n"
+ "\t\tsrc %Lx dst %Lx\n",
+ required_pkey,
+ osm_physp_get_port_guid( p_physp ),
+ osm_physp_get_port_guid( p_dest_physp ) );
+
+ status = IB_NOT_FOUND;
+ goto Exit;
+ }
+ } else
+ required_pkey = IB_DEFAULT_PKEY;
+
+ /*
+ Walk the subnet object from source to destination,
+ tracking the most restrictive rate and mtu values along the way...
+
+ If source port node is a switch, then p_physp should
+ point to the port that routes the destination lid
+ */
+
+ p_node = osm_physp_get_node_ptr( p_physp );
+
+ if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH )
+ {
+ p_sw = (osm_switch_t *)cl_qmap_get( p_sw_tbl,
+ osm_node_get_node_guid( p_node ) );
+
+ if( p_sw == (osm_switch_t *)cl_qmap_end( p_sw_tbl ) )
+ {
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ /*
+ * If the dest_lid_ho is equal to the lid of the switch pointed by
+ * p_sw then p_physp will be the physical port of the switch port zero.
+ */
+ p_physp = osm_switch_get_route_by_lid( p_sw, cl_ntoh16( dest_lid_ho ) );
+ if ( p_physp == 0 )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_path_parms: ERR 4514: "
+ "Can't find routing to LID 0x%X from switch for guid 0x%016" PRIx64 "\n",
+ dest_lid_ho,
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
+ status = IB_ERROR;
+ goto Exit;
+ }
+ }
+
+ /*
+ * Same as above
+ */
+ p_node = osm_physp_get_node_ptr( p_dest_physp );
+
+ if ( osm_node_get_type( p_node ) == IB_NODE_TYPE_SWITCH )
+ {
+ p_sw = (osm_switch_t *)cl_qmap_get( p_sw_tbl,
+ osm_node_get_node_guid( p_node ) );
+
+ if ( p_sw == (osm_switch_t *)cl_qmap_end( p_sw_tbl ) )
+ {
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ p_dest_physp = osm_switch_get_route_by_lid( p_sw, cl_ntoh16( dest_lid_ho ) );
+
+ if ( p_dest_physp == 0 )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_path_parms: ERR 4515: "
+ "Can't find routing to LID 0x%X from switch for guid 0x%016" PRIx64 "\n",
+ dest_lid_ho,
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ }
+
+ while ( p_physp != p_dest_physp )
+ {
+ p_physp = osm_physp_get_remote( p_physp );
+
+ if ( p_physp == 0 )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_path_parms: ERR 4505: "
+ "Can't find remote phys port when routing to LID 0x%X from node guid 0x%016" PRIx64 "\n",
+ dest_lid_ho,
+ cl_ntoh64( osm_node_get_node_guid( p_node ) ) );
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ hops++;
+
+ /*
+ This is point to point case (no switch in between)
+ */
+ if ( p_physp == p_dest_physp )
+ break;
+
+ p_node = osm_physp_get_node_ptr( p_physp );
+
+ if ( osm_node_get_type( p_node ) != IB_NODE_TYPE_SWITCH )
+ {
+ /*
+ There is some sort of problem in the subnet object!
+ If this isn't a switch, we should have reached
+ the destination by now!
+ */
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_path_parms: ERR 4503: "
+ "Internal error, bad path\n" );
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ node_guid = osm_node_get_node_guid( p_node );
+ p_sw = (osm_switch_t*)cl_qmap_get( p_sw_tbl, node_guid );
+
+ if ( p_sw == (osm_switch_t*)cl_qmap_end( p_sw_tbl ) )
+ {
+ /*
+ There is some sort of problem in the subnet object!
+ */
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_path_parms: ERR 4504: "
+ "Internal error, no switch for guid 0x%016" PRIx64 "\n",
+ cl_ntoh64( node_guid ) );
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ /*
+ Check parameters for the ingress port in this switch.
+ */
+ p_pi = osm_physp_get_port_info_ptr( p_physp );
+
+ if ( mtu > ib_port_info_get_mtu_cap( p_pi ) )
+ {
+ mtu = ib_port_info_get_mtu_cap( p_pi );
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "New smallest MTU = %u at intervening port 0x%016" PRIx64 "\n",
+ mtu,
+ osm_physp_get_port_guid( p_physp ) );
+ }
+ }
+
+ if ( rate > ib_port_info_compute_rate( p_pi ) )
+ {
+ rate = ib_port_info_compute_rate( p_pi );
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "New smallest rate = %u at intervening port 0x%016" PRIx64 "\n",
+ rate,
+ osm_physp_get_port_guid( p_physp ) );
+ }
+ }
+
+ /*
+ Continue with the egress port on this switch.
+ */
+ p_physp = osm_switch_get_route_by_lid( p_sw, dest_lid );
+
+ if ( p_physp == 0 )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_path_parms: ERR 4516: "
+ "Dead end on path to LID 0x%X from switch for guid 0x%016" PRIx64 "\n",
+ dest_lid_ho,
+ cl_ntoh64( node_guid ) );
+ status = IB_ERROR;
+ goto Exit;
+ }
+
+ CL_ASSERT( p_physp );
+ CL_ASSERT( osm_physp_is_valid( p_physp ) );
+
+ if ( comp_mask & IB_MPR_COMPMASK_SL ) {
+ in_port_num = osm_physp_get_port_num( p_physp );
+ p_slvl_tbl = osm_physp_get_slvl_tbl( p_physp, in_port_num );
+ vl = ib_slvl_table_get( p_slvl_tbl, required_sl );
+ if (vl == IB_DROP_VL) { /* discard packet */
+ osm_log( p_rcv->p_log, OSM_LOG_VERBOSE,
+ "__osm_mpr_rcv_get_path_parms: Path not found for SL %d\n"
+ "\t\tin_port_num %d port_guid %Lx\n",
+ required_sl, in_port_num,
+ osm_physp_get_port_guid( p_physp ) );
+ status = IB_NOT_FOUND;
+ goto Exit;
+ }
+ }
+
+ p_pi = osm_physp_get_port_info_ptr( p_physp );
+
+ if ( mtu > ib_port_info_get_mtu_cap( p_pi ) )
+ {
+ mtu = ib_port_info_get_mtu_cap( p_pi );
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "New smallest MTU = %u at intervening port 0x%016" PRIx64 "\n",
+ mtu,
+ osm_physp_get_port_guid( p_physp ) );
+ }
+ }
+
+ if ( rate > ib_port_info_compute_rate( p_pi ) )
+ {
+ rate = ib_port_info_compute_rate( p_pi );
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "New smallest rate = %u at intervening port 0x%016" PRIx64 "\n",
+ rate,
+ osm_physp_get_port_guid( p_physp ) );
+ }
+ }
+
+ }
+
+ /*
+ p_physp now points to the destination
+ */
+ p_pi = osm_physp_get_port_info_ptr( p_physp );
+
+ if ( mtu > ib_port_info_get_mtu_cap( p_pi ) )
+ {
+ mtu = ib_port_info_get_mtu_cap( p_pi );
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "New smallest MTU = %u at destination port 0x%016" PRIx64 "\n",
+ mtu,
+ osm_physp_get_port_guid( p_physp ) );
+ }
+ }
+
+ if ( rate > ib_port_info_compute_rate( p_pi ) )
+ {
+ rate = ib_port_info_compute_rate( p_pi );
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "New smallest rate = %u at destination port 0x%016" PRIx64 "\n",
+ rate,
+ osm_physp_get_port_guid( p_physp ) );
+ }
+ }
+
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_path_parms: "
+ "Path min MTU = %u, min rate = %u\n", mtu, rate );
+ }
+
+ /*
+ Determine if these values meet the user criteria
+ */
+
+ /* we silently ignore cases where only the MTU selector is defined */
+ if ( ( comp_mask & IB_MPR_COMPMASK_MTUSELEC ) &&
+ ( comp_mask & IB_MPR_COMPMASK_MTU ) )
+ {
+ required_mtu = ib_multipath_rec_mtu( p_mpr );
+ switch ( ib_multipath_rec_mtu_sel( p_mpr ) )
+ {
+ case 0: /* must be greater than */
+ if ( mtu <= required_mtu )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 1: /* must be less than */
+ if ( mtu >= required_mtu )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 2: /* exact match */
+ if ( mtu != required_mtu )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 3: /* largest available */
+ /* can't be disqualified by this one */
+ break;
+
+ default:
+ /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
+ CL_ASSERT( FALSE );
+ status = IB_ERROR;
+ break;
+ }
+ }
+
+ /* we silently ignore cases where only the Rate selector is defined */
+ if ( ( comp_mask & IB_MPR_COMPMASK_RATESELEC ) &&
+ ( comp_mask & IB_PR_COMPMASK_RATE ) )
+ {
+ required_rate = ib_multipath_rec_rate( p_mpr );
+ switch ( ib_multipath_rec_rate_sel( p_mpr ) )
+ {
+ case 0: /* must be greater than */
+ if ( rate <= required_rate )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 1: /* must be less than */
+ if ( rate >= required_rate )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 2: /* exact match */
+ if ( rate != required_rate )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 3: /* largest available */
+ /* can't be disqualified by this one */
+ break;
+
+ default:
+ /* if we're here, there's a bug in ib_multipath_rec_mtu_sel() */
+ CL_ASSERT( FALSE );
+ status = IB_ERROR;
+ break;
+ }
+ }
+
+ /* Verify the pkt_life_time */
+ /* According to spec definition IBA 1.2 Table 205 PacketLifeTime description,
+ for loopback paths, packetLifeTime shall be zero. */
+ if ( p_src_port == p_dest_port )
+ pkt_life = 0; /* loopback */
+ else
+ pkt_life = OSM_DEFAULT_SUBNET_TIMEOUT;
+
+ /* we silently ignore cases where only the PktLife selector is defined */
+ if ( ( comp_mask & IB_MPR_COMPMASK_PKTLIFETIMESELEC ) &&
+ ( comp_mask & IB_MPR_COMPMASK_PKTLIFETIME ) )
+ {
+ required_pkt_life = ib_multipath_rec_pkt_life( p_mpr );
+ switch ( ib_multipath_rec_pkt_life_sel( p_mpr ) )
+ {
+ case 0: /* must be greater than */
+ if ( pkt_life <= required_pkt_life )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 1: /* must be less than */
+ if ( pkt_life >= required_pkt_life )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 2: /* exact match */
+ if ( pkt_life != required_pkt_life )
+ status = IB_NOT_FOUND;
+ break;
+
+ case 3: /* smallest available */
+ /* can't be disqualified by this one */
+ break;
+
+ default:
+ /* if we're here, there's a bug in ib_path_rec_pkt_life_sel() */
+ CL_ASSERT( FALSE );
+ status = IB_ERROR;
+ break;
+ }
+ }
+
+ if (status != IB_SUCCESS)
+ goto Exit;
+
+ p_parms->mtu = mtu;
+ p_parms->rate = rate;
+ p_parms->pkey = required_pkey;
+ p_parms->pkt_life = pkt_life;
+ p_parms->sl = required_sl;
+ p_parms->hops = hops;
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+ return( status );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static void
+__osm_mpr_rcv_build_pr(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const osm_port_t* const p_src_port,
+ IN const osm_port_t* const p_dest_port,
+ IN const uint16_t src_lid_ho,
+ IN const uint16_t dest_lid_ho,
+ IN const uint8_t preference,
+ IN const osm_path_parms_t* const p_parms,
+ OUT ib_path_rec_t* const p_pr )
+{
+ const osm_physp_t* p_src_physp;
+ const osm_physp_t* p_dest_physp;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_build_pr );
+
+ p_src_physp = osm_port_get_default_phys_ptr( p_src_port );
+ p_dest_physp = osm_port_get_default_phys_ptr( p_dest_port );
+
+ p_pr->dgid.unicast.prefix = osm_physp_get_subnet_prefix( p_dest_physp );
+ p_pr->dgid.unicast.interface_id = osm_physp_get_port_guid( p_dest_physp );
+
+ p_pr->sgid.unicast.prefix = osm_physp_get_subnet_prefix( p_src_physp );
+ p_pr->sgid.unicast.interface_id = osm_physp_get_port_guid( p_src_physp );
+
+ p_pr->dlid = cl_hton16( dest_lid_ho );
+ p_pr->slid = cl_hton16( src_lid_ho );
+
+ p_pr->pkey = p_parms->pkey;
+ p_pr->sl = p_parms->sl;
+ p_pr->mtu = (uint8_t)( p_parms->mtu | 0x80 );
+ p_pr->rate = (uint8_t)( p_parms->rate | 0x80 );
+
+ /* According to 1.2 spec definition Table 205 PacketLifeTime description,
+ for loopback paths, packetLifeTime shall be zero. */
+ if ( p_src_port == p_dest_port )
+ p_pr->pkt_life = 0x80; /* loopback */
+ else
+ p_pr->pkt_life = (uint8_t)( p_parms->pkt_life | 0x80 );
+
+ p_pr->preference = preference;
+
+ /* always return num_path = 0 so this is only the reversible component */
+ if ( p_parms->reversible )
+ p_pr->num_path = 0x80;
+
+ OSM_LOG_EXIT( p_rcv->p_log );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static osm_mpr_item_t*
+__osm_mpr_rcv_get_lid_pair_path(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_port_t* const p_src_port,
+ IN const osm_port_t* const p_dest_port,
+ IN const uint16_t src_lid_ho,
+ IN const uint16_t dest_lid_ho,
+ IN const ib_net64_t comp_mask,
+ IN const uint8_t preference )
+{
+ osm_path_parms_t path_parms;
+ osm_path_parms_t rev_path_parms;
+ osm_mpr_item_t *p_pr_item;
+ ib_api_status_t status, rev_path_status;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_lid_pair_path );
+
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_lid_pair_path: "
+ "Src LID 0x%X, Dest LID 0x%X\n",
+ src_lid_ho, dest_lid_ho );
+ }
+
+ p_pr_item = (osm_mpr_item_t*)cl_qlock_pool_get( &p_rcv->pr_pool );
+ if ( p_pr_item == NULL )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_lid_pair_path: ERR 4501: "
+ "Unable to allocate path record\n" );
+ goto Exit;
+ }
+
+ status = __osm_mpr_rcv_get_path_parms( p_rcv, p_mpr, p_src_port,
+ p_dest_port, dest_lid_ho,
+ comp_mask, &path_parms );
+
+ if ( status != IB_SUCCESS )
+ {
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
+ p_pr_item = NULL;
+ goto Exit;
+ }
+
+ /* now try the reversible path */
+ rev_path_status = __osm_mpr_rcv_get_path_parms( p_rcv, p_mpr, p_dest_port,
+ p_src_port, src_lid_ho,
+ comp_mask, &rev_path_parms );
+ path_parms.reversible = ( rev_path_status == IB_SUCCESS );
+
+ /* did we get a Reversible Path compmask ? */
+ /*
+ NOTE that if the reversible component = 0, it is a don't care
+ rather then requiring non-reversible paths ...
+ see Vol1 Ver1.2 p900 l16
+ */
+ if ( comp_mask & IB_MPR_COMPMASK_REVERSIBLE )
+ if ( (! path_parms.reversible && ( p_mpr->num_path & 0x80 ) ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_lid_pair_path: "
+ "Requested reversible path but failed to get one\n");
+
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_pr_item->pool_item );
+ p_pr_item = NULL;
+ goto Exit;
+ };
+
+ p_pr_item->p_src_port = p_src_port;
+ p_pr_item->p_dest_port = p_dest_port;
+ p_pr_item->hops = path_parms.hops;
+
+ __osm_mpr_rcv_build_pr( p_rcv, p_src_port, p_dest_port, src_lid_ho,
+ dest_lid_ho, preference, &path_parms,
+ &p_pr_item->path_rec );
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+ return( p_pr_item );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static uint32_t
+__osm_mpr_rcv_get_port_pair_paths(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_port_t* const p_req_port,
+ IN const osm_port_t* const p_src_port,
+ IN const osm_port_t* const p_dest_port,
+ IN const uint32_t rem_paths,
+ IN const ib_net64_t comp_mask,
+ IN cl_qlist_t* const p_list )
+{
+ osm_mpr_item_t* p_pr_item;
+ uint16_t src_lid_min_ho;
+ uint16_t src_lid_max_ho;
+ uint16_t dest_lid_min_ho;
+ uint16_t dest_lid_max_ho;
+ uint16_t src_lid_ho;
+ uint16_t dest_lid_ho;
+ uint32_t path_num = 0;
+ uint8_t preference;
+ uintn_t src_offset;
+ uintn_t dest_offset;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_port_pair_paths );
+
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_port_pair_paths: "
+ "Src port 0x%016" PRIx64 ", "
+ "Dst port 0x%016" PRIx64 "\n",
+ cl_ntoh64( osm_port_get_guid( p_src_port ) ),
+ cl_ntoh64( osm_port_get_guid( p_dest_port ) ) );
+ }
+
+ /* Check that the req_port, src_port and dest_port all share a
+ pkey. The check is done on the default physical port of the ports. */
+ if ( osm_port_share_pkey(p_rcv->p_log, p_req_port, p_src_port ) == FALSE ||
+ osm_port_share_pkey(p_rcv->p_log, p_req_port, p_dest_port ) == FALSE ||
+ osm_port_share_pkey(p_rcv->p_log, p_src_port, p_dest_port ) == FALSE )
+ {
+ /* One of the pairs doesn't share a pkey so the path is disqualified. */
+ goto Exit;
+ }
+
+ /*
+ We shouldn't be here if the paths are disqualified in some way...
+ Thus, we assume every possible connection is valid.
+
+ We desire to return high-quality paths first.
+ In OpenSM, higher quality mean least overlap with other paths.
+ This is acheived in practice by returning paths with
+ different LID value on each end, which means these
+ paths are more redundent that paths with the same LID repeated
+ on one side. For example, in OpenSM the paths between two
+ endpoints with LMC = 1 might be as follows:
+
+ Port A, LID 1 <-> Port B, LID 3
+ Port A, LID 1 <-> Port B, LID 4
+ Port A, LID 2 <-> Port B, LID 3
+ Port A, LID 2 <-> Port B, LID 4
+
+ The OpenSM unicast routing algorithms attempt to disperse each path
+ to as varied a physical path as is reasonable. 1<->3 and 1<->4 have
+ more physical overlap (hence less redundancy) than 1<->3 and 2<->4.
+
+ OpenSM ranks paths in three preference groups:
+
+ Preference Value Description
+ ---------------- -------------------------------------------
+ 0 Redundant in both directions with other
+ pref value = 0 paths
+
+ 1 Redundant in one direction with other
+ pref value = 0 and pref value = 1 paths
+
+ 2 Not redundant in either direction with
+ other paths
+
+ 3-FF Unused
+
+
+ SA clients don't need to know these details, only that the lower
+ preference paths are preferred, as stated in the spec. The paths
+ may not actually be physically redundant depending on the topology
+ of the subnet, but the point of LMC > 0 is to offer redundancy,
+ so I assume the subnet is physically appropriate for the specified
+ LMC value. A more advanced implementation could inspect for physical
+ redundancy, but I'm not going to bother with that now.
+ */
+
+ osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho, &src_lid_max_ho );
+ osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho, &dest_lid_max_ho );
+
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_port_pair_paths: "
+ "Src LID [0x%X-0x%X], "
+ "Dest LID [0x%X-0x%X]\n",
+ src_lid_min_ho, src_lid_max_ho,
+ dest_lid_min_ho, dest_lid_max_ho );
+ }
+
+ src_lid_ho = src_lid_min_ho;
+ dest_lid_ho = dest_lid_min_ho;
+
+ /*
+ Preferred paths come first in OpenSM
+ */
+ preference = 0;
+
+ while ( path_num < rem_paths )
+ {
+ /*
+ These paths are "fully redundant"
+ */
+ p_pr_item = __osm_mpr_rcv_get_lid_pair_path( p_rcv, p_mpr,
+ p_src_port, p_dest_port,
+ src_lid_ho, dest_lid_ho,
+ comp_mask, preference );
+
+ if ( p_pr_item )
+ {
+ cl_qlist_insert_tail( p_list,
+ (cl_list_item_t*)&p_pr_item->pool_item );
+ ++path_num;
+ }
+
+ if ( ++src_lid_ho > src_lid_max_ho )
+ break;
+
+ if ( ++dest_lid_ho > dest_lid_max_ho )
+ break;
+ }
+
+ /*
+ Check if we've accumulated all the paths that the user cares to see
+ */
+ if ( path_num == rem_paths )
+ goto Exit;
+
+ /*
+ Don't bother reporting preference 1 paths for now.
+ It's more trouble than it's worth and can only occur
+ if ports have different LMC values, which isn't supported
+ by OpenSM right now anyway.
+ */
+ preference = 2;
+ src_lid_ho = src_lid_min_ho;
+ dest_lid_ho = dest_lid_min_ho;
+ src_offset = 0;
+ dest_offset = 0;
+
+ /*
+ Iterate over the remaining paths
+ */
+ while ( path_num < rem_paths )
+ {
+ dest_offset++;
+ dest_lid_ho++;
+
+ if ( dest_lid_ho > dest_lid_max_ho )
+ {
+ src_offset++;
+ src_lid_ho++;
+
+ if ( src_lid_ho > src_lid_max_ho )
+ break; /* done */
+
+ dest_offset = 0;
+ dest_lid_ho = dest_lid_min_ho;
+ }
+
+ /*
+ These paths are "fully non-redundant" with paths already
+ identified above and consequently not of much value.
+
+ Don't return paths we already identified above, as indicated
+ by the offset values being equal.
+ */
+ if ( src_offset == dest_offset )
+ continue; /* already reported */
+
+ p_pr_item = __osm_mpr_rcv_get_lid_pair_path( p_rcv, p_mpr,
+ p_src_port, p_dest_port,
+ src_lid_ho, dest_lid_ho,
+ comp_mask, preference );
+
+ if ( p_pr_item )
+ {
+ cl_qlist_insert_tail( p_list,
+ (cl_list_item_t*)&p_pr_item->pool_item );
+ ++path_num;
+ }
+ }
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+ return path_num;
+}
+
+#undef min
+#define min(x,y) (((x) < (y)) ? (x) : (y))
+
+/**********************************************************************
+ **********************************************************************/
+static osm_mpr_item_t*
+__osm_mpr_rcv_get_apm_port_pair_paths(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_port_t* const p_src_port,
+ IN const osm_port_t* const p_dest_port,
+ IN int base_offs,
+ IN const ib_net64_t comp_mask,
+ IN cl_qlist_t* const p_list )
+{
+ osm_mpr_item_t* p_pr_item = 0;
+ uint16_t src_lid_min_ho;
+ uint16_t src_lid_max_ho;
+ uint16_t dest_lid_min_ho;
+ uint16_t dest_lid_max_ho;
+ uint16_t src_lid_ho;
+ uint16_t dest_lid_ho;
+ uintn_t iterations;
+ int src_lids, dest_lids;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_apm_port_pair_paths );
+
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_apm_port_pair_paths: "
+ "Src port 0x%016" PRIx64 ", "
+ "Dst port 0x%016" PRIx64 ", base offs %d\n",
+ cl_ntoh64( osm_port_get_guid( p_src_port ) ),
+ cl_ntoh64( osm_port_get_guid( p_dest_port ) ),
+ base_offs );
+ }
+
+ osm_port_get_lid_range_ho( p_src_port, &src_lid_min_ho, &src_lid_max_ho );
+ osm_port_get_lid_range_ho( p_dest_port, &dest_lid_min_ho, &dest_lid_max_ho );
+
+ src_lid_ho = src_lid_min_ho;
+ dest_lid_ho = dest_lid_min_ho;
+
+ src_lids = src_lid_max_ho - src_lid_min_ho + 1;
+ dest_lids = dest_lid_max_ho - dest_lid_min_ho + 1;
+
+ src_lid_ho += base_offs % src_lids;
+ dest_lid_ho += base_offs % dest_lids;
+
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_apm_port_pair_paths: "
+ "Src LIDs [0x%X-0x%X] hashed %d, "
+ "Dest LIDs [0x%X-0x%X] hashed %d\n",
+ src_lid_min_ho, src_lid_max_ho, src_lid_ho,
+ dest_lid_min_ho, dest_lid_max_ho, dest_lid_ho );
+
+ iterations = min( src_lids, dest_lids );
+
+ while ( iterations-- )
+ {
+ /*
+ These paths are "fully redundant"
+ */
+ p_pr_item = __osm_mpr_rcv_get_lid_pair_path( p_rcv, p_mpr,
+ p_src_port, p_dest_port,
+ src_lid_ho, dest_lid_ho,
+ comp_mask, 0 );
+
+ if ( p_pr_item )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_get_apm_port_pair_paths: "
+ "Found matching path from Src LID 0x%X to Dest LID 0x%X with %d hops\n",
+ src_lid_ho, dest_lid_ho, p_pr_item->hops);
+ break;
+ }
+
+ if ( ++src_lid_ho > src_lid_max_ho )
+ src_lid_ho = src_lid_min_ho;
+
+ if ( ++dest_lid_ho > dest_lid_max_ho )
+ dest_lid_ho = dest_lid_min_ho;
+ }
+
+ OSM_LOG_EXIT( p_rcv->p_log );
+ return p_pr_item;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static ib_net16_t
+__osm_mpr_rcv_get_gids(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_gid_t * gids,
+ IN int ngids,
+ OUT osm_port_t** pp_port )
+{
+ osm_port_t *p_port;
+ ib_net16_t ib_status = IB_SUCCESS;
+ int i;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_gids );
+
+ for ( i = 0; i < ngids; i++, gids++ ) {
+ p_port = (osm_port_t *)cl_qmap_get( &p_rcv->p_subn->port_guid_tbl,
+ gids->unicast.interface_id );
+ if ( !p_port ||
+ p_port == (osm_port_t *)cl_qmap_end( &p_rcv->p_subn->port_guid_tbl ) ) {
+ /*
+ This 'error' is the client's fault (bad gid) so
+ don't enter it as an error in our own log.
+ Return an error response to the client.
+ */
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_get_gids: ERR 4506: "
+ "No port with GUID = 0x%016" PRIx64 "\n",
+ cl_ntoh64( gids->unicast.interface_id ) );
+
+ ib_status = IB_SA_MAD_STATUS_INVALID_GID;
+ goto Exit;
+ }
+
+ pp_port[i] = p_port;
+ }
+
+ Exit:
+ OSM_LOG_EXIT(p_rcv->p_log);
+
+ return ib_status;
+}
+
+/**********************************************************************
+ **********************************************************************/
+static ib_net16_t
+__osm_mpr_rcv_get_end_points(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const osm_madw_t* const p_madw,
+ OUT osm_port_t ** pp_ports,
+ OUT int * nsrc,
+ OUT int * ndest )
+{
+ const ib_multipath_rec_t* p_mpr;
+ const ib_sa_mad_t* p_sa_mad;
+ ib_net64_t comp_mask;
+ ib_net16_t sa_status = IB_SA_MAD_STATUS_SUCCESS;
+ ib_gid_t * gids;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_end_points );
+
+ /*
+ Determine what fields are valid and then get a pointer
+ to the source and destination port objects, if possible.
+ */
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
+ p_mpr = (ib_multipath_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
+ gids = (ib_gid_t *)p_mpr->gids;
+
+ comp_mask = p_sa_mad->comp_mask;
+
+ /*
+ Check a few easy disqualifying cases up front before getting
+ into the endpoints.
+ */
+
+ /* SDGIDs could be checked for multicast disqualification. */
+
+ *nsrc = *ndest = 0;
+
+ if ( comp_mask & IB_MPR_COMPMASK_SGIDCOUNT ) {
+ *nsrc = p_mpr->sgid_count;
+ if ( *nsrc > IB_MULTIPATH_MAX_GIDS )
+ *nsrc = IB_MULTIPATH_MAX_GIDS;
+ sa_status = __osm_mpr_rcv_get_gids( p_rcv, gids, *nsrc, pp_ports );
+ if ( sa_status != IB_SUCCESS )
+ goto Exit;
+ }
+
+ if ( comp_mask & IB_MPR_COMPMASK_DGIDCOUNT ) {
+ *ndest = p_mpr->dgid_count;
+ if ( *ndest + *nsrc > IB_MULTIPATH_MAX_GIDS )
+ *ndest = IB_MULTIPATH_MAX_GIDS - *nsrc;
+ sa_status = __osm_mpr_rcv_get_gids( p_rcv, gids + *nsrc, *ndest,
+ pp_ports + *nsrc );
+ }
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+ return( sa_status );
+}
+
+#define __hash_lids(a, b, lmc) \
+ (((((a) >> (lmc)) << 4) | ((b) >> (lmc))) % 103)
+
+/**********************************************************************
+ **********************************************************************/
+static void
+__osm_mpr_rcv_get_apm_paths(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_port_t* const p_req_port,
+ IN osm_port_t ** _pp_ports,
+ IN const ib_net64_t comp_mask,
+ IN cl_qlist_t* const p_list )
+{
+ osm_port_t *pp_ports[4];
+ osm_mpr_item_t *matrix[2][2];
+ int base_offs, src_lid_ho, dest_lid_ho;
+ int sumA, sumB, minA, minB;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_get_apm_paths );
+
+ /*
+ * We want to:
+ * 1. use different lid offsets (from base) for the resultant paths
+ * to increase the probability of redundant paths or in case
+ * of Clos - to ensure it (different offset => different spine!)
+ * 2. keep consistent paths no matter of direction and order of ports
+ * 3. distibute the lid offsets to balance the load
+ * So, we sort the ports (within the srcs, and within the dests),
+ * hash the lids of S0, D0 (after the sort), and call __osm_mpr_rcv_get_apm_port_pair_paths
+ * with base_lid for S0, D0 and base_lid + 1 for S1, D1. This way we will get
+ * always the same offsets - order indepentent, and make sure different spines are used.
+ * Note that the diagonals on a Clos have the same number of hops, so it doesn't
+ * really matter which diagonal we use.
+ */
+ if ( _pp_ports[0]->guid < _pp_ports[1]->guid ) {
+ pp_ports[0] = _pp_ports[0];
+ pp_ports[1] = _pp_ports[1];
+ } else {
+ pp_ports[0] = _pp_ports[1];
+ pp_ports[1] = _pp_ports[0];
+ }
+ if ( _pp_ports[2]->guid < _pp_ports[3]->guid ) {
+ pp_ports[2] = _pp_ports[2];
+ pp_ports[3] = _pp_ports[3];
+ } else {
+ pp_ports[2] = _pp_ports[3];
+ pp_ports[3] = _pp_ports[2];
+ }
+
+ src_lid_ho = osm_port_get_base_lid( pp_ports[0] );
+ dest_lid_ho = osm_port_get_base_lid( pp_ports[2] );
+
+ base_offs = src_lid_ho < dest_lid_ho ?
+ __hash_lids( src_lid_ho, dest_lid_ho, p_rcv->p_subn->opt.lmc ) :
+ __hash_lids( dest_lid_ho, src_lid_ho, p_rcv->p_subn->opt.lmc );
+
+ matrix[0][0] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[0],
+ pp_ports[2], base_offs, comp_mask , p_list );
+ matrix[0][1] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[0],
+ pp_ports[3], base_offs, comp_mask, p_list );
+ matrix[1][0] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[1],
+ pp_ports[2], base_offs+1, comp_mask, p_list );
+ matrix[1][1] = __osm_mpr_rcv_get_apm_port_pair_paths( p_rcv, p_mpr, pp_ports[1],
+ pp_ports[3], base_offs+1, comp_mask, p_list );
+
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_get_apm_paths: "
+ "APM matrix:\n"
+ "\t{0,0} 0x%X->0x%X (%d)\t| {0,1} 0x%X->0x%X (%d)\n"
+ "\t{1,0} 0x%X->0x%X (%d)\t| {1,1} 0x%X->0x%X (%d)\n",
+ matrix[0][0]->path_rec.slid, matrix[0][0]->path_rec.dlid, matrix[0][0]->hops,
+ matrix[0][1]->path_rec.slid, matrix[0][1]->path_rec.dlid, matrix[0][1]->hops,
+ matrix[1][0]->path_rec.slid, matrix[1][0]->path_rec.dlid, matrix[1][0]->hops,
+ matrix[1][1]->path_rec.slid, matrix[1][1]->path_rec.dlid, matrix[1][1]->hops );
+
+ /* check diagonal A {(0,0), (1,1)} */
+ sumA = matrix[0][0]->hops + matrix[1][1]->hops;
+ minA = min( matrix[0][0]->hops, matrix[1][1]->hops );
+
+ /* check diagonal B {(0,1), (1,0)} */
+ sumB = matrix[0][1]->hops + matrix[1][0]->hops;
+ minB = min( matrix[0][1]->hops, matrix[1][0]->hops );
+
+ /* and the winner is... */
+ if ( minA <= minB || ( minA == minB && sumA < sumB ) ) {
+ /* Diag A */
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_get_apm_paths: "
+ "Diag {0,0} & {1,1} is the best:\n"
+ "\t{0,0} 0x%X->0x%X (%d)\t & {1,1} 0x%X->0x%X (%d)\n",
+ matrix[0][0]->path_rec.slid, matrix[0][0]->path_rec.dlid, matrix[0][0]->hops,
+ matrix[1][1]->path_rec.slid, matrix[1][1]->path_rec.dlid, matrix[1][1]->hops );
+ cl_qlist_insert_tail( p_list,
+ (cl_list_item_t*)&matrix[0][0]->pool_item );
+ cl_qlist_insert_tail( p_list,
+ (cl_list_item_t*)&matrix[1][1]->pool_item );
+ cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[0][1]->pool_item );
+ cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[1][0]->pool_item );
+ } else {
+ /* Diag B */
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_get_apm_paths: "
+ "Diag {0,1} & {1,0} is the best:\n"
+ "\t{0,1} 0x%X->0x%X (%d)\t & {1,0} 0x%X->0x%X (%d)\n",
+ matrix[0][1]->path_rec.slid, matrix[0][1]->path_rec.dlid, matrix[0][1]->hops,
+ matrix[1][0]->path_rec.slid, matrix[1][0]->path_rec.dlid, matrix[1][0]->hops );
+ cl_qlist_insert_tail( p_list,
+ (cl_list_item_t*)&matrix[0][1]->pool_item );
+ cl_qlist_insert_tail( p_list,
+ (cl_list_item_t*)&matrix[1][0]->pool_item );
+ cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[0][0]->pool_item );
+ cl_qlock_pool_put( &p_rcv->pr_pool, &matrix[1][1]->pool_item );
+ }
+
+ OSM_LOG_EXIT( p_rcv->p_log );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static void
+__osm_mpr_rcv_process_pairs(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN osm_port_t* const p_req_port,
+ IN osm_port_t ** pp_ports,
+ IN const int nsrc,
+ IN const int ndest,
+ IN const ib_net64_t comp_mask,
+ IN cl_qlist_t* const p_list )
+{
+ osm_port_t **pp_src_port, **pp_es;
+ osm_port_t **pp_dest_port, **pp_ed;
+ uint32_t max_paths, num_paths, total_paths = 0;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_process_pairs );
+
+ if ( comp_mask & IB_MPR_COMPMASK_NUMBPATH )
+ max_paths = p_mpr->num_path & 0x7F;
+ else
+ max_paths = OSM_SA_MPR_MAX_NUM_PATH;
+
+ for ( pp_src_port = pp_ports, pp_es = pp_ports + nsrc; pp_src_port < pp_es; pp_src_port++ )
+ {
+ for ( pp_dest_port = pp_es, pp_ed = pp_es + ndest; pp_dest_port < pp_ed; pp_dest_port++ )
+ {
+ num_paths = __osm_mpr_rcv_get_port_pair_paths( p_rcv, p_mpr, p_req_port,
+ *pp_src_port, *pp_dest_port,
+ max_paths - total_paths,
+ comp_mask, p_list );
+ total_paths += num_paths;
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG, "__osm_mpr_rcv_process_pairs: "
+ "%d paths %d total paths %d max paths\n",
+ num_paths, total_paths, max_paths );
+ /* Just take first NumbPaths found */
+ if (total_paths >= max_paths)
+ goto Exit;
+ }
+ }
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+}
+
+/**********************************************************************
+ **********************************************************************/
+static void
+__osm_mpr_rcv_respond(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN const osm_madw_t* const p_madw,
+ IN cl_qlist_t* const p_list )
+{
+ osm_madw_t* p_resp_madw;
+ const ib_sa_mad_t* p_sa_mad;
+ ib_sa_mad_t* p_resp_sa_mad;
+ size_t num_rec;
+ size_t mad_size;
+ ib_path_rec_t* p_resp_pr;
+ ib_multipath_rec_t* p_mpr;
+ ib_api_status_t status;
+ osm_mpr_item_t* p_mpr_item;
+ uint32_t i;
+
+ OSM_LOG_ENTER( p_rcv->p_log, __osm_mpr_rcv_respond );
+
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
+ p_mpr = (ib_multipath_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
+
+ num_rec = cl_qlist_count( p_list );
+
+ osm_log( p_rcv->p_log, OSM_LOG_DEBUG,
+ "__osm_mpr_rcv_respond: "
+ "Generating response with %u records\n", num_rec );
+
+ mad_size = IB_SA_MAD_HDR_SIZE + num_rec * sizeof(ib_path_rec_t);
+
+ /*
+ Get a MAD to reply. Address of Mad is in the received mad_wrapper
+ */
+ p_resp_madw = osm_mad_pool_get( p_rcv->p_mad_pool, p_madw->h_bind,
+ mad_size, &p_madw->mad_addr );
+
+ if ( !p_resp_madw )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_respond: "
+ "ERR 4502: Unable to allocate MAD\n" );
+
+ for ( i = 0; i < num_rec; i++ )
+ {
+ p_mpr_item = (osm_mpr_item_t*)cl_qlist_remove_head( p_list );
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_mpr_item->pool_item );
+ }
+
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_NO_RESOURCES );
+ goto Exit;
+ }
+
+ p_resp_sa_mad = osm_madw_get_sa_mad_ptr( p_resp_madw );
+
+ cl_memcpy( p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE );
+ p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
+ /* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
+ p_resp_sa_mad->sm_key = 0;
+
+ /*
+ o15-0.2.7: If MultiPath is supported, then SA shall respond to a
+ SubnAdmGetMulti() containing a valid MultiPathRecord attribute with
+ a set of zero or more PathRecords satisfying the constraints indicated
+ in the MultiPathRecord received. The PathRecord Attribute ID shall be
+ used in the response.
+ */
+ p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
+ p_resp_sa_mad->attr_offset = ib_get_attr_offset( sizeof(ib_path_rec_t) );
+
+ p_resp_sa_mad->rmpp_flags = IB_RMPP_FLAG_ACTIVE;
+
+ p_resp_pr = (ib_path_rec_t*)ib_sa_mad_get_payload_ptr( p_resp_sa_mad );
+
+ for ( i = 0; i < num_rec; i++ )
+ {
+ p_mpr_item = (osm_mpr_item_t*)cl_qlist_remove_head( p_list );
+
+ /* Copy the Path Records from the list into the MAD */
+ *p_resp_pr = p_mpr_item->path_rec;
+
+ cl_qlock_pool_put( &p_rcv->pr_pool, &p_mpr_item->pool_item );
+ p_resp_pr++;
+ }
+
+ CL_ASSERT( cl_is_qlist_empty( p_list ) );
+
+ osm_dump_sa_mad( p_rcv->p_log, p_resp_sa_mad, OSM_LOG_FRAMES );
+
+ status = osm_vendor_send( p_resp_madw->h_bind, p_resp_madw, FALSE );
+
+ if ( status != IB_SUCCESS )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "__osm_mpr_rcv_respond: ERR 4507: "
+ "Unable to send MAD (%s)\n", ib_get_err_str( status ) );
+ /* osm_mad_pool_put( p_rcv->p_mad_pool, p_resp_madw ); */
+ }
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+}
+
+/**********************************************************************
+ **********************************************************************/
+void
+osm_mpr_rcv_process(
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN osm_madw_t* const p_madw )
+{
+ const ib_multipath_rec_t* p_mpr;
+ const ib_sa_mad_t* p_sa_mad;
+ osm_port_t* requester_port;
+ osm_port_t* pp_ports[IB_MULTIPATH_MAX_GIDS];
+ cl_qlist_t pr_list;
+ ib_net16_t sa_status;
+ int nsrc, ndest;
+
+ OSM_LOG_ENTER( p_rcv->p_log, osm_mpr_rcv_process );
+
+ CL_ASSERT( p_madw );
+
+ /* update the requester physical port. */
+ requester_port = osm_get_port_by_mad_addr( p_rcv->p_log, p_rcv->p_subn,
+ osm_madw_get_mad_addr_ptr( p_madw ) );
+ if ( requester_port == NULL )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "osm_mpr_rcv_process: ERR 4516: "
+ "Cannot find requester physical port\n" );
+ goto Exit;
+ }
+
+ p_sa_mad = osm_madw_get_sa_mad_ptr( p_madw );
+ p_mpr = (ib_multipath_rec_t*)ib_sa_mad_get_payload_ptr( p_sa_mad );
+
+ CL_ASSERT( p_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD );
+
+ if ( ( p_sa_mad->rmpp_flags & IB_RMPP_FLAG_ACTIVE ) != IB_RMPP_FLAG_ACTIVE )
+ {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "osm_mpr_rcv_process: ERR 4510: "
+ "Invalid request as RMPP_FLAG_ACTIVE is not set\n" );
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_REQ_INVALID );
+ goto Exit;
+ }
+
+ if ( p_sa_mad->method != IB_MAD_METHOD_GETMULTI ) {
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR,
+ "osm_mpr_rcv_process: ERR 4513: "
+ "Unsupported Method (%s)\n",
+ ib_get_sa_method_str( p_sa_mad->method ) );
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_REQ_INVALID );
+ goto Exit;
+ }
+
+ if ( osm_log_is_active( p_rcv->p_log, OSM_LOG_DEBUG ) )
+ osm_dump_multipath_record( p_rcv->p_log, p_mpr, OSM_LOG_DEBUG );
+
+ cl_qlist_init( &pr_list );
+
+ /*
+ Most SA functions (including this one) are read-only on the
+ subnet object, so we grab the lock non-exclusively.
+ */
+ cl_plock_acquire( p_rcv->p_lock );
+
+ sa_status = __osm_mpr_rcv_get_end_points( p_rcv, p_madw, pp_ports,
+ &nsrc, &ndest );
+
+ if ( sa_status != IB_SA_MAD_STATUS_SUCCESS || !nsrc || !ndest )
+ {
+ if ( sa_status == IB_SA_MAD_STATUS_SUCCESS && ( !nsrc || !ndest ) )
+ osm_log( p_rcv->p_log, OSM_LOG_ERROR, "osm_mpr_rcv_process_cb: ERR 4512: "
+ "__osm_mpr_rcv_get_end_points failed, not enough GIDs "
+ "(nsrc %d ndest %d)\n",
+ nsrc, ndest);
+ cl_plock_release( p_rcv->p_lock );
+ if ( sa_status == IB_SA_MAD_STATUS_SUCCESS )
+ osm_sa_send_error( p_rcv->p_resp, p_madw, IB_SA_MAD_STATUS_REQ_INVALID );
+ else
+ osm_sa_send_error( p_rcv->p_resp, p_madw, sa_status );
+ goto Exit;
+ }
+
+ /* APM request */
+ if ( nsrc == 2 && ndest == 2 && ( p_mpr->num_path & 0x7F ) == 2 )
+ __osm_mpr_rcv_get_apm_paths( p_rcv, p_mpr, requester_port, pp_ports,
+ p_sa_mad->comp_mask, &pr_list );
+ else
+ __osm_mpr_rcv_process_pairs( p_rcv, p_mpr, requester_port, pp_ports,
+ nsrc, ndest,
+ p_sa_mad->comp_mask, &pr_list );
+
+ cl_plock_release( p_rcv->p_lock );
+ __osm_mpr_rcv_respond( p_rcv, p_madw, &pr_list );
+
+ Exit:
+ OSM_LOG_EXIT( p_rcv->p_log );
+}
+#endif
Property changes on: osm/opensm/osm_sa_multipath_record.c
___________________________________________________________________
Name: svn:keywords
+ Id
Index: osm/opensm/osm_helper.c
===================================================================
--- osm/opensm/osm_helper.c (revision 6920)
+++ osm/opensm/osm_helper.c (working copy)
@@ -952,6 +952,79 @@ osm_dump_path_record(
/**********************************************************************
**********************************************************************/
void
+osm_dump_multipath_record(
+ IN osm_log_t* const p_log,
+ IN const ib_multipath_rec_t* const p_mpr,
+ IN const osm_log_level_t log_level )
+{
+ int i;
+ char buf_line[1024];
+ ib_gid_t const *p_gid;
+
+ if( osm_log_is_active( p_log, log_level ) )
+ {
+ cl_memclr(buf_line, sizeof(buf_line));
+ p_gid = p_mpr->gids;
+ if ( p_mpr->sgid_count )
+ {
+ for (i = 0; i < p_mpr->sgid_count; i++)
+ {
+ sprintf( buf_line, "%s\t\t\t\tsgid%02d.................."
+ "0x%016" PRIx64 " : 0x%016" PRIx64 "\n",
+ buf_line, i + 1, cl_ntoh64( p_gid->unicast.prefix ),
+ cl_ntoh64( p_gid->unicast.interface_id ) );
+ p_gid++;
+ }
+ }
+ if ( p_mpr->dgid_count )
+ {
+ for (i = 0; i < p_mpr->dgid_count; i++)
+ {
+ sprintf( buf_line, "%s\t\t\t\tdgid%02d.................."
+ "0x%016" PRIx64 " : 0x%016" PRIx64 "\n",
+ buf_line, i + 1, cl_ntoh64( p_gid->unicast.prefix ),
+ cl_ntoh64( p_gid->unicast.interface_id ) );
+ p_gid++;
+ }
+ }
+ osm_log( p_log, log_level,
+ "MultiPathRecord dump:\n"
+ "\t\t\t\thop_flow_raw............0x%X\n"
+ "\t\t\t\ttclass..................0x%X\n"
+ "\t\t\t\tnum_path_revers.........0x%X\n"
+ "\t\t\t\tpkey....................0x%X\n"
+ "\t\t\t\tresv0...................0x%X\n"
+ "\t\t\t\tsl......................0x%X\n"
+ "\t\t\t\tmtu.....................0x%X\n"
+ "\t\t\t\trate....................0x%X\n"
+ "\t\t\t\tpkt_life................0x%X\n"
+ "\t\t\t\tresv1...................0x%X\n"
+ "\t\t\t\tindependence............0x%X\n"
+ "\t\t\t\tsgid_count..............0x%X\n"
+ "\t\t\t\tdgid_count..............0x%X\n"
+ "%s\n"
+ "",
+ cl_ntoh32( p_mpr->hop_flow_raw ),
+ p_mpr->tclass,
+ p_mpr->num_path,
+ cl_ntoh16( p_mpr->pkey ),
+ p_mpr->resv0,
+ cl_ntoh16( p_mpr->sl ),
+ p_mpr->mtu,
+ p_mpr->rate,
+ p_mpr->pkt_life,
+ p_mpr->resv1,
+ p_mpr->independence,
+ p_mpr->sgid_count,
+ p_mpr->dgid_count,
+ buf_line
+ );
+ }
+}
+
+/**********************************************************************
+ **********************************************************************/
+void
osm_dump_mc_record(
IN osm_log_t* const p_log,
IN const ib_member_rec_t* const p_mcmr,
Index: osm/opensm/osm_sa_response.c
===================================================================
--- osm/opensm/osm_sa_response.c (revision 6920)
+++ osm/opensm/osm_sa_response.c (working copy)
@@ -154,6 +154,13 @@ osm_sa_send_error(
*/
p_resp_sa_mad->sm_key = 0;
+ /*
+ * o15-0.2.7 - The PathRecord Attribute ID shall be used in
+ * the response (to a SubnAdmGetMulti(MultiPathRecord)
+ */
+ if( p_resp_sa_mad->attr_id == IB_MAD_ATTR_MULTIPATH_RECORD )
+ p_resp_sa_mad->attr_id = IB_MAD_ATTR_PATH_RECORD;
+
if( osm_log_is_active( p_resp->p_log, OSM_LOG_FRAMES ) )
osm_dump_sa_mad( p_resp->p_log, p_resp_sa_mad, OSM_LOG_FRAMES );
Index: osm/opensm/osm_sa.c
===================================================================
--- osm/opensm/osm_sa.c (revision 6920)
+++ osm/opensm/osm_sa.c (working copy)
@@ -98,6 +98,11 @@ osm_sa_construct(
osm_pr_rcv_construct( &p_sa->pr_rcv );
osm_pr_rcv_ctrl_construct( &p_sa->pr_rcv_ctrl );
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ osm_mpr_rcv_construct( &p_sa->mpr_rcv );
+ osm_mpr_rcv_ctrl_construct( &p_sa->mpr_rcv_ctrl );
+#endif
+
osm_smir_rcv_construct( &p_sa->smir_rcv );
osm_smir_ctrl_construct( &p_sa->smir_ctrl );
@@ -141,6 +146,9 @@ osm_sa_shutdown(
osm_gir_rcv_ctrl_destroy( &p_sa->gir_rcv_ctrl );
osm_lr_rcv_ctrl_destroy( &p_sa->lr_rcv_ctrl );
osm_pr_rcv_ctrl_destroy( &p_sa->pr_rcv_ctrl );
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ osm_mpr_rcv_ctrl_destroy( &p_sa->mpr_rcv_ctrl );
+#endif
osm_smir_ctrl_destroy( &p_sa->smir_ctrl );
osm_mcmr_rcv_ctrl_destroy( &p_sa->mcmr_rcv_ctlr);
osm_sr_rcv_ctrl_destroy( &p_sa->sr_rcv_ctrl );
@@ -169,6 +177,9 @@ osm_sa_destroy(
osm_gir_rcv_destroy( &p_sa->gir_rcv );
osm_lr_rcv_destroy( &p_sa->lr_rcv );
osm_pr_rcv_destroy( &p_sa->pr_rcv );
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ osm_mpr_rcv_destroy( &p_sa->mpr_rcv );
+#endif
osm_smir_rcv_destroy( &p_sa->smir_rcv );
osm_mcmr_rcv_destroy(&p_sa->mcmr_rcv);
osm_sr_rcv_destroy( &p_sa->sr_rcv );
@@ -335,6 +346,26 @@ osm_sa_init(
if( status != IB_SUCCESS )
goto Exit;
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ status = osm_mpr_rcv_init(
+ &p_sa->mpr_rcv,
+ &p_sa->resp,
+ p_sa->p_mad_pool,
+ p_subn,
+ p_log,
+ p_lock );
+ if( status != IB_SUCCESS )
+ goto Exit;
+
+ status = osm_mpr_rcv_ctrl_init(
+ &p_sa->mpr_rcv_ctrl,
+ &p_sa->mpr_rcv,
+ p_log,
+ p_disp );
+ if( status != IB_SUCCESS )
+ goto Exit;
+#endif
+
status = osm_smir_rcv_init(
&p_sa->smir_rcv,
&p_sa->resp,
Index: osm/opensm/osm_sa_class_port_info.c
===================================================================
--- osm/opensm/osm_sa_class_port_info.c (revision 6920)
+++ osm/opensm/osm_sa_class_port_info.c (working copy)
@@ -219,8 +219,14 @@ __osm_cpi_rcv_respond(
*/
/* Note host notation replaced later */
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
p_resp_cpi->cap_mask = OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP |
- OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED;
+ OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED |
+ OSM_CAP_IS_MULTIPATH_SUP;
+#else
+ p_resp_cpi->cap_mask = OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP |
+ OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED;
+#endif
if (p_rcv->p_subn->opt.no_multicast_option != TRUE)
p_resp_cpi->cap_mask |= OSM_CAP_IS_UD_MCAST_SUP;
p_resp_cpi->cap_mask = cl_hton16(p_resp_cpi->cap_mask);
Index: osm/opensm/libopensm.map
===================================================================
--- osm/opensm/libopensm.map (revision 6920)
+++ osm/opensm/libopensm.map (working copy)
@@ -21,6 +21,7 @@ OPENSM_1.0 {
osm_dump_node_info;
osm_dump_node_record;
osm_dump_path_record;
+ osm_dump_multipath_record;
osm_dump_mc_record;
osm_dump_service_record;
osm_dump_inform_info;
Index: osm/opensm/osm_sa_mad_ctrl.c
===================================================================
--- osm/opensm/osm_sa_mad_ctrl.c (revision 6920)
+++ osm/opensm/osm_sa_mad_ctrl.c (working copy)
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2004-2006 Voltaire, Inc. All rights reserved.
* Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
* Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
*
@@ -209,6 +209,12 @@ __osm_sa_mad_ctrl_process(
msg_id = OSM_MSG_MAD_GUIDINFO_RECORD;
break;
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ case IB_MAD_ATTR_MULTIPATH_RECORD:
+ msg_id = OSM_MSG_MAD_MULTIPATH_RECORD;
+ break;
+#endif
+
default:
osm_log( p_ctrl->p_log, OSM_LOG_ERROR,
"__osm_sa_mad_ctrl_process: ERR 1A01: "
@@ -370,6 +376,9 @@ __osm_sa_mad_ctrl_rcv_callback(
case IB_MAD_METHOD_GET:
case IB_MAD_METHOD_GETTABLE:
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+ case IB_MAD_METHOD_GETMULTI:
+#endif
case IB_MAD_METHOD_SET:
case IB_MAD_METHOD_DELETE:
__osm_sa_mad_ctrl_process( p_ctrl, p_madw );
Index: osm/opensm/osm_sa_multipath_record_ctrl.c
===================================================================
--- osm/opensm/osm_sa_multipath_record_ctrl.c (revision 0)
+++ osm/opensm/osm_sa_multipath_record_ctrl.c (revision 0)
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2006 Voltaire, Inc. All rights reserved.
+ * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
+ * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * $Id$
+ */
+
+
+/*
+ * Abstract:
+ * Implementation of osm_mpr_rcv_ctrl_t.
+ * This object represents the MultiPathRecord request controller object.
+ * This object is part of the opensm family of objects.
+ *
+ * Environment:
+ * Linux User Mode
+ *
+ */
+
+/*
+ Next available error code: 0x203
+*/
+
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+
+#if HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_memory.h>
+#include <opensm/osm_sa_multipath_record_ctrl.h>
+#include <opensm/osm_msgdef.h>
+
+/**********************************************************************
+ **********************************************************************/
+static void
+__osm_mpr_rcv_ctrl_disp_callback(
+ IN void *context,
+ IN void *p_data )
+{
+ /* ignore return status when invoked via the dispatcher */
+ osm_mpr_rcv_process( ((osm_mpr_rcv_ctrl_t*)context)->p_rcv,
+ (osm_madw_t*)p_data );
+}
+
+/**********************************************************************
+ **********************************************************************/
+void
+osm_mpr_rcv_ctrl_construct(
+ IN osm_mpr_rcv_ctrl_t* const p_ctrl )
+{
+ cl_memclr( p_ctrl, sizeof(*p_ctrl) );
+ p_ctrl->h_disp = CL_DISP_INVALID_HANDLE;
+}
+
+/**********************************************************************
+ **********************************************************************/
+void
+osm_mpr_rcv_ctrl_destroy(
+ IN osm_mpr_rcv_ctrl_t* const p_ctrl )
+{
+ CL_ASSERT( p_ctrl );
+ cl_disp_unregister( p_ctrl->h_disp );
+}
+
+/**********************************************************************
+ **********************************************************************/
+ib_api_status_t
+osm_mpr_rcv_ctrl_init(
+ IN osm_mpr_rcv_ctrl_t* const p_ctrl,
+ IN osm_mpr_rcv_t* const p_rcv,
+ IN osm_log_t* const p_log,
+ IN cl_dispatcher_t* const p_disp )
+{
+ ib_api_status_t status = IB_SUCCESS;
+
+ OSM_LOG_ENTER( p_log, osm_mpr_rcv_ctrl_init );
+
+ osm_mpr_rcv_ctrl_construct( p_ctrl );
+ p_ctrl->p_log = p_log;
+ p_ctrl->p_rcv = p_rcv;
+ p_ctrl->p_disp = p_disp;
+
+ p_ctrl->h_disp = cl_disp_register(
+ p_disp,
+ OSM_MSG_MAD_MULTIPATH_RECORD,
+ __osm_mpr_rcv_ctrl_disp_callback,
+ p_ctrl );
+
+ if( p_ctrl->h_disp == CL_DISP_INVALID_HANDLE )
+ {
+ osm_log( p_log, OSM_LOG_ERROR,
+ "osm_mpr_rcv_ctrl_init: ERR 4B01: "
+ "Dispatcher registration failed\n" );
+ status = IB_INSUFFICIENT_RESOURCES;
+ goto Exit;
+ }
+
+ Exit:
+ OSM_LOG_EXIT( p_log );
+ return( status );
+}
+
+#endif
Property changes on: osm/opensm/osm_sa_multipath_record_ctrl.c
___________________________________________________________________
Name: svn:keywords
+ Id
Index: osm/opensm/Makefile.am
===================================================================
--- osm/opensm/Makefile.am (revision 6920)
+++ osm/opensm/Makefile.am (working copy)
@@ -69,6 +73,7 @@ opensm_SOURCES = main.c osm_console.c os
osm_sa_pkey_record.c osm_sa_pkey_record_ctrl.c \
osm_sa_portinfo_record.c osm_sa_portinfo_record_ctrl.c \
osm_sa_guidinfo_record.c osm_sa_guidinfo_record_ctrl.c \
+ osm_sa_multipath_record.c osm_sa_multipath_record_ctrl.c \
osm_sa_response.c osm_sa_service_record.c \
osm_sa_service_record_ctrl.c osm_sa_slvl_record.c \
osm_sa_slvl_record_ctrl.c osm_sa_sminfo_record.c \
More information about the general
mailing list