Skip to content

Commit 4e7392e

Browse files
martinkpetersenJames Bottomley
authored andcommitted
[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>
1 parent b4c2554 commit 4e7392e

File tree

3 files changed

+78
-11
lines changed

3 files changed

+78
-11
lines changed

drivers/scsi/sd.c

Lines changed: 70 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ static DEFINE_IDA(sd_index_ida);
116116
* object after last put) */
117117
static DEFINE_MUTEX(sd_ref_mutex);
118118

119+
struct kmem_cache *sd_cdb_cache;
120+
mempool_t *sd_cdb_pool;
121+
119122
static const char *sd_cache_types[] = {
120123
"write through", "none", "write back",
121124
"write back, no read (daft)"
@@ -413,6 +416,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
413416
sector_t threshold;
414417
unsigned int this_count = blk_rq_sectors(rq);
415418
int ret, host_dif;
419+
unsigned char protect;
416420

417421
if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {
418422
ret = scsi_setup_blk_pc_cmnd(sdp, rq);
@@ -545,13 +549,49 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq)
545549
/* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */
546550
host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type);
547551
if (host_dif)
548-
SCpnt->cmnd[1] = 1 << 5;
552+
protect = 1 << 5;
549553
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+
}
551563

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) {
553593
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);
555595
SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;
556596
SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;
557597
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)
572612
this_count = 0xffff;
573613

574614
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);
576616
SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;
577617
SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;
578618
SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;
@@ -1047,6 +1087,7 @@ static int sd_done(struct scsi_cmnd *SCpnt)
10471087
int result = SCpnt->result;
10481088
unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt);
10491089
struct scsi_sense_hdr sshdr;
1090+
struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk);
10501091
int sense_valid = 0;
10511092
int sense_deferred = 0;
10521093

@@ -1108,6 +1149,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
11081149
if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
11091150
sd_dif_complete(SCpnt, good_bytes);
11101151

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+
11111156
return good_bytes;
11121157
}
11131158

@@ -1271,12 +1316,7 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer)
12711316

12721317
sdkp->protection_type = type;
12731318

1274-
switch (type) {
1275-
case SD_DIF_TYPE1_PROTECTION:
1276-
case SD_DIF_TYPE3_PROTECTION:
1277-
break;
1278-
1279-
default:
1319+
if (type > SD_DIF_TYPE3_PROTECTION) {
12801320
sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \
12811321
"protection type %u. Disabling disk!\n", type);
12821322
sdkp->capacity = 0;
@@ -2323,8 +2363,24 @@ static int __init init_sd(void)
23232363
if (err)
23242364
goto err_out_class;
23252365

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+
23262379
return 0;
23272380

2381+
err_out_cache:
2382+
kmem_cache_destroy(sd_cdb_cache);
2383+
23282384
err_out_class:
23292385
class_unregister(&sd_disk_class);
23302386
err_out:
@@ -2344,6 +2400,9 @@ static void __exit exit_sd(void)
23442400

23452401
SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n"));
23462402

2403+
mempool_destroy(sd_cdb_pool);
2404+
kmem_cache_destroy(sd_cdb_cache);
2405+
23472406
scsi_unregister_driver(&sd_template.gendrv);
23482407
class_unregister(&sd_disk_class);
23492408

drivers/scsi/sd.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@
3737
*/
3838
#define SD_LAST_BUGGY_SECTORS 8
3939

40+
enum {
41+
SD_EXT_CDB_SIZE = 32, /* Extended CDB size */
42+
SD_MEMPOOL_SIZE = 2, /* CDB pool size */
43+
};
44+
4045
struct scsi_disk {
4146
struct scsi_driver *driver; /* always &sd_template */
4247
struct scsi_device *device;

include/scsi/scsi.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ struct scsi_cmnd;
129129
#define MI_REPORT_TARGET_PGS 0x0a
130130
/* values for maintenance out */
131131
#define MO_SET_TARGET_PGS 0x0a
132+
/* values for variable length command */
133+
#define READ_32 0x09
134+
#define WRITE_32 0x0b
132135

133136
/* Values for T10/04-262r7 */
134137
#define ATA_16 0x85 /* 16-byte pass-thru */

0 commit comments

Comments
 (0)