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 /drivers/target | |
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>
Diffstat (limited to 'drivers/target')
-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 |
3 files changed, 66 insertions, 23 deletions
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); |