diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -197,6 +197,118 @@ sd_store_allow_restart(struct device *de } static ssize_t +sd_store_read_guard_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + unsigned int val; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + val = simple_strtoul(buf, NULL, 10); + + if (val) + sdkp->err_mask |= SD_READ_GUARD_ERR; + else + sdkp->err_mask &= ~SD_READ_GUARD_ERR; + + return count; +} + +static ssize_t +sd_show_read_guard_err(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", (sdkp->err_mask & SD_READ_GUARD_ERR) ? 1 : 0); +} + +static ssize_t +sd_store_read_ref_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + unsigned int val; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + val = simple_strtoul(buf, NULL, 10); + + if (val) + sdkp->err_mask |= SD_READ_REF_ERR; + else + sdkp->err_mask &= ~SD_READ_REF_ERR; + + return count; +} + +static ssize_t +sd_show_read_ref_err(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", (sdkp->err_mask & SD_READ_REF_ERR) ? 1 : 0); +} + +static ssize_t +sd_store_write_guard_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + unsigned int val; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + val = simple_strtoul(buf, NULL, 10); + + if (val) + sdkp->err_mask |= SD_WRITE_GUARD_ERR; + else + sdkp->err_mask &= ~SD_WRITE_GUARD_ERR; + + return count; +} + +static ssize_t +sd_show_write_guard_err(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", (sdkp->err_mask & SD_WRITE_GUARD_ERR) ? 1 : 0); +} + +static ssize_t +sd_store_write_ref_err(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + unsigned int val; + + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + + val = simple_strtoul(buf, NULL, 10); + + if (val) + sdkp->err_mask |= SD_WRITE_REF_ERR; + else + sdkp->err_mask &= ~SD_WRITE_REF_ERR; + + return count; +} + +static ssize_t +sd_show_write_ref_err(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct scsi_disk *sdkp = to_scsi_disk(dev); + + return snprintf(buf, 20, "%u\n", (sdkp->err_mask & SD_WRITE_REF_ERR) ? 1 : 0); +} + +static ssize_t sd_show_cache_type(struct device *dev, struct device_attribute *attr, char *buf) { @@ -252,6 +364,10 @@ sd_show_app_tag_own(struct device *dev, } static struct device_attribute sd_disk_attrs[] = { + __ATTR(read_guard_err, S_IRUGO|S_IWUSR, sd_show_read_guard_err, sd_store_read_guard_err), + __ATTR(read_ref_err, S_IRUGO|S_IWUSR, sd_show_read_ref_err, sd_store_read_ref_err), + __ATTR(write_guard_err, S_IRUGO|S_IWUSR, sd_show_write_guard_err, sd_store_write_guard_err), + __ATTR(write_ref_err, S_IRUGO|S_IWUSR, sd_show_write_ref_err, sd_store_write_ref_err), __ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type, sd_store_cache_type), __ATTR(FUA, S_IRUGO, sd_show_fua, NULL), diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h @@ -37,6 +37,13 @@ */ #define SD_LAST_BUGGY_SECTORS 8 +enum sd_err_mask { + SD_READ_GUARD_ERR = 1, + SD_READ_REF_ERR = 2, + SD_WRITE_GUARD_ERR = 4, + SD_WRITE_REF_ERR = 8, +}; + struct scsi_disk { struct scsi_driver *driver; /* always &sd_template */ struct scsi_device *device; @@ -54,6 +61,7 @@ struct scsi_disk { unsigned RCD : 1; /* state of disk RCD bit, unused */ unsigned DPOFUA : 1; /* state of disk DPOFUA bit */ unsigned verbose : 1; + volatile int err_mask; }; #define to_scsi_disk(obj) container_of(obj,struct scsi_disk,dev) diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c @@ -463,6 +463,17 @@ int sd_dif_prepare(struct request *rq, s goto error; sdt->ref_tag = cpu_to_be32(phys); + + if (sdkp->err_mask & SD_WRITE_GUARD_ERR) { + sdt->guard_tag = cpu_to_be16(0x4242); + sdkp->err_mask &= ~SD_WRITE_GUARD_ERR; + } + + if (sdkp->err_mask & SD_WRITE_REF_ERR) { + sdt->ref_tag = cpu_to_be32(0x42424242); + sdkp->err_mask &= ~SD_WRITE_REF_ERR; + } + virt++; phys++; } @@ -527,6 +538,18 @@ void sd_dif_complete(struct scsi_cmnd *s sdt->ref_tag = 0xffffffff; /* Bad ref */ else sdt->ref_tag = cpu_to_be32(virt); + + if (sdkp->err_mask & SD_READ_GUARD_ERR) { + sdt->guard_tag = 0x4242; + sdt->app_tag = 0; + sdkp->err_mask &= ~SD_READ_GUARD_ERR; + } + + if (sdkp->err_mask & SD_READ_REF_ERR) { + sdt->ref_tag = 0x42424242; + sdt->app_tag = 0; + sdkp->err_mask &= ~SD_READ_REF_ERR; + } virt++; phys++;