xref: /freebsd/sys/dev/ocs_fc/ocs_io.c (revision ef270ab1b656486947b3b4aaec9bc0a6b5d6af21)
1*ef270ab1SKenneth D. Merry /*-
2*ef270ab1SKenneth D. Merry  * Copyright (c) 2017 Broadcom. All rights reserved.
3*ef270ab1SKenneth D. Merry  * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4*ef270ab1SKenneth D. Merry  *
5*ef270ab1SKenneth D. Merry  * Redistribution and use in source and binary forms, with or without
6*ef270ab1SKenneth D. Merry  * modification, are permitted provided that the following conditions are met:
7*ef270ab1SKenneth D. Merry  *
8*ef270ab1SKenneth D. Merry  * 1. Redistributions of source code must retain the above copyright notice,
9*ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer.
10*ef270ab1SKenneth D. Merry  *
11*ef270ab1SKenneth D. Merry  * 2. Redistributions in binary form must reproduce the above copyright notice,
12*ef270ab1SKenneth D. Merry  *    this list of conditions and the following disclaimer in the documentation
13*ef270ab1SKenneth D. Merry  *    and/or other materials provided with the distribution.
14*ef270ab1SKenneth D. Merry  *
15*ef270ab1SKenneth D. Merry  * 3. Neither the name of the copyright holder nor the names of its contributors
16*ef270ab1SKenneth D. Merry  *    may be used to endorse or promote products derived from this software
17*ef270ab1SKenneth D. Merry  *    without specific prior written permission.
18*ef270ab1SKenneth D. Merry  *
19*ef270ab1SKenneth D. Merry  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20*ef270ab1SKenneth D. Merry  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*ef270ab1SKenneth D. Merry  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*ef270ab1SKenneth D. Merry  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23*ef270ab1SKenneth D. Merry  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24*ef270ab1SKenneth D. Merry  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25*ef270ab1SKenneth D. Merry  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26*ef270ab1SKenneth D. Merry  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27*ef270ab1SKenneth D. Merry  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28*ef270ab1SKenneth D. Merry  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29*ef270ab1SKenneth D. Merry  * POSSIBILITY OF SUCH DAMAGE.
30*ef270ab1SKenneth D. Merry  *
31*ef270ab1SKenneth D. Merry  * $FreeBSD$
32*ef270ab1SKenneth D. Merry  */
33*ef270ab1SKenneth D. Merry 
34*ef270ab1SKenneth D. Merry /**
35*ef270ab1SKenneth D. Merry  * @file
36*ef270ab1SKenneth D. Merry  * Provide IO object allocation.
37*ef270ab1SKenneth D. Merry  */
38*ef270ab1SKenneth D. Merry 
39*ef270ab1SKenneth D. Merry /*!
40*ef270ab1SKenneth D. Merry  * @defgroup io_alloc IO allocation
41*ef270ab1SKenneth D. Merry  */
42*ef270ab1SKenneth D. Merry 
43*ef270ab1SKenneth D. Merry #include "ocs.h"
44*ef270ab1SKenneth D. Merry #include "ocs_scsi.h"
45*ef270ab1SKenneth D. Merry #include "ocs_els.h"
46*ef270ab1SKenneth D. Merry #include "ocs_utils.h"
47*ef270ab1SKenneth D. Merry 
48*ef270ab1SKenneth D. Merry void ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *io);
49*ef270ab1SKenneth D. Merry void ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *io);
50*ef270ab1SKenneth D. Merry int ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *io);
51*ef270ab1SKenneth D. Merry 
52*ef270ab1SKenneth D. Merry static ocs_mgmt_functions_t io_mgmt_functions = {
53*ef270ab1SKenneth D. Merry 	.get_list_handler	=	ocs_mgmt_io_list,
54*ef270ab1SKenneth D. Merry 	.get_handler		=	ocs_mgmt_io_get,
55*ef270ab1SKenneth D. Merry 	.get_all_handler	=	ocs_mgmt_io_get_all,
56*ef270ab1SKenneth D. Merry };
57*ef270ab1SKenneth D. Merry 
58*ef270ab1SKenneth D. Merry /**
59*ef270ab1SKenneth D. Merry  * @brief IO pool.
60*ef270ab1SKenneth D. Merry  *
61*ef270ab1SKenneth D. Merry  * Structure encapsulating a pool of IO objects.
62*ef270ab1SKenneth D. Merry  *
63*ef270ab1SKenneth D. Merry  */
64*ef270ab1SKenneth D. Merry 
65*ef270ab1SKenneth D. Merry struct ocs_io_pool_s {
66*ef270ab1SKenneth D. Merry 	ocs_t *ocs;			/* Pointer to device object */
67*ef270ab1SKenneth D. Merry 	ocs_lock_t lock;		/* IO pool lock */
68*ef270ab1SKenneth D. Merry 	uint32_t io_num_ios;		/* Total IOs allocated */
69*ef270ab1SKenneth D. Merry 	ocs_pool_t *pool;
70*ef270ab1SKenneth D. Merry };
71*ef270ab1SKenneth D. Merry 
72*ef270ab1SKenneth D. Merry /**
73*ef270ab1SKenneth D. Merry  * @brief Create a pool of IO objects.
74*ef270ab1SKenneth D. Merry  *
75*ef270ab1SKenneth D. Merry  * @par Description
76*ef270ab1SKenneth D. Merry  * This function allocates memory in larger chucks called
77*ef270ab1SKenneth D. Merry  * "slabs" which are a fixed size. It calculates the number of IO objects that
78*ef270ab1SKenneth D. Merry  * fit within each "slab" and determines the number of "slabs" required to
79*ef270ab1SKenneth D. Merry  * allocate the number of IOs requested. Each of the slabs is allocated and
80*ef270ab1SKenneth D. Merry  * then it grabs each IO object within the slab and adds it to the free list.
81*ef270ab1SKenneth D. Merry  * Individual command, response and SGL DMA buffers are allocated for each IO.
82*ef270ab1SKenneth D. Merry  *
83*ef270ab1SKenneth D. Merry  *           "Slabs"
84*ef270ab1SKenneth D. Merry  *      +----------------+
85*ef270ab1SKenneth D. Merry  *      |                |
86*ef270ab1SKenneth D. Merry  *   +----------------+  |
87*ef270ab1SKenneth D. Merry  *   |    IO          |  |
88*ef270ab1SKenneth D. Merry  *   +----------------+  |
89*ef270ab1SKenneth D. Merry  *   |    ...         |  |
90*ef270ab1SKenneth D. Merry  *   +----------------+__+
91*ef270ab1SKenneth D. Merry  *   |    IO          |
92*ef270ab1SKenneth D. Merry  *   +----------------+
93*ef270ab1SKenneth D. Merry  *
94*ef270ab1SKenneth D. Merry  * @param ocs Driver instance's software context.
95*ef270ab1SKenneth D. Merry  * @param num_io Number of IO contexts to allocate.
96*ef270ab1SKenneth D. Merry  * @param num_sgl Number of SGL entries to allocate for each IO.
97*ef270ab1SKenneth D. Merry  *
98*ef270ab1SKenneth D. Merry  * @return Returns a pointer to a new ocs_io_pool_t on success,
99*ef270ab1SKenneth D. Merry  *         or NULL on failure.
100*ef270ab1SKenneth D. Merry  */
101*ef270ab1SKenneth D. Merry 
102*ef270ab1SKenneth D. Merry ocs_io_pool_t *
103*ef270ab1SKenneth D. Merry ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl)
104*ef270ab1SKenneth D. Merry {
105*ef270ab1SKenneth D. Merry 	uint32_t i = 0;
106*ef270ab1SKenneth D. Merry 	int32_t	rc = -1;
107*ef270ab1SKenneth D. Merry 	ocs_io_pool_t *io_pool;
108*ef270ab1SKenneth D. Merry 
109*ef270ab1SKenneth D. Merry 	/* Allocate the IO pool */
110*ef270ab1SKenneth D. Merry 	io_pool = ocs_malloc(ocs, sizeof(*io_pool), OCS_M_ZERO | OCS_M_NOWAIT);
111*ef270ab1SKenneth D. Merry 	if (io_pool == NULL) {
112*ef270ab1SKenneth D. Merry 		ocs_log_err(ocs, "allocate of IO pool failed\n");
113*ef270ab1SKenneth D. Merry 		return NULL;;
114*ef270ab1SKenneth D. Merry 	}
115*ef270ab1SKenneth D. Merry 
116*ef270ab1SKenneth D. Merry 	io_pool->ocs = ocs;
117*ef270ab1SKenneth D. Merry 	io_pool->io_num_ios = num_io;
118*ef270ab1SKenneth D. Merry 
119*ef270ab1SKenneth D. Merry 	/* initialize IO pool lock */
120*ef270ab1SKenneth D. Merry 	ocs_lock_init(ocs, &io_pool->lock, "io_pool lock[%d]", ocs->instance_index);
121*ef270ab1SKenneth D. Merry 
122*ef270ab1SKenneth D. Merry 	io_pool->pool = ocs_pool_alloc(ocs, sizeof(ocs_io_t), io_pool->io_num_ios, FALSE);
123*ef270ab1SKenneth D. Merry 
124*ef270ab1SKenneth D. Merry 	for (i = 0; i < io_pool->io_num_ios; i++) {
125*ef270ab1SKenneth D. Merry 		ocs_io_t *io = ocs_pool_get_instance(io_pool->pool, i);
126*ef270ab1SKenneth D. Merry 
127*ef270ab1SKenneth D. Merry 		io->tag = i;
128*ef270ab1SKenneth D. Merry 		io->instance_index = i;
129*ef270ab1SKenneth D. Merry 		io->ocs = ocs;
130*ef270ab1SKenneth D. Merry 
131*ef270ab1SKenneth D. Merry 		/* allocate a command/response dma buffer */
132*ef270ab1SKenneth D. Merry 		if (ocs->enable_ini) {
133*ef270ab1SKenneth D. Merry 			rc = ocs_dma_alloc(ocs, &io->cmdbuf, SCSI_CMD_BUF_LENGTH, OCS_MIN_DMA_ALIGNMENT);
134*ef270ab1SKenneth D. Merry 			if (rc) {
135*ef270ab1SKenneth D. Merry 				ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n");
136*ef270ab1SKenneth D. Merry 				ocs_io_pool_free(io_pool);
137*ef270ab1SKenneth D. Merry 				return NULL;
138*ef270ab1SKenneth D. Merry 			}
139*ef270ab1SKenneth D. Merry 		}
140*ef270ab1SKenneth D. Merry 
141*ef270ab1SKenneth D. Merry 		/* Allocate a response buffer */
142*ef270ab1SKenneth D. Merry 		rc = ocs_dma_alloc(ocs, &io->rspbuf, SCSI_RSP_BUF_LENGTH, OCS_MIN_DMA_ALIGNMENT);
143*ef270ab1SKenneth D. Merry 		if (rc) {
144*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n");
145*ef270ab1SKenneth D. Merry 			ocs_io_pool_free(io_pool);
146*ef270ab1SKenneth D. Merry 			return NULL;
147*ef270ab1SKenneth D. Merry 		}
148*ef270ab1SKenneth D. Merry 
149*ef270ab1SKenneth D. Merry 		/* Allocate SGL */
150*ef270ab1SKenneth D. Merry 		io->sgl = ocs_malloc(ocs, sizeof(*io->sgl) * num_sgl, OCS_M_NOWAIT | OCS_M_ZERO);
151*ef270ab1SKenneth D. Merry 		if (io->sgl == NULL) {
152*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "malloc sgl's failed\n");
153*ef270ab1SKenneth D. Merry 			ocs_io_pool_free(io_pool);
154*ef270ab1SKenneth D. Merry 			return NULL;
155*ef270ab1SKenneth D. Merry 		}
156*ef270ab1SKenneth D. Merry 		io->sgl_allocated = num_sgl;
157*ef270ab1SKenneth D. Merry 		io->sgl_count = 0;
158*ef270ab1SKenneth D. Merry 
159*ef270ab1SKenneth D. Merry 		/* Make IO backend call to initialize IO */
160*ef270ab1SKenneth D. Merry 		ocs_scsi_tgt_io_init(io);
161*ef270ab1SKenneth D. Merry 		ocs_scsi_ini_io_init(io);
162*ef270ab1SKenneth D. Merry 
163*ef270ab1SKenneth D. Merry 		rc = ocs_dma_alloc(ocs, &io->els_req, OCS_ELS_REQ_LEN, OCS_MIN_DMA_ALIGNMENT);
164*ef270ab1SKenneth D. Merry 		if (rc) {
165*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_dma_alloc els_req failed\n");
166*ef270ab1SKenneth D. Merry 			ocs_io_pool_free(io_pool);
167*ef270ab1SKenneth D. Merry 			return NULL;
168*ef270ab1SKenneth D. Merry  		}
169*ef270ab1SKenneth D. Merry 
170*ef270ab1SKenneth D. Merry 		rc = ocs_dma_alloc(ocs, &io->els_rsp, OCS_ELS_GID_PT_RSP_LEN, OCS_MIN_DMA_ALIGNMENT);
171*ef270ab1SKenneth D. Merry 		if (rc) {
172*ef270ab1SKenneth D. Merry 			ocs_log_err(ocs, "ocs_dma_alloc els_rsp failed\n");
173*ef270ab1SKenneth D. Merry 			ocs_io_pool_free(io_pool);
174*ef270ab1SKenneth D. Merry 			return NULL;
175*ef270ab1SKenneth D. Merry  		}
176*ef270ab1SKenneth D. Merry 	}
177*ef270ab1SKenneth D. Merry 
178*ef270ab1SKenneth D. Merry 	return io_pool;
179*ef270ab1SKenneth D. Merry }
180*ef270ab1SKenneth D. Merry 
181*ef270ab1SKenneth D. Merry /**
182*ef270ab1SKenneth D. Merry  * @brief Free IO objects pool
183*ef270ab1SKenneth D. Merry  *
184*ef270ab1SKenneth D. Merry  * @par Description
185*ef270ab1SKenneth D. Merry  * The pool of IO objects are freed.
186*ef270ab1SKenneth D. Merry  *
187*ef270ab1SKenneth D. Merry  * @param io_pool Pointer to IO pool object.
188*ef270ab1SKenneth D. Merry  *
189*ef270ab1SKenneth D. Merry  * @return Returns 0 on success, or a negative error code value on failure.
190*ef270ab1SKenneth D. Merry  */
191*ef270ab1SKenneth D. Merry int32_t
192*ef270ab1SKenneth D. Merry ocs_io_pool_free(ocs_io_pool_t *io_pool)
193*ef270ab1SKenneth D. Merry {
194*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
195*ef270ab1SKenneth D. Merry 	uint32_t i;
196*ef270ab1SKenneth D. Merry 	ocs_io_t *io;
197*ef270ab1SKenneth D. Merry 
198*ef270ab1SKenneth D. Merry 	if (io_pool != NULL) {
199*ef270ab1SKenneth D. Merry 		ocs = io_pool->ocs;
200*ef270ab1SKenneth D. Merry 		for (i = 0; i < io_pool->io_num_ios; i++) {
201*ef270ab1SKenneth D. Merry 			io = ocs_pool_get_instance(io_pool->pool, i);
202*ef270ab1SKenneth D. Merry 			if (!io)
203*ef270ab1SKenneth D. Merry 				continue;
204*ef270ab1SKenneth D. Merry 			ocs_scsi_tgt_io_exit(io);
205*ef270ab1SKenneth D. Merry 			ocs_scsi_ini_io_exit(io);
206*ef270ab1SKenneth D. Merry 			if (io->sgl) {
207*ef270ab1SKenneth D. Merry 				ocs_free(ocs, io->sgl, sizeof(*io->sgl) * io->sgl_allocated);
208*ef270ab1SKenneth D. Merry 			}
209*ef270ab1SKenneth D. Merry 			ocs_dma_free(ocs, &io->cmdbuf);
210*ef270ab1SKenneth D. Merry 			ocs_dma_free(ocs, &io->rspbuf);
211*ef270ab1SKenneth D. Merry 			ocs_dma_free(ocs, &io->els_req);
212*ef270ab1SKenneth D. Merry 			ocs_dma_free(ocs, &io->els_rsp);
213*ef270ab1SKenneth D. Merry 		}
214*ef270ab1SKenneth D. Merry 
215*ef270ab1SKenneth D. Merry 		if (io_pool->pool != NULL) {
216*ef270ab1SKenneth D. Merry 			ocs_pool_free(io_pool->pool);
217*ef270ab1SKenneth D. Merry 		}
218*ef270ab1SKenneth D. Merry 		ocs_lock_free(&io_pool->lock);
219*ef270ab1SKenneth D. Merry 		ocs_free(ocs, io_pool, sizeof(*io_pool));
220*ef270ab1SKenneth D. Merry 		ocs->xport->io_pool = NULL;
221*ef270ab1SKenneth D. Merry 	}
222*ef270ab1SKenneth D. Merry 
223*ef270ab1SKenneth D. Merry 	return 0;
224*ef270ab1SKenneth D. Merry }
225*ef270ab1SKenneth D. Merry 
226*ef270ab1SKenneth D. Merry uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool)
227*ef270ab1SKenneth D. Merry {
228*ef270ab1SKenneth D. Merry 	return io_pool->io_num_ios;
229*ef270ab1SKenneth D. Merry }
230*ef270ab1SKenneth D. Merry 
231*ef270ab1SKenneth D. Merry /**
232*ef270ab1SKenneth D. Merry  * @ingroup io_alloc
233*ef270ab1SKenneth D. Merry  * @brief Allocate an object used to track an IO.
234*ef270ab1SKenneth D. Merry  *
235*ef270ab1SKenneth D. Merry  * @param io_pool Pointer to the IO pool.
236*ef270ab1SKenneth D. Merry  *
237*ef270ab1SKenneth D. Merry  * @return Returns the pointer to a new object, or NULL if none available.
238*ef270ab1SKenneth D. Merry  */
239*ef270ab1SKenneth D. Merry ocs_io_t *
240*ef270ab1SKenneth D. Merry ocs_io_pool_io_alloc(ocs_io_pool_t *io_pool)
241*ef270ab1SKenneth D. Merry {
242*ef270ab1SKenneth D. Merry 	ocs_io_t *io = NULL;
243*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
244*ef270ab1SKenneth D. Merry 
245*ef270ab1SKenneth D. Merry 	ocs_assert(io_pool, NULL);
246*ef270ab1SKenneth D. Merry 
247*ef270ab1SKenneth D. Merry 	ocs = io_pool->ocs;
248*ef270ab1SKenneth D. Merry 
249*ef270ab1SKenneth D. Merry 	ocs_lock(&io_pool->lock);
250*ef270ab1SKenneth D. Merry 	if ((io = ocs_pool_get(io_pool->pool)) != NULL) {
251*ef270ab1SKenneth D. Merry 		ocs_unlock(&io_pool->lock);
252*ef270ab1SKenneth D. Merry 
253*ef270ab1SKenneth D. Merry 		io->io_type = OCS_IO_TYPE_MAX;
254*ef270ab1SKenneth D. Merry 		io->hio_type = OCS_HW_IO_MAX;
255*ef270ab1SKenneth D. Merry 		io->hio = NULL;
256*ef270ab1SKenneth D. Merry 		io->transferred = 0;
257*ef270ab1SKenneth D. Merry 		io->ocs = ocs;
258*ef270ab1SKenneth D. Merry 		io->timeout = 0;
259*ef270ab1SKenneth D. Merry 		io->sgl_count = 0;
260*ef270ab1SKenneth D. Merry 		io->tgt_task_tag = 0;
261*ef270ab1SKenneth D. Merry 		io->init_task_tag = 0;
262*ef270ab1SKenneth D. Merry 		io->hw_tag = 0;
263*ef270ab1SKenneth D. Merry 		io->display_name = "pending";
264*ef270ab1SKenneth D. Merry 		io->seq_init = 0;
265*ef270ab1SKenneth D. Merry 		io->els_req_free = 0;
266*ef270ab1SKenneth D. Merry 		io->mgmt_functions = &io_mgmt_functions;
267*ef270ab1SKenneth D. Merry 		io->io_free = 0;
268*ef270ab1SKenneth D. Merry 		ocs_atomic_add_return(&ocs->xport->io_active_count, 1);
269*ef270ab1SKenneth D. Merry 		ocs_atomic_add_return(&ocs->xport->io_total_alloc, 1);
270*ef270ab1SKenneth D. Merry 	} else {
271*ef270ab1SKenneth D. Merry 		ocs_unlock(&io_pool->lock);
272*ef270ab1SKenneth D. Merry 	}
273*ef270ab1SKenneth D. Merry 	return io;
274*ef270ab1SKenneth D. Merry }
275*ef270ab1SKenneth D. Merry 
276*ef270ab1SKenneth D. Merry /**
277*ef270ab1SKenneth D. Merry  * @ingroup io_alloc
278*ef270ab1SKenneth D. Merry  * @brief Free an object used to track an IO.
279*ef270ab1SKenneth D. Merry  *
280*ef270ab1SKenneth D. Merry  * @param io_pool Pointer to IO pool object.
281*ef270ab1SKenneth D. Merry  * @param io Pointer to the IO object.
282*ef270ab1SKenneth D. Merry  */
283*ef270ab1SKenneth D. Merry void
284*ef270ab1SKenneth D. Merry ocs_io_pool_io_free(ocs_io_pool_t *io_pool, ocs_io_t *io)
285*ef270ab1SKenneth D. Merry {
286*ef270ab1SKenneth D. Merry 	ocs_t *ocs;
287*ef270ab1SKenneth D. Merry 	ocs_hw_io_t *hio = NULL;
288*ef270ab1SKenneth D. Merry 
289*ef270ab1SKenneth D. Merry 	ocs_assert(io_pool);
290*ef270ab1SKenneth D. Merry 
291*ef270ab1SKenneth D. Merry 	ocs = io_pool->ocs;
292*ef270ab1SKenneth D. Merry 
293*ef270ab1SKenneth D. Merry 	ocs_lock(&io_pool->lock);
294*ef270ab1SKenneth D. Merry 		hio = io->hio;
295*ef270ab1SKenneth D. Merry 		io->hio = NULL;
296*ef270ab1SKenneth D. Merry 		ocs_pool_put(io_pool->pool, io);
297*ef270ab1SKenneth D. Merry 	ocs_unlock(&io_pool->lock);
298*ef270ab1SKenneth D. Merry 
299*ef270ab1SKenneth D. Merry 	if (hio) {
300*ef270ab1SKenneth D. Merry 		ocs_hw_io_free(&ocs->hw, hio);
301*ef270ab1SKenneth D. Merry 	}
302*ef270ab1SKenneth D. Merry 	io->io_free = 1;
303*ef270ab1SKenneth D. Merry 	ocs_atomic_sub_return(&ocs->xport->io_active_count, 1);
304*ef270ab1SKenneth D. Merry 	ocs_atomic_add_return(&ocs->xport->io_total_free, 1);
305*ef270ab1SKenneth D. Merry }
306*ef270ab1SKenneth D. Merry 
307*ef270ab1SKenneth D. Merry /**
308*ef270ab1SKenneth D. Merry  * @ingroup io_alloc
309*ef270ab1SKenneth D. Merry  * @brief Find an I/O given it's node and ox_id.
310*ef270ab1SKenneth D. Merry  *
311*ef270ab1SKenneth D. Merry  * @param ocs Driver instance's software context.
312*ef270ab1SKenneth D. Merry  * @param node Pointer to node.
313*ef270ab1SKenneth D. Merry  * @param ox_id OX_ID to find.
314*ef270ab1SKenneth D. Merry  * @param rx_id RX_ID to find (0xffff for unassigned).
315*ef270ab1SKenneth D. Merry  */
316*ef270ab1SKenneth D. Merry ocs_io_t *
317*ef270ab1SKenneth D. Merry ocs_io_find_tgt_io(ocs_t *ocs, ocs_node_t *node, uint16_t ox_id, uint16_t rx_id)
318*ef270ab1SKenneth D. Merry {
319*ef270ab1SKenneth D. Merry 	ocs_io_t	*io = NULL;
320*ef270ab1SKenneth D. Merry 
321*ef270ab1SKenneth D. Merry 	ocs_lock(&node->active_ios_lock);
322*ef270ab1SKenneth D. Merry 		ocs_list_foreach(&node->active_ios, io)
323*ef270ab1SKenneth D. Merry 			if ((io->cmd_tgt && (io->init_task_tag == ox_id)) &&
324*ef270ab1SKenneth D. Merry 			    ((rx_id == 0xffff) || (io->tgt_task_tag == rx_id))) {
325*ef270ab1SKenneth D. Merry 				break;
326*ef270ab1SKenneth D. Merry 			}
327*ef270ab1SKenneth D. Merry 	ocs_unlock(&node->active_ios_lock);
328*ef270ab1SKenneth D. Merry 	return io;
329*ef270ab1SKenneth D. Merry }
330*ef270ab1SKenneth D. Merry 
331*ef270ab1SKenneth D. Merry /**
332*ef270ab1SKenneth D. Merry  * @ingroup io_alloc
333*ef270ab1SKenneth D. Merry  * @brief Return IO context given the instance index.
334*ef270ab1SKenneth D. Merry  *
335*ef270ab1SKenneth D. Merry  * @par Description
336*ef270ab1SKenneth D. Merry  * Returns a pointer to the IO context given by the instance index.
337*ef270ab1SKenneth D. Merry  *
338*ef270ab1SKenneth D. Merry  * @param ocs Pointer to driver structure.
339*ef270ab1SKenneth D. Merry  * @param index IO instance index to return.
340*ef270ab1SKenneth D. Merry  *
341*ef270ab1SKenneth D. Merry  * @return Returns a pointer to the IO context, or NULL if not found.
342*ef270ab1SKenneth D. Merry  */
343*ef270ab1SKenneth D. Merry ocs_io_t *
344*ef270ab1SKenneth D. Merry ocs_io_get_instance(ocs_t *ocs, uint32_t index)
345*ef270ab1SKenneth D. Merry {
346*ef270ab1SKenneth D. Merry 	ocs_xport_t *xport = ocs->xport;
347*ef270ab1SKenneth D. Merry 	ocs_io_pool_t *io_pool = xport->io_pool;
348*ef270ab1SKenneth D. Merry 	return ocs_pool_get_instance(io_pool->pool, index);
349*ef270ab1SKenneth D. Merry }
350*ef270ab1SKenneth D. Merry 
351*ef270ab1SKenneth D. Merry /**
352*ef270ab1SKenneth D. Merry  * @brief Generate IO context ddump data.
353*ef270ab1SKenneth D. Merry  *
354*ef270ab1SKenneth D. Merry  * The ddump data for an IO context is generated.
355*ef270ab1SKenneth D. Merry  *
356*ef270ab1SKenneth D. Merry  * @param textbuf Pointer to text buffer.
357*ef270ab1SKenneth D. Merry  * @param io Pointer to IO context.
358*ef270ab1SKenneth D. Merry  *
359*ef270ab1SKenneth D. Merry  * @return None.
360*ef270ab1SKenneth D. Merry  */
361*ef270ab1SKenneth D. Merry 
362*ef270ab1SKenneth D. Merry void
363*ef270ab1SKenneth D. Merry ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
364*ef270ab1SKenneth D. Merry {
365*ef270ab1SKenneth D. Merry 	ocs_ddump_section(textbuf, "io", io->instance_index);
366*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "display_name", "%s", io->display_name);
367*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "node_name", "%s", io->node->display_name);
368*ef270ab1SKenneth D. Merry 
369*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "ref_count", "%d", ocs_ref_read_count(&io->ref));
370*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "io_type", "%d", io->io_type);
371*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "hio_type", "%d", io->hio_type);
372*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "cmd_tgt", "%d", io->cmd_tgt);
373*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "cmd_ini", "%d", io->cmd_ini);
374*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "send_abts", "%d", io->send_abts);
375*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "init_task_tag", "0x%x", io->init_task_tag);
376*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "tgt_task_tag", "0x%x", io->tgt_task_tag);
377*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "hw_tag", "0x%x", io->hw_tag);
378*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "tag", "0x%x", io->tag);
379*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "timeout", "%d", io->timeout);
380*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "tmf_cmd", "%d", io->tmf_cmd);
381*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "abort_rx_id", "0x%x", io->abort_rx_id);
382*ef270ab1SKenneth D. Merry 
383*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "busy", "%d", ocs_io_busy(io));
384*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "transferred", "%zu", io->transferred);
385*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "auto_resp", "%d", io->auto_resp);
386*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "exp_xfer_len", "%d", io->exp_xfer_len);
387*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "xfer_req", "%d", io->xfer_req);
388*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "seq_init", "%d", io->seq_init);
389*ef270ab1SKenneth D. Merry 
390*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "alloc_link", "%d", ocs_list_on_list(&io->io_alloc_link));
391*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "pending_link", "%d", ocs_list_on_list(&io->io_pending_link));
392*ef270ab1SKenneth D. Merry 	ocs_ddump_value(textbuf, "backend_link", "%d", ocs_list_on_list(&io->link));
393*ef270ab1SKenneth D. Merry 
394*ef270ab1SKenneth D. Merry 	if (io->hio) {
395*ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "hw_tag", "%#x", io->hio->reqtag);
396*ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "hw_xri", "%#x", io->hio->indicator);
397*ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "hw_type", "%#x", io->hio->type);
398*ef270ab1SKenneth D. Merry 	} else {
399*ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "hw_tag", "%s", "pending");
400*ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "hw_xri", "%s", "pending");
401*ef270ab1SKenneth D. Merry 		ocs_ddump_value(textbuf, "hw_type", "%s", "pending");
402*ef270ab1SKenneth D. Merry 	}
403*ef270ab1SKenneth D. Merry 
404*ef270ab1SKenneth D. Merry 	ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_IO, io);
405*ef270ab1SKenneth D. Merry 	ocs_scsi_tgt_ddump(textbuf, OCS_SCSI_DDUMP_IO, io);
406*ef270ab1SKenneth D. Merry 
407*ef270ab1SKenneth D. Merry 	ocs_ddump_endsection(textbuf, "io", io->instance_index);
408*ef270ab1SKenneth D. Merry }
409*ef270ab1SKenneth D. Merry 
410*ef270ab1SKenneth D. Merry 
411*ef270ab1SKenneth D. Merry void
412*ef270ab1SKenneth D. Merry ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *object)
413*ef270ab1SKenneth D. Merry {
414*ef270ab1SKenneth D. Merry 
415*ef270ab1SKenneth D. Merry 	/* Readonly values */
416*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "display_name");
417*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init_task_tag");
418*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "tag");
419*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "transferred");
420*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "auto_resp");
421*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "exp_xfer_len");
422*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "xfer_req");
423*ef270ab1SKenneth D. Merry }
424*ef270ab1SKenneth D. Merry 
425*ef270ab1SKenneth D. Merry int
426*ef270ab1SKenneth D. Merry ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
427*ef270ab1SKenneth D. Merry {
428*ef270ab1SKenneth D. Merry 	char qualifier[80];
429*ef270ab1SKenneth D. Merry 	int retval = -1;
430*ef270ab1SKenneth D. Merry 	ocs_io_t *io = (ocs_io_t *) object;
431*ef270ab1SKenneth D. Merry 
432*ef270ab1SKenneth D. Merry 	snprintf(qualifier, sizeof(qualifier), "%s/io[%d]", parent, io->instance_index);
433*ef270ab1SKenneth D. Merry 
434*ef270ab1SKenneth D. Merry 	/* If it doesn't start with my qualifier I don't know what to do with it */
435*ef270ab1SKenneth D. Merry 	if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
436*ef270ab1SKenneth D. Merry 		char *unqualified_name = name + strlen(qualifier) +1;
437*ef270ab1SKenneth D. Merry 
438*ef270ab1SKenneth D. Merry 		/* See if it's a value I can supply */
439*ef270ab1SKenneth D. Merry 		if (ocs_strcmp(unqualified_name, "display_name") == 0) {
440*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", io->display_name);
441*ef270ab1SKenneth D. Merry 			retval = 0;
442*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "init_task_tag") == 0) {
443*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag);
444*ef270ab1SKenneth D. Merry 			retval = 0;
445*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "tgt_task_tag") == 0) {
446*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tgt_task_tag", "0x%x", io->tgt_task_tag);
447*ef270ab1SKenneth D. Merry 			retval = 0;
448*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "hw_tag") == 0) {
449*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_tag", "0x%x", io->hw_tag);
450*ef270ab1SKenneth D. Merry 			retval = 0;
451*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "tag") == 0) {
452*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag);
453*ef270ab1SKenneth D. Merry 			retval = 0;
454*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "transferred") == 0) {
455*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "transferred", "%zu", io->transferred);
456*ef270ab1SKenneth D. Merry 			retval = 0;
457*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "auto_resp") == 0) {
458*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp);
459*ef270ab1SKenneth D. Merry 			retval = 0;
460*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "exp_xfer_len") == 0) {
461*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "exp_xfer_len", "%d", io->exp_xfer_len);
462*ef270ab1SKenneth D. Merry 			retval = 0;
463*ef270ab1SKenneth D. Merry 		} else if (ocs_strcmp(unqualified_name, "xfer_req") == 0) {
464*ef270ab1SKenneth D. Merry 			ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "xfer_req", "%d", io->xfer_req);
465*ef270ab1SKenneth D. Merry 			retval = 0;
466*ef270ab1SKenneth D. Merry 		}
467*ef270ab1SKenneth D. Merry 	}
468*ef270ab1SKenneth D. Merry 
469*ef270ab1SKenneth D. Merry 	return retval;
470*ef270ab1SKenneth D. Merry }
471*ef270ab1SKenneth D. Merry 
472*ef270ab1SKenneth D. Merry void
473*ef270ab1SKenneth D. Merry ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *object)
474*ef270ab1SKenneth D. Merry {
475*ef270ab1SKenneth D. Merry 	ocs_io_t *io = (ocs_io_t *) object;
476*ef270ab1SKenneth D. Merry 
477*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_string(textbuf, MGMT_MODE_RD, "display_name", io->display_name);
478*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag);
479*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tgt_task_tag", "0x%x", io->tgt_task_tag);
480*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "hw_tag", "0x%x", io->hw_tag);
481*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag);
482*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "transferred", "%zu", io->transferred);
483*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp);
484*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "exp_xfer_len", "%d", io->exp_xfer_len);
485*ef270ab1SKenneth D. Merry 	ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "xfer_req", "%d", io->xfer_req);
486*ef270ab1SKenneth D. Merry 
487*ef270ab1SKenneth D. Merry }
488*ef270ab1SKenneth D. Merry 
489*ef270ab1SKenneth D. Merry 
490*ef270ab1SKenneth D. Merry 
491*ef270ab1SKenneth D. Merry 
492