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