Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[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>

authored by

Martin K. Petersen and committed by
James Bottomley
4e7392ec b4c2554d

+78 -11
+70 -11
drivers/scsi/sd.c
··· 116 116 * object after last put) */ 117 117 static DEFINE_MUTEX(sd_ref_mutex); 118 118 119 + struct kmem_cache *sd_cdb_cache; 120 + mempool_t *sd_cdb_pool; 121 + 119 122 static const char *sd_cache_types[] = { 120 123 "write through", "none", "write back", 121 124 "write back, no read (daft)" ··· 416 413 sector_t threshold; 417 414 unsigned int this_count = blk_rq_sectors(rq); 418 415 int ret, host_dif; 416 + unsigned char protect; 419 417 420 418 if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { 421 419 ret = scsi_setup_blk_pc_cmnd(sdp, rq); ··· 549 545 /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ 550 546 host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); 551 547 if (host_dif) 552 - SCpnt->cmnd[1] = 1 << 5; 548 + protect = 1 << 5; 553 549 else 554 - SCpnt->cmnd[1] = 0; 550 + protect = 0; 555 551 556 - if (block > 0xffffffff) { 552 + if (host_dif == SD_DIF_TYPE2_PROTECTION) { 553 + SCpnt->cmnd = mempool_alloc(sd_cdb_pool, GFP_ATOMIC); 554 + 555 + if (unlikely(SCpnt->cmnd == NULL)) { 556 + ret = BLKPREP_DEFER; 557 + goto out; 558 + } 559 + 560 + SCpnt->cmd_len = SD_EXT_CDB_SIZE; 561 + memset(SCpnt->cmnd, 0, SCpnt->cmd_len); 562 + SCpnt->cmnd[0] = VARIABLE_LENGTH_CMD; 563 + SCpnt->cmnd[7] = 0x18; 564 + SCpnt->cmnd[9] = (rq_data_dir(rq) == READ) ? READ_32 : WRITE_32; 565 + SCpnt->cmnd[10] = protect | (blk_fua_rq(rq) ? 0x8 : 0); 566 + 567 + /* LBA */ 568 + SCpnt->cmnd[12] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; 569 + SCpnt->cmnd[13] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; 570 + SCpnt->cmnd[14] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; 571 + SCpnt->cmnd[15] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0; 572 + SCpnt->cmnd[16] = (unsigned char) (block >> 24) & 0xff; 573 + SCpnt->cmnd[17] = (unsigned char) (block >> 16) & 0xff; 574 + SCpnt->cmnd[18] = (unsigned char) (block >> 8) & 0xff; 575 + SCpnt->cmnd[19] = (unsigned char) block & 0xff; 576 + 577 + /* Expected Indirect LBA */ 578 + SCpnt->cmnd[20] = (unsigned char) (block >> 24) & 0xff; 579 + SCpnt->cmnd[21] = (unsigned char) (block >> 16) & 0xff; 580 + SCpnt->cmnd[22] = (unsigned char) (block >> 8) & 0xff; 581 + SCpnt->cmnd[23] = (unsigned char) block & 0xff; 582 + 583 + /* Transfer length */ 584 + SCpnt->cmnd[28] = (unsigned char) (this_count >> 24) & 0xff; 585 + SCpnt->cmnd[29] = (unsigned char) (this_count >> 16) & 0xff; 586 + SCpnt->cmnd[30] = (unsigned char) (this_count >> 8) & 0xff; 587 + SCpnt->cmnd[31] = (unsigned char) this_count & 0xff; 588 + } else if (block > 0xffffffff) { 557 589 SCpnt->cmnd[0] += READ_16 - READ_6; 558 - SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; 590 + SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); 559 591 SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0; 560 592 SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0; 561 593 SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0; ··· 612 572 this_count = 0xffff; 613 573 614 574 SCpnt->cmnd[0] += READ_10 - READ_6; 615 - SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; 575 + SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); 616 576 SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; 617 577 SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; 618 578 SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; ··· 1087 1047 int result = SCpnt->result; 1088 1048 unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); 1089 1049 struct scsi_sense_hdr sshdr; 1050 + struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); 1090 1051 int sense_valid = 0; 1091 1052 int sense_deferred = 0; 1092 1053 ··· 1148 1107 out: 1149 1108 if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt)) 1150 1109 sd_dif_complete(SCpnt, good_bytes); 1110 + 1111 + if (scsi_host_dif_capable(sdkp->device->host, sdkp->protection_type) 1112 + == SD_DIF_TYPE2_PROTECTION && SCpnt->cmnd != SCpnt->request->cmd) 1113 + mempool_free(SCpnt->cmnd, sd_cdb_pool); 1151 1114 1152 1115 return good_bytes; 1153 1116 } ··· 1316 1271 1317 1272 sdkp->protection_type = type; 1318 1273 1319 - switch (type) { 1320 - case SD_DIF_TYPE1_PROTECTION: 1321 - case SD_DIF_TYPE3_PROTECTION: 1322 - break; 1323 - 1324 - default: 1274 + if (type > SD_DIF_TYPE3_PROTECTION) { 1325 1275 sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ 1326 1276 "protection type %u. Disabling disk!\n", type); 1327 1277 sdkp->capacity = 0; ··· 2363 2323 if (err) 2364 2324 goto err_out_class; 2365 2325 2326 + sd_cdb_cache = kmem_cache_create("sd_ext_cdb", SD_EXT_CDB_SIZE, 2327 + 0, 0, NULL); 2328 + if (!sd_cdb_cache) { 2329 + printk(KERN_ERR "sd: can't init extended cdb cache\n"); 2330 + goto err_out_class; 2331 + } 2332 + 2333 + sd_cdb_pool = mempool_create_slab_pool(SD_MEMPOOL_SIZE, sd_cdb_cache); 2334 + if (!sd_cdb_pool) { 2335 + printk(KERN_ERR "sd: can't init extended cdb pool\n"); 2336 + goto err_out_cache; 2337 + } 2338 + 2366 2339 return 0; 2340 + 2341 + err_out_cache: 2342 + kmem_cache_destroy(sd_cdb_cache); 2367 2343 2368 2344 err_out_class: 2369 2345 class_unregister(&sd_disk_class); ··· 2399 2343 int i; 2400 2344 2401 2345 SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); 2346 + 2347 + mempool_destroy(sd_cdb_pool); 2348 + kmem_cache_destroy(sd_cdb_cache); 2402 2349 2403 2350 scsi_unregister_driver(&sd_template.gendrv); 2404 2351 class_unregister(&sd_disk_class);
+5
drivers/scsi/sd.h
··· 37 37 */ 38 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 45 struct scsi_disk { 41 46 struct scsi_driver *driver; /* always &sd_template */ 42 47 struct scsi_device *device;
+3
include/scsi/scsi.h
··· 129 129 #define MI_REPORT_TARGET_PGS 0x0a 130 130 /* values for maintenance out */ 131 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 136 /* Values for T10/04-262r7 */ 134 137 #define ATA_16 0x85 /* 16-byte pass-thru */