void iscsi_iser_recv(struct iscsi_conn *conn, struct iscsi_hdr *hdr, char *rx_data, int rx_data_len) { int rc = 0; int datalen; int ahslen; /* verify PDU length */ datalen = ntoh24(hdr->dlength); if (datalen != rx_data_len) { printk(KERN_ERR "iscsi_iser: datalen %d (hdr) != %d (IB) \n", datalen, rx_data_len); rc = ISCSI_ERR_DATALEN; goto error; } /* read AHS */ ahslen = hdr->hlength * 4; rc = iscsi2_complete_pdu(conn, hdr, rx_data, rx_data_len); if (rc && rc != ISCSI_ERR_NO_SCSI_CMD) goto error; return; error: iscsi2_conn_failure(conn, rc); }
static void iser_handle_comp_error(struct iser_desc *desc) { struct iser_dto *dto = &desc->dto; struct iser_conn *ib_conn = dto->ib_conn; iser_dto_buffs_release(dto); if (desc->type == ISCSI_RX) { kfree(desc->data); kmem_cache_free(ig.desc_cache, desc); atomic_dec(&ib_conn->post_recv_buf_count); } else { /* type is TX control/command/dataout */ if (desc->type == ISCSI_TX_DATAOUT) kmem_cache_free(ig.desc_cache, desc); atomic_dec(&ib_conn->post_send_buf_count); } if (atomic_read(&ib_conn->post_recv_buf_count) == 0 && atomic_read(&ib_conn->post_send_buf_count) == 0) { /* getting here when the state is UP means that the conn is * * being terminated asynchronously from the iSCSI layer's * * perspective. */ if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP, ISER_CONN_TERMINATING)) iscsi2_conn_failure(ib_conn->iser_conn->iscsi_conn, ISCSI_ERR_CONN_FAILED); /* complete the termination process if disconnect event was delivered * * note there are no more non completed posts to the QP */ if (ib_conn->disc_evt_flag) { ib_conn->state = ISER_CONN_DOWN; wake_up_interruptible(&ib_conn->wait); } } }
void cxgb3i_conn_closing(struct s3_conn *c3cn) { struct iscsi_conn *conn; read_lock(&c3cn->callback_lock); conn = c3cn->user_data; if (conn && c3cn->state != C3CN_STATE_ESTABLISHED) iscsi2_conn_failure(conn, ISCSI_ERR_CONN_FAILED); read_unlock(&c3cn->callback_lock); }
int cxgb3i_conn_xmit_pdu(struct iscsi_task *task) { struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data; struct cxgb3i_conn *cconn = tcp_conn->dd_data; struct iscsi_tcp_task *tcp_task = task->dd_data; struct cxgb3i_task_data *tdata = tcp_task->dd_data; struct sk_buff *skb = tdata->skb; unsigned int datalen; int err; if (!skb) return 0; datalen = skb->data_len; tdata->skb = NULL; err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb); if (err > 0) { int pdulen = err; cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n", task, skb, skb->len, skb->data_len, err); if (task->conn->hdrdgst_en) pdulen += ISCSI_DIGEST_SIZE; if (datalen && task->conn->datadgst_en) pdulen += ISCSI_DIGEST_SIZE; task->conn->txdata_octets += pdulen; return 0; } if (err == -EAGAIN || err == -ENOBUFS) { /* reset skb to send when we are called again */ tdata->skb = skb; return err; } kfree_skb(skb); cxgb3i_tx_debug("itt 0x%x, skb 0x%p, len %u/%u, xmit err %d.\n", task->itt, skb, skb->len, skb->data_len, err); iscsi_conn_printk(KERN_ERR, task->conn, "xmit err %d.\n", err); iscsi2_conn_failure(task->conn, ISCSI_ERR_XMIT_FAILED); return err; }
static void iser_disconnected_handler(struct rdma_cm_id *cma_id) { struct iser_conn *ib_conn; ib_conn = (struct iser_conn *)cma_id->context; ib_conn->disc_evt_flag = 1; /* getting here when the state is UP means that the conn is being * * terminated asynchronously from the iSCSI layer's perspective. */ if (iser_conn_state_comp_exch(ib_conn, ISER_CONN_UP, ISER_CONN_TERMINATING)) iscsi2_conn_failure(ib_conn->iser_conn->iscsi_conn, ISCSI_ERR_CONN_FAILED); /* Complete the termination process if no posts are pending */ if ((atomic_read(&ib_conn->post_recv_buf_count) == 0) && (atomic_read(&ib_conn->post_send_buf_count) == 0)) { ib_conn->state = ISER_CONN_DOWN; wake_up_interruptible(&ib_conn->wait); } }
void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn) { struct sk_buff *skb; unsigned int read = 0; struct iscsi_conn *conn = c3cn->user_data; int err = 0; cxgb3i_rx_debug("cn 0x%p.\n", c3cn); read_lock(&c3cn->callback_lock); if (unlikely(!conn || conn->suspend_rx)) { cxgb3i_rx_debug("conn 0x%p, id %d, suspend_rx %lu!\n", conn, conn ? conn->id : 0xFF, conn ? conn->suspend_rx : 0xFF); read_unlock(&c3cn->callback_lock); return; } skb = skb_peek(&c3cn->receive_queue); while (!err && skb) { __skb_unlink(skb, &c3cn->receive_queue); read += skb_rx_pdulen(skb); cxgb3i_rx_debug("conn 0x%p, cn 0x%p, rx skb 0x%p, pdulen %u.\n", conn, c3cn, skb, skb_rx_pdulen(skb)); err = cxgb3i_conn_read_pdu_skb(conn, skb); __kfree_skb(skb); skb = skb_peek(&c3cn->receive_queue); } read_unlock(&c3cn->callback_lock); if (c3cn) { c3cn->copied_seq += read; cxgb3i_c3cn_rx_credits(c3cn, read); } conn->rxdata_octets += read; if (err) { cxgb3i_log_info("conn 0x%p rx failed err %d.\n", conn, err); iscsi2_conn_failure(conn, ISCSI_ERR_CONN_FAILED); } }
static int cxgb3i_conn_read_pdu_skb(struct iscsi_conn *conn, struct sk_buff *skb) { struct iscsi_tcp_conn *tcp_conn = conn->dd_data; bool offloaded = 0; unsigned int offset; int rc; cxgb3i_rx_debug("conn 0x%p, skb 0x%p, len %u, flag 0x%x.\n", conn, skb, skb->len, skb_ulp_mode(skb)); if (!iscsi_tcp_recv_segment_is_hdr(tcp_conn)) { iscsi2_conn_failure(conn, ISCSI_ERR_PROTO); return -EIO; } if (conn->hdrdgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_HCRC_ERROR)) { iscsi2_conn_failure(conn, ISCSI_ERR_HDR_DGST); return -EIO; } if (conn->datadgst_en && (skb_ulp_mode(skb) & ULP2_FLAG_DCRC_ERROR)) { iscsi2_conn_failure(conn, ISCSI_ERR_DATA_DGST); return -EIO; } /* iscsi hdr */ rc = read_pdu_skb(conn, skb, 0, 0); if (rc <= 0) return rc; if (iscsi_tcp_recv_segment_is_hdr(tcp_conn)) return 0; offset = rc; if (conn->hdrdgst_en) offset += ISCSI_DIGEST_SIZE; /* iscsi data */ if (skb_ulp_mode(skb) & ULP2_FLAG_DATA_DDPED) { cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, ddp'ed, " "itt 0x%x.\n", skb, tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK, tcp_conn->in.datalen, ntohl(tcp_conn->in.hdr->itt)); offloaded = 1; } else { cxgb3i_rx_debug("skb 0x%p, opcode 0x%x, data %u, NOT ddp'ed, " "itt 0x%x.\n", skb, tcp_conn->in.hdr->opcode & ISCSI_OPCODE_MASK, tcp_conn->in.datalen, ntohl(tcp_conn->in.hdr->itt)); offset += sizeof(struct cpl_iscsi_hdr_norss); } rc = read_pdu_skb(conn, skb, offset, offloaded); if (rc < 0) return rc; else return 0; }