xref: /illumos-gate/usr/src/uts/common/io/ib/clients/iser/iser_cq.c (revision 48bbca816818409505a6e214d0911fda44e622e3)
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 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2016 by Delphix. All rights reserved.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/ddi.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <sys/sunddi.h>
33 #include <sys/sdt.h>
34 #include <sys/ib/ibtl/ibti.h>
35 #include <sys/ib/ibtl/ibtl_types.h>
36 
37 #include <sys/ib/clients/iser/iser.h>
38 
39 /*
40  * iser_cq.c
41  *    Routines for completion queue handlers for iSER.
42  */
43 static void iser_msg_handle(iser_chan_t *chan, iser_msg_t *msg);
44 int iser_iscsihdr_handle(iser_chan_t *chan, iser_msg_t *msg);
45 static int iser_ib_poll_send_completions(ibt_cq_hdl_t cq_hdl,
46     iser_chan_t *iser_chan);
47 static int iser_ib_poll_recv_completions(ibt_cq_hdl_t cq_hdl,
48     iser_chan_t *iser_chan);
49 
50 void
iser_ib_sendcq_handler(ibt_cq_hdl_t cq_hdl,void * arg)51 iser_ib_sendcq_handler(ibt_cq_hdl_t cq_hdl, void *arg)
52 {
53 	iser_chan_t	*iser_chan;
54 	ibt_status_t	status;
55 
56 	iser_chan = (iser_chan_t *)arg;
57 
58 	/*
59 	 * Poll for work request completion while successful. If the
60 	 * queue empties or otherwise becomes invalid, stop polling.
61 	 */
62 	do {
63 		status = iser_ib_poll_send_completions(cq_hdl, iser_chan);
64 	} while (status == IBT_SUCCESS);
65 
66 	if (status == IBT_CQ_EMPTY) {
67 		/* We've emptied the CQ, rearm it before we're done here */
68 		status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
69 		if (status != IBT_SUCCESS) {
70 			/* Unexpected error */
71 			ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: "
72 			    "ibt_enable_cq_notify error (%d)", status);
73 			return;
74 		}
75 
76 		/* Now, check for more completions after the rearm */
77 		do {
78 			status = iser_ib_poll_send_completions(
79 			    cq_hdl, iser_chan);
80 		} while (status == IBT_SUCCESS);
81 	}
82 }
83 
84 static int
iser_ib_poll_send_completions(ibt_cq_hdl_t cq_hdl,iser_chan_t * iser_chan)85 iser_ib_poll_send_completions(ibt_cq_hdl_t cq_hdl, iser_chan_t *iser_chan)
86 {
87 	ibt_wc_t	wc[ISER_IB_SCQ_POLL_MAX];
88 	ibt_wrid_t	wrid;
89 	idm_buf_t	*idb = NULL;
90 	idm_task_t	*idt = NULL;
91 	iser_wr_t	*wr = NULL;
92 	int		i;
93 	uint_t		npoll = 0;
94 	ibt_status_t	status;
95 	iser_conn_t	*iser_conn;
96 	idm_status_t	idm_status;
97 	iser_mr_t	*mr;
98 
99 	iser_conn = iser_chan->ic_conn;
100 
101 	/* Poll ISER_IB_SCQ_POLL_MAX completions from the CQ */
102 	status = ibt_poll_cq(cq_hdl, wc, ISER_IB_SCQ_POLL_MAX, &npoll);
103 
104 	if (status != IBT_SUCCESS) {
105 		if (status != IBT_CQ_EMPTY) {
106 			/* Unexpected error */
107 			ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: ibt_poll_cq "
108 			    "unexpected error (%d)", status);
109 		}
110 		/* CQ is empty. Either way, move along... */
111 		return (status);
112 	}
113 
114 	/*
115 	 * Handle each of the completions we've polled
116 	 */
117 	for (i = 0; i < npoll; i++) {
118 
119 		DTRACE_PROBE3(iser__send__cqe, iser_chan_t *, iser_chan,
120 		    ibt_wc_t *, &wc[i], ibt_wc_status_t, wc[i].wc_status);
121 
122 		/* Grab the wrid of the completion */
123 		wrid = wc[i].wc_id;
124 
125 		/* Decrement this channel's SQ posted count */
126 		mutex_enter(&iser_chan->ic_sq_post_lock);
127 		iser_chan->ic_sq_post_count--;
128 		mutex_exit(&iser_chan->ic_sq_post_lock);
129 
130 		/* Pull in the wr handle */
131 		wr = (iser_wr_t *)(uintptr_t)wrid;
132 		ASSERT(wr != NULL);
133 
134 		/* Set an idm_status for return to IDM */
135 		idm_status = (wc[i].wc_status == IBT_WC_SUCCESS) ?
136 		    IDM_STATUS_SUCCESS : IDM_STATUS_FAIL;
137 
138 		/*
139 		 * A non-success status here indicates the QP went
140 		 * into an error state while this WR was being
141 		 * processed. This can also happen when the
142 		 * channel is closed on the remote end. Clean up
143 		 * the resources, then push CE_TRANSPORT_FAIL
144 		 * into IDM.
145 		 */
146 		if (wc[i].wc_status != IBT_WC_SUCCESS) {
147 			/*
148 			 * Free the resources attached to this
149 			 * completion.
150 			 */
151 			if (wr->iw_msg != NULL) {
152 				/* Free iser_msg handle */
153 				iser_msg_free(wr->iw_msg);
154 			}
155 
156 			if (wr->iw_pdu != NULL) {
157 				/* Complete the PDU */
158 				idm_pdu_complete(wr->iw_pdu, idm_status);
159 			}
160 
161 			if (wr->iw_buf != NULL) {
162 				/* Invoke buffer callback */
163 				idb = wr->iw_buf;
164 				mr = ((iser_buf_t *)
165 				    idb->idb_buf_private)->iser_mr;
166 #ifdef DEBUG
167 				bcopy(&wc[i],
168 				    &((iser_buf_t *)idb->idb_buf_private)->
169 				    buf_wc, sizeof (ibt_wc_t));
170 #endif
171 				idt = idb->idb_task_binding;
172 				mutex_enter(&idt->idt_mutex);
173 				if (wr->iw_type == ISER_WR_RDMAW) {
174 					DTRACE_ISCSI_8(xfer__done,
175 					    idm_conn_t *, idt->idt_ic,
176 					    uintptr_t, idb->idb_buf,
177 					    uint32_t, idb->idb_bufoffset,
178 					    uint64_t, mr->is_mrva, uint32_t, 0,
179 					    uint32_t, mr->is_mrrkey,
180 					    uint32_t, idb->idb_xfer_len,
181 					    int, XFER_BUF_TX_TO_INI);
182 					idm_buf_tx_to_ini_done(idt, idb,
183 					    IDM_STATUS_FAIL);
184 				} else { /* ISER_WR_RDMAR */
185 					DTRACE_ISCSI_8(xfer__done,
186 					    idm_conn_t *, idt->idt_ic,
187 					    uintptr_t, idb->idb_buf,
188 					    uint32_t, idb->idb_bufoffset,
189 					    uint64_t, mr->is_mrva, uint32_t, 0,
190 					    uint32_t, mr->is_mrrkey,
191 					    uint32_t, idb->idb_xfer_len,
192 					    int, XFER_BUF_RX_FROM_INI);
193 					idm_buf_rx_from_ini_done(idt, idb,
194 					    IDM_STATUS_FAIL);
195 				}
196 			}
197 
198 			/* Free the iser wr handle */
199 			iser_wr_free(wr);
200 
201 			/*
202 			 * Tell IDM that the channel has gone down,
203 			 * unless it already knows.
204 			 */
205 			mutex_enter(&iser_conn->ic_lock);
206 			switch (iser_conn->ic_stage) {
207 			case ISER_CONN_STAGE_IC_DISCONNECTED:
208 			case ISER_CONN_STAGE_IC_FREED:
209 			case ISER_CONN_STAGE_CLOSING:
210 			case ISER_CONN_STAGE_CLOSED:
211 				break;
212 
213 			default:
214 				idm_conn_event(iser_conn->ic_idmc,
215 				    CE_TRANSPORT_FAIL, idm_status);
216 				iser_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
217 			}
218 			mutex_exit(&iser_conn->ic_lock);
219 
220 			/* Move onto the next completion */
221 			continue;
222 		}
223 
224 		/*
225 		 * For a success status, just invoke the PDU or
226 		 * buffer completion. We use our WR handle's
227 		 * "iw_type" here so that we can properly process
228 		 * because the CQE's opcode is invalid if the status
229 		 * is failed.
230 		 */
231 		switch (wr->iw_type) {
232 		case ISER_WR_SEND:
233 			/* Free the msg handle */
234 			ASSERT(wr->iw_msg != NULL);
235 			iser_msg_free(wr->iw_msg);
236 
237 			if (wr->iw_pdu == NULL) {
238 				/* This is a hello exchange message */
239 				mutex_enter(&iser_conn->ic_lock);
240 				if (iser_conn->ic_stage ==
241 				    ISER_CONN_STAGE_HELLOREPLY_SENT) {
242 					/*
243 					 * We're on the target side,
244 					 * and have just successfully
245 					 * sent the HelloReply msg.
246 					 */
247 					iser_conn->ic_stage =
248 					    ISER_CONN_STAGE_LOGGED_IN;
249 				}
250 				mutex_exit(&iser_conn->ic_lock);
251 			} else {
252 				/* This is a normal control message */
253 				idm_pdu_complete(wr->iw_pdu, idm_status);
254 			}
255 
256 			/* Free the wr handle */
257 			iser_wr_free(wr);
258 
259 			break;
260 
261 		case ISER_WR_RDMAW:
262 		case ISER_WR_RDMAR:
263 			/*
264 			 * Invoke the appropriate callback;
265 			 * the buffer will be freed there.
266 			 */
267 			idb = wr->iw_buf;
268 			mr = ((iser_buf_t *)idb->idb_buf_private)->iser_mr;
269 #ifdef DEBUG
270 			bcopy(&wc[i],
271 			    &((iser_buf_t *)idb->idb_buf_private)->buf_wc,
272 			    sizeof (ibt_wc_t));
273 #endif
274 			idt = idb->idb_task_binding;
275 
276 			mutex_enter(&idt->idt_mutex);
277 			if (wr->iw_type == ISER_WR_RDMAW) {
278 				DTRACE_ISCSI_8(xfer__done,
279 				    idm_conn_t *, idt->idt_ic,
280 				    uintptr_t, idb->idb_buf,
281 				    uint32_t, idb->idb_bufoffset,
282 				    uint64_t, mr->is_mrva, uint32_t, 0,
283 				    uint32_t, mr->is_mrrkey,
284 				    uint32_t, idb->idb_xfer_len,
285 				    int, XFER_BUF_TX_TO_INI);
286 				idm_buf_tx_to_ini_done(idt, idb, idm_status);
287 			} else {
288 				DTRACE_ISCSI_8(xfer__done,
289 				    idm_conn_t *, idt->idt_ic,
290 				    uintptr_t, idb->idb_buf,
291 				    uint32_t, idb->idb_bufoffset,
292 				    uint64_t, mr->is_mrva, uint32_t, 0,
293 				    uint32_t, mr->is_mrrkey,
294 				    uint32_t, idb->idb_xfer_len,
295 				    int, XFER_BUF_RX_FROM_INI);
296 				idm_buf_rx_from_ini_done(idt, idb, idm_status);
297 			}
298 
299 			/* Free the wr handle */
300 			iser_wr_free(wr);
301 
302 			break;
303 
304 		default:
305 			ASSERT(0);
306 			break;
307 		}
308 	}
309 
310 	return (status);
311 }
312 
313 void
iser_ib_recvcq_handler(ibt_cq_hdl_t cq_hdl,void * arg)314 iser_ib_recvcq_handler(ibt_cq_hdl_t cq_hdl, void *arg)
315 {
316 	iser_chan_t	*iser_chan;
317 	ibt_status_t	status;
318 
319 	iser_chan = (iser_chan_t *)arg;
320 
321 	/*
322 	 * Poll for work request completion while successful. If the
323 	 * queue empties or otherwise becomes invalid, stop polling.
324 	 */
325 	do {
326 		status = iser_ib_poll_recv_completions(cq_hdl, iser_chan);
327 	} while (status == IBT_SUCCESS);
328 
329 	if (status == IBT_CQ_EMPTY) {
330 		/* We've emptied the CQ, rearm it before we're done here */
331 		status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
332 		if (status != IBT_SUCCESS) {
333 			/* Unexpected error */
334 			ISER_LOG(CE_NOTE, "iser_ib_recvcq_handler: "
335 			    "ibt_enable_cq_notify error (%d)", status);
336 			return;
337 		}
338 
339 		/* Now, check for more completions after the rearm */
340 		do {
341 			status = iser_ib_poll_recv_completions(
342 			    cq_hdl, iser_chan);
343 		} while (status == IBT_SUCCESS);
344 	}
345 }
346 
347 static int
iser_ib_poll_recv_completions(ibt_cq_hdl_t cq_hdl,iser_chan_t * iser_chan)348 iser_ib_poll_recv_completions(ibt_cq_hdl_t cq_hdl, iser_chan_t *iser_chan)
349 {
350 	ibt_wc_t	wc;
351 	iser_msg_t	*msg;
352 	iser_qp_t	*iser_qp;
353 	int		status;
354 
355 	iser_qp = &(iser_chan->ic_qp);
356 
357 	bzero(&wc, sizeof (ibt_wc_t));
358 	status = ibt_poll_cq(cq_hdl, &wc, 1, NULL);
359 	if (status == IBT_CQ_EMPTY) {
360 		/* CQ is empty, return */
361 		return (status);
362 	}
363 
364 	if (status != IBT_SUCCESS) {
365 		/* Unexpected error */
366 		ISER_LOG(CE_NOTE, "iser_ib_poll_recv_completions: "
367 		    "ibt_poll_cq error (%d)", status);
368 		mutex_enter(&iser_qp->qp_lock);
369 		iser_qp->rq_level--;
370 		mutex_exit(&iser_qp->qp_lock);
371 		/* Free the msg handle (if we got it back) */
372 		if ((msg = (iser_msg_t *)(uintptr_t)wc.wc_id) != NULL) {
373 			iser_msg_free(msg);
374 		}
375 		return (status);
376 	}
377 
378 	/* Retrieve the iSER msg handle */
379 	msg = (iser_msg_t *)(uintptr_t)wc.wc_id;
380 	ASSERT(msg != NULL);
381 
382 	/*
383 	 * Decrement the posted level in the RQ, then check
384 	 * to see if we need to fill the RQ back up (or if
385 	 * we are already on the taskq).
386 	 */
387 	mutex_enter(&iser_chan->ic_conn->ic_lock);
388 	mutex_enter(&iser_qp->qp_lock);
389 	iser_qp->rq_level--;
390 
391 	if ((iser_qp->rq_taskqpending == B_FALSE) &&
392 	    (iser_qp->rq_level <= iser_qp->rq_lwm) &&
393 	    (iser_chan->ic_conn->ic_stage >= ISER_CONN_STAGE_IC_CONNECTED) &&
394 	    (iser_chan->ic_conn->ic_stage <= ISER_CONN_STAGE_LOGGED_IN)) {
395 		/* Set the pending flag and fire off a post_recv */
396 		iser_qp->rq_taskqpending = B_TRUE;
397 		mutex_exit(&iser_qp->qp_lock);
398 
399 		status = iser_ib_post_recv_async(iser_chan->ic_chanhdl);
400 
401 		if (status != DDI_SUCCESS) {
402 			ISER_LOG(CE_NOTE, "iser_ib_poll_recv_completions: "
403 			    "task dispatch failed");
404 			/* Failure to launch, unset the pending flag */
405 			mutex_enter(&iser_qp->qp_lock);
406 			iser_qp->rq_taskqpending = B_FALSE;
407 			mutex_exit(&iser_qp->qp_lock);
408 		}
409 	} else {
410 		mutex_exit(&iser_qp->qp_lock);
411 	}
412 
413 	DTRACE_PROBE3(iser__recv__cqe, iser_chan_t *, iser_chan,
414 	    ibt_wc_t *, &wc, ibt_wc_status_t, wc.wc_status);
415 	if (wc.wc_status != IBT_WC_SUCCESS) {
416 		/*
417 		 * Tell IDM that the channel has gone down,
418 		 * unless it already knows.
419 		 */
420 		switch (iser_chan->ic_conn->ic_stage) {
421 		case ISER_CONN_STAGE_IC_DISCONNECTED:
422 		case ISER_CONN_STAGE_IC_FREED:
423 		case ISER_CONN_STAGE_CLOSING:
424 		case ISER_CONN_STAGE_CLOSED:
425 			break;
426 
427 		default:
428 			idm_conn_event(iser_chan->ic_conn->ic_idmc,
429 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
430 			iser_chan->ic_conn->ic_stage =
431 			    ISER_CONN_STAGE_CLOSING;
432 		}
433 		mutex_exit(&iser_chan->ic_conn->ic_lock);
434 
435 		iser_msg_free(msg);
436 		return (DDI_SUCCESS);
437 	} else {
438 		mutex_exit(&iser_chan->ic_conn->ic_lock);
439 
440 		/*
441 		 * We have an iSER message in, let's handle it.
442 		 * We will free the iser_msg_t later in this path,
443 		 * depending upon the action required.
444 		 */
445 		iser_msg_handle(iser_chan, msg);
446 		return (DDI_SUCCESS);
447 	}
448 }
449 
450 static void
iser_msg_handle(iser_chan_t * chan,iser_msg_t * msg)451 iser_msg_handle(iser_chan_t *chan, iser_msg_t *msg)
452 {
453 	int		opcode;
454 	iser_ctrl_hdr_t	*hdr = NULL;
455 	iser_conn_t	*iser_conn = chan->ic_conn;
456 	int		status;
457 
458 	hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
459 	ASSERT(hdr != NULL);
460 
461 	opcode = hdr->opcode;
462 	if (opcode == ISER_OPCODE_CTRL_TYPE_PDU) {
463 		/*
464 		 * Handle an iSCSI Control PDU iSER message.
465 		 * Note we'll free the msg handle in the PDU callback.
466 		 */
467 		status = iser_iscsihdr_handle(chan, msg);
468 		if (status != DDI_SUCCESS) {
469 			/*
470 			 * We are unable to handle this message, and
471 			 * have no way to recover from this.  Fail the
472 			 * transport.
473 			 */
474 			ISER_LOG(CE_NOTE, "iser_msg_handle: failed "
475 			    "iser_iscsihdr_handle");
476 			iser_msg_free(msg);
477 			idm_conn_event(iser_conn->ic_idmc,
478 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
479 		}
480 	} else if (opcode == ISER_OPCODE_HELLO_MSG) { /* at the target */
481 		/*
482 		 * We are currently not supporting Hello Exchange,
483 		 * since OFED iSER does not. May be revisited.
484 		 */
485 		ASSERT(opcode != ISER_OPCODE_HELLO_MSG);
486 
487 		if (iser_conn->ic_type != ISER_CONN_TYPE_TGT) {
488 			idm_conn_event(iser_conn->ic_idmc,
489 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
490 		}
491 
492 		iser_hello_hdr_t *hello_hdr = (iser_hello_hdr_t *)hdr;
493 
494 		ISER_LOG(CE_NOTE, "received Hello message: opcode[%d], "
495 		    "maxver[%d], minver[%d], iser_ird[%d], msg (0x%p)",
496 		    hello_hdr->opcode, hello_hdr->maxver, hello_hdr->minver,
497 		    ntohs(hello_hdr->iser_ird), (void *)msg);
498 
499 		mutex_enter(&iser_conn->ic_lock);
500 
501 		if (iser_conn->ic_stage != ISER_CONN_STAGE_HELLO_WAIT) {
502 			/* target is not expected to receive a Hello */
503 			idm_conn_event(iser_conn->ic_idmc,
504 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
505 		}
506 
507 		iser_conn->ic_stage = ISER_CONN_STAGE_HELLOREPLY_SENT;
508 		mutex_exit(&iser_conn->ic_lock);
509 
510 		/* Prepare and send a HelloReply message */
511 		status = iser_xfer_helloreply_msg(chan);
512 		if (status != ISER_STATUS_SUCCESS) {
513 
514 			mutex_enter(&iser_conn->ic_lock);
515 			iser_conn->ic_stage =
516 			    ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL;
517 			mutex_exit(&iser_conn->ic_lock);
518 
519 			idm_conn_event(iser_conn->ic_idmc,
520 			    CE_TRANSPORT_FAIL, status);
521 		}
522 
523 		/* Free this msg handle */
524 		iser_msg_free(msg);
525 
526 	} else if (opcode == ISER_OPCODE_HELLOREPLY_MSG) { /* at initiator */
527 
528 		/*
529 		 * We are currently not supporting Hello Exchange,
530 		 * since OFED iSER does not. May be revisited.
531 		 */
532 		ASSERT(opcode != ISER_OPCODE_HELLOREPLY_MSG);
533 
534 		if (iser_conn->ic_type != ISER_CONN_TYPE_INI) {
535 			idm_conn_event(iser_conn->ic_idmc,
536 			    CE_TRANSPORT_FAIL, status);
537 		}
538 
539 		iser_helloreply_hdr_t *hello_hdr = (iser_helloreply_hdr_t *)hdr;
540 
541 		ISER_LOG(CE_NOTE, "received Hello Reply message: opcode[%d], "
542 		    "maxver[%d], curver[%d], iser_ord[%d], msg (0x%p)",
543 		    hello_hdr->opcode, hello_hdr->maxver, hello_hdr->curver,
544 		    ntohs(hello_hdr->iser_ord), (void *)msg);
545 
546 		/* Free this msg handle */
547 		iser_msg_free(msg);
548 
549 		/*
550 		 * Signal the receipt of HelloReply to the waiting thread
551 		 * so that the initiator can proceed to the Full Feature
552 		 * Phase.
553 		 */
554 		mutex_enter(&iser_conn->ic_lock);
555 		iser_conn->ic_stage = ISER_CONN_STAGE_HELLOREPLY_RCV;
556 		cv_signal(&iser_conn->ic_stage_cv);
557 		mutex_exit(&iser_conn->ic_lock);
558 	} else {
559 		/* Protocol error: free the msg handle and fail the session */
560 		ISER_LOG(CE_NOTE, "iser_msg_handle: unsupported opcode (0x%x): "
561 		    "terminating session on IDM handle (0x%p)", opcode,
562 		    (void *) iser_conn->ic_idmc);
563 
564 		iser_msg_free(msg);
565 		idm_conn_event(iser_conn->ic_idmc, CE_TRANSPORT_FAIL,
566 		    IDM_STATUS_FAIL);
567 	}
568 }
569 
570 #define	IDM_PDU_OPCODE(PDU) \
571 	((PDU)->isp_hdr->opcode & ISCSI_OPCODE_MASK)
572 
573 /* network to host translation for 24b integers */
574 static uint32_t
n2h24(uchar_t * ptr)575 n2h24(uchar_t *ptr)
576 {
577 	return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
578 }
579 
580 /* ARGSUSED */
581 static void
iser_rx_pdu_cb(idm_pdu_t * pdu,idm_status_t status)582 iser_rx_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
583 {
584 	/* Free the iser msg handle and the PDU handle */
585 	iser_msg_free((iser_msg_t *)pdu->isp_transport_private);
586 	idm_pdu_free(pdu);
587 }
588 
589 int
iser_iscsihdr_handle(iser_chan_t * chan,iser_msg_t * msg)590 iser_iscsihdr_handle(iser_chan_t *chan, iser_msg_t *msg)
591 {
592 	idm_pdu_t	*pdu;
593 	uint8_t		*iser_hdrp;
594 	uint8_t		*iscsi_hdrp;
595 	iscsi_hdr_t	*bhs;
596 
597 	pdu = idm_pdu_alloc_nosleep(sizeof (iscsi_hdr_t), 0);
598 	pdu->isp_ic = chan->ic_conn->ic_idmc;
599 	ASSERT(pdu->isp_ic != NULL);
600 
601 	/* Set the iser_msg handle into the transport-private field */
602 	pdu->isp_transport_private = (void *)msg;
603 
604 	/* Set up a pointer in the pdu handle to the iSER header */
605 	iser_hdrp = (uint8_t *)(uintptr_t)msg->msg_ds.ds_va;
606 	if (iser_hdrp == NULL) {
607 		ISER_LOG(CE_NOTE, "iser_iscsihdr_handle: iser_hdrp is NULL");
608 		idm_pdu_free(pdu);
609 		return (ISER_STATUS_FAIL);
610 	}
611 	pdu->isp_transport_hdr = (void *)iser_hdrp;
612 	pdu->isp_transport_hdrlen = ISER_HEADER_LENGTH;
613 
614 	/*
615 	 * Set up a pointer to the iSCSI header, which is directly
616 	 * after the iSER header in the message.
617 	 */
618 	iscsi_hdrp = ((uint8_t *)(uintptr_t)msg->msg_ds.ds_va) +
619 	    ISER_HEADER_LENGTH;
620 	if (iscsi_hdrp == NULL) {
621 		ISER_LOG(CE_NOTE, "iser_iscsihdr_handle: iscsi_hdrp is NULL");
622 		idm_pdu_free(pdu);
623 		return (ISER_STATUS_FAIL);
624 	}
625 	pdu->isp_hdr = (iscsi_hdr_t *)(uintptr_t)iscsi_hdrp;
626 
627 	/* Fill in the BHS */
628 	bhs = pdu->isp_hdr;
629 	pdu->isp_hdrlen	= sizeof (iscsi_hdr_t) +
630 	    (bhs->hlength * sizeof (uint32_t));
631 	pdu->isp_datalen = n2h24(bhs->dlength);
632 	pdu->isp_callback = iser_rx_pdu_cb;
633 
634 	/*
635 	 * If datalen > 0, then non-scsi data may be present. Allocate
636 	 * space in the PDU handle and set a pointer to the data.
637 	 */
638 	if (pdu->isp_datalen) {
639 		pdu->isp_data = ((uint8_t *)(uintptr_t)pdu->isp_hdr) +
640 		    pdu->isp_hdrlen;
641 	}
642 
643 	/* Process RX PDU */
644 	idm_pdu_rx(pdu->isp_ic, pdu);
645 
646 	return (DDI_SUCCESS);
647 }
648