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