Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fe542396 authored by Martin K. Petersen's avatar Martin K. Petersen Committed by James Bottomley
Browse files

[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: default avatarHannes Reinecke <hare@suse.de>
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent fe0c9610
Loading
Loading
Loading
Loading
+31 −19
Original line number Diff line number Diff line
@@ -1693,34 +1693,42 @@ sd_spinup_disk(struct scsi_disk *sdkp)
/*
 * Determine whether disk supports Data Integrity Field.
 */
static void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
{
	struct scsi_device *sdp = sdkp->device;
	u8 type;
	int ret = 0;

	if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0)
		return;
		return ret;

	type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */

	if (type == sdkp->protection_type || !sdkp->first_scan)
		return;

	sdkp->protection_type = type;
	if (type > SD_DIF_TYPE3_PROTECTION)
		ret = -ENODEV;
	else if (scsi_host_dif_capable(sdp->host, type))
		ret = 1;

	if (type > SD_DIF_TYPE3_PROTECTION) {
	if (sdkp->first_scan || type != sdkp->protection_type)
		switch (ret) {
		case -ENODEV:
			sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \
			  "protection type %u. Disabling disk!\n", type);
		sdkp->capacity = 0;
		return;
	}

	if (scsi_host_dif_capable(sdp->host, type))
				  " protection type %u. Disabling disk!\n",
				  type);
			break;
		case 1:
			sd_printk(KERN_NOTICE, sdkp,
				  "Enabling DIF Type %u protection\n", type);
	else
			break;
		case 0:
			sd_printk(KERN_NOTICE, sdkp,
				  "Disabling DIF Type %u protection\n", type);
			break;
		}

	sdkp->protection_type = type;

	return ret;
}

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,
	sector_size = get_unaligned_be32(&buffer[8]);
	lba = get_unaligned_be64(&buffer[0]);

	sd_read_protection_type(sdkp, buffer);
	if (sd_read_protection_type(sdkp, buffer) < 0) {
		sdkp->capacity = 0;
		return -ENODEV;
	}

	if ((sizeof(sdkp->capacity) == 4) && (lba >= 0xffffffffULL)) {
		sd_printk(KERN_ERR, sdkp, "Too big for this kernel. Use a "
@@ -2654,6 +2665,7 @@ static void sd_probe_async(void *data, async_cookie_t cookie)
	}

	add_disk(gd);
	if (sdkp->capacity)
		sd_dif_config_host(sdkp);

	sd_revalidate_disk(gd);
+6 −0
Original line number Diff line number Diff line
@@ -873,6 +873,9 @@ static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsign
				       SHOST_DIF_TYPE2_PROTECTION,
				       SHOST_DIF_TYPE3_PROTECTION };

	if (target_type > SHOST_DIF_TYPE3_PROTECTION)
		return 0;

	return shost->prot_capabilities & cap[target_type] ? target_type : 0;
}

@@ -884,6 +887,9 @@ static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsign
				       SHOST_DIX_TYPE2_PROTECTION,
				       SHOST_DIX_TYPE3_PROTECTION };

	if (target_type > SHOST_DIX_TYPE3_PROTECTION)
		return 0;

	return shost->prot_capabilities & cap[target_type];
#endif
	return 0;