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 #include <sys/conf.h> 27 #include <sys/file.h> 28 #include <sys/ddi.h> 29 #include <sys/sunddi.h> 30 #include <sys/modctl.h> 31 #include <sys/scsi/scsi.h> 32 #include <sys/scsi/impl/scsi_reset_notify.h> 33 #include <sys/disp.h> 34 #include <sys/byteorder.h> 35 #include <sys/varargs.h> 36 #include <sys/atomic.h> 37 #include <sys/sdt.h> 38 39 #include <stmf.h> 40 #include <stmf_ioctl.h> 41 #include <portif.h> 42 #include <fct.h> 43 #include <fct_impl.h> 44 #include <discovery.h> 45 #include <fctio.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_add_32(&irp->irp_rscn_counter, 1); 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_add_16(&irp->irp_nonfcp_xchg_count, 1); 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_add_32(&iport->iport_nrps_login, -1); 1002 } 1003 atomic_add_16(&irp->irp_sa_elses_count, 1); 1004 atomic_and_32(&irp->irp_flags, ~rf); 1005 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING); 1006 } else { 1007 atomic_add_16(&irp->irp_nsa_elses_count, 1); 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[160]; 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, 160, 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 info[159] = 0; 1128 goto hba_fatal_err; 1129 } 1130 if ((iport->iport_rp_slots[rp->rp_handle] != NULL) && 1131 (iport->iport_rp_slots[rp->rp_handle] != irp)) { 1132 fct_i_remote_port_t *t_irp = 1133 iport->iport_rp_slots[rp->rp_handle]; 1134 (void) snprintf(info, 160, "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 info[159] = 0; 1140 goto hba_fatal_err; 1141 } 1142 } else { 1143 /* Pick a handle for this port */ 1144 for (i = 0; i < port->port_max_logins; i++) { 1145 if (iport->iport_rp_slots[i] == NULL) { 1146 break; 1147 } 1148 } 1149 if (i == port->port_max_logins) { 1150 /* This is really pushing it. */ 1151 (void) snprintf(info, 160, "fct_register_remote_port " 1152 "Cannot register portid %x because all the " 1153 "handles are used up", rp->rp_id); 1154 info[159] = 0; 1155 goto hba_fatal_err; 1156 } 1157 rp->rp_handle = i; 1158 } 1159 /* By this time rport_handle is valid */ 1160 if ((irp->irp_flags & IRP_HANDLE_OPENED) == 0) { 1161 iport->iport_rp_slots[rp->rp_handle] = irp; 1162 atomic_or_32(&irp->irp_flags, IRP_HANDLE_OPENED); 1163 } 1164 (void) atomic_add_64_nv(&iport->iport_last_change, 1); 1165 fct_log_remote_port_event(port, ESC_SUNFC_TARGET_ADD, 1166 rp->rp_pwwn, rp->rp_id); 1167 1168 register_rp_done:; 1169 rw_exit(&irp->irp_lock); 1170 rw_exit(&iport->iport_lock); 1171 return (FCT_SUCCESS); 1172 1173 hba_fatal_err:; 1174 rw_exit(&irp->irp_lock); 1175 rw_exit(&iport->iport_lock); 1176 /* 1177 * XXX Throw HBA fatal error event 1178 */ 1179 (void) fct_port_shutdown(iport->iport_port, 1180 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1181 return (FCT_FAILURE); 1182 } 1183 1184 fct_status_t 1185 fct_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp) 1186 { 1187 fct_status_t ret = FCT_SUCCESS; 1188 fct_i_local_port_t *iport = PORT_TO_IPORT(port); 1189 fct_i_remote_port_t *irp = RP_TO_IRP(rp); 1190 1191 if (irp->irp_snn) { 1192 kmem_free(irp->irp_snn, strlen(irp->irp_snn) + 1); 1193 irp->irp_snn = NULL; 1194 } 1195 if (irp->irp_spn) { 1196 kmem_free(irp->irp_spn, strlen(irp->irp_spn) + 1); 1197 irp->irp_spn = NULL; 1198 } 1199 1200 if ((ret = port->port_deregister_remote_port(port, rp)) != 1201 FCT_SUCCESS) { 1202 return (ret); 1203 } 1204 1205 if (irp->irp_flags & IRP_HANDLE_OPENED) { 1206 atomic_and_32(&irp->irp_flags, ~IRP_HANDLE_OPENED); 1207 iport->iport_rp_slots[rp->rp_handle] = NULL; 1208 } 1209 (void) atomic_add_64_nv(&iport->iport_last_change, 1); 1210 fct_log_remote_port_event(port, ESC_SUNFC_TARGET_REMOVE, 1211 rp->rp_pwwn, rp->rp_id); 1212 1213 return (FCT_SUCCESS); 1214 } 1215 1216 fct_status_t 1217 fct_send_accrjt(fct_cmd_t *cmd, uint8_t accrjt, uint8_t reason, uint8_t expl) 1218 { 1219 fct_local_port_t *port = (fct_local_port_t *)cmd->cmd_port; 1220 fct_els_t *els = (fct_els_t *)cmd->cmd_specific; 1221 1222 els->els_resp_size = els->els_resp_alloc_size = 8; 1223 els->els_resp_payload = (uint8_t *)kmem_zalloc(8, KM_SLEEP); 1224 els->els_resp_payload[0] = accrjt; 1225 if (accrjt == 1) { 1226 els->els_resp_payload[5] = reason; 1227 els->els_resp_payload[6] = expl; 1228 } else { 1229 els->els_resp_size = 4; 1230 } 1231 1232 return (port->port_send_cmd_response(cmd, 0)); 1233 } 1234 1235 1236 disc_action_t 1237 fct_walk_discovery_queue(fct_i_local_port_t *iport) 1238 { 1239 char info[80]; 1240 fct_i_remote_port_t **pirp; 1241 fct_i_remote_port_t *prev_irp = NULL; 1242 disc_action_t suggested_action = DISC_ACTION_NO_WORK; 1243 fct_i_remote_port_t *irp_dereg_list = NULL; 1244 fct_i_remote_port_t *irp_cur_item = NULL; 1245 1246 for (pirp = &iport->iport_rpwe_head; *pirp != NULL; ) { 1247 fct_i_remote_port_t *irp = *pirp; 1248 disc_action_t ret = DISC_ACTION_NO_WORK; 1249 int do_deregister = 0; 1250 int irp_deregister_timer = 0; 1251 1252 if (irp->irp_els_list) { 1253 ret |= fct_process_els(iport, irp); 1254 } 1255 1256 irp_deregister_timer = irp->irp_deregister_timer; 1257 if (irp_deregister_timer) { 1258 if (ddi_get_lbolt() >= irp_deregister_timer) { 1259 do_deregister = 1; 1260 } else { 1261 ret |= DISC_ACTION_DELAY_RESCAN; 1262 } 1263 } 1264 suggested_action |= ret; 1265 1266 if (irp->irp_els_list == NULL) { 1267 mutex_exit(&iport->iport_worker_lock); 1268 rw_enter(&iport->iport_lock, RW_WRITER); 1269 rw_enter(&irp->irp_lock, RW_WRITER); 1270 mutex_enter(&iport->iport_worker_lock); 1271 if (irp->irp_els_list == NULL) { 1272 if (!irp_deregister_timer || 1273 (do_deregister && 1274 !irp->irp_sa_elses_count && 1275 !irp->irp_nsa_elses_count && 1276 !irp->irp_fcp_xchg_count && 1277 !irp->irp_nonfcp_xchg_count)) { 1278 /* dequeue irp from discovery queue */ 1279 atomic_and_32(&irp->irp_flags, 1280 ~IRP_IN_DISCOVERY_QUEUE); 1281 *pirp = irp->irp_discovery_next; 1282 if (iport->iport_rpwe_head == NULL) 1283 iport->iport_rpwe_tail = NULL; 1284 else if (irp == iport->iport_rpwe_tail) 1285 iport->iport_rpwe_tail = 1286 prev_irp; 1287 1288 irp->irp_discovery_next = NULL; 1289 if (do_deregister) { 1290 fct_deque_rp(iport, irp); 1291 rw_exit(&irp->irp_lock); 1292 /* queue irp for deregister */ 1293 irp->irp_next = NULL; 1294 if (!irp_dereg_list) { 1295 irp_dereg_list = 1296 irp_cur_item = irp; 1297 } else { 1298 irp_cur_item->irp_next = 1299 irp; 1300 irp_cur_item = irp; 1301 } 1302 } else { 1303 rw_exit(&irp->irp_lock); 1304 } 1305 rw_exit(&iport->iport_lock); 1306 if ((irp = *pirp) == NULL) 1307 break; 1308 } else { 1309 /* 1310 * wait for another scan until 1311 * deregister timeout 1312 */ 1313 rw_exit(&irp->irp_lock); 1314 rw_exit(&iport->iport_lock); 1315 } 1316 } else { 1317 rw_exit(&irp->irp_lock); 1318 rw_exit(&iport->iport_lock); 1319 /* 1320 * When we dropped the lock, 1321 * something went in. 1322 */ 1323 suggested_action |= DISC_ACTION_RESCAN; 1324 } 1325 } 1326 pirp = &(irp->irp_discovery_next); 1327 prev_irp = irp; 1328 } 1329 /* do deregister */ 1330 if (irp_dereg_list) { 1331 fct_i_remote_port_t *irp_next_item; 1332 /* drop the lock */ 1333 mutex_exit(&iport->iport_worker_lock); 1334 1335 for (irp_cur_item = irp_dereg_list; irp_cur_item != NULL; ) { 1336 irp_next_item = irp_cur_item->irp_next; 1337 if (fct_deregister_remote_port(iport->iport_port, 1338 irp_cur_item->irp_rp) == FCT_SUCCESS) { 1339 fct_free(irp_cur_item->irp_rp); 1340 } else if (++irp_cur_item->irp_dereg_count >= 5) { 1341 irp_cur_item->irp_deregister_timer = 0; 1342 irp_cur_item->irp_dereg_count = 0; 1343 1344 /* 1345 * It looks like we can't deregister it in the 1346 * normal way, so we have to use extrem way 1347 */ 1348 (void) snprintf(info, 80, 1349 "fct_walk_discovery_queue: " 1350 "iport-%p, can't deregister irp-%p after " 1351 "trying 5 times", (void *)iport, 1352 (void *)irp_cur_item); 1353 info[79] = 0; 1354 (void) fct_port_shutdown(iport->iport_port, 1355 STMF_RFLAG_FATAL_ERROR | 1356 STMF_RFLAG_RESET, info); 1357 suggested_action |= DISC_ACTION_RESCAN; 1358 break; 1359 } else { 1360 /* grab the iport_lock */ 1361 rw_enter(&iport->iport_lock, RW_WRITER); 1362 /* recover */ 1363 irp_cur_item->irp_deregister_timer = 1364 ddi_get_lbolt() + 1365 drv_usectohz(USEC_DEREG_RP_INTERVAL); 1366 fct_post_to_discovery_queue(iport, 1367 irp_cur_item, NULL); 1368 fct_queue_rp(iport, irp_cur_item); 1369 rw_exit(&iport->iport_lock); 1370 suggested_action |= DISC_ACTION_DELAY_RESCAN; 1371 } 1372 irp_cur_item = irp_next_item; 1373 } 1374 mutex_enter(&iport->iport_worker_lock); 1375 } 1376 return (suggested_action); 1377 } 1378 1379 disc_action_t 1380 fct_process_plogi(fct_i_cmd_t *icmd) 1381 { 1382 fct_cmd_t *cmd = icmd->icmd_cmd; 1383 fct_remote_port_t *rp = cmd->cmd_rp; 1384 fct_local_port_t *port = cmd->cmd_port; 1385 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1386 port->port_fct_private; 1387 fct_els_t *els = (fct_els_t *) 1388 cmd->cmd_specific; 1389 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1390 rp->rp_fct_private; 1391 uint8_t *p; 1392 fct_status_t ret; 1393 uint8_t cmd_type = cmd->cmd_type; 1394 uint32_t icmd_flags = icmd->icmd_flags; 1395 clock_t end_time; 1396 char info[160]; 1397 1398 DTRACE_FC_4(rport__login__start, 1399 fct_cmd_t, cmd, 1400 fct_local_port_t, port, 1401 fct_i_remote_port_t, irp, 1402 int, (cmd_type != FCT_CMD_RCVD_ELS)); 1403 1404 /* Drain I/Os */ 1405 if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) { 1406 /* Trigger cleanup if necessary */ 1407 if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) { 1408 stmf_trace(iport->iport_alias, "handling PLOGI rp_id" 1409 " %x. Triggering cleanup", cmd->cmd_rportid); 1410 /* Cleanup everything except elses */ 1411 if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) { 1412 atomic_or_32(&irp->irp_flags, 1413 IRP_SESSION_CLEANUP); 1414 } else { 1415 /* XXX: handle this */ 1416 /* EMPTY */ 1417 } 1418 } 1419 1420 end_time = icmd->icmd_start_time + 1421 drv_usectohz(USEC_ELS_TIMEOUT); 1422 if (ddi_get_lbolt() > end_time) { 1423 (void) snprintf(info, 160, 1424 "fct_process_plogi: unable to " 1425 "clean up I/O. iport-%p, icmd-%p", (void *)iport, 1426 (void *)icmd); 1427 info[159] = 0; 1428 (void) fct_port_shutdown(iport->iport_port, 1429 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1430 1431 return (DISC_ACTION_DELAY_RESCAN); 1432 } 1433 1434 if ((ddi_get_lbolt() & 0x7f) == 0) { 1435 stmf_trace(iport->iport_alias, "handling" 1436 " PLOGI rp_id %x, waiting for cmds to" 1437 " drain", cmd->cmd_rportid); 1438 } 1439 return (DISC_ACTION_DELAY_RESCAN); 1440 } 1441 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP); 1442 1443 /* Session can only be terminated after all the I/Os have drained */ 1444 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1445 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1446 irp->irp_session); 1447 stmf_free(irp->irp_session); 1448 irp->irp_session = NULL; 1449 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1450 } 1451 1452 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1453 els->els_resp_size = els->els_req_size; 1454 p = els->els_resp_payload = (uint8_t *)kmem_zalloc( 1455 els->els_resp_size, KM_SLEEP); 1456 els->els_resp_alloc_size = els->els_resp_size; 1457 bcopy(els->els_req_payload, p, els->els_resp_size); 1458 p[0] = ELS_OP_ACC; 1459 bcopy(p+20, rp->rp_pwwn, 8); 1460 bcopy(p+28, rp->rp_nwwn, 8); 1461 bcopy(port->port_pwwn, p+20, 8); 1462 bcopy(port->port_nwwn, p+28, 8); 1463 fct_wwn_to_str(rp->rp_pwwn_str, rp->rp_pwwn); 1464 fct_wwn_to_str(rp->rp_nwwn_str, rp->rp_nwwn); 1465 fct_wwn_to_str(port->port_pwwn_str, port->port_pwwn); 1466 fct_wwn_to_str(port->port_nwwn_str, port->port_nwwn); 1467 1468 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id, 1469 rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL); 1470 } 1471 1472 ret = fct_register_remote_port(port, rp, cmd); 1473 fct_dequeue_els(irp); 1474 if ((ret == FCT_SUCCESS) && !(icmd->icmd_flags & ICMD_IMPLICIT)) { 1475 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1476 ret = port->port_send_cmd_response(cmd, 0); 1477 if ((ret == FCT_SUCCESS) && IPORT_IN_NS_TOPO(iport) && 1478 !FC_WELL_KNOWN_ADDR(irp->irp_portid)) { 1479 fct_cmd_t *ct_cmd = fct_create_solct(port, 1480 rp, NS_GSNN_NN, fct_gsnn_cb); 1481 if (ct_cmd) { 1482 fct_post_to_solcmd_queue(port, ct_cmd); 1483 } 1484 ct_cmd = fct_create_solct(port, rp, 1485 NS_GSPN_ID, fct_gspn_cb); 1486 if (ct_cmd) 1487 fct_post_to_solcmd_queue(port, ct_cmd); 1488 ct_cmd = fct_create_solct(port, rp, 1489 NS_GCS_ID, fct_gcs_cb); 1490 if (ct_cmd) 1491 fct_post_to_solcmd_queue(port, ct_cmd); 1492 ct_cmd = fct_create_solct(port, rp, 1493 NS_GFT_ID, fct_gft_cb); 1494 if (ct_cmd) 1495 fct_post_to_solcmd_queue(port, ct_cmd); 1496 } 1497 } else { 1498 /* 1499 * The reason we set this flag is to prevent 1500 * killing a PRLI while we have not yet processed 1501 * a response to PLOGI. Because the initiator 1502 * will send a PRLI as soon as it responds to PLOGI. 1503 * Check fct_process_els() for more info. 1504 */ 1505 atomic_or_32(&irp->irp_flags, 1506 IRP_SOL_PLOGI_IN_PROGRESS); 1507 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 1508 ret = port->port_send_cmd(cmd); 1509 if (ret != FCT_SUCCESS) { 1510 atomic_and_32(&icmd->icmd_flags, 1511 ~ICMD_KNOWN_TO_FCA); 1512 atomic_and_32(&irp->irp_flags, 1513 ~IRP_SOL_PLOGI_IN_PROGRESS); 1514 } 1515 } 1516 } 1517 atomic_add_16(&irp->irp_sa_elses_count, -1); 1518 1519 if (ret == FCT_SUCCESS) { 1520 if (cmd_type == FCT_CMD_RCVD_ELS) { 1521 atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE); 1522 atomic_add_32(&iport->iport_nrps_login, 1); 1523 if (irp->irp_deregister_timer) 1524 irp->irp_deregister_timer = 0; 1525 } 1526 if (icmd_flags & ICMD_IMPLICIT) { 1527 DTRACE_FC_5(rport__login__end, 1528 fct_cmd_t, cmd, 1529 fct_local_port_t, port, 1530 fct_i_remote_port_t, irp, 1531 int, (cmd_type != FCT_CMD_RCVD_ELS), 1532 int, FCT_SUCCESS); 1533 1534 p = els->els_resp_payload; 1535 p[0] = ELS_OP_ACC; 1536 cmd->cmd_comp_status = FCT_SUCCESS; 1537 fct_send_cmd_done(cmd, FCT_SUCCESS, FCT_IOF_FCA_DONE); 1538 } 1539 } else { 1540 DTRACE_FC_5(rport__login__end, 1541 fct_cmd_t, cmd, 1542 fct_local_port_t, port, 1543 fct_i_remote_port_t, irp, 1544 int, (cmd_type != FCT_CMD_RCVD_ELS), 1545 int, ret); 1546 1547 fct_queue_cmd_for_termination(cmd, ret); 1548 } 1549 1550 /* Do not touch cmd here as it may have been freed */ 1551 1552 return (DISC_ACTION_RESCAN); 1553 } 1554 1555 uint8_t fct_prli_temp[] = { 0x20, 0x10, 0, 0x14, 8, 0, 0x20, 0, 0, 0, 0, 0, 1556 0, 0, 0, 0 }; 1557 1558 disc_action_t 1559 fct_process_prli(fct_i_cmd_t *icmd) 1560 { 1561 fct_cmd_t *cmd = icmd->icmd_cmd; 1562 fct_remote_port_t *rp = cmd->cmd_rp; 1563 fct_local_port_t *port = cmd->cmd_port; 1564 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1565 port->port_fct_private; 1566 fct_els_t *els = (fct_els_t *) 1567 cmd->cmd_specific; 1568 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1569 rp->rp_fct_private; 1570 stmf_scsi_session_t *ses = NULL; 1571 fct_status_t ret; 1572 clock_t end_time; 1573 char info[160]; 1574 1575 /* We dont support solicited PRLIs yet */ 1576 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS); 1577 1578 if (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS) { 1579 /* 1580 * Dont process the PRLI yet. Let the framework process the 1581 * PLOGI completion 1st. This should be very quick because 1582 * the reason we got the PRLI is because the initiator 1583 * has responded to PLOGI already. 1584 */ 1585 /* XXX: Probably need a timeout here */ 1586 return (DISC_ACTION_DELAY_RESCAN); 1587 } 1588 /* The caller has made sure that login is done */ 1589 1590 /* Make sure the process is fcp in this case */ 1591 if ((els->els_req_size != 20) || (bcmp(els->els_req_payload, 1592 fct_prli_temp, 16))) { 1593 if (els->els_req_payload[4] != 0x08) 1594 stmf_trace(iport->iport_alias, "PRLI received from" 1595 " %x for unknown FC-4 type %x", cmd->cmd_rportid, 1596 els->els_req_payload[4]); 1597 else 1598 stmf_trace(iport->iport_alias, "Rejecting PRLI from %x " 1599 " pld sz %d, prli_flags %x", cmd->cmd_rportid, 1600 els->els_req_size, els->els_req_payload[6]); 1601 1602 fct_dequeue_els(irp); 1603 atomic_add_16(&irp->irp_sa_elses_count, -1); 1604 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0x2c); 1605 goto prli_end; 1606 } 1607 1608 if (irp->irp_fcp_xchg_count) { 1609 /* Trigger cleanup if necessary */ 1610 if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) { 1611 stmf_trace(iport->iport_alias, "handling PRLI from" 1612 " %x. Triggering cleanup", cmd->cmd_rportid); 1613 if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) { 1614 atomic_or_32(&irp->irp_flags, IRP_FCP_CLEANUP); 1615 } else { 1616 /* XXX: handle this */ 1617 /* EMPTY */ 1618 } 1619 } 1620 1621 end_time = icmd->icmd_start_time + 1622 drv_usectohz(USEC_ELS_TIMEOUT); 1623 if (ddi_get_lbolt() > end_time) { 1624 (void) snprintf(info, 160, 1625 "fct_process_prli: unable to clean " 1626 "up I/O. iport-%p, icmd-%p", (void *)iport, 1627 (void *)icmd); 1628 info[159] = 0; 1629 (void) fct_port_shutdown(iport->iport_port, 1630 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1631 1632 return (DISC_ACTION_DELAY_RESCAN); 1633 } 1634 1635 if ((ddi_get_lbolt() & 0x7f) == 0) { 1636 stmf_trace(iport->iport_alias, "handling" 1637 " PRLI from %x, waiting for cmds to" 1638 " drain", cmd->cmd_rportid); 1639 } 1640 return (DISC_ACTION_DELAY_RESCAN); 1641 } 1642 atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP); 1643 1644 /* Session can only be terminated after all the I/Os have drained */ 1645 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1646 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1647 irp->irp_session); 1648 stmf_free(irp->irp_session); 1649 irp->irp_session = NULL; 1650 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1651 } 1652 1653 /* All good, lets start a session */ 1654 ses = (stmf_scsi_session_t *)stmf_alloc(STMF_STRUCT_SCSI_SESSION, 0, 0); 1655 if (ses) { 1656 ses->ss_port_private = irp; 1657 ses->ss_rport_id = (scsi_devid_desc_t *)irp->irp_id; 1658 ses->ss_lport = port->port_lport; 1659 if (stmf_register_scsi_session(port->port_lport, ses) != 1660 STMF_SUCCESS) { 1661 stmf_free(ses); 1662 ses = NULL; 1663 } else { 1664 irp->irp_session = ses; 1665 irp->irp_session->ss_rport_alias = irp->irp_snn; 1666 1667 /* 1668 * The reason IRP_SCSI_SESSION_STARTED is different 1669 * from IRP_PRLI_DONE is that we clear IRP_PRLI_DONE 1670 * inside interrupt context. We dont want to deregister 1671 * the session from an interrupt. 1672 */ 1673 atomic_or_32(&irp->irp_flags, IRP_SCSI_SESSION_STARTED); 1674 } 1675 } 1676 1677 fct_dequeue_els(irp); 1678 atomic_add_16(&irp->irp_sa_elses_count, -1); 1679 if (ses == NULL) { 1680 /* fail PRLI */ 1681 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0); 1682 } else { 1683 /* accept PRLI */ 1684 els->els_resp_payload = (uint8_t *)kmem_zalloc(20, KM_SLEEP); 1685 bcopy(fct_prli_temp, els->els_resp_payload, 20); 1686 els->els_resp_payload[0] = 2; 1687 els->els_resp_payload[6] = 0x21; 1688 1689 /* XXX the two bytes below need to set as per capabilities */ 1690 els->els_resp_payload[18] = 0; 1691 els->els_resp_payload[19] = 0x12; 1692 1693 els->els_resp_size = els->els_resp_alloc_size = 20; 1694 if ((ret = port->port_send_cmd_response(cmd, 0)) != 1695 FCT_SUCCESS) { 1696 stmf_deregister_scsi_session(port->port_lport, ses); 1697 stmf_free(irp->irp_session); 1698 irp->irp_session = NULL; 1699 atomic_and_32(&irp->irp_flags, 1700 ~IRP_SCSI_SESSION_STARTED); 1701 } else { 1702 /* Mark that PRLI is done */ 1703 atomic_or_32(&irp->irp_flags, IRP_PRLI_DONE); 1704 } 1705 } 1706 1707 prli_end:; 1708 if (ret != FCT_SUCCESS) 1709 fct_queue_cmd_for_termination(cmd, ret); 1710 1711 return (DISC_ACTION_RESCAN); 1712 } 1713 1714 disc_action_t 1715 fct_process_logo(fct_i_cmd_t *icmd) 1716 { 1717 fct_cmd_t *cmd = icmd->icmd_cmd; 1718 fct_remote_port_t *rp = cmd->cmd_rp; 1719 fct_local_port_t *port = cmd->cmd_port; 1720 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1721 port->port_fct_private; 1722 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1723 rp->rp_fct_private; 1724 fct_status_t ret; 1725 char info[160]; 1726 clock_t end_time; 1727 1728 DTRACE_FC_4(rport__logout__start, 1729 fct_cmd_t, cmd, 1730 fct_local_port_t, port, 1731 fct_i_remote_port_t, irp, 1732 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS)); 1733 1734 /* Drain I/Os */ 1735 if ((irp->irp_nonfcp_xchg_count + irp->irp_fcp_xchg_count) > 1) { 1736 /* Trigger cleanup if necessary */ 1737 if ((irp->irp_flags & IRP_SESSION_CLEANUP) == 0) { 1738 stmf_trace(iport->iport_alias, "handling LOGO rp_id" 1739 " %x. Triggering cleanup", cmd->cmd_rportid); 1740 /* Cleanup everything except elses */ 1741 if (fct_trigger_rport_cleanup(irp, ~(cmd->cmd_type))) { 1742 atomic_or_32(&irp->irp_flags, 1743 IRP_SESSION_CLEANUP); 1744 } else { 1745 /* XXX: need more handling */ 1746 return (DISC_ACTION_DELAY_RESCAN); 1747 } 1748 } 1749 1750 end_time = icmd->icmd_start_time + 1751 drv_usectohz(USEC_ELS_TIMEOUT); 1752 if (ddi_get_lbolt() > end_time) { 1753 (void) snprintf(info, 160, 1754 "fct_process_logo: unable to clean " 1755 "up I/O. iport-%p, icmd-%p", (void *)iport, 1756 (void *)icmd); 1757 info[159] = 0; 1758 (void) fct_port_shutdown(iport->iport_port, 1759 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1760 1761 return (DISC_ACTION_DELAY_RESCAN); 1762 } 1763 1764 if ((ddi_get_lbolt() & 0x7f) == 0) { 1765 stmf_trace(iport->iport_alias, "handling" 1766 " LOGO rp_id %x, waiting for cmds to" 1767 " drain", cmd->cmd_rportid); 1768 } 1769 return (DISC_ACTION_DELAY_RESCAN); 1770 } 1771 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP); 1772 1773 /* Session can only be terminated after all the I/Os have drained */ 1774 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1775 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1776 irp->irp_session); 1777 stmf_free(irp->irp_session); 1778 irp->irp_session = NULL; 1779 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1780 } 1781 1782 fct_dequeue_els(irp); 1783 atomic_add_16(&irp->irp_sa_elses_count, -1); 1784 1785 /* don't send response if this is an implicit logout cmd */ 1786 if (!(icmd->icmd_flags & ICMD_IMPLICIT)) { 1787 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1788 ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0); 1789 } else { 1790 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 1791 ret = port->port_send_cmd(cmd); 1792 if (ret != FCT_SUCCESS) { 1793 atomic_and_32(&icmd->icmd_flags, 1794 ~ICMD_KNOWN_TO_FCA); 1795 } 1796 } 1797 1798 if (ret != FCT_SUCCESS) { 1799 fct_queue_cmd_for_termination(cmd, ret); 1800 } 1801 1802 DTRACE_FC_4(rport__logout__end, 1803 fct_cmd_t, cmd, 1804 fct_local_port_t, port, 1805 fct_i_remote_port_t, irp, 1806 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS)); 1807 1808 } else { 1809 DTRACE_FC_4(rport__logout__end, 1810 fct_cmd_t, cmd, 1811 fct_local_port_t, port, 1812 fct_i_remote_port_t, irp, 1813 int, (cmd->cmd_type != FCT_CMD_RCVD_ELS)); 1814 1815 fct_cmd_free(cmd); 1816 } 1817 1818 irp->irp_deregister_timer = ddi_get_lbolt() + 1819 drv_usectohz(USEC_DEREG_RP_TIMEOUT); 1820 irp->irp_dereg_count = 0; 1821 1822 /* Do not touch cmd here as it may have been freed */ 1823 1824 ASSERT(irp->irp_flags & IRP_IN_DISCOVERY_QUEUE); 1825 1826 return (DISC_ACTION_RESCAN); 1827 } 1828 1829 disc_action_t 1830 fct_process_prlo(fct_i_cmd_t *icmd) 1831 { 1832 fct_cmd_t *cmd = icmd->icmd_cmd; 1833 fct_remote_port_t *rp = cmd->cmd_rp; 1834 fct_local_port_t *port = cmd->cmd_port; 1835 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1836 port->port_fct_private; 1837 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1838 rp->rp_fct_private; 1839 fct_status_t ret; 1840 clock_t end_time; 1841 char info[160]; 1842 1843 /* We do not support solicited PRLOs yet */ 1844 ASSERT(cmd->cmd_type == FCT_CMD_RCVD_ELS); 1845 1846 /* Drain I/Os */ 1847 if (irp->irp_fcp_xchg_count) { 1848 /* Trigger cleanup if necessary */ 1849 if ((irp->irp_flags & IRP_FCP_CLEANUP) == 0) { 1850 stmf_trace(iport->iport_alias, "handling LOGO from" 1851 " %x. Triggering cleanup", cmd->cmd_rportid); 1852 /* Cleanup everything except elses */ 1853 if (fct_trigger_rport_cleanup(irp, FCT_CMD_FCP_XCHG)) { 1854 atomic_or_32(&irp->irp_flags, 1855 IRP_FCP_CLEANUP); 1856 } else { 1857 /* XXX: need more handling */ 1858 return (DISC_ACTION_DELAY_RESCAN); 1859 } 1860 } 1861 1862 end_time = icmd->icmd_start_time + 1863 drv_usectohz(USEC_ELS_TIMEOUT); 1864 if (ddi_get_lbolt() > end_time) { 1865 (void) snprintf(info, 160, 1866 "fct_process_prlo: unable to " 1867 "clean up I/O. iport-%p, icmd-%p", (void *)iport, 1868 (void *)icmd); 1869 info[159] = 0; 1870 (void) fct_port_shutdown(iport->iport_port, 1871 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 1872 1873 return (DISC_ACTION_DELAY_RESCAN); 1874 } 1875 1876 if ((ddi_get_lbolt() & 0x7f) == 0) { 1877 stmf_trace(iport->iport_alias, "handling" 1878 " PRLO from %x, waiting for cmds to" 1879 " drain", cmd->cmd_rportid); 1880 } 1881 return (DISC_ACTION_DELAY_RESCAN); 1882 } 1883 atomic_and_32(&irp->irp_flags, ~IRP_FCP_CLEANUP); 1884 1885 /* Session can only be terminated after all the I/Os have drained */ 1886 if (irp->irp_flags & IRP_SCSI_SESSION_STARTED) { 1887 stmf_deregister_scsi_session(iport->iport_port->port_lport, 1888 irp->irp_session); 1889 stmf_free(irp->irp_session); 1890 irp->irp_session = NULL; 1891 atomic_and_32(&irp->irp_flags, ~IRP_SCSI_SESSION_STARTED); 1892 } 1893 1894 fct_dequeue_els(irp); 1895 atomic_add_16(&irp->irp_sa_elses_count, -1); 1896 ret = fct_send_accrjt(cmd, ELS_OP_ACC, 0, 0); 1897 if (ret != FCT_SUCCESS) 1898 fct_queue_cmd_for_termination(cmd, ret); 1899 1900 return (DISC_ACTION_RESCAN); 1901 } 1902 1903 disc_action_t 1904 fct_process_rcvd_adisc(fct_i_cmd_t *icmd) 1905 { 1906 fct_cmd_t *cmd = icmd->icmd_cmd; 1907 fct_remote_port_t *rp = cmd->cmd_rp; 1908 fct_local_port_t *port = cmd->cmd_port; 1909 fct_i_local_port_t *iport = (fct_i_local_port_t *) 1910 port->port_fct_private; 1911 fct_els_t *els = (fct_els_t *) 1912 cmd->cmd_specific; 1913 fct_i_remote_port_t *irp = (fct_i_remote_port_t *) 1914 rp->rp_fct_private; 1915 uint8_t *p; 1916 uint32_t *q; 1917 fct_status_t ret; 1918 1919 fct_dequeue_els(irp); 1920 atomic_add_16(&irp->irp_nsa_elses_count, -1); 1921 1922 /* Validate the adisc request */ 1923 p = els->els_req_payload; 1924 q = (uint32_t *)p; 1925 if ((els->els_req_size != 28) || (bcmp(rp->rp_pwwn, p + 8, 8)) || 1926 (bcmp(rp->rp_nwwn, p + 16, 8))) { 1927 ret = fct_send_accrjt(cmd, ELS_OP_LSRJT, 3, 0); 1928 } else { 1929 rp->rp_hard_address = BE_32(q[1]); 1930 els->els_resp_size = els->els_resp_alloc_size = 28; 1931 els->els_resp_payload = (uint8_t *)kmem_zalloc(28, KM_SLEEP); 1932 bcopy(p, els->els_resp_payload, 28); 1933 p = els->els_resp_payload; 1934 q = (uint32_t *)p; 1935 p[0] = ELS_OP_ACC; 1936 q[1] = BE_32(port->port_hard_address); 1937 bcopy(port->port_pwwn, p + 8, 8); 1938 bcopy(port->port_nwwn, p + 16, 8); 1939 q[6] = BE_32(iport->iport_link_info.portid); 1940 ret = port->port_send_cmd_response(cmd, 0); 1941 } 1942 if (ret != FCT_SUCCESS) { 1943 fct_queue_cmd_for_termination(cmd, ret); 1944 } 1945 1946 return (DISC_ACTION_RESCAN); 1947 } 1948 1949 disc_action_t 1950 fct_process_unknown_els(fct_i_cmd_t *icmd) 1951 { 1952 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 1953 fct_status_t ret = FCT_FAILURE; 1954 uint8_t op = 0; 1955 1956 ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS); 1957 fct_dequeue_els(ICMD_TO_IRP(icmd)); 1958 atomic_add_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count, -1); 1959 op = ICMD_TO_ELS(icmd)->els_req_payload[0]; 1960 stmf_trace(iport->iport_alias, "Rejecting unknown unsol els %x (%s)", 1961 op, FCT_ELS_NAME(op)); 1962 ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_LSRJT, 1, 0); 1963 if (ret != FCT_SUCCESS) { 1964 fct_queue_cmd_for_termination(icmd->icmd_cmd, ret); 1965 } 1966 1967 return (DISC_ACTION_RESCAN); 1968 } 1969 1970 disc_action_t 1971 fct_process_rscn(fct_i_cmd_t *icmd) 1972 { 1973 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 1974 fct_status_t ret = FCT_FAILURE; 1975 uint8_t op = 0; 1976 uint8_t *rscn_req_payload; 1977 uint32_t rscn_req_size; 1978 1979 fct_dequeue_els(ICMD_TO_IRP(icmd)); 1980 atomic_add_16(&ICMD_TO_IRP(icmd)->irp_nsa_elses_count, -1); 1981 if (icmd->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) { 1982 op = ICMD_TO_ELS(icmd)->els_req_payload[0]; 1983 stmf_trace(iport->iport_alias, "Accepting RSCN %x (%s)", 1984 op, FCT_ELS_NAME(op)); 1985 rscn_req_size = ICMD_TO_ELS(icmd)->els_req_size; 1986 rscn_req_payload = kmem_alloc(rscn_req_size, KM_SLEEP); 1987 bcopy(ICMD_TO_ELS(icmd)->els_req_payload, rscn_req_payload, 1988 rscn_req_size); 1989 ret = fct_send_accrjt(icmd->icmd_cmd, ELS_OP_ACC, 1, 0); 1990 if (ret != FCT_SUCCESS) { 1991 fct_queue_cmd_for_termination(icmd->icmd_cmd, ret); 1992 } else { 1993 if (fct_rscn_options & RSCN_OPTION_VERIFY) { 1994 fct_rscn_verify(iport, rscn_req_payload, 1995 rscn_req_size); 1996 } 1997 } 1998 1999 kmem_free(rscn_req_payload, rscn_req_size); 2000 } else { 2001 ASSERT(0); 2002 } 2003 2004 return (DISC_ACTION_RESCAN); 2005 } 2006 2007 disc_action_t 2008 fct_process_els(fct_i_local_port_t *iport, fct_i_remote_port_t *irp) 2009 { 2010 fct_i_cmd_t *cmd_to_abort = NULL; 2011 fct_i_cmd_t **ppcmd, *icmd; 2012 fct_cmd_t *cmd; 2013 fct_els_t *els; 2014 int dq; 2015 disc_action_t ret = DISC_ACTION_NO_WORK; 2016 uint8_t op; 2017 2018 mutex_exit(&iport->iport_worker_lock); 2019 2020 /* 2021 * Do some cleanup based on the following. 2022 * - We can only have one session affecting els pending. 2023 * - If any session affecting els is pending no other els is allowed. 2024 * - If PLOGI is not done, nothing except PLOGI or LOGO is allowed. 2025 * NOTE: If port is down the cleanup is done outside of this 2026 * function. 2027 * NOTE: There is a side effect, if a sa ELS (non PLOGI) is received 2028 * while a PLOGI is pending, it will kill itself and the PLOGI. 2029 * which is probably ok. 2030 */ 2031 rw_enter(&irp->irp_lock, RW_WRITER); 2032 ppcmd = &irp->irp_els_list; 2033 while ((*ppcmd) != NULL) { 2034 int special_prli_cond = 0; 2035 dq = 0; 2036 2037 els = (fct_els_t *)((*ppcmd)->icmd_cmd)->cmd_specific; 2038 2039 if (((*ppcmd)->icmd_cmd->cmd_type == FCT_CMD_RCVD_ELS) && 2040 (els->els_req_payload[0] == ELS_OP_PRLI) && 2041 (irp->irp_flags & IRP_SOL_PLOGI_IN_PROGRESS)) { 2042 /* 2043 * The initiator sent a PRLI right after responding 2044 * to PLOGI and we have not yet finished processing 2045 * the PLOGI completion. We should not kill the PRLI 2046 * as the initiator may not retry it. 2047 */ 2048 special_prli_cond = 1; 2049 } 2050 2051 if ((*ppcmd)->icmd_flags & ICMD_BEING_ABORTED) { 2052 dq = 1; 2053 } else if (irp->irp_sa_elses_count > 1) { 2054 dq = 1; 2055 /* This els might have set the CLEANUP flag */ 2056 atomic_and_32(&irp->irp_flags, ~IRP_SESSION_CLEANUP); 2057 stmf_trace(iport->iport_alias, "Killing ELS %x cond 1", 2058 els->els_req_payload[0]); 2059 } else if (irp->irp_sa_elses_count && 2060 (((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) == 0)) { 2061 stmf_trace(iport->iport_alias, "Killing ELS %x cond 2", 2062 els->els_req_payload[0]); 2063 dq = 1; 2064 } else if (((irp->irp_flags & IRP_PLOGI_DONE) == 0) && 2065 (els->els_req_payload[0] != ELS_OP_PLOGI) && 2066 (els->els_req_payload[0] != ELS_OP_LOGO) && 2067 (special_prli_cond == 0)) { 2068 stmf_trace(iport->iport_alias, "Killing ELS %x cond 3", 2069 els->els_req_payload[0]); 2070 dq = 1; 2071 } 2072 2073 if (dq) { 2074 fct_i_cmd_t *c = (*ppcmd)->icmd_next; 2075 2076 if ((*ppcmd)->icmd_flags & ICMD_SESSION_AFFECTING) 2077 atomic_add_16(&irp->irp_sa_elses_count, -1); 2078 else 2079 atomic_add_16(&irp->irp_nsa_elses_count, -1); 2080 (*ppcmd)->icmd_next = cmd_to_abort; 2081 cmd_to_abort = *ppcmd; 2082 *ppcmd = c; 2083 } else { 2084 ppcmd = &((*ppcmd)->icmd_next); 2085 } 2086 } 2087 rw_exit(&irp->irp_lock); 2088 2089 while (cmd_to_abort) { 2090 fct_i_cmd_t *c = cmd_to_abort->icmd_next; 2091 2092 atomic_and_32(&cmd_to_abort->icmd_flags, ~ICMD_IN_IRP_QUEUE); 2093 fct_queue_cmd_for_termination(cmd_to_abort->icmd_cmd, 2094 FCT_ABORTED); 2095 cmd_to_abort = c; 2096 } 2097 2098 /* 2099 * pick from the top of the queue 2100 */ 2101 icmd = irp->irp_els_list; 2102 if (icmd == NULL) { 2103 /* 2104 * The cleanup took care of everything. 2105 */ 2106 2107 mutex_enter(&iport->iport_worker_lock); 2108 return (DISC_ACTION_RESCAN); 2109 } 2110 2111 cmd = icmd->icmd_cmd; 2112 els = ICMD_TO_ELS(icmd); 2113 op = els->els_req_payload[0]; 2114 if ((icmd->icmd_flags & ICMD_ELS_PROCESSING_STARTED) == 0) { 2115 stmf_trace(iport->iport_alias, "Processing %ssol ELS %x (%s) " 2116 "rp_id=%x", (cmd->cmd_type == FCT_CMD_RCVD_ELS) ? "un" : "", 2117 op, FCT_ELS_NAME(op), cmd->cmd_rportid); 2118 atomic_or_32(&icmd->icmd_flags, ICMD_ELS_PROCESSING_STARTED); 2119 } 2120 2121 if (op == ELS_OP_PLOGI) { 2122 ret |= fct_process_plogi(icmd); 2123 } else if (op == ELS_OP_PRLI) { 2124 ret |= fct_process_prli(icmd); 2125 } else if (op == ELS_OP_LOGO) { 2126 ret |= fct_process_logo(icmd); 2127 } else if ((op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) { 2128 ret |= fct_process_prlo(icmd); 2129 } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) { 2130 fct_status_t s; 2131 fct_local_port_t *port = iport->iport_port; 2132 2133 fct_dequeue_els(irp); 2134 atomic_add_16(&irp->irp_nsa_elses_count, -1); 2135 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 2136 if ((s = port->port_send_cmd(cmd)) != FCT_SUCCESS) { 2137 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA); 2138 fct_queue_cmd_for_termination(cmd, s); 2139 stmf_trace(iport->iport_alias, "Solicited els " 2140 "transport failed, ret = %llx", s); 2141 } 2142 } else if (op == ELS_OP_ADISC) { 2143 ret |= fct_process_rcvd_adisc(icmd); 2144 } else if (op == ELS_OP_RSCN) { 2145 (void) fct_process_rscn(icmd); 2146 } else { 2147 (void) fct_process_unknown_els(icmd); 2148 } 2149 2150 /* 2151 * This if condition will be false if a sa ELS trigged a cleanup 2152 * and set the ret = DISC_ACTION_DELAY_RESCAN. In that case we should 2153 * keep it that way. 2154 */ 2155 if (ret == DISC_ACTION_NO_WORK) { 2156 /* 2157 * Since we dropped the lock, we will force a rescan. The 2158 * only exception is if someone returned 2159 * DISC_ACTION_DELAY_RESCAN, in which case that should be the 2160 * return value. 2161 */ 2162 ret = DISC_ACTION_RESCAN; 2163 } 2164 2165 mutex_enter(&iport->iport_worker_lock); 2166 return (ret); 2167 } 2168 2169 void 2170 fct_handle_sol_els_completion(fct_i_local_port_t *iport, fct_i_cmd_t *icmd) 2171 { 2172 fct_i_remote_port_t *irp = NULL; 2173 fct_els_t *els = ICMD_TO_ELS(icmd); 2174 uint8_t op = els->els_req_payload[0]; 2175 2176 if (icmd->icmd_cmd->cmd_rp) { 2177 irp = ICMD_TO_IRP(icmd); 2178 } 2179 if (icmd->icmd_cmd->cmd_rp && 2180 (icmd->icmd_cmd->cmd_comp_status == FCT_SUCCESS) && 2181 (els->els_req_payload[0] == ELS_OP_PLOGI)) { 2182 bcopy(els->els_resp_payload + 20, irp->irp_rp->rp_pwwn, 8); 2183 bcopy(els->els_resp_payload + 28, irp->irp_rp->rp_nwwn, 8); 2184 2185 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)irp->irp_id, 2186 irp->irp_rp->rp_pwwn, PROTOCOL_FIBRE_CHANNEL); 2187 atomic_or_32(&irp->irp_flags, IRP_PLOGI_DONE); 2188 atomic_add_32(&iport->iport_nrps_login, 1); 2189 if (irp->irp_deregister_timer) { 2190 irp->irp_deregister_timer = 0; 2191 irp->irp_dereg_count = 0; 2192 } 2193 } 2194 2195 if (irp && (els->els_req_payload[0] == ELS_OP_PLOGI)) { 2196 atomic_and_32(&irp->irp_flags, ~IRP_SOL_PLOGI_IN_PROGRESS); 2197 } 2198 atomic_or_32(&icmd->icmd_flags, ICMD_CMD_COMPLETE); 2199 stmf_trace(iport->iport_alias, "Sol ELS %x (%s) completed with " 2200 "status %llx, did/%x", op, FCT_ELS_NAME(op), 2201 icmd->icmd_cmd->cmd_comp_status, icmd->icmd_cmd->cmd_rportid); 2202 } 2203 2204 static disc_action_t 2205 fct_check_cmdlist(fct_i_local_port_t *iport) 2206 { 2207 int num_to_release, ndx; 2208 fct_i_cmd_t *icmd; 2209 uint32_t total, max_active; 2210 2211 ASSERT(MUTEX_HELD(&iport->iport_worker_lock)); 2212 2213 total = iport->iport_total_alloced_ncmds; 2214 max_active = iport->iport_max_active_ncmds; 2215 2216 if (total <= max_active) 2217 return (DISC_ACTION_NO_WORK); 2218 /* 2219 * Everytime, we release half of the difference 2220 */ 2221 num_to_release = (total + 1 - max_active) / 2; 2222 2223 mutex_exit(&iport->iport_worker_lock); 2224 for (ndx = 0; ndx < num_to_release; ndx++) { 2225 mutex_enter(&iport->iport_cached_cmd_lock); 2226 icmd = iport->iport_cached_cmdlist; 2227 if (icmd == NULL) { 2228 mutex_exit(&iport->iport_cached_cmd_lock); 2229 break; 2230 } 2231 iport->iport_cached_cmdlist = icmd->icmd_next; 2232 iport->iport_cached_ncmds--; 2233 mutex_exit(&iport->iport_cached_cmd_lock); 2234 atomic_add_32(&iport->iport_total_alloced_ncmds, -1); 2235 fct_free(icmd->icmd_cmd); 2236 } 2237 mutex_enter(&iport->iport_worker_lock); 2238 return (DISC_ACTION_RESCAN); 2239 } 2240 2241 /* 2242 * The efficiency of handling solicited commands is very low here. But 2243 * fortunately, we seldom send solicited commands. So it will not hurt 2244 * the system performance much. 2245 */ 2246 static disc_action_t 2247 fct_check_solcmd_queue(fct_i_local_port_t *iport) 2248 { 2249 fct_i_cmd_t *icmd = NULL; 2250 fct_i_cmd_t *prev_icmd = NULL; 2251 fct_i_cmd_t *next_icmd = NULL; 2252 2253 ASSERT(mutex_owned(&iport->iport_worker_lock)); 2254 for (icmd = iport->iport_solcmd_queue; icmd; icmd = next_icmd) { 2255 ASSERT(icmd->icmd_flags | ICMD_IN_SOLCMD_QUEUE); 2256 next_icmd = icmd->icmd_solcmd_next; 2257 if (icmd->icmd_flags & ICMD_SOLCMD_NEW) { 2258 /* 2259 * This solicited cmd is new. 2260 * Dispatch ELSes to discovery queue to make use of 2261 * existent framework. 2262 */ 2263 icmd->icmd_flags &= ~ICMD_SOLCMD_NEW; 2264 mutex_exit(&iport->iport_worker_lock); 2265 2266 if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) { 2267 fct_handle_els(icmd->icmd_cmd); 2268 } else { 2269 fct_handle_solct(icmd->icmd_cmd); 2270 } 2271 2272 mutex_enter(&iport->iport_worker_lock); 2273 } else if (icmd->icmd_flags & ICMD_CMD_COMPLETE) { 2274 /* 2275 * To make fct_check_solcmd simple and flexible, 2276 * We need only call callback to finish post-handling. 2277 */ 2278 if (icmd->icmd_cb) { 2279 /* 2280 * mutex ??? 2281 */ 2282 icmd->icmd_cb(icmd); 2283 } 2284 2285 2286 /* 2287 * Release resources for this solicited cmd 2288 */ 2289 if (iport->iport_solcmd_queue == icmd) { 2290 iport->iport_solcmd_queue = next_icmd; 2291 } else { 2292 prev_icmd = iport->iport_solcmd_queue; 2293 while (prev_icmd->icmd_solcmd_next != icmd) { 2294 prev_icmd = prev_icmd->icmd_solcmd_next; 2295 } 2296 prev_icmd->icmd_solcmd_next = next_icmd; 2297 } 2298 2299 icmd->icmd_cb = NULL; 2300 mutex_exit(&iport->iport_worker_lock); 2301 fct_cmd_free(icmd->icmd_cmd); 2302 mutex_enter(&iport->iport_worker_lock); 2303 } else { 2304 /* 2305 * This solicited cmd is still ongoing. 2306 * We need check if it's time to abort this cmd 2307 */ 2308 if (((icmd->icmd_start_time + drv_usectohz( 2309 USEC_SOL_TIMEOUT)) < ddi_get_lbolt()) && 2310 !(icmd->icmd_flags & ICMD_BEING_ABORTED)) { 2311 fct_q_for_termination_lock_held(iport, 2312 icmd, FCT_ABORTED); 2313 } 2314 } 2315 } 2316 2317 return (DISC_ACTION_DELAY_RESCAN); 2318 } 2319 2320 void 2321 fct_handle_solct(fct_cmd_t *cmd) 2322 { 2323 fct_status_t ret = FCT_SUCCESS; 2324 fct_i_cmd_t *icmd = CMD_TO_ICMD(cmd); 2325 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2326 fct_i_remote_port_t *irp = ICMD_TO_IRP(icmd); 2327 2328 ASSERT(cmd->cmd_type == FCT_CMD_SOL_CT); 2329 rw_enter(&iport->iport_lock, RW_READER); 2330 /* 2331 * Let's make sure local port is sane 2332 */ 2333 if ((iport->iport_link_state & S_LINK_ONLINE) == 0) { 2334 rw_exit(&iport->iport_lock); 2335 2336 stmf_trace(iport->iport_alias, "fct_transport_solct: " 2337 "solcmd-%p transport failed, becasue port state was %x", 2338 cmd, iport->iport_link_state); 2339 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE); 2340 return; 2341 } 2342 2343 /* 2344 * Let's make sure we have plogi-ed to name server 2345 */ 2346 rw_enter(&irp->irp_lock, RW_READER); 2347 if (!(irp->irp_flags & IRP_PLOGI_DONE)) { 2348 rw_exit(&irp->irp_lock); 2349 rw_exit(&iport->iport_lock); 2350 2351 stmf_trace(iport->iport_alias, "fct_transport_solct: " 2352 "Must login to name server first - cmd-%p", cmd); 2353 fct_queue_cmd_for_termination(cmd, FCT_NOT_LOGGED_IN); 2354 return; 2355 } 2356 2357 /* 2358 * Let's get a slot for this solcmd 2359 */ 2360 if (fct_alloc_cmd_slot(iport, cmd) == FCT_SLOT_EOL) { 2361 rw_exit(&irp->irp_lock); 2362 rw_exit(&iport->iport_lock); 2363 2364 stmf_trace(iport->iport_alias, "fct_transport_solcmd: " 2365 "ran out of xchg resources - cmd-%p", cmd); 2366 fct_queue_cmd_for_termination(cmd, FCT_NO_XCHG_RESOURCE); 2367 return; 2368 } 2369 2370 if (fct_netbuf_to_value(ICMD_TO_CT(icmd)->ct_req_payload + 8, 2) == 2371 NS_GID_PN) { 2372 fct_i_remote_port_t *query_irp = NULL; 2373 2374 query_irp = fct_lookup_irp_by_portwwn(iport, 2375 ICMD_TO_CT(icmd)->ct_req_payload + 16); 2376 if (query_irp) { 2377 atomic_and_32(&query_irp->irp_flags, ~IRP_RSCN_QUEUED); 2378 } 2379 } 2380 rw_exit(&irp->irp_lock); 2381 rw_exit(&iport->iport_lock); 2382 2383 atomic_add_16(&irp->irp_nonfcp_xchg_count, 1); 2384 atomic_or_32(&icmd->icmd_flags, ICMD_KNOWN_TO_FCA); 2385 icmd->icmd_start_time = ddi_get_lbolt(); 2386 ret = iport->iport_port->port_send_cmd(cmd); 2387 if (ret != FCT_SUCCESS) { 2388 atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA); 2389 fct_queue_cmd_for_termination(cmd, ret); 2390 } 2391 } 2392 2393 void 2394 fct_logo_cb(fct_i_cmd_t *icmd) 2395 { 2396 ASSERT(!(icmd->icmd_flags & ICMD_IMPLICIT)); 2397 if (!FCT_IS_ELS_ACC(icmd)) { 2398 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_logo_cb: " 2399 "solicited LOGO is not accepted - icmd/%p", icmd); 2400 } 2401 } 2402 2403 void 2404 fct_gsnn_cb(fct_i_cmd_t *icmd) 2405 { 2406 int snlen = 0; 2407 char *sn = NULL; 2408 fct_i_remote_port_t *query_irp = NULL; 2409 2410 if (!FCT_IS_CT_ACC(icmd)) { 2411 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: " 2412 "GSNN is not accepted by NS - icmd/%p", icmd); 2413 return; 2414 } 2415 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2416 2417 rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER); 2418 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2419 query_irp = fct_lookup_irp_by_nodewwn(ICMD_TO_IPORT(icmd), 2420 ICMD_TO_CT(icmd)->ct_req_payload + 16); 2421 2422 if (!query_irp) { 2423 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: " 2424 "can't get rp icmd-%p", icmd); 2425 goto exit_gsnn_cb; 2426 } else { 2427 snlen = ICMD_TO_CT(icmd)->ct_resp_payload[16]; 2428 } 2429 2430 if (query_irp && snlen) { 2431 /* 2432 * Release previous resource, then allocate needed resource 2433 */ 2434 sn = query_irp->irp_snn; 2435 if (sn) { 2436 kmem_free(sn, strlen(sn) + 1); 2437 } 2438 2439 query_irp->irp_snn = NULL; 2440 sn = kmem_zalloc(snlen + 1, KM_SLEEP); 2441 (void) strncpy(sn, (char *) 2442 ICMD_TO_CT(icmd)->ct_resp_payload + 17, snlen); 2443 if (strlen(sn) != snlen) { 2444 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, 2445 "fct_gsnn_cb: %s, but len=%d", sn, snlen); 2446 kmem_free(sn, snlen + 1); 2447 sn = NULL; 2448 } 2449 2450 /* 2451 * Update symbolic node name 2452 */ 2453 query_irp->irp_snn = sn; 2454 if ((query_irp->irp_flags & IRP_SCSI_SESSION_STARTED) && 2455 (query_irp->irp_session)) { 2456 query_irp->irp_session->ss_rport_alias = 2457 query_irp->irp_snn; 2458 } 2459 } else { 2460 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gsnn_cb: " 2461 "irp/%p, snlen/%d", query_irp, snlen); 2462 } 2463 2464 exit_gsnn_cb: 2465 rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock); 2466 } 2467 2468 void 2469 fct_link_init_cb(fct_i_cmd_t *icmd) 2470 { 2471 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2472 2473 iport->iport_li_state &= ~LI_STATE_FLAG_CMD_WAITING; 2474 if (icmd->icmd_cmd->cmd_comp_status != FCT_SUCCESS) { 2475 stmf_trace(iport->iport_alias, "fct_link_init_cb: ELS-%x failed" 2476 "comp_status- %llx", ICMD_TO_ELS(icmd)->els_req_payload[0], 2477 icmd->icmd_cmd->cmd_comp_status); 2478 iport->iport_li_comp_status = icmd->icmd_cmd->cmd_comp_status; 2479 } else if (icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_ELS) { 2480 if (!FCT_IS_ELS_ACC(icmd)) { 2481 stmf_trace(iport->iport_alias, 2482 "fct_link_init_cb: ELS-%x is rejected", 2483 ICMD_TO_ELS(icmd)->els_req_payload[0]); 2484 iport->iport_li_comp_status = FCT_REJECT_STATUS( 2485 ICMD_TO_ELS(icmd)->els_resp_payload[1], 2486 ICMD_TO_ELS(icmd)->els_resp_payload[2]); 2487 } else { 2488 iport->iport_li_comp_status = FCT_SUCCESS; 2489 } 2490 } else { 2491 ASSERT(icmd->icmd_cmd->cmd_type == FCT_CMD_SOL_CT); 2492 if (!FCT_IS_CT_ACC(icmd)) { 2493 stmf_trace(iport->iport_alias, 2494 "fct_link_init_cb: CT-%02x%02x is rejected", 2495 ICMD_TO_CT(icmd)->ct_req_payload[8], 2496 ICMD_TO_CT(icmd)->ct_req_payload[9]); 2497 iport->iport_li_comp_status = FCT_REJECT_STATUS( 2498 ICMD_TO_CT(icmd)->ct_resp_payload[8], 2499 ICMD_TO_CT(icmd)->ct_resp_payload[9]); 2500 } else { 2501 iport->iport_li_comp_status = FCT_SUCCESS; 2502 } 2503 } 2504 } 2505 2506 void 2507 fct_gcs_cb(fct_i_cmd_t *icmd) 2508 { 2509 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 2510 fct_i_remote_port_t *query_irp = NULL; 2511 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2512 uint32_t query_portid; 2513 uint8_t *resp; 2514 uint8_t *req; 2515 2516 if (!FCT_IS_CT_ACC(icmd)) { 2517 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gcs_cb: " 2518 "GCS_ID is not accepted by NS - icmd/%p", icmd); 2519 return; 2520 } 2521 mutex_exit(&iport->iport_worker_lock); 2522 2523 resp = ct->ct_resp_payload; 2524 req = ct->ct_req_payload; 2525 query_portid = (req[17] << 16) | (req[18] << 8) | req[19]; 2526 2527 rw_enter(&iport->iport_lock, RW_READER); 2528 mutex_enter(&iport->iport_worker_lock); 2529 query_irp = fct_portid_to_portptr(iport, query_portid); 2530 2531 if (query_irp) { 2532 query_irp->irp_cos = (resp[16] << 27) | (resp[17] << 18) | 2533 (resp[18] << 8) | resp[19]; 2534 } 2535 rw_exit(&iport->iport_lock); 2536 } 2537 2538 void 2539 fct_gft_cb(fct_i_cmd_t *icmd) 2540 { 2541 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 2542 fct_i_remote_port_t *query_irp = NULL; 2543 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2544 uint32_t query_portid; 2545 uint8_t *resp; 2546 uint8_t *req; 2547 2548 if (!FCT_IS_CT_ACC(icmd)) { 2549 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gft_cb: " 2550 "GFT_ID is not accepted by NS - icmd/%p", icmd); 2551 return; 2552 } 2553 mutex_exit(&iport->iport_worker_lock); 2554 2555 resp = ct->ct_resp_payload; 2556 req = ct->ct_req_payload; 2557 query_portid = (req[17] << 16) | (req[18] << 8) | req[19]; 2558 2559 rw_enter(&iport->iport_lock, RW_READER); 2560 mutex_enter(&iport->iport_worker_lock); 2561 query_irp = fct_portid_to_portptr(iport, query_portid); 2562 2563 if (query_irp) { 2564 (void) memcpy(query_irp->irp_fc4types, resp + 16, 32); 2565 } 2566 rw_exit(&iport->iport_lock); 2567 } 2568 2569 void 2570 fct_gid_cb(fct_i_cmd_t *icmd) 2571 { 2572 fct_cmd_t *cmd = NULL; 2573 fct_i_remote_port_t *query_irp = NULL; 2574 uint32_t nsportid = 0; 2575 int do_logo = 0; 2576 2577 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2578 2579 rw_enter(&ICMD_TO_IPORT(icmd)->iport_lock, RW_READER); 2580 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2581 query_irp = fct_lookup_irp_by_portwwn(ICMD_TO_IPORT(icmd), 2582 ICMD_TO_CT(icmd)->ct_req_payload + 16); 2583 2584 if (!query_irp || (query_irp && 2585 (PTR2INT(icmd->icmd_cb_private, uint32_t) != 2586 query_irp->irp_rscn_counter))) { 2587 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: " 2588 "new RSCN arrived - query_irp/%p, private-%x", query_irp, 2589 PTR2INT(icmd->icmd_cb_private, uint32_t)); 2590 goto exit_gid_cb; 2591 } 2592 2593 if ((query_irp->irp_flags & IRP_RSCN_QUEUED) || 2594 (!(query_irp->irp_flags & IRP_PLOGI_DONE))) { 2595 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: " 2596 "not proper irp_flags - query_irp/%p", query_irp); 2597 goto exit_gid_cb; 2598 } 2599 2600 if (!FCT_IS_CT_ACC(icmd)) { 2601 /* 2602 * Check if it has disappeared 2603 */ 2604 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gid_cb: " 2605 "GPN_ID is not accepted by NS - icmd/%p", icmd); 2606 do_logo = 1; 2607 } else { 2608 /* 2609 * Check if its portid has changed 2610 */ 2611 nsportid = fct_netbuf_to_value( 2612 ICMD_TO_CT(icmd)->ct_resp_payload + 17, 3); 2613 if (nsportid != query_irp->irp_rp->rp_id) { 2614 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, 2615 "portid has changed - query_irp/%p", query_irp); 2616 do_logo = 1; 2617 } 2618 } 2619 2620 if (do_logo) { 2621 cmd = fct_create_solels(ICMD_TO_PORT(icmd), 2622 query_irp->irp_rp, 1, ELS_OP_LOGO, 0, fct_logo_cb); 2623 if (cmd) { 2624 mutex_exit(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2625 fct_post_implicit_logo(cmd); 2626 mutex_enter(&ICMD_TO_IPORT(icmd)->iport_worker_lock); 2627 } 2628 } 2629 2630 exit_gid_cb: 2631 rw_exit(&ICMD_TO_IPORT(icmd)->iport_lock); 2632 } 2633 2634 void 2635 fct_gspn_cb(fct_i_cmd_t *icmd) 2636 { 2637 fct_sol_ct_t *ct = ICMD_TO_CT(icmd); 2638 fct_i_remote_port_t *query_irp = NULL; 2639 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2640 uint32_t query_portid; 2641 uint8_t *resp; 2642 uint8_t *req; 2643 uint8_t spnlen; 2644 2645 if (!FCT_IS_CT_ACC(icmd)) { 2646 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_gspn_cb: " 2647 "GSPN_ID is not accepted by NS - icmd/%p", icmd); 2648 return; 2649 } 2650 mutex_exit(&iport->iport_worker_lock); 2651 2652 resp = ct->ct_resp_payload; 2653 req = ct->ct_req_payload; 2654 query_portid = (req[17] << 16) | (req[18] << 8) | req[19]; 2655 2656 rw_enter(&iport->iport_lock, RW_READER); 2657 mutex_enter(&iport->iport_worker_lock); 2658 query_irp = fct_portid_to_portptr(iport, query_portid); 2659 if (query_irp) { 2660 spnlen = resp[16]; 2661 if (spnlen > 0) { 2662 if (query_irp->irp_spn) { 2663 kmem_free(query_irp->irp_spn, 2664 strlen(query_irp->irp_spn) + 1); 2665 } 2666 query_irp->irp_spn = kmem_zalloc(spnlen + 1, KM_SLEEP); 2667 (void) strncpy(query_irp->irp_spn, 2668 (char *)resp + 17, spnlen); 2669 } 2670 } 2671 rw_exit(&iport->iport_lock); 2672 } 2673 2674 void 2675 fct_rls_cb(fct_i_cmd_t *icmd) 2676 { 2677 fct_els_t *els = ICMD_TO_ELS(icmd); 2678 uint8_t *resp; 2679 fct_rls_cb_data_t *rls_cb_data = NULL; 2680 fct_port_link_status_t *rls_resp; 2681 fct_i_local_port_t *iport = ICMD_TO_IPORT(icmd); 2682 2683 rls_cb_data = icmd->icmd_cb_private; 2684 2685 if (!FCT_IS_ELS_ACC(icmd)) { 2686 stmf_trace(ICMD_TO_IPORT(icmd)->iport_alias, "fct_rls_cb: " 2687 "solicited RLS is not accepted - icmd/%p", icmd); 2688 if (rls_cb_data) { 2689 rls_cb_data->fct_els_res = FCT_FAILURE; 2690 sema_v(&iport->iport_rls_sema); 2691 } 2692 return; 2693 } 2694 2695 if (!rls_cb_data) { 2696 sema_v(&iport->iport_rls_sema); 2697 return; 2698 } 2699 2700 resp = els->els_resp_payload; 2701 2702 rls_cb_data = icmd->icmd_cb_private; 2703 2704 /* Get the response and store it somewhere */ 2705 rls_resp = (fct_port_link_status_t *)rls_cb_data->fct_link_status; 2706 rls_resp->LinkFailureCount = BE_32(*((uint32_t *)(resp + 4))); 2707 rls_resp->LossOfSyncCount = BE_32(*((uint32_t *)(resp + 8))); 2708 rls_resp->LossOfSignalsCount = BE_32(*((uint32_t *)(resp + 12))); 2709 rls_resp->PrimitiveSeqProtocolErrorCount = 2710 BE_32(*((uint32_t *)(resp + 16))); 2711 rls_resp->InvalidTransmissionWordCount = 2712 BE_32(*((uint32_t *)(resp + 20))); 2713 rls_resp->InvalidCRCCount = BE_32(*((uint32_t *)(resp + 24))); 2714 2715 rls_cb_data->fct_els_res = FCT_SUCCESS; 2716 sema_v(&iport->iport_rls_sema); 2717 icmd->icmd_cb_private = NULL; 2718 } 2719 2720 /* 2721 * For lookup functions, we move locking up one level 2722 */ 2723 fct_i_remote_port_t * 2724 fct_lookup_irp_by_nodewwn(fct_i_local_port_t *iport, uint8_t *nodewwn) 2725 { 2726 fct_i_remote_port_t *irp = NULL; 2727 int idx = 0; 2728 2729 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) { 2730 for (irp = iport->iport_rp_tb[idx]; irp; 2731 irp = irp->irp_next) { 2732 if (bcmp(irp->irp_rp->rp_nwwn, nodewwn, FC_WWN_LEN)) { 2733 continue; 2734 } else { 2735 return (irp); 2736 } 2737 } 2738 } 2739 2740 return (NULL); 2741 } 2742 2743 fct_i_remote_port_t * 2744 fct_lookup_irp_by_portwwn(fct_i_local_port_t *iport, uint8_t *portwwn) 2745 { 2746 fct_i_remote_port_t *irp = NULL; 2747 int idx = 0; 2748 2749 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) { 2750 for (irp = iport->iport_rp_tb[idx]; irp; 2751 irp = irp->irp_next) { 2752 if (bcmp(irp->irp_rp->rp_pwwn, portwwn, FC_WWN_LEN)) { 2753 continue; 2754 } else { 2755 return (irp); 2756 } 2757 } 2758 } 2759 2760 return (NULL); 2761 } 2762 2763 #ifdef lint 2764 #define FCT_VERIFY_RSCN() _NOTE(EMPTY) 2765 #else 2766 #define FCT_VERIFY_RSCN() \ 2767 do { \ 2768 ct_cmd = fct_create_solct(port, irp->irp_rp, NS_GID_PN, \ 2769 fct_gid_cb); \ 2770 if (ct_cmd) { \ 2771 uint32_t cnt; \ 2772 cnt = atomic_add_32_nv(&irp->irp_rscn_counter, 1); \ 2773 CMD_TO_ICMD(ct_cmd)->icmd_cb_private = \ 2774 INT2PTR(cnt, void *); \ 2775 irp->irp_flags |= IRP_RSCN_QUEUED; \ 2776 fct_post_to_solcmd_queue(port, ct_cmd); \ 2777 } \ 2778 } while (0) 2779 #endif 2780 2781 /* ARGSUSED */ 2782 static void 2783 fct_rscn_verify(fct_i_local_port_t *iport, uint8_t *rscn_req_payload, 2784 uint32_t rscn_req_size) 2785 { 2786 int idx = 0; 2787 uint8_t page_format = 0; 2788 uint32_t page_portid = 0; 2789 uint8_t *page_buf = NULL; 2790 uint8_t *last_page_buf = NULL; 2791 #ifndef lint 2792 fct_cmd_t *ct_cmd = NULL; 2793 fct_local_port_t *port = NULL; 2794 #endif 2795 fct_i_remote_port_t *irp = NULL; 2796 2797 page_buf = rscn_req_payload + 4; 2798 last_page_buf = rscn_req_payload + 2799 fct_netbuf_to_value(rscn_req_payload + 2, 2) - 4; 2800 #ifndef lint 2801 port = iport->iport_port; 2802 #endif 2803 for (; page_buf <= last_page_buf; page_buf += 4) { 2804 page_format = 0x03 & page_buf[0]; 2805 page_portid = fct_netbuf_to_value(page_buf + 1, 3); 2806 2807 DTRACE_FC_2(rscn__receive, 2808 fct_i_local_port_t, iport, 2809 int, page_portid); 2810 2811 rw_enter(&iport->iport_lock, RW_READER); 2812 if (!page_format) { 2813 irp = fct_portid_to_portptr(iport, page_portid); 2814 if (!(irp && !(irp->irp_flags & IRP_RSCN_QUEUED))) { 2815 rw_exit(&iport->iport_lock); 2816 2817 continue; /* try next page */ 2818 } 2819 2820 if (FC_WELL_KNOWN_ADDR(irp->irp_portid) || 2821 !(irp->irp_flags & IRP_PLOGI_DONE)) { 2822 rw_exit(&iport->iport_lock); 2823 2824 continue; /* try next page */ 2825 } 2826 2827 FCT_VERIFY_RSCN(); 2828 } else { 2829 for (idx = 0; idx < FCT_HASH_TABLE_SIZE; idx++) { 2830 for (irp = iport->iport_rp_tb[idx]; 2831 irp; irp = irp->irp_next) { 2832 if (FC_WELL_KNOWN_ADDR(irp->irp_portid)) 2833 continue; /* try next irp */ 2834 2835 if (!(irp->irp_flags & IRP_PLOGI_DONE)) 2836 continue; /* try next irp */ 2837 2838 if (irp->irp_flags & IRP_RSCN_QUEUED) { 2839 continue; /* try next irp */ 2840 } 2841 #ifndef lint 2842 if (!((0xFFFFFF << (page_format * 8)) & 2843 (page_portid ^ irp->irp_portid))) { 2844 FCT_VERIFY_RSCN(); 2845 } 2846 #endif 2847 } 2848 } 2849 } 2850 rw_exit(&iport->iport_lock); 2851 } 2852 } 2853