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 2009 Emulex. All rights reserved. 24 * Use is subject to License terms. 25 */ 26 27 #include <emlxs.h> 28 29 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */ 30 EMLXS_MSG_DEF(EMLXS_IP_C); 31 32 33 extern int32_t 34 emlxs_ip_handle_event(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 35 { 36 emlxs_port_t *port = &PPORT; 37 IOCB *cmd; 38 emlxs_buf_t *sbp; 39 NODELIST *ndlp; 40 41 cmd = &iocbq->iocb; 42 43 HBASTATS.IpEvent++; 44 45 sbp = (emlxs_buf_t *)iocbq->sbp; 46 47 if (!sbp) { 48 HBASTATS.IpStray++; 49 50 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg, 51 "cmd=0x%x iotag=0x%x status=0x%x perr=0x%x", 52 (uint32_t)cmd->ulpCommand, (uint32_t)cmd->ulpIoTag, 53 cmd->ulpStatus, cmd->un.ulpWord[4]); 54 55 return (EIO); 56 } 57 58 if (rp->ringno != FC_IP_RING) { 59 HBASTATS.IpStray++; 60 61 return (0); 62 } 63 64 port = sbp->iocbq.port; 65 66 switch (cmd->ulpCommand) { 67 /* 68 * Error: Abnormal BCAST command completion (Local error) 69 */ 70 case CMD_XMIT_BCAST_CN: 71 case CMD_XMIT_BCAST64_CN: 72 73 HBASTATS.IpBcastCompleted++; 74 HBASTATS.IpBcastError++; 75 76 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 77 "XMIT BCAST completion error cmd=0x%x status=0x%x " 78 "[%08x,%08x]", cmd->ulpCommand, cmd->ulpStatus, 79 cmd->un.ulpWord[4], cmd->un.ulpWord[5]); 80 81 emlxs_pkt_complete(sbp, cmd->ulpStatus, 82 cmd->un.grsp.perr.statLocalError, 1); 83 84 break; 85 86 /* 87 * Error: Abnormal XMIT SEQUENCE command completion 88 * (Local error) 89 */ 90 case CMD_XMIT_SEQUENCE_CR: 91 case CMD_XMIT_SEQUENCE64_CR: 92 93 HBASTATS.IpSeqCompleted++; 94 HBASTATS.IpSeqError++; 95 96 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 97 "XMIT SEQUENCE CR completion error: cmd=%x status=0x%x " 98 "[%08x,%08x]", cmd->ulpCommand, cmd->ulpStatus, 99 cmd->un.ulpWord[4], cmd->un.ulpWord[5]); 100 101 emlxs_pkt_complete(sbp, cmd->ulpStatus, 102 cmd->un.grsp.perr.statLocalError, 1); 103 104 break; 105 106 /* 107 * Normal BCAST completion 108 */ 109 case CMD_XMIT_BCAST_CX: 110 case CMD_XMIT_BCAST64_CX: 111 112 HBASTATS.IpBcastCompleted++; 113 HBASTATS.IpBcastGood++; 114 115 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 116 "XMIT BCAST CN completion: cmd=%x status=0x%x [%08x,%08x]", 117 cmd->ulpCommand, cmd->ulpStatus, cmd->un.ulpWord[4], 118 cmd->un.ulpWord[5]); 119 120 emlxs_pkt_complete(sbp, cmd->ulpStatus, 121 cmd->un.grsp.perr.statLocalError, 1); 122 123 break; 124 125 /* 126 * Normal XMIT SEQUENCE completion 127 */ 128 case CMD_XMIT_SEQUENCE_CX: 129 case CMD_XMIT_SEQUENCE64_CX: 130 131 HBASTATS.IpSeqCompleted++; 132 133 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 134 "XMIT SEQUENCE CR completion: cmd=%x status=0x%x" 135 "[%08x,%08x]", cmd->ulpCommand, cmd->ulpStatus, 136 cmd->un.ulpWord[4], cmd->un.ulpWord[5]); 137 138 if (cmd->ulpStatus) { 139 HBASTATS.IpSeqError++; 140 141 if ((cmd->ulpStatus == IOSTAT_LOCAL_REJECT) && 142 ((cmd->un.ulpWord[4] & 0xff) == IOERR_NO_XRI)) { 143 ndlp = (NODELIST *)sbp->node; 144 if ((cmd->ulpContext == ndlp->nlp_Xri) && 145 !(ndlp->nlp_flag[FC_IP_RING] & 146 NLP_RPI_XRI)) { 147 ndlp->nlp_Xri = 0; 148 (void) emlxs_create_xri(port, rp, ndlp); 149 } 150 } 151 } else { 152 HBASTATS.IpSeqGood++; 153 } 154 155 emlxs_pkt_complete(sbp, cmd->ulpStatus, 156 cmd->un.grsp.perr.statLocalError, 1); 157 158 break; 159 160 default: 161 162 HBASTATS.IpStray++; 163 164 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_invalid_ip_msg, 165 "Invalid iocb: cmd=0x%x", cmd->ulpCommand); 166 167 break; 168 169 } /* switch(cmd->ulpCommand) */ 170 171 172 return (0); 173 174 } /* emlxs_ip_handle_event() */ 175 176 177 extern int32_t 178 emlxs_ip_handle_unsol_req(emlxs_port_t *port, RING *rp, IOCBQ *iocbq, 179 MATCHMAP *mp, uint32_t size) 180 { 181 emlxs_hba_t *hba = HBA; 182 fc_unsol_buf_t *ubp; 183 IOCB *cmd; 184 NETHDR *nd; 185 NODELIST *ndlp; 186 uint8_t *mac; 187 emlxs_ub_priv_t *ub_priv; 188 uint32_t sid; 189 uint32_t i; 190 uint32_t IpDropped = 1; 191 uint32_t IpBcastReceived = 0; 192 uint32_t IpSeqReceived = 0; 193 194 cmd = &iocbq->iocb; 195 ubp = NULL; 196 197 for (i = 0; i < MAX_VPORTS; i++) { 198 port = &VPORT(i); 199 200 if (!(port->flag & EMLXS_PORT_BOUND) || 201 !(port->flag & EMLXS_PORT_IP_UP)) { 202 continue; 203 } 204 205 ubp = 206 (fc_unsol_buf_t *)emlxs_ub_get(port, size, 207 FC_TYPE_IS8802_SNAP, 0); 208 209 if (!ubp) { 210 /* Theoretically we should never get here. */ 211 /* There should be one DMA buffer for every ub */ 212 /* buffer. If we are out of ub buffers */ 213 /* then some how this matching has been corrupted */ 214 215 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg, 216 "Buffer not found. paddr=%lx", 217 getPaddr(cmd->un.cont64[0].addrHigh, 218 cmd->un.cont64[0].addrLow)); 219 220 continue; 221 } 222 223 bcopy(mp->virt, ubp->ub_buffer, size); 224 225 ub_priv = ubp->ub_fca_private; 226 nd = (NETHDR *)ubp->ub_buffer; 227 mac = nd->fc_srcname.IEEE; 228 ndlp = emlxs_node_find_mac(port, mac); 229 230 if (ndlp) { 231 sid = ndlp->nlp_DID; 232 233 if ((ndlp->nlp_Xri == 0) && 234 !(ndlp->nlp_flag[FC_IP_RING] & NLP_RPI_XRI)) { 235 (void) emlxs_create_xri(port, rp, ndlp); 236 } 237 } 238 239 /* 240 * If no node is found, then check if this is a 241 * broadcast frame 242 */ 243 else if (cmd->un.xrseq.w5.hcsw.Fctl & BC) { 244 sid = cmd->un.ulpWord[4] & 0x00ffffff; 245 } 246 247 else { 248 /* We have to drop this frame because we do not have */ 249 /* the S_ID of the request */ 250 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_ip_dropped_msg, 251 "Node not found. mac=%02x%02x%02x%02x%02x%02x", 252 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); 253 254 (void) emlxs_ub_release((opaque_t)port, 1, 255 &ubp->ub_token); 256 257 continue; 258 } 259 260 if (cmd->un.xrseq.w5.hcsw.Fctl & BC) { 261 IpBcastReceived++; 262 } else { 263 IpSeqReceived++; 264 } 265 266 /* 267 * Setup frame header 268 */ 269 ubp->ub_frame.r_ctl = cmd->un.xrseq.w5.hcsw.Rctl; 270 ubp->ub_frame.type = cmd->un.xrseq.w5.hcsw.Type; 271 ubp->ub_frame.s_id = sid; 272 ubp->ub_frame.ox_id = ub_priv->token; 273 ubp->ub_frame.rx_id = cmd->ulpContext; 274 ubp->ub_class = FC_TRAN_CLASS3; 275 276 emlxs_ub_callback(port, ubp); 277 IpDropped = 0; 278 } 279 port = &PPORT; 280 281 out: 282 283 if (IpDropped) { 284 HBASTATS.IpDropped++; 285 } 286 287 if (IpBcastReceived) { 288 HBASTATS.IpBcastReceived++; 289 } 290 291 if (IpSeqReceived) { 292 HBASTATS.IpSeqReceived++; 293 } 294 295 return (0); 296 297 } /* emlxs_ip_handle_unsol_req() */ 298 299 300 extern int32_t 301 emlxs_ip_handle_rcv_seq_list(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 302 { 303 emlxs_port_t *port = &PPORT; 304 IOCB *cmd; 305 uint64_t bdeAddr; 306 MATCHMAP *mp = NULL; 307 #ifdef SLI3_SUPPORT 308 HBQE_t *hbqE; 309 uint32_t hbq_id; 310 uint32_t hbqe_tag; 311 #endif /* SLI3_SUPPORT */ 312 313 /* 314 * No action required for now. 315 */ 316 cmd = &iocbq->iocb; 317 318 HBASTATS.IpRcvEvent++; 319 320 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 321 "Receive sequence list: cmd=0x%x iotag=0x%x status=0x%x " 322 "w4=0x%x ringno=0x%x", cmd->ulpCommand, cmd->ulpIoTag, 323 cmd->ulpStatus, cmd->un.ulpWord[4], rp->ringno); 324 325 if (cmd->ulpStatus) { 326 goto out; 327 } 328 #ifdef SLI3_SUPPORT 329 hbqE = (HBQE_t *)&iocbq->iocb; 330 hbq_id = hbqE->unt.ext.HBQ_tag; 331 hbqe_tag = hbqE->unt.ext.HBQE_tag; 332 333 if (hba->flag & FC_HBQ_ENABLED) { 334 HBQ_INIT_t *hbq; 335 336 hbq = &hba->hbq_table[hbq_id]; 337 338 HBASTATS.IpUbPosted--; 339 340 if (hbqe_tag >= hbq->HBQ_numEntries) { 341 mp = NULL; 342 } else { 343 mp = hba->hbq_table[hbq_id].HBQ_PostBufs[hbqe_tag]; 344 } 345 } else 346 #endif /* SLI3_SUPPORT */ 347 { 348 /* Check for valid buffer */ 349 if (!(cmd->un.cont64[0].tus.f.bdeFlags & BUFF_TYPE_INVALID)) { 350 bdeAddr = 351 getPaddr(cmd->un.cont64[0].addrHigh, 352 cmd->un.cont64[0].addrLow); 353 mp = emlxs_mem_get_vaddr(hba, rp, bdeAddr); 354 } 355 } 356 357 out: 358 359 #ifdef SLI3_SUPPORT 360 if (hba->flag & FC_HBQ_ENABLED) { 361 emlxs_update_HBQ_index(hba, hbq_id); 362 } else 363 #endif /* SLI3_SUPPORT */ 364 { 365 if (mp) { 366 (void) emlxs_mem_put(hba, MEM_IPBUF, (uint8_t *)mp); 367 } 368 (void) emlxs_post_buffer(hba, rp, 1); 369 } 370 371 HBASTATS.IpDropped++; 372 373 return (0); 374 375 } /* emlxs_ip_handle_rcv_seq_list() */ 376 377 378 379 /* 380 * Process a create_xri command completion. 381 */ 382 extern int32_t 383 emlxs_handle_create_xri(emlxs_hba_t *hba, RING *rp, IOCBQ *iocbq) 384 { 385 emlxs_port_t *port = &PPORT; 386 IOCB *cmd; 387 NODELIST *ndlp; 388 fc_packet_t *pkt; 389 emlxs_buf_t *sbp; 390 391 cmd = &iocbq->iocb; 392 393 sbp = (emlxs_buf_t *)iocbq->sbp; 394 395 if (!sbp) { 396 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_stray_ip_completion_msg, 397 "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x", 398 cmd->ulpCommand, cmd->ulpIoTag, cmd->ulpStatus, 399 cmd->un.ulpWord[4]); 400 401 return (EIO); 402 } 403 404 /* check for first xmit completion in sequence */ 405 ndlp = (NODELIST *)sbp->node; 406 407 if (cmd->ulpStatus) { 408 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_bad_ip_completion_msg, 409 "create_xri: cmd=0x%x iotag=0x%x status=0x%x w4=0x%x", 410 cmd->ulpCommand, cmd->ulpIoTag, cmd->ulpStatus, 411 cmd->un.ulpWord[4]); 412 413 mutex_enter(&EMLXS_RINGTX_LOCK); 414 ndlp->nlp_flag[rp->ringno] &= ~NLP_RPI_XRI; 415 mutex_exit(&EMLXS_RINGTX_LOCK); 416 417 return (EIO); 418 } 419 420 mutex_enter(&EMLXS_RINGTX_LOCK); 421 ndlp->nlp_Xri = cmd->ulpContext; 422 ndlp->nlp_flag[rp->ringno] &= ~NLP_RPI_XRI; 423 mutex_exit(&EMLXS_RINGTX_LOCK); 424 425 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 426 "create_xri completed: DID=0x%x Xri=0x%x iotag=0x%x", 427 ndlp->nlp_DID, ndlp->nlp_Xri, cmd->ulpIoTag); 428 429 pkt = sbp->pkt; 430 emlxs_pkt_free(pkt); 431 432 return (0); 433 434 } /* emlxs_handle_create_xri() */ 435 436 437 /* 438 * Issue an iocb command to create an exchange with the remote Nport 439 * specified by the NODELIST entry. 440 */ 441 extern int32_t 442 emlxs_create_xri(emlxs_port_t *port, RING *rp, NODELIST *ndlp) 443 { 444 emlxs_hba_t *hba = HBA; 445 IOCB *icmd; 446 IOCBQ *iocbq; 447 fc_packet_t *pkt; 448 emlxs_buf_t *sbp; 449 uint16_t iotag; 450 451 /* Check if an XRI has already been requested */ 452 mutex_enter(&EMLXS_RINGTX_LOCK); 453 if (ndlp->nlp_Xri != 0 || (ndlp->nlp_flag[rp->ringno] & NLP_RPI_XRI)) { 454 mutex_exit(&EMLXS_RINGTX_LOCK); 455 return (0); 456 } 457 ndlp->nlp_flag[rp->ringno] |= NLP_RPI_XRI; 458 mutex_exit(&EMLXS_RINGTX_LOCK); 459 460 if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) { 461 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 462 "create_xri failed: Unable to allocate pkt. did=0x%x", 463 ndlp->nlp_DID); 464 465 goto fail; 466 } 467 468 sbp = (emlxs_buf_t *)pkt->pkt_fca_private; 469 iocbq = &sbp->iocbq; 470 471 /* Get the iotag by registering the packet */ 472 iotag = emlxs_register_pkt(rp, sbp); 473 474 if (!iotag) { 475 /* 476 * No more command slots available, retry later 477 */ 478 emlxs_pkt_free(pkt); 479 480 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 481 "create_xri failed: Unable to allocate IOTAG. did=0x%x", 482 ndlp->nlp_DID); 483 484 goto fail; 485 } 486 487 icmd = &iocbq->iocb; 488 icmd->ulpIoTag = iotag; 489 icmd->ulpContext = ndlp->nlp_Rpi; 490 icmd->ulpLe = 1; 491 icmd->ulpCommand = CMD_CREATE_XRI_CR; 492 icmd->ulpOwner = OWN_CHIP; 493 494 /* Initalize iocbq */ 495 iocbq->port = (void *)port; 496 iocbq->node = (void *)ndlp; 497 iocbq->ring = (void *)rp; 498 499 mutex_enter(&sbp->mtx); 500 sbp->node = (void *)ndlp; 501 sbp->ring = rp; 502 mutex_exit(&sbp->mtx); 503 504 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_ip_detail_msg, 505 "create_xri sent: DID=0x%x Xri=0x%x iotag=0x%x", ndlp->nlp_DID, 506 ndlp->nlp_Xri, iotag); 507 508 emlxs_sli_issue_iocb_cmd(hba, rp, iocbq); 509 510 return (0); 511 512 fail: 513 514 /* Clear the XRI flag */ 515 mutex_enter(&EMLXS_RINGTX_LOCK); 516 ndlp->nlp_flag[rp->ringno] &= ~NLP_RPI_XRI; 517 mutex_exit(&EMLXS_RINGTX_LOCK); 518 519 return (1); 520 521 } /* emlxs_create_xri() */ 522