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/stat.h>
28 #include <sys/conf.h>
29 #include <sys/ddi.h>
30 #include <sys/sunddi.h>
31 #include <sys/modctl.h>
32 #include <sys/byteorder.h>
33 #include <sys/sdt.h>
34
35 #include <sys/ib/clients/iser/iser.h>
36
37 /*
38 * iser_xfer.c
39 */
40
41 int
iser_xfer_hello_msg(iser_chan_t * chan)42 iser_xfer_hello_msg(iser_chan_t *chan)
43 {
44 iser_hca_t *hca;
45 iser_wr_t *iser_wr;
46 iser_msg_t *msg;
47 ibt_send_wr_t wr;
48 iser_hello_hdr_t *hdr;
49 int status;
50
51 ASSERT(chan != NULL);
52
53 hca = (iser_hca_t *)chan->ic_hca;
54 if (hca == NULL) {
55 ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: no hca handle found");
56 return (ISER_STATUS_FAIL);
57 }
58
59 msg = iser_msg_get(hca, 1, NULL);
60
61 if (msg == NULL) {
62 ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: iser message cache "
63 "alloc failed");
64 return (ISER_STATUS_FAIL);
65 }
66
67 /* Send iSER Hello Message to declare iSER parameters to the target */
68 hdr = (iser_hello_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
69
70 hdr->opcode = ISER_OPCODE_HELLO_MSG;
71 hdr->rsvd1 = 0;
72 hdr->maxver = 1;
73 hdr->minver = 1;
74 hdr->iser_ird = htons(ISER_IB_DEFAULT_IRD);
75 hdr->rsvd2[0] = 0;
76 hdr->rsvd2[1] = 0;
77
78 /* Allocate an iSER WR handle and tuck this msg into it */
79 iser_wr = iser_wr_get();
80 if (iser_wr == NULL) {
81 ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: unable to allocate "
82 "iser wr handle");
83 iser_msg_free(msg);
84 return (ISER_STATUS_FAIL);
85 }
86 iser_wr->iw_msg = msg;
87 iser_wr->iw_type = ISER_WR_SEND;
88
89 /* Use the address of our generic iser_wr handle as our WRID */
90 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
91
92 /* Populate the rest of the work request */
93 wr.wr_trans = IBT_RC_SRV;
94 wr.wr_opcode = IBT_WRC_SEND;
95 wr.wr_nds = 1;
96 wr.wr_sgl = &msg->msg_ds;
97
98 /*
99 * Avoid race condition by incrementing this channel's
100 * SQ posted count prior to calling ibt_post_send
101 */
102 mutex_enter(&chan->ic_sq_post_lock);
103 chan->ic_sq_post_count++;
104 if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
105 chan->ic_sq_max_post_count = chan->ic_sq_post_count;
106 mutex_exit(&chan->ic_sq_post_lock);
107
108 status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
109 if (status != IBT_SUCCESS) {
110 ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: ibt_post_send "
111 "failure (%d)", status);
112 mutex_enter(&chan->ic_sq_post_lock);
113 chan->ic_sq_post_count--;
114 mutex_exit(&chan->ic_sq_post_lock);
115 iser_msg_free(msg);
116 iser_wr_free(iser_wr);
117 return (ISER_STATUS_FAIL);
118 }
119
120 ISER_LOG(CE_NOTE, "Posting iSER Hello message: chan (0x%p): "
121 "IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr,
122 chan->ic_remoteip.un.ip4addr);
123
124 return (ISER_STATUS_SUCCESS);
125 }
126
127 int
iser_xfer_helloreply_msg(iser_chan_t * chan)128 iser_xfer_helloreply_msg(iser_chan_t *chan)
129 {
130 iser_hca_t *hca;
131 iser_wr_t *iser_wr;
132 ibt_send_wr_t wr;
133 iser_msg_t *msg;
134 iser_helloreply_hdr_t *hdr;
135 int status;
136
137 ASSERT(chan != NULL);
138
139 hca = (iser_hca_t *)chan->ic_hca;
140 if (hca == NULL) {
141 ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: no hca handle "
142 "found");
143 return (ISER_STATUS_FAIL);
144 }
145
146 msg = iser_msg_get(hca, 1, NULL);
147
148 if (msg == NULL) {
149 ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: iser message "
150 "cache alloc failed");
151 return (ISER_STATUS_FAIL);
152 }
153
154 /* Use the iSER Hello Reply Message */
155 hdr = (iser_helloreply_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
156
157 hdr->opcode = ISER_OPCODE_HELLOREPLY_MSG;
158 hdr->rsvd1 = 0;
159 hdr->flag = 0;
160 hdr->maxver = 1;
161 hdr->curver = 1;
162 hdr->iser_ord = htons(ISER_IB_DEFAULT_ORD);
163 hdr->rsvd2[0] = 0;
164 hdr->rsvd2[1] = 0;
165
166 /* Allocate an iSER WR handle and tuck this msg into it */
167 iser_wr = iser_wr_get();
168 if (iser_wr == NULL) {
169 ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: unable to "
170 "allocate iser wr handle");
171 iser_msg_free(msg);
172 return (ISER_STATUS_FAIL);
173 }
174 iser_wr->iw_msg = msg;
175 iser_wr->iw_type = ISER_WR_SEND;
176
177 /* Use the address of our generic iser_wr handle as our WRID */
178 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
179
180 /* Populate the rest of the work request */
181 wr.wr_trans = IBT_RC_SRV;
182 wr.wr_opcode = IBT_WRC_SEND;
183 wr.wr_nds = 1;
184 wr.wr_sgl = &msg->msg_ds;
185
186 mutex_enter(&chan->ic_sq_post_lock);
187 chan->ic_sq_post_count++;
188 if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
189 chan->ic_sq_max_post_count = chan->ic_sq_post_count;
190
191 mutex_exit(&chan->ic_sq_post_lock);
192
193 status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
194 if (status != IBT_SUCCESS) {
195 ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: ibt_post_send "
196 "failure (%d)", status);
197 mutex_enter(&chan->ic_sq_post_lock);
198 chan->ic_sq_post_count--;
199 mutex_exit(&chan->ic_sq_post_lock);
200 iser_msg_free(msg);
201 iser_wr_free(iser_wr);
202 return (ISER_STATUS_FAIL);
203 }
204 ISER_LOG(CE_NOTE, "Posting iSER HelloReply message: chan (0x%p): "
205 "IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr,
206 chan->ic_remoteip.un.ip4addr);
207
208 return (ISER_STATUS_SUCCESS);
209 }
210
211 /*
212 * iser_xfer_ctrlpdu
213 *
214 * This is iSER's implementation of the 'Send_control' operational primitive.
215 * This iSER layer uses the Send Message type of RCaP to transfer the iSCSI
216 * Control-type PDU. A special case is that the transfer of SCSI Data-out PDUs
217 * carrying unsolicited data are also treated as iSCSI Control-Type PDUs. The
218 * message payload contains an iSER header followed by the iSCSI Control-type
219 * the iSCSI Control-type PDU.
220 * This function is invoked by an initiator iSCSI layer requesting the transfer
221 * of a iSCSI command PDU or a target iSCSI layer requesting the transfer of a
222 * iSCSI response PDU.
223 */
224 int
iser_xfer_ctrlpdu(iser_chan_t * chan,idm_pdu_t * pdu)225 iser_xfer_ctrlpdu(iser_chan_t *chan, idm_pdu_t *pdu)
226 {
227 iser_hca_t *hca;
228 iser_ctrl_hdr_t *hdr;
229 iser_msg_t *msg;
230 iser_wr_t *iser_wr;
231 ibt_send_wr_t wr;
232 int status;
233 iser_mr_t *mr;
234 iscsi_data_hdr_t *bhs;
235 idm_conn_t *ic;
236 idm_task_t *idt = NULL;
237 idm_buf_t *buf;
238
239 ASSERT(chan != NULL);
240
241 mutex_enter(&chan->ic_conn->ic_lock);
242 /* Bail out if the connection is closed */
243 if ((chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
244 (chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
245 mutex_exit(&chan->ic_conn->ic_lock);
246 return (ISER_STATUS_FAIL);
247 }
248
249 ic = chan->ic_conn->ic_idmc;
250
251 /* Pull the BHS out of the PDU handle */
252 bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
253
254 /*
255 * All SCSI command PDU (except SCSI Read and SCSI Write) and the SCSI
256 * Response PDU are sent to the remote end using the SendSE Message.
257 *
258 * The StatSN may need to be sent (and possibly advanced) at this time
259 * for some PDUs, identified by the IDM_PDU_SET_STATSN flag.
260 */
261 if (pdu->isp_flags & IDM_PDU_SET_STATSN) {
262 (ic->ic_conn_ops.icb_update_statsn)(NULL, pdu);
263 }
264 /*
265 * Setup a Send Message for carrying the iSCSI control-type PDU
266 * preceeded by an iSER header.
267 */
268 hca = (iser_hca_t *)chan->ic_hca;
269 if (hca == NULL) {
270 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: no hca handle found");
271 mutex_exit(&chan->ic_conn->ic_lock);
272 return (ISER_STATUS_FAIL);
273 }
274
275 msg = iser_msg_get(hca, 1, NULL);
276 if (msg == NULL) {
277 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: iser message cache "
278 "alloc failed");
279 mutex_exit(&chan->ic_conn->ic_lock);
280 return (ISER_STATUS_FAIL);
281 }
282
283 hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
284
285 /*
286 * Initialize header assuming no transfers
287 */
288 bzero(hdr, sizeof (*hdr));
289 hdr->opcode = ISER_OPCODE_CTRL_TYPE_PDU;
290
291 /*
292 * On the initiator side, the task buffers will be used to identify
293 * if there are any buffers to be advertised
294 */
295 if ((ic->ic_conn_type == CONN_TYPE_INI) &&
296 ((bhs->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_CMD) &&
297 ((idt = idm_task_find(ic, bhs->itt, bhs->ttt)) != NULL)) {
298
299 if (!list_is_empty(&idt->idt_inbufv)) {
300 buf = idm_buf_find(&idt->idt_inbufv, 0);
301 ASSERT(buf != NULL);
302
303 mr = (iser_mr_t *)buf->idb_reg_private;
304 ASSERT(mr != NULL);
305
306 hdr->rsv_flag = 1;
307 hdr->rstag = htonl(mr->is_mrrkey);
308 BE_OUT64(&hdr->rva, mr->is_mrva);
309 }
310
311 if (!list_is_empty(&idt->idt_outbufv)) {
312 buf = idm_buf_find(&idt->idt_outbufv, 0);
313 ASSERT(buf != NULL);
314
315 mr = (iser_mr_t *)buf->idb_reg_private;
316 ASSERT(mr != NULL);
317
318 hdr->wsv_flag = 1;
319 hdr->wstag = htonl(mr->is_mrrkey);
320 BE_OUT64(&hdr->wva, mr->is_mrva);
321 }
322
323 /* Release our reference on the task */
324 idm_task_rele(idt);
325 }
326
327 /* Copy the BHS after the iSER header */
328 bcopy(pdu->isp_hdr,
329 (uint8_t *)(uintptr_t)msg->msg_ds.ds_va + ISER_HEADER_LENGTH,
330 pdu->isp_hdrlen);
331
332 if (pdu->isp_datalen > 0) {
333 /* Copy the isp_data after the PDU header */
334 bcopy(pdu->isp_data,
335 (uint8_t *)(uintptr_t)msg->msg_ds.ds_va +
336 ISER_HEADER_LENGTH + pdu->isp_hdrlen,
337 pdu->isp_datalen);
338
339 /* Set the SGE's ds_len */
340 msg->msg_ds.ds_len = ISER_HEADER_LENGTH + pdu->isp_hdrlen +
341 pdu->isp_datalen;
342 } else {
343 /* No data, so set the SGE's ds_len to the headers length */
344 msg->msg_ds.ds_len = ISER_HEADER_LENGTH + pdu->isp_hdrlen;
345 }
346
347 /*
348 * Build Work Request to be posted on the Send Queue.
349 */
350 bzero(&wr, sizeof (wr));
351
352 /* Allocate an iSER WR handle and tuck the msg and pdu into it */
353 iser_wr = iser_wr_get();
354 if (iser_wr == NULL) {
355 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: unable to allocate "
356 "iser wr handle");
357 iser_msg_free(msg);
358 mutex_exit(&chan->ic_conn->ic_lock);
359 return (ISER_STATUS_FAIL);
360 }
361 iser_wr->iw_pdu = pdu;
362 iser_wr->iw_msg = msg;
363 iser_wr->iw_type = ISER_WR_SEND;
364
365 /*
366 * Use the address of our generic iser_wr handle as our WRID
367 * and populate the rest of the work request
368 */
369 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
370 wr.wr_trans = IBT_RC_SRV;
371 wr.wr_opcode = IBT_WRC_SEND;
372 wr.wr_nds = 1;
373 wr.wr_sgl = &msg->msg_ds;
374
375 /* Increment this channel's SQ posted count */
376 mutex_enter(&chan->ic_sq_post_lock);
377 chan->ic_sq_post_count++;
378 if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
379 chan->ic_sq_max_post_count = chan->ic_sq_post_count;
380 mutex_exit(&chan->ic_sq_post_lock);
381
382 /* Post Send Work Request on the specified channel */
383 status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
384 if (status != IBT_SUCCESS) {
385 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: ibt_post_send "
386 "failure (%d)", status);
387 iser_msg_free(msg);
388 iser_wr_free(iser_wr);
389 mutex_enter(&chan->ic_sq_post_lock);
390 chan->ic_sq_post_count--;
391 mutex_exit(&chan->ic_sq_post_lock);
392 mutex_exit(&chan->ic_conn->ic_lock);
393 return (ISER_STATUS_FAIL);
394 }
395
396 mutex_exit(&chan->ic_conn->ic_lock);
397 return (ISER_STATUS_SUCCESS);
398 }
399
400 /*
401 * iser_xfer_buf_to_ini
402 * This is iSER's implementation of the 'Put_Data' operational primitive.
403 * The iSCSI layer at the target invokes this function when it is ready to
404 * return the SCSI Read Data to the initiator. This function generates and
405 * sends an RDMA Write Message containing the read data to the initiator.
406 */
407 int
iser_xfer_buf_to_ini(idm_task_t * idt,idm_buf_t * buf)408 iser_xfer_buf_to_ini(idm_task_t *idt, idm_buf_t *buf)
409 {
410 iser_conn_t *iser_conn;
411 iser_chan_t *iser_chan;
412 iser_buf_t *iser_buf;
413 iser_wr_t *iser_wr;
414 iser_ctrl_hdr_t *iser_hdr;
415 ibt_send_wr_t wr;
416 uint64_t reg_raddr;
417 uint32_t reg_rkey;
418 int status;
419
420 /* Grab the iSER resources from the task and buf handles */
421 iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private;
422 iser_chan = iser_conn->ic_chan;
423
424 mutex_enter(&iser_chan->ic_conn->ic_lock);
425 /* Bail out if the connection is closed */
426 if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
427 (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
428 mutex_exit(&iser_chan->ic_conn->ic_lock);
429 return (ISER_STATUS_FAIL);
430 }
431
432 iser_buf = (iser_buf_t *)buf->idb_buf_private;
433 iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr;
434
435 /* Pull the Read STag data out of the iSER header in the task hdl */
436 reg_raddr = BE_IN64(&iser_hdr->rva);
437 reg_rkey = (ntohl(iser_hdr->rstag));
438
439 /* Set up the WR raddr and rkey based upon the Read iSER STag */
440 bzero(&wr, sizeof (ibt_send_wr_t));
441 wr.wr.rc.rcwr.rdma.rdma_raddr = reg_raddr + buf->idb_bufoffset;
442 wr.wr.rc.rcwr.rdma.rdma_rkey = reg_rkey;
443
444 /* Set the transfer length from the IDM buf handle */
445 iser_buf->buf_ds.ds_len = buf->idb_xfer_len;
446
447 /* Allocate an iSER WR handle and tuck the IDM buf handle into it */
448 iser_wr = iser_wr_get();
449 if (iser_wr == NULL) {
450 ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: unable to allocate "
451 "iser wr handle");
452 mutex_exit(&iser_chan->ic_conn->ic_lock);
453 return (ISER_STATUS_FAIL);
454 }
455 iser_wr->iw_buf = buf;
456 iser_wr->iw_type = ISER_WR_RDMAW;
457
458 /* Use the address of our generic iser_wr handle as our WRID */
459 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
460
461 /* Populate the rest of the work request */
462 wr.wr_flags = IBT_WR_SEND_SIGNAL;
463 wr.wr_trans = IBT_RC_SRV;
464 wr.wr_opcode = IBT_WRC_RDMAW;
465 wr.wr_nds = 1;
466 wr.wr_sgl = &iser_buf->buf_ds;
467
468 #ifdef DEBUG
469 bcopy(&wr, &iser_buf->buf_wr, sizeof (ibt_send_wr_t));
470 #endif
471
472 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
473 uintptr_t, buf->idb_buf, uint32_t, buf->idb_bufoffset,
474 uint64_t, reg_raddr, uint32_t, buf->idb_bufoffset,
475 uint32_t, reg_rkey,
476 uint32_t, buf->idb_xfer_len, int, XFER_BUF_TX_TO_INI);
477
478 /* Increment this channel's SQ posted count */
479 mutex_enter(&iser_chan->ic_sq_post_lock);
480 iser_chan->ic_sq_post_count++;
481 if (iser_chan->ic_sq_post_count > iser_chan->ic_sq_max_post_count)
482 iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count;
483 mutex_exit(&iser_chan->ic_sq_post_lock);
484
485 status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
486 if (status != IBT_SUCCESS) {
487 ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send "
488 "failure (%d)", status);
489 iser_wr_free(iser_wr);
490 mutex_enter(&iser_chan->ic_sq_post_lock);
491 iser_chan->ic_sq_post_count--;
492 mutex_exit(&iser_chan->ic_sq_post_lock);
493 mutex_exit(&iser_chan->ic_conn->ic_lock);
494 return (ISER_STATUS_FAIL);
495 }
496
497 mutex_exit(&iser_chan->ic_conn->ic_lock);
498 return (ISER_STATUS_SUCCESS);
499 }
500
501 /*
502 * iser_xfer_buf_from_ini
503 * This is iSER's implementation of the 'Get_Data' operational primitive.
504 * The iSCSI layer at the target invokes this function when it is ready to
505 * receive the SCSI Write Data from the initiator. This function generates and
506 * sends an RDMA Read Message to get the data from the initiator. No R2T PDUs
507 * are generated.
508 */
509 int
iser_xfer_buf_from_ini(idm_task_t * idt,idm_buf_t * buf)510 iser_xfer_buf_from_ini(idm_task_t *idt, idm_buf_t *buf)
511 {
512 iser_conn_t *iser_conn;
513 iser_chan_t *iser_chan;
514 iser_buf_t *iser_buf;
515 iser_wr_t *iser_wr;
516 iser_ctrl_hdr_t *iser_hdr;
517 ibt_send_wr_t wr;
518 uint64_t reg_raddr;
519 uint32_t reg_rkey;
520 int status;
521
522 /* Grab the iSER resources from the task and buf handles */
523 iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private;
524 iser_chan = iser_conn->ic_chan;
525
526 mutex_enter(&iser_chan->ic_conn->ic_lock);
527 /* Bail out if the connection is closed */
528 if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
529 (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
530 mutex_exit(&iser_chan->ic_conn->ic_lock);
531 return (ISER_STATUS_FAIL);
532 }
533
534 iser_buf = (iser_buf_t *)buf->idb_buf_private;
535 iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr;
536
537 /* Pull the Write STag data out of the iSER header in the task hdl */
538 reg_raddr = BE_IN64(&iser_hdr->wva);
539 reg_rkey = (ntohl(iser_hdr->wstag));
540
541 /* Set up the WR raddr and rkey based upon the iSER Write STag */
542 bzero(&wr, sizeof (ibt_send_wr_t));
543 wr.wr.rc.rcwr.rdma.rdma_raddr = reg_raddr + buf->idb_bufoffset;
544 wr.wr.rc.rcwr.rdma.rdma_rkey = reg_rkey;
545
546 /* Set the transfer length from the IDM buf handle */
547 iser_buf->buf_ds.ds_len = buf->idb_xfer_len;
548
549 /* Allocate an iSER WR handle and tuck the IDM buf handle into it */
550 iser_wr = iser_wr_get();
551 if (iser_wr == NULL) {
552 ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: unable to allocate "
553 "iser wr handle");
554 mutex_exit(&iser_chan->ic_conn->ic_lock);
555 return (ISER_STATUS_FAIL);
556 }
557 iser_wr->iw_buf = buf;
558 iser_wr->iw_type = ISER_WR_RDMAR;
559
560 /* Use the address of our generic iser_wr handle as our WRID */
561 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
562
563 /* Populate the rest of the work request */
564 wr.wr_flags = IBT_WR_SEND_SIGNAL;
565 wr.wr_trans = IBT_RC_SRV;
566 wr.wr_opcode = IBT_WRC_RDMAR;
567 wr.wr_nds = 1;
568 wr.wr_sgl = &iser_buf->buf_ds;
569
570 #ifdef DEBUG
571 bcopy(&wr, &iser_buf->buf_wr, sizeof (ibt_send_wr_t));
572 #endif
573
574 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
575 uintptr_t, buf->idb_buf, uint32_t, buf->idb_bufoffset,
576 uint64_t, reg_raddr, uint32_t, buf->idb_bufoffset,
577 uint32_t, reg_rkey,
578 uint32_t, buf->idb_xfer_len, int, XFER_BUF_RX_FROM_INI);
579
580 /* Increment this channel's SQ posted count */
581 mutex_enter(&iser_chan->ic_sq_post_lock);
582 iser_chan->ic_sq_post_count++;
583 if (iser_chan->ic_sq_post_count > iser_chan->ic_sq_max_post_count)
584 iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count;
585 mutex_exit(&iser_chan->ic_sq_post_lock);
586
587 status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
588 if (status != IBT_SUCCESS) {
589 ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send "
590 "failure (%d)", status);
591 iser_wr_free(iser_wr);
592 mutex_enter(&iser_chan->ic_sq_post_lock);
593 iser_chan->ic_sq_post_count--;
594 mutex_exit(&iser_chan->ic_sq_post_lock);
595 mutex_exit(&iser_chan->ic_conn->ic_lock);
596 return (ISER_STATUS_FAIL);
597 }
598
599 mutex_exit(&iser_chan->ic_conn->ic_lock);
600 return (ISER_STATUS_SUCCESS);
601 }
602