1 /*- 2 * Copyright (c) 2017 Broadcom. All rights reserved. 3 * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * 3. Neither the name of the copyright holder nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /** 33 * @file 34 * FC transport API 35 * 36 */ 37 38 #include "ocs.h" 39 #include "ocs_device.h" 40 41 static void ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg); 42 static void ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg); 43 /** 44 * @brief Post node event callback argument. 45 */ 46 typedef struct { 47 ocs_sem_t sem; 48 ocs_node_t *node; 49 ocs_sm_event_t evt; 50 void *context; 51 } ocs_xport_post_node_event_t; 52 53 /** 54 * @brief Allocate a transport object. 55 * 56 * @par Description 57 * A transport object is allocated, and associated with a device instance. 58 * 59 * @param ocs Pointer to device instance. 60 * 61 * @return Returns the pointer to the allocated transport object, or NULL if failed. 62 */ 63 ocs_xport_t * 64 ocs_xport_alloc(ocs_t *ocs) 65 { 66 ocs_xport_t *xport; 67 68 ocs_assert(ocs, NULL); 69 xport = ocs_malloc(ocs, sizeof(*xport), OCS_M_ZERO); 70 if (xport != NULL) { 71 xport->ocs = ocs; 72 } 73 return xport; 74 } 75 76 /** 77 * @brief Create the RQ threads and the circular buffers used to pass sequences. 78 * 79 * @par Description 80 * Creates the circular buffers and the servicing threads for RQ processing. 81 * 82 * @param xport Pointer to transport object 83 * 84 * @return Returns 0 on success, or a non-zero value on failure. 85 */ 86 static void 87 ocs_xport_rq_threads_teardown(ocs_xport_t *xport) 88 { 89 ocs_t *ocs = xport->ocs; 90 uint32_t i; 91 92 if (xport->num_rq_threads == 0 || 93 xport->rq_thread_info == NULL) { 94 return; 95 } 96 97 /* Abort any threads */ 98 for (i = 0; i < xport->num_rq_threads; i++) { 99 if (xport->rq_thread_info[i].thread_started) { 100 ocs_thread_terminate(&xport->rq_thread_info[i].thread); 101 /* wait for the thread to exit */ 102 ocs_log_debug(ocs, "wait for thread %d to exit\n", i); 103 while (xport->rq_thread_info[i].thread_started) { 104 ocs_udelay(10000); 105 } 106 ocs_log_debug(ocs, "thread %d to exited\n", i); 107 } 108 if (xport->rq_thread_info[i].seq_cbuf != NULL) { 109 ocs_cbuf_free(xport->rq_thread_info[i].seq_cbuf); 110 xport->rq_thread_info[i].seq_cbuf = NULL; 111 } 112 } 113 } 114 115 /** 116 * @brief Create the RQ threads and the circular buffers used to pass sequences. 117 * 118 * @par Description 119 * Creates the circular buffers and the servicing threads for RQ processing. 120 * 121 * @param xport Pointer to transport object. 122 * @param num_rq_threads Number of RQ processing threads that the 123 * driver creates. 124 * 125 * @return Returns 0 on success, or a non-zero value on failure. 126 */ 127 static int32_t 128 ocs_xport_rq_threads_create(ocs_xport_t *xport, uint32_t num_rq_threads) 129 { 130 ocs_t *ocs = xport->ocs; 131 int32_t rc = 0; 132 uint32_t i; 133 134 xport->num_rq_threads = num_rq_threads; 135 ocs_log_debug(ocs, "number of RQ threads %d\n", num_rq_threads); 136 if (num_rq_threads == 0) { 137 return 0; 138 } 139 140 /* Allocate the space for the thread objects */ 141 xport->rq_thread_info = ocs_malloc(ocs, sizeof(ocs_xport_rq_thread_info_t) * num_rq_threads, OCS_M_ZERO); 142 if (xport->rq_thread_info == NULL) { 143 ocs_log_err(ocs, "memory allocation failure\n"); 144 return -1; 145 } 146 147 /* Create the circular buffers and threads. */ 148 for (i = 0; i < num_rq_threads; i++) { 149 xport->rq_thread_info[i].ocs = ocs; 150 xport->rq_thread_info[i].seq_cbuf = ocs_cbuf_alloc(ocs, OCS_HW_RQ_NUM_HDR); 151 if (xport->rq_thread_info[i].seq_cbuf == NULL) { 152 goto ocs_xport_rq_threads_create_error; 153 } 154 155 ocs_snprintf(xport->rq_thread_info[i].thread_name, 156 sizeof(xport->rq_thread_info[i].thread_name), 157 "ocs_unsol_rq:%d:%d", ocs->instance_index, i); 158 rc = ocs_thread_create(ocs, &xport->rq_thread_info[i].thread, ocs_unsol_rq_thread, 159 xport->rq_thread_info[i].thread_name, 160 &xport->rq_thread_info[i], OCS_THREAD_RUN); 161 if (rc) { 162 ocs_log_err(ocs, "ocs_thread_create failed: %d\n", rc); 163 goto ocs_xport_rq_threads_create_error; 164 } 165 xport->rq_thread_info[i].thread_started = TRUE; 166 } 167 return 0; 168 169 ocs_xport_rq_threads_create_error: 170 ocs_xport_rq_threads_teardown(xport); 171 return -1; 172 } 173 174 /** 175 * @brief Do as much allocation as possible, but do not initialization the device. 176 * 177 * @par Description 178 * Performs the functions required to get a device ready to run. 179 * 180 * @param xport Pointer to transport object. 181 * 182 * @return Returns 0 on success, or a non-zero value on failure. 183 */ 184 int32_t 185 ocs_xport_attach(ocs_xport_t *xport) 186 { 187 ocs_t *ocs = xport->ocs; 188 int32_t rc; 189 uint32_t max_sgl; 190 uint32_t n_sgl; 191 uint32_t i; 192 uint32_t value; 193 uint32_t max_remote_nodes; 194 195 /* booleans used for cleanup if initialization fails */ 196 uint8_t io_pool_created = FALSE; 197 uint8_t node_pool_created = FALSE; 198 199 ocs_list_init(&ocs->domain_list, ocs_domain_t, link); 200 201 for (i = 0; i < SLI4_MAX_FCFI; i++) { 202 xport->fcfi[i].hold_frames = 1; 203 ocs_lock_init(ocs, &xport->fcfi[i].pend_frames_lock, "xport pend_frames[%d]", i); 204 ocs_list_init(&xport->fcfi[i].pend_frames, ocs_hw_sequence_t, link); 205 } 206 207 rc = ocs_hw_set_ptr(&ocs->hw, OCS_HW_WAR_VERSION, ocs->hw_war_version); 208 if (rc) { 209 ocs_log_test(ocs, "can't set OCS_HW_WAR_VERSION\n"); 210 return -1; 211 } 212 213 rc = ocs_hw_setup(&ocs->hw, ocs, SLI4_PORT_TYPE_FC); 214 if (rc) { 215 ocs_log_err(ocs, "%s: Can't setup hardware\n", ocs->desc); 216 return -1; 217 } else if (ocs->ctrlmask & OCS_CTRLMASK_CRASH_RESET) { 218 ocs_log_debug(ocs, "stopping after ocs_hw_setup\n"); 219 return -1; 220 } 221 222 ocs_hw_set(&ocs->hw, OCS_HW_BOUNCE, ocs->hw_bounce); 223 ocs_log_debug(ocs, "HW bounce: %d\n", ocs->hw_bounce); 224 225 ocs_hw_set(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, ocs->rq_selection_policy); 226 ocs_hw_set(&ocs->hw, OCS_HW_RR_QUANTA, ocs->rr_quanta); 227 ocs_hw_get(&ocs->hw, OCS_HW_RQ_SELECTION_POLICY, &value); 228 ocs_log_debug(ocs, "RQ Selection Policy: %d\n", value); 229 230 ocs_hw_set_ptr(&ocs->hw, OCS_HW_FILTER_DEF, (void*) ocs->filter_def); 231 232 ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl); 233 max_sgl -= SLI4_SGE_MAX_RESERVED; 234 n_sgl = MIN(OCS_FC_MAX_SGL, max_sgl); 235 236 /* EVT: For chained SGL testing */ 237 if (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) { 238 n_sgl = 4; 239 } 240 241 /* Note: number of SGLs must be set for ocs_node_create_pool */ 242 if (ocs_hw_set(&ocs->hw, OCS_HW_N_SGL, n_sgl) != OCS_HW_RTN_SUCCESS) { 243 ocs_log_err(ocs, "%s: Can't set number of SGLs\n", ocs->desc); 244 return -1; 245 } else { 246 ocs_log_debug(ocs, "%s: Configured for %d SGLs\n", ocs->desc, n_sgl); 247 } 248 249 ocs_hw_get(&ocs->hw, OCS_HW_MAX_NODES, &max_remote_nodes); 250 251 if (!ocs->max_remote_nodes) 252 ocs->max_remote_nodes = max_remote_nodes; 253 254 rc = ocs_node_create_pool(ocs, ocs->max_remote_nodes); 255 if (rc) { 256 ocs_log_err(ocs, "Can't allocate node pool\n"); 257 goto ocs_xport_attach_cleanup; 258 } else { 259 node_pool_created = TRUE; 260 } 261 262 /* EVT: if testing chained SGLs allocate OCS_FC_MAX_SGL SGE's in the IO */ 263 xport->io_pool = ocs_io_pool_create(ocs, ocs->num_scsi_ios, 264 (ocs->ctrlmask & OCS_CTRLMASK_TEST_CHAINED_SGLS) ? OCS_FC_MAX_SGL : n_sgl); 265 if (xport->io_pool == NULL) { 266 ocs_log_err(ocs, "Can't allocate IO pool\n"); 267 goto ocs_xport_attach_cleanup; 268 } else { 269 io_pool_created = TRUE; 270 } 271 272 /* 273 * setup the RQ processing threads 274 */ 275 if (ocs_xport_rq_threads_create(xport, ocs->rq_threads) != 0) { 276 ocs_log_err(ocs, "failure creating RQ threads\n"); 277 goto ocs_xport_attach_cleanup; 278 } 279 280 return 0; 281 282 ocs_xport_attach_cleanup: 283 if (io_pool_created) { 284 ocs_io_pool_free(xport->io_pool); 285 } 286 287 if (node_pool_created) { 288 ocs_node_free_pool(ocs); 289 } 290 291 return -1; 292 } 293 294 /** 295 * @brief Determines how to setup auto Xfer ready. 296 * 297 * @par Description 298 * @param xport Pointer to transport object. 299 * 300 * @return Returns 0 on success or a non-zero value on failure. 301 */ 302 static int32_t 303 ocs_xport_initialize_auto_xfer_ready(ocs_xport_t *xport) 304 { 305 ocs_t *ocs = xport->ocs; 306 uint32_t auto_xfer_rdy; 307 char prop_buf[32]; 308 uint32_t ramdisc_blocksize = 512; 309 uint8_t p_type = 0; 310 311 ocs_hw_get(&ocs->hw, OCS_HW_AUTO_XFER_RDY_CAPABLE, &auto_xfer_rdy); 312 if (!auto_xfer_rdy) { 313 ocs->auto_xfer_rdy_size = 0; 314 ocs_log_test(ocs, "Cannot enable auto xfer rdy for this port\n"); 315 return 0; 316 } 317 318 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_SIZE, ocs->auto_xfer_rdy_size)) { 319 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc); 320 return -1; 321 } 322 323 /* 324 * Determine if we are doing protection in the backend. We are looking 325 * at the modules parameters here. The backend cannot allow a format 326 * command to change the protection mode when using this feature, 327 * otherwise the firmware will not do the proper thing. 328 */ 329 if (ocs_get_property("p_type", prop_buf, sizeof(prop_buf)) == 0) { 330 p_type = ocs_strtoul(prop_buf, 0, 0); 331 } 332 if (ocs_get_property("ramdisc_blocksize", prop_buf, sizeof(prop_buf)) == 0) { 333 ramdisc_blocksize = ocs_strtoul(prop_buf, 0, 0); 334 } 335 if (ocs_get_property("external_dif", prop_buf, sizeof(prop_buf)) == 0) { 336 if(ocs_strlen(prop_buf)) { 337 if (p_type == 0) { 338 p_type = 1; 339 } 340 } 341 } 342 343 if (p_type != 0) { 344 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_T10_ENABLE, TRUE)) { 345 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc); 346 return -1; 347 } 348 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_BLK_SIZE, ramdisc_blocksize)) { 349 ocs_log_test(ocs, "%s: Can't set auto xfer rdy blk size\n", ocs->desc); 350 return -1; 351 } 352 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_P_TYPE, p_type)) { 353 ocs_log_test(ocs, "%s: Can't set auto xfer rdy mode\n", ocs->desc); 354 return -1; 355 } 356 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_REF_TAG_IS_LBA, TRUE)) { 357 ocs_log_test(ocs, "%s: Can't set auto xfer rdy ref tag\n", ocs->desc); 358 return -1; 359 } 360 if (ocs_hw_set(&ocs->hw, OCS_HW_AUTO_XFER_RDY_APP_TAG_VALID, FALSE)) { 361 ocs_log_test(ocs, "%s: Can't set auto xfer rdy app tag valid\n", ocs->desc); 362 return -1; 363 } 364 } 365 ocs_log_debug(ocs, "Auto xfer rdy is enabled, p_type=%d, blksize=%d\n", 366 p_type, ramdisc_blocksize); 367 return 0; 368 } 369 370 /** 371 * @brief Initialize link topology config 372 * 373 * @par Description 374 * Topology can be fetched from mod-param or Persistet Topology(PT). 375 * a. Mod-param value is used when the value is 1(P2P) or 2(LOOP). 376 * a. PT is used if mod-param is not provided( i.e, default value of AUTO) 377 * Also, if mod-param is used, update PT. 378 * 379 * @param ocs Pointer to ocs 380 * 381 * @return Returns 0 on success, or a non-zero value on failure. 382 */ 383 static int 384 ocs_topology_setup(ocs_t *ocs) 385 { 386 uint32_t topology; 387 388 if (ocs->topology == OCS_HW_TOPOLOGY_AUTO) { 389 topology = ocs_hw_get_config_persistent_topology(&ocs->hw); 390 } else { 391 topology = ocs->topology; 392 /* ignore failure here. link will come-up either in auto mode 393 * if PT is not supported or last saved PT value */ 394 ocs_hw_set_persistent_topology(&ocs->hw, topology, OCS_CMD_POLL); 395 } 396 397 return ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, topology); 398 } 399 400 /** 401 * @brief Initializes the device. 402 * 403 * @par Description 404 * Performs the functions required to make a device functional. 405 * 406 * @param xport Pointer to transport object. 407 * 408 * @return Returns 0 on success, or a non-zero value on failure. 409 */ 410 int32_t 411 ocs_xport_initialize(ocs_xport_t *xport) 412 { 413 ocs_t *ocs = xport->ocs; 414 int32_t rc; 415 uint32_t i; 416 uint32_t max_hw_io; 417 uint32_t max_sgl; 418 uint32_t hlm; 419 uint32_t rq_limit; 420 uint32_t dif_capable; 421 uint8_t dif_separate = 0; 422 char prop_buf[32]; 423 424 /* booleans used for cleanup if initialization fails */ 425 uint8_t ini_device_set = FALSE; 426 uint8_t tgt_device_set = FALSE; 427 uint8_t hw_initialized = FALSE; 428 429 ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io); 430 if (ocs_hw_set(&ocs->hw, OCS_HW_N_IO, max_hw_io) != OCS_HW_RTN_SUCCESS) { 431 ocs_log_err(ocs, "%s: Can't set number of IOs\n", ocs->desc); 432 return -1; 433 } 434 435 ocs_hw_get(&ocs->hw, OCS_HW_MAX_SGL, &max_sgl); 436 max_sgl -= SLI4_SGE_MAX_RESERVED; 437 438 if (ocs->enable_hlm) { 439 ocs_hw_get(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, &hlm); 440 if (!hlm) { 441 ocs->enable_hlm = FALSE; 442 ocs_log_err(ocs, "Cannot enable high login mode for this port\n"); 443 } else { 444 ocs_log_debug(ocs, "High login mode is enabled\n"); 445 if (ocs_hw_set(&ocs->hw, OCS_HW_HIGH_LOGIN_MODE, TRUE)) { 446 ocs_log_err(ocs, "%s: Can't set high login mode\n", ocs->desc); 447 return -1; 448 } 449 } 450 } 451 452 /* validate the auto xfer_rdy size */ 453 if (ocs->auto_xfer_rdy_size > 0 && 454 (ocs->auto_xfer_rdy_size < 2048 || 455 ocs->auto_xfer_rdy_size > 65536)) { 456 ocs_log_err(ocs, "Auto XFER_RDY size is out of range (2K-64K)\n"); 457 return -1; 458 } 459 460 ocs_hw_get(&ocs->hw, OCS_HW_MAX_IO, &max_hw_io); 461 462 if (ocs->auto_xfer_rdy_size > 0) { 463 if (ocs_xport_initialize_auto_xfer_ready(xport)) { 464 ocs_log_err(ocs, "%s: Failed auto xfer ready setup\n", ocs->desc); 465 return -1; 466 } 467 if (ocs->esoc){ 468 ocs_hw_set(&ocs->hw, OCS_ESOC, TRUE); 469 } 470 } 471 472 if (ocs->explicit_buffer_list) { 473 /* Are pre-registered SGL's required? */ 474 ocs_hw_get(&ocs->hw, OCS_HW_PREREGISTER_SGL, &i); 475 if (i == TRUE) { 476 ocs_log_err(ocs, "Explicit Buffer List not supported on this device, not enabled\n"); 477 } else { 478 ocs_hw_set(&ocs->hw, OCS_HW_PREREGISTER_SGL, FALSE); 479 } 480 } 481 482 /* Setup persistent topology based on topology mod-param value */ 483 rc = ocs_topology_setup(ocs); 484 if (rc) { 485 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc); 486 return -1; 487 } 488 489 if (ocs_hw_set(&ocs->hw, OCS_HW_TOPOLOGY, ocs->topology) != OCS_HW_RTN_SUCCESS) { 490 ocs_log_err(ocs, "%s: Can't set the toplogy\n", ocs->desc); 491 return -1; 492 } 493 ocs_hw_set(&ocs->hw, OCS_HW_RQ_DEFAULT_BUFFER_SIZE, OCS_FC_RQ_SIZE_DEFAULT); 494 495 if (ocs_hw_set(&ocs->hw, OCS_HW_LINK_SPEED, ocs->speed) != OCS_HW_RTN_SUCCESS) { 496 ocs_log_err(ocs, "%s: Can't set the link speed\n", ocs->desc); 497 return -1; 498 } 499 500 if (ocs_hw_set(&ocs->hw, OCS_HW_ETH_LICENSE, ocs->ethernet_license) != OCS_HW_RTN_SUCCESS) { 501 ocs_log_err(ocs, "%s: Can't set the ethernet license\n", ocs->desc); 502 return -1; 503 } 504 505 /* currently only lancer support setting the CRC seed value */ 506 if (ocs->hw.sli.asic_type == SLI4_ASIC_TYPE_LANCER) { 507 if (ocs_hw_set(&ocs->hw, OCS_HW_DIF_SEED, OCS_FC_DIF_SEED) != OCS_HW_RTN_SUCCESS) { 508 ocs_log_err(ocs, "%s: Can't set the DIF seed\n", ocs->desc); 509 return -1; 510 } 511 } 512 513 /* Set the Dif mode */ 514 if (0 == ocs_hw_get(&ocs->hw, OCS_HW_DIF_CAPABLE, &dif_capable)) { 515 if (dif_capable) { 516 if (ocs_get_property("dif_separate", prop_buf, sizeof(prop_buf)) == 0) { 517 dif_separate = ocs_strtoul(prop_buf, 0, 0); 518 } 519 520 if ((rc = ocs_hw_set(&ocs->hw, OCS_HW_DIF_MODE, 521 (dif_separate == 0 ? OCS_HW_DIF_MODE_INLINE : OCS_HW_DIF_MODE_SEPARATE)))) { 522 ocs_log_err(ocs, "Requested DIF MODE not supported\n"); 523 } 524 } 525 } 526 527 if (ocs->target_io_timer_sec) { 528 ocs_log_debug(ocs, "setting target io timer=%d\n", ocs->target_io_timer_sec); 529 ocs_hw_set(&ocs->hw, OCS_HW_EMULATE_TARGET_WQE_TIMEOUT, TRUE); 530 } 531 532 ocs_hw_callback(&ocs->hw, OCS_HW_CB_DOMAIN, ocs_domain_cb, ocs); 533 ocs_hw_callback(&ocs->hw, OCS_HW_CB_REMOTE_NODE, ocs_remote_node_cb, ocs); 534 ocs_hw_callback(&ocs->hw, OCS_HW_CB_UNSOLICITED, ocs_unsolicited_cb, ocs); 535 ocs_hw_callback(&ocs->hw, OCS_HW_CB_PORT, ocs_port_cb, ocs); 536 537 ocs->fw_version = (const char*) ocs_hw_get_ptr(&ocs->hw, OCS_HW_FW_REV); 538 539 /* Initialize vport list */ 540 ocs_list_init(&xport->vport_list, ocs_vport_spec_t, link); 541 ocs_lock_init(ocs, &xport->io_pending_lock, "io_pending_lock[%d]", ocs->instance_index); 542 ocs_list_init(&xport->io_pending_list, ocs_io_t, io_pending_link); 543 ocs_atomic_init(&xport->io_active_count, 0); 544 ocs_atomic_init(&xport->io_pending_count, 0); 545 ocs_atomic_init(&xport->io_total_free, 0); 546 ocs_atomic_init(&xport->io_total_pending, 0); 547 ocs_atomic_init(&xport->io_alloc_failed_count, 0); 548 ocs_atomic_init(&xport->io_pending_recursing, 0); 549 ocs_lock_init(ocs, &ocs->hw.watchdog_lock, " Watchdog Lock[%d]", ocs_instance(ocs)); 550 rc = ocs_hw_init(&ocs->hw); 551 if (rc) { 552 ocs_log_err(ocs, "ocs_hw_init failure\n"); 553 goto ocs_xport_init_cleanup; 554 } else { 555 hw_initialized = TRUE; 556 } 557 558 rq_limit = max_hw_io/2; 559 if (ocs_hw_set(&ocs->hw, OCS_HW_RQ_PROCESS_LIMIT, rq_limit) != OCS_HW_RTN_SUCCESS) { 560 ocs_log_err(ocs, "%s: Can't set the RQ process limit\n", ocs->desc); 561 } 562 563 if (ocs->config_tgt) { 564 rc = ocs_scsi_tgt_new_device(ocs); 565 if (rc) { 566 ocs_log_err(ocs, "failed to initialize target\n"); 567 goto ocs_xport_init_cleanup; 568 } else { 569 tgt_device_set = TRUE; 570 } 571 } 572 573 if (ocs->enable_ini) { 574 rc = ocs_scsi_ini_new_device(ocs); 575 if (rc) { 576 ocs_log_err(ocs, "failed to initialize initiator\n"); 577 goto ocs_xport_init_cleanup; 578 } else { 579 ini_device_set = TRUE; 580 } 581 } 582 583 /* Add vports */ 584 if (ocs->num_vports != 0) { 585 uint32_t max_vports; 586 ocs_hw_get(&ocs->hw, OCS_HW_MAX_VPORTS, &max_vports); 587 588 if (ocs->num_vports < max_vports) { 589 ocs_log_debug(ocs, "Provisioning %d vports\n", ocs->num_vports); 590 for (i = 0; i < ocs->num_vports; i++) { 591 ocs_vport_create_spec(ocs, 0, 0, UINT32_MAX, ocs->enable_ini, ocs->enable_tgt, NULL, NULL); 592 } 593 } else { 594 ocs_log_err(ocs, "failed to create vports. num_vports range should be (1-%d) \n", max_vports-1); 595 goto ocs_xport_init_cleanup; 596 } 597 } 598 599 return 0; 600 601 ocs_xport_init_cleanup: 602 if (ini_device_set) { 603 ocs_scsi_ini_del_device(ocs); 604 } 605 606 if (tgt_device_set) { 607 ocs_scsi_tgt_del_device(ocs); 608 } 609 610 if (hw_initialized) { 611 /* ocs_hw_teardown can only execute after ocs_hw_init */ 612 ocs_hw_teardown(&ocs->hw); 613 } 614 615 return -1; 616 } 617 618 /** 619 * @brief Detaches the transport from the device. 620 * 621 * @par Description 622 * Performs the functions required to shut down a device. 623 * 624 * @param xport Pointer to transport object. 625 * 626 * @return Returns 0 on success or a non-zero value on failure. 627 */ 628 int32_t 629 ocs_xport_detach(ocs_xport_t *xport) 630 { 631 ocs_t *ocs = xport->ocs; 632 633 /* free resources associated with target-server and initiator-client */ 634 if (ocs->config_tgt) 635 ocs_scsi_tgt_del_device(ocs); 636 637 if (ocs->enable_ini) { 638 ocs_scsi_ini_del_device(ocs); 639 640 /*Shutdown FC Statistics timer*/ 641 if (ocs_timer_pending(&ocs->xport->stats_timer)) 642 ocs_del_timer(&ocs->xport->stats_timer); 643 } 644 645 ocs_hw_teardown(&ocs->hw); 646 647 return 0; 648 } 649 650 /** 651 * @brief domain list empty callback 652 * 653 * @par Description 654 * Function is invoked when the device domain list goes empty. By convention 655 * @c arg points to an ocs_sem_t instance, that is incremented. 656 * 657 * @param ocs Pointer to device object. 658 * @param arg Pointer to semaphore instance. 659 * 660 * @return None. 661 */ 662 663 static void 664 ocs_xport_domain_list_empty_cb(ocs_t *ocs, void *arg) 665 { 666 ocs_sem_t *sem = arg; 667 668 ocs_assert(ocs); 669 ocs_assert(sem); 670 671 ocs_sem_v(sem); 672 } 673 674 /** 675 * @brief post node event callback 676 * 677 * @par Description 678 * This function is called from the mailbox completion interrupt context to post an 679 * event to a node object. By doing this in the interrupt context, it has 680 * the benefit of only posting events in the interrupt context, deferring the need to 681 * create a per event node lock. 682 * 683 * @param hw Pointer to HW structure. 684 * @param status Completion status for mailbox command. 685 * @param mqe Mailbox queue completion entry. 686 * @param arg Callback argument. 687 * 688 * @return Returns 0 on success, a negative error code value on failure. 689 */ 690 691 static int32_t 692 ocs_xport_post_node_event_cb(ocs_hw_t *hw, int32_t status, uint8_t *mqe, void *arg) 693 { 694 ocs_xport_post_node_event_t *payload = arg; 695 696 if (payload != NULL) { 697 ocs_node_post_event(payload->node, payload->evt, payload->context); 698 ocs_sem_v(&payload->sem); 699 } 700 701 return 0; 702 } 703 704 /** 705 * @brief Initiate force free. 706 * 707 * @par Description 708 * Perform force free of OCS. 709 * 710 * @param xport Pointer to transport object. 711 * 712 * @return None. 713 */ 714 715 static void 716 ocs_xport_force_free(ocs_xport_t *xport) 717 { 718 ocs_t *ocs = xport->ocs; 719 ocs_domain_t *domain; 720 ocs_domain_t *next; 721 722 ocs_log_debug(ocs, "reset required, do force shutdown\n"); 723 ocs_device_lock(ocs); 724 ocs_list_foreach_safe(&ocs->domain_list, domain, next) { 725 ocs_domain_force_free(domain); 726 } 727 ocs_device_unlock(ocs); 728 } 729 730 /** 731 * @brief Perform transport attach function. 732 * 733 * @par Description 734 * Perform the attach function, which for the FC transport makes a HW call 735 * to bring up the link. 736 * 737 * @param xport pointer to transport object. 738 * @param cmd command to execute. 739 * 740 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_ONLINE) 741 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_OFFLINE) 742 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_PORT_SHUTDOWN) 743 * ocs_xport_control(ocs_xport_t *xport, OCS_XPORT_POST_NODE_EVENT, ocs_node_t *node, ocs_sm_event_t, void *context) 744 * 745 * @return Returns 0 on success, or a negative error code value on failure. 746 */ 747 748 int32_t 749 ocs_xport_control(ocs_xport_t *xport, ocs_xport_ctrl_e cmd, ...) 750 { 751 uint32_t rc = 0; 752 ocs_t *ocs = NULL; 753 va_list argp; 754 755 ocs_assert(xport, -1); 756 ocs_assert(xport->ocs, -1); 757 ocs = xport->ocs; 758 759 switch (cmd) { 760 case OCS_XPORT_PORT_ONLINE: { 761 /* Bring the port on-line */ 762 rc = ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_INIT, 0, NULL, NULL); 763 if (rc) { 764 ocs_log_err(ocs, "%s: Can't init port\n", ocs->desc); 765 } else { 766 xport->configured_link_state = cmd; 767 } 768 break; 769 } 770 case OCS_XPORT_PORT_OFFLINE: { 771 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) { 772 ocs_log_err(ocs, "port shutdown failed\n"); 773 } else { 774 xport->configured_link_state = cmd; 775 } 776 break; 777 } 778 779 case OCS_XPORT_SHUTDOWN: { 780 ocs_sem_t sem; 781 uint32_t reset_required; 782 783 /* if a PHYSDEV reset was performed (e.g. hw dump), will affect 784 * all PCI functions; orderly shutdown won't work, just force free 785 */ 786 /* TODO: need to poll this regularly... */ 787 if (ocs_hw_get(&ocs->hw, OCS_HW_RESET_REQUIRED, &reset_required) != OCS_HW_RTN_SUCCESS) { 788 reset_required = 0; 789 } 790 791 if (reset_required) { 792 ocs_log_debug(ocs, "reset required, do force shutdown\n"); 793 ocs_xport_force_free(xport); 794 break; 795 } 796 ocs_sem_init(&sem, 0, "domain_list_sem"); 797 ocs_register_domain_list_empty_cb(ocs, ocs_xport_domain_list_empty_cb, &sem); 798 799 if (ocs_hw_port_control(&ocs->hw, OCS_HW_PORT_SHUTDOWN, 0, NULL, NULL)) { 800 ocs_log_debug(ocs, "port shutdown failed, do force shutdown\n"); 801 ocs_xport_force_free(xport); 802 } else { 803 ocs_log_debug(ocs, "Waiting %d seconds for domain shutdown.\n", (OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC/1000000)); 804 805 rc = ocs_sem_p(&sem, OCS_FC_DOMAIN_SHUTDOWN_TIMEOUT_USEC); 806 if (rc) { 807 ocs_log_debug(ocs, "Note: Domain shutdown timed out\n"); 808 ocs_xport_force_free(xport); 809 } 810 } 811 812 ocs_register_domain_list_empty_cb(ocs, NULL, NULL); 813 814 /* Free up any saved virtual ports */ 815 ocs_vport_del_all(ocs); 816 break; 817 } 818 819 /* 820 * POST_NODE_EVENT: post an event to a node object 821 * 822 * This transport function is used to post an event to a node object. It does 823 * this by submitting a NOP mailbox command to defer execution to the 824 * interrupt context (thereby enforcing the serialized execution of event posting 825 * to the node state machine instances) 826 * 827 * A counting semaphore is used to make the call synchronous (we wait until 828 * the callback increments the semaphore before returning (or times out) 829 */ 830 case OCS_XPORT_POST_NODE_EVENT: { 831 ocs_node_t *node; 832 ocs_sm_event_t evt; 833 void *context; 834 ocs_xport_post_node_event_t payload; 835 ocs_t *ocs; 836 ocs_hw_t *hw; 837 838 /* Retrieve arguments */ 839 va_start(argp, cmd); 840 node = va_arg(argp, ocs_node_t*); 841 evt = va_arg(argp, ocs_sm_event_t); 842 context = va_arg(argp, void *); 843 va_end(argp); 844 845 ocs_assert(node, -1); 846 ocs_assert(node->ocs, -1); 847 848 ocs = node->ocs; 849 hw = &ocs->hw; 850 851 /* if node's state machine is disabled, don't bother continuing */ 852 if (!node->sm.current_state) { 853 ocs_log_test(ocs, "node %p state machine disabled\n", node); 854 return -1; 855 } 856 857 /* Setup payload */ 858 ocs_memset(&payload, 0, sizeof(payload)); 859 ocs_sem_init(&payload.sem, 0, "xport_post_node_Event"); 860 payload.node = node; 861 payload.evt = evt; 862 payload.context = context; 863 864 if (ocs_hw_async_call(hw, ocs_xport_post_node_event_cb, &payload)) { 865 ocs_log_test(ocs, "ocs_hw_async_call failed\n"); 866 rc = -1; 867 break; 868 } 869 870 /* Wait for completion */ 871 if (ocs_sem_p(&payload.sem, OCS_SEM_FOREVER)) { 872 ocs_log_test(ocs, "POST_NODE_EVENT: sem wait failed\n"); 873 rc = -1; 874 } 875 876 break; 877 } 878 /* 879 * Set wwnn for the port. This will be used instead of the default provided by FW. 880 */ 881 case OCS_XPORT_WWNN_SET: { 882 uint64_t wwnn; 883 884 /* Retrieve arguments */ 885 va_start(argp, cmd); 886 wwnn = va_arg(argp, uint64_t); 887 va_end(argp); 888 889 ocs_log_debug(ocs, " WWNN %016" PRIx64 "\n", wwnn); 890 xport->req_wwnn = wwnn; 891 892 break; 893 } 894 /* 895 * Set wwpn for the port. This will be used instead of the default provided by FW. 896 */ 897 case OCS_XPORT_WWPN_SET: { 898 uint64_t wwpn; 899 900 /* Retrieve arguments */ 901 va_start(argp, cmd); 902 wwpn = va_arg(argp, uint64_t); 903 va_end(argp); 904 905 ocs_log_debug(ocs, " WWPN %016" PRIx64 "\n", wwpn); 906 xport->req_wwpn = wwpn; 907 908 break; 909 } 910 911 default: 912 break; 913 } 914 return rc; 915 } 916 917 /** 918 * @brief Return status on a link. 919 * 920 * @par Description 921 * Returns status information about a link. 922 * 923 * @param xport Pointer to transport object. 924 * @param cmd Command to execute. 925 * @param result Pointer to result value. 926 * 927 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_PORT_STATUS) 928 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_SPEED, ocs_xport_stats_t *result) 929 * return link speed in MB/sec 930 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_IS_SUPPORTED_LINK_SPEED, ocs_xport_stats_t *result) 931 * [in] *result is speed to check in MB/s 932 * returns 1 if supported, 0 if not 933 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STATISTICS, ocs_xport_stats_t *result) 934 * return link/host port stats 935 * ocs_xport_status(ocs_xport_t *xport, OCS_XPORT_LINK_STAT_RESET, ocs_xport_stats_t *result) 936 * resets link/host stats 937 * 938 * 939 * @return Returns 0 on success, or a negative error code value on failure. 940 */ 941 942 int32_t 943 ocs_xport_status(ocs_xport_t *xport, ocs_xport_status_e cmd, ocs_xport_stats_t *result) 944 { 945 uint32_t rc = 0; 946 ocs_t *ocs = NULL; 947 ocs_xport_stats_t value; 948 ocs_hw_rtn_e hw_rc; 949 950 ocs_assert(xport, -1); 951 ocs_assert(xport->ocs, -1); 952 953 ocs = xport->ocs; 954 955 switch (cmd) { 956 case OCS_XPORT_CONFIG_PORT_STATUS: 957 ocs_assert(result, -1); 958 if (xport->configured_link_state == 0) { 959 /* Initial state is offline. configured_link_state is */ 960 /* set to online explicitly when port is brought online. */ 961 xport->configured_link_state = OCS_XPORT_PORT_OFFLINE; 962 } 963 result->value = xport->configured_link_state; 964 break; 965 966 case OCS_XPORT_PORT_STATUS: 967 ocs_assert(result, -1); 968 /* Determine port status based on link speed. */ 969 hw_rc = ocs_hw_get(&(ocs->hw), OCS_HW_LINK_SPEED, &value.value); 970 if (hw_rc == OCS_HW_RTN_SUCCESS) { 971 if (value.value == 0) { 972 result->value = 0; 973 } else { 974 result->value = 1; 975 } 976 rc = 0; 977 } else { 978 rc = -1; 979 } 980 break; 981 982 case OCS_XPORT_LINK_SPEED: { 983 uint32_t speed; 984 985 ocs_assert(result, -1); 986 result->value = 0; 987 988 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_SPEED, &speed); 989 if (rc == 0) { 990 result->value = speed; 991 } 992 break; 993 } 994 995 case OCS_XPORT_IS_SUPPORTED_LINK_SPEED: { 996 uint32_t speed; 997 uint32_t link_module_type; 998 999 ocs_assert(result, -1); 1000 speed = result->value; 1001 1002 rc = ocs_hw_get(&ocs->hw, OCS_HW_LINK_MODULE_TYPE, &link_module_type); 1003 if (rc == 0) { 1004 switch(speed) { 1005 case 1000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_1GB) != 0; break; 1006 case 2000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_2GB) != 0; break; 1007 case 4000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_4GB) != 0; break; 1008 case 8000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_8GB) != 0; break; 1009 case 10000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_10GB) != 0; break; 1010 case 16000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_16GB) != 0; break; 1011 case 32000: rc = (link_module_type & OCS_HW_LINK_MODULE_TYPE_32GB) != 0; break; 1012 default: rc = 0; break; 1013 } 1014 } else { 1015 rc = 0; 1016 } 1017 break; 1018 } 1019 case OCS_XPORT_LINK_STATISTICS: 1020 ocs_device_lock(ocs); 1021 ocs_memcpy((void *)result, &ocs->xport->fc_xport_stats, sizeof(ocs_xport_stats_t)); 1022 ocs_device_unlock(ocs); 1023 break; 1024 case OCS_XPORT_LINK_STAT_RESET: { 1025 /* Create a semaphore to synchronize the stat reset process. */ 1026 ocs_sem_init(&(result->stats.semaphore), 0, "fc_stats_reset"); 1027 1028 /* First reset the link stats */ 1029 if ((rc = ocs_hw_get_link_stats(&ocs->hw, 0, 1, 1, ocs_xport_link_stats_cb, result)) != 0) { 1030 ocs_log_err(ocs, "%s: Failed to reset link statistics\n", __func__); 1031 break; 1032 } 1033 1034 /* Wait for semaphore to be signaled when the command completes */ 1035 /* TODO: Should there be a timeout on this? If so, how long? */ 1036 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) { 1037 /* Undefined failure */ 1038 ocs_log_test(ocs, "ocs_sem_p failed\n"); 1039 rc = -ENXIO; 1040 break; 1041 } 1042 1043 /* Next reset the host stats */ 1044 if ((rc = ocs_hw_get_host_stats(&ocs->hw, 1, ocs_xport_host_stats_cb, result)) != 0) { 1045 ocs_log_err(ocs, "%s: Failed to reset host statistics\n", __func__); 1046 break; 1047 } 1048 1049 /* Wait for semaphore to be signaled when the command completes */ 1050 if (ocs_sem_p(&(result->stats.semaphore), OCS_SEM_FOREVER) != 0) { 1051 /* Undefined failure */ 1052 ocs_log_test(ocs, "ocs_sem_p failed\n"); 1053 rc = -ENXIO; 1054 break; 1055 } 1056 break; 1057 } 1058 case OCS_XPORT_IS_QUIESCED: 1059 ocs_device_lock(ocs); 1060 result->value = ocs_list_empty(&ocs->domain_list); 1061 ocs_device_unlock(ocs); 1062 break; 1063 default: 1064 rc = -1; 1065 break; 1066 } 1067 1068 return rc; 1069 1070 } 1071 1072 static void 1073 ocs_xport_link_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_link_stat_counts_t *counters, void *arg) 1074 { 1075 ocs_xport_stats_t *result = arg; 1076 1077 result->stats.link_stats.link_failure_error_count = counters[OCS_HW_LINK_STAT_LINK_FAILURE_COUNT].counter; 1078 result->stats.link_stats.loss_of_sync_error_count = counters[OCS_HW_LINK_STAT_LOSS_OF_SYNC_COUNT].counter; 1079 result->stats.link_stats.primitive_sequence_error_count = counters[OCS_HW_LINK_STAT_PRIMITIVE_SEQ_COUNT].counter; 1080 result->stats.link_stats.invalid_transmission_word_error_count = counters[OCS_HW_LINK_STAT_INVALID_XMIT_WORD_COUNT].counter; 1081 result->stats.link_stats.crc_error_count = counters[OCS_HW_LINK_STAT_CRC_COUNT].counter; 1082 1083 ocs_sem_v(&(result->stats.semaphore)); 1084 } 1085 1086 static void 1087 ocs_xport_host_stats_cb(int32_t status, uint32_t num_counters, ocs_hw_host_stat_counts_t *counters, void *arg) 1088 { 1089 ocs_xport_stats_t *result = arg; 1090 1091 result->stats.host_stats.transmit_kbyte_count = counters[OCS_HW_HOST_STAT_TX_KBYTE_COUNT].counter; 1092 result->stats.host_stats.receive_kbyte_count = counters[OCS_HW_HOST_STAT_RX_KBYTE_COUNT].counter; 1093 result->stats.host_stats.transmit_frame_count = counters[OCS_HW_HOST_STAT_TX_FRAME_COUNT].counter; 1094 result->stats.host_stats.receive_frame_count = counters[OCS_HW_HOST_STAT_RX_FRAME_COUNT].counter; 1095 1096 ocs_sem_v(&(result->stats.semaphore)); 1097 } 1098 1099 /** 1100 * @brief Free a transport object. 1101 * 1102 * @par Description 1103 * The transport object is freed. 1104 * 1105 * @param xport Pointer to transport object. 1106 * 1107 * @return None. 1108 */ 1109 1110 void 1111 ocs_xport_free(ocs_xport_t *xport) 1112 { 1113 ocs_t *ocs; 1114 uint32_t i; 1115 1116 if (xport) { 1117 ocs = xport->ocs; 1118 ocs_io_pool_free(xport->io_pool); 1119 ocs_node_free_pool(ocs); 1120 if(mtx_initialized(&xport->io_pending_lock.lock)) 1121 ocs_lock_free(&xport->io_pending_lock); 1122 1123 for (i = 0; i < SLI4_MAX_FCFI; i++) { 1124 ocs_lock_free(&xport->fcfi[i].pend_frames_lock); 1125 } 1126 1127 ocs_xport_rq_threads_teardown(xport); 1128 1129 ocs_free(ocs, xport, sizeof(*xport)); 1130 } 1131 } 1132