1145 "fct: %s driver version mismatch",
1146 port->port_default_alias);
1147 return (FCT_FAILURE);
1148 }
1149 if (port->port_default_alias) {
1150 int l = strlen(port->port_default_alias);
1151
1152 if (l < 16) {
1153 iport->iport_alias = iport->iport_alias_mem;
1154 } else {
1155 iport->iport_alias =
1156 (char *)kmem_zalloc(l+1, KM_SLEEP);
1157 }
1158 (void) strcpy(iport->iport_alias, port->port_default_alias);
1159 } else {
1160 iport->iport_alias = NULL;
1161 }
1162 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)iport->iport_id,
1163 port->port_pwwn, PROTOCOL_FIBRE_CHANNEL);
1164 (void) snprintf(taskq_name, sizeof (taskq_name), "stmf_fct_taskq_%d",
1165 atomic_add_32_nv(&taskq_cntr, 1));
1166 if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
1167 taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
1168 return (FCT_FAILURE);
1169 }
1170 mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
1171 cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
1172 rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
1173 sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
1174
1175 /* Remote port mgmt */
1176 iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
1177 port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
1178 iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
1179 sizeof (fct_i_remote_port_t *), KM_SLEEP);
1180
1181 /* fct_cmds for SCSI traffic */
1182 iport->iport_total_alloced_ncmds = 0;
1183 iport->iport_cached_ncmds = 0;
1184 port->port_fca_fcp_cmd_size =
1185 (port->port_fca_fcp_cmd_size + 7) & ~7;
1423 iport->iport_rp_tb[hash_key] = irp;
1424 iport->iport_nrps++;
1425 }
1426
1427 /*
1428 * Called with irp_lock and iport_lock held as writer.
1429 */
1430 void
1431 fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
1432 {
1433 fct_i_remote_port_t *irp_next = NULL;
1434 fct_i_remote_port_t *irp_last = NULL;
1435 int hash_key =
1436 FCT_PORTID_HASH_FUNC(irp->irp_portid);
1437
1438 irp_next = iport->iport_rp_tb[hash_key];
1439 irp_last = NULL;
1440 while (irp_next != NULL) {
1441 if (irp == irp_next) {
1442 if (irp->irp_flags & IRP_PLOGI_DONE) {
1443 atomic_add_32(&iport->iport_nrps_login, -1);
1444 }
1445 atomic_and_32(&irp->irp_flags,
1446 ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1447 break;
1448 }
1449 irp_last = irp_next;
1450 irp_next = irp_next->irp_next;
1451 }
1452
1453 if (irp_next) {
1454 if (irp_last == NULL) {
1455 iport->iport_rp_tb[hash_key] =
1456 irp->irp_next;
1457 } else {
1458 irp_last->irp_next = irp->irp_next;
1459 }
1460 irp->irp_next = NULL;
1461 iport->iport_nrps--;
1462 }
1463 }
1661 iport->iport_cached_ncmds--;
1662 cmd = icmd->icmd_cmd;
1663 } else {
1664 icmd = NULL;
1665 }
1666 mutex_exit(&iport->iport_cached_cmd_lock);
1667 if (icmd == NULL) {
1668 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
1669 port->port_fca_fcp_cmd_size, 0);
1670 if (cmd == NULL) {
1671 rw_exit(&irp->irp_lock);
1672 rw_exit(&iport->iport_lock);
1673 stmf_trace(iport->iport_alias, "Ran out of "
1674 "memory, port=%p", port);
1675 return (NULL);
1676 }
1677
1678 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1679 icmd->icmd_next = NULL;
1680 cmd->cmd_port = port;
1681 atomic_add_32(&iport->iport_total_alloced_ncmds, 1);
1682 }
1683
1684 /*
1685 * The accuracy of iport_max_active_ncmds is not important
1686 */
1687 if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
1688 iport->iport_max_active_ncmds) {
1689 iport->iport_max_active_ncmds =
1690 iport->iport_total_alloced_ncmds -
1691 iport->iport_cached_ncmds;
1692 }
1693
1694 /* Lets get a slot */
1695 cmd_slot = fct_alloc_cmd_slot(iport, cmd);
1696 if (cmd_slot == FCT_SLOT_EOL) {
1697 rw_exit(&irp->irp_lock);
1698 rw_exit(&iport->iport_lock);
1699 stmf_trace(iport->iport_alias, "Ran out of xchg resources");
1700 cmd->cmd_handle = 0;
1701 fct_cmd_free(cmd);
1702 return (NULL);
1703 }
1704 atomic_add_16(&irp->irp_fcp_xchg_count, 1);
1705 cmd->cmd_rp = rp;
1706 icmd->icmd_flags |= ICMD_IN_TRANSITION | ICMD_KNOWN_TO_FCA;
1707 rw_exit(&irp->irp_lock);
1708 rw_exit(&iport->iport_lock);
1709
1710 icmd->icmd_start_time = ddi_get_lbolt();
1711
1712 cmd->cmd_specific = stmf_task_alloc(port->port_lport, irp->irp_session,
1713 lun, cdb_length, task_ext);
1714 if ((task = (scsi_task_t *)cmd->cmd_specific) != NULL) {
1715 task->task_port_private = cmd;
1716 return (cmd);
1717 }
1718
1719 fct_cmd_free(cmd);
1720
1721 return (NULL);
1722 }
1723
1724 void
1809 ASSERT(0);
1810 }
1811
1812 /*
1813 * This function bypasses fct_handle_els()
1814 */
1815 void
1816 fct_post_implicit_logo(fct_cmd_t *cmd)
1817 {
1818 fct_local_port_t *port = cmd->cmd_port;
1819 fct_i_local_port_t *iport =
1820 (fct_i_local_port_t *)port->port_fct_private;
1821 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1822 fct_remote_port_t *rp = cmd->cmd_rp;
1823 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)rp->rp_fct_private;
1824
1825 icmd->icmd_start_time = ddi_get_lbolt();
1826
1827 rw_enter(&irp->irp_lock, RW_WRITER);
1828 atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
1829 atomic_add_16(&irp->irp_nonfcp_xchg_count, 1);
1830 atomic_add_16(&irp->irp_sa_elses_count, 1);
1831 /*
1832 * An implicit LOGO can also be posted to a irp where a PLOGI might
1833 * be in process. That PLOGI will reset this flag and decrement the
1834 * iport_nrps_login counter.
1835 */
1836 if (irp->irp_flags & IRP_PLOGI_DONE) {
1837 atomic_add_32(&iport->iport_nrps_login, -1);
1838 }
1839 atomic_and_32(&irp->irp_flags, ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1840 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
1841 fct_post_to_discovery_queue(iport, irp, icmd);
1842 rw_exit(&irp->irp_lock);
1843 }
1844
1845 /*
1846 * called with iport_lock held, return the slot number
1847 */
1848 uint16_t
1849 fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd)
1850 {
1851 uint16_t cmd_slot;
1852 uint32_t old, new;
1853 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1854
1855 do {
1856 old = iport->iport_next_free_slot;
1857 cmd_slot = old & 0xFFFF;
1858 if (cmd_slot == FCT_SLOT_EOL)
1859 return (cmd_slot);
1860 /*
1861 * We use high order 16 bits as a counter which keeps on
1862 * incrementing to avoid ABA issues with atomic lists.
1863 */
1864 new = ((old + (0x10000)) & 0xFFFF0000);
1865 new |= iport->iport_cmd_slots[cmd_slot].slot_next;
1866 } while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
1867
1868 atomic_add_16(&iport->iport_nslots_free, -1);
1869 iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
1870 cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
1871 (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
1872 << 24);
1873 return (cmd_slot);
1874 }
1875
1876 /*
1877 * If icmd is not NULL, irp_lock must be held
1878 */
1879 void
1880 fct_post_to_discovery_queue(fct_i_local_port_t *iport,
1881 fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
1882 {
1883 fct_i_cmd_t **p;
1884
1885 ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
1886 if (icmd) {
1887 icmd->icmd_next = NULL;
1888 for (p = &irp->irp_els_list; *p != NULL;
2055 }
2056
2057 if ((icmd->icmd_flags & ICMD_ABTS_RECEIVED) &&
2058 (cmd->cmd_link != NULL)) {
2059 do_abts_acc = 1;
2060 }
2061
2062 /* XXX Validate slot before freeing */
2063
2064 slot = &iport->iport_cmd_slots[n];
2065 slot->slot_uniq_cntr++;
2066 slot->slot_cmd = NULL;
2067 do {
2068 old = iport->iport_next_free_slot;
2069 slot->slot_next = old & 0xFFFF;
2070 new = (old + 0x10000) & 0xFFFF0000;
2071 new |= slot->slot_no;
2072 } while (atomic_cas_32(&iport->iport_next_free_slot,
2073 old, new) != old);
2074 cmd->cmd_handle = 0;
2075 atomic_add_16(&iport->iport_nslots_free, 1);
2076 if (cmd->cmd_rp) {
2077 irp = (fct_i_remote_port_t *)
2078 cmd->cmd_rp->rp_fct_private;
2079 if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2080 atomic_add_16(&irp->irp_fcp_xchg_count, -1);
2081 else
2082 atomic_add_16(&irp->irp_nonfcp_xchg_count, -1);
2083 }
2084 rw_exit(&iport->iport_lock);
2085 } else if ((icmd->icmd_flags & ICMD_IMPLICIT) &&
2086 (icmd->icmd_flags & ICMD_IMPLICIT_CMD_HAS_RESOURCE)) {
2087 /* for implicit cmd, no cmd slot is used */
2088 if (cmd->cmd_rp) {
2089 irp = (fct_i_remote_port_t *)
2090 cmd->cmd_rp->rp_fct_private;
2091 if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2092 atomic_add_16(&irp->irp_fcp_xchg_count, -1);
2093 else
2094 atomic_add_16(&irp->irp_nonfcp_xchg_count, -1);
2095 }
2096 }
2097
2098 if (do_abts_acc) {
2099 fct_cmd_t *lcmd = cmd->cmd_link;
2100 fct_fill_abts_acc(lcmd);
2101 if (port->port_send_cmd_response(lcmd,
2102 FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2103 /*
2104 * XXX Throw HBA fatal error event
2105 * Later shutdown svc will terminate the ABTS in the end
2106 */
2107 (void) snprintf(info, sizeof (info),
2108 "fct_cmd_free: iport-%p, ABTS_ACC"
2109 " port_send_cmd_response failed", (void *)iport);
2110 (void) fct_port_shutdown(iport->iport_port,
2111 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2112 return;
2113 } else {
2114 fct_cmd_free(lcmd);
2115 cmd->cmd_link = NULL;
2116 }
2117 }
2118
2119 /* Free the cmd */
2120 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2121 if (iport->iport_cached_ncmds < max_cached_ncmds) {
2122 icmd->icmd_flags = 0;
2123 mutex_enter(&iport->iport_cached_cmd_lock);
2124 icmd->icmd_next = iport->iport_cached_cmdlist;
2125 iport->iport_cached_cmdlist = icmd;
2126 iport->iport_cached_ncmds++;
2127 mutex_exit(&iport->iport_cached_cmd_lock);
2128 } else {
2129 atomic_add_32(&iport->iport_total_alloced_ncmds, -1);
2130 fct_free(cmd);
2131 }
2132 } else {
2133 fct_free(cmd);
2134 }
2135 }
2136
2137 /* ARGSUSED */
2138 stmf_status_t
2139 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
2140 uint32_t flags)
2141 {
2142 stmf_status_t ret = STMF_SUCCESS;
2143 scsi_task_t *task;
2144 fct_cmd_t *cmd;
2145 fct_i_cmd_t *icmd;
2146 fct_local_port_t *port;
2147 uint32_t old, new;
2148
2149 ASSERT(abort_cmd == STMF_LPORT_ABORT_TASK);
|
1145 "fct: %s driver version mismatch",
1146 port->port_default_alias);
1147 return (FCT_FAILURE);
1148 }
1149 if (port->port_default_alias) {
1150 int l = strlen(port->port_default_alias);
1151
1152 if (l < 16) {
1153 iport->iport_alias = iport->iport_alias_mem;
1154 } else {
1155 iport->iport_alias =
1156 (char *)kmem_zalloc(l+1, KM_SLEEP);
1157 }
1158 (void) strcpy(iport->iport_alias, port->port_default_alias);
1159 } else {
1160 iport->iport_alias = NULL;
1161 }
1162 stmf_wwn_to_devid_desc((scsi_devid_desc_t *)iport->iport_id,
1163 port->port_pwwn, PROTOCOL_FIBRE_CHANNEL);
1164 (void) snprintf(taskq_name, sizeof (taskq_name), "stmf_fct_taskq_%d",
1165 atomic_inc_32_nv(&taskq_cntr));
1166 if ((iport->iport_worker_taskq = ddi_taskq_create(NULL,
1167 taskq_name, 1, TASKQ_DEFAULTPRI, 0)) == NULL) {
1168 return (FCT_FAILURE);
1169 }
1170 mutex_init(&iport->iport_worker_lock, NULL, MUTEX_DRIVER, NULL);
1171 cv_init(&iport->iport_worker_cv, NULL, CV_DRIVER, NULL);
1172 rw_init(&iport->iport_lock, NULL, RW_DRIVER, NULL);
1173 sema_init(&iport->iport_rls_sema, 0, NULL, SEMA_DRIVER, NULL);
1174
1175 /* Remote port mgmt */
1176 iport->iport_rp_slots = (fct_i_remote_port_t **)kmem_zalloc(
1177 port->port_max_logins * sizeof (fct_i_remote_port_t *), KM_SLEEP);
1178 iport->iport_rp_tb = kmem_zalloc(rportid_table_size *
1179 sizeof (fct_i_remote_port_t *), KM_SLEEP);
1180
1181 /* fct_cmds for SCSI traffic */
1182 iport->iport_total_alloced_ncmds = 0;
1183 iport->iport_cached_ncmds = 0;
1184 port->port_fca_fcp_cmd_size =
1185 (port->port_fca_fcp_cmd_size + 7) & ~7;
1423 iport->iport_rp_tb[hash_key] = irp;
1424 iport->iport_nrps++;
1425 }
1426
1427 /*
1428 * Called with irp_lock and iport_lock held as writer.
1429 */
1430 void
1431 fct_deque_rp(fct_i_local_port_t *iport, fct_i_remote_port_t *irp)
1432 {
1433 fct_i_remote_port_t *irp_next = NULL;
1434 fct_i_remote_port_t *irp_last = NULL;
1435 int hash_key =
1436 FCT_PORTID_HASH_FUNC(irp->irp_portid);
1437
1438 irp_next = iport->iport_rp_tb[hash_key];
1439 irp_last = NULL;
1440 while (irp_next != NULL) {
1441 if (irp == irp_next) {
1442 if (irp->irp_flags & IRP_PLOGI_DONE) {
1443 atomic_dec_32(&iport->iport_nrps_login);
1444 }
1445 atomic_and_32(&irp->irp_flags,
1446 ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1447 break;
1448 }
1449 irp_last = irp_next;
1450 irp_next = irp_next->irp_next;
1451 }
1452
1453 if (irp_next) {
1454 if (irp_last == NULL) {
1455 iport->iport_rp_tb[hash_key] =
1456 irp->irp_next;
1457 } else {
1458 irp_last->irp_next = irp->irp_next;
1459 }
1460 irp->irp_next = NULL;
1461 iport->iport_nrps--;
1462 }
1463 }
1661 iport->iport_cached_ncmds--;
1662 cmd = icmd->icmd_cmd;
1663 } else {
1664 icmd = NULL;
1665 }
1666 mutex_exit(&iport->iport_cached_cmd_lock);
1667 if (icmd == NULL) {
1668 cmd = (fct_cmd_t *)fct_alloc(FCT_STRUCT_CMD_FCP_XCHG,
1669 port->port_fca_fcp_cmd_size, 0);
1670 if (cmd == NULL) {
1671 rw_exit(&irp->irp_lock);
1672 rw_exit(&iport->iport_lock);
1673 stmf_trace(iport->iport_alias, "Ran out of "
1674 "memory, port=%p", port);
1675 return (NULL);
1676 }
1677
1678 icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1679 icmd->icmd_next = NULL;
1680 cmd->cmd_port = port;
1681 atomic_inc_32(&iport->iport_total_alloced_ncmds);
1682 }
1683
1684 /*
1685 * The accuracy of iport_max_active_ncmds is not important
1686 */
1687 if ((iport->iport_total_alloced_ncmds - iport->iport_cached_ncmds) >
1688 iport->iport_max_active_ncmds) {
1689 iport->iport_max_active_ncmds =
1690 iport->iport_total_alloced_ncmds -
1691 iport->iport_cached_ncmds;
1692 }
1693
1694 /* Lets get a slot */
1695 cmd_slot = fct_alloc_cmd_slot(iport, cmd);
1696 if (cmd_slot == FCT_SLOT_EOL) {
1697 rw_exit(&irp->irp_lock);
1698 rw_exit(&iport->iport_lock);
1699 stmf_trace(iport->iport_alias, "Ran out of xchg resources");
1700 cmd->cmd_handle = 0;
1701 fct_cmd_free(cmd);
1702 return (NULL);
1703 }
1704 atomic_inc_16(&irp->irp_fcp_xchg_count);
1705 cmd->cmd_rp = rp;
1706 icmd->icmd_flags |= ICMD_IN_TRANSITION | ICMD_KNOWN_TO_FCA;
1707 rw_exit(&irp->irp_lock);
1708 rw_exit(&iport->iport_lock);
1709
1710 icmd->icmd_start_time = ddi_get_lbolt();
1711
1712 cmd->cmd_specific = stmf_task_alloc(port->port_lport, irp->irp_session,
1713 lun, cdb_length, task_ext);
1714 if ((task = (scsi_task_t *)cmd->cmd_specific) != NULL) {
1715 task->task_port_private = cmd;
1716 return (cmd);
1717 }
1718
1719 fct_cmd_free(cmd);
1720
1721 return (NULL);
1722 }
1723
1724 void
1809 ASSERT(0);
1810 }
1811
1812 /*
1813 * This function bypasses fct_handle_els()
1814 */
1815 void
1816 fct_post_implicit_logo(fct_cmd_t *cmd)
1817 {
1818 fct_local_port_t *port = cmd->cmd_port;
1819 fct_i_local_port_t *iport =
1820 (fct_i_local_port_t *)port->port_fct_private;
1821 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1822 fct_remote_port_t *rp = cmd->cmd_rp;
1823 fct_i_remote_port_t *irp = (fct_i_remote_port_t *)rp->rp_fct_private;
1824
1825 icmd->icmd_start_time = ddi_get_lbolt();
1826
1827 rw_enter(&irp->irp_lock, RW_WRITER);
1828 atomic_or_32(&icmd->icmd_flags, ICMD_IMPLICIT_CMD_HAS_RESOURCE);
1829 atomic_inc_16(&irp->irp_nonfcp_xchg_count);
1830 atomic_inc_16(&irp->irp_sa_elses_count);
1831 /*
1832 * An implicit LOGO can also be posted to a irp where a PLOGI might
1833 * be in process. That PLOGI will reset this flag and decrement the
1834 * iport_nrps_login counter.
1835 */
1836 if (irp->irp_flags & IRP_PLOGI_DONE) {
1837 atomic_dec_32(&iport->iport_nrps_login);
1838 }
1839 atomic_and_32(&irp->irp_flags, ~(IRP_PLOGI_DONE | IRP_PRLI_DONE));
1840 atomic_or_32(&icmd->icmd_flags, ICMD_SESSION_AFFECTING);
1841 fct_post_to_discovery_queue(iport, irp, icmd);
1842 rw_exit(&irp->irp_lock);
1843 }
1844
1845 /*
1846 * called with iport_lock held, return the slot number
1847 */
1848 uint16_t
1849 fct_alloc_cmd_slot(fct_i_local_port_t *iport, fct_cmd_t *cmd)
1850 {
1851 uint16_t cmd_slot;
1852 uint32_t old, new;
1853 fct_i_cmd_t *icmd = (fct_i_cmd_t *)cmd->cmd_fct_private;
1854
1855 do {
1856 old = iport->iport_next_free_slot;
1857 cmd_slot = old & 0xFFFF;
1858 if (cmd_slot == FCT_SLOT_EOL)
1859 return (cmd_slot);
1860 /*
1861 * We use high order 16 bits as a counter which keeps on
1862 * incrementing to avoid ABA issues with atomic lists.
1863 */
1864 new = ((old + (0x10000)) & 0xFFFF0000);
1865 new |= iport->iport_cmd_slots[cmd_slot].slot_next;
1866 } while (atomic_cas_32(&iport->iport_next_free_slot, old, new) != old);
1867
1868 atomic_dec_16(&iport->iport_nslots_free);
1869 iport->iport_cmd_slots[cmd_slot].slot_cmd = icmd;
1870 cmd->cmd_handle = (uint32_t)cmd_slot | 0x80000000 |
1871 (((uint32_t)(iport->iport_cmd_slots[cmd_slot].slot_uniq_cntr))
1872 << 24);
1873 return (cmd_slot);
1874 }
1875
1876 /*
1877 * If icmd is not NULL, irp_lock must be held
1878 */
1879 void
1880 fct_post_to_discovery_queue(fct_i_local_port_t *iport,
1881 fct_i_remote_port_t *irp, fct_i_cmd_t *icmd)
1882 {
1883 fct_i_cmd_t **p;
1884
1885 ASSERT(!MUTEX_HELD(&iport->iport_worker_lock));
1886 if (icmd) {
1887 icmd->icmd_next = NULL;
1888 for (p = &irp->irp_els_list; *p != NULL;
2055 }
2056
2057 if ((icmd->icmd_flags & ICMD_ABTS_RECEIVED) &&
2058 (cmd->cmd_link != NULL)) {
2059 do_abts_acc = 1;
2060 }
2061
2062 /* XXX Validate slot before freeing */
2063
2064 slot = &iport->iport_cmd_slots[n];
2065 slot->slot_uniq_cntr++;
2066 slot->slot_cmd = NULL;
2067 do {
2068 old = iport->iport_next_free_slot;
2069 slot->slot_next = old & 0xFFFF;
2070 new = (old + 0x10000) & 0xFFFF0000;
2071 new |= slot->slot_no;
2072 } while (atomic_cas_32(&iport->iport_next_free_slot,
2073 old, new) != old);
2074 cmd->cmd_handle = 0;
2075 atomic_inc_16(&iport->iport_nslots_free);
2076 if (cmd->cmd_rp) {
2077 irp = (fct_i_remote_port_t *)
2078 cmd->cmd_rp->rp_fct_private;
2079 if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2080 atomic_dec_16(&irp->irp_fcp_xchg_count);
2081 else
2082 atomic_dec_16(&irp->irp_nonfcp_xchg_count);
2083 }
2084 rw_exit(&iport->iport_lock);
2085 } else if ((icmd->icmd_flags & ICMD_IMPLICIT) &&
2086 (icmd->icmd_flags & ICMD_IMPLICIT_CMD_HAS_RESOURCE)) {
2087 /* for implicit cmd, no cmd slot is used */
2088 if (cmd->cmd_rp) {
2089 irp = (fct_i_remote_port_t *)
2090 cmd->cmd_rp->rp_fct_private;
2091 if (cmd->cmd_type == FCT_CMD_FCP_XCHG)
2092 atomic_dec_16(&irp->irp_fcp_xchg_count);
2093 else
2094 atomic_dec_16(&irp->irp_nonfcp_xchg_count);
2095 }
2096 }
2097
2098 if (do_abts_acc) {
2099 fct_cmd_t *lcmd = cmd->cmd_link;
2100 fct_fill_abts_acc(lcmd);
2101 if (port->port_send_cmd_response(lcmd,
2102 FCT_IOF_FORCE_FCA_DONE) != FCT_SUCCESS) {
2103 /*
2104 * XXX Throw HBA fatal error event
2105 * Later shutdown svc will terminate the ABTS in the end
2106 */
2107 (void) snprintf(info, sizeof (info),
2108 "fct_cmd_free: iport-%p, ABTS_ACC"
2109 " port_send_cmd_response failed", (void *)iport);
2110 (void) fct_port_shutdown(iport->iport_port,
2111 STMF_RFLAG_FATAL_ERROR | STMF_RFLAG_RESET, info);
2112 return;
2113 } else {
2114 fct_cmd_free(lcmd);
2115 cmd->cmd_link = NULL;
2116 }
2117 }
2118
2119 /* Free the cmd */
2120 if (cmd->cmd_type == FCT_CMD_FCP_XCHG) {
2121 if (iport->iport_cached_ncmds < max_cached_ncmds) {
2122 icmd->icmd_flags = 0;
2123 mutex_enter(&iport->iport_cached_cmd_lock);
2124 icmd->icmd_next = iport->iport_cached_cmdlist;
2125 iport->iport_cached_cmdlist = icmd;
2126 iport->iport_cached_ncmds++;
2127 mutex_exit(&iport->iport_cached_cmd_lock);
2128 } else {
2129 atomic_dec_32(&iport->iport_total_alloced_ncmds);
2130 fct_free(cmd);
2131 }
2132 } else {
2133 fct_free(cmd);
2134 }
2135 }
2136
2137 /* ARGSUSED */
2138 stmf_status_t
2139 fct_scsi_abort(stmf_local_port_t *lport, int abort_cmd, void *arg,
2140 uint32_t flags)
2141 {
2142 stmf_status_t ret = STMF_SUCCESS;
2143 scsi_task_t *task;
2144 fct_cmd_t *cmd;
2145 fct_i_cmd_t *icmd;
2146 fct_local_port_t *port;
2147 uint32_t old, new;
2148
2149 ASSERT(abort_cmd == STMF_LPORT_ABORT_TASK);
|