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
   9  * http://www.opensource.org/licenses/cddl1.txt.
  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) 2004-2012 Emulex. All rights reserved.
  24  * Use is subject to license terms.
  25  * Copyright 2016 Nexenta Systems, Inc. All rights reserved.
  26  */
  27 
  28 #include <emlxs.h>
  29 
  30 #ifdef SFCT_SUPPORT
  31 
  32 
  33 /* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
  34 EMLXS_MSG_DEF(EMLXS_FCT_C);
  35 
  36 static void emlxs_fct_memseg_init(emlxs_hba_t *hba);
  37 
  38 static fct_status_t emlxs_fct_cmd_acquire(emlxs_port_t *port,
  39         fct_cmd_t *fct_cmd, uint16_t fct_state);
  40 static fct_status_t emlxs_fct_cmd_accept(emlxs_port_t *port,
  41         fct_cmd_t *fct_cmd, uint16_t fct_state);
  42 static void emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
  43         uint16_t fct_state);
  44 
  45 static emlxs_buf_t *emlxs_fct_cmd_init(emlxs_port_t *port,
  46     fct_cmd_t *fct_cmd, uint16_t fct_state);
  47 static void emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd,
  48         uint16_t fct_state);
  49 static void emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
  50         uint16_t fct_state);
  51 
  52 static fct_status_t emlxs_fct_flogi_xchg(struct fct_local_port *fct_port,
  53     struct fct_flogi_xchg *fx);
  54 static fct_status_t emlxs_fct_get_link_info(fct_local_port_t *fct_port,
  55     fct_link_info_t *link);
  56 static fct_status_t emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
  57     fct_remote_port_t *port_handle);
  58 static fct_status_t emlxs_fct_send_cmd(fct_cmd_t *fct_cmd);
  59 static fct_status_t emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd,
  60     stmf_data_buf_t *dbuf, uint32_t ioflags);
  61 static fct_status_t emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t flags);
  62 static fct_status_t emlxs_fct_abort(fct_local_port_t *fct_port,
  63     fct_cmd_t *cmd, uint32_t flags);
  64 static void emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg);
  65 static fct_status_t emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
  66     fct_remote_port_t *port_handle, fct_cmd_t *plogi);
  67 static fct_status_t emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd);
  68 static fct_status_t emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd);
  69 static fct_status_t emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd);
  70 static fct_status_t emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd);
  71 static void emlxs_fct_pkt_comp(fc_packet_t *pkt);
  72 static void emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
  73     fct_port_attrs_t *port_attrs);
  74 static fct_status_t emlxs_fct_port_info(uint32_t cmd,
  75     fct_local_port_t *fct_port, void *arg, uint8_t *buffer, uint32_t *size);
  76 
  77 static fct_status_t emlxs_fct_dmem_init(emlxs_port_t *port);
  78 static void emlxs_fct_dmem_fini(emlxs_port_t *port);
  79 
  80 static stmf_data_buf_t *emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port,
  81     uint32_t size, uint32_t *pminsize, uint32_t flags);
  82 static void emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *dbuf);
  83 
  84 static int emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *dbuf,
  85     uint_t sync_type);
  86 static emlxs_buf_t *emlxs_fct_pkt_init(emlxs_port_t *port,
  87     fct_cmd_t *fct_cmd, fc_packet_t *pkt);
  88 
  89 static void emlxs_fct_unsol_flush_thread(emlxs_hba_t *hba, void *arg1,
  90     void *arg2);
  91 static void emlxs_fct_unsol_flush(emlxs_port_t *port);
  92 static uint32_t emlxs_fct_process_unsol_flogi(emlxs_port_t *port,
  93     CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size);
  94 static uint32_t emlxs_fct_process_unsol_plogi(emlxs_port_t *port,
  95     CHANNEL *cp, IOCBQ *iocbq, MATCHMAP *mp, uint32_t size);
  96 static uint32_t emlxs_fct_pkt_abort_txq(emlxs_port_t *port,
  97     emlxs_buf_t *cmd_sbp);
  98 static fct_status_t emlxs_fct_send_qfull_reply(emlxs_port_t *port,
  99     emlxs_node_t *ndlp, uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd);
 100 
 101 #ifdef FCT_IO_TRACE
 102 uint8_t *emlxs_iotrace = 0;     /* global for mdb */
 103 int emlxs_iotrace_cnt = 0;
 104 
 105 /*
 106  *
 107  * FCT_CMD  (cmd_sbp->fct_state)
 108  *
 109  * STATE                                LOCK STATUS                     OWNER
 110  * -----------------------------------------------------------------------------
 111  * EMLXS_FCT_ABORT_DONE                 Lock Destroyed                  COMSTAR
 112  * EMLXS_FCT_IO_DONE                    Lock Destroyed                  COMSTAR
 113  *
 114  * EMLXS_FCT_CMD_POSTED                 Lock Released                   COMSTAR
 115  * EMLXS_FCT_OWNED                      Lock Released                   COMSTAR
 116  *
 117  * EMLXS_FCT_CMD_WAITQ                  Lock Released                   DRIVER
 118  * EMLXS_FCT_RSP_PENDING                Lock Released                   DRIVER
 119  * EMLXS_FCT_REQ_PENDING                Lock Released                   DRIVER
 120  * EMLXS_FCT_REG_PENDING                Lock Released                   DRIVER
 121  * EMLXS_FCT_DATA_PENDING               Lock Released                   DRIVER
 122  * EMLXS_FCT_STATUS_PENDING             Lock Released                   DRIVER
 123  * EMLXS_FCT_CLOSE_PENDING              Lock Released                   DRIVER
 124  * EMLXS_FCT_ABORT_PENDING              Lock Released                   DRIVER
 125  *
 126  * EMLXS_FCT_FCP_CMD_RECEIVED           Transistional, lock held        DRIVER
 127  * EMLXS_FCT_ELS_CMD_RECEIVED           Transistional, lock held        DRIVER
 128  * EMLXS_FCT_SEND_CMD_RSP               Transistional, lock held        DRIVER
 129  * EMLXS_FCT_SEND_ELS_RSP               Transistional, lock held        DRIVER
 130  * EMLXS_FCT_SEND_ELS_REQ               Transistional, lock held        DRIVER
 131  * EMLXS_FCT_SEND_CT_REQ                Transistional, lock held        DRIVER
 132  * EMLXS_FCT_REG_COMPLETE               Transistional, lock held        DRIVER
 133  * EMLXS_FCT_SEND_FCP_DATA              Transistional, lock held        DRIVER
 134  * EMLXS_FCT_SEND_FCP_STATUS            Transistional, lock held        DRIVER
 135  * EMLXS_FCT_PKT_COMPLETE               Transistional, lock held        DRIVER
 136  * EMLXS_FCT_PKT_FCPRSP_COMPLETE        Transistional, lock held        DRIVER
 137  * EMLXS_FCT_PKT_ELSRSP_COMPLETE        Transistional, lock held        DRIVER
 138  * EMLXS_FCT_PKT_ELSCMD_COMPLETE        Transistional, lock held        DRIVER
 139  * EMLXS_FCT_PKT_CTCMD_COMPLETE         Transistional, lock held        DRIVER
 140  * EMLXS_FCT_REQ_COMPLETE               Transistional, lock held        DRIVER
 141  *
 142  *
 143  *      COMSTAR OWNED   DRIVER OWNED
 144  *      -------------   ---------------------------------------------------
 145  *      ------- >    @          Accept---- >Release  @   Acquire--- >+
 146  *                                                                      |
 147  *      < -------    @       Post/Done< ----Acquire  @   Release< ---+
 148  *
 149  *      @  :Indicates COMSTAR use of emlxs_fct_abort()
 150  *          Abort requests set the EMLXS_FCT_ABORT_INP flag.
 151  *
 152  *      Accept          :Indicates use of emlxs_fct_cmd_accept()
 153  *      Acquire         :Indicates use of emlxs_fct_cmd_acquire()
 154  *      Post            :Indicates use of emlxs_fct_cmd_post()
 155  *      Done            :Indicates use of emlxs_fct_cmd_done()
 156  */
 157 
 158 void
 159 emlxs_fct_io_trace(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint32_t data)
 160 {
 161         emlxs_iotrace_t *iop = port->iotrace;
 162         uint16_t iotrace_cnt;
 163         uint16_t iotrace_index;
 164         int i;
 165 
 166         if (!iop) {
 167                 return;
 168         }
 169 
 170         mutex_enter(&port->iotrace_mtx);
 171         iotrace_cnt = port->iotrace_cnt;
 172         iotrace_index = port->iotrace_index;
 173 
 174         switch (data) {
 175 
 176                 /* New entry */
 177         case EMLXS_FCT_ELS_CMD_RECEIVED:
 178         case EMLXS_FCT_FCP_CMD_RECEIVED:
 179         case EMLXS_FCT_SEND_ELS_REQ:
 180         case EMLXS_FCT_SEND_CT_REQ:
 181                 for (i = 0; i < iotrace_cnt; i++) {
 182                         if ((iop->fct_cmd == fct_cmd) &&
 183                             (iop->trc[0] != (uint8_t)(0)))
 184                                 break;
 185                         iop++;
 186                 }
 187                 if (i < iotrace_cnt) {
 188                         /* New entry already exists */
 189                         mutex_exit(&port->iotrace_mtx);
 190                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 191                             "IOTRACE: New entry already exists: fct_cmd: %p",
 192                             fct_cmd);
 193                         return;
 194                 }
 195                 iop = port->iotrace + iotrace_index;
 196                 for (i = 0; i < iotrace_cnt; i++) {
 197                         if (iop->trc[0] == (uint8_t)(0))
 198                                 break;
 199 
 200                         iop++;
 201                         if (iop == (port->iotrace + iotrace_cnt))
 202                                 iop = port->iotrace;
 203                 }
 204                 if (i >= iotrace_cnt) {
 205                         /* No new slots available */
 206                         mutex_exit(&port->iotrace_mtx);
 207                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 208                             "IOTRACE: No new slots: fct_cmd: %p data: %d",
 209                             fct_cmd, data);
 210                         return;
 211                 }
 212                 port->iotrace_index++;
 213                 if (port->iotrace_index >= iotrace_cnt)
 214                         port->iotrace_index = 0;
 215 
 216                 bzero((uint8_t *)iop, sizeof (emlxs_iotrace_t));
 217                 iop->fct_cmd = fct_cmd;
 218                 iop->xri = fct_cmd->cmd_rxid;
 219                 iop->marker = 0xff;
 220                 iop->trc[0] = 2;
 221                 iop->trc[1] = data;
 222                 mutex_exit(&port->iotrace_mtx);
 223                 return;
 224         }
 225 
 226         for (i = 0; i < iotrace_cnt; i++) {
 227                 if ((iop->fct_cmd == fct_cmd) &&
 228                     (iop->trc[0] != (uint8_t)(0)))
 229                         break;
 230                 iop++;
 231         }
 232         if (i >= iotrace_cnt) {
 233                 /* Cannot find existing slot for fct_cmd */
 234                 mutex_exit(&port->iotrace_mtx);
 235 
 236                 if ((data != EMLXS_FCT_REG_PENDING) &&
 237                     (data != EMLXS_FCT_REG_COMPLETE)) {
 238                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 239                             "IOTRACE: Missing slot: fct_cmd: %p data: %d",
 240                             fct_cmd, data);
 241                 }
 242                 return;
 243         }
 244 
 245         if (iop->trc[0] >= MAX_IO_TRACE) {
 246                 /* trc overrun for fct_cmd */
 247                 mutex_exit(&port->iotrace_mtx);
 248                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 249                     "IOTRACE: trc overrun slot: fct_cmd: %p data: %d",
 250                     fct_cmd, data);
 251                 return;
 252         }
 253 
 254         if (iop->xri != fct_cmd->cmd_rxid) {
 255                 /* xri mismatch for fct_cmd */
 256                 mutex_exit(&port->iotrace_mtx);
 257                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 258                     "IOTRACE: xri mismatch %x != %x: fct_cmd: %p data: %d",
 259                     iop->xri, fct_cmd->cmd_rxid, fct_cmd, data);
 260                 return;
 261         }
 262 
 263         iop->trc[iop->trc[0]] = data;
 264         if ((data == EMLXS_FCT_IO_DONE) || (data == EMLXS_FCT_ABORT_DONE)) {
 265                 /* IOCB ULPCOMMAND is saved after EMLXS_FCT_IOCB_ISSUED */
 266                 if (iop->trc[iop->trc[0]-1] == EMLXS_FCT_IOCB_ISSUED) {
 267                         iop->trc[0]++;
 268                 } else {
 269                         iop->trc[0] = 0;
 270         } else {
 271                 iop->trc[0]++;
 272         }
 273         mutex_exit(&port->iotrace_mtx);
 274 
 275         return;
 276 
 277 } /* emlxs_fct_io_trace() */
 278 #endif /* FCT_IO_TRACE */
 279 
 280 #ifdef MODSYM_SUPPORT
 281 
 282 extern int
 283 emlxs_fct_modopen()
 284 {
 285         int err;
 286 
 287         mutex_enter(&emlxs_device.lock);
 288 
 289         if (emlxs_modsym.fct_modopen) {
 290                 mutex_exit(&emlxs_device.lock);
 291                 return (0);
 292         }
 293 
 294         emlxs_modsym.fct_modopen++;
 295 
 296         /* Comstar (fct) */
 297         err = 0;
 298         emlxs_modsym.mod_fct = ddi_modopen("drv/fct", KRTLD_MODE_FIRST, &err);
 299         if (!emlxs_modsym.mod_fct) {
 300 
 301                 cmn_err(CE_WARN, "?%s: ddi_modopen drv/fct failed: err %d",
 302                     DRIVER_NAME, err);
 303                 goto failed;
 304         }
 305 
 306         /* Comstar (stmf) */
 307         err = 0;
 308         emlxs_modsym.mod_stmf =
 309             ddi_modopen("drv/stmf", KRTLD_MODE_FIRST, &err);
 310         if (!emlxs_modsym.mod_stmf) {
 311 
 312                 cmn_err(CE_WARN, "?%s: ddi_modopen drv/stmf failed: err %d",
 313                     DRIVER_NAME, err);
 314                 goto failed;
 315         }
 316 
 317         err = 0;
 318         /* Check if the fct fct_alloc is present */
 319         emlxs_modsym.fct_alloc = (void *(*)())ddi_modsym(emlxs_modsym.mod_fct,
 320             "fct_alloc", &err);
 321         if ((void *)emlxs_modsym.fct_alloc == NULL) {
 322                 cmn_err(CE_WARN,
 323                     "?%s: drv/fct: fct_alloc not present", DRIVER_NAME);
 324                 goto failed;
 325         }
 326 
 327         err = 0;
 328         /* Check if the fct fct_free is present */
 329         emlxs_modsym.fct_free = (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 330             "fct_free", &err);
 331         if ((void *)emlxs_modsym.fct_free == NULL) {
 332                 cmn_err(CE_WARN,
 333                     "?%s: drv/fct: fct_free not present", DRIVER_NAME);
 334                 goto failed;
 335         }
 336 
 337         err = 0;
 338         /* Check if the fct fct_scsi_task_alloc is present */
 339         emlxs_modsym.fct_scsi_task_alloc =
 340             (void *(*)(void *, uint16_t, uint32_t, uint8_t *,
 341             uint16_t, uint16_t))ddi_modsym(emlxs_modsym.mod_fct,
 342             "fct_scsi_task_alloc", &err);
 343         if ((void *)emlxs_modsym.fct_scsi_task_alloc == NULL) {
 344                 cmn_err(CE_WARN,
 345                     "?%s: drv/fct: fct_scsi_task_alloc not present",
 346                     DRIVER_NAME);
 347                 goto failed;
 348         }
 349 
 350         err = 0;
 351         /* Check if the fct fct_register_local_port is present */
 352         emlxs_modsym.fct_register_local_port =
 353             (int (*)())ddi_modsym(emlxs_modsym.mod_fct,
 354             "fct_register_local_port", &err);
 355         if ((void *)emlxs_modsym.fct_register_local_port == NULL) {
 356                 cmn_err(CE_WARN,
 357                     "?%s: drv/fct: fct_register_local_port not present",
 358                     DRIVER_NAME);
 359                 goto failed;
 360         }
 361 
 362         err = 0;
 363         /* Check if the fct fct_deregister_local_port is present */
 364         emlxs_modsym.fct_deregister_local_port =
 365             (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 366             "fct_deregister_local_port", &err);
 367         if ((void *)emlxs_modsym.fct_deregister_local_port == NULL) {
 368                 cmn_err(CE_WARN,
 369                     "?%s: drv/fct: fct_deregister_local_port not present",
 370                     DRIVER_NAME);
 371                 goto failed;
 372         }
 373 
 374         err = 0;
 375         /* Check if the fct fct_handle_event is present */
 376         emlxs_modsym.fct_handle_event =
 377             (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_handle_event",
 378             &err);
 379         if ((void *)emlxs_modsym.fct_handle_event == NULL) {
 380                 cmn_err(CE_WARN,
 381                     "?%s: drv/fct: fct_handle_event not present",
 382                     DRIVER_NAME);
 383                 goto failed;
 384         }
 385 
 386         err = 0;
 387         /* Check if the fct fct_post_rcvd_cmd is present */
 388         emlxs_modsym.fct_post_rcvd_cmd =
 389             (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_post_rcvd_cmd",
 390             &err);
 391         if ((void *)emlxs_modsym.fct_post_rcvd_cmd == NULL) {
 392                 cmn_err(CE_WARN,
 393                     "?%s: drv/fct: fct_post_rcvd_cmd not present",
 394                     DRIVER_NAME);
 395                 goto failed;
 396         }
 397         err = 0;
 398         /* Check if the fct fct_alloc is present */
 399         emlxs_modsym.fct_ctl = (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 400             "fct_ctl", &err);
 401         if ((void *)emlxs_modsym.fct_ctl == NULL) {
 402                 cmn_err(CE_WARN,
 403                     "?%s: drv/fct: fct_ctl not present", DRIVER_NAME);
 404                 goto failed;
 405         }
 406         err = 0;
 407         /* Check if the fct fct_queue_cmd_for_termination is present */
 408         emlxs_modsym.fct_queue_cmd_for_termination =
 409             (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 410             "fct_queue_cmd_for_termination", &err);
 411         if ((void *)emlxs_modsym.fct_queue_cmd_for_termination == NULL) {
 412                 cmn_err(CE_WARN,
 413                     "?%s: drv/fct: fct_queue_cmd_for_termination not present",
 414                     DRIVER_NAME);
 415                 goto failed;
 416         }
 417         err = 0;
 418         /* Check if the fct fct_send_response_done is present */
 419         emlxs_modsym.fct_send_response_done =
 420             (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 421             "fct_send_response_done", &err);
 422         if ((void *)emlxs_modsym.fct_send_response_done == NULL) {
 423                 cmn_err(CE_WARN,
 424                     "?%s: drv/fct: fct_send_response_done not present",
 425                     DRIVER_NAME);
 426                 goto failed;
 427         }
 428         err = 0;
 429         /* Check if the fct fct_send_cmd_done is present */
 430         emlxs_modsym.fct_send_cmd_done =
 431             (void (*)())ddi_modsym(emlxs_modsym.mod_fct, "fct_send_cmd_done",
 432             &err);
 433         if ((void *)emlxs_modsym.fct_send_cmd_done == NULL) {
 434                 cmn_err(CE_WARN,
 435                     "?%s: drv/fct: fct_send_cmd_done not present",
 436                     DRIVER_NAME);
 437                 goto failed;
 438         }
 439         err = 0;
 440         /* Check if the fct fct_scsi_xfer_data_done is present */
 441         emlxs_modsym.fct_scsi_data_xfer_done =
 442             (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 443             "fct_scsi_data_xfer_done", &err);
 444         if ((void *)emlxs_modsym.fct_scsi_data_xfer_done == NULL) {
 445                 cmn_err(CE_WARN,
 446                     "?%s: drv/fct: fct_scsi_data_xfer_done not present",
 447                     DRIVER_NAME);
 448                 goto failed;
 449         }
 450         err = 0;
 451         /* Check if the fct fct_port_shutdown is present */
 452         emlxs_modsym.fct_port_shutdown =
 453             (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
 454             "fct_port_shutdown", &err);
 455         if ((void *)emlxs_modsym.fct_port_shutdown == NULL) {
 456                 cmn_err(CE_WARN,
 457                     "?%s: drv/fct: fct_port_shutdown not present",
 458                     DRIVER_NAME);
 459                 goto failed;
 460         }
 461 
 462         err = 0;
 463         /* Check if the fct fct_port_initialize is present */
 464         emlxs_modsym.fct_port_initialize =
 465             (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
 466             "fct_port_initialize", &err);
 467         if ((void *)emlxs_modsym.fct_port_initialize == NULL) {
 468                 cmn_err(CE_WARN,
 469                     "?%s: drv/fct: fct_port_initialize not present",
 470                     DRIVER_NAME);
 471                 goto failed;
 472         }
 473 
 474         err = 0;
 475         /* Check if the fct fct_cmd_fca_aborted is present */
 476         emlxs_modsym.fct_cmd_fca_aborted =
 477             (void (*)())ddi_modsym(emlxs_modsym.mod_fct,
 478             "fct_cmd_fca_aborted", &err);
 479         if ((void *)emlxs_modsym.fct_cmd_fca_aborted == NULL) {
 480                 cmn_err(CE_WARN,
 481                     "?%s: drv/fct: fct_cmd_fca_aborted not present",
 482                     DRIVER_NAME);
 483                 goto failed;
 484         }
 485 
 486         err = 0;
 487         /* Check if the fct fct_handle_rcvd_flogi is present */
 488         emlxs_modsym.fct_handle_rcvd_flogi =
 489             (fct_status_t(*)())ddi_modsym(emlxs_modsym.mod_fct,
 490             "fct_handle_rcvd_flogi", &err);
 491         if ((void *)emlxs_modsym.fct_handle_rcvd_flogi == NULL) {
 492                 cmn_err(CE_WARN,
 493                     "?%s: drv/fct: fct_handle_rcvd_flogi not present",
 494                     DRIVER_NAME);
 495                 goto failed;
 496         }
 497 
 498         /* Comstar (stmf) */
 499         err = 0;
 500         /* Check if the stmf stmf_alloc is present */
 501         emlxs_modsym.stmf_alloc =
 502             (void *(*)())ddi_modsym(emlxs_modsym.mod_stmf, "stmf_alloc",
 503             &err);
 504         if ((void *)emlxs_modsym.stmf_alloc == NULL) {
 505                 cmn_err(CE_WARN,
 506                     "?%s: drv/stmf: stmf_alloc not present", DRIVER_NAME);
 507                 goto failed;
 508         }
 509 
 510         err = 0;
 511         /* Check if the stmf stmf_free is present */
 512         emlxs_modsym.stmf_free = (void (*)())ddi_modsym(emlxs_modsym.mod_stmf,
 513             "stmf_free", &err);
 514         if ((void *)emlxs_modsym.stmf_free == NULL) {
 515                 cmn_err(CE_WARN,
 516                     "?%s: drv/stmf: stmf_free not present", DRIVER_NAME);
 517                 goto failed;
 518         }
 519 
 520         err = 0;
 521         /* Check if the stmf stmf_deregister_port_provider is present */
 522         emlxs_modsym.stmf_deregister_port_provider =
 523             (void (*)())ddi_modsym(emlxs_modsym.mod_stmf,
 524             "stmf_deregister_port_provider", &err);
 525         if ((void *)emlxs_modsym.stmf_deregister_port_provider == NULL) {
 526                 cmn_err(CE_WARN,
 527                     "?%s: drv/stmf: stmf_deregister_port_provider not present",
 528                     DRIVER_NAME);
 529                 goto failed;
 530         }
 531 
 532         err = 0;
 533         /* Check if the stmf stmf_register_port_provider is present */
 534         emlxs_modsym.stmf_register_port_provider =
 535             (int (*)())ddi_modsym(emlxs_modsym.mod_stmf,
 536             "stmf_register_port_provider", &err);
 537         if ((void *)emlxs_modsym.stmf_register_port_provider == NULL) {
 538                 cmn_err(CE_WARN,
 539                     "?%s: drv/stmf: stmf_register_port_provider not present",
 540                     DRIVER_NAME);
 541                 goto failed;
 542         }
 543 
 544         mutex_exit(&emlxs_device.lock);
 545         return (0);
 546 
 547 failed:
 548 
 549         mutex_exit(&emlxs_device.lock);
 550         emlxs_fct_modclose();
 551         return (1);
 552 
 553 } /* emlxs_fct_modopen() */
 554 
 555 
 556 extern void
 557 emlxs_fct_modclose()
 558 {
 559         mutex_enter(&emlxs_device.lock);
 560 
 561         if (emlxs_modsym.fct_modopen == 0) {
 562                 mutex_exit(&emlxs_device.lock);
 563                 return;
 564         }
 565 
 566         emlxs_modsym.fct_modopen--;
 567 
 568         if (emlxs_modsym.fct_modopen) {
 569                 mutex_exit(&emlxs_device.lock);
 570                 return;
 571         }
 572 
 573         if (emlxs_modsym.mod_fct) {
 574                 (void) ddi_modclose(emlxs_modsym.mod_fct);
 575                 emlxs_modsym.mod_fct = 0;
 576         }
 577 
 578         if (emlxs_modsym.mod_stmf) {
 579                 (void) ddi_modclose(emlxs_modsym.mod_stmf);
 580                 emlxs_modsym.mod_stmf = 0;
 581         }
 582 
 583         emlxs_modsym.fct_alloc = NULL;
 584         emlxs_modsym.fct_free = NULL;
 585         emlxs_modsym.fct_scsi_task_alloc = NULL;
 586         emlxs_modsym.fct_register_local_port = NULL;
 587         emlxs_modsym.fct_deregister_local_port = NULL;
 588         emlxs_modsym.fct_handle_event = NULL;
 589         emlxs_modsym.fct_ctl = NULL;
 590         emlxs_modsym.fct_queue_cmd_for_termination = NULL;
 591         emlxs_modsym.fct_send_response_done = NULL;
 592         emlxs_modsym.fct_send_cmd_done = NULL;
 593         emlxs_modsym.fct_scsi_data_xfer_done = NULL;
 594         emlxs_modsym.fct_port_shutdown = NULL;
 595         emlxs_modsym.fct_port_initialize = NULL;
 596         emlxs_modsym.fct_cmd_fca_aborted = NULL;
 597         emlxs_modsym.fct_handle_rcvd_flogi = NULL;
 598 
 599         emlxs_modsym.stmf_alloc = NULL;
 600         emlxs_modsym.stmf_free = NULL;
 601         emlxs_modsym.stmf_deregister_port_provider = NULL;
 602         emlxs_modsym.stmf_register_port_provider = NULL;
 603 
 604         mutex_exit(&emlxs_device.lock);
 605 
 606 } /* emlxs_fct_modclose() */
 607 
 608 #endif /* MODSYM_SUPPORT */
 609 
 610 /*
 611  * This routine is called to handle an unsol FLOGI exchange
 612  *      fx      save
 613  *      0       1       Process or save port->fx
 614  *      0       0       Process or reject port->fx
 615  *      1       1       Process port->fx, Process or save fx
 616  *      1       0       Process or reject port->fx, Process or reject fx
 617  */
 618 static void
 619 emlxs_fct_handle_unsol_flogi(emlxs_port_t *port, fct_flogi_xchg_t *fx,
 620     uint32_t save)
 621 {
 622         emlxs_hba_t *hba = HBA;
 623         fct_status_t status;
 624         IOCBQ iocbq;
 625         fct_flogi_xchg_t fxchg;
 626 
 627 begin:
 628         mutex_enter(&EMLXS_PORT_LOCK);
 629 
 630         /* Check if there is an old saved FLOGI */
 631         if (port->fx.fx_op) {
 632                 /* Get it now */
 633                 bcopy(&port->fx, &fxchg, sizeof (fct_flogi_xchg_t));
 634 
 635                 if (fx) {
 636                         /* Save new FLOGI */
 637                         bcopy(fx, &port->fx, sizeof (fct_flogi_xchg_t));
 638 
 639                         /* Reject old stale FLOGI */
 640                         fx = &fxchg;
 641                         goto reject_it;
 642 
 643                 } else {
 644                         bzero(&port->fx, sizeof (fct_flogi_xchg_t));
 645                         fx = &fxchg;
 646                 }
 647 
 648         } else if (!fx) {
 649                 /* Nothing to do, just return */
 650                 mutex_exit(&EMLXS_PORT_LOCK);
 651                 return;
 652         }
 653 
 654         /* We have a valid FLOGI here */
 655         /* There is no saved FLOGI at this point either */
 656 
 657         /* Check if COMSTAR is ready to accept it */
 658         if (port->fct_flags & FCT_STATE_LINK_UP_ACKED) {
 659                 mutex_exit(&EMLXS_PORT_LOCK);
 660 
 661                 bzero((uint8_t *)&iocbq, sizeof (IOCBQ));
 662                 iocbq.iocb.un.elsreq.remoteID = fx->fx_sid;
 663                 iocbq.iocb.un.elsreq.myID = fx->fx_did;
 664                 iocbq.iocb.ULPCONTEXT = (uint16_t)fx->rsvd2;
 665                 fx->rsvd2 = 0; /* Clear the reserved field now */
 666 
 667                 status = MODSYM(fct_handle_rcvd_flogi) (port->fct_port, fx);
 668 
 669 #ifdef FCT_API_TRACE
 670                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
 671                     "fct_handle_rcvd_flogi %p: status=%x",
 672                     port->fct_port, status);
 673 #endif /* FCT_API_TRACE */
 674 
 675                 if (status == FCT_SUCCESS) {
 676                         if (fx->fx_op == ELS_OP_ACC) {
 677                                 (void) emlxs_els_reply(port, &iocbq,
 678                                     ELS_CMD_ACC, ELS_CMD_FLOGI, 0, 0);
 679 
 680                         } else {        /* ELS_OP_LSRJT */
 681                                 (void) emlxs_els_reply(port, &iocbq,
 682                                     ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
 683                                     fx->fx_rjt_reason, fx->fx_rjt_expl);
 684                         }
 685                 } else {
 686                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
 687                             "FLOGI: sid=%x xid=%x. "
 688                             "fct_handle_rcvd_flogi failed. Rejecting.",
 689                             fx->fx_sid, iocbq.iocb.ULPCONTEXT);
 690 
 691                         (void) emlxs_els_reply(port, &iocbq,
 692                             ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
 693                             LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
 694                 }
 695 
 696                 return;
 697         }
 698 
 699         if (save) {
 700                 /* Save FLOGI for later */
 701                 bcopy(fx, &port->fx, sizeof (fct_flogi_xchg_t));
 702                 mutex_exit(&EMLXS_PORT_LOCK);
 703                 return;
 704         }
 705 
 706 reject_it:
 707 
 708         mutex_exit(&EMLXS_PORT_LOCK);
 709 
 710         if (port->fct_flags & FCT_STATE_LINK_UP) {
 711                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
 712                     "FLOGI: sid=%x xid=%x. Stale. Rejecting.",
 713                     fx->fx_sid, fx->rsvd2);
 714 
 715                 bzero((uint8_t *)&iocbq, sizeof (IOCBQ));
 716                 iocbq.iocb.un.elsreq.remoteID = fx->fx_sid;
 717                 iocbq.iocb.un.elsreq.myID = fx->fx_did;
 718                 iocbq.iocb.ULPCONTEXT = fx->rsvd2;
 719 
 720                 (void) emlxs_els_reply(port, &iocbq,
 721                     ELS_CMD_LS_RJT, ELS_CMD_FLOGI,
 722                     LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
 723 
 724                 /* If we have an FLOGI saved, try sending it now */
 725                 if (port->fx.fx_op) {
 726                         fx = NULL;
 727                         goto begin;
 728                 }
 729 
 730         } else {
 731                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
 732                     "FLOGI: sid=%x xid=%x. Link down. "
 733                     "Dropping.",
 734                     fx->fx_sid, fx->rsvd2);
 735         }
 736 
 737         return;
 738 
 739 } /* emlxs_fct_handle_unsol_flogi() */
 740 
 741 
 742 /* ARGSUSED */
 743 static void
 744 emlxs_fct_unsol_flush_thread(emlxs_hba_t *hba, void *arg1, void *arg2)
 745 {
 746         emlxs_port_t *port = (emlxs_port_t *)arg1;
 747 
 748         emlxs_fct_unsol_flush(port);
 749         return;
 750 
 751 } /* emlxs_fct_unsol_flush_thread() */
 752 
 753 
 754 /* This is called at port online and offline */
 755 static void
 756 emlxs_fct_unsol_flush(emlxs_port_t *port)
 757 {
 758         emlxs_hba_t *hba = HBA;
 759         emlxs_buf_t *cmd_sbp;
 760         emlxs_buf_t *next;
 761         fct_cmd_t *fct_cmd;
 762         fct_status_t rval;
 763         uint32_t cmd_code;
 764 
 765         if (!port->fct_port) {
 766                 return;
 767         }
 768 
 769         /* First handle any pending FLOGI */
 770         emlxs_fct_handle_unsol_flogi(port, NULL, 0);
 771 
 772         if ((port->fct_flags & FCT_STATE_LINK_UP_ACKED) &&
 773             !(port->fct_flags & FCT_STATE_FLOGI_CMPL)) {
 774                 return;
 775         }
 776 
 777         /* Wait queue */
 778         mutex_enter(&EMLXS_PORT_LOCK);
 779         cmd_sbp = port->fct_wait_head;
 780         port->fct_wait_head = NULL;
 781         port->fct_wait_tail = NULL;
 782         mutex_exit(&EMLXS_PORT_LOCK);
 783 
 784         /*
 785          * Next process any outstanding ELS commands. It doesn't
 786          * matter if the Link is up or not, always post them to FCT.
 787          */
 788         while (cmd_sbp) {
 789                 next = cmd_sbp->next;
 790                 fct_cmd = cmd_sbp->fct_cmd;
 791 
 792                 cmd_code = (fct_cmd->cmd_oxid << ELS_CMD_SHIFT);
 793 
 794                 /* Reacquire ownership of the fct_cmd */
 795                 rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
 796                 if (rval) {
 797                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 798                             "fct_unsol_flush: %s: sid=%x xid=%x "
 799                             "Unable to reacquire fct_cmd.",
 800                             emlxs_elscmd_xlate(cmd_code),
 801                             fct_cmd->cmd_rxid, fct_cmd->cmd_rportid);
 802 
 803                         cmd_sbp = next;
 804                         continue;
 805                 }
 806                 /* mutex_enter(&cmd_sbp->fct_mtx); */
 807 
 808                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
 809                     "Posting %s: sid=%x xid=%x %p",
 810                     emlxs_elscmd_xlate(cmd_code),
 811                     fct_cmd->cmd_rportid, fct_cmd->cmd_rxid,
 812                     fct_cmd);
 813 
 814                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
 815                 /* mutex_exit(&cmd_sbp->fct_mtx); */
 816 
 817 #ifdef FCT_API_TRACE
 818                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
 819                     "fct_post_rcvd_cmd:2 %p:%p portid x%x", fct_cmd, cmd_sbp,
 820                     fct_cmd->cmd_lportid);
 821 #endif /* FCT_API_TRACE */
 822 
 823                 MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
 824 
 825                 cmd_sbp = next;
 826 
 827         }       /* while () */
 828 
 829         return;
 830 
 831 } /* emlxs_fct_unsol_flush() */
 832 
 833 
 834 int
 835 emlxs_is_digit(uint8_t chr)
 836 {
 837         if ((chr >= '0') && (chr <= '9')) {
 838                 return (1);
 839         }
 840 
 841         return (0);
 842 
 843 } /* emlxs_is_digit */
 844 
 845 
 846 /*
 847  *   Convert an ASCII decimal numeric string to integer.
 848  *   Negation character '-' is not handled.
 849  */
 850 static uint32_t
 851 emlxs_str_atoi(uint8_t *string)
 852 {
 853         uint32_t num = 0;
 854         int i = 0;
 855 
 856         while (string[i]) {
 857                 if (!emlxs_is_digit(string[i])) {
 858                         return (num);
 859                 }
 860 
 861                 num = num * 10 + (string[i++] - '0');
 862         }
 863 
 864         return (num);
 865 
 866 } /* emlxs_str_atoi() */
 867 
 868 
 869 extern uint32_t
 870 emlxs_fct_init(emlxs_hba_t *hba)
 871 {
 872         emlxs_port_t *port = &PPORT;
 873 
 874         /* Check if COMSTAR is present */
 875         if (((void *)MODSYM(stmf_alloc) == NULL) ||
 876             ((void *)MODSYM(fct_alloc) == NULL)) {
 877                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_attach_debug_msg,
 878                     "Comstar not present.");
 879                 return (1);
 880         }
 881 
 882         return (0);
 883 
 884 } /* emlxs_fct_init() */
 885 
 886 
 887 extern void
 888 emlxs_fct_attach(emlxs_hba_t *hba)
 889 {
 890         emlxs_port_t *port = &PPORT;
 891         uint32_t vpi;
 892 
 893         if (!(port->flag & EMLXS_TGT_ENABLED)) {
 894                 return;
 895         }
 896 
 897         /* Bind the physical port */
 898         emlxs_fct_bind_port(port);
 899 
 900         /* Bind virtual ports */
 901         if (hba->flag & FC_NPIV_ENABLED) {
 902                 for (vpi = 1; vpi <= hba->vpi_high; vpi++) {
 903                         port = &VPORT(vpi);
 904 
 905                         if (!(port->flag & EMLXS_PORT_ENABLED)) {
 906                                 continue;
 907                         }
 908 
 909                         emlxs_fct_bind_port(port);
 910                 }
 911         }
 912 
 913         return;
 914 
 915 } /* emlxs_fct_attach() */
 916 
 917 
 918 extern void
 919 emlxs_fct_detach(emlxs_hba_t *hba)
 920 {
 921         uint32_t i;
 922         emlxs_port_t *vport;
 923 
 924         for (i = 0; i < MAX_VPORTS; i++) {
 925                 vport = &VPORT(i);
 926 
 927                 if (!(vport->flag & EMLXS_PORT_ENABLED)) {
 928                         continue;
 929                 }
 930 
 931                 emlxs_fct_unbind_port(vport);
 932         }
 933 
 934 #ifdef FCT_IO_TRACE
 935 {
 936         emlxs_port_t *port = &PPORT;
 937 
 938         mutex_destroy(&port->iotrace_mtx);
 939         if (port->iotrace) {
 940                 kmem_free(port->iotrace,
 941                     (port->iotrace_cnt * sizeof (emlxs_iotrace_t)));
 942         }
 943         port->iotrace = NULL;
 944 }
 945 #endif /* FCT_IO_TRACE */
 946 
 947         return;
 948 
 949 } /* emlxs_fct_detach() */
 950 
 951 
 952 extern void
 953 emlxs_fct_unbind_port(emlxs_port_t *port)
 954 {
 955         emlxs_hba_t *hba = HBA;
 956         char node_name[32];
 957 
 958         mutex_enter(&EMLXS_PORT_LOCK);
 959 
 960         if (!(port->flag & EMLXS_TGT_BOUND)) {
 961                 mutex_exit(&EMLXS_PORT_LOCK);
 962                 return;
 963         }
 964 
 965         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
 966             "fct_unbind_port: port=%d", port->vpi);
 967 
 968         /* Destroy & flush all port nodes, if they exist */
 969         if (port->node_count) {
 970                 (void) EMLXS_SLI_UNREG_NODE(port, NULL, NULL, NULL, NULL);
 971         }
 972 
 973         port->flag &= ~EMLXS_TGT_BOUND;
 974         port->flag &= ~EMLXS_TGT_ENABLED;
 975         hba->num_of_ports--;
 976         mutex_exit(&EMLXS_PORT_LOCK);
 977 
 978         if (port->fct_port) {
 979                 emlxs_fct_link_down(port);
 980                 emlxs_fct_unsol_flush(port);
 981 
 982 #ifdef FCT_API_TRACE
 983                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
 984                     "fct_deregister_local_port %p", port->fct_port);
 985 #endif /* FCT_API_TRACE */
 986                 MODSYM(fct_deregister_local_port) (port->fct_port);
 987 
 988                 if (port->fct_port->port_fds) {
 989 #ifdef FCT_API_TRACE
 990                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
 991                             "fct_free:3 %p", port->fct_port->port_fds);
 992 #endif /* FCT_API_TRACE */
 993                         MODSYM(fct_free) (port->fct_port->port_fds);
 994                         port->fct_port->port_fds = NULL;
 995                 }
 996 #ifdef FCT_API_TRACE
 997                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
 998                     "fct_free:4 %p", port->fct_port);
 999 #endif /* FCT_API_TRACE */
1000                 MODSYM(fct_free) (port->fct_port);
1001                 port->fct_port = NULL;
1002                 port->fct_flags = 0;
1003         }
1004 
1005         if (port->port_provider) {
1006 #ifdef FCT_API_TRACE
1007                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1008                     "stmf_deregister_port_provider:1 %p",
1009                     port->port_provider);
1010 #endif /* FCT_API_TRACE */
1011                 MODSYM(stmf_deregister_port_provider) (port->port_provider);
1012 
1013 #ifdef FCT_API_TRACE
1014                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1015                     "stmf_free:1 %p", port->port_provider);
1016 #endif /* FCT_API_TRACE */
1017                 MODSYM(stmf_free) (port->port_provider);
1018                 port->port_provider = NULL;
1019         }
1020 
1021         if (port->fct_memseg) {
1022                 emlxs_fct_dmem_fini(port);
1023         }
1024 
1025         (void) snprintf(node_name, sizeof (node_name), "%d,%d:SFCT",
1026             hba->ddiinst, port->vpi);
1027         (void) ddi_remove_minor_node(hba->dip, node_name);
1028 
1029         return;
1030 
1031 } /* emlxs_fct_unbind_port() */
1032 
1033 
1034 extern void
1035 emlxs_fct_bind_port(emlxs_port_t *port)
1036 {
1037         emlxs_hba_t *hba = HBA;
1038         fct_local_port_t *fct_port;
1039         uint32_t flag = 0;
1040         emlxs_config_t *cfg = &CFG;
1041         fct_dbuf_store_t *fds;
1042         char node_name[32];
1043         uint8_t *bptr;
1044 
1045         if (!(port->flag & EMLXS_TGT_ENABLED)) {
1046                 return;
1047         }
1048 
1049         mutex_enter(&EMLXS_PORT_LOCK);
1050 
1051         if (port->flag & EMLXS_TGT_BOUND) {
1052                 mutex_exit(&EMLXS_PORT_LOCK);
1053                 return;
1054         }
1055 
1056         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1057             "fct_bind_port: port=%d", port->vpi);
1058 
1059         /* Perform generic port initialization */
1060         emlxs_port_init(port);
1061 
1062         if (port->vpi == 0) {
1063                 (void) snprintf(port->cfd_name, sizeof (port->cfd_name),
1064                     "%s%d", DRIVER_NAME, hba->ddiinst);
1065         } else {
1066                 (void) snprintf(port->cfd_name, sizeof (port->cfd_name),
1067                     "%s%d.%d", DRIVER_NAME, hba->ddiinst, port->vpi);
1068         }
1069 
1070         if (emlxs_fct_dmem_init(port) != FCT_SUCCESS) {
1071                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1072                     "fct_bind_port: Unable to allocate fct memory.");
1073                 goto failed;
1074         }
1075         flag |= 0x00000001;
1076 
1077         port->port_provider =
1078             (stmf_port_provider_t *)
1079             MODSYM(stmf_alloc) (STMF_STRUCT_PORT_PROVIDER, 0, 0);
1080 #ifdef FCT_API_TRACE
1081         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1082             "stmf_alloc port_provider %p", port->port_provider);
1083 #endif /* FCT_API_TRACE */
1084 
1085         if (port->port_provider == NULL) {
1086                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1087                     "fct_bind_port: Unable to allocate port provider.");
1088                 goto failed;
1089         }
1090         flag |= 0x00000002;
1091 
1092         port->port_provider->pp_portif_rev = PORTIF_REV_1;
1093         port->port_provider->pp_name = port->cfd_name;
1094         port->port_provider->pp_provider_private = port;
1095 
1096 #ifdef FCT_API_TRACE
1097         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1098             "stmf_register_port_provider %p", port->port_provider);
1099 #endif /* FCT_API_TRACE */
1100         /* register port provider with framework */
1101         if (MODSYM(stmf_register_port_provider) (port->port_provider) !=
1102             STMF_SUCCESS) {
1103                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1104                     "fct_bind_port: Unable to register port provider.");
1105                 goto failed;
1106         }
1107         flag |= 0x00000004;
1108 
1109         port->fct_port =
1110             (fct_local_port_t *)MODSYM(fct_alloc) (FCT_STRUCT_LOCAL_PORT, 0,
1111             0);
1112 #ifdef FCT_API_TRACE
1113         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1114             "fct_alloc fct_port %p", port->fct_port);
1115 #endif /* FCT_API_TRACE */
1116 
1117         if (port->fct_port == NULL) {
1118                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1119                     "fct_bind_port: Unable to allocate fct port.");
1120                 goto failed;
1121         }
1122         flag |= 0x00000008;
1123 
1124         port->fct_port->port_fds =
1125             (fct_dbuf_store_t *)MODSYM(fct_alloc) (FCT_STRUCT_DBUF_STORE, 0,
1126             0);
1127 #ifdef FCT_API_TRACE
1128         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1129             "fct_alloc port_fds %p", port->fct_port->port_fds);
1130 #endif /* FCT_API_TRACE */
1131 
1132         if (port->fct_port->port_fds == NULL) {
1133                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1134                     "fct_bind_port: Unable to allocate dbuf store.");
1135                 goto failed;
1136         }
1137         flag |= 0x00000010;
1138 
1139         (void) snprintf(node_name, sizeof (node_name), "%d,%d:SFCT",
1140             hba->ddiinst, port->vpi);
1141         if (ddi_create_minor_node(hba->dip, node_name, S_IFCHR, hba->ddiinst,
1142             NULL, 0) == DDI_FAILURE) {
1143                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1144                     "Unable to create SFCT device node.");
1145                 goto failed;
1146         }
1147         flag |= 0x00000020;
1148 
1149         /* Intialize */
1150         fct_port = port->fct_port;
1151         fct_port->port_fca_version = FCT_FCA_MODREV_1;
1152         fct_port->port_fca_private = port;
1153         fct_port->port_fca_abort_timeout = 30 * 1000;        /* 30 seconds */
1154 
1155         bcopy((uint8_t *)&port->wwpn, (uint8_t *)fct_port->port_pwwn, 8);
1156         bcopy((uint8_t *)&port->wwnn, (uint8_t *)fct_port->port_nwwn, 8);
1157 
1158         bptr = (uint8_t *)&port->wwnn;
1159         (void) snprintf(fct_port->port_nwwn_str, FC_WWN_BUFLEN,
1160             "%02x%02x%02x%02x%02x%02x%02x%02x",
1161             bptr[0], bptr[1], bptr[2], bptr[3],
1162             bptr[4], bptr[5], bptr[6], bptr[7]);
1163 
1164         bptr = (uint8_t *)&port->wwpn;
1165         (void) snprintf(fct_port->port_pwwn_str, FC_WWN_BUFLEN,
1166             "%02x%02x%02x%02x%02x%02x%02x%02x",
1167             bptr[0], bptr[1], bptr[2], bptr[3],
1168             bptr[4], bptr[5], bptr[6], bptr[7]);
1169 
1170         fct_port->port_sym_node_name = port->snn;
1171         fct_port->port_sym_port_name = port->spn;
1172         fct_port->port_hard_address = cfg[CFG_ASSIGN_ALPA].current;
1173         fct_port->port_default_alias = port->cfd_name;
1174         fct_port->port_pp = port->port_provider;
1175         fct_port->port_max_logins = hba->max_nodes + EMLXS_FCT_NUM_ELS_ONLY;
1176 
1177         if (cfg[CFG_FCT_QDEPTH].current &&
1178             (cfg[CFG_FCT_QDEPTH].current < hba->io_throttle)) {
1179                 fct_port->port_max_xchges = cfg[CFG_FCT_QDEPTH].current;
1180         } else {
1181                 fct_port->port_max_xchges = hba->io_throttle;
1182         }
1183 
1184         fct_port->port_fca_fcp_cmd_size = sizeof (emlxs_buf_t);
1185         fct_port->port_fca_rp_private_size = sizeof (uintptr_t);
1186         fct_port->port_fca_sol_els_private_size = sizeof (emlxs_buf_t);
1187         fct_port->port_fca_sol_ct_private_size = sizeof (emlxs_buf_t);
1188         fct_port->port_get_link_info = emlxs_fct_get_link_info;
1189         fct_port->port_register_remote_port = emlxs_fct_register_remote_port;
1190         fct_port->port_deregister_remote_port =
1191             emlxs_fct_deregister_remote_port;
1192         fct_port->port_send_cmd = emlxs_fct_send_cmd;
1193         fct_port->port_xfer_scsi_data = emlxs_fct_send_fcp_data;
1194         fct_port->port_send_cmd_response = emlxs_fct_send_cmd_rsp;
1195         fct_port->port_abort_cmd = emlxs_fct_abort;
1196         fct_port->port_ctl = emlxs_fct_ctl;
1197         fct_port->port_flogi_xchg = emlxs_fct_flogi_xchg;
1198         fct_port->port_populate_hba_details = emlxs_fct_populate_hba_details;
1199         fct_port->port_info = emlxs_fct_port_info;
1200 
1201         fds = port->fct_port->port_fds;
1202         fds->fds_fca_private = port;
1203         fds->fds_alloc_data_buf = emlxs_fct_dbuf_alloc;
1204         fds->fds_free_data_buf = emlxs_fct_dbuf_free;
1205 
1206         /* Scatter gather list support */
1207 /*      fds->fds_setup_dbuf = ; */
1208 /*      fds->fds_teardown_dbuf = ; */
1209 /*      fds->fds_max_sgl_xfer_len = ; */
1210 /*      fds->fds_copy_threshold = ; */
1211 
1212 #ifdef FCT_API_TRACE
1213         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1214             "fct_register_local_port %p", fct_port);
1215 #endif /* FCT_API_TRACE */
1216         /* register this local port with the fct module */
1217         if (MODSYM(fct_register_local_port) (fct_port) != FCT_SUCCESS) {
1218                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1219                     "fct_bind_port: Unable to register fct port.");
1220                 goto failed;
1221         }
1222 
1223         /* Set the bound flag */
1224         port->flag |= EMLXS_TGT_BOUND;
1225         hba->num_of_ports++;
1226 
1227         mutex_exit(&EMLXS_PORT_LOCK);
1228 
1229         return;
1230 
1231 failed:
1232 
1233         if (flag & 0x20) {
1234                 (void) ddi_remove_minor_node(hba->dip, node_name);
1235         }
1236 
1237         if (flag & 0x10) {
1238 #ifdef FCT_API_TRACE
1239                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1240                     "fct_free:5 %p", port->fct_port->port_fds);
1241 #endif /* FCT_API_TRACE */
1242                 MODSYM(fct_free) (port->fct_port->port_fds);
1243                 port->fct_port->port_fds = NULL;
1244         }
1245 
1246         if (flag & 0x8) {
1247 #ifdef FCT_API_TRACE
1248                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1249                     "fct_free:6 %p", port->fct_port);
1250 #endif /* FCT_API_TRACE */
1251                 MODSYM(fct_free) (port->fct_port);
1252                 port->fct_port = NULL;
1253                 port->fct_flags = 0;
1254         }
1255 
1256         if (flag & 0x4) {
1257 #ifdef FCT_API_TRACE
1258                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1259                     "stmf_deregister_port_provider:2 %p",
1260                     port->port_provider);
1261 #endif /* FCT_API_TRACE */
1262                 MODSYM(stmf_deregister_port_provider) (port->port_provider);
1263         }
1264 
1265         if (flag & 0x2) {
1266 #ifdef FCT_API_TRACE
1267                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1268                     "stmf_free:2 %p", port->port_provider);
1269 #endif /* FCT_API_TRACE */
1270                 MODSYM(stmf_free) (port->port_provider);
1271                 port->port_provider = NULL;
1272         }
1273 
1274         if (flag & 0x1) {
1275                 emlxs_fct_dmem_fini(port);
1276         }
1277 
1278         port->flag &= ~EMLXS_TGT_ENABLED;
1279 
1280         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1281             "Target mode disabled.");
1282 
1283         mutex_exit(&EMLXS_PORT_LOCK);
1284 
1285         return;
1286 
1287 } /* emlxs_fct_bind_port() */
1288 
1289 
1290 /* COMSTAR ENTER POINT */
1291 /*ARGSUSED*/
1292 static fct_status_t
1293 emlxs_fct_port_info(uint32_t cmd, fct_local_port_t *fct_port, void *arg,
1294     uint8_t *buffer, uint32_t *size)
1295 {
1296         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1297         emlxs_hba_t *hba = HBA;
1298         fct_status_t rval = FCT_SUCCESS;
1299         fct_port_link_status_t *link_status;
1300         MAILBOX *mb;
1301         MAILBOXQ *mbq;
1302 
1303         switch (cmd) {
1304         case FC_TGT_PORT_RLS:
1305                 bzero(buffer, *size);
1306 
1307                 if ((*size) < sizeof (fct_port_link_status_t)) {
1308                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1309                             "FC_TGT_PORT_RLS: Buffer too small. %d < %d",
1310                             *size, sizeof (fct_port_link_status_t));
1311 
1312                         rval = FCT_FAILURE;
1313                         break;
1314                 }
1315 
1316                 if ((mbq = (MAILBOXQ *)emlxs_mem_get(hba, MEM_MBOX)) == 0) {
1317                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1318                             "FC_TGT_PORT_RLS: Unable to allocate mailbox.");
1319 
1320                         rval = FCT_ALLOC_FAILURE;
1321                         break;
1322                 }
1323                 mb = (MAILBOX *)mbq;
1324 
1325                 emlxs_mb_read_lnk_stat(hba, mbq);
1326                 if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0)
1327                     != MBX_SUCCESS) {
1328                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1329                             "FC_TGT_PORT_RLS: Unable to send request.");
1330 
1331                         rval = FCT_BUSY;
1332                 } else {
1333                         link_status = (fct_port_link_status_t *)buffer;
1334                         link_status->LinkFailureCount =
1335                             mb->un.varRdLnk.linkFailureCnt;
1336                         link_status->LossOfSyncCount =
1337                             mb->un.varRdLnk.lossSyncCnt;
1338                         link_status->LossOfSignalsCount =
1339                             mb->un.varRdLnk.lossSignalCnt;
1340                         link_status->PrimitiveSeqProtocolErrorCount =
1341                             mb->un.varRdLnk.primSeqErrCnt;
1342                         link_status->InvalidTransmissionWordCount =
1343                             mb->un.varRdLnk.invalidXmitWord;
1344                         link_status->InvalidCRCCount =
1345                             mb->un.varRdLnk.crcCnt;
1346                 }
1347 
1348                 emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
1349                 break;
1350 
1351         default:
1352                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
1353                     "fct_port_info: Invalid request. cmd=%x",
1354                     cmd);
1355 
1356                 rval = FCT_FAILURE;
1357                 break;
1358 
1359         }
1360 
1361         return (rval);
1362 
1363 } /* emlxs_fct_port_info() */
1364 
1365 
1366 /* COMSTAR ENTER POINT */
1367 static void
1368 emlxs_fct_populate_hba_details(fct_local_port_t *fct_port,
1369     fct_port_attrs_t *port_attrs)
1370 {
1371         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1372         emlxs_hba_t *hba = HBA;
1373         emlxs_vpd_t *vpd = &VPD;
1374 
1375         (void) strncpy(port_attrs->manufacturer,
1376             hba->model_info.manufacturer,
1377             (sizeof (port_attrs->manufacturer)-1));
1378         (void) strncpy(port_attrs->serial_number, vpd->serial_num,
1379             (sizeof (port_attrs->serial_number)-1));
1380         (void) strncpy(port_attrs->model, hba->model_info.model,
1381             (sizeof (port_attrs->model)-1));
1382         (void) strncpy(port_attrs->model_description,
1383             hba->model_info.model_desc,
1384             (sizeof (port_attrs->model_description)-1));
1385         (void) snprintf(port_attrs->hardware_version,
1386             (sizeof (port_attrs->hardware_version)-1),
1387             "%x", vpd->biuRev);
1388         (void) snprintf(port_attrs->driver_version,
1389             (sizeof (port_attrs->driver_version)-1),
1390             "%s (%s)", emlxs_version,
1391             emlxs_revision);
1392         (void) strncpy(port_attrs->option_rom_version, vpd->fcode_version,
1393             (sizeof (port_attrs->option_rom_version)-1));
1394         (void) snprintf(port_attrs->firmware_version,
1395             (sizeof (port_attrs->firmware_version)-1),
1396             "%s (%s)", vpd->fw_version,
1397             vpd->fw_label);
1398         (void) strncpy(port_attrs->driver_name, DRIVER_NAME,
1399             (sizeof (port_attrs->driver_name)-1));
1400         port_attrs->vendor_specific_id =
1401             ((hba->model_info.device_id << 16) | PCI_VENDOR_ID_EMULEX);
1402         port_attrs->supported_cos = LE_SWAP32(FC_NS_CLASS3);
1403 
1404         port_attrs->max_frame_size = FF_FRAME_SIZE;
1405 
1406         if (vpd->link_speed & LMT_16GB_CAPABLE) {
1407                 port_attrs->supported_speed |= PORT_SPEED_16G;
1408         }
1409         if (vpd->link_speed & LMT_10GB_CAPABLE) {
1410                 port_attrs->supported_speed |= PORT_SPEED_10G;
1411         }
1412         if (vpd->link_speed & LMT_8GB_CAPABLE) {
1413                 port_attrs->supported_speed |= PORT_SPEED_8G;
1414         }
1415         if (vpd->link_speed & LMT_4GB_CAPABLE) {
1416                 port_attrs->supported_speed |= PORT_SPEED_4G;
1417         }
1418         if (vpd->link_speed & LMT_2GB_CAPABLE) {
1419                 port_attrs->supported_speed |= PORT_SPEED_2G;
1420         }
1421         if (vpd->link_speed & LMT_1GB_CAPABLE) {
1422                 port_attrs->supported_speed |= PORT_SPEED_1G;
1423         }
1424 
1425         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1426             "Port attr: manufacturer       = %s", port_attrs->manufacturer);
1427         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1428             "Port attr: serial_num         = %s", port_attrs->serial_number);
1429         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1430             "Port attr: model              = %s", port_attrs->model);
1431         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1432             "Port attr: model_description  = %s",
1433             port_attrs->model_description);
1434         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1435             "Port attr: hardware_version   = %s",
1436             port_attrs->hardware_version);
1437         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1438             "Port attr: driver_version     = %s", port_attrs->driver_version);
1439         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1440             "Port attr: option_rom_version = %s",
1441             port_attrs->option_rom_version);
1442         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1443             "Port attr: firmware_version   = %s",
1444             port_attrs->firmware_version);
1445         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1446             "Port attr: driver_name        = %s", port_attrs->driver_name);
1447         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1448             "Port attr: vendor_specific_id = 0x%x",
1449             port_attrs->vendor_specific_id);
1450         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1451             "Port attr: supported_cos      = 0x%x",
1452             port_attrs->supported_cos);
1453         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1454             "Port attr: supported_speed    = 0x%x",
1455             port_attrs->supported_speed);
1456         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1457             "Port attr: max_frame_size     = 0x%x",
1458             port_attrs->max_frame_size);
1459 
1460         return;
1461 
1462 } /* emlxs_fct_populate_hba_details() */
1463 
1464 
1465 /* COMSTAR ENTER POINT */
1466 /* ARGSUSED */
1467 static void
1468 emlxs_fct_ctl(fct_local_port_t *fct_port, int cmd, void *arg)
1469 {
1470         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1471         emlxs_hba_t *hba = HBA;
1472         stmf_change_status_t st;
1473         int32_t rval;
1474 
1475         st.st_completion_status = FCT_SUCCESS;
1476         st.st_additional_info = NULL;
1477 
1478         switch (cmd) {
1479         case FCT_CMD_PORT_ONLINE:
1480                 /* If the HBA is offline, we cannot bring the tgtport online */
1481                 if (hba->flag & (FC_OFFLINE_MODE | FC_OFFLINING_MODE)) {
1482                         st.st_completion_status = FCT_FAILURE;
1483                         MODSYM(fct_ctl) (fct_port->port_lport,
1484                             FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1485                         break;
1486                 }
1487 
1488                 if (port->fct_flags & FCT_STATE_PORT_ONLINE) {
1489                         st.st_completion_status = STMF_ALREADY;
1490                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1491                             "STATE: ONLINE chk");
1492                 } else {
1493                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1494                             "STATE: OFFLINE --> ONLINE");
1495 
1496                         port->fct_flags |= FCT_STATE_NOT_ACKED;
1497                         port->fct_flags |= FCT_STATE_PORT_ONLINE;
1498 
1499                         if ((port->vpi == 0) &&
1500                             (port->mode == MODE_TARGET) &&
1501                             (hba->state <= FC_LINK_DOWN)) {
1502                                 /* Try to bring the link up */
1503                                 (void) emlxs_reset_link(hba, 1, 1);
1504                         }
1505 
1506                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1507                             "STATE: ONLINE");
1508                 }
1509 
1510                 MODSYM(fct_ctl) (fct_port->port_lport,
1511                     FCT_CMD_PORT_ONLINE_COMPLETE, &st);
1512                 break;
1513 
1514         case FCT_CMD_PORT_OFFLINE:
1515                 if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
1516                         st.st_completion_status = STMF_ALREADY;
1517                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1518                             "STATE: OFFLINE chk");
1519 
1520                 } else {
1521                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1522                             "STATE: ONLINE --> OFFLINE");
1523 
1524                         /* Take link down and flush */
1525                         emlxs_fct_link_down(port);
1526                         emlxs_fct_unsol_flush(port);
1527 
1528                         /* Declare this port offline now */
1529                         port->fct_flags |= FCT_STATE_NOT_ACKED;
1530                         port->fct_flags &= ~FCT_STATE_PORT_ONLINE;
1531 
1532                         if ((port->vpi == 0) &&
1533                             (port->mode == MODE_TARGET) &&
1534                             !(port->flag & EMLXS_INI_ENABLED)) {
1535                                 /* Take link down and hold it down */
1536                                 (void) emlxs_reset_link(hba, 0, 1);
1537                         }
1538 
1539                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1540                             "STATE: OFFLINE");
1541                 }
1542 
1543                 MODSYM(fct_ctl) (fct_port->port_lport,
1544                     FCT_CMD_PORT_OFFLINE_COMPLETE, &st);
1545 
1546                 break;
1547 
1548         case FCT_ACK_PORT_OFFLINE_COMPLETE:
1549                 port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1550                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1551                     "STATE: OFFLINE ack");
1552                 break;
1553 
1554         case FCT_ACK_PORT_ONLINE_COMPLETE:
1555                 port->fct_flags &= ~FCT_STATE_NOT_ACKED;
1556                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1557                     "STATE: ONLINE ack");
1558                 break;
1559 
1560         case FCT_CMD_FORCE_LIP:
1561                 if (port->mode == MODE_INITIATOR) {
1562                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1563                             "fct_ctl: FCT_CMD_FORCE_LIP.");
1564                         *((fct_status_t *)arg) = FCT_FAILURE;
1565                         break;
1566                 }
1567 
1568                 if (hba->fw_flag & FW_UPDATE_NEEDED) {
1569                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1570                             "fct_ctl: FCT_CMD_FORCE_LIP -> "
1571                             "FCT_CMD_RESET");
1572 
1573                         hba->fw_flag |= FW_UPDATE_KERNEL;
1574 
1575                         /* Reset the adapter */
1576                         rval = emlxs_reset(port, FC_FCA_RESET);
1577                 } else {
1578                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1579                             "fct_ctl: FCT_CMD_FORCE_LIP");
1580 
1581                         /* Reset the link */
1582                         rval = emlxs_reset(port, FC_FCA_LINK_RESET);
1583                 }
1584                 *((fct_status_t *)arg) = (rval == FC_SUCCESS) ? FCT_SUCCESS:
1585                     FCT_FAILURE;
1586                 break;
1587         }
1588 
1589         return;
1590 
1591 } /* emlxs_fct_ctl() */
1592 
1593 
1594 extern int
1595 emlxs_fct_port_shutdown(emlxs_port_t *port)
1596 {
1597         fct_local_port_t *fct_port;
1598         int i;
1599 
1600         fct_port = port->fct_port;
1601         if (!fct_port) {
1602                 return (0);
1603         }
1604 
1605         port->fct_flags |= FCT_STATE_NOT_ACKED;
1606 
1607         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg, "fct_port_shutdown");
1608         MODSYM(fct_port_shutdown) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1609             DRIVER_NAME" shutdown");
1610 
1611         i = 0;
1612         while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1613                 i++;
1614                 if (i > 300) {       /* 30 seconds */
1615                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1616                             "fct_port_shutdown failed to ACK");
1617                         break;
1618                 }
1619                 delay(drv_usectohz(100000));    /* 100 msec */
1620         }
1621         return (1);
1622 }
1623 
1624 
1625 extern int
1626 emlxs_fct_port_initialize(emlxs_port_t *port)
1627 {
1628         fct_local_port_t *fct_port;
1629         int i;
1630 
1631         fct_port = port->fct_port;
1632         if (!fct_port) {
1633                 return (0);
1634         }
1635 
1636         port->fct_flags |= FCT_STATE_NOT_ACKED;
1637 
1638         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1639             "fct_port_initialize");
1640         MODSYM(fct_port_initialize) (fct_port, STMF_RFLAG_STAY_OFFLINED,
1641             DRIVER_NAME" initialize");
1642 
1643         i = 0;
1644         while (port->fct_flags & FCT_STATE_NOT_ACKED) {
1645                 i++;
1646                 if (i > 300) {       /* 30 seconds */
1647                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1648                             "fct_port_initialize failed to ACK");
1649                         break;
1650                 }
1651                 delay(drv_usectohz(100000));    /* 100 msec */
1652         }
1653         return (1);
1654 }
1655 
1656 
1657 /* COMSTAR ENTER POINT */
1658 static fct_status_t
1659 emlxs_fct_send_cmd(fct_cmd_t *fct_cmd)
1660 {
1661         emlxs_port_t *port;
1662 
1663         port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1664 
1665 #ifdef FCT_API_TRACE
1666         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1667             "fct_send_cmd %p:%p  x%x", fct_cmd,
1668             fct_cmd->cmd_fca_private, fct_cmd->cmd_type);
1669 #endif /* FCT_API_TRACE */
1670 
1671         switch (fct_cmd->cmd_type) {
1672         case FCT_CMD_SOL_ELS:
1673 
1674                 return (emlxs_fct_send_els_cmd(fct_cmd));
1675 
1676         case FCT_CMD_SOL_CT:
1677 
1678                 return (emlxs_fct_send_ct_cmd(fct_cmd));
1679 
1680         default:
1681 
1682                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1683                     "fct_send_cmd: Invalid cmd type found. type=%x",
1684                     fct_cmd->cmd_type);
1685 
1686                 return (FCT_FAILURE);
1687         }
1688 
1689 } /* emlxs_fct_send_cmd() */
1690 
1691 
1692 /* COMSTAR ENTER POINT */
1693 static fct_status_t
1694 emlxs_fct_send_cmd_rsp(fct_cmd_t *fct_cmd, uint32_t ioflags)
1695 {
1696         emlxs_port_t *port;
1697         emlxs_buf_t *cmd_sbp;
1698         fct_status_t rval;
1699         IOCBQ *iocbq;
1700         IOCB *iocb;
1701         uint32_t status;
1702 
1703         port = (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
1704 
1705         rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_CMD_RSP);
1706         if (rval) {
1707                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1708                     "fct_send_cmd_rsp: "
1709                     "Unable to accept fct_cmd. type=%x",
1710                     fct_cmd->cmd_type);
1711 
1712                 return (rval);
1713         }
1714         /* mutex_enter(&cmd_sbp->fct_mtx); */
1715 
1716         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
1717         iocbq = &cmd_sbp->iocbq;
1718         iocbq->sbp = cmd_sbp;
1719         iocb = &iocbq->iocb;
1720         status = iocb->ULPSTATUS;
1721 
1722 #ifdef FCT_API_TRACE
1723         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1724             "fct_send_cmd_rsp %p:%p x%x, %x, %x",
1725             fct_cmd, cmd_sbp, fct_cmd->cmd_type, iocb->ULPCT, status);
1726 #endif /* FCT_API_TRACE */
1727 
1728         switch (fct_cmd->cmd_type) {
1729         case FCT_CMD_FCP_XCHG:
1730 
1731                 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1732                         goto failure;
1733                 }
1734 
1735                 if ((iocb->ULPCT == 0x1) && (status == 0)) {
1736 
1737                         /* Firmware already sent out resp */
1738                         cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
1739 
1740                         TGTPORTSTAT.FctOutstandingIO--;
1741 
1742                         emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
1743                         /* mutex_exit(&cmd_sbp->fct_mtx); */
1744 
1745 #ifdef FCT_API_TRACE
1746                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1747                             "fct_send_response_done:4 %p: x%x",
1748                             fct_cmd, fct_cmd->cmd_comp_status);
1749 
1750 #endif /* FCT_API_TRACE */
1751 
1752                         MODSYM(fct_send_response_done) (fct_cmd,
1753                             fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
1754 
1755                         return (FCT_SUCCESS);
1756                 }
1757 
1758                 rval =  emlxs_fct_send_fcp_status(fct_cmd);
1759                 if (rval == FCT_NOT_FOUND) {
1760                         goto failure;
1761                 }
1762                 /* mutex_exit(&cmd_sbp->fct_mtx); */
1763 
1764                 return (rval);
1765 
1766         case FCT_CMD_RCVD_ELS:
1767 
1768                 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1769                         goto failure;
1770                 }
1771 
1772                 rval =  emlxs_fct_send_els_rsp(fct_cmd);
1773                 /* mutex_exit(&cmd_sbp->fct_mtx); */
1774 
1775                 return (rval);
1776 
1777         default:
1778 
1779                 if (ioflags & FCT_IOF_FORCE_FCA_DONE) {
1780                         fct_cmd->cmd_handle = 0;
1781                 }
1782 
1783                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1784                     "fct_send_cmd_rsp: Invalid cmd type found. type=%x",
1785                     fct_cmd->cmd_type);
1786 
1787                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1788                 /* mutex_exit(&cmd_sbp->fct_mtx); */
1789 
1790                 return (FCT_FAILURE);
1791         }
1792 
1793 failure:
1794 
1795         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1796             "fct_send_cmd_rsp: "
1797             "Unable to handle FCT_IOF_FORCE_FCA_DONE. type=%x",
1798             fct_cmd->cmd_type);
1799 
1800         emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
1801         /* mutex_exit(&cmd_sbp->fct_mtx); */
1802 
1803         return (FCT_FAILURE);
1804 
1805 } /* emlxs_fct_send_cmd_rsp() */
1806 
1807 
1808 /* COMSTAR ENTER POINT */
1809 static fct_status_t
1810 emlxs_fct_flogi_xchg(struct fct_local_port *fct_port, struct fct_flogi_xchg *fx)
1811 {
1812         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1813         emlxs_hba_t *hba = HBA;
1814         uint32_t size;
1815         fc_packet_t *pkt = NULL;
1816         ELS_PKT *els;
1817         fct_status_t rval = FCT_SUCCESS;
1818 
1819 #ifdef FCT_API_TRACE
1820         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1821             "fct_flogi_xchg: Sending FLOGI: %p", fct_port);
1822 #else
1823         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1824             "fct_flogi_xchg: Sending FLOGI.");
1825 #endif /* FCT_API_TRACE */
1826 
1827         if (hba->state <= FC_LINK_DOWN) {
1828                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1829                     "fct_flogi_xchg: FLOGI failed. Link down.");
1830                 rval = FCT_FAILURE;
1831                 goto done;
1832         }
1833 
1834         /* Use this entry point as the link up acknowledgment */
1835         mutex_enter(&EMLXS_PORT_LOCK);
1836         port->fct_flags |= FCT_STATE_LINK_UP_ACKED;
1837         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1838             "fct_link_up acked.");
1839         mutex_exit(&EMLXS_PORT_LOCK);
1840 
1841         /* First handle any pending FLOGI's */
1842         emlxs_fct_handle_unsol_flogi(port, NULL, 0);
1843 
1844         size = sizeof (SERV_PARM) + 4;
1845 
1846         if (!(pkt = emlxs_pkt_alloc(port, size, size, 0, KM_NOSLEEP))) {
1847                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1848                     "fct_flogi_xchg: FLOGI failed. "
1849                     "Unable allocate packet.");
1850                 rval = FCT_FAILURE;
1851                 goto done;
1852         }
1853 
1854         /* Make this a polled IO */
1855         pkt->pkt_tran_flags &= ~FC_TRAN_INTR;
1856         pkt->pkt_tran_flags |= FC_TRAN_NO_INTR;
1857         pkt->pkt_comp = NULL;
1858 
1859         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
1860         pkt->pkt_timeout = fx->fx_sec_timeout;
1861 
1862         /* Build the fc header */
1863         pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fx->fx_did);
1864         pkt->pkt_cmd_fhdr.r_ctl =
1865             R_CTL_EXTENDED_SVC | R_CTL_SOLICITED_CONTROL;
1866         pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(fx->fx_sid);
1867         pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
1868         pkt->pkt_cmd_fhdr.f_ctl = F_CTL_FIRST_SEQ | F_CTL_SEQ_INITIATIVE;
1869         pkt->pkt_cmd_fhdr.seq_id = 0;
1870         pkt->pkt_cmd_fhdr.df_ctl = 0;
1871         pkt->pkt_cmd_fhdr.seq_cnt = 0;
1872         pkt->pkt_cmd_fhdr.ox_id = 0xffff;
1873         pkt->pkt_cmd_fhdr.rx_id = 0xffff;
1874         pkt->pkt_cmd_fhdr.ro = 0;
1875 
1876         /* Build the command */
1877         /* Service paramters will be added automatically later by the driver */
1878         els = (ELS_PKT *)pkt->pkt_cmd;
1879         els->elsCode = 0x04; /* FLOGI */
1880 
1881         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
1882                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1883                     "fct_flogi_xchg: FLOGI failed. "
1884                     "Unable to send packet.");
1885 
1886                 rval = FCT_FAILURE;
1887                 goto done;
1888         }
1889 
1890         if ((pkt->pkt_state != FC_PKT_SUCCESS) &&
1891             (pkt->pkt_state != FC_PKT_LS_RJT)) {
1892                 if (pkt->pkt_state == FC_PKT_TIMEOUT) {
1893                         rval = FCT_TIMEOUT;
1894                 } else if ((pkt->pkt_state == FC_PKT_LOCAL_RJT) &&
1895                     (pkt->pkt_reason == FC_REASON_FCAL_OPN_FAIL)) {
1896                         rval = FCT_NOT_FOUND;
1897                 } else {
1898                         rval = FCT_FAILURE;
1899                 }
1900 
1901                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1902                     "fct_flogi_xchg: FLOGI failed. state=%x reason=%x "
1903                     "rval=%llx", pkt->pkt_state, pkt->pkt_reason, rval);
1904 
1905                 goto done;
1906         }
1907 
1908         if (pkt->pkt_state == FC_PKT_LS_RJT) {
1909                 fx->fx_op = ELS_OP_LSRJT;
1910                 fx->fx_rjt_reason = pkt->pkt_reason;
1911                 fx->fx_rjt_expl = pkt->pkt_expln;
1912         } else {        /* FC_PKT_SUCCESS */
1913 
1914                 fx->fx_op = ELS_OP_ACC;
1915                 fx->fx_sid = FABRIC_DID;
1916                 fx->fx_did = port->did;
1917 
1918                 els = (ELS_PKT *)pkt->pkt_resp;
1919                 bcopy((caddr_t)&els->un.logi.nodeName,
1920                     (caddr_t)fx->fx_nwwn, 8);
1921                 bcopy((caddr_t)&els->un.logi.portName,
1922                     (caddr_t)fx->fx_pwwn, 8);
1923                 fx->fx_fport = els->un.logi.cmn.fPort;
1924         }
1925 
1926 done:
1927         if (pkt) {
1928                 emlxs_pkt_free(pkt);
1929         }
1930 
1931         if ((rval == FCT_SUCCESS) || (rval == FCT_NOT_FOUND)) {
1932 
1933                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
1934                     "fct_flogi_xchg: FCT_STATE_FLOGI_CMPL.  rval=%s",
1935                     ((rval == FCT_SUCCESS)? "FCT_SUCCESS":"FCT_NOT_FOUND"));
1936 
1937                 mutex_enter(&EMLXS_PORT_LOCK);
1938                 port->fct_flags |= FCT_STATE_FLOGI_CMPL;
1939                 mutex_exit(&EMLXS_PORT_LOCK);
1940 
1941                 /*
1942                  * Flush all unsolicited commands
1943                  * Must use separate thread since
1944                  * this thread must complete first
1945                  */
1946                 emlxs_thread_spawn(hba, emlxs_fct_unsol_flush_thread,
1947                     (void *)port, 0);
1948         }
1949 
1950         return (rval);
1951 
1952 } /* emlxs_fct_flogi_xchg() */
1953 
1954 
1955 /* COMSTAR ENTER POINT */
1956 /* This is called right after we report that link has come online */
1957 static fct_status_t
1958 emlxs_fct_get_link_info(fct_local_port_t *fct_port, fct_link_info_t *link)
1959 {
1960         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
1961         emlxs_hba_t *hba = HBA;
1962 
1963         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
1964             "fct_get_link_info %p: FCT: flg x%x  HBA: ste x%x flg x%x topo x%x",
1965             fct_port, port->fct_flags, hba->state, hba->flag, hba->topology);
1966 
1967         mutex_enter(&EMLXS_PORT_LOCK);
1968 
1969         if (port->mode == MODE_INITIATOR) {
1970                 link->port_topology = PORT_TOPOLOGY_UNKNOWN;
1971                 link->port_speed = PORT_SPEED_UNKNOWN;
1972                 link->portid = 0;
1973 
1974                 mutex_exit(&EMLXS_PORT_LOCK);
1975 
1976                 return (FCT_SUCCESS);
1977         }
1978 
1979         if (!(port->fct_flags & FCT_STATE_LINK_UP) ||
1980             (hba->state < FC_LINK_UP) || (hba->flag & FC_LOOPBACK_MODE)) {
1981                 link->port_topology = PORT_TOPOLOGY_UNKNOWN;
1982                 link->port_speed = PORT_SPEED_UNKNOWN;
1983                 link->portid = 0;
1984 
1985                 mutex_exit(&EMLXS_PORT_LOCK);
1986 
1987                 return (FCT_SUCCESS);
1988         }
1989 
1990         if (hba->topology == TOPOLOGY_LOOP) {
1991                 link->port_topology = PORT_TOPOLOGY_PRIVATE_LOOP;
1992         } else {
1993                 link->port_topology = PORT_TOPOLOGY_PT_TO_PT;
1994         }
1995 
1996         switch (hba->linkspeed) {
1997         case LA_1GHZ_LINK:
1998                 link->port_speed = PORT_SPEED_1G;
1999                 break;
2000         case LA_2GHZ_LINK:
2001                 link->port_speed = PORT_SPEED_2G;
2002                 break;
2003         case LA_4GHZ_LINK:
2004                 link->port_speed = PORT_SPEED_4G;
2005                 break;
2006         case LA_8GHZ_LINK:
2007                 link->port_speed = PORT_SPEED_8G;
2008                 break;
2009         case LA_10GHZ_LINK:
2010                 link->port_speed = PORT_SPEED_10G;
2011                 break;
2012         case LA_16GHZ_LINK:
2013                 link->port_speed = PORT_SPEED_16G;
2014                 break;
2015         case LA_32GHZ_LINK:
2016                 link->port_speed = PORT_SPEED_32G;
2017                 break;
2018         default:
2019                 link->port_speed = PORT_SPEED_UNKNOWN;
2020                 break;
2021         }
2022 
2023         link->portid = port->did;
2024         link->port_no_fct_flogi = 0;
2025         link->port_fca_flogi_done = 0;
2026         link->port_fct_flogi_done = 0;
2027 
2028         mutex_exit(&EMLXS_PORT_LOCK);
2029 
2030         return (FCT_SUCCESS);
2031 
2032 } /* emlxs_fct_get_link_info() */
2033 
2034 
2035 /* COMSTAR ENTER POINT */
2036 static fct_status_t
2037 emlxs_fct_register_remote_port(fct_local_port_t *fct_port,
2038     fct_remote_port_t *remote_port, fct_cmd_t *fct_cmd)
2039 {
2040         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2041         emlxs_hba_t *hba = HBA;
2042         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2043         clock_t timeout;
2044         int32_t pkt_ret;
2045         fct_els_t *els;
2046         SERV_PARM *sp;
2047         emlxs_node_t *ndlp;
2048         SERV_PARM sparam;
2049         uint32_t *iptr;
2050         uint16_t hdl;
2051         uint64_t addr;
2052         fct_status_t rval;
2053         fct_status_t rval2;
2054         uint32_t i;
2055 
2056 #ifdef FCT_API_TRACE
2057         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2058             "fct_register_remote_port %p", fct_port);
2059 #endif /* FCT_API_TRACE */
2060 
2061         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
2062 
2063                 cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd,
2064                     EMLXS_FCT_REG_PENDING);
2065                 /* mutex_enter(&cmd_sbp->fct_mtx); */
2066 
2067                 cmd_sbp->channel = &hba->chan[hba->channel_els];
2068                 cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
2069 
2070         } else {
2071 
2072                 rval = emlxs_fct_cmd_accept(port, fct_cmd,
2073                     EMLXS_FCT_REG_PENDING);
2074                 if (rval) {
2075                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2076                             "fct_register_remote_port: "
2077                             "Unable to accept fct_cmd. lid=%x rid=%x",
2078                             fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2079 
2080                         return (rval);
2081                 }
2082                 /* mutex_enter(&cmd_sbp->fct_mtx); */
2083         }
2084 
2085         cmd_sbp->fct_flags &= ~EMLXS_FCT_REGISTERED;
2086         cmd_sbp->node = emlxs_node_find_did(port, fct_cmd->cmd_rportid, 1);
2087 
2088         /* Check for unsolicited PLOGI */
2089         if (cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED) {
2090                 els = (fct_els_t *)fct_cmd->cmd_specific;
2091                 sp = (SERV_PARM *)((caddr_t)els->els_req_payload +
2092                     sizeof (uint32_t));
2093 
2094         } else {        /* Solicited PLOGI */
2095 
2096                 sp = &sparam;
2097                 bcopy((caddr_t)&port->sparam, (caddr_t)sp,
2098                     sizeof (SERV_PARM));
2099 
2100                 /*
2101                  * Create temporary WWN's from fct_cmd address
2102                  * This simply allows us to get an RPI from the
2103                  * adapter until we get real service params.
2104                  * The PLOGI ACC reply will trigger a REG_LOGIN
2105                  * update later
2106                  */
2107                 addr = (uint64_t)((unsigned long)fct_cmd);
2108 
2109                 iptr = (uint32_t *)&sp->portName;
2110                 iptr[0] = PADDR_HI(addr);
2111                 iptr[1] = PADDR_LO(addr);
2112 
2113                 iptr = (uint32_t *)&sp->nodeName;
2114                 iptr[0] = PADDR_HI(addr);
2115                 iptr[1] = PADDR_LO(addr);
2116         }
2117 
2118         if (hba->flag & FC_PT_TO_PT) {
2119                 mutex_enter(&EMLXS_PORT_LOCK);
2120                 port->did = fct_cmd->cmd_lportid;
2121                 port->rdid = fct_cmd->cmd_rportid;
2122                 mutex_exit(&EMLXS_PORT_LOCK);
2123 
2124                 /*
2125                  * We already received the remote port's
2126                  * parameters in the FLOGI exchange
2127                  */
2128                 if (!(cmd_sbp->fct_flags & EMLXS_FCT_PLOGI_RECEIVED)) {
2129                         sp = &sparam;
2130                         bcopy((caddr_t)&port->fabric_sparam, (caddr_t)sp,
2131                             sizeof (SERV_PARM));
2132 
2133                         /*
2134                          * Since this is a PLOGI, not a FLOGI, we need
2135                          * to fix up word2 of the CSP accordingly.
2136                          */
2137                         sp->cmn.w2.r_a_tov = port->sparam.cmn.w2.r_a_tov;
2138                 }
2139         }
2140 
2141         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
2142             "fct_register_remote_port: Register lid=%x rid=%x. (%x,%x,%p)",
2143             fct_cmd->cmd_lportid, fct_cmd->cmd_rportid, cmd_sbp->fct_state,
2144             hba->flag, fct_cmd);
2145 
2146         emlxs_fct_cmd_release(port, fct_cmd, 0);
2147         /* mutex_exit(&cmd_sbp->fct_mtx); */
2148 
2149         /* Create a new node */
2150         if (EMLXS_SLI_REG_DID(port, fct_cmd->cmd_rportid, sp, cmd_sbp,
2151             NULL, NULL) != 0) {
2152                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2153                     "fct_register_remote_port: "
2154                     "Reg login failed. lid=%x rid=%x",
2155                     fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2156         } else {
2157 
2158                 /* Wait for completion */
2159                 mutex_enter(&EMLXS_PKT_LOCK);
2160                 timeout = emlxs_timeout(hba, 30);
2161                 pkt_ret = 0;
2162                 while ((pkt_ret != -1) &&
2163                     (cmd_sbp->fct_state == EMLXS_FCT_REG_PENDING) &&
2164                     !(cmd_sbp->fct_flags & EMLXS_FCT_REGISTERED)) {
2165                         pkt_ret = cv_timedwait(&EMLXS_PKT_CV,
2166                             &EMLXS_PKT_LOCK, timeout);
2167                 }
2168                 mutex_exit(&EMLXS_PKT_LOCK);
2169         }
2170 
2171         /* Reacquire ownership of the fct_cmd */
2172         rval2 = emlxs_fct_cmd_acquire(port, fct_cmd,
2173             EMLXS_FCT_REG_COMPLETE);
2174         if (rval2) {
2175                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2176                     "fct_register_remote_port: "
2177                     "Unable to reacquire fct_cmd. lid=%x rid=%x",
2178                     fct_cmd->cmd_lportid, fct_cmd->cmd_rportid);
2179 
2180                 return (rval2);
2181         }
2182         /* mutex_enter(&cmd_sbp->fct_mtx); */
2183 
2184         /* Prepare response */
2185 
2186         ndlp = (emlxs_node_t *)cmd_sbp->node;
2187 
2188         if (ndlp) {
2189                 cmd_sbp->fct_flags |= EMLXS_FCT_REGISTERED;
2190 
2191                 *((emlxs_node_t **)remote_port->rp_fca_private) =
2192                     cmd_sbp->node;
2193 
2194                 hdl = ndlp->nlp_Rpi;
2195                 if (hdl == FABRIC_RPI) {
2196                         if (fct_cmd->cmd_rportid == SCR_DID) {
2197                                 /* The SCR handle is hardcoded */
2198                                 remote_port->rp_handle = hba->max_nodes;
2199                                 port->fct_els_only_bmap |= 1;
2200 
2201                         } else {
2202                                 for (i = 1; i < EMLXS_FCT_NUM_ELS_ONLY; i++) {
2203                                         if (port->fct_els_only_bmap & (1 << i))
2204                                                 continue;
2205                                         /*
2206                                          * Bit is not set, so use this
2207                                          * for the handle
2208                                          */
2209                                         remote_port->rp_handle =
2210                                             hba->max_nodes + i;
2211                                         port->fct_els_only_bmap |= (1 << i);
2212                                         break;
2213                                 }
2214                                 if (i >= EMLXS_FCT_NUM_ELS_ONLY) {
2215                                         remote_port->rp_handle =
2216                                             FCT_HANDLE_NONE;
2217                                 }
2218                         }
2219                 } else {
2220                         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2221                                 hdl = emlxs_sli4_rpi_to_index(hba, hdl);
2222                         }
2223                         remote_port->rp_handle = hdl;
2224                 }
2225 
2226                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2227                     "fct_register_remote_port: lid=%x rid=%x hdl=%x",
2228                     fct_cmd->cmd_lportid, fct_cmd->cmd_rportid,
2229                     remote_port->rp_handle);
2230 
2231                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2232                 /* mutex_exit(&cmd_sbp->fct_mtx); */
2233 
2234                 TGTPORTSTAT.FctPortRegister++;
2235                 return (FCT_SUCCESS);
2236         } else {
2237                 *((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2238 
2239                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2240                     "fct_register_remote_port: failed. lid=%x rid=%x hdl=%x",
2241                     fct_cmd->cmd_lportid, fct_cmd->cmd_rportid,
2242                     remote_port->rp_handle);
2243 
2244                 remote_port->rp_handle = FCT_HANDLE_NONE;
2245 
2246                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2247                 /* mutex_exit(&cmd_sbp->fct_mtx); */
2248 
2249                 TGTPORTSTAT.FctFailedPortRegister++;
2250                 return (FCT_FAILURE);
2251         }
2252 
2253 } /* emlxs_fct_register_remote_port() */
2254 
2255 
2256 /* COMSTAR ENTER POINT */
2257 static fct_status_t
2258 emlxs_fct_deregister_remote_port(fct_local_port_t *fct_port,
2259     fct_remote_port_t *remote_port)
2260 {
2261         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
2262         emlxs_hba_t *hba = HBA;
2263         emlxs_node_t *ndlp;
2264         uint32_t i;
2265 
2266 #ifdef FCT_API_TRACE
2267         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2268             "fct_deregister_remote_port: did=%x hdl=%x",
2269             remote_port->rp_id, remote_port->rp_handle);
2270 #else
2271         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2272             "fct_deregister_remote_port: did=%x hdl=%x",
2273             remote_port->rp_id, remote_port->rp_handle);
2274 #endif /* FCT_API_TRACE */
2275 
2276         if (remote_port->rp_handle >= hba->max_nodes) {
2277                 i = remote_port->rp_handle - hba->max_nodes;
2278                 if ((i < EMLXS_FCT_NUM_ELS_ONLY) &&
2279                     (port->fct_els_only_bmap & (1 << i))) {
2280                         port->fct_els_only_bmap &= ~(1 << i);
2281                 }
2282         }
2283 
2284         ndlp = *((emlxs_node_t **)remote_port->rp_fca_private);
2285         *((emlxs_node_t **)remote_port->rp_fca_private) = NULL;
2286 
2287         if (ndlp) {
2288                 (void) EMLXS_SLI_UNREG_NODE(port, ndlp, NULL,
2289                     NULL, NULL);
2290         }
2291 
2292         TGTPORTSTAT.FctPortDeregister++;
2293         return (FCT_SUCCESS);
2294 
2295 } /* emlxs_fct_deregister_remote_port() */
2296 
2297 
2298 /* ARGSUSED */
2299 extern int
2300 emlxs_fct_handle_unsol_req(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
2301     MATCHMAP *mp, uint32_t size)
2302 {
2303         emlxs_hba_t *hba = HBA;
2304         IOCB *iocb;
2305         fct_cmd_t *fct_cmd;
2306         emlxs_buf_t *cmd_sbp;
2307         emlxs_fcp_cmd_t *fcp_cmd;
2308         emlxs_node_t *ndlp;
2309         uint32_t cnt;
2310         uint32_t tm;
2311         uint16_t hdl;
2312         scsi_task_t *fct_task;
2313         uint8_t lun[8];
2314         uint32_t sid = 0;
2315 
2316         iocb = &iocbq->iocb;
2317         ndlp = emlxs_node_find_rpi(port, iocb->ULPIOTAG);
2318         if (!ndlp) {
2319                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2320                     "FCP rcvd: Unknown RPI. rpi=%d rxid=%x. Dropping...",
2321                     iocb->ULPIOTAG, iocb->ULPCONTEXT);
2322 
2323                 goto dropped;
2324         }
2325         sid = ndlp->nlp_DID;
2326 
2327         fcp_cmd = (emlxs_fcp_cmd_t *)mp->virt;
2328 
2329         if (!port->fct_port) {
2330                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2331                     "FCP rcvd: Target unbound. rpi=%d rxid=%x. Dropping...",
2332                     iocb->ULPIOTAG, iocb->ULPCONTEXT);
2333 
2334                 emlxs_send_logo(port, sid);
2335 
2336                 goto dropped;
2337         }
2338 
2339         if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
2340                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2341                     "FCP rcvd: Target offline. rpi=%d rxid=%x. Dropping...",
2342                     iocb->ULPIOTAG, iocb->ULPCONTEXT);
2343 
2344                 emlxs_send_logo(port, sid);
2345 
2346                 goto dropped;
2347         }
2348 
2349         /* Get lun id */
2350         bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2351 
2352         if (TGTPORTSTAT.FctOutstandingIO >= port->fct_port->port_max_xchges) {
2353                 TGTPORTSTAT.FctOverQDepth++;
2354         }
2355 
2356         hdl = ndlp->nlp_Rpi;
2357         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2358                 hdl = emlxs_sli4_rpi_to_index(hba, hdl);
2359         }
2360         fct_cmd =
2361             MODSYM(fct_scsi_task_alloc) (port->fct_port, hdl, sid, lun, 16, 0);
2362 
2363         if (fct_cmd == NULL) {
2364                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2365                     "FCP rcvd: sid=%x xid=%x. "
2366                     "Unable to allocate scsi task. Returning QFULL.",
2367                     sid, iocb->ULPCONTEXT);
2368 
2369                 (void) emlxs_fct_send_qfull_reply(port, ndlp, iocb->ULPCONTEXT,
2370                     iocb->ULPCLASS, fcp_cmd);
2371 
2372                 goto dropped;
2373         }
2374 
2375         /* Initialize fct_cmd */
2376         fct_cmd->cmd_rportid = sid;
2377         fct_cmd->cmd_lportid = port->did;
2378         fct_cmd->cmd_rp_handle = hdl;
2379         fct_cmd->cmd_port = port->fct_port;
2380 
2381         cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_FCP_CMD_RECEIVED);
2382         /* mutex_enter(&cmd_sbp->fct_mtx); */
2383 
2384 #ifdef FCT_API_TRACE
2385         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2386             "fct_scsi_task_alloc %p:%p FCP rcvd: "
2387             "cmd=%x sid=%x rxid=%x oxid=%x lun=%02x%02x dl=%d",
2388             fct_cmd, cmd_sbp, fcp_cmd->fcpCdb[0], sid, iocb->ULPCONTEXT,
2389             iocb->unsli3.ext_rcv.oxid, lun[0], lun[1],
2390             LE_SWAP32(fcp_cmd->fcpDl));
2391 #endif /* FCT_API_TRACE */
2392 
2393         /* Initialize cmd_sbp */
2394         cmd_sbp->channel = cp;
2395         cmd_sbp->class = iocb->ULPCLASS;
2396         cmd_sbp->lun = (lun[0] << 8) | lun[1];
2397         cmd_sbp->fct_type = EMLXS_FCT_FCP_CMD;
2398         cmd_sbp->ticks = hba->timer_tics + (2 * hba->fc_ratov);
2399 
2400         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2401                 /* xrip was setup / passed in from the SLI layer */
2402                 cmd_sbp->xrip = iocbq->sbp;
2403                 cmd_sbp->node = iocbq->node;
2404                 iocbq->sbp = 0;
2405 
2406                 fct_cmd->cmd_oxid = cmd_sbp->xrip->rx_id;
2407                 fct_cmd->cmd_rxid = cmd_sbp->xrip->XRI;
2408 
2409 #ifdef FCT_API_TRACE
2410                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2411                     "FCP rcvd: oxid=%x rxid=%x iotag=%d %p ",
2412                     fct_cmd->cmd_oxid, fct_cmd->cmd_rxid, cmd_sbp->xrip->iotag,
2413                     hba->fc_table[cmd_sbp->xrip->iotag]);
2414 #endif /* FCT_API_TRACE */
2415 
2416         } else {
2417                 fct_cmd->cmd_oxid = iocb->unsli3.ext_rcv.oxid;
2418                 if (!fct_cmd->cmd_oxid) {
2419                         fct_cmd->cmd_oxid = 0xFFFF;
2420                 }
2421                 fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
2422         }
2423 
2424 
2425         fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2426 
2427         /* Set task_flags */
2428         switch (fcp_cmd->fcpCntl1) {
2429         case SIMPLE_Q:
2430                 fct_task->task_flags = TF_ATTR_SIMPLE_QUEUE;
2431                 break;
2432 
2433         case HEAD_OF_Q:
2434                 fct_task->task_flags = TF_ATTR_HEAD_OF_QUEUE;
2435                 break;
2436 
2437         case ORDERED_Q:
2438                 fct_task->task_flags = TF_ATTR_ORDERED_QUEUE;
2439                 break;
2440 
2441         case ACA_Q:
2442                 fct_task->task_flags = TF_ATTR_ACA;
2443                 break;
2444 
2445         case UNTAGGED:
2446                 fct_task->task_flags = TF_ATTR_UNTAGGED;
2447                 break;
2448         }
2449 
2450         cnt = LE_SWAP32(fcp_cmd->fcpDl);
2451         switch (fcp_cmd->fcpCntl3) {
2452         case 0:
2453                 TGTPORTSTAT.FctIOCmdCnt++;
2454                 break;
2455         case 1:
2456                 EMLXS_BUMP_WRIOCTR(port, cnt);
2457                 TGTPORTSTAT.FctWriteBytes += cnt;
2458                 fct_task->task_flags |= TF_WRITE_DATA;
2459                 break;
2460 
2461         case 2:
2462                 EMLXS_BUMP_RDIOCTR(port, cnt);
2463                 TGTPORTSTAT.FctReadBytes += cnt;
2464                 fct_task->task_flags |= TF_READ_DATA;
2465                 break;
2466         }
2467 
2468         fct_task->task_priority = 0;
2469 
2470         /* task_mgmt_function */
2471         tm = fcp_cmd->fcpCntl2;
2472         if (tm) {
2473                 if (tm & BIT_1) {
2474                         fct_task->task_mgmt_function = TM_ABORT_TASK_SET;
2475                 } else if (tm & BIT_2) {
2476                         fct_task->task_mgmt_function = TM_CLEAR_TASK_SET;
2477                 } else if (tm & BIT_4) {
2478                         fct_task->task_mgmt_function = TM_LUN_RESET;
2479                 } else if (tm & BIT_5) {
2480                         fct_task->task_mgmt_function = TM_TARGET_COLD_RESET;
2481                 } else if (tm & BIT_6) {
2482                         fct_task->task_mgmt_function = TM_CLEAR_ACA;
2483                 } else {
2484                         fct_task->task_mgmt_function = TM_ABORT_TASK;
2485                 }
2486         }
2487 
2488         /* Parallel buffers support - future */
2489         fct_task->task_max_nbufs = 1;
2490 
2491         fct_task->task_additional_flags = 0;
2492         fct_task->task_cur_nbufs = 0;
2493         fct_task->task_csn_size = 8;
2494         fct_task->task_cmd_seq_no = 0;
2495         fct_task->task_expected_xfer_length = cnt;
2496         bcopy((void *)&fcp_cmd->fcpCdb, fct_task->task_cdb, 16);
2497 
2498         TGTPORTSTAT.FctCmdReceived++;
2499         TGTPORTSTAT.FctOutstandingIO++;
2500 
2501         emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2502         /* mutex_exit(&cmd_sbp->fct_mtx); */
2503 
2504 #ifdef FCT_API_TRACE
2505         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2506             "fct_post_rcvd_cmd:3 %p:%p portid x%x, %d outio %d",
2507             fct_cmd, cmd_sbp, fct_cmd->cmd_lportid,
2508             fct_task->task_expected_xfer_length,
2509             TGTPORTSTAT.FctOutstandingIO);
2510 #endif /* FCT_API_TRACE */
2511 
2512         MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
2513 
2514         return (0);
2515 
2516 dropped:
2517 
2518         TGTPORTSTAT.FctRcvDropped++;
2519         return (1);
2520 
2521 } /* emlxs_fct_handle_unsol_req() */
2522 
2523 
2524 /* COMSTAR ENTER POINT */
2525 /* ARGSUSED */
2526 static fct_status_t
2527 emlxs_fct_send_fcp_data(fct_cmd_t *fct_cmd, stmf_data_buf_t *dbuf,
2528     uint32_t ioflags)
2529 {
2530         emlxs_port_t *port =
2531             (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2532         emlxs_hba_t *hba = HBA;
2533         emlxs_buf_t *cmd_sbp;
2534 #ifdef FCT_API_TRACE
2535         scsi_task_t *fct_task;
2536 #endif /* FCT_API_TRACE */
2537         IOCBQ *iocbq;
2538         emlxs_node_t *ndlp;
2539 
2540         int     channel;
2541         int     channelno;
2542         fct_status_t rval = 0;
2543 
2544         rval = emlxs_fct_cmd_accept(port, fct_cmd, EMLXS_FCT_SEND_FCP_DATA);
2545         if (rval) {
2546                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2547                     "fct_send_fcp_data: "
2548                     "Unable to accept fct_cmd. did=%x",
2549                     fct_cmd->cmd_rportid);
2550 
2551                 return (rval);
2552         }
2553         /* mutex_enter(&cmd_sbp->fct_mtx); */
2554 
2555         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2556 #ifdef FCT_API_TRACE
2557         fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2558 #endif /* FCT_API_TRACE */
2559         ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2560 
2561         cmd_sbp->node = ndlp;
2562         cmd_sbp->fct_buf = dbuf;
2563 
2564         channelno = ((CHANNEL *)cmd_sbp->channel)->channelno;
2565 
2566         channel = channelno;
2567 
2568 
2569 
2570         iocbq = &cmd_sbp->iocbq;
2571         iocbq->sbp = cmd_sbp;
2572 
2573 #ifdef FCT_API_TRACE
2574         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2575             "fct_send_fcp_data %p:%p flgs=%x ioflags=%x dl=%d,%d,%d,%d",
2576             fct_cmd, cmd_sbp, dbuf->db_flags, ioflags,
2577             fct_task->task_cmd_xfer_length,
2578             fct_task->task_nbytes_transferred, dbuf->db_data_size,
2579             fct_task->task_expected_xfer_length);
2580 #endif /* FCT_API_TRACE */
2581 
2582         /* Setup for I/O prep routine */
2583         iocbq->iocb.ULPCOMMAND = 0;
2584 
2585         if (EMLXS_SLI_PREP_FCT_IOCB(port, cmd_sbp, channel) != IOERR_SUCCESS) {
2586 
2587                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2588                 /* mutex_exit(&cmd_sbp->fct_mtx); */
2589 
2590                 return (FCT_BUSY);
2591         }
2592 
2593         cmd_sbp->fct_type = EMLXS_FCT_FCP_DATA;
2594 
2595         if (dbuf->db_flags & DB_SEND_STATUS_GOOD) {
2596                 cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
2597         }
2598 
2599         if (dbuf->db_flags & DB_DIRECTION_TO_RPORT) {
2600                 if (emlxs_fct_dbuf_dma_sync(hba, dbuf, DDI_DMA_SYNC_FORDEV)) {
2601                         emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2602                         /* mutex_exit(&cmd_sbp->fct_mtx); */
2603 
2604                         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2605                                 emlxs_sli4_free_xri(port, cmd_sbp, 0, 0);
2606                         }
2607                         return (FCT_BUSY);
2608                 }
2609         }
2610 
2611         cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2612         emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_DATA_PENDING);
2613         /* mutex_exit(&cmd_sbp->fct_mtx); */
2614 
2615         EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, iocbq);
2616 
2617         return (FCT_SUCCESS);
2618 
2619 } /* emlxs_fct_send_fcp_data() */
2620 
2621 
2622 /* cmd_sbp->fct_mtx must be held to enter */
2623 /* cmd_sbp->fct_mtx must be released before exiting */
2624 static fct_status_t
2625 emlxs_fct_send_fcp_status(fct_cmd_t *fct_cmd)
2626 {
2627         emlxs_port_t *port =
2628             (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
2629         emlxs_hba_t *hba = HBA;
2630         emlxs_buf_t *cmd_sbp;
2631         scsi_task_t *fct_task;
2632         fc_packet_t *pkt;
2633         emlxs_buf_t *sbp = NULL;
2634         emlxs_fcp_rsp *fcp_rsp;
2635         emlxs_node_t *ndlp;
2636         fct_status_t rval;
2637         uint32_t did;
2638         uint32_t size;
2639 
2640         fct_task = (scsi_task_t *)fct_cmd->cmd_specific;
2641         ndlp = *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private;
2642         did = fct_cmd->cmd_rportid;
2643 
2644         /* Initialize cmd_sbp */
2645         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2646 
2647         EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_FCP_STATUS);
2648 
2649         cmd_sbp->node = ndlp;
2650 
2651         size = 24;
2652         if (fct_task->task_sense_length) {
2653                 size += fct_task->task_sense_length;
2654         }
2655 #ifdef FCT_API_TRACE
2656         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2657             "fct_send_fcp_status %p:%p stat=%d resid=%d size=%d rx=%x ox=%x",
2658             fct_cmd, cmd_sbp, fct_task->task_scsi_status,
2659             fct_task->task_resid, size, fct_cmd->cmd_rxid, fct_cmd->cmd_oxid);
2660 #endif /* FCT_API_TRACE */
2661 
2662         if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2663                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2664                     "fct_send_fcp_status: Unable to allocate packet.");
2665 
2666                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2667                 /* mutex_exit(&cmd_sbp->fct_mtx); */
2668 
2669                 return (FCT_BUSY);
2670         }
2671 
2672         cmd_sbp->fct_type = EMLXS_FCT_FCP_STATUS;
2673 
2674         sbp =  emlxs_fct_pkt_init(port, fct_cmd, pkt);
2675         cmd_sbp->fct_pkt = pkt;
2676 
2677         pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2678         pkt->pkt_timeout =
2679             ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2680         pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
2681         pkt->pkt_comp = emlxs_fct_pkt_comp;
2682 
2683         /* Build the fc header */
2684         pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
2685         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2686         pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2687         pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2688         pkt->pkt_cmd_fhdr.f_ctl =
2689             F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2690         pkt->pkt_cmd_fhdr.seq_id = 0;
2691         pkt->pkt_cmd_fhdr.df_ctl = 0;
2692         pkt->pkt_cmd_fhdr.seq_cnt = 0;
2693         pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
2694         pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
2695         pkt->pkt_cmd_fhdr.ro = 0;
2696 
2697         /* Build the status payload */
2698         fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2699 
2700         if (fct_task->task_resid) {
2701                 if (fct_task->task_status_ctrl & TASK_SCTRL_OVER) {
2702                         TGTPORTSTAT.FctScsiResidOver++;
2703                         fcp_rsp->rspStatus2 |= RESID_OVER;
2704                         fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2705 
2706                 } else if (fct_task->task_status_ctrl & TASK_SCTRL_UNDER) {
2707                         TGTPORTSTAT.FctScsiResidUnder++;
2708                         fcp_rsp->rspStatus2 |= RESID_UNDER;
2709                         fcp_rsp->rspResId = LE_SWAP32(fct_task->task_resid);
2710 
2711                 }
2712         }
2713 
2714         if (fct_task->task_scsi_status) {
2715                 if (fct_task->task_scsi_status == SCSI_STAT_QUE_FULL) {
2716                         TGTPORTSTAT.FctScsiQfullErr++;
2717                 } else {
2718                         TGTPORTSTAT.FctScsiStatusErr++;
2719                 }
2720 
2721                 /* Make sure residual reported on non-SCSI_GOOD READ status */
2722                 if ((fct_task->task_flags & TF_READ_DATA) &&
2723                     (fcp_rsp->rspResId == 0)) {
2724                         fcp_rsp->rspStatus2 |= RESID_UNDER;
2725                         fcp_rsp->rspResId =
2726                             fct_task->task_expected_xfer_length;
2727                 }
2728         }
2729 
2730 
2731         if (fct_task->task_sense_length) {
2732                 TGTPORTSTAT.FctScsiSenseErr++;
2733                 fcp_rsp->rspStatus2 |= SNS_LEN_VALID;
2734                 fcp_rsp->rspSnsLen = LE_SWAP32(fct_task->task_sense_length);
2735 
2736                 bcopy((uint8_t *)fct_task->task_sense_data,
2737                     (uint8_t *)&fcp_rsp->rspInfo0,
2738                     fct_task->task_sense_length);
2739         }
2740 
2741         fcp_rsp->rspStatus3 = fct_task->task_scsi_status;
2742         fcp_rsp->rspRspLen = 0;
2743 
2744 #ifdef FCT_API_TRACE
2745         emlxs_data_dump(port, "RESP", (uint32_t *)fcp_rsp, 36, 0);
2746 #endif /* FCT_API_TRACE */
2747 
2748         cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
2749         emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_STATUS_PENDING);
2750         /* mutex_exit(&cmd_sbp->fct_mtx); */
2751 
2752         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2753 
2754                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2755                     "fct_send_fcp_status: Unable to send packet.");
2756 
2757                 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2758                         emlxs_sli4_free_xri(port, sbp, 0, 0);
2759                 }
2760 
2761                 /* Reacquire ownership of the fct_cmd */
2762                 rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
2763                 if (rval) {
2764                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2765                             "fct_send_fcp_status: "
2766                             "Unable to acquire fct_cmd.");
2767                         return (rval);
2768                 }
2769                 /* mutex_enter(&cmd_sbp->fct_mtx); */
2770 
2771                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
2772                 /* mutex_exit(&cmd_sbp->fct_mtx); */
2773 
2774                 return (FCT_BUSY);
2775         }
2776 
2777         return (FCT_SUCCESS);
2778 
2779 } /* emlxs_fct_send_fcp_status() */
2780 
2781 
2782 static fct_status_t
2783 emlxs_fct_send_qfull_reply(emlxs_port_t *port, emlxs_node_t *ndlp,
2784     uint16_t xid, uint32_t class, emlxs_fcp_cmd_t *fcp_cmd)
2785 {
2786         emlxs_hba_t *hba = HBA;
2787         emlxs_buf_t *sbp;
2788         fc_packet_t *pkt;
2789         emlxs_fcp_rsp *fcp_rsp;
2790         uint32_t size;
2791         CHANNEL *cp = &hba->chan[hba->CHANNEL_FCT];
2792         uint8_t lun[8];
2793 
2794         bcopy((void *)&fcp_cmd->fcpLunMsl, lun, 8);
2795         size = 24;
2796 
2797         if (!(pkt = emlxs_pkt_alloc(port, size, 0, 0, KM_NOSLEEP))) {
2798                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2799                     "fct_send_qfull_reply: Unable to allocate packet.");
2800                 return (FCT_FAILURE);
2801         }
2802 
2803         sbp = PKT2PRIV(pkt);
2804         sbp->node = ndlp;
2805         sbp->channel = cp;
2806         sbp->did = ndlp->nlp_DID;
2807         sbp->lun = (lun[0] << 8) | lun[1];
2808         sbp->class = class;
2809 
2810         pkt->pkt_tran_type = FC_PKT_OUTBOUND;
2811         pkt->pkt_timeout =
2812             ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
2813 
2814         /* Build the fc header */
2815         pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(ndlp->nlp_DID);
2816         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
2817         pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
2818         pkt->pkt_cmd_fhdr.type = FC_TYPE_SCSI_FCP;
2819         pkt->pkt_cmd_fhdr.f_ctl =
2820             F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
2821         pkt->pkt_cmd_fhdr.seq_id = 0;
2822         pkt->pkt_cmd_fhdr.df_ctl = 0;
2823         pkt->pkt_cmd_fhdr.seq_cnt = 0;
2824         pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
2825         pkt->pkt_cmd_fhdr.rx_id = xid;
2826         pkt->pkt_cmd_fhdr.ro = 0;
2827 
2828         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2829             "fct_send_qfull_reply: Sending QFULL: x%x lun x%x: %d %d",
2830             xid, sbp->lun, TGTPORTSTAT.FctOutstandingIO,
2831             port->fct_port->port_max_xchges);
2832 
2833         /* Build the status payload */
2834         fcp_rsp = (emlxs_fcp_rsp *)pkt->pkt_cmd;
2835 
2836         TGTPORTSTAT.FctScsiQfullErr++;
2837         fcp_rsp->rspStatus3 = SCSI_STAT_QUE_FULL;
2838         fcp_rsp->rspStatus2 |= RESID_UNDER;
2839         fcp_rsp->rspResId = LE_SWAP32(fcp_cmd->fcpDl);
2840 
2841         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
2842 
2843                 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
2844                         emlxs_sli4_free_xri(port, sbp, 0, 0);
2845                 }
2846 
2847                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
2848                     "fct_send_qfull_reply: Unable to send packet.");
2849                 emlxs_pkt_free(pkt);
2850                 return (FCT_FAILURE);
2851         }
2852 
2853         return (FCT_SUCCESS);
2854 
2855 } /* emlxs_fct_send_qfull_reply() */
2856 
2857 
2858 /* ARGSUSED */
2859 extern int
2860 emlxs_fct_handle_fcp_event(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
2861 {
2862         emlxs_port_t *port = &PPORT;
2863         IOCB *iocb;
2864         emlxs_buf_t *sbp;
2865         emlxs_buf_t *cmd_sbp;
2866         uint32_t status;
2867         fct_cmd_t *fct_cmd;
2868         stmf_data_buf_t *dbuf;
2869         scsi_task_t *fct_task;
2870         fc_packet_t *pkt;
2871         uint32_t fct_flags;
2872         stmf_data_buf_t *fct_buf;
2873         fct_status_t rval;
2874 
2875         iocb = &iocbq->iocb;
2876         sbp = (emlxs_buf_t *)iocbq->sbp;
2877 
2878         TGTPORTSTAT.FctEvent++;
2879 
2880         if (!sbp) {
2881                 /* completion with missing xmit command */
2882                 TGTPORTSTAT.FctStray++;
2883 
2884                 /* emlxs_stray_fcp_completion_msg */
2885                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2886                     "FCP event cmd=%x status=%x error=%x iotag=%d",
2887                     iocb->ULPCOMMAND, iocb->ULPSTATUS,
2888                     iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
2889 
2890                 return (1);
2891         }
2892 
2893         TGTPORTSTAT.FctCompleted++;
2894 
2895         port = sbp->iocbq.port;
2896         fct_cmd = sbp->fct_cmd;
2897         status = iocb->ULPSTATUS;
2898 
2899 #ifdef FCT_API_TRACE
2900         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2901             "fct_handle_fcp_event: %p:%p cmd=%x status=%x, %x",
2902             fct_cmd, sbp, iocb->ULPCOMMAND, status, iocb->ULPCT);
2903 #endif /* FCT_API_TRACE */
2904 
2905         if (fct_cmd == NULL) {
2906                 /* For driver generated QFULL response */
2907                 if (((iocb->ULPCOMMAND == CMD_FCP_TRSP_CX) ||
2908                     (iocb->ULPCOMMAND == CMD_FCP_TRSP64_CX)) && sbp->pkt) {
2909                         emlxs_pkt_free(sbp->pkt);
2910                 }
2911                 return (0);
2912         }
2913 
2914         rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_REQ_COMPLETE);
2915         if (rval) {
2916                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
2917                     "fct_handle_fcp_event: "
2918                     "Unable to reacquire fct_cmd. type=%x",
2919                     fct_cmd->cmd_type);
2920 
2921                 return (1);
2922         }
2923         /* mutex_enter(&cmd_sbp->fct_mtx); */
2924 
2925         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
2926         cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
2927 
2928         pkt = cmd_sbp->fct_pkt;
2929         cmd_sbp->fct_pkt = NULL;
2930 
2931         dbuf = sbp->fct_buf;
2932 
2933         fct_cmd->cmd_comp_status = FCT_SUCCESS;
2934 
2935         if (status) {
2936 emlxs_dma_error:
2937                 /*
2938                  * The error indicates this IO should be terminated
2939                  * immediately.
2940                  */
2941                 cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
2942                 fct_cmd->cmd_comp_status = FCT_FAILURE;
2943 
2944                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
2945                 /* mutex_exit(&cmd_sbp->fct_mtx); */
2946 
2947 #ifdef FCT_API_TRACE
2948                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
2949                     "fct_queue_cmd_for_termination:1 %p: x%x",
2950                     fct_cmd, fct_cmd->cmd_comp_status);
2951 #endif /* FCT_API_TRACE */
2952 
2953                 MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
2954                     FCT_ABTS_RECEIVED);
2955 
2956                 goto done;
2957         }
2958 
2959         switch (iocb->ULPCOMMAND) {
2960 
2961         /*
2962          *  FCP Data completion
2963          */
2964         case CMD_FCP_TSEND_CX:
2965         case CMD_FCP_TSEND64_CX:
2966         case CMD_FCP_TRECEIVE_CX:
2967         case CMD_FCP_TRECEIVE64_CX:
2968 
2969                 if (dbuf->db_flags & DB_DIRECTION_FROM_RPORT) {
2970                         if (emlxs_fct_dbuf_dma_sync(hba, dbuf,
2971                             DDI_DMA_SYNC_FORCPU)) {
2972                                 goto emlxs_dma_error;
2973                         }
2974                 }
2975 
2976                 if ((cmd_sbp->fct_flags & EMLXS_FCT_SEND_STATUS) &&
2977                     (iocb->ULPCT != 1)) {
2978 
2979                         dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2980 
2981                         fct_task =
2982                             (scsi_task_t *)fct_cmd->cmd_specific;
2983                         fct_task->task_scsi_status = 0;
2984 
2985                         (void) emlxs_fct_send_fcp_status(fct_cmd);
2986                         /* mutex_exit(&cmd_sbp->fct_mtx); */
2987 
2988                         break;
2989 
2990                 } else if ((cmd_sbp->fct_flags &
2991                     EMLXS_FCT_SEND_STATUS) &&
2992                     (iocb->ULPCT == 1)) {
2993                         /* Auto-resp has been sent out by firmware */
2994                         /* We can assume this is really a FC_TRSP_CX */
2995 
2996                         dbuf->db_flags |= DB_STATUS_GOOD_SENT;
2997                         fct_task =
2998                             (scsi_task_t *)fct_cmd->cmd_specific;
2999                         fct_task->task_scsi_status = 0;
3000 
3001                         cmd_sbp->fct_flags |= EMLXS_FCT_SEND_STATUS;
3002 
3003                         goto auto_resp;
3004                 }
3005 
3006                 cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
3007 
3008                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3009                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3010 
3011 #ifdef FCT_API_TRACE
3012                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3013                     "fct_scsi_data_xfer_done:1 %p %p", fct_cmd, dbuf);
3014 #endif /* FCT_API_TRACE */
3015 
3016                 MODSYM(fct_scsi_data_xfer_done) (fct_cmd, dbuf, 0);
3017 
3018                 break;
3019 
3020                 /* FCP Status completion */
3021         case CMD_FCP_TRSP_CX:
3022         case CMD_FCP_TRSP64_CX:
3023 
3024 auto_resp:
3025                 /* Copy these before calling emlxs_fct_cmd_done */
3026                 fct_flags = cmd_sbp->fct_flags;
3027                 fct_buf = cmd_sbp->fct_buf;
3028 
3029                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3030                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3031 
3032                 TGTPORTSTAT.FctOutstandingIO--;
3033 
3034                 if (fct_flags & EMLXS_FCT_SEND_STATUS) {
3035 #ifdef FCT_API_TRACE
3036                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3037                             "fct_scsi_data_xfer_done:2 %p %p outio %d",
3038                             fct_cmd, fct_buf, TGTPORTSTAT.FctOutstandingIO);
3039 #endif /* FCT_API_TRACE */
3040 
3041                         MODSYM(fct_scsi_data_xfer_done) (fct_cmd,
3042                             fct_buf, FCT_IOF_FCA_DONE);
3043                 } else {
3044 #ifdef FCT_API_TRACE
3045                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3046                             "fct_send_response_done:1 %p: x%x outio %d",
3047                             fct_cmd, fct_cmd->cmd_comp_status,
3048                             TGTPORTSTAT.FctOutstandingIO);
3049 #endif /* FCT_API_TRACE */
3050 
3051                         MODSYM(fct_send_response_done) (fct_cmd,
3052                             fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3053                 }
3054                 break;
3055 
3056         default:
3057                 emlxs_fct_cmd_release(port, fct_cmd, 0);
3058                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3059 
3060                 TGTPORTSTAT.FctStray++;
3061                 TGTPORTSTAT.FctCompleted--;
3062 
3063                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3064                     "Invalid iocb: cmd=0x%x", iocb->ULPCOMMAND);
3065 
3066                 if (pkt) {
3067                         emlxs_pkt_complete(sbp, status,
3068                             iocb->un.grsp.perr.statLocalError, 1);
3069                 }
3070 
3071         }       /* switch(iocb->ULPCOMMAND) */
3072 
3073 
3074 done:
3075         if (pkt) {
3076                 emlxs_pkt_free(pkt);
3077         }
3078 
3079         if (status == IOSTAT_SUCCESS) {
3080                 TGTPORTSTAT.FctCmplGood++;
3081         } else {
3082                 TGTPORTSTAT.FctCmplError++;
3083         }
3084 
3085         return (0);
3086 
3087 } /* emlxs_fct_handle_fcp_event() */
3088 
3089 
3090 /* ARGSUSED */
3091 extern int
3092 emlxs_fct_handle_abort(emlxs_hba_t *hba, CHANNEL *cp, IOCBQ *iocbq)
3093 {
3094         emlxs_port_t *port = &PPORT;
3095         IOCB *iocb;
3096         emlxs_buf_t *sbp;
3097         fc_packet_t *pkt;
3098 
3099         iocb = &iocbq->iocb;
3100         sbp = (emlxs_buf_t *)iocbq->sbp;
3101 
3102         TGTPORTSTAT.FctEvent++;
3103 
3104         if (!sbp) {
3105                 /* completion with missing xmit command */
3106                 TGTPORTSTAT.FctStray++;
3107 
3108                 /* emlxs_stray_fcp_completion_msg */
3109                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3110                     "ABORT event cmd=%x status=%x error=%x iotag=%d",
3111                     iocb->ULPCOMMAND, iocb->ULPSTATUS,
3112                     iocb->un.grsp.perr.statLocalError, iocb->ULPIOTAG);
3113 
3114                 return (1);
3115         }
3116 
3117         pkt = PRIV2PKT(sbp);
3118 
3119 #ifdef FCT_API_TRACE
3120         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3121             "fct_handle_abort: %p:%p xri=%d cmd=%x status=%x",
3122             sbp->fct_cmd, sbp,
3123             iocb->ULPCONTEXT, iocb->ULPCOMMAND, iocb->ULPSTATUS);
3124 #endif /* FCT_API_TRACE */
3125 
3126         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3127                 XRIobj_t        *xrip;
3128 
3129                 emlxs_sli4_free_xri(port, NULL, sbp->xrip, 1);
3130                 xrip = emlxs_sli4_find_xri(port, iocb->ULPCONTEXT);
3131                 if (!xrip || xrip->state == XRI_STATE_FREE) {
3132                         goto exit;
3133                 }
3134 
3135                 if ((hba->fc_table[xrip->iotag]) &&
3136                     (hba->fc_table[xrip->iotag] != STALE_PACKET)) {
3137                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
3138                             "Cmd not aborted, retrying: xri=%d iotag=%d sbp=%p",
3139                             xrip->XRI, xrip->iotag, hba->fc_table[xrip->iotag]);
3140 
3141                         /* Abort retry */
3142                         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
3143                                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_debug_msg,
3144                                     "Abort retry failed xri=%x", xrip->XRI);
3145                         } else {
3146                                 return (0);
3147                         }
3148                 }
3149         }
3150 
3151 exit:
3152         if (pkt) {
3153                 emlxs_pkt_free(pkt);
3154         }
3155         return (0);
3156 
3157 } /* emlxs_fct_handle_abort() */
3158 
3159 
3160 extern int
3161 emlxs_fct_handle_unsol_els(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3162     MATCHMAP *mp, uint32_t size)
3163 {
3164         emlxs_hba_t *hba = HBA;
3165         IOCB *iocb;
3166         uint32_t cmd_code;
3167         fct_cmd_t *fct_cmd;
3168         fct_els_t *els;
3169         uint32_t sid;
3170         uint32_t padding;
3171         uint8_t *bp;
3172         emlxs_buf_t *cmd_sbp;
3173         uint32_t rval;
3174 
3175         HBASTATS.ElsCmdReceived++;
3176 
3177         bp = mp->virt;
3178         cmd_code = (*(uint32_t *)bp) & ELS_CMD_MASK;
3179         iocb = &iocbq->iocb;
3180         sid = iocb->un.elsreq.remoteID;
3181 
3182         if (!port->fct_port) {
3183                 if (!(hba->flag & FC_ONLINE_MODE)) {
3184                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3185                             "%s: sid=%x. Adapter offline. Dropping...",
3186                             emlxs_elscmd_xlate(cmd_code), sid);
3187                         goto done;
3188                 }
3189 
3190                 switch (cmd_code) {
3191                 case ELS_CMD_LOGO:
3192                 case ELS_CMD_PRLO:
3193                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3194                             "%s: sid=%x. Target unbound. Accepting...",
3195                             emlxs_elscmd_xlate(cmd_code), sid);
3196                         (void) emlxs_els_reply(port, iocbq, ELS_CMD_ACC,
3197                             ELS_CMD_LOGO, 0, 0);
3198                         break;
3199                 default:
3200                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3201                             "%s: sid=%x. Target unbound. Rejecting...",
3202                             emlxs_elscmd_xlate(cmd_code), sid);
3203                         (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT,
3204                             cmd_code, LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3205                         break;
3206                 }
3207                 goto done;
3208         }
3209 
3210         if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3211                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3212                     "%s: sid=%x. Target offline. Rejecting...",
3213                     emlxs_elscmd_xlate(cmd_code), sid);
3214                 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3215                     LSRJT_UNABLE_TPC, LSEXP_NOTHING_MORE);
3216 
3217                 goto done;
3218         }
3219 
3220 #ifdef FCT_API_TRACE
3221         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3222             "%s: sid=%x cnt=%d. Target rcv. ",
3223             emlxs_elscmd_xlate(cmd_code), sid, size);
3224 #endif /* FCT_API_TRACE */
3225 
3226         /* Process the request */
3227         switch (cmd_code) {
3228         case ELS_CMD_FLOGI:
3229                 rval = emlxs_fct_process_unsol_flogi(port, cp, iocbq, mp, size);
3230 
3231                 if (!rval) {
3232                         ELS_PKT *els_pkt = (ELS_PKT *)bp;
3233                         fct_flogi_xchg_t fx;
3234 
3235                         bzero((uint8_t *)&fx, sizeof (fct_flogi_xchg_t));
3236 
3237                         /* Save the FLOGI exchange information */
3238                         fx.rsvd2 = iocb->ULPCONTEXT;
3239                         bcopy((caddr_t)&els_pkt->un.logi.nodeName,
3240                             (caddr_t)fx.fx_nwwn, 8);
3241                         bcopy((caddr_t)&els_pkt->un.logi.portName,
3242                             (caddr_t)fx.fx_pwwn, 8);
3243                         fx.fx_sid = sid;
3244                         fx.fx_did = iocb->un.elsreq.myID;
3245                         fx.fx_fport = els_pkt->un.logi.cmn.fPort;
3246                         fx.fx_op = ELS_OP_FLOGI;
3247 
3248                         emlxs_fct_handle_unsol_flogi(port, &fx, 1);
3249                 }
3250 
3251                 goto done;
3252 
3253         case ELS_CMD_PLOGI:
3254                 rval =
3255                     emlxs_fct_process_unsol_plogi(port, cp, iocbq, mp, size);
3256                 break;
3257 
3258         default:
3259                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3260                     "%s: sid=0x%x", emlxs_elscmd_xlate(cmd_code), sid);
3261                 rval = 0;
3262                 break;
3263         }
3264 
3265         if (rval) {
3266                 goto done;
3267         }
3268 
3269         padding = (8 - (size & 7)) & 7;
3270 
3271         fct_cmd = (fct_cmd_t *)MODSYM(fct_alloc) (FCT_STRUCT_CMD_RCVD_ELS,
3272             (size + padding + GET_STRUCT_SIZE(emlxs_buf_t)),
3273             AF_FORCE_NOSLEEP);
3274 
3275 #ifdef FCT_API_TRACE
3276         {
3277                 uint32_t *ptr = (uint32_t *)bp;
3278 
3279                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3280                     "fct_alloc %p: ELS rcvd: rxid=%x payload: x%x x%x",
3281                     fct_cmd, iocb->ULPCONTEXT, *ptr, *(ptr + 1));
3282         }
3283 #endif /* FCT_API_TRACE */
3284 
3285         if (fct_cmd == NULL) {
3286                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3287                     "%s: sid=%x. Out of memory. Rejecting...",
3288                     emlxs_elscmd_xlate(cmd_code), sid);
3289 
3290                 (void) emlxs_els_reply(port, iocbq, ELS_CMD_LS_RJT, cmd_code,
3291                     LSRJT_LOGICAL_BSY, LSEXP_OUT_OF_RESOURCE);
3292                 goto done;
3293         }
3294 
3295         /* Initialize fct_cmd */
3296         fct_cmd->cmd_oxid = (cmd_code >> ELS_CMD_SHIFT) & 0xff;
3297         fct_cmd->cmd_rxid = iocb->ULPCONTEXT;
3298         fct_cmd->cmd_rportid = sid;
3299         fct_cmd->cmd_lportid = port->did;
3300         fct_cmd->cmd_rp_handle = FCT_HANDLE_NONE;
3301         fct_cmd->cmd_port = port->fct_port;
3302 
3303         cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_ELS_CMD_RECEIVED);
3304         /* mutex_enter(&cmd_sbp->fct_mtx); */
3305 
3306         /* Initialize cmd_sbp */
3307         cmd_sbp->channel = cp;
3308         cmd_sbp->class = iocb->ULPCLASS;
3309         cmd_sbp->fct_type = EMLXS_FCT_ELS_CMD;
3310         cmd_sbp->fct_flags |= EMLXS_FCT_PLOGI_RECEIVED;
3311 
3312         bcopy((uint8_t *)iocb, (uint8_t *)&cmd_sbp->iocbq,
3313             sizeof (emlxs_iocb_t));
3314 
3315         els = (fct_els_t *)fct_cmd->cmd_specific;
3316         els->els_req_size = (uint16_t)size;
3317         els->els_req_payload =
3318             GET_BYTE_OFFSET(fct_cmd->cmd_fca_private,
3319             GET_STRUCT_SIZE(emlxs_buf_t));
3320         bcopy(bp, els->els_req_payload, size);
3321 
3322 
3323         /* Check if Offline */
3324         if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
3325 
3326                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3327                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3328 
3329 #ifdef FCT_API_TRACE
3330                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3331                     "fct_post_rcvd_cmd:4 %p: portid x%x", fct_cmd,
3332                     fct_cmd->cmd_lportid);
3333 #endif /* FCT_API_TRACE */
3334 
3335                 MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
3336 
3337                 goto done;
3338         }
3339 
3340         /* Online */
3341 
3342         /* Check if Link up is acked */
3343         if (!(port->fct_flags & FCT_STATE_LINK_UP_ACKED)) {
3344                 goto defer;
3345         }
3346 
3347         if ((cmd_code != ELS_CMD_FLOGI) &&
3348             !(port->fct_flags & FCT_STATE_FLOGI_CMPL)) {
3349                 goto defer;
3350         }
3351 
3352         /* Post it to COMSTAR */
3353         emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
3354         /* mutex_exit(&cmd_sbp->fct_mtx); */
3355 
3356 #ifdef FCT_API_TRACE
3357         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3358             "fct_post_rcvd_cmd:1 %p: portid x%x", fct_cmd,
3359             fct_cmd->cmd_lportid);
3360 #endif /* FCT_API_TRACE */
3361 
3362         MODSYM(fct_post_rcvd_cmd) (fct_cmd, 0);
3363 
3364         goto done;
3365 
3366 defer:
3367         /* Defer processing of fct_cmd till later (after link up ack). */
3368 
3369         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3370             "%s: sid=%x. Defer Processing x%x.",
3371             emlxs_elscmd_xlate(cmd_code), sid, port->fct_flags);
3372 
3373         emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_CMD_WAITQ);
3374         /* mutex_exit(&cmd_sbp->fct_mtx); */
3375 
3376         /* Add cmd_sbp to queue tail */
3377         mutex_enter(&EMLXS_PORT_LOCK);
3378 
3379         if (port->fct_wait_tail) {
3380                 port->fct_wait_tail->next = cmd_sbp;
3381         }
3382         port->fct_wait_tail = cmd_sbp;
3383 
3384         if (!port->fct_wait_head) {
3385                 port->fct_wait_head = cmd_sbp;
3386         }
3387 
3388         mutex_exit(&EMLXS_PORT_LOCK);
3389 
3390 done:
3391 
3392         return (0);
3393 
3394 } /* emlxs_fct_handle_unsol_els() */
3395 
3396 
3397 /* ARGSUSED */
3398 static uint32_t
3399 emlxs_fct_process_unsol_flogi(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3400     MATCHMAP *mp, uint32_t size)
3401 {
3402         IOCB *iocb;
3403         char buffer[64];
3404 
3405         buffer[0] = 0;
3406 
3407         iocb = &iocbq->iocb;
3408 
3409         /* Perform processing of FLOGI payload */
3410         if (emlxs_process_unsol_flogi(port, iocbq, mp, size, buffer,
3411             sizeof (buffer))) {
3412                 return (1);
3413         }
3414 
3415         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3416             "FLOGI: sid=0x%x xid=%x %s",
3417             iocb->un.elsreq.remoteID, iocb->ULPIOTAG, buffer);
3418 
3419         return (0);
3420 
3421 } /* emlxs_fct_process_unsol_flogi() */
3422 
3423 
3424 /* ARGSUSED */
3425 static uint32_t
3426 emlxs_fct_process_unsol_plogi(emlxs_port_t *port, CHANNEL *cp, IOCBQ *iocbq,
3427     MATCHMAP *mp, uint32_t size)
3428 {
3429         IOCB *iocb;
3430         char buffer[64];
3431 
3432         buffer[0] = 0;
3433 
3434         iocb = &iocbq->iocb;
3435 
3436         /* Perform processing of PLOGI payload */
3437         if (emlxs_process_unsol_plogi(port, iocbq, mp, size, buffer,
3438             sizeof (buffer))) {
3439                 return (1);
3440         }
3441 
3442         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_unsol_els_msg,
3443             "PLOGI: sid=0x%x xid=%x %s",
3444             iocb->un.elsreq.remoteID, iocb->ULPIOTAG, buffer);
3445 
3446         return (0);
3447 
3448 } /* emlxs_fct_process_unsol_plogi() */
3449 
3450 
3451 /* ARGSUSED */
3452 static emlxs_buf_t *
3453 emlxs_fct_pkt_init(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3454     fc_packet_t *pkt)
3455 {
3456         emlxs_buf_t *cmd_sbp;
3457         emlxs_buf_t *sbp;
3458 
3459         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3460 
3461         sbp = PKT2PRIV(pkt);
3462         sbp->fct_cmd = cmd_sbp->fct_cmd;
3463         sbp->node = cmd_sbp->node;
3464         sbp->channel = cmd_sbp->channel;
3465         sbp->did = cmd_sbp->did;
3466         sbp->lun = cmd_sbp->lun;
3467         sbp->class = cmd_sbp->class;
3468         sbp->fct_type = cmd_sbp->fct_type;
3469         sbp->fct_state = cmd_sbp->fct_state;
3470         sbp->xrip = cmd_sbp->xrip;
3471         sbp->iotag = cmd_sbp->iotag;
3472 
3473         return (sbp);
3474 
3475 } /* emlxs_fct_pkt_init() */
3476 
3477 
3478 /* Mutex will be acquired */
3479 static emlxs_buf_t *
3480 emlxs_fct_cmd_init(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3481 {
3482         emlxs_hba_t *hba = HBA;
3483         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3484 
3485         bzero((void *)cmd_sbp, sizeof (emlxs_buf_t));
3486         mutex_init(&cmd_sbp->fct_mtx, NULL, MUTEX_DRIVER,
3487             DDI_INTR_PRI(hba->intr_arg));
3488         mutex_init(&cmd_sbp->mtx, NULL, MUTEX_DRIVER,
3489             DDI_INTR_PRI(hba->intr_arg));
3490 
3491         mutex_enter(&cmd_sbp->fct_mtx);
3492         cmd_sbp->pkt_flags = PACKET_VALID;
3493         cmd_sbp->port = port;
3494         cmd_sbp->fct_cmd = fct_cmd;
3495         cmd_sbp->node = (fct_cmd->cmd_rp) ?
3496             *(emlxs_node_t **)fct_cmd->cmd_rp->rp_fca_private : NULL;
3497         cmd_sbp->iocbq.sbp = cmd_sbp;
3498         cmd_sbp->iocbq.port = port;
3499         cmd_sbp->did = fct_cmd->cmd_rportid;
3500 
3501         /* Flags fct_cmd as inuse */
3502         if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3503                 fct_cmd->cmd_oxid = 0xffff;
3504                 fct_cmd->cmd_rxid = 0xffff;
3505         }
3506 
3507         if (fct_state) {
3508                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3509         }
3510 
3511         return (cmd_sbp);
3512 
3513 } /* emlxs_fct_cmd_init() */
3514 
3515 
3516 /* Called after receiving fct_cmd from COMSTAR */
3517 static fct_status_t
3518 emlxs_fct_cmd_accept(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3519 {
3520         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3521 
3522         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3523                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3524                     "fct_cmd_accept: "
3525                     "Invalid fct_cmd found! fct_cmd=%p state=%x",
3526                     fct_cmd, fct_state);
3527 
3528                 return (FCT_NOT_FOUND);
3529         }
3530 
3531         mutex_enter(&cmd_sbp->fct_mtx);
3532 
3533         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3534                 mutex_exit(&cmd_sbp->fct_mtx);
3535 
3536                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3537                     "fct_cmd_accept:2 "
3538                     "Invalid fct_cmd found! fct_cmd=%p state=%x",
3539                     fct_cmd, fct_state);
3540 
3541                 return (FCT_NOT_FOUND);
3542         }
3543 
3544         if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
3545 
3546                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3547                     "fct_cmd_accept: "
3548                     "Aborted fct_cmd found! fct_cmd=%p state=%x",
3549                     fct_cmd, fct_state);
3550 
3551                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_ABORT_DONE);
3552                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3553 
3554                 MODSYM(fct_cmd_fca_aborted) (fct_cmd,
3555                     FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
3556 
3557                 return (FCT_NOT_FOUND);
3558         }
3559 
3560         mutex_enter(&cmd_sbp->mtx);
3561         if (!(cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3562                 mutex_exit(&cmd_sbp->mtx);
3563                 mutex_exit(&cmd_sbp->fct_mtx);
3564 
3565                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3566                     "fct_cmd_accept: "
3567                     "Busy fct_cmd found! fct_cmd=%p state=%x",
3568                     fct_cmd, fct_state);
3569 
3570                 return (FCT_BUSY);
3571         }
3572         cmd_sbp->pkt_flags &= ~PACKET_ULP_OWNED;
3573         mutex_exit(&cmd_sbp->mtx);
3574 
3575         if (fct_state) {
3576                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3577         }
3578 
3579         return (FCT_SUCCESS);
3580 
3581 } /* emlxs_fct_cmd_accept() */
3582 
3583 
3584 /* Called after receiving fct_cmd from driver */
3585 static fct_status_t
3586 emlxs_fct_cmd_acquire(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3587     uint16_t fct_state)
3588 {
3589         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3590 
3591         if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3592                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3593                     "fct_cmd_acquire: "
3594                     "Bad fct_cmd found! fct_cmd=%p state=%x",
3595                     fct_cmd, fct_state);
3596 
3597                 return (FCT_NOT_FOUND);
3598         }
3599 
3600         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3601                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3602                     "fct_cmd_acquire: "
3603                     "Invalid fct_cmd found! fct_cmd=%p state=%x",
3604                     fct_cmd, fct_state);
3605 
3606                 return (FCT_NOT_FOUND);
3607         }
3608 
3609         if ((cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3610                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3611                     "fct_cmd_acquire: "
3612                     "Returned fct_cmd found! fct_cmd=%p state=%x",
3613                     fct_cmd, fct_state);
3614 
3615                 return (FCT_NOT_FOUND);
3616         }
3617 
3618         mutex_enter(&cmd_sbp->fct_mtx);
3619 
3620         if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
3621                 mutex_exit(&cmd_sbp->fct_mtx);
3622 
3623                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3624                     "fct_cmd_acquire:2 "
3625                     "Bad fct_cmd found! fct_cmd=%p state=%x",
3626                     fct_cmd, fct_state);
3627 
3628                 return (FCT_NOT_FOUND);
3629         }
3630 
3631         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
3632                 mutex_exit(&cmd_sbp->fct_mtx);
3633 
3634                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3635                     "fct_cmd_acquire:2 "
3636                     "Invalid fct_cmd found! fct_cmd=%p state=%x",
3637                     fct_cmd, fct_state);
3638 
3639                 return (FCT_NOT_FOUND);
3640         }
3641 
3642         if ((cmd_sbp->pkt_flags & PACKET_ULP_OWNED)) {
3643                 mutex_exit(&cmd_sbp->fct_mtx);
3644 
3645                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3646                     "fct_cmd_acquire:2 "
3647                     "Returned fct_cmd found! fct_cmd=%p state=%x",
3648                     fct_cmd, fct_state);
3649 
3650                 return (FCT_NOT_FOUND);
3651         }
3652 
3653         if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
3654 
3655                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3656                     "fct_cmd_acquire: "
3657                     "Aborting cmd. fct_cmd=%p state=%x",
3658                     fct_cmd, fct_state);
3659 
3660                 if (fct_cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3661                         TGTPORTSTAT.FctOutstandingIO--;
3662                 }
3663 
3664                 fct_cmd->cmd_comp_status = FCT_FAILURE;
3665 
3666                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_ABORT_DONE);
3667                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3668 
3669                 MODSYM(fct_cmd_fca_aborted) (fct_cmd,
3670                     FCT_ABORT_SUCCESS, FCT_IOF_FCA_DONE);
3671 
3672                 return (FCT_NOT_FOUND);
3673         }
3674 
3675         if (fct_state) {
3676                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3677         }
3678 
3679         return (FCT_SUCCESS);
3680 
3681 } /* emlxs_fct_cmd_acquire() */
3682 
3683 
3684 /* cmd_sbp->fct_mtx must be held to enter */
3685 /* cmd_sbp->fct_mtx must be released before exiting */
3686 /* Called before transitionally sending fct_cmd to driver */
3687 /*ARGSUSED*/
3688 static void
3689 emlxs_fct_cmd_release(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3690     uint16_t fct_state)
3691 {
3692         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3693 
3694         if (fct_state) {
3695                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3696         }
3697 
3698         mutex_exit(&cmd_sbp->fct_mtx);
3699 
3700         return;
3701 
3702 } /* emlxs_fct_cmd_release() */
3703 
3704 
3705 /* cmd_sbp->fct_mtx must be held to enter */
3706 /* cmd_sbp->fct_mtx must be released before exiting */
3707 /* Called before posting fct_cmd back to COMSTAR */
3708 /*ARGSUSED*/
3709 static void
3710 emlxs_fct_cmd_post(emlxs_port_t *port, fct_cmd_t *fct_cmd,
3711     uint16_t fct_state)
3712 {
3713         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3714         fc_packet_t *pkt;
3715 
3716         pkt = cmd_sbp->fct_pkt;
3717         cmd_sbp->fct_pkt = NULL;
3718         cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3719 
3720         mutex_enter(&cmd_sbp->mtx);
3721         cmd_sbp->pkt_flags |= PACKET_ULP_OWNED;
3722         mutex_exit(&cmd_sbp->mtx);
3723 
3724         if (fct_state) {
3725                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3726         }
3727 
3728         mutex_exit(&cmd_sbp->fct_mtx);
3729 
3730         if (pkt) {
3731                 emlxs_pkt_free(pkt);
3732         }
3733 
3734         return;
3735 
3736 } /* emlxs_fct_cmd_post() */
3737 
3738 
3739 /* cmd_sbp->fct_mtx must be held to enter */
3740 /* Called before completing fct_cmd back to COMSTAR */
3741 static void
3742 emlxs_fct_cmd_done(emlxs_port_t *port, fct_cmd_t *fct_cmd, uint16_t fct_state)
3743 {
3744         emlxs_hba_t *hba = HBA;
3745         emlxs_buf_t *cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3746         fc_packet_t *pkt;
3747 
3748         /* Flags fct_cmd is no longer used */
3749         fct_cmd->cmd_oxid = 0;
3750         fct_cmd->cmd_rxid = 0;
3751 
3752         if (cmd_sbp->iotag != 0) {
3753                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3754                     "Pkt still registered! channel=%p iotag=%d sbp=%p",
3755                     cmd_sbp->channel, cmd_sbp->iotag, cmd_sbp);
3756 
3757                 if (cmd_sbp->channel) {
3758                         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
3759                                 emlxs_sli4_free_xri(port, cmd_sbp,
3760                                     cmd_sbp->xrip, 1);
3761                         } else {
3762                                 (void) emlxs_unregister_pkt(cmd_sbp->channel,
3763                                     cmd_sbp->iotag, 0);
3764                         }
3765 
3766                 }
3767         }
3768 
3769         pkt = cmd_sbp->fct_pkt;
3770         cmd_sbp->fct_pkt = NULL;
3771         cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3772 
3773         if (fct_state) {
3774                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, fct_state);
3775         }
3776 
3777         mutex_enter(&cmd_sbp->mtx);
3778         cmd_sbp->pkt_flags |= PACKET_ULP_OWNED;
3779         cmd_sbp->pkt_flags &= ~PACKET_VALID;
3780         mutex_exit(&cmd_sbp->mtx);
3781         mutex_exit(&cmd_sbp->fct_mtx);
3782 
3783 
3784         mutex_destroy(&cmd_sbp->fct_mtx);
3785         mutex_destroy(&cmd_sbp->mtx);
3786 
3787         if (pkt) {
3788                 emlxs_pkt_free(pkt);
3789         }
3790 
3791         return;
3792 
3793 } /* emlxs_fct_cmd_done() */
3794 
3795 
3796 static void
3797 emlxs_fct_pkt_comp(fc_packet_t *pkt)
3798 {
3799         emlxs_port_t *port;
3800 #ifdef FMA_SUPPORT
3801         emlxs_hba_t *hba;
3802 #endif  /* FMA_SUPPORT */
3803         emlxs_buf_t *sbp;
3804         emlxs_buf_t *cmd_sbp;
3805         fct_cmd_t *fct_cmd;
3806         fct_els_t *fct_els;
3807         fct_sol_ct_t *fct_ct;
3808         fct_status_t rval;
3809 
3810         sbp = PKT2PRIV(pkt);
3811         port = sbp->port;
3812 #ifdef FMA_SUPPORT
3813         hba = HBA;
3814 #endif  /* FMA_SUPPORT */
3815         fct_cmd = sbp->fct_cmd;
3816 
3817         rval = emlxs_fct_cmd_acquire(port, fct_cmd, EMLXS_FCT_PKT_COMPLETE);
3818         if (rval) {
3819                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3820                     "fct_pkt_comp: "
3821                     "Unable to reacquire fct_cmd.");
3822                 return;
3823         }
3824         /* mutex_enter(&cmd_sbp->fct_mtx); */
3825 
3826         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
3827         cmd_sbp->fct_flags &= ~EMLXS_FCT_IO_INP;
3828         cmd_sbp->fct_pkt = NULL;
3829 
3830         switch (fct_cmd->cmd_type) {
3831         case FCT_CMD_FCP_XCHG:
3832                 if ((pkt->pkt_reason == FC_REASON_ABORTED) ||
3833                     (pkt->pkt_reason == FC_REASON_XCHG_DROPPED) ||
3834                     (pkt->pkt_reason == FC_REASON_OFFLINE)) {
3835                         /*
3836                          * The error indicates this IO should be terminated
3837                          * immediately.
3838                          */
3839                         cmd_sbp->fct_flags &= ~EMLXS_FCT_SEND_STATUS;
3840 
3841                         emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
3842                         /* mutex_exit(&cmd_sbp->fct_mtx); */
3843 
3844 #ifdef FCT_API_TRACE
3845                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3846                             "fct_queue_cmd_for_termination:2 %p:%p x%x",
3847                             fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3848 #endif /* FCT_API_TRACE */
3849 
3850                         MODSYM(fct_queue_cmd_for_termination) (fct_cmd,
3851                             FCT_ABTS_RECEIVED);
3852 
3853                         break;
3854                 }
3855 
3856                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3857                     EMLXS_FCT_PKT_FCPRSP_COMPLETE);
3858 
3859                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3860                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3861 
3862 #ifdef FCT_API_TRACE
3863                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3864                     "fct_send_response_done:2 %p:%p x%x outio %d",
3865                     fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status,
3866                     TGTPORTSTAT.FctOutstandingIO);
3867 #else
3868                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3869                     "fct_pkt_comp: fct_send_response_done. dbuf=%p",
3870                     sbp->fct_buf);
3871 #endif /* FCT_API_TRACE */
3872 
3873                 TGTPORTSTAT.FctOutstandingIO--;
3874 
3875                 MODSYM(fct_send_response_done) (fct_cmd,
3876                     fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3877 
3878                 break;
3879 
3880         case FCT_CMD_RCVD_ELS:
3881 
3882                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3883                     EMLXS_FCT_PKT_ELSRSP_COMPLETE);
3884 
3885                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3886                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3887 
3888 #ifdef FCT_API_TRACE
3889                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3890                     "fct_send_response_done:3 %p:%p x%x",
3891                     fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3892 #endif /* FCT_API_TRACE */
3893 
3894                 MODSYM(fct_send_response_done) (fct_cmd,
3895                     fct_cmd->cmd_comp_status, FCT_IOF_FCA_DONE);
3896 
3897                 break;
3898 
3899         case FCT_CMD_SOL_ELS:
3900 
3901                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3902                     EMLXS_FCT_PKT_ELSCMD_COMPLETE);
3903 
3904                 fct_els = (fct_els_t *)fct_cmd->cmd_specific;
3905 
3906                 if (fct_els->els_resp_payload) {
3907                         EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0,
3908                             pkt->pkt_rsplen, DDI_DMA_SYNC_FORKERNEL);
3909 
3910                         bcopy((uint8_t *)pkt->pkt_resp,
3911                             (uint8_t *)fct_els->els_resp_payload,
3912                             fct_els->els_resp_size);
3913                 }
3914 
3915                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3916                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3917 
3918 #ifdef FCT_API_TRACE
3919                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3920                     "fct_send_cmd_done:1 %p:%p x%x",
3921                     fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3922 #endif /* FCT_API_TRACE */
3923 
3924 #ifdef FMA_SUPPORT
3925                 if (emlxs_fm_check_dma_handle(hba, pkt->pkt_resp_dma)
3926                     != DDI_FM_OK) {
3927                         EMLXS_MSGF(EMLXS_CONTEXT,
3928                             &emlxs_invalid_dma_handle_msg,
3929                             "fct_pkt_comp: hdl=%p",
3930                             pkt->pkt_resp_dma);
3931                         MODSYM(fct_send_cmd_done) (fct_cmd, FCT_FAILURE,
3932                             FCT_IOF_FCA_DONE);
3933 
3934                         break;
3935                 }
3936 #endif /* FMA_SUPPORT */
3937 
3938                 MODSYM(fct_send_cmd_done) (fct_cmd, FCT_SUCCESS,
3939                     FCT_IOF_FCA_DONE);
3940 
3941                 break;
3942 
3943         case FCT_CMD_SOL_CT:
3944 
3945                 EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp,
3946                     EMLXS_FCT_PKT_CTCMD_COMPLETE);
3947 
3948                 fct_ct = (fct_sol_ct_t *)fct_cmd->cmd_specific;
3949 
3950                 if (fct_ct->ct_resp_payload) {
3951                         EMLXS_MPDATA_SYNC(pkt->pkt_resp_dma, 0,
3952                             pkt->pkt_rsplen, DDI_DMA_SYNC_FORKERNEL);
3953 
3954                         bcopy((uint8_t *)pkt->pkt_resp,
3955                             (uint8_t *)fct_ct->ct_resp_payload,
3956                             fct_ct->ct_resp_size);
3957                 }
3958 
3959                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3960                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3961 
3962 #ifdef FCT_API_TRACE
3963                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
3964                     "fct_send_cmd_done:2 %p:%p x%x",
3965                     fct_cmd, cmd_sbp, fct_cmd->cmd_comp_status);
3966 #endif /* FCT_API_TRACE */
3967 
3968 #ifdef FMA_SUPPORT
3969                 if (emlxs_fm_check_dma_handle(hba, pkt->pkt_resp_dma)
3970                     != DDI_FM_OK) {
3971                         EMLXS_MSGF(EMLXS_CONTEXT,
3972                             &emlxs_invalid_dma_handle_msg,
3973                             "fct_pkt_comp: hdl=%p",
3974                             pkt->pkt_resp_dma);
3975                         MODSYM(fct_send_cmd_done) (fct_cmd, FCT_FAILURE,
3976                             FCT_IOF_FCA_DONE);
3977 
3978                         break;
3979                 }
3980 #endif /* FMA_SUPPORT */
3981                 MODSYM(fct_send_cmd_done) (fct_cmd, FCT_SUCCESS,
3982                     FCT_IOF_FCA_DONE);
3983 
3984                 break;
3985 
3986         default:
3987                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
3988                     "fct_pkt_comp: Invalid cmd type found. type=%x",
3989                     fct_cmd->cmd_type);
3990 
3991                 emlxs_fct_cmd_done(port, fct_cmd, EMLXS_FCT_IO_DONE);
3992                 /* mutex_exit(&cmd_sbp->fct_mtx); */
3993 
3994                 break;
3995         }
3996 
3997         emlxs_pkt_free(pkt);
3998         return;
3999 
4000 } /* emlxs_fct_pkt_comp() */
4001 
4002 
4003 static void
4004 emlxs_fct_abort_pkt_comp(fc_packet_t *pkt)
4005 {
4006 #ifdef FCT_API_TRACE
4007         emlxs_buf_t *sbp;
4008         IOCBQ *iocbq;
4009         IOCB *iocb;
4010         emlxs_port_t *port;
4011 
4012         sbp = PKT2PRIV(pkt);
4013         port = sbp->port;
4014         iocbq = &sbp->iocbq;
4015         iocb = &iocbq->iocb;
4016 
4017         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4018             "fct_abort_pkt_comp: %p: xri=%d cmd=%x status=%x",
4019             sbp->fct_cmd, sbp,
4020             iocb->ULPCONTEXT, iocb->ULPCOMMAND, iocb->ULPSTATUS);
4021 #endif /* FCT_API_TRACE */
4022 
4023         emlxs_pkt_free(pkt);
4024         return;
4025 
4026 } /* emlxs_fct_abort_pkt_comp() */
4027 
4028 
4029 /* COMSTAR ENTER POINT (INDIRECT) */
4030 static fct_status_t
4031 emlxs_fct_send_els_cmd(fct_cmd_t *fct_cmd)
4032 {
4033         emlxs_port_t *port =
4034             (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4035         emlxs_hba_t *hba = HBA;
4036         uint32_t did;
4037         uint32_t sid;
4038         fct_els_t *fct_els;
4039         fc_packet_t *pkt;
4040         emlxs_buf_t *cmd_sbp;
4041         fct_status_t rval;
4042 
4043         did = fct_cmd->cmd_rportid;
4044         sid = fct_cmd->cmd_lportid;
4045         fct_els = (fct_els_t *)fct_cmd->cmd_specific;
4046 
4047         if (!(pkt = emlxs_pkt_alloc(port, fct_els->els_req_size,
4048             fct_els->els_resp_size, 0, KM_NOSLEEP))) {
4049                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4050                     "fct_send_els_cmd: Unable to allocate packet.");
4051 
4052                 return (FCT_BUSY);
4053         }
4054 
4055         cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_SEND_ELS_REQ);
4056         /* mutex_enter(&cmd_sbp->fct_mtx); */
4057 
4058         cmd_sbp->channel = &hba->chan[hba->channel_els];
4059         cmd_sbp->fct_type = EMLXS_FCT_ELS_REQ;
4060 
4061         (void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4062         cmd_sbp->fct_pkt = pkt;
4063 
4064         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4065         pkt->pkt_timeout =
4066             ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4067         pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
4068         pkt->pkt_comp = emlxs_fct_pkt_comp;
4069 
4070         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4071             "fct_send_els_cmd: pkt_timeout=%d ratov=%d",
4072             pkt->pkt_timeout, hba->fc_ratov);
4073 
4074         /* Build the fc header */
4075         pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4076         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_REQ;
4077         pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(sid);
4078         pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4079         pkt->pkt_cmd_fhdr.f_ctl =
4080             F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
4081         pkt->pkt_cmd_fhdr.seq_id = 0;
4082         pkt->pkt_cmd_fhdr.df_ctl = 0;
4083         pkt->pkt_cmd_fhdr.seq_cnt = 0;
4084         pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
4085         pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
4086         pkt->pkt_cmd_fhdr.ro = 0;
4087 
4088         /* Copy the cmd payload */
4089         bcopy((uint8_t *)fct_els->els_req_payload, (uint8_t *)pkt->pkt_cmd,
4090             fct_els->els_req_size);
4091 
4092         cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4093         emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_REQ_PENDING);
4094         /* mutex_exit(&cmd_sbp->fct_mtx); */
4095 
4096         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4097 
4098                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4099                     "fct_send_els_cmd: Unable to send packet.");
4100 
4101                 /* Reacquire ownership of the fct_cmd */
4102                 rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4103                 if (rval) {
4104                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4105                             "fct_send_els_cmd: "
4106                             "Unable to reacquire fct_cmd.");
4107                         return (rval);
4108                 }
4109                 /* mutex_enter(&cmd_sbp->fct_mtx); */
4110 
4111                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
4112                 /* mutex_exit(&cmd_sbp->fct_mtx); */
4113 
4114                 return (FCT_BUSY);
4115         }
4116 
4117         return (FCT_SUCCESS);
4118 
4119 } /* emlxs_fct_send_els_cmd() */
4120 
4121 
4122 /* cmd_sbp->fct_mtx must be held to enter */
4123 /* cmd_sbp->fct_mtx must be released before exiting */
4124 static fct_status_t
4125 emlxs_fct_send_els_rsp(fct_cmd_t *fct_cmd)
4126 {
4127         emlxs_port_t *port =
4128             (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4129         emlxs_hba_t *hba = HBA;
4130         uint32_t did;
4131         uint32_t sid;
4132         fct_els_t *fct_els;
4133         fc_packet_t *pkt;
4134         emlxs_buf_t *cmd_sbp;
4135         fct_status_t rval;
4136 
4137         fct_els = (fct_els_t *)fct_cmd->cmd_specific;
4138         did = fct_cmd->cmd_rportid;
4139         sid = fct_cmd->cmd_lportid;
4140         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
4141 
4142         if (!(pkt = emlxs_pkt_alloc(port, fct_els->els_resp_size, 0, 0,
4143             KM_NOSLEEP))) {
4144                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4145                     "fct_send_els_rsp: Unable to allocate packet.");
4146 
4147                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
4148                 /* mutex_exit(&cmd_sbp->fct_mtx); */
4149 
4150                 return (FCT_FAILURE);
4151         }
4152 
4153         EMLXS_FCT_STATE_CHG(fct_cmd, cmd_sbp, EMLXS_FCT_SEND_ELS_RSP);
4154 
4155         cmd_sbp->fct_type = EMLXS_FCT_ELS_RSP;
4156 
4157         (void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4158         cmd_sbp->fct_pkt = pkt;
4159 
4160         pkt->pkt_tran_type = FC_PKT_OUTBOUND;
4161         pkt->pkt_timeout =
4162             ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4163         pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
4164         pkt->pkt_comp = emlxs_fct_pkt_comp;
4165 
4166         /* Build the fc header */
4167         pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4168         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_ELS_RSP;
4169         pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(sid);
4170         pkt->pkt_cmd_fhdr.type = FC_TYPE_EXTENDED_LS;
4171         pkt->pkt_cmd_fhdr.f_ctl =
4172             F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ;
4173         pkt->pkt_cmd_fhdr.seq_id = 0;
4174         pkt->pkt_cmd_fhdr.df_ctl = 0;
4175         pkt->pkt_cmd_fhdr.seq_cnt = 0;
4176         pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
4177         pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
4178         pkt->pkt_cmd_fhdr.ro = 0;
4179 
4180         /* Copy the resp payload to pkt_cmd buffer */
4181         bcopy((uint8_t *)fct_els->els_resp_payload, (uint8_t *)pkt->pkt_cmd,
4182             fct_els->els_resp_size);
4183 
4184         cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4185         emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_RSP_PENDING);
4186         /* mutex_exit(&cmd_sbp->fct_mtx); */
4187 
4188         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4189 
4190                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4191                     "fct_send_els_rsp: Unable to send packet.");
4192 
4193                 /* Reacquire ownership of the fct_cmd */
4194                 rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4195                 if (rval) {
4196                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4197                             "fct_send_els_rsp: "
4198                             "Unable to reacquire fct_cmd.");
4199                         return (rval);
4200                 }
4201                 /* mutex_enter(&cmd_sbp->fct_mtx); */
4202 
4203                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_CMD_POSTED);
4204                 /* mutex_exit(&cmd_sbp->fct_mtx); */
4205 
4206                 return (FCT_FAILURE);
4207         }
4208 
4209         return (FCT_SUCCESS);
4210 
4211 } /* emlxs_fct_send_els_rsp() */
4212 
4213 
4214 /* COMSTAR ENTER POINT (INDIRECT) */
4215 static fct_status_t
4216 emlxs_fct_send_ct_cmd(fct_cmd_t *fct_cmd)
4217 {
4218         emlxs_port_t *port =
4219             (emlxs_port_t *)fct_cmd->cmd_port->port_fca_private;
4220         emlxs_hba_t *hba = HBA;
4221         uint32_t did;
4222         fct_sol_ct_t *fct_ct;
4223         fc_packet_t *pkt;
4224         emlxs_buf_t *cmd_sbp;
4225         fct_status_t rval;
4226 
4227         did = fct_cmd->cmd_rportid;
4228         fct_ct = (fct_sol_ct_t *)fct_cmd->cmd_specific;
4229 
4230         if (!(pkt = emlxs_pkt_alloc(port, fct_ct->ct_req_size,
4231             fct_ct->ct_resp_size, 0, KM_NOSLEEP))) {
4232                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4233                     "fct_send_ct_cmd: Unable to allocate packet.");
4234                 return (FCT_BUSY);
4235         }
4236 
4237         cmd_sbp = emlxs_fct_cmd_init(port, fct_cmd, EMLXS_FCT_SEND_CT_REQ);
4238         /* mutex_enter(&cmd_sbp->fct_mtx); */
4239 
4240         cmd_sbp->channel = &hba->chan[hba->channel_ct];
4241         cmd_sbp->fct_type = EMLXS_FCT_CT_REQ;
4242 
4243         (void) emlxs_fct_pkt_init(port, fct_cmd, pkt);
4244         cmd_sbp->fct_pkt = pkt;
4245 
4246         pkt->pkt_tran_type = FC_PKT_EXCHANGE;
4247         pkt->pkt_timeout =
4248             ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4249         pkt->pkt_timeout = (pkt->pkt_timeout > 60)? 60: pkt->pkt_timeout;
4250         pkt->pkt_comp = emlxs_fct_pkt_comp;
4251 
4252         /* Build the fc header */
4253         pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(did);
4254         pkt->pkt_cmd_fhdr.r_ctl = R_CTL_UNSOL_CONTROL;
4255         pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4256         pkt->pkt_cmd_fhdr.type = FC_TYPE_FC_SERVICES;
4257         pkt->pkt_cmd_fhdr.f_ctl =
4258             F_CTL_FIRST_SEQ | F_CTL_END_SEQ | F_CTL_SEQ_INITIATIVE;
4259         pkt->pkt_cmd_fhdr.seq_id = 0;
4260         pkt->pkt_cmd_fhdr.df_ctl = 0;
4261         pkt->pkt_cmd_fhdr.seq_cnt = 0;
4262         pkt->pkt_cmd_fhdr.ox_id = 0xFFFF;
4263         pkt->pkt_cmd_fhdr.rx_id = 0xFFFF;
4264         pkt->pkt_cmd_fhdr.ro = 0;
4265 
4266         /* Copy the cmd payload */
4267         bcopy((uint8_t *)fct_ct->ct_req_payload, (uint8_t *)pkt->pkt_cmd,
4268             fct_ct->ct_req_size);
4269 
4270         cmd_sbp->fct_flags |= EMLXS_FCT_IO_INP;
4271         emlxs_fct_cmd_release(port, fct_cmd, EMLXS_FCT_REQ_PENDING);
4272         /* mutex_exit(&cmd_sbp->fct_mtx); */
4273 
4274         if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4275 
4276                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4277                     "fct_send_ct_cmd: Unable to send packet.");
4278 
4279                 /* Reacquire ownership of the fct_cmd */
4280                 rval = emlxs_fct_cmd_acquire(port, fct_cmd, 0);
4281                 if (rval) {
4282                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4283                             "fct_send_ct_cmd: "
4284                             "Unable to reacquire fct_cmd.");
4285 
4286                         return (rval);
4287                 }
4288                 /* mutex_enter(&cmd_sbp->fct_mtx); */
4289 
4290                 emlxs_fct_cmd_post(port, fct_cmd, EMLXS_FCT_OWNED);
4291                 /* mutex_exit(&cmd_sbp->fct_mtx); */
4292 
4293                 return (FCT_BUSY);
4294         }
4295 
4296         return (FCT_SUCCESS);
4297 
4298 } /* emlxs_fct_send_ct_cmd() */
4299 
4300 
4301 /* cmd_sbp->fct_mtx must be held to enter */
4302 static uint32_t
4303 emlxs_fct_pkt_abort_txq(emlxs_port_t *port, emlxs_buf_t *cmd_sbp)
4304 {
4305         emlxs_hba_t *hba = HBA;
4306         NODELIST *nlp;
4307         fc_packet_t *pkt;
4308         emlxs_buf_t *sbp;
4309         emlxs_buf_t *iocb_sbp;
4310         uint8_t channelno;
4311         CHANNEL *cp;
4312         IOCBQ *iocbq;
4313         IOCBQ *next;
4314         IOCBQ *prev;
4315         uint32_t found;
4316         uint32_t pkt_flags;
4317 
4318         /* Check the transmit queue */
4319         mutex_enter(&EMLXS_TX_CHANNEL_LOCK);
4320 
4321         /* The IOCB could point to a cmd_sbp (no packet) or a sbp (packet) */
4322         pkt = cmd_sbp->fct_pkt;
4323         if (pkt) {
4324                 sbp = PKT2PRIV(pkt);
4325                 if (sbp == NULL) {
4326                         goto done;
4327                 }
4328                 iocb_sbp = sbp;
4329                 iocbq = &sbp->iocbq;
4330                 pkt_flags = sbp->pkt_flags;
4331         } else {
4332                 sbp = NULL;
4333                 iocb_sbp = cmd_sbp;
4334                 iocbq = &cmd_sbp->iocbq;
4335                 pkt_flags = cmd_sbp->pkt_flags;
4336         }
4337 
4338         nlp = (NODELIST *)cmd_sbp->node;
4339         cp = (CHANNEL *)cmd_sbp->channel;
4340         channelno = (cp) ? cp->channelno : 0;
4341 
4342         if (pkt_flags & PACKET_IN_TXQ) {
4343                 /* Find it on the queue */
4344                 found = 0;
4345                 if (iocbq->flag & IOCB_PRIORITY) {
4346                         /* Search the priority queue */
4347                         prev = NULL;
4348                         next = (IOCBQ *)nlp->nlp_ptx[channelno].q_first;
4349 
4350                         while (next) {
4351                                 if (next == iocbq) {
4352                                         /* Remove it */
4353                                         if (prev) {
4354                                                 prev->next = iocbq->next;
4355                                         }
4356 
4357                                         if (nlp->nlp_ptx[channelno].q_last ==
4358                                             (void *)iocbq) {
4359                                                 nlp->nlp_ptx[channelno].q_last =
4360                                                     (void *)prev;
4361                                         }
4362 
4363                                         if (nlp->nlp_ptx[channelno].q_first ==
4364                                             (void *)iocbq) {
4365                                                 nlp->nlp_ptx[channelno].
4366                                                     q_first =
4367                                                     (void *)iocbq->next;
4368                                         }
4369 
4370                                         nlp->nlp_ptx[channelno].q_cnt--;
4371                                         iocbq->next = NULL;
4372                                         found = 1;
4373                                         break;
4374                                 }
4375 
4376                                 prev = next;
4377                                 next = next->next;
4378                         }
4379                 } else {
4380                         /* Search the normal queue */
4381                         prev = NULL;
4382                         next = (IOCBQ *)nlp->nlp_tx[channelno].q_first;
4383 
4384                         while (next) {
4385                                 if (next == iocbq) {
4386                                         /* Remove it */
4387                                         if (prev) {
4388                                                 prev->next = iocbq->next;
4389                                         }
4390 
4391                                         if (nlp->nlp_tx[channelno].q_last ==
4392                                             (void *)iocbq) {
4393                                                 nlp->nlp_tx[channelno].q_last =
4394                                                     (void *)prev;
4395                                         }
4396 
4397                                         if (nlp->nlp_tx[channelno].q_first ==
4398                                             (void *)iocbq) {
4399                                                 nlp->nlp_tx[channelno].q_first =
4400                                                     (void *)iocbq->next;
4401                                         }
4402 
4403                                         nlp->nlp_tx[channelno].q_cnt--;
4404                                         iocbq->next = NULL;
4405                                         found = 1;
4406                                         break;
4407                                 }
4408 
4409                                 prev = next;
4410                                 next = (IOCBQ *)next->next;
4411                         }
4412                 }
4413 
4414                 if (!found) {
4415                         goto done;
4416                 }
4417 
4418                 /* Check if node still needs servicing */
4419                 if ((nlp->nlp_ptx[channelno].q_first) ||
4420                     (nlp->nlp_tx[channelno].q_first &&
4421                     !(nlp->nlp_flag[channelno] & NLP_CLOSED))) {
4422 
4423                         /*
4424                          * If this is the base node, don't shift the pointers
4425                          */
4426                         /* We want to drain the base node before moving on */
4427                         if (!nlp->nlp_base) {
4428                                 /* Shift channel queue pointers to next node */
4429                                 cp->nodeq.q_last = (void *)nlp;
4430                                 cp->nodeq.q_first = nlp->nlp_next[channelno];
4431                         }
4432                 } else {
4433                         /* Remove node from channel queue */
4434 
4435                         /* If this is the last node on list */
4436                         if (cp->nodeq.q_last == (void *)nlp) {
4437                                 cp->nodeq.q_last = NULL;
4438                                 cp->nodeq.q_first = NULL;
4439                                 cp->nodeq.q_cnt = 0;
4440                         } else {
4441                                 /* Remove node from head */
4442                                 cp->nodeq.q_first = nlp->nlp_next[channelno];
4443                                 ((NODELIST *)cp->nodeq.q_last)->
4444                                     nlp_next[channelno] = cp->nodeq.q_first;
4445                                 cp->nodeq.q_cnt--;
4446                         }
4447 
4448                         /* Clear node */
4449                         nlp->nlp_next[channelno] = NULL;
4450                 }
4451 
4452                 /* The IOCB points to iocb_sbp (no packet) or a sbp (packet) */
4453                 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4454                         emlxs_sli4_free_xri(port, iocb_sbp, iocb_sbp->xrip, 1);
4455                 } else {
4456                         (void) emlxs_unregister_pkt(cp, iocb_sbp->iotag, 0);
4457                 }
4458 
4459                 mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
4460 
4461                 if (pkt) {
4462                         emlxs_pkt_free(pkt);
4463                         cmd_sbp->fct_pkt = NULL;
4464                 }
4465                 return (1);
4466         }
4467 done:
4468         mutex_exit(&EMLXS_TX_CHANNEL_LOCK);
4469         return (0);
4470 
4471 } /* emlxs_fct_pkt_abort_txq() */
4472 
4473 
4474 /* COMSTAR ENTER POINT */
4475 /* FCT_NOT_FOUND & FCT_ABORT_SUCCESS indicates IO is done */
4476 /* FCT_SUCCESS indicates abort will occur asyncronously */
4477 static fct_status_t
4478 emlxs_fct_abort(fct_local_port_t *fct_port, fct_cmd_t *fct_cmd,
4479     uint32_t flags)
4480 {
4481         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
4482         emlxs_hba_t *hba = HBA;
4483         emlxs_buf_t *cmd_sbp;
4484         emlxs_buf_t *cmd_sbp2;
4485         emlxs_buf_t *prev;
4486         fc_packet_t *pkt;
4487         emlxs_buf_t *sbp = NULL;
4488         kmutex_t *fct_mtx;
4489         uint32_t fct_state;
4490 
4491         cmd_sbp = (emlxs_buf_t *)fct_cmd->cmd_fca_private;
4492         fct_mtx = &cmd_sbp->fct_mtx;
4493 
4494 top:
4495 
4496         /* Sanity check */
4497         if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
4498                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4499                     "fct_abort: Bad fct_cmd=%p.", fct_cmd);
4500 
4501                 return (FCT_NOT_FOUND);
4502         }
4503 
4504         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
4505                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4506                     "fct_abort: Pkt invalid. cmd_sbp=%p",
4507                     cmd_sbp);
4508 
4509                 return (FCT_NOT_FOUND);
4510         }
4511 
4512         if (mutex_tryenter(fct_mtx) == 0) {
4513                 /*
4514                  * This code path handles a race condition if
4515                  * an IO completes, in emlxs_fct_handle_fcp_event(),
4516                  * and we get an abort at the same time.
4517                  */
4518                 delay(drv_usectohz(100000));    /* 100 msec */
4519                 goto top;
4520         }
4521         /* At this point, we have entered the mutex */
4522 
4523         /* Sanity check */
4524         if ((fct_cmd->cmd_oxid == 0) && (fct_cmd->cmd_rxid == 0)) {
4525                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4526                     "fct_abort: Bad fct_cmd=%p.", fct_cmd);
4527 
4528                 mutex_exit(fct_mtx);
4529                 return (FCT_NOT_FOUND);
4530         }
4531 
4532         if (!(cmd_sbp->pkt_flags & PACKET_VALID)) {
4533                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4534                     "fct_abort: Pkt invalid. cmd_sbp=%p",
4535                     cmd_sbp);
4536 
4537                 mutex_exit(fct_mtx);
4538                 return (FCT_NOT_FOUND);
4539         }
4540 
4541         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4542             "fct_abort: hbastate=%x. "
4543             "xid=%x,%x cmd_sbp=%p fctstate=%d flags=%x,%x,%x",
4544             hba->state, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid, cmd_sbp,
4545             cmd_sbp->fct_state, flags, cmd_sbp->fct_flags, cmd_sbp->pkt_flags);
4546 
4547         if (cmd_sbp->fct_flags & EMLXS_FCT_ABORT_INP) {
4548                 EMLXS_SLI_ISSUE_IOCB_CMD(hba, cmd_sbp->channel, 0);
4549 
4550                 /* If Abort is already in progress */
4551                 mutex_exit(fct_mtx);
4552                 return (FCT_SUCCESS);
4553         }
4554         cmd_sbp->fct_flags |= EMLXS_FCT_ABORT_INP;
4555 
4556         if (flags & FCT_IOF_FORCE_FCA_DONE) {
4557                 fct_cmd->cmd_handle = 0;
4558         }
4559 
4560         TGTPORTSTAT.FctAbortSent++;
4561 
4562         switch (cmd_sbp->fct_state) {
4563         /* These are currently owned by COMSTAR. */
4564         /* They were last processed by emlxs_fct_cmd_post() */
4565         /* We have NO exchange resources associated with this IO. */
4566         case EMLXS_FCT_OWNED:
4567                 goto abort_done;
4568 
4569         /* These are on the unsol waitQ in the driver */
4570         case EMLXS_FCT_CMD_WAITQ:
4571                 /* Find and remove it */
4572                 mutex_enter(&EMLXS_PORT_LOCK);
4573                 cmd_sbp2 = port->fct_wait_head;
4574                 prev = NULL;
4575                 while (cmd_sbp2) {
4576                         if (cmd_sbp2 == cmd_sbp) {
4577                                 /* Remove it */
4578                                 if (prev) {
4579                                         prev->next = cmd_sbp2->next;
4580                                 }
4581 
4582                                 if (port->fct_wait_head == cmd_sbp2) {
4583                                         port->fct_wait_head = cmd_sbp2->next;
4584                                 }
4585 
4586                                 if (port->fct_wait_tail == cmd_sbp2) {
4587                                         port->fct_wait_tail = prev;
4588                                 }
4589 
4590                                 cmd_sbp2->next = NULL;
4591                                 break;
4592                         }
4593                         prev = cmd_sbp2;
4594                         cmd_sbp2 = cmd_sbp2->next;
4595                 }
4596                 mutex_exit(&EMLXS_PORT_LOCK);
4597 
4598                 /*FALLTHROUGH*/
4599 
4600         /* These are currently owned by COMSTAR. */
4601         /* They were last processed by emlxs_fct_cmd_post() */
4602         /* We have residual exchange resources associated with this IO */
4603         case EMLXS_FCT_CMD_POSTED:
4604                 switch (fct_cmd->cmd_type) {
4605                 case FCT_CMD_FCP_XCHG: /* Unsol */
4606                         TGTPORTSTAT.FctOutstandingIO--;
4607                         emlxs_abort_fct_exchange(hba, port, fct_cmd->cmd_rxid);
4608                         break;
4609 
4610                 case FCT_CMD_RCVD_ELS: /* Unsol */
4611                         emlxs_abort_els_exchange(hba, port, fct_cmd->cmd_rxid);
4612                         break;
4613                 }
4614 
4615                 goto abort_done;
4616 
4617         /* These are active in the driver */
4618         /* They were last processed by emlxs_fct_cmd_release() */
4619         case EMLXS_FCT_RSP_PENDING:
4620         case EMLXS_FCT_REQ_PENDING:
4621         case EMLXS_FCT_REG_PENDING:
4622         case EMLXS_FCT_DATA_PENDING:
4623         case EMLXS_FCT_STATUS_PENDING:
4624 
4625                 /* Abort anything pending */
4626                 if (emlxs_fct_pkt_abort_txq(port, cmd_sbp)) {
4627 
4628                         if (fct_cmd->cmd_type == FCT_CMD_FCP_XCHG) {
4629                                 TGTPORTSTAT.FctOutstandingIO--;
4630                         }
4631 
4632                         goto abort_done;
4633                 }
4634 
4635                 /* If we're not online, then all IO will be flushed anyway */
4636                 if (!(hba->flag & FC_ONLINE_MODE)) {
4637                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4638                             "fct_abort: Not online. fct_cmd=%p.",
4639                             fct_cmd);
4640 
4641                         emlxs_fct_cmd_release(port, fct_cmd, 0);
4642                         /* mutex_exit(&cmd_sbp->fct_mtx); */
4643 
4644                         /* The cmd will be aborted on the */
4645                         /* next emlxs_fct_cmd_acquire */
4646                         /* because EMLXS_FCT_ABORT_INP is set. */
4647                         break;
4648                 }
4649 
4650                 /* Try to send abort request */
4651                 if (!(pkt = emlxs_pkt_alloc(port, 0, 0, 0, KM_NOSLEEP))) {
4652                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4653                             "fct_abort: Unable to allocate packet. "
4654                             "fct_cmd=%p",
4655                             fct_cmd);
4656 
4657                         emlxs_fct_cmd_release(port, fct_cmd, 0);
4658                         /* mutex_exit(&cmd_sbp->fct_mtx); */
4659 
4660                         /* The cmd will be aborted on the */
4661                         /* next emlxs_fct_cmd_acquire anyway */
4662                         /* because EMLXS_FCT_ABORT_INP is set. */
4663                         break;
4664                 }
4665 
4666                 sbp = emlxs_fct_pkt_init(port, fct_cmd, pkt);
4667 
4668                 pkt->pkt_tran_type = FC_PKT_OUTBOUND;
4669                 pkt->pkt_timeout =
4670                     ((2 * hba->fc_ratov) < 30) ? 30 : (2 * hba->fc_ratov);
4671                 pkt->pkt_comp = emlxs_fct_abort_pkt_comp;
4672 
4673                 /* Build the fc header */
4674                 pkt->pkt_cmd_fhdr.d_id = LE_SWAP24_LO(fct_cmd->cmd_rportid);
4675                 pkt->pkt_cmd_fhdr.r_ctl = R_CTL_STATUS;
4676                 pkt->pkt_cmd_fhdr.s_id = LE_SWAP24_LO(port->did);
4677                 pkt->pkt_cmd_fhdr.type = FC_TYPE_BASIC_LS;
4678                 pkt->pkt_cmd_fhdr.f_ctl =
4679                     (F_CTL_XCHG_CONTEXT | F_CTL_LAST_SEQ | F_CTL_END_SEQ);
4680                 pkt->pkt_cmd_fhdr.seq_id = 0;
4681                 pkt->pkt_cmd_fhdr.df_ctl = 0;
4682                 pkt->pkt_cmd_fhdr.seq_cnt = 0;
4683                 pkt->pkt_cmd_fhdr.ox_id = fct_cmd->cmd_oxid;
4684                 pkt->pkt_cmd_fhdr.rx_id = fct_cmd->cmd_rxid;
4685                 pkt->pkt_cmd_fhdr.ro = 0;
4686 
4687                 /* Make sure xrip is setup */
4688                 if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4689                         if (!sbp->xrip || sbp->xrip->state == XRI_STATE_FREE) {
4690                                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4691                                     "fct_abort: "
4692                                     "Unable to acquire xri. (xid:%x,%x)",
4693                                     fct_cmd->cmd_oxid, fct_cmd->cmd_rxid);
4694 
4695                                 emlxs_pkt_free(pkt);
4696                                 return (FCT_NOT_FOUND);
4697                         }
4698                 }
4699 
4700                 cmd_sbp->fct_cmd = fct_cmd;
4701                 cmd_sbp->abort_attempts++;
4702 
4703                 /* Now disassociate the sbp / pkt from the fct_cmd */
4704                 sbp->fct_cmd = NULL;
4705 
4706                 if (hba->state >= FC_LINK_UP) {
4707                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4708                             "fct_abort: ABORT: %p xid:%x,%x",
4709                             fct_cmd, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid);
4710 
4711                         fct_state = EMLXS_FCT_ABORT_PENDING;
4712 
4713                 } else {
4714                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4715                             "fct_abort: CLOSE: %p xid:%x,%x",
4716                             fct_cmd, fct_cmd->cmd_oxid, fct_cmd->cmd_rxid);
4717 
4718                         fct_state = EMLXS_FCT_CLOSE_PENDING;
4719                 }
4720 
4721                 emlxs_fct_cmd_release(port, fct_cmd, fct_state);
4722                 /* mutex_exit(&cmd_sbp->fct_mtx); */
4723 
4724                 if (emlxs_pkt_send(pkt, 1) != FC_SUCCESS) {
4725                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4726                             "fct_abort: Unable to send abort packet.");
4727 
4728                         emlxs_pkt_free(pkt);
4729 
4730                         /* The cmd will be aborted on the */
4731                         /* next emlxs_fct_cmd_acquire anyway */
4732                         /* because EMLXS_FCT_ABORT_INP is set. */
4733                 }
4734 
4735                 break;
4736 
4737         default:
4738                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_error_msg,
4739                     "fct_abort: Unexpected fct_state. "
4740                     "fct_cmd=%p state=%d",
4741                     fct_cmd, cmd_sbp->fct_state);
4742 
4743                 emlxs_fct_cmd_release(port, fct_cmd, 0);
4744                 /* mutex_exit(&cmd_sbp->fct_mtx); */
4745 
4746                 /* The cmd will be aborted on the */
4747                 /* next emlxs_fct_cmd_acquire anyway */
4748                 /* because EMLXS_FCT_ABORT_INP is set. */
4749 
4750         }       /* switch */
4751 
4752         return (FCT_SUCCESS);
4753 
4754 abort_done:
4755 
4756         emlxs_fct_cmd_done(port, fct_cmd,
4757             EMLXS_FCT_ABORT_DONE);
4758         /* mutex_exit(&cmd_sbp->fct_mtx); */
4759 
4760         return (FCT_ABORT_SUCCESS);
4761 
4762 } /* emlxs_fct_abort() */
4763 
4764 
4765 extern void
4766 emlxs_fct_link_up(emlxs_port_t *port)
4767 {
4768         emlxs_hba_t *hba = HBA;
4769 
4770         mutex_enter(&EMLXS_PORT_LOCK);
4771 #ifdef FCT_API_TRACE
4772         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4773             "fct_link_up port %p fct flags x%x",
4774             port->fct_port, port->fct_flags);
4775 #endif /* FCT_API_TRACE */
4776 
4777         if (port->fct_port &&
4778             (port->fct_flags & FCT_STATE_PORT_ONLINE) &&
4779             !(port->fct_flags & FCT_STATE_LINK_UP)) {
4780                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4781                     "fct_link_up event.");
4782 
4783                 port->fct_flags &= ~FCT_STATE_LINK_UP_ACKED;
4784                 port->fct_flags &= ~FCT_STATE_FLOGI_CMPL;
4785                 port->fct_flags |= FCT_STATE_LINK_UP;
4786                 mutex_exit(&EMLXS_PORT_LOCK);
4787 
4788 #ifdef FCT_API_TRACE
4789                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4790                     "fct_handle_event LINK_UP");
4791 #endif /* FCT_API_TRACE */
4792                 MODSYM(fct_handle_event) (port->fct_port, FCT_EVENT_LINK_UP,
4793                     0, 0);
4794         } else if (!(port->fct_flags & FCT_STATE_PORT_ONLINE)) {
4795                 mutex_exit(&EMLXS_PORT_LOCK);
4796 
4797                 if (port->vpi == 0) {
4798                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4799                             "fct_link_up event. FCT port offline (%x). "
4800                             "Disable link.",
4801                             port->fct_flags);
4802 
4803                         /* Take link down and hold it down */
4804                         (void) emlxs_reset_link(hba, 0, 1);
4805                 } else {
4806                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4807                             "fct_link_up event. FCT port offline (%x).",
4808                             port->fct_flags);
4809                 }
4810         } else {
4811                 mutex_exit(&EMLXS_PORT_LOCK);
4812         }
4813 
4814         return;
4815 
4816 } /* emlxs_fct_link_up() */
4817 
4818 
4819 extern void
4820 emlxs_fct_link_down(emlxs_port_t *port)
4821 {
4822         emlxs_hba_t *hba = HBA;
4823 
4824         mutex_enter(&EMLXS_PORT_LOCK);
4825 #ifdef FCT_API_TRACE
4826         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4827             "fct_link_down port %p fct flags x%x",
4828             port->fct_port, port->fct_flags);
4829 #endif /* FCT_API_TRACE */
4830 
4831         if (port->fct_port &&
4832             (port->fct_flags & FCT_STATE_PORT_ONLINE) &&
4833             (port->fct_flags & FCT_STATE_LINK_UP)) {
4834                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4835                     "fct_link_down event.");
4836 
4837                 port->fct_flags &= ~FCT_STATE_LINK_UP_ACKED;
4838                 port->fct_flags &= ~FCT_STATE_FLOGI_CMPL;
4839                 port->fct_flags &= ~FCT_STATE_LINK_UP;
4840                 mutex_exit(&EMLXS_PORT_LOCK);
4841 
4842 #ifdef FCT_API_TRACE
4843                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4844                     "fct_handle_event LINK_DOWN");
4845 #endif /* FCT_API_TRACE */
4846 
4847                 MODSYM(fct_handle_event) (port->fct_port, FCT_EVENT_LINK_DOWN,
4848                     0, 0);
4849         } else {
4850                 mutex_exit(&EMLXS_PORT_LOCK);
4851         }
4852 
4853         return;
4854 
4855 } /* emlxs_fct_link_down() */
4856 
4857 
4858 void
4859 emlxs_abort_fct_exchange(emlxs_hba_t *hba, emlxs_port_t *port, uint32_t rxid)
4860 {
4861         CHANNEL *cp;
4862         IOCBQ *iocbq;
4863         IOCB *iocb;
4864 
4865         if (rxid == 0 || rxid == 0xFFFF) {
4866                 return;
4867         }
4868 
4869         if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
4870                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4871                     "Aborting FCT exchange: xid=%x", rxid);
4872 
4873                 if (emlxs_sli4_unreserve_xri(port, rxid, 1) == 0) {
4874                         /* We have no way to abort unsolicited exchanges */
4875                         /* that we have not responded to at this time */
4876                         /* So we will return for now */
4877                         return;
4878                 }
4879         }
4880 
4881         cp = &hba->chan[hba->channel_fcp];
4882 
4883         mutex_enter(&EMLXS_FCTAB_LOCK);
4884 
4885         /* Create the abort IOCB */
4886         if (hba->state >= FC_LINK_UP) {
4887                 iocbq = emlxs_create_abort_xri_cx(port, NULL, rxid, cp,
4888                     CLASS3, ABORT_TYPE_ABTS);
4889         } else {
4890                 iocbq = emlxs_create_close_xri_cx(port, NULL, rxid, cp);
4891         }
4892 
4893         mutex_exit(&EMLXS_FCTAB_LOCK);
4894 
4895         if (iocbq) {
4896                 iocb = &iocbq->iocb;
4897                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4898                     "Aborting FCT exchange: xid=%x iotag=%d", rxid,
4899                     iocb->ULPIOTAG);
4900 
4901                 EMLXS_SLI_ISSUE_IOCB_CMD(hba, cp, iocbq);
4902         }
4903 
4904 } /* emlxs_abort_fct_exchange() */
4905 
4906 
4907 extern uint32_t
4908 emlxs_fct_stmf_alloc(emlxs_hba_t *hba, MATCHMAP *mp)
4909 {
4910         emlxs_port_t *port = &PPORT;
4911         stmf_data_buf_t *db;
4912 
4913         if (mp->tag < MEM_FCTSEG) {
4914                 return (0);
4915         }
4916 
4917         db = MODSYM(stmf_alloc) (STMF_STRUCT_DATA_BUF, 0, 0);
4918 
4919 #ifdef FCT_API_TRACE
4920         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4921             "stmf_alloc:%p iotag=%d phys %p virt %p sz %d",
4922             db, mp->tag, mp->phys, mp->virt, mp->size);
4923 #endif /* FCT_API_TRACE */
4924 
4925         if (db == NULL) {
4926                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
4927                     "emlxs_fct_stmf_alloc: alloc failed.");
4928                 return (1);
4929         }
4930 
4931         db->db_port_private = (void*)mp;
4932         db->db_sglist[0].seg_addr = mp->virt;
4933         db->db_sglist[0].seg_length = mp->size;
4934         db->db_buf_size = mp->size;
4935         db->db_sglist_length = 1;
4936 
4937         mp->fct_private = (void*)db;
4938 
4939         return (0);
4940 
4941 } /* emlxs_fct_stmf_alloc() */
4942 
4943 
4944 /* ARGSUSED */
4945 extern void
4946 emlxs_fct_stmf_free(emlxs_hba_t *hba, MATCHMAP *mp)
4947 {
4948 #ifdef FCT_API_TRACE
4949         emlxs_port_t *port = &PPORT;
4950 #endif /* FCT_API_TRACE */
4951         stmf_data_buf_t *db;
4952 
4953         if (mp->tag < MEM_FCTSEG) {
4954                 return;
4955         }
4956 
4957         db = (stmf_data_buf_t *)mp->fct_private;
4958         mp->fct_private = NULL;
4959 
4960         if (db == NULL) {
4961                 return;
4962         }
4963 
4964 #ifdef FCT_API_TRACE
4965         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
4966             "stmf_free:%p iotag=%d",
4967             db, mp->tag);
4968 #endif /* FCT_API_TRACE */
4969 
4970         MODSYM(stmf_free) (db);
4971 
4972         return;
4973 
4974 } /* emlxs_fct_stmf_free() */
4975 
4976 
4977 static void
4978 emlxs_fct_memseg_init(emlxs_hba_t *hba)
4979 {
4980         emlxs_port_t *port = &PPORT;
4981         char **arrayp = NULL;
4982         uint32_t cnt = 0;
4983         char buf[32];
4984         uint32_t rval;
4985         uint8_t *datap;
4986         int i;
4987         int j;
4988         int fct_memseg_cnt = 0;
4989         int numblks;
4990         int memsize;
4991         emlxs_memseg_t *fct_memseg = NULL;
4992         uint32_t fct_memseg_size = 0;
4993         emlxs_memseg_t *current;
4994         emlxs_memseg_t *next;
4995         emlxs_memseg_t *seg;
4996 
4997         port->fct_memseg = NULL;
4998         port->fct_memseg_cnt = 0;
4999 
5000         /* Check for the per adapter setting */
5001         (void) snprintf(buf, sizeof (buf), "%s%d-fct-bufpool", DRIVER_NAME,
5002             hba->ddiinst);
5003         rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
5004             (DDI_PROP_DONTPASS), buf, &arrayp, &cnt);
5005 
5006         if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
5007                 /* Check for the global setting */
5008                 cnt = 0;
5009                 arrayp = NULL;
5010                 rval = ddi_prop_lookup_string_array(DDI_DEV_T_ANY, hba->dip,
5011                     (DDI_PROP_DONTPASS), "fct-bufpool", &arrayp, &cnt);
5012         }
5013 
5014         if ((rval != DDI_PROP_SUCCESS) || !cnt || !arrayp) {
5015                 goto default_config;
5016         }
5017 
5018         fct_memseg_size = cnt * sizeof (emlxs_memseg_t);
5019         fct_memseg = kmem_zalloc(fct_memseg_size, KM_SLEEP);
5020 
5021         if (!fct_memseg) {
5022                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5023                     "Unable to alloc fct_memseg. cnt=%d. "
5024                     "Trying default config.",
5025                     cnt);
5026                 goto default_config;
5027         }
5028 
5029         for (i = 0; i < cnt; i++) {
5030                 datap = (uint8_t *)arrayp[i];
5031                 if (datap == 0) {
5032                         break;
5033                 }
5034 
5035                 while (*datap == ' ') { /* Skip spaces */
5036                         datap++;
5037                 }
5038 
5039                 memsize = emlxs_str_atoi(datap);
5040 
5041                 while ((*datap != ':') && (*datap != 0)) {
5042                         datap++;
5043                 }
5044                 if (*datap == ':') { /* Skip past delimeter */
5045                         datap++;
5046                 }
5047                 while (*datap == ' ') { /* Skip spaces */
5048                         datap++;
5049                 }
5050 
5051                 numblks = emlxs_str_atoi(datap);
5052 
5053                 /* Check for a bad entry */
5054                 if (!memsize || !numblks) {
5055                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5056                             "fct-bufpool: Entry %d:%d. Invalid.",
5057                             memsize, numblks);
5058                         continue;
5059                 }
5060 
5061                 fct_memseg[fct_memseg_cnt].fc_memsize = memsize;
5062                 fct_memseg[fct_memseg_cnt].fc_numblks = numblks;
5063                 fct_memseg_cnt++;
5064 
5065                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5066                     "fct-bufpool: Entry:%d  %d:%d",
5067                     fct_memseg_cnt, memsize, numblks);
5068         }
5069 
5070         if (!fct_memseg_cnt) {
5071                 kmem_free(fct_memseg, fct_memseg_size);
5072                 fct_memseg_size = 0;
5073                 fct_memseg = NULL;
5074         }
5075 
5076 default_config:
5077         /* If buffer list is empty, setup defaults */
5078         if (!fct_memseg) {
5079 
5080                 fct_memseg_size = 8 * sizeof (emlxs_memseg_t);
5081                 fct_memseg = kmem_zalloc(fct_memseg_size, KM_SLEEP);
5082 
5083                 if (!fct_memseg) {
5084                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5085                             "Unable to alloc default port buffer pool. "
5086                             "fct_memseg_cnt=%d",
5087                             cnt);
5088                         return;
5089                 }
5090 
5091                 i = 0;
5092                 numblks = FCT_BUF_COUNT_2K;
5093                 if (numblks) {
5094                         fct_memseg[i].fc_memsize = 2 * 1024;
5095                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_2K;
5096                 }
5097                 numblks = FCT_BUF_COUNT_4K;
5098                 if (numblks) {
5099                         fct_memseg[i].fc_memsize = 4 * 1024;
5100                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_4K;
5101                 }
5102                 numblks = FCT_BUF_COUNT_8K;
5103                 if (numblks) {
5104                         fct_memseg[i].fc_memsize = 8 * 1024;
5105                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_8K;
5106                 }
5107                 numblks = FCT_BUF_COUNT_16K;
5108                 if (numblks) {
5109                         fct_memseg[i].fc_memsize = 16 * 1024;
5110                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_16K;
5111                 }
5112                 numblks = FCT_BUF_COUNT_32K;
5113                 if (numblks) {
5114                         fct_memseg[i].fc_memsize = 32 * 1024;
5115                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_32K;
5116                 }
5117                 numblks = FCT_BUF_COUNT_64K;
5118                 if (numblks) {
5119                         fct_memseg[i].fc_memsize = 64 * 1024;
5120                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_64K;
5121                 }
5122                 numblks = FCT_BUF_COUNT_128K;
5123                 if (numblks) {
5124                         fct_memseg[i].fc_memsize = 128 * 1024;
5125                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_128K;
5126                 }
5127                 numblks = FCT_BUF_COUNT_256K;
5128                 if (numblks) {
5129                         fct_memseg[i].fc_memsize = 256 * 1024;
5130                         fct_memseg[i++].fc_numblks = FCT_BUF_COUNT_256K;
5131                 }
5132                 fct_memseg_cnt = i;
5133         }
5134 
5135         port->fct_memseg = kmem_zalloc((fct_memseg_cnt *
5136             sizeof (emlxs_memseg_t)), KM_SLEEP);
5137 
5138         if (!port->fct_memseg) {
5139                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5140                     "Unable to alloc port buffer pool. fct_memseg_cnt=%d",
5141                     fct_memseg_cnt);
5142                 kmem_free(fct_memseg, fct_memseg_size);
5143                 return;
5144         }
5145 
5146         /* Initalize port bucket list */
5147         port->fct_memseg_cnt = fct_memseg_cnt;
5148 
5149         /* Sort the entries smallest to largest */
5150         seg = port->fct_memseg;
5151         for (i = 0; i < fct_memseg_cnt; i++, seg++) {
5152 
5153                 /* Find next smallest buffer */
5154                 current = fct_memseg;
5155                 next = NULL;
5156                 for (j = 0; j < fct_memseg_cnt; j++, current++) {
5157                         if (current->fc_memsize == 0) {
5158                                 continue;
5159                         }
5160 
5161                         if (next == NULL) {
5162                                 next = current;
5163                                 continue;
5164                         }
5165 
5166                         if (current->fc_memsize < next->fc_memsize) {
5167                                 next = current;
5168                         }
5169                 }
5170 
5171                 /* Save next entry */
5172                 seg->fc_memsize = next->fc_memsize;
5173                 seg->fc_numblks = next->fc_numblks;
5174                 next->fc_memsize = 0;
5175                 next->fc_numblks = 0;
5176         }
5177 
5178         kmem_free(fct_memseg, fct_memseg_size);
5179 
5180         /* Complete the initialization */
5181         seg = port->fct_memseg;
5182         for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5183 /*              seg->fc_memsize = ; Already setup */
5184 /*              seg->fc_numblks = ; Already setup */
5185 
5186                 (void) snprintf(seg->fc_label, sizeof (seg->fc_label),
5187                     "FCT_DMEM_%d", seg->fc_memsize);
5188 
5189                 seg->fc_memtag   = MEM_FCTSEG + i;
5190                 seg->fc_memflag  = FC_MBUF_DMA | FC_MBUF_SNGLSG;
5191                 seg->fc_memalign = 32;
5192                 seg->fc_hi_water = 0xFFFF;
5193                 seg->fc_lo_water = seg->fc_numblks;
5194                 seg->fc_numblks  = 0;
5195                 seg->fc_step = 1;
5196         }
5197 
5198         return;
5199 
5200 } /* emlxs_fct_memseg_init() */
5201 
5202 
5203 fct_status_t
5204 emlxs_fct_dmem_init(emlxs_port_t *port)
5205 {
5206         emlxs_hba_t *hba = HBA;
5207         emlxs_memseg_t *seg;
5208         int32_t i;
5209 
5210         /* Initialize the fct memseg list */
5211         emlxs_fct_memseg_init(hba);
5212 
5213         if (!port->fct_memseg || !port->fct_memseg_cnt) {
5214                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5215                     "fct_dmem_init: fct_memseg list is empty.");
5216                 return (FCT_FAILURE);
5217         }
5218 
5219         /* Create the DMA buffer pools */
5220         seg = port->fct_memseg;
5221         for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5222 
5223                 (void) emlxs_mem_pool_create(hba, seg);
5224 
5225                 if (seg->fc_numblks < seg->fc_lo_water) {
5226                         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_mem_alloc_failed_msg,
5227                             "%s: count=%d size=%d flags=%x lo=%d hi=%d",
5228                             seg->fc_label, seg->fc_numblks,
5229                             seg->fc_memsize, seg->fc_memflag, seg->fc_lo_water,
5230                             seg->fc_hi_water);
5231                 }
5232         }
5233 
5234         return (FCT_SUCCESS);
5235 
5236 } /* emlxs_fct_dmem_init */
5237 
5238 
5239 void
5240 emlxs_fct_dmem_fini(emlxs_port_t *port)
5241 {
5242         emlxs_hba_t *hba = HBA;
5243         emlxs_memseg_t *seg;
5244         int32_t i;
5245 
5246         if (!port->fct_memseg || !port->fct_memseg_cnt) {
5247                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_detail_msg,
5248                     "fct_dmem_fini: fct_memseg list is empty.");
5249                 return;
5250         }
5251 
5252         /* Destroy the dmem buffer pools */
5253         seg = port->fct_memseg;
5254         for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5255                 (void) emlxs_mem_pool_destroy(hba, seg);
5256         }
5257 
5258         /* Clear the segment space */
5259         kmem_free(port->fct_memseg,
5260             (port->fct_memseg_cnt * sizeof (emlxs_memseg_t)));
5261 
5262         port->fct_memseg = 0;
5263         port->fct_memseg_cnt = 0;
5264 
5265         return;
5266 
5267 } /* emlxs_fct_dmem_fini */
5268 
5269 
5270 /* COMSTAR ENTER POINT */
5271 /*ARGSUSED*/
5272 static stmf_data_buf_t *
5273 emlxs_fct_dbuf_alloc(fct_local_port_t *fct_port, uint32_t size,
5274     uint32_t *pminsize, uint32_t flags)
5275 {
5276         emlxs_port_t *port = (emlxs_port_t *)fct_port->port_fca_private;
5277         emlxs_hba_t *hba = HBA;
5278         emlxs_memseg_t *seg;
5279         stmf_data_buf_t *db;
5280         MATCHMAP *mp;
5281         int i;
5282         uint32_t minsize = 0;
5283 
5284         if (!port->fct_memseg || !port->fct_memseg_cnt) {
5285                 goto failed;
5286         }
5287 
5288         /* Check if our largest buffer is too small */
5289         seg = &port->fct_memseg[port->fct_memseg_cnt-1];
5290         if (size > seg->fc_memsize) {
5291                 goto partial_alloc;
5292         }
5293 
5294         /* Find smallest available buffer >= size */
5295         seg = port->fct_memseg;
5296         for (i = 0; i < port->fct_memseg_cnt; i++, seg++) {
5297                 if (seg->fc_memsize < size) {
5298                         continue;
5299                 }
5300 
5301                 mp = (MATCHMAP*)emlxs_mem_pool_get(hba, seg);
5302 
5303                 if (mp) {
5304                         goto success;
5305                 }
5306         }
5307 
5308         seg = &port->fct_memseg[port->fct_memseg_cnt-1];
5309 
5310 partial_alloc:
5311         /* Find largest available buffer >= *pminsize */
5312         for (i = port->fct_memseg_cnt-1; i >= 0; i--, seg--) {
5313                 if (seg->fc_memsize < *pminsize) {
5314                         minsize = seg->fc_memsize;
5315                         goto failed;
5316                 }
5317 
5318                 mp = (MATCHMAP*)emlxs_mem_pool_get(hba, seg);
5319 
5320                 if (mp) {
5321                         goto success;
5322                 }
5323         }
5324 
5325 failed:
5326         *pminsize = minsize;
5327         TGTPORTSTAT.FctNoBuffer++;
5328 
5329         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5330             "fct_dbuf_alloc:Failed. size=%d minsize=%d",
5331             size, *pminsize);
5332 
5333         return (NULL);
5334 
5335 success:
5336         /* Setup the data buffer */
5337         db = (stmf_data_buf_t *)mp->fct_private;
5338         db->db_data_size = min(size, mp->size);
5339 
5340 #ifdef FCT_API_TRACE
5341         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5342             "fct_dbuf_alloc:%p iotag=%d size=%d,%d",
5343             db, mp->tag, size,  mp->size);
5344 #endif /* FCT_API_TRACE */
5345 
5346         return (db);
5347 
5348 } /* emlxs_fct_dbuf_alloc() */
5349 
5350 
5351 /* COMSTAR ENTER POINT */
5352 /*ARGSUSED*/
5353 static void
5354 emlxs_fct_dbuf_free(fct_dbuf_store_t *fds, stmf_data_buf_t *db)
5355 {
5356         emlxs_port_t *port = (emlxs_port_t *)fds->fds_fca_private;
5357         emlxs_hba_t *hba = HBA;
5358         MATCHMAP *mp = (MATCHMAP *)db->db_port_private;
5359 
5360         if (!mp) {
5361                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5362                     "fct_dbuf_free:%p  NULL mp found!",
5363                     db);
5364                 return;
5365         }
5366 
5367 #ifdef FCT_API_TRACE
5368         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5369             "fct_dbuf_free:%p iotag=%d",
5370             db, mp->tag);
5371 #endif /* FCT_API_TRACE */
5372 
5373         emlxs_mem_pool_put(hba, mp->segment, (void *)mp);
5374 
5375 } /* emlxs_fct_dbuf_free() */
5376 
5377 
5378 static int
5379 emlxs_fct_dbuf_dma_sync(emlxs_hba_t *hba, stmf_data_buf_t *db,
5380     uint_t sync_type)
5381 {
5382         emlxs_port_t *port = &PPORT;
5383         MATCHMAP *mp = (MATCHMAP *)db->db_port_private;
5384 
5385         if (!mp) {
5386                 EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5387                     "fct_dbuf_dma_sync:%p  NULL mp found!",
5388                     db);
5389                 return (0);
5390         }
5391 
5392 #ifdef FCT_API_TRACE
5393 {
5394         char buf[16];
5395 
5396         EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fct_api_msg,
5397             "fct_dbuf_dma_sync:%p iotag=%d size=%d",
5398             db, mp->tag, db->db_data_size);
5399 
5400         (void) snprintf(buf, sizeof (buf), "TAG%d:", mp->tag);
5401         emlxs_data_dump(port, buf, (uint32_t *)db->db_sglist[0].seg_addr,
5402             36, 0);
5403 }
5404 #endif /* FCT_API_TRACE */
5405 
5406         EMLXS_MPDATA_SYNC(mp->dma_handle, 0, db->db_data_size, sync_type);
5407 
5408 #ifdef FMA_SUPPORT
5409         if (emlxs_fm_check_dma_handle(hba, mp->dma_handle)
5410             != DDI_FM_OK) {
5411                 EMLXS_MSGF(EMLXS_CONTEXT,
5412                     &emlxs_invalid_dma_handle_msg,
5413                     "fct_dbuf_dma_sync:%p iotag=%d",
5414                     db, mp->tag);
5415                 return (1);
5416         }
5417 #endif  /* FMA_SUPPORT */
5418 
5419         return (0);
5420 
5421 } /* emlxs_fct_dbuf_dma_sync() */
5422 
5423 #endif /* SFCT_SUPPORT */