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