diff options
author | Andy Grover <agrover@redhat.com> | 2015-05-19 17:44:40 -0400 |
---|---|---|
committer | Nicholas Bellinger <nab@linux-iscsi.org> | 2015-05-30 22:57:59 -0400 |
commit | 7bfea53b5c936d706d0bf60ec218fa72cde77121 (patch) | |
tree | 1bed6667ac527acab7c2b2fb72e2bb1aa7b4cca5 | |
parent | 9c1cd1b68cd15c81d12a0cf2402129475882b620 (diff) |
target: Move passthrough CDB parsing into a common function
Aside from whether they handle BIDI ops or not, parsing of the CDB by
kernel and user SCSI passthrough modules should be identical. Move this
into a new passthrough_parse_cdb() and call it from tcm-pscsi and tcm-user.
Reported-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Ilias Tsitsimpis <iliastsi@arrikto.com>
Signed-off-by: Andy Grover <agrover@redhat.com>
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>
-rw-r--r-- | drivers/target/target_core_device.c | 74 | ||||
-rw-r--r-- | drivers/target/target_core_pscsi.c | 53 | ||||
-rw-r--r-- | drivers/target/target_core_user.c | 43 | ||||
-rw-r--r-- | include/target/target_core_backend.h | 2 |
4 files changed, 78 insertions, 94 deletions
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c index 7faa6aef9a4d..56b20dc54087 100644 --- a/drivers/target/target_core_device.c +++ b/drivers/target/target_core_device.c | |||
@@ -33,6 +33,7 @@ | |||
33 | #include <linux/kthread.h> | 33 | #include <linux/kthread.h> |
34 | #include <linux/in.h> | 34 | #include <linux/in.h> |
35 | #include <linux/export.h> | 35 | #include <linux/export.h> |
36 | #include <asm/unaligned.h> | ||
36 | #include <net/sock.h> | 37 | #include <net/sock.h> |
37 | #include <net/tcp.h> | 38 | #include <net/tcp.h> |
38 | #include <scsi/scsi.h> | 39 | #include <scsi/scsi.h> |
@@ -1707,3 +1708,76 @@ void core_dev_release_virtual_lun0(void) | |||
1707 | target_free_device(g_lun0_dev); | 1708 | target_free_device(g_lun0_dev); |
1708 | core_delete_hba(hba); | 1709 | core_delete_hba(hba); |
1709 | } | 1710 | } |
1711 | |||
1712 | /* | ||
1713 | * Common CDB parsing for kernel and user passthrough. | ||
1714 | */ | ||
1715 | sense_reason_t | ||
1716 | passthrough_parse_cdb(struct se_cmd *cmd, | ||
1717 | sense_reason_t (*exec_cmd)(struct se_cmd *cmd)) | ||
1718 | { | ||
1719 | unsigned char *cdb = cmd->t_task_cdb; | ||
1720 | |||
1721 | /* | ||
1722 | * Clear a lun set in the cdb if the initiator talking to use spoke | ||
1723 | * and old standards version, as we can't assume the underlying device | ||
1724 | * won't choke up on it. | ||
1725 | */ | ||
1726 | switch (cdb[0]) { | ||
1727 | case READ_10: /* SBC - RDProtect */ | ||
1728 | case READ_12: /* SBC - RDProtect */ | ||
1729 | case READ_16: /* SBC - RDProtect */ | ||
1730 | case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ | ||
1731 | case VERIFY: /* SBC - VRProtect */ | ||
1732 | case VERIFY_16: /* SBC - VRProtect */ | ||
1733 | case WRITE_VERIFY: /* SBC - VRProtect */ | ||
1734 | case WRITE_VERIFY_12: /* SBC - VRProtect */ | ||
1735 | case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ | ||
1736 | break; | ||
1737 | default: | ||
1738 | cdb[1] &= 0x1f; /* clear logical unit number */ | ||
1739 | break; | ||
1740 | } | ||
1741 | |||
1742 | /* | ||
1743 | * For REPORT LUNS we always need to emulate the response, for everything | ||
1744 | * else, pass it up. | ||
1745 | */ | ||
1746 | if (cdb[0] == REPORT_LUNS) { | ||
1747 | cmd->execute_cmd = spc_emulate_report_luns; | ||
1748 | return TCM_NO_SENSE; | ||
1749 | } | ||
1750 | |||
1751 | /* Set DATA_CDB flag for ops that should have it */ | ||
1752 | switch (cdb[0]) { | ||
1753 | case READ_6: | ||
1754 | case READ_10: | ||
1755 | case READ_12: | ||
1756 | case READ_16: | ||
1757 | case WRITE_6: | ||
1758 | case WRITE_10: | ||
1759 | case WRITE_12: | ||
1760 | case WRITE_16: | ||
1761 | case WRITE_VERIFY: | ||
1762 | case WRITE_VERIFY_12: | ||
1763 | case 0x8e: /* WRITE_VERIFY_16 */ | ||
1764 | case COMPARE_AND_WRITE: | ||
1765 | case XDWRITEREAD_10: | ||
1766 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | ||
1767 | break; | ||
1768 | case VARIABLE_LENGTH_CMD: | ||
1769 | switch (get_unaligned_be16(&cdb[8])) { | ||
1770 | case READ_32: | ||
1771 | case WRITE_32: | ||
1772 | case 0x0c: /* WRITE_VERIFY_32 */ | ||
1773 | case XDWRITEREAD_32: | ||
1774 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | ||
1775 | break; | ||
1776 | } | ||
1777 | } | ||
1778 | |||
1779 | cmd->execute_cmd = exec_cmd; | ||
1780 | |||
1781 | return TCM_NO_SENSE; | ||
1782 | } | ||
1783 | EXPORT_SYMBOL(passthrough_parse_cdb); | ||
diff --git a/drivers/target/target_core_pscsi.c b/drivers/target/target_core_pscsi.c index 4073869d2090..53bd0eb57095 100644 --- a/drivers/target/target_core_pscsi.c +++ b/drivers/target/target_core_pscsi.c | |||
@@ -973,64 +973,13 @@ fail: | |||
973 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; | 973 | return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE; |
974 | } | 974 | } |
975 | 975 | ||
976 | /* | ||
977 | * Clear a lun set in the cdb if the initiator talking to use spoke | ||
978 | * and old standards version, as we can't assume the underlying device | ||
979 | * won't choke up on it. | ||
980 | */ | ||
981 | static inline void pscsi_clear_cdb_lun(unsigned char *cdb) | ||
982 | { | ||
983 | switch (cdb[0]) { | ||
984 | case READ_10: /* SBC - RDProtect */ | ||
985 | case READ_12: /* SBC - RDProtect */ | ||
986 | case READ_16: /* SBC - RDProtect */ | ||
987 | case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */ | ||
988 | case VERIFY: /* SBC - VRProtect */ | ||
989 | case VERIFY_16: /* SBC - VRProtect */ | ||
990 | case WRITE_VERIFY: /* SBC - VRProtect */ | ||
991 | case WRITE_VERIFY_12: /* SBC - VRProtect */ | ||
992 | case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */ | ||
993 | break; | ||
994 | default: | ||
995 | cdb[1] &= 0x1f; /* clear logical unit number */ | ||
996 | break; | ||
997 | } | ||
998 | } | ||
999 | |||
1000 | static sense_reason_t | 976 | static sense_reason_t |
1001 | pscsi_parse_cdb(struct se_cmd *cmd) | 977 | pscsi_parse_cdb(struct se_cmd *cmd) |
1002 | { | 978 | { |
1003 | unsigned char *cdb = cmd->t_task_cdb; | ||
1004 | |||
1005 | if (cmd->se_cmd_flags & SCF_BIDI) | 979 | if (cmd->se_cmd_flags & SCF_BIDI) |
1006 | return TCM_UNSUPPORTED_SCSI_OPCODE; | 980 | return TCM_UNSUPPORTED_SCSI_OPCODE; |
1007 | 981 | ||
1008 | pscsi_clear_cdb_lun(cdb); | 982 | return passthrough_parse_cdb(cmd, pscsi_execute_cmd); |
1009 | |||
1010 | /* | ||
1011 | * For REPORT LUNS we always need to emulate the response, for everything | ||
1012 | * else the default for pSCSI is to pass the command to the underlying | ||
1013 | * LLD / physical hardware. | ||
1014 | */ | ||
1015 | switch (cdb[0]) { | ||
1016 | case REPORT_LUNS: | ||
1017 | cmd->execute_cmd = spc_emulate_report_luns; | ||
1018 | return 0; | ||
1019 | case READ_6: | ||
1020 | case READ_10: | ||
1021 | case READ_12: | ||
1022 | case READ_16: | ||
1023 | case WRITE_6: | ||
1024 | case WRITE_10: | ||
1025 | case WRITE_12: | ||
1026 | case WRITE_16: | ||
1027 | case WRITE_VERIFY: | ||
1028 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | ||
1029 | /* FALLTHROUGH*/ | ||
1030 | default: | ||
1031 | cmd->execute_cmd = pscsi_execute_cmd; | ||
1032 | return 0; | ||
1033 | } | ||
1034 | } | 983 | } |
1035 | 984 | ||
1036 | static sense_reason_t | 985 | static sense_reason_t |
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c index 90e084ea7b92..2768ea2cfd7a 100644 --- a/drivers/target/target_core_user.c +++ b/drivers/target/target_core_user.c | |||
@@ -1049,48 +1049,7 @@ tcmu_pass_op(struct se_cmd *se_cmd) | |||
1049 | static sense_reason_t | 1049 | static sense_reason_t |
1050 | tcmu_parse_cdb(struct se_cmd *cmd) | 1050 | tcmu_parse_cdb(struct se_cmd *cmd) |
1051 | { | 1051 | { |
1052 | unsigned char *cdb = cmd->t_task_cdb; | 1052 | return passthrough_parse_cdb(cmd, tcmu_pass_op); |
1053 | |||
1054 | /* | ||
1055 | * For REPORT LUNS we always need to emulate the response, for everything | ||
1056 | * else, pass it up. | ||
1057 | */ | ||
1058 | if (cdb[0] == REPORT_LUNS) { | ||
1059 | cmd->execute_cmd = spc_emulate_report_luns; | ||
1060 | return TCM_NO_SENSE; | ||
1061 | } | ||
1062 | |||
1063 | /* Set DATA_CDB flag for ops that should have it */ | ||
1064 | switch (cdb[0]) { | ||
1065 | case READ_6: | ||
1066 | case READ_10: | ||
1067 | case READ_12: | ||
1068 | case READ_16: | ||
1069 | case WRITE_6: | ||
1070 | case WRITE_10: | ||
1071 | case WRITE_12: | ||
1072 | case WRITE_16: | ||
1073 | case WRITE_VERIFY: | ||
1074 | case WRITE_VERIFY_12: | ||
1075 | case 0x8e: /* WRITE_VERIFY_16 */ | ||
1076 | case COMPARE_AND_WRITE: | ||
1077 | case XDWRITEREAD_10: | ||
1078 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | ||
1079 | break; | ||
1080 | case VARIABLE_LENGTH_CMD: | ||
1081 | switch (get_unaligned_be16(&cdb[8])) { | ||
1082 | case READ_32: | ||
1083 | case WRITE_32: | ||
1084 | case 0x0c: /* WRITE_VERIFY_32 */ | ||
1085 | case XDWRITEREAD_32: | ||
1086 | cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB; | ||
1087 | break; | ||
1088 | } | ||
1089 | } | ||
1090 | |||
1091 | cmd->execute_cmd = tcmu_pass_op; | ||
1092 | |||
1093 | return TCM_NO_SENSE; | ||
1094 | } | 1053 | } |
1095 | 1054 | ||
1096 | DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type); | 1055 | DEF_TB_DEV_ATTRIB_RO(tcmu, hw_pi_prot_type); |
diff --git a/include/target/target_core_backend.h b/include/target/target_core_backend.h index d61be7297b2c..563e11970152 100644 --- a/include/target/target_core_backend.h +++ b/include/target/target_core_backend.h | |||
@@ -138,5 +138,7 @@ int se_dev_set_queue_depth(struct se_device *, u32); | |||
138 | int se_dev_set_max_sectors(struct se_device *, u32); | 138 | int se_dev_set_max_sectors(struct se_device *, u32); |
139 | int se_dev_set_optimal_sectors(struct se_device *, u32); | 139 | int se_dev_set_optimal_sectors(struct se_device *, u32); |
140 | int se_dev_set_block_size(struct se_device *, u32); | 140 | int se_dev_set_block_size(struct se_device *, u32); |
141 | sense_reason_t passthrough_parse_cdb(struct se_cmd *cmd, | ||
142 | sense_reason_t (*exec_cmd)(struct se_cmd *cmd)); | ||
141 | 143 | ||
142 | #endif /* TARGET_CORE_BACKEND_H */ | 144 | #endif /* TARGET_CORE_BACKEND_H */ |