diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-13 01:38:32 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-13 01:38:32 -0400 |
| commit | ed9ea4ed3a44e8f8e8c7e8a12a05fd73f9ae1fb4 (patch) | |
| tree | f7275c1cade0a756d5b456dc23ccb692ff6073d5 /drivers/target | |
| parent | c1fdb2d3389c5a1e7c559a37a4967c1d2580e75c (diff) | |
| parent | 0ed6e189e3f6ac3a25383ed5cc8b0ac24c9b97b7 (diff) | |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger:
"The highlights this round include:
- Add support for T10 PI pass-through between vhost-scsi +
virtio-scsi (MST + Paolo + MKP + nab)
- Add support for T10 PI in qla2xxx target mode (Quinn + MKP + hch +
nab, merged through scsi.git)
- Add support for percpu-ida pre-allocation in qla2xxx target code
(Quinn + nab)
- A number of iser-target fixes related to hardening the network
portal shutdown path (Sagi + Slava)
- Fix response length residual handling for a number of control CDBs
(Roland + Christophe V.)
- Various iscsi RFC conformance fixes in the CHAP authentication path
(Tejas and Calsoft folks + nab)
- Return TASK_SET_FULL status for tcm_fc(FCoE) DataIn + Response
failures (Vasu + Jun + nab)
- Fix long-standing ABORT_TASK + session reset hang (nab)
- Convert iser-initiator + iser-target to include T10 bytes into EDTL
(Sagi + Or + MKP + Mike Christie)
- Fix NULL pointer dereference regression related to XCOPY introduced
in v3.15 + CC'ed to v3.12.y (nab)"
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (34 commits)
target: Fix NULL pointer dereference for XCOPY in target_put_sess_cmd
vhost-scsi: Include prot_bytes into expected data transfer length
TARGET/sbc,loopback: Adjust command data length in case pi exists on the wire
libiscsi, iser: Adjust data_length to include protection information
scsi_cmnd: Introduce scsi_transfer_length helper
target: Report correct response length for some commands
target/sbc: Check that the LBA and number of blocks are correct in VERIFY
target/sbc: Remove sbc_check_valid_sectors()
Target/iscsi: Fix sendtargets response pdu for iser transport
Target/iser: Fix a wrong dereference in case discovery session is over iser
iscsi-target: Fix ABORT_TASK + connection reset iscsi_queue_req memory leak
target: Use complete_all for se_cmd->t_transport_stop_comp
target: Set CMD_T_ACTIVE bit for Task Management Requests
target: cleanup some boolean tests
target/spc: Simplify INQUIRY EVPD=0x80
tcm_fc: Generate TASK_SET_FULL status for response failures
tcm_fc: Generate TASK_SET_FULL status for DataIN failures
iscsi-target: Reject mutual authentication with reflected CHAP_C
iscsi-target: Remove no-op from iscsit_tpg_del_portal_group
iscsi-target: Fix CHAP_A parameter list handling
...
Diffstat (limited to 'drivers/target')
| -rw-r--r-- | drivers/target/iscsi/iscsi_target.c | 29 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_auth.c | 74 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_auth.h | 1 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_login.c | 2 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_nego.c | 12 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_parameters.c | 14 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.c | 8 | ||||
| -rw-r--r-- | drivers/target/iscsi/iscsi_target_tpg.h | 1 | ||||
| -rw-r--r-- | drivers/target/loopback/tcm_loop.c | 15 | ||||
| -rw-r--r-- | drivers/target/target_core_sbc.c | 68 | ||||
| -rw-r--r-- | drivers/target/target_core_spc.c | 18 | ||||
| -rw-r--r-- | drivers/target/target_core_transport.c | 37 | ||||
| -rw-r--r-- | drivers/target/target_core_xcopy.c | 10 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_cmd.c | 19 | ||||
| -rw-r--r-- | drivers/target/tcm_fc/tfc_io.c | 17 |
15 files changed, 210 insertions, 115 deletions
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 9189bc0a87ae..5663f4d19d02 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
| @@ -300,7 +300,7 @@ bool iscsit_check_np_match( | |||
| 300 | port = ntohs(sock_in->sin_port); | 300 | port = ntohs(sock_in->sin_port); |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | if ((ip_match == true) && (np->np_port == port) && | 303 | if (ip_match && (np->np_port == port) && |
| 304 | (np->np_network_transport == network_transport)) | 304 | (np->np_network_transport == network_transport)) |
| 305 | return true; | 305 | return true; |
| 306 | 306 | ||
| @@ -325,7 +325,7 @@ static struct iscsi_np *iscsit_get_np( | |||
| 325 | } | 325 | } |
| 326 | 326 | ||
| 327 | match = iscsit_check_np_match(sockaddr, np, network_transport); | 327 | match = iscsit_check_np_match(sockaddr, np, network_transport); |
| 328 | if (match == true) { | 328 | if (match) { |
| 329 | /* | 329 | /* |
| 330 | * Increment the np_exports reference count now to | 330 | * Increment the np_exports reference count now to |
| 331 | * prevent iscsit_del_np() below from being called | 331 | * prevent iscsit_del_np() below from being called |
| @@ -1121,7 +1121,7 @@ iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, | |||
| 1121 | /* | 1121 | /* |
| 1122 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. | 1122 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. |
| 1123 | */ | 1123 | */ |
| 1124 | if (dump_payload == true) | 1124 | if (dump_payload) |
| 1125 | goto after_immediate_data; | 1125 | goto after_immediate_data; |
| 1126 | 1126 | ||
| 1127 | immed_ret = iscsit_handle_immediate_data(cmd, hdr, | 1127 | immed_ret = iscsit_handle_immediate_data(cmd, hdr, |
| @@ -3390,7 +3390,9 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np) | |||
| 3390 | 3390 | ||
| 3391 | #define SENDTARGETS_BUF_LIMIT 32768U | 3391 | #define SENDTARGETS_BUF_LIMIT 32768U |
| 3392 | 3392 | ||
| 3393 | static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | 3393 | static int |
| 3394 | iscsit_build_sendtargets_response(struct iscsi_cmd *cmd, | ||
| 3395 | enum iscsit_transport_type network_transport) | ||
| 3394 | { | 3396 | { |
| 3395 | char *payload = NULL; | 3397 | char *payload = NULL; |
| 3396 | struct iscsi_conn *conn = cmd->conn; | 3398 | struct iscsi_conn *conn = cmd->conn; |
| @@ -3467,6 +3469,9 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | |||
| 3467 | struct iscsi_np *np = tpg_np->tpg_np; | 3469 | struct iscsi_np *np = tpg_np->tpg_np; |
| 3468 | bool inaddr_any = iscsit_check_inaddr_any(np); | 3470 | bool inaddr_any = iscsit_check_inaddr_any(np); |
| 3469 | 3471 | ||
| 3472 | if (np->np_network_transport != network_transport) | ||
| 3473 | continue; | ||
| 3474 | |||
| 3470 | if (!target_name_printed) { | 3475 | if (!target_name_printed) { |
| 3471 | len = sprintf(buf, "TargetName=%s", | 3476 | len = sprintf(buf, "TargetName=%s", |
| 3472 | tiqn->tiqn); | 3477 | tiqn->tiqn); |
| @@ -3485,10 +3490,8 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | |||
| 3485 | 3490 | ||
| 3486 | len = sprintf(buf, "TargetAddress=" | 3491 | len = sprintf(buf, "TargetAddress=" |
| 3487 | "%s:%hu,%hu", | 3492 | "%s:%hu,%hu", |
| 3488 | (inaddr_any == false) ? | 3493 | inaddr_any ? conn->local_ip : np->np_ip, |
| 3489 | np->np_ip : conn->local_ip, | 3494 | inaddr_any ? conn->local_port : np->np_port, |
| 3490 | (inaddr_any == false) ? | ||
| 3491 | np->np_port : conn->local_port, | ||
| 3492 | tpg->tpgt); | 3495 | tpg->tpgt); |
| 3493 | len += 1; | 3496 | len += 1; |
| 3494 | 3497 | ||
| @@ -3520,11 +3523,12 @@ eob: | |||
| 3520 | 3523 | ||
| 3521 | int | 3524 | int |
| 3522 | iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | 3525 | iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, |
| 3523 | struct iscsi_text_rsp *hdr) | 3526 | struct iscsi_text_rsp *hdr, |
| 3527 | enum iscsit_transport_type network_transport) | ||
| 3524 | { | 3528 | { |
| 3525 | int text_length, padding; | 3529 | int text_length, padding; |
| 3526 | 3530 | ||
| 3527 | text_length = iscsit_build_sendtargets_response(cmd); | 3531 | text_length = iscsit_build_sendtargets_response(cmd, network_transport); |
| 3528 | if (text_length < 0) | 3532 | if (text_length < 0) |
| 3529 | return text_length; | 3533 | return text_length; |
| 3530 | 3534 | ||
| @@ -3562,7 +3566,7 @@ static int iscsit_send_text_rsp( | |||
| 3562 | u32 tx_size = 0; | 3566 | u32 tx_size = 0; |
| 3563 | int text_length, iov_count = 0, rc; | 3567 | int text_length, iov_count = 0, rc; |
| 3564 | 3568 | ||
| 3565 | rc = iscsit_build_text_rsp(cmd, conn, hdr); | 3569 | rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_TCP); |
| 3566 | if (rc < 0) | 3570 | if (rc < 0) |
| 3567 | return rc; | 3571 | return rc; |
| 3568 | 3572 | ||
| @@ -4234,8 +4238,6 @@ int iscsit_close_connection( | |||
| 4234 | if (conn->conn_transport->iscsit_wait_conn) | 4238 | if (conn->conn_transport->iscsit_wait_conn) |
| 4235 | conn->conn_transport->iscsit_wait_conn(conn); | 4239 | conn->conn_transport->iscsit_wait_conn(conn); |
| 4236 | 4240 | ||
| 4237 | iscsit_free_queue_reqs_for_conn(conn); | ||
| 4238 | |||
| 4239 | /* | 4241 | /* |
| 4240 | * During Connection recovery drop unacknowledged out of order | 4242 | * During Connection recovery drop unacknowledged out of order |
| 4241 | * commands for this connection, and prepare the other commands | 4243 | * commands for this connection, and prepare the other commands |
| @@ -4252,6 +4254,7 @@ int iscsit_close_connection( | |||
| 4252 | iscsit_clear_ooo_cmdsns_for_conn(conn); | 4254 | iscsit_clear_ooo_cmdsns_for_conn(conn); |
| 4253 | iscsit_release_commands_from_conn(conn); | 4255 | iscsit_release_commands_from_conn(conn); |
| 4254 | } | 4256 | } |
| 4257 | iscsit_free_queue_reqs_for_conn(conn); | ||
| 4255 | 4258 | ||
| 4256 | /* | 4259 | /* |
| 4257 | * Handle decrementing session or connection usage count if | 4260 | * Handle decrementing session or connection usage count if |
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index de77d9aa22c6..19b842c3e0b3 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c | |||
| @@ -71,6 +71,40 @@ static void chap_gen_challenge( | |||
| 71 | challenge_asciihex); | 71 | challenge_asciihex); |
| 72 | } | 72 | } |
| 73 | 73 | ||
| 74 | static int chap_check_algorithm(const char *a_str) | ||
| 75 | { | ||
| 76 | char *tmp, *orig, *token; | ||
| 77 | |||
| 78 | tmp = kstrdup(a_str, GFP_KERNEL); | ||
| 79 | if (!tmp) { | ||
| 80 | pr_err("Memory allocation failed for CHAP_A temporary buffer\n"); | ||
| 81 | return CHAP_DIGEST_UNKNOWN; | ||
| 82 | } | ||
| 83 | orig = tmp; | ||
| 84 | |||
| 85 | token = strsep(&tmp, "="); | ||
| 86 | if (!token) | ||
| 87 | goto out; | ||
| 88 | |||
| 89 | if (strcmp(token, "CHAP_A")) { | ||
| 90 | pr_err("Unable to locate CHAP_A key\n"); | ||
| 91 | goto out; | ||
| 92 | } | ||
| 93 | while (token) { | ||
| 94 | token = strsep(&tmp, ","); | ||
| 95 | if (!token) | ||
| 96 | goto out; | ||
| 97 | |||
| 98 | if (!strncmp(token, "5", 1)) { | ||
| 99 | pr_debug("Selected MD5 Algorithm\n"); | ||
| 100 | kfree(orig); | ||
| 101 | return CHAP_DIGEST_MD5; | ||
| 102 | } | ||
| 103 | } | ||
| 104 | out: | ||
| 105 | kfree(orig); | ||
| 106 | return CHAP_DIGEST_UNKNOWN; | ||
| 107 | } | ||
| 74 | 108 | ||
| 75 | static struct iscsi_chap *chap_server_open( | 109 | static struct iscsi_chap *chap_server_open( |
| 76 | struct iscsi_conn *conn, | 110 | struct iscsi_conn *conn, |
| @@ -79,6 +113,7 @@ static struct iscsi_chap *chap_server_open( | |||
| 79 | char *aic_str, | 113 | char *aic_str, |
| 80 | unsigned int *aic_len) | 114 | unsigned int *aic_len) |
| 81 | { | 115 | { |
| 116 | int ret; | ||
| 82 | struct iscsi_chap *chap; | 117 | struct iscsi_chap *chap; |
| 83 | 118 | ||
| 84 | if (!(auth->naf_flags & NAF_USERID_SET) || | 119 | if (!(auth->naf_flags & NAF_USERID_SET) || |
| @@ -93,21 +128,24 @@ static struct iscsi_chap *chap_server_open( | |||
| 93 | return NULL; | 128 | return NULL; |
| 94 | 129 | ||
| 95 | chap = conn->auth_protocol; | 130 | chap = conn->auth_protocol; |
| 96 | /* | 131 | ret = chap_check_algorithm(a_str); |
| 97 | * We only support MD5 MDA presently. | 132 | switch (ret) { |
| 98 | */ | 133 | case CHAP_DIGEST_MD5: |
| 99 | if (strncmp(a_str, "CHAP_A=5", 8)) { | 134 | pr_debug("[server] Got CHAP_A=5\n"); |
| 100 | pr_err("CHAP_A is not MD5.\n"); | 135 | /* |
| 136 | * Send back CHAP_A set to MD5. | ||
| 137 | */ | ||
| 138 | *aic_len = sprintf(aic_str, "CHAP_A=5"); | ||
| 139 | *aic_len += 1; | ||
| 140 | chap->digest_type = CHAP_DIGEST_MD5; | ||
| 141 | pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type); | ||
| 142 | break; | ||
| 143 | case CHAP_DIGEST_UNKNOWN: | ||
| 144 | default: | ||
| 145 | pr_err("Unsupported CHAP_A value\n"); | ||
| 101 | return NULL; | 146 | return NULL; |
| 102 | } | 147 | } |
| 103 | pr_debug("[server] Got CHAP_A=5\n"); | 148 | |
| 104 | /* | ||
| 105 | * Send back CHAP_A set to MD5. | ||
| 106 | */ | ||
| 107 | *aic_len = sprintf(aic_str, "CHAP_A=5"); | ||
| 108 | *aic_len += 1; | ||
| 109 | chap->digest_type = CHAP_DIGEST_MD5; | ||
| 110 | pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type); | ||
| 111 | /* | 149 | /* |
| 112 | * Set Identifier. | 150 | * Set Identifier. |
| 113 | */ | 151 | */ |
| @@ -314,6 +352,16 @@ static int chap_server_compute_md5( | |||
| 314 | goto out; | 352 | goto out; |
| 315 | } | 353 | } |
| 316 | /* | 354 | /* |
| 355 | * During mutual authentication, the CHAP_C generated by the | ||
| 356 | * initiator must not match the original CHAP_C generated by | ||
| 357 | * the target. | ||
| 358 | */ | ||
| 359 | if (!memcmp(challenge_binhex, chap->challenge, CHAP_CHALLENGE_LENGTH)) { | ||
| 360 | pr_err("initiator CHAP_C matches target CHAP_C, failing" | ||
| 361 | " login attempt\n"); | ||
| 362 | goto out; | ||
| 363 | } | ||
| 364 | /* | ||
| 317 | * Generate CHAP_N and CHAP_R for mutual authentication. | 365 | * Generate CHAP_N and CHAP_R for mutual authentication. |
| 318 | */ | 366 | */ |
| 319 | tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); | 367 | tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); |
diff --git a/drivers/target/iscsi/iscsi_target_auth.h b/drivers/target/iscsi/iscsi_target_auth.h index 2f463c09626d..d22f7b96a06c 100644 --- a/drivers/target/iscsi/iscsi_target_auth.h +++ b/drivers/target/iscsi/iscsi_target_auth.h | |||
| @@ -1,6 +1,7 @@ | |||
| 1 | #ifndef _ISCSI_CHAP_H_ | 1 | #ifndef _ISCSI_CHAP_H_ |
| 2 | #define _ISCSI_CHAP_H_ | 2 | #define _ISCSI_CHAP_H_ |
| 3 | 3 | ||
| 4 | #define CHAP_DIGEST_UNKNOWN 0 | ||
| 4 | #define CHAP_DIGEST_MD5 5 | 5 | #define CHAP_DIGEST_MD5 5 |
| 5 | #define CHAP_DIGEST_SHA 6 | 6 | #define CHAP_DIGEST_SHA 6 |
| 6 | 7 | ||
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index d9b1d88e1ad3..fecb69535a15 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
| @@ -1145,7 +1145,7 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t) | |||
| 1145 | void iscsi_target_login_sess_out(struct iscsi_conn *conn, | 1145 | void iscsi_target_login_sess_out(struct iscsi_conn *conn, |
| 1146 | struct iscsi_np *np, bool zero_tsih, bool new_sess) | 1146 | struct iscsi_np *np, bool zero_tsih, bool new_sess) |
| 1147 | { | 1147 | { |
| 1148 | if (new_sess == false) | 1148 | if (!new_sess) |
| 1149 | goto old_sess_out; | 1149 | goto old_sess_out; |
| 1150 | 1150 | ||
| 1151 | pr_err("iSCSI Login negotiation failed.\n"); | 1151 | pr_err("iSCSI Login negotiation failed.\n"); |
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 75b685960e80..62a095f36bf2 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
| @@ -404,7 +404,7 @@ static void iscsi_target_sk_data_ready(struct sock *sk) | |||
| 404 | } | 404 | } |
| 405 | 405 | ||
| 406 | rc = schedule_delayed_work(&conn->login_work, 0); | 406 | rc = schedule_delayed_work(&conn->login_work, 0); |
| 407 | if (rc == false) { | 407 | if (!rc) { |
| 408 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" | 408 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" |
| 409 | " got false\n"); | 409 | " got false\n"); |
| 410 | } | 410 | } |
| @@ -513,7 +513,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) | |||
| 513 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); | 513 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); |
| 514 | spin_unlock(&tpg->tpg_state_lock); | 514 | spin_unlock(&tpg->tpg_state_lock); |
| 515 | 515 | ||
| 516 | if (state == false) { | 516 | if (!state) { |
| 517 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); | 517 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); |
| 518 | iscsi_target_restore_sock_callbacks(conn); | 518 | iscsi_target_restore_sock_callbacks(conn); |
| 519 | iscsi_target_login_drop(conn, login); | 519 | iscsi_target_login_drop(conn, login); |
| @@ -528,7 +528,7 @@ static void iscsi_target_do_login_rx(struct work_struct *work) | |||
| 528 | state = iscsi_target_sk_state_check(sk); | 528 | state = iscsi_target_sk_state_check(sk); |
| 529 | read_unlock_bh(&sk->sk_callback_lock); | 529 | read_unlock_bh(&sk->sk_callback_lock); |
| 530 | 530 | ||
| 531 | if (state == false) { | 531 | if (!state) { |
| 532 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); | 532 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); |
| 533 | iscsi_target_restore_sock_callbacks(conn); | 533 | iscsi_target_restore_sock_callbacks(conn); |
| 534 | iscsi_target_login_drop(conn, login); | 534 | iscsi_target_login_drop(conn, login); |
| @@ -773,6 +773,12 @@ static int iscsi_target_handle_csg_zero( | |||
| 773 | } | 773 | } |
| 774 | 774 | ||
| 775 | goto do_auth; | 775 | goto do_auth; |
| 776 | } else if (!payload_length) { | ||
| 777 | pr_err("Initiator sent zero length security payload," | ||
| 778 | " login failed\n"); | ||
| 779 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | ||
| 780 | ISCSI_LOGIN_STATUS_AUTH_FAILED); | ||
| 781 | return -1; | ||
| 776 | } | 782 | } |
| 777 | 783 | ||
| 778 | if (login->first_request) | 784 | if (login->first_request) |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 4d2e23fc76fd..02f9de26f38a 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
| @@ -474,10 +474,10 @@ int iscsi_set_keys_to_negotiate( | |||
| 474 | if (!strcmp(param->name, AUTHMETHOD)) { | 474 | if (!strcmp(param->name, AUTHMETHOD)) { |
| 475 | SET_PSTATE_NEGOTIATE(param); | 475 | SET_PSTATE_NEGOTIATE(param); |
| 476 | } else if (!strcmp(param->name, HEADERDIGEST)) { | 476 | } else if (!strcmp(param->name, HEADERDIGEST)) { |
| 477 | if (iser == false) | 477 | if (!iser) |
| 478 | SET_PSTATE_NEGOTIATE(param); | 478 | SET_PSTATE_NEGOTIATE(param); |
| 479 | } else if (!strcmp(param->name, DATADIGEST)) { | 479 | } else if (!strcmp(param->name, DATADIGEST)) { |
| 480 | if (iser == false) | 480 | if (!iser) |
| 481 | SET_PSTATE_NEGOTIATE(param); | 481 | SET_PSTATE_NEGOTIATE(param); |
| 482 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { | 482 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { |
| 483 | SET_PSTATE_NEGOTIATE(param); | 483 | SET_PSTATE_NEGOTIATE(param); |
| @@ -497,7 +497,7 @@ int iscsi_set_keys_to_negotiate( | |||
| 497 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { | 497 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { |
| 498 | SET_PSTATE_NEGOTIATE(param); | 498 | SET_PSTATE_NEGOTIATE(param); |
| 499 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { | 499 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { |
| 500 | if (iser == false) | 500 | if (!iser) |
| 501 | SET_PSTATE_NEGOTIATE(param); | 501 | SET_PSTATE_NEGOTIATE(param); |
| 502 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { | 502 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { |
| 503 | continue; | 503 | continue; |
| @@ -528,13 +528,13 @@ int iscsi_set_keys_to_negotiate( | |||
| 528 | } else if (!strcmp(param->name, OFMARKINT)) { | 528 | } else if (!strcmp(param->name, OFMARKINT)) { |
| 529 | SET_PSTATE_NEGOTIATE(param); | 529 | SET_PSTATE_NEGOTIATE(param); |
| 530 | } else if (!strcmp(param->name, RDMAEXTENSIONS)) { | 530 | } else if (!strcmp(param->name, RDMAEXTENSIONS)) { |
| 531 | if (iser == true) | 531 | if (iser) |
| 532 | SET_PSTATE_NEGOTIATE(param); | 532 | SET_PSTATE_NEGOTIATE(param); |
| 533 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { | 533 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { |
| 534 | if (iser == true) | 534 | if (iser) |
| 535 | SET_PSTATE_NEGOTIATE(param); | 535 | SET_PSTATE_NEGOTIATE(param); |
| 536 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { | 536 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { |
| 537 | if (iser == true) | 537 | if (iser) |
| 538 | SET_PSTATE_NEGOTIATE(param); | 538 | SET_PSTATE_NEGOTIATE(param); |
| 539 | } | 539 | } |
| 540 | } | 540 | } |
| @@ -1605,7 +1605,7 @@ int iscsi_decode_text_input( | |||
| 1605 | 1605 | ||
| 1606 | tmpbuf = kzalloc(length + 1, GFP_KERNEL); | 1606 | tmpbuf = kzalloc(length + 1, GFP_KERNEL); |
| 1607 | if (!tmpbuf) { | 1607 | if (!tmpbuf) { |
| 1608 | pr_err("Unable to allocate memory for tmpbuf.\n"); | 1608 | pr_err("Unable to allocate %u + 1 bytes for tmpbuf.\n", length); |
| 1609 | return -1; | 1609 | return -1; |
| 1610 | } | 1610 | } |
| 1611 | 1611 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 1431e8400d28..c3cb5c15efda 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
| @@ -189,7 +189,7 @@ static void iscsit_clear_tpg_np_login_thread( | |||
| 189 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); | 189 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | void iscsit_clear_tpg_np_login_threads( | 192 | static void iscsit_clear_tpg_np_login_threads( |
| 193 | struct iscsi_portal_group *tpg, | 193 | struct iscsi_portal_group *tpg, |
| 194 | bool shutdown) | 194 | bool shutdown) |
| 195 | { | 195 | { |
| @@ -276,8 +276,6 @@ int iscsit_tpg_del_portal_group( | |||
| 276 | tpg->tpg_state = TPG_STATE_INACTIVE; | 276 | tpg->tpg_state = TPG_STATE_INACTIVE; |
| 277 | spin_unlock(&tpg->tpg_state_lock); | 277 | spin_unlock(&tpg->tpg_state_lock); |
| 278 | 278 | ||
| 279 | iscsit_clear_tpg_np_login_threads(tpg, true); | ||
| 280 | |||
| 281 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | 279 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { |
| 282 | pr_err("Unable to delete iSCSI Target Portal Group:" | 280 | pr_err("Unable to delete iSCSI Target Portal Group:" |
| 283 | " %hu while active sessions exist, and force=0\n", | 281 | " %hu while active sessions exist, and force=0\n", |
| @@ -453,7 +451,7 @@ static bool iscsit_tpg_check_network_portal( | |||
| 453 | 451 | ||
| 454 | match = iscsit_check_np_match(sockaddr, np, | 452 | match = iscsit_check_np_match(sockaddr, np, |
| 455 | network_transport); | 453 | network_transport); |
| 456 | if (match == true) | 454 | if (match) |
| 457 | break; | 455 | break; |
| 458 | } | 456 | } |
| 459 | spin_unlock(&tpg->tpg_np_lock); | 457 | spin_unlock(&tpg->tpg_np_lock); |
| @@ -475,7 +473,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
| 475 | 473 | ||
| 476 | if (!tpg_np_parent) { | 474 | if (!tpg_np_parent) { |
| 477 | if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, | 475 | if (iscsit_tpg_check_network_portal(tpg->tpg_tiqn, sockaddr, |
| 478 | network_transport) == true) { | 476 | network_transport)) { |
| 479 | pr_err("Network Portal: %s already exists on a" | 477 | pr_err("Network Portal: %s already exists on a" |
| 480 | " different TPG on %s\n", ip_str, | 478 | " different TPG on %s\n", ip_str, |
| 481 | tpg->tpg_tiqn->tiqn); | 479 | tpg->tpg_tiqn->tiqn); |
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index 0a182f2aa8a2..e7265337bc43 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h | |||
| @@ -8,7 +8,6 @@ extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, | |||
| 8 | struct iscsi_np *, struct iscsi_tpg_np **); | 8 | struct iscsi_np *, struct iscsi_tpg_np **); |
| 9 | extern int iscsit_get_tpg(struct iscsi_portal_group *); | 9 | extern int iscsit_get_tpg(struct iscsi_portal_group *); |
| 10 | extern void iscsit_put_tpg(struct iscsi_portal_group *); | 10 | extern void iscsit_put_tpg(struct iscsi_portal_group *); |
| 11 | extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *, bool); | ||
| 12 | extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); | 11 | extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); |
| 13 | extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); | 12 | extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); |
| 14 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, | 13 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, |
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 73ab75ddaf42..6d2f37578b29 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c | |||
| @@ -179,7 +179,7 @@ static void tcm_loop_submission_work(struct work_struct *work) | |||
| 179 | struct tcm_loop_hba *tl_hba; | 179 | struct tcm_loop_hba *tl_hba; |
| 180 | struct tcm_loop_tpg *tl_tpg; | 180 | struct tcm_loop_tpg *tl_tpg; |
| 181 | struct scatterlist *sgl_bidi = NULL; | 181 | struct scatterlist *sgl_bidi = NULL; |
| 182 | u32 sgl_bidi_count = 0; | 182 | u32 sgl_bidi_count = 0, transfer_length; |
| 183 | int rc; | 183 | int rc; |
| 184 | 184 | ||
| 185 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); | 185 | tl_hba = *(struct tcm_loop_hba **)shost_priv(sc->device->host); |
| @@ -213,12 +213,21 @@ static void tcm_loop_submission_work(struct work_struct *work) | |||
| 213 | 213 | ||
| 214 | } | 214 | } |
| 215 | 215 | ||
| 216 | if (!scsi_prot_sg_count(sc) && scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) | 216 | transfer_length = scsi_transfer_length(sc); |
| 217 | if (!scsi_prot_sg_count(sc) && | ||
| 218 | scsi_get_prot_op(sc) != SCSI_PROT_NORMAL) { | ||
| 217 | se_cmd->prot_pto = true; | 219 | se_cmd->prot_pto = true; |
| 220 | /* | ||
| 221 | * loopback transport doesn't support | ||
| 222 | * WRITE_GENERATE, READ_STRIP protection | ||
| 223 | * information operations, go ahead unprotected. | ||
| 224 | */ | ||
| 225 | transfer_length = scsi_bufflen(sc); | ||
| 226 | } | ||
| 218 | 227 | ||
| 219 | rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, | 228 | rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd, |
| 220 | &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, | 229 | &tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun, |
| 221 | scsi_bufflen(sc), tcm_loop_sam_attr(sc), | 230 | transfer_length, tcm_loop_sam_attr(sc), |
| 222 | sc->sc_data_direction, 0, | 231 | sc->sc_data_direction, 0, |
| 223 | scsi_sglist(sc), scsi_sg_count(sc), | 232 | scsi_sglist(sc), scsi_sg_count(sc), |
| 224 | sgl_bidi, sgl_bidi_count, | 233 | sgl_bidi, sgl_bidi_count, |
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index e0229592ec55..bd78d9235ac6 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
| @@ -81,7 +81,7 @@ sbc_emulate_readcapacity(struct se_cmd *cmd) | |||
| 81 | transport_kunmap_data_sg(cmd); | 81 | transport_kunmap_data_sg(cmd); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | target_complete_cmd(cmd, GOOD); | 84 | target_complete_cmd_with_length(cmd, GOOD, 8); |
| 85 | return 0; | 85 | return 0; |
| 86 | } | 86 | } |
| 87 | 87 | ||
| @@ -137,7 +137,7 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd) | |||
| 137 | transport_kunmap_data_sg(cmd); | 137 | transport_kunmap_data_sg(cmd); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | target_complete_cmd(cmd, GOOD); | 140 | target_complete_cmd_with_length(cmd, GOOD, 32); |
| 141 | return 0; | 141 | return 0; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| @@ -176,24 +176,6 @@ static inline u32 sbc_get_size(struct se_cmd *cmd, u32 sectors) | |||
| 176 | return cmd->se_dev->dev_attrib.block_size * sectors; | 176 | return cmd->se_dev->dev_attrib.block_size * sectors; |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static int sbc_check_valid_sectors(struct se_cmd *cmd) | ||
| 180 | { | ||
| 181 | struct se_device *dev = cmd->se_dev; | ||
| 182 | unsigned long long end_lba; | ||
| 183 | u32 sectors; | ||
| 184 | |||
| 185 | sectors = cmd->data_length / dev->dev_attrib.block_size; | ||
| 186 | end_lba = dev->transport->get_blocks(dev) + 1; | ||
| 187 | |||
| 188 | if (cmd->t_task_lba + sectors > end_lba) { | ||
| 189 | pr_err("target: lba %llu, sectors %u exceeds end lba %llu\n", | ||
| 190 | cmd->t_task_lba, sectors, end_lba); | ||
| 191 | return -EINVAL; | ||
| 192 | } | ||
| 193 | |||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static inline u32 transport_get_sectors_6(unsigned char *cdb) | 179 | static inline u32 transport_get_sectors_6(unsigned char *cdb) |
| 198 | { | 180 | { |
| 199 | /* | 181 | /* |
| @@ -665,8 +647,19 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb, | |||
| 665 | 647 | ||
| 666 | cmd->prot_type = dev->dev_attrib.pi_prot_type; | 648 | cmd->prot_type = dev->dev_attrib.pi_prot_type; |
| 667 | cmd->prot_length = dev->prot_length * sectors; | 649 | cmd->prot_length = dev->prot_length * sectors; |
| 668 | pr_debug("%s: prot_type=%d, prot_length=%d prot_op=%d prot_checks=%d\n", | 650 | |
| 669 | __func__, cmd->prot_type, cmd->prot_length, | 651 | /** |
| 652 | * In case protection information exists over the wire | ||
| 653 | * we modify command data length to describe pure data. | ||
| 654 | * The actual transfer length is data length + protection | ||
| 655 | * length | ||
| 656 | **/ | ||
| 657 | if (protect) | ||
| 658 | cmd->data_length = sectors * dev->dev_attrib.block_size; | ||
| 659 | |||
| 660 | pr_debug("%s: prot_type=%d, data_length=%d, prot_length=%d " | ||
| 661 | "prot_op=%d prot_checks=%d\n", | ||
| 662 | __func__, cmd->prot_type, cmd->data_length, cmd->prot_length, | ||
| 670 | cmd->prot_op, cmd->prot_checks); | 663 | cmd->prot_op, cmd->prot_checks); |
| 671 | 664 | ||
| 672 | return true; | 665 | return true; |
| @@ -877,15 +870,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 877 | break; | 870 | break; |
| 878 | case SYNCHRONIZE_CACHE: | 871 | case SYNCHRONIZE_CACHE: |
| 879 | case SYNCHRONIZE_CACHE_16: | 872 | case SYNCHRONIZE_CACHE_16: |
| 880 | if (!ops->execute_sync_cache) { | ||
| 881 | size = 0; | ||
| 882 | cmd->execute_cmd = sbc_emulate_noop; | ||
| 883 | break; | ||
| 884 | } | ||
| 885 | |||
| 886 | /* | ||
| 887 | * Extract LBA and range to be flushed for emulated SYNCHRONIZE_CACHE | ||
| 888 | */ | ||
| 889 | if (cdb[0] == SYNCHRONIZE_CACHE) { | 873 | if (cdb[0] == SYNCHRONIZE_CACHE) { |
| 890 | sectors = transport_get_sectors_10(cdb); | 874 | sectors = transport_get_sectors_10(cdb); |
| 891 | cmd->t_task_lba = transport_lba_32(cdb); | 875 | cmd->t_task_lba = transport_lba_32(cdb); |
| @@ -893,18 +877,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 893 | sectors = transport_get_sectors_16(cdb); | 877 | sectors = transport_get_sectors_16(cdb); |
| 894 | cmd->t_task_lba = transport_lba_64(cdb); | 878 | cmd->t_task_lba = transport_lba_64(cdb); |
| 895 | } | 879 | } |
| 896 | 880 | if (ops->execute_sync_cache) { | |
| 897 | size = sbc_get_size(cmd, sectors); | 881 | cmd->execute_cmd = ops->execute_sync_cache; |
| 898 | 882 | goto check_lba; | |
| 899 | /* | ||
| 900 | * Check to ensure that LBA + Range does not exceed past end of | ||
| 901 | * device for IBLOCK and FILEIO ->do_sync_cache() backend calls | ||
| 902 | */ | ||
| 903 | if (cmd->t_task_lba || sectors) { | ||
| 904 | if (sbc_check_valid_sectors(cmd) < 0) | ||
| 905 | return TCM_ADDRESS_OUT_OF_RANGE; | ||
| 906 | } | 883 | } |
| 907 | cmd->execute_cmd = ops->execute_sync_cache; | 884 | size = 0; |
| 885 | cmd->execute_cmd = sbc_emulate_noop; | ||
| 908 | break; | 886 | break; |
| 909 | case UNMAP: | 887 | case UNMAP: |
| 910 | if (!ops->execute_unmap) | 888 | if (!ops->execute_unmap) |
| @@ -947,8 +925,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 947 | break; | 925 | break; |
| 948 | case VERIFY: | 926 | case VERIFY: |
| 949 | size = 0; | 927 | size = 0; |
| 928 | sectors = transport_get_sectors_10(cdb); | ||
| 929 | cmd->t_task_lba = transport_lba_32(cdb); | ||
| 950 | cmd->execute_cmd = sbc_emulate_noop; | 930 | cmd->execute_cmd = sbc_emulate_noop; |
| 951 | break; | 931 | goto check_lba; |
| 952 | case REZERO_UNIT: | 932 | case REZERO_UNIT: |
| 953 | case SEEK_6: | 933 | case SEEK_6: |
| 954 | case SEEK_10: | 934 | case SEEK_10: |
| @@ -988,7 +968,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
| 988 | dev->dev_attrib.hw_max_sectors); | 968 | dev->dev_attrib.hw_max_sectors); |
| 989 | return TCM_INVALID_CDB_FIELD; | 969 | return TCM_INVALID_CDB_FIELD; |
| 990 | } | 970 | } |
| 991 | 971 | check_lba: | |
| 992 | end_lba = dev->transport->get_blocks(dev) + 1; | 972 | end_lba = dev->transport->get_blocks(dev) + 1; |
| 993 | if (cmd->t_task_lba + sectors > end_lba) { | 973 | if (cmd->t_task_lba + sectors > end_lba) { |
| 994 | pr_err("cmd exceeds last lba %llu " | 974 | pr_err("cmd exceeds last lba %llu " |
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 8653666612a8..6cd7222738fc 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
| @@ -129,15 +129,10 @@ static sense_reason_t | |||
| 129 | spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) | 129 | spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) |
| 130 | { | 130 | { |
| 131 | struct se_device *dev = cmd->se_dev; | 131 | struct se_device *dev = cmd->se_dev; |
| 132 | u16 len = 0; | 132 | u16 len; |
| 133 | 133 | ||
| 134 | if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { | 134 | if (dev->dev_flags & DF_EMULATED_VPD_UNIT_SERIAL) { |
| 135 | u32 unit_serial_len; | 135 | len = sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial); |
| 136 | |||
| 137 | unit_serial_len = strlen(dev->t10_wwn.unit_serial); | ||
| 138 | unit_serial_len++; /* For NULL Terminator */ | ||
| 139 | |||
| 140 | len += sprintf(&buf[4], "%s", dev->t10_wwn.unit_serial); | ||
| 141 | len++; /* Extra Byte for NULL Terminator */ | 136 | len++; /* Extra Byte for NULL Terminator */ |
| 142 | buf[3] = len; | 137 | buf[3] = len; |
| 143 | } | 138 | } |
| @@ -721,6 +716,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) | |||
| 721 | unsigned char *buf; | 716 | unsigned char *buf; |
| 722 | sense_reason_t ret; | 717 | sense_reason_t ret; |
| 723 | int p; | 718 | int p; |
| 719 | int len = 0; | ||
| 724 | 720 | ||
| 725 | buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); | 721 | buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL); |
| 726 | if (!buf) { | 722 | if (!buf) { |
| @@ -742,6 +738,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) | |||
| 742 | } | 738 | } |
| 743 | 739 | ||
| 744 | ret = spc_emulate_inquiry_std(cmd, buf); | 740 | ret = spc_emulate_inquiry_std(cmd, buf); |
| 741 | len = buf[4] + 5; | ||
| 745 | goto out; | 742 | goto out; |
| 746 | } | 743 | } |
| 747 | 744 | ||
| @@ -749,6 +746,7 @@ spc_emulate_inquiry(struct se_cmd *cmd) | |||
| 749 | if (cdb[2] == evpd_handlers[p].page) { | 746 | if (cdb[2] == evpd_handlers[p].page) { |
| 750 | buf[1] = cdb[2]; | 747 | buf[1] = cdb[2]; |
| 751 | ret = evpd_handlers[p].emulate(cmd, buf); | 748 | ret = evpd_handlers[p].emulate(cmd, buf); |
| 749 | len = get_unaligned_be16(&buf[2]) + 4; | ||
| 752 | goto out; | 750 | goto out; |
| 753 | } | 751 | } |
| 754 | } | 752 | } |
| @@ -765,7 +763,7 @@ out: | |||
| 765 | kfree(buf); | 763 | kfree(buf); |
| 766 | 764 | ||
| 767 | if (!ret) | 765 | if (!ret) |
| 768 | target_complete_cmd(cmd, GOOD); | 766 | target_complete_cmd_with_length(cmd, GOOD, len); |
| 769 | return ret; | 767 | return ret; |
| 770 | } | 768 | } |
| 771 | 769 | ||
| @@ -1103,7 +1101,7 @@ set_length: | |||
| 1103 | transport_kunmap_data_sg(cmd); | 1101 | transport_kunmap_data_sg(cmd); |
| 1104 | } | 1102 | } |
| 1105 | 1103 | ||
| 1106 | target_complete_cmd(cmd, GOOD); | 1104 | target_complete_cmd_with_length(cmd, GOOD, length); |
| 1107 | return 0; | 1105 | return 0; |
| 1108 | } | 1106 | } |
| 1109 | 1107 | ||
| @@ -1279,7 +1277,7 @@ done: | |||
| 1279 | buf[3] = (lun_count & 0xff); | 1277 | buf[3] = (lun_count & 0xff); |
| 1280 | transport_kunmap_data_sg(cmd); | 1278 | transport_kunmap_data_sg(cmd); |
| 1281 | 1279 | ||
| 1282 | target_complete_cmd(cmd, GOOD); | 1280 | target_complete_cmd_with_length(cmd, GOOD, 8 + lun_count * 8); |
| 1283 | return 0; | 1281 | return 0; |
| 1284 | } | 1282 | } |
| 1285 | EXPORT_SYMBOL(spc_emulate_report_luns); | 1283 | EXPORT_SYMBOL(spc_emulate_report_luns); |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2179feed0d63..7fa62fc93e0b 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
| @@ -504,7 +504,7 @@ void transport_deregister_session(struct se_session *se_sess) | |||
| 504 | * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group | 504 | * ->acl_free_comp caller to wakeup configfs se_node_acl->acl_group |
| 505 | * removal context. | 505 | * removal context. |
| 506 | */ | 506 | */ |
| 507 | if (se_nacl && comp_nacl == true) | 507 | if (se_nacl && comp_nacl) |
| 508 | target_put_nacl(se_nacl); | 508 | target_put_nacl(se_nacl); |
| 509 | 509 | ||
| 510 | transport_free_session(se_sess); | 510 | transport_free_session(se_sess); |
| @@ -562,7 +562,7 @@ static int transport_cmd_check_stop(struct se_cmd *cmd, bool remove_from_lists, | |||
| 562 | 562 | ||
| 563 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 563 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 564 | 564 | ||
| 565 | complete(&cmd->t_transport_stop_comp); | 565 | complete_all(&cmd->t_transport_stop_comp); |
| 566 | return 1; | 566 | return 1; |
| 567 | } | 567 | } |
| 568 | 568 | ||
| @@ -687,7 +687,7 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | |||
| 687 | if (cmd->transport_state & CMD_T_ABORTED && | 687 | if (cmd->transport_state & CMD_T_ABORTED && |
| 688 | cmd->transport_state & CMD_T_STOP) { | 688 | cmd->transport_state & CMD_T_STOP) { |
| 689 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | 689 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); |
| 690 | complete(&cmd->t_transport_stop_comp); | 690 | complete_all(&cmd->t_transport_stop_comp); |
| 691 | return; | 691 | return; |
| 692 | } else if (!success) { | 692 | } else if (!success) { |
| 693 | INIT_WORK(&cmd->work, target_complete_failure_work); | 693 | INIT_WORK(&cmd->work, target_complete_failure_work); |
| @@ -703,6 +703,23 @@ void target_complete_cmd(struct se_cmd *cmd, u8 scsi_status) | |||
| 703 | } | 703 | } |
| 704 | EXPORT_SYMBOL(target_complete_cmd); | 704 | EXPORT_SYMBOL(target_complete_cmd); |
| 705 | 705 | ||
| 706 | void target_complete_cmd_with_length(struct se_cmd *cmd, u8 scsi_status, int length) | ||
| 707 | { | ||
| 708 | if (scsi_status == SAM_STAT_GOOD && length < cmd->data_length) { | ||
| 709 | if (cmd->se_cmd_flags & SCF_UNDERFLOW_BIT) { | ||
| 710 | cmd->residual_count += cmd->data_length - length; | ||
| 711 | } else { | ||
| 712 | cmd->se_cmd_flags |= SCF_UNDERFLOW_BIT; | ||
| 713 | cmd->residual_count = cmd->data_length - length; | ||
| 714 | } | ||
| 715 | |||
| 716 | cmd->data_length = length; | ||
| 717 | } | ||
| 718 | |||
| 719 | target_complete_cmd(cmd, scsi_status); | ||
| 720 | } | ||
| 721 | EXPORT_SYMBOL(target_complete_cmd_with_length); | ||
| 722 | |||
| 706 | static void target_add_to_state_list(struct se_cmd *cmd) | 723 | static void target_add_to_state_list(struct se_cmd *cmd) |
| 707 | { | 724 | { |
| 708 | struct se_device *dev = cmd->se_dev; | 725 | struct se_device *dev = cmd->se_dev; |
| @@ -1761,7 +1778,7 @@ void target_execute_cmd(struct se_cmd *cmd) | |||
| 1761 | cmd->se_tfo->get_task_tag(cmd)); | 1778 | cmd->se_tfo->get_task_tag(cmd)); |
| 1762 | 1779 | ||
| 1763 | spin_unlock_irq(&cmd->t_state_lock); | 1780 | spin_unlock_irq(&cmd->t_state_lock); |
| 1764 | complete(&cmd->t_transport_stop_comp); | 1781 | complete_all(&cmd->t_transport_stop_comp); |
| 1765 | return; | 1782 | return; |
| 1766 | } | 1783 | } |
| 1767 | 1784 | ||
| @@ -2363,7 +2380,7 @@ int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, | |||
| 2363 | * fabric acknowledgement that requires two target_put_sess_cmd() | 2380 | * fabric acknowledgement that requires two target_put_sess_cmd() |
| 2364 | * invocations before se_cmd descriptor release. | 2381 | * invocations before se_cmd descriptor release. |
| 2365 | */ | 2382 | */ |
| 2366 | if (ack_kref == true) { | 2383 | if (ack_kref) { |
| 2367 | kref_get(&se_cmd->cmd_kref); | 2384 | kref_get(&se_cmd->cmd_kref); |
| 2368 | se_cmd->se_cmd_flags |= SCF_ACK_KREF; | 2385 | se_cmd->se_cmd_flags |= SCF_ACK_KREF; |
| 2369 | } | 2386 | } |
| @@ -2407,6 +2424,10 @@ static void target_release_cmd_kref(struct kref *kref) | |||
| 2407 | */ | 2424 | */ |
| 2408 | int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) | 2425 | int target_put_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd) |
| 2409 | { | 2426 | { |
| 2427 | if (!se_sess) { | ||
| 2428 | se_cmd->se_tfo->release_cmd(se_cmd); | ||
| 2429 | return 1; | ||
| 2430 | } | ||
| 2410 | return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, | 2431 | return kref_put_spinlock_irqsave(&se_cmd->cmd_kref, target_release_cmd_kref, |
| 2411 | &se_sess->sess_cmd_lock); | 2432 | &se_sess->sess_cmd_lock); |
| 2412 | } | 2433 | } |
| @@ -2934,6 +2955,12 @@ static void target_tmr_work(struct work_struct *work) | |||
| 2934 | int transport_generic_handle_tmr( | 2955 | int transport_generic_handle_tmr( |
| 2935 | struct se_cmd *cmd) | 2956 | struct se_cmd *cmd) |
| 2936 | { | 2957 | { |
| 2958 | unsigned long flags; | ||
| 2959 | |||
| 2960 | spin_lock_irqsave(&cmd->t_state_lock, flags); | ||
| 2961 | cmd->transport_state |= CMD_T_ACTIVE; | ||
| 2962 | spin_unlock_irqrestore(&cmd->t_state_lock, flags); | ||
| 2963 | |||
| 2937 | INIT_WORK(&cmd->work, target_tmr_work); | 2964 | INIT_WORK(&cmd->work, target_tmr_work); |
| 2938 | queue_work(cmd->se_dev->tmr_wq, &cmd->work); | 2965 | queue_work(cmd->se_dev->tmr_wq, &cmd->work); |
| 2939 | return 0; | 2966 | return 0; |
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c index 669c536fd959..e9186cdf35e9 100644 --- a/drivers/target/target_core_xcopy.c +++ b/drivers/target/target_core_xcopy.c | |||
| @@ -70,7 +70,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
| 70 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; | 70 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; |
| 71 | int rc; | 71 | int rc; |
| 72 | 72 | ||
| 73 | if (src == true) | 73 | if (src) |
| 74 | dev_wwn = &xop->dst_tid_wwn[0]; | 74 | dev_wwn = &xop->dst_tid_wwn[0]; |
| 75 | else | 75 | else |
| 76 | dev_wwn = &xop->src_tid_wwn[0]; | 76 | dev_wwn = &xop->src_tid_wwn[0]; |
| @@ -88,7 +88,7 @@ static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
| 88 | if (rc != 0) | 88 | if (rc != 0) |
| 89 | continue; | 89 | continue; |
| 90 | 90 | ||
| 91 | if (src == true) { | 91 | if (src) { |
| 92 | xop->dst_dev = se_dev; | 92 | xop->dst_dev = se_dev; |
| 93 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" | 93 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" |
| 94 | " se_dev\n", xop->dst_dev); | 94 | " se_dev\n", xop->dst_dev); |
| @@ -166,7 +166,7 @@ static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op | |||
| 166 | return -EINVAL; | 166 | return -EINVAL; |
| 167 | } | 167 | } |
| 168 | 168 | ||
| 169 | if (src == true) { | 169 | if (src) { |
| 170 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); | 170 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); |
| 171 | /* | 171 | /* |
| 172 | * Determine if the source designator matches the local device | 172 | * Determine if the source designator matches the local device |
| @@ -236,7 +236,7 @@ static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | |||
| 236 | /* | 236 | /* |
| 237 | * Assume target descriptors are in source -> destination order.. | 237 | * Assume target descriptors are in source -> destination order.. |
| 238 | */ | 238 | */ |
| 239 | if (src == true) | 239 | if (src) |
| 240 | src = false; | 240 | src = false; |
| 241 | else | 241 | else |
| 242 | src = true; | 242 | src = true; |
| @@ -560,7 +560,7 @@ static int target_xcopy_init_pt_lun( | |||
| 560 | * reservations. The pt_cmd->se_lun pointer will be setup from within | 560 | * reservations. The pt_cmd->se_lun pointer will be setup from within |
| 561 | * target_xcopy_setup_pt_port() | 561 | * target_xcopy_setup_pt_port() |
| 562 | */ | 562 | */ |
| 563 | if (remote_port == false) { | 563 | if (!remote_port) { |
| 564 | pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; | 564 | pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; |
| 565 | return 0; | 565 | return 0; |
| 566 | } | 566 | } |
diff --git a/drivers/target/tcm_fc/tfc_cmd.c b/drivers/target/tcm_fc/tfc_cmd.c index f5fd515b2bee..be0c0d08c56a 100644 --- a/drivers/target/tcm_fc/tfc_cmd.c +++ b/drivers/target/tcm_fc/tfc_cmd.c | |||
| @@ -128,6 +128,7 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
| 128 | struct fc_lport *lport; | 128 | struct fc_lport *lport; |
| 129 | struct fc_exch *ep; | 129 | struct fc_exch *ep; |
| 130 | size_t len; | 130 | size_t len; |
| 131 | int rc; | ||
| 131 | 132 | ||
| 132 | if (cmd->aborted) | 133 | if (cmd->aborted) |
| 133 | return 0; | 134 | return 0; |
| @@ -137,9 +138,10 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
| 137 | len = sizeof(*fcp) + se_cmd->scsi_sense_length; | 138 | len = sizeof(*fcp) + se_cmd->scsi_sense_length; |
| 138 | fp = fc_frame_alloc(lport, len); | 139 | fp = fc_frame_alloc(lport, len); |
| 139 | if (!fp) { | 140 | if (!fp) { |
| 140 | /* XXX shouldn't just drop it - requeue and retry? */ | 141 | se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; |
| 141 | return 0; | 142 | return -ENOMEM; |
| 142 | } | 143 | } |
| 144 | |||
| 143 | fcp = fc_frame_payload_get(fp, len); | 145 | fcp = fc_frame_payload_get(fp, len); |
| 144 | memset(fcp, 0, len); | 146 | memset(fcp, 0, len); |
| 145 | fcp->resp.fr_status = se_cmd->scsi_status; | 147 | fcp->resp.fr_status = se_cmd->scsi_status; |
| @@ -170,7 +172,18 @@ int ft_queue_status(struct se_cmd *se_cmd) | |||
| 170 | fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, | 172 | fc_fill_fc_hdr(fp, FC_RCTL_DD_CMD_STATUS, ep->did, ep->sid, FC_TYPE_FCP, |
| 171 | FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); | 173 | FC_FC_EX_CTX | FC_FC_LAST_SEQ | FC_FC_END_SEQ, 0); |
| 172 | 174 | ||
| 173 | lport->tt.seq_send(lport, cmd->seq, fp); | 175 | rc = lport->tt.seq_send(lport, cmd->seq, fp); |
| 176 | if (rc) { | ||
| 177 | pr_info_ratelimited("%s: Failed to send response frame %p, " | ||
| 178 | "xid <0x%x>\n", __func__, fp, ep->xid); | ||
| 179 | /* | ||
| 180 | * Generate a TASK_SET_FULL status to notify the initiator | ||
| 181 | * to reduce it's queue_depth after the se_cmd response has | ||
| 182 | * been re-queued by target-core. | ||
| 183 | */ | ||
| 184 | se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; | ||
| 185 | return -ENOMEM; | ||
| 186 | } | ||
| 174 | lport->tt.exch_done(cmd->seq); | 187 | lport->tt.exch_done(cmd->seq); |
| 175 | return 0; | 188 | return 0; |
| 176 | } | 189 | } |
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index e415af32115a..97b486c3dda1 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c | |||
| @@ -82,6 +82,10 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
| 82 | 82 | ||
| 83 | if (cmd->aborted) | 83 | if (cmd->aborted) |
| 84 | return 0; | 84 | return 0; |
| 85 | |||
| 86 | if (se_cmd->scsi_status == SAM_STAT_TASK_SET_FULL) | ||
| 87 | goto queue_status; | ||
| 88 | |||
| 85 | ep = fc_seq_exch(cmd->seq); | 89 | ep = fc_seq_exch(cmd->seq); |
| 86 | lport = ep->lp; | 90 | lport = ep->lp; |
| 87 | cmd->seq = lport->tt.seq_start_next(cmd->seq); | 91 | cmd->seq = lport->tt.seq_start_next(cmd->seq); |
| @@ -178,14 +182,23 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
| 178 | FC_TYPE_FCP, f_ctl, fh_off); | 182 | FC_TYPE_FCP, f_ctl, fh_off); |
| 179 | error = lport->tt.seq_send(lport, seq, fp); | 183 | error = lport->tt.seq_send(lport, seq, fp); |
| 180 | if (error) { | 184 | if (error) { |
| 181 | /* XXX For now, initiator will retry */ | 185 | pr_info_ratelimited("%s: Failed to send frame %p, " |
| 182 | pr_err_ratelimited("%s: Failed to send frame %p, " | ||
| 183 | "xid <0x%x>, remaining %zu, " | 186 | "xid <0x%x>, remaining %zu, " |
| 184 | "lso_max <0x%x>\n", | 187 | "lso_max <0x%x>\n", |
| 185 | __func__, fp, ep->xid, | 188 | __func__, fp, ep->xid, |
| 186 | remaining, lport->lso_max); | 189 | remaining, lport->lso_max); |
| 190 | /* | ||
| 191 | * Go ahead and set TASK_SET_FULL status ignoring the | ||
| 192 | * rest of the DataIN, and immediately attempt to | ||
| 193 | * send the response via ft_queue_status() in order | ||
| 194 | * to notify the initiator that it should reduce it's | ||
| 195 | * per LUN queue_depth. | ||
| 196 | */ | ||
| 197 | se_cmd->scsi_status = SAM_STAT_TASK_SET_FULL; | ||
| 198 | break; | ||
| 187 | } | 199 | } |
| 188 | } | 200 | } |
| 201 | queue_status: | ||
| 189 | return ft_queue_status(se_cmd); | 202 | return ft_queue_status(se_cmd); |
| 190 | } | 203 | } |
| 191 | 204 | ||
