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