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
32/**
33 * @file
34 * FC transport API
35 *
36 */
37
38#include "ocs.h"
39#include "ocs_device.h"
40
41static void ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg);
42static void ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg);
43/**
44 * @brief Post node event callback argument.
45 */
46typedef struct {
47	ocs_sem_t sem;
48	ocs_node_t *node;
49	ocs_sm_event_t evt;
50	void *context;
51} ocs_xport_post_node_event_t;
52
53/**
54 * @brief Allocate a transport object.
55 *
56 * @par Description
57 * A transport object is allocated, and associated with a device instance.
58 *
59 * @param ocs Pointer to device instance.
60 *
61 * @return Returns the pointer to the allocated transport object, or NULL if failed.
62 */
63ocs_xport_t *
64ocs_xport_alloc(ocs_t *ocs)
65{
66	ocs_xport_t *xport;
67
68	ocs_assert(ocs, NULL);
69	xport = ocs_malloc(ocs, sizeof(*xport), OCS_M_ZERO);
70	if (xport != NULL) {
71		xport->ocs = ocs;
72	}
73	return xport;
74}
75
76/**
77 * @brief Create the RQ threads and the circular buffers used to pass sequences.
78 *
79 * @par Description
80 * Creates the circular buffers and the servicing threads for RQ processing.
81 *
82 * @param xport Pointer to transport object
83 *
84 * @return Returns 0 on success, or a non-zero value on failure.
85 */
86static void
87ocs_xport_rq_threads_teardown(ocs_xport_t *xport)
88{
89	ocs_t *ocs = xport->ocs;
90	uint32_t i;
91
92	if (xport->num_rq_threads == 0 ||
93	    xport->rq_thread_info == NULL) {
94		return;
95	}
96
97	/* Abort any threads */
98	for (i = 0; i < xport->num_rq_threads; i++) {
99		if (xport->rq_thread_info[i].thread_started) {
100			ocs_thread_terminate(&xport->rq_thread_info[i].thread);
101			/* wait for the thread to exit */
102			ocs_log_debug(ocs, "wait for thread %d to exit\n", i);
103			while (xport->rq_thread_info[i].thread_started) {
104				ocs_udelay(10000);
105			}
106			ocs_log_debug(ocs, "thread %d to exited\n", i);
107		}
108		if (xport->rq_thread_info[i].seq_cbuf != NULL) {
109			ocs_cbuf_free(xport->rq_thread_info[i].seq_cbuf);
110			xport->rq_thread_info[i].seq_cbuf = NULL;
111		}
112	}
113}
114
115/**
116 * @brief Create the RQ threads and the circular buffers used to pass sequences.
117 *
118 * @par Description
119 * Creates the circular buffers and the servicing threads for RQ processing.
120 *
121 * @param xport Pointer to transport object.
122 * @param num_rq_threads Number of RQ processing threads that the
123 * driver creates.
124 *
125 * @return Returns 0 on success, or a non-zero value on failure.
126 */
127static int32_t
128ocs_xport_rq_threads_create(ocs_xport_t *xport, uint32_t num_rq_threads)
129{
130	ocs_t *ocs = xport->ocs;
131	int32_t rc = 0;
132	uint32_t i;
133
134	xport->num_rq_threads = num_rq_threads;
135	ocs_log_debug(ocs, "number of RQ threads %d\n", num_rq_threads);
136	if (num_rq_threads == 0) {
137		return 0;
138	}
139
140	/* Allocate the space for the thread objects */
141	xport->rq_thread_info = ocs_malloc(ocs, sizeof(ocs_xport_rq_thread_info_t) * num_rq_threads, OCS_M_ZERO);
142	if (xport->rq_thread_info == NULL) {
143		ocs_log_err(ocs, "memory allocation failure\n");
144		return -1;
145	}
146
147	/* Create the circular buffers and threads. */
148	for (i = 0; i < num_rq_threads; i++) {
149		xport->rq_thread_info[i].ocs = ocs;
150		xport->rq_thread_info[i].seq_cbuf = ocs_cbuf_alloc(ocs, OCS_HW_RQ_NUM_HDR);
151		if (xport->rq_thread_info[i].seq_cbuf == NULL) {
152			goto ocs_xport_rq_threads_create_error;
153		}
154
155		ocs_snprintf(xport->rq_thread_info[i].thread_name,
156			     sizeof(xport->rq_thread_info[i].thread_name),
157			     "ocs_unsol_rq:%d:%d", ocs->instance_index, i);
158		rc = ocs_thread_create(ocs, &xport->rq_thread_info[i].thread, ocs_unsol_rq_thread,
159				       xport->rq_thread_info[i].thread_name,
160				       &xport->rq_thread_info[i], OCS_THREAD_RUN);
161		if (rc) {
162			ocs_log_err(ocs, "ocs_thread_create failed: %d\n", rc);
163			goto ocs_xport_rq_threads_create_error;
164		}
165		xport->rq_thread_info[i].thread_started = TRUE;
166	}
167	return 0;
168
169ocs_xport_rq_threads_create_error:
170	ocs_xport_rq_threads_teardown(xport);
171	return -1;
172}
173
174/**
175 * @brief Do as much allocation as possible, but do not initialization the device.
176 *
177 * @par Description
178 * Performs the functions required to get a device ready to run.
179 *
180 * @param xport Pointer to transport object.
181 *
182 * @return Returns 0 on success, or a non-zero value on failure.
183 */
184int32_t
185ocs_xport_attach(ocs_xport_t *xport)
186{
187	ocs_t *ocs = xport->ocs;
188	int32_t rc;
189	uint32_t max_sgl;
190	uint32_t n_sgl;
191	uint32_t i;
192	uint32_t value;
193	uint32_t max_remote_nodes;
194
195	/* booleans used for cleanup if initialization fails */
196	uint8_t io_pool_created = FALSE;
197	uint8_t node_pool_created = FALSE;
198
199	ocs_list_init(&ocs->domain_list, ocs_domain_t, link);
200
201	for (i = 0; i < SLI4_MAX_FCFI; i++) {
202		xport->fcfi[i].hold_frames = 1;
203		ocs_lock_init(ocs, &xport->fcfi[i].pend_frames_lock, "xport pend_frames[%d]", i);
204		ocs_list_init(&xport->fcfi[i].pend_frames, ocs_hw_sequence_t, link);
205	}
206
207	rc = ocs_hw_set_ptr(&ocs->hw, OCS_HW_WAR_VERSION, ocs->hw_war_version);
208	if (rc) {
209		ocs_log_test(ocs, "can't set OCS_HW_WAR_VERSION\n");
210		return -1;
211	}
212
213	rc = ocs_hw_setup(&ocs->hw, ocs, SLI4_PORT_TYPE_FC);
214	if (rc) {
215		ocs_log_err(ocs, "%s: Can't setup hardware\n", ocs->desc);
216		return -1;
217	} else if (ocs->ctrlmask & OCS_CTRLMASK_CRASH_RESET) {
218		ocs_log_debug(ocs, "stopping after ocs_hw_setup\n");
219		return -1;
220	}
221
222	ocs_hw_set(&ocs->hw, OCS_HW_BOUNCE, ocs->hw_bounce);
223	ocs_log_debug(ocs, "HW bounce: %d\n", ocs->hw_bounce);
224
225	ocs_hw_set(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, ocs->rq_selection_policy);
226	ocs_hw_set(&ocs->hw, OCS_HW_RR_QUANTA, ocs->rr_quanta);
227	ocs_hw_get(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, &value);
228	ocs_log_debug(ocs, "RQ Selection Policy: %d\n", value);
229
230	ocs_hw_set_ptr(&ocs->hw, OCS_HW_FILTER_DEF, (void*) ocs->filter_def);
231
232	ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
233	max_sgl -= SLI4_SGE_MAX_RESERVED;
234	n_sgl = MIN(OCS_FC_MAX_SGL, max_sgl);
235
236	/* EVT: For chained SGL testing */
237	if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) {
238		n_sgl = 4;
239	}
240
241	/* Note: number of SGLs must be set for ocs_node_create_pool */
242	if (ocs_hw_set(&ocs->hw, OCS_HW_N_SGL, n_sgl) != OCS_HW_RTN_SUCCESS) {
243		ocs_log_err(ocs, "%s: Can't set number of SGLs\n", ocs->desc);
244		return -1;
245	} else {
246		ocs_log_debug(ocs, "%s: Configured for %d SGLs\n", ocs->desc, n_sgl);
247	}
248
249	ocs_hw_get(&ocs->hw, OCS_HW_MAX_NODES, &max_remote_nodes);
250
251	if (!ocs->max_remote_nodes)
252		ocs->max_remote_nodes = max_remote_nodes;
253
254	rc = ocs_node_create_pool(ocs, ocs->max_remote_nodes);
255	if (rc) {
256		ocs_log_err(ocs, "Can't allocate node pool\n");
257		goto ocs_xport_attach_cleanup;
258	} else {
259		node_pool_created = TRUE;
260	}
261
262	/* EVT: if testing chained SGLs allocate OCS_FC_MAX_SGL SGE's in the IO */
263	xport->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios,
264		(ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) ? OCS_FC_MAX_SGL : n_sgl);
265	if (xport->io_pool == NULL) {
266		ocs_log_err(ocs, "Can't allocate IO pool\n");
267		goto ocs_xport_attach_cleanup;
268	} else {
269		io_pool_created = TRUE;
270	}
271
272	/*
273	 * setup the RQ processing threads
274	 */
275	if (ocs_xport_rq_threads_create(xport, ocs->rq_threads) != 0) {
276		ocs_log_err(ocs, "failure creating RQ threads\n");
277		goto ocs_xport_attach_cleanup;
278	}
279
280	return 0;
281
282ocs_xport_attach_cleanup:
283	if (io_pool_created) {
284		ocs_io_pool_free(xport->io_pool);
285	}
286
287	if (node_pool_created) {
288		ocs_node_free_pool(ocs);
289	}
290
291	return -1;
292}
293
294/**
295 * @brief Determines how to setup auto Xfer ready.
296 *
297 * @par Description
298 * @param xport Pointer to transport object.
299 *
300 * @return Returns 0 on success or a non-zero value on failure.
301 */
302static int32_t
303ocs_xport_initialize_auto_xfer_ready(ocs_xport_t *xport)
304{
305	ocs_t *ocs = xport->ocs;
306	uint32_t auto_xfer_rdy;
307	char prop_buf[32];
308	uint32_t ramdisc_blocksize = 512;
309	uint8_t p_type = 0;
310
311	ocs_hw_get(&ocs->hw, OCS_HW_AUTO_XFER_RDY_CAPABLE, &auto_xfer_rdy);
312	if (!auto_xfer_rdy) {
313		ocs->auto_xfer_rdy_size = 0;
314		ocs_log_test(ocs, "Cannot enable auto xfer rdy for this port\n");
315		return 0;
316	}
317
318	if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_SIZE, ocs->auto_xfer_rdy_size)) {
319		ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
320		return -1;
321	}
322
323	/*
324	 * Determine if we are doing protection in the backend. We are looking
325	 * at the modules parameters here. The backend cannot allow a format
326	 * command to change the protection mode when using this feature,
327	 * otherwise the firmware will not do the proper thing.
328	 */
329	if (ocs_get_property("p_type", prop_buf, sizeof(prop_buf)) == 0) {
330		p_type = ocs_strtoul(prop_buf, 0, 0);
331	}
332	if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) {
333		ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0);
334	}
335	if (ocs_get_property("external_dif", prop_buf, sizeof(prop_buf)) == 0) {
336		if(ocs_strlen(prop_buf)) {
337			if (p_type == 0) {
338				p_type = 1;
339			}
340		}
341	}
342
343	if (p_type != 0) {
344		if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_T10_ENABLE, TRUE)) {
345			ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
346			return -1;
347		}
348		if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_BLK_SIZE, ramdisc_blocksize)) {
349			ocs_log_test(ocs, "%s: Can't set auto xfer rdy blk size\n", ocs->desc);
350			return -1;
351		}
352		if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_P_TYPE, p_type)) {
353			ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc);
354			return -1;
355		}
356		if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA, TRUE)) {
357			ocs_log_test(ocs, "%s: Can't set auto xfer rdy ref tag\n", ocs->desc);
358			return -1;
359		}
360		if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID, FALSE)) {
361			ocs_log_test(ocs, "%s: Can't set auto xfer rdy app tag valid\n", ocs->desc);
362			return -1;
363		}
364	}
365	ocs_log_debug(ocs, "Auto xfer rdy is enabled, p_type=%d, blksize=%d\n",
366		p_type, ramdisc_blocksize);
367	return 0;
368}
369
370/**
371 * @brief Initialize link topology config
372 *
373 * @par Description
374 * Topology can be fetched from mod-param or Persistet Topology(PT).
375 *  a. Mod-param value is used when the value is 1(P2P) or 2(LOOP).
376 *  a. PT is used if mod-param is not provided( i.e, default value of AUTO)
377 * Also, if mod-param is used, update PT.
378 *
379 * @param ocs Pointer to ocs
380 *
381 * @return Returns 0 on success, or a non-zero value on failure.
382 */
383static int
384ocs_topology_setup(ocs_t *ocs)
385{
386        uint32_t topology;
387
388        if (ocs->topology == OCS_HW_TOPOLOGY_AUTO) {
389                topology = ocs_hw_get_config_persistent_topology(&ocs->hw);
390        }  else {
391                topology = ocs->topology;
392                /* ignore failure here. link will come-up either in auto mode
393                 * if PT is not supported or last saved PT value */
394                ocs_hw_set_persistent_topology(&ocs->hw, topology, OCS_CMD_POLL);
395        }
396
397        return ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, topology);
398}
399
400/**
401 * @brief Initializes the device.
402 *
403 * @par Description
404 * Performs the functions required to make a device functional.
405 *
406 * @param xport Pointer to transport object.
407 *
408 * @return Returns 0 on success, or a non-zero value on failure.
409 */
410int32_t
411ocs_xport_initialize(ocs_xport_t *xport)
412{
413	ocs_t *ocs = xport->ocs;
414	int32_t rc;
415	uint32_t i;
416	uint32_t max_hw_io;
417	uint32_t max_sgl;
418	uint32_t hlm;
419	uint32_t rq_limit;
420	uint32_t dif_capable;
421	uint8_t dif_separate = 0;
422	char prop_buf[32];
423
424	/* booleans used for cleanup if initialization fails */
425	uint8_t ini_device_set = FALSE;
426	uint8_t tgt_device_set = FALSE;
427	uint8_t hw_initialized = FALSE;
428
429	ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
430	if (ocs_hw_set(&ocs->hw, OCS_HW_N_IO, max_hw_io) != OCS_HW_RTN_SUCCESS) {
431		ocs_log_err(ocs, "%s: Can't set number of IOs\n", ocs->desc);
432		return -1;
433	}
434
435	ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl);
436	max_sgl -= SLI4_SGE_MAX_RESERVED;
437
438	if (ocs->enable_hlm) {
439		ocs_hw_get(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, &hlm);
440		if (!hlm) {
441			ocs->enable_hlm = FALSE;
442			ocs_log_err(ocs, "Cannot enable high login mode for this port\n");
443		} else {
444                        ocs_log_debug(ocs, "High login mode is enabled\n");
445			if (ocs_hw_set(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, TRUE)) {
446				ocs_log_err(ocs, "%s: Can't set high login mode\n", ocs->desc);
447				return -1;
448			}
449		}
450	}
451
452	/* validate the auto xfer_rdy size */
453	if (ocs->auto_xfer_rdy_size > 0 &&
454	    (ocs->auto_xfer_rdy_size < 2048 ||
455	     ocs->auto_xfer_rdy_size > 65536)) {
456		ocs_log_err(ocs, "Auto XFER_RDY size is out of range (2K-64K)\n");
457		return -1;
458	}
459
460	ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io);
461
462	if (ocs->auto_xfer_rdy_size > 0) {
463		if (ocs_xport_initialize_auto_xfer_ready(xport)) {
464			ocs_log_err(ocs, "%s: Failed auto xfer ready setup\n", ocs->desc);
465			return -1;
466		}
467		if (ocs->esoc){
468			ocs_hw_set(&ocs->hw, OCS_ESOC, TRUE);
469		}
470	}
471
472	if (ocs->explicit_buffer_list) {
473		/* Are pre-registered SGL's required? */
474		ocs_hw_get(&ocs->hw, OCS_HW_PREREGISTER_SGL, &i);
475		if (i == TRUE) {
476			ocs_log_err(ocs, "Explicit Buffer List not supported on this device, not enabled\n");
477		} else {
478			ocs_hw_set(&ocs->hw, OCS_HW_PREREGISTER_SGL, FALSE);
479		}
480	}
481
482	 /* Setup persistent topology based on topology mod-param value */
483        rc = ocs_topology_setup(ocs);
484        if (rc) {
485                ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
486                return -1;
487        }
488
489	if (ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, ocs->topology) != OCS_HW_RTN_SUCCESS) {
490		ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc);
491		return -1;
492	}
493	ocs_hw_set(&ocs->hw, OCS_HW_RQ_DEFAULT_BUFFER_SIZE, OCS_FC_RQ_SIZE_DEFAULT);
494
495	if (ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, ocs->speed) != OCS_HW_RTN_SUCCESS) {
496		ocs_log_err(ocs, "%s: Can't set the link speed\n", ocs->desc);
497		return -1;
498	}
499
500	if (ocs_hw_set(&ocs->hw, OCS_HW_ETH_LICENSE, ocs->ethernet_license) != OCS_HW_RTN_SUCCESS) {
501		ocs_log_err(ocs, "%s: Can't set the ethernet license\n", ocs->desc);
502		return -1;
503	}
504
505	/* currently only lancer support setting the CRC seed value */
506	if (ocs->hw.sli.asic_type == SLI4_ASIC_TYPE_LANCER) {
507		if (ocs_hw_set(&ocs->hw, OCS_HW_DIF_SEED, OCS_FC_DIF_SEED) != OCS_HW_RTN_SUCCESS) {
508			ocs_log_err(ocs, "%s: Can't set the DIF seed\n", ocs->desc);
509			return -1;
510		}
511	}
512
513	/* Set the Dif mode */
514	if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &dif_capable)) {
515		if (dif_capable) {
516			if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) {
517				dif_separate = ocs_strtoul(prop_buf, 0, 0);
518			}
519
520			if ((rc = ocs_hw_set(&ocs->hw, OCS_HW_DIF_MODE,
521			      (dif_separate == 0 ? OCS_HW_DIF_MODE_INLINE : OCS_HW_DIF_MODE_SEPARATE)))) {
522				ocs_log_err(ocs, "Requested DIF MODE not supported\n");
523			}
524		}
525	}
526
527	if (ocs->target_io_timer_sec || ocs->enable_ini) {
528		if (ocs->target_io_timer_sec)
529			ocs_log_debug(ocs, "setting target io timer=%d\n", ocs->target_io_timer_sec);
530
531		ocs_hw_set(&ocs->hw, OCS_HW_EMULATE_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
603ocs_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 */
630int32_t
631ocs_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
665static void
666ocs_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
693static int32_t
694ocs_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
717static void
718ocs_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
750int32_t
751ocs_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
944int32_t
945ocs_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
1074static void
1075ocs_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
1088static void
1089ocs_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
1112void
1113ocs_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}
1134