#include <sys/types.h>
#include <sys/stat.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/byteorder.h>
#include <sys/sdt.h>
#include <sys/ib/clients/iser/iser.h>
int
iser_xfer_hello_msg(iser_chan_t *chan)
{
iser_hca_t *hca;
iser_wr_t *iser_wr;
iser_msg_t *msg;
ibt_send_wr_t wr;
iser_hello_hdr_t *hdr;
int status;
ASSERT(chan != NULL);
hca = (iser_hca_t *)chan->ic_hca;
if (hca == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: no hca handle found");
return (ISER_STATUS_FAIL);
}
msg = iser_msg_get(hca, 1, NULL);
if (msg == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: iser message cache "
"alloc failed");
return (ISER_STATUS_FAIL);
}
hdr = (iser_hello_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
hdr->opcode = ISER_OPCODE_HELLO_MSG;
hdr->rsvd1 = 0;
hdr->maxver = 1;
hdr->minver = 1;
hdr->iser_ird = htons(ISER_IB_DEFAULT_IRD);
hdr->rsvd2[0] = 0;
hdr->rsvd2[1] = 0;
iser_wr = iser_wr_get();
if (iser_wr == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: unable to allocate "
"iser wr handle");
iser_msg_free(msg);
return (ISER_STATUS_FAIL);
}
iser_wr->iw_msg = msg;
iser_wr->iw_type = ISER_WR_SEND;
wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
wr.wr_trans = IBT_RC_SRV;
wr.wr_opcode = IBT_WRC_SEND;
wr.wr_nds = 1;
wr.wr_sgl = &msg->msg_ds;
mutex_enter(&chan->ic_sq_post_lock);
chan->ic_sq_post_count++;
if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
chan->ic_sq_max_post_count = chan->ic_sq_post_count;
mutex_exit(&chan->ic_sq_post_lock);
status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
if (status != IBT_SUCCESS) {
ISER_LOG(CE_NOTE, "iser_xfer_hello_msg: ibt_post_send "
"failure (%d)", status);
mutex_enter(&chan->ic_sq_post_lock);
chan->ic_sq_post_count--;
mutex_exit(&chan->ic_sq_post_lock);
iser_msg_free(msg);
iser_wr_free(iser_wr);
return (ISER_STATUS_FAIL);
}
ISER_LOG(CE_NOTE, "Posting iSER Hello message: chan (0x%p): "
"IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr,
chan->ic_remoteip.un.ip4addr);
return (ISER_STATUS_SUCCESS);
}
int
iser_xfer_helloreply_msg(iser_chan_t *chan)
{
iser_hca_t *hca;
iser_wr_t *iser_wr;
ibt_send_wr_t wr;
iser_msg_t *msg;
iser_helloreply_hdr_t *hdr;
int status;
ASSERT(chan != NULL);
hca = (iser_hca_t *)chan->ic_hca;
if (hca == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: no hca handle "
"found");
return (ISER_STATUS_FAIL);
}
msg = iser_msg_get(hca, 1, NULL);
if (msg == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: iser message "
"cache alloc failed");
return (ISER_STATUS_FAIL);
}
hdr = (iser_helloreply_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
hdr->opcode = ISER_OPCODE_HELLOREPLY_MSG;
hdr->rsvd1 = 0;
hdr->flag = 0;
hdr->maxver = 1;
hdr->curver = 1;
hdr->iser_ord = htons(ISER_IB_DEFAULT_ORD);
hdr->rsvd2[0] = 0;
hdr->rsvd2[1] = 0;
iser_wr = iser_wr_get();
if (iser_wr == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: unable to "
"allocate iser wr handle");
iser_msg_free(msg);
return (ISER_STATUS_FAIL);
}
iser_wr->iw_msg = msg;
iser_wr->iw_type = ISER_WR_SEND;
wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
wr.wr_trans = IBT_RC_SRV;
wr.wr_opcode = IBT_WRC_SEND;
wr.wr_nds = 1;
wr.wr_sgl = &msg->msg_ds;
mutex_enter(&chan->ic_sq_post_lock);
chan->ic_sq_post_count++;
if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
chan->ic_sq_max_post_count = chan->ic_sq_post_count;
mutex_exit(&chan->ic_sq_post_lock);
status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
if (status != IBT_SUCCESS) {
ISER_LOG(CE_NOTE, "iser_xfer_helloreply_msg: ibt_post_send "
"failure (%d)", status);
mutex_enter(&chan->ic_sq_post_lock);
chan->ic_sq_post_count--;
mutex_exit(&chan->ic_sq_post_lock);
iser_msg_free(msg);
iser_wr_free(iser_wr);
return (ISER_STATUS_FAIL);
}
ISER_LOG(CE_NOTE, "Posting iSER HelloReply message: chan (0x%p): "
"IP [%x to %x]", (void *)chan, chan->ic_localip.un.ip4addr,
chan->ic_remoteip.un.ip4addr);
return (ISER_STATUS_SUCCESS);
}
int
iser_xfer_ctrlpdu(iser_chan_t *chan, idm_pdu_t *pdu)
{
iser_hca_t *hca;
iser_ctrl_hdr_t *hdr;
iser_msg_t *msg;
iser_wr_t *iser_wr;
ibt_send_wr_t wr;
int status;
iser_mr_t *mr;
iscsi_data_hdr_t *bhs;
idm_conn_t *ic;
idm_task_t *idt = NULL;
idm_buf_t *buf;
ASSERT(chan != NULL);
mutex_enter(&chan->ic_conn->ic_lock);
if ((chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
(chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
mutex_exit(&chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
ic = chan->ic_conn->ic_idmc;
bhs = (iscsi_data_hdr_t *)pdu->isp_hdr;
if (pdu->isp_flags & IDM_PDU_SET_STATSN) {
(ic->ic_conn_ops.icb_update_statsn)(NULL, pdu);
}
hca = (iser_hca_t *)chan->ic_hca;
if (hca == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: no hca handle found");
mutex_exit(&chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
msg = iser_msg_get(hca, 1, NULL);
if (msg == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: iser message cache "
"alloc failed");
mutex_exit(&chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
hdr = (iser_ctrl_hdr_t *)(uintptr_t)msg->msg_ds.ds_va;
bzero(hdr, sizeof (*hdr));
hdr->opcode = ISER_OPCODE_CTRL_TYPE_PDU;
if ((ic->ic_conn_type == CONN_TYPE_INI) &&
((bhs->opcode & ISCSI_OPCODE_MASK) == ISCSI_OP_SCSI_CMD) &&
((idt = idm_task_find(ic, bhs->itt, bhs->ttt)) != NULL)) {
if (!list_is_empty(&idt->idt_inbufv)) {
buf = idm_buf_find(&idt->idt_inbufv, 0);
ASSERT(buf != NULL);
mr = (iser_mr_t *)buf->idb_reg_private;
ASSERT(mr != NULL);
hdr->rsv_flag = 1;
hdr->rstag = htonl(mr->is_mrrkey);
BE_OUT64(&hdr->rva, mr->is_mrva);
}
if (!list_is_empty(&idt->idt_outbufv)) {
buf = idm_buf_find(&idt->idt_outbufv, 0);
ASSERT(buf != NULL);
mr = (iser_mr_t *)buf->idb_reg_private;
ASSERT(mr != NULL);
hdr->wsv_flag = 1;
hdr->wstag = htonl(mr->is_mrrkey);
BE_OUT64(&hdr->wva, mr->is_mrva);
}
idm_task_rele(idt);
}
bcopy(pdu->isp_hdr,
(uint8_t *)(uintptr_t)msg->msg_ds.ds_va + ISER_HEADER_LENGTH,
pdu->isp_hdrlen);
if (pdu->isp_datalen > 0) {
bcopy(pdu->isp_data,
(uint8_t *)(uintptr_t)msg->msg_ds.ds_va +
ISER_HEADER_LENGTH + pdu->isp_hdrlen,
pdu->isp_datalen);
msg->msg_ds.ds_len = ISER_HEADER_LENGTH + pdu->isp_hdrlen +
pdu->isp_datalen;
} else {
msg->msg_ds.ds_len = ISER_HEADER_LENGTH + pdu->isp_hdrlen;
}
bzero(&wr, sizeof (wr));
iser_wr = iser_wr_get();
if (iser_wr == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: unable to allocate "
"iser wr handle");
iser_msg_free(msg);
mutex_exit(&chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
iser_wr->iw_pdu = pdu;
iser_wr->iw_msg = msg;
iser_wr->iw_type = ISER_WR_SEND;
wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
wr.wr_trans = IBT_RC_SRV;
wr.wr_opcode = IBT_WRC_SEND;
wr.wr_nds = 1;
wr.wr_sgl = &msg->msg_ds;
mutex_enter(&chan->ic_sq_post_lock);
chan->ic_sq_post_count++;
if (chan->ic_sq_post_count > chan->ic_sq_max_post_count)
chan->ic_sq_max_post_count = chan->ic_sq_post_count;
mutex_exit(&chan->ic_sq_post_lock);
status = ibt_post_send(chan->ic_chanhdl, &wr, 1, NULL);
if (status != IBT_SUCCESS) {
ISER_LOG(CE_NOTE, "iser_xfer_ctrlpdu: ibt_post_send "
"failure (%d)", status);
iser_msg_free(msg);
iser_wr_free(iser_wr);
mutex_enter(&chan->ic_sq_post_lock);
chan->ic_sq_post_count--;
mutex_exit(&chan->ic_sq_post_lock);
mutex_exit(&chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
mutex_exit(&chan->ic_conn->ic_lock);
return (ISER_STATUS_SUCCESS);
}
int
iser_xfer_buf_to_ini(idm_task_t *idt, idm_buf_t *buf)
{
iser_conn_t *iser_conn;
iser_chan_t *iser_chan;
iser_buf_t *iser_buf;
iser_wr_t *iser_wr;
iser_ctrl_hdr_t *iser_hdr;
ibt_send_wr_t wr;
uint64_t reg_raddr;
uint32_t reg_rkey;
int status;
iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private;
iser_chan = iser_conn->ic_chan;
mutex_enter(&iser_chan->ic_conn->ic_lock);
if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
(iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
iser_buf = (iser_buf_t *)buf->idb_buf_private;
iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr;
reg_raddr = BE_IN64(&iser_hdr->rva);
reg_rkey = (ntohl(iser_hdr->rstag));
bzero(&wr, sizeof (ibt_send_wr_t));
wr.wr.rc.rcwr.rdma.rdma_raddr = reg_raddr + buf->idb_bufoffset;
wr.wr.rc.rcwr.rdma.rdma_rkey = reg_rkey;
iser_buf->buf_ds.ds_len = buf->idb_xfer_len;
iser_wr = iser_wr_get();
if (iser_wr == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: unable to allocate "
"iser wr handle");
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
iser_wr->iw_buf = buf;
iser_wr->iw_type = ISER_WR_RDMAW;
wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
wr.wr_flags = IBT_WR_SEND_SIGNAL;
wr.wr_trans = IBT_RC_SRV;
wr.wr_opcode = IBT_WRC_RDMAW;
wr.wr_nds = 1;
wr.wr_sgl = &iser_buf->buf_ds;
#ifdef DEBUG
bcopy(&wr, &iser_buf->buf_wr, sizeof (ibt_send_wr_t));
#endif
DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
uintptr_t, buf->idb_buf, uint32_t, buf->idb_bufoffset,
uint64_t, reg_raddr, uint32_t, buf->idb_bufoffset,
uint32_t, reg_rkey,
uint32_t, buf->idb_xfer_len, int, XFER_BUF_TX_TO_INI);
mutex_enter(&iser_chan->ic_sq_post_lock);
iser_chan->ic_sq_post_count++;
if (iser_chan->ic_sq_post_count > iser_chan->ic_sq_max_post_count)
iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count;
mutex_exit(&iser_chan->ic_sq_post_lock);
status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
if (status != IBT_SUCCESS) {
ISER_LOG(CE_NOTE, "iser_xfer_buf_to_ini: ibt_post_send "
"failure (%d)", status);
iser_wr_free(iser_wr);
mutex_enter(&iser_chan->ic_sq_post_lock);
iser_chan->ic_sq_post_count--;
mutex_exit(&iser_chan->ic_sq_post_lock);
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_SUCCESS);
}
int
iser_xfer_buf_from_ini(idm_task_t *idt, idm_buf_t *buf)
{
iser_conn_t *iser_conn;
iser_chan_t *iser_chan;
iser_buf_t *iser_buf;
iser_wr_t *iser_wr;
iser_ctrl_hdr_t *iser_hdr;
ibt_send_wr_t wr;
uint64_t reg_raddr;
uint32_t reg_rkey;
int status;
iser_conn = (iser_conn_t *)idt->idt_ic->ic_transport_private;
iser_chan = iser_conn->ic_chan;
mutex_enter(&iser_chan->ic_conn->ic_lock);
if ((iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSING) ||
(iser_chan->ic_conn->ic_stage == ISER_CONN_STAGE_CLOSED)) {
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
iser_buf = (iser_buf_t *)buf->idb_buf_private;
iser_hdr = (iser_ctrl_hdr_t *)idt->idt_transport_hdr;
reg_raddr = BE_IN64(&iser_hdr->wva);
reg_rkey = (ntohl(iser_hdr->wstag));
bzero(&wr, sizeof (ibt_send_wr_t));
wr.wr.rc.rcwr.rdma.rdma_raddr = reg_raddr + buf->idb_bufoffset;
wr.wr.rc.rcwr.rdma.rdma_rkey = reg_rkey;
iser_buf->buf_ds.ds_len = buf->idb_xfer_len;
iser_wr = iser_wr_get();
if (iser_wr == NULL) {
ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: unable to allocate "
"iser wr handle");
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
iser_wr->iw_buf = buf;
iser_wr->iw_type = ISER_WR_RDMAR;
wr.wr_id = (ibt_wrid_t)(uintptr_t)iser_wr;
wr.wr_flags = IBT_WR_SEND_SIGNAL;
wr.wr_trans = IBT_RC_SRV;
wr.wr_opcode = IBT_WRC_RDMAR;
wr.wr_nds = 1;
wr.wr_sgl = &iser_buf->buf_ds;
#ifdef DEBUG
bcopy(&wr, &iser_buf->buf_wr, sizeof (ibt_send_wr_t));
#endif
DTRACE_ISCSI_8(xfer__start, idm_conn_t *, idt->idt_ic,
uintptr_t, buf->idb_buf, uint32_t, buf->idb_bufoffset,
uint64_t, reg_raddr, uint32_t, buf->idb_bufoffset,
uint32_t, reg_rkey,
uint32_t, buf->idb_xfer_len, int, XFER_BUF_RX_FROM_INI);
mutex_enter(&iser_chan->ic_sq_post_lock);
iser_chan->ic_sq_post_count++;
if (iser_chan->ic_sq_post_count > iser_chan->ic_sq_max_post_count)
iser_chan->ic_sq_max_post_count = iser_chan->ic_sq_post_count;
mutex_exit(&iser_chan->ic_sq_post_lock);
status = ibt_post_send(iser_chan->ic_chanhdl, &wr, 1, NULL);
if (status != IBT_SUCCESS) {
ISER_LOG(CE_NOTE, "iser_xfer_buf_from_ini: ibt_post_send "
"failure (%d)", status);
iser_wr_free(iser_wr);
mutex_enter(&iser_chan->ic_sq_post_lock);
iser_chan->ic_sq_post_count--;
mutex_exit(&iser_chan->ic_sq_post_lock);
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_FAIL);
}
mutex_exit(&iser_chan->ic_conn->ic_lock);
return (ISER_STATUS_SUCCESS);
}