Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_io.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2011-2015, Emulex
3  * All rights reserved.
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  */
32 
33 /**
34  * @file
35  * Provide IO object allocation
36  */
37 
38 /*!
39  * @defgroup io_alloc IO allocation
40  */
41 
42 #include "ocs.h"
43 
44 void ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *io);
45 void ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *io);
46 int ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *io);
47 
50  .get_handler = ocs_mgmt_io_get,
51  .get_all_handler = ocs_mgmt_io_get_all,
52 };
53 
54 /* Define largest slab allocation */
55 #define OCS_IO_MAX_ALLOCATION (64*1024)
56 
57 typedef struct {
58  uint32_t count;
59  ocs_io_t *ios;
61 
62 /**
63  * @brief IO pool
64  *
65  * Structure encapsulating a pool of IO objects.
66  *
67  */
68 
69 struct ocs_io_pool_s {
70  ocs_t *ocs; /* Pointer to device object */
71  ocs_lock_t lock; /* IO pool lock */
72  uint32_t io_num_ios; /* Total IOs allocated */
73  uint32_t io_per_slab; /* IOs per slab */
74  uint32_t io_slab_count; /* slab count */
75  ocs_list_t io_free_list; /* IO free list (using io->io_alloc_link) */
76  ocs_io_slab_t *io_slabs; /* Pointer to slabs */
77 };
78 
79 /**
80  * @brief Create a pool of IO objects
81  *
82  * @param ocs the driver instance's software context
83  * @param num_io number of IO context's to allocate
84  * @param num_sgl number of SGL entries to allocate for each IO
85  *
86  * @return 0 on success, non-zero otherwise
87  */
88 
89 ocs_io_pool_t *
90 ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl)
91 {
92  uint32_t i = 0;
93  uint32_t j;
94  uint32_t idx;
95  int32_t rc = -1;
96  ocs_io_t *io;
97  ocs_io_pool_t *io_pool;
98  ocs_io_slab_t *slab;
99 
100  /* Allocate the IO pool */
101  io_pool = ocs_malloc(ocs, sizeof(*io_pool), OCS_M_ZERO | OCS_M_NOWAIT);
102  if (io_pool == NULL) {
103  ocs_log_err(ocs, "allocate of IO pool failed\n");
104  return NULL;;
105  }
106 
107  io_pool->ocs = ocs;
108 
109  io_pool->io_per_slab = OCS_IO_MAX_ALLOCATION / sizeof(ocs_io_t);
110  io_pool->io_slab_count = (num_io + io_pool->io_per_slab - 1) / io_pool->io_per_slab;
111  io_pool->io_slabs = ocs_malloc(ocs, sizeof(ocs_io_slab_t) * io_pool->io_slab_count, OCS_M_ZERO | OCS_M_NOWAIT);
112 
113  if (io_pool->io_slabs == NULL) {
114  ocs_log_err(ocs, "allocate of io_slabs failed\n");
115  ocs_free(ocs, io_pool, sizeof(*io_pool));
116  return NULL;
117  }
118  io_pool->io_num_ios = num_io;
119 
120  /* initialize IO pool lock */
121  ocs_lock_init(ocs, &io_pool->lock, "io_pool lock[%d]", ocs->instance_index);
122 
123  /* initailize IO free list */
124  ocs_list_init(&io_pool->io_free_list, ocs_io_t, io_alloc_link);
125 
126  /* Allocate IO slabs */
127  for (idx = 0, i = 0, slab = io_pool->io_slabs; i < io_pool->io_slab_count; i++, slab++, idx += io_pool->io_per_slab) {
128  slab->count = io_pool->io_per_slab;
129  slab->ios = ocs_malloc(ocs, slab->count*sizeof(ocs_io_t), OCS_M_ZERO | OCS_M_NOWAIT);
130  if (slab->ios == NULL) {
131  ocs_log_err(ocs, "slab ios allocation failed\n");
132  ocs_io_pool_free(io_pool);
133  return NULL;
134  }
135 
136  /* Initialize each IO */
137  for (j = 0, io = slab->ios; (j < slab->count) && ((idx + j) < num_io); j++, io++) {
138  io->tag = idx + j;
139  io->instance_index = idx + j;
140  io->ocs = ocs;
141 
142  ocs_list_add_tail(&io_pool->io_free_list, io);
143 
144  /* Allocate a response buffer */
145  rc = ocs_dma_alloc(ocs, &io->sensebuf, 256 + 2, 16);
146  if (rc) {
147  ocs_log_err(ocs, "ocs_dma_alloc cmdbuf failed\n");
148  ocs_io_pool_free(io_pool);
149  return NULL;
150  }
151 
152  /* Allocate SGL */
153  io->sgl = ocs_malloc(ocs, sizeof(*io->sgl) * num_sgl, OCS_M_NOWAIT | OCS_M_ZERO);
154  if (io->sgl == NULL) {
155  ocs_log_err(ocs, "malloc sgl's failed\n");
156  ocs_io_pool_free(io_pool);
157  return NULL;
158  }
159  io->sgl_allocated = num_sgl;
160  io->sgl_count = 0;
161 
162  /* Make IO backend call to initialize IO */
165  }
166  }
167 
168  return io_pool;
169 }
170 
171 /**
172  * @brief Free IO objects pool
173  *
174  * The pool of IO objects are freed
175  *
176  * @param io_pool pointer to IO Pool object
177  *
178  * @return returns 0 for success, a negative error code value for failure.
179  */
180 int32_t
181 ocs_io_pool_free(ocs_io_pool_t *io_pool)
182 {
183  uint32_t i;
184  uint32_t j;
185  ocs_io_slab_t *slab;
186  ocs_io_t *io;
187  ocs_t *ocs;
188 
189  ocs_assert(io_pool, -1);
190  ocs = io_pool->ocs;
191 
192  if (io_pool->io_slabs) {
193  for (i = 0, slab = io_pool->io_slabs; i < io_pool->io_slab_count; i++, slab++) {
194  if (!slab->ios) {
195  continue;
196  }
197 
198  for (j = 0, io = slab->ios; j < slab->count; j++, io++) {
201 
202  if (io->sgl) {
203  ocs_free(ocs, io->sgl, sizeof(*io->sgl) * io->sgl_allocated);
204  io->sgl = NULL;
205  }
206  ocs_dma_free(io_pool->ocs, &io->sensebuf);
207  }
208  ocs_free(ocs, slab->ios, slab->count*sizeof(ocs_io_t));
209  slab->ios = NULL;
210  }
211  ocs_free(ocs, io_pool->io_slabs, io_pool->io_slab_count*sizeof(ocs_io_slab_t));
212  io_pool->io_slabs = NULL;
213  }
214 
215  ocs_lock_free(&io_pool->lock);
216  ocs_free(ocs, io_pool, sizeof(*io_pool));
217  return 0;
218 }
219 
220 uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool)
221 {
222  return io_pool->io_num_ios;
223 }
224 
225 /**
226  * @ingroup io_alloc
227  * @brief Allocate an object used to track an IO
228  *
229  * The algorithm locklessly allocates IO objects using an atomic increment with
230  * the following rules
231  * - at most check each object once for availability
232  * - IO objects are allocated sequentially
233  * - once the index is out of range, all callers will wait on the top level lock
234  * to serialize resetting the counter
235  * - objects are not required to complete in order
236  *
237  * @param io_pool pointer to IO Pool object
238  *
239  * @return pointer to a new object, NULL if none available
240  */
241 ocs_io_t *
242 ocs_io_pool_io_alloc(ocs_io_pool_t *io_pool)
243 {
244  ocs_io_t *io = NULL;
245  ocs_t *ocs = io_pool->ocs;
246 
247  ocs_assert(io_pool, NULL);
248 
249  ocs_lock(&io_pool->lock);
250  if (!ocs_list_empty(&io_pool->io_free_list)) {
251  io = ocs_list_get_head(&io_pool->io_free_list);
252  ocs_list_remove(&io_pool->io_free_list, io);
253  io->ocs = ocs;
254  io->timeout = 0;
255  io->sgl_count = 0;
256  io->tgt_task_tag = 0;
257  io->hw_tag = 0;
258  io->mgmt_functions = &io_mgmt_functions;
259  }
260  ocs_unlock(&io_pool->lock);
261  return io;
262 }
263 
264 /**
265  * @ingroup io_alloc
266  * @brief Free an object used to track an IO
267  *
268  * @param io_pool pointer to the IO Pool object
269  * @param io pointer to the IO object
270  */
271 void
272 ocs_io_pool_io_free(ocs_io_pool_t *io_pool, ocs_io_t *io)
273 {
274  ocs_t *ocs = io_pool->ocs;
275 
276  ocs_assert(io_pool);
277 
278  ocs_lock(&io_pool->lock);
279  if (io->hio) {
280  ocs_hal_io_free(&ocs->hal, io->hio);
281  io->hio = NULL;
282  }
283  ocs_list_add_tail(&io_pool->io_free_list, io);
284  ocs_unlock(&io_pool->lock);
285 }
286 
287 
288 /**
289  * @ingroup io_alloc
290  * @brief return pointer to IO object given instance index
291  *
292  * A pointer to to an IO object is returned given an instance index.
293  *
294  * @param ocs driver instance context
295  * @param index instance index
296  *
297  * @return returns pointer to IO object or NULL
298  */
299 
300 ocs_io_t *
301 ocs_io_get_instance(ocs_t *ocs, uint32_t index)
302 {
303  ocs_io_pool_t *io_pool = ocs->io_pool;
304  uint32_t slab_idx;
305  uint32_t idx;
306 
307  if (index >= io_pool->io_num_ios) {
308  return NULL;
309  }
310 
311  slab_idx = index / io_pool->io_per_slab;
312  idx = index % io_pool->io_per_slab;
313 
314  return &io_pool->io_slabs[slab_idx].ios[idx];
315 }
316 
317 
318 /**
319  * @brief generate IO context ddump data
320  *
321  * The ddump data for an IO context is generated
322  *
323  * @param textbuf pointer to text buffer
324  * @param io pointer to IO context
325  *
326  * @return none
327  */
328 
329 void
330 ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
331 {
332  ocs_hal_io_t *hio = io->hio;
333 
334  ocs_ddump_section(textbuf, "io", 0);
335 
336  ocs_ddump_value(textbuf, "init_task_tag", "0x%x", io->init_task_tag);
337  ocs_ddump_value(textbuf, "tag", "0x%x", io->tag);
338 
339 
340  ocs_ddump_value(textbuf, "auto_resp", "%d", io->auto_resp);
341  ocs_ddump_value(textbuf, "busy", "%d", ocs_io_busy(io));
342 
343  if (hio != NULL) {
344  ocs_ddump_value(textbuf, "icd", "0x%x", hio->icd);
345  ocs_ddump_value(textbuf, "type", "%d", hio->type);
346  }
347 
348  // ocs_scsi_ini_ddump(textbuf, OCS_SCSI_DDUMP_IO, io);
350 
351  ocs_ddump_endsection(textbuf, "io", 0);
352 }
353 
354 void
355 ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *object)
356 {
357  ocs_io_t *io = (ocs_io_t *)object;
358 
359  ocs_mgmt_start_section(textbuf, "io", io->instance_index);
360 
361  /* Add my status values to textbuf */
362  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "init_task_tag");
363  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "tag");
364  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "auto_resp");
365  ocs_mgmt_emit_property_name(textbuf, MGMT_MODE_RD, "busy");
366 
367  ocs_mgmt_end_section(textbuf, "io", io->instance_index);
368 
369 }
370 
371 int
372 ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *object)
373 {
374  ocs_io_t *io = (ocs_io_t *)object;
375  char qualifier[80];
376  int retval = -1;
377 
378  ocs_mgmt_start_section(textbuf, "io", io->instance_index);
379  snprintf(qualifier, sizeof(qualifier), "%s.io%d", parent, io->instance_index);
380 
381  /* If it doesn't start with my qualifier I don't know what to do with it */
382  if (ocs_strncmp(name, qualifier, strlen(qualifier)) == 0) {
383  char *unqualified_name = name + strlen(qualifier) +1;
384 
385  /* See if it's a value I can supply */
386  if (ocs_strcmp(unqualified_name, "init_task_tag") == 0) {
387  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag);
388  retval = 0;
389  } else if (ocs_strcmp(unqualified_name, "tag") == 0) {
390  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag);
391  retval = 0;
392  } else if (ocs_strcmp(unqualified_name, "auto_resp") == 0) {
393  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp);
394  retval = 0;
395  } else if (ocs_strcmp(unqualified_name, "busy") == 0) {
396  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "busy", ocs_io_busy(io));
397  retval = 0;
398  }
399  }
400 
401  ocs_mgmt_end_section(textbuf, "io", io->instance_index);
402  return retval;
403 }
404 
405 void
406 ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *object)
407 {
408  ocs_io_t *io = (ocs_io_t *)object;
409 
410  ocs_mgmt_start_section(textbuf, "io", io->instance_index);
411 
412  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "init_task_tag", "0x%x", io->init_task_tag);
413  ocs_mgmt_emit_int(textbuf, MGMT_MODE_RD, "tag", "0x%x", io->tag);
414  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "auto_resp", io->auto_resp);
415  ocs_mgmt_emit_boolean(textbuf, MGMT_MODE_RD, "busy", ocs_io_busy(io));
416 
417  ocs_mgmt_end_section(textbuf, "io", io->instance_index);
418 }
419 
static int32_t ocs_io_busy(ocs_io_t *io)
Test if IO object is busy.
Definition: ocs_io.h:129
int32_t ocs_scsi_tgt_io_exit(ocs_io_t *io)
Un-initialize SCSI IO.
Definition: ocs_ramd.c:450
ocs_io_pool_t * ocs_io_pool_create(ocs_t *ocs, uint32_t num_io, uint32_t num_sgl)
Create a pool of IO objects.
Definition: ocs_io.c:90
ocs_io_t * ocs_io_pool_io_alloc(ocs_io_pool_t *io_pool)
Allocate an object used to track an IO.
Definition: ocs_io.c:242
int32_t ocs_scsi_tgt_io_init(ocs_io_t *io)
Initialize SCSI IO.
Definition: ocs_ramd.c:433
ocs_lock_t lock
Definition: ocs_io.c:71
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
void ocs_mgmt_emit_int(ocs_textbuf_t *textbuf, int mode, const char *name, const char *fmt,...)
Generate a property with an integer value in a management XML document.
ocs_io_t * ios
Definition: ocs_io.c:59
static void * ocs_list_get_head(ocs_list_t *list)
Return the first item in the list.
Definition: ocs_list.h:292
const char * name
Definition: ocs_ddump.h:54
uint16_t icd
Definition: ocs_hal.h:474
void ocs_mgmt_io_get_all(ocs_textbuf_t *textbuf, void *io)
Definition: ocs_io.c:406
void ocs_ddump_section(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section start data.
Definition: ocs_ddumplib.c:90
int32_t ocs_scsi_ini_io_exit(ocs_io_t *io)
void ocs_mgmt_start_section(ocs_textbuf_t *textbuf, const char *name, int index)
Generate the beginning of a numbered section in a management XML document.
int const char const char void ocs_mgmt_emit_boolean(ocs_textbuf_t *textbuf, int access, const char *name, const int value)
Generate a property with a boolean value in a management XML document.
static void * ocs_list_remove(ocs_list_t *list, void *item)
Remove an item from the list.
Definition: ocs_list.h:385
int32_t ocs_scsi_ini_io_init(ocs_io_t *io)
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
void ocs_io_pool_io_free(ocs_io_pool_t *io_pool, ocs_io_t *io)
Free an object used to track an IO.
Definition: ocs_io.c:272
uint32_t ocs_io_pool_allocated(ocs_io_pool_t *io_pool)
Definition: ocs_io.c:220
void ocs_mgmt_io_list(ocs_textbuf_t *textbuf, void *io)
Definition: ocs_io.c:355
uint32_t io_slab_count
Definition: ocs_io.c:74
ocs_io_t * ocs_io_get_instance(ocs_t *ocs, uint32_t index)
return pointer to IO object given instance index
Definition: ocs_io.c:301
void ocs_mgmt_end_section(ocs_textbuf_t *textbuf, const char *name, int index)
Generate the indexed end of a section in a management XML document.
ocs_list_t io_free_list
Definition: ocs_io.c:75
HAL IO object.
Definition: ocs_hal.h:471
void ocs_ddump_endsection(ocs_textbuf_t *textbuf, const char *name, uint32_t instance)
Generate driver dump section end data.
Definition: ocs_ddumplib.c:108
ocs_mgmt_get_list_handler get_list_handler
Definition: ocs_mgmt.h:83
#define MGMT_MODE_RD
Definition: ocs_mgmt.h:47
uint32_t count
Definition: ocs_io.c:58
static void ocs_list_add_tail(ocs_list_t *list, void *item)
Add an item to the tail of the list.
Definition: ocs_list.h:263
void ocs_hal_io_free(ocs_hal_t *hal, ocs_hal_io_t *io)
Free a previously allocated HAL IO object.
Definition: ocs_hal.c:5231
void ocs_scsi_tgt_ddump(ocs_textbuf_t *textbuf, ocs_scsi_ddump_type_e type, void *obj)
Definition: ocs_ramd.c:6580
void ocs_ddump_io(ocs_textbuf_t *textbuf, ocs_io_t *io)
generate IO context ddump data
Definition: ocs_io.c:330
static ocs_mgmt_functions_t io_mgmt_functions
Definition: ocs_io.c:48
uint32_t io_num_ios
Definition: ocs_io.c:72
int32_t ocs_io_pool_free(ocs_io_pool_t *io_pool)
Free IO objects pool.
Definition: ocs_io.c:181
int ocs_mgmt_io_get(ocs_textbuf_t *textbuf, char *parent, char *name, void *io)
Definition: ocs_io.c:372
ocs_t * ocs
Definition: ocs_io.c:70
#define ocs_assert(cond,...)
Definition: ocs_debug.h:163
IO pool.
Definition: ocs_io.c:69
ocs_io_slab_t * io_slabs
Definition: ocs_io.c:76
uint16_t type
Definition: ocs_hal.h:477
#define OCS_IO_MAX_ALLOCATION
Definition: ocs_io.c:55
void ocs_mgmt_emit_property_name(ocs_textbuf_t *textbuf, int access, const char *name)
Generate a property, with no value, in a management XML document.
void ocs_ddump_value(ocs_textbuf_t *textbuf, const char *name, const char *fmt,...)
Generate driver dump data for a given value.
Definition: ocs_ddumplib.c:126
uint32_t io_per_slab
Definition: ocs_io.c:73