Commit 9e06688e authored by Martin K. Petersen's avatar Martin K. Petersen Committed by James Bottomley

[SCSI] sd: Correctly handle all combinations of DIF and DIX

The old detection code couldn't handle all possible combinations of
DIX and DIF.  This version does, giving priority to DIX if the
controller is capable.
Signed-off-by: default avatarMartin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent be922f47
...@@ -575,7 +575,8 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) ...@@ -575,7 +575,8 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
/* If DIF or DIX is enabled, tell HBA how to handle request */ /* If DIF or DIX is enabled, tell HBA how to handle request */
if (host_dif || scsi_prot_sg_count(SCpnt)) if (host_dif || scsi_prot_sg_count(SCpnt))
sd_dif_op(SCpnt, sdkp->protection_type, scsi_prot_sg_count(SCpnt)); sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt),
sdkp->protection_type);
/* /*
* We shouldn't disconnect in the middle of a sector, so with a dumb * We shouldn't disconnect in the middle of a sector, so with a dumb
......
...@@ -99,7 +99,7 @@ struct sd_dif_tuple { ...@@ -99,7 +99,7 @@ struct sd_dif_tuple {
#if defined(CONFIG_BLK_DEV_INTEGRITY) #if defined(CONFIG_BLK_DEV_INTEGRITY)
extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int); extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int, unsigned int);
extern void sd_dif_config_host(struct scsi_disk *); extern void sd_dif_config_host(struct scsi_disk *);
extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int); extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int);
extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
......
...@@ -311,24 +311,26 @@ void sd_dif_config_host(struct scsi_disk *sdkp) ...@@ -311,24 +311,26 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
struct scsi_device *sdp = sdkp->device; struct scsi_device *sdp = sdkp->device;
struct gendisk *disk = sdkp->disk; struct gendisk *disk = sdkp->disk;
u8 type = sdkp->protection_type; u8 type = sdkp->protection_type;
int dif, dix;
/* If this HBA doesn't support DIX, resort to normal I/O or DIF */ dif = scsi_host_dif_capable(sdp->host, type);
if (scsi_host_dix_capable(sdp->host, type) == 0) { dix = scsi_host_dix_capable(sdp->host, type);
if (type == SD_DIF_TYPE0_PROTECTION) if (!dix && scsi_host_dix_capable(sdp->host, 0)) {
return; dif = 0; dix = 1;
if (scsi_host_dif_capable(sdp->host, type) == 0) {
sd_printk(KERN_INFO, sdkp, "Type %d protection " \
"unsupported by HBA. Disabling DIF.\n", type);
return;
} }
sd_printk(KERN_INFO, sdkp, "Enabling DIF Type %d protection\n", if (type) {
type); if (dif)
sd_printk(KERN_INFO, sdkp,
"Enabling DIF Type %d protection\n", type);
else
sd_printk(KERN_INFO, sdkp,
"Disabling DIF Type %d protection\n", type);
}
if (!dix)
return; return;
}
/* Enable DMA of protection information */ /* Enable DMA of protection information */
if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP)
...@@ -343,10 +345,10 @@ void sd_dif_config_host(struct scsi_disk *sdkp) ...@@ -343,10 +345,10 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
blk_integrity_register(disk, &dif_type1_integrity_crc); blk_integrity_register(disk, &dif_type1_integrity_crc);
sd_printk(KERN_INFO, sdkp, sd_printk(KERN_INFO, sdkp,
"Enabling %s integrity protection\n", disk->integrity->name); "Enabling DIX %s protection\n", disk->integrity->name);
/* Signal to block layer that we support sector tagging */ /* Signal to block layer that we support sector tagging */
if (type && sdkp->ATO) { if (dif && type && sdkp->ATO) {
if (type == SD_DIF_TYPE3_PROTECTION) if (type == SD_DIF_TYPE3_PROTECTION)
disk->integrity->tag_size = sizeof(u16) + sizeof(u32); disk->integrity->tag_size = sizeof(u16) + sizeof(u32);
else else
...@@ -360,7 +362,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp) ...@@ -360,7 +362,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
/* /*
* DIF DMA operation magic decoder ring. * DIF DMA operation magic decoder ring.
*/ */
void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix) void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsigned int type)
{ {
int csum_convert, prot_op; int csum_convert, prot_op;
...@@ -405,7 +407,8 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix) ...@@ -405,7 +407,8 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix)
} }
scsi_set_prot_op(scmd, prot_op); scsi_set_prot_op(scmd, prot_op);
scsi_set_prot_type(scmd, dif); if (dif)
scsi_set_prot_type(scmd, type);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment