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