diff options
author | mav <mav@FreeBSD.org> | 2015-11-30 21:58:51 +0000 |
---|---|---|
committer | mav <mav@FreeBSD.org> | 2015-11-30 21:58:51 +0000 |
commit | 97189158140218a2e5bfbd037679e515e9b2c64e (patch) | |
tree | 7d2745eb767919ae36eed1656e80ff70595c31c5 /sys/dev/isp | |
parent | 7e425797577f91547491a85ffd37c7eab99b9bb2 (diff) | |
download | FreeBSD-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.
Diffstat (limited to 'sys/dev/isp')
-rw-r--r-- | sys/dev/isp/isp.c | 103 | ||||
-rw-r--r-- | sys/dev/isp/isp_freebsd.c | 254 | ||||
-rw-r--r-- | sys/dev/isp/isp_freebsd.h | 11 | ||||
-rw-r--r-- | sys/dev/isp/isp_library.c | 49 | ||||
-rw-r--r-- | sys/dev/isp/isp_pci.c | 10 | ||||
-rw-r--r-- | sys/dev/isp/ispvar.h | 20 |
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 |