Date: Fri, 5 Aug 2011 22:32:49 GMT From: Matt Jacob <mjacob@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 197237 for review Message-ID: <201108052232.p75MWnO5053735@skunkworks.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://p4web.freebsd.org/@@197237?ac=10 Change 197237 by mjacob@mjacob-sandbox on 2011/08/05 22:32:09 Merge changes from Panasas for isp. Mostly in implementing taskqueues for loop down and gone device events. Affected files ... .. //depot/projects/mjacob-dev/sys/dev/isp/isp.c#5 edit .. //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.c#6 edit .. //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.h#6 edit .. //depot/projects/mjacob-dev/sys/dev/isp/ispvar.h#5 edit Differences ... ==== //depot/projects/mjacob-dev/sys/dev/isp/isp.c#5 (text+ko) ==== @@ -102,7 +102,6 @@ /* * Local function prototypes. */ -static void isp_prt_endcmd(ispsoftc_t *, XS_T *); static int isp_parse_async(ispsoftc_t *, uint16_t); static int isp_parse_async_fc(ispsoftc_t *, uint16_t); static int isp_handle_other_response(ispsoftc_t *, int, isphdr_t *, uint32_t *); @@ -5391,7 +5390,7 @@ * Support routines. */ -static void +void isp_prt_endcmd(ispsoftc_t *isp, XS_T *xs) { char cdbstr[16 * 5 + 1]; ==== //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.c#6 (text+ko) ==== @@ -67,7 +67,10 @@ static void isp_cam_async(void *, uint32_t, struct cam_path *, void *); 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 *); #ifdef ISP_INTERNAL_TARGET @@ -141,8 +144,11 @@ 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); + 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 @@ -303,6 +309,20 @@ } } +static void +isp_unfreeze_loopdown(ispsoftc_t *isp, int chan) +{ + if (IS_FC(isp)) { + struct isp_fc *fc = ISP_FC_PC(isp, chan); + int wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN; + fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN; + if (wasfrozen && fc->simqfrozen == 0) { + isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan); + xpt_release_simq(fc->sim, 1); + } + } +} + static int ispioctl(struct cdev *dev, u_long c, caddr_t addr, int flags, struct thread *td) @@ -3837,12 +3857,33 @@ { struct ccb_scsiio *xs = arg; ispsoftc_t *isp; - uint32_t handle; + uint32_t ohandle = ISP_HANDLE_FREE, handle; isp = XS_ISP(xs); handle = isp_find_handle(isp, xs); + + if (handle != ISP_HANDLE_FREE && !XS_CMD_WPEND_P(xs)) { + isp_xs_prt(isp, xs, ISP_LOGWARN, "first watchdog (handle 0x%x) timed out- deferring for grace period", handle); + callout_reset(&PISP_PCMD(xs)->wdog, 2 * hz, isp_watchdog, xs); + XS_CMD_S_WPEND(xs); + return; + } + XS_C_TACTIVE(xs); + + /* + * Hand crank the interrupt code just to be sure the command isn't stuck somewhere. + */ if (handle != ISP_HANDLE_FREE) { + uint32_t isr; + uint16_t sema, mbox; + if (ISP_READ_ISR(isp, &isr, &sema, &mbox) != 0) { + isp_intr(isp, isr, sema, mbox); + } + ohandle = handle; + handle = isp_find_handle(isp, xs); + } + if (handle != ISP_HANDLE_FREE) { /* * Try and make sure the command is really dead before * we release the handle (and DMA resources) for reuse. @@ -3878,7 +3919,14 @@ isp_destroy_handle(isp, handle); isp_prt(isp, ISP_LOGERR, "%s: timeout for handle 0x%x", __func__, handle); XS_SETERR(xs, CAM_CMD_TIMEOUT); + isp_prt_endcmd(isp, xs); isp_done(xs); + } else { + if (ohandle != ISP_HANDLE_FREE) { + isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle 0x%x, recovered during interrupt", __func__, ohandle); + } else { + isp_prt(isp, ISP_LOGWARN, "%s: timeout for handle already free", __func__); + } } } @@ -3937,12 +3985,20 @@ isp_gdt(void *arg) { struct isp_fc *fc = arg; + taskqueue_enqueue_fast(taskqueue_fast, &fc->gtask); +} + +static void +isp_gdt_task(void *arg, int pending) +{ + struct isp_fc *fc = arg; ispsoftc_t *isp = fc->isp; int chan = fc - isp->isp_osinfo.pc.fc; fcportdb_t *lp; int dbidx, tgt, more_to_do = 0; - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d GDT timer expired @ %lu", chan, (unsigned long) time_uptime); + ISP_LOCK(isp); + isp_prt(isp, ISP_LOGDEBUG0, "Chan %d GDT timer expired", chan); for (dbidx = 0; dbidx < MAX_FC_TARG; dbidx++) { lp = &FCPARAM(isp, chan)->portdb[dbidx]; @@ -3971,6 +4027,7 @@ isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Stopping Gone Device Timer", chan); } } + ISP_UNLOCK(isp); } /* @@ -3986,11 +4043,19 @@ isp_ldt(void *arg) { struct isp_fc *fc = arg; + taskqueue_enqueue_fast(taskqueue_fast, &fc->ltask); +} + +static void +isp_ldt_task(void *arg, int pending) +{ + struct isp_fc *fc = arg; ispsoftc_t *isp = fc->isp; int chan = fc - isp->isp_osinfo.pc.fc; fcportdb_t *lp; - int dbidx, tgt; + int dbidx, tgt, i; + ISP_LOCK(isp); isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "Chan %d Loop Down Timer expired @ %lu", chan, (unsigned long) time_uptime); /* @@ -4009,7 +4074,24 @@ /* * XXX: CLEAN UP AND COMPLETE ANY PENDING COMMANDS FIRST! */ + + + for (i = 0; i < isp->isp_maxcmds; i++) { + struct ccb_scsiio *xs; + if (!ISP_VALID_HANDLE(isp, isp->isp_xflist[i].handle)) { + continue; + } + if ((xs = isp->isp_xflist[i].cmd) == NULL) { + continue; + } + if (dbidx != (FCPARAM(isp, chan)->isp_dev_map[XS_TGT(xs)] - 1)) { + continue; + } + isp_prt(isp, ISP_LOGWARN, "command handle 0x%08x for %d.%d.%d orphaned by loop down timeout", + isp->isp_xflist[i].handle, chan, XS_TGT(xs), XS_LUN(xs)); + } + /* * Mark that we've announced that this device is gone.... */ @@ -4030,6 +4112,10 @@ isp_make_gone(isp, chan, tgt); } + if (FCPARAM(isp, chan)->role & ISP_ROLE_INITIATOR) { + isp_unfreeze_loopdown(isp, chan); + } + /* * The loop down timer has expired. Wake up the kthread * to notice that fact (or make it false). @@ -4037,6 +4123,7 @@ fc->loop_dead = 1; fc->loop_down_time = fc->loop_down_limit+1; wakeup(fc); + ISP_UNLOCK(isp); } static void @@ -4050,7 +4137,7 @@ mtx_lock(&isp->isp_osinfo.lock); for (;;) { - int wasfrozen, lb, lim; + int lb, lim; isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d checking FC state", __func__, chan); lb = isp_fc_runstate(isp, chan, 250000); @@ -4121,12 +4208,7 @@ */ if (FCPARAM(isp, chan)->loop_seen_once || fc->loop_dead) { - wasfrozen = fc->simqfrozen & SIMQFRZ_LOOPDOWN; - fc->simqfrozen &= ~SIMQFRZ_LOOPDOWN; - if (wasfrozen && fc->simqfrozen == 0) { - isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d releasing simq", __func__, chan); - xpt_release_simq(fc->sim, 1); - } + isp_unfreeze_loopdown(isp, chan); } isp_prt(isp, ISP_LOGSANCFG|ISP_LOGDEBUG0, "%s: Chan %d sleep time %d", __func__, chan, slp); @@ -4225,6 +4307,7 @@ ts = 60*1000; } ts = isp_mstohz(ts); + XS_S_TACTIVE(ccb); callout_reset(&PISP_PCMD(ccb)->wdog, ts, isp_watchdog, ccb); break; case CMD_RQLATER: @@ -4751,7 +4834,9 @@ /* * Set base transfer capabilities for Fibre Channel, for this HBA. */ - if (IS_24XX(isp)) { + if (IS_25XX(isp)) { + cpi->base_transfer_speed = 8000000; + } else if (IS_24XX(isp)) { cpi->base_transfer_speed = 4000000; } else if (IS_23XX(isp)) { cpi->base_transfer_speed = 2000000; @@ -4797,6 +4882,7 @@ isp_done(XS_T *sccb) { ispsoftc_t *isp = XS_ISP(sccb); + uint32_t status; if (XS_NOERR(sccb)) XS_SETERR(sccb, CAM_REQ_CMP); @@ -4811,8 +4897,10 @@ } sccb->ccb_h.status &= ~CAM_SIM_QUEUED; - if ((sccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { - isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); + status = sccb->ccb_h.status & CAM_STATUS_MASK; + if (status != CAM_REQ_CMP) { + if (status != CAM_SEL_TIMEOUT) + isp_prt(isp, ISP_LOGDEBUG0, "target %d lun %d CAM status 0x%x SCSI status 0x%x", XS_TGT(sccb), XS_LUN(sccb), sccb->ccb_h.status, sccb->scsi_status); if ((sccb->ccb_h.status & CAM_DEV_QFRZN) == 0) { sccb->ccb_h.status |= CAM_DEV_QFRZN; xpt_freeze_devq(sccb->ccb_h.path, 1); @@ -4824,7 +4912,8 @@ } XS_CMD_S_DONE(sccb); - callout_stop(&PISP_PCMD(sccb)->wdog); + if (XS_TACTIVE_P(sccb)) + callout_stop(&PISP_PCMD(sccb)->wdog); XS_CMD_S_CLEAR(sccb); isp_free_pcmd(isp, (union ccb *) sccb); xpt_done((union ccb *) sccb); @@ -4974,7 +5063,6 @@ va_end(ap); fc = ISP_FC_PC(isp, bus); lp->reserved = 0; - lp->gone_timer = 0; if ((FCPARAM(isp, bus)->role & ISP_ROLE_INITIATOR) && (lp->roles & (SVC3_TGT_ROLE >> SVC3_ROLE_SHIFT))) { int dbidx = lp - FCPARAM(isp, bus)->portdb; int i; @@ -5010,7 +5098,6 @@ va_end(ap); fc = ISP_FC_PC(isp, bus); lp->reserved = 0; - lp->gone_timer = 0; if (isp_change_is_bad) { lp->state = FC_PORTDB_STATE_NIL; if (lp->dev_map_idx) { ==== //depot/projects/mjacob-dev/sys/dev/isp/isp_freebsd.h#6 (text+ko) ==== @@ -41,6 +41,7 @@ #include <sys/proc.h> #include <sys/bus.h> +#include <sys/taskqueue.h> #include <machine/bus.h> #include <machine/cpu.h> @@ -182,6 +183,8 @@ 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]; #ifdef ISP_INTERNAL_TARGET @@ -597,12 +600,23 @@ * Platform private flags */ #define ISP_SPRIV_ERRSET 0x1 +#define ISP_SPRIV_TACTIVE 0x2 #define ISP_SPRIV_DONE 0x8 +#define ISP_SPRIV_WPEND 0x10 + +#define XS_S_TACTIVE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_TACTIVE +#define XS_C_TACTIVE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_TACTIVE +#define XS_TACTIVE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_TACTIVE) #define XS_CMD_S_DONE(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_DONE #define XS_CMD_C_DONE(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_DONE #define XS_CMD_DONE_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_DONE) +#define XS_CMD_S_WPEND(sccb) (sccb)->ccb_h.spriv_field0 |= ISP_SPRIV_WPEND +#define XS_CMD_C_WPEND(sccb) (sccb)->ccb_h.spriv_field0 &= ~ISP_SPRIV_WPEND +#define XS_CMD_WPEND_P(sccb) ((sccb)->ccb_h.spriv_field0 & ISP_SPRIV_WPEND) + + #define XS_CMD_S_CLEAR(sccb) (sccb)->ccb_h.spriv_field0 = 0 /* ==== //depot/projects/mjacob-dev/sys/dev/isp/ispvar.h#5 (text+ko) ==== @@ -953,6 +953,11 @@ #define ISPASYNC_CHANGE_OTHER 2 /* + * Platform Independent Error Prinout + */ +void isp_prt_endcmd(ispsoftc_t *, XS_T *); + +/* * Platform Dependent Error and Debug Printout * * Two required functions for each platform must be provided:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201108052232.p75MWnO5053735>