diff options
Diffstat (limited to 'drivers/target')
47 files changed, 2347 insertions, 473 deletions
diff --git a/drivers/target/Makefile b/drivers/target/Makefile index 9fdcb561422f..85b012d2f89b 100644 --- a/drivers/target/Makefile +++ b/drivers/target/Makefile | |||
@@ -13,7 +13,8 @@ target_core_mod-y := target_core_configfs.o \ | |||
13 | target_core_spc.o \ | 13 | target_core_spc.o \ |
14 | target_core_ua.o \ | 14 | target_core_ua.o \ |
15 | target_core_rd.o \ | 15 | target_core_rd.o \ |
16 | target_core_stat.o | 16 | target_core_stat.o \ |
17 | target_core_xcopy.o | ||
17 | 18 | ||
18 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o | 19 | obj-$(CONFIG_TARGET_CORE) += target_core_mod.o |
19 | 20 | ||
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 3a179302b904..35b61f7d6c63 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains main functions related to the iSCSI Target Core Driver. | 2 | * This file contains main functions related to the iSCSI Target Core Driver. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -63,7 +61,6 @@ spinlock_t sess_idr_lock; | |||
63 | 61 | ||
64 | struct iscsit_global *iscsit_global; | 62 | struct iscsit_global *iscsit_global; |
65 | 63 | ||
66 | struct kmem_cache *lio_cmd_cache; | ||
67 | struct kmem_cache *lio_qr_cache; | 64 | struct kmem_cache *lio_qr_cache; |
68 | struct kmem_cache *lio_dr_cache; | 65 | struct kmem_cache *lio_dr_cache; |
69 | struct kmem_cache *lio_ooo_cache; | 66 | struct kmem_cache *lio_ooo_cache; |
@@ -220,11 +217,6 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | |||
220 | spin_unlock_bh(&np->np_thread_lock); | 217 | spin_unlock_bh(&np->np_thread_lock); |
221 | return -1; | 218 | return -1; |
222 | } | 219 | } |
223 | if (np->np_login_tpg) { | ||
224 | pr_err("np->np_login_tpg() is not NULL!\n"); | ||
225 | spin_unlock_bh(&np->np_thread_lock); | ||
226 | return -1; | ||
227 | } | ||
228 | spin_unlock_bh(&np->np_thread_lock); | 220 | spin_unlock_bh(&np->np_thread_lock); |
229 | /* | 221 | /* |
230 | * Determine if the portal group is accepting storage traffic. | 222 | * Determine if the portal group is accepting storage traffic. |
@@ -239,26 +231,38 @@ int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | |||
239 | /* | 231 | /* |
240 | * Here we serialize access across the TIQN+TPG Tuple. | 232 | * Here we serialize access across the TIQN+TPG Tuple. |
241 | */ | 233 | */ |
242 | ret = mutex_lock_interruptible(&tpg->np_login_lock); | 234 | ret = down_interruptible(&tpg->np_login_sem); |
243 | if ((ret != 0) || signal_pending(current)) | 235 | if ((ret != 0) || signal_pending(current)) |
244 | return -1; | 236 | return -1; |
245 | 237 | ||
246 | spin_lock_bh(&np->np_thread_lock); | 238 | spin_lock_bh(&tpg->tpg_state_lock); |
247 | np->np_login_tpg = tpg; | 239 | if (tpg->tpg_state != TPG_STATE_ACTIVE) { |
248 | spin_unlock_bh(&np->np_thread_lock); | 240 | spin_unlock_bh(&tpg->tpg_state_lock); |
241 | up(&tpg->np_login_sem); | ||
242 | return -1; | ||
243 | } | ||
244 | spin_unlock_bh(&tpg->tpg_state_lock); | ||
249 | 245 | ||
250 | return 0; | 246 | return 0; |
251 | } | 247 | } |
252 | 248 | ||
253 | int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) | 249 | void iscsit_login_kref_put(struct kref *kref) |
250 | { | ||
251 | struct iscsi_tpg_np *tpg_np = container_of(kref, | ||
252 | struct iscsi_tpg_np, tpg_np_kref); | ||
253 | |||
254 | complete(&tpg_np->tpg_np_comp); | ||
255 | } | ||
256 | |||
257 | int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg, | ||
258 | struct iscsi_tpg_np *tpg_np) | ||
254 | { | 259 | { |
255 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; | 260 | struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; |
256 | 261 | ||
257 | spin_lock_bh(&np->np_thread_lock); | 262 | up(&tpg->np_login_sem); |
258 | np->np_login_tpg = NULL; | ||
259 | spin_unlock_bh(&np->np_thread_lock); | ||
260 | 263 | ||
261 | mutex_unlock(&tpg->np_login_lock); | 264 | if (tpg_np) |
265 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
262 | 266 | ||
263 | if (tiqn) | 267 | if (tiqn) |
264 | iscsit_put_tiqn_for_login(tiqn); | 268 | iscsit_put_tiqn_for_login(tiqn); |
@@ -410,20 +414,10 @@ struct iscsi_np *iscsit_add_np( | |||
410 | int iscsit_reset_np_thread( | 414 | int iscsit_reset_np_thread( |
411 | struct iscsi_np *np, | 415 | struct iscsi_np *np, |
412 | struct iscsi_tpg_np *tpg_np, | 416 | struct iscsi_tpg_np *tpg_np, |
413 | struct iscsi_portal_group *tpg) | 417 | struct iscsi_portal_group *tpg, |
418 | bool shutdown) | ||
414 | { | 419 | { |
415 | spin_lock_bh(&np->np_thread_lock); | 420 | spin_lock_bh(&np->np_thread_lock); |
416 | if (tpg && tpg_np) { | ||
417 | /* | ||
418 | * The reset operation need only be performed when the | ||
419 | * passed struct iscsi_portal_group has a login in progress | ||
420 | * to one of the network portals. | ||
421 | */ | ||
422 | if (tpg_np->tpg_np->np_login_tpg != tpg) { | ||
423 | spin_unlock_bh(&np->np_thread_lock); | ||
424 | return 0; | ||
425 | } | ||
426 | } | ||
427 | if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) { | 421 | if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) { |
428 | spin_unlock_bh(&np->np_thread_lock); | 422 | spin_unlock_bh(&np->np_thread_lock); |
429 | return 0; | 423 | return 0; |
@@ -438,6 +432,12 @@ int iscsit_reset_np_thread( | |||
438 | } | 432 | } |
439 | spin_unlock_bh(&np->np_thread_lock); | 433 | spin_unlock_bh(&np->np_thread_lock); |
440 | 434 | ||
435 | if (tpg_np && shutdown) { | ||
436 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
437 | |||
438 | wait_for_completion(&tpg_np->tpg_np_comp); | ||
439 | } | ||
440 | |||
441 | return 0; | 441 | return 0; |
442 | } | 442 | } |
443 | 443 | ||
@@ -497,7 +497,6 @@ static struct iscsit_transport iscsi_target_transport = { | |||
497 | .iscsit_setup_np = iscsit_setup_np, | 497 | .iscsit_setup_np = iscsit_setup_np, |
498 | .iscsit_accept_np = iscsit_accept_np, | 498 | .iscsit_accept_np = iscsit_accept_np, |
499 | .iscsit_free_np = iscsit_free_np, | 499 | .iscsit_free_np = iscsit_free_np, |
500 | .iscsit_alloc_cmd = iscsit_alloc_cmd, | ||
501 | .iscsit_get_login_rx = iscsit_get_login_rx, | 500 | .iscsit_get_login_rx = iscsit_get_login_rx, |
502 | .iscsit_put_login_tx = iscsit_put_login_tx, | 501 | .iscsit_put_login_tx = iscsit_put_login_tx, |
503 | .iscsit_get_dataout = iscsit_build_r2ts_for_cmd, | 502 | .iscsit_get_dataout = iscsit_build_r2ts_for_cmd, |
@@ -538,22 +537,13 @@ static int __init iscsi_target_init_module(void) | |||
538 | goto ts_out1; | 537 | goto ts_out1; |
539 | } | 538 | } |
540 | 539 | ||
541 | lio_cmd_cache = kmem_cache_create("lio_cmd_cache", | ||
542 | sizeof(struct iscsi_cmd), __alignof__(struct iscsi_cmd), | ||
543 | 0, NULL); | ||
544 | if (!lio_cmd_cache) { | ||
545 | pr_err("Unable to kmem_cache_create() for" | ||
546 | " lio_cmd_cache\n"); | ||
547 | goto ts_out2; | ||
548 | } | ||
549 | |||
550 | lio_qr_cache = kmem_cache_create("lio_qr_cache", | 540 | lio_qr_cache = kmem_cache_create("lio_qr_cache", |
551 | sizeof(struct iscsi_queue_req), | 541 | sizeof(struct iscsi_queue_req), |
552 | __alignof__(struct iscsi_queue_req), 0, NULL); | 542 | __alignof__(struct iscsi_queue_req), 0, NULL); |
553 | if (!lio_qr_cache) { | 543 | if (!lio_qr_cache) { |
554 | pr_err("nable to kmem_cache_create() for" | 544 | pr_err("nable to kmem_cache_create() for" |
555 | " lio_qr_cache\n"); | 545 | " lio_qr_cache\n"); |
556 | goto cmd_out; | 546 | goto ts_out2; |
557 | } | 547 | } |
558 | 548 | ||
559 | lio_dr_cache = kmem_cache_create("lio_dr_cache", | 549 | lio_dr_cache = kmem_cache_create("lio_dr_cache", |
@@ -597,8 +587,6 @@ dr_out: | |||
597 | kmem_cache_destroy(lio_dr_cache); | 587 | kmem_cache_destroy(lio_dr_cache); |
598 | qr_out: | 588 | qr_out: |
599 | kmem_cache_destroy(lio_qr_cache); | 589 | kmem_cache_destroy(lio_qr_cache); |
600 | cmd_out: | ||
601 | kmem_cache_destroy(lio_cmd_cache); | ||
602 | ts_out2: | 590 | ts_out2: |
603 | iscsi_deallocate_thread_sets(); | 591 | iscsi_deallocate_thread_sets(); |
604 | ts_out1: | 592 | ts_out1: |
@@ -616,7 +604,6 @@ static void __exit iscsi_target_cleanup_module(void) | |||
616 | iscsi_thread_set_free(); | 604 | iscsi_thread_set_free(); |
617 | iscsit_release_discovery_tpg(); | 605 | iscsit_release_discovery_tpg(); |
618 | iscsit_unregister_transport(&iscsi_target_transport); | 606 | iscsit_unregister_transport(&iscsi_target_transport); |
619 | kmem_cache_destroy(lio_cmd_cache); | ||
620 | kmem_cache_destroy(lio_qr_cache); | 607 | kmem_cache_destroy(lio_qr_cache); |
621 | kmem_cache_destroy(lio_dr_cache); | 608 | kmem_cache_destroy(lio_dr_cache); |
622 | kmem_cache_destroy(lio_ooo_cache); | 609 | kmem_cache_destroy(lio_ooo_cache); |
@@ -3447,12 +3434,10 @@ static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) | |||
3447 | bool inaddr_any = iscsit_check_inaddr_any(np); | 3434 | bool inaddr_any = iscsit_check_inaddr_any(np); |
3448 | 3435 | ||
3449 | len = sprintf(buf, "TargetAddress=" | 3436 | len = sprintf(buf, "TargetAddress=" |
3450 | "%s%s%s:%hu,%hu", | 3437 | "%s:%hu,%hu", |
3451 | (np->np_sockaddr.ss_family == AF_INET6) ? | 3438 | (inaddr_any == false) ? |
3452 | "[" : "", (inaddr_any == false) ? | ||
3453 | np->np_ip : conn->local_ip, | 3439 | np->np_ip : conn->local_ip, |
3454 | (np->np_sockaddr.ss_family == AF_INET6) ? | 3440 | (inaddr_any == false) ? |
3455 | "]" : "", (inaddr_any == false) ? | ||
3456 | np->np_port : conn->local_port, | 3441 | np->np_port : conn->local_port, |
3457 | tpg->tpgt); | 3442 | tpg->tpgt); |
3458 | len += 1; | 3443 | len += 1; |
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index 2c437cb8ca00..e936d56fb523 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h | |||
@@ -7,13 +7,15 @@ extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *); | |||
7 | extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); | 7 | extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); |
8 | extern void iscsit_del_tiqn(struct iscsi_tiqn *); | 8 | extern void iscsit_del_tiqn(struct iscsi_tiqn *); |
9 | extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); | 9 | extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); |
10 | extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *); | 10 | extern void iscsit_login_kref_put(struct kref *); |
11 | extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *, | ||
12 | struct iscsi_tpg_np *); | ||
11 | extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, | 13 | extern bool iscsit_check_np_match(struct __kernel_sockaddr_storage *, |
12 | struct iscsi_np *, int); | 14 | struct iscsi_np *, int); |
13 | extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, | 15 | extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, |
14 | char *, int); | 16 | char *, int); |
15 | extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, | 17 | extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, |
16 | struct iscsi_portal_group *); | 18 | struct iscsi_portal_group *, bool); |
17 | extern int iscsit_del_np(struct iscsi_np *); | 19 | extern int iscsit_del_np(struct iscsi_np *); |
18 | extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *); | 20 | extern int iscsit_reject_cmd(struct iscsi_cmd *cmd, u8, unsigned char *); |
19 | extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *); | 21 | extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *); |
@@ -37,7 +39,6 @@ extern struct target_fabric_configfs *lio_target_fabric_configfs; | |||
37 | 39 | ||
38 | extern struct kmem_cache *lio_dr_cache; | 40 | extern struct kmem_cache *lio_dr_cache; |
39 | extern struct kmem_cache *lio_ooo_cache; | 41 | extern struct kmem_cache *lio_ooo_cache; |
40 | extern struct kmem_cache *lio_cmd_cache; | ||
41 | extern struct kmem_cache *lio_qr_cache; | 42 | extern struct kmem_cache *lio_qr_cache; |
42 | extern struct kmem_cache *lio_r2t_cache; | 43 | extern struct kmem_cache *lio_r2t_cache; |
43 | 44 | ||
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index cee17543278c..7505fddca15f 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file houses the main functions for the iSCSI CHAP support | 2 | * This file houses the main functions for the iSCSI CHAP support |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index bbfd28893164..fd145259361d 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c | |||
@@ -2,9 +2,7 @@ | |||
2 | * This file contains the configfs implementation for iSCSI Target mode | 2 | * This file contains the configfs implementation for iSCSI Target mode |
3 | * from the LIO-Target Project. | 3 | * from the LIO-Target Project. |
4 | * | 4 | * |
5 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 5 | * (c) Copyright 2007-2013 Datera, Inc. |
6 | * | ||
7 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
8 | * | 6 | * |
9 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 8 | * |
@@ -265,9 +263,9 @@ static struct se_tpg_np *lio_target_call_addnptotpg( | |||
265 | *port_str = '\0'; /* Terminate string for IP */ | 263 | *port_str = '\0'; /* Terminate string for IP */ |
266 | port_str++; /* Skip over ":" */ | 264 | port_str++; /* Skip over ":" */ |
267 | 265 | ||
268 | ret = strict_strtoul(port_str, 0, &port); | 266 | ret = kstrtoul(port_str, 0, &port); |
269 | if (ret < 0) { | 267 | if (ret < 0) { |
270 | pr_err("strict_strtoul() failed for port_str: %d\n", ret); | 268 | pr_err("kstrtoul() failed for port_str: %d\n", ret); |
271 | return ERR_PTR(ret); | 269 | return ERR_PTR(ret); |
272 | } | 270 | } |
273 | sock_in6 = (struct sockaddr_in6 *)&sockaddr; | 271 | sock_in6 = (struct sockaddr_in6 *)&sockaddr; |
@@ -290,9 +288,9 @@ static struct se_tpg_np *lio_target_call_addnptotpg( | |||
290 | *port_str = '\0'; /* Terminate string for IP */ | 288 | *port_str = '\0'; /* Terminate string for IP */ |
291 | port_str++; /* Skip over ":" */ | 289 | port_str++; /* Skip over ":" */ |
292 | 290 | ||
293 | ret = strict_strtoul(port_str, 0, &port); | 291 | ret = kstrtoul(port_str, 0, &port); |
294 | if (ret < 0) { | 292 | if (ret < 0) { |
295 | pr_err("strict_strtoul() failed for port_str: %d\n", ret); | 293 | pr_err("kstrtoul() failed for port_str: %d\n", ret); |
296 | return ERR_PTR(ret); | 294 | return ERR_PTR(ret); |
297 | } | 295 | } |
298 | sock_in = (struct sockaddr_in *)&sockaddr; | 296 | sock_in = (struct sockaddr_in *)&sockaddr; |
@@ -1481,7 +1479,7 @@ static ssize_t lio_target_wwn_show_attr_lio_version( | |||
1481 | struct target_fabric_configfs *tf, | 1479 | struct target_fabric_configfs *tf, |
1482 | char *page) | 1480 | char *page) |
1483 | { | 1481 | { |
1484 | return sprintf(page, "RisingTide Systems Linux-iSCSI Target "ISCSIT_VERSION"\n"); | 1482 | return sprintf(page, "Datera Inc. iSCSI Target "ISCSIT_VERSION"\n"); |
1485 | } | 1483 | } |
1486 | 1484 | ||
1487 | TF_WWN_ATTR_RO(lio_target, lio_version); | 1485 | TF_WWN_ATTR_RO(lio_target, lio_version); |
@@ -1925,7 +1923,7 @@ static void lio_release_cmd(struct se_cmd *se_cmd) | |||
1925 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); | 1923 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); |
1926 | 1924 | ||
1927 | pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd); | 1925 | pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd); |
1928 | cmd->release_cmd(cmd); | 1926 | iscsit_release_cmd(cmd); |
1929 | } | 1927 | } |
1930 | 1928 | ||
1931 | /* End functions for target_core_fabric_ops */ | 1929 | /* End functions for target_core_fabric_ops */ |
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 4f77a78edef9..9a5721b8ff96 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h | |||
@@ -9,7 +9,7 @@ | |||
9 | #include <scsi/iscsi_proto.h> | 9 | #include <scsi/iscsi_proto.h> |
10 | #include <target/target_core_base.h> | 10 | #include <target/target_core_base.h> |
11 | 11 | ||
12 | #define ISCSIT_VERSION "v4.1.0-rc2" | 12 | #define ISCSIT_VERSION "v4.1.0" |
13 | #define ISCSI_MAX_DATASN_MISSING_COUNT 16 | 13 | #define ISCSI_MAX_DATASN_MISSING_COUNT 16 |
14 | #define ISCSI_TX_THREAD_TCP_TIMEOUT 2 | 14 | #define ISCSI_TX_THREAD_TCP_TIMEOUT 2 |
15 | #define ISCSI_RX_THREAD_TCP_TIMEOUT 2 | 15 | #define ISCSI_RX_THREAD_TCP_TIMEOUT 2 |
@@ -17,6 +17,9 @@ | |||
17 | #define SECONDS_FOR_ASYNC_TEXT 10 | 17 | #define SECONDS_FOR_ASYNC_TEXT 10 |
18 | #define SECONDS_FOR_LOGOUT_COMP 15 | 18 | #define SECONDS_FOR_LOGOUT_COMP 15 |
19 | #define WHITE_SPACE " \t\v\f\n\r" | 19 | #define WHITE_SPACE " \t\v\f\n\r" |
20 | #define ISCSIT_MIN_TAGS 16 | ||
21 | #define ISCSIT_EXTRA_TAGS 8 | ||
22 | #define ISCSIT_TCP_BACKLOG 256 | ||
20 | 23 | ||
21 | /* struct iscsi_node_attrib sanity values */ | 24 | /* struct iscsi_node_attrib sanity values */ |
22 | #define NA_DATAOUT_TIMEOUT 3 | 25 | #define NA_DATAOUT_TIMEOUT 3 |
@@ -47,7 +50,7 @@ | |||
47 | #define TA_NETIF_TIMEOUT_MAX 15 | 50 | #define TA_NETIF_TIMEOUT_MAX 15 |
48 | #define TA_NETIF_TIMEOUT_MIN 2 | 51 | #define TA_NETIF_TIMEOUT_MIN 2 |
49 | #define TA_GENERATE_NODE_ACLS 0 | 52 | #define TA_GENERATE_NODE_ACLS 0 |
50 | #define TA_DEFAULT_CMDSN_DEPTH 16 | 53 | #define TA_DEFAULT_CMDSN_DEPTH 64 |
51 | #define TA_DEFAULT_CMDSN_DEPTH_MAX 512 | 54 | #define TA_DEFAULT_CMDSN_DEPTH_MAX 512 |
52 | #define TA_DEFAULT_CMDSN_DEPTH_MIN 1 | 55 | #define TA_DEFAULT_CMDSN_DEPTH_MIN 1 |
53 | #define TA_CACHE_DYNAMIC_ACLS 0 | 56 | #define TA_CACHE_DYNAMIC_ACLS 0 |
@@ -489,7 +492,6 @@ struct iscsi_cmd { | |||
489 | u32 first_data_sg_off; | 492 | u32 first_data_sg_off; |
490 | u32 kmapped_nents; | 493 | u32 kmapped_nents; |
491 | sense_reason_t sense_reason; | 494 | sense_reason_t sense_reason; |
492 | void (*release_cmd)(struct iscsi_cmd *); | ||
493 | } ____cacheline_aligned; | 495 | } ____cacheline_aligned; |
494 | 496 | ||
495 | struct iscsi_tmr_req { | 497 | struct iscsi_tmr_req { |
@@ -554,9 +556,19 @@ struct iscsi_conn { | |||
554 | struct completion rx_half_close_comp; | 556 | struct completion rx_half_close_comp; |
555 | /* socket used by this connection */ | 557 | /* socket used by this connection */ |
556 | struct socket *sock; | 558 | struct socket *sock; |
559 | void (*orig_data_ready)(struct sock *, int); | ||
560 | void (*orig_state_change)(struct sock *); | ||
561 | #define LOGIN_FLAGS_READ_ACTIVE 1 | ||
562 | #define LOGIN_FLAGS_CLOSED 2 | ||
563 | #define LOGIN_FLAGS_READY 4 | ||
564 | unsigned long login_flags; | ||
565 | struct delayed_work login_work; | ||
566 | struct delayed_work login_cleanup_work; | ||
567 | struct iscsi_login *login; | ||
557 | struct timer_list nopin_timer; | 568 | struct timer_list nopin_timer; |
558 | struct timer_list nopin_response_timer; | 569 | struct timer_list nopin_response_timer; |
559 | struct timer_list transport_timer; | 570 | struct timer_list transport_timer; |
571 | struct task_struct *login_kworker; | ||
560 | /* Spinlock used for add/deleting cmd's from conn_cmd_list */ | 572 | /* Spinlock used for add/deleting cmd's from conn_cmd_list */ |
561 | spinlock_t cmd_lock; | 573 | spinlock_t cmd_lock; |
562 | spinlock_t conn_usage_lock; | 574 | spinlock_t conn_usage_lock; |
@@ -584,6 +596,7 @@ struct iscsi_conn { | |||
584 | void *context; | 596 | void *context; |
585 | struct iscsi_login_thread_s *login_thread; | 597 | struct iscsi_login_thread_s *login_thread; |
586 | struct iscsi_portal_group *tpg; | 598 | struct iscsi_portal_group *tpg; |
599 | struct iscsi_tpg_np *tpg_np; | ||
587 | /* Pointer to parent session */ | 600 | /* Pointer to parent session */ |
588 | struct iscsi_session *sess; | 601 | struct iscsi_session *sess; |
589 | /* Pointer to thread_set in use for this conn's threads */ | 602 | /* Pointer to thread_set in use for this conn's threads */ |
@@ -682,6 +695,7 @@ struct iscsi_login { | |||
682 | u8 version_max; | 695 | u8 version_max; |
683 | u8 login_complete; | 696 | u8 login_complete; |
684 | u8 login_failed; | 697 | u8 login_failed; |
698 | bool zero_tsih; | ||
685 | char isid[6]; | 699 | char isid[6]; |
686 | u32 cmd_sn; | 700 | u32 cmd_sn; |
687 | itt_t init_task_tag; | 701 | itt_t init_task_tag; |
@@ -694,6 +708,7 @@ struct iscsi_login { | |||
694 | char *req_buf; | 708 | char *req_buf; |
695 | char *rsp_buf; | 709 | char *rsp_buf; |
696 | struct iscsi_conn *conn; | 710 | struct iscsi_conn *conn; |
711 | struct iscsi_np *np; | ||
697 | } ____cacheline_aligned; | 712 | } ____cacheline_aligned; |
698 | 713 | ||
699 | struct iscsi_node_attrib { | 714 | struct iscsi_node_attrib { |
@@ -773,7 +788,6 @@ struct iscsi_np { | |||
773 | struct __kernel_sockaddr_storage np_sockaddr; | 788 | struct __kernel_sockaddr_storage np_sockaddr; |
774 | struct task_struct *np_thread; | 789 | struct task_struct *np_thread; |
775 | struct timer_list np_login_timer; | 790 | struct timer_list np_login_timer; |
776 | struct iscsi_portal_group *np_login_tpg; | ||
777 | void *np_context; | 791 | void *np_context; |
778 | struct iscsit_transport *np_transport; | 792 | struct iscsit_transport *np_transport; |
779 | struct list_head np_list; | 793 | struct list_head np_list; |
@@ -788,6 +802,8 @@ struct iscsi_tpg_np { | |||
788 | struct list_head tpg_np_parent_list; | 802 | struct list_head tpg_np_parent_list; |
789 | struct se_tpg_np se_tpg_np; | 803 | struct se_tpg_np se_tpg_np; |
790 | spinlock_t tpg_np_parent_lock; | 804 | spinlock_t tpg_np_parent_lock; |
805 | struct completion tpg_np_comp; | ||
806 | struct kref tpg_np_kref; | ||
791 | }; | 807 | }; |
792 | 808 | ||
793 | struct iscsi_portal_group { | 809 | struct iscsi_portal_group { |
@@ -809,7 +825,7 @@ struct iscsi_portal_group { | |||
809 | spinlock_t tpg_state_lock; | 825 | spinlock_t tpg_state_lock; |
810 | struct se_portal_group tpg_se_tpg; | 826 | struct se_portal_group tpg_se_tpg; |
811 | struct mutex tpg_access_lock; | 827 | struct mutex tpg_access_lock; |
812 | struct mutex np_login_lock; | 828 | struct semaphore np_login_sem; |
813 | struct iscsi_tpg_attrib tpg_attrib; | 829 | struct iscsi_tpg_attrib tpg_attrib; |
814 | struct iscsi_node_auth tpg_demo_auth; | 830 | struct iscsi_node_auth tpg_demo_auth; |
815 | /* Pointer to default list of iSCSI parameters for TPG */ | 831 | /* Pointer to default list of iSCSI parameters for TPG */ |
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c index 848fee768948..e93d5a7a3f81 100644 --- a/drivers/target/iscsi/iscsi_target_datain_values.c +++ b/drivers/target/iscsi/iscsi_target_datain_values.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the iSCSI Target DataIN value generation functions. | 2 | * This file contains the iSCSI Target DataIN value generation functions. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c index 1b74033510a0..6c7a5104a4cd 100644 --- a/drivers/target/iscsi/iscsi_target_device.c +++ b/drivers/target/iscsi/iscsi_target_device.c | |||
@@ -2,9 +2,7 @@ | |||
2 | * This file contains the iSCSI Virtual Device and Disk Transport | 2 | * This file contains the iSCSI Virtual Device and Disk Transport |
3 | * agnostic related functions. | 3 | * agnostic related functions. |
4 | * | 4 | * |
5 | \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 5 | * (c) Copyright 2007-2013 Datera, Inc. |
6 | * | ||
7 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
8 | * | 6 | * |
9 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 8 | * |
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c index 08bd87833321..41052e512d92 100644 --- a/drivers/target/iscsi/iscsi_target_erl0.c +++ b/drivers/target/iscsi/iscsi_target_erl0.c | |||
@@ -2,9 +2,7 @@ | |||
2 | * This file contains error recovery level zero functions used by | 2 | * This file contains error recovery level zero functions used by |
3 | * the iSCSI Target driver. | 3 | * the iSCSI Target driver. |
4 | * | 4 | * |
5 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 5 | * (c) Copyright 2007-2013 Datera, Inc. |
6 | * | ||
7 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
8 | * | 6 | * |
9 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 8 | * |
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 586c268679a4..e048d6439f4a 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains error recovery level one used by the iSCSI Target driver. | 2 | * This file contains error recovery level one used by the iSCSI Target driver. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c index 45a5afd5ea13..33be1fb1df32 100644 --- a/drivers/target/iscsi/iscsi_target_erl2.c +++ b/drivers/target/iscsi/iscsi_target_erl2.c | |||
@@ -2,9 +2,7 @@ | |||
2 | * This file contains error recovery level two functions used by | 2 | * This file contains error recovery level two functions used by |
3 | * the iSCSI Target driver. | 3 | * the iSCSI Target driver. |
4 | * | 4 | * |
5 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 5 | * (c) Copyright 2007-2013 Datera, Inc. |
6 | * | ||
7 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
8 | * | 6 | * |
9 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 8 | * |
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index bc788c52b6cc..1794c753954a 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the login functions used by the iSCSI Target driver. | 2 | * This file contains the login functions used by the iSCSI Target driver. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -50,6 +48,7 @@ static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) | |||
50 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); | 48 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); |
51 | return NULL; | 49 | return NULL; |
52 | } | 50 | } |
51 | conn->login = login; | ||
53 | login->conn = conn; | 52 | login->conn = conn; |
54 | login->first_request = 1; | 53 | login->first_request = 1; |
55 | 54 | ||
@@ -428,7 +427,7 @@ static int iscsi_login_zero_tsih_s2( | |||
428 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | 427 | ISCSI_LOGIN_STATUS_NO_RESOURCES); |
429 | return -1; | 428 | return -1; |
430 | } | 429 | } |
431 | rc = strict_strtoul(param->value, 0, &mrdsl); | 430 | rc = kstrtoul(param->value, 0, &mrdsl); |
432 | if (rc < 0) { | 431 | if (rc < 0) { |
433 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | 432 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, |
434 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | 433 | ISCSI_LOGIN_STATUS_NO_RESOURCES); |
@@ -684,7 +683,7 @@ static void iscsi_post_login_start_timers(struct iscsi_conn *conn) | |||
684 | iscsit_start_nopin_timer(conn); | 683 | iscsit_start_nopin_timer(conn); |
685 | } | 684 | } |
686 | 685 | ||
687 | static int iscsi_post_login_handler( | 686 | int iscsi_post_login_handler( |
688 | struct iscsi_np *np, | 687 | struct iscsi_np *np, |
689 | struct iscsi_conn *conn, | 688 | struct iscsi_conn *conn, |
690 | u8 zero_tsih) | 689 | u8 zero_tsih) |
@@ -872,7 +871,7 @@ int iscsit_setup_np( | |||
872 | struct __kernel_sockaddr_storage *sockaddr) | 871 | struct __kernel_sockaddr_storage *sockaddr) |
873 | { | 872 | { |
874 | struct socket *sock = NULL; | 873 | struct socket *sock = NULL; |
875 | int backlog = 5, ret, opt = 0, len; | 874 | int backlog = ISCSIT_TCP_BACKLOG, ret, opt = 0, len; |
876 | 875 | ||
877 | switch (np->np_network_transport) { | 876 | switch (np->np_network_transport) { |
878 | case ISCSI_TCP: | 877 | case ISCSI_TCP: |
@@ -1007,16 +1006,24 @@ int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) | |||
1007 | rc = conn->sock->ops->getname(conn->sock, | 1006 | rc = conn->sock->ops->getname(conn->sock, |
1008 | (struct sockaddr *)&sock_in6, &err, 1); | 1007 | (struct sockaddr *)&sock_in6, &err, 1); |
1009 | if (!rc) { | 1008 | if (!rc) { |
1010 | snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", | 1009 | if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) |
1011 | &sock_in6.sin6_addr.in6_u); | 1010 | snprintf(conn->login_ip, sizeof(conn->login_ip), "[%pI6c]", |
1011 | &sock_in6.sin6_addr.in6_u); | ||
1012 | else | ||
1013 | snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI4", | ||
1014 | &sock_in6.sin6_addr.s6_addr32[3]); | ||
1012 | conn->login_port = ntohs(sock_in6.sin6_port); | 1015 | conn->login_port = ntohs(sock_in6.sin6_port); |
1013 | } | 1016 | } |
1014 | 1017 | ||
1015 | rc = conn->sock->ops->getname(conn->sock, | 1018 | rc = conn->sock->ops->getname(conn->sock, |
1016 | (struct sockaddr *)&sock_in6, &err, 0); | 1019 | (struct sockaddr *)&sock_in6, &err, 0); |
1017 | if (!rc) { | 1020 | if (!rc) { |
1018 | snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", | 1021 | if (!ipv6_addr_v4mapped(&sock_in6.sin6_addr)) |
1019 | &sock_in6.sin6_addr.in6_u); | 1022 | snprintf(conn->local_ip, sizeof(conn->local_ip), "[%pI6c]", |
1023 | &sock_in6.sin6_addr.in6_u); | ||
1024 | else | ||
1025 | snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI4", | ||
1026 | &sock_in6.sin6_addr.s6_addr32[3]); | ||
1020 | conn->local_port = ntohs(sock_in6.sin6_port); | 1027 | conn->local_port = ntohs(sock_in6.sin6_port); |
1021 | } | 1028 | } |
1022 | } else { | 1029 | } else { |
@@ -1116,6 +1123,77 @@ iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t) | |||
1116 | return 0; | 1123 | return 0; |
1117 | } | 1124 | } |
1118 | 1125 | ||
1126 | void iscsi_target_login_sess_out(struct iscsi_conn *conn, | ||
1127 | struct iscsi_np *np, bool zero_tsih, bool new_sess) | ||
1128 | { | ||
1129 | if (new_sess == false) | ||
1130 | goto old_sess_out; | ||
1131 | |||
1132 | pr_err("iSCSI Login negotiation failed.\n"); | ||
1133 | iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | ||
1134 | ISCSI_LOGIN_STATUS_INIT_ERR); | ||
1135 | if (!zero_tsih || !conn->sess) | ||
1136 | goto old_sess_out; | ||
1137 | if (conn->sess->se_sess) | ||
1138 | transport_free_session(conn->sess->se_sess); | ||
1139 | if (conn->sess->session_index != 0) { | ||
1140 | spin_lock_bh(&sess_idr_lock); | ||
1141 | idr_remove(&sess_idr, conn->sess->session_index); | ||
1142 | spin_unlock_bh(&sess_idr_lock); | ||
1143 | } | ||
1144 | kfree(conn->sess->sess_ops); | ||
1145 | kfree(conn->sess); | ||
1146 | |||
1147 | old_sess_out: | ||
1148 | iscsi_stop_login_thread_timer(np); | ||
1149 | /* | ||
1150 | * If login negotiation fails check if the Time2Retain timer | ||
1151 | * needs to be restarted. | ||
1152 | */ | ||
1153 | if (!zero_tsih && conn->sess) { | ||
1154 | spin_lock_bh(&conn->sess->conn_lock); | ||
1155 | if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { | ||
1156 | struct se_portal_group *se_tpg = | ||
1157 | &ISCSI_TPG_C(conn)->tpg_se_tpg; | ||
1158 | |||
1159 | atomic_set(&conn->sess->session_continuation, 0); | ||
1160 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1161 | spin_lock_bh(&se_tpg->session_lock); | ||
1162 | iscsit_start_time2retain_handler(conn->sess); | ||
1163 | spin_unlock_bh(&se_tpg->session_lock); | ||
1164 | } else | ||
1165 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1166 | iscsit_dec_session_usage_count(conn->sess); | ||
1167 | } | ||
1168 | |||
1169 | if (!IS_ERR(conn->conn_rx_hash.tfm)) | ||
1170 | crypto_free_hash(conn->conn_rx_hash.tfm); | ||
1171 | if (!IS_ERR(conn->conn_tx_hash.tfm)) | ||
1172 | crypto_free_hash(conn->conn_tx_hash.tfm); | ||
1173 | |||
1174 | if (conn->conn_cpumask) | ||
1175 | free_cpumask_var(conn->conn_cpumask); | ||
1176 | |||
1177 | kfree(conn->conn_ops); | ||
1178 | |||
1179 | if (conn->param_list) { | ||
1180 | iscsi_release_param_list(conn->param_list); | ||
1181 | conn->param_list = NULL; | ||
1182 | } | ||
1183 | iscsi_target_nego_release(conn); | ||
1184 | |||
1185 | if (conn->sock) { | ||
1186 | sock_release(conn->sock); | ||
1187 | conn->sock = NULL; | ||
1188 | } | ||
1189 | |||
1190 | if (conn->conn_transport->iscsit_free_conn) | ||
1191 | conn->conn_transport->iscsit_free_conn(conn); | ||
1192 | |||
1193 | iscsit_put_transport(conn->conn_transport); | ||
1194 | kfree(conn); | ||
1195 | } | ||
1196 | |||
1119 | static int __iscsi_target_login_thread(struct iscsi_np *np) | 1197 | static int __iscsi_target_login_thread(struct iscsi_np *np) |
1120 | { | 1198 | { |
1121 | u8 *buffer, zero_tsih = 0; | 1199 | u8 *buffer, zero_tsih = 0; |
@@ -1124,6 +1202,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1124 | struct iscsi_login *login; | 1202 | struct iscsi_login *login; |
1125 | struct iscsi_portal_group *tpg = NULL; | 1203 | struct iscsi_portal_group *tpg = NULL; |
1126 | struct iscsi_login_req *pdu; | 1204 | struct iscsi_login_req *pdu; |
1205 | struct iscsi_tpg_np *tpg_np; | ||
1206 | bool new_sess = false; | ||
1127 | 1207 | ||
1128 | flush_signals(current); | 1208 | flush_signals(current); |
1129 | 1209 | ||
@@ -1264,6 +1344,7 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1264 | tpg = conn->tpg; | 1344 | tpg = conn->tpg; |
1265 | goto new_sess_out; | 1345 | goto new_sess_out; |
1266 | } | 1346 | } |
1347 | login->zero_tsih = zero_tsih; | ||
1267 | 1348 | ||
1268 | tpg = conn->tpg; | 1349 | tpg = conn->tpg; |
1269 | if (!tpg) { | 1350 | if (!tpg) { |
@@ -1279,7 +1360,8 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1279 | goto old_sess_out; | 1360 | goto old_sess_out; |
1280 | } | 1361 | } |
1281 | 1362 | ||
1282 | if (iscsi_target_start_negotiation(login, conn) < 0) | 1363 | ret = iscsi_target_start_negotiation(login, conn); |
1364 | if (ret < 0) | ||
1283 | goto new_sess_out; | 1365 | goto new_sess_out; |
1284 | 1366 | ||
1285 | if (!conn->sess) { | 1367 | if (!conn->sess) { |
@@ -1292,84 +1374,32 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1292 | if (signal_pending(current)) | 1374 | if (signal_pending(current)) |
1293 | goto new_sess_out; | 1375 | goto new_sess_out; |
1294 | 1376 | ||
1295 | ret = iscsi_post_login_handler(np, conn, zero_tsih); | 1377 | if (ret == 1) { |
1378 | tpg_np = conn->tpg_np; | ||
1296 | 1379 | ||
1297 | if (ret < 0) | 1380 | ret = iscsi_post_login_handler(np, conn, zero_tsih); |
1298 | goto new_sess_out; | 1381 | if (ret < 0) |
1382 | goto new_sess_out; | ||
1383 | |||
1384 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
1385 | } | ||
1299 | 1386 | ||
1300 | iscsit_deaccess_np(np, tpg); | ||
1301 | tpg = NULL; | 1387 | tpg = NULL; |
1388 | tpg_np = NULL; | ||
1302 | /* Get another socket */ | 1389 | /* Get another socket */ |
1303 | return 1; | 1390 | return 1; |
1304 | 1391 | ||
1305 | new_sess_out: | 1392 | new_sess_out: |
1306 | pr_err("iSCSI Login negotiation failed.\n"); | 1393 | new_sess = true; |
1307 | iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, | ||
1308 | ISCSI_LOGIN_STATUS_INIT_ERR); | ||
1309 | if (!zero_tsih || !conn->sess) | ||
1310 | goto old_sess_out; | ||
1311 | if (conn->sess->se_sess) | ||
1312 | transport_free_session(conn->sess->se_sess); | ||
1313 | if (conn->sess->session_index != 0) { | ||
1314 | spin_lock_bh(&sess_idr_lock); | ||
1315 | idr_remove(&sess_idr, conn->sess->session_index); | ||
1316 | spin_unlock_bh(&sess_idr_lock); | ||
1317 | } | ||
1318 | kfree(conn->sess->sess_ops); | ||
1319 | kfree(conn->sess); | ||
1320 | old_sess_out: | 1394 | old_sess_out: |
1321 | iscsi_stop_login_thread_timer(np); | 1395 | tpg_np = conn->tpg_np; |
1322 | /* | 1396 | iscsi_target_login_sess_out(conn, np, zero_tsih, new_sess); |
1323 | * If login negotiation fails check if the Time2Retain timer | 1397 | new_sess = false; |
1324 | * needs to be restarted. | ||
1325 | */ | ||
1326 | if (!zero_tsih && conn->sess) { | ||
1327 | spin_lock_bh(&conn->sess->conn_lock); | ||
1328 | if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { | ||
1329 | struct se_portal_group *se_tpg = | ||
1330 | &ISCSI_TPG_C(conn)->tpg_se_tpg; | ||
1331 | |||
1332 | atomic_set(&conn->sess->session_continuation, 0); | ||
1333 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1334 | spin_lock_bh(&se_tpg->session_lock); | ||
1335 | iscsit_start_time2retain_handler(conn->sess); | ||
1336 | spin_unlock_bh(&se_tpg->session_lock); | ||
1337 | } else | ||
1338 | spin_unlock_bh(&conn->sess->conn_lock); | ||
1339 | iscsit_dec_session_usage_count(conn->sess); | ||
1340 | } | ||
1341 | |||
1342 | if (!IS_ERR(conn->conn_rx_hash.tfm)) | ||
1343 | crypto_free_hash(conn->conn_rx_hash.tfm); | ||
1344 | if (!IS_ERR(conn->conn_tx_hash.tfm)) | ||
1345 | crypto_free_hash(conn->conn_tx_hash.tfm); | ||
1346 | |||
1347 | if (conn->conn_cpumask) | ||
1348 | free_cpumask_var(conn->conn_cpumask); | ||
1349 | |||
1350 | kfree(conn->conn_ops); | ||
1351 | |||
1352 | if (conn->param_list) { | ||
1353 | iscsi_release_param_list(conn->param_list); | ||
1354 | conn->param_list = NULL; | ||
1355 | } | ||
1356 | iscsi_target_nego_release(conn); | ||
1357 | |||
1358 | if (conn->sock) { | ||
1359 | sock_release(conn->sock); | ||
1360 | conn->sock = NULL; | ||
1361 | } | ||
1362 | |||
1363 | if (conn->conn_transport->iscsit_free_conn) | ||
1364 | conn->conn_transport->iscsit_free_conn(conn); | ||
1365 | |||
1366 | iscsit_put_transport(conn->conn_transport); | ||
1367 | |||
1368 | kfree(conn); | ||
1369 | 1398 | ||
1370 | if (tpg) { | 1399 | if (tpg) { |
1371 | iscsit_deaccess_np(np, tpg); | 1400 | iscsit_deaccess_np(np, tpg, tpg_np); |
1372 | tpg = NULL; | 1401 | tpg = NULL; |
1402 | tpg_np = NULL; | ||
1373 | } | 1403 | } |
1374 | 1404 | ||
1375 | out: | 1405 | out: |
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 63efd2878451..29d098324b7f 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h | |||
@@ -12,6 +12,9 @@ extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *); | |||
12 | extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); | 12 | extern int iscsit_get_login_rx(struct iscsi_conn *, struct iscsi_login *); |
13 | extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); | 13 | extern int iscsit_put_login_tx(struct iscsi_conn *, struct iscsi_login *, u32); |
14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); | 14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); |
15 | extern int iscsi_post_login_handler(struct iscsi_np *, struct iscsi_conn *, u8); | ||
16 | extern void iscsi_target_login_sess_out(struct iscsi_conn *, struct iscsi_np *, | ||
17 | bool, bool); | ||
15 | extern int iscsi_target_login_thread(void *); | 18 | extern int iscsi_target_login_thread(void *); |
16 | extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); | 19 | extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); |
17 | 20 | ||
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index c4675b4ceb49..14d1aed5af1d 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains main functions related to iSCSI Parameter negotiation. | 2 | * This file contains main functions related to iSCSI Parameter negotiation. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -377,15 +375,284 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
377 | return 0; | 375 | return 0; |
378 | } | 376 | } |
379 | 377 | ||
380 | static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) | 378 | static void iscsi_target_sk_data_ready(struct sock *sk, int count) |
381 | { | 379 | { |
382 | if (iscsi_target_do_tx_login_io(conn, login) < 0) | 380 | struct iscsi_conn *conn = sk->sk_user_data; |
383 | return -1; | 381 | bool rc; |
384 | 382 | ||
385 | if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0) | 383 | pr_debug("Entering iscsi_target_sk_data_ready: conn: %p\n", conn); |
386 | return -1; | ||
387 | 384 | ||
388 | return 0; | 385 | write_lock_bh(&sk->sk_callback_lock); |
386 | if (!sk->sk_user_data) { | ||
387 | write_unlock_bh(&sk->sk_callback_lock); | ||
388 | return; | ||
389 | } | ||
390 | if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { | ||
391 | write_unlock_bh(&sk->sk_callback_lock); | ||
392 | pr_debug("Got LOGIN_FLAGS_READY=0, conn: %p >>>>\n", conn); | ||
393 | return; | ||
394 | } | ||
395 | if (test_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { | ||
396 | write_unlock_bh(&sk->sk_callback_lock); | ||
397 | pr_debug("Got LOGIN_FLAGS_CLOSED=1, conn: %p >>>>\n", conn); | ||
398 | return; | ||
399 | } | ||
400 | if (test_and_set_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { | ||
401 | write_unlock_bh(&sk->sk_callback_lock); | ||
402 | pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1, conn: %p >>>>\n", conn); | ||
403 | return; | ||
404 | } | ||
405 | |||
406 | rc = schedule_delayed_work(&conn->login_work, 0); | ||
407 | if (rc == false) { | ||
408 | pr_debug("iscsi_target_sk_data_ready, schedule_delayed_work" | ||
409 | " got false\n"); | ||
410 | } | ||
411 | write_unlock_bh(&sk->sk_callback_lock); | ||
412 | } | ||
413 | |||
414 | static void iscsi_target_sk_state_change(struct sock *); | ||
415 | |||
416 | static void iscsi_target_set_sock_callbacks(struct iscsi_conn *conn) | ||
417 | { | ||
418 | struct sock *sk; | ||
419 | |||
420 | if (!conn->sock) | ||
421 | return; | ||
422 | |||
423 | sk = conn->sock->sk; | ||
424 | pr_debug("Entering iscsi_target_set_sock_callbacks: conn: %p\n", conn); | ||
425 | |||
426 | write_lock_bh(&sk->sk_callback_lock); | ||
427 | sk->sk_user_data = conn; | ||
428 | conn->orig_data_ready = sk->sk_data_ready; | ||
429 | conn->orig_state_change = sk->sk_state_change; | ||
430 | sk->sk_data_ready = iscsi_target_sk_data_ready; | ||
431 | sk->sk_state_change = iscsi_target_sk_state_change; | ||
432 | write_unlock_bh(&sk->sk_callback_lock); | ||
433 | |||
434 | sk->sk_sndtimeo = TA_LOGIN_TIMEOUT * HZ; | ||
435 | sk->sk_rcvtimeo = TA_LOGIN_TIMEOUT * HZ; | ||
436 | } | ||
437 | |||
438 | static void iscsi_target_restore_sock_callbacks(struct iscsi_conn *conn) | ||
439 | { | ||
440 | struct sock *sk; | ||
441 | |||
442 | if (!conn->sock) | ||
443 | return; | ||
444 | |||
445 | sk = conn->sock->sk; | ||
446 | pr_debug("Entering iscsi_target_restore_sock_callbacks: conn: %p\n", conn); | ||
447 | |||
448 | write_lock_bh(&sk->sk_callback_lock); | ||
449 | if (!sk->sk_user_data) { | ||
450 | write_unlock_bh(&sk->sk_callback_lock); | ||
451 | return; | ||
452 | } | ||
453 | sk->sk_user_data = NULL; | ||
454 | sk->sk_data_ready = conn->orig_data_ready; | ||
455 | sk->sk_state_change = conn->orig_state_change; | ||
456 | write_unlock_bh(&sk->sk_callback_lock); | ||
457 | |||
458 | sk->sk_sndtimeo = MAX_SCHEDULE_TIMEOUT; | ||
459 | sk->sk_rcvtimeo = MAX_SCHEDULE_TIMEOUT; | ||
460 | } | ||
461 | |||
462 | static int iscsi_target_do_login(struct iscsi_conn *, struct iscsi_login *); | ||
463 | |||
464 | static bool iscsi_target_sk_state_check(struct sock *sk) | ||
465 | { | ||
466 | if (sk->sk_state == TCP_CLOSE_WAIT || sk->sk_state == TCP_CLOSE) { | ||
467 | pr_debug("iscsi_target_sk_state_check: TCP_CLOSE_WAIT|TCP_CLOSE," | ||
468 | "returning FALSE\n"); | ||
469 | return false; | ||
470 | } | ||
471 | return true; | ||
472 | } | ||
473 | |||
474 | static void iscsi_target_login_drop(struct iscsi_conn *conn, struct iscsi_login *login) | ||
475 | { | ||
476 | struct iscsi_np *np = login->np; | ||
477 | bool zero_tsih = login->zero_tsih; | ||
478 | |||
479 | iscsi_remove_failed_auth_entry(conn); | ||
480 | iscsi_target_nego_release(conn); | ||
481 | iscsi_target_login_sess_out(conn, np, zero_tsih, true); | ||
482 | } | ||
483 | |||
484 | static void iscsi_target_login_timeout(unsigned long data) | ||
485 | { | ||
486 | struct iscsi_conn *conn = (struct iscsi_conn *)data; | ||
487 | |||
488 | pr_debug("Entering iscsi_target_login_timeout >>>>>>>>>>>>>>>>>>>\n"); | ||
489 | |||
490 | if (conn->login_kworker) { | ||
491 | pr_debug("Sending SIGINT to conn->login_kworker %s/%d\n", | ||
492 | conn->login_kworker->comm, conn->login_kworker->pid); | ||
493 | send_sig(SIGINT, conn->login_kworker, 1); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | static void iscsi_target_do_login_rx(struct work_struct *work) | ||
498 | { | ||
499 | struct iscsi_conn *conn = container_of(work, | ||
500 | struct iscsi_conn, login_work.work); | ||
501 | struct iscsi_login *login = conn->login; | ||
502 | struct iscsi_np *np = login->np; | ||
503 | struct iscsi_portal_group *tpg = conn->tpg; | ||
504 | struct iscsi_tpg_np *tpg_np = conn->tpg_np; | ||
505 | struct timer_list login_timer; | ||
506 | int rc, zero_tsih = login->zero_tsih; | ||
507 | bool state; | ||
508 | |||
509 | pr_debug("entering iscsi_target_do_login_rx, conn: %p, %s:%d\n", | ||
510 | conn, current->comm, current->pid); | ||
511 | |||
512 | spin_lock(&tpg->tpg_state_lock); | ||
513 | state = (tpg->tpg_state == TPG_STATE_ACTIVE); | ||
514 | spin_unlock(&tpg->tpg_state_lock); | ||
515 | |||
516 | if (state == false) { | ||
517 | pr_debug("iscsi_target_do_login_rx: tpg_state != TPG_STATE_ACTIVE\n"); | ||
518 | iscsi_target_restore_sock_callbacks(conn); | ||
519 | iscsi_target_login_drop(conn, login); | ||
520 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
521 | return; | ||
522 | } | ||
523 | |||
524 | if (conn->sock) { | ||
525 | struct sock *sk = conn->sock->sk; | ||
526 | |||
527 | read_lock_bh(&sk->sk_callback_lock); | ||
528 | state = iscsi_target_sk_state_check(sk); | ||
529 | read_unlock_bh(&sk->sk_callback_lock); | ||
530 | |||
531 | if (state == false) { | ||
532 | pr_debug("iscsi_target_do_login_rx, TCP state CLOSE\n"); | ||
533 | iscsi_target_restore_sock_callbacks(conn); | ||
534 | iscsi_target_login_drop(conn, login); | ||
535 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
536 | return; | ||
537 | } | ||
538 | } | ||
539 | |||
540 | conn->login_kworker = current; | ||
541 | allow_signal(SIGINT); | ||
542 | |||
543 | init_timer(&login_timer); | ||
544 | login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ); | ||
545 | login_timer.data = (unsigned long)conn; | ||
546 | login_timer.function = iscsi_target_login_timeout; | ||
547 | add_timer(&login_timer); | ||
548 | pr_debug("Starting login_timer for %s/%d\n", current->comm, current->pid); | ||
549 | |||
550 | rc = conn->conn_transport->iscsit_get_login_rx(conn, login); | ||
551 | del_timer_sync(&login_timer); | ||
552 | flush_signals(current); | ||
553 | conn->login_kworker = NULL; | ||
554 | |||
555 | if (rc < 0) { | ||
556 | iscsi_target_restore_sock_callbacks(conn); | ||
557 | iscsi_target_login_drop(conn, login); | ||
558 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
559 | return; | ||
560 | } | ||
561 | |||
562 | pr_debug("iscsi_target_do_login_rx after rx_login_io, %p, %s:%d\n", | ||
563 | conn, current->comm, current->pid); | ||
564 | |||
565 | rc = iscsi_target_do_login(conn, login); | ||
566 | if (rc < 0) { | ||
567 | iscsi_target_restore_sock_callbacks(conn); | ||
568 | iscsi_target_login_drop(conn, login); | ||
569 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
570 | } else if (!rc) { | ||
571 | if (conn->sock) { | ||
572 | struct sock *sk = conn->sock->sk; | ||
573 | |||
574 | write_lock_bh(&sk->sk_callback_lock); | ||
575 | clear_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags); | ||
576 | write_unlock_bh(&sk->sk_callback_lock); | ||
577 | } | ||
578 | } else if (rc == 1) { | ||
579 | iscsi_target_nego_release(conn); | ||
580 | iscsi_post_login_handler(np, conn, zero_tsih); | ||
581 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
582 | } | ||
583 | } | ||
584 | |||
585 | static void iscsi_target_do_cleanup(struct work_struct *work) | ||
586 | { | ||
587 | struct iscsi_conn *conn = container_of(work, | ||
588 | struct iscsi_conn, login_cleanup_work.work); | ||
589 | struct sock *sk = conn->sock->sk; | ||
590 | struct iscsi_login *login = conn->login; | ||
591 | struct iscsi_np *np = login->np; | ||
592 | struct iscsi_portal_group *tpg = conn->tpg; | ||
593 | struct iscsi_tpg_np *tpg_np = conn->tpg_np; | ||
594 | |||
595 | pr_debug("Entering iscsi_target_do_cleanup\n"); | ||
596 | |||
597 | cancel_delayed_work_sync(&conn->login_work); | ||
598 | conn->orig_state_change(sk); | ||
599 | |||
600 | iscsi_target_restore_sock_callbacks(conn); | ||
601 | iscsi_target_login_drop(conn, login); | ||
602 | iscsit_deaccess_np(np, tpg, tpg_np); | ||
603 | |||
604 | pr_debug("iscsi_target_do_cleanup done()\n"); | ||
605 | } | ||
606 | |||
607 | static void iscsi_target_sk_state_change(struct sock *sk) | ||
608 | { | ||
609 | struct iscsi_conn *conn; | ||
610 | void (*orig_state_change)(struct sock *); | ||
611 | bool state; | ||
612 | |||
613 | pr_debug("Entering iscsi_target_sk_state_change\n"); | ||
614 | |||
615 | write_lock_bh(&sk->sk_callback_lock); | ||
616 | conn = sk->sk_user_data; | ||
617 | if (!conn) { | ||
618 | write_unlock_bh(&sk->sk_callback_lock); | ||
619 | return; | ||
620 | } | ||
621 | orig_state_change = conn->orig_state_change; | ||
622 | |||
623 | if (!test_bit(LOGIN_FLAGS_READY, &conn->login_flags)) { | ||
624 | pr_debug("Got LOGIN_FLAGS_READY=0 sk_state_change conn: %p\n", | ||
625 | conn); | ||
626 | write_unlock_bh(&sk->sk_callback_lock); | ||
627 | orig_state_change(sk); | ||
628 | return; | ||
629 | } | ||
630 | if (test_bit(LOGIN_FLAGS_READ_ACTIVE, &conn->login_flags)) { | ||
631 | pr_debug("Got LOGIN_FLAGS_READ_ACTIVE=1 sk_state_change" | ||
632 | " conn: %p\n", conn); | ||
633 | write_unlock_bh(&sk->sk_callback_lock); | ||
634 | orig_state_change(sk); | ||
635 | return; | ||
636 | } | ||
637 | if (test_and_set_bit(LOGIN_FLAGS_CLOSED, &conn->login_flags)) { | ||
638 | pr_debug("Got LOGIN_FLAGS_CLOSED=1 sk_state_change conn: %p\n", | ||
639 | conn); | ||
640 | write_unlock_bh(&sk->sk_callback_lock); | ||
641 | orig_state_change(sk); | ||
642 | return; | ||
643 | } | ||
644 | |||
645 | state = iscsi_target_sk_state_check(sk); | ||
646 | write_unlock_bh(&sk->sk_callback_lock); | ||
647 | |||
648 | pr_debug("iscsi_target_sk_state_change: state: %d\n", state); | ||
649 | |||
650 | if (!state) { | ||
651 | pr_debug("iscsi_target_sk_state_change got failed state\n"); | ||
652 | schedule_delayed_work(&conn->login_cleanup_work, 0); | ||
653 | return; | ||
654 | } | ||
655 | orig_state_change(sk); | ||
389 | } | 656 | } |
390 | 657 | ||
391 | /* | 658 | /* |
@@ -643,10 +910,11 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
643 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { | 910 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { |
644 | login->tsih = conn->sess->tsih; | 911 | login->tsih = conn->sess->tsih; |
645 | login->login_complete = 1; | 912 | login->login_complete = 1; |
913 | iscsi_target_restore_sock_callbacks(conn); | ||
646 | if (iscsi_target_do_tx_login_io(conn, | 914 | if (iscsi_target_do_tx_login_io(conn, |
647 | login) < 0) | 915 | login) < 0) |
648 | return -1; | 916 | return -1; |
649 | return 0; | 917 | return 1; |
650 | } | 918 | } |
651 | break; | 919 | break; |
652 | default: | 920 | default: |
@@ -656,13 +924,29 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
656 | break; | 924 | break; |
657 | } | 925 | } |
658 | 926 | ||
659 | if (iscsi_target_do_login_io(conn, login) < 0) | 927 | if (iscsi_target_do_tx_login_io(conn, login) < 0) |
660 | return -1; | 928 | return -1; |
661 | 929 | ||
662 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { | 930 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { |
663 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; | 931 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; |
664 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; | 932 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; |
665 | } | 933 | } |
934 | break; | ||
935 | } | ||
936 | |||
937 | if (conn->sock) { | ||
938 | struct sock *sk = conn->sock->sk; | ||
939 | bool state; | ||
940 | |||
941 | read_lock_bh(&sk->sk_callback_lock); | ||
942 | state = iscsi_target_sk_state_check(sk); | ||
943 | read_unlock_bh(&sk->sk_callback_lock); | ||
944 | |||
945 | if (!state) { | ||
946 | pr_debug("iscsi_target_do_login() failed state for" | ||
947 | " conn: %p\n", conn); | ||
948 | return -1; | ||
949 | } | ||
666 | } | 950 | } |
667 | 951 | ||
668 | return 0; | 952 | return 0; |
@@ -695,9 +979,17 @@ int iscsi_target_locate_portal( | |||
695 | char *tmpbuf, *start = NULL, *end = NULL, *key, *value; | 979 | char *tmpbuf, *start = NULL, *end = NULL, *key, *value; |
696 | struct iscsi_session *sess = conn->sess; | 980 | struct iscsi_session *sess = conn->sess; |
697 | struct iscsi_tiqn *tiqn; | 981 | struct iscsi_tiqn *tiqn; |
982 | struct iscsi_tpg_np *tpg_np = NULL; | ||
698 | struct iscsi_login_req *login_req; | 983 | struct iscsi_login_req *login_req; |
699 | u32 payload_length; | 984 | struct se_node_acl *se_nacl; |
700 | int sessiontype = 0, ret = 0; | 985 | u32 payload_length, queue_depth = 0; |
986 | int sessiontype = 0, ret = 0, tag_num, tag_size; | ||
987 | |||
988 | INIT_DELAYED_WORK(&conn->login_work, iscsi_target_do_login_rx); | ||
989 | INIT_DELAYED_WORK(&conn->login_cleanup_work, iscsi_target_do_cleanup); | ||
990 | iscsi_target_set_sock_callbacks(conn); | ||
991 | |||
992 | login->np = np; | ||
701 | 993 | ||
702 | login_req = (struct iscsi_login_req *) login->req; | 994 | login_req = (struct iscsi_login_req *) login->req; |
703 | payload_length = ntoh24(login_req->dlength); | 995 | payload_length = ntoh24(login_req->dlength); |
@@ -791,7 +1083,7 @@ int iscsi_target_locate_portal( | |||
791 | goto out; | 1083 | goto out; |
792 | } | 1084 | } |
793 | ret = 0; | 1085 | ret = 0; |
794 | goto out; | 1086 | goto alloc_tags; |
795 | } | 1087 | } |
796 | 1088 | ||
797 | get_target: | 1089 | get_target: |
@@ -822,7 +1114,7 @@ get_target: | |||
822 | /* | 1114 | /* |
823 | * Locate Target Portal Group from Storage Node. | 1115 | * Locate Target Portal Group from Storage Node. |
824 | */ | 1116 | */ |
825 | conn->tpg = iscsit_get_tpg_from_np(tiqn, np); | 1117 | conn->tpg = iscsit_get_tpg_from_np(tiqn, np, &tpg_np); |
826 | if (!conn->tpg) { | 1118 | if (!conn->tpg) { |
827 | pr_err("Unable to locate Target Portal Group" | 1119 | pr_err("Unable to locate Target Portal Group" |
828 | " on %s\n", tiqn->tiqn); | 1120 | " on %s\n", tiqn->tiqn); |
@@ -832,12 +1124,16 @@ get_target: | |||
832 | ret = -1; | 1124 | ret = -1; |
833 | goto out; | 1125 | goto out; |
834 | } | 1126 | } |
1127 | conn->tpg_np = tpg_np; | ||
835 | pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); | 1128 | pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); |
836 | /* | 1129 | /* |
837 | * Setup crc32c modules from libcrypto | 1130 | * Setup crc32c modules from libcrypto |
838 | */ | 1131 | */ |
839 | if (iscsi_login_setup_crypto(conn) < 0) { | 1132 | if (iscsi_login_setup_crypto(conn) < 0) { |
840 | pr_err("iscsi_login_setup_crypto() failed\n"); | 1133 | pr_err("iscsi_login_setup_crypto() failed\n"); |
1134 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
1135 | iscsit_put_tiqn_for_login(tiqn); | ||
1136 | conn->tpg = NULL; | ||
841 | ret = -1; | 1137 | ret = -1; |
842 | goto out; | 1138 | goto out; |
843 | } | 1139 | } |
@@ -846,11 +1142,12 @@ get_target: | |||
846 | * process login attempt. | 1142 | * process login attempt. |
847 | */ | 1143 | */ |
848 | if (iscsit_access_np(np, conn->tpg) < 0) { | 1144 | if (iscsit_access_np(np, conn->tpg) < 0) { |
1145 | kref_put(&tpg_np->tpg_np_kref, iscsit_login_kref_put); | ||
849 | iscsit_put_tiqn_for_login(tiqn); | 1146 | iscsit_put_tiqn_for_login(tiqn); |
850 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | 1147 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, |
851 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); | 1148 | ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); |
852 | ret = -1; | ||
853 | conn->tpg = NULL; | 1149 | conn->tpg = NULL; |
1150 | ret = -1; | ||
854 | goto out; | 1151 | goto out; |
855 | } | 1152 | } |
856 | 1153 | ||
@@ -883,8 +1180,27 @@ get_target: | |||
883 | ret = -1; | 1180 | ret = -1; |
884 | goto out; | 1181 | goto out; |
885 | } | 1182 | } |
1183 | se_nacl = sess->se_sess->se_node_acl; | ||
1184 | queue_depth = se_nacl->queue_depth; | ||
1185 | /* | ||
1186 | * Setup pre-allocated tags based upon allowed per NodeACL CmdSN | ||
1187 | * depth for non immediate commands, plus extra tags for immediate | ||
1188 | * commands. | ||
1189 | * | ||
1190 | * Also enforce a ISCSIT_MIN_TAGS to prevent unnecessary contention | ||
1191 | * in per-cpu-ida tag allocation logic + small queue_depth. | ||
1192 | */ | ||
1193 | alloc_tags: | ||
1194 | tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth); | ||
1195 | tag_num += ISCSIT_EXTRA_TAGS; | ||
1196 | tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; | ||
886 | 1197 | ||
887 | ret = 0; | 1198 | ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size); |
1199 | if (ret < 0) { | ||
1200 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
1201 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
1202 | ret = -1; | ||
1203 | } | ||
888 | out: | 1204 | out: |
889 | kfree(tmpbuf); | 1205 | kfree(tmpbuf); |
890 | return ret; | 1206 | return ret; |
@@ -897,10 +1213,23 @@ int iscsi_target_start_negotiation( | |||
897 | int ret; | 1213 | int ret; |
898 | 1214 | ||
899 | ret = iscsi_target_do_login(conn, login); | 1215 | ret = iscsi_target_do_login(conn, login); |
900 | if (ret != 0) | 1216 | if (!ret) { |
1217 | if (conn->sock) { | ||
1218 | struct sock *sk = conn->sock->sk; | ||
1219 | |||
1220 | write_lock_bh(&sk->sk_callback_lock); | ||
1221 | set_bit(LOGIN_FLAGS_READY, &conn->login_flags); | ||
1222 | write_unlock_bh(&sk->sk_callback_lock); | ||
1223 | } | ||
1224 | } else if (ret < 0) { | ||
1225 | cancel_delayed_work_sync(&conn->login_work); | ||
1226 | cancel_delayed_work_sync(&conn->login_cleanup_work); | ||
1227 | iscsi_target_restore_sock_callbacks(conn); | ||
901 | iscsi_remove_failed_auth_entry(conn); | 1228 | iscsi_remove_failed_auth_entry(conn); |
1229 | } | ||
1230 | if (ret != 0) | ||
1231 | iscsi_target_nego_release(conn); | ||
902 | 1232 | ||
903 | iscsi_target_nego_release(conn); | ||
904 | return ret; | 1233 | return ret; |
905 | } | 1234 | } |
906 | 1235 | ||
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c index 11dc2936af76..93bdc475eb00 100644 --- a/drivers/target/iscsi/iscsi_target_nodeattrib.c +++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the main functions related to Initiator Node Attributes. | 2 | * This file contains the main functions related to Initiator Node Attributes. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index 35fd6439eb01..4d2e23fc76fd 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains main functions related to iSCSI Parameter negotiation. | 2 | * This file contains main functions related to iSCSI Parameter negotiation. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -1182,7 +1180,7 @@ static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value, | |||
1182 | unsigned long long tmp; | 1180 | unsigned long long tmp; |
1183 | int rc; | 1181 | int rc; |
1184 | 1182 | ||
1185 | rc = strict_strtoull(param->value, 0, &tmp); | 1183 | rc = kstrtoull(param->value, 0, &tmp); |
1186 | if (rc < 0) | 1184 | if (rc < 0) |
1187 | return -1; | 1185 | return -1; |
1188 | 1186 | ||
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c index edb592a368ef..ca41b583f2f6 100644 --- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c +++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c | |||
@@ -2,9 +2,7 @@ | |||
2 | * This file contains main functions related to iSCSI DataSequenceInOrder=No | 2 | * This file contains main functions related to iSCSI DataSequenceInOrder=No |
3 | * and DataPDUInOrder=No. | 3 | * and DataPDUInOrder=No. |
4 | * | 4 | * |
5 | \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 5 | * (c) Copyright 2007-2013 Datera, Inc. |
6 | * | ||
7 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
8 | * | 6 | * |
9 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 8 | * |
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c index 464b4206a51e..f788e8b5e855 100644 --- a/drivers/target/iscsi/iscsi_target_stat.c +++ b/drivers/target/iscsi/iscsi_target_stat.c | |||
@@ -2,9 +2,7 @@ | |||
2 | * Modern ConfigFS group context specific iSCSI statistics based on original | 2 | * Modern ConfigFS group context specific iSCSI statistics based on original |
3 | * iscsi_target_mib.c code | 3 | * iscsi_target_mib.c code |
4 | * | 4 | * |
5 | * Copyright (c) 2011 Rising Tide Systems | 5 | * Copyright (c) 2011-2013 Datera, Inc. |
6 | * | ||
7 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
8 | * | 6 | * |
9 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 7 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 8 | * |
@@ -177,7 +175,7 @@ ISCSI_STAT_INSTANCE_ATTR_RO(description); | |||
177 | static ssize_t iscsi_stat_instance_show_attr_vendor( | 175 | static ssize_t iscsi_stat_instance_show_attr_vendor( |
178 | struct iscsi_wwn_stat_grps *igrps, char *page) | 176 | struct iscsi_wwn_stat_grps *igrps, char *page) |
179 | { | 177 | { |
180 | return snprintf(page, PAGE_SIZE, "RisingTide Systems iSCSI-Target\n"); | 178 | return snprintf(page, PAGE_SIZE, "Datera, Inc. iSCSI-Target\n"); |
181 | } | 179 | } |
182 | ISCSI_STAT_INSTANCE_ATTR_RO(vendor); | 180 | ISCSI_STAT_INSTANCE_ATTR_RO(vendor); |
183 | 181 | ||
@@ -432,13 +430,7 @@ static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( | |||
432 | int ret; | 430 | int ret; |
433 | 431 | ||
434 | spin_lock(&lstat->lock); | 432 | spin_lock(&lstat->lock); |
435 | if (lstat->last_intr_fail_ip_family == AF_INET6) { | 433 | ret = snprintf(page, PAGE_SIZE, "%s\n", lstat->last_intr_fail_ip_addr); |
436 | ret = snprintf(page, PAGE_SIZE, "[%s]\n", | ||
437 | lstat->last_intr_fail_ip_addr); | ||
438 | } else { | ||
439 | ret = snprintf(page, PAGE_SIZE, "%s\n", | ||
440 | lstat->last_intr_fail_ip_addr); | ||
441 | } | ||
442 | spin_unlock(&lstat->lock); | 434 | spin_unlock(&lstat->lock); |
443 | 435 | ||
444 | return ret; | 436 | return ret; |
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index b997e5da47d3..78404b1cc0bf 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the iSCSI Target specific Task Management functions. | 2 | * This file contains the iSCSI Target specific Task Management functions. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index 439260b7d87f..4faeb47fa5e1 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains iSCSI Target Portal Group related functions. | 2 | * This file contains iSCSI Target Portal Group related functions. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -49,7 +47,7 @@ struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u1 | |||
49 | INIT_LIST_HEAD(&tpg->tpg_gnp_list); | 47 | INIT_LIST_HEAD(&tpg->tpg_gnp_list); |
50 | INIT_LIST_HEAD(&tpg->tpg_list); | 48 | INIT_LIST_HEAD(&tpg->tpg_list); |
51 | mutex_init(&tpg->tpg_access_lock); | 49 | mutex_init(&tpg->tpg_access_lock); |
52 | mutex_init(&tpg->np_login_lock); | 50 | sema_init(&tpg->np_login_sem, 1); |
53 | spin_lock_init(&tpg->tpg_state_lock); | 51 | spin_lock_init(&tpg->tpg_state_lock); |
54 | spin_lock_init(&tpg->tpg_np_lock); | 52 | spin_lock_init(&tpg->tpg_np_lock); |
55 | 53 | ||
@@ -129,7 +127,8 @@ void iscsit_release_discovery_tpg(void) | |||
129 | 127 | ||
130 | struct iscsi_portal_group *iscsit_get_tpg_from_np( | 128 | struct iscsi_portal_group *iscsit_get_tpg_from_np( |
131 | struct iscsi_tiqn *tiqn, | 129 | struct iscsi_tiqn *tiqn, |
132 | struct iscsi_np *np) | 130 | struct iscsi_np *np, |
131 | struct iscsi_tpg_np **tpg_np_out) | ||
133 | { | 132 | { |
134 | struct iscsi_portal_group *tpg = NULL; | 133 | struct iscsi_portal_group *tpg = NULL; |
135 | struct iscsi_tpg_np *tpg_np; | 134 | struct iscsi_tpg_np *tpg_np; |
@@ -147,6 +146,8 @@ struct iscsi_portal_group *iscsit_get_tpg_from_np( | |||
147 | spin_lock(&tpg->tpg_np_lock); | 146 | spin_lock(&tpg->tpg_np_lock); |
148 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { | 147 | list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { |
149 | if (tpg_np->tpg_np == np) { | 148 | if (tpg_np->tpg_np == np) { |
149 | *tpg_np_out = tpg_np; | ||
150 | kref_get(&tpg_np->tpg_np_kref); | ||
150 | spin_unlock(&tpg->tpg_np_lock); | 151 | spin_unlock(&tpg->tpg_np_lock); |
151 | spin_unlock(&tiqn->tiqn_tpg_lock); | 152 | spin_unlock(&tiqn->tiqn_tpg_lock); |
152 | return tpg; | 153 | return tpg; |
@@ -175,18 +176,20 @@ void iscsit_put_tpg(struct iscsi_portal_group *tpg) | |||
175 | 176 | ||
176 | static void iscsit_clear_tpg_np_login_thread( | 177 | static void iscsit_clear_tpg_np_login_thread( |
177 | struct iscsi_tpg_np *tpg_np, | 178 | struct iscsi_tpg_np *tpg_np, |
178 | struct iscsi_portal_group *tpg) | 179 | struct iscsi_portal_group *tpg, |
180 | bool shutdown) | ||
179 | { | 181 | { |
180 | if (!tpg_np->tpg_np) { | 182 | if (!tpg_np->tpg_np) { |
181 | pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); | 183 | pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); |
182 | return; | 184 | return; |
183 | } | 185 | } |
184 | 186 | ||
185 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg); | 187 | iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg, shutdown); |
186 | } | 188 | } |
187 | 189 | ||
188 | void iscsit_clear_tpg_np_login_threads( | 190 | void iscsit_clear_tpg_np_login_threads( |
189 | struct iscsi_portal_group *tpg) | 191 | struct iscsi_portal_group *tpg, |
192 | bool shutdown) | ||
190 | { | 193 | { |
191 | struct iscsi_tpg_np *tpg_np; | 194 | struct iscsi_tpg_np *tpg_np; |
192 | 195 | ||
@@ -197,7 +200,7 @@ void iscsit_clear_tpg_np_login_threads( | |||
197 | continue; | 200 | continue; |
198 | } | 201 | } |
199 | spin_unlock(&tpg->tpg_np_lock); | 202 | spin_unlock(&tpg->tpg_np_lock); |
200 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg); | 203 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg, shutdown); |
201 | spin_lock(&tpg->tpg_np_lock); | 204 | spin_lock(&tpg->tpg_np_lock); |
202 | } | 205 | } |
203 | spin_unlock(&tpg->tpg_np_lock); | 206 | spin_unlock(&tpg->tpg_np_lock); |
@@ -268,6 +271,8 @@ int iscsit_tpg_del_portal_group( | |||
268 | tpg->tpg_state = TPG_STATE_INACTIVE; | 271 | tpg->tpg_state = TPG_STATE_INACTIVE; |
269 | spin_unlock(&tpg->tpg_state_lock); | 272 | spin_unlock(&tpg->tpg_state_lock); |
270 | 273 | ||
274 | iscsit_clear_tpg_np_login_threads(tpg, true); | ||
275 | |||
271 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | 276 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { |
272 | pr_err("Unable to delete iSCSI Target Portal Group:" | 277 | pr_err("Unable to delete iSCSI Target Portal Group:" |
273 | " %hu while active sessions exist, and force=0\n", | 278 | " %hu while active sessions exist, and force=0\n", |
@@ -368,7 +373,7 @@ int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) | |||
368 | tpg->tpg_state = TPG_STATE_INACTIVE; | 373 | tpg->tpg_state = TPG_STATE_INACTIVE; |
369 | spin_unlock(&tpg->tpg_state_lock); | 374 | spin_unlock(&tpg->tpg_state_lock); |
370 | 375 | ||
371 | iscsit_clear_tpg_np_login_threads(tpg); | 376 | iscsit_clear_tpg_np_login_threads(tpg, false); |
372 | 377 | ||
373 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { | 378 | if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { |
374 | spin_lock(&tpg->tpg_state_lock); | 379 | spin_lock(&tpg->tpg_state_lock); |
@@ -490,6 +495,8 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
490 | INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); | 495 | INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); |
491 | INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); | 496 | INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); |
492 | spin_lock_init(&tpg_np->tpg_np_parent_lock); | 497 | spin_lock_init(&tpg_np->tpg_np_parent_lock); |
498 | init_completion(&tpg_np->tpg_np_comp); | ||
499 | kref_init(&tpg_np->tpg_np_kref); | ||
493 | tpg_np->tpg_np = np; | 500 | tpg_np->tpg_np = np; |
494 | tpg_np->tpg = tpg; | 501 | tpg_np->tpg = tpg; |
495 | 502 | ||
@@ -520,7 +527,7 @@ static int iscsit_tpg_release_np( | |||
520 | struct iscsi_portal_group *tpg, | 527 | struct iscsi_portal_group *tpg, |
521 | struct iscsi_np *np) | 528 | struct iscsi_np *np) |
522 | { | 529 | { |
523 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg); | 530 | iscsit_clear_tpg_np_login_thread(tpg_np, tpg, true); |
524 | 531 | ||
525 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", | 532 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", |
526 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, | 533 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, |
diff --git a/drivers/target/iscsi/iscsi_target_tpg.h b/drivers/target/iscsi/iscsi_target_tpg.h index dda48c141a8c..b77693e2c209 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.h +++ b/drivers/target/iscsi/iscsi_target_tpg.h | |||
@@ -5,10 +5,10 @@ extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, | |||
5 | extern int iscsit_load_discovery_tpg(void); | 5 | extern int iscsit_load_discovery_tpg(void); |
6 | extern void iscsit_release_discovery_tpg(void); | 6 | extern void iscsit_release_discovery_tpg(void); |
7 | extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, | 7 | extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, |
8 | struct iscsi_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 *); | 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 *); | 12 | 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 *); | 13 | 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 *, | 14 | extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, |
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c index 81289520f96b..601e9cc61e98 100644 --- a/drivers/target/iscsi/iscsi_target_tq.c +++ b/drivers/target/iscsi/iscsi_target_tq.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the iSCSI Login Thread and Thread Queue functions. | 2 | * This file contains the iSCSI Login Thread and Thread Queue functions. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -105,12 +103,11 @@ int iscsi_allocate_thread_sets(u32 thread_pair_count) | |||
105 | ts->status = ISCSI_THREAD_SET_FREE; | 103 | ts->status = ISCSI_THREAD_SET_FREE; |
106 | INIT_LIST_HEAD(&ts->ts_list); | 104 | INIT_LIST_HEAD(&ts->ts_list); |
107 | spin_lock_init(&ts->ts_state_lock); | 105 | spin_lock_init(&ts->ts_state_lock); |
108 | init_completion(&ts->rx_post_start_comp); | ||
109 | init_completion(&ts->tx_post_start_comp); | ||
110 | init_completion(&ts->rx_restart_comp); | 106 | init_completion(&ts->rx_restart_comp); |
111 | init_completion(&ts->tx_restart_comp); | 107 | init_completion(&ts->tx_restart_comp); |
112 | init_completion(&ts->rx_start_comp); | 108 | init_completion(&ts->rx_start_comp); |
113 | init_completion(&ts->tx_start_comp); | 109 | init_completion(&ts->tx_start_comp); |
110 | sema_init(&ts->ts_activate_sem, 0); | ||
114 | 111 | ||
115 | ts->create_threads = 1; | 112 | ts->create_threads = 1; |
116 | ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", | 113 | ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", |
@@ -139,35 +136,44 @@ int iscsi_allocate_thread_sets(u32 thread_pair_count) | |||
139 | return allocated_thread_pair_count; | 136 | return allocated_thread_pair_count; |
140 | } | 137 | } |
141 | 138 | ||
142 | void iscsi_deallocate_thread_sets(void) | 139 | static void iscsi_deallocate_thread_one(struct iscsi_thread_set *ts) |
143 | { | 140 | { |
144 | u32 released_count = 0; | 141 | spin_lock_bh(&ts->ts_state_lock); |
145 | struct iscsi_thread_set *ts = NULL; | 142 | ts->status = ISCSI_THREAD_SET_DIE; |
146 | |||
147 | while ((ts = iscsi_get_ts_from_inactive_list())) { | ||
148 | 143 | ||
144 | if (ts->rx_thread) { | ||
145 | complete(&ts->rx_start_comp); | ||
146 | spin_unlock_bh(&ts->ts_state_lock); | ||
147 | kthread_stop(ts->rx_thread); | ||
149 | spin_lock_bh(&ts->ts_state_lock); | 148 | spin_lock_bh(&ts->ts_state_lock); |
150 | ts->status = ISCSI_THREAD_SET_DIE; | 149 | } |
150 | if (ts->tx_thread) { | ||
151 | complete(&ts->tx_start_comp); | ||
151 | spin_unlock_bh(&ts->ts_state_lock); | 152 | spin_unlock_bh(&ts->ts_state_lock); |
153 | kthread_stop(ts->tx_thread); | ||
154 | spin_lock_bh(&ts->ts_state_lock); | ||
155 | } | ||
156 | spin_unlock_bh(&ts->ts_state_lock); | ||
157 | /* | ||
158 | * Release this thread_id in the thread_set_bitmap | ||
159 | */ | ||
160 | spin_lock(&ts_bitmap_lock); | ||
161 | bitmap_release_region(iscsit_global->ts_bitmap, | ||
162 | ts->thread_id, get_order(1)); | ||
163 | spin_unlock(&ts_bitmap_lock); | ||
152 | 164 | ||
153 | if (ts->rx_thread) { | 165 | kfree(ts); |
154 | send_sig(SIGINT, ts->rx_thread, 1); | 166 | } |
155 | kthread_stop(ts->rx_thread); | ||
156 | } | ||
157 | if (ts->tx_thread) { | ||
158 | send_sig(SIGINT, ts->tx_thread, 1); | ||
159 | kthread_stop(ts->tx_thread); | ||
160 | } | ||
161 | /* | ||
162 | * Release this thread_id in the thread_set_bitmap | ||
163 | */ | ||
164 | spin_lock(&ts_bitmap_lock); | ||
165 | bitmap_release_region(iscsit_global->ts_bitmap, | ||
166 | ts->thread_id, get_order(1)); | ||
167 | spin_unlock(&ts_bitmap_lock); | ||
168 | 167 | ||
168 | void iscsi_deallocate_thread_sets(void) | ||
169 | { | ||
170 | struct iscsi_thread_set *ts = NULL; | ||
171 | u32 released_count = 0; | ||
172 | |||
173 | while ((ts = iscsi_get_ts_from_inactive_list())) { | ||
174 | |||
175 | iscsi_deallocate_thread_one(ts); | ||
169 | released_count++; | 176 | released_count++; |
170 | kfree(ts); | ||
171 | } | 177 | } |
172 | 178 | ||
173 | if (released_count) | 179 | if (released_count) |
@@ -187,34 +193,13 @@ static void iscsi_deallocate_extra_thread_sets(void) | |||
187 | if (!ts) | 193 | if (!ts) |
188 | break; | 194 | break; |
189 | 195 | ||
190 | spin_lock_bh(&ts->ts_state_lock); | 196 | iscsi_deallocate_thread_one(ts); |
191 | ts->status = ISCSI_THREAD_SET_DIE; | ||
192 | spin_unlock_bh(&ts->ts_state_lock); | ||
193 | |||
194 | if (ts->rx_thread) { | ||
195 | send_sig(SIGINT, ts->rx_thread, 1); | ||
196 | kthread_stop(ts->rx_thread); | ||
197 | } | ||
198 | if (ts->tx_thread) { | ||
199 | send_sig(SIGINT, ts->tx_thread, 1); | ||
200 | kthread_stop(ts->tx_thread); | ||
201 | } | ||
202 | /* | ||
203 | * Release this thread_id in the thread_set_bitmap | ||
204 | */ | ||
205 | spin_lock(&ts_bitmap_lock); | ||
206 | bitmap_release_region(iscsit_global->ts_bitmap, | ||
207 | ts->thread_id, get_order(1)); | ||
208 | spin_unlock(&ts_bitmap_lock); | ||
209 | |||
210 | released_count++; | 197 | released_count++; |
211 | kfree(ts); | ||
212 | } | 198 | } |
213 | 199 | ||
214 | if (released_count) { | 200 | if (released_count) |
215 | pr_debug("Stopped %d thread set(s) (%d total threads)." | 201 | pr_debug("Stopped %d thread set(s) (%d total threads)." |
216 | "\n", released_count, released_count * 2); | 202 | "\n", released_count, released_count * 2); |
217 | } | ||
218 | } | 203 | } |
219 | 204 | ||
220 | void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) | 205 | void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) |
@@ -224,37 +209,23 @@ void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set | |||
224 | spin_lock_bh(&ts->ts_state_lock); | 209 | spin_lock_bh(&ts->ts_state_lock); |
225 | conn->thread_set = ts; | 210 | conn->thread_set = ts; |
226 | ts->conn = conn; | 211 | ts->conn = conn; |
212 | ts->status = ISCSI_THREAD_SET_ACTIVE; | ||
227 | spin_unlock_bh(&ts->ts_state_lock); | 213 | spin_unlock_bh(&ts->ts_state_lock); |
228 | /* | 214 | |
229 | * Start up the RX thread and wait on rx_post_start_comp. The RX | ||
230 | * Thread will then do the same for the TX Thread in | ||
231 | * iscsi_rx_thread_pre_handler(). | ||
232 | */ | ||
233 | complete(&ts->rx_start_comp); | 215 | complete(&ts->rx_start_comp); |
234 | wait_for_completion(&ts->rx_post_start_comp); | 216 | complete(&ts->tx_start_comp); |
217 | |||
218 | down(&ts->ts_activate_sem); | ||
235 | } | 219 | } |
236 | 220 | ||
237 | struct iscsi_thread_set *iscsi_get_thread_set(void) | 221 | struct iscsi_thread_set *iscsi_get_thread_set(void) |
238 | { | 222 | { |
239 | int allocate_ts = 0; | 223 | struct iscsi_thread_set *ts; |
240 | struct completion comp; | 224 | |
241 | struct iscsi_thread_set *ts = NULL; | ||
242 | /* | ||
243 | * If no inactive thread set is available on the first call to | ||
244 | * iscsi_get_ts_from_inactive_list(), sleep for a second and | ||
245 | * try again. If still none are available after two attempts, | ||
246 | * allocate a set ourselves. | ||
247 | */ | ||
248 | get_set: | 225 | get_set: |
249 | ts = iscsi_get_ts_from_inactive_list(); | 226 | ts = iscsi_get_ts_from_inactive_list(); |
250 | if (!ts) { | 227 | if (!ts) { |
251 | if (allocate_ts == 2) | 228 | iscsi_allocate_thread_sets(1); |
252 | iscsi_allocate_thread_sets(1); | ||
253 | |||
254 | init_completion(&comp); | ||
255 | wait_for_completion_timeout(&comp, 1 * HZ); | ||
256 | |||
257 | allocate_ts++; | ||
258 | goto get_set; | 229 | goto get_set; |
259 | } | 230 | } |
260 | 231 | ||
@@ -263,6 +234,7 @@ get_set: | |||
263 | ts->thread_count = 2; | 234 | ts->thread_count = 2; |
264 | init_completion(&ts->rx_restart_comp); | 235 | init_completion(&ts->rx_restart_comp); |
265 | init_completion(&ts->tx_restart_comp); | 236 | init_completion(&ts->tx_restart_comp); |
237 | sema_init(&ts->ts_activate_sem, 0); | ||
266 | 238 | ||
267 | return ts; | 239 | return ts; |
268 | } | 240 | } |
@@ -400,7 +372,8 @@ static void iscsi_check_to_add_additional_sets(void) | |||
400 | static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) | 372 | static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) |
401 | { | 373 | { |
402 | spin_lock_bh(&ts->ts_state_lock); | 374 | spin_lock_bh(&ts->ts_state_lock); |
403 | if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) { | 375 | if (ts->status == ISCSI_THREAD_SET_DIE || kthread_should_stop() || |
376 | signal_pending(current)) { | ||
404 | spin_unlock_bh(&ts->ts_state_lock); | 377 | spin_unlock_bh(&ts->ts_state_lock); |
405 | return -1; | 378 | return -1; |
406 | } | 379 | } |
@@ -419,7 +392,8 @@ struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) | |||
419 | goto sleep; | 392 | goto sleep; |
420 | } | 393 | } |
421 | 394 | ||
422 | flush_signals(current); | 395 | if (ts->status != ISCSI_THREAD_SET_DIE) |
396 | flush_signals(current); | ||
423 | 397 | ||
424 | if (ts->delay_inactive && (--ts->thread_count == 0)) { | 398 | if (ts->delay_inactive && (--ts->thread_count == 0)) { |
425 | spin_unlock_bh(&ts->ts_state_lock); | 399 | spin_unlock_bh(&ts->ts_state_lock); |
@@ -446,18 +420,19 @@ sleep: | |||
446 | if (iscsi_signal_thread_pre_handler(ts) < 0) | 420 | if (iscsi_signal_thread_pre_handler(ts) < 0) |
447 | return NULL; | 421 | return NULL; |
448 | 422 | ||
423 | iscsi_check_to_add_additional_sets(); | ||
424 | |||
425 | spin_lock_bh(&ts->ts_state_lock); | ||
449 | if (!ts->conn) { | 426 | if (!ts->conn) { |
450 | pr_err("struct iscsi_thread_set->conn is NULL for" | 427 | pr_err("struct iscsi_thread_set->conn is NULL for" |
451 | " thread_id: %d, going back to sleep\n", ts->thread_id); | 428 | " RX thread_id: %s/%d\n", current->comm, current->pid); |
452 | goto sleep; | 429 | spin_unlock_bh(&ts->ts_state_lock); |
430 | return NULL; | ||
453 | } | 431 | } |
454 | iscsi_check_to_add_additional_sets(); | ||
455 | /* | ||
456 | * The RX Thread starts up the TX Thread and sleeps. | ||
457 | */ | ||
458 | ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; | 432 | ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; |
459 | complete(&ts->tx_start_comp); | 433 | spin_unlock_bh(&ts->ts_state_lock); |
460 | wait_for_completion(&ts->tx_post_start_comp); | 434 | |
435 | up(&ts->ts_activate_sem); | ||
461 | 436 | ||
462 | return ts->conn; | 437 | return ts->conn; |
463 | } | 438 | } |
@@ -472,7 +447,8 @@ struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) | |||
472 | goto sleep; | 447 | goto sleep; |
473 | } | 448 | } |
474 | 449 | ||
475 | flush_signals(current); | 450 | if (ts->status != ISCSI_THREAD_SET_DIE) |
451 | flush_signals(current); | ||
476 | 452 | ||
477 | if (ts->delay_inactive && (--ts->thread_count == 0)) { | 453 | if (ts->delay_inactive && (--ts->thread_count == 0)) { |
478 | spin_unlock_bh(&ts->ts_state_lock); | 454 | spin_unlock_bh(&ts->ts_state_lock); |
@@ -498,27 +474,20 @@ sleep: | |||
498 | if (iscsi_signal_thread_pre_handler(ts) < 0) | 474 | if (iscsi_signal_thread_pre_handler(ts) < 0) |
499 | return NULL; | 475 | return NULL; |
500 | 476 | ||
501 | if (!ts->conn) { | ||
502 | pr_err("struct iscsi_thread_set->conn is NULL for " | ||
503 | " thread_id: %d, going back to sleep\n", | ||
504 | ts->thread_id); | ||
505 | goto sleep; | ||
506 | } | ||
507 | |||
508 | iscsi_check_to_add_additional_sets(); | 477 | iscsi_check_to_add_additional_sets(); |
509 | /* | ||
510 | * From the TX thread, up the tx_post_start_comp that the RX Thread is | ||
511 | * sleeping on in iscsi_rx_thread_pre_handler(), then up the | ||
512 | * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on. | ||
513 | */ | ||
514 | ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; | ||
515 | complete(&ts->tx_post_start_comp); | ||
516 | complete(&ts->rx_post_start_comp); | ||
517 | 478 | ||
518 | spin_lock_bh(&ts->ts_state_lock); | 479 | spin_lock_bh(&ts->ts_state_lock); |
519 | ts->status = ISCSI_THREAD_SET_ACTIVE; | 480 | if (!ts->conn) { |
481 | pr_err("struct iscsi_thread_set->conn is NULL for" | ||
482 | " TX thread_id: %s/%d\n", current->comm, current->pid); | ||
483 | spin_unlock_bh(&ts->ts_state_lock); | ||
484 | return NULL; | ||
485 | } | ||
486 | ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; | ||
520 | spin_unlock_bh(&ts->ts_state_lock); | 487 | spin_unlock_bh(&ts->ts_state_lock); |
521 | 488 | ||
489 | up(&ts->ts_activate_sem); | ||
490 | |||
522 | return ts->conn; | 491 | return ts->conn; |
523 | } | 492 | } |
524 | 493 | ||
diff --git a/drivers/target/iscsi/iscsi_target_tq.h b/drivers/target/iscsi/iscsi_target_tq.h index 547d11831282..cc1eede5ab3a 100644 --- a/drivers/target/iscsi/iscsi_target_tq.h +++ b/drivers/target/iscsi/iscsi_target_tq.h | |||
@@ -64,10 +64,6 @@ struct iscsi_thread_set { | |||
64 | struct iscsi_conn *conn; | 64 | struct iscsi_conn *conn; |
65 | /* used for controlling ts state accesses */ | 65 | /* used for controlling ts state accesses */ |
66 | spinlock_t ts_state_lock; | 66 | spinlock_t ts_state_lock; |
67 | /* Used for rx side post startup */ | ||
68 | struct completion rx_post_start_comp; | ||
69 | /* Used for tx side post startup */ | ||
70 | struct completion tx_post_start_comp; | ||
71 | /* used for restarting thread queue */ | 67 | /* used for restarting thread queue */ |
72 | struct completion rx_restart_comp; | 68 | struct completion rx_restart_comp; |
73 | /* used for restarting thread queue */ | 69 | /* used for restarting thread queue */ |
@@ -82,6 +78,7 @@ struct iscsi_thread_set { | |||
82 | struct task_struct *tx_thread; | 78 | struct task_struct *tx_thread; |
83 | /* struct iscsi_thread_set in list list head*/ | 79 | /* struct iscsi_thread_set in list list head*/ |
84 | struct list_head ts_list; | 80 | struct list_head ts_list; |
81 | struct semaphore ts_activate_sem; | ||
85 | }; | 82 | }; |
86 | 83 | ||
87 | #endif /*** ISCSI_THREAD_QUEUE_H ***/ | 84 | #endif /*** ISCSI_THREAD_QUEUE_H ***/ |
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 1df06d5e4e01..f2de28e178fd 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
@@ -1,9 +1,7 @@ | |||
1 | /******************************************************************************* | 1 | /******************************************************************************* |
2 | * This file contains the iSCSI Target specific utility functions. | 2 | * This file contains the iSCSI Target specific utility functions. |
3 | * | 3 | * |
4 | * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. | 4 | * (c) Copyright 2007-2013 Datera, Inc. |
5 | * | ||
6 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | ||
7 | * | 5 | * |
8 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> | 6 | * Author: Nicholas A. Bellinger <nab@linux-iscsi.org> |
9 | * | 7 | * |
@@ -19,6 +17,7 @@ | |||
19 | ******************************************************************************/ | 17 | ******************************************************************************/ |
20 | 18 | ||
21 | #include <linux/list.h> | 19 | #include <linux/list.h> |
20 | #include <linux/percpu_ida.h> | ||
22 | #include <scsi/scsi_tcq.h> | 21 | #include <scsi/scsi_tcq.h> |
23 | #include <scsi/iscsi_proto.h> | 22 | #include <scsi/iscsi_proto.h> |
24 | #include <target/target_core_base.h> | 23 | #include <target/target_core_base.h> |
@@ -149,18 +148,6 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) | |||
149 | spin_unlock_bh(&cmd->r2t_lock); | 148 | spin_unlock_bh(&cmd->r2t_lock); |
150 | } | 149 | } |
151 | 150 | ||
152 | struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) | ||
153 | { | ||
154 | struct iscsi_cmd *cmd; | ||
155 | |||
156 | cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask); | ||
157 | if (!cmd) | ||
158 | return NULL; | ||
159 | |||
160 | cmd->release_cmd = &iscsit_release_cmd; | ||
161 | return cmd; | ||
162 | } | ||
163 | |||
164 | /* | 151 | /* |
165 | * May be called from software interrupt (timer) context for allocating | 152 | * May be called from software interrupt (timer) context for allocating |
166 | * iSCSI NopINs. | 153 | * iSCSI NopINs. |
@@ -168,12 +155,15 @@ struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) | |||
168 | struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) | 155 | struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) |
169 | { | 156 | { |
170 | struct iscsi_cmd *cmd; | 157 | struct iscsi_cmd *cmd; |
158 | struct se_session *se_sess = conn->sess->se_sess; | ||
159 | int size, tag; | ||
171 | 160 | ||
172 | cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask); | 161 | tag = percpu_ida_alloc(&se_sess->sess_tag_pool, gfp_mask); |
173 | if (!cmd) { | 162 | size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size; |
174 | pr_err("Unable to allocate memory for struct iscsi_cmd.\n"); | 163 | cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size)); |
175 | return NULL; | 164 | memset(cmd, 0, size); |
176 | } | 165 | |
166 | cmd->se_cmd.map_tag = tag; | ||
177 | cmd->conn = conn; | 167 | cmd->conn = conn; |
178 | INIT_LIST_HEAD(&cmd->i_conn_node); | 168 | INIT_LIST_HEAD(&cmd->i_conn_node); |
179 | INIT_LIST_HEAD(&cmd->datain_list); | 169 | INIT_LIST_HEAD(&cmd->datain_list); |
@@ -689,6 +679,16 @@ void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) | |||
689 | 679 | ||
690 | void iscsit_release_cmd(struct iscsi_cmd *cmd) | 680 | void iscsit_release_cmd(struct iscsi_cmd *cmd) |
691 | { | 681 | { |
682 | struct iscsi_session *sess; | ||
683 | struct se_cmd *se_cmd = &cmd->se_cmd; | ||
684 | |||
685 | if (cmd->conn) | ||
686 | sess = cmd->conn->sess; | ||
687 | else | ||
688 | sess = cmd->sess; | ||
689 | |||
690 | BUG_ON(!sess || !sess->se_sess); | ||
691 | |||
692 | kfree(cmd->buf_ptr); | 692 | kfree(cmd->buf_ptr); |
693 | kfree(cmd->pdu_list); | 693 | kfree(cmd->pdu_list); |
694 | kfree(cmd->seq_list); | 694 | kfree(cmd->seq_list); |
@@ -696,8 +696,9 @@ void iscsit_release_cmd(struct iscsi_cmd *cmd) | |||
696 | kfree(cmd->iov_data); | 696 | kfree(cmd->iov_data); |
697 | kfree(cmd->text_in_ptr); | 697 | kfree(cmd->text_in_ptr); |
698 | 698 | ||
699 | kmem_cache_free(lio_cmd_cache, cmd); | 699 | percpu_ida_free(&sess->se_sess->sess_tag_pool, se_cmd->map_tag); |
700 | } | 700 | } |
701 | EXPORT_SYMBOL(iscsit_release_cmd); | ||
701 | 702 | ||
702 | static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd, | 703 | static void __iscsit_free_cmd(struct iscsi_cmd *cmd, bool scsi_cmd, |
703 | bool check_queues) | 704 | bool check_queues) |
@@ -761,7 +762,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd, bool shutdown) | |||
761 | /* Fall-through */ | 762 | /* Fall-through */ |
762 | default: | 763 | default: |
763 | __iscsit_free_cmd(cmd, false, shutdown); | 764 | __iscsit_free_cmd(cmd, false, shutdown); |
764 | cmd->release_cmd(cmd); | 765 | iscsit_release_cmd(cmd); |
765 | break; | 766 | break; |
766 | } | 767 | } |
767 | } | 768 | } |
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c index 568ad25f25d3..0f6d69dabca1 100644 --- a/drivers/target/loopback/tcm_loop.c +++ b/drivers/target/loopback/tcm_loop.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * This file contains the Linux/SCSI LLD virtual SCSI initiator driver | 3 | * This file contains the Linux/SCSI LLD virtual SCSI initiator driver |
4 | * for emulated SAS initiator ports | 4 | * for emulated SAS initiator ports |
5 | * | 5 | * |
6 | * © Copyright 2011 RisingTide Systems LLC. | 6 | * © Copyright 2011-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. | 8 | * Licensed to the Linux Foundation under the General Public License (GPL) version 2. |
9 | * | 9 | * |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index cbe48ab41745..47244102281e 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA) | 4 | * This file contains SPC-3 compliant asymmetric logical unit assigntment (ALUA) |
5 | * | 5 | * |
6 | * (c) Copyright 2009-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2009-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
@@ -557,6 +557,9 @@ target_alua_state_check(struct se_cmd *cmd) | |||
557 | * a ALUA logical unit group. | 557 | * a ALUA logical unit group. |
558 | */ | 558 | */ |
559 | tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; | 559 | tg_pt_gp_mem = port->sep_alua_tg_pt_gp_mem; |
560 | if (!tg_pt_gp_mem) | ||
561 | return 0; | ||
562 | |||
560 | spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); | 563 | spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock); |
561 | tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; | 564 | tg_pt_gp = tg_pt_gp_mem->tg_pt_gp; |
562 | out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); | 565 | out_alua_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state); |
@@ -730,7 +733,7 @@ static int core_alua_write_tpg_metadata( | |||
730 | if (ret < 0) | 733 | if (ret < 0) |
731 | pr_err("Error writing ALUA metadata file: %s\n", path); | 734 | pr_err("Error writing ALUA metadata file: %s\n", path); |
732 | fput(file); | 735 | fput(file); |
733 | return ret ? -EIO : 0; | 736 | return (ret < 0) ? -EIO : 0; |
734 | } | 737 | } |
735 | 738 | ||
736 | /* | 739 | /* |
@@ -1756,10 +1759,10 @@ ssize_t core_alua_store_access_type( | |||
1756 | unsigned long tmp; | 1759 | unsigned long tmp; |
1757 | int ret; | 1760 | int ret; |
1758 | 1761 | ||
1759 | ret = strict_strtoul(page, 0, &tmp); | 1762 | ret = kstrtoul(page, 0, &tmp); |
1760 | if (ret < 0) { | 1763 | if (ret < 0) { |
1761 | pr_err("Unable to extract alua_access_type\n"); | 1764 | pr_err("Unable to extract alua_access_type\n"); |
1762 | return -EINVAL; | 1765 | return ret; |
1763 | } | 1766 | } |
1764 | if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) { | 1767 | if ((tmp != 0) && (tmp != 1) && (tmp != 2) && (tmp != 3)) { |
1765 | pr_err("Illegal value for alua_access_type:" | 1768 | pr_err("Illegal value for alua_access_type:" |
@@ -1794,10 +1797,10 @@ ssize_t core_alua_store_nonop_delay_msecs( | |||
1794 | unsigned long tmp; | 1797 | unsigned long tmp; |
1795 | int ret; | 1798 | int ret; |
1796 | 1799 | ||
1797 | ret = strict_strtoul(page, 0, &tmp); | 1800 | ret = kstrtoul(page, 0, &tmp); |
1798 | if (ret < 0) { | 1801 | if (ret < 0) { |
1799 | pr_err("Unable to extract nonop_delay_msecs\n"); | 1802 | pr_err("Unable to extract nonop_delay_msecs\n"); |
1800 | return -EINVAL; | 1803 | return ret; |
1801 | } | 1804 | } |
1802 | if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) { | 1805 | if (tmp > ALUA_MAX_NONOP_DELAY_MSECS) { |
1803 | pr_err("Passed nonop_delay_msecs: %lu, exceeds" | 1806 | pr_err("Passed nonop_delay_msecs: %lu, exceeds" |
@@ -1825,10 +1828,10 @@ ssize_t core_alua_store_trans_delay_msecs( | |||
1825 | unsigned long tmp; | 1828 | unsigned long tmp; |
1826 | int ret; | 1829 | int ret; |
1827 | 1830 | ||
1828 | ret = strict_strtoul(page, 0, &tmp); | 1831 | ret = kstrtoul(page, 0, &tmp); |
1829 | if (ret < 0) { | 1832 | if (ret < 0) { |
1830 | pr_err("Unable to extract trans_delay_msecs\n"); | 1833 | pr_err("Unable to extract trans_delay_msecs\n"); |
1831 | return -EINVAL; | 1834 | return ret; |
1832 | } | 1835 | } |
1833 | if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) { | 1836 | if (tmp > ALUA_MAX_TRANS_DELAY_MSECS) { |
1834 | pr_err("Passed trans_delay_msecs: %lu, exceeds" | 1837 | pr_err("Passed trans_delay_msecs: %lu, exceeds" |
@@ -1856,10 +1859,10 @@ ssize_t core_alua_store_implict_trans_secs( | |||
1856 | unsigned long tmp; | 1859 | unsigned long tmp; |
1857 | int ret; | 1860 | int ret; |
1858 | 1861 | ||
1859 | ret = strict_strtoul(page, 0, &tmp); | 1862 | ret = kstrtoul(page, 0, &tmp); |
1860 | if (ret < 0) { | 1863 | if (ret < 0) { |
1861 | pr_err("Unable to extract implict_trans_secs\n"); | 1864 | pr_err("Unable to extract implict_trans_secs\n"); |
1862 | return -EINVAL; | 1865 | return ret; |
1863 | } | 1866 | } |
1864 | if (tmp > ALUA_MAX_IMPLICT_TRANS_SECS) { | 1867 | if (tmp > ALUA_MAX_IMPLICT_TRANS_SECS) { |
1865 | pr_err("Passed implict_trans_secs: %lu, exceeds" | 1868 | pr_err("Passed implict_trans_secs: %lu, exceeds" |
@@ -1887,10 +1890,10 @@ ssize_t core_alua_store_preferred_bit( | |||
1887 | unsigned long tmp; | 1890 | unsigned long tmp; |
1888 | int ret; | 1891 | int ret; |
1889 | 1892 | ||
1890 | ret = strict_strtoul(page, 0, &tmp); | 1893 | ret = kstrtoul(page, 0, &tmp); |
1891 | if (ret < 0) { | 1894 | if (ret < 0) { |
1892 | pr_err("Unable to extract preferred ALUA value\n"); | 1895 | pr_err("Unable to extract preferred ALUA value\n"); |
1893 | return -EINVAL; | 1896 | return ret; |
1894 | } | 1897 | } |
1895 | if ((tmp != 0) && (tmp != 1)) { | 1898 | if ((tmp != 0) && (tmp != 1)) { |
1896 | pr_err("Illegal value for preferred ALUA: %lu\n", tmp); | 1899 | pr_err("Illegal value for preferred ALUA: %lu\n", tmp); |
@@ -1922,10 +1925,10 @@ ssize_t core_alua_store_offline_bit( | |||
1922 | if (!lun->lun_sep) | 1925 | if (!lun->lun_sep) |
1923 | return -ENODEV; | 1926 | return -ENODEV; |
1924 | 1927 | ||
1925 | ret = strict_strtoul(page, 0, &tmp); | 1928 | ret = kstrtoul(page, 0, &tmp); |
1926 | if (ret < 0) { | 1929 | if (ret < 0) { |
1927 | pr_err("Unable to extract alua_tg_pt_offline value\n"); | 1930 | pr_err("Unable to extract alua_tg_pt_offline value\n"); |
1928 | return -EINVAL; | 1931 | return ret; |
1929 | } | 1932 | } |
1930 | if ((tmp != 0) && (tmp != 1)) { | 1933 | if ((tmp != 0) && (tmp != 1)) { |
1931 | pr_err("Illegal value for alua_tg_pt_offline: %lu\n", | 1934 | pr_err("Illegal value for alua_tg_pt_offline: %lu\n", |
@@ -1961,10 +1964,10 @@ ssize_t core_alua_store_secondary_status( | |||
1961 | unsigned long tmp; | 1964 | unsigned long tmp; |
1962 | int ret; | 1965 | int ret; |
1963 | 1966 | ||
1964 | ret = strict_strtoul(page, 0, &tmp); | 1967 | ret = kstrtoul(page, 0, &tmp); |
1965 | if (ret < 0) { | 1968 | if (ret < 0) { |
1966 | pr_err("Unable to extract alua_tg_pt_status\n"); | 1969 | pr_err("Unable to extract alua_tg_pt_status\n"); |
1967 | return -EINVAL; | 1970 | return ret; |
1968 | } | 1971 | } |
1969 | if ((tmp != ALUA_STATUS_NONE) && | 1972 | if ((tmp != ALUA_STATUS_NONE) && |
1970 | (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && | 1973 | (tmp != ALUA_STATUS_ALTERED_BY_EXPLICT_STPG) && |
@@ -1994,10 +1997,10 @@ ssize_t core_alua_store_secondary_write_metadata( | |||
1994 | unsigned long tmp; | 1997 | unsigned long tmp; |
1995 | int ret; | 1998 | int ret; |
1996 | 1999 | ||
1997 | ret = strict_strtoul(page, 0, &tmp); | 2000 | ret = kstrtoul(page, 0, &tmp); |
1998 | if (ret < 0) { | 2001 | if (ret < 0) { |
1999 | pr_err("Unable to extract alua_tg_pt_write_md\n"); | 2002 | pr_err("Unable to extract alua_tg_pt_write_md\n"); |
2000 | return -EINVAL; | 2003 | return ret; |
2001 | } | 2004 | } |
2002 | if ((tmp != 0) && (tmp != 1)) { | 2005 | if ((tmp != 0) && (tmp != 1)) { |
2003 | pr_err("Illegal value for alua_tg_pt_write_md:" | 2006 | pr_err("Illegal value for alua_tg_pt_write_md:" |
diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c index e4d22933efaf..82e81c542e43 100644 --- a/drivers/target/target_core_configfs.c +++ b/drivers/target/target_core_configfs.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains ConfigFS logic for the Generic Target Engine project. | 4 | * This file contains ConfigFS logic for the Generic Target Engine project. |
5 | * | 5 | * |
6 | * (c) Copyright 2008-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2008-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
@@ -48,6 +48,7 @@ | |||
48 | #include "target_core_alua.h" | 48 | #include "target_core_alua.h" |
49 | #include "target_core_pr.h" | 49 | #include "target_core_pr.h" |
50 | #include "target_core_rd.h" | 50 | #include "target_core_rd.h" |
51 | #include "target_core_xcopy.h" | ||
51 | 52 | ||
52 | extern struct t10_alua_lu_gp *default_lu_gp; | 53 | extern struct t10_alua_lu_gp *default_lu_gp; |
53 | 54 | ||
@@ -268,7 +269,7 @@ static struct configfs_subsystem target_core_fabrics = { | |||
268 | }, | 269 | }, |
269 | }; | 270 | }; |
270 | 271 | ||
271 | static struct configfs_subsystem *target_core_subsystem[] = { | 272 | struct configfs_subsystem *target_core_subsystem[] = { |
272 | &target_core_fabrics, | 273 | &target_core_fabrics, |
273 | NULL, | 274 | NULL, |
274 | }; | 275 | }; |
@@ -577,9 +578,9 @@ static ssize_t target_core_dev_store_attr_##_name( \ | |||
577 | unsigned long val; \ | 578 | unsigned long val; \ |
578 | int ret; \ | 579 | int ret; \ |
579 | \ | 580 | \ |
580 | ret = strict_strtoul(page, 0, &val); \ | 581 | ret = kstrtoul(page, 0, &val); \ |
581 | if (ret < 0) { \ | 582 | if (ret < 0) { \ |
582 | pr_err("strict_strtoul() failed with" \ | 583 | pr_err("kstrtoul() failed with" \ |
583 | " ret: %d\n", ret); \ | 584 | " ret: %d\n", ret); \ |
584 | return -EINVAL; \ | 585 | return -EINVAL; \ |
585 | } \ | 586 | } \ |
@@ -636,6 +637,12 @@ SE_DEV_ATTR(emulate_tpu, S_IRUGO | S_IWUSR); | |||
636 | DEF_DEV_ATTRIB(emulate_tpws); | 637 | DEF_DEV_ATTRIB(emulate_tpws); |
637 | SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR); | 638 | SE_DEV_ATTR(emulate_tpws, S_IRUGO | S_IWUSR); |
638 | 639 | ||
640 | DEF_DEV_ATTRIB(emulate_caw); | ||
641 | SE_DEV_ATTR(emulate_caw, S_IRUGO | S_IWUSR); | ||
642 | |||
643 | DEF_DEV_ATTRIB(emulate_3pc); | ||
644 | SE_DEV_ATTR(emulate_3pc, S_IRUGO | S_IWUSR); | ||
645 | |||
639 | DEF_DEV_ATTRIB(enforce_pr_isids); | 646 | DEF_DEV_ATTRIB(enforce_pr_isids); |
640 | SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR); | 647 | SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR); |
641 | 648 | ||
@@ -693,6 +700,8 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = { | |||
693 | &target_core_dev_attrib_emulate_tas.attr, | 700 | &target_core_dev_attrib_emulate_tas.attr, |
694 | &target_core_dev_attrib_emulate_tpu.attr, | 701 | &target_core_dev_attrib_emulate_tpu.attr, |
695 | &target_core_dev_attrib_emulate_tpws.attr, | 702 | &target_core_dev_attrib_emulate_tpws.attr, |
703 | &target_core_dev_attrib_emulate_caw.attr, | ||
704 | &target_core_dev_attrib_emulate_3pc.attr, | ||
696 | &target_core_dev_attrib_enforce_pr_isids.attr, | 705 | &target_core_dev_attrib_enforce_pr_isids.attr, |
697 | &target_core_dev_attrib_is_nonrot.attr, | 706 | &target_core_dev_attrib_is_nonrot.attr, |
698 | &target_core_dev_attrib_emulate_rest_reord.attr, | 707 | &target_core_dev_attrib_emulate_rest_reord.attr, |
@@ -1310,9 +1319,9 @@ static ssize_t target_core_dev_pr_store_attr_res_aptpl_metadata( | |||
1310 | ret = -ENOMEM; | 1319 | ret = -ENOMEM; |
1311 | goto out; | 1320 | goto out; |
1312 | } | 1321 | } |
1313 | ret = strict_strtoull(arg_p, 0, &tmp_ll); | 1322 | ret = kstrtoull(arg_p, 0, &tmp_ll); |
1314 | if (ret < 0) { | 1323 | if (ret < 0) { |
1315 | pr_err("strict_strtoull() failed for" | 1324 | pr_err("kstrtoull() failed for" |
1316 | " sa_res_key=\n"); | 1325 | " sa_res_key=\n"); |
1317 | goto out; | 1326 | goto out; |
1318 | } | 1327 | } |
@@ -1836,11 +1845,11 @@ static ssize_t target_core_alua_lu_gp_store_attr_lu_gp_id( | |||
1836 | unsigned long lu_gp_id; | 1845 | unsigned long lu_gp_id; |
1837 | int ret; | 1846 | int ret; |
1838 | 1847 | ||
1839 | ret = strict_strtoul(page, 0, &lu_gp_id); | 1848 | ret = kstrtoul(page, 0, &lu_gp_id); |
1840 | if (ret < 0) { | 1849 | if (ret < 0) { |
1841 | pr_err("strict_strtoul() returned %d for" | 1850 | pr_err("kstrtoul() returned %d for" |
1842 | " lu_gp_id\n", ret); | 1851 | " lu_gp_id\n", ret); |
1843 | return -EINVAL; | 1852 | return ret; |
1844 | } | 1853 | } |
1845 | if (lu_gp_id > 0x0000ffff) { | 1854 | if (lu_gp_id > 0x0000ffff) { |
1846 | pr_err("ALUA lu_gp_id: %lu exceeds maximum:" | 1855 | pr_err("ALUA lu_gp_id: %lu exceeds maximum:" |
@@ -2032,11 +2041,11 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state( | |||
2032 | return -EINVAL; | 2041 | return -EINVAL; |
2033 | } | 2042 | } |
2034 | 2043 | ||
2035 | ret = strict_strtoul(page, 0, &tmp); | 2044 | ret = kstrtoul(page, 0, &tmp); |
2036 | if (ret < 0) { | 2045 | if (ret < 0) { |
2037 | pr_err("Unable to extract new ALUA access state from" | 2046 | pr_err("Unable to extract new ALUA access state from" |
2038 | " %s\n", page); | 2047 | " %s\n", page); |
2039 | return -EINVAL; | 2048 | return ret; |
2040 | } | 2049 | } |
2041 | new_state = (int)tmp; | 2050 | new_state = (int)tmp; |
2042 | 2051 | ||
@@ -2079,11 +2088,11 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_status( | |||
2079 | return -EINVAL; | 2088 | return -EINVAL; |
2080 | } | 2089 | } |
2081 | 2090 | ||
2082 | ret = strict_strtoul(page, 0, &tmp); | 2091 | ret = kstrtoul(page, 0, &tmp); |
2083 | if (ret < 0) { | 2092 | if (ret < 0) { |
2084 | pr_err("Unable to extract new ALUA access status" | 2093 | pr_err("Unable to extract new ALUA access status" |
2085 | " from %s\n", page); | 2094 | " from %s\n", page); |
2086 | return -EINVAL; | 2095 | return ret; |
2087 | } | 2096 | } |
2088 | new_status = (int)tmp; | 2097 | new_status = (int)tmp; |
2089 | 2098 | ||
@@ -2139,10 +2148,10 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_write_metadata( | |||
2139 | unsigned long tmp; | 2148 | unsigned long tmp; |
2140 | int ret; | 2149 | int ret; |
2141 | 2150 | ||
2142 | ret = strict_strtoul(page, 0, &tmp); | 2151 | ret = kstrtoul(page, 0, &tmp); |
2143 | if (ret < 0) { | 2152 | if (ret < 0) { |
2144 | pr_err("Unable to extract alua_write_metadata\n"); | 2153 | pr_err("Unable to extract alua_write_metadata\n"); |
2145 | return -EINVAL; | 2154 | return ret; |
2146 | } | 2155 | } |
2147 | 2156 | ||
2148 | if ((tmp != 0) && (tmp != 1)) { | 2157 | if ((tmp != 0) && (tmp != 1)) { |
@@ -2263,11 +2272,11 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_tg_pt_gp_id( | |||
2263 | unsigned long tg_pt_gp_id; | 2272 | unsigned long tg_pt_gp_id; |
2264 | int ret; | 2273 | int ret; |
2265 | 2274 | ||
2266 | ret = strict_strtoul(page, 0, &tg_pt_gp_id); | 2275 | ret = kstrtoul(page, 0, &tg_pt_gp_id); |
2267 | if (ret < 0) { | 2276 | if (ret < 0) { |
2268 | pr_err("strict_strtoul() returned %d for" | 2277 | pr_err("kstrtoul() returned %d for" |
2269 | " tg_pt_gp_id\n", ret); | 2278 | " tg_pt_gp_id\n", ret); |
2270 | return -EINVAL; | 2279 | return ret; |
2271 | } | 2280 | } |
2272 | if (tg_pt_gp_id > 0x0000ffff) { | 2281 | if (tg_pt_gp_id > 0x0000ffff) { |
2273 | pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum:" | 2282 | pr_err("ALUA tg_pt_gp_id: %lu exceeds maximum:" |
@@ -2676,10 +2685,10 @@ static ssize_t target_core_hba_store_attr_hba_mode(struct se_hba *hba, | |||
2676 | if (transport->pmode_enable_hba == NULL) | 2685 | if (transport->pmode_enable_hba == NULL) |
2677 | return -EINVAL; | 2686 | return -EINVAL; |
2678 | 2687 | ||
2679 | ret = strict_strtoul(page, 0, &mode_flag); | 2688 | ret = kstrtoul(page, 0, &mode_flag); |
2680 | if (ret < 0) { | 2689 | if (ret < 0) { |
2681 | pr_err("Unable to extract hba mode flag: %d\n", ret); | 2690 | pr_err("Unable to extract hba mode flag: %d\n", ret); |
2682 | return -EINVAL; | 2691 | return ret; |
2683 | } | 2692 | } |
2684 | 2693 | ||
2685 | if (hba->dev_count) { | 2694 | if (hba->dev_count) { |
@@ -2767,11 +2776,11 @@ static struct config_group *target_core_call_addhbatotarget( | |||
2767 | str++; /* Skip to start of plugin dependent ID */ | 2776 | str++; /* Skip to start of plugin dependent ID */ |
2768 | } | 2777 | } |
2769 | 2778 | ||
2770 | ret = strict_strtoul(str, 0, &plugin_dep_id); | 2779 | ret = kstrtoul(str, 0, &plugin_dep_id); |
2771 | if (ret < 0) { | 2780 | if (ret < 0) { |
2772 | pr_err("strict_strtoul() returned %d for" | 2781 | pr_err("kstrtoul() returned %d for" |
2773 | " plugin_dep_id\n", ret); | 2782 | " plugin_dep_id\n", ret); |
2774 | return ERR_PTR(-EINVAL); | 2783 | return ERR_PTR(ret); |
2775 | } | 2784 | } |
2776 | /* | 2785 | /* |
2777 | * Load up TCM subsystem plugins if they have not already been loaded. | 2786 | * Load up TCM subsystem plugins if they have not already been loaded. |
@@ -2927,6 +2936,10 @@ static int __init target_core_init_configfs(void) | |||
2927 | if (ret < 0) | 2936 | if (ret < 0) |
2928 | goto out; | 2937 | goto out; |
2929 | 2938 | ||
2939 | ret = target_xcopy_setup_pt(); | ||
2940 | if (ret < 0) | ||
2941 | goto out; | ||
2942 | |||
2930 | return 0; | 2943 | return 0; |
2931 | 2944 | ||
2932 | out: | 2945 | out: |
@@ -2999,6 +3012,7 @@ static void __exit target_core_exit_configfs(void) | |||
2999 | 3012 | ||
3000 | core_dev_release_virtual_lun0(); | 3013 | core_dev_release_virtual_lun0(); |
3001 | rd_module_exit(); | 3014 | rd_module_exit(); |
3015 | target_xcopy_release_pt(); | ||
3002 | release_se_kmem_caches(); | 3016 | release_se_kmem_caches(); |
3003 | } | 3017 | } |
3004 | 3018 | ||
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 8f4142fe5f19..d90dbb0f1a69 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This file contains the TCM Virtual Device and Disk Transport | 4 | * This file contains the TCM Virtual Device and Disk Transport |
5 | * agnostic related functions. | 5 | * agnostic related functions. |
6 | * | 6 | * |
7 | * (c) Copyright 2003-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2003-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
@@ -47,6 +47,9 @@ | |||
47 | #include "target_core_pr.h" | 47 | #include "target_core_pr.h" |
48 | #include "target_core_ua.h" | 48 | #include "target_core_ua.h" |
49 | 49 | ||
50 | DEFINE_MUTEX(g_device_mutex); | ||
51 | LIST_HEAD(g_device_list); | ||
52 | |||
50 | static struct se_hba *lun0_hba; | 53 | static struct se_hba *lun0_hba; |
51 | /* not static, needed by tpg.c */ | 54 | /* not static, needed by tpg.c */ |
52 | struct se_device *g_lun0_dev; | 55 | struct se_device *g_lun0_dev; |
@@ -890,6 +893,32 @@ int se_dev_set_emulate_tpws(struct se_device *dev, int flag) | |||
890 | return 0; | 893 | return 0; |
891 | } | 894 | } |
892 | 895 | ||
896 | int se_dev_set_emulate_caw(struct se_device *dev, int flag) | ||
897 | { | ||
898 | if (flag != 0 && flag != 1) { | ||
899 | pr_err("Illegal value %d\n", flag); | ||
900 | return -EINVAL; | ||
901 | } | ||
902 | dev->dev_attrib.emulate_caw = flag; | ||
903 | pr_debug("dev[%p]: SE Device CompareAndWrite (AtomicTestandSet): %d\n", | ||
904 | dev, flag); | ||
905 | |||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | int se_dev_set_emulate_3pc(struct se_device *dev, int flag) | ||
910 | { | ||
911 | if (flag != 0 && flag != 1) { | ||
912 | pr_err("Illegal value %d\n", flag); | ||
913 | return -EINVAL; | ||
914 | } | ||
915 | dev->dev_attrib.emulate_3pc = flag; | ||
916 | pr_debug("dev[%p]: SE Device 3rd Party Copy (EXTENDED_COPY): %d\n", | ||
917 | dev, flag); | ||
918 | |||
919 | return 0; | ||
920 | } | ||
921 | |||
893 | int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag) | 922 | int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag) |
894 | { | 923 | { |
895 | if ((flag != 0) && (flag != 1)) { | 924 | if ((flag != 0) && (flag != 1)) { |
@@ -1393,6 +1422,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | |||
1393 | INIT_LIST_HEAD(&dev->delayed_cmd_list); | 1422 | INIT_LIST_HEAD(&dev->delayed_cmd_list); |
1394 | INIT_LIST_HEAD(&dev->state_list); | 1423 | INIT_LIST_HEAD(&dev->state_list); |
1395 | INIT_LIST_HEAD(&dev->qf_cmd_list); | 1424 | INIT_LIST_HEAD(&dev->qf_cmd_list); |
1425 | INIT_LIST_HEAD(&dev->g_dev_node); | ||
1396 | spin_lock_init(&dev->stats_lock); | 1426 | spin_lock_init(&dev->stats_lock); |
1397 | spin_lock_init(&dev->execute_task_lock); | 1427 | spin_lock_init(&dev->execute_task_lock); |
1398 | spin_lock_init(&dev->delayed_cmd_lock); | 1428 | spin_lock_init(&dev->delayed_cmd_lock); |
@@ -1400,6 +1430,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | |||
1400 | spin_lock_init(&dev->se_port_lock); | 1430 | spin_lock_init(&dev->se_port_lock); |
1401 | spin_lock_init(&dev->se_tmr_lock); | 1431 | spin_lock_init(&dev->se_tmr_lock); |
1402 | spin_lock_init(&dev->qf_cmd_lock); | 1432 | spin_lock_init(&dev->qf_cmd_lock); |
1433 | sema_init(&dev->caw_sem, 1); | ||
1403 | atomic_set(&dev->dev_ordered_id, 0); | 1434 | atomic_set(&dev->dev_ordered_id, 0); |
1404 | INIT_LIST_HEAD(&dev->t10_wwn.t10_vpd_list); | 1435 | INIT_LIST_HEAD(&dev->t10_wwn.t10_vpd_list); |
1405 | spin_lock_init(&dev->t10_wwn.t10_vpd_lock); | 1436 | spin_lock_init(&dev->t10_wwn.t10_vpd_lock); |
@@ -1423,6 +1454,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name) | |||
1423 | dev->dev_attrib.emulate_tas = DA_EMULATE_TAS; | 1454 | dev->dev_attrib.emulate_tas = DA_EMULATE_TAS; |
1424 | dev->dev_attrib.emulate_tpu = DA_EMULATE_TPU; | 1455 | dev->dev_attrib.emulate_tpu = DA_EMULATE_TPU; |
1425 | dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS; | 1456 | dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS; |
1457 | dev->dev_attrib.emulate_caw = DA_EMULATE_CAW; | ||
1458 | dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC; | ||
1426 | dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; | 1459 | dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS; |
1427 | dev->dev_attrib.is_nonrot = DA_IS_NONROT; | 1460 | dev->dev_attrib.is_nonrot = DA_IS_NONROT; |
1428 | dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; | 1461 | dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD; |
@@ -1510,6 +1543,11 @@ int target_configure_device(struct se_device *dev) | |||
1510 | spin_lock(&hba->device_lock); | 1543 | spin_lock(&hba->device_lock); |
1511 | hba->dev_count++; | 1544 | hba->dev_count++; |
1512 | spin_unlock(&hba->device_lock); | 1545 | spin_unlock(&hba->device_lock); |
1546 | |||
1547 | mutex_lock(&g_device_mutex); | ||
1548 | list_add_tail(&dev->g_dev_node, &g_device_list); | ||
1549 | mutex_unlock(&g_device_mutex); | ||
1550 | |||
1513 | return 0; | 1551 | return 0; |
1514 | 1552 | ||
1515 | out_free_alua: | 1553 | out_free_alua: |
@@ -1528,6 +1566,10 @@ void target_free_device(struct se_device *dev) | |||
1528 | if (dev->dev_flags & DF_CONFIGURED) { | 1566 | if (dev->dev_flags & DF_CONFIGURED) { |
1529 | destroy_workqueue(dev->tmr_wq); | 1567 | destroy_workqueue(dev->tmr_wq); |
1530 | 1568 | ||
1569 | mutex_lock(&g_device_mutex); | ||
1570 | list_del(&dev->g_dev_node); | ||
1571 | mutex_unlock(&g_device_mutex); | ||
1572 | |||
1531 | spin_lock(&hba->device_lock); | 1573 | spin_lock(&hba->device_lock); |
1532 | hba->dev_count--; | 1574 | hba->dev_count--; |
1533 | spin_unlock(&hba->device_lock); | 1575 | spin_unlock(&hba->device_lock); |
diff --git a/drivers/target/target_core_fabric_configfs.c b/drivers/target/target_core_fabric_configfs.c index eb56eb129563..3503996d7d10 100644 --- a/drivers/target/target_core_fabric_configfs.c +++ b/drivers/target/target_core_fabric_configfs.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This file contains generic fabric module configfs infrastructure for | 4 | * This file contains generic fabric module configfs infrastructure for |
5 | * TCM v4.x code | 5 | * TCM v4.x code |
6 | * | 6 | * |
7 | * (c) Copyright 2010-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2010-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> | 9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 10 | * |
@@ -189,9 +189,11 @@ static ssize_t target_fabric_mappedlun_store_write_protect( | |||
189 | struct se_node_acl *se_nacl = lacl->se_lun_nacl; | 189 | struct se_node_acl *se_nacl = lacl->se_lun_nacl; |
190 | struct se_portal_group *se_tpg = se_nacl->se_tpg; | 190 | struct se_portal_group *se_tpg = se_nacl->se_tpg; |
191 | unsigned long op; | 191 | unsigned long op; |
192 | int ret; | ||
192 | 193 | ||
193 | if (strict_strtoul(page, 0, &op)) | 194 | ret = kstrtoul(page, 0, &op); |
194 | return -EINVAL; | 195 | if (ret) |
196 | return ret; | ||
195 | 197 | ||
196 | if ((op != 1) && (op != 0)) | 198 | if ((op != 1) && (op != 0)) |
197 | return -EINVAL; | 199 | return -EINVAL; |
@@ -350,7 +352,10 @@ static struct config_group *target_fabric_make_mappedlun( | |||
350 | * Determine the Mapped LUN value. This is what the SCSI Initiator | 352 | * Determine the Mapped LUN value. This is what the SCSI Initiator |
351 | * Port will actually see. | 353 | * Port will actually see. |
352 | */ | 354 | */ |
353 | if (strict_strtoul(buf + 4, 0, &mapped_lun) || mapped_lun > UINT_MAX) { | 355 | ret = kstrtoul(buf + 4, 0, &mapped_lun); |
356 | if (ret) | ||
357 | goto out; | ||
358 | if (mapped_lun > UINT_MAX) { | ||
354 | ret = -EINVAL; | 359 | ret = -EINVAL; |
355 | goto out; | 360 | goto out; |
356 | } | 361 | } |
@@ -875,7 +880,10 @@ static struct config_group *target_fabric_make_lun( | |||
875 | " \"lun_$LUN_NUMBER\"\n"); | 880 | " \"lun_$LUN_NUMBER\"\n"); |
876 | return ERR_PTR(-EINVAL); | 881 | return ERR_PTR(-EINVAL); |
877 | } | 882 | } |
878 | if (strict_strtoul(name + 4, 0, &unpacked_lun) || unpacked_lun > UINT_MAX) | 883 | errno = kstrtoul(name + 4, 0, &unpacked_lun); |
884 | if (errno) | ||
885 | return ERR_PTR(errno); | ||
886 | if (unpacked_lun > UINT_MAX) | ||
879 | return ERR_PTR(-EINVAL); | 887 | return ERR_PTR(-EINVAL); |
880 | 888 | ||
881 | lun = core_get_lun_from_tpg(se_tpg, unpacked_lun); | 889 | lun = core_get_lun_from_tpg(se_tpg, unpacked_lun); |
diff --git a/drivers/target/target_core_fabric_lib.c b/drivers/target/target_core_fabric_lib.c index 687b0b0a4aa6..0d1cf8b4f49f 100644 --- a/drivers/target/target_core_fabric_lib.c +++ b/drivers/target/target_core_fabric_lib.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This file contains generic high level protocol identifier and PR | 4 | * This file contains generic high level protocol identifier and PR |
5 | * handlers for TCM fabric modules | 5 | * handlers for TCM fabric modules |
6 | * | 6 | * |
7 | * (c) Copyright 2010-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2010-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> | 9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 10 | * |
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index b11890d85120..b662f89dedac 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains the Storage Engine <-> FILEIO transport specific functions | 4 | * This file contains the Storage Engine <-> FILEIO transport specific functions |
5 | * | 5 | * |
6 | * (c) Copyright 2005-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2005-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
@@ -547,11 +547,9 @@ fd_execute_unmap(struct se_cmd *cmd) | |||
547 | } | 547 | } |
548 | 548 | ||
549 | static sense_reason_t | 549 | static sense_reason_t |
550 | fd_execute_rw(struct se_cmd *cmd) | 550 | fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, |
551 | enum dma_data_direction data_direction) | ||
551 | { | 552 | { |
552 | struct scatterlist *sgl = cmd->t_data_sg; | ||
553 | u32 sgl_nents = cmd->t_data_nents; | ||
554 | enum dma_data_direction data_direction = cmd->data_direction; | ||
555 | struct se_device *dev = cmd->se_dev; | 553 | struct se_device *dev = cmd->se_dev; |
556 | int ret = 0; | 554 | int ret = 0; |
557 | 555 | ||
@@ -635,10 +633,10 @@ static ssize_t fd_set_configfs_dev_params(struct se_device *dev, | |||
635 | ret = -ENOMEM; | 633 | ret = -ENOMEM; |
636 | break; | 634 | break; |
637 | } | 635 | } |
638 | ret = strict_strtoull(arg_p, 0, &fd_dev->fd_dev_size); | 636 | ret = kstrtoull(arg_p, 0, &fd_dev->fd_dev_size); |
639 | kfree(arg_p); | 637 | kfree(arg_p); |
640 | if (ret < 0) { | 638 | if (ret < 0) { |
641 | pr_err("strict_strtoull() failed for" | 639 | pr_err("kstrtoull() failed for" |
642 | " fd_dev_size=\n"); | 640 | " fd_dev_size=\n"); |
643 | goto out; | 641 | goto out; |
644 | } | 642 | } |
diff --git a/drivers/target/target_core_hba.c b/drivers/target/target_core_hba.c index d2616cd48f1e..a25051a37dd7 100644 --- a/drivers/target/target_core_hba.c +++ b/drivers/target/target_core_hba.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains the TCM HBA Transport related functions. | 4 | * This file contains the TCM HBA Transport related functions. |
5 | * | 5 | * |
6 | * (c) Copyright 2003-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2003-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index aa1620abec6d..b9a3394fe479 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This file contains the Storage Engine <-> Linux BlockIO transport | 4 | * This file contains the Storage Engine <-> Linux BlockIO transport |
5 | * specific functions. | 5 | * specific functions. |
6 | * | 6 | * |
7 | * (c) Copyright 2003-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2003-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
@@ -536,10 +536,10 @@ static ssize_t iblock_set_configfs_dev_params(struct se_device *dev, | |||
536 | ret = -ENOMEM; | 536 | ret = -ENOMEM; |
537 | break; | 537 | break; |
538 | } | 538 | } |
539 | ret = strict_strtoul(arg_p, 0, &tmp_readonly); | 539 | ret = kstrtoul(arg_p, 0, &tmp_readonly); |
540 | kfree(arg_p); | 540 | kfree(arg_p); |
541 | if (ret < 0) { | 541 | if (ret < 0) { |
542 | pr_err("strict_strtoul() failed for" | 542 | pr_err("kstrtoul() failed for" |
543 | " readonly=\n"); | 543 | " readonly=\n"); |
544 | goto out; | 544 | goto out; |
545 | } | 545 | } |
@@ -587,11 +587,9 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b) | |||
587 | } | 587 | } |
588 | 588 | ||
589 | static sense_reason_t | 589 | static sense_reason_t |
590 | iblock_execute_rw(struct se_cmd *cmd) | 590 | iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, |
591 | enum dma_data_direction data_direction) | ||
591 | { | 592 | { |
592 | struct scatterlist *sgl = cmd->t_data_sg; | ||
593 | u32 sgl_nents = cmd->t_data_nents; | ||
594 | enum dma_data_direction data_direction = cmd->data_direction; | ||
595 | struct se_device *dev = cmd->se_dev; | 593 | struct se_device *dev = cmd->se_dev; |
596 | struct iblock_req *ibr; | 594 | struct iblock_req *ibr; |
597 | struct bio *bio; | 595 | struct bio *bio; |
diff --git a/drivers/target/target_core_internal.h b/drivers/target/target_core_internal.h index 18d49df4d0ac..579128abe3f5 100644 --- a/drivers/target/target_core_internal.h +++ b/drivers/target/target_core_internal.h | |||
@@ -33,6 +33,8 @@ int se_dev_set_emulate_ua_intlck_ctrl(struct se_device *, int); | |||
33 | int se_dev_set_emulate_tas(struct se_device *, int); | 33 | int se_dev_set_emulate_tas(struct se_device *, int); |
34 | int se_dev_set_emulate_tpu(struct se_device *, int); | 34 | int se_dev_set_emulate_tpu(struct se_device *, int); |
35 | int se_dev_set_emulate_tpws(struct se_device *, int); | 35 | int se_dev_set_emulate_tpws(struct se_device *, int); |
36 | int se_dev_set_emulate_caw(struct se_device *, int); | ||
37 | int se_dev_set_emulate_3pc(struct se_device *, int); | ||
36 | int se_dev_set_enforce_pr_isids(struct se_device *, int); | 38 | int se_dev_set_enforce_pr_isids(struct se_device *, int); |
37 | int se_dev_set_is_nonrot(struct se_device *, int); | 39 | int se_dev_set_is_nonrot(struct se_device *, int); |
38 | int se_dev_set_emulate_rest_reord(struct se_device *dev, int); | 40 | int se_dev_set_emulate_rest_reord(struct se_device *dev, int); |
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c index bd78faf67c6b..d1ae4c5c3ffd 100644 --- a/drivers/target/target_core_pr.c +++ b/drivers/target/target_core_pr.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This file contains SPC-3 compliant persistent reservations and | 4 | * This file contains SPC-3 compliant persistent reservations and |
5 | * legacy SPC-2 reservations with compatible reservation handling (CRH=1) | 5 | * legacy SPC-2 reservations with compatible reservation handling (CRH=1) |
6 | * | 6 | * |
7 | * (c) Copyright 2009-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2009-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
@@ -1949,7 +1949,7 @@ static int __core_scsi3_write_aptpl_to_file( | |||
1949 | pr_debug("Error writing APTPL metadata file: %s\n", path); | 1949 | pr_debug("Error writing APTPL metadata file: %s\n", path); |
1950 | fput(file); | 1950 | fput(file); |
1951 | 1951 | ||
1952 | return ret ? -EIO : 0; | 1952 | return (ret < 0) ? -EIO : 0; |
1953 | } | 1953 | } |
1954 | 1954 | ||
1955 | /* | 1955 | /* |
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index e992b27aa090..551c96ca60ac 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains the generic target mode <-> Linux SCSI subsystem plugin. | 4 | * This file contains the generic target mode <-> Linux SCSI subsystem plugin. |
5 | * | 5 | * |
6 | * (c) Copyright 2003-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2003-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
@@ -1050,9 +1050,8 @@ pscsi_execute_cmd(struct se_cmd *cmd) | |||
1050 | req = blk_get_request(pdv->pdv_sd->request_queue, | 1050 | req = blk_get_request(pdv->pdv_sd->request_queue, |
1051 | (data_direction == DMA_TO_DEVICE), | 1051 | (data_direction == DMA_TO_DEVICE), |
1052 | GFP_KERNEL); | 1052 | GFP_KERNEL); |
1053 | if (!req || IS_ERR(req)) { | 1053 | if (!req) { |
1054 | pr_err("PSCSI: blk_get_request() failed: %ld\n", | 1054 | pr_err("PSCSI: blk_get_request() failed\n"); |
1055 | req ? IS_ERR(req) : -ENOMEM); | ||
1056 | ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 1055 | ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
1057 | goto fail; | 1056 | goto fail; |
1058 | } | 1057 | } |
diff --git a/drivers/target/target_core_rd.c b/drivers/target/target_core_rd.c index 51127d15d5c5..131327ac7f5b 100644 --- a/drivers/target/target_core_rd.c +++ b/drivers/target/target_core_rd.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * This file contains the Storage Engine <-> Ramdisk transport | 4 | * This file contains the Storage Engine <-> Ramdisk transport |
5 | * specific functions. | 5 | * specific functions. |
6 | * | 6 | * |
7 | * (c) Copyright 2003-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2003-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@kernel.org> | 9 | * Nicholas A. Bellinger <nab@kernel.org> |
10 | * | 10 | * |
@@ -280,11 +280,9 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page) | |||
280 | } | 280 | } |
281 | 281 | ||
282 | static sense_reason_t | 282 | static sense_reason_t |
283 | rd_execute_rw(struct se_cmd *cmd) | 283 | rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents, |
284 | enum dma_data_direction data_direction) | ||
284 | { | 285 | { |
285 | struct scatterlist *sgl = cmd->t_data_sg; | ||
286 | u32 sgl_nents = cmd->t_data_nents; | ||
287 | enum dma_data_direction data_direction = cmd->data_direction; | ||
288 | struct se_device *se_dev = cmd->se_dev; | 286 | struct se_device *se_dev = cmd->se_dev; |
289 | struct rd_dev *dev = RD_DEV(se_dev); | 287 | struct rd_dev *dev = RD_DEV(se_dev); |
290 | struct rd_dev_sg_table *table; | 288 | struct rd_dev_sg_table *table; |
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 8a462773d0c8..6c17295e8d7c 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SCSI Block Commands (SBC) parsing and emulation. | 2 | * SCSI Block Commands (SBC) parsing and emulation. |
3 | * | 3 | * |
4 | * (c) Copyright 2002-2012 RisingTide Systems LLC. | 4 | * (c) Copyright 2002-2013 Datera, Inc. |
5 | * | 5 | * |
6 | * Nicholas A. Bellinger <nab@kernel.org> | 6 | * Nicholas A. Bellinger <nab@kernel.org> |
7 | * | 7 | * |
@@ -25,6 +25,7 @@ | |||
25 | #include <linux/ratelimit.h> | 25 | #include <linux/ratelimit.h> |
26 | #include <asm/unaligned.h> | 26 | #include <asm/unaligned.h> |
27 | #include <scsi/scsi.h> | 27 | #include <scsi/scsi.h> |
28 | #include <scsi/scsi_tcq.h> | ||
28 | 29 | ||
29 | #include <target/target_core_base.h> | 30 | #include <target/target_core_base.h> |
30 | #include <target/target_core_backend.h> | 31 | #include <target/target_core_backend.h> |
@@ -280,13 +281,13 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o | |||
280 | return 0; | 281 | return 0; |
281 | } | 282 | } |
282 | 283 | ||
283 | static void xdreadwrite_callback(struct se_cmd *cmd) | 284 | static sense_reason_t xdreadwrite_callback(struct se_cmd *cmd) |
284 | { | 285 | { |
285 | unsigned char *buf, *addr; | 286 | unsigned char *buf, *addr; |
286 | struct scatterlist *sg; | 287 | struct scatterlist *sg; |
287 | unsigned int offset; | 288 | unsigned int offset; |
288 | int i; | 289 | sense_reason_t ret = TCM_NO_SENSE; |
289 | int count; | 290 | int i, count; |
290 | /* | 291 | /* |
291 | * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command | 292 | * From sbc3r22.pdf section 5.48 XDWRITEREAD (10) command |
292 | * | 293 | * |
@@ -301,7 +302,7 @@ static void xdreadwrite_callback(struct se_cmd *cmd) | |||
301 | buf = kmalloc(cmd->data_length, GFP_KERNEL); | 302 | buf = kmalloc(cmd->data_length, GFP_KERNEL); |
302 | if (!buf) { | 303 | if (!buf) { |
303 | pr_err("Unable to allocate xor_callback buf\n"); | 304 | pr_err("Unable to allocate xor_callback buf\n"); |
304 | return; | 305 | return TCM_OUT_OF_RESOURCES; |
305 | } | 306 | } |
306 | /* | 307 | /* |
307 | * Copy the scatterlist WRITE buffer located at cmd->t_data_sg | 308 | * Copy the scatterlist WRITE buffer located at cmd->t_data_sg |
@@ -320,8 +321,10 @@ static void xdreadwrite_callback(struct se_cmd *cmd) | |||
320 | offset = 0; | 321 | offset = 0; |
321 | for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { | 322 | for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, count) { |
322 | addr = kmap_atomic(sg_page(sg)); | 323 | addr = kmap_atomic(sg_page(sg)); |
323 | if (!addr) | 324 | if (!addr) { |
325 | ret = TCM_OUT_OF_RESOURCES; | ||
324 | goto out; | 326 | goto out; |
327 | } | ||
325 | 328 | ||
326 | for (i = 0; i < sg->length; i++) | 329 | for (i = 0; i < sg->length; i++) |
327 | *(addr + sg->offset + i) ^= *(buf + offset + i); | 330 | *(addr + sg->offset + i) ^= *(buf + offset + i); |
@@ -332,6 +335,193 @@ static void xdreadwrite_callback(struct se_cmd *cmd) | |||
332 | 335 | ||
333 | out: | 336 | out: |
334 | kfree(buf); | 337 | kfree(buf); |
338 | return ret; | ||
339 | } | ||
340 | |||
341 | static sense_reason_t | ||
342 | sbc_execute_rw(struct se_cmd *cmd) | ||
343 | { | ||
344 | return cmd->execute_rw(cmd, cmd->t_data_sg, cmd->t_data_nents, | ||
345 | cmd->data_direction); | ||
346 | } | ||
347 | |||
348 | static sense_reason_t compare_and_write_post(struct se_cmd *cmd) | ||
349 | { | ||
350 | struct se_device *dev = cmd->se_dev; | ||
351 | |||
352 | cmd->se_cmd_flags |= SCF_COMPARE_AND_WRITE_POST; | ||
353 | /* | ||
354 | * Unlock ->caw_sem originally obtained during sbc_compare_and_write() | ||
355 | * before the original READ I/O submission. | ||
356 | */ | ||
357 | up(&dev->caw_sem); | ||
358 | |||
359 | return TCM_NO_SENSE; | ||
360 | } | ||
361 | |||
362 | static sense_reason_t compare_and_write_callback(struct se_cmd *cmd) | ||
363 | { | ||
364 | struct se_device *dev = cmd->se_dev; | ||
365 | struct scatterlist *write_sg = NULL, *sg; | ||
366 | unsigned char *buf, *addr; | ||
367 | struct sg_mapping_iter m; | ||
368 | unsigned int offset = 0, len; | ||
369 | unsigned int nlbas = cmd->t_task_nolb; | ||
370 | unsigned int block_size = dev->dev_attrib.block_size; | ||
371 | unsigned int compare_len = (nlbas * block_size); | ||
372 | sense_reason_t ret = TCM_NO_SENSE; | ||
373 | int rc, i; | ||
374 | |||
375 | /* | ||
376 | * Handle early failure in transport_generic_request_failure(), | ||
377 | * which will not have taken ->caw_mutex yet.. | ||
378 | */ | ||
379 | if (!cmd->t_data_sg || !cmd->t_bidi_data_sg) | ||
380 | return TCM_NO_SENSE; | ||
381 | |||
382 | buf = kzalloc(cmd->data_length, GFP_KERNEL); | ||
383 | if (!buf) { | ||
384 | pr_err("Unable to allocate compare_and_write buf\n"); | ||
385 | ret = TCM_OUT_OF_RESOURCES; | ||
386 | goto out; | ||
387 | } | ||
388 | |||
389 | write_sg = kzalloc(sizeof(struct scatterlist) * cmd->t_data_nents, | ||
390 | GFP_KERNEL); | ||
391 | if (!write_sg) { | ||
392 | pr_err("Unable to allocate compare_and_write sg\n"); | ||
393 | ret = TCM_OUT_OF_RESOURCES; | ||
394 | goto out; | ||
395 | } | ||
396 | /* | ||
397 | * Setup verify and write data payloads from total NumberLBAs. | ||
398 | */ | ||
399 | rc = sg_copy_to_buffer(cmd->t_data_sg, cmd->t_data_nents, buf, | ||
400 | cmd->data_length); | ||
401 | if (!rc) { | ||
402 | pr_err("sg_copy_to_buffer() failed for compare_and_write\n"); | ||
403 | ret = TCM_OUT_OF_RESOURCES; | ||
404 | goto out; | ||
405 | } | ||
406 | /* | ||
407 | * Compare against SCSI READ payload against verify payload | ||
408 | */ | ||
409 | for_each_sg(cmd->t_bidi_data_sg, sg, cmd->t_bidi_data_nents, i) { | ||
410 | addr = (unsigned char *)kmap_atomic(sg_page(sg)); | ||
411 | if (!addr) { | ||
412 | ret = TCM_OUT_OF_RESOURCES; | ||
413 | goto out; | ||
414 | } | ||
415 | |||
416 | len = min(sg->length, compare_len); | ||
417 | |||
418 | if (memcmp(addr, buf + offset, len)) { | ||
419 | pr_warn("Detected MISCOMPARE for addr: %p buf: %p\n", | ||
420 | addr, buf + offset); | ||
421 | kunmap_atomic(addr); | ||
422 | goto miscompare; | ||
423 | } | ||
424 | kunmap_atomic(addr); | ||
425 | |||
426 | offset += len; | ||
427 | compare_len -= len; | ||
428 | if (!compare_len) | ||
429 | break; | ||
430 | } | ||
431 | |||
432 | i = 0; | ||
433 | len = cmd->t_task_nolb * block_size; | ||
434 | sg_miter_start(&m, cmd->t_data_sg, cmd->t_data_nents, SG_MITER_TO_SG); | ||
435 | /* | ||
436 | * Currently assumes NoLB=1 and SGLs are PAGE_SIZE.. | ||
437 | */ | ||
438 | while (len) { | ||
439 | sg_miter_next(&m); | ||
440 | |||
441 | if (block_size < PAGE_SIZE) { | ||
442 | sg_set_page(&write_sg[i], m.page, block_size, | ||
443 | block_size); | ||
444 | } else { | ||
445 | sg_miter_next(&m); | ||
446 | sg_set_page(&write_sg[i], m.page, block_size, | ||
447 | 0); | ||
448 | } | ||
449 | len -= block_size; | ||
450 | i++; | ||
451 | } | ||
452 | sg_miter_stop(&m); | ||
453 | /* | ||
454 | * Save the original SGL + nents values before updating to new | ||
455 | * assignments, to be released in transport_free_pages() -> | ||
456 | * transport_reset_sgl_orig() | ||
457 | */ | ||
458 | cmd->t_data_sg_orig = cmd->t_data_sg; | ||
459 | cmd->t_data_sg = write_sg; | ||
460 | cmd->t_data_nents_orig = cmd->t_data_nents; | ||
461 | cmd->t_data_nents = 1; | ||
462 | |||
463 | cmd->sam_task_attr = MSG_HEAD_TAG; | ||
464 | cmd->transport_complete_callback = compare_and_write_post; | ||
465 | /* | ||
466 | * Now reset ->execute_cmd() to the normal sbc_execute_rw() handler | ||
467 | * for submitting the adjusted SGL to write instance user-data. | ||
468 | */ | ||
469 | cmd->execute_cmd = sbc_execute_rw; | ||
470 | |||
471 | spin_lock_irq(&cmd->t_state_lock); | ||
472 | cmd->t_state = TRANSPORT_PROCESSING; | ||
473 | cmd->transport_state |= CMD_T_ACTIVE|CMD_T_BUSY|CMD_T_SENT; | ||
474 | spin_unlock_irq(&cmd->t_state_lock); | ||
475 | |||
476 | __target_execute_cmd(cmd); | ||
477 | |||
478 | kfree(buf); | ||
479 | return ret; | ||
480 | |||
481 | miscompare: | ||
482 | pr_warn("Target/%s: Send MISCOMPARE check condition and sense\n", | ||
483 | dev->transport->name); | ||
484 | ret = TCM_MISCOMPARE_VERIFY; | ||
485 | out: | ||
486 | /* | ||
487 | * In the MISCOMPARE or failure case, unlock ->caw_sem obtained in | ||
488 | * sbc_compare_and_write() before the original READ I/O submission. | ||
489 | */ | ||
490 | up(&dev->caw_sem); | ||
491 | kfree(write_sg); | ||
492 | kfree(buf); | ||
493 | return ret; | ||
494 | } | ||
495 | |||
496 | static sense_reason_t | ||
497 | sbc_compare_and_write(struct se_cmd *cmd) | ||
498 | { | ||
499 | struct se_device *dev = cmd->se_dev; | ||
500 | sense_reason_t ret; | ||
501 | int rc; | ||
502 | /* | ||
503 | * Submit the READ first for COMPARE_AND_WRITE to perform the | ||
504 | * comparision using SGLs at cmd->t_bidi_data_sg.. | ||
505 | */ | ||
506 | rc = down_interruptible(&dev->caw_sem); | ||
507 | if ((rc != 0) || signal_pending(current)) { | ||
508 | cmd->transport_complete_callback = NULL; | ||
509 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
510 | } | ||
511 | |||
512 | ret = cmd->execute_rw(cmd, cmd->t_bidi_data_sg, cmd->t_bidi_data_nents, | ||
513 | DMA_FROM_DEVICE); | ||
514 | if (ret) { | ||
515 | cmd->transport_complete_callback = NULL; | ||
516 | up(&dev->caw_sem); | ||
517 | return ret; | ||
518 | } | ||
519 | /* | ||
520 | * Unlock of dev->caw_sem to occur in compare_and_write_callback() | ||
521 | * upon MISCOMPARE, or in compare_and_write_done() upon completion | ||
522 | * of WRITE instance user-data. | ||
523 | */ | ||
524 | return TCM_NO_SENSE; | ||
335 | } | 525 | } |
336 | 526 | ||
337 | sense_reason_t | 527 | sense_reason_t |
@@ -348,31 +538,36 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
348 | sectors = transport_get_sectors_6(cdb); | 538 | sectors = transport_get_sectors_6(cdb); |
349 | cmd->t_task_lba = transport_lba_21(cdb); | 539 | cmd->t_task_lba = transport_lba_21(cdb); |
350 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 540 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
351 | cmd->execute_cmd = ops->execute_rw; | 541 | cmd->execute_rw = ops->execute_rw; |
542 | cmd->execute_cmd = sbc_execute_rw; | ||
352 | break; | 543 | break; |
353 | case READ_10: | 544 | case READ_10: |
354 | sectors = transport_get_sectors_10(cdb); | 545 | sectors = transport_get_sectors_10(cdb); |
355 | cmd->t_task_lba = transport_lba_32(cdb); | 546 | cmd->t_task_lba = transport_lba_32(cdb); |
356 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 547 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
357 | cmd->execute_cmd = ops->execute_rw; | 548 | cmd->execute_rw = ops->execute_rw; |
549 | cmd->execute_cmd = sbc_execute_rw; | ||
358 | break; | 550 | break; |
359 | case READ_12: | 551 | case READ_12: |
360 | sectors = transport_get_sectors_12(cdb); | 552 | sectors = transport_get_sectors_12(cdb); |
361 | cmd->t_task_lba = transport_lba_32(cdb); | 553 | cmd->t_task_lba = transport_lba_32(cdb); |
362 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 554 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
363 | cmd->execute_cmd = ops->execute_rw; | 555 | cmd->execute_rw = ops->execute_rw; |
556 | cmd->execute_cmd = sbc_execute_rw; | ||
364 | break; | 557 | break; |
365 | case READ_16: | 558 | case READ_16: |
366 | sectors = transport_get_sectors_16(cdb); | 559 | sectors = transport_get_sectors_16(cdb); |
367 | cmd->t_task_lba = transport_lba_64(cdb); | 560 | cmd->t_task_lba = transport_lba_64(cdb); |
368 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 561 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
369 | cmd->execute_cmd = ops->execute_rw; | 562 | cmd->execute_rw = ops->execute_rw; |
563 | cmd->execute_cmd = sbc_execute_rw; | ||
370 | break; | 564 | break; |
371 | case WRITE_6: | 565 | case WRITE_6: |
372 | sectors = transport_get_sectors_6(cdb); | 566 | sectors = transport_get_sectors_6(cdb); |
373 | cmd->t_task_lba = transport_lba_21(cdb); | 567 | cmd->t_task_lba = transport_lba_21(cdb); |
374 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 568 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
375 | cmd->execute_cmd = ops->execute_rw; | 569 | cmd->execute_rw = ops->execute_rw; |
570 | cmd->execute_cmd = sbc_execute_rw; | ||
376 | break; | 571 | break; |
377 | case WRITE_10: | 572 | case WRITE_10: |
378 | case WRITE_VERIFY: | 573 | case WRITE_VERIFY: |
@@ -381,7 +576,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
381 | if (cdb[1] & 0x8) | 576 | if (cdb[1] & 0x8) |
382 | cmd->se_cmd_flags |= SCF_FUA; | 577 | cmd->se_cmd_flags |= SCF_FUA; |
383 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 578 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
384 | cmd->execute_cmd = ops->execute_rw; | 579 | cmd->execute_rw = ops->execute_rw; |
580 | cmd->execute_cmd = sbc_execute_rw; | ||
385 | break; | 581 | break; |
386 | case WRITE_12: | 582 | case WRITE_12: |
387 | sectors = transport_get_sectors_12(cdb); | 583 | sectors = transport_get_sectors_12(cdb); |
@@ -389,7 +585,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
389 | if (cdb[1] & 0x8) | 585 | if (cdb[1] & 0x8) |
390 | cmd->se_cmd_flags |= SCF_FUA; | 586 | cmd->se_cmd_flags |= SCF_FUA; |
391 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 587 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
392 | cmd->execute_cmd = ops->execute_rw; | 588 | cmd->execute_rw = ops->execute_rw; |
589 | cmd->execute_cmd = sbc_execute_rw; | ||
393 | break; | 590 | break; |
394 | case WRITE_16: | 591 | case WRITE_16: |
395 | sectors = transport_get_sectors_16(cdb); | 592 | sectors = transport_get_sectors_16(cdb); |
@@ -397,7 +594,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
397 | if (cdb[1] & 0x8) | 594 | if (cdb[1] & 0x8) |
398 | cmd->se_cmd_flags |= SCF_FUA; | 595 | cmd->se_cmd_flags |= SCF_FUA; |
399 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | 596 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; |
400 | cmd->execute_cmd = ops->execute_rw; | 597 | cmd->execute_rw = ops->execute_rw; |
598 | cmd->execute_cmd = sbc_execute_rw; | ||
401 | break; | 599 | break; |
402 | case XDWRITEREAD_10: | 600 | case XDWRITEREAD_10: |
403 | if (cmd->data_direction != DMA_TO_DEVICE || | 601 | if (cmd->data_direction != DMA_TO_DEVICE || |
@@ -411,7 +609,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
411 | /* | 609 | /* |
412 | * Setup BIDI XOR callback to be run after I/O completion. | 610 | * Setup BIDI XOR callback to be run after I/O completion. |
413 | */ | 611 | */ |
414 | cmd->execute_cmd = ops->execute_rw; | 612 | cmd->execute_rw = ops->execute_rw; |
613 | cmd->execute_cmd = sbc_execute_rw; | ||
415 | cmd->transport_complete_callback = &xdreadwrite_callback; | 614 | cmd->transport_complete_callback = &xdreadwrite_callback; |
416 | if (cdb[1] & 0x8) | 615 | if (cdb[1] & 0x8) |
417 | cmd->se_cmd_flags |= SCF_FUA; | 616 | cmd->se_cmd_flags |= SCF_FUA; |
@@ -434,7 +633,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
434 | * Setup BIDI XOR callback to be run during after I/O | 633 | * Setup BIDI XOR callback to be run during after I/O |
435 | * completion. | 634 | * completion. |
436 | */ | 635 | */ |
437 | cmd->execute_cmd = ops->execute_rw; | 636 | cmd->execute_rw = ops->execute_rw; |
637 | cmd->execute_cmd = sbc_execute_rw; | ||
438 | cmd->transport_complete_callback = &xdreadwrite_callback; | 638 | cmd->transport_complete_callback = &xdreadwrite_callback; |
439 | if (cdb[1] & 0x8) | 639 | if (cdb[1] & 0x8) |
440 | cmd->se_cmd_flags |= SCF_FUA; | 640 | cmd->se_cmd_flags |= SCF_FUA; |
@@ -461,6 +661,28 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
461 | } | 661 | } |
462 | break; | 662 | break; |
463 | } | 663 | } |
664 | case COMPARE_AND_WRITE: | ||
665 | sectors = cdb[13]; | ||
666 | /* | ||
667 | * Currently enforce COMPARE_AND_WRITE for a single sector | ||
668 | */ | ||
669 | if (sectors > 1) { | ||
670 | pr_err("COMPARE_AND_WRITE contains NoLB: %u greater" | ||
671 | " than 1\n", sectors); | ||
672 | return TCM_INVALID_CDB_FIELD; | ||
673 | } | ||
674 | /* | ||
675 | * Double size because we have two buffers, note that | ||
676 | * zero is not an error.. | ||
677 | */ | ||
678 | size = 2 * sbc_get_size(cmd, sectors); | ||
679 | cmd->t_task_lba = get_unaligned_be64(&cdb[2]); | ||
680 | cmd->t_task_nolb = sectors; | ||
681 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB | SCF_COMPARE_AND_WRITE; | ||
682 | cmd->execute_rw = ops->execute_rw; | ||
683 | cmd->execute_cmd = sbc_compare_and_write; | ||
684 | cmd->transport_complete_callback = compare_and_write_callback; | ||
685 | break; | ||
464 | case READ_CAPACITY: | 686 | case READ_CAPACITY: |
465 | size = READ_CAP_LEN; | 687 | size = READ_CAP_LEN; |
466 | cmd->execute_cmd = sbc_emulate_readcapacity; | 688 | cmd->execute_cmd = sbc_emulate_readcapacity; |
@@ -600,7 +822,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops) | |||
600 | return TCM_ADDRESS_OUT_OF_RANGE; | 822 | return TCM_ADDRESS_OUT_OF_RANGE; |
601 | } | 823 | } |
602 | 824 | ||
603 | size = sbc_get_size(cmd, sectors); | 825 | if (!(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) |
826 | size = sbc_get_size(cmd, sectors); | ||
604 | } | 827 | } |
605 | 828 | ||
606 | return target_cmd_size_check(cmd, size); | 829 | return target_cmd_size_check(cmd, size); |
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c index 9fabbf7214cd..074539558a54 100644 --- a/drivers/target/target_core_spc.c +++ b/drivers/target/target_core_spc.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SCSI Primary Commands (SPC) parsing and emulation. | 2 | * SCSI Primary Commands (SPC) parsing and emulation. |
3 | * | 3 | * |
4 | * (c) Copyright 2002-2012 RisingTide Systems LLC. | 4 | * (c) Copyright 2002-2013 Datera, Inc. |
5 | * | 5 | * |
6 | * Nicholas A. Bellinger <nab@kernel.org> | 6 | * Nicholas A. Bellinger <nab@kernel.org> |
7 | * | 7 | * |
@@ -35,7 +35,7 @@ | |||
35 | #include "target_core_alua.h" | 35 | #include "target_core_alua.h" |
36 | #include "target_core_pr.h" | 36 | #include "target_core_pr.h" |
37 | #include "target_core_ua.h" | 37 | #include "target_core_ua.h" |
38 | 38 | #include "target_core_xcopy.h" | |
39 | 39 | ||
40 | static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) | 40 | static void spc_fill_alua_data(struct se_port *port, unsigned char *buf) |
41 | { | 41 | { |
@@ -95,6 +95,12 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf) | |||
95 | */ | 95 | */ |
96 | spc_fill_alua_data(lun->lun_sep, buf); | 96 | spc_fill_alua_data(lun->lun_sep, buf); |
97 | 97 | ||
98 | /* | ||
99 | * Set Third-Party Copy (3PC) bit to indicate support for EXTENDED_COPY | ||
100 | */ | ||
101 | if (dev->dev_attrib.emulate_3pc) | ||
102 | buf[5] |= 0x8; | ||
103 | |||
98 | buf[7] = 0x2; /* CmdQue=1 */ | 104 | buf[7] = 0x2; /* CmdQue=1 */ |
99 | 105 | ||
100 | memcpy(&buf[8], "LIO-ORG ", 8); | 106 | memcpy(&buf[8], "LIO-ORG ", 8); |
@@ -129,8 +135,8 @@ spc_emulate_evpd_80(struct se_cmd *cmd, unsigned char *buf) | |||
129 | return 0; | 135 | return 0; |
130 | } | 136 | } |
131 | 137 | ||
132 | static void spc_parse_naa_6h_vendor_specific(struct se_device *dev, | 138 | void spc_parse_naa_6h_vendor_specific(struct se_device *dev, |
133 | unsigned char *buf) | 139 | unsigned char *buf) |
134 | { | 140 | { |
135 | unsigned char *p = &dev->t10_wwn.unit_serial[0]; | 141 | unsigned char *p = &dev->t10_wwn.unit_serial[0]; |
136 | int cnt; | 142 | int cnt; |
@@ -460,6 +466,11 @@ spc_emulate_evpd_b0(struct se_cmd *cmd, unsigned char *buf) | |||
460 | 466 | ||
461 | /* Set WSNZ to 1 */ | 467 | /* Set WSNZ to 1 */ |
462 | buf[4] = 0x01; | 468 | buf[4] = 0x01; |
469 | /* | ||
470 | * Set MAXIMUM COMPARE AND WRITE LENGTH | ||
471 | */ | ||
472 | if (dev->dev_attrib.emulate_caw) | ||
473 | buf[5] = 0x01; | ||
463 | 474 | ||
464 | /* | 475 | /* |
465 | * Set OPTIMAL TRANSFER LENGTH GRANULARITY | 476 | * Set OPTIMAL TRANSFER LENGTH GRANULARITY |
@@ -1250,8 +1261,14 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size) | |||
1250 | *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; | 1261 | *size = (cdb[6] << 24) | (cdb[7] << 16) | (cdb[8] << 8) | cdb[9]; |
1251 | break; | 1262 | break; |
1252 | case EXTENDED_COPY: | 1263 | case EXTENDED_COPY: |
1253 | case READ_ATTRIBUTE: | 1264 | *size = get_unaligned_be32(&cdb[10]); |
1265 | cmd->execute_cmd = target_do_xcopy; | ||
1266 | break; | ||
1254 | case RECEIVE_COPY_RESULTS: | 1267 | case RECEIVE_COPY_RESULTS: |
1268 | *size = get_unaligned_be32(&cdb[10]); | ||
1269 | cmd->execute_cmd = target_do_receive_copy_results; | ||
1270 | break; | ||
1271 | case READ_ATTRIBUTE: | ||
1255 | case WRITE_ATTRIBUTE: | 1272 | case WRITE_ATTRIBUTE: |
1256 | *size = (cdb[10] << 24) | (cdb[11] << 16) | | 1273 | *size = (cdb[10] << 24) | (cdb[11] << 16) | |
1257 | (cdb[12] << 8) | cdb[13]; | 1274 | (cdb[12] << 8) | cdb[13]; |
diff --git a/drivers/target/target_core_stat.c b/drivers/target/target_core_stat.c index d154ce797180..9c642e02cba1 100644 --- a/drivers/target/target_core_stat.c +++ b/drivers/target/target_core_stat.c | |||
@@ -4,7 +4,7 @@ | |||
4 | * Modern ConfigFS group context specific statistics based on original | 4 | * Modern ConfigFS group context specific statistics based on original |
5 | * target_core_mib.c code | 5 | * target_core_mib.c code |
6 | * | 6 | * |
7 | * (c) Copyright 2006-2012 RisingTide Systems LLC. | 7 | * (c) Copyright 2006-2013 Datera, Inc. |
8 | * | 8 | * |
9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> | 9 | * Nicholas A. Bellinger <nab@linux-iscsi.org> |
10 | * | 10 | * |
diff --git a/drivers/target/target_core_tmr.c b/drivers/target/target_core_tmr.c index 0d7cacb91107..250009909d49 100644 --- a/drivers/target/target_core_tmr.c +++ b/drivers/target/target_core_tmr.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains SPC-3 task management infrastructure | 4 | * This file contains SPC-3 task management infrastructure |
5 | * | 5 | * |
6 | * (c) Copyright 2009-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2009-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
diff --git a/drivers/target/target_core_tpg.c b/drivers/target/target_core_tpg.c index aac9d2727e3c..b9a6ec0aa5fe 100644 --- a/drivers/target/target_core_tpg.c +++ b/drivers/target/target_core_tpg.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains generic Target Portal Group related functions. | 4 | * This file contains generic Target Portal Group related functions. |
5 | * | 5 | * |
6 | * (c) Copyright 2002-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2002-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index d8e49d79f8cc..84747cc1aac0 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains the Generic Target Engine Core. | 4 | * This file contains the Generic Target Engine Core. |
5 | * | 5 | * |
6 | * (c) Copyright 2002-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2002-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
@@ -67,7 +67,6 @@ struct kmem_cache *t10_alua_tg_pt_gp_mem_cache; | |||
67 | static void transport_complete_task_attr(struct se_cmd *cmd); | 67 | static void transport_complete_task_attr(struct se_cmd *cmd); |
68 | static void transport_handle_queue_full(struct se_cmd *cmd, | 68 | static void transport_handle_queue_full(struct se_cmd *cmd, |
69 | struct se_device *dev); | 69 | struct se_device *dev); |
70 | static int transport_generic_get_mem(struct se_cmd *cmd); | ||
71 | static int transport_put_cmd(struct se_cmd *cmd); | 70 | static int transport_put_cmd(struct se_cmd *cmd); |
72 | static void target_complete_ok_work(struct work_struct *work); | 71 | static void target_complete_ok_work(struct work_struct *work); |
73 | 72 | ||
@@ -232,6 +231,50 @@ struct se_session *transport_init_session(void) | |||
232 | } | 231 | } |
233 | EXPORT_SYMBOL(transport_init_session); | 232 | EXPORT_SYMBOL(transport_init_session); |
234 | 233 | ||
234 | int transport_alloc_session_tags(struct se_session *se_sess, | ||
235 | unsigned int tag_num, unsigned int tag_size) | ||
236 | { | ||
237 | int rc; | ||
238 | |||
239 | se_sess->sess_cmd_map = kzalloc(tag_num * tag_size, GFP_KERNEL); | ||
240 | if (!se_sess->sess_cmd_map) { | ||
241 | pr_err("Unable to allocate se_sess->sess_cmd_map\n"); | ||
242 | return -ENOMEM; | ||
243 | } | ||
244 | |||
245 | rc = percpu_ida_init(&se_sess->sess_tag_pool, tag_num); | ||
246 | if (rc < 0) { | ||
247 | pr_err("Unable to init se_sess->sess_tag_pool," | ||
248 | " tag_num: %u\n", tag_num); | ||
249 | kfree(se_sess->sess_cmd_map); | ||
250 | se_sess->sess_cmd_map = NULL; | ||
251 | return -ENOMEM; | ||
252 | } | ||
253 | |||
254 | return 0; | ||
255 | } | ||
256 | EXPORT_SYMBOL(transport_alloc_session_tags); | ||
257 | |||
258 | struct se_session *transport_init_session_tags(unsigned int tag_num, | ||
259 | unsigned int tag_size) | ||
260 | { | ||
261 | struct se_session *se_sess; | ||
262 | int rc; | ||
263 | |||
264 | se_sess = transport_init_session(); | ||
265 | if (IS_ERR(se_sess)) | ||
266 | return se_sess; | ||
267 | |||
268 | rc = transport_alloc_session_tags(se_sess, tag_num, tag_size); | ||
269 | if (rc < 0) { | ||
270 | transport_free_session(se_sess); | ||
271 | return ERR_PTR(-ENOMEM); | ||
272 | } | ||
273 | |||
274 | return se_sess; | ||
275 | } | ||
276 | EXPORT_SYMBOL(transport_init_session_tags); | ||
277 | |||
235 | /* | 278 | /* |
236 | * Called with spin_lock_irqsave(&struct se_portal_group->session_lock called. | 279 | * Called with spin_lock_irqsave(&struct se_portal_group->session_lock called. |
237 | */ | 280 | */ |
@@ -367,6 +410,10 @@ EXPORT_SYMBOL(transport_deregister_session_configfs); | |||
367 | 410 | ||
368 | void transport_free_session(struct se_session *se_sess) | 411 | void transport_free_session(struct se_session *se_sess) |
369 | { | 412 | { |
413 | if (se_sess->sess_cmd_map) { | ||
414 | percpu_ida_destroy(&se_sess->sess_tag_pool); | ||
415 | kfree(se_sess->sess_cmd_map); | ||
416 | } | ||
370 | kmem_cache_free(se_sess_cache, se_sess); | 417 | kmem_cache_free(se_sess_cache, se_sess); |
371 | } | 418 | } |
372 | EXPORT_SYMBOL(transport_free_session); | 419 | EXPORT_SYMBOL(transport_free_session); |
@@ -1206,7 +1253,7 @@ int transport_handle_cdb_direct( | |||
1206 | } | 1253 | } |
1207 | EXPORT_SYMBOL(transport_handle_cdb_direct); | 1254 | EXPORT_SYMBOL(transport_handle_cdb_direct); |
1208 | 1255 | ||
1209 | static sense_reason_t | 1256 | sense_reason_t |
1210 | transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, | 1257 | transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl, |
1211 | u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count) | 1258 | u32 sgl_count, struct scatterlist *sgl_bidi, u32 sgl_bidi_count) |
1212 | { | 1259 | { |
@@ -1512,6 +1559,13 @@ void transport_generic_request_failure(struct se_cmd *cmd, | |||
1512 | * For SAM Task Attribute emulation for failed struct se_cmd | 1559 | * For SAM Task Attribute emulation for failed struct se_cmd |
1513 | */ | 1560 | */ |
1514 | transport_complete_task_attr(cmd); | 1561 | transport_complete_task_attr(cmd); |
1562 | /* | ||
1563 | * Handle special case for COMPARE_AND_WRITE failure, where the | ||
1564 | * callback is expected to drop the per device ->caw_mutex. | ||
1565 | */ | ||
1566 | if ((cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) && | ||
1567 | cmd->transport_complete_callback) | ||
1568 | cmd->transport_complete_callback(cmd); | ||
1515 | 1569 | ||
1516 | switch (sense_reason) { | 1570 | switch (sense_reason) { |
1517 | case TCM_NON_EXISTENT_LUN: | 1571 | case TCM_NON_EXISTENT_LUN: |
@@ -1579,7 +1633,7 @@ queue_full: | |||
1579 | } | 1633 | } |
1580 | EXPORT_SYMBOL(transport_generic_request_failure); | 1634 | EXPORT_SYMBOL(transport_generic_request_failure); |
1581 | 1635 | ||
1582 | static void __target_execute_cmd(struct se_cmd *cmd) | 1636 | void __target_execute_cmd(struct se_cmd *cmd) |
1583 | { | 1637 | { |
1584 | sense_reason_t ret; | 1638 | sense_reason_t ret; |
1585 | 1639 | ||
@@ -1784,7 +1838,7 @@ static void transport_complete_qf(struct se_cmd *cmd) | |||
1784 | ret = cmd->se_tfo->queue_data_in(cmd); | 1838 | ret = cmd->se_tfo->queue_data_in(cmd); |
1785 | break; | 1839 | break; |
1786 | case DMA_TO_DEVICE: | 1840 | case DMA_TO_DEVICE: |
1787 | if (cmd->t_bidi_data_sg) { | 1841 | if (cmd->se_cmd_flags & SCF_BIDI) { |
1788 | ret = cmd->se_tfo->queue_data_in(cmd); | 1842 | ret = cmd->se_tfo->queue_data_in(cmd); |
1789 | if (ret < 0) | 1843 | if (ret < 0) |
1790 | break; | 1844 | break; |
@@ -1856,10 +1910,25 @@ static void target_complete_ok_work(struct work_struct *work) | |||
1856 | } | 1910 | } |
1857 | /* | 1911 | /* |
1858 | * Check for a callback, used by amongst other things | 1912 | * Check for a callback, used by amongst other things |
1859 | * XDWRITE_READ_10 emulation. | 1913 | * XDWRITE_READ_10 and COMPARE_AND_WRITE emulation. |
1860 | */ | 1914 | */ |
1861 | if (cmd->transport_complete_callback) | 1915 | if (cmd->transport_complete_callback) { |
1862 | cmd->transport_complete_callback(cmd); | 1916 | sense_reason_t rc; |
1917 | |||
1918 | rc = cmd->transport_complete_callback(cmd); | ||
1919 | if (!rc && !(cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE_POST)) { | ||
1920 | return; | ||
1921 | } else if (rc) { | ||
1922 | ret = transport_send_check_condition_and_sense(cmd, | ||
1923 | rc, 0); | ||
1924 | if (ret == -EAGAIN || ret == -ENOMEM) | ||
1925 | goto queue_full; | ||
1926 | |||
1927 | transport_lun_remove_cmd(cmd); | ||
1928 | transport_cmd_check_stop_to_fabric(cmd); | ||
1929 | return; | ||
1930 | } | ||
1931 | } | ||
1863 | 1932 | ||
1864 | switch (cmd->data_direction) { | 1933 | switch (cmd->data_direction) { |
1865 | case DMA_FROM_DEVICE: | 1934 | case DMA_FROM_DEVICE: |
@@ -1885,7 +1954,7 @@ static void target_complete_ok_work(struct work_struct *work) | |||
1885 | /* | 1954 | /* |
1886 | * Check if we need to send READ payload for BIDI-COMMAND | 1955 | * Check if we need to send READ payload for BIDI-COMMAND |
1887 | */ | 1956 | */ |
1888 | if (cmd->t_bidi_data_sg) { | 1957 | if (cmd->se_cmd_flags & SCF_BIDI) { |
1889 | spin_lock(&cmd->se_lun->lun_sep_lock); | 1958 | spin_lock(&cmd->se_lun->lun_sep_lock); |
1890 | if (cmd->se_lun->lun_sep) { | 1959 | if (cmd->se_lun->lun_sep) { |
1891 | cmd->se_lun->lun_sep->sep_stats.tx_data_octets += | 1960 | cmd->se_lun->lun_sep->sep_stats.tx_data_octets += |
@@ -1930,10 +1999,29 @@ static inline void transport_free_sgl(struct scatterlist *sgl, int nents) | |||
1930 | kfree(sgl); | 1999 | kfree(sgl); |
1931 | } | 2000 | } |
1932 | 2001 | ||
2002 | static inline void transport_reset_sgl_orig(struct se_cmd *cmd) | ||
2003 | { | ||
2004 | /* | ||
2005 | * Check for saved t_data_sg that may be used for COMPARE_AND_WRITE | ||
2006 | * emulation, and free + reset pointers if necessary.. | ||
2007 | */ | ||
2008 | if (!cmd->t_data_sg_orig) | ||
2009 | return; | ||
2010 | |||
2011 | kfree(cmd->t_data_sg); | ||
2012 | cmd->t_data_sg = cmd->t_data_sg_orig; | ||
2013 | cmd->t_data_sg_orig = NULL; | ||
2014 | cmd->t_data_nents = cmd->t_data_nents_orig; | ||
2015 | cmd->t_data_nents_orig = 0; | ||
2016 | } | ||
2017 | |||
1933 | static inline void transport_free_pages(struct se_cmd *cmd) | 2018 | static inline void transport_free_pages(struct se_cmd *cmd) |
1934 | { | 2019 | { |
1935 | if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) | 2020 | if (cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) { |
2021 | transport_reset_sgl_orig(cmd); | ||
1936 | return; | 2022 | return; |
2023 | } | ||
2024 | transport_reset_sgl_orig(cmd); | ||
1937 | 2025 | ||
1938 | transport_free_sgl(cmd->t_data_sg, cmd->t_data_nents); | 2026 | transport_free_sgl(cmd->t_data_sg, cmd->t_data_nents); |
1939 | cmd->t_data_sg = NULL; | 2027 | cmd->t_data_sg = NULL; |
@@ -2029,24 +2117,22 @@ void transport_kunmap_data_sg(struct se_cmd *cmd) | |||
2029 | } | 2117 | } |
2030 | EXPORT_SYMBOL(transport_kunmap_data_sg); | 2118 | EXPORT_SYMBOL(transport_kunmap_data_sg); |
2031 | 2119 | ||
2032 | static int | 2120 | int |
2033 | transport_generic_get_mem(struct se_cmd *cmd) | 2121 | target_alloc_sgl(struct scatterlist **sgl, unsigned int *nents, u32 length, |
2122 | bool zero_page) | ||
2034 | { | 2123 | { |
2035 | u32 length = cmd->data_length; | 2124 | struct scatterlist *sg; |
2036 | unsigned int nents; | ||
2037 | struct page *page; | 2125 | struct page *page; |
2038 | gfp_t zero_flag; | 2126 | gfp_t zero_flag = (zero_page) ? __GFP_ZERO : 0; |
2127 | unsigned int nent; | ||
2039 | int i = 0; | 2128 | int i = 0; |
2040 | 2129 | ||
2041 | nents = DIV_ROUND_UP(length, PAGE_SIZE); | 2130 | nent = DIV_ROUND_UP(length, PAGE_SIZE); |
2042 | cmd->t_data_sg = kmalloc(sizeof(struct scatterlist) * nents, GFP_KERNEL); | 2131 | sg = kmalloc(sizeof(struct scatterlist) * nent, GFP_KERNEL); |
2043 | if (!cmd->t_data_sg) | 2132 | if (!sg) |
2044 | return -ENOMEM; | 2133 | return -ENOMEM; |
2045 | 2134 | ||
2046 | cmd->t_data_nents = nents; | 2135 | sg_init_table(sg, nent); |
2047 | sg_init_table(cmd->t_data_sg, nents); | ||
2048 | |||
2049 | zero_flag = cmd->se_cmd_flags & SCF_SCSI_DATA_CDB ? 0 : __GFP_ZERO; | ||
2050 | 2136 | ||
2051 | while (length) { | 2137 | while (length) { |
2052 | u32 page_len = min_t(u32, length, PAGE_SIZE); | 2138 | u32 page_len = min_t(u32, length, PAGE_SIZE); |
@@ -2054,19 +2140,20 @@ transport_generic_get_mem(struct se_cmd *cmd) | |||
2054 | if (!page) | 2140 | if (!page) |
2055 | goto out; | 2141 | goto out; |
2056 | 2142 | ||
2057 | sg_set_page(&cmd->t_data_sg[i], page, page_len, 0); | 2143 | sg_set_page(&sg[i], page, page_len, 0); |
2058 | length -= page_len; | 2144 | length -= page_len; |
2059 | i++; | 2145 | i++; |
2060 | } | 2146 | } |
2147 | *sgl = sg; | ||
2148 | *nents = nent; | ||
2061 | return 0; | 2149 | return 0; |
2062 | 2150 | ||
2063 | out: | 2151 | out: |
2064 | while (i > 0) { | 2152 | while (i > 0) { |
2065 | i--; | 2153 | i--; |
2066 | __free_page(sg_page(&cmd->t_data_sg[i])); | 2154 | __free_page(sg_page(&sg[i])); |
2067 | } | 2155 | } |
2068 | kfree(cmd->t_data_sg); | 2156 | kfree(sg); |
2069 | cmd->t_data_sg = NULL; | ||
2070 | return -ENOMEM; | 2157 | return -ENOMEM; |
2071 | } | 2158 | } |
2072 | 2159 | ||
@@ -2087,7 +2174,27 @@ transport_generic_new_cmd(struct se_cmd *cmd) | |||
2087 | */ | 2174 | */ |
2088 | if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) && | 2175 | if (!(cmd->se_cmd_flags & SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC) && |
2089 | cmd->data_length) { | 2176 | cmd->data_length) { |
2090 | ret = transport_generic_get_mem(cmd); | 2177 | bool zero_flag = !(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB); |
2178 | |||
2179 | if ((cmd->se_cmd_flags & SCF_BIDI) || | ||
2180 | (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE)) { | ||
2181 | u32 bidi_length; | ||
2182 | |||
2183 | if (cmd->se_cmd_flags & SCF_COMPARE_AND_WRITE) | ||
2184 | bidi_length = cmd->t_task_nolb * | ||
2185 | cmd->se_dev->dev_attrib.block_size; | ||
2186 | else | ||
2187 | bidi_length = cmd->data_length; | ||
2188 | |||
2189 | ret = target_alloc_sgl(&cmd->t_bidi_data_sg, | ||
2190 | &cmd->t_bidi_data_nents, | ||
2191 | bidi_length, zero_flag); | ||
2192 | if (ret < 0) | ||
2193 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
2194 | } | ||
2195 | |||
2196 | ret = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents, | ||
2197 | cmd->data_length, zero_flag); | ||
2091 | if (ret < 0) | 2198 | if (ret < 0) |
2092 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 2199 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
2093 | } | 2200 | } |
@@ -2740,6 +2847,15 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2740 | buffer[SPC_ASC_KEY_OFFSET] = asc; | 2847 | buffer[SPC_ASC_KEY_OFFSET] = asc; |
2741 | buffer[SPC_ASCQ_KEY_OFFSET] = ascq; | 2848 | buffer[SPC_ASCQ_KEY_OFFSET] = ascq; |
2742 | break; | 2849 | break; |
2850 | case TCM_MISCOMPARE_VERIFY: | ||
2851 | /* CURRENT ERROR */ | ||
2852 | buffer[0] = 0x70; | ||
2853 | buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; | ||
2854 | buffer[SPC_SENSE_KEY_OFFSET] = MISCOMPARE; | ||
2855 | /* MISCOMPARE DURING VERIFY OPERATION */ | ||
2856 | buffer[SPC_ASC_KEY_OFFSET] = 0x1d; | ||
2857 | buffer[SPC_ASCQ_KEY_OFFSET] = 0x00; | ||
2858 | break; | ||
2743 | case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: | 2859 | case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE: |
2744 | default: | 2860 | default: |
2745 | /* CURRENT ERROR */ | 2861 | /* CURRENT ERROR */ |
diff --git a/drivers/target/target_core_ua.c b/drivers/target/target_core_ua.c index bf0e390ce2d7..b04467e7547c 100644 --- a/drivers/target/target_core_ua.c +++ b/drivers/target/target_core_ua.c | |||
@@ -3,7 +3,7 @@ | |||
3 | * | 3 | * |
4 | * This file contains logic for SPC-3 Unit Attention emulation | 4 | * This file contains logic for SPC-3 Unit Attention emulation |
5 | * | 5 | * |
6 | * (c) Copyright 2009-2012 RisingTide Systems LLC. | 6 | * (c) Copyright 2009-2013 Datera, Inc. |
7 | * | 7 | * |
8 | * Nicholas A. Bellinger <nab@kernel.org> | 8 | * Nicholas A. Bellinger <nab@kernel.org> |
9 | * | 9 | * |
diff --git a/drivers/target/target_core_xcopy.c b/drivers/target/target_core_xcopy.c new file mode 100644 index 000000000000..4d22e7d2adca --- /dev/null +++ b/drivers/target/target_core_xcopy.c | |||
@@ -0,0 +1,1081 @@ | |||
1 | /******************************************************************************* | ||
2 | * Filename: target_core_xcopy.c | ||
3 | * | ||
4 | * This file contains support for SPC-4 Extended-Copy offload with generic | ||
5 | * TCM backends. | ||
6 | * | ||
7 | * Copyright (c) 2011-2013 Datera, Inc. All rights reserved. | ||
8 | * | ||
9 | * Author: | ||
10 | * Nicholas A. Bellinger <nab@daterainc.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License as published by | ||
14 | * the Free Software Foundation; either version 2 of the License, or | ||
15 | * (at your option) any later version. | ||
16 | * | ||
17 | * This program is distributed in the hope that it will be useful, | ||
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
20 | * GNU General Public License for more details. | ||
21 | * | ||
22 | ******************************************************************************/ | ||
23 | |||
24 | #include <linux/slab.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/list.h> | ||
27 | #include <linux/configfs.h> | ||
28 | #include <scsi/scsi.h> | ||
29 | #include <scsi/scsi_cmnd.h> | ||
30 | #include <asm/unaligned.h> | ||
31 | |||
32 | #include <target/target_core_base.h> | ||
33 | #include <target/target_core_backend.h> | ||
34 | #include <target/target_core_fabric.h> | ||
35 | #include <target/target_core_configfs.h> | ||
36 | |||
37 | #include "target_core_pr.h" | ||
38 | #include "target_core_ua.h" | ||
39 | #include "target_core_xcopy.h" | ||
40 | |||
41 | static struct workqueue_struct *xcopy_wq = NULL; | ||
42 | /* | ||
43 | * From target_core_spc.c | ||
44 | */ | ||
45 | extern void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *); | ||
46 | /* | ||
47 | * From target_core_device.c | ||
48 | */ | ||
49 | extern struct mutex g_device_mutex; | ||
50 | extern struct list_head g_device_list; | ||
51 | /* | ||
52 | * From target_core_configfs.c | ||
53 | */ | ||
54 | extern struct configfs_subsystem *target_core_subsystem[]; | ||
55 | |||
56 | static int target_xcopy_gen_naa_ieee(struct se_device *dev, unsigned char *buf) | ||
57 | { | ||
58 | int off = 0; | ||
59 | |||
60 | buf[off++] = (0x6 << 4); | ||
61 | buf[off++] = 0x01; | ||
62 | buf[off++] = 0x40; | ||
63 | buf[off] = (0x5 << 4); | ||
64 | |||
65 | spc_parse_naa_6h_vendor_specific(dev, &buf[off]); | ||
66 | return 0; | ||
67 | } | ||
68 | |||
69 | static int target_xcopy_locate_se_dev_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | ||
70 | bool src) | ||
71 | { | ||
72 | struct se_device *se_dev; | ||
73 | struct configfs_subsystem *subsys = target_core_subsystem[0]; | ||
74 | unsigned char tmp_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN], *dev_wwn; | ||
75 | int rc; | ||
76 | |||
77 | if (src == true) | ||
78 | dev_wwn = &xop->dst_tid_wwn[0]; | ||
79 | else | ||
80 | dev_wwn = &xop->src_tid_wwn[0]; | ||
81 | |||
82 | mutex_lock(&g_device_mutex); | ||
83 | list_for_each_entry(se_dev, &g_device_list, g_dev_node) { | ||
84 | |||
85 | memset(&tmp_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); | ||
86 | target_xcopy_gen_naa_ieee(se_dev, &tmp_dev_wwn[0]); | ||
87 | |||
88 | rc = memcmp(&tmp_dev_wwn[0], dev_wwn, XCOPY_NAA_IEEE_REGEX_LEN); | ||
89 | if (rc != 0) | ||
90 | continue; | ||
91 | |||
92 | if (src == true) { | ||
93 | xop->dst_dev = se_dev; | ||
94 | pr_debug("XCOPY 0xe4: Setting xop->dst_dev: %p from located" | ||
95 | " se_dev\n", xop->dst_dev); | ||
96 | } else { | ||
97 | xop->src_dev = se_dev; | ||
98 | pr_debug("XCOPY 0xe4: Setting xop->src_dev: %p from located" | ||
99 | " se_dev\n", xop->src_dev); | ||
100 | } | ||
101 | |||
102 | rc = configfs_depend_item(subsys, | ||
103 | &se_dev->dev_group.cg_item); | ||
104 | if (rc != 0) { | ||
105 | pr_err("configfs_depend_item attempt failed:" | ||
106 | " %d for se_dev: %p\n", rc, se_dev); | ||
107 | mutex_unlock(&g_device_mutex); | ||
108 | return rc; | ||
109 | } | ||
110 | |||
111 | pr_debug("Called configfs_depend_item for subsys: %p se_dev: %p" | ||
112 | " se_dev->se_dev_group: %p\n", subsys, se_dev, | ||
113 | &se_dev->dev_group); | ||
114 | |||
115 | mutex_unlock(&g_device_mutex); | ||
116 | return 0; | ||
117 | } | ||
118 | mutex_unlock(&g_device_mutex); | ||
119 | |||
120 | pr_err("Unable to locate 0xe4 descriptor for EXTENDED_COPY\n"); | ||
121 | return -EINVAL; | ||
122 | } | ||
123 | |||
124 | static int target_xcopy_parse_tiddesc_e4(struct se_cmd *se_cmd, struct xcopy_op *xop, | ||
125 | unsigned char *p, bool src) | ||
126 | { | ||
127 | unsigned char *desc = p; | ||
128 | unsigned short ript; | ||
129 | u8 desig_len; | ||
130 | /* | ||
131 | * Extract RELATIVE INITIATOR PORT IDENTIFIER | ||
132 | */ | ||
133 | ript = get_unaligned_be16(&desc[2]); | ||
134 | pr_debug("XCOPY 0xe4: RELATIVE INITIATOR PORT IDENTIFIER: %hu\n", ript); | ||
135 | /* | ||
136 | * Check for supported code set, association, and designator type | ||
137 | */ | ||
138 | if ((desc[4] & 0x0f) != 0x1) { | ||
139 | pr_err("XCOPY 0xe4: code set of non binary type not supported\n"); | ||
140 | return -EINVAL; | ||
141 | } | ||
142 | if ((desc[5] & 0x30) != 0x00) { | ||
143 | pr_err("XCOPY 0xe4: association other than LUN not supported\n"); | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | if ((desc[5] & 0x0f) != 0x3) { | ||
147 | pr_err("XCOPY 0xe4: designator type unsupported: 0x%02x\n", | ||
148 | (desc[5] & 0x0f)); | ||
149 | return -EINVAL; | ||
150 | } | ||
151 | /* | ||
152 | * Check for matching 16 byte length for NAA IEEE Registered Extended | ||
153 | * Assigned designator | ||
154 | */ | ||
155 | desig_len = desc[7]; | ||
156 | if (desig_len != 16) { | ||
157 | pr_err("XCOPY 0xe4: invalid desig_len: %d\n", (int)desig_len); | ||
158 | return -EINVAL; | ||
159 | } | ||
160 | pr_debug("XCOPY 0xe4: desig_len: %d\n", (int)desig_len); | ||
161 | /* | ||
162 | * Check for NAA IEEE Registered Extended Assigned header.. | ||
163 | */ | ||
164 | if ((desc[8] & 0xf0) != 0x60) { | ||
165 | pr_err("XCOPY 0xe4: Unsupported DESIGNATOR TYPE: 0x%02x\n", | ||
166 | (desc[8] & 0xf0)); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | if (src == true) { | ||
171 | memcpy(&xop->src_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); | ||
172 | /* | ||
173 | * Determine if the source designator matches the local device | ||
174 | */ | ||
175 | if (!memcmp(&xop->local_dev_wwn[0], &xop->src_tid_wwn[0], | ||
176 | XCOPY_NAA_IEEE_REGEX_LEN)) { | ||
177 | xop->op_origin = XCOL_SOURCE_RECV_OP; | ||
178 | xop->src_dev = se_cmd->se_dev; | ||
179 | pr_debug("XCOPY 0xe4: Set xop->src_dev %p from source" | ||
180 | " received xop\n", xop->src_dev); | ||
181 | } | ||
182 | } else { | ||
183 | memcpy(&xop->dst_tid_wwn[0], &desc[8], XCOPY_NAA_IEEE_REGEX_LEN); | ||
184 | /* | ||
185 | * Determine if the destination designator matches the local device | ||
186 | */ | ||
187 | if (!memcmp(&xop->local_dev_wwn[0], &xop->dst_tid_wwn[0], | ||
188 | XCOPY_NAA_IEEE_REGEX_LEN)) { | ||
189 | xop->op_origin = XCOL_DEST_RECV_OP; | ||
190 | xop->dst_dev = se_cmd->se_dev; | ||
191 | pr_debug("XCOPY 0xe4: Set xop->dst_dev: %p from destination" | ||
192 | " received xop\n", xop->dst_dev); | ||
193 | } | ||
194 | } | ||
195 | |||
196 | return 0; | ||
197 | } | ||
198 | |||
199 | static int target_xcopy_parse_target_descriptors(struct se_cmd *se_cmd, | ||
200 | struct xcopy_op *xop, unsigned char *p, | ||
201 | unsigned short tdll) | ||
202 | { | ||
203 | struct se_device *local_dev = se_cmd->se_dev; | ||
204 | unsigned char *desc = p; | ||
205 | int offset = tdll % XCOPY_TARGET_DESC_LEN, rc, ret = 0; | ||
206 | unsigned short start = 0; | ||
207 | bool src = true; | ||
208 | |||
209 | if (offset != 0) { | ||
210 | pr_err("XCOPY target descriptor list length is not" | ||
211 | " multiple of %d\n", XCOPY_TARGET_DESC_LEN); | ||
212 | return -EINVAL; | ||
213 | } | ||
214 | if (tdll > 64) { | ||
215 | pr_err("XCOPY target descriptor supports a maximum" | ||
216 | " two src/dest descriptors, tdll: %hu too large..\n", tdll); | ||
217 | return -EINVAL; | ||
218 | } | ||
219 | /* | ||
220 | * Generate an IEEE Registered Extended designator based upon the | ||
221 | * se_device the XCOPY was received upon.. | ||
222 | */ | ||
223 | memset(&xop->local_dev_wwn[0], 0, XCOPY_NAA_IEEE_REGEX_LEN); | ||
224 | target_xcopy_gen_naa_ieee(local_dev, &xop->local_dev_wwn[0]); | ||
225 | |||
226 | while (start < tdll) { | ||
227 | /* | ||
228 | * Check target descriptor identification with 0xE4 type with | ||
229 | * use VPD 0x83 WWPN matching .. | ||
230 | */ | ||
231 | switch (desc[0]) { | ||
232 | case 0xe4: | ||
233 | rc = target_xcopy_parse_tiddesc_e4(se_cmd, xop, | ||
234 | &desc[0], src); | ||
235 | if (rc != 0) | ||
236 | goto out; | ||
237 | /* | ||
238 | * Assume target descriptors are in source -> destination order.. | ||
239 | */ | ||
240 | if (src == true) | ||
241 | src = false; | ||
242 | else | ||
243 | src = true; | ||
244 | start += XCOPY_TARGET_DESC_LEN; | ||
245 | desc += XCOPY_TARGET_DESC_LEN; | ||
246 | ret++; | ||
247 | break; | ||
248 | default: | ||
249 | pr_err("XCOPY unsupported descriptor type code:" | ||
250 | " 0x%02x\n", desc[0]); | ||
251 | goto out; | ||
252 | } | ||
253 | } | ||
254 | |||
255 | if (xop->op_origin == XCOL_SOURCE_RECV_OP) | ||
256 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, true); | ||
257 | else | ||
258 | rc = target_xcopy_locate_se_dev_e4(se_cmd, xop, false); | ||
259 | |||
260 | if (rc < 0) | ||
261 | goto out; | ||
262 | |||
263 | pr_debug("XCOPY TGT desc: Source dev: %p NAA IEEE WWN: 0x%16phN\n", | ||
264 | xop->src_dev, &xop->src_tid_wwn[0]); | ||
265 | pr_debug("XCOPY TGT desc: Dest dev: %p NAA IEEE WWN: 0x%16phN\n", | ||
266 | xop->dst_dev, &xop->dst_tid_wwn[0]); | ||
267 | |||
268 | return ret; | ||
269 | |||
270 | out: | ||
271 | return -EINVAL; | ||
272 | } | ||
273 | |||
274 | static int target_xcopy_parse_segdesc_02(struct se_cmd *se_cmd, struct xcopy_op *xop, | ||
275 | unsigned char *p) | ||
276 | { | ||
277 | unsigned char *desc = p; | ||
278 | int dc = (desc[1] & 0x02); | ||
279 | unsigned short desc_len; | ||
280 | |||
281 | desc_len = get_unaligned_be16(&desc[2]); | ||
282 | if (desc_len != 0x18) { | ||
283 | pr_err("XCOPY segment desc 0x02: Illegal desc_len:" | ||
284 | " %hu\n", desc_len); | ||
285 | return -EINVAL; | ||
286 | } | ||
287 | |||
288 | xop->stdi = get_unaligned_be16(&desc[4]); | ||
289 | xop->dtdi = get_unaligned_be16(&desc[6]); | ||
290 | pr_debug("XCOPY seg desc 0x02: desc_len: %hu stdi: %hu dtdi: %hu, DC: %d\n", | ||
291 | desc_len, xop->stdi, xop->dtdi, dc); | ||
292 | |||
293 | xop->nolb = get_unaligned_be16(&desc[10]); | ||
294 | xop->src_lba = get_unaligned_be64(&desc[12]); | ||
295 | xop->dst_lba = get_unaligned_be64(&desc[20]); | ||
296 | pr_debug("XCOPY seg desc 0x02: nolb: %hu src_lba: %llu dst_lba: %llu\n", | ||
297 | xop->nolb, (unsigned long long)xop->src_lba, | ||
298 | (unsigned long long)xop->dst_lba); | ||
299 | |||
300 | if (dc != 0) { | ||
301 | xop->dbl = (desc[29] << 16) & 0xff; | ||
302 | xop->dbl |= (desc[30] << 8) & 0xff; | ||
303 | xop->dbl |= desc[31] & 0xff; | ||
304 | |||
305 | pr_debug("XCOPY seg desc 0x02: DC=1 w/ dbl: %u\n", xop->dbl); | ||
306 | } | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int target_xcopy_parse_segment_descriptors(struct se_cmd *se_cmd, | ||
311 | struct xcopy_op *xop, unsigned char *p, | ||
312 | unsigned int sdll) | ||
313 | { | ||
314 | unsigned char *desc = p; | ||
315 | unsigned int start = 0; | ||
316 | int offset = sdll % XCOPY_SEGMENT_DESC_LEN, rc, ret = 0; | ||
317 | |||
318 | if (offset != 0) { | ||
319 | pr_err("XCOPY segment descriptor list length is not" | ||
320 | " multiple of %d\n", XCOPY_SEGMENT_DESC_LEN); | ||
321 | return -EINVAL; | ||
322 | } | ||
323 | |||
324 | while (start < sdll) { | ||
325 | /* | ||
326 | * Check segment descriptor type code for block -> block | ||
327 | */ | ||
328 | switch (desc[0]) { | ||
329 | case 0x02: | ||
330 | rc = target_xcopy_parse_segdesc_02(se_cmd, xop, desc); | ||
331 | if (rc < 0) | ||
332 | goto out; | ||
333 | |||
334 | ret++; | ||
335 | start += XCOPY_SEGMENT_DESC_LEN; | ||
336 | desc += XCOPY_SEGMENT_DESC_LEN; | ||
337 | break; | ||
338 | default: | ||
339 | pr_err("XCOPY unspported segment descriptor" | ||
340 | "type: 0x%02x\n", desc[0]); | ||
341 | goto out; | ||
342 | } | ||
343 | } | ||
344 | |||
345 | return ret; | ||
346 | |||
347 | out: | ||
348 | return -EINVAL; | ||
349 | } | ||
350 | |||
351 | /* | ||
352 | * Start xcopy_pt ops | ||
353 | */ | ||
354 | |||
355 | struct xcopy_pt_cmd { | ||
356 | bool remote_port; | ||
357 | struct se_cmd se_cmd; | ||
358 | struct xcopy_op *xcopy_op; | ||
359 | struct completion xpt_passthrough_sem; | ||
360 | }; | ||
361 | |||
362 | static struct se_port xcopy_pt_port; | ||
363 | static struct se_portal_group xcopy_pt_tpg; | ||
364 | static struct se_session xcopy_pt_sess; | ||
365 | static struct se_node_acl xcopy_pt_nacl; | ||
366 | |||
367 | static char *xcopy_pt_get_fabric_name(void) | ||
368 | { | ||
369 | return "xcopy-pt"; | ||
370 | } | ||
371 | |||
372 | static u32 xcopy_pt_get_tag(struct se_cmd *se_cmd) | ||
373 | { | ||
374 | return 0; | ||
375 | } | ||
376 | |||
377 | static int xcopy_pt_get_cmd_state(struct se_cmd *se_cmd) | ||
378 | { | ||
379 | return 0; | ||
380 | } | ||
381 | |||
382 | static void xcopy_pt_undepend_remotedev(struct xcopy_op *xop) | ||
383 | { | ||
384 | struct configfs_subsystem *subsys = target_core_subsystem[0]; | ||
385 | struct se_device *remote_dev; | ||
386 | |||
387 | if (xop->op_origin == XCOL_SOURCE_RECV_OP) | ||
388 | remote_dev = xop->dst_dev; | ||
389 | else | ||
390 | remote_dev = xop->src_dev; | ||
391 | |||
392 | pr_debug("Calling configfs_undepend_item for subsys: %p" | ||
393 | " remote_dev: %p remote_dev->dev_group: %p\n", | ||
394 | subsys, remote_dev, &remote_dev->dev_group.cg_item); | ||
395 | |||
396 | configfs_undepend_item(subsys, &remote_dev->dev_group.cg_item); | ||
397 | } | ||
398 | |||
399 | static void xcopy_pt_release_cmd(struct se_cmd *se_cmd) | ||
400 | { | ||
401 | struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd, | ||
402 | struct xcopy_pt_cmd, se_cmd); | ||
403 | |||
404 | if (xpt_cmd->remote_port) | ||
405 | kfree(se_cmd->se_lun); | ||
406 | |||
407 | kfree(xpt_cmd); | ||
408 | } | ||
409 | |||
410 | static int xcopy_pt_check_stop_free(struct se_cmd *se_cmd) | ||
411 | { | ||
412 | struct xcopy_pt_cmd *xpt_cmd = container_of(se_cmd, | ||
413 | struct xcopy_pt_cmd, se_cmd); | ||
414 | |||
415 | complete(&xpt_cmd->xpt_passthrough_sem); | ||
416 | return 0; | ||
417 | } | ||
418 | |||
419 | static int xcopy_pt_write_pending(struct se_cmd *se_cmd) | ||
420 | { | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int xcopy_pt_write_pending_status(struct se_cmd *se_cmd) | ||
425 | { | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | static int xcopy_pt_queue_data_in(struct se_cmd *se_cmd) | ||
430 | { | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | static int xcopy_pt_queue_status(struct se_cmd *se_cmd) | ||
435 | { | ||
436 | return 0; | ||
437 | } | ||
438 | |||
439 | static struct target_core_fabric_ops xcopy_pt_tfo = { | ||
440 | .get_fabric_name = xcopy_pt_get_fabric_name, | ||
441 | .get_task_tag = xcopy_pt_get_tag, | ||
442 | .get_cmd_state = xcopy_pt_get_cmd_state, | ||
443 | .release_cmd = xcopy_pt_release_cmd, | ||
444 | .check_stop_free = xcopy_pt_check_stop_free, | ||
445 | .write_pending = xcopy_pt_write_pending, | ||
446 | .write_pending_status = xcopy_pt_write_pending_status, | ||
447 | .queue_data_in = xcopy_pt_queue_data_in, | ||
448 | .queue_status = xcopy_pt_queue_status, | ||
449 | }; | ||
450 | |||
451 | /* | ||
452 | * End xcopy_pt_ops | ||
453 | */ | ||
454 | |||
455 | int target_xcopy_setup_pt(void) | ||
456 | { | ||
457 | xcopy_wq = alloc_workqueue("xcopy_wq", WQ_MEM_RECLAIM, 0); | ||
458 | if (!xcopy_wq) { | ||
459 | pr_err("Unable to allocate xcopy_wq\n"); | ||
460 | return -ENOMEM; | ||
461 | } | ||
462 | |||
463 | memset(&xcopy_pt_port, 0, sizeof(struct se_port)); | ||
464 | INIT_LIST_HEAD(&xcopy_pt_port.sep_alua_list); | ||
465 | INIT_LIST_HEAD(&xcopy_pt_port.sep_list); | ||
466 | mutex_init(&xcopy_pt_port.sep_tg_pt_md_mutex); | ||
467 | |||
468 | memset(&xcopy_pt_tpg, 0, sizeof(struct se_portal_group)); | ||
469 | INIT_LIST_HEAD(&xcopy_pt_tpg.se_tpg_node); | ||
470 | INIT_LIST_HEAD(&xcopy_pt_tpg.acl_node_list); | ||
471 | INIT_LIST_HEAD(&xcopy_pt_tpg.tpg_sess_list); | ||
472 | |||
473 | xcopy_pt_port.sep_tpg = &xcopy_pt_tpg; | ||
474 | xcopy_pt_tpg.se_tpg_tfo = &xcopy_pt_tfo; | ||
475 | |||
476 | memset(&xcopy_pt_nacl, 0, sizeof(struct se_node_acl)); | ||
477 | INIT_LIST_HEAD(&xcopy_pt_nacl.acl_list); | ||
478 | INIT_LIST_HEAD(&xcopy_pt_nacl.acl_sess_list); | ||
479 | memset(&xcopy_pt_sess, 0, sizeof(struct se_session)); | ||
480 | INIT_LIST_HEAD(&xcopy_pt_sess.sess_list); | ||
481 | INIT_LIST_HEAD(&xcopy_pt_sess.sess_acl_list); | ||
482 | |||
483 | xcopy_pt_nacl.se_tpg = &xcopy_pt_tpg; | ||
484 | xcopy_pt_nacl.nacl_sess = &xcopy_pt_sess; | ||
485 | |||
486 | xcopy_pt_sess.se_tpg = &xcopy_pt_tpg; | ||
487 | xcopy_pt_sess.se_node_acl = &xcopy_pt_nacl; | ||
488 | |||
489 | return 0; | ||
490 | } | ||
491 | |||
492 | void target_xcopy_release_pt(void) | ||
493 | { | ||
494 | if (xcopy_wq) | ||
495 | destroy_workqueue(xcopy_wq); | ||
496 | } | ||
497 | |||
498 | static void target_xcopy_setup_pt_port( | ||
499 | struct xcopy_pt_cmd *xpt_cmd, | ||
500 | struct xcopy_op *xop, | ||
501 | bool remote_port) | ||
502 | { | ||
503 | struct se_cmd *ec_cmd = xop->xop_se_cmd; | ||
504 | struct se_cmd *pt_cmd = &xpt_cmd->se_cmd; | ||
505 | |||
506 | if (xop->op_origin == XCOL_SOURCE_RECV_OP) { | ||
507 | /* | ||
508 | * Honor destination port reservations for X-COPY PUSH emulation | ||
509 | * when CDB is received on local source port, and READs blocks to | ||
510 | * WRITE on remote destination port. | ||
511 | */ | ||
512 | if (remote_port) { | ||
513 | xpt_cmd->remote_port = remote_port; | ||
514 | pt_cmd->se_lun->lun_sep = &xcopy_pt_port; | ||
515 | pr_debug("Setup emulated remote DEST xcopy_pt_port: %p to" | ||
516 | " cmd->se_lun->lun_sep for X-COPY data PUSH\n", | ||
517 | pt_cmd->se_lun->lun_sep); | ||
518 | } else { | ||
519 | pt_cmd->se_lun = ec_cmd->se_lun; | ||
520 | pt_cmd->se_dev = ec_cmd->se_dev; | ||
521 | |||
522 | pr_debug("Honoring local SRC port from ec_cmd->se_dev:" | ||
523 | " %p\n", pt_cmd->se_dev); | ||
524 | pt_cmd->se_lun = ec_cmd->se_lun; | ||
525 | pr_debug("Honoring local SRC port from ec_cmd->se_lun: %p\n", | ||
526 | pt_cmd->se_lun); | ||
527 | } | ||
528 | } else { | ||
529 | /* | ||
530 | * Honor source port reservation for X-COPY PULL emulation | ||
531 | * when CDB is received on local desintation port, and READs | ||
532 | * blocks from the remote source port to WRITE on local | ||
533 | * destination port. | ||
534 | */ | ||
535 | if (remote_port) { | ||
536 | xpt_cmd->remote_port = remote_port; | ||
537 | pt_cmd->se_lun->lun_sep = &xcopy_pt_port; | ||
538 | pr_debug("Setup emulated remote SRC xcopy_pt_port: %p to" | ||
539 | " cmd->se_lun->lun_sep for X-COPY data PULL\n", | ||
540 | pt_cmd->se_lun->lun_sep); | ||
541 | } else { | ||
542 | pt_cmd->se_lun = ec_cmd->se_lun; | ||
543 | pt_cmd->se_dev = ec_cmd->se_dev; | ||
544 | |||
545 | pr_debug("Honoring local DST port from ec_cmd->se_dev:" | ||
546 | " %p\n", pt_cmd->se_dev); | ||
547 | pt_cmd->se_lun = ec_cmd->se_lun; | ||
548 | pr_debug("Honoring local DST port from ec_cmd->se_lun: %p\n", | ||
549 | pt_cmd->se_lun); | ||
550 | } | ||
551 | } | ||
552 | } | ||
553 | |||
554 | static int target_xcopy_init_pt_lun( | ||
555 | struct xcopy_pt_cmd *xpt_cmd, | ||
556 | struct xcopy_op *xop, | ||
557 | struct se_device *se_dev, | ||
558 | struct se_cmd *pt_cmd, | ||
559 | bool remote_port) | ||
560 | { | ||
561 | /* | ||
562 | * Don't allocate + init an pt_cmd->se_lun if honoring local port for | ||
563 | * reservations. The pt_cmd->se_lun pointer will be setup from within | ||
564 | * target_xcopy_setup_pt_port() | ||
565 | */ | ||
566 | if (remote_port == false) { | ||
567 | pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; | ||
568 | return 0; | ||
569 | } | ||
570 | |||
571 | pt_cmd->se_lun = kzalloc(sizeof(struct se_lun), GFP_KERNEL); | ||
572 | if (!pt_cmd->se_lun) { | ||
573 | pr_err("Unable to allocate pt_cmd->se_lun\n"); | ||
574 | return -ENOMEM; | ||
575 | } | ||
576 | init_completion(&pt_cmd->se_lun->lun_shutdown_comp); | ||
577 | INIT_LIST_HEAD(&pt_cmd->se_lun->lun_cmd_list); | ||
578 | INIT_LIST_HEAD(&pt_cmd->se_lun->lun_acl_list); | ||
579 | spin_lock_init(&pt_cmd->se_lun->lun_acl_lock); | ||
580 | spin_lock_init(&pt_cmd->se_lun->lun_cmd_lock); | ||
581 | spin_lock_init(&pt_cmd->se_lun->lun_sep_lock); | ||
582 | |||
583 | pt_cmd->se_dev = se_dev; | ||
584 | |||
585 | pr_debug("Setup emulated se_dev: %p from se_dev\n", pt_cmd->se_dev); | ||
586 | pt_cmd->se_lun->lun_se_dev = se_dev; | ||
587 | pt_cmd->se_cmd_flags |= SCF_SE_LUN_CMD | SCF_CMD_XCOPY_PASSTHROUGH; | ||
588 | |||
589 | pr_debug("Setup emulated se_dev: %p to pt_cmd->se_lun->lun_se_dev\n", | ||
590 | pt_cmd->se_lun->lun_se_dev); | ||
591 | |||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int target_xcopy_setup_pt_cmd( | ||
596 | struct xcopy_pt_cmd *xpt_cmd, | ||
597 | struct xcopy_op *xop, | ||
598 | struct se_device *se_dev, | ||
599 | unsigned char *cdb, | ||
600 | bool remote_port, | ||
601 | bool alloc_mem) | ||
602 | { | ||
603 | struct se_cmd *cmd = &xpt_cmd->se_cmd; | ||
604 | sense_reason_t sense_rc; | ||
605 | int ret = 0, rc; | ||
606 | /* | ||
607 | * Setup LUN+port to honor reservations based upon xop->op_origin for | ||
608 | * X-COPY PUSH or X-COPY PULL based upon where the CDB was received. | ||
609 | */ | ||
610 | rc = target_xcopy_init_pt_lun(xpt_cmd, xop, se_dev, cmd, remote_port); | ||
611 | if (rc < 0) { | ||
612 | ret = rc; | ||
613 | goto out; | ||
614 | } | ||
615 | xpt_cmd->xcopy_op = xop; | ||
616 | target_xcopy_setup_pt_port(xpt_cmd, xop, remote_port); | ||
617 | |||
618 | sense_rc = target_setup_cmd_from_cdb(cmd, cdb); | ||
619 | if (sense_rc) { | ||
620 | ret = -EINVAL; | ||
621 | goto out; | ||
622 | } | ||
623 | |||
624 | if (alloc_mem) { | ||
625 | rc = target_alloc_sgl(&cmd->t_data_sg, &cmd->t_data_nents, | ||
626 | cmd->data_length, false); | ||
627 | if (rc < 0) { | ||
628 | ret = rc; | ||
629 | goto out; | ||
630 | } | ||
631 | /* | ||
632 | * Set this bit so that transport_free_pages() allows the | ||
633 | * caller to release SGLs + physical memory allocated by | ||
634 | * transport_generic_get_mem().. | ||
635 | */ | ||
636 | cmd->se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; | ||
637 | } else { | ||
638 | /* | ||
639 | * Here the previously allocated SGLs for the internal READ | ||
640 | * are mapped zero-copy to the internal WRITE. | ||
641 | */ | ||
642 | sense_rc = transport_generic_map_mem_to_cmd(cmd, | ||
643 | xop->xop_data_sg, xop->xop_data_nents, | ||
644 | NULL, 0); | ||
645 | if (sense_rc) { | ||
646 | ret = -EINVAL; | ||
647 | goto out; | ||
648 | } | ||
649 | |||
650 | pr_debug("Setup PASSTHROUGH_NOALLOC t_data_sg: %p t_data_nents:" | ||
651 | " %u\n", cmd->t_data_sg, cmd->t_data_nents); | ||
652 | } | ||
653 | |||
654 | return 0; | ||
655 | |||
656 | out: | ||
657 | if (remote_port == true) | ||
658 | kfree(cmd->se_lun); | ||
659 | return ret; | ||
660 | } | ||
661 | |||
662 | static int target_xcopy_issue_pt_cmd(struct xcopy_pt_cmd *xpt_cmd) | ||
663 | { | ||
664 | struct se_cmd *se_cmd = &xpt_cmd->se_cmd; | ||
665 | sense_reason_t sense_rc; | ||
666 | |||
667 | sense_rc = transport_generic_new_cmd(se_cmd); | ||
668 | if (sense_rc) | ||
669 | return -EINVAL; | ||
670 | |||
671 | if (se_cmd->data_direction == DMA_TO_DEVICE) | ||
672 | target_execute_cmd(se_cmd); | ||
673 | |||
674 | wait_for_completion_interruptible(&xpt_cmd->xpt_passthrough_sem); | ||
675 | |||
676 | pr_debug("target_xcopy_issue_pt_cmd(): SCSI status: 0x%02x\n", | ||
677 | se_cmd->scsi_status); | ||
678 | return 0; | ||
679 | } | ||
680 | |||
681 | static int target_xcopy_read_source( | ||
682 | struct se_cmd *ec_cmd, | ||
683 | struct xcopy_op *xop, | ||
684 | struct se_device *src_dev, | ||
685 | sector_t src_lba, | ||
686 | u32 src_sectors) | ||
687 | { | ||
688 | struct xcopy_pt_cmd *xpt_cmd; | ||
689 | struct se_cmd *se_cmd; | ||
690 | u32 length = (src_sectors * src_dev->dev_attrib.block_size); | ||
691 | int rc; | ||
692 | unsigned char cdb[16]; | ||
693 | bool remote_port = (xop->op_origin == XCOL_DEST_RECV_OP); | ||
694 | |||
695 | xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL); | ||
696 | if (!xpt_cmd) { | ||
697 | pr_err("Unable to allocate xcopy_pt_cmd\n"); | ||
698 | return -ENOMEM; | ||
699 | } | ||
700 | init_completion(&xpt_cmd->xpt_passthrough_sem); | ||
701 | se_cmd = &xpt_cmd->se_cmd; | ||
702 | |||
703 | memset(&cdb[0], 0, 16); | ||
704 | cdb[0] = READ_16; | ||
705 | put_unaligned_be64(src_lba, &cdb[2]); | ||
706 | put_unaligned_be32(src_sectors, &cdb[10]); | ||
707 | pr_debug("XCOPY: Built READ_16: LBA: %llu Sectors: %u Length: %u\n", | ||
708 | (unsigned long long)src_lba, src_sectors, length); | ||
709 | |||
710 | transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length, | ||
711 | DMA_FROM_DEVICE, 0, NULL); | ||
712 | xop->src_pt_cmd = xpt_cmd; | ||
713 | |||
714 | rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, src_dev, &cdb[0], | ||
715 | remote_port, true); | ||
716 | if (rc < 0) { | ||
717 | transport_generic_free_cmd(se_cmd, 0); | ||
718 | return rc; | ||
719 | } | ||
720 | |||
721 | xop->xop_data_sg = se_cmd->t_data_sg; | ||
722 | xop->xop_data_nents = se_cmd->t_data_nents; | ||
723 | pr_debug("XCOPY-READ: Saved xop->xop_data_sg: %p, num: %u for READ" | ||
724 | " memory\n", xop->xop_data_sg, xop->xop_data_nents); | ||
725 | |||
726 | rc = target_xcopy_issue_pt_cmd(xpt_cmd); | ||
727 | if (rc < 0) { | ||
728 | transport_generic_free_cmd(se_cmd, 0); | ||
729 | return rc; | ||
730 | } | ||
731 | /* | ||
732 | * Clear off the allocated t_data_sg, that has been saved for | ||
733 | * zero-copy WRITE submission reuse in struct xcopy_op.. | ||
734 | */ | ||
735 | se_cmd->t_data_sg = NULL; | ||
736 | se_cmd->t_data_nents = 0; | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | static int target_xcopy_write_destination( | ||
742 | struct se_cmd *ec_cmd, | ||
743 | struct xcopy_op *xop, | ||
744 | struct se_device *dst_dev, | ||
745 | sector_t dst_lba, | ||
746 | u32 dst_sectors) | ||
747 | { | ||
748 | struct xcopy_pt_cmd *xpt_cmd; | ||
749 | struct se_cmd *se_cmd; | ||
750 | u32 length = (dst_sectors * dst_dev->dev_attrib.block_size); | ||
751 | int rc; | ||
752 | unsigned char cdb[16]; | ||
753 | bool remote_port = (xop->op_origin == XCOL_SOURCE_RECV_OP); | ||
754 | |||
755 | xpt_cmd = kzalloc(sizeof(struct xcopy_pt_cmd), GFP_KERNEL); | ||
756 | if (!xpt_cmd) { | ||
757 | pr_err("Unable to allocate xcopy_pt_cmd\n"); | ||
758 | return -ENOMEM; | ||
759 | } | ||
760 | init_completion(&xpt_cmd->xpt_passthrough_sem); | ||
761 | se_cmd = &xpt_cmd->se_cmd; | ||
762 | |||
763 | memset(&cdb[0], 0, 16); | ||
764 | cdb[0] = WRITE_16; | ||
765 | put_unaligned_be64(dst_lba, &cdb[2]); | ||
766 | put_unaligned_be32(dst_sectors, &cdb[10]); | ||
767 | pr_debug("XCOPY: Built WRITE_16: LBA: %llu Sectors: %u Length: %u\n", | ||
768 | (unsigned long long)dst_lba, dst_sectors, length); | ||
769 | |||
770 | transport_init_se_cmd(se_cmd, &xcopy_pt_tfo, NULL, length, | ||
771 | DMA_TO_DEVICE, 0, NULL); | ||
772 | xop->dst_pt_cmd = xpt_cmd; | ||
773 | |||
774 | rc = target_xcopy_setup_pt_cmd(xpt_cmd, xop, dst_dev, &cdb[0], | ||
775 | remote_port, false); | ||
776 | if (rc < 0) { | ||
777 | struct se_cmd *src_cmd = &xop->src_pt_cmd->se_cmd; | ||
778 | /* | ||
779 | * If the failure happened before the t_mem_list hand-off in | ||
780 | * target_xcopy_setup_pt_cmd(), Reset memory + clear flag so that | ||
781 | * core releases this memory on error during X-COPY WRITE I/O. | ||
782 | */ | ||
783 | src_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; | ||
784 | src_cmd->t_data_sg = xop->xop_data_sg; | ||
785 | src_cmd->t_data_nents = xop->xop_data_nents; | ||
786 | |||
787 | transport_generic_free_cmd(se_cmd, 0); | ||
788 | return rc; | ||
789 | } | ||
790 | |||
791 | rc = target_xcopy_issue_pt_cmd(xpt_cmd); | ||
792 | if (rc < 0) { | ||
793 | se_cmd->se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; | ||
794 | transport_generic_free_cmd(se_cmd, 0); | ||
795 | return rc; | ||
796 | } | ||
797 | |||
798 | return 0; | ||
799 | } | ||
800 | |||
801 | static void target_xcopy_do_work(struct work_struct *work) | ||
802 | { | ||
803 | struct xcopy_op *xop = container_of(work, struct xcopy_op, xop_work); | ||
804 | struct se_device *src_dev = xop->src_dev, *dst_dev = xop->dst_dev; | ||
805 | struct se_cmd *ec_cmd = xop->xop_se_cmd; | ||
806 | sector_t src_lba = xop->src_lba, dst_lba = xop->dst_lba, end_lba; | ||
807 | unsigned int max_sectors; | ||
808 | int rc; | ||
809 | unsigned short nolb = xop->nolb, cur_nolb, max_nolb, copied_nolb = 0; | ||
810 | |||
811 | end_lba = src_lba + nolb; | ||
812 | /* | ||
813 | * Break up XCOPY I/O into hw_max_sectors sized I/O based on the | ||
814 | * smallest max_sectors between src_dev + dev_dev, or | ||
815 | */ | ||
816 | max_sectors = min(src_dev->dev_attrib.hw_max_sectors, | ||
817 | dst_dev->dev_attrib.hw_max_sectors); | ||
818 | max_sectors = min_t(u32, max_sectors, XCOPY_MAX_SECTORS); | ||
819 | |||
820 | max_nolb = min_t(u16, max_sectors, ((u16)(~0U))); | ||
821 | |||
822 | pr_debug("target_xcopy_do_work: nolb: %hu, max_nolb: %hu end_lba: %llu\n", | ||
823 | nolb, max_nolb, (unsigned long long)end_lba); | ||
824 | pr_debug("target_xcopy_do_work: Starting src_lba: %llu, dst_lba: %llu\n", | ||
825 | (unsigned long long)src_lba, (unsigned long long)dst_lba); | ||
826 | |||
827 | while (src_lba < end_lba) { | ||
828 | cur_nolb = min(nolb, max_nolb); | ||
829 | |||
830 | pr_debug("target_xcopy_do_work: Calling read src_dev: %p src_lba: %llu," | ||
831 | " cur_nolb: %hu\n", src_dev, (unsigned long long)src_lba, cur_nolb); | ||
832 | |||
833 | rc = target_xcopy_read_source(ec_cmd, xop, src_dev, src_lba, cur_nolb); | ||
834 | if (rc < 0) | ||
835 | goto out; | ||
836 | |||
837 | src_lba += cur_nolb; | ||
838 | pr_debug("target_xcopy_do_work: Incremented READ src_lba to %llu\n", | ||
839 | (unsigned long long)src_lba); | ||
840 | |||
841 | pr_debug("target_xcopy_do_work: Calling write dst_dev: %p dst_lba: %llu," | ||
842 | " cur_nolb: %hu\n", dst_dev, (unsigned long long)dst_lba, cur_nolb); | ||
843 | |||
844 | rc = target_xcopy_write_destination(ec_cmd, xop, dst_dev, | ||
845 | dst_lba, cur_nolb); | ||
846 | if (rc < 0) { | ||
847 | transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0); | ||
848 | goto out; | ||
849 | } | ||
850 | |||
851 | dst_lba += cur_nolb; | ||
852 | pr_debug("target_xcopy_do_work: Incremented WRITE dst_lba to %llu\n", | ||
853 | (unsigned long long)dst_lba); | ||
854 | |||
855 | copied_nolb += cur_nolb; | ||
856 | nolb -= cur_nolb; | ||
857 | |||
858 | transport_generic_free_cmd(&xop->src_pt_cmd->se_cmd, 0); | ||
859 | xop->dst_pt_cmd->se_cmd.se_cmd_flags &= ~SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; | ||
860 | |||
861 | transport_generic_free_cmd(&xop->dst_pt_cmd->se_cmd, 0); | ||
862 | } | ||
863 | |||
864 | xcopy_pt_undepend_remotedev(xop); | ||
865 | kfree(xop); | ||
866 | |||
867 | pr_debug("target_xcopy_do_work: Final src_lba: %llu, dst_lba: %llu\n", | ||
868 | (unsigned long long)src_lba, (unsigned long long)dst_lba); | ||
869 | pr_debug("target_xcopy_do_work: Blocks copied: %hu, Bytes Copied: %u\n", | ||
870 | copied_nolb, copied_nolb * dst_dev->dev_attrib.block_size); | ||
871 | |||
872 | pr_debug("target_xcopy_do_work: Setting X-COPY GOOD status -> sending response\n"); | ||
873 | target_complete_cmd(ec_cmd, SAM_STAT_GOOD); | ||
874 | return; | ||
875 | |||
876 | out: | ||
877 | xcopy_pt_undepend_remotedev(xop); | ||
878 | kfree(xop); | ||
879 | |||
880 | pr_warn("target_xcopy_do_work: Setting X-COPY CHECK_CONDITION -> sending response\n"); | ||
881 | ec_cmd->scsi_status = SAM_STAT_CHECK_CONDITION; | ||
882 | target_complete_cmd(ec_cmd, SAM_STAT_CHECK_CONDITION); | ||
883 | } | ||
884 | |||
885 | sense_reason_t target_do_xcopy(struct se_cmd *se_cmd) | ||
886 | { | ||
887 | struct xcopy_op *xop = NULL; | ||
888 | unsigned char *p = NULL, *seg_desc; | ||
889 | unsigned int list_id, list_id_usage, sdll, inline_dl, sa; | ||
890 | int rc; | ||
891 | unsigned short tdll; | ||
892 | |||
893 | sa = se_cmd->t_task_cdb[1] & 0x1f; | ||
894 | if (sa != 0x00) { | ||
895 | pr_err("EXTENDED_COPY(LID4) not supported\n"); | ||
896 | return TCM_UNSUPPORTED_SCSI_OPCODE; | ||
897 | } | ||
898 | |||
899 | p = transport_kmap_data_sg(se_cmd); | ||
900 | if (!p) { | ||
901 | pr_err("transport_kmap_data_sg() failed in target_do_xcopy\n"); | ||
902 | return TCM_OUT_OF_RESOURCES; | ||
903 | } | ||
904 | |||
905 | list_id = p[0]; | ||
906 | if (list_id != 0x00) { | ||
907 | pr_err("XCOPY with non zero list_id: 0x%02x\n", list_id); | ||
908 | goto out; | ||
909 | } | ||
910 | list_id_usage = (p[1] & 0x18); | ||
911 | /* | ||
912 | * Determine TARGET DESCRIPTOR LIST LENGTH + SEGMENT DESCRIPTOR LIST LENGTH | ||
913 | */ | ||
914 | tdll = get_unaligned_be16(&p[2]); | ||
915 | sdll = get_unaligned_be32(&p[8]); | ||
916 | |||
917 | inline_dl = get_unaligned_be32(&p[12]); | ||
918 | if (inline_dl != 0) { | ||
919 | pr_err("XCOPY with non zero inline data length\n"); | ||
920 | goto out; | ||
921 | } | ||
922 | |||
923 | xop = kzalloc(sizeof(struct xcopy_op), GFP_KERNEL); | ||
924 | if (!xop) { | ||
925 | pr_err("Unable to allocate xcopy_op\n"); | ||
926 | goto out; | ||
927 | } | ||
928 | xop->xop_se_cmd = se_cmd; | ||
929 | |||
930 | pr_debug("Processing XCOPY with list_id: 0x%02x list_id_usage: 0x%02x" | ||
931 | " tdll: %hu sdll: %u inline_dl: %u\n", list_id, list_id_usage, | ||
932 | tdll, sdll, inline_dl); | ||
933 | |||
934 | rc = target_xcopy_parse_target_descriptors(se_cmd, xop, &p[16], tdll); | ||
935 | if (rc <= 0) | ||
936 | goto out; | ||
937 | |||
938 | pr_debug("XCOPY: Processed %d target descriptors, length: %u\n", rc, | ||
939 | rc * XCOPY_TARGET_DESC_LEN); | ||
940 | seg_desc = &p[16]; | ||
941 | seg_desc += (rc * XCOPY_TARGET_DESC_LEN); | ||
942 | |||
943 | rc = target_xcopy_parse_segment_descriptors(se_cmd, xop, seg_desc, sdll); | ||
944 | if (rc <= 0) { | ||
945 | xcopy_pt_undepend_remotedev(xop); | ||
946 | goto out; | ||
947 | } | ||
948 | transport_kunmap_data_sg(se_cmd); | ||
949 | |||
950 | pr_debug("XCOPY: Processed %d segment descriptors, length: %u\n", rc, | ||
951 | rc * XCOPY_SEGMENT_DESC_LEN); | ||
952 | INIT_WORK(&xop->xop_work, target_xcopy_do_work); | ||
953 | queue_work(xcopy_wq, &xop->xop_work); | ||
954 | return TCM_NO_SENSE; | ||
955 | |||
956 | out: | ||
957 | if (p) | ||
958 | transport_kunmap_data_sg(se_cmd); | ||
959 | kfree(xop); | ||
960 | return TCM_INVALID_CDB_FIELD; | ||
961 | } | ||
962 | |||
963 | static sense_reason_t target_rcr_operating_parameters(struct se_cmd *se_cmd) | ||
964 | { | ||
965 | unsigned char *p; | ||
966 | |||
967 | p = transport_kmap_data_sg(se_cmd); | ||
968 | if (!p) { | ||
969 | pr_err("transport_kmap_data_sg failed in" | ||
970 | " target_rcr_operating_parameters\n"); | ||
971 | return TCM_OUT_OF_RESOURCES; | ||
972 | } | ||
973 | |||
974 | if (se_cmd->data_length < 54) { | ||
975 | pr_err("Receive Copy Results Op Parameters length" | ||
976 | " too small: %u\n", se_cmd->data_length); | ||
977 | transport_kunmap_data_sg(se_cmd); | ||
978 | return TCM_INVALID_CDB_FIELD; | ||
979 | } | ||
980 | /* | ||
981 | * Set SNLID=1 (Supports no List ID) | ||
982 | */ | ||
983 | p[4] = 0x1; | ||
984 | /* | ||
985 | * MAXIMUM TARGET DESCRIPTOR COUNT | ||
986 | */ | ||
987 | put_unaligned_be16(RCR_OP_MAX_TARGET_DESC_COUNT, &p[8]); | ||
988 | /* | ||
989 | * MAXIMUM SEGMENT DESCRIPTOR COUNT | ||
990 | */ | ||
991 | put_unaligned_be16(RCR_OP_MAX_SG_DESC_COUNT, &p[10]); | ||
992 | /* | ||
993 | * MAXIMUM DESCRIPTOR LIST LENGTH | ||
994 | */ | ||
995 | put_unaligned_be32(RCR_OP_MAX_DESC_LIST_LEN, &p[12]); | ||
996 | /* | ||
997 | * MAXIMUM SEGMENT LENGTH | ||
998 | */ | ||
999 | put_unaligned_be32(RCR_OP_MAX_SEGMENT_LEN, &p[16]); | ||
1000 | /* | ||
1001 | * MAXIMUM INLINE DATA LENGTH for SA 0x04 (NOT SUPPORTED) | ||
1002 | */ | ||
1003 | put_unaligned_be32(0x0, &p[20]); | ||
1004 | /* | ||
1005 | * HELD DATA LIMIT | ||
1006 | */ | ||
1007 | put_unaligned_be32(0x0, &p[24]); | ||
1008 | /* | ||
1009 | * MAXIMUM STREAM DEVICE TRANSFER SIZE | ||
1010 | */ | ||
1011 | put_unaligned_be32(0x0, &p[28]); | ||
1012 | /* | ||
1013 | * TOTAL CONCURRENT COPIES | ||
1014 | */ | ||
1015 | put_unaligned_be16(RCR_OP_TOTAL_CONCURR_COPIES, &p[34]); | ||
1016 | /* | ||
1017 | * MAXIMUM CONCURRENT COPIES | ||
1018 | */ | ||
1019 | p[36] = RCR_OP_MAX_CONCURR_COPIES; | ||
1020 | /* | ||
1021 | * DATA SEGMENT GRANULARITY (log 2) | ||
1022 | */ | ||
1023 | p[37] = RCR_OP_DATA_SEG_GRAN_LOG2; | ||
1024 | /* | ||
1025 | * INLINE DATA GRANULARITY log 2) | ||
1026 | */ | ||
1027 | p[38] = RCR_OP_INLINE_DATA_GRAN_LOG2; | ||
1028 | /* | ||
1029 | * HELD DATA GRANULARITY | ||
1030 | */ | ||
1031 | p[39] = RCR_OP_HELD_DATA_GRAN_LOG2; | ||
1032 | /* | ||
1033 | * IMPLEMENTED DESCRIPTOR LIST LENGTH | ||
1034 | */ | ||
1035 | p[43] = 0x2; | ||
1036 | /* | ||
1037 | * List of implemented descriptor type codes (ordered) | ||
1038 | */ | ||
1039 | p[44] = 0x02; /* Copy Block to Block device */ | ||
1040 | p[45] = 0xe4; /* Identification descriptor target descriptor */ | ||
1041 | |||
1042 | /* | ||
1043 | * AVAILABLE DATA (n-3) | ||
1044 | */ | ||
1045 | put_unaligned_be32(42, &p[0]); | ||
1046 | |||
1047 | transport_kunmap_data_sg(se_cmd); | ||
1048 | target_complete_cmd(se_cmd, GOOD); | ||
1049 | |||
1050 | return TCM_NO_SENSE; | ||
1051 | } | ||
1052 | |||
1053 | sense_reason_t target_do_receive_copy_results(struct se_cmd *se_cmd) | ||
1054 | { | ||
1055 | unsigned char *cdb = &se_cmd->t_task_cdb[0]; | ||
1056 | int sa = (cdb[1] & 0x1f), list_id = cdb[2]; | ||
1057 | sense_reason_t rc = TCM_NO_SENSE; | ||
1058 | |||
1059 | pr_debug("Entering target_do_receive_copy_results: SA: 0x%02x, List ID:" | ||
1060 | " 0x%02x, AL: %u\n", sa, list_id, se_cmd->data_length); | ||
1061 | |||
1062 | if (list_id != 0) { | ||
1063 | pr_err("Receive Copy Results with non zero list identifier" | ||
1064 | " not supported\n"); | ||
1065 | return TCM_INVALID_CDB_FIELD; | ||
1066 | } | ||
1067 | |||
1068 | switch (sa) { | ||
1069 | case RCR_SA_OPERATING_PARAMETERS: | ||
1070 | rc = target_rcr_operating_parameters(se_cmd); | ||
1071 | break; | ||
1072 | case RCR_SA_COPY_STATUS: | ||
1073 | case RCR_SA_RECEIVE_DATA: | ||
1074 | case RCR_SA_FAILED_SEGMENT_DETAILS: | ||
1075 | default: | ||
1076 | pr_err("Unsupported SA for receive copy results: 0x%02x\n", sa); | ||
1077 | return TCM_INVALID_CDB_FIELD; | ||
1078 | } | ||
1079 | |||
1080 | return rc; | ||
1081 | } | ||
diff --git a/drivers/target/target_core_xcopy.h b/drivers/target/target_core_xcopy.h new file mode 100644 index 000000000000..700a981c7b41 --- /dev/null +++ b/drivers/target/target_core_xcopy.h | |||
@@ -0,0 +1,62 @@ | |||
1 | #define XCOPY_TARGET_DESC_LEN 32 | ||
2 | #define XCOPY_SEGMENT_DESC_LEN 28 | ||
3 | #define XCOPY_NAA_IEEE_REGEX_LEN 16 | ||
4 | #define XCOPY_MAX_SECTORS 1024 | ||
5 | |||
6 | enum xcopy_origin_list { | ||
7 | XCOL_SOURCE_RECV_OP = 0x01, | ||
8 | XCOL_DEST_RECV_OP = 0x02, | ||
9 | }; | ||
10 | |||
11 | struct xcopy_pt_cmd; | ||
12 | |||
13 | struct xcopy_op { | ||
14 | int op_origin; | ||
15 | |||
16 | struct se_cmd *xop_se_cmd; | ||
17 | struct se_device *src_dev; | ||
18 | unsigned char src_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; | ||
19 | struct se_device *dst_dev; | ||
20 | unsigned char dst_tid_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; | ||
21 | unsigned char local_dev_wwn[XCOPY_NAA_IEEE_REGEX_LEN]; | ||
22 | |||
23 | sector_t src_lba; | ||
24 | sector_t dst_lba; | ||
25 | unsigned short stdi; | ||
26 | unsigned short dtdi; | ||
27 | unsigned short nolb; | ||
28 | unsigned int dbl; | ||
29 | |||
30 | struct xcopy_pt_cmd *src_pt_cmd; | ||
31 | struct xcopy_pt_cmd *dst_pt_cmd; | ||
32 | |||
33 | u32 xop_data_nents; | ||
34 | struct scatterlist *xop_data_sg; | ||
35 | struct work_struct xop_work; | ||
36 | }; | ||
37 | |||
38 | /* | ||
39 | * Receive Copy Results Sevice Actions | ||
40 | */ | ||
41 | #define RCR_SA_COPY_STATUS 0x00 | ||
42 | #define RCR_SA_RECEIVE_DATA 0x01 | ||
43 | #define RCR_SA_OPERATING_PARAMETERS 0x03 | ||
44 | #define RCR_SA_FAILED_SEGMENT_DETAILS 0x04 | ||
45 | |||
46 | /* | ||
47 | * Receive Copy Results defs for Operating Parameters | ||
48 | */ | ||
49 | #define RCR_OP_MAX_TARGET_DESC_COUNT 0x2 | ||
50 | #define RCR_OP_MAX_SG_DESC_COUNT 0x1 | ||
51 | #define RCR_OP_MAX_DESC_LIST_LEN 1024 | ||
52 | #define RCR_OP_MAX_SEGMENT_LEN 268435456 /* 256 MB */ | ||
53 | #define RCR_OP_TOTAL_CONCURR_COPIES 0x1 /* Must be <= 16384 */ | ||
54 | #define RCR_OP_MAX_CONCURR_COPIES 0x1 /* Must be <= 255 */ | ||
55 | #define RCR_OP_DATA_SEG_GRAN_LOG2 9 /* 512 bytes in log 2 */ | ||
56 | #define RCR_OP_INLINE_DATA_GRAN_LOG2 9 /* 512 bytes in log 2 */ | ||
57 | #define RCR_OP_HELD_DATA_GRAN_LOG2 9 /* 512 bytes in log 2 */ | ||
58 | |||
59 | extern int target_xcopy_setup_pt(void); | ||
60 | extern void target_xcopy_release_pt(void); | ||
61 | extern sense_reason_t target_do_xcopy(struct se_cmd *); | ||
62 | extern sense_reason_t target_do_receive_copy_results(struct se_cmd *); | ||
diff --git a/drivers/target/tcm_fc/tfc_conf.c b/drivers/target/tcm_fc/tfc_conf.c index b74feb0d5133..4e0050840a72 100644 --- a/drivers/target/tcm_fc/tfc_conf.c +++ b/drivers/target/tcm_fc/tfc_conf.c | |||
@@ -311,7 +311,11 @@ static struct se_portal_group *ft_add_tpg( | |||
311 | */ | 311 | */ |
312 | if (strstr(name, "tpgt_") != name) | 312 | if (strstr(name, "tpgt_") != name) |
313 | return NULL; | 313 | return NULL; |
314 | if (strict_strtoul(name + 5, 10, &index) || index > UINT_MAX) | 314 | |
315 | ret = kstrtoul(name + 5, 10, &index); | ||
316 | if (ret) | ||
317 | return NULL; | ||
318 | if (index > UINT_MAX) | ||
315 | return NULL; | 319 | return NULL; |
316 | 320 | ||
317 | lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); | 321 | lacl = container_of(wwn, struct ft_lport_acl, fc_lport_wwn); |