diff options
| author | Martin K. Petersen <martin.petersen@oracle.com> | 2009-09-20 16:49:38 -0400 |
|---|---|---|
| committer | James Bottomley <James.Bottomley@suse.de> | 2009-10-02 10:47:04 -0400 |
| commit | 4e7392ec582cf06753b0969ca9ab959923e38493 (patch) | |
| tree | b630b857bd004612c14d4abe622c082b975e22fe | |
| parent | b4c2554d40ceac130a8d062eaa8838ed22158c45 (diff) | |
[SCSI] sd: Support disks formatted with DIF Type 2
Disks formatted with DIF Type 2 reject READ/WRITE 6/10/12/16 commands
when protection is enabled. Only the 32-byte variants are supported.
Implement support for issusing 32-byte READ/WRITE and enable Type 2
drives in the protection type detection logic.
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 | 81 | ||||
| -rw-r--r-- | drivers/scsi/sd.h | 5 | ||||
| -rw-r--r-- | include/scsi/scsi.h | 3 |
3 files changed, 78 insertions, 11 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 1e0a0b07dab6..9093c7261f33 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c | |||
| @@ -116,6 +116,9 @@ static DEFINE_IDA(sd_index_ida); | |||
| 116 | * object after last put) */ | 116 | * object after last put) */ |
| 117 | static DEFINE_MUTEX(sd_ref_mutex); | 117 | static DEFINE_MUTEX(sd_ref_mutex); |
| 118 | 118 | ||
| 119 | struct kmem_cache *sd_cdb_cache; | ||
| 120 | mempool_t *sd_cdb_pool; | ||
| 121 | |||
| 119 | static const char *sd_cache_types[] = { | 122 | static const char *sd_cache_types[] = { |
| 120 | "write through", "none", "write back", | 123 | "write through", "none", "write back", |
| 121 | "write back, no read (daft)" | 124 | "write back, no read (daft)" |
| @@ -413,6 +416,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 413 | sector_t threshold; | 416 | sector_t threshold; |
| 414 | unsigned int this_count = blk_rq_sectors(rq); | 417 | unsigned int this_count = blk_rq_sectors(rq); |
| 415 | int ret, host_dif; | 418 | int ret, host_dif; |
| 419 | unsigned char protect; | ||
| 416 | 420 | ||
| 417 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { | 421 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { |
| 418 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); | 422 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); |
| @@ -545,13 +549,49 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 545 | /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ | 549 | /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ |
| 546 | host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); | 550 | host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); |
| 547 | if (host_dif) | 551 | if (host_dif) |
| 548 | SCpnt->cmnd[1] = 1 << 5; | 552 | protect = 1 << 5; |
| 549 | else | 553 | else |
| 550 | SCpnt->cmnd[1] = 0; | 554 | protect = 0; |
| 555 | |||
| 556 | if (host_dif == SD_DIF_TYPE2_PROTECTION) { | ||
| 557 | SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC); | ||
| 558 | |||
| 559 | if (unlikely(SCpnt->cmnd == NULL)) { | ||
| 560 | ret = BLKPREP_DEFER; | ||
| 561 | goto out; | ||
| 562 | } | ||
| 551 | 563 | ||
| 552 | if (block > 0xffffffff) { | 564 | SCpnt->cmd_len = SD_EXT_CDB_SIZE; |
| 565 | memset(SCpnt->cmnd, 0, SCpnt->cmd_len); | ||
| 566 | SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD; | ||
| 567 | SCpnt->cmnd[7] = 0x18; | ||
| 568 | SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32; | ||
| 569 | SCpnt->cmnd[10] = protect | (blk_fua_rq(rq) ? 0x8 : 0); | ||
| 570 | |||
| 571 | /* LBA */ | ||
| 572 | SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; | ||
| 573 | SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; | ||
| 574 | SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; | ||
| 575 | SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0; | ||
| 576 | SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff; | ||
| 577 | SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff; | ||
| 578 | SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff; | ||
| 579 | SCpnt->cmnd[19] = (unsigned char) block & 0xff; | ||
| 580 | |||
| 581 | /* Expected Indirect LBA */ | ||
| 582 | SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff; | ||
| 583 | SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff; | ||
| 584 | SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff; | ||
| 585 | SCpnt->cmnd[23] = (unsigned char) block & 0xff; | ||
| 586 | |||
| 587 | /* Transfer length */ | ||
| 588 | SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff; | ||
| 589 | SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff; | ||
| 590 | SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff; | ||
| 591 | SCpnt->cmnd[31] = (unsigned char) this_count & 0xff; | ||
| 592 | } else if (block > 0xffffffff) { | ||
| 553 | SCpnt->cmnd[0] += READ_16 - READ_6; | 593 | SCpnt->cmnd[0] += READ_16 - READ_6; |
| 554 | SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; | 594 | SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); |
| 555 | SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; | 595 | SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; |
| 556 | SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; | 596 | SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; |
| 557 | SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; | 597 | SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; |
| @@ -572,7 +612,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
| 572 | this_count = 0xffff; | 612 | this_count = 0xffff; |
| 573 | 613 | ||
| 574 | SCpnt->cmnd[0] += READ_10 - READ_6; | 614 | SCpnt->cmnd[0] += READ_10 - READ_6; |
| 575 | SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; | 615 | SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); |
| 576 | SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; | 616 | SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; |
| 577 | SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; | 617 | SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; |
| 578 | SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; | 618 | SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; |
| @@ -1047,6 +1087,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
| 1047 | int result = SCpnt->result; | 1087 | int result = SCpnt->result; |
| 1048 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); | 1088 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); |
| 1049 | struct scsi_sense_hdr sshdr; | 1089 | struct scsi_sense_hdr sshdr; |
| 1090 | struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); | ||
| 1050 | int sense_valid = 0; | 1091 | int sense_valid = 0; |
| 1051 | int sense_deferred = 0; | 1092 | int sense_deferred = 0; |
| 1052 | 1093 | ||
| @@ -1108,6 +1149,10 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
| 1108 | if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt)) | 1149 | if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt)) |
| 1109 | sd_dif_complete(SCpnt, good_bytes); | 1150 | sd_dif_complete(SCpnt, good_bytes); |
| 1110 | 1151 | ||
| 1152 | if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type) | ||
| 1153 | == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) | ||
| 1154 | mempool_free(SCpnt->cmnd, sd_cdb_pool); | ||
| 1155 | |||
| 1111 | return good_bytes; | 1156 | return good_bytes; |
| 1112 | } | 1157 | } |
| 1113 | 1158 | ||
| @@ -1271,12 +1316,7 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
| 1271 | 1316 | ||
| 1272 | sdkp->protection_type = type; | 1317 | sdkp->protection_type = type; |
| 1273 | 1318 | ||
| 1274 | switch (type) { | 1319 | if (type > SD_DIF_TYPE3_PROTECTION) { |
| 1275 | case SD_DIF_TYPE1_PROTECTION: | ||
| 1276 | case SD_DIF_TYPE3_PROTECTION: | ||
| 1277 | break; | ||
| 1278 | |||
| 1279 | default: | ||
| 1280 | sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ | 1320 | sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ |
| 1281 | "protection type %u. Disabling disk!\n", type); | 1321 | "protection type %u. Disabling disk!\n", type); |
| 1282 | sdkp->capacity = 0; | 1322 | sdkp->capacity = 0; |
| @@ -2323,8 +2363,24 @@ static int __init init_sd(void) | |||
| 2323 | if (err) | 2363 | if (err) |
| 2324 | goto err_out_class; | 2364 | goto err_out_class; |
| 2325 | 2365 | ||
| 2366 | sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE, | ||
| 2367 | 0, 0, NULL); | ||
| 2368 | if (!sd_cdb_cache) { | ||
| 2369 | printk(KERN_ERR "sd: can't init extended cdb cache\n"); | ||
| 2370 | goto err_out_class; | ||
| 2371 | } | ||
| 2372 | |||
| 2373 | sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache); | ||
| 2374 | if (!sd_cdb_pool) { | ||
| 2375 | printk(KERN_ERR "sd: can't init extended cdb pool\n"); | ||
| 2376 | goto err_out_cache; | ||
| 2377 | } | ||
| 2378 | |||
| 2326 | return 0; | 2379 | return 0; |
| 2327 | 2380 | ||
| 2381 | err_out_cache: | ||
| 2382 | kmem_cache_destroy(sd_cdb_cache); | ||
| 2383 | |||
| 2328 | err_out_class: | 2384 | err_out_class: |
| 2329 | class_unregister(&sd_disk_class); | 2385 | class_unregister(&sd_disk_class); |
| 2330 | err_out: | 2386 | err_out: |
| @@ -2344,6 +2400,9 @@ static void __exit exit_sd(void) | |||
| 2344 | 2400 | ||
| 2345 | SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); | 2401 | SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); |
| 2346 | 2402 | ||
| 2403 | mempool_destroy(sd_cdb_pool); | ||
| 2404 | kmem_cache_destroy(sd_cdb_cache); | ||
| 2405 | |||
| 2347 | scsi_unregister_driver(&sd_template.gendrv); | 2406 | scsi_unregister_driver(&sd_template.gendrv); |
| 2348 | class_unregister(&sd_disk_class); | 2407 | class_unregister(&sd_disk_class); |
| 2349 | 2408 | ||
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h index ce1f5f899fe3..e374804d26fb 100644 --- a/drivers/scsi/sd.h +++ b/drivers/scsi/sd.h | |||
| @@ -37,6 +37,11 @@ | |||
| 37 | */ | 37 | */ |
| 38 | #define SD_LAST_BUGGY_SECTORS 8 | 38 | #define SD_LAST_BUGGY_SECTORS 8 |
| 39 | 39 | ||
| 40 | enum { | ||
| 41 | SD_EXT_CDB_SIZE = 32, /* Extended CDB size */ | ||
| 42 | SD_MEMPOOL_SIZE = 2, /* CDB pool size */ | ||
| 43 | }; | ||
| 44 | |||
| 40 | struct scsi_disk { | 45 | struct scsi_disk { |
| 41 | struct scsi_driver *driver; /* always &sd_template */ | 46 | struct scsi_driver *driver; /* always &sd_template */ |
| 42 | struct scsi_device *device; | 47 | struct scsi_device *device; |
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index 084478e14d24..34c46ab5c31b 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h | |||
| @@ -129,6 +129,9 @@ struct scsi_cmnd; | |||
| 129 | #define MI_REPORT_TARGET_PGS 0x0a | 129 | #define MI_REPORT_TARGET_PGS 0x0a |
| 130 | /* values for maintenance out */ | 130 | /* values for maintenance out */ |
| 131 | #define MO_SET_TARGET_PGS 0x0a | 131 | #define MO_SET_TARGET_PGS 0x0a |
| 132 | /* values for variable length command */ | ||
| 133 | #define READ_32 0x09 | ||
| 134 | #define WRITE_32 0x0b | ||
| 132 | 135 | ||
| 133 | /* Values for T10/04-262r7 */ | 136 | /* Values for T10/04-262r7 */ |
| 134 | #define ATA_16 0x85 /* 16-byte pass-thru */ | 137 | #define ATA_16 0x85 /* 16-byte pass-thru */ |
