1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright (c) 2002-2003, Network Appliance, Inc. All rights reserved.
24 */
25
26/*
27 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28 * Use is subject to license terms.
29 */
30
31
32/*
33 *
34 * MODULE: dapl_lmr_create.c
35 *
36 * PURPOSE: Memory management
37 * Description: Interfaces in this file are completely described in
38 *		the DAPL 1.1 API, Chapter 6, section 6
39 *
40 */
41
42#include <dat/udat.h>
43#include <dapl_lmr_util.h>
44#include <dapl_adapter_util.h>
45#include <libdevinfo.h>
46
47/*
48 * Function Prototypes
49 */
50
51static DAT_RETURN
52dapl_lmr_create_virtual(IN DAPL_IA *ia,
53			IN DAT_PVOID virt_addr,
54			IN DAT_VLEN length,
55			IN DAT_LMR_COOKIE shm_cookie,
56			IN DAPL_PZ *pz,
57			IN DAT_MEM_PRIV_FLAGS privileges,
58			OUT DAT_LMR_HANDLE *lmr_handle,
59			OUT DAT_LMR_CONTEXT *lmr_context,
60			OUT DAT_RMR_CONTEXT *rmr_context,
61			OUT DAT_VLEN *registered_length,
62			OUT DAT_VADDR *registered_address);
63
64static DAT_RETURN
65dapl_lmr_create_lmr(IN DAPL_IA *ia,
66		    IN DAPL_LMR *original_lmr,
67		    IN DAPL_PZ *pz,
68		    IN DAT_MEM_PRIV_FLAGS privileges,
69		    OUT DAT_LMR_HANDLE *lmr_handle,
70		    OUT DAT_LMR_CONTEXT *lmr_context,
71		    OUT DAT_RMR_CONTEXT *rmr_context,
72		    OUT DAT_VLEN *registered_length,
73		    OUT DAT_VADDR *registered_address);
74
75/*
76 * Function Definitions
77 */
78
79static DAT_RETURN
80dapl_lmr_create_virtual(IN DAPL_IA *ia,
81			IN DAT_PVOID virt_addr,
82			IN DAT_VLEN length,
83			IN DAT_LMR_COOKIE shm_cookie,
84			IN DAPL_PZ *pz,
85			IN DAT_MEM_PRIV_FLAGS privileges,
86			OUT DAT_LMR_HANDLE *lmr_handle,
87			OUT DAT_LMR_CONTEXT *lmr_context,
88			OUT DAT_RMR_CONTEXT *rmr_context,
89			OUT DAT_VLEN *registered_length,
90			OUT DAT_VADDR *registered_address)
91{
92	DAPL_LMR *lmr;
93	DAT_REGION_DESCRIPTION reg_desc;
94	DAT_RETURN dat_status;
95
96	reg_desc.for_va = virt_addr;
97	dat_status = DAT_SUCCESS;
98
99	lmr = dapl_lmr_alloc(ia, DAT_MEM_TYPE_VIRTUAL,
100	    reg_desc, length, (DAT_PZ_HANDLE) pz, privileges);
101
102	if (NULL == lmr) {
103		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
104		    DAT_RESOURCE_MEMORY);
105		goto bail;
106	}
107
108	if (shm_cookie == NULL) {
109		dat_status = dapls_ib_mr_register(ia, lmr, virt_addr,
110		    length, privileges);
111	} else {
112		dat_status = dapls_ib_mr_register_shared(ia, lmr, virt_addr,
113		    length, shm_cookie, privileges);
114	}
115
116	if (DAT_SUCCESS != dat_status) {
117		dapl_lmr_dealloc(lmr);
118		goto bail;
119	}
120
121	/* if the LMR context is already in the hash table */
122	dat_status = dapls_hash_search(ia->hca_ptr->lmr_hash_table,
123	    lmr->param.lmr_context, NULL);
124	if (dat_status == DAT_SUCCESS) {
125		(void) dapls_ib_mr_deregister(lmr);
126		dapl_lmr_dealloc(lmr);
127
128		dat_status = DAT_ERROR(DAT_INVALID_STATE,
129		    DAT_INVALID_STATE_LMR_IN_USE);
130		goto bail;
131	}
132
133	dat_status = dapls_hash_insert(ia->hca_ptr->lmr_hash_table,
134	    lmr->param.lmr_context, lmr);
135	if (dat_status != DAT_SUCCESS) {
136		(void) dapls_ib_mr_deregister(lmr);
137		dapl_lmr_dealloc(lmr);
138		/*
139		 * The value returned by dapls_hash_insert(.) is not
140		 * returned to the consumer because the spec. requires
141		 * that dat_lmr_create(.) return only certain values.
142		 */
143		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
144		    DAT_RESOURCE_MEMORY);
145		goto bail;
146	}
147
148	(void) dapl_os_atomic_inc(&pz->pz_ref_count);
149
150	if (NULL != lmr_handle) {
151		*lmr_handle = (DAT_LMR_HANDLE) lmr;
152	}
153	if (NULL != lmr_context) {
154		*lmr_context = lmr->param.lmr_context;
155	}
156	if (NULL != rmr_context) {
157		*rmr_context = lmr->param.rmr_context;
158	}
159	if (NULL != registered_length) {
160		*registered_length = lmr->param.registered_size;
161	}
162	if (NULL != registered_address) {
163		*registered_address = lmr->param.registered_address;
164	}
165
166bail:
167	return (dat_status);
168}
169
170
171static DAT_RETURN
172dapl_lmr_create_lmr(IN DAPL_IA *ia,
173		    IN DAPL_LMR *original_lmr,
174		    IN DAPL_PZ *pz,
175		    IN DAT_MEM_PRIV_FLAGS privileges,
176		    OUT DAT_LMR_HANDLE *lmr_handle,
177		    OUT DAT_LMR_CONTEXT *lmr_context,
178		    OUT DAT_RMR_CONTEXT *rmr_context,
179		    OUT DAT_VLEN *registered_length,
180		    OUT DAT_VADDR *registered_address)
181{
182	DAPL_LMR *lmr;
183	DAT_REGION_DESCRIPTION reg_desc;
184	DAT_RETURN dat_status;
185
186	dapl_dbg_log(DAPL_DBG_TYPE_API,
187	    "dapl_lmr_create_lmr (%p, %p, %p, %x, %p, %p, %p, %p)\n",
188	    ia,
189	    original_lmr,
190	    pz, privileges,
191	    lmr_handle,
192	    lmr_context, registered_length, registered_address);
193
194	dat_status = dapls_hash_search(ia->hca_ptr->lmr_hash_table,
195	    original_lmr->param.lmr_context,
196	    (DAPL_HASH_DATA *) & lmr);
197	if (dat_status != DAT_SUCCESS) {
198		dat_status = DAT_ERROR(DAT_INVALID_PARAMETER,
199		    DAT_INVALID_ARG2);
200		goto bail;
201	}
202
203	reg_desc.for_lmr_handle = (DAT_LMR_HANDLE) original_lmr;
204
205	lmr = dapl_lmr_alloc(ia, DAT_MEM_TYPE_LMR, reg_desc, 0,
206	    (DAT_PZ_HANDLE) pz, privileges);
207
208	if (NULL == lmr) {
209		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
210		    DAT_RESOURCE_MEMORY);
211		goto bail;
212	}
213
214	dat_status = dapls_ib_mr_register_lmr(ia, lmr, privileges);
215
216	if (DAT_SUCCESS != dat_status) {
217		dapl_lmr_dealloc(lmr);
218		goto bail;
219	}
220
221	/* if the LMR context is already in the hash table */
222	dat_status = dapls_hash_search(ia->hca_ptr->lmr_hash_table,
223	    lmr->param.lmr_context, NULL);
224	if (dat_status == DAT_SUCCESS) {
225		(void) dapls_ib_mr_deregister(lmr);
226		dapl_lmr_dealloc(lmr);
227
228		dat_status = DAT_ERROR(DAT_INVALID_STATE,
229		    DAT_INVALID_STATE_LMR_IN_USE);
230		goto bail;
231	}
232
233	dat_status = dapls_hash_insert(ia->hca_ptr->lmr_hash_table,
234	    lmr->param.lmr_context, lmr);
235	if (dat_status != DAT_SUCCESS) {
236		(void) dapls_ib_mr_deregister(lmr);
237		dapl_lmr_dealloc(lmr);
238
239		/*
240		 * The value returned by dapls_hash_insert(.) is not
241		 * returned to the consumer because the spec. requires
242		 * that dat_lmr_create(.) return only certain values.
243		 */
244		dat_status = DAT_ERROR(DAT_INSUFFICIENT_RESOURCES,
245		    DAT_RESOURCE_MEMORY);
246		goto bail;
247	}
248
249	(void) dapl_os_atomic_inc(&pz->pz_ref_count);
250
251	if (NULL != lmr_handle) {
252		*lmr_handle = (DAT_LMR_HANDLE)lmr;
253	}
254	if (NULL != lmr_context) {
255		*lmr_context = lmr->param.lmr_context;
256	}
257	if (NULL != rmr_context) {
258		*rmr_context = lmr->param.rmr_context;
259	}
260	if (NULL != registered_length) {
261		*registered_length = original_lmr->param.registered_size;
262	}
263	if (NULL != registered_address) {
264		*registered_address = original_lmr->param.registered_address;
265	}
266
267bail:
268	return (dat_status);
269}
270
271
272/*
273 * dapl_lmr_create
274 *
275 * DAPL Requirements Version xxx, 6.6.3.1
276 *
277 * Register a memory region with an Interface Adaptor.
278 *
279 * Input:
280 *	ia_handle
281 *	mem_type
282 *	region_description
283 *	length
284 *	pz_handle
285 *	privileges
286 *
287 * Output:
288 *	lmr_handle
289 *	lmr_context
290 *	registered_length
291 *	registered_address
292 *
293 * Returns:
294 * 	DAT_SUCCESS
295 * 	DAT_INSUFFICIENT_RESOURCES
296 * 	DAT_INVALID_PARAMETER
297 * 	DAT_INVALID_STATE
298 * 	DAT_MODEL_NOT_SUPPORTED
299 *
300 */
301DAT_RETURN
302dapl_lmr_create(IN DAT_IA_HANDLE ia_handle,
303		IN DAT_MEM_TYPE mem_type,
304		IN DAT_REGION_DESCRIPTION region_description,
305		IN DAT_VLEN length,
306		IN DAT_PZ_HANDLE pz_handle,
307		IN DAT_MEM_PRIV_FLAGS privileges,
308		OUT DAT_LMR_HANDLE *lmr_handle,
309		OUT DAT_LMR_CONTEXT *lmr_context,
310		OUT DAT_RMR_CONTEXT *rmr_context,
311		OUT DAT_VLEN *registered_length,
312		OUT DAT_VADDR *registered_address)
313{
314	DAPL_IA *ia;
315	DAPL_PZ *pz;
316
317	if (DAPL_BAD_HANDLE(ia_handle, DAPL_MAGIC_IA) ||
318	    DAPL_BAD_HANDLE(pz_handle, DAPL_MAGIC_PZ)) {
319		return (DAT_INVALID_HANDLE);
320	}
321
322	if (length == 0) {
323		return (DAT_ERROR(DAT_INVALID_PARAMETER, DAT_INVALID_ARG4));
324	}
325
326	ia = (DAPL_IA *) ia_handle;
327	pz = (DAPL_PZ *) pz_handle;
328
329	/* Always ignore this bit as it is passed in */
330	privileges &= ~DAT_MEM_PRIV_RO_DISABLE_FLAG;
331
332	/*
333	 * If at open time we determined that RO should not be used,
334	 * note it here.
335	 */
336	if (ia->dapl_flags & DAPL_DISABLE_RO)
337		privileges |= DAT_MEM_PRIV_RO_DISABLE_FLAG;
338
339	switch (mem_type) {
340	case DAT_MEM_TYPE_SO_VIRTUAL:
341		privileges |= DAT_MEM_PRIV_RO_DISABLE_FLAG;
342		/* FALLTHROUGH */
343	case DAT_MEM_TYPE_VIRTUAL:
344		return (dapl_lmr_create_virtual(ia, region_description.for_va,
345		    length, NULL, pz, privileges,
346		    lmr_handle, lmr_context,
347		    rmr_context, registered_length,
348		    registered_address));
349		/* NOTREACHED */
350	case DAT_MEM_TYPE_LMR: {
351		DAPL_LMR *lmr;
352
353		if (DAPL_BAD_HANDLE
354		    (region_description.for_lmr_handle, DAPL_MAGIC_LMR)) {
355			return (DAT_INVALID_HANDLE);
356		}
357
358		lmr = (DAPL_LMR *)region_description.for_lmr_handle;
359
360		return (dapl_lmr_create_lmr(ia, lmr, pz, privileges, lmr_handle,
361		    lmr_context, rmr_context,
362		    registered_length, registered_address));
363		/* NOTREACHED */
364	}
365	case DAT_MEM_TYPE_SHARED_VIRTUAL:
366		return (dapl_lmr_create_virtual(ia,
367		    region_description.
368		    for_shared_memory.virtual_address,
369		    length,
370		    region_description.
371		    for_shared_memory.shared_memory_id,
372		    pz, privileges, lmr_handle,
373		    lmr_context, rmr_context,
374		    registered_length,
375		    registered_address));
376		/* NOTREACHED */
377	default:
378		return (DAT_INVALID_PARAMETER);
379	}
380}
381