Skip to content

Commit

Permalink
[SCSI] sd: Correctly handle all combinations of DIF and DIX
Browse files Browse the repository at this point in the history
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: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
  • Loading branch information
Martin K. Petersen authored and James Bottomley committed Oct 13, 2008
1 parent be922f4 commit 9e06688
Show file tree
Hide file tree
Showing 3 changed files with 23 additions and 19 deletions.
3 changes: 2 additions & 1 deletion drivers/scsi/sd.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 (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
Expand Down
2 changes: 1 addition & 1 deletion drivers/scsi/sd.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ struct sd_dif_tuple {

#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 int sd_dif_prepare(struct request *rq, sector_t, unsigned int);
extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
Expand Down
37 changes: 20 additions & 17 deletions drivers/scsi/sd_dif.c
Original file line number Diff line number Diff line change
Expand Up @@ -311,24 +311,26 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
struct scsi_device *sdp = sdkp->device;
struct gendisk *disk = sdkp->disk;
u8 type = sdkp->protection_type;
int dif, dix;

/* If this HBA doesn't support DIX, resort to normal I/O or DIF */
if (scsi_host_dix_capable(sdp->host, type) == 0) {
dif = scsi_host_dif_capable(sdp->host, type);
dix = scsi_host_dix_capable(sdp->host, type);

if (type == SD_DIF_TYPE0_PROTECTION)
return;

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;
}
if (!dix && scsi_host_dix_capable(sdp->host, 0)) {
dif = 0; dix = 1;
}

sd_printk(KERN_INFO, sdkp, "Enabling DIF Type %d protection\n",
type);
if (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;
}

/* Enable DMA of protection information */
if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP)
Expand All @@ -343,10 +345,10 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
blk_integrity_register(disk, &dif_type1_integrity_crc);

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 */
if (type && sdkp->ATO) {
if (dif && type && sdkp->ATO) {
if (type == SD_DIF_TYPE3_PROTECTION)
disk->integrity->tag_size = sizeof(u16) + sizeof(u32);
else
Expand All @@ -360,7 +362,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
/*
* 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;

Expand Down Expand Up @@ -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_type(scmd, dif);
if (dif)
scsi_set_prot_type(scmd, type);
}

/*
Expand Down

0 comments on commit 9e06688

Please sign in to comment.