xref: /freebsd/sys/dev/ocs_fc/ocs_xport.c (revision 78b9f0095b4af3aca6c931b2c7b009ddb8a05125)
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 	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 
286 ocs_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  */
310 static int32_t
311 ocs_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  */
388 int32_t
389 ocs_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 
574 ocs_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  */
601 int32_t
602 ocs_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 
636 static void
637 ocs_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 
664 static int32_t
665 ocs_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 
688 static void
689 ocs_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 
721 int32_t
722 ocs_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 
916 int32_t
917 ocs_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 
1046 static void
1047 ocs_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 
1061 static void
1062 ocs_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 
1086 void
1087 ocs_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