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