|  | /* SPDX-License-Identifier: GPL-2.0 */ | 
|  | #ifndef _LINUX_BLK_INTEGRITY_H | 
|  | #define _LINUX_BLK_INTEGRITY_H | 
|  |  | 
|  | #include <linux/blk-mq.h> | 
|  |  | 
|  | struct request; | 
|  |  | 
|  | enum blk_integrity_flags { | 
|  | BLK_INTEGRITY_VERIFY		= 1 << 0, | 
|  | BLK_INTEGRITY_GENERATE		= 1 << 1, | 
|  | BLK_INTEGRITY_DEVICE_CAPABLE	= 1 << 2, | 
|  | BLK_INTEGRITY_IP_CHECKSUM	= 1 << 3, | 
|  | }; | 
|  |  | 
|  | struct blk_integrity_iter { | 
|  | void			*prot_buf; | 
|  | void			*data_buf; | 
|  | sector_t		seed; | 
|  | unsigned int		data_size; | 
|  | unsigned short		interval; | 
|  | unsigned char		tuple_size; | 
|  | const char		*disk_name; | 
|  | }; | 
|  |  | 
|  | typedef blk_status_t (integrity_processing_fn) (struct blk_integrity_iter *); | 
|  | typedef void (integrity_prepare_fn) (struct request *); | 
|  | typedef void (integrity_complete_fn) (struct request *, unsigned int); | 
|  |  | 
|  | struct blk_integrity_profile { | 
|  | integrity_processing_fn		*generate_fn; | 
|  | integrity_processing_fn		*verify_fn; | 
|  | integrity_prepare_fn		*prepare_fn; | 
|  | integrity_complete_fn		*complete_fn; | 
|  | const char			*name; | 
|  | }; | 
|  |  | 
|  | #ifdef CONFIG_BLK_DEV_INTEGRITY | 
|  | void blk_integrity_register(struct gendisk *, struct blk_integrity *); | 
|  | void blk_integrity_unregister(struct gendisk *); | 
|  | int blk_integrity_compare(struct gendisk *, struct gendisk *); | 
|  | int blk_rq_map_integrity_sg(struct request_queue *, struct bio *, | 
|  | struct scatterlist *); | 
|  | int blk_rq_count_integrity_sg(struct request_queue *, struct bio *); | 
|  |  | 
|  | static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk) | 
|  | { | 
|  | struct blk_integrity *bi = &disk->queue->integrity; | 
|  |  | 
|  | if (!bi->profile) | 
|  | return NULL; | 
|  |  | 
|  | return bi; | 
|  | } | 
|  |  | 
|  | static inline struct blk_integrity * | 
|  | bdev_get_integrity(struct block_device *bdev) | 
|  | { | 
|  | return blk_get_integrity(bdev->bd_disk); | 
|  | } | 
|  |  | 
|  | static inline bool | 
|  | blk_integrity_queue_supports_integrity(struct request_queue *q) | 
|  | { | 
|  | return q->integrity.profile; | 
|  | } | 
|  |  | 
|  | static inline void blk_queue_max_integrity_segments(struct request_queue *q, | 
|  | unsigned int segs) | 
|  | { | 
|  | q->limits.max_integrity_segments = segs; | 
|  | } | 
|  |  | 
|  | static inline unsigned short | 
|  | queue_max_integrity_segments(const struct request_queue *q) | 
|  | { | 
|  | return q->limits.max_integrity_segments; | 
|  | } | 
|  |  | 
|  | /** | 
|  | * bio_integrity_intervals - Return number of integrity intervals for a bio | 
|  | * @bi:		blk_integrity profile for device | 
|  | * @sectors:	Size of the bio in 512-byte sectors | 
|  | * | 
|  | * Description: The block layer calculates everything in 512 byte | 
|  | * sectors but integrity metadata is done in terms of the data integrity | 
|  | * interval size of the storage device.  Convert the block layer sectors | 
|  | * to the appropriate number of integrity intervals. | 
|  | */ | 
|  | static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi, | 
|  | unsigned int sectors) | 
|  | { | 
|  | return sectors >> (bi->interval_exp - 9); | 
|  | } | 
|  |  | 
|  | static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi, | 
|  | unsigned int sectors) | 
|  | { | 
|  | return bio_integrity_intervals(bi, sectors) * bi->tuple_size; | 
|  | } | 
|  |  | 
|  | static inline bool blk_integrity_rq(struct request *rq) | 
|  | { | 
|  | return rq->cmd_flags & REQ_INTEGRITY; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Return the first bvec that contains integrity data.  Only drivers that are | 
|  | * limited to a single integrity segment should use this helper. | 
|  | */ | 
|  | static inline struct bio_vec *rq_integrity_vec(struct request *rq) | 
|  | { | 
|  | if (WARN_ON_ONCE(queue_max_integrity_segments(rq->q) > 1)) | 
|  | return NULL; | 
|  | return rq->bio->bi_integrity->bip_vec; | 
|  | } | 
|  | #else /* CONFIG_BLK_DEV_INTEGRITY */ | 
|  | static inline int blk_rq_count_integrity_sg(struct request_queue *q, | 
|  | struct bio *b) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | static inline int blk_rq_map_integrity_sg(struct request_queue *q, | 
|  | struct bio *b, | 
|  | struct scatterlist *s) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | static inline struct blk_integrity *bdev_get_integrity(struct block_device *b) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | static inline struct blk_integrity *blk_get_integrity(struct gendisk *disk) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | static inline bool | 
|  | blk_integrity_queue_supports_integrity(struct request_queue *q) | 
|  | { | 
|  | return false; | 
|  | } | 
|  | static inline int blk_integrity_compare(struct gendisk *a, struct gendisk *b) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | static inline void blk_integrity_register(struct gendisk *d, | 
|  | struct blk_integrity *b) | 
|  | { | 
|  | } | 
|  | static inline void blk_integrity_unregister(struct gendisk *d) | 
|  | { | 
|  | } | 
|  | static inline void blk_queue_max_integrity_segments(struct request_queue *q, | 
|  | unsigned int segs) | 
|  | { | 
|  | } | 
|  | static inline unsigned short | 
|  | queue_max_integrity_segments(const struct request_queue *q) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline unsigned int bio_integrity_intervals(struct blk_integrity *bi, | 
|  | unsigned int sectors) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi, | 
|  | unsigned int sectors) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  | static inline int blk_integrity_rq(struct request *rq) | 
|  | { | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | static inline struct bio_vec *rq_integrity_vec(struct request *rq) | 
|  | { | 
|  | return NULL; | 
|  | } | 
|  | #endif /* CONFIG_BLK_DEV_INTEGRITY */ | 
|  | #endif /* _LINUX_BLK_INTEGRITY_H */ |