aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2008-09-19 18:47:21 -0400
committerJames Bottomley <James.Bottomley@HansenPartnership.com>2008-10-13 09:28:58 -0400
commit9e06688e7d60149cc9ef78ff29515c20186bb418 (patch)
treecb6df4657c1964244a51d6ad3a5a54b849b93894 /drivers
parentbe922f478f430f8fab4db952ffc20c86f23de397 (diff)
[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: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/scsi/sd.c3
-rw-r--r--drivers/scsi/sd.h2
-rw-r--r--drivers/scsi/sd_dif.c37
3 files changed, 23 insertions, 19 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index a494a2ec67d7..7c4d2e68df1c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -575,7 +575,8 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
575 575
576 /* If DIF or DIX is enabled, tell HBA how to handle request */ 576 /* If DIF or DIX is enabled, tell HBA how to handle request */
577 if (host_dif || scsi_prot_sg_count(SCpnt)) 577 if (host_dif || scsi_prot_sg_count(SCpnt))
578 sd_dif_op(SCpnt, sdkp->protection_type, scsi_prot_sg_count(SCpnt)); 578 sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt),
579 sdkp->protection_type);
579 580
580 /* 581 /*
581 * We shouldn't disconnect in the middle of a sector, so with a dumb 582 * We shouldn't disconnect in the middle of a sector, so with a dumb
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 95b9f06534d5..a92b991d98ab 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -99,7 +99,7 @@ struct sd_dif_tuple {
99 99
100#if defined(CONFIG_BLK_DEV_INTEGRITY) 100#if defined(CONFIG_BLK_DEV_INTEGRITY)
101 101
102extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int); 102extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int, unsigned int);
103extern void sd_dif_config_host(struct scsi_disk *); 103extern void sd_dif_config_host(struct scsi_disk *);
104extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int); 104extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int);
105extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); 105extern void sd_dif_complete(struct scsi_cmnd *, unsigned int);
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c
index 943fde7e7ffb..194c7706083b 100644
--- a/drivers/scsi/sd_dif.c
+++ b/drivers/scsi/sd_dif.c
@@ -311,24 +311,26 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
311 struct scsi_device *sdp = sdkp->device; 311 struct scsi_device *sdp = sdkp->device;
312 struct gendisk *disk = sdkp->disk; 312 struct gendisk *disk = sdkp->disk;
313 u8 type = sdkp->protection_type; 313 u8 type = sdkp->protection_type;
314 int dif, dix;
314 315
315 /* If this HBA doesn't support DIX, resort to normal I/O or DIF */ 316 dif = scsi_host_dif_capable(sdp->host, type);
316 if (scsi_host_dix_capable(sdp->host, type) == 0) { 317 dix = scsi_host_dix_capable(sdp->host, type);
317 318
318 if (type == SD_DIF_TYPE0_PROTECTION) 319 if (!dix && scsi_host_dix_capable(sdp->host, 0)) {
319 return; 320 dif = 0; dix = 1;
320 321 }
321 if (scsi_host_dif_capable(sdp->host, type) == 0) {
322 sd_printk(KERN_INFO, sdkp, "Type %d protection " \
323 "unsupported by HBA. Disabling DIF.\n", type);
324 return;
325 }
326 322
327 sd_printk(KERN_INFO, sdkp, "Enabling DIF Type %d protection\n", 323 if (type) {
328 type); 324 if (dif)
325 sd_printk(KERN_INFO, sdkp,
326 "Enabling DIF Type %d protection\n", type);
327 else
328 sd_printk(KERN_INFO, sdkp,
329 "Disabling DIF Type %d protection\n", type);
330 }
329 331
332 if (!dix)
330 return; 333 return;
331 }
332 334
333 /* Enable DMA of protection information */ 335 /* Enable DMA of protection information */
334 if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) 336 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 blk_integrity_register(disk, &dif_type1_integrity_crc); 345 blk_integrity_register(disk, &dif_type1_integrity_crc);
344 346
345 sd_printk(KERN_INFO, sdkp, 347 sd_printk(KERN_INFO, sdkp,
346 "Enabling %s integrity protection\n", disk->integrity->name); 348 "Enabling DIX %s protection\n", disk->integrity->name);
347 349
348 /* Signal to block layer that we support sector tagging */ 350 /* Signal to block layer that we support sector tagging */
349 if (type && sdkp->ATO) { 351 if (dif && type && sdkp->ATO) {
350 if (type == SD_DIF_TYPE3_PROTECTION) 352 if (type == SD_DIF_TYPE3_PROTECTION)
351 disk->integrity->tag_size = sizeof(u16) + sizeof(u32); 353 disk->integrity->tag_size = sizeof(u16) + sizeof(u32);
352 else 354 else
@@ -360,7 +362,7 @@ void sd_dif_config_host(struct scsi_disk *sdkp)
360/* 362/*
361 * DIF DMA operation magic decoder ring. 363 * DIF DMA operation magic decoder ring.
362 */ 364 */
363void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix) 365void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsigned int type)
364{ 366{
365 int csum_convert, prot_op; 367 int csum_convert, prot_op;
366 368
@@ -405,7 +407,8 @@ void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix)
405 } 407 }
406 408
407 scsi_set_prot_op(scmd, prot_op); 409 scsi_set_prot_op(scmd, prot_op);
408 scsi_set_prot_type(scmd, dif); 410 if (dif)
411 scsi_set_prot_type(scmd, type);
409} 412}
410 413
411/* 414/*