2 * Copyright (c) 2009 Sun Microsystems, Inc. All rights reserved.
3 * Copyright (c) 2004-2009 Voltaire, Inc. All rights reserved.
4 * Copyright (c) 2002-2010 Mellanox Technologies LTD. All rights reserved.
5 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
7 * This software is available to you under a choice of one of two
8 * licenses. You may choose to be licensed under the terms of the GNU
9 * General Public License (GPL) Version 2, available from the file
10 * COPYING in the main directory of this source tree, or the
11 * OpenIB.org BSD license below:
13 * Redistribution and use in source and binary forms, with or
14 * without modification, are permitted provided that the following
17 * - Redistributions of source code must retain the above
18 * copyright notice, this list of conditions and the following
21 * - Redistributions in binary form must reproduce the above
22 * copyright notice, this list of conditions and the following
23 * disclaimer in the documentation and/or other materials
24 * provided with the distribution.
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
30 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
31 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
32 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
39 * Implementation of osm_vl15_t.
40 * This object represents the VL15 Interface object.
41 * This object is part of the opensm family of objects.
46 #endif /* HAVE_CONFIG_H */
49 #include <iba/ib_types.h>
50 #include <complib/cl_thread.h>
51 #include <opensm/osm_file_ids.h>
52 #define FILE_ID OSM_FILE_VL15INTF_C
53 #include <vendor/osm_vendor_api.h>
54 #include <opensm/osm_vl15intf.h>
55 #include <opensm/osm_madw.h>
56 #include <opensm/osm_log.h>
57 #include <opensm/osm_helper.h>
59 static void vl15_send_mad(osm_vl15_t * p_vl, osm_madw_t * p_madw)
61 ib_api_status_t status;
62 boolean_t resp_expected = p_madw->resp_expected;
67 p_smp = osm_madw_get_smp_ptr(p_madw);
68 method = p_smp->method;
69 attr_id = p_smp->attr_id;
72 Non-response-expected mads are not throttled on the wire
73 since we can have no confirmation that they arrived
78 Note that other threads may not see the response MAD
79 arrive before send() even returns.
80 In that case, the wire count would temporarily go negative.
81 To avoid this confusion, preincrement the counts on the
82 assumption that send() will succeed.
84 cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding_on_wire);
86 cl_atomic_inc(&p_vl->p_stats->qp0_unicasts_sent);
88 cl_atomic_inc(&p_vl->p_stats->qp0_mads_sent);
90 status = osm_vendor_send(osm_madw_get_bind_handle(p_madw),
91 p_madw, p_madw->resp_expected);
93 if (status == IB_SUCCESS) {
94 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
95 "%u QP0 MADs on wire, %u outstanding, "
96 "%u unicasts sent, %u total sent\n",
97 p_vl->p_stats->qp0_mads_outstanding_on_wire,
98 p_vl->p_stats->qp0_mads_outstanding,
99 p_vl->p_stats->qp0_unicasts_sent,
100 p_vl->p_stats->qp0_mads_sent);
104 OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E03: "
105 "MAD send failed (%s)\n", ib_get_err_str(status));
108 The MAD was never successfully sent, so
109 fix up the pre-incremented count values.
112 /* Decrement qp0_mads_sent that were incremented in the code above.
113 qp0_mads_outstanding will be decremented by send error callback
114 (called by osm_vendor_send() */
115 cl_atomic_dec(&p_vl->p_stats->qp0_mads_sent);
116 if (!resp_expected) {
117 cl_atomic_dec(&p_vl->p_stats->qp0_unicasts_sent);
121 /* need to cause heavy-sweep if resp_expected MAD sending failed */
122 OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E04: "
123 "%s method failed for attribute 0x%X (%s)\n",
124 method == IB_MAD_METHOD_SET ? "SET" : "GET",
125 cl_ntoh16(attr_id), ib_get_sm_attr_str(attr_id));
127 p_vl->p_subn->subnet_initialization_error = TRUE;
131 static void vl15_poller(IN void *p_ptr)
133 ib_api_status_t status;
135 osm_vl15_t *p_vl = p_ptr;
137 int32_t max_smps = p_vl->max_wire_smps;
138 int32_t max_smps2 = p_vl->max_wire_smps2;
140 OSM_LOG_ENTER(p_vl->p_log);
142 if (p_vl->thread_state == OSM_THREAD_STATE_NONE)
143 p_vl->thread_state = OSM_THREAD_STATE_RUN;
145 while (p_vl->thread_state == OSM_THREAD_STATE_RUN) {
147 Start servicing the FIFOs by pulling off MAD wrappers
148 and passing them to the transport interface.
149 There are lots of corner cases here so tread carefully.
151 The unicast FIFO has priority, since somebody is waiting
152 for a timely response.
154 cl_spinlock_acquire(&p_vl->lock);
156 if (cl_qlist_count(&p_vl->ufifo) != 0)
157 p_fifo = &p_vl->ufifo;
159 p_fifo = &p_vl->rfifo;
161 p_madw = (osm_madw_t *) cl_qlist_remove_head(p_fifo);
163 cl_spinlock_release(&p_vl->lock);
165 if (p_madw != (osm_madw_t *) cl_qlist_end(p_fifo)) {
166 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
167 "Servicing p_madw = %p\n", p_madw);
168 if (OSM_LOG_IS_ACTIVE_V2(p_vl->p_log, OSM_LOG_FRAMES))
169 osm_dump_dr_smp_v2(p_vl->p_log,
170 osm_madw_get_smp_ptr(p_madw),
171 FILE_ID, OSM_LOG_FRAMES);
173 vl15_send_mad(p_vl, p_madw);
176 The VL15 FIFO is empty, so we have nothing left to do.
178 status = cl_event_wait_on(&p_vl->signal,
179 EVENT_NO_TIMEOUT, TRUE);
181 while (p_vl->p_stats->qp0_mads_outstanding_on_wire >= max_smps &&
182 p_vl->thread_state == OSM_THREAD_STATE_RUN) {
183 status = cl_event_wait_on(&p_vl->signal,
184 p_vl->max_smps_timeout,
186 if (status == CL_TIMEOUT) {
187 if (max_smps < max_smps2)
190 } else if (status != CL_SUCCESS) {
191 OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E02: "
192 "Event wait failed (%s)\n",
193 CL_STATUS_MSG(status));
196 max_smps = p_vl->max_wire_smps;
201 since we abort immediately when the state != OSM_THREAD_STATE_RUN
202 we might have some mads on the queues. After the thread exits
203 the vl15 destroy routine should put these mads back...
206 OSM_LOG_EXIT(p_vl->p_log);
209 void osm_vl15_construct(IN osm_vl15_t * p_vl)
211 memset(p_vl, 0, sizeof(*p_vl));
212 p_vl->state = OSM_VL15_STATE_INIT;
213 p_vl->thread_state = OSM_THREAD_STATE_NONE;
214 cl_event_construct(&p_vl->signal);
215 cl_spinlock_construct(&p_vl->lock);
216 cl_qlist_init(&p_vl->rfifo);
217 cl_qlist_init(&p_vl->ufifo);
218 cl_thread_construct(&p_vl->poller);
221 void osm_vl15_destroy(IN osm_vl15_t * p_vl, IN struct osm_mad_pool *p_pool)
225 OSM_LOG_ENTER(p_vl->p_log);
228 Signal our threads that we're leaving.
230 p_vl->thread_state = OSM_THREAD_STATE_EXIT;
233 Don't trigger unless event has been initialized.
234 Destroy the thread before we tear down the other objects.
236 if (p_vl->state != OSM_VL15_STATE_INIT)
237 cl_event_signal(&p_vl->signal);
239 cl_thread_destroy(&p_vl->poller);
242 Return the outstanding messages to the pool
245 cl_spinlock_acquire(&p_vl->lock);
247 while (!cl_is_qlist_empty(&p_vl->rfifo)) {
248 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
249 osm_mad_pool_put(p_pool, p_madw);
251 while (!cl_is_qlist_empty(&p_vl->ufifo)) {
252 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
253 osm_mad_pool_put(p_pool, p_madw);
256 cl_spinlock_release(&p_vl->lock);
258 cl_event_destroy(&p_vl->signal);
259 p_vl->state = OSM_VL15_STATE_INIT;
260 cl_spinlock_destroy(&p_vl->lock);
262 OSM_LOG_EXIT(p_vl->p_log);
265 ib_api_status_t osm_vl15_init(IN osm_vl15_t * p_vl, IN osm_vendor_t * p_vend,
266 IN osm_log_t * p_log, IN osm_stats_t * p_stats,
267 IN osm_subn_t * p_subn,
268 IN int32_t max_wire_smps,
269 IN int32_t max_wire_smps2,
270 IN uint32_t max_smps_timeout)
272 ib_api_status_t status = IB_SUCCESS;
274 OSM_LOG_ENTER(p_log);
276 p_vl->p_vend = p_vend;
278 p_vl->p_stats = p_stats;
279 p_vl->p_subn = p_subn;
280 p_vl->max_wire_smps = max_wire_smps;
281 p_vl->max_wire_smps2 = max_wire_smps2;
282 p_vl->max_smps_timeout = max_wire_smps < max_wire_smps2 ?
283 max_smps_timeout : EVENT_NO_TIMEOUT;
285 status = cl_event_init(&p_vl->signal, FALSE);
286 if (status != IB_SUCCESS)
289 p_vl->state = OSM_VL15_STATE_READY;
291 status = cl_spinlock_init(&p_vl->lock);
292 if (status != IB_SUCCESS)
296 Initialize the thread after all other dependent objects
297 have been initialized.
299 status = cl_thread_init(&p_vl->poller, vl15_poller, p_vl,
306 void osm_vl15_poll(IN osm_vl15_t * p_vl)
308 OSM_LOG_ENTER(p_vl->p_log);
310 CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
313 If we have room for more VL15 MADs on the wire,
314 then signal the poller thread.
316 This is not an airtight check, since the poller thread
317 could be just about to send another MAD as we signal
318 the event here. To cover this rare case, the poller
319 thread checks for a spurious wake-up.
321 if (p_vl->p_stats->qp0_mads_outstanding_on_wire <
322 (int32_t) p_vl->max_wire_smps) {
323 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
324 "Signalling poller thread\n");
325 cl_event_signal(&p_vl->signal);
328 OSM_LOG_EXIT(p_vl->p_log);
331 void osm_vl15_post(IN osm_vl15_t * p_vl, IN osm_madw_t * p_madw)
333 OSM_LOG_ENTER(p_vl->p_log);
335 CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
337 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, "Posting p_madw = %p\n", p_madw);
340 Determine in which fifo to place the pending madw.
342 cl_spinlock_acquire(&p_vl->lock);
343 if (p_madw->resp_expected == TRUE) {
344 cl_qlist_insert_tail(&p_vl->rfifo, &p_madw->list_item);
345 osm_stats_inc_qp0_outstanding(p_vl->p_stats);
347 cl_qlist_insert_tail(&p_vl->ufifo, &p_madw->list_item);
348 cl_spinlock_release(&p_vl->lock);
350 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
351 "%u QP0 MADs on wire, %u QP0 MADs outstanding\n",
352 p_vl->p_stats->qp0_mads_outstanding_on_wire,
353 p_vl->p_stats->qp0_mads_outstanding);
357 OSM_LOG_EXIT(p_vl->p_log);
360 void osm_vl15_shutdown(IN osm_vl15_t * p_vl, IN osm_mad_pool_t * p_mad_pool)
364 OSM_LOG_ENTER(p_vl->p_log);
366 /* we only should get here after the VL15 interface was initialized */
367 CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
369 /* grab a lock on the object */
370 cl_spinlock_acquire(&p_vl->lock);
372 /* go over all outstanding MADs and retire their transactions */
374 /* first we handle the list of response MADs */
375 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
376 while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->ufifo)) {
377 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
378 "Releasing Response p_madw = %p\n", p_madw);
380 osm_mad_pool_put(p_mad_pool, p_madw);
382 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
385 /* Request MADs we send out */
386 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
387 while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->rfifo)) {
388 OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
389 "Releasing Request p_madw = %p\n", p_madw);
391 osm_mad_pool_put(p_mad_pool, p_madw);
392 osm_stats_dec_qp0_outstanding(p_vl->p_stats);
394 p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
398 cl_spinlock_release(&p_vl->lock);
400 OSM_LOG_EXIT(p_vl->p_log);