1*e2cf422bSJames Smart // SPDX-License-Identifier: GPL-2.0 2*e2cf422bSJames Smart /* 3*e2cf422bSJames Smart * Copyright (C) 2021 Broadcom. All Rights Reserved. The term 4*e2cf422bSJames Smart * “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 5*e2cf422bSJames Smart */ 6*e2cf422bSJames Smart 7*e2cf422bSJames Smart #include "efct_driver.h" 8*e2cf422bSJames Smart #include "efct_hw.h" 9*e2cf422bSJames Smart #include "efct_io.h" 10*e2cf422bSJames Smart 11*e2cf422bSJames Smart struct efct_io_pool { 12*e2cf422bSJames Smart struct efct *efct; 13*e2cf422bSJames Smart spinlock_t lock; /* IO pool lock */ 14*e2cf422bSJames Smart u32 io_num_ios; /* Total IOs allocated */ 15*e2cf422bSJames Smart struct efct_io *ios[EFCT_NUM_SCSI_IOS]; 16*e2cf422bSJames Smart struct list_head freelist; 17*e2cf422bSJames Smart 18*e2cf422bSJames Smart }; 19*e2cf422bSJames Smart 20*e2cf422bSJames Smart struct efct_io_pool * 21*e2cf422bSJames Smart efct_io_pool_create(struct efct *efct, u32 num_sgl) 22*e2cf422bSJames Smart { 23*e2cf422bSJames Smart u32 i = 0; 24*e2cf422bSJames Smart struct efct_io_pool *io_pool; 25*e2cf422bSJames Smart struct efct_io *io; 26*e2cf422bSJames Smart 27*e2cf422bSJames Smart /* Allocate the IO pool */ 28*e2cf422bSJames Smart io_pool = kzalloc(sizeof(*io_pool), GFP_KERNEL); 29*e2cf422bSJames Smart if (!io_pool) 30*e2cf422bSJames Smart return NULL; 31*e2cf422bSJames Smart 32*e2cf422bSJames Smart io_pool->efct = efct; 33*e2cf422bSJames Smart INIT_LIST_HEAD(&io_pool->freelist); 34*e2cf422bSJames Smart /* initialize IO pool lock */ 35*e2cf422bSJames Smart spin_lock_init(&io_pool->lock); 36*e2cf422bSJames Smart 37*e2cf422bSJames Smart for (i = 0; i < EFCT_NUM_SCSI_IOS; i++) { 38*e2cf422bSJames Smart io = kzalloc(sizeof(*io), GFP_KERNEL); 39*e2cf422bSJames Smart if (!io) 40*e2cf422bSJames Smart break; 41*e2cf422bSJames Smart 42*e2cf422bSJames Smart io_pool->io_num_ios++; 43*e2cf422bSJames Smart io_pool->ios[i] = io; 44*e2cf422bSJames Smart io->tag = i; 45*e2cf422bSJames Smart io->instance_index = i; 46*e2cf422bSJames Smart 47*e2cf422bSJames Smart /* Allocate a response buffer */ 48*e2cf422bSJames Smart io->rspbuf.size = SCSI_RSP_BUF_LENGTH; 49*e2cf422bSJames Smart io->rspbuf.virt = dma_alloc_coherent(&efct->pci->dev, 50*e2cf422bSJames Smart io->rspbuf.size, 51*e2cf422bSJames Smart &io->rspbuf.phys, GFP_DMA); 52*e2cf422bSJames Smart if (!io->rspbuf.virt) { 53*e2cf422bSJames Smart efc_log_err(efct, "dma_alloc rspbuf failed\n"); 54*e2cf422bSJames Smart efct_io_pool_free(io_pool); 55*e2cf422bSJames Smart return NULL; 56*e2cf422bSJames Smart } 57*e2cf422bSJames Smart 58*e2cf422bSJames Smart /* Allocate SGL */ 59*e2cf422bSJames Smart io->sgl = kzalloc(sizeof(*io->sgl) * num_sgl, GFP_KERNEL); 60*e2cf422bSJames Smart if (!io->sgl) { 61*e2cf422bSJames Smart efct_io_pool_free(io_pool); 62*e2cf422bSJames Smart return NULL; 63*e2cf422bSJames Smart } 64*e2cf422bSJames Smart 65*e2cf422bSJames Smart memset(io->sgl, 0, sizeof(*io->sgl) * num_sgl); 66*e2cf422bSJames Smart io->sgl_allocated = num_sgl; 67*e2cf422bSJames Smart io->sgl_count = 0; 68*e2cf422bSJames Smart 69*e2cf422bSJames Smart INIT_LIST_HEAD(&io->list_entry); 70*e2cf422bSJames Smart list_add_tail(&io->list_entry, &io_pool->freelist); 71*e2cf422bSJames Smart } 72*e2cf422bSJames Smart 73*e2cf422bSJames Smart return io_pool; 74*e2cf422bSJames Smart } 75*e2cf422bSJames Smart 76*e2cf422bSJames Smart int 77*e2cf422bSJames Smart efct_io_pool_free(struct efct_io_pool *io_pool) 78*e2cf422bSJames Smart { 79*e2cf422bSJames Smart struct efct *efct; 80*e2cf422bSJames Smart u32 i; 81*e2cf422bSJames Smart struct efct_io *io; 82*e2cf422bSJames Smart 83*e2cf422bSJames Smart if (io_pool) { 84*e2cf422bSJames Smart efct = io_pool->efct; 85*e2cf422bSJames Smart 86*e2cf422bSJames Smart for (i = 0; i < io_pool->io_num_ios; i++) { 87*e2cf422bSJames Smart io = io_pool->ios[i]; 88*e2cf422bSJames Smart if (!io) 89*e2cf422bSJames Smart continue; 90*e2cf422bSJames Smart 91*e2cf422bSJames Smart kfree(io->sgl); 92*e2cf422bSJames Smart dma_free_coherent(&efct->pci->dev, 93*e2cf422bSJames Smart io->rspbuf.size, io->rspbuf.virt, 94*e2cf422bSJames Smart io->rspbuf.phys); 95*e2cf422bSJames Smart memset(&io->rspbuf, 0, sizeof(struct efc_dma)); 96*e2cf422bSJames Smart } 97*e2cf422bSJames Smart 98*e2cf422bSJames Smart kfree(io_pool); 99*e2cf422bSJames Smart efct->xport->io_pool = NULL; 100*e2cf422bSJames Smart } 101*e2cf422bSJames Smart 102*e2cf422bSJames Smart return 0; 103*e2cf422bSJames Smart } 104*e2cf422bSJames Smart 105*e2cf422bSJames Smart struct efct_io * 106*e2cf422bSJames Smart efct_io_pool_io_alloc(struct efct_io_pool *io_pool) 107*e2cf422bSJames Smart { 108*e2cf422bSJames Smart struct efct_io *io = NULL; 109*e2cf422bSJames Smart struct efct *efct; 110*e2cf422bSJames Smart unsigned long flags = 0; 111*e2cf422bSJames Smart 112*e2cf422bSJames Smart efct = io_pool->efct; 113*e2cf422bSJames Smart 114*e2cf422bSJames Smart spin_lock_irqsave(&io_pool->lock, flags); 115*e2cf422bSJames Smart 116*e2cf422bSJames Smart if (!list_empty(&io_pool->freelist)) { 117*e2cf422bSJames Smart io = list_first_entry(&io_pool->freelist, struct efct_io, 118*e2cf422bSJames Smart list_entry); 119*e2cf422bSJames Smart list_del_init(&io->list_entry); 120*e2cf422bSJames Smart } 121*e2cf422bSJames Smart 122*e2cf422bSJames Smart spin_unlock_irqrestore(&io_pool->lock, flags); 123*e2cf422bSJames Smart 124*e2cf422bSJames Smart if (!io) 125*e2cf422bSJames Smart return NULL; 126*e2cf422bSJames Smart 127*e2cf422bSJames Smart io->io_type = EFCT_IO_TYPE_MAX; 128*e2cf422bSJames Smart io->hio_type = EFCT_HW_IO_MAX; 129*e2cf422bSJames Smart io->hio = NULL; 130*e2cf422bSJames Smart io->transferred = 0; 131*e2cf422bSJames Smart io->efct = efct; 132*e2cf422bSJames Smart io->timeout = 0; 133*e2cf422bSJames Smart io->sgl_count = 0; 134*e2cf422bSJames Smart io->tgt_task_tag = 0; 135*e2cf422bSJames Smart io->init_task_tag = 0; 136*e2cf422bSJames Smart io->hw_tag = 0; 137*e2cf422bSJames Smart io->display_name = "pending"; 138*e2cf422bSJames Smart io->seq_init = 0; 139*e2cf422bSJames Smart io->io_free = 0; 140*e2cf422bSJames Smart io->release = NULL; 141*e2cf422bSJames Smart atomic_add_return(1, &efct->xport->io_active_count); 142*e2cf422bSJames Smart atomic_add_return(1, &efct->xport->io_total_alloc); 143*e2cf422bSJames Smart return io; 144*e2cf422bSJames Smart } 145*e2cf422bSJames Smart 146*e2cf422bSJames Smart /* Free an object used to track an IO */ 147*e2cf422bSJames Smart void 148*e2cf422bSJames Smart efct_io_pool_io_free(struct efct_io_pool *io_pool, struct efct_io *io) 149*e2cf422bSJames Smart { 150*e2cf422bSJames Smart struct efct *efct; 151*e2cf422bSJames Smart struct efct_hw_io *hio = NULL; 152*e2cf422bSJames Smart unsigned long flags = 0; 153*e2cf422bSJames Smart 154*e2cf422bSJames Smart efct = io_pool->efct; 155*e2cf422bSJames Smart 156*e2cf422bSJames Smart spin_lock_irqsave(&io_pool->lock, flags); 157*e2cf422bSJames Smart hio = io->hio; 158*e2cf422bSJames Smart io->hio = NULL; 159*e2cf422bSJames Smart io->io_free = 1; 160*e2cf422bSJames Smart INIT_LIST_HEAD(&io->list_entry); 161*e2cf422bSJames Smart list_add(&io->list_entry, &io_pool->freelist); 162*e2cf422bSJames Smart spin_unlock_irqrestore(&io_pool->lock, flags); 163*e2cf422bSJames Smart 164*e2cf422bSJames Smart if (hio) 165*e2cf422bSJames Smart efct_hw_io_free(&efct->hw, hio); 166*e2cf422bSJames Smart 167*e2cf422bSJames Smart atomic_sub_return(1, &efct->xport->io_active_count); 168*e2cf422bSJames Smart atomic_add_return(1, &efct->xport->io_total_free); 169*e2cf422bSJames Smart } 170*e2cf422bSJames Smart 171*e2cf422bSJames Smart /* Find an I/O given it's node and ox_id */ 172*e2cf422bSJames Smart struct efct_io * 173*e2cf422bSJames Smart efct_io_find_tgt_io(struct efct *efct, struct efct_node *node, 174*e2cf422bSJames Smart u16 ox_id, u16 rx_id) 175*e2cf422bSJames Smart { 176*e2cf422bSJames Smart struct efct_io *io = NULL; 177*e2cf422bSJames Smart unsigned long flags = 0; 178*e2cf422bSJames Smart u8 found = false; 179*e2cf422bSJames Smart 180*e2cf422bSJames Smart spin_lock_irqsave(&node->active_ios_lock, flags); 181*e2cf422bSJames Smart list_for_each_entry(io, &node->active_ios, list_entry) { 182*e2cf422bSJames Smart if ((io->cmd_tgt && io->init_task_tag == ox_id) && 183*e2cf422bSJames Smart (rx_id == 0xffff || io->tgt_task_tag == rx_id)) { 184*e2cf422bSJames Smart if (kref_get_unless_zero(&io->ref)) 185*e2cf422bSJames Smart found = true; 186*e2cf422bSJames Smart break; 187*e2cf422bSJames Smart } 188*e2cf422bSJames Smart } 189*e2cf422bSJames Smart spin_unlock_irqrestore(&node->active_ios_lock, flags); 190*e2cf422bSJames Smart return found ? io : NULL; 191*e2cf422bSJames Smart } 192