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 * FC transport API
37 *
38 */
39
40 #include "ocs.h"
41 #include "ocs_device.h"
42
43 static void ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg);
44 static void ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg);
45 /**
46 * @brief Post node event callback argument.
47 */
48 typedef struct {
49 ocs_sem_t sem;
50 ocs_node_t *node;
51 ocs_sm_event_t evt;
52 void *context;
53 } ocs_xport_post_node_event_t;
54
55 /**
56 * @brief Allocate a transport object.
57 *
58 * @par Description
59 * A transport object is allocated, and associated with a device instance.
60 *
61 * @param ocs Pointer to device instance.
62 *
63 * @return Returns the pointer to the allocated transport object, or NULL if failed.
64 */
65 ocs_xport_t *
66 ocs_xport_alloc(ocs_t *ocs)
67 {
68 ocs_xport_t *xport;
69
70 ocs_assert(ocs, NULL);
71 xport = ocs_malloc(ocs, sizeof(*xport), OCS_M_ZERO);
72 if (xport != NULL) {
73 xport->ocs = ocs;
74 }
75 return xport;
76 }
77
78 /**
79 * @brief Create the RQ threads and the circular buffers used to pass sequences.
80 *
81 * @par Description
82 * Creates the circular buffers and the servicing threads for RQ processing.
83 *
84 * @param xport Pointer to transport object
85 *
86 * @return Returns 0 on success, or a non-zero value on failure.
87 */
88 static void
89 ocs_xport_rq_threads_teardown(ocs_xport_t *xport)
90 {
91 ocs_t *ocs = xport->ocs;
92 uint32_t i;
93
94 if (xport->num_rq_threads == 0 ||
95 xport->rq_thread_info == NULL) {
96 return;
97 }
98
99 /* Abort any threads */
100 for (i = 0; i < xport->num_rq_threads; i++) {
101 if (xport->rq_thread_info[i].thread_started) {
102 ocs_thread_terminate(&xport->rq_thread_info[i].thread);
103 /* wait for the thread to exit */
104 ocs_log_debug(ocs, "wait for thread %d to exit\n", i);
105 while (xport->rq_thread_info[i].thread_started) {
106 ocs_udelay(10000);
107 }
108 ocs_log_debug(ocs, "thread %d to exited\n", i);
109 }
110 if (xport->rq_thread_info[i].seq_cbuf != NULL) {
111 ocs_cbuf_free(xport->rq_thread_info[i].seq_cbuf);
112 xport->rq_thread_info[i].seq_cbuf = NULL;
113 }
114 }
115 }
116
117 /**
118 * @brief Create the RQ threads and the circular buffers used to pass sequences.
119 *
120 * @par Description
121 * Creates the circular buffers and the servicing threads for RQ processing.
122 *
123 * @param xport Pointer to transport object.
124 * @param num_rq_threads Number of RQ processing threads that the
125 * driver creates.
126 *
127 * @return Returns 0 on success, or a non-zero value on failure.
128 */
129 static int32_t
130 ocs_xport_rq_threads_create(ocs_xport_t *xport, uint32_t num_rq_threads)
131 {
132 ocs_t *ocs = xport->ocs;
133 int32_t rc = 0;
134 uint32_t i;
135
136 xport->num_rq_threads = num_rq_threads;
137 ocs_log_debug(ocs, "number of RQ threads %d\n", num_rq_threads);
138 if (num_rq_threads == 0) {
139 return 0;
140 }
141
142 /* Allocate the space for the thread objects */
143 xport->rq_thread_info = ocs_malloc(ocs, sizeof(ocs_xport_rq_thread_info_t) * num_rq_threads, OCS_M_ZERO);
144 if (xport->rq_thread_info == NULL) {
145 ocs_log_err(ocs, "memory allocation failure\n");
146 return -1;
147 }
148
149 /* Create the circular buffers and threads. */
150 for (i = 0; i < num_rq_threads; i++) {
151 xport->rq_thread_info[i].ocs = ocs;
152 xport->rq_thread_info[i].seq_cbuf = ocs_cbuf_alloc(ocs, OCS_HW_RQ_NUM_HDR);
153 if (xport->rq_thread_info[i].seq_cbuf == NULL) {
154 goto ocs_xport_rq_threads_create_error;
155 }
156
157 ocs_snprintf(xport->rq_thread_info[i].thread_name,
158 sizeof(xport->rq_thread_info[i].thread_name),
159 "ocs_unsol_rq:%d:%d", ocs->instance_index, i);
160 rc = ocs_thread_create(ocs, &xport->rq_thread_info[i].thread, ocs_unsol_rq_thread,
161 xport->rq_thread_info[i].thread_name,
162 &xport->rq_thread_info[i], OCS_THREAD_RUN);
163 if (rc) {
164 ocs_log_err(ocs, "ocs_thread_create failed: %d\n", rc);
165 goto ocs_xport_rq_threads_create_error;
166 }
167 xport->rq_thread_info[i].thread_started = TRUE;
168 }
169 return 0;
170
171 ocs_xport_rq_threads_create_error:
172 ocs_xport_rq_threads_teardown(xport);
173 return -1;
174 }
175
176 /**
177 * @brief Do as much allocation as possible, but do not initialization the device.
178 *
179 * @par Description
180 * Performs the functions required to get a device ready to run.
181 *
182 * @param xport Pointer to transport object.
183 *
184 * @return Returns 0 on success, or a non-zero value on failure.
185 */
186 int32_t
187 ocs_xport_attach(ocs_xport_t *xport)
188 {
189 ocs_t *ocs = xport->ocs;
190 int32_t rc;
191 uint32_t max_sgl;
192 uint32_t n_sgl;
193 uint32_t i;
194 uint32_t value;
195 uint32_t max_remote_nodes;
196
197 /* booleans used for cleanup if initialization fails */
198 uint8_t io_pool_created = FALSE;
199 uint8_t node_pool_created = FALSE;
200
201 ocs_list_init(&ocs->domain_list, ocs_domain_t, link);
202
203 for (i = 0; i < SLI4_MAX_FCFI; i++) {
204 xport->fcfi[i].hold_frames = 1;
205 ocs_lock_init(ocs, &xport->fcfi[i].pend_frames_lock, "xport pend_frames[%d]", i);
206 ocs_list_init(&xport->fcfi[i].pend_frames, ocs_hw_sequence_t, link);
207 }
208
209 rc = ocs_hw_set_ptr(&ocs->hw, OCS_HW_WAR_VERSION, ocs->hw_war_version);
210 if (rc) {
211 ocs_log_test(ocs, "can't set OCS_HW_WAR_VERSION\n");
212 return -1;
213 }
214
215 rc = ocs_hw_setup(&ocs->hw, ocs, SLI4_PORT_TYPE_FC);
216 if (rc) {
217 ocs_log_err(ocs, "%s: Can't setup hardware\n", ocs->desc);
218 return -1;
219 } else if (ocs->ctrlmask & OCS_CTRLMASK_CRASH_RESET) {
220 ocs_log_debug(ocs, "stopping after ocs_hw_setup\n");
221 return -1;
222 }
223
224 ocs_hw_set(&ocs->hw, OCS_HW_BOUNCE, ocs->hw_bounce);
225 ocs_log_debug(ocs, "HW bounce: %d\n", ocs->hw_bounce);
226
227 ocs_hw_set(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, ocs->rq_selection_policy);
228 ocs_hw_set(&ocs->hw, OCS_HW_RR_QUANTA, ocs->rr_quanta);
229 ocs_hw_get(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, &value);
230 ocs_log_debug(ocs, "RQ Selection Policy: %d\n", value);
231
232 ocs_hw_set_ptr(&ocs->hw, OCS_HW_FILTER_DEF, (void*) ocs->filter_def);
233
234 ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
235 max_sgl -= SLI4_SGE_MAX_RESERVED;
236 n_sgl = MIN(OCS_FC_MAX_SGL, max_sgl);
237
238 /* EVT: For chained SGL testing */
239 if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
240 n_sgl = 4;
241 }
242
243 /* Note: number of SGLs must be set for ocs_node_create_pool */
244 if (ocs_hw_set(&ocs->hw, OCS_HW_N_SGL, n_sgl) != OCS_HW_RTN_SUCCESS) {
245 ocs_log_err(ocs, "%s: Can't set number of SGLs\n", ocs->desc);
246 return -1;
247 } else {
248 ocs_log_debug(ocs, "%s: Configured for %d SGLs\n", ocs->desc, n_sgl);
249 }
250
251 ocs_hw_get(&ocs->hw, OCS_HW_MAX_NODES, &max_remote_nodes);
252
253 if (!ocs->max_remote_nodes)
254 ocs->max_remote_nodes = max_remote_nodes;
255
256 rc = ocs_node_create_pool(ocs, ocs->max_remote_nodes);
257 if (rc) {
258 ocs_log_err(ocs, "Can't allocate node pool\n");
259 goto ocs_xport_attach_cleanup;
260 } else {
261 node_pool_created = TRUE;
262 }
263
264 /* EVT: if testing chained SGLs allocate OCS_FC_MAX_SGL SGE's in the IO */
265 xport->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios,
266 (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) ? OCS_FC_MAX_SGL : n_sgl);
267 if (xport->io_pool == NULL) {
268 ocs_log_err(ocs, "Can't allocate IO pool\n");
269 goto ocs_xport_attach_cleanup;
270 } else {
271 io_pool_created = TRUE;
272 }
273
274 /*
275 * setup the RQ processing threads
276 */
277 if (ocs_xport_rq_threads_create(xport, ocs->rq_threads) != 0) {
278 ocs_log_err(ocs, "failure creating RQ threads\n");
279 goto ocs_xport_attach_cleanup;
280 }
281
282 return 0;
283
284 ocs_xport_attach_cleanup:
285 if (io_pool_created) {
286 ocs_io_pool_free(xport->io_pool);
287 }
288
289 if (node_pool_created) {
290 ocs_node_free_pool(ocs);
291 }
292
293 return -1;
294 }
295
296 /**
297 * @brief Determines how to setup auto Xfer ready.
298 *
299 * @par Description
300 * @param xport Pointer to transport object.
301 *
302 * @return Returns 0 on success or a non-zero value on failure.
303 */
304 static int32_t
305 ocs_xport_initialize_auto_xfer_ready(ocs_xport_t *xport)
306 {
307 ocs_t *ocs = xport->ocs;
308 uint32_t auto_xfer_rdy;
309 char prop_buf[32];
310 uint32_t ramdisc_blocksize = 512;
311 uint8_t p_type = 0;
312
313 ocs_hw_get(&ocs->hw, OCS_HW_AUTO_XFER_RDY_CAPABLE, &auto_xfer_rdy);
314 if (!auto_xfer_rdy) {
315 ocs->auto_xfer_rdy_size = 0;
316 ocs_log_test(ocs, "Cannot enable auto xfer rdy for this port\n");
317 return 0;
318 }
319
320 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_SIZE, ocs->auto_xfer_rdy_size)) {
321 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
322 return -1;
323 }
324
325 /*
326 * Determine if we are doing protection in the backend. We are looking
327 * at the modules parameters here. The backend cannot allow a format
328 * command to change the protection mode when using this feature,
329 * otherwise the firmware will not do the proper thing.
330 */
331 if (ocs_get_property("p_type", prop_buf, sizeof(prop_buf)) == 0) {
332 p_type = ocs_strtoul(prop_buf, 0, 0);
333 }
334 if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
335 ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
336 }
337 if (ocs_get_property("external_dif", prop_buf, sizeof(prop_buf)) == 0) {
338 if(ocs_strlen(prop_buf)) {
339 if (p_type == 0) {
340 p_type = 1;
341 }
342 }
343 }
344
345 if (p_type != 0) {
346 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_T10_ENABLE, TRUE)) {
347 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
348 return -1;
349 }
350 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_BLK_SIZE, ramdisc_blocksize)) {
351 ocs_log_test(ocs, "%s: Can't set auto xfer rdy blk size\n", ocs->desc);
352 return -1;
353 }
354 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_P_TYPE, p_type)) {
355 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
356 return -1;
357 }
358 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA, TRUE)) {
359 ocs_log_test(ocs, "%s: Can't set auto xfer rdy ref tag\n", ocs->desc);
360 return -1;
361 }
362 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID, FALSE)) {
363 ocs_log_test(ocs, "%s: Can't set auto xfer rdy app tag valid\n", ocs->desc);
364 return -1;
365 }
366 }
367 ocs_log_debug(ocs, "Auto xfer rdy is enabled, p_type=%d, blksize=%d\n",
368 p_type, ramdisc_blocksize);
369 return 0;
370 }
371
372 /**
373 * @brief Initialize link topology config
374 *
375 * @par Description
376 * Topology can be fetched from mod-param or Persistet Topology(PT).
377 * a. Mod-param value is used when the value is 1(P2P) or 2(LOOP).
378 * a. PT is used if mod-param is not provided( i.e, default value of AUTO)
379 * Also, if mod-param is used, update PT.
380 *
381 * @param ocs Pointer to ocs
382 *
383 * @return Returns 0 on success, or a non-zero value on failure.
384 */
385 static int
386 ocs_topology_setup(ocs_t *ocs)
387 {
388 uint32_t topology;
389
390 if (ocs->topology == OCS_HW_TOPOLOGY_AUTO) {
391 topology = ocs_hw_get_config_persistent_topology(&ocs->hw);
392 } else {
393 topology = ocs->topology;
394 /* ignore failure here. link will come-up either in auto mode
395 * if PT is not supported or last saved PT value */
396 ocs_hw_set_persistent_topology(&ocs->hw, topology, OCS_CMD_POLL);
397 }
398
399 return ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, topology);
400 }
401
402 /**
403 * @brief Initializes the device.
404 *
405 * @par Description
406 * Performs the functions required to make a device functional.
407 *
408 * @param xport Pointer to transport object.
409 *
410 * @return Returns 0 on success, or a non-zero value on failure.
411 */
412 int32_t
413 ocs_xport_initialize(ocs_xport_t *xport)
414 {
415 ocs_t *ocs = xport->ocs;
416 int32_t rc;
417 uint32_t i;
418 uint32_t max_hw_io;
419 uint32_t max_sgl;
420 uint32_t hlm;
421 uint32_t rq_limit;
422 uint32_t dif_capable;
423 uint8_t dif_separate = 0;
424 char prop_buf[32];
425
426 /* booleans used for cleanup if initialization fails */
427 uint8_t ini_device_set = FALSE;
428 uint8_t tgt_device_set = FALSE;
429 uint8_t hw_initialized = FALSE;
430
431 ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
432 if (ocs_hw_set(&ocs->hw, OCS_HW_N_IO, max_hw_io) != OCS_HW_RTN_SUCCESS) {
433 ocs_log_err(ocs, "%s: Can't set number of IOs\n", ocs->desc);
434 return -1;
435 }
436
437 ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
438 max_sgl -= SLI4_SGE_MAX_RESERVED;
439
440 if (ocs->enable_hlm) {
441 ocs_hw_get(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, &hlm);
442 if (!hlm) {
443 ocs->enable_hlm = FALSE;
444 ocs_log_err(ocs, "Cannot enable high login mode for this port\n");
445 } else {
446 ocs_log_debug(ocs, "High login mode is enabled\n");
447 if (ocs_hw_set(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, TRUE)) {
448 ocs_log_err(ocs, "%s: Can't set high login mode\n", ocs->desc);
449 return -1;
450 }
451 }
452 }
453
454 /* validate the auto xfer_rdy size */
455 if (ocs->auto_xfer_rdy_size > 0 &&
456 (ocs->auto_xfer_rdy_size < 2048 ||
457 ocs->auto_xfer_rdy_size > 65536)) {
458 ocs_log_err(ocs, "Auto XFER_RDY size is out of range (2K-64K)\n");
459 return -1;
460 }
461
462 ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
463
464 if (ocs->auto_xfer_rdy_size > 0) {
465 if (ocs_xport_initialize_auto_xfer_ready(xport)) {
466 ocs_log_err(ocs, "%s: Failed auto xfer ready setup\n", ocs->desc);
467 return -1;
468 }
469 if (ocs->esoc){
470 ocs_hw_set(&ocs->hw, OCS_ESOC, TRUE);
471 }
472 }
473
474 if (ocs->explicit_buffer_list) {
475 /* Are pre-registered SGL's required? */
476 ocs_hw_get(&ocs->hw, OCS_HW_PREREGISTER_SGL, &i);
477 if (i == TRUE) {
478 ocs_log_err(ocs, "Explicit Buffer List not supported on this device, not enabled\n");
479 } else {
480 ocs_hw_set(&ocs->hw, OCS_HW_PREREGISTER_SGL, FALSE);
481 }
482 }
483
484 /* Setup persistent topology based on topology mod-param value */
485 rc = ocs_topology_setup(ocs);
486 if (rc) {
487 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
488 return -1;
489 }
490
491 if (ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, ocs->topology) != OCS_HW_RTN_SUCCESS) {
492 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
493 return -1;
494 }
495 ocs_hw_set(&ocs->hw, OCS_HW_RQ_DEFAULT_BUFFER_SIZE, OCS_FC_RQ_SIZE_DEFAULT);
496
497 if (ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, ocs->speed) != OCS_HW_RTN_SUCCESS) {
498 ocs_log_err(ocs, "%s: Can't set the link speed\n", ocs->desc);
499 return -1;
500 }
501
502 if (ocs_hw_set(&ocs->hw, OCS_HW_ETH_LICENSE, ocs->ethernet_license) != OCS_HW_RTN_SUCCESS) {
503 ocs_log_err(ocs, "%s: Can't set the ethernet license\n", ocs->desc);
504 return -1;
505 }
506
507 /* currently only lancer support setting the CRC seed value */
508 if (ocs->hw.sli.asic_type == SLI4_ASIC_TYPE_LANCER) {
509 if (ocs_hw_set(&ocs->hw, OCS_HW_DIF_SEED, OCS_FC_DIF_SEED) != OCS_HW_RTN_SUCCESS) {
510 ocs_log_err(ocs, "%s: Can't set the DIF seed\n", ocs->desc);
511 return -1;
512 }
513 }
514
515 /* Set the Dif mode */
516 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &dif_capable)) {
517 if (dif_capable) {
518 if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) {
519 dif_separate = ocs_strtoul(prop_buf, 0, 0);
520 }
521
522 if ((rc = ocs_hw_set(&ocs->hw, OCS_HW_DIF_MODE,
523 (dif_separate == 0 ? OCS_HW_DIF_MODE_INLINE : OCS_HW_DIF_MODE_SEPARATE)))) {
524 ocs_log_err(ocs, "Requested DIF MODE not supported\n");
525 }
526 }
527 }
528
529 if (ocs->target_io_timer_sec) {
530 ocs_log_debug(ocs, "setting target io timer=%d\n", ocs->target_io_timer_sec);
531 ocs_hw_set(&ocs->hw, OCS_HW_EMULATE_TARGET_WQE_TIMEOUT, TRUE);
532 }
533
534 ocs_hw_callback(&ocs->hw, OCS_HW_CB_DOMAIN, ocs_domain_cb, ocs);
535 ocs_hw_callback(&ocs->hw, OCS_HW_CB_REMOTE_NODE, ocs_remote_node_cb, ocs);
536 ocs_hw_callback(&ocs->hw, OCS_HW_CB_UNSOLICITED, ocs_unsolicited_cb, ocs);
537 ocs_hw_callback(&ocs->hw, OCS_HW_CB_PORT, ocs_port_cb, ocs);
538
539 ocs->fw_version = (const char*) ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV);
540
541 /* Initialize vport list */
542 ocs_list_init(&xport->vport_list, ocs_vport_spec_t, link);
543 ocs_lock_init(ocs, &xport->io_pending_lock, "io_pending_lock[%d]", ocs->instance_index);
544 ocs_list_init(&xport->io_pending_list, ocs_io_t, io_pending_link);
545 ocs_atomic_init(&xport->io_active_count, 0);
546 ocs_atomic_init(&xport->io_pending_count, 0);
547 ocs_atomic_init(&xport->io_total_free, 0);
548 ocs_atomic_init(&xport->io_total_pending, 0);
549 ocs_atomic_init(&xport->io_alloc_failed_count, 0);
550 ocs_atomic_init(&xport->io_pending_recursing, 0);
551 ocs_lock_init(ocs, &ocs->hw.watchdog_lock, " Watchdog Lock[%d]", ocs_instance(ocs));
552 rc = ocs_hw_init(&ocs->hw);
553 if (rc) {
554 ocs_log_err(ocs, "ocs_hw_init failure\n");
555 goto ocs_xport_init_cleanup;
556 } else {
557 hw_initialized = TRUE;
558 }
559
560 rq_limit = max_hw_io/2;
561 if (ocs_hw_set(&ocs->hw, OCS_HW_RQ_PROCESS_LIMIT, rq_limit) != OCS_HW_RTN_SUCCESS) {
562 ocs_log_err(ocs, "%s: Can't set the RQ process limit\n", ocs->desc);
563 }
564
565 if (ocs->config_tgt) {
566 rc = ocs_scsi_tgt_new_device(ocs);
567 if (rc) {
568 ocs_log_err(ocs, "failed to initialize target\n");
569 goto ocs_xport_init_cleanup;
570 } else {
571 tgt_device_set = TRUE;
572 }
573 }
574
575 if (ocs->enable_ini) {
576 rc = ocs_scsi_ini_new_device(ocs);
577 if (rc) {
578 ocs_log_err(ocs, "failed to initialize initiator\n");
579 goto ocs_xport_init_cleanup;
580 } else {
581 ini_device_set = TRUE;
582 }
583 }
584
585 /* Add vports */
586 if (ocs->num_vports != 0) {
587 uint32_t max_vports;
588 ocs_hw_get(&ocs->hw, OCS_HW_MAX_VPORTS, &max_vports);
589
590 if (ocs->num_vports < max_vports) {
591 ocs_log_debug(ocs, "Provisioning %d vports\n", ocs->num_vports);
592 for (i = 0; i < ocs->num_vports; i++) {
593 ocs_vport_create_spec(ocs, 0, 0, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt, NULL, NULL);
594 }
595 } else {
596 ocs_log_err(ocs, "failed to create vports. num_vports range should be (1-%d) \n", max_vports-1);
597 goto ocs_xport_init_cleanup;
598 }
599 }
600
601 return 0;
602
603 ocs_xport_init_cleanup:
604 if (ini_device_set) {
605 ocs_scsi_ini_del_device(ocs);
606 }
607
608 if (tgt_device_set) {
609 ocs_scsi_tgt_del_device(ocs);
610 }
611
612 if (hw_initialized) {
613 /* ocs_hw_teardown can only execute after ocs_hw_init */
614 ocs_hw_teardown(&ocs->hw);
615 }
616
617 return -1;
618 }
619
620 /**
621 * @brief Detaches the transport from the device.
622 *
623 * @par Description
624 * Performs the functions required to shut down a device.
625 *
626 * @param xport Pointer to transport object.
627 *
628 * @return Returns 0 on success or a non-zero value on failure.
629 */
630 int32_t
631 ocs_xport_detach(ocs_xport_t *xport)
632 {
633 ocs_t *ocs = xport->ocs;
634
635 /* free resources associated with target-server and initiator-client */
636 if (ocs->config_tgt)
637 ocs_scsi_tgt_del_device(ocs);
638
639 if (ocs->enable_ini) {
640 ocs_scsi_ini_del_device(ocs);
641
642 /*Shutdown FC Statistics timer*/
643 if (ocs_timer_pending(&ocs->xport->stats_timer))
644 ocs_del_timer(&ocs->xport->stats_timer);
645 }
646
647 ocs_hw_teardown(&ocs->hw);
648
649 return 0;
650 }
651
652 /**
653 * @brief domain list empty callback
654 *
655 * @par Description
656 * Function is invoked when the device domain list goes empty. By convention
657 * @c arg points to an ocs_sem_t instance, that is incremented.
658 *
659 * @param ocs Pointer to device object.
660 * @param arg Pointer to semaphore instance.
661 *
662 * @return None.
663 */
664
665 static void
666 ocs_xport_domain_list_empty_cb(ocs_t *ocs, void *arg)
667 {
668 ocs_sem_t *sem = arg;
669
670 ocs_assert(ocs);
671 ocs_assert(sem);
672
673 ocs_sem_v(sem);
674 }
675
676 /**
677 * @brief post node event callback
678 *
679 * @par Description
680 * This function is called from the mailbox completion interrupt context to post an
681 * event to a node object. By doing this in the interrupt context, it has
682 * the benefit of only posting events in the interrupt context, deferring the need to
683 * create a per event node lock.
684 *
685 * @param hw Pointer to HW structure.
686 * @param status Completion status for mailbox command.
687 * @param mqe Mailbox queue completion entry.
688 * @param arg Callback argument.
689 *
690 * @return Returns 0 on success, a negative error code value on failure.
691 */
692
693 static int32_t
694 ocs_xport_post_node_event_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg)
695 {
696 ocs_xport_post_node_event_t *payload = arg;
697
698 if (payload != NULL) {
699 ocs_node_post_event(payload->node, payload->evt, payload->context);
700 ocs_sem_v(&payload->sem);
701 }
702
703 return 0;
704 }
705
706 /**
707 * @brief Initiate force free.
708 *
709 * @par Description
710 * Perform force free of OCS.
711 *
712 * @param xport Pointer to transport object.
713 *
714 * @return None.
715 */
716
717 static void
718 ocs_xport_force_free(ocs_xport_t *xport)
719 {
720 ocs_t *ocs = xport->ocs;
721 ocs_domain_t *domain;
722 ocs_domain_t *next;
723
724 ocs_log_debug(ocs, "reset required, do force shutdown\n");
725 ocs_device_lock(ocs);
726 ocs_list_foreach_safe(&ocs->domain_list, domain, next) {
727 ocs_domain_force_free(domain);
728 }
729 ocs_device_unlock(ocs);
730 }
731
732 /**
733 * @brief Perform transport attach function.
734 *
735 * @par Description
736 * Perform the attach function, which for the FC transport makes a HW call
737 * to bring up the link.
738 *
739 * @param xport pointer to transport object.
740 * @param cmd command to execute.
741 *
742 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_ONLINE)
743 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_OFFLINE)
744 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_SHUTDOWN)
745 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_POST_NODE_EVENT, ocs_node_t *node, ocs_sm_event_t, void *context)
746 *
747 * @return Returns 0 on success, or a negative error code value on failure.
748 */
749
750 int32_t
751 ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd, ...)
752 {
753 uint32_t rc = 0;
754 ocs_t *ocs = NULL;
755 va_list argp;
756
757 ocs_assert(xport, -1);
758 ocs_assert(xport->ocs, -1);
759 ocs = xport->ocs;
760
761 switch (cmd) {
762 case OCS_XPORT_PORT_ONLINE: {
763 /* Bring the port on-line */
764 rc = ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_INIT, 0, NULL, NULL);
765 if (rc) {
766 ocs_log_err(ocs, "%s: Can't init port\n", ocs->desc);
767 } else {
768 xport->configured_link_state = cmd;
769 }
770 break;
771 }
772 case OCS_XPORT_PORT_OFFLINE: {
773 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) {
774 ocs_log_err(ocs, "port shutdown failed\n");
775 } else {
776 xport->configured_link_state = cmd;
777 }
778 break;
779 }
780
781 case OCS_XPORT_SHUTDOWN: {
782 ocs_sem_t sem;
783 uint32_t reset_required;
784
785 /* if a PHYSDEV reset was performed (e.g. hw dump), will affect
786 * all PCI functions; orderly shutdown won't work, just force free
787 */
788 /* TODO: need to poll this regularly... */
789 if (ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required) != OCS_HW_RTN_SUCCESS) {
790 reset_required = 0;
791 }
792
793 if (reset_required) {
794 ocs_log_debug(ocs, "reset required, do force shutdown\n");
795 ocs_xport_force_free(xport);
796 break;
797 }
798 ocs_sem_init(&sem, 0, "domain_list_sem");
799 ocs_register_domain_list_empty_cb(ocs, ocs_xport_domain_list_empty_cb, &sem);
800
801 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) {
802 ocs_log_debug(ocs, "port shutdown failed, do force shutdown\n");
803 ocs_xport_force_free(xport);
804 } else {
805 ocs_log_debug(ocs, "Waiting %d seconds for domain shutdown.\n", (OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC/1000000));
806
807 rc = ocs_sem_p(&sem, OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC);
808 if (rc) {
809 ocs_log_debug(ocs, "Note: Domain shutdown timed out\n");
810 ocs_xport_force_free(xport);
811 }
812 }
813
814 ocs_register_domain_list_empty_cb(ocs, NULL, NULL);
815
816 /* Free up any saved virtual ports */
817 ocs_vport_del_all(ocs);
818 break;
819 }
820
821 /*
822 * POST_NODE_EVENT: post an event to a node object
823 *
824 * This transport function is used to post an event to a node object. It does
825 * this by submitting a NOP mailbox command to defer execution to the
826 * interrupt context (thereby enforcing the serialized execution of event posting
827 * to the node state machine instances)
828 *
829 * A counting semaphore is used to make the call synchronous (we wait until
830 * the callback increments the semaphore before returning (or times out)
831 */
832 case OCS_XPORT_POST_NODE_EVENT: {
833 ocs_node_t *node;
834 ocs_sm_event_t evt;
835 void *context;
836 ocs_xport_post_node_event_t payload;
837 ocs_t *ocs;
838 ocs_hw_t *hw;
839
840 /* Retrieve arguments */
841 va_start(argp, cmd);
842 node = va_arg(argp, ocs_node_t*);
843 evt = va_arg(argp, ocs_sm_event_t);
844 context = va_arg(argp, void *);
845 va_end(argp);
846
847 ocs_assert(node, -1);
848 ocs_assert(node->ocs, -1);
849
850 ocs = node->ocs;
851 hw = &ocs->hw;
852
853 /* if node's state machine is disabled, don't bother continuing */
854 if (!node->sm.current_state) {
855 ocs_log_test(ocs, "node %p state machine disabled\n", node);
856 return -1;
857 }
858
859 /* Setup payload */
860 ocs_memset(&payload, 0, sizeof(payload));
861 ocs_sem_init(&payload.sem, 0, "xport_post_node_Event");
862 payload.node = node;
863 payload.evt = evt;
864 payload.context = context;
865
866 if (ocs_hw_async_call(hw, ocs_xport_post_node_event_cb, &payload)) {
867 ocs_log_test(ocs, "ocs_hw_async_call failed\n");
868 rc = -1;
869 break;
870 }
871
872 /* Wait for completion */
873 if (ocs_sem_p(&payload.sem, OCS_SEM_FOREVER)) {
874 ocs_log_test(ocs, "POST_NODE_EVENT: sem wait failed\n");
875 rc = -1;
876 }
877
878 break;
879 }
880 /*
881 * Set wwnn for the port. This will be used instead of the default provided by FW.
882 */
883 case OCS_XPORT_WWNN_SET: {
884 uint64_t wwnn;
885
886 /* Retrieve arguments */
887 va_start(argp, cmd);
888 wwnn = va_arg(argp, uint64_t);
889 va_end(argp);
890
891 ocs_log_debug(ocs, " WWNN %016" PRIx64 "\n", wwnn);
892 xport->req_wwnn = wwnn;
893
894 break;
895 }
896 /*
897 * Set wwpn for the port. This will be used instead of the default provided by FW.
898 */
899 case OCS_XPORT_WWPN_SET: {
900 uint64_t wwpn;
901
902 /* Retrieve arguments */
903 va_start(argp, cmd);
904 wwpn = va_arg(argp, uint64_t);
905 va_end(argp);
906
907 ocs_log_debug(ocs, " WWPN %016" PRIx64 "\n", wwpn);
908 xport->req_wwpn = wwpn;
909
910 break;
911 }
912
913 default:
914 break;
915 }
916 return rc;
917 }
918
919 /**
920 * @brief Return status on a link.
921 *
922 * @par Description
923 * Returns status information about a link.
924 *
925 * @param xport Pointer to transport object.
926 * @param cmd Command to execute.
927 * @param result Pointer to result value.
928 *
929 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_PORT_STATUS)
930 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_SPEED, ocs_xport_stats_t *result)
931 * return link speed in MB/sec
932 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_IS_SUPPORTED_LINK_SPEED, ocs_xport_stats_t *result)
933 * [in] *result is speed to check in MB/s
934 * returns 1 if supported, 0 if not
935 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STATISTICS, ocs_xport_stats_t *result)
936 * return link/host port stats
937 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STAT_RESET, ocs_xport_stats_t *result)
938 * resets link/host stats
939 *
940 *
941 * @return Returns 0 on success, or a negative error code value on failure.
942 */
943
944 int32_t
945 ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result)
946 {
947 uint32_t rc = 0;
948 ocs_t *ocs = NULL;
949 ocs_xport_stats_t value;
950 ocs_hw_rtn_e hw_rc;
951
952 ocs_assert(xport, -1);
953 ocs_assert(xport->ocs, -1);
954
955 ocs = xport->ocs;
956
957 switch (cmd) {
958 case OCS_XPORT_CONFIG_PORT_STATUS:
959 ocs_assert(result, -1);
960 if (xport->configured_link_state == 0) {
961 /* Initial state is offline. configured_link_state is */
962 /* set to online explicitly when port is brought online. */
963 xport->configured_link_state = OCS_XPORT_PORT_OFFLINE;
964 }
965 result->value = xport->configured_link_state;
966 break;
967
968 case OCS_XPORT_PORT_STATUS:
969 ocs_assert(result, -1);
970 /* Determine port status based on link speed. */
971 hw_rc = ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value.value);
972 if (hw_rc == OCS_HW_RTN_SUCCESS) {
973 if (value.value == 0) {
974 result->value = 0;
975 } else {
976 result->value = 1;
977 }
978 rc = 0;
979 } else {
980 rc = -1;
981 }
982 break;
983
984 case OCS_XPORT_LINK_SPEED: {
985 uint32_t speed;
986
987 ocs_assert(result, -1);
988 result->value = 0;
989
990 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_SPEED, &speed);
991 if (rc == 0) {
992 result->value = speed;
993 }
994 break;
995 }
996
997 case OCS_XPORT_IS_SUPPORTED_LINK_SPEED: {
998 uint32_t speed;
999 uint32_t link_module_type;
1000
1001 ocs_assert(result, -1);
1002 speed = result->value;
1003
1004 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_MODULE_TYPE, &link_module_type);
1005 if (rc == 0) {
1006 switch(speed) {
1007 case 1000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_1GB) != 0; break;
1008 case 2000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_2GB) != 0; break;
1009 case 4000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_4GB) != 0; break;
1010 case 8000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_8GB) != 0; break;
1011 case 10000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_10GB) != 0; break;
1012 case 16000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_16GB) != 0; break;
1013 case 32000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_32GB) != 0; break;
1014 default: rc = 0; break;
1015 }
1016 } else {
1017 rc = 0;
1018 }
1019 break;
1020 }
1021 case OCS_XPORT_LINK_STATISTICS:
1022 ocs_device_lock(ocs);
1023 ocs_memcpy((void *)result, &ocs->xport->fc_xport_stats, sizeof(ocs_xport_stats_t));
1024 ocs_device_unlock(ocs);
1025 break;
1026 case OCS_XPORT_LINK_STAT_RESET: {
1027 /* Create a semaphore to synchronize the stat reset process. */
1028 ocs_sem_init(&(result->stats.semaphore), 0, "fc_stats_reset");
1029
1030 /* First reset the link stats */
1031 if ((rc = ocs_hw_get_link_stats(&ocs->hw, 0, 1, 1, ocs_xport_link_stats_cb, result)) != 0) {
1032 ocs_log_err(ocs, "%s: Failed to reset link statistics\n", __func__);
1033 break;
1034 }
1035
1036 /* Wait for semaphore to be signaled when the command completes */
1037 /* TODO: Should there be a timeout on this? If so, how long? */
1038 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
1039 /* Undefined failure */
1040 ocs_log_test(ocs, "ocs_sem_p failed\n");
1041 rc = -ENXIO;
1042 break;
1043 }
1044
1045 /* Next reset the host stats */
1046 if ((rc = ocs_hw_get_host_stats(&ocs->hw, 1, ocs_xport_host_stats_cb, result)) != 0) {
1047 ocs_log_err(ocs, "%s: Failed to reset host statistics\n", __func__);
1048 break;
1049 }
1050
1051 /* Wait for semaphore to be signaled when the command completes */
1052 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) {
1053 /* Undefined failure */
1054 ocs_log_test(ocs, "ocs_sem_p failed\n");
1055 rc = -ENXIO;
1056 break;
1057 }
1058 break;
1059 }
1060 case OCS_XPORT_IS_QUIESCED:
1061 ocs_device_lock(ocs);
1062 result->value = ocs_list_empty(&ocs->domain_list);
1063 ocs_device_unlock(ocs);
1064 break;
1065 default:
1066 rc = -1;
1067 break;
1068 }
1069
1070 return rc;
1071
1072 }
1073
1074 static void
1075 ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg)
1076 {
1077 ocs_xport_stats_t *result = arg;
1078
1079 result->stats.link_stats.link_failure_error_count = counters[OCS_HW_LINK_STAT_LINK_FAILURE_COUNT].counter;
1080 result->stats.link_stats.loss_of_sync_error_count = counters[OCS_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter;
1081 result->stats.link_stats.primitive_sequence_error_count = counters[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter;
1082 result->stats.link_stats.invalid_transmission_word_error_count = counters[OCS_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter;
1083 result->stats.link_stats.crc_error_count = counters[OCS_HW_LINK_STAT_CRC_COUNT].counter;
1084
1085 ocs_sem_v(&(result->stats.semaphore));
1086 }
1087
1088 static void
1089 ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg)
1090 {
1091 ocs_xport_stats_t *result = arg;
1092
1093 result->stats.host_stats.transmit_kbyte_count = counters[OCS_HW_HOST_STAT_TX_KBYTE_COUNT].counter;
1094 result->stats.host_stats.receive_kbyte_count = counters[OCS_HW_HOST_STAT_RX_KBYTE_COUNT].counter;
1095 result->stats.host_stats.transmit_frame_count = counters[OCS_HW_HOST_STAT_TX_FRAME_COUNT].counter;
1096 result->stats.host_stats.receive_frame_count = counters[OCS_HW_HOST_STAT_RX_FRAME_COUNT].counter;
1097
1098 ocs_sem_v(&(result->stats.semaphore));
1099 }
1100
1101 /**
1102 * @brief Free a transport object.
1103 *
1104 * @par Description
1105 * The transport object is freed.
1106 *
1107 * @param xport Pointer to transport object.
1108 *
1109 * @return None.
1110 */
1111
1112 void
1113 ocs_xport_free(ocs_xport_t *xport)
1114 {
1115 ocs_t *ocs;
1116 uint32_t i;
1117
1118 if (xport) {
1119 ocs = xport->ocs;
1120 ocs_io_pool_free(xport->io_pool);
1121 ocs_node_free_pool(ocs);
1122 if(mtx_initialized(&xport->io_pending_lock.lock))
1123 ocs_lock_free(&xport->io_pending_lock);
1124
1125 for (i = 0; i < SLI4_MAX_FCFI; i++) {
1126 ocs_lock_free(&xport->fcfi[i].pend_frames_lock);
1127 }
1128
1129 ocs_xport_rq_threads_teardown(xport);
1130
1131 ocs_free(ocs, xport, sizeof(*xport));
1132 }
1133 }
Cache object: 7b59e9a4d8ca0003ecd83cc549e705cf
|