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 */ |