Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_ramd_thread.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  *
36  */
37 
38 #include "ocs.h"
39 #include "ocs_ramd.h"
40 #include "ocs_ramd_thread.h"
41 
42 static uint32_t threads_per_cpu = 2;
43 static ocs_array_t *ramd_cmd_array; /* cmd array for ramd cmd queues */
44 static ocs_cbuf_t *ramd_cmd_free_queue; /* cmd free list */
45 static ocs_atomic_t *ramd_threads_next; /* next thread within a cpu */
46 static ocs_ramd_thread_t **ramd_threads; /* ramd_threads */
47 static uint32_t enable_ramd_threading;
48 static uint32_t thread_cmds;
49 
50 static int32_t
51 ocs_ramd_server_thread(ocs_thread_t *mythread)
52 {
53  int32_t rc;
54  ocs_ramd_thread_t *thr = mythread->arg;
55  ocs_ramd_cmd_t *cmd;
56 
57  ocs_log_debug(NULL, "%s: ramd running %p\n", mythread->name, thr->cmd_queue);
58  while (!ocs_thread_terminate_requested(mythread)) {
59  cmd = ocs_cbuf_get(thr->cmd_queue, 100000);
60  if (cmd != NULL) {
61  OCS_STAT(thr->cmd_count[cmd->ramd_cmd_type]++);
62  switch(cmd->ramd_cmd_type) {
65  cmd->ramd_cmd.recv_cmd.lun,
66  cmd->ramd_cmd.recv_cmd.cdb,
68  cmd->ramd_cmd.recv_cmd.flags);
69  if (rc) {
70  ocs_log_test(NULL, "ocs_scsi_recv_cmd_common returned %d\n", rc);
71  }
72  break;
78  if (rc) {
79  ocs_log_test(NULL, "_scsi_dataphase_cb returned %d\n", rc);
80  }
81  break;
82  case OCS_RAMD_CMD_IO_CB:
83  rc = _scsi_io_cb(cmd->ramd_cmd.io_cb.io,
85  cmd->ramd_cmd.io_cb.flags,
86  cmd->ramd_cmd.io_cb.arg);
87  if (rc) {
88  ocs_log_test(NULL, "_scsi_io_cb returned %d\n", rc);
89  }
90  break;
92  (*cmd->ramd_cmd.bounce.fctn)(cmd->ramd_cmd.bounce.arg);
93  break;
94  default:
95  break;
96  }
98  }
99  }
100  return 0;
101 }
102 
103 int32_t
104 ocs_ramd_start_threads(uint32_t threading_mode, uint32_t arg_thread_cmds)
105 {
106  int32_t rc;
107  uint32_t i;
108  uint32_t num_cpus = ocs_get_num_cpus();
109  uint32_t cpuidx;
110  uint32_t thridx;
111  ocs_ramd_thread_t *pthr;
112 
113  enable_ramd_threading = threading_mode;
114  thread_cmds = arg_thread_cmds;
115 
116  /* Don't start threads if not enabled */
117  if (enable_ramd_threading) {
118 
119  /* Create the free queue */
120  ramd_cmd_free_queue = ocs_cbuf_alloc(NULL, 1000);
121  if (ramd_cmd_free_queue == NULL) {
122  ocs_log_err(NULL, "ocs_cbuf_alloc cmd_free_queue failed\n");
124  return -1;
125  }
126  ramd_cmd_array = ocs_array_alloc(NULL, sizeof(ocs_ramd_cmd_t), 1000);
128 
129  /* Allocate 2D array of threads */
130  ramd_threads = ocs_malloc(NULL, num_cpus * sizeof(ocs_ramd_thread_t*), OCS_M_ZERO | OCS_M_NOWAIT);
131  for (i = 0; i < num_cpus; i++) {
132  ramd_threads[i] = ocs_malloc(NULL, threads_per_cpu * sizeof(ocs_ramd_thread_t), OCS_M_ZERO | OCS_M_NOWAIT);
133  }
134  ramd_threads_next = ocs_malloc(NULL, num_cpus * sizeof(*ramd_threads_next), OCS_M_ZERO | OCS_M_NOWAIT);
135  for (i = 0; i < num_cpus; i++) {
136  ocs_atomic_init(&ramd_threads_next[i], 0);
137  }
138 
139  for (cpuidx = 0; cpuidx < num_cpus; cpuidx++) {
140  for (thridx = 0; thridx < threads_per_cpu; thridx++) {
141  char name[64];
142  pthr = &ramd_threads[cpuidx][thridx];
143 
144  /* Create command queue */
145  pthr->cmd_queue = ocs_cbuf_alloc(NULL, 100);
146  if (pthr->cmd_queue == NULL) {
147  ocs_log_err(NULL, "ocs_cbuf_alloc failed\n");
149  return -1;
150  }
151 
152  /* Create thread */
153  ocs_snprintf(name, sizeof(name), "ocs_ramd:%d:%d", cpuidx, thridx);
154 
155  rc = ocs_thread_create(NULL, &pthr->thread, ocs_ramd_server_thread, name,
156  pthr, OCS_THREAD_CREATE);
157  if (rc) {
158  ocs_log_err(NULL, "ocs_thread_create failed: %d\n", rc);
160  return -1;
161  }
162 
163  /* Set priority */
164 
165  /* Set CPU affinity ... */
166  rc = ocs_thread_setcpu(&pthr->thread, cpuidx);
167  if (rc == 0) {
168  ocs_log_debug(NULL, "thread %s locked to cpu %d\n", pthr->thread.name,
169  pthr->thread.cpu_affinity);
170  }
171  }
172  }
173 
174  for (cpuidx = 0; cpuidx < num_cpus; cpuidx++) {
175  for (thridx = 0; thridx < threads_per_cpu; thridx++) {
176  /* Start */
177  pthr = &ramd_threads[cpuidx][thridx];
178  pthr->started = TRUE;
179  ocs_thread_start(&pthr->thread);
180  }
181  }
182  }
183  return 0;
184 }
185 
186 void
188 {
189  uint32_t num_cpus = ocs_get_num_cpus();
190  uint32_t cpuidx;
191  uint32_t thridx;
192  int32_t rc;
193  ocs_ramd_thread_t *pthr;
194 
195  if (enable_ramd_threading) {
196 
197  for (cpuidx = 0; cpuidx < num_cpus; cpuidx++) {
198  for (thridx = 0; thridx < threads_per_cpu; thridx++) {
199  pthr = &ramd_threads[cpuidx][thridx];
200  if (pthr->started) {
201  rc = ocs_thread_terminate(&pthr->thread);
202  if (rc) {
203  ocs_log_test(NULL, "ocs_thread_terminate failed: %d\n", rc);
204  }
205  pthr->started = FALSE;
206  }
207  ocs_cbuf_free(pthr->cmd_queue);
208  }
209  ocs_free(NULL, ramd_threads[cpuidx], threads_per_cpu*sizeof(ocs_ramd_thread_t));
210  }
211 
212  ocs_free(NULL, ramd_threads, num_cpus * sizeof(*ramd_threads));
213  ocs_free(NULL, ramd_threads_next, num_cpus * sizeof(*ramd_threads_next));
216  }
217 }
218 
219 void
221 {
222 #if OCS_STAT_ENABLE
223  uint32_t num_cpus = ocs_get_num_cpus();
224  uint32_t cpuidx;
225  uint32_t thridx;
226  uint32_t instance;
227  uint32_t cmdidx;
228  ocs_ramd_thread_t *pthr;
229 
230  if (ramd_threads != NULL) {
231  ocs_ddump_section(textbuf, "ramd_threads", 0);
232  for (instance = 0., cpuidx = 0; cpuidx < num_cpus; cpuidx++) {
233  for (thridx = 0; thridx < threads_per_cpu; thridx++) {
234  pthr = &ramd_threads[cpuidx][thridx];
235  ocs_ddump_section(textbuf, "ramd_thread", instance);
236  for (cmdidx = 0; cmdidx < OCS_RAMD_CMD_MAX; cmdidx++) {
237  switch(cmdidx) {
239  ocs_ddump_value(textbuf, "recv_cmd", "%d %d", cmdidx,
240  pthr->cmd_count[cmdidx]);
241  break;
243  ocs_ddump_value(textbuf, "dataphase_cb", "%d %d", cmdidx,
244  pthr->cmd_count[cmdidx]);
245  break;
246  case OCS_RAMD_CMD_IO_CB:
247  ocs_ddump_value(textbuf, "io_cb", "%d %d", cmdidx,
248  pthr->cmd_count[cmdidx]);
249  break;
250  default:
251  break;
252  }
253  }
254  ocs_ddump_endsection(textbuf, "ramd_thread", instance);
255  instance++;
256  }
257  }
258  ocs_ddump_endsection(textbuf, "ramd_threads", 0);
259  }
260 #endif
261 }
262 
263 uint32_t
265 {
266  return enable_ramd_threading;
267 }
268 
269 int32_t
270 ocs_scsi_recv_cmd(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags)
271 {
272  ocs_ramd_cmd_t *cmd;
273  ocs_ramd_thread_t *pthr;
274  int32_t rc;
275  uint32_t num_cpus = ocs_get_num_cpus();
276  uint32_t cpuidx;
277  uint32_t idx;
278 
279  if (thread_cmds == 0) {
280  return _ocs_scsi_recv_cmd(io, lun, cdb, cdb_len, flags);
281  }
282 
284  if (cmd == NULL) {
285  ocs_log_test(io->ocs, "ocs_cbuf_get() free queue failed\n");
286  return -1;
287  }
288 
290  cmd->ramd_cmd.recv_cmd.io = io;
291  cmd->ramd_cmd.recv_cmd.lun = lun;
292  ocs_assert(cdb_len < sizeof(cmd->ramd_cmd.recv_cmd.cdb), -1);
293  ocs_memcpy(cmd->ramd_cmd.recv_cmd.cdb, cdb, cdb_len);
294  cmd->ramd_cmd.recv_cmd.cdb_len = cdb_len;
295  cmd->ramd_cmd.recv_cmd.flags = flags;
296 
297  /* Pick a thread and pass the command to it */
298  cpuidx = io->init_task_tag % num_cpus;
299  idx = ocs_atomic_add_return(&ramd_threads_next[cpuidx], 1) % threads_per_cpu;
300 
301  pthr = &ramd_threads[cpuidx][idx];
302 
303  /* save thread pointer for future reference */
304  io->tgt_io.thr = pthr;
305 
306  rc = ocs_cbuf_put(pthr->cmd_queue, cmd);
307  if (rc < 0) {
308  ocs_log_test(io->ocs, "ocs_cbuf_put() failed: %d\n", rc);
310  return -1;
311  }
312 
313  return 0;
314 }
315 
316 int32_t
317 scsi_dataphase_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
318 {
319  ocs_ramd_cmd_t *cmd;
320  ocs_ramd_thread_t *pthr;
321  int32_t rc;
322 
323  if (io->tgt_io.thr == NULL) {
324  return _scsi_dataphase_cb(io, scsi_status, flags, arg);
325  }
326 
328  if (cmd == NULL) {
329  ocs_log_test(io->ocs, "ocs_cbuf_get() free queue failed\n");
330  return -1;
331  }
332 
334  cmd->ramd_cmd.dataphase_cb.io = io;
335  cmd->ramd_cmd.dataphase_cb.scsi_status = scsi_status;
336  cmd->ramd_cmd.dataphase_cb.flags = flags;
337  cmd->ramd_cmd.dataphase_cb.arg = arg;
338 
339  pthr = io->tgt_io.thr;
340 
341  rc = ocs_cbuf_put(pthr->cmd_queue, cmd);
342  if (rc < 0) {
343  ocs_log_test(io->ocs, "ocs_cbuf_put failed: %d\n", rc);
345  return -1;
346  }
347  return 0;
348 }
349 
350 int32_t
351 scsi_io_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
352 {
353  ocs_ramd_cmd_t *cmd;
354  ocs_ramd_thread_t *pthr;
355  int32_t rc;
356 
357  if (io->tgt_io.thr == NULL) {
358  return _scsi_io_cb(io, scsi_status, flags, arg);
359  }
360 
362  if (cmd == NULL) {
363  ocs_log_test(io->ocs, "ocs_cbuf_get() free queue failed\n");
364  return -1;
365  }
366 
368  cmd->ramd_cmd.dataphase_cb.io = io;
369  cmd->ramd_cmd.dataphase_cb.scsi_status = scsi_status;
370  cmd->ramd_cmd.dataphase_cb.flags = flags;
371  cmd->ramd_cmd.dataphase_cb.arg = arg;
372 
373  pthr = io->tgt_io.thr;
374 
375  rc = ocs_cbuf_put(pthr->cmd_queue, cmd);
376  if (rc < 0) {
377  ocs_log_test(io->ocs, "ocs_cbuf_put failed: %d\n", rc);
379  return -1;
380  }
381  return 0;
382 }
383 
384 void
385 ocs_ramd_tgt_bounce(void (*fctn)(void *arg), void *arg, uint32_t s_id, uint32_t d_id, uint32_t ox_id)
386 {
387  ocs_ramd_cmd_t *cmd;
388  ocs_ramd_thread_t *pthr;
389  uint32_t idx;
390  int32_t rc;
391  uint32_t cpu;
392 
393  /* If threading is not enabled, then just make the callback */
395  (*fctn)(arg);
396  } else {
397  cpu = ox_id % ocs_get_num_cpus();
398 
400  if (cmd == NULL) {
401  ocs_log_test(NULL, "ocs_cbuf_get() free queue failed\n");
402  return;
403  }
404 
406  cmd->ramd_cmd.bounce.fctn = fctn;
407  cmd->ramd_cmd.bounce.arg = arg;
408 
409  idx = ocs_atomic_add_return(&ramd_threads_next[cpu], 1) % threads_per_cpu;
410  pthr = &ramd_threads[cpu][idx];
411 
412  rc = ocs_cbuf_put(pthr->cmd_queue, cmd);
413  if (rc < 0) {
414  ocs_log_test(NULL, "ocs_cbuf_put failed: %d\n", rc);
416  return;
417  }
418  }
419 }
static uint32_t threads_per_cpu
ocs_ramd_cmd_io_cb_t io_cb
void ocs_ramd_tgt_bounce(void(*fctn)(void *arg), void *arg, uint32_t s_id, uint32_t d_id, uint32_t ox_id)
uint32_t ocs_ramd_get_enable_ramd_threading(void)
int32_t _scsi_io_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
Response phase callback.
Definition: ocs_ramd.c:2846
void ocs_cbuf_free(ocs_cbuf_t *cbuf)
Free a circular buffer.
Definition: ocs_cbuf.c:103
int32_t _ocs_scsi_recv_cmd(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags)
Receive an FCP SCSI command.
Definition: ocs_ramd.c:1207
const char * name
Definition: ocs_ddump.h:54
static uint32_t thread_cmds
ocs_scsi_io_status_e scsi_status
int32_t _scsi_dataphase_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
Command data phase callback.
Definition: ocs_ramd.c:2875
static ocs_cbuf_t * ramd_cmd_free_queue
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
static uint32_t enable_ramd_threading
ocs_ramd_cmd_e ramd_cmd_type
void ocs_ramd_stop_threads(void)
uint32_t cmd_count[OCS_RAMD_CMD_MAX]
void ocs_ramd_thread_ddump(ocs_textbuf_t *textbuf)
int32_t ocs_ramd_start_threads(uint32_t threading_mode, uint32_t arg_thread_cmds)
ocs_array_t * ocs_array_alloc(ocs_os_handle_t os, uint32_t size, uint32_t count)
Allocate an array object.
Definition: ocs_array.c:87
void ocs_array_free(ocs_array_t *array)
Free an array object.
Definition: ocs_array.c:139
ocs_thread_t thread
ocs_cbuf_t * cmd_queue
#define OCS_STAT(x)
Definition: ocs_stats.h:46
void * ocs_cbuf_get(ocs_cbuf_t *cbuf, int32_t timeout_usec)
Get pointer to buffer.
Definition: ocs_cbuf.c:126
int32_t ocs_scsi_recv_cmd(ocs_io_t *io, uint32_t lun, uint8_t *cdb, uint32_t cdb_len, uint32_t flags)
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
int32_t scsi_io_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
int32_t ocs_cbuf_prime(ocs_cbuf_t *cbuf, ocs_array_t *array)
Prime a circular buffer data.
Definition: ocs_cbuf.c:182
static int32_t ocs_ramd_server_thread(ocs_thread_t *mythread)
void(* fctn)(void *arg)
static ocs_atomic_t * ramd_threads_next
ocs_ramd_cmd_dataphase_cb_t dataphase_cb
ocs_cbuf_t * ocs_cbuf_alloc(ocs_os_handle_t os, uint32_t entry_count)
Initialize a circular buffer queue.
Definition: ocs_cbuf.c:65
static ocs_ramd_thread_t ** ramd_threads
static ocs_array_t * ramd_cmd_array
ocs_scsi_io_status_e scsi_status
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
int32_t ocs_cbuf_put(ocs_cbuf_t *cbuf, void *elem)
write a buffer
Definition: ocs_cbuf.c:153
ocs_ramd_cmd_recv_cmd_t recv_cmd
ocs_scsi_io_status_e
Definition: ocs_scsi.h:105
int32_t scsi_dataphase_cb(ocs_io_t *io, ocs_scsi_io_status_e scsi_status, uint32_t flags, void *arg)
union ocs_ramd_cmd_t::@55 ramd_cmd
ocs_ramd_cmd_bounce_t bounce
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