1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 #include <sys/ddi.h>
26 #include <sys/sunddi.h>
27 
28 #include <sys/socket.h>		/* networking stuff */
29 #include <sys/sysmacros.h>	/* offsetof */
30 
31 #include <sys/ib/clients/iser/iser.h>
32 #include <sys/ib/clients/iser/iser_idm.h>
33 
34 /*
35  * iSER transport routines
36  *
37  * All transport functions except iser_tgt_svc_create() are called through
38  * the ops vector, iser_tgt_svc_create() is called from the async handler
39  * inaddition to being called by the ULP
40  */
41 
42 static void iser_pdu_tx(idm_conn_t *ic, idm_pdu_t *pdu);
43 
44 static idm_status_t iser_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb);
45 static idm_status_t iser_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb);
46 static idm_status_t iser_tgt_enable_datamover(idm_conn_t *ic);
47 static idm_status_t iser_ini_enable_datamover(idm_conn_t *ic);
48 static void iser_notice_key_values(struct idm_conn_s *ic,
49     nvlist_t *negotiated_nvl);
50 static kv_status_t iser_declare_key_values(struct idm_conn_s *ic,
51     nvlist_t *config_nvl, nvlist_t *outgoing_nvl);
52 static idm_status_t iser_free_task_rsrcs(idm_task_t *idt);
53 static kv_status_t iser_negotiate_key_values(idm_conn_t *ic,
54     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
55 static kv_status_t iser_handle_numerical(nvpair_t *nvp, uint64_t value,
56     const idm_kv_xlate_t *ikvx, uint64_t min_value, uint64_t max_value,
57     uint64_t iser_max_value, nvlist_t *request_nvl, nvlist_t *response_nvl,
58     nvlist_t *negotiated_nvl);
59 static kv_status_t iser_handle_boolean(nvpair_t *nvp, boolean_t value,
60     const idm_kv_xlate_t *ikvx, boolean_t iser_value, nvlist_t *request_nvl,
61     nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
62 static kv_status_t iser_handle_key(nvpair_t *nvp, const idm_kv_xlate_t *ikvx,
63     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
64 static kv_status_t iser_process_request_nvlist(nvlist_t *request_nvl,
65     nvlist_t *response_nvl, nvlist_t *negotiated_nvl);
66 static boolean_t iser_conn_is_capable(idm_conn_req_t *ic,
67     idm_transport_caps_t *caps);
68 static idm_status_t iser_buf_alloc(idm_buf_t *idb, uint64_t buflen);
69 static idm_status_t iser_buf_setup(idm_buf_t *idb);
70 static void iser_buf_teardown(idm_buf_t *idb);
71 static void iser_buf_free(idm_buf_t *idb);
72 static void iser_tgt_svc_destroy(struct idm_svc_s *is);
73 static idm_status_t iser_tgt_svc_online(struct idm_svc_s *is);
74 static void iser_tgt_svc_offline(struct idm_svc_s *is);
75 static idm_status_t iser_tgt_conn_connect(struct idm_conn_s *ic);
76 static idm_status_t iser_ini_conn_create(idm_conn_req_t *cr,
77     struct idm_conn_s *ic);
78 static void iser_conn_destroy(struct idm_conn_s *ic);
79 static idm_status_t iser_ini_conn_connect(struct idm_conn_s *ic);
80 static void iser_conn_disconnect(struct idm_conn_s *ic);
81 
82 /*
83  * iSER IDM transport operations
84  */
85 idm_transport_ops_t iser_transport_ops = {
86 	&iser_pdu_tx,			/* it_tx_pdu */
87 	&iser_buf_tx_to_ini,		/* it_buf_tx_to_ini */
88 	&iser_buf_rx_from_ini,		/* it_buf_rx_from_ini */
89 	NULL,				/* it_rx_datain */
90 	NULL,				/* it_rx_rtt */
91 	NULL,				/* it_rx_dataout */
92 	NULL,				/* it_alloc_conn_rsrc */
93 	NULL,				/* it_free_conn_rsrc */
94 	&iser_tgt_enable_datamover,	/* it_tgt_enable_datamover */
95 	&iser_ini_enable_datamover,	/* it_ini_enable_datamover */
96 	NULL,				/* it_conn_terminate */
97 	&iser_free_task_rsrcs,		/* it_free_task_rsrc */
98 	&iser_negotiate_key_values,	/* it_negotiate_key_values */
99 	&iser_notice_key_values,	/* it_notice_key_values */
100 	&iser_conn_is_capable,		/* it_conn_is_capable */
101 	&iser_buf_alloc,		/* it_buf_alloc */
102 	&iser_buf_free,			/* it_buf_free */
103 	&iser_buf_setup,		/* it_buf_setup */
104 	&iser_buf_teardown,		/* it_buf_teardown */
105 	&iser_tgt_svc_create,		/* it_tgt_svc_create */
106 	&iser_tgt_svc_destroy,		/* it_tgt_svc_destroy */
107 	&iser_tgt_svc_online,		/* it_tgt_svc_online */
108 	&iser_tgt_svc_offline,		/* it_tgt_svc_offline */
109 	&iser_conn_destroy,		/* it_tgt_conn_destroy */
110 	&iser_tgt_conn_connect,		/* it_tgt_conn_connect */
111 	&iser_conn_disconnect,		/* it_tgt_conn_disconnect */
112 	&iser_ini_conn_create,		/* it_ini_conn_create */
113 	&iser_conn_destroy,		/* it_ini_conn_destroy */
114 	&iser_ini_conn_connect,		/* it_ini_conn_connect */
115 	&iser_conn_disconnect,		/* it_ini_conn_disconnect */
116 	&iser_declare_key_values	/* it_declare_key_values */
117 };
118 
119 /*
120  * iSER IDM transport capabilities
121  */
122 idm_transport_caps_t iser_transport_caps = {
123 	0		/* flags */
124 };
125 
126 int
iser_idm_register()127 iser_idm_register()
128 {
129 	idm_transport_attr_t	attr;
130 	idm_status_t		status;
131 
132 	attr.type	= IDM_TRANSPORT_TYPE_ISER;
133 	attr.it_ops	= &iser_transport_ops;
134 	attr.it_caps	= &iser_transport_caps;
135 
136 	status = idm_transport_register(&attr);
137 	if (status != IDM_STATUS_SUCCESS) {
138 		ISER_LOG(CE_WARN, "Failed to register iSER transport with IDM");
139 		return (DDI_FAILURE);
140 	}
141 
142 	ISER_LOG(CE_NOTE, "Registered iSER transport with IDM");
143 
144 	return (DDI_SUCCESS);
145 }
146 
147 /*
148  * iser_ini_conn_create()
149  * Allocate an iSER initiator connection context
150  */
151 static idm_status_t
iser_ini_conn_create(idm_conn_req_t * cr,idm_conn_t * ic)152 iser_ini_conn_create(idm_conn_req_t *cr, idm_conn_t *ic)
153 {
154 	iser_chan_t	*iser_chan = NULL;
155 	iser_conn_t	*iser_conn;
156 
157 	/* Allocate and set up a connection handle */
158 	iser_conn = kmem_zalloc(sizeof (iser_conn_t), KM_SLEEP);
159 	mutex_init(&iser_conn->ic_lock, NULL, MUTEX_DRIVER, NULL);
160 
161 	/* Allocate and open a channel to the target node */
162 	iser_chan = iser_channel_alloc(NULL, &cr->cr_ini_dst_addr);
163 	if (iser_chan == NULL) {
164 		ISER_LOG(CE_WARN, "iser: failed to allocate channel");
165 		mutex_destroy(&iser_conn->ic_lock);
166 		kmem_free(iser_conn, sizeof (iser_conn_t));
167 		return (IDM_STATUS_FAIL);
168 	}
169 
170 	/*
171 	 * The local IP and remote IP are filled in iser_channel_alloc. The
172 	 * remote port needs to be filled in from idm_conn_req_t. The local
173 	 * port is irrelevant. Internal representation of the port in the
174 	 * IDM sockaddr structure is in network byte order. IBT expects the
175 	 * port in host byte order.
176 	 */
177 	switch (cr->cr_ini_dst_addr.sin.sa_family) {
178 	case AF_INET:
179 		iser_chan->ic_rport = ntohs(cr->cr_ini_dst_addr.sin4.sin_port);
180 		break;
181 	case AF_INET6:
182 		iser_chan->ic_rport = ntohs(cr->cr_ini_dst_addr.sin6.sin6_port);
183 		break;
184 	default:
185 		iser_chan->ic_rport = ISCSI_LISTEN_PORT;
186 	}
187 	iser_chan->ic_lport = 0;
188 
189 	cv_init(&iser_conn->ic_stage_cv, NULL, CV_DEFAULT, NULL);
190 	iser_conn->ic_type = ISER_CONN_TYPE_INI;
191 	iser_conn->ic_stage = ISER_CONN_STAGE_ALLOCATED;
192 	iser_conn->ic_chan = iser_chan;
193 	iser_conn->ic_idmc = ic;
194 
195 	/*
196 	 * Set a pointer to the iser_conn in the iser_chan for easy
197 	 * access during CM event handling
198 	 */
199 	iser_chan->ic_conn = iser_conn;
200 
201 	/* Set the iSER conn handle in the IDM conn private handle */
202 	ic->ic_transport_private = (void *)iser_conn;
203 
204 	/* Set the transport header length */
205 	ic->ic_transport_hdrlen = ISER_HEADER_LENGTH;
206 
207 	return (IDM_STATUS_SUCCESS);
208 }
209 
210 /*
211  * iser_internal_conn_destroy()
212  * Tear down iSER-specific connection resources. This is used below
213  * in iser_conn_destroy(), but also from the CM code when we may have
214  * some of the connection established, but not fully connected.
215  */
216 void
iser_internal_conn_destroy(iser_conn_t * ic)217 iser_internal_conn_destroy(iser_conn_t *ic)
218 {
219 	mutex_enter(&ic->ic_lock);
220 	iser_channel_free(ic->ic_chan);
221 	if ((ic->ic_type == ISER_CONN_TYPE_TGT) &&
222 	    (ic->ic_stage == ISER_CONN_STAGE_ALLOCATED)) {
223 		/*
224 		 * This is a target connection that has yet to be
225 		 * established. Free our reference on the target
226 		 * service handle.
227 		 */
228 		iser_tgt_svc_rele(ic->ic_idms->is_iser_svc);
229 	}
230 	cv_destroy(&ic->ic_stage_cv);
231 	mutex_exit(&ic->ic_lock);
232 	mutex_destroy(&ic->ic_lock);
233 	kmem_free(ic, sizeof (iser_conn_t));
234 }
235 
236 /*
237  * iser_conn_destroy()
238  * Tear down an initiator or target connection.
239  */
240 static void
iser_conn_destroy(idm_conn_t * ic)241 iser_conn_destroy(idm_conn_t *ic)
242 {
243 	iser_conn_t	*iser_conn;
244 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
245 
246 	iser_internal_conn_destroy(iser_conn);
247 	ic->ic_transport_private = NULL;
248 }
249 
250 /*
251  * iser_ini_conn_connect()
252  * Establish the connection referred to by the handle previously allocated via
253  * iser_ini_conn_create().
254  */
255 static idm_status_t
iser_ini_conn_connect(idm_conn_t * ic)256 iser_ini_conn_connect(idm_conn_t *ic)
257 {
258 	iser_conn_t		*iser_conn;
259 	iser_status_t		status;
260 
261 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
262 
263 	status = iser_channel_open(iser_conn->ic_chan);
264 	if (status != ISER_STATUS_SUCCESS) {
265 		ISER_LOG(CE_WARN, "iser: failed to open channel");
266 		return (IDM_STATUS_FAIL);
267 	}
268 
269 	/*
270 	 * Set the local and remote addresses in the idm conn handle.
271 	 */
272 	iser_ib_conv_ibtaddr2sockaddr(&ic->ic_laddr,
273 	    &iser_conn->ic_chan->ic_localip, iser_conn->ic_chan->ic_lport);
274 	iser_ib_conv_ibtaddr2sockaddr(&ic->ic_raddr,
275 	    &iser_conn->ic_chan->ic_remoteip, iser_conn->ic_chan->ic_rport);
276 
277 	mutex_enter(&iser_conn->ic_lock);
278 	/* Hold a reference on the IDM connection handle */
279 	idm_conn_hold(ic);
280 	iser_conn->ic_stage = ISER_CONN_STAGE_IC_CONNECTED;
281 	mutex_exit(&iser_conn->ic_lock);
282 
283 	return (IDM_STATUS_SUCCESS);
284 }
285 
286 /*
287  * iser_conn_disconnect()
288  * Shutdown this iSER connection
289  */
290 static void
iser_conn_disconnect(idm_conn_t * ic)291 iser_conn_disconnect(idm_conn_t *ic)
292 {
293 	iser_conn_t	*iser_conn;
294 
295 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
296 
297 	mutex_enter(&iser_conn->ic_lock);
298 	iser_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
299 	mutex_exit(&iser_conn->ic_lock);
300 
301 	/* Close the channel */
302 	iser_channel_close(iser_conn->ic_chan);
303 
304 	/* Free our reference held on the IDM conn handle, and set CLOSED */
305 	mutex_enter(&iser_conn->ic_lock);
306 	idm_conn_rele(iser_conn->ic_idmc);
307 	iser_conn->ic_stage = ISER_CONN_STAGE_CLOSED;
308 	mutex_exit(&iser_conn->ic_lock);
309 }
310 
311 /*
312  * iser_tgt_svc_create()
313  * Establish the CM service for inbound iSER service requests on the port
314  * indicated by sr->sr_port.
315  * idm_svc_req_t contains the service parameters.
316  */
317 idm_status_t
iser_tgt_svc_create(idm_svc_req_t * sr,idm_svc_t * is)318 iser_tgt_svc_create(idm_svc_req_t *sr, idm_svc_t *is)
319 {
320 	iser_svc_t		*iser_svc;
321 
322 	int			rc;
323 
324 	iser_svc = kmem_zalloc(sizeof (iser_svc_t), KM_SLEEP);
325 	is->is_iser_svc = (void *)iser_svc;
326 
327 	idm_refcnt_init(&iser_svc->is_refcnt, iser_svc);
328 
329 	list_create(&iser_svc->is_sbindlist, sizeof (iser_sbind_t),
330 	    offsetof(iser_sbind_t, is_list_node));
331 	iser_svc->is_svcid = ibt_get_ip_sid(IPPROTO_TCP, sr->sr_port);
332 
333 	/*
334 	 * Register an iSER target service for the requested port
335 	 * and set the iser_svc structure in the idm_svc handle.
336 	 */
337 	rc = iser_register_service(is);
338 	if (rc != DDI_SUCCESS) {
339 		ISER_LOG(CE_NOTE, "iser_tgt_svc_create: iser_register_service "
340 		    "failed on port (%d): rc (0x%x)", sr->sr_port, rc);
341 		(void) ibt_release_ip_sid(iser_svc->is_svcid);
342 		list_destroy(&iser_svc->is_sbindlist);
343 		idm_refcnt_destroy(&iser_svc->is_refcnt);
344 		kmem_free(iser_svc, sizeof (iser_svc_t));
345 		return (IDM_STATUS_FAIL);
346 	}
347 
348 	return (IDM_STATUS_SUCCESS);
349 }
350 
351 /* IDM refcnt utilities for the iSER service handle */
352 void
iser_tgt_svc_hold(iser_svc_t * is)353 iser_tgt_svc_hold(iser_svc_t *is)
354 {
355 	idm_refcnt_hold(&is->is_refcnt);
356 }
357 
358 void
iser_tgt_svc_rele(iser_svc_t * is)359 iser_tgt_svc_rele(iser_svc_t *is)
360 {
361 	idm_refcnt_rele(&is->is_refcnt);
362 }
363 
364 /*
365  * iser_tgt_svc_destroy()
366  * Teardown resources allocated in iser_tgt_svc_create()
367  */
368 static void
iser_tgt_svc_destroy(idm_svc_t * is)369 iser_tgt_svc_destroy(idm_svc_t *is)
370 {
371 	iser_svc_t	*iser_svc;
372 
373 	iser_svc = (iser_svc_t *)is->is_iser_svc;
374 
375 	/*
376 	 * Deregister the iSER target service on this port and free
377 	 * the iser_svc structure from the idm_svc handle.
378 	 */
379 	iser_deregister_service(is);
380 
381 	/* Wait for the iSER service handle's refcnt to zero */
382 	idm_refcnt_wait_ref(&iser_svc->is_refcnt);
383 
384 	list_destroy(&iser_svc->is_sbindlist);
385 
386 	idm_refcnt_destroy(&iser_svc->is_refcnt);
387 
388 	kmem_free(iser_svc, sizeof (iser_svc_t));
389 }
390 
391 /*
392  * iser_tgt_svc_online()
393  * Bind the CM service allocated via iser_tgt_svc_create().
394  */
395 static idm_status_t
iser_tgt_svc_online(idm_svc_t * is)396 iser_tgt_svc_online(idm_svc_t *is)
397 {
398 	iser_status_t	status;
399 
400 	mutex_enter(&is->is_mutex);
401 
402 	/*
403 	 * Pass the IDM service handle as the client private data for
404 	 * later use.
405 	 */
406 	status = iser_bind_service(is);
407 	if (status != ISER_STATUS_SUCCESS) {
408 		ISER_LOG(CE_NOTE, "iser_tgt_svc_online: failed bind service");
409 		mutex_exit(&is->is_mutex);
410 		return (IDM_STATUS_FAIL);
411 	}
412 
413 	mutex_exit(&is->is_mutex);
414 	return (IDM_STATUS_SUCCESS);
415 }
416 
417 /*
418  * iser_tgt_svc_offline
419  * Unbind the service on all available HCA ports.
420  */
421 static void
iser_tgt_svc_offline(idm_svc_t * is)422 iser_tgt_svc_offline(idm_svc_t *is)
423 {
424 	mutex_enter(&is->is_mutex);
425 
426 	iser_unbind_service(is);
427 	mutex_exit(&is->is_mutex);
428 
429 }
430 
431 /*
432  * iser_tgt_conn_connect()
433  * Establish the connection in ic, passed from idm_tgt_conn_finish(), which
434  * is invoked from the SM as a result of an inbound connection request.
435  */
436 /* ARGSUSED */
437 static idm_status_t
iser_tgt_conn_connect(idm_conn_t * ic)438 iser_tgt_conn_connect(idm_conn_t *ic)
439 {
440 	/* No action required */
441 	return (IDM_STATUS_SUCCESS);
442 }
443 
444 /*
445  * iser_tgt_enable_datamover() sets the transport private data on the
446  * idm_conn_t and move the conn stage to indicate logged in.
447  */
448 static idm_status_t
iser_tgt_enable_datamover(idm_conn_t * ic)449 iser_tgt_enable_datamover(idm_conn_t *ic)
450 {
451 	iser_conn_t	*iser_conn;
452 
453 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
454 	mutex_enter(&iser_conn->ic_lock);
455 
456 	iser_conn->ic_stage = ISER_CONN_STAGE_LOGGED_IN;
457 	mutex_exit(&iser_conn->ic_lock);
458 
459 	return (IDM_STATUS_SUCCESS);
460 }
461 
462 /*
463  * iser_ini_enable_datamover() is used by the iSCSI initator to request that a
464  * specified iSCSI connection be transitioned to iSER-assisted mode.
465  * In the case of iSER, the RDMA resources for a reliable connection have
466  * already been allocated at this time, and the 'RDMAExtensions' is set to 'Yes'
467  * so no further negotiations are required at this time.
468  * The initiator now sends the first iSER Message - 'Hello' to the target
469  * and waits for  the 'HelloReply' Message from the target before directing
470  * the initiator to go into the Full Feature Phase.
471  *
472  * No transport op is required on the target side.
473  */
474 static idm_status_t
iser_ini_enable_datamover(idm_conn_t * ic)475 iser_ini_enable_datamover(idm_conn_t *ic)
476 {
477 
478 	iser_conn_t	*iser_conn;
479 	clock_t		delay;
480 	int		status;
481 
482 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
483 
484 	mutex_enter(&iser_conn->ic_lock);
485 	iser_conn->ic_stage = ISER_CONN_STAGE_HELLO_SENT;
486 	mutex_exit(&iser_conn->ic_lock);
487 
488 	/* Send the iSER Hello Message to the target */
489 	status = iser_xfer_hello_msg(iser_conn->ic_chan);
490 	if (status != ISER_STATUS_SUCCESS) {
491 
492 		mutex_enter(&iser_conn->ic_lock);
493 		iser_conn->ic_stage = ISER_CONN_STAGE_HELLO_SENT_FAIL;
494 		mutex_exit(&iser_conn->ic_lock);
495 
496 		return (IDM_STATUS_FAIL);
497 	}
498 
499 	/*
500 	 * Acquire the iser_conn->ic_lock and wait for the iSER HelloReply
501 	 * Message from the target, i.e. iser_conn_stage_t to be set to
502 	 * ISER_CONN_STAGE_HELLOREPLY_RCV. If the handshake does not
503 	 * complete within a specified time period (.5s), then return failure.
504 	 *
505 	 */
506 	delay = ddi_get_lbolt() + drv_usectohz(500000);
507 
508 	mutex_enter(&iser_conn->ic_lock);
509 	while ((iser_conn->ic_stage != ISER_CONN_STAGE_HELLOREPLY_RCV) &&
510 	    (ddi_get_lbolt() < delay)) {
511 
512 		(void) cv_timedwait(&iser_conn->ic_stage_cv,
513 		    &iser_conn->ic_lock, delay);
514 	}
515 
516 	switch (iser_conn->ic_stage) {
517 	case ISER_CONN_STAGE_HELLOREPLY_RCV:
518 		iser_conn->ic_stage = ISER_CONN_STAGE_LOGGED_IN;
519 		mutex_exit(&iser_conn->ic_lock);
520 		/*
521 		 * Return suceess to indicate that the initiator connection can
522 		 * go to the next phase - FFP
523 		 */
524 		return (IDM_STATUS_SUCCESS);
525 	default:
526 		iser_conn->ic_stage = ISER_CONN_STAGE_HELLOREPLY_RCV_FAIL;
527 		mutex_exit(&iser_conn->ic_lock);
528 		return (IDM_STATUS_FAIL);
529 
530 	}
531 
532 	/* STATEMENT_NEVER_REACHED */
533 }
534 
535 /*
536  * iser_free_task_rsrcs()
537  * This routine does not currently need to do anything. It is used in
538  * the sockets transport to explicitly complete any buffers on the task,
539  * but we can rely on our RCaP layer to finish up it's work without any
540  * intervention.
541  */
542 /* ARGSUSED */
543 idm_status_t
iser_free_task_rsrcs(idm_task_t * idt)544 iser_free_task_rsrcs(idm_task_t *idt)
545 {
546 	return (IDM_STATUS_SUCCESS);
547 }
548 
549 /*
550  * iser_negotiate_key_values() validates the key values for this connection
551  */
552 /* ARGSUSED */
553 static kv_status_t
iser_negotiate_key_values(idm_conn_t * ic,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)554 iser_negotiate_key_values(idm_conn_t *ic, nvlist_t *request_nvl,
555     nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
556 {
557 	kv_status_t		kvrc = KV_HANDLED;
558 
559 	/* Process the request nvlist */
560 	kvrc = iser_process_request_nvlist(request_nvl, response_nvl,
561 	    negotiated_nvl);
562 
563 	/* We must be using RDMA, so set the flag on the ic handle */
564 	ic->ic_rdma_extensions = B_TRUE;
565 
566 	return (kvrc);
567 }
568 
569 /* Process a list of key=value pairs from a login request */
570 static kv_status_t
iser_process_request_nvlist(nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)571 iser_process_request_nvlist(nvlist_t *request_nvl, nvlist_t *response_nvl,
572     nvlist_t *negotiated_nvl)
573 {
574 	const idm_kv_xlate_t	*ikvx;
575 	char			*nvp_name;
576 	nvpair_t		*nvp;
577 	nvpair_t		*next_nvp;
578 	kv_status_t		kvrc = KV_HANDLED;
579 	boolean_t		transit = B_TRUE;
580 
581 	/* Process the list */
582 	nvp = nvlist_next_nvpair(request_nvl, NULL);
583 	while (nvp != NULL) {
584 		next_nvp = nvlist_next_nvpair(request_nvl, nvp);
585 
586 		nvp_name = nvpair_name(nvp);
587 		ikvx = idm_lookup_kv_xlate(nvp_name, strlen(nvp_name));
588 
589 		kvrc = iser_handle_key(nvp, ikvx, request_nvl, response_nvl,
590 		    negotiated_nvl);
591 		if (kvrc != KV_HANDLED) {
592 			if (kvrc == KV_HANDLED_NO_TRANSIT) {
593 				/* we countered, clear the transit flag */
594 				transit = B_FALSE;
595 			} else {
596 				/* error, bail out */
597 				break;
598 			}
599 		}
600 
601 		nvp = next_nvp;
602 	}
603 	/*
604 	 * If the current kv_status_t indicates success, we've handled
605 	 * the entire list. Explicitly set kvrc to NO_TRANSIT if we've
606 	 * cleared the transit flag along the way.
607 	 */
608 	if ((kvrc == KV_HANDLED) && (transit == B_FALSE)) {
609 		kvrc = KV_HANDLED_NO_TRANSIT;
610 	}
611 
612 	return (kvrc);
613 }
614 
615 /* Handle a given list, boolean or numerical key=value pair */
616 static kv_status_t
iser_handle_key(nvpair_t * nvp,const idm_kv_xlate_t * ikvx,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)617 iser_handle_key(nvpair_t *nvp, const idm_kv_xlate_t *ikvx,
618     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
619 {
620 	kv_status_t		kvrc = KV_UNHANDLED;
621 	boolean_t		bool_val;
622 	uint64_t		num_val;
623 	int			nvrc;
624 
625 	/* Retrieve values for booleans and numericals */
626 	switch (ikvx->ik_key_id) {
627 		/* Booleans */
628 	case KI_RDMA_EXTENSIONS:
629 	case KI_IMMEDIATE_DATA:
630 		nvrc = nvpair_value_boolean_value(nvp, &bool_val);
631 		ASSERT(nvrc == 0);
632 		break;
633 		/* Numericals */
634 	case KI_INITIATOR_RECV_DATA_SEGMENT_LENGTH:
635 	case KI_TARGET_RECV_DATA_SEGMENT_LENGTH:
636 	case KI_MAX_OUTSTANDING_UNEXPECTED_PDUS:
637 		nvrc = nvpair_value_uint64(nvp, &num_val);
638 		ASSERT(nvrc == 0);
639 		break;
640 	default:
641 		break;
642 	}
643 
644 	/*
645 	 * Now handle the values according to the key name. Keys not
646 	 * specifically handled here will be negotiated by the iscsi
647 	 * target. Negotiated values take effect when
648 	 * iser_notice_key_values gets called.
649 	 */
650 	switch (ikvx->ik_key_id) {
651 	case KI_RDMA_EXTENSIONS:
652 		/* Ensure "Yes" */
653 		kvrc = iser_handle_boolean(nvp, bool_val, ikvx, B_TRUE,
654 		    request_nvl, response_nvl, negotiated_nvl);
655 		break;
656 	case KI_TARGET_RECV_DATA_SEGMENT_LENGTH:
657 		/* Validate the proposed value */
658 		kvrc = iser_handle_numerical(nvp, num_val, ikvx,
659 		    ISER_TARGET_RECV_DATA_SEGMENT_LENGTH_MIN,
660 		    ISER_TARGET_RECV_DATA_SEGMENT_LENGTH_MAX,
661 		    ISER_TARGET_RECV_DATA_SEGMENT_LENGTH_IMPL_MAX,
662 		    request_nvl, response_nvl, negotiated_nvl);
663 		break;
664 	case KI_INITIATOR_RECV_DATA_SEGMENT_LENGTH:
665 		/* Validate the proposed value */
666 		kvrc = iser_handle_numerical(nvp, num_val, ikvx,
667 		    ISER_INITIATOR_RECV_DATA_SEGMENT_LENGTH_MIN,
668 		    ISER_INITIATOR_RECV_DATA_SEGMENT_LENGTH_MAX,
669 		    ISER_INITIATOR_RECV_DATA_SEGMENT_LENGTH_IMPL_MAX,
670 		    request_nvl, response_nvl, negotiated_nvl);
671 		break;
672 	case KI_IMMEDIATE_DATA:
673 		/* Ensure "No" */
674 		kvrc = iser_handle_boolean(nvp, bool_val, ikvx, B_FALSE,
675 		    request_nvl, response_nvl, negotiated_nvl);
676 		break;
677 	case KI_MAX_OUTSTANDING_UNEXPECTED_PDUS:
678 		/* Validate the proposed value */
679 		kvrc = iser_handle_numerical(nvp, num_val, ikvx,
680 		    ISER_MAX_OUTSTANDING_UNEXPECTED_PDUS_MIN,
681 		    ISER_MAX_OUTSTANDING_UNEXPECTED_PDUS_MAX,
682 		    ISER_MAX_OUTSTANDING_UNEXPECTED_PDUS_IMPL_MAX,
683 		    request_nvl, response_nvl, negotiated_nvl);
684 		break;
685 	default:
686 		/*
687 		 * All other keys, including invalid keys, will be
688 		 * handled at the client layer.
689 		 */
690 		kvrc = KV_HANDLED;
691 		break;
692 	}
693 
694 	return (kvrc);
695 }
696 
697 
698 /* Validate a proposed boolean value, and set the alternate if necessary */
699 static kv_status_t
iser_handle_boolean(nvpair_t * nvp,boolean_t value,const idm_kv_xlate_t * ikvx,boolean_t iser_value,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)700 iser_handle_boolean(nvpair_t *nvp, boolean_t value, const idm_kv_xlate_t *ikvx,
701     boolean_t iser_value, nvlist_t *request_nvl, nvlist_t *response_nvl,
702     nvlist_t *negotiated_nvl)
703 {
704 	kv_status_t		kvrc = KV_UNHANDLED;
705 	int			nvrc;
706 	boolean_t		respond = B_FALSE;
707 
708 	if (value != iser_value) {
709 		/*
710 		 * Respond back to initiator with our value, and
711 		 * set the return value to unset the transit bit.
712 		 */
713 		value = iser_value;
714 		nvrc = nvlist_add_boolean_value(negotiated_nvl,
715 		    ikvx->ik_key_name, value);
716 		if (nvrc == 0) {
717 			kvrc = KV_HANDLED_NO_TRANSIT;
718 			respond = B_TRUE;
719 		}
720 
721 	} else {
722 		/* Add this to our negotiated values */
723 		nvrc = nvlist_add_nvpair(negotiated_nvl, nvp);
724 		/* Respond if this is not a declarative */
725 		respond = (ikvx->ik_declarative == B_FALSE);
726 	}
727 
728 	/* Response of Simple-value Negotiation */
729 	if (nvrc == 0 && respond) {
730 		nvrc = nvlist_add_boolean_value(response_nvl,
731 		    ikvx->ik_key_name, value);
732 		/* Remove from the request (we've handled it) */
733 		(void) nvlist_remove_all(request_nvl, ikvx->ik_key_name);
734 	}
735 
736 	if (kvrc == KV_HANDLED_NO_TRANSIT) {
737 		return (kvrc);
738 	}
739 
740 	return (idm_nvstat_to_kvstat(nvrc));
741 }
742 
743 /*
744  * Validate a proposed value against the iSER and/or iSCSI RFC's minimum and
745  * maximum values, and set an alternate, if necessary.  Note that the value
746  * 'iser_max_value" represents our implementation maximum (typically the max).
747  */
748 static kv_status_t
iser_handle_numerical(nvpair_t * nvp,uint64_t value,const idm_kv_xlate_t * ikvx,uint64_t min_value,uint64_t max_value,uint64_t iser_max_value,nvlist_t * request_nvl,nvlist_t * response_nvl,nvlist_t * negotiated_nvl)749 iser_handle_numerical(nvpair_t *nvp, uint64_t value, const idm_kv_xlate_t *ikvx,
750     uint64_t min_value, uint64_t max_value, uint64_t iser_max_value,
751     nvlist_t *request_nvl, nvlist_t *response_nvl, nvlist_t *negotiated_nvl)
752 {
753 	kv_status_t		kvrc = KV_UNHANDLED;
754 	int			nvrc;
755 	boolean_t		respond = B_FALSE;
756 
757 	/* Validate against standard */
758 	if ((value < min_value) || (value > max_value)) {
759 		kvrc = KV_VALUE_ERROR;
760 	} else {
761 		if (value > iser_max_value) {
762 			/*
763 			 * Respond back to initiator with our value, and
764 			 * set the return value to unset the transit bit.
765 			 */
766 			value = iser_max_value;
767 			nvrc = nvlist_add_uint64(negotiated_nvl,
768 			    ikvx->ik_key_name, value);
769 			if (nvrc == 0) {
770 				kvrc = KV_HANDLED_NO_TRANSIT;
771 				respond = B_TRUE;
772 			}
773 		} else {
774 			/* Add this to our negotiated values */
775 			nvrc = nvlist_add_nvpair(negotiated_nvl, nvp);
776 			/* Respond if this is not a declarative */
777 			respond = (ikvx->ik_declarative == B_FALSE);
778 		}
779 
780 		/* Response of Simple-value Negotiation */
781 		if (nvrc == 0 && respond) {
782 			nvrc = nvlist_add_uint64(response_nvl,
783 			    ikvx->ik_key_name, value);
784 			/* Remove from the request (we've handled it) */
785 			(void) nvlist_remove_all(request_nvl,
786 			    ikvx->ik_key_name);
787 		}
788 	}
789 
790 	if (kvrc == KV_HANDLED_NO_TRANSIT) {
791 		return (kvrc);
792 	}
793 
794 	return (idm_nvstat_to_kvstat(nvrc));
795 }
796 
797 /*
798  * iser_declare_key_values() declares the declarative key values for
799  * this connection.
800  */
801 /* ARGSUSED */
802 static kv_status_t
iser_declare_key_values(idm_conn_t * ic,nvlist_t * config_nvl,nvlist_t * outgoing_nvl)803 iser_declare_key_values(idm_conn_t *ic, nvlist_t *config_nvl,
804     nvlist_t *outgoing_nvl)
805 {
806 	kv_status_t		kvrc;
807 	int			nvrc = 0;
808 	int			rc;
809 	uint64_t		uint64_val;
810 
811 	if ((rc = nvlist_lookup_uint64(config_nvl,
812 	    ISER_KV_KEY_NAME_MAX_OUTSTANDING_PDU, &uint64_val)) != ENOENT) {
813 		ASSERT(rc == 0);
814 		if (outgoing_nvl) {
815 			nvrc = nvlist_add_uint64(outgoing_nvl,
816 			    ISER_KV_KEY_NAME_MAX_OUTSTANDING_PDU, uint64_val);
817 		}
818 	}
819 	kvrc = idm_nvstat_to_kvstat(nvrc);
820 	return (kvrc);
821 }
822 
823 /*
824  * iser_notice_key_values() activates the negotiated key values for
825  * this connection.
826  */
827 static void
iser_notice_key_values(idm_conn_t * ic,nvlist_t * negotiated_nvl)828 iser_notice_key_values(idm_conn_t *ic, nvlist_t *negotiated_nvl)
829 {
830 	iser_conn_t		*iser_conn;
831 	boolean_t		boolean_val;
832 	uint64_t		uint64_val;
833 	int			nvrc;
834 	char			*digest_choice_string;
835 
836 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
837 
838 	/*
839 	 * Validate the final negotiated operational parameters,
840 	 * and save a copy.
841 	 */
842 	if ((nvrc = nvlist_lookup_string(negotiated_nvl,
843 	    "HeaderDigest", &digest_choice_string)) != ENOENT) {
844 		ASSERT(nvrc == 0);
845 
846 		/*
847 		 * Per the iSER RFC, override the negotiated value with "None"
848 		 */
849 		iser_conn->ic_op_params.op_header_digest = B_FALSE;
850 	}
851 
852 	if ((nvrc = nvlist_lookup_string(negotiated_nvl,
853 	    "DataDigest", &digest_choice_string)) != ENOENT) {
854 		ASSERT(nvrc == 0);
855 
856 		/*
857 		 * Per the iSER RFC, override the negotiated value with "None"
858 		 */
859 		iser_conn->ic_op_params.op_data_digest = B_FALSE;
860 	}
861 
862 	if ((nvrc = nvlist_lookup_boolean_value(negotiated_nvl,
863 	    "RDMAExtensions", &boolean_val)) != ENOENT) {
864 		ASSERT(nvrc == 0);
865 		iser_conn->ic_op_params.op_rdma_extensions = boolean_val;
866 	}
867 
868 	if ((nvrc = nvlist_lookup_boolean_value(negotiated_nvl,
869 	    "OFMarker", &boolean_val)) != ENOENT) {
870 		ASSERT(nvrc == 0);
871 		/*
872 		 * Per the iSER RFC, override the negotiated value with "No"
873 		 */
874 		iser_conn->ic_op_params.op_ofmarker = B_FALSE;
875 	}
876 
877 	if ((nvrc = nvlist_lookup_boolean_value(negotiated_nvl,
878 	    "IFMarker", &boolean_val)) != ENOENT) {
879 		ASSERT(nvrc == 0);
880 		/*
881 		 * Per the iSER RFC, override the negotiated value with "No"
882 		 */
883 		iser_conn->ic_op_params.op_ifmarker = B_FALSE;
884 	}
885 
886 	if ((nvrc = nvlist_lookup_uint64(negotiated_nvl,
887 	    "TargetRecvDataSegmentLength", &uint64_val)) != ENOENT) {
888 		ASSERT(nvrc == 0);
889 		iser_conn->ic_op_params.op_target_recv_data_segment_length =
890 		    uint64_val;
891 	}
892 
893 	if ((nvrc = nvlist_lookup_uint64(negotiated_nvl,
894 	    "InitiatorRecvDataSegmentLength", &uint64_val)) != ENOENT) {
895 		ASSERT(nvrc == 0);
896 		iser_conn->ic_op_params.op_initiator_recv_data_segment_length =
897 		    uint64_val;
898 	}
899 
900 	if ((nvrc = nvlist_lookup_uint64(negotiated_nvl,
901 	    "MaxOutstandingUnexpectedPDUs", &uint64_val)) != ENOENT) {
902 		ASSERT(nvrc == 0);
903 		iser_conn->ic_op_params.op_max_outstanding_unexpected_pdus =
904 		    uint64_val;
905 	}
906 
907 	/* Test boolean values which are required by RFC 5046 */
908 #ifdef ISER_DEBUG
909 	ASSERT(iser_conn->ic_op_params.op_rdma_extensions == B_TRUE);
910 	ASSERT(iser_conn->ic_op_params.op_header_digest == B_FALSE);
911 	ASSERT(iser_conn->ic_op_params.op_data_digest == B_FALSE);
912 	ASSERT(iser_conn->ic_op_params.op_ofmarker == B_FALSE);
913 	ASSERT(iser_conn->ic_op_params.op_ifmarker == B_FALSE);
914 #endif
915 }
916 
917 
918 /*
919  * iser_conn_is_capable() verifies that the passed connection is provided
920  * for by an iSER-capable link.
921  * NOTE: When utilizing InfiniBand RC as an RCaP, this routine will check
922  * if the link is on IPoIB. This only indicates a chance that the link is
923  * on an RCaP, and thus iSER-capable, since we may be running on an IB-Eth
924  * gateway, or other IB but non-RCaP link. Rather than fully establishing the
925  * link to verify RCaP here, we instead will return B_TRUE
926  * indicating the link is iSER-capable, if the link is IPoIB. If then in
927  * iser_ini_conn_create() the link proves not be RCaP, IDM will fall back
928  * to using the IDM Sockets transport.
929  */
930 /* ARGSUSED */
931 static boolean_t
iser_conn_is_capable(idm_conn_req_t * cr,idm_transport_caps_t * caps)932 iser_conn_is_capable(idm_conn_req_t *cr, idm_transport_caps_t *caps)
933 {
934 	/* A NULL value for laddr indicates implicit source */
935 	return (iser_path_exists(NULL, &cr->cr_ini_dst_addr));
936 }
937 
938 /*
939  * iser_pdu_tx() transmits a Control PDU via the iSER channel. We pull the
940  * channel out of the idm_conn_t passed in, and pass it and the pdu to the
941  * iser_xfer routine.
942  */
943 static void
iser_pdu_tx(idm_conn_t * ic,idm_pdu_t * pdu)944 iser_pdu_tx(idm_conn_t *ic, idm_pdu_t *pdu)
945 {
946 	iser_conn_t	*iser_conn;
947 	iser_status_t	iser_status;
948 
949 	iser_conn = (iser_conn_t *)ic->ic_transport_private;
950 
951 	iser_status = iser_xfer_ctrlpdu(iser_conn->ic_chan, pdu);
952 	if (iser_status != ISER_STATUS_SUCCESS) {
953 		ISER_LOG(CE_WARN, "iser_pdu_tx: failed iser_xfer_ctrlpdu: "
954 		    "ic (0x%p) pdu (0x%p)", (void *) ic, (void *) pdu);
955 		/* Fail this PDU transmission */
956 		idm_pdu_complete(pdu, IDM_STATUS_FAIL);
957 	}
958 
959 	/*
960 	 * We successfully posted this PDU for transmission.
961 	 * The completion handler will invoke idm_pdu_complete()
962 	 * with the completion status. See iser_cq.c for more
963 	 * information.
964 	 */
965 }
966 
967 /*
968  * iser_buf_tx_to_ini() transmits the data buffer encoded in idb to the
969  * initiator to fulfill SCSI Read commands. An iser_xfer routine is invoked
970  * to implement the RDMA operations.
971  *
972  * Caller holds idt->idt_mutex.
973  */
974 static idm_status_t
iser_buf_tx_to_ini(idm_task_t * idt,idm_buf_t * idb)975 iser_buf_tx_to_ini(idm_task_t *idt, idm_buf_t *idb)
976 {
977 	iser_status_t	iser_status;
978 	idm_status_t	idm_status = IDM_STATUS_SUCCESS;
979 
980 	ASSERT(mutex_owned(&idt->idt_mutex));
981 
982 	iser_status = iser_xfer_buf_to_ini(idt, idb);
983 
984 	if (iser_status != ISER_STATUS_SUCCESS) {
985 		ISER_LOG(CE_WARN, "iser_buf_tx_to_ini: failed "
986 		    "iser_xfer_buf_to_ini: idt (0x%p) idb (0x%p)",
987 		    (void *) idt, (void *) idb);
988 		idm_buf_tx_to_ini_done(idt, idb, IDM_STATUS_ABORTED);
989 		return (IDM_STATUS_FAIL);
990 	}
991 
992 	/*
993 	 * iSCSIt's Data Completion Notify callback is invoked from
994 	 * the Work Request Send completion Handler
995 	 */
996 
997 	mutex_exit(&idt->idt_mutex);
998 	return (idm_status);
999 }
1000 
1001 /*
1002  * iser_buf_tx_from_ini() transmits data from the initiator into the buffer
1003  * in idb to fulfill SCSI Write commands. An iser_xfer routine is invoked
1004  * to implement the RDMA operations.
1005  *
1006  * Caller holds idt->idt_mutex.
1007  */
1008 static idm_status_t
iser_buf_rx_from_ini(idm_task_t * idt,idm_buf_t * idb)1009 iser_buf_rx_from_ini(idm_task_t *idt, idm_buf_t *idb)
1010 {
1011 	iser_status_t	iser_status;
1012 	idm_status_t	idm_status = IDM_STATUS_SUCCESS;
1013 
1014 	ASSERT(mutex_owned(&idt->idt_mutex));
1015 
1016 	iser_status = iser_xfer_buf_from_ini(idt, idb);
1017 
1018 	if (iser_status != ISER_STATUS_SUCCESS) {
1019 		ISER_LOG(CE_WARN, "iser_buf_rx_from_ini: failed "
1020 		    "iser_xfer_buf_from_ini: idt (0x%p) idb (0x%p)",
1021 		    (void *) idt, (void *) idb);
1022 		idm_buf_rx_from_ini_done(idt, idb, IDM_STATUS_ABORTED);
1023 		return (IDM_STATUS_FAIL);
1024 	}
1025 
1026 	/*
1027 	 * iSCSIt's Data Completion Notify callback is invoked from
1028 	 * the Work Request Send completion Handler
1029 	 */
1030 
1031 	mutex_exit(&idt->idt_mutex);
1032 	return (idm_status);
1033 }
1034 
1035 /*
1036  * iser_buf_alloc() allocates a buffer and registers it with the IBTF for
1037  * use with iSER. Each HCA has it's own kmem cache for establishing a pool
1038  * of registered buffers, when once initially allocated, will remain
1039  * registered with the HCA. This routine is invoked only on the target,
1040  * where we have the requirement to pre-allocate buffers for the upper layers.
1041  * Note: buflen is compared to ISER_DEFAULT_BUFLEN, and allocation is failed
1042  * if the requested buflen is larger than our default.
1043  */
1044 /* ARGSUSED */
1045 static idm_status_t
iser_buf_alloc(idm_buf_t * idb,uint64_t buflen)1046 iser_buf_alloc(idm_buf_t *idb, uint64_t buflen)
1047 {
1048 	iser_conn_t	*iser_conn;
1049 	iser_hca_t	*iser_hca;
1050 	iser_buf_t	*iser_buf;
1051 
1052 	if (buflen > ISER_DEFAULT_BUFLEN) {
1053 		return (IDM_STATUS_FAIL);
1054 	}
1055 
1056 	iser_conn = (iser_conn_t *)idb->idb_ic->ic_transport_private;
1057 	iser_hca = iser_conn->ic_chan->ic_hca;
1058 
1059 	/*
1060 	 * Allocate a buffer from this HCA's cache. Once initialized, these
1061 	 * will remain allocated and registered (see above).
1062 	 */
1063 	iser_buf = kmem_cache_alloc(iser_hca->iser_buf_cache, KM_NOSLEEP);
1064 	if (iser_buf == NULL) {
1065 		ISER_LOG(CE_NOTE, "iser_buf_alloc: alloc failed");
1066 		return (IDM_STATUS_FAIL);
1067 	}
1068 
1069 	/* Set the allocated data buffer pointer in the IDM buf handle */
1070 	idb->idb_buf = iser_buf->buf;
1071 
1072 	/* Set the private buf and reg handles in the IDM buf handle */
1073 	idb->idb_buf_private = (void *)iser_buf;
1074 	idb->idb_reg_private = (void *)iser_buf->iser_mr;
1075 
1076 	return (IDM_STATUS_SUCCESS);
1077 }
1078 
1079 /*
1080  * iser_buf_free() frees the buffer handle passed in. Note that the cached
1081  * kmem object has an HCA-registered buffer in it which will not be freed.
1082  * This allows us to build up a cache of pre-allocated and registered
1083  * buffers for use on the target.
1084  */
1085 static void
iser_buf_free(idm_buf_t * buf)1086 iser_buf_free(idm_buf_t *buf)
1087 {
1088 	iser_buf_t	*iser_buf;
1089 
1090 	iser_buf = buf->idb_buf_private;
1091 	kmem_cache_free(iser_buf->cache, iser_buf);
1092 }
1093 
1094 /*
1095  * iser_buf_setup() is invoked on the initiator in order to register memory
1096  * on demand for use with the iSER layer.
1097  */
1098 static idm_status_t
iser_buf_setup(idm_buf_t * idb)1099 iser_buf_setup(idm_buf_t *idb)
1100 {
1101 	iser_conn_t	*iser_conn;
1102 	iser_chan_t	*iser_chan;
1103 	iser_hca_t	*iser_hca;
1104 	iser_buf_t	*iser_buf;
1105 	int		status;
1106 
1107 	ASSERT(idb->idb_buf != NULL);
1108 
1109 	iser_conn = (iser_conn_t *)idb->idb_ic->ic_transport_private;
1110 	ASSERT(iser_conn != NULL);
1111 
1112 	iser_hca = iser_conn->ic_chan->ic_hca;
1113 
1114 	iser_chan = iser_conn->ic_chan;
1115 	ASSERT(iser_chan != NULL);
1116 
1117 	/*
1118 	 * Memory registration is known to be slow, so for small
1119 	 * transfers, use pre-registered memory buffers and just
1120 	 * copy the data into/from them at the appropriate time
1121 	 */
1122 	if (idb->idb_buflen < ISER_BCOPY_THRESHOLD) {
1123 		iser_buf =
1124 		    kmem_cache_alloc(iser_hca->iser_buf_cache, KM_NOSLEEP);
1125 
1126 		if (iser_buf == NULL) {
1127 
1128 			/* Fail over to dynamic registration */
1129 			status = iser_reg_rdma_mem(iser_chan->ic_hca, idb);
1130 			idb->idb_bufalloc = B_FALSE;
1131 			return (status);
1132 		}
1133 
1134 		/*
1135 		 * Set the allocated data buffer pointer in the IDM buf handle
1136 		 * Data is to be copied from/to this buffer using bcopy
1137 		 */
1138 		idb->idb_bufptr = idb->idb_buf;
1139 		idb->idb_bufbcopy = B_TRUE;
1140 
1141 		idb->idb_buf = iser_buf->buf;
1142 
1143 		/* Set the private buf and reg handles in the IDM buf handle */
1144 		idb->idb_buf_private = (void *)iser_buf;
1145 		idb->idb_reg_private = (void *)iser_buf->iser_mr;
1146 
1147 		/* Ensure bufalloc'd flag is set */
1148 		idb->idb_bufalloc = B_TRUE;
1149 
1150 		return (IDM_STATUS_SUCCESS);
1151 
1152 	} else {
1153 
1154 		/* Dynamically register the memory passed in on the idb */
1155 		status = iser_reg_rdma_mem(iser_chan->ic_hca, idb);
1156 
1157 		/* Ensure bufalloc'd flag is unset */
1158 		idb->idb_bufalloc = B_FALSE;
1159 
1160 		return (status);
1161 	}
1162 }
1163 
1164 /*
1165  * iser_buf_teardown() is invoked on the initiator in order to register memory
1166  * on demand for use with the iSER layer.
1167  */
1168 static void
iser_buf_teardown(idm_buf_t * idb)1169 iser_buf_teardown(idm_buf_t *idb)
1170 {
1171 	iser_conn_t	*iser_conn;
1172 
1173 	iser_conn = (iser_conn_t *)idb->idb_ic->ic_transport_private;
1174 
1175 	/* Deregister the memory passed in on the idb */
1176 	iser_dereg_rdma_mem(iser_conn->ic_chan->ic_hca, idb);
1177 }
1178