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 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 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 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 /* 250 * All SCSI command PDU (except SCSI Read and SCSI Write) and the SCSI 251 * Response PDU are sent to the remote end using the SendSE Message. 252 * 253 * Setup a Send Message for carrying the iSCSI control-type PDU 254 * preceeded by an iSER header. 255 */ 256 hca = (iser_hca_t *)chan->ic_hca; 257 if (hca == NULL) { 258 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: no hca handle found"); 259 mutex_exit(&chan->ic_conn->ic_lock); 260 return (ISER_STATUS_FAIL); 261 } 262 263 msg = iser_msg_get(hca, 1, NULL); 264 if (msg == NULL) { 265 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: iser message cache " 266 "alloc failed"); 267 mutex_exit(&chan->ic_conn->ic_lock); 268 return (ISER_STATUS_FAIL); 269 } 270 271 /* Pull the BHS out of the PDU handle */ 272 bhs = (iscsi_data_hdr_t *)pdu->isp_hdr; 273 274 ic = chan->ic_conn->ic_idmc; 275 276 hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va; 277 278 /* 279 * Initialize header assuming no transfers 280 */ 281 bzero(hdr, sizeof (*hdr)); 282 hdr->opcode = ISER_OPCODE_CTRL_TYPE_PDU; 283 284 /* 285 * On the initiator side, the task buffers will be used to identify 286 * if there are any buffers to be advertised 287 */ 288 if ((ic->ic_conn_type == CONN_TYPE_INI) && 289 ((bhs->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_CMD) && 290 ((idt = idm_task_find(ic, bhs->itt, bhs->ttt)) != NULL)) { 291 292 if (!list_is_empty(&idt->idt_inbufv)) { 293 buf = idm_buf_find(&idt->idt_inbufv, 0); 294 ASSERT(buf != NULL); 295 296 mr = (iser_mr_t *)buf->idb_reg_private; 297 ASSERT(mr != NULL); 298 299 hdr->rsv_flag = 1; 300 hdr->rstag = htonl(mr->is_mrrkey); 301 BE_OUT64(&hdr->rva, mr->is_mrva); 302 } 303 304 if (!list_is_empty(&idt->idt_outbufv)) { 305 buf = idm_buf_find(&idt->idt_outbufv, 0); 306 ASSERT(buf != NULL); 307 308 mr = (iser_mr_t *)buf->idb_reg_private; 309 ASSERT(mr != NULL); 310 311 hdr->wsv_flag = 1; 312 hdr->wstag = htonl(mr->is_mrrkey); 313 BE_OUT64(&hdr->wva, mr->is_mrva); 314 } 315 316 /* Release our reference on the task */ 317 idm_task_rele(idt); 318 } 319 320 /* Copy the BHS after the iSER header */ 321 bcopy(pdu->isp_hdr, 322 (uint8_t *)(uintptr_t)msg->msg_ds.ds_va + ISER_HEADER_LENGTH, 323 pdu->isp_hdrlen); 324 325 if (pdu->isp_datalen > 0) { 326 /* Copy the isp_data after the PDU header */ 327 bcopy(pdu->isp_data, 328 (uint8_t *)(uintptr_t)msg->msg_ds.ds_va + 329 ISER_HEADER_LENGTH + pdu->isp_hdrlen, 330 pdu->isp_datalen); 331 332 /* Set the SGE's ds_len */ 333 msg->msg_ds.ds_len = ISER_HEADER_LENGTH + pdu->isp_hdrlen + 334 pdu->isp_datalen; 335 } else { 336 /* No data, so set the SGE's ds_len to the headers length */ 337 msg->msg_ds.ds_len = ISER_HEADER_LENGTH + pdu->isp_hdrlen; 338 } 339 340 /* 341 * Build Work Request to be posted on the Send Queue. 342 */ 343 bzero(&wr, sizeof (wr)); 344 345 /* Allocate an iSER WR handle and tuck the msg and pdu into it */ 346 iser_wr = iser_wr_get(); 347 if (iser_wr == NULL) { 348 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: unable to allocate " 349 "iser wr handle"); 350 iser_msg_free(msg); 351 mutex_exit(&chan->ic_conn->ic_lock); 352 return (ISER_STATUS_FAIL); 353 } 354 iser_wr->iw_pdu = pdu; 355 iser_wr->iw_msg = msg; 356 iser_wr->iw_type = ISER_WR_SEND; 357 358 /* 359 * Use the address of our generic iser_wr handle as our WRID 360 * and populate the rest of the work request 361 */ 362 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr; 363 wr.wr_trans = IBT_RC_SRV; 364 wr.wr_opcode = IBT_WRC_SEND; 365 wr.wr_nds = 1; 366 wr.wr_sgl = &msg->msg_ds; 367 368 /* Increment this channel's SQ posted count */ 369 mutex_enter(&chan->ic_sq_post_lock); 370 chan->ic_sq_post_count++; 371 if (chan->ic_sq_post_count > chan->ic_sq_max_post_count) 372 chan->ic_sq_max_post_count = chan->ic_sq_post_count; 373 mutex_exit(&chan->ic_sq_post_lock); 374 375 /* Post Send Work Request on the specified channel */ 376 status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL); 377 if (status != IBT_SUCCESS) { 378 ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: ibt_post_send " 379 "failure (%d)", status); 380 iser_msg_free(msg); 381 iser_wr_free(iser_wr); 382 mutex_enter(&chan->ic_sq_post_lock); 383 chan->ic_sq_post_count--; 384 mutex_exit(&chan->ic_sq_post_lock); 385 mutex_exit(&chan->ic_conn->ic_lock); 386 return (ISER_STATUS_FAIL); 387 } 388 389 mutex_exit(&chan->ic_conn->ic_lock); 390 return (ISER_STATUS_SUCCESS); 391 } 392 393 /* 394 * iser_xfer_buf_to_ini 395 * This is iSER's implementation of the 'Put_Data' operational primitive. 396 * The iSCSI layer at the target invokes this function when it is ready to 397 * return the SCSI Read Data to the initiator. This function generates and 398 * sends an RDMA Write Message containing the read data to the initiator. 399 */ 400 int 401 iser_xfer_buf_to_ini(idm_task_t *idt, idm_buf_t *buf) 402 { 403 iser_conn_t *iser_conn; 404 iser_chan_t *iser_chan; 405 iser_buf_t *iser_buf; 406 iser_wr_t *iser_wr; 407 iser_ctrl_hdr_t *iser_hdr; 408 ibt_send_wr_t wr; 409 uint64_t reg_raddr; 410 uint32_t reg_rkey; 411 int status; 412 413 /* Grab the iSER resources from the task and buf handles */ 414 iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private; 415 iser_chan = iser_conn->ic_chan; 416 417 mutex_enter(&iser_chan->ic_conn->ic_lock); 418 /* Bail out if the connection is closed */ 419 if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) || 420 (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) { 421 mutex_exit(&iser_chan->ic_conn->ic_lock); 422 return (ISER_STATUS_FAIL); 423 } 424 425 iser_buf = (iser_buf_t *)buf->idb_buf_private; 426 iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr; 427 428 /* Pull the Read STag data out of the iSER header in the task hdl */ 429 reg_raddr = BE_IN64(&iser_hdr->rva); 430 reg_rkey = (ntohl(iser_hdr->rstag)); 431 432 /* Set up the WR raddr and rkey based upon the Read iSER STag */ 433 bzero(&wr, sizeof (ibt_send_wr_t)); 434 wr.wr.rc.rcwr.rdma.rdma_raddr = reg_raddr + buf->idb_bufoffset; 435 wr.wr.rc.rcwr.rdma.rdma_rkey = reg_rkey; 436 437 /* Set the transfer length from the IDM buf handle */ 438 iser_buf->buf_ds.ds_len = buf->idb_xfer_len; 439 440 /* Allocate an iSER WR handle and tuck the IDM buf handle into it */ 441 iser_wr = iser_wr_get(); 442 if (iser_wr == NULL) { 443 ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: unable to allocate " 444 "iser wr handle"); 445 mutex_exit(&iser_chan->ic_conn->ic_lock); 446 return (ISER_STATUS_FAIL); 447 } 448 iser_wr->iw_buf = buf; 449 iser_wr->iw_type = ISER_WR_RDMAW; 450 451 /* Use the address of our generic iser_wr handle as our WRID */ 452 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr; 453 454 /* Populate the rest of the work request */ 455 wr.wr_flags = IBT_WR_SEND_SIGNAL; 456 wr.wr_trans = IBT_RC_SRV; 457 wr.wr_opcode = IBT_WRC_RDMAW; 458 wr.wr_nds = 1; 459 wr.wr_sgl = &iser_buf->buf_ds; 460 461 #ifdef DEBUG 462 bcopy(&wr, &iser_buf->buf_wr, sizeof (ibt_send_wr_t)); 463 #endif 464 465 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 466 uintptr_t, buf->idb_buf, uint32_t, buf->idb_bufoffset, 467 uint64_t, reg_raddr, uint32_t, buf->idb_bufoffset, 468 uint32_t, reg_rkey, 469 uint32_t, buf->idb_xfer_len, int, XFER_BUF_TX_TO_INI); 470 471 /* Increment this channel's SQ posted count */ 472 mutex_enter(&iser_chan->ic_sq_post_lock); 473 iser_chan->ic_sq_post_count++; 474 if (iser_chan->ic_sq_post_count > iser_chan->ic_sq_max_post_count) 475 iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count; 476 mutex_exit(&iser_chan->ic_sq_post_lock); 477 478 status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL); 479 if (status != IBT_SUCCESS) { 480 ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send " 481 "failure (%d)", status); 482 iser_wr_free(iser_wr); 483 mutex_enter(&iser_chan->ic_sq_post_lock); 484 iser_chan->ic_sq_post_count--; 485 mutex_exit(&iser_chan->ic_sq_post_lock); 486 mutex_exit(&iser_chan->ic_conn->ic_lock); 487 return (ISER_STATUS_FAIL); 488 } 489 490 mutex_exit(&iser_chan->ic_conn->ic_lock); 491 return (ISER_STATUS_SUCCESS); 492 } 493 494 /* 495 * iser_xfer_buf_from_ini 496 * This is iSER's implementation of the 'Get_Data' operational primitive. 497 * The iSCSI layer at the target invokes this function when it is ready to 498 * receive the SCSI Write Data from the initiator. This function generates and 499 * sends an RDMA Read Message to get the data from the initiator. No R2T PDUs 500 * are generated. 501 */ 502 int 503 iser_xfer_buf_from_ini(idm_task_t *idt, idm_buf_t *buf) 504 { 505 iser_conn_t *iser_conn; 506 iser_chan_t *iser_chan; 507 iser_buf_t *iser_buf; 508 iser_wr_t *iser_wr; 509 iser_ctrl_hdr_t *iser_hdr; 510 ibt_send_wr_t wr; 511 uint64_t reg_raddr; 512 uint32_t reg_rkey; 513 int status; 514 515 /* Grab the iSER resources from the task and buf handles */ 516 iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private; 517 iser_chan = iser_conn->ic_chan; 518 519 mutex_enter(&iser_chan->ic_conn->ic_lock); 520 /* Bail out if the connection is closed */ 521 if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) || 522 (iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) { 523 mutex_exit(&iser_chan->ic_conn->ic_lock); 524 return (ISER_STATUS_FAIL); 525 } 526 527 iser_buf = (iser_buf_t *)buf->idb_buf_private; 528 iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr; 529 530 /* Pull the Write STag data out of the iSER header in the task hdl */ 531 reg_raddr = BE_IN64(&iser_hdr->wva); 532 reg_rkey = (ntohl(iser_hdr->wstag)); 533 534 /* Set up the WR raddr and rkey based upon the iSER Write STag */ 535 bzero(&wr, sizeof (ibt_send_wr_t)); 536 wr.wr.rc.rcwr.rdma.rdma_raddr = reg_raddr + buf->idb_bufoffset; 537 wr.wr.rc.rcwr.rdma.rdma_rkey = reg_rkey; 538 539 /* Set the transfer length from the IDM buf handle */ 540 iser_buf->buf_ds.ds_len = buf->idb_xfer_len; 541 542 /* Allocate an iSER WR handle and tuck the IDM buf handle into it */ 543 iser_wr = iser_wr_get(); 544 if (iser_wr == NULL) { 545 ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: unable to allocate " 546 "iser wr handle"); 547 mutex_exit(&iser_chan->ic_conn->ic_lock); 548 return (ISER_STATUS_FAIL); 549 } 550 iser_wr->iw_buf = buf; 551 iser_wr->iw_type = ISER_WR_RDMAR; 552 553 /* Use the address of our generic iser_wr handle as our WRID */ 554 wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr; 555 556 /* Populate the rest of the work request */ 557 wr.wr_flags = IBT_WR_SEND_SIGNAL; 558 wr.wr_trans = IBT_RC_SRV; 559 wr.wr_opcode = IBT_WRC_RDMAR; 560 wr.wr_nds = 1; 561 wr.wr_sgl = &iser_buf->buf_ds; 562 563 #ifdef DEBUG 564 bcopy(&wr, &iser_buf->buf_wr, sizeof (ibt_send_wr_t)); 565 #endif 566 567 DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic, 568 uintptr_t, buf->idb_buf, uint32_t, buf->idb_bufoffset, 569 uint64_t, reg_raddr, uint32_t, buf->idb_bufoffset, 570 uint32_t, reg_rkey, 571 uint32_t, buf->idb_xfer_len, int, XFER_BUF_RX_FROM_INI); 572 573 /* Increment this channel's SQ posted count */ 574 mutex_enter(&iser_chan->ic_sq_post_lock); 575 iser_chan->ic_sq_post_count++; 576 if (iser_chan->ic_sq_post_count > iser_chan->ic_sq_max_post_count) 577 iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count; 578 mutex_exit(&iser_chan->ic_sq_post_lock); 579 580 status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL); 581 if (status != IBT_SUCCESS) { 582 ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send " 583 "failure (%d)", status); 584 iser_wr_free(iser_wr); 585 mutex_enter(&iser_chan->ic_sq_post_lock); 586 iser_chan->ic_sq_post_count--; 587 mutex_exit(&iser_chan->ic_sq_post_lock); 588 mutex_exit(&iser_chan->ic_conn->ic_lock); 589 return (ISER_STATUS_FAIL); 590 } 591 592 mutex_exit(&iser_chan->ic_conn->ic_lock); 593 return (ISER_STATUS_SUCCESS); 594 } 595