summaryrefslogtreecommitdiffstats
path: root/sys/dev
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2015-12-30 11:50:52 +0000
committermav <mav@FreeBSD.org>2015-12-30 11:50:52 +0000
commit27a8f09a1b080c3913553e9a747a1e1b1ddde85b (patch)
tree2b8fe844c062d94796c02bf3c91f051d9bc3cec9 /sys/dev
parenta4b1c16e98e75f90d54e9dbd7a1fdb698da68539 (diff)
downloadFreeBSD-src-27a8f09a1b080c3913553e9a747a1e1b1ddde85b.zip
FreeBSD-src-27a8f09a1b080c3913553e9a747a1e1b1ddde85b.tar.gz
MFC r292739: Make virtual ports control asynchronous.
Before this change virtual ports control IOCBs were executed synchronously via Execute IOCB mailbox command. It required exclusive use of scratch space of driver and mailbox registers of the hardware. Because of that shared resources use this code could not really sleep, having to spin for completion, blocking any other operation. This change introduces new asynchronous design, sending the IOCBs directly on request queue and gracefully waiting for their return on response queue. Returned IOCBs are identified with unified handle space from r292725.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/isp/isp.c178
-rw-r--r--sys/dev/isp/isp_library.c16
-rw-r--r--sys/dev/isp/ispvar.h4
3 files changed, 111 insertions, 87 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index 66eff1e..b5385bc 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -2348,64 +2348,64 @@ static int
isp_fc_enable_vp(ispsoftc_t *isp, int chan)
{
fcparam *fcp = FCPARAM(isp, chan);
- mbreg_t mbs;
- vp_modify_t *vp;
- uint8_t qe[QENTRY_LEN], *scp;
-
- ISP_MEMZERO(qe, QENTRY_LEN);
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- return (EBUSY);
- }
- scp = fcp->isp_scratch;
+ vp_modify_t vp;
+ void *reqp;
+ uint8_t resp[QENTRY_LEN];
/* Build a VP MODIFY command in memory */
- vp = (vp_modify_t *) qe;
- vp->vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY;
- vp->vp_mod_hdr.rqs_entry_count = 1;
- vp->vp_mod_cnt = 1;
- vp->vp_mod_idx0 = chan;
- vp->vp_mod_cmd = VP_MODIFY_ENA;
- vp->vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED |
+ ISP_MEMZERO(&vp, sizeof(vp));
+ vp.vp_mod_hdr.rqs_entry_type = RQSTYPE_VP_MODIFY;
+ vp.vp_mod_hdr.rqs_entry_count = 1;
+ vp.vp_mod_cnt = 1;
+ vp.vp_mod_idx0 = chan;
+ vp.vp_mod_cmd = VP_MODIFY_ENA;
+ vp.vp_mod_ports[0].options = ICB2400_VPOPT_ENABLED |
ICB2400_VPOPT_ENA_SNSLOGIN;
- if (fcp->role & ISP_ROLE_INITIATOR) {
- vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE;
- }
- if ((fcp->role & ISP_ROLE_TARGET) == 0) {
- vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE;
- }
+ if (fcp->role & ISP_ROLE_INITIATOR)
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE;
+ if ((fcp->role & ISP_ROLE_TARGET) == 0)
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE;
if (fcp->isp_loopid < LOCAL_LOOP_LIM) {
- vp->vp_mod_ports[0].loopid = fcp->isp_loopid;
+ vp.vp_mod_ports[0].loopid = fcp->isp_loopid;
if (isp->isp_confopts & ISP_CFG_OWNLOOPID)
- vp->vp_mod_ports[0].options |=
- ICB2400_VPOPT_HARD_ADDRESS;
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_HARD_ADDRESS;
else
- vp->vp_mod_ports[0].options |=
- ICB2400_VPOPT_PREV_ADDRESS;
+ vp.vp_mod_ports[0].options |= ICB2400_VPOPT_PREV_ADDRESS;
}
- MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwpn, fcp->isp_wwpn);
- MAKE_NODE_NAME_FROM_WWN(vp->vp_mod_ports[0].wwnn, fcp->isp_wwnn);
- isp_put_vp_modify(isp, vp, (vp_modify_t *) scp);
+ MAKE_NODE_NAME_FROM_WWN(vp.vp_mod_ports[0].wwpn, fcp->isp_wwpn);
+ MAKE_NODE_NAME_FROM_WWN(vp.vp_mod_ports[0].wwnn, fcp->isp_wwnn);
- /* Build a EXEC IOCB A64 command that points to the VP MODIFY command */
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0);
- mbs.param[1] = QENTRY_LEN;
- mbs.param[2] = DMA_WD1(fcp->isp_scdma);
- mbs.param[3] = DMA_WD0(fcp->isp_scdma);
- mbs.param[6] = DMA_WD3(fcp->isp_scdma);
- mbs.param[7] = DMA_WD2(fcp->isp_scdma);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan);
- isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- FC_SCRATCH_RELEASE(isp, chan);
+ /* Prepare space for response in memory */
+ memset(resp, 0xff, sizeof(resp));
+ vp.vp_mod_hdl = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL);
+ if (vp.vp_mod_hdl == 0) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d out of handles", __func__, chan);
return (EIO);
}
- MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
- isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp);
- FC_SCRATCH_RELEASE(isp, chan);
+ /* Send request and wait for response. */
+ reqp = isp_getrqentry(isp);
+ if (reqp == NULL) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d out of rqent", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_mod_hdl);
+ return (EIO);
+ }
+ isp_put_vp_modify(isp, &vp, (vp_modify_t *)reqp);
+ ISP_SYNC_REQUEST(isp);
+ if (msleep(resp, &isp->isp_lock, 0, "VP_MODIFY", 5*hz) == EWOULDBLOCK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d timed out", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_mod_hdl);
+ return (EIO);
+ }
+ isp_get_vp_modify(isp, (vp_modify_t *)resp, &vp);
- if (vp->vp_mod_status != VP_STS_OK) {
- isp_prt(isp, ISP_LOGERR, "%s: VP_MODIFY of Chan %d failed with status %d", __func__, chan, vp->vp_mod_status);
+ if (vp.vp_mod_hdr.rqs_flags != 0 || vp.vp_mod_status != VP_STS_OK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_MODIFY of Chan %d failed with flags %x status %d",
+ __func__, chan, vp.vp_mod_hdr.rqs_flags, vp.vp_mod_status);
return (EIO);
}
return (0);
@@ -2414,54 +2414,56 @@ isp_fc_enable_vp(ispsoftc_t *isp, int chan)
static int
isp_fc_disable_vp(ispsoftc_t *isp, int chan)
{
- fcparam *fcp = FCPARAM(isp, chan);
- mbreg_t mbs;
- vp_ctrl_info_t *vp;
- uint8_t qe[QENTRY_LEN], *scp;
-
- ISP_MEMZERO(qe, QENTRY_LEN);
- if (FC_SCRATCH_ACQUIRE(isp, chan)) {
- return (EBUSY);
- }
- scp = fcp->isp_scratch;
+ vp_ctrl_info_t vp;
+ void *reqp;
+ uint8_t resp[QENTRY_LEN];
/* Build a VP CTRL command in memory */
- vp = (vp_ctrl_info_t *) qe;
- vp->vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL;
- vp->vp_ctrl_hdr.rqs_entry_count = 1;
+ ISP_MEMZERO(&vp, sizeof(vp));
+ vp.vp_ctrl_hdr.rqs_entry_type = RQSTYPE_VP_CTRL;
+ vp.vp_ctrl_hdr.rqs_entry_count = 1;
if (ISP_CAP_VP0(isp)) {
- vp->vp_ctrl_status = 1;
+ vp.vp_ctrl_status = 1;
} else {
- vp->vp_ctrl_status = 0;
+ vp.vp_ctrl_status = 0;
chan--; /* VP0 can not be controlled in this case. */
}
- vp->vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL;
- vp->vp_ctrl_vp_count = 1;
- vp->vp_ctrl_idmap[chan / 16] |= (1 << chan % 16);
- isp_put_vp_ctrl_info(isp, vp, (vp_ctrl_info_t *) scp);
+ vp.vp_ctrl_command = VP_CTRL_CMD_DISABLE_VP_LOGO_ALL;
+ vp.vp_ctrl_vp_count = 1;
+ vp.vp_ctrl_idmap[chan / 16] |= (1 << chan % 16);
- /* Build a EXEC IOCB A64 command that points to the VP CTRL command */
- MBSINIT(&mbs, MBOX_EXEC_COMMAND_IOCB_A64, MBLOGALL, 0);
- mbs.param[1] = QENTRY_LEN;
- mbs.param[2] = DMA_WD1(fcp->isp_scdma);
- mbs.param[3] = DMA_WD0(fcp->isp_scdma);
- mbs.param[6] = DMA_WD3(fcp->isp_scdma);
- mbs.param[7] = DMA_WD2(fcp->isp_scdma);
- MEMORYBARRIER(isp, SYNC_SFORDEV, 0, 2 * QENTRY_LEN, chan);
- isp_control(isp, ISPCTL_RUN_MBOXCMD, &mbs);
- if (mbs.param[0] != MBOX_COMMAND_COMPLETE) {
- FC_SCRATCH_RELEASE(isp, chan);
+ /* Prepare space for response in memory */
+ memset(resp, 0xff, sizeof(resp));
+ vp.vp_ctrl_handle = isp_allocate_handle(isp, resp, ISP_HANDLE_CTRL);
+ if (vp.vp_ctrl_handle == 0) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d out of handles", __func__, chan);
return (EIO);
}
- MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
- isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)&scp[QENTRY_LEN], vp);
- FC_SCRATCH_RELEASE(isp, chan);
+ /* Send request and wait for response. */
+ reqp = isp_getrqentry(isp);
+ if (reqp == NULL) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d out of rqent", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_ctrl_handle);
+ return (EIO);
+ }
+ isp_put_vp_ctrl_info(isp, &vp, (vp_ctrl_info_t *)reqp);
+ ISP_SYNC_REQUEST(isp);
+ if (msleep(resp, &isp->isp_lock, 0, "VP_CTRL", 5*hz) == EWOULDBLOCK) {
+ isp_prt(isp, ISP_LOGERR,
+ "%s: VP_CTRL of Chan %d timed out", __func__, chan);
+ isp_destroy_handle(isp, vp.vp_ctrl_handle);
+ return (EIO);
+ }
+ isp_get_vp_ctrl_info(isp, (vp_ctrl_info_t *)resp, &vp);
- if (vp->vp_ctrl_status != 0) {
+ if (vp.vp_ctrl_hdr.rqs_flags != 0 || vp.vp_ctrl_status != 0) {
isp_prt(isp, ISP_LOGERR,
- "%s: VP_CTRL of Chan %d failed with status %d %d",
- __func__, chan, vp->vp_ctrl_status, vp->vp_ctrl_index_fail);
+ "%s: VP_CTRL of Chan %d failed with flags %x status %d %d",
+ __func__, chan, vp.vp_ctrl_hdr.rqs_flags,
+ vp.vp_ctrl_status, vp.vp_ctrl_index_fail);
return (EIO);
}
return (0);
@@ -6123,6 +6125,8 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt
{
isp_ridacq_t rid;
int chan, c;
+ uint32_t hdl;
+ void *ptr;
switch (type) {
case RQSTYPE_STATUS_CONT:
@@ -6164,6 +6168,16 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt
}
}
return (1);
+ case RQSTYPE_VP_MODIFY:
+ case RQSTYPE_VP_CTRL:
+ ISP_IOXGET_32(isp, (uint32_t *)(hp + 1), hdl);
+ ptr = isp_find_xs(isp, hdl);
+ if (ptr != NULL) {
+ isp_destroy_handle(isp, hdl);
+ memcpy(ptr, hp, QENTRY_LEN);
+ wakeup(ptr);
+ }
+ return (1);
case RQSTYPE_ATIO:
case RQSTYPE_CTIO:
case RQSTYPE_ENABLE_LUN:
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index 76890dc..78c7f6f 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -572,7 +572,8 @@ isp_clear_commands(ispsoftc_t *isp)
for (tmp = 0; isp->isp_xflist && tmp < isp->isp_maxcmds; tmp++) {
hdp = &isp->isp_xflist[tmp];
- if (ISP_H2HT(hdp->handle) == ISP_HANDLE_INITIATOR) {
+ switch (ISP_H2HT(hdp->handle)) {
+ case ISP_HANDLE_INITIATOR: {
XS_T *xs = hdp->cmd;
if (XS_XFRLEN(xs)) {
ISP_DMAFREE(isp, xs, hdp->handle);
@@ -580,12 +581,13 @@ isp_clear_commands(ispsoftc_t *isp)
} else {
XS_SET_RESID(xs, 0);
}
- hdp->handle = 0;
- hdp->cmd = NULL;
+ isp_destroy_handle(isp, hdp->handle);
XS_SETERR(xs, HBA_BUSRESET);
isp_done(xs);
+ break;
+ }
#ifdef ISP_TARGET_MODE
- } else if (ISP_H2HT(hdp->handle) == ISP_HANDLE_TARGET) {
+ case ISP_HANDLE_TARGET: {
uint8_t local[QENTRY_LEN];
ISP_DMAFREE(isp, hdp->cmd, hdp->handle);
ISP_MEMZERO(local, QENTRY_LEN);
@@ -601,7 +603,13 @@ isp_clear_commands(ispsoftc_t *isp)
ctio->ct_header.rqs_entry_type = RQSTYPE_CTIO2;
}
isp_async(isp, ISPASYNC_TARGET_ACTION, local);
+ break;
+ }
#endif
+ case ISP_HANDLE_CTRL:
+ wakeup(hdp->cmd);
+ isp_destroy_handle(isp, hdp->handle);
+ break;
}
}
#ifdef ISP_TARGET_MODE
diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h
index ba285fb..f752254 100644
--- a/sys/dev/isp/ispvar.h
+++ b/sys/dev/isp/ispvar.h
@@ -315,12 +315,14 @@ typedef struct {
# define ISP_HANDLE_NONE 0
# define ISP_HANDLE_INITIATOR 1
# define ISP_HANDLE_TARGET 2
+# define ISP_HANDLE_CTRL 3
#define ISP_HANDLE_SEQ_MASK 0xffff0000
#define ISP_HANDLE_SEQ_SHIFT 16
#define ISP_H2SEQ(hdl) ((hdl & ISP_HANDLE_SEQ_MASK) >> ISP_HANDLE_SEQ_SHIFT)
#define ISP_VALID_HANDLE(c, hdl) \
((ISP_H2HT(hdl) == ISP_HANDLE_INITIATOR || \
- ISP_H2HT(hdl) == ISP_HANDLE_TARGET) && \
+ ISP_H2HT(hdl) == ISP_HANDLE_TARGET || \
+ ISP_H2HT(hdl) == ISP_HANDLE_CTRL) && \
((hdl) & ISP_HANDLE_CMD_MASK) < (c)->isp_maxcmds && \
(hdl) == ((c)->isp_xflist[(hdl) & ISP_HANDLE_CMD_MASK].handle))
#define ISP_BAD_HANDLE_INDEX 0xffffffff
OpenPOWER on IntegriCloud