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