diff options
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 140 |
1 files changed, 111 insertions, 29 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 8dd96dcd716c..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)" |
@@ -370,6 +373,31 @@ static void scsi_disk_put(struct scsi_disk *sdkp) | |||
370 | mutex_unlock(&sd_ref_mutex); | 373 | mutex_unlock(&sd_ref_mutex); |
371 | } | 374 | } |
372 | 375 | ||
376 | static void sd_prot_op(struct scsi_cmnd *scmd, unsigned int dif) | ||
377 | { | ||
378 | unsigned int prot_op = SCSI_PROT_NORMAL; | ||
379 | unsigned int dix = scsi_prot_sg_count(scmd); | ||
380 | |||
381 | if (scmd->sc_data_direction == DMA_FROM_DEVICE) { | ||
382 | if (dif && dix) | ||
383 | prot_op = SCSI_PROT_READ_PASS; | ||
384 | else if (dif && !dix) | ||
385 | prot_op = SCSI_PROT_READ_STRIP; | ||
386 | else if (!dif && dix) | ||
387 | prot_op = SCSI_PROT_READ_INSERT; | ||
388 | } else { | ||
389 | if (dif && dix) | ||
390 | prot_op = SCSI_PROT_WRITE_PASS; | ||
391 | else if (dif && !dix) | ||
392 | prot_op = SCSI_PROT_WRITE_INSERT; | ||
393 | else if (!dif && dix) | ||
394 | prot_op = SCSI_PROT_WRITE_STRIP; | ||
395 | } | ||
396 | |||
397 | scsi_set_prot_op(scmd, prot_op); | ||
398 | scsi_set_prot_type(scmd, dif); | ||
399 | } | ||
400 | |||
373 | /** | 401 | /** |
374 | * sd_init_command - build a scsi (read or write) command from | 402 | * sd_init_command - build a scsi (read or write) command from |
375 | * information in the request structure. | 403 | * information in the request structure. |
@@ -388,6 +416,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
388 | sector_t threshold; | 416 | sector_t threshold; |
389 | unsigned int this_count = blk_rq_sectors(rq); | 417 | unsigned int this_count = blk_rq_sectors(rq); |
390 | int ret, host_dif; | 418 | int ret, host_dif; |
419 | unsigned char protect; | ||
391 | 420 | ||
392 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { | 421 | if (rq->cmd_type == REQ_TYPE_BLOCK_PC) { |
393 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); | 422 | ret = scsi_setup_blk_pc_cmnd(sdp, rq); |
@@ -520,13 +549,49 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
520 | /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ | 549 | /* Set RDPROTECT/WRPROTECT if disk is formatted with DIF */ |
521 | host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); | 550 | host_dif = scsi_host_dif_capable(sdp->host, sdkp->protection_type); |
522 | if (host_dif) | 551 | if (host_dif) |
523 | SCpnt->cmnd[1] = 1 << 5; | 552 | protect = 1 << 5; |
524 | else | 553 | else |
525 | SCpnt->cmnd[1] = 0; | 554 | protect = 0; |
526 | 555 | ||
527 | if (block > 0xffffffff) { | 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 | } | ||
563 | |||
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) { | ||
528 | SCpnt->cmnd[0] += READ_16 - READ_6; | 593 | SCpnt->cmnd[0] += READ_16 - READ_6; |
529 | SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; | 594 | SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); |
530 | 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; |
531 | 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; |
532 | 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; |
@@ -547,7 +612,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
547 | this_count = 0xffff; | 612 | this_count = 0xffff; |
548 | 613 | ||
549 | SCpnt->cmnd[0] += READ_10 - READ_6; | 614 | SCpnt->cmnd[0] += READ_10 - READ_6; |
550 | SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0; | 615 | SCpnt->cmnd[1] = protect | (blk_fua_rq(rq) ? 0x8 : 0); |
551 | SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; | 616 | SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff; |
552 | SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; | 617 | SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff; |
553 | SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; | 618 | SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff; |
@@ -578,8 +643,7 @@ static int sd_prep_fn(struct request_queue *q, struct request *rq) | |||
578 | 643 | ||
579 | /* If DIF or DIX is enabled, tell HBA how to handle request */ | 644 | /* If DIF or DIX is enabled, tell HBA how to handle request */ |
580 | if (host_dif || scsi_prot_sg_count(SCpnt)) | 645 | if (host_dif || scsi_prot_sg_count(SCpnt)) |
581 | sd_dif_op(SCpnt, host_dif, scsi_prot_sg_count(SCpnt), | 646 | sd_prot_op(SCpnt, host_dif); |
582 | sdkp->protection_type); | ||
583 | 647 | ||
584 | /* | 648 | /* |
585 | * We shouldn't disconnect in the middle of a sector, so with a dumb | 649 | * We shouldn't disconnect in the middle of a sector, so with a dumb |
@@ -1023,6 +1087,7 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
1023 | int result = SCpnt->result; | 1087 | int result = SCpnt->result; |
1024 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); | 1088 | unsigned int good_bytes = result ? 0 : scsi_bufflen(SCpnt); |
1025 | struct scsi_sense_hdr sshdr; | 1089 | struct scsi_sense_hdr sshdr; |
1090 | struct scsi_disk *sdkp = scsi_disk(SCpnt->request->rq_disk); | ||
1026 | int sense_valid = 0; | 1091 | int sense_valid = 0; |
1027 | int sense_deferred = 0; | 1092 | int sense_deferred = 0; |
1028 | 1093 | ||
@@ -1084,6 +1149,10 @@ static int sd_done(struct scsi_cmnd *SCpnt) | |||
1084 | 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)) |
1085 | sd_dif_complete(SCpnt, good_bytes); | 1150 | sd_dif_complete(SCpnt, good_bytes); |
1086 | 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 | |||
1087 | return good_bytes; | 1156 | return good_bytes; |
1088 | } | 1157 | } |
1089 | 1158 | ||
@@ -1238,34 +1307,28 @@ void sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer) | |||
1238 | u8 type; | 1307 | u8 type; |
1239 | 1308 | ||
1240 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) | 1309 | if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) |
1241 | type = 0; | 1310 | return; |
1242 | else | ||
1243 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ | ||
1244 | 1311 | ||
1245 | sdkp->protection_type = type; | 1312 | type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ |
1246 | 1313 | ||
1247 | switch (type) { | 1314 | if (type == sdkp->protection_type || !sdkp->first_scan) |
1248 | case SD_DIF_TYPE0_PROTECTION: | 1315 | return; |
1249 | case SD_DIF_TYPE1_PROTECTION: | ||
1250 | case SD_DIF_TYPE3_PROTECTION: | ||
1251 | break; | ||
1252 | 1316 | ||
1253 | case SD_DIF_TYPE2_PROTECTION: | 1317 | sdkp->protection_type = type; |
1254 | sd_printk(KERN_ERR, sdkp, "formatted with DIF Type 2 " \ | ||
1255 | "protection which is currently unsupported. " \ | ||
1256 | "Disabling disk!\n"); | ||
1257 | goto disable; | ||
1258 | 1318 | ||
1259 | default: | 1319 | if (type > SD_DIF_TYPE3_PROTECTION) { |
1260 | sd_printk(KERN_ERR, sdkp, "formatted with unknown " \ | 1320 | sd_printk(KERN_ERR, sdkp, "formatted with unsupported " \ |
1261 | "protection type %d. Disabling disk!\n", type); | 1321 | "protection type %u. Disabling disk!\n", type); |
1262 | goto disable; | 1322 | sdkp->capacity = 0; |
1323 | return; | ||
1263 | } | 1324 | } |
1264 | 1325 | ||
1265 | return; | 1326 | if (scsi_host_dif_capable(sdp->host, type)) |
1266 | 1327 | sd_printk(KERN_NOTICE, sdkp, | |
1267 | disable: | 1328 | "Enabling DIF Type %u protection\n", type); |
1268 | sdkp->capacity = 0; | 1329 | else |
1330 | sd_printk(KERN_NOTICE, sdkp, | ||
1331 | "Disabling DIF Type %u protection\n", type); | ||
1269 | } | 1332 | } |
1270 | 1333 | ||
1271 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, | 1334 | static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, |
@@ -2300,8 +2363,24 @@ static int __init init_sd(void) | |||
2300 | if (err) | 2363 | if (err) |
2301 | goto err_out_class; | 2364 | goto err_out_class; |
2302 | 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 | |||
2303 | return 0; | 2379 | return 0; |
2304 | 2380 | ||
2381 | err_out_cache: | ||
2382 | kmem_cache_destroy(sd_cdb_cache); | ||
2383 | |||
2305 | err_out_class: | 2384 | err_out_class: |
2306 | class_unregister(&sd_disk_class); | 2385 | class_unregister(&sd_disk_class); |
2307 | err_out: | 2386 | err_out: |
@@ -2321,6 +2400,9 @@ static void __exit exit_sd(void) | |||
2321 | 2400 | ||
2322 | SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); | 2401 | SCSI_LOG_HLQUEUE(3, printk("exit_sd: exiting sd driver\n")); |
2323 | 2402 | ||
2403 | mempool_destroy(sd_cdb_pool); | ||
2404 | kmem_cache_destroy(sd_cdb_cache); | ||
2405 | |||
2324 | scsi_unregister_driver(&sd_template.gendrv); | 2406 | scsi_unregister_driver(&sd_template.gendrv); |
2325 | class_unregister(&sd_disk_class); | 2407 | class_unregister(&sd_disk_class); |
2326 | 2408 | ||