1219820Sjeff/*
2219820Sjeff * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
3219820Sjeff * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
4219820Sjeff * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
5219820Sjeff *
6219820Sjeff * This software is available to you under a choice of one of two
7219820Sjeff * licenses.  You may choose to be licensed under the terms of the GNU
8219820Sjeff * General Public License (GPL) Version 2, available from the file
9219820Sjeff * COPYING in the main directory of this source tree, or the
10219820Sjeff * OpenIB.org BSD license below:
11219820Sjeff *
12219820Sjeff *     Redistribution and use in source and binary forms, with or
13219820Sjeff *     without modification, are permitted provided that the following
14219820Sjeff *     conditions are met:
15219820Sjeff *
16219820Sjeff *      - Redistributions of source code must retain the above
17219820Sjeff *        copyright notice, this list of conditions and the following
18219820Sjeff *        disclaimer.
19219820Sjeff *
20219820Sjeff *      - Redistributions in binary form must reproduce the above
21219820Sjeff *        copyright notice, this list of conditions and the following
22219820Sjeff *        disclaimer in the documentation and/or other materials
23219820Sjeff *        provided with the distribution.
24219820Sjeff *
25219820Sjeff * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26219820Sjeff * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27219820Sjeff * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28219820Sjeff * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
29219820Sjeff * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
30219820Sjeff * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
31219820Sjeff * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32219820Sjeff * SOFTWARE.
33219820Sjeff *
34219820Sjeff */
35219820Sjeff
36219820Sjeff/*
37219820Sjeff * Abstract:
38219820Sjeff *    Implementation of osm_cpi_rcv_t.
39219820Sjeff * This object represents the ClassPortInfo Receiver object.
40219820Sjeff * This object is part of the opensm family of objects.
41219820Sjeff */
42219820Sjeff
43219820Sjeff#if HAVE_CONFIG_H
44219820Sjeff#  include <config.h>
45219820Sjeff#endif				/* HAVE_CONFIG_H */
46219820Sjeff
47219820Sjeff#include <string.h>
48219820Sjeff#include <iba/ib_types.h>
49219820Sjeff#include <complib/cl_qmap.h>
50219820Sjeff#include <complib/cl_passivelock.h>
51219820Sjeff#include <complib/cl_debug.h>
52219820Sjeff#include <complib/cl_qlist.h>
53219820Sjeff#include <vendor/osm_vendor_api.h>
54219820Sjeff#include <opensm/osm_helper.h>
55219820Sjeff#include <opensm/osm_sa.h>
56219820Sjeff
57219820Sjeff#define MAX_MSECS_TO_RTV 24
58219820Sjeff/* Precalculated table in msec (index is related to encoded value) */
59219820Sjeff/* 4.096 usec * 2 ** n (where n = 8 - 31) */
60219820Sjeffconst static uint32_t __msecs_to_rtv_table[MAX_MSECS_TO_RTV] = {
61219820Sjeff	1, 2, 4, 8,
62219820Sjeff	16, 33, 67, 134,
63219820Sjeff	268, 536, 1073, 2147,
64219820Sjeff	4294, 8589, 17179, 34359,
65219820Sjeff	68719, 137438, 274877, 549755,
66219820Sjeff	1099511, 2199023, 4398046, 8796093
67219820Sjeff};
68219820Sjeff
69219820Sjeff/**********************************************************************
70219820Sjeff **********************************************************************/
71219820Sjeffstatic void
72219820Sjeff__osm_cpi_rcv_respond(IN osm_sa_t * sa,
73219820Sjeff		      IN const osm_madw_t * const p_madw)
74219820Sjeff{
75219820Sjeff	osm_madw_t *p_resp_madw;
76219820Sjeff	const ib_sa_mad_t *p_sa_mad;
77219820Sjeff	ib_sa_mad_t *p_resp_sa_mad;
78219820Sjeff	ib_class_port_info_t *p_resp_cpi;
79219820Sjeff	ib_gid_t zero_gid;
80219820Sjeff	uint8_t rtv;
81219820Sjeff
82219820Sjeff	OSM_LOG_ENTER(sa->p_log);
83219820Sjeff
84219820Sjeff	memset(&zero_gid, 0, sizeof(ib_gid_t));
85219820Sjeff
86219820Sjeff	/*
87219820Sjeff	   Get a MAD to reply. Address of Mad is in the received mad_wrapper
88219820Sjeff	 */
89219820Sjeff	p_resp_madw = osm_mad_pool_get(sa->p_mad_pool, p_madw->h_bind,
90219820Sjeff				       MAD_BLOCK_SIZE, &p_madw->mad_addr);
91219820Sjeff	if (!p_resp_madw) {
92219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1408: "
93219820Sjeff			"Unable to allocate MAD\n");
94219820Sjeff		goto Exit;
95219820Sjeff	}
96219820Sjeff
97219820Sjeff	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
98219820Sjeff	p_resp_sa_mad = osm_madw_get_sa_mad_ptr(p_resp_madw);
99219820Sjeff
100219820Sjeff	memcpy(p_resp_sa_mad, p_sa_mad, IB_SA_MAD_HDR_SIZE);
101219820Sjeff	p_resp_sa_mad->method |= IB_MAD_METHOD_RESP_MASK;
102219820Sjeff	/* C15-0.1.5 - always return SM_Key = 0 (table 185 p 884) */
103219820Sjeff	p_resp_sa_mad->sm_key = 0;
104219820Sjeff
105219820Sjeff	p_resp_cpi =
106219820Sjeff	    (ib_class_port_info_t *) ib_sa_mad_get_payload_ptr(p_resp_sa_mad);
107219820Sjeff
108219820Sjeff	/* finally do it (the job) man ! */
109219820Sjeff	p_resp_cpi->base_ver = 1;
110219820Sjeff	p_resp_cpi->class_ver = 2;
111219820Sjeff	/* Calculate encoded response time value */
112219820Sjeff	/* transaction timeout is in msec */
113219820Sjeff	if (sa->p_subn->opt.transaction_timeout >
114219820Sjeff	    __msecs_to_rtv_table[MAX_MSECS_TO_RTV - 1])
115219820Sjeff		rtv = MAX_MSECS_TO_RTV - 1;
116219820Sjeff	else {
117219820Sjeff		for (rtv = 0; rtv < MAX_MSECS_TO_RTV; rtv++) {
118219820Sjeff			if (sa->p_subn->opt.transaction_timeout <=
119219820Sjeff			    __msecs_to_rtv_table[rtv])
120219820Sjeff				break;
121219820Sjeff		}
122219820Sjeff	}
123219820Sjeff	rtv += 8;
124219820Sjeff	ib_class_set_resp_time_val(p_resp_cpi, rtv);
125219820Sjeff	p_resp_cpi->redir_gid = zero_gid;
126219820Sjeff	p_resp_cpi->redir_tc_sl_fl = 0;
127219820Sjeff	p_resp_cpi->redir_lid = 0;
128219820Sjeff	p_resp_cpi->redir_pkey = 0;
129219820Sjeff	p_resp_cpi->redir_qp = CL_NTOH32(1);
130219820Sjeff	p_resp_cpi->redir_qkey = IB_QP1_WELL_KNOWN_Q_KEY;
131219820Sjeff	p_resp_cpi->trap_gid = zero_gid;
132219820Sjeff	p_resp_cpi->trap_tc_sl_fl = 0;
133219820Sjeff	p_resp_cpi->trap_lid = 0;
134219820Sjeff	p_resp_cpi->trap_pkey = 0;
135219820Sjeff	p_resp_cpi->trap_hop_qp = 0;
136219820Sjeff	p_resp_cpi->trap_qkey = IB_QP1_WELL_KNOWN_Q_KEY;
137219820Sjeff
138219820Sjeff	/* set specific capability mask bits */
139219820Sjeff	/* we do not support the following options/optional records:
140219820Sjeff	   OSM_CAP_IS_SUBN_OPT_RECS_SUP :
141219820Sjeff	   RandomForwardingTableRecord,
142219820Sjeff	   ServiceAssociationRecord
143219820Sjeff	   other optional records supported "under the table"
144219820Sjeff
145219820Sjeff	   OSM_CAP_IS_MULTIPATH_SUP:
146219820Sjeff	   TraceRecord
147219820Sjeff
148219820Sjeff	   OSM_CAP_IS_REINIT_SUP:
149219820Sjeff	   For reinitialization functionality.
150219820Sjeff
151219820Sjeff	   So not sending traps, but supporting Get(Notice) and Set(Notice).
152219820Sjeff	 */
153219820Sjeff
154219820Sjeff	/* Note host notation replaced later */
155219820Sjeff#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
156219820Sjeff	p_resp_cpi->cap_mask = OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP |
157219820Sjeff	    OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED |
158219820Sjeff	    OSM_CAP_IS_MULTIPATH_SUP;
159219820Sjeff#else
160219820Sjeff	p_resp_cpi->cap_mask = OSM_CAP_IS_SUBN_GET_SET_NOTICE_SUP |
161219820Sjeff	    OSM_CAP_IS_PORT_INFO_CAPMASK_MATCH_SUPPORTED;
162219820Sjeff#endif
163219820Sjeff	if (sa->p_subn->opt.qos)
164219820Sjeff		ib_class_set_cap_mask2(p_resp_cpi, OSM_CAP2_IS_QOS_SUPPORTED);
165219820Sjeff
166219820Sjeff	if (!sa->p_subn->opt.disable_multicast)
167219820Sjeff		p_resp_cpi->cap_mask |= OSM_CAP_IS_UD_MCAST_SUP;
168219820Sjeff	p_resp_cpi->cap_mask = cl_hton16(p_resp_cpi->cap_mask);
169219820Sjeff
170219820Sjeff	if (osm_log_is_active(sa->p_log, OSM_LOG_FRAMES))
171219820Sjeff		osm_dump_sa_mad(sa->p_log, p_resp_sa_mad, OSM_LOG_FRAMES);
172219820Sjeff
173219820Sjeff	osm_sa_send(sa, p_resp_madw, FALSE);
174219820Sjeff
175219820SjeffExit:
176219820Sjeff	OSM_LOG_EXIT(sa->p_log);
177219820Sjeff}
178219820Sjeff
179219820Sjeff/**********************************************************************
180219820Sjeff * This code actually handles the call
181219820Sjeff **********************************************************************/
182219820Sjeffvoid osm_cpi_rcv_process(IN void *context, IN void *data)
183219820Sjeff{
184219820Sjeff	osm_sa_t *sa = context;
185219820Sjeff	osm_madw_t *p_madw = data;
186219820Sjeff	const ib_sa_mad_t *p_sa_mad;
187219820Sjeff
188219820Sjeff	OSM_LOG_ENTER(sa->p_log);
189219820Sjeff
190219820Sjeff	CL_ASSERT(p_madw);
191219820Sjeff
192219820Sjeff	p_sa_mad = osm_madw_get_sa_mad_ptr(p_madw);
193219820Sjeff
194219820Sjeff	/* we only support GET */
195219820Sjeff	if (p_sa_mad->method != IB_MAD_METHOD_GET) {
196219820Sjeff		OSM_LOG(sa->p_log, OSM_LOG_ERROR, "ERR 1403: "
197219820Sjeff			"Unsupported Method (%s)\n",
198219820Sjeff			ib_get_sa_method_str(p_sa_mad->method));
199219820Sjeff		osm_sa_send_error(sa, p_madw, IB_SA_MAD_STATUS_REQ_INVALID);
200219820Sjeff		goto Exit;
201219820Sjeff	}
202219820Sjeff
203219820Sjeff	CL_ASSERT(p_sa_mad->attr_id == IB_MAD_ATTR_CLASS_PORT_INFO);
204219820Sjeff
205219820Sjeff	/*
206219820Sjeff	   CLASS PORT INFO does not really look on the SMDB - no lock required.
207219820Sjeff	 */
208219820Sjeff
209219820Sjeff	__osm_cpi_rcv_respond(sa, p_madw);
210219820Sjeff
211219820SjeffExit:
212219820Sjeff	OSM_LOG_EXIT(sa->p_log);
213219820Sjeff}
214