diff options
| author | Martin K. Petersen <martin.petersen@oracle.com> | 2009-09-18 17:33:00 -0400 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2009-10-02 10:46:39 -0400 |
| commit | 35e1a5d90b66487d754ef2f2dcbf1007f806d921 (patch) | |
| tree | 964511498993ed8fe0c1604ab74ac7a3db9361ba | |
| parent | c6af404215bab0d333accbb497f835d10cb0050c (diff) | |
[SCSI] sd: Detach DIF from block integrity infrastructure
So far we have only issued DIF commands if CONFIG_BLK_DEV_INTEGRITY is
enabled. However, communication between initiator and target should be
independent of protection information DMA. There are DIF-only host
adapters coming out that will be able to take advantage of this.
Move the relevant DIF bits to sd.c.
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
| -rw-r--r-- | drivers/scsi/sd.c | 61 | ||||
| -rw-r--r-- | drivers/scsi/sd.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/sd_dif.c | 53 | ||||
| -rw-r--r-- | include/scsi/scsi_host.h | 15 |
4 files changed, 53 insertions, 80 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8dd96dcd716c..1e0a0b07dab6 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -370,6 +370,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp) | |||
| 370 | mutex_unlock(&sd_ref_mutex); | 370 | mutex_unlock(&sd_ref_mutex); |
| 371 | } | 371 | } |
| 372 | 372 | ||
| 373 | static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) | ||
| 374 | { | ||
| 375 | unsigned int prot_op = SCSI_PROT_NORMAL; | ||
| 376 | unsigned int dix = scsi_prot_sg_count(scmd); | ||
| 377 | |||
| 378 | if (scmd->sc_data_direction == DMA_FROM_DEVICE) { | ||
| 379 | if (dif && dix) | ||
| 380 | prot_op = SCSI_PROT_READ_PASS; | ||
| 381 | else if (dif && !dix) | ||
| 382 | prot_op = SCSI_PROT_READ_STRIP; | ||
| 383 | else if (!dif && dix) | ||
| 384 | prot_op = SCSI_PROT_READ_INSERT; | ||
| 385 | } else { | ||
| 386 | if (dif && dix) | ||
| 387 | prot_op = SCSI_PROT_WRITE_PASS; | ||
| 388 | else if (dif && !dix) | ||
| 389 | prot_op = SCSI_PROT_WRITE_INSERT; | ||
| 390 | else if (!dif && dix) | ||
| 391 | prot_op = SCSI_PROT_WRITE_STRIP; | ||
| 392 | } | ||
| 393 | |||
| 394 | scsi_set_prot_op(scmd, prot_op); | ||
| 395 | scsi_set_prot_type(scmd, dif); | ||
| 396 | } | ||
| 397 | |||
| 373 | /** | 398 | /** |
| 374 | * sd_init_command - build a scsi (read or write) command from | 399 | * sd_init_command - build a scsi (read or write) command from |
| 375 | * information in the request structure. | 400 | * information in the request structure. |
| @@ -578,8 +603,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 578 | 603 | ||
| 579 | /* If DIF or DIX is enabled, tell HBA how to handle request */ | 604 | /* If DIF or DIX is enabled, tell HBA how to handle request */ |
| 580 | if (host_dif || scsi_prot_sg_count(SCpnt)) | 605 | if (host_dif || scsi_prot_sg_count(SCpnt)) |
| 581 | sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt), | 606 | sd_prot_op(SCpnt, host_dif); |
| 582 | sdkp->protection_type); | ||
| 583 | 607 | ||
| 584 | /* | 608 | /* |
| 585 | * We shouldn't disconnect in the middle of a sector, so with a dumb | 609 | * We shouldn't disconnect in the middle of a sector, so with a dumb |
| @@ -1238,34 +1262,33 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
| 1238 | u8 type; | 1262 | u8 type; |
| 1239 | 1263 | ||
| 1240 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) | 1264 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) |
| 1241 | type = 0; | 1265 | return; |
| 1242 | else | 1266 | |
| 1243 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ | 1267 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ |
| 1268 | |||
| 1269 | if (type == sdkp->protection_type || !sdkp->first_scan) | ||
| 1270 | return; | ||
| 1244 | 1271 | ||
| 1245 | sdkp->protection_type = type; | 1272 | sdkp->protection_type = type; |
| 1246 | 1273 | ||
| 1247 | switch (type) { | 1274 | switch (type) { |
| 1248 | case SD_DIF_TYPE0_PROTECTION: | ||
| 1249 | case SD_DIF_TYPE1_PROTECTION: | 1275 | case SD_DIF_TYPE1_PROTECTION: |
| 1250 | case SD_DIF_TYPE3_PROTECTION: | 1276 | case SD_DIF_TYPE3_PROTECTION: |
| 1251 | break; | 1277 | break; |
| 1252 | 1278 | ||
| 1253 | case SD_DIF_TYPE2_PROTECTION: | ||
| 1254 | sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 " \ | ||
| 1255 | "protection which is currently unsupported. " \ | ||
| 1256 | "Disabling disk!\n"); | ||
| 1257 | goto disable; | ||
| 1258 | |||
| 1259 | default: | 1279 | default: |
| 1260 | sd_printk(KERN_ERR, sdkp, "formatted with unknown " \ | 1280 | sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ |
| 1261 | "protection type %d. Disabling disk!\n", type); | 1281 | "protection type %u. Disabling disk!\n", type); |
| 1262 | goto disable; | 1282 | sdkp->capacity = 0; |
| 1283 | return; | ||
| 1263 | } | 1284 | } |
| 1264 | 1285 | ||
| 1265 | return; | 1286 | if (scsi_host_dif_capable(sdp->host, type)) |
| 1266 | 1287 | sd_printk(KERN_NOTICE, sdkp, | |
| 1267 | disable: | 1288 | "Enabling DIF Type %u protection\n", type); |
| 1268 | sdkp->capacity = 0; | 1289 | else |
| 1290 | sd_printk(KERN_NOTICE, sdkp, | ||
| 1291 | "Disabling DIF Type %u protection\n", type); | ||
| 1269 | } | 1292 | } |
| 1270 | 1293 | ||
| 1271 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, | 1294 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, |
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index 8474b5bad3fe..ce1f5f899fe3 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
| @@ -101,16 +101,12 @@ struct sd_dif_tuple { | |||
| 101 | 101 | ||
| 102 | #ifdef CONFIG_BLK_DEV_INTEGRITY | 102 | #ifdef CONFIG_BLK_DEV_INTEGRITY |
| 103 | 103 | ||
| 104 | extern void sd_dif_op(struct scsi_cmnd *, unsigned int, unsigned int, unsigned int); | ||
| 105 | extern void sd_dif_config_host(struct scsi_disk *); | 104 | extern void sd_dif_config_host(struct scsi_disk *); |
| 106 | extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int); | 105 | extern int sd_dif_prepare(struct request *rq, sector_t, unsigned int); |
| 107 | extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); | 106 | extern void sd_dif_complete(struct scsi_cmnd *, unsigned int); |
| 108 | 107 | ||
| 109 | #else /* CONFIG_BLK_DEV_INTEGRITY */ | 108 | #else /* CONFIG_BLK_DEV_INTEGRITY */ |
| 110 | 109 | ||
| 111 | static inline void sd_dif_op(struct scsi_cmnd *cmd, unsigned int a, unsigned int b, unsigned int c) | ||
| 112 | { | ||
| 113 | } | ||
| 114 | static inline void sd_dif_config_host(struct scsi_disk *disk) | 110 | static inline void sd_dif_config_host(struct scsi_disk *disk) |
| 115 | { | 111 | { |
| 116 | } | 112 | } |
diff --git a/drivers/scsi/sd_dif.c b/drivers/scsi/sd_dif.c index 84224dd21acf..88da97745710 100644 --- a/drivers/scsi/sd_dif.c +++ b/drivers/scsi/sd_dif.c | |||
| @@ -320,15 +320,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp) | |||
| 320 | dif = 0; dix = 1; | 320 | dif = 0; dix = 1; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | if (type) { | ||
| 324 | if (dif) | ||
| 325 | sd_printk(KERN_NOTICE, sdkp, | ||
| 326 | "Enabling DIF Type %d protection\n", type); | ||
| 327 | else | ||
| 328 | sd_printk(KERN_NOTICE, sdkp, | ||
| 329 | "Disabling DIF Type %d protection\n", type); | ||
| 330 | } | ||
| 331 | |||
| 332 | if (!dix) | 323 | if (!dix) |
| 333 | return; | 324 | return; |
| 334 | 325 | ||
| @@ -360,50 +351,6 @@ void sd_dif_config_host(struct scsi_disk *sdkp) | |||
| 360 | } | 351 | } |
| 361 | 352 | ||
| 362 | /* | 353 | /* |
| 363 | * DIF DMA operation magic decoder ring. | ||
| 364 | */ | ||
| 365 | void sd_dif_op(struct scsi_cmnd *scmd, unsigned int dif, unsigned int dix, unsigned int type) | ||
| 366 | { | ||
| 367 | int prot_op; | ||
| 368 | |||
| 369 | prot_op = SCSI_PROT_NORMAL; | ||
| 370 | |||
| 371 | BUG_ON(dif && (scmd->cmnd[0] == READ_6 || scmd->cmnd[0] == WRITE_6)); | ||
| 372 | |||
| 373 | switch (scmd->cmnd[0]) { | ||
| 374 | case READ_6: | ||
| 375 | case READ_10: | ||
| 376 | case READ_12: | ||
| 377 | case READ_16: | ||
| 378 | if (dif && dix) | ||
| 379 | prot_op = SCSI_PROT_READ_PASS; | ||
| 380 | else if (dif && !dix) | ||
| 381 | prot_op = SCSI_PROT_READ_STRIP; | ||
| 382 | else if (!dif && dix) | ||
| 383 | prot_op = SCSI_PROT_READ_INSERT; | ||
| 384 | |||
| 385 | break; | ||
| 386 | |||
| 387 | case WRITE_6: | ||
| 388 | case WRITE_10: | ||
| 389 | case WRITE_12: | ||
| 390 | case WRITE_16: | ||
| 391 | if (dif && dix) | ||
| 392 | prot_op = SCSI_PROT_WRITE_PASS; | ||
| 393 | else if (dif && !dix) | ||
| 394 | prot_op = SCSI_PROT_WRITE_INSERT; | ||
| 395 | else if (!dif && dix) | ||
| 396 | prot_op = SCSI_PROT_WRITE_STRIP; | ||
| 397 | |||
| 398 | break; | ||
| 399 | } | ||
| 400 | |||
| 401 | scsi_set_prot_op(scmd, prot_op); | ||
| 402 | if (dif) | ||
| 403 | scsi_set_prot_type(scmd, type); | ||
| 404 | } | ||
| 405 | |||
| 406 | /* | ||
| 407 | * The virtual start sector is the one that was originally submitted | 354 | * The virtual start sector is the one that was originally submitted |
| 408 | * by the block layer. Due to partitioning, MD/DM cloning, etc. the | 355 | * by the block layer. Due to partitioning, MD/DM cloning, etc. the |
| 409 | * actual physical start sector is likely to be different. Remap | 356 | * actual physical start sector is likely to be different. Remap |
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h index b62a097b3ecb..6e728b176904 100644 --- a/include/scsi/scsi_host.h +++ b/include/scsi/scsi_host.h | |||
| @@ -798,9 +798,15 @@ static inline unsigned int scsi_host_get_prot(struct Scsi_Host *shost) | |||
| 798 | static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type) | 798 | static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsigned int target_type) |
| 799 | { | 799 | { |
| 800 | switch (target_type) { | 800 | switch (target_type) { |
| 801 | case 1: return shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION; | 801 | case 1: |
| 802 | case 2: return shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION; | 802 | if (shost->prot_capabilities & SHOST_DIF_TYPE1_PROTECTION) |
| 803 | case 3: return shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION; | 803 | return target_type; |
| 804 | case 2: | ||
| 805 | if (shost->prot_capabilities & SHOST_DIF_TYPE2_PROTECTION) | ||
| 806 | return target_type; | ||
| 807 | case 3: | ||
| 808 | if (shost->prot_capabilities & SHOST_DIF_TYPE3_PROTECTION) | ||
| 809 | return target_type; | ||
| 804 | } | 810 | } |
| 805 | 811 | ||
| 806 | return 0; | 812 | return 0; |
| @@ -808,13 +814,14 @@ static inline unsigned int scsi_host_dif_capable(struct Scsi_Host *shost, unsign | |||
| 808 | 814 | ||
| 809 | static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type) | 815 | static inline unsigned int scsi_host_dix_capable(struct Scsi_Host *shost, unsigned int target_type) |
| 810 | { | 816 | { |
| 817 | #if defined(CONFIG_BLK_DEV_INTEGRITY) | ||
| 811 | switch (target_type) { | 818 | switch (target_type) { |
| 812 | case 0: return shost->prot_capabilities & SHOST_DIX_TYPE0_PROTECTION; | 819 | case 0: return shost->prot_capabilities & SHOST_DIX_TYPE0_PROTECTION; |
| 813 | case 1: return shost->prot_capabilities & SHOST_DIX_TYPE1_PROTECTION; | 820 | case 1: return shost->prot_capabilities & SHOST_DIX_TYPE1_PROTECTION; |
| 814 | case 2: return shost->prot_capabilities & SHOST_DIX_TYPE2_PROTECTION; | 821 | case 2: return shost->prot_capabilities & SHOST_DIX_TYPE2_PROTECTION; |
| 815 | case 3: return shost->prot_capabilities & SHOST_DIX_TYPE3_PROTECTION; | 822 | case 3: return shost->prot_capabilities & SHOST_DIX_TYPE3_PROTECTION; |
| 816 | } | 823 | } |
| 817 | 824 | #endif | |
| 818 | return 0; | 825 | return 0; |
| 819 | } | 826 | } |
| 820 | 827 | ||
