1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * fcsm - ULP Module for Fibre Channel SAN Management 28 */ 29 30 #include <sys/types.h> 31 #include <sys/file.h> 32 #include <sys/kmem.h> 33 #include <sys/scsi/scsi.h> 34 #include <sys/var.h> 35 #include <sys/byteorder.h> 36 37 #include <sys/fibre-channel/fc.h> 38 #include <sys/fibre-channel/impl/fc_ulpif.h> 39 #include <sys/fibre-channel/ulp/fcsm.h> 40 41 /* Definitions */ 42 #define FCSM_VERSION "1.26" 43 #define FCSM_NAME_VERSION "SunFC FCSM v" FCSM_VERSION 44 45 46 47 /* Global Variables */ 48 static char fcsm_name[] = "FCSM"; 49 static void *fcsm_state = NULL; 50 static kmutex_t fcsm_global_mutex; 51 static uint32_t fcsm_flag = FCSM_IDLE; 52 static dev_info_t *fcsm_dip = NULL; 53 static fcsm_t *fcsm_port_head = NULL; 54 static kmem_cache_t *fcsm_job_cache = NULL; 55 static int fcsm_num_attaching = 0; 56 static int fcsm_num_detaching = 0; 57 static int fcsm_detached = 0; 58 59 static int fcsm_max_cmd_retries = FCSM_MAX_CMD_RETRIES; 60 static int fcsm_retry_interval = FCSM_RETRY_INTERVAL; 61 static int fcsm_retry_ticker = FCSM_RETRY_TICKER; 62 static int fcsm_offline_ticker = FCSM_OFFLINE_TICKER; 63 static int fcsm_max_job_retries = FCSM_MAX_JOB_RETRIES; 64 static clock_t fcsm_retry_ticks; 65 static clock_t fcsm_offline_ticks; 66 67 68 69 #ifdef DEBUG 70 uint32_t fcsm_debug = (SMDL_TRACE | SMDL_IO | 71 SMDL_ERR | SMDL_INFO); 72 #endif 73 74 75 /* Character/Block entry points */ 76 struct cb_ops fcsm_cb_ops = { 77 fcsm_open, /* open */ 78 fcsm_close, /* close */ 79 nodev, /* strategy */ 80 nodev, /* print */ 81 nodev, /* dump */ 82 nodev, /* read */ 83 nodev, /* write */ 84 fcsm_ioctl, /* ioctl */ 85 nodev, /* devmap */ 86 nodev, /* mmap */ 87 nodev, /* segmap */ 88 nochpoll, /* poll */ 89 ddi_prop_op, 90 NULL, /* streams info */ 91 D_NEW | D_MP, 92 CB_REV, 93 nodev, /* aread */ 94 nodev /* awrite */ 95 }; 96 97 struct dev_ops fcsm_ops = { 98 DEVO_REV, 99 0, /* refcnt */ 100 fcsm_getinfo, /* get info */ 101 nulldev, /* identify (obsolete) */ 102 nulldev, /* probe (not required for self-identifying devices) */ 103 fcsm_attach, /* attach */ 104 fcsm_detach, /* detach */ 105 nodev, /* reset */ 106 &fcsm_cb_ops, /* char/block entry points structure for leaf drivers */ 107 NULL, /* bus operations for nexus driver */ 108 NULL /* power management */ 109 }; 110 111 112 struct modldrv modldrv = { 113 &mod_driverops, 114 FCSM_NAME_VERSION, 115 &fcsm_ops 116 }; 117 118 struct modlinkage modlinkage = { 119 MODREV_1, 120 &modldrv, 121 NULL 122 }; 123 124 static fc_ulp_modinfo_t fcsm_modinfo = { 125 &fcsm_modinfo, /* ulp_handle */ 126 FCTL_ULP_MODREV_4, /* ulp_rev */ 127 FC_TYPE_FC_SERVICES, /* ulp_type */ 128 fcsm_name, /* ulp_name */ 129 0, /* ulp_statec_mask: get all statec callbacks */ 130 fcsm_port_attach, /* ulp_port_attach */ 131 fcsm_port_detach, /* ulp_port_detach */ 132 fcsm_port_ioctl, /* ulp_port_ioctl */ 133 fcsm_els_cb, /* ulp_els_callback */ 134 fcsm_data_cb, /* ulp_data_callback */ 135 fcsm_statec_cb /* ulp_statec_callback */ 136 }; 137 138 struct fcsm_xlat_pkt_state { 139 uchar_t xlat_state; 140 int xlat_rval; 141 } fcsm_xlat_pkt_state [] = { 142 { FC_PKT_SUCCESS, FC_SUCCESS }, 143 { FC_PKT_REMOTE_STOP, FC_FAILURE }, 144 { FC_PKT_LOCAL_RJT, FC_TRANSPORT_ERROR }, 145 { FC_PKT_NPORT_RJT, FC_PREJECT }, 146 { FC_PKT_FABRIC_RJT, FC_FREJECT }, 147 { FC_PKT_LOCAL_BSY, FC_TRAN_BUSY }, 148 { FC_PKT_TRAN_BSY, FC_TRAN_BUSY }, 149 { FC_PKT_NPORT_BSY, FC_PBUSY }, 150 { FC_PKT_FABRIC_BSY, FC_FBUSY }, 151 { FC_PKT_LS_RJT, FC_PREJECT }, 152 { FC_PKT_BA_RJT, FC_PREJECT }, 153 { FC_PKT_TIMEOUT, FC_FAILURE }, 154 { FC_PKT_FS_RJT, FC_FAILURE }, 155 { FC_PKT_TRAN_ERROR, FC_TRANSPORT_ERROR }, 156 { FC_PKT_FAILURE, FC_FAILURE }, 157 { FC_PKT_PORT_OFFLINE, FC_OFFLINE }, 158 { FC_PKT_ELS_IN_PROGRESS, FC_FAILURE } 159 }; 160 161 struct fcsm_xlat_port_state { 162 uint32_t xlat_pstate; 163 caddr_t xlat_state_str; 164 } fcsm_xlat_port_state [] = { 165 { FC_STATE_OFFLINE, "OFFLINE" }, 166 { FC_STATE_ONLINE, "ONLINE" }, 167 { FC_STATE_LOOP, "LOOP" }, 168 { FC_STATE_NAMESERVICE, "NAMESERVICE" }, 169 { FC_STATE_RESET, "RESET" }, 170 { FC_STATE_RESET_REQUESTED, "RESET_REQUESTED" }, 171 { FC_STATE_LIP, "LIP" }, 172 { FC_STATE_LIP_LBIT_SET, "LIP_LBIT_SET" }, 173 { FC_STATE_DEVICE_CHANGE, "DEVICE_CHANGE" }, 174 { FC_STATE_TARGET_PORT_RESET, "TARGET_PORT_RESET" } 175 }; 176 177 struct fcsm_xlat_topology { 178 uint32_t xlat_top; 179 caddr_t xlat_top_str; 180 } fcsm_xlat_topology [] = { 181 { FC_TOP_UNKNOWN, "UNKNOWN" }, 182 { FC_TOP_PRIVATE_LOOP, "Private Loop" }, 183 { FC_TOP_PUBLIC_LOOP, "Public Loop" }, 184 { FC_TOP_FABRIC, "Fabric" }, 185 { FC_TOP_PT_PT, "Point-to-Point" }, 186 { FC_TOP_NO_NS, "NO_NS" } 187 }; 188 189 struct fcsm_xlat_dev_type { 190 uint32_t xlat_type; 191 caddr_t xlat_str; 192 } fcsm_xlat_dev_type [] = { 193 { PORT_DEVICE_NOCHANGE, "No Change" }, 194 { PORT_DEVICE_NEW, "New" }, 195 { PORT_DEVICE_OLD, "Old" }, 196 { PORT_DEVICE_CHANGED, "Changed" }, 197 { PORT_DEVICE_DELETE, "Delete" }, 198 { PORT_DEVICE_USER_LOGIN, "User Login" }, 199 { PORT_DEVICE_USER_LOGOUT, "User Logout" }, 200 { PORT_DEVICE_USER_CREATE, "User Create" }, 201 { PORT_DEVICE_USER_DELETE, "User Delete" } 202 }; 203 204 int 205 _init(void) 206 { 207 int rval; 208 209 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_init")); 210 211 fcsm_retry_ticks = drv_usectohz(fcsm_retry_ticker * 1000 * 1000); 212 fcsm_offline_ticks = drv_usectohz(fcsm_offline_ticker * 1000 * 1000); 213 214 if (rval = ddi_soft_state_init(&fcsm_state, sizeof (fcsm_t), 215 FCSM_INIT_INSTANCES)) { 216 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 217 "_init: ddi_soft_state_init failed"); 218 return (ENOMEM); 219 } 220 221 mutex_init(&fcsm_global_mutex, NULL, MUTEX_DRIVER, NULL); 222 223 fcsm_job_cache = kmem_cache_create("fcsm_job_cache", 224 sizeof (fcsm_job_t), 8, fcsm_job_cache_constructor, 225 fcsm_job_cache_destructor, NULL, NULL, NULL, 0); 226 227 if (fcsm_job_cache == NULL) { 228 mutex_destroy(&fcsm_global_mutex); 229 ddi_soft_state_fini(&fcsm_state); 230 return (ENOMEM); 231 } 232 233 /* 234 * Now call fc_ulp_add to add this ULP in the transport layer 235 * database. This will cause 'ulp_port_attach' callback function 236 * to be called. 237 */ 238 rval = fc_ulp_add(&fcsm_modinfo); 239 if (rval != 0) { 240 switch (rval) { 241 case FC_ULP_SAMEMODULE: 242 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 243 "_init: FC SAN Management module is already " 244 "registered with transport layer"); 245 rval = EEXIST; 246 break; 247 248 case FC_ULP_SAMETYPE: 249 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 250 "_init: Another module with same type 0x%x is " 251 "already registered with transport layer", 252 fcsm_modinfo.ulp_type); 253 rval = EEXIST; 254 break; 255 256 case FC_BADULP: 257 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 258 "_init: Please upgrade this module. Current " 259 "version 0x%x is not the most recent version", 260 fcsm_modinfo.ulp_rev); 261 rval = EIO; 262 break; 263 default: 264 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 265 "_init: fc_ulp_add failed with status 0x%x", rval); 266 rval = EIO; 267 break; 268 } 269 kmem_cache_destroy(fcsm_job_cache); 270 mutex_destroy(&fcsm_global_mutex); 271 ddi_soft_state_fini(&fcsm_state); 272 return (rval); 273 } 274 275 if ((rval = mod_install(&modlinkage)) != 0) { 276 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL, 277 "_init: mod_install failed with status 0x%x", rval)); 278 (void) fc_ulp_remove(&fcsm_modinfo); 279 kmem_cache_destroy(fcsm_job_cache); 280 mutex_destroy(&fcsm_global_mutex); 281 ddi_soft_state_fini(&fcsm_state); 282 return (rval); 283 } 284 285 return (rval); 286 } 287 288 int 289 _fini(void) 290 { 291 int rval; 292 #ifdef DEBUG 293 int status; 294 #endif /* DEBUG */ 295 296 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "_fini")); 297 298 /* 299 * don't start cleaning up until we know that the module remove 300 * has worked -- if this works, then we know that each instance 301 * has successfully been DDI_DETACHed 302 */ 303 if ((rval = mod_remove(&modlinkage)) != 0) { 304 return (rval); 305 } 306 307 #ifdef DEBUG 308 status = fc_ulp_remove(&fcsm_modinfo); 309 if (status != 0) { 310 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, NULL, 311 "_fini: fc_ulp_remove failed with status 0x%x", status)); 312 } 313 #else 314 (void) fc_ulp_remove(&fcsm_modinfo); 315 #endif /* DEBUG */ 316 317 fcsm_detached = 0; 318 319 /* 320 * It is possible to modunload fcsm manually, which will cause 321 * a bypass of all the port_detach functionality. We may need 322 * to force that code path to be executed to properly clean up 323 * in that case. 324 */ 325 fcsm_force_port_detach_all(); 326 327 kmem_cache_destroy(fcsm_job_cache); 328 mutex_destroy(&fcsm_global_mutex); 329 ddi_soft_state_fini(&fcsm_state); 330 331 return (rval); 332 } 333 334 335 int 336 _info(struct modinfo *modinfop) 337 { 338 return (mod_info(&modlinkage, modinfop)); 339 } 340 341 /* ARGSUSED */ 342 static int 343 fcsm_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 344 { 345 int rval = DDI_FAILURE; 346 347 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 348 "attach: cmd 0x%x", cmd)); 349 350 switch (cmd) { 351 case DDI_ATTACH: 352 mutex_enter(&fcsm_global_mutex); 353 if (fcsm_dip != NULL) { 354 mutex_exit(&fcsm_global_mutex); 355 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 356 "attach: duplicate attach of fcsm!!")); 357 break; 358 } 359 360 fcsm_dip = dip; 361 362 /* 363 * The detach routine cleans up all the port instances 364 * i.e. it detaches all ports. 365 * If _fini never got called after detach, then 366 * perform an fc_ulp_remove() followed by fc_ulp_add() 367 * to ensure that port_attach callbacks are called 368 * again. 369 */ 370 if (fcsm_detached) { 371 int status; 372 373 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 374 "attach: rebinding to transport driver")); 375 376 mutex_exit(&fcsm_global_mutex); 377 378 (void) fc_ulp_remove(&fcsm_modinfo); 379 380 /* 381 * Reset the detached flag, so that ports can attach 382 */ 383 mutex_enter(&fcsm_global_mutex); 384 fcsm_detached = 0; 385 mutex_exit(&fcsm_global_mutex); 386 387 status = fc_ulp_add(&fcsm_modinfo); 388 389 if (status != 0) { 390 /* 391 * ULP add failed. So set the 392 * detached flag again 393 */ 394 mutex_enter(&fcsm_global_mutex); 395 fcsm_detached = 1; 396 mutex_exit(&fcsm_global_mutex); 397 398 switch (status) { 399 case FC_ULP_SAMEMODULE: 400 fcsm_display(CE_WARN, SM_LOG, NULL, 401 NULL, "attach: FC SAN Management " 402 "module is already " 403 "registered with transport layer"); 404 break; 405 406 case FC_ULP_SAMETYPE: 407 fcsm_display(CE_WARN, SM_LOG, NULL, 408 NULL, "attach: Another module with " 409 "same type 0x%x is already " 410 "registered with transport layer", 411 fcsm_modinfo.ulp_type); 412 break; 413 414 case FC_BADULP: 415 fcsm_display(CE_WARN, SM_LOG, NULL, 416 NULL, "attach: Please upgrade this " 417 "module. Current version 0x%x is " 418 "not the most recent version", 419 fcsm_modinfo.ulp_rev); 420 break; 421 default: 422 fcsm_display(CE_WARN, SM_LOG, NULL, 423 NULL, "attach: fc_ulp_add failed " 424 "with status 0x%x", status); 425 break; 426 } 427 428 /* Return failure */ 429 break; 430 } 431 432 mutex_enter(&fcsm_global_mutex); 433 } 434 435 /* Create a minor node */ 436 if (ddi_create_minor_node(fcsm_dip, "fcsm", S_IFCHR, 437 NULL, DDI_PSEUDO, 0) == DDI_SUCCESS) { 438 /* Announce presence of the device */ 439 mutex_exit(&fcsm_global_mutex); 440 ddi_report_dev(dip); 441 rval = DDI_SUCCESS; 442 } else { 443 fcsm_dip = NULL; 444 mutex_exit(&fcsm_global_mutex); 445 fcsm_display(CE_WARN, SM_LOG_AND_CONSOLE, 446 NULL, NULL, "attach: create minor node failed"); 447 } 448 break; 449 450 case DDI_RESUME: 451 rval = DDI_SUCCESS; 452 break; 453 454 default: 455 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL, 456 "attach: unknown cmd 0x%x dip 0x%p", cmd, dip)); 457 break; 458 } 459 460 return (rval); 461 } 462 463 /* ARGSUSED */ 464 static int 465 fcsm_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **result) 466 { 467 int instance; 468 int rval = DDI_SUCCESS; 469 470 instance = getminor((dev_t)arg); 471 472 switch (cmd) { 473 case DDI_INFO_DEVT2INSTANCE: 474 *result = (void *)(long)instance; /* minor number is instance */ 475 break; 476 477 case DDI_INFO_DEVT2DEVINFO: 478 mutex_enter(&fcsm_global_mutex); 479 *result = (void *)fcsm_dip; 480 mutex_exit(&fcsm_global_mutex); 481 break; 482 483 default: 484 rval = DDI_FAILURE; 485 break; 486 } 487 488 return (rval); 489 } 490 491 492 /* ARGSUSED */ 493 static int 494 fcsm_port_attach(opaque_t ulph, fc_ulp_port_info_t *pinfo, 495 fc_attach_cmd_t cmd, uint32_t s_id) 496 { 497 int instance; 498 int rval = FC_FAILURE; 499 500 instance = ddi_get_instance(pinfo->port_dip); 501 502 /* 503 * Set the attaching flag, so that fcsm_detach will fail, if 504 * port attach is in progress. 505 */ 506 mutex_enter(&fcsm_global_mutex); 507 if (fcsm_detached) { 508 mutex_exit(&fcsm_global_mutex); 509 510 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 511 "port_attach: end. detach in progress. failing attach " 512 "instance 0x%x", instance)); 513 return (((cmd == FC_CMD_POWER_UP) || (cmd == FC_CMD_RESUME)) ? 514 FC_FAILURE_SILENT : FC_FAILURE); 515 } 516 517 fcsm_num_attaching++; 518 mutex_exit(&fcsm_global_mutex); 519 520 switch (cmd) { 521 case FC_CMD_ATTACH: 522 if (fcsm_handle_port_attach(pinfo, s_id, instance) 523 != DDI_SUCCESS) { 524 ASSERT(ddi_get_soft_state(fcsm_state, 525 instance) == NULL); 526 break; 527 } 528 rval = FC_SUCCESS; 529 break; 530 531 case FC_CMD_RESUME: 532 case FC_CMD_POWER_UP: { 533 fcsm_t *fcsm; 534 char fcsm_pathname[MAXPATHLEN]; 535 536 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 537 "port_attach: cmd 0x%x instance 0x%x", cmd, instance)); 538 539 /* Get the soft state structure */ 540 if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) { 541 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL, 542 "port_attach: instance 0x%x, cmd 0x%x " 543 "get softstate failed", instance, cmd)); 544 break; 545 } 546 547 ASSERT(fcsm->sm_instance == instance); 548 549 /* If this instance is not attached, then return failure */ 550 mutex_enter(&fcsm->sm_mutex); 551 if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) { 552 mutex_exit(&fcsm->sm_mutex); 553 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 554 "port_detach: port is not attached"); 555 break; 556 } 557 mutex_exit(&fcsm->sm_mutex); 558 559 if (fcsm_handle_port_resume(ulph, pinfo, cmd, s_id, fcsm) != 560 DDI_SUCCESS) { 561 break; 562 } 563 564 (void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname); 565 fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL, 566 "attached to path %s", fcsm_pathname); 567 rval = FC_SUCCESS; 568 break; 569 } 570 571 default: 572 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL, 573 "port_attach: unknown cmd 0x%x for port 0x%x", 574 cmd, instance)); 575 break; 576 } 577 578 mutex_enter(&fcsm_global_mutex); 579 fcsm_num_attaching--; 580 mutex_exit(&fcsm_global_mutex); 581 return (rval); 582 } 583 584 585 static int 586 fcsm_handle_port_attach(fc_ulp_port_info_t *pinfo, uint32_t s_id, int instance) 587 { 588 fcsm_t *fcsm; 589 kthread_t *thread; 590 char name[32]; 591 char fcsm_pathname[MAXPATHLEN]; 592 593 /* Allocate a soft state structure for the port */ 594 if (ddi_soft_state_zalloc(fcsm_state, instance) != DDI_SUCCESS) { 595 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 596 "port_attach: instance 0x%x, soft state alloc failed", 597 instance); 598 return (DDI_FAILURE); 599 } 600 601 if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) { 602 fcsm_display(CE_WARN, SM_LOG, NULL, NULL, 603 "port_attach: instance 0x%x, get soft state failed", 604 instance); 605 ddi_soft_state_free(fcsm_state, instance); 606 return (DDI_FAILURE); 607 } 608 609 610 /* Initialize the mutex */ 611 mutex_init(&fcsm->sm_mutex, NULL, MUTEX_DRIVER, NULL); 612 cv_init(&fcsm->sm_job_cv, NULL, CV_DRIVER, NULL); 613 614 mutex_enter(&fcsm->sm_mutex); 615 fcsm->sm_flags |= FCSM_ATTACHING; 616 fcsm->sm_sid = s_id; 617 fcsm->sm_instance = instance; 618 fcsm->sm_port_state = pinfo->port_state; 619 620 /* 621 * Make a copy of the port_information structure, since fctl 622 * uses a temporary structure. 623 */ 624 fcsm->sm_port_info = *pinfo; /* Structure copy !!! */ 625 mutex_exit(&fcsm->sm_mutex); 626 627 628 (void) sprintf(name, "fcsm%d_cmd_cache", fcsm->sm_instance); 629 fcsm->sm_cmd_cache = kmem_cache_create(name, 630 sizeof (fcsm_cmd_t) + pinfo->port_fca_pkt_size, 8, 631 fcsm_cmd_cache_constructor, fcsm_cmd_cache_destructor, 632 NULL, (void *)fcsm, NULL, 0); 633 if (fcsm->sm_cmd_cache == NULL) { 634 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 635 "port_attach: pkt cache create failed"); 636 cv_destroy(&fcsm->sm_job_cv); 637 mutex_destroy(&fcsm->sm_mutex); 638 ddi_soft_state_free(fcsm_state, instance); 639 return (DDI_FAILURE); 640 } 641 642 thread = thread_create((caddr_t)NULL, 0, fcsm_job_thread, 643 (caddr_t)fcsm, 0, &p0, TS_RUN, v.v_maxsyspri-2); 644 if (thread == NULL) { 645 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 646 "port_attach: job thread create failed"); 647 kmem_cache_destroy(fcsm->sm_cmd_cache); 648 cv_destroy(&fcsm->sm_job_cv); 649 mutex_destroy(&fcsm->sm_mutex); 650 ddi_soft_state_free(fcsm_state, instance); 651 return (DDI_FAILURE); 652 } 653 654 fcsm->sm_thread = thread; 655 656 /* Add this structure to fcsm global linked list */ 657 mutex_enter(&fcsm_global_mutex); 658 if (fcsm_port_head == NULL) { 659 fcsm_port_head = fcsm; 660 } else { 661 fcsm->sm_next = fcsm_port_head; 662 fcsm_port_head = fcsm; 663 } 664 mutex_exit(&fcsm_global_mutex); 665 666 mutex_enter(&fcsm->sm_mutex); 667 fcsm->sm_flags &= ~FCSM_ATTACHING; 668 fcsm->sm_flags |= FCSM_ATTACHED; 669 fcsm->sm_port_top = pinfo->port_flags; 670 fcsm->sm_port_state = pinfo->port_state; 671 mutex_exit(&fcsm->sm_mutex); 672 673 (void) ddi_pathname(fcsm->sm_port_info.port_dip, fcsm_pathname); 674 fcsm_display(CE_NOTE, SM_LOG, fcsm, NULL, 675 "attached to path %s", fcsm_pathname); 676 677 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 678 "port_attach: state <%s>(0x%x) topology <%s>(0x%x)", 679 fcsm_port_state_to_str(FC_PORT_STATE_MASK(pinfo->port_state)), 680 pinfo->port_state, 681 fcsm_topology_to_str(pinfo->port_flags), pinfo->port_flags)); 682 683 return (DDI_SUCCESS); 684 } 685 686 static int 687 fcsm_handle_port_resume(opaque_t ulph, fc_ulp_port_info_t *pinfo, 688 fc_attach_cmd_t cmd, uint32_t s_id, fcsm_t *fcsm) 689 { 690 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 691 "port_resume: cmd 0x%x", cmd)); 692 693 mutex_enter(&fcsm->sm_mutex); 694 695 switch (cmd) { 696 case FC_CMD_RESUME: 697 ASSERT(!(fcsm->sm_flags & FCSM_POWER_DOWN)); 698 fcsm->sm_flags &= ~FCSM_SUSPENDED; 699 break; 700 701 case FC_CMD_POWER_UP: 702 /* If port is suspended, then no need to resume */ 703 fcsm->sm_flags &= ~FCSM_POWER_DOWN; 704 if (fcsm->sm_flags & FCSM_SUSPENDED) { 705 mutex_exit(&fcsm->sm_mutex); 706 return (DDI_SUCCESS); 707 } 708 break; 709 default: 710 mutex_exit(&fcsm->sm_mutex); 711 return (DDI_FAILURE); 712 } 713 714 fcsm->sm_sid = s_id; 715 716 /* 717 * Make a copy of the new port_information structure 718 */ 719 fcsm->sm_port_info = *pinfo; /* Structure copy !!! */ 720 mutex_exit(&fcsm->sm_mutex); 721 722 fcsm_resume_port(fcsm); 723 724 /* 725 * Invoke state change processing. 726 * This will ensure that 727 * - offline timer is started if new port state changed to offline. 728 * - MGMT_SERVER_LOGIN flag is reset. 729 * - Port topology is updated. 730 */ 731 fcsm_statec_cb(ulph, (opaque_t)pinfo->port_handle, pinfo->port_state, 732 pinfo->port_flags, NULL, 0, s_id); 733 734 return (DDI_SUCCESS); 735 } 736 737 738 /* ARGSUSED */ 739 static int 740 fcsm_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 741 { 742 int rval = DDI_SUCCESS; 743 744 switch (cmd) { 745 case DDI_DETACH: { 746 fcsm_t *fcsm; 747 748 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 749 "detach: start. cmd <DETACH>", cmd)); 750 751 mutex_enter(&fcsm_global_mutex); 752 753 /* 754 * If port attach/detach in progress, then wait for 5 seconds 755 * for them to complete. 756 */ 757 if (fcsm_num_attaching || fcsm_num_detaching) { 758 int count; 759 760 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL, 761 "detach: wait for port attach/detach to complete")); 762 763 count = 0; 764 while ((count++ <= 30) && 765 (fcsm_num_attaching || fcsm_num_detaching)) { 766 mutex_exit(&fcsm_global_mutex); 767 delay(drv_usectohz(1000000)); 768 mutex_enter(&fcsm_global_mutex); 769 } 770 771 /* Port attach/detach still in prog, so fail detach */ 772 if (fcsm_num_attaching || fcsm_num_detaching) { 773 mutex_exit(&fcsm_global_mutex); 774 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, NULL, 775 NULL, "detach: Failing detach. port " 776 "attach/detach in progress")); 777 rval = DDI_FAILURE; 778 break; 779 } 780 } 781 782 if (fcsm_port_head == NULL) { 783 /* Not much do, Succeed to detach. */ 784 ddi_remove_minor_node(fcsm_dip, NULL); 785 fcsm_dip = NULL; 786 fcsm_detached = 0; 787 mutex_exit(&fcsm_global_mutex); 788 break; 789 } 790 791 /* 792 * Check to see, if any ports are active. 793 * If not, then set the DETACHING flag to indicate 794 * that they are being detached. 795 */ 796 fcsm = fcsm_port_head; 797 while (fcsm != NULL) { 798 799 mutex_enter(&fcsm->sm_mutex); 800 if (!(fcsm->sm_flags & FCSM_ATTACHED) || 801 fcsm->sm_ncmds || fcsm->sm_cb_count) { 802 /* port is busy. We can't detach */ 803 mutex_exit(&fcsm->sm_mutex); 804 break; 805 } 806 807 fcsm->sm_flags |= FCSM_DETACHING; 808 mutex_exit(&fcsm->sm_mutex); 809 810 fcsm = fcsm->sm_next; 811 } 812 813 /* 814 * If all ports could not be marked for detaching, 815 * then clear the flags and fail the detach. 816 * Also if a port attach is currently in progress 817 * then fail the detach. 818 */ 819 if (fcsm != NULL || fcsm_num_attaching || fcsm_num_detaching) { 820 /* 821 * Some ports were busy, so can't detach. 822 * Clear the DETACHING flag and return failure 823 */ 824 fcsm = fcsm_port_head; 825 while (fcsm != NULL) { 826 mutex_enter(&fcsm->sm_mutex); 827 if (fcsm->sm_flags & FCSM_DETACHING) { 828 fcsm->sm_flags &= ~FCSM_DETACHING; 829 } 830 mutex_exit(&fcsm->sm_mutex); 831 832 fcsm = fcsm->sm_next; 833 } 834 mutex_exit(&fcsm_global_mutex); 835 return (DDI_FAILURE); 836 } else { 837 fcsm_detached = 1; 838 /* 839 * Mark all the detaching ports as detached, as we 840 * will be detaching them 841 */ 842 fcsm = fcsm_port_head; 843 while (fcsm != NULL) { 844 mutex_enter(&fcsm->sm_mutex); 845 fcsm->sm_flags &= ~FCSM_DETACHING; 846 fcsm->sm_flags |= FCSM_DETACHED; 847 mutex_exit(&fcsm->sm_mutex); 848 849 fcsm = fcsm->sm_next; 850 } 851 } 852 mutex_exit(&fcsm_global_mutex); 853 854 855 /* 856 * Go ahead and detach the ports 857 */ 858 mutex_enter(&fcsm_global_mutex); 859 while (fcsm_port_head != NULL) { 860 fcsm = fcsm_port_head; 861 mutex_exit(&fcsm_global_mutex); 862 863 /* 864 * Call fcsm_cleanup_port(). This cleansup and 865 * removes the fcsm structure from global linked list 866 */ 867 fcsm_cleanup_port(fcsm); 868 869 /* 870 * Soft state cleanup done. 871 * Remember that fcsm struct doesn't exist anymore. 872 */ 873 874 mutex_enter(&fcsm_global_mutex); 875 } 876 877 ddi_remove_minor_node(fcsm_dip, NULL); 878 fcsm_dip = NULL; 879 mutex_exit(&fcsm_global_mutex); 880 break; 881 } 882 883 case DDI_SUSPEND: 884 rval = DDI_SUCCESS; 885 break; 886 887 default: 888 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL, 889 "detach: unknown cmd 0x%x", cmd)); 890 rval = DDI_FAILURE; 891 break; 892 } 893 894 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 895 "detach: end. cmd 0x%x, rval 0x%x", cmd, rval)); 896 897 return (rval); 898 } 899 900 901 /* ARGSUSED */ 902 static void 903 fcsm_force_port_detach_all(void) 904 { 905 fcsm_t *fcsm; 906 907 fcsm = fcsm_port_head; 908 909 while (fcsm) { 910 fcsm_cleanup_port(fcsm); 911 /* 912 * fcsm_cleanup_port will remove the current fcsm structure 913 * from the list, which will cause fcsm_port_head to point 914 * to what would have been the next structure on the list. 915 */ 916 fcsm = fcsm_port_head; 917 } 918 } 919 920 921 /* ARGSUSED */ 922 static int 923 fcsm_port_detach(opaque_t ulph, fc_ulp_port_info_t *pinfo, fc_detach_cmd_t cmd) 924 { 925 int instance; 926 int rval = FC_FAILURE; 927 fcsm_t *fcsm; 928 929 instance = ddi_get_instance(pinfo->port_dip); 930 931 mutex_enter(&fcsm_global_mutex); 932 if (fcsm_detached) { 933 mutex_exit(&fcsm_global_mutex); 934 935 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL, 936 "port_detach: end. instance 0x%x, fcsm is detached", 937 instance)); 938 return (FC_SUCCESS); 939 } 940 fcsm_num_detaching++; /* Set the flag */ 941 mutex_exit(&fcsm_global_mutex); 942 943 /* Get the soft state structure */ 944 if ((fcsm = ddi_get_soft_state(fcsm_state, instance)) == NULL) { 945 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL, 946 "port_detach: instance 0x%x, cmd 0x%x get softstate failed", 947 instance, cmd)); 948 mutex_enter(&fcsm_global_mutex); 949 fcsm_num_detaching--; 950 mutex_exit(&fcsm_global_mutex); 951 return (rval); 952 } 953 954 ASSERT(fcsm->sm_instance == instance); 955 956 /* If this instance is not attached, then fail the detach */ 957 mutex_enter(&fcsm->sm_mutex); 958 if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) { 959 mutex_exit(&fcsm->sm_mutex); 960 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 961 "port_detach: port is not attached"); 962 mutex_enter(&fcsm_global_mutex); 963 fcsm_num_detaching--; 964 mutex_exit(&fcsm_global_mutex); 965 return (rval); 966 } 967 mutex_exit(&fcsm->sm_mutex); 968 969 /* 970 * If fcsm has been detached, then all instance has already been 971 * detached or are being detached. So succeed this detach. 972 */ 973 974 switch (cmd) { 975 case FC_CMD_DETACH: 976 case FC_CMD_SUSPEND: 977 case FC_CMD_POWER_DOWN: 978 break; 979 980 default: 981 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 982 "port_detach: port unknown cmd 0x%x", cmd)); 983 mutex_enter(&fcsm_global_mutex); 984 fcsm_num_detaching--; 985 mutex_exit(&fcsm_global_mutex); 986 return (rval); 987 }; 988 989 if (fcsm_handle_port_detach(pinfo, fcsm, cmd) == DDI_SUCCESS) { 990 rval = FC_SUCCESS; 991 } 992 993 mutex_enter(&fcsm_global_mutex); 994 fcsm_num_detaching--; 995 mutex_exit(&fcsm_global_mutex); 996 997 /* If it was a detach, then fcsm state structure no longer exists */ 998 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 999 "port_detach: end. cmd 0x%x rval 0x%x", cmd, rval)); 1000 return (rval); 1001 } 1002 1003 1004 static int 1005 fcsm_handle_port_detach(fc_ulp_port_info_t *pinfo, fcsm_t *fcsm, 1006 fc_detach_cmd_t cmd) 1007 { 1008 uint32_t flag; 1009 int count; 1010 #ifdef DEBUG 1011 char pathname[MAXPATHLEN]; 1012 #endif /* DEBUG */ 1013 1014 /* 1015 * If port is already powered down OR suspended and there is nothing 1016 * else to do then just return. 1017 * Otherwise, set the flag, so that no more new activity will be 1018 * initiated on this port. 1019 */ 1020 mutex_enter(&fcsm->sm_mutex); 1021 1022 switch (cmd) { 1023 case FC_CMD_DETACH: 1024 flag = FCSM_DETACHING; 1025 break; 1026 1027 case FC_CMD_SUSPEND: 1028 case FC_CMD_POWER_DOWN: 1029 (cmd == FC_CMD_SUSPEND) ? (flag = FCSM_SUSPENDED) : \ 1030 (flag = FCSM_POWER_DOWN); 1031 if (fcsm->sm_flags & 1032 (FCSM_POWER_DOWN | FCSM_SUSPENDED)) { 1033 fcsm->sm_flags |= flag; 1034 mutex_exit(&fcsm->sm_mutex); 1035 return (DDI_SUCCESS); 1036 } 1037 break; 1038 1039 default: 1040 mutex_exit(&fcsm->sm_mutex); 1041 return (DDI_FAILURE); 1042 }; 1043 1044 fcsm->sm_flags |= flag; 1045 1046 /* 1047 * If some commands are pending OR callback in progress, then 1048 * wait for some finite amount of time for their completion. 1049 * TODO: add more checks here to check for cmd timeout, offline 1050 * timeout and other (??) threads. 1051 */ 1052 count = 0; 1053 while ((count++ <= 30) && (fcsm->sm_ncmds || fcsm->sm_cb_count)) { 1054 mutex_exit(&fcsm->sm_mutex); 1055 delay(drv_usectohz(1000000)); 1056 mutex_enter(&fcsm->sm_mutex); 1057 } 1058 if (fcsm->sm_ncmds || fcsm->sm_cb_count) { 1059 fcsm->sm_flags &= ~flag; 1060 mutex_exit(&fcsm->sm_mutex); 1061 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 1062 "port_detach: Failing suspend, port is busy"); 1063 return (DDI_FAILURE); 1064 } 1065 if (flag == FCSM_DETACHING) { 1066 fcsm->sm_flags &= ~FCSM_DETACHING; 1067 fcsm->sm_flags |= FCSM_DETACHED; 1068 } 1069 1070 mutex_exit(&fcsm->sm_mutex); 1071 1072 FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL, 1073 "port_detach: cmd 0x%x pathname <%s>", 1074 cmd, ddi_pathname(pinfo->port_dip, pathname))); 1075 1076 if (cmd == FC_CMD_DETACH) { 1077 fcsm_cleanup_port(fcsm); 1078 /* 1079 * Soft state cleanup done. 1080 * Always remember that fcsm struct doesn't exist anymore. 1081 */ 1082 } else { 1083 fcsm_suspend_port(fcsm); 1084 } 1085 1086 return (DDI_SUCCESS); 1087 } 1088 1089 static void 1090 fcsm_suspend_port(fcsm_t *fcsm) 1091 { 1092 mutex_enter(&fcsm->sm_mutex); 1093 1094 if (fcsm->sm_offline_tid != NULL) { 1095 timeout_id_t tid; 1096 1097 tid = fcsm->sm_offline_tid; 1098 fcsm->sm_offline_tid = (timeout_id_t)NULL; 1099 mutex_exit(&fcsm->sm_mutex); 1100 (void) untimeout(tid); 1101 mutex_enter(&fcsm->sm_mutex); 1102 fcsm->sm_flags |= FCSM_RESTORE_OFFLINE_TIMEOUT; 1103 } 1104 1105 if (fcsm->sm_retry_tid != NULL) { 1106 timeout_id_t tid; 1107 1108 tid = fcsm->sm_retry_tid; 1109 fcsm->sm_retry_tid = (timeout_id_t)NULL; 1110 mutex_exit(&fcsm->sm_mutex); 1111 (void) untimeout(tid); 1112 mutex_enter(&fcsm->sm_mutex); 1113 fcsm->sm_flags |= FCSM_RESTORE_RETRY_TIMEOUT; 1114 } 1115 1116 mutex_exit(&fcsm->sm_mutex); 1117 } 1118 1119 static void 1120 fcsm_resume_port(fcsm_t *fcsm) 1121 { 1122 mutex_enter(&fcsm->sm_mutex); 1123 1124 if (fcsm->sm_flags & FCSM_RESTORE_OFFLINE_TIMEOUT) { 1125 fcsm->sm_flags &= ~FCSM_RESTORE_OFFLINE_TIMEOUT; 1126 1127 /* 1128 * If port if offline, link is not marked down and offline 1129 * timer is not already running, then restart offline timer. 1130 */ 1131 if (!(fcsm->sm_flags & FCSM_LINK_DOWN) && 1132 fcsm->sm_offline_tid == NULL && 1133 (fcsm->sm_flags & FCSM_PORT_OFFLINE)) { 1134 fcsm->sm_offline_tid = timeout(fcsm_offline_timeout, 1135 (caddr_t)fcsm, fcsm_offline_ticks); 1136 } 1137 } 1138 1139 if (fcsm->sm_flags & FCSM_RESTORE_RETRY_TIMEOUT) { 1140 fcsm->sm_flags &= ~FCSM_RESTORE_RETRY_TIMEOUT; 1141 1142 /* 1143 * If retry queue is not suspended and some cmds are waiting 1144 * to be retried, then restart the retry timer 1145 */ 1146 if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) { 1147 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout, 1148 (caddr_t)fcsm, fcsm_retry_ticks); 1149 } 1150 } 1151 mutex_exit(&fcsm->sm_mutex); 1152 } 1153 1154 static void 1155 fcsm_cleanup_port(fcsm_t *fcsm) 1156 { 1157 fcsm_t *curr, *prev; 1158 int status; 1159 fcsm_job_t *job; 1160 1161 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1162 "fcsm_cleanup_port: entered")); 1163 1164 /* 1165 * Kill the job thread 1166 */ 1167 job = fcsm_alloc_job(KM_SLEEP); 1168 ASSERT(job != NULL); 1169 fcsm_init_job(job, fcsm->sm_instance, FCSM_JOB_THREAD_SHUTDOWN, 1170 FCSM_JOBFLAG_SYNC, NULL, NULL, NULL, NULL); 1171 1172 status = fcsm_process_job(job, 0); 1173 ASSERT(status == FC_SUCCESS); 1174 1175 ASSERT(job->job_result == FC_SUCCESS); 1176 fcsm_dealloc_job(job); 1177 1178 /* 1179 * We got here after ensuring the no commands are pending or active. 1180 * Therefore retry timeout thread should NOT be running. 1181 * Kill the offline timeout thread if currently running. 1182 */ 1183 mutex_enter(&fcsm->sm_mutex); 1184 1185 ASSERT(fcsm->sm_retry_tid == NULL); 1186 1187 if (fcsm->sm_offline_tid != NULL) { 1188 timeout_id_t tid; 1189 1190 tid = fcsm->sm_offline_tid; 1191 fcsm->sm_offline_tid = (timeout_id_t)NULL; 1192 mutex_exit(&fcsm->sm_mutex); 1193 (void) untimeout(tid); 1194 } else { 1195 mutex_exit(&fcsm->sm_mutex); 1196 } 1197 1198 /* Remove from the fcsm state structure from global linked list */ 1199 mutex_enter(&fcsm_global_mutex); 1200 curr = fcsm_port_head; 1201 prev = NULL; 1202 while (curr != fcsm && curr != NULL) { 1203 prev = curr; 1204 curr = curr->sm_next; 1205 } 1206 ASSERT(curr != NULL); 1207 1208 if (prev == NULL) { 1209 fcsm_port_head = curr->sm_next; 1210 } else { 1211 prev->sm_next = curr->sm_next; 1212 } 1213 mutex_exit(&fcsm_global_mutex); 1214 1215 if (fcsm->sm_cmd_cache != NULL) { 1216 kmem_cache_destroy(fcsm->sm_cmd_cache); 1217 } 1218 cv_destroy(&fcsm->sm_job_cv); 1219 mutex_destroy(&fcsm->sm_mutex); 1220 1221 /* Free the fcsm state structure */ 1222 ddi_soft_state_free(fcsm_state, fcsm->sm_instance); 1223 } 1224 1225 1226 /* ARGSUSED */ 1227 static void 1228 fcsm_statec_cb(opaque_t ulph, opaque_t port_handle, uint32_t port_state, 1229 uint32_t port_top, fc_portmap_t *devlist, uint32_t dev_cnt, 1230 uint32_t port_sid) 1231 { 1232 fcsm_t *fcsm; 1233 timeout_id_t offline_tid, retry_tid; 1234 1235 mutex_enter(&fcsm_global_mutex); 1236 if (fcsm_detached) { 1237 mutex_exit(&fcsm_global_mutex); 1238 return; 1239 } 1240 1241 fcsm = ddi_get_soft_state(fcsm_state, 1242 fc_ulp_get_port_instance(port_handle)); 1243 if (fcsm == NULL) { 1244 mutex_exit(&fcsm_global_mutex); 1245 FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL, 1246 "statec_cb: instance 0x%x not found", 1247 fc_ulp_get_port_instance(port_handle))); 1248 return; 1249 } 1250 mutex_enter(&fcsm->sm_mutex); 1251 ASSERT(fcsm->sm_instance == fc_ulp_get_port_instance(port_handle)); 1252 if ((fcsm->sm_flags & FCSM_ATTACHED) == 0) { 1253 mutex_exit(&fcsm->sm_mutex); 1254 mutex_exit(&fcsm_global_mutex); 1255 FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, fcsm, NULL, 1256 "statec_cb: port not attached")); 1257 return; 1258 } 1259 1260 ASSERT(fcsm->sm_cb_count >= 0); 1261 1262 fcsm->sm_cb_count++; 1263 mutex_exit(&fcsm->sm_mutex); 1264 mutex_exit(&fcsm_global_mutex); 1265 1266 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1267 "statec_cb: state <%s>(0x%x) topology <%s>(0x%x) dev_cnt %d", 1268 fcsm_port_state_to_str(FC_PORT_STATE_MASK(port_state)), port_state, 1269 fcsm_topology_to_str(port_top), port_top, dev_cnt)); 1270 1271 fcsm_disp_devlist(fcsm, devlist, dev_cnt); 1272 1273 mutex_enter(&fcsm->sm_mutex); 1274 1275 /* 1276 * Reset the Mgmt server Login flag, so that login is performed again. 1277 */ 1278 fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN; 1279 1280 fcsm->sm_sid = port_sid; 1281 fcsm->sm_port_top = port_top; 1282 fcsm->sm_port_state = port_state; 1283 1284 switch (port_state) { 1285 case FC_STATE_OFFLINE: 1286 case FC_STATE_RESET: 1287 case FC_STATE_RESET_REQUESTED: 1288 fcsm->sm_flags |= FCSM_PORT_OFFLINE; 1289 break; 1290 1291 case FC_STATE_ONLINE: 1292 case FC_STATE_LOOP: 1293 case FC_STATE_LIP: 1294 case FC_STATE_LIP_LBIT_SET: 1295 fcsm->sm_flags &= ~FCSM_PORT_OFFLINE; 1296 fcsm->sm_flags &= ~FCSM_LINK_DOWN; 1297 break; 1298 1299 case FC_STATE_NAMESERVICE: 1300 case FC_STATE_DEVICE_CHANGE: 1301 case FC_STATE_TARGET_PORT_RESET: 1302 default: 1303 /* Do nothing */ 1304 break; 1305 } 1306 1307 offline_tid = retry_tid = NULL; 1308 if (fcsm->sm_flags & FCSM_PORT_OFFLINE) { 1309 /* 1310 * Port is offline. 1311 * Suspend cmd processing and start offline timeout thread. 1312 */ 1313 if (fcsm->sm_offline_tid == NULL) { 1314 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1315 "statec_cb: schedule offline timeout thread")); 1316 fcsm->sm_flags |= FCSM_CMD_RETRY_Q_SUSPENDED; 1317 /* Stop the cmd retry thread */ 1318 retry_tid = fcsm->sm_retry_tid; 1319 fcsm->sm_retry_tid = (timeout_id_t)NULL; 1320 1321 fcsm->sm_offline_tid = timeout(fcsm_offline_timeout, 1322 (caddr_t)fcsm, fcsm_offline_ticks); 1323 } 1324 1325 } else { 1326 /* 1327 * Port is online. 1328 * Cancel offline timeout thread and resume command processing. 1329 */ 1330 if (fcsm->sm_offline_tid) { 1331 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1332 "statec_cb: cancel offline timeout thread")); 1333 offline_tid = fcsm->sm_offline_tid; 1334 fcsm->sm_offline_tid = (timeout_id_t)NULL; 1335 } 1336 1337 fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED; 1338 /* Start retry thread if needed */ 1339 if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) { 1340 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout, 1341 (caddr_t)fcsm, fcsm_retry_ticks); 1342 } 1343 } 1344 1345 mutex_exit(&fcsm->sm_mutex); 1346 1347 if (offline_tid != NULL) { 1348 (void) untimeout(offline_tid); 1349 } 1350 1351 if (retry_tid != NULL) { 1352 (void) untimeout(retry_tid); 1353 } 1354 1355 mutex_enter(&fcsm->sm_mutex); 1356 fcsm->sm_cb_count--; 1357 ASSERT(fcsm->sm_cb_count >= 0); 1358 mutex_exit(&fcsm->sm_mutex); 1359 } 1360 1361 1362 static void 1363 fcsm_offline_timeout(void *handle) 1364 { 1365 fcsm_t *fcsm = (fcsm_t *)handle; 1366 1367 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1368 "offline_timeout")); 1369 1370 mutex_enter(&fcsm->sm_mutex); 1371 if (fcsm->sm_flags & FCSM_PORT_OFFLINE) { 1372 fcsm->sm_flags |= FCSM_LINK_DOWN; 1373 } 1374 fcsm->sm_offline_tid = (timeout_id_t)NULL; 1375 fcsm->sm_flags &= ~FCSM_CMD_RETRY_Q_SUSPENDED; 1376 1377 /* Start the retry thread if needed */ 1378 if (fcsm->sm_retry_head && fcsm->sm_retry_tid == NULL) { 1379 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1380 "offline_timeout: reschedule cmd retry thread")); 1381 ASSERT(fcsm->sm_retry_tid == NULL); 1382 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout, 1383 (caddr_t)fcsm, fcsm_retry_ticks); 1384 } 1385 mutex_exit(&fcsm->sm_mutex); 1386 } 1387 1388 /* ARGSUSED */ 1389 static int 1390 fcsm_els_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf, 1391 uint32_t claimed) 1392 { 1393 return (FC_UNCLAIMED); 1394 } 1395 1396 1397 /* ARGSUSED */ 1398 static int 1399 fcsm_data_cb(opaque_t ulph, opaque_t port_handle, fc_unsol_buf_t *buf, 1400 uint32_t claimed) 1401 { 1402 return (FC_UNCLAIMED); 1403 } 1404 1405 1406 /* ARGSUSED */ 1407 static int 1408 fcsm_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 1409 int *rval_p) 1410 { 1411 int retval = 0; 1412 1413 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: start")); 1414 1415 mutex_enter(&fcsm_global_mutex); 1416 if (!(fcsm_flag & FCSM_OPEN)) { 1417 mutex_exit(&fcsm_global_mutex); 1418 return (ENXIO); 1419 } 1420 mutex_exit(&fcsm_global_mutex); 1421 1422 /* Allow only root to talk */ 1423 if (drv_priv(credp)) { 1424 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1425 "ioctl: end (disallowing underprivileged user)")); 1426 return (EPERM); 1427 } 1428 1429 switch (cmd) { 1430 1431 case FCSMIO_CMD: { 1432 fcio_t fcio; 1433 int status; 1434 #ifdef _MULTI_DATAMODEL 1435 switch (ddi_model_convert_from(mode & FMODELS)) { 1436 case DDI_MODEL_ILP32: { 1437 struct fcio32 fcio32; 1438 1439 if (status = ddi_copyin((void *)arg, (void *)&fcio32, 1440 sizeof (struct fcio32), mode)) { 1441 retval = EFAULT; 1442 break; 1443 } 1444 fcio.fcio_xfer = fcio32.fcio_xfer; 1445 fcio.fcio_cmd = fcio32.fcio_cmd; 1446 fcio.fcio_flags = fcio32.fcio_flags; 1447 fcio.fcio_cmd_flags = fcio32.fcio_cmd_flags; 1448 fcio.fcio_ilen = (size_t)fcio32.fcio_ilen; 1449 fcio.fcio_ibuf = (caddr_t)(long)fcio32.fcio_ibuf; 1450 fcio.fcio_olen = (size_t)fcio32.fcio_olen; 1451 fcio.fcio_obuf = (caddr_t)(long)fcio32.fcio_obuf; 1452 fcio.fcio_alen = (size_t)fcio32.fcio_alen; 1453 fcio.fcio_abuf = (caddr_t)(long)fcio32.fcio_abuf; 1454 fcio.fcio_errno = fcio32.fcio_errno; 1455 break; 1456 } 1457 1458 case DDI_MODEL_NONE: 1459 if (status = ddi_copyin((void *)arg, (void *)&fcio, 1460 sizeof (fcio_t), mode)) { 1461 retval = EFAULT; 1462 } 1463 break; 1464 } 1465 #else /* _MULTI_DATAMODEL */ 1466 if (status = ddi_copyin((void *)arg, (void *)&fcio, 1467 sizeof (fcio_t), mode)) { 1468 retval = EFAULT; 1469 break; 1470 } 1471 #endif /* _MULTI_DATAMODEL */ 1472 if (!status) { 1473 retval = fcsm_fciocmd(arg, mode, credp, &fcio); 1474 } 1475 break; 1476 } 1477 1478 default: 1479 retval = ENOTTY; 1480 break; 1481 } 1482 1483 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "ioctl: end")); 1484 return (retval); 1485 } 1486 1487 /* ARGSUSED */ 1488 static int 1489 fcsm_port_ioctl(opaque_t ulph, opaque_t port_handle, dev_t dev, int cmd, 1490 intptr_t arg, int mode, cred_t *credp, int *rval, uint32_t claimed) 1491 { 1492 return (FC_UNCLAIMED); 1493 } 1494 1495 1496 /* ARGSUSED */ 1497 static int 1498 fcsm_fciocmd(intptr_t arg, int mode, cred_t *credp, fcio_t *fcio) 1499 { 1500 int retval = 0; 1501 1502 switch (fcio->fcio_cmd) { 1503 case FCSMIO_CT_CMD: { 1504 fcsm_t *fcsm; 1505 caddr_t user_ibuf, user_obuf; 1506 caddr_t req_iu, rsp_iu, abuf; 1507 int status, instance, count; 1508 1509 if ((fcio->fcio_xfer != FCIO_XFER_RW) || 1510 (fcio->fcio_ilen == 0) || (fcio->fcio_ibuf == 0) || 1511 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0) || 1512 (fcio->fcio_alen == 0) || (fcio->fcio_abuf == 0) || 1513 (fcio->fcio_flags != 0) || (fcio->fcio_cmd_flags != 0) || 1514 (fcio->fcio_ilen > FCSM_MAX_CT_SIZE) || 1515 (fcio->fcio_olen > FCSM_MAX_CT_SIZE) || 1516 (fcio->fcio_alen > MAXPATHLEN)) { 1517 retval = EINVAL; 1518 break; 1519 } 1520 1521 /* 1522 * Get the destination port for which this ioctl 1523 * is targeted. The abuf will have the fp_minor 1524 * number. 1525 */ 1526 abuf = kmem_zalloc(fcio->fcio_alen, KM_SLEEP); 1527 ASSERT(abuf != NULL); 1528 if (ddi_copyin(fcio->fcio_abuf, abuf, fcio->fcio_alen, mode)) { 1529 retval = EFAULT; 1530 kmem_free(abuf, fcio->fcio_alen); 1531 break; 1532 } 1533 1534 instance = *((int *)abuf); 1535 kmem_free(abuf, fcio->fcio_alen); 1536 1537 if (instance < 0) { 1538 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL, 1539 "fciocmd: instance 0x%x, invalid instance", 1540 instance)); 1541 retval = ENXIO; 1542 break; 1543 } 1544 1545 /* 1546 * We confirmed that path corresponds to our port driver 1547 * and a valid instance. 1548 * If this port instance is not yet attached, then wait 1549 * for a finite time for attach to complete 1550 */ 1551 fcsm = ddi_get_soft_state(fcsm_state, instance); 1552 count = 0; 1553 while (count++ <= 30) { 1554 if (fcsm != NULL) { 1555 mutex_enter(&fcsm->sm_mutex); 1556 if (fcsm->sm_flags & FCSM_ATTACHED) { 1557 mutex_exit(&fcsm->sm_mutex); 1558 break; 1559 } 1560 mutex_exit(&fcsm->sm_mutex); 1561 } 1562 if (count == 1) { 1563 FCSM_DEBUG(SMDL_TRACE, 1564 (CE_WARN, SM_LOG, NULL, NULL, 1565 "fciocmd: instance 0x%x, " 1566 "wait for port attach", instance)); 1567 } 1568 delay(drv_usectohz(1000000)); 1569 fcsm = ddi_get_soft_state(fcsm_state, instance); 1570 } 1571 if (count > 30) { 1572 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, NULL, NULL, 1573 "fciocmd: instance 0x%x, port not attached", 1574 instance)); 1575 retval = ENXIO; 1576 break; 1577 } 1578 1579 req_iu = kmem_zalloc(fcio->fcio_ilen, KM_SLEEP); 1580 rsp_iu = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 1581 ASSERT((req_iu != NULL) && (rsp_iu != NULL)); 1582 1583 if (ddi_copyin(fcio->fcio_ibuf, req_iu, 1584 fcio->fcio_ilen, mode)) { 1585 retval = EFAULT; 1586 kmem_free(req_iu, fcio->fcio_ilen); 1587 kmem_free(rsp_iu, fcio->fcio_olen); 1588 break; 1589 } 1590 1591 user_ibuf = fcio->fcio_ibuf; 1592 user_obuf = fcio->fcio_obuf; 1593 fcio->fcio_ibuf = req_iu; 1594 fcio->fcio_obuf = rsp_iu; 1595 1596 status = fcsm_ct_passthru(fcsm->sm_instance, fcio, KM_SLEEP, 1597 FCSM_JOBFLAG_SYNC, NULL); 1598 if (status != FC_SUCCESS) { 1599 retval = EIO; 1600 } 1601 1602 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1603 "fciocmd: cmd 0x%x completion status 0x%x", 1604 fcio->fcio_cmd, status)); 1605 fcio->fcio_errno = status; 1606 fcio->fcio_ibuf = user_ibuf; 1607 fcio->fcio_obuf = user_obuf; 1608 1609 if (ddi_copyout(rsp_iu, fcio->fcio_obuf, 1610 fcio->fcio_olen, mode)) { 1611 retval = EFAULT; 1612 kmem_free(req_iu, fcio->fcio_ilen); 1613 kmem_free(rsp_iu, fcio->fcio_olen); 1614 break; 1615 } 1616 1617 kmem_free(req_iu, fcio->fcio_ilen); 1618 kmem_free(rsp_iu, fcio->fcio_olen); 1619 1620 if (fcsm_fcio_copyout(fcio, arg, mode)) { 1621 retval = EFAULT; 1622 } 1623 break; 1624 } 1625 1626 case FCSMIO_ADAPTER_LIST: { 1627 fc_hba_list_t *list; 1628 int count; 1629 1630 if ((fcio->fcio_xfer != FCIO_XFER_RW) || 1631 (fcio->fcio_olen == 0) || (fcio->fcio_obuf == 0)) { 1632 retval = EINVAL; 1633 break; 1634 } 1635 1636 list = kmem_zalloc(fcio->fcio_olen, KM_SLEEP); 1637 1638 if (ddi_copyin(fcio->fcio_obuf, list, fcio->fcio_olen, mode)) { 1639 retval = EFAULT; 1640 break; 1641 } 1642 list->version = FC_HBA_LIST_VERSION; 1643 1644 if (fcio->fcio_olen < MAXPATHLEN * list->numAdapters) { 1645 retval = EFAULT; 1646 break; 1647 } 1648 1649 count = fc_ulp_get_adapter_paths((char *)list->hbaPaths, 1650 list->numAdapters); 1651 if (count < 0) { /* Did something go wrong? */ 1652 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1653 "Error fetching adapter list.")); 1654 retval = ENXIO; 1655 kmem_free(list, fcio->fcio_olen); 1656 break; 1657 } 1658 /* Sucess (or short buffer) */ 1659 list->numAdapters = count; 1660 if (ddi_copyout(list, fcio->fcio_obuf, 1661 fcio->fcio_olen, mode)) { 1662 retval = EFAULT; 1663 } 1664 kmem_free(list, fcio->fcio_olen); 1665 break; 1666 } 1667 1668 default: 1669 FCSM_DEBUG(SMDL_TRACE, (CE_NOTE, SM_LOG, NULL, NULL, 1670 "fciocmd: unknown cmd <0x%x>", fcio->fcio_cmd)); 1671 retval = ENOTTY; 1672 break; 1673 } 1674 1675 return (retval); 1676 } 1677 1678 static int 1679 fcsm_fcio_copyout(fcio_t *fcio, intptr_t arg, int mode) 1680 { 1681 int status; 1682 1683 #ifdef _MULTI_DATAMODEL 1684 switch (ddi_model_convert_from(mode & FMODELS)) { 1685 case DDI_MODEL_ILP32: { 1686 struct fcio32 fcio32; 1687 1688 fcio32.fcio_xfer = fcio->fcio_xfer; 1689 fcio32.fcio_cmd = fcio->fcio_cmd; 1690 fcio32.fcio_flags = fcio->fcio_flags; 1691 fcio32.fcio_cmd_flags = fcio->fcio_cmd_flags; 1692 fcio32.fcio_ilen = fcio->fcio_ilen; 1693 fcio32.fcio_ibuf = (caddr32_t)(long)fcio->fcio_ibuf; 1694 fcio32.fcio_olen = fcio->fcio_olen; 1695 fcio32.fcio_obuf = (caddr32_t)(long)fcio->fcio_obuf; 1696 fcio32.fcio_alen = fcio->fcio_alen; 1697 fcio32.fcio_abuf = (caddr32_t)(long)fcio->fcio_abuf; 1698 fcio32.fcio_errno = fcio->fcio_errno; 1699 1700 status = ddi_copyout((void *)&fcio32, (void *)arg, 1701 sizeof (struct fcio32), mode); 1702 break; 1703 } 1704 case DDI_MODEL_NONE: 1705 status = ddi_copyout((void *)fcio, (void *)arg, 1706 sizeof (fcio_t), mode); 1707 break; 1708 } 1709 #else /* _MULTI_DATAMODEL */ 1710 status = ddi_copyout((void *)fcio, (void *)arg, sizeof (fcio_t), mode); 1711 #endif /* _MULTI_DATAMODEL */ 1712 1713 return (status); 1714 } 1715 1716 1717 /* ARGSUSED */ 1718 static int 1719 fcsm_open(dev_t *devp, int flags, int otyp, cred_t *credp) 1720 { 1721 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "open")); 1722 1723 if (otyp != OTYP_CHR) { 1724 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1725 "fcsm_open: failed. open type 0x%x for minor 0x%x is not " 1726 "OTYP_CHR", otyp, getminor(*devp))); 1727 return (EINVAL); 1728 } 1729 1730 /* 1731 * Allow anybody to open (both root and non-root users). 1732 * Previlege level checks are made on the per ioctl basis. 1733 */ 1734 mutex_enter(&fcsm_global_mutex); 1735 if (flags & FEXCL) { 1736 if (fcsm_flag & FCSM_OPEN) { 1737 mutex_exit(&fcsm_global_mutex); 1738 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1739 "fcsm_open: exclusive open of 0x%x failed", 1740 getminor(*devp))); 1741 return (EBUSY); 1742 } else { 1743 ASSERT(fcsm_flag == FCSM_IDLE); 1744 fcsm_flag |= FCSM_EXCL; 1745 } 1746 } else { 1747 if (fcsm_flag & FCSM_EXCL) { 1748 mutex_exit(&fcsm_global_mutex); 1749 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1750 "fcsm_open: failed. Device minor 0x%x is in " 1751 "exclusive open mode", getminor(*devp))); 1752 return (EBUSY); 1753 } 1754 1755 } 1756 fcsm_flag |= FCSM_OPEN; 1757 mutex_exit(&fcsm_global_mutex); 1758 return (0); 1759 } 1760 1761 1762 /* ARGSUSED */ 1763 static int 1764 fcsm_close(dev_t dev, int flag, int otyp, cred_t *credp) 1765 { 1766 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, "close")); 1767 1768 if (otyp != OTYP_CHR) { 1769 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1770 "fcsm_close: failed. close type 0x%x for minor 0x%x is not " 1771 "OTYP_CHR", otyp, getminor(dev))); 1772 return (EINVAL); 1773 } 1774 1775 mutex_enter(&fcsm_global_mutex); 1776 if ((fcsm_flag & FCSM_OPEN) == 0) { 1777 mutex_exit(&fcsm_global_mutex); 1778 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 1779 "fcsm_close: failed. minor 0x%x is already closed", 1780 getminor(dev))); 1781 return (ENODEV); 1782 } 1783 fcsm_flag = FCSM_IDLE; 1784 mutex_exit(&fcsm_global_mutex); 1785 return (0); 1786 } 1787 1788 1789 /* ARGSUSED */ 1790 static void 1791 fcsm_disp_devlist(fcsm_t *fcsm, fc_portmap_t *devlist, uint32_t dev_cnt) 1792 { 1793 fc_portmap_t *map; 1794 uint32_t i; 1795 1796 if (dev_cnt == 0) { 1797 return; 1798 } 1799 1800 ASSERT(devlist != NULL); 1801 for (i = 0; i < dev_cnt; i++) { 1802 map = &devlist[i]; 1803 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 1804 "list[%d]: ID 0x%x WWN %x:%x:%x:%x:%x:%x:%x:%x " 1805 "state (0x%x) " 1806 "type <%s>(0x%x) " 1807 "flags (0x%x)", 1808 i, map->map_did.port_id, 1809 map->map_pwwn.raw_wwn[0], map->map_pwwn.raw_wwn[1], 1810 map->map_pwwn.raw_wwn[2], map->map_pwwn.raw_wwn[3], 1811 map->map_pwwn.raw_wwn[4], map->map_pwwn.raw_wwn[5], 1812 map->map_pwwn.raw_wwn[6], map->map_pwwn.raw_wwn[7], 1813 map->map_state, 1814 fcsm_dev_type_to_str(map->map_type), map->map_type, 1815 map->map_flags)); 1816 } 1817 } 1818 1819 /* ARGSUSED */ 1820 static void 1821 fcsm_display(int level, int flags, fcsm_t *fcsm, fc_packet_t *pkt, 1822 const char *fmt, ...) 1823 { 1824 caddr_t buf; 1825 va_list ap; 1826 1827 buf = kmem_zalloc(256, KM_NOSLEEP); 1828 if (buf == NULL) { 1829 return; 1830 } 1831 1832 if (fcsm) { 1833 (void) sprintf(buf + strlen(buf), "fcsm(%d): ", 1834 ddi_get_instance(fcsm->sm_port_info.port_dip)); 1835 } else { 1836 (void) sprintf(buf, "fcsm: "); 1837 } 1838 1839 va_start(ap, fmt); 1840 (void) vsprintf(buf + strlen(buf), fmt, ap); 1841 va_end(ap); 1842 1843 if (pkt) { 1844 caddr_t state, reason, action, expln; 1845 1846 (void) fc_ulp_pkt_error(pkt, &state, &reason, &action, &expln); 1847 1848 (void) sprintf(buf + strlen(buf), 1849 " state: %s(0x%x); reason: %s(0x%x)", 1850 state, pkt->pkt_state, reason, pkt->pkt_reason); 1851 } 1852 1853 switch (flags) { 1854 case SM_LOG: 1855 cmn_err(level, "!%s", buf); 1856 break; 1857 1858 case SM_CONSOLE: 1859 cmn_err(level, "^%s", buf); 1860 break; 1861 1862 default: 1863 cmn_err(level, "%s", buf); 1864 break; 1865 } 1866 1867 kmem_free(buf, 256); 1868 } 1869 1870 1871 /* 1872 * Convert FC packet state to FC errno 1873 */ 1874 int 1875 fcsm_pkt_state_to_rval(uchar_t state, uint32_t reason) 1876 { 1877 int count; 1878 1879 if (state == FC_PKT_LOCAL_RJT && (reason == FC_REASON_NO_CONNECTION || 1880 reason == FC_REASON_LOGIN_REQUIRED)) { 1881 return (FC_LOGINREQ); 1882 } else if (state == FC_PKT_PORT_OFFLINE && 1883 reason == FC_REASON_LOGIN_REQUIRED) { 1884 return (FC_LOGINREQ); 1885 } 1886 1887 for (count = 0; count < sizeof (fcsm_xlat_pkt_state) / 1888 sizeof (fcsm_xlat_pkt_state[0]); count++) { 1889 if (fcsm_xlat_pkt_state[count].xlat_state == state) { 1890 return (fcsm_xlat_pkt_state[count].xlat_rval); 1891 } 1892 } 1893 1894 return (FC_FAILURE); 1895 } 1896 1897 1898 /* 1899 * Convert port state state to descriptive string 1900 */ 1901 caddr_t 1902 fcsm_port_state_to_str(uint32_t port_state) 1903 { 1904 int count; 1905 1906 for (count = 0; count < sizeof (fcsm_xlat_port_state) / 1907 sizeof (fcsm_xlat_port_state[0]); count++) { 1908 if (fcsm_xlat_port_state[count].xlat_pstate == port_state) { 1909 return (fcsm_xlat_port_state[count].xlat_state_str); 1910 } 1911 } 1912 1913 return (NULL); 1914 } 1915 1916 1917 /* 1918 * Convert port topology state to descriptive string 1919 */ 1920 caddr_t 1921 fcsm_topology_to_str(uint32_t topology) 1922 { 1923 int count; 1924 1925 for (count = 0; count < sizeof (fcsm_xlat_topology) / 1926 sizeof (fcsm_xlat_topology[0]); count++) { 1927 if (fcsm_xlat_topology[count].xlat_top == topology) { 1928 return (fcsm_xlat_topology[count].xlat_top_str); 1929 } 1930 } 1931 1932 return (NULL); 1933 } 1934 1935 1936 /* 1937 * Convert port topology state to descriptive string 1938 */ 1939 static caddr_t 1940 fcsm_dev_type_to_str(uint32_t type) 1941 { 1942 int count; 1943 1944 for (count = 0; count < sizeof (fcsm_xlat_dev_type) / 1945 sizeof (fcsm_xlat_dev_type[0]); count++) { 1946 if (fcsm_xlat_dev_type[count].xlat_type == type) { 1947 return (fcsm_xlat_dev_type[count].xlat_str); 1948 } 1949 } 1950 1951 return (NULL); 1952 } 1953 1954 static int 1955 fcsm_cmd_cache_constructor(void *buf, void *cdarg, int kmflags) 1956 { 1957 fcsm_cmd_t *cmd = (fcsm_cmd_t *)buf; 1958 fcsm_t *fcsm = (fcsm_t *)cdarg; 1959 int (*callback)(caddr_t); 1960 fc_packet_t *pkt; 1961 fc_ulp_port_info_t *pinfo; 1962 1963 ASSERT(fcsm != NULL && buf != NULL); 1964 callback = (kmflags == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT; 1965 1966 cmd->cmd_fp_pkt = &cmd->cmd_fc_packet; 1967 cmd->cmd_job = NULL; 1968 cmd->cmd_fcsm = fcsm; 1969 cmd->cmd_dma_flags = 0; 1970 1971 pkt = &cmd->cmd_fc_packet; 1972 1973 pkt->pkt_ulp_rscn_infop = NULL; 1974 pkt->pkt_fca_private = (opaque_t)((caddr_t)cmd + sizeof (fcsm_cmd_t)); 1975 pkt->pkt_ulp_private = (opaque_t)cmd; 1976 1977 pinfo = &fcsm->sm_port_info; 1978 if (ddi_dma_alloc_handle(pinfo->port_dip, pinfo->port_cmd_dma_attr, 1979 callback, NULL, &pkt->pkt_cmd_dma) != DDI_SUCCESS) { 1980 return (1); 1981 } 1982 1983 if (ddi_dma_alloc_handle(pinfo->port_dip, pinfo->port_resp_dma_attr, 1984 callback, NULL, &pkt->pkt_resp_dma) != DDI_SUCCESS) { 1985 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 1986 return (1); 1987 } 1988 1989 pkt->pkt_cmd_acc = pkt->pkt_resp_acc = NULL; 1990 pkt->pkt_cmd_cookie_cnt = pkt->pkt_resp_cookie_cnt = 1991 pkt->pkt_data_cookie_cnt = 0; 1992 pkt->pkt_cmd_cookie = pkt->pkt_resp_cookie = 1993 pkt->pkt_data_cookie = NULL; 1994 1995 return (0); 1996 } 1997 1998 1999 /* ARGSUSED */ 2000 static void 2001 fcsm_cmd_cache_destructor(void *buf, void *cdarg) 2002 { 2003 fcsm_cmd_t *cmd = (fcsm_cmd_t *)buf; 2004 fcsm_t *fcsm = (fcsm_t *)cdarg; 2005 fc_packet_t *pkt; 2006 2007 ASSERT(fcsm == cmd->cmd_fcsm); 2008 2009 pkt = cmd->cmd_fp_pkt; 2010 2011 if (pkt->pkt_cmd_dma != NULL) { 2012 ddi_dma_free_handle(&pkt->pkt_cmd_dma); 2013 } 2014 2015 if (pkt->pkt_resp_dma != NULL) { 2016 ddi_dma_free_handle(&pkt->pkt_resp_dma); 2017 } 2018 } 2019 2020 2021 static fcsm_cmd_t * 2022 fcsm_alloc_cmd(fcsm_t *fcsm, uint32_t cmd_len, uint32_t resp_len, int sleep) 2023 { 2024 fcsm_cmd_t *cmd; 2025 fc_packet_t *pkt; 2026 int rval; 2027 ulong_t real_len; 2028 int (*callback)(caddr_t); 2029 ddi_dma_cookie_t pkt_cookie; 2030 ddi_dma_cookie_t *cp; 2031 uint32_t cnt; 2032 fc_ulp_port_info_t *pinfo; 2033 2034 ASSERT(fcsm != NULL); 2035 pinfo = &fcsm->sm_port_info; 2036 2037 callback = (sleep == KM_SLEEP) ? DDI_DMA_SLEEP: DDI_DMA_DONTWAIT; 2038 2039 cmd = (fcsm_cmd_t *)kmem_cache_alloc(fcsm->sm_cmd_cache, sleep); 2040 if (cmd == NULL) { 2041 FCSM_DEBUG(SMDL_ERR, (CE_WARN, SM_LOG, fcsm, NULL, 2042 "alloc_cmd: kmem_cache_alloc failed")); 2043 return (NULL); 2044 } 2045 2046 cmd->cmd_retry_count = 0; 2047 cmd->cmd_max_retries = 0; 2048 cmd->cmd_retry_interval = 0; 2049 cmd->cmd_transport = NULL; 2050 2051 ASSERT(cmd->cmd_dma_flags == 0); 2052 ASSERT(cmd->cmd_fp_pkt == &cmd->cmd_fc_packet); 2053 pkt = cmd->cmd_fp_pkt; 2054 2055 /* Zero out the important fc_packet fields */ 2056 pkt->pkt_pd = NULL; 2057 pkt->pkt_datalen = 0; 2058 pkt->pkt_data = NULL; 2059 pkt->pkt_state = 0; 2060 pkt->pkt_action = 0; 2061 pkt->pkt_reason = 0; 2062 pkt->pkt_expln = 0; 2063 2064 /* 2065 * Now that pkt_pd is initialized, we can call fc_ulp_init_packet 2066 */ 2067 2068 if (fc_ulp_init_packet((opaque_t)pinfo->port_handle, pkt, sleep) 2069 != FC_SUCCESS) { 2070 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2071 return (NULL); 2072 } 2073 2074 if (cmd_len) { 2075 ASSERT(pkt->pkt_cmd_dma != NULL); 2076 2077 rval = ddi_dma_mem_alloc(pkt->pkt_cmd_dma, cmd_len, 2078 fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT, 2079 callback, NULL, (caddr_t *)&pkt->pkt_cmd, &real_len, 2080 &pkt->pkt_cmd_acc); 2081 2082 if (rval != DDI_SUCCESS) { 2083 (void) fc_ulp_uninit_packet( 2084 (opaque_t)pinfo->port_handle, pkt); 2085 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2086 fcsm_free_cmd_dma(cmd); 2087 return (NULL); 2088 } 2089 2090 cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_MEM; 2091 2092 if (real_len < cmd_len) { 2093 (void) fc_ulp_uninit_packet( 2094 (opaque_t)pinfo->port_handle, pkt); 2095 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2096 fcsm_free_cmd_dma(cmd); 2097 return (NULL); 2098 } 2099 2100 rval = ddi_dma_addr_bind_handle(pkt->pkt_cmd_dma, NULL, 2101 pkt->pkt_cmd, real_len, DDI_DMA_WRITE | DDI_DMA_CONSISTENT, 2102 callback, NULL, &pkt_cookie, &pkt->pkt_cmd_cookie_cnt); 2103 2104 if (rval != DDI_DMA_MAPPED) { 2105 (void) fc_ulp_uninit_packet( 2106 (opaque_t)pinfo->port_handle, pkt); 2107 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2108 fcsm_free_cmd_dma(cmd); 2109 return (NULL); 2110 } 2111 2112 cmd->cmd_dma_flags |= FCSM_CF_CMD_VALID_DMA_BIND; 2113 2114 if (pkt->pkt_cmd_cookie_cnt > 2115 pinfo->port_cmd_dma_attr->dma_attr_sgllen) { 2116 (void) fc_ulp_uninit_packet( 2117 (opaque_t)pinfo->port_handle, pkt); 2118 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2119 fcsm_free_cmd_dma(cmd); 2120 return (NULL); 2121 } 2122 2123 ASSERT(pkt->pkt_cmd_cookie_cnt != 0); 2124 2125 cp = pkt->pkt_cmd_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2126 pkt->pkt_cmd_cookie_cnt * sizeof (pkt_cookie), 2127 KM_NOSLEEP); 2128 2129 if (cp == NULL) { 2130 (void) fc_ulp_uninit_packet( 2131 (opaque_t)pinfo->port_handle, pkt); 2132 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2133 fcsm_free_cmd_dma(cmd); 2134 return (NULL); 2135 } 2136 2137 *cp = pkt_cookie; 2138 cp++; 2139 for (cnt = 1; cnt < pkt->pkt_cmd_cookie_cnt; cnt++, cp++) { 2140 ddi_dma_nextcookie(pkt->pkt_cmd_dma, &pkt_cookie); 2141 *cp = pkt_cookie; 2142 } 2143 } 2144 2145 if (resp_len) { 2146 ASSERT(pkt->pkt_resp_dma != NULL); 2147 2148 rval = ddi_dma_mem_alloc(pkt->pkt_resp_dma, resp_len, 2149 fcsm->sm_port_info.port_acc_attr, DDI_DMA_CONSISTENT, 2150 callback, NULL, (caddr_t *)&pkt->pkt_resp, &real_len, 2151 &pkt->pkt_resp_acc); 2152 2153 if (rval != DDI_SUCCESS) { 2154 (void) fc_ulp_uninit_packet( 2155 (opaque_t)pinfo->port_handle, pkt); 2156 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2157 fcsm_free_cmd_dma(cmd); 2158 return (NULL); 2159 } 2160 2161 cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_MEM; 2162 2163 if (real_len < resp_len) { 2164 (void) fc_ulp_uninit_packet( 2165 (opaque_t)pinfo->port_handle, pkt); 2166 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2167 fcsm_free_cmd_dma(cmd); 2168 return (NULL); 2169 } 2170 2171 rval = ddi_dma_addr_bind_handle(pkt->pkt_resp_dma, NULL, 2172 pkt->pkt_resp, real_len, DDI_DMA_READ | DDI_DMA_CONSISTENT, 2173 callback, NULL, &pkt_cookie, &pkt->pkt_resp_cookie_cnt); 2174 2175 if (rval != DDI_DMA_MAPPED) { 2176 (void) fc_ulp_uninit_packet( 2177 (opaque_t)pinfo->port_handle, pkt); 2178 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2179 fcsm_free_cmd_dma(cmd); 2180 return (NULL); 2181 } 2182 2183 cmd->cmd_dma_flags |= FCSM_CF_RESP_VALID_DMA_BIND; 2184 2185 if (pkt->pkt_resp_cookie_cnt > 2186 pinfo->port_resp_dma_attr->dma_attr_sgllen) { 2187 (void) fc_ulp_uninit_packet( 2188 (opaque_t)pinfo->port_handle, pkt); 2189 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2190 fcsm_free_cmd_dma(cmd); 2191 return (NULL); 2192 } 2193 2194 ASSERT(pkt->pkt_resp_cookie_cnt != 0); 2195 2196 cp = pkt->pkt_resp_cookie = (ddi_dma_cookie_t *)kmem_alloc( 2197 pkt->pkt_resp_cookie_cnt * sizeof (pkt_cookie), 2198 KM_NOSLEEP); 2199 2200 if (cp == NULL) { 2201 (void) fc_ulp_uninit_packet( 2202 (opaque_t)pinfo->port_handle, pkt); 2203 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2204 fcsm_free_cmd_dma(cmd); 2205 return (NULL); 2206 } 2207 2208 *cp = pkt_cookie; 2209 cp++; 2210 for (cnt = 1; cnt < pkt->pkt_resp_cookie_cnt; cnt++, cp++) { 2211 ddi_dma_nextcookie(pkt->pkt_resp_dma, &pkt_cookie); 2212 *cp = pkt_cookie; 2213 } 2214 } 2215 2216 pkt->pkt_cmdlen = cmd_len; 2217 pkt->pkt_rsplen = resp_len; 2218 2219 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2220 "alloc_cmd: cmd 0x%p", (void *)cmd)); 2221 return (cmd); 2222 } 2223 2224 static void 2225 fcsm_free_cmd(fcsm_cmd_t *cmd) 2226 { 2227 fcsm_t *fcsm; 2228 2229 fcsm = cmd->cmd_fcsm; 2230 ASSERT(fcsm != NULL); 2231 2232 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2233 "free_cmd: cmd 0x%p", (void *)cmd)); 2234 2235 fcsm_free_cmd_dma(cmd); 2236 2237 (void) fc_ulp_uninit_packet((opaque_t)fcsm->sm_port_info.port_handle, 2238 cmd->cmd_fp_pkt); 2239 kmem_cache_free(fcsm->sm_cmd_cache, (void *)cmd); 2240 } 2241 2242 static void 2243 fcsm_free_cmd_dma(fcsm_cmd_t *cmd) 2244 { 2245 fc_packet_t *pkt; 2246 2247 pkt = cmd->cmd_fp_pkt; 2248 ASSERT(pkt != NULL); 2249 2250 pkt->pkt_cmdlen = 0; 2251 pkt->pkt_rsplen = 0; 2252 pkt->pkt_tran_type = 0; 2253 pkt->pkt_tran_flags = 0; 2254 2255 if (pkt->pkt_cmd_cookie != NULL) { 2256 kmem_free(pkt->pkt_cmd_cookie, pkt->pkt_cmd_cookie_cnt * 2257 sizeof (ddi_dma_cookie_t)); 2258 pkt->pkt_cmd_cookie = NULL; 2259 } 2260 2261 if (pkt->pkt_resp_cookie != NULL) { 2262 kmem_free(pkt->pkt_resp_cookie, pkt->pkt_resp_cookie_cnt * 2263 sizeof (ddi_dma_cookie_t)); 2264 pkt->pkt_resp_cookie = NULL; 2265 } 2266 2267 if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_BIND) { 2268 (void) ddi_dma_unbind_handle(pkt->pkt_cmd_dma); 2269 } 2270 2271 if (cmd->cmd_dma_flags & FCSM_CF_CMD_VALID_DMA_MEM) { 2272 if (pkt->pkt_cmd_acc) { 2273 ddi_dma_mem_free(&pkt->pkt_cmd_acc); 2274 } 2275 } 2276 2277 if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_BIND) { 2278 (void) ddi_dma_unbind_handle(pkt->pkt_resp_dma); 2279 } 2280 2281 if (cmd->cmd_dma_flags & FCSM_CF_RESP_VALID_DMA_MEM) { 2282 if (pkt->pkt_resp_acc) { 2283 ddi_dma_mem_free(&pkt->pkt_resp_acc); 2284 } 2285 } 2286 2287 cmd->cmd_dma_flags = 0; 2288 } 2289 2290 /* ARGSUSED */ 2291 static int 2292 fcsm_job_cache_constructor(void *buf, void *cdarg, int kmflag) 2293 { 2294 fcsm_job_t *job = (fcsm_job_t *)buf; 2295 2296 mutex_init(&job->job_mutex, NULL, MUTEX_DRIVER, NULL); 2297 sema_init(&job->job_sema, 0, NULL, SEMA_DEFAULT, NULL); 2298 2299 return (0); 2300 } 2301 2302 /* ARGSUSED */ 2303 static void 2304 fcsm_job_cache_destructor(void *buf, void *cdarg) 2305 { 2306 fcsm_job_t *job = (fcsm_job_t *)buf; 2307 2308 sema_destroy(&job->job_sema); 2309 mutex_destroy(&job->job_mutex); 2310 } 2311 2312 2313 static fcsm_job_t * 2314 fcsm_alloc_job(int sleep) 2315 { 2316 fcsm_job_t *job; 2317 2318 job = (fcsm_job_t *)kmem_cache_alloc(fcsm_job_cache, sleep); 2319 if (job != NULL) { 2320 job->job_code = FCSM_JOB_NONE; 2321 job->job_flags = 0; 2322 job->job_port_instance = -1; 2323 job->job_result = -1; 2324 job->job_arg = (opaque_t)0; 2325 job->job_caller_priv = (opaque_t)0; 2326 job->job_comp = NULL; 2327 job->job_comp_arg = (opaque_t)0; 2328 job->job_priv = (void *)0; 2329 job->job_priv_flags = 0; 2330 job->job_next = 0; 2331 } 2332 2333 return (job); 2334 } 2335 2336 static void 2337 fcsm_dealloc_job(fcsm_job_t *job) 2338 { 2339 kmem_cache_free(fcsm_job_cache, (void *)job); 2340 } 2341 2342 2343 static void 2344 fcsm_init_job(fcsm_job_t *job, int instance, uint32_t command, uint32_t flags, 2345 opaque_t arg, opaque_t caller_priv, 2346 void (*comp)(opaque_t, fcsm_job_t *, int), opaque_t comp_arg) 2347 { 2348 ASSERT(job != NULL); 2349 job->job_port_instance = instance; 2350 job->job_code = command; 2351 job->job_flags = flags; 2352 job->job_arg = arg; 2353 job->job_caller_priv = caller_priv; 2354 job->job_comp = comp; 2355 job->job_comp_arg = comp_arg; 2356 job->job_retry_count = 0; 2357 } 2358 2359 static int 2360 fcsm_process_job(fcsm_job_t *job, int priority_flag) 2361 { 2362 fcsm_t *fcsm; 2363 int sync; 2364 2365 ASSERT(job != NULL); 2366 ASSERT(!MUTEX_HELD(&job->job_mutex)); 2367 2368 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance); 2369 2370 if (fcsm == NULL) { 2371 FCSM_DEBUG(SMDL_ERR, (CE_NOTE, SM_LOG, NULL, NULL, 2372 "process_job: port instance 0x%x not found", 2373 job->job_port_instance)); 2374 return (FC_BADDEV); 2375 } 2376 2377 mutex_enter(&job->job_mutex); 2378 /* Both SYNC and ASYNC flags should not be set */ 2379 ASSERT(((job->job_flags & (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) == 2380 FCSM_JOBFLAG_SYNC) || ((job->job_flags & 2381 (FCSM_JOBFLAG_SYNC | FCSM_JOBFLAG_ASYNC)) == FCSM_JOBFLAG_ASYNC)); 2382 /* 2383 * Check if job is a synchronous job. We might not be able to 2384 * check it reliably after enque_job(), if job is an ASYNC job. 2385 */ 2386 sync = job->job_flags & FCSM_JOBFLAG_SYNC; 2387 mutex_exit(&job->job_mutex); 2388 2389 /* Queue the job for processing by job thread */ 2390 fcsm_enque_job(fcsm, job, priority_flag); 2391 2392 /* Wait for job completion, if it is a synchronous job */ 2393 if (sync) { 2394 /* 2395 * This is a Synchronous Job. So job structure is available. 2396 * Caller is responsible for freeing it. 2397 */ 2398 FCSM_DEBUG(SMDL_ERR, (CE_CONT, SM_LOG, fcsm, NULL, 2399 "process_job: Waiting for sync job <%p> completion", 2400 (void *)job)); 2401 sema_p(&job->job_sema); 2402 } 2403 2404 return (FC_SUCCESS); 2405 } 2406 2407 static void 2408 fcsm_enque_job(fcsm_t *fcsm, fcsm_job_t *job, int priority_flag) 2409 { 2410 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex)); 2411 2412 mutex_enter(&fcsm->sm_mutex); 2413 /* Queue the job at the head or tail depending on the job priority */ 2414 if (priority_flag) { 2415 FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL, 2416 "enque_job: job 0x%p is high priority", job)); 2417 /* Queue at the head */ 2418 if (fcsm->sm_job_tail == NULL) { 2419 ASSERT(fcsm->sm_job_head == NULL); 2420 fcsm->sm_job_head = fcsm->sm_job_tail = job; 2421 } else { 2422 ASSERT(fcsm->sm_job_head != NULL); 2423 job->job_next = fcsm->sm_job_head; 2424 fcsm->sm_job_head = job; 2425 } 2426 } else { 2427 FCSM_DEBUG(SMDL_INFO, (CE_CONT, SM_LOG, fcsm, NULL, 2428 "enque_job: job 0x%p is normal", job)); 2429 /* Queue at the tail */ 2430 if (fcsm->sm_job_tail == NULL) { 2431 ASSERT(fcsm->sm_job_head == NULL); 2432 fcsm->sm_job_head = fcsm->sm_job_tail = job; 2433 } else { 2434 ASSERT(fcsm->sm_job_head != NULL); 2435 fcsm->sm_job_tail->job_next = job; 2436 fcsm->sm_job_tail = job; 2437 } 2438 job->job_next = NULL; 2439 } 2440 2441 /* Signal the job thread to process the job */ 2442 cv_signal(&fcsm->sm_job_cv); 2443 mutex_exit(&fcsm->sm_mutex); 2444 } 2445 2446 static int 2447 fcsm_retry_job(fcsm_t *fcsm, fcsm_job_t *job) 2448 { 2449 /* 2450 * If it is a CT passthru job and status is login required, then 2451 * retry the job so that login can be performed again. 2452 * Ensure that this retry is performed a finite number of times, 2453 * so that a faulty fabric does not cause us to retry forever. 2454 */ 2455 2456 switch (job->job_code) { 2457 case FCSM_JOB_CT_PASSTHRU: { 2458 uint32_t jobflag; 2459 fc_ct_header_t *ct_header; 2460 2461 if (job->job_result != FC_LOGINREQ) { 2462 break; 2463 } 2464 2465 /* 2466 * If it is a management server command 2467 * then Reset the Management server login flag, so that login 2468 * gets re-established. 2469 * If it is a Name server command, 2470 * then it is 'fp' responsibility to perform the login. 2471 */ 2472 ASSERT(job->job_arg != NULL); 2473 ct_header = 2474 (fc_ct_header_t *)((fcio_t *)job->job_arg)->fcio_ibuf; 2475 if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) { 2476 mutex_enter(&fcsm->sm_mutex); 2477 fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGGED_IN; 2478 mutex_exit(&fcsm->sm_mutex); 2479 } 2480 2481 if (job->job_retry_count >= fcsm_max_job_retries) { 2482 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2483 "retry_job: job 0x%p max retries (%d) reached", 2484 (void *)job, job->job_retry_count)); 2485 break; 2486 } 2487 2488 /* 2489 * Login is required again. Retry the command, so that 2490 * login will get performed again. 2491 */ 2492 mutex_enter(&job->job_mutex); 2493 job->job_retry_count++; 2494 jobflag = job->job_flags; 2495 mutex_exit(&job->job_mutex); 2496 2497 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2498 "retry_job: retry(%d) job 0x%p", 2499 job->job_retry_count, (void *)job)); 2500 /* 2501 * This job should get picked up before the 2502 * other jobs sitting in the queue. 2503 * Requeue the command at the head and then 2504 * reset the SERIALIZE flag. 2505 */ 2506 fcsm_enque_job(fcsm, job, 1); 2507 if (jobflag & FCSM_JOBFLAG_SERIALIZE) { 2508 mutex_enter(&fcsm->sm_mutex); 2509 ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD); 2510 fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD; 2511 2512 /* Signal the job thread to process the job */ 2513 cv_signal(&fcsm->sm_job_cv); 2514 mutex_exit(&fcsm->sm_mutex); 2515 } 2516 2517 /* Command is queued for retrying */ 2518 return (0); 2519 } 2520 2521 default: 2522 break; 2523 } 2524 return (1); 2525 } 2526 2527 static void 2528 fcsm_jobdone(fcsm_job_t *job) 2529 { 2530 fcsm_t *fcsm; 2531 2532 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance); 2533 ASSERT(fcsm != NULL); 2534 2535 if (job->job_result != FC_SUCCESS) { 2536 if (fcsm_retry_job(fcsm, job) == 0) { 2537 /* Job retried. so just return from here */ 2538 return; 2539 } 2540 } 2541 2542 if (job->job_comp) { 2543 job->job_comp(job->job_comp_arg, job, job->job_result); 2544 } 2545 2546 mutex_enter(&job->job_mutex); 2547 if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) { 2548 mutex_exit(&job->job_mutex); 2549 mutex_enter(&fcsm->sm_mutex); 2550 ASSERT(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD); 2551 fcsm->sm_flags &= ~FCSM_SERIALIZE_JOBTHREAD; 2552 2553 /* Signal the job thread to process the job */ 2554 cv_signal(&fcsm->sm_job_cv); 2555 mutex_exit(&fcsm->sm_mutex); 2556 mutex_enter(&job->job_mutex); 2557 } 2558 2559 if (job->job_flags & FCSM_JOBFLAG_SYNC) { 2560 mutex_exit(&job->job_mutex); 2561 sema_v(&job->job_sema); 2562 } else { 2563 mutex_exit(&job->job_mutex); 2564 /* Async job, free the job structure */ 2565 fcsm_dealloc_job(job); 2566 } 2567 } 2568 2569 fcsm_job_t * 2570 fcsm_deque_job(fcsm_t *fcsm) 2571 { 2572 fcsm_job_t *job; 2573 2574 ASSERT(MUTEX_HELD(&fcsm->sm_mutex)); 2575 2576 if (fcsm->sm_job_head == NULL) { 2577 ASSERT(fcsm->sm_job_tail == NULL); 2578 job = NULL; 2579 } else { 2580 ASSERT(fcsm->sm_job_tail != NULL); 2581 job = fcsm->sm_job_head; 2582 if (job->job_next == NULL) { 2583 ASSERT(fcsm->sm_job_tail == job); 2584 fcsm->sm_job_tail = NULL; 2585 } 2586 fcsm->sm_job_head = job->job_next; 2587 job->job_next = NULL; 2588 } 2589 2590 return (job); 2591 } 2592 2593 2594 /* Dedicated per port thread to process various commands */ 2595 static void 2596 fcsm_job_thread(fcsm_t *fcsm) 2597 { 2598 fcsm_job_t *job; 2599 2600 ASSERT(fcsm != NULL); 2601 #ifndef __lock_lint 2602 CALLB_CPR_INIT(&fcsm->sm_cpr_info, &fcsm->sm_mutex, 2603 callb_generic_cpr, "fcsm_job_thread"); 2604 #endif /* __lock_lint */ 2605 2606 for (;;) { 2607 mutex_enter(&fcsm->sm_mutex); 2608 2609 while (fcsm->sm_job_head == NULL || 2610 fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD) { 2611 CALLB_CPR_SAFE_BEGIN(&fcsm->sm_cpr_info); 2612 cv_wait(&fcsm->sm_job_cv, &fcsm->sm_mutex); 2613 CALLB_CPR_SAFE_END(&fcsm->sm_cpr_info, &fcsm->sm_mutex); 2614 } 2615 2616 job = fcsm_deque_job(fcsm); 2617 2618 mutex_exit(&fcsm->sm_mutex); 2619 2620 mutex_enter(&job->job_mutex); 2621 if (job->job_flags & FCSM_JOBFLAG_SERIALIZE) { 2622 mutex_exit(&job->job_mutex); 2623 2624 mutex_enter(&fcsm->sm_mutex); 2625 ASSERT(!(fcsm->sm_flags & FCSM_SERIALIZE_JOBTHREAD)); 2626 fcsm->sm_flags |= FCSM_SERIALIZE_JOBTHREAD; 2627 mutex_exit(&fcsm->sm_mutex); 2628 } else { 2629 mutex_exit(&job->job_mutex); 2630 } 2631 2632 ASSERT(fcsm->sm_instance == job->job_port_instance); 2633 2634 switch (job->job_code) { 2635 case FCSM_JOB_NONE: 2636 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 2637 "job_thread: uninitialized job code"); 2638 job->job_result = FC_FAILURE; 2639 fcsm_jobdone(job); 2640 break; 2641 2642 case FCSM_JOB_THREAD_SHUTDOWN: 2643 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2644 "job_thread: job code <JOB PORT SHUTDOWN>")); 2645 2646 /* 2647 * There should not be any pending jobs, when this 2648 * is being called. 2649 */ 2650 mutex_enter(&fcsm->sm_mutex); 2651 ASSERT(fcsm->sm_job_head == NULL); 2652 ASSERT(fcsm->sm_job_tail == NULL); 2653 ASSERT(fcsm->sm_retry_head == NULL); 2654 ASSERT(fcsm->sm_retry_tail == NULL); 2655 job->job_result = FC_SUCCESS; 2656 #ifndef __lock_lint 2657 CALLB_CPR_EXIT(&fcsm->sm_cpr_info); 2658 #endif 2659 /* CPR_EXIT has also dropped the fcsm->sm_mutex */ 2660 2661 fcsm_jobdone(job); 2662 thread_exit(); 2663 /* NOTREACHED */ 2664 break; 2665 2666 case FCSM_JOB_LOGIN_NAME_SERVER: 2667 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2668 "job_thread: job code <LOGIN_NAME_SERVER>")); 2669 job->job_result = FC_SUCCESS; 2670 fcsm_jobdone(job); 2671 break; 2672 2673 case FCSM_JOB_LOGIN_MGMT_SERVER: 2674 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2675 "job_thread: job code <LOGIN_MGMT_SERVER>")); 2676 fcsm_job_login_mgmt_server(job); 2677 break; 2678 2679 case FCSM_JOB_CT_PASSTHRU: 2680 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2681 "job_thread: job code <CT_PASSTHRU>")); 2682 fcsm_job_ct_passthru(job); 2683 break; 2684 2685 default: 2686 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2687 "job_thread: job code <UNKNOWN>")); 2688 job->job_result = FC_FAILURE; 2689 fcsm_jobdone(job); 2690 break; 2691 } 2692 } 2693 2694 /* NOTREACHED */ 2695 } 2696 2697 2698 static void 2699 fcsm_ct_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, fc_ct_aiu_t *req_iu, size_t req_len, 2700 void (*comp_func)()) 2701 { 2702 fc_packet_t *pkt; 2703 2704 pkt = cmd->cmd_fp_pkt; 2705 ASSERT(pkt != NULL); 2706 2707 ASSERT(req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE || 2708 (req_iu->aiu_header.ct_fcstype == FCSTYPE_DIRECTORY && 2709 req_iu->aiu_header.ct_fcssubtype == FCSSUB_DS_NAME_SERVER)); 2710 2711 2712 /* Set the pkt d_id properly */ 2713 if (req_iu->aiu_header.ct_fcstype == FCSTYPE_MGMTSERVICE) { 2714 pkt->pkt_cmd_fhdr.d_id = FS_MANAGEMENT_SERVER; 2715 } else { 2716 pkt->pkt_cmd_fhdr.d_id = FS_NAME_SERVER; 2717 } 2718 2719 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; 2720 pkt->pkt_cmd_fhdr.rsvd = 0; 2721 pkt->pkt_cmd_fhdr.s_id = fcsm->sm_sid; 2722 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; 2723 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | 2724 F_CTL_FIRST_SEQ | F_CTL_END_SEQ; 2725 pkt->pkt_cmd_fhdr.seq_id = 0; 2726 pkt->pkt_cmd_fhdr.df_ctl = 0; 2727 pkt->pkt_cmd_fhdr.seq_cnt = 0; 2728 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 2729 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 2730 pkt->pkt_cmd_fhdr.ro = 0; 2731 2732 pkt->pkt_timeout = FCSM_MS_TIMEOUT; 2733 pkt->pkt_comp = comp_func; 2734 2735 FCSM_REP_WR(pkt->pkt_cmd_acc, req_iu, pkt->pkt_cmd, req_len); 2736 2737 cmd->cmd_transport = fc_ulp_transport; 2738 } 2739 2740 static void 2741 fcsm_ct_intr(fcsm_cmd_t *cmd) 2742 { 2743 fc_packet_t *pkt; 2744 fcsm_job_t *job; 2745 fcio_t *fcio; 2746 2747 pkt = cmd->cmd_fp_pkt; 2748 job = cmd->cmd_job; 2749 ASSERT(job != NULL); 2750 2751 fcio = job->job_arg; 2752 ASSERT(fcio != NULL); 2753 2754 if (pkt->pkt_state != FC_PKT_SUCCESS) { 2755 fcsm_display(CE_WARN, SM_LOG, cmd->cmd_fcsm, pkt, 2756 "ct_intr: CT command <0x%x> to did 0x%x failed", 2757 ((fc_ct_aiu_t *)fcio->fcio_ibuf)->aiu_header.ct_cmdrsp, 2758 pkt->pkt_cmd_fhdr.d_id); 2759 } else { 2760 /* Get the CT response payload */ 2761 FCSM_REP_RD(pkt->pkt_resp_acc, fcio->fcio_obuf, 2762 pkt->pkt_resp, fcio->fcio_olen); 2763 } 2764 2765 job->job_result = 2766 fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason); 2767 2768 fcsm_free_cmd(cmd); 2769 2770 fcsm_jobdone(job); 2771 } 2772 2773 2774 static void 2775 fcsm_job_ct_passthru(fcsm_job_t *job) 2776 { 2777 fcsm_t *fcsm; 2778 fcio_t *fcio; 2779 fcsm_cmd_t *cmd; 2780 int status; 2781 fc_ct_header_t *ct_header; 2782 2783 ASSERT(job != NULL); 2784 ASSERT(job->job_port_instance != -1); 2785 2786 job->job_result = FC_FAILURE; 2787 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance); 2788 if (fcsm == NULL) { 2789 fcsm_jobdone(job); 2790 return; 2791 } 2792 2793 /* 2794 * Process the CT Passthru job only if port is attached 2795 * to a FABRIC. 2796 */ 2797 if (!FC_TOP_EXTERNAL(fcsm->sm_port_top)) { 2798 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2799 "job_ct_passthru: end (non-fabric port)")); 2800 job->job_result = FC_BADDEV; 2801 fcsm_jobdone(job); 2802 return; 2803 } 2804 2805 fcio = job->job_arg; 2806 ASSERT(fcio != NULL); 2807 2808 /* 2809 * If it is NOT a Management Seriver (MS) or Name Server (NS) command 2810 * then complete the command with failure. 2811 */ 2812 ct_header = (fc_ct_header_t *)fcio->fcio_ibuf; 2813 2814 /* 2815 * According to libHBAAPI spec, CT header from libHBAAPI would always 2816 * be big endian, so we must swap CT header before continue in little 2817 * endian platforms. 2818 */ 2819 mutex_enter(&job->job_mutex); 2820 if (!(job->job_flags & FCSM_JOBFLAG_CTHEADER_BE)) { 2821 job->job_flags |= FCSM_JOBFLAG_CTHEADER_BE; 2822 *((uint32_t *)((uint32_t *)ct_header + 0)) = 2823 BE_32(*((uint32_t *)((uint32_t *)ct_header + 0))); 2824 *((uint32_t *)((uint32_t *)ct_header + 1)) = 2825 BE_32(*((uint32_t *)((uint32_t *)ct_header + 1))); 2826 *((uint32_t *)((uint32_t *)ct_header + 2)) = 2827 BE_32(*((uint32_t *)((uint32_t *)ct_header + 2))); 2828 *((uint32_t *)((uint32_t *)ct_header + 3)) = 2829 BE_32(*((uint32_t *)((uint32_t *)ct_header + 3))); 2830 } 2831 mutex_exit(&job->job_mutex); 2832 2833 if (ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) { 2834 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2835 "job_ct_passthru: Management Server Cmd")); 2836 } else if (ct_header->ct_fcstype == FCSTYPE_DIRECTORY) { 2837 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2838 "job_ct_passthru: Name Server Cmd")); 2839 } else { 2840 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2841 "job_ct_passthru: Unsupported Destination " 2842 "gs_type <0x%x> gs_subtype <0x%x>", 2843 ct_header->ct_fcstype, ct_header->ct_fcssubtype)); 2844 } 2845 2846 if (ct_header->ct_fcstype != FCSTYPE_MGMTSERVICE && 2847 (ct_header->ct_fcstype != FCSTYPE_DIRECTORY || 2848 ct_header->ct_fcssubtype != FCSSUB_DS_NAME_SERVER)) { 2849 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2850 "job_ct_passthru: end (Not a Name Server OR " 2851 "Mgmt Server Cmd)")); 2852 job->job_result = FC_BADCMD; 2853 fcsm_jobdone(job); 2854 return; 2855 } 2856 2857 /* 2858 * If it is an MS command and we are not logged in to the management 2859 * server, then start the login and requeue the command. 2860 * If login to management server is in progress, then reque the 2861 * command to wait for login to complete. 2862 */ 2863 mutex_enter(&fcsm->sm_mutex); 2864 if ((ct_header->ct_fcstype == FCSTYPE_MGMTSERVICE) && 2865 !(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN)) { 2866 mutex_exit(&fcsm->sm_mutex); 2867 if (fcsm_login_and_process_job(fcsm, job) != FC_SUCCESS) { 2868 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2869 "job_ct_passthru: perform login failed")); 2870 job->job_result = FC_FAILURE; 2871 fcsm_jobdone(job); 2872 } 2873 return; 2874 } 2875 mutex_exit(&fcsm->sm_mutex); 2876 2877 /* 2878 * We are already logged in to the management server. 2879 * Issue the CT Passthru command 2880 */ 2881 cmd = fcsm_alloc_cmd(fcsm, fcio->fcio_ilen, fcio->fcio_olen, KM_SLEEP); 2882 if (cmd == NULL) { 2883 job->job_result = FC_NOMEM; 2884 fcsm_jobdone(job); 2885 return; 2886 } 2887 2888 FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE, 2889 fcsm_max_cmd_retries, fcsm_ct_intr); 2890 2891 fcsm_ct_init(fcsm, cmd, (fc_ct_aiu_t *)fcio->fcio_ibuf, fcio->fcio_ilen, 2892 fcsm_pkt_common_intr); 2893 2894 if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) { 2895 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL, 2896 "job_ct_passthru: issue CT Passthru failed, status 0x%x", 2897 status)); 2898 job->job_result = status; 2899 fcsm_free_cmd(cmd); 2900 fcsm_jobdone(job); 2901 return; 2902 } 2903 } 2904 2905 static int 2906 fcsm_login_and_process_job(fcsm_t *fcsm, fcsm_job_t *orig_job) 2907 { 2908 fcsm_job_t *login_job; 2909 #ifdef DEBUG 2910 int status; 2911 #endif /* DEBUG */ 2912 2913 if (orig_job->job_code != FCSM_JOB_CT_PASSTHRU) { 2914 return (FC_FAILURE); 2915 } 2916 2917 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 2918 "login_and_process_job: start login.")); 2919 2920 mutex_enter(&fcsm->sm_mutex); 2921 if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) { 2922 /* 2923 * Directory server login completed just now, while the 2924 * mutex was dropped. Just queue the command again for 2925 * processing. 2926 */ 2927 mutex_exit(&fcsm->sm_mutex); 2928 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2929 "login_and_process_job: got job 0x%p. login just " 2930 "completed", (void *)orig_job)); 2931 fcsm_enque_job(fcsm, orig_job, 0); 2932 return (FC_SUCCESS); 2933 } 2934 2935 if (fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG) { 2936 /* 2937 * Ideally we shouldn't have come here, since login 2938 * job has the serialize flag set. 2939 * Anyway, put the command back on the queue. 2940 */ 2941 mutex_exit(&fcsm->sm_mutex); 2942 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 2943 "login_and_process_job: got job 0x%p while login to " 2944 "management server in progress", (void *)orig_job)); 2945 fcsm_enque_job(fcsm, orig_job, 0); 2946 return (FC_SUCCESS); 2947 } 2948 2949 fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGIN_IN_PROG; 2950 mutex_exit(&fcsm->sm_mutex); 2951 2952 login_job = fcsm_alloc_job(KM_SLEEP); 2953 ASSERT(login_job != NULL); 2954 2955 /* 2956 * Mark the login job as SERIALIZE, so that all other jobs will 2957 * be processed after completing the login. 2958 * Save the original job (CT Passthru job) in the caller private 2959 * field in the job structure, so that CT command can be issued 2960 * after login has completed. 2961 */ 2962 fcsm_init_job(login_job, fcsm->sm_instance, FCSM_JOB_LOGIN_MGMT_SERVER, 2963 FCSM_JOBFLAG_ASYNC | FCSM_JOBFLAG_SERIALIZE, 2964 (opaque_t)NULL, (opaque_t)orig_job, fcsm_login_ms_comp, NULL); 2965 orig_job->job_priv = (void *)login_job; 2966 2967 #ifdef DEBUG 2968 status = fcsm_process_job(login_job, 1); 2969 ASSERT(status == FC_SUCCESS); 2970 #else /* DEBUG */ 2971 (void) fcsm_process_job(login_job, 1); 2972 #endif /* DEBUG */ 2973 return (FC_SUCCESS); 2974 } 2975 2976 2977 /* ARGSUSED */ 2978 static void 2979 fcsm_login_ms_comp(opaque_t comp_arg, fcsm_job_t *login_job, int result) 2980 { 2981 fcsm_t *fcsm; 2982 fcsm_job_t *orig_job; 2983 2984 ASSERT(login_job != NULL); 2985 2986 orig_job = (fcsm_job_t *)login_job->job_caller_priv; 2987 2988 ASSERT(orig_job != NULL); 2989 ASSERT(orig_job->job_priv == (void *)login_job); 2990 orig_job->job_priv = NULL; 2991 2992 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 2993 "login_ms_comp: result 0x%x", login_job->job_result)); 2994 2995 /* Set the login flag in the per port fcsm structure */ 2996 ASSERT(login_job->job_port_instance == orig_job->job_port_instance); 2997 fcsm = ddi_get_soft_state(fcsm_state, login_job->job_port_instance); 2998 ASSERT(fcsm != NULL); 2999 3000 mutex_enter(&fcsm->sm_mutex); 3001 ASSERT((fcsm->sm_flags & FCSM_MGMT_SERVER_LOGGED_IN) == 0); 3002 ASSERT(fcsm->sm_flags & FCSM_MGMT_SERVER_LOGIN_IN_PROG); 3003 fcsm->sm_flags &= ~FCSM_MGMT_SERVER_LOGIN_IN_PROG; 3004 if (login_job->job_result != FC_SUCCESS) { 3005 caddr_t msg; 3006 3007 /* 3008 * Login failed. Complete the original job with FC_LOGINREQ 3009 * status. Retry of that job will cause login to be 3010 * retried. 3011 */ 3012 mutex_exit(&fcsm->sm_mutex); 3013 orig_job->job_result = FC_LOGINREQ; 3014 fcsm_jobdone(orig_job); 3015 3016 (void) fc_ulp_error(login_job->job_result, &msg); 3017 fcsm_display(CE_WARN, SM_LOG, fcsm, NULL, 3018 "login_ms_comp: Management server login failed: <%s>", msg); 3019 return; 3020 } 3021 fcsm->sm_flags |= FCSM_MGMT_SERVER_LOGGED_IN; 3022 mutex_exit(&fcsm->sm_mutex); 3023 3024 /* 3025 * Queue the original job at the head of the queue for processing. 3026 */ 3027 fcsm_enque_job(fcsm, orig_job, 1); 3028 } 3029 3030 3031 static void 3032 fcsm_els_init(fcsm_cmd_t *cmd, uint32_t d_id) 3033 { 3034 fc_packet_t *pkt; 3035 fcsm_t *fcsm; 3036 3037 fcsm = cmd->cmd_fcsm; 3038 pkt = cmd->cmd_fp_pkt; 3039 ASSERT(fcsm != NULL && pkt != NULL); 3040 3041 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ; 3042 pkt->pkt_cmd_fhdr.d_id = d_id; 3043 pkt->pkt_cmd_fhdr.rsvd = 0; 3044 pkt->pkt_cmd_fhdr.s_id = fcsm->sm_sid; 3045 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 3046 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_SEQ_INITIATIVE | F_CTL_FIRST_SEQ; 3047 pkt->pkt_cmd_fhdr.seq_id = 0; 3048 pkt->pkt_cmd_fhdr.df_ctl = 0; 3049 pkt->pkt_cmd_fhdr.seq_cnt = 0; 3050 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 3051 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 3052 pkt->pkt_cmd_fhdr.ro = 0; 3053 3054 pkt->pkt_timeout = FCSM_ELS_TIMEOUT; 3055 } 3056 3057 3058 static int 3059 fcsm_xlogi_init(fcsm_t *fcsm, fcsm_cmd_t *cmd, uint32_t d_id, 3060 void (*comp_func)(), uchar_t ls_code) 3061 { 3062 ls_code_t payload; 3063 fc_packet_t *pkt; 3064 la_els_logi_t *login_params; 3065 int status; 3066 3067 login_params = (la_els_logi_t *) 3068 kmem_zalloc(sizeof (la_els_logi_t), KM_SLEEP); 3069 if (login_params == NULL) { 3070 return (FC_NOMEM); 3071 } 3072 3073 status = fc_ulp_get_port_login_params(fcsm->sm_port_info.port_handle, 3074 login_params); 3075 if (status != FC_SUCCESS) { 3076 kmem_free(login_params, sizeof (la_els_logi_t)); 3077 return (status); 3078 } 3079 3080 pkt = cmd->cmd_fp_pkt; 3081 3082 fcsm_els_init(cmd, d_id); 3083 pkt->pkt_comp = comp_func; 3084 3085 payload.ls_code = ls_code; 3086 payload.mbz = 0; 3087 3088 FCSM_REP_WR(pkt->pkt_cmd_acc, login_params, 3089 pkt->pkt_cmd, sizeof (la_els_logi_t)); 3090 FCSM_REP_WR(pkt->pkt_cmd_acc, &payload, 3091 pkt->pkt_cmd, sizeof (payload)); 3092 3093 cmd->cmd_transport = fc_ulp_issue_els; 3094 3095 kmem_free(login_params, sizeof (la_els_logi_t)); 3096 3097 return (FC_SUCCESS); 3098 } 3099 3100 static void 3101 fcsm_xlogi_intr(fcsm_cmd_t *cmd) 3102 { 3103 fc_packet_t *pkt; 3104 fcsm_job_t *job; 3105 fcsm_t *fcsm; 3106 3107 pkt = cmd->cmd_fp_pkt; 3108 job = cmd->cmd_job; 3109 ASSERT(job != NULL); 3110 3111 fcsm = cmd->cmd_fcsm; 3112 ASSERT(fcsm != NULL); 3113 3114 if (pkt->pkt_state != FC_PKT_SUCCESS) { 3115 fcsm_display(CE_WARN, SM_LOG, fcsm, pkt, 3116 "xlogi_intr: login to DID 0x%x failed", 3117 pkt->pkt_cmd_fhdr.d_id); 3118 } else { 3119 /* Get the Login parameters of the Management Server */ 3120 FCSM_REP_RD(pkt->pkt_resp_acc, &fcsm->sm_ms_service_params, 3121 pkt->pkt_resp, sizeof (la_els_logi_t)); 3122 } 3123 3124 3125 job->job_result = 3126 fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason); 3127 3128 fcsm_free_cmd(cmd); 3129 3130 fcsm_jobdone(job); 3131 } 3132 3133 static void 3134 fcsm_job_login_mgmt_server(fcsm_job_t *job) 3135 { 3136 fcsm_t *fcsm; 3137 fcsm_cmd_t *cmd; 3138 int status; 3139 3140 ASSERT(job != NULL); 3141 ASSERT(job->job_port_instance != -1); 3142 3143 fcsm = ddi_get_soft_state(fcsm_state, job->job_port_instance); 3144 if (fcsm == NULL) { 3145 job->job_result = FC_NOMEM; 3146 fcsm_jobdone(job); 3147 return; 3148 } 3149 3150 /* 3151 * Issue the Login command to the management server. 3152 */ 3153 cmd = fcsm_alloc_cmd(fcsm, sizeof (la_els_logi_t), 3154 sizeof (la_els_logi_t), KM_SLEEP); 3155 if (cmd == NULL) { 3156 job->job_result = FC_NOMEM; 3157 fcsm_jobdone(job); 3158 return; 3159 } 3160 3161 FCSM_INIT_CMD(cmd, job, FC_TRAN_INTR | FC_TRAN_CLASS3, FC_PKT_EXCHANGE, 3162 fcsm_max_cmd_retries, fcsm_xlogi_intr); 3163 3164 status = fcsm_xlogi_init(fcsm, cmd, FS_MANAGEMENT_SERVER, 3165 fcsm_pkt_common_intr, LA_ELS_PLOGI); 3166 3167 if (status != FC_SUCCESS) { 3168 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 3169 "job_login_mgmt_server: plogi init failed. status 0x%x", 3170 status)); 3171 job->job_result = status; 3172 fcsm_free_cmd(cmd); 3173 fcsm_jobdone(job); 3174 return; 3175 } 3176 3177 if ((status = fcsm_issue_cmd(cmd)) != FC_SUCCESS) { 3178 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL, 3179 "job_ct_passthru: issue login cmd failed, status 0x%x", 3180 status)); 3181 job->job_result = status; 3182 fcsm_free_cmd(cmd); 3183 fcsm_jobdone(job); 3184 return; 3185 } 3186 } 3187 3188 3189 int 3190 fcsm_ct_passthru(int instance, fcio_t *fcio, int sleep, int job_flags, 3191 void (*func)(fcio_t *)) 3192 { 3193 fcsm_job_t *job; 3194 int status; 3195 3196 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 3197 "ct_passthru: instance 0x%x fcio 0x%p", instance, fcio)); 3198 job = fcsm_alloc_job(sleep); 3199 ASSERT(sleep == KM_NOSLEEP || job != NULL); 3200 3201 fcsm_init_job(job, instance, FCSM_JOB_CT_PASSTHRU, job_flags, 3202 (opaque_t)fcio, (opaque_t)func, fcsm_ct_passthru_comp, NULL); 3203 status = fcsm_process_job(job, 0); 3204 if (status != FC_SUCCESS) { 3205 /* Job could not be issued. So free the job and return */ 3206 fcsm_dealloc_job(job); 3207 return (status); 3208 } 3209 3210 if (job_flags & FCSM_JOBFLAG_SYNC) { 3211 status = job->job_result; 3212 fcsm_dealloc_job(job); 3213 } 3214 3215 return (status); 3216 } 3217 3218 3219 /* ARGSUSED */ 3220 static void 3221 fcsm_ct_passthru_comp(opaque_t comp_arg, fcsm_job_t *job, int result) 3222 { 3223 ASSERT(job != NULL); 3224 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 3225 "ct_passthru_comp: result 0x%x port 0x%x", 3226 job->job_result, job->job_port_instance)); 3227 } 3228 3229 3230 static void 3231 fcsm_pkt_common_intr(fc_packet_t *pkt) 3232 { 3233 fcsm_cmd_t *cmd; 3234 int jobstatus; 3235 fcsm_t *fcsm; 3236 3237 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, NULL, NULL, 3238 "pkt_common_intr")); 3239 3240 cmd = (fcsm_cmd_t *)pkt->pkt_ulp_private; 3241 ASSERT(cmd != NULL); 3242 3243 if (pkt->pkt_state == FC_PKT_SUCCESS) { 3244 /* Command completed successfully. Just complete the command */ 3245 cmd->cmd_comp(cmd); 3246 return; 3247 } 3248 3249 fcsm = cmd->cmd_fcsm; 3250 ASSERT(fcsm != NULL); 3251 3252 fcsm_display(CE_WARN, SM_LOG, cmd->cmd_fcsm, pkt, 3253 "fc packet to DID 0x%x failed for pkt 0x%p", 3254 pkt->pkt_cmd_fhdr.d_id, pkt); 3255 3256 mutex_enter(&fcsm->sm_mutex); 3257 if (fcsm->sm_flags & FCSM_LINK_DOWN) { 3258 /* 3259 * No need to retry the command. The link previously 3260 * suffered an offline timeout. 3261 */ 3262 mutex_exit(&fcsm->sm_mutex); 3263 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL, 3264 "pkt_common_intr: end. Link is down")); 3265 cmd->cmd_comp(cmd); 3266 return; 3267 } 3268 mutex_exit(&fcsm->sm_mutex); 3269 3270 jobstatus = fcsm_pkt_state_to_rval(pkt->pkt_state, pkt->pkt_reason); 3271 if (jobstatus == FC_LOGINREQ) { 3272 /* 3273 * Login to the destination is required. No need to 3274 * retry this cmd again. 3275 */ 3276 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, cmd->cmd_fcsm, NULL, 3277 "pkt_common_intr: end. LOGIN required")); 3278 cmd->cmd_comp(cmd); 3279 return; 3280 } 3281 3282 switch (pkt->pkt_state) { 3283 case FC_PKT_PORT_OFFLINE: 3284 case FC_PKT_LOCAL_RJT: 3285 case FC_PKT_TIMEOUT: { 3286 uchar_t pkt_state; 3287 3288 pkt_state = pkt->pkt_state; 3289 cmd->cmd_retry_interval = fcsm_retry_interval; 3290 if (fcsm_retry_cmd(cmd) != 0) { 3291 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, 3292 cmd->cmd_fcsm, NULL, 3293 "common_intr: max retries(%d) reached, status 0x%x", 3294 cmd->cmd_retry_count)); 3295 3296 /* 3297 * Restore the pkt_state to the actual failure status 3298 * received at the time of pkt completion. 3299 */ 3300 pkt->pkt_state = pkt_state; 3301 pkt->pkt_reason = 0; 3302 cmd->cmd_comp(cmd); 3303 } else { 3304 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, 3305 cmd->cmd_fcsm, NULL, 3306 "pkt_common_intr: retry(%d) on pkt state (0x%x)", 3307 cmd->cmd_retry_count, pkt_state)); 3308 } 3309 break; 3310 } 3311 default: 3312 cmd->cmd_comp(cmd); 3313 break; 3314 } 3315 } 3316 3317 static int 3318 fcsm_issue_cmd(fcsm_cmd_t *cmd) 3319 { 3320 fc_packet_t *pkt; 3321 fcsm_t *fcsm; 3322 int status; 3323 3324 pkt = cmd->cmd_fp_pkt; 3325 fcsm = cmd->cmd_fcsm; 3326 3327 /* Explicitly invalidate this field till fcsm decides to use it */ 3328 pkt->pkt_ulp_rscn_infop = NULL; 3329 3330 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 3331 "issue_cmd: entry")); 3332 3333 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex)); 3334 mutex_enter(&fcsm->sm_mutex); 3335 if (fcsm->sm_flags & FCSM_LINK_DOWN) { 3336 /* 3337 * Update the pkt_state/pkt_reason appropriately. 3338 * Caller of this function can decide whether to call 3339 * 'pkt->pkt_comp' or use the 'status' returned by this func. 3340 */ 3341 mutex_exit(&fcsm->sm_mutex); 3342 pkt->pkt_state = FC_PKT_PORT_OFFLINE; 3343 pkt->pkt_reason = FC_REASON_OFFLINE; 3344 return (FC_OFFLINE); 3345 } 3346 mutex_exit(&fcsm->sm_mutex); 3347 3348 ASSERT(cmd->cmd_transport != NULL); 3349 status = cmd->cmd_transport(fcsm->sm_port_info.port_handle, pkt); 3350 if (status != FC_SUCCESS) { 3351 switch (status) { 3352 case FC_LOGINREQ: 3353 /* 3354 * No need to retry. Return the cause of failure. 3355 * Also update the pkt_state/pkt_reason. Caller of 3356 * this function can decide, whether to call 3357 * 'pkt->pkt_comp' or use the 'status' code returned 3358 * by this function. 3359 */ 3360 pkt->pkt_state = FC_PKT_LOCAL_RJT; 3361 pkt->pkt_reason = FC_REASON_LOGIN_REQUIRED; 3362 break; 3363 3364 case FC_DEVICE_BUSY_NEW_RSCN: 3365 /* 3366 * There was a newer RSCN than what fcsm knows about. 3367 * So, just retry again 3368 */ 3369 cmd->cmd_retry_count = 0; 3370 /*FALLTHROUGH*/ 3371 case FC_OFFLINE: 3372 case FC_STATEC_BUSY: 3373 /* 3374 * TODO: set flag, so that command is retried after 3375 * port is back online. 3376 * FALL Through for now. 3377 */ 3378 3379 case FC_TRAN_BUSY: 3380 case FC_NOMEM: 3381 case FC_DEVICE_BUSY: 3382 cmd->cmd_retry_interval = fcsm_retry_interval; 3383 if (fcsm_retry_cmd(cmd) != 0) { 3384 FCSM_DEBUG(SMDL_TRACE, 3385 (CE_WARN, SM_LOG, fcsm, NULL, 3386 "issue_cmd: max retries (%d) reached", 3387 cmd->cmd_retry_count)); 3388 3389 /* 3390 * status variable is not changed here. 3391 * Return the cause of the original 3392 * cmd_transport failure. 3393 * Update the pkt_state/pkt_reason. Caller 3394 * of this function can decide whether to 3395 * call 'pkt->pkt_comp' or use the 'status' 3396 * code returned by this function. 3397 */ 3398 pkt->pkt_state = FC_PKT_TRAN_BSY; 3399 pkt->pkt_reason = 0; 3400 } else { 3401 FCSM_DEBUG(SMDL_TRACE, 3402 (CE_WARN, SM_LOG, fcsm, NULL, 3403 "issue_cmd: retry (%d) on fc status (0x%x)", 3404 cmd->cmd_retry_count, status)); 3405 3406 status = FC_SUCCESS; 3407 } 3408 break; 3409 3410 default: 3411 FCSM_DEBUG(SMDL_TRACE, (CE_WARN, SM_LOG, fcsm, NULL, 3412 "issue_cmd: failure status 0x%x", status)); 3413 3414 pkt->pkt_state = FC_PKT_TRAN_ERROR; 3415 pkt->pkt_reason = 0; 3416 break; 3417 3418 3419 } 3420 } 3421 3422 return (status); 3423 } 3424 3425 3426 static int 3427 fcsm_retry_cmd(fcsm_cmd_t *cmd) 3428 { 3429 if (cmd->cmd_retry_count < cmd->cmd_max_retries) { 3430 cmd->cmd_retry_count++; 3431 fcsm_enque_cmd(cmd->cmd_fcsm, cmd); 3432 return (0); 3433 } 3434 3435 return (1); 3436 } 3437 3438 static void 3439 fcsm_enque_cmd(fcsm_t *fcsm, fcsm_cmd_t *cmd) 3440 { 3441 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex)); 3442 3443 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "enque_cmd")); 3444 3445 cmd->cmd_next = NULL; 3446 mutex_enter(&fcsm->sm_mutex); 3447 if (fcsm->sm_retry_tail) { 3448 ASSERT(fcsm->sm_retry_head != NULL); 3449 fcsm->sm_retry_tail->cmd_next = cmd; 3450 fcsm->sm_retry_tail = cmd; 3451 } else { 3452 ASSERT(fcsm->sm_retry_tail == NULL); 3453 fcsm->sm_retry_head = fcsm->sm_retry_tail = cmd; 3454 3455 /* Schedule retry thread, if not already running */ 3456 if (fcsm->sm_retry_tid == NULL) { 3457 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 3458 "enque_cmd: schedule retry thread")); 3459 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout, 3460 (caddr_t)fcsm, fcsm_retry_ticks); 3461 } 3462 } 3463 mutex_exit(&fcsm->sm_mutex); 3464 } 3465 3466 3467 static fcsm_cmd_t * 3468 fcsm_deque_cmd(fcsm_t *fcsm) 3469 { 3470 fcsm_cmd_t *cmd; 3471 3472 ASSERT(!MUTEX_HELD(&fcsm->sm_mutex)); 3473 3474 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "deque_cmd")); 3475 3476 mutex_enter(&fcsm->sm_mutex); 3477 if (fcsm->sm_retry_head == NULL) { 3478 ASSERT(fcsm->sm_retry_tail == NULL); 3479 cmd = NULL; 3480 } else { 3481 cmd = fcsm->sm_retry_head; 3482 fcsm->sm_retry_head = cmd->cmd_next; 3483 if (fcsm->sm_retry_head == NULL) { 3484 fcsm->sm_retry_tail = NULL; 3485 } 3486 cmd->cmd_next = NULL; 3487 } 3488 mutex_exit(&fcsm->sm_mutex); 3489 3490 return (cmd); 3491 } 3492 3493 static void 3494 fcsm_retry_timeout(void *handle) 3495 { 3496 fcsm_t *fcsm; 3497 fcsm_cmd_t *curr_tail; 3498 fcsm_cmd_t *cmd; 3499 int done = 0; 3500 int linkdown; 3501 3502 fcsm = (fcsm_t *)handle; 3503 3504 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, "retry_timeout")); 3505 3506 /* 3507 * If retry cmd queue is suspended, then go away. 3508 * This retry thread will be restarted, when cmd queue resumes. 3509 */ 3510 mutex_enter(&fcsm->sm_mutex); 3511 if (fcsm->sm_flags & FCSM_CMD_RETRY_Q_SUSPENDED) { 3512 /* 3513 * Clear the retry_tid, to indicate that this routine is not 3514 * currently being rescheduled. 3515 */ 3516 fcsm->sm_retry_tid = (timeout_id_t)NULL; 3517 mutex_exit(&fcsm->sm_mutex); 3518 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 3519 "retry_timeout: end. No processing. " 3520 "Queue is currently suspended for this instance")); 3521 return; 3522 } 3523 3524 linkdown = (fcsm->sm_flags & FCSM_LINK_DOWN) ? 1 : 0; 3525 3526 /* 3527 * Save the curr_tail, so that we only process the commands 3528 * which are in the queue at this time. 3529 */ 3530 curr_tail = fcsm->sm_retry_tail; 3531 mutex_exit(&fcsm->sm_mutex); 3532 3533 /* 3534 * Check for done flag before dequeing the command. 3535 * Dequeing before checking the done flag will cause a command 3536 * to be lost. 3537 */ 3538 while ((!done) && ((cmd = fcsm_deque_cmd(fcsm)) != NULL)) { 3539 3540 if (cmd == curr_tail) { 3541 done = 1; 3542 } 3543 3544 cmd->cmd_retry_interval -= fcsm_retry_ticker; 3545 3546 if (linkdown) { 3547 fc_packet_t *pkt; 3548 3549 /* 3550 * No need to retry the command. The link has 3551 * suffered an offline timeout. 3552 */ 3553 pkt = cmd->cmd_fp_pkt; 3554 pkt->pkt_state = FC_PKT_PORT_OFFLINE; 3555 pkt->pkt_reason = FC_REASON_OFFLINE; 3556 pkt->pkt_comp(pkt); 3557 continue; 3558 } 3559 3560 if (cmd->cmd_retry_interval <= 0) { 3561 /* Retry the command */ 3562 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 3563 "retry_timeout: issue cmd 0x%p", (void *)cmd)); 3564 if (fcsm_issue_cmd(cmd) != FC_SUCCESS) { 3565 cmd->cmd_fp_pkt->pkt_comp(cmd->cmd_fp_pkt); 3566 } 3567 } else { 3568 /* 3569 * Put the command back on the queue. Retry time 3570 * has not yet reached. 3571 */ 3572 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 3573 "retry_timeout: queue cmd 0x%p", (void *)cmd)); 3574 fcsm_enque_cmd(fcsm, cmd); 3575 } 3576 } 3577 3578 mutex_enter(&fcsm->sm_mutex); 3579 if (fcsm->sm_retry_head) { 3580 /* Activate timer */ 3581 fcsm->sm_retry_tid = timeout(fcsm_retry_timeout, 3582 (caddr_t)fcsm, fcsm_retry_ticks); 3583 FCSM_DEBUG(SMDL_TRACE, (CE_CONT, SM_LOG, fcsm, NULL, 3584 "retry_timeout: retry thread rescheduled")); 3585 } else { 3586 /* 3587 * Reset the tid variable. The first thread which queues the 3588 * command, will restart the timer. 3589 */ 3590 fcsm->sm_retry_tid = (timeout_id_t)NULL; 3591 } 3592 mutex_exit(&fcsm->sm_mutex); 3593 } 3594