xref: /freebsd/sys/compat/linuxkpi/common/include/linux/scatterlist.h (revision 256eb8d5361143b7d436a195530e0eefe1450e6d)
18d59ecb2SHans Petter Selasky /*-
28d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Isilon Systems, Inc.
38d59ecb2SHans Petter Selasky  * Copyright (c) 2010 iX Systems, Inc.
48d59ecb2SHans Petter Selasky  * Copyright (c) 2010 Panasas, Inc.
58306998fSHans Petter Selasky  * Copyright (c) 2013-2017 Mellanox Technologies, Ltd.
68d59ecb2SHans Petter Selasky  * Copyright (c) 2015 Matthew Dillon <dillon@backplane.com>
7c072f6e8SVladimir Kondratyev  * Copyright (c) 2016 Matthew Macy
88d59ecb2SHans Petter Selasky  * All rights reserved.
98d59ecb2SHans Petter Selasky  *
108d59ecb2SHans Petter Selasky  * Redistribution and use in source and binary forms, with or without
118d59ecb2SHans Petter Selasky  * modification, are permitted provided that the following conditions
128d59ecb2SHans Petter Selasky  * are met:
138d59ecb2SHans Petter Selasky  * 1. Redistributions of source code must retain the above copyright
148d59ecb2SHans Petter Selasky  *    notice unmodified, this list of conditions, and the following
158d59ecb2SHans Petter Selasky  *    disclaimer.
168d59ecb2SHans Petter Selasky  * 2. Redistributions in binary form must reproduce the above copyright
178d59ecb2SHans Petter Selasky  *    notice, this list of conditions and the following disclaimer in the
188d59ecb2SHans Petter Selasky  *    documentation and/or other materials provided with the distribution.
198d59ecb2SHans Petter Selasky  *
208d59ecb2SHans Petter Selasky  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
218d59ecb2SHans Petter Selasky  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
228d59ecb2SHans Petter Selasky  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
238d59ecb2SHans Petter Selasky  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
248d59ecb2SHans Petter Selasky  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
258d59ecb2SHans Petter Selasky  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
268d59ecb2SHans Petter Selasky  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
278d59ecb2SHans Petter Selasky  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
288d59ecb2SHans Petter Selasky  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
298d59ecb2SHans Petter Selasky  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
308d59ecb2SHans Petter Selasky  */
31307f78f3SVladimir Kondratyev #ifndef	_LINUXKPI_LINUX_SCATTERLIST_H_
32307f78f3SVladimir Kondratyev #define	_LINUXKPI_LINUX_SCATTERLIST_H_
338d59ecb2SHans Petter Selasky 
344abbf816SBjoern A. Zeeb #include <sys/types.h>
35*256eb8d5SVladimir Kondratyev #include <sys/proc.h>
36*256eb8d5SVladimir Kondratyev #include <sys/sched.h>
374abbf816SBjoern A. Zeeb #include <sys/sf_buf.h>
384abbf816SBjoern A. Zeeb 
39*256eb8d5SVladimir Kondratyev #include <linux/err.h>
408d59ecb2SHans Petter Selasky #include <linux/page.h>
418d59ecb2SHans Petter Selasky #include <linux/slab.h>
428306998fSHans Petter Selasky #include <linux/mm.h>
438d59ecb2SHans Petter Selasky 
44442d12d8SHans Petter Selasky struct bus_dmamap;
458d59ecb2SHans Petter Selasky struct scatterlist {
468306998fSHans Petter Selasky 	unsigned long page_link;
4772ebbe00SHans Petter Selasky #define	SG_PAGE_LINK_CHAIN	0x1UL
4872ebbe00SHans Petter Selasky #define	SG_PAGE_LINK_LAST	0x2UL
4972ebbe00SHans Petter Selasky #define	SG_PAGE_LINK_MASK	0x3UL
508306998fSHans Petter Selasky 	unsigned int offset;
518306998fSHans Petter Selasky 	unsigned int length;
52f211d536STycho Nightingale 	dma_addr_t dma_address;
53442d12d8SHans Petter Selasky 	struct bus_dmamap *dma_map;	/* FreeBSD specific */
548d59ecb2SHans Petter Selasky };
558d59ecb2SHans Petter Selasky 
5672ebbe00SHans Petter Selasky CTASSERT((sizeof(struct scatterlist) & SG_PAGE_LINK_MASK) == 0);
578306998fSHans Petter Selasky 
588d59ecb2SHans Petter Selasky struct sg_table {
598d59ecb2SHans Petter Selasky 	struct scatterlist *sgl;
608d59ecb2SHans Petter Selasky 	unsigned int nents;
618d59ecb2SHans Petter Selasky 	unsigned int orig_nents;
628d59ecb2SHans Petter Selasky };
638d59ecb2SHans Petter Selasky 
648d59ecb2SHans Petter Selasky struct sg_page_iter {
658d59ecb2SHans Petter Selasky 	struct scatterlist *sg;
668d59ecb2SHans Petter Selasky 	unsigned int sg_pgoffset;
678d59ecb2SHans Petter Selasky 	unsigned int maxents;
688306998fSHans Petter Selasky 	struct {
698306998fSHans Petter Selasky 		unsigned int nents;
708306998fSHans Petter Selasky 		int	pg_advance;
718306998fSHans Petter Selasky 	} internal;
728d59ecb2SHans Petter Selasky };
738d59ecb2SHans Petter Selasky 
74fe4b041aSHans Petter Selasky struct sg_dma_page_iter {
75fe4b041aSHans Petter Selasky 	struct sg_page_iter base;
76fe4b041aSHans Petter Selasky };
77fe4b041aSHans Petter Selasky 
7857a865f8SHans Petter Selasky #define	SCATTERLIST_MAX_SEGMENT	(-1U & ~(PAGE_SIZE - 1))
7957a865f8SHans Petter Selasky 
808d59ecb2SHans Petter Selasky #define	SG_MAX_SINGLE_ALLOC	(PAGE_SIZE / sizeof(struct scatterlist))
818d59ecb2SHans Petter Selasky 
828306998fSHans Petter Selasky #define	SG_MAGIC		0x87654321UL
8356b16627SHans Petter Selasky #define	SG_CHAIN		SG_PAGE_LINK_CHAIN
8456b16627SHans Petter Selasky #define	SG_END			SG_PAGE_LINK_LAST
858306998fSHans Petter Selasky 
8672ebbe00SHans Petter Selasky #define	sg_is_chain(sg)		((sg)->page_link & SG_PAGE_LINK_CHAIN)
8772ebbe00SHans Petter Selasky #define	sg_is_last(sg)		((sg)->page_link & SG_PAGE_LINK_LAST)
888306998fSHans Petter Selasky #define	sg_chain_ptr(sg)	\
8972ebbe00SHans Petter Selasky 	((struct scatterlist *) ((sg)->page_link & ~SG_PAGE_LINK_MASK))
908306998fSHans Petter Selasky 
91f211d536STycho Nightingale #define	sg_dma_address(sg)	(sg)->dma_address
92442d12d8SHans Petter Selasky #define	sg_dma_len(sg)		(sg)->length
938d59ecb2SHans Petter Selasky 
948306998fSHans Petter Selasky #define	for_each_sg_page(sgl, iter, nents, pgoffset)			\
958306998fSHans Petter Selasky 	for (_sg_iter_init(sgl, iter, nents, pgoffset);			\
968306998fSHans Petter Selasky 	     (iter)->sg; _sg_iter_next(iter))
97fe4b041aSHans Petter Selasky #define	for_each_sg_dma_page(sgl, iter, nents, pgoffset) 		\
98fe4b041aSHans Petter Selasky 	for_each_sg_page(sgl, &(iter)->base, nents, pgoffset)
998306998fSHans Petter Selasky 
1008306998fSHans Petter Selasky #define	for_each_sg(sglist, sg, sgmax, iter)				\
1018306998fSHans Petter Selasky 	for (iter = 0, sg = (sglist); iter < (sgmax); iter++, sg = sg_next(sg))
1028306998fSHans Petter Selasky 
1034370e9f1SEmmanuel Vadot #define	for_each_sgtable_sg(sgt, sg, i) \
1044370e9f1SEmmanuel Vadot 	for_each_sg((sgt)->sgl, sg, (sgt)->orig_nents, i)
1054370e9f1SEmmanuel Vadot 
1064370e9f1SEmmanuel Vadot #define	for_each_sgtable_page(sgt, iter, pgoffset) \
1074370e9f1SEmmanuel Vadot 	for_each_sg_page((sgt)->sgl, iter, (sgt)->orig_nents, pgoffset)
1084370e9f1SEmmanuel Vadot 
1091aca8a6eSEmmanuel Vadot #define	for_each_sgtable_dma_sg(sgt, sg, iter)				\
1101aca8a6eSEmmanuel Vadot 	for_each_sg((sgt)->sgl, sg, (sgt)->nents, iter)
1111aca8a6eSEmmanuel Vadot 
1121aca8a6eSEmmanuel Vadot #define	for_each_sgtable_dma_page(sgt, iter, pgoffset)			\
1131aca8a6eSEmmanuel Vadot 	for_each_sg_dma_page((sgt)->sgl, iter, (sgt)->nents, pgoffset)
1141aca8a6eSEmmanuel Vadot 
1158306998fSHans Petter Selasky typedef struct scatterlist *(sg_alloc_fn) (unsigned int, gfp_t);
1168306998fSHans Petter Selasky typedef void (sg_free_fn) (struct scatterlist *, unsigned int);
1178306998fSHans Petter Selasky 
1188306998fSHans Petter Selasky static inline void
1198306998fSHans Petter Selasky sg_assign_page(struct scatterlist *sg, struct page *page)
1208306998fSHans Petter Selasky {
12172ebbe00SHans Petter Selasky 	unsigned long page_link = sg->page_link & SG_PAGE_LINK_MASK;
1228306998fSHans Petter Selasky 
1238306998fSHans Petter Selasky 	sg->page_link = page_link | (unsigned long)page;
1248306998fSHans Petter Selasky }
1258d59ecb2SHans Petter Selasky 
1268d59ecb2SHans Petter Selasky static inline void
1278d59ecb2SHans Petter Selasky sg_set_page(struct scatterlist *sg, struct page *page, unsigned int len,
1288d59ecb2SHans Petter Selasky     unsigned int offset)
1298d59ecb2SHans Petter Selasky {
1308306998fSHans Petter Selasky 	sg_assign_page(sg, page);
1318d59ecb2SHans Petter Selasky 	sg->offset = offset;
1328306998fSHans Petter Selasky 	sg->length = len;
1338306998fSHans Petter Selasky }
1348306998fSHans Petter Selasky 
1358306998fSHans Petter Selasky static inline struct page *
1368306998fSHans Petter Selasky sg_page(struct scatterlist *sg)
1378306998fSHans Petter Selasky {
13872ebbe00SHans Petter Selasky 	return ((struct page *)((sg)->page_link & ~SG_PAGE_LINK_MASK));
1398d59ecb2SHans Petter Selasky }
1408d59ecb2SHans Petter Selasky 
1418d59ecb2SHans Petter Selasky static inline void
1428d59ecb2SHans Petter Selasky sg_set_buf(struct scatterlist *sg, const void *buf, unsigned int buflen)
1438d59ecb2SHans Petter Selasky {
1448d59ecb2SHans Petter Selasky 	sg_set_page(sg, virt_to_page(buf), buflen,
1458d59ecb2SHans Petter Selasky 	    ((uintptr_t)buf) & (PAGE_SIZE - 1));
1468d59ecb2SHans Petter Selasky }
1478d59ecb2SHans Petter Selasky 
1488d59ecb2SHans Petter Selasky static inline struct scatterlist *
1498d59ecb2SHans Petter Selasky sg_next(struct scatterlist *sg)
1508d59ecb2SHans Petter Selasky {
1518306998fSHans Petter Selasky 	if (sg_is_last(sg))
1528d59ecb2SHans Petter Selasky 		return (NULL);
1538d59ecb2SHans Petter Selasky 	sg++;
1548306998fSHans Petter Selasky 	if (sg_is_chain(sg))
1558306998fSHans Petter Selasky 		sg = sg_chain_ptr(sg);
1568d59ecb2SHans Petter Selasky 	return (sg);
1578d59ecb2SHans Petter Selasky }
1588d59ecb2SHans Petter Selasky 
1598d59ecb2SHans Petter Selasky static inline vm_paddr_t
1608d59ecb2SHans Petter Selasky sg_phys(struct scatterlist *sg)
1618d59ecb2SHans Petter Selasky {
162d1ea0764SBjoern A. Zeeb 	return (page_to_phys(sg_page(sg)) + sg->offset);
1638d59ecb2SHans Petter Selasky }
1648d59ecb2SHans Petter Selasky 
165998f22ebSHans Petter Selasky static inline void *
166998f22ebSHans Petter Selasky sg_virt(struct scatterlist *sg)
167998f22ebSHans Petter Selasky {
168998f22ebSHans Petter Selasky 
169998f22ebSHans Petter Selasky 	return ((void *)((unsigned long)page_address(sg_page(sg)) + sg->offset));
170998f22ebSHans Petter Selasky }
171998f22ebSHans Petter Selasky 
1728d59ecb2SHans Petter Selasky static inline void
1738d59ecb2SHans Petter Selasky sg_chain(struct scatterlist *prv, unsigned int prv_nents,
1748d59ecb2SHans Petter Selasky     struct scatterlist *sgl)
1758d59ecb2SHans Petter Selasky {
1768d59ecb2SHans Petter Selasky 	struct scatterlist *sg = &prv[prv_nents - 1];
1778d59ecb2SHans Petter Selasky 
1788d59ecb2SHans Petter Selasky 	sg->offset = 0;
1798d59ecb2SHans Petter Selasky 	sg->length = 0;
18072ebbe00SHans Petter Selasky 	sg->page_link = ((unsigned long)sgl |
18172ebbe00SHans Petter Selasky 	    SG_PAGE_LINK_CHAIN) & ~SG_PAGE_LINK_LAST;
1828d59ecb2SHans Petter Selasky }
1838d59ecb2SHans Petter Selasky 
1848d59ecb2SHans Petter Selasky static inline void
1858d59ecb2SHans Petter Selasky sg_mark_end(struct scatterlist *sg)
1868d59ecb2SHans Petter Selasky {
18772ebbe00SHans Petter Selasky 	sg->page_link |= SG_PAGE_LINK_LAST;
18872ebbe00SHans Petter Selasky 	sg->page_link &= ~SG_PAGE_LINK_CHAIN;
1898d59ecb2SHans Petter Selasky }
1908d59ecb2SHans Petter Selasky 
1918d59ecb2SHans Petter Selasky static inline void
1928306998fSHans Petter Selasky sg_init_table(struct scatterlist *sg, unsigned int nents)
1938306998fSHans Petter Selasky {
1948306998fSHans Petter Selasky 	bzero(sg, sizeof(*sg) * nents);
1958306998fSHans Petter Selasky 	sg_mark_end(&sg[nents - 1]);
1968306998fSHans Petter Selasky }
1978306998fSHans Petter Selasky 
1982686b10dSAlex Richardson static inline void
1992686b10dSAlex Richardson sg_init_one(struct scatterlist *sg, const void *buf, unsigned int buflen)
2002686b10dSAlex Richardson {
2012686b10dSAlex Richardson 	sg_init_table(sg, 1);
2022686b10dSAlex Richardson 	sg_set_buf(sg, buf, buflen);
2032686b10dSAlex Richardson }
2042686b10dSAlex Richardson 
2058306998fSHans Petter Selasky static struct scatterlist *
2068306998fSHans Petter Selasky sg_kmalloc(unsigned int nents, gfp_t gfp_mask)
2078306998fSHans Petter Selasky {
2088306998fSHans Petter Selasky 	if (nents == SG_MAX_SINGLE_ALLOC) {
2098306998fSHans Petter Selasky 		return ((void *)__get_free_page(gfp_mask));
2108306998fSHans Petter Selasky 	} else
2118306998fSHans Petter Selasky 		return (kmalloc(nents * sizeof(struct scatterlist), gfp_mask));
2128306998fSHans Petter Selasky }
2138306998fSHans Petter Selasky 
2148306998fSHans Petter Selasky static inline void
2158306998fSHans Petter Selasky sg_kfree(struct scatterlist *sg, unsigned int nents)
2168306998fSHans Petter Selasky {
2178306998fSHans Petter Selasky 	if (nents == SG_MAX_SINGLE_ALLOC) {
2188306998fSHans Petter Selasky 		free_page((unsigned long)sg);
2198306998fSHans Petter Selasky 	} else
2208306998fSHans Petter Selasky 		kfree(sg);
2218306998fSHans Petter Selasky }
2228306998fSHans Petter Selasky 
2238306998fSHans Petter Selasky static inline void
2248306998fSHans Petter Selasky __sg_free_table(struct sg_table *table, unsigned int max_ents,
2258306998fSHans Petter Selasky     bool skip_first_chunk, sg_free_fn * free_fn)
2268d59ecb2SHans Petter Selasky {
2278d59ecb2SHans Petter Selasky 	struct scatterlist *sgl, *next;
2288d59ecb2SHans Petter Selasky 
2298d59ecb2SHans Petter Selasky 	if (unlikely(!table->sgl))
2308d59ecb2SHans Petter Selasky 		return;
2318d59ecb2SHans Petter Selasky 
2328d59ecb2SHans Petter Selasky 	sgl = table->sgl;
2338d59ecb2SHans Petter Selasky 	while (table->orig_nents) {
2348d59ecb2SHans Petter Selasky 		unsigned int alloc_size = table->orig_nents;
2358d59ecb2SHans Petter Selasky 		unsigned int sg_size;
2368d59ecb2SHans Petter Selasky 
2378d59ecb2SHans Petter Selasky 		if (alloc_size > max_ents) {
2388306998fSHans Petter Selasky 			next = sg_chain_ptr(&sgl[max_ents - 1]);
2398d59ecb2SHans Petter Selasky 			alloc_size = max_ents;
2408d59ecb2SHans Petter Selasky 			sg_size = alloc_size - 1;
2418d59ecb2SHans Petter Selasky 		} else {
2428d59ecb2SHans Petter Selasky 			sg_size = alloc_size;
2438d59ecb2SHans Petter Selasky 			next = NULL;
2448d59ecb2SHans Petter Selasky 		}
2458d59ecb2SHans Petter Selasky 
2468d59ecb2SHans Petter Selasky 		table->orig_nents -= sg_size;
2478306998fSHans Petter Selasky 		if (skip_first_chunk)
2488306998fSHans Petter Selasky 			skip_first_chunk = 0;
2498306998fSHans Petter Selasky 		else
2508306998fSHans Petter Selasky 			free_fn(sgl, alloc_size);
2518d59ecb2SHans Petter Selasky 		sgl = next;
2528d59ecb2SHans Petter Selasky 	}
2538d59ecb2SHans Petter Selasky 
2548d59ecb2SHans Petter Selasky 	table->sgl = NULL;
2558d59ecb2SHans Petter Selasky }
2568d59ecb2SHans Petter Selasky 
2578d59ecb2SHans Petter Selasky static inline void
2588d59ecb2SHans Petter Selasky sg_free_table(struct sg_table *table)
2598d59ecb2SHans Petter Selasky {
2608306998fSHans Petter Selasky 	__sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
2618d59ecb2SHans Petter Selasky }
2628d59ecb2SHans Petter Selasky 
2638d59ecb2SHans Petter Selasky static inline int
2648d59ecb2SHans Petter Selasky __sg_alloc_table(struct sg_table *table, unsigned int nents,
2658306998fSHans Petter Selasky     unsigned int max_ents, struct scatterlist *first_chunk,
2668306998fSHans Petter Selasky     gfp_t gfp_mask, sg_alloc_fn *alloc_fn)
2678d59ecb2SHans Petter Selasky {
2688d59ecb2SHans Petter Selasky 	struct scatterlist *sg, *prv;
2698d59ecb2SHans Petter Selasky 	unsigned int left;
2708d59ecb2SHans Petter Selasky 
2718d59ecb2SHans Petter Selasky 	memset(table, 0, sizeof(*table));
2728d59ecb2SHans Petter Selasky 
2738d59ecb2SHans Petter Selasky 	if (nents == 0)
2748306998fSHans Petter Selasky 		return (-EINVAL);
2758d59ecb2SHans Petter Selasky 	left = nents;
2768d59ecb2SHans Petter Selasky 	prv = NULL;
2778d59ecb2SHans Petter Selasky 	do {
2788d59ecb2SHans Petter Selasky 		unsigned int sg_size;
2798d59ecb2SHans Petter Selasky 		unsigned int alloc_size = left;
2808d59ecb2SHans Petter Selasky 
2818d59ecb2SHans Petter Selasky 		if (alloc_size > max_ents) {
2828d59ecb2SHans Petter Selasky 			alloc_size = max_ents;
2838d59ecb2SHans Petter Selasky 			sg_size = alloc_size - 1;
2848d59ecb2SHans Petter Selasky 		} else
2858d59ecb2SHans Petter Selasky 			sg_size = alloc_size;
2868d59ecb2SHans Petter Selasky 
2878d59ecb2SHans Petter Selasky 		left -= sg_size;
2888d59ecb2SHans Petter Selasky 
2898306998fSHans Petter Selasky 		if (first_chunk) {
2908306998fSHans Petter Selasky 			sg = first_chunk;
2918306998fSHans Petter Selasky 			first_chunk = NULL;
2928306998fSHans Petter Selasky 		} else {
2938306998fSHans Petter Selasky 			sg = alloc_fn(alloc_size, gfp_mask);
2948306998fSHans Petter Selasky 		}
2958d59ecb2SHans Petter Selasky 		if (unlikely(!sg)) {
2968d59ecb2SHans Petter Selasky 			if (prv)
2978d59ecb2SHans Petter Selasky 				table->nents = ++table->orig_nents;
2988d59ecb2SHans Petter Selasky 
2998306998fSHans Petter Selasky 			return (-ENOMEM);
3008d59ecb2SHans Petter Selasky 		}
3018d59ecb2SHans Petter Selasky 		sg_init_table(sg, alloc_size);
3028d59ecb2SHans Petter Selasky 		table->nents = table->orig_nents += sg_size;
3038d59ecb2SHans Petter Selasky 
3048d59ecb2SHans Petter Selasky 		if (prv)
3058d59ecb2SHans Petter Selasky 			sg_chain(prv, max_ents, sg);
3068d59ecb2SHans Petter Selasky 		else
3078d59ecb2SHans Petter Selasky 			table->sgl = sg;
3088d59ecb2SHans Petter Selasky 
3098d59ecb2SHans Petter Selasky 		if (!left)
3108d59ecb2SHans Petter Selasky 			sg_mark_end(&sg[sg_size - 1]);
3118d59ecb2SHans Petter Selasky 
3128d59ecb2SHans Petter Selasky 		prv = sg;
3138d59ecb2SHans Petter Selasky 	} while (left);
3148d59ecb2SHans Petter Selasky 
3158306998fSHans Petter Selasky 	return (0);
3168d59ecb2SHans Petter Selasky }
3178d59ecb2SHans Petter Selasky 
3188d59ecb2SHans Petter Selasky static inline int
3198d59ecb2SHans Petter Selasky sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask)
3208d59ecb2SHans Petter Selasky {
3218d59ecb2SHans Petter Selasky 	int ret;
3228d59ecb2SHans Petter Selasky 
3238d59ecb2SHans Petter Selasky 	ret = __sg_alloc_table(table, nents, SG_MAX_SINGLE_ALLOC,
3248306998fSHans Petter Selasky 	    NULL, gfp_mask, sg_kmalloc);
3258d59ecb2SHans Petter Selasky 	if (unlikely(ret))
3268306998fSHans Petter Selasky 		__sg_free_table(table, SG_MAX_SINGLE_ALLOC, 0, sg_kfree);
3278d59ecb2SHans Petter Selasky 
3288306998fSHans Petter Selasky 	return (ret);
3298306998fSHans Petter Selasky }
3308306998fSHans Petter Selasky 
3313e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3323e0856b6SJean-Sébastien Pédron static inline struct scatterlist *
3333e0856b6SJean-Sébastien Pédron __sg_alloc_table_from_pages(struct sg_table *sgt,
3343e0856b6SJean-Sébastien Pédron     struct page **pages, unsigned int count,
3353e0856b6SJean-Sébastien Pédron     unsigned long off, unsigned long size,
3363e0856b6SJean-Sébastien Pédron     unsigned int max_segment,
3373e0856b6SJean-Sébastien Pédron     struct scatterlist *prv, unsigned int left_pages,
3383e0856b6SJean-Sébastien Pédron     gfp_t gfp_mask)
3393e0856b6SJean-Sébastien Pédron #else
3408306998fSHans Petter Selasky static inline int
34157a865f8SHans Petter Selasky __sg_alloc_table_from_pages(struct sg_table *sgt,
3428306998fSHans Petter Selasky     struct page **pages, unsigned int count,
3438306998fSHans Petter Selasky     unsigned long off, unsigned long size,
34457a865f8SHans Petter Selasky     unsigned int max_segment, gfp_t gfp_mask)
3453e0856b6SJean-Sébastien Pédron #endif
3468306998fSHans Petter Selasky {
34757a865f8SHans Petter Selasky 	unsigned int i, segs, cur, len;
3488306998fSHans Petter Selasky 	int rc;
34909b0401eSAustin Shafer 	struct scatterlist *s, *sg_iter;
3508306998fSHans Petter Selasky 
3513e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3523e0856b6SJean-Sébastien Pédron 	if (prv != NULL) {
3533e0856b6SJean-Sébastien Pédron 		panic(
3543e0856b6SJean-Sébastien Pédron 		    "Support for prv != NULL not implemented in "
3553e0856b6SJean-Sébastien Pédron 		    "__sg_alloc_table_from_pages()");
3563e0856b6SJean-Sébastien Pédron 	}
3573e0856b6SJean-Sébastien Pédron #endif
3583e0856b6SJean-Sébastien Pédron 
35957a865f8SHans Petter Selasky 	if (__predict_false(!max_segment || offset_in_page(max_segment)))
3603e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3613e0856b6SJean-Sébastien Pédron 		return (ERR_PTR(-EINVAL));
3623e0856b6SJean-Sébastien Pédron #else
36357a865f8SHans Petter Selasky 		return (-EINVAL);
3643e0856b6SJean-Sébastien Pédron #endif
36557a865f8SHans Petter Selasky 
36657a865f8SHans Petter Selasky 	len = 0;
3678306998fSHans Petter Selasky 	for (segs = i = 1; i < count; ++i) {
36857a865f8SHans Petter Selasky 		len += PAGE_SIZE;
36957a865f8SHans Petter Selasky 		if (len >= max_segment ||
37057a865f8SHans Petter Selasky 		    page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) {
3718306998fSHans Petter Selasky 			++segs;
37257a865f8SHans Petter Selasky 			len = 0;
37357a865f8SHans Petter Selasky 		}
3748306998fSHans Petter Selasky 	}
3758306998fSHans Petter Selasky 	if (__predict_false((rc = sg_alloc_table(sgt, segs, gfp_mask))))
3763e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
3773e0856b6SJean-Sébastien Pédron 		return (ERR_PTR(rc));
3783e0856b6SJean-Sébastien Pédron #else
3798306998fSHans Petter Selasky 		return (rc);
3803e0856b6SJean-Sébastien Pédron #endif
3818306998fSHans Petter Selasky 
3828306998fSHans Petter Selasky 	cur = 0;
38309b0401eSAustin Shafer 	for_each_sg(sgt->sgl, sg_iter, sgt->orig_nents, i) {
3848306998fSHans Petter Selasky 		unsigned long seg_size;
3858306998fSHans Petter Selasky 		unsigned int j;
3868306998fSHans Petter Selasky 
38709b0401eSAustin Shafer 		/*
38809b0401eSAustin Shafer 		 * We need to make sure that when we exit this loop "s" has the
38909b0401eSAustin Shafer 		 * last sg in the chain so we can call sg_mark_end() on it.
39009b0401eSAustin Shafer 		 * Only set this inside the loop since sg_iter will be iterated
39109b0401eSAustin Shafer 		 * until it is NULL.
39209b0401eSAustin Shafer 		 */
39309b0401eSAustin Shafer 		s = sg_iter;
39409b0401eSAustin Shafer 
39557a865f8SHans Petter Selasky 		len = 0;
39657a865f8SHans Petter Selasky 		for (j = cur + 1; j < count; ++j) {
39757a865f8SHans Petter Selasky 			len += PAGE_SIZE;
39857a865f8SHans Petter Selasky 			if (len >= max_segment || page_to_pfn(pages[j]) !=
3998306998fSHans Petter Selasky 			    page_to_pfn(pages[j - 1]) + 1)
4008306998fSHans Petter Selasky 				break;
40157a865f8SHans Petter Selasky 		}
4028306998fSHans Petter Selasky 
4038306998fSHans Petter Selasky 		seg_size = ((j - cur) << PAGE_SHIFT) - off;
404a399cf13SHans Petter Selasky 		sg_set_page(s, pages[cur], MIN(size, seg_size), off);
4058306998fSHans Petter Selasky 		size -= seg_size;
4068306998fSHans Petter Selasky 		off = 0;
4078306998fSHans Petter Selasky 		cur = j;
4088306998fSHans Petter Selasky 	}
4093e0856b6SJean-Sébastien Pédron 	KASSERT(s != NULL, ("s is NULL after loop in __sg_alloc_table_from_pages()"));
4103e0856b6SJean-Sébastien Pédron 
4113e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
4123e0856b6SJean-Sébastien Pédron 	if (left_pages == 0)
4133e0856b6SJean-Sébastien Pédron 		sg_mark_end(s);
4143e0856b6SJean-Sébastien Pédron 
4153e0856b6SJean-Sébastien Pédron 	return (s);
4163e0856b6SJean-Sébastien Pédron #else
4178306998fSHans Petter Selasky 	return (0);
4183e0856b6SJean-Sébastien Pédron #endif
4198306998fSHans Petter Selasky }
4208306998fSHans Petter Selasky 
42157a865f8SHans Petter Selasky static inline int
42257a865f8SHans Petter Selasky sg_alloc_table_from_pages(struct sg_table *sgt,
42357a865f8SHans Petter Selasky     struct page **pages, unsigned int count,
42457a865f8SHans Petter Selasky     unsigned long off, unsigned long size,
42557a865f8SHans Petter Selasky     gfp_t gfp_mask)
42657a865f8SHans Petter Selasky {
42757a865f8SHans Petter Selasky 
4283e0856b6SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
4293e0856b6SJean-Sébastien Pédron 	return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
4303e0856b6SJean-Sébastien Pédron 	    SCATTERLIST_MAX_SEGMENT, NULL, 0, gfp_mask)));
4313e0856b6SJean-Sébastien Pédron #else
43257a865f8SHans Petter Selasky 	return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
43357a865f8SHans Petter Selasky 	    SCATTERLIST_MAX_SEGMENT, gfp_mask));
4343e0856b6SJean-Sébastien Pédron #endif
43557a865f8SHans Petter Selasky }
4368306998fSHans Petter Selasky 
4378306998fSHans Petter Selasky static inline int
438f3490083SJean-Sébastien Pédron sg_alloc_table_from_pages_segment(struct sg_table *sgt,
439f3490083SJean-Sébastien Pédron     struct page **pages, unsigned int count, unsigned int off,
440f3490083SJean-Sébastien Pédron     unsigned long size, unsigned int max_segment, gfp_t gfp_mask)
441f3490083SJean-Sébastien Pédron {
442f3490083SJean-Sébastien Pédron #if defined(LINUXKPI_VERSION) && LINUXKPI_VERSION >= 51300
443f3490083SJean-Sébastien Pédron 	return (PTR_ERR_OR_ZERO(__sg_alloc_table_from_pages(sgt, pages, count, off, size,
444f3490083SJean-Sébastien Pédron 	    max_segment, NULL, 0, gfp_mask)));
445f3490083SJean-Sébastien Pédron #else
446f3490083SJean-Sébastien Pédron 	return (__sg_alloc_table_from_pages(sgt, pages, count, off, size,
447f3490083SJean-Sébastien Pédron 	    max_segment, gfp_mask));
448f3490083SJean-Sébastien Pédron #endif
449f3490083SJean-Sébastien Pédron }
450f3490083SJean-Sébastien Pédron 
451f3490083SJean-Sébastien Pédron static inline int
4528306998fSHans Petter Selasky sg_nents(struct scatterlist *sg)
4538306998fSHans Petter Selasky {
4548306998fSHans Petter Selasky 	int nents;
4558306998fSHans Petter Selasky 
4568306998fSHans Petter Selasky 	for (nents = 0; sg; sg = sg_next(sg))
4578306998fSHans Petter Selasky 		nents++;
4588306998fSHans Petter Selasky 	return (nents);
4598306998fSHans Petter Selasky }
4608306998fSHans Petter Selasky 
4618306998fSHans Petter Selasky static inline void
4628306998fSHans Petter Selasky __sg_page_iter_start(struct sg_page_iter *piter,
4638306998fSHans Petter Selasky     struct scatterlist *sglist, unsigned int nents,
4648306998fSHans Petter Selasky     unsigned long pgoffset)
4658306998fSHans Petter Selasky {
4668306998fSHans Petter Selasky 	piter->internal.pg_advance = 0;
4678306998fSHans Petter Selasky 	piter->internal.nents = nents;
4688306998fSHans Petter Selasky 
4698306998fSHans Petter Selasky 	piter->sg = sglist;
4708306998fSHans Petter Selasky 	piter->sg_pgoffset = pgoffset;
4718d59ecb2SHans Petter Selasky }
4728d59ecb2SHans Petter Selasky 
4738d59ecb2SHans Petter Selasky static inline void
4748d59ecb2SHans Petter Selasky _sg_iter_next(struct sg_page_iter *iter)
4758d59ecb2SHans Petter Selasky {
4768d59ecb2SHans Petter Selasky 	struct scatterlist *sg;
4778d59ecb2SHans Petter Selasky 	unsigned int pgcount;
4788d59ecb2SHans Petter Selasky 
4798d59ecb2SHans Petter Selasky 	sg = iter->sg;
4808d59ecb2SHans Petter Selasky 	pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
4818d59ecb2SHans Petter Selasky 
4828d59ecb2SHans Petter Selasky 	++iter->sg_pgoffset;
4838d59ecb2SHans Petter Selasky 	while (iter->sg_pgoffset >= pgcount) {
4848d59ecb2SHans Petter Selasky 		iter->sg_pgoffset -= pgcount;
4858d59ecb2SHans Petter Selasky 		sg = sg_next(sg);
4868d59ecb2SHans Petter Selasky 		--iter->maxents;
4878d59ecb2SHans Petter Selasky 		if (sg == NULL || iter->maxents == 0)
4888d59ecb2SHans Petter Selasky 			break;
4898d59ecb2SHans Petter Selasky 		pgcount = (sg->offset + sg->length + PAGE_SIZE - 1) >> PAGE_SHIFT;
4908d59ecb2SHans Petter Selasky 	}
4918d59ecb2SHans Petter Selasky 	iter->sg = sg;
4928d59ecb2SHans Petter Selasky }
4938d59ecb2SHans Petter Selasky 
4948306998fSHans Petter Selasky static inline int
4958306998fSHans Petter Selasky sg_page_count(struct scatterlist *sg)
4968306998fSHans Petter Selasky {
4978306998fSHans Petter Selasky 	return (PAGE_ALIGN(sg->offset + sg->length) >> PAGE_SHIFT);
4988306998fSHans Petter Selasky }
499fe4b041aSHans Petter Selasky #define	sg_dma_page_count(sg) \
500fe4b041aSHans Petter Selasky 	sg_page_count(sg)
5018306998fSHans Petter Selasky 
5028306998fSHans Petter Selasky static inline bool
5038306998fSHans Petter Selasky __sg_page_iter_next(struct sg_page_iter *piter)
5048306998fSHans Petter Selasky {
5055e6233ccSHans Petter Selasky 	unsigned int pgcount;
5065e6233ccSHans Petter Selasky 
5078306998fSHans Petter Selasky 	if (piter->internal.nents == 0)
5088306998fSHans Petter Selasky 		return (0);
5098306998fSHans Petter Selasky 	if (piter->sg == NULL)
5108306998fSHans Petter Selasky 		return (0);
5118306998fSHans Petter Selasky 
5128306998fSHans Petter Selasky 	piter->sg_pgoffset += piter->internal.pg_advance;
5138306998fSHans Petter Selasky 	piter->internal.pg_advance = 1;
5148306998fSHans Petter Selasky 
5155e6233ccSHans Petter Selasky 	while (1) {
5165e6233ccSHans Petter Selasky 		pgcount = sg_page_count(piter->sg);
5175e6233ccSHans Petter Selasky 		if (likely(piter->sg_pgoffset < pgcount))
5185e6233ccSHans Petter Selasky 			break;
5195e6233ccSHans Petter Selasky 		piter->sg_pgoffset -= pgcount;
5208306998fSHans Petter Selasky 		piter->sg = sg_next(piter->sg);
5218306998fSHans Petter Selasky 		if (--piter->internal.nents == 0)
5228306998fSHans Petter Selasky 			return (0);
5238306998fSHans Petter Selasky 		if (piter->sg == NULL)
5248306998fSHans Petter Selasky 			return (0);
5258306998fSHans Petter Selasky 	}
5268306998fSHans Petter Selasky 	return (1);
5278306998fSHans Petter Selasky }
528fe4b041aSHans Petter Selasky #define	__sg_page_iter_dma_next(itr) \
529fe4b041aSHans Petter Selasky 	__sg_page_iter_next(&(itr)->base)
5308306998fSHans Petter Selasky 
5318d59ecb2SHans Petter Selasky static inline void
5328d59ecb2SHans Petter Selasky _sg_iter_init(struct scatterlist *sgl, struct sg_page_iter *iter,
5338d59ecb2SHans Petter Selasky     unsigned int nents, unsigned long pgoffset)
5348d59ecb2SHans Petter Selasky {
5358d59ecb2SHans Petter Selasky 	if (nents) {
5368d59ecb2SHans Petter Selasky 		iter->sg = sgl;
5378d59ecb2SHans Petter Selasky 		iter->sg_pgoffset = pgoffset - 1;
5388d59ecb2SHans Petter Selasky 		iter->maxents = nents;
5398d59ecb2SHans Petter Selasky 		_sg_iter_next(iter);
5408d59ecb2SHans Petter Selasky 	} else {
5418d59ecb2SHans Petter Selasky 		iter->sg = NULL;
5428d59ecb2SHans Petter Selasky 		iter->sg_pgoffset = 0;
5438d59ecb2SHans Petter Selasky 		iter->maxents = 0;
5448d59ecb2SHans Petter Selasky 	}
5458d59ecb2SHans Petter Selasky }
5468d59ecb2SHans Petter Selasky 
547fe4b041aSHans Petter Selasky /*
548fe4b041aSHans Petter Selasky  * sg_page_iter_dma_address() is implemented as a macro because it
549fe4b041aSHans Petter Selasky  * needs to accept two different and identical structure types. This
550fe4b041aSHans Petter Selasky  * allows both old and new code to co-exist. The compile time assert
551fe4b041aSHans Petter Selasky  * adds some safety, that the structure sizes match.
552fe4b041aSHans Petter Selasky  */
553fe4b041aSHans Petter Selasky #define	sg_page_iter_dma_address(spi) ({		\
554fe4b041aSHans Petter Selasky 	struct sg_page_iter *__spi = (void *)(spi);	\
555fe4b041aSHans Petter Selasky 	dma_addr_t __dma_address;			\
556fe4b041aSHans Petter Selasky 	CTASSERT(sizeof(*(spi)) == sizeof(*__spi));	\
557fe4b041aSHans Petter Selasky 	__dma_address = __spi->sg->dma_address +	\
558fe4b041aSHans Petter Selasky 	    (__spi->sg_pgoffset << PAGE_SHIFT);		\
559fe4b041aSHans Petter Selasky 	__dma_address;					\
560fe4b041aSHans Petter Selasky })
5618d59ecb2SHans Petter Selasky 
5628306998fSHans Petter Selasky static inline struct page *
5638306998fSHans Petter Selasky sg_page_iter_page(struct sg_page_iter *piter)
5648306998fSHans Petter Selasky {
5658306998fSHans Petter Selasky 	return (nth_page(sg_page(piter->sg), piter->sg_pgoffset));
5668306998fSHans Petter Selasky }
5678d59ecb2SHans Petter Selasky 
5684abbf816SBjoern A. Zeeb static __inline size_t
5694abbf816SBjoern A. Zeeb sg_pcopy_from_buffer(struct scatterlist *sgl, unsigned int nents,
5704abbf816SBjoern A. Zeeb     const void *buf, size_t buflen, off_t skip)
5714abbf816SBjoern A. Zeeb {
5724abbf816SBjoern A. Zeeb 	struct sg_page_iter piter;
5734abbf816SBjoern A. Zeeb 	struct page *page;
5744abbf816SBjoern A. Zeeb 	struct sf_buf *sf;
5754abbf816SBjoern A. Zeeb 	size_t len, copied;
5764abbf816SBjoern A. Zeeb 	char *p, *b;
5774abbf816SBjoern A. Zeeb 
5784abbf816SBjoern A. Zeeb 	if (buflen == 0)
5794abbf816SBjoern A. Zeeb 		return (0);
5804abbf816SBjoern A. Zeeb 
5814abbf816SBjoern A. Zeeb 	b = __DECONST(char *, buf);
5824abbf816SBjoern A. Zeeb 	copied = 0;
5834abbf816SBjoern A. Zeeb 	sched_pin();
5844abbf816SBjoern A. Zeeb 	for_each_sg_page(sgl, &piter, nents, 0) {
5854abbf816SBjoern A. Zeeb 
5864abbf816SBjoern A. Zeeb 		/* Skip to the start. */
5874abbf816SBjoern A. Zeeb 		if (piter.sg->length <= skip) {
5884abbf816SBjoern A. Zeeb 			skip -= piter.sg->length;
5894abbf816SBjoern A. Zeeb 			continue;
5904abbf816SBjoern A. Zeeb 		}
5914abbf816SBjoern A. Zeeb 
5924abbf816SBjoern A. Zeeb 		/* See how much to copy. */
5934abbf816SBjoern A. Zeeb 		KASSERT(((piter.sg->length - skip) != 0 && (buflen != 0)),
5944abbf816SBjoern A. Zeeb 		    ("%s: sg len %u - skip %ju || buflen %zu is 0\n",
5954abbf816SBjoern A. Zeeb 		    __func__, piter.sg->length, (uintmax_t)skip, buflen));
5964abbf816SBjoern A. Zeeb 		len = min(piter.sg->length - skip, buflen);
5974abbf816SBjoern A. Zeeb 
5984abbf816SBjoern A. Zeeb 		page = sg_page_iter_page(&piter);
5994abbf816SBjoern A. Zeeb 		sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
6004abbf816SBjoern A. Zeeb 		if (sf == NULL)
6014abbf816SBjoern A. Zeeb 			break;
6024abbf816SBjoern A. Zeeb 		p = (char *)sf_buf_kva(sf) + piter.sg_pgoffset + skip;
6034abbf816SBjoern A. Zeeb 		memcpy(p, b, len);
6044abbf816SBjoern A. Zeeb 		sf_buf_free(sf);
6054abbf816SBjoern A. Zeeb 
606edfcdffeSBjoern A. Zeeb 		/* We copied so nothing more to skip. */
607edfcdffeSBjoern A. Zeeb 		skip = 0;
6084abbf816SBjoern A. Zeeb 		copied += len;
6094abbf816SBjoern A. Zeeb 		/* Either we exactly filled the page, or we are done. */
6104abbf816SBjoern A. Zeeb 		buflen -= len;
6114abbf816SBjoern A. Zeeb 		if (buflen == 0)
6124abbf816SBjoern A. Zeeb 			break;
6134abbf816SBjoern A. Zeeb 		b += len;
6144abbf816SBjoern A. Zeeb 	}
6154abbf816SBjoern A. Zeeb 	sched_unpin();
6164abbf816SBjoern A. Zeeb 
6174abbf816SBjoern A. Zeeb 	return (copied);
6184abbf816SBjoern A. Zeeb }
6194abbf816SBjoern A. Zeeb 
620c072f6e8SVladimir Kondratyev static inline size_t
621c072f6e8SVladimir Kondratyev sg_copy_from_buffer(struct scatterlist *sgl, unsigned int nents,
622c072f6e8SVladimir Kondratyev     const void *buf, size_t buflen)
623c072f6e8SVladimir Kondratyev {
624c072f6e8SVladimir Kondratyev 	return (sg_pcopy_from_buffer(sgl, nents, buf, buflen, 0));
625c072f6e8SVladimir Kondratyev }
626c072f6e8SVladimir Kondratyev 
627c072f6e8SVladimir Kondratyev static inline size_t
628c072f6e8SVladimir Kondratyev sg_pcopy_to_buffer(struct scatterlist *sgl, unsigned int nents,
629c072f6e8SVladimir Kondratyev     void *buf, size_t buflen, off_t offset)
630c072f6e8SVladimir Kondratyev {
631c072f6e8SVladimir Kondratyev 	struct sg_page_iter iter;
632c072f6e8SVladimir Kondratyev 	struct scatterlist *sg;
633c072f6e8SVladimir Kondratyev 	struct page *page;
634c072f6e8SVladimir Kondratyev 	struct sf_buf *sf;
635c072f6e8SVladimir Kondratyev 	char *vaddr;
636c072f6e8SVladimir Kondratyev 	size_t total = 0;
637c072f6e8SVladimir Kondratyev 	size_t len;
638c072f6e8SVladimir Kondratyev 
639c072f6e8SVladimir Kondratyev 	if (!PMAP_HAS_DMAP)
640c072f6e8SVladimir Kondratyev 		sched_pin();
641c072f6e8SVladimir Kondratyev 	for_each_sg_page(sgl, &iter, nents, 0) {
642c072f6e8SVladimir Kondratyev 		sg = iter.sg;
643c072f6e8SVladimir Kondratyev 
644c072f6e8SVladimir Kondratyev 		if (offset >= sg->length) {
645c072f6e8SVladimir Kondratyev 			offset -= sg->length;
646c072f6e8SVladimir Kondratyev 			continue;
647c072f6e8SVladimir Kondratyev 		}
648c072f6e8SVladimir Kondratyev 		len = ulmin(buflen, sg->length - offset);
649c072f6e8SVladimir Kondratyev 		if (len == 0)
650c072f6e8SVladimir Kondratyev 			break;
651c072f6e8SVladimir Kondratyev 
652c072f6e8SVladimir Kondratyev 		page = sg_page_iter_page(&iter);
653c072f6e8SVladimir Kondratyev 		if (!PMAP_HAS_DMAP) {
654c072f6e8SVladimir Kondratyev 			sf = sf_buf_alloc(page, SFB_CPUPRIVATE | SFB_NOWAIT);
655c072f6e8SVladimir Kondratyev 			if (sf == NULL)
656c072f6e8SVladimir Kondratyev 				break;
657c072f6e8SVladimir Kondratyev 			vaddr = (char *)sf_buf_kva(sf);
658c072f6e8SVladimir Kondratyev 		} else
659d1ea0764SBjoern A. Zeeb 			vaddr = (char *)PHYS_TO_DMAP(page_to_phys(page));
660c072f6e8SVladimir Kondratyev 		memcpy(buf, vaddr + sg->offset + offset, len);
661c072f6e8SVladimir Kondratyev 		if (!PMAP_HAS_DMAP)
662c072f6e8SVladimir Kondratyev 			sf_buf_free(sf);
663c072f6e8SVladimir Kondratyev 
664c072f6e8SVladimir Kondratyev 		/* start at beginning of next page */
665c072f6e8SVladimir Kondratyev 		offset = 0;
666c072f6e8SVladimir Kondratyev 
667c072f6e8SVladimir Kondratyev 		/* advance buffer */
668c072f6e8SVladimir Kondratyev 		buf = (char *)buf + len;
669c072f6e8SVladimir Kondratyev 		buflen -= len;
670c072f6e8SVladimir Kondratyev 		total += len;
671c072f6e8SVladimir Kondratyev 	}
672c072f6e8SVladimir Kondratyev 	if (!PMAP_HAS_DMAP)
673c072f6e8SVladimir Kondratyev 		sched_unpin();
674c072f6e8SVladimir Kondratyev 	return (total);
675c072f6e8SVladimir Kondratyev }
676c072f6e8SVladimir Kondratyev 
677307f78f3SVladimir Kondratyev #endif					/* _LINUXKPI_LINUX_SCATTERLIST_H_ */
678