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);
|