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_inc_8(&xch->xch_sequence_no);
 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_inc_16_nv(&ss->ss_next_sol_oxid);
 942         if (xch_oxid == 0xFFFF) {
 943                 xch_oxid = atomic_inc_16_nv(&ss->ss_next_sol_oxid);
 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 }