11590Srgrimes/*
21590Srgrimes * Copyright (c) 2004-2008 Voltaire, Inc. All rights reserved.
31590Srgrimes * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
41590Srgrimes * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
51590Srgrimes *
61590Srgrimes * This software is available to you under a choice of one of two
71590Srgrimes * licenses.  You may choose to be licensed under the terms of the GNU
81590Srgrimes * General Public License (GPL) Version 2, available from the file
91590Srgrimes * COPYING in the main directory of this source tree, or the
101590Srgrimes * OpenIB.org BSD license below:
111590Srgrimes *
121590Srgrimes *     Redistribution and use in source and binary forms, with or
131590Srgrimes *     without modification, are permitted provided that the following
141590Srgrimes *     conditions are met:
151590Srgrimes *
161590Srgrimes *      - Redistributions of source code must retain the above
171590Srgrimes *        copyright notice, this list of conditions and the following
181590Srgrimes *        disclaimer.
191590Srgrimes *
201590Srgrimes *      - Redistributions in binary form must reproduce the above
211590Srgrimes *        copyright notice, this list of conditions and the following
221590Srgrimes *        disclaimer in the documentation and/or other materials
231590Srgrimes *        provided with the distribution.
241590Srgrimes *
251590Srgrimes * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
261590Srgrimes * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
271590Srgrimes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
281590Srgrimes * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
291590Srgrimes * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
301590Srgrimes * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
311590Srgrimes * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
321590Srgrimes * SOFTWARE.
331590Srgrimes *
341590Srgrimes */
3534797Scharnier
361590Srgrimes/*
3734797Scharnier * Abstract:
3834797Scharnier *    Implementation of osm_vl15_t.
3942815Sdanny * This object represents the VL15 Interface object.
401590Srgrimes * This object is part of the opensm family of objects.
411590Srgrimes */
421590Srgrimes
431590Srgrimes#if HAVE_CONFIG_H
441590Srgrimes#  include <config.h>
451590Srgrimes#endif				/* HAVE_CONFIG_H */
461590Srgrimes
471590Srgrimes#include <string.h>
481590Srgrimes#include <iba/ib_types.h>
491590Srgrimes#include <complib/cl_thread.h>
501590Srgrimes#include <vendor/osm_vendor_api.h>
511590Srgrimes#include <opensm/osm_vl15intf.h>
521590Srgrimes#include <opensm/osm_madw.h>
531590Srgrimes#include <opensm/osm_log.h>
541590Srgrimes#include <opensm/osm_helper.h>
551590Srgrimes
561590Srgrimes/**********************************************************************
571590Srgrimes **********************************************************************/
581590Srgrimes
591590Srgrimesstatic void vl15_send_mad(osm_vl15_t * p_vl, osm_madw_t * p_madw)
601590Srgrimes{
611590Srgrimes	ib_api_status_t status;
621590Srgrimes
631590Srgrimes	/*
641590Srgrimes	   Non-response-expected mads are not throttled on the wire
651590Srgrimes	   since we can have no confirmation that they arrived
661590Srgrimes	   at their destination.
671590Srgrimes	 */
681590Srgrimes	if (p_madw->resp_expected == TRUE)
691590Srgrimes		/*
709987Swollman		   Note that other threads may not see the response MAD
711590Srgrimes		   arrive before send() even returns.
721590Srgrimes		   In that case, the wire count would temporarily go negative.
731590Srgrimes		   To avoid this confusion, preincrement the counts on the
741590Srgrimes		   assumption that send() will succeed.
758874Srgrimes		 */
761590Srgrimes		cl_atomic_inc(&p_vl->p_stats->qp0_mads_outstanding_on_wire);
771590Srgrimes	else
781590Srgrimes		cl_atomic_inc(&p_vl->p_stats->qp0_unicasts_sent);
791590Srgrimes
801590Srgrimes	cl_atomic_inc(&p_vl->p_stats->qp0_mads_sent);
811590Srgrimes
821590Srgrimes	status = osm_vendor_send(osm_madw_get_bind_handle(p_madw),
831590Srgrimes				 p_madw, p_madw->resp_expected);
841590Srgrimes
851590Srgrimes	if (status == IB_SUCCESS) {
861590Srgrimes		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
871590Srgrimes			"%u QP0 MADs on wire, %u outstanding, "
881590Srgrimes			"%u unicasts sent, %u total sent\n",
891590Srgrimes			p_vl->p_stats->qp0_mads_outstanding_on_wire,
901590Srgrimes			p_vl->p_stats->qp0_mads_outstanding,
911590Srgrimes			p_vl->p_stats->qp0_unicasts_sent,
921590Srgrimes			p_vl->p_stats->qp0_mads_sent);
931590Srgrimes		return;
941590Srgrimes	}
951590Srgrimes
961590Srgrimes	OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E03: "
971590Srgrimes		"MAD send failed (%s)\n", ib_get_err_str(status));
9817544Speter
9917544Speter	/*
10017544Speter	   The MAD was never successfully sent, so
10117544Speter	   fix up the pre-incremented count values.
10217544Speter	 */
10317544Speter
10417544Speter	/* Decrement qp0_mads_sent that were incremented in the code above.
10517544Speter	   qp0_mads_outstanding will be decremented by send error callback
10617544Speter	   (called by osm_vendor_send() */
10717544Speter	cl_atomic_dec(&p_vl->p_stats->qp0_mads_sent);
1081590Srgrimes	if (!p_madw->resp_expected)
1091590Srgrimes		cl_atomic_dec(&p_vl->p_stats->qp0_unicasts_sent);
1101590Srgrimes}
1111590Srgrimes
1121590Srgrimesstatic void __osm_vl15_poller(IN void *p_ptr)
1131590Srgrimes{
1141590Srgrimes	ib_api_status_t status;
1151590Srgrimes	osm_madw_t *p_madw;
1161590Srgrimes	osm_vl15_t *const p_vl = (osm_vl15_t *) p_ptr;
1171590Srgrimes	cl_qlist_t *p_fifo;
11842815Sdanny
11942815Sdanny	OSM_LOG_ENTER(p_vl->p_log);
12042815Sdanny
12142815Sdanny	if (p_vl->thread_state == OSM_THREAD_STATE_NONE)
1229987Swollman		p_vl->thread_state = OSM_THREAD_STATE_RUN;
12342815Sdanny
1241590Srgrimes	while (p_vl->thread_state == OSM_THREAD_STATE_RUN) {
1259987Swollman		/*
1269554Smpp		   Start servicing the FIFOs by pulling off MAD wrappers
1279554Smpp		   and passing them to the transport interface.
1289554Smpp		   There are lots of corner cases here so tread carefully.
1299554Smpp
1309554Smpp		   The unicast FIFO has priority, since somebody is waiting
1319554Smpp		   for a timely response.
1329554Smpp		 */
1339554Smpp		cl_spinlock_acquire(&p_vl->lock);
1341590Srgrimes
1351590Srgrimes		if (cl_qlist_count(&p_vl->ufifo) != 0)
1361590Srgrimes			p_fifo = &p_vl->ufifo;
1371590Srgrimes		else
1381590Srgrimes			p_fifo = &p_vl->rfifo;
1391590Srgrimes
1401590Srgrimes		p_madw = (osm_madw_t *) cl_qlist_remove_head(p_fifo);
1411590Srgrimes
1421590Srgrimes		cl_spinlock_release(&p_vl->lock);
1431590Srgrimes
1441590Srgrimes		if (p_madw != (osm_madw_t *) cl_qlist_end(p_fifo)) {
14534797Scharnier			OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
1461590Srgrimes				"Servicing p_madw = %p\n", p_madw);
1471590Srgrimes			if (osm_log_is_active(p_vl->p_log, OSM_LOG_FRAMES))
1481590Srgrimes				osm_dump_dr_smp(p_vl->p_log,
1491590Srgrimes						osm_madw_get_smp_ptr(p_madw),
1501590Srgrimes						OSM_LOG_FRAMES);
1511590Srgrimes
1521590Srgrimes			vl15_send_mad(p_vl, p_madw);
1531590Srgrimes		} else
154			/*
155			   The VL15 FIFO is empty, so we have nothing left to do.
156			 */
157			status = cl_event_wait_on(&p_vl->signal,
158						  EVENT_NO_TIMEOUT, TRUE);
159
160		while ((p_vl->p_stats->qp0_mads_outstanding_on_wire >=
161			(int32_t) p_vl->max_wire_smps) &&
162		       (p_vl->thread_state == OSM_THREAD_STATE_RUN)) {
163			status = cl_event_wait_on(&p_vl->signal,
164						  EVENT_NO_TIMEOUT, TRUE);
165			if (status != CL_SUCCESS) {
166				OSM_LOG(p_vl->p_log, OSM_LOG_ERROR, "ERR 3E02: "
167					"Event wait failed (%s)\n",
168					CL_STATUS_MSG(status));
169				break;
170			}
171		}
172	}
173
174	/*
175	   since we abort immediately when the state != OSM_THREAD_STATE_RUN
176	   we might have some mads on the queues. After the thread exits
177	   the vl15 destroy routine should put these mads back...
178	 */
179
180	OSM_LOG_EXIT(p_vl->p_log);
181}
182
183/**********************************************************************
184 **********************************************************************/
185void osm_vl15_construct(IN osm_vl15_t * const p_vl)
186{
187	memset(p_vl, 0, sizeof(*p_vl));
188	p_vl->state = OSM_VL15_STATE_INIT;
189	p_vl->thread_state = OSM_THREAD_STATE_NONE;
190	cl_event_construct(&p_vl->signal);
191	cl_spinlock_construct(&p_vl->lock);
192	cl_qlist_init(&p_vl->rfifo);
193	cl_qlist_init(&p_vl->ufifo);
194	cl_thread_construct(&p_vl->poller);
195}
196
197/**********************************************************************
198 **********************************************************************/
199void
200osm_vl15_destroy(IN osm_vl15_t * const p_vl, IN struct osm_mad_pool *p_pool)
201{
202	osm_madw_t *p_madw;
203
204	OSM_LOG_ENTER(p_vl->p_log);
205
206	/*
207	   Signal our threads that we're leaving.
208	 */
209	p_vl->thread_state = OSM_THREAD_STATE_EXIT;
210
211	/*
212	   Don't trigger unless event has been initialized.
213	   Destroy the thread before we tear down the other objects.
214	 */
215	if (p_vl->state != OSM_VL15_STATE_INIT)
216		cl_event_signal(&p_vl->signal);
217
218	cl_thread_destroy(&p_vl->poller);
219
220	/*
221	   Return the outstanding messages to the pool
222	 */
223
224	cl_spinlock_acquire(&p_vl->lock);
225
226	while (!cl_is_qlist_empty(&p_vl->rfifo)) {
227		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
228		osm_mad_pool_put(p_pool, p_madw);
229	}
230	while (!cl_is_qlist_empty(&p_vl->ufifo)) {
231		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
232		osm_mad_pool_put(p_pool, p_madw);
233	}
234
235	cl_spinlock_release(&p_vl->lock);
236
237	cl_event_destroy(&p_vl->signal);
238	p_vl->state = OSM_VL15_STATE_INIT;
239	cl_spinlock_destroy(&p_vl->lock);
240
241	OSM_LOG_EXIT(p_vl->p_log);
242}
243
244/**********************************************************************
245 **********************************************************************/
246ib_api_status_t
247osm_vl15_init(IN osm_vl15_t * const p_vl,
248	      IN osm_vendor_t * const p_vend,
249	      IN osm_log_t * const p_log,
250	      IN osm_stats_t * const p_stats, IN const int32_t max_wire_smps)
251{
252	ib_api_status_t status = IB_SUCCESS;
253
254	OSM_LOG_ENTER(p_log);
255
256	p_vl->p_vend = p_vend;
257	p_vl->p_log = p_log;
258	p_vl->p_stats = p_stats;
259	p_vl->max_wire_smps = max_wire_smps;
260
261	status = cl_event_init(&p_vl->signal, FALSE);
262	if (status != IB_SUCCESS)
263		goto Exit;
264
265	p_vl->state = OSM_VL15_STATE_READY;
266
267	status = cl_spinlock_init(&p_vl->lock);
268	if (status != IB_SUCCESS)
269		goto Exit;
270
271	/*
272	   Initialize the thread after all other dependent objects
273	   have been initialized.
274	 */
275	status = cl_thread_init(&p_vl->poller, __osm_vl15_poller, p_vl,
276				"opensm poller");
277	if (status != IB_SUCCESS)
278		goto Exit;
279
280Exit:
281	OSM_LOG_EXIT(p_log);
282	return (status);
283}
284
285/**********************************************************************
286 **********************************************************************/
287void osm_vl15_poll(IN osm_vl15_t * const p_vl)
288{
289	OSM_LOG_ENTER(p_vl->p_log);
290
291	CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
292
293	/*
294	   If we have room for more VL15 MADs on the wire,
295	   then signal the poller thread.
296
297	   This is not an airtight check, since the poller thread
298	   could be just about to send another MAD as we signal
299	   the event here.  To cover this rare case, the poller
300	   thread checks for a spurious wake-up.
301	 */
302	if (p_vl->p_stats->qp0_mads_outstanding_on_wire <
303	    (int32_t) p_vl->max_wire_smps) {
304		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
305			"Signalling poller thread\n");
306		cl_event_signal(&p_vl->signal);
307	}
308
309	OSM_LOG_EXIT(p_vl->p_log);
310}
311
312/**********************************************************************
313 **********************************************************************/
314void osm_vl15_post(IN osm_vl15_t * const p_vl, IN osm_madw_t * const p_madw)
315{
316	OSM_LOG_ENTER(p_vl->p_log);
317
318	CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
319
320	OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG, "Posting p_madw = 0x%p\n", p_madw);
321
322	/*
323	   Determine in which fifo to place the pending madw.
324	 */
325	cl_spinlock_acquire(&p_vl->lock);
326	if (p_madw->resp_expected == TRUE) {
327		cl_qlist_insert_tail(&p_vl->rfifo, &p_madw->list_item);
328		osm_stats_inc_qp0_outstanding(p_vl->p_stats);
329	} else
330		cl_qlist_insert_tail(&p_vl->ufifo, &p_madw->list_item);
331	cl_spinlock_release(&p_vl->lock);
332
333	OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
334		"%u QP0 MADs on wire, %u QP0 MADs outstanding\n",
335		p_vl->p_stats->qp0_mads_outstanding_on_wire,
336		p_vl->p_stats->qp0_mads_outstanding);
337
338	osm_vl15_poll(p_vl);
339
340	OSM_LOG_EXIT(p_vl->p_log);
341}
342
343void
344osm_vl15_shutdown(IN osm_vl15_t * const p_vl,
345		  IN osm_mad_pool_t * const p_mad_pool)
346{
347	osm_madw_t *p_madw;
348
349	OSM_LOG_ENTER(p_vl->p_log);
350
351	/* we only should get here after the VL15 interface was initialized */
352	CL_ASSERT(p_vl->state == OSM_VL15_STATE_READY);
353
354	/* grap a lock on the object */
355	cl_spinlock_acquire(&p_vl->lock);
356
357	/* go over all outstanding MADs and retire their transactions */
358
359	/* first we handle the list of response MADs */
360	p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
361	while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->ufifo)) {
362		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
363			"Releasing Response p_madw = %p\n", p_madw);
364
365		osm_mad_pool_put(p_mad_pool, p_madw);
366
367		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->ufifo);
368	}
369
370	/* Request MADs we send out */
371	p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
372	while (p_madw != (osm_madw_t *) cl_qlist_end(&p_vl->rfifo)) {
373		OSM_LOG(p_vl->p_log, OSM_LOG_DEBUG,
374			"Releasing Request p_madw = %p\n", p_madw);
375
376		osm_mad_pool_put(p_mad_pool, p_madw);
377		osm_stats_dec_qp0_outstanding(p_vl->p_stats);
378
379		p_madw = (osm_madw_t *) cl_qlist_remove_head(&p_vl->rfifo);
380	}
381
382	/* free the lock */
383	cl_spinlock_release(&p_vl->lock);
384
385	OSM_LOG_EXIT(p_vl->p_log);
386}
387