diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-26 04:09:48 +0200 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2022-05-26 04:09:48 +0200 |
commit | fbe86daca0ba878b04fa241b85e26e54d17d4229 (patch) | |
tree | a179e18657e4ed82005c6e8846fd2c297c471a8c /drivers/scsi/sd.c | |
parent | Merge tag 'sound-5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/t... (diff) | |
parent | scsi: target: tcmu: Avoid holding XArray lock when calling lock_page (diff) | |
download | linux-fbe86daca0ba878b04fa241b85e26e54d17d4229.tar.xz linux-fbe86daca0ba878b04fa241b85e26e54d17d4229.zip |
Merge tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI updates from James Bottomley:
"This consists of a small set of driver updates (lpfc, ufs, mpt3sas
mpi3mr, iscsi target). Apart from that this is mostly small fixes with
very few core changes (the biggest one being VPD caching)"
* tag 'scsi-misc' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: (177 commits)
scsi: target: tcmu: Avoid holding XArray lock when calling lock_page
scsi: elx: efct: Remove NULL check after calling container_of()
scsi: dpt_i2o: Drop redundant spinlock initialization
scsi: qedf: Remove redundant variable op
scsi: hisi_sas: Fix memory ordering in hisi_sas_task_deliver()
scsi: fnic: Replace DMA mask of 64 bits with 47 bits
scsi: mpi3mr: Add target device related sysfs attributes
scsi: mpi3mr: Add shost related sysfs attributes
scsi: elx: efct: Remove redundant memset() statement
scsi: megaraid_sas: Remove redundant memset() statement
scsi: mpi3mr: Return error if dma_alloc_coherent() fails
scsi: hisi_sas: Fix rescan after deleting a disk
scsi: hisi_sas: Use sas_ata_wait_after_reset() in IT nexus reset
scsi: libsas: Refactor sas_ata_hard_reset()
scsi: mpt3sas: Update driver version to 42.100.00.00
scsi: mpt3sas: Fix junk chars displayed while printing ChipName
scsi: ipr: Use kobj_to_dev()
scsi: mpi3mr: Fix a NULL vs IS_ERR() bug in mpi3mr_bsg_init()
scsi: bnx2fc: Avoid using get_cpu() in bnx2fc_cmd_alloc()
scsi: libfc: Remove get_cpu() semantics in fc_exch_em_alloc()
...
Diffstat (limited to 'drivers/scsi/sd.c')
-rw-r--r-- | drivers/scsi/sd.c | 193 |
1 files changed, 118 insertions, 75 deletions
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 9694e2cfaf9a..749316462075 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2174,40 +2174,48 @@ static int sd_read_protection_type(struct scsi_disk *sdkp, unsigned char *buffer { struct scsi_device *sdp = sdkp->device; u8 type; - int ret = 0; if (scsi_device_protection(sdp) == 0 || (buffer[12] & 1) == 0) { sdkp->protection_type = 0; - return ret; + return 0; } type = ((buffer[12] >> 1) & 7) + 1; /* P_TYPE 0 = Type 1 */ - if (type > T10_PI_TYPE3_PROTECTION) - ret = -ENODEV; - else if (scsi_host_dif_capable(sdp->host, type)) - ret = 1; - - if (sdkp->first_scan || type != sdkp->protection_type) - switch (ret) { - case -ENODEV: - sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ - " protection type %u. Disabling disk!\n", - type); - break; - case 1: - sd_printk(KERN_NOTICE, sdkp, - "Enabling DIF Type %u protection\n", type); - break; - case 0: - sd_printk(KERN_NOTICE, sdkp, - "Disabling DIF Type %u protection\n", type); - break; - } + if (type > T10_PI_TYPE3_PROTECTION) { + sd_printk(KERN_ERR, sdkp, "formatted with unsupported" \ + " protection type %u. Disabling disk!\n", + type); + sdkp->protection_type = 0; + return -ENODEV; + } sdkp->protection_type = type; - return ret; + return 0; +} + +static void sd_config_protection(struct scsi_disk *sdkp) +{ + struct scsi_device *sdp = sdkp->device; + + if (!sdkp->first_scan) + return; + + sd_dif_config_host(sdkp); + + if (!sdkp->protection_type) + return; + + if (!scsi_host_dif_capable(sdp->host, sdkp->protection_type)) { + sd_printk(KERN_NOTICE, sdkp, + "Disabling DIF Type %u protection\n", + sdkp->protection_type); + sdkp->protection_type = 0; + } + + sd_printk(KERN_NOTICE, sdkp, "Enabling DIF Type %u protection\n", + sdkp->protection_type); } static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp, @@ -2841,40 +2849,37 @@ static void sd_read_app_tag_own(struct scsi_disk *sdkp, unsigned char *buffer) */ static void sd_read_block_limits(struct scsi_disk *sdkp) { - unsigned int sector_sz = sdkp->device->sector_size; - const int vpd_len = 64; - unsigned char *buffer = kmalloc(vpd_len, GFP_KERNEL); + struct scsi_vpd *vpd; - if (!buffer || - /* Block Limits VPD */ - scsi_get_vpd_page(sdkp->device, 0xb0, buffer, vpd_len)) - goto out; + rcu_read_lock(); - blk_queue_io_min(sdkp->disk->queue, - get_unaligned_be16(&buffer[6]) * sector_sz); + vpd = rcu_dereference(sdkp->device->vpd_pgb0); + if (!vpd || vpd->len < 16) + goto out; - sdkp->max_xfer_blocks = get_unaligned_be32(&buffer[8]); - sdkp->opt_xfer_blocks = get_unaligned_be32(&buffer[12]); + sdkp->min_xfer_blocks = get_unaligned_be16(&vpd->data[6]); + sdkp->max_xfer_blocks = get_unaligned_be32(&vpd->data[8]); + sdkp->opt_xfer_blocks = get_unaligned_be32(&vpd->data[12]); - if (buffer[3] == 0x3c) { + if (vpd->len >= 64) { unsigned int lba_count, desc_count; - sdkp->max_ws_blocks = (u32)get_unaligned_be64(&buffer[36]); + sdkp->max_ws_blocks = (u32)get_unaligned_be64(&vpd->data[36]); if (!sdkp->lbpme) goto out; - lba_count = get_unaligned_be32(&buffer[20]); - desc_count = get_unaligned_be32(&buffer[24]); + lba_count = get_unaligned_be32(&vpd->data[20]); + desc_count = get_unaligned_be32(&vpd->data[24]); if (lba_count && desc_count) sdkp->max_unmap_blocks = lba_count; - sdkp->unmap_granularity = get_unaligned_be32(&buffer[28]); + sdkp->unmap_granularity = get_unaligned_be32(&vpd->data[28]); - if (buffer[32] & 0x80) + if (vpd->data[32] & 0x80) sdkp->unmap_alignment = - get_unaligned_be32(&buffer[32]) & ~(1 << 31); + get_unaligned_be32(&vpd->data[32]) & ~(1 << 31); if (!sdkp->lbpvpd) { /* LBP VPD page not provided */ @@ -2896,7 +2901,7 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) } out: - kfree(buffer); + rcu_read_unlock(); } /** @@ -2906,18 +2911,21 @@ static void sd_read_block_limits(struct scsi_disk *sdkp) static void sd_read_block_characteristics(struct scsi_disk *sdkp) { struct request_queue *q = sdkp->disk->queue; - unsigned char *buffer; + struct scsi_vpd *vpd; u16 rot; - const int vpd_len = 64; + u8 zoned; - buffer = kmalloc(vpd_len, GFP_KERNEL); + rcu_read_lock(); + vpd = rcu_dereference(sdkp->device->vpd_pgb1); - if (!buffer || - /* Block Device Characteristics VPD */ - scsi_get_vpd_page(sdkp->device, 0xb1, buffer, vpd_len)) - goto out; + if (!vpd || vpd->len < 8) { + rcu_read_unlock(); + return; + } - rot = get_unaligned_be16(&buffer[4]); + rot = get_unaligned_be16(&vpd->data[4]); + zoned = (vpd->data[8] >> 4) & 3; + rcu_read_unlock(); if (rot == 1) { blk_queue_flag_set(QUEUE_FLAG_NONROT, q); @@ -2928,7 +2936,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) /* Host-managed */ blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HM); } else { - sdkp->zoned = (buffer[8] >> 4) & 3; + sdkp->zoned = zoned; if (sdkp->zoned == 1) { /* Host-aware */ blk_queue_set_zoned(sdkp->disk, BLK_ZONED_HA); @@ -2939,7 +2947,7 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) } if (!sdkp->first_scan) - goto out; + return; if (blk_queue_is_zoned(q)) { sd_printk(KERN_NOTICE, sdkp, "Host-%s zoned block device\n", @@ -2952,9 +2960,6 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) sd_printk(KERN_NOTICE, sdkp, "Drive-managed SMR disk\n"); } - - out: - kfree(buffer); } /** @@ -2963,24 +2968,24 @@ static void sd_read_block_characteristics(struct scsi_disk *sdkp) */ static void sd_read_block_provisioning(struct scsi_disk *sdkp) { - unsigned char *buffer; - const int vpd_len = 8; + struct scsi_vpd *vpd; if (sdkp->lbpme == 0) return; - buffer = kmalloc(vpd_len, GFP_KERNEL); + rcu_read_lock(); + vpd = rcu_dereference(sdkp->device->vpd_pgb2); - if (!buffer || scsi_get_vpd_page(sdkp->device, 0xb2, buffer, vpd_len)) - goto out; + if (!vpd || vpd->len < 8) { + rcu_read_unlock(); + return; + } sdkp->lbpvpd = 1; - sdkp->lbpu = (buffer[5] >> 7) & 1; /* UNMAP */ - sdkp->lbpws = (buffer[5] >> 6) & 1; /* WRITE SAME(16) with UNMAP */ - sdkp->lbpws10 = (buffer[5] >> 5) & 1; /* WRITE SAME(10) with UNMAP */ - - out: - kfree(buffer); + sdkp->lbpu = (vpd->data[5] >> 7) & 1; /* UNMAP */ + sdkp->lbpws = (vpd->data[5] >> 6) & 1; /* WRITE SAME(16) w/ UNMAP */ + sdkp->lbpws10 = (vpd->data[5] >> 5) & 1; /* WRITE SAME(10) w/ UNMAP */ + rcu_read_unlock(); } static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) @@ -2994,8 +2999,7 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) } if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, INQUIRY) < 0) { - /* too large values might cause issues with arcmsr */ - int vpd_buf_len = 64; + struct scsi_vpd *vpd; sdev->no_report_opcodes = 1; @@ -3003,8 +3007,11 @@ static void sd_read_write_same(struct scsi_disk *sdkp, unsigned char *buffer) * CODES is unsupported and the device has an ATA * Information VPD page (SAT). */ - if (!scsi_get_vpd_page(sdev, 0x89, buffer, vpd_buf_len)) + rcu_read_lock(); + vpd = rcu_dereference(sdev->vpd_pg89); + if (vpd) sdev->no_write_same = 1; + rcu_read_unlock(); } if (scsi_report_opcode(sdev, buffer, SD_BUF_SIZE, WRITE_SAME_16) == 1) @@ -3108,6 +3115,29 @@ out: kfree(buffer); } +static bool sd_validate_min_xfer_size(struct scsi_disk *sdkp) +{ + struct scsi_device *sdp = sdkp->device; + unsigned int min_xfer_bytes = + logical_to_bytes(sdp, sdkp->min_xfer_blocks); + + if (sdkp->min_xfer_blocks == 0) + return false; + + if (min_xfer_bytes & (sdkp->physical_block_size - 1)) { + sd_first_printk(KERN_WARNING, sdkp, + "Preferred minimum I/O size %u bytes not a " \ + "multiple of physical block size (%u bytes)\n", + min_xfer_bytes, sdkp->physical_block_size); + sdkp->min_xfer_blocks = 0; + return false; + } + + sd_first_printk(KERN_INFO, sdkp, "Preferred minimum I/O size %u bytes\n", + min_xfer_bytes); + return true; +} + /* * Determine the device's preferred I/O size for reads and writes * unless the reported value is unreasonably small, large, not a @@ -3119,6 +3149,8 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp, struct scsi_device *sdp = sdkp->device; unsigned int opt_xfer_bytes = logical_to_bytes(sdp, sdkp->opt_xfer_blocks); + unsigned int min_xfer_bytes = + logical_to_bytes(sdp, sdkp->min_xfer_blocks); if (sdkp->opt_xfer_blocks == 0) return false; @@ -3147,6 +3179,15 @@ static bool sd_validate_opt_xfer_size(struct scsi_disk *sdkp, return false; } + if (min_xfer_bytes && opt_xfer_bytes % min_xfer_bytes) { + sd_first_printk(KERN_WARNING, sdkp, + "Optimal transfer size %u bytes not a " \ + "multiple of preferred minimum block " \ + "size (%u bytes)\n", + opt_xfer_bytes, min_xfer_bytes); + return false; + } + if (opt_xfer_bytes & (sdkp->physical_block_size - 1)) { sd_first_printk(KERN_WARNING, sdkp, "Optimal transfer size %u bytes not a " \ @@ -3224,6 +3265,7 @@ static int sd_revalidate_disk(struct gendisk *disk) sd_read_app_tag_own(sdkp, buffer); sd_read_write_same(sdkp, buffer); sd_read_security(sdkp, buffer); + sd_config_protection(sdkp); } /* @@ -3239,6 +3281,12 @@ static int sd_revalidate_disk(struct gendisk *disk) dev_max = min_not_zero(dev_max, sdkp->max_xfer_blocks); q->limits.max_dev_sectors = logical_to_sectors(sdp, dev_max); + if (sd_validate_min_xfer_size(sdkp)) + blk_queue_io_min(sdkp->disk->queue, + logical_to_bytes(sdp, sdkp->min_xfer_blocks)); + else + blk_queue_io_min(sdkp->disk->queue, 0); + if (sd_validate_opt_xfer_size(sdkp, dev_max)) { q->limits.io_opt = logical_to_bytes(sdp, sdkp->opt_xfer_blocks); rw_max = logical_to_sectors(sdp, sdkp->opt_xfer_blocks); @@ -3477,11 +3525,6 @@ static int sd_probe(struct device *dev) goto out; } - if (sdkp->capacity) - sd_dif_config_host(sdkp); - - sd_revalidate_disk(gd); - if (sdkp->security) { sdkp->opal_dev = init_opal_dev(sdkp, &sd_sec_submit); if (sdkp->opal_dev) |