Commit fe542396da73b7e2b0848618c7e95855c1b75689
Committed by
James Bottomley
1 parent
fe0c9610bb
Exists in
master
and in
20 other branches
[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>
Showing 2 changed files with 37 additions and 19 deletions Side-by-side Diff
drivers/scsi/sd.c
... | ... | @@ -1693,34 +1693,42 @@ |
1693 | 1693 | /* |
1694 | 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 | 1698 | struct scsi_device *sdp = sdkp->device; |
1699 | 1699 | u8 type; |
1700 | + int ret = 0; | |
1700 | 1701 | |
1701 | 1702 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) |
1702 | - return; | |
1703 | + return ret; | |
1703 | 1704 | |
1704 | 1705 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ |
1705 | 1706 | |
1706 | - if (type == sdkp->protection_type || !sdkp->first_scan) | |
1707 | - return; | |
1707 | + if (type > SD_DIF_TYPE3_PROTECTION) | |
1708 | + ret = -ENODEV; | |
1709 | + else if (scsi_host_dif_capable(sdp->host, type)) | |
1710 | + ret = 1; | |
1708 | 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 | + } | |
1728 | + | |
1709 | 1729 | sdkp->protection_type = type; |
1710 | 1730 | |
1711 | - if (type > SD_DIF_TYPE3_PROTECTION) { | |
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); | |
1731 | + return ret; | |
1724 | 1732 | } |
1725 | 1733 | |
1726 | 1734 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, |
... | ... | @@ -1816,7 +1824,10 @@ |
1816 | 1824 | sector_size = get_unaligned_be32(&buffer[8]); |
1817 | 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 | 1832 | if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) { |
1822 | 1833 | sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a " |
... | ... | @@ -2654,7 +2665,8 @@ |
2654 | 2665 | } |
2655 | 2666 | |
2656 | 2667 | add_disk(gd); |
2657 | - sd_dif_config_host(sdkp); | |
2668 | + if (sdkp->capacity) | |
2669 | + sd_dif_config_host(sdkp); | |
2658 | 2670 | |
2659 | 2671 | sd_revalidate_disk(gd); |
2660 | 2672 |
include/scsi/scsi_host.h
... | ... | @@ -873,6 +873,9 @@ |
873 | 873 | SHOST_DIF_TYPE2_PROTECTION, |
874 | 874 | SHOST_DIF_TYPE3_PROTECTION }; |
875 | 875 | |
876 | + if (target_type > SHOST_DIF_TYPE3_PROTECTION) | |
877 | + return 0; | |
878 | + | |
876 | 879 | return shost->prot_capabilities & cap[target_type] ? target_type : 0; |
877 | 880 | } |
878 | 881 | |
... | ... | @@ -883,6 +886,9 @@ |
883 | 886 | SHOST_DIX_TYPE1_PROTECTION, |
884 | 887 | SHOST_DIX_TYPE2_PROTECTION, |
885 | 888 | SHOST_DIX_TYPE3_PROTECTION }; |
889 | + | |
890 | + if (target_type > SHOST_DIX_TYPE3_PROTECTION) | |
891 | + return 0; | |
886 | 892 | |
887 | 893 | return shost->prot_capabilities & cap[target_type]; |
888 | 894 | #endif |