1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 QLogic Corporation. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 29 * Use is subject to license terms. 30 */ 31 32 #include <sys/conf.h> 33 #include <sys/ddi.h> 34 #include <sys/sunddi.h> 35 #include <sys/modctl.h> 36 37 #include <stmf_defines.h> 38 #include <fct_defines.h> 39 #include <stmf.h> 40 #include <portif.h> 41 #include <fct.h> 42 #include <qlt.h> 43 #include <qlt_dma.h> 44 45 #define BUF_COUNT_2K 2048 46 #define BUF_COUNT_8K 512 47 #define BUF_COUNT_64K 128 48 #define BUF_COUNT_128K 64 49 #define BUF_COUNT_256K 8 50 51 #define QLT_DMEM_MAX_BUF_SIZE (4 * 65536) 52 #define QLT_DMEM_NBUCKETS 5 53 static qlt_dmem_bucket_t bucket2K = { 2048, BUF_COUNT_2K }, 54 bucket8K = { 8192, BUF_COUNT_8K }, 55 bucket64K = { 65536, BUF_COUNT_64K }, 56 bucket128k = { (2 * 65536), BUF_COUNT_128K }, 57 bucket256k = { (4 * 65536), BUF_COUNT_256K }; 58 59 static qlt_dmem_bucket_t *dmem_buckets[] = { &bucket2K, &bucket8K, 60 &bucket64K, &bucket128k, &bucket256k, NULL }; 61 static ddi_device_acc_attr_t acc; 62 static ddi_dma_attr_t qlt_scsi_dma_attr = { 63 DMA_ATTR_V0, /* dma_attr_version */ 64 0, /* low DMA address range */ 65 0xffffffffffffffff, /* high DMA address range */ 66 0xffffffff, /* DMA counter register */ 67 8192, /* DMA address alignment */ 68 0xff, /* DMA burstsizes */ 69 1, /* min effective DMA size */ 70 0xffffffff, /* max DMA xfer size */ 71 0xffffffff, /* segment boundary */ 72 1, /* s/g list length */ 73 1, /* granularity of device */ 74 0 /* DMA transfer flags */ 75 }; 76 77 fct_status_t 78 qlt_dmem_init(qlt_state_t *qlt) 79 { 80 qlt_dmem_bucket_t *p; 81 qlt_dmem_bctl_t *bctl, *bc; 82 qlt_dmem_bctl_t *prev; 83 int ndx, i; 84 uint32_t total_mem; 85 uint8_t *addr; 86 uint8_t *host_addr; 87 uint64_t dev_addr; 88 ddi_dma_cookie_t cookie; 89 uint32_t ncookie; 90 uint32_t bsize; 91 size_t len; 92 93 if (qlt->qlt_bucketcnt[0] != 0) { 94 bucket2K.dmem_nbufs = qlt->qlt_bucketcnt[0]; 95 } 96 if (qlt->qlt_bucketcnt[1] != 0) { 97 bucket8K.dmem_nbufs = qlt->qlt_bucketcnt[1]; 98 } 99 if (qlt->qlt_bucketcnt[2] != 0) { 100 bucket64K.dmem_nbufs = qlt->qlt_bucketcnt[2]; 101 } 102 if (qlt->qlt_bucketcnt[3] != 0) { 103 bucket128k.dmem_nbufs = qlt->qlt_bucketcnt[3]; 104 } 105 if (qlt->qlt_bucketcnt[4] != 0) { 106 bucket256k.dmem_nbufs = qlt->qlt_bucketcnt[4]; 107 } 108 109 bsize = sizeof (dmem_buckets); 110 ndx = (int)(bsize / sizeof (void *)); 111 /* 112 * The reason it is ndx - 1 everywhere is becasue the last bucket 113 * pointer is NULL. 114 */ 115 qlt->dmem_buckets = (qlt_dmem_bucket_t **)kmem_zalloc(bsize + 116 ((ndx - 1) * (int)sizeof (qlt_dmem_bucket_t)), KM_SLEEP); 117 for (i = 0; i < (ndx - 1); i++) { 118 qlt->dmem_buckets[i] = (qlt_dmem_bucket_t *) 119 ((uint8_t *)qlt->dmem_buckets + bsize + 120 (i * (int)sizeof (qlt_dmem_bucket_t))); 121 bcopy(dmem_buckets[i], qlt->dmem_buckets[i], 122 sizeof (qlt_dmem_bucket_t)); 123 } 124 bzero(&acc, sizeof (acc)); 125 acc.devacc_attr_version = DDI_DEVICE_ATTR_V0; 126 acc.devacc_attr_endian_flags = DDI_NEVERSWAP_ACC; 127 acc.devacc_attr_dataorder = DDI_STRICTORDER_ACC; 128 for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) { 129 bctl = (qlt_dmem_bctl_t *)kmem_zalloc(p->dmem_nbufs * 130 sizeof (qlt_dmem_bctl_t), KM_NOSLEEP); 131 if (bctl == NULL) { 132 EL(qlt, "bctl==NULL\n"); 133 goto alloc_bctl_failed; 134 } 135 p->dmem_bctls_mem = bctl; 136 mutex_init(&p->dmem_lock, NULL, MUTEX_DRIVER, NULL); 137 if ((i = ddi_dma_alloc_handle(qlt->dip, &qlt_scsi_dma_attr, 138 DDI_DMA_SLEEP, 0, &p->dmem_dma_handle)) != DDI_SUCCESS) { 139 EL(qlt, "ddi_dma_alloc_handle status=%xh\n", i); 140 goto alloc_handle_failed; 141 } 142 143 total_mem = p->dmem_buf_size * p->dmem_nbufs; 144 145 if ((i = ddi_dma_mem_alloc(p->dmem_dma_handle, total_mem, &acc, 146 DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0, (caddr_t *)&addr, 147 &len, &p->dmem_acc_handle)) != DDI_SUCCESS) { 148 EL(qlt, "ddi_dma_mem_alloc status=%xh\n", i); 149 goto mem_alloc_failed; 150 } 151 152 if ((i = ddi_dma_addr_bind_handle(p->dmem_dma_handle, NULL, 153 (caddr_t)addr, total_mem, DDI_DMA_RDWR | DDI_DMA_STREAMING, 154 DDI_DMA_DONTWAIT, 0, &cookie, &ncookie)) != DDI_SUCCESS) { 155 EL(qlt, "ddi_dma_addr_bind_handle status=%xh\n", i); 156 goto addr_bind_handle_failed; 157 } 158 if (ncookie != 1) { 159 EL(qlt, "ncookie=%d\n", ncookie); 160 goto dmem_init_failed; 161 } 162 163 p->dmem_host_addr = host_addr = addr; 164 p->dmem_dev_addr = dev_addr = (uint64_t)cookie.dmac_laddress; 165 bsize = p->dmem_buf_size; 166 p->dmem_bctl_free_list = bctl; 167 p->dmem_nbufs_free = p->dmem_nbufs; 168 for (i = 0; i < p->dmem_nbufs; i++) { 169 stmf_data_buf_t *db; 170 prev = bctl; 171 bctl->bctl_bucket = p; 172 bctl->bctl_buf = db = stmf_alloc(STMF_STRUCT_DATA_BUF, 173 0, 0); 174 db->db_port_private = bctl; 175 db->db_sglist[0].seg_addr = host_addr; 176 bctl->bctl_dev_addr = dev_addr; 177 db->db_sglist[0].seg_length = db->db_buf_size = bsize; 178 db->db_sglist_length = 1; 179 host_addr += bsize; 180 dev_addr += bsize; 181 bctl++; 182 prev->bctl_next = bctl; 183 } 184 prev->bctl_next = NULL; 185 } 186 187 return (QLT_SUCCESS); 188 189 dmem_failure_loop:; 190 bc = bctl; 191 while (bc) { 192 stmf_free(bc->bctl_buf); 193 bc = bc->bctl_next; 194 } 195 dmem_init_failed:; 196 (void) ddi_dma_unbind_handle(p->dmem_dma_handle); 197 addr_bind_handle_failed:; 198 ddi_dma_mem_free(&p->dmem_acc_handle); 199 mem_alloc_failed:; 200 ddi_dma_free_handle(&p->dmem_dma_handle); 201 alloc_handle_failed:; 202 kmem_free(p->dmem_bctls_mem, p->dmem_nbufs * sizeof (qlt_dmem_bctl_t)); 203 mutex_destroy(&p->dmem_lock); 204 alloc_bctl_failed:; 205 if (--ndx >= 0) { 206 p = qlt->dmem_buckets[ndx]; 207 bctl = p->dmem_bctl_free_list; 208 goto dmem_failure_loop; 209 } 210 kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) + 211 ((sizeof (dmem_buckets)/sizeof (void *)) 212 *sizeof (qlt_dmem_bucket_t))); 213 qlt->dmem_buckets = NULL; 214 215 return (QLT_FAILURE); 216 } 217 218 void 219 qlt_dmem_fini(qlt_state_t *qlt) 220 { 221 qlt_dmem_bucket_t *p; 222 qlt_dmem_bctl_t *bctl; 223 int ndx; 224 225 for (ndx = 0; (p = qlt->dmem_buckets[ndx]) != NULL; ndx++) { 226 bctl = p->dmem_bctl_free_list; 227 while (bctl) { 228 stmf_free(bctl->bctl_buf); 229 bctl = bctl->bctl_next; 230 } 231 bctl = p->dmem_bctl_free_list; 232 (void) ddi_dma_unbind_handle(p->dmem_dma_handle); 233 ddi_dma_mem_free(&p->dmem_acc_handle); 234 ddi_dma_free_handle(&p->dmem_dma_handle); 235 kmem_free(p->dmem_bctls_mem, 236 p->dmem_nbufs * sizeof (qlt_dmem_bctl_t)); 237 mutex_destroy(&p->dmem_lock); 238 } 239 kmem_free(qlt->dmem_buckets, sizeof (dmem_buckets) + 240 (((sizeof (dmem_buckets)/sizeof (void *))-1)* 241 sizeof (qlt_dmem_bucket_t))); 242 qlt->dmem_buckets = NULL; 243 } 244 245 stmf_data_buf_t * 246 qlt_dmem_alloc(fct_local_port_t *port, uint32_t size, uint32_t *pminsize, 247 uint32_t flags) 248 { 249 return (qlt_i_dmem_alloc((qlt_state_t *) 250 port->port_fca_private, size, pminsize, 251 flags)); 252 } 253 254 /* ARGSUSED */ 255 stmf_data_buf_t * 256 qlt_i_dmem_alloc(qlt_state_t *qlt, uint32_t size, uint32_t *pminsize, 257 uint32_t flags) 258 { 259 qlt_dmem_bucket_t *p; 260 qlt_dmem_bctl_t *bctl; 261 int i; 262 263 if ((size <= QLT_DMEM_MAX_BUF_SIZE) && (size > 0)) { 264 265 for (i = 0; (p = qlt->dmem_buckets[i]) != NULL; i++) { 266 if (p->dmem_buf_size >= size) { 267 if (p->dmem_nbufs_free) { 268 mutex_enter(&p->dmem_lock); 269 bctl = p->dmem_bctl_free_list; 270 if (bctl == NULL) { 271 mutex_exit(&p->dmem_lock); 272 continue; 273 } 274 p->dmem_bctl_free_list = 275 bctl->bctl_next; 276 p->dmem_nbufs_free--; 277 qlt->qlt_bufref[i]++; 278 mutex_exit(&p->dmem_lock); 279 bctl->bctl_buf->db_data_size = size; 280 return (bctl->bctl_buf); 281 } else { 282 qlt->qlt_bumpbucket++; 283 } 284 } 285 } 286 } 287 288 *pminsize = QLT_DMEM_MAX_BUF_SIZE; 289 290 if (size <= 0x800) { 291 qlt->qlt_nullbufref[0]++; 292 } else if (size <= 0x2000) { 293 qlt->qlt_nullbufref[1]++; 294 } else if (size <= 0x10000) { 295 qlt->qlt_nullbufref[2]++; 296 } else if (size <= 0x20000) { 297 qlt->qlt_nullbufref[3]++; 298 } else { 299 qlt->qlt_nullbufref[4]++; 300 } 301 302 return (NULL); 303 } 304 305 /* ARGSUSED */ 306 void 307 qlt_i_dmem_free(qlt_state_t *qlt, stmf_data_buf_t *dbuf) 308 { 309 qlt_dmem_free(0, dbuf); 310 } 311 312 /* ARGSUSED */ 313 void 314 qlt_dmem_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf) 315 { 316 qlt_dmem_bctl_t *bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private; 317 qlt_dmem_bucket_t *p = bctl->bctl_bucket; 318 319 mutex_enter(&p->dmem_lock); 320 bctl->bctl_next = p->dmem_bctl_free_list; 321 p->dmem_bctl_free_list = bctl; 322 p->dmem_nbufs_free++; 323 mutex_exit(&p->dmem_lock); 324 } 325 326 void 327 qlt_dmem_dma_sync(stmf_data_buf_t *dbuf, uint_t sync_type) 328 { 329 qlt_dmem_bctl_t *bctl = (qlt_dmem_bctl_t *)dbuf->db_port_private; 330 qlt_dmem_bucket_t *p = bctl->bctl_bucket; 331 332 (void) ddi_dma_sync(p->dmem_dma_handle, (off_t) 333 (bctl->bctl_dev_addr - p->dmem_dev_addr), 334 dbuf->db_data_size, sync_type); 335 } 336