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 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * The following notice accompanied the original version of this file: 29 * 30 * BSD LICENSE 31 * 32 * Copyright(c) 2007 Intel Corporation. All rights reserved. 33 * All rights reserved. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 39 * * Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * * Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in 43 * the documentation and/or other materials provided with the 44 * distribution. 45 * * Neither the name of Intel Corporation nor the names of its 46 * contributors may be used to endorse or promote products derived 47 * from this software without specific prior written permission. 48 * 49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 60 */ 61 62 /* 63 * This file defines interfaces between fcoe and fcoet driver. 64 */ 65 66 /* 67 * Driver kernel header files 68 */ 69 #include <sys/conf.h> 70 #include <sys/ddi.h> 71 #include <sys/stat.h> 72 #include <sys/pci.h> 73 #include <sys/sunddi.h> 74 #include <sys/modctl.h> 75 #include <sys/file.h> 76 #include <sys/cred.h> 77 #include <sys/byteorder.h> 78 #include <sys/atomic.h> 79 #include <sys/modhash.h> 80 #include <sys/scsi/scsi.h> 81 #include <sys/ethernet.h> 82 83 /* 84 * COMSTAR header files 85 */ 86 #include <sys/stmf_defines.h> 87 #include <sys/fct_defines.h> 88 #include <sys/stmf.h> 89 #include <sys/portif.h> 90 #include <sys/fct.h> 91 92 /* 93 * FCoE header files 94 */ 95 #include <sys/fcoe/fcoe_common.h> 96 97 /* 98 * Driver's own header files 99 */ 100 #include <fcoet.h> 101 #include <fcoet_eth.h> 102 103 /* 104 * function forward declaration 105 */ 106 static fcoet_exchange_t *fcoet_create_unsol_exchange(fcoe_frame_t *frame); 107 static int fcoet_process_sol_fcp_data(fcoe_frame_t *frm); 108 static int fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm); 109 static int fcoet_process_unsol_els_req(fcoe_frame_t *frm); 110 static int fcoet_process_sol_els_rsp(fcoe_frame_t *frm); 111 static int fcoet_process_unsol_abts_req(fcoe_frame_t *frame); 112 static int fcoet_process_sol_abts_acc(fcoe_frame_t *frame); 113 static int fcoet_process_sol_abts_rjt(fcoe_frame_t *frame); 114 static int fcoet_process_unsol_ct_req(fcoe_frame_t *frm); 115 static int fcoet_process_sol_ct_rsp(fcoe_frame_t *frame); 116 static int fcoet_process_sol_flogi_rsp(fcoe_frame_t *frame); 117 static int fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm); 118 static int fcoet_send_fcp_status_done(fcoe_frame_t *frm); 119 static int fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm); 120 static int fcoet_send_sol_els_req_done(fcoe_frame_t *frm); 121 static int fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm); 122 static int fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm); 123 static int fcoet_send_sol_bls_req_done(fcoe_frame_t *frm); 124 static int fcoet_send_sol_ct_req_done(fcoe_frame_t *frm); 125 static int fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch); 126 127 /* 128 * rx_frame & release_sol_frame 129 * There should be no same OXID/RXID in on-going exchanges. 130 * RXID -> unsol_rxid_hash 131 * OXID -> sol_oxid_hash 132 */ 133 134 void 135 fcoet_rx_frame(fcoe_frame_t *frm) 136 { 137 uint8_t rctl = FRM_R_CTL(frm); 138 139 switch (rctl) { 140 case 0x01: 141 /* 142 * Solicited data 143 */ 144 if (fcoet_process_sol_fcp_data(frm)) { 145 FCOET_LOG("fcoet_rx_frame", 146 "fcoet_process_sol_fcp_data failed"); 147 } 148 break; 149 150 case 0x06: 151 /* 152 * Unsolicited fcp_cmnd 153 */ 154 if (fcoet_process_unsol_fcp_cmd(frm)) { 155 FCOET_LOG("fcoet_rx_frame", 156 "fcoet_process_unsol_fcp_cmd failed"); 157 } 158 break; 159 160 case 0x22: 161 /* 162 * unsolicited ELS req 163 */ 164 if (fcoet_process_unsol_els_req(frm)) { 165 FCOET_LOG("fcoet_rx_frame", 166 "fcoet_process_unsol_els_req failed"); 167 } 168 break; 169 170 case 0x23: 171 /* 172 * solicited ELS rsp 173 */ 174 if (fcoet_process_sol_els_rsp(frm)) { 175 FCOET_LOG("fcoet_rx_frame", 176 "fcoet_process_sol_els_rsp failed"); 177 } 178 break; 179 180 case 0x81: 181 /* 182 * unsolicted ABTS req 183 */ 184 if (fcoet_process_unsol_abts_req(frm)) { 185 FCOET_LOG("fcoet_rx_frame", 186 "fcoet_process_unsol_abts_req failed"); 187 } 188 break; 189 190 case 0x84: 191 /* 192 * solicited ABTS acc response 193 */ 194 if (fcoet_process_sol_abts_acc(frm)) { 195 FCOET_LOG("fcoet_rx_frame", 196 "fcoet_process_sol_abts_acc failed"); 197 } 198 break; 199 case 0x85: 200 /* 201 * solcited ABTS rjt response 202 */ 203 if (fcoet_process_sol_abts_rjt(frm)) { 204 FCOET_LOG("fcoet_rx_frame", 205 "fcoet_process_sol_abts_rjt failed"); 206 } 207 break; 208 209 case 0x02: 210 /* 211 * unsolicited CT req 212 */ 213 if (fcoet_process_unsol_ct_req(frm)) { 214 FCOET_LOG("fcoet_rx_frame", 215 "fcoet_process_sol_ct_rsp failed"); 216 } 217 break; 218 219 case 0x03: 220 /* 221 * sol ct rsp 222 */ 223 if (fcoet_process_sol_ct_rsp(frm)) { 224 FCOET_LOG("fcoet_rx_frame", 225 "fcoet_process_sol_ct_rsp failed"); 226 } 227 break; 228 229 default: 230 /* 231 * Unsupported frame 232 */ 233 PRT_FRM_HDR("Unsupported unsol frame: ", frm); 234 break; 235 } 236 237 /* 238 * Release the frame in the end 239 */ 240 frm->frm_eport->eport_free_netb(frm->frm_netb); 241 frm->frm_eport->eport_release_frame(frm); 242 } 243 244 /* 245 * For solicited frames, after FCoE has sent it out, it will call this 246 * to notify client(FCoEI/FCoET) about its completion. 247 */ 248 void 249 fcoet_release_sol_frame(fcoe_frame_t *frm) 250 { 251 fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; 252 253 /* 254 * From now, we should not access both frm_hdr and frm_payload. Its 255 * mblk could have been released by MAC driver. 256 */ 257 switch (FRM2TFM(frm)->tfm_rctl) { 258 case 0x01: 259 if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 260 FCOET_RELE_XCHG(xch); 261 break; 262 } 263 if (fcoet_send_sol_fcp_data_done(frm)) { 264 ASSERT(0); 265 } 266 break; 267 268 case 0x05: 269 break; 270 271 case 0x07: 272 if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 273 FCOET_RELE_XCHG(xch); 274 break; 275 } 276 277 if (fcoet_send_fcp_status_done(frm)) { 278 ASSERT(0); 279 } 280 break; 281 282 case 0x23: 283 if (xch && xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 284 FCOET_RELE_XCHG(xch); 285 break; 286 } 287 if (fcoet_send_unsol_els_rsp_done(frm)) { 288 ASSERT(0); 289 } 290 break; 291 292 case 0x22: 293 if (fcoet_send_sol_els_req_done(frm)) { 294 ASSERT(0); 295 } 296 break; 297 298 case 0x84: 299 if (fcoet_send_unsol_bls_acc_done(frm)) { 300 ASSERT(0); 301 } 302 break; 303 304 case 0x85: 305 if (fcoet_send_unsol_bls_rjt_done(frm)) { 306 ASSERT(0); 307 } 308 break; 309 310 case 0x81: 311 if (fcoet_send_sol_bls_req_done(frm)) { 312 ASSERT(0); 313 } 314 break; 315 316 case 0x02: 317 if (fcoet_send_sol_ct_req_done(frm)) { 318 ASSERT(0); 319 } 320 break; 321 322 case 0x03: 323 default: 324 /* 325 * Unsupported frame 326 */ 327 PRT_FRM_HDR("Unsupported sol frame: ", frm); 328 break; 329 } 330 331 /* 332 * We should release the frame 333 */ 334 FRM2SS(frm)->ss_eport->eport_release_frame(frm); 335 } 336 337 void 338 fcoet_port_event(fcoe_port_t *eport, uint32_t event) 339 { 340 fcoet_soft_state_t *ss = EPORT2SS(eport); 341 switch (event) { 342 case FCOE_NOTIFY_EPORT_LINK_UP: 343 if (eport->eport_mtu >= FCOE_MIN_MTU_SIZE) { 344 ss->ss_fcp_data_payload_size = 345 FCOE_DEFAULT_FCP_DATA_PAYLOAD_SIZE; 346 } else { 347 ss->ss_fcp_data_payload_size = 348 FCOE_MIN_FCP_DATA_PAYLOAD_SIZE; 349 } 350 FCOET_LOG("fcoet_port_event", "LINK UP notified"); 351 mutex_enter(&ss->ss_watch_mutex); 352 ss->ss_sol_flogi_state = SFS_FLOGI_INIT; 353 cv_signal(&ss->ss_watch_cv); 354 mutex_exit(&ss->ss_watch_mutex); 355 break; 356 case FCOE_NOTIFY_EPORT_LINK_DOWN: 357 fct_handle_event(ss->ss_port, 358 FCT_EVENT_LINK_DOWN, 0, 0); 359 /* Need clear up all other things */ 360 FCOET_LOG("fcoet_port_event", "LINK DOWN notified"); 361 ss->ss_sol_flogi_state = SFS_WAIT_LINKUP; 362 break; 363 default: 364 break; 365 } 366 } 367 368 /* 369 * For unsolicited exchanges, FCoET is only responsible for allocation of 370 * req_payload. FCT will allocate resp_payload after the exchange is 371 * passed on. 372 */ 373 static fcoet_exchange_t * 374 fcoet_create_unsol_exchange(fcoe_frame_t *frm) 375 { 376 uint8_t r_ctl; 377 int cdb_size; 378 fcoet_exchange_t *xch, *xch_tmp; 379 fct_cmd_t *cmd; 380 fcoe_fcp_cmnd_t *ffc; 381 uint32_t task_expected_len = 0; 382 383 r_ctl = FRM_R_CTL(frm); 384 switch (r_ctl) { 385 case 0x22: 386 /* 387 * FCoET's unsolicited ELS 388 */ 389 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ELS, 390 GET_STRUCT_SIZE(fcoet_exchange_t) + 391 frm->frm_payload_size, 0); 392 if (cmd == NULL) { 393 FCOET_EXT_LOG(0, "can't get cmd"); 394 return (NULL); 395 } 396 break; 397 398 case 0x06: 399 /* 400 * FCoET's unsolicited SCSI cmd 401 */ 402 cdb_size = 16; /* need improve later */ 403 cmd = fct_scsi_task_alloc(FRM2SS(frm)->ss_port, FCT_HANDLE_NONE, 404 FRM_S_ID(frm), frm->frm_payload, cdb_size, 405 STMF_TASK_EXT_NONE); 406 if (cmd == NULL) { 407 FCOET_EXT_LOG(0, "can't get fcp cmd"); 408 return (NULL); 409 } 410 ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload; 411 task_expected_len = FCOE_B2V_4(ffc->ffc_fcp_dl); 412 break; 413 414 default: 415 FCOET_EXT_LOG(0, "unsupported R_CTL: %x", r_ctl); 416 return (NULL); 417 } 418 419 /* 420 * xch initialization 421 */ 422 xch = CMD2XCH(cmd); 423 xch->xch_oxid = FRM_OXID(frm); 424 xch->xch_flags = 0; 425 xch->xch_ss = FRM2SS(frm); 426 xch->xch_cmd = cmd; 427 xch->xch_current_seq = NULL; 428 xch->xch_left_data_size = 0; 429 if (task_expected_len) { 430 xch->xch_dbuf_num = 431 (task_expected_len + FCOET_MAX_DBUF_LEN - 1) / 432 FCOET_MAX_DBUF_LEN; 433 xch->xch_dbufs = 434 kmem_zalloc(xch->xch_dbuf_num * sizeof (stmf_data_buf_t *), 435 KM_SLEEP); 436 } 437 xch->xch_start_time = ddi_get_lbolt(); 438 do { 439 xch->xch_rxid = atomic_add_16_nv( 440 &xch->xch_ss->ss_next_unsol_rxid, 1); 441 if (xch->xch_rxid == 0xFFFF) { 442 xch->xch_rxid = atomic_add_16_nv( 443 &xch->xch_ss->ss_next_unsol_rxid, 1); 444 } 445 } while (mod_hash_find(FRM2SS(frm)->ss_unsol_rxid_hash, 446 (mod_hash_key_t)(intptr_t)xch->xch_rxid, 447 (mod_hash_val_t)&xch_tmp) == 0); 448 449 xch->xch_sequence_no = 0; 450 xch->xch_ref = 0; 451 (void) mod_hash_insert(xch->xch_ss->ss_unsol_rxid_hash, 452 (mod_hash_key_t)(intptr_t)xch->xch_rxid, (mod_hash_val_t)xch); 453 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; 454 455 /* 456 * cmd initialization 457 */ 458 cmd->cmd_port = FRM2SS(frm)->ss_port; 459 cmd->cmd_rp_handle = FCT_HANDLE_NONE; 460 cmd->cmd_rportid = FRM_S_ID(frm); 461 cmd->cmd_lportid = FRM_D_ID(frm); 462 cmd->cmd_oxid = xch->xch_oxid; 463 cmd->cmd_rxid = xch->xch_rxid; 464 465 fcoet_init_tfm(frm, xch); 466 return (xch); 467 } 468 469 int 470 fcoet_clear_unsol_exchange(fcoet_exchange_t *xch) 471 { 472 mod_hash_val_t val = NULL; 473 474 if (mod_hash_remove(xch->xch_ss->ss_unsol_rxid_hash, 475 (mod_hash_key_t)(intptr_t)xch->xch_rxid, &val) == 0) { 476 if (xch->xch_dbuf_num) { 477 kmem_free((void*)xch->xch_dbufs, 478 xch->xch_dbuf_num * sizeof (void *)); 479 xch->xch_dbufs = NULL; 480 xch->xch_dbuf_num = 0; 481 } 482 ASSERT(xch->xch_flags & XCH_FLAG_IN_HASH_TABLE); 483 ASSERT((fcoet_exchange_t *)val == xch); 484 xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; 485 return (FCOE_SUCCESS); 486 } 487 488 FCOET_LOG("fcoet_clear_unsol_exchange", "xch %p already cleared from " 489 "hash table", xch); 490 return (FCOE_FAILURE); 491 } 492 493 void 494 fcoet_clear_sol_exchange(fcoet_exchange_t *xch) 495 { 496 mod_hash_val_t val = NULL; 497 498 if (xch->xch_flags & XCH_FLAG_IN_HASH_TABLE) { 499 (void) mod_hash_remove(xch->xch_ss->ss_sol_oxid_hash, 500 (mod_hash_key_t)(intptr_t)xch->xch_oxid, &val); 501 ASSERT((fcoet_exchange_t *)val == xch); 502 xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; 503 } 504 } 505 506 static int 507 fcoet_process_sol_fcp_data(fcoe_frame_t *frm) 508 { 509 fcoet_exchange_t *xch = NULL; 510 fcoet_soft_state_t *ss = NULL; 511 fct_status_t fc_st; 512 uint32_t iof; 513 uint16_t unsol_rxid; 514 int sge_idx; 515 stmf_data_buf_t *dbuf; 516 int data_offset; 517 518 unsol_rxid = FRM_RXID(frm); 519 if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash, 520 (mod_hash_key_t)(intptr_t)unsol_rxid, 521 (mod_hash_val_t)&xch, fcoet_modhash_find_cb) != 0) { 522 return (FCOE_FAILURE); 523 } 524 525 /* 526 * we will always have a buf waiting there 527 */ 528 data_offset = FRM_PARAM(frm); 529 dbuf = xch->xch_dbufs[data_offset/FCOET_MAX_DBUF_LEN]; 530 ASSERT(dbuf); 531 ss = xch->xch_ss; 532 sge_idx = (data_offset % FCOET_MAX_DBUF_LEN)/ 533 ss->ss_fcp_data_payload_size; 534 535 ASSERT(((sge_idx < FCOET_GET_SEG_NUM(dbuf) - 1) && 536 (frm->frm_payload_size == ss->ss_fcp_data_payload_size)) || 537 ((sge_idx == FCOET_GET_SEG_NUM(dbuf) - 1) && 538 (frm->frm_payload_size % ss->ss_fcp_data_payload_size == 539 dbuf->db_data_size % ss->ss_fcp_data_payload_size))); 540 541 bcopy(frm->frm_payload, dbuf->db_sglist[sge_idx].seg_addr, 542 frm->frm_payload_size); 543 544 xch->xch_left_data_size -= frm->frm_payload_size; 545 if (xch->xch_left_data_size <= 0) { 546 fc_st = FCT_SUCCESS; 547 iof = 0; 548 dbuf->db_xfer_status = fc_st; 549 dbuf->db_flags |= DB_DONT_REUSE; 550 fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof); 551 } 552 553 FCOET_RELE_XCHG(xch); 554 return (FCOE_SUCCESS); 555 } 556 557 static int 558 fcoet_process_unsol_fcp_cmd(fcoe_frame_t *frm) 559 { 560 fcoet_exchange_t *xch; 561 fcoe_fcp_cmnd_t *ffc; 562 uint8_t tm; 563 scsi_task_t *task; 564 565 xch = fcoet_create_unsol_exchange(frm); 566 if (xch == NULL) { 567 FCOET_LOG("fcoet_process_unsol_fcp_cmd", "can't get exchange"); 568 return (FCOE_FAILURE); 569 } 570 571 ffc = (fcoe_fcp_cmnd_t *)frm->frm_payload; 572 task = XCH2TASK(xch); 573 task->task_csn_size = 8; 574 task->task_max_nbufs = 1; 575 task->task_cmd_seq_no = FCOE_B2V_1(ffc->ffc_ref_num); 576 task->task_flags = FCOE_B2V_1(ffc->ffc_attribute) & 0x07; 577 task->task_flags |= 578 (FCOE_B2V_1(ffc->ffc_addlen_rdwr) & 0x03) << 5; 579 task->task_expected_xfer_length = FCOE_B2V_4(ffc->ffc_fcp_dl); 580 581 tm = FCOE_B2V_1(ffc->ffc_management_flags); 582 if (tm) { 583 if (tm & BIT_1) { 584 task->task_mgmt_function = TM_ABORT_TASK_SET; 585 } else if (tm & BIT_2) { 586 task->task_mgmt_function = TM_CLEAR_TASK_SET; 587 } else if (tm & BIT_4) { 588 task->task_mgmt_function = TM_LUN_RESET; 589 } else if (tm & BIT_5) { 590 task->task_mgmt_function = TM_TARGET_COLD_RESET; 591 } else if (tm & BIT_6) { 592 task->task_mgmt_function = TM_CLEAR_ACA; 593 } else { 594 task->task_mgmt_function = TM_ABORT_TASK; 595 } 596 } 597 598 bcopy(ffc->ffc_cdb, task->task_cdb, 16); 599 fct_post_rcvd_cmd(xch->xch_cmd, NULL); 600 return (FCOE_SUCCESS); 601 } 602 /* 603 * It must be from link 604 * req_payload has been allocated when create_unsol_exchange 605 */ 606 static int 607 fcoet_process_unsol_els_req(fcoe_frame_t *frm) 608 { 609 int ret = FCOE_SUCCESS; 610 fcoet_exchange_t *xch; 611 612 xch = fcoet_create_unsol_exchange(frm); 613 ASSERT(xch); 614 ASSERT(FRM_IS_LAST_FRAME(frm)); 615 616 /* 617 * For the reason of keeping symmetric, we do copy here as in 618 * process_sol_els instead of in create_unsol_exchange. 619 * req_payload depends on how to allocate buf in create_unsol_exchange 620 */ 621 XCH2ELS(xch)->els_req_alloc_size = 0; 622 XCH2ELS(xch)->els_req_size = frm->frm_payload_size; 623 XCH2ELS(xch)->els_req_payload = 624 GET_BYTE_OFFSET(xch, GET_STRUCT_SIZE(fcoet_exchange_t)); 625 bcopy(frm->frm_payload, XCH2ELS(xch)->els_req_payload, 626 XCH2ELS(xch)->els_req_size); 627 if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) { 628 /* 629 * Ensure LINK_UP event has been handled, or PLOIG has 630 * been processed by FCT, or else it will be discarded. 631 * It need more consideration later ??? 632 */ 633 if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PLOGI) && 634 (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) { 635 delay(STMF_SEC2TICK(1)/2); 636 } 637 638 if ((XCH2ELS(xch)->els_req_payload[0] == ELS_OP_PRLI) && 639 (xch->xch_ss->ss_flags & SS_FLAG_DELAY_PLOGI)) { 640 atomic_and_32(&xch->xch_ss->ss_flags, 641 ~SS_FLAG_DELAY_PLOGI); 642 delay(STMF_SEC2TICK(1)/3); 643 } 644 fct_post_rcvd_cmd(xch->xch_cmd, NULL); 645 } else { 646 /* 647 * We always handle FLOGI internally 648 * Save dst mac address from FLOGI request to restore later 649 */ 650 bcopy((char *)frm->frm_hdr-22, 651 frm->frm_eport->eport_efh_dst, ETHERADDRL); 652 ret = fcoet_process_unsol_flogi_req(xch); 653 } 654 return (ret); 655 } 656 657 658 /* 659 * It must be from link, but could be incomplete because of network problems 660 */ 661 static int 662 fcoet_process_sol_els_rsp(fcoe_frame_t *frm) 663 { 664 uint32_t actual_size; 665 fct_status_t fc_st; 666 uint32_t iof; 667 uint16_t sol_oxid; 668 fcoet_exchange_t *xch = NULL; 669 fct_els_t *els = NULL; 670 int ret = FCOE_SUCCESS; 671 672 sol_oxid = FRM_OXID(frm); 673 if (mod_hash_find_cb(FRM2SS(frm)->ss_sol_oxid_hash, 674 (mod_hash_key_t)(intptr_t)sol_oxid, 675 (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) { 676 return (FCOE_FAILURE); 677 } 678 if (xch != FRM2SS(frm)->ss_sol_flogi) { 679 fcoet_clear_sol_exchange(xch); 680 } 681 682 fcoet_init_tfm(frm, xch); 683 els = CMD2ELS(xch->xch_cmd); 684 ASSERT(FRM_IS_LAST_FRAME(frm)); 685 actual_size = els->els_resp_size; 686 if (actual_size > frm->frm_payload_size) { 687 actual_size = frm->frm_payload_size; 688 } 689 690 els->els_resp_size = (uint16_t)actual_size; 691 bcopy(frm->frm_payload, els->els_resp_payload, actual_size); 692 693 if (xch->xch_ss->ss_sol_flogi == xch) { 694 /* 695 * We handle FLOGI internally 696 */ 697 ret = fcoet_process_sol_flogi_rsp(frm); 698 FCOET_RELE_XCHG(xch); 699 } else { 700 fc_st = FCT_SUCCESS; 701 iof = FCT_IOF_FCA_DONE; 702 FCOET_RELE_XCHG(xch); 703 fct_send_cmd_done(xch->xch_cmd, fc_st, iof); 704 } 705 return (ret); 706 } 707 708 /* 709 * It's still in the context of being aborted exchange, but FCT can't support 710 * this scheme, so there are two fct_cmd_t that are bound with one exchange. 711 */ 712 static int 713 fcoet_process_unsol_abts_req(fcoe_frame_t *frm) 714 { 715 fct_cmd_t *cmd; 716 fcoet_exchange_t *xch = NULL; 717 uint16_t unsol_rxid; 718 719 FCOET_LOG("fcoet_process_unsol_abts_req", "ABTS: %x/%x", 720 FRM_OXID(frm), FRM_RXID(frm)); 721 unsol_rxid = FRM_RXID(frm); 722 if (mod_hash_find_cb(FRM2SS(frm)->ss_unsol_rxid_hash, 723 (mod_hash_key_t)(intptr_t)unsol_rxid, 724 (mod_hash_val_t *)&xch, fcoet_modhash_find_cb) != 0) { 725 FCOET_LOG("fcoet_process_unsol_abts_req", 726 "can't find aborted exchange"); 727 return (FCOE_SUCCESS); 728 } 729 730 fcoet_init_tfm(frm, xch); 731 if (!FRM_IS_LAST_FRAME(frm)) { 732 FCOET_LOG("fcoet_process_unsol_abts_req", 733 "not supported this kind frame"); 734 FCOET_RELE_XCHG(xch); 735 return (FCOE_FAILURE); 736 } 737 738 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_RCVD_ABTS, 0, 0); 739 if (cmd == NULL) { 740 FCOET_LOG("fcoet_process_unsol_abts_req", 741 "can't alloc fct_cmd_t"); 742 FCOET_RELE_XCHG(xch); 743 return (FCOE_FAILURE); 744 } 745 746 xch->xch_flags |= XCH_FLAG_INI_ASKED_ABORT; 747 cmd->cmd_fca_private = xch; 748 cmd->cmd_port = xch->xch_cmd->cmd_port; 749 cmd->cmd_rp_handle = xch->xch_cmd->cmd_rp_handle; 750 cmd->cmd_rportid = xch->xch_cmd->cmd_rportid; 751 cmd->cmd_lportid = xch->xch_cmd->cmd_lportid; 752 cmd->cmd_oxid = xch->xch_cmd->cmd_oxid; 753 cmd->cmd_rxid = xch->xch_cmd->cmd_rxid; 754 fct_post_rcvd_cmd(cmd, NULL); 755 FCOET_LOG("fcoet_process_unsol_abts_req", 756 "abts now: xch/%p, frm/%p - time/%p", 757 xch, frm, ddi_get_lbolt()); 758 759 FCOET_RELE_XCHG(xch); 760 return (FCOE_SUCCESS); 761 } 762 763 static int 764 fcoet_process_sol_abts_acc(fcoe_frame_t *frm) 765 { 766 fcoet_exchange_t *xch = NULL; 767 uint16_t sol_oxid; 768 769 sol_oxid = FRM_OXID(frm); 770 if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, 771 (mod_hash_key_t)(intptr_t)sol_oxid, 772 (mod_hash_val_t *)&xch) != 0) { 773 /* 774 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash 775 * in fcoet_watch_handle_sol_flogi, Will improve it later 776 */ 777 return (FCOE_SUCCESS); 778 } 779 780 xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; 781 if (!FRM_IS_LAST_FRAME(frm)) { 782 FCOET_LOG("fcoet_process_sol_abts_acc", 783 "not supported this kind frame"); 784 FCOET_RELE_XCHG(xch); 785 return (FCOE_FAILURE); 786 } 787 FCOET_LOG("fcoet_process_sol_abts_acc", 788 "ABTS received but there is nothing to do"); 789 return (FCOE_SUCCESS); 790 } 791 792 static int 793 fcoet_process_sol_abts_rjt(fcoe_frame_t *frm) 794 { 795 fcoet_exchange_t *xch = NULL; 796 uint16_t sol_oxid; 797 798 sol_oxid = FRM_OXID(frm); 799 if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, 800 (mod_hash_key_t)(intptr_t)sol_oxid, 801 (mod_hash_val_t *)&xch) != 0) { 802 /* 803 * So far ABTS for FLOGI might be removed from ss_sol_oxid_hash 804 * in fcoet_watch_handle_sol_flogi, Will improve it later 805 */ 806 return (FCOE_SUCCESS); 807 } 808 809 xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; 810 811 if (!FRM_IS_LAST_FRAME(frm)) { 812 FCOET_LOG("fcoet_process_sol_abts_rjt", 813 "not supported this kind frame"); 814 return (FCOE_FAILURE); 815 } 816 817 FCOET_LOG("fcoet_process_sol_abts_rjt", 818 "ABTS_RJT received rjt reason %x but there is nothing to do", 819 frm->frm_payload[1]); 820 return (FCOE_SUCCESS); 821 } 822 823 static int 824 fcoet_process_unsol_ct_req(fcoe_frame_t *frm) 825 { 826 /* 827 * If you want to implement virtual name server, or FC/ETH 828 * gateway, you can do it here 829 */ 830 if (!FRM_IS_LAST_FRAME(frm)) { 831 FCOET_LOG("fcoet_process_unsol_ct_req", 832 "not supported this kind frame"); 833 return (FCOE_FAILURE); 834 } 835 836 FCOET_LOG("fcoet_process_unsol_ct_req", 837 "No support for unsolicited CT request"); 838 return (FCOE_SUCCESS); 839 } 840 841 static int 842 fcoet_process_sol_ct_rsp(fcoe_frame_t *frm) 843 { 844 uint32_t actual_size; 845 fct_status_t fc_st; 846 uint32_t iof; 847 fct_sol_ct_t *ct = NULL; 848 fcoet_exchange_t *xch = NULL; 849 uint16_t sol_oxid; 850 851 sol_oxid = FRM_OXID(frm); 852 853 if (mod_hash_remove(FRM2SS(frm)->ss_sol_oxid_hash, 854 (mod_hash_key_t)(intptr_t)sol_oxid, 855 (mod_hash_val_t *)&xch) != 0) { 856 return (FCOE_SUCCESS); 857 } 858 859 xch->xch_flags &= ~XCH_FLAG_IN_HASH_TABLE; 860 fcoet_init_tfm(frm, xch); 861 862 ASSERT(FRM_IS_LAST_FRAME(frm)); 863 actual_size = CMD2ELS(xch->xch_cmd)->els_resp_size; 864 if (actual_size > frm->frm_payload_size) { 865 actual_size = frm->frm_payload_size; 866 } 867 ct = CMD2CT(xch->xch_cmd); 868 ct->ct_resp_size = (uint16_t)actual_size; 869 870 bcopy(frm->frm_payload, 871 CMD2CT(xch->xch_cmd)->ct_resp_payload, actual_size); 872 873 fc_st = FCT_SUCCESS; 874 iof = FCT_IOF_FCA_DONE; 875 fct_send_cmd_done(xch->xch_cmd, fc_st, iof); 876 877 return (FCOE_SUCCESS); 878 } 879 880 static int 881 fcoet_send_sol_fcp_data_done(fcoe_frame_t *frm) 882 { 883 fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; 884 stmf_data_buf_t *dbuf; 885 int dbuf_index; 886 uint32_t iof; 887 888 dbuf_index = FRM2TFM(frm)->tfm_buf_idx; 889 xch->xch_left_data_size -= frm->frm_payload_size; 890 dbuf = xch->xch_dbufs[dbuf_index]; 891 ASSERT((dbuf) && (dbuf->db_flags & DB_DIRECTION_TO_RPORT)); 892 893 /* 894 * We decrease db_sglist_length only for READ-type commands. 895 * For INQUIRY, resid could be non-zero, then db_sglist_length will 896 * be useful. 897 */ 898 dbuf->db_sglist_length--; 899 if ((xch->xch_left_data_size <= 0) || (!dbuf->db_sglist_length)) { 900 iof = 0; 901 dbuf->db_xfer_status = FCT_SUCCESS; 902 dbuf->db_flags |= DB_DONT_REUSE; 903 if (dbuf->db_flags & DB_SEND_STATUS_GOOD) { 904 if (fcoet_send_status(xch->xch_cmd) != FCT_SUCCESS) { 905 return (FCOE_FAILURE); 906 } 907 } else { 908 fct_scsi_data_xfer_done(xch->xch_cmd, dbuf, iof); 909 } 910 } 911 FCOET_RELE_XCHG(xch); 912 return (FCOE_SUCCESS); 913 } 914 915 static int 916 fcoet_send_fcp_status_done(fcoe_frame_t *frm) 917 { 918 fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; 919 fct_status_t fc_st = FCT_SUCCESS; 920 uint32_t iof = FCT_IOF_FCA_DONE; 921 922 if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 923 FCOET_RELE_XCHG(xch); 924 return (FCOE_SUCCESS); 925 } 926 927 if (fcoet_clear_unsol_exchange(xch) == FCOE_SUCCESS) { 928 FCOET_RELE_XCHG(xch); 929 fct_send_response_done(xch->xch_cmd, fc_st, iof); 930 } else { 931 /* Already cleared from hash table by abort */ 932 FCOET_RELE_XCHG(xch); 933 } 934 935 return (FCOE_SUCCESS); 936 } 937 938 /* 939 * Solicited frames callback area 940 */ 941 static int 942 fcoet_send_unsol_els_rsp_done(fcoe_frame_t *frm) 943 { 944 fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; 945 fct_status_t fc_st; 946 uint32_t iof; 947 948 FCOET_EXT_LOG("fcoet_send_unsol_els_rsp_done", 949 "frm/oxid/els: %p/%x/%x", 950 frm, FRM_OXID(frm), XCH2ELS(xch)->els_req_payload[0]); 951 if (xch->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 952 FCOET_RELE_XCHG(xch); 953 return (FCOE_SUCCESS); 954 } 955 956 if (fcoet_clear_unsol_exchange(xch) == FCOE_FAILURE) { 957 FCOET_RELE_XCHG(xch); 958 return (FCOE_SUCCESS); 959 } 960 961 FCOET_RELE_XCHG(xch); 962 if (XCH2ELS(xch)->els_req_payload[0] != ELS_OP_FLOGI) { 963 fc_st = FCT_SUCCESS; 964 iof = FCT_IOF_FCA_DONE; 965 fct_send_response_done(xch->xch_cmd, fc_st, iof); 966 } else { 967 /* 968 * We need update ss_link_info and flags. 969 */ 970 mutex_enter(&xch->xch_ss->ss_watch_mutex); 971 xch->xch_ss->ss_link_info.portid = 972 xch->xch_cmd->cmd_lportid; 973 xch->xch_ss->ss_link_info.port_topology = 974 PORT_TOPOLOGY_PT_TO_PT; 975 if (frm->frm_eport->eport_link_speed == FCOE_PORT_SPEED_1G) { 976 xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_1G; 977 } else if (frm->frm_eport->eport_link_speed == 978 FCOE_PORT_SPEED_10G) { 979 xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G; 980 } 981 xch->xch_ss->ss_link_info.port_no_fct_flogi = 1; 982 xch->xch_ss->ss_link_info.port_fca_flogi_done = 1; 983 xch->xch_ss->ss_link_info.port_fct_flogi_done = 0; 984 bcopy(XCH2ELS(xch)->els_req_payload + 20, 985 xch->xch_ss->ss_link_info.port_rpwwn, 8); 986 bcopy(XCH2ELS(xch)->els_req_payload + 28, 987 xch->xch_ss->ss_link_info.port_rnwwn, 8); 988 atomic_or_32(&xch->xch_ss->ss_flags, 989 SS_FLAG_UNSOL_FLOGI_DONE); 990 atomic_or_32(&xch->xch_ss->ss_flags, 991 SS_FLAG_REPORT_TO_FCT); 992 993 xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC; 994 mutex_exit(&xch->xch_ss->ss_watch_mutex); 995 996 fct_free(xch->xch_cmd); 997 } 998 return (FCOE_SUCCESS); 999 } 1000 1001 /* ARGSUSED */ 1002 static int 1003 fcoet_send_sol_els_req_done(fcoe_frame_t *frm) 1004 { 1005 return (FCOE_SUCCESS); 1006 } 1007 1008 /* 1009 * FCT have released relevant fct_cmd_t and fcoet_exchange_t now, so it's not 1010 * needed to notify FCT anything. Just do nothing. 1011 */ 1012 /* ARGSUSED */ 1013 static int 1014 fcoet_send_unsol_bls_acc_done(fcoe_frame_t *frm) 1015 { 1016 FCOET_LOG("fcoet_send_unsol_bls_acc_done", 1017 "Unsolicited BA_ACC sent out and released "); 1018 1019 return (FCOE_SUCCESS); 1020 } 1021 1022 /* ARGSUSED */ 1023 static int 1024 fcoet_send_unsol_bls_rjt_done(fcoe_frame_t *frm) 1025 { 1026 FCOET_LOG("fcoet_send_unsol_bls_rjt_done", 1027 "Unsolicited BA_RJT sent out and released"); 1028 return (FCOE_SUCCESS); 1029 } 1030 1031 /* ARGSUSED */ 1032 static int 1033 fcoet_send_sol_bls_req_done(fcoe_frame_t *frm) 1034 { 1035 FCOET_LOG("fcoet_send_sol_bls_req_done", 1036 "Soclited ABTS was sent out and released"); 1037 return (FCOE_SUCCESS); 1038 } 1039 1040 /* ARGSUSED */ 1041 static int 1042 fcoet_send_sol_ct_req_done(fcoe_frame_t *frm) 1043 { 1044 FCOET_LOG("fcoet_send_sol_ct_req_done", 1045 "CT request was sent out and released"); 1046 return (FCOE_SUCCESS); 1047 } 1048 1049 /* 1050 * FCoET can only interpret solicited and unsolicited FLOGI, all the other 1051 * ELS/CT/FCP should be passed up to FCT. 1052 */ 1053 static int 1054 fcoet_process_unsol_flogi_req(fcoet_exchange_t *xch) 1055 { 1056 fcoe_frame_t *frm; 1057 1058 atomic_or_32(&xch->xch_ss->ss_flags, SS_FLAG_DELAY_PLOGI); 1059 1060 /* 1061 * In spec, common service parameter should indicate if it's from 1062 * N-port or F-port, but the initial intel implementation is not 1063 * spec-compliant, so we use eport_flags to workaround the problem 1064 */ 1065 if (!(xch->xch_ss->ss_eport->eport_flags & EPORT_FLAG_IS_DIRECT_P2P)) { 1066 /* 1067 * The topology is switch P2P, so there's no need to respond 1068 * to this FLOGI 1069 */ 1070 FCOET_LOG("fcoet_process_unsol_flogi_req", 1071 "skip FLOGI, since we are in switch topology"); 1072 return (FCOE_SUCCESS); 1073 } 1074 1075 /* 1076 * Send ACC according to the spec. 1077 */ 1078 frm = xch->xch_ss->ss_eport->eport_alloc_frame(xch->xch_ss->ss_eport, 1079 FLOGI_ACC_PAYLOAD_SIZE + FCFH_SIZE, 0); 1080 if (frm == NULL) { 1081 ASSERT(0); 1082 return (FCOE_FAILURE); 1083 } else { 1084 fcoet_init_tfm(frm, xch); 1085 bzero(frm->frm_payload, frm->frm_payload_size); 1086 } 1087 1088 FFM_R_CTL(0x23, frm); 1089 FRM2TFM(frm)->tfm_rctl = 0x23; 1090 FFM_TYPE(0x01, frm); 1091 FFM_F_CTL(0x980000, frm); 1092 FFM_OXID(xch->xch_oxid, frm); 1093 FFM_RXID(xch->xch_rxid, frm); 1094 FFM_S_ID(0xFFFFFE, frm); 1095 1096 /* 1097 * ACC 1098 */ 1099 frm->frm_payload[0] = 0x02; 1100 1101 /* 1102 * Common Svc Parameters 1103 */ 1104 frm->frm_payload[4] = 0x20; 1105 frm->frm_payload[5] = 0x20; 1106 frm->frm_payload[7] = 0x0A; 1107 frm->frm_payload[10] = 0x05; 1108 frm->frm_payload[11] = 0xAC; 1109 bcopy(xch->xch_ss->ss_eport->eport_portwwn, frm->frm_payload + 20, 8); 1110 bcopy(xch->xch_ss->ss_eport->eport_nodewwn, frm->frm_payload + 28, 8); 1111 1112 /* 1113 * Class3 Svc Parameters 1114 */ 1115 frm->frm_payload[68] = 0x88; 1116 1117 /* 1118 * Send FLOGI ACC out 1119 * After this, we should never use the exchange, because it could 1120 * have been released. Please pay attention to other similiar cases. 1121 */ 1122 xch->xch_ss->ss_eport->eport_tx_frame(frm); 1123 return (FCOE_SUCCESS); 1124 } 1125 1126 static int 1127 fcoet_process_sol_flogi_rsp(fcoe_frame_t *frm) 1128 { 1129 int ret = FCOE_SUCCESS; 1130 fcoet_exchange_t *xch = FRM2TFM(frm)->tfm_xch; 1131 fct_els_t *els = CMD2ELS(xch->xch_cmd); 1132 1133 if (els->els_resp_payload[0] == ELS_OP_ACC) { 1134 /* 1135 * We need always update ss_link_info and flags for solicited 1136 * FLOGI, because someone has assigned address for you. The 1137 * initial intel implementation will always assign address for 1138 * you even you are in back-to-back mode (direct P2P). 1139 */ 1140 mutex_enter(&xch->xch_ss->ss_watch_mutex); 1141 if (xch->xch_flags & XCH_FLAG_NONFCP_REQ_SENT) { 1142 xch->xch_cmd->cmd_lportid = FRM_D_ID(frm); 1143 xch->xch_ss->ss_link_info.portid = 1144 xch->xch_cmd->cmd_lportid; 1145 /* 1146 * Check the bit 28 in 3rd word of the payload 1147 * in common service parameters to know the 1148 * remote port is F_PORT or N_PORT 1149 */ 1150 if (els->els_resp_payload[8] & 0x10) { 1151 uint8_t src_addr[ETHERADDRL]; 1152 frm->frm_eport->eport_flags &= 1153 ~EPORT_FLAG_IS_DIRECT_P2P; 1154 FCOE_SET_DEFAULT_OUI(src_addr); 1155 bcopy(frm->frm_hdr->hdr_d_id, src_addr + 3, 3); 1156 bcopy((char *)frm->frm_hdr-22, 1157 frm->frm_eport->eport_efh_dst, 1158 ETHERADDRL); 1159 frm->frm_eport->eport_set_mac_address( 1160 frm->frm_eport, src_addr, B_TRUE); 1161 xch->xch_ss->ss_link_info.port_topology = 1162 PORT_TOPOLOGY_FABRIC_PT_TO_PT; 1163 } else { 1164 xch->xch_ss->ss_link_info.port_topology = 1165 PORT_TOPOLOGY_PT_TO_PT; 1166 } 1167 1168 xch->xch_ss->ss_link_info.port_speed = PORT_SPEED_10G; 1169 xch->xch_ss->ss_link_info.port_no_fct_flogi = 1; 1170 xch->xch_ss->ss_link_info.port_fca_flogi_done = 1; 1171 xch->xch_ss->ss_link_info.port_fct_flogi_done = 0; 1172 xch->xch_ss->ss_sol_flogi_state = SFS_FLOGI_ACC; 1173 cv_signal(&xch->xch_ss->ss_watch_cv); 1174 FCOET_LOG("fcoet_process_sol_flogi_rsp", 1175 "FLOGI is accecpted"); 1176 } else { 1177 FCOET_LOG("fcoet_process_sol_flogi_rsp", 1178 "FLOGI xch_flags/%x", xch->xch_flags); 1179 ret = FCOE_FAILURE; 1180 } 1181 mutex_exit(&xch->xch_ss->ss_watch_mutex); 1182 } else { 1183 FCOET_LOG("fcoet_process_sol_flogi_rsp", "FLOGI is rejected"); 1184 ret = FCOE_FAILURE; 1185 } 1186 return (ret); 1187 } 1188