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 (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. 24 */ 25 26 /* 27 * This file defines interfaces between fcoe and fct driver. 28 */ 29 30 /* 31 * Driver kernel header files 32 */ 33 #include <sys/conf.h> 34 #include <sys/ddi.h> 35 #include <sys/stat.h> 36 #include <sys/pci.h> 37 #include <sys/sunddi.h> 38 #include <sys/modctl.h> 39 #include <sys/file.h> 40 #include <sys/cred.h> 41 #include <sys/byteorder.h> 42 #include <sys/atomic.h> 43 #include <sys/modhash.h> 44 #include <sys/scsi/scsi.h> 45 #include <sys/ethernet.h> 46 47 /* 48 * COMSTAR header files 49 */ 50 #include <sys/stmf_defines.h> 51 #include <sys/fct_defines.h> 52 #include <sys/stmf.h> 53 #include <sys/portif.h> 54 #include <sys/fct.h> 55 56 /* 57 * FCoE hader files 58 */ 59 #include <sys/fcoe/fcoe_common.h> 60 61 /* 62 * Driver's own header files 63 */ 64 #include "fcoet.h" 65 #include "fcoet_fc.h" 66 #include "fcoet_eth.h" 67 68 /* 69 * function forward declaration 70 */ 71 static fct_status_t fcoet_fill_plogi_req(fct_local_port_t *port, 72 fct_remote_port_t *rp, fct_cmd_t *login); 73 static fct_status_t fcoet_fill_plogi_resp(fct_local_port_t *port, 74 fct_remote_port_t *rp, fct_cmd_t *login); 75 static fct_status_t fcoet_send_sol_els(fct_cmd_t *cmd); 76 static fct_status_t fcoet_send_sol_ct(fct_cmd_t *cmd); 77 static fct_status_t fcoet_send_good_status(fct_cmd_t *cmd); 78 static fct_status_t fcoet_send_els_response(fct_cmd_t *cmd); 79 static fct_status_t fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags); 80 static fct_status_t fcoet_logo_fabric(fcoet_soft_state_t *ss); 81 82 /* 83 * Return the lower link information 84 */ 85 fct_status_t 86 fcoet_get_link_info(fct_local_port_t *port, fct_link_info_t *li) 87 { 88 bcopy(&PORT2SS(port)->ss_link_info, li, sizeof (fct_link_info_t)); 89 return (FCT_SUCCESS); 90 } 91 92 /* 93 * FCT will call this, when it wants to send PLOGI or has received PLOGI. 94 */ 95 fct_status_t 96 fcoet_register_remote_port(fct_local_port_t *port, fct_remote_port_t *rp, 97 fct_cmd_t *login) 98 { 99 uint16_t handle; 100 fct_status_t ret; 101 102 switch (rp->rp_id) { 103 case 0xFFFFFC: 104 handle = 0x7FC; 105 break; 106 107 case 0xFFFFFD: 108 handle = 0x7FD; 109 break; 110 111 case 0xFFFFFE: 112 handle = 0x7FE; 113 break; 114 115 case 0xFFFFFF: 116 handle = 0x7FF; 117 break; 118 119 default: 120 /* 121 * For not well-known address, we let FCT to select one. 122 */ 123 handle = FCT_HANDLE_NONE; 124 break; 125 } 126 127 rp->rp_handle = handle; 128 if (login->cmd_type == FCT_CMD_SOL_ELS) { 129 ret = fcoet_fill_plogi_req(port, rp, login); 130 } else { 131 ret = fcoet_fill_plogi_resp(port, rp, login); 132 } 133 134 return (ret); 135 } 136 137 /* 138 * FCT will call this to say "FCoET can release resources with this RP now." 139 */ 140 /* ARGSUSED */ 141 fct_status_t 142 fcoet_deregister_remote_port(fct_local_port_t *port, fct_remote_port_t *rp) 143 { 144 fcoet_soft_state_t *this_ss = PORT2SS(port); 145 146 this_ss->ss_rport_dereg_state = 0; 147 this_ss->ss_rportid_in_dereg = 0; 148 return (FCT_SUCCESS); 149 } 150 151 fct_status_t 152 fcoet_send_cmd(fct_cmd_t *cmd) 153 { 154 if (cmd->cmd_type == FCT_CMD_SOL_ELS) { 155 return (fcoet_send_sol_els(cmd)); 156 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) { 157 return (fcoet_send_sol_ct(cmd)); 158 } 159 160 return (FCT_FAILURE); 161 } 162 163 /* 164 * SCSI response phase 165 * ELS_ACC/ELS_RJT 166 */ 167 fct_status_t 168 fcoet_send_cmd_response(fct_cmd_t *cmd, uint32_t ioflags) 169 { 170 char info[FCT_INFO_LEN]; 171 172 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) { 173 if (ioflags & FCT_IOF_FORCE_FCA_DONE) { 174 goto send_cmd_rsp_error; 175 } else { 176 return (fcoet_send_status(cmd)); 177 } 178 } 179 180 if (cmd->cmd_type == FCT_CMD_RCVD_ELS) { 181 if (ioflags & FCT_IOF_FORCE_FCA_DONE) { 182 goto send_cmd_rsp_error; 183 } else { 184 return (fcoet_send_els_response(cmd)); 185 } 186 } 187 188 if (ioflags & FCT_IOF_FORCE_FCA_DONE) { 189 cmd->cmd_handle = 0; 190 } 191 192 if (cmd->cmd_type == FCT_CMD_RCVD_ABTS) { 193 return (fcoet_send_abts_response(cmd, 0)); 194 } else { 195 ASSERT(0); 196 return (FCT_FAILURE); 197 } 198 199 send_cmd_rsp_error: 200 (void) snprintf(info, sizeof (info), "fcoet_send_cmd_response: can not " 201 "handle FCT_IOF_FORCE_FCA_DONE for cmd %p, ioflags-%x", (void *)cmd, 202 ioflags); 203 (void) fct_port_shutdown(CMD2SS(cmd)->ss_port, 204 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info); 205 return (FCT_FAILURE); 206 } 207 208 /* 209 * It's for read/write (xfer_rdy) 210 */ 211 /* ARGSUSED */ 212 fct_status_t 213 fcoet_xfer_scsi_data(fct_cmd_t *cmd, stmf_data_buf_t *dbuf, uint32_t ioflags) 214 { 215 fcoe_frame_t *frm; 216 int idx; 217 int frm_num; 218 int data_size; 219 int left_size; 220 int offset; 221 fcoet_exchange_t *xch = CMD2XCH(cmd); 222 223 ASSERT(!xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN]); 224 xch->xch_dbufs[dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN] = dbuf; 225 226 left_size = (int)dbuf->db_data_size; 227 if (dbuf->db_relative_offset == 0) 228 xch->xch_left_data_size = 229 XCH2TASK(xch)->task_expected_xfer_length; 230 231 if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) { 232 /* 233 * If it's write type command, we need send xfer_rdy now 234 * We may need to consider bidirectional command later 235 */ 236 dbuf->db_sglist_length = 0; 237 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame( 238 CMD2SS(cmd)->ss_eport, sizeof (fcoe_fcp_xfer_rdy_t) + 239 FCFH_SIZE, NULL); 240 if (frm == NULL) { 241 ASSERT(0); 242 return (FCT_FAILURE); 243 } else { 244 fcoet_init_tfm(frm, CMD2XCH(cmd)); 245 bzero(frm->frm_payload, frm->frm_payload_size); 246 } 247 248 FFM_R_CTL(0x05, frm); 249 FRM2TFM(frm)->tfm_rctl = 0x05; 250 FFM_TYPE(0x08, frm); 251 FFM_F_CTL(0x890000, frm); 252 FFM_OXID(cmd->cmd_oxid, frm); 253 FFM_RXID(cmd->cmd_rxid, frm); 254 FFM_S_ID(cmd->cmd_lportid, frm); 255 FFM_D_ID(cmd->cmd_rportid, frm); 256 FCOE_V2B_4(dbuf->db_relative_offset, frm->frm_payload); 257 FCOE_V2B_4(dbuf->db_data_size, frm->frm_payload + 4); 258 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 259 260 return (FCT_SUCCESS); 261 } 262 263 /* 264 * It's time to transfer READ data to remote side 265 */ 266 frm_num = (dbuf->db_data_size + CMD2SS(cmd)->ss_fcp_data_payload_size - 267 1) / CMD2SS(cmd)->ss_fcp_data_payload_size; 268 offset = dbuf->db_relative_offset; 269 for (idx = 0; idx < frm_num; idx++) { 270 if (idx == (frm_num -1)) { 271 data_size = P2ROUNDUP(left_size, 4); 272 } else { 273 data_size = CMD2SS(cmd)->ss_fcp_data_payload_size; 274 } 275 276 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame( 277 CMD2SS(cmd)->ss_eport, data_size + FCFH_SIZE, 278 FCOET_GET_NETB(dbuf, idx)); 279 if (frm == NULL) { 280 ASSERT(0); 281 return (FCT_FAILURE); 282 } else { 283 fcoet_init_tfm(frm, CMD2XCH(cmd)); 284 /* 285 * lock the xchg to avoid being released (by abort) 286 * after sent out and before release 287 */ 288 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 289 } 290 291 FFM_R_CTL(0x01, frm); 292 FRM2TFM(frm)->tfm_rctl = 0x01; 293 FRM2TFM(frm)->tfm_buf_idx = 294 dbuf->db_relative_offset/FCOET_MAX_DBUF_LEN; 295 FFM_TYPE(0x08, frm); 296 if (idx != frm_num - 1) { 297 FFM_F_CTL(0x800008, frm); 298 } else { 299 FFM_F_CTL(0x880008 | (data_size - left_size), frm); 300 } 301 302 FFM_OXID(cmd->cmd_oxid, frm); 303 FFM_RXID(cmd->cmd_rxid, frm); 304 FFM_S_ID(cmd->cmd_lportid, frm); 305 FFM_D_ID(cmd->cmd_rportid, frm); 306 FFM_SEQ_CNT(xch->xch_sequence_no, frm); 307 atomic_add_8(&xch->xch_sequence_no, 1); 308 FFM_PARAM(offset, frm); 309 offset += data_size; 310 left_size -= data_size; 311 312 /* 313 * Disassociate netbs which will be freed by NIC driver 314 */ 315 FCOET_SET_NETB(dbuf, idx, NULL); 316 317 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 318 } 319 320 return (FCT_SUCCESS); 321 } 322 323 fct_status_t 324 fcoet_abort_cmd(struct fct_local_port *port, fct_cmd_t *cmd, uint32_t flags) 325 { 326 fcoet_soft_state_t *this_ss = PORT2SS(port); 327 fct_status_t fct_ret = FCT_SUCCESS; 328 329 FCOET_LOG("fcoet_abort_cmd", "cmd=%p, xch=%p, cmd_specific=%p", 330 cmd, cmd->cmd_fca_private, cmd->cmd_specific); 331 switch (cmd->cmd_type) { 332 case FCT_CMD_RCVD_ABTS: 333 /* 334 * Sometimes unsolicited ABTS request will be received twice 335 * and the first ABTS is not done yet, so the second ABTS 336 * will be passed down here, in this case we will do 337 * nothing and abts response is not needed to be sent 338 * fct_ret = fcoet_send_abts_response(cmd, 1); 339 */ 340 break; 341 case FCT_CMD_FCP_XCHG: 342 case FCT_CMD_RCVD_ELS: 343 if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 344 break; 345 } 346 347 CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT; 348 (void) fcoet_clear_unsol_exchange(CMD2XCH(cmd)); 349 if (!(flags & FCT_IOF_FORCE_FCA_DONE)) { 350 mutex_enter(&this_ss->ss_watch_mutex); 351 CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt(); 352 list_insert_tail(&this_ss->ss_abort_xchg_list, 353 CMD2XCH(cmd)); 354 cv_signal(&this_ss->ss_watch_cv); 355 mutex_exit(&this_ss->ss_watch_mutex); 356 } 357 break; 358 359 case FCT_CMD_SOL_ELS: 360 case FCT_CMD_SOL_CT: 361 if (CMD2XCH(cmd)->xch_flags & XCH_FLAG_FCT_CALLED_ABORT) { 362 break; 363 } 364 365 CMD2XCH(cmd)->xch_flags |= XCH_FLAG_FCT_CALLED_ABORT; 366 fcoet_clear_sol_exchange(CMD2XCH(cmd)); 367 368 if (!(flags & FCT_IOF_FORCE_FCA_DONE)) { 369 mutex_enter(&this_ss->ss_watch_mutex); 370 CMD2XCH(cmd)->xch_start_time = ddi_get_lbolt(); 371 cv_signal(&this_ss->ss_watch_cv); 372 list_insert_tail(&this_ss->ss_abort_xchg_list, 373 CMD2XCH(cmd)); 374 mutex_exit(&this_ss->ss_watch_mutex); 375 } 376 377 break; 378 379 default: 380 ASSERT(0); 381 break; 382 } 383 384 if ((flags & FCT_IOF_FORCE_FCA_DONE) && 385 (cmd->cmd_type != FCT_CMD_FCP_XCHG)) { 386 cmd->cmd_handle = 0; 387 } 388 389 return (fct_ret); 390 } 391 392 /* ARGSUSED */ 393 fct_status_t 394 fcoet_do_flogi(fct_local_port_t *port, fct_flogi_xchg_t *fx) 395 { 396 cmn_err(CE_WARN, "FLOGI requested (not supported)"); 397 return (FCT_FAILURE); 398 } 399 400 void 401 fcoet_send_sol_flogi(fcoet_soft_state_t *ss) 402 { 403 fcoet_exchange_t *xch; 404 fct_cmd_t *cmd; 405 fct_els_t *els; 406 fcoe_frame_t *frm; 407 408 /* 409 * FCT will initialize fct_cmd_t 410 * Initialize fcoet_exchange 411 */ 412 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_SOL_ELS, 413 sizeof (fcoet_exchange_t), 0); 414 xch = CMD2XCH(cmd); 415 els = CMD2ELS(cmd); 416 417 xch->xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); 418 if (xch->xch_oxid == 0xFFFF) { 419 xch->xch_oxid = 420 atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); 421 } 422 xch->xch_rxid = 0xFFFF; 423 xch->xch_flags = 0; 424 xch->xch_ss = ss; 425 xch->xch_cmd = cmd; 426 xch->xch_current_seq = NULL; 427 xch->xch_start_time = ddi_get_lbolt(); 428 429 /* 430 * Keep it to compare with response 431 */ 432 ss->ss_sol_flogi = xch; 433 els->els_resp_alloc_size = 116; 434 els->els_resp_size = 116; 435 els->els_resp_payload = (uint8_t *) 436 kmem_zalloc(els->els_resp_size, KM_SLEEP); 437 (void) mod_hash_insert(xch->xch_ss->ss_sol_oxid_hash, 438 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); 439 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; 440 atomic_or_32(&ss->ss_flags, SS_FLAG_DELAY_PLOGI); 441 442 /* 443 * FCoE will initialize fcoe_frame_t 444 */ 445 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, 446 FLOGI_REQ_PAYLOAD_SIZE + FCFH_SIZE, NULL); 447 if (frm == NULL) { 448 ASSERT(0); 449 return; 450 } else { 451 fcoet_init_tfm(frm, xch); 452 bzero(frm->frm_payload, frm->frm_payload_size); 453 } 454 455 FFM_R_CTL(0x22, frm); 456 FRM2TFM(frm)->tfm_rctl = 0x22; 457 FFM_TYPE(0x01, frm); 458 FFM_F_CTL(0x290000, frm); 459 FFM_OXID(xch->xch_oxid, frm); 460 FFM_RXID(xch->xch_rxid, frm); 461 FFM_D_ID(0xfffffe, frm); 462 frm->frm_payload[0] = ELS_OP_FLOGI; 463 /* Common Service Parameters */ 464 frm->frm_payload[4] = 0x20; 465 frm->frm_payload[5] = 0x08; 466 frm->frm_payload[6] = 0x0; 467 frm->frm_payload[7] = 0x03; 468 /* N_PORT */ 469 frm->frm_payload[8] = 0x88; 470 frm->frm_payload[9] = 0x00; 471 frm->frm_payload[10] = 0x08; 472 frm->frm_payload[11] = 0x0; 473 frm->frm_payload[12] = 0x0; 474 frm->frm_payload[13] = 0xff; 475 frm->frm_payload[14] = 0x0; 476 frm->frm_payload[15] = 0x03; 477 frm->frm_payload[16] = 0x0; 478 frm->frm_payload[17] = 0x0; 479 frm->frm_payload[18] = 0x07; 480 frm->frm_payload[19] = 0xd0; 481 /* PWWN and NWWN */ 482 frm->frm_payload[20] = 0x0; 483 bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload+20, 8); 484 bcopy(ss->ss_eport->eport_nodewwn, frm->frm_payload+28, 8); 485 /* Class 3 Service Parameters */ 486 frm->frm_payload[68] = 0x88; 487 frm->frm_payload[74] = 0x08; 488 frm->frm_payload[77] = 0xff; 489 490 ss->ss_eport->eport_tx_frame(frm); 491 xch->xch_flags |= XCH_FLAG_NONFCP_REQ_SENT; 492 } 493 494 /* 495 * This is for solicited FLOGI only 496 */ 497 void 498 fcoet_send_sol_abts(fcoet_exchange_t *xch) 499 { 500 fcoe_frame_t *frm; 501 fcoet_soft_state_t *ss = xch->xch_ss; 502 503 /* 504 * FCoE will initialize fcoe_frame_t 505 * ABTS has no payload 506 */ 507 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, 508 FCFH_SIZE, NULL); 509 if (frm == NULL) { 510 ASSERT(0); 511 return; 512 } else { 513 fcoet_init_tfm(frm, xch); 514 frm->frm_payload = NULL; 515 } 516 517 FFM_R_CTL(0x81, frm); 518 FRM2TFM(frm)->tfm_rctl = 0x81; 519 FFM_F_CTL(0x090000, frm); 520 FFM_OXID(xch->xch_oxid, frm); 521 FFM_RXID(xch->xch_rxid, frm); 522 FFM_D_ID(0xfffffe, frm); 523 FFM_SEQ_CNT(xch->xch_sequence_no, frm); 524 xch->xch_start_time = ddi_get_lbolt(); 525 526 ss->ss_eport->eport_tx_frame(frm); 527 } 528 529 void 530 fcoet_ctl(struct fct_local_port *port, int cmd, void *arg) 531 { 532 stmf_change_status_t st; 533 stmf_state_change_info_t *ssci = (stmf_state_change_info_t *)arg; 534 fcoet_soft_state_t *this_ss = PORT2SS(port); 535 536 st.st_completion_status = FCT_SUCCESS; 537 st.st_additional_info = NULL; 538 539 switch (cmd) { 540 case FCT_CMD_PORT_ONLINE: 541 if (this_ss->ss_state == FCT_STATE_ONLINE) 542 st.st_completion_status = STMF_ALREADY; 543 else if (this_ss->ss_state != FCT_STATE_OFFLINE) 544 st.st_completion_status = FCT_FAILURE; 545 if (st.st_completion_status == FCT_SUCCESS) { 546 this_ss->ss_state = FCT_STATE_ONLINING; 547 this_ss->ss_state_not_acked = 1; 548 st.st_completion_status = fcoet_enable_port(this_ss); 549 if (st.st_completion_status != STMF_SUCCESS) { 550 this_ss->ss_state = FCT_STATE_OFFLINE; 551 this_ss->ss_state_not_acked = 0; 552 } else { 553 this_ss->ss_state = FCT_STATE_ONLINE; 554 } 555 } 556 fct_ctl(port->port_lport, FCT_CMD_PORT_ONLINE_COMPLETE, &st); 557 this_ss->ss_change_state_flags = 0; 558 break; 559 560 case FCT_CMD_PORT_OFFLINE: 561 if (this_ss->ss_state == FCT_STATE_OFFLINE) { 562 st.st_completion_status = STMF_ALREADY; 563 } else if (this_ss->ss_state != FCT_STATE_ONLINE) { 564 st.st_completion_status = FCT_FAILURE; 565 } 566 if (st.st_completion_status == FCT_SUCCESS) { 567 this_ss->ss_state = FCT_STATE_OFFLINING; 568 this_ss->ss_state_not_acked = 1; 569 this_ss->ss_change_state_flags = ssci->st_rflags; 570 st.st_completion_status = fcoet_disable_port(this_ss); 571 if (st.st_completion_status != STMF_SUCCESS) { 572 this_ss->ss_state = FCT_STATE_ONLINE; 573 this_ss->ss_state_not_acked = 0; 574 } else { 575 this_ss->ss_state = FCT_STATE_OFFLINE; 576 } 577 } 578 /* 579 * Notify the watchdog to do clear work 580 */ 581 mutex_enter(&this_ss->ss_watch_mutex); 582 cv_signal(&this_ss->ss_watch_cv); 583 mutex_exit(&this_ss->ss_watch_mutex); 584 fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st); 585 break; 586 587 case FCT_ACK_PORT_ONLINE_COMPLETE: 588 this_ss->ss_state_not_acked = 0; 589 break; 590 591 case FCT_ACK_PORT_OFFLINE_COMPLETE: 592 this_ss->ss_state_not_acked = 0; 593 if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) { 594 if (fct_port_initialize(port, 595 this_ss->ss_change_state_flags, 596 "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE " 597 "with RLFLAG_RESET") != FCT_SUCCESS) { 598 cmn_err(CE_WARN, "fcoet_ctl: " 599 "fct_port_initialize %s failed", 600 this_ss->ss_alias); 601 FCOET_LOG("fcoet_ctl: fct_port_initialize " 602 "%s failed", this_ss->ss_alias); 603 } 604 } 605 break; 606 default: 607 FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd); 608 break; 609 } 610 } 611 612 /* 613 * Filling the hba attributes 614 */ 615 /* ARGSUSED */ 616 void 617 fcoet_populate_hba_fru_details(struct fct_local_port *port, 618 struct fct_port_attrs *port_attrs) 619 { 620 (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN, 621 "Sun Microsystems, Inc."); 622 (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN, 623 "%s", FCOET_NAME); 624 (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN, 625 "%s", FCOET_VERSION); 626 (void) strcpy(port_attrs->serial_number, "N/A"); 627 (void) strcpy(port_attrs->hardware_version, "N/A"); 628 (void) strcpy(port_attrs->model, "FCoE Virtual FC HBA"); 629 (void) strcpy(port_attrs->model_description, "N/A"); 630 (void) strcpy(port_attrs->firmware_version, "N/A"); 631 (void) strcpy(port_attrs->option_rom_version, "N/A"); 632 633 port_attrs->vendor_specific_id = 0xFC0E; 634 port_attrs->max_frame_size = 2136; 635 port_attrs->supported_cos = 0x10000000; 636 /* Specified a fix speed here, need to change it in the future */ 637 port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G; 638 } 639 640 641 static fct_status_t 642 fcoet_send_sol_els(fct_cmd_t *cmd) 643 { 644 fcoe_frame_t *frm; 645 fcoet_exchange_t *xch = NULL; 646 647 xch = CMD2XCH(cmd); 648 xch->xch_flags = 0; 649 xch->xch_ss = CMD2SS(cmd); 650 xch->xch_cmd = cmd; 651 xch->xch_current_seq = NULL; 652 xch->xch_left_data_size = 0; 653 xch->xch_sequence_no = 0; 654 xch->xch_start_time = ddi_get_lbolt(); 655 xch->xch_rxid = 0xFFFF; 656 xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 657 if (xch->xch_oxid == 0xFFFF) { 658 xch->xch_oxid = 659 atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 660 } 661 662 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 663 CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL); 664 if (frm == NULL) { 665 ASSERT(0); 666 return (FCT_FAILURE); 667 } else { 668 fcoet_init_tfm(frm, CMD2XCH(cmd)); 669 bzero(frm->frm_payload, frm->frm_payload_size); 670 } 671 672 (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash, 673 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); 674 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; 675 bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload, 676 frm->frm_payload_size); 677 FFM_R_CTL(0x22, frm); 678 FRM2TFM(frm)->tfm_rctl = 0x22; 679 FFM_TYPE(0x01, frm); 680 FFM_F_CTL(0x290000, frm); 681 FFM_OXID(xch->xch_oxid, frm); 682 FFM_RXID(xch->xch_rxid, frm); 683 FFM_S_ID(cmd->cmd_lportid, frm); 684 FFM_D_ID(cmd->cmd_rportid, frm); 685 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 686 687 return (FCT_SUCCESS); 688 } 689 690 static fct_status_t 691 fcoet_send_sol_ct(fct_cmd_t *cmd) 692 { 693 fcoe_frame_t *frm; 694 fcoet_exchange_t *xch; 695 696 xch = CMD2XCH(cmd); 697 xch->xch_flags = 0; 698 xch->xch_ss = CMD2SS(cmd); 699 xch->xch_cmd = cmd; 700 xch->xch_current_seq = NULL; 701 xch->xch_left_data_size = 0; 702 xch->xch_sequence_no = 0; 703 xch->xch_start_time = ddi_get_lbolt(); 704 xch->xch_rxid = 0xFFFF; 705 xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 706 if (xch->xch_oxid == 0xFFFF) { 707 xch->xch_oxid = 708 atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 709 } 710 711 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 712 CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL); 713 if (frm == NULL) { 714 ASSERT(0); 715 return (FCT_FAILURE); 716 } else { 717 fcoet_init_tfm(frm, CMD2XCH(cmd)); 718 bzero(frm->frm_payload, frm->frm_payload_size); 719 } 720 721 (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash, 722 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); 723 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; 724 bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload, 725 frm->frm_payload_size); 726 FFM_R_CTL(0x2, frm); 727 FRM2TFM(frm)->tfm_rctl = 0x2; 728 FFM_TYPE(0x20, frm); 729 FFM_F_CTL(0x290000, frm); 730 FFM_OXID(xch->xch_oxid, frm); 731 FFM_RXID(xch->xch_rxid, frm); 732 FFM_S_ID(cmd->cmd_lportid, frm); 733 FFM_D_ID(cmd->cmd_rportid, frm); 734 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 735 736 return (FCT_SUCCESS); 737 } 738 739 fct_status_t 740 fcoet_send_status(fct_cmd_t *cmd) 741 { 742 fcoe_frame_t *frm; 743 scsi_task_t *task = CMD2TASK(cmd); 744 fcoe_fcp_rsp_t *ffr; 745 int raw_frame_size; 746 747 /* 748 * Fast channel for good status phase 749 */ 750 if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) { 751 return (fcoet_send_good_status(cmd)); 752 } 753 754 raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t); 755 if (task->task_scsi_status == STATUS_CHECK) { 756 raw_frame_size += task->task_sense_length; 757 } 758 raw_frame_size = P2ROUNDUP(raw_frame_size, 4); 759 760 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 761 raw_frame_size, NULL); 762 if (frm == NULL) { 763 ASSERT(0); 764 return (FCT_FAILURE); 765 } else { 766 fcoet_init_tfm(frm, CMD2XCH(cmd)); 767 bzero(frm->frm_payload, frm->frm_payload_size); 768 /* 769 * lock the xchg to avoid being released (by abort) 770 * after sent out and before release 771 */ 772 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 773 } 774 775 /* 776 * If there's sense data, copy it first 777 */ 778 if ((task->task_scsi_status == STATUS_CHECK) && 779 task->task_sense_length) { 780 bcopy(task->task_sense_data, frm->frm_payload + 781 sizeof (fcoe_fcp_rsp_t), task->task_sense_length); 782 } 783 784 /* 785 * Fill fcp_rsp 786 */ 787 ffr = (fcoe_fcp_rsp_t *)frm->frm_payload; 788 FCOE_V2B_4(0, ffr->ffr_retry_delay_timer); 789 FCOE_V2B_1(0, ffr->ffr_flags); 790 if (task->task_scsi_status == STATUS_CHECK || task->task_resid) { 791 if (task->task_scsi_status == STATUS_CHECK) { 792 ffr->ffr_flags[0] |= BIT_1; 793 } 794 if (task->task_status_ctrl == TASK_SCTRL_OVER) { 795 ffr->ffr_flags[0] |= BIT_2; 796 } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) { 797 ffr->ffr_flags[0] |= BIT_3; 798 } 799 } 800 FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status); 801 FCOE_V2B_4(task->task_resid, ffr->ffr_resid); 802 FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len); 803 FCOE_V2B_4(0, ffr->ffr_rsp_len); 804 805 /* 806 * Fill fc frame header 807 */ 808 FFM_R_CTL(0x07, frm); 809 FRM2TFM(frm)->tfm_rctl = 0x07; 810 FFM_TYPE(0x08, frm); 811 FFM_F_CTL(0x990000, frm); 812 FFM_OXID(cmd->cmd_oxid, frm); 813 FFM_RXID(cmd->cmd_rxid, frm); 814 FFM_S_ID(cmd->cmd_lportid, frm); 815 FFM_D_ID(cmd->cmd_rportid, frm); 816 FFM_SEQ_ID(0x01, frm); 817 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 818 819 return (FCT_SUCCESS); 820 } 821 822 static fct_status_t 823 fcoet_send_els_response(fct_cmd_t *cmd) 824 { 825 fcoe_frame_t *frm; 826 827 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 828 CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL); 829 if (frm == NULL) { 830 ASSERT(0); 831 return (FCT_FAILURE); 832 } else { 833 fcoet_init_tfm(frm, CMD2XCH(cmd)); 834 bzero(frm->frm_payload, frm->frm_payload_size); 835 /* 836 * lock the xchg to avoid being released (by abort) 837 * after sent out and before release 838 */ 839 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 840 } 841 842 bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload, 843 frm->frm_payload_size); 844 FFM_R_CTL(0x23, frm); 845 FRM2TFM(frm)->tfm_rctl = 0x23; 846 FFM_TYPE(0x01, frm); 847 FFM_F_CTL(0x980000, frm); 848 FFM_OXID(cmd->cmd_oxid, frm); 849 FFM_RXID(cmd->cmd_rxid, frm); 850 FFM_S_ID(cmd->cmd_lportid, frm); 851 FFM_D_ID(cmd->cmd_rportid, frm); 852 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 853 854 return (FCT_SUCCESS); 855 } 856 857 /* ARGSUSED */ 858 static fct_status_t 859 fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags) 860 { 861 fcoe_frame_t *frm; 862 fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific; 863 864 /* 865 * The relevant fcoet_exchange has been released 866 */ 867 cmd->cmd_fca_private = NULL; 868 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 869 12 + FCFH_SIZE, NULL); 870 if (frm == NULL) { 871 ASSERT(0); 872 return (FCT_FAILURE); 873 } else { 874 fcoet_init_tfm(frm, NULL); 875 } 876 877 bcopy(abts->abts_resp_payload, frm->frm_payload, 878 frm->frm_payload_size); 879 FFM_R_CTL(abts->abts_resp_rctl, frm); 880 FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl; 881 FFM_TYPE(0x00, frm); 882 FFM_F_CTL(0x980000, frm); 883 FFM_OXID(cmd->cmd_oxid, frm); 884 FFM_RXID(cmd->cmd_rxid, frm); 885 FFM_S_ID(cmd->cmd_lportid, frm); 886 FFM_D_ID(cmd->cmd_rportid, frm); 887 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 888 889 return (FCT_SUCCESS); 890 } 891 892 /* 893 * enable/disable port is simple compared to physical FC HBAs 894 */ 895 fct_status_t 896 fcoet_enable_port(fcoet_soft_state_t *ss) 897 { 898 FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss); 899 /* Call fcoe function to online the port */ 900 if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) == 901 FCOE_FAILURE) { 902 return (FCT_FAILURE); 903 } 904 905 if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) { 906 atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED); 907 } 908 909 return (FCT_SUCCESS); 910 } 911 912 fct_status_t 913 fcoet_disable_port(fcoet_soft_state_t *ss) 914 { 915 fct_status_t status; 916 917 FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss); 918 /* Call fcoe function to offline the port */ 919 status = fcoet_logo_fabric(ss); 920 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0); 921 atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED); 922 return (status); 923 } 924 925 static fct_status_t 926 fcoet_logo_fabric(fcoet_soft_state_t *ss) 927 { 928 fcoe_frame_t *frm; 929 uint32_t req_payload_size = 16; 930 uint16_t xch_oxid, xch_rxid = 0xFFFF; 931 932 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, 933 req_payload_size + FCFH_SIZE, NULL); 934 if (frm == NULL) { 935 ASSERT(0); 936 return (FCT_FAILURE); 937 } else { 938 fcoet_init_tfm(frm, NULL); 939 bzero(frm->frm_payload, frm->frm_payload_size); 940 } 941 xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); 942 if (xch_oxid == 0xFFFF) { 943 xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); 944 } 945 FFM_R_CTL(0x22, frm); 946 FRM2TFM(frm)->tfm_rctl = 0x22; 947 FFM_TYPE(0x01, frm); 948 FFM_F_CTL(0x290000, frm); 949 FFM_OXID(xch_oxid, frm); 950 FFM_RXID(xch_rxid, frm); 951 FFM_S_ID(ss->ss_link_info.portid, frm); 952 FFM_D_ID(0xfffffe, frm); 953 954 FCOE_V2B_1(0x5, frm->frm_payload); 955 FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5); 956 bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8); 957 ss->ss_eport->eport_tx_frame(frm); 958 959 return (FCT_SUCCESS); 960 961 } 962 963 /* 964 * Called by: fcoet_register_remote_port 965 */ 966 /* ARGSUSED */ 967 static fct_status_t 968 fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp, 969 fct_cmd_t *login) 970 { 971 uint8_t *p; 972 973 p = ((fct_els_t *)login->cmd_specific)->els_req_payload; 974 p[0] = ELS_OP_PLOGI; 975 p[4] = 0x20; 976 p[5] = 0x20; 977 p[7] = 3; 978 p[8] = 0x88; 979 p[10] = 8; 980 p[13] = 0xff; p[15] = 0x1f; 981 p[18] = 7; p[19] = 0xd0; 982 983 bcopy(port->port_pwwn, p + 20, 8); 984 bcopy(port->port_nwwn, p + 28, 8); 985 986 p[68] = 0x80; 987 p[74] = 8; 988 p[77] = 0xff; 989 p[81] = 1; 990 991 return (FCT_SUCCESS); 992 } 993 994 /* 995 * Called by: fcoet_register_remote_port 996 */ 997 /* ARGSUSED */ 998 static fct_status_t 999 fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp, 1000 fct_cmd_t *login) 1001 { 1002 uint8_t *p; 1003 /* 1004 * ACC 1005 */ 1006 p = ((fct_els_t *)login->cmd_specific)->els_req_payload; 1007 p[0] = ELS_OP_ACC; 1008 p[4] = 0x20; 1009 p[5] = 0x20; 1010 p[7] = 0x0A; 1011 p[10] = 0x05; 1012 p[11] = 0xAC; 1013 1014 bcopy(port->port_pwwn, p + 20, 8); 1015 bcopy(port->port_nwwn, p + 28, 8); 1016 1017 p[68] = 0x88; 1018 return (FCT_SUCCESS); 1019 } 1020 1021 static fct_status_t 1022 fcoet_send_good_status(fct_cmd_t *cmd) 1023 { 1024 fcoe_frame_t *frm; 1025 int raw_frame_size; 1026 1027 raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t); 1028 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 1029 raw_frame_size, NULL); 1030 if (frm == NULL) { 1031 ASSERT(0); 1032 return (FCT_FAILURE); 1033 } else { 1034 fcoet_init_tfm(frm, CMD2XCH(cmd)); 1035 bzero(frm->frm_payload, frm->frm_payload_size); 1036 /* 1037 * lock the xchg to avoid being released (by abort) 1038 * after sent out and before release 1039 */ 1040 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 1041 } 1042 1043 /* 1044 * Fill fc frame header 1045 */ 1046 FFM_R_CTL(0x07, frm); 1047 FRM2TFM(frm)->tfm_rctl = 0x07; 1048 FFM_TYPE(0x08, frm); 1049 FFM_F_CTL(0x990000, frm); 1050 FFM_OXID(cmd->cmd_oxid, frm); 1051 FFM_RXID(cmd->cmd_rxid, frm); 1052 FFM_S_ID(cmd->cmd_lportid, frm); 1053 FFM_D_ID(cmd->cmd_rportid, frm); 1054 FFM_SEQ_ID(0x01, frm); 1055 1056 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 1057 1058 return (FCT_SUCCESS); 1059 } 1060