diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-13 01:38:32 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-06-13 01:38:32 -0400 |
commit | ed9ea4ed3a44e8f8e8c7e8a12a05fd73f9ae1fb4 (patch) | |
tree | f7275c1cade0a756d5b456dc23ccb692ff6073d5 /drivers/vhost | |
parent | c1fdb2d3389c5a1e7c559a37a4967c1d2580e75c (diff) | |
parent | 0ed6e189e3f6ac3a25383ed5cc8b0ac24c9b97b7 (diff) |
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending
Pull SCSI target updates from Nicholas Bellinger:
"The highlights this round include:
- Add support for T10 PI pass-through between vhost-scsi +
virtio-scsi (MST + Paolo + MKP + nab)
- Add support for T10 PI in qla2xxx target mode (Quinn + MKP + hch +
nab, merged through scsi.git)
- Add support for percpu-ida pre-allocation in qla2xxx target code
(Quinn + nab)
- A number of iser-target fixes related to hardening the network
portal shutdown path (Sagi + Slava)
- Fix response length residual handling for a number of control CDBs
(Roland + Christophe V.)
- Various iscsi RFC conformance fixes in the CHAP authentication path
(Tejas and Calsoft folks + nab)
- Return TASK_SET_FULL status for tcm_fc(FCoE) DataIn + Response
failures (Vasu + Jun + nab)
- Fix long-standing ABORT_TASK + session reset hang (nab)
- Convert iser-initiator + iser-target to include T10 bytes into EDTL
(Sagi + Or + MKP + Mike Christie)
- Fix NULL pointer dereference regression related to XCOPY introduced
in v3.15 + CC'ed to v3.12.y (nab)"
* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/nab/target-pending: (34 commits)
target: Fix NULL pointer dereference for XCOPY in target_put_sess_cmd
vhost-scsi: Include prot_bytes into expected data transfer length
TARGET/sbc,loopback: Adjust command data length in case pi exists on the wire
libiscsi, iser: Adjust data_length to include protection information
scsi_cmnd: Introduce scsi_transfer_length helper
target: Report correct response length for some commands
target/sbc: Check that the LBA and number of blocks are correct in VERIFY
target/sbc: Remove sbc_check_valid_sectors()
Target/iscsi: Fix sendtargets response pdu for iser transport
Target/iser: Fix a wrong dereference in case discovery session is over iser
iscsi-target: Fix ABORT_TASK + connection reset iscsi_queue_req memory leak
target: Use complete_all for se_cmd->t_transport_stop_comp
target: Set CMD_T_ACTIVE bit for Task Management Requests
target: cleanup some boolean tests
target/spc: Simplify INQUIRY EVPD=0x80
tcm_fc: Generate TASK_SET_FULL status for response failures
tcm_fc: Generate TASK_SET_FULL status for DataIN failures
iscsi-target: Reject mutual authentication with reflected CHAP_C
iscsi-target: Remove no-op from iscsit_tpg_del_portal_group
iscsi-target: Fix CHAP_A parameter list handling
...
Diffstat (limited to 'drivers/vhost')
-rw-r--r-- | drivers/vhost/scsi.c | 308 |
1 files changed, 212 insertions, 96 deletions
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c index e9c280f55819..4f4ffa4c604e 100644 --- a/drivers/vhost/scsi.c +++ b/drivers/vhost/scsi.c | |||
@@ -57,7 +57,8 @@ | |||
57 | #define TCM_VHOST_MAX_CDB_SIZE 32 | 57 | #define TCM_VHOST_MAX_CDB_SIZE 32 |
58 | #define TCM_VHOST_DEFAULT_TAGS 256 | 58 | #define TCM_VHOST_DEFAULT_TAGS 256 |
59 | #define TCM_VHOST_PREALLOC_SGLS 2048 | 59 | #define TCM_VHOST_PREALLOC_SGLS 2048 |
60 | #define TCM_VHOST_PREALLOC_PAGES 2048 | 60 | #define TCM_VHOST_PREALLOC_UPAGES 2048 |
61 | #define TCM_VHOST_PREALLOC_PROT_SGLS 512 | ||
61 | 62 | ||
62 | struct vhost_scsi_inflight { | 63 | struct vhost_scsi_inflight { |
63 | /* Wait for the flush operation to finish */ | 64 | /* Wait for the flush operation to finish */ |
@@ -79,10 +80,12 @@ struct tcm_vhost_cmd { | |||
79 | u64 tvc_tag; | 80 | u64 tvc_tag; |
80 | /* The number of scatterlists associated with this cmd */ | 81 | /* The number of scatterlists associated with this cmd */ |
81 | u32 tvc_sgl_count; | 82 | u32 tvc_sgl_count; |
83 | u32 tvc_prot_sgl_count; | ||
82 | /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */ | 84 | /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */ |
83 | u32 tvc_lun; | 85 | u32 tvc_lun; |
84 | /* Pointer to the SGL formatted memory from virtio-scsi */ | 86 | /* Pointer to the SGL formatted memory from virtio-scsi */ |
85 | struct scatterlist *tvc_sgl; | 87 | struct scatterlist *tvc_sgl; |
88 | struct scatterlist *tvc_prot_sgl; | ||
86 | struct page **tvc_upages; | 89 | struct page **tvc_upages; |
87 | /* Pointer to response */ | 90 | /* Pointer to response */ |
88 | struct virtio_scsi_cmd_resp __user *tvc_resp; | 91 | struct virtio_scsi_cmd_resp __user *tvc_resp; |
@@ -166,7 +169,8 @@ enum { | |||
166 | }; | 169 | }; |
167 | 170 | ||
168 | enum { | 171 | enum { |
169 | VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) | 172 | VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) | |
173 | (1ULL << VIRTIO_SCSI_F_T10_PI) | ||
170 | }; | 174 | }; |
171 | 175 | ||
172 | #define VHOST_SCSI_MAX_TARGET 256 | 176 | #define VHOST_SCSI_MAX_TARGET 256 |
@@ -456,12 +460,16 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd) | |||
456 | struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd, | 460 | struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd, |
457 | struct tcm_vhost_cmd, tvc_se_cmd); | 461 | struct tcm_vhost_cmd, tvc_se_cmd); |
458 | struct se_session *se_sess = se_cmd->se_sess; | 462 | struct se_session *se_sess = se_cmd->se_sess; |
463 | int i; | ||
459 | 464 | ||
460 | if (tv_cmd->tvc_sgl_count) { | 465 | if (tv_cmd->tvc_sgl_count) { |
461 | u32 i; | ||
462 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) | 466 | for (i = 0; i < tv_cmd->tvc_sgl_count; i++) |
463 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); | 467 | put_page(sg_page(&tv_cmd->tvc_sgl[i])); |
464 | } | 468 | } |
469 | if (tv_cmd->tvc_prot_sgl_count) { | ||
470 | for (i = 0; i < tv_cmd->tvc_prot_sgl_count; i++) | ||
471 | put_page(sg_page(&tv_cmd->tvc_prot_sgl[i])); | ||
472 | } | ||
465 | 473 | ||
466 | tcm_vhost_put_inflight(tv_cmd->inflight); | 474 | tcm_vhost_put_inflight(tv_cmd->inflight); |
467 | percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); | 475 | percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag); |
@@ -713,16 +721,14 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work) | |||
713 | } | 721 | } |
714 | 722 | ||
715 | static struct tcm_vhost_cmd * | 723 | static struct tcm_vhost_cmd * |
716 | vhost_scsi_get_tag(struct vhost_virtqueue *vq, | 724 | vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg, |
717 | struct tcm_vhost_tpg *tpg, | 725 | unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr, |
718 | struct virtio_scsi_cmd_req *v_req, | 726 | u32 exp_data_len, int data_direction) |
719 | u32 exp_data_len, | ||
720 | int data_direction) | ||
721 | { | 727 | { |
722 | struct tcm_vhost_cmd *cmd; | 728 | struct tcm_vhost_cmd *cmd; |
723 | struct tcm_vhost_nexus *tv_nexus; | 729 | struct tcm_vhost_nexus *tv_nexus; |
724 | struct se_session *se_sess; | 730 | struct se_session *se_sess; |
725 | struct scatterlist *sg; | 731 | struct scatterlist *sg, *prot_sg; |
726 | struct page **pages; | 732 | struct page **pages; |
727 | int tag; | 733 | int tag; |
728 | 734 | ||
@@ -741,19 +747,24 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, | |||
741 | 747 | ||
742 | cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; | 748 | cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag]; |
743 | sg = cmd->tvc_sgl; | 749 | sg = cmd->tvc_sgl; |
750 | prot_sg = cmd->tvc_prot_sgl; | ||
744 | pages = cmd->tvc_upages; | 751 | pages = cmd->tvc_upages; |
745 | memset(cmd, 0, sizeof(struct tcm_vhost_cmd)); | 752 | memset(cmd, 0, sizeof(struct tcm_vhost_cmd)); |
746 | 753 | ||
747 | cmd->tvc_sgl = sg; | 754 | cmd->tvc_sgl = sg; |
755 | cmd->tvc_prot_sgl = prot_sg; | ||
748 | cmd->tvc_upages = pages; | 756 | cmd->tvc_upages = pages; |
749 | cmd->tvc_se_cmd.map_tag = tag; | 757 | cmd->tvc_se_cmd.map_tag = tag; |
750 | cmd->tvc_tag = v_req->tag; | 758 | cmd->tvc_tag = scsi_tag; |
751 | cmd->tvc_task_attr = v_req->task_attr; | 759 | cmd->tvc_lun = lun; |
760 | cmd->tvc_task_attr = task_attr; | ||
752 | cmd->tvc_exp_data_len = exp_data_len; | 761 | cmd->tvc_exp_data_len = exp_data_len; |
753 | cmd->tvc_data_direction = data_direction; | 762 | cmd->tvc_data_direction = data_direction; |
754 | cmd->tvc_nexus = tv_nexus; | 763 | cmd->tvc_nexus = tv_nexus; |
755 | cmd->inflight = tcm_vhost_get_inflight(vq); | 764 | cmd->inflight = tcm_vhost_get_inflight(vq); |
756 | 765 | ||
766 | memcpy(cmd->tvc_cdb, cdb, TCM_VHOST_MAX_CDB_SIZE); | ||
767 | |||
757 | return cmd; | 768 | return cmd; |
758 | } | 769 | } |
759 | 770 | ||
@@ -767,35 +778,28 @@ vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd, | |||
767 | struct scatterlist *sgl, | 778 | struct scatterlist *sgl, |
768 | unsigned int sgl_count, | 779 | unsigned int sgl_count, |
769 | struct iovec *iov, | 780 | struct iovec *iov, |
770 | int write) | 781 | struct page **pages, |
782 | bool write) | ||
771 | { | 783 | { |
772 | unsigned int npages = 0, pages_nr, offset, nbytes; | 784 | unsigned int npages = 0, pages_nr, offset, nbytes; |
773 | struct scatterlist *sg = sgl; | 785 | struct scatterlist *sg = sgl; |
774 | void __user *ptr = iov->iov_base; | 786 | void __user *ptr = iov->iov_base; |
775 | size_t len = iov->iov_len; | 787 | size_t len = iov->iov_len; |
776 | struct page **pages; | ||
777 | int ret, i; | 788 | int ret, i; |
778 | 789 | ||
779 | if (sgl_count > TCM_VHOST_PREALLOC_SGLS) { | ||
780 | pr_err("vhost_scsi_map_to_sgl() psgl_count: %u greater than" | ||
781 | " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n", | ||
782 | sgl_count, TCM_VHOST_PREALLOC_SGLS); | ||
783 | return -ENOBUFS; | ||
784 | } | ||
785 | |||
786 | pages_nr = iov_num_pages(iov); | 790 | pages_nr = iov_num_pages(iov); |
787 | if (pages_nr > sgl_count) | 791 | if (pages_nr > sgl_count) { |
792 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | ||
793 | " sgl_count: %u\n", pages_nr, sgl_count); | ||
788 | return -ENOBUFS; | 794 | return -ENOBUFS; |
789 | 795 | } | |
790 | if (pages_nr > TCM_VHOST_PREALLOC_PAGES) { | 796 | if (pages_nr > TCM_VHOST_PREALLOC_UPAGES) { |
791 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" | 797 | pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than" |
792 | " preallocated TCM_VHOST_PREALLOC_PAGES: %u\n", | 798 | " preallocated TCM_VHOST_PREALLOC_UPAGES: %u\n", |
793 | pages_nr, TCM_VHOST_PREALLOC_PAGES); | 799 | pages_nr, TCM_VHOST_PREALLOC_UPAGES); |
794 | return -ENOBUFS; | 800 | return -ENOBUFS; |
795 | } | 801 | } |
796 | 802 | ||
797 | pages = tv_cmd->tvc_upages; | ||
798 | |||
799 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); | 803 | ret = get_user_pages_fast((unsigned long)ptr, pages_nr, write, pages); |
800 | /* No pages were pinned */ | 804 | /* No pages were pinned */ |
801 | if (ret < 0) | 805 | if (ret < 0) |
@@ -825,33 +829,32 @@ out: | |||
825 | static int | 829 | static int |
826 | vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, | 830 | vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, |
827 | struct iovec *iov, | 831 | struct iovec *iov, |
828 | unsigned int niov, | 832 | int niov, |
829 | int write) | 833 | bool write) |
830 | { | 834 | { |
831 | int ret; | 835 | struct scatterlist *sg = cmd->tvc_sgl; |
832 | unsigned int i; | 836 | unsigned int sgl_count = 0; |
833 | u32 sgl_count; | 837 | int ret, i; |
834 | struct scatterlist *sg; | ||
835 | 838 | ||
836 | /* | ||
837 | * Find out how long sglist needs to be | ||
838 | */ | ||
839 | sgl_count = 0; | ||
840 | for (i = 0; i < niov; i++) | 839 | for (i = 0; i < niov; i++) |
841 | sgl_count += iov_num_pages(&iov[i]); | 840 | sgl_count += iov_num_pages(&iov[i]); |
842 | 841 | ||
843 | /* TODO overflow checking */ | 842 | if (sgl_count > TCM_VHOST_PREALLOC_SGLS) { |
843 | pr_err("vhost_scsi_map_iov_to_sgl() sgl_count: %u greater than" | ||
844 | " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n", | ||
845 | sgl_count, TCM_VHOST_PREALLOC_SGLS); | ||
846 | return -ENOBUFS; | ||
847 | } | ||
844 | 848 | ||
845 | sg = cmd->tvc_sgl; | ||
846 | pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count); | 849 | pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count); |
847 | sg_init_table(sg, sgl_count); | 850 | sg_init_table(sg, sgl_count); |
848 | |||
849 | cmd->tvc_sgl_count = sgl_count; | 851 | cmd->tvc_sgl_count = sgl_count; |
850 | 852 | ||
851 | pr_debug("Mapping %u iovecs for %u pages\n", niov, sgl_count); | 853 | pr_debug("Mapping iovec %p for %u pages\n", &iov[0], sgl_count); |
854 | |||
852 | for (i = 0; i < niov; i++) { | 855 | for (i = 0; i < niov; i++) { |
853 | ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i], | 856 | ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i], |
854 | write); | 857 | cmd->tvc_upages, write); |
855 | if (ret < 0) { | 858 | if (ret < 0) { |
856 | for (i = 0; i < cmd->tvc_sgl_count; i++) | 859 | for (i = 0; i < cmd->tvc_sgl_count; i++) |
857 | put_page(sg_page(&cmd->tvc_sgl[i])); | 860 | put_page(sg_page(&cmd->tvc_sgl[i])); |
@@ -859,31 +862,70 @@ vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd, | |||
859 | cmd->tvc_sgl_count = 0; | 862 | cmd->tvc_sgl_count = 0; |
860 | return ret; | 863 | return ret; |
861 | } | 864 | } |
862 | |||
863 | sg += ret; | 865 | sg += ret; |
864 | sgl_count -= ret; | 866 | sgl_count -= ret; |
865 | } | 867 | } |
866 | return 0; | 868 | return 0; |
867 | } | 869 | } |
868 | 870 | ||
871 | static int | ||
872 | vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd, | ||
873 | struct iovec *iov, | ||
874 | int niov, | ||
875 | bool write) | ||
876 | { | ||
877 | struct scatterlist *prot_sg = cmd->tvc_prot_sgl; | ||
878 | unsigned int prot_sgl_count = 0; | ||
879 | int ret, i; | ||
880 | |||
881 | for (i = 0; i < niov; i++) | ||
882 | prot_sgl_count += iov_num_pages(&iov[i]); | ||
883 | |||
884 | if (prot_sgl_count > TCM_VHOST_PREALLOC_PROT_SGLS) { | ||
885 | pr_err("vhost_scsi_map_iov_to_prot() sgl_count: %u greater than" | ||
886 | " preallocated TCM_VHOST_PREALLOC_PROT_SGLS: %u\n", | ||
887 | prot_sgl_count, TCM_VHOST_PREALLOC_PROT_SGLS); | ||
888 | return -ENOBUFS; | ||
889 | } | ||
890 | |||
891 | pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__, | ||
892 | prot_sg, prot_sgl_count); | ||
893 | sg_init_table(prot_sg, prot_sgl_count); | ||
894 | cmd->tvc_prot_sgl_count = prot_sgl_count; | ||
895 | |||
896 | for (i = 0; i < niov; i++) { | ||
897 | ret = vhost_scsi_map_to_sgl(cmd, prot_sg, prot_sgl_count, &iov[i], | ||
898 | cmd->tvc_upages, write); | ||
899 | if (ret < 0) { | ||
900 | for (i = 0; i < cmd->tvc_prot_sgl_count; i++) | ||
901 | put_page(sg_page(&cmd->tvc_prot_sgl[i])); | ||
902 | |||
903 | cmd->tvc_prot_sgl_count = 0; | ||
904 | return ret; | ||
905 | } | ||
906 | prot_sg += ret; | ||
907 | prot_sgl_count -= ret; | ||
908 | } | ||
909 | return 0; | ||
910 | } | ||
911 | |||
869 | static void tcm_vhost_submission_work(struct work_struct *work) | 912 | static void tcm_vhost_submission_work(struct work_struct *work) |
870 | { | 913 | { |
871 | struct tcm_vhost_cmd *cmd = | 914 | struct tcm_vhost_cmd *cmd = |
872 | container_of(work, struct tcm_vhost_cmd, work); | 915 | container_of(work, struct tcm_vhost_cmd, work); |
873 | struct tcm_vhost_nexus *tv_nexus; | 916 | struct tcm_vhost_nexus *tv_nexus; |
874 | struct se_cmd *se_cmd = &cmd->tvc_se_cmd; | 917 | struct se_cmd *se_cmd = &cmd->tvc_se_cmd; |
875 | struct scatterlist *sg_ptr, *sg_bidi_ptr = NULL; | 918 | struct scatterlist *sg_ptr, *sg_prot_ptr = NULL; |
876 | int rc, sg_no_bidi = 0; | 919 | int rc; |
877 | 920 | ||
921 | /* FIXME: BIDI operation */ | ||
878 | if (cmd->tvc_sgl_count) { | 922 | if (cmd->tvc_sgl_count) { |
879 | sg_ptr = cmd->tvc_sgl; | 923 | sg_ptr = cmd->tvc_sgl; |
880 | /* FIXME: Fix BIDI operation in tcm_vhost_submission_work() */ | 924 | |
881 | #if 0 | 925 | if (cmd->tvc_prot_sgl_count) |
882 | if (se_cmd->se_cmd_flags & SCF_BIDI) { | 926 | sg_prot_ptr = cmd->tvc_prot_sgl; |
883 | sg_bidi_ptr = NULL; | 927 | else |
884 | sg_no_bidi = 0; | 928 | se_cmd->prot_pto = true; |
885 | } | ||
886 | #endif | ||
887 | } else { | 929 | } else { |
888 | sg_ptr = NULL; | 930 | sg_ptr = NULL; |
889 | } | 931 | } |
@@ -894,7 +936,7 @@ static void tcm_vhost_submission_work(struct work_struct *work) | |||
894 | cmd->tvc_lun, cmd->tvc_exp_data_len, | 936 | cmd->tvc_lun, cmd->tvc_exp_data_len, |
895 | cmd->tvc_task_attr, cmd->tvc_data_direction, | 937 | cmd->tvc_task_attr, cmd->tvc_data_direction, |
896 | TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count, | 938 | TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count, |
897 | sg_bidi_ptr, sg_no_bidi, NULL, 0); | 939 | NULL, 0, sg_prot_ptr, cmd->tvc_prot_sgl_count); |
898 | if (rc < 0) { | 940 | if (rc < 0) { |
899 | transport_send_check_condition_and_sense(se_cmd, | 941 | transport_send_check_condition_and_sense(se_cmd, |
900 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); | 942 | TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0); |
@@ -926,12 +968,18 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
926 | { | 968 | { |
927 | struct tcm_vhost_tpg **vs_tpg; | 969 | struct tcm_vhost_tpg **vs_tpg; |
928 | struct virtio_scsi_cmd_req v_req; | 970 | struct virtio_scsi_cmd_req v_req; |
971 | struct virtio_scsi_cmd_req_pi v_req_pi; | ||
929 | struct tcm_vhost_tpg *tpg; | 972 | struct tcm_vhost_tpg *tpg; |
930 | struct tcm_vhost_cmd *cmd; | 973 | struct tcm_vhost_cmd *cmd; |
931 | u32 exp_data_len, data_first, data_num, data_direction; | 974 | u64 tag; |
975 | u32 exp_data_len, data_first, data_num, data_direction, prot_first; | ||
932 | unsigned out, in, i; | 976 | unsigned out, in, i; |
933 | int head, ret; | 977 | int head, ret, data_niov, prot_niov, prot_bytes; |
934 | u8 target; | 978 | size_t req_size; |
979 | u16 lun; | ||
980 | u8 *target, *lunp, task_attr; | ||
981 | bool hdr_pi; | ||
982 | void *req, *cdb; | ||
935 | 983 | ||
936 | mutex_lock(&vq->mutex); | 984 | mutex_lock(&vq->mutex); |
937 | /* | 985 | /* |
@@ -962,7 +1010,7 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
962 | break; | 1010 | break; |
963 | } | 1011 | } |
964 | 1012 | ||
965 | /* FIXME: BIDI operation */ | 1013 | /* FIXME: BIDI operation */ |
966 | if (out == 1 && in == 1) { | 1014 | if (out == 1 && in == 1) { |
967 | data_direction = DMA_NONE; | 1015 | data_direction = DMA_NONE; |
968 | data_first = 0; | 1016 | data_first = 0; |
@@ -992,29 +1040,38 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
992 | break; | 1040 | break; |
993 | } | 1041 | } |
994 | 1042 | ||
995 | if (unlikely(vq->iov[0].iov_len != sizeof(v_req))) { | 1043 | if (vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI)) { |
996 | vq_err(vq, "Expecting virtio_scsi_cmd_req, got %zu" | 1044 | req = &v_req_pi; |
997 | " bytes\n", vq->iov[0].iov_len); | 1045 | lunp = &v_req_pi.lun[0]; |
1046 | target = &v_req_pi.lun[1]; | ||
1047 | req_size = sizeof(v_req_pi); | ||
1048 | hdr_pi = true; | ||
1049 | } else { | ||
1050 | req = &v_req; | ||
1051 | lunp = &v_req.lun[0]; | ||
1052 | target = &v_req.lun[1]; | ||
1053 | req_size = sizeof(v_req); | ||
1054 | hdr_pi = false; | ||
1055 | } | ||
1056 | |||
1057 | if (unlikely(vq->iov[0].iov_len < req_size)) { | ||
1058 | pr_err("Expecting virtio-scsi header: %zu, got %zu\n", | ||
1059 | req_size, vq->iov[0].iov_len); | ||
998 | break; | 1060 | break; |
999 | } | 1061 | } |
1000 | pr_debug("Calling __copy_from_user: vq->iov[0].iov_base: %p," | 1062 | ret = memcpy_fromiovecend(req, &vq->iov[0], 0, req_size); |
1001 | " len: %zu\n", vq->iov[0].iov_base, sizeof(v_req)); | ||
1002 | ret = __copy_from_user(&v_req, vq->iov[0].iov_base, | ||
1003 | sizeof(v_req)); | ||
1004 | if (unlikely(ret)) { | 1063 | if (unlikely(ret)) { |
1005 | vq_err(vq, "Faulted on virtio_scsi_cmd_req\n"); | 1064 | vq_err(vq, "Faulted on virtio_scsi_cmd_req\n"); |
1006 | break; | 1065 | break; |
1007 | } | 1066 | } |
1008 | 1067 | ||
1009 | /* virtio-scsi spec requires byte 0 of the lun to be 1 */ | 1068 | /* virtio-scsi spec requires byte 0 of the lun to be 1 */ |
1010 | if (unlikely(v_req.lun[0] != 1)) { | 1069 | if (unlikely(*lunp != 1)) { |
1011 | vhost_scsi_send_bad_target(vs, vq, head, out); | 1070 | vhost_scsi_send_bad_target(vs, vq, head, out); |
1012 | continue; | 1071 | continue; |
1013 | } | 1072 | } |
1014 | 1073 | ||
1015 | /* Extract the tpgt */ | 1074 | tpg = ACCESS_ONCE(vs_tpg[*target]); |
1016 | target = v_req.lun[1]; | ||
1017 | tpg = ACCESS_ONCE(vs_tpg[target]); | ||
1018 | 1075 | ||
1019 | /* Target does not exist, fail the request */ | 1076 | /* Target does not exist, fail the request */ |
1020 | if (unlikely(!tpg)) { | 1077 | if (unlikely(!tpg)) { |
@@ -1022,17 +1079,79 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
1022 | continue; | 1079 | continue; |
1023 | } | 1080 | } |
1024 | 1081 | ||
1082 | data_niov = data_num; | ||
1083 | prot_niov = prot_first = prot_bytes = 0; | ||
1084 | /* | ||
1085 | * Determine if any protection information iovecs are preceeding | ||
1086 | * the actual data payload, and adjust data_first + data_niov | ||
1087 | * values accordingly for vhost_scsi_map_iov_to_sgl() below. | ||
1088 | * | ||
1089 | * Also extract virtio_scsi header bits for vhost_scsi_get_tag() | ||
1090 | */ | ||
1091 | if (hdr_pi) { | ||
1092 | if (v_req_pi.pi_bytesout) { | ||
1093 | if (data_direction != DMA_TO_DEVICE) { | ||
1094 | vq_err(vq, "Received non zero do_pi_niov" | ||
1095 | ", but wrong data_direction\n"); | ||
1096 | goto err_cmd; | ||
1097 | } | ||
1098 | prot_bytes = v_req_pi.pi_bytesout; | ||
1099 | } else if (v_req_pi.pi_bytesin) { | ||
1100 | if (data_direction != DMA_FROM_DEVICE) { | ||
1101 | vq_err(vq, "Received non zero di_pi_niov" | ||
1102 | ", but wrong data_direction\n"); | ||
1103 | goto err_cmd; | ||
1104 | } | ||
1105 | prot_bytes = v_req_pi.pi_bytesin; | ||
1106 | } | ||
1107 | if (prot_bytes) { | ||
1108 | int tmp = 0; | ||
1109 | |||
1110 | for (i = 0; i < data_num; i++) { | ||
1111 | tmp += vq->iov[data_first + i].iov_len; | ||
1112 | prot_niov++; | ||
1113 | if (tmp >= prot_bytes) | ||
1114 | break; | ||
1115 | } | ||
1116 | prot_first = data_first; | ||
1117 | data_first += prot_niov; | ||
1118 | data_niov = data_num - prot_niov; | ||
1119 | } | ||
1120 | tag = v_req_pi.tag; | ||
1121 | task_attr = v_req_pi.task_attr; | ||
1122 | cdb = &v_req_pi.cdb[0]; | ||
1123 | lun = ((v_req_pi.lun[2] << 8) | v_req_pi.lun[3]) & 0x3FFF; | ||
1124 | } else { | ||
1125 | tag = v_req.tag; | ||
1126 | task_attr = v_req.task_attr; | ||
1127 | cdb = &v_req.cdb[0]; | ||
1128 | lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF; | ||
1129 | } | ||
1025 | exp_data_len = 0; | 1130 | exp_data_len = 0; |
1026 | for (i = 0; i < data_num; i++) | 1131 | for (i = 0; i < data_niov; i++) |
1027 | exp_data_len += vq->iov[data_first + i].iov_len; | 1132 | exp_data_len += vq->iov[data_first + i].iov_len; |
1133 | /* | ||
1134 | * Check that the recieved CDB size does not exceeded our | ||
1135 | * hardcoded max for vhost-scsi | ||
1136 | * | ||
1137 | * TODO what if cdb was too small for varlen cdb header? | ||
1138 | */ | ||
1139 | if (unlikely(scsi_command_size(cdb) > TCM_VHOST_MAX_CDB_SIZE)) { | ||
1140 | vq_err(vq, "Received SCSI CDB with command_size: %d that" | ||
1141 | " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", | ||
1142 | scsi_command_size(cdb), TCM_VHOST_MAX_CDB_SIZE); | ||
1143 | goto err_cmd; | ||
1144 | } | ||
1028 | 1145 | ||
1029 | cmd = vhost_scsi_get_tag(vq, tpg, &v_req, | 1146 | cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr, |
1030 | exp_data_len, data_direction); | 1147 | exp_data_len + prot_bytes, |
1148 | data_direction); | ||
1031 | if (IS_ERR(cmd)) { | 1149 | if (IS_ERR(cmd)) { |
1032 | vq_err(vq, "vhost_scsi_get_tag failed %ld\n", | 1150 | vq_err(vq, "vhost_scsi_get_tag failed %ld\n", |
1033 | PTR_ERR(cmd)); | 1151 | PTR_ERR(cmd)); |
1034 | goto err_cmd; | 1152 | goto err_cmd; |
1035 | } | 1153 | } |
1154 | |||
1036 | pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction" | 1155 | pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction" |
1037 | ": %d\n", cmd, exp_data_len, data_direction); | 1156 | ": %d\n", cmd, exp_data_len, data_direction); |
1038 | 1157 | ||
@@ -1040,40 +1159,28 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq) | |||
1040 | cmd->tvc_vq = vq; | 1159 | cmd->tvc_vq = vq; |
1041 | cmd->tvc_resp = vq->iov[out].iov_base; | 1160 | cmd->tvc_resp = vq->iov[out].iov_base; |
1042 | 1161 | ||
1043 | /* | ||
1044 | * Copy in the recieved CDB descriptor into cmd->tvc_cdb | ||
1045 | * that will be used by tcm_vhost_new_cmd_map() and down into | ||
1046 | * target_setup_cmd_from_cdb() | ||
1047 | */ | ||
1048 | memcpy(cmd->tvc_cdb, v_req.cdb, TCM_VHOST_MAX_CDB_SIZE); | ||
1049 | /* | ||
1050 | * Check that the recieved CDB size does not exceeded our | ||
1051 | * hardcoded max for tcm_vhost | ||
1052 | */ | ||
1053 | /* TODO what if cdb was too small for varlen cdb header? */ | ||
1054 | if (unlikely(scsi_command_size(cmd->tvc_cdb) > | ||
1055 | TCM_VHOST_MAX_CDB_SIZE)) { | ||
1056 | vq_err(vq, "Received SCSI CDB with command_size: %d that" | ||
1057 | " exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n", | ||
1058 | scsi_command_size(cmd->tvc_cdb), | ||
1059 | TCM_VHOST_MAX_CDB_SIZE); | ||
1060 | goto err_free; | ||
1061 | } | ||
1062 | cmd->tvc_lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF; | ||
1063 | |||
1064 | pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n", | 1162 | pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n", |
1065 | cmd->tvc_cdb[0], cmd->tvc_lun); | 1163 | cmd->tvc_cdb[0], cmd->tvc_lun); |
1066 | 1164 | ||
1165 | if (prot_niov) { | ||
1166 | ret = vhost_scsi_map_iov_to_prot(cmd, | ||
1167 | &vq->iov[prot_first], prot_niov, | ||
1168 | data_direction == DMA_FROM_DEVICE); | ||
1169 | if (unlikely(ret)) { | ||
1170 | vq_err(vq, "Failed to map iov to" | ||
1171 | " prot_sgl\n"); | ||
1172 | goto err_free; | ||
1173 | } | ||
1174 | } | ||
1067 | if (data_direction != DMA_NONE) { | 1175 | if (data_direction != DMA_NONE) { |
1068 | ret = vhost_scsi_map_iov_to_sgl(cmd, | 1176 | ret = vhost_scsi_map_iov_to_sgl(cmd, |
1069 | &vq->iov[data_first], data_num, | 1177 | &vq->iov[data_first], data_niov, |
1070 | data_direction == DMA_FROM_DEVICE); | 1178 | data_direction == DMA_FROM_DEVICE); |
1071 | if (unlikely(ret)) { | 1179 | if (unlikely(ret)) { |
1072 | vq_err(vq, "Failed to map iov to sgl\n"); | 1180 | vq_err(vq, "Failed to map iov to sgl\n"); |
1073 | goto err_free; | 1181 | goto err_free; |
1074 | } | 1182 | } |
1075 | } | 1183 | } |
1076 | |||
1077 | /* | 1184 | /* |
1078 | * Save the descriptor from vhost_get_vq_desc() to be used to | 1185 | * Save the descriptor from vhost_get_vq_desc() to be used to |
1079 | * complete the virtio-scsi request in TCM callback context via | 1186 | * complete the virtio-scsi request in TCM callback context via |
@@ -1716,6 +1823,7 @@ static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus, | |||
1716 | tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i]; | 1823 | tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i]; |
1717 | 1824 | ||
1718 | kfree(tv_cmd->tvc_sgl); | 1825 | kfree(tv_cmd->tvc_sgl); |
1826 | kfree(tv_cmd->tvc_prot_sgl); | ||
1719 | kfree(tv_cmd->tvc_upages); | 1827 | kfree(tv_cmd->tvc_upages); |
1720 | } | 1828 | } |
1721 | } | 1829 | } |
@@ -1750,7 +1858,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg, | |||
1750 | tv_nexus->tvn_se_sess = transport_init_session_tags( | 1858 | tv_nexus->tvn_se_sess = transport_init_session_tags( |
1751 | TCM_VHOST_DEFAULT_TAGS, | 1859 | TCM_VHOST_DEFAULT_TAGS, |
1752 | sizeof(struct tcm_vhost_cmd), | 1860 | sizeof(struct tcm_vhost_cmd), |
1753 | TARGET_PROT_NORMAL); | 1861 | TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS); |
1754 | if (IS_ERR(tv_nexus->tvn_se_sess)) { | 1862 | if (IS_ERR(tv_nexus->tvn_se_sess)) { |
1755 | mutex_unlock(&tpg->tv_tpg_mutex); | 1863 | mutex_unlock(&tpg->tv_tpg_mutex); |
1756 | kfree(tv_nexus); | 1864 | kfree(tv_nexus); |
@@ -1769,12 +1877,20 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg, | |||
1769 | } | 1877 | } |
1770 | 1878 | ||
1771 | tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * | 1879 | tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) * |
1772 | TCM_VHOST_PREALLOC_PAGES, GFP_KERNEL); | 1880 | TCM_VHOST_PREALLOC_UPAGES, GFP_KERNEL); |
1773 | if (!tv_cmd->tvc_upages) { | 1881 | if (!tv_cmd->tvc_upages) { |
1774 | mutex_unlock(&tpg->tv_tpg_mutex); | 1882 | mutex_unlock(&tpg->tv_tpg_mutex); |
1775 | pr_err("Unable to allocate tv_cmd->tvc_upages\n"); | 1883 | pr_err("Unable to allocate tv_cmd->tvc_upages\n"); |
1776 | goto out; | 1884 | goto out; |
1777 | } | 1885 | } |
1886 | |||
1887 | tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) * | ||
1888 | TCM_VHOST_PREALLOC_PROT_SGLS, GFP_KERNEL); | ||
1889 | if (!tv_cmd->tvc_prot_sgl) { | ||
1890 | mutex_unlock(&tpg->tv_tpg_mutex); | ||
1891 | pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n"); | ||
1892 | goto out; | ||
1893 | } | ||
1778 | } | 1894 | } |
1779 | /* | 1895 | /* |
1780 | * Since we are running in 'demo mode' this call with generate a | 1896 | * Since we are running in 'demo mode' this call with generate a |