changeset 19431:5599be23ae32

12183 Want new IPD 13 DMA Cookie APIs Reviewed by: Alex Wilson <alex@uq.edu.au> Reviewed by: Paul Winder <paul@winders.demon.co.uk> Reviewed by: Hans Rosenfeld <rosenfeld@grumpf.hope-2000.org> Reviewed by: Garrett D'Amore <garrett@damore.org> Approved by: Garrett D'Amore <garrett@damore.org>
author Robert Mustacchi <rm@fingolfin.org>
date Wed, 18 Dec 2019 06:18:35 +0000
parents 6e69910f8ded
children 4dba224dcf8d
files usr/src/man/man9f/Intro.9f usr/src/man/man9f/Makefile usr/src/man/man9f/ddi_dma_addr_bind_handle.9f usr/src/man/man9f/ddi_dma_buf_bind_handle.9f usr/src/man/man9f/ddi_dma_cookie_iter.9f usr/src/man/man9f/ddi_dma_getwin.9f usr/src/man/man9f/ddi_dma_nextcookie.9f usr/src/man/man9f/ddi_dmae.9f usr/src/pkg/manifests/system-kernel.man9f.inc usr/src/uts/common/io/scsi/impl/scsi_resource.c usr/src/uts/common/os/sunddi.c usr/src/uts/common/sys/ddi_impldefs.h usr/src/uts/common/sys/sunddi.h usr/src/uts/i86pc/io/rootnex.c usr/src/uts/sun4/io/px/px.c usr/src/uts/sun4/io/px/px_dma.c usr/src/uts/sun4u/io/pci/pci.c usr/src/uts/sun4u/io/pci/pci_dma.c usr/src/uts/sun4v/io/niumx/niumx.c
diffstat 19 files changed, 526 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/man/man9f/Intro.9f	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/man/man9f/Intro.9f	Wed Dec 18 06:18:35 2019 +0000
@@ -356,10 +356,14 @@
 \fBddi_dma_alloc_handle\fR	illumos DDI
 \fBddi_dma_buf_bind_handle\fR	illumos DDI
 \fBddi_dma_burstsizes\fR	illumos DDI
+\fBddi_dma_cookie_get\fR	illumos DDI
+\fBddi_dma_cookie_next\fR	illumos DDI
+\fBddi_dma_cookie_one\fR	illumos DDI
 \fBddi_dma_free_handle\fR	illumos DDI
 \fBddi_dma_getwin\fR	illumos DDI
 \fBddi_dma_mem_alloc\fR	illumos DDI
 \fBddi_dma_mem_free\fR	illumos DDI
+\fBddi_dma_ncookies\fR	illumos DDI
 \fBddi_dma_nextcookie\fR	illumos DDI
 \fBddi_dma_numwin\fR	illumos DDI
 \fBddi_dma_set_sbus64\fR	illumos DDI
--- a/usr/src/man/man9f/Makefile	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/man/man9f/Makefile	Wed Dec 18 06:18:35 2019 +0000
@@ -154,11 +154,11 @@
 		ddi_dma_alloc_handle.9f			\
 		ddi_dma_buf_bind_handle.9f		\
 		ddi_dma_burstsizes.9f			\
+		ddi_dma_cookie_iter.9f			\
 		ddi_dma_free_handle.9f			\
 		ddi_dma_getwin.9f			\
 		ddi_dma_mem_alloc.9f			\
 		ddi_dma_mem_free.9f			\
-		ddi_dma_nextcookie.9f			\
 		ddi_dma_numwin.9f			\
 		ddi_dma_set_sbus64.9f			\
 		ddi_dma_sync.9f				\
@@ -748,6 +748,10 @@
 		ddi_devid_unregister.9f				\
 		ddi_devid_valid.9f				\
 		ddi_devmap_segmap.9f				\
+		ddi_dma_cookie_get.9f				\
+		ddi_dma_cookie_one.9f				\
+		ddi_dma_ncookies.9f				\
+		ddi_dma_nextcookie.9f				\
 		ddi_dmae_1stparty.9f				\
 		ddi_dmae_alloc.9f				\
 		ddi_dmae_disable.9f				\
@@ -1557,6 +1561,11 @@
 ddi_devid_unregister.9f			:= LINKSRC = ddi_devid_compare.9f
 ddi_devid_valid.9f			:= LINKSRC = ddi_devid_compare.9f
 
+ddi_dma_cookie_get.9f			:= LINKSRC = ddi_dma_cookie_iter.9f
+ddi_dma_cookie_one.9f			:= LINKSRC = ddi_dma_cookie_iter.9f
+ddi_dma_ncookies.9f			:= LINKSRC = ddi_dma_cookie_iter.9f
+ddi_dma_nextcookie.9f			:= LINKSRC = ddi_dma_cookie_iter.9f
+
 ddi_dmae_1stparty.9f			:= LINKSRC = ddi_dmae.9f
 ddi_dmae_alloc.9f			:= LINKSRC = ddi_dmae.9f
 ddi_dmae_disable.9f			:= LINKSRC = ddi_dmae.9f
--- a/usr/src/man/man9f/ddi_dma_addr_bind_handle.9f	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/man/man9f/ddi_dma_addr_bind_handle.9f	Wed Dec 18 06:18:35 2019 +0000
@@ -3,7 +3,7 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DDI_DMA_ADDR_BIND_HANDLE 9F "Jul 26, 1996"
+.TH DDI_DMA_ADDR_BIND_HANDLE 9F "Jan 18, 2020"
 .SH NAME
 ddi_dma_addr_bind_handle \- binds an address to a DMA handle
 .SH SYNOPSIS
@@ -20,11 +20,9 @@
 .fi
 
 .SH INTERFACE LEVEL
-.sp
 .LP
 Solaris DDI specific (Solaris DDI).
 .SH PARAMETERS
-.sp
 .ne 2
 .na
 \fB\fIhandle\fR \fR
@@ -178,7 +176,8 @@
 \fB\fIcookiep\fR \fR
 .ad
 .RS 13n
-A pointer to the first  \fBddi_dma_cookie\fR(9S) structure.
+A pointer to the first \fBddi_dma_cookie\fR(9S) structure.  This should
+be left as \fBNULL\fR in new callers.
 .RE
 
 .sp
@@ -188,11 +187,12 @@
 .ad
 .RS 13n
 Upon a successful return,  \fIccountp\fR points to a value representing the
-number of cookies for this \fBDMA\fR object.
+number of cookies for this \fBDMA\fR object.  This can
+be left as \fBNULL\fR in new callers.  The cookie count can be obtained
+by calling \fBddi_dma_ncookies\fR(9F).
 .RE
 
 .SH DESCRIPTION
-.sp
 .LP
 \fBddi_dma_addr_bind_handle()\fR allocates \fBDMA\fR resources for a memory
 object  such that a device can perform \fBDMA\fR to or from the object.
@@ -200,12 +200,15 @@
 as expressed by \fBddi_dma_attr\fR(9S) (see \fBddi_dma_alloc_handle\fR(9F)).
 .sp
 .LP
-\fBddi_dma_addr_bind_handle()\fR fills in the first \fBDMA\fR cookie pointed to
-by \fIcookiep\fR with the appropriate address, length, and bus type.
-\fB*\fR\fIccountp\fR is set to the number of \fBDMA\fR cookies representing
-this \fBDMA\fR object. Subsequent \fBDMA\fR cookies must be retrieved by
-calling \fBddi_dma_nextcookie\fR(9F) the number of times specified by
-\fB*\fR\fIcountp\fR-1.
+\fBddi_dma_addr_bind_handle()\fR allocates and associates a number of
+\fBDMA\fR cookies with \fIhandle\fR.  To get the total number of
+cookies, callers should use the \fBddi_dma_ncookies\fR(9F) function. To
+get all of the cookies, callers should use the
+\fBddi_dma_cookie_iter\fR(9F) or \fBddi_dma_cookie_get\fR(9F) functions.
+Callers should pass \fBNULL\fR for \fIcookiep\fR and \fIccountp\fR.
+These values are required if using the deprecated
+\fBddi_dma_nextcookie\fR(9F) interface, in which case \fIcookiep\fR is
+filled in with the first \fBddi_dma_cookie\fR(9S) structure.
 .sp
 .LP
 When a \fBDMA\fR transfer completes, the driver frees up system \fBDMA\fR
@@ -307,7 +310,6 @@
 function must take whatever steps are necessary to protect its critical
 resources, data structures, queues, and so on.
 .SH RETURN VALUES
-.sp
 .LP
 \fBddi_dma_addr_bind_handle()\fR returns:
 .sp
@@ -369,24 +371,22 @@
 .RE
 
 .SH CONTEXT
-.sp
 .LP
 \fBddi_dma_addr_bind_handle()\fR can be called from user, kernel, or interrupt
 context, except when \fIcallback\fR is set to  \fBDDI_DMA_SLEEP\fR, in which
 case it can only be called from user or kernel context.
 .SH SEE ALSO
-.sp
 .LP
-\fBddi_dma_alloc_handle\fR(9F), \fBddi_dma_free_handle\fR(9F),
+\fBddi_dma_alloc_handle\fR(9F), \fBddi_dma_cookie_get\fR(9F),
+\fBddi_dma_cookie_iter\fR(9F), \fBddi_dma_free_handle\fR(9F),
 \fBddi_dma_getwin\fR(9F), \fBddi_dma_mem_alloc\fR(9F),
-\fBddi_dma_mem_free\fR(9F), \fBddi_dma_nextcookie\fR(9F),
+\fBddi_dma_mem_free\fR(9F), \fBddi_dma_ncookies\fR(9F),
 \fBddi_dma_sync\fR(9F), \fBddi_dma_unbind_handle\fR(9F),
 \fBddi_umem_iosetup\fR(9F), \fBddi_dma_attr\fR(9S), \fBddi_dma_cookie\fR(9S)
 .sp
 .LP
 \fIWriting Device Drivers\fR
 .SH NOTES
-.sp
 .LP
 If the driver permits partial mapping with the  \fBDDI_DMA_PARTIAL\fR flag, the
 number of cookies in each window may exceed the size of the device's
--- a/usr/src/man/man9f/ddi_dma_buf_bind_handle.9f	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/man/man9f/ddi_dma_buf_bind_handle.9f	Wed Dec 18 06:18:35 2019 +0000
@@ -3,7 +3,7 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DDI_DMA_BUF_BIND_HANDLE 9F "Jul 27, 1996"
+.TH DDI_DMA_BUF_BIND_HANDLE 9F "Jan 18, 2020"
 .SH NAME
 ddi_dma_buf_bind_handle \- binds a system buffer to a DMA handle
 .SH SYNOPSIS
@@ -20,11 +20,9 @@
 .fi
 
 .SH INTERFACE LEVEL
-.sp
 .LP
 Solaris DDI specific (Solaris DDI).
 .SH PARAMETERS
-.sp
 .ne 2
 .na
 \fB\fIhandle\fR\fR
@@ -159,7 +157,8 @@
 \fB\fIcookiep\fR\fR
 .ad
 .RS 12n
-A pointer to the first \fBddi_dma_cookie\fR(9S) structure.
+A pointer to the first  \fBddi_dma_cookie\fR(9S) structure.  This should
+be left as \fBNULL\fR in new callers.
 .RE
 
 .sp
@@ -169,11 +168,12 @@
 .ad
 .RS 12n
 Upon a successful return, \fIccountp\fR points to a value representing the
-number of cookies for this \fBDMA\fR object.
+number of cookies for this \fBDMA\fR object.  This can
+be left as \fBNULL\fR in new callers.  The cookie count can be obtained
+by calling \fBddi_dma_ncookies\fR(9F).
 .RE
 
 .SH DESCRIPTION
-.sp
 .LP
 \fBddi_dma_buf_bind_handle()\fR allocates \fBDMA\fR resources for a system
 buffer such that a device can perform \fBDMA\fR to or from the buffer.
@@ -181,11 +181,16 @@
 as expressed by \fBddi_dma_attr\fR(9S) (see \fBddi_dma_alloc_handle\fR(9F)).
 .sp
 .LP
-\fBddi_dma_buf_bind_handle()\fR fills in the first \fBDMA\fR cookie pointed to
-by \fIcookiep\fR with the appropriate address, length, and bus type.
-\fB*\fR\fIccountp\fR is set to the number of \fBDMA\fR cookies representing
-this \fBDMA\fR object. Subsequent \fBDMA\fR cookies must be retrieved by
-calling \fBddi_dma_nextcookie\fR(9F) \fB*\fR\fIcountp\fR-1 times.
+\fBddi_dma_buf_bind_handle()\fR allocates and associates a number of
+\fBDMA\fR cookies with \fIhandle\fR.  To get the total number of
+cookies, callers should use the \fBddi_dma_ncookies\fR(9F) function. To
+get all of the cookies, callers should use the
+\fBddi_dma_cookie_iter\fR(9F) or \fBddi_dma_cookie_get\fR(9F) functions.
+Callers should pass \fBNULL\fR for \fIcookiep\fR and \fIccountp\fR.
+These values are required if using the deprecated
+\fBddi_dma_nextcookie\fR(9F) interface, in which case \fIcookiep\fR is
+filled in with the first \fBddi_dma_cookie\fR(9S) structure.
+
 .sp
 .LP
 When a \fBDMA\fR transfer completes, the driver should free up system \fBDMA\fR
@@ -287,7 +292,6 @@
 function must take whatever steps necessary to protect its critical resources,
 data structures, queues, etc.
 .SH RETURN VALUES
-.sp
 .LP
 \fBddi_dma_buf_bind_handle()\fR returns:
 .sp
@@ -349,24 +353,22 @@
 .RE
 
 .SH CONTEXT
-.sp
 .LP
 \fBddi_dma_buf_bind_handle()\fR can be called from user, kernel, or interrupt
 context, except when \fIcallback\fR is set to \fBDDI_DMA_SLEEP\fR, in which
 case it can be called from user or kernel context only.
 .SH SEE ALSO
-.sp
 .LP
 \fBddi_dma_addr_bind_handle\fR(9F), \fBddi_dma_alloc_handle\fR(9F),
+\fBddi_dma_cookie_get\fR(9F), \fBddi_dma_cookie_iter\fR(9F),
 \fBddi_dma_free_handle\fR(9F), \fBddi_dma_getwin\fR(9F),
-\fBddi_dma_nextcookie\fR(9F), \fBddi_dma_sync\fR(9F),
+\fBddi_dma_ncookies\fR(9F), \fBddi_dma_sync\fR(9F),
 \fBddi_dma_unbind_handle\fR(9F), \fBbuf\fR(9S), \fBddi_dma_attr\fR(9S),
 \fBddi_dma_cookie\fR(9S)
 .sp
 .LP
 \fIWriting Device Drivers\fR
 .SH NOTES
-.sp
 .LP
 If the driver permits partial mapping with the \fBDDI_DMA_PARTIAL\fR flag, the
 number of cookies in each window may exceed the size of the device's
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/man/man9f/ddi_dma_cookie_iter.9f	Wed Dec 18 06:18:35 2019 +0000
@@ -0,0 +1,282 @@
+.\"
+.\" This file and its contents are supplied under the terms of the
+.\" Common Development and Distribution License ("CDDL"), version 1.0.
+.\" You may only use this file in accordance with the terms of version
+.\" 1.0 of the CDDL.
+.\"
+.\" A full copy of the text of the CDDL should have accompanied this
+.\" source.  A copy of the CDDL is also available via the Internet at
+.\" http://www.illumos.org/license/CDDL.
+.\"
+.\"
+.\" Copyright 2019 Robert Mustacchi
+.\"
+.Dd December 9, 2019
+.Dt DDI_DMA_COOKIE_ITER 9F
+.Os
+.Sh NAME
+.Nm ddi_dma_cookie_get ,
+.Nm ddi_dma_cookie_iter ,
+.Nm ddi_dma_cookie_one ,
+.Nm ddi_dma_ncookies ,
+.Nm ddi_dma_nextcookie
+.Nd retrieve DMA cookies
+.Sh SYNOPSIS
+.In sys/ddi.h
+.In sys/sunddi.h
+.Ft "const ddi_dma_cookie_t *"
+.Fo ddi_dma_cookie_iter
+.Fa "ddi_dma_handle_t handle"
+.Fa "const ddi_dma_cookie_t *cookiep"
+.Fc
+.Ft "const ddi_dma_cookie_t *"
+.Fo ddi_dma_cookie_get
+.Fa "ddi_dma_handle_t handle"
+.Fa "uint_t index"
+.Fc
+.Ft "const ddi_dma_cookie_t *"
+.Fo ddi_dma_cookie_one
+.Fa "ddi_dma_handle_t handle"
+.Fc
+.Ft "uint_t"
+.Fo ddi_dma_ncookies
+.Fa "ddi_dma_handle_t handle"
+.Fc
+.Ft void
+.Fo ddi_dma_nextcookie
+.Fa "ddi_dma_handle_t handle"
+.Fa "ddi_dma_cookie_t *cookiep"
+.Fc
+.Sh PARAMETERS
+.Bl -tag -width Fa
+.It Fa handle
+The DMA handle obtained by a call to
+.Xr ddi_dma_alloc_handle 9F .
+.It Fa cookie
+A pointer to a
+.Xr ddi_dma_cookie 9S
+structure.
+.It Fa index
+An unsigned integer that represents the index of a cookie to obtain.
+The first entry is at index zero.
+.El
+.Sh DESCRIPTION
+The
+.Fn ddi_dma_cookie_iter ,
+.Fn ddi_dma_cookie_get ,
+and
+.Fn ddi_dma_cookie_one
+functions obtain information about DMA cookies.
+When a DMA request, represented by the DMA handle
+.Fa handle ,
+has been bound to a series of addresses with the
+.Xr ddi_dma_addr_bind_handle 9F
+or
+.Xr ddi_dma_buf_bind_handle 9F
+functions, the resulting addresses are stored in one or more
+.Xr ddi_dma_cookie 9S
+structures.
+the three different functions provide different ways to obtain cookies
+and are safe alternatives to the unsafe
+.Fn ddi_dma_nextcookie
+function.
+To see how to use these functions, please see the
+.Sx EXAMPLES
+section.
+.Pp
+The
+.Fn ddi_dma_cookie_iter
+function provides a way to iterate over all the cookies that are
+associated with the DMA handle
+.Fa handle .
+To get the first handle, pass
+.Dv NULL
+in
+.Fa cookiep .
+Do not use the DMA cookie returned from either of the
+.Xr ddi_dma_addr_bind_handle 9F
+or
+.Xr ddi_dma_buf_bind_handle 9F
+functions.
+To get subsequent cookies, pass the returned cookie as the argument
+.Fa cookiep .
+When the function returns
+.Dv NULL
+then that indicates that the last handle has been iterated over.
+.Pp
+The
+.Fn ddi_dma_cookie_get
+function returns a specific cookie.
+The
+.Fa index
+indicates which of the cookies should be returned.
+The first cookie is at index
+.Sy 0 .
+If an invalid index is specified, the function returns
+.Dv NULL .
+.Pp
+The
+.Ft ddi_dma_cookie_one
+function is a convenience function for DMA requests that have a single
+cookie.
+This function always returns the single cookie assosciated with the DMA
+handle
+.Fa handle .
+If this function is used when there is a DMA request with multiple
+cookies, then it will panic the system.
+It can never return
+.Dv NULL .
+.Pp
+The
+.Fn ddi_dma_ncookies
+function returns the number of DMA cookies that are associated with the
+DMA handle
+.Fa handle .
+If there are no DMA resources bound to the handle, then this will return
+.Sy 0 .
+.Pp
+The
+.Fn ddi_dma_nextcookie
+function was the historical function that was associated with obtaining
+DMA cookies.
+It should not be used due to several flaws.
+The
+.Fn ddi_dma_nextcookie
+function mutates the underlying DMA handle meaning that a driver cannot
+obtain a cookie a second time and thus a device driver using this
+interface must either manually keep storage of the cookie around wasting
+space or rebind the handle, wasting time.
+In addition, there is no way for the function to indicate that a driver
+has consumed all of its cookies.
+If for some reason a device driver calls the
+.Fn ddi_dma_nextcookie
+function more times than there are cookies, the results are undefined.
+In short, this function should not be used for any purpose.
+Use the
+.Fn ddi_dma_cookie_iter ,
+.Fn ddi_dma_cookie_get ,
+or
+.Fn ddi_dma_cookie_one
+functions instead.
+.Sh CONTEXT
+The
+.Fn ddi_dma_cookie_iter ,
+.Fn ddi_dma_cookie_get ,
+.Fn ddi_dma_cookie_one ,
+.Fn ddi_dma_ncookies ,
+and
+.Fn ddi_dma_nextcookie
+functions may be called from
+.Sy user ,
+.Sy kernel ,
+or
+.Sy interrupt
+context.
+.Sh RETURN VALUES
+Upon successful completion, the
+.Fn ddi_dma_cookie_iter ,
+.Fn ddi_dma_cookie_get ,
+.Fn ddi_dma_cookie_one
+functions will return the requested DMA cookie.
+If there are no more cookies, or
+.Fa coookiep
+is invalid, the
+.Fn ddi_dma_cookie_iter
+function will return
+.Dv NULL .
+If
+.Fa index
+does not correspond to a valid cookie, the
+.Fn ddi_dma_cookie_get
+function will return
+.Dv NULL .
+If there is not exactly one DMA cookie, or another issue occurs, then the
+.Fn ddi_dma_cookie_one
+function will panic the system.
+.Pp
+Upon successful completion, the
+.Fn ddi_dma_ncookies
+function returns the number of cookies associated with
+.Fa handle .
+If there are none, then
+.Sy 0
+is returned.
+.Pp
+The
+.Fn ddi_dma_nextcookie
+function always updates
+.Fa cookiep
+regardless of whether it is valid or not.
+.Sh EXAMPLES
+.Sy Example 1
+Using the
+.Fn ddi_dma_cookie_iter
+function to obtain all DMA cookies.
+.Bd -literal
+/*
+ * This example assumes that either ddi_dma_addr_bind_handle() or
+ * ddi_dma_buf_bind_handle() has already been successfully called.
+ */
+void
+program_dma(ddi_dma_handle_t handle)
+{
+	const ddi_dma_cookie_t *c;
+
+	for (cookie = ddi_dma_cookie_iter(handle, NULL); c != NULL;
+	    c = ddi_dma_cookie_iter(handle, c)) {
+		/*
+		 * Use the dmac_laddress and dmac_size members to
+		 * properly program the device or descriptor rings.
+		 */
+	}
+}
+.Ed
+.Pp
+.Sy Example 2
+Using the
+.Fn ddi_dma_cookie_get
+function.
+.Bd -literal
+/*
+ * This example assumes that either ddi_dma_mem_alloc() has already
+ * been successfully called.
+ */
+int
+bind_dma(ddi_dma_handle_t handle, void *addr, size_t len)
+{
+	int ret;
+	uint_t i, ncookies;
+	ddi_dma_cookie_t first;
+
+	ret = ddi_dma_addr_bind_handle(handle, NULL, addr, len,
+	    DDI_DMA_RDWR | DDI_DMA_CONSISTENT, NULL, NULL, &first,
+	    &ncookies);
+	if (ret != DDI_DMA_MAPPED) {
+		return (ret);
+	}
+
+	/*
+	 * A driver doesn't need to store ncookies. It can get it again
+	 * by simply calling ddi_dma_ncookies() and using the result in
+	 * place of ncookies from ddi_dma_addr_bind_handle().
+	 */
+	for (i = 0; i < ncookies; i++) {
+		const ddi_dma_cookie_t *cookie;
+
+		cookie = ddi_dma_coookie_get(handle, i);
+		/*
+		 * Use the dmac_laddress and dmac_size members to
+		 * properly program the device or descriptor rings.
+		 */
+	}
+}
+.Ed
+.Sh SEE ALSO
+.Xr ddi_dma_addr_bind_handle 9F ,
+.Xr ddi_dma_alloc_handle 9F ,
+.Xr ddi_dma_buf_bind_handle 9F ,
+.Xr ddi_dma_unbind_handle 9F ,
+.Xr ddi_dma_cookie 9S
+.Rs
+.%T Writing Device Drivers
+.Re
--- a/usr/src/man/man9f/ddi_dma_getwin.9f	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/man/man9f/ddi_dma_getwin.9f	Wed Dec 18 06:18:35 2019 +0000
@@ -3,7 +3,7 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DDI_DMA_GETWIN 9F "Nov 15, 1996"
+.TH DDI_DMA_GETWIN 9F "Jan 18, 2020"
 .SH NAME
 ddi_dma_getwin \- activate a new DMA window
 .SH SYNOPSIS
@@ -20,11 +20,9 @@
 .fi
 
 .SH INTERFACE LEVEL
-.sp
 .LP
 Solaris DDI specific (Solaris DDI).
 .SH PARAMETERS
-.sp
 .ne 2
 .na
 \fB\fIhandle\fR \fR
@@ -69,7 +67,8 @@
 \fB\fIcookiep\fR \fR
 .ad
 .RS 12n
-A pointer to the first  \fBddi_dma_cookie\fR(9S) structure.
+A pointer to the first \fBddi_dma_cookie\fR(9S) structure.  This should
+be left as \fBNULL\fR in new callers.
 .RE
 
 .sp
@@ -79,11 +78,12 @@
 .ad
 .RS 12n
 Upon a successful return,  \fIccountp\fR will contain the number of cookies for
-this  \fBDMA\fR window.
+this  \fBDMA\fR window.  This can
+be left as \fBNULL\fR in new callers.  The cookie count can be obtained
+by calling \fBddi_dma_ncookies\fR(9F).
 .RE
 
 .SH DESCRIPTION
-.sp
 .LP
 \fBddi_dma_getwin()\fR activates a new  \fBDMA\fR window. If a  \fBDMA\fR
 resource allocation request returns \fBDDI_DMA_PARTIAL_MAP\fR indicating that
@@ -97,11 +97,15 @@
 makes it the current  \fBDMA\fR window.
 .sp
 .LP
-\fBddi_dma_getwin()\fR fills in the first \fBDMA\fR cookie pointed to by
-\fIcookiep\fR with the appropriate address, length, and bus type.
-\fB*\fR\fIccountp\fR is set to the number of \fBDMA\fR cookies representing
-this \fBDMA \fRobject. Subsequent \fBDMA\fR cookies must be retrieved using
-\fBddi_dma_nextcookie\fR(9F).
+\fBddi_dma_getwin()\fR allocates and assosciates a number of
+\fBDMA\fR cookies with \fIhandle\fR.  To get the total number of
+cookies, callers should use the \fBddi_dma_ncookies\fR(9F) function. To
+get all of the cookies, callers should use the
+\fBddi_dma_cookie_iter\fR(9F) or \fBddi_dma_cookie_get\fR(9F) functions.
+Callers should pass \fBNULL\fR for \fIcookiep\fR and \fIccountp\fR.
+These values are required if using the deprecated
+\fBddi_dma_nextcookie\fR(9F) interface, in which case \fIcookiep\fR is
+filled in with the first \fBddi_dma_cookie\fR(9S) structure.
 .sp
 .LP
 \fBddi_dma_getwin()\fR takes care of underlying resource synchronizations
@@ -118,7 +122,6 @@
 Otherwise, it calls  \fBddi_dma_getwin()\fR to shift the current window and
 start another \fBDMA\fR transfer.
 .SH RETURN VALUES
-.sp
 .LP
 \fBddi_dma_getwin()\fR returns:
 .sp
@@ -140,14 +143,13 @@
 .RE
 
 .SH CONTEXT
-.sp
 .LP
 \fBddi_dma_getwin()\fR can be called from user, kernel, or interrupt context.
 .SH SEE ALSO
-.sp
 .LP
 \fBddi_dma_addr_bind_handle\fR(9F), \fBddi_dma_alloc_handle\fR(9F),
-\fBddi_dma_buf_bind_handle\fR(9F), \fBddi_dma_nextcookie\fR(9F),
+\fBddi_dma_buf_bind_handle\fR(9F),  \fBddi_dma_cookie_get\fR(9F),
+\fBddi_dma_cookie_iter\fR(9F), \fBddi_dma_ncookies\fR(9F),
 \fBddi_dma_numwin\fR(9F), \fBddi_dma_sync\fR(9F),
 \fBddi_dma_unbind_handle\fR(9F), \fBddi_dma_cookie\fR(9S)
 .sp
--- a/usr/src/man/man9f/ddi_dma_nextcookie.9f	Wed Jan 22 16:05:13 2020 -0800
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-'\" te
-.\" Copyright (c) 1994, Sun Microsystems, Inc.
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DDI_DMA_NEXTCOOKIE 9F "Sep 26, 1994"
-.SH NAME
-ddi_dma_nextcookie \- retrieve subsequent DMA cookie
-.SH SYNOPSIS
-.LP
-.nf
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-
-
-
-\fBvoid\fR \fBddi_dma_nextcookie\fR(\fBddi_dma_handle_t\fR \fIhandle\fR,
-     \fBddi_dma_cookie_t *\fR\fIcookiep\fR);
-.fi
-
-.SH PARAMETERS
-.sp
-.ne 2
-.na
-\fB\fIhandle\fR\fR
-.ad
-.RS 11n
-The handle previously allocated by a call to  \fBddi_dma_alloc_handle\fR(9F).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIcookiep\fR\fR
-.ad
-.RS 11n
-A pointer to a  \fBddi_dma_cookie\fR(9S) structure.
-.RE
-
-.SH INTERFACE LEVEL
-.sp
-.LP
-Solaris DDI specific (Solaris DDI).
-.SH DESCRIPTION
-.sp
-.LP
-\fBddi_dma_nextcookie()\fR retrieves subsequent  \fBDMA\fR cookies for a
-\fBDMA\fR object.   \fBddi_dma_nextcookie()\fR fills in the
-\fBddi_dma_cookie\fR(9S) structure pointed to by  \fIcookiep\fR. The
-\fBddi_dma_cookie\fR(9S) structure must be allocated prior to calling
-\fBddi_dma_nextcookie()\fR.
-.sp
-.LP
-The \fBDMA\fR cookie count returned by \fBddi_dma_buf_bind_handle\fR(9F),
-\fBddi_dma_addr_bind_handle\fR(9F), or \fBddi_dma_getwin\fR(9F) indicates the
-number of \fBDMA\fR cookies a \fBDMA\fR object consists of. If the resulting
-cookie count,  \fIN\fR, is larger than 1,  \fBddi_dma_nextcookie()\fR must be
-called \fIN\fR-1 times to retrieve all  \fBDMA\fR cookies.
-.SH CONTEXT
-.sp
-.LP
-\fBddi_dma_nextcookie()\fR can be called from user, kernel, or interrupt
-context.
-.SH EXAMPLES
-.LP
-\fBExample 1 \fRProcess a scatter-gather list of I/O requests.
-.sp
-.LP
-This example demonstrates the use of  \fBddi_dma_nextcookie()\fR to process a
-scatter-gather list of I/O requests.
-
-.sp
-.in +2
-.nf
-/* setup scatter-gather list with multiple DMA cookies */
-ddi_dma_cookie_t  dmacookie;
-uint_t            ccount;
-\&...
-
-status = ddi_dma_buf_bind_handle(handle, bp, DDI_DMA_READ,
-	NULL, NULL, &dmacookie, &ccount);
-
-if (status == DDI_DMA_MAPPED) {
-
-	/* program DMA engine with first cookie */
-
-	while (--ccount > 0) {
-		ddi_dma_nextcookie(handle, &dmacookie);
-		/* program DMA engine with next cookie */
-	}
-}
-\&...
-.fi
-.in -2
-
-.SH SEE ALSO
-.sp
-.LP
-\fBddi_dma_addr_bind_handle\fR(9F), \fBddi_dma_alloc_handle\fR(9F),
-\fBddi_dma_buf_bind_handle\fR(9F), \fBddi_dma_unbind_handle\fR(9F),
-\fBddi_dma_cookie\fR(9S)
-.sp
-.LP
-\fIWriting Device Drivers\fR
--- a/usr/src/man/man9f/ddi_dmae.9f	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/man/man9f/ddi_dmae.9f	Wed Dec 18 06:18:35 2019 +0000
@@ -4,7 +4,7 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
 .\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
 .\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DDI_DMAE 9F "May 24, 2014"
+.TH DDI_DMAE 9F "Jan 18, 2020"
 .SH NAME
 ddi_dmae, ddi_dmae_alloc, ddi_dmae_release, ddi_dmae_prog, ddi_dmae_disable,
 ddi_dmae_enable, ddi_dmae_stop, ddi_dmae_getcnt, ddi_dmae_1stparty,
@@ -58,11 +58,9 @@
 .fi
 
 .SH INTERFACE LEVEL
-.sp
 .LP
 Solaris DDI specific (Solaris DDI).
 .SH PARAMETERS
-.sp
 .ne 2
 .na
 \fB\fIdip\fR\fR
@@ -157,7 +155,6 @@
 .RE
 
 .SH DESCRIPTION
-.sp
 .LP
 There are three possible ways that a device can perform \fBDMA\fR engine
 functions:
@@ -201,7 +198,6 @@
 .RE
 
 .SS "\fBddi_dmae_alloc()\fR"
-.sp
 .LP
 The \fBddi_dmae_alloc()\fR function is used to acquire a \fBDMA\fR channel of
 the system \fBDMA\fR engine. \fBddi_dmae_alloc()\fR allows only one device at a
@@ -228,7 +224,6 @@
 fails to do so, it must return the value \fBDDI_DMA_CALLBACK_RUNOUT\fR. In this
 case, the callback function is put back on a list to be called again later.
 .SS "\fBddi_dmae_prog()\fR"
-.sp
 .LP
 The \fBddi_dmae_prog()\fR function programs the \fBDMA\fR channel for a
 \fBDMA\fR transfer. The \fBddi_dmae_req\fR structure contains all the
@@ -250,30 +245,25 @@
 contains the address and count. Then this cookie is passed to
 \fBddi_dmae_prog()\fR.
 .SS "\fBddi_dmae_disable()\fR"
-.sp
 .LP
 The \fBddi_dmae_disable()\fR function disables the \fBDMA\fR channel so that it
 no longer responds to a device's  \fBDMA\fR service requests.
 .SS "\fBddi_dmae_enable()\fR"
-.sp
 .LP
 The \fBddi_dmae_enable()\fR function enables the \fBDMA\fR channel for
 operation. This may be used to re-enable the channel after a call to
 \fBddi_dmae_disable()\fR. The channel is automatically enabled after successful
 programming by \fBddi_dmae_prog()\fR.
 .SS "\fBddi_dmae_stop()\fR"
-.sp
 .LP
 The \fBddi_dmae_stop()\fR function disables the channel and terminates any
 active operation.
 .SS "\fBddi_dmae_getcnt()\fR"
-.sp
 .LP
 The \fBddi_dmae_getcnt()\fR function examines the count register of the
 \fBDMA\fR channel and sets \fI*countp\fR to the number of bytes remaining to be
 transferred.  The channel is assumed to be stopped.
 .SS "\fBddi_dmae_1stparty()\fR"
-.sp
 .LP
 In the case of \fBISA\fR buses, \fBddi_dmae_1stparty()\fR configures a channel
 in the system's \fBDMA\fR engine to operate in a ``slave'' (``cascade'') mode.
@@ -285,7 +275,6 @@
 I/O, including the necessary \fBDMA\fR address and count values obtained from
 the \fBddi_dma_cookie\fR(9S).
 .SS "\fBddi_dmae_getattr()\fR"
-.sp
 .LP
 The \fBddi_dmae_getattr()\fR function fills in the \fBDMA\fR attribute
 structure, pointed to by \fIattrp\fR, with the \fBDMA\fR attributes of the
@@ -295,9 +284,8 @@
 The \fBDMA\fR attribute structure must be passed to the \fBDMA\fR resource
 allocation functions to provide the information necessary to break the
 \fBDMA\fR request into \fBDMA\fR windows and \fBDMA\fR cookies. See
-\fBddi_dma_nextcookie\fR(9F) and \fBddi_dma_getwin\fR(9F).
+\fBddi_dma_cookie_iter\fR(9F) and \fBddi_dma_getwin\fR(9F).
 .SH RETURN VALUES
-.sp
 .ne 2
 .na
 \fB\fBDDI_SUCCESS\fR\fR
@@ -326,14 +314,12 @@
 .RE
 
 .SH CONTEXT
-.sp
 .LP
 If \fBddi_dmae_alloc()\fR is called from interrupt context, then its
 \fIdmae_waitfp\fR argument and the callback function must not have the value
 \fBDDI_DMA_SLEEP\fR. Otherwise, all these routines can be called from user,
 interrupt, or kernel context.
 .SH ATTRIBUTES
-.sp
 .LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
 .sp
@@ -349,10 +335,9 @@
 .TE
 
 .SH SEE ALSO
-.sp
 .LP
 \fBisa\fR(4), \fBattributes\fR(5), \fBddi_dma_buf_setup\fR(9F),
-\fBddi_dma_getwin\fR(9F), \fBddi_dma_nextcookie\fR(9F),
+\fBddi_dma_cookie_iter\fR(9F), \fBddi_dma_getwin\fR(9F),
 \fBddi_dma_mem_alloc\fR(9F), \fBddi_dma_addr_bind_handle\fR(9F), \fBddi_dma_attr\fR(9S),
 \fBddi_dma_cookie\fR(9S),
 \fBddi_dmae_req\fR(9S)
--- a/usr/src/pkg/manifests/system-kernel.man9f.inc	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/pkg/manifests/system-kernel.man9f.inc	Wed Dec 18 06:18:35 2019 +0000
@@ -150,11 +150,11 @@
 file path=usr/share/man/man9f/ddi_dma_alloc_handle.9f
 file path=usr/share/man/man9f/ddi_dma_buf_bind_handle.9f
 file path=usr/share/man/man9f/ddi_dma_burstsizes.9f
+file path=usr/share/man/man9f/ddi_dma_cookie_iter.9f
 file path=usr/share/man/man9f/ddi_dma_free_handle.9f
 file path=usr/share/man/man9f/ddi_dma_getwin.9f
 file path=usr/share/man/man9f/ddi_dma_mem_alloc.9f
 file path=usr/share/man/man9f/ddi_dma_mem_free.9f
-file path=usr/share/man/man9f/ddi_dma_nextcookie.9f
 file path=usr/share/man/man9f/ddi_dma_numwin.9f
 file path=usr/share/man/man9f/ddi_dma_set_sbus64.9f
 file path=usr/share/man/man9f/ddi_dma_sync.9f
@@ -719,6 +719,10 @@
     target=ddi_devid_compare.9f
 link path=usr/share/man/man9f/ddi_devid_valid.9f target=ddi_devid_compare.9f
 link path=usr/share/man/man9f/ddi_devmap_segmap.9f target=devmap_setup.9f
+link path=usr/share/man/man9f/ddi_dma_cookie_get.9f target=ddi_dma_cookie_iter.9f
+link path=usr/share/man/man9f/ddi_dma_cookie_one.9f target=ddi_dma_cookie_iter.9f
+link path=usr/share/man/man9f/ddi_dma_ncookies.9f target=ddi_dma_cookie_iter.9f
+link path=usr/share/man/man9f/ddi_dma_nextcookie.9f target=ddi_dma_cookie_iter.9f
 link path=usr/share/man/man9f/ddi_dmae_1stparty.9f target=ddi_dmae.9f
 link path=usr/share/man/man9f/ddi_dmae_alloc.9f target=ddi_dmae.9f
 link path=usr/share/man/man9f/ddi_dmae_disable.9f target=ddi_dmae.9f
--- a/usr/src/uts/common/io/scsi/impl/scsi_resource.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/common/io/scsi/impl/scsi_resource.c	Wed Dec 18 06:18:35 2019 +0000
@@ -258,6 +258,7 @@
 	pktw->pcw_total_xfer += pktp->pkt_dma_len;
 	pktp->pkt_cookies = hp->dmai_cookie - 1;
 	hp->dmai_cookie = cp;
+	hp->dmai_curcookie = num_segs;
 
 	return (1);
 }
--- a/usr/src/uts/common/os/sunddi.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/common/os/sunddi.c	Wed Dec 18 06:18:35 2019 +0000
@@ -7074,6 +7074,14 @@
 	dev_info_t *dip, *rdip;
 	struct ddi_dma_req dmareq;
 	int (*funcp)();
+	ddi_dma_cookie_t cookie;
+	uint_t count;
+
+	if (cookiep == NULL)
+		cookiep = &cookie;
+
+	if (ccountp == NULL)
+		ccountp = &count;
 
 	dmareq.dmar_flags = flags;
 	dmareq.dmar_fp = waitfp;
@@ -7130,10 +7138,19 @@
 	dev_info_t *dip, *rdip;
 	struct ddi_dma_req dmareq;
 	int (*funcp)();
+	ddi_dma_cookie_t cookie;
+	uint_t count;
 
 	if (len == (uint_t)0) {
 		return (DDI_DMA_NOMAPPING);
 	}
+
+	if (cookiep == NULL)
+		cookiep = &cookie;
+
+	if (ccountp == NULL)
+		ccountp = &count;
+
 	dmareq.dmar_flags = flags;
 	dmareq.dmar_fp = waitfp;
 	dmareq.dmar_arg = arg;
@@ -7156,6 +7173,11 @@
 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
 	ddi_dma_cookie_t *cp;
 
+	if (hp->dmai_curcookie >= hp->dmai_ncookies) {
+		panic("ddi_dma_nextcookie() called too many times on handle %p",
+		    hp);
+	}
+
 	cp = hp->dmai_cookie;
 	ASSERT(cp);
 
@@ -7164,6 +7186,74 @@
 	cookiep->dmac_address = cp->dmac_address;
 	cookiep->dmac_size = cp->dmac_size;
 	hp->dmai_cookie++;
+	hp->dmai_curcookie++;
+}
+
+int
+ddi_dma_ncookies(ddi_dma_handle_t handle)
+{
+	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
+
+	return (hp->dmai_ncookies);
+}
+
+const ddi_dma_cookie_t *
+ddi_dma_cookie_iter(ddi_dma_handle_t handle, const ddi_dma_cookie_t *iter)
+{
+	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
+	const ddi_dma_cookie_t *base, *end;
+
+	if (hp->dmai_ncookies == 0) {
+		return (NULL);
+	}
+
+	base = hp->dmai_cookie - hp->dmai_curcookie;
+	end = base + hp->dmai_ncookies;
+	if (iter == NULL) {
+		return (base);
+	}
+
+	if ((uintptr_t)iter < (uintptr_t)base ||
+	    (uintptr_t)iter >= (uintptr_t)end) {
+		return (NULL);
+	}
+
+	iter++;
+	if (iter == end) {
+		return (NULL);
+	}
+
+	return (iter);
+}
+
+const ddi_dma_cookie_t *
+ddi_dma_cookie_get(ddi_dma_handle_t handle, uint_t index)
+{
+	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
+	const ddi_dma_cookie_t *base;
+
+	if (index >= hp->dmai_ncookies) {
+		return (NULL);
+	}
+
+	base = hp->dmai_cookie - hp->dmai_curcookie;
+	return (base + index);
+}
+
+const ddi_dma_cookie_t *
+ddi_dma_cookie_one(ddi_dma_handle_t handle)
+{
+	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
+	const ddi_dma_cookie_t *base;
+
+	if (hp->dmai_ncookies != 1) {
+		panic("ddi_dma_cookie_one() called with improper handle %p",
+		    hp);
+	}
+	ASSERT3P(hp->dmai_cookie, !=, NULL);
+
+	base = hp->dmai_cookie - hp->dmai_curcookie;
+	return (base);
 }
 
 int
@@ -7184,11 +7274,19 @@
 {
 	int (*funcp)() = ddi_dma_win;
 	struct bus_ops *bop;
+	ddi_dma_cookie_t cookie;
+	uint_t count;
 
 	bop = DEVI(HD)->devi_ops->devo_bus_ops;
 	if (bop && bop->bus_dma_win)
 		funcp = bop->bus_dma_win;
 
+	if (cookiep == NULL)
+		cookiep = &cookie;
+
+	if (ccountp == NULL)
+		ccountp = &count;
+
 	return ((*funcp)(HD, HD, h, win, offp, lenp, cookiep, ccountp));
 }
 
--- a/usr/src/uts/common/sys/ddi_impldefs.h	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/common/sys/ddi_impldefs.h	Wed Dec 18 06:18:35 2019 +0000
@@ -877,6 +877,8 @@
 	uint_t		dmai_inuse;	/* active handle? */
 	uint_t		dmai_nwin;
 	uint_t		dmai_winsize;
+	uint_t		dmai_ncookies;
+	uint_t		dmai_curcookie;
 	caddr_t		dmai_nexus_private;
 	void		*dmai_iopte;
 	uint_t		*dmai_sbi;
@@ -901,6 +903,8 @@
  */
 typedef struct ddi_dma_impl {
 	ddi_dma_cookie_t *dmai_cookie; /* array of DMA cookies */
+	uint_t		dmai_ncookies;
+	uint_t		dmai_curcookie;
 	void		*dmai_private;
 
 	/*
--- a/usr/src/uts/common/sys/sunddi.h	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/common/sys/sunddi.h	Wed Dec 18 06:18:35 2019 +0000
@@ -1368,6 +1368,10 @@
 
 /*
  * get next DMA cookie
+ *
+ * This function has been deprecated because it is unsafe. Please use
+ * ddi_dma_cookie_iter(), ddi_dma_cookie_get(), or ddi_dma_cookie_one() instead.
+ * For more information on the problems, please see the manual page.
  */
 
 void
@@ -1851,6 +1855,16 @@
 extern ddi_devstate_t ddi_get_devstate(dev_info_t *);
 
 /*
+ * Replacement DMA cookie functions for ddi_dma_nextcookie().
+ */
+extern int ddi_dma_ncookies(ddi_dma_handle_t);
+extern const ddi_dma_cookie_t *ddi_dma_cookie_iter(ddi_dma_handle_t,
+    const ddi_dma_cookie_t *);
+extern const ddi_dma_cookie_t *ddi_dma_cookie_get(ddi_dma_handle_t, uint_t);
+extern const ddi_dma_cookie_t *ddi_dma_cookie_one(ddi_dma_handle_t);
+
+
+/*
  * Miscellaneous redefines
  */
 #define	uiophysio	physio
--- a/usr/src/uts/i86pc/io/rootnex.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/i86pc/io/rootnex.c	Wed Dec 18 06:18:35 2019 +0000
@@ -2186,6 +2186,8 @@
 		*ccountp = sinfo->si_sgl_size;
 		hp->dmai_cookie++;
 		hp->dmai_rflags &= ~DDI_DMA_PARTIAL;
+		hp->dmai_ncookies = *ccountp;
+		hp->dmai_curcookie = 1;
 		ROOTNEX_DPROF_INC(&rootnex_cnt[ROOTNEX_CNT_ACTIVE_BINDS]);
 		ROOTNEX_DPROBE4(rootnex__bind__fast, dev_info_t *, rdip,
 		    uint64_t, rootnex_cnt[ROOTNEX_CNT_ACTIVE_BINDS],
@@ -2259,6 +2261,8 @@
 	}
 	*cookiep = dma->dp_cookies[0];
 	hp->dmai_cookie++;
+	hp->dmai_ncookies = *ccountp;
+	hp->dmai_curcookie = 1;
 
 	ROOTNEX_DPROF_INC(&rootnex_cnt[ROOTNEX_CNT_ACTIVE_BINDS]);
 	ROOTNEX_DPROBE4(rootnex__bind__slow, dev_info_t *, rdip, uint64_t,
@@ -2411,6 +2415,7 @@
 		hp->dmai_cookie = dma->dp_cookies;
 	}
 	hp->dmai_cookie++;
+	hp->dmai_curcookie = 1;
 }
 
 /*ARGSUSED*/
@@ -2671,6 +2676,10 @@
 	hp->dmai_error.err_status = DDI_FM_OK;
 	hp->dmai_error.err_expected = DDI_FM_ERR_UNEXPECTED;
 	hp->dmai_error.err_ontrap = NULL;
+
+	/* Cookie tracking */
+	hp->dmai_ncookies = 0;
+	hp->dmai_curcookie = 0;
 }
 
 
@@ -4770,6 +4779,8 @@
 		*ccountp = dma->dp_sglinfo.si_sgl_size;
 		*cookiep = hp->dmai_cookie[0];
 		hp->dmai_cookie++;
+		hp->dmai_ncookies = *ccountp;
+		hp->dmai_curcookie = 1;
 		return (DDI_SUCCESS);
 	}
 
@@ -4865,6 +4876,8 @@
 	*lenp = window->wd_size;
 	*ccountp = window->wd_cookie_cnt;
 	*cookiep = hp->dmai_cookie[0];
+	hp->dmai_ncookies = *ccountp;
+	hp->dmai_curcookie = 1;
 	hp->dmai_cookie++;
 
 #if !defined(__amd64)
--- a/usr/src/uts/sun4/io/px/px.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/sun4/io/px/px.c	Wed Dec 18 06:18:35 2019 +0000
@@ -999,6 +999,8 @@
 mapped:
 		*ccountp = 1;
 		MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size);
+		mp->dmai_ncookies = 1;
+		mp->dmai_curcookie = 1;
 		break;
 	case PX_DMAI_FLAGS_BYPASS:
 	case PX_DMAI_FLAGS_PTP:
@@ -1007,6 +1009,10 @@
 		*ccountp = PX_WINLST(mp)->win_ncookies;
 		*cookiep =
 		    *(ddi_dma_cookie_t *)(PX_WINLST(mp) + 1); /* wholeobj */
+		/*
+		 * mp->dmai_ncookies and mp->dmai_curcookie are set by
+		 * px_dma_physwin().
+		 */
 		break;
 	default:
 		cmn_err(CE_PANIC, "%s%d: px_dma_bindhdl(%p): bad dma type",
@@ -1078,6 +1084,8 @@
 		ddi_run_callback(&px_kmem_clid);
 	}
 	mp->dmai_flags &= PX_DMAI_FLAGS_PRESERVE;
+	mp->dmai_ncookies = 0;
+	mp->dmai_curcookie = 0;
 
 	return (DDI_SUCCESS);
 }
@@ -1120,6 +1128,8 @@
 			    mp->dmai_size);
 		if (ccountp)
 			*ccountp = 1;
+		mp->dmai_ncookies = 1;
+		mp->dmai_curcookie = 1;
 		break;
 	case PX_DMAI_FLAGS_PTP:
 	case PX_DMAI_FLAGS_BYPASS: {
@@ -1137,6 +1147,8 @@
 		win_p->win_curseg = 0;
 		if (ccountp)
 			*ccountp = win_p->win_ncookies;
+		mp->dmai_ncookies = win_p->win_ncookies;
+		mp->dmai_curcookie = 1;
 		}
 		break;
 	default:
--- a/usr/src/uts/sun4/io/px/px_dma.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/sun4/io/px/px_dma.c	Wed Dec 18 06:18:35 2019 +0000
@@ -76,6 +76,8 @@
 	mp->dmai_flags = 0;
 	mp->dmai_pfnlst = NULL;
 	mp->dmai_winlst = NULL;
+	mp->dmai_ncookies = 0;
+	mp->dmai_curcookie = 0;
 
 	/*
 	 * kmem_alloc debug: the following fields are not zero-ed
@@ -1229,7 +1231,9 @@
 	mp->dmai_rflags &= ~DDI_DMA_REDZONE;
 	mp->dmai_flags |= PX_DMAI_FLAGS_NOSYNC;
 	cookie0_p = (ddi_dma_cookie_t *)(PX_WINLST(mp) + 1);
-	mp->dmai_cookie = PX_WINLST(mp)->win_ncookies > 1 ? cookie0_p + 1 : 0;
+	mp->dmai_cookie = cookie0_p + 1;
+	mp->dmai_curcookie = 1;
+	mp->dmai_ncookies = PX_WINLST(mp)->win_ncookies;
 	mp->dmai_mapping = cookie0_p->dmac_laddress;
 
 	px_dma_freepfn(mp);
--- a/usr/src/uts/sun4u/io/pci/pci.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/sun4u/io/pci/pci.c	Wed Dec 18 06:18:35 2019 +0000
@@ -731,6 +731,8 @@
 mapped:
 		*ccountp = 1;
 		MAKE_DMA_COOKIE(cookiep, mp->dmai_mapping, mp->dmai_size);
+		mp->dmai_ncookies = 1;
+		mp->dmai_curcookie = 1;
 		break;
 	case DMAI_FLAGS_BYPASS:
 	case DMAI_FLAGS_PEER_TO_PEER:
@@ -738,6 +740,10 @@
 			goto map_err;
 		*ccountp = WINLST(mp)->win_ncookies;
 		*cookiep = *(ddi_dma_cookie_t *)(WINLST(mp) + 1); /* wholeobj */
+		/*
+		 * mp->dmai_ncookies and mp->dmai_curcookie are set by
+		 * pci_dma_physwin().
+		 */
 		break;
 	default:
 		panic("%s%d: pci_dma_bindhdl(%p): bad dma type",
@@ -809,6 +815,8 @@
 	SYNC_BUF_PA(mp) = 0;
 
 	mp->dmai_error.err_cf = NULL;
+	mp->dmai_ncookies = 0;
+	mp->dmai_curcookie = 0;
 
 	return (DDI_SUCCESS);
 }
@@ -845,6 +853,8 @@
 			    mp->dmai_size);
 		if (ccountp)
 			*ccountp = 1;
+		mp->dmai_ncookies = 1;
+		mp->dmai_curcookie = 1;
 		break;
 	case DMAI_FLAGS_PEER_TO_PEER:
 	case DMAI_FLAGS_BYPASS: {
@@ -863,6 +873,8 @@
 		win_p->win_curseg = 0;
 		if (ccountp)
 			*ccountp = win_p->win_ncookies;
+		mp->dmai_ncookies = win_p->win_ncookies;
+		mp->dmai_curcookie = 1;
 		}
 		break;
 	default:
--- a/usr/src/uts/sun4u/io/pci/pci_dma.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/sun4u/io/pci/pci_dma.c	Wed Dec 18 06:18:35 2019 +0000
@@ -267,6 +267,8 @@
 	mp->dmai_flags = 0;
 	mp->dmai_pfnlst = NULL;
 	mp->dmai_winlst = NULL;
+	mp->dmai_ncookies = 0;
+	mp->dmai_curcookie = 0;
 
 	/*
 	 * kmem_alloc debug: the following fields are not zero-ed
@@ -1410,8 +1412,10 @@
 	}
 	mp->dmai_rflags &= ~DDI_DMA_REDZONE;
 	cookie0_p = (ddi_dma_cookie_t *)(WINLST(mp) + 1);
-	mp->dmai_cookie = WINLST(mp)->win_ncookies > 1 ? cookie0_p + 1 : 0;
+	mp->dmai_cookie = cookie0_p + 1;
 	mp->dmai_mapping = cookie0_p->dmac_laddress;
+	mp->dmai_ncookies = WINLST(mp)->win_ncookies;
+	mp->dmai_curcookie = 1;
 
 	pci_dma_freepfn(mp);
 	return (DDI_DMA_MAPPED);
--- a/usr/src/uts/sun4v/io/niumx/niumx.c	Wed Jan 22 16:05:13 2020 -0800
+++ b/usr/src/uts/sun4v/io/niumx/niumx.c	Wed Dec 18 06:18:35 2019 +0000
@@ -665,6 +665,8 @@
 	mp->dmai_rdip = rdip;
 	mp->dmai_pfnlst = NULL;
 	mp->dmai_cookie = NULL;
+	mp->dmai_ncookies = 0;
+	mp->dmai_curcookie = 0;
 	mp->dmai_fault = 0;
 	mp->dmai_fault_check = NULL;
 	mp->dmai_fault_notify = NULL;
@@ -775,6 +777,8 @@
 		}
 	mp->dmai_cookie->dmac_laddress = mp->dmai_mapping;
 	mp->dmai_cookie->dmac_size = mp->dmai_size;
+	mp->dmai_ncookies = 1;
+	mp->dmai_curcookie = 0;
 	*ccountp = 1;
 	*cookiep = *mp->dmai_cookie;
 	DBG(NIUMX_DBG_DMA_BINDH, dip, "cookie %" PRIx64 "+%x, count=%d\n",
@@ -801,6 +805,7 @@
 	if (mp->dmai_cookie) {
 		kmem_free(mp->dmai_cookie, sizeof (ddi_dma_cookie_t));
 		mp->dmai_cookie = NULL;
+		mp->dmai_ncookies = mp->dmai_curcookie = 0;
 	}
 
 	return (DDI_SUCCESS);