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