1/*
2 * Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved.
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
4 *
5 * This software is available to you under a choice of one of two
6 * licenses.  You may choose to be licensed under the terms of the GNU
7 * General Public License (GPL) Version 2, available from the file
8 * COPYING in the main directory of this source tree, or the
9 * OpenIB.org BSD license below:
10 *
11 *     Redistribution and use in source and binary forms, with or
12 *     without modification, are permitted provided that the following
13 *     conditions are met:
14 *
15 *      - Redistributions of source code must retain the above
16 *        copyright notice, this list of conditions and the following
17 *        disclaimer.
18 *
19 *      - Redistributions in binary form must reproduce the above
20 *        copyright notice, this list of conditions and the following
21 *        disclaimer in the documentation and/or other materials
22 *        provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 *
33 */
34
35#ifdef OSM_VENDOR_INTF_MTL
36
37/*                  - Mellanox Confidential and Proprietary -
38 *
39 *  Copyright (C) Jul. 2001, Mellanox Technologies Ltd.  ALL RIGHTS RESERVED.
40 *
41 *  Except as specifically permitted herein, no portion of the information,
42 *  including but not limited to object code and source code, may be reproduced,
43 *  modified, distributed, republished or otherwise exploited in any form or by
44 *  any means for any purpose without the prior written permission of Mellanox
45 *  Technologies Ltd. Use of software subject to the terms and conditions
46 *  detailed in the file "LICENSE.txt".
47 *
48 *  End of legal section ......................................................
49 *
50 *  osmt_mtl_regular_qp.c -
51 *    Provide Simple Interface for Sending and Receiving MADS through a regular QP
52 *
53 *  Creation date:
54 *
55 *  Version: $Id$
56 *
57 *  Authors:
58 *    Eitan Zahavi
59 *
60 *  Changes:
61 */
62
63#include <stdio.h>
64#include <stdlib.h>
65#include <string.h>
66#include <unistd.h>
67#include <signal.h>
68
69#include <mtl_common.h>
70#include <vapi.h>
71#include <evapi.h>
72#include <vapi_common.h>
73#include <ib_defs.h>
74#include <osmt_mtl_regular_qp.h>
75#include <complib/cl_types.h>
76/*
77 * Initialize the QP etc.
78 * Given in res: port_num, max_outs_sq, max_outs_rq
79 */
80VAPI_ret_t osmt_mtl_get_qp_resources(IN OUT osmt_mtl_mad_res_t * res)
81{
82	VAPI_ret_t ret;
83	VAPI_hca_port_t hca_port_info;
84	VAPI_qp_init_attr_t qp_init_attr;
85	VAPI_qp_prop_t qp_prop;
86	VAPI_cqe_num_t act_num;
87
88	/* Get HCA LID */
89	ret =
90	    VAPI_query_hca_port_prop(res->hca_hndl, res->port_num,
91				     &hca_port_info);
92	VAPI_CHECK_RET;
93	res->slid = hca_port_info.lid;
94
95	/* Get a PD */
96	ret = VAPI_alloc_pd(res->hca_hndl, &(res->pd_hndl));
97	VAPI_CHECK_RET;
98
99	/* Create CQ for RQ and SQ *//* TBD - Check we have enough act nums */
100	ret =
101	    VAPI_create_cq(res->hca_hndl, res->max_outs_sq + 1,
102			   &(res->sq_cq_hndl), &act_num);
103	VAPI_CHECK_RET;
104	ret =
105	    VAPI_create_cq(res->hca_hndl, res->max_outs_rq + 1,
106			   &(res->rq_cq_hndl), &act_num);
107	VAPI_CHECK_RET;
108
109	/* register event handlers for polling(block mode) internal use */
110	/* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->rq_cq_hndl, */
111	/*                            EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->rq_cq_eventh)); */
112	/* VAPI_CHECK_RET; */
113	/* ret= EVAPI_set_comp_eventh(res->hca_hndl,res->sq_cq_hndl, */
114	/*                            EVAPI_POLL_CQ_UNBLOCK_HANDLER,NULL,&(res->sq_cq_eventh)); */
115	/* VAPI_CHECK_RET; */
116
117	/* Create QP */
118	qp_init_attr.cap.max_oust_wr_sq = res->max_outs_sq + 1;
119	qp_init_attr.cap.max_oust_wr_rq = res->max_outs_rq + 1;
120	qp_init_attr.cap.max_sg_size_sq = 4;
121	qp_init_attr.cap.max_sg_size_rq = 4;
122
123	qp_init_attr.pd_hndl = res->pd_hndl;
124	qp_init_attr.rdd_hndl = 0;
125	qp_init_attr.rq_cq_hndl = res->rq_cq_hndl;
126	qp_init_attr.rq_sig_type = VAPI_SIGNAL_ALL_WR;	/* That's default for IB */
127	qp_init_attr.sq_cq_hndl = res->sq_cq_hndl;
128	qp_init_attr.sq_sig_type = VAPI_SIGNAL_REQ_WR;
129	qp_init_attr.ts_type = VAPI_TS_UD;
130
131	ret =
132	    VAPI_create_qp(res->hca_hndl, &qp_init_attr, &(res->qp_hndl),
133			   &qp_prop);
134	VAPI_CHECK_RET;
135	res->qp_id.qp_num = qp_prop.qp_num;
136
137	return (VAPI_OK);
138}
139
140VAPI_ret_t osmt_mtl_qp_init(osmt_mtl_mad_res_t * res)
141{
142	VAPI_ret_t ret;
143
144	VAPI_qp_attr_t qp_attr;
145	VAPI_qp_attr_mask_t qp_attr_mask;
146	VAPI_qp_cap_t qp_cap;
147
148	/*
149	 * Change QP to INIT
150	 *
151	 */
152	QP_ATTR_MASK_CLR_ALL(qp_attr_mask);
153	qp_attr.qp_state = VAPI_INIT;
154	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE);
155	qp_attr.pkey_ix = 0;
156	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PKEY_IX);
157	qp_attr.port = res->port_num;
158	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_PORT);
159	qp_attr.qkey = res->qkey;
160	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QKEY);
161
162	/* If I do not set this mask, I get an error from HH. QPM should catch it */
163	ret =
164	    VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask,
165			   &qp_cap);
166	VAPI_CHECK_RET;
167
168	return (ret);
169
170}
171
172VAPI_ret_t osmt_mtl_qp_2_rtr_rts(osmt_mtl_mad_res_t * res)
173{
174	VAPI_ret_t ret;
175
176	VAPI_qp_attr_t qp_attr;
177	VAPI_qp_attr_mask_t qp_attr_mask;
178	VAPI_qp_cap_t qp_cap;
179
180	/*
181	 *  Change QP to RTR
182	 *
183	 */
184	QP_ATTR_MASK_CLR_ALL(qp_attr_mask);
185	qp_attr.qp_state = VAPI_RTR;
186	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE);
187	/*   qp_attr.rq_psn   = 0;                */
188	/*   QP_ATTR_MASK_SET(qp_attr_mask,QP_ATTR_RQ_PSN); */
189
190	ret =
191	    VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask,
192			   &qp_cap);
193	VAPI_CHECK_RET;
194
195	/*
196	 * Change QP to RTS
197	 *
198	 */
199	QP_ATTR_MASK_CLR_ALL(qp_attr_mask);
200	qp_attr.qp_state = VAPI_RTS;
201	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_QP_STATE);
202	qp_attr.sq_psn = 0;
203	QP_ATTR_MASK_SET(qp_attr_mask, QP_ATTR_SQ_PSN);
204
205	ret =
206	    VAPI_modify_qp(res->hca_hndl, res->qp_hndl, &qp_attr, &qp_attr_mask,
207			   &qp_cap);
208	VAPI_CHECK_RET;
209
210	return (ret);
211}
212
213VAPI_ret_t osmt_mtl_mad_create_mr(osmt_mtl_mad_res_t * res)
214{
215
216	VAPI_ret_t ret;
217
218	VAPI_mrw_t mr_in, mr_out;
219
220	res->buf_size =
221	    (MAD_SIZE + GRH_LEN) * (res->max_outs_sq + res->max_outs_rq + 1);
222
223	/* Register single memory address region for all buffers */
224	res->buf_ptr = VMALLOC(res->buf_size);
225
226	if (res->buf_ptr == ((VAPI_virt_addr_t) NULL)) {
227		ret = VAPI_EAGAIN;
228		VAPI_CHECK_RET;
229	}
230
231	/* Enable local and remote access to memory region */
232	mr_in.acl = VAPI_EN_LOCAL_WRITE | VAPI_EN_REMOTE_WRITE;
233	mr_in.l_key = 0;
234	mr_in.pd_hndl = res->pd_hndl;
235	mr_in.r_key = 0;
236	mr_in.size = res->buf_size;
237	ASSERT_VOIDP2UINTN(res->buf_ptr);
238	mr_in.start = (VAPI_virt_addr_t) (uintn_t) (res->buf_ptr);
239	mr_in.type = VAPI_MR;
240
241	ret = VAPI_register_mr(res->hca_hndl, &mr_in, &(res->mr_hndl), &mr_out);
242	VAPI_CHECK_RET;
243
244	res->l_key = mr_out.l_key;
245
246	return (ret);
247}
248
249VAPI_ret_t osmt_mtl_init_opened_hca(osmt_mtl_mad_res_t * res)
250{
251	VAPI_ret_t ret;
252
253	res->pd_hndl = VAPI_INVAL_HNDL;
254	res->rq_cq_hndl = VAPI_INVAL_HNDL;
255	res->sq_cq_hndl = VAPI_INVAL_HNDL;
256	res->sq_cq_eventh = VAPI_INVAL_HNDL;
257	res->rq_cq_eventh = VAPI_INVAL_HNDL;
258	res->qp_hndl = VAPI_INVAL_HNDL;
259	res->mr_hndl = VAPI_INVAL_HNDL;
260
261	/*
262	 * Create QP
263	 *
264	 */
265	ret = osmt_mtl_get_qp_resources(res);
266	if (ret != VAPI_OK) {
267		return ret;
268	}
269
270	/*
271	 * Move to init
272	 *
273	 */
274	ret = osmt_mtl_qp_init(res);
275	if (ret != VAPI_OK) {
276		return ret;
277	}
278
279	/*
280	 * Initialize memory regions
281	 *
282	 */
283	ret = osmt_mtl_mad_create_mr(res);
284	if (ret != VAPI_OK) {
285		return ret;
286	}
287
288	/* only now move to RTR and RTS */
289	ret = osmt_mtl_qp_2_rtr_rts(res);
290	if (ret != VAPI_OK) {
291		return ret;
292	}
293
294	return VAPI_OK;
295}
296
297VAPI_ret_t osmt_mtl_mad_cleanup(osmt_mtl_mad_res_t * res)
298{
299	if (res->qp_hndl != VAPI_INVAL_HNDL) {
300		VAPI_destroy_qp(res->hca_hndl, res->qp_hndl);
301	}
302	if (res->sq_cq_eventh != VAPI_INVAL_HNDL) {
303		EVAPI_clear_comp_eventh(res->hca_hndl, res->sq_cq_eventh);
304	}
305	if (res->rq_cq_eventh != VAPI_INVAL_HNDL) {
306		EVAPI_clear_comp_eventh(res->hca_hndl, res->rq_cq_eventh);
307	}
308	if (res->rq_cq_hndl != VAPI_INVAL_HNDL) {
309		VAPI_destroy_cq(res->hca_hndl, res->rq_cq_hndl);
310	}
311	if (res->sq_cq_hndl != VAPI_INVAL_HNDL) {
312		VAPI_destroy_cq(res->hca_hndl, res->sq_cq_hndl);
313	}
314	if (res->mr_hndl != VAPI_INVAL_HNDL) {
315		VAPI_deregister_mr(res->hca_hndl, res->mr_hndl);
316	}
317	if (res->pd_hndl != VAPI_INVAL_HNDL) {
318		VAPI_dealloc_pd(res->hca_hndl, res->pd_hndl);
319	}
320#if 0
321	/* open/close of HCA should be done system wide - not per application */
322	if (res->hca_hndl != VAPI_INVAL_HNDL) {
323		VAPI_close_hca(res->hca_hndl);	/* TBD: HCA_open/close should be done on a system wide basis */
324	}
325#endif
326	return VAPI_OK;
327}
328
329VAPI_ret_t osmt_mtl_create_av(osmt_mtl_mad_res_t * res, int16_t dlid,
330			      VAPI_ud_av_hndl_t * avh_p)
331{
332	VAPI_ud_av_t av;
333	VAPI_ret_t ret;
334
335	av.dlid = dlid;
336	av.port = res->port_num;
337	av.sl = 0;		/* dest->sl; */
338	av.src_path_bits = 0;	/*  dest->ee_dlid.dst_path_bits; */
339	av.static_rate = 0;
340	/* GRH ? */
341	av.grh_flag = 0;
342
343	ret = VAPI_create_addr_hndl(res->hca_hndl, res->pd_hndl, &av, avh_p);
344	if (ret != VAPI_OK) {
345		MTL_ERROR1("%s: failed VAPI_create_addr_hndl (%s)\n", __func__,
346			   VAPI_strerror_sym(ret));
347		return ret;
348	}
349	return VAPI_OK;
350}
351
352VAPI_ret_t osmt_mtl_mad_send(osmt_mtl_mad_res_t * res, VAPI_wr_id_t id,
353			     void *mad, VAPI_qp_num_t dest_qp, IB_sl_t sl,
354			     u_int32_t dest_qkey, VAPI_ud_av_hndl_t avh)
355{
356	VAPI_sr_desc_t sr;
357	VAPI_sg_lst_entry_t sg_entry;
358	VAPI_ret_t ret;
359
360	/* building SEND request */
361	sr.opcode = VAPI_SEND;
362	sr.remote_ah = avh;
363	sr.remote_qp = dest_qp;
364	sr.remote_qkey = dest_qkey;
365
366	sr.id = id;
367	sr.set_se = FALSE;
368	sr.fence = FALSE;
369	sr.comp_type = VAPI_SIGNALED;
370	sr.sg_lst_len = 1;
371	sr.sg_lst_p = &sg_entry;
372	ASSERT_VOIDP2UINTN(mad);
373	sg_entry.addr = (VAPI_virt_addr_t) (uintn_t) (mad);
374	sg_entry.len = MAD_SIZE;
375	sg_entry.lkey = res->l_key;
376
377	ret = VAPI_post_sr(res->hca_hndl, res->qp_hndl, &sr);
378	if (ret != VAPI_OK) {
379		MTL_ERROR1(__FUNCTION__ ": failed VAPI_post_sr (%s)\n",
380			   VAPI_strerror_sym(ret));
381		return ret;
382	}
383
384	return VAPI_OK;
385}
386
387int osmt_mtl_mad_post_recv_bufs(osmt_mtl_mad_res_t * res, void *buf_array,
388				u_int32_t num_o_bufs, u_int32_t size,
389				VAPI_wr_id_t start_id)
390{
391	uint32_t i;
392	void *cur_buf;
393	VAPI_rr_desc_t rr;
394	VAPI_sg_lst_entry_t sg_entry;
395	VAPI_ret_t ret;
396
397	rr.opcode = VAPI_RECEIVE;
398	rr.comp_type = VAPI_SIGNALED;	/* All with CQE (IB compliant) */
399	rr.sg_lst_len = 1;	/* single buffers */
400	rr.sg_lst_p = &sg_entry;
401	sg_entry.lkey = res->l_key;
402	cur_buf = buf_array;
403	for (i = 0; i < num_o_bufs; i++) {
404		rr.id = start_id + i;	/* WQE id used is the index to buffers ptr array */
405		ASSERT_VOIDP2UINTN(cur_buf);
406		sg_entry.addr = (VAPI_virt_addr_t) (uintn_t) cur_buf;
407		sg_entry.len = size;
408		memset(cur_buf, 0x00, size);	/* fill with 0 */
409		ret = VAPI_post_rr(res->hca_hndl, res->qp_hndl, &rr);
410		if (ret != VAPI_OK) {
411			MTL_ERROR1(__FUNCTION__
412				   ": failed posting RQ WQE (%s)\n",
413				   VAPI_strerror_sym(ret));
414			return i;
415		}
416		MTL_DEBUG4(__FUNCTION__ ": posted buf at %p\n", cur_buf);
417		cur_buf += size;
418	}
419
420	return i;		/* num of buffers posted */
421}
422
423VAPI_ret_t osmt_mtl_mad_poll4cqe(VAPI_hca_hndl_t hca, VAPI_cq_hndl_t cq,
424				 VAPI_wc_desc_t * wc_desc_p,
425				 u_int32_t max_poll, u_int32_t poll_sleep,
426				 VAPI_ud_av_hndl_t * avh_p)
427{
428	VAPI_ret_t ret = VAPI_CQ_EMPTY;
429	u_int32_t poll_cnt = 0;
430
431	/* wait for something to arrive */
432	while ((ret == VAPI_CQ_EMPTY) && (poll_cnt < max_poll)) {
433		ret = VAPI_poll_cq(hca, cq, wc_desc_p);
434		/* don't sleep if we already succeeded) */
435		if (ret != VAPI_CQ_EMPTY) {
436			break;
437		}
438		usleep(poll_sleep);
439		poll_cnt++;
440	}
441
442	/* if passed an AVH to destory - do it */
443	if (avh_p != NULL) {
444		VAPI_destroy_addr_hndl(hca, *avh_p);
445	}
446
447	if ((poll_cnt == max_poll) && (ret == VAPI_CQ_EMPTY)) {
448		MTL_DEBUG1(__FUNCTION__
449			   ": Failed to get completion on wq after %d polls.\n",
450			   max_poll);
451		return VAPI_CQ_EMPTY;
452	}
453
454	if (ret != VAPI_OK) {
455		MTL_DEBUG1(__FUNCTION__
456			   ": VAPI_poll_cq failed with ret=%s on sq_cq\n",
457			   mtl_strerror_sym(ret));
458		return ret;
459	}
460
461	if (wc_desc_p->status != VAPI_SUCCESS) {
462		MTL_DEBUG1(__FUNCTION__ ": completion error (%d) detected\n",
463			   wc_desc_p->status);
464	}
465
466	return VAPI_OK;
467}
468
469#endif				/*  OSM_VENDOR_INTF_MTL */
470