diff options
author | mjacob <mjacob@FreeBSD.org> | 2009-12-04 03:34:12 +0000 |
---|---|---|
committer | mjacob <mjacob@FreeBSD.org> | 2009-12-04 03:34:12 +0000 |
commit | 131d3745385aefd75c98f334be75366694ccbd9c (patch) | |
tree | 69ca594dc7af6d5e7423015418427516190b8ab0 /sys/dev/isp/isp_freebsd.c | |
parent | 901b0b81fe3969528db13d192d74c87c04ac6bf4 (diff) | |
download | FreeBSD-src-131d3745385aefd75c98f334be75366694ccbd9c.zip FreeBSD-src-131d3745385aefd75c98f334be75366694ccbd9c.tar.gz |
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
Diffstat (limited to 'sys/dev/isp/isp_freebsd.c')
-rw-r--r-- | sys/dev/isp/isp_freebsd.c | 91 |
1 files changed, 50 insertions, 41 deletions
diff --git a/sys/dev/isp/isp_freebsd.c b/sys/dev/isp/isp_freebsd.c index ca85d64..2861d7b 100644 --- a/sys/dev/isp/isp_freebsd.c +++ b/sys/dev/isp/isp_freebsd.c @@ -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 |