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 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, 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 fct_ctl(port->port_lport, FCT_CMD_PORT_OFFLINE_COMPLETE, &st); 579 break; 580 581 case FCT_ACK_PORT_ONLINE_COMPLETE: 582 this_ss->ss_state_not_acked = 0; 583 break; 584 585 case FCT_ACK_PORT_OFFLINE_COMPLETE: 586 this_ss->ss_state_not_acked = 0; 587 if (this_ss->ss_change_state_flags & STMF_RFLAG_RESET) { 588 if (fct_port_initialize(port, 589 this_ss->ss_change_state_flags, 590 "fcoet_ctl FCT_ACK_PORT_OFFLINE_COMPLETE " 591 "with RLFLAG_RESET") != FCT_SUCCESS) { 592 cmn_err(CE_WARN, "fcoet_ctl: " 593 "fct_port_initialize %s failed", 594 this_ss->ss_alias); 595 FCOET_LOG("fcoet_ctl: fct_port_initialize " 596 "%s failed", this_ss->ss_alias); 597 } 598 } 599 break; 600 default: 601 FCOET_LOG("fcoet_ctl", "Unsupported cmd %x", cmd); 602 break; 603 } 604 } 605 606 /* 607 * Filling the hba attributes 608 */ 609 /* ARGSUSED */ 610 void 611 fcoet_populate_hba_fru_details(struct fct_local_port *port, 612 struct fct_port_attrs *port_attrs) 613 { 614 (void) snprintf(port_attrs->manufacturer, FCHBA_MANUFACTURER_LEN, 615 "Sun Microsystems, Inc."); 616 (void) snprintf(port_attrs->driver_name, FCHBA_DRIVER_NAME_LEN, 617 "%s", FCOET_NAME); 618 (void) snprintf(port_attrs->driver_version, FCHBA_DRIVER_VERSION_LEN, 619 "%s", FCOET_VERSION); 620 (void) strcpy(port_attrs->serial_number, "N/A"); 621 (void) strcpy(port_attrs->hardware_version, "N/A"); 622 (void) strcpy(port_attrs->model, "FCoE Virtual FC HBA"); 623 (void) strcpy(port_attrs->model_description, "N/A"); 624 (void) strcpy(port_attrs->firmware_version, "N/A"); 625 (void) strcpy(port_attrs->option_rom_version, "N/A"); 626 627 port_attrs->vendor_specific_id = 0xFC0E; 628 port_attrs->max_frame_size = 2136; 629 port_attrs->supported_cos = 0x10000000; 630 /* Specified a fix speed here, need to change it in the future */ 631 port_attrs->supported_speed = PORT_SPEED_1G | PORT_SPEED_10G; 632 } 633 634 635 static fct_status_t 636 fcoet_send_sol_els(fct_cmd_t *cmd) 637 { 638 fcoe_frame_t *frm; 639 fcoet_exchange_t *xch = NULL; 640 641 xch = CMD2XCH(cmd); 642 xch->xch_flags = 0; 643 xch->xch_ss = CMD2SS(cmd); 644 xch->xch_cmd = cmd; 645 xch->xch_current_seq = NULL; 646 xch->xch_left_data_size = 0; 647 xch->xch_sequence_no = 0; 648 xch->xch_start_time = ddi_get_lbolt(); 649 xch->xch_rxid = 0xFFFF; 650 xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 651 if (xch->xch_oxid == 0xFFFF) { 652 xch->xch_oxid = 653 atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 654 } 655 656 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 657 CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL); 658 if (frm == NULL) { 659 ASSERT(0); 660 return (FCT_FAILURE); 661 } else { 662 fcoet_init_tfm(frm, CMD2XCH(cmd)); 663 bzero(frm->frm_payload, frm->frm_payload_size); 664 } 665 666 (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash, 667 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); 668 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; 669 bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload, 670 frm->frm_payload_size); 671 FFM_R_CTL(0x22, frm); 672 FRM2TFM(frm)->tfm_rctl = 0x22; 673 FFM_TYPE(0x01, frm); 674 FFM_F_CTL(0x290000, frm); 675 FFM_OXID(xch->xch_oxid, frm); 676 FFM_RXID(xch->xch_rxid, frm); 677 FFM_S_ID(cmd->cmd_lportid, frm); 678 FFM_D_ID(cmd->cmd_rportid, frm); 679 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 680 681 return (FCT_SUCCESS); 682 } 683 684 static fct_status_t 685 fcoet_send_sol_ct(fct_cmd_t *cmd) 686 { 687 fcoe_frame_t *frm; 688 fcoet_exchange_t *xch; 689 690 xch = CMD2XCH(cmd); 691 xch->xch_flags = 0; 692 xch->xch_ss = CMD2SS(cmd); 693 xch->xch_cmd = cmd; 694 xch->xch_current_seq = NULL; 695 xch->xch_left_data_size = 0; 696 xch->xch_sequence_no = 0; 697 xch->xch_start_time = ddi_get_lbolt(); 698 xch->xch_rxid = 0xFFFF; 699 xch->xch_oxid = atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 700 if (xch->xch_oxid == 0xFFFF) { 701 xch->xch_oxid = 702 atomic_add_16_nv(&xch->xch_ss->ss_next_sol_oxid, 1); 703 } 704 705 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 706 CMD2ELS(cmd)->els_req_size + FCFH_SIZE, NULL); 707 if (frm == NULL) { 708 ASSERT(0); 709 return (FCT_FAILURE); 710 } else { 711 fcoet_init_tfm(frm, CMD2XCH(cmd)); 712 bzero(frm->frm_payload, frm->frm_payload_size); 713 } 714 715 (void) mod_hash_insert(FRM2SS(frm)->ss_sol_oxid_hash, 716 (mod_hash_key_t)(uintptr_t)xch->xch_oxid, (mod_hash_val_t)xch); 717 xch->xch_flags |= XCH_FLAG_IN_HASH_TABLE; 718 bcopy(CMD2ELS(cmd)->els_req_payload, frm->frm_payload, 719 frm->frm_payload_size); 720 FFM_R_CTL(0x2, frm); 721 FRM2TFM(frm)->tfm_rctl = 0x2; 722 FFM_TYPE(0x20, frm); 723 FFM_F_CTL(0x290000, frm); 724 FFM_OXID(xch->xch_oxid, frm); 725 FFM_RXID(xch->xch_rxid, frm); 726 FFM_S_ID(cmd->cmd_lportid, frm); 727 FFM_D_ID(cmd->cmd_rportid, frm); 728 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 729 730 return (FCT_SUCCESS); 731 } 732 733 fct_status_t 734 fcoet_send_status(fct_cmd_t *cmd) 735 { 736 fcoe_frame_t *frm; 737 scsi_task_t *task = CMD2TASK(cmd); 738 fcoe_fcp_rsp_t *ffr; 739 int raw_frame_size; 740 741 /* 742 * Fast channel for good status phase 743 */ 744 if (task->task_scsi_status == STATUS_GOOD && !task->task_resid) { 745 return (fcoet_send_good_status(cmd)); 746 } 747 748 raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t); 749 if (task->task_scsi_status == STATUS_CHECK) { 750 raw_frame_size += task->task_sense_length; 751 } 752 raw_frame_size = P2ROUNDUP(raw_frame_size, 4); 753 754 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 755 raw_frame_size, NULL); 756 if (frm == NULL) { 757 ASSERT(0); 758 return (FCT_FAILURE); 759 } else { 760 fcoet_init_tfm(frm, CMD2XCH(cmd)); 761 bzero(frm->frm_payload, frm->frm_payload_size); 762 /* 763 * lock the xchg to avoid being released (by abort) 764 * after sent out and before release 765 */ 766 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 767 } 768 769 /* 770 * If there's sense data, copy it first 771 */ 772 if ((task->task_scsi_status == STATUS_CHECK) && 773 task->task_sense_length) { 774 bcopy(task->task_sense_data, frm->frm_payload + 775 sizeof (fcoe_fcp_rsp_t), task->task_sense_length); 776 } 777 778 /* 779 * Fill fcp_rsp 780 */ 781 ffr = (fcoe_fcp_rsp_t *)frm->frm_payload; 782 FCOE_V2B_4(0, ffr->ffr_retry_delay_timer); 783 FCOE_V2B_1(0, ffr->ffr_flags); 784 if (task->task_scsi_status == STATUS_CHECK || task->task_resid) { 785 if (task->task_scsi_status == STATUS_CHECK) { 786 ffr->ffr_flags[0] |= BIT_1; 787 } 788 if (task->task_status_ctrl == TASK_SCTRL_OVER) { 789 ffr->ffr_flags[0] |= BIT_2; 790 } else if (task->task_status_ctrl == TASK_SCTRL_UNDER) { 791 ffr->ffr_flags[0] |= BIT_3; 792 } 793 } 794 FCOE_V2B_1(task->task_scsi_status, ffr->ffr_scsi_status); 795 FCOE_V2B_4(task->task_resid, ffr->ffr_resid); 796 FCOE_V2B_4(task->task_sense_length, ffr->ffr_sns_len); 797 FCOE_V2B_4(0, ffr->ffr_rsp_len); 798 799 /* 800 * Fill fc frame header 801 */ 802 FFM_R_CTL(0x07, frm); 803 FRM2TFM(frm)->tfm_rctl = 0x07; 804 FFM_TYPE(0x08, frm); 805 FFM_F_CTL(0x990000, frm); 806 FFM_OXID(cmd->cmd_oxid, frm); 807 FFM_RXID(cmd->cmd_rxid, frm); 808 FFM_S_ID(cmd->cmd_lportid, frm); 809 FFM_D_ID(cmd->cmd_rportid, frm); 810 FFM_SEQ_ID(0x01, frm); 811 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 812 813 return (FCT_SUCCESS); 814 } 815 816 static fct_status_t 817 fcoet_send_els_response(fct_cmd_t *cmd) 818 { 819 fcoe_frame_t *frm; 820 821 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 822 CMD2ELS(cmd)->els_resp_size + FCFH_SIZE, NULL); 823 if (frm == NULL) { 824 ASSERT(0); 825 return (FCT_FAILURE); 826 } else { 827 fcoet_init_tfm(frm, CMD2XCH(cmd)); 828 bzero(frm->frm_payload, frm->frm_payload_size); 829 /* 830 * lock the xchg to avoid being released (by abort) 831 * after sent out and before release 832 */ 833 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 834 } 835 836 bcopy(CMD2ELS(cmd)->els_resp_payload, frm->frm_payload, 837 frm->frm_payload_size); 838 FFM_R_CTL(0x23, frm); 839 FRM2TFM(frm)->tfm_rctl = 0x23; 840 FFM_TYPE(0x01, frm); 841 FFM_F_CTL(0x980000, frm); 842 FFM_OXID(cmd->cmd_oxid, frm); 843 FFM_RXID(cmd->cmd_rxid, frm); 844 FFM_S_ID(cmd->cmd_lportid, frm); 845 FFM_D_ID(cmd->cmd_rportid, frm); 846 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 847 848 return (FCT_SUCCESS); 849 } 850 851 /* ARGSUSED */ 852 static fct_status_t 853 fcoet_send_abts_response(fct_cmd_t *cmd, uint32_t flags) 854 { 855 fcoe_frame_t *frm; 856 fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific; 857 858 /* 859 * The relevant fcoet_exchange has been released 860 */ 861 cmd->cmd_fca_private = NULL; 862 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 863 12 + FCFH_SIZE, NULL); 864 if (frm == NULL) { 865 ASSERT(0); 866 return (FCT_FAILURE); 867 } else { 868 fcoet_init_tfm(frm, NULL); 869 } 870 871 bcopy(abts->abts_resp_payload, frm->frm_payload, 872 frm->frm_payload_size); 873 FFM_R_CTL(abts->abts_resp_rctl, frm); 874 FRM2TFM(frm)->tfm_rctl = abts->abts_resp_rctl; 875 FFM_TYPE(0x00, frm); 876 FFM_F_CTL(0x980000, frm); 877 FFM_OXID(cmd->cmd_oxid, frm); 878 FFM_RXID(cmd->cmd_rxid, frm); 879 FFM_S_ID(cmd->cmd_lportid, frm); 880 FFM_D_ID(cmd->cmd_rportid, frm); 881 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 882 883 return (FCT_SUCCESS); 884 } 885 886 /* 887 * enable/disable port is simple compared to physical FC HBAs 888 */ 889 fct_status_t 890 fcoet_enable_port(fcoet_soft_state_t *ss) 891 { 892 FCOET_EXT_LOG(ss->ss_alias, "port is being enabled-%p", ss); 893 /* Call fcoe function to online the port */ 894 if (ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_ONLINE, 0) == 895 FCOE_FAILURE) { 896 return (FCT_FAILURE); 897 } 898 899 if ((ss->ss_flags & SS_FLAG_PORT_DISABLED) == SS_FLAG_PORT_DISABLED) { 900 atomic_and_32(&ss->ss_flags, ~SS_FLAG_PORT_DISABLED); 901 } 902 903 return (FCT_SUCCESS); 904 } 905 906 fct_status_t 907 fcoet_disable_port(fcoet_soft_state_t *ss) 908 { 909 fct_status_t status; 910 911 FCOET_EXT_LOG(ss->ss_alias, "port is being disabled-%p", ss); 912 /* Call fcoe function to offline the port */ 913 status = fcoet_logo_fabric(ss); 914 ss->ss_eport->eport_ctl(ss->ss_eport, FCOE_CMD_PORT_OFFLINE, 0); 915 atomic_or_32(&ss->ss_flags, SS_FLAG_PORT_DISABLED); 916 return (status); 917 } 918 919 static fct_status_t 920 fcoet_logo_fabric(fcoet_soft_state_t *ss) 921 { 922 fcoe_frame_t *frm; 923 uint32_t req_payload_size = 16; 924 uint16_t xch_oxid, xch_rxid = 0xFFFF; 925 926 frm = ss->ss_eport->eport_alloc_frame(ss->ss_eport, 927 req_payload_size + FCFH_SIZE, NULL); 928 if (frm == NULL) { 929 ASSERT(0); 930 return (FCT_FAILURE); 931 } else { 932 fcoet_init_tfm(frm, NULL); 933 bzero(frm->frm_payload, frm->frm_payload_size); 934 } 935 xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); 936 if (xch_oxid == 0xFFFF) { 937 xch_oxid = atomic_add_16_nv(&ss->ss_next_sol_oxid, 1); 938 } 939 FFM_R_CTL(0x22, frm); 940 FRM2TFM(frm)->tfm_rctl = 0x22; 941 FFM_TYPE(0x01, frm); 942 FFM_F_CTL(0x290000, frm); 943 FFM_OXID(xch_oxid, frm); 944 FFM_RXID(xch_rxid, frm); 945 FFM_S_ID(ss->ss_link_info.portid, frm); 946 FFM_D_ID(0xfffffe, frm); 947 948 FCOE_V2B_1(0x5, frm->frm_payload); 949 FCOE_V2B_3(ss->ss_link_info.portid, frm->frm_payload + 5); 950 bcopy(ss->ss_eport->eport_portwwn, frm->frm_payload + 8, 8); 951 ss->ss_eport->eport_tx_frame(frm); 952 953 return (FCT_SUCCESS); 954 955 } 956 957 /* 958 * Called by: fcoet_register_remote_port 959 */ 960 /* ARGSUSED */ 961 static fct_status_t 962 fcoet_fill_plogi_req(fct_local_port_t *port, fct_remote_port_t *rp, 963 fct_cmd_t *login) 964 { 965 uint8_t *p; 966 967 p = ((fct_els_t *)login->cmd_specific)->els_req_payload; 968 p[0] = ELS_OP_PLOGI; 969 p[4] = 0x20; 970 p[5] = 0x20; 971 p[7] = 3; 972 p[8] = 0x88; 973 p[10] = 8; 974 p[13] = 0xff; p[15] = 0x1f; 975 p[18] = 7; p[19] = 0xd0; 976 977 bcopy(port->port_pwwn, p + 20, 8); 978 bcopy(port->port_nwwn, p + 28, 8); 979 980 p[68] = 0x80; 981 p[74] = 8; 982 p[77] = 0xff; 983 p[81] = 1; 984 985 return (FCT_SUCCESS); 986 } 987 988 /* 989 * Called by: fcoet_register_remote_port 990 */ 991 /* ARGSUSED */ 992 static fct_status_t 993 fcoet_fill_plogi_resp(fct_local_port_t *port, fct_remote_port_t *rp, 994 fct_cmd_t *login) 995 { 996 uint8_t *p; 997 /* 998 * ACC 999 */ 1000 p = ((fct_els_t *)login->cmd_specific)->els_req_payload; 1001 p[0] = ELS_OP_ACC; 1002 p[4] = 0x20; 1003 p[5] = 0x20; 1004 p[7] = 0x0A; 1005 p[10] = 0x05; 1006 p[11] = 0xAC; 1007 1008 bcopy(port->port_pwwn, p + 20, 8); 1009 bcopy(port->port_nwwn, p + 28, 8); 1010 1011 p[68] = 0x88; 1012 return (FCT_SUCCESS); 1013 } 1014 1015 static fct_status_t 1016 fcoet_send_good_status(fct_cmd_t *cmd) 1017 { 1018 fcoe_frame_t *frm; 1019 int raw_frame_size; 1020 1021 raw_frame_size = FCFH_SIZE + sizeof (fcoe_fcp_rsp_t); 1022 frm = CMD2SS(cmd)->ss_eport->eport_alloc_frame(CMD2SS(cmd)->ss_eport, 1023 raw_frame_size, NULL); 1024 if (frm == NULL) { 1025 ASSERT(0); 1026 return (FCT_FAILURE); 1027 } else { 1028 fcoet_init_tfm(frm, CMD2XCH(cmd)); 1029 bzero(frm->frm_payload, frm->frm_payload_size); 1030 /* 1031 * lock the xchg to avoid being released (by abort) 1032 * after sent out and before release 1033 */ 1034 FCOET_BUSY_XCHG(CMD2XCH(cmd)); 1035 } 1036 1037 /* 1038 * Fill fc frame header 1039 */ 1040 FFM_R_CTL(0x07, frm); 1041 FRM2TFM(frm)->tfm_rctl = 0x07; 1042 FFM_TYPE(0x08, frm); 1043 FFM_F_CTL(0x990000, frm); 1044 FFM_OXID(cmd->cmd_oxid, frm); 1045 FFM_RXID(cmd->cmd_rxid, frm); 1046 FFM_S_ID(cmd->cmd_lportid, frm); 1047 FFM_D_ID(cmd->cmd_rportid, frm); 1048 FFM_SEQ_ID(0x01, frm); 1049 1050 CMD2SS(cmd)->ss_eport->eport_tx_frame(frm); 1051 1052 return (FCT_SUCCESS); 1053 } 1054