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