aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Motin <mav@FreeBSD.org>2015-10-26 18:14:15 +0000
committerAlexander Motin <mav@FreeBSD.org>2015-10-26 18:14:15 +0000
commit86a1e16def70706fdf31b0d743e95a6ab18bafe2 (patch)
tree6c2456da275ae26e1adf39181444c1e40d7fdb34
parentcd684494e5b91d2e7fbaa3889538808038654efd (diff)
downloadsrc-86a1e16def70706fdf31b0d743e95a6ab18bafe2.tar.gz
src-86a1e16def70706fdf31b0d743e95a6ab18bafe2.zip
Reimplement enable and implement disable of virtual ports.
Now on 24xx and above chips it is really possible to simulate several virtual FC ports with single physical one. For example, it allows to configure several targets in ctl.conf, assign each of them to separate virtual port, and let user to control access to them with switch zoning. I still doubt that all problems are solved there, but at now it passes at least basic tests.
Notes
Notes: svn path=/head/; revision=290018
-rw-r--r--sys/dev/isp/isp.c13
-rw-r--r--sys/dev/isp/isp_library.c210
-rw-r--r--sys/dev/isp/ispmbox.h16
3 files changed, 167 insertions, 72 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index d78a9c36e38a..72717b89a679 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -1275,7 +1275,12 @@ isp_reset(ispsoftc_t *isp, int do_load_defaults)
*/
if (IS_FC(isp) && isp->isp_nchan > 1) {
if (!ISP_CAP_MULTI_ID(isp)) {
- isp_prt(isp, ISP_LOGWARN, "non-MULTIID f/w loaded, only can enable 1 of %d channels", isp->isp_nchan);
+ isp_prt(isp, ISP_LOGWARN, "non-MULTIID f/w loaded, "
+ "only can enable 1 of %d channels", isp->isp_nchan);
+ isp->isp_nchan = 1;
+ } else if (!ISP_CAP_VP0(isp)) {
+ isp_prt(isp, ISP_LOGWARN, "We can not use MULTIID "
+ "feature properly without VP0_Decoupling");
isp->isp_nchan = 1;
}
}
@@ -2017,7 +2022,7 @@ isp_fibre_init_2400(ispsoftc_t *isp)
icbp->icb_fwoptions1 = fcp->isp_fwoptions;
icbp->icb_fwoptions2 = fcp->isp_xfwoptions;
icbp->icb_fwoptions3 = fcp->isp_zfwoptions;
- if (isp->isp_nchan > 1 && (isp->isp_fwattr & ISP2400_FW_ATTR_VP0)) {
+ if (isp->isp_nchan > 1 && ISP_CAP_VP0(isp)) {
icbp->icb_fwoptions1 &= ~ICB2400_OPT1_INI_DISABLE;
icbp->icb_fwoptions1 |= ICB2400_OPT1_TGT_ENABLE;
} else {
@@ -2200,7 +2205,7 @@ isp_fibre_init_2400(ispsoftc_t *isp)
uint8_t *off;
vpinfo.vp_global_options = 0;
- if (isp->isp_fwattr & ISP2400_FW_ATTR_VP0) {
+ if (ISP_CAP_VP0(isp)) {
vpinfo.vp_global_options |= ICB2400_VPGOPT_VP0_DECOUPLE;
vpinfo.vp_count = isp->isp_nchan;
chan = 0;
@@ -2235,7 +2240,7 @@ isp_fibre_init_2400(ispsoftc_t *isp)
MAKE_NODE_NAME_FROM_WWN(pi.vp_port_portname, fcp2->isp_wwpn);
MAKE_NODE_NAME_FROM_WWN(pi.vp_port_nodename, fcp2->isp_wwnn);
off = fcp->isp_scratch;
- if (isp->isp_fwattr & ISP2400_FW_ATTR_VP0)
+ if (ISP_CAP_VP0(isp))
off += ICB2400_VPINFO_PORT_OFF(chan);
else
off += ICB2400_VPINFO_PORT_OFF(chan - 1);
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index 35d2c976b6d5..ee0206f28fa7 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -581,6 +581,136 @@ isp_fc_toponame(fcparam *fcp)
}
}
+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;
+
+ /*
+ * 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;
+ 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;
+ if (isp->isp_confopts & ISP_CFG_OWNLOOPID)
+ vp->vp_mod_ports[0].options |=
+ ICB2400_VPOPT_HARD_ADDRESS;
+ else
+ 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);
+
+ /*
+ * 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);
+ 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);
+
+ 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);
+ return (EIO);
+ }
+ return (0);
+}
+
+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;
+
+ /*
+ * 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;
+ if (ISP_CAP_VP0(isp)) {
+ vp->vp_ctrl_status = 1;
+ } else {
+ 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);
+
+ /*
+ * 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);
+ 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);
+
+ if (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);
+ return (EIO);
+ }
+ return (0);
+}
+
/*
* Change Roles
*/
@@ -588,74 +718,28 @@ int
isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
{
fcparam *fcp = FCPARAM(isp, chan);
+ int i, was, res = 0;
if (chan >= isp->isp_nchan) {
isp_prt(isp, ISP_LOGWARN, "%s: bad channel %d", __func__, chan);
return (ENXIO);
}
- if (chan == 0) {
+ if (fcp->role == new_role)
+ return (0);
+ for (was = 0, i = 0; i < isp->isp_nchan; i++) {
+ if (FCPARAM(isp, i)->role != ISP_ROLE_NONE)
+ was++;
+ }
+ if (was == 0 || (was == 1 && fcp->role != ISP_ROLE_NONE)) {
fcp->role = new_role;
return (isp_reinit(isp, 0));
- } else if (ISP_CAP_MULTI_ID(isp)) {
- 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;
-
- /*
- * 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;
- if (new_role & ISP_ROLE_INITIATOR) {
- vp->vp_mod_ports[0].options |= ICB2400_VPOPT_INI_ENABLE;
- }
- if ((new_role & ISP_ROLE_TARGET) == 0) {
- vp->vp_mod_ports[0].options |= ICB2400_VPOPT_TGT_DISABLE;
- }
- 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);
-
- /*
- * 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);
- 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);
-
- 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);
- return (EIO);
- }
- fcp->role = new_role;
- return (0);
- } else {
- return (EINVAL);
}
+ if (fcp->role != ISP_ROLE_NONE)
+ res = isp_fc_disable_vp(isp, chan);
+ fcp->role = new_role;
+ if (fcp->role != ISP_ROLE_NONE)
+ res = isp_fc_enable_vp(isp, chan);
+ return (res);
}
void
@@ -1400,8 +1484,9 @@ isp_put_vp_ctrl_info(ispsoftc_t *isp, vp_ctrl_info_t *src, vp_ctrl_info_t *dst)
ISP_IOXPUT_16(isp, src->vp_ctrl_idmap[i], &dst->vp_ctrl_idmap[i]);
}
for (i = 0; i < ASIZE(src->vp_ctrl_reserved); i++) {
- ISP_IOXPUT_8(isp, src->vp_ctrl_reserved[i], &dst->vp_ctrl_reserved[i]);
+ ISP_IOXPUT_16(isp, src->vp_ctrl_reserved[i], &dst->vp_ctrl_reserved[i]);
}
+ ISP_IOXPUT_16(isp, src->vp_ctrl_fcf_index, &dst->vp_ctrl_fcf_index);
}
void
@@ -1418,8 +1503,9 @@ isp_get_vp_ctrl_info(ispsoftc_t *isp, vp_ctrl_info_t *src, vp_ctrl_info_t *dst)
ISP_IOXGET_16(isp, &src->vp_ctrl_idmap[i], dst->vp_ctrl_idmap[i]);
}
for (i = 0; i < ASIZE(src->vp_ctrl_reserved); i++) {
- ISP_IOXGET_8(isp, &src->vp_ctrl_reserved[i], dst->vp_ctrl_reserved[i]);
+ ISP_IOXGET_16(isp, &src->vp_ctrl_reserved[i], dst->vp_ctrl_reserved[i]);
}
+ ISP_IOXGET_16(isp, &src->vp_ctrl_fcf_index, dst->vp_ctrl_fcf_index);
}
void
diff --git a/sys/dev/isp/ispmbox.h b/sys/dev/isp/ispmbox.h
index c1823de68cd5..d72c600f3c0e 100644
--- a/sys/dev/isp/ispmbox.h
+++ b/sys/dev/isp/ispmbox.h
@@ -855,6 +855,8 @@ typedef struct {
(IS_24XX(isp)? (isp->isp_fwattr & ISP2400_FW_ATTR_MULTIID) : 0)
#define ISP_GET_VPIDX(isp, tag) \
(ISP_CAP_MULTI_ID(isp) ? tag : 0)
+#define ISP_CAP_VP0(isp) \
+ (IS_24XX(isp)? (isp->isp_fwattr & ISP2400_FW_ATTR_VP0) : 0)
/*
* This is true manifestly or is dependent on a f/w attribute
@@ -1177,14 +1179,16 @@ typedef struct {
uint16_t vp_ctrl_status;
uint16_t vp_ctrl_command;
uint16_t vp_ctrl_vp_count;
- uint16_t vp_ctrl_idmap[8];
- uint8_t vp_ctrl_reserved[32];
+ uint16_t vp_ctrl_idmap[16];
+ uint16_t vp_ctrl_reserved[7];
+ uint16_t vp_ctrl_fcf_index;
} vp_ctrl_info_t;
-#define VP_CTRL_CMD_ENABLE_VP 0
-#define VP_CTRL_CMD_DISABLE_VP 8
-#define VP_CTRL_CMD_DISABLE_VP_REINIT_LINK 9
-#define VP_CTRL_CMD_DISABLE_VP_LOGO 0xA
+#define VP_CTRL_CMD_ENABLE_VP 0x00
+#define VP_CTRL_CMD_DISABLE_VP 0x08
+#define VP_CTRL_CMD_DISABLE_VP_REINIT_LINK 0x09
+#define VP_CTRL_CMD_DISABLE_VP_LOGO 0x0A
+#define VP_CTRL_CMD_DISABLE_VP_LOGO_ALL 0x0B
/*
* We can use this structure for modifying either one or two VP ports after initialization