diff options
| author | Sagi Grimberg <sagig@mellanox.com> | 2015-02-09 11:07:25 -0500 |
|---|---|---|
| committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-02-12 14:24:29 -0500 |
| commit | e4f4e8016e6823475291eb0da7cc95d0fada2237 (patch) | |
| tree | d9e1bb4da2c4d3ce8f80d055055482f89d490741 | |
| parent | 11378cdbb69521530f69072a987f7f1280747c1a (diff) | |
iscsi/iser-target: Support multi-sequence sendtargets text response
In case sendtargets response is larger than initiator MRDSL, we
send a partial sendtargets response (setting F=0, C=1, TTT!=0xffffffff),
accept a consecutive empty text message and send the rest of the payload.
In case we are done, we set F=1, C=0, TTT=0xffffffff.
We do that by storing the sendtargets response bytes done under
the session.
This patch also makes iscsit_find_cmd_from_itt public for isert.
(Re-add cmd->maxcmdsn_inc and clear in iscsit_build_text_rsp - nab)
Signed-off-by: Sagi Grimberg <sagig@mellanox.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
| -rw-r--r-- | drivers/infiniband/ulp/isert/ib_isert.c | 18 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 87 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_util.c | 1 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_util.h | 1 | ||||
| -rw-r--r-- | include/target/iscsi/iscsi_target_core.h | 1 |
5 files changed, 82 insertions, 26 deletions
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c index da8c860e71c1..075b19cc78e8 100644 --- a/drivers/infiniband/ulp/isert/ib_isert.c +++ b/drivers/infiniband/ulp/isert/ib_isert.c | |||
| @@ -1436,9 +1436,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, | |||
| 1436 | ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr); | 1436 | ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr); |
| 1437 | break; | 1437 | break; |
| 1438 | case ISCSI_OP_TEXT: | 1438 | case ISCSI_OP_TEXT: |
| 1439 | cmd = isert_allocate_cmd(conn); | 1439 | if (be32_to_cpu(hdr->ttt) != 0xFFFFFFFF) { |
| 1440 | if (!cmd) | 1440 | cmd = iscsit_find_cmd_from_itt(conn, hdr->itt); |
| 1441 | break; | 1441 | if (!cmd) |
| 1442 | break; | ||
| 1443 | } else { | ||
| 1444 | cmd = isert_allocate_cmd(conn); | ||
| 1445 | if (!cmd) | ||
| 1446 | break; | ||
| 1447 | } | ||
| 1442 | 1448 | ||
| 1443 | isert_cmd = iscsit_priv_cmd(cmd); | 1449 | isert_cmd = iscsit_priv_cmd(cmd); |
| 1444 | ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd, | 1450 | ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd, |
| @@ -1660,6 +1666,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) | |||
| 1660 | struct isert_conn *isert_conn = isert_cmd->conn; | 1666 | struct isert_conn *isert_conn = isert_cmd->conn; |
| 1661 | struct iscsi_conn *conn = isert_conn->conn; | 1667 | struct iscsi_conn *conn = isert_conn->conn; |
| 1662 | struct isert_device *device = isert_conn->conn_device; | 1668 | struct isert_device *device = isert_conn->conn_device; |
| 1669 | struct iscsi_text_rsp *hdr; | ||
| 1663 | 1670 | ||
| 1664 | isert_dbg("Cmd %p\n", isert_cmd); | 1671 | isert_dbg("Cmd %p\n", isert_cmd); |
| 1665 | 1672 | ||
| @@ -1700,6 +1707,11 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) | |||
| 1700 | case ISCSI_OP_REJECT: | 1707 | case ISCSI_OP_REJECT: |
| 1701 | case ISCSI_OP_NOOP_OUT: | 1708 | case ISCSI_OP_NOOP_OUT: |
| 1702 | case ISCSI_OP_TEXT: | 1709 | case ISCSI_OP_TEXT: |
| 1710 | hdr = (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header; | ||
| 1711 | /* If the continue bit is on, keep the command alive */ | ||
| 1712 | if (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE) | ||
| 1713 | break; | ||
| 1714 | |||
| 1703 | spin_lock_bh(&conn->cmd_lock); | 1715 | spin_lock_bh(&conn->cmd_lock); |
| 1704 | if (!list_empty(&cmd->i_conn_node)) | 1716 | if (!list_empty(&cmd->i_conn_node)) |
| 1705 | list_del_init(&cmd->i_conn_node); | 1717 | list_del_init(&cmd->i_conn_node); |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 75c29b687f35..f533a0dfa4de 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
| @@ -1994,6 +1994,7 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
| 1994 | cmd->cmd_sn = be32_to_cpu(hdr->cmdsn); | 1994 | cmd->cmd_sn = be32_to_cpu(hdr->cmdsn); |
| 1995 | cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); | 1995 | cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); |
| 1996 | cmd->data_direction = DMA_NONE; | 1996 | cmd->data_direction = DMA_NONE; |
| 1997 | cmd->text_in_ptr = NULL; | ||
| 1997 | 1998 | ||
| 1998 | return 0; | 1999 | return 0; |
| 1999 | } | 2000 | } |
| @@ -2007,9 +2008,13 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
| 2007 | int cmdsn_ret; | 2008 | int cmdsn_ret; |
| 2008 | 2009 | ||
| 2009 | if (!text_in) { | 2010 | if (!text_in) { |
| 2010 | pr_err("Unable to locate text_in buffer for sendtargets" | 2011 | cmd->targ_xfer_tag = be32_to_cpu(hdr->ttt); |
| 2011 | " discovery\n"); | 2012 | if (cmd->targ_xfer_tag == 0xFFFFFFFF) { |
| 2012 | goto reject; | 2013 | pr_err("Unable to locate text_in buffer for sendtargets" |
| 2014 | " discovery\n"); | ||
| 2015 | goto reject; | ||
| 2016 | } | ||
| 2017 | goto empty_sendtargets; | ||
| 2013 | } | 2018 | } |
| 2014 | if (strncmp("SendTargets", text_in, 11) != 0) { | 2019 | if (strncmp("SendTargets", text_in, 11) != 0) { |
| 2015 | pr_err("Received Text Data that is not" | 2020 | pr_err("Received Text Data that is not" |
| @@ -2036,6 +2041,7 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | |||
| 2036 | list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); | 2041 | list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list); |
| 2037 | spin_unlock_bh(&conn->cmd_lock); | 2042 | spin_unlock_bh(&conn->cmd_lock); |
| 2038 | 2043 | ||
| 2044 | empty_sendtargets: | ||
| 2039 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); | 2045 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); |
| 2040 | 2046 | ||
| 2041 | if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { | 2047 | if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { |
| @@ -3385,7 +3391,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np) | |||
| 3385 | 3391 | ||
| 3386 | static int | 3392 | static int |
| 3387 | iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, | 3393 | iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, |
| 3388 | enum iscsit_transport_type network_transport) | 3394 | enum iscsit_transport_type network_transport, |
| 3395 | int skip_bytes, bool *completed) | ||
| 3389 | { | 3396 | { |
| 3390 | char *payload = NULL; | 3397 | char *payload = NULL; |
| 3391 | struct iscsi_conn *conn = cmd->conn; | 3398 | struct iscsi_conn *conn = cmd->conn; |
| @@ -3476,9 +3483,16 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, | |||
| 3476 | end_of_buf = 1; | 3483 | end_of_buf = 1; |
| 3477 | goto eob; | 3484 | goto eob; |
| 3478 | } | 3485 | } |
| 3479 | memcpy(payload + payload_len, buf, len); | 3486 | |
| 3480 | payload_len += len; | 3487 | if (skip_bytes && len <= skip_bytes) { |
| 3481 | target_name_printed = 1; | 3488 | skip_bytes -= len; |
| 3489 | } else { | ||
| 3490 | memcpy(payload + payload_len, buf, len); | ||
| 3491 | payload_len += len; | ||
| 3492 | target_name_printed = 1; | ||
| 3493 | if (len > skip_bytes) | ||
| 3494 | skip_bytes = 0; | ||
| 3495 | } | ||
| 3482 | } | 3496 | } |
| 3483 | 3497 | ||
| 3484 | len = sprintf(buf, "TargetAddress=" | 3498 | len = sprintf(buf, "TargetAddress=" |
| @@ -3494,15 +3508,24 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, | |||
| 3494 | end_of_buf = 1; | 3508 | end_of_buf = 1; |
| 3495 | goto eob; | 3509 | goto eob; |
| 3496 | } | 3510 | } |
| 3497 | memcpy(payload + payload_len, buf, len); | 3511 | |
| 3498 | payload_len += len; | 3512 | if (skip_bytes && len <= skip_bytes) { |
| 3513 | skip_bytes -= len; | ||
| 3514 | } else { | ||
| 3515 | memcpy(payload + payload_len, buf, len); | ||
| 3516 | payload_len += len; | ||
| 3517 | if (len > skip_bytes) | ||
| 3518 | skip_bytes = 0; | ||
| 3519 | } | ||
| 3499 | } | 3520 | } |
| 3500 | spin_unlock(&tpg->tpg_np_lock); | 3521 | spin_unlock(&tpg->tpg_np_lock); |
| 3501 | } | 3522 | } |
| 3502 | spin_unlock(&tiqn->tiqn_tpg_lock); | 3523 | spin_unlock(&tiqn->tiqn_tpg_lock); |
| 3503 | eob: | 3524 | eob: |
| 3504 | if (end_of_buf) | 3525 | if (end_of_buf) { |
| 3526 | *completed = false; | ||
| 3505 | break; | 3527 | break; |
| 3528 | } | ||
| 3506 | 3529 | ||
| 3507 | if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) | 3530 | if (cmd->cmd_flags & IFC_SENDTARGETS_SINGLE) |
| 3508 | break; | 3531 | break; |
| @@ -3520,13 +3543,23 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | |||
| 3520 | enum iscsit_transport_type network_transport) | 3543 | enum iscsit_transport_type network_transport) |
| 3521 | { | 3544 | { |
| 3522 | int text_length, padding; | 3545 | int text_length, padding; |
| 3546 | bool completed = true; | ||
| 3523 | 3547 | ||
| 3524 | text_length = iscsit_build_sendtargets_response(cmd, network_transport); | 3548 | text_length = iscsit_build_sendtargets_response(cmd, network_transport, |
| 3549 | cmd->read_data_done, | ||
| 3550 | &completed); | ||
| 3525 | if (text_length < 0) | 3551 | if (text_length < 0) |
| 3526 | return text_length; | 3552 | return text_length; |
| 3527 | 3553 | ||
| 3554 | if (completed) { | ||
| 3555 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
| 3556 | } else { | ||
| 3557 | hdr->flags |= ISCSI_FLAG_TEXT_CONTINUE; | ||
| 3558 | cmd->read_data_done += text_length; | ||
| 3559 | if (cmd->targ_xfer_tag == 0xFFFFFFFF) | ||
| 3560 | cmd->targ_xfer_tag = session_get_next_ttt(conn->sess); | ||
| 3561 | } | ||
| 3528 | hdr->opcode = ISCSI_OP_TEXT_RSP; | 3562 | hdr->opcode = ISCSI_OP_TEXT_RSP; |
| 3529 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
| 3530 | padding = ((-text_length) & 3); | 3563 | padding = ((-text_length) & 3); |
| 3531 | hton24(hdr->dlength, text_length); | 3564 | hton24(hdr->dlength, text_length); |
| 3532 | hdr->itt = cmd->init_task_tag; | 3565 | hdr->itt = cmd->init_task_tag; |
| @@ -3535,21 +3568,25 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | |||
| 3535 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | 3568 | hdr->statsn = cpu_to_be32(cmd->stat_sn); |
| 3536 | 3569 | ||
| 3537 | iscsit_increment_maxcmdsn(cmd, conn->sess); | 3570 | iscsit_increment_maxcmdsn(cmd, conn->sess); |
| 3571 | /* | ||
| 3572 | * Reset maxcmdsn_inc in multi-part text payload exchanges to | ||
| 3573 | * correctly increment MaxCmdSN for each response answering a | ||
| 3574 | * non immediate text request with a valid CmdSN. | ||
| 3575 | */ | ||
| 3576 | cmd->maxcmdsn_inc = 0; | ||
| 3538 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | 3577 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); |
| 3539 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | 3578 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); |
| 3540 | 3579 | ||
| 3541 | pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x," | 3580 | pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x," |
| 3542 | " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn, | 3581 | " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag, |
| 3543 | text_length, conn->cid); | 3582 | cmd->targ_xfer_tag, cmd->stat_sn, text_length, conn->cid, |
| 3583 | !!(hdr->flags & ISCSI_FLAG_CMD_FINAL), | ||
| 3584 | !!(hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)); | ||
| 3544 | 3585 | ||
| 3545 | return text_length + padding; | 3586 | return text_length + padding; |
| 3546 | } | 3587 | } |
| 3547 | EXPORT_SYMBOL(iscsit_build_text_rsp); | 3588 | EXPORT_SYMBOL(iscsit_build_text_rsp); |
| 3548 | 3589 | ||
| 3549 | /* | ||
| 3550 | * FIXME: Add support for F_BIT and C_BIT when the length is longer than | ||
| 3551 | * MaxRecvDataSegmentLength. | ||
| 3552 | */ | ||
| 3553 | static int iscsit_send_text_rsp( | 3590 | static int iscsit_send_text_rsp( |
| 3554 | struct iscsi_cmd *cmd, | 3591 | struct iscsi_cmd *cmd, |
| 3555 | struct iscsi_conn *conn) | 3592 | struct iscsi_conn *conn) |
| @@ -4013,9 +4050,15 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) | |||
| 4013 | ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf); | 4050 | ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf); |
| 4014 | break; | 4051 | break; |
| 4015 | case ISCSI_OP_TEXT: | 4052 | case ISCSI_OP_TEXT: |
| 4016 | cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); | 4053 | if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) { |
| 4017 | if (!cmd) | 4054 | cmd = iscsit_find_cmd_from_itt(conn, hdr->itt); |
| 4018 | goto reject; | 4055 | if (!cmd) |
| 4056 | goto reject; | ||
| 4057 | } else { | ||
| 4058 | cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); | ||
| 4059 | if (!cmd) | ||
| 4060 | goto reject; | ||
| 4061 | } | ||
| 4019 | 4062 | ||
| 4020 | ret = iscsit_handle_text_cmd(conn, cmd, buf); | 4063 | ret = iscsit_handle_text_cmd(conn, cmd, buf); |
| 4021 | break; | 4064 | break; |
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index c211d3f2726c..390df8ed72b2 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
| @@ -390,6 +390,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt( | |||
| 390 | init_task_tag, conn->cid); | 390 | init_task_tag, conn->cid); |
| 391 | return NULL; | 391 | return NULL; |
| 392 | } | 392 | } |
| 393 | EXPORT_SYMBOL(iscsit_find_cmd_from_itt); | ||
| 393 | 394 | ||
| 394 | struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( | 395 | struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( |
| 395 | struct iscsi_conn *conn, | 396 | struct iscsi_conn *conn, |
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index a68508c4fec8..1ab754a671ff 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h | |||
| @@ -16,7 +16,6 @@ extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); | |||
| 16 | extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | 16 | extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
| 17 | unsigned char * ,__be32 cmdsn); | 17 | unsigned char * ,__be32 cmdsn); |
| 18 | extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); | 18 | extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); |
| 19 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t); | ||
| 20 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, | 19 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, |
| 21 | itt_t, u32); | 20 | itt_t, u32); |
| 22 | extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32); | 21 | extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32); |
diff --git a/include/target/iscsi/iscsi_target_core.h b/include/target/iscsi/iscsi_target_core.h index 5f41a17bdafd..04d8f99ea3a2 100644 --- a/include/target/iscsi/iscsi_target_core.h +++ b/include/target/iscsi/iscsi_target_core.h | |||
| @@ -893,4 +893,5 @@ static inline u32 session_get_next_ttt(struct iscsi_session *session) | |||
| 893 | return ttt; | 893 | return ttt; |
| 894 | } | 894 | } |
| 895 | 895 | ||
| 896 | extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t); | ||
| 896 | #endif /* ISCSI_TARGET_CORE_H */ | 897 | #endif /* ISCSI_TARGET_CORE_H */ |
