#include "blk.h"
+const char *blk_integrity_type_str(struct blk_integrity *bi)
+{
+ return bi->profile->name;
+}
+EXPORT_SYMBOL_GPL(blk_integrity_type_str);
+
/**
* blk_rq_count_integrity_sg - Count number of integrity scatterlist elements
* @q: request queue
};
/**
- * blk_integrity_register - Register a gendisk as being integrity-capable
+ * blk_nointegrity_register - Register a gendisk as having non-itegrity metadata
* @disk: struct gendisk pointer to make integrity-aware
- * @template: block integrity profile to register
- *
- * Description: When a device needs to advertise itself as being able to
- * send/receive integrity metadata it must use this function to register
- * the capability with the block layer. The template is a blk_integrity
- * struct with values appropriate for the underlying hardware. See
- * Documentation/block/data-integrity.rst.
+ * @meta_size: size of the metadata
*/
-void blk_integrity_register(struct gendisk *disk, struct blk_integrity *template)
+void blk_nointegrity_register(struct gendisk *disk, unsigned char meta_size)
{
struct blk_integrity *bi = &disk->queue->integrity;
- bi->flags = template->flags;
- if (bi->profile->verify_fn)
- bi->flags |= BLK_INTEGRITY_VERIFY;
- if (bi->profile->generate_fn)
- bi->flags |= BLK_INTEGRITY_GENERATE;
- bi->interval_exp = template->interval_exp ? :
- ilog2(queue_logical_block_size(disk->queue));
- bi->profile = template->profile ? template->profile : &nop_profile;
- bi->tuple_size = template->tuple_size;
- bi->tag_size = template->tag_size;
-
- if (!bi->profile->verify_fn && !bi->profile->generate_fn)
- return;
-
- blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
+ bi->flags = 0;
+ bi->profile = &nop_profile;
+ bi->tuple_size = meta_size;
+ bi->tag_size = meta_size;
+ bi->interval_exp = ilog2(queue_logical_block_size(disk->queue));
+}
+EXPORT_SYMBOL(blk_nointegrity_register);
-#ifdef CONFIG_BLK_INLINE_ENCRYPTION
- if (disk->queue->ksm) {
- pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together. Disabling hardware inline encryption.\n");
- blk_ksm_unregister(disk->queue);
- }
-#endif
+void blk_integrity_copy(struct gendisk *to, struct gendisk *from)
+{
+ to->queue->integrity = from->queue->integrity;
+ if (to->queue->integrity.flags &
+ (BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE))
+ blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, to->queue);
}
-EXPORT_SYMBOL(blk_integrity_register);
+EXPORT_SYMBOL(blk_integrity_copy);
/**
* blk_integrity_unregister - Unregister block integrity profile
};
EXPORT_SYMBOL(t10_pi_type1_crc);
-const struct blk_integrity_profile t10_pi_type1_ip = {
+static const struct blk_integrity_profile t10_pi_type1_ip = {
.name = "T10-DIF-TYPE1-IP",
.generate_fn = t10_pi_type1_generate_ip,
.verify_fn = t10_pi_type1_verify_ip,
.prepare_fn = t10_pi_type1_prepare,
.complete_fn = t10_pi_type1_complete,
};
-EXPORT_SYMBOL(t10_pi_type1_ip);
const struct blk_integrity_profile t10_pi_type3_crc = {
.name = "T10-DIF-TYPE3-CRC",
};
EXPORT_SYMBOL(t10_pi_type3_crc);
-const struct blk_integrity_profile t10_pi_type3_ip = {
+static const struct blk_integrity_profile t10_pi_type3_ip = {
.name = "T10-DIF-TYPE3-IP",
.generate_fn = t10_pi_type3_generate_ip,
.verify_fn = t10_pi_type3_verify_ip,
.prepare_fn = t10_pi_type3_prepare,
.complete_fn = t10_pi_type3_complete,
};
-EXPORT_SYMBOL(t10_pi_type3_ip);
+
+/**
+ * t10_pi_register - Register a gendisk as being T10-PI capable
+ * @disk: struct gendisk pointer to make integrity-aware
+ * @type: Protetion type
+ * @flags: BLK_INTEGRITY_* flags applicatble to this disk
+ */
+void t10_pi_register(struct gendisk *disk, enum t10_dif_type type,
+ unsigned int flags)
+{
+ struct blk_integrity *bi = &disk->queue->integrity;
+
+ switch (type) {
+ case T10_PI_TYPE0_PROTECTION:
+ flags &= ~(BLK_INTEGRITY_DEVICE_CAPABLE | BLK_INTEGRITY_APP_TAG);
+ break;
+ case T10_PI_TYPE2_PROTECTION:
+ case T10_PI_TYPE1_PROTECTION:
+ if (flags & BLK_INTEGRITY_IP_CHECKSUM)
+ bi->profile = &t10_pi_type1_ip;
+ else
+ bi->profile = &t10_pi_type1_crc;
+ break;
+ case T10_PI_TYPE3_PROTECTION:
+ if (flags & BLK_INTEGRITY_IP_CHECKSUM)
+ bi->profile = &t10_pi_type3_ip;
+ else
+ bi->profile = &t10_pi_type3_crc;
+ break;
+ default:
+ WARN_ON_ONCE(1);
+ return;
+ }
+
+ bi->tuple_size = sizeof(struct t10_pi_tuple);
+ bi->interval_exp = ilog2(queue_logical_block_size(disk->queue));
+ bi->flags = flags | BLK_INTEGRITY_VERIFY | BLK_INTEGRITY_GENERATE;
+
+ if (!(flags & BLK_INTEGRITY_APP_TAG))
+ bi->tag_size = 0;
+ else if (type == T10_PI_TYPE3_PROTECTION)
+ bi->tag_size = sizeof(u16) + sizeof(u32);
+ else
+ bi->tag_size = sizeof(u16);
+
+ blk_queue_flag_set(QUEUE_FLAG_STABLE_WRITES, disk->queue);
+
+#ifdef CONFIG_BLK_INLINE_ENCRYPTION
+ if (disk->queue->ksm) {
+ pr_warn("blk-integrity: Integrity and hardware inline encryption are not supported together. ");
+ pr_warn("Disabling hardware inline encryption.\n");
+ blk_ksm_unregister(disk->queue);
+ }
+#endif
+}
+EXPORT_SYMBOL(t10_pi_register);
MODULE_LICENSE("GPL");
static void dm_integrity_set(struct dm_target *ti, struct dm_integrity_c *ic)
{
struct gendisk *disk = dm_disk(dm_table_get_md(ti->table));
- struct blk_integrity bi;
- memset(&bi, 0, sizeof(bi));
- bi.tuple_size = ic->tag_size;
- bi.tag_size = bi.tuple_size;
- bi.interval_exp = ic->sb->log2_sectors_per_block + SECTOR_SHIFT;
-
- blk_integrity_register(disk, &bi);
+ blk_nointegrity_register(disk, ic->tag_size);
+ blk_set_integrity_interval(disk,
+ ic->sb->log2_sectors_per_block + SECTOR_SHIFT);
blk_queue_max_integrity_segments(disk->queue, UINT_MAX);
}
* Register integrity profile during table load; we can do
* this because the final profile must match during resume.
*/
- blk_integrity_register(dm_disk(md),
- blk_get_integrity(template_disk));
+ blk_integrity_copy(dm_disk(md), template_disk);
return 0;
}
* All component devices are integrity capable and have matching
* profiles, register the common profile for the md device.
*/
- blk_integrity_register(mddev->gendisk,
- bdev_get_integrity(reference->bdev));
+ blk_integrity_copy(mddev->gendisk, reference->bdev->bd_disk);
pr_debug("md: data integrity enabled on %s\n", mdname(mddev));
if (bioset_integrity_create(&mddev->bio_set, BIO_POOL_SIZE)) {
#ifdef CONFIG_BLK_DEV_INTEGRITY
int nd_integrity_init(struct gendisk *disk, unsigned long meta_size)
{
- struct blk_integrity bi;
-
- if (meta_size == 0)
- return 0;
-
- memset(&bi, 0, sizeof(bi));
-
- bi.tuple_size = meta_size;
- bi.tag_size = meta_size;
-
- blk_integrity_register(disk, &bi);
- blk_queue_max_integrity_segments(disk->queue, 1);
-
+ if (meta_size) {
+ blk_nointegrity_register(disk, meta_size);
+ blk_queue_max_integrity_segments(disk->queue, 1);
+ }
return 0;
}
EXPORT_SYMBOL(nd_integrity_init);
return 0;
}
-#ifdef CONFIG_BLK_DEV_INTEGRITY
-static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
- u32 max_integrity_segments)
-{
- struct blk_integrity integrity;
-
- memset(&integrity, 0, sizeof(integrity));
- switch (pi_type) {
- case NVME_NS_DPS_PI_TYPE3:
- integrity.profile = &t10_pi_type3_crc;
- integrity.tag_size = sizeof(u16) + sizeof(u32);
- integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
- break;
- case NVME_NS_DPS_PI_TYPE1:
- case NVME_NS_DPS_PI_TYPE2:
- integrity.profile = &t10_pi_type1_crc;
- integrity.tag_size = sizeof(u16);
- integrity.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
- break;
- default:
- integrity.profile = NULL;
- break;
- }
- integrity.tuple_size = ms;
- blk_integrity_register(disk, &integrity);
- blk_queue_max_integrity_segments(disk->queue, max_integrity_segments);
-}
-#else
-static void nvme_init_integrity(struct gendisk *disk, u16 ms, u8 pi_type,
- u32 max_integrity_segments)
-{
-}
-#endif /* CONFIG_BLK_DEV_INTEGRITY */
-
static void nvme_config_discard(struct gendisk *disk, struct nvme_ns *ns)
{
struct nvme_ctrl *ctrl = ns->ctrl;
*/
if (ns->ms) {
if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) &&
- (ns->features & NVME_NS_METADATA_SUPPORTED))
- nvme_init_integrity(disk, ns->ms, ns->pi_type,
- ns->ctrl->max_integrity_segments);
- else if (!nvme_ns_has_pi(ns))
+ (ns->features & NVME_NS_METADATA_SUPPORTED)) {
+ switch (ns->pi_type) {
+ case NVME_NS_DPS_PI_TYPE3:
+ case NVME_NS_DPS_PI_TYPE1:
+ case NVME_NS_DPS_PI_TYPE2:
+ t10_pi_register(disk, ns->pi_type,
+ BLK_INTEGRITY_DEVICE_CAPABLE |
+ BLK_INTEGRITY_APP_TAG);
+ break;
+ default:
+ blk_nointegrity_register(disk, ns->ms);
+ break;
+ }
+
+ blk_queue_max_integrity_segments(disk->queue,
+ ns->ctrl->max_integrity_segments);
+ } else if (!nvme_ns_has_pi(ns)) {
capacity = 0;
+ }
}
set_capacity_and_notify(disk, capacity);
hv_storvsc-y := storvsc_drv.o
sd_mod-objs := sd.o
-sd_mod-$(CONFIG_BLK_DEV_INTEGRITY) += sd_dif.o
sd_mod-$(CONFIG_BLK_DEV_ZONED) += sd_zbc.o
sr_mod-objs := sr.o sr_ioctl.o sr_vendor.o
// SPDX-License-Identifier: GPL-2.0-only
/*
- * sd.c Copyright (C) 1992 Drew Eckhardt
- * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
+ * Copyright (C) 1992 Drew Eckhardt
+ * Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale
+ * Copyright (C) 2007, 2008 Oracle Corporation
*
* Linux scsi disk driver
* Initial versions: Drew Eckhardt
return 0;
}
+static void sd_dif_config_host(struct scsi_disk *sdkp)
+{
+ struct scsi_device *sdp = sdkp->device;
+ unsigned int flags = 0;
+
+ if (scsi_host_dix_capable(sdp->host, sdkp->protection_type)) {
+ if (scsi_host_dif_capable(sdp->host, sdkp->protection_type)) {
+ flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
+ if (sdkp->ATO)
+ flags |= BLK_INTEGRITY_APP_TAG;
+ }
+ } else {
+ if (!scsi_host_dix_capable(sdp->host, 0))
+ return;
+ }
+
+ if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP)
+ flags |= BLK_INTEGRITY_IP_CHECKSUM;
+
+ t10_pi_register(sdkp->disk, sdkp->protection_type, flags);
+
+ sd_printk(KERN_NOTICE, sdkp, "Enabling DIX %s protection\n",
+ blk_integrity_type_str(blk_get_integrity(sdkp->disk)));
+}
+
/**
* sd_probe - called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
sdp->host->hostt->rpm_autosuspend_delay);
}
device_add_disk(dev, gd, NULL);
- if (sdkp->capacity)
+
+ if (IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY) && sdkp->capacity)
sd_dif_config_host(sdkp);
sd_revalidate_disk(gd);
return sector >> (ilog2(sdev->sector_size) - 9);
}
-#ifdef CONFIG_BLK_DEV_INTEGRITY
-
-extern void sd_dif_config_host(struct scsi_disk *);
-
-#else /* CONFIG_BLK_DEV_INTEGRITY */
-
-static inline void sd_dif_config_host(struct scsi_disk *disk)
-{
-}
-
-#endif /* CONFIG_BLK_DEV_INTEGRITY */
-
static inline int sd_is_zoned(struct scsi_disk *sdkp)
{
return sdkp->zoned == 1 || sdkp->device->type == TYPE_ZBC;
+++ /dev/null
-// SPDX-License-Identifier: GPL-2.0-only
-/*
- * sd_dif.c - SCSI Data Integrity Field
- *
- * Copyright (C) 2007, 2008 Oracle Corporation
- * Written by: Martin K. Petersen <martin.petersen@oracle.com>
- */
-
-#include <linux/blkdev.h>
-#include <linux/t10-pi.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_driver.h>
-#include <scsi/scsi_eh.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_ioctl.h>
-#include <scsi/scsicam.h>
-
-#include "sd.h"
-
-/*
- * Configure exchange of protection information between OS and HBA.
- */
-void sd_dif_config_host(struct scsi_disk *sdkp)
-{
- struct scsi_device *sdp = sdkp->device;
- struct gendisk *disk = sdkp->disk;
- u8 type = sdkp->protection_type;
- struct blk_integrity bi;
- int dif, dix;
-
- dif = scsi_host_dif_capable(sdp->host, type);
- dix = scsi_host_dix_capable(sdp->host, type);
-
- if (!dix && scsi_host_dix_capable(sdp->host, 0)) {
- dif = 0; dix = 1;
- }
-
- if (!dix)
- return;
-
- memset(&bi, 0, sizeof(bi));
-
- /* Enable DMA of protection information */
- if (scsi_host_get_guard(sdkp->device->host) & SHOST_DIX_GUARD_IP) {
- if (type == T10_PI_TYPE3_PROTECTION)
- bi.profile = &t10_pi_type3_ip;
- else
- bi.profile = &t10_pi_type1_ip;
-
- bi.flags |= BLK_INTEGRITY_IP_CHECKSUM;
- } else
- if (type == T10_PI_TYPE3_PROTECTION)
- bi.profile = &t10_pi_type3_crc;
- else
- bi.profile = &t10_pi_type1_crc;
-
- bi.tuple_size = sizeof(struct t10_pi_tuple);
- sd_printk(KERN_NOTICE, sdkp,
- "Enabling DIX %s protection\n", bi.profile->name);
-
- if (dif && type) {
- bi.flags |= BLK_INTEGRITY_DEVICE_CAPABLE;
-
- if (!sdkp->ATO)
- goto out;
-
- if (type == T10_PI_TYPE3_PROTECTION)
- bi.tag_size = sizeof(u16) + sizeof(u32);
- else
- bi.tag_size = sizeof(u16);
-
- sd_printk(KERN_NOTICE, sdkp, "DIF application tag size %u\n",
- bi.tag_size);
- }
-
-out:
- blk_integrity_register(disk, &bi);
-}
-
BLK_INTEGRITY_GENERATE = 1 << 1,
BLK_INTEGRITY_DEVICE_CAPABLE = 1 << 2,
BLK_INTEGRITY_IP_CHECKSUM = 1 << 3,
+ BLK_INTEGRITY_APP_TAG = 1 << 4,
};
#ifdef CONFIG_BLK_DEV_INTEGRITY
const char *name;
};
-extern void blk_integrity_register(struct gendisk *, struct blk_integrity *);
+void blk_integrity_copy(struct gendisk *to, struct gendisk *from);
+void blk_nointegrity_register(struct gendisk *disk, unsigned char meta_size);
extern void blk_integrity_unregister(struct gendisk *);
extern int blk_integrity_compare(struct gendisk *, struct gendisk *);
extern int blk_rq_map_integrity_sg(struct request_queue *, struct bio *,
return rq->cmd_flags & REQ_INTEGRITY;
}
+static inline void blk_set_integrity_interval(struct gendisk *disk,
+ u8 interval_exp)
+{
+ disk->queue->integrity.interval_exp = interval_exp;
+}
+
static inline void blk_queue_max_integrity_segments(struct request_queue *q,
unsigned int segs)
{
{
return 0;
}
-static inline void blk_integrity_register(struct gendisk *d,
- struct blk_integrity *b)
+static inline void blk_integrity_copy(struct gendisk *to, struct gendisk *from)
+{
+}
+static inline void blk_nointegrity_register(struct gendisk *disk,
+ unsigned char meta_size)
{
}
static inline void blk_integrity_unregister(struct gendisk *d)
{
}
+static inline void blk_set_integrity_interval(struct gendisk *disk,
+ u8 interval_exp)
+{
+}
static inline void blk_queue_max_integrity_segments(struct request_queue *q,
unsigned int segs)
{
#endif /* CONFIG_BLK_DEV_INTEGRITY */
+const char *blk_integrity_type_str(struct blk_integrity *bi);
+
#ifdef CONFIG_BLK_INLINE_ENCRYPTION
bool blk_ksm_register(struct blk_keyslot_manager *ksm, struct request_queue *q);
return blk_rq_pos(rq) >> (shift - SECTOR_SHIFT) & 0xffffffff;
}
+void t10_pi_register(struct gendisk *disk, enum t10_dif_type type,
+ unsigned int flags);
+
extern const struct blk_integrity_profile t10_pi_type1_crc;
-extern const struct blk_integrity_profile t10_pi_type1_ip;
extern const struct blk_integrity_profile t10_pi_type3_crc;
-extern const struct blk_integrity_profile t10_pi_type3_ip;
#endif