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