|
@@ -33,6 +33,7 @@
|
|
#include <linux/kthread.h>
|
|
#include <linux/kthread.h>
|
|
#include <linux/in.h>
|
|
#include <linux/in.h>
|
|
#include <linux/export.h>
|
|
#include <linux/export.h>
|
|
|
|
+#include <asm/unaligned.h>
|
|
#include <net/sock.h>
|
|
#include <net/sock.h>
|
|
#include <net/tcp.h>
|
|
#include <net/tcp.h>
|
|
#include <scsi/scsi.h>
|
|
#include <scsi/scsi.h>
|
|
@@ -1707,3 +1708,76 @@ void core_dev_release_virtual_lun0(void)
|
|
target_free_device(g_lun0_dev);
|
|
target_free_device(g_lun0_dev);
|
|
core_delete_hba(hba);
|
|
core_delete_hba(hba);
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+/*
|
|
|
|
+ * Common CDB parsing for kernel and user passthrough.
|
|
|
|
+ */
|
|
|
|
+sense_reason_t
|
|
|
|
+passthrough_parse_cdb(struct se_cmd *cmd,
|
|
|
|
+ sense_reason_t (*exec_cmd)(struct se_cmd *cmd))
|
|
|
|
+{
|
|
|
|
+ unsigned char *cdb = cmd->t_task_cdb;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * Clear a lun set in the cdb if the initiator talking to use spoke
|
|
|
|
+ * and old standards version, as we can't assume the underlying device
|
|
|
|
+ * won't choke up on it.
|
|
|
|
+ */
|
|
|
|
+ switch (cdb[0]) {
|
|
|
|
+ case READ_10: /* SBC - RDProtect */
|
|
|
|
+ case READ_12: /* SBC - RDProtect */
|
|
|
|
+ case READ_16: /* SBC - RDProtect */
|
|
|
|
+ case SEND_DIAGNOSTIC: /* SPC - SELF-TEST Code */
|
|
|
|
+ case VERIFY: /* SBC - VRProtect */
|
|
|
|
+ case VERIFY_16: /* SBC - VRProtect */
|
|
|
|
+ case WRITE_VERIFY: /* SBC - VRProtect */
|
|
|
|
+ case WRITE_VERIFY_12: /* SBC - VRProtect */
|
|
|
|
+ case MAINTENANCE_IN: /* SPC - Parameter Data Format for SA RTPG */
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ cdb[1] &= 0x1f; /* clear logical unit number */
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * For REPORT LUNS we always need to emulate the response, for everything
|
|
|
|
+ * else, pass it up.
|
|
|
|
+ */
|
|
|
|
+ if (cdb[0] == REPORT_LUNS) {
|
|
|
|
+ cmd->execute_cmd = spc_emulate_report_luns;
|
|
|
|
+ return TCM_NO_SENSE;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /* Set DATA_CDB flag for ops that should have it */
|
|
|
|
+ switch (cdb[0]) {
|
|
|
|
+ case READ_6:
|
|
|
|
+ case READ_10:
|
|
|
|
+ case READ_12:
|
|
|
|
+ case READ_16:
|
|
|
|
+ case WRITE_6:
|
|
|
|
+ case WRITE_10:
|
|
|
|
+ case WRITE_12:
|
|
|
|
+ case WRITE_16:
|
|
|
|
+ case WRITE_VERIFY:
|
|
|
|
+ case WRITE_VERIFY_12:
|
|
|
|
+ case 0x8e: /* WRITE_VERIFY_16 */
|
|
|
|
+ case COMPARE_AND_WRITE:
|
|
|
|
+ case XDWRITEREAD_10:
|
|
|
|
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
|
|
|
|
+ break;
|
|
|
|
+ case VARIABLE_LENGTH_CMD:
|
|
|
|
+ switch (get_unaligned_be16(&cdb[8])) {
|
|
|
|
+ case READ_32:
|
|
|
|
+ case WRITE_32:
|
|
|
|
+ case 0x0c: /* WRITE_VERIFY_32 */
|
|
|
|
+ case XDWRITEREAD_32:
|
|
|
|
+ cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ cmd->execute_cmd = exec_cmd;
|
|
|
|
+
|
|
|
|
+ return TCM_NO_SENSE;
|
|
|
|
+}
|
|
|
|
+EXPORT_SYMBOL(passthrough_parse_cdb);
|