1c0dd49bdSEiji Ota /*
2c0dd49bdSEiji Ota  * CDDL HEADER START
3c0dd49bdSEiji Ota  *
4c0dd49bdSEiji Ota  * The contents of this file are subject to the terms of the
5c0dd49bdSEiji Ota  * Common Development and Distribution License (the "License").
6c0dd49bdSEiji Ota  * You may not use this file except in compliance with the License.
7c0dd49bdSEiji Ota  *
8c0dd49bdSEiji Ota  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c0dd49bdSEiji Ota  * or http://www.opensolaris.org/os/licensing.
10c0dd49bdSEiji Ota  * See the License for the specific language governing permissions
11c0dd49bdSEiji Ota  * and limitations under the License.
12c0dd49bdSEiji Ota  *
13c0dd49bdSEiji Ota  * When distributing Covered Code, include this CDDL HEADER in each
14c0dd49bdSEiji Ota  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c0dd49bdSEiji Ota  * If applicable, add the following below this CDDL HEADER, with the
16c0dd49bdSEiji Ota  * fields enclosed by brackets "[]" replaced with your own identifying
17c0dd49bdSEiji Ota  * information: Portions Copyright [yyyy] [name of copyright owner]
18c0dd49bdSEiji Ota  *
19c0dd49bdSEiji Ota  * CDDL HEADER END
20c0dd49bdSEiji Ota  */
21c0dd49bdSEiji Ota /*
22c0dd49bdSEiji Ota  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23c0dd49bdSEiji Ota  */
24c0dd49bdSEiji Ota 
25c0dd49bdSEiji Ota /* Solaris Open Fabric kernel verbs */
26c0dd49bdSEiji Ota 
27c0dd49bdSEiji Ota #include <sys/types.h>
28c0dd49bdSEiji Ota #include <sys/ddi.h>
29c0dd49bdSEiji Ota #include <sys/sunddi.h>
30c0dd49bdSEiji Ota #include <sys/modctl.h>
31c0dd49bdSEiji Ota #include <sys/ib/clients/of/rdma/ib_verbs.h>
32c0dd49bdSEiji Ota #include <sys/ib/clients/of/rdma/ib_addr.h>
33c0dd49bdSEiji Ota #include <sys/ib/clients/of/rdma/rdma_cm.h>
34c0dd49bdSEiji Ota #include <sys/ib/clients/of/sol_ofs/sol_kverb_impl.h>
35c0dd49bdSEiji Ota 
36c0dd49bdSEiji Ota static void *statep;
37c0dd49bdSEiji Ota char *sol_kverbs_dbg_str = "sol_kverbs";
38c0dd49bdSEiji Ota 
39c0dd49bdSEiji Ota static llist_head_t client_list = LLIST_HEAD_INIT(client_list);
40c0dd49bdSEiji Ota kmutex_t clist_lock; /* mutex for client_list */
41c0dd49bdSEiji Ota 
42c0dd49bdSEiji Ota static void ofs_async_handler(void *, ibt_hca_hdl_t, ibt_async_code_t,
43c0dd49bdSEiji Ota     ibt_async_event_t *);
44c0dd49bdSEiji Ota 
45c0dd49bdSEiji Ota /*
46c0dd49bdSEiji Ota  * set ibt_client_t members. clnt->ib_client must be set before
47c0dd49bdSEiji Ota  * this func is called.
48c0dd49bdSEiji Ota  */
49c0dd49bdSEiji Ota static int
alloc_ibt_client(ofs_client_t * clnt)50c0dd49bdSEiji Ota alloc_ibt_client(ofs_client_t *clnt)
51c0dd49bdSEiji Ota {
52c0dd49bdSEiji Ota 	int namelen;
53c0dd49bdSEiji Ota 	ASSERT(clnt->ib_client != NULL);
54c0dd49bdSEiji Ota 
55c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
56c0dd49bdSEiji Ota 	    "alloc_ibt_client: client: 0x%p", clnt);
57c0dd49bdSEiji Ota 
58c0dd49bdSEiji Ota 	/*
59c0dd49bdSEiji Ota 	 * double-check the name string. if it's longer than MAXNAMELEN
60c0dd49bdSEiji Ota 	 * including the string terminator, assuming the name is invalid,
61c0dd49bdSEiji Ota 	 * return EINVAL.
62c0dd49bdSEiji Ota 	 */
63c0dd49bdSEiji Ota 	namelen = strlen(clnt->ib_client->name);
64c0dd49bdSEiji Ota 	if (namelen >= MAXNAMELEN) {
65c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
66c0dd49bdSEiji Ota 		    "alloc_ibt_client: client: 0x%p => "
67c0dd49bdSEiji Ota 		    "namelen(%d) is larger than MAXNAMELEN", clnt, namelen);
68c0dd49bdSEiji Ota 		return (-EINVAL);
69c0dd49bdSEiji Ota 	}
70c0dd49bdSEiji Ota 	clnt->ibt_client.mi_clnt_name = kmem_zalloc(namelen + 1, KM_NOSLEEP);
71c0dd49bdSEiji Ota 	if (clnt->ibt_client.mi_clnt_name == NULL) {
72c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
73c0dd49bdSEiji Ota 		    "alloc_ibt_client: client: 0x%p => "
74c0dd49bdSEiji Ota 		    "no sufficient memory", clnt);
75c0dd49bdSEiji Ota 		return (-ENOMEM);
76c0dd49bdSEiji Ota 	}
77c0dd49bdSEiji Ota 	bcopy(clnt->ib_client->name, clnt->ibt_client.mi_clnt_name, namelen);
78c0dd49bdSEiji Ota 	clnt->ibt_client.mi_ibt_version = IBTI_V_CURR;
79c0dd49bdSEiji Ota 	if (clnt->ib_client->dip) {
80c0dd49bdSEiji Ota 		clnt->ibt_client.mi_clnt_class = IBT_GENERIC;
81c0dd49bdSEiji Ota 	} else {
82c0dd49bdSEiji Ota 		clnt->ibt_client.mi_clnt_class = IBT_GENERIC_MISC;
83c0dd49bdSEiji Ota 	}
84c0dd49bdSEiji Ota 	clnt->ibt_client.mi_async_handler = ofs_async_handler;
85c0dd49bdSEiji Ota 
86c0dd49bdSEiji Ota 	return (0);
87c0dd49bdSEiji Ota }
88c0dd49bdSEiji Ota 
89c0dd49bdSEiji Ota static void
free_ibt_client(ofs_client_t * clnt)90c0dd49bdSEiji Ota free_ibt_client(ofs_client_t *clnt)
91c0dd49bdSEiji Ota {
92c0dd49bdSEiji Ota 	int namelen = strlen(clnt->ib_client->name);
93c0dd49bdSEiji Ota 	ASSERT(namelen < MAXNAMELEN);
94c0dd49bdSEiji Ota 
95c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
96c0dd49bdSEiji Ota 	    "free_ibt_client: client: 0x%p", clnt);
97c0dd49bdSEiji Ota 
98c0dd49bdSEiji Ota 	kmem_free(clnt->ibt_client.mi_clnt_name, namelen + 1);
99c0dd49bdSEiji Ota 	clnt->ibt_client.mi_clnt_name = NULL;
100c0dd49bdSEiji Ota }
101c0dd49bdSEiji Ota 
102c0dd49bdSEiji Ota /*
103c0dd49bdSEiji Ota  * get_device() returns a pointer to struct ib_devcie with
104c0dd49bdSEiji Ota  * the same guid as one passed to the function.
105c0dd49bdSEiji Ota  */
106c0dd49bdSEiji Ota static ib_device_t *
get_device(ofs_client_t * ofs_client,ib_guid_t guid)107c0dd49bdSEiji Ota get_device(ofs_client_t *ofs_client, ib_guid_t guid)
108c0dd49bdSEiji Ota {
109c0dd49bdSEiji Ota 	ib_device_t *device;
110c0dd49bdSEiji Ota 	llist_head_t *entry;
111c0dd49bdSEiji Ota 
112c0dd49bdSEiji Ota 	ASSERT(RW_LOCK_HELD(&ofs_client->lock));
113c0dd49bdSEiji Ota 
114c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
115c0dd49bdSEiji Ota 	    "get_device: client: 0x%p, guid:0x%p",
116c0dd49bdSEiji Ota 	    ofs_client, (void *)(uintptr_t)htonll(guid));
117c0dd49bdSEiji Ota 
118c0dd49bdSEiji Ota 	list_for_each(entry, &ofs_client->device_list) {
119c0dd49bdSEiji Ota 		device = entry->ptr;
120c0dd49bdSEiji Ota 		if (device->node_guid == htonll(guid)) {
121c0dd49bdSEiji Ota 			ASSERT(device->reg_state == IB_DEV_CLOSE);
122c0dd49bdSEiji Ota 			ASSERT(device->node_type == RDMA_NODE_IB_CA);
123c0dd49bdSEiji Ota 			ASSERT(device->clnt_hdl == (ofs_client_p_t)ofs_client);
124c0dd49bdSEiji Ota 			return (device);
125c0dd49bdSEiji Ota 		}
126c0dd49bdSEiji Ota 	}
127c0dd49bdSEiji Ota 
128c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
129c0dd49bdSEiji Ota 	    "get_device: client: 0x%p, guid:0x%p => no match guid",
130c0dd49bdSEiji Ota 	    ofs_client, (void *)(uintptr_t)htonll(guid));
131c0dd49bdSEiji Ota 
132c0dd49bdSEiji Ota 	return (NULL);
133c0dd49bdSEiji Ota }
134c0dd49bdSEiji Ota 
135c0dd49bdSEiji Ota /*
136c0dd49bdSEiji Ota  * ofs_async_handler() is a delegated function to handle asynchrnonous events,
137c0dd49bdSEiji Ota  * which dispatches each event to corresponding qp/cq handlers registered
138c0dd49bdSEiji Ota  * with ib_create_qp() and/or ib_create_cq().
139c0dd49bdSEiji Ota  */
140c0dd49bdSEiji Ota static void
ofs_async_handler(void * clntp,ibt_hca_hdl_t hdl,ibt_async_code_t code,ibt_async_event_t * event)141c0dd49bdSEiji Ota ofs_async_handler(void *clntp, ibt_hca_hdl_t hdl, ibt_async_code_t code,
142c0dd49bdSEiji Ota     ibt_async_event_t *event)
143c0dd49bdSEiji Ota {
144c0dd49bdSEiji Ota 	ofs_client_t 	*ofs_client = (ofs_client_t *)clntp;
145c0dd49bdSEiji Ota 	struct ib_event ib_event;
146c0dd49bdSEiji Ota 	struct ib_qp 	*qpp;
147c0dd49bdSEiji Ota 	struct ib_cq	*cqp;
148c0dd49bdSEiji Ota 
149c0dd49bdSEiji Ota 
150c0dd49bdSEiji Ota 	ASSERT(ofs_client != NULL);
151c0dd49bdSEiji Ota 
152c0dd49bdSEiji Ota 	cqp = event->ev_cq_hdl ? ibt_get_cq_private(event->ev_cq_hdl) : NULL;
153c0dd49bdSEiji Ota 	qpp = event->ev_chan_hdl ?
154c0dd49bdSEiji Ota 	    ibt_get_qp_private(event->ev_chan_hdl) : NULL;
155c0dd49bdSEiji Ota 
156c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
157c0dd49bdSEiji Ota 	    "ofs_async_handler: client: 0x%p, hca_hdl: 0x%p, code:0x%x, "
158c0dd49bdSEiji Ota 	    "event->qp: 0x%p, event->cq: 0x%p, event->srq: 0x%p "
159c0dd49bdSEiji Ota 	    "event->guid: 0x%p, event->port: 0x%x",
160c0dd49bdSEiji Ota 	    clntp, hdl, code, qpp, cqp, event->ev_srq_hdl,
161c0dd49bdSEiji Ota 	    (void *)(uintptr_t)event->ev_hca_guid, event->ev_port);
162c0dd49bdSEiji Ota 
163c0dd49bdSEiji Ota 	bzero(&ib_event, sizeof (struct ib_event));
164c0dd49bdSEiji Ota 	switch (code) {
165c0dd49bdSEiji Ota 	case IBT_EVENT_PATH_MIGRATED:
166c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
167c0dd49bdSEiji Ota 		    IB_EVENT_PATH_MIG);
168c0dd49bdSEiji Ota 		return;
169c0dd49bdSEiji Ota 	case IBT_EVENT_SQD:
170c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
171c0dd49bdSEiji Ota 		    IB_EVENT_SQ_DRAINED);
172c0dd49bdSEiji Ota 		return;
173c0dd49bdSEiji Ota 	case IBT_EVENT_COM_EST:
174c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
175c0dd49bdSEiji Ota 		    IB_EVENT_COMM_EST);
176c0dd49bdSEiji Ota 		return;
177c0dd49bdSEiji Ota 	case IBT_ERROR_CATASTROPHIC_CHAN:
178c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
179c0dd49bdSEiji Ota 		    IB_EVENT_QP_FATAL);
180c0dd49bdSEiji Ota 		return;
181c0dd49bdSEiji Ota 	case IBT_ERROR_INVALID_REQUEST_CHAN:
182c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
183c0dd49bdSEiji Ota 		    IB_EVENT_QP_REQ_ERR);
184c0dd49bdSEiji Ota 		return;
185c0dd49bdSEiji Ota 	case IBT_ERROR_ACCESS_VIOLATION_CHAN:
186c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
187c0dd49bdSEiji Ota 		    IB_EVENT_QP_ACCESS_ERR);
188c0dd49bdSEiji Ota 		return;
189c0dd49bdSEiji Ota 	case IBT_ERROR_PATH_MIGRATE_REQ:
190c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
191c0dd49bdSEiji Ota 		    IB_EVENT_PATH_MIG);
192c0dd49bdSEiji Ota 		return;
193c0dd49bdSEiji Ota 	case IBT_EVENT_EMPTY_CHAN:
194c0dd49bdSEiji Ota 		FIRE_QP_EVENT(ofs_client, hdl, ib_event, qpp,
195c0dd49bdSEiji Ota 		    IB_EVENT_QP_LAST_WQE_REACHED);
196c0dd49bdSEiji Ota 		return;
197c0dd49bdSEiji Ota 	case IBT_ERROR_CQ:
198c0dd49bdSEiji Ota 		FIRE_CQ_EVENT(ofs_client, hdl, ib_event, cqp,
199c0dd49bdSEiji Ota 		    IB_EVENT_CQ_ERR);
200c0dd49bdSEiji Ota 		return;
201c0dd49bdSEiji Ota 	case IBT_HCA_ATTACH_EVENT:
202c0dd49bdSEiji Ota 	{
203c0dd49bdSEiji Ota 		ib_device_t	*device;
204c0dd49bdSEiji Ota 		int		rtn;
205c0dd49bdSEiji Ota 
206c0dd49bdSEiji Ota 		/* re-use the device once it was created */
207c0dd49bdSEiji Ota 		rw_enter(&ofs_client->lock, RW_WRITER);
208c0dd49bdSEiji Ota 		device = get_device(ofs_client, event->ev_hca_guid);
209c0dd49bdSEiji Ota 		if (device == NULL) {
210c0dd49bdSEiji Ota 			device = kmem_alloc(sizeof (ib_device_t), KM_SLEEP);
211c0dd49bdSEiji Ota 			device->node_type = RDMA_NODE_IB_CA;
212c0dd49bdSEiji Ota 			device->reg_state = IB_DEV_CLOSE;
213c0dd49bdSEiji Ota 			device->clnt_hdl = (ofs_client_p_t)ofs_client;
214c0dd49bdSEiji Ota 			device->node_guid = htonll(event->ev_hca_guid);
215c0dd49bdSEiji Ota 			device->data = NULL;
216c0dd49bdSEiji Ota 			/* add this HCA */
217c0dd49bdSEiji Ota 			ofs_client->hca_num++;
218c0dd49bdSEiji Ota 			llist_head_init(&device->list, device);
219c0dd49bdSEiji Ota 			llist_add_tail(&device->list, &ofs_client->device_list);
220c0dd49bdSEiji Ota 		}
221c0dd49bdSEiji Ota 		device->hca_hdl = NULL;
222c0dd49bdSEiji Ota 		device->local_dma_lkey = 0;
223c0dd49bdSEiji Ota 		device->phys_port_cnt = 0;
224c0dd49bdSEiji Ota 
225c0dd49bdSEiji Ota 		/* open this HCA */
226c0dd49bdSEiji Ota 		rtn = ibt_open_hca(ofs_client->ibt_hdl, event->ev_hca_guid,
227c0dd49bdSEiji Ota 		    &device->hca_hdl);
228c0dd49bdSEiji Ota 		if (rtn == IBT_SUCCESS) {
229c0dd49bdSEiji Ota 			ibt_hca_attr_t hattr;
230c0dd49bdSEiji Ota 
231c0dd49bdSEiji Ota 			ofs_client->hca_open_num++;
232c0dd49bdSEiji Ota 			device->reg_state = IB_DEV_OPEN;
233c0dd49bdSEiji Ota 			ibt_set_hca_private(device->hca_hdl, device);
234c0dd49bdSEiji Ota 
235c0dd49bdSEiji Ota 			rtn = ibt_query_hca(device->hca_hdl, &hattr);
236c0dd49bdSEiji Ota 			if (rtn != IBT_SUCCESS) {
237c0dd49bdSEiji Ota 				device->reg_state = IB_DEV_CLOSE;
238c0dd49bdSEiji Ota 				rtn = ibt_close_hca(device->hca_hdl);
239c0dd49bdSEiji Ota 				ASSERT(rtn == IBT_SUCCESS);
240c0dd49bdSEiji Ota 				ofs_client->hca_open_num--;
241c0dd49bdSEiji Ota 				return;
242c0dd49bdSEiji Ota 			}
243c0dd49bdSEiji Ota 
244c0dd49bdSEiji Ota 			(void) sprintf(device->name, "%x:%x:%x",
245c0dd49bdSEiji Ota 			    hattr.hca_vendor_id, hattr.hca_device_id,
246c0dd49bdSEiji Ota 			    hattr.hca_version_id);
247c0dd49bdSEiji Ota 			device->local_dma_lkey = hattr.hca_reserved_lkey;
248c0dd49bdSEiji Ota 			device->phys_port_cnt = hattr.hca_nports;
249c0dd49bdSEiji Ota 			ibt_set_hca_private(device->hca_hdl, device);
250c0dd49bdSEiji Ota 
251c0dd49bdSEiji Ota 			/* invoke client's callback */
252c0dd49bdSEiji Ota 			if (ofs_client->ib_client->add) {
253c0dd49bdSEiji Ota 				ofs_client->ib_client->add(device);
254c0dd49bdSEiji Ota 			}
255c0dd49bdSEiji Ota 		}
256c0dd49bdSEiji Ota 		rw_exit(&ofs_client->lock);
257c0dd49bdSEiji Ota 
258c0dd49bdSEiji Ota 		return;
259c0dd49bdSEiji Ota 	}
260c0dd49bdSEiji Ota 	case IBT_HCA_DETACH_EVENT:
261c0dd49bdSEiji Ota 	{
262c0dd49bdSEiji Ota 		struct ib_device *device;
263c0dd49bdSEiji Ota 
264c0dd49bdSEiji Ota 		rw_enter(&ofs_client->lock, RW_WRITER);
265c0dd49bdSEiji Ota 		device = ibt_get_hca_private(hdl);
266c0dd49bdSEiji Ota 		if (device->reg_state == IB_DEV_OPEN) {
267c0dd49bdSEiji Ota 			ibt_status_t rtn;
268c0dd49bdSEiji Ota 			/* invoke client's callback */
269c0dd49bdSEiji Ota 			if (ofs_client->ib_client->remove) {
270c0dd49bdSEiji Ota 				ofs_client->ib_client->remove(device);
271c0dd49bdSEiji Ota 			}
272c0dd49bdSEiji Ota 			/* change the state only */
273c0dd49bdSEiji Ota 			device->reg_state = IB_DEV_CLOSE;
274c0dd49bdSEiji Ota 			/* close this HCA */
275c0dd49bdSEiji Ota 			rtn = ibt_close_hca(device->hca_hdl);
276c0dd49bdSEiji Ota 			ASSERT(rtn == IBT_SUCCESS);
277c0dd49bdSEiji Ota 			ofs_client->hca_open_num--;
278c0dd49bdSEiji Ota 		}
279c0dd49bdSEiji Ota 		rw_exit(&ofs_client->lock);
280c0dd49bdSEiji Ota 
281c0dd49bdSEiji Ota 		return;
282c0dd49bdSEiji Ota 	}
283c0dd49bdSEiji Ota 	case IBT_EVENT_LIMIT_REACHED_SRQ:
284c0dd49bdSEiji Ota 	case IBT_ERROR_CATASTROPHIC_SRQ:
285c0dd49bdSEiji Ota 	default:
286c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
287c0dd49bdSEiji Ota 		    "sol_ofs does not support this event(0x%x).\n"
288c0dd49bdSEiji Ota 		    "\t clntp=0x%p, hca_hdl=0x%p, code=%d, eventp=0x%p\n",
289c0dd49bdSEiji Ota 		    code, clntp, hdl, code, event);
290c0dd49bdSEiji Ota 		return;
291c0dd49bdSEiji Ota 	}
292c0dd49bdSEiji Ota }
293c0dd49bdSEiji Ota 
294c0dd49bdSEiji Ota /*
295c0dd49bdSEiji Ota  * ib_register_client - Register an IB client
296c0dd49bdSEiji Ota  * @client:Client to register
297c0dd49bdSEiji Ota  *
298c0dd49bdSEiji Ota  * Upper level users of the IB drivers can use ib_register_client() to
299c0dd49bdSEiji Ota  * register callbacks for IB device addition and removal.  When an IB
300c0dd49bdSEiji Ota  * device is added, each registered client's add method will be called
301c0dd49bdSEiji Ota  * (in the order the clients were registered), and when a device is
302c0dd49bdSEiji Ota  * removed, each client's remove method will be called (in the reverse
303c0dd49bdSEiji Ota  * order that clients were registered).  In addition, when
304c0dd49bdSEiji Ota  * ib_register_client() is called, the client will receive an add
305c0dd49bdSEiji Ota  * callback for all devices already registered.
306c0dd49bdSEiji Ota  *
307c0dd49bdSEiji Ota  * Note that struct ib_client should have a dip pointer to the client,
308c0dd49bdSEiji Ota  * which is different from the Linux implementation.
309c0dd49bdSEiji Ota  */
310c0dd49bdSEiji Ota int
ib_register_client(struct ib_client * client)311c0dd49bdSEiji Ota ib_register_client(struct ib_client *client)
312c0dd49bdSEiji Ota {
313c0dd49bdSEiji Ota 	uint_t		i, nhcas; /* number of HCAs */
314c0dd49bdSEiji Ota 	ib_guid_t	*guidp;
315c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client;
316c0dd49bdSEiji Ota 	llist_head_t	*entry, *tmp;
317c0dd49bdSEiji Ota 	ib_device_t	*device;
318c0dd49bdSEiji Ota 	int		rtn;
319c0dd49bdSEiji Ota 
320c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
321c0dd49bdSEiji Ota 	    "ib_register_client: client: 0x%p", client);
322c0dd49bdSEiji Ota 
323c0dd49bdSEiji Ota 	/* get the number of HCAs on this system */
324c0dd49bdSEiji Ota 	if ((nhcas = ibt_get_hca_list(&guidp)) == 0) {
325c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
326c0dd49bdSEiji Ota 		    "ib_register_client: client: 0x%p => no HCA", client);
327c0dd49bdSEiji Ota 		return (-ENXIO);
328c0dd49bdSEiji Ota 	}
329c0dd49bdSEiji Ota 
330c0dd49bdSEiji Ota 	/* allocate a new sol_ofs_client structure */
331c0dd49bdSEiji Ota 	ofs_client = kmem_zalloc(sizeof (ofs_client_t), KM_NOSLEEP);
332c0dd49bdSEiji Ota 	if (ofs_client == NULL) {
333c0dd49bdSEiji Ota 		(void) ibt_free_hca_list(guidp, nhcas);
334c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
335c0dd49bdSEiji Ota 		    "ib_register_client: client: 0x%p => "
336c0dd49bdSEiji Ota 		    "no sufficient memory for ofs_client", client);
337c0dd49bdSEiji Ota 		return (-ENOMEM);
338c0dd49bdSEiji Ota 	}
339c0dd49bdSEiji Ota 
340c0dd49bdSEiji Ota 	/* set members */
341c0dd49bdSEiji Ota 	ofs_client->ib_client = client;
342c0dd49bdSEiji Ota 	if ((rtn = alloc_ibt_client(ofs_client)) != 0) {
343c0dd49bdSEiji Ota 		kmem_free(ofs_client, sizeof (ofs_client_t));
344c0dd49bdSEiji Ota 		(void) ibt_free_hca_list(guidp, nhcas);
345c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
346c0dd49bdSEiji Ota 		    "ib_register_client: client: 0x%p => "
347c0dd49bdSEiji Ota 		    "alloc_ibt_client failed w/ 0x%x", client, rtn);
348c0dd49bdSEiji Ota 		return (rtn);
349c0dd49bdSEiji Ota 	}
350c0dd49bdSEiji Ota 	ofs_client->state = IB_OFS_CLNT_INITIALIZED;
351c0dd49bdSEiji Ota 	llist_head_init(&ofs_client->device_list, NULL);
352c0dd49bdSEiji Ota 	llist_head_init(&ofs_client->client_list, ofs_client);
353c0dd49bdSEiji Ota 	rw_init(&ofs_client->lock, NULL, RW_DEFAULT, NULL);
354c0dd49bdSEiji Ota 
355c0dd49bdSEiji Ota 	/* initialize IB client */
356c0dd49bdSEiji Ota 	rw_enter(&ofs_client->lock, RW_WRITER);
357c0dd49bdSEiji Ota 	if (client->state != IB_CLNT_UNINITIALIZED) {
358c0dd49bdSEiji Ota 		rw_exit(&ofs_client->lock);
359c0dd49bdSEiji Ota 		kmem_free(ofs_client, sizeof (ofs_client_t));
360c0dd49bdSEiji Ota 		(void) ibt_free_hca_list(guidp, nhcas);
361c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
362c0dd49bdSEiji Ota 		    "ib_register_client: client: 0x%p => "
363c0dd49bdSEiji Ota 		    "invalid client state(%d)", client, client->state);
364c0dd49bdSEiji Ota 		return (-EPERM);
365c0dd49bdSEiji Ota 	}
366c0dd49bdSEiji Ota 
367c0dd49bdSEiji Ota 	/* attach this client to IBTF */
368c0dd49bdSEiji Ota 	rtn = ibt_attach(&ofs_client->ibt_client, client->dip, ofs_client,
369c0dd49bdSEiji Ota 	    &ofs_client->ibt_hdl);
370c0dd49bdSEiji Ota 	if (rtn != IBT_SUCCESS) {
371c0dd49bdSEiji Ota 		rw_exit(&ofs_client->lock);
372c0dd49bdSEiji Ota 		free_ibt_client(ofs_client);
373c0dd49bdSEiji Ota 		kmem_free(ofs_client, sizeof (ofs_client_t));
374c0dd49bdSEiji Ota 		(void) ibt_free_hca_list(guidp, nhcas);
375c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
376c0dd49bdSEiji Ota 		    "ib_register_client: client: 0x%p => "
377c0dd49bdSEiji Ota 		    "ibt_attach failed w/ 0x%x", client, rtn);
378c0dd49bdSEiji Ota 		return (-EINVAL);
379c0dd49bdSEiji Ota 	}
380c0dd49bdSEiji Ota 	client->clnt_hdl = (ofs_client_p_t)ofs_client;
381c0dd49bdSEiji Ota 	client->state = IB_CLNT_INITIALIZED;
382c0dd49bdSEiji Ota 
383c0dd49bdSEiji Ota 	/* link this client */
384c0dd49bdSEiji Ota 	mutex_enter(&clist_lock);
385c0dd49bdSEiji Ota 	llist_add_tail(&ofs_client->client_list, &client_list);
386c0dd49bdSEiji Ota 	mutex_exit(&clist_lock);
387c0dd49bdSEiji Ota 
388c0dd49bdSEiji Ota 	/* Open HCAs */
389c0dd49bdSEiji Ota 	ofs_client->hca_num = nhcas;
390c0dd49bdSEiji Ota 	for (i = 0; i < ofs_client->hca_num; i++) {
391c0dd49bdSEiji Ota 		/* allocate the ib_device structure */
392c0dd49bdSEiji Ota 		device = kmem_zalloc(sizeof (ib_device_t), KM_NOSLEEP);
393c0dd49bdSEiji Ota 		if (device == NULL) {
394c0dd49bdSEiji Ota 			rtn = -ENOMEM;
395c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
396c0dd49bdSEiji Ota 			    "ib_register_client: client: 0x%p => "
397c0dd49bdSEiji Ota 			    "no sufficient memory for ib_device", client);
398c0dd49bdSEiji Ota 			goto err;
399c0dd49bdSEiji Ota 		}
400c0dd49bdSEiji Ota 		device->node_guid = htonll(guidp[i]);
401c0dd49bdSEiji Ota 		device->node_type = RDMA_NODE_IB_CA;
402c0dd49bdSEiji Ota 		device->reg_state = IB_DEV_CLOSE;
403c0dd49bdSEiji Ota 		device->clnt_hdl = (ofs_client_p_t)ofs_client;
404c0dd49bdSEiji Ota 		llist_head_init(&device->list, device);
405c0dd49bdSEiji Ota 		llist_add_tail(&device->list, &ofs_client->device_list);
406c0dd49bdSEiji Ota 
407c0dd49bdSEiji Ota 		rtn = ibt_open_hca(ofs_client->ibt_hdl, guidp[i],
408c0dd49bdSEiji Ota 		    &device->hca_hdl);
409c0dd49bdSEiji Ota 		if (rtn == IBT_SUCCESS) {
410c0dd49bdSEiji Ota 			ibt_hca_attr_t hattr;
411c0dd49bdSEiji Ota 
412c0dd49bdSEiji Ota 			ofs_client->hca_open_num++;
413c0dd49bdSEiji Ota 			device->reg_state = IB_DEV_OPEN;
414c0dd49bdSEiji Ota 
415c0dd49bdSEiji Ota 			rtn = ibt_query_hca(device->hca_hdl, &hattr);
416c0dd49bdSEiji Ota 			if (rtn != IBT_SUCCESS) {
417c0dd49bdSEiji Ota 				rtn = -EIO;
418c0dd49bdSEiji Ota 				SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
419c0dd49bdSEiji Ota 				    "ib_register_client: client: 0x%p,"
420c0dd49bdSEiji Ota 				    "hca_hdl: 0x%p ==> "
421c0dd49bdSEiji Ota 				    "ibt_query_hca() failed w/ %d",
422c0dd49bdSEiji Ota 				    client, device->hca_hdl, rtn);
423c0dd49bdSEiji Ota 				goto err;
424c0dd49bdSEiji Ota 			}
425c0dd49bdSEiji Ota 
426c0dd49bdSEiji Ota 			(void) sprintf(device->name, "%x:%x:%x",
427c0dd49bdSEiji Ota 			    hattr.hca_vendor_id, hattr.hca_device_id,
428c0dd49bdSEiji Ota 			    hattr.hca_version_id);
429c0dd49bdSEiji Ota 			device->local_dma_lkey = hattr.hca_reserved_lkey;
430c0dd49bdSEiji Ota 			device->phys_port_cnt = hattr.hca_nports;
431c0dd49bdSEiji Ota 			ibt_set_hca_private(device->hca_hdl, device);
432c0dd49bdSEiji Ota 
433c0dd49bdSEiji Ota 			/* invoke client's callback */
434c0dd49bdSEiji Ota 			if (client->add) {
435c0dd49bdSEiji Ota 				client->add(device);
436c0dd49bdSEiji Ota 			}
437c0dd49bdSEiji Ota 		}
438c0dd49bdSEiji Ota 	}
439c0dd49bdSEiji Ota 	if (ofs_client->hca_open_num == 0) {
440c0dd49bdSEiji Ota 		rtn = -ENXIO;
441c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
442c0dd49bdSEiji Ota 		    "ib_register_client: client: 0x%p => "
443c0dd49bdSEiji Ota 		    "no available HCA", client);
444c0dd49bdSEiji Ota 		goto err;
445c0dd49bdSEiji Ota 	}
446c0dd49bdSEiji Ota 	rw_exit(&ofs_client->lock);
447c0dd49bdSEiji Ota 
448c0dd49bdSEiji Ota 	(void) ibt_free_hca_list(guidp, nhcas);
449c0dd49bdSEiji Ota 	return (0);
450c0dd49bdSEiji Ota 
451c0dd49bdSEiji Ota err:
452c0dd49bdSEiji Ota 	/* first close all open HCAs */
453c0dd49bdSEiji Ota 	list_for_each(entry, &ofs_client->device_list) {
454c0dd49bdSEiji Ota 		device = entry->ptr;
455c0dd49bdSEiji Ota 		/*
456c0dd49bdSEiji Ota 		 * If it's open already, close it after the remove
457c0dd49bdSEiji Ota 		 * callback.
458c0dd49bdSEiji Ota 		 */
459c0dd49bdSEiji Ota 		if (device->reg_state == IB_DEV_OPEN) {
460c0dd49bdSEiji Ota 			ibt_status_t rtn;
461c0dd49bdSEiji Ota 			/* invoke client's callback */
462c0dd49bdSEiji Ota 			if (client->remove) {
463c0dd49bdSEiji Ota 				client->remove(device);
464c0dd49bdSEiji Ota 			}
465c0dd49bdSEiji Ota 			device->reg_state = IB_DEV_CLOSE;
466c0dd49bdSEiji Ota 			rtn = ibt_close_hca(device->hca_hdl);
467c0dd49bdSEiji Ota 			ASSERT(rtn == IBT_SUCCESS);
468c0dd49bdSEiji Ota 			ofs_client->hca_open_num--;
469c0dd49bdSEiji Ota 		}
470c0dd49bdSEiji Ota 	}
471c0dd49bdSEiji Ota 	ASSERT(ofs_client->hca_open_num == 0);
472c0dd49bdSEiji Ota 
473c0dd49bdSEiji Ota 	/* then free the devices */
474c0dd49bdSEiji Ota 	list_for_each_safe(entry, tmp, &ofs_client->device_list) {
475c0dd49bdSEiji Ota 		device = entry->ptr;
476c0dd49bdSEiji Ota 		/* de-link and free the device */
477c0dd49bdSEiji Ota 		llist_del(entry);
478c0dd49bdSEiji Ota 		kmem_free(device, sizeof (ib_device_t));
479c0dd49bdSEiji Ota 		ofs_client->hca_num--;
480c0dd49bdSEiji Ota 	}
481c0dd49bdSEiji Ota 	ASSERT(ofs_client->hca_num == 0);
482c0dd49bdSEiji Ota 
483c0dd49bdSEiji Ota 	/* delink this client */
484c0dd49bdSEiji Ota 	mutex_enter(&clist_lock);
485c0dd49bdSEiji Ota 	llist_del(&ofs_client->client_list);
486c0dd49bdSEiji Ota 	mutex_exit(&clist_lock);
487c0dd49bdSEiji Ota 
488c0dd49bdSEiji Ota 	/* detach the client */
489c0dd49bdSEiji Ota 	client->clnt_hdl = NULL;
490c0dd49bdSEiji Ota 	client->state = IB_CLNT_UNINITIALIZED;
491c0dd49bdSEiji Ota 	(void) ibt_detach(ofs_client->ibt_hdl);
492c0dd49bdSEiji Ota 	rw_exit(&ofs_client->lock);
493c0dd49bdSEiji Ota 
494c0dd49bdSEiji Ota 	/* free sol_ofs_client */
495c0dd49bdSEiji Ota 	free_ibt_client(ofs_client);
496c0dd49bdSEiji Ota 	kmem_free(ofs_client, sizeof (ofs_client_t));
497c0dd49bdSEiji Ota 
498c0dd49bdSEiji Ota 	(void) ibt_free_hca_list(guidp, nhcas);
499c0dd49bdSEiji Ota 	return (rtn);
500c0dd49bdSEiji Ota }
501c0dd49bdSEiji Ota 
502c0dd49bdSEiji Ota /*
503c0dd49bdSEiji Ota  * ib_unregister_client - Unregister an IB client
504c0dd49bdSEiji Ota  * @client:Client to unregister
505c0dd49bdSEiji Ota  *
506c0dd49bdSEiji Ota  * Upper level users use ib_unregister_client() to remove their client
507c0dd49bdSEiji Ota  * registration.  When ib_unregister_client() is called, the client
508c0dd49bdSEiji Ota  * will receive a remove callback for each IB device still registered.
509c0dd49bdSEiji Ota  */
510c0dd49bdSEiji Ota void
ib_unregister_client(struct ib_client * client)511c0dd49bdSEiji Ota ib_unregister_client(struct ib_client *client)
512c0dd49bdSEiji Ota {
513c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client;
514c0dd49bdSEiji Ota 	ib_device_t	*device;
515c0dd49bdSEiji Ota 	llist_head_t	*entry, *tmp;
516c0dd49bdSEiji Ota 
517c0dd49bdSEiji Ota 	ASSERT(client->state == IB_CLNT_INITIALIZED &&
518c0dd49bdSEiji Ota 	    client->clnt_hdl != NULL);
519c0dd49bdSEiji Ota 
520c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
521c0dd49bdSEiji Ota 	    "ib_unregister_client: client: 0x%p", client);
522c0dd49bdSEiji Ota 
523c0dd49bdSEiji Ota 	ofs_client = (ofs_client_t *)client->clnt_hdl;
524c0dd49bdSEiji Ota 	rw_enter(&ofs_client->lock, RW_WRITER);
525c0dd49bdSEiji Ota 
526c0dd49bdSEiji Ota 	/* first close all open HCAs */
527c0dd49bdSEiji Ota 	list_for_each(entry, &ofs_client->device_list) {
528c0dd49bdSEiji Ota 		device = entry->ptr;
529c0dd49bdSEiji Ota 		/*
530c0dd49bdSEiji Ota 		 * If it's open already, close it after the remove
531c0dd49bdSEiji Ota 		 * callback.
532c0dd49bdSEiji Ota 		 */
533c0dd49bdSEiji Ota 		if (device->reg_state == IB_DEV_OPEN) {
534c0dd49bdSEiji Ota 			ibt_status_t rtn;
535c0dd49bdSEiji Ota 			/* invoke client's callback */
536c0dd49bdSEiji Ota 			if (client->remove) {
537c0dd49bdSEiji Ota 				client->remove(device);
538c0dd49bdSEiji Ota 			}
539c0dd49bdSEiji Ota 			device->reg_state = IB_DEV_CLOSE;
540c0dd49bdSEiji Ota 			rtn = ibt_close_hca(device->hca_hdl);
541c0dd49bdSEiji Ota 			if (rtn != IBT_SUCCESS)
542c0dd49bdSEiji Ota 				SOL_OFS_DPRINTF_L3(
543c0dd49bdSEiji Ota 				    sol_kverbs_dbg_str,
544c0dd49bdSEiji Ota 				    "ib_unregister_client(%p) - "
545c0dd49bdSEiji Ota 				    "ibt_close_hca failed %d",
546c0dd49bdSEiji Ota 				    client, rtn);
547c0dd49bdSEiji Ota 
548c0dd49bdSEiji Ota 			ofs_client->hca_open_num--;
549c0dd49bdSEiji Ota 		}
550c0dd49bdSEiji Ota 	}
551c0dd49bdSEiji Ota 	ASSERT(ofs_client->hca_open_num == 0);
552c0dd49bdSEiji Ota 
553c0dd49bdSEiji Ota 	/* then free the devices */
554c0dd49bdSEiji Ota 	list_for_each_safe(entry, tmp, &ofs_client->device_list) {
555c0dd49bdSEiji Ota 		device = entry->ptr;
556c0dd49bdSEiji Ota 		/* de-link and free the device */
557c0dd49bdSEiji Ota 		llist_del(entry);
558c0dd49bdSEiji Ota 		kmem_free(device, sizeof (ib_device_t));
559c0dd49bdSEiji Ota 		ofs_client->hca_num--;
560c0dd49bdSEiji Ota 	}
561c0dd49bdSEiji Ota 	ASSERT(ofs_client->hca_num == 0);
562c0dd49bdSEiji Ota 
563c0dd49bdSEiji Ota 	/* delink this client */
564c0dd49bdSEiji Ota 	mutex_enter(&clist_lock);
565c0dd49bdSEiji Ota 	llist_del(&ofs_client->client_list);
566c0dd49bdSEiji Ota 	mutex_exit(&clist_lock);
567c0dd49bdSEiji Ota 
568c0dd49bdSEiji Ota 	/* detach the client */
569c0dd49bdSEiji Ota 	client->clnt_hdl = NULL;
570c0dd49bdSEiji Ota 	client->state = IB_CLNT_UNINITIALIZED;
571c0dd49bdSEiji Ota 	(void) ibt_detach(ofs_client->ibt_hdl);
572c0dd49bdSEiji Ota 	rw_exit(&ofs_client->lock);
573c0dd49bdSEiji Ota 
574c0dd49bdSEiji Ota 	/* free sol_ofs_client */
575c0dd49bdSEiji Ota 	free_ibt_client(ofs_client);
576c0dd49bdSEiji Ota 	kmem_free(ofs_client, sizeof (ofs_client_t));
577c0dd49bdSEiji Ota }
578c0dd49bdSEiji Ota 
579c0dd49bdSEiji Ota /*
580c0dd49bdSEiji Ota  * ofs_lock_enter() and ofs_lock_exit() are used to avoid the recursive
581c0dd49bdSEiji Ota  * rwlock while the client callbacks are invoked.
582c0dd49bdSEiji Ota  *
583c0dd49bdSEiji Ota  * Note that the writer lock is used only in the client callback case,
584c0dd49bdSEiji Ota  * so that the kverb functions wanting to acquire the reader lock can
585c0dd49bdSEiji Ota  * safely ignore the reader lock if the writer lock is already held.
586c0dd49bdSEiji Ota  * The writer lock shouldn't be used in no other plances.
587c0dd49bdSEiji Ota  */
588c0dd49bdSEiji Ota static inline void
ofs_lock_enter(krwlock_t * lock)589c0dd49bdSEiji Ota ofs_lock_enter(krwlock_t *lock)
590c0dd49bdSEiji Ota {
591c0dd49bdSEiji Ota 	if (!RW_WRITE_HELD(lock)) {
592c0dd49bdSEiji Ota 		rw_enter(lock, RW_READER);
593c0dd49bdSEiji Ota 	}
594c0dd49bdSEiji Ota }
595c0dd49bdSEiji Ota 
596c0dd49bdSEiji Ota static inline void
ofs_lock_exit(krwlock_t * lock)597c0dd49bdSEiji Ota ofs_lock_exit(krwlock_t *lock)
598c0dd49bdSEiji Ota {
599c0dd49bdSEiji Ota 	if (!RW_WRITE_HELD(lock)) {
600c0dd49bdSEiji Ota 		rw_exit(lock);
601c0dd49bdSEiji Ota 	}
602c0dd49bdSEiji Ota }
603c0dd49bdSEiji Ota 
604c0dd49bdSEiji Ota /*
605c0dd49bdSEiji Ota  * ib_get_client_data - Get IB client context
606c0dd49bdSEiji Ota  * @device:Device to get context for
607c0dd49bdSEiji Ota  * @client:Client to get context for
608c0dd49bdSEiji Ota  *
609c0dd49bdSEiji Ota  * ib_get_client_data() returns client context set with
610c0dd49bdSEiji Ota  * ib_set_client_data() and returns NULL if it's not found.
611c0dd49bdSEiji Ota  */
ib_get_client_data(struct ib_device * device,struct ib_client * client)612c0dd49bdSEiji Ota void *ib_get_client_data(struct ib_device *device,
613c0dd49bdSEiji Ota     struct ib_client *client)
614c0dd49bdSEiji Ota {
615c0dd49bdSEiji Ota 	ofs_client_t		*ofs_client;
616c0dd49bdSEiji Ota 	struct ib_device	*ib_device;
617c0dd49bdSEiji Ota 	boolean_t		found = B_FALSE;
618c0dd49bdSEiji Ota 	llist_head_t		*entry;
619c0dd49bdSEiji Ota 	void			*data;
620c0dd49bdSEiji Ota 
621c0dd49bdSEiji Ota 	ASSERT(device != 0 && client != 0);
622c0dd49bdSEiji Ota 
623c0dd49bdSEiji Ota 	ofs_client = (ofs_client_t *)client->clnt_hdl;
624c0dd49bdSEiji Ota 	if (ofs_client == 0) {
625c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
626c0dd49bdSEiji Ota 		    "ib_get_client_data: device: 0x%p, client: 0x%p => "
627c0dd49bdSEiji Ota 		    "no ofs_client", device, client);
628c0dd49bdSEiji Ota 		return (NULL);
629c0dd49bdSEiji Ota 	}
630c0dd49bdSEiji Ota 
631c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
632c0dd49bdSEiji Ota 	list_for_each(entry, &ofs_client->device_list) {
633c0dd49bdSEiji Ota 		ib_device = entry->ptr;
634c0dd49bdSEiji Ota 		if (ib_device->node_guid == device->node_guid) {
635c0dd49bdSEiji Ota 			found = B_TRUE;
636c0dd49bdSEiji Ota 			break;
637c0dd49bdSEiji Ota 		}
638c0dd49bdSEiji Ota 	}
639c0dd49bdSEiji Ota 	if (!found) {
640c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
641c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
642c0dd49bdSEiji Ota 		    "ib_get_client_data: device: 0x%p, client: 0x%p => "
643c0dd49bdSEiji Ota 		    "no ib_device found", device, client);
644c0dd49bdSEiji Ota 		return (NULL);
645c0dd49bdSEiji Ota 	}
646c0dd49bdSEiji Ota 	data = ib_device->data;
647c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
648c0dd49bdSEiji Ota 
649c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
650c0dd49bdSEiji Ota 	    "ib_get_client_data: device: 0x%p, client: 0x%p",
651c0dd49bdSEiji Ota 	    device, client);
652c0dd49bdSEiji Ota 
653c0dd49bdSEiji Ota 	return (data);
654c0dd49bdSEiji Ota }
655c0dd49bdSEiji Ota 
656c0dd49bdSEiji Ota /*
657c0dd49bdSEiji Ota  * ib_set_client_data - Set IB client context
658c0dd49bdSEiji Ota  * @device:Device to set context for
659c0dd49bdSEiji Ota  * @client:Client to set context for
660c0dd49bdSEiji Ota  * @data:Context to set
661c0dd49bdSEiji Ota  *
662c0dd49bdSEiji Ota  * ib_set_client_data() sets client context that can be retrieved with
663c0dd49bdSEiji Ota  * ib_get_client_data(). If the specified device is not found, the function
664c0dd49bdSEiji Ota  * returns w/o any operations.
665c0dd49bdSEiji Ota  */
ib_set_client_data(struct ib_device * device,struct ib_client * client,void * data)666c0dd49bdSEiji Ota void ib_set_client_data(struct ib_device *device, struct ib_client *client,
667c0dd49bdSEiji Ota     void *data)
668c0dd49bdSEiji Ota {
669c0dd49bdSEiji Ota 	ofs_client_t		*ofs_client;
670c0dd49bdSEiji Ota 	struct ib_device	*ib_device;
671c0dd49bdSEiji Ota 	boolean_t		found = B_FALSE;
672c0dd49bdSEiji Ota 	llist_head_t		*entry;
673c0dd49bdSEiji Ota 
674c0dd49bdSEiji Ota 	ASSERT(device != 0 && client != 0);
675c0dd49bdSEiji Ota 
676c0dd49bdSEiji Ota 	ofs_client = (ofs_client_t *)client->clnt_hdl;
677c0dd49bdSEiji Ota 	if (ofs_client == 0) {
678c0dd49bdSEiji Ota 		cmn_err(CE_WARN, "No client context found for %s/%s\n",
679c0dd49bdSEiji Ota 		    device->name, client->name);
680c0dd49bdSEiji Ota 		return;
681c0dd49bdSEiji Ota 	}
682c0dd49bdSEiji Ota 
683c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
684c0dd49bdSEiji Ota 	list_for_each(entry, &ofs_client->device_list) {
685c0dd49bdSEiji Ota 		ib_device = entry->ptr;
686c0dd49bdSEiji Ota 		if (ib_device->node_guid == device->node_guid) {
687c0dd49bdSEiji Ota 			found = B_TRUE;
688c0dd49bdSEiji Ota 			break;
689c0dd49bdSEiji Ota 		}
690c0dd49bdSEiji Ota 	}
691c0dd49bdSEiji Ota 	if (!found) {
692c0dd49bdSEiji Ota 		cmn_err(CE_WARN, "No client context found for %s/%s\n",
693c0dd49bdSEiji Ota 		    device->name, client->name);
694c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
695c0dd49bdSEiji Ota 		return;
696c0dd49bdSEiji Ota 	}
697c0dd49bdSEiji Ota 	ib_device->data = data;
698c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
699c0dd49bdSEiji Ota 
700c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
701c0dd49bdSEiji Ota 	    "ib_set_client_data: device: 0x%p, client: 0x%p, "
702c0dd49bdSEiji Ota 	    "data: 0x%p", device, client, data);
703c0dd49bdSEiji Ota }
704c0dd49bdSEiji Ota 
705c0dd49bdSEiji Ota /*
706c0dd49bdSEiji Ota  * ib_query_device - Query IB device attributes
707c0dd49bdSEiji Ota  * @device:Device to query
708c0dd49bdSEiji Ota  * @device_attr:Device attributes
709c0dd49bdSEiji Ota  *
710c0dd49bdSEiji Ota  * ib_query_device() returns the attributes of a device through the
711c0dd49bdSEiji Ota  * @device_attr pointer.
712c0dd49bdSEiji Ota  */
713c0dd49bdSEiji Ota int
ib_query_device(struct ib_device * device,struct ib_device_attr * attr)714c0dd49bdSEiji Ota ib_query_device(struct ib_device *device, struct ib_device_attr *attr)
715c0dd49bdSEiji Ota {
716c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client = (ofs_client_t *)device->clnt_hdl;
717c0dd49bdSEiji Ota 	ibt_hca_attr_t	hattr;
718c0dd49bdSEiji Ota 	int		rtn;
719c0dd49bdSEiji Ota 
720c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
721c0dd49bdSEiji Ota 	if (device->reg_state != IB_DEV_OPEN) {
722c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
723c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
724c0dd49bdSEiji Ota 		    "ib_query_device: device: 0x%p => "
725c0dd49bdSEiji Ota 		    "invalid device state (%d)", device, device->reg_state);
726c0dd49bdSEiji Ota 		return (-ENXIO);
727c0dd49bdSEiji Ota 	}
728c0dd49bdSEiji Ota 	if ((rtn = ibt_query_hca(device->hca_hdl, &hattr)) != IBT_SUCCESS) {
729c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
730c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
731c0dd49bdSEiji Ota 		    "ib_query_device: device: 0x%p => "
732c0dd49bdSEiji Ota 		    "ibt_query_hca failed w/ 0x%x", device, rtn);
733c0dd49bdSEiji Ota 		return (-EIO);
734c0dd49bdSEiji Ota 	}
735c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
736c0dd49bdSEiji Ota 
737c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
738c0dd49bdSEiji Ota 	    "ib_query_device: device: 0x%p, attr: 0x%p, rtn: 0x%p",
739c0dd49bdSEiji Ota 	    device, attr, rtn);
740c0dd49bdSEiji Ota 
741c0dd49bdSEiji Ota 	/* OF order is major.micro.minor, so keep it here */
742c0dd49bdSEiji Ota 	attr->fw_ver = (uint64_t)hattr.hca_fw_major_version << 32	|
743c0dd49bdSEiji Ota 	    hattr.hca_fw_micro_version << 16 & 0xFFFF0000		|
744c0dd49bdSEiji Ota 	    hattr.hca_fw_minor_version & 0xFFFF;
745c0dd49bdSEiji Ota 
746c0dd49bdSEiji Ota 	attr->device_cap_flags    = IB_DEVICE_CHANGE_PHY_PORT		|
747c0dd49bdSEiji Ota 	    IB_DEVICE_PORT_ACTIVE_EVENT					|
748c0dd49bdSEiji Ota 	    IB_DEVICE_SYS_IMAGE_GUID					|
749c0dd49bdSEiji Ota 	    IB_DEVICE_RC_RNR_NAK_GEN;
750c0dd49bdSEiji Ota 	if (hattr.hca_flags & IBT_HCA_PKEY_CNTR) {
751c0dd49bdSEiji Ota 		attr->device_cap_flags |= IB_DEVICE_BAD_PKEY_CNTR;
752c0dd49bdSEiji Ota 	}
753c0dd49bdSEiji Ota 	if (hattr.hca_flags & IBT_HCA_QKEY_CNTR) {
754c0dd49bdSEiji Ota 		attr->device_cap_flags |= IB_DEVICE_BAD_QKEY_CNTR;
755c0dd49bdSEiji Ota 	}
756c0dd49bdSEiji Ota 	if (hattr.hca_flags & IBT_HCA_AUTO_PATH_MIG) {
757c0dd49bdSEiji Ota 		attr->device_cap_flags |= IB_DEVICE_AUTO_PATH_MIG;
758c0dd49bdSEiji Ota 	}
759c0dd49bdSEiji Ota 	if (hattr.hca_flags & IBT_HCA_AH_PORT_CHECK) {
760c0dd49bdSEiji Ota 		attr->device_cap_flags |= IB_DEVICE_UD_AV_PORT_ENFORCE;
761c0dd49bdSEiji Ota 	}
762c0dd49bdSEiji Ota 
763c0dd49bdSEiji Ota 	attr->vendor_id		= hattr.hca_vendor_id;
764c0dd49bdSEiji Ota 	attr->vendor_part_id	= hattr.hca_device_id;
765c0dd49bdSEiji Ota 	attr->hw_ver		= hattr.hca_version_id;
766c0dd49bdSEiji Ota 	attr->sys_image_guid	= htonll(hattr.hca_si_guid);
767c0dd49bdSEiji Ota 	attr->max_mr_size	= ~0ull;
768c0dd49bdSEiji Ota 	attr->page_size_cap	= IBTF2OF_PGSZ(hattr.hca_page_sz);
769c0dd49bdSEiji Ota 	attr->max_qp		= hattr.hca_max_qp;
770c0dd49bdSEiji Ota 	attr->max_qp_wr		= hattr.hca_max_qp_sz;
771c0dd49bdSEiji Ota 	attr->max_sge		= hattr.hca_max_sgl;
772c0dd49bdSEiji Ota 	attr->max_sge_rd	= hattr.hca_max_rd_sgl;
773c0dd49bdSEiji Ota 	attr->max_cq		= hattr.hca_max_cq;
774c0dd49bdSEiji Ota 	attr->max_cqe		= hattr.hca_max_cq_sz;
775c0dd49bdSEiji Ota 	attr->max_mr		= hattr.hca_max_memr;
776c0dd49bdSEiji Ota 	attr->max_pd		= hattr.hca_max_pd;
777c0dd49bdSEiji Ota 	attr->max_qp_rd_atom	= hattr.hca_max_rdma_in_qp;
778c0dd49bdSEiji Ota 	attr->max_qp_init_rd_atom	= hattr.hca_max_rdma_in_qp;
779c0dd49bdSEiji Ota 	attr->max_ee_rd_atom	= hattr.hca_max_rdma_in_ee;
780c0dd49bdSEiji Ota 	attr->max_ee_init_rd_atom	= hattr.hca_max_rdma_in_ee;
781c0dd49bdSEiji Ota 	attr->max_res_rd_atom	= hattr.hca_max_rsc;
782c0dd49bdSEiji Ota 	attr->max_srq		= hattr.hca_max_srqs;
783c0dd49bdSEiji Ota 	attr->max_srq_wr	= hattr.hca_max_srqs_sz -1;
784c0dd49bdSEiji Ota 	attr->max_srq_sge	= hattr.hca_max_srq_sgl;
785c0dd49bdSEiji Ota 	attr->local_ca_ack_delay	= hattr.hca_local_ack_delay;
786c0dd49bdSEiji Ota 	attr->atomic_cap = hattr.hca_flags & IBT_HCA_ATOMICS_GLOBAL ?
787c0dd49bdSEiji Ota 	    IB_ATOMIC_GLOB : (hattr.hca_flags & IBT_HCA_ATOMICS_HCA ?
788c0dd49bdSEiji Ota 	    IB_ATOMIC_HCA : IB_ATOMIC_NONE);
789c0dd49bdSEiji Ota 	attr->max_ee		= hattr.hca_max_eec;
790c0dd49bdSEiji Ota 	attr->max_rdd		= hattr.hca_max_rdd;
791c0dd49bdSEiji Ota 	attr->max_mw		= hattr.hca_max_mem_win;
792c0dd49bdSEiji Ota 	attr->max_pkeys		= hattr.hca_max_port_pkey_tbl_sz;
793c0dd49bdSEiji Ota 	attr->max_raw_ipv6_qp	= hattr.hca_max_ipv6_qp;
794c0dd49bdSEiji Ota 	attr->max_raw_ethy_qp	= hattr.hca_max_ether_qp;
795c0dd49bdSEiji Ota 	attr->max_mcast_grp	= hattr.hca_max_mcg;
796c0dd49bdSEiji Ota 	attr->max_mcast_qp_attach	= hattr.hca_max_qp_per_mcg;
797c0dd49bdSEiji Ota 	attr->max_total_mcast_qp_attach = hattr.hca_max_mcg_qps;
798c0dd49bdSEiji Ota 	attr->max_ah		= hattr.hca_max_ah;
799c0dd49bdSEiji Ota 	attr->max_fmr		= hattr.hca_max_fmrs;
800c0dd49bdSEiji Ota 	attr->max_map_per_fmr	= hattr.hca_opaque9; /* hca_max_map_per_fmr */
801c0dd49bdSEiji Ota 
802c0dd49bdSEiji Ota 	return (0);
803c0dd49bdSEiji Ota }
804c0dd49bdSEiji Ota 
805c0dd49bdSEiji Ota /* Protection domains */
806c0dd49bdSEiji Ota struct ib_pd *
ib_alloc_pd(struct ib_device * device)807c0dd49bdSEiji Ota ib_alloc_pd(struct ib_device *device)
808c0dd49bdSEiji Ota {
809c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client = (ofs_client_t *)device->clnt_hdl;
810c0dd49bdSEiji Ota 	struct ib_pd	*pd;
811c0dd49bdSEiji Ota 	int		rtn;
812c0dd49bdSEiji Ota 
813c0dd49bdSEiji Ota 	if ((pd = kmem_alloc(sizeof (struct ib_pd), KM_NOSLEEP)) == NULL) {
814c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
815c0dd49bdSEiji Ota 		    "ib_alloc_pd: device: 0x%p => no sufficient memory",
816c0dd49bdSEiji Ota 		    device);
817c0dd49bdSEiji Ota 		return ((struct ib_pd *)-ENOMEM);
818c0dd49bdSEiji Ota 	}
819c0dd49bdSEiji Ota 
820c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
821c0dd49bdSEiji Ota 	if (device->reg_state != IB_DEV_OPEN) {
822c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
823c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
824c0dd49bdSEiji Ota 		    "ib_alloc_pd: device: 0x%p => invalid device state (%d)",
825c0dd49bdSEiji Ota 		    device, device->reg_state);
826c0dd49bdSEiji Ota 		return ((struct ib_pd *)-ENXIO);
827c0dd49bdSEiji Ota 	}
828c0dd49bdSEiji Ota 
829c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
830c0dd49bdSEiji Ota 	    "ib_alloc_pd: device: 0x%p", device);
831c0dd49bdSEiji Ota 
832c0dd49bdSEiji Ota 	rtn = ibt_alloc_pd(device->hca_hdl, IBT_PD_NO_FLAGS, &pd->ibt_pd);
833c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
834c0dd49bdSEiji Ota 
835c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
836c0dd49bdSEiji Ota 		pd->device = device;
837c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
838c0dd49bdSEiji Ota 		    "ib_alloc_pd: device: 0x%p, pd: 0x%p, ibt_pd: 0x%p, "
839c0dd49bdSEiji Ota 		    "rtn: 0x%x", device, pd, pd->ibt_pd, rtn);
840c0dd49bdSEiji Ota 		return (pd);
841c0dd49bdSEiji Ota 	}
842c0dd49bdSEiji Ota 	kmem_free(pd, sizeof (struct ib_pd));
843c0dd49bdSEiji Ota 
844c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
845c0dd49bdSEiji Ota 	    "ib_alloc_pd: device: 0x%p, pd: 0x%p, ibt_pd: 0x%p => "
846c0dd49bdSEiji Ota 	    "ibt_alloc_pd failed w/ 0x%x", device, pd, pd->ibt_pd, rtn);
847c0dd49bdSEiji Ota 
848c0dd49bdSEiji Ota 	switch (rtn) {
849c0dd49bdSEiji Ota 	case IBT_INSUFF_RESOURCE:
850c0dd49bdSEiji Ota 		return ((struct ib_pd *)-ENOMEM);
851c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
852c0dd49bdSEiji Ota 		return ((struct ib_pd *)-EFAULT);
853c0dd49bdSEiji Ota 	default:
854c0dd49bdSEiji Ota 		return ((struct ib_pd *)-EIO);
855c0dd49bdSEiji Ota 	}
856c0dd49bdSEiji Ota }
857c0dd49bdSEiji Ota 
858c0dd49bdSEiji Ota int
ib_dealloc_pd(struct ib_pd * pd)859c0dd49bdSEiji Ota ib_dealloc_pd(struct ib_pd *pd)
860c0dd49bdSEiji Ota {
861c0dd49bdSEiji Ota 	ofs_client_t *ofs_client = (ofs_client_t *)pd->device->clnt_hdl;
862c0dd49bdSEiji Ota 	int rtn;
863c0dd49bdSEiji Ota 
864c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
865c0dd49bdSEiji Ota 	if (pd->device->reg_state != IB_DEV_OPEN) {
866c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
867c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
868c0dd49bdSEiji Ota 		    "ib_dealloc_pd: pd: 0x%p => invalid device state (%d)",
869c0dd49bdSEiji Ota 		    pd, pd->device->reg_state);
870c0dd49bdSEiji Ota 		return (-ENXIO);
871c0dd49bdSEiji Ota 	}
872c0dd49bdSEiji Ota 
873c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
874c0dd49bdSEiji Ota 	    "ib_dealloc_pd: pd: 0x%p", pd);
875c0dd49bdSEiji Ota 
876c0dd49bdSEiji Ota 	rtn = ibt_free_pd(pd->device->hca_hdl, pd->ibt_pd);
877c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
878c0dd49bdSEiji Ota 
879c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
880c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
881c0dd49bdSEiji Ota 		    "ib_dealloc_pd: pd: 0x%p, device: 0x%p, ibt_pd: 0x%p, "
882c0dd49bdSEiji Ota 		    "rtn: 0x%x", pd, pd->device, pd->ibt_pd, rtn);
883c0dd49bdSEiji Ota 		kmem_free(pd, sizeof (struct ib_pd));
884c0dd49bdSEiji Ota 		return (0);
885c0dd49bdSEiji Ota 	}
886c0dd49bdSEiji Ota 
887c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
888c0dd49bdSEiji Ota 	    "ib_dealloc_pd: pd: 0x%p => ibt_free_pd failed w/ 0x%x",
889c0dd49bdSEiji Ota 	    pd, rtn);
890c0dd49bdSEiji Ota 
891c0dd49bdSEiji Ota 	switch (rtn) {
892c0dd49bdSEiji Ota 	case IBT_PD_IN_USE:
893c0dd49bdSEiji Ota 		return (-EBUSY);
894c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
895c0dd49bdSEiji Ota 		return (-EFAULT);
896c0dd49bdSEiji Ota 	default:
897c0dd49bdSEiji Ota 		return (-EIO);
898c0dd49bdSEiji Ota 	}
899c0dd49bdSEiji Ota }
900c0dd49bdSEiji Ota 
901c0dd49bdSEiji Ota /*
902c0dd49bdSEiji Ota  * ofs_cq_handler() is a delegated function to handle CQ events,
903c0dd49bdSEiji Ota  * which dispatches them to corresponding cq handlers registered
904c0dd49bdSEiji Ota  * with ib_create_cq().
905c0dd49bdSEiji Ota  */
906c0dd49bdSEiji Ota static void
ofs_cq_handler(ibt_cq_hdl_t ibt_cq,void * arg)907c0dd49bdSEiji Ota ofs_cq_handler(ibt_cq_hdl_t ibt_cq, void *arg)
908c0dd49bdSEiji Ota {
909c0dd49bdSEiji Ota 	struct ib_cq *cq = (struct ib_cq *)ibt_get_cq_private(ibt_cq);
910c0dd49bdSEiji Ota 
911c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
912c0dd49bdSEiji Ota 	    "ofs_cq_handler: ibt_cq: 0x%p, ib_cq: 0x%p, comp_handler: 0x%p, "
913c0dd49bdSEiji Ota 	    "arg: 0x%p", ibt_cq, cq, cq->comp_handler, arg);
914c0dd49bdSEiji Ota 
915c0dd49bdSEiji Ota 	if (cq->comp_handler) {
916c0dd49bdSEiji Ota 		cq->comp_handler(cq, cq->cq_context);
917c0dd49bdSEiji Ota 	}
918c0dd49bdSEiji Ota }
919c0dd49bdSEiji Ota 
920c0dd49bdSEiji Ota /*
921c0dd49bdSEiji Ota  * ib_create_cq - Creates a CQ on the specified device.
922c0dd49bdSEiji Ota  * @device: The device on which to create the CQ.
923c0dd49bdSEiji Ota  * @comp_handler: A user-specified callback that is invoked when a
924c0dd49bdSEiji Ota  *   completion event occurs on the CQ.
925c0dd49bdSEiji Ota  * @event_handler: A user-specified callback that is invoked when an
926c0dd49bdSEiji Ota  *   asynchronous event not associated with a completion occurs on the CQ.
927c0dd49bdSEiji Ota  * @cq_context: Context associated with the CQ returned to the user via
928c0dd49bdSEiji Ota  *   the associated completion and event handlers.
929c0dd49bdSEiji Ota  * @cqe: The minimum size of the CQ.
930c0dd49bdSEiji Ota  * @comp_vector - Completion vector used to signal completion events.
931c0dd49bdSEiji Ota  *     Must be >= 0 and < context->num_comp_vectors.
932c0dd49bdSEiji Ota  *
933c0dd49bdSEiji Ota  * Users can examine the cq structure to determine the actual CQ size.
934c0dd49bdSEiji Ota  *
935c0dd49bdSEiji Ota  * Note that comp_vector is not supported currently.
936c0dd49bdSEiji Ota  */
937c0dd49bdSEiji Ota struct ib_cq *
ib_create_cq(struct ib_device * device,ib_comp_handler comp_handler,void (* event_handler)(struct ib_event *,void *),void * cq_context,int cqe,void * comp_vector)938c0dd49bdSEiji Ota ib_create_cq(struct ib_device *device, ib_comp_handler comp_handler,
939c0dd49bdSEiji Ota     void (*event_handler)(struct ib_event *, void *), void *cq_context,
940*17a2b317SBill Taylor     int cqe, void *comp_vector)
941c0dd49bdSEiji Ota {
942c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client = (ofs_client_t *)device->clnt_hdl;
943c0dd49bdSEiji Ota 	ibt_cq_attr_t	cq_attr;
944c0dd49bdSEiji Ota 	uint32_t	real_size;
945c0dd49bdSEiji Ota 	struct ib_cq	*cq;
946c0dd49bdSEiji Ota 	int		rtn;
947c0dd49bdSEiji Ota 
948c0dd49bdSEiji Ota 	if ((cq = kmem_alloc(sizeof (struct ib_cq), KM_NOSLEEP)) == NULL) {
949c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
950c0dd49bdSEiji Ota 		    "ib_create_cq: device: 0x%p, comp_handler: 0x%p, "
951c0dd49bdSEiji Ota 		    "event_handler: 0x%p, cq_context: 0x%p, cqe: 0x%x, "
952*17a2b317SBill Taylor 		    "comp_vector: %p => no sufficient memory", device,
953c0dd49bdSEiji Ota 		    comp_handler, event_handler, cq_context, cqe, comp_vector);
954c0dd49bdSEiji Ota 		return ((struct ib_cq *)-ENOMEM);
955c0dd49bdSEiji Ota 	}
956c0dd49bdSEiji Ota 
957c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
958c0dd49bdSEiji Ota 	if (device->reg_state != IB_DEV_OPEN) {
959c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
960c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
961c0dd49bdSEiji Ota 		    "ib_create_cq: device: 0x%p, comp_handler: 0x%p, "
962c0dd49bdSEiji Ota 		    "event_handler: 0x%p, cq_context: 0x%p, cqe: 0x%x, "
963*17a2b317SBill Taylor 		    "comp_vector: %p => invalid device state (%d)", device,
964c0dd49bdSEiji Ota 		    comp_handler, event_handler, cq_context, cqe, comp_vector,
965c0dd49bdSEiji Ota 		    device->reg_state);
966c0dd49bdSEiji Ota 		return ((struct ib_cq *)-ENXIO);
967c0dd49bdSEiji Ota 	}
968c0dd49bdSEiji Ota 
969c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
970c0dd49bdSEiji Ota 	    "ib_create_cq: device: 0x%p, comp_handler: 0x%p, "
971c0dd49bdSEiji Ota 	    "event_handler: 0x%p, cq_context: 0x%p, cqe: 0x%x, "
972c0dd49bdSEiji Ota 	    "comp_vector: %d", device, comp_handler, event_handler,
973c0dd49bdSEiji Ota 	    cq_context, cqe, comp_vector);
974c0dd49bdSEiji Ota 
975c0dd49bdSEiji Ota 	cq_attr.cq_size = cqe;
976*17a2b317SBill Taylor 	cq_attr.cq_sched = comp_vector;
977c0dd49bdSEiji Ota 	cq_attr.cq_flags = IBT_CQ_NO_FLAGS;
978c0dd49bdSEiji Ota 	rtn = ibt_alloc_cq(device->hca_hdl, &cq_attr, &cq->ibt_cq, &real_size);
979c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
980c0dd49bdSEiji Ota 
981c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
982c0dd49bdSEiji Ota 		cq->device = device;
983c0dd49bdSEiji Ota 		cq->comp_handler = comp_handler;
984c0dd49bdSEiji Ota 		cq->event_handler = event_handler;
985c0dd49bdSEiji Ota 		cq->cq_context = cq_context;
986c0dd49bdSEiji Ota 		cq->cqe = real_size;
987c0dd49bdSEiji Ota 		ibt_set_cq_private(cq->ibt_cq, cq);
988c0dd49bdSEiji Ota 		ibt_set_cq_handler(cq->ibt_cq, ofs_cq_handler, cq_context);
989c0dd49bdSEiji Ota 		mutex_init(&cq->lock, NULL, MUTEX_DEFAULT, NULL);
990c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
991c0dd49bdSEiji Ota 		    "ib_create_cq: device: 0x%p, cqe: 0x%x, ibt_cq: 0x%p, "
992c0dd49bdSEiji Ota 		    "rtn: 0x%x", device, cqe, cq->ibt_cq, rtn);
993c0dd49bdSEiji Ota 		return (cq);
994c0dd49bdSEiji Ota 	}
995c0dd49bdSEiji Ota 	kmem_free(cq, sizeof (struct ib_cq));
996c0dd49bdSEiji Ota 
997c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
998c0dd49bdSEiji Ota 	    "ib_create_cq: device: 0x%p, cqe: 0x%x, ibt_cq: 0x%p => "
999c0dd49bdSEiji Ota 	    "ibt_alloc_cq failed w/ 0x%x", device, cqe, cq->ibt_cq, rtn);
1000c0dd49bdSEiji Ota 
1001c0dd49bdSEiji Ota 	switch (rtn) {
1002c0dd49bdSEiji Ota 	case IBT_HCA_CQ_EXCEEDED:
1003c0dd49bdSEiji Ota 	case IBT_INVALID_PARAM:
1004c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
1005c0dd49bdSEiji Ota 		return ((struct ib_cq *)-EINVAL);
1006c0dd49bdSEiji Ota 	case IBT_INSUFF_RESOURCE:
1007c0dd49bdSEiji Ota 		return ((struct ib_cq *)-ENOMEM);
1008c0dd49bdSEiji Ota 	default:
1009c0dd49bdSEiji Ota 		return ((struct ib_cq *)-EIO);
1010c0dd49bdSEiji Ota 	}
1011c0dd49bdSEiji Ota }
1012c0dd49bdSEiji Ota 
1013c0dd49bdSEiji Ota int
ib_destroy_cq(struct ib_cq * cq)1014c0dd49bdSEiji Ota ib_destroy_cq(struct ib_cq *cq)
1015c0dd49bdSEiji Ota {
1016c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client = (ofs_client_t *)cq->device->clnt_hdl;
1017c0dd49bdSEiji Ota 	int		rtn;
1018c0dd49bdSEiji Ota 
1019c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
1020c0dd49bdSEiji Ota 	if (cq->device->reg_state != IB_DEV_OPEN) {
1021c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1022c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1023c0dd49bdSEiji Ota 		    "ib_destroy_cq: cq: 0x%p => invalid device state (%d)",
1024c0dd49bdSEiji Ota 		    cq, cq->device->reg_state);
1025c0dd49bdSEiji Ota 		return (-ENXIO);
1026c0dd49bdSEiji Ota 	}
1027c0dd49bdSEiji Ota 
1028c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1029c0dd49bdSEiji Ota 	    "ib_destroy_cq: cq: 0x%p", cq);
1030c0dd49bdSEiji Ota 
1031c0dd49bdSEiji Ota 	/*
1032c0dd49bdSEiji Ota 	 * if IBTL_ASYNC_PENDING is set, ibt_qp is not freed
1033c0dd49bdSEiji Ota 	 * at this moment, but yet alive for a while. Then
1034c0dd49bdSEiji Ota 	 * there is a possibility that this qp is used even after
1035c0dd49bdSEiji Ota 	 * ib_destroy_cq() is called. To distinguish this case from
1036c0dd49bdSEiji Ota 	 * others, clear ibt_qp here.
1037c0dd49bdSEiji Ota 	 */
1038c0dd49bdSEiji Ota 	ibt_set_cq_private(cq->ibt_cq, NULL);
1039c0dd49bdSEiji Ota 
1040c0dd49bdSEiji Ota 	rtn = ibt_free_cq(cq->ibt_cq);
1041c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
1042c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1043c0dd49bdSEiji Ota 		kmem_free(cq, sizeof (struct ib_cq));
1044c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1045c0dd49bdSEiji Ota 		    "ib_destroy_cq: cq: 0x%p, rtn: 0x%x", cq, rtn);
1046c0dd49bdSEiji Ota 		return (0);
1047c0dd49bdSEiji Ota 	}
1048c0dd49bdSEiji Ota 	ibt_set_cq_private(cq->ibt_cq, cq);
1049c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
1050c0dd49bdSEiji Ota 
1051c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1052c0dd49bdSEiji Ota 	    "ib_destroy_cq: cq: 0x%p => ibt_free_cq failed w/ 0x%x", cq, rtn);
1053c0dd49bdSEiji Ota 
1054c0dd49bdSEiji Ota 	switch (rtn) {
1055c0dd49bdSEiji Ota 	case IBT_CQ_BUSY:
1056c0dd49bdSEiji Ota 		return (-EBUSY);
1057c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
1058c0dd49bdSEiji Ota 	case IBT_CQ_HDL_INVALID:
1059c0dd49bdSEiji Ota 		return (-EINVAL);
1060c0dd49bdSEiji Ota 	default:
1061c0dd49bdSEiji Ota 		return (-EIO);
1062c0dd49bdSEiji Ota 	}
1063c0dd49bdSEiji Ota }
1064c0dd49bdSEiji Ota 
1065c0dd49bdSEiji Ota struct ib_qp *
ib_create_qp(struct ib_pd * pd,struct ib_qp_init_attr * qp_init_attr)1066c0dd49bdSEiji Ota ib_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *qp_init_attr)
1067c0dd49bdSEiji Ota {
1068c0dd49bdSEiji Ota 	ofs_client_t		*ofs_client = pd->device->clnt_hdl;
1069c0dd49bdSEiji Ota 	ibt_qp_alloc_attr_t	attrs;
1070c0dd49bdSEiji Ota 	ibt_chan_sizes_t	sizes;
1071c0dd49bdSEiji Ota 	ib_qpn_t		qpn;
1072c0dd49bdSEiji Ota 	ibt_qp_hdl_t		ibt_qp;
1073c0dd49bdSEiji Ota 	struct ib_qp		*qp;
1074c0dd49bdSEiji Ota 	int			rtn;
1075c0dd49bdSEiji Ota 
1076c0dd49bdSEiji Ota 	/* sanity check */
1077c0dd49bdSEiji Ota 	if (!(qp_init_attr->send_cq && qp_init_attr->recv_cq)) {
1078c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1079c0dd49bdSEiji Ota 		    "ib_create_qp: pd: 0x%p => invalid cqs "
1080c0dd49bdSEiji Ota 		    "(send_cq=0x%p, recv_cq=0x%p)", pd,
1081c0dd49bdSEiji Ota 		    qp_init_attr->send_cq, qp_init_attr->recv_cq);
1082c0dd49bdSEiji Ota 		return ((struct ib_qp *)-EINVAL);
1083c0dd49bdSEiji Ota 	}
1084c0dd49bdSEiji Ota 
1085c0dd49bdSEiji Ota 	/* UC, Raw IPv6 and Raw Ethernet are not supported */
1086c0dd49bdSEiji Ota 	if (qp_init_attr->qp_type == IB_QPT_UC ||
1087c0dd49bdSEiji Ota 	    qp_init_attr->qp_type == IB_QPT_RAW_IPV6 ||
1088c0dd49bdSEiji Ota 	    qp_init_attr->qp_type == IB_QPT_RAW_ETY) {
1089c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1090c0dd49bdSEiji Ota 		    "ib_create_qp: pd: 0x%p => invalid qp_type",
1091c0dd49bdSEiji Ota 		    pd, qp_init_attr->qp_type);
1092c0dd49bdSEiji Ota 		return ((struct ib_qp *)-EINVAL);
1093c0dd49bdSEiji Ota 	}
1094c0dd49bdSEiji Ota 
1095c0dd49bdSEiji Ota 	if ((qp = kmem_alloc(sizeof (struct ib_qp), KM_NOSLEEP)) == NULL) {
1096c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1097c0dd49bdSEiji Ota 		    "ib_create_qp: pd: 0x%p, init_attr: 0x%p => "
1098c0dd49bdSEiji Ota 		    "no sufficient memory", pd, qp_init_attr);
1099c0dd49bdSEiji Ota 		return ((struct ib_qp *)-ENOMEM);
1100c0dd49bdSEiji Ota 	}
1101c0dd49bdSEiji Ota 
1102c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
1103c0dd49bdSEiji Ota 	if (pd->device->reg_state != IB_DEV_OPEN) {
1104c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1105c0dd49bdSEiji Ota 		kmem_free(qp, sizeof (struct ib_qp));
1106c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1107c0dd49bdSEiji Ota 		    "ib_create_qp: pd: 0x%p, init_attr: 0x%p => "
1108c0dd49bdSEiji Ota 		    "invalid device state (%d)", pd, qp_init_attr,
1109c0dd49bdSEiji Ota 		    pd->device->reg_state);
1110c0dd49bdSEiji Ota 		return ((struct ib_qp *)-ENXIO);
1111c0dd49bdSEiji Ota 	}
1112c0dd49bdSEiji Ota 
1113c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1114c0dd49bdSEiji Ota 	    "ib_create_qp: pd: 0x%p, event_handler: 0x%p, qp_context: 0x%p, "
1115c0dd49bdSEiji Ota 	    "send_cq: 0x%p, recv_cq: 0x%p, srq: 0x%p, max_send_wr: 0x%x, "
1116c0dd49bdSEiji Ota 	    "max_recv_wr: 0x%x, max_send_sge: 0x%x, max_recv_sge: 0x%x, "
1117c0dd49bdSEiji Ota 	    "max_inline_data: 0x%x, sq_sig_type: %d, qp_type: %d, "
1118c0dd49bdSEiji Ota 	    "port_num: %d",
1119c0dd49bdSEiji Ota 	    pd, qp_init_attr->event_handler, qp_init_attr->qp_context,
1120c0dd49bdSEiji Ota 	    qp_init_attr->send_cq, qp_init_attr->recv_cq, qp_init_attr->srq,
1121c0dd49bdSEiji Ota 	    qp_init_attr->cap.max_send_wr, qp_init_attr->cap.max_recv_wr,
1122c0dd49bdSEiji Ota 	    qp_init_attr->cap.max_send_sge, qp_init_attr->cap.max_recv_sge,
1123c0dd49bdSEiji Ota 	    qp_init_attr->cap.max_inline_data, qp_init_attr->sq_sig_type,
1124c0dd49bdSEiji Ota 	    qp_init_attr->qp_type, qp_init_attr->port_num);
1125c0dd49bdSEiji Ota 
1126c0dd49bdSEiji Ota 	attrs.qp_alloc_flags = IBT_QP_NO_FLAGS;
1127c0dd49bdSEiji Ota 	if (qp_init_attr->srq) {
1128c0dd49bdSEiji Ota 		attrs.qp_alloc_flags |= IBT_QP_USES_SRQ;
1129c0dd49bdSEiji Ota 	}
1130c0dd49bdSEiji Ota 
1131c0dd49bdSEiji Ota 	attrs.qp_flags = IBT_ALL_SIGNALED | IBT_FAST_REG_RES_LKEY;
1132c0dd49bdSEiji Ota 	if (qp_init_attr->sq_sig_type == IB_SIGNAL_REQ_WR) {
1133c0dd49bdSEiji Ota 		attrs.qp_flags |= IBT_WR_SIGNALED;
1134c0dd49bdSEiji Ota 	}
1135c0dd49bdSEiji Ota 
1136c0dd49bdSEiji Ota 	attrs.qp_scq_hdl = qp_init_attr->send_cq->ibt_cq;
1137c0dd49bdSEiji Ota 	attrs.qp_rcq_hdl = qp_init_attr->recv_cq->ibt_cq;
1138c0dd49bdSEiji Ota 	attrs.qp_pd_hdl = pd->ibt_pd;
1139c0dd49bdSEiji Ota 
1140c0dd49bdSEiji Ota 	attrs.qp_sizes.cs_sq = qp_init_attr->cap.max_send_wr;
1141c0dd49bdSEiji Ota 	attrs.qp_sizes.cs_rq = qp_init_attr->cap.max_recv_wr;
1142c0dd49bdSEiji Ota 	attrs.qp_sizes.cs_sq_sgl = qp_init_attr->cap.max_send_sge;
1143c0dd49bdSEiji Ota 	attrs.qp_sizes.cs_rq_sgl = qp_init_attr->cap.max_recv_sge;
1144c0dd49bdSEiji Ota 	attrs.qp_sizes.cs_inline = qp_init_attr->cap.max_inline_data;
1145c0dd49bdSEiji Ota 
1146c0dd49bdSEiji Ota 	switch (qp_init_attr->qp_type) {
1147c0dd49bdSEiji Ota 	case IB_QPT_RC:
1148c0dd49bdSEiji Ota 		rtn = ibt_alloc_qp(pd->device->hca_hdl, IBT_RC_RQP, &attrs,
1149c0dd49bdSEiji Ota 		    &sizes, &qpn, &ibt_qp);
1150c0dd49bdSEiji Ota 		break;
1151c0dd49bdSEiji Ota 	case IB_QPT_UD:
1152c0dd49bdSEiji Ota 		rtn = ibt_alloc_qp(pd->device->hca_hdl, IBT_UD_RQP, &attrs,
1153c0dd49bdSEiji Ota 		    &sizes, &qpn, &ibt_qp);
1154c0dd49bdSEiji Ota 		break;
1155c0dd49bdSEiji Ota 	case IB_QPT_SMI:
1156c0dd49bdSEiji Ota 		rtn = ibt_alloc_special_qp(pd->device->hca_hdl,
1157c0dd49bdSEiji Ota 		    qp_init_attr->port_num, IBT_SMI_SQP, &attrs, &sizes,
1158c0dd49bdSEiji Ota 		    &ibt_qp);
1159c0dd49bdSEiji Ota 		break;
1160c0dd49bdSEiji Ota 	case IB_QPT_GSI:
1161c0dd49bdSEiji Ota 		rtn = ibt_alloc_special_qp(pd->device->hca_hdl,
1162c0dd49bdSEiji Ota 		    qp_init_attr->port_num, IBT_GSI_SQP, &attrs, &sizes,
1163c0dd49bdSEiji Ota 		    &ibt_qp);
1164c0dd49bdSEiji Ota 		break;
1165c0dd49bdSEiji Ota 	default:
1166c0dd49bdSEiji Ota 		/* this should never happens */
1167c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1168c0dd49bdSEiji Ota 		kmem_free(qp, sizeof (struct ib_qp));
1169c0dd49bdSEiji Ota 		return ((struct ib_qp *)-EINVAL);
1170c0dd49bdSEiji Ota 	}
1171c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
1172c0dd49bdSEiji Ota 
1173c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
1174c0dd49bdSEiji Ota 		/* fill in ib_qp_cap w/ the real values */
1175c0dd49bdSEiji Ota 		qp_init_attr->cap.max_send_wr = sizes.cs_sq;
1176c0dd49bdSEiji Ota 		qp_init_attr->cap.max_recv_wr = sizes.cs_rq;
1177c0dd49bdSEiji Ota 		qp_init_attr->cap.max_send_sge = sizes.cs_sq_sgl;
1178c0dd49bdSEiji Ota 		qp_init_attr->cap.max_recv_sge = sizes.cs_rq_sgl;
1179c0dd49bdSEiji Ota 		/* max_inline_data is not supported */
1180c0dd49bdSEiji Ota 		qp_init_attr->cap.max_inline_data = 0;
1181c0dd49bdSEiji Ota 		/* fill in ib_qp */
1182c0dd49bdSEiji Ota 		qp->device = pd->device;
1183c0dd49bdSEiji Ota 		qp->pd = pd;
1184c0dd49bdSEiji Ota 		qp->send_cq = qp_init_attr->send_cq;
1185c0dd49bdSEiji Ota 		qp->recv_cq = qp_init_attr->recv_cq;
1186c0dd49bdSEiji Ota 		qp->srq = qp_init_attr->srq;
1187c0dd49bdSEiji Ota 		qp->event_handler = qp_init_attr->event_handler;
1188c0dd49bdSEiji Ota 		qp->qp_context = qp_init_attr->qp_context;
1189c0dd49bdSEiji Ota 		qp->qp_num = qp_init_attr->qp_type == IB_QPT_SMI ? 0 :
1190c0dd49bdSEiji Ota 		    qp_init_attr->qp_type == IB_QPT_GSI ? 1 : qpn;
1191c0dd49bdSEiji Ota 		qp->qp_type = qp_init_attr->qp_type;
1192c0dd49bdSEiji Ota 		qp->ibt_qp = ibt_qp;
1193c0dd49bdSEiji Ota 		ibt_set_qp_private(qp->ibt_qp, qp);
1194c0dd49bdSEiji Ota 		mutex_init(&qp->lock, NULL, MUTEX_DEFAULT, NULL);
1195c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1196c0dd49bdSEiji Ota 		    "ib_create_qp: device: 0x%p, pd: 0x%x, init_attr: 0x%p, "
1197c0dd49bdSEiji Ota 		    "rtn: 0x%x", pd->device, pd, qp_init_attr, rtn);
1198c0dd49bdSEiji Ota 		return (qp);
1199c0dd49bdSEiji Ota 	}
1200c0dd49bdSEiji Ota 	kmem_free(qp, sizeof (struct ib_qp));
1201c0dd49bdSEiji Ota 
1202c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1203c0dd49bdSEiji Ota 	    "ib_create_qp: device: 0x%p, pd: 0x%x, init_attr: 0x%p => "
1204c0dd49bdSEiji Ota 	    "ibt_alloc_(special)_qp failed w/ rtn: 0x%x", pd->device, pd,
1205c0dd49bdSEiji Ota 	    qp_init_attr, rtn);
1206c0dd49bdSEiji Ota 
1207c0dd49bdSEiji Ota 	switch (rtn) {
1208c0dd49bdSEiji Ota 	case IBT_NOT_SUPPORTED:
1209c0dd49bdSEiji Ota 	case IBT_QP_SRV_TYPE_INVALID:
1210c0dd49bdSEiji Ota 	case IBT_CQ_HDL_INVALID:
1211c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
1212c0dd49bdSEiji Ota 	case IBT_INVALID_PARAM:
1213c0dd49bdSEiji Ota 	case IBT_SRQ_HDL_INVALID:
1214c0dd49bdSEiji Ota 	case IBT_PD_HDL_INVALID:
1215c0dd49bdSEiji Ota 	case IBT_HCA_SGL_EXCEEDED:
1216c0dd49bdSEiji Ota 	case IBT_HCA_WR_EXCEEDED:
1217c0dd49bdSEiji Ota 		return ((struct ib_qp *)-EINVAL);
1218c0dd49bdSEiji Ota 	case IBT_INSUFF_RESOURCE:
1219c0dd49bdSEiji Ota 		return ((struct ib_qp *)-ENOMEM);
1220c0dd49bdSEiji Ota 	default:
1221c0dd49bdSEiji Ota 		return ((struct ib_qp *)-EIO);
1222c0dd49bdSEiji Ota 	}
1223c0dd49bdSEiji Ota }
1224c0dd49bdSEiji Ota 
1225c0dd49bdSEiji Ota int
ib_destroy_qp(struct ib_qp * qp)1226c0dd49bdSEiji Ota ib_destroy_qp(struct ib_qp *qp)
1227c0dd49bdSEiji Ota {
1228c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client = (ofs_client_t *)qp->device->clnt_hdl;
1229c0dd49bdSEiji Ota 	int		rtn;
1230c0dd49bdSEiji Ota 
1231c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
1232c0dd49bdSEiji Ota 	if (qp->device->reg_state != IB_DEV_OPEN) {
1233c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1234c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1235c0dd49bdSEiji Ota 		    "ib_destroy_qp: qp: 0x%p => invalid device state (%d)",
1236c0dd49bdSEiji Ota 		    qp, qp->device->reg_state);
1237c0dd49bdSEiji Ota 		return (-ENXIO);
1238c0dd49bdSEiji Ota 	}
1239c0dd49bdSEiji Ota 
1240c0dd49bdSEiji Ota 	/*
1241c0dd49bdSEiji Ota 	 * if IBTL_ASYNC_PENDING is set, ibt_qp is not freed
1242c0dd49bdSEiji Ota 	 * at this moment, but yet alive for a while. Then
1243c0dd49bdSEiji Ota 	 * there is a possibility that this qp is used even after
1244c0dd49bdSEiji Ota 	 * ib_destroy_qp() is called. To distinguish this case from
1245c0dd49bdSEiji Ota 	 * others, clear ibt_qp here.
1246c0dd49bdSEiji Ota 	 */
1247c0dd49bdSEiji Ota 	ibt_set_qp_private(qp->ibt_qp, NULL);
1248c0dd49bdSEiji Ota 
1249c0dd49bdSEiji Ota 	rtn = ibt_free_qp(qp->ibt_qp);
1250c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
1251c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1252c0dd49bdSEiji Ota 		kmem_free(qp, sizeof (struct ib_qp));
1253c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1254c0dd49bdSEiji Ota 		    "ib_destroy_qp: qp: 0x%p, rtn: 0x%x", qp, rtn);
1255c0dd49bdSEiji Ota 		return (0);
1256c0dd49bdSEiji Ota 	}
1257c0dd49bdSEiji Ota 	ibt_set_qp_private(qp->ibt_qp, qp);
1258c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
1259c0dd49bdSEiji Ota 
1260c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1261c0dd49bdSEiji Ota 	    "ib_destroy_qp: qp: 0x%p => ibt_free_qp failed w/ 0x%x", qp, rtn);
1262c0dd49bdSEiji Ota 
1263c0dd49bdSEiji Ota 	switch (rtn) {
1264c0dd49bdSEiji Ota 	case IBT_CHAN_STATE_INVALID:
1265c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
1266c0dd49bdSEiji Ota 	case IBT_QP_HDL_INVALID:
1267c0dd49bdSEiji Ota 		return (-EINVAL);
1268c0dd49bdSEiji Ota 	default:
1269c0dd49bdSEiji Ota 		return (-EIO);
1270c0dd49bdSEiji Ota 	}
1271c0dd49bdSEiji Ota }
1272c0dd49bdSEiji Ota 
1273c0dd49bdSEiji Ota /*
1274c0dd49bdSEiji Ota  * ib_req_notify_cq - Request completion notification on a CQ.
1275c0dd49bdSEiji Ota  * @cq: The CQ to generate an event for.
1276c0dd49bdSEiji Ota  * @flags:
1277c0dd49bdSEiji Ota  *   Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP
1278c0dd49bdSEiji Ota  *   to request an event on the next solicited event or next work
1279c0dd49bdSEiji Ota  *   completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS
1280c0dd49bdSEiji Ota  *   may also be |ed in to request a hint about missed events, as
1281c0dd49bdSEiji Ota  *   described below.
1282c0dd49bdSEiji Ota  *
1283c0dd49bdSEiji Ota  * Return Value:
1284c0dd49bdSEiji Ota  *    < 0 means an error occurred while requesting notification
1285c0dd49bdSEiji Ota  *   == 0 means notification was requested successfully, and if
1286c0dd49bdSEiji Ota  *        IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events
1287c0dd49bdSEiji Ota  *        were missed and it is safe to wait for another event.  In
1288c0dd49bdSEiji Ota  *        this case is it guaranteed that any work completions added
1289c0dd49bdSEiji Ota  *        to the CQ since the last CQ poll will trigger a completion
1290c0dd49bdSEiji Ota  *        notification event.
1291c0dd49bdSEiji Ota  *    > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed
1292c0dd49bdSEiji Ota  *        in.  It means that the consumer must poll the CQ again to
1293c0dd49bdSEiji Ota  *        make sure it is empty to avoid missing an event because of a
1294c0dd49bdSEiji Ota  *        race between requesting notification and an entry being
1295c0dd49bdSEiji Ota  *        added to the CQ.  This return value means it is possible
1296c0dd49bdSEiji Ota  *        (but not guaranteed) that a work completion has been added
1297c0dd49bdSEiji Ota  *        to the CQ since the last poll without triggering a
1298c0dd49bdSEiji Ota  *        completion notification event.
1299c0dd49bdSEiji Ota  *
1300c0dd49bdSEiji Ota  * Note that IB_CQ_REPORT_MISSED_EVENTS is currently not supported.
1301c0dd49bdSEiji Ota  */
1302c0dd49bdSEiji Ota int
ib_req_notify_cq(struct ib_cq * cq,enum ib_cq_notify_flags flags)1303c0dd49bdSEiji Ota ib_req_notify_cq(struct ib_cq *cq, enum ib_cq_notify_flags flags)
1304c0dd49bdSEiji Ota {
1305c0dd49bdSEiji Ota 	ibt_cq_notify_flags_t	notify_type;
1306c0dd49bdSEiji Ota 	int			rtn;
1307c0dd49bdSEiji Ota 	ofs_client_t		*ofs_client = cq->device->clnt_hdl;
1308c0dd49bdSEiji Ota 
1309c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
1310c0dd49bdSEiji Ota 	if (cq->device->reg_state != IB_DEV_OPEN) {
1311c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1312c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1313c0dd49bdSEiji Ota 		    "ib_req_notify_cq: cq: 0x%p, flag: 0x%x", cq, flags);
1314c0dd49bdSEiji Ota 		return (-ENXIO);
1315c0dd49bdSEiji Ota 	}
1316c0dd49bdSEiji Ota 
1317c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1318c0dd49bdSEiji Ota 	    "ib_req_notify_cq: cq: 0x%p, flag: 0x%x", cq, flags);
1319c0dd49bdSEiji Ota 
1320c0dd49bdSEiji Ota 	switch (flags & IB_CQ_SOLICITED_MASK) {
1321c0dd49bdSEiji Ota 	case IB_CQ_SOLICITED:
1322c0dd49bdSEiji Ota 		notify_type = IBT_NEXT_SOLICITED;
1323c0dd49bdSEiji Ota 		break;
1324c0dd49bdSEiji Ota 	case IB_CQ_NEXT_COMP:
1325c0dd49bdSEiji Ota 		notify_type = IBT_NEXT_COMPLETION;
1326c0dd49bdSEiji Ota 		break;
1327c0dd49bdSEiji Ota 	default:
1328c0dd49bdSEiji Ota 		/* Currently only two flags are supported */
1329c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1330c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1331c0dd49bdSEiji Ota 		    "ib_req_notify_cq: cq: 0x%p, flag: 0x%x => invalid flag",
1332c0dd49bdSEiji Ota 		    cq, flags);
1333c0dd49bdSEiji Ota 		return (-EINVAL);
1334c0dd49bdSEiji Ota 	}
1335c0dd49bdSEiji Ota 
1336c0dd49bdSEiji Ota 	rtn = ibt_enable_cq_notify(cq->ibt_cq, notify_type);
1337c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
1338c0dd49bdSEiji Ota 
1339c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
1340c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
1341c0dd49bdSEiji Ota 		    "ib_req_notify_cq: cq: 0x%p, flag: 0x%x rtn: 0x%x",
1342c0dd49bdSEiji Ota 		    cq, flags, rtn);
1343c0dd49bdSEiji Ota 		return (0);
1344c0dd49bdSEiji Ota 	}
1345c0dd49bdSEiji Ota 
1346c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1347c0dd49bdSEiji Ota 	    "ib_req_notify_cq: cq: 0x%p, flag: 0x%x => ibt_enable_cq_notify "
1348c0dd49bdSEiji Ota 	    "failed w/ 0x%x", cq, flags, rtn);
1349c0dd49bdSEiji Ota 
1350c0dd49bdSEiji Ota 	switch (rtn) {
1351c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
1352c0dd49bdSEiji Ota 	case IBT_CQ_HDL_INVALID:
1353c0dd49bdSEiji Ota 	case IBT_CQ_NOTIFY_TYPE_INVALID:
1354c0dd49bdSEiji Ota 		return (-EINVAL);
1355c0dd49bdSEiji Ota 	default:
1356c0dd49bdSEiji Ota 		return (-EIO);
1357c0dd49bdSEiji Ota 	}
1358c0dd49bdSEiji Ota }
1359c0dd49bdSEiji Ota 
1360c0dd49bdSEiji Ota static const struct {
1361c0dd49bdSEiji Ota 	int			valid;
1362c0dd49bdSEiji Ota 	enum ib_qp_attr_mask	req_param[IB_QPT_RAW_ETY + 1];
1363c0dd49bdSEiji Ota 	enum ib_qp_attr_mask	opt_param[IB_QPT_RAW_ETY + 1];
1364c0dd49bdSEiji Ota } qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
1365c0dd49bdSEiji Ota 
1366c0dd49bdSEiji Ota 	[IB_QPS_RESET] = {
1367c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1368c0dd49bdSEiji Ota 		[IB_QPS_INIT]  = {
1369c0dd49bdSEiji Ota 			.valid = 1,
1370c0dd49bdSEiji Ota 			.req_param = {
1371c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
1372c0dd49bdSEiji Ota 				    IB_QP_QKEY),
1373c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
1374c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS),
1375c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
1376c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS),
1377c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1378c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1379c0dd49bdSEiji Ota 			}
1380c0dd49bdSEiji Ota 		},
1381c0dd49bdSEiji Ota 	},
1382c0dd49bdSEiji Ota 	[IB_QPS_INIT]  = {
1383c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1384c0dd49bdSEiji Ota 		[IB_QPS_ERR] =   { .valid = 1 },
1385c0dd49bdSEiji Ota 		[IB_QPS_INIT]  = {
1386c0dd49bdSEiji Ota 			.valid = 1,
1387c0dd49bdSEiji Ota 			.opt_param = {
1388c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
1389c0dd49bdSEiji Ota 				    IB_QP_QKEY),
1390c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
1391c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS),
1392c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
1393c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS),
1394c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1395c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1396c0dd49bdSEiji Ota 			}
1397c0dd49bdSEiji Ota 		},
1398c0dd49bdSEiji Ota 		[IB_QPS_RTR]   = {
1399c0dd49bdSEiji Ota 			.valid = 1,
1400c0dd49bdSEiji Ota 			.req_param = {
1401c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_AV | IB_QP_PATH_MTU |
1402c0dd49bdSEiji Ota 				    IB_QP_DEST_QPN | IB_QP_RQ_PSN),
1403c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_AV | IB_QP_PATH_MTU |
1404c0dd49bdSEiji Ota 				    IB_QP_DEST_QPN | IB_QP_RQ_PSN |
1405c0dd49bdSEiji Ota 				    IB_QP_MAX_DEST_RD_ATOMIC |
1406c0dd49bdSEiji Ota 				    IB_QP_MIN_RNR_TIMER),
1407c0dd49bdSEiji Ota 			},
1408c0dd49bdSEiji Ota 			.opt_param = {
1409c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1410c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_ALT_PATH |
1411c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX),
1412c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_ALT_PATH |
1413c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX),
1414c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1415c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1416c0dd49bdSEiji Ota 			}
1417c0dd49bdSEiji Ota 		}
1418c0dd49bdSEiji Ota 	},
1419c0dd49bdSEiji Ota 	[IB_QPS_RTR]   = {
1420c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1421c0dd49bdSEiji Ota 		[IB_QPS_ERR] =   { .valid = 1 },
1422c0dd49bdSEiji Ota 		[IB_QPS_RTS]   = {
1423c0dd49bdSEiji Ota 			.valid = 1,
1424c0dd49bdSEiji Ota 			.req_param = {
1425c0dd49bdSEiji Ota 				[IB_QPT_UD] = IB_QP_SQ_PSN,
1426c0dd49bdSEiji Ota 				[IB_QPT_UC] = IB_QP_SQ_PSN,
1427c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_TIMEOUT |
1428c0dd49bdSEiji Ota 				    IB_QP_RETRY_CNT | IB_QP_RNR_RETRY |
1429c0dd49bdSEiji Ota 				    IB_QP_SQ_PSN | IB_QP_MAX_QP_RD_ATOMIC),
1430c0dd49bdSEiji Ota 				[IB_QPT_SMI] = IB_QP_SQ_PSN,
1431c0dd49bdSEiji Ota 				[IB_QPT_GSI] = IB_QP_SQ_PSN,
1432c0dd49bdSEiji Ota 			},
1433c0dd49bdSEiji Ota 			.opt_param = {
1434c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1435c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
1436c0dd49bdSEiji Ota 				    IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
1437c0dd49bdSEiji Ota 				    IB_QP_PATH_MIG_STATE),
1438c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_CUR_STATE |
1439c0dd49bdSEiji Ota 				    IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS	|
1440c0dd49bdSEiji Ota 				    IB_QP_MIN_RNR_TIMER | IB_QP_PATH_MIG_STATE),
1441c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1442c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1443c0dd49bdSEiji Ota 			}
1444c0dd49bdSEiji Ota 		}
1445c0dd49bdSEiji Ota 	},
1446c0dd49bdSEiji Ota 	[IB_QPS_RTS] = {
1447c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1448c0dd49bdSEiji Ota 		[IB_QPS_ERR] =  { .valid = 1 },
1449c0dd49bdSEiji Ota 		[IB_QPS_RTS] = {
1450c0dd49bdSEiji Ota 			.valid = 1,
1451c0dd49bdSEiji Ota 			.opt_param = {
1452c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1453c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_CUR_STATE	|
1454c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS | IB_QP_ALT_PATH |
1455c0dd49bdSEiji Ota 				    IB_QP_PATH_MIG_STATE),
1456c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_CUR_STATE	|
1457c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS | IB_QP_ALT_PATH |
1458c0dd49bdSEiji Ota 				    IB_QP_PATH_MIG_STATE | IB_QP_MIN_RNR_TIMER),
1459c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1460c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_CUR_STATE	| IB_QP_QKEY),
1461c0dd49bdSEiji Ota 			}
1462c0dd49bdSEiji Ota 		},
1463c0dd49bdSEiji Ota 		[IB_QPS_SQD] = {
1464c0dd49bdSEiji Ota 			.valid = 1,
1465c0dd49bdSEiji Ota 			.opt_param = {
1466c0dd49bdSEiji Ota 				[IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY,
1467c0dd49bdSEiji Ota 				[IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
1468c0dd49bdSEiji Ota 				[IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
1469c0dd49bdSEiji Ota 				[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
1470c0dd49bdSEiji Ota 				[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
1471c0dd49bdSEiji Ota 			}
1472c0dd49bdSEiji Ota 		},
1473c0dd49bdSEiji Ota 	},
1474c0dd49bdSEiji Ota 	[IB_QPS_SQD] = {
1475c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1476c0dd49bdSEiji Ota 		[IB_QPS_ERR] = { .valid = 1 },
1477c0dd49bdSEiji Ota 		[IB_QPS_RTS] = {
1478c0dd49bdSEiji Ota 			.valid = 1,
1479c0dd49bdSEiji Ota 			.opt_param = {
1480c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1481c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
1482c0dd49bdSEiji Ota 				    IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
1483c0dd49bdSEiji Ota 				    IB_QP_PATH_MIG_STATE),
1484c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_CUR_STATE |
1485c0dd49bdSEiji Ota 				    IB_QP_ALT_PATH | IB_QP_ACCESS_FLAGS |
1486c0dd49bdSEiji Ota 				    IB_QP_MIN_RNR_TIMER	| IB_QP_PATH_MIG_STATE),
1487c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_CUR_STATE	| IB_QP_QKEY),
1488c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_CUR_STATE	| IB_QP_QKEY),
1489c0dd49bdSEiji Ota 			}
1490c0dd49bdSEiji Ota 		},
1491c0dd49bdSEiji Ota 		[IB_QPS_SQD] = {
1492c0dd49bdSEiji Ota 			.valid = 1,
1493c0dd49bdSEiji Ota 			.opt_param = {
1494c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_PKEY_INDEX	| IB_QP_QKEY),
1495c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_AV | IB_QP_ALT_PATH |
1496c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX |
1497c0dd49bdSEiji Ota 				    IB_QP_PATH_MIG_STATE),
1498c0dd49bdSEiji Ota 				[IB_QPT_RC] = (IB_QP_PORT | IB_QP_AV |
1499c0dd49bdSEiji Ota 				    IB_QP_TIMEOUT | IB_QP_RETRY_CNT |
1500c0dd49bdSEiji Ota 				    IB_QP_RNR_RETRY | IB_QP_MAX_QP_RD_ATOMIC |
1501c0dd49bdSEiji Ota 				    IB_QP_MAX_DEST_RD_ATOMIC | IB_QP_ALT_PATH |
1502c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS | IB_QP_PKEY_INDEX |
1503c0dd49bdSEiji Ota 				    IB_QP_MIN_RNR_TIMER	| IB_QP_PATH_MIG_STATE),
1504c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1505c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
1506c0dd49bdSEiji Ota 			}
1507c0dd49bdSEiji Ota 		}
1508c0dd49bdSEiji Ota 	},
1509c0dd49bdSEiji Ota 	[IB_QPS_SQE]  = {
1510c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1511c0dd49bdSEiji Ota 		[IB_QPS_ERR] = { .valid = 1 },
1512c0dd49bdSEiji Ota 		[IB_QPS_RTS] = {
1513c0dd49bdSEiji Ota 			.valid = 1,
1514c0dd49bdSEiji Ota 			.opt_param = {
1515c0dd49bdSEiji Ota 				[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1516c0dd49bdSEiji Ota 				[IB_QPT_UC] = (IB_QP_CUR_STATE |
1517c0dd49bdSEiji Ota 				    IB_QP_ACCESS_FLAGS),
1518c0dd49bdSEiji Ota 				[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
1519c0dd49bdSEiji Ota 				[IB_QPT_GSI] = (IB_QP_CUR_STATE	| IB_QP_QKEY),
1520c0dd49bdSEiji Ota 			}
1521c0dd49bdSEiji Ota 		}
1522c0dd49bdSEiji Ota 	},
1523c0dd49bdSEiji Ota 	[IB_QPS_ERR] = {
1524c0dd49bdSEiji Ota 		[IB_QPS_RESET] = { .valid = 1 },
1525c0dd49bdSEiji Ota 		[IB_QPS_ERR] =  { .valid = 1 }
1526c0dd49bdSEiji Ota 	}
1527c0dd49bdSEiji Ota };
1528c0dd49bdSEiji Ota 
1529c0dd49bdSEiji Ota static inline int
ib_modify_qp_is_ok(enum ib_qp_state cur_state,enum ib_qp_state next_state,enum ib_qp_type type,enum ib_qp_attr_mask mask)1530c0dd49bdSEiji Ota ib_modify_qp_is_ok(enum ib_qp_state cur_state, enum ib_qp_state next_state,
1531c0dd49bdSEiji Ota     enum ib_qp_type type, enum ib_qp_attr_mask mask)
1532c0dd49bdSEiji Ota {
1533c0dd49bdSEiji Ota 	enum ib_qp_attr_mask req_param, opt_param;
1534c0dd49bdSEiji Ota 
1535c0dd49bdSEiji Ota 	if (cur_state  < 0 || cur_state  > IB_QPS_ERR ||
1536c0dd49bdSEiji Ota 	    next_state < 0 || next_state > IB_QPS_ERR) {
1537c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1538c0dd49bdSEiji Ota 		    "ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
1539c0dd49bdSEiji Ota 		    "qp_type: %d, attr_mask: 0x%x => invalid state(1)",
1540c0dd49bdSEiji Ota 		    cur_state, next_state, type, mask);
1541c0dd49bdSEiji Ota 		return (0);
1542c0dd49bdSEiji Ota 	}
1543c0dd49bdSEiji Ota 
1544c0dd49bdSEiji Ota 	if (mask & IB_QP_CUR_STATE &&
1545c0dd49bdSEiji Ota 	    cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
1546c0dd49bdSEiji Ota 	    cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE) {
1547c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1548c0dd49bdSEiji Ota 		    "ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
1549c0dd49bdSEiji Ota 		    "qp_type: %d, attr_mask: 0x%x => invalid state(2)",
1550c0dd49bdSEiji Ota 		    cur_state, next_state, type, mask);
1551c0dd49bdSEiji Ota 		return (0);
1552c0dd49bdSEiji Ota 	}
1553c0dd49bdSEiji Ota 
1554c0dd49bdSEiji Ota 	if (!qp_state_table[cur_state][next_state].valid) {
1555c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1556c0dd49bdSEiji Ota 		    "ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
1557c0dd49bdSEiji Ota 		    "qp_type: %d, attr_mask: 0x%x => state is not valid",
1558c0dd49bdSEiji Ota 		    cur_state, next_state, type, mask);
1559c0dd49bdSEiji Ota 		return (0);
1560c0dd49bdSEiji Ota 	}
1561c0dd49bdSEiji Ota 
1562c0dd49bdSEiji Ota 	req_param = qp_state_table[cur_state][next_state].req_param[type];
1563c0dd49bdSEiji Ota 	opt_param = qp_state_table[cur_state][next_state].opt_param[type];
1564c0dd49bdSEiji Ota 
1565c0dd49bdSEiji Ota 	if ((mask & req_param) != req_param) {
1566c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1567c0dd49bdSEiji Ota 		    "ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
1568c0dd49bdSEiji Ota 		    "qp_type: %d, attr_mask: 0x%x => "
1569c0dd49bdSEiji Ota 		    "required param doesn't match. req_param = 0x%x",
1570c0dd49bdSEiji Ota 		    cur_state, next_state, type, mask, req_param);
1571c0dd49bdSEiji Ota 		return (0);
1572c0dd49bdSEiji Ota 	}
1573c0dd49bdSEiji Ota 
1574c0dd49bdSEiji Ota 	if (mask & ~(req_param | opt_param | IB_QP_STATE)) {
1575c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1576c0dd49bdSEiji Ota 		    "ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
1577c0dd49bdSEiji Ota 		    "qp_type: %d, attr_mask: 0x%x => "
1578c0dd49bdSEiji Ota 		    "unsupported options. req_param = 0x%x, opt_param = 0x%x",
1579c0dd49bdSEiji Ota 		    cur_state, next_state, type, mask, req_param, opt_param);
1580c0dd49bdSEiji Ota 		return (0);
1581c0dd49bdSEiji Ota 	}
1582c0dd49bdSEiji Ota 
1583c0dd49bdSEiji Ota 	return (1);
1584c0dd49bdSEiji Ota }
1585c0dd49bdSEiji Ota 
1586c0dd49bdSEiji Ota static inline enum ib_qp_state
qp_current_state(ibt_qp_query_attr_t * qp_attr)1587c0dd49bdSEiji Ota qp_current_state(ibt_qp_query_attr_t *qp_attr)
1588c0dd49bdSEiji Ota {
1589c0dd49bdSEiji Ota 	ASSERT(qp_attr->qp_info.qp_state != IBT_STATE_SQDRAIN);
1590c0dd49bdSEiji Ota 	return (enum ib_qp_state)(qp_attr->qp_info.qp_state);
1591c0dd49bdSEiji Ota }
1592c0dd49bdSEiji Ota 
1593c0dd49bdSEiji Ota static inline ibt_tran_srv_t
of2ibtf_qp_type(enum ib_qp_type type)1594c0dd49bdSEiji Ota of2ibtf_qp_type(enum ib_qp_type type)
1595c0dd49bdSEiji Ota {
1596c0dd49bdSEiji Ota 	switch (type) {
1597c0dd49bdSEiji Ota 	case IB_QPT_SMI:
1598c0dd49bdSEiji Ota 	case IB_QPT_GSI:
1599c0dd49bdSEiji Ota 	case IB_QPT_UD:
1600c0dd49bdSEiji Ota 		return (IBT_UD_SRV);
1601c0dd49bdSEiji Ota 	case IB_QPT_RC:
1602c0dd49bdSEiji Ota 		return (IBT_RC_SRV);
1603c0dd49bdSEiji Ota 	case IB_QPT_UC:
1604c0dd49bdSEiji Ota 		return (IBT_UC_SRV);
1605c0dd49bdSEiji Ota 	case IB_QPT_RAW_IPV6:
1606c0dd49bdSEiji Ota 		return (IBT_RAWIP_SRV);
1607c0dd49bdSEiji Ota 	case IB_QPT_RAW_ETY:
1608c0dd49bdSEiji Ota 	default:
1609c0dd49bdSEiji Ota 		ASSERT(type == IB_QPT_RAW_ETY);
1610c0dd49bdSEiji Ota 		return (IBT_RAWETHER_SRV);
1611c0dd49bdSEiji Ota 	}
1612c0dd49bdSEiji Ota }
1613c0dd49bdSEiji Ota 
1614c0dd49bdSEiji Ota static inline void
set_av(struct ib_ah_attr * attr,ibt_cep_path_t * pathp)1615c0dd49bdSEiji Ota set_av(struct ib_ah_attr *attr, ibt_cep_path_t *pathp)
1616c0dd49bdSEiji Ota {
1617c0dd49bdSEiji Ota 	ibt_adds_vect_t		*av = &pathp->cep_adds_vect;
1618c0dd49bdSEiji Ota 
1619c0dd49bdSEiji Ota 	pathp->cep_hca_port_num = attr->port_num;
1620c0dd49bdSEiji Ota 	av->av_srate = OF2IBTF_SRATE(attr->static_rate);
1621c0dd49bdSEiji Ota 	av->av_srvl = attr->sl & 0xF;
1622c0dd49bdSEiji Ota 	av->av_send_grh = attr->ah_flags & IB_AH_GRH ? 1 : 0;
1623c0dd49bdSEiji Ota 
1624c0dd49bdSEiji Ota 	if (av->av_send_grh) {
1625c0dd49bdSEiji Ota 		av->av_dgid.gid_prefix =
1626c0dd49bdSEiji Ota 		    attr->grh.dgid.global.subnet_prefix;
1627c0dd49bdSEiji Ota 		av->av_dgid.gid_guid =
1628c0dd49bdSEiji Ota 		    attr->grh.dgid.global.interface_id;
1629c0dd49bdSEiji Ota 		av->av_flow = attr->grh.flow_label & 0xFFFFF;
1630c0dd49bdSEiji Ota 		av->av_tclass = attr->grh.traffic_class;
1631c0dd49bdSEiji Ota 		av->av_hop = attr->grh.hop_limit;
1632c0dd49bdSEiji Ota 		av->av_sgid_ix = attr->grh.sgid_index;
1633c0dd49bdSEiji Ota 	}
1634c0dd49bdSEiji Ota 	av->av_dlid = attr->dlid;
1635c0dd49bdSEiji Ota 	av->av_src_path = attr->src_path_bits;
1636c0dd49bdSEiji Ota }
1637c0dd49bdSEiji Ota 
1638c0dd49bdSEiji Ota int
ib_modify_qp(struct ib_qp * qp,struct ib_qp_attr * attr,int attr_mask)1639c0dd49bdSEiji Ota ib_modify_qp(struct ib_qp *qp, struct ib_qp_attr *attr, int attr_mask)
1640c0dd49bdSEiji Ota {
1641c0dd49bdSEiji Ota 	enum ib_qp_state	cur_state, new_state;
1642c0dd49bdSEiji Ota 	ibt_hca_attr_t		hattr;
1643c0dd49bdSEiji Ota 	ibt_qp_query_attr_t	qp_attr;
1644c0dd49bdSEiji Ota 	ibt_qp_info_t		modify_attr;
1645c0dd49bdSEiji Ota 	ibt_cep_modify_flags_t	flags;
1646c0dd49bdSEiji Ota 	int			rtn;
1647c0dd49bdSEiji Ota 	ofs_client_t		*ofs_client = qp->device->clnt_hdl;
1648c0dd49bdSEiji Ota 
1649c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
1650c0dd49bdSEiji Ota 	if (qp->device->reg_state != IB_DEV_OPEN) {
1651c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1652c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1653c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p => invalid device state (%d)",
1654c0dd49bdSEiji Ota 		    qp, qp->device->reg_state);
1655c0dd49bdSEiji Ota 		return (-ENXIO);
1656c0dd49bdSEiji Ota 	}
1657c0dd49bdSEiji Ota 
1658c0dd49bdSEiji Ota 	rtn = ibt_query_hca(qp->device->hca_hdl, &hattr);
1659c0dd49bdSEiji Ota 	if (rtn != IBT_SUCCESS) {
1660c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1661c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1662c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, hca_hdl: 0x%p => "
1663c0dd49bdSEiji Ota 		    "ibt_query_hca() failed w/ %d",
1664c0dd49bdSEiji Ota 		    qp, qp->device->hca_hdl, rtn);
1665c0dd49bdSEiji Ota 		return (-EIO);
1666c0dd49bdSEiji Ota 	}
1667c0dd49bdSEiji Ota 
1668c0dd49bdSEiji Ota 	/* only one thread per qp is allowed during the qp modification */
1669c0dd49bdSEiji Ota 	mutex_enter(&qp->lock);
1670c0dd49bdSEiji Ota 
1671c0dd49bdSEiji Ota 	/* Get the current QP attributes first */
1672c0dd49bdSEiji Ota 	bzero(&qp_attr, sizeof (ibt_qp_query_attr_t));
1673c0dd49bdSEiji Ota 	if ((rtn = ibt_query_qp(qp->ibt_qp, &qp_attr)) != IBT_SUCCESS) {
1674c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1675c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1676c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1677c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1678c0dd49bdSEiji Ota 		    "ibt_query_qp failed w/ 0x%x", qp, attr, attr_mask, rtn);
1679c0dd49bdSEiji Ota 		return (-EIO);
1680c0dd49bdSEiji Ota 	}
1681c0dd49bdSEiji Ota 
1682c0dd49bdSEiji Ota 	/* Get the current and new state for this QP */
1683c0dd49bdSEiji Ota 	cur_state = attr_mask & IB_QP_CUR_STATE ?  attr->cur_qp_state :
1684c0dd49bdSEiji Ota 	    qp_current_state(&qp_attr);
1685c0dd49bdSEiji Ota 	new_state = attr_mask & IB_QP_STATE ? attr->qp_state :
1686c0dd49bdSEiji Ota 	    cur_state;
1687c0dd49bdSEiji Ota 
1688c0dd49bdSEiji Ota 	/* Sanity check of the current/new states */
1689c0dd49bdSEiji Ota 	if (cur_state == new_state && cur_state == IB_QPS_RESET) {
1690c0dd49bdSEiji Ota 		/* Linux OF returns 0 in this case */
1691c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1692c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1693c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1694c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1695c0dd49bdSEiji Ota 		    "invalid state (both of current/new states are RESET)",
1696c0dd49bdSEiji Ota 		    qp, attr, attr_mask);
1697c0dd49bdSEiji Ota 		return (0);
1698c0dd49bdSEiji Ota 	}
1699c0dd49bdSEiji Ota 
1700c0dd49bdSEiji Ota 	/*
1701c0dd49bdSEiji Ota 	 * Check if this modification request is supported with the new
1702c0dd49bdSEiji Ota 	 * and/or current state.
1703c0dd49bdSEiji Ota 	 */
1704c0dd49bdSEiji Ota 	if (!ib_modify_qp_is_ok(cur_state, new_state, qp->qp_type, attr_mask)) {
1705c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1706c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1707c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1708c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1709c0dd49bdSEiji Ota 		    "invalid arguments",
1710c0dd49bdSEiji Ota 		    qp, attr, attr_mask);
1711c0dd49bdSEiji Ota 		return (-EINVAL);
1712c0dd49bdSEiji Ota 	}
1713c0dd49bdSEiji Ota 
1714c0dd49bdSEiji Ota 	/* Sanity checks */
1715c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_PORT && (attr->port_num == 0 ||
1716c0dd49bdSEiji Ota 	    attr->port_num > hattr.hca_nports)) {
1717c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1718c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1719c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1720c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1721c0dd49bdSEiji Ota 		    "invalid attr->port_num(%d), max_nports(%d)",
1722c0dd49bdSEiji Ota 		    qp, attr, attr_mask, attr->port_num, hattr.hca_nports);
1723c0dd49bdSEiji Ota 		return (-EINVAL);
1724c0dd49bdSEiji Ota 	}
1725c0dd49bdSEiji Ota 
1726c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_PKEY_INDEX &&
1727c0dd49bdSEiji Ota 	    attr->pkey_index >= hattr.hca_max_port_pkey_tbl_sz) {
1728c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1729c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1730c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1731c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1732c0dd49bdSEiji Ota 		    "invalid attr->pkey_index(%d), max_pkey_index(%d)",
1733c0dd49bdSEiji Ota 		    qp, attr, attr_mask, attr->pkey_index,
1734c0dd49bdSEiji Ota 		    hattr.hca_max_port_pkey_tbl_sz);
1735c0dd49bdSEiji Ota 		return (-EINVAL);
1736c0dd49bdSEiji Ota 	}
1737c0dd49bdSEiji Ota 
1738c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
1739c0dd49bdSEiji Ota 	    attr->max_rd_atomic > hattr.hca_max_rdma_out_qp) {
1740c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1741c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1742c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1743c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1744c0dd49bdSEiji Ota 		    "invalid attr->max_rd_atomic(0x%x), max_rdma_out_qp(0x%x)",
1745c0dd49bdSEiji Ota 		    qp, attr, attr_mask, attr->max_rd_atomic,
1746c0dd49bdSEiji Ota 		    hattr.hca_max_rdma_out_qp);
1747c0dd49bdSEiji Ota 		return (-EINVAL);
1748c0dd49bdSEiji Ota 	}
1749c0dd49bdSEiji Ota 
1750c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
1751c0dd49bdSEiji Ota 	    attr->max_dest_rd_atomic > hattr.hca_max_rdma_in_qp) {
1752c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
1753c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
1754c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1755c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
1756c0dd49bdSEiji Ota 		    "invalid attr->max_dest_rd_atomic(0x%x), "
1757c0dd49bdSEiji Ota 		    "max_rdma_in_qp(0x%x)", qp, attr, attr_mask,
1758c0dd49bdSEiji Ota 		    attr->max_dest_rd_atomic, hattr.hca_max_rdma_in_qp);
1759c0dd49bdSEiji Ota 		return (-EINVAL);
1760c0dd49bdSEiji Ota 	}
1761c0dd49bdSEiji Ota 
1762c0dd49bdSEiji Ota 	/* copy the current setting */
1763c0dd49bdSEiji Ota 	modify_attr = qp_attr.qp_info;
1764c0dd49bdSEiji Ota 
1765c0dd49bdSEiji Ota 	/*
1766c0dd49bdSEiji Ota 	 * Since it's already checked if the modification request matches
1767c0dd49bdSEiji Ota 	 * the new and/or current states, just assign both of states to
1768c0dd49bdSEiji Ota 	 * modify_attr here. The current state is required if qp_state
1769c0dd49bdSEiji Ota 	 * is RTR, but it's harmelss otherwise, so it's set always.
1770c0dd49bdSEiji Ota 	 */
1771c0dd49bdSEiji Ota 	modify_attr.qp_current_state = OF2IBTF_STATE(cur_state);
1772c0dd49bdSEiji Ota 	modify_attr.qp_state = OF2IBTF_STATE(new_state);
1773c0dd49bdSEiji Ota 	modify_attr.qp_trans = of2ibtf_qp_type(qp->qp_type);
1774c0dd49bdSEiji Ota 
1775c0dd49bdSEiji Ota 	/* Convert OF modification requests into IBTF ones */
1776c0dd49bdSEiji Ota 	flags = IBT_CEP_SET_STATE;	/* IBTF needs IBT_CEP_SET_STATE */
1777c0dd49bdSEiji Ota 	if (cur_state == IB_QPS_RESET &&
1778c0dd49bdSEiji Ota 	    new_state == IB_QPS_INIT) {
1779c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_RESET_INIT;
1780c0dd49bdSEiji Ota 	} else if (cur_state == IB_QPS_INIT &&
1781c0dd49bdSEiji Ota 	    new_state == IB_QPS_RTR) {
1782c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_INIT_RTR;
1783c0dd49bdSEiji Ota 	} else if (cur_state == IB_QPS_RTR &&
1784c0dd49bdSEiji Ota 	    new_state == IB_QPS_RTS) {
1785c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_RTR_RTS;
1786c0dd49bdSEiji Ota 	}
1787c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
1788c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_SQD_EVENT;
1789c0dd49bdSEiji Ota 	}
1790c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_ACCESS_FLAGS) {
1791c0dd49bdSEiji Ota 		modify_attr.qp_flags &= ~(IBT_CEP_RDMA_RD | IBT_CEP_RDMA_WR |
1792c0dd49bdSEiji Ota 		    IBT_CEP_ATOMIC);
1793c0dd49bdSEiji Ota 		if (attr->qp_access_flags & IB_ACCESS_REMOTE_READ) {
1794c0dd49bdSEiji Ota 			flags |= IBT_CEP_SET_RDMA_R;
1795c0dd49bdSEiji Ota 			modify_attr.qp_flags |= IBT_CEP_RDMA_RD;
1796c0dd49bdSEiji Ota 		}
1797c0dd49bdSEiji Ota 		if (attr->qp_access_flags & IB_ACCESS_REMOTE_WRITE) {
1798c0dd49bdSEiji Ota 			flags |= IBT_CEP_SET_RDMA_W;
1799c0dd49bdSEiji Ota 			modify_attr.qp_flags |= IBT_CEP_RDMA_WR;
1800c0dd49bdSEiji Ota 		}
1801c0dd49bdSEiji Ota 		if (attr->qp_access_flags & IB_ACCESS_REMOTE_ATOMIC) {
1802c0dd49bdSEiji Ota 			flags |= IBT_CEP_SET_ATOMIC;
1803c0dd49bdSEiji Ota 			modify_attr.qp_flags |= IBT_CEP_ATOMIC;
1804c0dd49bdSEiji Ota 		}
1805c0dd49bdSEiji Ota 	}
1806c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_PKEY_INDEX) {
1807c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_PKEY_IX;
1808c0dd49bdSEiji Ota 		switch (qp->qp_type)  {
1809c0dd49bdSEiji Ota 		case IB_QPT_SMI:
1810c0dd49bdSEiji Ota 		case IB_QPT_GSI:
1811c0dd49bdSEiji Ota 		case IB_QPT_UD:
1812c0dd49bdSEiji Ota 			modify_attr.qp_transport.ud.ud_pkey_ix =
1813c0dd49bdSEiji Ota 			    attr->pkey_index;
1814c0dd49bdSEiji Ota 			break;
1815c0dd49bdSEiji Ota 		case IB_QPT_RC:
1816c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_path.cep_pkey_ix =
1817c0dd49bdSEiji Ota 			    attr->pkey_index;
1818c0dd49bdSEiji Ota 			break;
1819c0dd49bdSEiji Ota 		case IB_QPT_UC:
1820c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_path.cep_pkey_ix =
1821c0dd49bdSEiji Ota 			    attr->pkey_index;
1822c0dd49bdSEiji Ota 			break;
1823c0dd49bdSEiji Ota 		default:
1824c0dd49bdSEiji Ota 			/* This should never happen */
1825c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
1826c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
1827c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1828c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_PKEY_INDEX): qp: 0x%p, "
1829c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
1830c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
1831c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
1832c0dd49bdSEiji Ota 			return (-EINVAL);
1833c0dd49bdSEiji Ota 		}
1834c0dd49bdSEiji Ota 	}
1835c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_PORT) {
1836c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_PORT;
1837c0dd49bdSEiji Ota 		switch (qp->qp_type) {
1838c0dd49bdSEiji Ota 		case IB_QPT_SMI:
1839c0dd49bdSEiji Ota 		case IB_QPT_GSI:
1840c0dd49bdSEiji Ota 		case IB_QPT_UD:
1841c0dd49bdSEiji Ota 			modify_attr.qp_transport.ud.ud_port = attr->port_num;
1842c0dd49bdSEiji Ota 			break;
1843c0dd49bdSEiji Ota 		case IB_QPT_RC:
1844c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_path.cep_hca_port_num =
1845c0dd49bdSEiji Ota 			    attr->port_num;
1846c0dd49bdSEiji Ota 			break;
1847c0dd49bdSEiji Ota 		case IB_QPT_UC:
1848c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_path.cep_hca_port_num =
1849c0dd49bdSEiji Ota 			    attr->port_num;
1850c0dd49bdSEiji Ota 			break;
1851c0dd49bdSEiji Ota 		default:
1852c0dd49bdSEiji Ota 			/* This should never happen */
1853c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
1854c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
1855c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1856c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_PORT): qp: 0x%p, "
1857c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
1858c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
1859c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
1860c0dd49bdSEiji Ota 			return (-EINVAL);
1861c0dd49bdSEiji Ota 		}
1862c0dd49bdSEiji Ota 	}
1863c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_QKEY) {
1864c0dd49bdSEiji Ota 		ASSERT(qp->qp_type == IB_QPT_UD || qp->qp_type == IB_QPT_SMI ||
1865c0dd49bdSEiji Ota 		    qp->qp_type == IB_QPT_GSI);
1866c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_QKEY;
1867c0dd49bdSEiji Ota 		modify_attr.qp_transport.ud.ud_qkey = attr->qkey;
1868c0dd49bdSEiji Ota 	}
1869c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_AV) {
1870c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_ADDS_VECT;
1871c0dd49bdSEiji Ota 		switch (qp->qp_type) {
1872c0dd49bdSEiji Ota 		case IB_QPT_RC:
1873c0dd49bdSEiji Ota 			set_av(&attr->ah_attr,
1874c0dd49bdSEiji Ota 			    &modify_attr.qp_transport.rc.rc_path);
1875c0dd49bdSEiji Ota 			break;
1876c0dd49bdSEiji Ota 		case IB_QPT_UC:
1877c0dd49bdSEiji Ota 			set_av(&attr->ah_attr,
1878c0dd49bdSEiji Ota 			    &modify_attr.qp_transport.uc.uc_path);
1879c0dd49bdSEiji Ota 			break;
1880c0dd49bdSEiji Ota 		case IB_QPT_SMI:
1881c0dd49bdSEiji Ota 		case IB_QPT_GSI:
1882c0dd49bdSEiji Ota 		case IB_QPT_UD:
1883c0dd49bdSEiji Ota 		default:
1884c0dd49bdSEiji Ota 			/* This should never happen */
1885c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
1886c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
1887c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1888c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_AV): qp: 0x%p, "
1889c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
1890c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
1891c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
1892c0dd49bdSEiji Ota 			return (-EINVAL);
1893c0dd49bdSEiji Ota 		}
1894c0dd49bdSEiji Ota 	}
1895c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_PATH_MTU) {
1896c0dd49bdSEiji Ota 		switch (qp->qp_type) {
1897c0dd49bdSEiji Ota 		case IB_QPT_RC:
1898c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_path_mtu =
1899c0dd49bdSEiji Ota 			    OF2IBTF_PATH_MTU(attr->path_mtu);
1900c0dd49bdSEiji Ota 			break;
1901c0dd49bdSEiji Ota 		case IB_QPT_UC:
1902c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_path_mtu =
1903c0dd49bdSEiji Ota 			    OF2IBTF_PATH_MTU(attr->path_mtu);
1904c0dd49bdSEiji Ota 			break;
1905c0dd49bdSEiji Ota 		case IB_QPT_SMI:
1906c0dd49bdSEiji Ota 		case IB_QPT_GSI:
1907c0dd49bdSEiji Ota 		case IB_QPT_UD:
1908c0dd49bdSEiji Ota 		default:
1909c0dd49bdSEiji Ota 			/* nothing to do */
1910c0dd49bdSEiji Ota 			break;
1911c0dd49bdSEiji Ota 		}
1912c0dd49bdSEiji Ota 	}
1913c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_TIMEOUT && qp->qp_type == IB_QPT_RC) {
1914c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_TIMEOUT;
1915c0dd49bdSEiji Ota 		modify_attr.qp_transport.rc.rc_path.cep_timeout =
1916c0dd49bdSEiji Ota 		    attr->timeout;
1917c0dd49bdSEiji Ota 	}
1918c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_RETRY_CNT && qp->qp_type == IB_QPT_RC) {
1919c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_RETRY;
1920c0dd49bdSEiji Ota 		modify_attr.qp_transport.rc.rc_retry_cnt =
1921c0dd49bdSEiji Ota 		    attr->retry_cnt & 0x7;
1922c0dd49bdSEiji Ota 	}
1923c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_RNR_RETRY && qp->qp_type == IB_QPT_RC) {
1924c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_RNR_NAK_RETRY;
1925c0dd49bdSEiji Ota 		modify_attr.qp_transport.rc.rc_rnr_retry_cnt =
1926c0dd49bdSEiji Ota 		    attr->rnr_retry & 0x7;
1927c0dd49bdSEiji Ota 	}
1928c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_RQ_PSN) {
1929c0dd49bdSEiji Ota 		switch (qp->qp_type) {
1930c0dd49bdSEiji Ota 		case IB_QPT_RC:
1931c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_rq_psn =
1932c0dd49bdSEiji Ota 			    attr->rq_psn & 0xFFFFFF;
1933c0dd49bdSEiji Ota 			break;
1934c0dd49bdSEiji Ota 		case IB_QPT_UC:
1935c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_rq_psn =
1936c0dd49bdSEiji Ota 			    attr->rq_psn & 0xFFFFFF;
1937c0dd49bdSEiji Ota 			break;
1938c0dd49bdSEiji Ota 		case IB_QPT_SMI:
1939c0dd49bdSEiji Ota 		case IB_QPT_GSI:
1940c0dd49bdSEiji Ota 		case IB_QPT_UD:
1941c0dd49bdSEiji Ota 		default:
1942c0dd49bdSEiji Ota 			/* nothing to do */
1943c0dd49bdSEiji Ota 			break;
1944c0dd49bdSEiji Ota 		}
1945c0dd49bdSEiji Ota 	}
1946c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC && qp->qp_type == IB_QPT_RC) {
1947c0dd49bdSEiji Ota 		if (attr->max_rd_atomic) {
1948c0dd49bdSEiji Ota 			flags |= IBT_CEP_SET_RDMARA_OUT;
1949c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_rdma_ra_out =
1950c0dd49bdSEiji Ota 			    attr->max_rd_atomic;
1951c0dd49bdSEiji Ota 		}
1952c0dd49bdSEiji Ota 	}
1953c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_ALT_PATH) {
1954c0dd49bdSEiji Ota 		/* Sanity checks */
1955c0dd49bdSEiji Ota 		if (attr->alt_port_num == 0 ||
1956c0dd49bdSEiji Ota 		    attr->alt_port_num > hattr.hca_nports) {
1957c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
1958c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
1959c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1960c0dd49bdSEiji Ota 			    "ib_modify_qp: qp: 0x%p, attr: 0x%p, "
1961c0dd49bdSEiji Ota 			    "attr_mask: 0x%x => invalid attr->alt_port_num"
1962c0dd49bdSEiji Ota 			    "(%d), max_nports(%d)",
1963c0dd49bdSEiji Ota 			    qp, attr, attr_mask, attr->alt_port_num,
1964c0dd49bdSEiji Ota 			    hattr.hca_nports);
1965c0dd49bdSEiji Ota 			return (-EINVAL);
1966c0dd49bdSEiji Ota 		}
1967c0dd49bdSEiji Ota 		if (attr->alt_pkey_index >= hattr.hca_max_port_pkey_tbl_sz) {
1968c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
1969c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
1970c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
1971c0dd49bdSEiji Ota 			    "ib_modify_qp: qp: 0x%p, attr: 0x%p, "
1972c0dd49bdSEiji Ota 			    "attr_mask: 0x%x => invalid attr->alt_pkey_index"
1973c0dd49bdSEiji Ota 			    "(%d), max_port_key_index(%d)",
1974c0dd49bdSEiji Ota 			    qp, attr, attr_mask, attr->alt_pkey_index,
1975c0dd49bdSEiji Ota 			    hattr.hca_max_port_pkey_tbl_sz);
1976c0dd49bdSEiji Ota 			return (-EINVAL);
1977c0dd49bdSEiji Ota 		}
1978c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_ALT_PATH;
1979c0dd49bdSEiji Ota 		switch (qp->qp_type) {
1980c0dd49bdSEiji Ota 		case IB_QPT_RC:
1981c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_alt_path.
1982c0dd49bdSEiji Ota 			    cep_pkey_ix = attr->alt_pkey_index;
1983c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_alt_path.
1984c0dd49bdSEiji Ota 			    cep_hca_port_num = attr->alt_port_num;
1985c0dd49bdSEiji Ota 			set_av(&attr->alt_ah_attr,
1986c0dd49bdSEiji Ota 			    &modify_attr.qp_transport.rc.rc_alt_path);
1987c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_alt_path.
1988c0dd49bdSEiji Ota 			    cep_timeout = attr->alt_timeout;
1989c0dd49bdSEiji Ota 			break;
1990c0dd49bdSEiji Ota 		case IB_QPT_UC:
1991c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_alt_path.
1992c0dd49bdSEiji Ota 			    cep_pkey_ix = attr->alt_pkey_index;
1993c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_alt_path.
1994c0dd49bdSEiji Ota 			    cep_hca_port_num = attr->alt_port_num;
1995c0dd49bdSEiji Ota 			set_av(&attr->alt_ah_attr,
1996c0dd49bdSEiji Ota 			    &modify_attr.qp_transport.uc.uc_alt_path);
1997c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_alt_path.
1998c0dd49bdSEiji Ota 			    cep_timeout = attr->alt_timeout;
1999c0dd49bdSEiji Ota 			break;
2000c0dd49bdSEiji Ota 		case IB_QPT_SMI:
2001c0dd49bdSEiji Ota 		case IB_QPT_GSI:
2002c0dd49bdSEiji Ota 		case IB_QPT_UD:
2003c0dd49bdSEiji Ota 		default:
2004c0dd49bdSEiji Ota 			/* This should never happen */
2005c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
2006c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
2007c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2008c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_ALT_PATH): qp: 0x%p, "
2009c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
2010c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
2011c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
2012c0dd49bdSEiji Ota 			return (-EINVAL);
2013c0dd49bdSEiji Ota 		}
2014c0dd49bdSEiji Ota 	}
2015c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_MIN_RNR_TIMER && qp->qp_type == IB_QPT_RC) {
2016c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_MIN_RNR_NAK;
2017c0dd49bdSEiji Ota 		modify_attr.qp_transport.rc.rc_min_rnr_nak =
2018c0dd49bdSEiji Ota 		    attr->min_rnr_timer & 0x1F;
2019c0dd49bdSEiji Ota 	}
2020c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_SQ_PSN) {
2021c0dd49bdSEiji Ota 		switch (qp->qp_type)  {
2022c0dd49bdSEiji Ota 		case IB_QPT_SMI:
2023c0dd49bdSEiji Ota 		case IB_QPT_GSI:
2024c0dd49bdSEiji Ota 		case IB_QPT_UD:
2025c0dd49bdSEiji Ota 			modify_attr.qp_transport.ud.ud_sq_psn =
2026c0dd49bdSEiji Ota 			    attr->sq_psn;
2027c0dd49bdSEiji Ota 			break;
2028c0dd49bdSEiji Ota 		case IB_QPT_RC:
2029c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_sq_psn =
2030c0dd49bdSEiji Ota 			    attr->sq_psn;
2031c0dd49bdSEiji Ota 			break;
2032c0dd49bdSEiji Ota 		case IB_QPT_UC:
2033c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_sq_psn =
2034c0dd49bdSEiji Ota 			    attr->sq_psn;
2035c0dd49bdSEiji Ota 			break;
2036c0dd49bdSEiji Ota 		default:
2037c0dd49bdSEiji Ota 			/* This should never happen */
2038c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
2039c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
2040c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2041c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_SQ_PSN): qp: 0x%p, "
2042c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
2043c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
2044c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
2045c0dd49bdSEiji Ota 			return (-EINVAL);
2046c0dd49bdSEiji Ota 		}
2047c0dd49bdSEiji Ota 	}
2048c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC && qp->qp_type == IB_QPT_RC) {
2049c0dd49bdSEiji Ota 		/* Linux OF sets the value if max_dest_rd_atomic is not zero */
2050c0dd49bdSEiji Ota 		if (attr->max_dest_rd_atomic) {
2051c0dd49bdSEiji Ota 			flags |= IBT_CEP_SET_RDMARA_IN;
2052c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_rdma_ra_in =
2053c0dd49bdSEiji Ota 			    attr->max_dest_rd_atomic;
2054c0dd49bdSEiji Ota 		}
2055c0dd49bdSEiji Ota 	}
2056c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_PATH_MIG_STATE) {
2057c0dd49bdSEiji Ota 		flags |= IBT_CEP_SET_MIG;
2058c0dd49bdSEiji Ota 		switch (qp->qp_type)  {
2059c0dd49bdSEiji Ota 		case IB_QPT_RC:
2060c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_mig_state =
2061c0dd49bdSEiji Ota 			    OF2IBTF_PATH_MIG_STATE(attr->path_mig_state);
2062c0dd49bdSEiji Ota 			break;
2063c0dd49bdSEiji Ota 		case IB_QPT_UC:
2064c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_mig_state =
2065c0dd49bdSEiji Ota 			    OF2IBTF_PATH_MIG_STATE(attr->path_mig_state);
2066c0dd49bdSEiji Ota 			break;
2067c0dd49bdSEiji Ota 		case IB_QPT_SMI:
2068c0dd49bdSEiji Ota 		case IB_QPT_GSI:
2069c0dd49bdSEiji Ota 		case IB_QPT_UD:
2070c0dd49bdSEiji Ota 		default:
2071c0dd49bdSEiji Ota 			/* This should never happen */
2072c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
2073c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
2074c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2075c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_PATH_MIG_STATE): qp: 0x%p, "
2076c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
2077c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
2078c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
2079c0dd49bdSEiji Ota 			return (-EINVAL);
2080c0dd49bdSEiji Ota 		}
2081c0dd49bdSEiji Ota 	}
2082c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_CAP) {
2083c0dd49bdSEiji Ota 		/* IB_QP_CAP is not supported */
2084c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
2085c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
2086c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2087c0dd49bdSEiji Ota 		    "ib_modify_qp: qp: 0x%p, attr: 0x%p, "
2088c0dd49bdSEiji Ota 		    "attr_mask: 0x%x => IB_QP_CAP is not supported",
2089c0dd49bdSEiji Ota 		    qp, attr, attr_mask);
2090c0dd49bdSEiji Ota 		return (-EINVAL);
2091c0dd49bdSEiji Ota 	}
2092c0dd49bdSEiji Ota 	if (attr_mask & IB_QP_DEST_QPN) {
2093c0dd49bdSEiji Ota 		switch (qp->qp_type)  {
2094c0dd49bdSEiji Ota 		case IB_QPT_RC:
2095c0dd49bdSEiji Ota 			modify_attr.qp_transport.rc.rc_dst_qpn =
2096c0dd49bdSEiji Ota 			    attr->dest_qp_num;
2097c0dd49bdSEiji Ota 			break;
2098c0dd49bdSEiji Ota 		case IB_QPT_UC:
2099c0dd49bdSEiji Ota 			modify_attr.qp_transport.uc.uc_dst_qpn =
2100c0dd49bdSEiji Ota 			    attr->dest_qp_num;
2101c0dd49bdSEiji Ota 			break;
2102c0dd49bdSEiji Ota 		case IB_QPT_SMI:
2103c0dd49bdSEiji Ota 		case IB_QPT_GSI:
2104c0dd49bdSEiji Ota 		case IB_QPT_UD:
2105c0dd49bdSEiji Ota 		default:
2106c0dd49bdSEiji Ota 			/* This should never happen */
2107c0dd49bdSEiji Ota 			mutex_exit(&qp->lock);
2108c0dd49bdSEiji Ota 			ofs_lock_exit(&ofs_client->lock);
2109c0dd49bdSEiji Ota 			SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2110c0dd49bdSEiji Ota 			    "ib_modify_qp(IB_QP_DEST_PSN): qp: 0x%p, "
2111c0dd49bdSEiji Ota 			    "attr: 0x%p, attr_mask: 0x%x => "
2112c0dd49bdSEiji Ota 			    "invalid qp->qp_type(%d)",
2113c0dd49bdSEiji Ota 			    qp, attr, attr_mask, qp->qp_type);
2114c0dd49bdSEiji Ota 			return (-EINVAL);
2115c0dd49bdSEiji Ota 		}
2116c0dd49bdSEiji Ota 	}
2117c0dd49bdSEiji Ota 
2118c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
2119c0dd49bdSEiji Ota 	    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x, "
2120c0dd49bdSEiji Ota 	    "flags: 0x%x, modify_attr: 0x%p",
2121c0dd49bdSEiji Ota 	    qp, attr, attr_mask, flags, &modify_attr);
2122c0dd49bdSEiji Ota 
2123c0dd49bdSEiji Ota 	/* Modify the QP attributes */
2124c0dd49bdSEiji Ota 	rtn = ibt_modify_qp(qp->ibt_qp, flags, &modify_attr, NULL);
2125c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS) {
2126c0dd49bdSEiji Ota 		mutex_exit(&qp->lock);
2127c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
2128c0dd49bdSEiji Ota 		return (0);
2129c0dd49bdSEiji Ota 	}
2130c0dd49bdSEiji Ota 	mutex_exit(&qp->lock);
2131c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
2132c0dd49bdSEiji Ota 
2133c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2134c0dd49bdSEiji Ota 	    "ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
2135c0dd49bdSEiji Ota 	    "ibt_modify_qp failed w/ %d, flags: 0x%x",
2136c0dd49bdSEiji Ota 	    qp, attr, attr_mask, rtn, flags);
2137c0dd49bdSEiji Ota 
2138c0dd49bdSEiji Ota 	switch (rtn) {
2139c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
2140c0dd49bdSEiji Ota 	case IBT_QP_HDL_INVALID:
2141c0dd49bdSEiji Ota 	case IBT_QP_SRV_TYPE_INVALID:
2142c0dd49bdSEiji Ota 	case IBT_QP_STATE_INVALID:
2143c0dd49bdSEiji Ota 	case IBT_HCA_PORT_INVALID:
2144c0dd49bdSEiji Ota 	case IBT_PKEY_IX_ILLEGAL:
2145c0dd49bdSEiji Ota 		return (-EINVAL);
2146c0dd49bdSEiji Ota 	default:
2147c0dd49bdSEiji Ota 		return (-EIO);
2148c0dd49bdSEiji Ota 	}
2149c0dd49bdSEiji Ota }
2150c0dd49bdSEiji Ota 
2151c0dd49bdSEiji Ota static inline enum ib_wc_status
ibt2of_wc_status(ibt_wc_status_t status)2152c0dd49bdSEiji Ota ibt2of_wc_status(ibt_wc_status_t status)
2153c0dd49bdSEiji Ota {
2154c0dd49bdSEiji Ota 	switch (status) {
2155c0dd49bdSEiji Ota 	case IBT_WC_LOCAL_LEN_ERR:
2156c0dd49bdSEiji Ota 		return (IB_WC_LOC_LEN_ERR);
2157c0dd49bdSEiji Ota 	case IBT_WC_LOCAL_CHAN_OP_ERR:
2158c0dd49bdSEiji Ota 		return (IB_WC_LOC_QP_OP_ERR);
2159c0dd49bdSEiji Ota 	case IBT_WC_LOCAL_PROTECT_ERR:
2160c0dd49bdSEiji Ota 		return (IB_WC_LOC_PROT_ERR);
2161c0dd49bdSEiji Ota 	case IBT_WC_WR_FLUSHED_ERR:
2162c0dd49bdSEiji Ota 		return (IB_WC_WR_FLUSH_ERR);
2163c0dd49bdSEiji Ota 	case IBT_WC_MEM_WIN_BIND_ERR:
2164c0dd49bdSEiji Ota 		return (IB_WC_MW_BIND_ERR);
2165c0dd49bdSEiji Ota 	case IBT_WC_BAD_RESPONSE_ERR:
2166c0dd49bdSEiji Ota 		return (IB_WC_BAD_RESP_ERR);
2167c0dd49bdSEiji Ota 	case IBT_WC_LOCAL_ACCESS_ERR:
2168c0dd49bdSEiji Ota 		return (IB_WC_LOC_ACCESS_ERR);
2169c0dd49bdSEiji Ota 	case IBT_WC_REMOTE_INVALID_REQ_ERR:
2170c0dd49bdSEiji Ota 		return (IB_WC_REM_INV_REQ_ERR);
2171c0dd49bdSEiji Ota 	case IBT_WC_REMOTE_ACCESS_ERR:
2172c0dd49bdSEiji Ota 		return (IB_WC_REM_ACCESS_ERR);
2173c0dd49bdSEiji Ota 	case IBT_WC_REMOTE_OP_ERR:
2174c0dd49bdSEiji Ota 		return (IB_WC_REM_OP_ERR);
2175c0dd49bdSEiji Ota 	case IBT_WC_TRANS_TIMEOUT_ERR:
2176c0dd49bdSEiji Ota 		return (IB_WC_RETRY_EXC_ERR);
2177c0dd49bdSEiji Ota 	case IBT_WC_RNR_NAK_TIMEOUT_ERR:
2178c0dd49bdSEiji Ota 		return (IB_WC_RNR_RETRY_EXC_ERR);
2179c0dd49bdSEiji Ota 	case IBT_WC_SUCCESS:
2180c0dd49bdSEiji Ota 	default:
2181c0dd49bdSEiji Ota 		/* Hermon doesn't support EEC yet */
2182c0dd49bdSEiji Ota 		ASSERT(status == IBT_WC_SUCCESS);
2183c0dd49bdSEiji Ota 		return (IB_WC_SUCCESS);
2184c0dd49bdSEiji Ota 	}
2185c0dd49bdSEiji Ota }
2186c0dd49bdSEiji Ota 
2187c0dd49bdSEiji Ota static inline enum ib_wc_opcode
ibt2of_wc_opcode(ibt_wrc_opcode_t wc_type)2188c0dd49bdSEiji Ota ibt2of_wc_opcode(ibt_wrc_opcode_t wc_type)
2189c0dd49bdSEiji Ota {
2190c0dd49bdSEiji Ota 	switch (wc_type) {
2191c0dd49bdSEiji Ota 	case IBT_WRC_SEND:
2192c0dd49bdSEiji Ota 		return (IB_WC_SEND);
2193c0dd49bdSEiji Ota 	case IBT_WRC_RDMAR:
2194c0dd49bdSEiji Ota 		return (IB_WC_RDMA_READ);
2195c0dd49bdSEiji Ota 	case IBT_WRC_RDMAW:
2196c0dd49bdSEiji Ota 		return (IB_WC_RDMA_WRITE);
2197c0dd49bdSEiji Ota 	case IBT_WRC_CSWAP:
2198c0dd49bdSEiji Ota 		return (IB_WC_COMP_SWAP);
2199c0dd49bdSEiji Ota 	case IBT_WRC_FADD:
2200c0dd49bdSEiji Ota 		return (IB_WC_FETCH_ADD);
2201c0dd49bdSEiji Ota 	case IBT_WRC_BIND:
2202c0dd49bdSEiji Ota 		return (IB_WC_BIND_MW);
2203c0dd49bdSEiji Ota 	case IBT_WRC_RECV:
2204c0dd49bdSEiji Ota 		return (IB_WC_RECV);
2205c0dd49bdSEiji Ota 	case IBT_WRC_RECV_RDMAWI:
2206c0dd49bdSEiji Ota 	default:
2207c0dd49bdSEiji Ota 		ASSERT(wc_type == IBT_WRC_RECV_RDMAWI);
2208c0dd49bdSEiji Ota 		return (IB_WC_RECV_RDMA_WITH_IMM);
2209c0dd49bdSEiji Ota 	}
2210c0dd49bdSEiji Ota }
2211c0dd49bdSEiji Ota 
2212c0dd49bdSEiji Ota static inline int
ibt2of_wc_flags(ibt_wc_flags_t wc_flags)2213c0dd49bdSEiji Ota ibt2of_wc_flags(ibt_wc_flags_t wc_flags)
2214c0dd49bdSEiji Ota {
2215c0dd49bdSEiji Ota 	return (wc_flags & ~IBT_WC_CKSUM_OK);
2216c0dd49bdSEiji Ota }
2217c0dd49bdSEiji Ota 
2218c0dd49bdSEiji Ota static inline void
set_wc(ibt_wc_t * ibt_wc,struct ib_wc * wc)2219c0dd49bdSEiji Ota set_wc(ibt_wc_t *ibt_wc, struct ib_wc *wc)
2220c0dd49bdSEiji Ota {
2221c0dd49bdSEiji Ota 	wc->wr_id = ibt_wc->wc_id;
2222c0dd49bdSEiji Ota 	wc->status = ibt2of_wc_status(ibt_wc->wc_status);
2223c0dd49bdSEiji Ota 	/* opcode can be undefined if status is not success */
2224c0dd49bdSEiji Ota 	if (wc->status == IB_WC_SUCCESS) {
2225c0dd49bdSEiji Ota 		wc->opcode = ibt2of_wc_opcode(ibt_wc->wc_type);
2226c0dd49bdSEiji Ota 	}
2227c0dd49bdSEiji Ota 	wc->vendor_err = 0;			/* not supported */
2228c0dd49bdSEiji Ota 	wc->byte_len = ibt_wc->wc_bytes_xfer;
2229c0dd49bdSEiji Ota 	wc->qp = NULL;				/* not supported */
2230c0dd49bdSEiji Ota 	wc->imm_data = htonl(ibt_wc->wc_immed_data);
2231c0dd49bdSEiji Ota 	wc->src_qp = ibt_wc->wc_qpn;
2232c0dd49bdSEiji Ota 	wc->wc_flags = ibt2of_wc_flags(ibt_wc->wc_flags);
2233c0dd49bdSEiji Ota 	wc->pkey_index = ibt_wc->wc_pkey_ix;
2234c0dd49bdSEiji Ota 	wc->slid = ibt_wc->wc_slid;
2235c0dd49bdSEiji Ota 	wc->sl = ibt_wc->wc_sl;
2236c0dd49bdSEiji Ota 	wc->dlid_path_bits = ibt_wc->wc_path_bits;
2237c0dd49bdSEiji Ota 	wc->port_num = 0;			/* not supported */
2238c0dd49bdSEiji Ota }
2239c0dd49bdSEiji Ota 
2240c0dd49bdSEiji Ota /*
2241c0dd49bdSEiji Ota  * ib_poll_cq - poll a CQ for completion(s)
2242c0dd49bdSEiji Ota  * @cq:the CQ being polled
2243c0dd49bdSEiji Ota  * @num_entries:maximum number of completions to return
2244c0dd49bdSEiji Ota  * @wc:array of at least @num_entries &struct ib_wc where completions
2245c0dd49bdSEiji Ota  *   will be returned
2246c0dd49bdSEiji Ota  *
2247c0dd49bdSEiji Ota  * Poll a CQ for (possibly multiple) completions.  If the return value
2248c0dd49bdSEiji Ota  * is < 0, an error occurred.  If the return value is >= 0, it is the
2249c0dd49bdSEiji Ota  * number of completions returned.  If the return value is
2250c0dd49bdSEiji Ota  * non-negative and < num_entries, then the CQ was emptied.
2251c0dd49bdSEiji Ota  *
2252c0dd49bdSEiji Ota  * Note that three following memebers in struct ib_wc are not supported
2253c0dd49bdSEiji Ota  * currently, and the values are always either 0 or NULL.
2254c0dd49bdSEiji Ota  *	u32			vendor_err;
2255c0dd49bdSEiji Ota  *	struct ib_qp		*qp;
2256c0dd49bdSEiji Ota  *	u8			port_num;
2257c0dd49bdSEiji Ota  */
2258c0dd49bdSEiji Ota int
ib_poll_cq(struct ib_cq * cq,int num_entries,struct ib_wc * wc)2259c0dd49bdSEiji Ota ib_poll_cq(struct ib_cq *cq, int num_entries, struct ib_wc *wc)
2260c0dd49bdSEiji Ota {
2261c0dd49bdSEiji Ota 	ibt_wc_t	ibt_wc;
2262c0dd49bdSEiji Ota 	int		npolled;
2263c0dd49bdSEiji Ota 	ibt_status_t	rtn;
2264c0dd49bdSEiji Ota 	ofs_client_t	*ofs_client = (ofs_client_t *)cq->device->clnt_hdl;
2265c0dd49bdSEiji Ota 
2266c0dd49bdSEiji Ota 	ofs_lock_enter(&ofs_client->lock);
2267c0dd49bdSEiji Ota 	if (cq->device->reg_state != IB_DEV_OPEN) {
2268c0dd49bdSEiji Ota 		ofs_lock_exit(&ofs_client->lock);
2269c0dd49bdSEiji Ota 		SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2270c0dd49bdSEiji Ota 		    "ib_poll_cq: cq: 0x%p => invalid device state (%d)",
2271c0dd49bdSEiji Ota 		    cq, cq->device->reg_state);
2272c0dd49bdSEiji Ota 		return (-ENXIO);
2273c0dd49bdSEiji Ota 	}
2274c0dd49bdSEiji Ota 
2275c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L3(sol_kverbs_dbg_str,
2276c0dd49bdSEiji Ota 	    "ib_poll_cq: cq: 0x%p, num_entries: %d, wc: 0x%p, "
2277c0dd49bdSEiji Ota 	    "ibt_cq: 0x%p, ibt_wc: 0x%p",
2278c0dd49bdSEiji Ota 	    cq, num_entries, wc, cq->ibt_cq, &ibt_wc);
2279c0dd49bdSEiji Ota 
2280c0dd49bdSEiji Ota 	/* only one thread per cq is allowed during ibt_poll_cq() */
2281c0dd49bdSEiji Ota 	mutex_enter(&cq->lock);
2282c0dd49bdSEiji Ota 	for (npolled = 0; npolled < num_entries; ++npolled) {
2283c0dd49bdSEiji Ota 		bzero(&ibt_wc, sizeof (ibt_wc_t));
2284c0dd49bdSEiji Ota 		rtn = ibt_poll_cq(cq->ibt_cq, &ibt_wc, 1, NULL);
2285c0dd49bdSEiji Ota 		if (rtn != IBT_SUCCESS) {
2286c0dd49bdSEiji Ota 			break;
2287c0dd49bdSEiji Ota 		}
2288c0dd49bdSEiji Ota 		/* save this result to struct ib_wc */
2289c0dd49bdSEiji Ota 		set_wc(&ibt_wc, wc + npolled);
2290c0dd49bdSEiji Ota 	}
2291c0dd49bdSEiji Ota 	mutex_exit(&cq->lock);
2292c0dd49bdSEiji Ota 	ofs_lock_exit(&ofs_client->lock);
2293c0dd49bdSEiji Ota 
2294c0dd49bdSEiji Ota 	if (rtn == IBT_SUCCESS || rtn == IBT_CQ_EMPTY) {
2295c0dd49bdSEiji Ota 		return (npolled);
2296c0dd49bdSEiji Ota 	}
2297c0dd49bdSEiji Ota 
2298c0dd49bdSEiji Ota 	SOL_OFS_DPRINTF_L2(sol_kverbs_dbg_str,
2299c0dd49bdSEiji Ota 	    "ib_poll_cq: cq: 0x%p, num_entries: %d, wc: 0x%p => "
2300c0dd49bdSEiji Ota 	    "ibt_poll_cq failed w/ %d, npolled = %d",
2301c0dd49bdSEiji Ota 	    cq, num_entries, wc, rtn, npolled);
2302c0dd49bdSEiji Ota 
2303c0dd49bdSEiji Ota 	switch (rtn) {
2304c0dd49bdSEiji Ota 	case IBT_HCA_HDL_INVALID:
2305c0dd49bdSEiji Ota 	case IBT_CQ_HDL_INVALID:
2306c0dd49bdSEiji Ota 	case IBT_INVALID_PARAM:
2307c0dd49bdSEiji Ota 		return (-EINVAL);
2308c0dd49bdSEiji Ota 	default:
2309c0dd49bdSEiji Ota 		return (-EIO);
2310c0dd49bdSEiji Ota 	}
2311c0dd49bdSEiji Ota }
2312c0dd49bdSEiji Ota 
2313c0dd49bdSEiji Ota ibt_hca_hdl_t
ib_get_ibt_hca_hdl(struct ib_device * device)2314c0dd49bdSEiji Ota ib_get_ibt_hca_hdl(struct ib_device *device)
2315c0dd49bdSEiji Ota {
2316c0dd49bdSEiji Ota 	return (device->hca_hdl);
2317c0dd49bdSEiji Ota }
2318c0dd49bdSEiji Ota 
2319c0dd49bdSEiji Ota ibt_channel_hdl_t
ib_get_ibt_channel_hdl(struct rdma_cm_id * cm)2320c0dd49bdSEiji Ota ib_get_ibt_channel_hdl(struct rdma_cm_id *cm)
2321c0dd49bdSEiji Ota {
2322c0dd49bdSEiji Ota 	return (cm->qp == NULL ? NULL : cm->qp->ibt_qp);
2323c0dd49bdSEiji Ota }
2324