diff options
Diffstat (limited to 'drivers/infiniband/ulp/isert/ib_isert.c')
-rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.c | 268 |
1 files changed, 225 insertions, 43 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index 2693129055c1..3f62041222f2 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c @@ -388,6 +388,7 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) init_waitqueue_head(&isert_conn->conn_wait_comp_err); kref_init(&isert_conn->conn_kref); kref_get(&isert_conn->conn_kref); + mutex_init(&isert_conn->conn_mutex); cma_id->context = isert_conn; isert_conn->conn_cm_id = cma_id; @@ -540,15 +541,32 @@ isert_disconnect_work(struct work_struct *work) struct isert_conn, conn_logout_work); pr_debug("isert_disconnect_work(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); - + mutex_lock(&isert_conn->conn_mutex); isert_conn->state = ISER_CONN_DOWN; if (isert_conn->post_recv_buf_count == 0 && atomic_read(&isert_conn->post_send_buf_count) == 0) { pr_debug("Calling wake_up(&isert_conn->conn_wait);\n"); - wake_up(&isert_conn->conn_wait); + mutex_unlock(&isert_conn->conn_mutex); + goto wake_up; + } + if (!isert_conn->conn_cm_id) { + mutex_unlock(&isert_conn->conn_mutex); + isert_put_conn(isert_conn); + return; } + if (!isert_conn->logout_posted) { + pr_debug("Calling rdma_disconnect for !logout_posted from" + " isert_disconnect_work\n"); + rdma_disconnect(isert_conn->conn_cm_id); + mutex_unlock(&isert_conn->conn_mutex); + iscsit_cause_connection_reinstatement(isert_conn->conn, 0); + goto wake_up; + } + mutex_unlock(&isert_conn->conn_mutex); +wake_up: + wake_up(&isert_conn->conn_wait); isert_put_conn(isert_conn); } @@ -934,16 +952,11 @@ isert_handle_scsi_cmd(struct isert_conn *isert_conn, } sequence_cmd: - rc = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); + rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); if (!rc && dump_payload == false && unsol_data) iscsit_set_unsoliticed_dataout(cmd); - if (rc == CMDSN_ERROR_CANNOT_RECOVER) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, (unsigned char *)hdr, cmd); - return 0; } @@ -1001,17 +1014,71 @@ isert_handle_iscsi_dataout(struct isert_conn *isert_conn, } static int +isert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, + struct iser_rx_desc *rx_desc, unsigned char *buf) +{ + struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; + struct iscsi_conn *conn = isert_conn->conn; + struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf; + int rc; + + rc = iscsit_setup_nop_out(conn, cmd, hdr); + if (rc < 0) + return rc; + /* + * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload + */ + + return iscsit_process_nop_out(conn, cmd, hdr); +} + +static int +isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, + struct iser_rx_desc *rx_desc, struct iscsi_text *hdr) +{ + struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; + struct iscsi_conn *conn = isert_conn->conn; + u32 payload_length = ntoh24(hdr->dlength); + int rc; + unsigned char *text_in; + + rc = iscsit_setup_text_cmd(conn, cmd, hdr); + if (rc < 0) + return rc; + + text_in = kzalloc(payload_length, GFP_KERNEL); + if (!text_in) { + pr_err("Unable to allocate text_in of payload_length: %u\n", + payload_length); + return -ENOMEM; + } + cmd->text_in_ptr = text_in; + + memcpy(cmd->text_in_ptr, &rx_desc->data[0], payload_length); + + return iscsit_process_text_cmd(conn, cmd, hdr); +} + +static int isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, uint32_t read_stag, uint64_t read_va, uint32_t write_stag, uint64_t write_va) { struct iscsi_hdr *hdr = &rx_desc->iscsi_header; struct iscsi_conn *conn = isert_conn->conn; + struct iscsi_session *sess = conn->sess; struct iscsi_cmd *cmd; struct isert_cmd *isert_cmd; int ret = -EINVAL; u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK); + if (sess->sess_ops->SessionType && + (!(opcode & ISCSI_OP_TEXT) || !(opcode & ISCSI_OP_LOGOUT))) { + pr_err("Got illegal opcode: 0x%02x in SessionType=Discovery," + " ignoring\n", opcode); + return 0; + } + switch (opcode) { case ISCSI_OP_SCSI_CMD: cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); @@ -1032,7 +1099,9 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, if (!cmd) break; - ret = iscsit_handle_nop_out(conn, cmd, (unsigned char *)hdr); + isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd); + ret = isert_handle_nop_out(isert_conn, isert_cmd, + rx_desc, (unsigned char *)hdr); break; case ISCSI_OP_SCSI_DATA_OUT: ret = isert_handle_iscsi_dataout(isert_conn, rx_desc, @@ -1057,6 +1126,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, SECONDS_FOR_LOGOUT_COMP * HZ); break; + case ISCSI_OP_TEXT: + cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); + if (!cmd) + break; + + isert_cmd = container_of(cmd, struct isert_cmd, iscsi_cmd); + ret = isert_handle_text_cmd(isert_conn, isert_cmd, + rx_desc, (struct iscsi_text *)hdr); + break; default: pr_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode); dump_stack(); @@ -1184,14 +1262,12 @@ isert_put_cmd(struct isert_cmd *isert_cmd) { struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; struct isert_conn *isert_conn = isert_cmd->conn; - struct iscsi_conn *conn; + struct iscsi_conn *conn = isert_conn->conn; pr_debug("Entering isert_put_cmd: %p\n", isert_cmd); switch (cmd->iscsi_opcode) { case ISCSI_OP_SCSI_CMD: - conn = isert_conn->conn; - spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node)) list_del(&cmd->i_conn_node); @@ -1201,16 +1277,19 @@ isert_put_cmd(struct isert_cmd *isert_cmd) iscsit_stop_dataout_timer(cmd); isert_unmap_cmd(isert_cmd, isert_conn); - /* - * Fall-through - */ + transport_generic_free_cmd(&cmd->se_cmd, 0); + break; case ISCSI_OP_SCSI_TMFUNC: + spin_lock_bh(&conn->cmd_lock); + if (!list_empty(&cmd->i_conn_node)) + list_del(&cmd->i_conn_node); + spin_unlock_bh(&conn->cmd_lock); + transport_generic_free_cmd(&cmd->se_cmd, 0); break; case ISCSI_OP_REJECT: case ISCSI_OP_NOOP_OUT: - conn = isert_conn->conn; - + case ISCSI_OP_TEXT: spin_lock_bh(&conn->cmd_lock); if (!list_empty(&cmd->i_conn_node)) list_del(&cmd->i_conn_node); @@ -1222,6 +1301,9 @@ isert_put_cmd(struct isert_cmd *isert_cmd) * associated cmd->se_cmd needs to be released. */ if (cmd->se_cmd.se_tfo != NULL) { + pr_debug("Calling transport_generic_free_cmd from" + " isert_put_cmd for 0x%02x\n", + cmd->iscsi_opcode); transport_generic_free_cmd(&cmd->se_cmd, 0); break; } @@ -1249,11 +1331,11 @@ static void isert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd, struct ib_device *ib_dev) { - if (isert_cmd->sense_buf_dma != 0) { - pr_debug("Calling ib_dma_unmap_single for isert_cmd->sense_buf_dma\n"); - ib_dma_unmap_single(ib_dev, isert_cmd->sense_buf_dma, - isert_cmd->sense_buf_len, DMA_TO_DEVICE); - isert_cmd->sense_buf_dma = 0; + if (isert_cmd->pdu_buf_dma != 0) { + pr_debug("Calling ib_dma_unmap_single for isert_cmd->pdu_buf_dma\n"); + ib_dma_unmap_single(ib_dev, isert_cmd->pdu_buf_dma, + isert_cmd->pdu_buf_len, DMA_TO_DEVICE); + isert_cmd->pdu_buf_dma = 0; } isert_unmap_tx_desc(tx_desc, ib_dev); @@ -1318,8 +1400,8 @@ isert_do_control_comp(struct work_struct *work) atomic_dec(&isert_conn->post_send_buf_count); cmd->i_state = ISTATE_SENT_STATUS; - complete(&cmd->reject_comp); isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev); + break; case ISTATE_SEND_LOGOUTRSP: pr_debug("Calling iscsit_logout_post_handler >>>>>>>>>>>>>>\n"); /* @@ -1329,6 +1411,11 @@ isert_do_control_comp(struct work_struct *work) isert_conn->logout_posted = true; iscsit_logout_post_handler(cmd, cmd->conn); break; + case ISTATE_SEND_TEXTRSP: + atomic_dec(&isert_conn->post_send_buf_count); + cmd->i_state = ISTATE_SENT_STATUS; + isert_completion_put(&isert_cmd->tx_desc, isert_cmd, ib_dev); + break; default: pr_err("Unknown do_control_comp i_state %d\n", cmd->i_state); dump_stack(); @@ -1345,7 +1432,9 @@ isert_response_completion(struct iser_tx_desc *tx_desc, struct iscsi_cmd *cmd = &isert_cmd->iscsi_cmd; if (cmd->i_state == ISTATE_SEND_TASKMGTRSP || - cmd->i_state == ISTATE_SEND_LOGOUTRSP) { + cmd->i_state == ISTATE_SEND_LOGOUTRSP || + cmd->i_state == ISTATE_SEND_REJECT || + cmd->i_state == ISTATE_SEND_TEXTRSP) { isert_unmap_tx_desc(tx_desc, ib_dev); INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp); @@ -1419,7 +1508,11 @@ isert_cq_comp_err(struct iser_tx_desc *tx_desc, struct isert_conn *isert_conn) pr_debug("isert_cq_comp_err >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"); pr_debug("Calling wake_up from isert_cq_comp_err\n"); - isert_conn->state = ISER_CONN_TERMINATING; + mutex_lock(&isert_conn->conn_mutex); + if (isert_conn->state != ISER_CONN_DOWN) + isert_conn->state = ISER_CONN_TERMINATING; + mutex_unlock(&isert_conn->conn_mutex); + wake_up(&isert_conn->conn_wait_comp_err); } } @@ -1445,6 +1538,7 @@ isert_cq_tx_work(struct work_struct *work) } else { pr_debug("TX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n"); pr_debug("TX wc.status: 0x%08x\n", wc.status); + pr_debug("TX wc.vendor_err: 0x%08x\n", wc.vendor_err); atomic_dec(&isert_conn->post_send_buf_count); isert_cq_comp_err(tx_desc, isert_conn); } @@ -1484,9 +1578,11 @@ isert_cq_rx_work(struct work_struct *work) isert_rx_completion(rx_desc, isert_conn, xfer_len); } else { pr_debug("RX wc.status != IB_WC_SUCCESS >>>>>>>>>>>>>>\n"); - if (wc.status != IB_WC_WR_FLUSH_ERR) + if (wc.status != IB_WC_WR_FLUSH_ERR) { pr_debug("RX wc.status: 0x%08x\n", wc.status); - + pr_debug("RX wc.vendor_err: 0x%08x\n", + wc.vendor_err); + } isert_conn->post_recv_buf_count--; isert_cq_comp_err(NULL, isert_conn); } @@ -1543,7 +1639,7 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd) (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { struct ib_device *ib_dev = isert_conn->conn_cm_id->device; struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; - u32 padding, sense_len; + u32 padding, pdu_len; put_unaligned_be16(cmd->se_cmd.scsi_sense_length, cmd->sense_buffer); @@ -1551,15 +1647,15 @@ isert_put_response(struct iscsi_conn *conn, struct iscsi_cmd *cmd) padding = -(cmd->se_cmd.scsi_sense_length) & 3; hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length); - sense_len = cmd->se_cmd.scsi_sense_length + padding; + pdu_len = cmd->se_cmd.scsi_sense_length + padding; - isert_cmd->sense_buf_dma = ib_dma_map_single(ib_dev, - (void *)cmd->sense_buffer, sense_len, + isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, + (void *)cmd->sense_buffer, pdu_len, DMA_TO_DEVICE); - isert_cmd->sense_buf_len = sense_len; - tx_dsg->addr = isert_cmd->sense_buf_dma; - tx_dsg->length = sense_len; + isert_cmd->pdu_buf_len = pdu_len; + tx_dsg->addr = isert_cmd->pdu_buf_dma; + tx_dsg->length = pdu_len; tx_dsg->lkey = isert_conn->conn_mr->lkey; isert_cmd->tx_desc.num_sge = 2; } @@ -1637,11 +1733,25 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn) struct isert_cmd, iscsi_cmd); struct isert_conn *isert_conn = (struct isert_conn *)conn->context; struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; + struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; + struct iscsi_reject *hdr = + (struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header; isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); - iscsit_build_reject(cmd, conn, (struct iscsi_reject *) - &isert_cmd->tx_desc.iscsi_header); + iscsit_build_reject(cmd, conn, hdr); isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); + + hton24(hdr->dlength, ISCSI_HDR_LEN); + isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, + (void *)cmd->buf_ptr, ISCSI_HDR_LEN, + DMA_TO_DEVICE); + isert_cmd->pdu_buf_len = ISCSI_HDR_LEN; + tx_dsg->addr = isert_cmd->pdu_buf_dma; + tx_dsg->length = ISCSI_HDR_LEN; + tx_dsg->lkey = isert_conn->conn_mr->lkey; + isert_cmd->tx_desc.num_sge = 2; + isert_init_send_wr(isert_cmd, send_wr); pr_debug("Posting Reject IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); @@ -1650,6 +1760,47 @@ isert_put_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn) } static int +isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) +{ + struct isert_cmd *isert_cmd = container_of(cmd, + struct isert_cmd, iscsi_cmd); + struct isert_conn *isert_conn = (struct isert_conn *)conn->context; + struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; + struct iscsi_text_rsp *hdr = + (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header; + u32 txt_rsp_len; + int rc; + + isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); + rc = iscsit_build_text_rsp(cmd, conn, hdr); + if (rc < 0) + return rc; + + txt_rsp_len = rc; + isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); + + if (txt_rsp_len) { + struct ib_device *ib_dev = isert_conn->conn_cm_id->device; + struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; + void *txt_rsp_buf = cmd->buf_ptr; + + isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, + txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE); + + isert_cmd->pdu_buf_len = txt_rsp_len; + tx_dsg->addr = isert_cmd->pdu_buf_dma; + tx_dsg->length = txt_rsp_len; + tx_dsg->lkey = isert_conn->conn_mr->lkey; + isert_cmd->tx_desc.num_sge = 2; + } + isert_init_send_wr(isert_cmd, send_wr); + + pr_debug("Posting Text Response IB_WR_SEND >>>>>>>>>>>>>>>>>>>>>>\n"); + + return isert_post_response(isert_conn, isert_cmd); +} + +static int isert_build_rdma_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, struct ib_sge *ib_sge, struct ib_send_wr *send_wr, u32 data_left, u32 offset) @@ -1947,6 +2098,9 @@ isert_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) case ISTATE_SEND_REJECT: ret = isert_put_reject(cmd, conn); break; + case ISTATE_SEND_TEXTRSP: + ret = isert_put_text_rsp(cmd, conn); + break; case ISTATE_SEND_STATUS: /* * Special case for sending non GOOD SCSI status from TX thread @@ -2175,6 +2329,17 @@ isert_free_np(struct iscsi_np *np) kfree(isert_np); } +static int isert_check_state(struct isert_conn *isert_conn, int state) +{ + int ret; + + mutex_lock(&isert_conn->conn_mutex); + ret = (isert_conn->state == state); + mutex_unlock(&isert_conn->conn_mutex); + + return ret; +} + static void isert_free_conn(struct iscsi_conn *conn) { struct isert_conn *isert_conn = conn->context; @@ -2184,26 +2349,43 @@ static void isert_free_conn(struct iscsi_conn *conn) * Decrement post_send_buf_count for special case when called * from isert_do_control_comp() -> iscsit_logout_post_handler() */ + mutex_lock(&isert_conn->conn_mutex); if (isert_conn->logout_posted) atomic_dec(&isert_conn->post_send_buf_count); - if (isert_conn->conn_cm_id) + if (isert_conn->conn_cm_id && isert_conn->state != ISER_CONN_DOWN) { + pr_debug("Calling rdma_disconnect from isert_free_conn\n"); rdma_disconnect(isert_conn->conn_cm_id); + } /* * Only wait for conn_wait_comp_err if the isert_conn made it * into full feature phase.. */ - if (isert_conn->state > ISER_CONN_INIT) { + if (isert_conn->state == ISER_CONN_UP) { pr_debug("isert_free_conn: Before wait_event comp_err %d\n", isert_conn->state); + mutex_unlock(&isert_conn->conn_mutex); + wait_event(isert_conn->conn_wait_comp_err, - isert_conn->state == ISER_CONN_TERMINATING); - pr_debug("isert_free_conn: After wait_event #1 >>>>>>>>>>>>\n"); + (isert_check_state(isert_conn, ISER_CONN_TERMINATING))); + + wait_event(isert_conn->conn_wait, + (isert_check_state(isert_conn, ISER_CONN_DOWN))); + + isert_put_conn(isert_conn); + return; + } + if (isert_conn->state == ISER_CONN_INIT) { + mutex_unlock(&isert_conn->conn_mutex); + isert_put_conn(isert_conn); + return; } + pr_debug("isert_free_conn: wait_event conn_wait %d\n", + isert_conn->state); + mutex_unlock(&isert_conn->conn_mutex); - pr_debug("isert_free_conn: wait_event conn_wait %d\n", isert_conn->state); - wait_event(isert_conn->conn_wait, isert_conn->state == ISER_CONN_DOWN); - pr_debug("isert_free_conn: After wait_event #2 >>>>>>>>>>>>>>>>>>>>\n"); + wait_event(isert_conn->conn_wait, + (isert_check_state(isert_conn, ISER_CONN_DOWN))); isert_put_conn(isert_conn); } |