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