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 /* 23 * Copyright 2008 Emulex. All rights reserved. 24 * Use is subject to License terms. 25 */ 26 27 28 #include "emlxs.h" 29 30 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 31 EMLXS_MSG_DEF(EMLXS_ELS_C); 32 33 static void emlxs_handle_sol_flogi(emlxs_port_t *port, emlxs_buf_t *sbp); 34 static void emlxs_handle_sol_fdisk(emlxs_port_t *port, emlxs_buf_t *sbp); 35 static void emlxs_handle_sol_plogi(emlxs_port_t *port, emlxs_buf_t *sbp); 36 static void emlxs_handle_sol_adisc(emlxs_port_t *port, emlxs_buf_t *sbp); 37 static void emlxs_handle_sol_logo(emlxs_port_t *port, emlxs_buf_t *sbp); 38 static void emlxs_handle_sol_prli(emlxs_port_t *port, emlxs_buf_t *sbp); 39 40 static void emlxs_handle_unsol_rscn(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 41 MATCHMAP *mp, uint32_t size); 42 static void emlxs_handle_unsol_flogi(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 43 MATCHMAP *mp, uint32_t size); 44 static void emlxs_handle_unsol_plogi(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 45 MATCHMAP *mp, uint32_t size); 46 static void emlxs_handle_unsol_logo(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 47 MATCHMAP *mp, uint32_t size); 48 static void emlxs_handle_unsol_adisc(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 49 MATCHMAP *mp, uint32_t size); 50 static void emlxs_handle_unsol_prli(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 51 MATCHMAP *mp, uint32_t size); 52 static void emlxs_handle_unsol_prlo(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 53 MATCHMAP *mp, uint32_t size); 54 static void emlxs_handle_unsol_auth(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 55 MATCHMAP *mp, uint32_t size); 56 static void emlxs_handle_unsol_gen_cmd(emlxs_port_t *port, RING *rp, 57 IOCBQ *iocbq, MATCHMAP *mp, uint32_t size); 58 static void emlxs_handle_acc(emlxs_port_t *port, emlxs_buf_t *sbp, IOCBQ *iocbq, 59 uint32_t flag); 60 static void emlxs_handle_reject(emlxs_port_t *port, emlxs_buf_t *sbp, 61 IOCBQ *iocbq, uint32_t flag); 62 static void emlxs_send_rsnn(emlxs_port_t *port); 63 64 65 66 67 /* Routine Declaration - Local */ 68 /* End Routine Declaration - Local */ 69 70 /* 71 * emlxs_els_handle_event 72 * 73 * Description: Process an ELS Response Ring cmpl. 74 * 75 */ 76 extern int 77 emlxs_els_handle_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 78 { 79 emlxs_port_t *port = &PPORT; 80 IOCB *iocb; 81 emlxs_buf_t *sbp; 82 fc_packet_t *pkt; 83 uint32_t *lp0; 84 uint32_t command; 85 NODELIST *ndlp; 86 uint32_t did; 87 ELS_PKT *els; 88 89 iocb = &iocbq->iocb; 90 91 HBASTATS.ElsEvent++; 92 93 sbp = (emlxs_buf_t *)iocbq->sbp; 94 95 if (!sbp) { 96 /* 97 * completion with missing xmit command 98 */ 99 HBASTATS.ElsStray++; 100 101 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_els_completion_msg, 102 "iocbq=%p cmd=0x%x iotag=0x%x status=0x%x perr=0x%x", 103 iocbq, (uint32_t)iocb->ulpCommand, (uint32_t)iocb->ulpIoTag, 104 iocb->ulpStatus, iocb->un.ulpWord[4]); 105 106 return (1); 107 } 108 if (rp->ringno != FC_ELS_RING) { 109 HBASTATS.ElsStray++; 110 111 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_els_completion_msg, 112 "Not ELS ring: ring=%d iocbq=%p cmd=0x%x " 113 "iotag=0x%x status=0x%x perr=0x%x", 114 rp->ringno, iocbq, (uint32_t)iocb->ulpCommand, 115 (uint32_t)iocb->ulpIoTag, iocb->ulpStatus, 116 iocb->un.ulpWord[4]); 117 118 return (1); 119 } 120 port = sbp->iocbq.port; 121 pkt = PRIV2PKT(sbp); 122 lp0 = (uint32_t *)pkt->pkt_cmd; 123 command = *lp0 & ELS_CMD_MASK; 124 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 125 126 /* Check if a response buffer was provided */ 127 if (pkt->pkt_rsplen) { 128 emlxs_mpdata_sync(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen, 129 DDI_DMA_SYNC_FORKERNEL); 130 } 131 switch (iocb->ulpCommand) { 132 /* ELS Reply completion */ 133 case CMD_XMIT_ELS_RSP_CX: 134 case CMD_XMIT_ELS_RSP64_CX: 135 136 HBASTATS.ElsRspCompleted++; 137 138 if (command == ELS_CMD_ACC) { 139 emlxs_handle_acc(port, sbp, iocbq, 1); 140 } else { 141 emlxs_handle_reject(port, sbp, iocbq, 1); 142 } 143 144 break; 145 146 /* ELS command completion */ 147 case CMD_ELS_REQUEST_CR: 148 case CMD_ELS_REQUEST64_CR: 149 case CMD_ELS_REQUEST_CX: 150 case CMD_ELS_REQUEST64_CX: 151 152 HBASTATS.ElsCmdCompleted++; 153 154 sbp->pkt_flags |= PACKET_ELS_RSP_VALID; 155 156 els = (ELS_PKT *)pkt->pkt_resp; 157 158 pkt->pkt_resp_resid = 159 pkt->pkt_rsplen - iocb->un.elsreq64.bdl.bdeSize; 160 pkt->pkt_data_resid = pkt->pkt_datalen; 161 162 pkt->pkt_resp_fhdr.d_id = pkt->pkt_cmd_fhdr.s_id; 163 pkt->pkt_resp_fhdr.s_id = pkt->pkt_cmd_fhdr.d_id; 164 165 if ((iocb->ulpStatus == 0) && (els->elsCode == 0x02)) { 166 HBASTATS.ElsCmdGood++; 167 168 if (!(sbp->pkt_flags & PACKET_ALLOCATED)) { 169 /* 170 * ULP patch - ULP expects resp_resid = 0 on 171 * success 172 */ 173 pkt->pkt_resp_resid = 0; 174 } 175 switch (command) { 176 case ELS_CMD_FDISC: /* Fabric login */ 177 emlxs_handle_sol_fdisk(port, sbp); 178 179 break; 180 181 case ELS_CMD_FLOGI: /* Fabric login */ 182 emlxs_handle_sol_flogi(port, sbp); 183 184 break; 185 186 case ELS_CMD_PLOGI: /* NPort login */ 187 emlxs_handle_sol_plogi(port, sbp); 188 189 break; 190 191 case ELS_CMD_ADISC: /* Adisc */ 192 emlxs_handle_sol_adisc(port, sbp); 193 194 break; 195 196 case ELS_CMD_LOGO: /* Logout */ 197 emlxs_handle_sol_logo(port, sbp); 198 199 break; 200 201 case ELS_CMD_PRLI: /* Process Log In */ 202 emlxs_handle_sol_prli(port, sbp); 203 204 break; 205 206 default: 207 EMLXS_MSGF(EMLXS_CONTEXT, 208 &emlxs_els_completion_msg, 209 "%s: did=%x", 210 emlxs_elscmd_xlate(command), did); 211 212 emlxs_pkt_complete(sbp, IOSTAT_SUCCESS, 0, 1); 213 214 break; 215 } 216 217 } else { 218 HBASTATS.ElsCmdError++; 219 220 /* Look for LS_REJECT */ 221 if (iocb->ulpStatus == IOSTAT_LS_RJT) { 222 pkt->pkt_state = FC_PKT_LS_RJT; 223 pkt->pkt_action = FC_ACTION_RETRYABLE; 224 pkt->pkt_reason = iocb->un.grsp.perr.statRsn; 225 pkt->pkt_expln = iocb->un.grsp.perr.statBaExp; 226 sbp->pkt_flags |= PACKET_STATE_VALID; 227 228 EMLXS_MSGF(EMLXS_CONTEXT, 229 &emlxs_els_completion_msg, 230 "%s Rejected: did=%x rsn=%x exp=%x", 231 emlxs_elscmd_xlate(command), did, 232 pkt->pkt_reason, pkt->pkt_expln); 233 } else if (iocb->ulpStatus == IOSTAT_LOCAL_REJECT) { 234 EMLXS_MSGF(EMLXS_CONTEXT, 235 &emlxs_bad_els_completion_msg, 236 "%s: did=%x Local Reject. %s", 237 emlxs_elscmd_xlate(command), did, 238 emlxs_error_xlate( 239 iocb->un.grsp.perr.statLocalError)); 240 } else { 241 EMLXS_MSGF(EMLXS_CONTEXT, 242 &emlxs_bad_els_completion_msg, 243 "%s: did=%x %s (%02x%02x%02x%02x)", 244 emlxs_elscmd_xlate(command), did, 245 emlxs_state_xlate(iocb->ulpStatus), 246 iocb->un.grsp.perr.statAction, 247 iocb->un.grsp.perr.statRsn, 248 iocb->un.grsp.perr.statBaExp, 249 iocb->un.grsp.perr.statLocalError); 250 } 251 252 switch (command) { 253 case ELS_CMD_PLOGI: /* NPort login failed */ 254 ndlp = emlxs_node_find_did(port, did); 255 256 if (ndlp && ndlp->nlp_active) { 257 /* Open the node again */ 258 emlxs_node_open(port, ndlp, 259 FC_FCP_RING); 260 emlxs_node_open(port, ndlp, 261 FC_IP_RING); 262 #ifdef DHCHAP_SUPPORT 263 if (pkt->pkt_state == FC_PKT_LS_RJT) { 264 emlxs_dhc_state(port, ndlp, 265 NODE_STATE_NOCHANGE, 266 pkt->pkt_reason, 267 pkt->pkt_expln); 268 } 269 #endif /* DHCHAP_SUPPORT */ 270 } 271 break; 272 273 274 case ELS_CMD_PRLI: /* Process Log In failed */ 275 ndlp = emlxs_node_find_did(port, did); 276 277 if (ndlp && ndlp->nlp_active) { 278 /* Open the node again */ 279 emlxs_node_open(port, ndlp, 280 FC_FCP_RING); 281 } 282 break; 283 284 case ELS_CMD_FDISC: /* Fabric login */ 285 case ELS_CMD_FLOGI: /* Fabric login */ 286 if (pkt->pkt_state == FC_PKT_LS_RJT) { 287 /* 288 * This will cause ULP to retry FLOGI 289 * requests 290 */ 291 pkt->pkt_reason = FC_REASON_QFULL; 292 pkt->pkt_expln = 0; 293 294 #ifdef DHCHAP_SUPPORT 295 ndlp = emlxs_node_find_did(port, did); 296 if (ndlp && ndlp->nlp_active) { 297 emlxs_dhc_state(port, ndlp, 298 NODE_STATE_NOCHANGE, 299 pkt->pkt_reason, 300 pkt->pkt_expln); 301 } 302 #endif /* DHCHAP_SUPPORT */ 303 } 304 break; 305 306 default: 307 break; 308 } 309 310 emlxs_pkt_complete(sbp, iocb->ulpStatus, 311 iocb->un.grsp.perr.statLocalError, 1); 312 313 } 314 315 316 break; 317 318 default: 319 320 HBASTATS.ElsStray++; 321 322 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_els_msg, 323 "Invalid iocb: cmd=0x%x", iocb->ulpCommand); 324 325 emlxs_pkt_complete(sbp, iocb->ulpStatus, 326 iocb->un.grsp.perr.statLocalError, 1); 327 328 break; 329 } /* switch(iocb->ulpCommand) */ 330 331 return (0); 332 333 } /* emlxs_els_handle_event() */ 334 335 336 extern int 337 emlxs_els_handle_unsol_req(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 338 MATCHMAP *mp, uint32_t size) 339 { 340 emlxs_hba_t *hba = HBA; 341 uint32_t cmd_code; 342 343 HBASTATS.ElsCmdReceived++; 344 345 cmd_code = *((uint32_t *)mp->virt) & ELS_CMD_MASK; 346 347 switch (cmd_code) { 348 case ELS_CMD_RSCN: 349 HBASTATS.ElsRscnReceived++; 350 emlxs_handle_unsol_rscn(port, rp, iocbq, mp, size); 351 break; 352 353 case ELS_CMD_FLOGI: 354 HBASTATS.ElsFlogiReceived++; 355 emlxs_handle_unsol_flogi(port, rp, iocbq, mp, size); 356 break; 357 358 case ELS_CMD_PLOGI: 359 HBASTATS.ElsPlogiReceived++; 360 emlxs_handle_unsol_plogi(port, rp, iocbq, mp, size); 361 break; 362 363 case ELS_CMD_PRLI: 364 HBASTATS.ElsPrliReceived++; 365 emlxs_handle_unsol_prli(port, rp, iocbq, mp, size); 366 break; 367 368 case ELS_CMD_PRLO: 369 HBASTATS.ElsPrloReceived++; 370 emlxs_handle_unsol_prlo(port, rp, iocbq, mp, size); 371 break; 372 373 case ELS_CMD_LOGO: 374 HBASTATS.ElsLogoReceived++; 375 emlxs_handle_unsol_logo(port, rp, iocbq, mp, size); 376 break; 377 378 case ELS_CMD_ADISC: 379 HBASTATS.ElsAdiscReceived++; 380 emlxs_handle_unsol_adisc(port, rp, iocbq, mp, size); 381 break; 382 383 case ELS_CMD_AUTH: 384 HBASTATS.ElsAuthReceived++; 385 emlxs_handle_unsol_auth(port, rp, iocbq, mp, size); 386 break; 387 388 default: 389 HBASTATS.ElsGenReceived++; 390 emlxs_handle_unsol_gen_cmd(port, rp, iocbq, mp, size); 391 break; 392 } 393 394 return (0); 395 396 } /* emlxs_els_handle_unsol_req() */ 397 398 399 static void 400 emlxs_handle_sol_flogi(emlxs_port_t *port, emlxs_buf_t *sbp) 401 { 402 emlxs_hba_t *hba = HBA; 403 emlxs_config_t *cfg = &CFG; 404 emlxs_port_t *vport; 405 SERV_PARM *sp; 406 fc_packet_t *pkt; 407 MAILBOXQ *mbox; 408 uint32_t did; 409 IOCBQ *iocbq; 410 IOCB *iocb; 411 char buffer[64]; 412 uint32_t i; 413 414 pkt = PRIV2PKT(sbp); 415 sp = (SERV_PARM *)((caddr_t)pkt->pkt_resp + sizeof (uint32_t)); 416 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 417 iocbq = &sbp->iocbq; 418 iocb = &iocbq->iocb; 419 420 if (sp->cmn.fPort) { 421 mutex_enter(&EMLXS_PORT_LOCK); 422 423 hba->flag |= FC_FABRIC_ATTACHED; 424 hba->flag &= ~FC_PT_TO_PT; 425 426 /* Save our new port ID */ 427 port->did = iocb->un.elsreq.myID; 428 pkt->pkt_resp_fhdr.s_id = SWAP_DATA24_LO(Fabric_DID); 429 pkt->pkt_resp_fhdr.d_id = SWAP_DATA24_LO(port->did); 430 431 /* Save E_D_TOV ticks in nanoseconds */ 432 if (sp->cmn.edtovResolution) { 433 hba->fc_edtov = 434 (SWAP_DATA32(sp->cmn.e_d_tov) + 999999) / 1000000; 435 } else { 436 hba->fc_edtov = SWAP_DATA32(sp->cmn.e_d_tov); 437 } 438 439 /* Save R_A_TOV ticks */ 440 hba->fc_ratov = (SWAP_DATA32(sp->cmn.w2.r_a_tov) + 999) / 1000; 441 442 if (hba->topology != TOPOLOGY_LOOP) { 443 /* 444 * If we are a N-port connected to a Fabric, fixup 445 * sparam's so logins to devices on remote loops 446 * work. 447 */ 448 hba->sparam.cmn.altBbCredit = 1; 449 450 /* Set this bit in all the port sparam copies */ 451 for (i = 0; i < MAX_VPORTS; i++) { 452 vport = &VPORT(i); 453 454 if (!(vport->flag & EMLXS_PORT_BOUND)) { 455 continue; 456 } 457 vport->sparam.cmn.altBbCredit = 1; 458 } 459 } 460 #ifdef NPIV_SUPPORT 461 if (sp->cmn.rspMultipleNPort) { 462 hba->flag |= FC_NPIV_SUPPORTED; 463 464 if (cfg[CFG_NPIV_DELAY].current) { 465 /* 466 * PATCH: for NPIV support on Brocade switch 467 * firmware 5.10b 468 */ 469 if ((hba->flag & FC_NPIV_ENABLED) && 470 ((sp->nodeName.IEEE[0] == 0x00) && 471 (sp->nodeName.IEEE[1] == 0x05) && 472 (sp->nodeName.IEEE[2] == 0x1e))) { 473 hba->flag |= FC_NPIV_DELAY_REQUIRED; 474 } 475 } 476 } else { 477 hba->flag |= FC_NPIV_UNSUPPORTED; 478 } 479 480 if (!(hba->flag & FC_NPIV_ENABLED)) { 481 (void) strcpy(buffer, "npiv:Disabled "); 482 } else if (hba->flag & FC_NPIV_SUPPORTED) { 483 (void) strcpy(buffer, "npiv:Supported "); 484 } else { 485 (void) strcpy(buffer, "npiv:Unsupported "); 486 } 487 #else 488 buffer[0] = 0; 489 #endif /* NPIV_SUPPORT */ 490 491 /* Save the fabric service parameters */ 492 bcopy((void *)sp, (void *)&port->fabric_sparam, 493 sizeof (SERV_PARM)); 494 495 #ifdef DHCHAP_SUPPORT 496 if (!sp->cmn.fcsp_support) { 497 (void) strcat(buffer, "fcsp:Unsupported"); 498 } else if (cfg[CFG_AUTH_ENABLE].current && 499 (port->vpi == 0 || cfg[CFG_AUTH_NPIV].current)) { 500 (void) strcat(buffer, "fcsp:Supported"); 501 } else { 502 (void) strcat(buffer, "fcsp:Disabled"); 503 } 504 #endif /* DHCHAP_SUPPORT */ 505 506 mutex_exit(&EMLXS_PORT_LOCK); 507 508 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 509 "FLOGI: did=%x sid=%x %s", 510 did, port->did, buffer); 511 512 /* Update our service parms */ 513 if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba, 514 MEM_MBOX | MEM_PRI))) { 515 emlxs_mb_config_link(hba, (MAILBOX *) mbox); 516 517 if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mbox, 518 MBX_NOWAIT, 0) != MBX_BUSY) { 519 (void) emlxs_mem_put(hba, MEM_MBOX, 520 (uint8_t *)mbox); 521 } 522 } 523 /* Preset the state for the reg_did */ 524 emlxs_set_pkt_state(sbp, IOSTAT_SUCCESS, 0, 1); 525 526 if (emlxs_mb_reg_did(port, Fabric_DID, &port->fabric_sparam, 527 sbp, NULL, NULL) == 0) { 528 /* 529 * Deferred completion of this pkt until login is 530 * complete 531 */ 532 return; 533 } 534 emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 535 IOERR_NO_RESOURCES, 1); 536 537 } else { /* No switch */ 538 mutex_enter(&EMLXS_PORT_LOCK); 539 540 hba->flag &= ~FC_FABRIC_ATTACHED; 541 hba->flag |= FC_PT_TO_PT; 542 543 /* Save E_D_TOV ticks in nanoseconds */ 544 if (sp->cmn.edtovResolution) { 545 hba->fc_edtov = 546 (SWAP_DATA32(sp->cmn.e_d_tov) + 999999) / 1000000; 547 } else { 548 hba->fc_edtov = SWAP_DATA32(sp->cmn.e_d_tov); 549 } 550 551 /* Save R_A_TOV ticks */ 552 hba->fc_ratov = (SWAP_DATA32(sp->cmn.w2.r_a_tov) + 999) / 1000; 553 554 #ifdef NPIV_SUPPORT 555 hba->flag &= ~FC_NPIV_SUPPORTED; 556 (void) strcpy(buffer, "npiv:Disabled. P2P"); 557 #else 558 (void) strcpy(buffer, "P2P"); 559 #endif /* NPIV_SUPPORT */ 560 561 /* Clear the fabric service parameters */ 562 bzero((void *)&port->fabric_sparam, sizeof (SERV_PARM)); 563 564 mutex_exit(&EMLXS_PORT_LOCK); 565 566 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 567 "FLOGI: did=%x sid=%x %s", 568 did, port->did, buffer); 569 570 emlxs_pkt_complete(sbp, IOSTAT_SUCCESS, 0, 1); 571 } 572 573 return; 574 575 } /* emlxs_handle_sol_flogi() */ 576 577 578 static void 579 emlxs_handle_sol_fdisk(emlxs_port_t *port, emlxs_buf_t *sbp) 580 { 581 emlxs_hba_t *hba = HBA; 582 emlxs_config_t *cfg = &CFG; 583 SERV_PARM *sp; 584 fc_packet_t *pkt; 585 MAILBOXQ *mbox; 586 uint32_t did; 587 IOCBQ *iocbq; 588 IOCB *iocb; 589 char buffer[64]; 590 591 pkt = PRIV2PKT(sbp); 592 sp = (SERV_PARM *)((caddr_t)pkt->pkt_resp + sizeof (uint32_t)); 593 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 594 iocbq = &sbp->iocbq; 595 iocb = &iocbq->iocb; 596 597 mutex_enter(&EMLXS_PORT_LOCK); 598 599 /* Save our new port ID */ 600 port->did = iocb->un.elsreq.myID; 601 pkt->pkt_resp_fhdr.d_id = SWAP_DATA24_LO(port->did); 602 603 /* Save the fabric service parameters */ 604 bcopy((void *)sp, (void *)&port->fabric_sparam, sizeof (SERV_PARM)); 605 606 mutex_exit(&EMLXS_PORT_LOCK); 607 608 buffer[0] = 0; 609 610 #ifdef DHCHAP_SUPPORT 611 if (!sp->cmn.fcsp_support) { 612 (void) strcat(buffer, "fcsp:Unsupported"); 613 } else if (cfg[CFG_AUTH_ENABLE].current && 614 cfg[CFG_AUTH_NPIV].current) { 615 (void) strcat(buffer, "fcsp:Supported"); 616 } else { 617 (void) strcat(buffer, "fcsp:Disabled"); 618 } 619 #endif /* DHCHAP_SUPPORT */ 620 621 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 622 "FDISK: did=%x sid=%x %s", 623 did, port->did, buffer); 624 625 /* Update our service parms */ 626 if ((mbox = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) { 627 emlxs_mb_config_link(hba, (MAILBOX *) mbox); 628 629 if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mbox, 630 MBX_NOWAIT, 0) != MBX_BUSY) { 631 (void) emlxs_mem_put(hba, MEM_MBOX, (uint8_t *)mbox); 632 } 633 } 634 /* Preset the state for the reg_did */ 635 emlxs_set_pkt_state(sbp, IOSTAT_SUCCESS, 0, 1); 636 637 if (emlxs_mb_reg_did(port, Fabric_DID, &port->fabric_sparam, sbp, 638 NULL, NULL) == 0) { 639 /* 640 * Deferred completion of this pkt until login is complete 641 */ 642 643 return; 644 } 645 emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, IOERR_NO_RESOURCES, 1); 646 647 return; 648 649 } /* emlxs_handle_sol_fdisk() */ 650 651 652 static void 653 emlxs_handle_sol_plogi(emlxs_port_t *port, emlxs_buf_t *sbp) 654 { 655 emlxs_hba_t *hba = HBA; 656 emlxs_config_t *cfg = &CFG; 657 SERV_PARM *sp; 658 fc_packet_t *pkt; 659 uint32_t did; 660 uint32_t sid; 661 NODELIST *ndlp; 662 char buffer[64]; 663 664 pkt = PRIV2PKT(sbp); 665 sp = (SERV_PARM *)((caddr_t)pkt->pkt_resp + sizeof (uint32_t)); 666 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 667 sid = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.s_id); 668 669 buffer[0] = 0; 670 671 #ifdef DHCHAP_SUPPORT 672 if (!sp->cmn.fcsp_support) { 673 (void) strcat(buffer, "fcsp:Unsupported"); 674 } else if (cfg[CFG_AUTH_ENABLE].current && cfg[CFG_AUTH_E2E].current && 675 (port->vpi == 0 || cfg[CFG_AUTH_NPIV].current)) { 676 (void) strcat(buffer, "fcsp:Supported"); 677 } else { 678 (void) strcat(buffer, "fcsp:Disabled"); 679 } 680 #endif /* DHCHAP_SUPPORT */ 681 682 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 683 "PLOGI: sid=%x did=%x %s", 684 sid, did, buffer); 685 686 /* Preset the pkt state for reg_did */ 687 emlxs_set_pkt_state(sbp, IOSTAT_SUCCESS, 0, 1); 688 689 /* 690 * Do register login to Firmware before calling packet completion 691 */ 692 if (emlxs_mb_reg_did(port, did, sp, sbp, NULL, NULL) == 0) { 693 /* 694 * Deferred completion of this pkt until login is complete 695 */ 696 return; 697 } 698 ndlp = emlxs_node_find_did(port, did); 699 700 if (ndlp && ndlp->nlp_active) { 701 /* Open the node again */ 702 emlxs_node_open(port, ndlp, FC_FCP_RING); 703 emlxs_node_open(port, ndlp, FC_IP_RING); 704 } 705 emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, IOERR_NO_RESOURCES, 1); 706 707 return; 708 709 } /* emlxs_handle_sol_plogi() */ 710 711 712 static void 713 emlxs_handle_sol_adisc(emlxs_port_t *port, emlxs_buf_t *sbp) 714 { 715 fc_packet_t *pkt; 716 uint32_t did; 717 NODELIST *ndlp; 718 719 pkt = PRIV2PKT(sbp); 720 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 721 722 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 723 "ADISC: did=%x", 724 did); 725 726 ndlp = emlxs_node_find_did(port, did); 727 728 if (ndlp && ndlp->nlp_active) { 729 /* Open the node again */ 730 emlxs_node_open(port, ndlp, FC_FCP_RING); 731 emlxs_node_open(port, ndlp, FC_IP_RING); 732 } 733 emlxs_pkt_complete(sbp, IOSTAT_SUCCESS, 0, 1); 734 735 return; 736 737 } /* emlxs_handle_sol_adisc() */ 738 739 740 static void 741 emlxs_handle_sol_prli(emlxs_port_t *port, emlxs_buf_t *sbp) 742 { 743 emlxs_hba_t *hba = HBA; 744 emlxs_config_t *cfg = &CFG; 745 fc_packet_t *pkt; 746 NODELIST *ndlp; 747 uint32_t did; 748 PRLI *npr; 749 uint32_t task_retry_id; 750 751 pkt = PRIV2PKT(sbp); 752 npr = (PRLI *)((caddr_t)pkt->pkt_resp + sizeof (uint32_t)); 753 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 754 755 ndlp = emlxs_node_find_did(port, did); 756 757 if (ndlp && ndlp->nlp_active) { 758 /* Check for FCP support */ 759 if ((npr->acceptRspCode == PRLI_REQ_EXECUTED) && 760 (npr->prliType == PRLI_FCP_TYPE)) { 761 /* Check for target */ 762 if (npr->targetFunc) { 763 ndlp->nlp_fcp_info |= NLP_FCP_TGT_DEVICE; 764 } else { 765 ndlp->nlp_fcp_info &= ~NLP_FCP_TGT_DEVICE; 766 } 767 768 /* Check for initiator */ 769 if (npr->initiatorFunc) { 770 ndlp->nlp_fcp_info |= NLP_FCP_INI_DEVICE; 771 } else { 772 ndlp->nlp_fcp_info &= ~NLP_FCP_INI_DEVICE; 773 } 774 775 /* 776 * If TRI support is not required then force the 777 * task_retry_id value to one 778 */ 779 if (cfg[CFG_TRI_REQUIRED].current == 0) { 780 task_retry_id = 1; 781 } else { 782 task_retry_id = npr->TaskRetryIdReq; 783 } 784 785 /* Check for FCP2 target support */ 786 /* Retry and TaskRetryId bits are both required here */ 787 if (npr->targetFunc && npr->Retry && task_retry_id) { 788 ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; 789 } else { 790 ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; 791 } 792 } 793 /* Open the node again */ 794 emlxs_node_open(port, ndlp, FC_FCP_RING); 795 796 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 797 "PRLI: did=%x info=%02x", 798 did, ndlp->nlp_fcp_info); 799 800 /* 801 * Report PRLI completion 802 */ 803 emlxs_pkt_complete(sbp, IOSTAT_SUCCESS, 0, 1); 804 805 } else { 806 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 807 "PRLI: did=%x: Node not found. Failing.", 808 did); 809 810 /* 811 * Report PRLI failed 812 */ 813 emlxs_pkt_complete(sbp, IOSTAT_LOCAL_REJECT, 814 IOERR_INVALID_RPI, 1); 815 } 816 817 return; 818 819 } /* emlxs_handle_sol_prli() */ 820 821 822 static void 823 emlxs_handle_sol_logo(emlxs_port_t *port, emlxs_buf_t *sbp) 824 { 825 fc_packet_t *pkt; 826 uint32_t did; 827 NODELIST *ndlp; 828 829 pkt = PRIV2PKT(sbp); 830 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 831 832 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 833 "LOGO: did=%x", 834 did); 835 836 ndlp = emlxs_node_find_did(port, did); 837 838 if (ndlp && ndlp->nlp_active) { 839 /* Close the node for any further normal IO */ 840 emlxs_node_close(port, ndlp, FC_FCP_RING, 60); 841 emlxs_node_close(port, ndlp, FC_IP_RING, 60); 842 843 /* Flush tx queues */ 844 (void) emlxs_tx_node_flush(port, ndlp, 0, 0, 0); 845 846 /* Flush chip queues */ 847 (void) emlxs_chipq_node_flush(port, 0, ndlp, 0); 848 } 849 emlxs_pkt_complete(sbp, IOSTAT_SUCCESS, 0, 1); 850 851 return; 852 853 } /* emlxs_handle_sol_logo() */ 854 855 856 /* ARGSUSED */ 857 static void 858 emlxs_handle_unsol_rscn(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 859 MATCHMAP *mp, uint32_t size) 860 { 861 uint32_t *lp; 862 fc_unsol_buf_t *ubp; 863 uint8_t *bp; 864 IOCB *iocb; 865 uint32_t count; 866 uint32_t sid; 867 emlxs_ub_priv_t *ub_priv; 868 869 iocb = &iocbq->iocb; 870 bp = mp->virt; 871 lp = (uint32_t *)bp; 872 sid = iocb->un.elsreq.remoteID; 873 874 /* Log the event */ 875 emlxs_log_rscn_event(port, bp, size); 876 877 count = ((size - 4) / 4); 878 879 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 1); 880 881 if (ubp == NULL) { 882 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 883 "RSCN rcvd: sid=%x %d page(s): %08X, %08X. Rejecting.", 884 sid, count, SWAP_DATA32(*lp), 885 ((count > 1) ? SWAP_DATA32(*(lp + 1)) : 0)); 886 887 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 888 ELS_CMD_RSCN, LSRJT_LOGICAL_BSY, 889 LSEXP_OUT_OF_RESOURCE); 890 891 goto drop_it; 892 } 893 bcopy(bp, ubp->ub_buffer, size); 894 ub_priv = ubp->ub_fca_private; 895 ub_priv->cmd = ELS_CMD_RSCN; 896 897 /* 898 * Setup frame header 899 */ 900 ubp->ub_frame.r_ctl = FC_ELS_REQ; 901 ubp->ub_frame.type = FC_ELS_DATA; 902 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 903 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 904 ubp->ub_frame.ox_id = ub_priv->token; 905 ubp->ub_frame.rx_id = iocb->ulpContext; 906 ubp->ub_class = FC_TRAN_CLASS3; 907 908 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 909 "RSCN: sid=%x %d page(s): %08X, %08X buffer=%p token=%x.", 910 sid, count, SWAP_DATA32(*lp), 911 ((count > 1) ? SWAP_DATA32(*(lp + 1)) : 0), ubp, ub_priv->token); 912 913 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 914 emlxs_swap_els_ub(ubp); 915 #endif /* EMLXS_MODREV2X */ 916 917 emlxs_ub_callback(port, ubp); 918 919 drop_it: 920 921 return; 922 923 } /* emlxs_handle_unsol_rscn() */ 924 925 926 /* This is shared by FCT driver */ 927 extern uint32_t 928 emlxs_process_unsol_flogi(emlxs_port_t *port, IOCBQ *iocbq, 929 MATCHMAP *mp, uint32_t size, char *buffer) 930 { 931 emlxs_hba_t *hba = HBA; 932 emlxs_config_t *cfg = &CFG; 933 uint8_t *bp; 934 IOCB *iocb; 935 uint32_t sid; 936 SERV_PARM *sp; 937 938 iocb = &iocbq->iocb; 939 sid = iocb->un.elsreq.remoteID; 940 941 /* Check payload size */ 942 if (size < (sizeof (SERV_PARM) + 4)) { 943 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 944 "FLOGI: sid=%x. Payload too small. %d<%d Rejecting.", 945 sid, size, (sizeof (SERV_PARM) + 4)); 946 947 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 948 ELS_CMD_FLOGI, LSRJT_PROTOCOL_ERR, LSEXP_NOTHING_MORE); 949 950 return (1); 951 } 952 bp = mp->virt; 953 sp = (SERV_PARM *)(bp + sizeof (uint32_t)); 954 955 mutex_enter(&EMLXS_PORT_LOCK); 956 957 hba->flag &= ~FC_FABRIC_ATTACHED; 958 hba->flag |= FC_PT_TO_PT; 959 960 /* Save E_D_TOV ticks in nanoseconds */ 961 if (sp->cmn.edtovResolution) { 962 hba->fc_edtov = 963 (SWAP_DATA32(sp->cmn.e_d_tov) + 999999) / 1000000; 964 } else { 965 hba->fc_edtov = SWAP_DATA32(sp->cmn.e_d_tov); 966 } 967 968 /* Save R_A_TOV ticks */ 969 hba->fc_ratov = (SWAP_DATA32(sp->cmn.w2.r_a_tov) + 999) / 1000; 970 971 buffer[0] = 0; 972 973 #ifdef NPIV_SUPPORT 974 hba->flag &= ~FC_NPIV_SUPPORTED; 975 (void) strcpy(buffer, "npiv:Disabled. P2P "); 976 #else 977 (void) strcpy(buffer, "P2P "); 978 #endif /* NPIV_SUPPORT */ 979 980 #ifdef DHCHAP_SUPPORT 981 if (!sp->cmn.fcsp_support) { 982 (void) strcat(buffer, "fcsp:Unsupported"); 983 } else if (cfg[CFG_AUTH_ENABLE].current && 984 (port->vpi == 0 || cfg[CFG_AUTH_NPIV].current)) { 985 (void) strcat(buffer, "fcsp:Supported"); 986 } else { 987 (void) strcat(buffer, "fcsp:Disabled"); 988 } 989 #endif /* DHCHAP_SUPPORT */ 990 991 /* Clear the fabric service parameters */ 992 bzero((void *) &port->fabric_sparam, sizeof (SERV_PARM)); 993 994 mutex_exit(&EMLXS_PORT_LOCK); 995 996 return (0); 997 998 } /* emlxs_process_unsol_flogi() */ 999 1000 1001 /* ARGSUSED */ 1002 static void 1003 emlxs_handle_unsol_flogi(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1004 MATCHMAP *mp, uint32_t size) 1005 { 1006 uint8_t *bp; 1007 fc_unsol_buf_t *ubp; 1008 IOCB *iocb; 1009 uint32_t sid; 1010 emlxs_ub_priv_t *ub_priv; 1011 char buffer[64]; 1012 1013 buffer[0] = 0; 1014 1015 /* Perform processing of FLOGI payload */ 1016 if (emlxs_process_unsol_flogi(port, iocbq, mp, size, buffer)) { 1017 return; 1018 } 1019 iocb = &iocbq->iocb; 1020 sid = iocb->un.elsreq.remoteID; 1021 bp = mp->virt; 1022 size = sizeof (SERV_PARM) + 4; 1023 1024 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 0); 1025 1026 if (ubp == NULL) { 1027 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 1028 "FLOGI rcvd: sid=%x. Rejecting.", 1029 sid); 1030 1031 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1032 ELS_CMD_FLOGI, LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE); 1033 1034 goto drop_it; 1035 } 1036 /* 1037 * Setup unsolicited buffer and pass it up 1038 */ 1039 bcopy(bp, ubp->ub_buffer, size); 1040 ub_priv = ubp->ub_fca_private; 1041 ub_priv->cmd = ELS_CMD_FLOGI; 1042 1043 /* 1044 * Setup frame header 1045 */ 1046 ubp->ub_frame.r_ctl = FC_ELS_REQ; 1047 ubp->ub_frame.type = FC_ELS_DATA; 1048 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 1049 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 1050 ubp->ub_frame.ox_id = ub_priv->token; 1051 ubp->ub_frame.rx_id = iocb->ulpContext; 1052 ubp->ub_class = FC_TRAN_CLASS3; 1053 1054 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1055 "FLOGI: sid=%x buffer=%p token=%x %s", 1056 sid, ubp, ub_priv->token, buffer); 1057 1058 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 1059 emlxs_swap_els_ub(ubp); 1060 #endif /* EMLXS_MODREV2X */ 1061 1062 emlxs_ub_callback(port, ubp); 1063 1064 drop_it: 1065 1066 return; 1067 1068 } /* emlxs_handle_unsol_flogi() */ 1069 1070 1071 1072 /* This is shared by FCT driver */ 1073 extern uint32_t 1074 emlxs_process_unsol_plogi(emlxs_port_t *port, IOCBQ *iocbq, 1075 MATCHMAP *mp, uint32_t size, char *buffer) 1076 { 1077 emlxs_hba_t *hba = HBA; 1078 emlxs_config_t *cfg = &CFG; 1079 uint8_t *bp; 1080 IOCB *iocb; 1081 uint32_t sid; 1082 SERV_PARM *sp; 1083 MAILBOXQ *mbox; 1084 1085 iocb = &iocbq->iocb; 1086 sid = iocb->un.elsreq.remoteID; 1087 1088 if (size < (sizeof (SERV_PARM) + 4)) { 1089 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1090 "PLOGI: sid=%x. Payload too small. %d<%d Rejecting.", 1091 sid, size, (sizeof (SERV_PARM) + 4)); 1092 1093 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1094 ELS_CMD_PLOGI, LSRJT_PROTOCOL_ERR, LSEXP_NOTHING_MORE); 1095 1096 return (1); 1097 } 1098 bp = mp->virt; 1099 sp = (SERV_PARM *)(bp + sizeof (uint32_t)); 1100 1101 #ifdef NPIV_SUPPORT 1102 if ((hba->flag & FC_NPIV_ENABLED) && 1103 (hba->flag & FC_NPIV_SUPPORTED) && 1104 (port->flag & EMLXS_PORT_RESTRICTED)) { 1105 uint32_t reject_it = 0; 1106 1107 /* Check for Emulex adapters */ 1108 if (sp->valid_vendor_version) { 1109 emlxs_vvl_fmt_t vvl; 1110 1111 bcopy((caddr_t *)&sp->vendorVersion[0], 1112 (caddr_t *)&vvl, sizeof (emlxs_vvl_fmt_t)); 1113 vvl.un0.word0 = SWAP_DATA32(vvl.un0.word0); 1114 vvl.un1.word1 = SWAP_DATA32(vvl.un1.word1); 1115 1116 if (vvl.un0.w0.oui == 0x0000C9) { 1117 if (port->vpi || vvl.un1.w1.vport) { 1118 reject_it = 1; 1119 } 1120 } 1121 } 1122 /* 1123 * If we are a virtual port and the remote device is not a 1124 * switch, then reject it 1125 */ 1126 else if (port->vpi && ((sid & Fabric_DID_MASK) != 1127 Fabric_DID_MASK)) { 1128 reject_it = 1; 1129 } 1130 if (reject_it) { 1131 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1132 "PLOGI rcvd: sid=%x. Restricted. Rejecting.", 1133 sid); 1134 1135 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1136 ELS_CMD_PLOGI, LSRJT_UNABLE_TPC, 1137 LSEXP_NOTHING_MORE); 1138 1139 /* 1140 * We still need to do reg_did and unreg_did to free 1141 * up rpi 1142 */ 1143 (void) emlxs_mb_reg_did(port, sid, sp, NULL, NULL, 1144 (IOCBQ *)1); 1145 1146 return (1); 1147 } 1148 } 1149 #endif /* NPIV_SUPPORT */ 1150 1151 #ifdef DHCHAP_SUPPORT 1152 if (emlxs_dhc_verify_login(port, sid, sp)) { 1153 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1154 "PLOGI: sid=%x. FCSP disabled. Rejecting.", 1155 sid); 1156 1157 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1158 ELS_CMD_PLOGI, LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE); 1159 1160 return (1); 1161 } 1162 if (!sp->cmn.fcsp_support) { 1163 (void) strcat(buffer, "fcsp:Unsupported"); 1164 } else if (cfg[CFG_AUTH_ENABLE].current && cfg[CFG_AUTH_E2E].current && 1165 (port->vpi == 0 || cfg[CFG_AUTH_NPIV].current)) { 1166 (void) strcat(buffer, "fcsp:Supported"); 1167 } else { 1168 (void) strcat(buffer, "fcsp:Disabled"); 1169 } 1170 #endif /* DHCHAP_SUPPORT */ 1171 1172 /* Check if this was a point to point Plogi */ 1173 if (hba->flag & FC_PT_TO_PT) { 1174 mutex_enter(&EMLXS_PORT_LOCK); 1175 1176 /* Save our new port ID */ 1177 port->did = iocb->un.elsreq.myID; 1178 1179 /* Save E_D_TOV ticks in nanoseconds */ 1180 if (sp->cmn.edtovResolution) { 1181 hba->fc_edtov = 1182 (SWAP_DATA32(sp->cmn.e_d_tov) + 999999) / 1000000; 1183 } else { 1184 hba->fc_edtov = SWAP_DATA32(sp->cmn.e_d_tov); 1185 } 1186 1187 /* Save R_A_TOV ticks */ 1188 hba->fc_ratov = (SWAP_DATA32(sp->cmn.w2.r_a_tov) + 999) / 1000; 1189 1190 mutex_exit(&EMLXS_PORT_LOCK); 1191 1192 /* Update our service parms */ 1193 if ((mbox = (MAILBOXQ *) 1194 emlxs_mem_get(hba, MEM_MBOX | MEM_PRI))) { 1195 emlxs_mb_config_link(hba, (MAILBOX *) mbox); 1196 1197 if (emlxs_mb_issue_cmd(hba, (MAILBOX *)mbox, 1198 MBX_NOWAIT, 0) != MBX_BUSY) { 1199 (void) emlxs_mem_put(hba, MEM_MBOX, 1200 (uint8_t *)mbox); 1201 } 1202 } 1203 } 1204 return (0); 1205 1206 } /* emlxs_process_unsol_plogi() */ 1207 1208 1209 /* ARGSUSED */ 1210 static void 1211 emlxs_handle_unsol_plogi(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1212 MATCHMAP *mp, uint32_t size) 1213 { 1214 fc_unsol_buf_t *ubp; 1215 uint8_t *bp; 1216 IOCB *iocb; 1217 uint32_t sid; 1218 uint32_t did; 1219 emlxs_ub_priv_t *ub_priv; 1220 SERV_PARM *sp; 1221 char buffer[64]; 1222 1223 buffer[0] = 0; 1224 1225 /* Perform processing of PLOGI payload */ 1226 if (emlxs_process_unsol_plogi(port, iocbq, mp, size, buffer)) { 1227 return; 1228 } 1229 iocb = &iocbq->iocb; 1230 sid = iocb->un.elsreq.remoteID; 1231 did = iocb->un.elsreq.myID; 1232 bp = mp->virt; 1233 sp = (SERV_PARM *)(bp + sizeof (uint32_t)); 1234 size = sizeof (SERV_PARM) + 4; 1235 1236 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 0); 1237 1238 if (ubp == NULL) { 1239 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 1240 "PLOGI rcvd: sid=%x. Rejecting.", 1241 sid); 1242 1243 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1244 ELS_CMD_PLOGI, LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE); 1245 1246 goto drop_it; 1247 } 1248 /* 1249 * Setup unsolicited buffer and pass it up 1250 */ 1251 bcopy(bp, ubp->ub_buffer, size); 1252 ub_priv = ubp->ub_fca_private; 1253 ub_priv->cmd = ELS_CMD_PLOGI; 1254 1255 /* 1256 * Setup frame header 1257 */ 1258 ubp->ub_frame.r_ctl = FC_ELS_REQ; 1259 ubp->ub_frame.type = FC_ELS_DATA; 1260 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 1261 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 1262 ubp->ub_frame.ox_id = ub_priv->token; 1263 ubp->ub_frame.rx_id = iocb->ulpContext; 1264 ubp->ub_class = FC_TRAN_CLASS3; 1265 1266 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1267 "PLOGI: sid=%x did=%x buffer=%p token=%x %s", 1268 sid, did, ubp, ub_priv->token, buffer); 1269 1270 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 1271 emlxs_swap_els_ub(ubp); 1272 #endif /* EMLXS_MODREV2X */ 1273 1274 /* Create a new node and defer callback */ 1275 if (emlxs_mb_reg_did(port, sid, sp, NULL, ubp, NULL) == 0) { 1276 /* 1277 * Defer completion of this pkt until login is complete 1278 */ 1279 goto drop_it; 1280 } 1281 emlxs_ub_callback(port, ubp); 1282 1283 drop_it: 1284 1285 return; 1286 1287 } /* emlxs_handle_unsol_plogi() */ 1288 1289 1290 /* ARGSUSED */ 1291 static void 1292 emlxs_handle_unsol_prli(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1293 MATCHMAP *mp, uint32_t size) 1294 { 1295 IOCB *iocb; 1296 uint32_t sid; 1297 NODELIST *ndlp; 1298 PRLI *npr; 1299 1300 #ifndef ULP_PATCH3 1301 fc_unsol_buf_t *ubp; 1302 emlxs_ub_priv_t *ub_priv; 1303 #endif 1304 1305 iocb = &iocbq->iocb; 1306 sid = iocb->un.elsreq.remoteID; 1307 ndlp = emlxs_node_find_did(port, sid); 1308 1309 if (!ndlp || !ndlp->nlp_active) { 1310 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1311 "PRLI: sid=%x: Node not found. Rejecting.", 1312 sid); 1313 1314 /* Auto reply to PRLI's */ 1315 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1316 ELS_CMD_PRLI, LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE); 1317 1318 goto drop_it; 1319 } 1320 /* If node exists then save FCP2 support */ 1321 npr = (PRLI *)((caddr_t)mp->virt + sizeof (uint32_t)); 1322 1323 /* Check for FCP2 support */ 1324 if ((npr->prliType == PRLI_FCP_TYPE) && npr->targetFunc) { 1325 /* Check for target */ 1326 if (npr->targetFunc) { 1327 ndlp->nlp_fcp_info |= NLP_FCP_TGT_DEVICE; 1328 } else { 1329 ndlp->nlp_fcp_info &= ~NLP_FCP_TGT_DEVICE; 1330 } 1331 1332 /* Check for initiator */ 1333 if (npr->initiatorFunc) { 1334 ndlp->nlp_fcp_info |= NLP_FCP_INI_DEVICE; 1335 } else { 1336 ndlp->nlp_fcp_info &= ~NLP_FCP_INI_DEVICE; 1337 } 1338 1339 /* Check for FCP2 target support */ 1340 if (npr->targetFunc && npr->Retry) { 1341 ndlp->nlp_fcp_info |= NLP_FCP_2_DEVICE; 1342 } else { 1343 ndlp->nlp_fcp_info &= ~NLP_FCP_2_DEVICE; 1344 } 1345 } 1346 #ifdef ULP_PATCH3 1347 1348 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1349 "PRLI: sid=%x. Accepting.", 1350 sid); 1351 1352 /* Auto reply to PRLI's */ 1353 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_PRLI, 0, 0); 1354 1355 #else 1356 1357 /* Tell ULP about it */ 1358 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 0); 1359 1360 if (ubp == NULL) { 1361 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 1362 "PRLI rcvd: sid=%x. Rejecting.", 1363 sid); 1364 1365 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1366 ELS_CMD_PRLI, LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE); 1367 1368 goto drop_it; 1369 } 1370 /* 1371 * Setup unsolicited buffer and pass it up 1372 */ 1373 bcopy(mp->virt, ubp->ub_buffer, size); 1374 ub_priv = ubp->ub_fca_private; 1375 ub_priv->cmd = ELS_CMD_PRLI; 1376 1377 /* 1378 * Setup frame header 1379 */ 1380 ubp->ub_frame.r_ctl = FC_ELS_REQ; 1381 ubp->ub_frame.type = FC_ELS_DATA; 1382 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 1383 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 1384 ubp->ub_frame.ox_id = ub_priv->token; 1385 ubp->ub_frame.rx_id = iocb->ulpContext; 1386 ubp->ub_class = FC_TRAN_CLASS3; 1387 1388 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1389 "PRLI: sid=%x buffer=%p token=%x info=%02x", 1390 sid, ubp, ub_priv->token, ndlp->nlp_fcp_info); 1391 1392 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 1393 emlxs_swap_els_ub(ubp); 1394 #endif /* EMLXS_MODREV2X */ 1395 1396 emlxs_ub_callback(port, ubp); 1397 1398 #endif /* ULP_PATCH3 */ 1399 1400 drop_it: 1401 1402 return; 1403 1404 } /* emlxs_handle_unsol_prli() */ 1405 1406 1407 /* ARGSUSED */ 1408 static void 1409 emlxs_handle_unsol_auth(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1410 MATCHMAP *mp, uint32_t size) 1411 { 1412 IOCB *iocb; 1413 uint32_t sid; 1414 NODELIST *ndlp; 1415 1416 iocb = &iocbq->iocb; 1417 sid = iocb->un.elsreq.remoteID; 1418 1419 #ifdef DHCHAP_SUPPORT 1420 ndlp = emlxs_node_find_did(port, sid); 1421 1422 if (!ndlp || !ndlp->nlp_active) { 1423 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1424 "AUTH: sid=%x: Node not found. Rejecting.", 1425 sid); 1426 1427 /* Auto reply to AUTH_ELS's */ 1428 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1429 ELS_CMD_AUTH, LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE); 1430 1431 goto drop_it; 1432 } 1433 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1434 "AUTH: sid=%x", 1435 sid); 1436 1437 (void) emlxs_dhchap_state_machine(port, rp, iocbq, mp, ndlp, 1438 NODE_EVENT_RCV_AUTH_MSG); 1439 #else 1440 1441 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1442 "AUTH: sid=%x: Rejecting.", 1443 sid); 1444 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, ELS_CMD_AUTH, 1445 LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE); 1446 1447 #endif /* DHCAHP_SUPPORT */ 1448 1449 drop_it: 1450 1451 return; 1452 1453 } /* emlxs_handle_unsol_auth() */ 1454 1455 1456 /* ARGSUSED */ 1457 static void 1458 emlxs_handle_unsol_adisc(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1459 MATCHMAP *mp, uint32_t size) 1460 { 1461 IOCB *iocb; 1462 uint32_t sid; 1463 1464 iocb = &iocbq->iocb; 1465 sid = iocb->un.elsreq.remoteID; 1466 1467 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1468 "ADISC: sid=%x: Accepting.", 1469 sid); 1470 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_ADISC, 0, 0); 1471 1472 return; 1473 1474 } /* emlxs_handle_unsol_adisc() */ 1475 1476 1477 /* ARGSUSED */ 1478 static void 1479 emlxs_handle_unsol_prlo(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1480 MATCHMAP *mp, uint32_t size) 1481 { 1482 emlxs_hba_t *hba = HBA; 1483 IOCB *iocb; 1484 uint32_t sid; 1485 #ifndef ULP_PATCH4 1486 fc_unsol_buf_t *ubp; 1487 emlxs_ub_priv_t *ub_priv; 1488 #endif 1489 1490 #ifdef ULP_PATCH6 1491 NODELIST *ndlp; 1492 #endif 1493 1494 iocb = &iocbq->iocb; 1495 sid = iocb->un.elsreq.remoteID; 1496 1497 #ifdef ULP_PATCH4 1498 #ifdef ULP_PATCH6 1499 1500 /* Get the node */ 1501 ndlp = emlxs_node_find_did(port, sid); 1502 1503 /* Check if this is a SCSI target */ 1504 if (ndlp && (ndlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE)) { 1505 /* This is a SCSI target */ 1506 1507 /* If only one node is present, */ 1508 /* 1509 * then we can conclude that we are direct attached to a 1510 * target 1511 */ 1512 if (port->node_count == 1) { 1513 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1514 "PRLO: sid=%x. Accepting and reseting link.", 1515 sid); 1516 1517 /* Send Acc */ 1518 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, 1519 ELS_CMD_PRLO, 0, 0); 1520 1521 /* Spawn a thread to reset the link */ 1522 (void) thread_create(NULL, 0, emlxs_reset_link_thread, 1523 (char *)hba, 0, &p0, TS_RUN, v.v_maxsyspri - 2); 1524 1525 goto drop_it; 1526 1527 } 1528 /* Check if fabric is present */ 1529 else if (hba->flag & FC_FABRIC_ATTACHED) { 1530 /* Auto reply to PRLO */ 1531 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1532 "PRLO: sid=%x. Accepting and generating RSCN.", 1533 sid); 1534 1535 /* Send Acc */ 1536 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, 1537 ELS_CMD_PRLO, 0, 0); 1538 1539 /* Generate an RSCN to wakeup ULP */ 1540 (void) emlxs_generate_rscn(port, sid); 1541 1542 goto drop_it; 1543 } 1544 } /* SCSI target */ 1545 #endif /* ULP_PATCH6 */ 1546 1547 /* Auto reply to PRLO */ 1548 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1549 "PRLO: sid=%x. Accepting.", 1550 sid); 1551 1552 /* Send Acc */ 1553 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_PRLO, 0, 0); 1554 1555 goto drop_it; 1556 1557 #else /* !ULP_PATCH4 */ 1558 1559 /* Tell ULP about it */ 1560 1561 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 0); 1562 1563 if (ubp == NULL) { 1564 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 1565 "PRLO recvd: sid=%x. Rejecting.", 1566 sid); 1567 1568 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1569 ELS_CMD_PRLO, LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE); 1570 1571 goto drop_it; 1572 } 1573 /* 1574 * Setup unsolicited buffer and pass it up 1575 */ 1576 bcopy(mp->virt, ubp->ub_buffer, size); 1577 ub_priv = ubp->ub_fca_private; 1578 ub_priv->cmd = ELS_CMD_PRLO; 1579 1580 /* 1581 * Setup frame header 1582 */ 1583 ubp->ub_frame.r_ctl = FC_ELS_REQ; 1584 ubp->ub_frame.type = FC_ELS_DATA; 1585 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 1586 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 1587 ubp->ub_frame.ox_id = ub_priv->token; 1588 ubp->ub_frame.rx_id = iocb->ulpContext; 1589 ubp->ub_class = FC_TRAN_CLASS3; 1590 1591 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1592 "PRLO: sid=%x buffeiocbr=%p token=%x.", 1593 sid, ubp, ub_priv->token); 1594 1595 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 1596 emlxs_swap_els_ub(ubp); 1597 #endif /* EMLXS_MODREV2X */ 1598 1599 emlxs_ub_callback(port, ubp); 1600 1601 #endif /* ULP_PATCH4 */ 1602 1603 drop_it: 1604 1605 return; 1606 1607 } /* emlxs_handle_unsol_prlo() */ 1608 1609 1610 /* ARGSUSED */ 1611 static void 1612 emlxs_handle_unsol_logo(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1613 MATCHMAP *mp, uint32_t size) 1614 { 1615 emlxs_hba_t *hba = HBA; 1616 fc_unsol_buf_t *ubp; 1617 IOCB *iocb; 1618 uint32_t sid; 1619 emlxs_ub_priv_t *ub_priv; 1620 uint32_t reply_sent = 0; 1621 1622 #ifdef ULP_PATCH6 1623 NODELIST *ndlp; 1624 #endif 1625 1626 iocb = &iocbq->iocb; 1627 sid = iocb->un.elsreq.remoteID; 1628 1629 #ifdef ULP_PATCH6 1630 1631 ndlp = emlxs_node_find_did(port, sid); 1632 1633 /* Check if this is a SCSI target */ 1634 if (ndlp && (ndlp->nlp_fcp_info & NLP_FCP_TGT_DEVICE)) { 1635 /* This is a SCSI target */ 1636 1637 /* If only one node is present, */ 1638 /* 1639 * then we can conclude that we are direct attached to a 1640 * target 1641 */ 1642 if (port->node_count == 1) { 1643 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1644 "LOGO: sid=%x. Accepting and reseting link.", 1645 sid); 1646 1647 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, 1648 ELS_CMD_LOGO, 0, 0); 1649 1650 /* Spawn a thread to reset the link */ 1651 (void) thread_create(NULL, 0, emlxs_reset_link_thread, 1652 (char *)hba, 0, &p0, TS_RUN, v.v_maxsyspri - 2); 1653 1654 goto drop_it; 1655 } 1656 /* Check if fabric node is present */ 1657 else if (hba->flag & FC_FABRIC_ATTACHED) { 1658 /* Send reply ourselves */ 1659 /* 1660 * We will block all attempts for ULP to reply to a 1661 * LOGO 1662 */ 1663 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1664 "LOGO: sid=%x. Accepting and generating RSCN.", 1665 sid); 1666 1667 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, 1668 ELS_CMD_LOGO, 0, 0); 1669 1670 /* Generate an RSCN to wakeup ULP */ 1671 if (emlxs_generate_rscn(port, sid) == FC_SUCCESS) { 1672 goto drop_it; 1673 } 1674 reply_sent = 1; 1675 } 1676 } /* SCSI target */ 1677 #endif /* ULP_PATCH6 */ 1678 1679 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 1); 1680 1681 if (ubp == NULL) { 1682 if (!reply_sent) { 1683 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 1684 "LOGO rcvd: sid=%x. Rejecting.", 1685 sid); 1686 1687 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, 1688 ELS_CMD_LOGO, LSRJT_LOGICAL_BSY, 1689 LSEXP_OUT_OF_RESOURCE); 1690 } 1691 goto drop_it; 1692 1693 } 1694 /* Setup unsolicited buffer and pass it up */ 1695 bcopy(mp->virt, ubp->ub_buffer, size); 1696 ub_priv = ubp->ub_fca_private; 1697 ub_priv->cmd = ELS_CMD_LOGO; 1698 1699 /* Setup frame header */ 1700 ubp->ub_frame.r_ctl = FC_ELS_REQ; 1701 ubp->ub_frame.type = FC_ELS_DATA; 1702 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 1703 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 1704 ubp->ub_frame.ox_id = ub_priv->token; 1705 ubp->ub_frame.rx_id = iocb->ulpContext; 1706 ubp->ub_class = FC_TRAN_CLASS3; 1707 1708 #ifdef ULP_PATCH2 1709 1710 if (!reply_sent) { 1711 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1712 "LOGO: sid=%x buffer=%p token=%x. Accepting.", 1713 sid, ubp, ub_priv->token); 1714 1715 ub_priv->flags |= EMLXS_UB_REPLY; 1716 1717 /* Send Acc */ 1718 /* 1719 * Send reply ourselves because ULP doesn't always reply to 1720 * these 1721 */ 1722 /* We will block all attempts for ULP to reply to a LOGO */ 1723 (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC, ELS_CMD_LOGO, 1724 0, 0); 1725 reply_sent = 1; 1726 } 1727 #else /* !ULP_PATCH2 */ 1728 1729 if (!reply_sent) { 1730 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1731 "LOGO: sid=%x buffer=%p token=%x.", 1732 sid, ubp, ub_priv->token); 1733 } 1734 #endif /* ULP_PATCH2 */ 1735 1736 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 1737 emlxs_swap_els_ub(ubp); 1738 #endif /* EMLXS_MODREV2X */ 1739 1740 /* Clear the RPI */ 1741 if ((sid & Fabric_DID_MASK) == Fabric_DID_MASK) { 1742 if (emlxs_mb_unreg_did(port, sid, NULL, ubp, NULL) == 0) { 1743 /* 1744 * Deferred completion of this ubp until unreg login 1745 * is complete 1746 */ 1747 1748 return; 1749 } 1750 } 1751 emlxs_ub_callback(port, ubp); 1752 1753 drop_it: 1754 1755 return; 1756 1757 } /* emlxs_handle_unsol_logo() */ 1758 1759 1760 /* ARGSUSED */ 1761 static void 1762 emlxs_handle_unsol_gen_cmd(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 1763 MATCHMAP *mp, uint32_t size) 1764 { 1765 uint8_t *bp; 1766 fc_unsol_buf_t *ubp; 1767 IOCB *iocb; 1768 uint32_t *lp; 1769 uint32_t cmd; 1770 uint32_t sid; 1771 emlxs_ub_priv_t *ub_priv; 1772 1773 iocb = &iocbq->iocb; 1774 sid = iocb->un.elsreq.remoteID; 1775 1776 bp = mp->virt; 1777 lp = (uint32_t *)bp; 1778 cmd = *lp & ELS_CMD_MASK; 1779 1780 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, size, FC_ELS_DATA, 0); 1781 1782 if (ubp == NULL) { 1783 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 1784 "%s rcvd: sid=%x: Rejecting.", 1785 emlxs_elscmd_xlate(cmd), sid); 1786 1787 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd, 1788 LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE); 1789 1790 goto drop_it; 1791 } 1792 bcopy(bp, ubp->ub_buffer, size); 1793 ub_priv = ubp->ub_fca_private; 1794 ub_priv->cmd = cmd; 1795 1796 /* Setup frame header */ 1797 ubp->ub_frame.r_ctl = FC_ELS_REQ; 1798 ubp->ub_frame.type = FC_ELS_DATA; 1799 ubp->ub_frame.s_id = SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 1800 ubp->ub_frame.d_id = SWAP_DATA24_LO(iocb->un.elsreq.myID); 1801 ubp->ub_frame.ox_id = ub_priv->token; 1802 ubp->ub_frame.rx_id = iocb->ulpContext; 1803 ubp->ub_class = FC_TRAN_CLASS3; 1804 1805 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 1806 "%s: sid=%x buffer=%p token=%x.", 1807 emlxs_elscmd_xlate(cmd), sid, ubp, ub_priv->token); 1808 1809 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 1810 emlxs_swap_els_ub(ubp); 1811 #endif /* EMLXS_MODREV2X */ 1812 1813 emlxs_ub_callback(port, ubp); 1814 1815 drop_it: 1816 1817 return; 1818 1819 } /* emlxs_handle_unsol_gen_cmd() */ 1820 1821 1822 /* This handles the reply completions to unsolicited cmds */ 1823 /* ARGSUSED */ 1824 static void 1825 emlxs_handle_acc(emlxs_port_t *port, emlxs_buf_t *sbp, 1826 IOCBQ *iocbq, uint32_t flag) 1827 { 1828 fc_packet_t *pkt; 1829 IOCB *iocb; 1830 uint32_t did; 1831 NODELIST *ndlp; 1832 uint32_t ucmd; 1833 uint32_t cmd; 1834 uint32_t *lp; 1835 1836 iocb = &iocbq->iocb; 1837 pkt = PRIV2PKT(sbp); 1838 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 1839 ucmd = pkt->pkt_cmd_fhdr.ox_id << ELS_CMD_SHIFT; 1840 lp = (uint32_t *)pkt->pkt_cmd; 1841 cmd = *lp & ELS_CMD_MASK; 1842 1843 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 1844 "%s %s: did=%x %s %s", 1845 emlxs_elscmd_xlate(ucmd), emlxs_elscmd_xlate(cmd), 1846 did, emlxs_state_xlate(iocb->ulpStatus), 1847 emlxs_error_xlate(iocb->un.grsp.perr.statLocalError)); 1848 1849 switch (ucmd) { 1850 case ELS_CMD_PLOGI: 1851 case ELS_CMD_ADISC: 1852 1853 ndlp = emlxs_node_find_did(port, did); 1854 1855 if (ndlp && ndlp->nlp_active) { 1856 /* Open the node again */ 1857 emlxs_node_open(port, ndlp, FC_FCP_RING); 1858 emlxs_node_open(port, ndlp, FC_IP_RING); 1859 } 1860 break; 1861 1862 case ELS_CMD_PRLI: 1863 1864 ndlp = emlxs_node_find_did(port, did); 1865 1866 if (ndlp && ndlp->nlp_active) { 1867 /* Open the node again */ 1868 emlxs_node_open(port, ndlp, FC_FCP_RING); 1869 } 1870 break; 1871 } 1872 1873 emlxs_pkt_complete(sbp, iocb->ulpStatus, 1874 iocb->un.grsp.perr.statLocalError, 1); 1875 1876 return; 1877 1878 } /* emlxs_handle_acc() */ 1879 1880 1881 /* This handles the reply completions to unsolicited cmds */ 1882 /* ARGSUSED */ 1883 static void 1884 emlxs_handle_reject(emlxs_port_t *port, emlxs_buf_t *sbp, 1885 IOCBQ *iocbq, uint32_t flag) 1886 { 1887 fc_packet_t *pkt; 1888 IOCB *iocb; 1889 uint32_t did; 1890 NODELIST *ndlp; 1891 uint32_t ucmd; 1892 uint32_t cmd; 1893 uint32_t *lp; 1894 1895 iocb = &iocbq->iocb; 1896 pkt = PRIV2PKT(sbp); 1897 did = SWAP_DATA24_LO(pkt->pkt_cmd_fhdr.d_id); 1898 ucmd = pkt->pkt_cmd_fhdr.ox_id << ELS_CMD_SHIFT; 1899 lp = (uint32_t *)pkt->pkt_cmd; 1900 cmd = *lp & ELS_CMD_MASK; 1901 1902 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_els_completion_msg, 1903 "%s %s: did=%x %s %s", 1904 emlxs_elscmd_xlate(ucmd), emlxs_elscmd_xlate(cmd), 1905 did, emlxs_state_xlate(iocb->ulpStatus), 1906 emlxs_error_xlate(iocb->un.grsp.perr.statLocalError)); 1907 1908 switch (ucmd) { 1909 case ELS_CMD_PLOGI: 1910 1911 ndlp = emlxs_node_find_did(port, did); 1912 1913 if (ndlp && ndlp->nlp_active) { 1914 /* Open the node again */ 1915 emlxs_node_open(port, ndlp, FC_FCP_RING); 1916 emlxs_node_open(port, ndlp, FC_IP_RING); 1917 } 1918 break; 1919 1920 case ELS_CMD_PRLI: 1921 1922 ndlp = emlxs_node_find_did(port, did); 1923 1924 if (ndlp && ndlp->nlp_active) { 1925 /* Open the node again */ 1926 emlxs_node_open(port, ndlp, FC_FCP_RING); 1927 } 1928 break; 1929 } 1930 1931 emlxs_pkt_complete(sbp, iocb->ulpStatus, 1932 iocb->un.grsp.perr.statLocalError, 1); 1933 1934 return; 1935 1936 } /* emlxs_handle_reject() */ 1937 1938 1939 /* ARGSUSED */ 1940 extern int32_t 1941 emlxs_els_reply(emlxs_port_t *port, IOCBQ *iocbq, uint32_t type, 1942 uint32_t type2, uint32_t reason, uint32_t explain) 1943 { 1944 emlxs_hba_t *hba = HBA; 1945 emlxs_config_t *cfg = &CFG; 1946 fc_packet_t *pkt; 1947 ELS_PKT *els; 1948 uint32_t rval; 1949 IOCB *iocb; 1950 1951 iocb = &iocbq->iocb; 1952 1953 switch (type) { 1954 case ELS_CMD_ACC: /* Accept Response */ 1955 1956 /* Allocate the pkt */ 1957 switch (type2) { 1958 case ELS_CMD_FLOGI: 1959 if (!(pkt = emlxs_pkt_alloc(port, 1960 sizeof (uint32_t) + sizeof (SERV_PARM), 1961 0, 0, KM_NOSLEEP))) { 1962 return (1); 1963 } 1964 break; 1965 1966 case ELS_CMD_ADISC: 1967 if (!(pkt = emlxs_pkt_alloc(port, 1968 sizeof (uint32_t) + sizeof (ADISC), 1969 0, 0, KM_NOSLEEP))) { 1970 return (1); 1971 } 1972 break; 1973 1974 case ELS_CMD_PRLI: 1975 if (!(pkt = emlxs_pkt_alloc(port, 1976 sizeof (uint32_t) + sizeof (PRLI), 1977 0, 0, KM_NOSLEEP))) { 1978 return (1); 1979 } 1980 break; 1981 1982 case ELS_CMD_PRLO: 1983 if (!(pkt = emlxs_pkt_alloc(port, 1984 sizeof (uint32_t) + sizeof (PRLO), 1985 0, 0, KM_NOSLEEP))) { 1986 return (1); 1987 } 1988 break; 1989 1990 case ELS_CMD_AUTH: 1991 default: 1992 1993 if (!(pkt = emlxs_pkt_alloc(port, 1994 sizeof (uint32_t), 0, 0, KM_NOSLEEP))) { 1995 return (1); 1996 } 1997 } 1998 1999 /* Common initialization */ 2000 pkt->pkt_tran_type = FC_PKT_OUTBOUND; 2001 pkt->pkt_timeout = (2 * hba->fc_ratov); 2002 2003 if ((uint32_t)iocb->ulpClass == CLASS2) { 2004 pkt->pkt_tran_flags &= ~FC_TRAN_CLASS3; 2005 pkt->pkt_tran_flags |= FC_TRAN_CLASS2; 2006 } 2007 /* Build the fc header */ 2008 pkt->pkt_cmd_fhdr.d_id = 2009 SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 2010 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | 2011 R_CTL_SOLICITED_CONTROL; 2012 pkt->pkt_cmd_fhdr.s_id = 2013 SWAP_DATA24_LO(iocb->un.elsreq.myID); 2014 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 2015 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_XCHG_CONTEXT | 2016 F_CTL_LAST_SEQ | F_CTL_END_SEQ; 2017 pkt->pkt_cmd_fhdr.seq_id = 0; 2018 pkt->pkt_cmd_fhdr.df_ctl = 0; 2019 pkt->pkt_cmd_fhdr.seq_cnt = 0; 2020 pkt->pkt_cmd_fhdr.ox_id = (type2 >> ELS_CMD_SHIFT) & 0xff; 2021 pkt->pkt_cmd_fhdr.rx_id = iocb->ulpContext; 2022 pkt->pkt_cmd_fhdr.ro = 0; 2023 2024 /* 2025 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, "%s ACC 2026 * send. oxid=%x", emlxs_elscmd_xlate(type2), 2027 * pkt->pkt_cmd_fhdr.ox_id); 2028 */ 2029 2030 /* Build the command */ 2031 els = (ELS_PKT *) pkt->pkt_cmd; 2032 els->elsCode = 0x02; 2033 2034 /* Build the payload */ 2035 switch (type2) { 2036 case ELS_CMD_ADISC: 2037 2038 els->un.adisc.hardAL_PA = 2039 (uint8_t)cfg[CFG_ASSIGN_ALPA].current; 2040 bcopy(&port->wwnn, &els->un.adisc.nodeName, 2041 sizeof (NAME_TYPE)); 2042 bcopy(&port->wwpn, &els->un.adisc.portName, 2043 sizeof (NAME_TYPE)); 2044 els->un.adisc.DID = SWAP_DATA24_LO(port->did); 2045 2046 break; 2047 2048 case ELS_CMD_PRLI: 2049 2050 els->elsByte1 = 0x10; 2051 els->elsByte2 = 0; 2052 els->elsByte3 = 0x14; 2053 2054 els->un.prli.prliType = PRLI_FCP_TYPE; 2055 els->un.prli.estabImagePair = 1; 2056 els->un.prli.acceptRspCode = PRLI_REQ_EXECUTED; 2057 2058 if (port->ini_mode) { 2059 els->un.prli.initiatorFunc = 1; 2060 } 2061 if (port->tgt_mode) { 2062 els->un.prli.targetFunc = 1; 2063 } 2064 els->un.prli.readXferRdyDis = 1; 2065 2066 if (hba->vpd.feaLevelHigh >= 0x02) { 2067 els->un.prli.ConfmComplAllowed = 1; 2068 els->un.prli.Retry = 1; 2069 els->un.prli.TaskRetryIdReq = 1; 2070 } else { 2071 els->un.prli.ConfmComplAllowed = 0; 2072 els->un.prli.Retry = 0; 2073 els->un.prli.TaskRetryIdReq = 0; 2074 } 2075 2076 break; 2077 2078 case ELS_CMD_PRLO: 2079 2080 els->elsByte1 = 0x10; 2081 els->elsByte2 = 0; 2082 els->elsByte3 = 0x14; 2083 2084 els->un.prlo.prloType = PRLO_FCP_TYPE; 2085 els->un.prlo.acceptRspCode = PRLO_REQ_EXECUTED; 2086 2087 break; 2088 2089 2090 } /* switch(type2) */ 2091 break; 2092 2093 case ELS_CMD_LS_RJT: /* reject response */ 2094 2095 if (!(pkt = emlxs_pkt_alloc(port, 2096 sizeof (uint32_t) + sizeof (LS_RJT), 0, 0, KM_NOSLEEP))) { 2097 return (1); 2098 } 2099 pkt->pkt_tran_type = FC_PKT_OUTBOUND; 2100 pkt->pkt_timeout = (2 * hba->fc_ratov); 2101 2102 if ((uint32_t)iocb->ulpClass == CLASS2) { 2103 pkt->pkt_tran_flags &= ~FC_TRAN_CLASS3; 2104 pkt->pkt_tran_flags |= FC_TRAN_CLASS2; 2105 } 2106 /* Build the fc header */ 2107 pkt->pkt_cmd_fhdr.d_id = 2108 SWAP_DATA24_LO(iocb->un.elsreq.remoteID); 2109 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | 2110 R_CTL_SOLICITED_CONTROL; 2111 pkt->pkt_cmd_fhdr.s_id = 2112 SWAP_DATA24_LO(iocb->un.elsreq.myID); 2113 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 2114 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_XCHG_CONTEXT | 2115 F_CTL_LAST_SEQ | F_CTL_END_SEQ; 2116 pkt->pkt_cmd_fhdr.seq_id = 0; 2117 pkt->pkt_cmd_fhdr.df_ctl = 0; 2118 pkt->pkt_cmd_fhdr.seq_cnt = 0; 2119 pkt->pkt_cmd_fhdr.ox_id = (type2 >> ELS_CMD_SHIFT) & 0xff; 2120 pkt->pkt_cmd_fhdr.rx_id = iocb->ulpContext; 2121 pkt->pkt_cmd_fhdr.ro = 0; 2122 2123 /* 2124 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, "%s LS_RJT 2125 * send. oxid=%x", emlxs_elscmd_xlate(type2), 2126 * pkt->pkt_cmd_fhdr.ox_id); 2127 */ 2128 2129 /* Build the command */ 2130 els = (ELS_PKT *) pkt->pkt_cmd; 2131 els->elsCode = 0x01; 2132 els->un.lsRjt.un.b.lsRjtRsvd0 = 0; 2133 els->un.lsRjt.un.b.lsRjtRsnCode = LSRJT_UNABLE_TPC; 2134 els->un.lsRjt.un.b.lsRjtRsnCodeExp = LSEXP_NOTHING_MORE; 2135 els->un.lsRjt.un.b.vendorUnique = 0x01; 2136 2137 break; 2138 } 2139 2140 if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) { 2141 /* Free the pkt */ 2142 emlxs_pkt_free(pkt); 2143 } 2144 return (rval); 2145 2146 } /* emlxs_els_reply() */ 2147 2148 2149 #ifdef ULP_PATCH6 2150 2151 extern uint32_t 2152 emlxs_generate_rscn(emlxs_port_t *port, uint32_t d_id) 2153 { 2154 fc_unsol_buf_t *ubp; 2155 fc_rscn_t *rscn; 2156 emlxs_ub_priv_t *ub_priv; 2157 uint32_t *page; 2158 2159 ubp = (fc_unsol_buf_t *)emlxs_ub_get(port, 8, FC_ELS_DATA, 1); 2160 2161 if (ubp == NULL) { 2162 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_no_unsol_buf_msg, 2163 "RSCN create: sid=0xfffffd " 2164 "1 page(s): %08X, 00000000. Creation failed.", 2165 d_id); 2166 2167 return ((uint32_t)FC_FAILURE); 2168 } 2169 /* Simulate an RSCN payload */ 2170 rscn = (fc_rscn_t *)ubp->ub_buffer; 2171 rscn->rscn_code = 0x61; 2172 rscn->rscn_len = 0x04; 2173 rscn->rscn_payload_len = 0x0008; 2174 page = ((uint32_t *)rscn); 2175 page++; 2176 *page = d_id; 2177 2178 #ifdef EMLXS_I386 2179 /* Put payload in BE format */ 2180 rscn->rscn_payload_len = SWAP_DATA16(rscn->rscn_payload_len); 2181 *page = SWAP_DATA32(d_id); 2182 #endif /* EMLXS_I386 */ 2183 2184 ub_priv = ubp->ub_fca_private; 2185 ub_priv->cmd = ELS_CMD_RSCN; 2186 ub_priv->flags |= EMLXS_UB_INTERCEPT; 2187 2188 ubp->ub_frame.r_ctl = FC_ELS_REQ; 2189 ubp->ub_frame.type = FC_ELS_DATA; 2190 ubp->ub_frame.s_id = 0xfffffd; 2191 ubp->ub_frame.d_id = SWAP_DATA24_LO(port->did); 2192 ubp->ub_frame.ox_id = ub_priv->token; 2193 ubp->ub_frame.rx_id = 0xffff; 2194 ubp->ub_class = FC_TRAN_CLASS3; 2195 2196 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg, 2197 "RSCN: sid=fffffd 1 page(s): %08X, " 2198 "00000000 buffer=%p token=%x. Created.", 2199 d_id, ubp, ub_priv->token); 2200 2201 #if (EMLXS_MODREVX == EMLXS_MODREV2X) 2202 emlxs_swap_els_ub(ubp); 2203 #endif /* EMLXS_MODREV2X */ 2204 2205 emlxs_ub_callback(port, ubp); 2206 2207 return (FC_SUCCESS); 2208 2209 } /* emlxs_generate_rscn() */ 2210 2211 #endif /* ULP_PATCH6 */ 2212 2213 2214 #ifdef MENLO_SUPPORT 2215 extern int 2216 emlxs_menlo_handle_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 2217 { 2218 emlxs_port_t *port = &PPORT; 2219 IOCB *iocb; 2220 emlxs_buf_t *sbp; 2221 fc_packet_t *pkt; 2222 uint32_t cmd_code = 0; 2223 uint32_t rsp_code = 0; 2224 menlo_cmd_t *cmd; 2225 uint32_t *rsp; 2226 2227 iocb = &iocbq->iocb; 2228 2229 HBASTATS.CtEvent++; 2230 2231 sbp = (emlxs_buf_t *)iocbq->sbp; 2232 2233 if (!sbp) { 2234 /* 2235 * completion with missing xmit command 2236 */ 2237 HBASTATS.CtStray++; 2238 2239 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ct_completion_msg, 2240 "iocbq=%p cmd=0x%x iotag=0x%x status=0x%x perr=0x%x", 2241 iocbq, (uint32_t)iocb->ulpCommand, (uint32_t)iocb->ulpIoTag, 2242 iocb->ulpStatus, iocb->un.ulpWord[4]); 2243 2244 return (1); 2245 } 2246 if (rp->ringno != FC_CT_RING) { 2247 HBASTATS.CtStray++; 2248 2249 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ct_completion_msg, 2250 "Invalid ring: ring=%d iocbq=%p", 2251 rp->ringno, iocbq); 2252 2253 return (1); 2254 } 2255 port = sbp->iocbq.port; 2256 pkt = PRIV2PKT(sbp); 2257 2258 cmd = (menlo_cmd_t *)pkt->pkt_cmd; 2259 cmd_code = SWAP_LONG(cmd->code); 2260 2261 /* Check if a response buffer was provided */ 2262 if (pkt->pkt_rsplen) { 2263 emlxs_mpdata_sync(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen, 2264 DDI_DMA_SYNC_FORKERNEL); 2265 } 2266 switch (iocb->ulpCommand) { 2267 /* MENLO Command completion */ 2268 case CMD_GEN_REQUEST64_CR: 2269 case CMD_GEN_REQUEST64_CX: 2270 2271 HBASTATS.CtCmdCompleted++; 2272 2273 sbp->pkt_flags |= PACKET_CT_RSP_VALID; 2274 2275 rsp = (uint32_t *)pkt->pkt_resp; 2276 rsp_code = *rsp; 2277 rsp_code = SWAP_LONG(rsp_code); 2278 2279 #ifdef SLI3_SUPPORT 2280 if (hba->sli_mode >= 3) { 2281 pkt->pkt_resp_resid = 2282 pkt->pkt_rsplen - iocb->unsli3.ext_iocb.rsplen; 2283 } else 2284 #endif /* SLI3_SUPPORT */ 2285 { 2286 pkt->pkt_resp_resid = 2287 pkt->pkt_rsplen - iocb->un.genreq64.bdl.bdeSize; 2288 } 2289 2290 pkt->pkt_data_resid = pkt->pkt_datalen; 2291 pkt->pkt_cmd_fhdr.rx_id = iocb->ulpContext; 2292 2293 if ((iocb->ulpStatus == 0) && (rsp_code == MENLO_RSP_SUCCESS)) { 2294 HBASTATS.CtCmdGood++; 2295 2296 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, 2297 "%s: %s rxid=0x%x", 2298 emlxs_menlo_cmd_xlate(cmd_code), 2299 emlxs_menlo_rsp_xlate(rsp_code), 2300 iocb->ulpContext); 2301 2302 } else { 2303 HBASTATS.CtCmdError++; 2304 2305 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, 2306 "%s: %s %s %s rxid=0x%x", 2307 emlxs_menlo_cmd_xlate(cmd_code), 2308 emlxs_menlo_rsp_xlate(rsp_code), 2309 emlxs_state_xlate(iocb->ulpStatus), 2310 emlxs_error_xlate( 2311 iocb->un.grsp.perr.statLocalError), 2312 iocb->ulpContext); 2313 } 2314 2315 emlxs_pkt_complete(sbp, iocb->ulpStatus, 2316 iocb->un.grsp.perr.statLocalError, 1); 2317 2318 break; 2319 2320 default: 2321 2322 HBASTATS.CtStray++; 2323 2324 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_ct_msg, 2325 "Invalid iocb: cmd=0x%x", 2326 iocb->ulpCommand); 2327 2328 emlxs_pkt_complete(sbp, iocb->ulpStatus, 2329 iocb->un.grsp.perr.statLocalError, 1); 2330 2331 break; 2332 2333 } /* switch(iocb->ulpCommand) */ 2334 2335 return (0); 2336 2337 } /* emlxs_menlo_handle_event() */ 2338 2339 #endif /* MENLO_SUPPORT */ 2340 2341 2342 extern int 2343 emlxs_ct_handle_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 2344 { 2345 emlxs_port_t *port = &PPORT; 2346 IOCB *iocb; 2347 emlxs_buf_t *sbp; 2348 fc_packet_t *pkt; 2349 uint32_t *rsp; 2350 SLI_CT_REQUEST *CtRsp; 2351 SLI_CT_REQUEST *CtCmd; 2352 uint32_t cmd_code = 0; 2353 uint32_t rsp_code = 0; 2354 2355 iocb = &iocbq->iocb; 2356 2357 HBASTATS.CtEvent++; 2358 2359 sbp = (emlxs_buf_t *)iocbq->sbp; 2360 2361 if (!sbp) { 2362 /* 2363 * completion with missing xmit command 2364 */ 2365 HBASTATS.CtStray++; 2366 2367 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ct_completion_msg, 2368 "iocbq=%p cmd=0x%x iotag=0x%x status=0x%x perr=0x%x", 2369 iocbq, (uint32_t)iocb->ulpCommand, (uint32_t)iocb->ulpIoTag, 2370 iocb->ulpStatus, iocb->un.ulpWord[4]); 2371 2372 return (1); 2373 } 2374 if (rp->ringno != FC_CT_RING) { 2375 HBASTATS.CtStray++; 2376 2377 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ct_completion_msg, 2378 "Invalid ring: ring=%d iocbq=%p", 2379 rp->ringno, iocbq); 2380 2381 return (1); 2382 } 2383 pkt = PRIV2PKT(sbp); 2384 port = sbp->iocbq.port; 2385 CtCmd = (SLI_CT_REQUEST *) pkt->pkt_cmd; 2386 cmd_code = SWAP_DATA16(CtCmd->CommandResponse.bits.CmdRsp); 2387 2388 #ifdef DFC_SUPPORT 2389 if (cmd_code == SLI_CT_LOOPBACK) { 2390 HBASTATS.CtEvent--; 2391 return (emlxs_dfc_handle_event(hba, rp, iocbq)); 2392 } 2393 #endif /* DFC_SUPPORT */ 2394 2395 /* Check if a response buffer was provided */ 2396 if (pkt->pkt_rsplen) { 2397 emlxs_mpdata_sync(pkt->pkt_resp_dma, 0, pkt->pkt_rsplen, 2398 DDI_DMA_SYNC_FORKERNEL); 2399 } 2400 switch (iocb->ulpCommand) { 2401 /* CT Reply completion */ 2402 case CMD_XMIT_SEQUENCE_CX: 2403 case CMD_XMIT_SEQUENCE64_CX: 2404 2405 HBASTATS.CtRspCompleted++; 2406 2407 switch (CtCmd->FsType) { 2408 case 0xFC: /* Name server */ 2409 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, 2410 "%s: %s %s", 2411 emlxs_ctcmd_xlate(cmd_code), 2412 emlxs_state_xlate(iocb->ulpStatus), 2413 emlxs_error_xlate( 2414 iocb->un.grsp.perr.statLocalError)); 2415 break; 2416 2417 case 0xFA: /* Managment server */ 2418 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, 2419 "%s: %s %s", 2420 emlxs_mscmd_xlate(cmd_code), 2421 emlxs_state_xlate(iocb->ulpStatus), 2422 emlxs_error_xlate( 2423 iocb->un.grsp.perr.statLocalError)); 2424 break; 2425 2426 case 0x0A: /* Emulex Remote server */ 2427 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, 2428 "%s: %s %s", 2429 emlxs_rmcmd_xlate(cmd_code), 2430 emlxs_state_xlate(iocb->ulpStatus), 2431 emlxs_error_xlate( 2432 iocb->un.grsp.perr.statLocalError)); 2433 break; 2434 2435 default: 2436 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, 2437 "%s: %s %s", 2438 emlxs_ctcmd_xlate(cmd_code), 2439 emlxs_state_xlate(iocb->ulpStatus), 2440 emlxs_error_xlate( 2441 iocb->un.grsp.perr.statLocalError)); 2442 } 2443 2444 emlxs_pkt_complete(sbp, iocb->ulpStatus, 2445 iocb->un.grsp.perr.statLocalError, 1); 2446 2447 break; 2448 2449 /* CT Command completion */ 2450 case CMD_GEN_REQUEST64_CR: 2451 case CMD_GEN_REQUEST64_CX: 2452 2453 HBASTATS.CtCmdCompleted++; 2454 2455 sbp->pkt_flags |= PACKET_CT_RSP_VALID; 2456 2457 rsp = (uint32_t *)pkt->pkt_resp; 2458 CtRsp = (SLI_CT_REQUEST *)pkt->pkt_resp; 2459 rsp_code = SWAP_DATA16(CtRsp->CommandResponse.bits.CmdRsp); 2460 2461 #ifdef SLI3_SUPPORT 2462 if (hba->sli_mode >= 3) { 2463 pkt->pkt_resp_resid = 2464 pkt->pkt_rsplen - iocb->unsli3.ext_iocb.rsplen; 2465 } else 2466 #endif /* SLI3_SUPPORT */ 2467 { 2468 pkt->pkt_resp_resid = 2469 pkt->pkt_rsplen - iocb->un.genreq64.bdl.bdeSize; 2470 } 2471 2472 pkt->pkt_data_resid = pkt->pkt_datalen; 2473 2474 /* 2475 * EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_completion_msg, "INFO: 2476 * pkt_resid=%d %d %d %x", pkt->pkt_resp_resid, 2477 * pkt->pkt_rsplen, iocb->un.genreq64.bdl.bdeSize, 2478 * iocb->un.genreq64.bdl.bdeFlags); 2479 */ 2480 2481 if ((iocb->ulpStatus == 0) && 2482 (rsp_code == SLI_CT_RESPONSE_FS_ACC)) { 2483 HBASTATS.CtCmdGood++; 2484 2485 if (!(sbp->pkt_flags & PACKET_ALLOCATED)) { 2486 /* 2487 * ULP patch - ULP expects resp_resid = 0 on 2488 * success 2489 */ 2490 pkt->pkt_resp_resid = 0; 2491 } 2492 switch (CtCmd->FsType) { 2493 case 0xFC: /* Name server */ 2494 EMLXS_MSGF(EMLXS_CONTEXT, 2495 &emlxs_ct_completion_msg, 2496 "%s: %s: Rsn=%x Exp=%x [%08x,%08x]", 2497 emlxs_ctcmd_xlate(cmd_code), 2498 emlxs_ctcmd_xlate(rsp_code), 2499 CtRsp->ReasonCode, CtRsp->Explanation, 2500 SWAP_DATA32(rsp[4]), SWAP_DATA32(rsp[5])); 2501 2502 #if (EMLXS_MODREV < EMLXS_MODREV4) 2503 if (cmd_code == SLI_CTNS_RNN_ID) { 2504 emlxs_send_rsnn(port); 2505 } 2506 #endif /* < EMLXS_MODREV4 */ 2507 2508 break; 2509 2510 case 0xFA: /* Managment server */ 2511 EMLXS_MSGF(EMLXS_CONTEXT, 2512 &emlxs_ct_completion_msg, 2513 "%s: %s: Rsn=%x Exp=%x [%08x,%08x]", 2514 emlxs_mscmd_xlate(cmd_code), 2515 emlxs_mscmd_xlate(rsp_code), 2516 CtRsp->ReasonCode, CtRsp->Explanation, 2517 SWAP_DATA32(rsp[4]), SWAP_DATA32(rsp[5])); 2518 break; 2519 2520 case 0x0A: /* Emulex Remote server */ 2521 EMLXS_MSGF(EMLXS_CONTEXT, 2522 &emlxs_ct_completion_msg, 2523 "%s: %s: Rsn=%x Exp=%x [%08x,%08x]", 2524 emlxs_rmcmd_xlate(cmd_code), 2525 emlxs_rmcmd_xlate(rsp_code), 2526 CtRsp->ReasonCode, CtRsp->Explanation, 2527 SWAP_DATA32(rsp[4]), SWAP_DATA32(rsp[5])); 2528 break; 2529 2530 default: 2531 EMLXS_MSGF(EMLXS_CONTEXT, 2532 &emlxs_ct_completion_msg, 2533 "%s: %s: Rsn=%x Exp=%x [%08x,%08x]", 2534 emlxs_ctcmd_xlate(cmd_code), 2535 emlxs_ctcmd_xlate(rsp_code), 2536 CtRsp->ReasonCode, CtRsp->Explanation, 2537 SWAP_DATA32(rsp[4]), SWAP_DATA32(rsp[5])); 2538 } 2539 } else { 2540 HBASTATS.CtCmdError++; 2541 2542 if (rsp_code == SLI_CT_RESPONSE_FS_RJT) { 2543 pkt->pkt_state = FC_PKT_FS_RJT; 2544 pkt->pkt_action = FC_ACTION_RETRYABLE; 2545 pkt->pkt_reason = CtRsp->ReasonCode; 2546 pkt->pkt_expln = CtRsp->Explanation; 2547 sbp->pkt_flags |= PACKET_STATE_VALID; 2548 2549 EMLXS_MSGF(EMLXS_CONTEXT, 2550 &emlxs_ct_completion_msg, 2551 "%s: Rejected. rsn=%x exp=%x", 2552 emlxs_ctcmd_xlate(cmd_code), 2553 pkt->pkt_reason, 2554 pkt->pkt_expln); 2555 } else if (iocb->ulpStatus == IOSTAT_LOCAL_REJECT) { 2556 switch (CtCmd->FsType) { 2557 case 0xFC: /* Name server */ 2558 EMLXS_MSGF(EMLXS_CONTEXT, 2559 &emlxs_ct_completion_msg, 2560 "%s: %s %s", 2561 emlxs_ctcmd_xlate(cmd_code), 2562 emlxs_state_xlate(iocb->ulpStatus), 2563 emlxs_error_xlate( 2564 iocb->un.grsp.perr.statLocalError)); 2565 break; 2566 2567 case 0xFA: /* Managment server */ 2568 EMLXS_MSGF(EMLXS_CONTEXT, 2569 &emlxs_ct_completion_msg, 2570 "%s: %s %s", 2571 emlxs_mscmd_xlate(cmd_code), 2572 emlxs_state_xlate(iocb->ulpStatus), 2573 emlxs_error_xlate( 2574 iocb->un.grsp.perr.statLocalError)); 2575 break; 2576 2577 case 0x0A: /* Emulex Remote server */ 2578 EMLXS_MSGF(EMLXS_CONTEXT, 2579 &emlxs_ct_completion_msg, 2580 "%s: %s %s", 2581 emlxs_rmcmd_xlate(cmd_code), 2582 emlxs_state_xlate(iocb->ulpStatus), 2583 emlxs_error_xlate( 2584 iocb->un.grsp.perr.statLocalError)); 2585 break; 2586 2587 default: 2588 EMLXS_MSGF(EMLXS_CONTEXT, 2589 &emlxs_ct_completion_msg, 2590 "%s: %s %s", 2591 emlxs_ctcmd_xlate(cmd_code), 2592 emlxs_state_xlate(iocb->ulpStatus), 2593 emlxs_error_xlate( 2594 iocb->un.grsp.perr.statLocalError)); 2595 } 2596 } else { 2597 switch (CtCmd->FsType) { 2598 case 0xFC: /* Name server */ 2599 EMLXS_MSGF(EMLXS_CONTEXT, 2600 &emlxs_ct_completion_msg, 2601 "%s: %s (%02x%02x%02x%02x)", 2602 emlxs_ctcmd_xlate(cmd_code), 2603 emlxs_state_xlate(iocb->ulpStatus), 2604 iocb->un.grsp.perr.statAction, 2605 iocb->un.grsp.perr.statRsn, 2606 iocb->un.grsp.perr.statBaExp, 2607 iocb->un.grsp.perr.statLocalError); 2608 break; 2609 2610 case 0xFA: /* Managment server */ 2611 EMLXS_MSGF(EMLXS_CONTEXT, 2612 &emlxs_ct_completion_msg, 2613 "%s: %s (%02x%02x%02x%02x)", 2614 emlxs_mscmd_xlate(cmd_code), 2615 emlxs_state_xlate(iocb->ulpStatus), 2616 iocb->un.grsp.perr.statAction, 2617 iocb->un.grsp.perr.statRsn, 2618 iocb->un.grsp.perr.statBaExp, 2619 iocb->un.grsp.perr.statLocalError); 2620 break; 2621 2622 case 0x0A: /* Emulex Remote server */ 2623 EMLXS_MSGF(EMLXS_CONTEXT, 2624 &emlxs_ct_completion_msg, 2625 "%s: %s (%02x%02x%02x%02x)", 2626 emlxs_rmcmd_xlate(cmd_code), 2627 emlxs_state_xlate(iocb->ulpStatus), 2628 iocb->un.grsp.perr.statAction, 2629 iocb->un.grsp.perr.statRsn, 2630 iocb->un.grsp.perr.statBaExp, 2631 iocb->un.grsp.perr.statLocalError); 2632 break; 2633 2634 default: 2635 EMLXS_MSGF(EMLXS_CONTEXT, 2636 &emlxs_ct_completion_msg, 2637 "%s: %s (%02x%02x%02x%02x)", 2638 emlxs_ctcmd_xlate(cmd_code), 2639 emlxs_state_xlate(iocb->ulpStatus), 2640 iocb->un.grsp.perr.statAction, 2641 iocb->un.grsp.perr.statRsn, 2642 iocb->un.grsp.perr.statBaExp, 2643 iocb->un.grsp.perr.statLocalError); 2644 } 2645 } 2646 } 2647 2648 emlxs_pkt_complete(sbp, iocb->ulpStatus, 2649 iocb->un.grsp.perr.statLocalError, 1); 2650 2651 break; 2652 2653 default: 2654 2655 HBASTATS.CtStray++; 2656 2657 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_ct_msg, 2658 "Invalid iocb: cmd=0x%x", 2659 iocb->ulpCommand); 2660 2661 emlxs_pkt_complete(sbp, iocb->ulpStatus, 2662 iocb->un.grsp.perr.statLocalError, 1); 2663 2664 break; 2665 } /* switch(iocb->ulpCommand) */ 2666 2667 return (0); 2668 2669 } /* emlxs_ct_handle_event() */ 2670 2671 2672 extern int 2673 emlxs_ct_handle_unsol_req(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 2674 MATCHMAP *mp, uint32_t size) 2675 { 2676 emlxs_hba_t *hba = HBA; 2677 IOCB *iocb; 2678 SLI_CT_REQUEST *CtCmd; 2679 uint32_t cmd_code; 2680 2681 iocb = &iocbq->iocb; 2682 2683 CtCmd = (SLI_CT_REQUEST *)mp->virt; 2684 cmd_code = SWAP_DATA16(CtCmd->CommandResponse.bits.CmdRsp); 2685 2686 #ifdef DFC_SUPPORT 2687 if (cmd_code == SLI_CT_LOOPBACK) { 2688 int rval; 2689 2690 rval = emlxs_dfc_handle_unsol_req(port, rp, iocbq, mp, size); 2691 2692 return (rval); 2693 } 2694 #endif /* DFC_SUPPORT */ 2695 2696 HBASTATS.CtCmdReceived++; 2697 2698 switch (CtCmd->FsType) { 2699 case 0xFC: /* Name server */ 2700 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg, 2701 "%s: pl=%p size=%d rxid=%x", 2702 emlxs_ctcmd_xlate(cmd_code), 2703 CtCmd, size, iocb->ulpContext); 2704 break; 2705 2706 case 0xFA: /* Managment server */ 2707 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg, 2708 "%s: pl=%p size=%d rxid=%x", 2709 emlxs_mscmd_xlate(cmd_code), 2710 CtCmd, size, iocb->ulpContext); 2711 break; 2712 2713 case 0x0A: /* Emulex Remote server */ 2714 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg, 2715 "%s: pl=%p size=%d rxid=%x", 2716 emlxs_rmcmd_xlate(cmd_code), 2717 CtCmd, size, iocb->ulpContext); 2718 break; 2719 2720 default: 2721 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ct_msg, 2722 "%s: pl=%p size=%d rxid=%x", 2723 emlxs_ctcmd_xlate(cmd_code), 2724 CtCmd, size, iocb->ulpContext); 2725 } 2726 2727 if (emlxs_log_ct_event(port, (uint8_t *)mp->virt, size, 2728 iocb->ulpContext)) { 2729 /* Abort the exchange */ 2730 emlxs_abort_ct_exchange(port, iocb->ulpContext); 2731 } 2732 2733 return (0); 2734 2735 } /* emlxs_ct_handle_unsol_req() */ 2736 2737 2738 static void 2739 emlxs_send_rsnn(emlxs_port_t *port) 2740 { 2741 emlxs_hba_t *hba = HBA; 2742 fc_packet_t *pkt; 2743 SLI_CT_REQUEST *ct; 2744 2745 if (!(pkt = emlxs_pkt_alloc(port, 2746 sizeof (SLI_CT_REQUEST), sizeof (SLI_CT_REQUEST), 0, KM_NOSLEEP))) { 2747 return; 2748 } 2749 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 2750 pkt->pkt_timeout = (2 * hba->fc_ratov); 2751 2752 /* Build the fc header */ 2753 pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(NameServer_DID); 2754 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL; 2755 pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did); 2756 pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES; 2757 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | 2758 F_CTL_SEQ_INITIATIVE; 2759 pkt->pkt_cmd_fhdr.seq_id = 0; 2760 pkt->pkt_cmd_fhdr.df_ctl = 0; 2761 pkt->pkt_cmd_fhdr.seq_cnt = 0; 2762 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 2763 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 2764 pkt->pkt_cmd_fhdr.ro = 0; 2765 2766 /* Build the command */ 2767 ct = (SLI_CT_REQUEST *)pkt->pkt_cmd; 2768 2769 ct->RevisionId.bits.Revision = SLI_CT_REVISION; 2770 ct->RevisionId.bits.InId = 0; 2771 2772 ct->FsType = SLI_CT_DIRECTORY_SERVICE; 2773 ct->FsSubType = SLI_CT_DIRECTORY_NAME_SERVER; 2774 2775 ct->CommandResponse.bits.Size = 0; 2776 ct->CommandResponse.bits.CmdRsp = SWAP_DATA16(SLI_CTNS_RSNN_NN); 2777 2778 bcopy((uint8_t *)&hba->wwnn, (char *)ct->un.rsnn.wwnn, 8); 2779 2780 ct->un.rsnn.snn_len = strlen(port->snn); 2781 bcopy(port->snn, (char *)ct->un.rsnn.snn, ct->un.rsnn.snn_len); 2782 2783 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ct_send_msg, 2784 "Sending RSNN_NN. [%s]", 2785 port->snn); 2786 2787 /* Send the pkt later in another thread */ 2788 if (emlxs_pkt_send(pkt, 0) != FC_SUCCESS) { 2789 /* Free the pkt */ 2790 emlxs_pkt_free(pkt); 2791 } 2792 return; 2793 2794 } /* emlxs_send_rsnn() */ 2795 2796 2797 extern uint32_t 2798 emlxs_ub_send_login_acc(emlxs_port_t *port, fc_unsol_buf_t *ubp) 2799 { 2800 emlxs_hba_t *hba = HBA; 2801 fc_packet_t *pkt; 2802 ELS_PKT *els; 2803 uint32_t rval; 2804 emlxs_ub_priv_t *ub_priv; 2805 2806 ub_priv = ubp->ub_fca_private; 2807 2808 if (!(pkt = emlxs_pkt_alloc(port, 2809 sizeof (uint32_t) + sizeof (SERV_PARM), 0, 0, KM_NOSLEEP))) { 2810 return (1); 2811 } 2812 /* Common initialization */ 2813 pkt->pkt_tran_type = FC_PKT_OUTBOUND; 2814 pkt->pkt_timeout = (2 * hba->fc_ratov); 2815 2816 if ((uint32_t)ubp->ub_class == FC_TRAN_CLASS2) { 2817 pkt->pkt_tran_flags &= ~FC_TRAN_CLASS3; 2818 pkt->pkt_tran_flags |= FC_TRAN_CLASS2; 2819 } 2820 /* Build the fc header */ 2821 pkt->pkt_cmd_fhdr.d_id = ubp->ub_frame.s_id; 2822 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL; 2823 pkt->pkt_cmd_fhdr.s_id = ubp->ub_frame.d_id; 2824 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 2825 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | 2826 F_CTL_END_SEQ; 2827 pkt->pkt_cmd_fhdr.seq_id = 0; 2828 pkt->pkt_cmd_fhdr.df_ctl = 0; 2829 pkt->pkt_cmd_fhdr.seq_cnt = 0; 2830 pkt->pkt_cmd_fhdr.ox_id = (ub_priv->cmd >> ELS_CMD_SHIFT) & 0xff; 2831 pkt->pkt_cmd_fhdr.rx_id = ubp->ub_frame.rx_id; 2832 pkt->pkt_cmd_fhdr.ro = 0; 2833 2834 /* Build the command */ 2835 els = (ELS_PKT *) pkt->pkt_cmd; 2836 els->elsCode = 0x02; 2837 bcopy((void *)&port->sparam, (void *)&els->un.logi, sizeof (SERV_PARM)); 2838 2839 if ((rval = emlxs_pkt_send(pkt, 1)) != FC_SUCCESS) { 2840 /* Free the pkt */ 2841 emlxs_pkt_free(pkt); 2842 } else { 2843 ub_priv->flags |= EMLXS_UB_INTERCEPT; 2844 } 2845 2846 return (rval); 2847 2848 } /* emlxs_ub_send_login_acc */ 2849 2850 2851 extern void 2852 emlxs_send_logo(emlxs_port_t *port, uint32_t d_id) 2853 { 2854 emlxs_hba_t *hba = HBA; 2855 fc_packet_t *pkt; 2856 ELS_PKT *els; 2857 2858 if (hba->state <= FC_LINK_DOWN) { 2859 return; 2860 } 2861 if (!(pkt = emlxs_pkt_alloc(port, sizeof (uint32_t) + sizeof (LOGO), 2862 sizeof (uint32_t) + sizeof (LOGO), 0, KM_NOSLEEP))) { 2863 return; 2864 } 2865 pkt->pkt_tran_type = FC_PKT_EXCHANGE; 2866 pkt->pkt_timeout = (2 * hba->fc_ratov); 2867 2868 /* Build the fc header */ 2869 pkt->pkt_cmd_fhdr.d_id = SWAP_DATA24_LO(d_id); 2870 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL; 2871 pkt->pkt_cmd_fhdr.s_id = SWAP_DATA24_LO(port->did); 2872 pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS; 2873 pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_END_SEQ | 2874 F_CTL_SEQ_INITIATIVE; 2875 pkt->pkt_cmd_fhdr.seq_id = 0; 2876 pkt->pkt_cmd_fhdr.df_ctl = 0; 2877 pkt->pkt_cmd_fhdr.seq_cnt = 0; 2878 pkt->pkt_cmd_fhdr.ox_id = 0xffff; 2879 pkt->pkt_cmd_fhdr.rx_id = 0xffff; 2880 pkt->pkt_cmd_fhdr.ro = 0; 2881 2882 /* Build the command */ 2883 els = (ELS_PKT *)pkt->pkt_cmd; 2884 els->elsCode = 0x05; 2885 els->un.logo.un.nPortId32 = pkt->pkt_cmd_fhdr.s_id; 2886 bcopy((uint8_t *)&port->wwpn, (uint8_t *)&els->un.logo.portName, 8); 2887 2888 /* Send the pkt now */ 2889 if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) { 2890 /* Free the pkt */ 2891 emlxs_pkt_free(pkt); 2892 } 2893 return; 2894 2895 } /* emlxs_send_logo() */ 2896