scsi: target: add emulate_pr backstore attr to toggle PR support
authorDavid Disseldorp <ddiss@suse.de>
Wed, 7 Nov 2018 13:11:07 +0000 (14:11 +0100)
committerMartin K. Petersen <martin.petersen@oracle.com>
Thu, 22 Nov 2018 03:10:36 +0000 (22:10 -0500)
The new emulate_pr backstore attribute allows for Persistent Reservation
and SCSI2 RESERVE/RELEASE support to be completely disabled. This can be
useful for scenarios such as:

- Ensuring ATS (Compare & Write) usage on recent VMware ESXi initiators.

- Allowing clustered (e.g. tcm-user) backends to block such requests,
  avoiding the multi-node reservation state propagation.

When explicitly disabled, PR and RESERVE/RELEASE requests receive Invalid
Command Operation Code response sense data.

Signed-off-by: David Disseldorp <ddiss@suse.de>
Reviewed-by: Mike Christie <mchristi@redhat.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_pr.c
drivers/target/target_core_spc.c
include/target/target_core_base.h

index f6b1549f4142257e46b1399abde86665e76c887b..70b9f6755c36aff1cb78732209058334875e214c 100644 (file)
@@ -532,6 +532,7 @@ DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpu);
 DEF_CONFIGFS_ATTRIB_SHOW(emulate_tpws);
 DEF_CONFIGFS_ATTRIB_SHOW(emulate_caw);
 DEF_CONFIGFS_ATTRIB_SHOW(emulate_3pc);
+DEF_CONFIGFS_ATTRIB_SHOW(emulate_pr);
 DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_type);
 DEF_CONFIGFS_ATTRIB_SHOW(hw_pi_prot_type);
 DEF_CONFIGFS_ATTRIB_SHOW(pi_prot_format);
@@ -592,6 +593,7 @@ static ssize_t _name##_store(struct config_item *item, const char *page,    \
 DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_fua_write);
 DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_caw);
 DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_3pc);
+DEF_CONFIGFS_ATTRIB_STORE_BOOL(emulate_pr);
 DEF_CONFIGFS_ATTRIB_STORE_BOOL(enforce_pr_isids);
 DEF_CONFIGFS_ATTRIB_STORE_BOOL(is_nonrot);
 
@@ -1116,6 +1118,7 @@ CONFIGFS_ATTR(, emulate_tpu);
 CONFIGFS_ATTR(, emulate_tpws);
 CONFIGFS_ATTR(, emulate_caw);
 CONFIGFS_ATTR(, emulate_3pc);
+CONFIGFS_ATTR(, emulate_pr);
 CONFIGFS_ATTR(, pi_prot_type);
 CONFIGFS_ATTR_RO(, hw_pi_prot_type);
 CONFIGFS_ATTR(, pi_prot_format);
@@ -1156,6 +1159,7 @@ struct configfs_attribute *sbc_attrib_attrs[] = {
        &attr_emulate_tpws,
        &attr_emulate_caw,
        &attr_emulate_3pc,
+       &attr_emulate_pr,
        &attr_pi_prot_type,
        &attr_hw_pi_prot_type,
        &attr_pi_prot_format,
@@ -1427,6 +1431,9 @@ static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
        struct se_device *dev = pr_to_dev(item);
        int ret;
 
+       if (!dev->dev_attrib.emulate_pr)
+               return sprintf(page, "SPC_RESERVATIONS_DISABLED\n");
+
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
                return sprintf(page, "Passthrough\n");
 
@@ -1567,12 +1574,14 @@ static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
 {
        struct se_device *dev = pr_to_dev(item);
 
+       if (!dev->dev_attrib.emulate_pr)
+               return sprintf(page, "SPC_RESERVATIONS_DISABLED\n");
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
                return sprintf(page, "SPC_PASSTHROUGH\n");
-       else if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
+       if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
                return sprintf(page, "SPC2_RESERVATIONS\n");
-       else
-               return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n");
+
+       return sprintf(page, "SPC3_PERSISTENT_RESERVATIONS\n");
 }
 
 static ssize_t target_pr_res_aptpl_active_show(struct config_item *item,
@@ -1580,7 +1589,8 @@ static ssize_t target_pr_res_aptpl_active_show(struct config_item *item,
 {
        struct se_device *dev = pr_to_dev(item);
 
-       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
+       if (!dev->dev_attrib.emulate_pr ||
+           (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR))
                return 0;
 
        return sprintf(page, "APTPL Bit Status: %s\n",
@@ -1592,7 +1602,8 @@ static ssize_t target_pr_res_aptpl_metadata_show(struct config_item *item,
 {
        struct se_device *dev = pr_to_dev(item);
 
-       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
+       if (!dev->dev_attrib.emulate_pr ||
+           (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR))
                return 0;
 
        return sprintf(page, "Ready to process PR APTPL metadata..\n");
@@ -1638,7 +1649,8 @@ static ssize_t target_pr_res_aptpl_metadata_store(struct config_item *item,
        u16 tpgt = 0;
        u8 type = 0;
 
-       if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
+       if (!dev->dev_attrib.emulate_pr ||
+           (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR))
                return count;
        if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
                return count;
index 47b5ef153135cbbe89d8a1395b75ff94054ef6f4..3274a5fa825c49075285775d87b009c60272fe68 100644 (file)
@@ -805,6 +805,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS;
        dev->dev_attrib.emulate_caw = DA_EMULATE_CAW;
        dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC;
+       dev->dev_attrib.emulate_pr = DA_EMULATE_PR;
        dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE0_PROT;
        dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
        dev->dev_attrib.force_pr_aptpl = DA_FORCE_PR_APTPL;
@@ -1158,6 +1159,18 @@ passthrough_parse_cdb(struct se_cmd *cmd,
                return TCM_NO_SENSE;
        }
 
+       /*
+        * With emulate_pr disabled, all reservation requests should fail,
+        * regardless of whether or not TRANSPORT_FLAG_PASSTHROUGH_PGR is set.
+        */
+       if (!dev->dev_attrib.emulate_pr &&
+           ((cdb[0] == PERSISTENT_RESERVE_IN) ||
+            (cdb[0] == PERSISTENT_RESERVE_OUT) ||
+            (cdb[0] == RELEASE || cdb[0] == RELEASE_10) ||
+            (cdb[0] == RESERVE || cdb[0] == RESERVE_10))) {
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
        /*
         * For PERSISTENT RESERVE IN/OUT, RELEASE, and RESERVE we need to
         * emulate the response, since tcmu does not have the information
index 10db5656fd5dcb8e95769a922223b8e88cf23983..91a2927acd365f6abe12d20ef1fc7f36cedc8176 100644 (file)
@@ -4095,6 +4095,8 @@ target_check_reservation(struct se_cmd *cmd)
                return 0;
        if (dev->se_hba->hba_flags & HBA_FLAGS_INTERNAL_USE)
                return 0;
+       if (!dev->dev_attrib.emulate_pr)
+               return 0;
        if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
                return 0;
 
index f459118bc11ba3864fd372a80d7d07980970fe2e..5c49eb6f4929fd19ddd7bcf88e11548be3f49596 100644 (file)
@@ -1281,6 +1281,14 @@ spc_parse_cdb(struct se_cmd *cmd, unsigned int *size)
        struct se_device *dev = cmd->se_dev;
        unsigned char *cdb = cmd->t_task_cdb;
 
+       if (!dev->dev_attrib.emulate_pr &&
+           ((cdb[0] == PERSISTENT_RESERVE_IN) ||
+            (cdb[0] == PERSISTENT_RESERVE_OUT) ||
+            (cdb[0] == RELEASE || cdb[0] == RELEASE_10) ||
+            (cdb[0] == RESERVE || cdb[0] == RESERVE_10))) {
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
        switch (cdb[0]) {
        case MODE_SELECT:
                *size = cdb[4];
index e3bdb0550a596bb4c8b90614c267920ec9ac1972..c15054116b867baa888952730c933e254ddf83b9 100644 (file)
@@ -87,6 +87,8 @@
 #define DA_EMULATE_3PC                         1
 /* No Emulation for PSCSI by default */
 #define DA_EMULATE_ALUA                                0
+/* Emulate SCSI2 RESERVE/RELEASE and Persistent Reservations by default */
+#define DA_EMULATE_PR                          1
 /* Enforce SCSI Initiator Port TransportID with 'ISID' for PR */
 #define DA_ENFORCE_PR_ISIDS                    1
 /* Force SPC-3 PR Activate Persistence across Target Power Loss */
@@ -664,6 +666,7 @@ struct se_dev_attrib {
        int             emulate_tpws;
        int             emulate_caw;
        int             emulate_3pc;
+       int             emulate_pr;
        int             pi_prot_format;
        enum target_prot_type pi_prot_type;
        enum target_prot_type hw_pi_prot_type;