diff mbox

[RFC] target: add emulate_pr backstore attr to toggle PR support

Message ID 20180601000532.11058-1-ddiss@suse.de (mailing list archive)
State New, archived
Headers show

Commit Message

David Disseldorp June 1, 2018, 12:05 a.m. UTC
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:
- Enforcing 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>
---
 drivers/target/target_core_configfs.c | 21 ++++++++++++++++-----
 drivers/target/target_core_device.c   |  1 +
 drivers/target/target_core_pr.c       | 22 ++++++++++++++++++++++
 include/target/target_core_base.h     |  3 +++
 4 files changed, 42 insertions(+), 5 deletions(-)

Comments

Bryant G. Ly June 1, 2018, 1:20 p.m. UTC | #1
On 5/31/18 7:05 PM, David Disseldorp wrote:

> 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:
> - Enforcing 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>
> ---
>  drivers/target/target_core_configfs.c | 21 ++++++++++++++++-----
>  drivers/target/target_core_device.c   |  1 +
>  drivers/target/target_core_pr.c       | 22 ++++++++++++++++++++++
>  include/target/target_core_base.h     |  3 +++
>  4 files changed, 42 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
> index 3f4bf126eed0..17b830e35a08 100644
> --- a/drivers/target/target_core_configfs.c
> +++ b/drivers/target/target_core_configfs.c
> @@ -530,6 +530,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);
> @@ -590,6 +591,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);
>
> @@ -1114,6 +1116,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);
> @@ -1154,6 +1157,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,
> @@ -1428,6 +1432,9 @@ static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
>  	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
>  		return sprintf(page, "Passthrough\n");
>
> +	if (!dev->dev_attrib.emulate_pr)
> +		return sprintf(page, "Reservations Disabled\n");
> +
>  	spin_lock(&dev->dev_reservation_lock);
>  	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
>  		ret = target_core_dev_pr_show_spc2_res(dev, page);
> @@ -1567,10 +1574,12 @@ static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
>
>  	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_attrib.emulate_pr)
> +		return sprintf(page, "Reservations Disabled\n");
> +	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,
> @@ -1578,7 +1587,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
> +						|| !dev->dev_attrib.emulate_pr)
>  		return 0;
>
>  	return sprintf(page, "APTPL Bit Status: %s\n",
> @@ -1590,7 +1600,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
> +						|| !dev->dev_attrib.emulate_pr)
>  		return 0;
>
>  	return sprintf(page, "Ready to process PR APTPL metadata..\n");
> diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
> index e27db4d45a9d..96a60072e446 100644
> --- a/drivers/target/target_core_device.c
> +++ b/drivers/target/target_core_device.c
> @@ -806,6 +806,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;
> diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
> index 2e865fdaa362..9960a44c3a59 100644
> --- a/drivers/target/target_core_pr.c
> +++ b/drivers/target/target_core_pr.c
> @@ -208,6 +208,11 @@ target_scsi2_reservation_release(struct se_cmd *cmd)
>  	struct se_portal_group *tpg;
>  	int rc;
>
> +	if (!dev->dev_attrib.emulate_pr) {
> +		pr_err("failing SCSI2 RELEASE with emulate_pr disabled\n");
> +		return TCM_UNSUPPORTED_SCSI_OPCODE;
> +	}
> +
>  	if (!sess || !sess->se_tpg)
>  		goto out;
>  	rc = target_check_scsi2_reservation_conflict(cmd);
> @@ -255,6 +260,11 @@ target_scsi2_reservation_reserve(struct se_cmd *cmd)
>  	sense_reason_t ret = 0;
>  	int rc;
>
> +	if (!dev->dev_attrib.emulate_pr) {
> +		pr_err("failing SCSI2 RESERVE with emulate_pr disabled\n");
> +		return TCM_UNSUPPORTED_SCSI_OPCODE;
> +	}
> +
>  	if ((cmd->t_task_cdb[1] & 0x01) &&
>  	    (cmd->t_task_cdb[1] & 0x02)) {
>  		pr_err("LongIO and Obsolete Bits set, returning ILLEGAL_REQUEST\n");
> @@ -3560,6 +3570,11 @@ target_scsi3_emulate_pr_out(struct se_cmd *cmd)
>  	int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
>  	sense_reason_t ret;
>
> +	if (!dev->dev_attrib.emulate_pr) {
> +		pr_err("failing PROUT with emulate_pr disabled\n");
> +		return TCM_UNSUPPORTED_SCSI_OPCODE;
> +	}
> +
>  	/*
>  	 * Following spc2r20 5.5.1 Reservations overview:
>  	 *
> @@ -4045,6 +4060,11 @@ target_scsi3_emulate_pr_in(struct se_cmd *cmd)
>  {
>  	sense_reason_t ret;
>
> +	if (!cmd->se_dev->dev_attrib.emulate_pr) {
> +		pr_err("failing PRIN with emulate_pr disabled\n");
> +		return TCM_UNSUPPORTED_SCSI_OPCODE;
> +	}
> +
>  	/*
>  	 * Following spc2r20 5.5.1 Reservations overview:
>  	 *
> @@ -4097,6 +4117,8 @@ target_check_reservation(struct se_cmd *cmd)
>  		return 0;
>  	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
>  		return 0;
> +	if (!dev->dev_attrib.emulate_pr)
> +		return 0;
>
>  	spin_lock(&dev->dev_reservation_lock);
>  	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
> diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
> index 9f9f5902af38..06d88645938b 100644
> --- a/include/target/target_core_base.h
> +++ b/include/target/target_core_base.h
> @@ -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 */
> @@ -665,6 +667,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;

You need to handle the passthrough case also, so you'll need to look at:

https://elixir.bootlin.com/linux/v4.17-rc7/source/drivers/target/target_core_device.c#L1179

In those cases you'll notice it calls some of the functions you changed
to address new attribute, but the return code is overwritten.

-Bryant


--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mike Christie June 1, 2018, 4:22 p.m. UTC | #2
On 05/31/2018 07:05 PM, David Disseldorp wrote:
> 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:
> - Enforcing ATS (Compare & Write) usage on recent VMware ESXi initiators

I was wondering why didn't you want your patch to be able to override
the passthrough case like for pscsi when TRANSPORT_FLAG_PASSTHROUGH_PGR
is set? It seems like for this ATS case you would want to do that for
all backends.

For the ATS case would you ever need to separate the SCSI 2
RESERVE/RELEASE case from the modern PR case (a emulate_scsi2_pr and
emulate_pr)? For example would you ever be using a device for ESX, want
to do ATS only, but have datastores on the same device that are exported
to VMs with apps that are going to use PRs so you would need
(emulate_scsi2_pr=false, emulate_pr=true)?


> - 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>
> ---
>  drivers/target/target_core_configfs.c | 21 ++++++++++++++++-----
>  drivers/target/target_core_device.c   |  1 +
>  drivers/target/target_core_pr.c       | 22 ++++++++++++++++++++++
>  include/target/target_core_base.h     |  3 +++
>  4 files changed, 42 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
> index 3f4bf126eed0..17b830e35a08 100644
> --- a/drivers/target/target_core_configfs.c
> +++ b/drivers/target/target_core_configfs.c
> @@ -530,6 +530,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);
> @@ -590,6 +591,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);
>  
> @@ -1114,6 +1116,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);
> @@ -1154,6 +1157,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,
> @@ -1428,6 +1432,9 @@ static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
>  	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
>  		return sprintf(page, "Passthrough\n");
>  
> +	if (!dev->dev_attrib.emulate_pr)
> +		return sprintf(page, "Reservations Disabled\n");
> +
>  	spin_lock(&dev->dev_reservation_lock);
>  	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
>  		ret = target_core_dev_pr_show_spc2_res(dev, page);
> @@ -1567,10 +1574,12 @@ static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
>  
>  	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_attrib.emulate_pr)
> +		return sprintf(page, "Reservations Disabled\n");

Do we want this formatted like the other strings here in caps with no
spaces between words incase parsers are expecting that format for this file?

> +	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,
> @@ -1578,7 +1587,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
> +						|| !dev->dev_attrib.emulate_pr)

We normally put the "||" on the line above it and the next line starts
at the column after the opening "(" above it. I guess we sometimes tab
over too, but we never tab way way over like above.

Same below.

>  		return 0;
>  
>  	return sprintf(page, "APTPL Bit Status: %s\n",
> @@ -1590,7 +1600,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
> +						|| !dev->dev_attrib.emulate_pr)
>  		return 0;
>  
--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Disseldorp June 3, 2018, 12:57 p.m. UTC | #3
On Fri, 1 Jun 2018 11:22:50 -0500, Mike Christie wrote:

> On 05/31/2018 07:05 PM, David Disseldorp wrote:
> > 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:
> > - Enforcing ATS (Compare & Write) usage on recent VMware ESXi initiators  
> 
> I was wondering why didn't you want your patch to be able to override
> the passthrough case like for pscsi when TRANSPORT_FLAG_PASSTHROUGH_PGR
> is set? It seems like for this ATS case you would want to do that for
> all backends.

Agreed, I'll fix the passthrough case in the next revision.

> For the ATS case would you ever need to separate the SCSI 2
> RESERVE/RELEASE case from the modern PR case (a emulate_scsi2_pr and
> emulate_pr)? For example would you ever be using a device for ESX, want
> to do ATS only, but have datastores on the same device that are exported
> to VMs with apps that are going to use PRs so you would need
> (emulate_scsi2_pr=false, emulate_pr=true)?

I considered more granular toggles, but decided against it due to the
added configuration/implementation complexity. Happy to revisit this if
others would prefer it though.
Perhaps emulate_reservations would make more sense as a single toggle,
given that RESERVE/RELEASE aren't "persistent", although the existing
configfs paths seem to use "pr" for both types.

> > - 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>
> > ---
> >  drivers/target/target_core_configfs.c | 21 ++++++++++++++++-----
> >  drivers/target/target_core_device.c   |  1 +
> >  drivers/target/target_core_pr.c       | 22 ++++++++++++++++++++++
> >  include/target/target_core_base.h     |  3 +++
> >  4 files changed, 42 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
> > index 3f4bf126eed0..17b830e35a08 100644
> > --- a/drivers/target/target_core_configfs.c
> > +++ b/drivers/target/target_core_configfs.c
> > @@ -530,6 +530,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);
> > @@ -590,6 +591,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);
> >  
> > @@ -1114,6 +1116,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);
> > @@ -1154,6 +1157,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,
> > @@ -1428,6 +1432,9 @@ static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
> >  	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
> >  		return sprintf(page, "Passthrough\n");
> >  
> > +	if (!dev->dev_attrib.emulate_pr)
> > +		return sprintf(page, "Reservations Disabled\n");
> > +
> >  	spin_lock(&dev->dev_reservation_lock);
> >  	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
> >  		ret = target_core_dev_pr_show_spc2_res(dev, page);
> > @@ -1567,10 +1574,12 @@ static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
> >  
> >  	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_attrib.emulate_pr)
> > +		return sprintf(page, "Reservations Disabled\n");  
> 
> Do we want this formatted like the other strings here in caps with no
> spaces between words incase parsers are expecting that format for this file?

AFAICT, targetcli (via rtslib-fb) only makes use of the
res_aptpl_metadata path. I'm not aware of any other consumers, so happy
to go with whatever the community preference is here.

> > +	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,
> > @@ -1578,7 +1587,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
> > +						|| !dev->dev_attrib.emulate_pr)  
> 
> We normally put the "||" on the line above it and the next line starts
> at the column after the opening "(" above it. I guess we sometimes tab
> over too, but we never tab way way over like above.
> 
> Same below.

Will fix these in the next round. Thanks for the feedback, Mike.

Cheers, David
--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mike Christie June 4, 2018, 5:13 p.m. UTC | #4
On 06/03/2018 07:57 AM, David Disseldorp wrote:
> On Fri, 1 Jun 2018 11:22:50 -0500, Mike Christie wrote:
> 
>> On 05/31/2018 07:05 PM, David Disseldorp wrote:
>>> 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:
>>> - Enforcing ATS (Compare & Write) usage on recent VMware ESXi initiators  
>>
>> I was wondering why didn't you want your patch to be able to override
>> the passthrough case like for pscsi when TRANSPORT_FLAG_PASSTHROUGH_PGR
>> is set? It seems like for this ATS case you would want to do that for
>> all backends.
> 
> Agreed, I'll fix the passthrough case in the next revision.
> 
>> For the ATS case would you ever need to separate the SCSI 2
>> RESERVE/RELEASE case from the modern PR case (a emulate_scsi2_pr and
>> emulate_pr)? For example would you ever be using a device for ESX, want
>> to do ATS only, but have datastores on the same device that are exported
>> to VMs with apps that are going to use PRs so you would need
>> (emulate_scsi2_pr=false, emulate_pr=true)?
> 
> I considered more granular toggles, but decided against it due to the
> added configuration/implementation complexity. Happy to revisit this if
> others would prefer it though.

I might not understand your original "enforce" part of the patch
description, because it seems like you must do this.

I think ATS only is the default for the newer versions of ESX when the
device reports it supports ATS, and it seems like running windows
clustering in VMs on ESX is common. So, you will have that combo of ATS
only with PRs a lot.

When you wrote "enforce" earlier I thought you meant the patch is
supposed to make sure that ATS only is really on and if ESX messes up
(or maybe the user messed up the settings) and it sends a
RESERVE/RELEASE then it is failed. I do not see how that is possible
with your patch with something like windows clustering VMs.

If the patch was more for protecting against the case where the backend
does not support reservations, and ATS only was used to make sure they
are never used due to that, and we assume backends always implement
older reservations if they implement newer PRs then I think the patch is
fine.

So I do not really care :) I think it depends on what you were trying to
support.


> Perhaps emulate_reservations would make more sense as a single toggle,
> given that RESERVE/RELEASE aren't "persistent", although the existing
> configfs paths seem to use "pr" for both types.
> 
>>> - 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>
>>> ---
>>>  drivers/target/target_core_configfs.c | 21 ++++++++++++++++-----
>>>  drivers/target/target_core_device.c   |  1 +
>>>  drivers/target/target_core_pr.c       | 22 ++++++++++++++++++++++
>>>  include/target/target_core_base.h     |  3 +++
>>>  4 files changed, 42 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
>>> index 3f4bf126eed0..17b830e35a08 100644
>>> --- a/drivers/target/target_core_configfs.c
>>> +++ b/drivers/target/target_core_configfs.c
>>> @@ -530,6 +530,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);
>>> @@ -590,6 +591,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);
>>>  
>>> @@ -1114,6 +1116,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);
>>> @@ -1154,6 +1157,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,
>>> @@ -1428,6 +1432,9 @@ static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
>>>  	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
>>>  		return sprintf(page, "Passthrough\n");
>>>  
>>> +	if (!dev->dev_attrib.emulate_pr)
>>> +		return sprintf(page, "Reservations Disabled\n");
>>> +
>>>  	spin_lock(&dev->dev_reservation_lock);
>>>  	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
>>>  		ret = target_core_dev_pr_show_spc2_res(dev, page);
>>> @@ -1567,10 +1574,12 @@ static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
>>>  
>>>  	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_attrib.emulate_pr)
>>> +		return sprintf(page, "Reservations Disabled\n");  
>>
>> Do we want this formatted like the other strings here in caps with no
>> spaces between words incase parsers are expecting that format for this file?
> 
> AFAICT, targetcli (via rtslib-fb) only makes use of the
> res_aptpl_metadata path. I'm not aware of any other consumers, so happy
> to go with whatever the community preference is here.
> 

I just seems odd to have a file use 2 different formats for no reason
except there were 2 different people coding it.

--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Disseldorp June 21, 2018, 3:03 p.m. UTC | #5
Hi Mike,

On Mon, 4 Jun 2018 12:13:22 -0500, Mike Christie wrote:

> On 06/03/2018 07:57 AM, David Disseldorp wrote:
...
> > I considered more granular toggles, but decided against it due to the
> > added configuration/implementation complexity. Happy to revisit this if
> > others would prefer it though.  
> 
> I might not understand your original "enforce" part of the patch
> description, because it seems like you must do this.

I've changed "enforce" to "ensure".

> I think ATS only is the default for the newer versions of ESX when the
> device reports it supports ATS, and it seems like running windows
> clustering in VMs on ESX is common. So, you will have that combo of ATS
> only with PRs a lot.

I don't think a combination of SCSI2 and persistent reservations is
common, as VMware recommends Raw Device Mapping (via a separate LUN) for
most Windows Failover Cluster use use cases[1]. See:
https://docs.vmware.com/en/VMware-vSphere/6.5/vsphere-esxi-vcenter-server-651-setup-mscs.pdf

IMO a single toggle to disable both RESERVE / RELEASE and Persistent
Reservation handling for a given backstore is still the simplest and
most user friendly option here.

> When you wrote "enforce" earlier I thought you meant the patch is
> supposed to make sure that ATS only is really on and if ESX messes up
> (or maybe the user messed up the settings) and it sends a
> RESERVE/RELEASE then it is failed. I do not see how that is possible
> with your patch with something like windows clustering VMs.
> 
> If the patch was more for protecting against the case where the backend
> does not support reservations, and ATS only was used to make sure they
> are never used due to that, and we assume backends always implement
> older reservations if they implement newer PRs then I think the patch is
> fine.
> 
> So I do not really care :) I think it depends on what you were trying to
> support.

Some older versions of ESX/VMFS can fall back to using SCSI2
reservations instead of ATS[2]. Disabling LIO SCSI2+PR support restricts
this fallback behaviour. That's what I was trying to get across in the
commit message :)

New version to follow...

Cheers, David

1) Windows Failover Cluster on VMware
https://docs.vmware.com/en/VMware-vSphere/6.5/vsphere-esxi-vcenter-server-651-setup-mscs.pdf
2) vSphere 5 SCSI reservations vs ATS locking
https://pubs.vmware.com/vsphere-50/topic/com.vmware.vsphere.storage.doc_50/GUID-DE30AAE3-72ED-43BF-95B3-A2B885A713DB.html
--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Disseldorp June 21, 2018, 3:26 p.m. UTC | #6
On Mon, 4 Jun 2018 12:13:22 -0500, Mike Christie wrote:

> > AFAICT, targetcli (via rtslib-fb) only makes use of the
> > res_aptpl_metadata path. I'm not aware of any other consumers, so happy
> > to go with whatever the community preference is here.
> >   
> 
> I just seems odd to have a file use 2 different formats for no reason
> except there were 2 different people coding it.

It's already a bit inconsistent, in that res_holder_show() returns human
readable strings and res_type_show() opts for enum type strings. I've
changed both to use "SPC_RESERVATIONS_DISABLED" for the disabled case
for now.

Cheers, David
--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Mike Christie June 21, 2018, 8:04 p.m. UTC | #7
On 06/21/2018 10:26 AM, David Disseldorp wrote:
> On Mon, 4 Jun 2018 12:13:22 -0500, Mike Christie wrote:
> 
>>> AFAICT, targetcli (via rtslib-fb) only makes use of the
>>> res_aptpl_metadata path. I'm not aware of any other consumers, so happy
>>> to go with whatever the community preference is here.
>>>   
>>
>> I just seems odd to have a file use 2 different formats for no reason
>> except there were 2 different people coding it.
> 
> It's already a bit inconsistent, in that res_holder_show() returns human
> readable strings and res_type_show() opts for enum type strings. I've
> changed both to use "SPC_RESERVATIONS_DISABLED" for the disabled case
> for now.
> 

I was only asking that we at least have the same format within a file,
so we do not have messes like the backend info file.

--
To unsubscribe from this list: send the line "unsubscribe target-devel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/target/target_core_configfs.c b/drivers/target/target_core_configfs.c
index 3f4bf126eed0..17b830e35a08 100644
--- a/drivers/target/target_core_configfs.c
+++ b/drivers/target/target_core_configfs.c
@@ -530,6 +530,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);
@@ -590,6 +591,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);
 
@@ -1114,6 +1116,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);
@@ -1154,6 +1157,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,
@@ -1428,6 +1432,9 @@  static ssize_t target_pr_res_holder_show(struct config_item *item, char *page)
 	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
 		return sprintf(page, "Passthrough\n");
 
+	if (!dev->dev_attrib.emulate_pr)
+		return sprintf(page, "Reservations Disabled\n");
+
 	spin_lock(&dev->dev_reservation_lock);
 	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
 		ret = target_core_dev_pr_show_spc2_res(dev, page);
@@ -1567,10 +1574,12 @@  static ssize_t target_pr_res_type_show(struct config_item *item, char *page)
 
 	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_attrib.emulate_pr)
+		return sprintf(page, "Reservations Disabled\n");
+	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,
@@ -1578,7 +1587,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
+						|| !dev->dev_attrib.emulate_pr)
 		return 0;
 
 	return sprintf(page, "APTPL Bit Status: %s\n",
@@ -1590,7 +1600,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->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH)
+						|| !dev->dev_attrib.emulate_pr)
 		return 0;
 
 	return sprintf(page, "Ready to process PR APTPL metadata..\n");
diff --git a/drivers/target/target_core_device.c b/drivers/target/target_core_device.c
index e27db4d45a9d..96a60072e446 100644
--- a/drivers/target/target_core_device.c
+++ b/drivers/target/target_core_device.c
@@ -806,6 +806,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;
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 2e865fdaa362..9960a44c3a59 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -208,6 +208,11 @@  target_scsi2_reservation_release(struct se_cmd *cmd)
 	struct se_portal_group *tpg;
 	int rc;
 
+	if (!dev->dev_attrib.emulate_pr) {
+		pr_err("failing SCSI2 RELEASE with emulate_pr disabled\n");
+		return TCM_UNSUPPORTED_SCSI_OPCODE;
+	}
+
 	if (!sess || !sess->se_tpg)
 		goto out;
 	rc = target_check_scsi2_reservation_conflict(cmd);
@@ -255,6 +260,11 @@  target_scsi2_reservation_reserve(struct se_cmd *cmd)
 	sense_reason_t ret = 0;
 	int rc;
 
+	if (!dev->dev_attrib.emulate_pr) {
+		pr_err("failing SCSI2 RESERVE with emulate_pr disabled\n");
+		return TCM_UNSUPPORTED_SCSI_OPCODE;
+	}
+
 	if ((cmd->t_task_cdb[1] & 0x01) &&
 	    (cmd->t_task_cdb[1] & 0x02)) {
 		pr_err("LongIO and Obsolete Bits set, returning ILLEGAL_REQUEST\n");
@@ -3560,6 +3570,11 @@  target_scsi3_emulate_pr_out(struct se_cmd *cmd)
 	int spec_i_pt = 0, all_tg_pt = 0, unreg = 0;
 	sense_reason_t ret;
 
+	if (!dev->dev_attrib.emulate_pr) {
+		pr_err("failing PROUT with emulate_pr disabled\n");
+		return TCM_UNSUPPORTED_SCSI_OPCODE;
+	}
+
 	/*
 	 * Following spc2r20 5.5.1 Reservations overview:
 	 *
@@ -4045,6 +4060,11 @@  target_scsi3_emulate_pr_in(struct se_cmd *cmd)
 {
 	sense_reason_t ret;
 
+	if (!cmd->se_dev->dev_attrib.emulate_pr) {
+		pr_err("failing PRIN with emulate_pr disabled\n");
+		return TCM_UNSUPPORTED_SCSI_OPCODE;
+	}
+
 	/*
 	 * Following spc2r20 5.5.1 Reservations overview:
 	 *
@@ -4097,6 +4117,8 @@  target_check_reservation(struct se_cmd *cmd)
 		return 0;
 	if (dev->transport->transport_flags & TRANSPORT_FLAG_PASSTHROUGH_PGR)
 		return 0;
+	if (!dev->dev_attrib.emulate_pr)
+		return 0;
 
 	spin_lock(&dev->dev_reservation_lock);
 	if (dev->dev_reservation_flags & DRF_SPC2_RESERVATIONS)
diff --git a/include/target/target_core_base.h b/include/target/target_core_base.h
index 9f9f5902af38..06d88645938b 100644
--- a/include/target/target_core_base.h
+++ b/include/target/target_core_base.h
@@ -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 */
@@ -665,6 +667,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;