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