summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2015-11-30 21:58:51 +0000
committermav <mav@FreeBSD.org>2015-11-30 21:58:51 +0000
commit97189158140218a2e5bfbd037679e515e9b2c64e (patch)
tree7d2745eb767919ae36eed1656e80ff70595c31c5
parent7e425797577f91547491a85ffd37c7eab99b9bb2 (diff)
downloadFreeBSD-src-97189158140218a2e5bfbd037679e515e9b2c64e.zip
FreeBSD-src-97189158140218a2e5bfbd037679e515e9b2c64e.tar.gz
MFC r291365, r291369: One more round of port scanner rewrite.
- Make scan aborted by event restart immediately and infinitely. - Improve handling of some loop events from firmware. - Remove loop down timer, adding its functionality to scanner thread. - Some more unification and simplification.
-rw-r--r--sys/dev/isp/isp.c103
-rw-r--r--sys/dev/isp/isp_freebsd.c254
-rw-r--r--sys/dev/isp/isp_freebsd.h11
-rw-r--r--sys/dev/isp/isp_library.c49
-rw-r--r--sys/dev/isp/isp_pci.c10
-rw-r--r--sys/dev/isp/ispvar.h20
6 files changed, 181 insertions, 266 deletions
diff --git a/sys/dev/isp/isp.c b/sys/dev/isp/isp.c
index 7b5b399..18c41e9 100644
--- a/sys/dev/isp/isp.c
+++ b/sys/dev/isp/isp.c
@@ -2810,6 +2810,8 @@ isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay)
fcp = FCPARAM(isp, chan);
+ if (fcp->isp_loopstate < LOOP_HAVE_LINK)
+ return (-1);
if (fcp->isp_loopstate >= LOOP_LTEST_DONE)
return (0);
@@ -2825,15 +2827,13 @@ isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay)
if (fcp->isp_fwstate == FW_READY) {
break;
}
+ if (fcp->isp_loopstate < LOOP_TESTING_LINK)
+ goto abort;
GET_NANOTIME(&hrb);
if ((NANOTIME_SUB(&hrb, &hra) / 1000 + 1000 >= usdelay))
break;
ISP_SLEEP(isp, 1000);
}
-
- /*
- * If we haven't gone to 'ready' state, return.
- */
if (fcp->isp_fwstate != FW_READY) {
isp_prt(isp, ISP_LOG_SANCFG,
"Chan %d Firmware is not ready (%s)",
@@ -2938,6 +2938,12 @@ not_on_fabric:
}
}
+ if (fcp->isp_loopstate < LOOP_TESTING_LINK) {
+abort:
+ isp_prt(isp, ISP_LOG_SANCFG,
+ "Chan %d FC link test aborted", chan);
+ return (1);
+ }
fcp->isp_loopstate = LOOP_LTEST_DONE;
isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGCONFIG,
"Chan %d WWPN %016jx WWNN %016jx",
@@ -2968,12 +2974,10 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
fcportdb_t *lp;
uint16_t dbidx;
- if (fcp->isp_loopstate < LOOP_FSCAN_DONE) {
+ if (fcp->isp_loopstate < LOOP_FSCAN_DONE)
return (-1);
- }
- if (fcp->isp_loopstate > LOOP_SYNCING_PDB) {
+ if (fcp->isp_loopstate >= LOOP_READY)
return (0);
- }
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC PDB sync", chan);
@@ -3025,12 +3029,12 @@ isp_pdb_sync(ispsoftc_t *isp, int chan)
}
}
- /*
- * If we get here, we've for sure seen not only a valid loop
- * but know what is or isn't on it, so mark this for usage
- * in isp_start.
- */
- fcp->loop_seen_once = 1;
+ if (fcp->isp_loopstate < LOOP_SYNCING_PDB) {
+ isp_prt(isp, ISP_LOG_SANCFG,
+ "Chan %d FC PDB sync aborted", chan);
+ return (1);
+ }
+
fcp->isp_loopstate = LOOP_READY;
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC PDB sync done", chan);
return (0);
@@ -3154,12 +3158,11 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
uint16_t handles[LOCAL_LOOP_LIM];
uint16_t handle;
- if (fcp->isp_loopstate < LOOP_LTEST_DONE) {
+ if (fcp->isp_loopstate < LOOP_LTEST_DONE)
return (-1);
- }
- if (fcp->isp_loopstate > LOOP_SCANNING_LOOP) {
+ if (fcp->isp_loopstate >= LOOP_LSCAN_DONE)
return (0);
- }
+
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC loop scan", chan);
fcp->isp_loopstate = LOOP_SCANNING_LOOP;
if (TOPO_IS_FABRIC(fcp->isp_topo)) {
@@ -3214,8 +3217,8 @@ isp_scan_loop(ispsoftc_t *isp, int chan)
if (fcp->isp_loopstate < LOOP_SCANNING_LOOP) {
abort:
isp_prt(isp, ISP_LOG_SANCFG,
- "Chan %d FC loop scan done (abort)", chan);
- return (-1);
+ "Chan %d FC loop scan aborted", chan);
+ return (1);
}
if (node_wwn == INI_NONE) {
continue;
@@ -3424,12 +3427,11 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
int portidx, portlim, r;
sns_gid_ft_rsp_t *rs0, *rs1;
- if (fcp->isp_loopstate < LOOP_LSCAN_DONE) {
+ if (fcp->isp_loopstate < LOOP_LSCAN_DONE)
return (-1);
- }
- if (fcp->isp_loopstate > LOOP_SCANNING_FABRIC) {
+ if (fcp->isp_loopstate >= LOOP_FSCAN_DONE)
return (0);
- }
+
isp_prt(isp, ISP_LOG_SANCFG, "Chan %d FC fabric scan", chan);
fcp->isp_loopstate = LOOP_SCANNING_FABRIC;
if (!TOPO_IS_FABRIC(fcp->isp_topo)) {
@@ -3450,8 +3452,8 @@ fail:
abort:
FC_SCRATCH_RELEASE(isp, chan);
isp_prt(isp, ISP_LOG_SANCFG,
- "Chan %d FC fabric scan done (abort)", chan);
- return (-1);
+ "Chan %d FC fabric scan aborted", chan);
+ return (1);
}
/*
@@ -3478,11 +3480,11 @@ abort:
if (r > 0) {
fcp->isp_loopstate = LOOP_FSCAN_DONE;
FC_SCRATCH_RELEASE(isp, chan);
- return (0);
+ return (-1);
} else if (r < 0) {
fcp->isp_loopstate = LOOP_LTEST_DONE; /* try again */
FC_SCRATCH_RELEASE(isp, chan);
- return (0);
+ return (-1);
}
MEMORYBARRIER(isp, SYNC_SFORCPU, IGPOFF, GIDLEN, chan);
@@ -3504,7 +3506,7 @@ abort:
rs1->snscb_cthdr.ct_explanation);
FC_SCRATCH_RELEASE(isp, chan);
fcp->isp_loopstate = LOOP_FSCAN_DONE;
- return (0);
+ return (-1);
}
/* Check our buffer was big enough to get the full list. */
@@ -5657,11 +5659,10 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
fcp = FCPARAM(isp, chan);
int topo = fcp->isp_topo;
- if (fcp->role == ISP_ROLE_NONE) {
+ if (fcp->role == ISP_ROLE_NONE)
continue;
- }
-
- fcp->isp_loopstate = LOOP_NIL;
+ if (fcp->isp_loopstate > LOOP_HAVE_LINK)
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
ISP_SET_SENDMARKER(isp, chan, 1);
isp_async(isp, ISPASYNC_LIP, chan);
#ifdef ISP_TARGET_MODE
@@ -5714,6 +5715,9 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
fcp = FCPARAM(isp, chan);
if (fcp->role == ISP_ROLE_NONE)
continue;
+ fcp->isp_linkstate = 1;
+ if (fcp->isp_loopstate < LOOP_HAVE_LINK)
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
ISP_SET_SENDMARKER(isp, chan, 1);
isp_async(isp, ISPASYNC_LOOP_UP, chan);
#ifdef ISP_TARGET_MODE
@@ -5734,6 +5738,7 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
if (fcp->role == ISP_ROLE_NONE)
continue;
ISP_SET_SENDMARKER(isp, chan, 1);
+ fcp->isp_linkstate = 0;
fcp->isp_loopstate = LOOP_NIL;
isp_async(isp, ISPASYNC_LOOP_DOWN, chan);
#ifdef ISP_TARGET_MODE
@@ -5754,7 +5759,8 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
if (fcp->role == ISP_ROLE_NONE)
continue;
ISP_SET_SENDMARKER(isp, chan, 1);
- fcp->isp_loopstate = LOOP_NIL;
+ if (fcp->isp_loopstate > LOOP_HAVE_LINK)
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
isp_async(isp, ISPASYNC_LOOP_RESET, chan);
#ifdef ISP_TARGET_MODE
if (isp_target_async(isp, chan, mbox)) {
@@ -5797,6 +5803,8 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
continue;
if (fcp->isp_loopstate > LOOP_LTEST_DONE)
fcp->isp_loopstate = LOOP_LTEST_DONE;
+ else if (fcp->isp_loopstate < LOOP_HAVE_LINK)
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan,
ISPASYNC_CHANGE_PDB, nphdl, nlstate, reason);
}
@@ -5820,6 +5828,8 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
break;
if (fcp->isp_loopstate > LOOP_LTEST_DONE)
fcp->isp_loopstate = LOOP_LTEST_DONE;
+ else if (fcp->isp_loopstate < LOOP_HAVE_LINK)
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan,
ISPASYNC_CHANGE_SNS, portid);
break;
@@ -5867,7 +5877,7 @@ isp_parse_async_fc(ispsoftc_t *isp, uint16_t mbox)
break;
}
ISP_SET_SENDMARKER(isp, chan, 1);
- FCPARAM(isp, chan)->isp_loopstate = LOOP_NIL;
+ FCPARAM(isp, chan)->isp_loopstate = LOOP_HAVE_LINK;
isp_async(isp, ISPASYNC_CHANGE_NOTIFY, chan, ISPASYNC_CHANGE_OTHER);
break;
case ASYNC_P2P_INIT_ERR:
@@ -5939,16 +5949,29 @@ isp_handle_other_response(ispsoftc_t *isp, int type, isphdr_t *hp, uint32_t *opt
if (fcp->role == ISP_ROLE_NONE)
continue;
c = (chan == 0) ? 127 : (chan - 1);
- if (rid.ridacq_map[c / 16] & (1 << (c % 16))) {
- fcp->isp_loopstate = LOOP_NIL;
+ if (rid.ridacq_map[c / 16] & (1 << (c % 16)) ||
+ chan == 0) {
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
isp_async(isp, ISPASYNC_CHANGE_NOTIFY,
chan, ISPASYNC_CHANGE_OTHER);
+ } else {
+ fcp->isp_loopstate = LOOP_NIL;
+ isp_async(isp, ISPASYNC_LOOP_DOWN,
+ chan);
}
}
} else {
- FCPARAM(isp, rid.ridacq_vp_index)->isp_loopstate = LOOP_NIL;
- isp_async(isp, ISPASYNC_CHANGE_NOTIFY,
- rid.ridacq_vp_index, ISPASYNC_CHANGE_OTHER);
+ fcparam *fcp = FCPARAM(isp, rid.ridacq_vp_index);
+ if (rid.ridacq_vp_status == RIDACQ_STS_COMPLETE ||
+ rid.ridacq_vp_status == RIDACQ_STS_CHANGED) {
+ fcp->isp_loopstate = LOOP_HAVE_LINK;
+ isp_async(isp, ISPASYNC_CHANGE_NOTIFY,
+ rid.ridacq_vp_index, ISPASYNC_CHANGE_OTHER);
+ } else {
+ fcp->isp_loopstate = LOOP_NIL;
+ isp_async(isp, ISPASYNC_LOOP_DOWN,
+ rid.ridacq_vp_index);
+ }
}
return (1);
case RQSTYPE_ATIO:
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c
index 6ce5b85..73741eb 100644
--- a/sys/dev/isp/isp_freebsd.c
+++ b/sys/dev/isp/isp_freebsd.c
@@ -50,13 +50,13 @@ __FBSDID("$FreeBSD$");
MODULE_VERSION(isp, 1);
MODULE_DEPEND(isp, cam, 1, 1, 1);
int isp_announced = 0;
-int isp_fabric_hysteresis = 5;
int isp_loop_down_limit = 60; /* default loop down limit */
int isp_quickboot_time = 7; /* don't wait more than N secs for loop up */
int isp_gone_device_time = 30; /* grace time before reporting device lost */
static const char prom3[] = "Chan %d [%u] PortID 0x%06x Departed because of %s";
-static void isp_freeze_loopdown(ispsoftc_t *, int, char *);
+static void isp_freeze_loopdown(ispsoftc_t *, int);
+static void isp_loop_changed(ispsoftc_t *isp, int chan);
static d_ioctl_t ispioctl;
static void isp_intr_enable(void *);
static void isp_cam_async(void *, uint32_t, struct cam_path *, void *);
@@ -64,8 +64,6 @@ static void isp_poll(struct cam_sim *);
static timeout_t isp_watchdog;
static timeout_t isp_gdt;
static task_fn_t isp_gdt_task;
-static timeout_t isp_ldt;
-static task_fn_t isp_ldt_task;
static void isp_kthread(void *);
static void isp_action(struct cam_sim *, union ccb *);
static int isp_timer_count;
@@ -168,25 +166,13 @@ isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan)
fc->isp = isp;
fc->ready = 1;
- callout_init_mtx(&fc->ldt, &isp->isp_osinfo.lock, 0);
callout_init_mtx(&fc->gdt, &isp->isp_osinfo.lock, 0);
- TASK_INIT(&fc->ltask, 1, isp_ldt_task, fc);
TASK_INIT(&fc->gtask, 1, isp_gdt_task, fc);
-
- /*
- * We start by being "loop down" if we have an initiator role
- */
- if (fcp->role & ISP_ROLE_INITIATOR) {
- isp_freeze_loopdown(isp, chan, "isp_attach");
- callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc);
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime);
- }
+ isp_loop_changed(isp, chan);
ISP_UNLOCK(isp);
if (THREAD_CREATE(isp_kthread, fc, &fc->kproc, 0, 0, "%s: fc_thrd%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
xpt_free_path(fc->path);
ISP_LOCK(isp);
- if (callout_active(&fc->ldt))
- callout_stop(&fc->ldt);
xpt_bus_deregister(cam_sim_path(fc->sim));
ISP_UNLOCK(isp);
cam_sim_free(fc->sim, FALSE);
@@ -377,13 +363,13 @@ isp_detach(ispsoftc_t *isp)
}
static void
-isp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg)
+isp_freeze_loopdown(ispsoftc_t *isp, int chan)
{
if (IS_FC(isp)) {
struct isp_fc *fc = ISP_FC_PC(isp, chan);
if (fc->simqfrozen == 0) {
isp_prt(isp, ISP_LOGDEBUG0,
- "Chan %d %s -- freeze simq (loopdown)", chan, msg);
+ "Chan %d Freeze simq (loopdown)", chan);
fc->simqfrozen = SIMQFRZ_LOOPDOWN;
#if __FreeBSD_version >= 1000039
xpt_hold_boot();
@@ -391,7 +377,7 @@ isp_freeze_loopdown(ispsoftc_t *isp, int chan, char *msg)
xpt_freeze_simq(fc->sim, 1);
} else {
isp_prt(isp, ISP_LOGDEBUG0,
- "Chan %d %s -- mark frozen (loopdown)", chan, msg);
+ "Chan %d Mark simq frozen (loopdown)", chan);
fc->simqfrozen |= SIMQFRZ_LOOPDOWN;
}
}
@@ -405,7 +391,8 @@ isp_unfreeze_loopdown(ispsoftc_t *isp, int chan)
int wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN;
fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN;
if (wasfrozen && fc->simqfrozen == 0) {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan);
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "Chan %d Release simq", chan);
xpt_release_simq(fc->sim, 1);
#if __FreeBSD_version >= 1000039
xpt_release_boot();
@@ -481,7 +468,7 @@ ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td)
break;
}
ISP_LOCK(isp);
- if (isp_fc_runstate(isp, chan, 5 * 1000000)) {
+ if (isp_fc_runstate(isp, chan, 5 * 1000000) != LOOP_READY) {
retval = EIO;
} else {
retval = 0;
@@ -3270,41 +3257,59 @@ isp_gdt_task(void *arg, int pending)
}
/*
- * Loop Down Timer Function- when loop goes down, a timer is started and
- * and after it expires we come here and take all probational devices that
- * the OS knows about and the tell the OS that they've gone away.
- *
+ * When loop goes down we remember the time and freeze CAM command queue.
+ * During some time period we are trying to reprobe the loop. But if we
+ * fail, we tell the OS that devices have gone away and drop the freeze.
+ *
* We don't clear the devices out of our port database because, when loop
* come back up, we have to do some actual cleanup with the chip at that
* point (implicit PLOGO, e.g., to get the chip's port database state right).
*/
static void
-isp_ldt(void *arg)
+isp_loop_changed(ispsoftc_t *isp, int chan)
{
- struct isp_fc *fc = arg;
- taskqueue_enqueue(taskqueue_thread, &fc->ltask);
+ fcparam *fcp = FCPARAM(isp, chan);
+ struct isp_fc *fc = ISP_FC_PC(isp, chan);
+
+ if (fc->loop_down_time)
+ return;
+ isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Loop changed", chan);
+ if (fcp->role & ISP_ROLE_INITIATOR)
+ isp_freeze_loopdown(isp, chan);
+ fc->loop_dead = 0;
+ fc->loop_down_time = time_uptime;
+ wakeup(fc);
}
static void
-isp_ldt_task(void *arg, int pending)
+isp_loop_up(ispsoftc_t *isp, int chan)
{
- struct isp_fc *fc = arg;
- ispsoftc_t *isp = fc->isp;
- int chan = fc - isp->isp_osinfo.pc.fc;
+ struct isp_fc *fc = ISP_FC_PC(isp, chan);
+
+ isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Loop is up", chan);
+ fc->loop_seen_once = 1;
+ fc->loop_dead = 0;
+ fc->loop_down_time = 0;
+ isp_unfreeze_loopdown(isp, chan);
+}
+
+static void
+isp_loop_dead(ispsoftc_t *isp, int chan)
+{
+ fcparam *fcp = FCPARAM(isp, chan);
+ struct isp_fc *fc = ISP_FC_PC(isp, chan);
fcportdb_t *lp;
struct ac_contract ac;
struct ac_device_changed *adc;
int dbidx, i;
- ISP_LOCK(isp);
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime);
- callout_deactivate(&fc->ldt);
+ isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Chan %d Loop is dead", chan);
/*
* Notify to the OS all targets who we now consider have departed.
*/
for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) {
- lp = &FCPARAM(isp, chan)->portdb[dbidx];
+ lp = &fcp->portdb[dbidx];
if (lp->state == FC_PORTDB_STATE_NIL)
continue;
@@ -3347,14 +3352,8 @@ isp_ldt_task(void *arg, int pending)
}
isp_unfreeze_loopdown(isp, chan);
- /*
- * The loop down timer has expired. Wake up the kthread
- * to notice that fact (or make it false).
- */
fc->loop_dead = 1;
- fc->loop_down_time = fc->loop_down_limit+1;
- wakeup(fc);
- ISP_UNLOCK(isp);
+ fc->loop_down_time = 0;
}
static void
@@ -3363,15 +3362,18 @@ isp_kthread(void *arg)
struct isp_fc *fc = arg;
ispsoftc_t *isp = fc->isp;
int chan = fc - isp->isp_osinfo.pc.fc;
- int slp = 0;
+ int slp = 0, d;
+ int lb, lim;
mtx_lock(&isp->isp_osinfo.lock);
while (isp->isp_osinfo.is_exiting == 0) {
- int lb, lim;
-
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan);
+ isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0,
+ "Chan %d Checking FC state", chan);
lb = isp_fc_runstate(isp, chan, 250000);
+ isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0,
+ "Chan %d FC got to %s state", chan,
+ isp_fc_loop_statename(lb));
/*
* Our action is different based upon whether we're supporting
@@ -3381,87 +3383,44 @@ isp_kthread(void *arg)
*
* If not, we simply just wait for loop to come up.
*/
- if (lb && (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR)) {
- /*
- * Increment loop down time by the last sleep interval
- */
- fc->loop_down_time += slp;
-
- if (lb < 0) {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC loop not up (down count %d)", __func__, chan, fc->loop_down_time);
- } else {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC got to %d (down count %d)", __func__, chan, lb, fc->loop_down_time);
- }
-
+ if (lb == LOOP_READY || lb < 0) {
+ slp = 0;
+ } else {
/*
* If we've never seen loop up and we've waited longer
* than quickboot time, or we've seen loop up but we've
* waited longer than loop_down_limit, give up and go
* to sleep until loop comes up.
*/
- if (FCPARAM(isp, chan)->loop_seen_once == 0) {
+ if (fc->loop_seen_once == 0)
lim = isp_quickboot_time;
- } else {
+ else
lim = fc->loop_down_limit;
- }
- if (fc->loop_down_time >= lim) {
- isp_freeze_loopdown(isp, chan, "loop limit hit");
+ d = time_uptime - fc->loop_down_time;
+ if (d >= lim)
slp = 0;
- } else if (fc->loop_down_time < 10) {
+ else if (d < 10)
slp = 1;
- } else if (fc->loop_down_time < 30) {
+ else if (d < 30)
slp = 5;
- } else if (fc->loop_down_time < 60) {
+ else if (d < 60)
slp = 10;
- } else if (fc->loop_down_time < 120) {
+ else if (d < 120)
slp = 20;
- } else {
- slp = 30;
- }
-
- } else if (lb) {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC Loop Down", __func__, chan);
- fc->loop_down_time += slp;
- if (fc->loop_down_time > 300)
- slp = 0;
else
- slp = 60;
- } else {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d FC state OK", __func__, chan);
- fc->loop_down_time = 0;
- slp = 0;
+ slp = 30;
}
-
- /*
- * If this is past the first loop up or the loop is dead and if we'd frozen the simq, unfreeze it
- * now so that CAM can start sending us commands.
- *
- * If the FC state isn't okay yet, they'll hit that in isp_start which will freeze the queue again
- * or kill the commands, as appropriate.
- */
-
- if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) {
- isp_unfreeze_loopdown(isp, chan);
+ if (slp == 0) {
+ if (lb == LOOP_READY)
+ isp_loop_up(isp, chan);
+ else
+ isp_loop_dead(isp, chan);
}
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp);
-
+ isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0,
+ "Chan %d sleep for %d seconds", chan, slp);
msleep(fc, &isp->isp_osinfo.lock, PRIBIO, "ispf", slp * hz);
-
- /*
- * If slp is zero, we're waking up for the first time after
- * things have been okay. In this case, we set a deferral state
- * for all commands and delay hysteresis seconds before starting
- * the FC state evaluation. This gives the loop/fabric a chance
- * to settle.
- */
- if (slp == 0 && fc->hysteresis) {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep hysteresis ticks %d", __func__, chan, fc->hysteresis * hz);
- mtx_unlock(&isp->isp_osinfo.lock);
- pause("ispt", fc->hysteresis * hz);
- mtx_lock(&isp->isp_osinfo.lock);
- }
}
fc->num_threads -= 1;
mtx_unlock(&isp->isp_osinfo.lock);
@@ -3471,7 +3430,7 @@ isp_kthread(void *arg)
static void
isp_action(struct cam_sim *sim, union ccb *ccb)
{
- int bus, tgt, ts, error, lim;
+ int bus, tgt, ts, error;
ispsoftc_t *isp;
struct ccb_trans_settings *cts;
@@ -3535,26 +3494,13 @@ isp_action(struct cam_sim *sim, union ccb *ccb)
break;
case CMD_RQLATER:
/*
- * We get this result for FC devices if the loop state isn't ready yet
- * or if the device in question has gone zombie on us.
- *
- * If we've never seen Loop UP at all, we requeue this request and wait
- * for the initial loop up delay to expire.
+ * We get this result if the loop isn't ready
+ * or if the device in question has gone zombie.
*/
- lim = ISP_FC_PC(isp, bus)->loop_down_limit;
- if (FCPARAM(isp, bus)->loop_seen_once == 0 || ISP_FC_PC(isp, bus)->loop_down_time >= lim) {
- if (FCPARAM(isp, bus)->loop_seen_once == 0) {
- isp_prt(isp, ISP_LOGDEBUG0,
- "%d.%jx loop not seen yet @ %lu",
- XS_TGT(ccb), (uintmax_t)XS_LUN(ccb),
- (unsigned long) time_uptime);
- } else {
- isp_prt(isp, ISP_LOGDEBUG0,
- "%d.%jx downtime (%d) > lim (%d)",
- XS_TGT(ccb), (uintmax_t)XS_LUN(ccb),
- ISP_FC_PC(isp, bus)->loop_down_time,
- lim);
- }
+ if (ISP_FC_PC(isp, bus)->loop_dead) {
+ isp_prt(isp, ISP_LOGDEBUG0,
+ "%d.%jx loop is dead",
+ XS_TGT(ccb), (uintmax_t)XS_LUN(ccb));
ccb->ccb_h.status = CAM_SEL_TIMEOUT;
isp_done((struct ccb_scsiio *) ccb);
break;
@@ -4260,49 +4206,20 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
msg = "LOOP Reset";
/* FALLTHROUGH */
case ISPASYNC_LOOP_DOWN:
- {
if (msg == NULL)
msg = "LOOP Down";
va_start(ap, cmd);
bus = va_arg(ap, int);
va_end(ap);
-
- FCPARAM(isp, bus)->isp_linkstate = 0;
-
- fc = ISP_FC_PC(isp, bus);
- if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) {
- /*
- * We don't do any simq freezing if we are only in target mode
- */
- if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) {
- if (fc->path) {
- isp_freeze_loopdown(isp, bus, msg);
- }
- }
- if (!callout_active(&fc->ldt)) {
- callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
- }
- }
isp_fcp_reset_crn(isp, bus, /*tgt*/0, /*tgt_set*/ 0);
-
- isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
+ isp_loop_changed(isp, bus);
+ isp_prt(isp, ISP_LOGINFO, "Chan %d %s", bus, msg);
break;
- }
case ISPASYNC_LOOP_UP:
va_start(ap, cmd);
bus = va_arg(ap, int);
va_end(ap);
- fc = ISP_FC_PC(isp, bus);
- /*
- * Now we just note that Loop has come up. We don't
- * actually do anything because we're waiting for a
- * Change Notify before activating the FC cleanup
- * thread to look at the state of the loop again.
- */
- FCPARAM(isp, bus)->isp_linkstate = 1;
- fc->loop_dead = 0;
- fc->loop_down_time = 0;
+ isp_loop_changed(isp, bus);
isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus);
break;
case ISPASYNC_DEV_ARRIVED:
@@ -4435,18 +4352,7 @@ changed:
msg = "Other Change Notify";
isp_prt(isp, ISP_LOGINFO, "Chan %d %s", bus, msg);
}
-
- /*
- * If the loop down timer is running, cancel it.
- */
- if (fc->ready && callout_active(&fc->ldt)) {
- isp_prt(isp, ISP_LOG_SANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime);
- callout_stop(&fc->ldt);
- }
- if (FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) {
- isp_freeze_loopdown(isp, bus, msg);
- }
- wakeup(fc);
+ isp_loop_changed(isp, bus);
break;
}
#ifdef ISP_TARGET_MODE
diff --git a/sys/dev/isp/isp_freebsd.h b/sys/dev/isp/isp_freebsd.h
index 8712cec..ff9a5a3 100644
--- a/sys/dev/isp/isp_freebsd.h
+++ b/sys/dev/isp/isp_freebsd.h
@@ -228,9 +228,9 @@ struct isp_fc {
bus_dmamap_t tdmap;
uint64_t def_wwpn;
uint64_t def_wwnn;
- uint32_t loop_down_time;
- uint32_t loop_down_limit;
- uint32_t gone_device_time;
+ time_t loop_down_time;
+ int loop_down_limit;
+ int gone_device_time;
/*
* Per target/lun info- just to keep a per-ITL nexus crn count
*/
@@ -239,15 +239,13 @@ struct isp_fc {
uint32_t
simqfrozen : 3,
default_id : 8,
- hysteresis : 8,
def_role : 2, /* default role */
gdt_running : 1,
loop_dead : 1,
+ loop_seen_once : 1,
fcbsy : 1,
ready : 1;
- struct callout ldt; /* loop down timer */
struct callout gdt; /* gone device timer */
- struct task ltask;
struct task gtask;
#ifdef ISP_TARGET_MODE
struct tslist lun_hash[LUN_HASH_SIZE];
@@ -698,7 +696,6 @@ extern uint64_t isp_default_wwn(ispsoftc_t *, int, int, int);
* driver global data
*/
extern int isp_announced;
-extern int isp_fabric_hysteresis;
extern int isp_loop_down_limit;
extern int isp_gone_device_time;
extern int isp_quickboot_time;
diff --git a/sys/dev/isp/isp_library.c b/sys/dev/isp/isp_library.c
index 6003d00..9e8f3ab 100644
--- a/sys/dev/isp/isp_library.c
+++ b/sys/dev/isp/isp_library.c
@@ -394,33 +394,31 @@ isp_print_bytes(ispsoftc_t *isp, const char *msg, int amt, void *arg)
int
isp_fc_runstate(ispsoftc_t *isp, int chan, int tval)
{
- fcparam *fcp;
+ fcparam *fcp = FCPARAM(isp, chan);
+ int res;
- fcp = FCPARAM(isp, chan);
- if (fcp->role == ISP_ROLE_NONE) {
- return (0);
- }
- if (isp_control(isp, ISPCTL_FCLINK_TEST, chan, tval) != 0) {
- isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: linktest failed for channel %d", chan);
- return (-1);
- }
- if (isp_control(isp, ISPCTL_SCAN_LOOP, chan) != 0) {
- isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: scan loop failed on channel %d", chan);
- return (LOOP_LTEST_DONE);
- }
- if (isp_control(isp, ISPCTL_SCAN_FABRIC, chan) != 0) {
- isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: scan fabric failed on channel %d", chan);
- return (LOOP_LSCAN_DONE);
- }
- if (isp_control(isp, ISPCTL_PDB_SYNC, chan) != 0) {
- isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: pdb_sync failed on channel %d", chan);
- return (LOOP_FSCAN_DONE);
- }
- if (fcp->isp_loopstate != LOOP_READY) {
- isp_prt(isp, ISP_LOG_SANCFG, "isp_fc_runstate: not ready again on channel %d", chan);
+again:
+ if (fcp->role == ISP_ROLE_NONE)
return (-1);
- }
- return (0);
+ res = isp_control(isp, ISPCTL_FCLINK_TEST, chan, tval);
+ if (res > 0)
+ goto again;
+ if (res < 0)
+ return (fcp->isp_loopstate);
+ res = isp_control(isp, ISPCTL_SCAN_LOOP, chan);
+ if (res > 0)
+ goto again;
+ if (res < 0)
+ return (fcp->isp_loopstate);
+ res = isp_control(isp, ISPCTL_SCAN_FABRIC, chan);
+ if (res > 0)
+ goto again;
+ if (res < 0)
+ return (fcp->isp_loopstate);
+ res = isp_control(isp, ISPCTL_PDB_SYNC, chan);
+ if (res > 0)
+ goto again;
+ return (fcp->isp_loopstate);
}
/*
@@ -545,6 +543,7 @@ isp_fc_loop_statename(int state)
{
switch (state) {
case LOOP_NIL: return "NIL";
+ case LOOP_HAVE_LINK: return "Have Link";
case LOOP_TESTING_LINK: return "Testing Link";
case LOOP_LTEST_DONE: return "Link Test Done";
case LOOP_SCANNING_LOOP: return "Scanning Loop";
diff --git a/sys/dev/isp/isp_pci.c b/sys/dev/isp/isp_pci.c
index 26fae24..55cb034 100644
--- a/sys/dev/isp/isp_pci.c
+++ b/sys/dev/isp/isp_pci.c
@@ -638,16 +638,6 @@ isp_get_specific_options(device_t dev, int chan, ispsoftc_t *isp)
}
}
- tval = 0;
- snprintf(name, sizeof(name), "%shysteresis", prefix);
- (void) resource_int_value(device_get_name(dev), device_get_unit(dev),
- "name", &tval);
- if (tval >= 0 && tval < 256) {
- ISP_FC_PC(isp, chan)->hysteresis = tval;
- } else {
- ISP_FC_PC(isp, chan)->hysteresis = isp_fabric_hysteresis;
- }
-
tval = -1;
snprintf(name, sizeof(name), "%sloop_down_limit", prefix);
(void) resource_int_value(device_get_name(dev), device_get_unit(dev),
diff --git a/sys/dev/isp/ispvar.h b/sys/dev/isp/ispvar.h
index 9b4156a..10060e1 100644
--- a/sys/dev/isp/ispvar.h
+++ b/sys/dev/isp/ispvar.h
@@ -438,10 +438,9 @@ typedef struct {
int isp_loopstate; /* Loop State */
int isp_topo; /* Connection Type */
- uint32_t : 3,
+ uint32_t : 4,
fctape_enabled : 1,
sendmarker : 1,
- loop_seen_once : 1,
role : 2,
isp_portid : 24; /* S_ID */
@@ -490,14 +489,15 @@ typedef struct {
#define FW_NON_PART 7
#define LOOP_NIL 0
-#define LOOP_TESTING_LINK 1
-#define LOOP_LTEST_DONE 2
-#define LOOP_SCANNING_LOOP 3
-#define LOOP_LSCAN_DONE 4
-#define LOOP_SCANNING_FABRIC 5
-#define LOOP_FSCAN_DONE 6
-#define LOOP_SYNCING_PDB 7
-#define LOOP_READY 8
+#define LOOP_HAVE_LINK 1
+#define LOOP_TESTING_LINK 2
+#define LOOP_LTEST_DONE 3
+#define LOOP_SCANNING_LOOP 4
+#define LOOP_LSCAN_DONE 5
+#define LOOP_SCANNING_FABRIC 6
+#define LOOP_FSCAN_DONE 7
+#define LOOP_SYNCING_PDB 8
+#define LOOP_READY 9
#define TOPO_NL_PORT 0
#define TOPO_FL_PORT 1
OpenPOWER on IntegriCloud