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 (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/conf.h> 26 #include <sys/file.h> 27 #include <sys/ddi.h> 28 #include <sys/sunddi.h> 29 #include <sys/modctl.h> 30 #include <sys/scsi/scsi.h> 31 #include <sys/scsi/impl/scsi_reset_notify.h> 32 #include <sys/disp.h> 33 #include <sys/byteorder.h> 34 #include <sys/varargs.h> 35 #include <sys/atomic.h> 36 #include <sys/sdt.h> 37 38 #include <sys/stmf.h> 39 #include <sys/stmf_ioctl.h> 40 #include <sys/portif.h> 41 #include <sys/fct.h> 42 #include <sys/fctio.h> 43 44 #include "fct_impl.h" 45 #include "discovery.h" 46 47 disc_action_t fct_handle_local_port_event(fct_i_local_port_t *iport); 48 disc_action_t fct_walk_discovery_queue(fct_i_local_port_t *iport); 49 disc_action_t fct_process_els(fct_i_local_port_t *iport, 50 fct_i_remote_port_t *irp); 51 fct_status_t fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt, 52 uint8_t reason, uint8_t expl); 53 disc_action_t fct_link_init_complete(fct_i_local_port_t *iport); 54 fct_status_t fct_complete_previous_li_cmd(fct_i_local_port_t *iport); 55 fct_status_t fct_sol_plogi(fct_i_local_port_t *iport, uint32_t id, 56 fct_cmd_t **ret_ppcmd, int implicit); 57 fct_status_t fct_sol_ct(fct_i_local_port_t *iport, uint32_t id, 58 fct_cmd_t **ret_ppcmd, uint16_t opcode); 59 fct_status_t fct_ns_scr(fct_i_local_port_t *iport, uint32_t id, 60 fct_cmd_t **ret_ppcmd); 61 static disc_action_t fct_check_cmdlist(fct_i_local_port_t *iport); 62 static disc_action_t fct_check_solcmd_queue(fct_i_local_port_t *iport); 63 static void fct_rscn_verify(fct_i_local_port_t *iport, 64 uint8_t *rscn_req_payload, uint32_t rscn_req_size); 65 void fct_gid_cb(fct_i_cmd_t *icmd); 66 67 char *fct_els_names[] = { 0, "LS_RJT", "ACC", "PLOGI", "FLOGI", "LOGO", 68 "ABTX", "RCS", "RES", "RSS", "RSI", "ESTS", 69 "ESTC", "ADVC", "RTV", "RLS", 70 /* 0x10 */ "ECHO", "TEST", "RRQ", "REC", "SRR", 0, 0, 71 0, 0, 0, 0, 0, 0, 0, 0, 0, 72 /* 0x20 */ "PRLI", "PRLO", "SCN", "TPLS", 73 "TPRLO", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 74 /* 0x30 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 75 /* 0x40 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 76 /* 0x50 */ "PDISC", "FDISC", "ADISC", "RNC", "FARP", 77 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 78 /* 0x60 */ "FAN", "RSCN", "SCR", 0, 0, 0, 0, 0, 0, 0, 0, 79 0, 0, 0, 0, 0, 80 /* 0x70 */ "LINIT", "LPC", "LSTS", 0, 0, 0, 0, 0, 81 "RNID", "RLIR", "LIRR", 0, 0, 0, 0, 0 82 }; 83 84 extern uint32_t fct_rscn_options; 85 86 /* 87 * NOTE: if anybody drops the iport_worker_lock then they should not return 88 * DISC_ACTION_NO_WORK. Which also means, dont drop the lock if you have 89 * nothing to do. Or else return DISC_ACTION_RESCAN or DISC_ACTION_DELAY_RESCAN. 90 * But you cannot be infinitly returning those so have some logic to 91 * determine that there is nothing to do without dropping the lock. 92 */ 93 void 94 fct_port_worker(void *arg) 95 { 96 fct_local_port_t *port = (fct_local_port_t *)arg; 97 fct_i_local_port_t *iport = (fct_i_local_port_t *) 98 port->port_fct_private; 99 disc_action_t suggested_action; 100 clock_t dl, short_delay, long_delay; 101 int64_t tmp_delay; 102 103 iport->iport_cmdcheck_clock = ddi_get_lbolt() + 104 drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000); 105 short_delay = drv_usectohz(10000); 106 long_delay = drv_usectohz(1000000); 107 108 stmf_trace(iport->iport_alias, "iport is %p", iport); 109 /* Discovery loop */ 110 mutex_enter(&iport->iport_worker_lock); 111 atomic_or_32(&iport->iport_flags, IPORT_WORKER_RUNNING); 112 while ((iport->iport_flags & IPORT_TERMINATE_WORKER) == 0) { 113 suggested_action = DISC_ACTION_NO_WORK; 114 /* 115 * Local port events are of the highest prioriy 116 */ 117 if (iport->iport_event_head) { 118 suggested_action |= fct_handle_local_port_event(iport); 119 } 120 121 /* 122 * We could post solicited ELSes to discovery queue. 123 * solicited CT will be processed inside fct_check_solcmd_queue 124 */ 125 if (iport->iport_solcmd_queue) { 126 suggested_action |= fct_check_solcmd_queue(iport); 127 } 128 129 /* 130 * All solicited and unsolicited ELS will be handled here 131 */ 132 if (iport->iport_rpwe_head) { 133 suggested_action |= fct_walk_discovery_queue(iport); 134 } 135 136 /* 137 * We only process it when there's no outstanding link init CMD 138 */ 139 if ((iport->iport_link_state == PORT_STATE_LINK_INIT_START) && 140 !(iport->iport_li_state & (LI_STATE_FLAG_CMD_WAITING | 141 LI_STATE_FLAG_NO_LI_YET))) { 142 suggested_action |= fct_process_link_init(iport); 143 } 144 145 /* 146 * We process cmd aborting in the end 147 */ 148 if (iport->iport_abort_queue) { 149 suggested_action |= fct_cmd_terminator(iport); 150 } 151 152 /* 153 * Check cmd max/free 154 */ 155 if (iport->iport_cmdcheck_clock <= ddi_get_lbolt()) { 156 suggested_action |= fct_check_cmdlist(iport); 157 iport->iport_cmdcheck_clock = ddi_get_lbolt() + 158 drv_usectohz(FCT_CMDLIST_CHECK_SECONDS * 1000000); 159 iport->iport_max_active_ncmds = 0; 160 } 161 162 if (iport->iport_offline_prstate != FCT_OPR_DONE) { 163 suggested_action |= fct_handle_port_offline(iport); 164 } 165 166 if (suggested_action & DISC_ACTION_RESCAN) { 167 continue; 168 } else if (suggested_action & DISC_ACTION_DELAY_RESCAN) { 169 /* 170 * This is not very optimum as whoever returned 171 * DISC_ACTION_DELAY_RESCAN must have dropped the lock 172 * and more things might have queued up. But since 173 * we are only doing small delays, it only delays 174 * things by a few ms, which is okey. 175 */ 176 if (suggested_action & DISC_ACTION_USE_SHORT_DELAY) { 177 dl = short_delay; 178 } else { 179 dl = long_delay; 180 } 181 atomic_or_32(&iport->iport_flags, 182 IPORT_WORKER_DOING_TIMEDWAIT); 183 (void) cv_reltimedwait(&iport->iport_worker_cv, 184 &iport->iport_worker_lock, dl, TR_CLOCK_TICK); 185 atomic_and_32(&iport->iport_flags, 186 ~IPORT_WORKER_DOING_TIMEDWAIT); 187 } else { 188 atomic_or_32(&iport->iport_flags, 189 IPORT_WORKER_DOING_WAIT); 190 tmp_delay = (int64_t)(iport->iport_cmdcheck_clock - 191 ddi_get_lbolt()); 192 if (tmp_delay < 0) { 193 tmp_delay = (int64_t)short_delay; 194 } 195 (void) cv_reltimedwait(&iport->iport_worker_cv, 196 &iport->iport_worker_lock, (clock_t)tmp_delay, 197 TR_CLOCK_TICK); 198 atomic_and_32(&iport->iport_flags, 199 ~IPORT_WORKER_DOING_WAIT); 200 } 201 } 202 203 atomic_and_32(&iport->iport_flags, ~IPORT_WORKER_RUNNING); 204 mutex_exit(&iport->iport_worker_lock); 205 } 206 207 static char *topologies[] = { "Unknown", "Direct Pt-to-Pt", "Private Loop", 208 "Unknown", "Unknown", "Fabric Pt-to-Pt", 209 "Public Loop" }; 210 211 void 212 fct_li_to_txt(fct_link_info_t *li, char *topology, char *speed) 213 { 214 uint8_t s = li->port_speed; 215 216 if (li->port_topology > PORT_TOPOLOGY_PUBLIC_LOOP) { 217 (void) sprintf(topology, "Invalid %02x", li->port_topology); 218 } else { 219 (void) strcpy(topology, topologies[li->port_topology]); 220 } 221 222 if ((s == 0) || ((s & 0xf00) != 0) || ((s & (s - 1)) != 0)) { 223 speed[0] = '?'; 224 } else if (s == PORT_SPEED_10G) { 225 speed[0] = '1'; 226 speed[1] = '0'; 227 speed[2] = 'G'; 228 speed[3] = 0; 229 } else { 230 speed[0] = '0' + li->port_speed; 231 speed[1] = 'G'; 232 speed[2] = 0; 233 } 234 } 235 236 /* 237 * discovery lock held. 238 * XXX: Implement command cleanup upon Link down. 239 * XXX: Implement a clean start and FC-GS registrations upon Link up. 240 * 241 * ================ Local Port State Machine ============ 242 * <hba fatal> <Link up>---| 243 * | v 244 * | <Start>--->[LINK_DOWN]--->[LINK_INIT_START]--->[LINK_INIT_DONE] 245 * | ^ ^ ^ | | 246 * | |---| | |--<Link down> |-| |---><Link Reset><--| 247 * | | | v | v 248 * |->[FATAL_CLEANING] [LINK_DOWN_CLEANING]--->[LINK_UP_CLEANING] 249 * ^ 250 * |--<Link up> 251 * ======================================================= 252 * An explicit port_online() is only allowed in LINK_DOWN state. 253 * An explicit port_offline() is only allowed in LINKDOWN and 254 * LINK_INIT_DONE state. 255 */ 256 disc_action_t 257 fct_handle_local_port_event(fct_i_local_port_t *iport) 258 { 259 disc_action_t ret = DISC_ACTION_RESCAN; 260 fct_i_event_t *in; 261 uint16_t old_state, new_state, new_bits; 262 int dqueue_and_free = 1; 263 int retry_implicit_logo = 0; 264 265 if (iport->iport_event_head == NULL) 266 return (DISC_ACTION_NO_WORK); 267 in = iport->iport_event_head; 268 mutex_exit(&iport->iport_worker_lock); 269 270 rw_enter(&iport->iport_lock, RW_WRITER); 271 272 if (in->event_type == FCT_EVENT_LINK_UP) { 273 DTRACE_FC_1(link__up, fct_i_local_port_t, iport); 274 } else if (in->event_type == FCT_EVENT_LINK_DOWN) { 275 DTRACE_FC_1(link__down, fct_i_local_port_t, iport); 276 } 277 278 /* Calculate new state */ 279 new_state = iport->iport_link_state; 280 281 if (in->event_type == FCT_EVENT_LINK_DOWN) { 282 new_state = PORT_STATE_LINK_DOWN_CLEANING; 283 } else if (in->event_type == FCT_EVENT_LINK_UP) { 284 if (iport->iport_link_state == PORT_STATE_LINK_DOWN_CLEANING) 285 new_state = PORT_STATE_LINK_UP_CLEANING; 286 else if (iport->iport_link_state == PORT_STATE_LINK_DOWN) 287 new_state = PORT_STATE_LINK_INIT_START; 288 else { /* This should not happen */ 289 stmf_trace(iport->iport_alias, 290 "Link up received when link state was" 291 "%x, Ignoring...", iport->iport_link_state); 292 } 293 } else if (in->event_type == FCT_I_EVENT_CLEANUP_POLL) { 294 if (!fct_local_port_cleanup_done(iport)) { 295 if (iport->iport_link_cleanup_retry >= 3) { 296 iport->iport_link_cleanup_retry = 0; 297 retry_implicit_logo = 1; 298 } else { 299 iport->iport_link_cleanup_retry++; 300 } 301 dqueue_and_free = 0; 302 ret = DISC_ACTION_DELAY_RESCAN; 303 } else { 304 if (iport->iport_link_state == 305 PORT_STATE_LINK_DOWN_CLEANING) { 306 new_state = PORT_STATE_LINK_DOWN; 307 } else if (iport->iport_link_state == 308 PORT_STATE_LINK_UP_CLEANING) { 309 new_state = PORT_STATE_LINK_INIT_START; 310 } else { /* This should not have happened */ 311 cmn_err(CE_WARN, "port state changed to %x " 312 "during cleanup", iport->iport_link_state); 313 new_state = PORT_STATE_LINK_DOWN; 314 } 315 } 316 } else if (in->event_type == FCT_EVENT_LINK_RESET) { 317 /* Link reset is only allowed when we are Online */ 318 if (iport->iport_link_state & S_LINK_ONLINE) { 319 new_state = PORT_STATE_LINK_UP_CLEANING; 320 } 321 } else if (in->event_type == FCT_I_EVENT_LINK_INIT_DONE) { 322 if (iport->iport_link_state == PORT_STATE_LINK_INIT_START) { 323 new_state = PORT_STATE_LINK_INIT_DONE; 324 iport->iport_li_state = LI_STATE_START; 325 } 326 } else { 327 ASSERT(0); 328 } 329 new_bits = iport->iport_link_state ^ 330 (iport->iport_link_state | new_state); 331 old_state = iport->iport_link_state; 332 iport->iport_link_state = new_state; 333 rw_exit(&iport->iport_lock); 334 335 stmf_trace(iport->iport_alias, "port state change from %x to %x", 336 old_state, new_state); 337 338 if (new_bits & S_PORT_CLEANUP) { 339 (void) fct_implicitly_logo_all(iport, 0); 340 fct_handle_event(iport->iport_port, 341 FCT_I_EVENT_CLEANUP_POLL, 0, 0); 342 } 343 if (retry_implicit_logo) { 344 (void) fct_implicitly_logo_all(iport, 1); 345 } 346 if (new_bits & S_INIT_LINK) { 347 fct_link_info_t *li = &iport->iport_link_info; 348 fct_status_t li_ret; 349 iport->iport_li_state |= LI_STATE_FLAG_NO_LI_YET; 350 bzero(li, sizeof (*li)); 351 if ((li_ret = iport->iport_port->port_get_link_info( 352 iport->iport_port, li)) != FCT_SUCCESS) { 353 stmf_trace(iport->iport_alias, "iport-%p: " 354 "port_get_link_info failed, ret %llx, forcing " 355 "link down.", iport, li_ret); 356 fct_handle_event(iport->iport_port, 357 FCT_EVENT_LINK_DOWN, 0, 0); 358 } else { 359 iport->iport_login_retry = 0; 360 /* This will reset LI_STATE_FLAG_NO_LI_YET */ 361 iport->iport_li_state = LI_STATE_START; 362 atomic_or_32(&iport->iport_flags, 363 IPORT_ALLOW_UNSOL_FLOGI); 364 } 365 fct_log_local_port_event(iport->iport_port, 366 ESC_SUNFC_PORT_ONLINE); 367 } else if (new_bits & S_RCVD_LINK_DOWN) { 368 fct_log_local_port_event(iport->iport_port, 369 ESC_SUNFC_PORT_OFFLINE); 370 } 371 372 mutex_enter(&iport->iport_worker_lock); 373 if (in && dqueue_and_free) { 374 iport->iport_event_head = in->event_next; 375 if (iport->iport_event_head == NULL) 376 iport->iport_event_tail = NULL; 377 kmem_free(in, sizeof (*in)); 378 } 379 return (ret); 380 } 381 382 int 383 fct_lport_has_bigger_wwn(fct_i_local_port_t *iport) 384 { 385 uint8_t *l, *r; 386 int i; 387 uint64_t wl, wr; 388 389 l = iport->iport_port->port_pwwn; 390 r = iport->iport_link_info.port_rpwwn; 391 392 for (i = 0, wl = 0; i < 8; i++) { 393 wl <<= 8; 394 wl |= l[i]; 395 } 396 for (i = 0, wr = 0; i < 8; i++) { 397 wr <<= 8; 398 wr |= r[i]; 399 } 400 401 if (wl > wr) { 402 return (1); 403 } 404 405 return (0); 406 } 407 408 void 409 fct_do_flogi(fct_i_local_port_t *iport) 410 { 411 fct_flogi_xchg_t fx; 412 fct_status_t ret; 413 int force_link_down = 0; 414 int do_retry = 0; 415 416 DTRACE_FC_1(fabric__login__start, fct_i_local_port_t, iport); 417 418 bzero(&fx, sizeof (fx)); 419 fx.fx_op = ELS_OP_FLOGI; 420 if (iport->iport_login_retry == 0) { 421 fx.fx_sec_timeout = 2; 422 } else { 423 fx.fx_sec_timeout = 5; 424 } 425 if (iport->iport_link_info.port_topology & PORT_TOPOLOGY_PRIVATE_LOOP) { 426 fx.fx_sid = iport->iport_link_info.portid & 0xFF; 427 } 428 fx.fx_did = 0xFFFFFE; 429 bcopy(iport->iport_port->port_nwwn, fx.fx_nwwn, 8); 430 bcopy(iport->iport_port->port_pwwn, fx.fx_pwwn, 8); 431 mutex_exit(&iport->iport_worker_lock); 432 ret = iport->iport_port->port_flogi_xchg(iport->iport_port, &fx); 433 mutex_enter(&iport->iport_worker_lock); 434 if (IPORT_FLOGI_DONE(iport)) { 435 /* The unsolicited path finished it. */ 436 goto done; 437 } 438 if (ret == FCT_NOT_FOUND) { 439 if (iport->iport_link_info.port_topology & 440 PORT_TOPOLOGY_PRIVATE_LOOP) { 441 /* This is a private loop. There is no switch. */ 442 iport->iport_link_info.port_no_fct_flogi = 1; 443 goto done; 444 } 445 /* 446 * This is really an error. This means we cannot init the 447 * link. Lets force the link to go down. 448 */ 449 force_link_down = 1; 450 } else if ((ret == FCT_SUCCESS) && (fx.fx_op == ELS_OP_LSRJT)) { 451 if ((fx.fx_rjt_reason == 5) || (fx.fx_rjt_reason == 0xe) || 452 ((fx.fx_rjt_reason == 9) && (fx.fx_rjt_expl == 0x29))) { 453 do_retry = 1; 454 } else { 455 force_link_down = 1; 456 } 457 } else if (ret == STMF_TIMEOUT) { 458 do_retry = 1; 459 } else if (ret != FCT_SUCCESS) { 460 force_link_down = 1; 461 } 462 463 if (do_retry) { 464 iport->iport_login_retry++; 465 if (iport->iport_login_retry >= 5) 466 force_link_down = 1; 467 goto done; 468 } 469 470 if (force_link_down) { 471 stmf_trace(iport->iport_alias, "iport-%p: flogi xchg failed. " 472 "Forcing link down, ret=%llx login_retry=%d ret_op=%d " 473 "reason=%d expl=%d", iport, ret, iport->iport_login_retry, 474 fx.fx_op, fx.fx_rjt_reason, fx.fx_rjt_expl); 475 mutex_exit(&iport->iport_worker_lock); 476 fct_handle_event(iport->iport_port, FCT_EVENT_LINK_DOWN, 0, 0); 477 mutex_enter(&iport->iport_worker_lock); 478 goto done; 479 } 480 481 /* FLOGI succeeded. Update local port state */ 482 ASSERT(fx.fx_op == ELS_OP_ACC); 483 bcopy(fx.fx_nwwn, iport->iport_link_info.port_rnwwn, 8); 484 bcopy(fx.fx_pwwn, iport->iport_link_info.port_rpwwn, 8); 485 if (fx.fx_fport) { 486 iport->iport_link_info.port_topology |= 487 PORT_TOPOLOGY_FABRIC_BIT; 488 iport->iport_link_info.portid = fx.fx_did; 489 } 490 iport->iport_link_info.port_fct_flogi_done = 1; 491 492 done: 493 DTRACE_FC_1(fabric__login__end, 494 fct_i_local_port_t, iport); 495 } 496 497 /* 498 * Called by FCAs to handle unsolicited FLOGIs. 499 */ 500 fct_status_t 501 fct_handle_rcvd_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx) 502 { 503 fct_i_local_port_t *iport; 504 uint32_t t; 505 506 iport = (fct_i_local_port_t *)port->port_fct_private; 507 if ((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) { 508 return (FCT_FAILURE); 509 } 510 511 mutex_enter(&iport->iport_worker_lock); 512 if (((iport->iport_flags & IPORT_ALLOW_UNSOL_FLOGI) == 0) || 513 (iport->iport_link_state != PORT_STATE_LINK_INIT_START) || 514 ((iport->iport_li_state & LI_STATE_MASK) > LI_STATE_N2N_PLOGI)) { 515 mutex_exit(&iport->iport_worker_lock); 516 return (FCT_FAILURE); 517 } 518 519 if (iport->iport_link_info.port_fct_flogi_done == 0) { 520 iport->iport_link_info.port_fct_flogi_done = 1; 521 bcopy(fx->fx_pwwn, iport->iport_link_info.port_rpwwn, 8); 522 bcopy(fx->fx_nwwn, iport->iport_link_info.port_rnwwn, 8); 523 } 524 525 fx->fx_op = ELS_OP_ACC; 526 t = fx->fx_sid; 527 fx->fx_sid = fx->fx_did; 528 fx->fx_did = t; 529 bcopy(iport->iport_port->port_pwwn, fx->fx_pwwn, 8); 530 bcopy(iport->iport_port->port_nwwn, fx->fx_nwwn, 8); 531 mutex_exit(&iport->iport_worker_lock); 532 533 return (FCT_SUCCESS); 534 } 535 536 /* 537 * iport_li_state can only be changed here and local_event 538 */ 539 disc_action_t 540 fct_process_link_init(fct_i_local_port_t *iport) 541 { 542 fct_cmd_t *cmd = NULL; 543 char *pname = NULL; 544 uint8_t elsop = 0; 545 uint16_t ctop = 0; 546 uint32_t wkdid = 0; 547 int implicit = 0; 548 int force_login = 0; 549 disc_action_t ret = DISC_ACTION_RESCAN; 550 fct_link_info_t *li = &iport->iport_link_info; 551 char topo[24], speed[4]; 552 553 ASSERT(MUTEX_HELD(&iport->iport_worker_lock)); 554 555 check_state_again: 556 switch (iport->iport_li_state & LI_STATE_MASK) { 557 case LI_STATE_DO_FLOGI: 558 /* Is FLOGI even needed or already done ? */ 559 if ((iport->iport_link_info.port_no_fct_flogi) || 560 (IPORT_FLOGI_DONE(iport))) { 561 iport->iport_li_state++; 562 goto check_state_again; 563 } 564 fct_do_flogi(iport); 565 break; 566 567 case LI_STATE_FINI_TOPOLOGY: 568 fct_li_to_txt(li, topo, speed); 569 cmn_err(CE_NOTE, "%s LINK UP, portid %x, topology %s," 570 "speed %s", iport->iport_alias, li->portid, 571 topo, speed); 572 if (li->port_topology != 573 iport->iport_link_old_topology) { 574 if (iport->iport_nrps) { 575 /* 576 * rehash it if change from fabric to 577 * none fabric, vice versa 578 */ 579 if ((li->port_topology ^ 580 iport->iport_link_old_topology) & 581 PORT_TOPOLOGY_FABRIC_BIT) { 582 mutex_exit(&iport->iport_worker_lock); 583 fct_rehash(iport); 584 mutex_enter(&iport->iport_worker_lock); 585 } 586 } 587 iport->iport_link_old_topology = li->port_topology; 588 } 589 /* Skip next level if topo is not N2N */ 590 if (li->port_topology != PORT_TOPOLOGY_PT_TO_PT) { 591 iport->iport_li_state += 2; 592 atomic_and_32(&iport->iport_flags, 593 ~IPORT_ALLOW_UNSOL_FLOGI); 594 } else { 595 iport->iport_li_state++; 596 iport->iport_login_retry = 0; 597 iport->iport_li_cmd_timeout = ddi_get_lbolt() + 598 drv_usectohz(25 * 1000000); 599 } 600 goto check_state_again; 601 602 case LI_STATE_N2N_PLOGI: 603 ASSERT(IPORT_FLOGI_DONE(iport)); 604 ASSERT(iport->iport_link_info.port_topology == 605 PORT_TOPOLOGY_PT_TO_PT); 606 if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) { 607 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK; 608 if (iport->iport_li_comp_status != FCT_SUCCESS) { 609 iport->iport_login_retry++; 610 if (iport->iport_login_retry >= 3) { 611 stmf_trace(iport->iport_alias, "Failing" 612 " to PLOGI to remote port in N2N " 613 " ret=%llx, forcing link down", 614 iport->iport_li_comp_status); 615 mutex_exit(&iport->iport_worker_lock); 616 fct_handle_event(iport->iport_port, 617 FCT_EVENT_LINK_DOWN, 0, 0); 618 mutex_enter(&iport->iport_worker_lock); 619 } 620 } 621 } 622 /* Find out if we need to do PLOGI at all */ 623 if (iport->iport_nrps_login) { 624 iport->iport_li_state++; 625 atomic_and_32(&iport->iport_flags, 626 ~IPORT_ALLOW_UNSOL_FLOGI); 627 goto check_state_again; 628 } 629 if ((ddi_get_lbolt() >= iport->iport_li_cmd_timeout) && 630 (!fct_lport_has_bigger_wwn(iport))) { 631 /* Cant wait forever */ 632 stmf_trace(iport->iport_alias, "N2N: Remote port is " 633 "not logging in, forcing from our side"); 634 force_login = 1; 635 } else { 636 force_login = 0; 637 } 638 if (force_login || fct_lport_has_bigger_wwn(iport)) { 639 elsop = ELS_OP_PLOGI; 640 wkdid = 1; 641 iport->iport_link_info.portid = 0xEF; 642 implicit = 0; 643 iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK; 644 } else { 645 ret = DISC_ACTION_DELAY_RESCAN; 646 } 647 break; 648 649 case LI_STATE_DO_FCLOGIN: 650 if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) { 651 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK; 652 if (iport->iport_li_comp_status != FCT_SUCCESS) { 653 /* 654 * Fabric controller login failed. Just skip all 655 * the fabric controller related cmds. 656 */ 657 iport->iport_li_state = LI_STATE_DO_SCR + 1; 658 } else { 659 /* 660 * Good. Now lets go to next state 661 */ 662 iport->iport_li_state++; 663 } 664 goto check_state_again; 665 } 666 if (!IPORT_IN_NS_TOPO(iport)) { 667 iport->iport_li_state = LI_STATE_DO_SCR + 1; 668 goto check_state_again; 669 } 670 671 elsop = ELS_OP_PLOGI; 672 wkdid = FS_FABRIC_CONTROLLER; 673 implicit = 1; 674 675 /* 676 * We want to come back in the same state and check its ret 677 * We can't modify the state here 678 */ 679 iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK; 680 break; 681 682 case LI_STATE_DO_SCR: 683 elsop = ELS_OP_SCR; 684 wkdid = FS_FABRIC_CONTROLLER; 685 686 /* 687 * We dont care about success of this state. Just go to 688 * next state upon completion. 689 */ 690 iport->iport_li_state++; 691 break; 692 693 case LI_STATE_DO_NSLOGIN: 694 if (iport->iport_li_state & LI_STATE_FLAG_CMD_RETCHECK) { 695 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_RETCHECK; 696 if (iport->iport_li_comp_status != FCT_SUCCESS) { 697 iport->iport_li_state = LI_STATE_DO_RSNN + 1; 698 } else { 699 iport->iport_li_state++; 700 } 701 goto check_state_again; 702 } 703 704 if (!IPORT_IN_NS_TOPO(iport)) { 705 iport->iport_li_state = LI_STATE_DO_RSNN + 1; 706 goto check_state_again; 707 } 708 709 elsop = ELS_OP_PLOGI; 710 wkdid = FS_NAME_SERVER; 711 iport->iport_li_state |= LI_STATE_FLAG_CMD_RETCHECK; 712 break; 713 714 /* 715 * CT state 716 */ 717 case LI_STATE_DO_RNN: 718 ctop = NS_RNN_ID; 719 iport->iport_li_state++; 720 break; 721 722 case LI_STATE_DO_RCS: 723 ctop = NS_RCS_ID; 724 iport->iport_li_state++; 725 break; 726 727 case LI_STATE_DO_RFT: 728 ctop = NS_RFT_ID; 729 iport->iport_li_state++; 730 break; 731 732 case LI_STATE_DO_RSPN: 733 /* 734 * Check if we need skip the state 735 */ 736 pname = iport->iport_port->port_sym_port_name != 737 NULL ? iport->iport_port->port_sym_port_name : NULL; 738 if (pname == NULL) { 739 pname = iport->iport_port->port_default_alias != 740 NULL ? iport->iport_port->port_default_alias : NULL; 741 iport->iport_port->port_sym_port_name = pname; 742 } 743 744 if (pname == NULL) { 745 iport->iport_li_state++; 746 goto check_state_again; 747 } 748 749 ctop = NS_RSPN_ID; 750 iport->iport_li_state++; 751 break; 752 753 case LI_STATE_DO_RSNN: 754 ctop = NS_RSNN_NN; 755 iport->iport_li_state++; 756 break; 757 758 case LI_STATE_MAX: 759 mutex_exit(&iport->iport_worker_lock); 760 761 fct_handle_event(iport->iport_port, 762 FCT_I_EVENT_LINK_INIT_DONE, 0, 0); 763 764 mutex_enter(&iport->iport_worker_lock); 765 break; 766 767 default: 768 ASSERT(0); 769 } 770 771 if (elsop != 0) { 772 cmd = fct_create_solels(iport->iport_port, NULL, implicit, 773 elsop, wkdid, fct_link_init_cb); 774 } else if (ctop != 0) { 775 cmd = fct_create_solct(iport->iport_port, NULL, ctop, 776 fct_link_init_cb); 777 } 778 779 if (cmd) { 780 iport->iport_li_state |= LI_STATE_FLAG_CMD_WAITING; 781 mutex_exit(&iport->iport_worker_lock); 782 783 fct_post_to_solcmd_queue(iport->iport_port, cmd); 784 785 mutex_enter(&iport->iport_worker_lock); 786 } 787 788 return (ret); 789 } 790 791 /* 792 * Handles both solicited and unsolicited elses. Can be called inside 793 * interrupt context. 794 */ 795 void 796 fct_handle_els(fct_cmd_t *cmd) 797 { 798 fct_local_port_t *port = cmd->cmd_port; 799 fct_i_local_port_t *iport = 800 (fct_i_local_port_t *)port->port_fct_private; 801 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private; 802 fct_els_t *els = (fct_els_t *)cmd->cmd_specific; 803 fct_remote_port_t *rp; 804 fct_i_remote_port_t *irp; 805 uint16_t cmd_slot; 806 uint8_t op; 807 808 op = els->els_req_payload[0]; 809 icmd->icmd_start_time = ddi_get_lbolt(); 810 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 811 icmd->icmd_flags |= ICMD_KNOWN_TO_FCA; 812 } 813 stmf_trace(iport->iport_alias, "Posting %ssol ELS %x (%s) rp_id=%x" 814 " lp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "", 815 op, FCT_ELS_NAME(op), cmd->cmd_rportid, 816 cmd->cmd_lportid); 817 818 rw_enter(&iport->iport_lock, RW_READER); 819 start_els_posting:; 820 /* Make sure local port is sane */ 821 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) { 822 rw_exit(&iport->iport_lock); 823 stmf_trace(iport->iport_alias, "ELS %x not posted becasue" 824 "port state was %x", els->els_req_payload[0], 825 iport->iport_link_state); 826 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE); 827 return; 828 } 829 830 /* Weed out any bad initiators in case of N2N topology */ 831 if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) && 832 (els->els_req_payload[0] == ELS_OP_PLOGI) && 833 (iport->iport_link_state == PORT_STATE_LINK_INIT_START) && 834 (iport->iport_link_info.port_topology == PORT_TOPOLOGY_PT_TO_PT)) { 835 int state; 836 int killit = 0; 837 838 mutex_enter(&iport->iport_worker_lock); 839 state = iport->iport_li_state & LI_STATE_MASK; 840 /* 841 * We dont allow remote port to plogi in N2N if we have not yet 842 * resolved the topology. 843 */ 844 if (state <= LI_STATE_FINI_TOPOLOGY) { 845 killit = 1; 846 stmf_trace(iport->iport_alias, "port %x is trying to " 847 "PLOGI in N2N topology, While we have not resolved" 848 " the topology. Dropping...", cmd->cmd_rportid); 849 } else if (state <= LI_STATE_N2N_PLOGI) { 850 if (fct_lport_has_bigger_wwn(iport)) { 851 killit = 1; 852 stmf_trace(iport->iport_alias, "port %x is " 853 "trying to PLOGI in N2N topology, even " 854 "though it has smaller PWWN", 855 cmd->cmd_rportid); 856 } else { 857 /* 858 * Remote port is assigning us a PORTID as 859 * a part of PLOGI. 860 */ 861 iport->iport_link_info.portid = 862 cmd->cmd_lportid; 863 } 864 } 865 mutex_exit(&iport->iport_worker_lock); 866 if (killit) { 867 rw_exit(&iport->iport_lock); 868 fct_queue_cmd_for_termination(cmd, 869 FCT_LOCAL_PORT_OFFLINE); 870 return; 871 } 872 } 873 874 /* 875 * For all unsolicited ELSes that are not FLOGIs, our portid 876 * has been established by now. Sometimes port IDs change due to 877 * link resets but remote ports may still send ELSes using the 878 * old IDs. Kill those right here. 879 */ 880 if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) && 881 (els->els_req_payload[0] != ELS_OP_FLOGI)) { 882 if (cmd->cmd_lportid != iport->iport_link_info.portid) { 883 rw_exit(&iport->iport_lock); 884 stmf_trace(iport->iport_alias, "Rcvd %s with " 885 "wrong lportid %x, expecting %x. Killing ELS.", 886 FCT_ELS_NAME(op), cmd->cmd_lportid, 887 iport->iport_link_info.portid); 888 fct_queue_cmd_for_termination(cmd, 889 FCT_NOT_FOUND); 890 return; 891 } 892 } 893 894 /* 895 * We always lookup by portid. port handles are too 896 * unreliable at this stage. 897 */ 898 irp = fct_portid_to_portptr(iport, cmd->cmd_rportid); 899 if (els->els_req_payload[0] == ELS_OP_PLOGI) { 900 if (irp == NULL) { 901 /* drop the lock while we do allocations */ 902 rw_exit(&iport->iport_lock); 903 rp = fct_alloc(FCT_STRUCT_REMOTE_PORT, 904 port->port_fca_rp_private_size, 0); 905 if (rp == NULL) { 906 fct_queue_cmd_for_termination(cmd, 907 FCT_ALLOC_FAILURE); 908 return; 909 } 910 irp = (fct_i_remote_port_t *)rp->rp_fct_private; 911 rw_init(&irp->irp_lock, 0, RW_DRIVER, 0); 912 irp->irp_rp = rp; 913 irp->irp_portid = cmd->cmd_rportid; 914 rp->rp_port = port; 915 rp->rp_id = cmd->cmd_rportid; 916 rp->rp_handle = FCT_HANDLE_NONE; 917 /* 918 * Grab port lock as writer since we are going 919 * to modify the local port struct. 920 */ 921 rw_enter(&iport->iport_lock, RW_WRITER); 922 /* Make sure nobody created the struct except us */ 923 if (fct_portid_to_portptr(iport, cmd->cmd_rportid)) { 924 /* Oh well, free it */ 925 fct_free(rp); 926 } else { 927 fct_queue_rp(iport, irp); 928 } 929 rw_downgrade(&iport->iport_lock); 930 /* Start over becasue we dropped the lock */ 931 goto start_els_posting; 932 } 933 934 /* A PLOGI is by default a logout of previous session */ 935 irp->irp_deregister_timer = ddi_get_lbolt() + 936 drv_usectohz(USEC_DEREG_RP_TIMEOUT); 937 irp->irp_dereg_count = 0; 938 fct_post_to_discovery_queue(iport, irp, NULL); 939 940 /* A PLOGI also invalidates any RSCNs related to this rp */ 941 atomic_inc_32(&irp->irp_rscn_counter); 942 } else { 943 /* 944 * For everything else, we have (or be able to lookup) a 945 * valid port pointer. 946 */ 947 if (irp == NULL) { 948 rw_exit(&iport->iport_lock); 949 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 950 /* XXX Throw a logout to the initiator */ 951 stmf_trace(iport->iport_alias, "ELS %x " 952 "received from %x without a session", 953 els->els_req_payload[0], cmd->cmd_rportid); 954 } else { 955 stmf_trace(iport->iport_alias, "Sending ELS %x " 956 "to %x without a session", 957 els->els_req_payload[0], cmd->cmd_rportid); 958 } 959 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN); 960 return; 961 } 962 } 963 cmd->cmd_rp = rp = irp->irp_rp; 964 965 /* 966 * Lets get a slot for this els 967 */ 968 if (!(icmd->icmd_flags & ICMD_IMPLICIT)) { 969 cmd_slot = fct_alloc_cmd_slot(iport, cmd); 970 if (cmd_slot == FCT_SLOT_EOL) { 971 /* This should not have happened */ 972 rw_exit(&iport->iport_lock); 973 stmf_trace(iport->iport_alias, 974 "ran out of xchg resources"); 975 fct_queue_cmd_for_termination(cmd, 976 FCT_NO_XCHG_RESOURCE); 977 return; 978 } 979 } else { 980 /* 981 * Tell the framework that fct_cmd_free() can decrement the 982 * irp_nonfcp_xchg_count variable. 983 */ 984 atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE); 985 } 986 atomic_inc_16(&irp->irp_nonfcp_xchg_count); 987 988 /* 989 * Grab the remote port lock while we modify the port state. 990 * we should not drop the fca port lock (as a reader) until we 991 * modify the remote port state. 992 */ 993 rw_enter(&irp->irp_lock, RW_WRITER); 994 if ((op == ELS_OP_PLOGI) || (op == ELS_OP_PRLI) || 995 (op == ELS_OP_LOGO) || (op == ELS_OP_PRLO) || 996 (op == ELS_OP_TPRLO)) { 997 uint32_t rf = IRP_PRLI_DONE; 998 if ((op == ELS_OP_PLOGI) || (op == ELS_OP_LOGO)) { 999 rf |= IRP_PLOGI_DONE; 1000 if (irp->irp_flags & IRP_PLOGI_DONE) 1001 atomic_dec_32(&iport->iport_nrps_login); 1002 } 1003 atomic_inc_16(&irp->irp_sa_elses_count); 1004 atomic_and_32(&irp->irp_flags, ~rf); 1005 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING); 1006 } else { 1007 atomic_inc_16(&irp->irp_nsa_elses_count); 1008 } 1009 1010 fct_post_to_discovery_queue(iport, irp, icmd); 1011 1012 rw_exit(&irp->irp_lock); 1013 rw_exit(&iport->iport_lock); 1014 } 1015 1016 /* 1017 * Cleanup I/Os for a rport. ttc is a bit Mask of cmd types to clean. 1018 * No locks held. 1019 */ 1020 int 1021 fct_trigger_rport_cleanup(fct_i_remote_port_t *irp, int ttc) 1022 { 1023 fct_remote_port_t *rp = irp->irp_rp; 1024 fct_local_port_t *port = rp->rp_port; 1025 fct_i_local_port_t *iport = 1026 (fct_i_local_port_t *)port->port_fct_private; 1027 fct_cmd_t *cmd; 1028 fct_i_cmd_t *icmd; 1029 int i; 1030 int ret; 1031 uint16_t total, cleaned, skipped, unhandled; 1032 1033 rw_enter(&iport->iport_lock, RW_WRITER); 1034 rw_enter(&irp->irp_lock, RW_WRITER); 1035 mutex_enter(&iport->iport_worker_lock); 1036 total = port->port_max_xchges - iport->iport_nslots_free; 1037 cleaned = skipped = unhandled = 0; 1038 1039 for (i = 0; i < port->port_max_xchges; i++) { 1040 if (iport->iport_cmd_slots[i].slot_cmd == NULL) 1041 continue; 1042 icmd = iport->iport_cmd_slots[i].slot_cmd; 1043 if (icmd->icmd_flags & ICMD_IN_TRANSITION) { 1044 unhandled++; 1045 continue; 1046 } 1047 1048 if (icmd->icmd_flags & ICMD_CMD_COMPLETE) { 1049 unhandled++; 1050 continue; 1051 } 1052 1053 cmd = icmd->icmd_cmd; 1054 if (cmd->cmd_rp != rp) { 1055 skipped++; 1056 continue; 1057 } 1058 if (cmd->cmd_type & ttc) { 1059 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) 1060 fct_queue_scsi_task_for_termination(cmd, 1061 FCT_ABORTED); 1062 else 1063 fct_q_for_termination_lock_held(iport, icmd, 1064 FCT_ABORTED); 1065 cleaned++; 1066 } else { 1067 skipped++; 1068 } 1069 } 1070 if (((cleaned + skipped) == total) && (unhandled == 0)) { 1071 ret = 1; 1072 } else { 1073 /* 1074 * XXX: handle this situation. 1075 */ 1076 stmf_trace(iport->iport_alias, "Clean up trouble for irp" 1077 " %p, c/s/u/t = %d/%d/%d/%d", irp, cleaned, skipped, 1078 unhandled, total); 1079 ret = 0; 1080 } 1081 if ((cleaned) && IS_WORKER_SLEEPING(iport)) 1082 cv_signal(&iport->iport_worker_cv); 1083 mutex_exit(&iport->iport_worker_lock); 1084 rw_exit(&irp->irp_lock); 1085 rw_exit(&iport->iport_lock); 1086 return (ret); 1087 } 1088 1089 void 1090 fct_dequeue_els(fct_i_remote_port_t *irp) 1091 { 1092 fct_i_cmd_t *icmd; 1093 1094 rw_enter(&irp->irp_lock, RW_WRITER); 1095 icmd = irp->irp_els_list; 1096 irp->irp_els_list = icmd->icmd_next; 1097 atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_IRP_QUEUE); 1098 rw_exit(&irp->irp_lock); 1099 } 1100 1101 fct_status_t 1102 fct_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp, 1103 fct_cmd_t *cmd) 1104 { 1105 fct_status_t ret; 1106 fct_i_local_port_t *iport; 1107 fct_i_remote_port_t *irp; 1108 int i; 1109 char info[FCT_INFO_LEN]; 1110 1111 iport = (fct_i_local_port_t *)port->port_fct_private; 1112 irp = (fct_i_remote_port_t *)rp->rp_fct_private; 1113 1114 if ((ret = port->port_register_remote_port(port, rp, cmd)) != 1115 FCT_SUCCESS) 1116 return (ret); 1117 1118 rw_enter(&iport->iport_lock, RW_WRITER); 1119 rw_enter(&irp->irp_lock, RW_WRITER); 1120 if (rp->rp_handle != FCT_HANDLE_NONE) { 1121 if (rp->rp_handle >= port->port_max_logins) { 1122 (void) snprintf(info, sizeof (info), 1123 "fct_register_remote_port: FCA " 1124 "returned a handle (%d) for portid %x which is " 1125 "out of range (max logins = %d)", rp->rp_handle, 1126 rp->rp_id, port->port_max_logins); 1127 goto hba_fatal_err; 1128 } 1129 if ((iport->iport_rp_slots[rp->rp_handle] != NULL) && 1130 (iport->iport_rp_slots[rp->rp_handle] != irp)) { 1131 fct_i_remote_port_t *t_irp = 1132 iport->iport_rp_slots[rp->rp_handle]; 1133 (void) snprintf(info, sizeof (info), 1134 "fct_register_remote_port: " 1135 "FCA returned a handle %d for portid %x " 1136 "which was already in use for a different " 1137 "portid (%x)", rp->rp_handle, rp->rp_id, 1138 t_irp->irp_rp->rp_id); 1139 goto hba_fatal_err; 1140 } 1141 } else { 1142 /* Pick a handle for this port */ 1143 for (i = 0; i < port->port_max_logins; i++) { 1144 if (iport->iport_rp_slots[i] == NULL) { 1145 break; 1146 } 1147 } 1148 if (i == port->port_max_logins) { 1149 /* This is really pushing it. */ 1150 (void) snprintf(info, sizeof (info), 1151 "fct_register_remote_port " 1152 "Cannot register portid %x because all the " 1153 "handles are used up", rp->rp_id); 1154 goto hba_fatal_err; 1155 } 1156 rp->rp_handle = i; 1157 } 1158 /* By this time rport_handle is valid */ 1159 if ((irp->irp_flags & IRP_HANDLE_OPENED) == 0) { 1160 iport->iport_rp_slots[rp->rp_handle] = irp; 1161 atomic_or_32(&irp->irp_flags, IRP_HANDLE_OPENED); 1162 } 1163 (void) atomic_inc_64_nv(&iport->iport_last_change); 1164 fct_log_remote_port_event(port, ESC_SUNFC_TARGET_ADD, 1165 rp->rp_pwwn, rp->rp_id); 1166 1167 register_rp_done:; 1168 rw_exit(&irp->irp_lock); 1169 rw_exit(&iport->iport_lock); 1170 return (FCT_SUCCESS); 1171 1172 hba_fatal_err:; 1173 rw_exit(&irp->irp_lock); 1174 rw_exit(&iport->iport_lock); 1175 /* 1176 * XXX Throw HBA fatal error event 1177 */ 1178 (void) fct_port_shutdown(iport->iport_port, 1179 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1180 return (FCT_FAILURE); 1181 } 1182 1183 fct_status_t 1184 fct_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp) 1185 { 1186 fct_status_t ret = FCT_SUCCESS; 1187 fct_i_local_port_t *iport = PORT_TO_IPORT(port); 1188 fct_i_remote_port_t *irp = RP_TO_IRP(rp); 1189 1190 if (irp->irp_snn) { 1191 kmem_free(irp->irp_snn, strlen(irp->irp_snn) + 1); 1192 irp->irp_snn = NULL; 1193 } 1194 if (irp->irp_spn) { 1195 kmem_free(irp->irp_spn, strlen(irp->irp_spn) + 1); 1196 irp->irp_spn = NULL; 1197 } 1198 1199 if ((ret = port->port_deregister_remote_port(port, rp)) != 1200 FCT_SUCCESS) { 1201 return (ret); 1202 } 1203 1204 if (irp->irp_flags & IRP_HANDLE_OPENED) { 1205 atomic_and_32(&irp->irp_flags, ~IRP_HANDLE_OPENED); 1206 iport->iport_rp_slots[rp->rp_handle] = NULL; 1207 } 1208 (void) atomic_inc_64_nv(&iport->iport_last_change); 1209 fct_log_remote_port_event(port, ESC_SUNFC_TARGET_REMOVE, 1210 rp->rp_pwwn, rp->rp_id); 1211 1212 return (FCT_SUCCESS); 1213 } 1214 1215 fct_status_t 1216 fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt, uint8_t reason, uint8_t expl) 1217 { 1218 fct_local_port_t *port = (fct_local_port_t *)cmd->cmd_port; 1219 fct_els_t *els = (fct_els_t *)cmd->cmd_specific; 1220 1221 els->els_resp_size = els->els_resp_alloc_size = 8; 1222 els->els_resp_payload = (uint8_t *)kmem_zalloc(8, KM_SLEEP); 1223 els->els_resp_payload[0] = accrjt; 1224 if (accrjt == 1) { 1225 els->els_resp_payload[5] = reason; 1226 els->els_resp_payload[6] = expl; 1227 } else { 1228 els->els_resp_size = 4; 1229 } 1230 1231 return (port->port_send_cmd_response(cmd, 0)); 1232 } 1233 1234 1235 disc_action_t 1236 fct_walk_discovery_queue(fct_i_local_port_t *iport) 1237 { 1238 char info[FCT_INFO_LEN]; 1239 fct_i_remote_port_t **pirp; 1240 fct_i_remote_port_t *prev_irp = NULL; 1241 disc_action_t suggested_action = DISC_ACTION_NO_WORK; 1242 fct_i_remote_port_t *irp_dereg_list = NULL; 1243 fct_i_remote_port_t *irp_cur_item = NULL; 1244 1245 for (pirp = &iport->iport_rpwe_head; *pirp != NULL; ) { 1246 fct_i_remote_port_t *irp = *pirp; 1247 disc_action_t ret = DISC_ACTION_NO_WORK; 1248 int do_deregister = 0; 1249 int irp_deregister_timer = 0; 1250 1251 if (irp->irp_els_list) { 1252 ret |= fct_process_els(iport, irp); 1253 } 1254 1255 irp_deregister_timer = irp->irp_deregister_timer; 1256 if (irp_deregister_timer) { 1257 if (ddi_get_lbolt() >= irp_deregister_timer) { 1258 do_deregister = 1; 1259 } else { 1260 ret |= DISC_ACTION_DELAY_RESCAN; 1261 } 1262 } 1263 suggested_action |= ret; 1264 1265 if (irp->irp_els_list == NULL) { 1266 mutex_exit(&iport->iport_worker_lock); 1267 rw_enter(&iport->iport_lock, RW_WRITER); 1268 rw_enter(&irp->irp_lock, RW_WRITER); 1269 mutex_enter(&iport->iport_worker_lock); 1270 if (irp->irp_els_list == NULL) { 1271 if (!irp_deregister_timer || 1272 (do_deregister && 1273 !irp->irp_sa_elses_count && 1274 !irp->irp_nsa_elses_count && 1275 !irp->irp_fcp_xchg_count && 1276 !irp->irp_nonfcp_xchg_count)) { 1277 /* dequeue irp from discovery queue */ 1278 atomic_and_32(&irp->irp_flags, 1279 ~IRP_IN_DISCOVERY_QUEUE); 1280 *pirp = irp->irp_discovery_next; 1281 if (iport->iport_rpwe_head == NULL) 1282 iport->iport_rpwe_tail = NULL; 1283 else if (irp == iport->iport_rpwe_tail) 1284 iport->iport_rpwe_tail = 1285 prev_irp; 1286 1287 irp->irp_discovery_next = NULL; 1288 if (do_deregister) { 1289 fct_deque_rp(iport, irp); 1290 rw_exit(&irp->irp_lock); 1291 /* queue irp for deregister */ 1292 irp->irp_next = NULL; 1293 if (!irp_dereg_list) { 1294 irp_dereg_list = 1295 irp_cur_item = irp; 1296 } else { 1297 irp_cur_item->irp_next = 1298 irp; 1299 irp_cur_item = irp; 1300 } 1301 } else { 1302 rw_exit(&irp->irp_lock); 1303 } 1304 rw_exit(&iport->iport_lock); 1305 if ((irp = *pirp) == NULL) 1306 break; 1307 } else { 1308 /* 1309 * wait for another scan until 1310 * deregister timeout 1311 */ 1312 rw_exit(&irp->irp_lock); 1313 rw_exit(&iport->iport_lock); 1314 } 1315 } else { 1316 rw_exit(&irp->irp_lock); 1317 rw_exit(&iport->iport_lock); 1318 /* 1319 * When we dropped the lock, 1320 * something went in. 1321 */ 1322 suggested_action |= DISC_ACTION_RESCAN; 1323 } 1324 } 1325 pirp = &(irp->irp_discovery_next); 1326 prev_irp = irp; 1327 } 1328 /* do deregister */ 1329 if (irp_dereg_list) { 1330 fct_i_remote_port_t *irp_next_item; 1331 /* drop the lock */ 1332 mutex_exit(&iport->iport_worker_lock); 1333 1334 for (irp_cur_item = irp_dereg_list; irp_cur_item != NULL; ) { 1335 irp_next_item = irp_cur_item->irp_next; 1336 if (fct_deregister_remote_port(iport->iport_port, 1337 irp_cur_item->irp_rp) == FCT_SUCCESS) { 1338 fct_free(irp_cur_item->irp_rp); 1339 } else if (++irp_cur_item->irp_dereg_count >= 5) { 1340 irp_cur_item->irp_deregister_timer = 0; 1341 irp_cur_item->irp_dereg_count = 0; 1342 1343 /* 1344 * It looks like we can't deregister it in the 1345 * normal way, so we have to use extrem way 1346 */ 1347 (void) snprintf(info, sizeof (info), 1348 "fct_walk_discovery_queue: " 1349 "iport-%p, can't deregister irp-%p after " 1350 "trying 5 times", (void *)iport, 1351 (void *)irp_cur_item); 1352 (void) fct_port_shutdown(iport->iport_port, 1353 STMF_RFLAG_FATAL_ERROR | 1354 STMF_RFLAG_RESET, info); 1355 suggested_action |= DISC_ACTION_RESCAN; 1356 break; 1357 } else { 1358 /* grab the iport_lock */ 1359 rw_enter(&iport->iport_lock, RW_WRITER); 1360 /* recover */ 1361 irp_cur_item->irp_deregister_timer = 1362 ddi_get_lbolt() + 1363 drv_usectohz(USEC_DEREG_RP_INTERVAL); 1364 fct_post_to_discovery_queue(iport, 1365 irp_cur_item, NULL); 1366 fct_queue_rp(iport, irp_cur_item); 1367 rw_exit(&iport->iport_lock); 1368 suggested_action |= DISC_ACTION_DELAY_RESCAN; 1369 } 1370 irp_cur_item = irp_next_item; 1371 } 1372 mutex_enter(&iport->iport_worker_lock); 1373 } 1374 return (suggested_action); 1375 } 1376 1377 disc_action_t 1378 fct_process_plogi(fct_i_cmd_t *icmd) 1379 { 1380 fct_cmd_t *cmd = icmd->icmd_cmd; 1381 fct_remote_port_t *rp = cmd->cmd_rp; 1382 fct_local_port_t *port = cmd->cmd_port; 1383 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1384 port->port_fct_private; 1385 fct_els_t *els = (fct_els_t *) 1386 cmd->cmd_specific; 1387 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1388 rp->rp_fct_private; 1389 uint8_t *p; 1390 fct_status_t ret; 1391 uint8_t cmd_type = cmd->cmd_type; 1392 uint32_t icmd_flags = icmd->icmd_flags; 1393 clock_t end_time; 1394 char info[FCT_INFO_LEN]; 1395 1396 DTRACE_FC_4(rport__login__start, 1397 fct_cmd_t, cmd, 1398 fct_local_port_t, port, 1399 fct_i_remote_port_t, irp, 1400 int, (cmd_type != FCT_CMD_RCVD_ELS)); 1401 1402 /* Drain I/Os */ 1403 if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) { 1404 /* Trigger cleanup if necessary */ 1405 if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) { 1406 stmf_trace(iport->iport_alias, "handling PLOGI rp_id" 1407 " %x. Triggering cleanup", cmd->cmd_rportid); 1408 /* Cleanup everything except elses */ 1409 if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) { 1410 atomic_or_32(&irp->irp_flags, 1411 IRP_SESSION_CLEANUP); 1412 } else { 1413 /* XXX: handle this */ 1414 /* EMPTY */ 1415 } 1416 } 1417 1418 end_time = icmd->icmd_start_time + 1419 drv_usectohz(USEC_ELS_TIMEOUT); 1420 if (ddi_get_lbolt() > end_time) { 1421 (void) snprintf(info, sizeof (info), 1422 "fct_process_plogi: unable to " 1423 "clean up I/O. iport-%p, icmd-%p", (void *)iport, 1424 (void *)icmd); 1425 (void) fct_port_shutdown(iport->iport_port, 1426 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1427 1428 return (DISC_ACTION_DELAY_RESCAN); 1429 } 1430 1431 if ((ddi_get_lbolt() & 0x7f) == 0) { 1432 stmf_trace(iport->iport_alias, "handling" 1433 " PLOGI rp_id %x, waiting for cmds to" 1434 " drain", cmd->cmd_rportid); 1435 } 1436 return (DISC_ACTION_DELAY_RESCAN); 1437 } 1438 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP); 1439 1440 /* Session can only be terminated after all the I/Os have drained */ 1441 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1442 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1443 irp->irp_session); 1444 stmf_free(irp->irp_session); 1445 irp->irp_session = NULL; 1446 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1447 } 1448 1449 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1450 els->els_resp_size = els->els_req_size; 1451 p = els->els_resp_payload = (uint8_t *)kmem_zalloc( 1452 els->els_resp_size, KM_SLEEP); 1453 els->els_resp_alloc_size = els->els_resp_size; 1454 bcopy(els->els_req_payload, p, els->els_resp_size); 1455 p[0] = ELS_OP_ACC; 1456 bcopy(p+20, rp->rp_pwwn, 8); 1457 bcopy(p+28, rp->rp_nwwn, 8); 1458 bcopy(port->port_pwwn, p+20, 8); 1459 bcopy(port->port_nwwn, p+28, 8); 1460 fct_wwn_to_str(rp->rp_pwwn_str, rp->rp_pwwn); 1461 fct_wwn_to_str(rp->rp_nwwn_str, rp->rp_nwwn); 1462 fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn); 1463 fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn); 1464 1465 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id, 1466 rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL); 1467 } 1468 1469 ret = fct_register_remote_port(port, rp, cmd); 1470 fct_dequeue_els(irp); 1471 if ((ret == FCT_SUCCESS) && !(icmd->icmd_flags & ICMD_IMPLICIT)) { 1472 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1473 ret = port->port_send_cmd_response(cmd, 0); 1474 if ((ret == FCT_SUCCESS) && IPORT_IN_NS_TOPO(iport) && 1475 !FC_WELL_KNOWN_ADDR(irp->irp_portid)) { 1476 fct_cmd_t *ct_cmd = fct_create_solct(port, 1477 rp, NS_GSNN_NN, fct_gsnn_cb); 1478 if (ct_cmd) { 1479 fct_post_to_solcmd_queue(port, ct_cmd); 1480 } 1481 ct_cmd = fct_create_solct(port, rp, 1482 NS_GSPN_ID, fct_gspn_cb); 1483 if (ct_cmd) 1484 fct_post_to_solcmd_queue(port, ct_cmd); 1485 ct_cmd = fct_create_solct(port, rp, 1486 NS_GCS_ID, fct_gcs_cb); 1487 if (ct_cmd) 1488 fct_post_to_solcmd_queue(port, ct_cmd); 1489 ct_cmd = fct_create_solct(port, rp, 1490 NS_GFT_ID, fct_gft_cb); 1491 if (ct_cmd) 1492 fct_post_to_solcmd_queue(port, ct_cmd); 1493 } 1494 } else { 1495 /* 1496 * The reason we set this flag is to prevent 1497 * killing a PRLI while we have not yet processed 1498 * a response to PLOGI. Because the initiator 1499 * will send a PRLI as soon as it responds to PLOGI. 1500 * Check fct_process_els() for more info. 1501 */ 1502 atomic_or_32(&irp->irp_flags, 1503 IRP_SOL_PLOGI_IN_PROGRESS); 1504 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 1505 ret = port->port_send_cmd(cmd); 1506 if (ret != FCT_SUCCESS) { 1507 atomic_and_32(&icmd->icmd_flags, 1508 ~ICMD_KNOWN_TO_FCA); 1509 atomic_and_32(&irp->irp_flags, 1510 ~IRP_SOL_PLOGI_IN_PROGRESS); 1511 } 1512 } 1513 } 1514 atomic_dec_16(&irp->irp_sa_elses_count); 1515 1516 if (ret == FCT_SUCCESS) { 1517 if (cmd_type == FCT_CMD_RCVD_ELS) { 1518 atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE); 1519 atomic_inc_32(&iport->iport_nrps_login); 1520 if (irp->irp_deregister_timer) 1521 irp->irp_deregister_timer = 0; 1522 } 1523 if (icmd_flags & ICMD_IMPLICIT) { 1524 DTRACE_FC_5(rport__login__end, 1525 fct_cmd_t, cmd, 1526 fct_local_port_t, port, 1527 fct_i_remote_port_t, irp, 1528 int, (cmd_type != FCT_CMD_RCVD_ELS), 1529 int, FCT_SUCCESS); 1530 1531 p = els->els_resp_payload; 1532 p[0] = ELS_OP_ACC; 1533 cmd->cmd_comp_status = FCT_SUCCESS; 1534 fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE); 1535 } 1536 } else { 1537 DTRACE_FC_5(rport__login__end, 1538 fct_cmd_t, cmd, 1539 fct_local_port_t, port, 1540 fct_i_remote_port_t, irp, 1541 int, (cmd_type != FCT_CMD_RCVD_ELS), 1542 int, ret); 1543 1544 fct_queue_cmd_for_termination(cmd, ret); 1545 } 1546 1547 /* Do not touch cmd here as it may have been freed */ 1548 1549 return (DISC_ACTION_RESCAN); 1550 } 1551 1552 uint8_t fct_prli_temp[] = { 0x20, 0x10, 0, 0x14, 8, 0, 0x20, 0, 0, 0, 0, 0, 1553 0, 0, 0, 0 }; 1554 1555 disc_action_t 1556 fct_process_prli(fct_i_cmd_t *icmd) 1557 { 1558 fct_cmd_t *cmd = icmd->icmd_cmd; 1559 fct_remote_port_t *rp = cmd->cmd_rp; 1560 fct_local_port_t *port = cmd->cmd_port; 1561 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1562 port->port_fct_private; 1563 fct_els_t *els = (fct_els_t *) 1564 cmd->cmd_specific; 1565 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1566 rp->rp_fct_private; 1567 stmf_scsi_session_t *ses = NULL; 1568 fct_status_t ret; 1569 clock_t end_time; 1570 char info[FCT_INFO_LEN]; 1571 1572 /* We dont support solicited PRLIs yet */ 1573 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS); 1574 1575 if (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS) { 1576 /* 1577 * Dont process the PRLI yet. Let the framework process the 1578 * PLOGI completion 1st. This should be very quick because 1579 * the reason we got the PRLI is because the initiator 1580 * has responded to PLOGI already. 1581 */ 1582 /* XXX: Probably need a timeout here */ 1583 return (DISC_ACTION_DELAY_RESCAN); 1584 } 1585 /* The caller has made sure that login is done */ 1586 1587 /* Make sure the process is fcp in this case */ 1588 if ((els->els_req_size != 20) || (bcmp(els->els_req_payload, 1589 fct_prli_temp, 16))) { 1590 if (els->els_req_payload[4] != 0x08) 1591 stmf_trace(iport->iport_alias, "PRLI received from" 1592 " %x for unknown FC-4 type %x", cmd->cmd_rportid, 1593 els->els_req_payload[4]); 1594 else 1595 stmf_trace(iport->iport_alias, "Rejecting PRLI from %x " 1596 " pld sz %d, prli_flags %x", cmd->cmd_rportid, 1597 els->els_req_size, els->els_req_payload[6]); 1598 1599 fct_dequeue_els(irp); 1600 atomic_dec_16(&irp->irp_sa_elses_count); 1601 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0x2c); 1602 goto prli_end; 1603 } 1604 1605 if (irp->irp_fcp_xchg_count) { 1606 /* Trigger cleanup if necessary */ 1607 if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) { 1608 stmf_trace(iport->iport_alias, "handling PRLI from" 1609 " %x. Triggering cleanup", cmd->cmd_rportid); 1610 if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) { 1611 atomic_or_32(&irp->irp_flags, IRP_FCP_CLEANUP); 1612 } else { 1613 /* XXX: handle this */ 1614 /* EMPTY */ 1615 } 1616 } 1617 1618 end_time = icmd->icmd_start_time + 1619 drv_usectohz(USEC_ELS_TIMEOUT); 1620 if (ddi_get_lbolt() > end_time) { 1621 (void) snprintf(info, sizeof (info), 1622 "fct_process_prli: unable to clean " 1623 "up I/O. iport-%p, icmd-%p", (void *)iport, 1624 (void *)icmd); 1625 (void) fct_port_shutdown(iport->iport_port, 1626 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1627 1628 return (DISC_ACTION_DELAY_RESCAN); 1629 } 1630 1631 if ((ddi_get_lbolt() & 0x7f) == 0) { 1632 stmf_trace(iport->iport_alias, "handling" 1633 " PRLI from %x, waiting for cmds to" 1634 " drain", cmd->cmd_rportid); 1635 } 1636 return (DISC_ACTION_DELAY_RESCAN); 1637 } 1638 atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP); 1639 1640 /* Session can only be terminated after all the I/Os have drained */ 1641 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1642 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1643 irp->irp_session); 1644 stmf_free(irp->irp_session); 1645 irp->irp_session = NULL; 1646 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1647 } 1648 1649 /* All good, lets start a session */ 1650 ses = (stmf_scsi_session_t *)stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 0); 1651 if (ses) { 1652 ses->ss_port_private = irp; 1653 ses->ss_rport_id = (scsi_devid_desc_t *)irp->irp_id; 1654 ses->ss_lport = port->port_lport; 1655 if (stmf_register_scsi_session(port->port_lport, ses) != 1656 STMF_SUCCESS) { 1657 stmf_free(ses); 1658 ses = NULL; 1659 } else { 1660 irp->irp_session = ses; 1661 irp->irp_session->ss_rport_alias = irp->irp_snn; 1662 1663 /* 1664 * The reason IRP_SCSI_SESSION_STARTED is different 1665 * from IRP_PRLI_DONE is that we clear IRP_PRLI_DONE 1666 * inside interrupt context. We dont want to deregister 1667 * the session from an interrupt. 1668 */ 1669 atomic_or_32(&irp->irp_flags, IRP_SCSI_SESSION_STARTED); 1670 } 1671 } 1672 1673 fct_dequeue_els(irp); 1674 atomic_dec_16(&irp->irp_sa_elses_count); 1675 if (ses == NULL) { 1676 /* fail PRLI */ 1677 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0); 1678 } else { 1679 /* accept PRLI */ 1680 els->els_resp_payload = (uint8_t *)kmem_zalloc(20, KM_SLEEP); 1681 bcopy(fct_prli_temp, els->els_resp_payload, 20); 1682 els->els_resp_payload[0] = 2; 1683 els->els_resp_payload[6] = 0x21; 1684 1685 /* XXX the two bytes below need to set as per capabilities */ 1686 els->els_resp_payload[18] = 0; 1687 els->els_resp_payload[19] = 0x12; 1688 1689 els->els_resp_size = els->els_resp_alloc_size = 20; 1690 if ((ret = port->port_send_cmd_response(cmd, 0)) != 1691 FCT_SUCCESS) { 1692 stmf_deregister_scsi_session(port->port_lport, ses); 1693 stmf_free(irp->irp_session); 1694 irp->irp_session = NULL; 1695 atomic_and_32(&irp->irp_flags, 1696 ~IRP_SCSI_SESSION_STARTED); 1697 } else { 1698 /* Mark that PRLI is done */ 1699 atomic_or_32(&irp->irp_flags, IRP_PRLI_DONE); 1700 } 1701 } 1702 1703 prli_end:; 1704 if (ret != FCT_SUCCESS) 1705 fct_queue_cmd_for_termination(cmd, ret); 1706 1707 return (DISC_ACTION_RESCAN); 1708 } 1709 1710 disc_action_t 1711 fct_process_logo(fct_i_cmd_t *icmd) 1712 { 1713 fct_cmd_t *cmd = icmd->icmd_cmd; 1714 fct_remote_port_t *rp = cmd->cmd_rp; 1715 fct_local_port_t *port = cmd->cmd_port; 1716 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1717 port->port_fct_private; 1718 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1719 rp->rp_fct_private; 1720 fct_status_t ret; 1721 char info[FCT_INFO_LEN]; 1722 clock_t end_time; 1723 1724 DTRACE_FC_4(rport__logout__start, 1725 fct_cmd_t, cmd, 1726 fct_local_port_t, port, 1727 fct_i_remote_port_t, irp, 1728 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS)); 1729 1730 /* Drain I/Os */ 1731 if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) { 1732 /* Trigger cleanup if necessary */ 1733 if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) { 1734 stmf_trace(iport->iport_alias, "handling LOGO rp_id" 1735 " %x. Triggering cleanup", cmd->cmd_rportid); 1736 /* Cleanup everything except elses */ 1737 if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) { 1738 atomic_or_32(&irp->irp_flags, 1739 IRP_SESSION_CLEANUP); 1740 } else { 1741 /* XXX: need more handling */ 1742 return (DISC_ACTION_DELAY_RESCAN); 1743 } 1744 } 1745 1746 end_time = icmd->icmd_start_time + 1747 drv_usectohz(USEC_ELS_TIMEOUT); 1748 if (ddi_get_lbolt() > end_time) { 1749 (void) snprintf(info, sizeof (info), 1750 "fct_process_logo: unable to clean " 1751 "up I/O. iport-%p, icmd-%p", (void *)iport, 1752 (void *)icmd); 1753 (void) fct_port_shutdown(iport->iport_port, 1754 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1755 1756 return (DISC_ACTION_DELAY_RESCAN); 1757 } 1758 1759 if ((ddi_get_lbolt() & 0x7f) == 0) { 1760 stmf_trace(iport->iport_alias, "handling" 1761 " LOGO rp_id %x, waiting for cmds to" 1762 " drain", cmd->cmd_rportid); 1763 } 1764 return (DISC_ACTION_DELAY_RESCAN); 1765 } 1766 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP); 1767 1768 /* Session can only be terminated after all the I/Os have drained */ 1769 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1770 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1771 irp->irp_session); 1772 stmf_free(irp->irp_session); 1773 irp->irp_session = NULL; 1774 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1775 } 1776 1777 fct_dequeue_els(irp); 1778 atomic_dec_16(&irp->irp_sa_elses_count); 1779 1780 /* don't send response if this is an implicit logout cmd */ 1781 if (!(icmd->icmd_flags & ICMD_IMPLICIT)) { 1782 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1783 ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0); 1784 } else { 1785 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 1786 ret = port->port_send_cmd(cmd); 1787 if (ret != FCT_SUCCESS) { 1788 atomic_and_32(&icmd->icmd_flags, 1789 ~ICMD_KNOWN_TO_FCA); 1790 } 1791 } 1792 1793 if (ret != FCT_SUCCESS) { 1794 fct_queue_cmd_for_termination(cmd, ret); 1795 } 1796 1797 DTRACE_FC_4(rport__logout__end, 1798 fct_cmd_t, cmd, 1799 fct_local_port_t, port, 1800 fct_i_remote_port_t, irp, 1801 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS)); 1802 1803 } else { 1804 DTRACE_FC_4(rport__logout__end, 1805 fct_cmd_t, cmd, 1806 fct_local_port_t, port, 1807 fct_i_remote_port_t, irp, 1808 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS)); 1809 1810 fct_cmd_free(cmd); 1811 } 1812 1813 irp->irp_deregister_timer = ddi_get_lbolt() + 1814 drv_usectohz(USEC_DEREG_RP_TIMEOUT); 1815 irp->irp_dereg_count = 0; 1816 1817 /* Do not touch cmd here as it may have been freed */ 1818 1819 ASSERT(irp->irp_flags & IRP_IN_DISCOVERY_QUEUE); 1820 1821 return (DISC_ACTION_RESCAN); 1822 } 1823 1824 disc_action_t 1825 fct_process_prlo(fct_i_cmd_t *icmd) 1826 { 1827 fct_cmd_t *cmd = icmd->icmd_cmd; 1828 fct_remote_port_t *rp = cmd->cmd_rp; 1829 fct_local_port_t *port = cmd->cmd_port; 1830 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1831 port->port_fct_private; 1832 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1833 rp->rp_fct_private; 1834 fct_status_t ret; 1835 clock_t end_time; 1836 char info[FCT_INFO_LEN]; 1837 1838 /* We do not support solicited PRLOs yet */ 1839 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS); 1840 1841 /* Drain I/Os */ 1842 if (irp->irp_fcp_xchg_count) { 1843 /* Trigger cleanup if necessary */ 1844 if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) { 1845 stmf_trace(iport->iport_alias, "handling LOGO from" 1846 " %x. Triggering cleanup", cmd->cmd_rportid); 1847 /* Cleanup everything except elses */ 1848 if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) { 1849 atomic_or_32(&irp->irp_flags, 1850 IRP_FCP_CLEANUP); 1851 } else { 1852 /* XXX: need more handling */ 1853 return (DISC_ACTION_DELAY_RESCAN); 1854 } 1855 } 1856 1857 end_time = icmd->icmd_start_time + 1858 drv_usectohz(USEC_ELS_TIMEOUT); 1859 if (ddi_get_lbolt() > end_time) { 1860 (void) snprintf(info, sizeof (info), 1861 "fct_process_prlo: unable to " 1862 "clean up I/O. iport-%p, icmd-%p", (void *)iport, 1863 (void *)icmd); 1864 (void) fct_port_shutdown(iport->iport_port, 1865 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1866 1867 return (DISC_ACTION_DELAY_RESCAN); 1868 } 1869 1870 if ((ddi_get_lbolt() & 0x7f) == 0) { 1871 stmf_trace(iport->iport_alias, "handling" 1872 " PRLO from %x, waiting for cmds to" 1873 " drain", cmd->cmd_rportid); 1874 } 1875 return (DISC_ACTION_DELAY_RESCAN); 1876 } 1877 atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP); 1878 1879 /* Session can only be terminated after all the I/Os have drained */ 1880 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1881 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1882 irp->irp_session); 1883 stmf_free(irp->irp_session); 1884 irp->irp_session = NULL; 1885 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1886 } 1887 1888 fct_dequeue_els(irp); 1889 atomic_dec_16(&irp->irp_sa_elses_count); 1890 ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0); 1891 if (ret != FCT_SUCCESS) 1892 fct_queue_cmd_for_termination(cmd, ret); 1893 1894 return (DISC_ACTION_RESCAN); 1895 } 1896 1897 disc_action_t 1898 fct_process_rcvd_adisc(fct_i_cmd_t *icmd) 1899 { 1900 fct_cmd_t *cmd = icmd->icmd_cmd; 1901 fct_remote_port_t *rp = cmd->cmd_rp; 1902 fct_local_port_t *port = cmd->cmd_port; 1903 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1904 port->port_fct_private; 1905 fct_els_t *els = (fct_els_t *) 1906 cmd->cmd_specific; 1907 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1908 rp->rp_fct_private; 1909 uint8_t *p; 1910 uint32_t *q; 1911 fct_status_t ret; 1912 1913 fct_dequeue_els(irp); 1914 atomic_dec_16(&irp->irp_nsa_elses_count); 1915 1916 /* Validate the adisc request */ 1917 p = els->els_req_payload; 1918 q = (uint32_t *)p; 1919 if ((els->els_req_size != 28) || (bcmp(rp->rp_pwwn, p + 8, 8)) || 1920 (bcmp(rp->rp_nwwn, p + 16, 8))) { 1921 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0); 1922 } else { 1923 rp->rp_hard_address = BE_32(q[1]); 1924 els->els_resp_size = els->els_resp_alloc_size = 28; 1925 els->els_resp_payload = (uint8_t *)kmem_zalloc(28, KM_SLEEP); 1926 bcopy(p, els->els_resp_payload, 28); 1927 p = els->els_resp_payload; 1928 q = (uint32_t *)p; 1929 p[0] = ELS_OP_ACC; 1930 q[1] = BE_32(port->port_hard_address); 1931 bcopy(port->port_pwwn, p + 8, 8); 1932 bcopy(port->port_nwwn, p + 16, 8); 1933 q[6] = BE_32(iport->iport_link_info.portid); 1934 ret = port->port_send_cmd_response(cmd, 0); 1935 } 1936 if (ret != FCT_SUCCESS) { 1937 fct_queue_cmd_for_termination(cmd, ret); 1938 } 1939 1940 return (DISC_ACTION_RESCAN); 1941 } 1942 1943 disc_action_t 1944 fct_process_unknown_els(fct_i_cmd_t *icmd) 1945 { 1946 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 1947 fct_status_t ret = FCT_FAILURE; 1948 uint8_t op = 0; 1949 1950 ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS); 1951 fct_dequeue_els(ICMD_TO_IRP(icmd)); 1952 atomic_dec_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count); 1953 op = ICMD_TO_ELS(icmd)->els_req_payload[0]; 1954 stmf_trace(iport->iport_alias, "Rejecting unknown unsol els %x (%s)", 1955 op, FCT_ELS_NAME(op)); 1956 ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_LSRJT, 1, 0); 1957 if (ret != FCT_SUCCESS) { 1958 fct_queue_cmd_for_termination(icmd->icmd_cmd, ret); 1959 } 1960 1961 return (DISC_ACTION_RESCAN); 1962 } 1963 1964 disc_action_t 1965 fct_process_rscn(fct_i_cmd_t *icmd) 1966 { 1967 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 1968 fct_status_t ret = FCT_FAILURE; 1969 uint8_t op = 0; 1970 uint8_t *rscn_req_payload; 1971 uint32_t rscn_req_size; 1972 1973 fct_dequeue_els(ICMD_TO_IRP(icmd)); 1974 atomic_dec_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count); 1975 if (icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1976 op = ICMD_TO_ELS(icmd)->els_req_payload[0]; 1977 stmf_trace(iport->iport_alias, "Accepting RSCN %x (%s)", 1978 op, FCT_ELS_NAME(op)); 1979 rscn_req_size = ICMD_TO_ELS(icmd)->els_req_size; 1980 rscn_req_payload = kmem_alloc(rscn_req_size, KM_SLEEP); 1981 bcopy(ICMD_TO_ELS(icmd)->els_req_payload, rscn_req_payload, 1982 rscn_req_size); 1983 ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_ACC, 1, 0); 1984 if (ret != FCT_SUCCESS) { 1985 fct_queue_cmd_for_termination(icmd->icmd_cmd, ret); 1986 } else { 1987 if (fct_rscn_options & RSCN_OPTION_VERIFY) { 1988 fct_rscn_verify(iport, rscn_req_payload, 1989 rscn_req_size); 1990 } 1991 } 1992 1993 kmem_free(rscn_req_payload, rscn_req_size); 1994 } else { 1995 ASSERT(0); 1996 } 1997 1998 return (DISC_ACTION_RESCAN); 1999 } 2000 2001 disc_action_t 2002 fct_process_els(fct_i_local_port_t *iport, fct_i_remote_port_t *irp) 2003 { 2004 fct_i_cmd_t *cmd_to_abort = NULL; 2005 fct_i_cmd_t **ppcmd, *icmd; 2006 fct_cmd_t *cmd; 2007 fct_els_t *els; 2008 int dq; 2009 disc_action_t ret = DISC_ACTION_NO_WORK; 2010 uint8_t op; 2011 2012 mutex_exit(&iport->iport_worker_lock); 2013 2014 /* 2015 * Do some cleanup based on the following. 2016 * - We can only have one session affecting els pending. 2017 * - If any session affecting els is pending no other els is allowed. 2018 * - If PLOGI is not done, nothing except PLOGI or LOGO is allowed. 2019 * NOTE: If port is down the cleanup is done outside of this 2020 * function. 2021 * NOTE: There is a side effect, if a sa ELS (non PLOGI) is received 2022 * while a PLOGI is pending, it will kill itself and the PLOGI. 2023 * which is probably ok. 2024 */ 2025 rw_enter(&irp->irp_lock, RW_WRITER); 2026 ppcmd = &irp->irp_els_list; 2027 while ((*ppcmd) != NULL) { 2028 int special_prli_cond = 0; 2029 dq = 0; 2030 2031 els = (fct_els_t *)((*ppcmd)->icmd_cmd)->cmd_specific; 2032 2033 if (((*ppcmd)->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) && 2034 (els->els_req_payload[0] == ELS_OP_PRLI) && 2035 (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS)) { 2036 /* 2037 * The initiator sent a PRLI right after responding 2038 * to PLOGI and we have not yet finished processing 2039 * the PLOGI completion. We should not kill the PRLI 2040 * as the initiator may not retry it. 2041 */ 2042 special_prli_cond = 1; 2043 } 2044 2045 if ((*ppcmd)->icmd_flags & ICMD_BEING_ABORTED) { 2046 dq = 1; 2047 } else if (irp->irp_sa_elses_count > 1) { 2048 dq = 1; 2049 /* This els might have set the CLEANUP flag */ 2050 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP); 2051 stmf_trace(iport->iport_alias, "Killing ELS %x cond 1", 2052 els->els_req_payload[0]); 2053 } else if (irp->irp_sa_elses_count && 2054 (((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) == 0)) { 2055 stmf_trace(iport->iport_alias, "Killing ELS %x cond 2", 2056 els->els_req_payload[0]); 2057 dq = 1; 2058 } else if (((irp->irp_flags & IRP_PLOGI_DONE) == 0) && 2059 (els->els_req_payload[0] != ELS_OP_PLOGI) && 2060 (els->els_req_payload[0] != ELS_OP_LOGO) && 2061 (special_prli_cond == 0)) { 2062 stmf_trace(iport->iport_alias, "Killing ELS %x cond 3", 2063 els->els_req_payload[0]); 2064 dq = 1; 2065 } 2066 2067 if (dq) { 2068 fct_i_cmd_t *c = (*ppcmd)->icmd_next; 2069 2070 if ((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) 2071 atomic_dec_16(&irp->irp_sa_elses_count); 2072 else 2073 atomic_dec_16(&irp->irp_nsa_elses_count); 2074 (*ppcmd)->icmd_next = cmd_to_abort; 2075 cmd_to_abort = *ppcmd; 2076 *ppcmd = c; 2077 } else { 2078 ppcmd = &((*ppcmd)->icmd_next); 2079 } 2080 } 2081 rw_exit(&irp->irp_lock); 2082 2083 while (cmd_to_abort) { 2084 fct_i_cmd_t *c = cmd_to_abort->icmd_next; 2085 2086 atomic_and_32(&cmd_to_abort->icmd_flags, ~ICMD_IN_IRP_QUEUE); 2087 fct_queue_cmd_for_termination(cmd_to_abort->icmd_cmd, 2088 FCT_ABORTED); 2089 cmd_to_abort = c; 2090 } 2091 2092 /* 2093 * pick from the top of the queue 2094 */ 2095 icmd = irp->irp_els_list; 2096 if (icmd == NULL) { 2097 /* 2098 * The cleanup took care of everything. 2099 */ 2100 2101 mutex_enter(&iport->iport_worker_lock); 2102 return (DISC_ACTION_RESCAN); 2103 } 2104 2105 cmd = icmd->icmd_cmd; 2106 els = ICMD_TO_ELS(icmd); 2107 op = els->els_req_payload[0]; 2108 if ((icmd->icmd_flags & ICMD_ELS_PROCESSING_STARTED) == 0) { 2109 stmf_trace(iport->iport_alias, "Processing %ssol ELS %x (%s) " 2110 "rp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "", 2111 op, FCT_ELS_NAME(op), cmd->cmd_rportid); 2112 atomic_or_32(&icmd->icmd_flags, ICMD_ELS_PROCESSING_STARTED); 2113 } 2114 2115 if (op == ELS_OP_PLOGI) { 2116 ret |= fct_process_plogi(icmd); 2117 } else if (op == ELS_OP_PRLI) { 2118 ret |= fct_process_prli(icmd); 2119 } else if (op == ELS_OP_LOGO) { 2120 ret |= fct_process_logo(icmd); 2121 } else if ((op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) { 2122 ret |= fct_process_prlo(icmd); 2123 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) { 2124 fct_status_t s; 2125 fct_local_port_t *port = iport->iport_port; 2126 2127 fct_dequeue_els(irp); 2128 atomic_dec_16(&irp->irp_nsa_elses_count); 2129 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 2130 if ((s = port->port_send_cmd(cmd)) != FCT_SUCCESS) { 2131 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA); 2132 fct_queue_cmd_for_termination(cmd, s); 2133 stmf_trace(iport->iport_alias, "Solicited els " 2134 "transport failed, ret = %llx", s); 2135 } 2136 } else if (op == ELS_OP_ADISC) { 2137 ret |= fct_process_rcvd_adisc(icmd); 2138 } else if (op == ELS_OP_RSCN) { 2139 (void) fct_process_rscn(icmd); 2140 } else { 2141 (void) fct_process_unknown_els(icmd); 2142 } 2143 2144 /* 2145 * This if condition will be false if a sa ELS trigged a cleanup 2146 * and set the ret = DISC_ACTION_DELAY_RESCAN. In that case we should 2147 * keep it that way. 2148 */ 2149 if (ret == DISC_ACTION_NO_WORK) { 2150 /* 2151 * Since we dropped the lock, we will force a rescan. The 2152 * only exception is if someone returned 2153 * DISC_ACTION_DELAY_RESCAN, in which case that should be the 2154 * return value. 2155 */ 2156 ret = DISC_ACTION_RESCAN; 2157 } 2158 2159 mutex_enter(&iport->iport_worker_lock); 2160 return (ret); 2161 } 2162 2163 void 2164 fct_handle_sol_els_completion(fct_i_local_port_t *iport, fct_i_cmd_t *icmd) 2165 { 2166 fct_i_remote_port_t *irp = NULL; 2167 fct_els_t *els = ICMD_TO_ELS(icmd); 2168 uint8_t op = els->els_req_payload[0]; 2169 2170 if (icmd->icmd_cmd->cmd_rp) { 2171 irp = ICMD_TO_IRP(icmd); 2172 } 2173 if (icmd->icmd_cmd->cmd_rp && 2174 (icmd->icmd_cmd->cmd_comp_status == FCT_SUCCESS) && 2175 (els->els_req_payload[0] == ELS_OP_PLOGI)) { 2176 bcopy(els->els_resp_payload + 20, irp->irp_rp->rp_pwwn, 8); 2177 bcopy(els->els_resp_payload + 28, irp->irp_rp->rp_nwwn, 8); 2178 2179 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id, 2180 irp->irp_rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL); 2181 atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE); 2182 atomic_inc_32(&iport->iport_nrps_login); 2183 if (irp->irp_deregister_timer) { 2184 irp->irp_deregister_timer = 0; 2185 irp->irp_dereg_count = 0; 2186 } 2187 } 2188 2189 if (irp && (els->els_req_payload[0] == ELS_OP_PLOGI)) { 2190 atomic_and_32(&irp->irp_flags, ~IRP_SOL_PLOGI_IN_PROGRESS); 2191 } 2192 atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE); 2193 stmf_trace(iport->iport_alias, "Sol ELS %x (%s) completed with " 2194 "status %llx, did/%x", op, FCT_ELS_NAME(op), 2195 icmd->icmd_cmd->cmd_comp_status, icmd->icmd_cmd->cmd_rportid); 2196 } 2197 2198 static disc_action_t 2199 fct_check_cmdlist(fct_i_local_port_t *iport) 2200 { 2201 int num_to_release, ndx; 2202 fct_i_cmd_t *icmd; 2203 uint32_t total, max_active; 2204 2205 ASSERT(MUTEX_HELD(&iport->iport_worker_lock)); 2206 2207 total = iport->iport_total_alloced_ncmds; 2208 max_active = iport->iport_max_active_ncmds; 2209 2210 if (total <= max_active) 2211 return (DISC_ACTION_NO_WORK); 2212 /* 2213 * Everytime, we release half of the difference 2214 */ 2215 num_to_release = (total + 1 - max_active) / 2; 2216 2217 mutex_exit(&iport->iport_worker_lock); 2218 for (ndx = 0; ndx < num_to_release; ndx++) { 2219 mutex_enter(&iport->iport_cached_cmd_lock); 2220 icmd = iport->iport_cached_cmdlist; 2221 if (icmd == NULL) { 2222 mutex_exit(&iport->iport_cached_cmd_lock); 2223 break; 2224 } 2225 iport->iport_cached_cmdlist = icmd->icmd_next; 2226 iport->iport_cached_ncmds--; 2227 mutex_exit(&iport->iport_cached_cmd_lock); 2228 atomic_dec_32(&iport->iport_total_alloced_ncmds); 2229 fct_free(icmd->icmd_cmd); 2230 } 2231 mutex_enter(&iport->iport_worker_lock); 2232 return (DISC_ACTION_RESCAN); 2233 } 2234 2235 /* 2236 * The efficiency of handling solicited commands is very low here. But 2237 * fortunately, we seldom send solicited commands. So it will not hurt 2238 * the system performance much. 2239 */ 2240 static disc_action_t 2241 fct_check_solcmd_queue(fct_i_local_port_t *iport) 2242 { 2243 fct_i_cmd_t *icmd = NULL; 2244 fct_i_cmd_t *prev_icmd = NULL; 2245 fct_i_cmd_t *next_icmd = NULL; 2246 2247 ASSERT(mutex_owned(&iport->iport_worker_lock)); 2248 for (icmd = iport->iport_solcmd_queue; icmd; icmd = next_icmd) { 2249 ASSERT(icmd->icmd_flags | ICMD_IN_SOLCMD_QUEUE); 2250 next_icmd = icmd->icmd_solcmd_next; 2251 if (icmd->icmd_flags & ICMD_SOLCMD_NEW) { 2252 /* 2253 * This solicited cmd is new. 2254 * Dispatch ELSes to discovery queue to make use of 2255 * existent framework. 2256 */ 2257 icmd->icmd_flags &= ~ICMD_SOLCMD_NEW; 2258 mutex_exit(&iport->iport_worker_lock); 2259 2260 if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) { 2261 fct_handle_els(icmd->icmd_cmd); 2262 } else { 2263 fct_handle_solct(icmd->icmd_cmd); 2264 } 2265 2266 mutex_enter(&iport->iport_worker_lock); 2267 } else if (icmd->icmd_flags & ICMD_CMD_COMPLETE) { 2268 /* 2269 * To make fct_check_solcmd simple and flexible, 2270 * We need only call callback to finish post-handling. 2271 */ 2272 if (icmd->icmd_cb) { 2273 /* 2274 * mutex ??? 2275 */ 2276 icmd->icmd_cb(icmd); 2277 } 2278 2279 2280 /* 2281 * Release resources for this solicited cmd 2282 */ 2283 if (iport->iport_solcmd_queue == icmd) { 2284 iport->iport_solcmd_queue = next_icmd; 2285 } else { 2286 prev_icmd = iport->iport_solcmd_queue; 2287 while (prev_icmd->icmd_solcmd_next != icmd) { 2288 prev_icmd = prev_icmd->icmd_solcmd_next; 2289 } 2290 prev_icmd->icmd_solcmd_next = next_icmd; 2291 } 2292 2293 icmd->icmd_cb = NULL; 2294 mutex_exit(&iport->iport_worker_lock); 2295 fct_cmd_free(icmd->icmd_cmd); 2296 mutex_enter(&iport->iport_worker_lock); 2297 } else { 2298 /* 2299 * This solicited cmd is still ongoing. 2300 * We need check if it's time to abort this cmd 2301 */ 2302 if (((icmd->icmd_start_time + drv_usectohz( 2303 USEC_SOL_TIMEOUT)) < ddi_get_lbolt()) && 2304 !(icmd->icmd_flags & ICMD_BEING_ABORTED)) { 2305 fct_q_for_termination_lock_held(iport, 2306 icmd, FCT_ABORTED); 2307 } 2308 } 2309 } 2310 2311 return (DISC_ACTION_DELAY_RESCAN); 2312 } 2313 2314 void 2315 fct_handle_solct(fct_cmd_t *cmd) 2316 { 2317 fct_status_t ret = FCT_SUCCESS; 2318 fct_i_cmd_t *icmd = CMD_TO_ICMD(cmd); 2319 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2320 fct_i_remote_port_t *irp = ICMD_TO_IRP(icmd); 2321 2322 ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT); 2323 rw_enter(&iport->iport_lock, RW_READER); 2324 /* 2325 * Let's make sure local port is sane 2326 */ 2327 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) { 2328 rw_exit(&iport->iport_lock); 2329 2330 stmf_trace(iport->iport_alias, "fct_transport_solct: " 2331 "solcmd-%p transport failed, becasue port state was %x", 2332 cmd, iport->iport_link_state); 2333 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE); 2334 return; 2335 } 2336 2337 /* 2338 * Let's make sure we have plogi-ed to name server 2339 */ 2340 rw_enter(&irp->irp_lock, RW_READER); 2341 if (!(irp->irp_flags & IRP_PLOGI_DONE)) { 2342 rw_exit(&irp->irp_lock); 2343 rw_exit(&iport->iport_lock); 2344 2345 stmf_trace(iport->iport_alias, "fct_transport_solct: " 2346 "Must login to name server first - cmd-%p", cmd); 2347 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN); 2348 return; 2349 } 2350 2351 /* 2352 * Let's get a slot for this solcmd 2353 */ 2354 if (fct_alloc_cmd_slot(iport, cmd) == FCT_SLOT_EOL) { 2355 rw_exit(&irp->irp_lock); 2356 rw_exit(&iport->iport_lock); 2357 2358 stmf_trace(iport->iport_alias, "fct_transport_solcmd: " 2359 "ran out of xchg resources - cmd-%p", cmd); 2360 fct_queue_cmd_for_termination(cmd, FCT_NO_XCHG_RESOURCE); 2361 return; 2362 } 2363 2364 if (fct_netbuf_to_value(ICMD_TO_CT(icmd)->ct_req_payload + 8, 2) == 2365 NS_GID_PN) { 2366 fct_i_remote_port_t *query_irp = NULL; 2367 2368 query_irp = fct_lookup_irp_by_portwwn(iport, 2369 ICMD_TO_CT(icmd)->ct_req_payload + 16); 2370 if (query_irp) { 2371 atomic_and_32(&query_irp->irp_flags, ~IRP_RSCN_QUEUED); 2372 } 2373 } 2374 rw_exit(&irp->irp_lock); 2375 rw_exit(&iport->iport_lock); 2376 2377 atomic_inc_16(&irp->irp_nonfcp_xchg_count); 2378 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 2379 icmd->icmd_start_time = ddi_get_lbolt(); 2380 ret = iport->iport_port->port_send_cmd(cmd); 2381 if (ret != FCT_SUCCESS) { 2382 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA); 2383 fct_queue_cmd_for_termination(cmd, ret); 2384 } 2385 } 2386 2387 void 2388 fct_logo_cb(fct_i_cmd_t *icmd) 2389 { 2390 ASSERT(!(icmd->icmd_flags & ICMD_IMPLICIT)); 2391 if (!FCT_IS_ELS_ACC(icmd)) { 2392 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_logo_cb: " 2393 "solicited LOGO is not accepted - icmd/%p", icmd); 2394 } 2395 } 2396 2397 void 2398 fct_gsnn_cb(fct_i_cmd_t *icmd) 2399 { 2400 int snlen = 0; 2401 char *sn = NULL; 2402 fct_i_remote_port_t *query_irp = NULL; 2403 2404 if (!FCT_IS_CT_ACC(icmd)) { 2405 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: " 2406 "GSNN is not accepted by NS - icmd/%p", icmd); 2407 return; 2408 } 2409 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2410 2411 rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER); 2412 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2413 query_irp = fct_lookup_irp_by_nodewwn(ICMD_TO_IPORT(icmd), 2414 ICMD_TO_CT(icmd)->ct_req_payload + 16); 2415 2416 if (!query_irp) { 2417 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: " 2418 "can't get rp icmd-%p", icmd); 2419 goto exit_gsnn_cb; 2420 } else { 2421 snlen = ICMD_TO_CT(icmd)->ct_resp_payload[16]; 2422 } 2423 2424 if (query_irp && snlen) { 2425 /* 2426 * Release previous resource, then allocate needed resource 2427 */ 2428 sn = query_irp->irp_snn; 2429 if (sn) { 2430 kmem_free(sn, strlen(sn) + 1); 2431 } 2432 2433 query_irp->irp_snn = NULL; 2434 sn = kmem_zalloc(snlen + 1, KM_SLEEP); 2435 (void) strncpy(sn, (char *) 2436 ICMD_TO_CT(icmd)->ct_resp_payload + 17, snlen); 2437 if (strlen(sn) != snlen) { 2438 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, 2439 "fct_gsnn_cb: %s, but len=%d", sn, snlen); 2440 kmem_free(sn, snlen + 1); 2441 sn = NULL; 2442 } 2443 2444 /* 2445 * Update symbolic node name 2446 */ 2447 query_irp->irp_snn = sn; 2448 if ((query_irp->irp_flags & IRP_SCSI_SESSION_STARTED) && 2449 (query_irp->irp_session)) { 2450 query_irp->irp_session->ss_rport_alias = 2451 query_irp->irp_snn; 2452 } 2453 } else { 2454 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: " 2455 "irp/%p, snlen/%d", query_irp, snlen); 2456 } 2457 2458 exit_gsnn_cb: 2459 rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock); 2460 } 2461 2462 void 2463 fct_link_init_cb(fct_i_cmd_t *icmd) 2464 { 2465 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2466 2467 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_WAITING; 2468 if (icmd->icmd_cmd->cmd_comp_status != FCT_SUCCESS) { 2469 stmf_trace(iport->iport_alias, "fct_link_init_cb: ELS-%x failed" 2470 "comp_status- %llx", ICMD_TO_ELS(icmd)->els_req_payload[0], 2471 icmd->icmd_cmd->cmd_comp_status); 2472 iport->iport_li_comp_status = icmd->icmd_cmd->cmd_comp_status; 2473 } else if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) { 2474 if (!FCT_IS_ELS_ACC(icmd)) { 2475 stmf_trace(iport->iport_alias, 2476 "fct_link_init_cb: ELS-%x is rejected", 2477 ICMD_TO_ELS(icmd)->els_req_payload[0]); 2478 iport->iport_li_comp_status = FCT_REJECT_STATUS( 2479 ICMD_TO_ELS(icmd)->els_resp_payload[1], 2480 ICMD_TO_ELS(icmd)->els_resp_payload[2]); 2481 } else { 2482 iport->iport_li_comp_status = FCT_SUCCESS; 2483 } 2484 } else { 2485 ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_CT); 2486 if (!FCT_IS_CT_ACC(icmd)) { 2487 stmf_trace(iport->iport_alias, 2488 "fct_link_init_cb: CT-%02x%02x is rejected", 2489 ICMD_TO_CT(icmd)->ct_req_payload[8], 2490 ICMD_TO_CT(icmd)->ct_req_payload[9]); 2491 iport->iport_li_comp_status = FCT_REJECT_STATUS( 2492 ICMD_TO_CT(icmd)->ct_resp_payload[8], 2493 ICMD_TO_CT(icmd)->ct_resp_payload[9]); 2494 } else { 2495 iport->iport_li_comp_status = FCT_SUCCESS; 2496 } 2497 } 2498 } 2499 2500 void 2501 fct_gcs_cb(fct_i_cmd_t *icmd) 2502 { 2503 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 2504 fct_i_remote_port_t *query_irp = NULL; 2505 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2506 uint32_t query_portid; 2507 uint8_t *resp; 2508 uint8_t *req; 2509 2510 if (!FCT_IS_CT_ACC(icmd)) { 2511 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gcs_cb: " 2512 "GCS_ID is not accepted by NS - icmd/%p", icmd); 2513 return; 2514 } 2515 mutex_exit(&iport->iport_worker_lock); 2516 2517 resp = ct->ct_resp_payload; 2518 req = ct->ct_req_payload; 2519 query_portid = (req[17] << 16) | (req[18] << 8) | req[19]; 2520 2521 rw_enter(&iport->iport_lock, RW_READER); 2522 mutex_enter(&iport->iport_worker_lock); 2523 query_irp = fct_portid_to_portptr(iport, query_portid); 2524 2525 if (query_irp) { 2526 query_irp->irp_cos = (resp[16] << 27) | (resp[17] << 18) | 2527 (resp[18] << 8) | resp[19]; 2528 } 2529 rw_exit(&iport->iport_lock); 2530 } 2531 2532 void 2533 fct_gft_cb(fct_i_cmd_t *icmd) 2534 { 2535 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 2536 fct_i_remote_port_t *query_irp = NULL; 2537 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2538 uint32_t query_portid; 2539 uint8_t *resp; 2540 uint8_t *req; 2541 2542 if (!FCT_IS_CT_ACC(icmd)) { 2543 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gft_cb: " 2544 "GFT_ID is not accepted by NS - icmd/%p", icmd); 2545 return; 2546 } 2547 mutex_exit(&iport->iport_worker_lock); 2548 2549 resp = ct->ct_resp_payload; 2550 req = ct->ct_req_payload; 2551 query_portid = (req[17] << 16) | (req[18] << 8) | req[19]; 2552 2553 rw_enter(&iport->iport_lock, RW_READER); 2554 mutex_enter(&iport->iport_worker_lock); 2555 query_irp = fct_portid_to_portptr(iport, query_portid); 2556 2557 if (query_irp) { 2558 (void) memcpy(query_irp->irp_fc4types, resp + 16, 32); 2559 } 2560 rw_exit(&iport->iport_lock); 2561 } 2562 2563 void 2564 fct_gid_cb(fct_i_cmd_t *icmd) 2565 { 2566 fct_cmd_t *cmd = NULL; 2567 fct_i_remote_port_t *query_irp = NULL; 2568 uint32_t nsportid = 0; 2569 int do_logo = 0; 2570 2571 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2572 2573 rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER); 2574 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2575 query_irp = fct_lookup_irp_by_portwwn(ICMD_TO_IPORT(icmd), 2576 ICMD_TO_CT(icmd)->ct_req_payload + 16); 2577 2578 if (!query_irp || (query_irp && 2579 (PTR2INT(icmd->icmd_cb_private, uint32_t) != 2580 query_irp->irp_rscn_counter))) { 2581 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: " 2582 "new RSCN arrived - query_irp/%p, private-%x", query_irp, 2583 PTR2INT(icmd->icmd_cb_private, uint32_t)); 2584 goto exit_gid_cb; 2585 } 2586 2587 if ((query_irp->irp_flags & IRP_RSCN_QUEUED) || 2588 (!(query_irp->irp_flags & IRP_PLOGI_DONE))) { 2589 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: " 2590 "not proper irp_flags - query_irp/%p", query_irp); 2591 goto exit_gid_cb; 2592 } 2593 2594 if (!FCT_IS_CT_ACC(icmd)) { 2595 /* 2596 * Check if it has disappeared 2597 */ 2598 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: " 2599 "GPN_ID is not accepted by NS - icmd/%p", icmd); 2600 do_logo = 1; 2601 } else { 2602 /* 2603 * Check if its portid has changed 2604 */ 2605 nsportid = fct_netbuf_to_value( 2606 ICMD_TO_CT(icmd)->ct_resp_payload + 17, 3); 2607 if (nsportid != query_irp->irp_rp->rp_id) { 2608 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, 2609 "portid has changed - query_irp/%p", query_irp); 2610 do_logo = 1; 2611 } 2612 } 2613 2614 if (do_logo) { 2615 cmd = fct_create_solels(ICMD_TO_PORT(icmd), 2616 query_irp->irp_rp, 1, ELS_OP_LOGO, 0, fct_logo_cb); 2617 if (cmd) { 2618 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2619 fct_post_implicit_logo(cmd); 2620 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2621 } 2622 } 2623 2624 exit_gid_cb: 2625 rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock); 2626 } 2627 2628 void 2629 fct_gspn_cb(fct_i_cmd_t *icmd) 2630 { 2631 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 2632 fct_i_remote_port_t *query_irp = NULL; 2633 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2634 uint32_t query_portid; 2635 uint8_t *resp; 2636 uint8_t *req; 2637 uint8_t spnlen; 2638 2639 if (!FCT_IS_CT_ACC(icmd)) { 2640 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gspn_cb: " 2641 "GSPN_ID is not accepted by NS - icmd/%p", icmd); 2642 return; 2643 } 2644 mutex_exit(&iport->iport_worker_lock); 2645 2646 resp = ct->ct_resp_payload; 2647 req = ct->ct_req_payload; 2648 query_portid = (req[17] << 16) | (req[18] << 8) | req[19]; 2649 2650 rw_enter(&iport->iport_lock, RW_READER); 2651 mutex_enter(&iport->iport_worker_lock); 2652 query_irp = fct_portid_to_portptr(iport, query_portid); 2653 if (query_irp) { 2654 spnlen = resp[16]; 2655 if (spnlen > 0) { 2656 if (query_irp->irp_spn) { 2657 kmem_free(query_irp->irp_spn, 2658 strlen(query_irp->irp_spn) + 1); 2659 } 2660 query_irp->irp_spn = kmem_zalloc(spnlen + 1, KM_SLEEP); 2661 (void) strncpy(query_irp->irp_spn, 2662 (char *)resp + 17, spnlen); 2663 } 2664 } 2665 rw_exit(&iport->iport_lock); 2666 } 2667 2668 void 2669 fct_rls_cb(fct_i_cmd_t *icmd) 2670 { 2671 fct_els_t *els = ICMD_TO_ELS(icmd); 2672 uint8_t *resp; 2673 fct_rls_cb_data_t *rls_cb_data = NULL; 2674 fct_port_link_status_t *rls_resp; 2675 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2676 2677 rls_cb_data = icmd->icmd_cb_private; 2678 2679 if (!FCT_IS_ELS_ACC(icmd)) { 2680 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: " 2681 "solicited RLS is not accepted - icmd/%p", icmd); 2682 if (rls_cb_data) { 2683 rls_cb_data->fct_els_res = FCT_FAILURE; 2684 sema_v(&iport->iport_rls_sema); 2685 } 2686 return; 2687 } 2688 2689 if (!rls_cb_data) { 2690 sema_v(&iport->iport_rls_sema); 2691 return; 2692 } 2693 2694 resp = els->els_resp_payload; 2695 2696 rls_cb_data = icmd->icmd_cb_private; 2697 2698 /* Get the response and store it somewhere */ 2699 rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status; 2700 rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4))); 2701 rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8))); 2702 rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12))); 2703 rls_resp->PrimitiveSeqProtocolErrorCount = 2704 BE_32(*((uint32_t *)(resp + 16))); 2705 rls_resp->InvalidTransmissionWordCount = 2706 BE_32(*((uint32_t *)(resp + 20))); 2707 rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24))); 2708 2709 rls_cb_data->fct_els_res = FCT_SUCCESS; 2710 sema_v(&iport->iport_rls_sema); 2711 icmd->icmd_cb_private = NULL; 2712 } 2713 2714 /* 2715 * For lookup functions, we move locking up one level 2716 */ 2717 fct_i_remote_port_t * 2718 fct_lookup_irp_by_nodewwn(fct_i_local_port_t *iport, uint8_t *nodewwn) 2719 { 2720 fct_i_remote_port_t *irp = NULL; 2721 int idx = 0; 2722 2723 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) { 2724 for (irp = iport->iport_rp_tb[idx]; irp; 2725 irp = irp->irp_next) { 2726 if (bcmp(irp->irp_rp->rp_nwwn, nodewwn, FC_WWN_LEN)) { 2727 continue; 2728 } else { 2729 return (irp); 2730 } 2731 } 2732 } 2733 2734 return (NULL); 2735 } 2736 2737 fct_i_remote_port_t * 2738 fct_lookup_irp_by_portwwn(fct_i_local_port_t *iport, uint8_t *portwwn) 2739 { 2740 fct_i_remote_port_t *irp = NULL; 2741 int idx = 0; 2742 2743 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) { 2744 for (irp = iport->iport_rp_tb[idx]; irp; 2745 irp = irp->irp_next) { 2746 if (bcmp(irp->irp_rp->rp_pwwn, portwwn, FC_WWN_LEN)) { 2747 continue; 2748 } else { 2749 return (irp); 2750 } 2751 } 2752 } 2753 2754 return (NULL); 2755 } 2756 2757 #ifdef lint 2758 #define FCT_VERIFY_RSCN() _NOTE(EMPTY) 2759 #else 2760 #define FCT_VERIFY_RSCN() \ 2761 do { \ 2762 ct_cmd = fct_create_solct(port, irp->irp_rp, NS_GID_PN, \ 2763 fct_gid_cb); \ 2764 if (ct_cmd) { \ 2765 uint32_t cnt; \ 2766 cnt = atomic_inc_32_nv(&irp->irp_rscn_counter); \ 2767 CMD_TO_ICMD(ct_cmd)->icmd_cb_private = \ 2768 INT2PTR(cnt, void *); \ 2769 irp->irp_flags |= IRP_RSCN_QUEUED; \ 2770 fct_post_to_solcmd_queue(port, ct_cmd); \ 2771 } \ 2772 } while (0) 2773 #endif 2774 2775 /* ARGSUSED */ 2776 static void 2777 fct_rscn_verify(fct_i_local_port_t *iport, uint8_t *rscn_req_payload, 2778 uint32_t rscn_req_size) 2779 { 2780 int idx = 0; 2781 uint8_t page_format = 0; 2782 uint32_t page_portid = 0; 2783 uint8_t *page_buf = NULL; 2784 uint8_t *last_page_buf = NULL; 2785 #ifndef lint 2786 fct_cmd_t *ct_cmd = NULL; 2787 fct_local_port_t *port = NULL; 2788 #endif 2789 fct_i_remote_port_t *irp = NULL; 2790 2791 page_buf = rscn_req_payload + 4; 2792 last_page_buf = rscn_req_payload + 2793 fct_netbuf_to_value(rscn_req_payload + 2, 2) - 4; 2794 #ifndef lint 2795 port = iport->iport_port; 2796 #endif 2797 for (; page_buf <= last_page_buf; page_buf += 4) { 2798 page_format = 0x03 & page_buf[0]; 2799 page_portid = fct_netbuf_to_value(page_buf + 1, 3); 2800 2801 DTRACE_FC_2(rscn__receive, 2802 fct_i_local_port_t, iport, 2803 int, page_portid); 2804 2805 rw_enter(&iport->iport_lock, RW_READER); 2806 if (!page_format) { 2807 irp = fct_portid_to_portptr(iport, page_portid); 2808 if (!(irp && !(irp->irp_flags & IRP_RSCN_QUEUED))) { 2809 rw_exit(&iport->iport_lock); 2810 2811 continue; /* try next page */ 2812 } 2813 2814 if (FC_WELL_KNOWN_ADDR(irp->irp_portid) || 2815 !(irp->irp_flags & IRP_PLOGI_DONE)) { 2816 rw_exit(&iport->iport_lock); 2817 2818 continue; /* try next page */ 2819 } 2820 2821 FCT_VERIFY_RSCN(); 2822 } else { 2823 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) { 2824 for (irp = iport->iport_rp_tb[idx]; 2825 irp; irp = irp->irp_next) { 2826 if (FC_WELL_KNOWN_ADDR(irp->irp_portid)) 2827 continue; /* try next irp */ 2828 2829 if (!(irp->irp_flags & IRP_PLOGI_DONE)) 2830 continue; /* try next irp */ 2831 2832 if (irp->irp_flags & IRP_RSCN_QUEUED) { 2833 continue; /* try next irp */ 2834 } 2835 #ifndef lint 2836 if (!((0xFFFFFF << (page_format * 8)) & 2837 (page_portid ^ irp->irp_portid))) { 2838 FCT_VERIFY_RSCN(); 2839 } 2840 #endif 2841 } 2842 } 2843 } 2844 rw_exit(&iport->iport_lock); 2845 } 2846 }