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
22c4ddbbe1SDaniel Beauregard /*
23*4c3888b8SHans Rosenfeld * Copyright 2009-2015 QLogic Corporation. All rights reserved.
24c4ddbbe1SDaniel Beauregard * Use is subject to license terms.
25c4ddbbe1SDaniel Beauregard */
26c4ddbbe1SDaniel Beauregard
27fcf3ce44SJohn Forte /*
28*4c3888b8SHans Rosenfeld * Copyright (c) 2008, 2015, 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
364558d122SViswanathan Kannappan #include <sys/stmf_defines.h>
374558d122SViswanathan Kannappan #include <sys/fct_defines.h>
384558d122SViswanathan Kannappan #include <sys/stmf.h>
394558d122SViswanathan Kannappan #include <sys/portif.h>
404558d122SViswanathan Kannappan #include <sys/fct.h>
414558d122SViswanathan Kannappan
424558d122SViswanathan Kannappan #include "qlt.h"
434558d122SViswanathan Kannappan #include "qlt_dma.h"
44fcf3ce44SJohn Forte
453fb517f7SJames Moore /*
463fb517f7SJames Moore * Local Function Prototypes.
473fb517f7SJames Moore */
483fb517f7SJames Moore static void
493fb517f7SJames Moore qlt_dma_free_handles(qlt_state_t *qlt, qlt_dma_handle_t *first_handle);
503fb517f7SJames Moore
51fcf3ce44SJohn Forte #define BUF_COUNT_2K 2048
52fcf3ce44SJohn Forte #define BUF_COUNT_8K 512
533f3ce7b9SDaniel Beauregard #define BUF_COUNT_64K 256
543f3ce7b9SDaniel Beauregard #define BUF_COUNT_128K 1024
55fcf3ce44SJohn Forte #define BUF_COUNT_256K 8
56fcf3ce44SJohn Forte
57fcf3ce44SJohn Forte #define QLT_DMEM_MAX_BUF_SIZE (4 * 65536)
58fcf3ce44SJohn Forte #define QLT_DMEM_NBUCKETS 5
59fcf3ce44SJohn Forte static qlt_dmem_bucket_t bucket2K = { 2048, BUF_COUNT_2K },
60fcf3ce44SJohn Forte bucket8K = { 8192, BUF_COUNT_8K },
61fcf3ce44SJohn Forte bucket64K = { 65536, BUF_COUNT_64K },
62fcf3ce44SJohn Forte bucket128k = { (2 * 65536), BUF_COUNT_128K },
63fcf3ce44SJohn Forte bucket256k = { (4 * 65536), BUF_COUNT_256K };
64fcf3ce44SJohn Forte
65fcf3ce44SJohn Forte static qlt_dmem_bucket_t *dmem_buckets[] = { &bucket2K, &bucket8K,
66fcf3ce44SJohn Forte &bucket64K, &bucket128k, &bucket256k, NULL };
67fcf3ce44SJohn Forte static ddi_device_acc_attr_t acc;
68fcf3ce44SJohn Forte static ddi_dma_attr_t qlt_scsi_dma_attr = {
69fcf3ce44SJohn Forte DMA_ATTR_V0, /* dma_attr_version */
70fcf3ce44SJohn Forte 0, /* low DMA address range */
71fcf3ce44SJohn Forte 0xffffffffffffffff, /* high DMA address range */
72fcf3ce44SJohn Forte 0xffffffff, /* DMA counter register */
73fcf3ce44SJohn Forte 8192, /* DMA address alignment */
74fcf3ce44SJohn Forte 0xff, /* DMA burstsizes */
75fcf3ce44SJohn Forte 1, /* min effective DMA size */
76fcf3ce44SJohn Forte 0xffffffff, /* max DMA xfer size */
77fcf3ce44SJohn Forte 0xffffffff, /* segment boundary */
78fcf3ce44SJohn Forte 1, /* s/g list length */
79fcf3ce44SJohn Forte 1, /* granularity of device */
80fcf3ce44SJohn Forte 0 /* DMA transfer flags */
81fcf3ce44SJohn Forte };
82fcf3ce44SJohn Forte
83fcf3ce44SJohn Forte fct_status_t
qlt_dmem_init(qlt_state_t * qlt)84fcf3ce44SJohn Forte qlt_dmem_init(qlt_state_t *qlt)
85fcf3ce44SJohn Forte {
863fb517f7SJames Moore qlt_dmem_bucket_t *p;
873fb517f7SJames Moore qlt_dmem_bctl_t *bctl, *bc;
883fb517f7SJames Moore qlt_dmem_bctl_t *prev;
893fb517f7SJames Moore int ndx, i;
903fb517f7SJames Moore uint32_t total_mem;
913fb517f7SJames Moore uint8_t *addr;
923fb517f7SJames Moore uint8_t *host_addr;
933fb517f7SJames Moore uint64_t dev_addr;
943fb517f7SJames Moore ddi_dma_cookie_t cookie;
953fb517f7SJames Moore uint32_t ncookie;
963fb517f7SJames Moore uint32_t bsize;
973fb517f7SJames Moore size_t len;
98fcf3ce44SJohn Forte
99a2255df3SDaniel Beauregard if (qlt->qlt_bucketcnt[0] != 0) {
100a2255df3SDaniel Beauregard bucket2K.dmem_nbufs = qlt->qlt_bucketcnt[0];
101a2255df3SDaniel Beauregard }
102a2255df3SDaniel Beauregard if (qlt->qlt_bucketcnt[1] != 0) {
103a2255df3SDaniel Beauregard bucket8K.dmem_nbufs = qlt->qlt_bucketcnt[1];
104a2255df3SDaniel Beauregard }
105a2255df3SDaniel Beauregard if (qlt->qlt_bucketcnt[2] != 0) {
106a2255df3SDaniel Beauregard bucket64K.dmem_nbufs = qlt->qlt_bucketcnt[2];
107a2255df3SDaniel Beauregard }
108a2255df3SDaniel Beauregard if (qlt->qlt_bucketcnt[3] != 0) {
109a2255df3SDaniel Beauregard bucket128k.dmem_nbufs = qlt->qlt_bucketcnt[3];
110fcf3ce44SJohn Forte }
111a2255df3SDaniel Beauregard if (qlt->qlt_bucketcnt[4] != 0) {
112a2255df3SDaniel Beauregard bucket256k.dmem_nbufs = qlt->qlt_bucketcnt[4];
113a2255df3SDaniel Beauregard }
114a2255df3SDaniel Beauregard
115fcf3ce44SJohn Forte bsize = sizeof (dmem_buckets);
116c4ddbbe1SDaniel Beauregard ndx = (int)(bsize / sizeof (void *));
117fcf3ce44SJohn Forte /*
118fcf3ce44SJohn Forte * The reason it is ndx - 1 everywhere is becasue the last bucket
119fcf3ce44SJohn Forte * pointer is NULL.
120fcf3ce44SJohn Forte */
121fcf3ce44SJohn Forte qlt->dmem_buckets = (qlt_dmem_bucket_t **)kmem_zalloc(bsize +
122c4ddbbe1SDaniel Beauregard ((ndx - 1) * (int)sizeof (qlt_dmem_bucket_t)), KM_SLEEP);
123fcf3ce44SJohn Forte for (i = 0; i < (ndx - 1); i++) {
124fcf3ce44SJohn Forte qlt->dmem_buckets[i] = (qlt_dmem_bucket_t *)
125c4ddbbe1SDaniel Beauregard ((uint8_t *)qlt->dmem_buckets + bsize +
126c4ddbbe1SDaniel Beauregard (i * (int)sizeof (qlt_dmem_bucket_t)));
127fcf3ce44SJohn Forte bcopy(dmem_buckets[i], qlt->dmem_buckets[i],
128c4ddbbe1SDaniel Beauregard sizeof (qlt_dmem_bucket_t));
129fcf3ce44SJohn Forte }
130fcf3ce44SJohn Forte bzero(&acc, sizeof (acc));
131fcf3ce44SJohn Forte acc.devacc_attr_version = DDI_DEVICE_ATTR_V0;
132fcf3ce44SJohn Forte acc.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC;
133fcf3ce44SJohn Forte acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
134fcf3ce44SJohn Forte for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) {
135fcf3ce44SJohn Forte bctl = (qlt_dmem_bctl_t *)kmem_zalloc(p->dmem_nbufs *
136c4ddbbe1SDaniel Beauregard sizeof (qlt_dmem_bctl_t), KM_NOSLEEP);
137c4ddbbe1SDaniel Beauregard if (bctl == NULL) {
138c4ddbbe1SDaniel Beauregard EL(qlt, "bctl==NULL\n");
139fcf3ce44SJohn Forte goto alloc_bctl_failed;
140c4ddbbe1SDaniel Beauregard }
141fcf3ce44SJohn Forte p->dmem_bctls_mem = bctl;
142fcf3ce44SJohn Forte mutex_init(&p->dmem_lock, NULL, MUTEX_DRIVER, NULL);
143c4ddbbe1SDaniel Beauregard if ((i = ddi_dma_alloc_handle(qlt->dip, &qlt_scsi_dma_attr,
144c4ddbbe1SDaniel Beauregard DDI_DMA_SLEEP, 0, &p->dmem_dma_handle)) != DDI_SUCCESS) {
145c4ddbbe1SDaniel Beauregard EL(qlt, "ddi_dma_alloc_handle status=%xh\n", i);
146fcf3ce44SJohn Forte goto alloc_handle_failed;
147c4ddbbe1SDaniel Beauregard }
148fcf3ce44SJohn Forte
149fcf3ce44SJohn Forte total_mem = p->dmem_buf_size * p->dmem_nbufs;
150fcf3ce44SJohn Forte
151c4ddbbe1SDaniel Beauregard if ((i = ddi_dma_mem_alloc(p->dmem_dma_handle, total_mem, &acc,
152fcf3ce44SJohn Forte DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, (caddr_t *)&addr,
153c4ddbbe1SDaniel Beauregard &len, &p->dmem_acc_handle)) != DDI_SUCCESS) {
154c4ddbbe1SDaniel Beauregard EL(qlt, "ddi_dma_mem_alloc status=%xh\n", i);
155fcf3ce44SJohn Forte goto mem_alloc_failed;
156c4ddbbe1SDaniel Beauregard }
157fcf3ce44SJohn Forte
158c4ddbbe1SDaniel Beauregard if ((i = ddi_dma_addr_bind_handle(p->dmem_dma_handle, NULL,
159fcf3ce44SJohn Forte (caddr_t)addr, total_mem, DDI_DMA_RDWR | DDI_DMA_STREAMING,
160c4ddbbe1SDaniel Beauregard DDI_DMA_DONTWAIT, 0, &cookie, &ncookie)) != DDI_SUCCESS) {
161c4ddbbe1SDaniel Beauregard EL(qlt, "ddi_dma_addr_bind_handle status=%xh\n", i);
162fcf3ce44SJohn Forte goto addr_bind_handle_failed;
163c4ddbbe1SDaniel Beauregard }
164c4ddbbe1SDaniel Beauregard if (ncookie != 1) {
165c4ddbbe1SDaniel Beauregard EL(qlt, "ncookie=%d\n", ncookie);
166fcf3ce44SJohn Forte goto dmem_init_failed;
167c4ddbbe1SDaniel Beauregard }
168fcf3ce44SJohn Forte
169fcf3ce44SJohn Forte p->dmem_host_addr = host_addr = addr;
170fcf3ce44SJohn Forte p->dmem_dev_addr = dev_addr = (uint64_t)cookie.dmac_laddress;
171fcf3ce44SJohn Forte bsize = p->dmem_buf_size;
172fcf3ce44SJohn Forte p->dmem_bctl_free_list = bctl;
173fcf3ce44SJohn Forte p->dmem_nbufs_free = p->dmem_nbufs;
174fcf3ce44SJohn Forte for (i = 0; i < p->dmem_nbufs; i++) {
1753fb517f7SJames Moore stmf_data_buf_t *db;
176fcf3ce44SJohn Forte prev = bctl;
177fcf3ce44SJohn Forte bctl->bctl_bucket = p;
178fcf3ce44SJohn Forte bctl->bctl_buf = db = stmf_alloc(STMF_STRUCT_DATA_BUF,
179c4ddbbe1SDaniel Beauregard 0, 0);
180fcf3ce44SJohn Forte db->db_port_private = bctl;
181fcf3ce44SJohn Forte db->db_sglist[0].seg_addr = host_addr;
182fcf3ce44SJohn Forte bctl->bctl_dev_addr = dev_addr;
183fcf3ce44SJohn Forte db->db_sglist[0].seg_length = db->db_buf_size = bsize;
184fcf3ce44SJohn Forte db->db_sglist_length = 1;
185fcf3ce44SJohn Forte host_addr += bsize;
186fcf3ce44SJohn Forte dev_addr += bsize;
187fcf3ce44SJohn Forte bctl++;
188fcf3ce44SJohn Forte prev->bctl_next = bctl;
189fcf3ce44SJohn Forte }
190fcf3ce44SJohn Forte prev->bctl_next = NULL;
191fcf3ce44SJohn Forte }
192fcf3ce44SJohn Forte
193fcf3ce44SJohn Forte return (QLT_SUCCESS);
194fcf3ce44SJohn Forte
195fcf3ce44SJohn Forte dmem_failure_loop:;
196fcf3ce44SJohn Forte bc = bctl;
197fcf3ce44SJohn Forte while (bc) {
198fcf3ce44SJohn Forte stmf_free(bc->bctl_buf);
199fcf3ce44SJohn Forte bc = bc->bctl_next;
200fcf3ce44SJohn Forte }
201fcf3ce44SJohn Forte dmem_init_failed:;
202fcf3ce44SJohn Forte (void) ddi_dma_unbind_handle(p->dmem_dma_handle);
203fcf3ce44SJohn Forte addr_bind_handle_failed:;
204fcf3ce44SJohn Forte ddi_dma_mem_free(&p->dmem_acc_handle);
205fcf3ce44SJohn Forte mem_alloc_failed:;
206fcf3ce44SJohn Forte ddi_dma_free_handle(&p->dmem_dma_handle);
207fcf3ce44SJohn Forte alloc_handle_failed:;
208fcf3ce44SJohn Forte kmem_free(p->dmem_bctls_mem, p->dmem_nbufs * sizeof (qlt_dmem_bctl_t));
209fcf3ce44SJohn Forte mutex_destroy(&p->dmem_lock);
210fcf3ce44SJohn Forte alloc_bctl_failed:;
211fcf3ce44SJohn Forte if (--ndx >= 0) {
212fcf3ce44SJohn Forte p = qlt->dmem_buckets[ndx];
213fcf3ce44SJohn Forte bctl = p->dmem_bctl_free_list;
214fcf3ce44SJohn Forte goto dmem_failure_loop;
215fcf3ce44SJohn Forte }
216fcf3ce44SJohn Forte kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) +
217*4c3888b8SHans Rosenfeld (((sizeof (dmem_buckets)/sizeof (void *))-1)*
218*4c3888b8SHans Rosenfeld sizeof (qlt_dmem_bucket_t)));
219fcf3ce44SJohn Forte qlt->dmem_buckets = NULL;
220fcf3ce44SJohn Forte
221fcf3ce44SJohn Forte return (QLT_FAILURE);
222fcf3ce44SJohn Forte }
223fcf3ce44SJohn Forte
2243fb517f7SJames Moore void
qlt_dma_handle_pool_init(qlt_state_t * qlt)2253fb517f7SJames Moore qlt_dma_handle_pool_init(qlt_state_t *qlt)
2263fb517f7SJames Moore {
2273fb517f7SJames Moore qlt_dma_handle_pool_t *pool;
2283fb517f7SJames Moore
2293fb517f7SJames Moore pool = kmem_zalloc(sizeof (*pool), KM_SLEEP);
2303fb517f7SJames Moore mutex_init(&pool->pool_lock, NULL, MUTEX_DRIVER, NULL);
2313fb517f7SJames Moore qlt->qlt_dma_handle_pool = pool;
2323fb517f7SJames Moore }
2333fb517f7SJames Moore
2343fb517f7SJames Moore void
qlt_dma_handle_pool_fini(qlt_state_t * qlt)2353fb517f7SJames Moore qlt_dma_handle_pool_fini(qlt_state_t *qlt)
2363fb517f7SJames Moore {
2373fb517f7SJames Moore qlt_dma_handle_pool_t *pool;
2383fb517f7SJames Moore qlt_dma_handle_t *handle, *next_handle;
2393fb517f7SJames Moore
2403fb517f7SJames Moore pool = qlt->qlt_dma_handle_pool;
2413fb517f7SJames Moore mutex_enter(&pool->pool_lock);
2423fb517f7SJames Moore /*
2433fb517f7SJames Moore * XXX Need to wait for free == total elements
2443fb517f7SJames Moore * XXX Not sure how other driver shutdown stuff is done.
2453fb517f7SJames Moore */
2463fb517f7SJames Moore ASSERT(pool->num_free == pool->num_total);
2473fb517f7SJames Moore if (pool->num_free != pool->num_total)
2483fb517f7SJames Moore cmn_err(CE_WARN,
2493fb517f7SJames Moore "num_free %d != num_total %d\n",
2503fb517f7SJames Moore pool->num_free, pool->num_total);
2513fb517f7SJames Moore handle = pool->free_list;
2523fb517f7SJames Moore while (handle) {
2533fb517f7SJames Moore next_handle = handle->next;
2543fb517f7SJames Moore kmem_free(handle, sizeof (*handle));
2553fb517f7SJames Moore handle = next_handle;
2563fb517f7SJames Moore }
2573fb517f7SJames Moore qlt->qlt_dma_handle_pool = NULL;
2583fb517f7SJames Moore mutex_destroy(&pool->pool_lock);
2593fb517f7SJames Moore kmem_free(pool, sizeof (*pool));
2603fb517f7SJames Moore }
2613fb517f7SJames Moore
262fcf3ce44SJohn Forte void
qlt_dmem_fini(qlt_state_t * qlt)263fcf3ce44SJohn Forte qlt_dmem_fini(qlt_state_t *qlt)
264fcf3ce44SJohn Forte {
265fcf3ce44SJohn Forte qlt_dmem_bucket_t *p;
266fcf3ce44SJohn Forte qlt_dmem_bctl_t *bctl;
267fcf3ce44SJohn Forte int ndx;
268fcf3ce44SJohn Forte
269fcf3ce44SJohn Forte for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) {
270fcf3ce44SJohn Forte bctl = p->dmem_bctl_free_list;
271fcf3ce44SJohn Forte while (bctl) {
272fcf3ce44SJohn Forte stmf_free(bctl->bctl_buf);
273fcf3ce44SJohn Forte bctl = bctl->bctl_next;
274fcf3ce44SJohn Forte }
275fcf3ce44SJohn Forte bctl = p->dmem_bctl_free_list;
276fcf3ce44SJohn Forte (void) ddi_dma_unbind_handle(p->dmem_dma_handle);
277fcf3ce44SJohn Forte ddi_dma_mem_free(&p->dmem_acc_handle);
278fcf3ce44SJohn Forte ddi_dma_free_handle(&p->dmem_dma_handle);
279fcf3ce44SJohn Forte kmem_free(p->dmem_bctls_mem,
280c4ddbbe1SDaniel Beauregard p->dmem_nbufs * sizeof (qlt_dmem_bctl_t));
281fcf3ce44SJohn Forte mutex_destroy(&p->dmem_lock);
282fcf3ce44SJohn Forte }
283fcf3ce44SJohn Forte kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) +
284fcf3ce44SJohn Forte (((sizeof (dmem_buckets)/sizeof (void *))-1)*
285c4ddbbe1SDaniel Beauregard sizeof (qlt_dmem_bucket_t)));
286fcf3ce44SJohn Forte qlt->dmem_buckets = NULL;
287fcf3ce44SJohn Forte }
288fcf3ce44SJohn Forte
289fcf3ce44SJohn Forte stmf_data_buf_t *
qlt_dmem_alloc(fct_local_port_t * port,uint32_t size,uint32_t * pminsize,uint32_t flags)290fcf3ce44SJohn Forte qlt_dmem_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize,
291fcf3ce44SJohn Forte uint32_t flags)
292fcf3ce44SJohn Forte {
293fcf3ce44SJohn Forte return (qlt_i_dmem_alloc((qlt_state_t *)
294fcf3ce44SJohn Forte port->port_fca_private, size, pminsize,
295fcf3ce44SJohn Forte flags));
296fcf3ce44SJohn Forte }
297fcf3ce44SJohn Forte
298fcf3ce44SJohn Forte /* ARGSUSED */
299fcf3ce44SJohn Forte stmf_data_buf_t *
qlt_i_dmem_alloc(qlt_state_t * qlt,uint32_t size,uint32_t * pminsize,uint32_t flags)300fcf3ce44SJohn Forte qlt_i_dmem_alloc(qlt_state_t *qlt, uint32_t size, uint32_t *pminsize,
3013fb517f7SJames Moore uint32_t flags)
302fcf3ce44SJohn Forte {
303a2255df3SDaniel Beauregard qlt_dmem_bucket_t *p;
3043f3ce7b9SDaniel Beauregard qlt_dmem_bctl_t *bctl;
305a2255df3SDaniel Beauregard int i;
3063f3ce7b9SDaniel Beauregard uint32_t size_possible = 0;
307fcf3ce44SJohn Forte
3083f3ce7b9SDaniel Beauregard if (size > QLT_DMEM_MAX_BUF_SIZE) {
3093f3ce7b9SDaniel Beauregard goto qlt_try_partial_alloc;
3103f3ce7b9SDaniel Beauregard }
3113f3ce7b9SDaniel Beauregard
3123f3ce7b9SDaniel Beauregard /* 1st try to do a full allocation */
3133f3ce7b9SDaniel Beauregard for (i = 0; (p = qlt->dmem_buckets[i]) != NULL; i++) {
3143f3ce7b9SDaniel Beauregard if (p->dmem_buf_size >= size) {
3153f3ce7b9SDaniel Beauregard if (p->dmem_nbufs_free) {
3163f3ce7b9SDaniel Beauregard mutex_enter(&p->dmem_lock);
3173f3ce7b9SDaniel Beauregard bctl = p->dmem_bctl_free_list;
3183f3ce7b9SDaniel Beauregard if (bctl == NULL) {
319a2255df3SDaniel Beauregard mutex_exit(&p->dmem_lock);
3203f3ce7b9SDaniel Beauregard continue;
321a2255df3SDaniel Beauregard }
3223f3ce7b9SDaniel Beauregard p->dmem_bctl_free_list =
3233f3ce7b9SDaniel Beauregard bctl->bctl_next;
3243f3ce7b9SDaniel Beauregard p->dmem_nbufs_free--;
3253f3ce7b9SDaniel Beauregard qlt->qlt_bufref[i]++;
3263f3ce7b9SDaniel Beauregard mutex_exit(&p->dmem_lock);
3273f3ce7b9SDaniel Beauregard bctl->bctl_buf->db_data_size = size;
3283f3ce7b9SDaniel Beauregard return (bctl->bctl_buf);
3293f3ce7b9SDaniel Beauregard } else {
3303f3ce7b9SDaniel Beauregard qlt->qlt_bumpbucket++;
331fcf3ce44SJohn Forte }
332fcf3ce44SJohn Forte }
333fcf3ce44SJohn Forte }
334fcf3ce44SJohn Forte
3353f3ce7b9SDaniel Beauregard qlt_try_partial_alloc:
3363f3ce7b9SDaniel Beauregard
3373f3ce7b9SDaniel Beauregard qlt->qlt_pmintry++;
3383f3ce7b9SDaniel Beauregard
3393f3ce7b9SDaniel Beauregard /* Now go from high to low */
3403f3ce7b9SDaniel Beauregard for (i = QLT_DMEM_NBUCKETS - 1; i >= 0; i--) {
3413f3ce7b9SDaniel Beauregard p = qlt->dmem_buckets[i];
3423f3ce7b9SDaniel Beauregard if (p->dmem_nbufs_free == 0)
3433f3ce7b9SDaniel Beauregard continue;
3443f3ce7b9SDaniel Beauregard if (!size_possible) {
3453f3ce7b9SDaniel Beauregard size_possible = p->dmem_buf_size;
3463f3ce7b9SDaniel Beauregard }
3473f3ce7b9SDaniel Beauregard if (*pminsize > p->dmem_buf_size) {
3483f3ce7b9SDaniel Beauregard /* At this point we know the request is failing. */
3493f3ce7b9SDaniel Beauregard if (size_possible) {
3503f3ce7b9SDaniel Beauregard /*
3513f3ce7b9SDaniel Beauregard * This caller is asking too much. We already
3523f3ce7b9SDaniel Beauregard * know what we can give, so get out.
3533f3ce7b9SDaniel Beauregard */
3543f3ce7b9SDaniel Beauregard break;
3553f3ce7b9SDaniel Beauregard } else {
3563f3ce7b9SDaniel Beauregard /*
3573f3ce7b9SDaniel Beauregard * Lets continue to find out and tell what
3583f3ce7b9SDaniel Beauregard * we can give.
3593f3ce7b9SDaniel Beauregard */
3603f3ce7b9SDaniel Beauregard continue;
3613f3ce7b9SDaniel Beauregard }
3623f3ce7b9SDaniel Beauregard }
3633f3ce7b9SDaniel Beauregard mutex_enter(&p->dmem_lock);
3643f3ce7b9SDaniel Beauregard if (*pminsize <= p->dmem_buf_size) {
3653f3ce7b9SDaniel Beauregard bctl = p->dmem_bctl_free_list;
3663f3ce7b9SDaniel Beauregard if (bctl == NULL) {
3673f3ce7b9SDaniel Beauregard /* Someone took it. */
3683f3ce7b9SDaniel Beauregard size_possible = 0;
3693f3ce7b9SDaniel Beauregard mutex_exit(&p->dmem_lock);
3703f3ce7b9SDaniel Beauregard continue;
3713f3ce7b9SDaniel Beauregard }
3723f3ce7b9SDaniel Beauregard p->dmem_bctl_free_list = bctl->bctl_next;
3733f3ce7b9SDaniel Beauregard p->dmem_nbufs_free--;
3743f3ce7b9SDaniel Beauregard mutex_exit(&p->dmem_lock);
3753f3ce7b9SDaniel Beauregard bctl->bctl_buf->db_data_size = p->dmem_buf_size;
3763f3ce7b9SDaniel Beauregard qlt->qlt_pmin_ok++;
3773f3ce7b9SDaniel Beauregard return (bctl->bctl_buf);
3783f3ce7b9SDaniel Beauregard }
379fcf3ce44SJohn Forte }
380a2255df3SDaniel Beauregard
3813f3ce7b9SDaniel Beauregard *pminsize = size_possible;
3823f3ce7b9SDaniel Beauregard
383fcf3ce44SJohn Forte return (NULL);
384fcf3ce44SJohn Forte }
385fcf3ce44SJohn Forte
386fcf3ce44SJohn Forte /* ARGSUSED */
387fcf3ce44SJohn Forte void
qlt_i_dmem_free(qlt_state_t * qlt,stmf_data_buf_t * dbuf)388fcf3ce44SJohn Forte qlt_i_dmem_free(qlt_state_t *qlt, stmf_data_buf_t *dbuf)
389fcf3ce44SJohn Forte {
390fcf3ce44SJohn Forte qlt_dmem_free(0, dbuf);
391fcf3ce44SJohn Forte }
392fcf3ce44SJohn Forte
393fcf3ce44SJohn Forte /* ARGSUSED */
394fcf3ce44SJohn Forte void
qlt_dmem_free(fct_dbuf_store_t * fds,stmf_data_buf_t * dbuf)395fcf3ce44SJohn Forte qlt_dmem_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
396fcf3ce44SJohn Forte {
3973fb517f7SJames Moore qlt_dmem_bctl_t *bctl;
3983fb517f7SJames Moore qlt_dmem_bucket_t *p;
399fcf3ce44SJohn Forte
4003fb517f7SJames Moore ASSERT((dbuf->db_flags & DB_LU_DATA_BUF) == 0);
4013fb517f7SJames Moore
4023fb517f7SJames Moore bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
4033fb517f7SJames Moore p = bctl->bctl_bucket;
404fcf3ce44SJohn Forte mutex_enter(&p->dmem_lock);
405fcf3ce44SJohn Forte bctl->bctl_next = p->dmem_bctl_free_list;
406fcf3ce44SJohn Forte p->dmem_bctl_free_list = bctl;
407fcf3ce44SJohn Forte p->dmem_nbufs_free++;
408fcf3ce44SJohn Forte mutex_exit(&p->dmem_lock);
409fcf3ce44SJohn Forte }
410fcf3ce44SJohn Forte
411fcf3ce44SJohn Forte void
qlt_dmem_dma_sync(stmf_data_buf_t * dbuf,uint_t sync_type)412fcf3ce44SJohn Forte qlt_dmem_dma_sync(stmf_data_buf_t *dbuf, uint_t sync_type)
413fcf3ce44SJohn Forte {
4143fb517f7SJames Moore qlt_dmem_bctl_t *bctl;
4153fb517f7SJames Moore qlt_dma_sgl_t *qsgl;
4163fb517f7SJames Moore qlt_dmem_bucket_t *p;
4173fb517f7SJames Moore qlt_dma_handle_t *th;
4183fb517f7SJames Moore int rv;
4193fb517f7SJames Moore
4203fb517f7SJames Moore if (dbuf->db_flags & DB_LU_DATA_BUF) {
4213fb517f7SJames Moore /*
4223fb517f7SJames Moore * go through ddi handle list
4233fb517f7SJames Moore */
4243fb517f7SJames Moore qsgl = (qlt_dma_sgl_t *)dbuf->db_port_private;
4253fb517f7SJames Moore th = qsgl->handle_list;
4263fb517f7SJames Moore while (th) {
4273fb517f7SJames Moore rv = ddi_dma_sync(th->dma_handle,
4283fb517f7SJames Moore 0, 0, sync_type);
4293fb517f7SJames Moore if (rv != DDI_SUCCESS) {
4303fb517f7SJames Moore cmn_err(CE_WARN, "ddi_dma_sync FAILED\n");
4313fb517f7SJames Moore }
4323fb517f7SJames Moore th = th->next;
4333fb517f7SJames Moore }
4343fb517f7SJames Moore } else {
4353fb517f7SJames Moore bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private;
4363fb517f7SJames Moore p = bctl->bctl_bucket;
4373fb517f7SJames Moore (void) ddi_dma_sync(p->dmem_dma_handle, (off_t)
4383fb517f7SJames Moore (bctl->bctl_dev_addr - p->dmem_dev_addr),
4393fb517f7SJames Moore dbuf->db_data_size, sync_type);
4403fb517f7SJames Moore }
4413fb517f7SJames Moore }
4423fb517f7SJames Moore
4433fb517f7SJames Moore /*
4443fb517f7SJames Moore * A very lite version of ddi_dma_addr_bind_handle()
4453fb517f7SJames Moore */
4463fb517f7SJames Moore uint64_t
qlt_ddi_vtop(caddr_t vaddr)4473fb517f7SJames Moore qlt_ddi_vtop(caddr_t vaddr)
4483fb517f7SJames Moore {
4493fb517f7SJames Moore uint64_t offset, paddr;
4503fb517f7SJames Moore pfn_t pfn;
4513fb517f7SJames Moore
4523fb517f7SJames Moore pfn = hat_getpfnum(kas.a_hat, vaddr);
4533fb517f7SJames Moore ASSERT(pfn != PFN_INVALID && pfn != PFN_SUSPENDED);
4543fb517f7SJames Moore offset = ((uintptr_t)vaddr) & MMU_PAGEOFFSET;
4553fb517f7SJames Moore paddr = mmu_ptob(pfn);
4563fb517f7SJames Moore return (paddr+offset);
4573fb517f7SJames Moore }
4583fb517f7SJames Moore
4593fb517f7SJames Moore static ddi_dma_attr_t qlt_sgl_dma_attr = {
4603fb517f7SJames Moore DMA_ATTR_V0, /* dma_attr_version */
4613fb517f7SJames Moore 0, /* low DMA address range */
4623fb517f7SJames Moore 0xffffffffffffffff, /* high DMA address range */
4633fb517f7SJames Moore 0xffffffff, /* DMA counter register */
4643fb517f7SJames Moore 64, /* DMA address alignment */
4653fb517f7SJames Moore 0xff, /* DMA burstsizes */
4663fb517f7SJames Moore 1, /* min effective DMA size */
4673fb517f7SJames Moore 0xffffffff, /* max DMA xfer size */
4683fb517f7SJames Moore 0xffffffff, /* segment boundary */
4693fb517f7SJames Moore QLT_DMA_SG_LIST_LENGTH, /* s/g list length */
4703fb517f7SJames Moore 1, /* granularity of device */
4713fb517f7SJames Moore 0 /* DMA transfer flags */
4723fb517f7SJames Moore };
4733fb517f7SJames Moore
4743fb517f7SJames Moore /*
4753fb517f7SJames Moore * Allocate a qlt_dma_handle container and fill it with a ddi_dma_handle
4763fb517f7SJames Moore */
4773fb517f7SJames Moore static qlt_dma_handle_t *
qlt_dma_alloc_handle(qlt_state_t * qlt)4783fb517f7SJames Moore qlt_dma_alloc_handle(qlt_state_t *qlt)
4793fb517f7SJames Moore {
4803fb517f7SJames Moore ddi_dma_handle_t ddi_handle;
4813fb517f7SJames Moore qlt_dma_handle_t *qlt_handle;
4823fb517f7SJames Moore int rv;
4833fb517f7SJames Moore
4843fb517f7SJames Moore rv = ddi_dma_alloc_handle(qlt->dip, &qlt_sgl_dma_attr,
4853fb517f7SJames Moore DDI_DMA_SLEEP, 0, &ddi_handle);
4863fb517f7SJames Moore if (rv != DDI_SUCCESS) {
4873fb517f7SJames Moore EL(qlt, "ddi_dma_alloc_handle status=%xh\n", rv);
4883fb517f7SJames Moore return (NULL);
4893fb517f7SJames Moore }
4903fb517f7SJames Moore qlt_handle = kmem_zalloc(sizeof (qlt_dma_handle_t), KM_SLEEP);
4913fb517f7SJames Moore qlt_handle->dma_handle = ddi_handle;
4923fb517f7SJames Moore return (qlt_handle);
4933fb517f7SJames Moore }
4943fb517f7SJames Moore
4953fb517f7SJames Moore /*
4963fb517f7SJames Moore * Allocate a list of qlt_dma_handle containers from the free list
4973fb517f7SJames Moore */
4983fb517f7SJames Moore static qlt_dma_handle_t *
qlt_dma_alloc_handle_list(qlt_state_t * qlt,int handle_count)4993fb517f7SJames Moore qlt_dma_alloc_handle_list(qlt_state_t *qlt, int handle_count)
5003fb517f7SJames Moore {
5013fb517f7SJames Moore qlt_dma_handle_pool_t *pool;
5023fb517f7SJames Moore qlt_dma_handle_t *tmp_handle, *first_handle, *last_handle;
5033fb517f7SJames Moore int i;
5043fb517f7SJames Moore
5053fb517f7SJames Moore /*
5063fb517f7SJames Moore * Make sure the free list can satisfy the request.
5073fb517f7SJames Moore * Once the free list is primed, it should satisfy most requests.
5083fb517f7SJames Moore * XXX Should there be a limit on pool size?
5093fb517f7SJames Moore */
5103fb517f7SJames Moore pool = qlt->qlt_dma_handle_pool;
5113fb517f7SJames Moore mutex_enter(&pool->pool_lock);
5123fb517f7SJames Moore while (handle_count > pool->num_free) {
5133fb517f7SJames Moore mutex_exit(&pool->pool_lock);
5143fb517f7SJames Moore if ((tmp_handle = qlt_dma_alloc_handle(qlt)) == NULL)
5153fb517f7SJames Moore return (NULL);
5163fb517f7SJames Moore mutex_enter(&pool->pool_lock);
5173fb517f7SJames Moore tmp_handle->next = pool->free_list;
5183fb517f7SJames Moore pool->free_list = tmp_handle;
5193fb517f7SJames Moore pool->num_free++;
5203fb517f7SJames Moore pool->num_total++;
5213fb517f7SJames Moore }
5223fb517f7SJames Moore
5233fb517f7SJames Moore /*
5243fb517f7SJames Moore * The free list lock is held and the list is large enough to
5253fb517f7SJames Moore * satisfy this request. Run down the freelist and snip off
5263fb517f7SJames Moore * the number of elements needed for this request.
5273fb517f7SJames Moore */
5283fb517f7SJames Moore first_handle = pool->free_list;
5293fb517f7SJames Moore tmp_handle = first_handle;
5303fb517f7SJames Moore for (i = 0; i < handle_count; i++) {
5313fb517f7SJames Moore last_handle = tmp_handle;
5323fb517f7SJames Moore tmp_handle = tmp_handle->next;
5333fb517f7SJames Moore }
5343fb517f7SJames Moore pool->free_list = tmp_handle;
5353fb517f7SJames Moore pool->num_free -= handle_count;
5363fb517f7SJames Moore mutex_exit(&pool->pool_lock);
5373fb517f7SJames Moore last_handle->next = NULL; /* sanity */
5383fb517f7SJames Moore return (first_handle);
5393fb517f7SJames Moore }
5403fb517f7SJames Moore
5413fb517f7SJames Moore /*
5423fb517f7SJames Moore * Return a list of qlt_dma_handle containers to the free list.
5433fb517f7SJames Moore */
5443fb517f7SJames Moore static void
qlt_dma_free_handles(qlt_state_t * qlt,qlt_dma_handle_t * first_handle)5453fb517f7SJames Moore qlt_dma_free_handles(qlt_state_t *qlt, qlt_dma_handle_t *first_handle)
5463fb517f7SJames Moore {
5473fb517f7SJames Moore qlt_dma_handle_pool_t *pool;
5483fb517f7SJames Moore qlt_dma_handle_t *tmp_handle, *last_handle;
5493fb517f7SJames Moore int rv, handle_count;
5503fb517f7SJames Moore
5513fb517f7SJames Moore /*
5523fb517f7SJames Moore * Traverse the list and unbind the handles
5533fb517f7SJames Moore */
5543fb517f7SJames Moore ASSERT(first_handle);
5553fb517f7SJames Moore tmp_handle = first_handle;
5563fb517f7SJames Moore handle_count = 0;
5573fb517f7SJames Moore while (tmp_handle != NULL) {
5583fb517f7SJames Moore last_handle = tmp_handle;
5593fb517f7SJames Moore /*
5603fb517f7SJames Moore * If the handle is bound, unbind the handle so it can be
5613fb517f7SJames Moore * reused. It may not be bound if there was a bind failure.
5623fb517f7SJames Moore */
5633fb517f7SJames Moore if (tmp_handle->num_cookies != 0) {
5643fb517f7SJames Moore rv = ddi_dma_unbind_handle(tmp_handle->dma_handle);
5653fb517f7SJames Moore ASSERT(rv == DDI_SUCCESS);
566*4c3888b8SHans Rosenfeld if (rv == DDI_SUCCESS) {
567*4c3888b8SHans Rosenfeld tmp_handle->num_cookies = 0;
568*4c3888b8SHans Rosenfeld tmp_handle->num_cookies_fetched = 0;
569*4c3888b8SHans Rosenfeld }
5703fb517f7SJames Moore }
5713fb517f7SJames Moore tmp_handle = tmp_handle->next;
5723fb517f7SJames Moore handle_count++;
5733fb517f7SJames Moore }
5743fb517f7SJames Moore /*
5753fb517f7SJames Moore * Insert this list into the free list
5763fb517f7SJames Moore */
5773fb517f7SJames Moore pool = qlt->qlt_dma_handle_pool;
5783fb517f7SJames Moore mutex_enter(&pool->pool_lock);
5793fb517f7SJames Moore last_handle->next = pool->free_list;
5803fb517f7SJames Moore pool->free_list = first_handle;
5813fb517f7SJames Moore pool->num_free += handle_count;
5823fb517f7SJames Moore mutex_exit(&pool->pool_lock);
5833fb517f7SJames Moore }
5843fb517f7SJames Moore
5853fb517f7SJames Moore /*
5863fb517f7SJames Moore * cookies produced by mapping this dbuf
5873fb517f7SJames Moore */
5883fb517f7SJames Moore uint16_t
qlt_get_cookie_count(stmf_data_buf_t * dbuf)5893fb517f7SJames Moore qlt_get_cookie_count(stmf_data_buf_t *dbuf)
5903fb517f7SJames Moore {
5913fb517f7SJames Moore qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
5923fb517f7SJames Moore
5933fb517f7SJames Moore ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
5943fb517f7SJames Moore return (qsgl->cookie_count);
5953fb517f7SJames Moore }
596fcf3ce44SJohn Forte
5973fb517f7SJames Moore ddi_dma_cookie_t
qlt_get_cookie_array(stmf_data_buf_t * dbuf)5983fb517f7SJames Moore *qlt_get_cookie_array(stmf_data_buf_t *dbuf)
5993fb517f7SJames Moore {
6003fb517f7SJames Moore qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
6013fb517f7SJames Moore
6023fb517f7SJames Moore ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
6033fb517f7SJames Moore
6043fb517f7SJames Moore if (qsgl->cookie_prefetched)
6053fb517f7SJames Moore return (&qsgl->cookie[0]);
6063fb517f7SJames Moore else
6073fb517f7SJames Moore return (NULL);
6083fb517f7SJames Moore }
6093fb517f7SJames Moore
6103fb517f7SJames Moore /*
6113fb517f7SJames Moore * Wrapper around ddi_dma_nextcookie that hides the ddi_dma_handle usage.
6123fb517f7SJames Moore */
6133fb517f7SJames Moore void
qlt_ddi_dma_nextcookie(stmf_data_buf_t * dbuf,ddi_dma_cookie_t * cookiep)6143fb517f7SJames Moore qlt_ddi_dma_nextcookie(stmf_data_buf_t *dbuf, ddi_dma_cookie_t *cookiep)
6153fb517f7SJames Moore {
6163fb517f7SJames Moore qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
6173fb517f7SJames Moore
6183fb517f7SJames Moore ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
6193fb517f7SJames Moore
6203fb517f7SJames Moore if (qsgl->cookie_prefetched) {
6213fb517f7SJames Moore ASSERT(qsgl->cookie_next_fetch < qsgl->cookie_count);
6223fb517f7SJames Moore *cookiep = qsgl->cookie[qsgl->cookie_next_fetch++];
6233fb517f7SJames Moore } else {
6243fb517f7SJames Moore qlt_dma_handle_t *fetch;
6253fb517f7SJames Moore qlt_dma_handle_t *FETCH_DONE = (qlt_dma_handle_t *)0xbad;
6263fb517f7SJames Moore
6273fb517f7SJames Moore ASSERT(qsgl->handle_list != NULL);
6283fb517f7SJames Moore ASSERT(qsgl->handle_next_fetch != FETCH_DONE);
6293fb517f7SJames Moore
6303fb517f7SJames Moore fetch = qsgl->handle_next_fetch;
6313fb517f7SJames Moore if (fetch->num_cookies_fetched == 0) {
6323fb517f7SJames Moore *cookiep = fetch->first_cookie;
6333fb517f7SJames Moore } else {
6343fb517f7SJames Moore ddi_dma_nextcookie(fetch->dma_handle, cookiep);
6353fb517f7SJames Moore }
6363fb517f7SJames Moore if (++fetch->num_cookies_fetched == fetch->num_cookies) {
6373fb517f7SJames Moore if (fetch->next == NULL)
6383fb517f7SJames Moore qsgl->handle_next_fetch = FETCH_DONE;
6393fb517f7SJames Moore else
6403fb517f7SJames Moore qsgl->handle_next_fetch = fetch->next;
6413fb517f7SJames Moore }
6423fb517f7SJames Moore }
6433fb517f7SJames Moore }
6443fb517f7SJames Moore
6453fb517f7SJames Moore /*
6463fb517f7SJames Moore * Set this flag to fetch the DDI dma cookies from the handles here and
6473fb517f7SJames Moore * store them in the port private area of the dbuf. This will allow
6483fb517f7SJames Moore * faster access to the cookies in qlt_xfer_scsi_data() at the expense of
6493fb517f7SJames Moore * an extra copy. If the qlt->req_lock is hot, this may help.
6503fb517f7SJames Moore */
651*4c3888b8SHans Rosenfeld uint16_t qlt_sgl_prefetch = 0;
6523fb517f7SJames Moore
6533fb517f7SJames Moore /*ARGSUSED*/
6543fb517f7SJames Moore stmf_status_t
qlt_dma_setup_dbuf(fct_local_port_t * port,stmf_data_buf_t * dbuf,uint32_t flags)6553fb517f7SJames Moore qlt_dma_setup_dbuf(fct_local_port_t *port, stmf_data_buf_t *dbuf,
6563fb517f7SJames Moore uint32_t flags)
6573fb517f7SJames Moore {
6583fb517f7SJames Moore qlt_state_t *qlt = port->port_fca_private;
6593fb517f7SJames Moore qlt_dma_sgl_t *qsgl;
6603fb517f7SJames Moore struct stmf_sglist_ent *sglp;
6613fb517f7SJames Moore qlt_dma_handle_t *handle_list, *th;
6623fb517f7SJames Moore int i, rv;
6633fb517f7SJames Moore ddi_dma_cookie_t *cookie_p;
664*4c3888b8SHans Rosenfeld int numbufs;
665*4c3888b8SHans Rosenfeld uint16_t cookie_count;
666*4c3888b8SHans Rosenfeld uint16_t prefetch;
6673fb517f7SJames Moore size_t qsize;
6683fb517f7SJames Moore
6693fb517f7SJames Moore /*
6703fb517f7SJames Moore * psuedo code:
6713fb517f7SJames Moore * get dma handle list from cache - one per sglist entry
6723fb517f7SJames Moore * foreach sglist entry
6733fb517f7SJames Moore * bind dma handle to sglist vaddr
6743fb517f7SJames Moore * allocate space for DMA state to store in db_port_private
6753fb517f7SJames Moore * fill in port private object
6763fb517f7SJames Moore * if prefetching
6773fb517f7SJames Moore * move all dma cookies into db_port_private
6783fb517f7SJames Moore */
6793fb517f7SJames Moore dbuf->db_port_private = NULL;
6803fb517f7SJames Moore numbufs = dbuf->db_sglist_length;
6813fb517f7SJames Moore handle_list = qlt_dma_alloc_handle_list(qlt, numbufs);
6823fb517f7SJames Moore if (handle_list == NULL) {
6833fb517f7SJames Moore EL(qlt, "handle_list==NULL\n");
6843fb517f7SJames Moore return (STMF_FAILURE);
6853fb517f7SJames Moore }
6863fb517f7SJames Moore /*
6873fb517f7SJames Moore * Loop through sglist and bind each entry to a handle
6883fb517f7SJames Moore */
6893fb517f7SJames Moore th = handle_list;
6903fb517f7SJames Moore sglp = &dbuf->db_sglist[0];
6913fb517f7SJames Moore cookie_count = 0;
6923fb517f7SJames Moore for (i = 0; i < numbufs; i++, sglp++) {
6933fb517f7SJames Moore
6943fb517f7SJames Moore /*
6953fb517f7SJames Moore * Bind this sgl entry to a DDI dma handle
6963fb517f7SJames Moore */
6973fb517f7SJames Moore if ((rv = ddi_dma_addr_bind_handle(
6983fb517f7SJames Moore th->dma_handle,
6993fb517f7SJames Moore NULL,
7003fb517f7SJames Moore (caddr_t)(sglp->seg_addr),
7013fb517f7SJames Moore (size_t)sglp->seg_length,
7023fb517f7SJames Moore DDI_DMA_RDWR | DDI_DMA_STREAMING,
7033fb517f7SJames Moore DDI_DMA_DONTWAIT,
7043fb517f7SJames Moore NULL,
7053fb517f7SJames Moore &th->first_cookie,
7063fb517f7SJames Moore &th->num_cookies)) != DDI_DMA_MAPPED) {
7073fb517f7SJames Moore cmn_err(CE_NOTE, "ddi_dma_addr_bind_handle %d", rv);
7083fb517f7SJames Moore qlt_dma_free_handles(qlt, handle_list);
7093fb517f7SJames Moore return (STMF_FAILURE);
7103fb517f7SJames Moore }
7113fb517f7SJames Moore
7123fb517f7SJames Moore /*
7133fb517f7SJames Moore * Add to total cookie count
7143fb517f7SJames Moore */
7153fb517f7SJames Moore cookie_count += th->num_cookies;
7163fb517f7SJames Moore if (cookie_count > QLT_DMA_SG_LIST_LENGTH) {
7173fb517f7SJames Moore /*
7183fb517f7SJames Moore * Request exceeds HBA limit
7193fb517f7SJames Moore */
7203fb517f7SJames Moore qlt_dma_free_handles(qlt, handle_list);
7213fb517f7SJames Moore return (STMF_FAILURE);
7223fb517f7SJames Moore }
7233fb517f7SJames Moore /* move to next ddi_dma_handle */
7243fb517f7SJames Moore th = th->next;
7253fb517f7SJames Moore }
7263fb517f7SJames Moore
7273fb517f7SJames Moore /*
7283fb517f7SJames Moore * Allocate our port private object for DMA mapping state.
7293fb517f7SJames Moore */
7303fb517f7SJames Moore prefetch = qlt_sgl_prefetch;
7313fb517f7SJames Moore qsize = sizeof (qlt_dma_sgl_t);
7323fb517f7SJames Moore if (prefetch) {
7333fb517f7SJames Moore /* one extra ddi_dma_cookie allocated for alignment padding */
7343fb517f7SJames Moore qsize += cookie_count * sizeof (ddi_dma_cookie_t);
7353fb517f7SJames Moore }
7363fb517f7SJames Moore qsgl = kmem_alloc(qsize, KM_SLEEP);
7373fb517f7SJames Moore /*
7383fb517f7SJames Moore * Fill in the sgl
7393fb517f7SJames Moore */
7403fb517f7SJames Moore dbuf->db_port_private = qsgl;
7413fb517f7SJames Moore qsgl->qsize = qsize;
7423fb517f7SJames Moore qsgl->handle_count = dbuf->db_sglist_length;
7433fb517f7SJames Moore qsgl->cookie_prefetched = prefetch;
7443fb517f7SJames Moore qsgl->cookie_count = cookie_count;
7453fb517f7SJames Moore qsgl->cookie_next_fetch = 0;
7463fb517f7SJames Moore qsgl->handle_list = handle_list;
7473fb517f7SJames Moore qsgl->handle_next_fetch = handle_list;
7483fb517f7SJames Moore if (prefetch) {
7493fb517f7SJames Moore /*
7503fb517f7SJames Moore * traverse handle list and move cookies to db_port_private
7513fb517f7SJames Moore */
7523fb517f7SJames Moore th = handle_list;
7533fb517f7SJames Moore cookie_p = &qsgl->cookie[0];
7543fb517f7SJames Moore for (i = 0; i < numbufs; i++) {
7553fb517f7SJames Moore uint_t cc = th->num_cookies;
7563fb517f7SJames Moore
7573fb517f7SJames Moore *cookie_p++ = th->first_cookie;
7583fb517f7SJames Moore while (--cc > 0) {
7593fb517f7SJames Moore ddi_dma_nextcookie(th->dma_handle, cookie_p++);
7603fb517f7SJames Moore }
7613fb517f7SJames Moore th->num_cookies_fetched = th->num_cookies;
7623fb517f7SJames Moore th = th->next;
7633fb517f7SJames Moore }
7643fb517f7SJames Moore }
7653fb517f7SJames Moore
7663fb517f7SJames Moore return (STMF_SUCCESS);
7673fb517f7SJames Moore }
7683fb517f7SJames Moore
7693fb517f7SJames Moore void
qlt_dma_teardown_dbuf(fct_dbuf_store_t * fds,stmf_data_buf_t * dbuf)7703fb517f7SJames Moore qlt_dma_teardown_dbuf(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf)
7713fb517f7SJames Moore {
7723fb517f7SJames Moore qlt_state_t *qlt = fds->fds_fca_private;
7733fb517f7SJames Moore qlt_dma_sgl_t *qsgl = dbuf->db_port_private;
7743fb517f7SJames Moore
7753fb517f7SJames Moore ASSERT(qlt);
7763fb517f7SJames Moore ASSERT(qsgl);
7773fb517f7SJames Moore ASSERT(dbuf->db_flags & DB_LU_DATA_BUF);
7783fb517f7SJames Moore
7793fb517f7SJames Moore /*
7803fb517f7SJames Moore * unbind and free the dma handles
7813fb517f7SJames Moore */
7823fb517f7SJames Moore if (qsgl->handle_list) {
7833fb517f7SJames Moore /* go through ddi handle list */
7843fb517f7SJames Moore qlt_dma_free_handles(qlt, qsgl->handle_list);
7853fb517f7SJames Moore }
7863fb517f7SJames Moore kmem_free(qsgl, qsgl->qsize);
7873fb517f7SJames Moore }
7883fb517f7SJames Moore
7893fb517f7SJames Moore uint8_t
qlt_get_iocb_count(uint32_t cookie_count)7903fb517f7SJames Moore qlt_get_iocb_count(uint32_t cookie_count)
7913fb517f7SJames Moore {
7923fb517f7SJames Moore uint32_t cnt, cont_segs;
7933fb517f7SJames Moore uint8_t iocb_count;
7943fb517f7SJames Moore
7953fb517f7SJames Moore iocb_count = 1;
7963fb517f7SJames Moore cnt = CMD7_2400_DATA_SEGMENTS;
7973fb517f7SJames Moore cont_segs = CONT_A64_DATA_SEGMENTS;
7983fb517f7SJames Moore
7993fb517f7SJames Moore if (cookie_count > cnt) {
8003fb517f7SJames Moore cnt = cookie_count - cnt;
8013fb517f7SJames Moore iocb_count = (uint8_t)(iocb_count + cnt / cont_segs);
8023fb517f7SJames Moore if (cnt % cont_segs) {
8033fb517f7SJames Moore iocb_count++;
8043fb517f7SJames Moore }
8053fb517f7SJames Moore }
8063fb517f7SJames Moore return (iocb_count);
807fcf3ce44SJohn Forte }
808