xref: /onnv-gate/usr/src/uts/common/io/ib/clients/iser/iser_cq.c (revision 10101:7c5eeed83fdb)
19162SPeter.Dunlap@Sun.COM /*
29162SPeter.Dunlap@Sun.COM  * CDDL HEADER START
39162SPeter.Dunlap@Sun.COM  *
49162SPeter.Dunlap@Sun.COM  * The contents of this file are subject to the terms of the
59162SPeter.Dunlap@Sun.COM  * Common Development and Distribution License (the "License").
69162SPeter.Dunlap@Sun.COM  * You may not use this file except in compliance with the License.
79162SPeter.Dunlap@Sun.COM  *
89162SPeter.Dunlap@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99162SPeter.Dunlap@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109162SPeter.Dunlap@Sun.COM  * See the License for the specific language governing permissions
119162SPeter.Dunlap@Sun.COM  * and limitations under the License.
129162SPeter.Dunlap@Sun.COM  *
139162SPeter.Dunlap@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149162SPeter.Dunlap@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159162SPeter.Dunlap@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169162SPeter.Dunlap@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179162SPeter.Dunlap@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189162SPeter.Dunlap@Sun.COM  *
199162SPeter.Dunlap@Sun.COM  * CDDL HEADER END
209162SPeter.Dunlap@Sun.COM  */
219162SPeter.Dunlap@Sun.COM /*
229162SPeter.Dunlap@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
239162SPeter.Dunlap@Sun.COM  * Use is subject to license terms.
249162SPeter.Dunlap@Sun.COM  */
259162SPeter.Dunlap@Sun.COM 
269162SPeter.Dunlap@Sun.COM #include <sys/types.h>
279162SPeter.Dunlap@Sun.COM #include <sys/ddi.h>
289162SPeter.Dunlap@Sun.COM #include <sys/types.h>
299162SPeter.Dunlap@Sun.COM #include <sys/socket.h>
309162SPeter.Dunlap@Sun.COM #include <netinet/in.h>
319162SPeter.Dunlap@Sun.COM #include <sys/sunddi.h>
329162SPeter.Dunlap@Sun.COM #include <sys/sdt.h>
339162SPeter.Dunlap@Sun.COM #include <sys/ib/ibtl/ibti.h>
349162SPeter.Dunlap@Sun.COM #include <sys/ib/ibtl/ibtl_types.h>
359162SPeter.Dunlap@Sun.COM 
369162SPeter.Dunlap@Sun.COM #include <sys/ib/clients/iser/iser.h>
379162SPeter.Dunlap@Sun.COM 
389162SPeter.Dunlap@Sun.COM /*
399162SPeter.Dunlap@Sun.COM  * iser_cq.c
409162SPeter.Dunlap@Sun.COM  *    Routines for completion queue handlers for iSER.
419162SPeter.Dunlap@Sun.COM  */
429162SPeter.Dunlap@Sun.COM static void iser_msg_handle(iser_chan_t *chan, iser_msg_t *msg);
439162SPeter.Dunlap@Sun.COM int iser_iscsihdr_handle(iser_chan_t *chan, iser_msg_t *msg);
449162SPeter.Dunlap@Sun.COM static int iser_ib_poll_send_completions(ibt_cq_hdl_t cq_hdl,
459162SPeter.Dunlap@Sun.COM     iser_chan_t *iser_chan);
469162SPeter.Dunlap@Sun.COM static int iser_ib_poll_recv_completions(ibt_cq_hdl_t cq_hdl,
479162SPeter.Dunlap@Sun.COM     iser_chan_t *iser_chan);
489162SPeter.Dunlap@Sun.COM 
499162SPeter.Dunlap@Sun.COM void
iser_ib_sendcq_handler(ibt_cq_hdl_t cq_hdl,void * arg)509162SPeter.Dunlap@Sun.COM iser_ib_sendcq_handler(ibt_cq_hdl_t cq_hdl, void *arg)
519162SPeter.Dunlap@Sun.COM {
529162SPeter.Dunlap@Sun.COM 	iser_chan_t	*iser_chan;
539162SPeter.Dunlap@Sun.COM 	ibt_status_t	status;
549162SPeter.Dunlap@Sun.COM 
559162SPeter.Dunlap@Sun.COM 	iser_chan = (iser_chan_t *)arg;
569162SPeter.Dunlap@Sun.COM 
57*10101SPriya.Krishnan@Sun.COM 	/*
58*10101SPriya.Krishnan@Sun.COM 	 * Poll for work request completion while successful. If the
59*10101SPriya.Krishnan@Sun.COM 	 * queue empties or otherwise becomes invalid, stop polling.
60*10101SPriya.Krishnan@Sun.COM 	 */
619162SPeter.Dunlap@Sun.COM 	do {
629162SPeter.Dunlap@Sun.COM 		status = iser_ib_poll_send_completions(cq_hdl, iser_chan);
63*10101SPriya.Krishnan@Sun.COM 	} while (status == IBT_SUCCESS);
649162SPeter.Dunlap@Sun.COM 
65*10101SPriya.Krishnan@Sun.COM 	if (status == IBT_CQ_EMPTY) {
66*10101SPriya.Krishnan@Sun.COM 		/* We've emptied the CQ, rearm it before we're done here */
67*10101SPriya.Krishnan@Sun.COM 		status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
68*10101SPriya.Krishnan@Sun.COM 		if (status != IBT_SUCCESS) {
69*10101SPriya.Krishnan@Sun.COM 			/* Unexpected error */
70*10101SPriya.Krishnan@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: "
71*10101SPriya.Krishnan@Sun.COM 			    "ibt_enable_cq_notify error (%d)", status);
72*10101SPriya.Krishnan@Sun.COM 			return;
73*10101SPriya.Krishnan@Sun.COM 		}
74*10101SPriya.Krishnan@Sun.COM 
75*10101SPriya.Krishnan@Sun.COM 		/* Now, check for more completions after the rearm */
76*10101SPriya.Krishnan@Sun.COM 		do {
77*10101SPriya.Krishnan@Sun.COM 			status = iser_ib_poll_send_completions(
78*10101SPriya.Krishnan@Sun.COM 			    cq_hdl, iser_chan);
79*10101SPriya.Krishnan@Sun.COM 		} while (status == IBT_SUCCESS);
809162SPeter.Dunlap@Sun.COM 	}
819162SPeter.Dunlap@Sun.COM }
829162SPeter.Dunlap@Sun.COM 
839162SPeter.Dunlap@Sun.COM static int
iser_ib_poll_send_completions(ibt_cq_hdl_t cq_hdl,iser_chan_t * iser_chan)849162SPeter.Dunlap@Sun.COM iser_ib_poll_send_completions(ibt_cq_hdl_t cq_hdl, iser_chan_t *iser_chan)
859162SPeter.Dunlap@Sun.COM {
869162SPeter.Dunlap@Sun.COM 	ibt_wc_t	wc[ISER_IB_SCQ_POLL_MAX];
879162SPeter.Dunlap@Sun.COM 	ibt_wrid_t	wrid;
889162SPeter.Dunlap@Sun.COM 	idm_buf_t	*idb = NULL;
899162SPeter.Dunlap@Sun.COM 	idm_task_t	*idt = NULL;
909162SPeter.Dunlap@Sun.COM 	iser_wr_t	*wr = NULL;
919162SPeter.Dunlap@Sun.COM 	int		i;
929162SPeter.Dunlap@Sun.COM 	uint_t		npoll = 0;
939162SPeter.Dunlap@Sun.COM 	ibt_status_t	status;
949162SPeter.Dunlap@Sun.COM 	iser_conn_t	*iser_conn;
959162SPeter.Dunlap@Sun.COM 	idm_status_t	idm_status;
969721SPriya.Krishnan@Sun.COM 	iser_mr_t	*mr;
979162SPeter.Dunlap@Sun.COM 
989162SPeter.Dunlap@Sun.COM 	iser_conn = iser_chan->ic_conn;
999162SPeter.Dunlap@Sun.COM 
100*10101SPriya.Krishnan@Sun.COM 	/* Poll ISER_IB_SCQ_POLL_MAX completions from the CQ */
1019162SPeter.Dunlap@Sun.COM 	status = ibt_poll_cq(cq_hdl, wc, ISER_IB_SCQ_POLL_MAX, &npoll);
1029162SPeter.Dunlap@Sun.COM 
1039162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
1049162SPeter.Dunlap@Sun.COM 		if (status != IBT_CQ_EMPTY) {
1059162SPeter.Dunlap@Sun.COM 			/* Unexpected error */
1069162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_sendcq_handler: ibt_poll_cq "
107*10101SPriya.Krishnan@Sun.COM 			    "unexpected error (%d)", status);
1089162SPeter.Dunlap@Sun.COM 		}
1099162SPeter.Dunlap@Sun.COM 		/* CQ is empty. Either way, move along... */
1109162SPeter.Dunlap@Sun.COM 		return (status);
1119162SPeter.Dunlap@Sun.COM 	}
1129162SPeter.Dunlap@Sun.COM 
1139162SPeter.Dunlap@Sun.COM 	/*
1149162SPeter.Dunlap@Sun.COM 	 * Handle each of the completions we've polled
1159162SPeter.Dunlap@Sun.COM 	 */
1169162SPeter.Dunlap@Sun.COM 	for (i = 0; i < npoll; i++) {
1179162SPeter.Dunlap@Sun.COM 
1189162SPeter.Dunlap@Sun.COM 		DTRACE_PROBE3(iser__send__cqe, iser_chan_t *, iser_chan,
1199162SPeter.Dunlap@Sun.COM 		    ibt_wc_t *, &wc[i], ibt_wc_status_t, wc[i].wc_status);
1209162SPeter.Dunlap@Sun.COM 
1219162SPeter.Dunlap@Sun.COM 		/* Grab the wrid of the completion */
1229162SPeter.Dunlap@Sun.COM 		wrid = wc[i].wc_id;
1239162SPeter.Dunlap@Sun.COM 
1249162SPeter.Dunlap@Sun.COM 		/* Decrement this channel's SQ posted count */
1259162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_chan->ic_sq_post_lock);
1269162SPeter.Dunlap@Sun.COM 		iser_chan->ic_sq_post_count--;
1279162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_chan->ic_sq_post_lock);
1289162SPeter.Dunlap@Sun.COM 
1299162SPeter.Dunlap@Sun.COM 		/* Pull in the wr handle */
1309162SPeter.Dunlap@Sun.COM 		wr = (iser_wr_t *)(uintptr_t)wrid;
1319162SPeter.Dunlap@Sun.COM 		ASSERT(wr != NULL);
1329162SPeter.Dunlap@Sun.COM 
1339162SPeter.Dunlap@Sun.COM 		/* Set an idm_status for return to IDM */
1349162SPeter.Dunlap@Sun.COM 		idm_status = (wc[i].wc_status == IBT_WC_SUCCESS) ?
1359162SPeter.Dunlap@Sun.COM 		    IDM_STATUS_SUCCESS : IDM_STATUS_FAIL;
1369162SPeter.Dunlap@Sun.COM 
1379162SPeter.Dunlap@Sun.COM 		/*
1389162SPeter.Dunlap@Sun.COM 		 * A non-success status here indicates the QP went
1399162SPeter.Dunlap@Sun.COM 		 * into an error state while this WR was being
1409162SPeter.Dunlap@Sun.COM 		 * processed. This can also happen when the
1419162SPeter.Dunlap@Sun.COM 		 * channel is closed on the remote end. Clean up
1429162SPeter.Dunlap@Sun.COM 		 * the resources, then push CE_TRANSPORT_FAIL
1439162SPeter.Dunlap@Sun.COM 		 * into IDM.
1449162SPeter.Dunlap@Sun.COM 		 */
1459162SPeter.Dunlap@Sun.COM 		if (wc[i].wc_status != IBT_WC_SUCCESS) {
1469162SPeter.Dunlap@Sun.COM 			/*
1479162SPeter.Dunlap@Sun.COM 			 * Free the resources attached to this
1489162SPeter.Dunlap@Sun.COM 			 * completion.
1499162SPeter.Dunlap@Sun.COM 			 */
1509162SPeter.Dunlap@Sun.COM 			if (wr->iw_msg != NULL) {
1519162SPeter.Dunlap@Sun.COM 				/* Free iser_msg handle */
1529162SPeter.Dunlap@Sun.COM 				iser_msg_free(wr->iw_msg);
1539162SPeter.Dunlap@Sun.COM 			}
1549162SPeter.Dunlap@Sun.COM 
1559162SPeter.Dunlap@Sun.COM 			if (wr->iw_pdu != NULL) {
1569162SPeter.Dunlap@Sun.COM 				/* Complete the PDU */
1579162SPeter.Dunlap@Sun.COM 				idm_pdu_complete(wr->iw_pdu, idm_status);
1589162SPeter.Dunlap@Sun.COM 			}
1599162SPeter.Dunlap@Sun.COM 
1609162SPeter.Dunlap@Sun.COM 			if (wr->iw_buf != NULL) {
1619162SPeter.Dunlap@Sun.COM 				/* Invoke buffer callback */
1629162SPeter.Dunlap@Sun.COM 				idb = wr->iw_buf;
1639721SPriya.Krishnan@Sun.COM 				mr = ((iser_buf_t *)
1649721SPriya.Krishnan@Sun.COM 				    idb->idb_buf_private)->iser_mr;
1659162SPeter.Dunlap@Sun.COM #ifdef DEBUG
1669162SPeter.Dunlap@Sun.COM 				bcopy(&wc[i],
1679162SPeter.Dunlap@Sun.COM 				    &((iser_buf_t *)idb->idb_buf_private)->
1689162SPeter.Dunlap@Sun.COM 				    buf_wc, sizeof (ibt_wc_t));
1699162SPeter.Dunlap@Sun.COM #endif
1709162SPeter.Dunlap@Sun.COM 				idt = idb->idb_task_binding;
1719162SPeter.Dunlap@Sun.COM 				mutex_enter(&idt->idt_mutex);
1729162SPeter.Dunlap@Sun.COM 				if (wr->iw_type == ISER_WR_RDMAW) {
1739721SPriya.Krishnan@Sun.COM 					DTRACE_ISCSI_8(xfer__done,
1749721SPriya.Krishnan@Sun.COM 					    idm_conn_t *, idt->idt_ic,
1759721SPriya.Krishnan@Sun.COM 					    uintptr_t, idb->idb_buf,
1769721SPriya.Krishnan@Sun.COM 					    uint32_t, idb->idb_bufoffset,
1779721SPriya.Krishnan@Sun.COM 					    uint64_t, mr->is_mrva, uint32_t, 0,
1789721SPriya.Krishnan@Sun.COM 					    uint32_t, mr->is_mrrkey,
1799721SPriya.Krishnan@Sun.COM 					    uint32_t, idb->idb_xfer_len,
1809721SPriya.Krishnan@Sun.COM 					    int, XFER_BUF_TX_TO_INI);
1819162SPeter.Dunlap@Sun.COM 					idm_buf_tx_to_ini_done(idt, idb,
1829162SPeter.Dunlap@Sun.COM 					    IDM_STATUS_FAIL);
1839162SPeter.Dunlap@Sun.COM 				} else { /* ISER_WR_RDMAR */
1849721SPriya.Krishnan@Sun.COM 					DTRACE_ISCSI_8(xfer__done,
1859721SPriya.Krishnan@Sun.COM 					    idm_conn_t *, idt->idt_ic,
1869721SPriya.Krishnan@Sun.COM 					    uintptr_t, idb->idb_buf,
1879721SPriya.Krishnan@Sun.COM 					    uint32_t, idb->idb_bufoffset,
1889721SPriya.Krishnan@Sun.COM 					    uint64_t, mr->is_mrva, uint32_t, 0,
1899721SPriya.Krishnan@Sun.COM 					    uint32_t, mr->is_mrrkey,
1909721SPriya.Krishnan@Sun.COM 					    uint32_t, idb->idb_xfer_len,
1919721SPriya.Krishnan@Sun.COM 					    int, XFER_BUF_RX_FROM_INI);
1929162SPeter.Dunlap@Sun.COM 					idm_buf_rx_from_ini_done(idt, idb,
1939162SPeter.Dunlap@Sun.COM 					    IDM_STATUS_FAIL);
1949162SPeter.Dunlap@Sun.COM 				}
1959162SPeter.Dunlap@Sun.COM 			}
1969162SPeter.Dunlap@Sun.COM 
1979162SPeter.Dunlap@Sun.COM 			/* Free the iser wr handle */
1989162SPeter.Dunlap@Sun.COM 			iser_wr_free(wr);
1999162SPeter.Dunlap@Sun.COM 
2009162SPeter.Dunlap@Sun.COM 			/*
2019162SPeter.Dunlap@Sun.COM 			 * Tell IDM that the channel has gone down,
2029162SPeter.Dunlap@Sun.COM 			 * unless he already knows.
2039162SPeter.Dunlap@Sun.COM 			 */
2049162SPeter.Dunlap@Sun.COM 			mutex_enter(&iser_conn->ic_lock);
2059162SPeter.Dunlap@Sun.COM 			switch (iser_conn->ic_stage) {
2069162SPeter.Dunlap@Sun.COM 			case ISER_CONN_STAGE_IC_DISCONNECTED:
2079162SPeter.Dunlap@Sun.COM 			case ISER_CONN_STAGE_IC_FREED:
2089162SPeter.Dunlap@Sun.COM 			case ISER_CONN_STAGE_CLOSING:
2099162SPeter.Dunlap@Sun.COM 			case ISER_CONN_STAGE_CLOSED:
2109162SPeter.Dunlap@Sun.COM 				break;
2119162SPeter.Dunlap@Sun.COM 
2129162SPeter.Dunlap@Sun.COM 			default:
2139162SPeter.Dunlap@Sun.COM 				idm_conn_event(iser_conn->ic_idmc,
2149162SPeter.Dunlap@Sun.COM 				    CE_TRANSPORT_FAIL, idm_status);
2159162SPeter.Dunlap@Sun.COM 				iser_conn->ic_stage = ISER_CONN_STAGE_CLOSING;
2169162SPeter.Dunlap@Sun.COM 			}
2179162SPeter.Dunlap@Sun.COM 			mutex_exit(&iser_conn->ic_lock);
2189162SPeter.Dunlap@Sun.COM 
2199162SPeter.Dunlap@Sun.COM 			/* Move onto the next completion */
2209162SPeter.Dunlap@Sun.COM 			continue;
2219162SPeter.Dunlap@Sun.COM 		}
2229162SPeter.Dunlap@Sun.COM 
2239162SPeter.Dunlap@Sun.COM 		/*
2249162SPeter.Dunlap@Sun.COM 		 * For a success status, just invoke the PDU or
2259162SPeter.Dunlap@Sun.COM 		 * buffer completion. We use our WR handle's
2269162SPeter.Dunlap@Sun.COM 		 * "iw_type" here so that we can properly process
2279162SPeter.Dunlap@Sun.COM 		 * because the CQE's opcode is invalid if the status
2289162SPeter.Dunlap@Sun.COM 		 * is failed.
2299162SPeter.Dunlap@Sun.COM 		 */
2309162SPeter.Dunlap@Sun.COM 		switch (wr->iw_type) {
2319162SPeter.Dunlap@Sun.COM 		case ISER_WR_SEND:
2329162SPeter.Dunlap@Sun.COM 			/* Free the msg handle */
2339162SPeter.Dunlap@Sun.COM 			ASSERT(wr->iw_msg != NULL);
2349162SPeter.Dunlap@Sun.COM 			iser_msg_free(wr->iw_msg);
2359162SPeter.Dunlap@Sun.COM 
2369162SPeter.Dunlap@Sun.COM 			if (wr->iw_pdu == NULL) {
2379162SPeter.Dunlap@Sun.COM 				/* This is a hello exchange message */
2389162SPeter.Dunlap@Sun.COM 				mutex_enter(&iser_conn->ic_lock);
2399162SPeter.Dunlap@Sun.COM 				if (iser_conn->ic_stage ==
2409162SPeter.Dunlap@Sun.COM 				    ISER_CONN_STAGE_HELLOREPLY_SENT) {
2419162SPeter.Dunlap@Sun.COM 					/*
2429162SPeter.Dunlap@Sun.COM 					 * We're on the target side,
2439162SPeter.Dunlap@Sun.COM 					 * and have just successfully
2449162SPeter.Dunlap@Sun.COM 					 * sent the HelloReply msg.
2459162SPeter.Dunlap@Sun.COM 					 */
2469162SPeter.Dunlap@Sun.COM 					iser_conn->ic_stage =
2479162SPeter.Dunlap@Sun.COM 					    ISER_CONN_STAGE_LOGGED_IN;
2489162SPeter.Dunlap@Sun.COM 				}
2499162SPeter.Dunlap@Sun.COM 				mutex_exit(&iser_conn->ic_lock);
2509162SPeter.Dunlap@Sun.COM 			} else {
2519162SPeter.Dunlap@Sun.COM 				/* This is a normal control message */
2529162SPeter.Dunlap@Sun.COM 				idm_pdu_complete(wr->iw_pdu, idm_status);
2539162SPeter.Dunlap@Sun.COM 			}
2549162SPeter.Dunlap@Sun.COM 
2559162SPeter.Dunlap@Sun.COM 			/* Free the wr handle */
2569162SPeter.Dunlap@Sun.COM 			iser_wr_free(wr);
2579162SPeter.Dunlap@Sun.COM 
2589162SPeter.Dunlap@Sun.COM 			break;
2599162SPeter.Dunlap@Sun.COM 
2609162SPeter.Dunlap@Sun.COM 		case ISER_WR_RDMAW:
2619162SPeter.Dunlap@Sun.COM 		case ISER_WR_RDMAR:
2629162SPeter.Dunlap@Sun.COM 			/*
2639162SPeter.Dunlap@Sun.COM 			 * Invoke the appropriate callback;
2649162SPeter.Dunlap@Sun.COM 			 * the buffer will be freed there.
2659162SPeter.Dunlap@Sun.COM 			 */
2669162SPeter.Dunlap@Sun.COM 			idb = wr->iw_buf;
2679721SPriya.Krishnan@Sun.COM 			mr = ((iser_buf_t *)idb->idb_buf_private)->iser_mr;
2689162SPeter.Dunlap@Sun.COM #ifdef DEBUG
2699162SPeter.Dunlap@Sun.COM 			bcopy(&wc[i],
2709162SPeter.Dunlap@Sun.COM 			    &((iser_buf_t *)idb->idb_buf_private)->buf_wc,
2719162SPeter.Dunlap@Sun.COM 			    sizeof (ibt_wc_t));
2729162SPeter.Dunlap@Sun.COM #endif
2739162SPeter.Dunlap@Sun.COM 			idt = idb->idb_task_binding;
2749162SPeter.Dunlap@Sun.COM 
2759162SPeter.Dunlap@Sun.COM 			mutex_enter(&idt->idt_mutex);
2769162SPeter.Dunlap@Sun.COM 			if (wr->iw_type == ISER_WR_RDMAW) {
2779721SPriya.Krishnan@Sun.COM 				DTRACE_ISCSI_8(xfer__done,
2789721SPriya.Krishnan@Sun.COM 				    idm_conn_t *, idt->idt_ic,
2799721SPriya.Krishnan@Sun.COM 				    uintptr_t, idb->idb_buf,
2809721SPriya.Krishnan@Sun.COM 				    uint32_t, idb->idb_bufoffset,
2819721SPriya.Krishnan@Sun.COM 				    uint64_t, mr->is_mrva, uint32_t, 0,
2829721SPriya.Krishnan@Sun.COM 				    uint32_t, mr->is_mrrkey,
2839721SPriya.Krishnan@Sun.COM 				    uint32_t, idb->idb_xfer_len,
2849721SPriya.Krishnan@Sun.COM 				    int, XFER_BUF_TX_TO_INI);
2859162SPeter.Dunlap@Sun.COM 				idm_buf_tx_to_ini_done(idt, idb, idm_status);
2869162SPeter.Dunlap@Sun.COM 			} else {
2879721SPriya.Krishnan@Sun.COM 				DTRACE_ISCSI_8(xfer__done,
2889721SPriya.Krishnan@Sun.COM 				    idm_conn_t *, idt->idt_ic,
2899721SPriya.Krishnan@Sun.COM 				    uintptr_t, idb->idb_buf,
2909721SPriya.Krishnan@Sun.COM 				    uint32_t, idb->idb_bufoffset,
2919721SPriya.Krishnan@Sun.COM 				    uint64_t, mr->is_mrva, uint32_t, 0,
2929721SPriya.Krishnan@Sun.COM 				    uint32_t, mr->is_mrrkey,
2939721SPriya.Krishnan@Sun.COM 				    uint32_t, idb->idb_xfer_len,
2949721SPriya.Krishnan@Sun.COM 				    int, XFER_BUF_RX_FROM_INI);
2959162SPeter.Dunlap@Sun.COM 				idm_buf_rx_from_ini_done(idt, idb, idm_status);
2969162SPeter.Dunlap@Sun.COM 			}
2979162SPeter.Dunlap@Sun.COM 
2989162SPeter.Dunlap@Sun.COM 			/* Free the wr handle */
2999162SPeter.Dunlap@Sun.COM 			iser_wr_free(wr);
3009162SPeter.Dunlap@Sun.COM 
3019162SPeter.Dunlap@Sun.COM 			break;
3029162SPeter.Dunlap@Sun.COM 
3039162SPeter.Dunlap@Sun.COM 		default:
3049162SPeter.Dunlap@Sun.COM 			ASSERT(0);
3059162SPeter.Dunlap@Sun.COM 			break;
3069162SPeter.Dunlap@Sun.COM 		}
3079162SPeter.Dunlap@Sun.COM 	}
3089162SPeter.Dunlap@Sun.COM 
3099162SPeter.Dunlap@Sun.COM 	return (status);
3109162SPeter.Dunlap@Sun.COM }
3119162SPeter.Dunlap@Sun.COM 
3129162SPeter.Dunlap@Sun.COM void
iser_ib_recvcq_handler(ibt_cq_hdl_t cq_hdl,void * arg)3139162SPeter.Dunlap@Sun.COM iser_ib_recvcq_handler(ibt_cq_hdl_t cq_hdl, void *arg)
3149162SPeter.Dunlap@Sun.COM {
3159162SPeter.Dunlap@Sun.COM 	iser_chan_t	*iser_chan;
3169162SPeter.Dunlap@Sun.COM 	ibt_status_t	status;
3179162SPeter.Dunlap@Sun.COM 
3189162SPeter.Dunlap@Sun.COM 	iser_chan = (iser_chan_t *)arg;
3199162SPeter.Dunlap@Sun.COM 
320*10101SPriya.Krishnan@Sun.COM 	/*
321*10101SPriya.Krishnan@Sun.COM 	 * Poll for work request completion while successful. If the
322*10101SPriya.Krishnan@Sun.COM 	 * queue empties or otherwise becomes invalid, stop polling.
323*10101SPriya.Krishnan@Sun.COM 	 */
3249162SPeter.Dunlap@Sun.COM 	do {
3259162SPeter.Dunlap@Sun.COM 		status = iser_ib_poll_recv_completions(cq_hdl, iser_chan);
326*10101SPriya.Krishnan@Sun.COM 	} while (status == IBT_SUCCESS);
3279162SPeter.Dunlap@Sun.COM 
328*10101SPriya.Krishnan@Sun.COM 	if (status == IBT_CQ_EMPTY) {
329*10101SPriya.Krishnan@Sun.COM 		/* We've emptied the CQ, rearm it before we're done here */
330*10101SPriya.Krishnan@Sun.COM 		status = ibt_enable_cq_notify(cq_hdl, IBT_NEXT_COMPLETION);
331*10101SPriya.Krishnan@Sun.COM 		if (status != IBT_SUCCESS) {
332*10101SPriya.Krishnan@Sun.COM 			/* Unexpected error */
333*10101SPriya.Krishnan@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_recvcq_handler: "
334*10101SPriya.Krishnan@Sun.COM 			    "ibt_enable_cq_notify error (%d)", status);
335*10101SPriya.Krishnan@Sun.COM 			return;
336*10101SPriya.Krishnan@Sun.COM 		}
337*10101SPriya.Krishnan@Sun.COM 
338*10101SPriya.Krishnan@Sun.COM 		/* Now, check for more completions after the rearm */
339*10101SPriya.Krishnan@Sun.COM 		do {
340*10101SPriya.Krishnan@Sun.COM 			status = iser_ib_poll_recv_completions(
341*10101SPriya.Krishnan@Sun.COM 			    cq_hdl, iser_chan);
342*10101SPriya.Krishnan@Sun.COM 		} while (status == IBT_SUCCESS);
3439162SPeter.Dunlap@Sun.COM 	}
3449162SPeter.Dunlap@Sun.COM }
3459162SPeter.Dunlap@Sun.COM 
3469162SPeter.Dunlap@Sun.COM static int
iser_ib_poll_recv_completions(ibt_cq_hdl_t cq_hdl,iser_chan_t * iser_chan)3479162SPeter.Dunlap@Sun.COM iser_ib_poll_recv_completions(ibt_cq_hdl_t cq_hdl, iser_chan_t *iser_chan)
3489162SPeter.Dunlap@Sun.COM {
3499162SPeter.Dunlap@Sun.COM 	ibt_wc_t	wc;
3509162SPeter.Dunlap@Sun.COM 	iser_msg_t	*msg;
3519162SPeter.Dunlap@Sun.COM 	iser_qp_t	*iser_qp;
3529162SPeter.Dunlap@Sun.COM 	int		status;
3539162SPeter.Dunlap@Sun.COM 
3549162SPeter.Dunlap@Sun.COM 	iser_qp = &(iser_chan->ic_qp);
3559162SPeter.Dunlap@Sun.COM 
3569162SPeter.Dunlap@Sun.COM 	bzero(&wc, sizeof (ibt_wc_t));
3579162SPeter.Dunlap@Sun.COM 	status = ibt_poll_cq(cq_hdl, &wc, 1, NULL);
3589162SPeter.Dunlap@Sun.COM 	if (status == IBT_CQ_EMPTY) {
3599162SPeter.Dunlap@Sun.COM 		/* CQ is empty, return */
3609162SPeter.Dunlap@Sun.COM 		return (status);
3619162SPeter.Dunlap@Sun.COM 	}
3629162SPeter.Dunlap@Sun.COM 
3639162SPeter.Dunlap@Sun.COM 	if (status != IBT_SUCCESS) {
3649162SPeter.Dunlap@Sun.COM 		/* Unexpected error */
3659162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_ib_poll_recv_completions: "
3669162SPeter.Dunlap@Sun.COM 		    "ibt_poll_cq error (%d)", status);
3679162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_qp->qp_lock);
3689162SPeter.Dunlap@Sun.COM 		iser_qp->rq_level--;
3699162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
3709162SPeter.Dunlap@Sun.COM 		/* Free the msg handle (if we got it back) */
3719162SPeter.Dunlap@Sun.COM 		if ((msg = (iser_msg_t *)(uintptr_t)wc.wc_id) != NULL) {
3729162SPeter.Dunlap@Sun.COM 			iser_msg_free(msg);
3739162SPeter.Dunlap@Sun.COM 		}
3749162SPeter.Dunlap@Sun.COM 		return (status);
3759162SPeter.Dunlap@Sun.COM 	}
3769162SPeter.Dunlap@Sun.COM 
3779162SPeter.Dunlap@Sun.COM 	/* Retrieve the iSER msg handle */
3789162SPeter.Dunlap@Sun.COM 	msg = (iser_msg_t *)(uintptr_t)wc.wc_id;
3799162SPeter.Dunlap@Sun.COM 	ASSERT(msg != NULL);
3809162SPeter.Dunlap@Sun.COM 
3819162SPeter.Dunlap@Sun.COM 	/*
3829162SPeter.Dunlap@Sun.COM 	 * Decrement the posted level in the RQ, then check
3839162SPeter.Dunlap@Sun.COM 	 * to see if we need to fill the RQ back up (or if
3849162SPeter.Dunlap@Sun.COM 	 * we are already on the taskq).
3859162SPeter.Dunlap@Sun.COM 	 */
3869247SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_chan->ic_conn->ic_lock);
3879162SPeter.Dunlap@Sun.COM 	mutex_enter(&iser_qp->qp_lock);
3889162SPeter.Dunlap@Sun.COM 	iser_qp->rq_level--;
3899162SPeter.Dunlap@Sun.COM 
3909162SPeter.Dunlap@Sun.COM 	if ((iser_qp->rq_taskqpending == B_FALSE) &&
3919586SPeter.Dunlap@Sun.COM 	    (iser_qp->rq_level <= iser_qp->rq_lwm) &&
3929586SPeter.Dunlap@Sun.COM 	    (iser_chan->ic_conn->ic_stage >= ISER_CONN_STAGE_IC_CONNECTED) &&
3939586SPeter.Dunlap@Sun.COM 	    (iser_chan->ic_conn->ic_stage <= ISER_CONN_STAGE_LOGGED_IN)) {
3949162SPeter.Dunlap@Sun.COM 		/* Set the pending flag and fire off a post_recv */
3959162SPeter.Dunlap@Sun.COM 		iser_qp->rq_taskqpending = B_TRUE;
3969162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
3979162SPeter.Dunlap@Sun.COM 
3989247SPeter.Dunlap@Sun.COM 		status = iser_ib_post_recv_async(iser_chan->ic_chanhdl);
3999162SPeter.Dunlap@Sun.COM 
4009162SPeter.Dunlap@Sun.COM 		if (status != DDI_SUCCESS) {
4019162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_ib_poll_recv_completions: "
4029162SPeter.Dunlap@Sun.COM 			    "task dispatch failed");
4039162SPeter.Dunlap@Sun.COM 			/* Failure to launch, unset the pending flag */
4049162SPeter.Dunlap@Sun.COM 			mutex_enter(&iser_qp->qp_lock);
4059162SPeter.Dunlap@Sun.COM 			iser_qp->rq_taskqpending = B_FALSE;
4069162SPeter.Dunlap@Sun.COM 			mutex_exit(&iser_qp->qp_lock);
4079162SPeter.Dunlap@Sun.COM 		}
4089162SPeter.Dunlap@Sun.COM 	} else {
4099162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_qp->qp_lock);
4109162SPeter.Dunlap@Sun.COM 	}
4119162SPeter.Dunlap@Sun.COM 
4129162SPeter.Dunlap@Sun.COM 	DTRACE_PROBE3(iser__recv__cqe, iser_chan_t *, iser_chan,
4139162SPeter.Dunlap@Sun.COM 	    ibt_wc_t *, &wc, ibt_wc_status_t, wc.wc_status);
4149162SPeter.Dunlap@Sun.COM 	if (wc.wc_status != IBT_WC_SUCCESS) {
4159162SPeter.Dunlap@Sun.COM 		/*
4169162SPeter.Dunlap@Sun.COM 		 * Tell IDM that the channel has gone down,
4179162SPeter.Dunlap@Sun.COM 		 * unless he already knows.
4189162SPeter.Dunlap@Sun.COM 		 */
4199162SPeter.Dunlap@Sun.COM 		switch (iser_chan->ic_conn->ic_stage) {
4209162SPeter.Dunlap@Sun.COM 		case ISER_CONN_STAGE_IC_DISCONNECTED:
4219162SPeter.Dunlap@Sun.COM 		case ISER_CONN_STAGE_IC_FREED:
4229162SPeter.Dunlap@Sun.COM 		case ISER_CONN_STAGE_CLOSING:
4239162SPeter.Dunlap@Sun.COM 		case ISER_CONN_STAGE_CLOSED:
4249162SPeter.Dunlap@Sun.COM 			break;
4259162SPeter.Dunlap@Sun.COM 
4269162SPeter.Dunlap@Sun.COM 		default:
4279162SPeter.Dunlap@Sun.COM 			idm_conn_event(iser_chan->ic_conn->ic_idmc,
4289162SPeter.Dunlap@Sun.COM 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
4299162SPeter.Dunlap@Sun.COM 			iser_chan->ic_conn->ic_stage =
4309162SPeter.Dunlap@Sun.COM 			    ISER_CONN_STAGE_CLOSING;
4319162SPeter.Dunlap@Sun.COM 		}
4329162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_chan->ic_conn->ic_lock);
4339162SPeter.Dunlap@Sun.COM 
4349162SPeter.Dunlap@Sun.COM 		iser_msg_free(msg);
4359162SPeter.Dunlap@Sun.COM 		return (DDI_SUCCESS);
4369162SPeter.Dunlap@Sun.COM 	} else {
4379586SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_chan->ic_conn->ic_lock);
4389586SPeter.Dunlap@Sun.COM 
4399162SPeter.Dunlap@Sun.COM 		/*
4409162SPeter.Dunlap@Sun.COM 		 * We have an iSER message in, let's handle it.
4419162SPeter.Dunlap@Sun.COM 		 * We will free the iser_msg_t later in this path,
4429162SPeter.Dunlap@Sun.COM 		 * depending upon the action required.
4439162SPeter.Dunlap@Sun.COM 		 */
4449162SPeter.Dunlap@Sun.COM 		iser_msg_handle(iser_chan, msg);
4459162SPeter.Dunlap@Sun.COM 		return (DDI_SUCCESS);
4469162SPeter.Dunlap@Sun.COM 	}
4479162SPeter.Dunlap@Sun.COM }
4489162SPeter.Dunlap@Sun.COM 
4499162SPeter.Dunlap@Sun.COM static void
iser_msg_handle(iser_chan_t * chan,iser_msg_t * msg)4509162SPeter.Dunlap@Sun.COM iser_msg_handle(iser_chan_t *chan, iser_msg_t *msg)
4519162SPeter.Dunlap@Sun.COM {
4529162SPeter.Dunlap@Sun.COM 	int		opcode;
4539162SPeter.Dunlap@Sun.COM 	iser_ctrl_hdr_t	*hdr = NULL;
4549162SPeter.Dunlap@Sun.COM 	iser_conn_t	*iser_conn = chan->ic_conn;
4559162SPeter.Dunlap@Sun.COM 	int		status;
4569162SPeter.Dunlap@Sun.COM 
4579162SPeter.Dunlap@Sun.COM 	hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
4589162SPeter.Dunlap@Sun.COM 	ASSERT(hdr != NULL);
4599162SPeter.Dunlap@Sun.COM 
4609162SPeter.Dunlap@Sun.COM 	opcode = hdr->opcode;
4619162SPeter.Dunlap@Sun.COM 	if (opcode == ISER_OPCODE_CTRL_TYPE_PDU) {
4629162SPeter.Dunlap@Sun.COM 		/*
4639162SPeter.Dunlap@Sun.COM 		 * Handle an iSCSI Control PDU iSER message.
4649162SPeter.Dunlap@Sun.COM 		 * Note we'll free the msg handle in the PDU callback.
4659162SPeter.Dunlap@Sun.COM 		 */
4669162SPeter.Dunlap@Sun.COM 		status = iser_iscsihdr_handle(chan, msg);
4679162SPeter.Dunlap@Sun.COM 		if (status != DDI_SUCCESS) {
4689162SPeter.Dunlap@Sun.COM 			/*
4699162SPeter.Dunlap@Sun.COM 			 * We are unable to handle this message, and
4709162SPeter.Dunlap@Sun.COM 			 * have no way to recover from this.  Fail the
4719162SPeter.Dunlap@Sun.COM 			 * transport.
4729162SPeter.Dunlap@Sun.COM 			 */
4739162SPeter.Dunlap@Sun.COM 			ISER_LOG(CE_NOTE, "iser_msg_handle: failed "
4749162SPeter.Dunlap@Sun.COM 			    "iser_iscsihdr_handle");
4759162SPeter.Dunlap@Sun.COM 			iser_msg_free(msg);
4769162SPeter.Dunlap@Sun.COM 			idm_conn_event(iser_conn->ic_idmc,
4779162SPeter.Dunlap@Sun.COM 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
4789162SPeter.Dunlap@Sun.COM 		}
4799162SPeter.Dunlap@Sun.COM 	} else if (opcode == ISER_OPCODE_HELLO_MSG) { /* at the target */
4809162SPeter.Dunlap@Sun.COM 		/*
4819162SPeter.Dunlap@Sun.COM 		 * We are currently not supporting Hello Exchange,
4829162SPeter.Dunlap@Sun.COM 		 * since OFED iSER does not. May be revisited.
4839162SPeter.Dunlap@Sun.COM 		 */
4849162SPeter.Dunlap@Sun.COM 		ASSERT(opcode != ISER_OPCODE_HELLO_MSG);
4859162SPeter.Dunlap@Sun.COM 
4869162SPeter.Dunlap@Sun.COM 		if (iser_conn->ic_type != ISER_CONN_TYPE_TGT) {
4879162SPeter.Dunlap@Sun.COM 			idm_conn_event(iser_conn->ic_idmc,
4889162SPeter.Dunlap@Sun.COM 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
4899162SPeter.Dunlap@Sun.COM 		}
4909162SPeter.Dunlap@Sun.COM 
4919162SPeter.Dunlap@Sun.COM 		iser_hello_hdr_t *hello_hdr = (iser_hello_hdr_t *)hdr;
4929162SPeter.Dunlap@Sun.COM 
4939162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "received Hello message: opcode[%d], "
4949162SPeter.Dunlap@Sun.COM 		    "maxver[%d], minver[%d], iser_ird[%d], msg (0x%p)",
4959162SPeter.Dunlap@Sun.COM 		    hello_hdr->opcode, hello_hdr->maxver, hello_hdr->minver,
4969162SPeter.Dunlap@Sun.COM 		    ntohs(hello_hdr->iser_ird), (void *)msg);
4979162SPeter.Dunlap@Sun.COM 
4989162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_conn->ic_lock);
4999162SPeter.Dunlap@Sun.COM 
5009162SPeter.Dunlap@Sun.COM 		if (iser_conn->ic_stage != ISER_CONN_STAGE_HELLO_WAIT) {
5019162SPeter.Dunlap@Sun.COM 			/* target is not expected to receive a Hello */
5029162SPeter.Dunlap@Sun.COM 			idm_conn_event(iser_conn->ic_idmc,
5039162SPeter.Dunlap@Sun.COM 			    CE_TRANSPORT_FAIL, IDM_STATUS_FAIL);
5049162SPeter.Dunlap@Sun.COM 		}
5059162SPeter.Dunlap@Sun.COM 
5069162SPeter.Dunlap@Sun.COM 		iser_conn->ic_stage = ISER_CONN_STAGE_HELLOREPLY_SENT;
5079162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_conn->ic_lock);
5089162SPeter.Dunlap@Sun.COM 
5099162SPeter.Dunlap@Sun.COM 		/* Prepare and send a HelloReply message */
5109162SPeter.Dunlap@Sun.COM 		status = iser_xfer_helloreply_msg(chan);
5119162SPeter.Dunlap@Sun.COM 		if (status != ISER_STATUS_SUCCESS) {
5129162SPeter.Dunlap@Sun.COM 
5139162SPeter.Dunlap@Sun.COM 			mutex_enter(&iser_conn->ic_lock);
5149162SPeter.Dunlap@Sun.COM 			iser_conn->ic_stage =
5159162SPeter.Dunlap@Sun.COM 			    ISER_CONN_STAGE_HELLOREPLY_SENT_FAIL;
5169162SPeter.Dunlap@Sun.COM 			mutex_exit(&iser_conn->ic_lock);
5179162SPeter.Dunlap@Sun.COM 
5189162SPeter.Dunlap@Sun.COM 			idm_conn_event(iser_conn->ic_idmc,
5199162SPeter.Dunlap@Sun.COM 			    CE_TRANSPORT_FAIL, status);
5209162SPeter.Dunlap@Sun.COM 		}
5219162SPeter.Dunlap@Sun.COM 
5229162SPeter.Dunlap@Sun.COM 		/* Free this msg handle */
5239162SPeter.Dunlap@Sun.COM 		iser_msg_free(msg);
5249162SPeter.Dunlap@Sun.COM 
5259162SPeter.Dunlap@Sun.COM 	} else if (opcode == ISER_OPCODE_HELLOREPLY_MSG) { /* at initiator */
5269162SPeter.Dunlap@Sun.COM 
5279162SPeter.Dunlap@Sun.COM 		/*
5289162SPeter.Dunlap@Sun.COM 		 * We are currently not supporting Hello Exchange,
5299162SPeter.Dunlap@Sun.COM 		 * since OFED iSER does not. May be revisited.
5309162SPeter.Dunlap@Sun.COM 		 */
5319162SPeter.Dunlap@Sun.COM 		ASSERT(opcode != ISER_OPCODE_HELLOREPLY_MSG);
5329162SPeter.Dunlap@Sun.COM 
5339162SPeter.Dunlap@Sun.COM 		if (iser_conn->ic_type != ISER_CONN_TYPE_INI) {
5349162SPeter.Dunlap@Sun.COM 			idm_conn_event(iser_conn->ic_idmc,
5359162SPeter.Dunlap@Sun.COM 			    CE_TRANSPORT_FAIL, status);
5369162SPeter.Dunlap@Sun.COM 		}
5379162SPeter.Dunlap@Sun.COM 
5389162SPeter.Dunlap@Sun.COM 		iser_helloreply_hdr_t *hello_hdr = (iser_helloreply_hdr_t *)hdr;
5399162SPeter.Dunlap@Sun.COM 
5409162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "received Hello Reply message: opcode[%d], "
5419162SPeter.Dunlap@Sun.COM 		    "maxver[%d], curver[%d], iser_ord[%d], msg (0x%p)",
5429162SPeter.Dunlap@Sun.COM 		    hello_hdr->opcode, hello_hdr->maxver, hello_hdr->curver,
5439162SPeter.Dunlap@Sun.COM 		    ntohs(hello_hdr->iser_ord), (void *)msg);
5449162SPeter.Dunlap@Sun.COM 
5459162SPeter.Dunlap@Sun.COM 		/* Free this msg handle */
5469162SPeter.Dunlap@Sun.COM 		iser_msg_free(msg);
5479162SPeter.Dunlap@Sun.COM 
5489162SPeter.Dunlap@Sun.COM 		/*
5499162SPeter.Dunlap@Sun.COM 		 * Signal the receipt of HelloReply to the waiting thread
5509162SPeter.Dunlap@Sun.COM 		 * so that the initiator can proceed to the Full Feature
5519162SPeter.Dunlap@Sun.COM 		 * Phase.
5529162SPeter.Dunlap@Sun.COM 		 */
5539162SPeter.Dunlap@Sun.COM 		mutex_enter(&iser_conn->ic_lock);
5549162SPeter.Dunlap@Sun.COM 		iser_conn->ic_stage = ISER_CONN_STAGE_HELLOREPLY_RCV;
5559162SPeter.Dunlap@Sun.COM 		cv_signal(&iser_conn->ic_stage_cv);
5569162SPeter.Dunlap@Sun.COM 		mutex_exit(&iser_conn->ic_lock);
5579162SPeter.Dunlap@Sun.COM 	} else {
5589162SPeter.Dunlap@Sun.COM 		/* Protocol error: free the msg handle and fail the session */
5599162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_msg_handle: unsupported opcode (0x%x): "
5609162SPeter.Dunlap@Sun.COM 		    "terminating session on IDM handle (0x%p)", opcode,
5619162SPeter.Dunlap@Sun.COM 		    (void *) iser_conn->ic_idmc);
5629162SPeter.Dunlap@Sun.COM 
5639162SPeter.Dunlap@Sun.COM 		iser_msg_free(msg);
5649162SPeter.Dunlap@Sun.COM 		idm_conn_event(iser_conn->ic_idmc, CE_TRANSPORT_FAIL,
5659162SPeter.Dunlap@Sun.COM 		    IDM_STATUS_FAIL);
5669162SPeter.Dunlap@Sun.COM 	}
5679162SPeter.Dunlap@Sun.COM }
5689162SPeter.Dunlap@Sun.COM 
5699162SPeter.Dunlap@Sun.COM #define	IDM_PDU_OPCODE(PDU) \
5709162SPeter.Dunlap@Sun.COM 	((PDU)->isp_hdr->opcode & ISCSI_OPCODE_MASK)
5719162SPeter.Dunlap@Sun.COM 
5729162SPeter.Dunlap@Sun.COM /* network to host translation for 24b integers */
5739162SPeter.Dunlap@Sun.COM static uint32_t
n2h24(uchar_t * ptr)5749162SPeter.Dunlap@Sun.COM n2h24(uchar_t *ptr)
5759162SPeter.Dunlap@Sun.COM {
5769162SPeter.Dunlap@Sun.COM 	return ((ptr[0] << 16) | (ptr[1] << 8) | ptr[2]);
5779162SPeter.Dunlap@Sun.COM }
5789162SPeter.Dunlap@Sun.COM 
5799162SPeter.Dunlap@Sun.COM /* ARGSUSED */
5809162SPeter.Dunlap@Sun.COM static void
iser_rx_pdu_cb(idm_pdu_t * pdu,idm_status_t status)5819162SPeter.Dunlap@Sun.COM iser_rx_pdu_cb(idm_pdu_t *pdu, idm_status_t status)
5829162SPeter.Dunlap@Sun.COM {
5839162SPeter.Dunlap@Sun.COM 	/* Free the iser msg handle and the PDU handle */
5849162SPeter.Dunlap@Sun.COM 	iser_msg_free((iser_msg_t *)pdu->isp_transport_private);
5859162SPeter.Dunlap@Sun.COM 	idm_pdu_free(pdu);
5869162SPeter.Dunlap@Sun.COM }
5879162SPeter.Dunlap@Sun.COM 
5889162SPeter.Dunlap@Sun.COM int
iser_iscsihdr_handle(iser_chan_t * chan,iser_msg_t * msg)5899162SPeter.Dunlap@Sun.COM iser_iscsihdr_handle(iser_chan_t *chan, iser_msg_t *msg)
5909162SPeter.Dunlap@Sun.COM {
5919162SPeter.Dunlap@Sun.COM 	idm_pdu_t	*pdu;
5929162SPeter.Dunlap@Sun.COM 	uint8_t		*iser_hdrp;
5939162SPeter.Dunlap@Sun.COM 	uint8_t		*iscsi_hdrp;
5949162SPeter.Dunlap@Sun.COM 	iscsi_hdr_t	*bhs;
5959162SPeter.Dunlap@Sun.COM 
5969162SPeter.Dunlap@Sun.COM 	pdu = idm_pdu_alloc_nosleep(sizeof (iscsi_hdr_t), 0);
5979162SPeter.Dunlap@Sun.COM 	pdu->isp_ic = chan->ic_conn->ic_idmc;
5989162SPeter.Dunlap@Sun.COM 	ASSERT(pdu->isp_ic != NULL);
5999162SPeter.Dunlap@Sun.COM 
6009162SPeter.Dunlap@Sun.COM 	/* Set the iser_msg handle into the transport-private field */
6019162SPeter.Dunlap@Sun.COM 	pdu->isp_transport_private = (void *)msg;
6029162SPeter.Dunlap@Sun.COM 
6039162SPeter.Dunlap@Sun.COM 	/* Set up a pointer in the pdu handle to the iSER header */
6049162SPeter.Dunlap@Sun.COM 	iser_hdrp = (uint8_t *)(uintptr_t)msg->msg_ds.ds_va;
6059162SPeter.Dunlap@Sun.COM 	if (iser_hdrp == NULL) {
6069162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_iscsihdr_handle: iser_hdrp is NULL");
6079162SPeter.Dunlap@Sun.COM 		idm_pdu_free(pdu);
6089162SPeter.Dunlap@Sun.COM 		return (ISER_STATUS_FAIL);
6099162SPeter.Dunlap@Sun.COM 	}
6109162SPeter.Dunlap@Sun.COM 	pdu->isp_transport_hdr = (void *)iser_hdrp;
6119162SPeter.Dunlap@Sun.COM 	pdu->isp_transport_hdrlen = ISER_HEADER_LENGTH;
6129162SPeter.Dunlap@Sun.COM 
6139162SPeter.Dunlap@Sun.COM 	/*
6149162SPeter.Dunlap@Sun.COM 	 * Set up a pointer to the iSCSI header, which is directly
6159162SPeter.Dunlap@Sun.COM 	 * after the iSER header in the message.
6169162SPeter.Dunlap@Sun.COM 	 */
6179162SPeter.Dunlap@Sun.COM 	iscsi_hdrp = ((uint8_t *)(uintptr_t)msg->msg_ds.ds_va) +
6189162SPeter.Dunlap@Sun.COM 	    ISER_HEADER_LENGTH;
6199162SPeter.Dunlap@Sun.COM 	if (iscsi_hdrp == NULL) {
6209162SPeter.Dunlap@Sun.COM 		ISER_LOG(CE_NOTE, "iser_iscsihdr_handle: iscsi_hdrp is NULL");
6219162SPeter.Dunlap@Sun.COM 		idm_pdu_free(pdu);
6229162SPeter.Dunlap@Sun.COM 		return (ISER_STATUS_FAIL);
6239162SPeter.Dunlap@Sun.COM 	}
6249162SPeter.Dunlap@Sun.COM 	pdu->isp_hdr = (iscsi_hdr_t *)(uintptr_t)iscsi_hdrp;
6259162SPeter.Dunlap@Sun.COM 
6269162SPeter.Dunlap@Sun.COM 	/* Fill in the BHS */
6279162SPeter.Dunlap@Sun.COM 	bhs = pdu->isp_hdr;
6289162SPeter.Dunlap@Sun.COM 	pdu->isp_hdrlen	= sizeof (iscsi_hdr_t) +
6299162SPeter.Dunlap@Sun.COM 	    (bhs->hlength * sizeof (uint32_t));
6309162SPeter.Dunlap@Sun.COM 	pdu->isp_datalen = n2h24(bhs->dlength);
6319162SPeter.Dunlap@Sun.COM 	pdu->isp_callback = iser_rx_pdu_cb;
6329162SPeter.Dunlap@Sun.COM 
6339162SPeter.Dunlap@Sun.COM 	/*
6349162SPeter.Dunlap@Sun.COM 	 * If datalen > 0, then non-scsi data may be present. Allocate
6359162SPeter.Dunlap@Sun.COM 	 * space in the PDU handle and set a pointer to the data.
6369162SPeter.Dunlap@Sun.COM 	 */
6379162SPeter.Dunlap@Sun.COM 	if (pdu->isp_datalen) {
6389162SPeter.Dunlap@Sun.COM 		pdu->isp_data = ((uint8_t *)(uintptr_t)pdu->isp_hdr) +
6399162SPeter.Dunlap@Sun.COM 		    pdu->isp_hdrlen;
6409162SPeter.Dunlap@Sun.COM 	}
6419162SPeter.Dunlap@Sun.COM 
6429162SPeter.Dunlap@Sun.COM 	/* Process RX PDU */
6439162SPeter.Dunlap@Sun.COM 	idm_pdu_rx(pdu->isp_ic, pdu);
6449162SPeter.Dunlap@Sun.COM 
6459162SPeter.Dunlap@Sun.COM 	return (DDI_SUCCESS);
6469162SPeter.Dunlap@Sun.COM }
647