96 #define FCT_MODULE_NAME "fct"
  97 
  98 extern struct mod_ops mod_driverops;
  99 static struct modldrv modldrv = {
 100         &mod_driverops,
 101         FCT_NAME,
 102         &fct_ops
 103 };
 104 
 105 static struct modlinkage modlinkage = {
 106         MODREV_1,
 107         &modldrv,
 108         NULL
 109 };
 110 
 111 static uint32_t rportid_table_size = FCT_HASH_TABLE_SIZE;
 112 static int max_cached_ncmds = FCT_MAX_CACHED_CMDS;
 113 static fct_i_local_port_t *fct_iport_list = NULL;
 114 static kmutex_t fct_global_mutex;
 115 uint32_t fct_rscn_options = RSCN_OPTION_VERIFY;
 116 
 117 int
 118 _init(void)
 119 {
 120         int ret;
 121 
 122         ret = mod_install(&modlinkage);
 123         if (ret)
 124                 return (ret);
 125         /* XXX */
 126         mutex_init(&fct_global_mutex, NULL, MUTEX_DRIVER, NULL);
 127         return (ret);
 128 }
 129 
 130 int
 131 _fini(void)
 132 {
 133         int ret;
 134 
 135         ret = mod_remove(&modlinkage);
 136         if (ret)
 
1171         if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
1172             taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
1173                 return (FCT_FAILURE);
1174         }
1175         mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
1176         cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
1177         rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
1178         sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
1179 
1180         /* Remote port mgmt */
1181         iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
1182             port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
1183         iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
1184             sizeof (fct_i_remote_port_t *), KM_SLEEP);
1185 
1186         /* fct_cmds for SCSI traffic */
1187         iport->iport_total_alloced_ncmds = 0;
1188         iport->iport_cached_ncmds = 0;
1189         port->port_fca_fcp_cmd_size =
1190             (port->port_fca_fcp_cmd_size + 7) & ~7;
1191         iport->iport_cached_cmdlist = NULL;
1192         mutex_init(&iport->iport_cached_cmd_lock, NULL, MUTEX_DRIVER, NULL);
1193 
1194         /* Initialize cmd slots */
1195         iport->iport_cmd_slots = (fct_cmd_slot_t *)kmem_zalloc(
1196             port->port_max_xchges * sizeof (fct_cmd_slot_t), KM_SLEEP);
1197         iport->iport_next_free_slot = 0;
1198         for (i = 0; i < port->port_max_xchges; ) {
1199                 slot = &iport->iport_cmd_slots[i];
1200                 slot->slot_no = (uint16_t)i;
1201                 slot->slot_next = (uint16_t)(++i);
1202         }
1203         slot->slot_next = FCT_SLOT_EOL;
1204         iport->iport_nslots_free = port->port_max_xchges;
1205 
1206         iport->iport_task_green_limit =
1207             (port->port_max_xchges * FCT_TASK_GREEN_LIMIT) / 100;
1208         iport->iport_task_yellow_limit =
1209             (port->port_max_xchges * FCT_TASK_YELLOW_LIMIT) / 100;
1210         iport->iport_task_red_limit =
1211             (port->port_max_xchges * FCT_TASK_RED_LIMIT) / 100;
 
1260         /* Stop the taskq 1st */
1261         if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1262                 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1263                 cv_broadcast(&iport->iport_worker_cv);
1264                 while (iport->iport_flags & IPORT_WORKER_RUNNING) {
1265                         delay(1);
1266                 }
1267         }
1268         ddi_taskq_destroy(iport->iport_worker_taskq);
1269         if (iport->iport_rp_tb) {
1270                 kmem_free(iport->iport_rp_tb, rportid_table_size *
1271                     sizeof (fct_i_remote_port_t *));
1272         }
1273         return (FCT_FAILURE);
1274 }
1275 
1276 fct_status_t
1277 fct_deregister_local_port(fct_local_port_t *port)
1278 {
1279         fct_i_local_port_t      *iport;
1280         fct_i_cmd_t             *icmd, *next_icmd;
1281         int                     ndx;
1282 
1283         iport = (fct_i_local_port_t *)port->port_fct_private;
1284 
1285         if ((iport->iport_state != FCT_STATE_OFFLINE) ||
1286             iport->iport_state_not_acked) {
1287                 return (FCT_FAILURE);
1288         }
1289 
1290         /* Stop the taskq 1st */
1291         if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1292                 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1293                 cv_broadcast(&iport->iport_worker_cv);
1294                 for (ndx = 0; ndx < 100; ndx++) {
1295                         if ((iport->iport_flags & IPORT_WORKER_RUNNING)
1296                             == 0) {
1297                                 break;
1298                         }
1299                         delay(drv_usectohz(10000));
1300                 }
 
1305                 }
1306         }
1307 
1308         if (stmf_deregister_local_port(port->port_lport) != FCT_SUCCESS) {
1309                 goto fct_deregport_fail1;
1310         }
1311 
1312         mutex_enter(&fct_global_mutex);
1313         if (iport->iport_next)
1314                 iport->iport_next->iport_prev = iport->iport_prev;
1315         if (iport->iport_prev)
1316                 iport->iport_prev->iport_next = iport->iport_next;
1317         else
1318                 fct_iport_list = iport->iport_next;
1319         mutex_exit(&fct_global_mutex);
1320         /*
1321          * At this time, there should be no outstanding and pending
1322          * I/Os, so we can just release resources.
1323          */
1324         ASSERT(iport->iport_total_alloced_ncmds == iport->iport_cached_ncmds);
1325         for (icmd = iport->iport_cached_cmdlist; icmd; icmd = next_icmd) {
1326                 next_icmd = icmd->icmd_next;
1327                 fct_free(icmd->icmd_cmd);
1328         }
1329         mutex_destroy(&iport->iport_cached_cmd_lock);
1330         kmem_free(iport->iport_cmd_slots, port->port_max_xchges *
1331             sizeof (fct_cmd_slot_t));
1332         kmem_free(iport->iport_rp_slots, port->port_max_logins *
1333             sizeof (fct_i_remote_port_t *));
1334         rw_destroy(&iport->iport_lock);
1335         cv_destroy(&iport->iport_worker_cv);
1336         sema_destroy(&iport->iport_rls_sema);
1337         mutex_destroy(&iport->iport_worker_lock);
1338         ddi_taskq_destroy(iport->iport_worker_taskq);
1339         if (iport->iport_rp_tb) {
1340                 kmem_free(iport->iport_rp_tb, rportid_table_size *
1341                     sizeof (fct_i_remote_port_t *));
1342         }
1343 
1344         if (iport->iport_kstat_portstat) {
1345                 kstat_delete(iport->iport_kstat_portstat);
1346         }
1347 
 
1460                         iport->iport_rp_tb[hash_key] =
1461                             irp->irp_next;
1462                 } else {
1463                         irp_last->irp_next = irp->irp_next;
1464                 }
1465                 irp->irp_next = NULL;
1466                 iport->iport_nrps--;
1467         }
1468 }
1469 
1470 int
1471 fct_is_irp_logging_out(fct_i_remote_port_t *irp, int force_implicit)
1472 {
1473         int logging_out = 0;
1474 
1475         rw_enter(&irp->irp_lock, RW_WRITER);
1476         if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1477                 logging_out = 0;
1478                 goto ilo_done;
1479         }
1480         if ((irp->irp_els_list == NULL) && (irp->irp_deregister_timer)) {
1481                 if (force_implicit && irp->irp_nonfcp_xchg_count) {
1482                         logging_out = 0;
1483                 } else {
1484                         logging_out = 1;
1485                 }
1486                 goto ilo_done;
1487         }
1488         if (irp->irp_els_list) {
1489                 fct_i_cmd_t *icmd;
1490                 /* Last session affecting ELS should be a LOGO */
1491                 for (icmd = irp->irp_els_list; icmd; icmd = icmd->icmd_next) {
1492                         uint8_t op = (ICMD_TO_ELS(icmd))->els_req_payload[0];
1493                         if (op == ELS_OP_LOGO) {
1494                                 if (force_implicit) {
1495                                         if (icmd->icmd_flags & ICMD_IMPLICIT)
1496                                                 logging_out = 1;
1497                                         else
1498                                                 logging_out = 0;
1499                                 } else {
1500                                         logging_out = 1;
1501                                 }
1502                         } else if ((op == ELS_OP_PLOGI) ||
1503                             (op == ELS_OP_PRLI) ||
1504                             (op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
1505                                 logging_out = 0;
1506                         }
1507                 }
1508         }
1509 ilo_done:;
1510         rw_exit(&irp->irp_lock);
1511 
 
1595         fct_i_remote_port_t *irp;
1596         int i;
1597 
1598         if (iport->iport_nrps_login)
1599                 return (0);
1600         /* loop all rps to check if the cmd have already been drained */
1601         for (i = 0; i < rportid_table_size; i++) {
1602                 irp = iport->iport_rp_tb[i];
1603                 while (irp) {
1604                         if (irp->irp_fcp_xchg_count ||
1605                             irp->irp_nonfcp_xchg_count)
1606                                 return (0);
1607                         irp = irp->irp_next;
1608                 }
1609         }
1610         return (1);
1611 }
1612 
1613 fct_cmd_t *
1614 fct_scsi_task_alloc(fct_local_port_t *port, uint16_t rp_handle,
1615     uint32_t rportid, uint8_t *lun, uint16_t cdb_length, uint16_t task_ext)
1616 {
1617         fct_cmd_t *cmd;
1618         fct_i_cmd_t *icmd;
1619         fct_i_local_port_t *iport =
1620             (fct_i_local_port_t *)port->port_fct_private;
1621         fct_i_remote_port_t *irp;
1622         scsi_task_t *task;
1623         fct_remote_port_t *rp;
1624         uint16_t cmd_slot;
1625 
1626         rw_enter(&iport->iport_lock, RW_READER);
1627         if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
1628                 rw_exit(&iport->iport_lock);
1629                 stmf_trace(iport->iport_alias, "cmd alloc called while the port"
1630                     " was offline");
1631                 return (NULL);
1632         }
1633 
1634         if (rp_handle == FCT_HANDLE_NONE) {
1635                 irp = fct_portid_to_portptr(iport, rportid);
 
1643                 if ((rp_handle >= port->port_max_logins) ||
1644                     ((irp = iport->iport_rp_slots[rp_handle]) == NULL)) {
1645                         rw_exit(&iport->iport_lock);
1646                         stmf_trace(iport->iport_alias, "cmd received from "
1647                             "invalid port handle %x", rp_handle);
1648                         return (NULL);
1649                 }
1650         }
1651         rp = irp->irp_rp;
1652 
1653         rw_enter(&irp->irp_lock, RW_READER);
1654         if ((irp->irp_flags & IRP_PRLI_DONE) == 0) {
1655                 rw_exit(&irp->irp_lock);
1656                 rw_exit(&iport->iport_lock);
1657                 stmf_trace(iport->iport_alias, "cmd alloc called while fcp "
1658                     "login was not done. portid=%x, rp=%p", rp->rp_id, rp);
1659                 return (NULL);
1660         }
1661 
1662         mutex_enter(&iport->iport_cached_cmd_lock);
1663         if ((icmd = iport->iport_cached_cmdlist) != NULL) {
1664                 iport->iport_cached_cmdlist = icmd->icmd_next;
1665                 iport->iport_cached_ncmds--;
1666                 cmd = icmd->icmd_cmd;
1667         } else {
1668                 icmd = NULL;
1669         }
1670         mutex_exit(&iport->iport_cached_cmd_lock);
1671         if (icmd == NULL) {
1672                 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
1673                     port->port_fca_fcp_cmd_size, 0);
1674                 if (cmd == NULL) {
1675                         rw_exit(&irp->irp_lock);
1676                         rw_exit(&iport->iport_lock);
1677                         stmf_trace(iport->iport_alias, "Ran out of "
1678                             "memory, port=%p", port);
1679                         return (NULL);
1680                 }
1681 
1682                 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1683                 icmd->icmd_next = NULL;
1684                 cmd->cmd_port = port;
1685                 atomic_inc_32(&iport->iport_total_alloced_ncmds);
1686         }
1687 
1688         /*
1689          * The accuracy of iport_max_active_ncmds is not important
1690          */
1691         if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
1692             iport->iport_max_active_ncmds) {
1693                 iport->iport_max_active_ncmds =
1694                     iport->iport_total_alloced_ncmds -
1695                     iport->iport_cached_ncmds;
1696         }
1697 
1698         /* Lets get a slot */
1699         cmd_slot = fct_alloc_cmd_slot(iport, cmd);
1700         if (cmd_slot == FCT_SLOT_EOL) {
1701                 rw_exit(&irp->irp_lock);
1702                 rw_exit(&iport->iport_lock);
1703                 stmf_trace(iport->iport_alias, "Ran out of xchg resources");
 
1867                  */
1868                 new = ((old + (0x10000)) & 0xFFFF0000);
1869                 new |= iport->iport_cmd_slots[cmd_slot].slot_next;
1870         } while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
1871 
1872         atomic_dec_16(&iport->iport_nslots_free);
1873         iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
1874         cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
1875             (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
1876             << 24);
1877         return (cmd_slot);
1878 }
1879 
1880 /*
1881  * If icmd is not NULL, irp_lock must be held
1882  */
1883 void
1884 fct_post_to_discovery_queue(fct_i_local_port_t *iport,
1885     fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
1886 {
1887         fct_i_cmd_t     **p;
1888 
1889         ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
1890         if (icmd) {
1891                 icmd->icmd_next = NULL;
1892                 for (p = &irp->irp_els_list; *p != NULL;
1893                     p = &((*p)->icmd_next))
1894                         ;
1895 
1896                 *p = icmd;
1897                 atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE);
1898         }
1899 
1900         mutex_enter(&iport->iport_worker_lock);
1901         if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1902 
1903                 /*
1904                  * CAUTION: do not grab local_port/remote_port locks after
1905                  * grabbing the worker lock.
1906                  */
1907                 irp->irp_discovery_next = NULL;
1908                 if (iport->iport_rpwe_tail) {
1909                         iport->iport_rpwe_tail->irp_discovery_next = irp;
1910                         iport->iport_rpwe_tail = irp;
1911                 } else {
1912                         iport->iport_rpwe_head = iport->iport_rpwe_tail = irp;
1913                 }
1914 
1915                 atomic_or_32(&irp->irp_flags, IRP_IN_DISCOVERY_QUEUE);
1916         }
 
2108                          * XXX Throw HBA fatal error event
2109                          * Later shutdown svc will terminate the ABTS in the end
2110                          */
2111                         (void) snprintf(info, sizeof (info),
2112                             "fct_cmd_free: iport-%p, ABTS_ACC"
2113                             " port_send_cmd_response failed", (void *)iport);
2114                         (void) fct_port_shutdown(iport->iport_port,
2115                             STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2116                         return;
2117                 } else {
2118                         fct_cmd_free(lcmd);
2119                         cmd->cmd_link = NULL;
2120                 }
2121         }
2122 
2123         /* Free the cmd */
2124         if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2125                 if (iport->iport_cached_ncmds < max_cached_ncmds) {
2126                         icmd->icmd_flags = 0;
2127                         mutex_enter(&iport->iport_cached_cmd_lock);
2128                         icmd->icmd_next = iport->iport_cached_cmdlist;
2129                         iport->iport_cached_cmdlist = icmd;
2130                         iport->iport_cached_ncmds++;
2131                         mutex_exit(&iport->iport_cached_cmd_lock);
2132                 } else {
2133                         atomic_dec_32(&iport->iport_total_alloced_ncmds);
2134                         fct_free(cmd);
2135                 }
2136         } else {
2137                 fct_free(cmd);
2138         }
2139 }
2140 
2141 /* ARGSUSED */
2142 stmf_status_t
2143 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
2144     uint32_t flags)
2145 {
2146         stmf_status_t ret = STMF_SUCCESS;
2147         scsi_task_t *task;
2148         fct_cmd_t *cmd;
2149         fct_i_cmd_t *icmd;
 
2812         fct_i_cmd_t             *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2813         char                    info[FCT_INFO_LEN];
2814         unsigned long long      st;
2815 
2816         st = s; /* To make gcc happy */
2817         ASSERT(icmd->icmd_flags & ICMD_BEING_ABORTED);
2818         if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) ||
2819             ((ioflags & FCT_IOF_FCA_DONE) == 0)) {
2820                 (void) snprintf(info, sizeof (info),
2821                     "fct_cmd_fca_aborted: cmd-%p, "
2822                     "s-%llx, iofalgs-%x", (void *)cmd, st, ioflags);
2823                 (void) fct_port_shutdown(cmd->cmd_port,
2824                     STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2825                 return;
2826         }
2827 
2828         atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2829         /* For non FCP Rest of the work is done by the terminator */
2830         /* For FCP stuff just call stmf */
2831         if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2832                 stmf_task_lport_aborted((scsi_task_t *)cmd->cmd_specific,
2833                     s, STMF_IOF_LPORT_DONE);
2834         }
2835 }
2836 
2837 /*
2838  * FCA drivers will use it, when they want to abort some FC transactions
2839  * due to lack of resource.
2840  */
2841 uint16_t
2842 fct_get_rp_handle(fct_local_port_t *port, uint32_t rportid)
2843 {
2844         fct_i_remote_port_t     *irp;
2845 
2846         irp = fct_portid_to_portptr(
2847             (fct_i_local_port_t *)(port->port_fct_private), rportid);
2848         if (irp == NULL) {
2849                 return (0xFFFF);
2850         } else {
2851                 return (irp->irp_rp->rp_handle);
2852         }
2853 }
 
2886                 new = old | ICMD_BEING_ABORTED;
2887         } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2888         stmf_abort(STMF_QUEUE_TASK_ABORT, (scsi_task_t *)cmd->cmd_specific,
2889             s, NULL);
2890 }
2891 
2892 void
2893 fct_fill_abts_acc(fct_cmd_t *cmd)
2894 {
2895         fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
2896         uint8_t *p;
2897 
2898         abts->abts_resp_rctl = BLS_OP_BA_ACC;
2899         p = abts->abts_resp_payload;
2900         bzero(p, 12);
2901         *((uint16_t *)(p+4)) = BE_16(cmd->cmd_oxid);
2902         *((uint16_t *)(p+6)) = BE_16(cmd->cmd_rxid);
2903         p[10] = p[11] = 0xff;
2904 }
2905 
2906 void
2907 fct_handle_rcvd_abts(fct_cmd_t *cmd)
2908 {
2909         char                    info[FCT_INFO_LEN];
2910         fct_local_port_t        *port = cmd->cmd_port;
2911         fct_i_local_port_t      *iport =
2912             (fct_i_local_port_t *)port->port_fct_private;
2913         fct_i_cmd_t             *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2914         fct_i_remote_port_t     *irp;
2915         fct_cmd_t               *c = NULL;
2916         fct_i_cmd_t             *ic = NULL;
2917         int                     found = 0;
2918         int                     i;
2919 
2920         icmd->icmd_start_time = ddi_get_lbolt();
2921         icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
2922 
2923         rw_enter(&iport->iport_lock, RW_WRITER);
2924         /* Make sure local port is sane */
2925         if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
2926                 rw_exit(&iport->iport_lock);
2927                 stmf_trace(iport->iport_alias, "ABTS not posted becasue"
2928                     "port state was %x", iport->iport_link_state);
2929                 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
2930                 return;
2931         }
2932 
2933         if (cmd->cmd_rp_handle == FCT_HANDLE_NONE)
2934                 irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
2935         else if (cmd->cmd_rp_handle < port->port_max_logins)
2936                 irp = iport->iport_rp_slots[cmd->cmd_rp_handle];
2937         else
2938                 irp = NULL;
 
2981                 /* Dont even bother queueing it. Just respond */
2982                 fct_fill_abts_acc(cmd);
2983                 if (port->port_send_cmd_response(cmd,
2984                     FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2985                         /*
2986                          * XXX Throw HBA fatal error event
2987                          * Later shutdown svc will terminate the ABTS in the end
2988                          */
2989                         (void) snprintf(info, sizeof (info),
2990                             "fct_handle_rcvd_abts: iport-%p, "
2991                             "ABTS_ACC port_send_cmd_response failed",
2992                             (void *)iport);
2993                         (void) fct_port_shutdown(iport->iport_port,
2994                             STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2995                 } else {
2996                         fct_cmd_free(cmd);
2997                 }
2998                 return;
2999         }
3000 
3001         /* Check if this an abts retry */
3002         if (c->cmd_link && (ic->icmd_flags & ICMD_ABTS_RECEIVED)) {
3003                 /* Kill this abts. */
3004                 fct_q_for_termination_lock_held(iport, icmd, FCT_ABORTED);
3005                 if (IS_WORKER_SLEEPING(iport))
3006                         cv_signal(&iport->iport_worker_cv);
3007                 mutex_exit(&iport->iport_worker_lock);
3008                 rw_exit(&irp->irp_lock);
3009                 rw_exit(&iport->iport_lock);
3010                 return;
3011         }
3012         c->cmd_link = cmd;
3013         atomic_or_32(&ic->icmd_flags, ICMD_ABTS_RECEIVED);
3014         cmd->cmd_link = c;
3015         mutex_exit(&iport->iport_worker_lock);
3016         rw_exit(&irp->irp_lock);
3017         fct_queue_cmd_for_termination(c, FCT_ABTS_RECEIVED);
3018         rw_exit(&iport->iport_lock);
3019 }
3020 
3021 void
3022 fct_queue_cmd_for_termination(fct_cmd_t *cmd, fct_status_t s)
3023 {
3024         fct_local_port_t *port = cmd->cmd_port;
3025         fct_i_local_port_t *iport = (fct_i_local_port_t *)
3026             port->port_fct_private;
3027         fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
3028 
3029         if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3030                 fct_queue_scsi_task_for_termination(cmd, s);
3031                 return;
3032         }
3033         mutex_enter(&iport->iport_worker_lock);
3034         fct_q_for_termination_lock_held(iport, icmd, s);
3035         if (IS_WORKER_SLEEPING(iport))
3036                 cv_signal(&iport->iport_worker_cv);
3037         mutex_exit(&iport->iport_worker_lock);
3038 }
3039 
3040 /*
3041  * This function will not be called for SCSI CMDS
3042  */
3043 void
3044 fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd,
3045     fct_status_t s)
3046 {
3047         uint32_t old, new;
3048         fct_i_cmd_t **ppicmd;
3049 
3050         do {
3051                 old = icmd->icmd_flags;
3052                 if (old & ICMD_BEING_ABORTED)
3053                         return;
3054                 new = old | ICMD_BEING_ABORTED;
3055         } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
3056 
3057         icmd->icmd_start_time = ddi_get_lbolt();
3058         icmd->icmd_cmd->cmd_comp_status = s;
3059 
3060         icmd->icmd_next = NULL;
3061         for (ppicmd = &(iport->iport_abort_queue); *ppicmd != NULL;
3062             ppicmd = &((*ppicmd)->icmd_next))
3063                 ;
3064 
3065         *ppicmd = icmd;
3066 }
3067 
3068 /*
3069  * For those cmds, for which we called fca_abort but it has not yet completed,
3070  * reset the FCA_ABORT_CALLED flag, so that abort can be called again.
3071  * This is done after a FCA offline. The reason is that after offline, the
3072  * firmware is not running so abort will never complete. But if we call it
3073  * again, the FCA will detect that it is not offline and it will
3074  * not call the firmware at all. Most likely it will abort in a synchronous
3075  * manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND.
3076  */
3077 void
3078 fct_reset_flag_abort_called(fct_i_local_port_t *iport)
3079 {
3080         fct_i_cmd_t *icmd;
3081         uint32_t old, new;
3082         int i, do_clear;
3083 
3084         ASSERT(mutex_owned(&iport->iport_worker_lock));
3085         mutex_exit(&iport->iport_worker_lock);
 
3224 {
3225         stmf_state_change_info_t st;
3226 
3227         st.st_rflags = rflags;
3228         st.st_additional_info = additional_info;
3229         stmf_trace(NULL, "fct_port_shutdown: port-%p, %s", port,
3230             additional_info? additional_info : "no more information");
3231         return (stmf_ctl(STMF_CMD_LPORT_OFFLINE, port->port_lport, &st));
3232 }
3233 
3234 /*
3235  * Called by worker thread. The aim is to terminate the command
3236  * using whatever means it takes.
3237  * Called with worker lock held.
3238  */
3239 disc_action_t
3240 fct_cmd_terminator(fct_i_local_port_t *iport)
3241 {
3242         char                    info[FCT_INFO_LEN];
3243         clock_t                 endtime;
3244         fct_i_cmd_t             **ppicmd;
3245         fct_i_cmd_t             *icmd;
3246         fct_cmd_t               *cmd;
3247         fct_local_port_t        *port = iport->iport_port;
3248         disc_action_t           ret = DISC_ACTION_NO_WORK;
3249         fct_status_t            abort_ret;
3250         int                     fca_done, fct_done, cmd_implicit = 0;
3251         int                     flags;
3252         unsigned long long      st;
3253 
3254         /* Lets Limit each run to 20ms max. */
3255         endtime = ddi_get_lbolt() + drv_usectohz(20000);
3256 
3257         /* Start from where we left off last time */
3258         if (iport->iport_ppicmd_term) {
3259                 ppicmd = iport->iport_ppicmd_term;
3260                 iport->iport_ppicmd_term = NULL;
3261         } else {
3262                 ppicmd = &iport->iport_abort_queue;
3263         }
3264 
3265         /*
3266          * Once a command gets on discovery queue, this is the only thread
3267          * which can access it. So no need for the lock here.
3268          */
3269         mutex_exit(&iport->iport_worker_lock);
3270 
3271         while ((icmd = *ppicmd) != NULL) {
3272                 cmd = icmd->icmd_cmd;
3273 
3274                 /* Always remember that cmd->cmd_rp can be NULL */
3275                 if ((icmd->icmd_flags & (ICMD_KNOWN_TO_FCA |
3276                     ICMD_FCA_ABORT_CALLED)) == ICMD_KNOWN_TO_FCA) {
3277                         atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3278                         if (CMD_HANDLE_VALID(cmd->cmd_handle))
3279                                 flags = 0;
3280                         else
3281                                 flags = FCT_IOF_FORCE_FCA_DONE;
3282                         abort_ret = port->port_abort_cmd(port, cmd, flags);
3283                         if ((abort_ret != FCT_SUCCESS) &&
3284                             (abort_ret != FCT_ABORT_SUCCESS) &&
3285                             (abort_ret != FCT_NOT_FOUND)) {
3286                                 if (flags & FCT_IOF_FORCE_FCA_DONE) {
3287                                         /*
3288                                          * XXX trigger port fatal,
3289                                          * Abort the termination, and shutdown
3290                                          * svc will trigger fct_cmd_termination
3291                                          * again.
3292                                          */
3293                                         (void) snprintf(info, sizeof (info),
3294                                             "fct_cmd_terminator:"
3295                                             " iport-%p, port_abort_cmd with "
3296                                             "FORCE_FCA_DONE failed",
3297                                             (void *)iport);
3298                                         (void) fct_port_shutdown(
3299                                             iport->iport_port,
3300                                             STMF_RFLAG_FATAL_ERROR |
3301                                             STMF_RFLAG_RESET, info);
3302 
3303                                         mutex_enter(&iport->iport_worker_lock);
3304                                         iport->iport_ppicmd_term = ppicmd;
3305                                         return (DISC_ACTION_DELAY_RESCAN);
3306                                 }
3307                                 atomic_and_32(&icmd->icmd_flags,
3308                                     ~ICMD_FCA_ABORT_CALLED);
3309                         } else if ((flags & FCT_IOF_FORCE_FCA_DONE) ||
3310                             (abort_ret == FCT_ABORT_SUCCESS) ||
3311                             (abort_ret == FCT_NOT_FOUND)) {
3312                                 atomic_and_32(&icmd->icmd_flags,
3313                                     ~ICMD_KNOWN_TO_FCA);
3314                         }
3315                         ret |= DISC_ACTION_DELAY_RESCAN;
3316                 } else if (icmd->icmd_flags & ICMD_IMPLICIT) {
3317                         if (cmd->cmd_type == FCT_CMD_SOL_ELS)
3318                                 cmd->cmd_comp_status = FCT_ABORTED;
3319                         atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3320                         cmd_implicit = 1;
3321                 }
3322                 if ((icmd->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
3323                         fca_done = 1;
3324                 else
3325                         fca_done = 0;
3326                 if ((icmd->icmd_flags & ICMD_IN_IRP_QUEUE) == 0)
3327                         fct_done = 1;
3328                 else
3329                         fct_done = 0;
3330                 if ((fca_done || cmd_implicit) && fct_done) {
3331                         mutex_enter(&iport->iport_worker_lock);
3332                         ASSERT(*ppicmd == icmd);
3333                         *ppicmd = (*ppicmd)->icmd_next;
3334                         mutex_exit(&iport->iport_worker_lock);
3335                         if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) ||
3336                             (cmd->cmd_type == FCT_CMD_RCVD_ABTS)) {
3337                                 /* Free the cmd */
3338                                 fct_cmd_free(cmd);
3339                         } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
3340                                 fct_handle_sol_els_completion(iport, icmd);
3341                                 if (icmd->icmd_flags & ICMD_IMPLICIT) {
3342                                         if (IS_LOGO_ELS(icmd)) {
3343                                                 /* IMPLICIT LOGO is special */
3344                                                 fct_cmd_free(cmd);
3345                                         }
3346                                 }
3347                         } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3348                                 fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
3349 
3350                                 /* Tell the caller that we are done */
3351                                 atomic_or_32(&icmd->icmd_flags,
3352                                     ICMD_CMD_COMPLETE);
3353                                 if (fct_netbuf_to_value(
3354                                     ct->ct_req_payload + 8, 2) == NS_GID_PN) {
 
3390                                 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3391                                         fct_sol_ct_t *ct = cmd->cmd_specific;
3392                                         (void) snprintf(cmd_type,
3393                                             sizeof (cmd_type), "%x.%02x%02x",
3394                                             cmd->cmd_type,
3395                                             ct->ct_req_payload[8],
3396                                             ct->ct_req_payload[9]);
3397                                 } else {
3398                                         cmd_type[0] = 0;
3399                                 }
3400                                 st = cmd->cmd_comp_status;   /* gcc fix */
3401                                 (void) snprintf(info, sizeof (info),
3402                                     "fct_cmd_terminator:"
3403                                     " iport-%p, cmd_type(0x%s),"
3404                                     " reason(%llx)", (void *)iport, cmd_type,
3405                                     st);
3406                                 (void) fct_port_shutdown(port,
3407                                     STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET,
3408                                     info);
3409                         }
3410                         ppicmd = &((*ppicmd)->icmd_next);
3411                 }
3412 
3413                 if (ddi_get_lbolt() > endtime) {
3414                         mutex_enter(&iport->iport_worker_lock);
3415                         iport->iport_ppicmd_term = ppicmd;
3416                         return (DISC_ACTION_DELAY_RESCAN);
3417                 }
3418         }
3419         mutex_enter(&iport->iport_worker_lock);
3420         if (iport->iport_abort_queue)
3421                 return (DISC_ACTION_DELAY_RESCAN);
3422         if (ret == DISC_ACTION_NO_WORK)
3423                 return (DISC_ACTION_RESCAN);
3424         return (ret);
3425 }
3426 
3427 /*
3428  * Send a syslog event for adapter port level events.
3429  */
3430 void
3431 fct_log_local_port_event(fct_local_port_t *port, char *subclass)
3432 {
3433         nvlist_t *attr_list;
3434         int port_instance;
3435 
3436         if (!fct_dip)
3437                 return;
3438         port_instance = ddi_get_instance(fct_dip);
3439 
3440         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3441             KM_SLEEP) != DDI_SUCCESS) {
3442                 goto alloc_failed;
3443         }
3444 
3445         if (nvlist_add_uint32(attr_list, "instance", port_instance)
3446             != DDI_SUCCESS) {
3447                 goto error;
3448         }
3449 
3450         if (nvlist_add_byte_array(attr_list, "port-wwn",
3451             port->port_pwwn, 8) != DDI_SUCCESS) {
3452                 goto error;
3453         }
3454 
3455         (void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3456             subclass, attr_list, NULL, DDI_SLEEP);
3457 
3458         nvlist_free(attr_list);
3459         return;
3460 
3461 error:
3462         nvlist_free(attr_list);
3463 alloc_failed:
3464         stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3465             "Unable to send %s event", subclass);
3466 }
3467 
3468 void
3469 fct_log_remote_port_event(fct_local_port_t *port, char *subclass,
3470     uint8_t *rp_pwwn, uint32_t rp_id)
3471 {
3472         nvlist_t *attr_list;
3473         int port_instance;
3474 
3475         if (!fct_dip)
3476                 return;
3477         port_instance = ddi_get_instance(fct_dip);
3478 
3479         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3480             KM_SLEEP) != DDI_SUCCESS) {
3481                 goto alloc_failed;
3482         }
3483 
3484         if (nvlist_add_uint32(attr_list, "instance", port_instance)
3485             != DDI_SUCCESS) {
3486                 goto error;
3487         }
3488 
3489         if (nvlist_add_byte_array(attr_list, "port-wwn",
3490             port->port_pwwn, 8) != DDI_SUCCESS) {
3491                 goto error;
3492         }
3493 
3494         if (nvlist_add_byte_array(attr_list, "target-port-wwn",
3495             rp_pwwn, 8) != DDI_SUCCESS) {
3496                 goto error;
3497         }
3498 
3499         if (nvlist_add_uint32(attr_list, "target-port-id",
3500             rp_id) != DDI_SUCCESS) {
3501                 goto error;
3502         }
3503 
3504         (void) ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3505             subclass, attr_list, NULL, DDI_SLEEP);
3506 
3507         nvlist_free(attr_list);
3508         return;
3509 
3510 error:
3511         nvlist_free(attr_list);
3512 alloc_failed:
3513         stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3514             "Unable to send %s event", subclass);
3515 }
3516 
3517 uint64_t
3518 fct_netbuf_to_value(uint8_t *buf, uint8_t nbytes)
3519 {
3520         uint64_t        ret = 0;
3521         uint8_t         idx = 0;
3522 
3523         do {
3524                 ret |= (buf[idx] << (8 * (nbytes -idx - 1)));
3525         } while (++idx < nbytes);
 
 | 
 
 
  96 #define FCT_MODULE_NAME "fct"
  97 
  98 extern struct mod_ops mod_driverops;
  99 static struct modldrv modldrv = {
 100         &mod_driverops,
 101         FCT_NAME,
 102         &fct_ops
 103 };
 104 
 105 static struct modlinkage modlinkage = {
 106         MODREV_1,
 107         &modldrv,
 108         NULL
 109 };
 110 
 111 static uint32_t rportid_table_size = FCT_HASH_TABLE_SIZE;
 112 static int max_cached_ncmds = FCT_MAX_CACHED_CMDS;
 113 static fct_i_local_port_t *fct_iport_list = NULL;
 114 static kmutex_t fct_global_mutex;
 115 uint32_t fct_rscn_options = RSCN_OPTION_VERIFY;
 116 /*
 117  * This is to keep fibre channel from hanging if syseventd is
 118  * not working correctly and the queue fills. It is a tunable
 119  * to allow the user to force event logging to always happen
 120  * which is the default.
 121  */
 122 static uint8_t fct_force_log = 0;  /* use DDI_SLEEP on ddi_log_sysevent */
 123 
 124 /*
 125  * For use during core examination. These counts are normally really low
 126  * since they're bumped during port operations. If a customer core shows
 127  * really high values without having an uptime of a year something is most
 128  * likely wrong with their environment.
 129  */
 130 int fct_els_cnt = 0;
 131 int fct_abort_cnt = 0;
 132 
 133 int
 134 _init(void)
 135 {
 136         int ret;
 137 
 138         ret = mod_install(&modlinkage);
 139         if (ret)
 140                 return (ret);
 141         /* XXX */
 142         mutex_init(&fct_global_mutex, NULL, MUTEX_DRIVER, NULL);
 143         return (ret);
 144 }
 145 
 146 int
 147 _fini(void)
 148 {
 149         int ret;
 150 
 151         ret = mod_remove(&modlinkage);
 152         if (ret)
 
1187         if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
1188             taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
1189                 return (FCT_FAILURE);
1190         }
1191         mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
1192         cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
1193         rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
1194         sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
1195 
1196         /* Remote port mgmt */
1197         iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
1198             port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
1199         iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
1200             sizeof (fct_i_remote_port_t *), KM_SLEEP);
1201 
1202         /* fct_cmds for SCSI traffic */
1203         iport->iport_total_alloced_ncmds = 0;
1204         iport->iport_cached_ncmds = 0;
1205         port->port_fca_fcp_cmd_size =
1206             (port->port_fca_fcp_cmd_size + 7) & ~7;
1207         list_create(&iport->iport_cached_cmdlist, sizeof (fct_i_cmd_t),
1208             offsetof(fct_i_cmd_t, icmd_node));
1209         list_create(&iport->iport_abort_queue, sizeof (fct_i_cmd_t),
1210             offsetof(fct_i_cmd_t, icmd_node));
1211 
1212         mutex_init(&iport->iport_cached_cmd_lock, NULL, MUTEX_DRIVER, NULL);
1213 
1214         /* Initialize cmd slots */
1215         iport->iport_cmd_slots = (fct_cmd_slot_t *)kmem_zalloc(
1216             port->port_max_xchges * sizeof (fct_cmd_slot_t), KM_SLEEP);
1217         iport->iport_next_free_slot = 0;
1218         for (i = 0; i < port->port_max_xchges; ) {
1219                 slot = &iport->iport_cmd_slots[i];
1220                 slot->slot_no = (uint16_t)i;
1221                 slot->slot_next = (uint16_t)(++i);
1222         }
1223         slot->slot_next = FCT_SLOT_EOL;
1224         iport->iport_nslots_free = port->port_max_xchges;
1225 
1226         iport->iport_task_green_limit =
1227             (port->port_max_xchges * FCT_TASK_GREEN_LIMIT) / 100;
1228         iport->iport_task_yellow_limit =
1229             (port->port_max_xchges * FCT_TASK_YELLOW_LIMIT) / 100;
1230         iport->iport_task_red_limit =
1231             (port->port_max_xchges * FCT_TASK_RED_LIMIT) / 100;
 
1280         /* Stop the taskq 1st */
1281         if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1282                 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1283                 cv_broadcast(&iport->iport_worker_cv);
1284                 while (iport->iport_flags & IPORT_WORKER_RUNNING) {
1285                         delay(1);
1286                 }
1287         }
1288         ddi_taskq_destroy(iport->iport_worker_taskq);
1289         if (iport->iport_rp_tb) {
1290                 kmem_free(iport->iport_rp_tb, rportid_table_size *
1291                     sizeof (fct_i_remote_port_t *));
1292         }
1293         return (FCT_FAILURE);
1294 }
1295 
1296 fct_status_t
1297 fct_deregister_local_port(fct_local_port_t *port)
1298 {
1299         fct_i_local_port_t      *iport;
1300         fct_i_cmd_t             *icmd;
1301         int                     ndx;
1302 
1303         iport = (fct_i_local_port_t *)port->port_fct_private;
1304 
1305         if ((iport->iport_state != FCT_STATE_OFFLINE) ||
1306             iport->iport_state_not_acked) {
1307                 return (FCT_FAILURE);
1308         }
1309 
1310         /* Stop the taskq 1st */
1311         if (iport->iport_flags & IPORT_WORKER_RUNNING) {
1312                 atomic_or_32(&iport->iport_flags, IPORT_TERMINATE_WORKER);
1313                 cv_broadcast(&iport->iport_worker_cv);
1314                 for (ndx = 0; ndx < 100; ndx++) {
1315                         if ((iport->iport_flags & IPORT_WORKER_RUNNING)
1316                             == 0) {
1317                                 break;
1318                         }
1319                         delay(drv_usectohz(10000));
1320                 }
 
1325                 }
1326         }
1327 
1328         if (stmf_deregister_local_port(port->port_lport) != FCT_SUCCESS) {
1329                 goto fct_deregport_fail1;
1330         }
1331 
1332         mutex_enter(&fct_global_mutex);
1333         if (iport->iport_next)
1334                 iport->iport_next->iport_prev = iport->iport_prev;
1335         if (iport->iport_prev)
1336                 iport->iport_prev->iport_next = iport->iport_next;
1337         else
1338                 fct_iport_list = iport->iport_next;
1339         mutex_exit(&fct_global_mutex);
1340         /*
1341          * At this time, there should be no outstanding and pending
1342          * I/Os, so we can just release resources.
1343          */
1344         ASSERT(iport->iport_total_alloced_ncmds == iport->iport_cached_ncmds);
1345         while (!list_is_empty(&iport->iport_cached_cmdlist)) {
1346                 icmd = list_remove_head(&iport->iport_cached_cmdlist);
1347                 fct_free(icmd);
1348         }
1349         mutex_destroy(&iport->iport_cached_cmd_lock);
1350         kmem_free(iport->iport_cmd_slots, port->port_max_xchges *
1351             sizeof (fct_cmd_slot_t));
1352         kmem_free(iport->iport_rp_slots, port->port_max_logins *
1353             sizeof (fct_i_remote_port_t *));
1354         rw_destroy(&iport->iport_lock);
1355         cv_destroy(&iport->iport_worker_cv);
1356         sema_destroy(&iport->iport_rls_sema);
1357         mutex_destroy(&iport->iport_worker_lock);
1358         ddi_taskq_destroy(iport->iport_worker_taskq);
1359         if (iport->iport_rp_tb) {
1360                 kmem_free(iport->iport_rp_tb, rportid_table_size *
1361                     sizeof (fct_i_remote_port_t *));
1362         }
1363 
1364         if (iport->iport_kstat_portstat) {
1365                 kstat_delete(iport->iport_kstat_portstat);
1366         }
1367 
 
1480                         iport->iport_rp_tb[hash_key] =
1481                             irp->irp_next;
1482                 } else {
1483                         irp_last->irp_next = irp->irp_next;
1484                 }
1485                 irp->irp_next = NULL;
1486                 iport->iport_nrps--;
1487         }
1488 }
1489 
1490 int
1491 fct_is_irp_logging_out(fct_i_remote_port_t *irp, int force_implicit)
1492 {
1493         int logging_out = 0;
1494 
1495         rw_enter(&irp->irp_lock, RW_WRITER);
1496         if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1497                 logging_out = 0;
1498                 goto ilo_done;
1499         }
1500         if (list_is_empty(&irp->irp_els_list) && (irp->irp_deregister_timer)) {
1501                 if (force_implicit && irp->irp_nonfcp_xchg_count) {
1502                         logging_out = 0;
1503                 } else {
1504                         logging_out = 1;
1505                 }
1506                 goto ilo_done;
1507         }
1508         if (!list_is_empty(&irp->irp_els_list)) {
1509                 fct_i_cmd_t *icmd;
1510                 /* Last session affecting ELS should be a LOGO */
1511                 for (icmd = list_head(&irp->irp_els_list); icmd;
1512                     icmd = list_next(&irp->irp_els_list, icmd)) {
1513                         uint8_t op = (ICMD_TO_ELS(icmd))->els_req_payload[0];
1514                         if (op == ELS_OP_LOGO) {
1515                                 if (force_implicit) {
1516                                         if (icmd->icmd_flags & ICMD_IMPLICIT)
1517                                                 logging_out = 1;
1518                                         else
1519                                                 logging_out = 0;
1520                                 } else {
1521                                         logging_out = 1;
1522                                 }
1523                         } else if ((op == ELS_OP_PLOGI) ||
1524                             (op == ELS_OP_PRLI) ||
1525                             (op == ELS_OP_PRLO) || (op == ELS_OP_TPRLO)) {
1526                                 logging_out = 0;
1527                         }
1528                 }
1529         }
1530 ilo_done:;
1531         rw_exit(&irp->irp_lock);
1532 
 
1616         fct_i_remote_port_t *irp;
1617         int i;
1618 
1619         if (iport->iport_nrps_login)
1620                 return (0);
1621         /* loop all rps to check if the cmd have already been drained */
1622         for (i = 0; i < rportid_table_size; i++) {
1623                 irp = iport->iport_rp_tb[i];
1624                 while (irp) {
1625                         if (irp->irp_fcp_xchg_count ||
1626                             irp->irp_nonfcp_xchg_count)
1627                                 return (0);
1628                         irp = irp->irp_next;
1629                 }
1630         }
1631         return (1);
1632 }
1633 
1634 fct_cmd_t *
1635 fct_scsi_task_alloc(fct_local_port_t *port, uint16_t rp_handle,
1636     uint32_t rportid, uint8_t *lun, uint16_t cdb_length,
1637     uint16_t task_ext)
1638 {
1639         fct_cmd_t *cmd;
1640         fct_i_cmd_t *icmd;
1641         fct_i_local_port_t *iport =
1642             (fct_i_local_port_t *)port->port_fct_private;
1643         fct_i_remote_port_t *irp;
1644         scsi_task_t *task;
1645         fct_remote_port_t *rp;
1646         uint16_t cmd_slot;
1647 
1648         rw_enter(&iport->iport_lock, RW_READER);
1649         if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
1650                 rw_exit(&iport->iport_lock);
1651                 stmf_trace(iport->iport_alias, "cmd alloc called while the port"
1652                     " was offline");
1653                 return (NULL);
1654         }
1655 
1656         if (rp_handle == FCT_HANDLE_NONE) {
1657                 irp = fct_portid_to_portptr(iport, rportid);
 
1665                 if ((rp_handle >= port->port_max_logins) ||
1666                     ((irp = iport->iport_rp_slots[rp_handle]) == NULL)) {
1667                         rw_exit(&iport->iport_lock);
1668                         stmf_trace(iport->iport_alias, "cmd received from "
1669                             "invalid port handle %x", rp_handle);
1670                         return (NULL);
1671                 }
1672         }
1673         rp = irp->irp_rp;
1674 
1675         rw_enter(&irp->irp_lock, RW_READER);
1676         if ((irp->irp_flags & IRP_PRLI_DONE) == 0) {
1677                 rw_exit(&irp->irp_lock);
1678                 rw_exit(&iport->iport_lock);
1679                 stmf_trace(iport->iport_alias, "cmd alloc called while fcp "
1680                     "login was not done. portid=%x, rp=%p", rp->rp_id, rp);
1681                 return (NULL);
1682         }
1683 
1684         mutex_enter(&iport->iport_cached_cmd_lock);
1685         if (!list_is_empty(&iport->iport_cached_cmdlist)) {
1686                 icmd = list_remove_head(&iport->iport_cached_cmdlist);
1687                 iport->iport_cached_ncmds--;
1688                 cmd = icmd->icmd_cmd;
1689         } else {
1690                 icmd = NULL;
1691         }
1692         mutex_exit(&iport->iport_cached_cmd_lock);
1693         if (icmd == NULL) {
1694                 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
1695                     port->port_fca_fcp_cmd_size, 0);
1696                 if (cmd == NULL) {
1697                         rw_exit(&irp->irp_lock);
1698                         rw_exit(&iport->iport_lock);
1699                         stmf_trace(iport->iport_alias, "Ran out of "
1700                             "memory, port=%p", port);
1701                         return (NULL);
1702                 }
1703 
1704                 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1705                 list_link_init(&icmd->icmd_node);
1706                 cmd->cmd_port = port;
1707                 atomic_inc_32(&iport->iport_total_alloced_ncmds);
1708         }
1709 
1710         /*
1711          * The accuracy of iport_max_active_ncmds is not important
1712          */
1713         if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
1714             iport->iport_max_active_ncmds) {
1715                 iport->iport_max_active_ncmds =
1716                     iport->iport_total_alloced_ncmds -
1717                     iport->iport_cached_ncmds;
1718         }
1719 
1720         /* Lets get a slot */
1721         cmd_slot = fct_alloc_cmd_slot(iport, cmd);
1722         if (cmd_slot == FCT_SLOT_EOL) {
1723                 rw_exit(&irp->irp_lock);
1724                 rw_exit(&iport->iport_lock);
1725                 stmf_trace(iport->iport_alias, "Ran out of xchg resources");
 
1889                  */
1890                 new = ((old + (0x10000)) & 0xFFFF0000);
1891                 new |= iport->iport_cmd_slots[cmd_slot].slot_next;
1892         } while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
1893 
1894         atomic_dec_16(&iport->iport_nslots_free);
1895         iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
1896         cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
1897             (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
1898             << 24);
1899         return (cmd_slot);
1900 }
1901 
1902 /*
1903  * If icmd is not NULL, irp_lock must be held
1904  */
1905 void
1906 fct_post_to_discovery_queue(fct_i_local_port_t *iport,
1907     fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
1908 {
1909         ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
1910         if (icmd) {
1911                 list_insert_tail(&irp->irp_els_list, icmd);
1912                 fct_els_cnt++;
1913                 atomic_or_32(&icmd->icmd_flags, ICMD_IN_IRP_QUEUE);
1914         }
1915 
1916         mutex_enter(&iport->iport_worker_lock);
1917         if ((irp->irp_flags & IRP_IN_DISCOVERY_QUEUE) == 0) {
1918 
1919                 /*
1920                  * CAUTION: do not grab local_port/remote_port locks after
1921                  * grabbing the worker lock.
1922                  */
1923                 irp->irp_discovery_next = NULL;
1924                 if (iport->iport_rpwe_tail) {
1925                         iport->iport_rpwe_tail->irp_discovery_next = irp;
1926                         iport->iport_rpwe_tail = irp;
1927                 } else {
1928                         iport->iport_rpwe_head = iport->iport_rpwe_tail = irp;
1929                 }
1930 
1931                 atomic_or_32(&irp->irp_flags, IRP_IN_DISCOVERY_QUEUE);
1932         }
 
2124                          * XXX Throw HBA fatal error event
2125                          * Later shutdown svc will terminate the ABTS in the end
2126                          */
2127                         (void) snprintf(info, sizeof (info),
2128                             "fct_cmd_free: iport-%p, ABTS_ACC"
2129                             " port_send_cmd_response failed", (void *)iport);
2130                         (void) fct_port_shutdown(iport->iport_port,
2131                             STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2132                         return;
2133                 } else {
2134                         fct_cmd_free(lcmd);
2135                         cmd->cmd_link = NULL;
2136                 }
2137         }
2138 
2139         /* Free the cmd */
2140         if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2141                 if (iport->iport_cached_ncmds < max_cached_ncmds) {
2142                         icmd->icmd_flags = 0;
2143                         mutex_enter(&iport->iport_cached_cmd_lock);
2144                         list_insert_head(&iport->iport_cached_cmdlist, icmd);
2145                         iport->iport_cached_ncmds++;
2146                         mutex_exit(&iport->iport_cached_cmd_lock);
2147                 } else {
2148                         atomic_dec_32(&iport->iport_total_alloced_ncmds);
2149                         fct_free(cmd);
2150                 }
2151         } else {
2152                 fct_free(cmd);
2153         }
2154 }
2155 
2156 /* ARGSUSED */
2157 stmf_status_t
2158 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
2159     uint32_t flags)
2160 {
2161         stmf_status_t ret = STMF_SUCCESS;
2162         scsi_task_t *task;
2163         fct_cmd_t *cmd;
2164         fct_i_cmd_t *icmd;
 
2827         fct_i_cmd_t             *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2828         char                    info[FCT_INFO_LEN];
2829         unsigned long long      st;
2830 
2831         st = s; /* To make gcc happy */
2832         ASSERT(icmd->icmd_flags & ICMD_BEING_ABORTED);
2833         if ((((s != FCT_ABORT_SUCCESS) && (s != FCT_NOT_FOUND))) ||
2834             ((ioflags & FCT_IOF_FCA_DONE) == 0)) {
2835                 (void) snprintf(info, sizeof (info),
2836                     "fct_cmd_fca_aborted: cmd-%p, "
2837                     "s-%llx, iofalgs-%x", (void *)cmd, st, ioflags);
2838                 (void) fct_port_shutdown(cmd->cmd_port,
2839                     STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2840                 return;
2841         }
2842 
2843         atomic_and_32(&icmd->icmd_flags, ~ICMD_KNOWN_TO_FCA);
2844         /* For non FCP Rest of the work is done by the terminator */
2845         /* For FCP stuff just call stmf */
2846         if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2847                 stmf_task_lport_aborted_unlocked(
2848                     (scsi_task_t *)cmd->cmd_specific, s, STMF_IOF_LPORT_DONE);
2849         }
2850 }
2851 
2852 /*
2853  * FCA drivers will use it, when they want to abort some FC transactions
2854  * due to lack of resource.
2855  */
2856 uint16_t
2857 fct_get_rp_handle(fct_local_port_t *port, uint32_t rportid)
2858 {
2859         fct_i_remote_port_t     *irp;
2860 
2861         irp = fct_portid_to_portptr(
2862             (fct_i_local_port_t *)(port->port_fct_private), rportid);
2863         if (irp == NULL) {
2864                 return (0xFFFF);
2865         } else {
2866                 return (irp->irp_rp->rp_handle);
2867         }
2868 }
 
2901                 new = old | ICMD_BEING_ABORTED;
2902         } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
2903         stmf_abort(STMF_QUEUE_TASK_ABORT, (scsi_task_t *)cmd->cmd_specific,
2904             s, NULL);
2905 }
2906 
2907 void
2908 fct_fill_abts_acc(fct_cmd_t *cmd)
2909 {
2910         fct_rcvd_abts_t *abts = (fct_rcvd_abts_t *)cmd->cmd_specific;
2911         uint8_t *p;
2912 
2913         abts->abts_resp_rctl = BLS_OP_BA_ACC;
2914         p = abts->abts_resp_payload;
2915         bzero(p, 12);
2916         *((uint16_t *)(p+4)) = BE_16(cmd->cmd_oxid);
2917         *((uint16_t *)(p+6)) = BE_16(cmd->cmd_rxid);
2918         p[10] = p[11] = 0xff;
2919 }
2920 
2921 /*
2922  * fct_cmd_unlink_els -- remove icmd from ELS queue
2923  *
2924  * The commands are found via the slot array of active commands and will be
2925  * terminated shortly after being removed.
2926  */
2927 void
2928 fct_cmd_unlink_els(fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
2929 {
2930         ASSERT(rw_write_held(&irp->irp_lock));
2931         if (icmd->icmd_node.list_next) {
2932                 /*
2933                  * Command is on two queues. Determine which queue and
2934                  * handle appropriately.
2935                  */
2936                 if (icmd->icmd_flags & ICMD_IN_IRP_QUEUE) {
2937                         /*
2938                          * If the command is active on the IRP queue it
2939                          * will be freed during command termination
2940                          * processing. Unfortuntely the ELS processing will
2941                          * peek at the command and possibly panic if it's
2942                          * been freed already. Remove it from the ELS
2943                          * queue to avoid that.
2944                          */
2945                         if (icmd->icmd_flags & ICMD_SESSION_AFFECTING)
2946                                 atomic_dec_16(&irp->irp_sa_elses_count);
2947                         else
2948                                 atomic_dec_16(&irp->irp_nsa_elses_count);
2949                         atomic_and_32(&icmd->icmd_flags, ~ICMD_IN_IRP_QUEUE);
2950                         list_remove(&irp->irp_els_list, icmd);
2951                 }
2952                 /*
2953                  * There's an else case here, but the processing is handled
2954                  * in fct_check_solcmd_queue(). In this case the command
2955                  * is on the solicited queue and will be marked as aborted.
2956                  * During command termination processing the command will be
2957                  * marked as complete, but not freed. The freeing of the memory
2958                  * is done in fct_check_solcmd_queue(). If that routine, which
2959                  * holds the appropriate lock, is run first it will remove the
2960                  * command from the abort queue so that no memory access
2961                  * is done after the command has been freed.
2962                  */
2963         }
2964 }
2965 
2966 void
2967 fct_handle_rcvd_abts(fct_cmd_t *cmd)
2968 {
2969         char                    info[FCT_INFO_LEN];
2970         fct_local_port_t        *port = cmd->cmd_port;
2971         fct_i_local_port_t      *iport =
2972             (fct_i_local_port_t *)port->port_fct_private;
2973         fct_i_cmd_t             *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
2974         fct_i_remote_port_t     *irp;
2975         fct_cmd_t               *c = NULL, *term_cmd;
2976         fct_i_cmd_t             *ic = NULL;
2977         int                     found = 0;
2978         int                     i;
2979         fct_status_t            term_val;
2980 
2981         icmd->icmd_start_time = ddi_get_lbolt();
2982         icmd->icmd_flags |= ICMD_KNOWN_TO_FCA;
2983 
2984         rw_enter(&iport->iport_lock, RW_WRITER);
2985         /* Make sure local port is sane */
2986         if ((iport->iport_link_state & S_LINK_ONLINE) == 0) {
2987                 rw_exit(&iport->iport_lock);
2988                 stmf_trace(iport->iport_alias, "ABTS not posted becasue"
2989                     "port state was %x", iport->iport_link_state);
2990                 fct_queue_cmd_for_termination(cmd, FCT_LOCAL_PORT_OFFLINE);
2991                 return;
2992         }
2993 
2994         if (cmd->cmd_rp_handle == FCT_HANDLE_NONE)
2995                 irp = fct_portid_to_portptr(iport, cmd->cmd_rportid);
2996         else if (cmd->cmd_rp_handle < port->port_max_logins)
2997                 irp = iport->iport_rp_slots[cmd->cmd_rp_handle];
2998         else
2999                 irp = NULL;
 
3042                 /* Dont even bother queueing it. Just respond */
3043                 fct_fill_abts_acc(cmd);
3044                 if (port->port_send_cmd_response(cmd,
3045                     FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
3046                         /*
3047                          * XXX Throw HBA fatal error event
3048                          * Later shutdown svc will terminate the ABTS in the end
3049                          */
3050                         (void) snprintf(info, sizeof (info),
3051                             "fct_handle_rcvd_abts: iport-%p, "
3052                             "ABTS_ACC port_send_cmd_response failed",
3053                             (void *)iport);
3054                         (void) fct_port_shutdown(iport->iport_port,
3055                             STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
3056                 } else {
3057                         fct_cmd_free(cmd);
3058                 }
3059                 return;
3060         }
3061 
3062         fct_cmd_unlink_els(irp, ic);
3063 
3064         /* Check if this an abts retry */
3065         if (c->cmd_link && (ic->icmd_flags & ICMD_ABTS_RECEIVED)) {
3066                 /* Kill this abts. */
3067                 term_cmd = icmd->icmd_cmd;
3068                 term_val = FCT_ABORTED;
3069         } else {
3070                 c->cmd_link = cmd;
3071                 atomic_or_32(&ic->icmd_flags, ICMD_ABTS_RECEIVED);
3072                 cmd->cmd_link = c;
3073                 term_cmd = c;
3074                 term_val = FCT_ABTS_RECEIVED;
3075         }
3076         mutex_exit(&iport->iport_worker_lock);
3077         rw_exit(&irp->irp_lock);
3078         fct_queue_cmd_for_termination(term_cmd, term_val);
3079         rw_exit(&iport->iport_lock);
3080 }
3081 
3082 void
3083 fct_queue_cmd_for_termination(fct_cmd_t *cmd, fct_status_t s)
3084 {
3085         fct_local_port_t *port = cmd->cmd_port;
3086         fct_i_local_port_t *iport = (fct_i_local_port_t *)
3087             port->port_fct_private;
3088         fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
3089 
3090         if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
3091                 fct_queue_scsi_task_for_termination(cmd, s);
3092                 return;
3093         }
3094         mutex_enter(&iport->iport_worker_lock);
3095         fct_q_for_termination_lock_held(iport, icmd, s);
3096         if (IS_WORKER_SLEEPING(iport))
3097                 cv_signal(&iport->iport_worker_cv);
3098         mutex_exit(&iport->iport_worker_lock);
3099 }
3100 
3101 /*
3102  * This function will not be called for SCSI CMDS
3103  */
3104 void
3105 fct_q_for_termination_lock_held(fct_i_local_port_t *iport, fct_i_cmd_t *icmd,
3106     fct_status_t s)
3107 {
3108         uint32_t old, new;
3109 
3110         do {
3111                 old = icmd->icmd_flags;
3112                 if (old & ICMD_BEING_ABORTED)
3113                         return;
3114                 new = old | ICMD_BEING_ABORTED;
3115         } while (atomic_cas_32(&icmd->icmd_flags, old, new) != old);
3116 
3117         icmd->icmd_start_time = ddi_get_lbolt();
3118         icmd->icmd_cmd->cmd_comp_status = s;
3119 
3120         list_insert_tail(&iport->iport_abort_queue, icmd);
3121         fct_abort_cnt++;
3122 }
3123 
3124 /*
3125  * For those cmds, for which we called fca_abort but it has not yet completed,
3126  * reset the FCA_ABORT_CALLED flag, so that abort can be called again.
3127  * This is done after a FCA offline. The reason is that after offline, the
3128  * firmware is not running so abort will never complete. But if we call it
3129  * again, the FCA will detect that it is not offline and it will
3130  * not call the firmware at all. Most likely it will abort in a synchronous
3131  * manner i.e. return FCT_ABORT_SUCCESS or FCT_NOT_FOUND.
3132  */
3133 void
3134 fct_reset_flag_abort_called(fct_i_local_port_t *iport)
3135 {
3136         fct_i_cmd_t *icmd;
3137         uint32_t old, new;
3138         int i, do_clear;
3139 
3140         ASSERT(mutex_owned(&iport->iport_worker_lock));
3141         mutex_exit(&iport->iport_worker_lock);
 
3280 {
3281         stmf_state_change_info_t st;
3282 
3283         st.st_rflags = rflags;
3284         st.st_additional_info = additional_info;
3285         stmf_trace(NULL, "fct_port_shutdown: port-%p, %s", port,
3286             additional_info? additional_info : "no more information");
3287         return (stmf_ctl(STMF_CMD_LPORT_OFFLINE, port->port_lport, &st));
3288 }
3289 
3290 /*
3291  * Called by worker thread. The aim is to terminate the command
3292  * using whatever means it takes.
3293  * Called with worker lock held.
3294  */
3295 disc_action_t
3296 fct_cmd_terminator(fct_i_local_port_t *iport)
3297 {
3298         char                    info[FCT_INFO_LEN];
3299         clock_t                 endtime;
3300         fct_i_cmd_t             *next;
3301         fct_i_cmd_t             *icmd;
3302         fct_cmd_t               *cmd;
3303         fct_local_port_t        *port = iport->iport_port;
3304         disc_action_t           ret = DISC_ACTION_NO_WORK;
3305         fct_status_t            abort_ret;
3306         int                     fca_done, fct_done, cmd_implicit = 0;
3307         int                     flags;
3308         unsigned long long      st;
3309 
3310         /* Lets Limit each run to 20ms max. */
3311         endtime = ddi_get_lbolt() + drv_usectohz(20000);
3312 
3313         /* Start from where we left off last time */
3314         if (iport->iport_ppicmd_term) {
3315                 icmd = iport->iport_ppicmd_term;
3316                 iport->iport_ppicmd_term = NULL;
3317         } else {
3318                 icmd = list_head(&iport->iport_abort_queue);
3319         }
3320 
3321         /*
3322          * Once a command gets on discovery queue, this is the only thread
3323          * which can access it. So no need for the lock here.
3324          */
3325         mutex_exit(&iport->iport_worker_lock);
3326 
3327         while (icmd) {
3328                 cmd = icmd->icmd_cmd;
3329 
3330                 /* Always remember that cmd->cmd_rp can be NULL */
3331                 if ((icmd->icmd_flags & (ICMD_KNOWN_TO_FCA |
3332                     ICMD_FCA_ABORT_CALLED)) == ICMD_KNOWN_TO_FCA) {
3333                         atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3334                         if (CMD_HANDLE_VALID(cmd->cmd_handle))
3335                                 flags = 0;
3336                         else
3337                                 flags = FCT_IOF_FORCE_FCA_DONE;
3338                         abort_ret = port->port_abort_cmd(port, cmd, flags);
3339                         if ((abort_ret != FCT_SUCCESS) &&
3340                             (abort_ret != FCT_ABORT_SUCCESS) &&
3341                             (abort_ret != FCT_NOT_FOUND)) {
3342                                 if (flags & FCT_IOF_FORCE_FCA_DONE) {
3343                                         /*
3344                                          * XXX trigger port fatal,
3345                                          * Abort the termination, and shutdown
3346                                          * svc will trigger fct_cmd_termination
3347                                          * again.
3348                                          */
3349                                         (void) snprintf(info, sizeof (info),
3350                                             "fct_cmd_terminator:"
3351                                             " iport-%p, port_abort_cmd with "
3352                                             "FORCE_FCA_DONE failed",
3353                                             (void *)iport);
3354                                         (void) fct_port_shutdown(
3355                                             iport->iport_port,
3356                                             STMF_RFLAG_FATAL_ERROR |
3357                                             STMF_RFLAG_RESET, info);
3358 
3359                                         mutex_enter(&iport->iport_worker_lock);
3360                                         iport->iport_ppicmd_term = icmd;
3361                                         return (DISC_ACTION_DELAY_RESCAN);
3362                                 }
3363                                 atomic_and_32(&icmd->icmd_flags,
3364                                     ~ICMD_FCA_ABORT_CALLED);
3365                         } else if ((flags & FCT_IOF_FORCE_FCA_DONE) ||
3366                             (abort_ret == FCT_ABORT_SUCCESS) ||
3367                             (abort_ret == FCT_NOT_FOUND)) {
3368                                 atomic_and_32(&icmd->icmd_flags,
3369                                     ~ICMD_KNOWN_TO_FCA);
3370                         }
3371                         ret |= DISC_ACTION_DELAY_RESCAN;
3372                 } else if (icmd->icmd_flags & ICMD_IMPLICIT) {
3373                         if (cmd->cmd_type == FCT_CMD_SOL_ELS)
3374                                 cmd->cmd_comp_status = FCT_ABORTED;
3375                         atomic_or_32(&icmd->icmd_flags, ICMD_FCA_ABORT_CALLED);
3376                         cmd_implicit = 1;
3377                 }
3378                 if ((icmd->icmd_flags & ICMD_KNOWN_TO_FCA) == 0)
3379                         fca_done = 1;
3380                 else
3381                         fca_done = 0;
3382                 if ((icmd->icmd_flags & ICMD_IN_IRP_QUEUE) == 0)
3383                         fct_done = 1;
3384                 else
3385                         fct_done = 0;
3386                 if ((fca_done || cmd_implicit) && fct_done) {
3387                         mutex_enter(&iport->iport_worker_lock);
3388                         next = list_next(&iport->iport_abort_queue, icmd);
3389                         list_remove(&iport->iport_abort_queue, icmd);
3390                         mutex_exit(&iport->iport_worker_lock);
3391 
3392                         if ((cmd->cmd_type == FCT_CMD_RCVD_ELS) ||
3393                             (cmd->cmd_type == FCT_CMD_RCVD_ABTS)) {
3394                                 /* Free the cmd */
3395                                 fct_cmd_free(cmd);
3396                         } else if (cmd->cmd_type == FCT_CMD_SOL_ELS) {
3397                                 fct_handle_sol_els_completion(iport, icmd);
3398                                 if (icmd->icmd_flags & ICMD_IMPLICIT) {
3399                                         if (IS_LOGO_ELS(icmd)) {
3400                                                 /* IMPLICIT LOGO is special */
3401                                                 fct_cmd_free(cmd);
3402                                         }
3403                                 }
3404                         } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3405                                 fct_sol_ct_t *ct = ICMD_TO_CT(icmd);
3406 
3407                                 /* Tell the caller that we are done */
3408                                 atomic_or_32(&icmd->icmd_flags,
3409                                     ICMD_CMD_COMPLETE);
3410                                 if (fct_netbuf_to_value(
3411                                     ct->ct_req_payload + 8, 2) == NS_GID_PN) {
 
3447                                 } else if (cmd->cmd_type == FCT_CMD_SOL_CT) {
3448                                         fct_sol_ct_t *ct = cmd->cmd_specific;
3449                                         (void) snprintf(cmd_type,
3450                                             sizeof (cmd_type), "%x.%02x%02x",
3451                                             cmd->cmd_type,
3452                                             ct->ct_req_payload[8],
3453                                             ct->ct_req_payload[9]);
3454                                 } else {
3455                                         cmd_type[0] = 0;
3456                                 }
3457                                 st = cmd->cmd_comp_status;   /* gcc fix */
3458                                 (void) snprintf(info, sizeof (info),
3459                                     "fct_cmd_terminator:"
3460                                     " iport-%p, cmd_type(0x%s),"
3461                                     " reason(%llx)", (void *)iport, cmd_type,
3462                                     st);
3463                                 (void) fct_port_shutdown(port,
3464                                     STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET,
3465                                     info);
3466                         }
3467                         mutex_enter(&iport->iport_worker_lock);
3468                         next = list_next(&iport->iport_abort_queue, icmd);
3469                         mutex_exit(&iport->iport_worker_lock);
3470                 }
3471 
3472                 if (ddi_get_lbolt() > endtime) {
3473                         mutex_enter(&iport->iport_worker_lock);
3474                         iport->iport_ppicmd_term = next;
3475                         return (DISC_ACTION_DELAY_RESCAN);
3476                 } else {
3477                         icmd = next;
3478                 }
3479         }
3480         mutex_enter(&iport->iport_worker_lock);
3481         if (!list_is_empty(&iport->iport_abort_queue))
3482                 return (DISC_ACTION_DELAY_RESCAN);
3483         if (ret == DISC_ACTION_NO_WORK)
3484                 return (DISC_ACTION_RESCAN);
3485         return (ret);
3486 }
3487 
3488 /*
3489  * Send a syslog event for adapter port level events.
3490  */
3491 void
3492 fct_log_local_port_event(fct_local_port_t *port, char *subclass)
3493 {
3494         nvlist_t *attr_list;
3495         int port_instance;
3496         int rc, sleep = DDI_SLEEP;
3497 
3498         if (!fct_dip)
3499                 return;
3500         port_instance = ddi_get_instance(fct_dip);
3501 
3502         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3503             KM_SLEEP) != DDI_SUCCESS) {
3504                 goto alloc_failed;
3505         }
3506 
3507         if (nvlist_add_uint32(attr_list, "instance", port_instance)
3508             != DDI_SUCCESS) {
3509                 goto error;
3510         }
3511 
3512         if (nvlist_add_byte_array(attr_list, "port-wwn",
3513             port->port_pwwn, 8) != DDI_SUCCESS) {
3514                 goto error;
3515         }
3516 
3517         if (fct_force_log == 0) {
3518                 sleep = DDI_NOSLEEP;
3519         }
3520         rc = ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3521             subclass, attr_list, NULL, sleep);
3522         if (rc != DDI_SUCCESS) {
3523                 cmn_err(CE_WARN, "%s: queue full event lost", __func__);
3524                 goto error;
3525         }
3526 
3527         nvlist_free(attr_list);
3528         return;
3529 
3530 error:
3531         nvlist_free(attr_list);
3532 alloc_failed:
3533         stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3534             "Unable to send %s event", subclass);
3535 }
3536 
3537 void
3538 fct_log_remote_port_event(fct_local_port_t *port, char *subclass,
3539     uint8_t *rp_pwwn, uint32_t rp_id)
3540 {
3541         nvlist_t *attr_list;
3542         int port_instance;
3543         int rc, sleep = DDI_SLEEP;
3544 
3545         if (!fct_dip)
3546                 return;
3547         port_instance = ddi_get_instance(fct_dip);
3548 
3549         if (nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE,
3550             KM_SLEEP) != DDI_SUCCESS) {
3551                 goto alloc_failed;
3552         }
3553 
3554         if (nvlist_add_uint32(attr_list, "instance", port_instance)
3555             != DDI_SUCCESS) {
3556                 goto error;
3557         }
3558 
3559         if (nvlist_add_byte_array(attr_list, "port-wwn",
3560             port->port_pwwn, 8) != DDI_SUCCESS) {
3561                 goto error;
3562         }
3563 
3564         if (nvlist_add_byte_array(attr_list, "target-port-wwn",
3565             rp_pwwn, 8) != DDI_SUCCESS) {
3566                 goto error;
3567         }
3568 
3569         if (nvlist_add_uint32(attr_list, "target-port-id",
3570             rp_id) != DDI_SUCCESS) {
3571                 goto error;
3572         }
3573 
3574         if (fct_force_log == 0) {
3575                 sleep = DDI_NOSLEEP;
3576         }
3577         rc = ddi_log_sysevent(fct_dip, DDI_VENDOR_SUNW, EC_SUNFC,
3578             subclass, attr_list, NULL, sleep);
3579         if (rc != DDI_SUCCESS) {
3580                 cmn_err(CE_WARN, "%s:event dropped", __func__);
3581                 goto error;
3582         }
3583 
3584         nvlist_free(attr_list);
3585         return;
3586 
3587 error:
3588         nvlist_free(attr_list);
3589 alloc_failed:
3590         stmf_trace(((fct_i_local_port_t *)port->port_fct_private)->iport_alias,
3591             "Unable to send %s event", subclass);
3592 }
3593 
3594 uint64_t
3595 fct_netbuf_to_value(uint8_t *buf, uint8_t nbytes)
3596 {
3597         uint64_t        ret = 0;
3598         uint8_t         idx = 0;
3599 
3600         do {
3601                 ret |= (buf[idx] << (8 * (nbytes -idx - 1)));
3602         } while (++idx < nbytes);
 
 |