xref: /openbmc/linux/drivers/scsi/elx/efct/efct_io.c (revision e2cf422ba833658c79681ba86b7c09988f3a0f28)
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