summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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 d78a9c3..72717b8 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 35d2c97..ee0206f 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 c1823de..d72c600 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
OpenPOWER on IntegriCloud