diff options
Diffstat (limited to 'drivers/target')
26 files changed, 1653 insertions, 965 deletions
diff --git a/drivers/target/iscsi/Makefile b/drivers/target/iscsi/Makefile index 5b9a2cf7f0a9..13a92403fe3e 100644 --- a/drivers/target/iscsi/Makefile +++ b/drivers/target/iscsi/Makefile | |||
@@ -15,6 +15,7 @@ iscsi_target_mod-y += iscsi_target_parameters.o \ | |||
15 | iscsi_target_util.o \ | 15 | iscsi_target_util.o \ |
16 | iscsi_target.o \ | 16 | iscsi_target.o \ |
17 | iscsi_target_configfs.o \ | 17 | iscsi_target_configfs.o \ |
18 | iscsi_target_stat.o | 18 | iscsi_target_stat.o \ |
19 | iscsi_target_transport.o | ||
19 | 20 | ||
20 | obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o | 21 | obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o |
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c index 7ea246a07731..ffbc6a94be52 100644 --- a/drivers/target/iscsi/iscsi_target.c +++ b/drivers/target/iscsi/iscsi_target.c | |||
@@ -49,6 +49,8 @@ | |||
49 | #include "iscsi_target_device.h" | 49 | #include "iscsi_target_device.h" |
50 | #include "iscsi_target_stat.h" | 50 | #include "iscsi_target_stat.h" |
51 | 51 | ||
52 | #include <target/iscsi/iscsi_transport.h> | ||
53 | |||
52 | static LIST_HEAD(g_tiqn_list); | 54 | static LIST_HEAD(g_tiqn_list); |
53 | static LIST_HEAD(g_np_list); | 55 | static LIST_HEAD(g_np_list); |
54 | static DEFINE_SPINLOCK(tiqn_lock); | 56 | static DEFINE_SPINLOCK(tiqn_lock); |
@@ -68,8 +70,7 @@ struct kmem_cache *lio_ooo_cache; | |||
68 | struct kmem_cache *lio_r2t_cache; | 70 | struct kmem_cache *lio_r2t_cache; |
69 | 71 | ||
70 | static int iscsit_handle_immediate_data(struct iscsi_cmd *, | 72 | static int iscsit_handle_immediate_data(struct iscsi_cmd *, |
71 | unsigned char *buf, u32); | 73 | struct iscsi_scsi_req *, u32); |
72 | static int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *); | ||
73 | 74 | ||
74 | struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf) | 75 | struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf) |
75 | { | 76 | { |
@@ -401,8 +402,7 @@ struct iscsi_np *iscsit_add_np( | |||
401 | spin_unlock_bh(&np_lock); | 402 | spin_unlock_bh(&np_lock); |
402 | 403 | ||
403 | pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", | 404 | pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", |
404 | np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ? | 405 | np->np_ip, np->np_port, np->np_transport->name); |
405 | "TCP" : "SCTP"); | ||
406 | 406 | ||
407 | return np; | 407 | return np; |
408 | } | 408 | } |
@@ -441,11 +441,10 @@ int iscsit_reset_np_thread( | |||
441 | return 0; | 441 | return 0; |
442 | } | 442 | } |
443 | 443 | ||
444 | static int iscsit_del_np_comm(struct iscsi_np *np) | 444 | static void iscsit_free_np(struct iscsi_np *np) |
445 | { | 445 | { |
446 | if (np->np_socket) | 446 | if (np->np_socket) |
447 | sock_release(np->np_socket); | 447 | sock_release(np->np_socket); |
448 | return 0; | ||
449 | } | 448 | } |
450 | 449 | ||
451 | int iscsit_del_np(struct iscsi_np *np) | 450 | int iscsit_del_np(struct iscsi_np *np) |
@@ -467,20 +466,47 @@ int iscsit_del_np(struct iscsi_np *np) | |||
467 | send_sig(SIGINT, np->np_thread, 1); | 466 | send_sig(SIGINT, np->np_thread, 1); |
468 | kthread_stop(np->np_thread); | 467 | kthread_stop(np->np_thread); |
469 | } | 468 | } |
470 | iscsit_del_np_comm(np); | 469 | |
470 | np->np_transport->iscsit_free_np(np); | ||
471 | 471 | ||
472 | spin_lock_bh(&np_lock); | 472 | spin_lock_bh(&np_lock); |
473 | list_del(&np->np_list); | 473 | list_del(&np->np_list); |
474 | spin_unlock_bh(&np_lock); | 474 | spin_unlock_bh(&np_lock); |
475 | 475 | ||
476 | pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", | 476 | pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", |
477 | np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ? | 477 | np->np_ip, np->np_port, np->np_transport->name); |
478 | "TCP" : "SCTP"); | ||
479 | 478 | ||
479 | iscsit_put_transport(np->np_transport); | ||
480 | kfree(np); | 480 | kfree(np); |
481 | return 0; | 481 | return 0; |
482 | } | 482 | } |
483 | 483 | ||
484 | static int iscsit_immediate_queue(struct iscsi_conn *, struct iscsi_cmd *, int); | ||
485 | static int iscsit_response_queue(struct iscsi_conn *, struct iscsi_cmd *, int); | ||
486 | |||
487 | static int iscsit_queue_rsp(struct iscsi_conn *conn, struct iscsi_cmd *cmd) | ||
488 | { | ||
489 | iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | static struct iscsit_transport iscsi_target_transport = { | ||
494 | .name = "iSCSI/TCP", | ||
495 | .transport_type = ISCSI_TCP, | ||
496 | .owner = NULL, | ||
497 | .iscsit_setup_np = iscsit_setup_np, | ||
498 | .iscsit_accept_np = iscsit_accept_np, | ||
499 | .iscsit_free_np = iscsit_free_np, | ||
500 | .iscsit_alloc_cmd = iscsit_alloc_cmd, | ||
501 | .iscsit_get_login_rx = iscsit_get_login_rx, | ||
502 | .iscsit_put_login_tx = iscsit_put_login_tx, | ||
503 | .iscsit_get_dataout = iscsit_build_r2ts_for_cmd, | ||
504 | .iscsit_immediate_queue = iscsit_immediate_queue, | ||
505 | .iscsit_response_queue = iscsit_response_queue, | ||
506 | .iscsit_queue_data_in = iscsit_queue_rsp, | ||
507 | .iscsit_queue_status = iscsit_queue_rsp, | ||
508 | }; | ||
509 | |||
484 | static int __init iscsi_target_init_module(void) | 510 | static int __init iscsi_target_init_module(void) |
485 | { | 511 | { |
486 | int ret = 0; | 512 | int ret = 0; |
@@ -557,6 +583,8 @@ static int __init iscsi_target_init_module(void) | |||
557 | goto ooo_out; | 583 | goto ooo_out; |
558 | } | 584 | } |
559 | 585 | ||
586 | iscsit_register_transport(&iscsi_target_transport); | ||
587 | |||
560 | if (iscsit_load_discovery_tpg() < 0) | 588 | if (iscsit_load_discovery_tpg() < 0) |
561 | goto r2t_out; | 589 | goto r2t_out; |
562 | 590 | ||
@@ -587,6 +615,7 @@ static void __exit iscsi_target_cleanup_module(void) | |||
587 | iscsi_deallocate_thread_sets(); | 615 | iscsi_deallocate_thread_sets(); |
588 | iscsi_thread_set_free(); | 616 | iscsi_thread_set_free(); |
589 | iscsit_release_discovery_tpg(); | 617 | iscsit_release_discovery_tpg(); |
618 | iscsit_unregister_transport(&iscsi_target_transport); | ||
590 | kmem_cache_destroy(lio_cmd_cache); | 619 | kmem_cache_destroy(lio_cmd_cache); |
591 | kmem_cache_destroy(lio_qr_cache); | 620 | kmem_cache_destroy(lio_qr_cache); |
592 | kmem_cache_destroy(lio_dr_cache); | 621 | kmem_cache_destroy(lio_dr_cache); |
@@ -682,11 +711,20 @@ int iscsit_add_reject_from_cmd( | |||
682 | iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); | 711 | iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); |
683 | 712 | ||
684 | ret = wait_for_completion_interruptible(&cmd->reject_comp); | 713 | ret = wait_for_completion_interruptible(&cmd->reject_comp); |
714 | /* | ||
715 | * Perform the kref_put now if se_cmd has already been setup by | ||
716 | * scsit_setup_scsi_cmd() | ||
717 | */ | ||
718 | if (cmd->se_cmd.se_tfo != NULL) { | ||
719 | pr_debug("iscsi reject: calling target_put_sess_cmd >>>>>>\n"); | ||
720 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | ||
721 | } | ||
685 | if (ret != 0) | 722 | if (ret != 0) |
686 | return -1; | 723 | return -1; |
687 | 724 | ||
688 | return (!fail_conn) ? 0 : -1; | 725 | return (!fail_conn) ? 0 : -1; |
689 | } | 726 | } |
727 | EXPORT_SYMBOL(iscsit_add_reject_from_cmd); | ||
690 | 728 | ||
691 | /* | 729 | /* |
692 | * Map some portion of the allocated scatterlist to an iovec, suitable for | 730 | * Map some portion of the allocated scatterlist to an iovec, suitable for |
@@ -745,6 +783,9 @@ static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) | |||
745 | 783 | ||
746 | conn->exp_statsn = exp_statsn; | 784 | conn->exp_statsn = exp_statsn; |
747 | 785 | ||
786 | if (conn->sess->sess_ops->RDMAExtensions) | ||
787 | return; | ||
788 | |||
748 | spin_lock_bh(&conn->cmd_lock); | 789 | spin_lock_bh(&conn->cmd_lock); |
749 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { | 790 | list_for_each_entry(cmd, &conn->conn_cmd_list, i_conn_node) { |
750 | spin_lock(&cmd->istate_lock); | 791 | spin_lock(&cmd->istate_lock); |
@@ -777,12 +818,10 @@ static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd) | |||
777 | return 0; | 818 | return 0; |
778 | } | 819 | } |
779 | 820 | ||
780 | static int iscsit_handle_scsi_cmd( | 821 | int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
781 | struct iscsi_conn *conn, | 822 | unsigned char *buf) |
782 | unsigned char *buf) | ||
783 | { | 823 | { |
784 | int data_direction, payload_length, cmdsn_ret = 0, immed_ret; | 824 | int data_direction, payload_length; |
785 | struct iscsi_cmd *cmd = NULL; | ||
786 | struct iscsi_scsi_req *hdr; | 825 | struct iscsi_scsi_req *hdr; |
787 | int iscsi_task_attr; | 826 | int iscsi_task_attr; |
788 | int sam_task_attr; | 827 | int sam_task_attr; |
@@ -805,8 +844,8 @@ static int iscsit_handle_scsi_cmd( | |||
805 | !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) { | 844 | !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) { |
806 | pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL" | 845 | pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL" |
807 | " not set. Bad iSCSI Initiator.\n"); | 846 | " not set. Bad iSCSI Initiator.\n"); |
808 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, | 847 | return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, |
809 | buf, conn); | 848 | 1, 1, buf, cmd); |
810 | } | 849 | } |
811 | 850 | ||
812 | if (((hdr->flags & ISCSI_FLAG_CMD_READ) || | 851 | if (((hdr->flags & ISCSI_FLAG_CMD_READ) || |
@@ -826,8 +865,8 @@ static int iscsit_handle_scsi_cmd( | |||
826 | pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE" | 865 | pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE" |
827 | " set when Expected Data Transfer Length is 0 for" | 866 | " set when Expected Data Transfer Length is 0 for" |
828 | " CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]); | 867 | " CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]); |
829 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, | 868 | return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, |
830 | buf, conn); | 869 | 1, 1, buf, cmd); |
831 | } | 870 | } |
832 | done: | 871 | done: |
833 | 872 | ||
@@ -836,29 +875,29 @@ done: | |||
836 | pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE" | 875 | pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE" |
837 | " MUST be set if Expected Data Transfer Length is not 0." | 876 | " MUST be set if Expected Data Transfer Length is not 0." |
838 | " Bad iSCSI Initiator\n"); | 877 | " Bad iSCSI Initiator\n"); |
839 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, | 878 | return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, |
840 | buf, conn); | 879 | 1, 1, buf, cmd); |
841 | } | 880 | } |
842 | 881 | ||
843 | if ((hdr->flags & ISCSI_FLAG_CMD_READ) && | 882 | if ((hdr->flags & ISCSI_FLAG_CMD_READ) && |
844 | (hdr->flags & ISCSI_FLAG_CMD_WRITE)) { | 883 | (hdr->flags & ISCSI_FLAG_CMD_WRITE)) { |
845 | pr_err("Bidirectional operations not supported!\n"); | 884 | pr_err("Bidirectional operations not supported!\n"); |
846 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, | 885 | return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, |
847 | buf, conn); | 886 | 1, 1, buf, cmd); |
848 | } | 887 | } |
849 | 888 | ||
850 | if (hdr->opcode & ISCSI_OP_IMMEDIATE) { | 889 | if (hdr->opcode & ISCSI_OP_IMMEDIATE) { |
851 | pr_err("Illegally set Immediate Bit in iSCSI Initiator" | 890 | pr_err("Illegally set Immediate Bit in iSCSI Initiator" |
852 | " Scsi Command PDU.\n"); | 891 | " Scsi Command PDU.\n"); |
853 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, | 892 | return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, |
854 | buf, conn); | 893 | 1, 1, buf, cmd); |
855 | } | 894 | } |
856 | 895 | ||
857 | if (payload_length && !conn->sess->sess_ops->ImmediateData) { | 896 | if (payload_length && !conn->sess->sess_ops->ImmediateData) { |
858 | pr_err("ImmediateData=No but DataSegmentLength=%u," | 897 | pr_err("ImmediateData=No but DataSegmentLength=%u," |
859 | " protocol error.\n", payload_length); | 898 | " protocol error.\n", payload_length); |
860 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 899 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
861 | buf, conn); | 900 | 1, 1, buf, cmd); |
862 | } | 901 | } |
863 | 902 | ||
864 | if ((be32_to_cpu(hdr->data_length )== payload_length) && | 903 | if ((be32_to_cpu(hdr->data_length )== payload_length) && |
@@ -866,43 +905,38 @@ done: | |||
866 | pr_err("Expected Data Transfer Length and Length of" | 905 | pr_err("Expected Data Transfer Length and Length of" |
867 | " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL" | 906 | " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL" |
868 | " bit is not set protocol error\n"); | 907 | " bit is not set protocol error\n"); |
869 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 908 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
870 | buf, conn); | 909 | 1, 1, buf, cmd); |
871 | } | 910 | } |
872 | 911 | ||
873 | if (payload_length > be32_to_cpu(hdr->data_length)) { | 912 | if (payload_length > be32_to_cpu(hdr->data_length)) { |
874 | pr_err("DataSegmentLength: %u is greater than" | 913 | pr_err("DataSegmentLength: %u is greater than" |
875 | " EDTL: %u, protocol error.\n", payload_length, | 914 | " EDTL: %u, protocol error.\n", payload_length, |
876 | hdr->data_length); | 915 | hdr->data_length); |
877 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 916 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
878 | buf, conn); | 917 | 1, 1, buf, cmd); |
879 | } | 918 | } |
880 | 919 | ||
881 | if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { | 920 | if (payload_length > conn->conn_ops->MaxXmitDataSegmentLength) { |
882 | pr_err("DataSegmentLength: %u is greater than" | 921 | pr_err("DataSegmentLength: %u is greater than" |
883 | " MaxXmitDataSegmentLength: %u, protocol error.\n", | 922 | " MaxXmitDataSegmentLength: %u, protocol error.\n", |
884 | payload_length, conn->conn_ops->MaxXmitDataSegmentLength); | 923 | payload_length, conn->conn_ops->MaxXmitDataSegmentLength); |
885 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 924 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
886 | buf, conn); | 925 | 1, 1, buf, cmd); |
887 | } | 926 | } |
888 | 927 | ||
889 | if (payload_length > conn->sess->sess_ops->FirstBurstLength) { | 928 | if (payload_length > conn->sess->sess_ops->FirstBurstLength) { |
890 | pr_err("DataSegmentLength: %u is greater than" | 929 | pr_err("DataSegmentLength: %u is greater than" |
891 | " FirstBurstLength: %u, protocol error.\n", | 930 | " FirstBurstLength: %u, protocol error.\n", |
892 | payload_length, conn->sess->sess_ops->FirstBurstLength); | 931 | payload_length, conn->sess->sess_ops->FirstBurstLength); |
893 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, | 932 | return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, |
894 | buf, conn); | 933 | 1, 1, buf, cmd); |
895 | } | 934 | } |
896 | 935 | ||
897 | data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE : | 936 | data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE : |
898 | (hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE : | 937 | (hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE : |
899 | DMA_NONE; | 938 | DMA_NONE; |
900 | 939 | ||
901 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
902 | if (!cmd) | ||
903 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, | ||
904 | buf, conn); | ||
905 | |||
906 | cmd->data_direction = data_direction; | 940 | cmd->data_direction = data_direction; |
907 | iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK; | 941 | iscsi_task_attr = hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK; |
908 | /* | 942 | /* |
@@ -945,7 +979,8 @@ done: | |||
945 | cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); | 979 | cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn); |
946 | cmd->first_burst_len = payload_length; | 980 | cmd->first_burst_len = payload_length; |
947 | 981 | ||
948 | if (cmd->data_direction == DMA_FROM_DEVICE) { | 982 | if (!conn->sess->sess_ops->RDMAExtensions && |
983 | cmd->data_direction == DMA_FROM_DEVICE) { | ||
949 | struct iscsi_datain_req *dr; | 984 | struct iscsi_datain_req *dr; |
950 | 985 | ||
951 | dr = iscsit_allocate_datain_req(); | 986 | dr = iscsit_allocate_datain_req(); |
@@ -967,7 +1002,10 @@ done: | |||
967 | 1002 | ||
968 | pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x," | 1003 | pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x," |
969 | " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, | 1004 | " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, |
970 | hdr->cmdsn, hdr->data_length, payload_length, conn->cid); | 1005 | hdr->cmdsn, be32_to_cpu(hdr->data_length), payload_length, |
1006 | conn->cid); | ||
1007 | |||
1008 | target_get_sess_cmd(conn->sess->se_sess, &cmd->se_cmd, true); | ||
971 | 1009 | ||
972 | cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, | 1010 | cmd->sense_reason = transport_lookup_cmd_lun(&cmd->se_cmd, |
973 | scsilun_to_int(&hdr->lun)); | 1011 | scsilun_to_int(&hdr->lun)); |
@@ -1001,12 +1039,24 @@ attach_cmd: | |||
1001 | */ | 1039 | */ |
1002 | core_alua_check_nonop_delay(&cmd->se_cmd); | 1040 | core_alua_check_nonop_delay(&cmd->se_cmd); |
1003 | 1041 | ||
1004 | if (iscsit_allocate_iovecs(cmd) < 0) { | 1042 | return 0; |
1005 | return iscsit_add_reject_from_cmd( | 1043 | } |
1006 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, | 1044 | EXPORT_SYMBOL(iscsit_setup_scsi_cmd); |
1007 | 1, 0, buf, cmd); | 1045 | |
1008 | } | 1046 | void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *cmd) |
1047 | { | ||
1048 | iscsit_set_dataout_sequence_values(cmd); | ||
1049 | |||
1050 | spin_lock_bh(&cmd->dataout_timeout_lock); | ||
1051 | iscsit_start_dataout_timer(cmd, cmd->conn); | ||
1052 | spin_unlock_bh(&cmd->dataout_timeout_lock); | ||
1053 | } | ||
1054 | EXPORT_SYMBOL(iscsit_set_unsoliticed_dataout); | ||
1009 | 1055 | ||
1056 | int iscsit_process_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | ||
1057 | struct iscsi_scsi_req *hdr) | ||
1058 | { | ||
1059 | int cmdsn_ret = 0; | ||
1010 | /* | 1060 | /* |
1011 | * Check the CmdSN against ExpCmdSN/MaxCmdSN here if | 1061 | * Check the CmdSN against ExpCmdSN/MaxCmdSN here if |
1012 | * the Immediate Bit is not set, and no Immediate | 1062 | * the Immediate Bit is not set, and no Immediate |
@@ -1019,12 +1069,17 @@ attach_cmd: | |||
1019 | */ | 1069 | */ |
1020 | if (!cmd->immediate_data) { | 1070 | if (!cmd->immediate_data) { |
1021 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 1071 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); |
1022 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) | 1072 | if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { |
1073 | if (!cmd->sense_reason) | ||
1074 | return 0; | ||
1075 | |||
1076 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | ||
1023 | return 0; | 1077 | return 0; |
1024 | else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) | 1078 | } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { |
1025 | return iscsit_add_reject_from_cmd( | 1079 | return iscsit_add_reject_from_cmd( |
1026 | ISCSI_REASON_PROTOCOL_ERROR, | 1080 | ISCSI_REASON_PROTOCOL_ERROR, |
1027 | 1, 0, buf, cmd); | 1081 | 1, 0, (unsigned char *)hdr, cmd); |
1082 | } | ||
1028 | } | 1083 | } |
1029 | 1084 | ||
1030 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); | 1085 | iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn)); |
@@ -1033,25 +1088,23 @@ attach_cmd: | |||
1033 | * If no Immediate Data is attached, it's OK to return now. | 1088 | * If no Immediate Data is attached, it's OK to return now. |
1034 | */ | 1089 | */ |
1035 | if (!cmd->immediate_data) { | 1090 | if (!cmd->immediate_data) { |
1036 | if (!cmd->sense_reason && cmd->unsolicited_data) { | 1091 | if (!cmd->sense_reason && cmd->unsolicited_data) |
1037 | iscsit_set_dataout_sequence_values(cmd); | 1092 | iscsit_set_unsoliticed_dataout(cmd); |
1038 | 1093 | if (!cmd->sense_reason) | |
1039 | spin_lock_bh(&cmd->dataout_timeout_lock); | 1094 | return 0; |
1040 | iscsit_start_dataout_timer(cmd, cmd->conn); | ||
1041 | spin_unlock_bh(&cmd->dataout_timeout_lock); | ||
1042 | } | ||
1043 | 1095 | ||
1096 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); | ||
1044 | return 0; | 1097 | return 0; |
1045 | } | 1098 | } |
1046 | 1099 | ||
1047 | /* | 1100 | /* |
1048 | * Early CHECK_CONDITIONs never make it to the transport processing | 1101 | * Early CHECK_CONDITIONs with ImmediateData never make it to command |
1049 | * thread. They are processed in CmdSN order by | 1102 | * execution. These exceptions are processed in CmdSN order using |
1050 | * iscsit_check_received_cmdsn() below. | 1103 | * iscsit_check_received_cmdsn() in iscsit_get_immediate_data() below. |
1051 | */ | 1104 | */ |
1052 | if (cmd->sense_reason) { | 1105 | if (cmd->sense_reason) { |
1053 | immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; | 1106 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); |
1054 | goto after_immediate_data; | 1107 | return 1; |
1055 | } | 1108 | } |
1056 | /* | 1109 | /* |
1057 | * Call directly into transport_generic_new_cmd() to perform | 1110 | * Call directly into transport_generic_new_cmd() to perform |
@@ -1059,11 +1112,27 @@ attach_cmd: | |||
1059 | */ | 1112 | */ |
1060 | cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); | 1113 | cmd->sense_reason = transport_generic_new_cmd(&cmd->se_cmd); |
1061 | if (cmd->sense_reason) { | 1114 | if (cmd->sense_reason) { |
1062 | immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; | 1115 | target_put_sess_cmd(conn->sess->se_sess, &cmd->se_cmd); |
1063 | goto after_immediate_data; | 1116 | return 1; |
1064 | } | 1117 | } |
1065 | 1118 | ||
1066 | immed_ret = iscsit_handle_immediate_data(cmd, buf, payload_length); | 1119 | return 0; |
1120 | } | ||
1121 | EXPORT_SYMBOL(iscsit_process_scsi_cmd); | ||
1122 | |||
1123 | static int | ||
1124 | iscsit_get_immediate_data(struct iscsi_cmd *cmd, struct iscsi_scsi_req *hdr, | ||
1125 | bool dump_payload) | ||
1126 | { | ||
1127 | int cmdsn_ret = 0, immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; | ||
1128 | /* | ||
1129 | * Special case for Unsupported SAM WRITE Opcodes and ImmediateData=Yes. | ||
1130 | */ | ||
1131 | if (dump_payload == true) | ||
1132 | goto after_immediate_data; | ||
1133 | |||
1134 | immed_ret = iscsit_handle_immediate_data(cmd, hdr, | ||
1135 | cmd->first_burst_len); | ||
1067 | after_immediate_data: | 1136 | after_immediate_data: |
1068 | if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) { | 1137 | if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) { |
1069 | /* | 1138 | /* |
@@ -1071,26 +1140,19 @@ after_immediate_data: | |||
1071 | * DataCRC, check against ExpCmdSN/MaxCmdSN if | 1140 | * DataCRC, check against ExpCmdSN/MaxCmdSN if |
1072 | * Immediate Bit is not set. | 1141 | * Immediate Bit is not set. |
1073 | */ | 1142 | */ |
1074 | cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); | 1143 | cmdsn_ret = iscsit_sequence_cmd(cmd->conn, cmd, hdr->cmdsn); |
1075 | /* | 1144 | |
1076 | * Special case for Unsupported SAM WRITE Opcodes | ||
1077 | * and ImmediateData=Yes. | ||
1078 | */ | ||
1079 | if (cmd->sense_reason) { | 1145 | if (cmd->sense_reason) { |
1080 | if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) | 1146 | if (iscsit_dump_data_payload(cmd->conn, |
1147 | cmd->first_burst_len, 1) < 0) | ||
1081 | return -1; | 1148 | return -1; |
1082 | } else if (cmd->unsolicited_data) { | 1149 | } else if (cmd->unsolicited_data) |
1083 | iscsit_set_dataout_sequence_values(cmd); | 1150 | iscsit_set_unsoliticed_dataout(cmd); |
1084 | |||
1085 | spin_lock_bh(&cmd->dataout_timeout_lock); | ||
1086 | iscsit_start_dataout_timer(cmd, cmd->conn); | ||
1087 | spin_unlock_bh(&cmd->dataout_timeout_lock); | ||
1088 | } | ||
1089 | 1151 | ||
1090 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) | 1152 | if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) |
1091 | return iscsit_add_reject_from_cmd( | 1153 | return iscsit_add_reject_from_cmd( |
1092 | ISCSI_REASON_PROTOCOL_ERROR, | 1154 | ISCSI_REASON_PROTOCOL_ERROR, |
1093 | 1, 0, buf, cmd); | 1155 | 1, 0, (unsigned char *)hdr, cmd); |
1094 | 1156 | ||
1095 | } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) { | 1157 | } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) { |
1096 | /* | 1158 | /* |
@@ -1105,13 +1167,47 @@ after_immediate_data: | |||
1105 | * CmdSN and issue a retry to plug the sequence. | 1167 | * CmdSN and issue a retry to plug the sequence. |
1106 | */ | 1168 | */ |
1107 | cmd->i_state = ISTATE_REMOVE; | 1169 | cmd->i_state = ISTATE_REMOVE; |
1108 | iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); | 1170 | iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, cmd->i_state); |
1109 | } else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */ | 1171 | } else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */ |
1110 | return -1; | 1172 | return -1; |
1111 | 1173 | ||
1112 | return 0; | 1174 | return 0; |
1113 | } | 1175 | } |
1114 | 1176 | ||
1177 | static int | ||
1178 | iscsit_handle_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | ||
1179 | unsigned char *buf) | ||
1180 | { | ||
1181 | struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf; | ||
1182 | int rc, immed_data; | ||
1183 | bool dump_payload = false; | ||
1184 | |||
1185 | rc = iscsit_setup_scsi_cmd(conn, cmd, buf); | ||
1186 | if (rc < 0) | ||
1187 | return rc; | ||
1188 | /* | ||
1189 | * Allocation iovecs needed for struct socket operations for | ||
1190 | * traditional iSCSI block I/O. | ||
1191 | */ | ||
1192 | if (iscsit_allocate_iovecs(cmd) < 0) { | ||
1193 | return iscsit_add_reject_from_cmd( | ||
1194 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
1195 | 1, 0, buf, cmd); | ||
1196 | } | ||
1197 | immed_data = cmd->immediate_data; | ||
1198 | |||
1199 | rc = iscsit_process_scsi_cmd(conn, cmd, hdr); | ||
1200 | if (rc < 0) | ||
1201 | return rc; | ||
1202 | else if (rc > 0) | ||
1203 | dump_payload = true; | ||
1204 | |||
1205 | if (!immed_data) | ||
1206 | return 0; | ||
1207 | |||
1208 | return iscsit_get_immediate_data(cmd, hdr, dump_payload); | ||
1209 | } | ||
1210 | |||
1115 | static u32 iscsit_do_crypto_hash_sg( | 1211 | static u32 iscsit_do_crypto_hash_sg( |
1116 | struct hash_desc *hash, | 1212 | struct hash_desc *hash, |
1117 | struct iscsi_cmd *cmd, | 1213 | struct iscsi_cmd *cmd, |
@@ -1174,20 +1270,16 @@ static void iscsit_do_crypto_hash_buf( | |||
1174 | crypto_hash_final(hash, data_crc); | 1270 | crypto_hash_final(hash, data_crc); |
1175 | } | 1271 | } |
1176 | 1272 | ||
1177 | static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | 1273 | int |
1274 | iscsit_check_dataout_hdr(struct iscsi_conn *conn, unsigned char *buf, | ||
1275 | struct iscsi_cmd **out_cmd) | ||
1178 | { | 1276 | { |
1179 | int iov_ret, ooo_cmdsn = 0, ret; | 1277 | struct iscsi_data *hdr = (struct iscsi_data *)buf; |
1180 | u8 data_crc_failed = 0; | ||
1181 | u32 checksum, iov_count = 0, padding = 0, rx_got = 0; | ||
1182 | u32 rx_size = 0, payload_length; | ||
1183 | struct iscsi_cmd *cmd = NULL; | 1278 | struct iscsi_cmd *cmd = NULL; |
1184 | struct se_cmd *se_cmd; | 1279 | struct se_cmd *se_cmd; |
1185 | struct iscsi_data *hdr; | ||
1186 | struct kvec *iov; | ||
1187 | unsigned long flags; | 1280 | unsigned long flags; |
1188 | 1281 | u32 payload_length = ntoh24(hdr->dlength); | |
1189 | hdr = (struct iscsi_data *) buf; | 1282 | int rc; |
1190 | payload_length = ntoh24(hdr->dlength); | ||
1191 | 1283 | ||
1192 | if (!payload_length) { | 1284 | if (!payload_length) { |
1193 | pr_err("DataOUT payload is ZERO, protocol error.\n"); | 1285 | pr_err("DataOUT payload is ZERO, protocol error.\n"); |
@@ -1220,7 +1312,7 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | |||
1220 | 1312 | ||
1221 | pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x," | 1313 | pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x," |
1222 | " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n", | 1314 | " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n", |
1223 | hdr->itt, hdr->ttt, hdr->datasn, hdr->offset, | 1315 | hdr->itt, hdr->ttt, hdr->datasn, ntohl(hdr->offset), |
1224 | payload_length, conn->cid); | 1316 | payload_length, conn->cid); |
1225 | 1317 | ||
1226 | if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { | 1318 | if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { |
@@ -1312,12 +1404,26 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | |||
1312 | * Preform DataSN, DataSequenceInOrder, DataPDUInOrder, and | 1404 | * Preform DataSN, DataSequenceInOrder, DataPDUInOrder, and |
1313 | * within-command recovery checks before receiving the payload. | 1405 | * within-command recovery checks before receiving the payload. |
1314 | */ | 1406 | */ |
1315 | ret = iscsit_check_pre_dataout(cmd, buf); | 1407 | rc = iscsit_check_pre_dataout(cmd, buf); |
1316 | if (ret == DATAOUT_WITHIN_COMMAND_RECOVERY) | 1408 | if (rc == DATAOUT_WITHIN_COMMAND_RECOVERY) |
1317 | return 0; | 1409 | return 0; |
1318 | else if (ret == DATAOUT_CANNOT_RECOVER) | 1410 | else if (rc == DATAOUT_CANNOT_RECOVER) |
1319 | return -1; | 1411 | return -1; |
1320 | 1412 | ||
1413 | *out_cmd = cmd; | ||
1414 | return 0; | ||
1415 | } | ||
1416 | EXPORT_SYMBOL(iscsit_check_dataout_hdr); | ||
1417 | |||
1418 | static int | ||
1419 | iscsit_get_dataout(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | ||
1420 | struct iscsi_data *hdr) | ||
1421 | { | ||
1422 | struct kvec *iov; | ||
1423 | u32 checksum, iov_count = 0, padding = 0, rx_got = 0, rx_size = 0; | ||
1424 | u32 payload_length = ntoh24(hdr->dlength); | ||
1425 | int iov_ret, data_crc_failed = 0; | ||
1426 | |||
1321 | rx_size += payload_length; | 1427 | rx_size += payload_length; |
1322 | iov = &cmd->iov_data[0]; | 1428 | iov = &cmd->iov_data[0]; |
1323 | 1429 | ||
@@ -1370,17 +1476,27 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | |||
1370 | payload_length); | 1476 | payload_length); |
1371 | } | 1477 | } |
1372 | } | 1478 | } |
1479 | |||
1480 | return data_crc_failed; | ||
1481 | } | ||
1482 | |||
1483 | int | ||
1484 | iscsit_check_dataout_payload(struct iscsi_cmd *cmd, struct iscsi_data *hdr, | ||
1485 | bool data_crc_failed) | ||
1486 | { | ||
1487 | struct iscsi_conn *conn = cmd->conn; | ||
1488 | int rc, ooo_cmdsn; | ||
1373 | /* | 1489 | /* |
1374 | * Increment post receive data and CRC values or perform | 1490 | * Increment post receive data and CRC values or perform |
1375 | * within-command recovery. | 1491 | * within-command recovery. |
1376 | */ | 1492 | */ |
1377 | ret = iscsit_check_post_dataout(cmd, buf, data_crc_failed); | 1493 | rc = iscsit_check_post_dataout(cmd, (unsigned char *)hdr, data_crc_failed); |
1378 | if ((ret == DATAOUT_NORMAL) || (ret == DATAOUT_WITHIN_COMMAND_RECOVERY)) | 1494 | if ((rc == DATAOUT_NORMAL) || (rc == DATAOUT_WITHIN_COMMAND_RECOVERY)) |
1379 | return 0; | 1495 | return 0; |
1380 | else if (ret == DATAOUT_SEND_R2T) { | 1496 | else if (rc == DATAOUT_SEND_R2T) { |
1381 | iscsit_set_dataout_sequence_values(cmd); | 1497 | iscsit_set_dataout_sequence_values(cmd); |
1382 | iscsit_build_r2ts_for_cmd(cmd, conn, false); | 1498 | conn->conn_transport->iscsit_get_dataout(conn, cmd, false); |
1383 | } else if (ret == DATAOUT_SEND_TO_TRANSPORT) { | 1499 | } else if (rc == DATAOUT_SEND_TO_TRANSPORT) { |
1384 | /* | 1500 | /* |
1385 | * Handle extra special case for out of order | 1501 | * Handle extra special case for out of order |
1386 | * Unsolicited Data Out. | 1502 | * Unsolicited Data Out. |
@@ -1401,15 +1517,37 @@ static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) | |||
1401 | 1517 | ||
1402 | return 0; | 1518 | return 0; |
1403 | } | 1519 | } |
1520 | EXPORT_SYMBOL(iscsit_check_dataout_payload); | ||
1404 | 1521 | ||
1405 | static int iscsit_handle_nop_out( | 1522 | static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) |
1406 | struct iscsi_conn *conn, | 1523 | { |
1407 | unsigned char *buf) | 1524 | struct iscsi_cmd *cmd; |
1525 | struct iscsi_data *hdr = (struct iscsi_data *)buf; | ||
1526 | int rc; | ||
1527 | bool data_crc_failed = false; | ||
1528 | |||
1529 | rc = iscsit_check_dataout_hdr(conn, buf, &cmd); | ||
1530 | if (rc < 0) | ||
1531 | return rc; | ||
1532 | else if (!cmd) | ||
1533 | return 0; | ||
1534 | |||
1535 | rc = iscsit_get_dataout(conn, cmd, hdr); | ||
1536 | if (rc < 0) | ||
1537 | return rc; | ||
1538 | else if (rc > 0) | ||
1539 | data_crc_failed = true; | ||
1540 | |||
1541 | return iscsit_check_dataout_payload(cmd, hdr, data_crc_failed); | ||
1542 | } | ||
1543 | |||
1544 | int iscsit_handle_nop_out(struct iscsi_conn *conn, struct iscsi_cmd *cmd, | ||
1545 | unsigned char *buf) | ||
1408 | { | 1546 | { |
1409 | unsigned char *ping_data = NULL; | 1547 | unsigned char *ping_data = NULL; |
1410 | int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size; | 1548 | int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size; |
1411 | u32 checksum, data_crc, padding = 0, payload_length; | 1549 | u32 checksum, data_crc, padding = 0, payload_length; |
1412 | struct iscsi_cmd *cmd = NULL; | 1550 | struct iscsi_cmd *cmd_p = NULL; |
1413 | struct kvec *iov = NULL; | 1551 | struct kvec *iov = NULL; |
1414 | struct iscsi_nopout *hdr; | 1552 | struct iscsi_nopout *hdr; |
1415 | 1553 | ||
@@ -1432,7 +1570,7 @@ static int iscsit_handle_nop_out( | |||
1432 | buf, conn); | 1570 | buf, conn); |
1433 | } | 1571 | } |
1434 | 1572 | ||
1435 | pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x," | 1573 | pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%08x," |
1436 | " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n", | 1574 | " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n", |
1437 | hdr->itt == RESERVED_ITT ? "Response" : "Request", | 1575 | hdr->itt == RESERVED_ITT ? "Response" : "Request", |
1438 | hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn, | 1576 | hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn, |
@@ -1445,7 +1583,6 @@ static int iscsit_handle_nop_out( | |||
1445 | * can contain ping data. | 1583 | * can contain ping data. |
1446 | */ | 1584 | */ |
1447 | if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { | 1585 | if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { |
1448 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
1449 | if (!cmd) | 1586 | if (!cmd) |
1450 | return iscsit_add_reject( | 1587 | return iscsit_add_reject( |
1451 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, | 1588 | ISCSI_REASON_BOOKMARK_NO_RESOURCES, |
@@ -1580,14 +1717,14 @@ static int iscsit_handle_nop_out( | |||
1580 | /* | 1717 | /* |
1581 | * This was a response to a unsolicited NOPIN ping. | 1718 | * This was a response to a unsolicited NOPIN ping. |
1582 | */ | 1719 | */ |
1583 | cmd = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt)); | 1720 | cmd_p = iscsit_find_cmd_from_ttt(conn, be32_to_cpu(hdr->ttt)); |
1584 | if (!cmd) | 1721 | if (!cmd_p) |
1585 | return -1; | 1722 | return -1; |
1586 | 1723 | ||
1587 | iscsit_stop_nopin_response_timer(conn); | 1724 | iscsit_stop_nopin_response_timer(conn); |
1588 | 1725 | ||
1589 | cmd->i_state = ISTATE_REMOVE; | 1726 | cmd_p->i_state = ISTATE_REMOVE; |
1590 | iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); | 1727 | iscsit_add_cmd_to_immediate_queue(cmd_p, conn, cmd_p->i_state); |
1591 | iscsit_start_nopin_timer(conn); | 1728 | iscsit_start_nopin_timer(conn); |
1592 | } else { | 1729 | } else { |
1593 | /* | 1730 | /* |
@@ -1611,12 +1748,12 @@ ping_out: | |||
1611 | kfree(ping_data); | 1748 | kfree(ping_data); |
1612 | return ret; | 1749 | return ret; |
1613 | } | 1750 | } |
1751 | EXPORT_SYMBOL(iscsit_handle_nop_out); | ||
1614 | 1752 | ||
1615 | static int iscsit_handle_task_mgt_cmd( | 1753 | int |
1616 | struct iscsi_conn *conn, | 1754 | iscsit_handle_task_mgt_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
1617 | unsigned char *buf) | 1755 | unsigned char *buf) |
1618 | { | 1756 | { |
1619 | struct iscsi_cmd *cmd; | ||
1620 | struct se_tmr_req *se_tmr; | 1757 | struct se_tmr_req *se_tmr; |
1621 | struct iscsi_tmr_req *tmr_req; | 1758 | struct iscsi_tmr_req *tmr_req; |
1622 | struct iscsi_tm *hdr; | 1759 | struct iscsi_tm *hdr; |
@@ -1645,18 +1782,13 @@ static int iscsit_handle_task_mgt_cmd( | |||
1645 | pr_err("Task Management Request TASK_REASSIGN not" | 1782 | pr_err("Task Management Request TASK_REASSIGN not" |
1646 | " issued as immediate command, bad iSCSI Initiator" | 1783 | " issued as immediate command, bad iSCSI Initiator" |
1647 | "implementation\n"); | 1784 | "implementation\n"); |
1648 | return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, | 1785 | return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, |
1649 | buf, conn); | 1786 | 1, 1, buf, cmd); |
1650 | } | 1787 | } |
1651 | if ((function != ISCSI_TM_FUNC_ABORT_TASK) && | 1788 | if ((function != ISCSI_TM_FUNC_ABORT_TASK) && |
1652 | be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG) | 1789 | be32_to_cpu(hdr->refcmdsn) != ISCSI_RESERVED_TAG) |
1653 | hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG); | 1790 | hdr->refcmdsn = cpu_to_be32(ISCSI_RESERVED_TAG); |
1654 | 1791 | ||
1655 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
1656 | if (!cmd) | ||
1657 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
1658 | 1, buf, conn); | ||
1659 | |||
1660 | cmd->data_direction = DMA_NONE; | 1792 | cmd->data_direction = DMA_NONE; |
1661 | 1793 | ||
1662 | cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL); | 1794 | cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL); |
@@ -1827,6 +1959,7 @@ attach: | |||
1827 | iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); | 1959 | iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); |
1828 | return 0; | 1960 | return 0; |
1829 | } | 1961 | } |
1962 | EXPORT_SYMBOL(iscsit_handle_task_mgt_cmd); | ||
1830 | 1963 | ||
1831 | /* #warning FIXME: Support Text Command parameters besides SendTargets */ | 1964 | /* #warning FIXME: Support Text Command parameters besides SendTargets */ |
1832 | static int iscsit_handle_text_cmd( | 1965 | static int iscsit_handle_text_cmd( |
@@ -2089,13 +2222,12 @@ int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *cmd, struct iscsi_conn | |||
2089 | return 0; | 2222 | return 0; |
2090 | } | 2223 | } |
2091 | 2224 | ||
2092 | static int iscsit_handle_logout_cmd( | 2225 | int |
2093 | struct iscsi_conn *conn, | 2226 | iscsit_handle_logout_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, |
2094 | unsigned char *buf) | 2227 | unsigned char *buf) |
2095 | { | 2228 | { |
2096 | int cmdsn_ret, logout_remove = 0; | 2229 | int cmdsn_ret, logout_remove = 0; |
2097 | u8 reason_code = 0; | 2230 | u8 reason_code = 0; |
2098 | struct iscsi_cmd *cmd; | ||
2099 | struct iscsi_logout *hdr; | 2231 | struct iscsi_logout *hdr; |
2100 | struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn); | 2232 | struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn); |
2101 | 2233 | ||
@@ -2119,14 +2251,10 @@ static int iscsit_handle_logout_cmd( | |||
2119 | if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) { | 2251 | if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) { |
2120 | pr_err("Received logout request on connection that" | 2252 | pr_err("Received logout request on connection that" |
2121 | " is not in logged in state, ignoring request.\n"); | 2253 | " is not in logged in state, ignoring request.\n"); |
2254 | iscsit_release_cmd(cmd); | ||
2122 | return 0; | 2255 | return 0; |
2123 | } | 2256 | } |
2124 | 2257 | ||
2125 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
2126 | if (!cmd) | ||
2127 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, | ||
2128 | buf, conn); | ||
2129 | |||
2130 | cmd->iscsi_opcode = ISCSI_OP_LOGOUT; | 2258 | cmd->iscsi_opcode = ISCSI_OP_LOGOUT; |
2131 | cmd->i_state = ISTATE_SEND_LOGOUTRSP; | 2259 | cmd->i_state = ISTATE_SEND_LOGOUTRSP; |
2132 | cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); | 2260 | cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); |
@@ -2176,6 +2304,7 @@ static int iscsit_handle_logout_cmd( | |||
2176 | 2304 | ||
2177 | return logout_remove; | 2305 | return logout_remove; |
2178 | } | 2306 | } |
2307 | EXPORT_SYMBOL(iscsit_handle_logout_cmd); | ||
2179 | 2308 | ||
2180 | static int iscsit_handle_snack( | 2309 | static int iscsit_handle_snack( |
2181 | struct iscsi_conn *conn, | 2310 | struct iscsi_conn *conn, |
@@ -2243,7 +2372,7 @@ static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn) | |||
2243 | 2372 | ||
2244 | static int iscsit_handle_immediate_data( | 2373 | static int iscsit_handle_immediate_data( |
2245 | struct iscsi_cmd *cmd, | 2374 | struct iscsi_cmd *cmd, |
2246 | unsigned char *buf, | 2375 | struct iscsi_scsi_req *hdr, |
2247 | u32 length) | 2376 | u32 length) |
2248 | { | 2377 | { |
2249 | int iov_ret, rx_got = 0, rx_size = 0; | 2378 | int iov_ret, rx_got = 0, rx_size = 0; |
@@ -2299,12 +2428,12 @@ static int iscsit_handle_immediate_data( | |||
2299 | " in ERL=0.\n"); | 2428 | " in ERL=0.\n"); |
2300 | iscsit_add_reject_from_cmd( | 2429 | iscsit_add_reject_from_cmd( |
2301 | ISCSI_REASON_DATA_DIGEST_ERROR, | 2430 | ISCSI_REASON_DATA_DIGEST_ERROR, |
2302 | 1, 0, buf, cmd); | 2431 | 1, 0, (unsigned char *)hdr, cmd); |
2303 | return IMMEDIATE_DATA_CANNOT_RECOVER; | 2432 | return IMMEDIATE_DATA_CANNOT_RECOVER; |
2304 | } else { | 2433 | } else { |
2305 | iscsit_add_reject_from_cmd( | 2434 | iscsit_add_reject_from_cmd( |
2306 | ISCSI_REASON_DATA_DIGEST_ERROR, | 2435 | ISCSI_REASON_DATA_DIGEST_ERROR, |
2307 | 0, 0, buf, cmd); | 2436 | 0, 0, (unsigned char *)hdr, cmd); |
2308 | return IMMEDIATE_DATA_ERL1_CRC_FAILURE; | 2437 | return IMMEDIATE_DATA_ERL1_CRC_FAILURE; |
2309 | } | 2438 | } |
2310 | } else { | 2439 | } else { |
@@ -2424,18 +2553,60 @@ static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn) | |||
2424 | } | 2553 | } |
2425 | } | 2554 | } |
2426 | 2555 | ||
2427 | static int iscsit_send_data_in( | 2556 | static void |
2428 | struct iscsi_cmd *cmd, | 2557 | iscsit_build_datain_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn, |
2429 | struct iscsi_conn *conn) | 2558 | struct iscsi_datain *datain, struct iscsi_data_rsp *hdr, |
2559 | bool set_statsn) | ||
2430 | { | 2560 | { |
2431 | int iov_ret = 0, set_statsn = 0; | 2561 | hdr->opcode = ISCSI_OP_SCSI_DATA_IN; |
2432 | u32 iov_count = 0, tx_size = 0; | 2562 | hdr->flags = datain->flags; |
2563 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | ||
2564 | if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { | ||
2565 | hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW; | ||
2566 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); | ||
2567 | } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { | ||
2568 | hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW; | ||
2569 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); | ||
2570 | } | ||
2571 | } | ||
2572 | hton24(hdr->dlength, datain->length); | ||
2573 | if (hdr->flags & ISCSI_FLAG_DATA_ACK) | ||
2574 | int_to_scsilun(cmd->se_cmd.orig_fe_lun, | ||
2575 | (struct scsi_lun *)&hdr->lun); | ||
2576 | else | ||
2577 | put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun); | ||
2578 | |||
2579 | hdr->itt = cmd->init_task_tag; | ||
2580 | |||
2581 | if (hdr->flags & ISCSI_FLAG_DATA_ACK) | ||
2582 | hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); | ||
2583 | else | ||
2584 | hdr->ttt = cpu_to_be32(0xFFFFFFFF); | ||
2585 | if (set_statsn) | ||
2586 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
2587 | else | ||
2588 | hdr->statsn = cpu_to_be32(0xFFFFFFFF); | ||
2589 | |||
2590 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
2591 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
2592 | hdr->datasn = cpu_to_be32(datain->data_sn); | ||
2593 | hdr->offset = cpu_to_be32(datain->offset); | ||
2594 | |||
2595 | pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x," | ||
2596 | " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n", | ||
2597 | cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn), | ||
2598 | ntohl(hdr->offset), datain->length, conn->cid); | ||
2599 | } | ||
2600 | |||
2601 | static int iscsit_send_datain(struct iscsi_cmd *cmd, struct iscsi_conn *conn) | ||
2602 | { | ||
2603 | struct iscsi_data_rsp *hdr = (struct iscsi_data_rsp *)&cmd->pdu[0]; | ||
2433 | struct iscsi_datain datain; | 2604 | struct iscsi_datain datain; |
2434 | struct iscsi_datain_req *dr; | 2605 | struct iscsi_datain_req *dr; |
2435 | struct iscsi_data_rsp *hdr; | ||
2436 | struct kvec *iov; | 2606 | struct kvec *iov; |
2437 | int eodr = 0; | 2607 | u32 iov_count = 0, tx_size = 0; |
2438 | int ret; | 2608 | int eodr = 0, ret, iov_ret; |
2609 | bool set_statsn = false; | ||
2439 | 2610 | ||
2440 | memset(&datain, 0, sizeof(struct iscsi_datain)); | 2611 | memset(&datain, 0, sizeof(struct iscsi_datain)); |
2441 | dr = iscsit_get_datain_values(cmd, &datain); | 2612 | dr = iscsit_get_datain_values(cmd, &datain); |
@@ -2444,7 +2615,6 @@ static int iscsit_send_data_in( | |||
2444 | cmd->init_task_tag); | 2615 | cmd->init_task_tag); |
2445 | return -1; | 2616 | return -1; |
2446 | } | 2617 | } |
2447 | |||
2448 | /* | 2618 | /* |
2449 | * Be paranoid and double check the logic for now. | 2619 | * Be paranoid and double check the logic for now. |
2450 | */ | 2620 | */ |
@@ -2452,7 +2622,7 @@ static int iscsit_send_data_in( | |||
2452 | pr_err("Command ITT: 0x%08x, datain.offset: %u and" | 2622 | pr_err("Command ITT: 0x%08x, datain.offset: %u and" |
2453 | " datain.length: %u exceeds cmd->data_length: %u\n", | 2623 | " datain.length: %u exceeds cmd->data_length: %u\n", |
2454 | cmd->init_task_tag, datain.offset, datain.length, | 2624 | cmd->init_task_tag, datain.offset, datain.length, |
2455 | cmd->se_cmd.data_length); | 2625 | cmd->se_cmd.data_length); |
2456 | return -1; | 2626 | return -1; |
2457 | } | 2627 | } |
2458 | 2628 | ||
@@ -2476,47 +2646,13 @@ static int iscsit_send_data_in( | |||
2476 | (dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) { | 2646 | (dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) { |
2477 | iscsit_increment_maxcmdsn(cmd, conn->sess); | 2647 | iscsit_increment_maxcmdsn(cmd, conn->sess); |
2478 | cmd->stat_sn = conn->stat_sn++; | 2648 | cmd->stat_sn = conn->stat_sn++; |
2479 | set_statsn = 1; | 2649 | set_statsn = true; |
2480 | } else if (dr->dr_complete == | 2650 | } else if (dr->dr_complete == |
2481 | DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY) | 2651 | DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY) |
2482 | set_statsn = 1; | 2652 | set_statsn = true; |
2483 | } | 2653 | } |
2484 | 2654 | ||
2485 | hdr = (struct iscsi_data_rsp *) cmd->pdu; | 2655 | iscsit_build_datain_pdu(cmd, conn, &datain, hdr, set_statsn); |
2486 | memset(hdr, 0, ISCSI_HDR_LEN); | ||
2487 | hdr->opcode = ISCSI_OP_SCSI_DATA_IN; | ||
2488 | hdr->flags = datain.flags; | ||
2489 | if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { | ||
2490 | if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { | ||
2491 | hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW; | ||
2492 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); | ||
2493 | } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { | ||
2494 | hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW; | ||
2495 | hdr->residual_count = cpu_to_be32(cmd->se_cmd.residual_count); | ||
2496 | } | ||
2497 | } | ||
2498 | hton24(hdr->dlength, datain.length); | ||
2499 | if (hdr->flags & ISCSI_FLAG_DATA_ACK) | ||
2500 | int_to_scsilun(cmd->se_cmd.orig_fe_lun, | ||
2501 | (struct scsi_lun *)&hdr->lun); | ||
2502 | else | ||
2503 | put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun); | ||
2504 | |||
2505 | hdr->itt = cmd->init_task_tag; | ||
2506 | |||
2507 | if (hdr->flags & ISCSI_FLAG_DATA_ACK) | ||
2508 | hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); | ||
2509 | else | ||
2510 | hdr->ttt = cpu_to_be32(0xFFFFFFFF); | ||
2511 | if (set_statsn) | ||
2512 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
2513 | else | ||
2514 | hdr->statsn = cpu_to_be32(0xFFFFFFFF); | ||
2515 | |||
2516 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
2517 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
2518 | hdr->datasn = cpu_to_be32(datain.data_sn); | ||
2519 | hdr->offset = cpu_to_be32(datain.offset); | ||
2520 | 2656 | ||
2521 | iov = &cmd->iov_data[0]; | 2657 | iov = &cmd->iov_data[0]; |
2522 | iov[iov_count].iov_base = cmd->pdu; | 2658 | iov[iov_count].iov_base = cmd->pdu; |
@@ -2527,7 +2663,7 @@ static int iscsit_send_data_in( | |||
2527 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; | 2663 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; |
2528 | 2664 | ||
2529 | iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, | 2665 | iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, |
2530 | (unsigned char *)hdr, ISCSI_HDR_LEN, | 2666 | (unsigned char *)cmd->pdu, ISCSI_HDR_LEN, |
2531 | 0, NULL, (u8 *)header_digest); | 2667 | 0, NULL, (u8 *)header_digest); |
2532 | 2668 | ||
2533 | iov[0].iov_len += ISCSI_CRC_LEN; | 2669 | iov[0].iov_len += ISCSI_CRC_LEN; |
@@ -2537,7 +2673,8 @@ static int iscsit_send_data_in( | |||
2537 | " for DataIN PDU 0x%08x\n", *header_digest); | 2673 | " for DataIN PDU 0x%08x\n", *header_digest); |
2538 | } | 2674 | } |
2539 | 2675 | ||
2540 | iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], datain.offset, datain.length); | 2676 | iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], |
2677 | datain.offset, datain.length); | ||
2541 | if (iov_ret < 0) | 2678 | if (iov_ret < 0) |
2542 | return -1; | 2679 | return -1; |
2543 | 2680 | ||
@@ -2568,11 +2705,6 @@ static int iscsit_send_data_in( | |||
2568 | cmd->iov_data_count = iov_count; | 2705 | cmd->iov_data_count = iov_count; |
2569 | cmd->tx_size = tx_size; | 2706 | cmd->tx_size = tx_size; |
2570 | 2707 | ||
2571 | pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x," | ||
2572 | " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n", | ||
2573 | cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn), | ||
2574 | ntohl(hdr->offset), datain.length, conn->cid); | ||
2575 | |||
2576 | /* sendpage is preferred but can't insert markers */ | 2708 | /* sendpage is preferred but can't insert markers */ |
2577 | if (!conn->conn_ops->IFMarker) | 2709 | if (!conn->conn_ops->IFMarker) |
2578 | ret = iscsit_fe_sendpage_sg(cmd, conn); | 2710 | ret = iscsit_fe_sendpage_sg(cmd, conn); |
@@ -2595,16 +2727,13 @@ static int iscsit_send_data_in( | |||
2595 | return eodr; | 2727 | return eodr; |
2596 | } | 2728 | } |
2597 | 2729 | ||
2598 | static int iscsit_send_logout_response( | 2730 | int |
2599 | struct iscsi_cmd *cmd, | 2731 | iscsit_build_logout_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, |
2600 | struct iscsi_conn *conn) | 2732 | struct iscsi_logout_rsp *hdr) |
2601 | { | 2733 | { |
2602 | int niov = 0, tx_size; | ||
2603 | struct iscsi_conn *logout_conn = NULL; | 2734 | struct iscsi_conn *logout_conn = NULL; |
2604 | struct iscsi_conn_recovery *cr = NULL; | 2735 | struct iscsi_conn_recovery *cr = NULL; |
2605 | struct iscsi_session *sess = conn->sess; | 2736 | struct iscsi_session *sess = conn->sess; |
2606 | struct kvec *iov; | ||
2607 | struct iscsi_logout_rsp *hdr; | ||
2608 | /* | 2737 | /* |
2609 | * The actual shutting down of Sessions and/or Connections | 2738 | * The actual shutting down of Sessions and/or Connections |
2610 | * for CLOSESESSION and CLOSECONNECTION Logout Requests | 2739 | * for CLOSESESSION and CLOSECONNECTION Logout Requests |
@@ -2673,9 +2802,6 @@ static int iscsit_send_logout_response( | |||
2673 | return -1; | 2802 | return -1; |
2674 | } | 2803 | } |
2675 | 2804 | ||
2676 | tx_size = ISCSI_HDR_LEN; | ||
2677 | hdr = (struct iscsi_logout_rsp *)cmd->pdu; | ||
2678 | memset(hdr, 0, ISCSI_HDR_LEN); | ||
2679 | hdr->opcode = ISCSI_OP_LOGOUT_RSP; | 2805 | hdr->opcode = ISCSI_OP_LOGOUT_RSP; |
2680 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 2806 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
2681 | hdr->response = cmd->logout_response; | 2807 | hdr->response = cmd->logout_response; |
@@ -2687,6 +2813,27 @@ static int iscsit_send_logout_response( | |||
2687 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | 2813 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); |
2688 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | 2814 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); |
2689 | 2815 | ||
2816 | pr_debug("Built Logout Response ITT: 0x%08x StatSN:" | ||
2817 | " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n", | ||
2818 | cmd->init_task_tag, cmd->stat_sn, hdr->response, | ||
2819 | cmd->logout_cid, conn->cid); | ||
2820 | |||
2821 | return 0; | ||
2822 | } | ||
2823 | EXPORT_SYMBOL(iscsit_build_logout_rsp); | ||
2824 | |||
2825 | static int | ||
2826 | iscsit_send_logout(struct iscsi_cmd *cmd, struct iscsi_conn *conn) | ||
2827 | { | ||
2828 | struct kvec *iov; | ||
2829 | int niov = 0, tx_size, rc; | ||
2830 | |||
2831 | rc = iscsit_build_logout_rsp(cmd, conn, | ||
2832 | (struct iscsi_logout_rsp *)&cmd->pdu[0]); | ||
2833 | if (rc < 0) | ||
2834 | return rc; | ||
2835 | |||
2836 | tx_size = ISCSI_HDR_LEN; | ||
2690 | iov = &cmd->iov_misc[0]; | 2837 | iov = &cmd->iov_misc[0]; |
2691 | iov[niov].iov_base = cmd->pdu; | 2838 | iov[niov].iov_base = cmd->pdu; |
2692 | iov[niov++].iov_len = ISCSI_HDR_LEN; | 2839 | iov[niov++].iov_len = ISCSI_HDR_LEN; |
@@ -2695,7 +2842,7 @@ static int iscsit_send_logout_response( | |||
2695 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; | 2842 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; |
2696 | 2843 | ||
2697 | iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, | 2844 | iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, |
2698 | (unsigned char *)hdr, ISCSI_HDR_LEN, | 2845 | (unsigned char *)&cmd->pdu[0], ISCSI_HDR_LEN, |
2699 | 0, NULL, (u8 *)header_digest); | 2846 | 0, NULL, (u8 *)header_digest); |
2700 | 2847 | ||
2701 | iov[0].iov_len += ISCSI_CRC_LEN; | 2848 | iov[0].iov_len += ISCSI_CRC_LEN; |
@@ -2706,14 +2853,37 @@ static int iscsit_send_logout_response( | |||
2706 | cmd->iov_misc_count = niov; | 2853 | cmd->iov_misc_count = niov; |
2707 | cmd->tx_size = tx_size; | 2854 | cmd->tx_size = tx_size; |
2708 | 2855 | ||
2709 | pr_debug("Sending Logout Response ITT: 0x%08x StatSN:" | ||
2710 | " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n", | ||
2711 | cmd->init_task_tag, cmd->stat_sn, hdr->response, | ||
2712 | cmd->logout_cid, conn->cid); | ||
2713 | |||
2714 | return 0; | 2856 | return 0; |
2715 | } | 2857 | } |
2716 | 2858 | ||
2859 | void | ||
2860 | iscsit_build_nopin_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | ||
2861 | struct iscsi_nopin *hdr, bool nopout_response) | ||
2862 | { | ||
2863 | hdr->opcode = ISCSI_OP_NOOP_IN; | ||
2864 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
2865 | hton24(hdr->dlength, cmd->buf_ptr_size); | ||
2866 | if (nopout_response) | ||
2867 | put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun); | ||
2868 | hdr->itt = cmd->init_task_tag; | ||
2869 | hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); | ||
2870 | cmd->stat_sn = (nopout_response) ? conn->stat_sn++ : | ||
2871 | conn->stat_sn; | ||
2872 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
2873 | |||
2874 | if (nopout_response) | ||
2875 | iscsit_increment_maxcmdsn(cmd, conn->sess); | ||
2876 | |||
2877 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
2878 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
2879 | |||
2880 | pr_debug("Built NOPIN %s Response ITT: 0x%08x, TTT: 0x%08x," | ||
2881 | " StatSN: 0x%08x, Length %u\n", (nopout_response) ? | ||
2882 | "Solicitied" : "Unsolicitied", cmd->init_task_tag, | ||
2883 | cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size); | ||
2884 | } | ||
2885 | EXPORT_SYMBOL(iscsit_build_nopin_rsp); | ||
2886 | |||
2717 | /* | 2887 | /* |
2718 | * Unsolicited NOPIN, either requesting a response or not. | 2888 | * Unsolicited NOPIN, either requesting a response or not. |
2719 | */ | 2889 | */ |
@@ -2722,20 +2892,10 @@ static int iscsit_send_unsolicited_nopin( | |||
2722 | struct iscsi_conn *conn, | 2892 | struct iscsi_conn *conn, |
2723 | int want_response) | 2893 | int want_response) |
2724 | { | 2894 | { |
2725 | int tx_size = ISCSI_HDR_LEN; | 2895 | struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0]; |
2726 | struct iscsi_nopin *hdr; | 2896 | int tx_size = ISCSI_HDR_LEN, ret; |
2727 | int ret; | ||
2728 | 2897 | ||
2729 | hdr = (struct iscsi_nopin *) cmd->pdu; | 2898 | iscsit_build_nopin_rsp(cmd, conn, hdr, false); |
2730 | memset(hdr, 0, ISCSI_HDR_LEN); | ||
2731 | hdr->opcode = ISCSI_OP_NOOP_IN; | ||
2732 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
2733 | hdr->itt = cmd->init_task_tag; | ||
2734 | hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); | ||
2735 | cmd->stat_sn = conn->stat_sn; | ||
2736 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
2737 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
2738 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
2739 | 2899 | ||
2740 | if (conn->conn_ops->HeaderDigest) { | 2900 | if (conn->conn_ops->HeaderDigest) { |
2741 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; | 2901 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; |
@@ -2771,31 +2931,17 @@ static int iscsit_send_unsolicited_nopin( | |||
2771 | return 0; | 2931 | return 0; |
2772 | } | 2932 | } |
2773 | 2933 | ||
2774 | static int iscsit_send_nopin_response( | 2934 | static int |
2775 | struct iscsi_cmd *cmd, | 2935 | iscsit_send_nopin(struct iscsi_cmd *cmd, struct iscsi_conn *conn) |
2776 | struct iscsi_conn *conn) | ||
2777 | { | 2936 | { |
2778 | int niov = 0, tx_size; | 2937 | struct iscsi_nopin *hdr = (struct iscsi_nopin *)&cmd->pdu[0]; |
2779 | u32 padding = 0; | ||
2780 | struct kvec *iov; | 2938 | struct kvec *iov; |
2781 | struct iscsi_nopin *hdr; | 2939 | u32 padding = 0; |
2782 | 2940 | int niov = 0, tx_size; | |
2783 | tx_size = ISCSI_HDR_LEN; | ||
2784 | hdr = (struct iscsi_nopin *) cmd->pdu; | ||
2785 | memset(hdr, 0, ISCSI_HDR_LEN); | ||
2786 | hdr->opcode = ISCSI_OP_NOOP_IN; | ||
2787 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
2788 | hton24(hdr->dlength, cmd->buf_ptr_size); | ||
2789 | put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun); | ||
2790 | hdr->itt = cmd->init_task_tag; | ||
2791 | hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); | ||
2792 | cmd->stat_sn = conn->stat_sn++; | ||
2793 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
2794 | 2941 | ||
2795 | iscsit_increment_maxcmdsn(cmd, conn->sess); | 2942 | iscsit_build_nopin_rsp(cmd, conn, hdr, true); |
2796 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
2797 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
2798 | 2943 | ||
2944 | tx_size = ISCSI_HDR_LEN; | ||
2799 | iov = &cmd->iov_misc[0]; | 2945 | iov = &cmd->iov_misc[0]; |
2800 | iov[niov].iov_base = cmd->pdu; | 2946 | iov[niov].iov_base = cmd->pdu; |
2801 | iov[niov++].iov_len = ISCSI_HDR_LEN; | 2947 | iov[niov++].iov_len = ISCSI_HDR_LEN; |
@@ -2851,10 +2997,6 @@ static int iscsit_send_nopin_response( | |||
2851 | cmd->iov_misc_count = niov; | 2997 | cmd->iov_misc_count = niov; |
2852 | cmd->tx_size = tx_size; | 2998 | cmd->tx_size = tx_size; |
2853 | 2999 | ||
2854 | pr_debug("Sending NOPIN Response ITT: 0x%08x, TTT:" | ||
2855 | " 0x%08x, StatSN: 0x%08x, Length %u\n", cmd->init_task_tag, | ||
2856 | cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size); | ||
2857 | |||
2858 | return 0; | 3000 | return 0; |
2859 | } | 3001 | } |
2860 | 3002 | ||
@@ -2939,8 +3081,8 @@ static int iscsit_send_r2t( | |||
2939 | * connection recovery. | 3081 | * connection recovery. |
2940 | */ | 3082 | */ |
2941 | int iscsit_build_r2ts_for_cmd( | 3083 | int iscsit_build_r2ts_for_cmd( |
2942 | struct iscsi_cmd *cmd, | ||
2943 | struct iscsi_conn *conn, | 3084 | struct iscsi_conn *conn, |
3085 | struct iscsi_cmd *cmd, | ||
2944 | bool recovery) | 3086 | bool recovery) |
2945 | { | 3087 | { |
2946 | int first_r2t = 1; | 3088 | int first_r2t = 1; |
@@ -3015,24 +3157,16 @@ int iscsit_build_r2ts_for_cmd( | |||
3015 | return 0; | 3157 | return 0; |
3016 | } | 3158 | } |
3017 | 3159 | ||
3018 | static int iscsit_send_status( | 3160 | void iscsit_build_rsp_pdu(struct iscsi_cmd *cmd, struct iscsi_conn *conn, |
3019 | struct iscsi_cmd *cmd, | 3161 | bool inc_stat_sn, struct iscsi_scsi_rsp *hdr) |
3020 | struct iscsi_conn *conn) | ||
3021 | { | 3162 | { |
3022 | u8 iov_count = 0, recovery; | 3163 | if (inc_stat_sn) |
3023 | u32 padding = 0, tx_size = 0; | ||
3024 | struct iscsi_scsi_rsp *hdr; | ||
3025 | struct kvec *iov; | ||
3026 | |||
3027 | recovery = (cmd->i_state != ISTATE_SEND_STATUS); | ||
3028 | if (!recovery) | ||
3029 | cmd->stat_sn = conn->stat_sn++; | 3164 | cmd->stat_sn = conn->stat_sn++; |
3030 | 3165 | ||
3031 | spin_lock_bh(&conn->sess->session_stats_lock); | 3166 | spin_lock_bh(&conn->sess->session_stats_lock); |
3032 | conn->sess->rsp_pdus++; | 3167 | conn->sess->rsp_pdus++; |
3033 | spin_unlock_bh(&conn->sess->session_stats_lock); | 3168 | spin_unlock_bh(&conn->sess->session_stats_lock); |
3034 | 3169 | ||
3035 | hdr = (struct iscsi_scsi_rsp *) cmd->pdu; | ||
3036 | memset(hdr, 0, ISCSI_HDR_LEN); | 3170 | memset(hdr, 0, ISCSI_HDR_LEN); |
3037 | hdr->opcode = ISCSI_OP_SCSI_CMD_RSP; | 3171 | hdr->opcode = ISCSI_OP_SCSI_CMD_RSP; |
3038 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | 3172 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; |
@@ -3052,6 +3186,23 @@ static int iscsit_send_status( | |||
3052 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | 3186 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); |
3053 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | 3187 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); |
3054 | 3188 | ||
3189 | pr_debug("Built SCSI Response, ITT: 0x%08x, StatSN: 0x%08x," | ||
3190 | " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n", | ||
3191 | cmd->init_task_tag, cmd->stat_sn, cmd->se_cmd.scsi_status, | ||
3192 | cmd->se_cmd.scsi_status, conn->cid); | ||
3193 | } | ||
3194 | EXPORT_SYMBOL(iscsit_build_rsp_pdu); | ||
3195 | |||
3196 | static int iscsit_send_response(struct iscsi_cmd *cmd, struct iscsi_conn *conn) | ||
3197 | { | ||
3198 | struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *)&cmd->pdu[0]; | ||
3199 | struct kvec *iov; | ||
3200 | u32 padding = 0, tx_size = 0; | ||
3201 | int iov_count = 0; | ||
3202 | bool inc_stat_sn = (cmd->i_state == ISTATE_SEND_STATUS); | ||
3203 | |||
3204 | iscsit_build_rsp_pdu(cmd, conn, inc_stat_sn, hdr); | ||
3205 | |||
3055 | iov = &cmd->iov_misc[0]; | 3206 | iov = &cmd->iov_misc[0]; |
3056 | iov[iov_count].iov_base = cmd->pdu; | 3207 | iov[iov_count].iov_base = cmd->pdu; |
3057 | iov[iov_count++].iov_len = ISCSI_HDR_LEN; | 3208 | iov[iov_count++].iov_len = ISCSI_HDR_LEN; |
@@ -3106,7 +3257,7 @@ static int iscsit_send_status( | |||
3106 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; | 3257 | u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; |
3107 | 3258 | ||
3108 | iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, | 3259 | iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, |
3109 | (unsigned char *)hdr, ISCSI_HDR_LEN, | 3260 | (unsigned char *)cmd->pdu, ISCSI_HDR_LEN, |
3110 | 0, NULL, (u8 *)header_digest); | 3261 | 0, NULL, (u8 *)header_digest); |
3111 | 3262 | ||
3112 | iov[0].iov_len += ISCSI_CRC_LEN; | 3263 | iov[0].iov_len += ISCSI_CRC_LEN; |
@@ -3118,11 +3269,6 @@ static int iscsit_send_status( | |||
3118 | cmd->iov_misc_count = iov_count; | 3269 | cmd->iov_misc_count = iov_count; |
3119 | cmd->tx_size = tx_size; | 3270 | cmd->tx_size = tx_size; |
3120 | 3271 | ||
3121 | pr_debug("Built %sSCSI Response, ITT: 0x%08x, StatSN: 0x%08x," | ||
3122 | " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n", | ||
3123 | (!recovery) ? "" : "Recovery ", cmd->init_task_tag, | ||
3124 | cmd->stat_sn, 0x00, cmd->se_cmd.scsi_status, conn->cid); | ||
3125 | |||
3126 | return 0; | 3272 | return 0; |
3127 | } | 3273 | } |
3128 | 3274 | ||
@@ -3145,16 +3291,12 @@ static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr) | |||
3145 | } | 3291 | } |
3146 | } | 3292 | } |
3147 | 3293 | ||
3148 | static int iscsit_send_task_mgt_rsp( | 3294 | void |
3149 | struct iscsi_cmd *cmd, | 3295 | iscsit_build_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn, |
3150 | struct iscsi_conn *conn) | 3296 | struct iscsi_tm_rsp *hdr) |
3151 | { | 3297 | { |
3152 | struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; | 3298 | struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; |
3153 | struct iscsi_tm_rsp *hdr; | ||
3154 | u32 tx_size = 0; | ||
3155 | 3299 | ||
3156 | hdr = (struct iscsi_tm_rsp *) cmd->pdu; | ||
3157 | memset(hdr, 0, ISCSI_HDR_LEN); | ||
3158 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; | 3300 | hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; |
3159 | hdr->flags = ISCSI_FLAG_CMD_FINAL; | 3301 | hdr->flags = ISCSI_FLAG_CMD_FINAL; |
3160 | hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr); | 3302 | hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr); |
@@ -3166,6 +3308,20 @@ static int iscsit_send_task_mgt_rsp( | |||
3166 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | 3308 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); |
3167 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | 3309 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); |
3168 | 3310 | ||
3311 | pr_debug("Built Task Management Response ITT: 0x%08x," | ||
3312 | " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n", | ||
3313 | cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid); | ||
3314 | } | ||
3315 | EXPORT_SYMBOL(iscsit_build_task_mgt_rsp); | ||
3316 | |||
3317 | static int | ||
3318 | iscsit_send_task_mgt_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn) | ||
3319 | { | ||
3320 | struct iscsi_tm_rsp *hdr = (struct iscsi_tm_rsp *)&cmd->pdu[0]; | ||
3321 | u32 tx_size = 0; | ||
3322 | |||
3323 | iscsit_build_task_mgt_rsp(cmd, conn, hdr); | ||
3324 | |||
3169 | cmd->iov_misc[0].iov_base = cmd->pdu; | 3325 | cmd->iov_misc[0].iov_base = cmd->pdu; |
3170 | cmd->iov_misc[0].iov_len = ISCSI_HDR_LEN; | 3326 | cmd->iov_misc[0].iov_len = ISCSI_HDR_LEN; |
3171 | tx_size += ISCSI_HDR_LEN; | 3327 | tx_size += ISCSI_HDR_LEN; |
@@ -3186,10 +3342,6 @@ static int iscsit_send_task_mgt_rsp( | |||
3186 | cmd->iov_misc_count = 1; | 3342 | cmd->iov_misc_count = 1; |
3187 | cmd->tx_size = tx_size; | 3343 | cmd->tx_size = tx_size; |
3188 | 3344 | ||
3189 | pr_debug("Built Task Management Response ITT: 0x%08x," | ||
3190 | " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n", | ||
3191 | cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid); | ||
3192 | |||
3193 | return 0; | 3345 | return 0; |
3194 | } | 3346 | } |
3195 | 3347 | ||
@@ -3385,6 +3537,22 @@ static int iscsit_send_text_rsp( | |||
3385 | return 0; | 3537 | return 0; |
3386 | } | 3538 | } |
3387 | 3539 | ||
3540 | void | ||
3541 | iscsit_build_reject(struct iscsi_cmd *cmd, struct iscsi_conn *conn, | ||
3542 | struct iscsi_reject *hdr) | ||
3543 | { | ||
3544 | hdr->opcode = ISCSI_OP_REJECT; | ||
3545 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
3546 | hton24(hdr->dlength, ISCSI_HDR_LEN); | ||
3547 | hdr->ffffffff = cpu_to_be32(0xffffffff); | ||
3548 | cmd->stat_sn = conn->stat_sn++; | ||
3549 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
3550 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
3551 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
3552 | |||
3553 | } | ||
3554 | EXPORT_SYMBOL(iscsit_build_reject); | ||
3555 | |||
3388 | static int iscsit_send_reject( | 3556 | static int iscsit_send_reject( |
3389 | struct iscsi_cmd *cmd, | 3557 | struct iscsi_cmd *cmd, |
3390 | struct iscsi_conn *conn) | 3558 | struct iscsi_conn *conn) |
@@ -3393,18 +3561,9 @@ static int iscsit_send_reject( | |||
3393 | struct iscsi_reject *hdr; | 3561 | struct iscsi_reject *hdr; |
3394 | struct kvec *iov; | 3562 | struct kvec *iov; |
3395 | 3563 | ||
3396 | hdr = (struct iscsi_reject *) cmd->pdu; | 3564 | iscsit_build_reject(cmd, conn, (struct iscsi_reject *)&cmd->pdu[0]); |
3397 | hdr->opcode = ISCSI_OP_REJECT; | ||
3398 | hdr->flags |= ISCSI_FLAG_CMD_FINAL; | ||
3399 | hton24(hdr->dlength, ISCSI_HDR_LEN); | ||
3400 | hdr->ffffffff = cpu_to_be32(0xffffffff); | ||
3401 | cmd->stat_sn = conn->stat_sn++; | ||
3402 | hdr->statsn = cpu_to_be32(cmd->stat_sn); | ||
3403 | hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); | ||
3404 | hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); | ||
3405 | 3565 | ||
3406 | iov = &cmd->iov_misc[0]; | 3566 | iov = &cmd->iov_misc[0]; |
3407 | |||
3408 | iov[iov_count].iov_base = cmd->pdu; | 3567 | iov[iov_count].iov_base = cmd->pdu; |
3409 | iov[iov_count++].iov_len = ISCSI_HDR_LEN; | 3568 | iov[iov_count++].iov_len = ISCSI_HDR_LEN; |
3410 | iov[iov_count].iov_base = cmd->buf_ptr; | 3569 | iov[iov_count].iov_base = cmd->buf_ptr; |
@@ -3501,55 +3660,41 @@ static inline void iscsit_thread_check_cpumask( | |||
3501 | set_cpus_allowed_ptr(p, conn->conn_cpumask); | 3660 | set_cpus_allowed_ptr(p, conn->conn_cpumask); |
3502 | } | 3661 | } |
3503 | 3662 | ||
3504 | static int handle_immediate_queue(struct iscsi_conn *conn) | 3663 | static int |
3664 | iscsit_immediate_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) | ||
3505 | { | 3665 | { |
3506 | struct iscsi_queue_req *qr; | ||
3507 | struct iscsi_cmd *cmd; | ||
3508 | u8 state; | ||
3509 | int ret; | 3666 | int ret; |
3510 | 3667 | ||
3511 | while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) { | 3668 | switch (state) { |
3512 | atomic_set(&conn->check_immediate_queue, 0); | 3669 | case ISTATE_SEND_R2T: |
3513 | cmd = qr->cmd; | 3670 | ret = iscsit_send_r2t(cmd, conn); |
3514 | state = qr->state; | 3671 | if (ret < 0) |
3515 | kmem_cache_free(lio_qr_cache, qr); | 3672 | goto err; |
3516 | 3673 | break; | |
3517 | switch (state) { | 3674 | case ISTATE_REMOVE: |
3518 | case ISTATE_SEND_R2T: | 3675 | spin_lock_bh(&conn->cmd_lock); |
3519 | ret = iscsit_send_r2t(cmd, conn); | 3676 | list_del(&cmd->i_conn_node); |
3520 | if (ret < 0) | 3677 | spin_unlock_bh(&conn->cmd_lock); |
3521 | goto err; | ||
3522 | break; | ||
3523 | case ISTATE_REMOVE: | ||
3524 | if (cmd->data_direction == DMA_TO_DEVICE) | ||
3525 | iscsit_stop_dataout_timer(cmd); | ||
3526 | |||
3527 | spin_lock_bh(&conn->cmd_lock); | ||
3528 | list_del(&cmd->i_conn_node); | ||
3529 | spin_unlock_bh(&conn->cmd_lock); | ||
3530 | 3678 | ||
3531 | iscsit_free_cmd(cmd); | 3679 | iscsit_free_cmd(cmd); |
3532 | continue; | 3680 | break; |
3533 | case ISTATE_SEND_NOPIN_WANT_RESPONSE: | 3681 | case ISTATE_SEND_NOPIN_WANT_RESPONSE: |
3534 | iscsit_mod_nopin_response_timer(conn); | 3682 | iscsit_mod_nopin_response_timer(conn); |
3535 | ret = iscsit_send_unsolicited_nopin(cmd, | 3683 | ret = iscsit_send_unsolicited_nopin(cmd, conn, 1); |
3536 | conn, 1); | 3684 | if (ret < 0) |
3537 | if (ret < 0) | ||
3538 | goto err; | ||
3539 | break; | ||
3540 | case ISTATE_SEND_NOPIN_NO_RESPONSE: | ||
3541 | ret = iscsit_send_unsolicited_nopin(cmd, | ||
3542 | conn, 0); | ||
3543 | if (ret < 0) | ||
3544 | goto err; | ||
3545 | break; | ||
3546 | default: | ||
3547 | pr_err("Unknown Opcode: 0x%02x ITT:" | ||
3548 | " 0x%08x, i_state: %d on CID: %hu\n", | ||
3549 | cmd->iscsi_opcode, cmd->init_task_tag, state, | ||
3550 | conn->cid); | ||
3551 | goto err; | 3685 | goto err; |
3552 | } | 3686 | break; |
3687 | case ISTATE_SEND_NOPIN_NO_RESPONSE: | ||
3688 | ret = iscsit_send_unsolicited_nopin(cmd, conn, 0); | ||
3689 | if (ret < 0) | ||
3690 | goto err; | ||
3691 | break; | ||
3692 | default: | ||
3693 | pr_err("Unknown Opcode: 0x%02x ITT:" | ||
3694 | " 0x%08x, i_state: %d on CID: %hu\n", | ||
3695 | cmd->iscsi_opcode, cmd->init_task_tag, state, | ||
3696 | conn->cid); | ||
3697 | goto err; | ||
3553 | } | 3698 | } |
3554 | 3699 | ||
3555 | return 0; | 3700 | return 0; |
@@ -3558,128 +3703,143 @@ err: | |||
3558 | return -1; | 3703 | return -1; |
3559 | } | 3704 | } |
3560 | 3705 | ||
3561 | static int handle_response_queue(struct iscsi_conn *conn) | 3706 | static int |
3707 | iscsit_handle_immediate_queue(struct iscsi_conn *conn) | ||
3562 | { | 3708 | { |
3709 | struct iscsit_transport *t = conn->conn_transport; | ||
3563 | struct iscsi_queue_req *qr; | 3710 | struct iscsi_queue_req *qr; |
3564 | struct iscsi_cmd *cmd; | 3711 | struct iscsi_cmd *cmd; |
3565 | u8 state; | 3712 | u8 state; |
3566 | int ret; | 3713 | int ret; |
3567 | 3714 | ||
3568 | while ((qr = iscsit_get_cmd_from_response_queue(conn))) { | 3715 | while ((qr = iscsit_get_cmd_from_immediate_queue(conn))) { |
3716 | atomic_set(&conn->check_immediate_queue, 0); | ||
3569 | cmd = qr->cmd; | 3717 | cmd = qr->cmd; |
3570 | state = qr->state; | 3718 | state = qr->state; |
3571 | kmem_cache_free(lio_qr_cache, qr); | 3719 | kmem_cache_free(lio_qr_cache, qr); |
3572 | 3720 | ||
3573 | check_rsp_state: | 3721 | ret = t->iscsit_immediate_queue(conn, cmd, state); |
3574 | switch (state) { | 3722 | if (ret < 0) |
3575 | case ISTATE_SEND_DATAIN: | 3723 | return ret; |
3576 | ret = iscsit_send_data_in(cmd, conn); | 3724 | } |
3577 | if (ret < 0) | ||
3578 | goto err; | ||
3579 | else if (!ret) | ||
3580 | /* more drs */ | ||
3581 | goto check_rsp_state; | ||
3582 | else if (ret == 1) { | ||
3583 | /* all done */ | ||
3584 | spin_lock_bh(&cmd->istate_lock); | ||
3585 | cmd->i_state = ISTATE_SENT_STATUS; | ||
3586 | spin_unlock_bh(&cmd->istate_lock); | ||
3587 | |||
3588 | if (atomic_read(&conn->check_immediate_queue)) | ||
3589 | return 1; | ||
3590 | 3725 | ||
3591 | continue; | 3726 | return 0; |
3592 | } else if (ret == 2) { | 3727 | } |
3593 | /* Still must send status, | ||
3594 | SCF_TRANSPORT_TASK_SENSE was set */ | ||
3595 | spin_lock_bh(&cmd->istate_lock); | ||
3596 | cmd->i_state = ISTATE_SEND_STATUS; | ||
3597 | spin_unlock_bh(&cmd->istate_lock); | ||
3598 | state = ISTATE_SEND_STATUS; | ||
3599 | goto check_rsp_state; | ||
3600 | } | ||
3601 | 3728 | ||
3602 | break; | 3729 | static int |
3603 | case ISTATE_SEND_STATUS: | 3730 | iscsit_response_queue(struct iscsi_conn *conn, struct iscsi_cmd *cmd, int state) |
3604 | case ISTATE_SEND_STATUS_RECOVERY: | 3731 | { |
3605 | ret = iscsit_send_status(cmd, conn); | 3732 | int ret; |
3606 | break; | 3733 | |
3607 | case ISTATE_SEND_LOGOUTRSP: | 3734 | check_rsp_state: |
3608 | ret = iscsit_send_logout_response(cmd, conn); | 3735 | switch (state) { |
3609 | break; | 3736 | case ISTATE_SEND_DATAIN: |
3610 | case ISTATE_SEND_ASYNCMSG: | 3737 | ret = iscsit_send_datain(cmd, conn); |
3611 | ret = iscsit_send_conn_drop_async_message( | ||
3612 | cmd, conn); | ||
3613 | break; | ||
3614 | case ISTATE_SEND_NOPIN: | ||
3615 | ret = iscsit_send_nopin_response(cmd, conn); | ||
3616 | break; | ||
3617 | case ISTATE_SEND_REJECT: | ||
3618 | ret = iscsit_send_reject(cmd, conn); | ||
3619 | break; | ||
3620 | case ISTATE_SEND_TASKMGTRSP: | ||
3621 | ret = iscsit_send_task_mgt_rsp(cmd, conn); | ||
3622 | if (ret != 0) | ||
3623 | break; | ||
3624 | ret = iscsit_tmr_post_handler(cmd, conn); | ||
3625 | if (ret != 0) | ||
3626 | iscsit_fall_back_to_erl0(conn->sess); | ||
3627 | break; | ||
3628 | case ISTATE_SEND_TEXTRSP: | ||
3629 | ret = iscsit_send_text_rsp(cmd, conn); | ||
3630 | break; | ||
3631 | default: | ||
3632 | pr_err("Unknown Opcode: 0x%02x ITT:" | ||
3633 | " 0x%08x, i_state: %d on CID: %hu\n", | ||
3634 | cmd->iscsi_opcode, cmd->init_task_tag, | ||
3635 | state, conn->cid); | ||
3636 | goto err; | ||
3637 | } | ||
3638 | if (ret < 0) | 3738 | if (ret < 0) |
3639 | goto err; | 3739 | goto err; |
3740 | else if (!ret) | ||
3741 | /* more drs */ | ||
3742 | goto check_rsp_state; | ||
3743 | else if (ret == 1) { | ||
3744 | /* all done */ | ||
3745 | spin_lock_bh(&cmd->istate_lock); | ||
3746 | cmd->i_state = ISTATE_SENT_STATUS; | ||
3747 | spin_unlock_bh(&cmd->istate_lock); | ||
3640 | 3748 | ||
3641 | if (iscsit_send_tx_data(cmd, conn, 1) < 0) { | 3749 | if (atomic_read(&conn->check_immediate_queue)) |
3642 | iscsit_tx_thread_wait_for_tcp(conn); | 3750 | return 1; |
3643 | iscsit_unmap_iovec(cmd); | ||
3644 | goto err; | ||
3645 | } | ||
3646 | iscsit_unmap_iovec(cmd); | ||
3647 | 3751 | ||
3648 | switch (state) { | 3752 | return 0; |
3649 | case ISTATE_SEND_LOGOUTRSP: | 3753 | } else if (ret == 2) { |
3650 | if (!iscsit_logout_post_handler(cmd, conn)) | 3754 | /* Still must send status, |
3651 | goto restart; | 3755 | SCF_TRANSPORT_TASK_SENSE was set */ |
3652 | /* fall through */ | ||
3653 | case ISTATE_SEND_STATUS: | ||
3654 | case ISTATE_SEND_ASYNCMSG: | ||
3655 | case ISTATE_SEND_NOPIN: | ||
3656 | case ISTATE_SEND_STATUS_RECOVERY: | ||
3657 | case ISTATE_SEND_TEXTRSP: | ||
3658 | case ISTATE_SEND_TASKMGTRSP: | ||
3659 | spin_lock_bh(&cmd->istate_lock); | 3756 | spin_lock_bh(&cmd->istate_lock); |
3660 | cmd->i_state = ISTATE_SENT_STATUS; | 3757 | cmd->i_state = ISTATE_SEND_STATUS; |
3661 | spin_unlock_bh(&cmd->istate_lock); | 3758 | spin_unlock_bh(&cmd->istate_lock); |
3759 | state = ISTATE_SEND_STATUS; | ||
3760 | goto check_rsp_state; | ||
3761 | } | ||
3762 | |||
3763 | break; | ||
3764 | case ISTATE_SEND_STATUS: | ||
3765 | case ISTATE_SEND_STATUS_RECOVERY: | ||
3766 | ret = iscsit_send_response(cmd, conn); | ||
3767 | break; | ||
3768 | case ISTATE_SEND_LOGOUTRSP: | ||
3769 | ret = iscsit_send_logout(cmd, conn); | ||
3770 | break; | ||
3771 | case ISTATE_SEND_ASYNCMSG: | ||
3772 | ret = iscsit_send_conn_drop_async_message( | ||
3773 | cmd, conn); | ||
3774 | break; | ||
3775 | case ISTATE_SEND_NOPIN: | ||
3776 | ret = iscsit_send_nopin(cmd, conn); | ||
3777 | break; | ||
3778 | case ISTATE_SEND_REJECT: | ||
3779 | ret = iscsit_send_reject(cmd, conn); | ||
3780 | break; | ||
3781 | case ISTATE_SEND_TASKMGTRSP: | ||
3782 | ret = iscsit_send_task_mgt_rsp(cmd, conn); | ||
3783 | if (ret != 0) | ||
3662 | break; | 3784 | break; |
3663 | case ISTATE_SEND_REJECT: | 3785 | ret = iscsit_tmr_post_handler(cmd, conn); |
3664 | if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) { | 3786 | if (ret != 0) |
3665 | cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN; | 3787 | iscsit_fall_back_to_erl0(conn->sess); |
3666 | complete(&cmd->reject_comp); | 3788 | break; |
3667 | goto err; | 3789 | case ISTATE_SEND_TEXTRSP: |
3668 | } | 3790 | ret = iscsit_send_text_rsp(cmd, conn); |
3791 | break; | ||
3792 | default: | ||
3793 | pr_err("Unknown Opcode: 0x%02x ITT:" | ||
3794 | " 0x%08x, i_state: %d on CID: %hu\n", | ||
3795 | cmd->iscsi_opcode, cmd->init_task_tag, | ||
3796 | state, conn->cid); | ||
3797 | goto err; | ||
3798 | } | ||
3799 | if (ret < 0) | ||
3800 | goto err; | ||
3801 | |||
3802 | if (iscsit_send_tx_data(cmd, conn, 1) < 0) { | ||
3803 | iscsit_tx_thread_wait_for_tcp(conn); | ||
3804 | iscsit_unmap_iovec(cmd); | ||
3805 | goto err; | ||
3806 | } | ||
3807 | iscsit_unmap_iovec(cmd); | ||
3808 | |||
3809 | switch (state) { | ||
3810 | case ISTATE_SEND_LOGOUTRSP: | ||
3811 | if (!iscsit_logout_post_handler(cmd, conn)) | ||
3812 | goto restart; | ||
3813 | /* fall through */ | ||
3814 | case ISTATE_SEND_STATUS: | ||
3815 | case ISTATE_SEND_ASYNCMSG: | ||
3816 | case ISTATE_SEND_NOPIN: | ||
3817 | case ISTATE_SEND_STATUS_RECOVERY: | ||
3818 | case ISTATE_SEND_TEXTRSP: | ||
3819 | case ISTATE_SEND_TASKMGTRSP: | ||
3820 | spin_lock_bh(&cmd->istate_lock); | ||
3821 | cmd->i_state = ISTATE_SENT_STATUS; | ||
3822 | spin_unlock_bh(&cmd->istate_lock); | ||
3823 | break; | ||
3824 | case ISTATE_SEND_REJECT: | ||
3825 | if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) { | ||
3826 | cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN; | ||
3669 | complete(&cmd->reject_comp); | 3827 | complete(&cmd->reject_comp); |
3670 | break; | ||
3671 | default: | ||
3672 | pr_err("Unknown Opcode: 0x%02x ITT:" | ||
3673 | " 0x%08x, i_state: %d on CID: %hu\n", | ||
3674 | cmd->iscsi_opcode, cmd->init_task_tag, | ||
3675 | cmd->i_state, conn->cid); | ||
3676 | goto err; | 3828 | goto err; |
3677 | } | 3829 | } |
3678 | 3830 | complete(&cmd->reject_comp); | |
3679 | if (atomic_read(&conn->check_immediate_queue)) | 3831 | break; |
3680 | return 1; | 3832 | default: |
3833 | pr_err("Unknown Opcode: 0x%02x ITT:" | ||
3834 | " 0x%08x, i_state: %d on CID: %hu\n", | ||
3835 | cmd->iscsi_opcode, cmd->init_task_tag, | ||
3836 | cmd->i_state, conn->cid); | ||
3837 | goto err; | ||
3681 | } | 3838 | } |
3682 | 3839 | ||
3840 | if (atomic_read(&conn->check_immediate_queue)) | ||
3841 | return 1; | ||
3842 | |||
3683 | return 0; | 3843 | return 0; |
3684 | 3844 | ||
3685 | err: | 3845 | err: |
@@ -3688,6 +3848,27 @@ restart: | |||
3688 | return -EAGAIN; | 3848 | return -EAGAIN; |
3689 | } | 3849 | } |
3690 | 3850 | ||
3851 | static int iscsit_handle_response_queue(struct iscsi_conn *conn) | ||
3852 | { | ||
3853 | struct iscsit_transport *t = conn->conn_transport; | ||
3854 | struct iscsi_queue_req *qr; | ||
3855 | struct iscsi_cmd *cmd; | ||
3856 | u8 state; | ||
3857 | int ret; | ||
3858 | |||
3859 | while ((qr = iscsit_get_cmd_from_response_queue(conn))) { | ||
3860 | cmd = qr->cmd; | ||
3861 | state = qr->state; | ||
3862 | kmem_cache_free(lio_qr_cache, qr); | ||
3863 | |||
3864 | ret = t->iscsit_response_queue(conn, cmd, state); | ||
3865 | if (ret == 1 || ret < 0) | ||
3866 | return ret; | ||
3867 | } | ||
3868 | |||
3869 | return 0; | ||
3870 | } | ||
3871 | |||
3691 | int iscsi_target_tx_thread(void *arg) | 3872 | int iscsi_target_tx_thread(void *arg) |
3692 | { | 3873 | { |
3693 | int ret = 0; | 3874 | int ret = 0; |
@@ -3722,11 +3903,11 @@ restart: | |||
3722 | goto transport_err; | 3903 | goto transport_err; |
3723 | 3904 | ||
3724 | get_immediate: | 3905 | get_immediate: |
3725 | ret = handle_immediate_queue(conn); | 3906 | ret = iscsit_handle_immediate_queue(conn); |
3726 | if (ret < 0) | 3907 | if (ret < 0) |
3727 | goto transport_err; | 3908 | goto transport_err; |
3728 | 3909 | ||
3729 | ret = handle_response_queue(conn); | 3910 | ret = iscsit_handle_response_queue(conn); |
3730 | if (ret == 1) | 3911 | if (ret == 1) |
3731 | goto get_immediate; | 3912 | goto get_immediate; |
3732 | else if (ret == -EAGAIN) | 3913 | else if (ret == -EAGAIN) |
@@ -3742,6 +3923,83 @@ out: | |||
3742 | return 0; | 3923 | return 0; |
3743 | } | 3924 | } |
3744 | 3925 | ||
3926 | static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf) | ||
3927 | { | ||
3928 | struct iscsi_hdr *hdr = (struct iscsi_hdr *)buf; | ||
3929 | struct iscsi_cmd *cmd; | ||
3930 | int ret = 0; | ||
3931 | |||
3932 | switch (hdr->opcode & ISCSI_OPCODE_MASK) { | ||
3933 | case ISCSI_OP_SCSI_CMD: | ||
3934 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
3935 | if (!cmd) | ||
3936 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
3937 | 1, buf, conn); | ||
3938 | |||
3939 | ret = iscsit_handle_scsi_cmd(conn, cmd, buf); | ||
3940 | break; | ||
3941 | case ISCSI_OP_SCSI_DATA_OUT: | ||
3942 | ret = iscsit_handle_data_out(conn, buf); | ||
3943 | break; | ||
3944 | case ISCSI_OP_NOOP_OUT: | ||
3945 | cmd = NULL; | ||
3946 | if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) { | ||
3947 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
3948 | if (!cmd) | ||
3949 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
3950 | 1, buf, conn); | ||
3951 | } | ||
3952 | ret = iscsit_handle_nop_out(conn, cmd, buf); | ||
3953 | break; | ||
3954 | case ISCSI_OP_SCSI_TMFUNC: | ||
3955 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
3956 | if (!cmd) | ||
3957 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
3958 | 1, buf, conn); | ||
3959 | |||
3960 | ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf); | ||
3961 | break; | ||
3962 | case ISCSI_OP_TEXT: | ||
3963 | ret = iscsit_handle_text_cmd(conn, buf); | ||
3964 | break; | ||
3965 | case ISCSI_OP_LOGOUT: | ||
3966 | cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); | ||
3967 | if (!cmd) | ||
3968 | return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, | ||
3969 | 1, buf, conn); | ||
3970 | |||
3971 | ret = iscsit_handle_logout_cmd(conn, cmd, buf); | ||
3972 | if (ret > 0) | ||
3973 | wait_for_completion_timeout(&conn->conn_logout_comp, | ||
3974 | SECONDS_FOR_LOGOUT_COMP * HZ); | ||
3975 | break; | ||
3976 | case ISCSI_OP_SNACK: | ||
3977 | ret = iscsit_handle_snack(conn, buf); | ||
3978 | break; | ||
3979 | default: | ||
3980 | pr_err("Got unknown iSCSI OpCode: 0x%02x\n", hdr->opcode); | ||
3981 | if (!conn->sess->sess_ops->ErrorRecoveryLevel) { | ||
3982 | pr_err("Cannot recover from unknown" | ||
3983 | " opcode while ERL=0, closing iSCSI connection.\n"); | ||
3984 | return -1; | ||
3985 | } | ||
3986 | if (!conn->conn_ops->OFMarker) { | ||
3987 | pr_err("Unable to recover from unknown" | ||
3988 | " opcode while OFMarker=No, closing iSCSI" | ||
3989 | " connection.\n"); | ||
3990 | return -1; | ||
3991 | } | ||
3992 | if (iscsit_recover_from_unknown_opcode(conn) < 0) { | ||
3993 | pr_err("Unable to recover from unknown" | ||
3994 | " opcode, closing iSCSI connection.\n"); | ||
3995 | return -1; | ||
3996 | } | ||
3997 | break; | ||
3998 | } | ||
3999 | |||
4000 | return ret; | ||
4001 | } | ||
4002 | |||
3745 | int iscsi_target_rx_thread(void *arg) | 4003 | int iscsi_target_rx_thread(void *arg) |
3746 | { | 4004 | { |
3747 | int ret; | 4005 | int ret; |
@@ -3761,6 +4019,18 @@ restart: | |||
3761 | if (!conn) | 4019 | if (!conn) |
3762 | goto out; | 4020 | goto out; |
3763 | 4021 | ||
4022 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) { | ||
4023 | struct completion comp; | ||
4024 | int rc; | ||
4025 | |||
4026 | init_completion(&comp); | ||
4027 | rc = wait_for_completion_interruptible(&comp); | ||
4028 | if (rc < 0) | ||
4029 | goto transport_err; | ||
4030 | |||
4031 | goto out; | ||
4032 | } | ||
4033 | |||
3764 | while (!kthread_should_stop()) { | 4034 | while (!kthread_should_stop()) { |
3765 | /* | 4035 | /* |
3766 | * Ensure that both TX and RX per connection kthreads | 4036 | * Ensure that both TX and RX per connection kthreads |
@@ -3832,62 +4102,9 @@ restart: | |||
3832 | goto transport_err; | 4102 | goto transport_err; |
3833 | } | 4103 | } |
3834 | 4104 | ||
3835 | switch (opcode) { | 4105 | ret = iscsi_target_rx_opcode(conn, buffer); |
3836 | case ISCSI_OP_SCSI_CMD: | 4106 | if (ret < 0) |
3837 | if (iscsit_handle_scsi_cmd(conn, buffer) < 0) | 4107 | goto transport_err; |
3838 | goto transport_err; | ||
3839 | break; | ||
3840 | case ISCSI_OP_SCSI_DATA_OUT: | ||
3841 | if (iscsit_handle_data_out(conn, buffer) < 0) | ||
3842 | goto transport_err; | ||
3843 | break; | ||
3844 | case ISCSI_OP_NOOP_OUT: | ||
3845 | if (iscsit_handle_nop_out(conn, buffer) < 0) | ||
3846 | goto transport_err; | ||
3847 | break; | ||
3848 | case ISCSI_OP_SCSI_TMFUNC: | ||
3849 | if (iscsit_handle_task_mgt_cmd(conn, buffer) < 0) | ||
3850 | goto transport_err; | ||
3851 | break; | ||
3852 | case ISCSI_OP_TEXT: | ||
3853 | if (iscsit_handle_text_cmd(conn, buffer) < 0) | ||
3854 | goto transport_err; | ||
3855 | break; | ||
3856 | case ISCSI_OP_LOGOUT: | ||
3857 | ret = iscsit_handle_logout_cmd(conn, buffer); | ||
3858 | if (ret > 0) { | ||
3859 | wait_for_completion_timeout(&conn->conn_logout_comp, | ||
3860 | SECONDS_FOR_LOGOUT_COMP * HZ); | ||
3861 | goto transport_err; | ||
3862 | } else if (ret < 0) | ||
3863 | goto transport_err; | ||
3864 | break; | ||
3865 | case ISCSI_OP_SNACK: | ||
3866 | if (iscsit_handle_snack(conn, buffer) < 0) | ||
3867 | goto transport_err; | ||
3868 | break; | ||
3869 | default: | ||
3870 | pr_err("Got unknown iSCSI OpCode: 0x%02x\n", | ||
3871 | opcode); | ||
3872 | if (!conn->sess->sess_ops->ErrorRecoveryLevel) { | ||
3873 | pr_err("Cannot recover from unknown" | ||
3874 | " opcode while ERL=0, closing iSCSI connection" | ||
3875 | ".\n"); | ||
3876 | goto transport_err; | ||
3877 | } | ||
3878 | if (!conn->conn_ops->OFMarker) { | ||
3879 | pr_err("Unable to recover from unknown" | ||
3880 | " opcode while OFMarker=No, closing iSCSI" | ||
3881 | " connection.\n"); | ||
3882 | goto transport_err; | ||
3883 | } | ||
3884 | if (iscsit_recover_from_unknown_opcode(conn) < 0) { | ||
3885 | pr_err("Unable to recover from unknown" | ||
3886 | " opcode, closing iSCSI connection.\n"); | ||
3887 | goto transport_err; | ||
3888 | } | ||
3889 | break; | ||
3890 | } | ||
3891 | } | 4108 | } |
3892 | 4109 | ||
3893 | transport_err: | 4110 | transport_err: |
@@ -4053,6 +4270,12 @@ int iscsit_close_connection( | |||
4053 | 4270 | ||
4054 | if (conn->sock) | 4271 | if (conn->sock) |
4055 | sock_release(conn->sock); | 4272 | sock_release(conn->sock); |
4273 | |||
4274 | if (conn->conn_transport->iscsit_free_conn) | ||
4275 | conn->conn_transport->iscsit_free_conn(conn); | ||
4276 | |||
4277 | iscsit_put_transport(conn->conn_transport); | ||
4278 | |||
4056 | conn->thread_set = NULL; | 4279 | conn->thread_set = NULL; |
4057 | 4280 | ||
4058 | pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); | 4281 | pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); |
@@ -4284,7 +4507,7 @@ static void iscsit_logout_post_handler_diffcid( | |||
4284 | /* | 4507 | /* |
4285 | * Return of 0 causes the TX thread to restart. | 4508 | * Return of 0 causes the TX thread to restart. |
4286 | */ | 4509 | */ |
4287 | static int iscsit_logout_post_handler( | 4510 | int iscsit_logout_post_handler( |
4288 | struct iscsi_cmd *cmd, | 4511 | struct iscsi_cmd *cmd, |
4289 | struct iscsi_conn *conn) | 4512 | struct iscsi_conn *conn) |
4290 | { | 4513 | { |
@@ -4342,6 +4565,7 @@ static int iscsit_logout_post_handler( | |||
4342 | } | 4565 | } |
4343 | return ret; | 4566 | return ret; |
4344 | } | 4567 | } |
4568 | EXPORT_SYMBOL(iscsit_logout_post_handler); | ||
4345 | 4569 | ||
4346 | void iscsit_fail_session(struct iscsi_session *sess) | 4570 | void iscsit_fail_session(struct iscsi_session *sess) |
4347 | { | 4571 | { |
diff --git a/drivers/target/iscsi/iscsi_target.h b/drivers/target/iscsi/iscsi_target.h index b1a1e6350707..a0050b2f294e 100644 --- a/drivers/target/iscsi/iscsi_target.h +++ b/drivers/target/iscsi/iscsi_target.h | |||
@@ -16,11 +16,12 @@ extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, | |||
16 | struct iscsi_portal_group *); | 16 | struct iscsi_portal_group *); |
17 | extern int iscsit_del_np(struct iscsi_np *); | 17 | extern int iscsit_del_np(struct iscsi_np *); |
18 | extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *); | 18 | extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *); |
19 | extern void iscsit_set_unsoliticed_dataout(struct iscsi_cmd *); | ||
19 | extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *); | 20 | extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *); |
20 | extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *); | 21 | extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *); |
21 | extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *); | 22 | extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *); |
22 | extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8); | 23 | extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8); |
23 | extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, bool recovery); | 24 | extern int iscsit_build_r2ts_for_cmd(struct iscsi_conn *, struct iscsi_cmd *, bool recovery); |
24 | extern void iscsit_thread_get_cpumask(struct iscsi_conn *); | 25 | extern void iscsit_thread_get_cpumask(struct iscsi_conn *); |
25 | extern int iscsi_target_tx_thread(void *); | 26 | extern int iscsi_target_tx_thread(void *); |
26 | extern int iscsi_target_rx_thread(void *); | 27 | extern int iscsi_target_rx_thread(void *); |
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c index a0fc7b9eea65..cee17543278c 100644 --- a/drivers/target/iscsi/iscsi_target_auth.c +++ b/drivers/target/iscsi/iscsi_target_auth.c | |||
@@ -49,32 +49,6 @@ static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len) | |||
49 | } | 49 | } |
50 | } | 50 | } |
51 | 51 | ||
52 | static void chap_set_random(char *data, int length) | ||
53 | { | ||
54 | long r; | ||
55 | unsigned n; | ||
56 | |||
57 | while (length > 0) { | ||
58 | get_random_bytes(&r, sizeof(long)); | ||
59 | r = r ^ (r >> 8); | ||
60 | r = r ^ (r >> 4); | ||
61 | n = r & 0x7; | ||
62 | |||
63 | get_random_bytes(&r, sizeof(long)); | ||
64 | r = r ^ (r >> 8); | ||
65 | r = r ^ (r >> 5); | ||
66 | n = (n << 3) | (r & 0x7); | ||
67 | |||
68 | get_random_bytes(&r, sizeof(long)); | ||
69 | r = r ^ (r >> 8); | ||
70 | r = r ^ (r >> 5); | ||
71 | n = (n << 2) | (r & 0x3); | ||
72 | |||
73 | *data++ = n; | ||
74 | length--; | ||
75 | } | ||
76 | } | ||
77 | |||
78 | static void chap_gen_challenge( | 52 | static void chap_gen_challenge( |
79 | struct iscsi_conn *conn, | 53 | struct iscsi_conn *conn, |
80 | int caller, | 54 | int caller, |
@@ -86,7 +60,7 @@ static void chap_gen_challenge( | |||
86 | 60 | ||
87 | memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1); | 61 | memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1); |
88 | 62 | ||
89 | chap_set_random(chap->challenge, CHAP_CHALLENGE_LENGTH); | 63 | get_random_bytes(chap->challenge, CHAP_CHALLENGE_LENGTH); |
90 | chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge, | 64 | chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge, |
91 | CHAP_CHALLENGE_LENGTH); | 65 | CHAP_CHALLENGE_LENGTH); |
92 | /* | 66 | /* |
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c index 78d75c8567d0..13e9e715ad2e 100644 --- a/drivers/target/iscsi/iscsi_target_configfs.c +++ b/drivers/target/iscsi/iscsi_target_configfs.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <target/target_core_fabric_configfs.h> | 27 | #include <target/target_core_fabric_configfs.h> |
28 | #include <target/target_core_configfs.h> | 28 | #include <target/target_core_configfs.h> |
29 | #include <target/configfs_macros.h> | 29 | #include <target/configfs_macros.h> |
30 | #include <target/iscsi/iscsi_transport.h> | ||
30 | 31 | ||
31 | #include "iscsi_target_core.h" | 32 | #include "iscsi_target_core.h" |
32 | #include "iscsi_target_parameters.h" | 33 | #include "iscsi_target_parameters.h" |
@@ -124,8 +125,87 @@ out: | |||
124 | 125 | ||
125 | TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR); | 126 | TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR); |
126 | 127 | ||
128 | static ssize_t lio_target_np_show_iser( | ||
129 | struct se_tpg_np *se_tpg_np, | ||
130 | char *page) | ||
131 | { | ||
132 | struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, | ||
133 | struct iscsi_tpg_np, se_tpg_np); | ||
134 | struct iscsi_tpg_np *tpg_np_iser; | ||
135 | ssize_t rb; | ||
136 | |||
137 | tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND); | ||
138 | if (tpg_np_iser) | ||
139 | rb = sprintf(page, "1\n"); | ||
140 | else | ||
141 | rb = sprintf(page, "0\n"); | ||
142 | |||
143 | return rb; | ||
144 | } | ||
145 | |||
146 | static ssize_t lio_target_np_store_iser( | ||
147 | struct se_tpg_np *se_tpg_np, | ||
148 | const char *page, | ||
149 | size_t count) | ||
150 | { | ||
151 | struct iscsi_np *np; | ||
152 | struct iscsi_portal_group *tpg; | ||
153 | struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, | ||
154 | struct iscsi_tpg_np, se_tpg_np); | ||
155 | struct iscsi_tpg_np *tpg_np_iser = NULL; | ||
156 | char *endptr; | ||
157 | u32 op; | ||
158 | int rc; | ||
159 | |||
160 | op = simple_strtoul(page, &endptr, 0); | ||
161 | if ((op != 1) && (op != 0)) { | ||
162 | pr_err("Illegal value for tpg_enable: %u\n", op); | ||
163 | return -EINVAL; | ||
164 | } | ||
165 | np = tpg_np->tpg_np; | ||
166 | if (!np) { | ||
167 | pr_err("Unable to locate struct iscsi_np from" | ||
168 | " struct iscsi_tpg_np\n"); | ||
169 | return -EINVAL; | ||
170 | } | ||
171 | |||
172 | tpg = tpg_np->tpg; | ||
173 | if (iscsit_get_tpg(tpg) < 0) | ||
174 | return -EINVAL; | ||
175 | |||
176 | if (op) { | ||
177 | int rc = request_module("ib_isert"); | ||
178 | if (rc != 0) | ||
179 | pr_warn("Unable to request_module for ib_isert\n"); | ||
180 | |||
181 | tpg_np_iser = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr, | ||
182 | np->np_ip, tpg_np, ISCSI_INFINIBAND); | ||
183 | if (!tpg_np_iser || IS_ERR(tpg_np_iser)) | ||
184 | goto out; | ||
185 | } else { | ||
186 | tpg_np_iser = iscsit_tpg_locate_child_np(tpg_np, ISCSI_INFINIBAND); | ||
187 | if (!tpg_np_iser) | ||
188 | goto out; | ||
189 | |||
190 | rc = iscsit_tpg_del_network_portal(tpg, tpg_np_iser); | ||
191 | if (rc < 0) | ||
192 | goto out; | ||
193 | } | ||
194 | |||
195 | printk("lio_target_np_store_iser() done, op: %d\n", op); | ||
196 | |||
197 | iscsit_put_tpg(tpg); | ||
198 | return count; | ||
199 | out: | ||
200 | iscsit_put_tpg(tpg); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | TF_NP_BASE_ATTR(lio_target, iser, S_IRUGO | S_IWUSR); | ||
205 | |||
127 | static struct configfs_attribute *lio_target_portal_attrs[] = { | 206 | static struct configfs_attribute *lio_target_portal_attrs[] = { |
128 | &lio_target_np_sctp.attr, | 207 | &lio_target_np_sctp.attr, |
208 | &lio_target_np_iser.attr, | ||
129 | NULL, | 209 | NULL, |
130 | }; | 210 | }; |
131 | 211 | ||
@@ -1536,16 +1616,18 @@ static int lio_queue_data_in(struct se_cmd *se_cmd) | |||
1536 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); | 1616 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); |
1537 | 1617 | ||
1538 | cmd->i_state = ISTATE_SEND_DATAIN; | 1618 | cmd->i_state = ISTATE_SEND_DATAIN; |
1539 | iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); | 1619 | cmd->conn->conn_transport->iscsit_queue_data_in(cmd->conn, cmd); |
1620 | |||
1540 | return 0; | 1621 | return 0; |
1541 | } | 1622 | } |
1542 | 1623 | ||
1543 | static int lio_write_pending(struct se_cmd *se_cmd) | 1624 | static int lio_write_pending(struct se_cmd *se_cmd) |
1544 | { | 1625 | { |
1545 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); | 1626 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); |
1627 | struct iscsi_conn *conn = cmd->conn; | ||
1546 | 1628 | ||
1547 | if (!cmd->immediate_data && !cmd->unsolicited_data) | 1629 | if (!cmd->immediate_data && !cmd->unsolicited_data) |
1548 | return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false); | 1630 | return conn->conn_transport->iscsit_get_dataout(conn, cmd, false); |
1549 | 1631 | ||
1550 | return 0; | 1632 | return 0; |
1551 | } | 1633 | } |
@@ -1567,7 +1649,8 @@ static int lio_queue_status(struct se_cmd *se_cmd) | |||
1567 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); | 1649 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); |
1568 | 1650 | ||
1569 | cmd->i_state = ISTATE_SEND_STATUS; | 1651 | cmd->i_state = ISTATE_SEND_STATUS; |
1570 | iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); | 1652 | cmd->conn->conn_transport->iscsit_queue_status(cmd->conn, cmd); |
1653 | |||
1571 | return 0; | 1654 | return 0; |
1572 | } | 1655 | } |
1573 | 1656 | ||
@@ -1696,11 +1779,17 @@ static void lio_set_default_node_attributes(struct se_node_acl *se_acl) | |||
1696 | iscsit_set_default_node_attribues(acl); | 1779 | iscsit_set_default_node_attribues(acl); |
1697 | } | 1780 | } |
1698 | 1781 | ||
1782 | static int lio_check_stop_free(struct se_cmd *se_cmd) | ||
1783 | { | ||
1784 | return target_put_sess_cmd(se_cmd->se_sess, se_cmd); | ||
1785 | } | ||
1786 | |||
1699 | static void lio_release_cmd(struct se_cmd *se_cmd) | 1787 | static void lio_release_cmd(struct se_cmd *se_cmd) |
1700 | { | 1788 | { |
1701 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); | 1789 | struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); |
1702 | 1790 | ||
1703 | iscsit_release_cmd(cmd); | 1791 | pr_debug("Entering lio_release_cmd for se_cmd: %p\n", se_cmd); |
1792 | cmd->release_cmd(cmd); | ||
1704 | } | 1793 | } |
1705 | 1794 | ||
1706 | /* End functions for target_core_fabric_ops */ | 1795 | /* End functions for target_core_fabric_ops */ |
@@ -1740,6 +1829,7 @@ int iscsi_target_register_configfs(void) | |||
1740 | fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; | 1829 | fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; |
1741 | fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; | 1830 | fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; |
1742 | fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; | 1831 | fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; |
1832 | fabric->tf_ops.check_stop_free = &lio_check_stop_free, | ||
1743 | fabric->tf_ops.release_cmd = &lio_release_cmd; | 1833 | fabric->tf_ops.release_cmd = &lio_release_cmd; |
1744 | fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session; | 1834 | fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session; |
1745 | fabric->tf_ops.close_session = &lio_tpg_close_session; | 1835 | fabric->tf_ops.close_session = &lio_tpg_close_session; |
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h index 7a333d28d9a2..60ec4b92be03 100644 --- a/drivers/target/iscsi/iscsi_target_core.h +++ b/drivers/target/iscsi/iscsi_target_core.h | |||
@@ -60,7 +60,7 @@ | |||
60 | 60 | ||
61 | #define ISCSI_IOV_DATA_BUFFER 5 | 61 | #define ISCSI_IOV_DATA_BUFFER 5 |
62 | 62 | ||
63 | enum tpg_np_network_transport_table { | 63 | enum iscsit_transport_type { |
64 | ISCSI_TCP = 0, | 64 | ISCSI_TCP = 0, |
65 | ISCSI_SCTP_TCP = 1, | 65 | ISCSI_SCTP_TCP = 1, |
66 | ISCSI_SCTP_UDP = 2, | 66 | ISCSI_SCTP_UDP = 2, |
@@ -244,6 +244,11 @@ struct iscsi_conn_ops { | |||
244 | u8 IFMarker; /* [0,1] == [No,Yes] */ | 244 | u8 IFMarker; /* [0,1] == [No,Yes] */ |
245 | u32 OFMarkInt; /* [1..65535] */ | 245 | u32 OFMarkInt; /* [1..65535] */ |
246 | u32 IFMarkInt; /* [1..65535] */ | 246 | u32 IFMarkInt; /* [1..65535] */ |
247 | /* | ||
248 | * iSER specific connection parameters | ||
249 | */ | ||
250 | u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */ | ||
251 | u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */ | ||
247 | }; | 252 | }; |
248 | 253 | ||
249 | struct iscsi_sess_ops { | 254 | struct iscsi_sess_ops { |
@@ -265,6 +270,10 @@ struct iscsi_sess_ops { | |||
265 | u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */ | 270 | u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */ |
266 | u8 ErrorRecoveryLevel; /* [0..2] */ | 271 | u8 ErrorRecoveryLevel; /* [0..2] */ |
267 | u8 SessionType; /* [0,1] == [Normal,Discovery]*/ | 272 | u8 SessionType; /* [0,1] == [Normal,Discovery]*/ |
273 | /* | ||
274 | * iSER specific session parameters | ||
275 | */ | ||
276 | u8 RDMAExtensions; /* [0,1] == [No,Yes] */ | ||
268 | }; | 277 | }; |
269 | 278 | ||
270 | struct iscsi_queue_req { | 279 | struct iscsi_queue_req { |
@@ -284,6 +293,7 @@ struct iscsi_data_count { | |||
284 | }; | 293 | }; |
285 | 294 | ||
286 | struct iscsi_param_list { | 295 | struct iscsi_param_list { |
296 | bool iser; | ||
287 | struct list_head param_list; | 297 | struct list_head param_list; |
288 | struct list_head extra_response_list; | 298 | struct list_head extra_response_list; |
289 | }; | 299 | }; |
@@ -475,6 +485,7 @@ struct iscsi_cmd { | |||
475 | u32 first_data_sg_off; | 485 | u32 first_data_sg_off; |
476 | u32 kmapped_nents; | 486 | u32 kmapped_nents; |
477 | sense_reason_t sense_reason; | 487 | sense_reason_t sense_reason; |
488 | void (*release_cmd)(struct iscsi_cmd *); | ||
478 | } ____cacheline_aligned; | 489 | } ____cacheline_aligned; |
479 | 490 | ||
480 | struct iscsi_tmr_req { | 491 | struct iscsi_tmr_req { |
@@ -503,6 +514,7 @@ struct iscsi_conn { | |||
503 | u16 login_port; | 514 | u16 login_port; |
504 | u16 local_port; | 515 | u16 local_port; |
505 | int net_size; | 516 | int net_size; |
517 | int login_family; | ||
506 | u32 auth_id; | 518 | u32 auth_id; |
507 | u32 conn_flags; | 519 | u32 conn_flags; |
508 | /* Used for iscsi_tx_login_rsp() */ | 520 | /* Used for iscsi_tx_login_rsp() */ |
@@ -562,9 +574,12 @@ struct iscsi_conn { | |||
562 | struct list_head immed_queue_list; | 574 | struct list_head immed_queue_list; |
563 | struct list_head response_queue_list; | 575 | struct list_head response_queue_list; |
564 | struct iscsi_conn_ops *conn_ops; | 576 | struct iscsi_conn_ops *conn_ops; |
577 | struct iscsi_login *conn_login; | ||
578 | struct iscsit_transport *conn_transport; | ||
565 | struct iscsi_param_list *param_list; | 579 | struct iscsi_param_list *param_list; |
566 | /* Used for per connection auth state machine */ | 580 | /* Used for per connection auth state machine */ |
567 | void *auth_protocol; | 581 | void *auth_protocol; |
582 | void *context; | ||
568 | struct iscsi_login_thread_s *login_thread; | 583 | struct iscsi_login_thread_s *login_thread; |
569 | struct iscsi_portal_group *tpg; | 584 | struct iscsi_portal_group *tpg; |
570 | /* Pointer to parent session */ | 585 | /* Pointer to parent session */ |
@@ -663,6 +678,8 @@ struct iscsi_login { | |||
663 | u8 first_request; | 678 | u8 first_request; |
664 | u8 version_min; | 679 | u8 version_min; |
665 | u8 version_max; | 680 | u8 version_max; |
681 | u8 login_complete; | ||
682 | u8 login_failed; | ||
666 | char isid[6]; | 683 | char isid[6]; |
667 | u32 cmd_sn; | 684 | u32 cmd_sn; |
668 | itt_t init_task_tag; | 685 | itt_t init_task_tag; |
@@ -670,10 +687,11 @@ struct iscsi_login { | |||
670 | u32 rsp_length; | 687 | u32 rsp_length; |
671 | u16 cid; | 688 | u16 cid; |
672 | u16 tsih; | 689 | u16 tsih; |
673 | char *req; | 690 | char req[ISCSI_HDR_LEN]; |
674 | char *rsp; | 691 | char rsp[ISCSI_HDR_LEN]; |
675 | char *req_buf; | 692 | char *req_buf; |
676 | char *rsp_buf; | 693 | char *rsp_buf; |
694 | struct iscsi_conn *conn; | ||
677 | } ____cacheline_aligned; | 695 | } ____cacheline_aligned; |
678 | 696 | ||
679 | struct iscsi_node_attrib { | 697 | struct iscsi_node_attrib { |
@@ -754,6 +772,8 @@ struct iscsi_np { | |||
754 | struct task_struct *np_thread; | 772 | struct task_struct *np_thread; |
755 | struct timer_list np_login_timer; | 773 | struct timer_list np_login_timer; |
756 | struct iscsi_portal_group *np_login_tpg; | 774 | struct iscsi_portal_group *np_login_tpg; |
775 | void *np_context; | ||
776 | struct iscsit_transport *np_transport; | ||
757 | struct list_head np_list; | 777 | struct list_head np_list; |
758 | } ____cacheline_aligned; | 778 | } ____cacheline_aligned; |
759 | 779 | ||
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c index bcc409853a67..1b74033510a0 100644 --- a/drivers/target/iscsi/iscsi_target_device.c +++ b/drivers/target/iscsi/iscsi_target_device.c | |||
@@ -60,8 +60,13 @@ void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess | |||
60 | 60 | ||
61 | cmd->maxcmdsn_inc = 1; | 61 | cmd->maxcmdsn_inc = 1; |
62 | 62 | ||
63 | mutex_lock(&sess->cmdsn_mutex); | 63 | if (!mutex_trylock(&sess->cmdsn_mutex)) { |
64 | sess->max_cmd_sn += 1; | ||
65 | pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn); | ||
66 | return; | ||
67 | } | ||
64 | sess->max_cmd_sn += 1; | 68 | sess->max_cmd_sn += 1; |
65 | pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn); | 69 | pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn); |
66 | mutex_unlock(&sess->cmdsn_mutex); | 70 | mutex_unlock(&sess->cmdsn_mutex); |
67 | } | 71 | } |
72 | EXPORT_SYMBOL(iscsit_increment_maxcmdsn); | ||
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c index 0b52a2371305..7816af6cdd12 100644 --- a/drivers/target/iscsi/iscsi_target_erl1.c +++ b/drivers/target/iscsi/iscsi_target_erl1.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <scsi/iscsi_proto.h> | 22 | #include <scsi/iscsi_proto.h> |
23 | #include <target/target_core_base.h> | 23 | #include <target/target_core_base.h> |
24 | #include <target/target_core_fabric.h> | 24 | #include <target/target_core_fabric.h> |
25 | #include <target/iscsi/iscsi_transport.h> | ||
25 | 26 | ||
26 | #include "iscsi_target_core.h" | 27 | #include "iscsi_target_core.h" |
27 | #include "iscsi_target_seq_pdu_list.h" | 28 | #include "iscsi_target_seq_pdu_list.h" |
@@ -53,6 +54,9 @@ int iscsit_dump_data_payload( | |||
53 | u32 length, padding, offset = 0, size; | 54 | u32 length, padding, offset = 0, size; |
54 | struct kvec iov; | 55 | struct kvec iov; |
55 | 56 | ||
57 | if (conn->sess->sess_ops->RDMAExtensions) | ||
58 | return 0; | ||
59 | |||
56 | length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len; | 60 | length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len; |
57 | 61 | ||
58 | buf = kzalloc(length, GFP_ATOMIC); | 62 | buf = kzalloc(length, GFP_ATOMIC); |
@@ -919,6 +923,7 @@ int iscsit_execute_ooo_cmdsns(struct iscsi_session *sess) | |||
919 | int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) | 923 | int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) |
920 | { | 924 | { |
921 | struct se_cmd *se_cmd = &cmd->se_cmd; | 925 | struct se_cmd *se_cmd = &cmd->se_cmd; |
926 | struct iscsi_conn *conn = cmd->conn; | ||
922 | int lr = 0; | 927 | int lr = 0; |
923 | 928 | ||
924 | spin_lock_bh(&cmd->istate_lock); | 929 | spin_lock_bh(&cmd->istate_lock); |
@@ -981,7 +986,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) | |||
981 | return 0; | 986 | return 0; |
982 | 987 | ||
983 | iscsit_set_dataout_sequence_values(cmd); | 988 | iscsit_set_dataout_sequence_values(cmd); |
984 | iscsit_build_r2ts_for_cmd(cmd, cmd->conn, false); | 989 | conn->conn_transport->iscsit_get_dataout(conn, cmd, false); |
985 | } | 990 | } |
986 | return 0; | 991 | return 0; |
987 | } | 992 | } |
@@ -999,10 +1004,7 @@ int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) | |||
999 | if (transport_check_aborted_status(se_cmd, 1) != 0) | 1004 | if (transport_check_aborted_status(se_cmd, 1) != 0) |
1000 | return 0; | 1005 | return 0; |
1001 | 1006 | ||
1002 | iscsit_set_dataout_sequence_values(cmd); | 1007 | iscsit_set_unsoliticed_dataout(cmd); |
1003 | spin_lock_bh(&cmd->dataout_timeout_lock); | ||
1004 | iscsit_start_dataout_timer(cmd, cmd->conn); | ||
1005 | spin_unlock_bh(&cmd->dataout_timeout_lock); | ||
1006 | } | 1008 | } |
1007 | return transport_handle_cdb_direct(&cmd->se_cmd); | 1009 | return transport_handle_cdb_direct(&cmd->se_cmd); |
1008 | 1010 | ||
@@ -1290,3 +1292,4 @@ void iscsit_stop_dataout_timer(struct iscsi_cmd *cmd) | |||
1290 | cmd->init_task_tag); | 1292 | cmd->init_task_tag); |
1291 | spin_unlock_bh(&cmd->dataout_timeout_lock); | 1293 | spin_unlock_bh(&cmd->dataout_timeout_lock); |
1292 | } | 1294 | } |
1295 | EXPORT_SYMBOL(iscsit_stop_dataout_timer); | ||
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c index 2535d4d46c0e..bb5d5c5bce65 100644 --- a/drivers/target/iscsi/iscsi_target_login.c +++ b/drivers/target/iscsi/iscsi_target_login.c | |||
@@ -39,8 +39,39 @@ | |||
39 | #include "iscsi_target.h" | 39 | #include "iscsi_target.h" |
40 | #include "iscsi_target_parameters.h" | 40 | #include "iscsi_target_parameters.h" |
41 | 41 | ||
42 | static int iscsi_login_init_conn(struct iscsi_conn *conn) | 42 | #include <target/iscsi/iscsi_transport.h> |
43 | |||
44 | static struct iscsi_login *iscsi_login_init_conn(struct iscsi_conn *conn) | ||
43 | { | 45 | { |
46 | struct iscsi_login *login; | ||
47 | |||
48 | login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL); | ||
49 | if (!login) { | ||
50 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); | ||
51 | return NULL; | ||
52 | } | ||
53 | login->conn = conn; | ||
54 | login->first_request = 1; | ||
55 | |||
56 | login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); | ||
57 | if (!login->req_buf) { | ||
58 | pr_err("Unable to allocate memory for response buffer.\n"); | ||
59 | goto out_login; | ||
60 | } | ||
61 | |||
62 | login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); | ||
63 | if (!login->rsp_buf) { | ||
64 | pr_err("Unable to allocate memory for request buffer.\n"); | ||
65 | goto out_req_buf; | ||
66 | } | ||
67 | |||
68 | conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL); | ||
69 | if (!conn->conn_ops) { | ||
70 | pr_err("Unable to allocate memory for" | ||
71 | " struct iscsi_conn_ops.\n"); | ||
72 | goto out_rsp_buf; | ||
73 | } | ||
74 | |||
44 | init_waitqueue_head(&conn->queues_wq); | 75 | init_waitqueue_head(&conn->queues_wq); |
45 | INIT_LIST_HEAD(&conn->conn_list); | 76 | INIT_LIST_HEAD(&conn->conn_list); |
46 | INIT_LIST_HEAD(&conn->conn_cmd_list); | 77 | INIT_LIST_HEAD(&conn->conn_cmd_list); |
@@ -62,10 +93,21 @@ static int iscsi_login_init_conn(struct iscsi_conn *conn) | |||
62 | 93 | ||
63 | if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) { | 94 | if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) { |
64 | pr_err("Unable to allocate conn->conn_cpumask\n"); | 95 | pr_err("Unable to allocate conn->conn_cpumask\n"); |
65 | return -ENOMEM; | 96 | goto out_conn_ops; |
66 | } | 97 | } |
98 | conn->conn_login = login; | ||
67 | 99 | ||
68 | return 0; | 100 | return login; |
101 | |||
102 | out_conn_ops: | ||
103 | kfree(conn->conn_ops); | ||
104 | out_rsp_buf: | ||
105 | kfree(login->rsp_buf); | ||
106 | out_req_buf: | ||
107 | kfree(login->req_buf); | ||
108 | out_login: | ||
109 | kfree(login); | ||
110 | return NULL; | ||
69 | } | 111 | } |
70 | 112 | ||
71 | /* | 113 | /* |
@@ -298,6 +340,7 @@ static int iscsi_login_zero_tsih_s2( | |||
298 | struct iscsi_node_attrib *na; | 340 | struct iscsi_node_attrib *na; |
299 | struct iscsi_session *sess = conn->sess; | 341 | struct iscsi_session *sess = conn->sess; |
300 | unsigned char buf[32]; | 342 | unsigned char buf[32]; |
343 | bool iser = false; | ||
301 | 344 | ||
302 | sess->tpg = conn->tpg; | 345 | sess->tpg = conn->tpg; |
303 | 346 | ||
@@ -319,7 +362,10 @@ static int iscsi_login_zero_tsih_s2( | |||
319 | return -1; | 362 | return -1; |
320 | } | 363 | } |
321 | 364 | ||
322 | iscsi_set_keys_to_negotiate(0, conn->param_list); | 365 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) |
366 | iser = true; | ||
367 | |||
368 | iscsi_set_keys_to_negotiate(conn->param_list, iser); | ||
323 | 369 | ||
324 | if (sess->sess_ops->SessionType) | 370 | if (sess->sess_ops->SessionType) |
325 | return iscsi_set_keys_irrelevant_for_discovery( | 371 | return iscsi_set_keys_irrelevant_for_discovery( |
@@ -357,6 +403,56 @@ static int iscsi_login_zero_tsih_s2( | |||
357 | 403 | ||
358 | if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0) | 404 | if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0) |
359 | return -1; | 405 | return -1; |
406 | /* | ||
407 | * Set RDMAExtensions=Yes by default for iSER enabled network portals | ||
408 | */ | ||
409 | if (iser) { | ||
410 | struct iscsi_param *param; | ||
411 | unsigned long mrdsl, off; | ||
412 | int rc; | ||
413 | |||
414 | sprintf(buf, "RDMAExtensions=Yes"); | ||
415 | if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) { | ||
416 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
417 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
418 | return -1; | ||
419 | } | ||
420 | /* | ||
421 | * Make MaxRecvDataSegmentLength PAGE_SIZE aligned for | ||
422 | * Immediate Data + Unsolicitied Data-OUT if necessary.. | ||
423 | */ | ||
424 | param = iscsi_find_param_from_key("MaxRecvDataSegmentLength", | ||
425 | conn->param_list); | ||
426 | if (!param) { | ||
427 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
428 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
429 | return -1; | ||
430 | } | ||
431 | rc = strict_strtoul(param->value, 0, &mrdsl); | ||
432 | if (rc < 0) { | ||
433 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
434 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
435 | return -1; | ||
436 | } | ||
437 | off = mrdsl % PAGE_SIZE; | ||
438 | if (!off) | ||
439 | return 0; | ||
440 | |||
441 | if (mrdsl < PAGE_SIZE) | ||
442 | mrdsl = PAGE_SIZE; | ||
443 | else | ||
444 | mrdsl -= off; | ||
445 | |||
446 | pr_warn("Aligning ISER MaxRecvDataSegmentLength: %lu down" | ||
447 | " to PAGE_SIZE\n", mrdsl); | ||
448 | |||
449 | sprintf(buf, "MaxRecvDataSegmentLength=%lu\n", mrdsl); | ||
450 | if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) { | ||
451 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
452 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
453 | return -1; | ||
454 | } | ||
455 | } | ||
360 | 456 | ||
361 | return 0; | 457 | return 0; |
362 | } | 458 | } |
@@ -436,6 +532,7 @@ static int iscsi_login_non_zero_tsih_s2( | |||
436 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; | 532 | struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; |
437 | struct se_session *se_sess, *se_sess_tmp; | 533 | struct se_session *se_sess, *se_sess_tmp; |
438 | struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; | 534 | struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; |
535 | bool iser = false; | ||
439 | 536 | ||
440 | spin_lock_bh(&se_tpg->session_lock); | 537 | spin_lock_bh(&se_tpg->session_lock); |
441 | list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, | 538 | list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, |
@@ -485,7 +582,10 @@ static int iscsi_login_non_zero_tsih_s2( | |||
485 | return -1; | 582 | return -1; |
486 | } | 583 | } |
487 | 584 | ||
488 | iscsi_set_keys_to_negotiate(0, conn->param_list); | 585 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) |
586 | iser = true; | ||
587 | |||
588 | iscsi_set_keys_to_negotiate(conn->param_list, iser); | ||
489 | /* | 589 | /* |
490 | * Need to send TargetPortalGroupTag back in first login response | 590 | * Need to send TargetPortalGroupTag back in first login response |
491 | * on any iSCSI connection where the Initiator provides TargetName. | 591 | * on any iSCSI connection where the Initiator provides TargetName. |
@@ -574,6 +674,11 @@ int iscsi_login_post_auth_non_zero_tsih( | |||
574 | static void iscsi_post_login_start_timers(struct iscsi_conn *conn) | 674 | static void iscsi_post_login_start_timers(struct iscsi_conn *conn) |
575 | { | 675 | { |
576 | struct iscsi_session *sess = conn->sess; | 676 | struct iscsi_session *sess = conn->sess; |
677 | /* | ||
678 | * FIXME: Unsolicitied NopIN support for ISER | ||
679 | */ | ||
680 | if (conn->conn_transport->transport_type == ISCSI_INFINIBAND) | ||
681 | return; | ||
577 | 682 | ||
578 | if (!sess->sess_ops->SessionType) | 683 | if (!sess->sess_ops->SessionType) |
579 | iscsit_start_nopin_timer(conn); | 684 | iscsit_start_nopin_timer(conn); |
@@ -632,6 +737,7 @@ static int iscsi_post_login_handler( | |||
632 | spin_unlock_bh(&sess->conn_lock); | 737 | spin_unlock_bh(&sess->conn_lock); |
633 | 738 | ||
634 | iscsi_post_login_start_timers(conn); | 739 | iscsi_post_login_start_timers(conn); |
740 | |||
635 | iscsi_activate_thread_set(conn, ts); | 741 | iscsi_activate_thread_set(conn, ts); |
636 | /* | 742 | /* |
637 | * Determine CPU mask to ensure connection's RX and TX kthreads | 743 | * Determine CPU mask to ensure connection's RX and TX kthreads |
@@ -761,11 +867,11 @@ static void iscsi_stop_login_thread_timer(struct iscsi_np *np) | |||
761 | spin_unlock_bh(&np->np_thread_lock); | 867 | spin_unlock_bh(&np->np_thread_lock); |
762 | } | 868 | } |
763 | 869 | ||
764 | int iscsi_target_setup_login_socket( | 870 | int iscsit_setup_np( |
765 | struct iscsi_np *np, | 871 | struct iscsi_np *np, |
766 | struct __kernel_sockaddr_storage *sockaddr) | 872 | struct __kernel_sockaddr_storage *sockaddr) |
767 | { | 873 | { |
768 | struct socket *sock; | 874 | struct socket *sock = NULL; |
769 | int backlog = 5, ret, opt = 0, len; | 875 | int backlog = 5, ret, opt = 0, len; |
770 | 876 | ||
771 | switch (np->np_network_transport) { | 877 | switch (np->np_network_transport) { |
@@ -781,15 +887,15 @@ int iscsi_target_setup_login_socket( | |||
781 | np->np_ip_proto = IPPROTO_SCTP; | 887 | np->np_ip_proto = IPPROTO_SCTP; |
782 | np->np_sock_type = SOCK_SEQPACKET; | 888 | np->np_sock_type = SOCK_SEQPACKET; |
783 | break; | 889 | break; |
784 | case ISCSI_IWARP_TCP: | ||
785 | case ISCSI_IWARP_SCTP: | ||
786 | case ISCSI_INFINIBAND: | ||
787 | default: | 890 | default: |
788 | pr_err("Unsupported network_transport: %d\n", | 891 | pr_err("Unsupported network_transport: %d\n", |
789 | np->np_network_transport); | 892 | np->np_network_transport); |
790 | return -EINVAL; | 893 | return -EINVAL; |
791 | } | 894 | } |
792 | 895 | ||
896 | np->np_ip_proto = IPPROTO_TCP; | ||
897 | np->np_sock_type = SOCK_STREAM; | ||
898 | |||
793 | ret = sock_create(sockaddr->ss_family, np->np_sock_type, | 899 | ret = sock_create(sockaddr->ss_family, np->np_sock_type, |
794 | np->np_ip_proto, &sock); | 900 | np->np_ip_proto, &sock); |
795 | if (ret < 0) { | 901 | if (ret < 0) { |
@@ -853,7 +959,6 @@ int iscsi_target_setup_login_socket( | |||
853 | } | 959 | } |
854 | 960 | ||
855 | return 0; | 961 | return 0; |
856 | |||
857 | fail: | 962 | fail: |
858 | np->np_socket = NULL; | 963 | np->np_socket = NULL; |
859 | if (sock) | 964 | if (sock) |
@@ -861,21 +966,169 @@ fail: | |||
861 | return ret; | 966 | return ret; |
862 | } | 967 | } |
863 | 968 | ||
969 | int iscsi_target_setup_login_socket( | ||
970 | struct iscsi_np *np, | ||
971 | struct __kernel_sockaddr_storage *sockaddr) | ||
972 | { | ||
973 | struct iscsit_transport *t; | ||
974 | int rc; | ||
975 | |||
976 | t = iscsit_get_transport(np->np_network_transport); | ||
977 | if (!t) | ||
978 | return -EINVAL; | ||
979 | |||
980 | rc = t->iscsit_setup_np(np, sockaddr); | ||
981 | if (rc < 0) { | ||
982 | iscsit_put_transport(t); | ||
983 | return rc; | ||
984 | } | ||
985 | |||
986 | np->np_transport = t; | ||
987 | printk("Set np->np_transport to %p -> %s\n", np->np_transport, | ||
988 | np->np_transport->name); | ||
989 | return 0; | ||
990 | } | ||
991 | |||
992 | int iscsit_accept_np(struct iscsi_np *np, struct iscsi_conn *conn) | ||
993 | { | ||
994 | struct socket *new_sock, *sock = np->np_socket; | ||
995 | struct sockaddr_in sock_in; | ||
996 | struct sockaddr_in6 sock_in6; | ||
997 | int rc, err; | ||
998 | |||
999 | rc = kernel_accept(sock, &new_sock, 0); | ||
1000 | if (rc < 0) | ||
1001 | return rc; | ||
1002 | |||
1003 | conn->sock = new_sock; | ||
1004 | conn->login_family = np->np_sockaddr.ss_family; | ||
1005 | printk("iSCSI/TCP: Setup conn->sock from new_sock: %p\n", new_sock); | ||
1006 | |||
1007 | if (np->np_sockaddr.ss_family == AF_INET6) { | ||
1008 | memset(&sock_in6, 0, sizeof(struct sockaddr_in6)); | ||
1009 | |||
1010 | rc = conn->sock->ops->getname(conn->sock, | ||
1011 | (struct sockaddr *)&sock_in6, &err, 1); | ||
1012 | if (!rc) { | ||
1013 | snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", | ||
1014 | &sock_in6.sin6_addr.in6_u); | ||
1015 | conn->login_port = ntohs(sock_in6.sin6_port); | ||
1016 | } | ||
1017 | |||
1018 | rc = conn->sock->ops->getname(conn->sock, | ||
1019 | (struct sockaddr *)&sock_in6, &err, 0); | ||
1020 | if (!rc) { | ||
1021 | snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", | ||
1022 | &sock_in6.sin6_addr.in6_u); | ||
1023 | conn->local_port = ntohs(sock_in6.sin6_port); | ||
1024 | } | ||
1025 | } else { | ||
1026 | memset(&sock_in, 0, sizeof(struct sockaddr_in)); | ||
1027 | |||
1028 | rc = conn->sock->ops->getname(conn->sock, | ||
1029 | (struct sockaddr *)&sock_in, &err, 1); | ||
1030 | if (!rc) { | ||
1031 | sprintf(conn->login_ip, "%pI4", | ||
1032 | &sock_in.sin_addr.s_addr); | ||
1033 | conn->login_port = ntohs(sock_in.sin_port); | ||
1034 | } | ||
1035 | |||
1036 | rc = conn->sock->ops->getname(conn->sock, | ||
1037 | (struct sockaddr *)&sock_in, &err, 0); | ||
1038 | if (!rc) { | ||
1039 | sprintf(conn->local_ip, "%pI4", | ||
1040 | &sock_in.sin_addr.s_addr); | ||
1041 | conn->local_port = ntohs(sock_in.sin_port); | ||
1042 | } | ||
1043 | } | ||
1044 | |||
1045 | return 0; | ||
1046 | } | ||
1047 | |||
1048 | int iscsit_get_login_rx(struct iscsi_conn *conn, struct iscsi_login *login) | ||
1049 | { | ||
1050 | struct iscsi_login_req *login_req; | ||
1051 | u32 padding = 0, payload_length; | ||
1052 | |||
1053 | if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0) | ||
1054 | return -1; | ||
1055 | |||
1056 | login_req = (struct iscsi_login_req *)login->req; | ||
1057 | payload_length = ntoh24(login_req->dlength); | ||
1058 | padding = ((-payload_length) & 3); | ||
1059 | |||
1060 | pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," | ||
1061 | " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n", | ||
1062 | login_req->flags, login_req->itt, login_req->cmdsn, | ||
1063 | login_req->exp_statsn, login_req->cid, payload_length); | ||
1064 | /* | ||
1065 | * Setup the initial iscsi_login values from the leading | ||
1066 | * login request PDU. | ||
1067 | */ | ||
1068 | if (login->first_request) { | ||
1069 | login_req = (struct iscsi_login_req *)login->req; | ||
1070 | login->leading_connection = (!login_req->tsih) ? 1 : 0; | ||
1071 | login->current_stage = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags); | ||
1072 | login->version_min = login_req->min_version; | ||
1073 | login->version_max = login_req->max_version; | ||
1074 | memcpy(login->isid, login_req->isid, 6); | ||
1075 | login->cmd_sn = be32_to_cpu(login_req->cmdsn); | ||
1076 | login->init_task_tag = login_req->itt; | ||
1077 | login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn); | ||
1078 | login->cid = be16_to_cpu(login_req->cid); | ||
1079 | login->tsih = be16_to_cpu(login_req->tsih); | ||
1080 | } | ||
1081 | |||
1082 | if (iscsi_target_check_login_request(conn, login) < 0) | ||
1083 | return -1; | ||
1084 | |||
1085 | memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS); | ||
1086 | if (iscsi_login_rx_data(conn, login->req_buf, | ||
1087 | payload_length + padding) < 0) | ||
1088 | return -1; | ||
1089 | |||
1090 | return 0; | ||
1091 | } | ||
1092 | |||
1093 | int iscsit_put_login_tx(struct iscsi_conn *conn, struct iscsi_login *login, | ||
1094 | u32 length) | ||
1095 | { | ||
1096 | if (iscsi_login_tx_data(conn, login->rsp, login->rsp_buf, length) < 0) | ||
1097 | return -1; | ||
1098 | |||
1099 | return 0; | ||
1100 | } | ||
1101 | |||
1102 | static int | ||
1103 | iscsit_conn_set_transport(struct iscsi_conn *conn, struct iscsit_transport *t) | ||
1104 | { | ||
1105 | int rc; | ||
1106 | |||
1107 | if (!t->owner) { | ||
1108 | conn->conn_transport = t; | ||
1109 | return 0; | ||
1110 | } | ||
1111 | |||
1112 | rc = try_module_get(t->owner); | ||
1113 | if (!rc) { | ||
1114 | pr_err("try_module_get() failed for %s\n", t->name); | ||
1115 | return -EINVAL; | ||
1116 | } | ||
1117 | |||
1118 | conn->conn_transport = t; | ||
1119 | return 0; | ||
1120 | } | ||
1121 | |||
864 | static int __iscsi_target_login_thread(struct iscsi_np *np) | 1122 | static int __iscsi_target_login_thread(struct iscsi_np *np) |
865 | { | 1123 | { |
866 | u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0; | 1124 | u8 *buffer, zero_tsih = 0; |
867 | int err, ret = 0, stop; | 1125 | int ret = 0, rc, stop; |
868 | struct iscsi_conn *conn = NULL; | 1126 | struct iscsi_conn *conn = NULL; |
869 | struct iscsi_login *login; | 1127 | struct iscsi_login *login; |
870 | struct iscsi_portal_group *tpg = NULL; | 1128 | struct iscsi_portal_group *tpg = NULL; |
871 | struct socket *new_sock, *sock; | ||
872 | struct kvec iov; | ||
873 | struct iscsi_login_req *pdu; | 1129 | struct iscsi_login_req *pdu; |
874 | struct sockaddr_in sock_in; | ||
875 | struct sockaddr_in6 sock_in6; | ||
876 | 1130 | ||
877 | flush_signals(current); | 1131 | flush_signals(current); |
878 | sock = np->np_socket; | ||
879 | 1132 | ||
880 | spin_lock_bh(&np->np_thread_lock); | 1133 | spin_lock_bh(&np->np_thread_lock); |
881 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { | 1134 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { |
@@ -886,75 +1139,76 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
886 | } | 1139 | } |
887 | spin_unlock_bh(&np->np_thread_lock); | 1140 | spin_unlock_bh(&np->np_thread_lock); |
888 | 1141 | ||
889 | if (kernel_accept(sock, &new_sock, 0) < 0) { | ||
890 | spin_lock_bh(&np->np_thread_lock); | ||
891 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { | ||
892 | spin_unlock_bh(&np->np_thread_lock); | ||
893 | complete(&np->np_restart_comp); | ||
894 | /* Get another socket */ | ||
895 | return 1; | ||
896 | } | ||
897 | spin_unlock_bh(&np->np_thread_lock); | ||
898 | goto out; | ||
899 | } | ||
900 | iscsi_start_login_thread_timer(np); | ||
901 | |||
902 | conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); | 1142 | conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); |
903 | if (!conn) { | 1143 | if (!conn) { |
904 | pr_err("Could not allocate memory for" | 1144 | pr_err("Could not allocate memory for" |
905 | " new connection\n"); | 1145 | " new connection\n"); |
906 | sock_release(new_sock); | ||
907 | /* Get another socket */ | 1146 | /* Get another socket */ |
908 | return 1; | 1147 | return 1; |
909 | } | 1148 | } |
910 | |||
911 | pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); | 1149 | pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); |
912 | conn->conn_state = TARG_CONN_STATE_FREE; | 1150 | conn->conn_state = TARG_CONN_STATE_FREE; |
913 | conn->sock = new_sock; | ||
914 | 1151 | ||
915 | pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); | 1152 | if (iscsit_conn_set_transport(conn, np->np_transport) < 0) { |
916 | conn->conn_state = TARG_CONN_STATE_XPT_UP; | 1153 | kfree(conn); |
1154 | return 1; | ||
1155 | } | ||
917 | 1156 | ||
918 | /* | 1157 | rc = np->np_transport->iscsit_accept_np(np, conn); |
919 | * Allocate conn->conn_ops early as a failure calling | 1158 | if (rc == -ENOSYS) { |
920 | * iscsit_tx_login_rsp() below will call tx_data(). | 1159 | complete(&np->np_restart_comp); |
921 | */ | 1160 | iscsit_put_transport(conn->conn_transport); |
922 | conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL); | 1161 | kfree(conn); |
923 | if (!conn->conn_ops) { | 1162 | conn = NULL; |
924 | pr_err("Unable to allocate memory for" | 1163 | goto exit; |
925 | " struct iscsi_conn_ops.\n"); | 1164 | } else if (rc < 0) { |
926 | goto new_sess_out; | 1165 | spin_lock_bh(&np->np_thread_lock); |
1166 | if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { | ||
1167 | spin_unlock_bh(&np->np_thread_lock); | ||
1168 | complete(&np->np_restart_comp); | ||
1169 | if (ret == -ENODEV) { | ||
1170 | iscsit_put_transport(conn->conn_transport); | ||
1171 | kfree(conn); | ||
1172 | conn = NULL; | ||
1173 | goto out; | ||
1174 | } | ||
1175 | /* Get another socket */ | ||
1176 | return 1; | ||
1177 | } | ||
1178 | spin_unlock_bh(&np->np_thread_lock); | ||
1179 | iscsit_put_transport(conn->conn_transport); | ||
1180 | kfree(conn); | ||
1181 | conn = NULL; | ||
1182 | goto out; | ||
927 | } | 1183 | } |
928 | /* | 1184 | /* |
929 | * Perform the remaining iSCSI connection initialization items.. | 1185 | * Perform the remaining iSCSI connection initialization items.. |
930 | */ | 1186 | */ |
931 | if (iscsi_login_init_conn(conn) < 0) | 1187 | login = iscsi_login_init_conn(conn); |
932 | goto new_sess_out; | 1188 | if (!login) { |
933 | |||
934 | memset(buffer, 0, ISCSI_HDR_LEN); | ||
935 | memset(&iov, 0, sizeof(struct kvec)); | ||
936 | iov.iov_base = buffer; | ||
937 | iov.iov_len = ISCSI_HDR_LEN; | ||
938 | |||
939 | if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) { | ||
940 | pr_err("rx_data() returned an error.\n"); | ||
941 | goto new_sess_out; | 1189 | goto new_sess_out; |
942 | } | 1190 | } |
943 | 1191 | ||
944 | iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK); | 1192 | iscsi_start_login_thread_timer(np); |
945 | if (!(iscsi_opcode & ISCSI_OP_LOGIN)) { | ||
946 | pr_err("First opcode is not login request," | ||
947 | " failing login request.\n"); | ||
948 | goto new_sess_out; | ||
949 | } | ||
950 | 1193 | ||
951 | pdu = (struct iscsi_login_req *) buffer; | 1194 | pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); |
1195 | conn->conn_state = TARG_CONN_STATE_XPT_UP; | ||
1196 | /* | ||
1197 | * This will process the first login request + payload.. | ||
1198 | */ | ||
1199 | rc = np->np_transport->iscsit_get_login_rx(conn, login); | ||
1200 | if (rc == 1) | ||
1201 | return 1; | ||
1202 | else if (rc < 0) | ||
1203 | goto new_sess_out; | ||
952 | 1204 | ||
1205 | buffer = &login->req[0]; | ||
1206 | pdu = (struct iscsi_login_req *)buffer; | ||
953 | /* | 1207 | /* |
954 | * Used by iscsit_tx_login_rsp() for Login Resonses PDUs | 1208 | * Used by iscsit_tx_login_rsp() for Login Resonses PDUs |
955 | * when Status-Class != 0. | 1209 | * when Status-Class != 0. |
956 | */ | 1210 | */ |
957 | conn->login_itt = pdu->itt; | 1211 | conn->login_itt = pdu->itt; |
958 | 1212 | ||
959 | spin_lock_bh(&np->np_thread_lock); | 1213 | spin_lock_bh(&np->np_thread_lock); |
960 | if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { | 1214 | if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { |
@@ -967,61 +1221,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
967 | } | 1221 | } |
968 | spin_unlock_bh(&np->np_thread_lock); | 1222 | spin_unlock_bh(&np->np_thread_lock); |
969 | 1223 | ||
970 | if (np->np_sockaddr.ss_family == AF_INET6) { | ||
971 | memset(&sock_in6, 0, sizeof(struct sockaddr_in6)); | ||
972 | |||
973 | if (conn->sock->ops->getname(conn->sock, | ||
974 | (struct sockaddr *)&sock_in6, &err, 1) < 0) { | ||
975 | pr_err("sock_ops->getname() failed.\n"); | ||
976 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
977 | ISCSI_LOGIN_STATUS_TARGET_ERROR); | ||
978 | goto new_sess_out; | ||
979 | } | ||
980 | snprintf(conn->login_ip, sizeof(conn->login_ip), "%pI6c", | ||
981 | &sock_in6.sin6_addr.in6_u); | ||
982 | conn->login_port = ntohs(sock_in6.sin6_port); | ||
983 | |||
984 | if (conn->sock->ops->getname(conn->sock, | ||
985 | (struct sockaddr *)&sock_in6, &err, 0) < 0) { | ||
986 | pr_err("sock_ops->getname() failed.\n"); | ||
987 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
988 | ISCSI_LOGIN_STATUS_TARGET_ERROR); | ||
989 | goto new_sess_out; | ||
990 | } | ||
991 | snprintf(conn->local_ip, sizeof(conn->local_ip), "%pI6c", | ||
992 | &sock_in6.sin6_addr.in6_u); | ||
993 | conn->local_port = ntohs(sock_in6.sin6_port); | ||
994 | |||
995 | } else { | ||
996 | memset(&sock_in, 0, sizeof(struct sockaddr_in)); | ||
997 | |||
998 | if (conn->sock->ops->getname(conn->sock, | ||
999 | (struct sockaddr *)&sock_in, &err, 1) < 0) { | ||
1000 | pr_err("sock_ops->getname() failed.\n"); | ||
1001 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
1002 | ISCSI_LOGIN_STATUS_TARGET_ERROR); | ||
1003 | goto new_sess_out; | ||
1004 | } | ||
1005 | sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr); | ||
1006 | conn->login_port = ntohs(sock_in.sin_port); | ||
1007 | |||
1008 | if (conn->sock->ops->getname(conn->sock, | ||
1009 | (struct sockaddr *)&sock_in, &err, 0) < 0) { | ||
1010 | pr_err("sock_ops->getname() failed.\n"); | ||
1011 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
1012 | ISCSI_LOGIN_STATUS_TARGET_ERROR); | ||
1013 | goto new_sess_out; | ||
1014 | } | ||
1015 | sprintf(conn->local_ip, "%pI4", &sock_in.sin_addr.s_addr); | ||
1016 | conn->local_port = ntohs(sock_in.sin_port); | ||
1017 | } | ||
1018 | |||
1019 | conn->network_transport = np->np_network_transport; | 1224 | conn->network_transport = np->np_network_transport; |
1020 | 1225 | ||
1021 | pr_debug("Received iSCSI login request from %s on %s Network" | 1226 | pr_debug("Received iSCSI login request from %s on %s Network" |
1022 | " Portal %s:%hu\n", conn->login_ip, | 1227 | " Portal %s:%hu\n", conn->login_ip, np->np_transport->name, |
1023 | (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP", | 1228 | conn->local_ip, conn->local_port); |
1024 | conn->local_ip, conn->local_port); | ||
1025 | 1229 | ||
1026 | pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); | 1230 | pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); |
1027 | conn->conn_state = TARG_CONN_STATE_IN_LOGIN; | 1231 | conn->conn_state = TARG_CONN_STATE_IN_LOGIN; |
@@ -1050,13 +1254,17 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1050 | if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0) | 1254 | if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0) |
1051 | goto new_sess_out; | 1255 | goto new_sess_out; |
1052 | } | 1256 | } |
1053 | |||
1054 | /* | 1257 | /* |
1055 | * This will process the first login request, and call | 1258 | * SessionType: Discovery |
1056 | * iscsi_target_locate_portal(), and return a valid struct iscsi_login. | 1259 | * |
1260 | * Locates Default Portal | ||
1261 | * | ||
1262 | * SessionType: Normal | ||
1263 | * | ||
1264 | * Locates Target Portal from NP -> Target IQN | ||
1057 | */ | 1265 | */ |
1058 | login = iscsi_target_init_negotiation(np, conn, buffer); | 1266 | rc = iscsi_target_locate_portal(np, conn, login); |
1059 | if (!login) { | 1267 | if (rc < 0) { |
1060 | tpg = conn->tpg; | 1268 | tpg = conn->tpg; |
1061 | goto new_sess_out; | 1269 | goto new_sess_out; |
1062 | } | 1270 | } |
@@ -1068,15 +1276,11 @@ static int __iscsi_target_login_thread(struct iscsi_np *np) | |||
1068 | } | 1276 | } |
1069 | 1277 | ||
1070 | if (zero_tsih) { | 1278 | if (zero_tsih) { |
1071 | if (iscsi_login_zero_tsih_s2(conn) < 0) { | 1279 | if (iscsi_login_zero_tsih_s2(conn) < 0) |
1072 | iscsi_target_nego_release(login, conn); | ||
1073 | goto new_sess_out; | 1280 | goto new_sess_out; |
1074 | } | ||
1075 | } else { | 1281 | } else { |
1076 | if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) { | 1282 | if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) |
1077 | iscsi_target_nego_release(login, conn); | ||
1078 | goto old_sess_out; | 1283 | goto old_sess_out; |
1079 | } | ||
1080 | } | 1284 | } |
1081 | 1285 | ||
1082 | if (iscsi_target_start_negotiation(login, conn) < 0) | 1286 | if (iscsi_target_start_negotiation(login, conn) < 0) |
@@ -1153,8 +1357,18 @@ old_sess_out: | |||
1153 | iscsi_release_param_list(conn->param_list); | 1357 | iscsi_release_param_list(conn->param_list); |
1154 | conn->param_list = NULL; | 1358 | conn->param_list = NULL; |
1155 | } | 1359 | } |
1156 | if (conn->sock) | 1360 | iscsi_target_nego_release(conn); |
1361 | |||
1362 | if (conn->sock) { | ||
1157 | sock_release(conn->sock); | 1363 | sock_release(conn->sock); |
1364 | conn->sock = NULL; | ||
1365 | } | ||
1366 | |||
1367 | if (conn->conn_transport->iscsit_free_conn) | ||
1368 | conn->conn_transport->iscsit_free_conn(conn); | ||
1369 | |||
1370 | iscsit_put_transport(conn->conn_transport); | ||
1371 | |||
1158 | kfree(conn); | 1372 | kfree(conn); |
1159 | 1373 | ||
1160 | if (tpg) { | 1374 | if (tpg) { |
@@ -1172,11 +1386,13 @@ out: | |||
1172 | /* Wait for another socket.. */ | 1386 | /* Wait for another socket.. */ |
1173 | if (!stop) | 1387 | if (!stop) |
1174 | return 1; | 1388 | return 1; |
1175 | 1389 | exit: | |
1176 | iscsi_stop_login_thread_timer(np); | 1390 | iscsi_stop_login_thread_timer(np); |
1177 | spin_lock_bh(&np->np_thread_lock); | 1391 | spin_lock_bh(&np->np_thread_lock); |
1178 | np->np_thread_state = ISCSI_NP_THREAD_EXIT; | 1392 | np->np_thread_state = ISCSI_NP_THREAD_EXIT; |
1393 | np->np_thread = NULL; | ||
1179 | spin_unlock_bh(&np->np_thread_lock); | 1394 | spin_unlock_bh(&np->np_thread_lock); |
1395 | |||
1180 | return 0; | 1396 | return 0; |
1181 | } | 1397 | } |
1182 | 1398 | ||
diff --git a/drivers/target/iscsi/iscsi_target_login.h b/drivers/target/iscsi/iscsi_target_login.h index 091dcae2532b..63efd2878451 100644 --- a/drivers/target/iscsi/iscsi_target_login.h +++ b/drivers/target/iscsi/iscsi_target_login.h | |||
@@ -4,8 +4,14 @@ | |||
4 | extern int iscsi_login_setup_crypto(struct iscsi_conn *); | 4 | extern int iscsi_login_setup_crypto(struct iscsi_conn *); |
5 | extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *); | 5 | extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *); |
6 | extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32); | 6 | extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32); |
7 | extern int iscsit_setup_np(struct iscsi_np *, | ||
8 | struct __kernel_sockaddr_storage *); | ||
7 | extern int iscsi_target_setup_login_socket(struct iscsi_np *, | 9 | extern int iscsi_target_setup_login_socket(struct iscsi_np *, |
8 | struct __kernel_sockaddr_storage *); | 10 | struct __kernel_sockaddr_storage *); |
11 | extern int iscsit_accept_np(struct iscsi_np *, struct iscsi_conn *); | ||
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); | ||
14 | extern void iscsit_free_conn(struct iscsi_np *, struct iscsi_conn *); | ||
9 | extern int iscsi_target_login_thread(void *); | 15 | extern int iscsi_target_login_thread(void *); |
10 | extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); | 16 | extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); |
11 | 17 | ||
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c index 9d902aefe01a..7ad912060e21 100644 --- a/drivers/target/iscsi/iscsi_target_nego.c +++ b/drivers/target/iscsi/iscsi_target_nego.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <scsi/iscsi_proto.h> | 22 | #include <scsi/iscsi_proto.h> |
23 | #include <target/target_core_base.h> | 23 | #include <target/target_core_base.h> |
24 | #include <target/target_core_fabric.h> | 24 | #include <target/target_core_fabric.h> |
25 | #include <target/iscsi/iscsi_transport.h> | ||
25 | 26 | ||
26 | #include "iscsi_target_core.h" | 27 | #include "iscsi_target_core.h" |
27 | #include "iscsi_target_parameters.h" | 28 | #include "iscsi_target_parameters.h" |
@@ -169,7 +170,7 @@ static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn) | |||
169 | kfree(conn->auth_protocol); | 170 | kfree(conn->auth_protocol); |
170 | } | 171 | } |
171 | 172 | ||
172 | static int iscsi_target_check_login_request( | 173 | int iscsi_target_check_login_request( |
173 | struct iscsi_conn *conn, | 174 | struct iscsi_conn *conn, |
174 | struct iscsi_login *login) | 175 | struct iscsi_login *login) |
175 | { | 176 | { |
@@ -200,8 +201,8 @@ static int iscsi_target_check_login_request( | |||
200 | return -1; | 201 | return -1; |
201 | } | 202 | } |
202 | 203 | ||
203 | req_csg = (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2; | 204 | req_csg = ISCSI_LOGIN_CURRENT_STAGE(login_req->flags); |
204 | req_nsg = (login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK); | 205 | req_nsg = ISCSI_LOGIN_NEXT_STAGE(login_req->flags); |
205 | 206 | ||
206 | if (req_csg != login->current_stage) { | 207 | if (req_csg != login->current_stage) { |
207 | pr_err("Initiator unexpectedly changed login stage" | 208 | pr_err("Initiator unexpectedly changed login stage" |
@@ -352,11 +353,8 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
352 | 353 | ||
353 | padding = ((-login->rsp_length) & 3); | 354 | padding = ((-login->rsp_length) & 3); |
354 | 355 | ||
355 | if (iscsi_login_tx_data( | 356 | if (conn->conn_transport->iscsit_put_login_tx(conn, login, |
356 | conn, | 357 | login->rsp_length + padding) < 0) |
357 | login->rsp, | ||
358 | login->rsp_buf, | ||
359 | login->rsp_length + padding) < 0) | ||
360 | return -1; | 358 | return -1; |
361 | 359 | ||
362 | login->rsp_length = 0; | 360 | login->rsp_length = 0; |
@@ -368,72 +366,12 @@ static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_log | |||
368 | return 0; | 366 | return 0; |
369 | } | 367 | } |
370 | 368 | ||
371 | static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) | ||
372 | { | ||
373 | u32 padding = 0, payload_length; | ||
374 | struct iscsi_login_req *login_req; | ||
375 | |||
376 | if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0) | ||
377 | return -1; | ||
378 | |||
379 | login_req = (struct iscsi_login_req *) login->req; | ||
380 | payload_length = ntoh24(login_req->dlength); | ||
381 | |||
382 | pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," | ||
383 | " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n", | ||
384 | login_req->flags, login_req->itt, login_req->cmdsn, | ||
385 | login_req->exp_statsn, login_req->cid, payload_length); | ||
386 | |||
387 | if (iscsi_target_check_login_request(conn, login) < 0) | ||
388 | return -1; | ||
389 | |||
390 | padding = ((-payload_length) & 3); | ||
391 | memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS); | ||
392 | |||
393 | if (iscsi_login_rx_data( | ||
394 | conn, | ||
395 | login->req_buf, | ||
396 | payload_length + padding) < 0) | ||
397 | return -1; | ||
398 | |||
399 | return 0; | ||
400 | } | ||
401 | |||
402 | static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) | 369 | static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) |
403 | { | 370 | { |
404 | if (iscsi_target_do_tx_login_io(conn, login) < 0) | 371 | if (iscsi_target_do_tx_login_io(conn, login) < 0) |
405 | return -1; | 372 | return -1; |
406 | 373 | ||
407 | if (iscsi_target_do_rx_login_io(conn, login) < 0) | 374 | if (conn->conn_transport->iscsit_get_login_rx(conn, login) < 0) |
408 | return -1; | ||
409 | |||
410 | return 0; | ||
411 | } | ||
412 | |||
413 | static int iscsi_target_get_initial_payload( | ||
414 | struct iscsi_conn *conn, | ||
415 | struct iscsi_login *login) | ||
416 | { | ||
417 | u32 padding = 0, payload_length; | ||
418 | struct iscsi_login_req *login_req; | ||
419 | |||
420 | login_req = (struct iscsi_login_req *) login->req; | ||
421 | payload_length = ntoh24(login_req->dlength); | ||
422 | |||
423 | pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," | ||
424 | " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n", | ||
425 | login_req->flags, login_req->itt, login_req->cmdsn, | ||
426 | login_req->exp_statsn, payload_length); | ||
427 | |||
428 | if (iscsi_target_check_login_request(conn, login) < 0) | ||
429 | return -1; | ||
430 | |||
431 | padding = ((-payload_length) & 3); | ||
432 | |||
433 | if (iscsi_login_rx_data( | ||
434 | conn, | ||
435 | login->req_buf, | ||
436 | payload_length + padding) < 0) | ||
437 | return -1; | 375 | return -1; |
438 | 376 | ||
439 | return 0; | 377 | return 0; |
@@ -681,9 +619,9 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
681 | return -1; | 619 | return -1; |
682 | } | 620 | } |
683 | 621 | ||
684 | switch ((login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2) { | 622 | switch (ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)) { |
685 | case 0: | 623 | case 0: |
686 | login_rsp->flags |= (0 & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK); | 624 | login_rsp->flags &= ~ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK; |
687 | if (iscsi_target_handle_csg_zero(conn, login) < 0) | 625 | if (iscsi_target_handle_csg_zero(conn, login) < 0) |
688 | return -1; | 626 | return -1; |
689 | break; | 627 | break; |
@@ -693,6 +631,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
693 | return -1; | 631 | return -1; |
694 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { | 632 | if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { |
695 | login->tsih = conn->sess->tsih; | 633 | login->tsih = conn->sess->tsih; |
634 | login->login_complete = 1; | ||
696 | if (iscsi_target_do_tx_login_io(conn, | 635 | if (iscsi_target_do_tx_login_io(conn, |
697 | login) < 0) | 636 | login) < 0) |
698 | return -1; | 637 | return -1; |
@@ -702,8 +641,7 @@ static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *lo | |||
702 | default: | 641 | default: |
703 | pr_err("Illegal CSG: %d received from" | 642 | pr_err("Illegal CSG: %d received from" |
704 | " Initiator, protocol error.\n", | 643 | " Initiator, protocol error.\n", |
705 | (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) | 644 | ISCSI_LOGIN_CURRENT_STAGE(login_req->flags)); |
706 | >> 2); | ||
707 | break; | 645 | break; |
708 | } | 646 | } |
709 | 647 | ||
@@ -737,7 +675,7 @@ static void iscsi_initiatorname_tolower( | |||
737 | /* | 675 | /* |
738 | * Processes the first Login Request.. | 676 | * Processes the first Login Request.. |
739 | */ | 677 | */ |
740 | static int iscsi_target_locate_portal( | 678 | int iscsi_target_locate_portal( |
741 | struct iscsi_np *np, | 679 | struct iscsi_np *np, |
742 | struct iscsi_conn *conn, | 680 | struct iscsi_conn *conn, |
743 | struct iscsi_login *login) | 681 | struct iscsi_login *login) |
@@ -753,22 +691,6 @@ static int iscsi_target_locate_portal( | |||
753 | login_req = (struct iscsi_login_req *) login->req; | 691 | login_req = (struct iscsi_login_req *) login->req; |
754 | payload_length = ntoh24(login_req->dlength); | 692 | payload_length = ntoh24(login_req->dlength); |
755 | 693 | ||
756 | login->first_request = 1; | ||
757 | login->leading_connection = (!login_req->tsih) ? 1 : 0; | ||
758 | login->current_stage = | ||
759 | (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2; | ||
760 | login->version_min = login_req->min_version; | ||
761 | login->version_max = login_req->max_version; | ||
762 | memcpy(login->isid, login_req->isid, 6); | ||
763 | login->cmd_sn = be32_to_cpu(login_req->cmdsn); | ||
764 | login->init_task_tag = login_req->itt; | ||
765 | login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn); | ||
766 | login->cid = be16_to_cpu(login_req->cid); | ||
767 | login->tsih = be16_to_cpu(login_req->tsih); | ||
768 | |||
769 | if (iscsi_target_get_initial_payload(conn, login) < 0) | ||
770 | return -1; | ||
771 | |||
772 | tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL); | 694 | tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL); |
773 | if (!tmpbuf) { | 695 | if (!tmpbuf) { |
774 | pr_err("Unable to allocate memory for tmpbuf.\n"); | 696 | pr_err("Unable to allocate memory for tmpbuf.\n"); |
@@ -800,6 +722,8 @@ static int iscsi_target_locate_portal( | |||
800 | start += strlen(key) + strlen(value) + 2; | 722 | start += strlen(key) + strlen(value) + 2; |
801 | } | 723 | } |
802 | 724 | ||
725 | printk("i_buf: %s, s_buf: %s, t_buf: %s\n", i_buf, s_buf, t_buf); | ||
726 | |||
803 | /* | 727 | /* |
804 | * See 5.3. Login Phase. | 728 | * See 5.3. Login Phase. |
805 | */ | 729 | */ |
@@ -958,100 +882,30 @@ out: | |||
958 | return ret; | 882 | return ret; |
959 | } | 883 | } |
960 | 884 | ||
961 | struct iscsi_login *iscsi_target_init_negotiation( | ||
962 | struct iscsi_np *np, | ||
963 | struct iscsi_conn *conn, | ||
964 | char *login_pdu) | ||
965 | { | ||
966 | struct iscsi_login *login; | ||
967 | |||
968 | login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL); | ||
969 | if (!login) { | ||
970 | pr_err("Unable to allocate memory for struct iscsi_login.\n"); | ||
971 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
972 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
973 | return NULL; | ||
974 | } | ||
975 | |||
976 | login->req = kmemdup(login_pdu, ISCSI_HDR_LEN, GFP_KERNEL); | ||
977 | if (!login->req) { | ||
978 | pr_err("Unable to allocate memory for Login Request.\n"); | ||
979 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
980 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
981 | goto out; | ||
982 | } | ||
983 | |||
984 | login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); | ||
985 | if (!login->req_buf) { | ||
986 | pr_err("Unable to allocate memory for response buffer.\n"); | ||
987 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
988 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
989 | goto out; | ||
990 | } | ||
991 | /* | ||
992 | * SessionType: Discovery | ||
993 | * | ||
994 | * Locates Default Portal | ||
995 | * | ||
996 | * SessionType: Normal | ||
997 | * | ||
998 | * Locates Target Portal from NP -> Target IQN | ||
999 | */ | ||
1000 | if (iscsi_target_locate_portal(np, conn, login) < 0) { | ||
1001 | goto out; | ||
1002 | } | ||
1003 | |||
1004 | return login; | ||
1005 | out: | ||
1006 | kfree(login->req); | ||
1007 | kfree(login->req_buf); | ||
1008 | kfree(login); | ||
1009 | |||
1010 | return NULL; | ||
1011 | } | ||
1012 | |||
1013 | int iscsi_target_start_negotiation( | 885 | int iscsi_target_start_negotiation( |
1014 | struct iscsi_login *login, | 886 | struct iscsi_login *login, |
1015 | struct iscsi_conn *conn) | 887 | struct iscsi_conn *conn) |
1016 | { | 888 | { |
1017 | int ret = -1; | 889 | int ret; |
1018 | |||
1019 | login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); | ||
1020 | if (!login->rsp) { | ||
1021 | pr_err("Unable to allocate memory for" | ||
1022 | " Login Response.\n"); | ||
1023 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
1024 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
1025 | ret = -1; | ||
1026 | goto out; | ||
1027 | } | ||
1028 | |||
1029 | login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); | ||
1030 | if (!login->rsp_buf) { | ||
1031 | pr_err("Unable to allocate memory for" | ||
1032 | " request buffer.\n"); | ||
1033 | iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, | ||
1034 | ISCSI_LOGIN_STATUS_NO_RESOURCES); | ||
1035 | ret = -1; | ||
1036 | goto out; | ||
1037 | } | ||
1038 | 890 | ||
1039 | ret = iscsi_target_do_login(conn, login); | 891 | ret = iscsi_target_do_login(conn, login); |
1040 | out: | ||
1041 | if (ret != 0) | 892 | if (ret != 0) |
1042 | iscsi_remove_failed_auth_entry(conn); | 893 | iscsi_remove_failed_auth_entry(conn); |
1043 | 894 | ||
1044 | iscsi_target_nego_release(login, conn); | 895 | iscsi_target_nego_release(conn); |
1045 | return ret; | 896 | return ret; |
1046 | } | 897 | } |
1047 | 898 | ||
1048 | void iscsi_target_nego_release( | 899 | void iscsi_target_nego_release(struct iscsi_conn *conn) |
1049 | struct iscsi_login *login, | ||
1050 | struct iscsi_conn *conn) | ||
1051 | { | 900 | { |
1052 | kfree(login->req); | 901 | struct iscsi_login *login = conn->conn_login; |
1053 | kfree(login->rsp); | 902 | |
903 | if (!login) | ||
904 | return; | ||
905 | |||
1054 | kfree(login->req_buf); | 906 | kfree(login->req_buf); |
1055 | kfree(login->rsp_buf); | 907 | kfree(login->rsp_buf); |
1056 | kfree(login); | 908 | kfree(login); |
909 | |||
910 | conn->conn_login = NULL; | ||
1057 | } | 911 | } |
diff --git a/drivers/target/iscsi/iscsi_target_nego.h b/drivers/target/iscsi/iscsi_target_nego.h index 92e133a5158f..f021cbd330e5 100644 --- a/drivers/target/iscsi/iscsi_target_nego.h +++ b/drivers/target/iscsi/iscsi_target_nego.h | |||
@@ -7,11 +7,14 @@ | |||
7 | extern void convert_null_to_semi(char *, int); | 7 | extern void convert_null_to_semi(char *, int); |
8 | extern int extract_param(const char *, const char *, unsigned int, char *, | 8 | extern int extract_param(const char *, const char *, unsigned int, char *, |
9 | unsigned char *); | 9 | unsigned char *); |
10 | extern struct iscsi_login *iscsi_target_init_negotiation( | 10 | extern int iscsi_target_check_login_request(struct iscsi_conn *, |
11 | struct iscsi_np *, struct iscsi_conn *, char *); | 11 | struct iscsi_login *); |
12 | extern int iscsi_target_get_initial_payload(struct iscsi_conn *, | ||
13 | struct iscsi_login *); | ||
14 | extern int iscsi_target_locate_portal(struct iscsi_np *, struct iscsi_conn *, | ||
15 | struct iscsi_login *); | ||
12 | extern int iscsi_target_start_negotiation( | 16 | extern int iscsi_target_start_negotiation( |
13 | struct iscsi_login *, struct iscsi_conn *); | 17 | struct iscsi_login *, struct iscsi_conn *); |
14 | extern void iscsi_target_nego_release( | 18 | extern void iscsi_target_nego_release(struct iscsi_conn *); |
15 | struct iscsi_login *, struct iscsi_conn *); | ||
16 | 19 | ||
17 | #endif /* ISCSI_TARGET_NEGO_H */ | 20 | #endif /* ISCSI_TARGET_NEGO_H */ |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c index ca2be406f141..f690be9e5293 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.c +++ b/drivers/target/iscsi/iscsi_target_parameters.c | |||
@@ -59,7 +59,7 @@ int iscsi_login_tx_data( | |||
59 | char *text_buf, | 59 | char *text_buf, |
60 | int text_length) | 60 | int text_length) |
61 | { | 61 | { |
62 | int length, tx_sent; | 62 | int length, tx_sent, iov_cnt = 1; |
63 | struct kvec iov[2]; | 63 | struct kvec iov[2]; |
64 | 64 | ||
65 | length = (ISCSI_HDR_LEN + text_length); | 65 | length = (ISCSI_HDR_LEN + text_length); |
@@ -67,8 +67,12 @@ int iscsi_login_tx_data( | |||
67 | memset(&iov[0], 0, 2 * sizeof(struct kvec)); | 67 | memset(&iov[0], 0, 2 * sizeof(struct kvec)); |
68 | iov[0].iov_len = ISCSI_HDR_LEN; | 68 | iov[0].iov_len = ISCSI_HDR_LEN; |
69 | iov[0].iov_base = pdu_buf; | 69 | iov[0].iov_base = pdu_buf; |
70 | iov[1].iov_len = text_length; | 70 | |
71 | iov[1].iov_base = text_buf; | 71 | if (text_buf && text_length) { |
72 | iov[1].iov_len = text_length; | ||
73 | iov[1].iov_base = text_buf; | ||
74 | iov_cnt++; | ||
75 | } | ||
72 | 76 | ||
73 | /* | 77 | /* |
74 | * Initial Marker-less Interval. | 78 | * Initial Marker-less Interval. |
@@ -77,7 +81,7 @@ int iscsi_login_tx_data( | |||
77 | */ | 81 | */ |
78 | conn->if_marker += length; | 82 | conn->if_marker += length; |
79 | 83 | ||
80 | tx_sent = tx_data(conn, &iov[0], 2, length); | 84 | tx_sent = tx_data(conn, &iov[0], iov_cnt, length); |
81 | if (tx_sent != length) { | 85 | if (tx_sent != length) { |
82 | pr_err("tx_data returned %d, expecting %d.\n", | 86 | pr_err("tx_data returned %d, expecting %d.\n", |
83 | tx_sent, length); | 87 | tx_sent, length); |
@@ -429,6 +433,28 @@ int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr) | |||
429 | TYPERANGE_MARKINT, USE_INITIAL_ONLY); | 433 | TYPERANGE_MARKINT, USE_INITIAL_ONLY); |
430 | if (!param) | 434 | if (!param) |
431 | goto out; | 435 | goto out; |
436 | /* | ||
437 | * Extra parameters for ISER from RFC-5046 | ||
438 | */ | ||
439 | param = iscsi_set_default_param(pl, RDMAEXTENTIONS, INITIAL_RDMAEXTENTIONS, | ||
440 | PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, | ||
441 | TYPERANGE_BOOL_AND, USE_LEADING_ONLY); | ||
442 | if (!param) | ||
443 | goto out; | ||
444 | |||
445 | param = iscsi_set_default_param(pl, INITIATORRECVDATASEGMENTLENGTH, | ||
446 | INITIAL_INITIATORRECVDATASEGMENTLENGTH, | ||
447 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, | ||
448 | TYPERANGE_512_TO_16777215, USE_ALL); | ||
449 | if (!param) | ||
450 | goto out; | ||
451 | |||
452 | param = iscsi_set_default_param(pl, TARGETRECVDATASEGMENTLENGTH, | ||
453 | INITIAL_TARGETRECVDATASEGMENTLENGTH, | ||
454 | PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, | ||
455 | TYPERANGE_512_TO_16777215, USE_ALL); | ||
456 | if (!param) | ||
457 | goto out; | ||
432 | 458 | ||
433 | *param_list_ptr = pl; | 459 | *param_list_ptr = pl; |
434 | return 0; | 460 | return 0; |
@@ -438,19 +464,23 @@ out: | |||
438 | } | 464 | } |
439 | 465 | ||
440 | int iscsi_set_keys_to_negotiate( | 466 | int iscsi_set_keys_to_negotiate( |
441 | int sessiontype, | 467 | struct iscsi_param_list *param_list, |
442 | struct iscsi_param_list *param_list) | 468 | bool iser) |
443 | { | 469 | { |
444 | struct iscsi_param *param; | 470 | struct iscsi_param *param; |
445 | 471 | ||
472 | param_list->iser = iser; | ||
473 | |||
446 | list_for_each_entry(param, ¶m_list->param_list, p_list) { | 474 | list_for_each_entry(param, ¶m_list->param_list, p_list) { |
447 | param->state = 0; | 475 | param->state = 0; |
448 | if (!strcmp(param->name, AUTHMETHOD)) { | 476 | if (!strcmp(param->name, AUTHMETHOD)) { |
449 | SET_PSTATE_NEGOTIATE(param); | 477 | SET_PSTATE_NEGOTIATE(param); |
450 | } else if (!strcmp(param->name, HEADERDIGEST)) { | 478 | } else if (!strcmp(param->name, HEADERDIGEST)) { |
451 | SET_PSTATE_NEGOTIATE(param); | 479 | if (iser == false) |
480 | SET_PSTATE_NEGOTIATE(param); | ||
452 | } else if (!strcmp(param->name, DATADIGEST)) { | 481 | } else if (!strcmp(param->name, DATADIGEST)) { |
453 | SET_PSTATE_NEGOTIATE(param); | 482 | if (iser == false) |
483 | SET_PSTATE_NEGOTIATE(param); | ||
454 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { | 484 | } else if (!strcmp(param->name, MAXCONNECTIONS)) { |
455 | SET_PSTATE_NEGOTIATE(param); | 485 | SET_PSTATE_NEGOTIATE(param); |
456 | } else if (!strcmp(param->name, TARGETNAME)) { | 486 | } else if (!strcmp(param->name, TARGETNAME)) { |
@@ -469,7 +499,8 @@ int iscsi_set_keys_to_negotiate( | |||
469 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { | 499 | } else if (!strcmp(param->name, IMMEDIATEDATA)) { |
470 | SET_PSTATE_NEGOTIATE(param); | 500 | SET_PSTATE_NEGOTIATE(param); |
471 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { | 501 | } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { |
472 | SET_PSTATE_NEGOTIATE(param); | 502 | if (iser == false) |
503 | SET_PSTATE_NEGOTIATE(param); | ||
473 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { | 504 | } else if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { |
474 | continue; | 505 | continue; |
475 | } else if (!strcmp(param->name, MAXBURSTLENGTH)) { | 506 | } else if (!strcmp(param->name, MAXBURSTLENGTH)) { |
@@ -498,6 +529,15 @@ int iscsi_set_keys_to_negotiate( | |||
498 | SET_PSTATE_NEGOTIATE(param); | 529 | SET_PSTATE_NEGOTIATE(param); |
499 | } else if (!strcmp(param->name, OFMARKINT)) { | 530 | } else if (!strcmp(param->name, OFMARKINT)) { |
500 | SET_PSTATE_NEGOTIATE(param); | 531 | SET_PSTATE_NEGOTIATE(param); |
532 | } else if (!strcmp(param->name, RDMAEXTENTIONS)) { | ||
533 | if (iser == true) | ||
534 | SET_PSTATE_NEGOTIATE(param); | ||
535 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { | ||
536 | if (iser == true) | ||
537 | SET_PSTATE_NEGOTIATE(param); | ||
538 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { | ||
539 | if (iser == true) | ||
540 | SET_PSTATE_NEGOTIATE(param); | ||
501 | } | 541 | } |
502 | } | 542 | } |
503 | 543 | ||
@@ -540,6 +580,12 @@ int iscsi_set_keys_irrelevant_for_discovery( | |||
540 | param->state &= ~PSTATE_NEGOTIATE; | 580 | param->state &= ~PSTATE_NEGOTIATE; |
541 | else if (!strcmp(param->name, OFMARKINT)) | 581 | else if (!strcmp(param->name, OFMARKINT)) |
542 | param->state &= ~PSTATE_NEGOTIATE; | 582 | param->state &= ~PSTATE_NEGOTIATE; |
583 | else if (!strcmp(param->name, RDMAEXTENTIONS)) | ||
584 | param->state &= ~PSTATE_NEGOTIATE; | ||
585 | else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) | ||
586 | param->state &= ~PSTATE_NEGOTIATE; | ||
587 | else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) | ||
588 | param->state &= ~PSTATE_NEGOTIATE; | ||
543 | } | 589 | } |
544 | 590 | ||
545 | return 0; | 591 | return 0; |
@@ -1755,6 +1801,9 @@ void iscsi_set_connection_parameters( | |||
1755 | * this key is not sent over the wire. | 1801 | * this key is not sent over the wire. |
1756 | */ | 1802 | */ |
1757 | if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { | 1803 | if (!strcmp(param->name, MAXXMITDATASEGMENTLENGTH)) { |
1804 | if (param_list->iser == true) | ||
1805 | continue; | ||
1806 | |||
1758 | ops->MaxXmitDataSegmentLength = | 1807 | ops->MaxXmitDataSegmentLength = |
1759 | simple_strtoul(param->value, &tmpptr, 0); | 1808 | simple_strtoul(param->value, &tmpptr, 0); |
1760 | pr_debug("MaxXmitDataSegmentLength: %s\n", | 1809 | pr_debug("MaxXmitDataSegmentLength: %s\n", |
@@ -1800,6 +1849,22 @@ void iscsi_set_connection_parameters( | |||
1800 | simple_strtoul(param->value, &tmpptr, 0); | 1849 | simple_strtoul(param->value, &tmpptr, 0); |
1801 | pr_debug("IFMarkInt: %s\n", | 1850 | pr_debug("IFMarkInt: %s\n", |
1802 | param->value); | 1851 | param->value); |
1852 | } else if (!strcmp(param->name, INITIATORRECVDATASEGMENTLENGTH)) { | ||
1853 | ops->InitiatorRecvDataSegmentLength = | ||
1854 | simple_strtoul(param->value, &tmpptr, 0); | ||
1855 | pr_debug("InitiatorRecvDataSegmentLength: %s\n", | ||
1856 | param->value); | ||
1857 | ops->MaxRecvDataSegmentLength = | ||
1858 | ops->InitiatorRecvDataSegmentLength; | ||
1859 | pr_debug("Set MRDSL from InitiatorRecvDataSegmentLength\n"); | ||
1860 | } else if (!strcmp(param->name, TARGETRECVDATASEGMENTLENGTH)) { | ||
1861 | ops->TargetRecvDataSegmentLength = | ||
1862 | simple_strtoul(param->value, &tmpptr, 0); | ||
1863 | pr_debug("TargetRecvDataSegmentLength: %s\n", | ||
1864 | param->value); | ||
1865 | ops->MaxXmitDataSegmentLength = | ||
1866 | ops->TargetRecvDataSegmentLength; | ||
1867 | pr_debug("Set MXDSL from TargetRecvDataSegmentLength\n"); | ||
1803 | } | 1868 | } |
1804 | } | 1869 | } |
1805 | pr_debug("----------------------------------------------------" | 1870 | pr_debug("----------------------------------------------------" |
@@ -1912,6 +1977,10 @@ void iscsi_set_session_parameters( | |||
1912 | ops->SessionType = !strcmp(param->value, DISCOVERY); | 1977 | ops->SessionType = !strcmp(param->value, DISCOVERY); |
1913 | pr_debug("SessionType: %s\n", | 1978 | pr_debug("SessionType: %s\n", |
1914 | param->value); | 1979 | param->value); |
1980 | } else if (!strcmp(param->name, RDMAEXTENTIONS)) { | ||
1981 | ops->RDMAExtensions = !strcmp(param->value, YES); | ||
1982 | pr_debug("RDMAExtensions: %s\n", | ||
1983 | param->value); | ||
1915 | } | 1984 | } |
1916 | } | 1985 | } |
1917 | pr_debug("----------------------------------------------------" | 1986 | pr_debug("----------------------------------------------------" |
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h index 1e1b7504a76b..f31b9c4b83f2 100644 --- a/drivers/target/iscsi/iscsi_target_parameters.h +++ b/drivers/target/iscsi/iscsi_target_parameters.h | |||
@@ -27,7 +27,7 @@ extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *); | |||
27 | extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *); | 27 | extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *); |
28 | extern void iscsi_print_params(struct iscsi_param_list *); | 28 | extern void iscsi_print_params(struct iscsi_param_list *); |
29 | extern int iscsi_create_default_params(struct iscsi_param_list **); | 29 | extern int iscsi_create_default_params(struct iscsi_param_list **); |
30 | extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *); | 30 | extern int iscsi_set_keys_to_negotiate(struct iscsi_param_list *, bool); |
31 | extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *); | 31 | extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *); |
32 | extern int iscsi_copy_param_list(struct iscsi_param_list **, | 32 | extern int iscsi_copy_param_list(struct iscsi_param_list **, |
33 | struct iscsi_param_list *, int); | 33 | struct iscsi_param_list *, int); |
@@ -89,6 +89,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, | |||
89 | #define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft" | 89 | #define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft" |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * Parameter names of iSCSI Extentions for RDMA (iSER). See RFC-5046 | ||
93 | */ | ||
94 | #define RDMAEXTENTIONS "RDMAExtensions" | ||
95 | #define INITIATORRECVDATASEGMENTLENGTH "InitiatorRecvDataSegmentLength" | ||
96 | #define TARGETRECVDATASEGMENTLENGTH "TargetRecvDataSegmentLength" | ||
97 | |||
98 | /* | ||
92 | * For AuthMethod. | 99 | * For AuthMethod. |
93 | */ | 100 | */ |
94 | #define KRB5 "KRB5" | 101 | #define KRB5 "KRB5" |
@@ -133,6 +140,13 @@ extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, | |||
133 | #define INITIAL_OFMARKINT "2048~65535" | 140 | #define INITIAL_OFMARKINT "2048~65535" |
134 | 141 | ||
135 | /* | 142 | /* |
143 | * Initial values for iSER parameters following RFC-5046 Section 6 | ||
144 | */ | ||
145 | #define INITIAL_RDMAEXTENTIONS NO | ||
146 | #define INITIAL_INITIATORRECVDATASEGMENTLENGTH "262144" | ||
147 | #define INITIAL_TARGETRECVDATASEGMENTLENGTH "8192" | ||
148 | |||
149 | /* | ||
136 | * For [Header,Data]Digests. | 150 | * For [Header,Data]Digests. |
137 | */ | 151 | */ |
138 | #define CRC32C "CRC32C" | 152 | #define CRC32C "CRC32C" |
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c index 9d4417aae921..b997e5da47d3 100644 --- a/drivers/target/iscsi/iscsi_target_tmr.c +++ b/drivers/target/iscsi/iscsi_target_tmr.c | |||
@@ -23,6 +23,7 @@ | |||
23 | #include <scsi/iscsi_proto.h> | 23 | #include <scsi/iscsi_proto.h> |
24 | #include <target/target_core_base.h> | 24 | #include <target/target_core_base.h> |
25 | #include <target/target_core_fabric.h> | 25 | #include <target/target_core_fabric.h> |
26 | #include <target/iscsi/iscsi_transport.h> | ||
26 | 27 | ||
27 | #include "iscsi_target_core.h" | 28 | #include "iscsi_target_core.h" |
28 | #include "iscsi_target_seq_pdu_list.h" | 29 | #include "iscsi_target_seq_pdu_list.h" |
@@ -301,7 +302,7 @@ static int iscsit_task_reassign_complete_write( | |||
301 | /* | 302 | /* |
302 | * iscsit_build_r2ts_for_cmd() can handle the rest from here. | 303 | * iscsit_build_r2ts_for_cmd() can handle the rest from here. |
303 | */ | 304 | */ |
304 | return iscsit_build_r2ts_for_cmd(cmd, conn, true); | 305 | return conn->conn_transport->iscsit_get_dataout(conn, cmd, true); |
305 | } | 306 | } |
306 | 307 | ||
307 | static int iscsit_task_reassign_complete_read( | 308 | static int iscsit_task_reassign_complete_read( |
@@ -471,6 +472,7 @@ int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn) | |||
471 | 472 | ||
472 | return 0; | 473 | return 0; |
473 | } | 474 | } |
475 | EXPORT_SYMBOL(iscsit_tmr_post_handler); | ||
474 | 476 | ||
475 | /* | 477 | /* |
476 | * Nothing to do here, but leave it for good measure. :-) | 478 | * Nothing to do here, but leave it for good measure. :-) |
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c index ee8f8c66248d..439260b7d87f 100644 --- a/drivers/target/iscsi/iscsi_target_tpg.c +++ b/drivers/target/iscsi/iscsi_target_tpg.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include "iscsi_target.h" | 31 | #include "iscsi_target.h" |
32 | #include "iscsi_target_parameters.h" | 32 | #include "iscsi_target_parameters.h" |
33 | 33 | ||
34 | #include <target/iscsi/iscsi_transport.h> | ||
35 | |||
34 | struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt) | 36 | struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt) |
35 | { | 37 | { |
36 | struct iscsi_portal_group *tpg; | 38 | struct iscsi_portal_group *tpg; |
@@ -508,7 +510,7 @@ struct iscsi_tpg_np *iscsit_tpg_add_network_portal( | |||
508 | 510 | ||
509 | pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n", | 511 | pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n", |
510 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, | 512 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, |
511 | (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); | 513 | np->np_transport->name); |
512 | 514 | ||
513 | return tpg_np; | 515 | return tpg_np; |
514 | } | 516 | } |
@@ -522,7 +524,7 @@ static int iscsit_tpg_release_np( | |||
522 | 524 | ||
523 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", | 525 | pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", |
524 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, | 526 | tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, |
525 | (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); | 527 | np->np_transport->name); |
526 | 528 | ||
527 | tpg_np->tpg_np = NULL; | 529 | tpg_np->tpg_np = NULL; |
528 | tpg_np->tpg = NULL; | 530 | tpg_np->tpg = NULL; |
diff --git a/drivers/target/iscsi/iscsi_target_transport.c b/drivers/target/iscsi/iscsi_target_transport.c new file mode 100644 index 000000000000..882728fac30c --- /dev/null +++ b/drivers/target/iscsi/iscsi_target_transport.c | |||
@@ -0,0 +1,55 @@ | |||
1 | #include <linux/spinlock.h> | ||
2 | #include <linux/list.h> | ||
3 | #include <target/iscsi/iscsi_transport.h> | ||
4 | |||
5 | static LIST_HEAD(g_transport_list); | ||
6 | static DEFINE_MUTEX(transport_mutex); | ||
7 | |||
8 | struct iscsit_transport *iscsit_get_transport(int type) | ||
9 | { | ||
10 | struct iscsit_transport *t; | ||
11 | |||
12 | mutex_lock(&transport_mutex); | ||
13 | list_for_each_entry(t, &g_transport_list, t_node) { | ||
14 | if (t->transport_type == type) { | ||
15 | if (t->owner && !try_module_get(t->owner)) { | ||
16 | t = NULL; | ||
17 | } | ||
18 | mutex_unlock(&transport_mutex); | ||
19 | return t; | ||
20 | } | ||
21 | } | ||
22 | mutex_unlock(&transport_mutex); | ||
23 | |||
24 | return NULL; | ||
25 | } | ||
26 | |||
27 | void iscsit_put_transport(struct iscsit_transport *t) | ||
28 | { | ||
29 | if (t->owner) | ||
30 | module_put(t->owner); | ||
31 | } | ||
32 | |||
33 | int iscsit_register_transport(struct iscsit_transport *t) | ||
34 | { | ||
35 | INIT_LIST_HEAD(&t->t_node); | ||
36 | |||
37 | mutex_lock(&transport_mutex); | ||
38 | list_add_tail(&t->t_node, &g_transport_list); | ||
39 | mutex_unlock(&transport_mutex); | ||
40 | |||
41 | pr_debug("Registered iSCSI transport: %s\n", t->name); | ||
42 | |||
43 | return 0; | ||
44 | } | ||
45 | EXPORT_SYMBOL(iscsit_register_transport); | ||
46 | |||
47 | void iscsit_unregister_transport(struct iscsit_transport *t) | ||
48 | { | ||
49 | mutex_lock(&transport_mutex); | ||
50 | list_del(&t->t_node); | ||
51 | mutex_unlock(&transport_mutex); | ||
52 | |||
53 | pr_debug("Unregistered iSCSI transport: %s\n", t->name); | ||
54 | } | ||
55 | EXPORT_SYMBOL(iscsit_unregister_transport); | ||
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c index 7ce350578c82..2cc6c9a3ffb8 100644 --- a/drivers/target/iscsi/iscsi_target_util.c +++ b/drivers/target/iscsi/iscsi_target_util.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <target/target_core_base.h> | 24 | #include <target/target_core_base.h> |
25 | #include <target/target_core_fabric.h> | 25 | #include <target/target_core_fabric.h> |
26 | #include <target/target_core_configfs.h> | 26 | #include <target/target_core_configfs.h> |
27 | #include <target/iscsi/iscsi_transport.h> | ||
27 | 28 | ||
28 | #include "iscsi_target_core.h" | 29 | #include "iscsi_target_core.h" |
29 | #include "iscsi_target_parameters.h" | 30 | #include "iscsi_target_parameters.h" |
@@ -148,6 +149,18 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) | |||
148 | spin_unlock_bh(&cmd->r2t_lock); | 149 | spin_unlock_bh(&cmd->r2t_lock); |
149 | } | 150 | } |
150 | 151 | ||
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 | |||
151 | /* | 164 | /* |
152 | * May be called from software interrupt (timer) context for allocating | 165 | * May be called from software interrupt (timer) context for allocating |
153 | * iSCSI NopINs. | 166 | * iSCSI NopINs. |
@@ -156,13 +169,12 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) | |||
156 | { | 169 | { |
157 | struct iscsi_cmd *cmd; | 170 | struct iscsi_cmd *cmd; |
158 | 171 | ||
159 | cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask); | 172 | cmd = conn->conn_transport->iscsit_alloc_cmd(conn, gfp_mask); |
160 | if (!cmd) { | 173 | if (!cmd) { |
161 | pr_err("Unable to allocate memory for struct iscsi_cmd.\n"); | 174 | pr_err("Unable to allocate memory for struct iscsi_cmd.\n"); |
162 | return NULL; | 175 | return NULL; |
163 | } | 176 | } |
164 | 177 | cmd->conn = conn; | |
165 | cmd->conn = conn; | ||
166 | INIT_LIST_HEAD(&cmd->i_conn_node); | 178 | INIT_LIST_HEAD(&cmd->i_conn_node); |
167 | INIT_LIST_HEAD(&cmd->datain_list); | 179 | INIT_LIST_HEAD(&cmd->datain_list); |
168 | INIT_LIST_HEAD(&cmd->cmd_r2t_list); | 180 | INIT_LIST_HEAD(&cmd->cmd_r2t_list); |
@@ -175,6 +187,7 @@ struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) | |||
175 | 187 | ||
176 | return cmd; | 188 | return cmd; |
177 | } | 189 | } |
190 | EXPORT_SYMBOL(iscsit_allocate_cmd); | ||
178 | 191 | ||
179 | struct iscsi_seq *iscsit_get_seq_holder_for_datain( | 192 | struct iscsi_seq *iscsit_get_seq_holder_for_datain( |
180 | struct iscsi_cmd *cmd, | 193 | struct iscsi_cmd *cmd, |
@@ -304,6 +317,7 @@ int iscsit_sequence_cmd( | |||
304 | 317 | ||
305 | return ret; | 318 | return ret; |
306 | } | 319 | } |
320 | EXPORT_SYMBOL(iscsit_sequence_cmd); | ||
307 | 321 | ||
308 | int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf) | 322 | int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf) |
309 | { | 323 | { |
@@ -689,6 +703,11 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd) | |||
689 | */ | 703 | */ |
690 | switch (cmd->iscsi_opcode) { | 704 | switch (cmd->iscsi_opcode) { |
691 | case ISCSI_OP_SCSI_CMD: | 705 | case ISCSI_OP_SCSI_CMD: |
706 | if (cmd->data_direction == DMA_TO_DEVICE) | ||
707 | iscsit_stop_dataout_timer(cmd); | ||
708 | /* | ||
709 | * Fallthrough | ||
710 | */ | ||
692 | case ISCSI_OP_SCSI_TMFUNC: | 711 | case ISCSI_OP_SCSI_TMFUNC: |
693 | transport_generic_free_cmd(&cmd->se_cmd, 1); | 712 | transport_generic_free_cmd(&cmd->se_cmd, 1); |
694 | break; | 713 | break; |
@@ -704,7 +723,7 @@ void iscsit_free_cmd(struct iscsi_cmd *cmd) | |||
704 | } | 723 | } |
705 | /* Fall-through */ | 724 | /* Fall-through */ |
706 | default: | 725 | default: |
707 | iscsit_release_cmd(cmd); | 726 | cmd->release_cmd(cmd); |
708 | break; | 727 | break; |
709 | } | 728 | } |
710 | } | 729 | } |
@@ -1226,34 +1245,19 @@ send_datacrc: | |||
1226 | */ | 1245 | */ |
1227 | int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail) | 1246 | int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail) |
1228 | { | 1247 | { |
1229 | u8 iscsi_hdr[ISCSI_HDR_LEN]; | ||
1230 | int err; | ||
1231 | struct kvec iov; | ||
1232 | struct iscsi_login_rsp *hdr; | 1248 | struct iscsi_login_rsp *hdr; |
1249 | struct iscsi_login *login = conn->conn_login; | ||
1233 | 1250 | ||
1251 | login->login_failed = 1; | ||
1234 | iscsit_collect_login_stats(conn, status_class, status_detail); | 1252 | iscsit_collect_login_stats(conn, status_class, status_detail); |
1235 | 1253 | ||
1236 | memset(&iov, 0, sizeof(struct kvec)); | 1254 | hdr = (struct iscsi_login_rsp *)&login->rsp[0]; |
1237 | memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN); | ||
1238 | |||
1239 | hdr = (struct iscsi_login_rsp *)&iscsi_hdr; | ||
1240 | hdr->opcode = ISCSI_OP_LOGIN_RSP; | 1255 | hdr->opcode = ISCSI_OP_LOGIN_RSP; |
1241 | hdr->status_class = status_class; | 1256 | hdr->status_class = status_class; |
1242 | hdr->status_detail = status_detail; | 1257 | hdr->status_detail = status_detail; |
1243 | hdr->itt = conn->login_itt; | 1258 | hdr->itt = conn->login_itt; |
1244 | 1259 | ||
1245 | iov.iov_base = &iscsi_hdr; | 1260 | return conn->conn_transport->iscsit_put_login_tx(conn, login, 0); |
1246 | iov.iov_len = ISCSI_HDR_LEN; | ||
1247 | |||
1248 | PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN); | ||
1249 | |||
1250 | err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN); | ||
1251 | if (err != ISCSI_HDR_LEN) { | ||
1252 | pr_err("tx_data returned less than expected\n"); | ||
1253 | return -1; | ||
1254 | } | ||
1255 | |||
1256 | return 0; | ||
1257 | } | 1261 | } |
1258 | 1262 | ||
1259 | void iscsit_print_session_params(struct iscsi_session *sess) | 1263 | void iscsit_print_session_params(struct iscsi_session *sess) |
@@ -1432,7 +1436,8 @@ void iscsit_collect_login_stats( | |||
1432 | strcpy(ls->last_intr_fail_name, | 1436 | strcpy(ls->last_intr_fail_name, |
1433 | (intrname ? intrname->value : "Unknown")); | 1437 | (intrname ? intrname->value : "Unknown")); |
1434 | 1438 | ||
1435 | ls->last_intr_fail_ip_family = conn->sock->sk->sk_family; | 1439 | ls->last_intr_fail_ip_family = conn->login_family; |
1440 | |||
1436 | snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE, | 1441 | snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE, |
1437 | "%s", conn->login_ip); | 1442 | "%s", conn->login_ip); |
1438 | ls->last_fail_time = get_jiffies_64(); | 1443 | ls->last_fail_time = get_jiffies_64(); |
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h index 894d0f837924..4f8e01a47081 100644 --- a/drivers/target/iscsi/iscsi_target_util.h +++ b/drivers/target/iscsi/iscsi_target_util.h | |||
@@ -8,6 +8,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32); | |||
8 | extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *); | 8 | extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *); |
9 | extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *); | 9 | extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *); |
10 | extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *); | 10 | extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *); |
11 | extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t); | ||
11 | extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); | 12 | extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); |
12 | extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32); | 13 | extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32); |
13 | extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); | 14 | extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); |
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c index ff1c5ee352cb..cbe48ab41745 100644 --- a/drivers/target/target_core_alua.c +++ b/drivers/target/target_core_alua.c | |||
@@ -409,6 +409,7 @@ static inline int core_alua_state_standby( | |||
409 | case REPORT_LUNS: | 409 | case REPORT_LUNS: |
410 | case RECEIVE_DIAGNOSTIC: | 410 | case RECEIVE_DIAGNOSTIC: |
411 | case SEND_DIAGNOSTIC: | 411 | case SEND_DIAGNOSTIC: |
412 | return 0; | ||
412 | case MAINTENANCE_IN: | 413 | case MAINTENANCE_IN: |
413 | switch (cdb[1] & 0x1f) { | 414 | switch (cdb[1] & 0x1f) { |
414 | case MI_REPORT_TARGET_PGS: | 415 | case MI_REPORT_TARGET_PGS: |
@@ -451,6 +452,7 @@ static inline int core_alua_state_unavailable( | |||
451 | switch (cdb[0]) { | 452 | switch (cdb[0]) { |
452 | case INQUIRY: | 453 | case INQUIRY: |
453 | case REPORT_LUNS: | 454 | case REPORT_LUNS: |
455 | return 0; | ||
454 | case MAINTENANCE_IN: | 456 | case MAINTENANCE_IN: |
455 | switch (cdb[1] & 0x1f) { | 457 | switch (cdb[1] & 0x1f) { |
456 | case MI_REPORT_TARGET_PGS: | 458 | case MI_REPORT_TARGET_PGS: |
@@ -491,6 +493,7 @@ static inline int core_alua_state_transition( | |||
491 | switch (cdb[0]) { | 493 | switch (cdb[0]) { |
492 | case INQUIRY: | 494 | case INQUIRY: |
493 | case REPORT_LUNS: | 495 | case REPORT_LUNS: |
496 | return 0; | ||
494 | case MAINTENANCE_IN: | 497 | case MAINTENANCE_IN: |
495 | switch (cdb[1] & 0x1f) { | 498 | switch (cdb[1] & 0x1f) { |
496 | case MI_REPORT_TARGET_PGS: | 499 | case MI_REPORT_TARGET_PGS: |
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c index 17a6acbc3ab0..58ed683e04ae 100644 --- a/drivers/target/target_core_file.c +++ b/drivers/target/target_core_file.c | |||
@@ -30,8 +30,10 @@ | |||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/spinlock.h> | 31 | #include <linux/spinlock.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/falloc.h> | ||
33 | #include <scsi/scsi.h> | 34 | #include <scsi/scsi.h> |
34 | #include <scsi/scsi_host.h> | 35 | #include <scsi/scsi_host.h> |
36 | #include <asm/unaligned.h> | ||
35 | 37 | ||
36 | #include <target/target_core_base.h> | 38 | #include <target/target_core_base.h> |
37 | #include <target/target_core_backend.h> | 39 | #include <target/target_core_backend.h> |
@@ -166,6 +168,33 @@ static int fd_configure_device(struct se_device *dev) | |||
166 | " block_device blocks: %llu logical_block_size: %d\n", | 168 | " block_device blocks: %llu logical_block_size: %d\n", |
167 | dev_size, div_u64(dev_size, fd_dev->fd_block_size), | 169 | dev_size, div_u64(dev_size, fd_dev->fd_block_size), |
168 | fd_dev->fd_block_size); | 170 | fd_dev->fd_block_size); |
171 | /* | ||
172 | * Check if the underlying struct block_device request_queue supports | ||
173 | * the QUEUE_FLAG_DISCARD bit for UNMAP/WRITE_SAME in SCSI + TRIM | ||
174 | * in ATA and we need to set TPE=1 | ||
175 | */ | ||
176 | if (blk_queue_discard(q)) { | ||
177 | dev->dev_attrib.max_unmap_lba_count = | ||
178 | q->limits.max_discard_sectors; | ||
179 | /* | ||
180 | * Currently hardcoded to 1 in Linux/SCSI code.. | ||
181 | */ | ||
182 | dev->dev_attrib.max_unmap_block_desc_count = 1; | ||
183 | dev->dev_attrib.unmap_granularity = | ||
184 | q->limits.discard_granularity >> 9; | ||
185 | dev->dev_attrib.unmap_granularity_alignment = | ||
186 | q->limits.discard_alignment; | ||
187 | pr_debug("IFILE: BLOCK Discard support available," | ||
188 | " disabled by default\n"); | ||
189 | } | ||
190 | /* | ||
191 | * Enable write same emulation for IBLOCK and use 0xFFFF as | ||
192 | * the smaller WRITE_SAME(10) only has a two-byte block count. | ||
193 | */ | ||
194 | dev->dev_attrib.max_write_same_len = 0xFFFF; | ||
195 | |||
196 | if (blk_queue_nonrot(q)) | ||
197 | dev->dev_attrib.is_nonrot = 1; | ||
169 | } else { | 198 | } else { |
170 | if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) { | 199 | if (!(fd_dev->fbd_flags & FBDF_HAS_SIZE)) { |
171 | pr_err("FILEIO: Missing fd_dev_size=" | 200 | pr_err("FILEIO: Missing fd_dev_size=" |
@@ -176,6 +205,23 @@ static int fd_configure_device(struct se_device *dev) | |||
176 | 205 | ||
177 | dev->dev_attrib.hw_block_size = FD_BLOCKSIZE; | 206 | dev->dev_attrib.hw_block_size = FD_BLOCKSIZE; |
178 | dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS; | 207 | dev->dev_attrib.hw_max_sectors = FD_MAX_SECTORS; |
208 | |||
209 | /* | ||
210 | * Limit UNMAP emulation to 8k Number of LBAs (NoLB) | ||
211 | */ | ||
212 | dev->dev_attrib.max_unmap_lba_count = 0x2000; | ||
213 | /* | ||
214 | * Currently hardcoded to 1 in Linux/SCSI code.. | ||
215 | */ | ||
216 | dev->dev_attrib.max_unmap_block_desc_count = 1; | ||
217 | dev->dev_attrib.unmap_granularity = 1; | ||
218 | dev->dev_attrib.unmap_granularity_alignment = 0; | ||
219 | |||
220 | /* | ||
221 | * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB) | ||
222 | * based upon struct iovec limit for vfs_writev() | ||
223 | */ | ||
224 | dev->dev_attrib.max_write_same_len = 0x1000; | ||
179 | } | 225 | } |
180 | 226 | ||
181 | fd_dev->fd_block_size = dev->dev_attrib.hw_block_size; | 227 | fd_dev->fd_block_size = dev->dev_attrib.hw_block_size; |
@@ -190,11 +236,6 @@ static int fd_configure_device(struct se_device *dev) | |||
190 | 236 | ||
191 | fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; | 237 | fd_dev->fd_dev_id = fd_host->fd_host_dev_id_count++; |
192 | fd_dev->fd_queue_depth = dev->queue_depth; | 238 | fd_dev->fd_queue_depth = dev->queue_depth; |
193 | /* | ||
194 | * Limit WRITE_SAME w/ UNMAP=0 emulation to 8k Number of LBAs (NoLB) | ||
195 | * based upon struct iovec limit for vfs_writev() | ||
196 | */ | ||
197 | dev->dev_attrib.max_write_same_len = 0x1000; | ||
198 | 239 | ||
199 | pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," | 240 | pr_debug("CORE_FILE[%u] - Added TCM FILEIO Device ID: %u at %s," |
200 | " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, | 241 | " %llu total bytes\n", fd_host->fd_host_id, fd_dev->fd_dev_id, |
@@ -442,6 +483,75 @@ fd_execute_write_same(struct se_cmd *cmd) | |||
442 | } | 483 | } |
443 | 484 | ||
444 | static sense_reason_t | 485 | static sense_reason_t |
486 | fd_do_unmap(struct se_cmd *cmd, void *priv, sector_t lba, sector_t nolb) | ||
487 | { | ||
488 | struct file *file = priv; | ||
489 | struct inode *inode = file->f_mapping->host; | ||
490 | int ret; | ||
491 | |||
492 | if (S_ISBLK(inode->i_mode)) { | ||
493 | /* The backend is block device, use discard */ | ||
494 | struct block_device *bdev = inode->i_bdev; | ||
495 | |||
496 | ret = blkdev_issue_discard(bdev, lba, | ||
497 | nolb, GFP_KERNEL, 0); | ||
498 | if (ret < 0) { | ||
499 | pr_warn("FILEIO: blkdev_issue_discard() failed: %d\n", | ||
500 | ret); | ||
501 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
502 | } | ||
503 | } else { | ||
504 | /* The backend is normal file, use fallocate */ | ||
505 | struct se_device *se_dev = cmd->se_dev; | ||
506 | loff_t pos = lba * se_dev->dev_attrib.block_size; | ||
507 | unsigned int len = nolb * se_dev->dev_attrib.block_size; | ||
508 | int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE; | ||
509 | |||
510 | if (!file->f_op->fallocate) | ||
511 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
512 | |||
513 | ret = file->f_op->fallocate(file, mode, pos, len); | ||
514 | if (ret < 0) { | ||
515 | pr_warn("FILEIO: fallocate() failed: %d\n", ret); | ||
516 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
517 | } | ||
518 | } | ||
519 | |||
520 | return 0; | ||
521 | } | ||
522 | |||
523 | static sense_reason_t | ||
524 | fd_execute_write_same_unmap(struct se_cmd *cmd) | ||
525 | { | ||
526 | struct se_device *se_dev = cmd->se_dev; | ||
527 | struct fd_dev *fd_dev = FD_DEV(se_dev); | ||
528 | struct file *file = fd_dev->fd_file; | ||
529 | sector_t lba = cmd->t_task_lba; | ||
530 | sector_t nolb = sbc_get_write_same_sectors(cmd); | ||
531 | int ret; | ||
532 | |||
533 | if (!nolb) { | ||
534 | target_complete_cmd(cmd, SAM_STAT_GOOD); | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | ret = fd_do_unmap(cmd, file, lba, nolb); | ||
539 | if (ret) | ||
540 | return ret; | ||
541 | |||
542 | target_complete_cmd(cmd, GOOD); | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static sense_reason_t | ||
547 | fd_execute_unmap(struct se_cmd *cmd) | ||
548 | { | ||
549 | struct file *file = FD_DEV(cmd->se_dev)->fd_file; | ||
550 | |||
551 | return sbc_execute_unmap(cmd, fd_do_unmap, file); | ||
552 | } | ||
553 | |||
554 | static sense_reason_t | ||
445 | fd_execute_rw(struct se_cmd *cmd) | 555 | fd_execute_rw(struct se_cmd *cmd) |
446 | { | 556 | { |
447 | struct scatterlist *sgl = cmd->t_data_sg; | 557 | struct scatterlist *sgl = cmd->t_data_sg; |
@@ -600,6 +710,8 @@ static struct sbc_ops fd_sbc_ops = { | |||
600 | .execute_rw = fd_execute_rw, | 710 | .execute_rw = fd_execute_rw, |
601 | .execute_sync_cache = fd_execute_sync_cache, | 711 | .execute_sync_cache = fd_execute_sync_cache, |
602 | .execute_write_same = fd_execute_write_same, | 712 | .execute_write_same = fd_execute_write_same, |
713 | .execute_write_same_unmap = fd_execute_write_same_unmap, | ||
714 | .execute_unmap = fd_execute_unmap, | ||
603 | }; | 715 | }; |
604 | 716 | ||
605 | static sense_reason_t | 717 | static sense_reason_t |
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c index 8bcc514ec8b6..07f5f94634bb 100644 --- a/drivers/target/target_core_iblock.c +++ b/drivers/target/target_core_iblock.c | |||
@@ -380,104 +380,40 @@ iblock_execute_sync_cache(struct se_cmd *cmd) | |||
380 | } | 380 | } |
381 | 381 | ||
382 | static sense_reason_t | 382 | static sense_reason_t |
383 | iblock_execute_unmap(struct se_cmd *cmd) | 383 | iblock_do_unmap(struct se_cmd *cmd, void *priv, |
384 | sector_t lba, sector_t nolb) | ||
384 | { | 385 | { |
385 | struct se_device *dev = cmd->se_dev; | 386 | struct block_device *bdev = priv; |
386 | struct iblock_dev *ib_dev = IBLOCK_DEV(dev); | 387 | int ret; |
387 | unsigned char *buf, *ptr = NULL; | ||
388 | sector_t lba; | ||
389 | int size; | ||
390 | u32 range; | ||
391 | sense_reason_t ret = 0; | ||
392 | int dl, bd_dl, err; | ||
393 | |||
394 | /* We never set ANC_SUP */ | ||
395 | if (cmd->t_task_cdb[1]) | ||
396 | return TCM_INVALID_CDB_FIELD; | ||
397 | |||
398 | if (cmd->data_length == 0) { | ||
399 | target_complete_cmd(cmd, SAM_STAT_GOOD); | ||
400 | return 0; | ||
401 | } | ||
402 | 388 | ||
403 | if (cmd->data_length < 8) { | 389 | ret = blkdev_issue_discard(bdev, lba, nolb, GFP_KERNEL, 0); |
404 | pr_warn("UNMAP parameter list length %u too small\n", | 390 | if (ret < 0) { |
405 | cmd->data_length); | 391 | pr_err("blkdev_issue_discard() failed: %d\n", ret); |
406 | return TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
407 | } | ||
408 | |||
409 | buf = transport_kmap_data_sg(cmd); | ||
410 | if (!buf) | ||
411 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 392 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
412 | |||
413 | dl = get_unaligned_be16(&buf[0]); | ||
414 | bd_dl = get_unaligned_be16(&buf[2]); | ||
415 | |||
416 | size = cmd->data_length - 8; | ||
417 | if (bd_dl > size) | ||
418 | pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", | ||
419 | cmd->data_length, bd_dl); | ||
420 | else | ||
421 | size = bd_dl; | ||
422 | |||
423 | if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { | ||
424 | ret = TCM_INVALID_PARAMETER_LIST; | ||
425 | goto err; | ||
426 | } | 393 | } |
427 | 394 | ||
428 | /* First UNMAP block descriptor starts at 8 byte offset */ | 395 | return 0; |
429 | ptr = &buf[8]; | 396 | } |
430 | pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" | ||
431 | " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); | ||
432 | |||
433 | while (size >= 16) { | ||
434 | lba = get_unaligned_be64(&ptr[0]); | ||
435 | range = get_unaligned_be32(&ptr[8]); | ||
436 | pr_debug("UNMAP: Using lba: %llu and range: %u\n", | ||
437 | (unsigned long long)lba, range); | ||
438 | |||
439 | if (range > dev->dev_attrib.max_unmap_lba_count) { | ||
440 | ret = TCM_INVALID_PARAMETER_LIST; | ||
441 | goto err; | ||
442 | } | ||
443 | |||
444 | if (lba + range > dev->transport->get_blocks(dev) + 1) { | ||
445 | ret = TCM_ADDRESS_OUT_OF_RANGE; | ||
446 | goto err; | ||
447 | } | ||
448 | |||
449 | err = blkdev_issue_discard(ib_dev->ibd_bd, lba, range, | ||
450 | GFP_KERNEL, 0); | ||
451 | if (err < 0) { | ||
452 | pr_err("blkdev_issue_discard() failed: %d\n", | ||
453 | err); | ||
454 | ret = TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
455 | goto err; | ||
456 | } | ||
457 | 397 | ||
458 | ptr += 16; | 398 | static sense_reason_t |
459 | size -= 16; | 399 | iblock_execute_unmap(struct se_cmd *cmd) |
460 | } | 400 | { |
401 | struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; | ||
461 | 402 | ||
462 | err: | 403 | return sbc_execute_unmap(cmd, iblock_do_unmap, bdev); |
463 | transport_kunmap_data_sg(cmd); | ||
464 | if (!ret) | ||
465 | target_complete_cmd(cmd, GOOD); | ||
466 | return ret; | ||
467 | } | 404 | } |
468 | 405 | ||
469 | static sense_reason_t | 406 | static sense_reason_t |
470 | iblock_execute_write_same_unmap(struct se_cmd *cmd) | 407 | iblock_execute_write_same_unmap(struct se_cmd *cmd) |
471 | { | 408 | { |
472 | struct iblock_dev *ib_dev = IBLOCK_DEV(cmd->se_dev); | 409 | struct block_device *bdev = IBLOCK_DEV(cmd->se_dev)->ibd_bd; |
473 | int rc; | 410 | sector_t lba = cmd->t_task_lba; |
474 | 411 | sector_t nolb = sbc_get_write_same_sectors(cmd); | |
475 | rc = blkdev_issue_discard(ib_dev->ibd_bd, cmd->t_task_lba, | 412 | int ret; |
476 | sbc_get_write_same_sectors(cmd), GFP_KERNEL, 0); | 413 | |
477 | if (rc < 0) { | 414 | ret = iblock_do_unmap(cmd, bdev, lba, nolb); |
478 | pr_warn("blkdev_issue_discard() failed: %d\n", rc); | 415 | if (ret) |
479 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 416 | return ret; |
480 | } | ||
481 | 417 | ||
482 | target_complete_cmd(cmd, GOOD); | 418 | target_complete_cmd(cmd, GOOD); |
483 | return 0; | 419 | return 0; |
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c index 60d4b5185f32..bbc5b0ee2bdc 100644 --- a/drivers/target/target_core_sbc.c +++ b/drivers/target/target_core_sbc.c | |||
@@ -596,3 +596,88 @@ u32 sbc_get_device_type(struct se_device *dev) | |||
596 | return TYPE_DISK; | 596 | return TYPE_DISK; |
597 | } | 597 | } |
598 | EXPORT_SYMBOL(sbc_get_device_type); | 598 | EXPORT_SYMBOL(sbc_get_device_type); |
599 | |||
600 | sense_reason_t | ||
601 | sbc_execute_unmap(struct se_cmd *cmd, | ||
602 | sense_reason_t (*do_unmap_fn)(struct se_cmd *, void *, | ||
603 | sector_t, sector_t), | ||
604 | void *priv) | ||
605 | { | ||
606 | struct se_device *dev = cmd->se_dev; | ||
607 | unsigned char *buf, *ptr = NULL; | ||
608 | sector_t lba; | ||
609 | int size; | ||
610 | u32 range; | ||
611 | sense_reason_t ret = 0; | ||
612 | int dl, bd_dl; | ||
613 | |||
614 | /* We never set ANC_SUP */ | ||
615 | if (cmd->t_task_cdb[1]) | ||
616 | return TCM_INVALID_CDB_FIELD; | ||
617 | |||
618 | if (cmd->data_length == 0) { | ||
619 | target_complete_cmd(cmd, SAM_STAT_GOOD); | ||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | if (cmd->data_length < 8) { | ||
624 | pr_warn("UNMAP parameter list length %u too small\n", | ||
625 | cmd->data_length); | ||
626 | return TCM_PARAMETER_LIST_LENGTH_ERROR; | ||
627 | } | ||
628 | |||
629 | buf = transport_kmap_data_sg(cmd); | ||
630 | if (!buf) | ||
631 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | ||
632 | |||
633 | dl = get_unaligned_be16(&buf[0]); | ||
634 | bd_dl = get_unaligned_be16(&buf[2]); | ||
635 | |||
636 | size = cmd->data_length - 8; | ||
637 | if (bd_dl > size) | ||
638 | pr_warn("UNMAP parameter list length %u too small, ignoring bd_dl %u\n", | ||
639 | cmd->data_length, bd_dl); | ||
640 | else | ||
641 | size = bd_dl; | ||
642 | |||
643 | if (size / 16 > dev->dev_attrib.max_unmap_block_desc_count) { | ||
644 | ret = TCM_INVALID_PARAMETER_LIST; | ||
645 | goto err; | ||
646 | } | ||
647 | |||
648 | /* First UNMAP block descriptor starts at 8 byte offset */ | ||
649 | ptr = &buf[8]; | ||
650 | pr_debug("UNMAP: Sub: %s Using dl: %u bd_dl: %u size: %u" | ||
651 | " ptr: %p\n", dev->transport->name, dl, bd_dl, size, ptr); | ||
652 | |||
653 | while (size >= 16) { | ||
654 | lba = get_unaligned_be64(&ptr[0]); | ||
655 | range = get_unaligned_be32(&ptr[8]); | ||
656 | pr_debug("UNMAP: Using lba: %llu and range: %u\n", | ||
657 | (unsigned long long)lba, range); | ||
658 | |||
659 | if (range > dev->dev_attrib.max_unmap_lba_count) { | ||
660 | ret = TCM_INVALID_PARAMETER_LIST; | ||
661 | goto err; | ||
662 | } | ||
663 | |||
664 | if (lba + range > dev->transport->get_blocks(dev) + 1) { | ||
665 | ret = TCM_ADDRESS_OUT_OF_RANGE; | ||
666 | goto err; | ||
667 | } | ||
668 | |||
669 | ret = do_unmap_fn(cmd, priv, lba, range); | ||
670 | if (ret) | ||
671 | goto err; | ||
672 | |||
673 | ptr += 16; | ||
674 | size -= 16; | ||
675 | } | ||
676 | |||
677 | err: | ||
678 | transport_kunmap_data_sg(cmd); | ||
679 | if (!ret) | ||
680 | target_complete_cmd(cmd, GOOD); | ||
681 | return ret; | ||
682 | } | ||
683 | EXPORT_SYMBOL(sbc_execute_unmap); | ||
diff --git a/drivers/target/target_core_transport.c b/drivers/target/target_core_transport.c index 2030b608136d..f8388b4024aa 100644 --- a/drivers/target/target_core_transport.c +++ b/drivers/target/target_core_transport.c | |||
@@ -65,7 +65,6 @@ static void transport_complete_task_attr(struct se_cmd *cmd); | |||
65 | static void transport_handle_queue_full(struct se_cmd *cmd, | 65 | static void transport_handle_queue_full(struct se_cmd *cmd, |
66 | struct se_device *dev); | 66 | struct se_device *dev); |
67 | static int transport_generic_get_mem(struct se_cmd *cmd); | 67 | static int transport_generic_get_mem(struct se_cmd *cmd); |
68 | static int target_get_sess_cmd(struct se_session *, struct se_cmd *, bool); | ||
69 | static void transport_put_cmd(struct se_cmd *cmd); | 68 | static void transport_put_cmd(struct se_cmd *cmd); |
70 | static void target_complete_ok_work(struct work_struct *work); | 69 | static void target_complete_ok_work(struct work_struct *work); |
71 | 70 | ||
@@ -1139,8 +1138,10 @@ target_setup_cmd_from_cdb(struct se_cmd *cmd, unsigned char *cdb) | |||
1139 | return ret; | 1138 | return ret; |
1140 | 1139 | ||
1141 | ret = target_check_reservation(cmd); | 1140 | ret = target_check_reservation(cmd); |
1142 | if (ret) | 1141 | if (ret) { |
1142 | cmd->scsi_status = SAM_STAT_RESERVATION_CONFLICT; | ||
1143 | return ret; | 1143 | return ret; |
1144 | } | ||
1144 | 1145 | ||
1145 | ret = dev->transport->parse_cdb(cmd); | 1146 | ret = dev->transport->parse_cdb(cmd); |
1146 | if (ret) | 1147 | if (ret) |
@@ -2177,7 +2178,7 @@ EXPORT_SYMBOL(transport_generic_free_cmd); | |||
2177 | * @se_cmd: command descriptor to add | 2178 | * @se_cmd: command descriptor to add |
2178 | * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() | 2179 | * @ack_kref: Signal that fabric will perform an ack target_put_sess_cmd() |
2179 | */ | 2180 | */ |
2180 | static int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, | 2181 | int target_get_sess_cmd(struct se_session *se_sess, struct se_cmd *se_cmd, |
2181 | bool ack_kref) | 2182 | bool ack_kref) |
2182 | { | 2183 | { |
2183 | unsigned long flags; | 2184 | unsigned long flags; |
@@ -2206,6 +2207,7 @@ out: | |||
2206 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); | 2207 | spin_unlock_irqrestore(&se_sess->sess_cmd_lock, flags); |
2207 | return ret; | 2208 | return ret; |
2208 | } | 2209 | } |
2210 | EXPORT_SYMBOL(target_get_sess_cmd); | ||
2209 | 2211 | ||
2210 | static void target_release_cmd_kref(struct kref *kref) | 2212 | static void target_release_cmd_kref(struct kref *kref) |
2211 | { | 2213 | { |
@@ -2763,8 +2765,13 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd, | |||
2763 | /* CURRENT ERROR */ | 2765 | /* CURRENT ERROR */ |
2764 | buffer[0] = 0x70; | 2766 | buffer[0] = 0x70; |
2765 | buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; | 2767 | buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10; |
2766 | /* ILLEGAL REQUEST */ | 2768 | /* |
2767 | buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST; | 2769 | * Returning ILLEGAL REQUEST would cause immediate IO errors on |
2770 | * Solaris initiators. Returning NOT READY instead means the | ||
2771 | * operations will be retried a finite number of times and we | ||
2772 | * can survive intermittent errors. | ||
2773 | */ | ||
2774 | buffer[SPC_SENSE_KEY_OFFSET] = NOT_READY; | ||
2768 | /* LOGICAL UNIT COMMUNICATION FAILURE */ | 2775 | /* LOGICAL UNIT COMMUNICATION FAILURE */ |
2769 | buffer[SPC_ASC_KEY_OFFSET] = 0x08; | 2776 | buffer[SPC_ASC_KEY_OFFSET] = 0x08; |
2770 | break; | 2777 | break; |
diff --git a/drivers/target/tcm_fc/tfc_io.c b/drivers/target/tcm_fc/tfc_io.c index b6fd4cf42840..e415af32115a 100644 --- a/drivers/target/tcm_fc/tfc_io.c +++ b/drivers/target/tcm_fc/tfc_io.c | |||
@@ -103,6 +103,13 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
103 | use_sg = !(remaining % 4); | 103 | use_sg = !(remaining % 4); |
104 | 104 | ||
105 | while (remaining) { | 105 | while (remaining) { |
106 | struct fc_seq *seq = cmd->seq; | ||
107 | |||
108 | if (!seq) { | ||
109 | pr_debug("%s: Command aborted, xid 0x%x\n", | ||
110 | __func__, ep->xid); | ||
111 | break; | ||
112 | } | ||
106 | if (!mem_len) { | 113 | if (!mem_len) { |
107 | sg = sg_next(sg); | 114 | sg = sg_next(sg); |
108 | mem_len = min((size_t)sg->length, remaining); | 115 | mem_len = min((size_t)sg->length, remaining); |
@@ -169,7 +176,7 @@ int ft_queue_data_in(struct se_cmd *se_cmd) | |||
169 | f_ctl |= FC_FC_END_SEQ; | 176 | f_ctl |= FC_FC_END_SEQ; |
170 | fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, | 177 | fc_fill_fc_hdr(fp, FC_RCTL_DD_SOL_DATA, ep->did, ep->sid, |
171 | FC_TYPE_FCP, f_ctl, fh_off); | 178 | FC_TYPE_FCP, f_ctl, fh_off); |
172 | error = lport->tt.seq_send(lport, cmd->seq, fp); | 179 | error = lport->tt.seq_send(lport, seq, fp); |
173 | if (error) { | 180 | if (error) { |
174 | /* XXX For now, initiator will retry */ | 181 | /* XXX For now, initiator will retry */ |
175 | pr_err_ratelimited("%s: Failed to send frame %p, " | 182 | pr_err_ratelimited("%s: Failed to send frame %p, " |
diff --git a/drivers/target/tcm_fc/tfc_sess.c b/drivers/target/tcm_fc/tfc_sess.c index 113f33598b9f..4859505ae2ed 100644 --- a/drivers/target/tcm_fc/tfc_sess.c +++ b/drivers/target/tcm_fc/tfc_sess.c | |||
@@ -428,19 +428,12 @@ static int ft_prli(struct fc_rport_priv *rdata, u32 spp_len, | |||
428 | return ret; | 428 | return ret; |
429 | } | 429 | } |
430 | 430 | ||
431 | static void ft_sess_rcu_free(struct rcu_head *rcu) | ||
432 | { | ||
433 | struct ft_sess *sess = container_of(rcu, struct ft_sess, rcu); | ||
434 | |||
435 | kfree(sess); | ||
436 | } | ||
437 | |||
438 | static void ft_sess_free(struct kref *kref) | 431 | static void ft_sess_free(struct kref *kref) |
439 | { | 432 | { |
440 | struct ft_sess *sess = container_of(kref, struct ft_sess, kref); | 433 | struct ft_sess *sess = container_of(kref, struct ft_sess, kref); |
441 | 434 | ||
442 | transport_deregister_session(sess->se_sess); | 435 | transport_deregister_session(sess->se_sess); |
443 | call_rcu(&sess->rcu, ft_sess_rcu_free); | 436 | kfree_rcu(sess, rcu); |
444 | } | 437 | } |
445 | 438 | ||
446 | void ft_sess_put(struct ft_sess *sess) | 439 | void ft_sess_put(struct ft_sess *sess) |