| // SPDX-License-Identifier: GPL-2.0-only | |
| /* | |
| * Copyright (C) 2025 Christoph Hellwig | |
| */ | |
| #include <linux/blk-integrity.h> | |
| #include <linux/blk-mq-dma.h> | |
| #include "blk.h" | |
| static bool __blk_map_iter_next(struct blk_map_iter *iter) | |
| { | |
| if (iter->iter.bi_size) | |
| return true; | |
| if (!iter->bio || !iter->bio->bi_next) | |
| return false; | |
| iter->bio = iter->bio->bi_next; | |
| if (iter->is_integrity) { | |
| iter->iter = bio_integrity(iter->bio)->bip_iter; | |
| iter->bvecs = bio_integrity(iter->bio)->bip_vec; | |
| } else { | |
| iter->iter = iter->bio->bi_iter; | |
| iter->bvecs = iter->bio->bi_io_vec; | |
| } | |
| return true; | |
| } | |
| static bool blk_map_iter_next(struct request *req, struct blk_map_iter *iter, | |
| struct phys_vec *vec) | |
| { | |
| unsigned int max_size; | |
| struct bio_vec bv; | |
| if (!iter->iter.bi_size) | |
| return false; | |
| bv = mp_bvec_iter_bvec(iter->bvecs, iter->iter); | |
| vec->paddr = bvec_phys(&bv); | |
| max_size = get_max_segment_size(&req->q->limits, vec->paddr, UINT_MAX); | |
| bv.bv_len = min(bv.bv_len, max_size); | |
| bvec_iter_advance_single(iter->bvecs, &iter->iter, bv.bv_len); | |
| /* | |
| * If we are entirely done with this bi_io_vec entry, check if the next | |
| * one could be merged into it. This typically happens when moving to | |
| * the next bio, but some callers also don't pack bvecs tight. | |
| */ | |
| while (!iter->iter.bi_size || !iter->iter.bi_bvec_done) { | |
| struct bio_vec next; | |
| if (!__blk_map_iter_next(iter)) | |
| break; | |
| next = mp_bvec_iter_bvec(iter->bvecs, iter->iter); | |
| if (bv.bv_len + next.bv_len > max_size || | |
| !biovec_phys_mergeable(req->q, &bv, &next)) | |
| break; | |
| bv.bv_len += next.bv_len; | |
| bvec_iter_advance_single(iter->bvecs, &iter->iter, next.bv_len); | |
| } | |
| vec->len = bv.bv_len; | |
| return true; | |
| } | |
| /* | |
| * The IOVA-based DMA API wants to be able to coalesce at the minimal IOMMU page | |
| * size granularity (which is guaranteed to be <= PAGE_SIZE and usually 4k), so | |
| * we need to ensure our segments are aligned to this as well. | |
| * | |
| * Note that there is no point in using the slightly more complicated IOVA based | |
| * path for single segment mappings. | |
| */ | |
| static inline bool blk_can_dma_map_iova(struct request *req, | |
| struct device *dma_dev) | |
| { | |
| return !(req_phys_gap_mask(req) & dma_get_merge_boundary(dma_dev)); | |
| } | |
| static bool blk_dma_map_bus(struct blk_dma_iter *iter, struct phys_vec *vec) | |
| { | |
| iter->addr = pci_p2pdma_bus_addr_map(iter->p2pdma.mem, vec->paddr); | |
| iter->len = vec->len; | |
| return true; | |
| } | |
| static bool blk_dma_map_direct(struct request *req, struct device *dma_dev, | |
| struct blk_dma_iter *iter, struct phys_vec *vec) | |
| { | |
| unsigned int attrs = 0; | |
| if (iter->p2pdma.map == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) | |
| attrs |= DMA_ATTR_MMIO; | |
| iter->addr = dma_map_phys(dma_dev, vec->paddr, vec->len, | |
| rq_dma_dir(req), attrs); | |
| if (dma_mapping_error(dma_dev, iter->addr)) { | |
| iter->status = BLK_STS_RESOURCE; | |
| return false; | |
| } | |
| iter->len = vec->len; | |
| return true; | |
| } | |
| static bool blk_rq_dma_map_iova(struct request *req, struct device *dma_dev, | |
| struct dma_iova_state *state, struct blk_dma_iter *iter, | |
| struct phys_vec *vec) | |
| { | |
| enum dma_data_direction dir = rq_dma_dir(req); | |
| unsigned int attrs = 0; | |
| size_t mapped = 0; | |
| int error; | |
| iter->addr = state->addr; | |
| iter->len = dma_iova_size(state); | |
| if (iter->p2pdma.map == PCI_P2PDMA_MAP_THRU_HOST_BRIDGE) | |
| attrs |= DMA_ATTR_MMIO; | |
| do { | |
| error = dma_iova_link(dma_dev, state, vec->paddr, mapped, | |
| vec->len, dir, attrs); | |
| if (error) | |
| goto out_unlink; | |
| mapped += vec->len; | |
| } while (blk_map_iter_next(req, &iter->iter, vec)); | |
| error = dma_iova_sync(dma_dev, state, 0, mapped); | |
| if (error) | |
| goto out_unlink; | |
| return true; | |
| out_unlink: | |
| dma_iova_destroy(dma_dev, state, mapped, dir, attrs); | |
| iter->status = errno_to_blk_status(error); | |
| return false; | |
| } | |
| static inline void blk_rq_map_iter_init(struct request *rq, | |
| struct blk_map_iter *iter) | |
| { | |
| struct bio *bio = rq->bio; | |
| if (rq->rq_flags & RQF_SPECIAL_PAYLOAD) { | |
| *iter = (struct blk_map_iter) { | |
| .bvecs = &rq->special_vec, | |
| .iter = { | |
| .bi_size = rq->special_vec.bv_len, | |
| } | |
| }; | |
| } else if (bio) { | |
| *iter = (struct blk_map_iter) { | |
| .bio = bio, | |
| .bvecs = bio->bi_io_vec, | |
| .iter = bio->bi_iter, | |
| }; | |
| } else { | |
| /* the internal flush request may not have bio attached */ | |
| *iter = (struct blk_map_iter) {}; | |
| } | |
| } | |
| static bool blk_dma_map_iter_start(struct request *req, struct device *dma_dev, | |
| struct dma_iova_state *state, struct blk_dma_iter *iter, | |
| unsigned int total_len) | |
| { | |
| struct phys_vec vec; | |
| memset(&iter->p2pdma, 0, sizeof(iter->p2pdma)); | |
| iter->status = BLK_STS_OK; | |
| iter->p2pdma.map = PCI_P2PDMA_MAP_NONE; | |
| /* | |
| * Grab the first segment ASAP because we'll need it to check for P2P | |
| * transfers. | |
| */ | |
| if (!blk_map_iter_next(req, &iter->iter, &vec)) | |
| return false; | |
| switch (pci_p2pdma_state(&iter->p2pdma, dma_dev, | |
| phys_to_page(vec.paddr))) { | |
| case PCI_P2PDMA_MAP_BUS_ADDR: | |
| return blk_dma_map_bus(iter, &vec); | |
| case PCI_P2PDMA_MAP_THRU_HOST_BRIDGE: | |
| /* | |
| * P2P transfers through the host bridge are treated the | |
| * same as non-P2P transfers below and during unmap. | |
| */ | |
| case PCI_P2PDMA_MAP_NONE: | |
| break; | |
| default: | |
| iter->status = BLK_STS_INVAL; | |
| return false; | |
| } | |
| if (blk_can_dma_map_iova(req, dma_dev) && | |
| dma_iova_try_alloc(dma_dev, state, vec.paddr, total_len)) | |
| return blk_rq_dma_map_iova(req, dma_dev, state, iter, &vec); | |
| memset(state, 0, sizeof(*state)); | |
| return blk_dma_map_direct(req, dma_dev, iter, &vec); | |
| } | |
| /** | |
| * blk_rq_dma_map_iter_start - map the first DMA segment for a request | |
| * @req: request to map | |
| * @dma_dev: device to map to | |
| * @state: DMA IOVA state | |
| * @iter: block layer DMA iterator | |
| * | |
| * Start DMA mapping @req to @dma_dev. @state and @iter are provided by the | |
| * caller and don't need to be initialized. @state needs to be stored for use | |
| * at unmap time, @iter is only needed at map time. | |
| * | |
| * Returns %false if there is no segment to map, including due to an error, or | |
| * %true ft it did map a segment. | |
| * | |
| * If a segment was mapped, the DMA address for it is returned in @iter.addr and | |
| * the length in @iter.len. If no segment was mapped the status code is | |
| * returned in @iter.status. | |
| * | |
| * The caller can call blk_rq_dma_map_coalesce() to check if further segments | |
| * need to be mapped after this, or go straight to blk_rq_dma_map_iter_next() | |
| * to try to map the following segments. | |
| */ | |
| bool blk_rq_dma_map_iter_start(struct request *req, struct device *dma_dev, | |
| struct dma_iova_state *state, struct blk_dma_iter *iter) | |
| { | |
| blk_rq_map_iter_init(req, &iter->iter); | |
| return blk_dma_map_iter_start(req, dma_dev, state, iter, | |
| blk_rq_payload_bytes(req)); | |
| } | |
| EXPORT_SYMBOL_GPL(blk_rq_dma_map_iter_start); | |
| /** | |
| * blk_rq_dma_map_iter_next - map the next DMA segment for a request | |
| * @req: request to map | |
| * @dma_dev: device to map to | |
| * @iter: block layer DMA iterator | |
| * | |
| * Iterate to the next mapping after a previous call to | |
| * blk_rq_dma_map_iter_start(). See there for a detailed description of the | |
| * arguments. | |
| * | |
| * Returns %false if there is no segment to map, including due to an error, or | |
| * %true ft it did map a segment. | |
| * | |
| * If a segment was mapped, the DMA address for it is returned in @iter.addr and | |
| * the length in @iter.len. If no segment was mapped the status code is | |
| * returned in @iter.status. | |
| */ | |
| bool blk_rq_dma_map_iter_next(struct request *req, struct device *dma_dev, | |
| struct blk_dma_iter *iter) | |
| { | |
| struct phys_vec vec; | |
| if (!blk_map_iter_next(req, &iter->iter, &vec)) | |
| return false; | |
| if (iter->p2pdma.map == PCI_P2PDMA_MAP_BUS_ADDR) | |
| return blk_dma_map_bus(iter, &vec); | |
| return blk_dma_map_direct(req, dma_dev, iter, &vec); | |
| } | |
| EXPORT_SYMBOL_GPL(blk_rq_dma_map_iter_next); | |
| static inline struct scatterlist * | |
| blk_next_sg(struct scatterlist **sg, struct scatterlist *sglist) | |
| { | |
| if (!*sg) | |
| return sglist; | |
| /* | |
| * If the driver previously mapped a shorter list, we could see a | |
| * termination bit prematurely unless it fully inits the sg table | |
| * on each mapping. We KNOW that there must be more entries here | |
| * or the driver would be buggy, so force clear the termination bit | |
| * to avoid doing a full sg_init_table() in drivers for each command. | |
| */ | |
| sg_unmark_end(*sg); | |
| return sg_next(*sg); | |
| } | |
| /* | |
| * Map a request to scatterlist, return number of sg entries setup. Caller | |
| * must make sure sg can hold rq->nr_phys_segments entries. | |
| */ | |
| int __blk_rq_map_sg(struct request *rq, struct scatterlist *sglist, | |
| struct scatterlist **last_sg) | |
| { | |
| struct blk_map_iter iter; | |
| struct phys_vec vec; | |
| int nsegs = 0; | |
| blk_rq_map_iter_init(rq, &iter); | |
| while (blk_map_iter_next(rq, &iter, &vec)) { | |
| *last_sg = blk_next_sg(last_sg, sglist); | |
| WARN_ON_ONCE(overflows_type(vec.len, unsigned int)); | |
| sg_set_page(*last_sg, phys_to_page(vec.paddr), vec.len, | |
| offset_in_page(vec.paddr)); | |
| nsegs++; | |
| } | |
| if (*last_sg) | |
| sg_mark_end(*last_sg); | |
| /* | |
| * Something must have been wrong if the figured number of | |
| * segment is bigger than number of req's physical segments | |
| */ | |
| WARN_ON(nsegs > blk_rq_nr_phys_segments(rq)); | |
| return nsegs; | |
| } | |
| EXPORT_SYMBOL(__blk_rq_map_sg); | |
| #ifdef CONFIG_BLK_DEV_INTEGRITY | |
| /** | |
| * blk_rq_integrity_dma_map_iter_start - map the first integrity DMA segment | |
| * for a request | |
| * @req: request to map | |
| * @dma_dev: device to map to | |
| * @state: DMA IOVA state | |
| * @iter: block layer DMA iterator | |
| * | |
| * Start DMA mapping @req integrity data to @dma_dev. @state and @iter are | |
| * provided by the caller and don't need to be initialized. @state needs to be | |
| * stored for use at unmap time, @iter is only needed at map time. | |
| * | |
| * Returns %false if there is no segment to map, including due to an error, or | |
| * %true if it did map a segment. | |
| * | |
| * If a segment was mapped, the DMA address for it is returned in @iter.addr | |
| * and the length in @iter.len. If no segment was mapped the status code is | |
| * returned in @iter.status. | |
| * | |
| * The caller can call blk_rq_dma_map_coalesce() to check if further segments | |
| * need to be mapped after this, or go straight to blk_rq_dma_map_iter_next() | |
| * to try to map the following segments. | |
| */ | |
| bool blk_rq_integrity_dma_map_iter_start(struct request *req, | |
| struct device *dma_dev, struct dma_iova_state *state, | |
| struct blk_dma_iter *iter) | |
| { | |
| unsigned len = bio_integrity_bytes(&req->q->limits.integrity, | |
| blk_rq_sectors(req)); | |
| struct bio *bio = req->bio; | |
| iter->iter = (struct blk_map_iter) { | |
| .bio = bio, | |
| .iter = bio_integrity(bio)->bip_iter, | |
| .bvecs = bio_integrity(bio)->bip_vec, | |
| .is_integrity = true, | |
| }; | |
| return blk_dma_map_iter_start(req, dma_dev, state, iter, len); | |
| } | |
| EXPORT_SYMBOL_GPL(blk_rq_integrity_dma_map_iter_start); | |
| /** | |
| * blk_rq_integrity_dma_map_iter_next - map the next integrity DMA segment for | |
| * a request | |
| * @req: request to map | |
| * @dma_dev: device to map to | |
| * @state: DMA IOVA state | |
| * @iter: block layer DMA iterator | |
| * | |
| * Iterate to the next integrity mapping after a previous call to | |
| * blk_rq_integrity_dma_map_iter_start(). See there for a detailed description | |
| * of the arguments. | |
| * | |
| * Returns %false if there is no segment to map, including due to an error, or | |
| * %true if it did map a segment. | |
| * | |
| * If a segment was mapped, the DMA address for it is returned in @iter.addr and | |
| * the length in @iter.len. If no segment was mapped the status code is | |
| * returned in @iter.status. | |
| */ | |
| bool blk_rq_integrity_dma_map_iter_next(struct request *req, | |
| struct device *dma_dev, struct blk_dma_iter *iter) | |
| { | |
| struct phys_vec vec; | |
| if (!blk_map_iter_next(req, &iter->iter, &vec)) | |
| return false; | |
| if (iter->p2pdma.map == PCI_P2PDMA_MAP_BUS_ADDR) | |
| return blk_dma_map_bus(iter, &vec); | |
| return blk_dma_map_direct(req, dma_dev, iter, &vec); | |
| } | |
| EXPORT_SYMBOL_GPL(blk_rq_integrity_dma_map_iter_next); | |
| /** | |
| * blk_rq_map_integrity_sg - Map integrity metadata into a scatterlist | |
| * @rq: request to map | |
| * @sglist: target scatterlist | |
| * | |
| * Description: Map the integrity vectors in request into a | |
| * scatterlist. The scatterlist must be big enough to hold all | |
| * elements. I.e. sized using blk_rq_count_integrity_sg() or | |
| * rq->nr_integrity_segments. | |
| */ | |
| int blk_rq_map_integrity_sg(struct request *rq, struct scatterlist *sglist) | |
| { | |
| struct request_queue *q = rq->q; | |
| struct scatterlist *sg = NULL; | |
| struct bio *bio = rq->bio; | |
| unsigned int segments = 0; | |
| struct phys_vec vec; | |
| struct blk_map_iter iter = { | |
| .bio = bio, | |
| .iter = bio_integrity(bio)->bip_iter, | |
| .bvecs = bio_integrity(bio)->bip_vec, | |
| .is_integrity = true, | |
| }; | |
| while (blk_map_iter_next(rq, &iter, &vec)) { | |
| sg = blk_next_sg(&sg, sglist); | |
| WARN_ON_ONCE(overflows_type(vec.len, unsigned int)); | |
| sg_set_page(sg, phys_to_page(vec.paddr), vec.len, | |
| offset_in_page(vec.paddr)); | |
| segments++; | |
| } | |
| if (sg) | |
| sg_mark_end(sg); | |
| /* | |
| * Something must have been wrong if the figured number of segment | |
| * is bigger than number of req's physical integrity segments | |
| */ | |
| BUG_ON(segments > rq->nr_integrity_segments); | |
| BUG_ON(segments > queue_max_integrity_segments(q)); | |
| return segments; | |
| } | |
| EXPORT_SYMBOL(blk_rq_map_integrity_sg); | |
| #endif |