aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin K. Petersen <martin.petersen@oracle.com>2009-09-20 16:49:38 -0400
committerJames Bottomley <James.Bottomley@suse.de>2009-10-02 10:47:04 -0400
commit4e7392ec582cf06753b0969ca9ab959923e38493 (patch)
treeb630b857bd004612c14d4abe622c082b975e22fe
parentb4c2554d40ceac130a8d062eaa8838ed22158c45 (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.c81
-rw-r--r--drivers/scsi/sd.h5
-rw-r--r--include/scsi/scsi.h3
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) */
117static DEFINE_MUTEX(sd_ref_mutex); 117static DEFINE_MUTEX(sd_ref_mutex);
118 118
119struct kmem_cache *sd_cdb_cache;
120mempool_t *sd_cdb_pool;
121
119static const char *sd_cache_types[] = { 122static 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
2381err_out_cache:
2382 kmem_cache_destroy(sd_cdb_cache);
2383
2328err_out_class: 2384err_out_class:
2329 class_unregister(&sd_disk_class); 2385 class_unregister(&sd_disk_class);
2330err_out: 2386err_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
40enum {
41 SD_EXT_CDB_SIZE = 32, /* Extended CDB size */
42 SD_MEMPOOL_SIZE = 2, /* CDB pool size */
43};
44
40struct scsi_disk { 45struct 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 */