xref: /illumos-gate/usr/src/uts/common/io/comstar/port/qlt/qlt_dma.c (revision 3fb517f786391b507780c78aabb8d98bfea9efe9)
1fcf3ce44SJohn Forte /*
2fcf3ce44SJohn Forte  * CDDL HEADER START
3fcf3ce44SJohn Forte  *
4fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7fcf3ce44SJohn Forte  *
8fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11fcf3ce44SJohn Forte  * and limitations under the License.
12fcf3ce44SJohn Forte  *
13fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18fcf3ce44SJohn Forte  *
19fcf3ce44SJohn Forte  * CDDL HEADER END
20fcf3ce44SJohn Forte  */
21c4ddbbe1SDaniel Beauregard 
22fcf3ce44SJohn Forte /*
23c4ddbbe1SDaniel Beauregard  * Copyright 2009 QLogic Corporation.  All rights reserved.
24c4ddbbe1SDaniel Beauregard  * Use is subject to license terms.
25c4ddbbe1SDaniel Beauregard  */
26c4ddbbe1SDaniel Beauregard 
27c4ddbbe1SDaniel Beauregard /*
28*3fb517f7SJames Moore  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
29fcf3ce44SJohn Forte  */
30fcf3ce44SJohn Forte 
31fcf3ce44SJohn Forte #include <sys/conf.h>
32fcf3ce44SJohn Forte #include <sys/ddi.h>
33fcf3ce44SJohn Forte #include <sys/sunddi.h>
34fcf3ce44SJohn Forte #include <sys/modctl.h>
35fcf3ce44SJohn Forte 
36fcf3ce44SJohn Forte #include <stmf_defines.h>
37fcf3ce44SJohn Forte #include <fct_defines.h>
38fcf3ce44SJohn Forte #include <stmf.h>
39fcf3ce44SJohn Forte #include <portif.h>
40fcf3ce44SJohn Forte #include <fct.h>
41fcf3ce44SJohn Forte #include <qlt.h>
42fcf3ce44SJohn Forte #include <qlt_dma.h>
43fcf3ce44SJohn Forte 
44*3fb517f7SJames Moore /*
45*3fb517f7SJames Moore  *  Local Function Prototypes.
46*3fb517f7SJames Moore  */
47*3fb517f7SJames Moore static void
48*3fb517f7SJames Moore qlt_dma_free_handles(qlt_state_t *qlt, qlt_dma_handle_t *first_handle);
49*3fb517f7SJames Moore 
50fcf3ce44SJohn Forte #define	BUF_COUNT_2K		2048
51fcf3ce44SJohn Forte #define	BUF_COUNT_8K		512
523f3ce7b9SDaniel Beauregard #define	BUF_COUNT_64K		256
533f3ce7b9SDaniel Beauregard #define	BUF_COUNT_128K		1024
54fcf3ce44SJohn Forte #define	BUF_COUNT_256K		8
55fcf3ce44SJohn Forte 
56fcf3ce44SJohn Forte #define	QLT_DMEM_MAX_BUF_SIZE	(4 * 65536)
57fcf3ce44SJohn Forte #define	QLT_DMEM_NBUCKETS	5
58fcf3ce44SJohn Forte static qlt_dmem_bucket_t bucket2K	= { 2048, BUF_COUNT_2K },
59fcf3ce44SJohn Forte 			bucket8K	= { 8192, BUF_COUNT_8K },
60fcf3ce44SJohn Forte 			bucket64K	= { 65536, BUF_COUNT_64K },
61fcf3ce44SJohn Forte 			bucket128k	= { (2 * 65536), BUF_COUNT_128K },
62fcf3ce44SJohn Forte 			bucket256k	= { (4 * 65536), BUF_COUNT_256K };
63fcf3ce44SJohn Forte 
64fcf3ce44SJohn Forte static qlt_dmem_bucket_t *dmem_buckets[] = { &bucket2K, &bucket8K,
65fcf3ce44SJohn Forte 			&bucket64K, &bucket128k, &bucket256k, NULL };
66fcf3ce44SJohn Forte static ddi_device_acc_attr_t acc;
67fcf3ce44SJohn Forte static ddi_dma_attr_t qlt_scsi_dma_attr = {
68fcf3ce44SJohn Forte 	DMA_ATTR_V0,		/* dma_attr_version */
69fcf3ce44SJohn Forte 	0,			/* low DMA address range */
70fcf3ce44SJohn Forte 	0xffffffffffffffff,	/* high DMA address range */
71fcf3ce44SJohn Forte 	0xffffffff,		/* DMA counter register */
72fcf3ce44SJohn Forte 	8192,			/* DMA address alignment */
73fcf3ce44SJohn Forte 	0xff,			/* DMA burstsizes */
74fcf3ce44SJohn Forte 	1,			/* min effective DMA size */
75fcf3ce44SJohn Forte 	0xffffffff,		/* max DMA xfer size */
76fcf3ce44SJohn Forte 	0xffffffff,		/* segment boundary */
77fcf3ce44SJohn Forte 	1,			/* s/g list length */
78fcf3ce44SJohn Forte 	1,			/* granularity of device */
79fcf3ce44SJohn Forte 	0			/* DMA transfer flags */
80fcf3ce44SJohn Forte };
81fcf3ce44SJohn Forte 
82fcf3ce44SJohn Forte fct_status_t
83fcf3ce44SJohn Forte qlt_dmem_init(qlt_state_t *qlt)
84fcf3ce44SJohn Forte {
85fcf3ce44SJohn Forte 	qlt_dmem_bucket_t	*p;
86fcf3ce44SJohn Forte 	qlt_dmem_bctl_t		*bctl, *bc;
87fcf3ce44SJohn Forte 	qlt_dmem_bctl_t		*prev;
88fcf3ce44SJohn Forte 	int			ndx, i;
89fcf3ce44SJohn Forte 	uint32_t		total_mem;
90fcf3ce44SJohn Forte 	uint8_t			*addr;
91fcf3ce44SJohn Forte 	uint8_t			*host_addr;
92fcf3ce44SJohn Forte 	uint64_t		dev_addr;
93fcf3ce44SJohn Forte 	ddi_dma_cookie_t	cookie;
94fcf3ce44SJohn Forte 	uint32_t		ncookie;
95fcf3ce44SJohn Forte 	uint32_t		bsize;
96fcf3ce44SJohn Forte 	size_t			len;
97fcf3ce44SJohn Forte 
98a2255df3SDaniel Beauregard 	if (qlt->qlt_bucketcnt[0] != 0) {
99a2255df3SDaniel Beauregard 		bucket2K.dmem_nbufs = qlt->qlt_bucketcnt[0];
100fcf3ce44SJohn Forte 	}
101a2255df3SDaniel Beauregard 	if (qlt->qlt_bucketcnt[1] != 0) {
102a2255df3SDaniel Beauregard 		bucket8K.dmem_nbufs = qlt->qlt_bucketcnt[1];
103a2255df3SDaniel Beauregard 	}
104a2255df3SDaniel Beauregard 	if (qlt->qlt_bucketcnt[2] != 0) {
105a2255df3SDaniel Beauregard 		bucket64K.dmem_nbufs = qlt->qlt_bucketcnt[2];
106a2255df3SDaniel Beauregard 	}
107a2255df3SDaniel Beauregard 	if (qlt->qlt_bucketcnt[3] != 0) {
108a2255df3SDaniel Beauregard 		bucket128k.dmem_nbufs = qlt->qlt_bucketcnt[3];
109a2255df3SDaniel Beauregard 	}
110a2255df3SDaniel Beauregard 	if (qlt->qlt_bucketcnt[4] != 0) {
111a2255df3SDaniel Beauregard 		bucket256k.dmem_nbufs = qlt->qlt_bucketcnt[4];
112a2255df3SDaniel Beauregard 	}
113a2255df3SDaniel Beauregard 
114fcf3ce44SJohn Forte 	bsize = sizeof (dmem_buckets);
115c4ddbbe1SDaniel Beauregard 	ndx = (int)(bsize / sizeof (void *));
116fcf3ce44SJohn Forte 	/*
117fcf3ce44SJohn Forte 	 * The reason it is ndx - 1 everywhere is becasue the last bucket
118fcf3ce44SJohn Forte 	 * pointer is NULL.
119fcf3ce44SJohn Forte 	 */
120fcf3ce44SJohn Forte 	qlt->dmem_buckets = (qlt_dmem_bucket_t **)kmem_zalloc(bsize +
121c4ddbbe1SDaniel Beauregard 	    ((ndx - 1) * (int)sizeof (qlt_dmem_bucket_t)), KM_SLEEP);
122fcf3ce44SJohn Forte 	for (i = 0; i < (ndx - 1); i++) {
123fcf3ce44SJohn Forte 		qlt->dmem_buckets[i] = (qlt_dmem_bucket_t *)
124fcf3ce44SJohn Forte 		    ((uint8_t *)qlt->dmem_buckets + bsize +
125c4ddbbe1SDaniel Beauregard 		    (i * (int)sizeof (qlt_dmem_bucket_t)));
126fcf3ce44SJohn Forte 		bcopy(dmem_buckets[i], qlt->dmem_buckets[i],
127fcf3ce44SJohn Forte 		    sizeof (qlt_dmem_bucket_t));
128fcf3ce44SJohn Forte 	}
129fcf3ce44SJohn Forte 	bzero(&acc, sizeof (acc));
130fcf3ce44SJohn Forte 	acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
131fcf3ce44SJohn Forte 	acc.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
132fcf3ce44SJohn Forte 	acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
133fcf3ce44SJohn Forte 	for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) {
134fcf3ce44SJohn Forte 		bctl = (qlt_dmem_bctl_t *)kmem_zalloc(p->dmem_nbufs *
135fcf3ce44SJohn Forte 		    sizeof (qlt_dmem_bctl_t), KM_NOSLEEP);
136c4ddbbe1SDaniel Beauregard 		if (bctl == NULL) {
137c4ddbbe1SDaniel Beauregard 			EL(qlt, "bctl==NULL\n");
138fcf3ce44SJohn Forte 			goto alloc_bctl_failed;
139c4ddbbe1SDaniel Beauregard 		}
140fcf3ce44SJohn Forte 		p->dmem_bctls_mem = bctl;
141fcf3ce44SJohn Forte 		mutex_init(&p->dmem_lock, NULL, MUTEX_DRIVER, NULL);
142c4ddbbe1SDaniel Beauregard 		if ((i = ddi_dma_alloc_handle(qlt->dip, &qlt_scsi_dma_attr,
143c4ddbbe1SDaniel Beauregard 		    DDI_DMA_SLEEP, 0, &p->dmem_dma_handle)) != DDI_SUCCESS) {
144c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_dma_alloc_handle status=%xh\n", i);
145fcf3ce44SJohn Forte 			goto alloc_handle_failed;
146c4ddbbe1SDaniel Beauregard 		}
147fcf3ce44SJohn Forte 
148fcf3ce44SJohn Forte 		total_mem = p->dmem_buf_size * p->dmem_nbufs;
149fcf3ce44SJohn Forte 
150c4ddbbe1SDaniel Beauregard 		if ((i = ddi_dma_mem_alloc(p->dmem_dma_handle, total_mem, &acc,
151fcf3ce44SJohn Forte 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, (caddr_t *)&addr,
152c4ddbbe1SDaniel Beauregard 		    &len, &p->dmem_acc_handle)) != DDI_SUCCESS) {
153c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_dma_mem_alloc status=%xh\n", i);
154fcf3ce44SJohn Forte 			goto mem_alloc_failed;
155c4ddbbe1SDaniel Beauregard 		}
156fcf3ce44SJohn Forte 
157c4ddbbe1SDaniel Beauregard 		if ((i = ddi_dma_addr_bind_handle(p->dmem_dma_handle, NULL,
158fcf3ce44SJohn Forte 		    (caddr_t)addr, total_mem, DDI_DMA_RDWR | DDI_DMA_STREAMING,
159c4ddbbe1SDaniel Beauregard 		    DDI_DMA_DONTWAIT, 0, &cookie, &ncookie)) != DDI_SUCCESS) {
160c4ddbbe1SDaniel Beauregard 			EL(qlt, "ddi_dma_addr_bind_handle status=%xh\n", i);
161fcf3ce44SJohn Forte 			goto addr_bind_handle_failed;
162c4ddbbe1SDaniel Beauregard 		}
163c4ddbbe1SDaniel Beauregard 		if (ncookie != 1) {
164c4ddbbe1SDaniel Beauregard 			EL(qlt, "ncookie=%d\n", ncookie);
165fcf3ce44SJohn Forte 			goto dmem_init_failed;
166c4ddbbe1SDaniel Beauregard 		}
167fcf3ce44SJohn Forte 
168fcf3ce44SJohn Forte 		p->dmem_host_addr = host_addr = addr;
169fcf3ce44SJohn Forte 		p->dmem_dev_addr = dev_addr = (uint64_t)cookie.dmac_laddress;
170fcf3ce44SJohn Forte 		bsize = p->dmem_buf_size;
171fcf3ce44SJohn Forte 		p->dmem_bctl_free_list = bctl;
172fcf3ce44SJohn Forte 		p->dmem_nbufs_free = p->dmem_nbufs;
173fcf3ce44SJohn Forte 		for (i = 0; i < p->dmem_nbufs; i++) {
174fcf3ce44SJohn Forte 			stmf_data_buf_t	*db;
175fcf3ce44SJohn Forte 			prev = bctl;
176fcf3ce44SJohn Forte 			bctl->bctl_bucket = p;
177fcf3ce44SJohn Forte 			bctl->bctl_buf = db = stmf_alloc(STMF_STRUCT_DATA_BUF,
178fcf3ce44SJohn Forte 			    0, 0);
179fcf3ce44SJohn Forte 			db->db_port_private = bctl;
180fcf3ce44SJohn Forte 			db->db_sglist[0].seg_addr = host_addr;
181fcf3ce44SJohn Forte 			bctl->bctl_dev_addr = dev_addr;
182fcf3ce44SJohn Forte 			db->db_sglist[0].seg_length = db->db_buf_size = bsize;
183fcf3ce44SJohn Forte 			db->db_sglist_length = 1;
184fcf3ce44SJohn Forte 			host_addr += bsize;
185fcf3ce44SJohn Forte 			dev_addr += bsize;
186fcf3ce44SJohn Forte 			bctl++;
187fcf3ce44SJohn Forte 			prev->bctl_next = bctl;
188fcf3ce44SJohn Forte 		}
189fcf3ce44SJohn Forte 		prev->bctl_next = NULL;
190fcf3ce44SJohn Forte 	}
191fcf3ce44SJohn Forte 
192fcf3ce44SJohn Forte 	return (QLT_SUCCESS);
193fcf3ce44SJohn Forte 
194fcf3ce44SJohn Forte dmem_failure_loop:;
195fcf3ce44SJohn Forte 	bc = bctl;
196fcf3ce44SJohn Forte 	while (bc) {
197fcf3ce44SJohn Forte 		stmf_free(bc->bctl_buf);
198fcf3ce44SJohn Forte 		bc = bc->bctl_next;
199fcf3ce44SJohn Forte 	}
200fcf3ce44SJohn Forte dmem_init_failed:;
201fcf3ce44SJohn Forte 	(void) ddi_dma_unbind_handle(p->dmem_dma_handle);
202fcf3ce44SJohn Forte addr_bind_handle_failed:;
203fcf3ce44SJohn Forte 	ddi_dma_mem_free(&p->dmem_acc_handle);
204fcf3ce44SJohn Forte mem_alloc_failed:;
205fcf3ce44SJohn Forte 	ddi_dma_free_handle(&p->dmem_dma_handle);
206fcf3ce44SJohn Forte alloc_handle_failed:;
207fcf3ce44SJohn Forte 	kmem_free(p->dmem_bctls_mem, p->dmem_nbufs * sizeof (qlt_dmem_bctl_t));
208fcf3ce44SJohn Forte 	mutex_destroy(&p->dmem_lock);
209fcf3ce44SJohn Forte alloc_bctl_failed:;
210fcf3ce44SJohn Forte 	if (--ndx >= 0) {
211fcf3ce44SJohn Forte 		p = qlt->dmem_buckets[ndx];
212fcf3ce44SJohn Forte 		bctl = p->dmem_bctl_free_list;
213fcf3ce44SJohn Forte 		goto dmem_failure_loop;
214fcf3ce44SJohn Forte 	}
215fcf3ce44SJohn Forte 	kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) +
216fcf3ce44SJohn Forte 	    ((sizeof (dmem_buckets)/sizeof (void *))
217fcf3ce44SJohn Forte 	    *sizeof (qlt_dmem_bucket_t)));
218fcf3ce44SJohn Forte 	qlt->dmem_buckets = NULL;
219fcf3ce44SJohn Forte 
220fcf3ce44SJohn Forte 	return (QLT_FAILURE);
221fcf3ce44SJohn Forte }
222fcf3ce44SJohn Forte 
223fcf3ce44SJohn Forte void
224*3fb517f7SJames Moore qlt_dma_handle_pool_init(qlt_state_t *qlt)
225*3fb517f7SJames Moore {
226*3fb517f7SJames Moore 	qlt_dma_handle_pool_t *pool;
227*3fb517f7SJames Moore 
228*3fb517f7SJames Moore 	pool = kmem_zalloc(sizeof (*pool), KM_SLEEP);
229*3fb517f7SJames Moore 	mutex_init(&pool->pool_lock, NULL, MUTEX_DRIVER, NULL);
230*3fb517f7SJames Moore 	qlt->qlt_dma_handle_pool = pool;
231*3fb517f7SJames Moore }
232*3fb517f7SJames Moore 
233*3fb517f7SJames Moore void
234*3fb517f7SJames Moore qlt_dma_handle_pool_fini(qlt_state_t *qlt)
235*3fb517f7SJames Moore {
236*3fb517f7SJames Moore 	qlt_dma_handle_pool_t	*pool;
237*3fb517f7SJames Moore 	qlt_dma_handle_t	*handle, *next_handle;
238*3fb517f7SJames Moore 
239*3fb517f7SJames Moore 	pool = qlt->qlt_dma_handle_pool;
240*3fb517f7SJames Moore 	mutex_enter(&pool->pool_lock);
241*3fb517f7SJames Moore 	/*
242*3fb517f7SJames Moore 	 * XXX Need to wait for free == total elements
243*3fb517f7SJames Moore 	 * XXX Not sure how other driver shutdown stuff is done.
244*3fb517f7SJames Moore 	 */
245*3fb517f7SJames Moore 	ASSERT(pool->num_free == pool->num_total);
246*3fb517f7SJames Moore 	if (pool->num_free != pool->num_total)
247*3fb517f7SJames Moore 		cmn_err(CE_WARN,
248*3fb517f7SJames Moore 		    "num_free %d != num_total %d\n",
249*3fb517f7SJames Moore 		    pool->num_free, pool->num_total);
250*3fb517f7SJames Moore 	handle = pool->free_list;
251*3fb517f7SJames Moore 	while (handle) {
252*3fb517f7SJames Moore 		next_handle = handle->next;
253*3fb517f7SJames Moore 		kmem_free(handle, sizeof (*handle));
254*3fb517f7SJames Moore 		handle = next_handle;
255*3fb517f7SJames Moore 	}
256*3fb517f7SJames Moore 	qlt->qlt_dma_handle_pool = NULL;
257*3fb517f7SJames Moore 	mutex_destroy(&pool->pool_lock);
258*3fb517f7SJames Moore 	kmem_free(pool, sizeof (*pool));
259*3fb517f7SJames Moore }
260*3fb517f7SJames Moore 
261*3fb517f7SJames Moore void
262fcf3ce44SJohn Forte qlt_dmem_fini(qlt_state_t *qlt)
263fcf3ce44SJohn Forte {
264fcf3ce44SJohn Forte 	qlt_dmem_bucket_t *p;
265fcf3ce44SJohn Forte 	qlt_dmem_bctl_t *bctl;
266fcf3ce44SJohn Forte 	int ndx;
267fcf3ce44SJohn Forte 
268fcf3ce44SJohn Forte 	for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) {
269fcf3ce44SJohn Forte 		bctl = p->dmem_bctl_free_list;
270fcf3ce44SJohn Forte 		while (bctl) {
271fcf3ce44SJohn Forte 			stmf_free(bctl->bctl_buf);
272fcf3ce44SJohn Forte 			bctl = bctl->bctl_next;
273fcf3ce44SJohn Forte 		}
274fcf3ce44SJohn Forte 		bctl = p->dmem_bctl_free_list;
275fcf3ce44SJohn Forte 		(void) ddi_dma_unbind_handle(p->dmem_dma_handle);
276fcf3ce44SJohn Forte 		ddi_dma_mem_free(&p->dmem_acc_handle);
277fcf3ce44SJohn Forte 		ddi_dma_free_handle(&p->dmem_dma_handle);
278fcf3ce44SJohn Forte 		kmem_free(p->dmem_bctls_mem,
279fcf3ce44SJohn Forte 		    p->dmem_nbufs * sizeof (qlt_dmem_bctl_t));
280fcf3ce44SJohn Forte 		mutex_destroy(&p->dmem_lock);
281fcf3ce44SJohn Forte 	}
282fcf3ce44SJohn Forte 	kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) +
283fcf3ce44SJohn Forte 	    (((sizeof (dmem_buckets)/sizeof (void *))-1)*
284fcf3ce44SJohn Forte 	    sizeof (qlt_dmem_bucket_t)));
285fcf3ce44SJohn Forte 	qlt->dmem_buckets = NULL;
286fcf3ce44SJohn Forte }
287fcf3ce44SJohn Forte 
288fcf3ce44SJohn Forte stmf_data_buf_t *
289fcf3ce44SJohn Forte qlt_dmem_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
290fcf3ce44SJohn Forte     uint32_t flags)
291fcf3ce44SJohn Forte {
292fcf3ce44SJohn Forte 	return (qlt_i_dmem_alloc((qlt_state_t *)
293fcf3ce44SJohn Forte 	    port->port_fca_private, size, pminsize,
294fcf3ce44SJohn Forte 	    flags));
295fcf3ce44SJohn Forte }
296fcf3ce44SJohn Forte 
297fcf3ce44SJohn Forte /* ARGSUSED */
298fcf3ce44SJohn Forte stmf_data_buf_t *
299fcf3ce44SJohn Forte qlt_i_dmem_alloc(qlt_state_t *qlt, uint32_t size, uint32_t *pminsize,
300fcf3ce44SJohn Forte     uint32_t flags)
301fcf3ce44SJohn Forte {
302fcf3ce44SJohn Forte 	qlt_dmem_bucket_t	*p;
303fcf3ce44SJohn Forte 	qlt_dmem_bctl_t 	*bctl;
304fcf3ce44SJohn Forte 	int			i;
3053f3ce7b9SDaniel Beauregard 	uint32_t		size_possible = 0;
306fcf3ce44SJohn Forte 
3073f3ce7b9SDaniel Beauregard 	if (size > QLT_DMEM_MAX_BUF_SIZE) {
3083f3ce7b9SDaniel Beauregard 		goto qlt_try_partial_alloc;
3093f3ce7b9SDaniel Beauregard 	}
310fcf3ce44SJohn Forte 
3113f3ce7b9SDaniel Beauregard 	/* 1st try to do a full allocation */
312fcf3ce44SJohn Forte 	for (i = 0; (p = qlt->dmem_buckets[i]) != NULL; i++) {
313a2255df3SDaniel Beauregard 		if (p->dmem_buf_size >= size) {
314a2255df3SDaniel Beauregard 			if (p->dmem_nbufs_free) {
315fcf3ce44SJohn Forte 				mutex_enter(&p->dmem_lock);
316fcf3ce44SJohn Forte 				bctl = p->dmem_bctl_free_list;
317fcf3ce44SJohn Forte 				if (bctl == NULL) {
318fcf3ce44SJohn Forte 					mutex_exit(&p->dmem_lock);
319fcf3ce44SJohn Forte 					continue;
320fcf3ce44SJohn Forte 				}
321a2255df3SDaniel Beauregard 				p->dmem_bctl_free_list =
322a2255df3SDaniel Beauregard 				    bctl->bctl_next;
323fcf3ce44SJohn Forte 				p->dmem_nbufs_free--;
324a2255df3SDaniel Beauregard 				qlt->qlt_bufref[i]++;
325fcf3ce44SJohn Forte 				mutex_exit(&p->dmem_lock);
326fcf3ce44SJohn Forte 				bctl->bctl_buf->db_data_size = size;
327fcf3ce44SJohn Forte 				return (bctl->bctl_buf);
328fcf3ce44SJohn Forte 			} else {
329a2255df3SDaniel Beauregard 				qlt->qlt_bumpbucket++;
330fcf3ce44SJohn Forte 			}
331fcf3ce44SJohn Forte 		}
332fcf3ce44SJohn Forte 	}
3333f3ce7b9SDaniel Beauregard 
3343f3ce7b9SDaniel Beauregard qlt_try_partial_alloc:
3353f3ce7b9SDaniel Beauregard 
3363f3ce7b9SDaniel Beauregard 	qlt->qlt_pmintry++;
3373f3ce7b9SDaniel Beauregard 
3383f3ce7b9SDaniel Beauregard 	/* Now go from high to low */
3393f3ce7b9SDaniel Beauregard 	for (i = QLT_DMEM_NBUCKETS - 1; i >= 0; i--) {
3403f3ce7b9SDaniel Beauregard 		p = qlt->dmem_buckets[i];
3413f3ce7b9SDaniel Beauregard 		if (p->dmem_nbufs_free == 0)
3423f3ce7b9SDaniel Beauregard 			continue;
3433f3ce7b9SDaniel Beauregard 		if (!size_possible) {
3443f3ce7b9SDaniel Beauregard 			size_possible = p->dmem_buf_size;
345fcf3ce44SJohn Forte 		}
3463f3ce7b9SDaniel Beauregard 		if (*pminsize > p->dmem_buf_size) {
3473f3ce7b9SDaniel Beauregard 			/* At this point we know the request is failing. */
3483f3ce7b9SDaniel Beauregard 			if (size_possible) {
3493f3ce7b9SDaniel Beauregard 				/*
3503f3ce7b9SDaniel Beauregard 				 * This caller is asking too much. We already
3513f3ce7b9SDaniel Beauregard 				 * know what we can give, so get out.
3523f3ce7b9SDaniel Beauregard 				 */
3533f3ce7b9SDaniel Beauregard 				break;
354a2255df3SDaniel Beauregard 			} else {
3553f3ce7b9SDaniel Beauregard 				/*
3563f3ce7b9SDaniel Beauregard 				 * Lets continue to find out and tell what
3573f3ce7b9SDaniel Beauregard 				 * we can give.
3583f3ce7b9SDaniel Beauregard 				 */
3593f3ce7b9SDaniel Beauregard 				continue;
360a2255df3SDaniel Beauregard 			}
3613f3ce7b9SDaniel Beauregard 		}
3623f3ce7b9SDaniel Beauregard 		mutex_enter(&p->dmem_lock);
3633f3ce7b9SDaniel Beauregard 		if (*pminsize <= p->dmem_buf_size) {
3643f3ce7b9SDaniel Beauregard 			bctl = p->dmem_bctl_free_list;
3653f3ce7b9SDaniel Beauregard 			if (bctl == NULL) {
3663f3ce7b9SDaniel Beauregard 				/* Someone took it. */
3673f3ce7b9SDaniel Beauregard 				size_possible = 0;
3683f3ce7b9SDaniel Beauregard 				mutex_exit(&p->dmem_lock);
3693f3ce7b9SDaniel Beauregard 				continue;
3703f3ce7b9SDaniel Beauregard 			}
3713f3ce7b9SDaniel Beauregard 			p->dmem_bctl_free_list = bctl->bctl_next;
3723f3ce7b9SDaniel Beauregard 			p->dmem_nbufs_free--;
3733f3ce7b9SDaniel Beauregard 			mutex_exit(&p->dmem_lock);
3743f3ce7b9SDaniel Beauregard 			bctl->bctl_buf->db_data_size = p->dmem_buf_size;
3753f3ce7b9SDaniel Beauregard 			qlt->qlt_pmin_ok++;
3763f3ce7b9SDaniel Beauregard 			return (bctl->bctl_buf);
3773f3ce7b9SDaniel Beauregard 		}
3783f3ce7b9SDaniel Beauregard 	}
3793f3ce7b9SDaniel Beauregard 
3803f3ce7b9SDaniel Beauregard 	*pminsize = size_possible;
381a2255df3SDaniel Beauregard 
382fcf3ce44SJohn Forte 	return (NULL);
383fcf3ce44SJohn Forte }
384fcf3ce44SJohn Forte 
385fcf3ce44SJohn Forte /* ARGSUSED */
386fcf3ce44SJohn Forte void
387fcf3ce44SJohn Forte qlt_i_dmem_free(qlt_state_t *qlt, stmf_data_buf_t *dbuf)
388fcf3ce44SJohn Forte {
389fcf3ce44SJohn Forte 	qlt_dmem_free(0, dbuf);
390fcf3ce44SJohn Forte }
391fcf3ce44SJohn Forte 
392fcf3ce44SJohn Forte /* ARGSUSED */
393fcf3ce44SJohn Forte void
394fcf3ce44SJohn Forte qlt_dmem_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
395fcf3ce44SJohn Forte {
396*3fb517f7SJames Moore 	qlt_dmem_bctl_t		*bctl;
397*3fb517f7SJames Moore 	qlt_dmem_bucket_t	*p;
398fcf3ce44SJohn Forte 
399*3fb517f7SJames Moore 	ASSERT((dbuf->db_flags & DB_LU_DATA_BUF) == 0);
400*3fb517f7SJames Moore 
401*3fb517f7SJames Moore 	bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
402*3fb517f7SJames Moore 	p = bctl->bctl_bucket;
403fcf3ce44SJohn Forte 	mutex_enter(&p->dmem_lock);
404fcf3ce44SJohn Forte 	bctl->bctl_next = p->dmem_bctl_free_list;
405fcf3ce44SJohn Forte 	p->dmem_bctl_free_list = bctl;
406fcf3ce44SJohn Forte 	p->dmem_nbufs_free++;
407fcf3ce44SJohn Forte 	mutex_exit(&p->dmem_lock);
408fcf3ce44SJohn Forte }
409fcf3ce44SJohn Forte 
410fcf3ce44SJohn Forte void
411fcf3ce44SJohn Forte qlt_dmem_dma_sync(stmf_data_buf_t *dbuf, uint_t sync_type)
412fcf3ce44SJohn Forte {
413*3fb517f7SJames Moore 	qlt_dmem_bctl_t		*bctl;
414*3fb517f7SJames Moore 	qlt_dma_sgl_t		*qsgl;
415*3fb517f7SJames Moore 	qlt_dmem_bucket_t	*p;
416*3fb517f7SJames Moore 	qlt_dma_handle_t	*th;
417*3fb517f7SJames Moore 	int			rv;
418fcf3ce44SJohn Forte 
419*3fb517f7SJames Moore 	if (dbuf->db_flags & DB_LU_DATA_BUF) {
420*3fb517f7SJames Moore 		/*
421*3fb517f7SJames Moore 		 * go through ddi handle list
422*3fb517f7SJames Moore 		 */
423*3fb517f7SJames Moore 		qsgl = (qlt_dma_sgl_t *)dbuf->db_port_private;
424*3fb517f7SJames Moore 		th = qsgl->handle_list;
425*3fb517f7SJames Moore 		while (th) {
426*3fb517f7SJames Moore 			rv = ddi_dma_sync(th->dma_handle,
427*3fb517f7SJames Moore 			    0, 0, sync_type);
428*3fb517f7SJames Moore 			if (rv != DDI_SUCCESS) {
429*3fb517f7SJames Moore 				cmn_err(CE_WARN, "ddi_dma_sync FAILED\n");
430*3fb517f7SJames Moore 			}
431*3fb517f7SJames Moore 			th = th->next;
432*3fb517f7SJames Moore 		}
433*3fb517f7SJames Moore 	} else {
434*3fb517f7SJames Moore 		bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
435*3fb517f7SJames Moore 		p = bctl->bctl_bucket;
436c4ddbbe1SDaniel Beauregard 		(void) ddi_dma_sync(p->dmem_dma_handle, (off_t)
437fcf3ce44SJohn Forte 		    (bctl->bctl_dev_addr - p->dmem_dev_addr),
438fcf3ce44SJohn Forte 		    dbuf->db_data_size, sync_type);
439fcf3ce44SJohn Forte 	}
440*3fb517f7SJames Moore }
441*3fb517f7SJames Moore 
442*3fb517f7SJames Moore /*
443*3fb517f7SJames Moore  * A very lite version of ddi_dma_addr_bind_handle()
444*3fb517f7SJames Moore  */
445*3fb517f7SJames Moore uint64_t
446*3fb517f7SJames Moore qlt_ddi_vtop(caddr_t vaddr)
447*3fb517f7SJames Moore {
448*3fb517f7SJames Moore 	uint64_t offset, paddr;
449*3fb517f7SJames Moore 	pfn_t pfn;
450*3fb517f7SJames Moore 
451*3fb517f7SJames Moore 	pfn = hat_getpfnum(kas.a_hat, vaddr);
452*3fb517f7SJames Moore 	ASSERT(pfn != PFN_INVALID && pfn != PFN_SUSPENDED);
453*3fb517f7SJames Moore 	offset = ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
454*3fb517f7SJames Moore 	paddr = mmu_ptob(pfn);
455*3fb517f7SJames Moore 	return (paddr+offset);
456*3fb517f7SJames Moore }
457*3fb517f7SJames Moore 
458*3fb517f7SJames Moore static ddi_dma_attr_t 	qlt_sgl_dma_attr = {
459*3fb517f7SJames Moore 	DMA_ATTR_V0,		/* dma_attr_version */
460*3fb517f7SJames Moore 	0,				/* low DMA address range */
461*3fb517f7SJames Moore 	0xffffffffffffffff,		/* high DMA address range */
462*3fb517f7SJames Moore 	0xffffffff,			/* DMA counter register */
463*3fb517f7SJames Moore 	64,				/* DMA address alignment */
464*3fb517f7SJames Moore 	0xff,			/* DMA burstsizes */
465*3fb517f7SJames Moore 	1,				/* min effective DMA size */
466*3fb517f7SJames Moore 	0xffffffff,			/* max DMA xfer size */
467*3fb517f7SJames Moore 	0xffffffff,			/* segment boundary */
468*3fb517f7SJames Moore 	QLT_DMA_SG_LIST_LENGTH,	/* s/g list length */
469*3fb517f7SJames Moore 	1,				/* granularity of device */
470*3fb517f7SJames Moore 	0				/* DMA transfer flags */
471*3fb517f7SJames Moore };
472*3fb517f7SJames Moore 
473*3fb517f7SJames Moore /*
474*3fb517f7SJames Moore  * Allocate a qlt_dma_handle container and fill it with a ddi_dma_handle
475*3fb517f7SJames Moore  */
476*3fb517f7SJames Moore static qlt_dma_handle_t *
477*3fb517f7SJames Moore qlt_dma_alloc_handle(qlt_state_t *qlt)
478*3fb517f7SJames Moore {
479*3fb517f7SJames Moore 	ddi_dma_handle_t ddi_handle;
480*3fb517f7SJames Moore 	qlt_dma_handle_t *qlt_handle;
481*3fb517f7SJames Moore 	int rv;
482*3fb517f7SJames Moore 
483*3fb517f7SJames Moore 	rv = ddi_dma_alloc_handle(qlt->dip, &qlt_sgl_dma_attr,
484*3fb517f7SJames Moore 	    DDI_DMA_SLEEP, 0, &ddi_handle);
485*3fb517f7SJames Moore 	if (rv != DDI_SUCCESS) {
486*3fb517f7SJames Moore 		EL(qlt, "ddi_dma_alloc_handle status=%xh\n", rv);
487*3fb517f7SJames Moore 		return (NULL);
488*3fb517f7SJames Moore 	}
489*3fb517f7SJames Moore 	qlt_handle = kmem_zalloc(sizeof (qlt_dma_handle_t), KM_SLEEP);
490*3fb517f7SJames Moore 	qlt_handle->dma_handle = ddi_handle;
491*3fb517f7SJames Moore 	return (qlt_handle);
492*3fb517f7SJames Moore }
493*3fb517f7SJames Moore 
494*3fb517f7SJames Moore /*
495*3fb517f7SJames Moore  * Allocate a list of qlt_dma_handle containers from the free list
496*3fb517f7SJames Moore  */
497*3fb517f7SJames Moore static qlt_dma_handle_t *
498*3fb517f7SJames Moore qlt_dma_alloc_handle_list(qlt_state_t *qlt, int handle_count)
499*3fb517f7SJames Moore {
500*3fb517f7SJames Moore 	qlt_dma_handle_pool_t	*pool;
501*3fb517f7SJames Moore 	qlt_dma_handle_t	*tmp_handle, *first_handle, *last_handle;
502*3fb517f7SJames Moore 	int i;
503*3fb517f7SJames Moore 
504*3fb517f7SJames Moore 	/*
505*3fb517f7SJames Moore 	 * Make sure the free list can satisfy the request.
506*3fb517f7SJames Moore 	 * Once the free list is primed, it should satisfy most requests.
507*3fb517f7SJames Moore 	 * XXX Should there be a limit on pool size?
508*3fb517f7SJames Moore 	 */
509*3fb517f7SJames Moore 	pool = qlt->qlt_dma_handle_pool;
510*3fb517f7SJames Moore 	mutex_enter(&pool->pool_lock);
511*3fb517f7SJames Moore 	while (handle_count > pool->num_free) {
512*3fb517f7SJames Moore 		mutex_exit(&pool->pool_lock);
513*3fb517f7SJames Moore 		if ((tmp_handle = qlt_dma_alloc_handle(qlt)) == NULL)
514*3fb517f7SJames Moore 			return (NULL);
515*3fb517f7SJames Moore 		mutex_enter(&pool->pool_lock);
516*3fb517f7SJames Moore 		tmp_handle->next = pool->free_list;
517*3fb517f7SJames Moore 		pool->free_list = tmp_handle;
518*3fb517f7SJames Moore 		pool->num_free++;
519*3fb517f7SJames Moore 		pool->num_total++;
520*3fb517f7SJames Moore 	}
521*3fb517f7SJames Moore 
522*3fb517f7SJames Moore 	/*
523*3fb517f7SJames Moore 	 * The free list lock is held and the list is large enough to
524*3fb517f7SJames Moore 	 * satisfy this request. Run down the freelist and snip off
525*3fb517f7SJames Moore 	 * the number of elements needed for this request.
526*3fb517f7SJames Moore 	 */
527*3fb517f7SJames Moore 	first_handle = pool->free_list;
528*3fb517f7SJames Moore 	tmp_handle = first_handle;
529*3fb517f7SJames Moore 	for (i = 0; i < handle_count; i++) {
530*3fb517f7SJames Moore 		last_handle = tmp_handle;
531*3fb517f7SJames Moore 		tmp_handle = tmp_handle->next;
532*3fb517f7SJames Moore 	}
533*3fb517f7SJames Moore 	pool->free_list = tmp_handle;
534*3fb517f7SJames Moore 	pool->num_free -= handle_count;
535*3fb517f7SJames Moore 	mutex_exit(&pool->pool_lock);
536*3fb517f7SJames Moore 	last_handle->next = NULL;	/* sanity */
537*3fb517f7SJames Moore 	return (first_handle);
538*3fb517f7SJames Moore }
539*3fb517f7SJames Moore 
540*3fb517f7SJames Moore /*
541*3fb517f7SJames Moore  * Return a list of qlt_dma_handle containers to the free list.
542*3fb517f7SJames Moore  */
543*3fb517f7SJames Moore static void
544*3fb517f7SJames Moore qlt_dma_free_handles(qlt_state_t *qlt, qlt_dma_handle_t *first_handle)
545*3fb517f7SJames Moore {
546*3fb517f7SJames Moore 	qlt_dma_handle_pool_t *pool;
547*3fb517f7SJames Moore 	qlt_dma_handle_t *tmp_handle, *last_handle;
548*3fb517f7SJames Moore 	int rv, handle_count;
549*3fb517f7SJames Moore 
550*3fb517f7SJames Moore 	/*
551*3fb517f7SJames Moore 	 * Traverse the list and unbind the handles
552*3fb517f7SJames Moore 	 */
553*3fb517f7SJames Moore 	ASSERT(first_handle);
554*3fb517f7SJames Moore 	tmp_handle = first_handle;
555*3fb517f7SJames Moore 	handle_count = 0;
556*3fb517f7SJames Moore 	while (tmp_handle != NULL) {
557*3fb517f7SJames Moore 		last_handle = tmp_handle;
558*3fb517f7SJames Moore 		/*
559*3fb517f7SJames Moore 		 * If the handle is bound, unbind the handle so it can be
560*3fb517f7SJames Moore 		 * reused. It may not be bound if there was a bind failure.
561*3fb517f7SJames Moore 		 */
562*3fb517f7SJames Moore 		if (tmp_handle->num_cookies != 0) {
563*3fb517f7SJames Moore 			rv = ddi_dma_unbind_handle(tmp_handle->dma_handle);
564*3fb517f7SJames Moore 			ASSERT(rv == DDI_SUCCESS);
565*3fb517f7SJames Moore 			tmp_handle->num_cookies = 0;
566*3fb517f7SJames Moore 			tmp_handle->num_cookies_fetched = 0;
567*3fb517f7SJames Moore 		}
568*3fb517f7SJames Moore 		tmp_handle = tmp_handle->next;
569*3fb517f7SJames Moore 		handle_count++;
570*3fb517f7SJames Moore 	}
571*3fb517f7SJames Moore 	/*
572*3fb517f7SJames Moore 	 * Insert this list into the free list
573*3fb517f7SJames Moore 	 */
574*3fb517f7SJames Moore 	pool = qlt->qlt_dma_handle_pool;
575*3fb517f7SJames Moore 	mutex_enter(&pool->pool_lock);
576*3fb517f7SJames Moore 	last_handle->next = pool->free_list;
577*3fb517f7SJames Moore 	pool->free_list = first_handle;
578*3fb517f7SJames Moore 	pool->num_free += handle_count;
579*3fb517f7SJames Moore 	mutex_exit(&pool->pool_lock);
580*3fb517f7SJames Moore }
581*3fb517f7SJames Moore 
582*3fb517f7SJames Moore /*
583*3fb517f7SJames Moore  * cookies produced by mapping this dbuf
584*3fb517f7SJames Moore  */
585*3fb517f7SJames Moore uint16_t
586*3fb517f7SJames Moore qlt_get_cookie_count(stmf_data_buf_t *dbuf)
587*3fb517f7SJames Moore {
588*3fb517f7SJames Moore 	qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
589*3fb517f7SJames Moore 
590*3fb517f7SJames Moore 	ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
591*3fb517f7SJames Moore 	return (qsgl->cookie_count);
592*3fb517f7SJames Moore }
593*3fb517f7SJames Moore 
594*3fb517f7SJames Moore ddi_dma_cookie_t
595*3fb517f7SJames Moore *qlt_get_cookie_array(stmf_data_buf_t *dbuf)
596*3fb517f7SJames Moore {
597*3fb517f7SJames Moore 	qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
598*3fb517f7SJames Moore 
599*3fb517f7SJames Moore 	ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
600*3fb517f7SJames Moore 
601*3fb517f7SJames Moore 	if (qsgl->cookie_prefetched)
602*3fb517f7SJames Moore 		return (&qsgl->cookie[0]);
603*3fb517f7SJames Moore 	else
604*3fb517f7SJames Moore 		return (NULL);
605*3fb517f7SJames Moore }
606*3fb517f7SJames Moore 
607*3fb517f7SJames Moore /*
608*3fb517f7SJames Moore  * Wrapper around ddi_dma_nextcookie that hides the ddi_dma_handle usage.
609*3fb517f7SJames Moore  */
610*3fb517f7SJames Moore void
611*3fb517f7SJames Moore qlt_ddi_dma_nextcookie(stmf_data_buf_t *dbuf, ddi_dma_cookie_t *cookiep)
612*3fb517f7SJames Moore {
613*3fb517f7SJames Moore 	qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
614*3fb517f7SJames Moore 
615*3fb517f7SJames Moore 	ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
616*3fb517f7SJames Moore 
617*3fb517f7SJames Moore 	if (qsgl->cookie_prefetched) {
618*3fb517f7SJames Moore 		ASSERT(qsgl->cookie_next_fetch < qsgl->cookie_count);
619*3fb517f7SJames Moore 		*cookiep = qsgl->cookie[qsgl->cookie_next_fetch++];
620*3fb517f7SJames Moore 	} else {
621*3fb517f7SJames Moore 		qlt_dma_handle_t *fetch;
622*3fb517f7SJames Moore 		qlt_dma_handle_t *FETCH_DONE = (qlt_dma_handle_t *)0xbad;
623*3fb517f7SJames Moore 
624*3fb517f7SJames Moore 		ASSERT(qsgl->handle_list != NULL);
625*3fb517f7SJames Moore 		ASSERT(qsgl->handle_next_fetch != FETCH_DONE);
626*3fb517f7SJames Moore 
627*3fb517f7SJames Moore 		fetch = qsgl->handle_next_fetch;
628*3fb517f7SJames Moore 		if (fetch->num_cookies_fetched == 0) {
629*3fb517f7SJames Moore 			*cookiep = fetch->first_cookie;
630*3fb517f7SJames Moore 		} else {
631*3fb517f7SJames Moore 			ddi_dma_nextcookie(fetch->dma_handle, cookiep);
632*3fb517f7SJames Moore 		}
633*3fb517f7SJames Moore 		if (++fetch->num_cookies_fetched == fetch->num_cookies) {
634*3fb517f7SJames Moore 			if (fetch->next == NULL)
635*3fb517f7SJames Moore 				qsgl->handle_next_fetch = FETCH_DONE;
636*3fb517f7SJames Moore 			else
637*3fb517f7SJames Moore 				qsgl->handle_next_fetch = fetch->next;
638*3fb517f7SJames Moore 		}
639*3fb517f7SJames Moore 	}
640*3fb517f7SJames Moore }
641*3fb517f7SJames Moore 
642*3fb517f7SJames Moore /*
643*3fb517f7SJames Moore  * Set this flag to fetch the DDI dma cookies from the handles here and
644*3fb517f7SJames Moore  * store them in the port private area of the dbuf. This will allow
645*3fb517f7SJames Moore  * faster access to the cookies in qlt_xfer_scsi_data() at the expense of
646*3fb517f7SJames Moore  * an extra copy. If the qlt->req_lock is hot, this may help.
647*3fb517f7SJames Moore  */
648*3fb517f7SJames Moore int qlt_sgl_prefetch = 0;
649*3fb517f7SJames Moore 
650*3fb517f7SJames Moore /*ARGSUSED*/
651*3fb517f7SJames Moore stmf_status_t
652*3fb517f7SJames Moore qlt_dma_setup_dbuf(fct_local_port_t *port, stmf_data_buf_t *dbuf,
653*3fb517f7SJames Moore     uint32_t flags)
654*3fb517f7SJames Moore {
655*3fb517f7SJames Moore 	qlt_state_t		*qlt = port->port_fca_private;
656*3fb517f7SJames Moore 	qlt_dma_sgl_t		*qsgl;
657*3fb517f7SJames Moore 	struct stmf_sglist_ent	*sglp;
658*3fb517f7SJames Moore 	qlt_dma_handle_t	*handle_list, *th;
659*3fb517f7SJames Moore 	int			i, rv;
660*3fb517f7SJames Moore 	ddi_dma_cookie_t	*cookie_p;
661*3fb517f7SJames Moore 	int			cookie_count, numbufs;
662*3fb517f7SJames Moore 	int			prefetch;
663*3fb517f7SJames Moore 	size_t			qsize;
664*3fb517f7SJames Moore 
665*3fb517f7SJames Moore 	/*
666*3fb517f7SJames Moore 	 * psuedo code:
667*3fb517f7SJames Moore 	 * get dma handle list from cache - one per sglist entry
668*3fb517f7SJames Moore 	 * foreach sglist entry
669*3fb517f7SJames Moore 	 *	bind dma handle to sglist vaddr
670*3fb517f7SJames Moore 	 * allocate space for DMA state to store in db_port_private
671*3fb517f7SJames Moore 	 * fill in port private object
672*3fb517f7SJames Moore 	 * if prefetching
673*3fb517f7SJames Moore 	 *	move all dma cookies into db_port_private
674*3fb517f7SJames Moore 	 */
675*3fb517f7SJames Moore 	dbuf->db_port_private = NULL;
676*3fb517f7SJames Moore 	numbufs = dbuf->db_sglist_length;
677*3fb517f7SJames Moore 	handle_list = qlt_dma_alloc_handle_list(qlt, numbufs);
678*3fb517f7SJames Moore 	if (handle_list == NULL) {
679*3fb517f7SJames Moore 		EL(qlt, "handle_list==NULL\n");
680*3fb517f7SJames Moore 		return (STMF_FAILURE);
681*3fb517f7SJames Moore 	}
682*3fb517f7SJames Moore 	/*
683*3fb517f7SJames Moore 	 * Loop through sglist and bind each entry to a handle
684*3fb517f7SJames Moore 	 */
685*3fb517f7SJames Moore 	th = handle_list;
686*3fb517f7SJames Moore 	sglp = &dbuf->db_sglist[0];
687*3fb517f7SJames Moore 	cookie_count = 0;
688*3fb517f7SJames Moore 	for (i = 0; i < numbufs; i++, sglp++) {
689*3fb517f7SJames Moore 
690*3fb517f7SJames Moore 		/*
691*3fb517f7SJames Moore 		 * Bind this sgl entry to a DDI dma handle
692*3fb517f7SJames Moore 		 */
693*3fb517f7SJames Moore 		if ((rv = ddi_dma_addr_bind_handle(
694*3fb517f7SJames Moore 		    th->dma_handle,
695*3fb517f7SJames Moore 		    NULL,
696*3fb517f7SJames Moore 		    (caddr_t)(sglp->seg_addr),
697*3fb517f7SJames Moore 		    (size_t)sglp->seg_length,
698*3fb517f7SJames Moore 		    DDI_DMA_RDWR | DDI_DMA_STREAMING,
699*3fb517f7SJames Moore 		    DDI_DMA_DONTWAIT,
700*3fb517f7SJames Moore 		    NULL,
701*3fb517f7SJames Moore 		    &th->first_cookie,
702*3fb517f7SJames Moore 		    &th->num_cookies)) != DDI_DMA_MAPPED) {
703*3fb517f7SJames Moore 			cmn_err(CE_NOTE, "ddi_dma_addr_bind_handle %d", rv);
704*3fb517f7SJames Moore 			qlt_dma_free_handles(qlt, handle_list);
705*3fb517f7SJames Moore 			return (STMF_FAILURE);
706*3fb517f7SJames Moore 		}
707*3fb517f7SJames Moore 
708*3fb517f7SJames Moore 		/*
709*3fb517f7SJames Moore 		 * Add to total cookie count
710*3fb517f7SJames Moore 		 */
711*3fb517f7SJames Moore 		cookie_count += th->num_cookies;
712*3fb517f7SJames Moore 		if (cookie_count > QLT_DMA_SG_LIST_LENGTH) {
713*3fb517f7SJames Moore 			/*
714*3fb517f7SJames Moore 			 * Request exceeds HBA limit
715*3fb517f7SJames Moore 			 */
716*3fb517f7SJames Moore 			qlt_dma_free_handles(qlt, handle_list);
717*3fb517f7SJames Moore 			return (STMF_FAILURE);
718*3fb517f7SJames Moore 		}
719*3fb517f7SJames Moore 		/* move to next ddi_dma_handle */
720*3fb517f7SJames Moore 		th = th->next;
721*3fb517f7SJames Moore 	}
722*3fb517f7SJames Moore 
723*3fb517f7SJames Moore 	/*
724*3fb517f7SJames Moore 	 * Allocate our port private object for DMA mapping state.
725*3fb517f7SJames Moore 	 */
726*3fb517f7SJames Moore 	prefetch =  qlt_sgl_prefetch;
727*3fb517f7SJames Moore 	qsize = sizeof (qlt_dma_sgl_t);
728*3fb517f7SJames Moore 	if (prefetch) {
729*3fb517f7SJames Moore 		/* one extra ddi_dma_cookie allocated for alignment padding */
730*3fb517f7SJames Moore 		qsize += cookie_count * sizeof (ddi_dma_cookie_t);
731*3fb517f7SJames Moore 	}
732*3fb517f7SJames Moore 	qsgl = kmem_alloc(qsize, KM_SLEEP);
733*3fb517f7SJames Moore 	/*
734*3fb517f7SJames Moore 	 * Fill in the sgl
735*3fb517f7SJames Moore 	 */
736*3fb517f7SJames Moore 	dbuf->db_port_private = qsgl;
737*3fb517f7SJames Moore 	qsgl->qsize = qsize;
738*3fb517f7SJames Moore 	qsgl->handle_count = dbuf->db_sglist_length;
739*3fb517f7SJames Moore 	qsgl->cookie_prefetched = prefetch;
740*3fb517f7SJames Moore 	qsgl->cookie_count = cookie_count;
741*3fb517f7SJames Moore 	qsgl->cookie_next_fetch = 0;
742*3fb517f7SJames Moore 	qsgl->handle_list = handle_list;
743*3fb517f7SJames Moore 	qsgl->handle_next_fetch = handle_list;
744*3fb517f7SJames Moore 	if (prefetch) {
745*3fb517f7SJames Moore 		/*
746*3fb517f7SJames Moore 		 * traverse handle list and move cookies to db_port_private
747*3fb517f7SJames Moore 		 */
748*3fb517f7SJames Moore 		th = handle_list;
749*3fb517f7SJames Moore 		cookie_p = &qsgl->cookie[0];
750*3fb517f7SJames Moore 		for (i = 0; i < numbufs; i++) {
751*3fb517f7SJames Moore 			uint_t cc = th->num_cookies;
752*3fb517f7SJames Moore 
753*3fb517f7SJames Moore 			*cookie_p++ = th->first_cookie;
754*3fb517f7SJames Moore 			while (--cc > 0) {
755*3fb517f7SJames Moore 				ddi_dma_nextcookie(th->dma_handle, cookie_p++);
756*3fb517f7SJames Moore 			}
757*3fb517f7SJames Moore 			th->num_cookies_fetched = th->num_cookies;
758*3fb517f7SJames Moore 			th = th->next;
759*3fb517f7SJames Moore 		}
760*3fb517f7SJames Moore 	}
761*3fb517f7SJames Moore 
762*3fb517f7SJames Moore 	return (STMF_SUCCESS);
763*3fb517f7SJames Moore }
764*3fb517f7SJames Moore 
765*3fb517f7SJames Moore void
766*3fb517f7SJames Moore qlt_dma_teardown_dbuf(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
767*3fb517f7SJames Moore {
768*3fb517f7SJames Moore 	qlt_state_t		*qlt = fds->fds_fca_private;
769*3fb517f7SJames Moore 	qlt_dma_sgl_t		*qsgl = dbuf->db_port_private;
770*3fb517f7SJames Moore 
771*3fb517f7SJames Moore 	ASSERT(qlt);
772*3fb517f7SJames Moore 	ASSERT(qsgl);
773*3fb517f7SJames Moore 	ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
774*3fb517f7SJames Moore 
775*3fb517f7SJames Moore 	/*
776*3fb517f7SJames Moore 	 * unbind and free the dma handles
777*3fb517f7SJames Moore 	 */
778*3fb517f7SJames Moore 	if (qsgl->handle_list) {
779*3fb517f7SJames Moore 		/* go through ddi handle list */
780*3fb517f7SJames Moore 		qlt_dma_free_handles(qlt, qsgl->handle_list);
781*3fb517f7SJames Moore 	}
782*3fb517f7SJames Moore 	kmem_free(qsgl, qsgl->qsize);
783*3fb517f7SJames Moore }
784*3fb517f7SJames Moore 
785*3fb517f7SJames Moore uint8_t
786*3fb517f7SJames Moore qlt_get_iocb_count(uint32_t cookie_count)
787*3fb517f7SJames Moore {
788*3fb517f7SJames Moore 	uint32_t	cnt, cont_segs;
789*3fb517f7SJames Moore 	uint8_t		iocb_count;
790*3fb517f7SJames Moore 
791*3fb517f7SJames Moore 	iocb_count = 1;
792*3fb517f7SJames Moore 	cnt = CMD7_2400_DATA_SEGMENTS;
793*3fb517f7SJames Moore 	cont_segs = CONT_A64_DATA_SEGMENTS;
794*3fb517f7SJames Moore 
795*3fb517f7SJames Moore 	if (cookie_count > cnt) {
796*3fb517f7SJames Moore 		cnt = cookie_count - cnt;
797*3fb517f7SJames Moore 		iocb_count = (uint8_t)(iocb_count + cnt / cont_segs);
798*3fb517f7SJames Moore 		if (cnt % cont_segs) {
799*3fb517f7SJames Moore 			iocb_count++;
800*3fb517f7SJames Moore 		}
801*3fb517f7SJames Moore 	}
802*3fb517f7SJames Moore 	return (iocb_count);
803*3fb517f7SJames Moore }
804