subr_bus_dma.c revision 249538
1246713Skib/*-
2246713Skib * Copyright (c) 2012 EMC Corp.
3246713Skib * All rights reserved.
4246713Skib *
5246713Skib * Copyright (c) 1997, 1998 Justin T. Gibbs.
6246713Skib * All rights reserved.
7246713Skib *
8246713Skib * Redistribution and use in source and binary forms, with or without
9246713Skib * modification, are permitted provided that the following conditions
10246713Skib * are met:
11246713Skib * 1. Redistributions of source code must retain the above copyright
12246713Skib *    notice, this list of conditions and the following disclaimer.
13246713Skib * 2. Redistributions in binary form must reproduce the above copyright
14246713Skib *    notice, this list of conditions and the following disclaimer in the
15246713Skib *    documentation and/or other materials provided with the distribution.
16246713Skib *
17246713Skib * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18246713Skib * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19246713Skib * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20246713Skib * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21246713Skib * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22246713Skib * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23246713Skib * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24246713Skib * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25246713Skib * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26246713Skib * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27246713Skib * SUCH DAMAGE.
28246713Skib */
29246713Skib
30246713Skib#include <sys/cdefs.h>
31246713Skib__FBSDID("$FreeBSD: head/sys/kern/subr_bus_dma.c 249538 2013-04-16 07:11:52Z kib $");
32246713Skib
33246713Skib#include "opt_bus.h"
34246713Skib
35246713Skib#include <sys/param.h>
36246713Skib#include <sys/conf.h>
37246713Skib#include <sys/systm.h>
38246713Skib#include <sys/bio.h>
39246713Skib#include <sys/bus.h>
40246713Skib#include <sys/callout.h>
41246713Skib#include <sys/mbuf.h>
42246713Skib#include <sys/memdesc.h>
43246713Skib#include <sys/proc.h>
44246713Skib#include <sys/uio.h>
45246713Skib
46246713Skib#include <vm/vm.h>
47246713Skib#include <vm/vm_page.h>
48246713Skib#include <vm/vm_map.h>
49246713Skib#include <vm/pmap.h>
50246713Skib
51246713Skib#include <cam/cam.h>
52246713Skib#include <cam/cam_ccb.h>
53246713Skib
54246713Skib#include <machine/bus.h>
55246713Skib
56246713Skib/*
57246713Skib * Load a list of virtual addresses.
58246713Skib */
59246713Skibstatic int
60246713Skib_bus_dmamap_load_vlist(bus_dma_tag_t dmat, bus_dmamap_t map,
61246713Skib    bus_dma_segment_t *list, int sglist_cnt, struct pmap *pmap, int *nsegs,
62246713Skib    int flags)
63246713Skib{
64246713Skib	int error;
65246713Skib
66246713Skib	error = 0;
67246713Skib	for (; sglist_cnt > 0; sglist_cnt--, list++) {
68246713Skib		error = _bus_dmamap_load_buffer(dmat, map,
69249538Skib		    (void *)(uintptr_t)list->ds_addr, list->ds_len, pmap,
70249538Skib		    flags, NULL, nsegs);
71246713Skib		if (error)
72246713Skib			break;
73246713Skib	}
74246713Skib	return (error);
75246713Skib}
76246713Skib
77246713Skib/*
78246713Skib * Load a list of physical addresses.
79246713Skib */
80246713Skibstatic int
81246713Skib_bus_dmamap_load_plist(bus_dma_tag_t dmat, bus_dmamap_t map,
82246713Skib    bus_dma_segment_t *list, int sglist_cnt, int *nsegs, int flags)
83246713Skib{
84246713Skib	int error;
85246713Skib
86246713Skib	error = 0;
87246713Skib	for (; sglist_cnt > 0; sglist_cnt--, list++) {
88246713Skib		error = _bus_dmamap_load_phys(dmat, map,
89246713Skib		    (vm_paddr_t)list->ds_addr, list->ds_len, flags, NULL,
90246713Skib		    nsegs);
91246713Skib		if (error)
92246713Skib			break;
93246713Skib	}
94246713Skib	return (error);
95246713Skib}
96246713Skib
97246713Skib/*
98246713Skib * Load an mbuf chain.
99246713Skib */
100246713Skibstatic int
101246713Skib_bus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map,
102246713Skib    struct mbuf *m0, bus_dma_segment_t *segs, int *nsegs, int flags)
103246713Skib{
104246713Skib	struct mbuf *m;
105246713Skib	int error;
106246713Skib
107246713Skib	M_ASSERTPKTHDR(m0);
108246713Skib
109246713Skib	error = 0;
110246713Skib	for (m = m0; m != NULL && error == 0; m = m->m_next) {
111246713Skib		if (m->m_len > 0) {
112246713Skib			error = _bus_dmamap_load_buffer(dmat, map, m->m_data,
113246713Skib			    m->m_len, kernel_pmap, flags | BUS_DMA_LOAD_MBUF,
114246713Skib			    segs, nsegs);
115246713Skib		}
116246713Skib	}
117246713Skib	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
118246713Skib	    __func__, dmat, flags, error, *nsegs);
119246713Skib	return (error);
120246713Skib}
121246713Skib
122246713Skib/*
123246713Skib * Load from block io.
124246713Skib */
125246713Skibstatic int
126246713Skib_bus_dmamap_load_bio(bus_dma_tag_t dmat, bus_dmamap_t map, struct bio *bio,
127246713Skib    int *nsegs, int flags)
128246713Skib{
129248508Skib	vm_paddr_t paddr;
130248508Skib	bus_size_t len, tlen;
131248508Skib	int error, i, ma_offs;
132246713Skib
133248508Skib	if ((bio->bio_flags & BIO_UNMAPPED) == 0) {
134248508Skib		error = _bus_dmamap_load_buffer(dmat, map, bio->bio_data,
135248508Skib		    bio->bio_bcount, kernel_pmap, flags, NULL, nsegs);
136248508Skib		return (error);
137248508Skib	}
138246713Skib
139248508Skib	error = 0;
140248508Skib	tlen = bio->bio_bcount;
141248508Skib	ma_offs = bio->bio_ma_offset;
142248508Skib	for (i = 0; tlen > 0; i++, tlen -= len) {
143248508Skib		len = min(PAGE_SIZE - ma_offs, tlen);
144248508Skib		paddr = VM_PAGE_TO_PHYS(bio->bio_ma[i]) + ma_offs;
145248508Skib		error = _bus_dmamap_load_phys(dmat, map, paddr, len,
146248508Skib		    flags, NULL, nsegs);
147248508Skib		if (error != 0)
148248508Skib			break;
149248508Skib		ma_offs = 0;
150248508Skib	}
151246713Skib	return (error);
152246713Skib}
153246713Skib
154246713Skib/*
155246713Skib * Load a cam control block.
156246713Skib */
157246713Skibstatic int
158246713Skib_bus_dmamap_load_ccb(bus_dma_tag_t dmat, bus_dmamap_t map, union ccb *ccb,
159246713Skib		    int *nsegs, int flags)
160246713Skib{
161246713Skib	struct ccb_hdr *ccb_h;
162246713Skib	void *data_ptr;
163246713Skib	int error;
164246713Skib	uint32_t dxfer_len;
165246713Skib	uint16_t sglist_cnt;
166246713Skib
167246713Skib	error = 0;
168246713Skib	ccb_h = &ccb->ccb_h;
169246713Skib	switch (ccb_h->func_code) {
170249025Sken	case XPT_SCSI_IO: {
171249025Sken		struct ccb_scsiio *csio;
172249025Sken
173246713Skib		csio = &ccb->csio;
174246713Skib		data_ptr = csio->data_ptr;
175246713Skib		dxfer_len = csio->dxfer_len;
176246713Skib		sglist_cnt = csio->sglist_cnt;
177246713Skib		break;
178249025Sken	}
179249025Sken	case XPT_CONT_TARGET_IO: {
180249025Sken		struct ccb_scsiio *ctio;
181249025Sken
182249025Sken		ctio = &ccb->ctio;
183249025Sken		data_ptr = ctio->data_ptr;
184249025Sken		dxfer_len = ctio->dxfer_len;
185249025Sken		sglist_cnt = ctio->sglist_cnt;
186249025Sken		break;
187249025Sken	}
188249025Sken	case XPT_ATA_IO: {
189249025Sken		struct ccb_ataio *ataio;
190249025Sken
191246713Skib		ataio = &ccb->ataio;
192246713Skib		data_ptr = ataio->data_ptr;
193246713Skib		dxfer_len = ataio->dxfer_len;
194246713Skib		sglist_cnt = 0;
195246713Skib		break;
196249025Sken	}
197246713Skib	default:
198246713Skib		panic("_bus_dmamap_load_ccb: Unsupported func code %d",
199246713Skib		    ccb_h->func_code);
200246713Skib	}
201246713Skib
202246713Skib	switch ((ccb_h->flags & CAM_DATA_MASK)) {
203246713Skib	case CAM_DATA_VADDR:
204246713Skib		error = _bus_dmamap_load_buffer(dmat, map, data_ptr, dxfer_len,
205246713Skib		    kernel_pmap, flags, NULL, nsegs);
206246713Skib		break;
207246713Skib	case CAM_DATA_PADDR:
208246713Skib		error = _bus_dmamap_load_phys(dmat, map,
209246713Skib		    (vm_paddr_t)(uintptr_t)data_ptr, dxfer_len, flags, NULL,
210246713Skib		    nsegs);
211246713Skib		break;
212246713Skib	case CAM_DATA_SG:
213246713Skib		error = _bus_dmamap_load_vlist(dmat, map,
214246713Skib		    (bus_dma_segment_t *)data_ptr, sglist_cnt, kernel_pmap,
215246713Skib		    nsegs, flags);
216246713Skib		break;
217246713Skib	case CAM_DATA_SG_PADDR:
218246713Skib		error = _bus_dmamap_load_plist(dmat, map,
219246713Skib		    (bus_dma_segment_t *)data_ptr, sglist_cnt, nsegs, flags);
220246713Skib		break;
221246713Skib	case CAM_DATA_BIO:
222246713Skib		error = _bus_dmamap_load_bio(dmat, map, (struct bio *)data_ptr,
223246713Skib		    nsegs, flags);
224246713Skib		break;
225246713Skib	default:
226246713Skib		panic("_bus_dmamap_load_ccb: flags 0x%X unimplemented",
227246713Skib		    ccb_h->flags);
228246713Skib	}
229246713Skib	return (error);
230246713Skib}
231246713Skib
232246713Skib/*
233246713Skib * Load a uio.
234246713Skib */
235246713Skibstatic int
236246713Skib_bus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
237246713Skib    int *nsegs, int flags)
238246713Skib{
239246713Skib	bus_size_t resid;
240246713Skib	bus_size_t minlen;
241246713Skib	struct iovec *iov;
242246713Skib	pmap_t pmap;
243246713Skib	caddr_t addr;
244246713Skib	int error, i;
245246713Skib
246246713Skib	if (uio->uio_segflg == UIO_USERSPACE) {
247246713Skib		KASSERT(uio->uio_td != NULL,
248246713Skib			("bus_dmamap_load_uio: USERSPACE but no proc"));
249246713Skib		pmap = vmspace_pmap(uio->uio_td->td_proc->p_vmspace);
250246713Skib	} else
251246713Skib		pmap = kernel_pmap;
252246713Skib	resid = uio->uio_resid;
253246713Skib	iov = uio->uio_iov;
254246713Skib	error = 0;
255246713Skib
256246713Skib	for (i = 0; i < uio->uio_iovcnt && resid != 0 && !error; i++) {
257246713Skib		/*
258246713Skib		 * Now at the first iovec to load.  Load each iovec
259246713Skib		 * until we have exhausted the residual count.
260246713Skib		 */
261246713Skib
262246713Skib		addr = (caddr_t) iov[i].iov_base;
263246713Skib		minlen = resid < iov[i].iov_len ? resid : iov[i].iov_len;
264246713Skib		if (minlen > 0) {
265246713Skib			error = _bus_dmamap_load_buffer(dmat, map, addr,
266246713Skib			    minlen, pmap, flags, NULL, nsegs);
267246713Skib			resid -= minlen;
268246713Skib		}
269246713Skib	}
270246713Skib
271246713Skib	return (error);
272246713Skib}
273246713Skib
274246713Skib/*
275246713Skib * Map the buffer buf into bus space using the dmamap map.
276246713Skib */
277246713Skibint
278246713Skibbus_dmamap_load(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf,
279246713Skib    bus_size_t buflen, bus_dmamap_callback_t *callback,
280246713Skib    void *callback_arg, int flags)
281246713Skib{
282246713Skib	bus_dma_segment_t *segs;
283246713Skib	struct memdesc mem;
284246713Skib	int error;
285246713Skib	int nsegs;
286246713Skib
287246713Skib	if ((flags & BUS_DMA_NOWAIT) == 0) {
288246713Skib		mem = memdesc_vaddr(buf, buflen);
289246713Skib		_bus_dmamap_waitok(dmat, map, &mem, callback, callback_arg);
290246713Skib	}
291246713Skib
292246713Skib	nsegs = -1;
293246713Skib	error = _bus_dmamap_load_buffer(dmat, map, buf, buflen, kernel_pmap,
294246713Skib	    flags, NULL, &nsegs);
295246713Skib	nsegs++;
296246713Skib
297246713Skib	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
298248892Sjimharris	    __func__, dmat, flags, error, nsegs);
299246713Skib
300246713Skib	if (error == EINPROGRESS)
301246713Skib		return (error);
302246713Skib
303246713Skib	segs = _bus_dmamap_complete(dmat, map, NULL, nsegs, error);
304246713Skib	if (error)
305246713Skib		(*callback)(callback_arg, segs, 0, error);
306246713Skib	else
307246713Skib		(*callback)(callback_arg, segs, nsegs, 0);
308246713Skib
309246713Skib	/*
310246713Skib	 * Return ENOMEM to the caller so that it can pass it up the stack.
311248804Sjimharris	 * This error only happens when NOWAIT is set, so deferral is disabled.
312246713Skib	 */
313246713Skib	if (error == ENOMEM)
314246713Skib		return (error);
315246713Skib
316246713Skib	return (0);
317246713Skib}
318246713Skib
319246713Skibint
320246713Skibbus_dmamap_load_mbuf(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
321246713Skib    bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
322246713Skib{
323246713Skib	bus_dma_segment_t *segs;
324246713Skib	int nsegs, error;
325246713Skib
326246713Skib	flags |= BUS_DMA_NOWAIT;
327246713Skib	nsegs = -1;
328246713Skib	error = _bus_dmamap_load_mbuf_sg(dmat, map, m0, NULL, &nsegs, flags);
329246713Skib	++nsegs;
330246713Skib
331246713Skib	segs = _bus_dmamap_complete(dmat, map, NULL, nsegs, error);
332246713Skib	if (error)
333246713Skib		(*callback)(callback_arg, segs, 0, 0, error);
334246713Skib	else
335246713Skib		(*callback)(callback_arg, segs, nsegs, m0->m_pkthdr.len, error);
336246713Skib
337246713Skib	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
338246713Skib	    __func__, dmat, flags, error, nsegs);
339246713Skib	return (error);
340246713Skib}
341246713Skib
342246713Skibint
343246713Skibbus_dmamap_load_mbuf_sg(bus_dma_tag_t dmat, bus_dmamap_t map, struct mbuf *m0,
344246713Skib    bus_dma_segment_t *segs, int *nsegs, int flags)
345246713Skib{
346246713Skib	int error;
347246713Skib
348246713Skib	flags |= BUS_DMA_NOWAIT;
349246713Skib	*nsegs = -1;
350246713Skib	error = _bus_dmamap_load_mbuf_sg(dmat, map, m0, segs, nsegs, flags);
351246713Skib	++*nsegs;
352246713Skib	_bus_dmamap_complete(dmat, map, segs, *nsegs, error);
353246713Skib	return (error);
354246713Skib}
355246713Skib
356246713Skibint
357246713Skibbus_dmamap_load_uio(bus_dma_tag_t dmat, bus_dmamap_t map, struct uio *uio,
358246713Skib    bus_dmamap_callback2_t *callback, void *callback_arg, int flags)
359246713Skib{
360246713Skib	bus_dma_segment_t *segs;
361246713Skib	int nsegs, error;
362246713Skib
363246713Skib	flags |= BUS_DMA_NOWAIT;
364246713Skib	nsegs = -1;
365246713Skib	error = _bus_dmamap_load_uio(dmat, map, uio, &nsegs, flags);
366246713Skib	nsegs++;
367246713Skib
368246713Skib	segs = _bus_dmamap_complete(dmat, map, NULL, nsegs, error);
369246713Skib	if (error)
370246713Skib		(*callback)(callback_arg, segs, 0, 0, error);
371246713Skib	else
372246713Skib		(*callback)(callback_arg, segs, nsegs, uio->uio_resid, error);
373246713Skib
374246713Skib	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
375248892Sjimharris	    __func__, dmat, flags, error, nsegs);
376246713Skib	return (error);
377246713Skib}
378246713Skib
379246713Skibint
380246713Skibbus_dmamap_load_ccb(bus_dma_tag_t dmat, bus_dmamap_t map, union ccb *ccb,
381246713Skib		    bus_dmamap_callback_t *callback, void *callback_arg,
382246713Skib		    int flags)
383246713Skib{
384246713Skib	bus_dma_segment_t *segs;
385246713Skib	struct ccb_hdr *ccb_h;
386246713Skib	struct memdesc mem;
387246713Skib	int error;
388246713Skib	int nsegs;
389246713Skib
390246713Skib	ccb_h = &ccb->ccb_h;
391246713Skib	if ((ccb_h->flags & CAM_DIR_MASK) == CAM_DIR_NONE) {
392246713Skib		callback(callback_arg, NULL, 0, 0);
393246713Skib		return (0);
394246713Skib	}
395246713Skib	if ((flags & BUS_DMA_NOWAIT) == 0) {
396246713Skib		mem = memdesc_ccb(ccb);
397246713Skib		_bus_dmamap_waitok(dmat, map, &mem, callback, callback_arg);
398246713Skib	}
399246713Skib	nsegs = -1;
400246713Skib	error = _bus_dmamap_load_ccb(dmat, map, ccb, &nsegs, flags);
401246713Skib	nsegs++;
402248893Sjimharris
403248893Sjimharris	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
404248893Sjimharris	    __func__, dmat, flags, error, nsegs);
405248893Sjimharris
406246713Skib	if (error == EINPROGRESS)
407246713Skib		return (error);
408246713Skib
409246713Skib	segs = _bus_dmamap_complete(dmat, map, NULL, nsegs, error);
410246713Skib	if (error)
411246713Skib		(*callback)(callback_arg, segs, 0, error);
412246713Skib	else
413246713Skib		(*callback)(callback_arg, segs, nsegs, error);
414246713Skib	/*
415246713Skib	 * Return ENOMEM to the caller so that it can pass it up the stack.
416248804Sjimharris	 * This error only happens when NOWAIT is set, so deferral is disabled.
417246713Skib	 */
418246713Skib	if (error == ENOMEM)
419246713Skib		return (error);
420246713Skib
421246713Skib	return (0);
422246713Skib}
423246713Skib
424246713Skibint
425248896Sjimharrisbus_dmamap_load_bio(bus_dma_tag_t dmat, bus_dmamap_t map, struct bio *bio,
426248896Sjimharris		    bus_dmamap_callback_t *callback, void *callback_arg,
427248896Sjimharris		    int flags)
428248896Sjimharris{
429248896Sjimharris	bus_dma_segment_t *segs;
430248896Sjimharris	struct memdesc mem;
431248896Sjimharris	int error;
432248896Sjimharris	int nsegs;
433248896Sjimharris
434248896Sjimharris	if ((flags & BUS_DMA_NOWAIT) == 0) {
435248896Sjimharris		mem = memdesc_bio(bio);
436248896Sjimharris		_bus_dmamap_waitok(dmat, map, &mem, callback, callback_arg);
437248896Sjimharris	}
438248896Sjimharris	nsegs = -1;
439248896Sjimharris	error = _bus_dmamap_load_bio(dmat, map, bio, &nsegs, flags);
440248896Sjimharris	nsegs++;
441248896Sjimharris
442248896Sjimharris	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
443248896Sjimharris	    __func__, dmat, flags, error, nsegs);
444248896Sjimharris
445248896Sjimharris	if (error == EINPROGRESS)
446248896Sjimharris		return (error);
447248896Sjimharris
448248896Sjimharris	segs = _bus_dmamap_complete(dmat, map, NULL, nsegs, error);
449248896Sjimharris	if (error)
450248896Sjimharris		(*callback)(callback_arg, segs, 0, error);
451248896Sjimharris	else
452248896Sjimharris		(*callback)(callback_arg, segs, nsegs, error);
453248896Sjimharris	/*
454248896Sjimharris	 * Return ENOMEM to the caller so that it can pass it up the stack.
455248896Sjimharris	 * This error only happens when NOWAIT is set, so deferral is disabled.
456248896Sjimharris	 */
457248896Sjimharris	if (error == ENOMEM)
458248896Sjimharris		return (error);
459248896Sjimharris
460248896Sjimharris	return (0);
461248896Sjimharris}
462248896Sjimharris
463248896Sjimharrisint
464246713Skibbus_dmamap_load_mem(bus_dma_tag_t dmat, bus_dmamap_t map,
465246713Skib    struct memdesc *mem, bus_dmamap_callback_t *callback,
466246713Skib    void *callback_arg, int flags)
467246713Skib{
468246713Skib	bus_dma_segment_t *segs;
469246713Skib	int error;
470246713Skib	int nsegs;
471246713Skib
472246713Skib	if ((flags & BUS_DMA_NOWAIT) == 0)
473246713Skib		_bus_dmamap_waitok(dmat, map, mem, callback, callback_arg);
474246713Skib
475246713Skib	nsegs = -1;
476246713Skib	error = 0;
477246713Skib	switch (mem->md_type) {
478246713Skib	case MEMDESC_VADDR:
479246713Skib		error = _bus_dmamap_load_buffer(dmat, map, mem->u.md_vaddr,
480246713Skib		    mem->md_opaque, kernel_pmap, flags, NULL, &nsegs);
481246713Skib		break;
482246713Skib	case MEMDESC_PADDR:
483246713Skib		error = _bus_dmamap_load_phys(dmat, map, mem->u.md_paddr,
484246713Skib		    mem->md_opaque, flags, NULL, &nsegs);
485246713Skib		break;
486246713Skib	case MEMDESC_VLIST:
487246713Skib		error = _bus_dmamap_load_vlist(dmat, map, mem->u.md_list,
488246713Skib		    mem->md_opaque, kernel_pmap, &nsegs, flags);
489246713Skib		break;
490246713Skib	case MEMDESC_PLIST:
491246713Skib		error = _bus_dmamap_load_plist(dmat, map, mem->u.md_list,
492246713Skib		    mem->md_opaque, &nsegs, flags);
493246713Skib		break;
494246713Skib	case MEMDESC_BIO:
495246713Skib		error = _bus_dmamap_load_bio(dmat, map, mem->u.md_bio,
496246713Skib		    &nsegs, flags);
497246713Skib		break;
498246713Skib	case MEMDESC_UIO:
499246713Skib		error = _bus_dmamap_load_uio(dmat, map, mem->u.md_uio,
500246713Skib		    &nsegs, flags);
501246713Skib		break;
502246713Skib	case MEMDESC_MBUF:
503246713Skib		error = _bus_dmamap_load_mbuf_sg(dmat, map, mem->u.md_mbuf,
504246713Skib		    NULL, &nsegs, flags);
505246713Skib		break;
506246713Skib	case MEMDESC_CCB:
507246713Skib		error = _bus_dmamap_load_ccb(dmat, map, mem->u.md_ccb, &nsegs,
508246713Skib		    flags);
509246713Skib		break;
510246713Skib	}
511246713Skib	nsegs++;
512246713Skib
513246713Skib	CTR5(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d nsegs %d",
514248892Sjimharris	    __func__, dmat, flags, error, nsegs);
515246713Skib
516246713Skib	if (error == EINPROGRESS)
517246713Skib		return (error);
518246713Skib
519246713Skib	segs = _bus_dmamap_complete(dmat, map, NULL, nsegs, error);
520246713Skib	if (error)
521246713Skib		(*callback)(callback_arg, segs, 0, error);
522246713Skib	else
523246713Skib		(*callback)(callback_arg, segs, nsegs, 0);
524246713Skib
525246713Skib	/*
526246713Skib	 * Return ENOMEM to the caller so that it can pass it up the stack.
527248804Sjimharris	 * This error only happens when NOWAIT is set, so deferral is disabled.
528246713Skib	 */
529246713Skib	if (error == ENOMEM)
530246713Skib		return (error);
531246713Skib
532246713Skib	return (0);
533246713Skib}
534