]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/ocs_fc/ocs_xport.c
Merge bmake-20180512
[FreeBSD/FreeBSD.git] / sys / dev / ocs_fc / ocs_xport.c
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 }