Emulex Logo
OneCoreā„¢ Storage SDK Release 11.2
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
ocs_xport.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  * FC transport API
36  *
37  */
38 
39 #include "ocs.h"
40 
41 static void ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg);
42 static void ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg);
43 static void ocs_xport_async_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg);
44 static void ocs_xport_async_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg);
45 static int32_t
46 ocs_xport_stats_timer_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg);
47 /**
48  * @brief Post node event callback argument.
49  */
50 typedef struct {
51  ocs_sem_t sem;
52  ocs_atomic_t refcnt;
53  ocs_node_t *node;
55  void *context;
57 
58 #define OCS_XPORT_STATS_TIMER_MS 3 * 1000
59 
60 /**
61  * @brief Allocate a transport object.
62  *
63  * @par Description
64  * A transport object is allocated, and associated with a device instance.
65  *
66  * @param ocs Pointer to device instance.
67  *
68  * @return Returns the pointer to the allocated transport object, or NULL if failed.
69  */
70 ocs_xport_t *
71 ocs_xport_alloc(ocs_t *ocs)
72 {
73  ocs_xport_t *xport;
74 
75  ocs_assert(ocs, NULL);
76  xport = ocs_malloc(ocs, sizeof(*xport), OCS_M_ZERO);
77  if (xport != NULL) {
78  xport->ocs = ocs;
79  }
80  return xport;
81 }
82 
83 /**
84  * @brief Create the RQ threads and the circular buffers used to pass sequences.
85  *
86  * @par Description
87  * Creates the circular buffers and the servicing threads for RQ processing.
88  *
89  * @param xport Pointer to transport object
90  *
91  * @return Returns 0 on success, or a non-zero value on failure.
92  */
93 static void
94 ocs_xport_rq_threads_teardown(ocs_xport_t *xport)
95 {
96  ocs_t *ocs = xport->ocs;
97  uint32_t i;
98 
99  if (xport->num_rq_threads == 0 ||
100  xport->rq_thread_info == NULL) {
101  return;
102  }
103 
104  /* Abort any threads */
105  for (i = 0; i < xport->num_rq_threads; i++) {
106  if (xport->rq_thread_info[i].thread_started) {
107  ocs_thread_terminate(&xport->rq_thread_info[i].thread);
108  /* wait for the thread to exit */
109  ocs_log_debug(ocs, "wait for thread %d to exit\n", i);
110  while (xport->rq_thread_info[i].thread_started) {
111  ocs_delay_usec(10000);
112  }
113  ocs_log_debug(ocs, "thread %d to exited\n", i);
114  }
115  if (xport->rq_thread_info[i].seq_cbuf != NULL) {
116  ocs_cbuf_free(xport->rq_thread_info[i].seq_cbuf);
117  xport->rq_thread_info[i].seq_cbuf = NULL;
118  }
119  }
120 }
121 
122 /**
123  * @brief Create the RQ threads and the circular buffers used to pass sequences.
124  *
125  * @par Description
126  * Creates the circular buffers and the servicing threads for RQ processing.
127  *
128  * @param xport Pointer to transport object.
129  * @param num_rq_threads Number of RQ processing threads that the
130  * driver creates.
131  *
132  * @return Returns 0 on success, or a non-zero value on failure.
133  */
134 static int32_t
135 ocs_xport_rq_threads_create(ocs_xport_t *xport, uint32_t num_rq_threads)
136 {
137  ocs_t *ocs = xport->ocs;
138  int32_t rc = 0;
139  uint32_t i;
140 
141  xport->num_rq_threads = num_rq_threads;
142  ocs_log_debug(ocs, "number of RQ threads %d\n", num_rq_threads);
143  if (num_rq_threads == 0) {
144  return 0;
145  }
146 
147  /* Allocate the space for the thread objects */
148  xport->rq_thread_info = ocs_malloc(ocs, sizeof(ocs_xport_rq_thread_info_t) * num_rq_threads, OCS_M_ZERO);
149  if (xport->rq_thread_info == NULL) {
150  ocs_log_err(ocs, "memory allocation failure\n");
151  return -1;
152  }
153 
154  /* Create the circular buffers and threads. */
155  for (i = 0; i < num_rq_threads; i++) {
156  xport->rq_thread_info[i].ocs = ocs;
157  xport->rq_thread_info[i].seq_cbuf =
159  if (xport->rq_thread_info[i].seq_cbuf == NULL) {
160  goto ocs_xport_rq_threads_create_error;
161  }
162 
163  ocs_snprintf(xport->rq_thread_info[i].thread_name,
164  sizeof(xport->rq_thread_info[i].thread_name),
165  "ocs_unsol_rq:%d:%d", ocs->instance_index, i);
166  rc = ocs_thread_create(ocs, &xport->rq_thread_info[i].thread, ocs_unsol_rq_thread,
167  xport->rq_thread_info[i].thread_name,
168  &xport->rq_thread_info[i], OCS_THREAD_RUN);
169  if (rc) {
170  ocs_log_err(ocs, "ocs_thread_create failed: %d\n", rc);
171  goto ocs_xport_rq_threads_create_error;
172  }
173  xport->rq_thread_info[i].thread_started = TRUE;
174  }
175  return 0;
176 
177 ocs_xport_rq_threads_create_error:
179  return -1;
180 }
181 
182 /**
183  * @brief Do as much allocation as possible, but do not initialization the device.
184  *
185  * @par Description
186  * Performs the functions required to get a device ready to run.
187  *
188  * @param xport Pointer to transport object.
189  *
190  * @return Returns 0 on success, or a non-zero value on failure.
191  */
192 int32_t
193 ocs_xport_attach(ocs_xport_t *xport)
194 {
195  ocs_t *ocs = xport->ocs;
196  int32_t rc;
197  uint32_t max_sgl;
198  uint32_t n_sgl;
199  uint32_t i;
200  uint32_t value;
201 
202  /* booleans used for cleanup if initialization fails */
203  uint8_t io_pool_created = FALSE;
204  uint8_t node_pool_created = FALSE;
205 
206  ocs_list_init(&ocs->domain_list, ocs_domain_t, link);
207 
208  for (i = 0; i < SLI4_MAX_FCFI; i++) {
209  xport->fcfi[i].hold_frames = 1;
210  ocs_lock_init(ocs, &xport->fcfi[i].pend_frames_lock, "xport pend_frames[%d]", i);
211  ocs_list_init(&xport->fcfi[i].pend_frames, ocs_hal_sequence_t, link);
212  }
213 
214  rc = ocs_hal_set_ptr(&ocs->hal, OCS_HAL_WAR_VERSION, ocs->hal_war_version);
215  if (rc) {
216  ocs_log_test(ocs, "can't set OCS_HAL_WAR_VERSION\n");
217  return -1;
218  }
219 
220  rc = ocs_hal_setup(&ocs->hal, ocs, SLI4_PORT_TYPE_FC);
221  if (rc) {
222  ocs_log_err(ocs, "%s: Can't setup hardware\n", ocs->desc);
223  return -1;
224  } else if (ocs->ctrlmask & OCS_CTRLMASK_CRASH_RESET) {
225  ocs_log_debug(ocs, "stopping after ocs_hal_setup\n");
226  return -1;
227  }
228 
229  ocs->hal.watchdog_timeout = ocs->watchdog_timeout;
230  ocs->hal.sliport_healthcheck = ocs->sliport_healthcheck;
231  ocs->hal.disable_fec = ocs->disable_fec;
232  ocs->hal.enable_fw_ag_rsp = ocs->enable_fw_ag_rsp;
233  ocs->hal.sliport_pause_errors = ocs->sliport_pause_errors;
234 
235  ocs_hal_set(&ocs->hal, OCS_HAL_BOUNCE, ocs->hal_bounce);
236  ocs_log_debug(ocs, "HAL bounce: %d\n", ocs->hal_bounce);
237 
238  ocs_hal_set(&ocs->hal, OCS_HAL_RQ_SELECTION_POLICY, ocs->rq_selection_policy);
239  ocs_hal_set(&ocs->hal, OCS_HAL_CQ_PROCESS_LIMIT, ocs->cq_process_limit);
240  ocs_hal_set(&ocs->hal, OCS_HAL_RR_QUANTA, ocs->rr_quanta);
241  ocs_hal_get(&ocs->hal, OCS_HAL_RQ_SELECTION_POLICY, &value);
242  ocs_log_debug(ocs, "RQ Selection Policy: %d\n", value);
243 
244  ocs_hal_set_ptr(&ocs->hal, OCS_HAL_FILTER_DEF, (void*) ocs->filter_def);
245 
246  ocs_hal_get(&ocs->hal, OCS_HAL_MAX_SGL, &max_sgl);
247  max_sgl -= SLI4_SGE_MAX_RESERVED;
248  n_sgl = MIN(OCS_FC_MAX_SGL, max_sgl);
249 
250  /* EVT: For chained SGL testing */
251  if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
252  n_sgl = 4;
253  }
254 
255  /* Note: number of SGLs must be set for ocs_node_create_pool */
256  if (ocs_hal_set(&ocs->hal, OCS_HAL_N_SGL, n_sgl) != OCS_HAL_RTN_SUCCESS) {
257  ocs_log_err(ocs, "%s: Can't set number of SGLs\n", ocs->desc);
258  return -1;
259  } else {
260  ocs_log_debug(ocs, "%s: Configured for %d SGLs\n", ocs->desc, n_sgl);
261  }
262 
263  /*
264  * Suppress response feature must satisfy the following 3 conditions.
265  * Module parameter cfg_suppress_rsp must be set (default 1)
266  * In SLI4-Parameters,
267  * Extended Inline Buffers (XIB) must be supported.
268  * Suppress Response UI Not Supported (SRIUNS) must not be supported.
269  * Must be validated after reading SLI4-parameters.
270  */
271  if (ocs->cfg_suppress_rsp && sli_get_xib_capable(&ocs->hal.sli) &&
272  !sli_get_suppress_rsp_not_supported(&ocs->hal.sli)) {
273  ocs_hal_set(&ocs->hal, OCS_HAL_SUPPRESS_RSP_CAPABLE, TRUE);
274  } else {
275  ocs_hal_set(&ocs->hal, OCS_HAL_SUPPRESS_RSP_CAPABLE, FALSE);
276  }
277 
278  rc = ocs_node_create_pool(ocs, (ocs->max_remote_nodes) ?
279  ocs->max_remote_nodes : OCS_MAX_REMOTE_NODES);
280  if (rc) {
281  ocs_log_err(ocs, "Can't allocate node pool\n");
282  goto ocs_xport_attach_cleanup;
283  } else {
284  node_pool_created = TRUE;
285  }
286 
287  /* EVT: if testing chained SGLs allocate OCS_FC_MAX_SGL SGE's in the IO */
288  xport->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios,
289  (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) ? OCS_FC_MAX_SGL : n_sgl);
290  if (xport->io_pool == NULL) {
291  ocs_log_err(ocs, "Can't allocate IO pool\n");
292  goto ocs_xport_attach_cleanup;
293  } else {
294  io_pool_created = TRUE;
295  }
296 
297  /*
298  * setup the RQ processing threads
299  */
300  if (ocs_xport_rq_threads_create(xport, ocs->rq_threads) != 0) {
301  ocs_log_err(ocs, "failure creating RQ threads\n");
302  goto ocs_xport_attach_cleanup;
303  }
304 
305  return 0;
306 
307 ocs_xport_attach_cleanup:
308  if (io_pool_created) {
309  ocs_io_pool_free(xport->io_pool);
310  }
311 
312  if (node_pool_created) {
313  ocs_node_free_pool(ocs);
314  }
315 
316  return -1;
317 }
318 
319 static int32_t ocs_tow_io_size_valid(int32_t tow_feature, int32_t tow_io_size)
320 {
321  int32_t rc = TRUE;
322 
323  if (tow_feature & OCS_TOW_FEATURE_AXR) {
324  if (tow_io_size < OCS_TOW_AXR_IO_SIZE_MIN ||
325  tow_io_size > OCS_TOW_IO_SIZE_MAX) {
326  rc = FALSE;
327  }
328  }
329 
330  if (rc && (tow_feature & OCS_TOW_FEATURE_TFB)) {
331  if (tow_io_size % 512 ||
332  tow_io_size > OCS_TOW_IO_SIZE_MAX) {
333  rc = FALSE;
334  }
335  }
336 
337  return rc;
338 }
339 
340 static int32_t ocs_tow_feature_valid(int32_t tow_feature)
341 {
342  int32_t rc = FALSE;
343 
344  if (!tow_feature)
345  return TRUE;
346 
347 #if !defined(OCS_ENABLE_FIRST_BURST)
348  if (tow_feature & OCS_TOW_FEATURE_TFB)
349  return rc;
350 #endif
351 
352 #if defined(OCS_INCLUDE_SCST)
353  if (tow_feature & OCS_TOW_FEATURE_TFB)
354  return rc;
355 #endif
356  if (tow_feature & OCS_TOW_FEATURE_AXR ||
357  tow_feature & OCS_TOW_FEATURE_TFB)
358  rc = TRUE;
359 
360  return rc;
361 }
362 
363 /**
364  * @brief Setup AXR/FB optimized write parameters.
365  * Must be called after sli_setup.
366  *
367  * @param hal Pointer to HAL context
368  *
369  * @return 0 on success, otherwise a negative value.
370  */
371 static int32_t ocs_tow_setup(ocs_t *ocs)
372 {
373  uint32_t agxf;
374  uint32_t tow;
375  char prop_buf[32];
376  int32_t rc = -1;
377  uint32_t ramdisc_blocksize = 512;
378  uint8_t p_type = 0;
379  int32_t tow_feature = 0;
380  uint32_t tow_xri_cnt = 0;
381  int32_t tow_io_size = 0;
382  uint32_t tow_xris_max = 0;
383 
384  if (ocs_get_property("tow_feature", prop_buf, sizeof(prop_buf)) == 0) {
385  tow_feature = ocs_strtoul(prop_buf, 0, 0);
386  }
387 
388  if (ocs_get_property("tow_io_size", prop_buf, sizeof(prop_buf)) == 0) {
389  tow_io_size = ocs_strtoul(prop_buf, 0, 0);
390  }
391 
392  if (ocs_get_property("tow_xri_cnt", prop_buf, sizeof(prop_buf)) == 0) {
393  tow_xri_cnt = ocs_strtoul(prop_buf, 0, 0);
394  }
395 
396  /* Validate tow_feature at first place */
397  if (!ocs_tow_feature_valid(tow_feature)) {
398  ocs_log_err(ocs, "Invalid target optimized write feature\n");
399  return rc;
400  }
401 
402  if (!ocs_tow_io_size_valid(tow_feature, tow_io_size)) {
403  ocs_log_err(ocs, "Invalid target optimized write io size\n");
404  return rc;
405  }
406 
407  ocs_hal_get(&ocs->hal, OCS_HAL_AUTO_XFER_RDY_CAPABLE, &agxf);
408  ocs_hal_get(&ocs->hal, OCS_HAL_TOW_CAPABLE, &tow);
409  if ((tow_feature & OCS_TOW_FEATURE_AXR) && !agxf && !tow) {
410  ocs_log_err(ocs, "Auto Xfer Rdy feature is unsupported\n");
411  return rc;
412  }
413 
414  if ((tow_feature & OCS_TOW_FEATURE_TFB) && !tow) {
415  ocs_log_err(ocs, "First burst feature is unsupported\n");
416  return rc;
417  }
418 
419  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_FEATURE, tow_feature)) {
420  ocs_log_err(ocs, "HAL set tow feature failed\n");
421  return rc;
422  }
423 
424  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_IO_SIZE, tow_io_size)) {
425  ocs_log_err(ocs, "HAL set tow io size failed\n");
426  return rc;
427  }
428 
429  if (tow) {
430  ocs_hal_get(&ocs->hal, OCS_HAL_TOW_XRIS_MAX, &tow_xris_max);
431  if (tow_xri_cnt > tow_xris_max) {
432  ocs_log_err(ocs, "Invalid TOW xri count! Max. supported %d\n", tow_xris_max);
433  return rc;
434  }
435  }
436 
437  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_XRI_CNT, tow_xri_cnt)) {
438  ocs_log_err(ocs, "HAL set tow xri cnt failed\n");
439  return rc;
440  }
441 
442  /*
443  * Determine if we are doing protection in the backend. We are looking
444  * at the modules parameters here. The backend cannot allow a format
445  * command to change the protection mode when using this feature,
446  * otherwise the firmware will not do the proper thing.
447  */
448  if (ocs_get_property("p_type", prop_buf, sizeof(prop_buf)) == 0) {
449  p_type = ocs_strtoul(prop_buf, 0, 0);
450  }
451 
452  if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
453  ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
454  }
455 
456  if (ocs_get_property("external_dif", prop_buf, sizeof(prop_buf)) == 0) {
457  if(ocs_strlen(prop_buf)) {
458  if (p_type == 0) {
459  p_type = 1;
460  }
461  }
462  }
463 
464  if (p_type != 0) {
465  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_T10_ENABLE, TRUE)) {
466  ocs_log_err(ocs, "HAL set tow t10 failed\n");
467  return rc;
468  }
469 
470  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_BLK_SIZE, ramdisc_blocksize)) {
471  ocs_log_err(ocs, "HAL set tow block size failed\n");
472  return rc;
473  }
474 
475  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_P_TYPE, p_type)) {
476  ocs_log_err(ocs, "HAL set tow p_type failed\n");
477  return rc;
478  }
479 
480  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_REF_TAG_LBA, TRUE)) {
481  ocs_log_err(ocs, "HAL set tow tag lba failed\n");
482  return rc;
483  }
484 
485  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOW_APP_TAG_VALID, FALSE)) {
486  ocs_log_err(ocs, "HAL set tow app tag valid\n");
487  return rc;
488  }
489  }
490 
491  if (tow_feature && ocs->esoc) {
492  ocs_hal_set(&ocs->hal, OCS_HAL_ESOC, TRUE);
493  }
494 
495  return 0;
496 }
497 
498 /**
499  * @brief Initializes the device.
500  *
501  * @par Description
502  * Performs the functions required to make a device functional.
503  *
504  * @param xport Pointer to transport object.
505  *
506  * @return Returns 0 on success, or a non-zero value on failure.
507  */
508 int32_t
509 ocs_xport_initialize(ocs_xport_t *xport)
510 {
511  ocs_t *ocs = xport->ocs;
512  int32_t rc;
513  uint32_t i;
514  uint32_t max_hal_io;
515  uint32_t max_sgl;
516  uint32_t hlm;
517  uint32_t dpp;
518  uint32_t rq_limit;
519  uint32_t dif_capable;
520  uint8_t dif_separate = 0;
521  char prop_buf[32];
522 
523  /* booleans used for cleanup if initialization fails */
524  uint8_t ini_device_set = FALSE;
525  uint8_t tgt_device_set = FALSE;
526  uint8_t hal_initialized = FALSE;
527 
528  ocs_hal_get(&ocs->hal, OCS_HAL_MAX_IO, &max_hal_io);
529  if (ocs_hal_set(&ocs->hal, OCS_HAL_N_IO, max_hal_io) != OCS_HAL_RTN_SUCCESS) {
530  ocs_log_err(ocs, "%s: Can't set number of IOs\n", ocs->desc);
531  return -1;
532  }
533 
534  ocs_hal_get(&ocs->hal, OCS_HAL_MAX_SGL, &max_sgl);
535  max_sgl -= SLI4_SGE_MAX_RESERVED;
536 
537  if (ocs->enable_hlm) {
538  ocs_hal_get(&ocs->hal, OCS_HAL_HIGH_LOGIN_MODE, &hlm);
539  if (!hlm) {
540  ocs->enable_hlm = FALSE;
541  ocs_log_err(ocs, "Cannot enable high login mode for this port\n");
542  } else {
543  ocs_log_debug(ocs, "High login mode is enabled\n");
544  if (ocs_hal_set(&ocs->hal, OCS_HAL_HIGH_LOGIN_MODE, TRUE)) {
545  ocs_log_err(ocs, "%s: Can't set high login mode\n", ocs->desc);
546  return -1;
547  }
548  }
549  }
550 
551  if (ocs->enable_dpp) {
552  ocs_hal_get(&ocs->hal, OCS_HAL_DPP_MODE, &dpp);
553  if (!dpp) {
554  ocs->enable_dpp = FALSE;
555  ocs_log_err(ocs, "Disabling DPP mode for this port\n");
556  } else {
557  if (ocs_hal_set(&ocs->hal, OCS_HAL_DPP_MODE, TRUE)) {
558  ocs_log_err(ocs, "%s: enable DPP mode failed\n", ocs->desc);
559  return -1;
560  }
561  ocs_log_debug(ocs, "DPP mode is enabled\n");
562  }
563  }
564 
565  ocs_hal_get(&ocs->hal, OCS_HAL_MAX_IO, &max_hal_io);
566 
567  /* Setup AXR/FB optimized write parameters, must be called after sli_setup */
568  if (ocs_tow_setup(ocs)) {
569  ocs_log_err(ocs, "Target optimized write setup failed\n");
570  return OCS_HAL_RTN_ERROR;
571  }
572 
573  if (ocs->explicit_buffer_list) {
574  // Are pre-registered SGL's required?
575  ocs_hal_get(&ocs->hal, OCS_HAL_PREREGISTER_SGL, &i);
576  if (i == TRUE) {
577  ocs_log_err(ocs, "Explicit Buffer List not supported on this device, not enabled\n");
578  } else {
579  ocs_hal_set(&ocs->hal, OCS_HAL_PREREGISTER_SGL, FALSE);
580  }
581  }
582 
583  if (ocs_hal_set(&ocs->hal, OCS_HAL_TOPOLOGY, ocs->topology) != OCS_HAL_RTN_SUCCESS) {
584  ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
585  return -1;
586  }
588 
589  if (ocs_hal_set(&ocs->hal, OCS_HAL_LINK_SPEED, ocs->speed) != OCS_HAL_RTN_SUCCESS) {
590  ocs_log_err(ocs, "%s: Can't set the link speed\n", ocs->desc);
591  return -1;
592  }
593 
594  if (ocs_hal_set(&ocs->hal, OCS_HAL_ETH_LICENSE, ocs->ethernet_license) != OCS_HAL_RTN_SUCCESS) {
595  ocs_log_err(ocs, "%s: Can't set the ethernet license\n", ocs->desc);
596  return -1;
597  }
598 
599  /* currently only lancer support setting the CRC seed value */
600  if (ocs->hal.sli.asic_type == SLI4_ASIC_TYPE_LANCER) {
602  ocs_log_err(ocs, "%s: Can't set the DIF seed\n", ocs->desc);
603  return -1;
604  }
605  }
606 
607  /* Set the Dif mode */
608  if (0 == ocs_hal_get(&ocs->hal, OCS_HAL_DIF_CAPABLE, &dif_capable)) {
609  if (dif_capable) {
610  if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) {
611  dif_separate = ocs_strtoul(prop_buf, 0, 0);
612  }
613 
614  if ((rc = ocs_hal_set(&ocs->hal, OCS_HAL_DIF_MODE,
615  (dif_separate == 0 ? OCS_HAL_DIF_MODE_INLINE : OCS_HAL_DIF_MODE_SEPARATE)))) {
616  ocs_log_err(ocs, "Requested DIF MODE not supported\n");
617  }
618  }
619  }
620 
621  if (ocs->target_io_timer_sec) {
622  ocs_log_debug(ocs, "setting target io timer=%d\n", ocs->target_io_timer_sec);
624  }
625 
629  ocs_hal_callback(&ocs->hal, OCS_HAL_CB_PORT, ocs_port_cb, ocs);
631 
632  ocs->fw_version = (const char*) ocs_hal_get_ptr(&ocs->hal, OCS_HAL_FW_REV);
633 
634  /* Initialize vport list */
635  ocs_list_init(&xport->vport_list, ocs_vport_spec_t, link);
636  ocs_lock_init(ocs, &xport->io_pending_lock, "io_pending_lock[%d]", ocs->instance_index);
637  ocs_list_init(&xport->io_pending_list, ocs_io_t, io_pending_link);
638  ocs_atomic_init(&xport->io_active_count, 0);
639  ocs_atomic_init(&xport->io_pending_count, 0);
640  ocs_atomic_init(&xport->io_total_free, 0);
641  ocs_atomic_init(&xport->io_total_pending, 0);
642  ocs_atomic_init(&xport->io_alloc_failed_count, 0);
643  ocs_atomic_init(&xport->io_pending_recursing, 0);
644 
645  /* Initilize driver statistics */
646  ocs_memset(&xport->fc_stats.stats.fcp_stats, 0, sizeof(xport->fc_stats.stats.fcp_stats));
647 
648  ocs_lock_init(ocs, &xport->fc_stats_lock, "fc_stats_lock[%d]", ocs->instance_index);
649  ocs_lock_init(ocs, &ocs->hal.watchdog_lock, " Watchdog Lock[%d]", ocs_instance(ocs));
650 
651  rc = ocs_hal_init(&ocs->hal);
652  if (rc) {
653  ocs_log_err(ocs, "ocs_hal_init failure\n");
654  goto ocs_xport_init_cleanup;
655  } else {
656  hal_initialized = TRUE;
657  }
658 
659  rq_limit = max_hal_io/2;
660  if (ocs_hal_set(&ocs->hal, OCS_HAL_RQ_PROCESS_LIMIT, rq_limit) != OCS_HAL_RTN_SUCCESS) {
661  ocs_log_err(ocs, "%s: Can't set the RQ process limit\n", ocs->desc);
662  }
663 
664  if (ocs->enable_tgt) {
665  rc = ocs_scsi_tgt_new_device(ocs);
666  if (rc) {
667  ocs_log_err(ocs, "failed to initialize target\n");
668  goto ocs_xport_init_cleanup;
669  } else {
670  tgt_device_set = TRUE;
671  }
672  }
673 
674  /*
675  * Create Scsi_Host for I+T modes.
676  * In T only mode, this is required for scsi host sysfs interface.
677  */
678  if (ocs->enable_ini || ocs->enable_tgt) {
679  rc = ocs_scsi_ini_new_device(ocs);
680  if (rc) {
681  ocs_log_err(ocs, "failed to initialize initiator\n");
682  goto ocs_xport_init_cleanup;
683  } else {
684  ini_device_set = TRUE;
685  }
686  }
687 
688  /* Add vports */
689  if (ocs->num_vports != 0) {
690 
691  uint32_t max_vports;
692  ocs_hal_get(&ocs->hal, OCS_HAL_MAX_VPORTS, &max_vports);
693 
694  if (ocs->num_vports < max_vports) {
695  ocs_log_debug(ocs, "Provisioning %d vports\n", ocs->num_vports);
696  for (i = 0; i < ocs->num_vports; i++) {
697  ocs_vport_create_spec(ocs, 0, 0, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt, NULL, NULL);
698  }
699  } else {
700  ocs_log_err(ocs, "failed to create vports. num_vports range should be (1-%d) \n", max_vports-1);
701  goto ocs_xport_init_cleanup;
702  }
703  }
704 
705  return 0;
706 
707 ocs_xport_init_cleanup:
708  if (ini_device_set) {
710  }
711 
712  if (tgt_device_set) {
714  }
715 
716  if (hal_initialized) {
717  /* ocs_hal_teardown can only execute after ocs_hal_init */
718  ocs_hal_teardown(&ocs->hal);
719  }
720 
721  return -1;
722 }
723 
724 /**
725  * @brief Detaches the transport from the device.
726  *
727  * @par Description
728  * Performs the functions required to shut down a device.
729  *
730  * @param xport Pointer to transport object.
731  *
732  * @return Returns 0 on success or a non-zero value on failure.
733  */
734 int32_t
735 ocs_xport_detach(ocs_xport_t *xport)
736 {
737  ocs_t *ocs = xport->ocs;
738 
739  /* free resources associated with target-server and initiator-client */
740  if (ocs->enable_tgt)
742 
743  if (ocs->enable_ini || ocs->enable_tgt) {
745 
746  /*Shutdown FC Statistics timer*/
747  ocs_lock(&xport->fc_stats_lock);
748  xport->fc_stats_timer_shutdown = true;
749  ocs_unlock(&xport->fc_stats_lock);
750  if (ocs_timer_pending(&xport->fc_stats_timer))
751  ocs_del_timer(&xport->fc_stats_timer);
752  }
753 
754  ocs_hal_teardown(&ocs->hal);
755 
756  return 0;
757 }
758 
759 /**
760  * @brief domain list empty callback
761  *
762  * @par Description
763  * Function is invoked when the device domain list goes empty. By convention
764  * @c arg points to an ocs_sem_t instance, that is incremented.
765  *
766  * @param ocs Pointer to device object.
767  * @param arg Pointer to semaphore instance.
768  *
769  * @return None.
770  */
771 void ocs_xport_domain_list_empty_cb(ocs_t *ocs, void *arg)
772 {
773  ocs_sem_t *sem = arg;
774 
775  ocs_assert(ocs);
776  ocs_assert(sem);
777 
778  ocs_sem_v(sem);
779 }
780 
781 /**
782  * @brief post node event callback
783  *
784  * @par Description
785  * This function is called from the mailbox completion interrupt context to post an
786  * event to a node object. By doing this in the interrupt context, it has
787  * the benefit of only posting events in the interrupt context, deferring the need to
788  * create a per event node lock.
789  *
790  * @param hal Pointer to HAL structure.
791  * @param status Completion status for mailbox command.
792  * @param mqe Mailbox queue completion entry.
793  * @param arg Callback argument.
794  *
795  * @return Returns 0 on success, a negative error code value on failure.
796  */
797 
798 static int32_t
799 ocs_xport_post_node_event_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
800 {
801  ocs_xport_post_node_event_t *payload = arg;
802 
803  if (payload != NULL) {
804  ocs_node_post_event(payload->node, payload->evt, payload->context);
805  ocs_sem_v(&payload->sem);
806  if (ocs_atomic_sub_and_test(&payload->refcnt, 1))
807  ocs_free(hal->os, payload, sizeof(*payload));
808  }
809 
810  return 0;
811 }
812 
813 /**
814  * @brief Initiate force free.
815  *
816  * @par Description
817  * Perform force free of OCS.
818  *
819  * @param xport Pointer to transport object.
820  *
821  * @return None.
822  */
823 
824 static void
825 ocs_xport_force_free(ocs_xport_t *xport)
826 {
827  ocs_t *ocs = xport->ocs;
828  ocs_domain_t *domain;
829  ocs_domain_t *next;
830 #if !defined(OCSU_FC_RAMD) && !defined(OCSU_FC_WORKLOAD) && !defined(OCS_USPACE_SPDK)
831  ocs_os_t *ocs_os = (ocs_os_t *)ocs;
832 
834 
835  /* Invoke backend callbacks if avalible */
837 #endif
838 
839  ocs_log_info(ocs, "Force shutdown\n");
840  ocs_device_lock(ocs);
841  ocs_list_foreach_safe(&ocs->domain_list, domain, next) {
842  ocs_domain_force_free(domain);
843  }
844  ocs_device_unlock(ocs);
845 }
846 
847 /**
848  * @brief Perform transport attach function.
849  *
850  * @par Description
851  * Perform the attach function, which for the FC transport makes a HAL call
852  * to bring up the link.
853  *
854  * @param xport pointer to transport object.
855  * @param cmd command to execute.
856  *
857  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_ONLINE)
858  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_OFFLINE)
859  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_SHUTDOWN)
860  * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_POST_NODE_EVENT, ocs_node_t *node, ocs_sm_event_t, void *context)
861  *
862  * @return Returns 0 on success, or a negative error code value on failure.
863  */
864 
865 int32_t
866 ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd, ...)
867 {
868  uint32_t rc = 0;
869  ocs_t *ocs = NULL;
870  va_list argp;
871 
872  ocs_assert(xport, -1);
873  ocs_assert(xport->ocs, -1);
874  ocs = xport->ocs;
875 
876  switch (cmd) {
877  case OCS_XPORT_PORT_ONLINE: {
878  /* Bring the port on-line */
879  rc = ocs_hal_port_control(&ocs->hal, OCS_HAL_PORT_INIT, 0, NULL, NULL);
880  if (rc) {
881  ocs_log_err(ocs, "%s: Can't init port\n", ocs->desc);
882  } else {
883  xport->configured_link_state = cmd;
884  }
885  break;
886  }
887  case OCS_XPORT_PORT_OFFLINE: {
888  if (ocs_hal_port_control(&ocs->hal, OCS_HAL_PORT_SHUTDOWN, 0, NULL, NULL)) {
889  ocs_log_err(ocs, "port shutdown failed\n");
890  } else {
891  xport->configured_link_state = cmd;
892  }
893  break;
894  }
895 
896  case OCS_XPORT_SHUTDOWN: {
897  uint32_t reset_required;
898 
899  /* if a PHYSDEV reset was performed (e.g. hal dump), will affect
900  * all PCI functions; orderly shutdown won't work, just force free
901  */
902  // TODO: need to poll this regularly...
903  if (ocs_hal_get(&ocs->hal, OCS_HAL_RESET_REQUIRED, &reset_required) != OCS_HAL_RTN_SUCCESS) {
904  reset_required = 0;
905  }
906 
907  if (reset_required) {
908  ocs_log_info(ocs, "Reset required, do force shutdown\n");
909  ocs_xport_force_free(xport);
910  break;
911  }
912 
913  if (ocs_hal_port_control(&ocs->hal, OCS_HAL_PORT_SHUTDOWN, 0, NULL, NULL)) {
914  ocs_log_warn(ocs, "Port shutdown failed, do force shutdown\n");
915  ocs_xport_force_free(xport);
916  } else {
917  if (ocs_list_empty(&ocs->domain_list)) {
918  ocs_log_info(ocs, "Domain list is empty\n");
919  } else {
921  rc = ocs_drain_shutdown_events(ocs, &ocs->domain_list_empty_cb_sem);
922  if (rc) {
923  ocs_log_warn(ocs, "Domain shutdown timed out of %d sec; " \
924  "do force shutdown\n",
926  ocs_log_info(ocs, "Print driver dump\n");
927  ocs_ddump(ocs, NULL, OCS_DDUMP_FLAGS_DEFAULT, -1);
928  ocs_xport_force_free(xport);
929  }
931  }
932  }
933 
934  /* Free up any saved virtual ports */
935  ocs_vport_del_all(ocs);
936  break;
937  }
938 
939  /*
940  * POST_NODE_EVENT: post an event to a node object
941  *
942  * This transport function is used to post an event to a node object. It does
943  * this by submitting a NOP mailbox command to defer execution to the
944  * interrupt context (thereby enforcing the serialized execution of event posting
945  * to the node state machine instances)
946  *
947  * A counting semaphore is used to make the call synchronous (we wait until
948  * the callback increments the semaphore before returning (or times out)
949  */
951  ocs_node_t *node;
952  ocs_sm_event_t evt;
953  void *context;
954  ocs_xport_post_node_event_t *payload = NULL;
955  ocs_t *ocs;
956  ocs_hal_t *hal;
957 
958  /* Retrieve arguments */
959  va_start(argp, cmd);
960  node = va_arg(argp, ocs_node_t*);
961  evt = va_arg(argp, ocs_sm_event_t);
962  context = va_arg(argp, void *);
963  va_end(argp);
964 
965  ocs_assert(node, -1);
966  ocs_assert(node->ocs, -1);
967 
968  ocs = node->ocs;
969  hal = &ocs->hal;
970 
971  /* if node's state machine is disabled, don't bother continuing */
972  if (!node->sm.current_state) {
973  ocs_log_test(ocs, "node %p state machine disabled\n", node);
974  return -1;
975  }
976 
977  payload = ocs_malloc(ocs, sizeof(*payload), OCS_M_ZERO);
978  if (payload == NULL) {
979  ocs_log_err(ocs, "%s: failed to allocate memory\n", __func__);
980  return -1;
981  }
982 
983  /* Setup payload */
984  ocs_sem_init(&payload->sem, 0, "xport_post_node_Event");
985  ocs_atomic_init(&payload->refcnt, 2); /* one for self and one for callback */
986  payload->node = node;
987  payload->evt = evt;
988  payload->context = context;
989 
991  ocs_log_test(ocs, "ocs_hal_async_call failed\n");
992  ocs_free(ocs, payload, sizeof(*payload));
993  rc = -1;
994  break;
995  }
996 
997  /* Wait for completion */
998  if (ocs_sem_p(&payload->sem, OCS_SEM_FOREVER)) {
999  ocs_log_test(ocs, "POST_NODE_EVENT: sem wait failed\n");
1000  rc = -1;
1001  }
1002 
1003  if (ocs_atomic_sub_and_test(&payload->refcnt, 1))
1004  ocs_free(ocs, payload, sizeof(*payload));
1005  break;
1006  }
1007  /*
1008  * Set wwnn for the port. This will be used instead of the default provided by FW.
1009  */
1010  case OCS_XPORT_WWNN_SET: {
1011  uint64_t wwnn;
1012 
1013  /* Retrieve arguments */
1014  va_start(argp, cmd);
1015  wwnn = va_arg(argp, uint64_t);
1016  va_end(argp);
1017 
1018  ocs_log_debug(ocs, " WWNN %016" PRIx64 "\n", wwnn);
1019  xport->req_wwnn = wwnn;
1020 
1021  break;
1022  }
1023  /*
1024  * Set wwpn for the port. This will be used instead of the default provided by FW.
1025  */
1026  case OCS_XPORT_WWPN_SET: {
1027  uint64_t wwpn;
1028 
1029  /* Retrieve arguments */
1030  va_start(argp, cmd);
1031  wwpn = va_arg(argp, uint64_t);
1032  va_end(argp);
1033 
1034  ocs_log_debug(ocs, " WWPN %016" PRIx64 "\n", wwpn);
1035  xport->req_wwpn = wwpn;
1036 
1037  break;
1038  }
1039 
1040 
1041  default:
1042  break;
1043  }
1044  return rc;
1045 }
1046 
1047 /**
1048  * @brief Return status on a link.
1049  *
1050  * @par Description
1051  * Returns status information about a link.
1052  *
1053  * @param xport Pointer to transport object.
1054  * @param cmd Command to execute.
1055  * @param result Pointer to result value.
1056  *
1057  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_PORT_STATUS)
1058  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_SPEED, ocs_xport_stats_t *result)
1059  * return link speed in MB/sec
1060  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_IS_SUPPORTED_LINK_SPEED, ocs_xport_stats_t *result)
1061  * [in] *result is speed to check in MB/s
1062  * returns 1 if supported, 0 if not
1063  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STATISTICS, ocs_xport_stats_t *result)
1064  * return link/host port stats
1065  * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STAT_RESET, ocs_xport_stats_t *result)
1066  * resets link/host stats
1067  *
1068  *
1069  * @return Returns 0 on success, or a negative error code value on failure.
1070  */
1071 
1072 int32_t
1073 ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result)
1074 {
1075  uint32_t rc = 0;
1076  ocs_t *ocs = NULL;
1077  ocs_xport_stats_t value;
1078  ocs_hal_rtn_e hal_rc;
1079 
1080  ocs_assert(xport, -1);
1081  ocs_assert(xport->ocs, -1);
1082 
1083  ocs = xport->ocs;
1084 
1085  switch (cmd) {
1087  ocs_assert(result, -1);
1088  if (xport->configured_link_state == 0) {
1089  /* Initial state is offline. configured_link_state is */
1090  /* set to online explicitly when port is brought online. */
1091  xport->configured_link_state = OCS_XPORT_PORT_OFFLINE;
1092  }
1093  result->value = xport->configured_link_state;
1094  break;
1095 
1096  case OCS_XPORT_PORT_STATUS:
1097  ocs_assert(result, -1);
1098  /* Determine port status based on link speed. */
1099  hal_rc = ocs_hal_get(&(ocs->hal), OCS_HAL_LINK_SPEED, &value.value);
1100  if (hal_rc == OCS_HAL_RTN_SUCCESS) {
1101  if (value.value == 0) {
1102  result->value = 0;
1103  } else {
1104  result->value = 1;
1105  }
1106  rc = 0;
1107  } else {
1108  rc = -1;
1109  }
1110  break;
1111 
1112  case OCS_XPORT_LINK_SPEED: {
1113  uint32_t speed;
1114 
1115  ocs_assert(result, -1);
1116  result->value = 0;
1117 
1118  rc = ocs_hal_get(&ocs->hal, OCS_HAL_LINK_SPEED, &speed);
1119  if (rc == 0) {
1120  result->value = speed;
1121  }
1122  break;
1123  }
1124 
1126  uint32_t speed;
1127 
1128  ocs_assert(result, -1);
1129  result->value = 0;
1130 
1131  rc = ocs_hal_get(&ocs->hal, OCS_HAL_LOGICAL_LINK_SPEED, &speed);
1132  if (rc == 0) {
1133  result->value = speed;
1134  }
1135  break;
1136  }
1137 
1139  uint32_t speed;
1140  uint32_t link_module_type;
1141  uint32_t aggregate_link_speed;
1142 
1143  ocs_assert(result, -1);
1144  speed = result->value;
1145 
1146  /* Look for aggregate link speed to handle trunked links. The
1147  link module property is immaterial in this case */
1148  if (!ocs_hal_get(&ocs->hal, OCS_HAL_AGGREGATE_LINK_SPEED, &aggregate_link_speed)) {
1149  if (aggregate_link_speed) {
1150  rc = (speed == aggregate_link_speed) ? true : false;
1151  break;
1152  }
1153  }
1154 
1155  rc = ocs_hal_get(&ocs->hal, OCS_HAL_LINK_MODULE_TYPE, &link_module_type);
1156  if (rc == 0) {
1157  switch(speed) {
1158  case 1000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_1GB) != 0; break;
1159  case 2000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_2GB) != 0; break;
1160  case 4000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_4GB) != 0; break;
1161  case 8000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_8GB) != 0; break;
1162  case 10000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_10GB) != 0; break;
1163  case 16000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_16GB) != 0; break;
1164  case 32000: rc = (link_module_type & OCS_HAL_LINK_MODULE_TYPE_32GB) != 0; break;
1165  default: rc = 0; break;
1166  }
1167  } else {
1168  rc = 0;
1169  }
1170  break;
1171  }
1173  ocs_lock(&ocs->xport->fc_stats_lock);
1174  ocs_memcpy((void *)result, &ocs->xport->fc_stats_sysfs,
1175  sizeof(ocs_xport_stats_t));
1176  ocs_unlock(&ocs->xport->fc_stats_lock);
1177  break;
1179  /* Create a semaphore to synchronize the stat reset process. */
1180  ocs_sem_init(&(result->stats.semaphore), 0, "fc_stats_reset");
1181 
1182  /* First reset the link stats */
1183  if ((rc = ocs_hal_get_link_stats(&ocs->hal, 0, 1, 1, ocs_xport_link_stats_cb, result)) != 0) {
1184  ocs_log_err(ocs, "%s: Failed to reset link statistics\n", __func__);
1185  break;
1186  }
1187 
1188  /* Wait for semaphore to be signaled when the command completes */
1189  // TODO: Should there be a timeout on this? If so, how long?
1190  if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
1191  /* Undefined failure */
1192  ocs_log_test(ocs, "ocs_sem_p failed\n");
1193  rc = -ENXIO;
1194  break;
1195  }
1196 
1197  /* Next reset the host stats */
1198  if ((rc = ocs_hal_get_host_stats(&ocs->hal, 1, ocs_xport_host_stats_cb, result)) != 0) {
1199  ocs_log_err(ocs, "%s: Failed to reset host statistics\n", __func__);
1200  break;
1201  }
1202 
1203  /* Wait for semaphore to be signaled when the command completes */
1204  // TODO: Should there be a timeout on this? If so, how long?
1205  if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
1206  /* Undefined failure */
1207  ocs_log_test(ocs, "ocs_sem_p failed\n");
1208  rc = -ENXIO;
1209  break;
1210  }
1211  break;
1212  }
1213  case OCS_XPORT_IS_QUIESCED:
1214  ocs_device_lock(ocs);
1215  result->value = ocs_list_empty(&ocs->domain_list);
1216  ocs_device_unlock(ocs);
1217  break;
1218  default:
1219  rc = -1;
1220  break;
1221  }
1222 
1223  return rc;
1224 
1225 }
1226 
1227 static void
1228 ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg)
1229 {
1230  ocs_xport_stats_t *result = arg;
1231 
1237 
1238  ocs_sem_v(&(result->stats.semaphore));
1239 }
1240 
1241 
1242 static void
1243 ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg)
1244 {
1245  ocs_xport_stats_t *result = arg;
1246 
1251 
1252  ocs_sem_v(&(result->stats.semaphore));
1253 }
1254 
1255 static void
1256 ocs_xport_async_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg)
1257 {
1258  ocs_xport_t *xport = (ocs_xport_t *)arg;
1259  ocs_xport_stats_t *result;
1260  ocs_t *ocs;
1261 
1262  ocs_assert(xport);
1263  ocs = xport->ocs;
1264  result = &xport->fc_stats;
1265 
1266 
1272 
1273  /* Notify user if there is changes in LRR counter compared to previous value */
1275  ocs_log_warn(ocs, "Received LRR local counter modified on Port: %d (prev value: 0x%x current value: 0x%x)\n",
1276  ocs->hal.sli.physical_port,
1277  result->stats.link_stats.lrr_count_local, counters[OCS_HAL_LINK_STAT_LRR_COUNT_LOCAL].counter);
1278  }
1279 
1280  /* Notify user if there is changes in LR counter compared to previous value */
1282  ocs_log_warn(ocs, "Received LR remote counter modified on Port: %d (prev value: 0x%x current value: 0x%x)\n",
1283  ocs->hal.sli.physical_port,
1284  result->stats.link_stats.lr_count_remote, counters[OCS_HAL_LINK_STAT_LR_COUNT_REMOTE].counter);
1285  }
1288 }
1289 
1290 
1291 static void
1292 ocs_xport_async_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg)
1293 {
1294  ocs_xport_stats_t *result = arg;
1295 
1300 }
1301 
1302 static int32_t
1303 ocs_xport_stats_timer_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
1304 {
1305  ocs_t *ocs = (ocs_t *)hal->os;
1306 
1307  ocs_lock(&ocs->xport->fc_stats_lock);
1308  if (!ocs->xport->fc_stats_timer_shutdown &&
1309  !ocs_timer_pending(&ocs->xport->fc_stats_timer)) {
1310  ocs_setup_timer(ocs->hal.os, &ocs->xport->fc_stats_timer,
1312  }
1313  ocs_unlock(&ocs->xport->fc_stats_lock);
1314 
1315  return 0;
1316 }
1317 
1318 void
1320 {
1321  ocs_t *other_ocs;
1322  uint8_t bus, dev, func;
1323  uint32_t index = 0;
1324 
1325  if (!ocs) {
1326  return;
1327  }
1328 
1329  ocs_get_bus_dev_func(ocs, &bus, &dev, &func);
1330  while ((other_ocs = ocs_get_instance(index++)) != NULL) {
1331  uint8_t other_bus, other_dev, other_func;
1332 
1333  ocs_get_bus_dev_func(other_ocs, &other_bus, &other_dev, &other_func);
1334  if ((bus == other_bus) && (dev == other_dev)) {
1335  ocs_log_debug(other_ocs, "Removing link stats timer\n");
1336  ocs_lock(&other_ocs->xport->fc_stats_lock);
1337  other_ocs->xport->fc_stats_timer_shutdown = true;
1338  ocs_unlock(&other_ocs->xport->fc_stats_lock);
1339  if (ocs_timer_pending(&other_ocs->xport->fc_stats_timer)) {
1340  ocs_del_timer(&other_ocs->xport->fc_stats_timer);
1341  }
1342  }
1343  }
1344 }
1345 
1346 /**
1347  * @brief Get FC link and host Statistics periodically
1348  *
1349  * @param hal Hardware context.
1350  *
1351  * @return NONE.
1352  */
1353 void
1355 {
1356  ocs_t *ocs = (ocs_t *)arg;
1357 
1358  if (ocs == NULL) {
1359  ocs_log_err(ocs, "failed to locate OCS device \n");
1360  return;
1361  }
1362 
1363  if (ocs->xport == NULL) {
1364  ocs_log_err(ocs, "xport object is missing, "
1365  "fc stats timer is not started\n");
1366  return;
1367  }
1368 
1369  /* Copy the cache'd stats. */
1370  ocs_lock(&ocs->xport->fc_stats_lock);
1371  ocs_memcpy(&ocs->xport->fc_stats_sysfs, &ocs->xport->fc_stats, sizeof(ocs_xport_stats_t));
1372  ocs_unlock(&ocs->xport->fc_stats_lock);
1373 
1374  ocs_hal_get_link_stats(&ocs->hal, 1, 0, 0, ocs_xport_async_link_stats_cb, ocs->xport);
1375  ocs_hal_get_host_stats(&ocs->hal, 0, ocs_xport_async_host_stats_cb, &ocs->xport->fc_stats);
1376 
1377  /* Reschedule the timer */
1378  if (ocs_hal_async_call(&ocs->hal, ocs_xport_stats_timer_cb, ocs))
1379  ocs_log_err(ocs, "ocs_hal_async_call failed\n");
1380 }
1381 
1382 /**
1383  * @brief Free a transport object.
1384  *
1385  * @par Description
1386  * The transport object is freed.
1387  *
1388  * @param xport Pointer to transport object.
1389  *
1390  * @return None.
1391  */
1392 
1393 void
1394 ocs_xport_free(ocs_xport_t *xport)
1395 {
1396  ocs_t *ocs;
1397  uint32_t i;
1398 
1399  if (xport) {
1400  ocs = xport->ocs;
1401  ocs_io_pool_free(xport->io_pool);
1402  ocs_node_free_pool(ocs);
1403 
1404  ocs_lock_free(&xport->io_pending_lock);
1405 
1406  for (i = 0; i < SLI4_MAX_FCFI; i++) {
1407  ocs_lock_free(&xport->fcfi[i].pend_frames_lock);
1408  }
1409 
1411 
1412  ocs_lock_free(&xport->fc_stats_lock);
1413  ocs_free(ocs, xport, sizeof(*xport));
1414  }
1415 }
1416 
1417 /**
1418  * @brief callback function for xport from HAL.
1419  *
1420  * @par Description
1421  * Handling XPORT event
1422  *
1423  * @param OCS context.
1424  *
1425  * @return status.
1426  */
1427 int32_t
1429 {
1430  ocs_t *ocs = arg;
1431 
1432  if (!ocs) {
1433  ocs_log_err(ocs, "Invalid argument\n");
1434  return -1;
1435  }
1436 
1437  switch (event) {
1439  /* Updated supported FC speeds */
1441  break;
1442  default:
1443  ocs_log_err(ocs, "Unsupported XPORT event type\n");
1444  return -1;
1445  }
1446 
1447  return 0;
1448 }
int32_t ocs_scsi_host_update_supported_speed(ocs_t *ocs)
Definition: ocs_ini_stub.c:175
uint32_t ocs_instance(void *os)
Return instance index of an opaque ocs structure.
int ocs_ddump(ocs_t *ocs, ocs_textbuf_t *textbuf, uint32_t flags, uint32_t qentries)
Initiate ddump.
Definition: ocs_ddump.c:656
static int32_t ocs_xport_post_node_event_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
post node event callback
Definition: ocs_xport.c:799
#define OCS_TOW_FEATURE_TFB
Definition: ocs_hal.h:149
uint32_t receive_kbyte_count
Definition: ocs_xport.h:139
static void ocs_xport_async_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg)
Definition: ocs_xport.c:1256
int32_t ocs_scsi_tgt_del_device(ocs_t *ocs)
Tears down the target members of the ocs structure.
Definition: ocs_ramd.c:836
int32_t ocs_scsi_tgt_new_device(ocs_t *ocs)
Initializes any target fields on the ocs structure.
Definition: ocs_ramd.c:753
HAL object describing fc host stats.
Definition: ocs_hal.h:843
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:101
void ocs_domain_force_free(ocs_domain_t *domain)
Free memory resources of a domain object.
Definition: ocs_domain.c:341
static int32_t ocs_tow_feature_valid(int32_t tow_feature)
Definition: ocs_xport.c:340
ocs_hal_rtn_e ocs_hal_init(ocs_hal_t *hal)
Allocate memory structures to prepare for the device operation.
Definition: ocs_hal.c:813
static void ocs_xport_force_free(ocs_xport_t *xport)
Initiate force free.
Definition: ocs_xport.c:825
void ocs_device_stop_stats_timers(ocs_t *ocs)
Definition: ocs_xport.c:1319
static int32_t ocs_list_empty(ocs_list_t *list)
Test if a list is empty.
Definition: ocs_list.h:125
ocs_hal_rtn_e ocs_hal_teardown(ocs_hal_t *hal)
Tear down the Hardware Abstraction Layer module.
Definition: ocs_hal.c:1446
ocs_xport_link_stats_t link_stats
Definition: ocs_xport.h:164
void ocs_cbuf_free(ocs_cbuf_t *cbuf)
Free a circular buffer.
Definition: ocs_cbuf.c:103
static void ocs_xport_rq_threads_teardown(ocs_xport_t *xport)
Create the RQ threads and the circular buffers used to pass sequences.
Definition: ocs_xport.c:94
void ocs_xport_config_stats_timer(void *arg)
Get FC link and host Statistics periodically.
Definition: ocs_xport.c:1354
int32_t ocs_scsi_ini_new_device(ocs_t *ocs)
Initializes any initiator fields on the ocs structure.
Definition: ocs_ini_stub.c:121
void ocs_node_post_event(ocs_node_t *node, ocs_sm_event_t evt, void *arg)
Post event to node state machine context.
Definition: ocs_node.c:1498
#define OCS_FC_DIF_SEED
Defines the DIF seed value used for the CRC calculation.
Definition: ocs_fc_config.h:70
ocs_hal_rtn_e
Definition: ocs_hal.h:159
#define OCS_FC_MAX_SGL
Defines the number of SGLs allocated on each IO object.
Definition: ocs_fc_config.h:58
uint32_t uint32_t transmit_kbyte_count
Definition: ocs_xport.h:136
int32_t ocs_port_cb(void *arg, ocs_hal_port_event_e event, void *data)
SLI port HAL callback.
Definition: ocs_sport.c:88
int32_t ocs_xport_detach(ocs_xport_t *xport)
Detaches the transport from the device.
Definition: ocs_xport.c:735
ocs_hal_rtn_e ocs_hal_get_host_stats(ocs_hal_t *hal, uint8_t cc, ocs_hal_host_stat_cb_t cb, void *arg)
Function to retrieve the link and host statistics.
Definition: ocs_hal.c:6044
static void ocs_device_lock(ocs_t *ocs)
Definition: ocs_drv_fc.h:218
static void ocs_xport_async_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg)
Definition: ocs_xport.c:1292
void ocs_vport_del_all(ocs_t *ocs)
Force free all saved vports.
Definition: ocs_sport.c:1175
ocs_hal_rtn_e ocs_hal_callback(ocs_hal_t *hal, ocs_hal_callback_e which, void *func, void *arg)
Register a callback for the given event.
Definition: ocs_hal.c:2824
int32_t ocs_xport_attach(ocs_xport_t *xport)
Do as much allocation as possible, but do not initialization the device.
Definition: ocs_xport.c:193
#define OCS_DDUMP_FLAGS_DEFAULT
Definition: ocs_ddump.h:43
void * context
Definition: ocs_xport.c:55
#define OCS_XPORT_STATS_TIMER_MS
Definition: ocs_xport.c:58
static uint32_t sli_get_suppress_rsp_not_supported(sli4_t *sli4)
Definition: sli4.h:3879
#define OCS_TOW_IO_SIZE_MAX
Definition: ocs_hal.h:145
int32_t ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd,...)
Perform transport attach function.
Definition: ocs_xport.c:866
#define OCS_FC_RQ_SIZE_DEFAULT
Definition: ocs_fc_config.h:46
#define ocs_list_init(head, type, link)
Definition: ocs_list.h:113
ocs_hal_xport_event_e
Definition: ocs_hal.h:704
ocs_node_t * node
Definition: ocs_xport.c:53
int32_t ocs_unsolicited_cb(void *arg, ocs_hal_sequence_t *seq)
Handle unsolicited FC frames.
Definition: ocs_unsol.c:164
uint32_t value
Definition: ocs_xport.h:170
ocs_atomic_t refcnt
Definition: ocs_xport.c:52
#define ocs_list_foreach_safe(list, item, nxt)
Iterate a linked list safely.
Definition: ocs_list.h:446
int32_t ocs_node_create_pool(ocs_t *ocs, uint32_t node_count)
allocate node object pool
Definition: ocs_node.c:281
static void ocs_device_unlock(ocs_t *ocs)
Definition: ocs_drv_fc.h:223
int32_t ocs_remote_node_cb(void *arg, ocs_hal_remote_node_event_e event, void *data)
Handle remote node events from HAL.
Definition: ocs_node.c:115
static int32_t ocs_tow_setup(ocs_t *ocs)
Setup AXR/FB optimized write parameters. Must be called after sli_setup.
Definition: ocs_xport.c:371
ocs_hal_rtn_e ocs_hal_get(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t *value)
Definition: ocs_hal.c:1840
static int32_t ocs_tow_io_size_valid(int32_t tow_feature, int32_t tow_io_size)
Definition: ocs_xport.c:319
ocs_hal_rtn_e ocs_hal_set_ptr(ocs_hal_t *hal, ocs_hal_property_e prop, void *value)
Definition: ocs_hal.c:2437
static int32_t ocs_xport_stats_timer_cb(ocs_hal_t *hal, int32_t status, uint8_t *mqe, void *arg)
Definition: ocs_xport.c:1303
ocs_hal_rtn_e ocs_hal_port_control(ocs_hal_t *hal, ocs_hal_port_e ctrl, uintptr_t value, ocs_hal_port_control_cb_t cb, void *arg)
Control a port (initialize, shutdown, or set link configuration).
Definition: ocs_hal.c:3060
ocs_xport_ctrl_e
Definition: ocs_xport.h:63
int32_t ocs_xport_initialize(ocs_xport_t *xport)
Initializes the device.
Definition: ocs_xport.c:509
ocs_t * ocs_get_instance(uint32_t index)
return pointer to ocs structure given instance index
#define OCS_TOW_AXR_IO_SIZE_MIN
Definition: ocs_hal.h:146
int8_t ocs_vport_create_spec(ocs_t *ocs, uint64_t wwnn, uint64_t wwpn, uint32_t fc_id, uint32_t enable_ini, uint32_t enable_tgt, void *tgt_data, void *ini_data)
Create a saved vport entry.
Definition: ocs_sport.c:1716
ocs_xport_status_e
Definition: ocs_xport.h:72
void ocs_scsi_tgt_cancel_io(ocs_t *ocs)
ocs_hal_rtn_e ocs_hal_set(ocs_hal_t *hal, ocs_hal_property_e prop, uint32_t value)
Definition: ocs_hal.c:2214
void ocs_xport_domain_list_empty_cb(ocs_t *ocs, void *arg)
domain list empty callback
Definition: ocs_xport.c:771
int32_t ocs_domain_cb(void *arg, ocs_hal_domain_event_e event, void *data)
Accept domain callback events from the HAL.
Definition: ocs_domain.c:94
static int32_t ocs_xport_rq_threads_create(ocs_xport_t *xport, uint32_t num_rq_threads)
Create the RQ threads and the circular buffers used to pass sequences.
Definition: ocs_xport.c:135
Post node event callback argument.
Definition: ocs_xport.c:50
static void ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_host_stat_counts_t *counters, void *arg)
Definition: ocs_xport.c:1243
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
void ocs_unregister_domain_list_empty_cb(ocs_t *ocs)
Unregister a callback for the domain_list empty cb.
Definition: ocs_domain.c:370
#define OCS_CTRLMASK_CRASH_RESET
#define SLI4_SGE_MAX_RESERVED
Definition: sli4.h:577
Defines a general FC sequence object, consisting of a header, payload buffers and a HAL IO in the cas...
Definition: ocs_hal.h:784
int32_t ocs_xport_cb(void *arg, ocs_hal_xport_event_e event)
callback function for xport from HAL.
Definition: ocs_xport.c:1428
void ocs_stop_event_processing(ocs_os_t *ocs_os)
ocs_xport_t * ocs_xport_alloc(ocs_t *ocs)
Allocate a transport object.
Definition: ocs_xport.c:71
int32_t ocs_io_pool_free(ocs_io_pool_t *io_pool)
Free IO objects pool.
Definition: ocs_io.c:185
int32_t ocs_scsi_ini_del_device(ocs_t *ocs)
Tears down target members of ocs structure.
Definition: ocs_ini_stub.c:139
int32_t ocs_get_bus_dev_func(ocs_t *ocs, uint8_t *bus, uint8_t *dev, uint8_t *func)
void ocs_xport_free(ocs_xport_t *xport)
Free a transport object.
Definition: ocs_xport.c:1394
ocs_xport_host_statistics_t stats
Definition: ocs_xport.h:171
void ocs_node_free_pool(ocs_t *ocs)
free node object pool
Definition: ocs_node.c:350
int32_t ocs_hal_async_call(ocs_hal_t *hal, ocs_hal_async_cb_t callback, void *arg)
Make an async callback using NOP mailbox command.
Definition: ocs_hal.c:13316
#define SLI4_MAX_FCFI
Maximum value for a FCFI.
Definition: sli4_fc.h:52
int32_t ocs_get_property(const char *prop_name, char *buffer, uint32_t buffer_len)
get driver wide property value
ocs_hal_rtn_e ocs_hal_setup(ocs_hal_t *hal, ocs_os_handle_t os, sli4_port_type_e port_type)
Set up the Hardware Abstraction Layer module.
Definition: ocs_hal.c:606
#define ocs_assert(cond,...)
Definition: ocs_debug.h:176
#define OCS_TOW_FEATURE_AXR
Definition: ocs_hal.h:148
static void ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hal_link_stat_counts_t *counters, void *arg)
Definition: ocs_xport.c:1228
void ocs_register_domain_list_empty_cb(ocs_t *ocs)
Register a callback when the domain_list goes empty.
Definition: ocs_domain.c:389
ocs_sm_event_t evt
Definition: ocs_xport.c:54
#define OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC
Definition: ocs_fc_config.h:93
void * ocs_hal_get_ptr(ocs_hal_t *hal, ocs_hal_property_e prop)
Definition: ocs_hal.c:2175
ocs_sm_event_t
Definition: ocs_sm.h:60
int32_t ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result)
Return status on a link.
Definition: ocs_xport.c:1073
int32_t ocs_unsol_rq_thread(ocs_thread_t *mythread)
Process the RQ circular buffer and process the incoming frames.
Definition: ocs_unsol.c:81
static uint32_t sli_get_xib_capable(sli4_t *sli4)
Definition: sli4.h:3874
ocs_xport_host_stats_t host_stats
Definition: ocs_xport.h:165
#define OCS_RQTHREADS_MAX_SEQ_CBUF
Define rq_threads seq cbuf size to be 4K (equal to SLI RQ max length)
uint32_t transmit_frame_count
Definition: ocs_xport.h:140
#define OCS_CTRLMASK_TEST_CHAINED_SGLS
ocs_hal_rtn_e ocs_hal_get_link_stats(ocs_hal_t *hal, uint8_t req_ext_counters, uint8_t clear_overflow_flags, uint8_t clear_all_counters, ocs_hal_link_stat_cb_t cb, void *arg)
Function to retrieve the link statistics.
Definition: ocs_hal.c:5909
Structure to hold the information related to an RQ processing thread used to increase 40G performance...
Definition: ocs_xport.h:55
ocs_sem_t sem
Definition: ocs_xport.c:51
uint32_t receive_frame_count
Definition: ocs_xport.h:141