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