aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDamien Le Moal <damien.lemoal@wdc.com>2018-10-12 06:08:41 -0400
committerJens Axboe <axboe@kernel.dk>2018-10-25 13:17:39 -0400
commitd2e428e49eec9b7ff175d7d5941d50e5a7d15324 (patch)
treedb4d6cfeae616a0f133ce78f5067933b0232ccce
parent7f9d35d24c56576a8c18a8b6f74711c7f3c9c6c0 (diff)
scsi: sd_zbc: Reduce boot device scan and revalidate time
Handling checks of ZBC device capacity using the max_lba field of the REPORT ZONES command reply for disks with rc_basis == 0 can be done using the same report zones command reply used to check the "same" field. Avoid executing a report zones command solely to check the disk capacity by merging sd_zbc_check_capacity() into sd_zbc_check_zone_size() and renaming that function to sd_zbc_check_zones(). This removes a costly execution of a full report zones command and so reduces device scan duration at boot time as well as the duration of disk revalidate calls. Furthermore, setting the partial report bit in the REPORT ZONES command cdb can significantly reduce this command execution time as the device does not have to count and report the total number of zones that could be reported assuming a large enough reply buffer. A non-partial zone report is necessary only for the first execution of report zones used to check the same field value (to ensure that this value applies to all zones of the disk). All other calls to sd_zbc_report_zones() can use a partial report to reduce execution time. Using a 14 TB ZBC disk, these simple changes reduce device scan time at boot from about 3.5s down to about 900ms. Disk revalidate times are also reduced from about 450ms down to 230ms. Reviewed-by: Christoph Hellwig <hch@lst.de> Reviewed-by: Hannes Reinecke <hare@suse.com> Acked-by: Martin K. Petersen <martin.petersen@oracle.com> Signed-off-by: Damien Le Moal <damien.lemoal@wdc.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
-rw-r--r--drivers/scsi/sd_zbc.c94
1 files changed, 40 insertions, 54 deletions
diff --git a/drivers/scsi/sd_zbc.c b/drivers/scsi/sd_zbc.c
index 0b7d8787f785..ca73c46931c0 100644
--- a/drivers/scsi/sd_zbc.c
+++ b/drivers/scsi/sd_zbc.c
@@ -67,11 +67,17 @@ static void sd_zbc_parse_report(struct scsi_disk *sdkp, u8 *buf,
67 * @buf: Buffer to use for the reply 67 * @buf: Buffer to use for the reply
68 * @buflen: the buffer size 68 * @buflen: the buffer size
69 * @lba: Start LBA of the report 69 * @lba: Start LBA of the report
70 * @partial: Do partial report
70 * 71 *
71 * For internal use during device validation. 72 * For internal use during device validation.
73 * Using partial=true can significantly speed up execution of a report zones
74 * command because the disk does not have to count all possible report matching
75 * zones and will only report the count of zones fitting in the command reply
76 * buffer.
72 */ 77 */
73static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf, 78static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
74 unsigned int buflen, sector_t lba) 79 unsigned int buflen, sector_t lba,
80 bool partial)
75{ 81{
76 struct scsi_device *sdp = sdkp->device; 82 struct scsi_device *sdp = sdkp->device;
77 const int timeout = sdp->request_queue->rq_timeout; 83 const int timeout = sdp->request_queue->rq_timeout;
@@ -85,6 +91,8 @@ static int sd_zbc_report_zones(struct scsi_disk *sdkp, unsigned char *buf,
85 cmd[1] = ZI_REPORT_ZONES; 91 cmd[1] = ZI_REPORT_ZONES;
86 put_unaligned_be64(lba, &cmd[2]); 92 put_unaligned_be64(lba, &cmd[2]);
87 put_unaligned_be32(buflen, &cmd[10]); 93 put_unaligned_be32(buflen, &cmd[10]);
94 if (partial)
95 cmd[14] = ZBC_REPORT_ZONE_PARTIAL;
88 memset(buf, 0, buflen); 96 memset(buf, 0, buflen);
89 97
90 result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE, 98 result = scsi_execute_req(sdp, cmd, DMA_FROM_DEVICE,
@@ -350,60 +358,25 @@ static int sd_zbc_check_zoned_characteristics(struct scsi_disk *sdkp,
350 return 0; 358 return 0;
351} 359}
352 360
353/**
354 * sd_zbc_check_capacity - Check reported capacity.
355 * @sdkp: Target disk
356 * @buf: Buffer to use for commands
357 *
358 * ZBC drive may report only the capacity of the first conventional zones at
359 * LBA 0. This is indicated by the RC_BASIS field of the read capacity reply.
360 * Check this here. If the disk reported only its conventional zones capacity,
361 * get the total capacity by doing a report zones.
362 */
363static int sd_zbc_check_capacity(struct scsi_disk *sdkp, unsigned char *buf)
364{
365 sector_t lba;
366 int ret;
367
368 if (sdkp->rc_basis != 0)
369 return 0;
370
371 /* Do a report zone to get the maximum LBA to check capacity */
372 ret = sd_zbc_report_zones(sdkp, buf, SD_BUF_SIZE, 0);
373 if (ret)
374 return ret;
375
376 /* The max_lba field is the capacity of this device */
377 lba = get_unaligned_be64(&buf[8]);
378 if (lba + 1 == sdkp->capacity)
379 return 0;
380
381 if (sdkp->first_scan)
382 sd_printk(KERN_WARNING, sdkp,
383 "Changing capacity from %llu to max LBA+1 %llu\n",
384 (unsigned long long)sdkp->capacity,
385 (unsigned long long)lba + 1);
386 sdkp->capacity = lba + 1;
387
388 return 0;
389}
390
391#define SD_ZBC_BUF_SIZE 131072U 361#define SD_ZBC_BUF_SIZE 131072U
392 362
393/** 363/**
394 * sd_zbc_check_zone_size - Check the device zone sizes 364 * sd_zbc_check_zones - Check the device capacity and zone sizes
395 * @sdkp: Target disk 365 * @sdkp: Target disk
396 * 366 *
397 * Check that all zones of the device are equal. The last zone can however 367 * Check that the device capacity as reported by READ CAPACITY matches the
398 * be smaller. The zone size must also be a power of two number of LBAs. 368 * max_lba value (plus one)of the report zones command reply. Also check that
369 * all zones of the device have an equal size, only allowing the last zone of
370 * the disk to have a smaller size (runt zone). The zone size must also be a
371 * power of two.
399 * 372 *
400 * Returns the zone size in number of blocks upon success or an error code 373 * Returns the zone size in number of blocks upon success or an error code
401 * upon failure. 374 * upon failure.
402 */ 375 */
403static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp) 376static s64 sd_zbc_check_zones(struct scsi_disk *sdkp)
404{ 377{
405 u64 zone_blocks = 0; 378 u64 zone_blocks = 0;
406 sector_t block = 0; 379 sector_t max_lba, block = 0;
407 unsigned char *buf; 380 unsigned char *buf;
408 unsigned char *rec; 381 unsigned char *rec;
409 unsigned int buf_len; 382 unsigned int buf_len;
@@ -416,11 +389,28 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
416 if (!buf) 389 if (!buf)
417 return -ENOMEM; 390 return -ENOMEM;
418 391
419 /* Do a report zone to get the same field */ 392 /* Do a report zone to get max_lba and the same field */
420 ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0); 393 ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 0, false);
421 if (ret) 394 if (ret)
422 goto out_free; 395 goto out_free;
423 396
397 if (sdkp->rc_basis == 0) {
398 /* The max_lba field is the capacity of this device */
399 max_lba = get_unaligned_be64(&buf[8]);
400 if (sdkp->capacity != max_lba + 1) {
401 if (sdkp->first_scan)
402 sd_printk(KERN_WARNING, sdkp,
403 "Changing capacity from %llu to max LBA+1 %llu\n",
404 (unsigned long long)sdkp->capacity,
405 (unsigned long long)max_lba + 1);
406 sdkp->capacity = max_lba + 1;
407 }
408 }
409
410 /*
411 * Check same field: for any value other than 0, we know that all zones
412 * have the same size.
413 */
424 same = buf[4] & 0x0f; 414 same = buf[4] & 0x0f;
425 if (same > 0) { 415 if (same > 0) {
426 rec = &buf[64]; 416 rec = &buf[64];
@@ -458,7 +448,7 @@ static s64 sd_zbc_check_zone_size(struct scsi_disk *sdkp)
458 448
459 if (block < sdkp->capacity) { 449 if (block < sdkp->capacity) {
460 ret = sd_zbc_report_zones(sdkp, buf, 450 ret = sd_zbc_report_zones(sdkp, buf,
461 SD_ZBC_BUF_SIZE, block); 451 SD_ZBC_BUF_SIZE, block, true);
462 if (ret) 452 if (ret)
463 goto out_free; 453 goto out_free;
464 } 454 }
@@ -574,7 +564,8 @@ sd_zbc_setup_seq_zones_bitmap(struct scsi_disk *sdkp, u32 zone_shift,
574 goto out; 564 goto out;
575 565
576 while (lba < sdkp->capacity) { 566 while (lba < sdkp->capacity) {
577 ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE, lba); 567 ret = sd_zbc_report_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
568 lba, true);
578 if (ret) 569 if (ret)
579 goto out; 570 goto out;
580 lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE, 571 lba = sd_zbc_get_seq_zones(sdkp, buf, SD_ZBC_BUF_SIZE,
@@ -692,16 +683,11 @@ int sd_zbc_read_zones(struct scsi_disk *sdkp, unsigned char *buf)
692 if (ret) 683 if (ret)
693 goto err; 684 goto err;
694 685
695 /* Check capacity */
696 ret = sd_zbc_check_capacity(sdkp, buf);
697 if (ret)
698 goto err;
699
700 /* 686 /*
701 * Check zone size: only devices with a constant zone size (except 687 * Check zone size: only devices with a constant zone size (except
702 * an eventual last runt zone) that is a power of 2 are supported. 688 * an eventual last runt zone) that is a power of 2 are supported.
703 */ 689 */
704 zone_blocks = sd_zbc_check_zone_size(sdkp); 690 zone_blocks = sd_zbc_check_zones(sdkp);
705 ret = -EFBIG; 691 ret = -EFBIG;
706 if (zone_blocks != (u32)zone_blocks) 692 if (zone_blocks != (u32)zone_blocks)
707 goto err; 693 goto err;