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