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 | ||