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

source code of linux/drivers/scsi/elx/efct/efct_io.c