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.
This commit is contained in:
parent
52f175be70
commit
e561aa79fb
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=291365
@ -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 @@ isp_fclink_test(ispsoftc_t *isp, int chan, int usdelay)
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
|
||||
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 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
|
||||
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 @@ isp_scan_fabric(ispsoftc_t *isp, int chan)
|
||||
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:
|
||||
|
@ -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 *);
|
||||
@ -168,25 +168,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 +365,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 +379,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 +393,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 +470,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 +3259,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 +3354,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 +3364,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 +3385,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 {
|
||||
lim = fc->loop_down_limit;
|
||||
}
|
||||
if (fc->loop_down_time >= lim) {
|
||||
isp_freeze_loopdown(isp, chan, "loop limit hit");
|
||||
slp = 0;
|
||||
} else if (fc->loop_down_time < 10) {
|
||||
slp = 1;
|
||||
} else if (fc->loop_down_time < 30) {
|
||||
slp = 5;
|
||||
} else if (fc->loop_down_time < 60) {
|
||||
slp = 10;
|
||||
} else if (fc->loop_down_time < 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;
|
||||
lim = fc->loop_down_limit;
|
||||
d = time_uptime - fc->loop_down_time;
|
||||
if (d >= lim)
|
||||
slp = 0;
|
||||
else if (d < 10)
|
||||
slp = 1;
|
||||
else if (d < 30)
|
||||
slp = 5;
|
||||
else if (d < 60)
|
||||
slp = 10;
|
||||
else if (d < 120)
|
||||
slp = 20;
|
||||
else
|
||||
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 +3432,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 +3496,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 +4208,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 +4354,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
|
||||
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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
again:
|
||||
if (fcp->role == ISP_ROLE_NONE)
|
||||
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);
|
||||
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";
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user