summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/dev/isp/isp.c54
-rw-r--r--sys/dev/isp/isp_freebsd.c30
-rw-r--r--sys/dev/isp/isp_library.c11
-rw-r--r--sys/dev/isp/ispvar.h5
4 files changed, 75 insertions, 25 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index a347143..dd203a4 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -2223,6 +2223,36 @@ isp_fibre_init_2400(ispsoftc_t *isp)
}
static void
+isp_del_all_init_entries(ispsoftc_t *isp, int chan)
+{
+ fcparam *fcp = FCPARAM(isp, chan);
+ fcportdb_t *lp;
+ int i;
+
+ for (i = 0; i < MAX_FC_TARG; i++) {
+ lp = &fcp->portdb[i];
+ if (lp->state == FC_PORTDB_STATE_NIL || lp->target_mode)
+ continue;
+ /*
+ * It's up to the outer layers to clear isp_dev_map.
+ */
+ lp->state = FC_PORTDB_STATE_NIL;
+ isp_async(isp, ISPASYNC_DEV_GONE, chan, lp, 1);
+ if (lp->autologin == 0) {
+ (void) isp_plogx(isp, chan, lp->handle,
+ lp->portid,
+ PLOGX_FLG_CMD_LOGO |
+ PLOGX_FLG_IMPLICIT |
+ PLOGX_FLG_FREE_NPHDL, 0);
+ } else {
+ lp->autologin = 0;
+ }
+ lp->new_prli_word3 = 0;
+ lp->new_portid = 0;
+ }
+}
+
+static void
isp_mark_portdb(ispsoftc_t *isp, int chan, int disposition)
{
fcparam *fcp = FCPARAM(isp, chan);
@@ -2981,7 +3011,7 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
* It's up to the outer layers to clear isp_dev_map.
*/
lp->state = FC_PORTDB_STATE_NIL;
- isp_async(isp, ISPASYNC_DEV_GONE, chan, lp);
+ isp_async(isp, ISPASYNC_DEV_GONE, chan, lp, 0);
if (lp->autologin == 0) {
(void) isp_plogx(isp, chan, lp->handle,
lp->portid,
@@ -4990,6 +5020,28 @@ isp_control(ispsoftc_t *isp, ispctl_t ctl, ...)
} while ((r & 0xffff) == MBOX_LOOP_ID_USED);
return (r);
}
+ case ISPCTL_CHANGE_ROLE:
+ {
+ int role, r;
+
+ va_start(ap, ctl);
+ chan = va_arg(ap, int);
+ role = va_arg(ap, int);
+ va_end(ap);
+ if (IS_FC(isp)) {
+#ifdef ISP_TARGET_MODE
+ if ((role & ISP_ROLE_TARGET) == 0)
+ isp_del_all_wwn_entries(isp, chan);
+#endif
+ if ((role & ISP_ROLE_INITIATOR) == 0)
+ isp_del_all_init_entries(isp, chan);
+ r = isp_fc_change_role(isp, chan, role);
+ } else {
+ SDPARAM(isp, chan)->role = role;
+ r = 0;
+ }
+ return (r);
+ }
default:
isp_prt(isp, ISP_LOGERR, "Unknown Control Opcode 0x%x", ctl);
break;
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index 5481c99..97dd7ae 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -115,7 +115,7 @@ isp_role_sysctl(SYSCTL_HANDLER_ARGS)
}
/* Actually change the role. */
- error = isp_fc_change_role(isp, chan, value);
+ error = isp_control(isp, ISPCTL_CHANGE_ROLE, chan, value);
ISP_UNLOCK(isp);
return (error);
}
@@ -474,18 +474,14 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
retval = EINVAL;
break;
}
- *(int *)addr = FCPARAM(isp, chan)->role;
-#ifdef ISP_INTERNAL_TARGET
ISP_LOCK(isp);
- retval = isp_fc_change_role(isp, chan, nr);
- ISP_UNLOCK(isp);
-#else
- FCPARAM(isp, chan)->role = nr;
-#endif
+ *(int *)addr = FCPARAM(isp, chan)->role;
} else {
+ ISP_LOCK(isp);
*(int *)addr = SDPARAM(isp, chan)->role;
- SDPARAM(isp, chan)->role = nr;
}
+ retval = isp_control(isp, ISPCTL_CHANGE_ROLE, chan, nr);
+ ISP_UNLOCK(isp);
retval = 0;
break;
@@ -5478,7 +5474,8 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
ISP_SET_PC(isp, bus, tm_enabled, 0);
ISP_SET_PC(isp, bus, tm_luns_enabled, 0);
#endif
- if (isp_fc_change_role(isp, bus, newrole) != 0) {
+ if (isp_control(isp, ISPCTL_CHANGE_ROLE,
+ bus, newrole) != 0) {
ccb->ccb_h.status = CAM_REQ_CMP_ERR;
xpt_done(ccb);
break;
@@ -5668,7 +5665,7 @@ isp_done(XS_T *sccb)
void
isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
{
- int bus;
+ int bus, now;
static const char prom0[] = "Chan %d PortID 0x%06x handle 0x%x %s %s WWPN 0x%08x%08x";
static const char prom2[] = "Chan %d PortID 0x%06x handle 0x%x %s %s tgt %u WWPN 0x%08x%08x";
char buf[64];
@@ -5909,6 +5906,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
va_start(ap, cmd);
bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *);
+ now = va_arg(ap, int);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
/*
@@ -5921,7 +5919,15 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
*
*/
isp_gen_role_str(buf, sizeof (buf), lp->prli_word3);
- if (lp->dev_map_idx && lp->announced == 0) {
+ if (lp->dev_map_idx && lp->announced == 0 && now) {
+ lp->announced = 1;
+ tgt = lp->dev_map_idx - 1;
+ FCPARAM(isp, bus)->isp_dev_map[tgt] = 0;
+ lp->dev_map_idx = 0;
+ isp_make_gone(isp, lp, bus, tgt);
+ isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, buf, "gone at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
+ isp_fcp_reset_crn(fc, tgt, /*tgt_set*/ 1);
+ } else if (lp->dev_map_idx && lp->announced == 0) {
lp->announced = 1;
lp->state = FC_PORTDB_STATE_ZOMBIE;
lp->gone_timer = ISP_FC_PC(isp, bus)->gone_device_time;
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index b56b1dc..2f7dc4e 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -603,9 +603,6 @@ isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
return (ENXIO);
}
if (chan == 0) {
-#ifdef ISP_TARGET_MODE
- isp_del_all_wwn_entries(isp, chan);
-#endif
isp_clear_commands(isp);
isp_reset(isp, 0);
if (isp->isp_state != ISP_RESETSTATE) {
@@ -626,8 +623,6 @@ isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
uint8_t qe[QENTRY_LEN], *scp;
ISP_MEMZERO(qe, QENTRY_LEN);
- /* Acquire Scratch */
-
if (FC_SCRATCH_ACQUIRE(isp, chan)) {
return (EBUSY);
}
@@ -671,12 +666,6 @@ isp_fc_change_role(ispsoftc_t *isp, int chan, int new_role)
MEMORYBARRIER(isp, SYNC_SFORCPU, QENTRY_LEN, QENTRY_LEN, chan);
isp_get_vp_modify(isp, (vp_modify_t *)&scp[QENTRY_LEN], vp);
-#ifdef ISP_TARGET_MODE
- isp_del_all_wwn_entries(isp, chan);
-#endif
- /*
- * Release Scratch
- */
FC_SCRATCH_RELEASE(isp, chan);
if (vp->vp_mod_status != VP_STS_OK) {
diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h
index 4ac91b9..150073e 100644
--- a/sys/dev/isp/ispvar.h
+++ b/sys/dev/isp/ispvar.h
@@ -915,6 +915,8 @@ void isp_done(XS_T *);
* Get PDB on this channel for this N-port handle
* ... ISPCTL_PLOGX, isp_plcmd_t *)
* Performa a port login/logout
+ * ... ISPCTL_CHANGE_ROLE, int channel, int role);
+ * Change role of specified channel
*
* ISPCTL_PDB_SYNC is somewhat misnamed. It actually is the final step, in
* order, of ISPCTL_FCLINK_TEST, ISPCTL_SCAN_FABRIC, and ISPCTL_SCAN_LOOP.
@@ -937,7 +939,8 @@ typedef enum {
ISPCTL_GET_NAMES,
ISPCTL_RUN_MBOXCMD,
ISPCTL_GET_PDB,
- ISPCTL_PLOGX
+ ISPCTL_PLOGX,
+ ISPCTL_CHANGE_ROLE
} ispctl_t;
int isp_control(ispsoftc_t *, ispctl_t, ...);
OpenPOWER on IntegriCloud