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