Fix cases where we've managed to get a Loop UP event prior to initializing

the loop down counter, as well as other things. This was brought to my
attention with a different fix, more for RELENG_7- this one covers the
multiple channel case.

PR:		140438
MFC after:	1 month
This commit is contained in:
Matt Jacob 2009-12-04 03:34:12 +00:00
parent d94f2b8506
commit a01f5aeb09
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=200089
2 changed files with 52 additions and 43 deletions

View file

@ -133,33 +133,37 @@ isp_attach_chan(ispsoftc_t *isp, struct cam_devq *devq, int chan)
}
#endif
} else {
fcparam *fcp = FCPARAM(isp, chan);
struct isp_fc *fc = ISP_FC_PC(isp, chan);
ISP_LOCK(isp);
fc->sim = sim;
fc->path = path;
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);
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);
xpt_bus_deregister(cam_sim_path(fc->sim));
ISP_UNLOCK(isp);
cam_sim_free(fc->sim, FALSE);
}
/*
* We start by being "loop down" if we have an initiator role
*/
ISP_LOCK(isp);
if ((FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) && fc->ldt_running == 0) {
if (fcp->role & ISP_ROLE_INITIATOR) {
isp_freeze_loopdown(isp, chan, "isp_attach");
fc->ldt_running = 1;
callout_reset(&fc->ldt, isp_quickboot_time * hz, isp_ldt, fc);
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Starting Initial Loop Down Timer @ %lu", (unsigned long) time_uptime);
}
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);
return (ENOMEM);
}
#ifdef ISP_INTERNAL_TARGET
ISP_SET_PC(isp, chan, proc_active, 1);
if (THREAD_CREATE(isp_target_thread_fc, fc, &fc->target_proc, 0, 0, "%s: isp_test_tgt%d", device_get_nameunit(isp->isp_osinfo.dev), chan)) {
@ -3935,12 +3939,12 @@ isp_gdt(void *arg)
isp_prt(isp, ISP_LOGCONFIG, prom3, chan, lp->portid, tgt, "Gone Device Timeout");
isp_make_gone(isp, chan, tgt);
}
if (more_to_do) {
fc->gdt_running = 1;
callout_reset(&fc->gdt, hz, isp_gdt, fc);
} else {
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d stopping Gone Device Timer", chan);
fc->gdt_running = 0;
if (fc->ready) {
if (more_to_do) {
callout_reset(&fc->gdt, hz, isp_gdt, fc);
} else {
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d stopping Gone Device Timer", chan);
}
}
}
@ -4017,6 +4021,7 @@ isp_kthread(void *arg)
ispsoftc_t *isp = fc->isp;
int chan = fc - isp->isp_osinfo.pc.fc;
int slp = 0;
mtx_lock(&isp->isp_osinfo.lock);
for (;;) {
@ -4802,6 +4807,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
char *msg = NULL;
target_id_t tgt;
fcportdb_t *lp;
struct isp_fc *fc;
struct cam_path *tmppath;
va_list ap;
@ -4886,7 +4892,6 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
/* FALLTHROUGH */
case ISPASYNC_LOOP_DOWN:
{
struct isp_fc *fc;
if (msg == NULL) {
msg = "LOOP Down";
}
@ -4894,20 +4899,21 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
bus = va_arg(ap, int);
va_end(ap);
FCPARAM(isp, bus)->link_active = 1;
FCPARAM(isp, bus)->link_active = 0;
fc = ISP_FC_PC(isp, bus);
/*
* We don't do any simq freezing if we are only in target mode
*/
if (fc->role & ISP_ROLE_INITIATOR) {
if (fc->path) {
isp_freeze_loopdown(isp, bus, msg);
}
if (fc->ldt_running == 0) {
fc->ldt_running = 1;
callout_reset(&fc->ldt, fc->loop_down_limit * hz, isp_ldt, fc);
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
if (cmd == ISPASYNC_LOOP_DOWN && fc->ready) {
/*
* We don't do any simq freezing if we are only in target mode
*/
if (fc->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_LOGSANCFG|ISP_LOGDEBUG0, "starting Loop Down Timer @ %lu", (unsigned long) time_uptime);
}
}
}
isp_prt(isp, ISP_LOGINFO, "Chan %d: %s", bus, msg);
@ -4917,6 +4923,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
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
@ -4924,8 +4931,8 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
* thread to look at the state of the loop again.
*/
FCPARAM(isp, bus)->link_active = 1;
ISP_FC_PC(isp, bus)->loop_dead = 0;
ISP_FC_PC(isp, bus)->loop_down_time = 0;
fc->loop_dead = 0;
fc->loop_down_time = 0;
isp_prt(isp, ISP_LOGINFO, "Chan %d Loop UP", bus);
break;
case ISPASYNC_DEV_ARRIVED:
@ -4933,8 +4940,9 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
lp->reserved = 0;
if ((ISP_FC_PC(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
if ((fc->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) {
int dbidx = lp - FCPARAM(isp, bus)->portdb;
int i;
@ -4967,6 +4975,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
lp->reserved = 0;
if (isp_change_is_bad) {
lp->state = FC_PORTDB_STATE_NIL;
@ -5013,6 +5022,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
bus = va_arg(ap, int);
lp = va_arg(ap, fcportdb_t *);
va_end(ap);
fc = ISP_FC_PC(isp, bus);
/*
* If this has a virtual target and we haven't marked it
* that we're going to have isp_gdt tell the OS it's gone,
@ -5025,10 +5035,9 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
lp->reserved = 1;
lp->new_reserved = ISP_FC_PC(isp, bus)->gone_device_time;
lp->state = FC_PORTDB_STATE_ZOMBIE;
if (ISP_FC_PC(isp, bus)->gdt_running == 0) {
if (fc->ready && !callout_active(&fc->gdt)) {
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d starting Gone Device Timer", bus);
ISP_FC_PC(isp, bus)->gdt_running = 1;
callout_reset(&ISP_FC_PC(isp, bus)->gdt, hz, isp_gdt, ISP_FC_PC(isp, bus));
callout_reset(&fc->gdt, hz, isp_gdt, fc);
}
tgt = lp->dev_map_idx - 1;
isp_prt(isp, ISP_LOGCONFIG, prom2, bus, lp->portid, lp->handle, roles[lp->roles], "gone zombie at", tgt, (uint32_t) (lp->port_wwn >> 32), (uint32_t) lp->port_wwn);
@ -5053,6 +5062,7 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
nlstate = reason = 0;
}
va_end(ap);
fc = ISP_FC_PC(isp, bus);
if (evt == ISPASYNC_CHANGE_PDB) {
msg = "Chan %d Port Database Changed";
@ -5065,16 +5075,15 @@ isp_async(ispsoftc_t *isp, ispasync_t cmd, ...)
/*
* If the loop down timer is running, cancel it.
*/
if (ISP_FC_PC(isp, bus)->ldt_running) {
if (fc->ready && callout_active(&fc->ldt)) {
isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Stopping Loop Down Timer @ %lu", (unsigned long) time_uptime);
ISP_FC_PC(isp, bus)->ldt_running = 0;
callout_stop(&ISP_FC_PC(isp, bus)->ldt);
callout_stop(&fc->ldt);
}
isp_prt(isp, ISP_LOGINFO, msg, bus);
if (ISP_FC_PC(isp, bus)->role & ISP_ROLE_INITIATOR) {
if (fc->role & ISP_ROLE_INITIATOR) {
isp_freeze_loopdown(isp, bus, msg);
}
wakeup(ISP_FC_PC(isp, bus));
wakeup(fc);
break;
}
#ifdef ISP_TARGET_MODE

View file

@ -177,9 +177,9 @@ struct isp_fc {
hysteresis : 8,
role : 2,
gdt_running : 1,
ldt_running : 1,
loop_dead : 1,
fcbsy : 1;
fcbsy : 1,
ready : 1;
struct callout ldt; /* loop down timer */
struct callout gdt; /* gone device timer */
#ifdef ISP_TARGET_MODE