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