summaryrefslogtreecommitdiffstats
path: root/sys/dev/isp/isp_library.c
diff options
context:
space:
mode:
authormjacob <mjacob@FreeBSD.org>2010-02-03 21:09:32 +0000
committermjacob <mjacob@FreeBSD.org>2010-02-03 21:09:32 +0000
commitdf42a0ca6b960167d6735a4fb358950b6d690ce6 (patch)
treefdde0434a01b70cd56bc51a41aa3aaccfc6b07f8 /sys/dev/isp/isp_library.c
parentc499a83bba8f8470ae5c8ef7a572fe3892a87d8c (diff)
downloadFreeBSD-src-df42a0ca6b960167d6735a4fb358950b6d690ce6.zip
FreeBSD-src-df42a0ca6b960167d6735a4fb358950b6d690ce6.tar.gz
Redo how commands handles are created and managed and implement sequence
numbers and handle types in rational way. This will better protect from (unwittingly) dealing with stale handles/commands. Fix the watchdog timeout code to better protect itself from mistakes. If we run an abort on a putatively timed out command, the command may in fact get completed, so check to make sure the command we're timing it out is still around. If the abort succeeds, btw, the command should get returned via a different path.
Diffstat (limited to 'sys/dev/isp/isp_library.c')
-rw-r--r--sys/dev/isp/isp_library.c147
1 files changed, 73 insertions, 74 deletions
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index acc2492..877303e 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -246,65 +246,70 @@ copy_and_sync:
}
int
-isp_save_xs(ispsoftc_t *isp, XS_T *xs, uint32_t *handlep)
+isp_allocate_xs(ispsoftc_t *isp, XS_T *xs, uint32_t *handlep)
{
- uint16_t i, j;
+ isp_hdl_t *hdp;
- for (j = isp->isp_lasthdls, i = 0; i < isp->isp_maxcmds; i++) {
- if (isp->isp_xflist[j] == NULL) {
- break;
- }
- if (++j == isp->isp_maxcmds) {
- j = 0;
- }
- }
- if (i == isp->isp_maxcmds) {
+ hdp = isp->isp_xffree;
+ if (hdp == NULL) {
return (-1);
}
- isp->isp_xflist[j] = xs;
- *handlep = j+1;
- if (++j == isp->isp_maxcmds) {
- j = 0;
- }
- isp->isp_lasthdls = (uint32_t)j;
+ isp->isp_xffree = hdp->cmd;
+ hdp->cmd = xs;
+ hdp->handle = (hdp - isp->isp_xflist);
+ hdp->handle |= (ISP_HANDLE_INITIATOR << ISP_HANDLE_USAGE_SHIFT);
+ hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT);
+ *handlep = hdp->handle;
return (0);
}
XS_T *
isp_find_xs(ispsoftc_t *isp, uint32_t handle)
{
- if (handle < 1 || handle > (uint32_t) isp->isp_maxcmds) {
+ if (!ISP_VALID_INI_HANDLE(isp, handle)) {
+ isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
return (NULL);
- } else {
- return (isp->isp_xflist[handle - 1]);
}
+ return (isp->isp_xflist[(handle & ISP_HANDLE_CMD_MASK)].cmd);
}
uint32_t
isp_find_handle(ispsoftc_t *isp, XS_T *xs)
{
- uint16_t i;
+ uint32_t i, foundhdl = ISP_HANDLE_FREE;
+
if (xs != NULL) {
for (i = 0; i < isp->isp_maxcmds; i++) {
- if (isp->isp_xflist[i] == xs) {
- return ((uint32_t) (i+1));
+ if (isp->isp_xflist[i].cmd != xs) {
+ continue;
}
+ foundhdl = isp->isp_xflist[i].handle;
+ break;
}
}
- return (0);
+ return (foundhdl);
}
uint32_t
-isp_handle_index(uint32_t handle)
+isp_handle_index(ispsoftc_t *isp, uint32_t handle)
{
- return (handle - 1);
+ if (!ISP_VALID_HANDLE(isp, handle)) {
+ return (handle & ISP_HANDLE_CMD_MASK);
+ } else {
+ isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
+ return (ISP_BAD_HANDLE_INDEX);
+ }
}
void
isp_destroy_handle(ispsoftc_t *isp, uint32_t handle)
{
- if (handle > 0 && handle <= (uint32_t) isp->isp_maxcmds) {
- isp->isp_xflist[handle - 1] = NULL;
+ if (!ISP_VALID_INI_HANDLE(isp, handle)) {
+ isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
+ } else {
+ isp->isp_xflist[(handle & ISP_HANDLE_CMD_MASK)].handle = ISP_HANDLE_FREE;
+ isp->isp_xflist[(handle & ISP_HANDLE_CMD_MASK)].cmd = isp->isp_xffree;
+ isp->isp_xffree = &isp->isp_xflist[(handle & ISP_HANDLE_CMD_MASK)];
}
}
@@ -617,54 +622,48 @@ isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
void
isp_clear_commands(ispsoftc_t *isp)
{
- XS_T *xs;
- uint32_t tmp, handle;
+ uint32_t tmp;
+ isp_hdl_t *hdp;
#ifdef ISP_TARGET_MODE
isp_notify_t notify;
#endif
for (tmp = 0; isp->isp_xflist && tmp < isp->isp_maxcmds; tmp++) {
- xs = isp->isp_xflist[tmp];
- if (xs == NULL) {
- continue;
- }
- handle = isp_find_handle(isp, xs);
- if (handle == 0) {
+ XS_T *xs;
+
+ hdp = &isp->isp_xflist[tmp];
+ if (hdp->handle == ISP_HANDLE_FREE) {
continue;
}
+ xs = hdp->cmd;
if (XS_XFRLEN(xs)) {
- ISP_DMAFREE(isp, xs, handle);
+ ISP_DMAFREE(isp, xs, hdp->handle);
XS_SET_RESID(xs, XS_XFRLEN(xs));
} else {
XS_SET_RESID(xs, 0);
}
- isp_destroy_handle(isp, handle);
+ hdp->handle = 0;
+ hdp->cmd = NULL;
XS_SETERR(xs, HBA_BUSRESET);
isp_done(xs);
}
#ifdef ISP_TARGET_MODE
for (tmp = 0; isp->isp_tgtlist && tmp < isp->isp_maxcmds; tmp++) {
uint8_t local[QENTRY_LEN];
-
- xs = isp->isp_tgtlist[tmp];
- if (xs == NULL) {
- continue;
- }
- handle = isp_find_tgt_handle(isp, xs);
- if (handle == 0) {
+ hdp = &isp->isp_tgt_xflist[tmp];
+ if (hdp->handle == ISP_HANDLE_FREE) {
continue;
}
- ISP_DMAFREE(isp, xs, handle);
-
+ ISP_DMAFREE(isp, hdp->cmd, hdp->handle);
ISP_MEMZERO(local, QENTRY_LEN);
if (IS_24XX(isp)) {
ct7_entry_t *ctio = (ct7_entry_t *) local;
- ctio->ct_syshandle = handle;
+ ctio->ct_syshandle = hdp->handle;
ctio->ct_nphdl = CT_HBA_RESET;
ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO7;
} else if (IS_FC(isp)) {
ct2_entry_t *ctio = (ct2_entry_t *) local;
- ctio->ct_syshandle = handle;
+ ctio->ct_syshandle = hdp->handle;
ctio->ct_status = CT_HBA_RESET;
ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
} else {
@@ -2229,59 +2228,59 @@ isp_send_tgt_cmd(ispsoftc_t *isp, void *fqe, void *segp, uint32_t nsegs, uint32_
}
int
-isp_save_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep)
+isp_allocate_xs_tgt(ispsoftc_t *isp, void *xs, uint32_t *handlep)
{
- int i;
+ isp_hdl_t *hdp;
- for (i = 0; i < (int) isp->isp_maxcmds; i++) {
- if (isp->isp_tgtlist[i] == NULL) {
- break;
- }
- }
- if (i == isp->isp_maxcmds) {
+ hdp = isp->isp_tgtfree;
+ if (hdp == NULL) {
return (-1);
}
- isp->isp_tgtlist[i] = xs;
- *handlep = (i+1) | 0x8000;
+ isp->isp_tgtfree = hdp->cmd;
+ hdp->cmd = xs;
+ hdp->handle = (hdp - isp->isp_tgtlist);
+ hdp->handle |= (ISP_HANDLE_TARGET << ISP_HANDLE_USAGE_SHIFT);
+ hdp->handle |= (isp->isp_seqno++ << ISP_HANDLE_SEQ_SHIFT);
+ *handlep = hdp->handle;
return (0);
}
void *
isp_find_xs_tgt(ispsoftc_t *isp, uint32_t handle)
{
- if (handle == 0 || IS_TARGET_HANDLE(handle) == 0 || (handle & ISP_HANDLE_MASK) > isp->isp_maxcmds) {
- isp_prt(isp, ISP_LOGERR, "bad handle %u in isp_find_xs_tgt", handle);
+ if (!ISP_VALID_TGT_HANDLE(isp, handle)) {
+ isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
return (NULL);
- } else {
- return (isp->isp_tgtlist[(handle & ISP_HANDLE_MASK) - 1]);
}
+ return (isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].cmd);
}
uint32_t
isp_find_tgt_handle(ispsoftc_t *isp, void *xs)
{
- int i;
+ uint32_t i, foundhdl = ISP_HANDLE_FREE;
+
if (xs != NULL) {
for (i = 0; i < isp->isp_maxcmds; i++) {
- if (isp->isp_tgtlist[i] == xs) {
- uint32_t handle = i;
- handle += 1;
- handle &= ISP_HANDLE_MASK;
- handle |= 0x8000;
- return (handle);
+ if (isp->isp_tgtlist[i].cmd != xs) {
+ continue;
}
+ foundhdl = isp->isp_tgtlist[i].handle;
+ break;
}
}
- return (0);
+ return (foundhdl);
}
void
isp_destroy_tgt_handle(ispsoftc_t *isp, uint32_t handle)
{
- if (handle == 0 || IS_TARGET_HANDLE(handle) == 0 || (handle & ISP_HANDLE_MASK) > isp->isp_maxcmds) {
- isp_prt(isp, ISP_LOGERR, "bad handle in isp_destroy_tgt_handle");
+ if (!ISP_VALID_TGT_HANDLE(handle)) {
+ isp_prt(isp, ISP_LOGERR, "%s: bad handle 0x%x", __func__, handle);
} else {
- isp->isp_tgtlist[(handle & ISP_HANDLE_MASK) - 1] = NULL;
+ isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].handle = ISP_HANDLE_FREE;
+ isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)].cmd = isp->isp_tgtfree;
+ isp->isp_tgtfree = &isp->isp_tgtlist[(handle & ISP_HANDLE_CMD_MASK)];
}
}
OpenPOWER on IntegriCloud