diff options
author | Martin K. Petersen <martin.petersen@oracle.com> | 2012-09-21 12:44:12 -0400 |
---|---|---|
committer | James Bottomley <JBottomley@Parallels.com> | 2012-09-24 05:01:24 -0400 |
commit | fe542396da73b7e2b0848618c7e95855c1b75689 (patch) | |
tree | 5ecc5110504cf3b2cd3cd3777d4e0295accae89e | |
parent | fe0c9610bb68dd0aad1017456f5e3c31264d70c2 (diff) |
[SCSI] sd: Ensure we correctly disable devices with unknown protection type
We set the capacity to zero when we discovered a device formatted with
an unknown DIF protection type. However, the read_capacity code would
override the capacity and cause the device to be enabled regardless.
Make sd_read_protection_type() return an error if the protection type is
unknown. Also prevent duplicate printk lines when the device is being
revalidated.
Reported-by: Hannes Reinecke <hare@suse.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <JBottomley@Parallels.com>
-rw-r--r-- | drivers/scsi/sd.c | 50 | ||||
-rw-r--r-- | include/scsi/scsi_host.h | 6 |
2 files changed, 37 insertions, 19 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index e04c302fa4f7..12f6fdfc1147 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
@@ -1693,34 +1693,42 @@ sd_spinup_disk(struct scsi_disk *sdkp) | |||
1693 | /* | 1693 | /* |
1694 | * Determine whether disk supports Data Integrity Field. | 1694 | * Determine whether disk supports Data Integrity Field. |
1695 | */ | 1695 | */ |
1696 | static void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) | 1696 | static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) |
1697 | { | 1697 | { |
1698 | struct scsi_device *sdp = sdkp->device; | 1698 | struct scsi_device *sdp = sdkp->device; |
1699 | u8 type; | 1699 | u8 type; |
1700 | int ret = 0; | ||
1700 | 1701 | ||
1701 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) | 1702 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) |
1702 | return; | 1703 | return ret; |
1703 | 1704 | ||
1704 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ | 1705 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ |
1705 | 1706 | ||
1706 | if (type == sdkp->protection_type || !sdkp->first_scan) | 1707 | if (type > SD_DIF_TYPE3_PROTECTION) |
1707 | return; | 1708 | ret = -ENODEV; |
1709 | else if (scsi_host_dif_capable(sdp->host, type)) | ||
1710 | ret = 1; | ||
1711 | |||
1712 | if (sdkp->first_scan || type != sdkp->protection_type) | ||
1713 | switch (ret) { | ||
1714 | case -ENODEV: | ||
1715 | sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ | ||
1716 | " protection type %u. Disabling disk!\n", | ||
1717 | type); | ||
1718 | break; | ||
1719 | case 1: | ||
1720 | sd_printk(KERN_NOTICE, sdkp, | ||
1721 | "Enabling DIF Type %u protection\n", type); | ||
1722 | break; | ||
1723 | case 0: | ||
1724 | sd_printk(KERN_NOTICE, sdkp, | ||
1725 | "Disabling DIF Type %u protection\n", type); | ||
1726 | break; | ||
1727 | } | ||
1708 | 1728 | ||
1709 | sdkp->protection_type = type; | 1729 | sdkp->protection_type = type; |
1710 | 1730 | ||
1711 | if (type > SD_DIF_TYPE3_PROTECTION) { | 1731 | return ret; |
1712 | sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ | ||
1713 | "protection type %u. Disabling disk!\n", type); | ||
1714 | sdkp->capacity = 0; | ||
1715 | return; | ||
1716 | } | ||
1717 | |||
1718 | if (scsi_host_dif_capable(sdp->host, type)) | ||
1719 | sd_printk(KERN_NOTICE, sdkp, | ||
1720 | "Enabling DIF Type %u protection\n", type); | ||
1721 | else | ||
1722 | sd_printk(KERN_NOTICE, sdkp, | ||
1723 | "Disabling DIF Type %u protection\n", type); | ||
1724 | } | 1732 | } |
1725 | 1733 | ||
1726 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, | 1734 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, |
@@ -1816,7 +1824,10 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp, | |||
1816 | sector_size = get_unaligned_be32(&buffer[8]); | 1824 | sector_size = get_unaligned_be32(&buffer[8]); |
1817 | lba = get_unaligned_be64(&buffer[0]); | 1825 | lba = get_unaligned_be64(&buffer[0]); |
1818 | 1826 | ||
1819 | sd_read_protection_type(sdkp, buffer); | 1827 | if (sd_read_protection_type(sdkp, buffer) < 0) { |
1828 | sdkp->capacity = 0; | ||
1829 | return -ENODEV; | ||
1830 | } | ||
1820 | 1831 | ||
1821 | if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { | 1832 | if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { |
1822 | sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " | 1833 | sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " |
@@ -2654,7 +2665,8 @@ static void sd_probe_async(void *data, async_cookie_t cookie) | |||
2654 | } | 2665 | } |
2655 | 2666 | ||
2656 | add_disk(gd); | 2667 | add_disk(gd); |
2657 | sd_dif_config_host(sdkp); | 2668 | if (sdkp->capacity) |
2669 | sd_dif_config_host(sdkp); | ||
2658 | 2670 | ||
2659 | sd_revalidate_disk(gd); | 2671 | sd_revalidate_disk(gd); |
2660 | 2672 | ||
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index 5f7d5b3b1c6e..49084807eb6b 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
@@ -873,6 +873,9 @@ static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsign | |||
873 | SHOST_DIF_TYPE2_PROTECTION, | 873 | SHOST_DIF_TYPE2_PROTECTION, |
874 | SHOST_DIF_TYPE3_PROTECTION }; | 874 | SHOST_DIF_TYPE3_PROTECTION }; |
875 | 875 | ||
876 | if (target_type > SHOST_DIF_TYPE3_PROTECTION) | ||
877 | return 0; | ||
878 | |||
876 | return shost->prot_capabilities & cap[target_type] ? target_type : 0; | 879 | return shost->prot_capabilities & cap[target_type] ? target_type : 0; |
877 | } | 880 | } |
878 | 881 | ||
@@ -884,6 +887,9 @@ static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsign | |||
884 | SHOST_DIX_TYPE2_PROTECTION, | 887 | SHOST_DIX_TYPE2_PROTECTION, |
885 | SHOST_DIX_TYPE3_PROTECTION }; | 888 | SHOST_DIX_TYPE3_PROTECTION }; |
886 | 889 | ||
890 | if (target_type > SHOST_DIX_TYPE3_PROTECTION) | ||
891 | return 0; | ||
892 | |||
887 | return shost->prot_capabilities & cap[target_type]; | 893 | return shost->prot_capabilities & cap[target_type]; |
888 | #endif | 894 | #endif |
889 | return 0; | 895 | return 0; |